mricron-0.20140804.1~dfsg.1.orig/0000755000175000017500000000000012413465015014201 5ustar mihmihmricron-0.20140804.1~dfsg.1.orig/ReadInt.lrs0000755000175000017500000000226512332725756016274 0ustar mihmih{ This is an automatically generated lazarus resource file } LazarusResources.Add('TReadIntForm','FORMDATA',[ 'TPF0'#12'TReadIntForm'#11'ReadIntForm'#4'Left'#3'N'#1#6'Height'#2'_'#3'Top'#3 +#206#0#5'Width'#3'X'#2#13'ActiveControl'#7#11'ReadIntEdit'#11'BorderStyle'#7 +#8'bsDialog'#7'Caption'#6#16'Integer required'#12'ClientHeight'#2'_'#11'Clie' +'ntWidth'#3'X'#2#21'Constraints.MaxHeight'#2'_'#20'Constraints.MaxWidth'#3'X' +#2#21'Constraints.MinHeight'#2'_'#20'Constraints.MinWidth'#3'X'#2#9'Font.Nam' +'e'#6#13'MS Sans Serif'#8'OnCreate'#7#10'FormCreate'#6'OnShow'#7#8'FormShow' +#8'Position'#7#14'poScreenCenter'#10'LCLVersion'#6#8'1.0.12.0'#0#6'TLabel'#12 +'ReadIntLabel'#4'Left'#2#8#6'Height'#2#14#3'Top'#2#15#5'Width'#3#192#1#9'Ali' +'gnment'#7#14'taRightJustify'#8'AutoSize'#8#7'Caption'#6#14'Enter a number' +#11'ParentColor'#8#0#0#9'TSpinEdit'#11'ReadIntEdit'#4'Left'#3#216#1#6'Height' +#2#16#3'Top'#2#12#5'Width'#2'x'#8'MaxValue'#2#0#8'TabOrder'#2#1#0#0#7'TButto' +'n'#5'OKBtn'#4'Left'#3#216#1#6'Height'#2#25#3'Top'#2'7'#5'Width'#2'K'#25'Bor' +'derSpacing.InnerBorder'#2#4#7'Caption'#6#2'OK'#7'OnClick'#7#10'OKBtnClick'#8 +'TabOrder'#2#0#0#0#0 ]); mricron-0.20140804.1~dfsg.1.orig/example/0000755000175000017500000000000012360763602015640 5ustar mihmihmricron-0.20140804.1~dfsg.1.orig/example/fmri2r.ini0000755000175000017500000000053610403375276017553 0ustar mihmih[BOOL] SmoothBG=1 SmoothOverlay=1 Trilinear=1 OverlayFromBGSurface=0 ShowCutout=0 FlipLR=0 [INT] BGNearClip=0 OverlayNearClip=0 Azimuth=110 Elevation=45 BGSurface=25 OverlaySurface=1 BGDepth=8 OverlayDepth=8 CutoutLo1=90 CutoutHi1=181 CutoutLo2=118 CutoutHi2=217 CutoutLo3=90 CutoutHi3=181 OverlayFromBGSurface=0 CutoutBias=4 mricron-0.20140804.1~dfsg.1.orig/example/clipnearr.ini0000755000175000017500000000051010403403160020301 0ustar mihmih[BOOL] SmoothBG=1 SmoothOverlay=1 Trilinear=1 ShowCutout=0 FlipLR=0 [INT] OverlayFromBGSurface=1 BGNearClip=56 OverlayNearClip=0 Azimuth=110 Elevation=30 BGSurface=25 OverlaySurface=1 BGDepth=12 OverlayDepth=8 CutoutBias=3 CutoutLo1=96 CutoutHi1=181 CutoutLo2=118 CutoutHi2=217 CutoutLo3=87 CutoutHi3=181 mricron-0.20140804.1~dfsg.1.orig/example/attention.nii.gz0000755000175000017500000000743310403376064020775 0ustar mihmihCDattention.niiُ#"EC$iZmW*ަ;3=4a aQ HQ"%R$(QH-/y&^[uki~Km߮98;3g^^mTj+=n}w?w_}gu!{ߏ{'[z?G??j$-JW?t7o|s?O&}?2ܭACQh8QbAqxH Ļ/xrpf &!“dΡ$5k$1""~'-EQŒBtഋu`yjs"ҽ#|xD&g~Dr!^nW0lC!4  Lw˞U):F+RM9% {=S"505{M\CgTtUh<~5Ы Њ|<s9Ԕ7e2wGۈO'> QuHUf)%pUγr.8f$AP&QI9 Qrw9rG5K'dhFOw \FDQiȜZdjN=FJ Z\s/+tKEbv(c}^BZQah̲'{F': b%H2om{yg,̋(%y-[Dbu')\Ň2i*gf:DXWs\RLͭ173BXqpzʶc⍟-3+RS2:-U;zN0Pq e˳m Rm7HqM*R`h>?&~tC{:&=B+Ddl^:L[_|Zyq{\oj->F;n),0Gw"ԍ]nR1 L,TOԹW:~X;\_F6Hyez%i SkI"֘"Y!!djSek;}SQps1{<]$NڼV9~_,z|^Y}eMrOroNgs dxNEɸ׌oXX*'MJϗzo3m#&5AN?|#!8yVwMFP@{! pRA'9߾hr|5+Q ?Y@7MDsB~*w .b')TOD])^?S N䦂 f2!v | {r76%>uAqNfm] 2|EbcS0?1~ 1ka ] '$vOvgBD`.9rǡIQeSZ Sk jǩ [_>"ؐԷȪR\1 :> ZGT/!vHZzlcOXkc#"ƥ@qxՃMy,R UvMRn/2hŅ oǑŲE}EHI)Y>Nؗ4ɉ0մ]`C,\wM:T{"83f UM? i4J T$a@VT3h&[>Q-@={; ;(~?;7*{bil+x3]5!əL໻RqOF87w ^~vmԷpb?|f'vnvEzx.I%^)zZIPjy>9w:u`#)!ui3203!rb~,! pi/3}JkmrQoq^V7Дݾ|aMݮFՃZ,vz31GӥVH|#5ݼ)%k~jl٩lo^RI4kt3X]YJtg-uɔ1զ׫Zmx^Wg(ZÏ+K M>1;K. GϥF5L}~Z>D(/Q$ihHg'I{}s06ozdU7(շ>ԗޱ r_{pA9G5??^ؾZp~?vyxoօs/oU\)˵'aEg^_ټw&ui#\$"j(qd(QBg3GTSRɍFz8EQ .F)%K/.%k4Y԰U9KM3iYU;VvBt(B_hI=J (EM в2I, rixN!|1HD˛/h?㭽FojK7/ n˯oSn_xeR꾳Ln{ϽȠM4ӥ7պ%Ս ПI޺9Tin+ј_ŬjwWGA+-*rAK-oogN%WT]nЇipGVF9-]9߲`L0k$spyetR }ïs<Ј|Px?B!m>>JN!4yʅpP(K;ͭ`-{ͭϡJ[ V#1UUl~`.f8.R3 n=|fLâUx%oi _5dz@dN惄B6[A"%sGNFvX+vf)ش pF6bywcl37Hjȍ>{?$nZw߹&f0:ܶH6-go]ۥ_NϮtŤ*F[>No55 R.PPvg]Rq8qNDMDS+  &)++uDvݒTe"*= l)|fv!׏\瞵oۆ5jp3|j- QKOƵCR? qgIfgҕ g}tecpUgp#sD*8&92sO=t>klLODWIߍN0{Z` 6DTHA OTH_djRpcc).7i"m^z5}QO>؜TKg&Of~T`7؋H VoO\x$M ZYmricron-0.20140804.1~dfsg.1.orig/example/saccades.nii.gz0000755000175000017500000002003610403376112020522 0ustar mihmihYDsaccades.niiIVr1#XG;lOo$@NRdU]VWKVKb1o: 6ZI Rݕ? xQx/zw ]gh]߱n]wB~@_ ?z?O9~Է7 ;ӟ_;aϐ]s_[/hɟ'i'eN^w(l#ѸyUi,55Gŋ lj4T":%=_ ذ ?x(dRݓ!0Ե̩euqD}': #w|.KN<{103n yH~Z ਥ|gUDMQ3Y ƢUzk itƱ31F,&o!0恾F,nS.\KbcX&ZvJ8&@˱݄+qS' 'Ún |Qӕ%nS񏟞60Xu=:+Hқu%{ǟuEUTY083=3(W'2$ jktj-š"H`,6Xc3JUCh'9gb[L$(B5VS]0bDau)H%P6V*"wYTc)4 a蛹y2-`F{ ow~Ǹr*@y˔MOVԨYUV!9'Ly%- ?t'æxgiE{~QE@]E=9QwpҔx 'Ox;?l^dɊ{H J1ڻv;Z&:&+S=5iU%HQ5Y'N!$=Y T FYA5VKa)CV؉c5\9*Twi)"KxJ7tOuuE,,7slslkFyG96|޽D5%s_eI<$48 uq 7*qr߶\靝z"_gh3¶!qcQKf`%ttlAc]1LI~ǭc$ǧ*^j8_YiHf'TKdNOfu@봇kY{,yQdjVoYvˉlKxѸ)}1RϪZONB=Ĕ+?;PZanl(5l9R -26ENњl5ܻTE9۬H$ Lx\P JS&B5()4)v`z;m[ݧVė{(y!Gd ñX (b<:Zu3kLՒ eUs^ zǜW!8n_xП$V*җT폧;#H9C/>J4{GE6w Rsx[ξWq9=xh|!I^BdNяθcԏ%BjrdU˖#"1&.jKՐd%eE0 ee@ڭsKޕB%Q)^U0}XD/1}נv*2HQuE jonOx]zn4GӮeպ^=G]bh9fY5L.5А%Y0G 0w r940%1E`:sRű'ZRFZqp<=9o^wԳܝnp}P̎?ݔn}g+qrIx#I -#u&yV zӡ̃/mA7Ӯ^~(ԒN[ݻm㩳]YPQ~[*awR `VhV-eHx3'hj~+@=c\jEz7ӾnST%vΨA0lo9"_[R0V'{f_> THnLNg5:G{Wg@` v_] Gqxu׬Yg^?It]}~+znMUvM*84{4)݄H=tƇ;xՙUۧjUZWٰqӕ9I:}tV%p7_ZZo- $%4^oAo2^t E28L$ (@R* UM6 k) Awr{W,ΎGhG40N+omyU;5{H쒛EPݪg?L+oQvmoXY~dyQ^4Lu{^g4 k\u1USwZ18VfӇ%OokaJ7m$ɽn}w-%Eվ9U2dvҸHȘ\ /ǿTJ һ!,ߓO ^۴nR\lIWFջy*/C/0IKv„NTvAykѸ~`n7&J^(m;v3mm Ip`TP׏R^puhagMlQ;;K[:9NJYҔ9 qE@"9a0K@d(̛RRm+ܗp&(!W C* ;ȒdM%x1+KNwRfc/OAxiypr΍iW4 do2+c5kgU)m ) F6fݽe-jL.ʄmV5S!X]W >y%2VP& HQoj񥹇jSf jHnml=,Aj0BD~ʀ@inǰz7'=ܹ _,ƨ5z8{3\QRvto>IB?Tn:3~/+d/󫎙UV+ӹz;~aK{Zq 00zlYR]6JI#մs5GX<^ɿAaj-ޭ].iK0Gx@9mP(nԃogE`z鉷UЅenfHی]Mw}gw]~$vmsNpT%Qa|i#xѕ21L^\vdգʶ{(cB-S>zO@T$-`x~:m)'xuٓg)k4غ"ykDW-`Rg#tXj}6@YJiU{ƕ/>L[5 `ֽ2[u窆>ٮ';0?R_=לzo4 <-PH8:; [_~]Zw{gGǛ+a4z33~x_=b_{&x]GE;3q B}#nc|b|zdtNv{4tL7tZ0^{yx&}>?¯%:y%wŠr)..zN3x37D՚o[ b/5NahRDk(OՋjL=ٝ*u$R5OaʼnqcF""$:n^U !t^qT vcbfUMJt|"|b~7R2lٗg꭫w0^I Skijn޿S825Af ݀fyPB8]3r|&{ɝLg>= 5ѩ$g?:+a:3fm)8ŽڨNC;Nu26HdѺnЊW1I Y,c(6&lqpQbWVɚ 7IvӇ8P'KMR{REN>_l 7Eda*#b8wZC1(X7NAbXJCoCXv&'djㆁwB\nŷ. vgLzbTuZڗMse`Yl>3Jfm@Y z֥vЄJ(aϵA0/D׻G7=Nw#jge}w^|Rj.t 'ꄍgr3d{ g ¥#9|dqf81 ' ˆC .Ժ:"e{IHZSb?e FJ!c Ml-jEtˑK렰᳨p_uxZ-/دZ=F.Dn߽\;w'LZ:6“38> &|9_V/QH#NVU,ܜ"^wpm"6֬fSPh%>^/8k ~}*rUTW2J;sE'Ps(s(;Gk#GyuJ(da?no~֊Cq}9ScK7SDX څ@Lյӕ $L} M>i™^\-U+QDZ,V_~ hbM7Yվ8PcB|-NK7Da)W( ql'*_}$]~xT\O4iqO72 /P6]E| {cE0dkMkiwrCqVqT~vt پTKT =|㳲 "/~ vb3=j% Q7 O{?=Ӡc]z٥ѐ8hHc D3Lb/4RIDb*R]s51FcTܨg'/Z_oӍ;iG_/u6.Gǯ%))݈7w ffebĂҶzqlٓ= ;N;F'8b"8,u–h|8ljO8"әl s]S FSxE@91oF"٫q$U]{Pa!r#sz-r5QĞ>9 o հ՗=cLjC߸Jg.EpROdxU)Xn_?Hd$)[pGcn_JXM 06le,V&Q3jZo=T\b2sLod0'BjVtgfi=xtBºcf5gg#^P);8mE mJ)y V)j!Ec[a5*djGX*VJ~YL>?q? A Fw")yƬX$jXw:dq̕Q{F 5 +&#+LvaՈ`U1~DKF IKZ0"ں^8ңW?rHlFi(ҺYrs?l"nǹZ;:|$,7tdݭ1s p]XNH7 X9皓$XW6o6+;F=g3c!<]D`L@X;k3*ՈÓKtl?eS# j7JjYtU[V-LfG$M%TW 9fٜ:Nx6]. }Q'}l/ԖsД\Z8gcizꘆ_+G z:A8Nl4F)iQsw(Wa3?3KZYmricron-0.20140804.1~dfsg.1.orig/example/lesionm.ini0000755000175000017500000000015310320337276020007 0ustar mihmih[STR] Slices=82,92,102,112,122,132 [BOOL] OrthoView=1 SliceLabel=1 [INT] Orient=1 OverslicePct=-35 mricron-0.20140804.1~dfsg.1.orig/example/dataset/0000755000175000017500000000000012360760642017266 5ustar mihmihmricron-0.20140804.1~dfsg.1.orig/example/dataset/binomial.val0000755000175000017500000000047510513251350021562 0ustar mihmih#Version:0 #Covary Volume 0 #Template C:\template.img #CritPct 16 ImageName Cancel 1.voi 0 2.voi 0 3.voi 0 4.voi 0 5.voi 0 6.voi 0 7.voi 0 8.voi 0 9.voi 0 10.voi 0 11.voi 0 12.voi 0 13.voi 1 14.voi 1 15.voi 1 16.voi 1 17.voi 1 18.voi 1 19.voi 1 20.voi 1 21.voi 1 22.voi 1 23.voi 1 24.voi 1mricron-0.20140804.1~dfsg.1.orig/example/dataset/14.voi0000755000175000017500000003616310513247662020245 0ustar mihmih14.nii]t˙l1 K"dq(,Z0L@L~""ܵ3'}]-,K}WwZe)\.wO?|_oo]s??__>w ~_O.k=+Z[}e'6Fn.O|Il$6w_n[ptTubst$ͱ?V|K¦Cbt[3%VGGGU}F5:DyPGy+Dgd/}ϰׁ!Ks%nno#g~?Vg|CZ]FeE??2W<$1W<~X}KG/}z+*bb.//$Kp+0?V5TsW<*YiE_\~R:7}&E?Kbyb:l&2zXkR?MdzuQ~&2:sdo<>֢;[Kn'KlMbEt|y X0+կ:mŢWM$6VꮩꗊVљիf";<&D_uB觉^+ <ԽEZ\uky-)v辸˱yu̓4?IzWtvWՇ͕_-lYO,/:m,9c\k*r#_R ^]6,}mF}4),-i'ѷW>ւ?[ hliYh^Uߏ]=h=[=.[=mD?ET.,3Y(,&ꢢGW5 WUKl~ \+/5;0xx:;Zn-(3ĴE%6W= ؼA ݉>.]=j.]=.zUQǗ͌AO^}ab,y"9ѝ57XՈ r4Zѣ%-]|MGT?O[Hfvf"ûOI:%E&ֵj\z]y}aA3q4_.ə#ч-gu~2Ȉnʚ;[6}zu(1$%IMBdte2'\s0"?b>+}D?M(, _-qO;;¤ݿ Σ,l-(]z\zҜ}umxu fs\5:x=o^ysc]ugQvbN;ȋ|mFF߫^ח}ƪ nyzzͣJ#`ΐiiٝ}BŔGzEFG~ns ]dtΝK̉GJgݽ L9&t g`;Z5s 64IԼKӆ#!gͣWͶ7uM rkKl4~Qmy_e]xfD?˨1'5ULF!2>illCu7UD_;UdѺ纼7yO<;S_6k3.֯N5gF7Do_]ugE#GFtz@IyԿmhitA}֢,TmFݱ#.]*jUFgVO<^uWbsftzu#"~IG^f<叔?WN_sҷ Gm#f?h\:1N}̋X$l,}b 7 ?gG5^{ѧo-+^EeM森Q=~Z]9{EFVWg=|F-93:ӥsDF>E͑ axni';W[ ޛc>3&V ͢VOEy蟓}~t祚ü$75Η\@~>w܍}kids\567tu0rudtf8rvf0 }\LR늌UN/2Sљc>15HZeDa!wi_6>9=3#zuw V0 ߟڳzGw?zVO^溋f]z]z\7wjDt{ Oo?@)ND bm=v0:zuKE)ܙϨ>[L>ur }|䋌|K0;VŤ4_"Jτ <67i2_vINyH:!Gv3wֱ^s~tAtasYt~gVLCDt{ =/]G8FG,|]Cbs?zu=/4ūGѪ觉Jl~YyTe?\wyݩ^]'MlLs.?u;4Lذ6$ydwͫSݜS8ϝ0\]<{\{]{]3}z}i^xR{[Ruǝ)Hlu Fwuo|\QtC1fiyG_]66ёSD!KG6eejKl5Wf42㯫sҟNdVIl DܑYH;9(ܣsvyL9ӛW<*l? ƛ< a}keL'3tO+F\Zt";+G׵fsfOӝECG(EwFO^X7һM^KTYuwёA^NoV<(9uDN 5o{EZ#?zl$U8ʬ wgise 7D'4~j6oPT,%XZ7ys{͙E?ɼfsQdV,?lc+`WCvojGK-KݯG> Uɚkꔕ5֍>-8tO6N=RSTro*uDFG~9^5)93Tўw!^B(-2zf6-z6AAS5_2A"wNioe~W1գՉѓf?g\:;zUs\d%2z<两OJOHb%yuatǑѕ}|Ə)ѻĜ¶Su;6o\v/dB"ի"#?6SXdtWGY}L3/^~}3&ɬl"+H<>3Ҥ?&'6n5W7׎46WN46եT;m/~}kQ|Ak7^-]gE7п[V s{/+_y@]72*7w V~iMfzuXbp.Ӽ5mPuTGgVWMgN?&%9i7KDgwj!Ivj{qlN5W7׎46WN4>EE} nV"/EEݑ旋~O3.=vKkuagFFFW|,p8Exݙ/9"F£71ѻg;7T]={0֫W; UnoW}Yފ6v2W;<3UNjydu}սуՇƈs^@9.u_ͫZ=E{/W k_ͣ/s,<[]xv`tJ~;%E7&nU}yu#^긡Y궉a갹Aꬹk.rի^Uno?AYsdV\$;3Lؘïori{sV'i._ͨ>n@tg(Gw'9(겤FENQ%%eH7=X}lާ~]uݻcQ}Xz\~{ D,}7Oa[=ڽ{y}m^:ͫW ̫W #ի&!чw)ѻ7w7׫^}hFsdVG(: ';4 鍘#oD=8&'TK3ݙ).=J7/{\my#8>rt׾J{xinۧq#ڪ>n7qt , V~ikdtջqYKŗòfd!"Nu}^HuS8}];,tx\zoN ѧ2Ց)*#{ c'|G !_ovV&DW~to G ֡9"K~np$lԧ^^JvX__6t>0E5F"Y^*Ł=]=z)ټymV]5{חY= m'}u3dzPx>ՕR9zRw^Ĉfx%dE-} }hꚇ}lN>FD׷~tH\3I9FƦ7l.\s]N|~ŵud꾮s{h^t+^r7bg֎>==>ܸ+Fڰf 'df8Q}ʋUV]YuIuQwY13$NF{D'K:&v lɻG͈N[7Ɂ{FAov!v9`‡ͅP=kˊEw79NsftҢ?8ݻʸkWzaq]O2nd;]_J/P]z궑sfWǍtRPb92zuH`rdTmޗ}M]k]cpsծ9Qx&"/o%bmމyPYd%dy7/E'w;NHý%"κ#2!ɏM>yÂ=K{LNv!gvoc&Ot/]x8z뫋&ͅůSi $q#ɷGK{a!mw;,[=(^=xtPdt89;ڎ@NZ}Y򸬇ӫ7QͿ -z53):r~ҢG|ޢֻ2jGWG}9wyPdWsAH<6 ÂӪ%Ftx4x:ѽv{乹r뫋fzկ:'EWY蟔y^o֑]3vxtZuO?-W;({A Uҋ?W}PZ?z7a_[zm]Ȝ~W=[]>3tҏLIR=zP褏k" NaG&xZplj2'&v:[)xx;zquL'|twOh+G&:aI5ImwE_˂iψ>եTJ7_?gdV,)1si@uoisO/-+zvS2x[u_X~ϸڪ뢆NW=}~:k%LIR=:>KdtmLfxmG'˜xt`s݁ˇw/ܝѽa.?أՇC괡I=k.}imsї~ꦑC[N.$W9`YBowno s{w՝ά+Kɛw͗ǼK{zuĦ2a?}vF5?u˷wV1&m|tSdt oWUܩyg'pxt`s͉݁gwW'~y`cc6ao^ס(2;1m LE[D56kɐ \- /nkV}~<2ӭn}&_ӎg-=;~{~kF[ΝE\՝<]={Cd;mG\14ܒY=GwXK9ߜ=oubsL2?FF7cg~NP5DFE_TL=;jΖ'g'>=yKXDVETo9VY ިU'N5D?ɣ7Zҩ{_ͽM4tNH̞}w%ѿLaD櫢3GwԊyU=:f}/V!4)̬f5%"g{ܟ`Kc-NzF7Պ}yitkE>=,sGw&aS=h.Ke/loգ^}ч}VXˏFNYusD]pg6'g^yO gcv={7qgщ͋$ytc٧<}}k_^sVtt<".n讗DFaQo%6G~h%L>>4IX3{}݌ٯ*.*.*/Z1#+1i0shD߾XNsR]/Cݫ,"D?Wnj|c.ӭ:9K4?&-v!'p#QUNT]D݌٭n٫+92zt> ]яS0ގZQDEa":^oD+Ȉ \{9[ٵ2ZS+koYoHRU>T+>SV]Svʫ5{F5Ybz={裈>Jbszt[޴蟗qi]LEBW$D.Ӳ2c;UOrfG]LUZu=N٭+0:9{tGᥬk[^D8ZQ%zt{ɛ9$6gM_$6_Wc| |񉪼 Nl~TL^1jQI>Jbs~wӭ{tF JsZ]OF=DEa3W٣cKl> L>Kl%{ޞ`}GHF$(-Hl>e-zߦTyYїت`>EFd`*H[q{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/23.voi0000755000175000017500000002633610513250544020237 0ustar mihmih23.nii],GZ K\"dq1BͰVZ &[2*ωDz;|$udDV/~>L7_}?|t鏧i_?Mݟݿ_o'ۿisZo߷_OPU` w9u;䄪jJxt3Ku~NwIu;䄪 ,#E+iң{<]{G ?7U;᤺rFU^vU`uVWV=DF{DθrT{<ݪ{W 0]w)X]X]UUh_Md*wAAkǏi1EW欋UtCދ[u UUWVWbu%VWbuxtPuUb'鎌NY!mfbt؎y'zp$wa͡X"оUWo.CNUTb,:;FgVD7)]3}T͞1׹k"2!]'0y;wK%w˽w!QKls2|>U NkmUNvU^uսbg9յuBu%Gw7S)*z?W3!5yoͫ0~eO~Hlު]t@XU`r-+G^1l]oSHJɞEwkՕ3GVÏzTGsz/S/JIUUT_.c0ښ`ʨn#5UV7A1{Nնn\#eԫQ>OH7oyn,ƴsTXUZ/@zӻᬺqJU`u%VGD_jC߰'ҶznގJmQlEn:$2zJl)'D7E'۰H„ẅ)4϶Cbw1SHVUh"[!J^V@0)XWW-"΀etB^sKVgDʄK\֤g:~N#zg=7 In;CGcp#waGwYWyVUN8>8OPmt-^#eSϢ{}&Fz.y;w+ʤͷG"5yqh޼*bڬ]|)͛`聯Uuc߅^?pZ}]qNFWUWןCZD'̽veu@t-+|DO{p=~~tﮧ>Oskye4/Ngi[]Ĭ1y7wsս^4omϽHlKty]%*'{]zWR]X][ՃZDݮQ/T}lE+0{[E6]O%6DR.&y|O6{ ^u綣{Wi=4oϽL^k0W"]ت쪼ꪦoAUMuڈO/u jQpW2:vY[Q9ͳ#&yR<=ԣ01:y2{dΜw{GtLj^?%Hl[7ܻ䌨XWջVNv-r^]9ՕX=sT^G_]Tg,6"NhFDs-$6W@Nt-y{LQ.;g=8OM}פGM:FV_@sҦ1~"0gTou_[TΨyjL:r1ͫEݻ爺G5?ڇؼ;jӣ*yh7y6ovǮ^E_:q~ xA? gbHjElYurTo)u{+kѷQoDG^;Q&\ {k/搵1jcM~2zdGi9RQNid܃Sf"fջU^]ՏUߤfzYW7~D]=+]ճe _=+vԽ=v榺;A5bnNN8y7|!&k#sq$)ɖfpBGU_c^{u3U;GUQUUћg]z=hix[l~ZEtô!_G.9!9[Ֆbv%Q (-Z] s34QGUiPKlUP>zYW|k}ww}RGGJ?ɪ}щ͑q<^s$6gD͇YwʨgjsFIѯMOܛ הk⽛w|>o,j=;gLb<&>U$6|Q̹5NLUwΈ*'No_}} mf`^w';보Y^qfa:{F$6gNǴ%cVx Tu\3֬;eZ[w?I+<]$6-;룴Yb\D!gHhLwѠzJف J L|xNVeT]WיώO>FwTEOc1@b~GI^+Nb3ϩ;dܳc.:zm:NއE~nr%%y_èpY`2j>TwȸTщ3UF))mgKtwe_jrAU^u`rnsF[i&0pY`2䨇kJ<&Ew\MM q{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/12.voi0000755000175000017500000003216110513247572020235 0ustar mihmih12.niiM,[Q+EJ4JGBiItR#`,4`9 Tf{Z++󺙻Tm;nmwo揿O?ݶz?ۿǿ_wwoz'F?'ۼsϿ߿_o_ Q%ZV1j-hKFsRlZڇϨծ@*Ebu־Ku1FWX]c5?ll4oB|/R9::jZk ZVzmiuşD矘1˜ S` V0L.N+P6.tl=*FWl.[)֢ ~͇.VÛVpk`uXթ":O$0w).C`+E2ͯ2 L~(<{ .FX*|3vTyT Ztg77?TYCh*٣} :+ۢ:ujsGϧz55iLVCG^šwxw 3Nn*Ll:>6](%-X\yW][赚Ok?EG|Nk]t70SH2,ct϶]fi\K^=K=kGɣG٣YtcAΥ~>|)/VH+L~<k+"gљѹWwՕz 4O[k4ڢjVo5 }mJv7?7-wpӵ:na]zt؜v|9zגWqmK=ĵN`R7Ft7UtEXEg{Ifяۖ*']iԃ 6۬@κPytZ9յ~sbC{w9wJ[l^GmUzOE D~MV}T豭Z衭o.Q]"9gtTѱe'^uU]$9a[[E?_XUsrDgV΢6wo Dt۩ub4:R_g-z^1pۣ UTB[V TkD bLJ4'ޥnѓWaZ/2nW$z\,: $',UN}0gd}x>.osnK0kOTt݉ͫ M*6W{E &onǿ0gjke[] E?[+UWt/kw-ݱmziG{Җy>y|Vo6LJ]_٫_GfzM󕿥UN}0 чsa;^Iͪg⩛] &ϣ.}KGYtt * Ek~dR[Wi~ |z728oo=NDm[]q_|;^]dKF'[2*tX8KζK-sh>g%i鬖n[|g˧`询kh*>@OewPTSK$#Pt{mm84i~wt¬9591:c.J3+1{}8N)Ϗ;5Τݥ|x9,(o ꛺m/3^Ϣij\zk/z/ԉޫ,Tl/eh.]ÉتS.yKQ-WX b^Z7v+|y6:milMJt¤9}9{히Λ+=/Ĵ\1:TxU}ȤîG~*oFףCz壍܍q'Tl.]r:Nֺb5{|4+=qUlNJ_( Gş/m/:GeDgcm54?V'g͢WI/sVF輓=޺tf͉ihnÓ6VduCYzýP胊͢J>6ɭF>Xx*0bUKFY;ߊyNm/T2zK'鵊0*CޯҷQtҕIryres.f}sY׻dXgїɪ+7lVEwFdԗ}\#p/T&zdyutJJ͏J#l*.P~ZՊͻl|+4,%2ok%tO;Oz`E!9,9{9uYdyuet{.ojxLSV W}/9WLѷE=EDTWU*E?{jEǿeIgEdQ6o"No朅׸UWuJF_|ctw`P sg٣͢}趥Ut?NZ}ZUosUm.ݹK*\%p 7r;:YqRяJϦBϦujJ,o辵M8ޖ3Ϟ>PubH|[挅FWh_TG7YzfS''?ItmH_=K.\3:yYt3Vi}9[u͹+FEh;U>?.[tՏեOWzލ=_CezSח\;_t)液5ؼ~.mdtɿ>GG]ڍqdS֋6$5g6g/?Λ}<9eUro5g*T{X zSf>Gf?|?:Syh^zp#3_ITa(=}wqɕ޲7g뛺 ZxщO[iΙW{=gl>^xQ\֕Yt2[_bOMsKE] TϚg/SgV5g;hN}՜9_Rj^z\tջRѻ9NN^ua{KwG'[[뚬g,|xQmuԿ$ lE,Vs?ke{,hGtıʂkާmúq\Sqph[hM\}2媇+;'K{}JFgv>Y 4O Do%@#?<~zfn+=;|uPMǼsR9\r[;ι.MgϣgSW/Ww5gɛ^!~)t=.o|Wns[ÜN˂gnFxaH@'u6Nt{ɪoF窾]:Ra@=m ]'w'M7׌Uy}@X]yUnQcb3W^t-mtiҜ>{ޜzzzҙzi S!~(u}X[]o׼{Mhd2^8Sm3Em/Vt{Ѫ7sUߍNU=t ~6H?N[n+2:c|բʭlwV8bÉK=ٿ菓!N_aeg&u雧{s:X&&чDZUV-z83#kD5Aq+CfnKf[oXوLb+]^u+=_SK4|?zrϟ:2Բ:2j La(,м 7%H)m/:֋6$Ȟ6'^45jTYڣU̥SgYr|d7?#Vt^4k"]ֿ$*on+OL˞ñdtﷳN+]{ȫP=թN^ H\օ$2¢:2|%hUlw͵7kniKյg"sGEvDg%_~>Fg݆TH]vDnTteжdtDuw|.\YՑEL7{E;* 55WTBocs [֖yF;NzM3ӮCεtLؙ! OuMuk3U[QOzT,b3.jмиcZdtQNH|=Ͷ-w&;H`/P0y?_Ok\tk 6&KN6`w6:neZ&>Y۴gvTa97 FO.4FocϳKoU,:6oaVpW*M}^vfC;[+s4ykgՑa^iݼk;V}acn˾͕Ȕ_`2 -: Z]r_:7oN]1zٜbIsj_bis귲]dmG-w+7ѭ?Hi^TG1nZ{cXu[_sOWsӡ::{TO* QkEg|Jۉn ɫ͹+F/3W*zCutZەn>墏Yڼ::¼:BVG7Q2xVi.m١;%н~_k^Snk5^t CsIsisJջzCutةCeUutֹnuE﫣 _i=zm<.^׫]::JFeZk Ck{17Vn+TE~Tn+rѵբQ ]/vRS[;|TR7dut|Zt'OhMWVY^anؗ>o;%kmJFJFo͵#>5M3R.Tt֧ZQ]2z;{=8$+lxq{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/13.voi0000755000175000017500000002374110513247626020242 0ustar mihmih13.niiO4G^`8%Y쑐lbpNYX| U؀23*kTzJ(Y_-Koy|}}/Wo\O߾\g7wof'vrwr_Vj3Z^ukբG=a3߈0T;xL;y@kyխUXnU9"r##O7bgS^P}xDkiKsLvkyVujѣDFoTWҢG|#VWt):oiN#ΪCZXϝJuVuӣcν=yKbtJo&ТZ4UҘ&k?%6ôwhSikYo-,tB[dkYշ sƏv4W58}ݱ|}*y}]DZ*z~[VR?_0_ǩ]'~}LlHl<&&Ug<]TծUVnW:1UnT_sg#o<t8.(:A.빮^շ^Wzڜٛ3Jlz~qݛѼ\|A&N#.Sjתsi[%'d Ӣ?ρIK}z?nNբGIlΌ^#W:&z:'2z:Az$/7Չ<]TծUnUݷJl0,\TٗyQz)Z(G=EWz}a][7o^6/A\_mk [fΪCk_UnUjhzy橫wgN4[mDG=Q"#߈ё2#o.[շQw}DF5gNYI`2/TG<]TnUjhzy橫w'4gFO[mDf#zC8Gd3os S,$]^1;YuaZu!Vu}ɫwm:1+ꔃڭVͳgo'] Lڵ#Zu]Wo6O^>]TծUnUݷJl:1zy晫;͢J(Gy}͢lj| ss7"#o+#Ώo>&:稏ҔU~aIuCEuQZu!Vu}ɫwNmZ fO%zꮮάJ^/4_.E\VJWGw?"e9G}iUg<]TծUnUjhzy湫wg=QwD#zuo@|[A7EvQ]i3.SjתsiX5To4_<{ubNբG=JbNtu=Il^EW5%6&ôꈇZnH^5To4_-z٫ 7bGXU]]t@BgFgIlμ#0vV۵cۭVՑK9(/:p{D>ɢ(MJ^ϻ&:ț 0vRvV[˫n-kxuA+ &6GnwK[TY^ĕ^"?OH]uCZ˫n-D q#rO&$S@T jAq{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/24.voi0000755000175000017500000002255210513251322020227 0ustar mihmih24.niiOn\i4FbPL`LND f0 &K` HNۮ:;oy*[JoPgT_o|Oox^7ӝϧMywM~s0oko__?|^=7o߼~1N˝~y_/r;Y]8***ZYD&9}:D՝TUWUWUWV>賈>Mbs托9{dNy߿qL}0:dzltNUՉumtѳjg}13:rʛ"dn#ݪf Չ EEYD&93:rȜ2enNqD=W=1fys@Rtբ",O؜T=:yA$6O;E`2p3:1;UU׵A;̚3W/4gFw^l^ݻz-u賈>Mbsft䑘9en${t0MU FWn٫**9!z֜PМ>{9wJsэE&Yy3GG=+9swU+0bW膃!#[ʫʫnG^h1,5gFw^n]ݹz=q賈>MbsfZmљ3SP=:hdjtau1:1;UU׵A{̢E ыݻW;WG7ވ[}sm#o?qtں3qztֶAoztSGyjtQuot`tnUyUyumtբO,#Xnݸz#oVtjgi"׫GmJlΜN376SbSQU{;SvʫʫkETϛW/6oDފn[ݵz;:ztѧIlΌ^%2zzt3G'|^^1pT3ᠺ7z0:eꪼ6:hYsBBtբOܼz-uzt՛]VGFztܚi"׫GmJl^̍|"8.FGTFwPn٫**::zPܿvW/77^n]9{#oVtME&Yyom)9t{gգsv+Cʫʫ+{nG^hΌ^ܽz%wZt}VoFwբO؜}sg ͡3uN9{&U脃]FVW]W]F17T/Ew^l^ݻz-ujt}V^t&2掗iCgezt}_8]mUXu=Ddד6:hYt@9z){bskѭW;WGhݶVoFwގ&2:xɌΜ2geztzC}bt~S]O٥cP=oΌn_ܾz9yZt7ݸz#oVtM#oE=:nUbsft̴V=:͡bӓ)ɏ Uuw_9}g W/G7^]ݺz5szt[m7V`td57N=:mCbsx\=:Y,{t^oޒǁ( j5=~4 Já¥3#AouR{}2*/*zQD/_=j^> z襫W>^AՏ~judߏ#љ;&ywCQ&v91U$\U]K1/Imt6GTw>^0z腫nh?J$6gFgN'Co9STw9\w!'ԧyX]ΙS[Av ՃkW4]}rŢ~g=^:2rbw͙ёgo7? [~s_sԧiUyյ3eQ7dWG/^}vQ׊^8zљiDLbs$<鍪&$6請sUw7TKԝ2_9Sj;h.:z~yqW^RKgGa_&Z;auwҌۦ;愼b~/ԇyUX]X]Aգ嫯z>^8:;"3bIo_4'0.0x}8>t̫cfU`uU`6:zPoE/_=^zxQ'e33˨;iBb;gV`yKTw7TU\x9*+v&WF^=^ :; QO%6$6B/VUwy]CΨ )]tB zQիёQDF_fNؼΙ| Q]p^]qN9*+fՃGёIEFgnzz; JFGd#fDF_bΙ|rN`2o;;⤪JcfUbu%V~SNHlΜ%UuVw'UntXx%V~>Uwkq{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/11.voi0000755000175000017500000002710510513247522020231 0ustar mihmih11.niiO;uv셑S pb>Od\@rob3$OUwSvޛ|l7@_^U7O//w/Wo7M?{\wϯ韖?Wo?/7}5'|7_+?}?z? HEX-:Gh^uxR+XKZV::弒S暇TZNxZ+ZeV٭nb9dTyV=Sh g蘓^U[z1-:嬶sN[:c]"dt::鄒c3F-9dܔJF@v]sN[:a\ZUpdoD_p/Stdz*=RDo{YUG4*Sa~(tn̔tnZtUtsLtYm+:P9}u9{uAsj/2l\ݦYdYeAutՁyfEutԡ^utӱmutS\y*4 %v %vpZNxVxJytB뉎:m^]1zМb9sumt2H:D4+D_&$8k`NV9(xN.Y]ТSjK9gCՃ͙?Vsyae`uai:8n2Xvv++4o6yU1^QR%O*]:YefiOj)g3VtҡNsnsAsaswe^uU`u`eam~aJ\9-~ZՋ*ѝꨒ'MuT3V\)ZN9-EѶuWwWSWW4`iczmuea^֨>揾ةYsփsffT/wV4oUl\b3UMtim):猶t>{Мz؜WzWzVzܖ7zwIVw]~}ӑk+\yQ9'-{dU؍.6˵ιK{A4+K)k?j)'cՃՏ:Ջ" ;uyw5iv ksU{ \!;Vہq ):c[^ٴ _FoXrGe¥ͳovi#w7f9'Z:.l2mSֵkmUnFg߈뇋gQ=HF漏w4_*jk$OcJ/'SNjkA6͹ɩmʚ=[:+_SzQ 4,옥^dW>&XgeA8|;=ay]mt'\^ iѫ\N?23ݛѳ3m鴈Lb;;:G_.;nVy]鸬'thٞ={{ը^~WyNsz14BX˅mwq}12mh0 )q>{Sj(<8d#+#mtd^nyQkXر}++=-NDEF,077h+Ҽ|[WGUi݊i;'[:kx/|䍞?Ti^z-E7GR,`rBѵ߫+ ~ܜ .re?N9+{Ñv#{[~9:YWJ-M?ߏκ;Չdg3mvRAutԱW>zEǜ5L^h~r<=>Eg_a-:cas%?ќLs;Tsjѯ"Uƕ%'SӜ10:bnutXiTx90m9Ugm>8A*6#$w͎N:`Ubϡoo3-'5ͯPvsttD6ggl?lθO4ޛE~&_TsjѯrY)zr`aJW3Sy̋|! Ӡ::nsλ{{1kۤ*6O ɫZ]bOگow%V.UnyBErbBtמ':n/Ir:EQ.6o.`J8gD\"Ygm:1@|Wz[͈~u' Wfk.\v6oDZ|R=* L^6öެ}m݌oy%6/cj%60ѝqF]uVýɉ_W?Dm[=gNՉѻ3V'FhIlގ[:o2Nw$z8=]F|UƤCؼR}7ol5ze%Gbsft̽YY{/n19 D}8K_ꙟzmyc;sV'F6GFwh~au+bV^bD'GVo7Oܙ!n6."?.:B Ͻ?;j-4&-*XWw Uqѕ|]+3?Bk _[Vl6Zu<<#y\ݴ+y2譗>dC37Ӽi^uumIշ3ꪻkLNo韠6tڊzy9EIbD?h[!ѯw[vLx'W]'094z8ho]}w} Ix9!Gw u]rXi~ zh][ע5Y[޸虇$1zyj=Rcs"M^'zQ:5"7?+yݴc^kS 8~tgQ]]Uy5ݴ'92z<}8'{W\D4ٜ1?@ac5:zMKQuwРUJr Kw9kʋʫ'=G<7GT'F6Tg7O4y^ =~{1n xwF_FOYs3}ʜ{i |pN8*.uTW]PҜ=}+ ZǾꕼQ$𫌭tN_<;}%h[-QD?LbIlΌM3ѻ]ԑY'7f&? L$Iu]g%[1ȫ+EWo77NkΌ\ݷoG9Z-Q.ݴ$::o[`z۫~Qu۾֋/KlެN,A wC7[&=F^msBFs;ѭ3W77lMGCG:nZ}՗Va.]ݷ-2`Hn|#u11!fȮ,3^Tgc|V]2mU3gܨqۜj^7toGi[gD>jN~+ݵ=E?Yt #/7%6gFgN#瀣͙W_`d_T7g|RqEuʬNu͜1oWٛݫw3;w4>Z}ܴ,eG9X}ݰ:2:Z$6DYuওmc u[͙LK%r]sb0Yu]ƫyI)VuЄUs@Fsͫ[wEw>lZ}g-E?itWW}Q(ksf%zy;$6VWg L~$0FuƋ{ϪKc&W=o7Go5ގ]Ӝ9mqt+FN>kΌX}LD(3ёՉkPܔ|R]+:PbNuuԹ'ɟ|^F?>:eqcE[AVf_Fsfo{ѭ0kqtՉ\g3W.ݮ:2 ͙̑먺:@byϔydެ? &佊~|RqEuʬNu͜=nUMX5DGo4W_93yatՉ͗\ 'UDά0͙Ձ[rFg2GWbnuu֙'yoC7[fW=F^msB9z}Vsfn92:XJ5.(n}2Y]aw&?+&佈~7ިn5F\U4aPќݽzyN菶,%F'6Gwޏn\}ݷ8iytFnW}[&93:pSbsfquuܮ%n,rɼYW -|xU2oQ2kq:hª9z93{fsջ͢?~sdtuفk=VG7jtv׍V}Q؜}^])93:nWby7zuydW*=UuȼFuˤ^uΔq:hª9z}Vs;͙ѝw;W'F4PώGۣmitĵȥnW-Q3#oEF_I]!93:oGbsеw׺yɼ]=? K{ǫyYcU[AV͙ݫ7W4gFwm\}ܷZFw>nY}ݱnY}ݱ{'unsՉGm/4,eitF7W-Q\3c̦N\:oGbsHyzϴ]]u68 Y"xQqYuɴVṳ1ǭ usf_Vs͍/ݵkIt׌X}ݰZDF_QcudEwuu尺:@bnuu֙'hiθdq)VuЄUs@YW>z}^t՗n[}ݴi%[VFw>nX-aE?E7u]}V]-2:sz9N;ؼdWGJl^2o֟xV]q:dxeycU6'D7E [V4gF>Z}'=O;VGF_tTn(Ѫ?ytduu3S 9'TWJlީ:$0^znxQqYuɴVṳ1ǭ ubftՉ}V_0iItkD/ё+P}-a"/yۑ؜9reNYg&? L4FuƳꊻW!-ȫ#9!znΌn_ܾ{/snsՉGmV_#zI\hFDVGF_Q]#9tzwN$6/z˒pߔW ߶:>;/Sfwkq:hª93Fs;ͽwW77\tȕ5嶮>\g-#IlΌK͙ycdB.w@1 5^Tgc|V]2m1ȫmN^7gFjnݺzuon\}բ0kI#aD?LbsfQuuځv:\`gy_;v8CQP0sɎnyESԋs]w ;尪ꪼZ:`nފ^tWtUW]ѵt9z#z|Vsf{ѣw'WGϭ~<7:rcFO~Y'2:93eԙ+WF#;头^଺8>tWtUW]WlN,M^ëwGW5ޏ\}ՑљՏVGF_N{ 93:sۮUbmݝsT`]^1';zӝqF}.99 իФꍃ_=:1zyvnEά4͙ё_7V9G&LVU UUVXuF׷Q]uՉë/=z7zrudGw#Ҍx#Gw/7LͯUuW/NɾVVu#V՛ӫC,z~:-sJlҶ/qԋMw ;尪ꪼBtB9z#z~eW~˼yI$6gNLipK\tgQAMwQ%9jetDg,_Aˣ9&2:;dUUwY;㔪jO|8Iwv&Huhq{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/3.voi0000755000175000017500000003142210513247106020145 0ustar mihmih3.niiM4ۙ(%Y`tE Q60B&I BY+2:}>mYzcED~,7o?~~]??Wl^~g>~~o?oo~n?߹>~?WB9Ievg쐏dW6KrFώT`2_Zk>f|5E7EfGϭyOMI.zjǂgW|*6zvšr6;cjvƇZbv˫nKkIc}l-g1zr9D zGdqg؜y&q3yɬ^PiMnճK^{6D"#BtFkn7!ћ7{S{r;fּi[K]btX)Jʙp+: nv'ZK̎nKdtPu^gD#ч% g&#c=5鵟= HKl̥^ [^qͱqr hNP{]򉖕}lITLlZ駘vYCq^&Glz83^DLzqYIlάLNT~qr%6;Cav'ZV{bR#%U&/A2Y1-P=9!22̬s-߼}Fj7gp%x#3zY_ONPI&lZ8Wt!h-*Vْ-ZPCbsP]1#zQ}h -l4D>Z~k7_.=;SշܥΜsC>qm;d^_DF߫x%{e ~$U`k!iEˈ5FFGT̰ݢtp ~|ŴW\9]u zG|$^)H\'9}t@aڠ%2D5/v5;mւd?[RC ޴DM^N*1!]{%Ey]m}:6im^V3^󼞷 6Eol3^Zf&ݦ7o/ͳ4"z}̊(]N8vfּQu9|Q"z.|vˇ(6;cnv{n-(ZR]LTo2w}ч¤gWGoϋSӆgTuaSĠþ1n71=饶lr׹Nu\zvשP\%D?^$lwI^3PS Is52~=; ˥]xFp Jl쎏)UGak1٫M^H/"},}TKwYâ?G6ѳqe'FN׎Aױ^}2n{XfGGTJWޒuKj~,uPsճ[;xHfE_v98Iѻ[`yvoOSZTe?r(p6/#zߗ} 5mG_CkWc׋3KLH~WѳFqQ.ݼ"o=7~[]B50my)csϜJO:?gW=n-zǪzv3¼N>n^F}DYѽ x5_3=~Y5t_"[Te?W}1ћ}_Bt'|^7m}\7ЋeBy}ѳF6!/.zABmW\ic]mzgG/՛/і}:͑ѓJ'/ ώyf,LJo NۧoD;O.z[J_]^10SsGmlI77Գ.&yYTo2yψ趬vfڡzr@'z="v]ۙw=n`טӼ<8b7Œ=8֏'>{C;uUѕхOV.}|kluCMVG`P!DFw泛ޓ77=l<_aG_L5u2zSRPvћ՞vbw(Z6zѷY6ﶊ5;ndQY%+z_Yv<֏46W хO g4׭>k}3lgKi}Zߧ7=ms49]~~X`VgvFκ4}κZKl y{[qSlݘR(l.wٓVu}#.f^ E-w}9#{6G5}]opի͞ݶueogyٜ^6/TlG̽ gENGWilj0T;\&.zǡzv;{젷lě*nūGљ'ĸ3UbsSd1{vϛ"wD>;-U ^UToCԐ꛶s8ΛKZ/j_C\<{ZF&]dk /kfc{W].|vWسRx伾(qtt>mF_J]K=;vIox?Eq?(sKK~쨗CnÏ2ٳsޖ u&E?;sו)[jHE7UfN*To*[H&]vv]u Q~smUPtz ^ س_t5sq Wr`kWs$zvܙCkS]?sǒPzҼz&׮_Pԟɥps)1*&9[%T~$}2Nh'ޫ|ݗt]`B#~FKd$e?CW.Fѷfu#fvlz͢ns]+ULT^zm9k|ՆsQouD;ӉĜW у]_8Ӫ^|\9Ioן٥ps912*9x%:{jx<;Yw&=~Si!3wDM<;eוk܍HIi:`-IEoEVz7cw.x]Tt~.WÕ.}bvPb8zvؙamnE޼W:__΋:[Vjj7 !Bqx!$6/㛗$6/1ȬG=.}T>,oe=;Qo*^G!nr_]ҫKIl^No L^ճ[>Y] qv<~v;Ѳ}׶NsnmceږMD[!xʢ"zv_--pOy5]Ipvv`hqKW'",Y|xAZ8R\a7ͣU$6m&7#K?e=}<~v;ٝJ[%FTGv+}:dnG&4ߢ쾮ą~ҳGԼ9ΊVm>< *z]ӏ6؜?oVGgVϮHl@Ӿ򸋌Uz!2:/."u$yV4I 8`HAo84Gd/RwiՇĀţ_5>+דίgu%6]7,^=XÉȊޯcjDFg %6٧C]5[m~Z]"n` KlVNzǪ6y  z89VGq5{v_ytQgճOd+ uh츑=mL>>-,2zP=oӟ xR5H`2 yOIo{^;$ϾeewxIs\492zv]&ѳۆ{k[?ū}]Km^zv^8h=DbtP׭m37o><-,2: 䮫}yy֨/DiO_tItgKW WgUOEzα`vqm;Q?ū`\*{v_ F_{v^ytQՉ̓[ͣKP׭"\F:g7cg#2~}ؼJJ{Dz[7;Crnr\lY_isb춑mt}EǥMNro~fF_y}U.Q|7Xڋ=>Sg EFgnՉ'L&/ý8'z1oÇ>ZwItgKW GF4>k+ LDoM^ՇȄ}GF^zv^_?=;o}7r]{38*rudt]mg^yͪSfEx쐏$6EH{}[7;Cr@vxtpnol#CcBugWU캁^zv]_1ٳFŞ]7p]Ou.tvItf촱Э:9tKq9TyY$܆wEF/y@QnvwI/uWwg W'6GFe'։)ѻČ}aV3|u^/캁^zv@7p8WFe{/~R׎%Qe91t (v~Y^GkGE؜}2Huw;љS/smsO"/r_dfgVS k5N9ֺsΨvGM<92;K5DOc9pgtٽ⢗qGы-wd/Qvh7~w 9\Z}XVdtԻػ_N:!jgա-_ j֝rVu眱 Ȯ=Q&^}档wXTB =_u&Dj/WϕN;S]QvGNl>Ƕ=FJtwgщ͛is4}NNͺSJvV9tG}pEiެ6}!яϚ/eD7-zQݚ.{#rwKUW][3y)0?,""y&:pW`2RU ߩ{rXv-NhyѫǏ~~ ~ ^ |iKG~rFfj ݼ;>J՗V_Huw))ᰴ0Dg%6u]z9^tڜPmzyfrDȈEDTw֦7o'^waGs.ixYtњԼxr'EdmgU!RwIUy;Ms@N{WGFOsePJF&0y&D?6Z_9-+Mވ2ՑѡbKfq=Mrêj37;S'#e sbtHGFk~yit̳DKd}F{t7yEV鴉|lt7wS6Fωё#9輽cN.͙ѓIlλ ~IlΌ|?Il_g3eê1O91zJlΜ'QȰgT)49m~9ѣ"}"W٣S؜=%6nP$66ߌ.ymtSfmnIW9#}oLjVLEh^tݪ90:rv~G)y$Fg||7:Y蚧s^YI} ^D/#Cb,nМݬ講{_Nh̊wD_RS[;ǒ5493|ؼ8Il0ߍNyҼ6:)s`9!zל9gذsuD=0hz\"~3ͥ4ۇ{cdҼ~ ?Mz= м)*W@2:cBWFyjzyZдKexkϩ=yʜY͉rn%Ms`֜֊!f/ؚcyi-otסedd=7~*kѼۨeȠgG<'dX V"3#37萻舻h_dtw~K}Mꛈk24项mtֱNW5~K^T50yڄFFOyыu(pXELis']{3ңs#3.* Ցљ:~ !7;훀4`sڹ'͙́ՋƘI=z\,նы_;Л壧feg\ztف߼7yzs'zt O;ǢUlʏV6 oŴ]φ-ͿHl-Oy&iĜHn5nG׮45~Fpˋ]ee:\U:⢷K]tqY"?`t؈%19mYdu9"?b~yRdt+AbztwDFO)7x[ѫwcpw.6:'G}G\>\<ݜ]\9خ#͈͑~旅4GogF:ܮ„͆wytס-zʼ~̕]j_= ztSDTw_DMbsM茧茗;9{t:T:f>/ejNztS6dtsEzsLu&EDFGn)o63J"G'ew| :Y~xy壛ţ͵;ͥ{͢_lZ?;΢_S[{YI9pF=:'-{ Wz&ztex)j&YsB$6gFOSMtθ-mHl31˳CzP|txt3xtY+G7ZGFzsr7F:EF'1GW="]"#iE=5#wO ^W'EcUQ] "#)*֘}Nj&ѣ3)2:=&yitsUpF0VsfsvsNs^snsVlOvwI]:2:rNOwxґ-&-+/0]=:ȥ//Y=:-Gw5O¤}_=ִ[{cNszhΓnAwI&99ztw&+tż2)s^5: Սѝѽa\vՉUXZDFg-eԙQE"cÎ\>%ztف[=@tt֋[vio oYխ8:2:[dd={hs"w;Ȗ ]MSb3ijFάv$2:r˼(E˲qyWJYѝGѣÎ #tâ2O1w2Iѝ8:v9oredLhi^Jlv%y5cNJ8489#dMWkGwKGs#kS"ѕљգˎdVO萑N۫aiѷ؜ TEF'= EnZ4D.;(Ջ;z4G=Tؘԃ,UӪ1y=Dߟ4o$6O<<>\v`Ҽ\TB:1$:Ch\݂zָ|>6PoDF~w"]%yetSfo8=\yˍiHztx~ucGwW;h.},3Q#SG뉥r5l]yoeIݭ׶]yQѝymэ'ŚG27WOܯXȺ0yL ՛c-CvԎ]Ȧytη$G=~d%FϑѝymA2/yV7y*:+]=4&0*:zopفU`tځkv|֗-ѣjDNzE蠧%/zt˳Vו1O[1K\Sdt⿾%~XayƝ9>Hm'׏n5Wn7׎45W6~~sՉч͢_H$6OWSXTW\HUmsdtzt^۽.2U=cӼV ;K%EUo*G߫]贾u*3&:aJO]:ѣDfEOXttҳ爋j)yZ8ɬҫG|Kdt*;`5yktv壛ţ͵;ͥ{͕͑ѣ$tpQtfѯs\4:r3aəOqnˊ%FG7OeQ*ztW%3G׵ږts/ztuoWOy_WgDfE@s*m eV'vKyy'8u|tcFsVrvsNs^snsfMͅV'F kK7DGM]P؇n(h:-~Ǧ5w]֙gͺ2szjNzJb wջ+wB%sC}OFhu^nI՝W6N>d;EߪG7=5TQdt7K'yNY;w.9 \=\=\;\:\9\8:x~sftEaN*0/z>8 hkOtt]~u?;nn San{5z~.hnUoyݯnh}ӭ~ZƔY}+=#">דfpءFtd??&Jdh6Wz]:z njxCs"]=鱬x"sv赼fay;q}rVsfrNs}k8gF;9Α3za$ES#{t[Oxu{\kGw&CNCuW9Y}h̏1QÖ"uQY2,ۼn>ԲAѫҢ{7"l6!93r]mvdVqtځ^:2\:y"3zn,%z=y+bDs^juUdmSf| ?-3xO;wF=Ojl.ni.kAͣ%sd=0.z^.^՝P:7â{`ءmj+Zw c}YV9s3o+psit\ϭ..!()(7ңۺZxůvjO79GO,ʯv^S,"#X?4oBCգ_ 5ϊx|]F;48Î?$Ƒ嫛ţ͵;ͥ5K^tKEE/ ӢOCcݍnы.`pڡŌ^ϏM3aDGE=7"KgD=!訷״Å8Wv9Շ9)GOKQptqP=@dtztءegJsG͋vmpBsҷKAJ`Ifuлtx? <68ݣK\=\^}ϝr-Rx#!|_Syu! Y5=F-,Kdtڜ7E0/z&G|tkFEFu͡Wo؜v XtDO̘ޔCey+$yg!2:[r΅;68HIأ{zwNt.9{Q;elՉs9q.KSf3+Bw3:Y];\;:09Y̋[ќ';f#O:ɥ͢_-2:c=_?4OƌmfbtHDg^Z3oK?]訇AՋʜK7!G'=!ywg"2:)ږfs wo aDeVO9ĐTNH-ōFsFh@4׮N6GF;WuD]8?"'udt\9э73âGHlgU&ztcμ'?h氭&2:i $6=yG&МwzIdt8VηBVᾹ~t~u3xuvt93ruYk%6Gnw]?+WGnԑщ#qN4~kYR-ltdt6y=̌7L|ez{X}3VWqelp蠧9Jw1_n%6]igF~1~=6'D嫛ū;͢_,ź͢_[9ҍޮ.?+񃶏eETdU$9r?!z*y=̌]|*-0yjz]:YԠekN4o{ts`yV\}axG4g~6'FGt;>yƼ5: VtfsvsNsOjbvsbX:71Ju'/D/u,DKbGD/~1~t3DEz$0}}V"H͉Wz=;(z=أc"w0y'~u ]dtHۻq- ?ۘ-@kթS O_6<:gHۨ.zo|^٣͢^Չ͑ϚO]܋>%>uĕ>P?x7E?mi}Ytu ё:5чIl<0ȴY܄tdES7=cs-y!2zhSyh~vu~9mgĺ9z|N{g6{fI󹫿9ٴ'o?(|-MtVtˢ^W6͑O#(ё{ȓsiy#Li'x/,*:o;٨;)=.2 N仰BrZuЀMs@ѝG?E/ ٣͙ѧNlϪ^.pXWC{(%6e:yp阾bEN㫖:̳̓YdR8շҨuuuΠ[lTbgE/Fd\2פ_FT3TX7'Do9$.23Wݖ&~?}RғSWo:a|O4fчά}~uu;ѽSo' :1z.ͬ.=VW׌͊-vXϟjÚ૤P2򢗵)ѿ&^6{7' E|JdtGGTr Wvuu>{eVVSإ>JZ[6OQSZUfǔΤb{T3FQD&?:fXztuʸ̍xc]dthu^"?ZNةͪ+KmXsnVsZ.5Jݥ>D&Yq,yh/Ԫ8-[%]A5WǵkuVFWw=EFOqcZuYQݰ_d |̏ybq{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/5.voi0000755000175000017500000003247710513247244020165 0ustar mihmih5.niiMlGZ K #!6E nXka&[a#GV_gXW輩}QفS3Y='mt'X-Q[jt\u{7.-:Y$6y#Y}l3^:hI.Xӟ!0Ց!wrٵ6~Mnt]Zbut莻$6Y֛^_mw=*ڨ[kLr؄Ω~K 7^mv6Z`uk-%VG#.Ed$Q"vHx -/a:b&.'нʻًwϵ&URcaG\mVO)wqNmt'X[buKn-/X{nG\װF٧#uuo>wfG*g/=|FF#f1͙wMcRXHF|BkՉѭV[ nՉo(>F٦#6ٛ[bMn3իm]Khdt>nҼTo^,-WvsMfn6Z`uk-%V wF1nu>oo.K%Cm#_E1Yw }Y4n_=c B3WZ]p[buKNnFܣ%Va6=:^fS"Gv٥%ni\#KNb͙wYuՕlj[}*,:c~h^Oxln ݠC?vf@._k-:1XZ`vK>k.ZN\_yrb).>nueO_&q٩^LhWȒcLvqbٝź+6W^ҙ=2,gӵegŚ]c=Ļʴι*(XZ`uk-V}1GͥWVkjs:vUXxʼC^b ]KΛk4n_ǀc{mv7ٵ彰sU:;mpˌkn-3#x rzsMFB}i jj~A V'F[]`N6kh/>;X7m۱STyw(Xx\vj+EdWr7cHفdo׊zޮ^=|?|u\4z "z5O;vEά蝇մi-˨3oyg?=KKVw9W%$6/M u۫G\u]z7-2A=Ս>X'f_N՗G壷WvtBWӢMmEVw<(;ת~|屘䶻^rVҢnעG79ͽ#mP[qNQY'ntӹmK)S}@d4}"Ov~nof_DhsczYgam~5%]?zQf׋FoZb靁n 1~=n6z>ߢNƸŽmRJtjZ~tס͇ ^E jԏOKѣ#׮Dnܺ$oc^U/D.xIgF׫Y=q#ٮv\#7Dž}U>,rGez vVmTd?KKz$6~7&y.sءٽSK~pYR= ˋNZWKFč<:n|)vaoot= Gw.Dl=r%0R-яr!^rՑϻ>F7n$6wFZo.X}92ztZVm=[ךUE\*ˣ>,2D?ʕr՗U~яM༾TGvZ?1$׍nַgƶ;[vdmK_%6O?qHli%ͼ\ \xtG/{W?292zt_OOE4.5ۑ|=:mוr~]q-͑.W})ZubxbtIVW\ONHl1,wqdܮ~_ݾջ3W9z}C:q^/ѷVR_tT&9BxY](I]{k/qsgO F'6ww4e6.Mq<+08ztۮ O\pƜehVjxjՉ͙w+7z,r~bs/j: }z'jFDU9z_EWlw6߰s[++2#>tt&Ȭ~ 0LؙnOg.9Q{'w_(}\4fIsѧћƵ9l`t屻+w^nsJ7?}et^_`a[Fθ&]rmsRtKգ7 tE4ىoc{onǵ(2X 0dCKtwVj|u-ˑ +ERzRV;z*5_m[wCzJ?X~^[in'މx|EFHl)y};s{/$tn5W>l.}[5xukFLC97^;hn]cNbdoh]w&m 9_+~]rJh߈DKbɛV˗ 9~pxVm?6.ydoڭ0"v`n]Btpݤtߜ yw yf~k{j]QH\'x]$6~w]rarYsyr`Լ:PRM~s]8}wŁ97NiҺ.JoΌn??n:k|M#?e:2*mn>_73לz3/DﯭN oAͷ8phR}`iL] :{\]=|%tɬ<[g$×͓їו\ ҾmnyNN:3H^=N]=m.\aeGգgZ9h&GW"aݏȓpW7.r>TW͛+?/,WX8tT} nݵՁ#[0-z_o~^71deفRٙա}=!EDG#";%_(!{Wk# gO WXsaaI^ $4&w3qgHN۝%6'2㓢WGo,:4X=i~\s=.eR]^furfFR܇TzNdUdtLDsDd/>FmAc]fHZI\>޲#nM>#n{d>Uf'6OG(+o/Yv?CQG\z| li~yu$:~}mىQtdח=G"EFW)=juZouҩAsqt[enՎŕooĭn\;{]7l6/Y%{u+qţ'u\za]asitM^NC]dze؁]^d%;EFofkTt7#KÎis]zq\nWTN;=g{%6>KBi#_yѱ{_CLb3jWCyZά~Y650_aK]^dtij{ ʮ ϼW Kdt#4oSTG!nAO‹ꂪuQћˆ12_Zul4 ՛ӣYXub3gE_SӢՋ̣wUWs$}qVF7c~WDFvگ/n1ُՃѭ Fx6nfc҃iуa<xX0^ufU~ܚڮCmV6>V6X]WPuۊ?bKlNVdtt(r#on7bw խV7`ʞ6Ȯ/z1IՏMho#FFT/:3~dEE'TGF%|w']#kZ <]??nVEV@vB=1!3y |8LwDKhڦSmT]]KGGTwѪO^-Kl$6ߪWg(2:?ߢxQ%Voʣ1!ѻhށןvKdtӼ k՟gyVdEDFwgA/Z[)Yi^~x]hwzJs7$ǩjX_9ՉѭV]"Cz:iѫS^؜5_>Pkmu¿ݾ]X3TSݚ7KdUdt[Xy cPk ^־xUbtkՉѭV^K#2 bӓq{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/18.voi0000755000175000017500000002627110513250014020231 0ustar mihmih18.niiMn#Uj`XE$Ȇ`L-DQ7 `l7 Hb'U2й5Dѵ<.}uφ޼3\xw^\_ՏWᏛ0ܓW ;QCBv=n'T?d֎QK2+f:*1z93~4[}vѭf%6gxխ%6FZ%ylywQ89ۧo%6[^v딓/U V{,Ъ̪ ILG]=ӜslsftG.LDVrìλCJd|uϟbTOD?.:dkZ͓խL|'zPUֻO~,GTtVTהQ &{Niz6~'CâW13]GNqͣ Ec}86c[^H]g#ˀ Ik& LJ`^hpMlUP}jUW`cjTׄMK{n:1z3z4+zoi#JCݰmkz;SCy觓؜Hu밣31{ӻfۻĭ zzgH J\wO* g?>RJʾVT5*,<~nS#};tNEu她FY]=VDzse#2;p؜}^w$2;D^$6IlԗOSwj;MUy%gl_>y{_Ttmﷆ9oRQWvތq7pQ3#V_GXK;pWbsfyuwܑЏY$6OO$6]@ͺSVUy%'T`WdmuG]ٍ{w恫ґ_&ݕ=~'z]i#O2z#+93;P`tT]u%K`ifԗ]w'+0*:?:ªoU]уg_LLNag;w^wى.;z%Gݷ$z܁k"\GgVw}Uݝ/2;P\M\MbǼoSK}Luw|*+=:V]g?+zј!sbDkUwڱ9z=/1M!lG}us߮al]=~\GUGGruw]$6O] $Lb3OMwg+3oUQȬgcPܘ3EcT/c+tGêǽvFE5_}&ù,;pOd-$V^/Kvwλ"?O%3GwçcCk ډzY1ՋJi)c7Ew']\E?vfΝVC| 18:]w@Ocv_5Y'/3| ueE/w#zoxQ7?d%O7^uw;2w2$60 GwDzQ֪GkUPvmU1shT/:cM<-.<.#/e#9VHw݁:]w@OS.zicWo+] pܫ"̫a<ϥ)CG]z|Ydۗ@UE=ў)֪zz^dD?g<#:xZxJ^-ް3cc >:w4z_=hubo֏#݁{g[;h^mSؙuf%8x~| =#} ݁϶;R1rgIۍ&>Wt7|+09NR_PȽNHލn.̭rs| _Kƭ3qG~_̓FGND/vbco郎{{}r {5nFr}\]'q{egkstĐy}:GkP2; >WW]]Esٓ[b9Bo__4Dc)漮J~.;q˫u[RǺӎD[}=liբ^ۼ~uGӥX:G{}~| w7ٍI_Uw++v1ezwӵ/,"bUw7ay 4OdwTu|**/UsJ&_EdReLȊocЊ^Eu;n;PwۡaOG%ы{ӎ weyżG&uw߮eYu?ap+qߌ^dt\Q^޴ UUw*0GjdQ̬ت9ZՏy9\dk;g7\}=lo~ߜv,g /[agʛs,cWN~tG]ZwUosk/:_]ui;L B"3fO5ݣ#͕TljMvyOT1i۵>$z_};XҀgͻoqG>=^%,˦/cwyuzuze'ֻ0^<_M1m/qi;Nuw;690s]S^s-vFvߪbokêk+cUQՏȸگ{Y)u;ItX4vԄ_7NWW]uNJ_DdWvtPuGQ]ՕX]7|. ؝ ?Tfl)"CϐO[sUyUT^stNu%VS++DG XXtXM:/DFPDFO1xBU^uU`ubtU`u%VGGGUWb4Cμ #ODF>WOrU N EFOѷO\KXwEfWw|$Kd4;/Tft^uU`udtpuw_L=t|DJlIlT"PźPWwW|,TU #4?#vq{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/2.voi0000755000175000017500000003151310513247030020141 0ustar mihmih2.niiO}a: *dhB DF 6X2d/+Zzt3[a -z]%Gzt S|rHF)5ztsK3ͣc^U-oʙI;.3ޫGDFIdO)7;^UZF֙U} ^8)x h6=5CF/[bzl3}tLsrt~DG,zAel]tBFnz*yBS1\u爊n1")z}$k޾k J)et˶r165[hY.zA^t !k`W=6ꙭ]K=F]L|=BEzk#E\JcIؤMzм8zI)xEov}mk^-*%1:rFc zt3Mm\ft+]YoTgbLt{*f襎ɮc::zaYIO/W9G/%"գ((WՃk'9TC5+zm .eW=}sdt9zw=7gEG6=%SꑾN\kA/8XMEiMO!DD73{|i ȐY谙^EF/gG=: +ZXѥ~}R{ۢ'on7$)}e@O5/7/}rhJG\Zt]O]|Uz^fTwKֻ#"賷#{+ʘVeyDE];HTMGFOIlHlF<=ޜg_*˶ ٷTzi.}tX]T}e<赱ʌ2YenETswhdcG͇ѳ_p%ޔEH7Fd8z7 &݉N^]"SҢȹѻ ;%6]K%7Rϟ%ztCUaIE'T}뛹E%z+wTvё -gr=8r=8]g\"33z]tF|9k^nz*1zP_ꃱȊ mznGhTO= 1џ"Cvit7zKޑrC !#syBzЃү#j.MtRWMتJ]c3jG\v?]2sdt9Ⱦ92zx=Aוe;2OOaH~GI17/o@&֜O[7EׇF=uܜݽ<#DLbtJ5oLCްVy_d4g\wgD'ELaugIylGw=VOu5"bʭHSr*6J̦׈N9w"3OwEJH@w_B[%-K=wvVz-uX7PiJ9^.Փ.2`eg.Zw|^3.%w#U-Sv ]tƢ)RzLDN1{tͅEׯJJωNu=DǺ[ͧqͬnː}4KlުGg%o翐hџEg71^zL4yK䪵i^Iћ`.yCΖW٨;K`FNc}ͼD<~mgϮ ꙳R@9kå]w"V ͻ"%>2,̼WXzl?җC;]9^;t%MƧVخqGGԷ!뾿dW.{ 2z_$Eo[R-覧.zE}S@=Mաdd4۽^6x{b=yvxyUnKep]cI5FDwKҥ,% <6:Pbs?KZ~¢C}zt#GE^Z=:}ԛUUU&FﶾVEt_iP}O^}E'&eK\B{f8',dkEFx2óGg-2:?OzVzNhA1!TmucɈ37ؼ~54/zh΋W{h~Ov:ph>]]%6nӣ^&:d@N>m8=SvҼ%"zw%G{蔓Z}5"[^dtȵe'2zO{ЉzV^?jҗ>4)&z{]zN:GǝH\:aOG$fk$IdtvwEF/͙zDT]/gO/Vz:UTy`tۙGͳFIOuo^'DWKF}iD.{ ,;qgxgѣ㑐(z24'͗c;N;eO[K]ɋ.M1{RWoF'nFUhh[i .eX4oG=PZmg[сgaNlqܔ6woދcyߍN; zGVqy&2&Dz~e9^tD^[2wo/Ɩ=p >\H6O>v?cҀYмZ7y'9PdO m΋Z>;ݥ5:Rvѳg_ z7y>39b""z\I׶{n5'_F&Y}蹫]w`,}]w^ףRQѧFǝ L>Pofc{|bh#ѧ_EEWGf=DR/ѻoO{ܟOEFџ ]R/Ul@^.z:#;D$D1|T{Ef-0$nXF;/cU.zZIK;s Xbl۩~ȍ>5:L`ɥev?%< 6/=p9UgߔEf~X߁Ϳ}O͝L?$c"gN#Kmt̋Jot3¦w3fo9[iD~$>ɣ3pM˄gHxsl?&t)뷏ys/JlѓwM:>6\51|;)srn;uS7TO|S}X?8$eeLKҲ24큓312z>bt۹㸩$zᆭo>P|rx y{Cy_bqҞ#܌Nyխ5),[i)]fD>rrGw:l^,{`M춼R')鷏>zi|p܉rГ/d >Jn@wzuLti߅D8-͝8v37/iSODZGP`2TB.ݑܭ#+:Ao(W3^vk-IД.3"{P]gn։imzhٹ[bQۥ=4r=q_/C6ns/'Gͥ38\bJzLwaˀڒ}:8^fn*fn>3H<<<:]͙+\=={_^1_kKcΌ>vzeSu5yBm[vn貋3GKXcNRѱY~//'_楉.aTu)+=&3e<ʣŸ٣άyQͧѓj9Y㙣7LD4g?h%4:zoN-uq=U2:e[jn:Cʄj ܹu)R7c;׷6 >DFǝi'!#OKh>:&/^j:FƃQT}1 Lp|!ȴvѣΝN}_z/0zpoc/9cˁyw]c40'HΨlK[R7h -%+zM̔J.1n N;WDwa}{sj22ύ{]B׉1mbH1+zgt۩Kѵl7/,Ks48UE%&:zFE;kfʗؔ\ ТJ|흽^]]zh֋Jot+"5o*N\f͟sTq9maHIbHt]O}GzUwFm)#> Od5'\wΤ]I˖}M蜗WxΨ.muxEG׼!,8p#G#;F(mK>Λ#MLJXZۥ0#zonQ͡ҾDF L茷7\regt AIl \ȏ鎌^"OŊOI[z%hNؼN߳Gw-#PVC^w .MuHvzꏊ?u̽#2:sDHx6Egn)_nnJSEFbtJmt̋JQ)K> Qё{DF&1:9-:q#OC]]QbèOK=:S)et›jtJmt2-|I]HnK ^RG&1:9p:':0Yo+ &EoIQ fwg?NgTUWUW`t-uqP}P=}jsW玎\iw@7]͡s޲;'!g@N8uWSW]n9* :9z-zɫכ'EO]X3WGF?%2zTݝ-2:sXN: 9rݝrJ^1zqN8S1GU`uU`2:{y٫ף4]='ވάN}7͙ёyfttydw,`Rp^=8*JwAX]KAGDt5O_=y zQ艫-zhկJ$6gFöDFgzQ/Uvw)y㫪ӪZw1Xl?1-{mEO]=:1zZݝ6[VoFZY7p7 ͫIG&? L~ } Ϋʫʫ]׺sesDD_>hz=sEO\-^-zhկH$6gFgު3ȃ;jWb%'!zqRU^uF9u;Z:&:93zAգ橫WoD[-^DV;sVEGVw筋ޮaQ&?+.;⤪֝sLV/#o^i?|=u0zqV=m^WWݝ.2z;n$2:s< &? L~ m Ϋ3NʫZ:&:9{=zQ晫7ފZYw3DFUw筋μeΧ'auw֎KxU՝pZ8*:1{YF'T4'TDO߽VoFZhN{AիG]_/2z;p(93z;n*2ڑ|dw5)wP]p^tWS_KNKD'?GG̻F W~7׭ފ^6{;z/QG~4;kGbetP^1A]uGTCΨjѿ":!e5]cx$ziVoE/hNtfuwX#3UNbNuwTbs 5c`\/0& gՇSKw X]IbtU`u=W'XwֶIճ襳 WoD[lfWڎ^:2:s?Y{/:;og͡צyuwئ0;䛼bQ]p^tWSCΨK+: 9:b赫gKgϣވ^z+ZKEFgV۝ is;o":2:~qOz<}_?/쇿OGOϿPWuhOS^W1k~W||/8=bzQ4;`jo>^MyYڝEͧsr^4TW~f!Å(Rftɧzw &+ v|UewlnG{s^ک6ڝt+hN5tbs^؜==?=zV;kMw)]>^2FzI_*6'*@/jvg|Ek Cs!ovgU.<ubω^>m\-Tl}~T5QTl~].]"?F _iw []a[]av=6;mNw(Rqv9;z,i,EN+=RcR﹟,BTXEi$~7}[Fk0 WȩNZ4.6UY8W͢I+6>_awPX+zLAuGN.G!\aۛkޖ ov7|Q{;+Z]>:кwHNZ4]~\)MÉ㙤s#{t9fo^DoKz,z[K&W⾠+ƞĭ=9I> EBxZ| ڛ_ZE0:vM-V/kV)9+66rÉA_/wlL4=Yk[-uߎ6ϦGnۖ6S7n#uw%`:`v)n zɯsxB) mS^>k[έ%[FUiShHɺ9gMsV2 Q_SG阖>DomZ[MqQwZ[el^ u_t>QѩG򇣉Z)R~S2fu]ջ+~WUے]yEN$Ϟ46'^4^Fg^G׬]7Q1i[]s豯XlӺ]uΦ<(}>r6vlooK/VS1ѻ ~AD昗}֊P7Zw(Vmv;m;N>{ҜzڜzќzzZwT19_]p蠯Z,u%}^+Dݽ-nf\޺ʄG脝%kVɫRtvBdzyghP?*E?U.]d*]z~igc^z Ջ7 [rW45q|xFEI,JF?Rp3 4{&Fg$ɫRtYtsdg>}̢SW U^V6O/KDD?i(KD9`rѷ{Cr09y9qYҪ9i:9gms_M?'݄7s&D6^q%^u#ӭ-a /]4:s48s|WFz(}\aK,Q=\}M,R]2G'֪}\D_?V>i*}Tl.;kJF'NNfVmFٳ'ɩiI9oSV6'~Pݍ=m~揞ķgUG7WaN񂗼}9{z՜6{^8|7hah;5/͂p_,q/mW7%S$Et.W>~@tKGouͫ[Ftbs_T2:׻*6k G޶7o's;a Ջwo3VW^&&[Wl?#:]``l.P>N?~M93RW0rx~gw`GuϏf90̖Me t7T~G'NZխ^F_^f]"zPUyV^fߧbsYQM N>-vM-V/V4mNj֜wS!eM5~_Z*EOCs,fgir,V.;L=U>h e:7-DZk-dGӭitw–u.Z5{tLx&qsp߫=~.ܭ 4_˔;JF]Gu{Z>i<_ioSV6'^6&[no{Ҧr*E'~Csٙy 33PYT&cJFV4PJdt_)ma4.[n+[~F'o"Y-DՓѳ;zސy􆘗M=9/N=(FnF+lsv>ȫNZ4^6'iNY}ۜ0z3nX3F΅/t/-v٢o /QexhWO&Dzwc/l~Ts@t\;zshH+}8%uѧ{I2oJKynݩGˉt^OƧlB݋7)oF/F kP#/֜/Mt_hW]1w]*4CX?:(KcKUJ|=7NBx~K|%~e7MŲj[R&jM# ?T)ƹmXrG~UN<|$Vug^>«.tpo>N+Dfe?{3?vŽϩ`sLpLIoSV#F/6ilgw?e(P]1|/E'~9otwX"? ew;5?LO vߛۑ7~ڜwgɏwGߗ?'l%Θy6'o_6g;X}ۜ|/Eg} +K=;cV"?%Au0,{#qX6_v͓1<5g~4-[ڋ::i$Vupٖ:uߧv&t&n3qQOgwW|AO[JW^v7)ؼJC^pj٫w5V7'IMY}m7stw,M8a{l Z_pR+b.zx7(dAqWWnեn~)zk`'D7&qe)-8?'kE|{ZG' o|gD l5ϕ/is/=>,foܓwNYg(]c&l=iN=k=mN\hN[lZ]1dPO*]dlaHgHqz2l fCw5&KYɛRzchW2zz>ِ52;bYvj2\]2z]8H0},>d7cOd;7l4Nt0ػV͉Z\6'_ݦ*Wc]zw(]a}-;ki>\5g6'7^ GJG>D_+6W_*Tw5Nd :Th.tfJ8[`_(/!٣Ei]茋|DO'5Igƛ:_lii׎c1w7kv~lsYUoWBimE1LL4I$̛b^ye+9%'7$Rqy6xo̳E)/EѽV'n]Q y4o!G1:h6&ϑ se|n_<ٝEWg㿫/nģU&ѳ{qZ W+zv[ٙŝGG_ʋM@֩|&٪gQfg⦴֦iV]iswx>9YS @zSVg|XX ! n >#Ulǚy/xԻdμWs;ǵQt~n'G ֆ꣋imV|wg_o D_SFGͧʔ32gvQzw*}S7w%}3o{zhL|#~pYbZ;z<O־l NkNW|,2WWO.Mq3m^7ޔ6w_OSF˳ӶYվKTwiL=1/ Wqe+QZ-W1/z.v߿4=wo%ߗ~RG?6.4AZVnW{Z/xsW|i,Ȝ*{M;gfϨi}e̫sTkU!@s5'+F4)7" Daiyp^Nk}8|ny]Mg4KջfY?ծ:嗰7j GJt؟ʳuSЗvxXEWN|D铏`?G_!VoyգX6 Ew7_=z 538mԜsn+q_ҙg;_g݉7Fo;bC32mtܮK^Ӓ/zM,>T2zU7s/{F q%i3q4fQVyT(|=<'narե/mu{Q]ɛ[ZXfvMEѭ9nDYg3:ҹǺz2:ux&wsP=M|/ܒp]6Ǽ~\~Ó􂡹BP &&%6w9N=IΜHN[掞kt=ƙBslQZwgSSRv9}޾HvݴCDNVDG%Z_7g^˹b.![#{v=yBdƻItYt)HNZ=n)[LSMi QuVJEgl},3wZ?-fD'N<,?Vh-1VtjP]2}.P`"[Ž[gOSg/V/Vk?ftU4ՋgV:zsŹJٻFMCU걪@u뻉_DQ%5pp_`$j6G' ǛyZ꯽Y8Wݘ] Yku{–ꤓ⤍Չ׍Odzvmg3Vz2Gu$ϗmyQi1p`w ջ^Ѻ?es':{28؛9}9s49q9gMr׼n8O/4~O݆؝y:7g^ת7W^.UOGW05ͪ cb8XDn=# 5n*QQϊd͓sSܜzޖ:Jk󷒈 Qw&z[Kf Φ{w.?^KCp{ݙ<چ=%uњ9|f~\/7༎w%.A>B\zwK =ڸ{f vgN&Ξ&'^6'iN-ל3s#v'Eݕ<+F1:ޜy[yu ZVo];}92yt돣%!j2Az_(خ u-ޘ8MWaiiJ5y̸ROTC7}J=d9ct?G8=/7[.gT5]!T.zI=N}7łYM=q3 6G&n>4Wg\nEcW;⾞Zr-UԽa+B=YSYE^F1wv-U%N}#}wΥvI>Zs^,LW|vVj> dPn`6ɇ;Ν=Ջ0Upze],F5g03FW_~zx?[tҍ?m5QEV|e J^m]WYG'7jN;mYiW$˵&1E2K5HvY"{hs&/_8MG}F_BQբ?u.<\;\6TG'Qؾ%f.tItbXhKs_+Q=ՊFcX3E?VCU7.UYo+UHA~eVRV1>z͟G˙SXz{斗`œEP_iCEٳ[\}^v-DkLspcD7I۵:w3oUtQyuf~fD駕񺱻^J:KPPmgIo? +~ ,}ͫQ=䕌.AVY*:{tx3tR䏎N}/[]_NWD}bZdc`$hs!连"sNd'/ސ::nGq Wѳ>JQZ0r;k,ѓK/wtt_kV*=RU[owKjE? 5V ϰ {Sӭs׸a+_ /!C ,捎/7݅GV0QF_?|;oR7+|}gV&DpBޗpH|TfuL޽$$Qbsk$J$@M>GXX$`B[q?;ɑ͙ϕ |lTGlD8h~U]7|]]v*!2zTV=ա2zro^f/7/!o&"~#Fu:IrIgRQ/GgYXEuqܙU^NF~WWWU2F7M_%.xͣϒ;G'5gFFeDʢR]7YDbeuuڹMgJXJ.2CeBq'WG44~T5sGILgJ3fT=|V]]R>&'gsUrA?DFWWMbWq1W]]w&:2:02:+ݍ1~k|_Jl܎1V)c:%y+~Ln2SQP?L9q{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/15.voi0000755000175000017500000002530410513247720020234 0ustar mihmih15.niiA$IZa`8EK,jGBkid#FA3pp*l`"*3#s^*ewI wE/߽Xo~7ÿ˫.?,x-ϣ??Ww??~/߭\O?/rfEf'|V{5;SZ˫n-:1jѧIlΌܧ3{RW3>[kyխV'FGD].Ң.ёtftG]y? ߜf|F{7;e[˫nfjNN4ׯNlˬtjѧIlU.!0yy]Wdt=;@mvgf%7*ݛK{4;hUs@u~ubtzgW={9բϒ؜؍\`r9;%6/O`i7#>][3f{͵E$9r#3:Jѳ}7u])W PY9GcvjfPJ._+=h]=l\}eć;2~(Y}aDFiճL L~W !iof>[ n-|:| trubFCi>IbVpudcvXd6e[D&yP=;e=;gy\MYGcvkQխov֦AsasftfGj6,,#Y-,O#4O4>TbʞW`i f|Bhv.mevSՃ[͢$͗[-,[eEFY"/8;mCdtxG Szv/N^nv>VՃfчh}e9r6Ң%,љբO#4Oyy”yD&+"W3jff'=I._o]=j\=n}fGJlݝek:v_/j\/zv܈DF_)zvPdt3bftzvئ%&0&0XOh͎٧=*9 \z\:z\z\7zYâ_nq`stԮn}g}뽹nά-춱sa3OMypnv^=g:͵G͕͢ͅќ춡ޚћUEEYDEY#/tgg}6yZy.6L`M`M`2f'|Jhv>VսգIoWg8/xl5Wn}'y,0ё3}u͙љՑC}7yyZy.6Db/z ڽ9{IOuWwGKG7DLq%Fot͢YaDEY"#gǍ\/Z"3:%3%7K9/Գ3Ӿ[7;g2urns~sAsQsqCm4gFNlZYaDEYD%9Ѫ?`vĘi"ScdJ/{y9>hfznP}у͙U7Eh;ffч}g}+FKlμ3\ȡ_0nWX>W]?ED7| ^"KѼKgNGyN٩=ݳcrBuzt/zkaV`kW'FFo4gFWl}բ",",͑x׋ά7ru͈YNt^>^W=;/Q_%6/@ !{sh+[7~I -sQsqsfGj.[$hkV>賈>Kbv츑GQXR/Mo1ǝ- YaIڣAOus°*5W7>F#m5>PbVoGbtg%#WZi#2#[2Gճ%6VGFgG=|̪^D-/FdY_|J'ѷwSjfjK^=h.=j.]=n,H[͑ѳF,Y.eVE/7y/]aѡ3}KjΌ9n3,ѳΜ,} yE̮٥^rAsQsftqsfGj}$'\tyAb׺XQy츑KE9e[>W/z(q=ڣA;{ի͵ͥG͕u?6&FǬV#]Y6V_0h]_Jr8Wk6Y8ҡO{0g^s~sAsQsqCm4>V#]93jV â_3/NtdFgVn1;mCdt Szv+Z:"ٳsv+6}}3fhv՝уѣՉ͢,HO,@EWi/͙GRdtx>Mdudt4=[W_e0"Jl^:)iF>O{0gNsns~sAsasqCm4>V#>KbfsDtBAMiѧ}ȇ3qm%`#zbGL"ڻ){{sh+Z'ׯ6KWKG GEjYEIY Z-m^tx9EFG{XDFG>dFG>gwm[D##2;id8R{5;Gcif=J5W67׎46>ָY6E*1zY/M Y۬}Zy"##o3#32OkKBp::d_$Gikf٣.zj\\<\;z\:1z,Xfч굊9$N ]՝?3-POؙo.Nz7zo|h|N@ms<CH3ob^}ڣAϭ{գţ͵G͢6l}qsRp [޴];i.N.۰]z=?@EO#,-%-3G ݵQ!hԾ[7;g2us^sns~sAsasXRy ݩ(ܝۥic}~nVB}X֨S{My[ ѧ? "Mmv'wSjfVf=ni.km^ ~8;kS.##8\=n.8/x\ev&ѧTϮz&2:f<˻ L"ki7#>W7;g/QmevsщE;\93: }]z,`{>ӈ>MdtzvSK M`bnfG|J{mNnwfa|GbzūѥG͢R'V?k[c`tx\-qvOܭG`M`b:ȍ(ag04 hX#$`xuG\Ro)Cw͘9!:}j79o~xuEUdtcS=ms%/swɌYdt;gT`bUwU2cU`tF;N_},'F?:2zLb[x̱gNFљ'cuwА)r/\E-3aޜҽoN>6T,akh`st$F﫻s%6&oR++0>uI">ѳZ)9t:z @NTUWV'FWVSb)6 V_ q{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/1.voi0000755000175000017500000004204110513251132020134 0ustar mihmih1.niiA4Ial[bP "!54#t 8 @_q̈pw3st}#~3$,7O?vo|ZOYeo?XW۟_77O;?~w2\矏?W_:;M쐷efWώx[bؼ$6C#r#Rm0~쌷)Ȫ~Des_D$6/͟ճޗ"ri#̽yܜ#W:1:sC8fWg}]52;Qx >~&4ˈ-Lh$6w+!9$ S=2'd] ?iv235 {WzW92 7/Klדdz5F:kr7EV6?=F[?̎xۺFvd7kBvP=ʫ=+}Wth.\8޹#s<:Z"7h'9Z7Hl-%T~C⚑T/.KVOyͺwƬ5:2-7S?FG󗴫S!2||Gճ+=$@b3?숷7;^U)mbBvX޷^Gϋzb=8=zPY[^5u].+&y /i㇬=#$6g}qY=;Mc[x0[eLvX?{TX}׽݉Y֋Y֓~XOj#[eT#2)z{䈊~Kھ))=ľ/&zD%6}q؜==ѵ?8|p~ugvˋnn\|#Q|N֣3]Wm]5^O[u"_Ǫ6Q8y[ҜyAPn{ˉ oRCR[6n *zt%^U׎y!O'͍%o^ Xofw!pk5vs6 zzpάg[uQgv?.=&۲Do;q02K}q*6D߫']ڧ7]/aneXZA[]L.*zfֵc^dtˈn~hn%Gxo,&_숷-rź_/*/zxkrեxwr؅1uݐWrhJ=iH>^xv#tz=Cr,ۯoX=)ʣ|1En,>]^DO EGw 'H-%24grgG-2XwfQ}TN?6"ANsuF.GZZUF}(J>ߨ݆muuxDSn^XMnv)/E 6c_Vt2"}]y3Fw1Όzf}<=^׏D/^=3}ѳ+=¡s ?nvȫ젧ջʘ,zvعdh.}\5zx~EDeåYw J 7FrN ԔmYIQo:9NGW)3RW~[ץ͇ߺ{vikj7ƂgW)V1qՑљS}mܒ7~d;cXtJ8~Ĺ}cIݨ3oO3w\GR'fw]8K\}\{v f۵֭GTEFŝY_VwjVk>4į]ubgf!*z?΍z"o?dESuK=G%2zԸ3'хpvUn>]w1%Sdt/.%GIQH;fc~vEl۔3?:ףIOc$>o. {sp$`>:ǨKq  G/}[@+SƞFO;wK(p~%NzKp2Fw%^yS. }c'\O;QtėM{ݪg]8E/>{wʍNN/MdtFoTl8eܠms;_JsT(xX$MCbslt`uIy[b]8{+LTn0SYܢջ\CpE7USUE?Y뉁 ~KS"J76p>&V%?v15ڡ0mo Abѽ;7om~0YxwK^Q?ubnPtnQчMϵMO^}Ԡ]hX~Y\PDVGF^11U=ܢW=ZԴ cS_Dܜ7dD#9fg *¾t-/(zv۹0=l͞[7U.ª&fq1k^E.+ zU?z_8%DP=9pQv=>Mܩ+WCQԲ ]c`"ܶǽHRFwo&ѳF#]K[Eo/lPt43nU)W[ܬk}tOpA @du7 3Fzv+ AJw4⥉X/q Keɼ/i[7J<&qmz=];zwݝc1#aCMIWUݮQ4]%۵ ѿ.+!zi"_7ԅE<^ƄGTO; nvjPX?zR8-wXSKWkN=mcgvϪg5?%V`5z^s=0`ȋ^Y߄o$=5Z_a_=e){t+2zLz*7;Π8}fHܜMלNfճ3(-釲B]uT=V)MeӶ[Uw6/_rjO .Zd%E7/}C'_!i#^>yc}^dR?y~zjܩ33,ݬ{=F5GFچ7yKLrVS.ty勗1ui\.zGrv墹t㋔拕v|zf[Xvs7KvCW$]C="VzM>44/{W8%1K3 ;xIйwa%6/퀔o ]vɯ G>.yEޓm5&[[W39p01&9rcTR8ҔE4uWntu)mܼA_VuN@8{j݉vYsGfYav:Ng͉ѳƎ^XtS}\@=5\м!ee^.evmvm.0z=B_Z>y o+2b3g7-2&Xǃٗ]u/ªF_>)[Kv&%wuwk6m(|8GuzUuy+n)unvDom KWDnumܾA] W6م#A~ioOD4{Zd'pI/!iТMх/V]:(GP}GF>zvk0;ؠpevإUO!KZ賏ӋG!4#,o j~+E,}~μ}\鞸#$71pgLEgGK_gD|GD/~̈^/+V7}M/0;p,B?U~\8}vн,2z9Y}C%-ϰȨُt~tuF3*zrمMn㋐c5/GMvYtfk'7=MFBtOa'0zqSW:1;2 U\r x]1уYlQ^.26mP\y⢻wJnxnb깥W/۟/}~6%'ؽ7vXfh~Q=0oE[XH_pcvمQrEt\}΅?%6wTOGzv vK˞GgN~6gՑѣgC=鹦:b~ <Dۥ\YvdGRnS65>h#d㍃ϫF_Ws>+Oj:MHQ6,%Oi>65U^kBnX襍;k^JS`EWӶnmh[%)sW!íjcf28dfLut궳3;pitu4Z?z'DFǧ4v Wm^3i5r]8*lD׎CEa4;CQewum՗|0出?s7 =1yM:> #/y)Gѳ ~q#W\Y۝:}hھfLhzn mN71~yプѣi. nzٞ7jښOF 1pnK޽,IF/&a{f~}wծnK~*!KUvR]{x7Qk8Tk].H#/g~?)7vJ~:ԳNk?C켡,h溜VWj]v!9n.ǥQ fG=5x^q=֭?YK>srzozG<ˀ2-h2yF=5ڢG._Qe5KasqY jt*bg9Vޟ:~h07img};6!o4eoS+WwR.z[ո4N4'v?ުܞ383ltujGzn@Gl/jGwtWe[śGчxIdO̺{L*;onSV>1;pd.XV.n媼_Vz/'zT=p7}]|/im.F#zvڹ漁ؼ g']j>!h>{`ZVs?S2}On^.g|{&GsG#.Cbsf4@ՏX#mtpfeIo]xCgյ+sf.u%wI3mMaˎ:}YRO;ӥNtvtu!K{o|^B΄%guMO4Uߺ[.;(D~ԱEf\~HS5jK $ovܙ,5x!2+NleIi/Ox(}˰n2.҉<-ɑ͑\2== !`w&G˝\@F C_HN=w}_@7/EoE.}HꢋNG[ѧWn^N*GwPϬ;mϝمv{e=cb&5RSQ;y9S.||t s.2R<^viѧf\qEEFW;s9׳NB77ǍF#-sh u%q8:&*zˉEtbr@== +򊗢3QVz&W7b;InpnAG8N>&VW^qR5t^=n'^ŷek>;hwV;z9iW||5 |5W:?jg_PѿPԍz#d0)7ճ.Ew0͑t`rftbS[:;X=;Խ.9rÚKGsH^sH.FS?l9~sAѡS<~{6uin*#W:<~WqY?G>ڜ]}h%wA{17yi~K4; Q^"~8@yi'h L QO. ~`i'ޚYWnX]tq8VW?K/,P=|l 㫒;~t[}[gGxYi6/3D\tWdDS\nj7%91*Z=,=\W=;Dbs~!2E?,n2O~U?znf!91&}w̸܅=/}Ilؼ ؼDK Rv,>(._}\;ʰ{bgQcNڼ5.0YAױ3>DלW$z=1T[7bWp4/ F\!+}s,}Uo0;oI_ʳїnQ듕77/g]hB[: Yؼ\d\,loճJlp̍|vϫ"o"z9҉͑)ۻdq5 ?0- mzTu8zz-@Wyu|4ͥYB2/%6O_ļ^X{ ~GwuOͫET]֤iج[^UoSvEϺ2mtDa>0f~:詣+J9J h>4ySFjוuG;\~:ⶣoO/I;31tJ_WL)jo&c6wڼ@#2L ڜyFFt{褓%9#?*Ȭg O9޷?~?0,L=gW}}=qsY?ȠʶK]&_ҋ{/F?w&ޭ#u>mݓ9i7zQEˎ Gdyf_IG*U.; .[9eNqKXXMd>;⃱m蜗'#쫖&7(pBFwJGG':/zLFYӼ%%ͧգӎ%Ft9gգΈHlUTzSdwV 6гG+iS.kY?Vnjkt[:wGFV:) j~6FE/sGgy]}2Ely$zt "k"#oL*ztֹQoHlά.!7j4%z= p%F.5.cSnGY4f0R)-A#s-69H]@KlRPswԣ%:3ftG9'{tm-u1:at'Gw|&0\G'ԋwC>bxG]Pb3=q{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/17.voi0000755000175000017500000002645210513247772020252 0ustar mihmih17.niiKYh`X%Y̑`L~mf0 x0ƭ"v󥟧YіѹDë{O}wчÿ<oLhLw?|ꗯoSyw߽}_~2w8ߏӿ?PZI=*0:92:R:cdFu.uѺd }͙S:rܤQ+lxY伎Ϊ%[X똍*0DFAtm uF͓)$6? L'u:ch]Gdt9ܹљխ#1U`tU^ubsdY|ѭs6z Mk>Jl{V: LnةNZwP8GÝ8G"WcrLjIFϛ͢f7|⢇ w#"_խv+s A}u)u' "+uq5:gk9 zJsdt@}z$j> QbsǣķKt}_գ{Uf9Uu]N٬#:qRWE/[6}Zsdt릗$6_Y:iaݺdΗ%T.حZWTYmo*-&ZlSwY:g輑OEr@ LF1Ҝd&Ma>'o$9p8U+:UbxU`vVWꪠA[,#3ǢuyiCG59ͭs5OSO4H`!uW&p:`ϪG5DfvbuF1յкhet@DGV."2":jW{jsѫŝ7Gnŝo|^iD6Fg6Eg.S!T`2SU5dcmU%eR+,,3;T]S]9Vnz[^nEfE`uPΏc-LV^Acra&kGϧpFT@O6gEG3o$0y1 Vu:cztGdS+*YYՏju3mUѣkբ9z93ȥ8dzWqic8Σh>l~WYzsyfHdHiKؤg"ͷ؜G V=8][lVu>_#LCk4=b}WO"u5հyZhZgXZdVgGyyC7ޣW;^o;z57-|u׳֓;fc0a̐wQ~,^qL͉s#sNv>Ϫ?٨T}T]R=ޫOq }=N72cq&/:p~ŵ Σy>vkm7Zg=oa<5D?<+Bv鱔eLm$6'!?[gPkUϣk:;>EsѧZj]讫O{VMeV? Y|^Wyѧ;^Y=qKVS'MzJrѣ"*94|#C`_U/CӵuF5Ψ5gTS2Oouֳ}螫+0V}UKtHS}Y=d#с#7aenAx5 kim^6 Ye|]Wo#9q kR)[Dmiчc"s_RnuT}\}=\ǒ[WT=_s69&zY{jsO4Djlͫ>+`c0Fp*cR17WWS5Dw_}Gw^} \Dw]}~:JtV84z9$z"2:zbܶU֚^澫EJdy7}1Ov腄e8uLelw#9{Ub<&ۻƑ%\ ?%Djc% s o˪+ +ѭ,subWmgvԭ3G?ÇͫG}rvEжpܪW'6GFgD>n]-S"GՎKܼy[|2Md>H w"nG?%6g~~ L4US)UVWXwbeU$VTu[WYt/.s^Y:G%T?̩ÜQ-0уѣ'ѽϢ[W3M69HLNDo\k)[S~Co ˪+Iuݺիs.fToǶ:fYem{σwf#coǗ浌蕜!i븋āN7?f\WW]Vݘ}ZgcP* XP=(_= l=(L71;*punziσUUώ&nѷ]eF^fsVtu;6Y&'|%6 @Cmv;ivuUY?YȟؐmdR c}LT/l| ^o͕E!sysom?45nΉJ]э_D>w ;ȱ.a"&d/?:zveAux:m_Zs{a-P[䜢ߝ.h>iyx]zsgy >%6'F5A`2C onJVP3rW1յ. چUoϧ6n4Wk[R=\ Օ=˨^nǭA\bGTG7^*cƽ8mgΧ}u;q&.e^KlXd'R?IߵUIJ}t@4zªWG3,윋֯Z[ Ĩ[}ZN6f\R{.84'Uס1Ճn䐩uݸEtWmwÀѷqZ>Cŧ0wIr/FMlN=Jn}|8xdzLyn3O_[7oSzvE멞r]R+zr]nvf\o^&GDHfCN[WF7կVGmuFZ/SV~s,n_=N}9qysW];w tM~q;ѷ YPn|Mv4|0;wAW-0'Տo씫jcv5Uyի֘DqG({ItGvS'mo'iͫ*x|l $7>k}47ywWO~rk}7o~kѫiUH۶2zv/_ zv9,077bvU1%6zߜ]YatG>\qO{W%E 'mWOw1ѧ)ћOU}$]}ffl;73O^fGjԳUι*e*/#RC-=bAX HWW0yrD!(@„$E+i_m'mz[G7'sG7YTL˦:y[|;ιjU=;-Ik uev[VXwmV6*6KkP13T}[vJ^D~=;ښsE!9zܽ:y;z="V`]E^~Nim:%˪zv[ @1-_aߵUQ?UIُبgk`mYU}{tfU?ZrQU\tU^9ܻzԛ} yj Yܭ}sF6:eŏ=UuNzvU5E 7|VVOmEU?bAՏ9Y#jevEUyњ?f?z=ODNyæ9&}KuPzvuIK pʪ%:BTL^u-f\V)]~uLyg#y}NJ.tP-UwVe͙Ѫ?!+/*/DFE2 :Y)Y|5;௨JV)]W]yUѳ;ޑЁɷ{%6?q{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/10.voi0000755000175000017500000002471710513247500020232 0ustar mihmih10.niiOXZa70@$#!5`R+u U XK &[aBWDlCC?ϓJ݈+OGT᫳_oͿ~wӟN>O?d߹__W7oo_Ϧi~|~|g( DuQU [Yw6]QIՑ;d3"κ+6ʋj{?S6HlTw7dVκ+6O!T`tFW`tGbDTAtH݈Mb;cq>ɬNGxTEWUW`tF'6GF'6MbtꝈKd;gLbsCuw%$6&ūMSwȸ2+0K>#gtdtb[LEtBud̏!w؜yyPݝAd5;cf㪓MSwȸ2*/K>͢_d4"0-:4:zP9?2 K˔ZPݝEd<]׫MSwȸ2*/+0z,E͢_c]4 0=:4:z%:;iDdt䪗y=y2=%6gFGnLOYulT;6QfLFW`9!z,5͢_b92;̵]ULdMVXDFO͑ɳ#*:9rFO͑<Ewuӝ2*/* ыeXi9'&tbsz.љEC2DEn"輑N\#-z8=.Qg[Uwɰk5c*0 f/,[SM:ԙWBU}9iїԨ):z;tl!z5ɐx4Ss' -ꪻdXU\tU^tFW`9:1zٜ}f/9AC2#<2Dnj͋ 2'1Sr?d.ԑyL8ҮMgvwEtGlRCU^sU^tzsJtU^uu X4'TKft8yřͧ=VOI!D[)F|ʯ?#k;hHd{Tw JlRO0a773-ꪻdX5]7d\wЈEtB2:hDdgHZ1=3t*0溃,CdVOҰ뤘KgjJ2e/WGSz~Rg #<#;hDbs%qq̥]AC"3O1{S7'go*qu]2*/K.*0!:zќSNOCޝEP]bJmFmpwE[c շ +WGFg^Ow.Gbhuwsw]ZGnf~0E~r *qu]2*.*/5ͪ_T!(0'29lB'6DdEZ^'T\IbHϣ#=E/y'yb&$2zJv KPqQUy] ы1i Đ;!9sX>~ZW^-z/"z/+oλ(=[F/GĀ'љW7{ёyәLQ;LyQUyѕ]=oN^4~es@tHE_ #3Yұ}WzE-ϟtG=WM#13z9ѻIl52o[6>+xTxubїZ>|숫83W{kѩL)pGW=nSFUEWEW`9!֚7%a2"ze8~jѫEEN֛9}m^'QO-fEX}ssɑP|Ww7=؜ؼvIIdgvw3UqQUy]y5448;h@ͣ<nH.qgף0i^WD轈ދ转G:?>zj1aѷMFDu⑸Zݝ4=$6gnN+ѳLf/A못dXU^tU`ud96&2.49#*y~ȟ tƨ?F̕ʤKzB^£uW=1ݰslHGiѯ=θuYpX}ssa9͋1ѩ{ѡՉ߹%6|G_W%ê+1:Ϲw?wG6Onݸ1+ǯ~N޵;f/Miѯ"z/ؼ^Ԣ7.z H6;hHb󼺻fTdTwl| %{}}8)6q[5y|Z,r#GZދDFVw7=!LyqT˘۫4$y^]3 c%6OIf/A묻bҼ nNN fѯ,DdY ދDFGӑK=4ϫΜ49ѷǠ-$Bd|K=%6OPah{O!ԣ!54`ќ}fѯ,D%1zY *>MO%6==ԳGw- =_BBDFOS锺?Nتκ+6);k5c͙f/,֚#{vFFOy8#3[S6IշWYѹ:%z^ݝ3(2z^G ?c;ܺ DQ! HQ H_V_#׹F1+0ܜPY[Msdtwҿf!z?ܰ9ёDwMIl= %SxDH^ތa[dt>|rnaꦻҼDSfAw͜ssDubfo)ED"z!5yRwأsFNΙsXiI+Weh\3[q:cEF%DFTwu\U^IUy%zssDubf͢C*{iNӼթga*BKc 3ݝ2/p:Guweɣ%iGw˼{nXt͘z`ЫnW'Aw͜ .k#E/Y{$6F?Qѵ .i79k_΍.2:sAmy͇ "ErQ%Fod^1~>ԸQѯuf"z3(%)z/i"cf%6VGFoIlκ w\uBUT#7[Aկ#)zН3D/}n6ּ.D"cf%6SYe"oìp ສ]gN5i@1IS]G9sD/Rݝ3)2!-kM2"î]b3lU՝pU}뮸ʋ'#(5Ak]Y)ыDFGCZ59o8"7DFoq]dtg ^Uu'\Uߺ+.ҼDlTptTuSGT'FWbtPIl3C2љyN>NUwey Nl~DgUWVWbu"CO-9p3G:2:qhY]19cWNX}";G>z$:7ѻ igː3zG.P]5ze-h.wq|ؼ$~ZtKڳsVtб]rnu~tAtQsꏪqsYoO4n+Yu7/D7L&[*zZ`^|VK:脃Q$]G~t،*6/WL$Mtim-:猶t>{МkVܐatϨqsYmKF׬BћW#fM[=]RѻŽ~fCB ;FO١}]脱7%C@ǷEgC3;Jj)'cՓ՟eժ?.!oQj֜.zZzIi%VϢZĽA*;4gnUԧGuRntt ϟ[^R0yyEt+ڳS^tґNrAsasIsisWߥS6ԝnPיk\2z|z}A:n`.z,a]::nEGMLRǼCӊ^+ j7!3^tґNrArIsisՇKF}sך3ݥZWG\F0稏njO[碓UϢӎ8z)9ϙQS2zXpn2J[Rs?::H9:Z7rCtIm+:.9v79y9q9m9iAs'URF/|VTnrKTGWntkzvGKǨ3'+7*=ιwVU~|U'E^tp_BKrRۊ:a\ ל={Мz؜zzޜ9cqsYjע#Ɠ.zYOս輣 my:oʍF 殟GU7s69o͹r( N5 ,^iiϢcNi{I̮9՝գѓܴ D׬nh%qttLn۽|;z"GmCmV6^UWWHt]_Q]OZa8zҜ6b(::kbNV퓊Gvt?,:收t>3VVUYF]558)歞>]:q[zه<}C1^:gd,z4utNඑa5߳i{/͉RstTɻxj?+PCd7iϢci[Avɳ͉}JS Yf]79ylt D5Z7ѕ_'zU]1^GWGsW?He? :m~45WxQ`Edi)'cՓOqJS vimtՃʒѹTR?:Yu?:яl' ;&KIup̸:8lb!eckvӪM_ P0bsFCtIm+:.9v79y9q9mS_RPjC>jrtQel}($K<Do$:sm$m>U\;vҜwQ/W_]]tBO&bsS/%Ztm/:HEξugOV?wթ~4b2ѳجӎzI_/zHbѧonc#ȭ/VGn ;Y=ZDSjEF]t.::Vh+*7xM.#^ўEǜԶEWDuGQWssWf֤ZѫfYG]0`;*EˑMtQt[5^WFnM۷c ;:͹+׾r?*E_=~TG,Ń跩؜C衂SNj[Ag+dwgwW_8}p~tj.t)=:rzte5g%gޏqs LO^oGQ=Vt{Ɲ]i/:6qo?QL{>z[(:mlOe6wFZ萗relLxvrZ[9E'4G4FJ;٫ :zt Szxu$6'7ݏIsnpa־s_Ng電g/{:k5ѭNdR2z|Qy @脗g1紭c٣ՓG)[V/h̙ǻZLnу [5L~vl3tF+[y6Ӎ^r7UV2ƻ^蒗Tli7!3^tґNrAsasIsis3VX}b9E/-(џ.ag;هѝknmCΝo^r7/qQG*\o{ߦzutK*WGW֢^ҞEǜӶ dwW3WSWLZ=n笞4:e4:̛.At8:傜0:oeT͛'i#k^G8ur /jG߾:ҀJ]{vt.&:䴶sFۋN:i^MN=hN=jzܜz\3:iftՇEYNfЮ>j[P݉~/gubEfK{N9EuWwg3WW45 MKFG 0:cw)Z2zIߑC2M*6NT*o=D֢sh{I:٫ٳ+FWOVW6gU`9ftj2M}Qe+ ]wWoZ5TGQ,V-Xk-:5!:嬶sFۋN:iN_mN^=hN]=l\]1'3Z=]zщbAs1/Ԝ:bsWG7ܩ:VGndxZNxM{N9EuWwWWp]3!筞FK]1zڜEG +^jޣB͏NsZ:Egl$J~( Y{N9EҶN5WDEg6f8quX ;{[9+5ߣ:c.:Zy;蚳*>L8nCkϢcNj^uۊ:a\Z*jtfِ^tqGѩE֨мZ"f/vAg\+K5Fs(Zt‹MtyYtIߣbRx\"}]c{zٳFK-VG%Uc'jEn5\k-:E&:իn^soE;GDި]^oSI9b3״+^jFWl.]rttƋDM !]a`:q{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/4.voi0000755000175000017500000002414710513247204020153 0ustar mihmih4.niiMVVa@"M"HH0 :A+#`,4`b*t;?>*yJɱ}"{}f?}s7|o6axiῆg~s zYgo~n?odhw]_ Md|]d4?M"UǫN9I 1̢ՖC*1u u_w}ˎ";\s "ಸɎ(b.>.jY9=ZѸ׽VJOu3"͋* =NuaBѳ:CL_"UGԫ,:,zlzfgbKD?GAg1N9%Afa.3.i.-Ҽ9bspR0|p]|n*^ụTQd#ԨR=cŕZKD?kVlkf,1Ӌ=åPt:;齒S*6+[tvVD<>C.xTGEWXTDYiT^(XBA=$o؛cv$6tVt SNؽͳJ ||gg@|n(Tclԩ5dGEhɎmuv؁OW^ Zuuvrفx]N۷~miZս7<kFޚii9k-|W?Ɏ*U[VT+Pu`u4ꞳW5ǾDtcDVՍ"!ޯ;R2zҼƔF3:;Ftv swbvy1f|&;⢈QZzLTugKT"4"*/+FBq{~hNת-my%Tl^>KD1eZUh^.u^,uRv윓1< xθ$^KκV~֊K+U&YhEheXTFؗkg>n+T<tvџeo.բw]EzSYzu%3E4Yo4g:;Ftv =/;RgL-T |Ɏ(;Iv)̨U,U,=uZؑud~ǾRͻJ:@sE)x<X.Oַz#KF%~.ݼw=̢Yo4{Of/*:;6\!;㒘dsˌbձ]޶fs澫ޏ1dt:mOɸuEw]]N7ZN}/ȊKT7n&޼v=̣][5tv Hp}~I+Dqswv1sJe-辫7Q$v`o{>hrt>mODg*8Gen:wH^XubdRfؑfaѫWۃ>mwԪ7fYyJ]|)=vۮRLbH7씳ysFފY,k:dXM[ qAs;ng%{]gJ%˞gX2z۶QtEdgnNzySvޛqwl ѓXy`Mdw씳b);Nz}JuD\ݜޫ+F4[]11RήQYDǰ]=’ѫԴ}Ft7e[⋬6t=/Yz#I:<nwtUأ'cbI䛂|E";࢘dK9gVv[geUֺ9WW>hbas_atvџHwԈI*6}JK]GIx xN{ygòyqK&VƓܰCmz9)=j>[1;ꬊGM  MLSΊ3b+;FsկBuzfmѻKsXt7]Ous{wu;•;zvX':'~Ւ<>Ӫh 4IMqOǰx ]wZ[cuK}z>zFwyܵYTxoUlOR &@xθ"sΈ줷ֹ7\`}us{n߄}G7Mnھ-8&3@sΟ]*]Y G_Ggz y];ۼxw_B;aQ>f{fklC#=ܬS *6eWd,XDXϳވutMut_݈~vĬc񫌞SvVyyBñ}؎dnu[w=?ƢXu$_oz}ލyg nE&[Yb{Z#[= F_=ؾ|TPyXX! SDvUq]qIܜS"%ڳ+NX߃UcfZY[dWdStλ^*6LW \ WxrV<ƚG,B=r{qwu#HMrŴscDUwWT>%Dџ3NVsTym*QyWnTg jV_*W ЫR;.xEO]Uc߱GX%WQzSX1]1 +W#4Wn\MJR?K숫 FWyH#+5jH.:a0nz+b]/^t¶ѻoW / ".Q:W/+6Suhp\7w$Fl93+K5ŚܪIŦ՛ ]vEQ: WgW\W!yys:W7cjџF(2W/z2;Mz+ QD DNVWP2zn!E+&;⪈QbsѡU /UU.; _bt.\\EiuVt!7齈uve=Vu5wc O ]vE+Ggg\U0yR2ft꒣-Ӕl.gwyh:^AgD+D/+>ԬJF WCv5Q:*Wgg/\fW\"eeӻBMBFOTXDd'\w(;zQ S#R&;[5ߔ{p@ ~ |Oq{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/continuous.val0000755000175000017500000000052410513255504022176 0ustar mihmih#Version:0 #Covary Volume 0 #Template C:\template.img #CritPct 16 ImageName Cancel 1.voi 2 2.voi 44 3.voi 22 4.voi 24 5.voi 23 6.voi 22 7.voi 18 8.voi 12 9.voi 15 10.voi 41 11.voi 32 12.voi 22 13.voi 60 14.voi 58 15.voi 57 16.voi 57 17.voi 55 18.voi 56 19.voi 60 20.voi 59 21.voi 57 22.voi 58 23.voi 56 24.voi 57mricron-0.20140804.1~dfsg.1.orig/example/dataset/9.voi0000755000175000017500000003517310513247442020165 0ustar mihmih9.niiM,Kao`XEI *1GBm0)%ZB,b+LffdyxS:qT5{XdiݧӟO_?M_vo?߬??__n??C?OoOvye^P6747~jNl#%? 2/=EFyC=FwKKl?39Ie"'1=.C`27~f2:G9:9zgWi?9e3?Agoyѻs;D9)2zJl^V.[F?ykF7Fs^=AtDY7'E?~\tjtS4?_MU"#2#߹dG\Wn9/2z#2茟F6g7Ds^[-2PѿDcNdD?~ =0nvCݭ[n47LwM%6gN?NJԼ\2r1~?wKN[Dbft[N5T7W7W'FwKWwEVYkWsdfхVJ+4+zȮC^=j=^ZRLsМݨ]tFdi#y65O99䦲 'Oay# э՝սՉf/u,E_FUVJ'2&zg:3vt'/-IcQ|f|ٮёKљՑё;{)*^LcCRP!:{NIw &9$z.9 \>\=m3kWwKWw+W3ZGoG6-zΕm]SlQW}7Z-*EjJc3aSo? :֊~vdT-݈LdubsctfFݨ]t#5yQxNj^T1!in@]I:Ӽ6:ykt FsVr]k^ݞ{͕߯.mJAIOm3ּe(E諼Muo=GFWw/Ӷs1/G~<"c;j_ū#{գ}ї^#>SC=P9kY=CdT!/vo_NFsVsfsvsNsns~sJՁQOlz?^j+Ϗ-D_%1YtSɽ,ztّ\-*љWb>^iftoY=:GiPtztѻ=|&5O@<ޤ:&S3Gk_H.l.n]kmZ͑ѣӺ9'Un(\}tN>n:ҋ uy]9/M˻tftfћ'ztSyKhtzt Ԥ}SǴ]sVb4e]յwvjީ3x~uztxtvurtptnAWzEF߫n^UVFkFF躎]x ά>[-2S^'E_GU"#?ʌW:#2:3i[=įz|ʬ^}&XXyϜxz~>~uxtvtttrt93nAsG_^ћۏc@u]fѯ| ]SfхVEBMG׉nVnz]G'ѣ{y9$6'~Sf3ڼ_Gfwq9FsVsfsvsNs^s~%D7C/9>']wj|EW.o7.qȇv佢+W WD׭>άvhWxatױMuHGn3?}]SM ":2z 9Qh`%Ucye<8$zn̮7 5գ͵;͙ѕͅ37n%E_?|4'g./iKݧ~tӣls^93rE>Vbǎ^a-ݪ?ԍgmuKS)2]=:Vw JnVgn~S_f{t%6xJi\0ؐQdstԞFWk7׎45W6WN>h.}ԜWױMLhDz9;FG=v~G.?.[i~0:='\V7zN:3z_۵=:XʴXkEoG'6:bdy"գ}tJbs 9Ze33WfRxj1ސgDEYOi=7:ni.]m.o}\:1:92zѼ{Py4?^[v9+fGzT?ƹ5tg51zt^DFOok]Fu~z6+b nVnzNe#zt)!y[/#2͙SdtxJl EޙG(=o9aٚVrvsNsn7׍>hJ͑щWܲ~=}LMlDvKu'}W~V=:'9-bGRz|]V;::bGG=I@htzts͑#G'͉їZ ;}7ykt ѝf/u\6:&贾G@N6uѭ^\bPs֏VijWiu"dzy=/2EGܪiVNz.qU_(2:mFe3?FF9)2::Kªoiћ=Ӫzp̉alU]xqvţ͵;ͥ͢ͅ_[\]<;p>^e3V'F7~7]!*o833GEFgo32wB^C=:f$ztyT_(-z%,zs=5y v@Jl @sl?ss)θ҈gt؁nsՉч͢_Y$Fw[#Gts%r~իM`^xy\فy.dL=V!ͭޱ=l:͢_獢﯏kqbt;FW^FF7GS룲&CNzXױX;KH߬K_KGeN#:9c#2:3k7Wsw!iVV <6 ջѭѝfѯkm\}]ltjKk =Vmn3wU nV-;P!a`5=eVydSrNyW\%'|gDMnWzMG7~ft3-cAѻ%dtIё_S%wj)ofN5DG7W7GkGQsdCkVjA#щ#3z. N[_d/v|!ch7oY Ȭ{Ȝ$B|uPwxT\33Gg=czTEO̔UuL4fzLA;yk95[fHg&sx}sFsfsvs7%6g)tv2#ȇ.n&vg#3zWYx|o]52GNtztߍIӣ2(CfNo]E&!K^藋NbӦE7G=^VDOР)Mbv,%6Hl坭xm1ljJ?bs խ\;:9rrd.S*=5G'YY="GלtOMh،^̆i yo,[i5s;ѵ^#Q,BΠUuFuNٝѽё#9%6O5̋BJt{Oox9/Cb3(yxq؜D7v/_jl.n]u}GGtjuVKD4o*{rNԺ%m?^l3Zs:5ru/rt`{MYODFOUuċ12\9,"v>Ңo">Kqhm*N <{7AяΉN<ٽ\>\=\<\;:LbƝSˈFF/j͇Sk]tB1uսԀ胡]v$1:qR4׍Μqյӛ%6;8DģGPoh.jlzѝfѯk^=-G6=j,HG.բ"*/6>K'xzoz~+|tiftG^^ftt='EFOѫ)?!;8DOIO<~ۜPoh.jlzf/i9y]М6?.բ"*"*ͽgս+13:m`tSftNozS^bsji=<<(xvw)[N5DG7GzCF:rvL+BFszmhGGP{(\:{wۨDa3_l @9ki}UW>裈>\$YwׯW͓gU O^=؉?]je%6g0Y'2: "gww=Q:݁OI|}t1nN4DOZ7M>W7#z4!DFG?Ewgn6,YoԢWO:foCuwԒ{w3TwtSdtE|*=;yϣʋniOְ滐ρh1+:ag^sq\hDEQD%23iϏ5z7CL(y&hIuw:ѡթ##GIl{xݫ⢫{-[c"v]ڙq3N5ggtƤ6D']E EwW-PɫE%2z;j48/QwӲIrJSi>̩]Fbsfa1%6AhM^&2zkۀߧFRuGuFGsȂ,tʘL_==ڐg=,z"(=[ݴ(y=d|u4g--4m_%4 A$6kֺ@uwzC։.sͪ릻b!^K6O9Xw fѻHkG}ge`tJEGtEkL#RP<u"'^zaǛf LUwf؜]7Ի Փf6GbL]>ʫRYyNG]׋QҷAN!nvxIl*;azؠuVW]UՉf;4GFw!(7Ak<:_ICxOIw1'z\ݝNb yRw׬qu"n+fޭ"WKb3P_uWlRO!TUW`tU^u>F] ;gf(D1y3?&zxF\tڑ7$6g~mIWo\Xm$rDF𗪪;aؤ**+0⣻cJNl}G+5yxfE?Ӣ<<7bw8"i[&2U՝QuglRUy])%FO]UY]Yb3G1nب*/#KA*;cdX.?§q{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/21.voi0000755000175000017500000002541110513250454020226 0ustar mihmih21.niiM,WV(%Y`tVbЀ $S>?s<͌s%wkޑoy7}_/_op5Mxg?~_j޿͟ןO7~>_o~M۝nw} _鎀H0Gރ;Gb3H;᤺9*;䤬йI[0r㈌=~hn;᤺9f[w#BCJgS=8~ؤć)4:l0>YjP;ê+0:9#D}sdtw!ɢ_'7UsqI |Y[ݝ#$63y#r䐕1DJݺSNN9T"m$hVwg=%6Uw쫪Sꪻ䰺*9 {y/uwP]y͵]sLU^}sBV#W'F?hSJlNlL_ ӥ άTLbs ]qZ^1_O8**.ckuٛ̓?h5D/6Yiu'YewwDFOoo;"3#3݋/u"~ޕ WS+Ψ*c^w᳷/=jFdXƮGac%2zJi6s)Ỹs*gV2љՑc?ʭn8-2:;z]qF]=WͣGW`tmz(.xY'ư;C/ե޶=;:t<}oF'鹄bEd%wSXԦD} *2z'=C?άs ?VUwY堪yXS^VuJuDdVsit楘xpr,39wUs1ս#VCWo]_#oAٷy]}>|n+:`C ={c&>{3!Yc[dtT7)Rw]:y҈Ub@:0ycћ7%=5J;Qޭ7Gލ#7WRek9 _Y䝘u\dV1V!Bw!؜EiH}eBqq>zkHi^u_3͉ۛG]sH*:zP=|v{CWo߼{4&=2 _%2 k2G9EFX;z[kL"4z5ٵᣫգGWmT]U=v2zVݘTN#go5=vu~}wCjtFDFo?LGHl޲ Q\Dރ;GbL}[kLu,5j=U@vFucUyUIc^oΌ^7doF^=vNC}{Ftws931 Bbsw'25 ,E_plqΪj娪 МPnފzyتN: 9tAͷ)y%9Vht,_EFG݁D0gV]w)u]r\uS]Hl^5DJVzy)s<3-EFG~H:oz߉~h]w)ur\uTW]Hl>2k2"z]#[Lr\t4O)yQݝr\bsf؜t\%6OɋG kEwq5rP-u}} ^D|9e_nts!L51%6O͙Sbsttw9S`rS4iU՝pNtUqN^q Ůr7&.tн1EFߪ/)7᧸wGwW؜}Hl;᜺N9,M\pmtW؜9ҡ~{1:7;x9#.Ha3.$6GNtftpuwiљՑSpZb3tGO!q+ELdt.YpZb0AwY]'%6Fw7,u"fkaeX?CtVc/_d`.)Natcs8Z_0'h'.klnl~zװq{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/7.voi0000755000175000017500000003332510513247326020161 0ustar mihmih7.niiM-ۙ(%Yi1Z%DcL@LVk\?9;J+"fY?7?X>iZ/Yy?Ym/ߍOr-ewy{y?7rKՖfvg|]9͑oiZk>v7;Z Nl^#gw|GnVU{#DFZiUܞfL L~Ff?-79qcvç*iƝh~N>} 5zv͋;tmfFqq7 pvש׻՛ţwf4ミNUOyͦ3yY}y{q@֖ߴ3>=8-6,=soQ-iy~E1zn 1zn+?@;Do:H/tQi[cδa~k͢7V&~G+WF6$4/ uVzsaB菻`@vKʈAԤ6"3GD/M^vK=3bw#2߂Ӣ{ӖV:)6ox x_Mt@vmAv83-+ܼIE׆;EIA'fEҷ)onn涼,?Kӷя#z'~{^q mIяAs͡>{tK_1z8.ic,zvى=;LbsztcQȄNc֎B>wd;5itK}r!f4׭܉^~Xⴥ~%gRCdudtfudtnW=_͜5Y7D^tCtudk|V(tkF)Y"3}R]:|>:WcB!o^t?&2-zrt'1'X%Y(=ߺg;E@s'~s£JE"#g:3zW}WmUjN%kfɯYYY=9ohn#*SvnǤ^@=XuSLG?M:u]R>.;aBΖ_2!"WcR>қNk=/\;3;nHWw%/$F__=:)pM G B ,E{ѻ{_D9ZWYDoR͓\Z㯓k^WNT=P i!ZjY] ~R& movеCrcl2ne#3#3zW$FGtHomC츁֍>FEϣ#dF`}tB9\:2zن&GώDDF"$zDJu~tRS]ʔ gLd ^۞R3mhv8nYsȕ>6{|%dVljmC[}2 ѽS_s56y'63*nϕ*;իѵw>TFTGF/M ͇#k]z?чʔ轌މ6_&2:s>j~_E {epۛtY}XٝeN6͢gF_],l5)z{f^יyK}b/bsؑR#aeى͙ҐFT&":rڋ(hP}8P:2z9Q͝DDFn_^"^Vfm#[Uʯin{s(=|=;mLWI̘éIUΆjVlnE{;V}d#rlGώ^}uy7}N> D@qG.áyM׆E.8pIt#;םXWHH^ G͙e=];i~Vq/nOS^۰Op\v[Vם=3!z<.u$62'+[l";''UlokoP݉.o.޽>D?T>.'v-e#L:wwU1Շ^ەcKWru]q}LBW93\?]]_&w$KNn?Fk겋慝9D-}߯9%z{j^ؙ-[}: E/bsESl|f?Ʊ93~u/|v?x3"1iǑǧчukleJԕneBҥv¿_=vݭ-5tu.Rz]zp]=z(]>thJ7ִB/'=͙5(̣[n+[^նgD]iCKݗ O7ޜ6vUg!!se\s;ߢY}lEimCuh݁Ǚy}ؼ35SP}c5E;IYS*D]zFӥz|mUID׮DW|77gyapxIKGу}O;Jjymev˫u}Z]49"zrR֩e1 [rm%6EOGeXins3zrXEԾgPesj ч#s\%2l3@QW.uUzu&Rz]zt.]=|EFrpIkGGj7{u酵j-]t@|u ?~.觓<qW]W;]3`us}\\@@H㑪OoGw8H>~C]˛z?szg$|$`E[zsuvuog.۽Yތ֥GqѵzWyUn.iyLU]Z\u{}]tunM'u[u(\Gͥ/kV_EWNl~%\nM3VP}<ݩ 5D}SWI:ՏݎTm|t;R?y`[-?MG4KwqnKA`; vrpm>#͵_p4;hv%_C4ׯF4.?.Z}ޜ]:xD/avо].IѝC,hcqXњK|ӝ`ܧxp zT4uūGqǷ` zvħ%6w!ށoJow'䷣I4o\\z]:nubis\Ȑe\}\ruU[0TYIur޲?~sujֿ'uzKG/wwϕ>sFԕQt? r}xNjz;KWx{3\=ԍ>}+\=Ծ"kߵT:owowMWKs~sQtqs~ljiCaKa GFFGTW s]]xܲwwWpV[\ۛT70ʈ{e뜘Tua%f;Q6d]Eu/".k^#]T~=ͭn\螉EF@_Z\u{~\t̎>pX5g\q9f']J[J2zQ}HL>֯7b?@wYw喽5ok.9߃ͣՏZ6'nzѽ=gvWz|o.+V#`>F^2\΀N`6};UIqCl!__Ǣ;rGc͙hN9NZ^ukm vZ]2^s*L{K=!ԡX6zYa'6's]a 'FT7}ս}un-et9tDƺ\sص wч.6މ9Q+=:QUtat]yo AxDUf33F>&6%6W||Edt+ڒ׵64 jht[럝Pu}`}0$OjYeF.ۼ-D+9>g7l׌BTzf`Ƕ) M6OKhE׽,'ǁk}]0SUW8Py-c~ѤqtևVzAFZ՝0rpYZr']]ϳ_]yytUiKWZ77sb^:c)+^uֺ1ʠghc-{qmKUͨ'EFVM-Z}5/vtͺs{.~X%gvԹCg@vgmWw'"y7SNtu=NVe%vUߊW`Bjt' t:_=+&W=̮kݫ}JǪImC;cJW>ՃKv(.zxhiZ :Y]h\6;%hvҕNr~r\8Y ϪvGVoR71˦x3h\=)mlU4vbԯvf,W}Twz2Dg_~,ݍKFbˈA^a\mcձyّՉoճ O3^rBs'|v֩{`R0 wob#iܶvZ=mznډegvEYM UvQvfߴ,}~}ѧ":c[sUo_GW+h~ @]hq{lmricron-0.20140804.1~dfsg.1.orig/example/dataset/16.voi0000755000175000017500000002637710513247750020253 0ustar mihmih16.niiO$W4@b$#!5 19',,s Utwu׿잊GӮɿ EMe}hy7_O|m뻷'.?^ec?Z~~s?~?_y?~o7>~'˸s9y_?=WPW""+ ]telݣ[Vgl2z^Z+Nv5"V7&GŢ?83z|Tr,"zm 3ex.2$]kTg\-[Oe:;鲖Atl>ΎB섭KQnFhS}٥z#zU8]uAeg^a&7ͅ(3zx{iciuvvEӊW~0;˒##TdFa7nn}&;k$txxr4z%o};{FOnul^NkձY<ȎJelDzsxܥ>Hl3>rf4D9@b"k,t`\;\|Aߔq'G}+kV]tvT[{vxE~2zRԾך[U_ΎϹn}1;lUe5L~0^_Dd'lRѥ3vrs6e^vE1uUsb~6]2j.`\9\|ragG캱;t캙ne+fܼak^Y]72z:;mEOlZ>7]@kӭ3G|7&ϭԈ&1tɨzvKcN,G ɕ'C=ٔKWG_QY͈=Wۦơk둝奸5n^7ձÏ?I[4L~.;88ݲKnv d7]2j^=n}z v̹vu-g#.=Vސ1wnp-ѷruϫ^ [3me0 ~);ݳ:;ǫocjuvڊ=A.-&?W 9@vF{t7׏>hn"gSnP=i.SesfѯjYVNgKQzAV{DPzӢ?{ؼ73 -u6}6nf 9Y6Z}4ӢRb Fw$6GLZWNo_l:?)9׭|x[yfuwTb6Fb6} Y]`2D_ZJ<ʨMOA'|E֝#5]v 1z,G%6Ϣo诗f˽.?(ձpsdtb7q3/6<:{<l7љycў~QbAuwر7o_E_U]wkNFU@wwFͫWN5\=o_eEw'}ot?JwhyzVFZZo?ꎛ:m_sQ/W8uOꯟ46EMǪљOM#CO F u;zscs@.9zԼz93zY敫Gvѓcp`׿C|F/[}jq/e~ Ge -e+q[yWT5m.2z2֫oa[臐oa9rZ9*/uk4/=j^zܼvyisfՉͳ zgձirLkaGCtLy~qբ Eޝ719޴{ۦfcr:,/7wMt:pB֎|w)Ӗ!dǽ&ߐ];嬺]sJ=:ao^zԼzyIsff?+92~X}мd޼p}c%yHv բKd7uG=]j^qiEtM`tfuw݄bMdauw܋EwKWo~vY#!9_03¾[T]7[N{9T`csByAѣի͋W'FϚ# {oVnvӱM~Lp}\~yDWw͈-Cm>~EwEF_?jx!1:09or3$6I`MUu-F}N9tלR}[]яP=j^:1zܼxubtbLtw IݻHAD\rGEFTwEFoљDtw9![Ew3SwiUqu;甛ܘ#NǃG]=i:<:c_~yyՓݱv"׼ZՑљՑeG"EFΈUw!E`bgUwKwYu攛ܘ.޾9zzYKl ߌ/G~8d1)gջgTE6ou; y tPx9E˝%ngE_~KNWtלe[xT`;I[vwsgtWUՕXx-^2ӢZ9'q{dGHl|:b~P՟_] NyBdݝ9[xnUUwꢻ9UYՙS}xVQu敘ؼew q{lmricron-0.20140804.1~dfsg.1.orig/example/fmrir.ini0000755000175000017500000000047010320414074017452 0ustar mihmih[BOOL] SmoothBG=1 SmoothOverlay=0 Trilinear=0 OverlayFromBGSurface=1 ShowCutout=0 FlipLR=0 [INT] BGNearClip=0 OverlayNearClip=0 Azimuth=80 Elevation=45 BGSurface=51 OverlaySurface=1 BGDepth=8 OverlayDepth=12 CutoutLo1=90 CutoutHi1=181 CutoutLo2=108 CutoutHi2=217 CutoutLo3=90 CutoutHi3=181 mricron-0.20140804.1~dfsg.1.orig/example/fmri3r.ini0000755000175000017500000000046710321335600017541 0ustar mihmih[BOOL] SmoothBG=1 SmoothOverlay=1 Trilinear=1 OverlayFromBGSurface=1 ShowCutout=0 FlipLR=0 [INT] BGNearClip=0 OverlayNearClip=0 Azimuth=80 Elevation=45 BGSurface=25 OverlaySurface=1 BGDepth=8 OverlayDepth=8 CutoutLo1=90 CutoutHi1=181 CutoutLo2=118 CutoutHi2=217 CutoutLo3=90 CutoutHi3=181 mricron-0.20140804.1~dfsg.1.orig/example/cutr.ini0000755000175000017500000000050710403217734017317 0ustar mihmih[BOOL] SmoothBG=1 SmoothOverlay=1 Trilinear=1 OverlayFromBGSurface=1 ShowCutout=1 FlipLR=0 [INT] BGNearClip=0 OverlayNearClip=0 Azimuth=110 Elevation=45 BGSurface=25 OverlaySurface=1 BGDepth=12 OverlayDepth=8 CutoutLo1=96 CutoutHi1=181 CutoutLo2=118 CutoutHi2=217 CutoutLo3=87 CutoutHi3=181 CutoutBias=3 mricron-0.20140804.1~dfsg.1.orig/example/cut2.ini0000755000175000017500000000051010403273766017220 0ustar mihmih[BOOL] SmoothBG=1 SmoothOverlay=1 Trilinear=1 ShowCutout=0 FlipLR=0 [INT] OverlayFromBGSurface=2 BGNearClip=72 OverlayNearClip=0 Azimuth=70 Elevation=25 BGSurface=25 OverlaySurface=0 BGDepth=12 OverlayDepth=12 CutoutBias=3 CutoutLo1=96 CutoutHi1=181 CutoutLo2=118 CutoutHi2=217 CutoutLo3=87 CutoutHi3=181 mricron-0.20140804.1~dfsg.1.orig/MultiSlice.lfm0000755000175000017500000001024712147215736016771 0ustar mihmihobject MultiSliceForm: TMultiSliceForm Left = 493 Height = 242 Top = 292 Width = 745 Caption = 'MultiSlice' ClientHeight = 242 ClientWidth = 745 Font.Height = -11 Font.Name = 'MS Sans Serif' Menu = MainMenu1 OnClose = FormClose OnCreate = FormCreate OnShow = FormShow Position = poScreenCenter LCLVersion = '0.9.30.2' object MultiPanel: TScrollBox Left = 0 Height = 242 Top = 0 Width = 745 Align = alClient ClientHeight = 242 ClientWidth = 745 TabOrder = 0 object MultiImage: TImage Tag = 2 Cursor = crCross Left = 2 Height = 12 Top = 2 Width = 12 AutoSize = True Stretch = True end end object MainMenu1: TMainMenu left = 40 top = 8 object File1: TMenuItem Caption = 'File' object Settings1: TMenuItem Caption = 'Open settings' OnClick = Settings1Click end object Savesettings1: TMenuItem Caption = 'Save settings' ShortCut = 16467 OnClick = Savesettings1Click end object Saveasbitmap1: TMenuItem Caption = 'Save as bitmap...' OnClick = Saveasbitmap1Click end object Closewindow1: TMenuItem Caption = 'Close window' ShortCut = 16471 OnClick = Closewindow1Click end end object Edit1: TMenuItem Caption = 'Edit' object Copy1: TMenuItem Caption = 'Copy' ShortCut = 16451 OnClick = Copy1Click end end object View1: TMenuItem Caption = 'View' object OrientMenu: TMenuItem Caption = 'Orient' object Sagittal1: TMenuItem Tag = 2 Caption = 'Sagittal' GroupIndex = 129 RadioItem = True OnClick = OrientClick end object Coronal1: TMenuItem Tag = 3 Caption = 'Coronal' GroupIndex = 129 RadioItem = True OnClick = OrientClick end object Axial1: TMenuItem Tag = 1 Caption = 'Axial' Checked = True GroupIndex = 129 RadioItem = True OnClick = OrientClick end end object OversliceMenu: TMenuItem Caption = 'Overslice' object N501: TMenuItem Tag = -50 Caption = '-50%' GroupIndex = 158 RadioItem = True OnClick = OverlsiceClick end object N331: TMenuItem Tag = -35 Caption = '-35%' GroupIndex = 158 RadioItem = True OnClick = OverlsiceClick end object N201: TMenuItem Tag = -20 Caption = '-20%' GroupIndex = 158 RadioItem = True OnClick = OverlsiceClick end object N01: TMenuItem Caption = '0%' Checked = True GroupIndex = 158 RadioItem = True OnClick = OverlsiceClick end object N202: TMenuItem Tag = 20 Caption = '20%' GroupIndex = 158 RadioItem = True OnClick = OverlsiceClick end object N351: TMenuItem Tag = 35 Caption = '35%' GroupIndex = 158 RadioItem = True OnClick = OverlsiceClick end object N502: TMenuItem Tag = 50 Caption = '50%' GroupIndex = 158 RadioItem = True OnClick = OverlsiceClick end end object Orthoview: TMenuItem Caption = 'Orthogonal view' Checked = True OnClick = OrthoviewClick end object SliceLabelCheck: TMenuItem Caption = 'Show slice label' Checked = True OnClick = SliceLabelCheckClick end object Slices1: TMenuItem Caption = 'Slices...' OnClick = Slices1Click end end end object MultiSaveDialog: TSaveDialog DefaultExt = '.ini' Filter = 'Settings file|*.ini' FilterIndex = 0 left = 97 top = 11 end end mricron-0.20140804.1~dfsg.1.orig/MultiSlice.lrs0000755000175000017500000000721512147215736017014 0ustar mihmih{ This is an automatically generated lazarus resource file } LazarusResources.Add('TMultiSliceForm','FORMDATA',[ 'TPF0'#15'TMultiSliceForm'#14'MultiSliceForm'#4'Left'#3#237#1#6'Height'#3#242 +#0#3'Top'#3'$'#1#5'Width'#3#233#2#7'Caption'#6#10'MultiSlice'#12'ClientHeigh' +'t'#3#242#0#11'ClientWidth'#3#233#2#11'Font.Height'#2#245#9'Font.Name'#6#13 +'MS Sans Serif'#4'Menu'#7#9'MainMenu1'#7'OnClose'#7#9'FormClose'#8'OnCreate' +#7#10'FormCreate'#6'OnShow'#7#8'FormShow'#8'Position'#7#14'poScreenCenter'#10 +'LCLVersion'#6#8'0.9.30.2'#0#10'TScrollBox'#10'MultiPanel'#4'Left'#2#0#6'Hei' +'ght'#3#242#0#3'Top'#2#0#5'Width'#3#233#2#5'Align'#7#8'alClient'#12'ClientHe' +'ight'#3#242#0#11'ClientWidth'#3#233#2#8'TabOrder'#2#0#0#6'TImage'#10'MultiI' +'mage'#3'Tag'#2#2#6'Cursor'#7#7'crCross'#4'Left'#2#2#6'Height'#2#12#3'Top'#2 +#2#5'Width'#2#12#8'AutoSize'#9#7'Stretch'#9#0#0#0#9'TMainMenu'#9'MainMenu1'#4 +'left'#2'('#3'top'#2#8#0#9'TMenuItem'#5'File1'#7'Caption'#6#4'File'#0#9'TMen' +'uItem'#9'Settings1'#7'Caption'#6#13'Open settings'#7'OnClick'#7#14'Settings' +'1Click'#0#0#9'TMenuItem'#13'Savesettings1'#7'Caption'#6#13'Save settings'#8 +'ShortCut'#3'S@'#7'OnClick'#7#18'Savesettings1Click'#0#0#9'TMenuItem'#13'Sav' +'easbitmap1'#7'Caption'#6#17'Save as bitmap...'#7'OnClick'#7#18'Saveasbitmap' +'1Click'#0#0#9'TMenuItem'#12'Closewindow1'#7'Caption'#6#12'Close window'#8'S' +'hortCut'#3'W@'#7'OnClick'#7#17'Closewindow1Click'#0#0#0#9'TMenuItem'#5'Edit' +'1'#7'Caption'#6#4'Edit'#0#9'TMenuItem'#5'Copy1'#7'Caption'#6#4'Copy'#8'Shor' +'tCut'#3'C@'#7'OnClick'#7#10'Copy1Click'#0#0#0#9'TMenuItem'#5'View1'#7'Capti' +'on'#6#4'View'#0#9'TMenuItem'#10'OrientMenu'#7'Caption'#6#6'Orient'#0#9'TMen' +'uItem'#9'Sagittal1'#3'Tag'#2#2#7'Caption'#6#8'Sagittal'#10'GroupIndex'#3#129 +#0#9'RadioItem'#9#7'OnClick'#7#11'OrientClick'#0#0#9'TMenuItem'#8'Coronal1'#3 +'Tag'#2#3#7'Caption'#6#7'Coronal'#10'GroupIndex'#3#129#0#9'RadioItem'#9#7'On' +'Click'#7#11'OrientClick'#0#0#9'TMenuItem'#6'Axial1'#3'Tag'#2#1#7'Caption'#6 +#5'Axial'#7'Checked'#9#10'GroupIndex'#3#129#0#9'RadioItem'#9#7'OnClick'#7#11 +'OrientClick'#0#0#0#9'TMenuItem'#13'OversliceMenu'#7'Caption'#6#9'Overslice' +#0#9'TMenuItem'#4'N501'#3'Tag'#2#206#7'Caption'#6#4'-50%'#10'GroupIndex'#3 +#158#0#9'RadioItem'#9#7'OnClick'#7#14'OverlsiceClick'#0#0#9'TMenuItem'#4'N33' +'1'#3'Tag'#2#221#7'Caption'#6#4'-35%'#10'GroupIndex'#3#158#0#9'RadioItem'#9#7 +'OnClick'#7#14'OverlsiceClick'#0#0#9'TMenuItem'#4'N201'#3'Tag'#2#236#7'Capti' +'on'#6#4'-20%'#10'GroupIndex'#3#158#0#9'RadioItem'#9#7'OnClick'#7#14'Overlsi' +'ceClick'#0#0#9'TMenuItem'#3'N01'#7'Caption'#6#2'0%'#7'Checked'#9#10'GroupIn' +'dex'#3#158#0#9'RadioItem'#9#7'OnClick'#7#14'OverlsiceClick'#0#0#9'TMenuItem' +#4'N202'#3'Tag'#2#20#7'Caption'#6#3'20%'#10'GroupIndex'#3#158#0#9'RadioItem' +#9#7'OnClick'#7#14'OverlsiceClick'#0#0#9'TMenuItem'#4'N351'#3'Tag'#2'#'#7'Ca' +'ption'#6#3'35%'#10'GroupIndex'#3#158#0#9'RadioItem'#9#7'OnClick'#7#14'Overl' +'siceClick'#0#0#9'TMenuItem'#4'N502'#3'Tag'#2'2'#7'Caption'#6#3'50%'#10'Grou' +'pIndex'#3#158#0#9'RadioItem'#9#7'OnClick'#7#14'OverlsiceClick'#0#0#0#9'TMen' +'uItem'#9'Orthoview'#7'Caption'#6#15'Orthogonal view'#7'Checked'#9#7'OnClick' +#7#14'OrthoviewClick'#0#0#9'TMenuItem'#15'SliceLabelCheck'#7'Caption'#6#16'S' +'how slice label'#7'Checked'#9#7'OnClick'#7#20'SliceLabelCheckClick'#0#0#9'T' +'MenuItem'#7'Slices1'#7'Caption'#6#9'Slices...'#7'OnClick'#7#12'Slices1Click' +#0#0#0#0#11'TSaveDialog'#15'MultiSaveDialog'#10'DefaultExt'#6#4'.ini'#6'Filt' +'er'#6#19'Settings file|*.ini'#11'FilterIndex'#2#0#4'left'#2'a'#3'top'#2#11#0 +#0#0 ]); mricron-0.20140804.1~dfsg.1.orig/xfmri.bat0000755000175000017500000000027410426762116016030 0ustar mihmih./mricron ./templates/ch2bet.nii.gz -s 3 -c -0 -l 20 -h 140 -b 40 -t -1 -r ./example/fmrir.ini -o ./example/saccades.nii.gz -l 1.96 -h 5 -z -o ./example/attention.nii.gz -l 1.96 -h 5 -z -xmricron-0.20140804.1~dfsg.1.orig/html/0000755000175000017500000000000012360760644015154 5ustar mihmihmricron-0.20140804.1~dfsg.1.orig/html/index.html0000755000175000017500000000537610653742224017164 0ustar mihmih MRIcron Index Page
MRIcron Index
splash screen
logo
mricron-0.20140804.1~dfsg.1.orig/html/tutorial/0000755000175000017500000000000012360760644017017 5ustar mihmihmricron-0.20140804.1~dfsg.1.orig/html/tutorial/images/0000755000175000017500000000000012360760644020264 5ustar mihmihmricron-0.20140804.1~dfsg.1.orig/html/tutorial/images/zhistogram.gif0000755000175000017500000001050010513265434023134 0ustar mihmihGIF89aoRQRuV R!,oI8ͻ`(dih~üp,tmx|pH,:Ej:ШtJZ7Juz04|zn|N~mdkK<gZfjyeXJh ǐJeϓgk3i/h 1n0m 4i&8P.Re-7pڹs9(2$t'٤,qJ+E Hmp:&aÝ(V705k>#\)#瑴NҭYu&+ẻ Vՠn܌bWFԖR R*X5!R*lja 86S•~$ւjhoa3 n@Q6g’omxᨶk[lY⺏kڛlF\SU?pzr7rM/pd?|͢fg\ @'n7Xy/M` yGw'}bhY[ `c0xQnvcGyS#fa'ESAb)5IA#~Ks(T!g`2YM<-SZXnwaf2 )s~BrN'g^柀j衈&j*j*餔jv]f*׉駠*"BꩨM꫰*+j뭸DV$Pl&lZByvNv`PBkgԎ-f+nkBRϊ.+V;ڻMn믧v {/t­6-C`2l+ 1g0Zc,ȥ: =20\2l3ެV@gLsD]F'4H/һD)TWmXg\w`-dP lp-2HYJf|߀7v7C8݈'7x_Wng~Ct标.yԟꬷhn{-{o<7<{>?vDt=_o/_xʋ<__ؿmQ4 x@5P#W%`2XA ! 7jpz&$! KP/a݀B,zP+"A[Ԡ_?}pdHEьkãظ7B.8/(5dqH9.hT ި8=&rulc# Aѐ$ZKnn'IHQ@xJz؋$+w˸YL\)YKN"L.2 f07M܍Ȗ]\f(M9JEB3v,&*glnlf )K1Q g3:>LE*P: _GGJϏb DIJ̖4*JKN"4hsL٘&4y|P[.̗^4U{҈U3EhWy֩tmOK}1 Zyתt'lԛ3~M;{_gM?>/A6vmy:s*?= Ы^vodGnm~]Õ ?bo.?:؞y?ޜ^y'>?}99;{j#6;M{k~;}y{6ZQP̷W~{G^죷8oY~,r{vwd.]Sz߼~\wxFe}guBw}z@}16e7}Ɨ| xeG]zuvfJW{(r7Tw((R*H~n灿0}7X'u'phz!X|#J(g~zHX/|?(H%ˇT{x>L؅"Xr=b}dhVxS}-؃ԄtDxs8)hc؁/1BX~gsyݧLj@($qexk3}\ȉ^n`XUoHdeHY8d|(~(yhޘYVvH˸ؐ4x8市 >؇ؑ)☀{8:yhr-/zviy؉FH)?K]%,'9I  s9(y ; }u䒇 a`c9VMȓƕ)X&4)yƗdupySIvɘhyy~Yqoyy:[ 3Y&W渋ɍh鐜Ji9.F!irw5Iǔ i]Iq.2E3~t`)iifޙL๘ yEwxi)yy׉5y4D䷖>ٖGzIY( C+v昅ÉdYIq7: <*>ʡ@J8:rYx"z^YNy[K*MJzQB jta馤' t/.D YUzvإz+Y,Z1zWZimo79cʤZp}mz |ʦ㦂Nrj-ڠڈXY4)YT,jSm숗J@Z3*J;Zh : ęeZک2D:=:zCJZyjʮ#Z*jc lW7]ɥjZr6E}YcNڱ0ꭊ:*}՚׊ճ>2B]9F?wJ[AINK?MR \8V U{ZKE+IT@DPADPY+ta˴GeiMEPDFQx \Z?dVVǷXնA\]kNh F# ^Wx]?P{K ۷Ep{V۬K Aik+_;=Ǜ@ۼK;o$8[{؛ڛ5_ۋ5;[({껾۾x+jWs{ۿ'i{Zk5{ ֽB,5 |\<'\i[S$\‡(\!,Qb0L)<¯&~K. 1 L@ܾ6];>LC-|R (#Q@QEQ@QEfb$*pI4hHk Vy(+U}m;(y`l5 %O$4W8#־PQEEPQEEPdaHjk݅7}ɒ»է IG5k-Un^斉x*.O[bmD6yC7zK3 2\m$(2}+ۋəDOO9֚≍}Z4QELZ (( +4XL#Ŝ)iȺG=%*Qgٓ@h!JW#sn&Ǽ{8Svm4'n>uǪRSSvC΢qz0r#)'`bs=GvʓѴવ.*çډ d{\ YY}OgӾwS2;8CGJ kΕ~]r8Q@Hu}w&+[I9qZi`݈%"P[ʂ]lMj&8*@ݑȫ.gN).ApIqU&>+qeJY;fSהGҁY]|EI^sl3kJBHg64˻#4Jsփ@wޠy)n+I+/3lݞXt%g), {^p犆Խ]L5Ұ[R z_Z +6@&€FIR3_v_rl)7dž0Jp4.wH.:ik#l?cЗVֶrpJ#)uD~ٟn1ugVy)~ V6[5ZT:TWozbe(_T}a.e$'?^2RR6twчrԼ5]/LKT^ǖHHTx Fx =&#{=ﺗzkCmT<Үo5Kq䜅L)nVMjK_Y/4χE}6zCIti\2'M+>v =%H}R-8R~cWh[\dcZ P |*`7Eq f OE!a a%C֋nP9nm>IO||~A!;"4><+z]$Kn\(cAmTj}Z]:p$3D'V)J“T9}XZh-9Ϻ䕤<2OQovziK"'(Uݧi~N8=3fim}gмUGsy_wҀ*RO˭X[L&Hgx a;Jra!Z9KR Ϻ|fU!VmTfY$@sqJ-Qم!ġ ;yFx5Y&YftVɈ<) g%9{7(2.pH  ?:3ÅPP]!~ͫ,e7.3-@u-O̱Lq jN7b&((,_6׶|_{N|>vA&Gv~+AF[lG@asg:jV gs/3kSv[M?6q5gzxsY5&j55eBrpSAxL_/fjOUuro=i<~_5ǿ|u u57Wm{3I'O)/S څcbala7tКT*l-1°do,qr}d 4feHVr3^.:> w})LVq9J<7 %<I^ѱaa #Ƨ-%ĂwprS@i7G)dj% ¹ly) S.l$=M``CVJ?qA7-:򒤕@g\B8 4#|SX/q\IJ8 ,ELeMQmgij76 Sj}(q6LZ$QoO\V*Tmٌ2{R,ρ&{`Б%zΑMx@9~+tw IvsyٷߙdͲ<0:Qvԓ$>0 H'1V0ZS3TE? jŦ71Uc4[!٭iUc\ K[ш]nr+iq􅕁8ޱ"uNI$ ȶ]U zr@>4 `!Ĝ+>5M[\mϯM N}(%\ :֗yJ0p R*C;+ C)?4LN\P\c)6 v k Qj6iW2=h{m٩)nD$;+GN|x{`.lڥ^$˧ʔڷGiDxR~kLjkJv>/Aw֝KV pԄ8 1e[֝O7x Jm0R|+֏E#I7d(!f$rO=Gf*Lp;{G$ OkIb֎a[ZJ=1U[7%6mjF}pz<ܮ=PxHu!NFW1:h-ZsC3>=jڔ!ԝe6b%Ĭ ".?jn%^@bkJYDp %8 &3 r#ӵq*JwOWעؙDI.gR R|T%VG/DY;<~yo]VkPw0r}>CkkB9[*LM=)q8=H뛐थS ! 5Upw9>B 'S{Gb u)^NƉlECB{J@< fKɅ9:<3AEQuPclfN \iIې*c1iJ$ouc4:'ӵۗrUYh~sN>rah2EvRJ]Cl%#rQn醛t!J׎j~",{UVXl~]V>GNϚ:9Q,2XR>,gOL̵cR\?gq9  x*zi/vɌ?9 @P ׫]5IaBKDmPҜM&kiJ+v2RzpW9JAl&9#5 veTzZ:rYq)%jA_uJdl-@ƨw'-T)aKARAqLóɟ!sP:)_ GƦhFĘlyMe# M.Z~ͤ@QL6I񤽦⥄:ĭppE5җ&N8A^9>tp@ek$Rkz뭙[H=Vʟjbq8K0OۊMR9|%}įv7vfJFVl% H+RDKxn{x%ps]ov6-LvRp\M:# ~+i7 L ]*[K^ҭV\am7Z vA d]qXMkFP*Zc4QShJ%I xq⡑Nאh`(yYrH8£q;XDbc,ODe\?WE7uC5oHj9y*>ӯ M!È-:"[hLe# ]ty1a2RVvchR6n8CDPfOykՊM%*X`'‚)l)u4jH1q8QQ ¡L7N}@A6]XR^لJvaw^+kSRXVzuN~ZyCzy8BBqBhҙu.CX9L\mQi ǐ= 22T;~7X \߈}{'WR雰uvdw2[I_R3>%Bw )>> *((=X_n8?Ju5jQoM\'Ru&oڝNԝ?isoY{? (H=C-^o - ADDODz';.s{-r1इUy鎦^^sNCadd!?_LhiТ\16҃M<␅%[y'i}Mv0XFIN3Yb|E% 1$ֶgܻzӠn#<նZXtnVJ %*v;)[mD8wqU6x겍A!'u|(1K:䐴G O"Ta;VaE>S֧Q8a쐳ϥ ZЏZ`{:9aNzYRGStmyٞ |}$;5z JJ}iaD^U$T|*5r,H]>1A&Z_.rK]8Jp"{(sWait'8[Z+Y)97vRJw@|>\vDVƄt$eq8X4ۯ Iu9i!Tԝpy=G*qf}DΙnpmpkm*#iINxɪ4ij*p.)Y8V>czUāTӎӎ=*rӏuPT`uƵj&y{i=W]rUBӃssdX-˶a}n)PQ<P&](|*LiM?-:"2##(ﰡ"`k 3M%|֓iA&2 NexU*jR|#M4DZˌ675:Y_~AɤicTanJt,ihT]ݥmg4[eӍq6/K[Cn;ZwTvZqGC<}xRH9`%-@8W$xHBe[nq\sPOʪڟUͳKCM)imם^8p=*#Wvl$) r ע^鲋-X*Zp<[M}ܪ9R1hw8[j@ }╝]f)  J9 .+HeDb < WG^qxޯ.S|,nf#;TiQqyg_JԺ.QI#JNƞS.m#S2*C,/k6•!XB9(zxs[/ Tz)I&i Ch~:ÐJ< J~iҊ 7}Hh6:>4 [-ߨ̀BӒYncWUN+tƱ+r; 'OmF|pJh/GC\N2J}=`jXmY[)p5ڻ qmZvp薎F;6'@Wv潃8r@>3ϥDj;x(}ڵpvp8'f.(ت6KQ2pN8-o]H m;eA!O)=ZDWoȭ{5{Gq!%D'ED)$)C!]>eR}$rTO>$ftlg %@Vf!#5H}nfvQԶ'#5 {<ψ *7KB>§{mg7~"#?jsQ@QE =qc~jѺ*՛u=͸_]ԡ\?is6wR7??xǡF_J(Ѻ2!|!#%Y9¹ <-C}ZYBR㠸qGЎ6-@$}{:ө6/+y-_k'k@nnh*1:6=׽Tӫ&;՜c1Zu}[IȦ&[̘O)u#}iym部$5( k }QS;Vpj62Tv86 焊 W+[m0s|ȬꎐBs+e= {-ƕIB*#;BSsySBz̃ 40^,HCme-wysx҄TFGjo{ORO8b;Bqq4+rdyynR=̂{}m“3<Ʒ/mڛ(̉./</b%l-)'Ӟ8o.wu p'a$'%g'>=EIZf[%.Kqx)*}&o-=l9c5~H^kZӎ$3]4dG8 k;`"DB I>1ik 9}lʹ9;sXPNBBdd/; ᎙Ҵ[ٵՒy5۶ܿ?M#NIgy{Xyl;j4S,q6ΦTmks/8B4݁"ϊ_uJ)9q3T7c үTߍ4tu&u%/~pR뚒mDLzk)j$8JTO n?'ؕyݰ!XqFRQmP挹So8d57+pЖN1>d@**RjŨ4,RԜ-RT랁c‚jsDsy']3oh)*+[Qi/WQIF!R‡=aC [HQ;g9sfP&eu/ʚWIH@r3HʔZ851z޷ķH~C2mHhVi IP;V3eb"ԭ&Z:?hj \WNUG;ώ4i G+UܝS?5,1)xnt)"c]H @O~;mH? eHVuů(2.'}͕|W^ٞkXid)M” 8u =T:Jx8!IRpI/]JxP<mZ2I-=?kf~2C eC OTkj=0ĨPw%c`ǒCꕜUE;8EMW"BZpHm}S r"1$R 1^Vgk <5.R<(4%%g5!`uAQx{xA=%P&6;[H1o{%jxAJPٳ%jY{˭ *xDQS\1S {YȪ+rbaM,xxzC=cv;+yY ;{Fq1;1%fđ8[ݶTR GĢjvL_OZ%KzUC|\{%{XfV+_6%qO֪Wq9 ,s=+0~csFO5ʤ2@#֍fWly CT3=)rG{nDNEq¿4}'tU8Av!K_I!$CAK+Fە!{%%$>SR䃔1ҫj^C %pq OyǦ\ Rπ94z ْ,(ϙ$[ͰHl|3L.pTF;wxjOwڦ`sʨ:7O\biC6ǁ5mJX_Yrpe/0#W.='u,EPX)`ƫ:q]i R A'`pC{PPu] ^2;- R=+Yѭ[ǻh nl6M!I+#V6{\DF A9p>$9&Qе-1HV*L4ۗC+ Sjp'.~X԰5Ur꽠wGm}GA,%X!hoqI?:mvCqJ GCe$T뻓4BވCxttM)[Ӛ.+gAс%JԳ#iK_8leL0<ꃬsmRܑ B>4),o>-s[v̝Hd $84|F?{0sޣ"&d<<*i\h) T?i^ JxA9[DƐ2k/ŷy>ov YQ쑤[b6c)Em0pBʶSU;[xF}̺$`nPsZ}bYwR/7u>[f5ˮ "5{xjE|ґVl ?5];z%$+ttc$A\WL^aHn;2zCm)*I9XC:LHL( Sfn_ 6nkj4RwɅvAsjWyA*u[ TT3 $1=+gX-6_-LTMզ2w+~~$U$1>t u$jfqÀ6el.OQQHȚ^u$s:SH؜?#NHq!`Q;HQ!rTS}.S`PZd7Eh i*;xԱ#1%l>u/[Lhnڴ=g%Dt ײRBb0J# `uT`-2 J]ISxCƂvYw78zShRv2U*= aZh,P=' )OWWۊ4Tn|@q}(i*.))hcmtzv-tYygaJ$ 0^Zz$ RN=*ؠV: Xڵ=Z+;ҁ"ZiJǒnK>$;]VbdJ(Q)j)Ym)~+%l\)H iqO*e*4i<>ڟH(n\_B^8~!![CJȌ*`LyM[Էpm_:oHsS)Jv*6Z`?3N^ % C`: /6|WG'u/-r{~&tBӕmOWR-6[iQ.PL1@N !)ڃ)10O g@^ 3f53_˘d0n|7Mdg:*T c@z6:ÊCKxS @:H6b0>6|S.K:-q Cidi]4WTrKG($mvhV{kPcO|.5ndʒ8I?ʖ6]{jbdaj;Sπl_4PUk #V>$+5ƚG 9C G6127v-? E ƫ;Q{*F~ӷ aQWU$uISN}bӨ= Ľ7ڕ5$wN+0G^(raxć+G1Q3#ݮj鬸;JNkVraC66xhڢersIzz#;З6'z`VOed?%e8giY&?d;jyi٩HROOJNer06}Tjkڔ (CM6nU_jV󛌒<]Wk^(.PSS-Sxk.go,yrxuP.?r_j/QTΕ5]3ÐbC?*E:JTLj rG]TGV  J%]#젥ݤ?;C.wHCO54зWģ5U«580Ԥ4qI(?Oy'U&Y/8Wˏ{+2>H4ε YJsڌ-4!9 ѻ\ނ'pPRQT4ӺzM9 Kgk䢾]Ze60(~w rA*Gf_V$S`xj-jժwŒ9U'܈ipqFlm_ujY/0[u Ճqg]MPyn#)cw4 [e="Cn ڗ!Y)4z!I;d#>cʗNZ%_&\S1uiqWJ³j v)y$/6R3|/ޓDa$8"<Х o ln#CC>(7\9pir[}n@Cy$>d/ƒJCN;>Fzm-ŏ< ϼ99d}Je-J> Ywg2y!/R!` .mT"*}{%gUb=j)H-ڭx9BKHD28vAk~Q 8 p>O}ʔFG7+j5wtDG|FqA"]]vGw H@R:թm'cJ# ӕ.+ \B46R;8!<m¼:AKuYPiLηaCOCJ 7`wJڢII b\;2;qYqA (3vQ,Np _j뤘\M%jeФ  V&1$Wt2MJ0FqH[u䄞2pie$bIKiLϡ)MS&(u}pMhwK*C`+$4K7%7rG֨}ަYmڇ|cwQ_XWʃVzanCI$'J8k\"J-<9smP̸ X:Y3|R[1ƁNȖ1ȷtT03TƦb= Ci)hvݾᥒ3@M!3#,-[I䞽jؖœTqp9*nyVΫVN܃TpsQϛdyH+mJ#$X\QZ=BPNw q S$YlބP-~GtЍu!EuΜ+<9vUV*3'Dl2lmDRtH''@Z&EEPZtŹ*guAӋ{Txt sܨk2,_/5uTWjV_)]65k5袊[ӷ#k2?Qؿj*Vf X 7+rpu*H5"t% agcC)~oB!=O###JtlD 3)?h:2٨ЉZW‡o7;p'C0ݦISͧ)'zS:*e%$dpO΂Ŧ,/Aurp c5:Ta4ڙSiu|GR<ᚉvlAVph.zcOBbE $'U .2eMSG JƹXH!}`c֫D: Kr^ P FA+> iVin!ih#xMn<\O!p*h~Z$%t4]FJ@$Ԋ)pZ$$)^4+.l#{q)Z[Eik{YRw2wSpGւz6T%zP}~&F:xUϺ+ުu3CdfRWa8Ipcn)П0IyP^S[p.29q#SO=`B.]vp8$)x$ަNؤ<ܣ`Tԉ5.nOJ2BO5 wpeIR^8_դG_Q6mnH>T TZn'2#Z([dJ$UgZ 2}Ð帗۴JoVA xfA[`:k)';|liKɂ7ӡ!(ܟW1PKq 2" TwPvPo5Ju -#*uQd*kmyPܽ!f0-Cy(t%sݮ(GO}z9EkhJJ P;4۪emRDv媘_t{' sW7NQ{OZkvD hX꾅C8>T[p4[VF_OvS]CyW$RJlw*m-[Rrܑrc xP TύFj 6]p9߻#V ir.ʛ9=(+}惮ZJMإ6kvj㔸9zh ʹriJp z E⵨4~1N8̚kXݟvW-$@?fUUS{-5%":ARO?BvK8m*H x$ ]+|KneY! *YKPwhNT#hpam)# Z6,wY]}RKBS ƢeۚzUN=Q7@ܥ$JWs"L^ Pmi]*r9 pKN2+]8랹\[*h94^\8,p~\ӗdM[@BGνSo%GLu#9L{ef;VžK{Zcn=rpNwQn:u3xV{rX`q¬ Kck}jklT; I+oRcF~f=R{<>uM_d\L|6C]!ioIwC+p)yI(I*NG<>T W r @ฮVp2DgjR<)E>vH] b|W+r}z#SqTSEW >Td!{ik-%rG\TͪVԄd]- bJQ߅xg(0߮HcI(Vҕm(5ݠ$|9Jj \~=:R=aא;ԬqY S-*N6p*Y;BgKuJ<Z)H{ WW3@8J`Kd/pMyڮ0^¼,mi)5,$xbIXh 湯[ɳ3$M8R#OEڄZ7Q'qG>LX+6 -V0N<35~2HF\s%#SǵMQMД*Rv:dԄh-y}z <SߜZQ z!y-TT^(( (vq TꋴD_+uw2c_Ԗ]WՏuV{{jET.s m5ζ>dT'w ~͋6Ҥ@)̗ qBm\Fjځ]yx'T4)!TGP5v4ijPyT3-sdGe02:n@Xh[g?W5!+j(+)l JBv!))ϡQ(g5nOA+֢vm/j.KajN;w)GCk.*dDT ;c>Tb!७_!HkMe3YB)8b892iُd/Rܪ,t${|=jFUfP[, ?OQ=vc]p3v(ͱZXlA/!+'v,.1 88$*$p3.[ +q^'UK[ڐ륤6+ OPF_M݁smX_QR=or'ğ;bm@mD6}E*ue M}Ii'$AuӺ- @>2FKX@񦍆q;_+t 4%-l)9 I|.5L$%&b02~*دDGVҕqQ,+RzJNx9u+k}Oasrִd$2*=.ZC֣'v۴, '+WzR;RK<?‚z%}TLd,d6pxIO<ǏFrޘ֘vĈ;0Ԥ66Zb~ţc--JPtϭ*#xJUkArb m_QʝSP9m״Z\i/OٜPVZ ޶m,eNpw9P?RيXKq9R~%߶f"[ є@⏸'&Αq/r֢p`{A. s* .nZSK q8+f9h(:C@5l32G4ao{BoS2F6*_Zӧ`*MP.8?|i3y̽=> M[%_:ʔT>V(( Wwh~[m)쥶wۜRh}K{|?0Rd;Jw{p3SSGw4Nr \1eRw6wtК{co/F:'9 wֳ9nquW:M7]?YwT.55U>WXƍLEƦ ((  EPZl=_!Q)[>ǑWȩm H =3P:zH$*U'2 d˝_ "ɄO?n*Թ }*J6E& =G*@l69>BxK'KCEH*{N+o|Y_ 8C;rԥR WŚ~mʔ)\r)rawXOc?ε'r="O{aKn˘Cm$zom6# 1!0G=~u9uկ&Zh@"J N>~V$I$&Q@QEXWC8RH#;lշKbǖO*q5)6LgxW&{6TZQE)(j33ِy FF_R۳ )OEc^ϧa{-֔Ӣ2r,8m)')-0)QEڅ3UJ]|(I$|MQ@QEQ@QE?;MJ=Î(P\-'1G;WW{%~me7(ςO{j:~n5 ]Iq 6JxN $t-//Nh9*,滩r%堕GUp)GJiHaNxߔUwbƣUܤ(5h8Вk9skQUQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEmricron-0.20140804.1~dfsg.1.orig/html/tutorial/images/npm.gif0000755000175000017500000001760510507017374021555 0ustar mihmihGIF89a[DDBD̄dbdɏ<>ͻ(q@Y7L6`hV@zuسkΝJOr+GmuV>ܒE_~u'}Pxy't0^W͆H%Ș!(X`q&k)J_ZV+)f]-A2`fUcn!U&Y|,""|蓃ɤLGi&J(ihYЙ12h`cfMWuMrhY']t譵ZNjk& *:Z[TkmdgJhaQ|l{k}*ҫ&,Ȋ#JUuf*;JʰۨC|n.j7B׬J'Pk VXaʭߢۧm]> tjL ry#w 3.愗,PwYcmvpFmy]r0P-Z{i  Zf#x=wm嘛%wwUG'2Fe및ulnlo'D/G/VNogoU ⧯ɓ?[yߐȳ+Bm"t.:%"ꎀ׳6oˌjdAITsGx~S:FC$9IhqǠlHPPt0?7ю$= P$(7SZҕ.}J=JӚH_P'LROIgO1:Յ6At&Ul^*P[Ӭj )X*ֳkEWVbLͫ^ RajY ,}OMś./8WT+.,w`K9a\ǹ9򑯛-å;'NuB}U:ul{WǞdӘhqϞ=v]&w}}Qg/fX<5dw<(uIQ?vǛog]9Y;pkOghF8K5tCs6izc|v_;{"?*gǿZЏeT>X'tg[G~{ osHigz61؁v"h[TF[n7wwo5hV18sG%=q]wo=xav|Bhn%`P8|vtg'kMmD( Yץj,aY(o:X<|wrFeb8N/g%׆|~nXne(aqz}؅JXz#GMȁ8ַ8؁ hP(SZ59Xzr^X(g>ljжׅv2gض{|Hh8iXxW qFqȅ@7Xhg릌|}Vϸl(gs3if(x&hȎ׈zH{x;qXVrՏ(^8]ioqq9`w ɀtX_7i+wՀXa(aVgr鑃uG']ͷg7.4[_sHb7kؓWbW(zhyLr *aޥ 749g'GbRa$io7VHl#tjW~x}ɖvG zBՒȐ)(tMvX،Uޔ9y ~rGgQ5ٍ@ǚin{E_'ioYget'yŋrea9pb5Uȉ_Kub)_h_6ŃFoH5ɒYԸ_wkIRIXEyrIȝɉb,pEg9Ir망ș] ;X57[]%H٠ |񙄸}?'xw^_שhc:ڞ&+r!=Y(*ɟwQx~Թ{WntaY W؇*Jjy }雊g|DdIƛbujĘ&|xy*טYjԂzgQfpj'4%:NOzxNCU:0e-gqUHꙩ*N:Ȫ_Tٞ y:bqDj_֕tL9䷥ :%ʬʨ6)Zy dɭᴅ\:ZKꀞʮ顭[jg{ ŝ'Szsdʰd8[NzqJx!hKd(% ZI*,۲MɱH#WuYV K7尦Vg>(Fl8Bx'ۥF`9m8pP˧ y"iLúS ek6 '{! 5 ˷Gw\{{sI12{ º&ʩ)TRȹ+Ȍ긲dsS?[%шU_UYajX+(sk{[{hCizu۩8;W DYxin: Z_kQkBʍ$zq[ FX#|"*y^@ Y)s[㗿KS;Z]E{bEEw$\9yJ[̊ 繞[YYۓs.eqYZJ̙Zɻ2ȂN|P<TATſFȆV6tJ߫ũګ|tH ɽ|ksAIS#L1x4۴\ڊ5:g{Y 5G 좾·[V &|X;iY^H&U|A7;l}{hЬm:,N˝;2raėU|x<,r<Iry_Gã[ߘh<WJ_9?⊾K{8o,wo:=Eڢ@,\6ktOIIi ˂Oܶ׾9;dkk +LŇ+w:f\OZu,˺ dhUioM+ΏX; dms,gy-nͅ>} ;[9)= *FzNJ|^+خriwlZO>R؎*̵ޡ+ǹ}e kXm/<N,6'͞A7f=<ߣ %/S}OwL%y򬬉~N`'`4 nL3Э d^&>vl.j 򘾉Ht˰n}m|)G~U^g.UM՚}ޠxI OV5*!EHl*sXiQ>?: i~3g3tv ?e¸ՏVEG?+J/NO|>@ * `…|x0JQF=~RH%MDRJ-7PSfL2mpSˎyTPEETL5SЄ>^ŚUV]jl6Ω_͞EVZ%ž+5ζuśWۧ}-kcUU%HbE"vF \|"f-GZ~MCngʉ7gU]CLumyaF\-\d(6t_֬qO뱕Gߨ9ێ$46*BDRΰ < OFc;f1Bo<1H!AJ/X쩼 G 3^|r#2K/=*K'cC쀜II,K;,9հt0bTL,#4"AkMzQJ0lҕӴSOʓ=?%TSѺTLOeUW ^V[MJUQC C>uF%3-DX?M7I5ڮbs:DL+kipElRZuʵUyݏQ6.RmD7լ[Lw]Qo/[(!LMp'*܁7fE81XfͥX_G6qeaԘc VӐ;+JCf$ά mDQߛf޽ɇGÙH&c޹j WMvc.Foe{Q!.TѮ-9?CCNqhkk" 0pvѪt6@9'Qj $`&r9 obK)TanB"v.AfGe1V7!|TDډD\ 24Wc`æawz:1b|D3ҏftT @lpL7 x,]JHJc9"4YIN6$:9JԱPwH)U :SeEZ~Qыe.o&^җe\@9LbӘDf2Lf6әτf49MjVӚdt恬g89NrӜDg:չNvӝg<9Oz֓f>O~ӟh@:aEhBP6` EC!L(FQrTG# ҉$(J7Ҏ(LMJQԦ7ACґʔ'iPw*Ԓ4CEjQҥ-)N:USJM*SԭB/jO Աg*ZWZUWMk\Vv+^ɪWʵ~+`Rְ\U+d+Ruld5;ֳٖgb7[^ljIZӲmkcZٞm4Eڙ֨}*o;e=._s\*s%.r66֭.fv׻{nmi;ힶ-x w߅wW5/~+rk_o`/f`6[ag!.jU.0 |+1N[L(qeL;jrd!Nqt=hBЇFthF7яt%;mricron-0.20140804.1~dfsg.1.orig/html/tutorial/images/patient9.jpg0000755000175000017500000002145710513266750022534 0ustar mihmihJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"@!1AQ"aq2R#Bb3$rCSc*!1qAQa" ?(( (mGB"T̎]l,14(8k+]%#,wg^;eԑ'ӕP2ѻh.e}Y_/*`+AA?ERvZYL-X4KoCNA݃f=ݮ*1UrOAJʃ*ɎGFk^E::ŗ.4rPGIzܦS"F)>PTTVTj!OOִ (( (( (IRR $@%*ZR5ah^]5L ":~ghARQ q)S>}۪'NcZͬSުQozBΠ!R!0Y;Av@*xFsW;{ա!jkLCRP溏 ?淡e!ӫQ ?" C,68F*fӡ[ G8>-vk ^0Ϛ^Wn;ejG>:5$b2 q6kj=$RVv΃ޚF8Tr=W.+ (=jhFiMzϳ}yo!#9 Ɋ522W|n$rZ}2S-ZoQ%Q"B8 ezh) IGWS:nv|ayi^`|x8? TAʃQ@QEQ@U}&SyNKMۭ͘mJ2@+΋mXЈ + O(ǗGXQfXbi-2Wװg֫S;fRg$dٴե:y%Ɛ @AfڣZ jF;).FՓzxzȭWSV͞[_dtwZj^ A3f[q# 8{#Bq a?¡ten*K` njc{V@/S058FqKA-r{$w3.6Z,߸;ZHkPƣ}pRМ4u6e2Jy:wuHdG"Yy#AʔTƦ;bh)HQ v > (ڷDT3,MۏFۅ0基3S/*;n; U}O?JjeYcq@c\![Vp?h%}$ 'V=ԏ/WTNJ. Uv6$vKi9ՠ,ʂyQ,IB{w MoR%,<=m.\RH&vny9턞5IƼwzw w-[ɚ™*#VK{ҕ Z;SohuBDdHW^Mͩo4q;<Z 4p; ~bm9DKSlVV;f L@ʟS9U(K"x㚭jt$Ҳ1n'-w2dRs aTN!5z.;w8k4۴4CriG/ ܻjcz*&;!!+>3R-g`Q%Tdi/,*D'p3+"O0 U4 77hx+a?N*n ̖J+=E{MB#Ƒxjrkz1 QW4k6:9J^i˵VMêghN6>06ޒBd:$x=A\i.Kq5KiX}=y2B;T'Q6kr"!9;dw.uK[YIu_nm_`iw>*[6{HF²:glahyg*#UgHKByҁk$qHmIJZ+3>Ӟ"T$_sih9@9Ρ-hRA#袊G+k8~;W7WOXcx&G%{z 䀘Pͪm %kpF?sS]0Ɖ`e2ڼ1TqޓzUCD|d˧4)IE-cHHxlX @#+S]X$Yi3:Pˑ' Kr#@w^rhhJ~4W?ϣ ")&}#3r Ҥ %*{0wT  ^ -P$#OqY n!"wlGljbO1V7zwM)==*uP۱ >.6GIDupHVWm CUj`Wi!mT%c[9(NV¢(ޱKF !Y1JI'M^\@'n5!Z]R->.=MqJ];N?qW=Dz-HJA 3dBw'ޫFϪQ[% !(wq6𑱸i qE˻I%֛z`KoTݾi涿 Z,q P=j D[_ v9m9M5s9Nf29>tS[x I%jIVEkF.^/PY*9RiYA)Pc*S<΁XjZZDV1%#{LtNvTVG4լ4).Ȑ!YjcmxۏAt٥ǹEjC.e$(fx@VF{sqГtE^Ϧ)U PS) )#(` <}=t2pi)Mk} Pi=O?JFRG4㨛-KZӃuJ$~Vx;c>*uV6GRNC)=vʢso:N";f8>'4VŅ+^8r7{ [ݴO_Rpk5LJe5(&&&c;n1$꒵OnP9'"Fn$s cӎWhI\;mGzβ=CV.3\SLS92gHO;nWEzmiF-٧ } uBguУ,X9iөq=s]KӹS9V-%-|;PM=Zr >}jf Kk 1N;qTQc; RF% u 9-|R}O縇4e@֛{j/\)>t 򪣮7͚ (l?ȐI5kGܨJT3ڹ󮒝k\@m{Gh+ks0ҧ8VI%'үKi dqY)KZN6s]$ rZG||ϝJor,džڛo<}wh[\%,8I$Yd96Vow}qLM&⒢JM[%KKj(:v%gm ҥ P}jzRJnJ!M'?VY.n 8ʸ-6wDI ,8ۉJ?{-w4 {])SY.3u`? 0tvkji԰4::ei1]h۠%@ prЀzqUK-@<{WB\oRt !#4tnAR.%CiI5Q|v^#&y>O_R}c s4d<[;1o\a%h*%q#P-EquSs^.TkQK!g̭Y<*jms'CyAvSLIirO@ e,XVWr91qGh*计:W)O1Iªݴ\k1-9QAsMf)!E|u0TN~DT?L5hvmS o VƸASC.TzW2A8\w}ZIݙ# m۴Kx,nҼ] I!ąeJP[QXf:YBp*ziz~\XqJH X0fn,u~&۞@PNEqwI}[H8ΤgLT1Rsn-TA< Gj)N'}CnO4u ;T.yR튫lz}b$/t FyOέfW Kr}kFc\]At{hbmmK|K=H>Zݼ eh֢m'aM~dT%AkGzL8qݹm*U'_o˩S?>2n*A8 O9{|Mܜ\cfܾBOH[S[{Niz~+qRYDTSv%*՚/d%ʿU}IoؤC'Cy=~BnZ޺jGl Q~d(/k?*@%yȊJҗfCJ (s#[Keh7F8p%AIrTqeWc\ۗ3|ܝp(c]ޣpRx7Amd4žyA)Hʉ8 áE<If}JXMal͍m)\gi9QZeZn_j20PKZ. M, }6v<ZSHq*8)^#\mMe ނM _DXoe!Vh.2 #Y]6[[ y}aŵHJ_B9V{>ҭwYnHKoe(Ks%nBPFǓ]P)eAjR;Gq}?c3nq'rOOiRL]W$cq\nfrT )9MiL0;I%AÅcRR'8U]s~,?g/R_40?WG})djTY2>*>|j龌u$v1Zq*yD{T4`DX-)ʻ% 1AQuR9|:]sa7[-VI5EPQEVH㶫P8|4SOUfӫaԺw4#f֐rOQ\L-:܍%zm-DޅOI?:qLzګ Ta!E~M*u M |Oi#L^ȮiaԽc )#$U&KI a/dZ s(/MI)fؗww4#"ku%ӗxN|Kn,& Eoz [p%H.㺱>UiZ>~QBϻ֘/N6}]CIZ0lŕ+#9`*dh2|C{LVa j8V"<їcz䤖JgBM6:'?R76w(nT5*fRG0=klB8/=OwR))G҂#Vk6!*Foޗ,6)ڊ,ZTЗeqK7p'ԟϕt QtGl ?wSdsA{_IhewUJ9GG\ѩ_.n8\R $)]Ouvej*8.|ǐ@QEQ@QEQ@g"t_S^B[|A+usDur[A?“q؟1<.igϵE.GPHHRYa9;m_U.LiL㍫HRq4 pӠ +JMn߭16ĄT He˧Oo˶W͜G941o>Y0oi[>)}.2xiI~T΃)gs?޷-j2_PR?: ^5Kǵ~9x|m#*M$C,R}מBB66)GX웥!KP)RVQڒ{Vgjy`׳L[ZKvTfT76$M'^;@]WޥtZ4CL>Oⱂ@I5f-N!YSQ ZQRTMc@QEQ@QEQ@QEQ@QE} RNRHE!?uf-\_5^tP}$((((((mricron-0.20140804.1~dfsg.1.orig/html/tutorial/images/threshold.gif0000755000175000017500000005440110512570046022746 0ustar mihmihGIF89aR{xĈDHI;\=IxdG8ȑ$(igf؄(HYħTd)E%)rA5פ)'(gHThٔ'HtXxkhXԨtҌJ4xtVt)wd&ڨXT'8hXyxƔ9Iv<hĘDX9THԸd*Ȅ8|@״)WtJhf G(x<XK̴g?ghgԙ(\(,wl(HY |'X8xȤ8Wd9yȻ8Xwy}Xa7L) sLliLw̉GH6'iX̨8(h\H|WivۊxX8gȜ8H8\DDeۛ[ƫ:|L;LGlHg֋*ٜ'gWܩDxXvx wh̘LYHܸlȌ7ܾ$Y|Xwkt d44u4T4lt\4k4{4l}dTN4!,R H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶-p㾽)nFmG;݈|/G R1ܚ\cCt\Ye/ܹeȑ-R.3AЀ5;$uꁰ3VH6Ձv.|`"7Aȁ*.?O a&, iñ,;k*zikt#r㒩\3ηKjo 4՛s,1T|-!W4  OCиʊ0? .H8 Vؒ Gviܴ(m'7G.Wngw砇.褗n騧ꬷ.n[{ҿo'3{AWogw?{_柯}/c߾OO}HinKX $fL)XA V^BBsBzāka3:-l601a 8pH&%.QLApQqщY c/>ZZ EPjzc71swxG |ylc9GRUdH"6q4coظH~q %%9MrAH򈲑#L#_S.cuT5WbS,Y 9W/M4->Pd1i1Ȉ-1L;yIHmn>-#g NϜl]l"γS&BCܓ>ihM6:TI=Њ æ-jΈ⎣GoR49FKz̑JR,ͧH]Jƴ'DwӎNS攈BENQ9Svq@XjKZEKOg ԗE*WZSIuG=UVzB x[}/ &Ů:@ʹ|}*nMbDF5zEkecfx65ִ TR^v$iQ  Sk+Զsa{;Lvȥ-pe'\w=-rG\kfYƎ*Jsʕnrk~*y+]mvq]wgGݙR'^H<wM rUc%-_g[OeKM[Zou0rԘÜ}j3۲J>ilx&5\w']F#; ;gLc"X o^%eq}},Sy*} h|+W3.Ӽ){g֘hqrf~ N+3]X^7ZN(jVӘ 3a׻V5)U:^\)3ɵuvhoc4?6OHh.uVjp#7w/wGu'v7xU|W~,6.19W7ud؁cUVyj7fro+~BGxBK&la"Xudw8y+Ȃ!O>87BhDjFx7Ku,:}d͇Xw77r%瀻KNư~wG){tC^q,"ȇHIG[(q@r^8|r\&~x]Hzw_؈r|'X,PKx׈)Hs!{8~Wc[y8fz(|~X8ؘ|HWxyrHx@8;B؇ϸ~J(nt[w,{ȁ pwWѐH8l}Zhy(ucIޘI89aؔ2AYA;9I7G_;h݊z+?UhʣB[}@<Kh)@  \p;_8d_&e2;w+?KYjjz F}&1Aۧszٟ {p{pKi<21K)ڣ컷9$| k-۷ Lt# P9Z 9< S{ywp\#YG*´꿟@ñ; ͳ -m P E=F|Hlc ࣱ[ypP!=$'msA// 'P%qӃ{K~Dz,}[ȀxIv,Q U-Am wulb=:\0"}+]s `;s%@~P ءxH}\ϋ-+[C1|Բ,̸Ԝ-}ݤ]ڦ] E|Pd‥:|d%c۱-s}d%PM܃MZG>zl̓& FBL,]@ Zmڧ_t0߭=%mb-\,p / P .:YxԼ|{6lН]2ṅ %;ݗ [TmŌ5n] 8`.=P^,֔ psP 0Y]_>,w|~O=ȓlF0@nݡ}4.7F/?k`.ܾ.~^`^0Ϡ刀WAIQ]кN }%8A`lA@A| N܀  ˝IȜK=L{>Yڞq?1^oW̤-O .Ԯn'/d{2 P8<^V}J_ڻ~E:MUl /{I`a?@G/ oLt}{}P/ °p[h_.AY^.)0ǜ/?5/A2 DPB >@D'Vxqg/iHs4ЛS s\ (H5k UBãwv@(\L\1QRMjtUjDQ"\aļ~@XXc-;Vٯ\r72#uZ;X No`.6ZeGZNݻx-C .LXuSԄ[g!5~A_͕pI/o]B +R^ݢvۻ-XkE۸n9 __u,*#02O M4ji!?p5;avSIR$l*Oz#w*+!%6 H zl+ss/= K~XH"0/ zm/8c >#P35TSAk̲,MB 1tO ;|aC"D Dw)ŏHlѸ`Lmq`#Y볻?95 O%(כ27-Isj*T~EBЈLW[hEVzr؊:CuFDghQFs6/KM9GqG`"V[U&%,p.;X34&80!7,L9;{Mf9:Zo!}Nɥq'BGm/䝷K/= }kud{&1.ɨtUW%L昫8dKA>H5VK9ONhtf!wY"D6qx(D/ =hkOo(R#s sSJ1V+f[Iچ+z离q5ƭ)?1ȁ du9wAI-(rq(@g  ҙvD)~:/H9odM_]G l`S^EypJ,CZzz]yk D>|*\D #ƷC,rղ- #8.@d (9A%P5  8 CA DP eM\1oСa9SCJ"Lf+ (Yu XybBRur{*whO4>QR \1'bD*s3"+і!sErQ4TW@>[z\T}Wlh(e n |YӚPJU̩OB1Ŭ3MSJ`@O} AQQQ[#@@l3vJ6,UlUzpf}/?7\OoA!Wm5(bO wuͲayXN^tLNN1eaޙ wQPT'ה#iGwDE0j9% )(ms+ -pSU8;M_4)my_j+g9#/qo/"Wsfl4_ w0NkifBO &1k_.ߗ)b͈L!+WO7τ֚&\!~}#HkM1|_Cl-\ SuV 0$]ey8~ҟtE̗LN1 ;2?sfz,vɳ~K3IBO6Q _tپ{*f_7{5Y"T(>N}w36CcUNXE @>܁ 8Oq,VSh/R;ԩVgR;2>곾 "1Ɏ+?S5 H tx#%#.˿>< t;4D z†BC 6\ۚ;&X4mA1A )H*cc"A@"8Nt:R"B^E0'+|<`HS0I @IgĀh, jT@&F;4!>̆*A\q,>հSuSʨĈ.*JGL,DŽ P ոA`,B#ͩKm[Mau& P[&8u­}PE\Q;ZD 8-"d,S$TD-A ]vM[p ݯу{B%^dZN] KE텫U,][@E%]^a8WWxbU[М|bJ%bJ_AbaN\bd&c".i/ӵ,66)$DG9vHU)59-<^|ΙCa VZ B62h,L9,hGyLvXO&he^(e^MeV˫AtX~X=bbb(b؇}p`-anPi;_@fi1nf斩Y$7S+c%2~ד[o6Sv '4%L&ȥםZKf}6T|vHegFe[X> :%SJ愨j޿k#ک^Հ v7PPh[vb iAKlˮhhmNál%E&2cmvHּY,ԡ>ڣkOJe9C=б\NUbU@]h8NXPRej^k.޾V!F qc-lnl`D4}lFl?hfaYឍm 4fNw5w`5Xf1T\XV&@o^Ld#Zn~~ae`hWknnPF"ae6omN^r.oow_,Al6fGpsnpM+2 &=/ K=gKҵwjVW FqTݿt$Pn}Fqu´ꀭ恸."ZxdFR]^r_K2qi5-.-e2/s]SKkvh8v*Lҽs 6yTN)tOp]~Z.40[dM?] uLtxLtequuSGuڶhXYEQF%g&WD ,/ّ]-ߔ,vi5lvT@ynoz9/ lns9 NxewSm}W?nJ[ qhrF,Y#UMtPt#tuHhHSOkuSGMxdO["[<xV^Gk?VP-w^y7f*8yyyPzg-Zn`+ذ_`:u*OUCײM{'֘%gEI]uj[VVEԩK#)]hVֿsТy*}4Ȑ9hM5֫3"ٳܺfZ]yҸhvtkޭ Od*C^%Tĉxl=qof϶t(@P(BND[gf\XXxWPUo[jMeWW~u[_VK}b]:QffBg,&yZ+FHY 鶗oY'eJ-tQ'J7 %}WxqO7-wyGEF` ߠq}dNTZNKS6uX"ŨՄb8pߦo5(T>G 7JU)ocf5s#<9eYzmC&eGKJ֤OBy-RY%ݦo}qYHd'\se:fkYsМixKg'\_tXYhȪNh* >zTjCS'-ܩV K f2VD5aٰ4cA֡vd,F+풲p5F,Ug0砢`1_#vl˖E!<(T&| Jmn7:P,.!Lpuy4IQBe Oᱺf#wr5(VYǣ5M-zKtli vK3f4O'uF;! aB5G"z@;#L;铭ZƇ!;vc Q)ɖ%Ԕ#"1ti+p!LԘRojEtFT>(PM/ SQԐ}Q7෩sFx.]u A/)BWuD>{c+5'\)ٚ6ΠvMk#yӖ)(6tDXqԤBtV, ]PVt)f"jHjSiZWց@ `T>dDVg)Lfl^S\E(u E]9[WslJƦ5-k]*]6 [}Js<┤K/Dz ųehQR;O2{BP-+NDqYxgʅ [4\͵0*l7vb`".H(*W.mxs|U/uv) Zo+$_i\pI,iߋfP bh,b, ˊسFWR*MúLZnZV r,՚طs#[I"Mmk3 F;V2#c$ID2'Y0$+B$G ozL! ˋh0yEo*|25N5i,-cy#jjhAZP@EV[:4b:-١n0cWӡ׼uV ȨNM2!wZ2#3GXe3ybetki6wbδ NpLL>66Æ>67G "v4KxS爫k<&:^uMj5|7;JvЈPO34W">ά=9ʑrt([D?v<2oߝ\:ѧ[Lt6<]^u_= ݯU{,ohUXwZ\$Ȼޯ^"тJPBZ+lid7Qk)AnO fj!*~aJ!d!c16k,2RgHNcLXY#J"Zi"82b#> $Rb%B% " B)OGTܶ%LԵ)oM5E])]-.$>}XÀmh5VEc ˭/1G¡E2ݗ((B FDZi:Q!a"q&gX~~F))'D^THj#E!@:h/$QPF,)|>,&BjV>)WJ6df))*I [>(EG@Q^N~dVfiddJffpg q.**fbB*ڠpD{jFQz**z%z Sjx)e]Q0ؚlNђỎ\밶. .@ņhhvjDHtFjxB*OrG`lz꧶ΆⓩNkRFkjNaqFXkK9PL)2lƫ6އBlj#uJbGTH5\6+*ʖS6v(׶GjiZjZ!-:)̢>$,mU*X:1ꡕUrM0 6HMD^^_Fxj | (O-zm--^҇*/j$/6/F6.Ў ^/_kvfo`^*npl6*bپl`1Fzmﺨi "/k%&0~DNق;XEYIAZoLo.I"YtDn>9l ^+3pAn]L,쫦cp[( B-咮pağp dv1i  K\.r rb~1kzD= 3Xy1%O[p'İJky'kh0 Dp;B1Ppz{1.G20#0ZmxWrV&gk"1/eΉ >??34knQ@_`@os~usEI  ޑhp8/Ki3-fF!3LSK&i-)6oK"2D&BGCԁDW/E/uNZtcIPG?;_Yb T-<7~HĴXuB^1u?;2?uAO[{ P{!a!uI[wEWNuW;c-0K,P, V55H8dN\b6E D5<Y9NO57r`^v_J 0$4C1tZ*K,Lcel6p糥Yeqrqwv1x4jwa6u뒞EiW/j6PMvpu7y3Etj#߂m\/ `PtsVQgkEy+x71O'xg&z7fOy[r'wXF1~W;5+m*~'|q u!`5}wZaJx~~oKdGN76'\L{eq䥔'L7E/u yy&9Ke~3X\y{\ >ͩ㹠n9e~9e~x 9bk߇:˽ԣzF>?o^#>S#(FeρS~,nt+x.::|T~x xoܷ:~|Qɽ$ 6# &7:fޫދS;wSF뚾|k )R=Tཛz%@Sh@D⨱^N܋˼;zP 9LA, <Ю;%5պ5bk:Ϳ@"zK("bX:m)C M)D}R-K̚#)L!|E5mF*#WbH!]ЈL*˸T9)ӭєIJI14J9]-#3A|4䤱F;oQ<4$TA 4XSMQx 1MikBt=BzIJ G=6oaNx!,`"Fs6\ ~ v;tD!:v|*< bHbI\( joWؿM$Rve.?Qua @dFwXG!b##H9bcZDȊ2` fH\{!GOWTQ!mvFmÓÈ@QtYYGYrde"8qx95_2 4X:|Ζlf35?1sHYJGBzE*uhx3ql,M8W^-dj'fL/=r OdZ^R ]Lj]٤UEy#<ˉMhb4IN3+<Kܐ@Dj=- jE|gWRpшiQ;a4qR 0Ԗ')ROԕTb-*O8zR;NVU:qiixF-jJj֥. y*TKgQnjJVkgԫ(U?4񏲒U3c=)Z])s% j'ZԵ+ 3 KT` ~],N9An|'eO լYZ<&A¶KwmM+8NΗMwc"6S=nbѻŬtZ]8p oɜr:ML1z[)0 aEĥ쭧TcUj]8,1c euh8U۹v$ &;pɕ16b.vEF񗻋߂ݡ.o5c|/ !}L usqZ=@h7^)OAьh>s-]|wc.3όQ?º:9@q LFѼ?SI~k`zvrwEwbҘÌ}ԡ6%fFvp!W6MM vBvml&ɻAR7-iv&w-FᰜqG=?升v}np3?~[3?ޕx 7f;߬iLn&ӘygyϽ =K zNqux0akr@Q:*v/˕c#fyUC 7ҍtsǝu;~]=:Rg Sbq_r[pL쌕Hڿuj7`oAkZQNȒ>"WFb=~TCtX\CX׮͛q{ V*hUPӡ˾n|?|~ v+CubC Ĕ%zHނ~W EΘ'*X(D$دH /EpZMAiY`׮O'7y5,5blOHDR8NZ bp Yb ʮ1P#ng| /  P AZ0I OOG&qI!1%q)1G0/ðo^N>PUJJ:H&i SaXBy%nMI11,*)ILj)p#n|q1E0ai (28$Qr4 H̀ qcaO C/¤:AjFfq.F'qjiUN'%*Tr%Yr%!%]rj3rY&7q+:t!#rr H̒ތzb$)P'r."&r*gR1H2T0!R(޸ ;'͘@8mh)13x_:*2/Y i/R0Mްj֊ ¼.) (E@/133-q Rp!ss4&0D3'{bN ;2BH"2ts7[75 Ϯ@8 &H0'ò9W OΚM6DH3@2b7;3<97N5RK+<ј+kVKxB2'<t@}&!3;&=&=/-,T"+5cO ҭ薠<@o턀@QTOS!R4JKSK]=7JIS:ŏcbR^#r7N44OQt%Tk<3C ~-Aq4LyM)ogO15S T%A4GrQ4QL(mRTiK ƒPuvMRv(SuO4Jt]P2XSXUT#JT_RrݎʯhI [OUWuOC@R4TN"UTK/\u=5)YMXc'1`s A[VIv[wIÕTU^gUawPXW^=5Bd/SR_/̨`EvdU\TAub9:SXSb %Ub MP FgvOрcTe6^W8ebCnfEQiThEr\Ӕ Z!lAdǖdf#U>29o2XQτji'}v`գռډ}qƵۡ'}ͭϽ-Sߥݝܾw}ޫ=V']#a^E`&9-!5~'A$޷+>1)B b9Y=E5^SY^}!9~!m;s<'wg8l~^~}^);iYD ~^[YԞ~oឡ1X5>ٞ գ;30Ō8dNe̜;{ :ѤK>:լ[~ ;ٴk۾;ݼ{ <ċ?<̛;=ԫ[=ܻ{>˛?< ;mricron-0.20140804.1~dfsg.1.orig/html/tutorial/images/meld.jpg0000755000175000017500000003571410476414432021721 0ustar mihmihJFIFHHC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((mo"F!1A"Qaq2#BR$3Cbr4S%s4!1AQaq"23#BR ? f3\c1&\|b?qK ͑O p̒&qU Kkddz47ˁr%Y -.9pj(aEN>[e q\?ˣFl[iTDIJ4TY'2kX_WBR&e&,Ϋf)Jֆyk]2q1X BGNb\3]=,Rpr:ǗGϝ%J3?GȊ [625ᙢAo@y?b-[&*;u7VnX(ZAn8?Ԩ 2wļ5$$s^FA̴/h:ꑽTT)U$Plp߯0ddez랕Z]JFU\sFW])ezI+$w6sD>{Lx ,$]r6Tv̇xiP+=u'v,"R-tOMFb7k32t:2jK6Vu-\>t L[?6nQ2- BQ[/$ܑ=(_ <K= ڌzl7-Ѧ)ta3ߐ[}Ǝ$"8qdC !3$VRW5iLA$5V-1{,XX-KLGAuHayEdPJCm:~ɿ\,j1d]?0BP,)M=X7"ǦNXJIqu& MƜ=f?N_u=+D֙h2QHo/uZUml0YC+|>>]aR0!/Rb=>9z^wP!>>xP>RF=V]k3M&~EP!PX_[Xɜ 8Yy:a?#u0AC@"#bnjm$@\$Ǣp|WGIʐUvf'/J Ï8$X@؋o*|̩fD&gڬ,F{#Q+s)¥Gz%rE"]kbm.6RJX5W*fL5"RÍ$lF'!̳Ŧ fCCLIˮſvB$N-\fA<8堐0u8Q1ڥQ)j::Kԓ *9ְʜ19GOMnߕE$L3) ;LԜ阩48%=FYt4\* `/MuDjR UI:(W1OչmJA]1bLP  WTϴ$<O gnlO͂R}C aG-D-cq4C<&M"6IvRQr3jW^2 0Y23O CӪ}!r?y=w`Nk PO9B@=}EFND1V\u YkξŴҷ[~dOԧdhڜ ?X.3at7]9*vDB2͹)LG[EP; KFuKO H?W1 2G&0g 24ŪCm*.-.|#lZӠܟMի)ԛ n6#JK|>32jE̩nQKD $|ȶ8<[R*J"lR2c% e B} 95|Dj)ޘ"((s.P⋒N)UD)!ܦ3QXq(+pO'615۲RB8[d =SƧƁrڀe6zvVS i[bhW%2?8.1`v%Wzs0SMKᰵ%i*uWRJ ݓBJlmnUe[w<օ9m ʸ&Bn~qRrYIUY6ƫ\i^rxz?'I겤yw7( sKR2Ԑ brS+gv2! "[VYSe!M$\Xzo9zrƩ֮V,hMLlZӸur$E:J>=:%FQbR_n>AizUJ$ A\P|.%>`v#pG j^Fġop~VB}&T~)!g Jdl K?1JnTgTbR#dyPKhINTĤ v#z:4CLS^\g*QnBrPO͸QƝnB|Ag lbotkF |Y.E`?@m̻Iej;<:4k=},aCił(b+E~zbW;wƳ7g8シUg6ΝvWk6T[.& %CQccRb;)D$c\+cɨ:7$'ZTY3Ԧp t7 `%̓$"m`e2H@wʎ6u.G6u-JHGBѠ;<θx^sbuR1ͮn7Yϧ#RB\Ioy Z?05ya}FĭC% eC{$nzCNJεH;* crH8cp5UT#Te+Ӹ^~%JUnSIcRA#B~mf.!"5)-}R}1D@RJq ,p;ZG(!7))$60K2cyIu| ׹qb0 \;8i7BRbF=R߱IiMFͥ! b>:+vmwP&l5m-yzL*QCFnsQPgR[7P];jƤ)v0)Y@O!6RG+.bEb"$2 a ٩H#,3]rӛ*-)wG(گeCH %rQz,l;v/1?Ҽ;>˝d$4nTc<#v4 ׉5ɻm2.\;"斊ځif?2O'Nh3lw UWg0%p4~u/=>*d(hX[r>jQZ1Zu\|Cj:X)ذ)]o1\Tw(k5*@IMLTs Rsm0̿PrSn l/pԹٚ VZs' ɆR*u?LZ ?>4%&zTPn)GAw.W-\P=z T8he?d:Vœ #x?1Jj+?+;~eCb1qAbDH3K5YàxT#ЎQc2\[USkTvD{:{V;U`=LJl*)>Gc]B S ez㠲]5Hq-4ϙO"겛KK"#L2;4̧vJLdPL"oէU6JLz zm&9`R nE0_J-?Fq@ehAf\P΀ڊ5=-rQsd- ,OQ-oxT6* =~"`1o^}q}HG,wǶãFK[XgZt}k) %"]U"+jtxFoK\}q>TӹDBl[IADp'2RRt'Wz`%enHǚ9&[sZBNփbߨ#៍K42CIpN$0+- ,nG:&46&E_*usfE*}[ޝϾMy2HBwÇ+,1>P=G5HBWE2(Gv8J?jTIR;\O|-$ҡ0YZ0ɹSJ _bu.H ?-ol,gF4;oܦ2[cZPmc}a )vp$A BueRTtj%Rou~AIn*U.;&U&% %!*5[ϩ6Ee)L%AW[I23͓)8j#תѻi rpŇ= qlHr$9f)zJm )IIؑnZS6kQ|Y O Ey3KoPAJOIɠZAvZǪ)ybMRM:fȫVK+C$ -gJ!ɥ! ү.!"N`Gb4I%e(Z>[&\juG-ћgLiWjޘuLj>}?pls{d oi?@4tQ*ql]`7SHMdg 7A$$tj T9YQ r8fjobdꀖmO}6NݱkZ^ 5s#l?ͷ yJ&GHNS~}2QbKk^>q_l_~iThrg0uCn} >xeFw崨#s[p-?&9郄q%f:Sӫ&I[s 81kRZJ !IY7o_\mRH %:Cƫfzu9VuA6iM-H؍3gQ6jJyҔsD=01TP^LǕ>-].,%Ǥ\- f͇-BKNE:҈w1`nʵ(ה$H %$˗ӳZ[1`ce?&oɴob:Mn}re/ՙQK~3!hZ~lsT'PKgY [ TSDT\jci\[5bWrNܽoPxsO+8/4q R\]b?/ԩO)GEq:V4CX-=*8l Md)s^pS>#[=I@r]̴i9Ep^l=EȿW *Jd>EF(TS&gaDjќI?NeHp'㥱UdhT3tdԔZYF:Wt-1oRtzaw6cU$=׹Yi?䐮æ:¼ {cb064!lUiQ~[~3zNj VG$ح]INNnu*V$VǺH^[pAfWe*LuA'm`gqar ҰJMN"I;pzvmTZi&PIo2+*u>*/  =-a)#r]C0zo1KڸaդN,rȭ0NmQqm *{|p ዆X/{z`A1)KuI֢ĢPĉQ~!$,+Rh)_yn( 6e?:\M v/8RE-ޝ]-r_oá ~GۯQ~"mbQǵSHYhRA*u'4 BNCSTV[԰48gAMmʂ kAHABq;zWWQ!pAHFa}H8WE1GZ&݁N[4ԄC8dBJtqt,"yV+je%-)+(rQ)~qjkFO\ 죊q۲ .:m'*8&򙥮%.ŅaL!./p-jiQRfHNK hg}J,E3IM.A\gQ^lcQ-ݒ !91w8:NtKqmJS51J'_٪+EnCMWrl-OnMKTXJ i`?8[䮫P|*xLU6V*CtNxBżV 26rc4WXU-^{m_ksdy `t,[HkZﵹ;c_$L{t)%x%heXF}@ȭNn,\]I)ȷLYT3 ĉn%1|( A:5edn*7lo#)SklCU34x%Ī_A =5:{.{ȼr7,j͹ xM +2#YlVW?|M~$7 qҥ ,Jϥ~c2T\_Bϙ@ԣ:Xcj6CJމ\EJ1jnTJ.ܑṿkaf1Mqٮ#Zw "罽1rt}M*M# K:IMSh:2}J RqJ R>{wШi&H:kWm 4sO6AMcXǚG!PQ R8JS)-Uhj=EspP&[{bއi!ٲЦJ_ V@{}`j~_f>zqWPc뎵 U9Qe|$,zR%$\#=56ѷ|"Z=OA+*%CM`<>}Rٱ=d\}ǘ⿉N'uUê 6K> Ά6$IK_6þ/9]_M|ccʊ]mAhPA8p&Fp^*'I< &sS(6oܻktDfH\U2GĶREǘgs†"ȅ#:k|TđZ& V*ƈ}FSuN㺼Jk{_b[t4x Zh*TD!}D_!>@)?NXA~\EBF}|ö>H*uس4p[BR\־:5H],1P)i )v[[@#洕m2~նt4Nm@xR[Բ!-=fw0"L<}p Eiu?|<'5XrꃊY 2M9C.ʌ%mqPRދ;wإWJhs5jvd;M cI(6qXTM\lPhף>S olul7S ޢMHM:[NJu!$@{Ƙo225g]:5Z\{ d A׺G'H6BC Jm,T썏Lt>dnV f0c9nΩ .R;h* nco<<F\Eˋ)&NSbޟAnطgAsRi 1:#g%!V H-%>-nHgI!y+,;6  BLL0!kOqB~GUj\MnmA:rW2#X;zXfUIF6"6>V)֞1/.ګ=R̄ө7Q= •fxЏةsTyl\VDBR7k$Q"U\d$VQ?)%IoSZS-h6noVd=ߒ(|zey6!gCX8Y_[E20 ADi:OP%6TåǢ$[ҏ5 YE;'Ìԇ0-\'ر8+bSi~rRS _But7달Q)"q dm>/*@u,I!WQGK'Ҥ"JH `W)RXqC֥Ǜ)5MӅ^iPp˙n&5%k6$]bAJS)ț ï9"BWC'r&wĤe4ܺcn-TԀe)WZçlgL3SABn4}ec.UCi) l5i*66=-,]OڧlVFAhpQ3^1*TWRUWmMf۩ogٖ8Buʛ0Ylo/n1%̌lmnۣFMw4ҤuY:qaٔ='1en|kT\nB5!CBFU3TϥOiǴ%^²{JqtiZt6M=Ʈ%C*ĭ} dEQH𛫨:l5 ~5"Z|BŷN>s{$aYҘťiG˸^ݱ^9LRa\L@M *7<N)C)X>5Dw >^F\>opU쑰?S.gCDV U.(Rp23SiMBJv"P8 ̬:*kڜB@lE".P뜈M̙$]n[8VR YP|=.KqJ[eHr2v dtQ^kRwPRP{0dV&cS@\ro,MPޟ *NkRs ;묶r*:T */kvCK5&2o4(uaA:u<71 4 }$#ױ\G*Qr ]Jbʹimu}Lq o[^Hj)-{*a|=P9(t ^*!qeIlT3]RVt*bJ!$%)VqF.p52wW,qm[A;A*f km%ܔw}LI%2#HqQ@7t4)/!$7ʩ"55 ʜM"$!ʊ9IMΧ>Sloy8!rY[(m8㝎 j 5TzַPe,ÔZ2jVmGek A%`:b'߯lRV)ݻ,Si1hƘۢG|` Wg R0%%8*^b D4HJm)#< %ָ[[9NߦWqg2˩Ye>ʎD݆y+'9I|\Ome2eܩMSMtZ(#gpkr ÉC[i2?5|Bl=APӨ)M49{`Daft:$6 MX Lr=HP%J==}J5AX(9O"5RU; 2RQӤt\ePKQ#kPҫ6t )r#Ymnb_Atڍhqp`OV$ҘAEVch Pب|y +ӗ5KMEթ1}dI@oĎ&>K6*3mIU=~T5$K95t MiH! x/1'Ԙξ #n;%ɯ՛ Ci!=¿5gJFH!Il4dHQZbl[Om*(8dwS+*MezsNi9WzyxgMND*~~UM,O-W z\+fyyϊrj K56ߠŬTN1Ŗ܊y  hFj*yߞ*4uO 2m+/K|zQq4(P$Ө DwR 6;t9yb Hzx.,d;U R#eQqᅱɜViꊿM6eIKg԰U i(*ۥOSq!͑S[.S}Cmn1RS jR \SW0 ů1U6>xJXJR۞$pǹ{]49_Ԥ)RnJUzoIrdū˦2-*׷A܏תٯ2\VHIJ@'ĥl_, TG4UW@G|n[>֛'? Ko.>8K)RX͛UrTTM=g+3 ]E8*77WMl ꨳbȳ`9Zs%M #R{SԪ_y=UdFخ`0{é͢ 6OCpd;OB0DS_uCVgE[Ii?kMl q@ŧvJ Ms,[]fyqB@d,wþ*ZN {-ej\Zz\8qK$܂_B⼪Q2dQr;7GSp; 9IDY+9VeQ3SnBǑ8U2o_\@ʹdox1t|bK<ۨ/2 VZSb8[_H75UUaIaĤ"*Iwa2go#TT$z7!ѸONd Z*"ǡ$mlT~C52CRZ=vTE}Տ%,i2sWQ(QFˬ -`(y'ZPj-Τr< ` "mU3Z Skh5h- M~-Veg&(.YLTeU![_؜+qt4W2vCCjR%<)O6ֈ_P j*w뉄L~Ms9)-Ku1 -D46b9D)fI%2!>'Ы2ZPZQ6()}#» Q0eR`VTO4Wu*BZDT3L?zHC@n5ck|@B24U'C[0VJ)R*}j%^%/-M) )PlF<1(|Htt2"t,>#~ۗ+UW*SUԸL_`Lֲ+V[yq(+P#˶=G:xW^VMž=?L/1"5q&Sd)']q ZJ7'1"f3Emricron-0.20140804.1~dfsg.1.orig/html/tutorial/images/lesionsum.jpg0000755000175000017500000005552510507015146023012 0ustar mihmihJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"E!1AQa"q2#BR3$Cbr4cT7 !1AQaq2"#B$Rbr ?*QRJ*evt"+@o<'E_[Pn )qԤp>g.*\‡I,&BHHs5 0@X-Yi}"DZ7\6H?A΋ޤ]e7rjR_O$( {Hiy|CZ\-ɿ8uDG+mO*NKP7UHmQl 婊nN^)^ꕟEID|WJTCDL/]d"4mC)!՟qxY-.06QƳ|LZyHP8[=S _ |\~b-/d4{nkZ?Ԗ`_ZZC**$$$ds_}Nh) ;SWt-qHLpOC+gf#e줎8N>AT5tjY IG~Iem9xP"*XP4/gV9-kua)kFkčg7:u.,J cᾡheDG#ukRڷ[+ЏWuTb+~rL+q )H8"AԮe5UW 1w?wPԾ^49էA DBU+$#5J(Tm2mKY2hբ.WP$mzt!xq-%rnm#G^k.Vc`|JCHBAG"-gϵ|)Rze\[g\FBvYDRJE*TDRJE*TDRJ)J^4,)ҡ|;]G $>*w*fUSKGd?$-o$-lkOYKβT}ޣ=}zt뤛&Vp#aPmyt#KJ9*BŒA\檖NR>--0fO)cJ茗eL.9RәS 䳄w+Qk X / ֈalAAzELfZrTfLbp6 5 (C =)z6`A#Q戈#˄wZrU]c Lp [os~[ڂKo\&q%YQ}x}KIm*!|69E 2`|CIۆjZR[ti@xϾ+,T e$^Tࡧ̰PIJ$0@ R/:VV7)Tgn-U+\E~=+>[i8>,c/k XA ʀM[, *2 _pH( Iu_n?!ΜsK#=Mڬj>i9∑tI>b!i%IGejnS?Q߭ CᰀAH1T6TIH"^^|4ru=Мg<4O]iϫIb$6IP6N0TC<}?ڼYmWk MrJ7 ^ֺ4z}Ĵ궶՝E"GZ/l q_z$w>4hݮKG!yc6w?SQNk}Ei#z j}VZ4^qNNq,*}hn2TfF1]w?LPCwfp-;4Do{' ?i ,5쌟,:^Oe\LXz$Tj.7ĸ'έ:W6\8:|g?DB{OE8eh\:ֽ̫qZ_N2PJ'Ab~GYq[3ZtKܜYJR9(./lڞSi*xoؗ"8zsaJFէ#{QJ(TRJ(b 'YJuA"dgýf6%΅*[x5bmJ] i*TdKUutsʂyDt߫|9AoM^ᒵgii+.#M45-AQ.m6{AC.'SZ99BR ZŸoǏ=ѧe -#@ KKƯʺyvԁ(S\bOVA4e丬: [GRAH*4Hh6ҟ894yzқCdr؄S`GVx).VX`chja*.$8S8gS1@)Xē ڳki \RlGTv>X <CYځtRc#@O%D r=VZLMsx;Lޡa'ǻH=kGR=kUYhg9^(xyJ|)9$SQ#inGi9W!g 3|H'u* t~9м[ mJW95p@ӵ A͒MYm= la@Զvz ӧ?^^İc}]H]λǞȸGۼ[:pBJjCr_o΄K[lvO|fO&7"GV=}u_EXWd~+m;IB~gMB亷oj(t6i@8hi~쏋yzol,Gnr~tTZka19-9J"*CS#$`c֮z˔q)lw[i};*Iޯny|F?X"Lk;Ehup _rءekϛ)g8'ֳkm/xvh- />AhnE !HP<ԮMD\ #x_evcω59QNvܐIm5^QIiI*$;%u@VFFVrrڏ3$|~]IK#oTaϙldg ^;ExG.yr2IWWG+U0#MֶfdH39ZwT45jFr>6Z9nے:d-\iZȟj◆6 `ϖ${TvҺO]uY4am#??Oj-e6Sn$i8P=A43FȲ] ccK"*T)[v.\q4 SZ/OݻIH-84DɼDEK@m/8.~')G) jR^XBO4U2Tg͐qC9z;yV*Du苦 ˰ā9nd<m۴n3{yo—+9Eq`X(ߒ+2Tz_E?*R8Fr~{fQ )'" x59p #TzT-mݤ6C%#'VMAm[!9'Ўƈz6c/Ozv.:{JP2OқڛhB}I;6X2T[5pmYq ^Q?Mȴ yܐTqc{c9*SrIRGhW[ޓ:[m,mPQϭ.i5rN%dKoj=? `.ͷ%S\Ӈ8_.if]Jռ$B֭tGVHœ\PaZX.f'Ğ'&=vbIB?xZ~RIYQ<7)Itԝm;Jig$IѷMxEJ[Y0%+%Do{uYnfS>㟨ηFK t9?$sGl"(UlX7X>|ա2fn eqzc'패*|lM߷$ OR@Vz剆:<޹Z&% qP)=xfCRi^mH[n6i# 8 _Vs3{PL~Ѻ:?#QR0qw%F1 mTZ A%DP3L6!Ԟmmr1<'%CB&{M93${#) ^LY-ޮ9MSx:q48gff3S=Pr?lʏSiSaDv &c.7caH;tXd%[ NOsTSPE-p6Ao\ZR$xW6vT@҈n|g>*NsTKiNdu1[X~+t7qz%is9BL_]EtȫS Hz+'9j{aBhkuG8p fWq\cHz#BOēDS ]q ;\Ɨn > ڔq!XOsNξȄϔC^u,: J@*O ׌+䦏;ݷTk -}cʒ9 Qz&:m#;L?䨿8ϥ.>҈u5m`m*=MV:]Xl}_^!7 ;>rRw(a#>aFݿ/•Z dv a%JJ&"8 y Q@ݑY%)D VeNlT`3X$lHڔ5ͶEdF͡B^C7-#gքk7~&3ґi׌ѳkm҂̛uخ.ĸGF%C$5i,rR Zˣ^jz][oaP}q⹏UXe/ D`(^ݱHinc=E4>Z%z)Dw\"] ˬd&SNi@4 3+r5ԆZ~5]*BwըLsS si~|d۝a>}YrwJ|Ir9zQDYև %a ta_[}+ĘҘAR?Gܒy~.0AkGJT$JCQB#=>}k ${k-ϽjRܐP) "]j˓. S$82 x54S1ZNO:ZkmH#/%7칏nJy[)R.-!IWQQчT=+yRPJqjc|.vAɯO"EHb88UkCa|k'8עcgժFtCo-CjzskAv6̤ps֍ڰAdPH;>-'>O|u1\(~W$[r-$,eahP<]c^jhv-\by'WN"CqUw^>֜~sFYr)?x#mP't@v6҇ ZPABIK ?ӷ[H:S Z"G)O#vP HhHZ[!%)Hq}3a41q!j%~2R !)Qqv ,LLjJ$:6r!.ę!jW+c >t]aYPZFpAks(\D`20}j0TTwm';@o!n?ڵeˮlRI}XRԝ:w˹Jp}H'su1# D`EvT .ǯwm9#o-2çq/RkyIK)ڮ5û۽$#%(A󯠖 gbK,zC:I^ԥJxGq7>?S~G'аD }ԅ\lHW֥4ӹJw${5DiA#zیoz*Z)*%%OŞ1|҆%aչ攉QO> p!ՖҞSѢG+%>v 8Yn-APJP2NoZq)Ո^b[)DcW:W2,ԝ'%/L޾^+ zs-GBc I_v;܅/C c#Ac&綖p9YZ{RƐ QGŒy<׽I`U.vV7RrWxn$}4&ݘܙ5MJ@R]B=(G#I ۇ<ܵBҫ}jÃ{VX5l:RZuvH #ҥZ) |@X4/PQM5-HQ攞"%ؤEdgޢ/qYy +m!rXqZmQV{ߴGPl>(s9WH2=ۦ1>9FNaI#Ai ->VzղN?$vUpECg^Z[r4;J:HR}iZI=+;)%I$ssk*ƍsQ40܀VR[@(qU3w1)=rCRVO|_[}^ J$6 =⣁ܓީl&ǧ)ʐP9ۊnkSj*p628s:qjַçVT@Zw=Ք҇u+&β9J8%Bw-j{ kQ\V޳Oy^x$i;ҷ2늆R )HĻ,E$Jhm@2iJV%#U/_i\c'ױLJ5! Ҏ>#-jid_ lUO@75an皽YQ"U%y~z{-!P҉A\UT6r~U~b7~uCCHZ>D>AsrW37l;~< ^J'O? `r}* yV[$F{􂪡Ņ{-eq=91t+x8Ѕr#%Y?#j;JH RA]i5KHyAd083O+C*RhikojۀK5ױ<7G^3nbqP!#;5uԺ?|2d jkx e$1z}0$]fIV:F8NOo;ߨ>Fv6{tZxqSJ_A Y'DU -ۨ7Qv8"anH {Cr(2i.RXq  #6e0'O5m [n+5U2+~vD!%a+Y$hGKIVVrV5݅p{UJ"U+HvR~ui61`!(,TirJG5seZb޶[ Wph|6ngT C4T5% IJ`<}99=h3]i^IB>c~ E'R`tV2ѝw*) =R6÷()= UR$))QHXϰkM6]SiQߌt% 6#tRS~?\Qˁ<(4 ℛRHJHL}kA'g5`Kыr~<s`j&2x9 ܩM΃|.p$|-HY"5)xcÊ@-!e)8==S0\U-,9(!^Fq'c$jK[}$4NFBSJn p)؀:Q/JpaOOʈ5yqAh&*N8+~#[VUZ\Qב(ijD'@ÈR9VZMEy̹(n6͹r$C~/%*NFEf VUGJN! a#PRַmMJ* p*W1MC$1YDtr\!nʊ;j-Lh !~"an?z?YN0~~xHR|D^*;WHjzfx-)5))Vܟ=~pS:Eն1)poBN ?~#RK`)dg%\ ULx. U18nNzzqST~BN_v9%Hl !._釤@2l R/r1uYDžwnHf/+\[YO'rP3mG'ҬJ؎Vӎ9+Mc|5{Z15q)P801ݸ{*^WJ2KIZ<xOzQ61!$&e:RއeK[kIRj&i$2?XMe$8-MŚZCbJw X=)\Ьמǖ!< zR%=Jk%sU0.TF9 {[tQ-ἢMrq}ʽ}J"tnzU%q vӍyW/Vلϖ{(Һ?m=R$wW!2ܕ!h>(NmiS%'Pj+{-ФeNA^7(Je+GϢ=;zF_o[}M<%‡Z#P=C྆Y(NE: ?+N7' l]2|+xp}DDyh](ǯL{UoUP;鵏5X~IKL(՞n&$ {!'q޵/Hn 9'QuҩǻuM-g)wmVl-yy)a sFHiHIqJO%|K|=im.t):C[f P1޷^ 3<UZpBr*a@<;)I?"j _,TS(ޫ|0@gEBSW?XȐ)‚J㓑usX')3w}Hl%ngQO_ C- t*5%kTJH+ F:+sܦT%j 7)%G 8w!G1DFR5%ĥIp~tJP c'~ԑ!-[mO'gQW:Ԏ?:2ZN*uw\RHBQ]"#c$cǵs"w1(؛ y[sJ#ܒp:ϊ U1MjJm1W^Amc=SG~4ڼSI mP@XdDV-ސBٙK'i~;^>OQYij%#4EMB[zq6!є=zQZI`#\0ٟ{r=E$eÖTi{,2ʒ▗ q@Mctv)>o\[HHCpBJQtJBӲn#GxJUN( k.tD\cp% ><ц\)m $֌C|QLb;h6 `}x{KOORƏ@7<|{iApE뀴U#ִV8Hn<Դ+c{:@\UJxݟTR`rsc;ssUKiY>.qV"8ڰ;G^{v*T_}+Jfo姭0<]t{K Zmi5l &P<6ta!Z”62s8im2~-_Bz%#M.raKDJhϔblj;xӖ8V0 >ǨT&^ }<R[n6*Ur S+"~򖭼wҕjQu6( q$G$֘wNJ-mt(w],]3GUJ&;ؐl3rW LbQBy\H##ʵe)*1^9$!PVp敵[p{\6%EI5E\e4PI$ys^RW)1+^ Z:3Nd6/ e\$DL$ ,фA!2g`I$nTQ@bkjiOv8kh[j6FrjL3!lV zWo%v:s\(!k]ڣV6m46HurzRB!2|E/FejJ6Zak4A)?d(#8 o2Rէc;Z=}ϒ2$+6"7 IQ7K-'U-I%jzWvt hݧZܓU&"!*9jD0֫䒠N(\E#)O. HC!V=iv_Ieє,`iϲIR<*$[Zͷ}^Ru/j\Vl 4y %*x v~D_ |dd(|Wz)bM}tLu_iۼ}rjVBԒ7 SHսgק.Q68vo_8A$GN i'!-(5xHJ;*Z76cX⡺VyN13ibĩRDB֚kmǖG9@PLp–\8G "ԭ VQ1ۚ=JYZ5db5MּuQc#Xv!Rҭܧh*{z¾;L]<5"b8W9Wm**0AR'oqX.qPRBlc=j;!h:id7[WQA'jp̀>GS.n;ARFy# U"%2Ui5>rXQBI86%B3iZlԘk  Zcȉ)RT0c=z"qc>*3%[ YNO\X}czHs\zfH榪z% xEIR Po)I>4d8ǔy+uu+W[0"83;I8c2wM \JE>FT}'*RJ6Bg}GqMή7戵Ko/͖RH,iwN(ɲ}JJw0'璢1UGکZ(+_%$ R?!YoӁi>\dŝ(g=e2_;qCԫ {TC+gn_I"ەorO4Wx&T:PnBgĉ($8ڢx$QFeԹqm3ڈ5u5-T=T֑f)ܨ:G:w Cׯ~4%)C?Gcو*Ex;'>-Y}%qmC.{oxGꗏ,#Jbvh\,'jVNy*^tuXBLJ?}]#`?_lƥwn3㮅%JZ~8?ץ-npvqz[q\jWJӗ#l2VvU5(J J[W' +\–qmHiY I*?Z<BOh'~;Kٟax>Ϩ?=hCnS]Aا;waR9w9**>֯i)ܕ9 Ҟ?)gBՍ4U1DWv\lL*QADm<Ԧ88"D[$u]$ 5'<ydP!SKFrs7uӱ2/kyD7N3K>Qʁ>BaBmqTb:[!kqʏ@zPLT$pO֬ d12E=V64p{Ҫf |8 JAT4\ ԚSX2dd%<5zm^aV'i힟ΰ>$^:Us[ #6Vˀxެ3ұ1<\tw @=jj=FŒĤ<|9#?Ł?z/(mO ~]^/soRIIVR>"\w^6mxqQ ~Ҕu|$WI#DS I71rǶ>4ν )́Ǡ4m}޲e (1 PB{nJIW_>9a_o:JRsj#H ヷ=xS[R2K;S]ߑ,!9;;LkVw,~uwkmpԤ<ڷpy&/dɖ(q5_3^Hڃ/T, F [\_%pKq@Ry5qKZDDZHio26uMs4fj-qQ'kkQfZe-ζUʈ)vSۋdjݗob:MK[lFJBY%[9KǮlAw HzHᔌeC&kmO;5I{j%/xWػsGOz^X$)UōeYLdI@CN($/q яnVG[x#>JKK.?cj&0\J1ҚgLֈE/w{f QM uU-{tǠ$[$[D^J@?ojHq]}>g럲&@]Owo8{.en]xl&;2V?w@#ꇯ7WX.nQ^ݓM1}cp#*#HNGڑZZ)G$K*T)RJ"޴]\ٛD-Զi4"" lFW uO&*yﮭ?;%R4)ʁ h=%d7Wo Êʝ 8J"7V2u`FG4c'y@BpQ͢jc i8YLyKĤģr@zOglXja艵=.0RAJ^ R,t|m3!Gz $?my´D+#֯ToV_|S:45JBI[>yy-m۰=}ZiW)a(>$u>g\}TD$g\n/]%y'pinxA&ZP6[M;i-uKmEs#]klj)ZkqG^@tUGHre9fLƄq)!8jHڔqHYfn15XR/!M<(R׸n[&nD Lz5|J/K_f!rԸ}hBȳj)R2$ Hyܩ/:qA:ݡnm!' {Ƞ7cϴIʃOE$Es[ /`#X@beۨosi--]q֒v%]}y=aX5pv1O өRJ(TRJ(M껆ѝ^+p] f N;%mZOz~C\.>Y^Wˉq-'!@fhi NV~.N;qKEѣnvؼ9776'ڗBqOI?ڰq,hݢȕ,e)##X-. ؠ4pW%{N*C,uDL׉%HKE;̙ ~gVT)RJ"*T)RJ"*T)RJ"*T)RJ"rӫG*"|;S5zfQ7Up2^?n\[WԢ-^. 2Wu]ZQ5J*QRJ*QRJ*QRJ*QRJ*QRJ*QRJ*QRJ*QRJ*QRmricron-0.20140804.1~dfsg.1.orig/html/tutorial/images/val.gif0000755000175000017500000000771510513265060021540 0ustar mihmihGIF89aJ\4Ř <\ &lڔl|d4NL4lvLL |4$$|  $DBD<d6l|L|~|  N\  ̤TT &l |^$ $tjl LD f%|p| 0|8T0||1|Mwp2ڑw|@7|7|`_#`@w|@| | `fpw|`w $.BwR||=?wR|B b?wA/;?w||p$`E|AX;`?wwm|w!,IH*\ȰÇ#JHb$hȱǏ CIɓ(S\ɲJXI͛8s|3Ο@ JtaO$(]ʴӧPJJիXjʵUG:Q«ٳhӪ]˶R1źK]'gUW\IF` *^x.Rz+yҿH bA€=Ѹi>V)װaåp_a@`E`>"A'W*Gn\Vv;_J#0eŊC!d)֥[_uP (vpі 5x^\ A{%|u`_~h`!~Iߊ,ב-t&X"[%Z ~wن\6@ p8BV'S('\._bqX2j`A ږk~7d`PPŝU@Np7Yeb& ]f-7gyЎj(ᏲiޜJ9 0X|B )sFhzfԥgx>BROa"P E|ù`kR饢jcj疉kj pI^)%E5_Q]@E}Ji趿Έ*:\üJ,H) 'qݽYjBU*(̌\9ڧfT)40@H;L7ݴ^NGtRKsND`s5dmhTi_ֳ\PutmSޭ|vQ.La'GWn8Qw` K蝓醃Φw PwlfAk~ɇND8{x;;z |ˎϸ;CZ}CW?}?FHX"Ā#7@"s> y3- ~,t@b݃z#W( |(Dc KPHE!NXTm`2hL׸ dY縓 #h;:qy #Y? t0򑐄$!g)+7ɢT pDixg'w8f4p>~CZi9F:2#BxZ0!_.WeeM dҍ%/{`޼ ^8C{̟ser[S8Q㕐G:5Hty#B9_> c:og5WzԦ3JsӔ>'JŠ$DZP Gg ƻEuPQԙ0=:mNpyRP ,}/GFU=Ut6Y*rGBuHZ:(Y][*> U˫^׾ `K:d'KZhSٟgCKQȰMjWֺzEJn`ͭnw[62EE%.V[Zf$-pC2WѕtA[]^6ȕr]V䪘s.vëb9z/^JWeRg2_~{ ;>x-02 oʋv,CWuN4)ZXr }۫4}bwغQ͙`bX&qj]$W7ÑU2θ+;KK0{I2Ō'œ.95[y*NLE9G8=vWPuD)9xXaACy;8xɛPד:eOUㄩ)9`k\wHٜJbƒ8 x!b=;E#iXyɛrv|gc%C剆$i/#lڹ4rIAIEڴիX\QNe`ȸژ8zۇO$U0?X:qEV\W߁r4fG4^e1\ h`fX5蘇(OH'_` bP~"H㐐cB_FP֤9W!ueV$`5aC_Ufht]fp&H'Ix{VyuCg(^Cf)jUjJ!Efi|\mXuJjBSF*QZEJk {S"hl,.6lQۙ}Z{-Y[JJa:{FƄBt뚴BQ0ͫP}/L p:{]s=\ k\rU[@-vկ'OuE0KC"<zhU^qF }2ݵ˦wҼ-v]>esey͞\HTf˽|QWch]R0䵜63aN5-7Z:,y7ykn( S^eg$vG8yST]rB :y۞\r 8PٳhO8ؿG>ի>#A]7s}{qG ʶw<@+c Qx4aG:X"qX,ڕIhPbGX>'8#(q>J<dE3qG"%{I\MU2Ў'8Qpm#äCҐo,X" R6}vٺZ2 ,#+!ɫHh%9G=CKPB+T3F2*GL B0oKBs\H n I-l.f4bnLP%MlӛgErz dJYs0)H+'B@Vr"O+^8%6;N HR"@M6qmj)y~)| 9U21䤹JGd59V[>6eB4Yj'1)AiMSop$Wq74ZUKAj35 N z7r`ڳ1B}\? 4:sEc ̜~ۑ[K{8⎤r96k".>kq1~vnva8$}x!0K^s$9C 0W,Mcd'e"D۸`o׹B~^{ M"j=z͐eڶ}>|^!\:DGvC!#Q~9\vB'N[Uǹ7y#$\;Cu&(]ֻ @[u7${;5ԫ𽙀ߺA%]Vy|ǧ"p濄J๩)sFU^uxW ;D'`GWv|if-~xӀ+Qunw~링<"z3q ȁ5Y!|b'4`E(уa@HY:FXHN?7M8HOhQkw+ۇB[H7~TU8-ae8AkȆLoq(;s@uh"y{X}8~Y{sbX8'ȄȈljaxHgF췊DPpԆmg (WhW| 8p хܤBXhΈh,8xa0%2x SDDA{ HnXp䳏f*!-| "3L7qŊg[| n[&׌( ]k,Iwh1c~5y'ғ.wz7dH<G׎NYp8x$i[U> rh-b(:ٕv^cueIgꤖ҇[\r)cxT:v 8D ]|ٖ"0)6٘;9OdL)RhiI &iym9A{ x%w݇ (/ّ }9i Hbɘh3|ɕ)ӹX\8F(9uqssi^ṂYՉzVT9Yi֩9Ij 9ZYMภ  ЉyU Ù{YxBGBWUC/Dggi&i@Zv"0DJxeɝa%ɚM8Mo`)d2KZ;Gckio tI(ʥNzf gJlX ZJhv_{Lo(sRx4^)J2tva_:j!"jHhZ(,p1TerJ*B 9Eh$StƩtê 誀sݷ 8Y^!Bg6ʺ ]霣WtvyLZ8$׮oʡezlY%<ګ 񒭩F&xȪGʯ~+sEaĦiXqX{71u)XF{HF8 ۡ{47"dZLKey"ukLjO2K lKb]Qت4bJvwؙ+ui!x0|5}{8˥:E!ָz_[~g!ƀK*{}D!k@P %k32KAJ\ B'`jPzDzۼ̢ +M[Qk{ 櫷 &b[Sq X7'J;I;"fe A3|#m;٫˺'oAm; uxt ©N Q(*K)N! qA|IܿJ APR[ Q c^Vcz" rZA_r#ڢ.Nk+qG^6A~3ܣA>1ѭ.ۯqX ~SOqKsgO][Ks yf#>~$5(mndnIlNӁ~C3ǜi-qMۿ7p2o| &T ƲW|t'|\ }C~8W| ??€i{A}V6vW,o_ǥ whUN( +py&~} z_֮d_q<~&p S?{,GoO/j_3]{$u !?S \VQ|Oo7\p2__oWlOE&͝3<  ^Oٸmnr? @ DPB >QD-^|Fjс ((H!\RL5m޴N:y@I* $0RM6tgԛ4:(`e-i”VX uyՒ&MX+ǁuDWޙj܈*nM&ң@u>_){VF&hҕM{B8@4bI Ɲ{lkxW|M@2F%`lj\W{&" ?/̽> ,?oF MB٣2 p@g<1Ӫ+1Hi$RBBV!+2J) :2&Ш&pJ/r/b1r/,2Lq%:M;El˻HbHMK?ESP\TUq,3)\V 73lB\㍀2:eVad]hkim6[WU0ԗӶQM/-wW`k7DsUԺٸW|Jp)%a Η~WS/ݐI-}#L? Xc25N. ٧opQD_Ii$po/\#wGww>x'xG>yg{rg|5B<{?|'x'yW?s^H秿~~~_X Ѐ$QVʕdi F *dʹ`r2 4 B9 c3kZPz-k/xdG«Jd5,JaCЇ?b8D"шG\Ђ;:[)'3e xD1]C?Nrd(X?62Q[-9&<4+ s_3+XfsL28Qs/osU|:wVgg?7- Vs|] gМ3O/Yb9 i.ʤVlf[s͝2jBZ`vu}F#ԣ}h'w͂&6S$bg֢^1 pzef1R;8wMDν6ima^_s L\7x˫p #>qW ;mricron-0.20140804.1~dfsg.1.orig/html/tutorial/images/icon.png0000755000175000017500000001243410476415444021732 0ustar mihmihPNG  IHDRQ>9 pHYs  IDATxyp՝?=ni$Ylc,``|`; (C͵!&#V?MU6]YRY6BK }c%ٖukFsF5HoR~}G왮w# f0xGg+UBa,B>5 /%P hC.[pZqEh]T]*e2Z»VFɄNx l@}=m'Rj~a(ą =ӦvË3LPxOeK}1(JzH4Zie_Ŏa<6}}=…3^b ;.okQ}bߢxKF&L<C+i2Jk-mk4vW%q{wipO;OR@@=XucT~Z)s6 iS}UՆծ=SД+|\ kd¬zQ+/ziTGPXg1úTMC+rf,ϛ_#wJyy9`>]Vg^QƵic=>sdx;`, ` inf,+]w?O==z1xdykZ>Yfd#ha<:v|tTE1- c\u{D륡@Fn;ms(O>y~h_\Y*o#$|+ethK]tZQ]-GGLfQ]M @ @S^oPr]zJcxb]qkM7SCj712)([};vF3$eܒ}NC(D(DGmS_OSSX֎#]D>x_qqA>,ZD[SD?O?KoA؛NCkUWh4ȉwTl|hv&hP2?sɮ˹s;GU,[Fmmfvz5uu{lV,*ꦓ |wq_KadP|@RzBcdpRsneS>o@!ݜ8uu|]Bc#5?Zʽ-^[C-Fq♷܎'s5`G3W|u낯X0~Nbd&',Zp)wY>Ç\_@NƢG1kW̦6t%RZY*SW!0 0>Μ 3KUJ n!*ߟp~?nVY}wc9{C2csݗRg@3)x p!I,8gK55̞p c^*dVҾu:ww]sgUj*!ZJ z m8chC mo_Td&>K0R[۷ _Q+-UBhjjq:rvox~ӈNd7C !O< 9*FۺzWo-Fy\8f DctxƩ_{q4` 55xc|*G9 קWW41l; Bu (odް|9MMaur ˧+#tp{%*N }7-_aolM .\ )ō76S鵶\Ni*7ivHXoAf$MLnDQtRٙfi[2R~_][hI#>w /F6ӟL20gE5irp&PlVb"SSi߯Zنg)TFK룡!ti @C5;|XQ1mJZ)eP)](JtsNf c|Fqi˙ 08xkхZB|WKZiR:g9&ULb` ҂m:.\\_R(O`Tɠe2#i4ӟtᬵ2x+/W<OMCk.몪\*XewxO##clf'p?dzNr`` yH*eT츴{͘r )ו f;&6LE}M##D"3 P] ,+5.{{=ufE(>PqotG13+)!qJB@j0f-nW_(6jt5R([#;EHa~Za+e5}ڇ7f~2bFF<6iYX=Xoy'V1鮭DW|}kV$Bp&i[=g~ᗐs<]~.9+i3 0'j\-JkRcښ7UmG-WCozU<@3Z iyHk"8B nb*B #nn1P?K E% A;.dȤԸ5K׍ Лz~&,ЖPR()ppU| H44xT8 ǘӭh`/!bda JgJWQ!\TvL;*u[JR+TjsS'k{+>C{V (xp{K(zؘaPW3S3K:f\)6G()\Q}lM_=- _ 'b,oU8_ A@TR)#RFX$@1]J%]%D IJ%=//t{ݎw7C#/{XNdJxiW|GyFEnғo% }{ Vr=~X?y| )&Q[?O\tL,"Kz  &vzX&xԵ DrF-˅h$q^ )d3Jqa-j#Ӈ>Bo;Bzz gU@;ٷ~`R:4{"VI=6U2\E)qG rnߊ0Kpg"T,A6J#|smJ翊s=K\Hw#ةW3a;cQlluMKkffB5H/,ͿI"y2e`)^)yb?Kġ"RKH%h>T-Ho6qX_m1iO{p qx#>{F#y=|{}4G}3m+kۗq;+L'͡?3IzҎl %  0~ @(&L!mHg@{b_;[ TP?C *醇*gDC)q#!`A$S E48;jE\bw4NV"s6^QP#F1oc:u-ABk, ;fHqTdpHJG|&M͸"qH8Ed/)Lz`(:H!]>0z$%!"/hHFڣ)G  [R}42E'`#J)f@w,&,0h.SH$8iN(I#H7]G7gI7rNf{|~&ʆ4ʪV:+^ kj0*ֲfMJ2jiFS5`kf 0ub_u)-_"vrs cBvtlGTֲ 3L)hvI.X6lیm?pZzFKk]K?V@m&84(O{SuVF\ғ 9S +n29\l z]^`e/ uDhylyUCFoJsK6GU/5[ExZFM0Ka,}0"a~3Vnu Ri[loqL/2(kBr'@ Zvִ"$Uurf,Z9 _f -幄٨XvbJ6i:]l2YT,h2ϹC&~=FYHc듥圼ڰOPnru6G&Ԇe[QZ<~tg9tI y>]ZCt65h(d iZs|@u7jO`̕ ɶvԔNnr7Pjß^#B&\qUr!=K~KŞQjU8!}+XERc`pf>GIi.i|0It<65Wpam ;rE%),Kw7Q>'Э{b3ѥ/8{{NյWcH!B=L?>G~~(7qzՙvedU{pƮ }:"+Ωq 펏yf.;y MRIcron Statistics Page
MRIcron Statistical Analysis Tutorial
  Introduction

Important note: By default, MRIcron has the lesion drawing tools switched off. To turn on the lesion drawing features of MRIcron, select Help/Preferences and make sure the "Show drawing menu and tools" checkbox is selected.

MRIcron is designed to relate lesion location to behavioral performance. For example, it can help identify brain regions that are crucial to language production. To conduct an analysis, we will need to conduct four steps:

  1. Lesion Mapping: For each individual, we need to map the extent of brain injury.
  2. Specify design: We need to design our experiment, creating a spreadsheet that links each individual's lesion map to their performance
  3. Compute results: We need to conduct a voxelwise statistical analysis.
  4. Viewing results: We need to interpret the results.
This tutorial guides you through a lesion data analysis.
  1. A copy of MRIcron: the version will include a folder named 'example\lesions' with the sample dataset described here.
  2. A copy of NPM for Windows
In this tutorial, I assume the lesion maps and design file are in the folder c:\dataset, but you can extract the files anywhere. Note that by default these are usually installed to c:\program files\mricron\example\lesions. The sample dataset includes simulated lesion maps for 23 patients. This folder also includes .val files that report the performance of these patients on a letter cancellation task.  In this task, patients are asked to mark each occurence of the letter 'A' on a piece of paper that was cluttered with letters. A perfect score on this task is 60 (when all the A's are detected). The file continuous.val lists each patient's performance on this task (a score of 2..60), while the file binomial.val lists performance on this task as binary: patients missing more than 4 items are listed as having failed this task (0), while patients who missed 4 or fewer items are listed as having passed this task (1). We have included both binomial and continuous values to illustrate the statistical analyses available with MRIcron.

Right: A sample lesion map (9.voi) overlayed ontop of the ch2 template showing injury to the left temporal lobe. To view this map, launch MRIcron and choose File/Template/Ch2, then choose Overlay/Add... and choose the image 9.voi included with the sample dataset. patient 9 lesion

Lesion Mapping

MRIcron provides simple tools for drawing a region of brain injury. However, it is crucial that all of our lesion maps are drawn with the same image dimensions and orientation. Therefore, we should either draw all the lesions on a standard template (e.g. File/OpenTemplates/CH2), or we need to first normalize all the scans so they are coregistered and then open each scan using File/Open.

  1. Launch MRIcron and open your scan (File/Open or File/OpenTemplate)
  2. Select your drawing tool (these are listed at the bottom of the Draw menu, e.g. the 'Pen' tool).
  3. Draw your region - for example if you use the 'Autoclose Pen' tool, simply click and draw the border of the brain injury. To fill in an enclosed region, simply shift+click in the center of the region. To erase part of your drawing, hold down the Shift key.
  4. Repeat step 3 for all slices where a lesion is present (e.g. you can adjust the X,Y,Z numbers that appear on the top left to select the desired slice. Note you can also use a mouse scroll-wheel to select slices.
  5. When you are done drawing the region of brain injury, choose Draw/SaveVOI to save a copy of the lesion map.
  6. Repeat steps 1-5 for each individual, save the lesion maps from all the individuals in a single folder.

pen tool closed pen tool fill tool circle tool 3D fill tool
Pen Tool Closed Pen Tool Fill Tool Circle Tool 3D Fill Tool
Left click Draw line Draw closed line Fill region Draw ellipse see web page
Shift+ left click Erase line Erase closed line Erase region Erase ellipse
Ctrl+ left click Draw thick line Draw thick closed line 3D Bubble Fill Draw rectangle
Ctrl+shift+ left click Erase thick line Erase thick closed line Erase 3D region Erase rectangle
right click Fill region Fill region Fill region -
Shift+ right click Erase region Erase region Erase region -
Alt+ left click Change view Change view Change view Change view Change view

Specify the Design

Lets famialize ourselves with the dataset we will analyze.
  1. Launch NPM and open the design window (VLSM/Design...). A speadsheet will appear. Select File/Open and view the file continuous.val. Each row shows the performance of each patient, for example the patient 1 identified 2 items, while patient 2 detected 44 items. Note that with this software higher scores reflect better performance. If you have binomial data (where performance falls into two discrete categoris), you should denote the presence of a deficit with a 0 and healthy performance with a one. Note that the filename listed in the left column and the performance in the right column always correspond to the same patient.
    Design
  2. We need to first describe the lesion maps and name the behavioral performance measures. Select View/Design to bring up the description window.
    design 
    1. Predictors: shows the number of behavioral measures - here we are only examining the letter cancelation performance..
    2. Predictor names: for each predictor, insert an easy to remember name, e.g. 'cancel' for our letter finding task.
    3. You can select the file names of your lesion maps by pressing the 'Select Images' button to select the lesion maps from all your participants. You should select all the images simultaneously, and all the images should be placed in a single folder (e.g. your lesion maps might be C:\dataset\1.voi, C:\dataset\2.voi, etc). The lesion images can be in MRIcron VOI, NIfTI .nii, compressed NIfTI .nii.gz or Analyze (.hdr/.img) format. If you do select images, make sure the filenames match the patient performance, as noted in step 1. 
    4. You can also set an a priori minimum lesion density threshold. For example, setting a value of 10% when you analyze 22 people means that statistics will only be computed for voxels damaged in more than 2 people. A large number for this threshold can increase your statistical power, as you will only compute statistics for voxels that are commonly injured. However, larger values will fail to detect rarely damaged regions that are reliable predictors of deficit. Note that this value is based on the total incidence of lesions in a voxel, regardless of behavioral performance.

Compute results

Next, we we compute our statistical results. You can conduct some statistics by choosing items in the Draw/Statistics menu of MRIcron. However, here we describe using some of the new features in NPM that are not yet available in MRIcron - specifically, NPM can conduct permutation thresholding and the Brunner and Munzel test. To conduct these statistics, you need to download and install npm.exe - this only works on the Windows operating system.

  1. First go to the 'Options' menu and set the permutations to None. Permutation thresholding can be useful, but it will take at least 1000 times longer than a normal False-Discovery Rate corrected threshold, and is typically less sensitive. Therfore, for you first glance at your data, turn this feature off.
  2. For analyzing the continuous data:
    1. Go to 'Option' menu and click 'Tests' - make sure the 'Brunner Munzel' is checked and the t-test is unchecked. Our data is not normally distributed, so we will use a non-parametric test (using the permuted Brunner Munzel rank order statistic).
    2. Click the VLSM/BinaryImagesContinuousGroups command. Select the continuous.val file.
  3. For analyzing the binomial data:
    1. Click the VLSM/BinaryImagesBinaryGroups command. Select the binomial.val file. This will use the Liebermeister measure (a more sensitive binomial test than Chi-Squared or Fisher's Exact test, see Seneta and Phipps, 2001; Phipps, 2003).
      Comparison
  4. NPM will now compute the requested tests. It will create overlap images of all your patients (e.g. sum.nii.gz) and a statistical map (BM.nii.gz for continuous data, L.nii.gz for binomial data).
    NPM

Viewing results

We can open up the statistical maps generated and place them on top of an anatomical scan. If your lesion maps were aligned to stereotaxic MNI space, you can open them on top of one of the standard templates (File/OpenTemplates/ch2). Here is a quick guide:

  1. Launch MRIcron and choose File/OpenTemplates/ch2bet as our background image
  2. Choose Overlay/Add and choose the statistical map created in the previous step (e.g. C:\dataset\binL.nii.gz).
  3. When MRIcron detects a statistical map, it calculates the p-values for each test in order to determine the false discover rate (FDR) threshold - e.g. how much robust signal is present in your data. MRIcron displays a histogram of the Z-scores. Note in the example below, most of the data has positive Z scores suggesting a robust signal (if our data was merely noise, we should see a bell-shaped distribution with a mean of 0, instead the mean Z score is around 2).
    Histogram
  4. Next, MRIcron displays the overlay. Note at the bottom of the screen the software reports the critical values: the p05/p01 values correspond to uncorrected p<0.05 and p<0.01 values that are very liberal (these tests will make many false alarms, e.g. here we have conducted 16082 tests, so p05 should result in many false positives). The fwe05 and fwe01 values correspond to the Bonferroni-corrected values: this test is very conservative, and you will often fail to detect real effects. The FDR05 and FDR01 results reflect the False Discover Rate - e.g. a FDR05 should show around 20 real activations for every false positive. Note that when there is very little or no signal, FDR is as conservative as Bonferroni, but it is adaptive to the actual signal in your dataset. Note that you can select the image thresholding and cutoff for your overlay. Note that by default, my software loads statistical maps with thresholds from FDR05 to FDR01, unless there is insufficient signal, in which case it uses the uncorrected 0.05...0.01 values. Also note that the current overlay is set to appear in a monochromatic red color scheme.
    lesion stats
    The image below shows how changing a threshold can change the appearance of a statistical overlay. Consider the raw statitical map shown in the left panel, while the middle panel has been thresholded to only show voxels with Z-scores greater than 2.5 (with three regions surviving this threshold), the right panel shows a more conservative threshold of Z>4.5 - with only a single peak surviving.
    Thresholding
  5. We can repeat steps 2..4 to load multiple overlays, to compare different statistical tests. For example, clicking on the 'tutorialfmri.bat' icon will launch MRIcron and load to overlapping regions of interest. By using the Overlay/TransparencyOnOtherOverlays command we can view both of these overlays simultaneously.
logo
mricron-0.20140804.1~dfsg.1.orig/html/main.html0000755000175000017500000002373310600577644017002 0ustar mihmih MRIcron Introduction Page
MRIcron Introduction

Main Window

I have tried to make the MRIcron main window as useful but simple as possible. While the options may appear confusing at first, I hope over time the software feels intuitive. A sample window is shown below. You can get a similar view by launching the software, choosing File/OpenTemplates/ch2bet to load the background image (shown as a grayscale brain) and then choosing Overlay/Add and opening the image \Template\attention.

the controls on the tool bar offer quick access to the main tools for brain imaging. The X/Y/Z numbers set the slice to view (X refers to Left/Right, Y to anterior/posterior and Z to superior/inferior). Adjusting these values will change the sagittal, coronal and axial slice displayed. The next item is the zoom-factor. Here images are scaled 'to fit' - e.g. each view of the brain is strecthed to fill its panel optimally. Alternatively, you could choose x1 (100%), x2 (200%) or x3 (300%) zoom factors. The next series of buttons refer to the active layer (more on layers in the next section). In the example below, the currently active layer is image 'attention', and this image is being shown as a red gradient with a minimum value of 1.96 to 4. In this example, attention is a statistical Z-score map that has been placed on top of the background image of a brain. Statistical values less than 1.96 are not shown, with the darkest value set to 4.

main mricron view
This image shows a sample rendering. You can view a similar image by running the fmri.bat file that is included with MRIcron. 

Layers

When you use the File menu's Open command (Open, Open recent and Open Templates) you are selecting a background image. What makes MRIcron powerful is its ability to load multiple layers of images. To add additional images on top of your background, simply choose 'Add' from the 'Overlay' menu. For example, launch MRIcron and choose 'File\Open templates\ch2bet', then choose 'Overlay/Add' and select the 'attention.nii.gz' image from the 'Example' folder that (typically, this folder is installed in C:\program files\mricron\examples). Now you should see a brain activation statistical map on top of the background anatomical image. Note that overlay images are scaled to map on top of the background image. You can adjust the appearance of each layer by using the layer panel:

overlay panel

Note that you can click on the leftmost button in the overlay panel to select between the open layers - for example the image above shows settings for the 'Background' image, as well as the overlay image named 'saccades'. Note that the image intensity range for the background is from 45 to 120, using a grayscale color scheme. This means that values of 45 or lower will appear as complete black, and 120 and above will be white, with intermediate intensities appearing as a corresponding gray value. There is also an icon with a color scale and the number zero: this allows you to have the color range set from zero, even if your threshold is greater than zero: for example our statistical map 'saccades' is set to show values from 2.3 to 6: values less than 2.3 will not be shown. However, since the 'color range from zero' button is depressed, a T-score of 2.3 will appear as a dark red (as 2.3 is part way between 0 and 6) instead of a black (if the color range was from 2.3 to 6).

MRIcron allows you to choose different color schemes for each layer. In the example above, the Background image is shown using the 'grayscale' black-and-white colorscheme, while the saccade overlay uses the Red color scheme. You can increase or decrease the colorschemes available by adding or removing files from the 'LUT' folder (this 'look up table' folder is located in the same path as MRIcron). This folder typically contains several *.lut files, with each file storing a different color scheme. For example, the blackbdy.lut' file describes a color scheme that goes from black to orange to yellow and finally white. MRIcron's *.lut files are interchangeable with the *.lut files used by ImageJ, XMedCon, MRIcro. You can copy *.lut files from these programs to MRIcron's LUT folder. Furthermore, you can create your own *.LUT files using ImageJ's LUT panel plugin, ImageJ's LUT Editor or my own LUTmaker.

Note that the 'Overlay' menu also allows you to modify how layers appear. For example, on image 'A' below, I have selected Overlay/TransparencyOnBackground/0%[Opaque], while for image B, I have set the transparency to 50%. Also note that you can load multiple overlays simultaneously. For example, images C and D below show the 'attention'  and  'saccades' files both overlayed on top of ch2bet - with attention shown in green and the saccades shown as red. For image C, I have set the Overlay/TransparencyOnOtherOverlays/50%, while for Figure D this has been set to 'Additive' (so regions with both red and green appear yellow).

Transparency

Render Window

From MRIcron's main window you can select Window/Render to view a volume rendering of your data. You can change the vieiwing angle of the image by adjusting the Aizmuth and Elevation values. The Background menu allows you to adjust therendering of the background image, while the background menu allows you to determine how overlays will appear. Of critical importance, the Overlay/SearchDepth will adjust whether the rendering shows superficial overlays (e.g. a settings of 4 will only look within the first 4 voxels of the background image [e.g. within the first 4mm if your background image hasa 1mm resoultion), while a setting of 'infinite' will show an overlay regardless of its depth. Also criticial is the Background/BehindOverlay menu item - if checked, the software will only start looking for overlays that exist behind the surface of the background. On the other hand, if this value, overlays will not be constrained by the background image (e.g. you will be able to view an overlay that is closer than the background). You can save your preferred settings by selecting File/SaveSettings. This information will be saved in the 'render' folder, and you will be able to select them by choosing File/OpenSettings.


example fmri
This image shows a sample rendering. You can view this image by running the fmri.bat file that is included with MRIcron. 

Multislice Window

From MRIcron's main window you can select Window/Multislice to see the multislice window. You will then be shown a series of slices of the currently open volumes. Within the Multislice form you can use the View meanu to adjust settings - e.g. to select whether you want to see sagittal, coronal or axial images, and to choose the desired slices and overlap between neighboring slices. You can also choose File/SaveSettings to save your favorite views (previous sets will be listed under File/OpenSettings).

This image shows a sample multslice image. You can view this image by running the fmri.bat file that is included with MRIcron. After MRIcron loads, choose Window/Multislice. Note you can adjust the amount of overlap between slices, as well as slice orientation. Forthermore, you can choose which slices to display.
multislice

logo

 

mricron-0.20140804.1~dfsg.1.orig/html/dcm2nii.html0000755000175000017500000007776311317112622017402 0ustar mihmih dcm2nii DICOM to NIfTI image conversion
dcm2nii DICOM to NIfTI conversion
  Introduction

Important note: dcm2nii is still beta software - please carefully monitor the output from this software. In particular, be aware of potential left-right flipping. This has only been tested with Philips Intera DICOM, Siemens Trio DICOM and Philips Intera PAR/REC images. This software is provided under the BSD license.

DCM2NII attempts to convert images from the proprietary scanner format to the NIfTI format used by FSL, SPM5, MRIcron and many other brain imaging tools. NIfTI is a modern incarnation of the Analyze format, but includes important information like the orientation of the image. DCM2NII is a stand-alone program that is distributed with MRIcron. It is natively compiled for Windows, Linux x86, Mac OSX PPC and Mac OSX x86.


The NIfTI image format standard was designed for scientific analysis of brain images. The format is simple, compact and versatile. The images can be stored as a pair of files (hdr/img, compliant with most Analyze format viewers), or a single file (nii). Programs like FSL and MRIcron can also read compressed (nii.gz) images. One nice feature about NIfTI is that the format attempts to keep spatial orientation information. Therefore, NIfTI software that can read the spatial information (MRIcron and SPM5) should reduce your chance of making left-right errors. Also, software like SPM5 will tend to be more accurate at coregistering images, as all the images from an individual can use the scanner position as a beginning estimate for alignment. For example, here are two scans from the same individual (the sagittal T1 is shown in grayscale, and the coronal FLAIR is shown in reds). Note that the scans were acquired with different orientations (with the FLAIR along the axis of the hippocampus), however MRIcron shows the image orientation correctly. NIfTI image transform

Installation

  1. Follow the instructions to install MRIcron on your hard disk - this should create a program named dcm2nii.exe (Windows) or dcm2nii (Unix).
  2. Double click on dcm2nii.exe - a file named dcm2nii.ini will be created. If you are using Windows, this file is in the same folder as dcm2nii. If you are using Unix (Linux, OSX) then this file is created in your home directory.
  3. Open dcm2nii.ini with a text editor (double click on the file). You will be able to adjust the settings:
    Text Description
    [BOOL]
    AnonymizeSourceDICOM=0 If '=1' then dcm2nii will create anonymized copies of DICOM images (remove name, DOB, patient ID, sex). No other conversion will occur.
    ManualNIfTIConv=1 If '=1' then dcm2nii will prompt user to describe output subformat for every NIfTI image dragged onto the program. Otherwise, subformat will be based on $D, SingleNIIFile,SPM2 settings.
    4D=1 If '=1' then dcm2nii will generate 4D files (FSL style), otherwise output will be 3D (SPM style).
    Anonymize=1 If '=1' then patient name will not be copied to NIfTI header.
    SingleNIIFile=1 If '=1' then dcm2nii will create .nii files (FSL style), otherwise .hdr/.img pairs will be created (SPM style)
    Gzip=0 If '=1' then dcm2nii will create compressed .nii.gz files (FSL style).
    SPM2=0 If '=1' then dcm2nii will create Analyze images (SPM2 style), otherwise headers will be in NIfTI (SPM5/FSL).
    AppendDate=1 If '=1' then output filename will include date of study.
    AppendAcqSeries=1 If '=1' then output filename will include acquisition number.
    AppendProtocolName=1 If '=1' then output filename will include protocol name.
    AppendPatientName=0 If '=1' then output filename will include patient name.
    AppendFilename=0 If '=1' then output filename will include source filename.
    EveryFile=1 If '=1' then all .par/.rec files in the source folder will be converted, otherwise only the file specified will be converted
    [INT]
    BeginClip=0 Specifies number of volumes to be removed from the beginning of a 4D acquisition (e.g. avoid T1 effects)
    LastClip=0 Specifies number of volumes to be removed from the end of a 4D acquisition (e.g. fMRI scanning continued after behavioral paradigm ended).
    MinReorientMatrix=255 Images with a larger matrix size than this value will be reoriented to canonical space (see below).


  4. With each option listed under the heading [BOOL], add a '1' for yes and a '0' for no. For example, if you want to have images saved as .hdr/.img pairs, set SingleNIIFile to 0. If you want to save images a single .nii files, set this to 1. The append options adjust the output filenames. For example, if you had both AppendDate and AppendProtocolName set to 1, the converted images would have names such as 20060331_123456anat1x1x1.nii if the data session was acquired on 31 March 2006 at 12:34:56 and the protocol was called 'anat1x1x1'. The last two values (listed under the heading [INT]) except integer values - for example if you set 'LastClip=8' then the last 8 volumes of every 4-dimensional dataset will not be saved (e.g. if you had an fMRI dataset with 120 volumes, only the first 111 volumes would be converted). A fuller description of these options is in the gray box below.

Running DCM2NII

There are two ways to run dcm2nii

  1. You can either drag and drop files onto the program - this will convert the images using the values in your dcm2nii.ini file (see above).
  2. You can launch dcm2nii from the command line, specifying specifically the options to use.

To use dcm2nii by dragging and dropping:

  1. Place all the DICOM (or Philips PAR/REC) images you wish to convert into a folder where you have write access.
  2. Drag and drop one of the images onto dcm2nii. 
  3. You can now vew the images with MRIcron, SPM5, FSL, or other Analyze/NIfTI viewers.
To see your options for running dcm2nii from the command line, simply execute the program without specifying any files (e.g. just double click on the program to launch it). The available options will the be written to the screen:
dcm2nii 12 May 2007 by Chris Rorden
Either drag and drop or specify command line options:
dcm2nii
OPTIONS:
 -a Anonymize [remove identifying information]: Y,N
   default: Y
 -b Clip beginning volumes from 4D file: 0..1000
   default: 0
 -d Date in filename [filename.dcm -> 20061230122032.nii]: Y,N
   default: N
 -e events (series/acq) in filename [filename.dcm -> s002a003.nii]: Y,N
   default: Y
 -f Source filename [e.g. filename.par -> filename.nii]: Y,N
   default: N
 -g gzip output, filename.nii.gz [ignored if '-n n']: Y,N
   default: Y
 -i ID in filename [filename.dcm -> johndoe.nii]: Y,N
   default: N
 -l Clip last volumes from 4D file: 0..1000
   default: 0
 -n output .nii file [if no, create .hdr/.img pair]: Y,N
   default: Y
 -o Output Directory, e.g. 'C:\TEMP'
   default: source directory
 -p Protocol in filename [filename.dcm -> TFE_T1.nii]: Y,N
   default: Y
 -s SPM2/Analyze not SPM5/NIfTI [ignored if '-n y']: Y,N
   default: N
 -v Convert every PAR file in the directory: Y,N
   default: Y
HINTS
  the combination '-d n -p n -i n -e n' will be ignored.
  You can also set defaults by editing C:\lazarus\mricron\dcm2nii\dcm2nii.ini
EXAMPLE: dcm2nii -a y -o C:\TEMP C:\DICOM\input1.par C:\input2.par


Reorienting to canonical space

The NIfTI format stores spatial transforms so that software can determine the oreintation of the image. This means that MRIcron can display the image with an intuitive orientation. However, many programs ignore these transforms, and display the images as they are saved to disk (e.g. FSLview, MRIcro) - this means that a sagittally acquired scan appears very differently from an axially acquired scan. In fact, the three spatial dimensions (left-right, anterior-posterior, superior-inferior) can be saved in 48 different orthogonal orientations. The drawing below shows just three of these possible orientations. Orthogonal orientations
You can set dcm2nii to reorient all images so they are all aligned to the nearest orthogonal direction to 'canonical space' (i.e. as close as possible to the rotation matrix [1 0 0; 0 1 0; 0 0 1]). This means programs like FSLview and MRIcro will display the images in a sensible orientation, regardless of the acquisition. The NIfTI transform codes the residual oblique orientations, so no information is lost in this tranformation. However, you will only want to orient anatomical scans to canonical space - reorienting fMRI data can disrupt slice timing correction (as the software assumes that the slice order of the stored data is correlated with the time of acquisition). Reorienting can also disrupt analysis of the DTI data (as the diffusion directions are not adjusted for the change in image orientation). Therefore, the "MinReorientMatrix" allows you to adjust which images will be reoriented - a value of 255 ensures that T1/T2 scans (typically with a 256x256 matrix) are reoriented, while fMRI (~64x64) and DTI (~128x128) scans are not. If you do not want any scans reoriented, reset this to a very large value (e.g. 5000).

After reorienting, dcm2nii will attempt to 'autocrop' T1-weighted anatomical images (images with a Echo Time [TE] of less than 20ms). A new copy of the image is created with the prefix 'c' that attempts to remove excess air surrounding the individual as well as parts of the neck below the cerebellum. This excess neck can disrupt normalization of images (as the template images do not have similar neck regions). This new image has a slightly different NIfTI transform - the origin is adjusted to compensate for the removed portions of the image. The image below shows a T1-weighted scan before and after cropping.
Orthogonal orientations
As a final note, reorienting images is useful if you want to create masks for an image to use with SPM or FSL. These programs require that the mask image has precisely the same dimensions as the image it is designed to mask. In these cases, you can not apply the precise spatial transforms to an image (as the oblique orientation corrections means that the resulting drawing will have different dimensions than the original image. Therefore, you will want to draw a mask on on a image that has not used the fine spatial transforms. You can use MRIcro or FSLview to do this (as they ignore these transforms). If yu use MRIcron, select Help/Preferences and uncheck the 'Reorient (reslice) images when loading' option - this will ensure that the raw image is loaded. Regardless of which software you use, having a canonically aligned image will mean that the image will be displayed in a sensible manner.

Diffusion data

Diffusion sequences are sensitive to the random spontaneous motion of water molecules. This movement is anisotropic in fiber bundles - in other words it preferentially moves up and down the fibers whereas motion across the fiber is constrained. Diffusion tensor imaging (DTI) use different gradient directions so that different images are sensitive to specific directions. In order to process this data with medINRIA or FSL, you need to extract the diffusion direction information as well as the images. For these images, dcm2niigui will attempt to generate .bvec and .bval text files. This information is extracted from the DICOM header (for Siemens data the software attempts to read the "B_value" and "DiffusionGradientDirection" fields from the CSA header).

NIfTI Sub-Formats

SPM5 and FSL both support NIfTI format images. However, by default these programs assume your data is in slightly different formats. Most SPM5 users generate a single 3D volume for each timepoint, and each image is saved as both a .hdr and .img file (separating the header information from the raw image data). On the other hand, by default FSL uses a single 4D dataset, with all the data stored in a single .nii file (this single file contains both the header and raw image data). To save disk space, FSL saved these files as compressed gzipped files (.nii.gz). Therefore, you may want to convert your DICOM data to a different NIfTI sub-format depending on how you want to process and analyze your data. You should adjust dcm2nii's settings depending on which software you will use for post-processing. Here are some general guidelines:
  1. FSL/MRIcron: compressed NIfTI (.nii.gz) - SingleNIIFile=1; Gzip=1; SPM2=0
  2. Recent software (SPM5/Voxbo/FSL/MRIcron): NIfTI (.nii) - SingleNIIFile=1; Gzip=0; SPM2=0
  3. Legacy software (SPM2/Analyze/MRIcro): analyze (.hdr/.img) - SingleNIIFile=0; Gzip=0; SPM2=1

Converting between NIfTI Sub-Formats

FSL includes the avwsplit and avwmerge tools for converting between 3D and 4D NIfTI images. This is useful, as FSL likes 4D images while SPM likes 3D images. The latest versions of dcm2nii (since May 2007) can also help you convert between NIfTI subformats. Specifically, if you drag and drop a NIfTI image (.nii, .nii.gz, or .hdr/.img subformats) onto dcm2nii it will ask how you want the data converted. You can convert these files to SPM2 (analyze 3D hdr/img), SPM5 (3D hdr/img), 3D nii, 4D nii, and FSL (NIfTI 4D nii.gz). If ManualNIfTIConv=1 then the user will be prompted for every file to specify the output format, while if this value is ManualNIfTIConv=0 then the files will be converted automatically using the sub-formant specified in the dcm2nii.ini file. Note that this software will both change subformat and/or convert 4D files to 3D files. However, it does not convert 3D files to 4D files (use avwmerge for this).

Anonymizing DICOM images

This software can also 'anonymize' DICOM data - protecting the participants private information. There are a number of free as well as professional programs that can help anonymize DICOM data. My favorite is the free uniPACS viewer can strip all the private tags from a DICOM file (choose File/BatchFileExport and select 'Anonymize' from the file menu). However, it is worth mentioning that some DICOM images store important data in the 'private' tags - for example, Siemens data includes information about the number of slices in a mosaic as well as DICOM diffusion directions. Therefore, use these 'strong' anonymizers with caution. In contrast, dcm2nii provides a 'weak' anonymization: it only anonymizes the patients name (0010:0010), ID (0010:0020), date of birth (0010:0030), sex (0010:0040), age (0010:1010) and weight (0010:1030). The name is replaced with the number of seconds that elapsed between the study time and January 1, 2000 (ensuring that data from different individuals will not be confused). In theory, the participant can still be identified by study time (if you know when people received scans), and some manufacturers may store personal information in other parts of the DICOM file. To use dcm2nii's DICOM anonymizer, simply edit the dcm2nii file to read "AnonymizeSourceDICOM=1". Then just drag and drop DICOM files on the program - an anonymized file will be created (with the same name as the original image, but with the extension '.dcm' appended at the end). Note that in this mode the software will not convert the DICOM files to the NIfTI format. You may want to keep two copies of dcm2nii with different filenames (and hence different .ini files) - for example you could call one 'dcmanon' and another 'dcm2nii' so that one copy generates anonymized files and the other converts files.

dcm2niiGUI

I find dcm2nii very easy to use - just drop the images that you wish to convert onto the program's icon. However, some people prefer programs with a graphical user interface. The Windows distribution of MRIcron includes my dcm2niigui program - which is simply a version of dcm2nii with a graphical interface. Just launch the program, then drag and drop the images you wish to convert. The 'Output format' pulldown menu determines whether the images will be saved in SPM or FSL style NIfTI format. You can also choose help/preferences to more advanced options. In addition, you can use the File/AnonymizeDICOM command to strip personal details from DICOM images. Finally, you can use the File/ModifyNIfTI command to change existing NIfTI images - this command guides you through selecting the images and then choosing how you want to modify the images (remove volumes, changing subformat, reorienting, or changing the order of the 3rd and fourth dimension).
dcm2niigui

Performance

Converting DICOM images is fast compared to the other processing stages common to neuroimaging. However, several people have asked me how to improve dcm2nii's performance. I have tried to design this software to be quick - it attempts to minimize the amount of time writing to disk (by using a large amount of RAM). The table below shows the time required to process a standard neuroimaging dataset (1060 DICOM images [325Mb] with 792 fMRI volumes [36 slices, saved as mosaics], one T1 weighted anatomical scan and a field map). This dataset is typical for a one hour scanning session. The table below shows the time (in seconds) for dcm2nii (and SPM5) to convert these images. The 'GZ' cells reflect times for creating FSL style compressed .nii.gz images, while the other cells report times for creating SPM5 style .hdr/.img pairs. In brief, creating uncompressed images is generally constrained by disk speeds, while creating compressed images is limited by your processing power.
Setup eSata Internal HD USB HD GZ eSata GZ Internal HD GZ USB HD
dcm2nii 2166Mhz CoreDuo Laptop 12
20 41 70 70 73
SPM5 2166Mhz CoreDuo Laptop 94 138 165 - - -
dcm2nii 667Mhz G4 Laptop - 41 - - 229 -

Sample Datasets

Here are some sample images that help show whether images are converted with the correct image orientation:
  1. GE DICOM dataset. Twelve 4D EPI series, each with five volumes: s26692 axial ascending sequentia, s26693: axial ascending interleaved, s26694: axial descending sequentia, s26695: axial descending interleaved, s26696: sagittal right to left sequential, s26697: sagittal right to left interleaved, s26698: sagittal left to right sequential, s26699 sagittal left to right interleaved, s26700: coronal P to A sequential, s26701: coronal P to A interleaved, s26702: coronal A to P sequential, s26703: EPI, coronal A to P interleaved. A water filled fiduical marker is placed over the right temple of the participant. Data were acquired on a GE-SignaHD-Excite scanner at 3 Tesla using an 8 Channel Brain Array Coil. The first volume of each series has been marked with a '1' on the image. (LMU Grosshadern)
  2. Philips DICOM dataset. Six 4D EPI volumes, each with two volumes: sagittal, coronal and axial each with both 'ascending' and 'descending' slice order. The white line added at the bottom should be shorter on the earlier volumes. (MUSC Center for Advanced Imaging Research)
  3. Philips PAR/REC dataset. Five 4D EPI volumes - same raw data as Philips DICOM dataset, but only a single axial volume is included.(MUSC Center for Advanced Imaging Research)
  4. Siemens Trio B12 DICOM dataset. Six 4D EPI volumes, each with two volumes: sagittal, coronal and axial each with both 'ascending' and 'descending' slice order. A saline bag is placed near the participant's left temple. (USC McCausland Center)
  5. Siemens Trio B13 DICOM DTI dataset. From May-2007, dcm2nii attempts to generate FSL and medINRIA compatible descriptions of the B-values (bval) and Diffusion Gradient Directions (bvec). For instructions on using FSL and medINRIA, see my DTI page. These sample images were simply designed to validate dcm2nii's conversion: these protocols are not appropriate for any other use (our standard protocol is described here). This large (33Mb) file includes four 20 direction EPI datasets: the first two are true axial (aligned to scanner bore, not the participant's head) and are identical except that the phase direction is Anterior-Posterior in the first and Right-Left in second. The third volume is identical to the second except that the imaging plane has been rotated: a pitch and yaw have been applied. The final scan is a coronal scan,also taken in plane with the scanner's bore with pahse encoding in the right-left direction. The file also includes a matlab function (dtivecs.m) that illustrates dcm2nii's calculation for correcting the diffusion directions for the imaging plane, using suggestions from dicom2ana (see below) and Paul Morgan. (USC McCausland Center)

Alternatives

Each manufacturer has interpretted the DICOM data standard a bit differently. Therefore, you may want to test several programs to see which one is best suited for your data
  1. LONI Debabeler is a Java applet that can run on just about any computer. It can also read a number of medical imaging formats. Another nice feature is that it reorients the raw data to be approximately aligned with the nearest orthogonal orientation (i.e. coronal and sagittal scans are resliced along the axial plane).
  2. SPM5 includes a DICOM to NIfTI covnerter that works particularly well for Siemens data (requires Matlab).
  3. dicom2nifti is a matlab script for converting DICOM to NIfTI (requires Matlab and the Matlab Image Processing Toolbox). [an alternative version is described here.]
  4. xmedcon offers limited NIfTI writing support for many image formats. It uses the niftilib tools, which look very useful.
  5. MRIconvert is a popular converter for Windows and Linux.
  6. dinifti looks useful.
  7. Here is a script that uses dicom2 and FSL to convert DICOM images to NIfTI.
  8. XMedCon includes the ability to convert between Acr/Nema 2.0, Analyze (SPM), Concorde/µPET, DICOM 3.0, CTI ECAT 6/7, NIfTI-1, InterFile3.3 and PNG or Gif87a/89a formats, as well as an elegant image viewer.
logo
mricron-0.20140804.1~dfsg.1.orig/html/source.html0000755000175000017500000000564510533450132017343 0ustar mihmih MRIcron Source Code Page
MRIcron source code

Introduction

MRIcron is written in Pascal, and can be compiled using Borland's Delphi or the open source Lazarus (Freepascal) software. MRIcron is open source, using the BSD license. Lazarus offers several advantages - it is free, comes complete with all the components required by MRIcron, and offers the potential to easily create native binary code for Windows, Linux, and OSX. However, Lazarus is still beta software. 

  1. Install the compiler. To compile this software, you will need a build of Lazarus created on or after May 1, 2006. This software requires some recent patches that are not available on the current stable release. To get the latest developmental snapshot of Lazarus, click here. There are still a few features that do not work correctly on the Lazarus versions of MRIcron. These are described here.
  2. Get the source code. The source code is available here. The source file includes sample images in the Templates and Example folders. To test this software, compile mricron.lpr. Next use the File/templates menu to open sample images. Alternatively, after compiling the software, you can click on the included .bat files to see sample renderings.
  3. The Lazarus version of this software still has a few bugs. For more details, click here.
logo   Lazarus
mricron-0.20140804.1~dfsg.1.orig/html/install.html0000755000175000017500000003361210613732344017513 0ustar mihmih MRIcron Installation Page
MRIcron Installation

Introduction

MRIcron can run on Windows, Macintosh OSX and Linux computers. Because Macintosh and Linux builds require a beta-release compiler, installation on these operating systems may be somewhat tricky. This software is covered under a variation of the BSD license. In theory, this software should work well on any of these platforms with recent hardware. However, currently Windows offers the optimal platform for four reasons:
  • Graphics are more fluid in the Windows version: uses direct Windows API routines.
  • Rendering is faster with the Windows version if you are using a multi-CPU system: Windows version multi-threads rendering, so rendering is twice as fast on a dual-core system.
  • Windows version recognizes tablets, making it easier to draw volumes of interest (as it can detect stylus pressure, and can detect whether you are using the stylus tip or eraser).
  • Windows version is the most popular, so it has received the most testing from users.
Hopefully, MRIcron should offer reasonable performance on any modern machine. There are a few ways to increase the performance of MRIcron, though these techniques necessarily reduce the quality of the images.
  • In the main MRIcron window, make sure that the option '2D smooth all' in the 'View' menu is unchecked. This displays images with the rapid nearest-neighbor interpolation instead of the much slower bilinear interpolation.
  • In the rendering window, make sure that the option 'Precise interpolation' in the 'View' menu is unchecked. This generates 3D renderings using nearest-neighbor interpolation instead of the slower trilinear interpolation. Renderings are typically three times faster.
  • In the rendering window, you may want to turn off the 'Smooth background' option in the 'View' menu. This displays the raw rendering, instead of applying a 2D blur to the image. Note that this change has much less influence on rendering times than the 'precise interpolation' option (as the precise interpolation is done in all 3 dimensions, while the smooth is only computed in 2 dimensions).
License
Chris Rorden's MRIcron, copyright 2007, all rights reserved.

Redistribution and use in binary forms, with or without modification, are permitted provided inclusion of the copyright notice, this list of conditions and the following disclaimer is provided with the distribution. Neither the name of the copyright owner nor the name of this project (MRIcron) may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "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 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.

Windows

  1. Download the installer.
  2. Unzip and run the installer (double click on the .zip file and run the program InstallMR.exe).
  3. By default, the installer places the programs in C:\program files\mricron, simply double click on mricron.exe to run the software.
  4. You may also double-click on the .bat files, which load example images, for example 'examplefmri.bat' shows two statistical maps on top of a high resolution anatomical scan.
  5. Note: The file dcm2nii.exe is compressed using UPX, which can lead some virus software to generate false alarms (AntiVir PE Premium). This software is generated on a computer that always has the latest update's for Trend Micro's OfficeScan virus detection software.

Linux x86 32bit If anyone finds an easier way to distribute this software for Linux, please contact me. I am still finding it tricky to develop a universal protocol for dealing with the dependencies of different distributions.
 NoteThe Linux-native version of MRIcron was created using a beta release compiler. In many cases the best solution is to run the Windows-native version of MRIcron using Wine or a virtualized Windows environment (e.g. VMware player, QEMU or Xen).

  1. Download the software.
  2. Unzip the software (for modern Linux systems, right click on the file mricronlx.zip and choose to 'extract here').
  3. Open a terminal window.
  4. Change to the folder where you installed mricron, e.g. cd ~/mricron
  5. Launch mricron by typing ./mricron (note you must be in the same folder as the mricron executable.
  6. You can also run the example .bat files, for example ./xfmri.bat shows two statistical maps on top of a high resolution anatomical scan.
    1. In case you receive error messages, check if all the dependencies of the program are installed. In particular, you need
      1. GTK 1.2 (this is called GTK+ by some distributions, and gtk by others)
      2. libgdk_lixbuf2.0
    2. You can see a complete list of .so files needed by the software using the command:
        ldd ./mricron
    3. In case you cannot run the program and it displays a message saying it cannot find one of these libraries (you must run the program from the command line to see error messages), you need to download and install a package for the necessary library:
        • On RPM-based distributions you can find packages here: http://rpm.pbone.net/
        • On Debian-based distributions you can find packages here: http://www.debian.org/distrib/packages

Macintosh PowerPC
 NoteThe Macintosh:PPC -native version of MRIcron was created using a beta release compiler. In many cases the best solution is to run the Windows-native version of MRIcron using VirtualPC.

  1. Download the software.
  2. Unzip the software (double click on the .zip file - a new folder called mricron will be created).
  3. You will need to install X11. 
    1. Check to see if X11 is in the applications\utilities folder.
    2. If X11 is not installed:
      1. OSX 10.4 user can install X11 by using the DVD installer disk
      2. Alternatively, download and run the X11 installer distributed by Apple.
  4. Download and install the correct version of fink for your version of OS X and let it download and install the additional 29 GTK and related packages needed. Here's the required command for my software (all on one line): 
    • sudo fink install gdk-pixbuf gtk+ gtk+-data gtk+-shlibs gtk-doc-1.2-13 gtkglarea gtk-engines
  5. Launch X11 (double click on the X11 icon in the applications\utilitiesfolder). 
  6. Launch an X11 terminal  (from the keyboard, type Apple-N). From the terminal you can do the following
    1. Change to the folder where you installed mricron, e.g. cd ~/Documents/mricron
    2. Launch mricron by typing ./mricron (note you must be in the same folder as the mricron executable.
    3. You can also run the example .bat files, for example ./xfmri.bat shows two statistical maps on top of a high resolution anatomical scan.

Macintosh Intel
 NoteThe Macintosh:Intel -native version of MRIcron was created using a beta release compiler. In many cases the best solution is to run the Windows-native version of MRIcron using VMware Fusion or Parallels Desktop for Mac. .

  1. Download the software.
  2. Unzip the software (double click on the .zip file - a new folder called mricron will be created).
  3. You will need to install X11. 
    1. Check to see if X11 is in the applications\utilities folder.
    2. If X11 is not installed:
      1. OSX 10.4 user can install X11 by using the DVD installer disk
      2. Alternatively, download and run the X11 installer distributed by Apple.
  4. Download and install the correct version of fink for your version of OS X and let it download and install the additional 29 GTK and related packages needed. Here's the required command for my software (all on one line): 
    • sudo fink install gdk-pixbuf gtk+ gtk+-data gtk+-shlibs gtk-doc-1.2-13 gtkglarea gtk-engines
  5. Launch X11 (double click on the X11 icon in the applications\utilitiesfolder). 
  6. Launch an X11 terminal  (from the keyboard, type Apple-N). From the terminal you can do the following
    1. Change to the folder where you installed mricron, e.g. cd ~/Documents/mricron
    2. Launch mricron by typing ./mricron (note you must be in the same folder as the mricron executable.
    3. You can also run the example .bat files, for example ./xfmri.bat shows two statistical maps on top of a high resolution anatomical scan.

Linux x86 64bit While the x86-32bit version may run, in theory it should be possible to create a 64-bit native version by recompiling the source code.
 NoteThe Linux-native version of MRIcron was created using a beta release compiler. In many cases the best solution is to run the Windows-native version of MRIcron using Wine or a virtualized Windows environment (e.g. VMware player, QEMU or Xen).

  1. Install the compiler. To compile this software, you will need a build of Lazarus created on or after May 1, 2006. This software requires some recent patches that are not available on the current stable release. To get the latest developmental snapshot of Lazarus, click here.
  2. Get the source code. The source code is available here. The source file includes sample images in the Templates and Example folders. To test this software, compile mricron.lpr. Next use the File/templates menu to open sample images. Alternatively, after compiling the software, you can click on the included .bat files to see sample renderings.
  3. Linux users:You need to have write access to the folder where you run MRIcron (it will want to create .ini files) I suggest placing this software in your home directory.
logo    Lazarus
mricron-0.20140804.1~dfsg.1.orig/html/peri/0000755000175000017500000000000012360760644016113 5ustar mihmihmricron-0.20140804.1~dfsg.1.orig/html/peri/index.html0000755000175000017500000002127410555534326020121 0ustar mihmih MRIcron Peristimulus Plots
Peristimulus Plots

Introduction

SPM and FSL are powerful tools for analyzing fMRI data. However, the statistical maps most people generate with these tools can be difficult to interpret. Generating peristimulus plots can allow you to get a better idea of what your data actually looks like, and can help you determine if a region shows an increased amplitude of activity or a more sustained response to a stimuli. To generate peristimulus plots you will need:
  1. MRIcron developmental release.
  2. A 4D fMRI dataset (typically motion corrected and smoothed)
  3. A FSL format 3-column text file for each condition you wish to analyze.
  4. Optional: regions of interest for specific brain regions.
You can also click here to download a sample data set (14mb).

Basic Usage

Here are step-by-step instructions
  1. launching MRIcron. Then choose '4D traces' from the View menu.
  2. Press the 'Open Data' button.
    • You will be asked to load a sample dataset, choose filtered_func_data.nii.gz
    • Optional: You will be asked to load event onset files, choose both L_Tap.txt and R_Tap.txt
    • Optional: You will be asked whether you want to load any regions of interest. These can be hdr/img; nii; or voi files (note you have to pull down the file-type menu to select voi files). Select L.voi and R.voi
  3. MRIcron will now display a timeline for your data. If you have loaded multiple regions, a separate line displays each ROI. If you have not selected any ROIs, you will be shown the currently selected voxel - use MRIcron's main window to select a voxel you want to view and then press the red refresh button in the timeline window to see the timeiline for this voxel. Note that if you have loaded any event onsets, each condition is shown as a unique color of vertical stripes - for example in the example left hand taps are shown as red bars and right taps are shown as green bars. Note with the example datasets that left taps are followed by increases in signal for the right ROI, while right taps are followed by increasing signal in the left hemisphere.
    Timeline
  4. Before generating peristimulus plots, make sure that the TR is accurately set. Our sample data has a TR of 3 seconds, and this is correctly reported in the image file, so MRIcron correctly reports a TR of 3 seconds. If your TR is incorrect, the events will not be correctly aligned with your images.
  5. Press the 'Plot' button to generate phase-locked peristimulus plot. You will want to check the settings for your peristimulus plot
    1. The bin width sets the resolution for plot - smaller bins are more precise but noiser. By default, the bin width is set to your TR, in our example 3 seconds.
    2. The pre-stimulus bins sets the number of baseline bins. In our example we are setting 4 bins (12 seconds).
    3. The number of post-stimulus bins plot signal changes after an event has been presented. Remember that fMRI signals are sluggish, and take 5-6 seconds to peak. For the example, set this to 14 (42 seconds).
    4. If you slice time corrected your data, check the appropriate box. Event times will be adjusted for the acquisition of the middle-slice in your volume (e.g. all of your onsets will be adjusted by 0.5 TR).
    5. The save peristimulus volume button allows you to save a separate 3D dataset for each time bin. This is an advanced feature we will discuss later.
      Settings
  6. MRIcron generates a peristimulus plot. Different colors are used for the different conditions, while different line styles are used for the different regions of interest. For our example, note that the right hemisphere shows a response for left but not right taps, while the reverse is true for the left hemisphere. The peak amplitude is about 1% signal change. While this effect sounds small, note that we are averaging over a large number of voxels which in this case were selected baseed solely on anatomy, rather than post-hoc selecting the single most active voxel. Also note that the error bars are rather small.
periplot

Advanced Usage

  • For statisitcal analysis, you will want the precise values for the effect sizes and standard errors. If you press the 'text' button instead of the plot button, you will be shown the precise values - save these as a .csv (comma separated values) format file to open them and generate nice graphs with Excel or other software.
  • You can save peristimulus volumes to see precisely what is happening for each voxel at a given time point. The image below shows the 8th time bin for both the left and right movement conditions. Note the bright contralateral signal.
    PeriVolume
  • When generating peristimulus plots, you have an option of choosing whether your data has been slice time corrected or not. This will influence how the event times are interpretted. Without STC, my software assumes that the event times are relative to the first slice of the first volume. On the other hand, if STC is checked, all times are relative to the acquisition of the middle slice of the first volume. The image below illustrates this (assuming a 2 second TR): without STC, the first event occurs at 0.5sec, and the second event occurs at 6 seconds. With STC, the first event occurs at -0.5s, and the second event occurs at 5s. Sparse acquisition is useful for auditory studies (as stimuli can be presented while the scanner is silent, and we can then observe the sluggish consequences of this). However, most sparse studies will not yield good peristimulus plots (good plots will required jittered stimulus-scan intervals). In any case, for sparse imaging I suggest making sure STC is NOT selected, and having the origin for event times to be the acquisition of the irst slice. Note that my software does not adjust for differences in slice time acquisition within a volume. The whole 3D volume is assumed to have been collected at a single instant. Therefore, (for axial acquisitions) signals from the cerebellum will appear to have a different lag than signals from the top of the brain. If you want to make comparisons between different brain areas, you may want to slice time correct your data before generating peristimulus plots.
    PeriVolume

Notes

My software gives you a direct view into how your data looks. Also note that a single timepoint can be averaged into a number of bins (e.g. if the events occur rapidly, one scan could show a timepoint which is after a previous event but before one or more others). Furthermore, my software does not attempt to remove data from other conditions. An alternative approach is to fit each condition and then plot the data having regressed out the variability explained by other conditions. A nice implementation of this alternative approach is described here.

logo
mricron-0.20140804.1~dfsg.1.orig/html/peri/images/0000755000175000017500000000000012360760644017360 5ustar mihmihmricron-0.20140804.1~dfsg.1.orig/html/peri/images/periset.png0000755000175000017500000000475110545120072021537 0ustar mihmihPNG  IHDRlPLTEJ\4Ř<\ &ll|d4NL4lLvL |4$$|  $DBD<d|L  N\  ̤TT6l |$ ^$t jlLD 0|ж|| q|q0|Mwpw7|7w|` fw# 0w` waaVnwwnw|CՀw|wpڄw|Ԣww ' Dw6BwO||L@?w|gBwe?Ԣww/=?w|p$E|X=?wwww 7 pHYs+IDATx흇4\m;XXC(^lqe[eshuyFcC*MےRȝOa}wp*k߻}U5aHbؘwT{ Of{Gk:D'<_3er||/UG̬jZV_|[cҷ^z?e}V^r)t.oU P:]}t7;ݥ| {l+- ߡ߸ȶVoa-q2χe1oSgE)k= f O38~̲bi/Qz3> E *w%md[p8NBRpGExTTzIpʇT&P9RFn70'blG?\:nb:/1Bz;7x/Ss3sH#IB=z5ƍ~>;8 /gN^8NbWS!x08'v|աCW>cGbcgꮺz505N:adN!uur'j NYW*8 ׻ uR U=kT.If=(4K ZQW J" uL=hm$xw1fҹt72f8{:]6o֞wՋd~C,B= %=;lKnZM$Ln<+jS}t]="cAW]|u\=1] |zل}]"YrSįu{t!8p|l'up"jrqB6lfnU+n[e q\?ˣFl[iTDIJ4TY'2kX_WBR&e&,Ϋf)Jֆyk]2q1X BGNb\3]=,Rpr:ǗGϝ%J3?GȊ [625ᙢAo@y?b-[&*;u7VnX(ZAn8?Ԩ 2wļ5$$s^FA̴/h:ꑽTT)U$Plp߯0ddez랕Z]JFU\sFW])ezI+$w6sD>{Lx ,$]r6Tv̇xiP+=u'v,"R-tOMFb7k32t:2jK6Vu-\>t L[?6nQ2- BQ[/$ܑ=(_ <K= ڌzl7-Ѧ)ta3ߐ[}Ǝ$"8qdC !3$VRW5iLA$5V-1{,XX-KLGAuHayEdPJCm:~ɿ\,j1d]?0BP,)M=X7"ǦNXJIqu& MƜ=f?N_u=+D֙h2QHo/uZUml0YC+|>>]aR0!/Rb=>9z^wP!>>xP>RF=V]k3M&~EP!PX_[Xɜ 8Yy:a?#u0AC@"#bnjm$@\$Ǣp|WGIʐUvf'/J Ï8$X@؋o*|̩fD&gڬ,F{#Q+s)¥Gz%rE"]kbm.6RJX5W*fL5"RÍ$lF'!̳Ŧ fCCLIˮſvB$N-\fA<8堐0u8Q1ڥQ)j::Kԓ *9ְʜ19GOMnߕE$L3) ;LԜ阩48%=FYt4\* `/MuDjR UI:(W1OչmJA]1bLP  WTϴ$<O gnlO͂R}C aG-D-cq4C<&M"6IvRQr3jW^2 0Y23O CӪ}!r?y=w`Nk PO9B@=}EFND1V\u YkξŴҷ[~dOԧdhڜ ?X.3at7]9*vDB2͹)LG[EP; KFuKO H?W1 2G&0g 24ŪCm*.-.|#lZӠܟMի)ԛ n6#JK|>32jE̩nQKD $|ȶ8<[R*J"lR2c% e B} 95|Dj)ޘ"((s.P⋒N)UD)!ܦ3QXq(+pO'615۲RB8[d =SƧƁrڀe6zvVS i[bhW%2?8.1`v%Wzs0SMKᰵ%i*uWRJ ݓBJlmnUe[w<օ9m ʸ&Bn~qRrYIUY6ƫ\i^rxz?'I겤yw7( sKR2Ԑ brS+gv2! "[VYSe!M$\Xzo9zrƩ֮V,hMLlZӸur$E:J>=:%FQbR_n>AizUJ$ A\P|.%>`v#pG j^Fġop~VB}&T~)!g Jdl K?1JnTgTbR#dyPKhINTĤ v#z:4CLS^\g*QnBrPO͸QƝnB|Ag lbotkF |Y.E`?@m̻Iej;<:4k=},aCił(b+E~zbW;wƳ7g8シUg6ΝvWk6T[.& %CQccRb;)D$c\+cɨ:7$'ZTY3Ԧp t7 `%̓$"m`e2H@wʎ6u.G6u-JHGBѠ;<θx^sbuR1ͮn7Yϧ#RB\Ioy Z?05ya}FĭC% eC{$nzCNJεH;* crH8cp5UT#Te+Ӹ^~%JUnSIcRA#B~mf.!"5)-}R}1D@RJq ,p;ZG(!7))$60K2cyIu| ׹qb0 \;8i7BRbF=R߱IiMFͥ! b>:+vmwP&l5m-yzL*QCFnsQPgR[7P];jƤ)v0)Y@O!6RG+.bEb"$2 a ٩H#,3]rӛ*-)wG(گeCH %rQz,l;v/1?Ҽ;>˝d$4nTc<#v4 ׉5ɻm2.\;"斊ځif?2O'Nh3lw UWg0%p4~u/=>*d(hX[r>jQZ1Zu\|Cj:X)ذ)]o1\Tw(k5*@IMLTs Rsm0̿PrSn l/pԹٚ VZs' ɆR*u?LZ ?>4%&zTPn)GAw.W-\P=z T8he?d:Vœ #x?1Jj+?+;~eCb1qAbDH3K5YàxT#ЎQc2\[USkTvD{:{V;U`=LJl*)>Gc]B S ez㠲]5Hq-4ϙO"겛KK"#L2;4̧vJLdPL"oէU6JLz zm&9`R nE0_J-?Fq@ehAf\P΀ڊ5=-rQsd- ,OQ-oxT6* =~"`1o^}q}HG,wǶãFK[XgZt}k) %"]U"+jtxFoK\}q>TӹDBl[IADp'2RRt'Wz`%enHǚ9&[sZBNփbߨ#៍K42CIpN$0+- ,nG:&46&E_*usfE*}[ޝϾMy2HBwÇ+,1>P=G5HBWE2(Gv8J?jTIR;\O|-$ҡ0YZ0ɹSJ _bu.H ?-ol,gF4;oܦ2[cZPmc}a )vp$A BueRTtj%Rou~AIn*U.;&U&% %!*5[ϩ6Ee)L%AW[I23͓)8j#תѻi rpŇ= qlHr$9f)zJm )IIؑnZS6kQ|Y O Ey3KoPAJOIɠZAvZǪ)ybMRM:fȫVK+C$ -gJ!ɥ! ү.!"N`Gb4I%e(Z>[&\juG-ћgLiWjޘuLj>}?pls{d oi?@4tQ*ql]`7SHMdg 7A$$tj T9YQ r8fjobdꀖmO}6NݱkZ^ 5s#l?ͷ yJ&GHNS~}2QbKk^>q_l_~iThrg0uCn} >xeFw崨#s[p-?&9郄q%f:Sӫ&I[s 81kRZJ !IY7o_\mRH %:Cƫfzu9VuA6iM-H؍3gQ6jJyҔsD=01TP^LǕ>-].,%Ǥ\- f͇-BKNE:҈w1`nʵ(ה$H %$˗ӳZ[1`ce?&oɴob:Mn}re/ՙQK~3!hZ~lsT'PKgY [ TSDT\jci\[5bWrNܽoPxsO+8/4q R\]b?/ԩO)GEq:V4CX-=*8l Md)s^pS>#[=I@r]̴i9Ep^l=EȿW *Jd>EF(TS&gaDjќI?NeHp'㥱UdhT3tdԔZYF:Wt-1oRtzaw6cU$=׹Yi?䐮æ:¼ {cb064!lUiQ~[~3zNj VG$ح]INNnu*V$VǺH^[pAfWe*LuA'm`gqar ҰJMN"I;pzvmTZi&PIo2+*u>*/  =-a)#r]C0zo1KڸaդN,rȭ0NmQqm *{|p ዆X/{z`A1)KuI֢ĢPĉQ~!$,+Rh)_yn( 6e?:\M v/8RE-ޝ]-r_oá ~GۯQ~"mbQǵSHYhRA*u'4 BNCSTV[԰48gAMmʂ kAHABq;zWWQ!pAHFa}H8WE1GZ&݁N[4ԄC8dBJtqt,"yV+je%-)+(rQ)~qjkFO\ 죊q۲ .:m'*8&򙥮%.ŅaL!./p-jiQRfHNK hg}J,E3IM.A\gQ^lcQ-ݒ !91w8:NtKqmJS51J'_٪+EnCMWrl-OnMKTXJ i`?8[䮫P|*xLU6V*CtNxBżV 26rc4WXU-^{m_ksdy `t,[HkZﵹ;c_$L{t)%x%heXF}@ȭNn,\]I)ȷLYT3 ĉn%1|( A:5edn*7lo#)SklCU34x%Ī_A =5:{.{ȼr7,j͹ xM +2#YlVW?|M~$7 qҥ ,Jϥ~c2T\_Bϙ@ԣ:Xcj6CJމ\EJ1jnTJ.ܑṿkaf1Mqٮ#Zw "罽1rt}M*M# K:IMSh:2}J RqJ R>{wШi&H:kWm 4sO6AMcXǚG!PQ R8JS)-Uhj=EspP&[{bއi!ٲЦJ_ V@{}`j~_f>zqWPc뎵 U9Qe|$,zR%$\#=56ѷ|"Z=OA+*%CM`<>}Rٱ=d\}ǘ⿉N'uUê 6K> Ά6$IK_6þ/9]_M|ccʊ]mAhPA8p&Fp^*'I< &sS(6oܻktDfH\U2GĶREǘgs†"ȅ#:k|TđZ& V*ƈ}FSuN㺼Jk{_b[t4x Zh*TD!}D_!>@)?NXA~\EBF}|ö>H*uس4p[BR\־:5H],1P)i )v[[@#洕m2~նt4Nm@xR[Բ!-=fw0"L<}p Eiu?|<'5XrꃊY 2M9C.ʌ%mqPRދ;wإWJhs5jvd;M cI(6qXTM\lPhף>S olul7S ޢMHM:[NJu!$@{Ƙo225g]:5Z\{ d A׺G'H6BC Jm,T썏Lt>dnV f0c9nΩ .R;h* nco<<F\Eˋ)&NSbޟAnطgAsRi 1:#g%!V H-%>-nHgI!y+,;6  BLL0!kOqB~GUj\MnmA:rW2#X;zXfUIF6"6>V)֞1/.ګ=R̄ө7Q= •fxЏةsTyl\VDBR7k$Q"U\d$VQ?)%IoSZS-h6noVd=ߒ(|zey6!gCX8Y_[E20 ADi:OP%6TåǢ$[ҏ5 YE;'Ìԇ0-\'ر8+bSi~rRS _But7달Q)"q dm>/*@u,I!WQGK'Ҥ"JH `W)RXqC֥Ǜ)5MӅ^iPp˙n&5%k6$]bAJS)ț ï9"BWC'r&wĤe4ܺcn-TԀe)WZçlgL3SABn4}ec.UCi) l5i*66=-,]OڧlVFAhpQ3^1*TWRUWmMf۩ogٖ8Buʛ0Ylo/n1%̌lmnۣFMw4ҤuY:qaٔ='1en|kT\nB5!CBFU3TϥOiǴ%^²{JqtiZt6M=Ʈ%C*ĭ} dEQH𛫨:l5 ~5"Z|BŷN>s{$aYҘťiG˸^ݱ^9LRa\L@M *7<N)C)X>5Dw >^F\>opU쑰?S.gCDV U.(Rp23SiMBJv"P8 ̬:*kڜB@lE".P뜈M̙$]n[8VR YP|=.KqJ[eHr2v dtQ^kRwPRP{0dV&cS@\ro,MPޟ *NkRs ;묶r*:T */kvCK5&2o4(uaA:u<71 4 }$#ױ\G*Qr ]Jbʹimu}Lq o[^Hj)-{*a|=P9(t ^*!qeIlT3]RVt*bJ!$%)VqF.p52wW,qm[A;A*f km%ܔw}LI%2#HqQ@7t4)/!$7ʩ"55 ʜM"$!ʊ9IMΧ>Sloy8!rY[(m8㝎 j 5TzַPe,ÔZ2jVmGek A%`:b'߯lRV)ݻ,Si1hƘۢG|` Wg R0%%8*^b D4HJm)#< %ָ[[9NߦWqg2˩Ye>ʎD݆y+'9I|\Ome2eܩMSMtZ(#gpkr ÉC[i2?5|Bl=APӨ)M49{`Daft:$6 MX Lr=HP%J==}J5AX(9O"5RU; 2RQӤt\ePKQ#kPҫ6t )r#Ymnb_Atڍhqp`OV$ҘAEVch Pب|y +ӗ5KMEթ1}dI@oĎ&>K6*3mIU=~T5$K95t MiH! x/1'Ԙξ #n;%ɯ՛ Ci!=¿5gJFH!Il4dHQZbl[Om*(8dwS+*MezsNi9WzyxgMND*~~UM,O-W z\+fyyϊrj K56ߠŬTN1Ŗ܊y  hFj*yߞ*4uO 2m+/K|zQq4(P$Ө DwR 6;t9yb Hzx.,d;U R#eQqᅱɜViꊿM6eIKg԰U i(*ۥOSq!͑S[.S}Cmn1RS jR \SW0 ů1U6>xJXJR۞$pǹ{]49_Ԥ)RnJUzoIrdū˦2-*׷A܏תٯ2\VHIJ@'ĥl_, TG4UW@G|n[>֛'? Ko.>8K)RX͛UrTTM=g+3 ]E8*77WMl ꨳbȳ`9Zs%M #R{SԪ_y=UdFخ`0{é͢ 6OCpd;OB0DS_uCVgE[Ii?kMl q@ŧvJ Ms,[]fyqB@d,wþ*ZN {-ej\Zz\8qK$܂_B⼪Q2dQr;7GSp; 9IDY+9VeQ3SnBǑ8U2o_\@ʹdox1t|bK<ۨ/2 VZSb8[_H75UUaIaĤ"*Iwa2go#TT$z7!ѸONd Z*"ǡ$mlT~C52CRZ=vTE}Տ%,i2sWQ(QFˬ -`(y'ZPj-Τr< ` "mU3Z Skh5h- M~-Veg&(.YLTeU![_؜+qt4W2vCCjR%<)O6ֈ_P j*w뉄L~Ms9)-Ku1 -D46b9D)fI%2!>'Ы2ZPZQ6()}#» Q0eR`VTO4Wu*BZDT3L?zHC@n5ck|@B24U'C[0VJ)R*}j%^%/-M) )PlF<1(|Htt2"t,>#~ۗ+UW*SUԸL_`Lֲ+V[yq(+P#˶=G:xW^VMž=?L/1"5q&Sd)']q ZJ7'1"f3Emricron-0.20140804.1~dfsg.1.orig/html/peri/images/timeline.png0000755000175000017500000003054210545120012021661 0ustar mihmihPNG  IHDRvPLTEJ\ b4<\NڔvL̜&l $"$4DBD|dbdld䂄ܤ424TRTtrtL4l4L" |$$BD,*,LJL|ljl<:<\Z\|z| ̼ $<d6lL|䬪 "DN\R TT^ jlĤ䢄 &l$&$DFD |dfd$ ܤ464TVTtvtbDDL$t 촲,.,LNLlnl<><\^\|~|  0w` wgaVnwwnw|CՀw|DQwpڄw|Ԣww' Dw6Bw$O(||L@?w$|(gBw e?Ԣww/=?w|p$E|X=?wwwwm IDATx݉cȞ t8M G&Nrd= "'x ;!Lc1ɋ7rv8/3\,nu(WU*]JHC%E icv32@ C b@ Eݯ2H@Edw%vl7@N"|v:[7>7<-1.q]B.;cJ"U0oT<5yo Jj.o_gf_'.˪nqwvGiw5%qA_nY^K>?gѿ8/.٠RYҲ)#x3^.;D=L^"/gpX;(YAR%?3N+_p]V(/3u%`6IbR e:[YD(%e,4:Oݮ>U A/Ž[2Yt61/*_2jʧҏ^%eFz6ͲV87 ,*_W!frUVT7:a|I R]:w?}VdeW"Ne8frc^[حkevoͺ[eglDvvaagfMx9h?/O[ݺ\fU4lVoTk\ֳ3egW<W[cWֳf+h`7*``O=_?;s˥Ⱦj/2'B)ŮV5efV`WA[leguȮ1flwtڒWfw>+V'J:/YHQ]/EfqvMuܬ֧ m삷P2;ʿ,Wu.Yʠ-.ݤRfoW~;,ɢ'ȿb2JesO?n΋AspVjصV!WQsS~E n7j@d!td@ ES!4Xo .2D .9; j͟\|>"_f^v=b'C[=|sERmZk?݄=Yqs.cq v:b7_y'ؙliv?"+.~|n=9Cg8_'5x+T(~T\.؁]gT)翴8= gGo=;2?]|fg( kڹ;>s\ǫ'dfT`eٮH,+ng;jˎ'>ݭu~TwXţzȭ.2=,NlDn^pgWߞᘂ]Wr[]jͲ(g;vS&-DE |չݗgJzWT[Vj팳]X˼v,ngg<3gˋFWTUOvݬ]:}HBٮrY8e wv˳]uaęy`7Rv_Q唴~-i9";*4٭"؍l[eg\XvOTn}cђY.>/cE$.2nv_}ή"vofQl,7sj fg4Ie,쌶IŨW_"EH'o9}8۵5xRj]Q*FՕ*+;+=_^vg4r!èr0ǫ;n֨ٞMoaL&؍]^SjWyljq[:fujVv{~6ˏ6ooےؑ·]yYvc'?Zݷ %<&YlƂ!;Ĕ]\~SC ;C]Wxݻwݻwwvv+ y ٝbGĔΝ;Jصk׎.]ٳ[xᡪZGSĔv٭7`vDlvJjr/_ںqǏo߾}tt|~yH޼yv;vjl޶~~/_/.O?}葪 T%Oݬ*lQVMxYx?`uk랝Xo  Gɰ+<uwؕbWQvgsrrr(pJoBS~^yW\Q-qoz4Fc Ν;W^=88犗^;USU*W\ ƎJ91ۍH n}H`GPv=gM75xeoNӧO_|y||Ǽg@O?T9; M^9vحa[9U9lGuHXvk&t .j漎,vXGn[j]ɭ[TNɗ; 6%~4;׋0O7=zuxx;;;;>~Znb)v_.BϫOu]07Q|/\ v`v`v`v`vd͛gϞXw dmNaRAzǏտZ}Z˗/=;;;;;==s玒s>WbiK3۩OszSPw^ v`v`v`v`vfL|A2nS4|ZOOLq t?w`v`v`v`v`7v?OT--9 NIR8hszZE,Aի}`v`v`v`v`7\v*tN'rԏokl_BwsLߐ; ZZYSK~]xӧ ёbN-!9]CTg==m^Sq+7nPջ7oހ؁E,J-;욟vSe*vz:B@)=DK/BOշ哄S; @k{_>88Pi.YQ qV6w_Q*9;n婚٩V;.\p=~hR v`v`v`v`7Vv@17ژiFzA}7b Qr)vvvn$(;+EyfooۚcO'=ZA>j GGG'''cgI6؁5;;;;'vV9hF]tòZ|\v*ztWѣk׮1DwĎ؁؁]u4g؁LQ n-{?u6VNG>ƧүWlׯ30"vK;.ّU f8ة6؁p5d V춷fН ҕv}fBLCfB$ ]iv`Ѷ;ً?sv- 2A+\bgQ@1ؕjuyr=xٳg>;kf uf\n8(; ;uX;U3ٝ(|(FhvP|J]* .].;ΒYc v}gWkt: vf!IH)ewivS`;s(߫/}V,{.(Qv`7.vo`)w/\ٵwqgGCdWY`GPpjGˎrew؍*߿r ]L#Y; 9[W^ݹsǏCW _  n它vaGkFNVxhjm&* chfWNlv~Ne>(ݥK#lT(X޻\9O4J*l߿ήܤ#v9>Zo; !u &.+ >~wPTn>?|pkk@}=z"ԗ.]R?W Ney!n7؁3>4;frfݻW^U>|)g^R";qڵE՟viKv/akRDdW`v`vVvmZȎ]&.2k{/q=ݻw/^P4^sv`vSg'y v7=FƎ{i ή}j]./*J)dH+;n.Wj v`gv zŽ#3k{QvSgg|+` -`v`'ŽҰ`w6HޟeǎY8]8٭?; avdvLvNe V_quΡv`v`׺vtv{쒱[wL<;;;11r:os_c\퀝;;~[V72;22CEw+Kq]ei;͎ dW,nf\N4&24- \([~CvUZt);[ %as;;H-1a- Q>ujbaתm)eoy,;r u˲sz;'v좰4:cGXnώ8;Laڒ5;c;r;Kb9vG k)ؑWe-.]6шYv`'WOZEok"euHƮ(rvݲcjc]JȮpnf; ;WFۍ`f8ԙe=aFi0ӈhSٵTq l J.#sbZftvs vcGKeG;/vd{93{2Wkce\ٹ t`׶(;>%ZTHɭ]#^`W9FfUٝ0;qȣT^#DY#:FȎn]R'Ŏ;l[}\ 1NCvSdWy˱szNi:vx<K'- ݰ}W`-;dwzy*aGuX+Cf<v mvVM}8$WrTm{H v'is_t[uOʼn-&@](>9ɔeU$9NڬTov?DٵvLaWN,}:}+ګC?ogg8BQܙ֓,;IS+^JO[4vy{KXŮD,SJm~\ 6 fuJv +$,aє]JSa1߻ʥ4VoеıBIqݪp~;]*Ne]eݹ_ @;YxZNQ3;rjvYlRÎp{Ϯ-0b۵Lqǎ6J`ݎD%Xc ov"[VşMY(&€숧(-;ٲ0xvm(EgגcuT";ϸREN G P앻/r)Kl ʎ(0`'n엄 M+ǎEg:ʽ, n'rxpBA vj.R2"? z$6/ʇ]&.8NW䶌cd,vtcjCrG_M ]6v%|/D2S5`v29Ir d욯ly1i`v7I"뽸̎N2,BM1Zv0-xIک*hl= e'{fMvag~FJvTeaNTBvϸ7PG=;HBم<ۍ]â(fr%j&vf*Av \(;$Qt=b ̜W斪fDvh;b . ]3 Bv=dG-;i)صP5/"&X+؉X\~18,֍ÉTҔȝmܚyMcc'FCb0`.JbYM#`'<Į5Zvu]ιnX1=\{ijp-}eǘ )I,(݌ =ծR>i5UPђsrjV3vQF[%3bjgXATQ@ݎ.QّxrN UZ0Dّ#~;oR!TgCrv% ^G+;}8ȩRK&Qllw~밀]f.; ή|H5nВ)yMcfGƢH`;b˄)ݢrA8ہ%f :R^h2d;;V؁]Zvj3Q;;;d؁] v$`v`v`v=eGrz؁],;>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;![YbF!:(vXGnz+dgvM+3C#شնt{9>*U v={.[F8Yܦm kρF.3 솿nv`߭-Pv`+hCd.:]w({ǺqQ2N0C &`@vC `@hd@ D@ C b5ϖ ٚ8"x;؁E²saջ#{׵Z¿wVW>uj*YWU`pQ|m,+-}R42_Sw(?v͂_daa,Į5"⒍irz1u5o-"Nƹx/tY`,[_4Z{uuu%YY.ͪGeVv_^-Ӵk9O.2TVSu5fvnwxIŵjQn, +uj~\Z++,CPWh4t%7eؗ[d׸C^]n7-;DmZ!]'uIgKB]@$C :aM"q l%IENDB`mricron-0.20140804.1~dfsg.1.orig/html/peri/images/icon.png0000755000175000017500000001243410476415444021026 0ustar mihmihPNG  IHDRQ>9 pHYs  IDATxyp՝?=ni$Ylc,``|`; (C͵!&#V?MU6]YRY6BK }c%ٖukFsF5HoR~}G왮w# f0xGg+UBa,B>5 /%P hC.[pZqEh]T]*e2Z»VFɄNx l@}=m'Rj~a(ą =ӦvË3LPxOeK}1(JzH4Zie_Ŏa<6}}=…3^b ;.okQ}bߢxKF&L<C+i2Jk-mk4vW%q{wipO;OR@@=XucT~Z)s6 iS}UՆծ=SД+|\ kd¬zQ+/ziTGPXg1úTMC+rf,ϛ_#wJyy9`>]Vg^QƵic=>sdx;`, ` inf,+]w?O==z1xdykZ>Yfd#ha<:v|tTE1- c\u{D륡@Fn;ms(O>y~h_\Y*o#$|+ethK]tZQ]-GGLfQ]M @ @S^oPr]zJcxb]qkM7SCj712)([};vF3$eܒ}NC(D(DGmS_OSSX֎#]D>x_qqA>,ZD[SD?O?KoA؛NCkUWh4ȉwTl|hv&hP2?sɮ˹s;GU,[Fmmfvz5uu{lV,*ꦓ |wq_KadP|@RzBcdpRsneS>o@!ݜ8uu|]Bc#5?Zʽ-^[C-Fq♷܎'s5`G3W|u낯X0~Nbd&',Zp)wY>Ç\_@NƢG1kW̦6t%RZY*SW!0 0>Μ 3KUJ n!*ߟp~?nVY}wc9{C2csݗRg@3)x p!I,8gK55̞p c^*dVҾu:ww]sgUj*!ZJ z m8chC mo_Td&>K0R[۷ _Q+-UBhjjq:rvox~ӈNd7C !O< 9*FۺzWo-Fy\8f DctxƩ_{q4` 55xc|*G9 קWW41l; Bu (odް|9MMaur ˧+#tp{%*N }7-_aolM .\ )ō76S鵶\Ni*7ivHXoAf$MLnDQtRٙfi[2R~_][hI#>w /F6ӟL20gE5irp&PlVb"SSi߯Zنg)TFK룡!ti @C5;|XQ1mJZ)eP)](JtsNf c|Fqi˙ 08xkхZB|WKZiR:g9&ULb` ҂m:.\\_R(O`Tɠe2#i4ӟtᬵ2x+/W<OMCk.몪\*XewxO##clf'p?dzNr`` yH*eT츴{͘r )ו f;&6LE}M##D"3 P] ,+5.{{=ufE(>PqotG13+)!qJB@j0f-nW_(6jt5R([#;EHa~Za+e5}ڇ7f~2bFF<6iYX=Xoy'V1鮭DW|}kV$Bp&i[=g~ᗐs<]~.9+i3 0'j\-JkRcښ7UmG-WCozU<@3Z iyHk"8B nb*B #nn1P?K E% A;.dȤԸ5K׍ Лz~&,ЖPR()ppU| H44xT8 ǘӭh`/!bda JgJWQ!\TvL;*u[JR+TjsS'k{+>C{V (xp{K(zؘaPW3S3K:f\)6G()\Q}lM_=- _ 'b,oU8_ A@TR)#RFX$@1]J%]%D IJ%=//t{ݎw7C#/{XNdJxiW|GyFEnғo% }{ Vr=~X?y| )&Q[?O\tL,"Kz  &vzX&xԵ DrF-˅h$q^ )d3Jqa-j#Ӈ>Bo;Bzz gU@;ٷ~`R:4{"VI=6U2\E)qG rnߊ0Kpg"T,A6J#|smJ翊s=K\Hw#ةW3a;cQlluMKkffB5H/,ͿI"y2e`)^)yb?Kġ"RKH%h>T>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~]} IDATxyp[չKhhBIC  HBBo"[^%˒ojI־Z.]I־ٖ=^% q6:-IJY\}om^`>D HWheL\]smVORA M|.{/d.M FQSɄGő.;8ug BbqtYX,3ayj;hөUx E@n9 -R2\ AUw-jJE.-hP(VzkW.c+?Y%p3 C`{F&:3$R9=J&g棕h@kS/2uF.lgyu+pt箿yWF%WhI%My$DFcK2p"SFh KJ x ^?T&%0̉LgF%Mױ j X%PG؎ק#K?3t|S$==;&vZZNQ[ccfGrZ:h. **0YE f)P~+ʞ|LiXz.,,:l506Տ`r2ʐJG ZJf*HBe/RRNh!l k=aŮvN=^MgSD< ݉%1kD*8 .a$6R,,֟*>ȱ[&Cw@G H L ϲReOk;.WV8l,il\Dg4-s`n2N!k8}&wd._͸/To;Pœu%<_z9I[n=V_?6/7ITWgRA`KvڭLgdvt[fzlR$E$,9=q o2+SC!iqHh;}ƴr/1bN\6a'ʪ{m\ uE>r Pi u+)e6p3=х\2=W o};65%!{$E|usG_ڹe9RwO Yb~KY }.K`+%29:M,,iح5%Ǐ}ȁ&:RwRcnuhoA%_)Uz/?S^ydV'q3؛V?uċ/ "6'.Worʍ g; 8FwŘ$ERpwKN_Ԙ&lBOr#!Vd2e^u5WgS}3s qd +>qWٖݫqŹ3 ;[I|SoxЭE}FRxk7qI"1 ׈[P2 Q]notwPh|jN7ۥ]f]{u K`^q3K%,HF`bv @c2eU ]^u)\Saw3NPi]HOcpM|j$H-J$+=UȨ$>,Ţ2?xwa4kmVⱑGkp'=f3[L&!bjOB;6T+0THɖOg tvnIexx20>_p2)d4Ꝡ?`s( ^^\I͐F2gx+}N*8\V $w!6'z7957'{ീn$kI^ mlTr Dtn eH볩 ũU>LzHaZT"ߊDj)(nu)2UdX ~!IIq[OCEr{-ūTףlRǶb **P)tZ8)ȃWn]Q!q-UUQ=r\ើUV(lJR݀b[qtAk_?c۷7ܱI6=d aqTJrXHJ.艮y ˷4BEY$fMw?'EmNqY% U*&vi%٠I!a%ǫˏVWAk ޿Xu]UѢF^ȡAOGtmHQ 2/g`];3Mm7҈o,B< p(WVE;v俴K uXȱӗj`FML^ƣ~{fm}eaNa 鷗9+K`&L]^OnC/s7axSf}R wf}.tܶX-P|xOV;$0IENDB`mricron-0.20140804.1~dfsg.1.orig/html/peri/images/peristimulusplot.png0000755000175000017500000002160310545120174023526 0ustar mihmihPNG  IHDRvPLTEJ\b4̌ <\ &l4ڔl|NdL4l4LvL" |$$|BD  $DBD<d6lL|䢄 "DN\R  ̤TT &l |^$ 䂄$t LjlbDD  | T0||1|Mwp܌w@7|q7| f#@`w@|||qDpw|qw 6Bw||L@?w|Be?w/=?w||p$E|X=p?wwm|wp1 pHYs+ IDATx݇]qkx׼ %pq!ʆvGqvg<$˖dHd{ lz Jv|DɀABD0}K$ AfGDXJޚϗ0}|?QR l%tv_G~>߉ߗ.omY3c{x?/?y?K/eǵ gJVeSy[t}w#6,Pe]kЅۂO_?')%(Zl__*#{]Z?b;{wg62O?~־>//؍^Ӡ,;}O=:UqŶ=/x4ީU|z]R#Ԏk);)Gq5]SRr]?OBM9=j/~goa2{ǨMfl!WeV!Ƈ|?g\Բ /(s I:}j(k;P6iޠ5RvsvC;d?c7v~ݼ%,nPnWldwіP/;gs얳c4FNovkFv__'~[vS3iumv۲JN2;[[-;=;ke{(;Kb;)`?ɯ_}O_Ys+Bxbg쏅Rv.Ζ@xbv>㬗55vW2/H);~?ׯiyJz,M럘ckQn^S:̋m7jEۀNy]h3;O]֡ץ c1RxܗTLvv?oZІWvM>Du9%ŌR\>~OPb/v^ =M R+9-ͳ{[7 x;> r7~(ASDI52 (.u5vwOOO><&gnoM@T.Z rOo=޿zLxSemCsq"v&sx` NeոK{lvN޼zz՛/?NG]髿v>޽S=>=zٻ-lb #}#vcnަ|{Ϯ뺛/vvwȮ+n v [\wƏ wҤ*6:ݕWHj;XoFvOvk]^uO曟 SnZ . ;n8/ax{>3{?{eX֫6MϾRۥaw2]c6ߐ]!{v?I9v+v?n8egSj~Tۍhxo11:jٍEδ1zgWuӹeBdm7ksj]nlvH0n΃]y=즗n힖6EI {[#SnNb^ų]47k,Jv[d|nl6\ɜwfpnv42ggv݃ǡ)9\k\o7ЯdT]Ɍf\RyJ+k)%BY[nd>{Ƽ|bĹʦQ*~TSn}.(w)bm4􌛵8uu lfRIÈ}yƢs%Q*Ʉ]"{Ǹὔcڎhp㣂W<}?aG8%@Ǘ`o^=}xvg7ܽNqos]-,@T.ϤysNuٝ4A"`G#;A#Į'PL: ʄŽ (#A {,}BbAz*m[[|q4ctuWG,h֔tښms*pu]xP8{eE~ ؉`/!l:?SjKۍ?u Ftv`GT_^wi?n)AݜWcB7S.tJvDeV ]FNvʱ#*e'd\R)dOXNĎ+ľl#s;yW[D~ vUb vDav^47|Fd:R2]9vحxnƃQ"m`G# `G#v;v;v#Dk?]{!$IXvX`Gdbש+Ԧ숲:#Ja;v#`;v;z-vvD6vx0R]-A`ghVLzi`Tw]vjR/]rvɜJv/MvY/ZJ/`RGJvV:礶vKnC\] ; i@vQ `і춱LCv g}W`@3u;Dbp;g;.@K*/44a`;o)2IJ+fC]vv 켌$UxlNX8;&~\:2f$`v[Mnv]Qv<v+\]yvv``;f&`WX3a;k_]氃]qu=#`;k^];ءε1v'(S`;v(inivgeg-wf'n]dH" 5N$;]nuvgc'@yv`G.p; 1w;;I%h(2 ح51} Ma;Ŗu|n'hfv^R` v]rw]T)TvRE ;fvC'vK.m `2[0 `w;5n)`EՉ$``W]`:K++av5;`w2!;|Γ a;.;qvGEB"R9r!-; 8xy[*&`BSWv 䨧tNX4m>UW]3$`Nx z!`;H ̆v明.ճ5ὴWΖG:KvK)t&KHsy5.M\aaؕ+"5:[cZsv"few7-G#duk `g1O/Rf}'(axi9[Nģ^N|.L%giiTN4Y][ /\ha)xO- 6fa[4O(b vsl-4!|'Q'"Qz.}s:U_{=ZNvͤ_eGC"rRnoصθ2(,|5i,;n]ح_c1EP./;]]MBN[Kvf;;…n~îQu&ѥ-wewF99e$3vvԵsb?ItTo`6!܉qd9R0;2E)ص}LM#Sr{RZ ?v%~-oMELkQQߔu;YFzC[:Ep/Qz ]\7R6/mi)kt\AC3e9>7pصX9ӤfvArR".0c׳^czم嫓d;7;Ub>issiB$[lb-Ϋ{MIwV;gaw a9·m>T|Vpf~d @:oj f5~3ZO+8,;vr 0 /x̏ran We} = ]/S&u'/.dX=\]>M3型>s7dhLA!SڻSۺnOdw.WÒ[Y(?<~J.Խ+C]XkuO8B\8_nJy&`͘A慴Z\X錏8;2kD}n*s=Igk,s_LX&Öb.O8wQ8wߛGyokM7.>39݇<ˁح 5ofoS Q:꯰ѝU嫕܊r}ݷ@z&19TA(1mLKw:zkG{zJղ )ז>"Qf_z9:ʮދ. ;d$FpGYli)e;D1X伏ROY.[>Kr)}&q,!V݇:[-0ì. q^dzȺơ qtvAG8[[LyA<>>hNcu#N=aGy߿JdLýo\`/cf؉_& 9q_:`UU]9u-l4S6<%lio}΅4ls;%;d<;^삖=*a@~4)c+E#` 8nmk;w8 ;%MDq'aı,~v흌gg9҄GN0 'Ggu)fx֋hj$gcQV`t"ׇwry vmvK.¥3n‘S^w[gQ .~h}Kl0}u5]?KW/Qw1 +YWvwsU4duH&}YMA$MP J#ȸa3̻T s?ɥ|9D;ovyWxRkpUy,]G]M]N`t3 ;QZ}Ǜs-s|UWQ%좗aÈ)Xs'`{&V3PbvEBn7߼Lm wfv9USrr[@nc3t)0J ؅)g@h@E&<>v)yn=v/;_yЅ ju'` /}' "v!z.W{U؅sxa=m؄]dPۅ (fv(.y`wnvk4W]Qb&`]x=@buO <Ṝ' sÞvf'7kO~xq4v.1MX ;.iٜ$~=|y~HvR6pv]cAk`Ws~jvgc4O '`wJv^vgGNzn*'`wv[M‡*vK.);6 3 [.Ű;zuMv^w+muɑƮ^nA3<ۊ'yիdg2wBABNKSiK8:/vFOdC{Ac)W਍L/v݃N۟am#W]ϗjBCϦϏg]ҚNuvOŽ^]@#hqv;fKdĮ/ ;ű,-]LNk݂:^8:k-`9,^ڟ>u]m[ a˒#W7;]kDiu#=ԍ:4 T ֋IDAT bvfOem .uNIENDB`mricron-0.20140804.1~dfsg.1.orig/html/peri/images/eventtime.png0000755000175000017500000001435110555532400022064 0ustar mihmihPNG  IHDRK0PLTE|w|@ "| `tIDATx Eq2_D`zO҉e7%" rbv$b b b Ð˨|[R)ZKvf}#bX?x+4`@m\>_9ÖDؕ޼53FQo{؂[ : 5z ^ 1ڙo?%`t00TF:lؚ)LRY Z2Z(:4B*0Gaaah>< ^M -?0T4ۄ 0KU|_*섑+ca狪Out+ 1& b b0xN^C`K& L0 0a`0a 0܊ʬwPm%iYL=^ foWg6vLT]L]U}us FWKR" $3 ',JҰt듔,݀ `?,k0ҭS66n%i3F`DKq7F8T0-IEˬ$&2F5R`).0f eh<C602iŋj,c5˜R~qdҩR0xޛx)^Z(\.ք,*l° fÏ66j%gM2=>[0\֯°a{YhΒRƩ02qUCq[1r|_. YfZXSoð "J{+y.G];!([6zn05C{Pi[l aSdjs'b=`HH5ah[0YA(٤[aIߒ~L׺b';s-%4JM jC6DZk732ܱc6@z);s-0 0ʤaaaa8À9> f(Wxd.À1w (֬aLr:l匩eg!l$РZ =`l>ڙMG-+]DK]`d&fjjc}Ѷ1'4Q`B3m+'hHs~FzO5ty bj{I[&<t^6, :,8 XJTmˡ0.V0iE}VŢ@a#CIh@ơD4ScZfyY A=] =0ψaaa#t:97 sa4O:1z '00GÈ{V0gn] O.[`lظKX@ߝTan1v/틽{JeBA|@a n{Ԃܩ&w1 4^co.]׏\l:}la.G@zEsaHn`HOJp\e` h1;7MM1 Л@zx[on1 1 1 1 1 1 1 1 1 1 1  "-j<\r%I7 Ϭ1so M)8(nÀF "ҟۿz,fv徒ߏ<2<8xqւph%0ܣJaiCgg~~߸I{𖞿GXalI,==9֣bkI Stm =žc&3 UBleE#|* 2 WmTW@X& a!FU+P'CG$^Z~kp]ʇ*AX|P'S{$ 30;7Qfv ǕaJ(W0;IHNoNVW'j0XN 4_ 1 1 1 1 1 1 1 1 1 9>s33[4k?a@אf'F=f 0-CM Ôz~-r%;}#bʵ~tZ+r6Cco1ZtvEV]bWz>Rr+c7Ub14l[;WF3?~~KXkf?IQѢ1z7):2=JIkI?7PePtC a Wj1Oa0z5Q`T+0T@NZ/P>/:/N)FkIU 0#-tu1a<|}B|0@ 0@ 0@a̾}!0%@& L0 0a`0/4IL/+LCbnqe^a,u, G $' #\ƒC> Fd@ Ks4,*%˼z7e#Z #KX1km0Zm07 ZkIڦ'jv䲥_=dw.2=I]`T3,e= \xz eKFٹCl4`ep-Y.hnp bXWPA0r1pٲћtaCPd0*4JwcA"^ŲQ^05CV 0 0֘\>Q02~q Ǐl-0)@E[a[3pZ02mdgF?c1&H=ٙk`qZՀی]̵ˋh0:+Fj?$b b b00Td0EhMk/FC0`|ap֜a>O14"I^P8@jY4P^D&lV/$7Hfbfj2MEBzD%S /4Ӷһ&4鎿#k⚿TAB殉bgy b0Hz.'a~pmjM3[DAAJҧ57%<Ѐ$ jmϤO尨9"G J@0"SQZ$ %}97GD gs?.袍aq/aaa#zCzZ {r:FìW@ #.Y Ü wN$3<o.ၫy@5f򡰷U-r{J5@|@a n{Ԃܩ#w1 4^coV! ös0 r(GҟPKqbp<`د7g40@omMms0@ 0@ 0@ 0@ 0@ 0@ 0@ 0@ 0@ 0@ T_1%*$hR\!]~Կt8#֤S0\/l{ZrTa$IֶWf頰8Uy06UU0 `;+ĶBZ  [j0DƓ g w"9`HW/ITm!X0p0͔̈́0dhu Èvw|sw0`{-BRsa(Z068OjhN 2Sa,{{Ԍa,j.È%)Pt2CMaJD tnbM`rתLKe( bIj[Z̻ D] A; 5{, f>@ 0EMIAKwA066L :@;9{Giοv8$[ʙ^Wτk` ]~s:v5>K=߈?Q OR>gpq90g]Ҍ#㩵dJ5,b b b b b b b b r0i}ffh0wP0Vmq[C<~Flԝ)?qݒZM!Z`7[ᵤ$co1~6$Į-|i1zUba 0ֻ`8Na|-Ycn04f֔M1 ezjκefBaBV)t\M>cC C{_`jh`oQ_x7L&LQ=]: C0Va']]' >F?_Tuut|]aL6.)_71 1 ]q>I^#g 1 p0g 1 p0g}aE >qպ>)a+e-OKkII60~F2 OJPF?II.ڌ0Ɖ!7`LSM j7Q[`lƈpx>!qvt t>f~mY]{a DZSѫ) :P\!hWT]a8WZJ"}kٹՙB%~~0zy [e!Y4aF8-e hqGgݺ. q2rGQ1F.Q{LWL0(>g'R2V C&+LY.pv~l bӵa &r+LdyU53? ǮހVҚjIq;{,fZ+iM8+ja0naaa `*mq0|(߁|! ʹUCC0D#M.AL]$Mn]d`"azuo۰ +khC 2 bbXDڶ h@iEX KvJ:L` A*1=ԁ'a@J3ܑ8OjIoǜ ԓz5(Πa@aa0BynCzZYޢ0'{eb£a=Sa37.p'-06sl\%0 ;BvC`( >Rx opۣN=^4q0TB~p ~zu=m'`ac tu<5+ CsCBj{I820p_ߝ McMit]7yakFaIENDB`mricron-0.20140804.1~dfsg.1.orig/html/bat.html0000755000175000017500000003136610623131014016603 0ustar mihmih MRIcron Batch File Page
MRIcron Advanced Settings

Advanced Options

Command line options   Usage: mricron BackgroundImageFilename [options]

If you launch MRIcron from the command line you can (optionally) include default parameters to specify desired settings. Nice examples of these commands are the batch files that are created in the same folder as the mricron.exe program (you need to include the 'Tutorials' when you install mricron). For example, lets look at simple batch file:
  start /MAX mricron .\templates\ch2bet.nii.gz -c -0 -l 20 -h 140
The terms 'start /MAX mricron' are standard parts of a Windows batch file. This launches MRIcron and ensures that the main window is maximized to fill the entire screen. You could run this from a batch script (a text file with the name '.bat') or from the command line (e.g. choose Start/Run and type 'cmd' to start the Windows command line). Note that this script will only work from the folder where MRIcron is stored. Otherwise, the script will need to specify the location of the software:
  start /MAX c:\mricron\mricron c:\mricron\templates\ch2bet.nii.gz -c -0 -l 20 -h 140 x
Note that after the program name the script specifies the background image that is to be loaded, in this cas the image ch2bet.nii.gz. After this, you can optinally specify additional settings. For example, the "-c -0" sets the image to have a grayscale color scheme. While "-l 20 -h 140" sets the image brightness to be set for the range 20..140 (e.g. voxels with values less than 20 will appear black, voxels greater than 140 will be white, and intermediate values will be linearly scaled for this range). Finally, the 'X' command adjusts the adjusts the proportions of the sagittal, coronal and axial panels so that each of these views will be shown at a similar scale.
This next example shows how you can load an overlay on top of another image:
  start mricron .\templates\ch2.nii.gz -c -0 -l 20 -h 140 -o .\templates\ch2bet.nii.gz -c -1 10 -h 130
Note how this script uses some parameters multiple times - the first set of -c-l-h parameters refer to the background image (ch2), while the second set refer to the overlay image (ch2bet). The parameters that can be adjusted for each image are noted with an asterix in the table below (-c, -l, -h, -z).

Here is a complete list of the parameters you can specify

Parameter Notes  
-b <%> Sets transparency of overlays on background. Supported values are -1,0,20,40,50,60,80,100. A value of -1 signifies additive color blending.  
-c <LUT name> Specify color lookup table. "-c bone" will load bone.lut. You can also specify the index number of the LUT by using the prefix "-". For example, "-c -1" will load the red color scheme, while "-c -0" will load the grayscale color scheme. *
-d Defaults will be saved when the user quits.  
-f Loads image 'flat': the NIfTI orientation matrix is ignored. This is the same effect as editing the .ini file and setting 'Reslice=0'
-h Sets maximum value for image intensity scaling. For example a Z-score statistical map loaded with "-l 1.96 -h 4" will show values near 1.96 as maximal dark and values near 4 as maximal bright. See also -l and -z *
-l Sets minimum value for image intensity scaling. see -h *
-m Will show a multi-slice view using default multislice settings.  
-m <INI name> Will show a multi-slice view using the settings for the file <INI name>. For example "-m c:\mymulti.ini". Multislice settings files can be created by selecting File/SaveSettings in the multislice window.  
-o <overlay name> Will load overlay <overlay name>. For example "-o c:\statmap.hdr".  
-r Will show a rendering using default rendering settings.  
-r <INI name> Will show a rendering using the settings for the file <INI name>. For example "-r c:\myrender.ini". Rendering settings files can be created by selecting File/SaveSettings in the render window.  
-s <v> Settings smoothing. <v> should be a value 0..3. If <v> is odd (1 or 3) then bilinear smoothing is applied to images (otherwise, nearest neighbor is used). If <v> is 2 or 3 then overlays will be scaled using trilinear interpolation (otherwise, nearest neighbor is used).  
-t <%> Sets transparency of overlays with respect to other overlays. Supported values are -1,0,20,40,50,60,80,100. A value of -1 signifies additive color blending.  
-v <drawing name> Will load volume of interest <drawing name>. For example "-o c:\lesion.voi".  
-x Main window will be maximized to fill entire screen. The size of each view (sagittal, coronal and axial) will be proportionally scaled.  
-z Image color scaling will be from zero. For example a Z-score statistical map loaded with "-l 1.96 -h 4 -z" will hide values below 1.96, but will show values near 1.96 as a medium intensity and values near 4 as maximal bright. See also -h *

Default Settings

You can adjust many of MRIcron's settings by choosing Help/Preferences. A window will appear that allows you to edit many of the values from your mricron.ini file. The window is shown below, and the mricron.ini settings are described in the table below.

overlay panel

MRIcron remembers users preferences. Three standard .INI format text files are automatically generated: mricron.ini, \render\default.ini, and \multislice\default.ini. The file mricron.ini saves general settings, while the other files store values specific to the rendering and multislice views respectively. The user can save custom multislice and rendering settings by opening up the render (or multislice view) and creating their desired settings and then choosing File\SaveSettings. Deleting the ini files will return the software to its factory settings.

The mricron.ini file has a few values that can not be adjusted from the program, but can be changed by editing the file with a text editor. Here is a complete list of the parameters you can specify

ParameterNotes
file0...file5=Stores the five most recently viewed images. These will appear in the File/OpenRecent submenu.
reslice=If 1, image will be spatially oriented using the NIfTI transforms, similar to SPM5. If 0, images will be shown as saved to disk (like SPM2 and FSLview). Reslice=1 requires more memory, but hopefully avoids left-right confusions.
ShowDraw=If 1, the 'Draw' menu and drawing tools will be visible.
Smooth=If 1, resliced images will use the slow but relatively precise trilinear interpolation
XBar=If 1, cross-hairs will mark the currently selected voxel.
OverlaySmooth=If 1, overlays will be scaled to background image using smooth trilinear interpolation. If 0, overlays will use nearest neighbor (and the edges may appear jagged).
LRMirror=If 1, images with NIfTI orientation parameters will appear in radiological convention (with left on the right). If 0, images will be in neurological convention (with left on the left).
Yoke=If 1, images in multiple instances of MRIcron will show the same location - changing the selected voxel in one instance will cahange the view in other instances.
MaxDim=If an image is larger than this value in any dimension, the image will be rescaled so that this is the largest dimension. This minimizes memory consumption. For example, if this is set to 256 and you open an image with 512x512x300 voxels, it will be displayed as 256x256x150voxels.
Zoom=Default image scaling. Zero specifies that the image is strecthed to fit the window, 1 for best integer fit to window (e.g. if a 235% scaling is possible, the image will be scaled 200%), 2 for 100%, 3 for 200%, etc.
LUT=Selected color scheme. E.G. if 24, then the 24th color scheme is used.
XBarGap=Empty gap between crosshairs. If 7, then 7 pixels separate crosshairs.
XBarThick=Width of crosshairs.
XBarClr=Color of crosshairs. This is a 24-bit value, with top 8 bytes representing blue, middle 8 representing blue and least significant 8 representing red. So a value of 255 would be a bright, pure red.
VOIClr=Color of volume of interest drawing. Same values as XBarClr.
BGTransPct=Transparency of overlays on background (in percent). 0 for opaque overlays, 50 for a translucent overlay (50% each) and 100 for a completely transparent overlay. -1 specificies additive combination.
OverlayTransPct=Transparency of overlays relative to each other. Same values as BGTransPct
MaxThreads=Maximum number of CPU cores used for rendering. If set to 5, only five cores will be used regardless of the number of CPUs. Higher numbers lead to faster rendering, but can slow other applications. For systems with more than two cores, a good value is the number of cores minus one. For example, with a quad-CPU machine, set this to 3. If you have fewer CPUs than MaxThreads, MRIcron will use all of your available CPUs (e.g. threads will equal the number of CPUs), offering optimal speed.
SigDigits=Number of digits shown after decimal place. Influences the voxel intensity value shown in the bottom-left status label.
TabletPressure=Only used when using a Tablet device (e.g. Wacom tablet or a Tablet PC which pressure sensitive stylus). Threshold for transitioning between a thin (1 voxel) and thick (3 voxel) pen - if pen pressure is double this threshold, a five pixel line will be drawn.. Tablet stylus pressure will range from 0..100. If set to 100, the pen will always draw a thin line, regardless of pressure. If set to 30, light pressure (<30%) will create a thin line, medium pressure (30..60%) will lead to a 3-voxel line and heavy pressure (>60%) will causes a very thick line (5 pixels wide).
TabletErasePressure=Pressure threshold for stylus eraser on Tablet systems. Same comments as TabletPressure.
LesionSmooth=Smoothing Full Width Half Maximum (in mm) This is used by the Draw Menu's "Create SPM5 mask" function.

logo
mricron-0.20140804.1~dfsg.1.orig/html/images/0000755000175000017500000000000012360760644016421 5ustar mihmihmricron-0.20140804.1~dfsg.1.orig/html/images/space.gif0000755000175000017500000001515010630062372020177 0ustar mihmihGIF89alDBD$"$dbdTRT424trt LJL,*,ljl\Z\<:<|z|DFD$&$dfdTVT464tvt  LNL,.,lnl\^\<><|~|m||@F` HN1o0 t0 a%l file~ WD~0A~P*A~PA~սAE~` | N|l J| PlNlEA~+|h||p|`|m)I||JIN|4Hd|l4dXL|W|w0O|l|4d|PN4d||8dN|84dd||N0̜u0G!,lH*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳ!@*"ϣH) "ӧJj hկIlKXebvpk.Ϲ]{+0L† q[&1$-cbk ktԱSoԬ+knMڸ}/i.O36W K|zirh Bٯ;yj _/ιa`(}~IF`.hW 8V2Da$Mx [ aUE#BxW+bacI!AVV혢Fuc  $UKNSVF)YNa &MbI [AM%fti'Ӝwޙ]?n=_VE"6B5, /LRjz%DzP ,XjCi~*ӪjA/`C[` +차*ӯ&l"BVkخxwe{ӶtmM;nAde5 .4o2݋/L- J[(I #= qHc[]1GW} E"7[D* sC2Z ݌3B:O G?#Z?=q28C 0SSb= sm=5]mÍFn[ww,!]o~".2nANRnbޫq穂^螒鸡F|z)>G:{ӸhS@WVYc۔B[)Ud'L*'^~4 {_1EV#sBO0, t=\[Yg lIvNQ%z,Xi_V XŅI,AE y\Yu!I' N DH%tD,9T l ZE+rcDpH3cbG1PрVHPl%<1%H<`+e"9ɟT$$T6 0,A8I0$d f0DqxUYI.wy$Pee-sK]&bٮ`d m9M J YԤ7iT`7!*0tƝTN˲$ZqBzJӗ :Eb2n#AV5&X*WbF1!$BjՄٔ"YݪS^`oBfv)PQ׾e B D6wU פ 8)KvY U>ͬK8埌bH!Zu%g2Ġ +CP `m7ۅַ FHM.nKBV-2AV؂=0A [nWŅQx!r$`x D@=HnG8`/~˱],`|R9Tp]MŰ@4a@ V J)d@ hj`, {771xW7c?^3{3i@1|3߹?UOw>W@ *6À(Ο޻!F|f)@ %|uh({CC\0 @AЀ(;|7ps `"0tb$8;&*7,8 j1}3(Y~%0 Ӄ?~3E3@4aĄF)$ P/ߦ?W[؅ra8SZȅb|6  / x}7xA># bG@h7BY!脹sxrtJPd(PxhYȋrhQ Y(h-:t؍ר.&zXPzHY.` X I*@&02#$F;Y "y%f?BVt//P H yB;i64AY. @ /71N RS\W9rW)YA%,3 v|Ö7r#uYv8n |99)(7W0/PI3B9+SxRi'0` `i^yu' p^8sy) 9y#}HYR}męn# }Y-ʙV0ϩ 39<W#ۂY>Y>)0#S癞|Ǟ% 2Py#'ɌRYq-ㄞ/Qf "=61*P(E(H*,Z-#*%:wCY rf00#l Jlh-JDZr Pt?W؆Zz5mR)?੠*BBj1P(bbiWIq,P'*o Y'źȪ;*AX}z3 C**܊p*JrʺڧuQ{Z #)z7 2;)[趰BҰQ+0 q!XCF*豵C!$t)j a ,+j ":k=F CE!GI[h,kNP[P!pP"wVvɷ_gWkcfi{k[km  @a_)r47: ZKcw{$ !Q [J Yk ˳+Rs,к˴)U`X b #-` ͫe{{NW0+ +q黾g[qc Tbۿ0 ,`؋z\HKb? Uq9By!& +.X& k 1,38`:ܸ==$k, p`HL] oحݒd43YMI3A}Ѹ&@/y Poֽy~9q []n/LMn[x2#`<qyJ}!Xd3D35~< J=1 ,En4n㞔⦼[q0 SU>g)p# D 1> km/q }=K"@R^~/$dZ)1r,Qn{&.7. A~΋oD~ 1Z^;~'!)Pd>D~>d>־(nF8.IZ?3(1뭾"?>n)>A/BD52l$oBo &*7Ta,!.O0Z!'=M4_6Oݮ8!/A#L@*8ZNQ=Uo?")!Fqb&A&_.m_o@. Q&u P&A  2@da(>.?&k$vU__tO$[{%`WO~/'aov bS/r-9ϥu~)+Q-jџNb , ON(9n@ BPB >Q"-LĘQƉ. N PG%1VpJQS&$U9„=YTSĂ$N(`ƛ9\U"PUKuℬ)ZJX>Sp eZt+GclڵmW` U u٭☌J6if5wzgѥM%}Z5ԫ]le-vn޸wwpGxr摗7Oҩ_k{n۽]#OtJBE PD jQRGSTt$qTR4@TTSOE5UUWeUW_5VYgV[o5W]w/ ;mricron-0.20140804.1~dfsg.1.orig/html/images/main.jpg0000755000175000017500000013537610431155546020065 0ustar mihmihJFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((v" c !1AU"QV6Saqs#247tu358BTr$RCbc%'DEWdD !1AQ"2Raqr#4s5S$BbTc ?mjJ٪EgĴQ[Vssss{HǿV)aVΙ FT JRaD{h04@oZ-X 8;*ɯ>Uܲ]NSt%:EwQ9vCN'n+J''''z*k/,=y@ιT5wx#8.[9˷Jb\W;0q °p?%R<fp#q[@6n _rO8:+O }3-y8C9O?w /gLk~bEr#[YzRI<7ZoiRX:PQe^b4U @PtVf4A{> ; $2;eB{8<0sv޺>  MNoΥ PT1l%&iڿKk|36ViԆ+*cT#E!J!Tފ7rfv#Nrfm3깼-u,)\ O*NY?P7udͅBSQ.w}׼St ᒒ8W65gl9ib][[$EJߓc*Rp&VT͜mroG0,vA!m![R50rxHl{jή% -SEAĥդ!E;$%GyHR+C:ll6lzr% %r@RTPsy)V㔃@J(z$[Gwז[T%d>'9 qeKjxTHD]qR7BԜN٭Qgu$fqIy2T1BRxsށm~hJo-2R+6TSb.ٶM"me<˓v+W*7TkC.+6,D )rX't->%C.~ۥב+y-n3MQVʳ D]޴lBrژF7ɗwp7F8`x+KShA'fBb%עIK岗BFJS 53\@r-G}OD{[y/EmU d %E_)lINқ@p78Xz! -mXum$!@ͨ:%;Jm>[UХ71E/)lINқ@t)MQKJm>[S:%] SsRқ@)lIWB:%;Jm>[UХ71E/)lINқ@t)MQKJm>[S:%] SsRқ@)lIWB:%;Jm>[UХ71E/)lINқ@t)MQKJm>[S:%] SsRқ@)lIWB:%;Jm>[UХ71E/)lINқ@t)MQKJm>[S:%] SsRқ@)lIWB:%;Jm>[UХ71E/)lINқ@t)MQKJm>[S:%] SsRқ@)lIWB:%;Jm>[UХ71E/)lINқ@t)MQKJm>[S:%] SsRқ@)lIWB:%;Jm>[UХ71E/)lINқ@t)MQm E'+,ҕmB:9!;$f\gjj9fkF@mZJ;4! Jnp;K%λ.B0(NIdIរMi ۦHC.d' JnW(1m (̏V'+۠}>si]gi>o?U%ӿO7-YW1`\[)C**1FQKs3I'BkX\"%R-ߌs ,nљQ@B* AE'-i % $ss$:JX4qqɍȍ%8J}[;=xgpS]$phhqܕ a]-@6Ե|)w`aDnq9:<]qC .%+g`dBBw)WSRk& $ r.֐Ie yRAlq)V8u L{ͺ|)nL2%r8T"P^^L}FNR,TChj/!65)ſnCҐ҄46@ |{,\-FےP}YZw[y穥)`>9_fκKnf+&/"R(J$+ +P+R\C;N8ݹ916 SOqGyǿO -o]n:qi܇vJ׼7R)`My2kd8T"&u4!Ki0!9s[Fk,^OdQq\72%'R~͡Xw |+NXh f;&)B9ʶt剒+/ljS䇟 h!ę IQv=q^;.PxpWW)3yNəs8&M)K뽞D4<w{y i܍ե*<0x[*T#g޾feV9%%]PaD\tC73v3\ vlN)R)2RP $'sDŽ•6Z¯20uke5nZG&(;//)2ӂx:WIq"ZSaS*N%"T<2PSJaˎ:Д)QNsZ,]8Q[n-JV3 հtҷ{a¹paPR)( y73B+)Jm#ö-EJ*(t௞]~u@1^Ȕ) _8_\*5\N{dj e"뷦,j#KHI'oI\lk z{+u+2N Hp3=8{j[$B(R `9N47-9 9)ޝYh+i)Vo,$rx<RY"͎4OFp.#Ƣz?Q_])-ۀgZG m\'mqTJɥnUA”]O)[\Z٥;@'u R򢢣 F򪺒KӤ*pӂw|ߘ Z%,%gM`nlh[.atTuc/ii mťI@XBG7u6)f!l7zR3Ӝ@3nt3RڕP"xeBA))I =tu_ \GTI79%)(qe*# ZNV㐋Qd\(HI<3R}%[&$mKǏ5"R ˺QEhYP6/|a$8(9^‰Zdc8HJ9UpӱK(iRHKPdp 1K \=w\TVd5mB\HvdR’| G1$ȕjNjXDe՘ OHN f@lXLK@J\lCw fԬFuIga$po4þ9'#$C%/۴קXXBb2nt 8G*4U,:@lrgU(ܧ4L=. Ff%VR wFS#KUd+KPӳeiǮ7kOh\Qyr46&+d*4rrJڛi\Q* v9ױoh;>"wn-\IJT '__򆹶ҤʁuE)aiۼR)=+ )w[?mLn:t]L$-iN B!A)yR_hZ)JHI/73¥G]D\RԹp=K1JT'#Tb9X6w$ g.XsT0rG _c%ًJ^Dw)ww hS%’ܘ$4!MHאG|g!7MRRޘnJX@kr0w2$+x~u:L6bDJFV✓đt c{pOƫ q:tƎ]-7*)IF|W5Զrkn 9*(C/[Ce֊JTSVwUpEI=#]Tf%Kfem 4TORe*# >_mH԰! ,n% *@Xrl棩7.L2h}R(ⴥT .&!~Jmd:%#9%$97d 63SysOIq'<* Jԧ!@7^[ʒHKJ}=֓lda" im:/%^1ks (7{(.l4ǕlR$$pNNxnɶNrܻt%s;0q C~J#gwYzBcuos!y 20 J7ӺTGYܳ”$4Oʐ_q 7x, 'Q{n#Tp=Kݤ:G r>{Q@R(rcWζ@\k[?|vc?}#L9"`|/Fi\&$;@?~JγںۢJR֔OzB0H@ƴ4`UžLYεCh/?iMk{-L,%)$&7[gOTYі{CVtA>dZ*BԒRABH)+8TBOtzBmME-!%([O) H8^|injU*pqI#z]I^֧lN6ѹHc{# 52"Đ bV2 1>4b"DBG"r RF8`eG 85iϛno8~^g`L7ڣ6O/mz?d\%૗4t3]̓nQ\{uXN*YjZ䐦-:} 5t5{ی@[R%8R{(zx@Ym*s ?馎d7.wpk6+nTx]S9V8IH}6[εdO H֙\!?Uۃaԍr\qpτWilj p^l%_i=O?Ub:ԣ3YrGjuRQkRw.rKl[5v{.۞J'˥IVw<XrTj}N(KKXjl;WZ#3\ԯ{Ns|W>;j|4%/>h;ݶ׭'>)JRq:wUږmZOnR_*} JJBV:NrxOEU%(%j"`''/oϴu Wgfχw94Wq%rcnn\\$O:èLKҤZoLmOdžKuRpx>xstTW_h@p}ϟxڤ2sIqҠB<'8]?ylYsm_]FҊSj߂7R11&~)&o9v#JB IP@$q<:?W=Fv.:M¹b2) RBK V@Js p[ e ৯mX5R[ t^{ռb9W׶,~䩎j N!,}(mx2'''$z>AKN[ 1ȲB樿 RU-?Km"8\j#ieDn!9;:T[ t^{S&iQԶk4-uee¶oxmX5R[ t^{&"߅_S׶,~Wt^{Ӻ/Vu=j|b9rFeyU.8nBFI>_, DX!(i)R РGAY{oWX|ޖz>AKNcmf)*PZB+^]!mS-+.P cxtU[ t^{S&u}{o)~?MT/Vu=iz>1~?MPiYquUջ) ''GV>[ }Q:o6naJᇽ-_9䚄zA]!3aȑKd7% ?%*AZ8"LFB-ǮkYo%PRx3Wfzc2m"9wzmF&,L)&#׻r|⧯wUߺ/Vu=izk&9>zS׻r|zս]azZmbjEnE}{ r>Vno(QAKN[ 1e5}?9McOUߺ/Vu=iz,I(q(-d0w[$skuUA} W[ t^{҅uUA} ;'ZuT!7j]6#VesXo(BJʺ9PmB饵$fe&am,=4sd0(,Q'4u֝UM4iP|CU/y4sKA(Y`'ZuT!7.۟m*C2=, sKA;{\~SDYdW۳2biKTJ qz80jVe.UHj(2WQlpd+ F~~?QjzW=k^Q)K*YIʸ|<˥p>G2$' hCn, LmÔ? $zI&6sTE_esKAwͥˁAUn\5m_eT[^`yz'eGsKA;{\~\)z'eש?.^k.?ok_i<S[^`yú<:XؤMa*Kr`Iq!X# (5T{\~N?tyҘzɧK=56EN.\1oMU?tyӷ/y4,'k'vxhCR31E Dg.֝UM5_;{\~] N+gu\e&3LgCσ#FiB΃:Ӫ :kjݽj>#@S^ڜeҢ8Hp xj{oWX|ޖ,}:i:Ӫ t^{Ӻ/Vu=iB:Ӫ :jwEޮ-;oWX|ޖ,sokzb _4ijRR149>]^Q-Ymn8)K% -{# zս]azZPlgF Bf*V%!TxR*V'<9lt֝UM5_;oWX|ޖz>AKSDY`'ZuT!7,6lY9iES+,@h88CoDC)XPCMUoWX|ޖz>AK]a&5Pm/Y '԰I0L== cCkVśsTU?;²3ǔ<1z>AKN[ \,dN&vN>Boz+ ec%}_~2ɚ+)_K]:kMo^dNAZ" FCND Azս]azZ6[i?Vˏ%4 3U2kY>juБe)%/99aXì/0rU°bxsZ27=˓kwWԌiLV}X`V}Xu@{0D Ru()JJRR/}~'}~'ǡ,=?Gʩ5mWm#TGbXJRR()JJRRR >J R >^~gוz^1K"]sbU?'^3GQeq )JViqJRR()JJRg(=Y~]OLEC=P>ޓjs*Rb)JJRR()JJWma s)J=>jϑH珬bb)JJRRat/ sJUat/ sJ;&k+Tr{HjƲUG*P()JJRR()JJRV}X`V}Xmk={9Oˏ)XQJRR()Jm'-~qJm'-~qJz/ ٜVy?UIz)JU()JJVD(R&[ҜP8¡lzhZw/ĝ{Uk ũv܎Vtn[ W }uM(A;wyZ|GP?y s8Ii^!!㻊Jrr8{2%yVp()JJRR( A߁K垨nۇIP{)9\_p6g2)V R()J^2!S(@'Kv!+uT2G?v]24؎%RB%+W(;4SXC[9E5M&IAUpk a zrO m,\K ?¶mH5]JqEs4vdT id\_n*U6%pDH9 ީG<ߴ6EenQ Ҙ `+Y'u`#!a9)$qWm۬S7Xƌ7܄yG+D$n/&27r@34T4N_J_-,{a)9JZ.)JP R v?kUz v?kT0qݤ}5OY_*#GT59R)@)JP R)@)JP Rr+r+o}Y߉~\])J:R)@)JPi>o?Si>o?UcЖB=V̭ mKi"|sϏʪ'>P$dUM쇽5Xn_qKŲ~-'>vs0k˲g?HӲg?H׫2|%>szs0i}.{ݜ#N{ݜ#M'>vs0k˲g?HM6g]bC$5Yఋ^_z4lM%״Ƈm*e;N MnYP'!J?q[a(v3#[%¼R+Qvg-Yc; x4ӟi_5ջ6hz`4Ni?)y~>󞃂7v_&ڀN> [cKxlS̗YZpIQI\xZei-X+FHT8Zq7Nk GC8A術}(wUf\*-];^Js%[\&&5֗wN2'5XyqC, ]fv&mRV4*JvjZsZHe%*n&2rޝ>mA.̂_Rqخҵ͞iżagt.$/JEzS kY6+k[9mV eO>sUř1f)mΏR{@q3X='>g/rUVi{ȌGU|UbS-y0@ R~zof_|s0i}.{ݜ#N{ݜ#M'>vs0k˲g?HӲg?H2|#=`I?'>쇽4쇽4̿zA}`I?!vs;!vs7o3/އ>sY<ښ*>(BrnߚqzE C i6RRyJ%D—Ĝ۹\or^gZ-/tni6~ cUN^^W.0w4w5}gO򏢴vpo?/݇sA{i{k׳GNϓE6po?/݇>syv;v;>QTg+7ACu>zl~_|c*Dx(TiOkٞD ھީ{ʒ+1'" x8+TQ(Zt^RjxvAy0uaAH&V>fx) .'Tճm=pa I;Z)5|xѣ \Nx?\i.h893Lu0[]MU..ڋ3ZϬ7w^@q+HB+aCu R.~L-ʐ꒤Ax %{G.O}>QT~_˱?Dӱ?DׯgO򏢝'?>l~_|w5`:TRD8ogO򏢻qN6@s'WYeܯ)W>/8>Qʑ#yUXR()JJRR()[!b ظwxc@kk>,?|°+>,?|¶w5=`RC)@)JP R|6?86?8V= dy?UImlag*=* R-RT]'MٛBJG*9[:VŃ Y8#p6:^37;}ouIqiJ89n+1?i$5z-6J(]JΏӳ5^j Hi쇔@2I|5IF=OZ,2ϙQSN$|Re),FA}JoO0l,;Җ<)!e.Gs[zv J$³[#Hof+hZxc#h~}(}[Uc )~^%U_ tx8'o֗Z ݽ+E\x*?;7No )`W*st9RP)q@XAtpPRUP}-M}>2mw-4~*^Ol  jҫӣW~rF]HiL J{#TSJ-@wRJ6+cxoH!]#!ܿ7d8\e)GIqEyIRmEvLܝFaZ]9X -4<8gnǦ佨{&BjSkR'%֚-Am qsPm=hn]O+%' Ko]uץ '4j:q)\vQpF?n{%c>d6ART0AkKSɐ)8Uݞ?~ y +8+:kg; {EQʑ#yU@R()JJVs֋05؏""Ҟ\e8<$]Ml- .;-Cy[) V`Q7Gq[CUoT[xRPZ.,.\ԕD'瞿5^m]9JSAX] JC#Q %/ fBoSI3ӨGG[P#8sln(RQ0c&$um8J)P5fʷ  җmo[df.SlCR`1;\w5c7Y@b=-E  [ߚw5=pRu()JJRR/}~'}~'ǡ,=?Gʩ5mWm#TGbXY[d͈PqםV[8 |]`N։j"wPe+ KdeP$;z1xU][&!q٬)KiPJ\J"A?mz& hNVwucV?x Xvۯ]ʹF2qqߗ>]4v6imAh I51\ 2B]{xu;٬\ED Yl!8~_RVi$v9$8̈́$ vA,Yw]+0k O/tuW>]͆ȘOoZvIm`n<"[u5~~{ ޞc_.!*y: y#XϚXNiĆ^u( O^G?-y4O@{sm8UeU# u?\U^1K"]?'t%q+\jʏ1?9SS0W{r\~B.?maMpɶnJ!|XVӄ+lu4Ylow59)0រ7cGE!"t{-yXom6tr՜p&zΎTU))##L"#”I&d mDJ*0*HHtUUduɮ6RG%U&RA<JRR-~/+z}n&S?ArTu|mڪ%ʔX^rK#$io>gc@t !y [iNPG+Z5 Hۍsrt .[ $Ԏkp 6]q tPRBJʑ-w*MJ$KbJ1Ē+NG(׺~zm.i.r3Y%4_*' /%hPRr(> 5‘iXHjx7YWaJ%H8ڕdl-DCUeVIHp7]\ [`rV"Ӥ)iH^Q-6E*Zs0U+՚Ue +N98j)0֔')JVB0?{ĪVB0?{Ĩ`HjƲUG*G&k+TrJRR( 檃ĩL xbvkC[86?jP枧{S^f\XB9 zwUw@yu}@%H)W@E6 mDm+km* 2'?ƺ~-Kn'PUgŽ5{zuOB5U0AKmKl+# m64IK8SB\h:;vNRB:hm KMNej]:<9*I '[ &U$7+ADnFw}񞑚Jꍣ6J=I8z~R +K#=ko}Y߉~\]oRn<0y'qCYT$XrͲRFB'I٬ZD RyLZkr*W3@)JP R|6?86?8V= dy?UT1J[$n)i nIm3X @p|,R"(<5!ӚBk;kidj <ě. m 4FFH\PK:Nݮm6ee2Gmj UsO'5GPVynt]W|\Q̥9;+h4I#&}-A@Kk#rU `6{RҗHs@mބv}G+VTsh*R6NHHI<~)U}#%ўGGWAx(W+DF- }>=p#ZMzxG/y/QqqY[<,9^N$ws4)%2p:}Trmz!G#?+]fd wVXRd̖Z|bw=;@w]]ꋷP^};=:PSNep?oa%N8V{BXZZ؋ o(*Q7W OHhpI#J]lm,DWz|//zG<}e2Ұ5򴄤+TQCxxy:U<  `ݭ,KeEXOm;F<^exMb0)q _NA+?c<x*D[b!8U m(7 `zsPʔ v?kUz v?kT0qݤ}5OY_*0#p59[+ U^G(mCNQRG9+?~oS~oUqؿ̏ `R(9(?qؿxU:yD-qK8Iy(u ](6}3Y:??5?qؿxUìlpa!o#m #q}!JZUVc:kRV(t%Ԃ?o6]u. 4?b1Ws ւаncPCsƻƁ+NK! ԧTxJ AkL%/)ˁ+=8A6FSɧ,SD+RA1~d32%kr ŞMg;<¸&bj1+S{ kiemzvn2'Ӛ:Hj-8ZJARA5sv/G<w?YvGFED`tqųUvM 2G ==k wO:̞P ?qؿxUh-4,1*\qi %Ys~ZVw7qtt9Q #|xtd^u-ukdTW'b:)k<d-gÊZO H2EwTԹ4оHpXLm}j~h=&LhmԸYҲ7TIjKlMI#xDTdvR ²@ߒZ_RjhVDkȌUhhx6|mF/F3,t5qɃU(UFDnZ~;pC1 H[`q]GVZo.Z˒l-)q$ cg ?+|WQG<|kh/MŒ V%%W9;#>w?gP=JrP=J~r?+?~oS~oSDž]/}~'}~'(;2 lag*89#glag*9(1JRG>-=ĦK 垐3V>uG& D&&aPܲTG^v[OW;uJbJV8nRq; ]uJjHIwuzTx|^ks4Զd:*Pmx/32@q |5ږ619ۈyYRTy9)JVB0?{ĪVB0?{Ĩ`HjƲUG*WmXoqpFG1QJӼxa*"Х)^rE)JV|tӱ߸5E|U8LB7q[\q¯>ʬic1e*xq@| KrTVڔ Jy{]Jm$)C5gu67* -3YjݐVM*@D&37˛;%”в^t{Frj3\nM%rU+$JO=6{ rUlfZº_dғތ`tWF%lbB:Y&:y\㦠z(yRom/)5umA}HiFvyۼ̕=o<~#EorMù5[Jy)D]GJ퐟 ˳o9oTxHɸ]YLw$yAR*PwE]ٱD[Oh_K7wֆ VU,}ֹŵ( 舒l"

8?~sVCCuo~ϑH珬g̹a1m*ׄn+I%[j{7JBc#V_ XCmTbX.96|uune 9 Z}_csaCqWzEdj}6F9{[mHMq-L֖kR<95u;ˁ!PT\_Dj[$2 ('8#(X] ñ\X] ñ\뒞ڹ*RSpTp3*1$+i|q+&HjƲUG+d% nA]uإ)^”6_ZG=V&-KKxV0H뢣BMbg@Kà/.V9nAƉt+I'멖-t޴% t"Ƽ cYH)e k]cFZ\mą$^WPt6s@5Dx*1ʅal2688uX“y=5v^$b)W6jmF-։?rqVX_Ř#IP1sk `8< h doL[R@GP[-MWiWӬI\{%-pΔҌ[_  \cjv));^]Oz.//Y&$#w=mk={9Oˏ배;n2#$VGX)YZUr`墜#߭-i#9WXS#[[ TpNy@]r~?UΗESWt]Zi8-̬8;Do9"bT()JJRIyRIyR lag*ն^{A~03RiRbw<7e+P[., خ嫮<ܶCR %BgFn6Q$,@ueuHxZ[O9h ߭2`)JPJ&B=-ۑ^9qjv-{n6p O#ۮͳm@ UFl6׌N[Xjy/-v!x|Wڀm SdzE{֣8c6Ft6Ԙi7T^kЕ}O}?,H N4d[gJG^n_02qH#a%Ɩ( +OQm- T!DgY3R>Z?֩knÐwI*/O+@;j)ts5-dy KeVYʴۉqV+L/sޔԖϬ-%)#$sT"#(f#E$lwk:n*&8͝^eG[EHqzZ'*DW8N.oB;m,)+u<QW&5V83j;>c}sO#2,."Re!@pYpk 3\GAC؜P$h:2eϰxqƳK5觛¶{> MrTiF"piuڲDdjQg˒1ѻ\x{/(,(f#mQCJfzNR}ITH4xz-)x|5Ȏ8gjy;iX9ffN=%6^ Ғ:*+.baD#us9Fftˑ s@i5{7#|fzh+Uz٪69(;Ԥ J>\jXn|~U KS*:'XVR-sKJi3^^\{`t5VN5e>Q^^@vP5DSmk}p Q=\SNbG[o?\+y$p1eJ\Y":+'\oy|)?dS^Fo([4N{JY2 -xx MHKe`d:5OmXV&Q*w;nmXYs*<KfNyOHpJQ1)JP R|6?86?8V= dy?UImlag*=* ȷT@[%OA'_l]C(()*c@Z} -1jI>—"*1PS{6oB'x(歮F Lҷ\NRhcr}qp$}ĒWб'ߤKU!qV[zRCqO<L>C9D#+);YW9Tq"51PӦ%H[-HppyO@E`s@D&YeƷF`){8[m[AVQ ̱%k%;@UOzmR~[n(7^6HBǞtV"RPe+C}uG?^{O+$~odQZ9zxG/y/Q qMt5?hnZp~jHvmj5#[KQ .ndj{×nZq-ΥIJJRR()JiRhrgۺ6mu=3 _W,@wW?zMY̩JU,ٍVQŷ-$֦֕E*I#Kp溴k%[!#&΂S!J(@xfj}Xmc{(NEqގT8Z0PFA=5.XvuHmI<Mfm}# A^u.0Hptf;=ջNsS-}wvgr[=@/B-pP B3Ɋ@t' 5mWx'suR]]jf4Dp$+xwsρk\p gq? =tAubgCpڛE=j5S=7rfi҄69>~.1ǃːET]&;(8ٵ9oZ.d`?Z).ɃYOF=in!i! ̒z8h^4ICuplЌ:qGarMXY2IP9)_k})jRح3i~{9/Y>a]9);ӪQ@&P4!1l,x*s yts.nJH¹nѦ;J _" u`ߠ6R3qI !(تqqq\$ꔟjKS-Ro>N8 R.a~U.a~Pv?eTi|MSWʨJ)@+sP)I?9Vh +~"h3i/wqPH'*-ocODؙKL}E?pjing}3YwIƲې^ uQ³m\֣M4_5.]=eE TxQ=+HJT™pp&g˲QiNGZ|͚Ӡԇ0აkݏ$r-vi3hW&),Zзq:R@Sxq5Eɋn;Ho ?j덲sGf+"=𶚎ۻFV[j%DkiF|,rpT|Ҕ*)JP RO[O[X%_Ug9U& ٜH R)JPcw], DNIVN:OO=t{}ocK[‡Py<&h-79N̞!@L&\Uep¥vb4HO{3wXH%?kYGiCtǤ7O,dH^S7hJ*\Mj+@&/V9TJPHkB*C*D4)@)JP R)@Z 3 _W,@wW?zM߁K垨nۇITK9)JDYu)<]Z72JqRN5O+!q-e!G( i=CjRMp-(dA\SKW5+f=\Li ō)-VI8?_֤:sP/F\Ņ'Wlm*E*eą -J $t^Y[vZ|5@rqi7Ze+Fꗽ#>S4aD6 KK`Nj( ~H [(t}ؽgOGG7Yխ\ \Si ('75{Y^Ldv|} 4|>Y4p].6;Rt^D8Y[Xp~jːr I))(28:&y%Y,nThqp0R|78J2#Q. 6G֨NWvXTTRYu|\sYrn2TWK O#ܶڡhĖyF RƴDz, '=orx3Ǣ ijC6HÛj'5mPj3i~{9/Y*K.yǜDķ^iX II\%CqNGyHZyYl'n>ۅi1R.7N]uZp}QN_4(q,uA|Qǯw9)•V*Rspix|(>V>#`ҧW>Ijb:bȶz9TQˍ#XbeDؐw?5ѧd奩'5ap>{uQSiv.Vv*.ݦMn$ UE\"[źgQR OI8^8~3vaR'Km[b$D{d8$#Y^[[KY'5JF**OiGhN]O*?'VSΓy8}E_ΚKo]E]^\)ISmTiVIu˳餺U܋QTiVIu˳餺T܅Fk4X߼>ΚKo]EMQTiVIu˳餺T܅Fk4X߼>ΚKo]EMQTiVIu˳餺T܅:g(=Y~]WiȚKa%݋ۋ}AK;+9 ΣZۦ,zl˝]͗ڹ\%1\m))J BrO*-*w:i.yv};4X߼>r"JΚKo]ENM%7.Ϣ(4]餺Tt]c~*nBJΚKo]ENM%7.Ϣ(4]餺Tt]c~*nBJΚKo]ENM%7.Ϣ(4]餺Tt]c~*nBJΚKo]ENM%7.Ϣ( 4?V[4c-pn(Y{餺Uu(]ܤ yTiVIu˳餺UҭwsgSIu˳詹 **w:i.yv};4X߼>ҭwsgSIu˳詹 *X] ñ\=ΚKo]E_w9I_gd8b}AK;(+9 ΣKEqGT59R=}5OY_*d@)@)JP R)@)JP Rr+r+o}Y߉~\])J:R)@)JPi>o?Si>o?UcЖK,o zȝ~)&ꅅ)J)JP R)@)JP R)@)JP R)@)JP RR/Z}5/K{nnJU@)@)JP R)@)JP R)@)JP RiϿ om/[Z=CU}}5OY_*#GT59]AJRR()JJRR(g>ϘVg>ϘVه Ru()JJRR/}~'}~'ǡ,NY?X;dSMc RR()JJRR()JJRR()JJRR()J u_q\]?o~[`j_[]%݃ҔJRR()JJRR()JJRR()J\i|-~+4_ g߆| zЪHjƲUG*G&k+Tr")@)JP R)@)JP ϸ}0 ϸ}0 g~')qv+)JP R)@_ EO)MEO)UBY.~)& Tػ-InuL?mp9?FqXy_U((E=)QJ>7k;j{>7k;jR|nw|nwԤ E*/8ݬ7k;j{>7k;jR|nw|nwԤ E*/8ݬJ]:]+v~rP>NҚOn^JiKs:]+v~rP>NҚOn^JiKs:]+v~rP>NҚOn^JiKs:]+v~rP>NҚOn^JiKs:]+v~rP>NҚOn^JiKs:]+v~rP>NҚOn^JiKs:]+v~rP>NҚOn^JiKs:]+v~rP>NҚOn^JiKs:]+v~rP>NҚOn^JiKs:]+v~rP>NҚOn^JiKs:]+v~rP>NҚOn^JiKs:]+v~rP>NҚOn^JiKs:]sM}kiM'/%굑dZv! N} J)$AI RRGz(dZY9Xe}wdZ^қ@j==NEW)lINқ@j==7 *iMucJvP|?Q8ݬ[S:%Zaaq~Oaaq~MŠShA6-*{>7k;j{>7k;jnU~қ@)lIVqXy_SqXy_SpP|?iMucJÏZÏZ_:%;Jm>[U|nw|nw(6-+.fƵFJ,9(N~vVvV^lɆ5YOcOE\i_:%;Jm>[U|nw|nwZShA6-*{>7k;j{>7k;jnU~қ@)lIVqXy_SqXy_SpP|?iMucJÏZÏZ_:%;Jm>[U|nw|nw(O[╫siз.UNrx?mx<ÛS=TD[eC8R*$9um[hZv3_DPP! 9JHo"_ NJyuBzTq:MsUo^r1 ҷP-`T'0ە QRRA%I8)P @ PnTZ +a) :)T<{[mLfn/^kO/帠RJ Ȕn1ZѧhEc,!%DUW)Ʌq :-Pm2RB(a -%$4 R\{ӏK}r΁oĩPwD2D!*#V[VS1 d#P&" L'/\RZڔmRؖ;9ZQ;6mʇ%(do X@ց]eun6Q \wR$$$)SpT[Zs"jWdonr?-iW{t۳smUڭv#=(]ad0y1 UO`tXW|s#{2P<\ R;ސy5[h1rZ%EAE;BR0+H4ѹ͓yDvtnqlߍ ))$'xdeT5]J\d:@},JY(%ʬ(uuZP9EPORV sw 6=*|9(Z[/tu J8N<oͫU2|样bo-S@s9LOw1sc]Piy,:#a+R VԼ S * =5ۖVc{97yT'{3#QZcɸrkez\ *Hm8NtEJ1]C(re;%gQo G~{~gdɀ IPBTI &j;6)w3;L ['SkaD)$$y8xgu\oSY/m%0p&xr4m JÁ-72T*Jm\Ck+JU (HN|)P)JJRR()JJRR()JJRR()JJRR()JJRR()JJRR()JJRR{B\8)BG*#1*Pۺ'OOZm_ȧRMy<~Υ,>ۺ'OOZm_ȧRMy<~Υ,>ۺ'OOZm_ȧRMy<~Υ,>ۺ'OOZm_ȧRMy<~Υ,>ۺ'OOZm_ȧR$v#l̶pJo?UU[i-eĂ@dnjdTN,v2|~v2|~RP;r>U?E;r>U?E)M[`L*`L*-ܰzOONܰzOOJSjnX=S'ʧnX=S'ʧ) c,SS,SRڅۖT)ۖT)JmBdTdT6lv2|~v2|~RP;r>U?E;r>U?E)M[`L*`L*-ܰzOONܰzOOJSjnX=S'ʧnX=S'ʧ) c,SS,SRڅۖT)ۖT)JmBdTdT6lv2|~v2|~RP;r>U?E;r>U?E)M[`L*`L*-ܰzOONܰzOOJSjnX=S'ʧnX=S'ʧ) c,SS,SRڅۖT)ۖT)JmBdTdT6lv2|~v2|~RP;r>U?E;r>U?E)M[`L*`L*-ܰzOONܰzOOJSjnX=S'ʧnX=S'ʧ) c,SS,SRڅۖT)ۖT)JmBdTdT6lv2|~v2|~RP;r>U?E;r>U?E)M[`L*`L*-ܰzOO_l2 <@Z~46l- ;xEu~_JR/SZv!c^W4- )JBoNki/SZRz_ӷ^W4) ":EoNkiJR;xEu~_Nz_Ҕ,v":E)HX- ;xEu~_JRQv[=nu RIJRmricron-0.20140804.1~dfsg.1.orig/html/images/lazarus.gif0000755000175000017500000001405710422016422020564 0ustar mihmihGIF89a}9 !$)%)!!)!!)!))5FE#A'X"U,g&a1K5 W>d> a@o: oF mDoP%9&-:3S.DJQ_dK/fRH8TxFRqU_ofbn%D&W1Z9Z!Z)Z-^1c=^BZF^MdRkTmdicv -.<1J7D9J9J9Z)Z%c1Z1Z1c1c1c9Z9cBRBZ9kBgJcJkRcRk9cBcJZZkBTR\JRZc9k9kBkBkBsJkJkJsRsJsRkRsR{JsRsRxZk`oZxcsc{huk{k{Zkbs^{gk{du`k1U VzV7g-}jFzgV}sWbh$q1rKdw1u.Pwkkwguwostvvwc~yn{kym{{{s{{s{{su{s{s{:1QHdy_z8MϡJÜ^Ʃkٵglw~swsx{{ɕs{vǀɜ̡ؽƽενֵӺֽҽƭέν˷έޭ޹,}9 H*\ȰÇGŋ3jȱǏ CR$_(S\ɲ˗0cʜIɉծܩ'ϟ>*(ѣF"]tSɓ0E**իVbݪ+ׯ^Âդͧg]˶۷pʝK]8%o9[lAs+;LѡcJb8f1rdɖpǎ+(\yF+[Ɍ(O@sΜ:w̐QcƓ)bHRÑװahz-uǎ[<^ ?z@%SP"IaQ[#8f U|"K-La 7pC q`Ggr. !B]_(" ,wrNj/f'r*8|J+0rvp̑'|1=rW# H(A BADJ*(p'̸@.ph#7舀O68̦r,PC?. #,D0|Ev>2VxPT x  T@)` .,`=PC<^vXh> %?p*"X! 2vA `QA*5`/\A\@đ#4P P@0*@pv^B%di%P7|pCs  DŽ>9:tC 09}a[p60 |@@"ъ1~j !QoԀ :3n؀&/wjXk#0@0!X {ch=q? A 8/%n"pA( v |NHsX%`D4B\"*H@"N2/;(FPYd 0 Ѓ`%H @#X@  A nh "`p%0*~! t H@@Lh P "da rʰRC IŏD P$` pp](щm}+L|m0( Xɇ+`! eHʐ% MhV 07 OЃ0zu1`! Np 'b"[aQ4Ha(C`PEFD6{i&P,Q ]Lkbp A 2niN<CP`k0a7Y0JL1?# 0ƬRpApӱ  ` /@ RS0~G 2OrWn4G Q~QT@ kaT` pYav'Pv %P'I87{ر> `'  ʠ *." PU0Q.@`y` &j&T@fyRU| r0ef3 pHDIXX0= +p ̀0(u 3wYX˜V _b!w WG2yuzU#$`!g0Pop2 U { 'v*  . P ^Z)\dHM`Vu|p}"xr@`d$nb V0D UH80Uu '@$ U0{)P | P @ |P Spe @ FJ p :+-IWh%)fщy*Uy =r@[ZTpzP1p``W7M@ @ ` ^x ɰ` P Эj&!.`kos rttz@ƐWOe P OZ1Ơz "J Gp + P ` p iCu uƀsO #7W P Btn Q@  np`@,O|FjYʹ*P@ @[ ` P p ʰpbP>` wR8@ ڐ'00 , `bp1 8g+ +0> ! , b@7[NTW$ P0^ @ZD@ p PZ@%|@ ;%g+j*>0%| ;5jA˰SCI`TEY幙$TP1 1?3*XB$Ʉ w?p_z#[:P   d%v$-0@gC@ʳ$ j "Pp S' 7 2P 45uERpΌpR0 @ @ K.RZ`+:PWPV۰iLIx0 P` u<#p;u,"0C#ͣ3  < -pΈ 6K|kP[f#+,Wp S  PCP< #ʃcyCif!P7@D:7,֨iS`ӦΠ{ DZK%\R0dUn +BPǸ@ɠ0 # /;e=HV?- W&7bD<;m uΧ ѠWp% ) ΐ' o00ul6.` p =ܐU{6"X& ݓ-P ǀN)vaa>; @j; u (l zW 0 [t ̰ @!1) >0Vr0 N% =XP;Nr@ 8 쯅ߩ@Ӄp5}ۣw 2 zSy%p80V-rTE p:, @%#PTp!Zj!O~FY# ;W4?< HL bVo@Z'P'p,H$OY2쾾,ra' ,0\>$ Q-Pi=#`Z=VV@ Z?0 Lwm v ! vNX8U  FH6\XЖ~>fvtۉ?^*#߱=0 P1,Ww} + 6 {(QV7e~8 6_wi!a~w WjO:|WN]?p ?(=9p ? 㰞P9*Tgy%2Zj4\'2tSkiuRgS !@a!"A&A_?*̯)? Oڟܿaq?_;mricron-0.20140804.1~dfsg.1.orig/html/images/zhistogram.gif0000755000175000017500000001050010513265434021271 0ustar mihmihGIF89aoRQRuV R!,oI8ͻ`(dih~üp,tmx|pH,:Ej:ШtJZ7Juz04|zn|N~mdkK<gZfjyeXJh ǐJeϓgk3i/h 1n0m 4i&8P.Re-7pڹs9(2$t'٤,qJ+E Hmp:&aÝ(V705k>#\)#瑴NҭYu&+ẻ Vՠn܌bWFԖR R*X5!R*lja 86S•~$ւjhoa3 n@Q6g’omxᨶk[lY⺏kڛlF\SU?pzr7rM/pd?|͢fg\ @'n7Xy/M` yGw'}bhY[ `c0xQnvcGyS#fa'ESAb)5IA#~Ks(T!g`2YM<-SZXnwaf2 )s~BrN'g^柀j衈&j*j*餔jv]f*׉駠*"BꩨM꫰*+j뭸DV$Pl&lZByvNv`PBkgԎ-f+nkBRϊ.+V;ڻMn믧v {/t­6-C`2l+ 1g0Zc,ȥ: =20\2l3ެV@gLsD]F'4H/һD)TWmXg\w`-dP lp-2HYJf|߀7v7C8݈'7x_Wng~Ct标.yԟꬷhn{-{o<7<{>?vDt=_o/_xʋ<__ؿmQ4 x@5P#W%`2XA ! 7jpz&$! KP/a݀B,zP+"A[Ԡ_?}pdHEьkãظ7B.8/(5dqH9.hT ި8=&rulc# Aѐ$ZKnn'IHQ@xJz؋$+w˸YL\)YKN"L.2 f07M܍Ȗ]\f(M9JEB3v,&*glnlf )K1Q g3:>LE*P: _GGJϏb DIJ̖4*JKN"4hsL٘&4y|P[.̗^4U{҈U3EhWy֩tmOK}1 Zyתt'lԛ3~M;{_gM?>/A6vmy:s*?= Ы^vodGnm~]Õ ?bo.?:؞y?ޜ^y'>?}99;{j#6;M{k~;}y{6ZQP̷W~{G^죷8oY~,r{vwd.]Sz߼~\wxFe}guBw}z@}16e7}Ɨ| xeG]zuvfJW{(r7Tw((R*H~n灿0}7X'u'phz!X|#J(g~zHX/|?(H%ˇT{x>L؅"Xr=b}dhVxS}-؃ԄtDxs8)hc؁/1BX~gsyݧLj@($qexk3}\ȉ^n`XUoHdeHY8d|(~(yhޘYVvH˸ؐ4x8市 >؇ؑ)☀{8:yhr-/zviy؉FH)?K]%,'9I  s9(y ; }u䒇 a`c9VMȓƕ)X&4)yƗdupySIvɘhyy~Yqoyy:[ 3Y&W渋ɍh鐜Ji9.F!irw5Iǔ i]Iq.2E3~t`)iifޙL๘ yEwxi)yy׉5y4D䷖>ٖGzIY( C+v昅ÉdYIq7: <*>ʡ@J8:rYx"z^YNy[K*MJzQB jta馤' t/.D YUzvإz+Y,Z1zWZimo79cʤZp}mz |ʦ㦂Nrj-ڠڈXY4)YT,jSm숗J@Z3*J;Zh : ęeZک2D:=:zCJZyjʮ#Z*jc lW7]ɥjZr6E}YcNڱ0ꭊ:*}՚׊ճ>2B]9F?wJ[AINK?MR \8V U{ZKE+IT@DPADPY+ta˴GeiMEPDFQx \Z?dVVǷXնA\]kNh F# ^Wx]?P{K ۷Ep{V۬K Aik+_;=Ǜ@ۼK;o$8[{؛ڛ5_ۋ5;[({껾۾x+jWs{ۿ'i{Zk5{ ֽB,5 |\<'\i[S$\‡(\!,Qb0L)<¯&~K. 1 L@ܾ6];>LC-|R (#Q@QEQ@QEfb$*pI4hHk Vy(+U}m;(y`l5 %O$4W8#־PQEEPQEEPdaHjk݅7}ɒ»է IG5k-Un^斉x*.O[bmD6yC7zK3 2\m$(2}+ۋəDOO9֚≍}Z4QELZ (( +4XL#Ŝ)iȺG=%*Qgٓ@h!JW#sn&Ǽ{8Svm4'n>uǪRSSvC΢qz0r#)'`bs=GvʓѴવ.*çډ d{\ YY}OgӾwS2;8CGJ kΕ~]r8Q@Hu}w&+[I9qZi`݈%"P[ʂ]lMj&8*@ݑȫ.gN).ApIqU&>+qeJY;fSהGҁY]|EI^sl3kJBHg64˻#4Jsփ@wޠy)n+I+/3lݞXt%g), {^p犆Խ]L5Ұ[R z_Z +6@&€FIR3_v_rl)7dž0Jp4.wH.:ik#l?cЗVֶrpJ#)uD~ٟn1ugVy)~ V6[5ZT:TWozbe(_T}a.e$'?^2RR6twчrԼ5]/LKT^ǖHHTx Fx =&#{=ﺗzkCmT<Үo5Kq䜅L)nVMjK_Y/4χE}6zCIti\2'M+>v =%H}R-8R~cWh[\dcZ P |*`7Eq f OE!a a%C֋nP9nm>IO||~A!;"4><+z]$Kn\(cAmTj}Z]:p$3D'V)J“T9}XZh-9Ϻ䕤<2OQovziK"'(Uݧi~N8=3fim}gмUGsy_wҀ*RO˭X[L&Hgx a;Jra!Z9KR Ϻ|fU!VmTfY$@sqJ-Qم!ġ ;yFx5Y&YftVɈ<) g%9{7(2.pH  ?:3ÅPP]!~ͫ,e7.3-@u-O̱Lq jN7b&((,_6׶|_{N|>vA&Gv~+AF[lG@asg:jV gs/3kSv[M?6q5gzxsY5&j55eBrpSAxL_/fjOUuro=i<~_5ǿ|u u57Wm{3I'O)/S څcbala7tКT*l-1°do,qr}d 4feHVr3^.:> w})LVq9J<7 %<I^ѱaa #Ƨ-%ĂwprS@i7G)dj% ¹ly) S.l$=M``CVJ?qA7-:򒤕@g\B8 4#|SX/q\IJ8 ,ELeMQmgij76 Sj}(q6LZ$QoO\V*Tmٌ2{R,ρ&{`Б%zΑMx@9~+tw IvsyٷߙdͲ<0:Qvԓ$>0 H'1V0ZS3TE? jŦ71Uc4[!٭iUc\ K[ш]nr+iq􅕁8ޱ"uNI$ ȶ]U zr@>4 `!Ĝ+>5M[\mϯM N}(%\ :֗yJ0p R*C;+ C)?4LN\P\c)6 v k Qj6iW2=h{m٩)nD$;+GN|x{`.lڥ^$˧ʔڷGiDxR~kLjkJv>/Aw֝KV pԄ8 1e[֝O7x Jm0R|+֏E#I7d(!f$rO=Gf*Lp;{G$ OkIb֎a[ZJ=1U[7%6mjF}pz<ܮ=PxHu!NFW1:h-ZsC3>=jڔ!ԝe6b%Ĭ ".?jn%^@bkJYDp %8 &3 r#ӵq*JwOWעؙDI.gR R|T%VG/DY;<~yo]VkPw0r}>CkkB9[*LM=)q8=H뛐थS ! 5Upw9>B 'S{Gb u)^NƉlECB{J@< fKɅ9:<3AEQuPclfN \iIې*c1iJ$ouc4:'ӵۗrUYh~sN>rah2EvRJ]Cl%#rQn醛t!J׎j~",{UVXl~]V>GNϚ:9Q,2XR>,gOL̵cR\?gq9  x*zi/vɌ?9 @P ׫]5IaBKDmPҜM&kiJ+v2RzpW9JAl&9#5 veTzZ:rYq)%jA_uJdl-@ƨw'-T)aKARAqLóɟ!sP:)_ GƦhFĘlyMe# M.Z~ͤ@QL6I񤽦⥄:ĭppE5җ&N8A^9>tp@ek$Rkz뭙[H=Vʟjbq8K0OۊMR9|%}įv7vfJFVl% H+RDKxn{x%ps]ov6-LvRp\M:# ~+i7 L ]*[K^ҭV\am7Z vA d]qXMkFP*Zc4QShJ%I xq⡑Nאh`(yYrH8£q;XDbc,ODe\?WE7uC5oHj9y*>ӯ M!È-:"[hLe# ]ty1a2RVvchR6n8CDPfOykՊM%*X`'‚)l)u4jH1q8QQ ¡L7N}@A6]XR^لJvaw^+kSRXVzuN~ZyCzy8BBqBhҙu.CX9L\mQi ǐ= 22T;~7X \߈}{'WR雰uvdw2[I_R3>%Bw )>> *((=X_n8?Ju5jQoM\'Ru&oڝNԝ?isoY{? (H=C-^o - ADDODz';.s{-r1इUy鎦^^sNCadd!?_LhiТ\16҃M<␅%[y'i}Mv0XFIN3Yb|E% 1$ֶgܻzӠn#<նZXtnVJ %*v;)[mD8wqU6x겍A!'u|(1K:䐴G O"Ta;VaE>S֧Q8a쐳ϥ ZЏZ`{:9aNzYRGStmyٞ |}$;5z JJ}iaD^U$T|*5r,H]>1A&Z_.rK]8Jp"{(sWait'8[Z+Y)97vRJw@|>\vDVƄt$eq8X4ۯ Iu9i!Tԝpy=G*qf}DΙnpmpkm*#iINxɪ4ij*p.)Y8V>czUāTӎӎ=*rӏuPT`uƵj&y{i=W]rUBӃssdX-˶a}n)PQ<P&](|*LiM?-:"2##(ﰡ"`k 3M%|֓iA&2 NexU*jR|#M4DZˌ675:Y_~AɤicTanJt,ihT]ݥmg4[eӍq6/K[Cn;ZwTvZqGC<}xRH9`%-@8W$xHBe[nq\sPOʪڟUͳKCM)imם^8p=*#Wvl$) r ע^鲋-X*Zp<[M}ܪ9R1hw8[j@ }╝]f)  J9 .+HeDb < WG^qxޯ.S|,nf#;TiQqyg_JԺ.QI#JNƞS.m#S2*C,/k6•!XB9(zxs[/ Tz)I&i Ch~:ÐJ< J~iҊ 7}Hh6:>4 [-ߨ̀BӒYncWUN+tƱ+r; 'OmF|pJh/GC\N2J}=`jXmY[)p5ڻ qmZvp薎F;6'@Wv潃8r@>3ϥDj;x(}ڵpvp8'f.(ت6KQ2pN8-o]H m;eA!O)=ZDWoȭ{5{Gq!%D'ED)$)C!]>eR}$rTO>$ftlg %@Vf!#5H}nfvQԶ'#5 {<ψ *7KB>§{mg7~"#?jsQ@QE =qc~jѺ*՛u=͸_]ԡ\?is6wR7??xǡF_J(Ѻ2!|!#%Y9¹ <-C}ZYBR㠸qGЎ6-@$}{:ө6/+y-_k'k@nnh*1:6=׽Tӫ&;՜c1Zu}[IȦ&[̘O)u#}iym部$5( k }QS;Vpj62Tv86 焊 W+[m0s|ȬꎐBs+e= {-ƕIB*#;BSsySBz̃ 40^,HCme-wysx҄TFGjo{ORO8b;Bqq4+rdyynR=̂{}m“3<Ʒ/mڛ(̉./</b%l-)'Ӟ8o.wu p'a$'%g'>=EIZf[%.Kqx)*}&o-=l9c5~H^kZӎ$3]4dG8 k;`"DB I>1ik 9}lʹ9;sXPNBBdd/; ᎙Ҵ[ٵՒy5۶ܿ?M#NIgy{Xyl;j4S,q6ΦTmks/8B4݁"ϊ_uJ)9q3T7c үTߍ4tu&u%/~pR뚒mDLzk)j$8JTO n?'ؕyݰ!XqFRQmP挹So8d57+pЖN1>d@**RjŨ4,RԜ-RT랁c‚jsDsy']3oh)*+[Qi/WQIF!R‡=aC [HQ;g9sfP&eu/ʚWIH@r3HʔZ851z޷ķH~C2mHhVi IP;V3eb"ԭ&Z:?hj \WNUG;ώ4i G+UܝS?5,1)xnt)"c]H @O~;mH? eHVuů(2.'}͕|W^ٞkXid)M” 8u =T:Jx8!IRpI/]JxP<mZ2I-=?kf~2C eC OTkj=0ĨPw%c`ǒCꕜUE;8EMW"BZpHm}S r"1$R 1^Vgk <5.R<(4%%g5!`uAQx{xA=%P&6;[H1o{%jxAJPٳ%jY{˭ *xDQS\1S {YȪ+rbaM,xxzC=cv;+yY ;{Fq1;1%fđ8[ݶTR GĢjvL_OZ%KzUC|\{%{XfV+_6%qO֪Wq9 ,s=+0~csFO5ʤ2@#֍fWly CT3=)rG{nDNEq¿4}'tU8Av!K_I!$CAK+Fە!{%%$>SR䃔1ҫj^C %pq OyǦ\ Rπ94z ْ,(ϙ$[ͰHl|3L.pTF;wxjOwڦ`sʨ:7O\biC6ǁ5mJX_Yrpe/0#W.='u,EPX)`ƫ:q]i R A'`pC{PPu] ^2;- R=+Yѭ[ǻh nl6M!I+#V6{\DF A9p>$9&Qе-1HV*L4ۗC+ Sjp'.~X԰5Ur꽠wGm}GA,%X!hoqI?:mvCqJ GCe$T뻓4BވCxttM)[Ӛ.+gAс%JԳ#iK_8leL0<ꃬsmRܑ B>4),o>-s[v̝Hd $84|F?{0sޣ"&d<<*i\h) T?i^ JxA9[DƐ2k/ŷy>ov YQ쑤[b6c)Em0pBʶSU;[xF}̺$`nPsZ}bYwR/7u>[f5ˮ "5{xjE|ґVl ?5];z%$+ttc$A\WL^aHn;2zCm)*I9XC:LHL( Sfn_ 6nkj4RwɅvAsjWyA*u[ TT3 $1=+gX-6_-LTMզ2w+~~$U$1>t u$jfqÀ6el.OQQHȚ^u$s:SH؜?#NHq!`Q;HQ!rTS}.S`PZd7Eh i*;xԱ#1%l>u/[Lhnڴ=g%Dt ײRBb0J# `uT`-2 J]ISxCƂvYw78zShRv2U*= aZh,P=' )OWWۊ4Tn|@q}(i*.))hcmtzv-tYygaJ$ 0^Zz$ RN=*ؠV: Xڵ=Z+;ҁ"ZiJǒnK>$;]VbdJ(Q)j)Ym)~+%l\)H iqO*e*4i<>ڟH(n\_B^8~!![CJȌ*`LyM[Էpm_:oHsS)Jv*6Z`?3N^ % C`: /6|WG'u/-r{~&tBӕmOWR-6[iQ.PL1@N !)ڃ)10O g@^ 3f53_˘d0n|7Mdg:*T c@z6:ÊCKxS @:H6b0>6|S.K:-q Cidi]4WTrKG($mvhV{kPcO|.5ndʒ8I?ʖ6]{jbdaj;Sπl_4PUk #V>$+5ƚG 9C G6127v-? E ƫ;Q{*F~ӷ aQWU$uISN}bӨ= Ľ7ڕ5$wN+0G^(raxć+G1Q3#ݮj鬸;JNkVraC66xhڢersIzz#;З6'z`VOed?%e8giY&?d;jyi٩HROOJNer06}Tjkڔ (CM6nU_jV󛌒<]Wk^(.PSS-Sxk.go,yrxuP.?r_j/QTΕ5]3ÐbC?*E:JTLj rG]TGV  J%]#젥ݤ?;C.wHCO54зWģ5U«580Ԥ4qI(?Oy'U&Y/8Wˏ{+2>H4ε YJsڌ-4!9 ѻ\ނ'pPRQT4ӺzM9 Kgk䢾]Ze60(~w rA*Gf_V$S`xj-jժwŒ9U'܈ipqFlm_ujY/0[u Ճqg]MPyn#)cw4 [e="Cn ڗ!Y)4z!I;d#>cʗNZ%_&\S1uiqWJ³j v)y$/6R3|/ޓDa$8"<Х o ln#CC>(7\9pir[}n@Cy$>d/ƒJCN;>Fzm-ŏ< ϼ99d}Je-J> Ywg2y!/R!` .mT"*}{%gUb=j)H-ڭx9BKHD28vAk~Q 8 p>O}ʔFG7+j5wtDG|FqA"]]vGw H@R:թm'cJ# ӕ.+ \B46R;8!<m¼:AKuYPiLηaCOCJ 7`wJڢII b\;2;qYqA (3vQ,Np _j뤘\M%jeФ  V&1$Wt2MJ0FqH[u䄞2pie$bIKiLϡ)MS&(u}pMhwK*C`+$4K7%7rG֨}ަYmڇ|cwQ_XWʃVzanCI$'J8k\"J-<9smP̸ X:Y3|R[1ƁNȖ1ȷtT03TƦb= Ci)hvݾᥒ3@M!3#,-[I䞽jؖœTqp9*nyVΫVN܃TpsQϛdyH+mJ#$X\QZ=BPNw q S$YlބP-~GtЍu!EuΜ+<9vUV*3'Dl2lmDRtH''@Z&EEPZtŹ*guAӋ{Txt sܨk2,_/5uTWjV_)]65k5袊[ӷ#k2?Qؿj*Vf X 7+rpu*H5"t% agcC)~oB!=O###JtlD 3)?h:2٨ЉZW‡o7;p'C0ݦISͧ)'zS:*e%$dpO΂Ŧ,/Aurp c5:Ta4ڙSiu|GR<ᚉvlAVph.zcOBbE $'U .2eMSG JƹXH!}`c֫D: Kr^ P FA+> iVin!ih#xMn<\O!p*h~Z$%t4]FJ@$Ԋ)pZ$$)^4+.l#{q)Z[Eik{YRw2wSpGւz6T%zP}~&F:xUϺ+ުu3CdfRWa8Ipcn)П0IyP^S[p.29q#SO=`B.]vp8$)x$ަNؤ<ܣ`Tԉ5.nOJ2BO5 wpeIR^8_դG_Q6mnH>T TZn'2#Z([dJ$UgZ 2}Ð帗۴JoVA xfA[`:k)';|liKɂ7ӡ!(ܟW1PKq 2" TwPvPo5Ju -#*uQd*kmyPܽ!f0-Cy(t%sݮ(GO}z9EkhJJ P;4۪emRDv媘_t{' sW7NQ{OZkvD hX꾅C8>T[p4[VF_OvS]CyW$RJlw*m-[Rrܑrc xP TύFj 6]p9߻#V ir.ʛ9=(+}惮ZJMإ6kvj㔸9zh ʹriJp z E⵨4~1N8̚kXݟvW-$@?fUUS{-5%":ARO?BvK8m*H x$ ]+|KneY! *YKPwhNT#hpam)# Z6,wY]}RKBS ƢeۚzUN=Q7@ܥ$JWs"L^ Pmi]*r9 pKN2+]8랹\[*h94^\8,p~\ӗdM[@BGνSo%GLu#9L{ef;VžK{Zcn=rpNwQn:u3xV{rX`q¬ Kck}jklT; I+oRcF~f=R{<>uM_d\L|6C]!ioIwC+p)yI(I*NG<>T W r @ฮVp2DgjR<)E>vH] b|W+r}z#SqTSEW >Td!{ik-%rG\TͪVԄd]- bJQ߅xg(0߮HcI(Vҕm(5ݠ$|9Jj \~=:R=aא;ԬqY S-*N6p*Y;BgKuJ<Z)H{ WW3@8J`Kd/pMyڮ0^¼,mi)5,$xbIXh 湯[ɳ3$M8R#OEڄZ7Q'qG>LX+6 -V0N<35~2HF\s%#SǵMQMД*Rv:dԄh-y}z <SߜZQ z!y-TT^(( (vq TꋴD_+uw2c_Ԗ]WՏuV{{jET.s m5ζ>dT'w ~͋6Ҥ@)̗ qBm\Fjځ]yx'T4)!TGP5v4ijPyT3-sdGe02:n@Xh[g?W5!+j(+)l JBv!))ϡQ(g5nOA+֢vm/j.KajN;w)GCk.*dDT ;c>Tb!७_!HkMe3YB)8b892iُd/Rܪ,t${|=jFUfP[, ?OQ=vc]p3v(ͱZXlA/!+'v,.1 88$*$p3.[ +q^'UK[ڐ륤6+ OPF_M݁smX_QR=or'ğ;bm@mD6}E*ue M}Ii'$AuӺ- @>2FKX@񦍆q;_+t 4%-l)9 I|.5L$%&b02~*دDGVҕqQ,+RzJNx9u+k}Oasrִd$2*=.ZC֣'v۴, '+WzR;RK<?‚z%}TLd,d6pxIO<ǏFrޘ֘vĈ;0Ԥ66Zb~ţc--JPtϭ*#xJUkArb m_QʝSP9m״Z\i/OٜPVZ ޶m,eNpw9P?RيXKq9R~%߶f"[ є@⏸'&Αq/r֢p`{A. s* .nZSK q8+f9h(:C@5l32G4ao{BoS2F6*_Zӧ`*MP.8?|i3y̽=> M[%_:ʔT>V(( Wwh~[m)쥶wۜRh}K{|?0Rd;Jw{p3SSGw4Nr \1eRw6wtК{co/F:'9 wֳ9nquW:M7]?YwT.55U>WXƍLEƦ ((  EPZl=_!Q)[>ǑWȩm H =3P:zH$*U'2 d˝_ "ɄO?n*Թ }*J6E& =G*@l69>BxK'KCEH*{N+o|Y_ 8C;rԥR WŚ~mʔ)\r)rawXOc?ε'r="O{aKn˘Cm$zom6# 1!0G=~u9uկ&Zh@"J N>~V$I$&Q@QEXWC8RH#;lշKbǖO*q5)6LgxW&{6TZQE)(j33ِy FF_R۳ )OEc^ϧa{-֔Ӣ2r,8m)')-0)QEڅ3UJ]|(I$|MQ@QEQ@QE?;MJ=Î(P\-'1G;WW{%~me7(ςO{j:~n5 ]Iq 6JxN $t-//Nh9*,滩r%堕GUp)GJiHaNxߔUwbƣUܤ(5h8Вk9skQUQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEQ@QEmricron-0.20140804.1~dfsg.1.orig/html/images/npm.gif0000755000175000017500000001760510507017374017712 0ustar mihmihGIF89a[DDBD̄dbdɏ<>ͻ(q@Y7L6`hV@zuسkΝJOr+GmuV>ܒE_~u'}Pxy't0^W͆H%Ș!(X`q&k)J_ZV+)f]-A2`fUcn!U&Y|,""|蓃ɤLGi&J(ihYЙ12h`cfMWuMrhY']t譵ZNjk& *:Z[TkmdgJhaQ|l{k}*ҫ&,Ȋ#JUuf*;JʰۨC|n.j7B׬J'Pk VXaʭߢۧm]> tjL ry#w 3.愗,PwYcmvpFmy]r0P-Z{i  Zf#x=wm嘛%wwUG'2Fe및ulnlo'D/G/VNogoU ⧯ɓ?[yߐȳ+Bm"t.:%"ꎀ׳6oˌjdAITsGx~S:FC$9IhqǠlHPPt0?7ю$= P$(7SZҕ.}J=JӚH_P'LROIgO1:Յ6At&Ul^*P[Ӭj )X*ֳkEWVbLͫ^ RajY ,}OMś./8WT+.,w`K9a\ǹ9򑯛-å;'NuB}U:ul{WǞdӘhqϞ=v]&w}}Qg/fX<5dw<(uIQ?vǛog]9Y;pkOghF8K5tCs6izc|v_;{"?*gǿZЏeT>X'tg[G~{ osHigz61؁v"h[TF[n7wwo5hV18sG%=q]wo=xav|Bhn%`P8|vtg'kMmD( Yץj,aY(o:X<|wrFeb8N/g%׆|~nXne(aqz}؅JXz#GMȁ8ַ8؁ hP(SZ59Xzr^X(g>ljжׅv2gض{|Hh8iXxW qFqȅ@7Xhg릌|}Vϸl(gs3if(x&hȎ׈zH{x;qXVrՏ(^8]ioqq9`w ɀtX_7i+wՀXa(aVgr鑃uG']ͷg7.4[_sHb7kؓWbW(zhyLr *aޥ 749g'GbRa$io7VHl#tjW~x}ɖvG zBՒȐ)(tMvX،Uޔ9y ~rGgQ5ٍ@ǚin{E_'ioYget'yŋrea9pb5Uȉ_Kub)_h_6ŃFoH5ɒYԸ_wkIRIXEyrIȝɉb,pEg9Ir망ș] ;X57[]%H٠ |񙄸}?'xw^_שhc:ڞ&+r!=Y(*ɟwQx~Թ{WntaY W؇*Jjy }雊g|DdIƛbujĘ&|xy*טYjԂzgQfpj'4%:NOzxNCU:0e-gqUHꙩ*N:Ȫ_Tٞ y:bqDj_֕tL9䷥ :%ʬʨ6)Zy dɭᴅ\:ZKꀞʮ顭[jg{ ŝ'Szsdʰd8[NzqJx!hKd(% ZI*,۲MɱH#WuYV K7尦Vg>(Fl8Bx'ۥF`9m8pP˧ y"iLúS ek6 '{! 5 ˷Gw\{{sI12{ º&ʩ)TRȹ+Ȍ긲dsS?[%шU_UYajX+(sk{[{hCizu۩8;W DYxin: Z_kQkBʍ$zq[ FX#|"*y^@ Y)s[㗿KS;Z]E{bEEw$\9yJ[̊ 繞[YYۓs.eqYZJ̙Zɻ2ȂN|P<TATſFȆV6tJ߫ũګ|tH ɽ|ksAIS#L1x4۴\ڊ5:g{Y 5G 좾·[V &|X;iY^H&U|A7;l}{hЬm:,N˝;2raėU|x<,r<Iry_Gã[ߘh<WJ_9?⊾K{8o,wo:=Eڢ@,\6ktOIIi ˂Oܶ׾9;dkk +LŇ+w:f\OZu,˺ dhUioM+ΏX; dms,gy-nͅ>} ;[9)= *FzNJ|^+خriwlZO>R؎*̵ޡ+ǹ}e kXm/<N,6'͞A7f=<ߣ %/S}OwL%y򬬉~N`'`4 nL3Э d^&>vl.j 򘾉Ht˰n}m|)G~U^g.UM՚}ޠxI OV5*!EHl*sXiQ>?: i~3g3tv ?e¸ՏVEG?+J/NO|>@ * `…|x0JQF=~RH%MDRJ-7PSfL2mpSˎyTPEETL5SЄ>^ŚUV]jl6Ω_͞EVZ%ž+5ζuśWۧ}-kcUU%HbE"vF \|"f-GZ~MCngʉ7gU]CLumyaF\-\d(6t_֬qO뱕Gߨ9ێ$46*BDRΰ < OFc;f1Bo<1H!AJ/X쩼 G 3^|r#2K/=*K'cC쀜II,K;,9հt0bTL,#4"AkMzQJ0lҕӴSOʓ=?%TSѺTLOeUW ^V[MJUQC C>uF%3-DX?M7I5ڮbs:DL+kipElRZuʵUyݏQ6.RmD7լ[Lw]Qo/[(!LMp'*܁7fE81XfͥX_G6qeaԘc VӐ;+JCf$ά mDQߛf޽ɇGÙH&c޹j WMvc.Foe{Q!.TѮ-9?CCNqhkk" 0pvѪt6@9'Qj $`&r9 obK)TanB"v.AfGe1V7!|TDډD\ 24Wc`æawz:1b|D3ҏftT @lpL7 x,]JHJc9"4YIN6$:9JԱPwH)U :SeEZ~Qыe.o&^җe\@9LbӘDf2Lf6әτf49MjVӚdt恬g89NrӜDg:չNvӝg<9Oz֓f>O~ӟh@:aEhBP6` EC!L(FQrTG# ҉$(J7Ҏ(LMJQԦ7ACґʔ'iPw*Ԓ4CEjQҥ-)N:USJM*SԭB/jO Աg*ZWZUWMk\Vv+^ɪWʵ~+`Rְ\U+d+Ruld5;ֳٖgb7[^ljIZӲmkcZٞm4Eڙ֨}*o;e=._s\*s%.r66֭.fv׻{nmi;ힶ-x w߅wW5/~+rk_o`/f`6[ag!.jU.0 |+1N[L(qeL;jrd!Nqt=hBЇFthF7яt%;mricron-0.20140804.1~dfsg.1.orig/html/images/patient9.jpg0000755000175000017500000002145710513266750020671 0ustar mihmihJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"@!1AQ"aq2R#Bb3$rCSc*!1qAQa" ?(( (mGB"T̎]l,14(8k+]%#,wg^;eԑ'ӕP2ѻh.e}Y_/*`+AA?ERvZYL-X4KoCNA݃f=ݮ*1UrOAJʃ*ɎGFk^E::ŗ.4rPGIzܦS"F)>PTTVTj!OOִ (( (( (IRR $@%*ZR5ah^]5L ":~ghARQ q)S>}۪'NcZͬSުQozBΠ!R!0Y;Av@*xFsW;{ա!jkLCRP溏 ?淡e!ӫQ ?" C,68F*fӡ[ G8>-vk ^0Ϛ^Wn;ejG>:5$b2 q6kj=$RVv΃ޚF8Tr=W.+ (=jhFiMzϳ}yo!#9 Ɋ522W|n$rZ}2S-ZoQ%Q"B8 ezh) IGWS:nv|ayi^`|x8? TAʃQ@QEQ@U}&SyNKMۭ͘mJ2@+΋mXЈ + O(ǗGXQfXbi-2Wװg֫S;fRg$dٴե:y%Ɛ @AfڣZ jF;).FՓzxzȭWSV͞[_dtwZj^ A3f[q# 8{#Bq a?¡ten*K` njc{V@/S058FqKA-r{$w3.6Z,߸;ZHkPƣ}pRМ4u6e2Jy:wuHdG"Yy#AʔTƦ;bh)HQ v > (ڷDT3,MۏFۅ0基3S/*;n; U}O?JjeYcq@c\![Vp?h%}$ 'V=ԏ/WTNJ. Uv6$vKi9ՠ,ʂyQ,IB{w MoR%,<=m.\RH&vny9턞5IƼwzw w-[ɚ™*#VK{ҕ Z;SohuBDdHW^Mͩo4q;<Z 4p; ~bm9DKSlVV;f L@ʟS9U(K"x㚭jt$Ҳ1n'-w2dRs aTN!5z.;w8k4۴4CriG/ ܻjcz*&;!!+>3R-g`Q%Tdi/,*D'p3+"O0 U4 77hx+a?N*n ̖J+=E{MB#Ƒxjrkz1 QW4k6:9J^i˵VMêghN6>06ޒBd:$x=A\i.Kq5KiX}=y2B;T'Q6kr"!9;dw.uK[YIu_nm_`iw>*[6{HF²:glahyg*#UgHKByҁk$qHmIJZ+3>Ӟ"T$_sih9@9Ρ-hRA#袊G+k8~;W7WOXcx&G%{z 䀘Pͪm %kpF?sS]0Ɖ`e2ڼ1TqޓzUCD|d˧4)IE-cHHxlX @#+S]X$Yi3:Pˑ' Kr#@w^rhhJ~4W?ϣ ")&}#3r Ҥ %*{0wT  ^ -P$#OqY n!"wlGljbO1V7zwM)==*uP۱ >.6GIDupHVWm CUj`Wi!mT%c[9(NV¢(ޱKF !Y1JI'M^\@'n5!Z]R->.=MqJ];N?qW=Dz-HJA 3dBw'ޫFϪQ[% !(wq6𑱸i qE˻I%֛z`KoTݾi涿 Z,q P=j D[_ v9m9M5s9Nf29>tS[x I%jIVEkF.^/PY*9RiYA)Pc*S<΁XjZZDV1%#{LtNvTVG4լ4).Ȑ!YjcmxۏAt٥ǹEjC.e$(fx@VF{sqГtE^Ϧ)U PS) )#(` <}=t2pi)Mk} Pi=O?JFRG4㨛-KZӃuJ$~Vx;c>*uV6GRNC)=vʢso:N";f8>'4VŅ+^8r7{ [ݴO_Rpk5LJe5(&&&c;n1$꒵OnP9'"Fn$s cӎWhI\;mGzβ=CV.3\SLS92gHO;nWEzmiF-٧ } uBguУ,X9iөq=s]KӹS9V-%-|;PM=Zr >}jf Kk 1N;qTQc; RF% u 9-|R}O縇4e@֛{j/\)>t 򪣮7͚ (l?ȐI5kGܨJT3ڹ󮒝k\@m{Gh+ks0ҧ8VI%'үKi dqY)KZN6s]$ rZG||ϝJor,džڛo<}wh[\%,8I$Yd96Vow}qLM&⒢JM[%KKj(:v%gm ҥ P}jzRJnJ!M'?VY.n 8ʸ-6wDI ,8ۉJ?{-w4 {])SY.3u`? 0tvkji԰4::ei1]h۠%@ prЀzqUK-@<{WB\oRt !#4tnAR.%CiI5Q|v^#&y>O_R}c s4d<[;1o\a%h*%q#P-EquSs^.TkQK!g̭Y<*jms'CyAvSLIirO@ e,XVWr91qGh*计:W)O1Iªݴ\k1-9QAsMf)!E|u0TN~DT?L5hvmS o VƸASC.TzW2A8\w}ZIݙ# m۴Kx,nҼ] I!ąeJP[QXf:YBp*ziz~\XqJH X0fn,u~&۞@PNEqwI}[H8ΤgLT1Rsn-TA< Gj)N'}CnO4u ;T.yR튫lz}b$/t FyOέfW Kr}kFc\]At{hbmmK|K=H>Zݼ eh֢m'aM~dT%AkGzL8qݹm*U'_o˩S?>2n*A8 O9{|Mܜ\cfܾBOH[S[{Niz~+qRYDTSv%*՚/d%ʿU}IoؤC'Cy=~BnZ޺jGl Q~d(/k?*@%yȊJҗfCJ (s#[Keh7F8p%AIrTqeWc\ۗ3|ܝp(c]ޣpRx7Amd4žyA)Hʉ8 áE<If}JXMal͍m)\gi9QZeZn_j20PKZ. M, }6v<ZSHq*8)^#\mMe ނM _DXoe!Vh.2 #Y]6[[ y}aŵHJ_B9V{>ҭwYnHKoe(Ks%nBPFǓ]P)eAjR;Gq}?c3nq'rOOiRL]W$cq\nfrT )9MiL0;I%AÅcRR'8U]s~,?g/R_40?WG})djTY2>*>|j龌u$v1Zq*yD{T4`DX-)ʻ% 1AQuR9|:]sa7[-VI5EPQEVH㶫P8|4SOUfӫaԺw4#f֐rOQ\L-:܍%zm-DޅOI?:qLzګ Ta!E~M*u M |Oi#L^ȮiaԽc )#$U&KI a/dZ s(/MI)fؗww4#"ku%ӗxN|Kn,& Eoz [p%H.㺱>UiZ>~QBϻ֘/N6}]CIZ0lŕ+#9`*dh2|C{LVa j8V"<їcz䤖JgBM6:'?R76w(nT5*fRG0=klB8/=OwR))G҂#Vk6!*Foޗ,6)ڊ,ZTЗeqK7p'ԟϕt QtGl ?wSdsA{_IhewUJ9GG\ѩ_.n8\R $)]Ouvej*8.|ǐ@QEQ@QEQ@g"t_S^B[|A+usDur[A?“q؟1<.igϵE.GPHHRYa9;m_U.LiL㍫HRq4 pӠ +JMn߭16ĄT He˧Oo˶W͜G941o>Y0oi[>)}.2xiI~T΃)gs?޷-j2_PR?: ^5Kǵ~9x|m#*M$C,R}מBB66)GX웥!KP)RVQڒ{Vgjy`׳L[ZKvTfT76$M'^;@]WޥtZ4CL>Oⱂ@I5f-N!YSQ ZQRTMc@QEQ@QEQ@QEQ@QE} RNRHE!?uf-\_5^tP}$((((((mricron-0.20140804.1~dfsg.1.orig/html/images/draw/0000755000175000017500000000000012360760644017356 5ustar mihmihmricron-0.20140804.1~dfsg.1.orig/html/images/draw/circle.png0000755000175000017500000000134410433076564021332 0ustar mihmihPNG  IHDŔngAMA aIDATHKŖAHZqǝR B xS:^FD$ƒ$%xKOu)(˅m7Z4&ˉʃ)ߓlӺ NЕz"H$Q)\.lfcJ t>= Dاz\n,cNb1B0LLF tH(~{<V :6<>BFL&5֡fJ\.gNQdR*kWx Н|>;t/''Sjhx? ڪ}qyE><BuTt¾ңя:;svn^*&鹹Ri&Z4=,. TH{~d$?~wDU[,WO>66 iFsrrޞ>22zeeU*oԖ7<}ppНY,$4ٻ9A;yyyollX渡aw~xe٤$Dzhh(\/ sB>y0)( =""}cwaᬪꪨh_z@,,,ŠGEEBc㸱V.L?Fa7LLLthbq!St<=66+KJ&9T`+z>K./c%9boH`v={|n'^*U(INudN!R~|.**R(g6YSsnΩP>wu ◎q/mj3?WXdMM صZ$;jo|R_V]~:23 Ўm;ث?~J$pE>!ޒ1CC^&Lde]bmy{yfшܛ505Vo_ug(}齨LbIENDB`mricron-0.20140804.1~dfsg.1.orig/html/images/draw/fill.png0000755000175000017500000000231410433076516021012 0ustar mihmihPNG  IHDŔngAMA aIDATHK͖kLWQZ%S-]%fkpm@ܲX-L]@ecŴ׬ј/?&Hq+)jXZ 8 jyAAS9{z A-ѡ=VtTSSFъXӁjommMIIa;ߢzd?" 7]"HVMQ)dETL&H~΍}NO=//NqAA WMp0络?g%D(lѸO=L~᳏? =Fz9<tX"vE[bq:5 }ᯤ/^ 0jjd2e]xӋ&QߍlRzQ :nEgl†y,1`г_&{́6C'ӍX1tvY~HW9 kڝ`'ݠJz?\m@Fۃ^?O@$*_ѻM&kIYesH}Ng iea3hoZ`3A?~HC,33Pbaaɓ<^ӽ{A=icq,!_Z*bӧ\HqccZbbc3~\5~A`47u$$$齿g5{r"íPL?C+rBєzI"ed`lT*)<~{Mq%%%>}I5p")K|u:G)F)** 6M]]."q]Nm4 ؝Is82^\ uIbjF3",id*l_dg.^y"TRizz:? <$?Y>|`" oy;SW-(ؑaۧ-i4ٮ]N@_akD-7sGGL6|[&_G:VXh-+-qq3%n"t-"IENDB`mricron-0.20140804.1~dfsg.1.orig/html/images/draw/3dfill.png0000755000175000017500000000221310433076646021243 0ustar mihmihPNG  IHDŔngAMA aBIDATHKݖ}LUǿ%.4f9@@Laf"Uo-&1)"Y\B)!/11\mj/f-Ƌ,#Pr"˜Yso>Kp}.l99;9s=6L#W0}hWo:o=đ/:߸vjOٳ=-Zx ?#!= FkzЁ5p?XVe`),wzCmw ӻښFjbA"W0f¨md_ ̵"^1#\ !9x{W0Y+ǀρ4gVnho(({W)9RYrYO,:RZ[-l?w@_Acp ppNuɺ1UU9?|X~z,bB6.X箷?G%ps  E!\8nM,R1e-xb,&`ZؾdL]hȈ؟v#]e0# \a\aZ>ZVCG2BX[QaI;2^۝3 h߁JoGgs@~!z~@d쾧xtoeNwy˖޲2ɓx'5fϹ+rIENDB`mricron-0.20140804.1~dfsg.1.orig/html/images/draw/closedpen.png0000755000175000017500000000156410433076440022042 0ustar mihmihPNG  IHDŔngAMA a+IDATHKŕ[(dqgHIA4RʃC4aăOa^\2>PJnsXavvՒKָnjg:s9sfZ/s;~n|~Q? CIII``λtc}||< ..7cKR(''飣WVV~<].3 5 iκv76==##vr兇JXƃ8)JJJNt,@SSJBaRibI "((w3t-b,.^TUi4*,,GEEVmۀMMb1]T$&&&~++5}2Zڶm)]=AJPULd艉tXyHI.+se=C0Xzzz:22ٝT Mr$+og[r*w߾)CtFFFHHZ֝KKץ]de$lK5}T{AΝ.##ƘcYz %w|=n ~V["XRUEœPzw7xS梹:?oHx_ Nб0/=Ӎ 5?wXi}8=m4Tv嬡ᢺdfB-{:g:v`LH%ƺHguu-;p<<K0\E"]VMqym-89/_thÙ]%͋ 4p# laH'؊+<kOmfPZV; ݰfmw, |$~n+݂r'+5 M>]dꗙ!iNQT9dj-0xĪŌ/^*d7{clcD5 *S)Li?,3뱳>w$[N/ l~k8fub^hu Oهz `h*d7Ybf<5HIb7]Kc{׉Q qܾwk E  ]C=L#QRxF*#$ƒ7GIVl) G8 뇽vt1RA'+əC+RYohK3 Rj;,U@u/z |,*]LT溠9,mI齑Vb!S8hI: 1#HBKa';yB*&ī_hYشw$R ];!GfdP"4g^YyMU1a4U8$7iG0Ts/ :H<,U& ?HtHW!`3b(e@WDЂ>ckGSRUR<``#=,(q@glIOMFM4,seix¦Ni,A\M 7aNO40X@4Lj@iT:xMOAlږvpo3WCvLôhM^ֺ'i;!nw[:`BoEBFr:tqZͮvz xKMz|Kͯ~ N/9"L [kC2 MVT/]~DC-j:W^*E,!16JUqbU<6QFև`0>*&O2d#$*_U*$GLLf\h TtD!ylCfDn*A$`bOzJh34CF.r-bY`pc%fh4{qt⚛qдҽ*egS9f7t>jaYr2`>ʦq W0V5y#r=6Ӡ.z.n#ngCZBˤH$d?J5OHL^Y gDgMeW5V+"@_M\alsB QVqc')oĊPozpw r{AW8ïk;f`iЊv")$UܣV]6UwLutoToO< hL<+6<,<@.ɹLh?bz7q?oHm>h'0HUH֜W^?C viY'u P$ξ̿M<Ќ{?SS.us9\4R诪=W>T;g}w{٭% 旂\|G &z@=9F7-Gg5?eCׁׁem(T@" mspjwpn7=L֧SwwːRRe MN jwXgiGgFT|u TPDvHDgpE]1t2En=OQxgwS>D8S&#'-t&N'xwu-m'P1M$FmąI!CITl$FXtqGxsGePf VuH؇A񇀨r:}.wzPLqLjL_ThndFf 1q$xE#RNo~HNN^us}>o"C#&~7PqmWguypQhhjpG .J׎ hlSS!SCyg>V=HhQGagg=TzSs؈]brj\2cJPtlӐϘPoYgx\֑`Wx{W8b\ Xא̘x1 :n#HdEYDF"pjx@ՖffZU%6<\Kfv\xٙ9Yyٚ9;mricron-0.20140804.1~dfsg.1.orig/html/images/threshold.gif0000755000175000017500000005440110512570046021103 0ustar mihmihGIF89aR{xĈDHI;\=IxdG8ȑ$(igf؄(HYħTd)E%)rA5פ)'(gHThٔ'HtXxkhXԨtҌJ4xtVt)wd&ڨXT'8hXyxƔ9Iv<hĘDX9THԸd*Ȅ8|@״)WtJhf G(x<XK̴g?ghgԙ(\(,wl(HY |'X8xȤ8Wd9yȻ8Xwy}Xa7L) sLliLw̉GH6'iX̨8(h\H|WivۊxX8gȜ8H8\DDeۛ[ƫ:|L;LGlHg֋*ٜ'gWܩDxXvx wh̘LYHܸlȌ7ܾ$Y|Xwkt d44u4T4lt\4k4{4l}dTN4!,R H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶-p㾽)nFmG;݈|/G R1ܚ\cCt\Ye/ܹeȑ-R.3AЀ5;$uꁰ3VH6Ձv.|`"7Aȁ*.?O a&, iñ,;k*zikt#r㒩\3ηKjo 4՛s,1T|-!W4  OCиʊ0? .H8 Vؒ Gviܴ(m'7G.Wngw砇.褗n騧ꬷ.n[{ҿo'3{AWogw?{_柯}/c߾OO}HinKX $fL)XA V^BBsBzāka3:-l601a 8pH&%.QLApQqщY c/>ZZ EPjzc71swxG |ylc9GRUdH"6q4coظH~q %%9MrAH򈲑#L#_S.cuT5WbS,Y 9W/M4->Pd1i1Ȉ-1L;yIHmn>-#g NϜl]l"γS&BCܓ>ihM6:TI=Њ æ-jΈ⎣GoR49FKz̑JR,ͧH]Jƴ'DwӎNS攈BENQ9Svq@XjKZEKOg ԗE*WZSIuG=UVzB x[}/ &Ů:@ʹ|}*nMbDF5zEkecfx65ִ TR^v$iQ  Sk+Զsa{;Lvȥ-pe'\w=-rG\kfYƎ*Jsʕnrk~*y+]mvq]wgGݙR'^H<wM rUc%-_g[OeKM[Zou0rԘÜ}j3۲J>ilx&5\w']F#; ;gLc"X o^%eq}},Sy*} h|+W3.Ӽ){g֘hqrf~ N+3]X^7ZN(jVӘ 3a׻V5)U:^\)3ɵuvhoc4?6OHh.uVjp#7w/wGu'v7xU|W~,6.19W7ud؁cUVyj7fro+~BGxBK&la"Xudw8y+Ȃ!O>87BhDjFx7Ku,:}d͇Xw77r%瀻KNư~wG){tC^q,"ȇHIG[(q@r^8|r\&~x]Hzw_؈r|'X,PKx׈)Hs!{8~Wc[y8fz(|~X8ؘ|HWxyrHx@8;B؇ϸ~J(nt[w,{ȁ pwWѐH8l}Zhy(ucIޘI89aؔ2AYA;9I7G_;h݊z+?UhʣB[}@<Kh)@  \p;_8d_&e2;w+?KYjjz F}&1Aۧszٟ {p{pKi<21K)ڣ컷9$| k-۷ Lt# P9Z 9< S{ywp\#YG*´꿟@ñ; ͳ -m P E=F|Hlc ࣱ[ypP!=$'msA// 'P%qӃ{K~Dz,}[ȀxIv,Q U-Am wulb=:\0"}+]s `;s%@~P ءxH}\ϋ-+[C1|Բ,̸Ԝ-}ݤ]ڦ] E|Pd‥:|d%c۱-s}d%PM܃MZG>zl̓& FBL,]@ Zmڧ_t0߭=%mb-\,p / P .:YxԼ|{6lН]2ṅ %;ݗ [TmŌ5n] 8`.=P^,֔ psP 0Y]_>,w|~O=ȓlF0@nݡ}4.7F/?k`.ܾ.~^`^0Ϡ刀WAIQ]кN }%8A`lA@A| N܀  ˝IȜK=L{>Yڞq?1^oW̤-O .Ԯn'/d{2 P8<^V}J_ڻ~E:MUl /{I`a?@G/ oLt}{}P/ °p[h_.AY^.)0ǜ/?5/A2 DPB >@D'Vxqg/iHs4ЛS s\ (H5k UBãwv@(\L\1QRMjtUjDQ"\aļ~@XXc-;Vٯ\r72#uZ;X No`.6ZeGZNݻx-C .LXuSԄ[g!5~A_͕pI/o]B +R^ݢvۻ-XkE۸n9 __u,*#02O M4ji!?p5;avSIR$l*Oz#w*+!%6 H zl+ss/= K~XH"0/ zm/8c >#P35TSAk̲,MB 1tO ;|aC"D Dw)ŏHlѸ`Lmq`#Y볻?95 O%(כ27-Isj*T~EBЈLW[hEVzr؊:CuFDghQFs6/KM9GqG`"V[U&%,p.;X34&80!7,L9;{Mf9:Zo!}Nɥq'BGm/䝷K/= }kud{&1.ɨtUW%L昫8dKA>H5VK9ONhtf!wY"D6qx(D/ =hkOo(R#s sSJ1V+f[Iچ+z离q5ƭ)?1ȁ du9wAI-(rq(@g  ҙvD)~:/H9odM_]G l`S^EypJ,CZzz]yk D>|*\D #ƷC,rղ- #8.@d (9A%P5  8 CA DP eM\1oСa9SCJ"Lf+ (Yu XybBRur{*whO4>QR \1'bD*s3"+і!sErQ4TW@>[z\T}Wlh(e n |YӚPJU̩OB1Ŭ3MSJ`@O} AQQQ[#@@l3vJ6,UlUzpf}/?7\OoA!Wm5(bO wuͲayXN^tLNN1eaޙ wQPT'ה#iGwDE0j9% )(ms+ -pSU8;M_4)my_j+g9#/qo/"Wsfl4_ w0NkifBO &1k_.ߗ)b͈L!+WO7τ֚&\!~}#HkM1|_Cl-\ SuV 0$]ey8~ҟtE̗LN1 ;2?sfz,vɳ~K3IBO6Q _tپ{*f_7{5Y"T(>N}w36CcUNXE @>܁ 8Oq,VSh/R;ԩVgR;2>곾 "1Ɏ+?S5 H tx#%#.˿>< t;4D z†BC 6\ۚ;&X4mA1A )H*cc"A@"8Nt:R"B^E0'+|<`HS0I @IgĀh, jT@&F;4!>̆*A\q,>հSuSʨĈ.*JGL,DŽ P ոA`,B#ͩKm[Mau& P[&8u­}PE\Q;ZD 8-"d,S$TD-A ]vM[p ݯу{B%^dZN] KE텫U,][@E%]^a8WWxbU[М|bJ%bJ_AbaN\bd&c".i/ӵ,66)$DG9vHU)59-<^|ΙCa VZ B62h,L9,hGyLvXO&he^(e^MeV˫AtX~X=bbb(b؇}p`-anPi;_@fi1nf斩Y$7S+c%2~ד[o6Sv '4%L&ȥםZKf}6T|vHegFe[X> :%SJ愨j޿k#ک^Հ v7PPh[vb iAKlˮhhmNál%E&2cmvHּY,ԡ>ڣkOJe9C=б\NUbU@]h8NXPRej^k.޾V!F qc-lnl`D4}lFl?hfaYឍm 4fNw5w`5Xf1T\XV&@o^Ld#Zn~~ae`hWknnPF"ae6omN^r.oow_,Al6fGpsnpM+2 &=/ K=gKҵwjVW FqTݿt$Pn}Fqu´ꀭ恸."ZxdFR]^r_K2qi5-.-e2/s]SKkvh8v*Lҽs 6yTN)tOp]~Z.40[dM?] uLtxLtequuSGuڶhXYEQF%g&WD ,/ّ]-ߔ,vi5lvT@ynoz9/ lns9 NxewSm}W?nJ[ qhrF,Y#UMtPt#tuHhHSOkuSGMxdO["[<xV^Gk?VP-w^y7f*8yyyPzg-Zn`+ذ_`:u*OUCײM{'֘%gEI]uj[VVEԩK#)]hVֿsТy*}4Ȑ9hM5֫3"ٳܺfZ]yҸhvtkޭ Od*C^%Tĉxl=qof϶t(@P(BND[gf\XXxWPUo[jMeWW~u[_VK}b]:QffBg,&yZ+FHY 鶗oY'eJ-tQ'J7 %}WxqO7-wyGEF` ߠq}dNTZNKS6uX"ŨՄb8pߦo5(T>G 7JU)ocf5s#<9eYzmC&eGKJ֤OBy-RY%ݦo}qYHd'\se:fkYsМixKg'\_tXYhȪNh* >zTjCS'-ܩV K f2VD5aٰ4cA֡vd,F+풲p5F,Ug0砢`1_#vl˖E!<(T&| Jmn7:P,.!Lpuy4IQBe Oᱺf#wr5(VYǣ5M-zKtli vK3f4O'uF;! aB5G"z@;#L;铭ZƇ!;vc Q)ɖ%Ԕ#"1ti+p!LԘRojEtFT>(PM/ SQԐ}Q7෩sFx.]u A/)BWuD>{c+5'\)ٚ6ΠvMk#yӖ)(6tDXqԤBtV, ]PVt)f"jHjSiZWց@ `T>dDVg)Lfl^S\E(u E]9[WslJƦ5-k]*]6 [}Js<┤K/Dz ųehQR;O2{BP-+NDqYxgʅ [4\͵0*l7vb`".H(*W.mxs|U/uv) Zo+$_i\pI,iߋfP bh,b, ˊسFWR*MúLZnZV r,՚طs#[I"Mmk3 F;V2#c$ID2'Y0$+B$G ozL! ˋh0yEo*|25N5i,-cy#jjhAZP@EV[:4b:-١n0cWӡ׼uV ȨNM2!wZ2#3GXe3ybetki6wbδ NpLL>66Æ>67G "v4KxS爫k<&:^uMj5|7;JvЈPO34W">ά=9ʑrt([D?v<2oߝ\:ѧ[Lt6<]^u_= ݯU{,ohUXwZ\$Ȼޯ^"тJPBZ+lid7Qk)AnO fj!*~aJ!d!c16k,2RgHNcLXY#J"Zi"82b#> $Rb%B% " B)OGTܶ%LԵ)oM5E])]-.$>}XÀmh5VEc ˭/1G¡E2ݗ((B FDZi:Q!a"q&gX~~F))'D^THj#E!@:h/$QPF,)|>,&BjV>)WJ6df))*I [>(EG@Q^N~dVfiddJffpg q.**fbB*ڠpD{jFQz**z%z Sjx)e]Q0ؚlNђỎ\밶. .@ņhhvjDHtFjxB*OrG`lz꧶ΆⓩNkRFkjNaqFXkK9PL)2lƫ6އBlj#uJbGTH5\6+*ʖS6v(׶GjiZjZ!-:)̢>$,mU*X:1ꡕUrM0 6HMD^^_Fxj | (O-zm--^҇*/j$/6/F6.Ў ^/_kvfo`^*npl6*bپl`1Fzmﺨi "/k%&0~DNق;XEYIAZoLo.I"YtDn>9l ^+3pAn]L,쫦cp[( B-咮pağp dv1i  K\.r rb~1kzD= 3Xy1%O[p'İJky'kh0 Dp;B1Ppz{1.G20#0ZmxWrV&gk"1/eΉ >??34knQ@_`@os~usEI  ޑhp8/Ki3-fF!3LSK&i-)6oK"2D&BGCԁDW/E/uNZtcIPG?;_Yb T-<7~HĴXuB^1u?;2?uAO[{ P{!a!uI[wEWNuW;c-0K,P, V55H8dN\b6E D5<Y9NO57r`^v_J 0$4C1tZ*K,Lcel6p糥Yeqrqwv1x4jwa6u뒞EiW/j6PMvpu7y3Etj#߂m\/ `PtsVQgkEy+x71O'xg&z7fOy[r'wXF1~W;5+m*~'|q u!`5}wZaJx~~oKdGN76'\L{eq䥔'L7E/u yy&9Ke~3X\y{\ >ͩ㹠n9e~9e~x 9bk߇:˽ԣzF>?o^#>S#(FeρS~,nt+x.::|T~x xoܷ:~|Qɽ$ 6# &7:fޫދS;wSF뚾|k )R=Tཛz%@Sh@D⨱^N܋˼;zP 9LA, <Ю;%5պ5bk:Ϳ@"zK("bX:m)C M)D}R-K̚#)L!|E5mF*#WbH!]ЈL*˸T9)ӭєIJI14J9]-#3A|4䤱F;oQ<4$TA 4XSMQx 1MikBt=BzIJ G=6oaNx!,`"Fs6\ ~ v;tD!:v|*< bHbI\( joWؿM$Rve.?Qua @dFwXG!b##H9bcZDȊ2` fH\{!GOWTQ!mvFmÓÈ@QtYYGYrde"8qx95_2 4X:|Ζlf35?1sHYJGBzE*uhx3ql,M8W^-dj'fL/=r OdZ^R ]Lj]٤UEy#<ˉMhb4IN3+<Kܐ@Dj=- jE|gWRpшiQ;a4qR 0Ԗ')ROԕTb-*O8zR;NVU:qiixF-jJj֥. y*TKgQnjJVkgԫ(U?4񏲒U3c=)Z])s% j'ZԵ+ 3 KT` ~],N9An|'eO լYZ<&A¶KwmM+8NΗMwc"6S=nbѻŬtZ]8p oɜr:ML1z[)0 aEĥ쭧TcUj]8,1c euh8U۹v$ &;pɕ16b.vEF񗻋߂ݡ.o5c|/ !}L usqZ=@h7^)OAьh>s-]|wc.3όQ?º:9@q LFѼ?SI~k`zvrwEwbҘÌ}ԡ6%fFvp!W6MM vBvml&ɻAR7-iv&w-FᰜqG=?升v}np3?~[3?ޕx 7f;߬iLn&ӘygyϽ =K zNqux0akr@Q:*v/˕c#fyUC 7ҍtsǝu;~]=:Rg Sbq_r[pL쌕Hڿuj7`oAkZQNȒ>"WFb=~TCtX\CX׮͛q{ V*hUPӡ˾n|?|~ v+CubC Ĕ%zHނ~W EΘ'*X(D$دH /EpZMAiY`׮O'7y5,5blOHDR8NZ bp Yb ʮ1P#ng| /  P AZ0I OOG&qI!1%q)1G0/ðo^N>PUJJ:H&i SaXBy%nMI11,*)ILj)p#n|q1E0ai (28$Qr4 H̀ qcaO C/¤:AjFfq.F'qjiUN'%*Tr%Yr%!%]rj3rY&7q+:t!#rr H̒ތzb$)P'r."&r*gR1H2T0!R(޸ ;'͘@8mh)13x_:*2/Y i/R0Mްj֊ ¼.) (E@/133-q Rp!ss4&0D3'{bN ;2BH"2ts7[75 Ϯ@8 &H0'ò9W OΚM6DH3@2b7;3<97N5RK+<ј+kVKxB2'<t@}&!3;&=&=/-,T"+5cO ҭ薠<@o턀@QTOS!R4JKSK]=7JIS:ŏcbR^#r7N44OQt%Tk<3C ~-Aq4LyM)ogO15S T%A4GrQ4QL(mRTiK ƒPuvMRv(SuO4Jt]P2XSXUT#JT_RrݎʯhI [OUWuOC@R4TN"UTK/\u=5)YMXc'1`s A[VIv[wIÕTU^gUawPXW^=5Bd/SR_/̨`EvdU\TAub9:SXSb %Ub MP FgvOрcTe6^W8ebCnfEQiThEr\Ӕ Z!lAdǖdf#U>29o2XQτji'}v`գռډ}qƵۡ'}ͭϽ-Sߥݝܾw}ޫ=V']#a^E`&9-!5~'A$޷+>1)B b9Y=E5^SY^}!9~!m;s<'wg8l~^~}^);iYD ~^[YԞ~oឡ1X5>ٞ գ;30Ō8dNe̜;{ :ѤK>:լ[~ ;ٴk۾;ݼ{ <ċ?<̛;=ԫ[=ܻ{>˛?< ;mricron-0.20140804.1~dfsg.1.orig/html/images/meld.jpg0000755000175000017500000003571410476414432020056 0ustar mihmihJFIFHHC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((mo"F!1A"Qaq2#BR$3Cbr4S%s4!1AQaq"23#BR ? f3\c1&\|b?qK ͑O p̒&qU Kkddz47ˁr%Y -.9pj(aEN>[e q\?ˣFl[iTDIJ4TY'2kX_WBR&e&,Ϋf)Jֆyk]2q1X BGNb\3]=,Rpr:ǗGϝ%J3?GȊ [625ᙢAo@y?b-[&*;u7VnX(ZAn8?Ԩ 2wļ5$$s^FA̴/h:ꑽTT)U$Plp߯0ddez랕Z]JFU\sFW])ezI+$w6sD>{Lx ,$]r6Tv̇xiP+=u'v,"R-tOMFb7k32t:2jK6Vu-\>t L[?6nQ2- BQ[/$ܑ=(_ <K= ڌzl7-Ѧ)ta3ߐ[}Ǝ$"8qdC !3$VRW5iLA$5V-1{,XX-KLGAuHayEdPJCm:~ɿ\,j1d]?0BP,)M=X7"ǦNXJIqu& MƜ=f?N_u=+D֙h2QHo/uZUml0YC+|>>]aR0!/Rb=>9z^wP!>>xP>RF=V]k3M&~EP!PX_[Xɜ 8Yy:a?#u0AC@"#bnjm$@\$Ǣp|WGIʐUvf'/J Ï8$X@؋o*|̩fD&gڬ,F{#Q+s)¥Gz%rE"]kbm.6RJX5W*fL5"RÍ$lF'!̳Ŧ fCCLIˮſvB$N-\fA<8堐0u8Q1ڥQ)j::Kԓ *9ְʜ19GOMnߕE$L3) ;LԜ阩48%=FYt4\* `/MuDjR UI:(W1OչmJA]1bLP  WTϴ$<O gnlO͂R}C aG-D-cq4C<&M"6IvRQr3jW^2 0Y23O CӪ}!r?y=w`Nk PO9B@=}EFND1V\u YkξŴҷ[~dOԧdhڜ ?X.3at7]9*vDB2͹)LG[EP; KFuKO H?W1 2G&0g 24ŪCm*.-.|#lZӠܟMի)ԛ n6#JK|>32jE̩nQKD $|ȶ8<[R*J"lR2c% e B} 95|Dj)ޘ"((s.P⋒N)UD)!ܦ3QXq(+pO'615۲RB8[d =SƧƁrڀe6zvVS i[bhW%2?8.1`v%Wzs0SMKᰵ%i*uWRJ ݓBJlmnUe[w<օ9m ʸ&Bn~qRrYIUY6ƫ\i^rxz?'I겤yw7( sKR2Ԑ brS+gv2! "[VYSe!M$\Xzo9zrƩ֮V,hMLlZӸur$E:J>=:%FQbR_n>AizUJ$ A\P|.%>`v#pG j^Fġop~VB}&T~)!g Jdl K?1JnTgTbR#dyPKhINTĤ v#z:4CLS^\g*QnBrPO͸QƝnB|Ag lbotkF |Y.E`?@m̻Iej;<:4k=},aCił(b+E~zbW;wƳ7g8シUg6ΝvWk6T[.& %CQccRb;)D$c\+cɨ:7$'ZTY3Ԧp t7 `%̓$"m`e2H@wʎ6u.G6u-JHGBѠ;<θx^sbuR1ͮn7Yϧ#RB\Ioy Z?05ya}FĭC% eC{$nzCNJεH;* crH8cp5UT#Te+Ӹ^~%JUnSIcRA#B~mf.!"5)-}R}1D@RJq ,p;ZG(!7))$60K2cyIu| ׹qb0 \;8i7BRbF=R߱IiMFͥ! b>:+vmwP&l5m-yzL*QCFnsQPgR[7P];jƤ)v0)Y@O!6RG+.bEb"$2 a ٩H#,3]rӛ*-)wG(گeCH %rQz,l;v/1?Ҽ;>˝d$4nTc<#v4 ׉5ɻm2.\;"斊ځif?2O'Nh3lw UWg0%p4~u/=>*d(hX[r>jQZ1Zu\|Cj:X)ذ)]o1\Tw(k5*@IMLTs Rsm0̿PrSn l/pԹٚ VZs' ɆR*u?LZ ?>4%&zTPn)GAw.W-\P=z T8he?d:Vœ #x?1Jj+?+;~eCb1qAbDH3K5YàxT#ЎQc2\[USkTvD{:{V;U`=LJl*)>Gc]B S ez㠲]5Hq-4ϙO"겛KK"#L2;4̧vJLdPL"oէU6JLz zm&9`R nE0_J-?Fq@ehAf\P΀ڊ5=-rQsd- ,OQ-oxT6* =~"`1o^}q}HG,wǶãFK[XgZt}k) %"]U"+jtxFoK\}q>TӹDBl[IADp'2RRt'Wz`%enHǚ9&[sZBNփbߨ#៍K42CIpN$0+- ,nG:&46&E_*usfE*}[ޝϾMy2HBwÇ+,1>P=G5HBWE2(Gv8J?jTIR;\O|-$ҡ0YZ0ɹSJ _bu.H ?-ol,gF4;oܦ2[cZPmc}a )vp$A BueRTtj%Rou~AIn*U.;&U&% %!*5[ϩ6Ee)L%AW[I23͓)8j#תѻi rpŇ= qlHr$9f)zJm )IIؑnZS6kQ|Y O Ey3KoPAJOIɠZAvZǪ)ybMRM:fȫVK+C$ -gJ!ɥ! ү.!"N`Gb4I%e(Z>[&\juG-ћgLiWjޘuLj>}?pls{d oi?@4tQ*ql]`7SHMdg 7A$$tj T9YQ r8fjobdꀖmO}6NݱkZ^ 5s#l?ͷ yJ&GHNS~}2QbKk^>q_l_~iThrg0uCn} >xeFw崨#s[p-?&9郄q%f:Sӫ&I[s 81kRZJ !IY7o_\mRH %:Cƫfzu9VuA6iM-H؍3gQ6jJyҔsD=01TP^LǕ>-].,%Ǥ\- f͇-BKNE:҈w1`nʵ(ה$H %$˗ӳZ[1`ce?&oɴob:Mn}re/ՙQK~3!hZ~lsT'PKgY [ TSDT\jci\[5bWrNܽoPxsO+8/4q R\]b?/ԩO)GEq:V4CX-=*8l Md)s^pS>#[=I@r]̴i9Ep^l=EȿW *Jd>EF(TS&gaDjќI?NeHp'㥱UdhT3tdԔZYF:Wt-1oRtzaw6cU$=׹Yi?䐮æ:¼ {cb064!lUiQ~[~3zNj VG$ح]INNnu*V$VǺH^[pAfWe*LuA'm`gqar ҰJMN"I;pzvmTZi&PIo2+*u>*/  =-a)#r]C0zo1KڸaդN,rȭ0NmQqm *{|p ዆X/{z`A1)KuI֢ĢPĉQ~!$,+Rh)_yn( 6e?:\M v/8RE-ޝ]-r_oá ~GۯQ~"mbQǵSHYhRA*u'4 BNCSTV[԰48gAMmʂ kAHABq;zWWQ!pAHFa}H8WE1GZ&݁N[4ԄC8dBJtqt,"yV+je%-)+(rQ)~qjkFO\ 죊q۲ .:m'*8&򙥮%.ŅaL!./p-jiQRfHNK hg}J,E3IM.A\gQ^lcQ-ݒ !91w8:NtKqmJS51J'_٪+EnCMWrl-OnMKTXJ i`?8[䮫P|*xLU6V*CtNxBżV 26rc4WXU-^{m_ksdy `t,[HkZﵹ;c_$L{t)%x%heXF}@ȭNn,\]I)ȷLYT3 ĉn%1|( A:5edn*7lo#)SklCU34x%Ī_A =5:{.{ȼr7,j͹ xM +2#YlVW?|M~$7 qҥ ,Jϥ~c2T\_Bϙ@ԣ:Xcj6CJމ\EJ1jnTJ.ܑṿkaf1Mqٮ#Zw "罽1rt}M*M# K:IMSh:2}J RqJ R>{wШi&H:kWm 4sO6AMcXǚG!PQ R8JS)-Uhj=EspP&[{bއi!ٲЦJ_ V@{}`j~_f>zqWPc뎵 U9Qe|$,zR%$\#=56ѷ|"Z=OA+*%CM`<>}Rٱ=d\}ǘ⿉N'uUê 6K> Ά6$IK_6þ/9]_M|ccʊ]mAhPA8p&Fp^*'I< &sS(6oܻktDfH\U2GĶREǘgs†"ȅ#:k|TđZ& V*ƈ}FSuN㺼Jk{_b[t4x Zh*TD!}D_!>@)?NXA~\EBF}|ö>H*uس4p[BR\־:5H],1P)i )v[[@#洕m2~նt4Nm@xR[Բ!-=fw0"L<}p Eiu?|<'5XrꃊY 2M9C.ʌ%mqPRދ;wإWJhs5jvd;M cI(6qXTM\lPhף>S olul7S ޢMHM:[NJu!$@{Ƙo225g]:5Z\{ d A׺G'H6BC Jm,T썏Lt>dnV f0c9nΩ .R;h* nco<<F\Eˋ)&NSbޟAnطgAsRi 1:#g%!V H-%>-nHgI!y+,;6  BLL0!kOqB~GUj\MnmA:rW2#X;zXfUIF6"6>V)֞1/.ګ=R̄ө7Q= •fxЏةsTyl\VDBR7k$Q"U\d$VQ?)%IoSZS-h6noVd=ߒ(|zey6!gCX8Y_[E20 ADi:OP%6TåǢ$[ҏ5 YE;'Ìԇ0-\'ر8+bSi~rRS _But7달Q)"q dm>/*@u,I!WQGK'Ҥ"JH `W)RXqC֥Ǜ)5MӅ^iPp˙n&5%k6$]bAJS)ț ï9"BWC'r&wĤe4ܺcn-TԀe)WZçlgL3SABn4}ec.UCi) l5i*66=-,]OڧlVFAhpQ3^1*TWRUWmMf۩ogٖ8Buʛ0Ylo/n1%̌lmnۣFMw4ҤuY:qaٔ='1en|kT\nB5!CBFU3TϥOiǴ%^²{JqtiZt6M=Ʈ%C*ĭ} dEQH𛫨:l5 ~5"Z|BŷN>s{$aYҘťiG˸^ݱ^9LRa\L@M *7<N)C)X>5Dw >^F\>opU쑰?S.gCDV U.(Rp23SiMBJv"P8 ̬:*kڜB@lE".P뜈M̙$]n[8VR YP|=.KqJ[eHr2v dtQ^kRwPRP{0dV&cS@\ro,MPޟ *NkRs ;묶r*:T */kvCK5&2o4(uaA:u<71 4 }$#ױ\G*Qr ]Jbʹimu}Lq o[^Hj)-{*a|=P9(t ^*!qeIlT3]RVt*bJ!$%)VqF.p52wW,qm[A;A*f km%ܔw}LI%2#HqQ@7t4)/!$7ʩ"55 ʜM"$!ʊ9IMΧ>Sloy8!rY[(m8㝎 j 5TzַPe,ÔZ2jVmGek A%`:b'߯lRV)ݻ,Si1hƘۢG|` Wg R0%%8*^b D4HJm)#< %ָ[[9NߦWqg2˩Ye>ʎD݆y+'9I|\Ome2eܩMSMtZ(#gpkr ÉC[i2?5|Bl=APӨ)M49{`Daft:$6 MX Lr=HP%J==}J5AX(9O"5RU; 2RQӤt\ePKQ#kPҫ6t )r#Ymnb_Atڍhqp`OV$ҘAEVch Pب|y +ӗ5KMEթ1}dI@oĎ&>K6*3mIU=~T5$K95t MiH! x/1'Ԙξ #n;%ɯ՛ Ci!=¿5gJFH!Il4dHQZbl[Om*(8dwS+*MezsNi9WzyxgMND*~~UM,O-W z\+fyyϊrj K56ߠŬTN1Ŗ܊y  hFj*yߞ*4uO 2m+/K|zQq4(P$Ө DwR 6;t9yb Hzx.,d;U R#eQqᅱɜViꊿM6eIKg԰U i(*ۥOSq!͑S[.S}Cmn1RS jR \SW0 ů1U6>xJXJR۞$pǹ{]49_Ԥ)RnJUzoIrdū˦2-*׷A܏תٯ2\VHIJ@'ĥl_, TG4UW@G|n[>֛'? Ko.>8K)RX͛UrTTM=g+3 ]E8*77WMl ꨳbȳ`9Zs%M #R{SԪ_y=UdFخ`0{é͢ 6OCpd;OB0DS_uCVgE[Ii?kMl q@ŧvJ Ms,[]fyqB@d,wþ*ZN {-ej\Zz\8qK$܂_B⼪Q2dQr;7GSp; 9IDY+9VeQ3SnBǑ8U2o_\@ʹdox1t|bK<ۨ/2 VZSb8[_H75UUaIaĤ"*Iwa2go#TT$z7!ѸONd Z*"ǡ$mlT~C52CRZ=vTE}Տ%,i2sWQ(QFˬ -`(y'ZPj-Τr< ` "mU3Z Skh5h- M~-Veg&(.YLTeU![_؜+qt4W2vCCjR%<)O6ֈ_P j*w뉄L~Ms9)-Ku1 -D46b9D)fI%2!>'Ы2ZPZQ6()}#» Q0eR`VTO4Wu*BZDT3L?zHC@n5ck|@B24U'C[0VJ)R*}j%^%/-M) )PlF<1(|Htt2"t,>#~ۗ+UW*SUԸL_`Lֲ+V[yq(+P#˶=G:xW^VMž=?L/1"5q&Sd)']q ZJ7'1"f3Emricron-0.20140804.1~dfsg.1.orig/html/images/lesionsum.jpg0000755000175000017500000005552510507015146021147 0ustar mihmihJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"E!1AQa"q2#BR3$Cbr4cT7 !1AQaq2"#B$Rbr ?*QRJ*evt"+@o<'E_[Pn )qԤp>g.*\‡I,&BHHs5 0@X-Yi}"DZ7\6H?A΋ޤ]e7rjR_O$( {Hiy|CZ\-ɿ8uDG+mO*NKP7UHmQl 婊nN^)^ꕟEID|WJTCDL/]d"4mC)!՟qxY-.06QƳ|LZyHP8[=S _ |\~b-/d4{nkZ?Ԗ`_ZZC**$$$ds_}Nh) ;SWt-qHLpOC+gf#e줎8N>AT5tjY IG~Iem9xP"*XP4/gV9-kua)kFkčg7:u.,J cᾡheDG#ukRڷ[+ЏWuTb+~rL+q )H8"AԮe5UW 1w?wPԾ^49էA DBU+$#5J(Tm2mKY2hբ.WP$mzt!xq-%rnm#G^k.Vc`|JCHBAG"-gϵ|)Rze\[g\FBvYDRJE*TDRJE*TDRJ)J^4,)ҡ|;]G $>*w*fUSKGd?$-o$-lkOYKβT}ޣ=}zt뤛&Vp#aPmyt#KJ9*BŒA\檖NR>--0fO)cJ茗eL.9RәS 䳄w+Qk X / ֈalAAzELfZrTfLbp6 5 (C =)z6`A#Q戈#˄wZrU]c Lp [os~[ڂKo\&q%YQ}x}KIm*!|69E 2`|CIۆjZR[ti@xϾ+,T e$^Tࡧ̰PIJ$0@ R/:VV7)Tgn-U+\E~=+>[i8>,c/k XA ʀM[, *2 _pH( Iu_n?!ΜsK#=Mڬj>i9∑tI>b!i%IGejnS?Q߭ CᰀAH1T6TIH"^^|4ru=Мg<4O]iϫIb$6IP6N0TC<}?ڼYmWk MrJ7 ^ֺ4z}Ĵ궶՝E"GZ/l q_z$w>4hݮKG!yc6w?SQNk}Ei#z j}VZ4^qNNq,*}hn2TfF1]w?LPCwfp-;4Do{' ?i ,5쌟,:^Oe\LXz$Tj.7ĸ'έ:W6\8:|g?DB{OE8eh\:ֽ̫qZ_N2PJ'Ab~GYq[3ZtKܜYJR9(./lڞSi*xoؗ"8zsaJFէ#{QJ(TRJ(b 'YJuA"dgýf6%΅*[x5bmJ] i*TdKUutsʂyDt߫|9AoM^ᒵgii+.#M45-AQ.m6{AC.'SZ99BR ZŸoǏ=ѧe -#@ KKƯʺyvԁ(S\bOVA4e丬: [GRAH*4Hh6ҟ894yzқCdr؄S`GVx).VX`chja*.$8S8gS1@)Xē ڳki \RlGTv>X <CYځtRc#@O%D r=VZLMsx;Lޡa'ǻH=kGR=kUYhg9^(xyJ|)9$SQ#inGi9W!g 3|H'u* t~9м[ mJW95p@ӵ A͒MYm= la@Զvz ӧ?^^İc}]H]λǞȸGۼ[:pBJjCr_o΄K[lvO|fO&7"GV=}u_EXWd~+m;IB~gMB亷oj(t6i@8hi~쏋yzol,Gnr~tTZka19-9J"*CS#$`c֮z˔q)lw[i};*Iޯny|F?X"Lk;Ehup _rءekϛ)g8'ֳkm/xvh- />AhnE !HP<ԮMD\ #x_evcω59QNvܐIm5^QIiI*$;%u@VFFVrrڏ3$|~]IK#oTaϙldg ^;ExG.yr2IWWG+U0#MֶfdH39ZwT45jFr>6Z9nے:d-\iZȟj◆6 `ϖ${TvҺO]uY4am#??Oj-e6Sn$i8P=A43FȲ] ccK"*T)[v.\q4 SZ/OݻIH-84DɼDEK@m/8.~')G) jR^XBO4U2Tg͐qC9z;yV*Du苦 ˰ā9nd<m۴n3{yo—+9Eq`X(ߒ+2Tz_E?*R8Fr~{fQ )'" x59p #TzT-mݤ6C%#'VMAm[!9'Ўƈz6c/Ozv.:{JP2OқڛhB}I;6X2T[5pmYq ^Q?Mȴ yܐTqc{c9*SrIRGhW[ޓ:[m,mPQϭ.i5rN%dKoj=? `.ͷ%S\Ӈ8_.if]Jռ$B֭tGVHœ\PaZX.f'Ğ'&=vbIB?xZ~RIYQ<7)Itԝm;Jig$IѷMxEJ[Y0%+%Do{uYnfS>㟨ηFK t9?$sGl"(UlX7X>|ա2fn eqzc'패*|lM߷$ OR@Vz剆:<޹Z&% qP)=xfCRi^mH[n6i# 8 _Vs3{PL~Ѻ:?#QR0qw%F1 mTZ A%DP3L6!Ԟmmr1<'%CB&{M93${#) ^LY-ޮ9MSx:q48gff3S=Pr?lʏSiSaDv &c.7caH;tXd%[ NOsTSPE-p6Ao\ZR$xW6vT@҈n|g>*NsTKiNdu1[X~+t7qz%is9BL_]EtȫS Hz+'9j{aBhkuG8p fWq\cHz#BOēDS ]q ;\Ɨn > ڔq!XOsNξȄϔC^u,: J@*O ׌+䦏;ݷTk -}cʒ9 Qz&:m#;L?䨿8ϥ.>҈u5m`m*=MV:]Xl}_^!7 ;>rRw(a#>aFݿ/•Z dv a%JJ&"8 y Q@ݑY%)D VeNlT`3X$lHڔ5ͶEdF͡B^C7-#gքk7~&3ґi׌ѳkm҂̛uخ.ĸGF%C$5i,rR Zˣ^jz][oaP}q⹏UXe/ D`(^ݱHinc=E4>Z%z)Dw\"] ˬd&SNi@4 3+r5ԆZ~5]*BwըLsS si~|d۝a>}YrwJ|Ir9zQDYև %a ta_[}+ĘҘAR?Gܒy~.0AkGJT$JCQB#=>}k ${k-ϽjRܐP) "]j˓. S$82 x54S1ZNO:ZkmH#/%7칏nJy[)R.-!IWQQчT=+yRPJqjc|.vAɯO"EHb88UkCa|k'8עcgժFtCo-CjzskAv6̤ps֍ڰAdPH;>-'>O|u1\(~W$[r-$,eahP<]c^jhv-\by'WN"CqUw^>֜~sFYr)?x#mP't@v6҇ ZPABIK ?ӷ[H:S Z"G)O#vP HhHZ[!%)Hq}3a41q!j%~2R !)Qqv ,LLjJ$:6r!.ę!jW+c >t]aYPZFpAks(\D`20}j0TTwm';@o!n?ڵeˮlRI}XRԝ:w˹Jp}H'su1# D`EvT .ǯwm9#o-2çq/RkyIK)ڮ5û۽$#%(A󯠖 gbK,zC:I^ԥJxGq7>?S~G'аD }ԅ\lHW֥4ӹJw${5DiA#zیoz*Z)*%%OŞ1|҆%aչ攉QO> p!ՖҞSѢG+%>v 8Yn-APJP2NoZq)Ո^b[)DcW:W2,ԝ'%/L޾^+ zs-GBc I_v;܅/C c#Ac&綖p9YZ{RƐ QGŒy<׽I`U.vV7RrWxn$}4&ݘܙ5MJ@R]B=(G#I ۇ<ܵBҫ}jÃ{VX5l:RZuvH #ҥZ) |@X4/PQM5-HQ攞"%ؤEdgޢ/qYy +m!rXqZmQV{ߴGPl>(s9WH2=ۦ1>9FNaI#Ai ->VzղN?$vUpECg^Z[r4;J:HR}iZI=+;)%I$ssk*ƍsQ40܀VR[@(qU3w1)=rCRVO|_[}^ J$6 =⣁ܓީl&ǧ)ʐP9ۊnkSj*p628s:qjַçVT@Zw=Ք҇u+&β9J8%Bw-j{ kQ\V޳Oy^x$i;ҷ2늆R )HĻ,E$Jhm@2iJV%#U/_i\c'ױLJ5! Ҏ>#-jid_ lUO@75an皽YQ"U%y~z{-!P҉A\UT6r~U~b7~uCCHZ>D>AsrW37l;~< ^J'O? `r}* yV[$F{􂪡Ņ{-eq=91t+x8Ѕr#%Y?#j;JH RA]i5KHyAd083O+C*RhikojۀK5ױ<7G^3nbqP!#;5uԺ?|2d jkx e$1z}0$]fIV:F8NOo;ߨ>Fv6{tZxqSJ_A Y'DU -ۨ7Qv8"anH {Cr(2i.RXq  #6e0'O5m [n+5U2+~vD!%a+Y$hGKIVVrV5݅p{UJ"U+HvR~ui61`!(,TirJG5seZb޶[ Wph|6ngT C4T5% IJ`<}99=h3]i^IB>c~ E'R`tV2ѝw*) =R6÷()= UR$))QHXϰkM6]SiQߌt% 6#tRS~?\Qˁ<(4 ℛRHJHL}kA'g5`Kыr~<s`j&2x9 ܩM΃|.p$|-HY"5)xcÊ@-!e)8==S0\U-,9(!^Fq'c$jK[}$4NFBSJn p)؀:Q/JpaOOʈ5yqAh&*N8+~#[VUZ\Qב(ijD'@ÈR9VZMEy̹(n6͹r$C~/%*NFEf VUGJN! a#PRַmMJ* p*W1MC$1YDtr\!nʊ;j-Lh !~"an?z?YN0~~xHR|D^*;WHjzfx-)5))Vܟ=~pS:Eն1)poBN ?~#RK`)dg%\ ULx. U18nNzzqST~BN_v9%Hl !._釤@2l R/r1uYDžwnHf/+\[YO'rP3mG'ҬJ؎Vӎ9+Mc|5{Z15q)P801ݸ{*^WJ2KIZ<xOzQ61!$&e:RއeK[kIRj&i$2?XMe$8-MŚZCbJw X=)\Ьמǖ!< zR%=Jk%sU0.TF9 {[tQ-ἢMrq}ʽ}J"tnzU%q vӍyW/Vلϖ{(Һ?m=R$wW!2ܕ!h>(NmiS%'Pj+{-ФeNA^7(Je+GϢ=;zF_o[}M<%‡Z#P=C྆Y(NE: ?+N7' l]2|+xp}DDyh](ǯL{UoUP;鵏5X~IKL(՞n&$ {!'q޵/Hn 9'QuҩǻuM-g)wmVl-yy)a sFHiHIqJO%|K|=im.t):C[f P1޷^ 3<UZpBr*a@<;)I?"j _,TS(ޫ|0@gEBSW?XȐ)‚J㓑usX')3w}Hl%ngQO_ C- t*5%kTJH+ F:+sܦT%j 7)%G 8w!G1DFR5%ĥIp~tJP c'~ԑ!-[mO'gQW:Ԏ?:2ZN*uw\RHBQ]"#c$cǵs"w1(؛ y[sJ#ܒp:ϊ U1MjJm1W^Amc=SG~4ڼSI mP@XdDV-ސBٙK'i~;^>OQYij%#4EMB[zq6!є=zQZI`#\0ٟ{r=E$eÖTi{,2ʒ▗ q@Mctv)>o\[HHCpBJQtJBӲn#GxJUN( k.tD\cp% ><ц\)m $֌C|QLb;h6 `}x{KOORƏ@7<|{iApE뀴U#ִV8Hn<Դ+c{:@\UJxݟTR`rsc;ssUKiY>.qV"8ڰ;G^{v*T_}+Jfo姭0<]t{K Zmi5l &P<6ta!Z”62s8im2~-_Bz%#M.raKDJhϔblj;xӖ8V0 >ǨT&^ }<R[n6*Ur S+"~򖭼wҕjQu6( q$G$֘wNJ-mt(w],]3GUJ&;ؐl3rW LbQBy\H##ʵe)*1^9$!PVp敵[p{\6%EI5E\e4PI$ys^RW)1+^ Z:3Nd6/ e\$DL$ ,фA!2g`I$nTQ@bkjiOv8kh[j6FrjL3!lV zWo%v:s\(!k]ڣV6m46HurzRB!2|E/FejJ6Zak4A)?d(#8 o2Rէc;Z=}ϒ2$+6"7 IQ7K-'U-I%jzWvt hݧZܓU&"!*9jD0֫䒠N(\E#)O. HC!V=iv_Ieє,`iϲIR<*$[Zͷ}^Ru/j\Vl 4y %*x v~D_ |dd(|Wz)bM}tLu_iۼ}rjVBԒ7 SHսgק.Q68vo_8A$GN i'!-(5xHJ;*Z76cX⡺VyN13ibĩRDB֚kmǖG9@PLp–\8G "ԭ VQ1ۚ=JYZ5db5MּuQc#Xv!Rҭܧh*{z¾;L]<5"b8W9Wm**0AR'oqX.qPRBlc=j;!h:id7[WQA'jp̀>GS.n;ARFy# U"%2Ui5>rXQBI86%B3iZlԘk  Zcȉ)RT0c=z"qc>*3%[ YNO\X}czHs\zfH榪z% xEIR Po)I>4d8ǔy+uu+W[0"83;I8c2wM \JE>FT}'*RJ6Bg}GqMή7戵Ko/͖RH,iwN(ɲ}JJw0'璢1UGکZ(+_%$ R?!YoӁi>\dŝ(g=e2_;qCԫ {TC+gn_I"ەorO4Wx&T:PnBgĉ($8ڢx$QFeԹqm3ڈ5u5-T=T֑f)ܨ:G:w Cׯ~4%)C?Gcو*Ex;'>-Y}%qmC.{oxGꗏ,#Jbvh\,'jVNy*^tuXBLJ?}]#`?_lƥwn3㮅%JZ~8?ץ-npvqz[q\jWJӗ#l2VvU5(J J[W' +\–qmHiY I*?Z<BOh'~;Kٟax>Ϩ?=hCnS]Aا;waR9w9**>֯i)ܕ9 Ҟ?)gBՍ4U1DWv\lL*QADm<Ԧ88"D[$u]$ 5'<ydP!SKFrs7uӱ2/kyD7N3K>Qʁ>BaBmqTb:[!kqʏ@zPLT$pO֬ d12E=V64p{Ҫf |8 JAT4\ ԚSX2dd%<5zm^aV'i힟ΰ>$^:Us[ #6Vˀxެ3ұ1<\tw @=jj=FŒĤ<|9#?Ł?z/(mO ~]^/soRIIVR>"\w^6mxqQ ~Ҕu|$WI#DS I71rǶ>4ν )́Ǡ4m}޲e (1 PB{nJIW_>9a_o:JRsj#H ヷ=xS[R2K;S]ߑ,!9;;LkVw,~uwkmpԤ<ڷpy&/dɖ(q5_3^Hڃ/T, F [\_%pKq@Ry5qKZDDZHio26uMs4fj-qQ'kkQfZe-ζUʈ)vSۋdjݗob:MK[lFJBY%[9KǮlAw HzHᔌeC&kmO;5I{j%/xWػsGOz^X$)UōeYLdI@CN($/q яnVG[x#>JKK.?cj&0\J1ҚgLֈE/w{f QM uU-{tǠ$[$[D^J@?ojHq]}>g럲&@]Owo8{.en]xl&;2V?w@#ꇯ7WX.nQ^ݓM1}cp#*#HNGڑZZ)G$K*T)RJ"޴]\ٛD-Զi4"" lFW uO&*yﮭ?;%R4)ʁ h=%d7Wo Êʝ 8J"7V2u`FG4c'y@BpQ͢jc i8YLyKĤģr@zOglXja艵=.0RAJ^ R,t|m3!Gz $?my´D+#֯ToV_|S:45JBI[>yy-m۰=}ZiW)a(>$u>g\}TD$g\n/]%y'pinxA&ZP6[M;i-uKmEs#]klj)ZkqG^@tUGHre9fLƄq)!8jHڔqHYfn15XR/!M<(R׸n[&nD Lz5|J/K_f!rԸ}hBȳj)R2$ Hyܩ/:qA:ݡnm!' {Ƞ7cϴIʃOE$Es[ /`#X@beۨosi--]q֒v%]}y=aX5pv1O өRJ(TRJ(M껆ѝ^+p] f N;%mZOz~C\.>Y^Wˉq-'!@fhi NV~.N;qKEѣnvؼ9776'ڗBqOI?ڰq,hݢȕ,e)##X-. ؠ4pW%{N*C,uDL׉%HKE;̙ ~gVT)RJ"*T)RJ"*T)RJ"*T)RJ"rӫG*"|;S5zfQ7Up2^?n\[WԢ-^. 2Wu]ZQ5J*QRJ*QRJ*QRJ*QRJ*QRJ*QRJ*QRJ*QRJ*QRmricron-0.20140804.1~dfsg.1.orig/html/images/val.gif0000755000175000017500000000771510513265060017675 0ustar mihmihGIF89aJ\4Ř <\ &lڔl|d4NL4lvLL |4$$|  $DBD<d6l|L|~|  N\  ̤TT &l |^$ $tjl LD f%|p| 0|8T0||1|Mwp2ڑw|@7|7|`_#`@w|@| | `fpw|`w $.BwR||=?wR|B b?wA/;?w||p$`E|AX;`?wwm|w!,IH*\ȰÇ#JHb$hȱǏ CIɓ(S\ɲJXI͛8s|3Ο@ JtaO$(]ʴӧPJJիXjʵUG:Q«ٳhӪ]˶R1źK]'gUW\IF` *^x.Rz+yҿH bA€=Ѹi>V)װaåp_a@`E`>"A'W*Gn\Vv;_J#0eŊC!d)֥[_uP (vpі 5x^\ A{%|u`_~h`!~Iߊ,ב-t&X"[%Z ~wن\6@ p8BV'S('\._bqX2j`A ږk~7d`PPŝU@Np7Yeb& ]f-7gyЎj(ᏲiޜJ9 0X|B )sFhzfԥgx>BROa"P E|ù`kR饢jcj疉kj pI^)%E5_Q]@E}Ji趿Έ*:\üJ,H) 'qݽYjBU*(̌\9ڧfT)40@H;L7ݴ^NGtRKsND`s5dmhTi_ֳ\PutmSޭ|vQ.La'GWn8Qw` K蝓醃Φw PwlfAk~ɇND8{x;;z |ˎϸ;CZ}CW?}?FHX"Ā#7@"s> y3- ~,t@b݃z#W( |(Dc KPHE!NXTm`2hL׸ dY縓 #h;:qy #Y? t0򑐄$!g)+7ɢT pDixg'w8f4p>~CZi9F:2#BxZ0!_.WeeM dҍ%/{`޼ ^8C{̟ser[S8Q㕐G:5Hty#B9_> c:og5WzԦ3JsӔ>'JŠ$DZP Gg ƻEuPQԙ0=:mNpyRP ,}/GFU=Ut6Y*rGBuHZ:(Y][*> U˫^׾ `K:d'KZhSٟgCKQȰMjWֺzEJn`ͭnw[62EE%.V[Zf$-pC2WѕtA[]^6ȕr]V䪘s.vëb9z/^JWeRg2_~{ ;>x-02 oʋv,CWuN4)ZXr }۫4}bwغQ͙`bX&qj]$W7ÑU2θ+;KK0{I2Ō'œ.95[y*NLE9G8=vWPuD)9xXaACy;8xɛPד:eOUㄩ)9`k\wHٜJbƒ8 x!b=;E#iXyɛrv|gc%C剆$i/#lڹ4rIAI<b46| zLJ.FD\|l\,0$HP`嚓qɍ9"W~9 u柒ɩ+`ف bf@ ?wVXqiv^g3 ˟1lbx%Yý*1h&CzfiΩ;_9?,2cH Ԗ4%G;rtzْ)_lg{Rge ?g p]-dx)[q'}x='ZfDIwh}ә8>Г? ]fGι/ZX*FsycsLrC-MYSVӷ[ʽ~8K)lܼiO,>_qzo)L`f3-_޺d Z EZ GH(6+b{ gHVhkáH"BDUJ{xzFx7)k Xq#!T gב+b1Z8DpFԔDeNIKЌʥR&y pӘv L?͏\[7:'XjR4v6ԝNdkto;0n"94IQ`ƺ)uNsb+R9fzwK+F͡>ȥ /T9-z4AcG1jfFfk 9QkO: Ns[%9ʁNrtfĀՖc6vէ6}WpOhCњ֝\$*0ֺ-=m7ͭnwX^lQo[ߊX[BMmr!\FEB+Ʋ5rmTxRtbz/COl£`"]FE,YW3-#5_9ekx%̤> ^8 6"qM3E1$c2tMӀ;ٷ 6bPZюmMAN'JDg,cJR7AKMj TyA,Ip^aI E^f< t~)F'{oV6C|)M9;w7ͳ:@zb 7F":-#i_UD̸<=(Bp.!AfʻƵ"֋6ӄh:jk*ێQlΚ17hn|7(y Ϳ}~w.p:8Ÿ7#S83 GN 09q瞧梽9-#>?#ЃġF?zӥ3]r`l 7]On|GWo_''t_uط/zj+L}v\'; 3}<1DIvvHQ?sϭ2ܵ [mN5=-w}*5}kQ3tA|)ŗqy~=A1 J}>=3@yLkˁ(QՋ>.KÛ㖋&=owk_*U?̯~Oa?Gs?WsVտ*1x,r= (Bx2b}buh}CDvuSfS`iiEa9H`ŗG%IZG=ukK't{\UeT;3TSBbu X1aPjVdAH56!%dLy{v1V{6UX$tI؁zaOUT8WfDpg||v9M}gj\Fxd#.4TS`8FX}6u.|nE兴}C>a%(ыh,/!3Ukv.c1uŌΘXo(;q2vw(( cyĊu\v2z𨎻Ȏ8-ym؈cfLōx\x۸xRHv0gHh(\ aa%I.i'i1Y-Yq8)@v>@!ٓD3m xLZ$9n'[R9T)omVsYaZyCĆs_ieaCcog)D^dՖ5jfeG(%xP8_'%MXVAbidG X_Pِ|hfG`_@JD{ua/i(Mۅ{3b #󉏉wFLQt) c$iT`_HiNhljWiI9Cc5ygRX”f}iZdhӉTqTɜdiJb(M"qөhٞ#xd6`e{Swheh|hjbxx$f8K|bP'ˇѠ 0oٕ΁(B9mWXBk,JF5Jަ;JD8:o(n>Wn>ЊyؤN*)ҔVzA>zmQY\ڥ^C o@ĕqcJi}+JUWanRI%zi߅yyvKTw(uAsc|ڟy6艣f7}YvJj[PJ^NbJapzGy0uJZ f䠬&cUygGR-|wë4hz9S6_UkZv'8z {3XESAVB֩IZ ;:O%ȃg)`HJ5VoTgiuf*< zlx۴DIʬeV٧ޥSI;wQ[tUv9څn2i4iZj#K[+˲=đikqK{75ڣLXCV"ᅤJ:*yCh+Trp[!`k][v{56צZǷE۴++רZyX:)Y[(ie>ڹ߃%!QʯaIj+6u,ت +f/fzJT(;HOsj'y*w1«c,_"Ƀ׆z j򙆸+mϪ{*Z R578er(H$賕;(49#Q'{tx(y_yɴK  , Td#{MHʊc~k51S'3|X(4ֿGP;kXTy D} TܸXf^< VkKeezk\^++m}Gt|Z<κqzj߸Ņ {Ƅ||ȣNJ|hȐ\|ɘɚruɠʢ"769v<+ٳʬl˲|,\˾t˿x˾\̲<|3 \i 4?@>`͂,Zq|RlB\,vP#8lw\ʐΙϝ<(|*@X|B-,+> {y\ ]3 XOMZM̰љ{Y"-QSюCز\u)dz9y&e)MH1{6f5+ 4Y>=?tRQ@x[WM|Z7`8}QG}рХy©] mHMWֲ׉Бׂm#6CEڴիX\QNe`ȸژ8zۇO$U0?X:qEV\W߁r4fG4^e1\ h`fX5蘇(OH'_` bP~"H㐐cB_FP֤9W!ueV$`5aC_Ufht]fp&H'Ix{VyuCg(^Cf)jUjJ!Efi|\mXuJjBSF*QZEJk {S"hl,.6lQۙ}Z{-Y[JJa:{FƄBt뚴BQ0ͫP}/L p:{]s=\ k\rU[@-vկ'OuE0KC"<zhU^qF }2ݵ˦wҼ-v]>esey͞\HTf˽|QWch]R0䵜63aN5-7Z:,y7ykn( S^eg$vG8yST]rB :y۞\r 8PٳhO8ؿG>ի>#A]7s}{qG ʶw<@+c Qx4aG:X"qX,ڕIhPbGX>'8#(q>J<dE3qG"%{I\MU2Ў'8Qpm#äCҐo,X" R6}vٺZ2 ,#+!ɫHh%9G=CKPB+T3F2*GL B0oKBs\H n I-l.f4bnLP%MlӛgErz dJYs0)H+'B@Vr"O+^8%6;N HR"@M6qmj)y~)| 9U21䤹JGd59V[>6eB4Yj'1)AiMSop$Wq74ZUKAj35 N z7r`ڳ1B}\? 4:sEc ̜~ۑ[K{8⎤r96k".>kq1~vnva8$}x!0K^s$9C 0W,Mcd'e"D۸`o׹B~^{ M"j=z͐eڶ}>|^!\:DGvC!#Q~9\vB'N[Uǹ7y#$\;Cu&(]ֻ @[u7${;5ԫ𽙀ߺA%]Vy|ǧ"p濄J๩)sFU^uxW ;D'`GWv|if-~xӀ+Qunw~링<"z3q ȁ5Y!|b'4`E(уa@HY:FXHN?7M8HOhQkw+ۇB[H7~TU8-ae8AkȆLoq(;s@uh"y{X}8~Y{sbX8'ȄȈljaxHgF췊DPpԆmg (WhW| 8p хܤBXhΈh,8xa0%2x SDDA{ HnXp䳏f*!-| "3L7qŊg[| n[&׌( ]k,Iwh1c~5y'ғ.wz7dH<G׎NYp8x$i[U> rh-b(:ٕv^cueIgꤖ҇[\r)cxT:v 8D ]|ٖ"0)6٘;9OdL)RhiI &iym9A{ x%w݇ (/ّ }9i Hbɘh3|ɕ)ӹX\8F(9uqssi^ṂYՉzVT9Yi֩9Ij 9ZYMภ  ЉyU Ù{YxBGBWUC/Dggi&i@Zv"0DJxeɝa%ɚM8Mo`)d2KZ;Gckio tI(ʥNzf gJlX ZJhv_{Lo(sRx4^)J2tva_:j!"jHhZ(,p1TerJ*B 9Eh$StƩtê 誀sݷ 8Y^!Bg6ʺ ]霣WtvyLZ8$׮oʡezlY%<ګ 񒭩F&xȪGʯ~+sEaĦiXqX{71u)XF{HF8 ۡ{47"dZLKey"ukLjO2K lKb]Qت4bJvwؙ+ui!x0|5}{8˥:E!ָz_[~g!ƀK*{}D!k@P %k32KAJ\ B'`jPzDzۼ̢ +M[Qk{ 櫷 &b[Sq X7'J;I;"fe A3|#m;٫˺'oAm; uxt ©N Q(*K)N! qA|IܿJ APR[ Q c^Vcz" rZA_r#ڢ.Nk+qG^6A~3ܣA>1ѭ.ۯqX ~SOqKsgO][Ks yf#>~$5(mndnIlNӁ~C3ǜi-qMۿ7p2o| &T ƲW|t'|\ }C~8W| ??€i{A}V6vW,o_ǥ whUN( +py&~} z_֮d_q<~&p S?{,GoO/j_3]{$u !?S \VQ|Oo7\p2__oWlOE&͝3<  ^Oٸmnr? @ DPB >QD-^|Fjс ((H!\RL5m޴N:y@I* $0RM6tgԛ4:(`e-i”VX uyՒ&MX+ǁuDWޙj܈*nM&ң@u>_){VF&hҕM{B8@4bI Ɲ{lkxW|M@2F%`lj\W{&" ?/̽> ,?oF MB٣2 p@g<1Ӫ+1Hi$RBBV!+2J) :2&Ш&pJ/r/b1r/,2Lq%:M;El˻HbHMK?ESP\TUq,3)\V 73lB\㍀2:eVad]hkim6[WU0ԗӶQM/-wW`k7DsUԺٸW|Jp)%a Η~WS/ݐI-}#L? Xc25N. ٧opQD_Ii$po/\#wGww>x'xG>yg{rg|5B<{?|'x'yW?s^H秿~~~_X Ѐ$QVʕdi F *dʹ`r2 4 B9 c3kZPz-k/xdG«Jd5,JaCЇ?b8D"шG\Ђ;:[)'3e xD1]C?Nrd(X?62Q[-9&<4+ s_3+XfsL28Qs/osU|:wVgg?7- Vs|] gМ3O/Yb9 i.ʤVlf[s͝2jBZ`vu}F#ԣ}h'w͂&6S$bg֢^1 pzef1R;8wMDν6ima^_s L\7x˫p #>qW ;mricron-0.20140804.1~dfsg.1.orig/html/images/dcm2niigui.gif0000755000175000017500000001670610630074706021152 0ustar mihmihGIF89adDBD||~~||~|><<>j馜v駄`J$jꩨ*ꡤ꫰Ǫ*뭸檫_y.hks,`kliST,f k-KoXP{-#T+ڦ-+3cmҮY{j- C1QqZp\lVl^\фl7Hq \[4ٗ-kD(l|XmSgI} -0st(0.^(9)RlҞUCvR!sS-E)vъ5(穜N?xdJT4ln!%m _%Hw払n%#p/<[\kG|uy!|'7ޙ lV*we@lvs5woQb𓧼[}U> _6nǺ%ϑ,7|A/|K?>wvǾQi s\gHwh&6Y|Y :qSfi]}vvnCHqV|oo],4!X]+`aD|E7-4s]sw)z$H>8BW:}`DCOv,oG{+ЄN(W{Zc82|\eT^O\ʗxeb~0v}i(qq,s&H|h|Zexn(t@F&_~7}Oy& -Ey?W@IA?TJÀF1Np>Hh"FXFz$VX7]GP h(X\ĊHD8(4XJY3AݸGb?(XDADlJzՈWyT/~i\Vl,Kd،Ȋ&"A9HE>aTؑ~y<"w]#PeHulFP({C`C=WhxxDُǸ@ D>9&6.<8e10|vxE>}DM#"(LI$)6S]^^1Bz}xCY7[đ&Iyx7sU);`hbR(ThtA%VēIl" ;AC鑑9kȸM)J(/YcxLjs9Oʇ\QSH)ѩ+;ùSX=wrݙI))+ >׹0X|ͷ)([%̳mgr-D\z*96y@Xi :9Lh^Ybz蘎sb#: cRƙZI8~yUg0~f:sR0鹓MY\ZHf[%yVt77 .OQPrULS`.S{dLf>J+\j8j{jp6kK| fo9:bKRF~#/R^ forg>8ܗw3Wk珞vQd'CҸ9|Ȼ594d>F۴s 操jz0zpʉ U{%uvHyr֑Q `99 V{ VgYt\VS{N **!ڃZ) K+db&UKʱH Ы{J{yyFvWL*{dG wgIE8iB9)&~muVڑ=ymp׵ PL ^B.%^(!.7ٝ;1^m3o A⬗[ AXtJ> hC-P϶,rl|O@2LG &nlӰl~!.eO+)B%^ 7&P.ɕ_֣֞{N.梞մK >]!}븞7>Ѽ뉰.>аRܵތd}j0lݾ..^家xL -Dn~cyp 2\;yo<.7T˜H:(x #n*)ϯ)=>漩M,rLM>}I'_9C  =Bӣ4fuƝjйeZs!eSmL*ԭWfGt d)*_VNӉbN̏OoSO^ȩ@?K);>Rξْo?7fo1]O, ?2:6FG7;-C+C>NBͰIETU6J'ڨ)\A]\a^^@[*`e=f;ba_mjk_hRVvuXeZ]OeLKphAP0a>"X1Hn t.Խ#Y+X-Գ3kĉɞ t/b194vcͅ='.ÝHi^ O<O. 9l+:(2&? W6 3R7䩞Ӹ(X.yZw_9yu]es_VhX 1f\탖_F1v/oxkQۺ\b!grz?вӊ.fX{i]:Н&E;Wid;vX}=4yk}RLw;MrT{={tg|I-wg}\_UOeB{D xpCd 64P4z M4A J= r $!B( P:! B&+~.,I m|7!wDC QBҡFlKKdbD'BB_4HlQ٨X?+hY IkdcF81 HXqRG@R$ X;J`$AHGFdX!1+Q"K' f&vDDbu)[IS6TL|5O ߊuPt'KRю&`&id1 eqdxJ4{JN-0I܄oW4%RlׄN3YJy ߩ%Q#揼1qf0cmZJtfFNITy=gyP;`2:QS<'7# SѤn RTirN}&Ie~r%+V-nS[BԷsnq:܉WB6]nt[%׺MDv]ox1^׼0@nջWo}{_Vmi_X&p_'X fp`GXpa;mricron-0.20140804.1~dfsg.1.orig/html/images/icon.png0000755000175000017500000001243410476415444020067 0ustar mihmihPNG  IHDRQ>9 pHYs  IDATxyp՝?=ni$Ylc,``|`; (C͵!&#V?MU6]YRY6BK }c%ٖukFsF5HoR~}G왮w# f0xGg+UBa,B>5 /%P hC.[pZqEh]T]*e2Z»VFɄNx l@}=m'Rj~a(ą =ӦvË3LPxOeK}1(JzH4Zie_Ŏa<6}}=…3^b ;.okQ}bߢxKF&L<C+i2Jk-mk4vW%q{wipO;OR@@=XucT~Z)s6 iS}UՆծ=SД+|\ kd¬zQ+/ziTGPXg1úTMC+rf,ϛ_#wJyy9`>]Vg^QƵic=>sdx;`, ` inf,+]w?O==z1xdykZ>Yfd#ha<:v|tTE1- c\u{D륡@Fn;ms(O>y~h_\Y*o#$|+ethK]tZQ]-GGLfQ]M @ @S^oPr]zJcxb]qkM7SCj712)([};vF3$eܒ}NC(D(DGmS_OSSX֎#]D>x_qqA>,ZD[SD?O?KoA؛NCkUWh4ȉwTl|hv&hP2?sɮ˹s;GU,[Fmmfvz5uu{lV,*ꦓ |wq_KadP|@RzBcdpRsneS>o@!ݜ8uu|]Bc#5?Zʽ-^[C-Fq♷܎'s5`G3W|u낯X0~Nbd&',Zp)wY>Ç\_@NƢG1kW̦6t%RZY*SW!0 0>Μ 3KUJ n!*ߟp~?nVY}wc9{C2csݗRg@3)x p!I,8gK55̞p c^*dVҾu:ww]sgUj*!ZJ z m8chC mo_Td&>K0R[۷ _Q+-UBhjjq:rvox~ӈNd7C !O< 9*FۺzWo-Fy\8f DctxƩ_{q4` 55xc|*G9 קWW41l; Bu (odް|9MMaur ˧+#tp{%*N }7-_aolM .\ )ō76S鵶\Ni*7ivHXoAf$MLnDQtRٙfi[2R~_][hI#>w /F6ӟL20gE5irp&PlVb"SSi߯Zنg)TFK룡!ti @C5;|XQ1mJZ)eP)](JtsNf c|Fqi˙ 08xkхZB|WKZiR:g9&ULb` ҂m:.\\_R(O`Tɠe2#i4ӟtᬵ2x+/W<OMCk.몪\*XewxO##clf'p?dzNr`` yH*eT츴{͘r )ו f;&6LE}M##D"3 P] ,+5.{{=ufE(>PqotG13+)!qJB@j0f-nW_(6jt5R([#;EHa~Za+e5}ڇ7f~2bFF<6iYX=Xoy'V1鮭DW|}kV$Bp&i[=g~ᗐs<]~.9+i3 0'j\-JkRcښ7UmG-WCozU<@3Z iyHk"8B nb*B #nn1P?K E% A;.dȤԸ5K׍ Лz~&,ЖPR()ppU| H44xT8 ǘӭh`/!bda JgJWQ!\TvL;*u[JR+TjsS'k{+>C{V (xp{K(zؘaPW3S3K:f\)6G()\Q}lM_=- _ 'b,oU8_ A@TR)#RFX$@1]J%]%D IJ%=//t{ݎw7C#/{XNdJxiW|GyFEnғo% }{ Vr=~X?y| )&Q[?O\tL,"Kz  &vzX&xԵ DrF-˅h$q^ )d3Jqa-j#Ӈ>Bo;Bzz gU@;ٷ~`R:4{"VI=6U2\E)qG rnߊ0Kpg"T,A6J#|smJ翊s=K\Hw#ةW3a;cQlluMKkffB5H/,ͿI"y2e`)^)yb?Kġ"RKH%h>Tԣc 69jJ7꘭>4Rk#+a8 %+  ]v3)yjdഃ( ּ֘ ݭ35 AV;7q;@F&^/L|N(z.kCZs &ûJS(֧IJi\j:5]EsjV^jV$ck qa 7tZ]P9 ,%쪽' J23s6ֺ7q?> %% b|Os8 BB !BB64d O@\!7oJ4Mi|-m?kvBݏSll#%:̍B@׈U'jv2ʼ:KINXgklp5k\7]#]}Ki2Fp'Ijm'1rWכOPnu*?N/kYgKS,3=v5<*U9}<5fR 4Y8=CZV?-,N);@<-Ik2JxʶXK ϕ*JugK |rfO@mty{4 +h%,:[#pjWrF 7.z~vpV- TR]=yy>]B*#bv4'g{7ZA?t g8eWc r{.ubxh> 18K +ՆH tFX0PX guNJ\,ZёR{SjWY;ƲWy+jˢ]O KZ|n1<8# HAd9IsaN4d!BB !iz3I}I{=CҚ1. MYNִ1>ih$=CKX9 9MQ <kۆc-D՜}Ӿԝ鑸Z<6f%<Ql.ul](:oޘg7uxJv4EfkZ6A ]@FTfi+%o\ch3E"y[N_~= 6{Lqp$-nE Rߏr;t܁ꞙo![;V6d+Ρ.PQΎhӌU]Vꐸ6MҒ|g&!!@Ba0\p[vfxhrQt~ѫkōxnO8TeEv?u+!eNђ0vd?W&=Ik $m{V *]#9 ={8W赲;YIUNf`T1>p,{ |v^|h秤021% 44?+Q s;RZ.dl<;}BSOtidmlc}U#lGZQsq,X\]X֜vsoӺs,-v'T ~Yd펍~UA2ӌ,98}g q\fY EirCMY$y$H%xyĪJB(NDƷ`Ӕ]:9dcAp򀳦W 8QQ) -eנ|6Dnҍ G?*HתֿW\Zs9Xg.2ԱdM9c"]imId}X6c] qlӞpU4<moH[m#Cq5tfs,TLF8c)wgN%;Gl~Q_m3hjߍCq0$ʿ%'j"ÎEcO #餔;T_Ql={vuo[P,'$5fw-tTp-=©PerkRCM.58aygkF@YhK.>ҳ˻5*Z=ߧ5.v B"w;z6~鞥];c'>WZdӭ5=n3Ǟ ú8T'^?d\c k#,lpM;=p/yZEe# ¦tI컧%6jn1e%о{6s!SKk][2ucbtzvVk̖ 쯦鍍w.*Kzh䷅9k {w dž=jGy6s,rHI2rJ#ZHm/f? `j+{K˕L[&H ǗU5WՖ'ASFU]e6Fw2jcZpBi>~<|tu l"F-M.v ;i l5j5/[>+i^r `nv1jk 9PzoMugb`6{ƲG@7:6% XߺmYI^tTjw# 9[$v/K&Ϩ`-is \wB VWk<)Ylv=lۻ+%R+ݨ$ixsӂޒêqYΔolsTs4 훪t+X <5eoZfޜrfGFe,7ՄQң# rh~9Z4SZ_P5(æyT$S;8'nS)wUI[<`=jh pf ֒v47s+9 v4y%sA{{Bt66(Ǡ _e7GttPZNr@9췕%ӫT̄52='Do" ?dmrqJݓrI5Cࡢp䫪: gW&pn=3u6qhoDZj*:_Mck2MqhvKj|L-o]A+Ïm1Z}E*D/B7z©6__'’q@2Sݫ,oKϮk|=J ׸Xuމ#?t',oP3 pG%vf,r֟J{wmS;f?fL7OM.ӐN8]_:C q;4rY8sZh.yH]ՉNzK6oFASVXe.)OTM[x#CԖ[l1uQeg MQt:ԠGYo0; {'֛Ԝ}FwOd+"c (.rL!p{h9w:\5 uwrca! Ko6 \xV._#Jtol\~X-F'lBBC LU4RwPkkz'b߱ĩ-Pdo$kgu +aҬ1)M\"ie KYU^rhiXt}ZK,덜'+]ckC!3BA2G{ѽ@^Ϥܳq\aM=?溧IXRrcPYW҈zqR 8rMi89PtMl_hssXi0r}s ͩyrm(cAOCpK [݃'%[%ԏkyen$8.=ڇӚkX2VP܂oɾK7VIhN-_5{uZH=)pgZ88wL\EǎG6|՞# CML<@?IjanpJgkN=&2fA^=:;:.-!2BiWZvllO1FX&/ۗ4LÍ,'G1R5N \vṦfg`H+\G^pFXY{k7裷jlufđKl ,_>=yK#uM,N5O( ³T=ڰ1HMMm iK# N$vnpltNtK lns77 Uk!2,sW}*PR3„\l>Պװ97ۚFSꚱ=FP1 q(VLp:k[F<UnƞC﷔P3WvF3ZmoHj?ci ;-&޽9j<_#=-/< a0ODH댻n.3ȇrC;u[+K+7vYm#П[1k||47SlVUj[|ɝjOiy])ls g\`oRNs$.F8ZlWk^쒵5~x3W- A*ڎ-DZ c`aqSL rfjy'.xYnouӤ$D4ʒǪ,5灀GDȩkhz6mn=j)Kj̮[ ? `azA =6zl86oq1Vg}O놇w '~B]#N9R<,g{[G 8I^QJeIkN!}tk"a JЖP=B1h֛f(-p>xO5*ϱSRugjrpjyj21>Ď^-G!5v<'We6`|/ɝ.^I>7ʫ-Mp1(DG+F!z`gTG`W]V&ԇP7@],8-p] 2G#\D |puu|1](4:ёtX89>i`.ezF#폹]b̌22 __Fޤo}u+,N?Gߞ]ÎlLقVI#H;L̃<gѣ7ƋΝeO1n{Zq WiE$شNEr\hkcy`GO{ 湠񅃹nƌ?u8$9 Ժg%?S%{Z}H1Tn)>]hp˨M+UDmNSk-5E $Dp9@b)WQ#<'QjWݬaw}I6[M)i Cݔf,1NY掟#_,@M&KR,=GQtQ0r>]&FI)K%ݬ;eZ7\lOθ}{R>,B/jf ބaw`{Zj4F+okLצna/lvap.6rj-΁T6ʙӐς8 *? + plqT3F"{s#UQ(:WUza6@[pPV8H:fF.ݜqkuj7l9YA;8;w?NA`h bq^9 QV㕑I,:GrN)1pk@1ry?YAB8jJW ER*j#U3 <=Զ %l}WNf'>VՄpjM2j@xwF|%/isAD] *wX.i2zjz2=/Zu2a<'^l`@S3ϻ(LMVnv.U4qsWیGB ;?e)\+ #Ν#K,!8w֎rkrqpVb&%w>Bq_R~֒NiZb|agYs Ʊ/)tRJ~euxT1W*;. ]j^W}{#-glWASp-s@yMm[4&G'f3x!О1Jy-JZc%*l6|+;T|O,O!qZɝW} 2mߐӖ= N9.fyL,mn@w?'tѷQZ"BƧˬ8O__4:~{#N%}sX#P~KMT }^0'%DczP*Dž| o{|5I >i3/_F.Ul^@PBFS`[v5 Z J3;X}^~l8 me9R:v,aevnՖ Ӑ:˨tq؎;.d6(-Yꞿmw;O%^K$YBB[w}"xq= }+l1E p=U0e c+~N,5GoVl%č|/c}̫/< sc*/Sm˘ARLbp{kiZ; jp|fCo!O S9ROO&"N.>սIƷsNU/FH34w׎Xd6Kx+ܚ`浸?*8m0Zq fۜ ۔R3ODn򥻗w }Y=(qbN_X | tn KNgva~ps;V|m:c'[204pɧr܏VZQ֑gO[/|^0yzMҿ#o#gJ@vb'Z2smK:-MtlkwB{1bOӡsC/ZakpTR aM$ɝsn&gIlLJ%\р n3xZe4b{*GNP(:iݜpܒsI #Hx`qr=I{Y3~7E[УhQG=?PݜJ{.q? 4ښxfYakZ-x)S, |^miwʿ,p8UCF7#ђJ/4hr](y%iNYt!!@B!!@ rSɢ8sJe.Qp Yw7K%l7yZIBN9 ̊v kR? hRWP ynU{+-<r[5H8WaRhbϲ7 k?1HZdlßZYqkZ %Wkd>3".spS{q {(- rXi2$i#@ld< cJmq 2| <@56KUW\ѻ*s8( wx@XU9v6zwIuiǙ^[N)pӸ}t3o%TSO80RUZ]3#V#u6g& :^)6#O=+^>#=~K4x%D !BB !BB=XN -!ִMl"cCrҿ=VLpZr166Gq@t+;%4J##? ~J͍Wh.V{ n1HۏI7K,]yXs縹Ē|I!,V%9L` FR 3rU&0K_ >ڝ\*kr~J !BB !BB !BBV튧0J aRjq5_&B}P}K6s璠BB !BB !BB !Bmricron-0.20140804.1~dfsg.1.orig/html/images/autocrop.jpg0000755000175000017500000005650610630065356020772 0ustar mihmihJFIFC    #%$""!&+7/&)4)!"0A149;>>>%.DIC; hR !1"AQUaq256Ss#BRrt347$TVbCc£?ڝڸ`1vyQ!<,XRty85%#l{![ z=w;8׍_ * 8ss:;Q"au!-GSbn F/d %RiOnvtrvcߙW+5kdSR9VqMVo= VØ`ԚvYq6 uD/*JANIZy8a쑷 )0BÇ;g -o;"mKE*B@8^$\%AG'{ ߷j=^QPzwڏzsףn{?Cvޡ۵G~ݨ~=z;GC9߷j=^QPzwڏzsףn{?Cvޡ۵G~ݨ~=z;GC9߷j=^QPzwڏzsףn{?Cvޡ۵G~ݨ~=z;GC9߷j=^QPzwڏzsףn{?Cvޡ۵Wb)CߛW'*?W<+;G1ҵ&J$fJTHOtpmf{fNv%'x*vwh/366R2[_S{m:@~=5yq?5uC.mhjP5{r`q8#Ў/RTIxB)#* ?NvV6r4sc]w__Gyq?5tw__Gyq?5tw__Gyq?5tw__Gyq?5tw__Gyq?5tw__Gyq?5tw__Gyq?5tw__Gyq?5tw__Gyq?5tw__Gyq?5t-bV3u27AYq{qy%[ËkMld7b;|cu.`p:셸. ŻwN.vF9cfqa_ij mBΞǯJJ)L3+k-s.-HS[\u\|BN5x6*̄!'7yv259v?̡)f)J` RwU)NyKHRoRT2Gǡ= Ppڼ~(Wa!%J!)H&6 + 6pGG{/Éؑ PJvp>s?AC.ڼ?Ok~kؑ!+Q%gy#5yq?5tw__Gyq?5tw__Gyq?5tw__Gyq?5tw__Gyq?5tw__Gyq?5tw__Gyq?5tw__Gyq?5tw__Gyq?5tw__Gyq?5tw__Gyq?5u?c{[TY&" V^r]IJPPVE'xp溨kvjK* ae!$MjKe쒭QTH\cJ/cL*fr_eєPP.-!{۟sψ~%i C 爠 $Riu BIW[_Ѿ:M_Ѿ:M_Ѿ:M_Ѿ:M{G>!{۟sψ~9?uy77U5; RV@^F+0&2^Ö)aŸJJ>z*5)A4Z'lg6󎬩%@nHyjJC"CEBA`+ .:Z4uRGfISOJRgLk>P<(\uG(R4Fuo%)PƵ%a,JPNrrI>SQRwԀ\QkтE&6j0$$|}Zp(ڄm Q' 5G٨RZBn2JGOy$9 V8@B$q 9޳GJM),($%_J-X-6?îFO.}ۅ>U2 m*LIW_F7OG mn,wp U-з\NG p8A(Z <8&% *3-)tr-uD) RA'Sg}k;6tTh5r?\[!+\Nࡽ8KSo9PDJtZSlP1#>OBnTM˙K{֧wH k4W&Hp!xH2(I^uiC[wy3NU>Oj>5-0R!C:n MU Sj2ʛx6A#*q'QHto4sɠ,VOPk^+h"#%k:d*TPA*P#D (|"se}v߳yuQ<㪾=u,{iuW-t%Xd)9⫳P.JY=9 iFI6} w;KY ZQp3)vܛɻjwpuJGA>AQnDF[^V8zx4!^G|[YB*6TI899JuC׭9iU2`RB )<#D Eڀ§mjCL2odnRySt,%v֒JSqOF'oG'o :^AÇ?s[@y*Xm) (2H}֓ghye 7VXYe DeKHVH'yq!ӷk/o$D5 w--Đj s([ۅcӯ#gf3)s>όL8#h/]fGJC"(1"Ia5!#>Wd]q+i+m:fcmDYSW%Ju o+ M=m۞uO*#t0J)왳9+p>'*^lيT`Q q+hFZTt[Åi*H4>sS69nsS; 8aw{{->-sQve`nu SHq$!wJpGƮ[ڛ;)ji@D8u<Ԥ}9~Fu^wWimQ]|_NLM;J c)uQ֚Pb),~2Ĩ!I)!*H):hA;ԖGuvykj푚aAlH +;Ss\ݠ`C`2At֭Z8w~ ]*Q<5~[kjo3mW%op֔$X"N}/uA 2T0:|JWAwN3q4Ͼ5~[vD-%*?jEi_HdACzbΠq=u[kRN[zkV:GН!);X`8}4wWl-מcjl> rZ4U!~[L,)ԟHgXqJZZQ 9z*f%[]m /yFk_߷7n}%$QϥFɛ>rr6͘nNu i8Wgk6`ړxMm~td((MKw̰vS[H()(X!`A4_6e1Үmdd:F1)ݷmr˭5r뜦P't'̚x;'X@]-9vd!R|eN(EeI8'kηIfmJ:I7Me ^I]D=*Ib8[RFפ㨔 `O5%;mUj~4|lZnV仔;[E;[۹9覝?Kg磺gIl6ێ6طJQO c Ϸ;nF[Ԕ+ ^m6ql@•I98ϦBP%7jST|kX}^+%i)UTh- J*C%* u#V7&ޓkñcHT4Պld {CmcTbkjc/kvrsܴ5dKR~I6Y|2HSy'=d׍<Kmm kYROwo!ro6K{׏u) Zr!@xSOR0H 9'8S1(4qosQ`8'M\S:on 7~TQuRVpMtZPX:ڥNU%T[hCkJJ $<:y:ԕA "sl'ã Nχ_\HYQEQEQEVګçl=ЫX%QEQEil?bG]fQEI٭kaO%w.9L-y'E1*sb}Z}F ~e *n`vJGG9aG m=k=N51&B#6ni^H)qт4DI ť (-HN=8gz,_In;KHJuΊ:>l oum9Fռ!>ZOG?o-Ywft~ jJ(((([WO٪&{WۨJ(("~ď)|Ÿ)$o+:g[W⸼.>:Z,@&%Ced 8EL.="P_RybP'qKBvR 4u`xIv8 yخXxt:PDsmIJVԧ=GTRЦP'*ob}Z}F ~e ,p6RF8MY/R m-F\98':); C"8R2zVsU]e K ͼāSp F4Ts\5o1PANԚb$1 pݪ#O4 MBvP})p9EQDU˜R#򲠤a(9>jVSiȳ#S"Nz?FL`8ø/FJwFO3Zi>3} EvV_ Y([MpJ*7W@XFLir '[`ܗ@!Ӓ |`նF lI:pOV"@,0AsZU15Jmp50 rS0*~k}*nJݐ%#@ER$EXnS HJ!Ĥtt>EhMᢳ[G) d$ ~ȫlR٫!H,0 Bw7HԆlrt ̵hЮ:Z,*2VY.0n'4:k^ jdd!)J j&)K9 +}ipGw9֫mV -P7A#'O? e ̩."4MԤ~qk aaaD*p`(g8Ir}5Lf"ߣ2FAFylu˻7kUQEWIi)XAJ2'({8'L1׊!#<#ӟ)RN(n\~?fa_n(mn!)j<FI,r^QI!+PVBAٹm?) cx>L QEil?bG]fJI8tmۭ16^l襩*AV:>Z|2eI!9:#IYl  KwدjUV `Þ q9idᷡFS G0G<:Gq;vZy)D2P=dKhRr8֚Le1DMss*|5CHT]ǵBNGQXS,8 i@ק|Fqm-Il2uH+:r/&&%j+=DTLXPy>TJi 4AՖ͵[JZ"4NYa8V8V6z"JT X$nt?|USgulrvQ(PZzim]ierڬ%r׉<1Ǣm-ZVt۠o+1Ի%N2"\2|YkjL2֭Ѿ5M] w)36y" $'DVK햋or!V.%Quvۏ^5'$%?vͻhK$6&PFiU[ged9pi;:gLZi\P!.'xn#Ud7yE*:H!N*I=*W@֖rnt HPޢ^oN39`  y5Ym=YD\J7TJRrNKl[= VTP+ O׳Y&죒B5w77Ϛ(+Rj"b,to6ѐGk}LXMǐڀJO Iʓ ~6Il(Kq@o$,i]nFfTYln^jHJw 9N M0˾[u1[,?o-Ywft~ jJ*~ϳ뒕0} H($6PZRp8e'"Yg(CO'B1Tݪ$0ïZ!^=+rEi2%$Bs~h&uؙImL8!@dUtcDkuSy[r!YBH<~='5YC8 wT= v/$&kaV !͡Djk]c 0ZIIzօjaSsQgmNٵrJY Y9 '#|q ŮZ`8UJM.@ d:lE^P,NzV\m\ۃ-wZjlDP!\k;5-Sn$˥3w"(soz aylu˻7kUSl5M%9ʱ֕p䶣٭͡l9I Aqî3LvN]f|8!APUm9-r(qG.6 !rnr<4-j $LB1ZZ4$M?nR@01º£n;/%$hЄ5N6m !Jnަl[ҩ3ZV(:pPM`s25CãůњR0AVګçl=ЫXӸ& (i~zM_:p@Xsp5>X6rǚWR[Jh |7IOVj7\$@uAs3Ǣ?-Ӻ* GJE/%gtn5m ۄg&7AaXR7q* (_}F?bG]0v-܎Nyxz*񘄦c]bNV z@Z 荕ITdWxVuٔ*;!jw\:p]R2" a[+ R02tUNG?%mZR29$ >ASED6wӐp8Hm6U< 8!T ө-W$kæ6dcn-9@5dV/ 5Y\nRv ]B1=_WS6bCL36Jrx-ӸCD%Ϛt_aӛJJEpĉT^+;yn49›/k.+Ls4'šҞEq-(j"̶2+O53d/-X3ݜLπ 5Ԏ%if"*I: Jw#KI V2|JWIqd6TKFqHV$x ~"eSk u%$2*-Lm ㇜lU6]ՠve %XJY!d_[i W騪ջUqt_"hu{{]?EYWɣia6[JJ|8HSיw2!oRW'9 l;יrVH^[`ڋ:Uwp2Gե/q&7,e)*Q**ӏFN՛V7?+^Hq28n4K )Hu :j0u5hV[LU&҂lC[\\)J q%9ǣԽv~;DFL4$ɃЧMZrϫ}TSkT)%OmahZTVK+vU0: IpiVWmm֕9t-nݼ%ym2piH$5A\v&Kߗ J8P”3#3+<;FDq;ﭒ0y5Ƽsej݇:~Ve#oQ bsȧWpey- w);tU4{khBp04g:Z.1;@#ZzbB%UT $d:5<6R}/x$ Ta![ˉXtn'J҄e1M'+:j|}棲$> /?J5ҡ..n@:ֹ8zDmu!p&k@RuazԏZES-x-Yu w2IŹCVF:q"lk>É} dY? yjZrm%={3 J#A NR열 %#fV$xHǔNk{odFQpT9ƴ|16$Ye WĚXTW%5,$FZZJ6GH$+CpWTu"'{ %êP%$ξU 9JrzPCnVMݞ|(;qa u`M1xIun,{Vsӌ뱼ט\!=qAm'9V}. [K۪CS@±)=$TyM8*OJuQēyM[.\v[ P;p>:p\r3-2u89򏪠:܉kZIQF78iذն#cx='sV>>U,\VF\Y:M?w!b3vҘ,߃Zs͚JOm%HQ8+Kɇp 9ĕSBcN X>[?o-Ywft~ jJ/OU0xx|,G$?2/|-dhx:FD eHG* :02[Vc9A]4׍RlzAd)-I\jR;]\N?`XڒA$)=*ˏAO0I $Q*S.rQa;I#SiOv.k# 2}5Z۩3b C+R+[À;߫ƫ70>ROFuRt xIf Z8\Vʉ6[WO٪ߔ;d9,,QZ[&1umQ':ս&6!42uPVwF}4- GyCU4 :܈2Y w# R5siR"B%\sƧQ:dSI;BZ"yVT2BAg҉*Ɋ,2n%;#⣰2ڇ ׆,s\vl~ATlq-6p²(/!;{!WۡG*ia'T/(%C@ e$ֹ 3WBe4HVze[m CMyt:s.r؂yPXs8tgMEɩ%I),!EI 8r}N݊/KmeY'I>zg >:4o<ǁ*IJAVdY=& oy+^#GƠqUkU%S-1:,N*r-NGh%dr6ૣMyex;PHvUQEQEQEQM_}iQEQEp~r&=! {&ki#7y੷NzzE/Hң˃dtN92,98O5ۜܠW& lӥS`ʀrq4C:RTtq&̺ReeQeD% PPw!c]S\ʊHu⡬2.$P]!]= OB}d9?+~[>r"f!c9j!jAjqƟCNu+) y|T5jDwcO{-|]:Э[[m )iק'jN4؉JPQC)%$Tr8kѭ\Fq_ԉ%1бO8>(ulJ̺ɖ1RRR8qUcaGx,a{>l둌˲$IQ҂q:rypG,gyǣ}$t84␡$\֭ګçvDlwE8)eyq"<|P"VYd==YY-Nȕ\< |cW6ggRQ qJXӢn[6݆񆦱!zTӴ(({?dU{O# ͊̀XU!)g9R~}8"/L]%8# p.Kls!XѰ-gL`g{ n<֯ίsx ;O'<5LB֣U~+y Nj?L/wva #BQmb|:>Яylu˻7kUQZVξvE* d@:j:Ӫ$ao9u#l8NB)V3C%.5}5OIuZ)МrDTc6(tԎ]G)RONyI\kaHAAz;N@( O$6 )Iv{83BcWȫֵ_A8 +er;*RDx.XwRoL@#ؘxNc*J*8}Uk[J9gj*@= J[%0<n^*ͶqM"HK*Ӝ@A :֫7yW")ь)-_"~ď)&,?ZC5pm^%.ۖSյ+E?.}<]AKLr--Ə((#Lh8v@7RP-o.ր |@W`9nZVwڑrqtRw5\d& L!yV:0zN* eӴ(({?dTS((χ_\HYUe/귩pէFN1X 9-YIl>8ЃyB-^dCm BPJ;##Ϗ%;[e]wyEDZNڣ%jh?%RVD*&!r% ⥶g,qmYs!LTrG }u[ʹ9 ʒH )s9לh%+F0x`}Ti2y[WI֭ګçl=ЫXգ+cDCFtBF!Ӵ(({?dTS((χ_\qo)(B‹,` ;Ew3f;Wml%+a@u_WP.HK*I*RsFxuf?b['\/Ž:zK EZssx΃I.~Lw7a_GPkvk/"+c BCjI$~O vO5|øzXEH],aPJ pOXtlܹ-%([!b߬׵6lZB@Du+:cъw3Ϻoui}ӭDU-䔇R ȪVد/=5W6GZp`)m\+dIC'B=rpTG\9@?6q9B*a..W!H@%($7m6+!-B)lA$FlLnN}"^l%Rm \OI(e#5*!FAEYuh7Kj _myUيQqthdB(((((((((((((((zv[ pdnVt6iy;ڀ2(8dc즤-tF-+)kK8J| A4[w J5 3F(zJU"$UFI<*3,1 [)$r֖ eJ(#{ 0VƛRE'Tz-;xvTMBiZ[]U/iq1Ϧ\y9▷T ;jKNWRv8gxdB^8>2;qii\#S >CC$S="Ωl 85jv`3(((((((((((((tV!}ɠqҺ`UFI'Uۤ::Y/hm06<]# LJ;USm4B$bhl1Y>*J!Lj矦MJ4{2TsNC߶7vI-vғH|ܿC}^Frv8*?[X hQpRmѰTO4Ju̪ZMSRZVXj&˪G2 -XqQ4דDb8 $WOf`yڣ@wzyUCR($ Tf(A/XsJ,v+vz?ŒssNߚEqʰ1PlwK^۱ZuDA7g_)E1+G#&K,R~E1y}L `yxW3 *8U5G<((KZBgPԍXrH\M8Gsf@ *BgTmɖL]XΐT.A@. jojCIݜҰd̸O 31N- خ,J1[EP>i҂So!K>njY4o|ƛ,|!NICK+DNsYuO]))|如#~>LV0#}2i?Bw7KqXELjl"pj4u9*OsHxr0hZ<;V5,i7x[P9`w)4 K h Q߷4﵉x-!i"nmT> @t;XvaޚJZ I9S!bFbx":hsԏZ[@6C)9gRQO\lǡ5d=pPD1\ۯ]u!J/YQj)-cTPcṿl};T9yEPD(((((((((((Vjw[Hp3PHޫ4?Ya[&XKޓt;e+7:s-jSV(hB^LP%'M./t} 0̽ *վeќC$XoZs@]9gT,{/hvİD'^iO2HTAnt@ArX#Ƞ آ683r\U]4Nm#tMmzژjz\T;YF?j|-~͚;T\zOobE{JtŬ:~dU+}V;tL8*wyCzylȹ8>JPp_Sa۽{ޭk J<[\WxPOiek U8F\04OrQ@5\kț}@{!?]꺅KJ^s{s'v|#n;\ϩ;ɢŧ^LPf$q˂=7BjA8q?k0X)|WCK $S/փʡ?-3lˊt"B;{ZZv&~J/rФ'OxYWhzO!Ǘm)ǽU:^~ IRZ NI&Z/kt'^dTWr#Fe8 W8!EPD9<Rm,ƱP~t$_/m9SS "9)tʑuxo##ʜ 㚺c_K+o .%9KhR';'m6wRO=IJ=slƹ1siO *ET+Bt@FxI ΀hdRsKRCyk,ml B>Kg5y]Aq4do#@,eW ZG’F43ȱ9cR@UF33Rw>=+\T2Hy\:jF*;SxaSn\:iaUr<֡m:Fu#EY:x_M 6y NUumxq⦭v񥳕SyV Fh3^la[e}-}> &uWW,=E\>d A5O)!(sjΒޏ-HKc,,?gMjZ!9#d8W][Q>FG''h]܄ڲJX0|Ρ9fI-D.=|&{s6ܝxH$0[ BQH2,r8] ,0yd'(X1,PP]!ǂv6V;fǐ>`p'$%!5~KHȊ~±yj~H () %9 gti#.@_8VxA>] \.>P= Uds)$Mvˀl>ҁ 5O IOjc}MBh]F [?Lh=R;Ȍ@ELq5Q긃3 5j]> bqP!{)n).˲sEtx#\զ((((((((((| [+(c\F~ՋgI,h)wv8ȥ.f8U{W FKqG"P989H\-o6#@/޼Ayh.AW?J48Տ[P !8'W6 ֮~*O_by n]w:iӍ`~)sc[6^-S:rL.(bRdII i4kܣM1VS 8Ǿ|DVxV٥yG|y!O `TUݽz1R3aS 7P@QOh0[eK}rpN["ǵ$ySP=)4w!𪇹̲4SG䚻f9穿¼3?y]Տҽ]*{q5q <8ֲj<^I 2;S!; @eJ2r`99c;~+n"9UFytmݨ\vaWq E\43z)<)>GրDX  Fmi v<|݀۾3y:Xm1 ;@\}鄷#+e1ڃs@2;R_' %[9 $}6Wr"ڋΠB㍪i?QT`@GJ [}KLg6?|A @ ^mb!cr3 HcME摔RĀ;tb1((#g *{{W-EKcw27Ƞ(-Dt.H#yU[b>5C$F`;UG}[Uw fKK(a?j7 *ze&I 6Kzޯ:_S^Y!(?JN5Ff=(=~%/.[;2B=H 5ϒ!x#vx#R~͑9f+ʰ:8fDL}* H&+"#֩qkE(R'hWBC)""AlE5VP3f_-0}d>{z*mr l0˷*3"[xag,{%l0`ƛCI;kk)̼?}ӡIiVxq /kue[:8А-v D4wڜx!>Uؽ6!)1؟LAWPjsC!LoPb-Dς%Ѻh=U`,F]Ysl.!FX>wT}5E$ہ޳鱵Hx޷^F'~K4 n!Ҵr Ҵ k FsU5[edb5Olgu<͹I8?>|p0icl!aV[|M&8qڈȥsr:ͨw'_B &Ynn %|C#Mj^5jG`*2 EA:Ni}. ]#$O'mNz.OPcIڤukUgPGxR9&'hgxIypT'arѮѧIYNHqJH(g0̬i%R׉Es}1S, zJ)oI$l/pgE$s犱jk5bvOՖIKE kkk,Xٿk~Ŋ㣴ӌ3-VHضyo!OKFdm7JzZJ>:a(c_SNpTꆚtyS%dkPO&<!%“ӽAH4I3]k2ݎuS鮷 %7K8G'<ƶ^[Ȳ~uk}cx2Z"Vf`ŹTRՒ(5QЮn-Yl8~=(rKp9&u{SmNɷeCD y[O[w<2ǩ^3V0Ny1X8M!kwWSϢ)]LU} >^ֵƼdᘨ!$s*jbA@tJ;s ʶAjnlTlsHxI?y>Z+VFIFYg 1ȧVR >ȝvެ=b($'Ua jNDѩN2;w;OgڒHڦ8>T0ΉUj%))9QOC=Q̅i(qL[Ha/ĻfEշ:{Z"A!ZuEH-ŎE$ˎrh֪_ܦr"*麽@FF;YznNLJ&ċκz~5F-eU+JecqK޳M$䲸^_?Iʥ(&e5Ә`#ozڡk+TLyI^u :ZHns$vI H9CC Inl5r-b«*duqD;gʸk;[eBsMX) y:ķVUDvg^Cqor[jfYn By^A| ; SU5O 47W7Ƿs9}˚eiKBIrp@?OI\vGY{{+xT4fzㄢxk7]σI!{S2MCXi[@]wpGF~eiVO3{+%g[", .[^yg9 IQ?74$]5*=|Alch`)|'|#GM$ SFo&:y =D22x3=I;3,veQ*)Rϟ(VJ3MFFdڸl6\_5nh"LԜؖ=j>RW8,U+ cH Ae(yCKG r[ּ$+ nA v4r 6\HŽI>DO Cnjޔ$#Ң>~6p2<5$RTt hr@1n4Ej!I }#yBE;^h^LHaH9?ޢB\BWcO&mXtN@+c~mnxw<$9cSp񚋕1슔my1ޖ#&4>yu9CJ; g&8~KJI$ aQ/$wvO'UP8S!VdnqB [^rGz+\{{kX Avky m"Etmr\ݕp)H:J%(ʬ5<$E)_7lP޵,:~Ȩ2q*k Ǥ#`M\l$-nN ԒO[t^bVOjo]ZڝUHT/c9uH]n;{U/SV%s{RFq nlmHpSN.:kQTgveg9pzsj e]`coǬW(p>ϚVq^:zpW"mdx~+!:f{ܦHb>{ ncr68=W²/Ӧ׺]yv$yO>uZ@cπ_R]|Iٛq?׾-zfhX/s]9PʠeujˇGxCAXh]ڣKly-#5 &Eu j=Qkx a˧˔M43s5"Uǧz4ibdv>hJ`C瑊umVjl#o5'd%柧HnV>KO^ҭ̛;O#8aڝ\ijViWEG8w -,o^{Xtd͔}Gգ_4q+$m[ڴo i>AN?/qXܚm25e>e5Tk4u \ܖ<|OnGj7M 8x)FC:OYۙTLrr*c Ve4TIDl}fj/ip1\Dq$lO(Zvoh̡TJD%3O+1>ڰ]L ~*߯ܳBpҀ.Si3/9MwHcDgPpaV'#ANX''@MZ,̓žZ_rd$Kjhuq0sޤOڦ_ {qJ%1-b)$$@ iL}ޘ,,v8 r[.R'^K &ݷ$F\L+ d8*޿BNS{g#T3ܳF"rý{d. "?w5(e7q_Cn]L2Pl򧶚Ce,uZ+ ͋R tdLqȨY&A)F;)-[gd9a,`mSmB9/6xϱk׹He7))'L9$1.Ie*;}cZYm]>yY_ąZL?,vh7r#o&>݇U-ȭa3Di$mjN.>-đ cy|튑,YēU4X}rHJK1*G7*D#j 2x Pn1zM3Le ?jAɒHh9{9@O*cw'q)IjPF ۂ)BSL܏/Zk1SUQed iq*<}bhĎGޫ4IX{E.?QT~&& %|Y|y-(,,oqjp)ܫU2œnN>և=|[qG9,}H\> t[ؚŒae:i?0xfEڸ;!;V֖1H'8#3>x/M"lYO1<2ָ潻?.u(i3JdiWDHq8/ЬזW}71Or5%$Q+\}ON=* N%eq,]>cYF9( OkEdUErzC#-Mg3A ʀ/qӏ4+U.Hou1F4LGp?*e׹z}rdlCGOGjڕΫtn.s1(((#yEZ4[$#Â*nYm {uc9W:\H{yUrFR>@w50D|{ifb ™\\ >U)mD֡Ph7.jum3cN5۹D@̥@]5iWw%crc^?vDŽ~E2nYҊ-h" rI=^ɳr R/Jy".9opN*-fM6$#Զ3G|sTg[wW@F<T(]U<+67۹8J^fLӹ^5kp KM6}ۼK2d\ײHIV[ ٩(ldFs5ȓhHdd=?S)Lvໞʃ4k.g \в(@Aض? ͦA'έ:*[fIJ[G#k O4\-hDŽjA xk?8ўyYGvxMYQ>wP%dcr*ty88;( V C?՚@j\B5 Vk?UC }*>p*+jwvOtRkmR\( *B%~N^"?WvOc԰'mrw՛2:+b? aV?~moMŴK)nyGhPhZR 1sYDӏgх̍ZdCaW]ʣW<{P;@>G~.ٶ6=W]'/]E6%~¥BUu;`,9kn6p2]lP8u:t J٥$Iڵn鋴3@OhWHd=%fMi6i@$nv/xԽOLc>LHdVcRh dYΌ40n#^㹧 }jp;{պ'Qva\r_d>>KM_M2Za *4X[va[Ӛ]M$0@s_=u/Ok[t"-R=+<5 ƈ4WFf@WX'LuY`7_C;Iir0KK%8il[4ko:k-X#1_euiWe7ɷ 1{DYI Cg3 ̮j7_Je-qn[=Vusح{:atiˢ({WQI&>x(P}Bkl̋njvY *QEQEQEQEQEQEQEQEQEQE12cE7hDz\N;Nƙ $WIn9.Ұ-緽0] {VܟJOB F-5C !.HܷIRad=$g,NmNOW Ѻ'=+Y)R[|b HΣ_]/OCN YT?<ڱMK oHvǞk/Kw __'y\p4m)T^`q#뚧{ֺ巍1۝Zk{ T @{(X:VnvuɎG"-W1_NZ݂i[2sbwAfVCؚf3#U,P |o>iiO¬Wj_ eH ƍC%RF>zc#.rc32߇m-4tym)89J{*u:'WuNm7'xS>Cy@xMRgĸkVr.sҷ?4[xv!5']t\lל;zzn+Xm{֨KfˆP;Ezdٳ}qIQVBi,ר`S{kòwښ Ɵ,%A8 OeIu3FpW1$`ߝ;B˯C&mֺOӆ["hXՇVR{3rg%ˊoees|ǥ8P۴HWce>F\ Jֵw?/$em <z[ehҐ92O?p[iI >e$r*WΣ\+ ~j[3=é\ܒ{C &#!>@Pr_61MN39S÷56L)7hckes|¬zS[i %(/jcۛ4u?~ΓV^-1DXih+1Z$h"Tԯ,զ$$h7ժ.꾬uōÆnQZ?Xs_ʲ r.ζPy-.|ӜޫI6C,$Oy(Fcy&=l¸ (Yy!P?zt'%zME-|%DZ {𳩚X5;R R|V}4OKVuZw:vFlSm{t,hm0C.V-HT]wJΟw BV<{BWio'Dҵk4N7?\U4MF%w⍻,ҥ?ī 2~uSBmqjotIy1[qPZ.rɐGI8#؟TC.wšce6w^B|ke~!hֲ1JK:Lrk;&cf[ 㝾ƪĮKqwfEv߭@>Y<|}0%ܙl%9=kŕMZ(ͅ%j{d8+TʭjٔӴK (ͱΒ{9$?Oj.%{ $PX |R:,єu4f;S#!FY.grғmQæH"Gef3Z8}H ~YKHb0T}U4.9!#|IZ>M8A=1k]GċeoBuNuU5pW޲6y| 1R6Zpp?}ώ Nլt@} Diz|īᙷl 1Vl&$e5$g^c'dqEv-ͫivuԓ[\M ʁ6k=>ixݱvkYzgR#\D)=ι[F!'6senK"۲PXeֱOgp!Ǝeڸ^kƀ {Vmiee;;W s\KRG.)Hy\$jYYq^[thɹgփ;х1^>X3 =6bd1hO~¤zwR}AzzRA\ٜBj8"ӄPH˅x?j͛6K}hmMhte1x($˻ISXM۬mZ5Ώ2C*XE:9ӣJ%♓&Z<\]&1*i+NRfED\i̍+Yi92OJeKҮmđ7cQ:5 KF+D5( ǴE]2) ( ( ($|;/Q|ʣXR_͓fҥ~; TZv7Uvڰ3ᬒN< ?C|8]uOuG ‹+jx["sMش0U[w-rHsO2fR=x%(̤ɨZY,(ޫ|-4?ݣGK-]#ԭ)<:yO`If++qޒenマy+*N.kWlog|IwsڹTR[yy7Kqߖۮ.Ɠw֖qmt6R>#Ox)^Q[d\j򨐻cTC0 bsjcsNl{7oMteo ֺ i{'Vyu;DzaEh׭c#sʤZo^Kd^O?kzvtVu N_o:e,L\RP_2u_i~ zq]x|ޖUް#?f_G!t; 0&׶Ӿ.{O6 ݅u(Yc("XP߻2uܘM:ؓ]75>@#,|`n5[Z  VPIEœT{<>);_LXH1XH.PKkecTGQآ8O?bL鯈=YӺ4'^\,wP%euʕ.M"I^]2&D 树nUZG3bC{}j <>|?ßGIu'~Zt  _!/35xCf\ 2-f紏Q_p<>uP'՞ QUӯcl7 GGuI d;պm7NoR9aIT~o͝k'Uu$S6[iBܰDӢk{#5[$,I;%Xz:t:Diڭdg gn|Wx/4Ē `R\F}QZ;w]Y>HᏨ*qY鉖%Ɵ4싐NK+M)yzZK'檺I@c[P)p9]-V4/P1ɪU#װkz{a2}蚆ϨnN8֣> \|{W{$v<#5+ %\2m'֤zmIl\ơV}aPmv yR c.ɸ7^\[p=~I\囹Rɷm#QMm&MARodϕ.[N΋\"(V=6^m']0G[ q֮ϧFUl |/dʚ zz6˖ >LK8lT^؉f O1C1 Lw3XD[hݓ޹Rm5m\1Sur.(?Π:]*`tv{5'q\Nm暋.&epsN2;SN1ng=Wl'8t峃 [=3Onnkd9枎LH=RqIt;We^oC[FG.TfD/<,;-^Ŧ\`nҞ]'l|yJ$k]2c}LV<q7cʨI&o}ĻjךIdz_ p?Ѫ"NWI ;W>T`K[G*yt ۖ7eW|/ZL镺:0rxqY!kiM_$00\ʍT޿&gkAbnfڝ/zRv2G/ZQgD/Է8O0]̀Ӄ='WtZKۅB?9c!`S,$Qu_Ӊi-iAךw+欢 R9q}af$bWިP|B>jwLP}*HNJ6sJy5’>^U݈!A4#)8 -*D14<[5O,J zGjJ꡸=Ey}E#= 2,0b5x$%.c'ЊO)3ިz#Z|]N.O*QwH[/b<>V=lċ`?J+[麢KIAvfF89UK-x"\[]皦ɷ.Se9]PE59a#ЊuB4`I'=Xn&ٷ;0} JZqIo 1{ m \ eġBMZjlq@;Tv6:eUTYYL<է&`u5zH 펌u}I5M,UgDp/Mk9tj'z,p5wH Qmr}0ʉQ&Vl2sO4 DkYHH>T\NZXS"3j0Jg[EhԖ =K!RÃ( R\ܣ._$L?xS70A.`09k}B(`7?syCN~.C)wt]ړ󑊶u>otd׸ =+>A'EIrI[jƥAAV~XX{w6;t{squz X3Jޤ.5go.Ro~ۂ}Q-uk_f7@{WS^O'BF=))(ѨK:z-#-"Ée# ++.[E#OMy%]5Kj)thzXIQ9ӽ]\CtbCʘ[_Ama1K?H@sP &x7 pIz Ym6,,AT*:QC YF]K"R.y' YHt=l%Եmmdvo#  ?ze𿦧{WYL{YUSrwf=^o_S&l7/6X(8x,CPa pXz,Yۡ®7A/jnuxJOc][hڞq*nKa":gF/iOx?WzH?7ِZgRAaI)A053Oa#|j)XE$e7PɀՏ/Z :I.Y[vs},){m 7 vz?NZWÕTn+nҬWppкwܸ<2#_Ԕ][~ÛMJ1y<9O!3Jyu"v]zeնɉQf~\'N!.J9nEnj;k!\vqӞ߰nar!DՉu.@85|#ksy}dۼn#h>uխZ&! u`H*G))SRc}>-7TSMDxT`uw+FZ:}4x$ո-!,P;S^wNzJ5t 5h8z֒e~ojsn]\ض(T3 X| ֱѭ^@./d=ˏ"3ҵ~fdQ|c?#xیWR]|o'YWYSw9vڀsW8φjVPMxL@hQ57zW46L!SJw = ).Iܜ)8F1몍|َ*Io(`8j3/#gjo?/ɕ_OHӯJFXv5~OU'kɜmlqdZDxl>QrgWg@ջ;Pm.I.tBBp<3;m2in&Ԗp߶FsS9 mbB$ߎ=ұEu70 <d:QScy\A8<*48[rW rCE&&=9Qة\\ۉT1I=cq^3YgkMU4\ݣ5x WGKݢ d1Ù[$Ƨz!P<;j5/ERhd2Ƹ|=nVcq5"kL¬:{j)vJ)Ho%yLjNjP\X X+H)pبs!LQ~%q5 }ږq1$\8Owač wbek=*S7Z >^&;cO"JX[ihGzqk\ۄv5֝k"Mp (/ɋ9W^;C2_V_Zooj#i5KV0Ucك`҆Vԏ1fUS^ Rw1iCA)N3ok&JiW-\+܁#rr)}o-LD!CWyA"RK 99_4Sv2fY1΍;c]Ңř(P8T{CmLtڶYʢ`s}m@|XyGeqeԶ]Wg \(S6\ma~xyziY7e XXD>"ieEZ>$s]qW?IV"tRٖʴMzj\v>}~G=z4K$0,D[ETYTdԗ.ִmH.ۊºSMk}EOkfHԧ\5ArF{՚f`F7cX .'P e|}HTG-܁aObtOFqۚohkdRRrUsT3SՏj9ڍb.'>uE:_PӕfL/Q:Gqx#+p53uQM-C xrb}+Tvje=Ԛ6dirOn)iM. ?3jҵ&Wca5}pD2ERkY ݳLSЋuO"NUa-Q"7QFJr?δJcՎ*IDhࠥ'0M h*IjSF3ӭOr?c]t}tˍX-2ƊqEc"vcI34{0}k0[ dHBFš襺f"> g;ś3H+^~bEdzj?RzW횭HҩX@Iɦ?Kms"JHoB3RVlռȯu;('R̪ӊQ޹+jlm{L;LSN RH}O4]tQ=K[ǗsNʌ|-\3)(*![H)Jɇ8Q" 1L.99#Σ+{vlgU'`ˏJ .p5Q X}G\)d"mo=Ή> 䨗x/n**m{8f:ԯ>ZeATYm1*)S-=F}Tvޣ㹹[;a@۳WZv=oqaOTr/%W`T+Jbm'5vM;~x!t;)#8ɬG:fm\ʲPz<%qq+ɞᚥ,mmd=U4Z"q<")u( ƛTiX~aCLxHq,d$$j $J 3.:И{􀽁6ihnmFxa,l渑ba]sSW]ݣ8*3%N%hf@~Lqj'J^{?ˋ W-%]朵֞sk8ћ[x/XY9vڍ6rY@RڹȽxRbmfdv d{cJA1t`mѠ 1*4=V?g4G0;;M>NAp#|qʸqHݘJYWPSYg1siU-Š(EPEPu>&sZBf(0b5jwAUx=˸gӪgHmI[X3>FϋvuGoX{2MVD˒;Tյk n qZžo2@UDgqsUvav#ްC=FR_$g~ :$QH_QU]><9㷶c1K=jy:NmA'흹~U. wҥ]"P؊OU Y"h4<<մO( zZ_Y SԲBE.".Ux4wqO lxQ@'P=մ/}G@Q]?U!NawߪNE存ʷ~Ǻ6<87uq̊kz+8l@@=_%Mky;ۘ;Ƶ[fBҥ4Z$bFƌ-͵s -оH4|v޴_鸮¢D~<̰4T2;<5]G]٩@xYGfi(qn6אi~@ ge}%\m[Z֣XiP5ΞJ(Q=8]ArsFy4|Tza<^b粥a%bC;ΨDT㊽uh:Զ$Gm=Sf_Nu.+U4xc.gY ,BE#/"KAXUՎ)[tGbIA-Ipr34˟XjVRF׷T/ ;j'Mv @yK7#o"۲|?[ka®k+'RO[{n6M$2=ZugL,2j6+2 0nBw]'JJ6ԝ:~$F4.9k"x hS:ųi$;OojggAK#?Q Pꯧ\D+5q)1Ty!c#e҇±.,j3LrvS[#q#JY/˖¢:1!2H(_|>n̨ZB;5UX]Ku%SگY@IM8g&$X&)[E:23sU.Go;4]wgR&F)"k.Y77m$7"~^# Ed"Udh( k(64U8Z4Ԛ i5?gǐSwi*'9kjl 6Be n y=>4UN+//2BqO|Iud 6繪1f,$N]$ (EPEPEPEPEPvZ\}?_RZ6 +4;+-=^۱$Sٽu%֙fOҽ^{#l"+N.& {q}*ҶӶٟ.?:3Vc$S{*sҖ OyNkQk5͏tGM=>=Nm"D<=eB)6LגYd4jiH&}͸U5]/fi$'\ 9q\U J-;f05u $?OT6wss*I1ٶMpq>I^&cS ?z[ҍik({8Wǖʙ AUtN:&;{5³ɮwa%ZI9k VVqqd͖u|+qK3ܼP]U,v8l'nx#J>f`d6S~3j=]gz˅.Qj:.qFD#aWvֲr=jԝach|Ey1S%L\|!ĭ>BGs܏?b:L+QZW*b-Ϧ+ID= ?|;pG7DkhL!q-0[;Ni58>gwH}1^u<ڀ x.a^FٕOrQ WR;:(?b?Jρvޠ=_XuJog||y? /] >o4[$-l<.+Dž0*Ȋ[̳TRCTXѴ]w\Ƥ}\v4k8Xr&x~H9B! t,(pqeD~ǣߤ#<ҝdt)$7Wriv0vt _U䠰7'%ǵz65R{ӂ>3=+ fƂ6lJNaw$,1''WuVݴA3@<>X?┱)Ft|:iMN"M⁺wfp~P$W+d mZUx.`=KhwK0 yc^Zն4Wu {Jȭ>m~"YIfkidžc5f.A؍J]\<#$YPւ63}j >͖t ڲ]El|}!![t"e ]N*8G74&5-}ϥ%q+Bs%oHX; xld\kHX,DˮQEi4˧-.G;PF.J-q},~!Dtʢ56Ϭwu܍Sn֣{wn6:7InWt岻|>Ӧi07;ɬz2KIiWH'1&G/%\WesdK《(D{TL?L[Dw|+:RJk[c;͓ښ떲TvG R0(""XU^Y,o|Sf1 ڥzgNۋ9)G"6E\2!TSfԥu&F;sVa-{&a 05C Z,D4r)Gdi?>uZ-a}ʮy*{75l讣7f+#cV|+$H[MvWyK7N9`\<$wU֚?}KEoY!`*N;Vc ̫ͥn˾Em^տ+f~ y=kk4dpG*$A&DS)ǫ\V(f1HF%#*G!r7sU:XԗvMs*)QH;1Yfgwq`pήmwxAj_ګAxcT!O{]e;U5%P{HrlP5A8lq-5Y+JV]}'NS_k"NŘ\EwIc踷j?TU?ù2lR4RJ<}Gizr Ggb3Iu;*i}[fMĞID˱-E:-Lwh^2Yqx׃ة>#M;E̢&\mqQʬn󫝎i5%%dz*(c]P*cOZN o)m\ALY>*V\mvRqnFՌei/,&y Uյ-KR{''޴tldNÑկ!R Tj2('GR/4R{UUU=j8d#yf־NF(*1U%˱Zh}DQ,H8==fFXcI?jCl-J59&ZuF]v$a.mȟ!qUzߨﭤc1S=ULYKBQ^M|?.&Tv b$vV^Xk 9=:яMFD䚩>((/UVm>bS: TtwaGaWM_5}?jF)R%M׆q}ɏz^\ z{Q6^剺]kgsU#iݏѬ5twmNLo^G ThSy廯K˷guiQk$x#yr|㰨izY=OVH~d'_]wz[J{N{%q_p@QJ3-cS cR^S?C?/jQE/a?uVxM7b~ PH''v%ڗWX/rZ'1?#R U1F(K̟i1-7/i(:Zņ, gH/rkgVDfV8PZjH#?W1^RQ dY1f,Ė'$渢((((((((((((u{Pȇ$y05W4%%8G-:gTX$.^4.qIe M݅|v*qM^<=BBEpr%{3UT&Ǯk+x.EWP&r-*za+vdqUP{@6ƇR蛗?Bڔ%:d[6<{5ƗKUv_G5y]E6(6s+/ͨ%մ[*-[%-JC,'daةrfjTY ~HXi xީEm:6~:W enM%.MK(F1XrNѫk]l: {tWv*/n&wI#aTǑ'948-rcn;Q򴒶ci*; (Q@Q@mricron-0.20140804.1~dfsg.1.orig/html/images/renderAAL.gif0000755000175000017500000002052710322546174020712 0ustar mihmihGIF89a-D\^\ҔF,^Rd̖dTҔ\d\4^4Ԟ\̎̔46dfdd &l66d:4:4L.|<<^<^\$T|~4^&,d4<:||4ڔ:|<~Զ|<4\\L~\d~|\F4|̼Ҕ^\:\d^\6 ~4d:|l^<\ҬҬҬ\ <>̄f<:tLܞLJvDBDvtJ|̜|<< |,dtv  |<|  4,||l|.$><< ,,$Lv  > $ t >4 ,,$LJ< ~4l!,-H*\ȰÇ#JHA0ghȱǏ CIɓ(S\ɲ%G6XI͛8sꄙQϟ@ :3T*]ʴӧPJJիXjݺUQ\ÊKٳhz )[xKݧ'MڞHvRPROi]̸q֣ aBVo~| .TQ&1S8JfհNN(Y ۸qߣJY$R%))]Vm ѳ~l kw[*sy5[tYalasڹ֝weA7zz%uI,2,hIfF#Nv^7EHF2&T,j1nZF8EBe}wPx %fFoGE+|%!yD"GSw(%FUk*FUqjp8ň6b$Ygg?nݚ^9c-.XN%JeQeYRxoJK=ԉUAm^A'݉7FnnݛJ-dGM^F鄗RaGH B, TryJk[ʫ6 -יxRJ(창)(mb٬fPbF%}h+()TRHhh껃jR7jnNJ{/gR"+ gLœԒJMKvVF{KCv4x4.ީaGź\sdsP'\Te_odd'R|-.z nxd~x+WnWTߍv䠇~o㢗n:lꬷNf. X箻W{oܷ3D <ܴ|@=3C DA 'X@ˇ  /H觿 +`A@P' dм$`Cw> EKg>}2_p &Dz8Z69`̇M >}(|<pH < R!3x #)"T .W % G%p 1#(&X09<dGHBbd_ 5)U2d\(+ x>YP^AK Bmzl 9@#|OEĦپP^q`#1$eCx8oMZ@ ',f*3[PfӁ(h%@ks E@ƈ>潱6 J"0 9M 2`I)Ǜ%Swd?C6s}S4a6 p+ (:GV9 DYЃNyj/([ϨԦ=$A?6gEՇB|mJp"q4 ̳ zj{Ф!]!4+r2CN¢tLx= -jSZM:[K8-nw[趷 .x\*Q=r:mKN7nv8 DaBDpM;nAK_:ԋKV N2UIRW BL! K& .p>ܲDyW\ax8î0[Fx 7 ∜IzF"<$frpBcCDSFƃ$9qxm(L77_*$)eg7! n%?8$>2vR{!3T_! yH#pt^>muoIֱ=x?Qgmb g#|~=AKuK xKδMx ڎ h:`?8D85XJ0wBȄP"&VxA\ȄZȃ]>I(fdxjhin(,o8"؆txhx|@OH~XwX؈脌舒8tX`ȉwXQh؈XxH؋w88xnʨ̈&hD8ؘֈ8؍7H(("pSNPN(8ak!XYy8؃옑َ "9Ʌـّ.$Xx- >Y^heY`8:\䆽17ܭ-{Kl<{0 ` Y,\^Gd-Mepl~̎ys,w.%v3"肮|V} ޙj^r.tNΖ~n^.d-;;ٙ^|^I˶^/>[Mn ̡n0{ҵ^q-_>ޢKې-n]֝N_^:Eձ+m 3Р.U[70N;Z /D.)*ο DZ+O!a.E6?i8貗~!Ҁ)Mv4MQ? ;U_\N]a/a_e gouʎM{NG{~oyN_M,^*bz .Ŏ?ڎ__7 _.l,6o+.|_O~V\ٯoOg>_D` DPB b4T0ED)9#0g`HLDBJZ\ 5m޴9@N=}TСEzRM>e:P^aC]%cF^͢DR leՂS͟u$hҤP:!V6pkD#qhMjаV-\s=Ӽ^Uj .\0bČ)W|yl#-_YJp?{|'iQ#]Ǧ}vd!̝Éyru7AtӃX?;C*GMǃǿ)b} J Ό\Ip@1qІ7<ABЇ&C:[ ZxANэ,8,.j@' F(lUGD$42qO޸zr#H#=Vr|O(F1oYB! 2RQ(s"N2%&3 ?oyDĖQ>44e0 Jbp L@&Xr"Fd ˘e))U> Df8LrљD&xKi0bl"r7=M~P g9-yN@˓;]k.=%O~Ԣh ZP?n Lh  @oۼhJ/ǍƠB*|<USqRL7ә"q7hNSTCMvO;Uv6e*L[նWm$-q/fnІnz88^8peK&. 7.[ 8!sD]5qosu=FtEGzltMПu}ǕzŸtwWWtޛ.۴_t>wt3۞w#|?xG|x7|yW|5y}E$'sG}U\}Y6}u4{~?|G>|7χ~?}W~}w;mricron-0.20140804.1~dfsg.1.orig/html/images/nifti.jpg0000755000175000017500000003047710416600460020237 0ustar mihmihJFIFC   %# , #&')*)-0-(0%()(C   ((((((((((((((((((((((((((((((((((((((((((((((((((("B!1"AQaq2#BR$3br4CS7!1AQaq"2#B3rRS ?R((B*v"`9=EH}X'?3;Fw+ &kb/o$ rs!s|f5`;Qe$ u,Ik%T(4j#vj^Y Es>'s>TqT4-qa=N[k'>E1}XoU֧ |@%E=VpL$|B )5lngCu-n-Żs3]P<r>Xy8YFOԌGTSg3kQE'ͽy`ʧ^Vtm{>jC+w;*OPG,i>B ǐ?&Hd1̏QI=?[H)j:(("(EDYO9*z.yܑZvTռT';>ǦkcaMROmcZ6kWΛ|EJr vZ_ړ,v gˋ2>iTU4K(HwSSߛ1D][; Lb\F9KF `Am?T!C @f=Cm޼日$ h3^Ljn_]vن|) nۿ8lK qKHv'H0{YJn#W1xV#Zc}ڥAs˹wb7v*dXȟ{4dhlZK=ûOUVW `-m%>8x~IRY!>}YnW @UG5tf]<5lp=6~w>mW)bII.-#nPuQ@"YU>l_ֲ̇}yp2q?zGiuAu5qm㧥Z(QE!QEEjzcJk|89VÊ8ꚬPGVw7e-mL]3Kh]xpsIn}hBw7h?[EKM7ԀG,0F_&{RYNO?[պif=E%8ݸy|-ب]9MzO5UI$6{nCV)VAqXȵy-iVhO^q1`=2R8Uhs K<D,7p}H+B*b}+Oꇮ%.܈ $*1|`?jn۹Y?6I? ?uնIg1v\(!sTvQEERVwUPK =u k{kev')>v?l~8uQD|O⽼ӥ HTa{yom{v 쩌𢤗EH}yvn-jD:rƣ=&h,I7v4p:=$q>{BIlw׏sqxZ'd vҘ8xkaS]P̛B0$r E FէsvTޛ S=M*L˗\7]4#+Bm3CCӯXӊv9!@ËfF~ c/%SȊ 7)XO|H]~\-$nr=Vb ٌp9Ҥ:]|Im csO[Ȏϱ.Bl:WN0{sN xN}ibPqR!h-M8XF+6vpx#Dբu#y^$)Dޘې~[t m!Q `7YVIC~1HU7WqSe}X1K\G)ed޸wn'ҷ{+Y$ 8\(_]fRbL 𽿾k|u+DX F*1>P7]5)HU[2M*3`N8{O{;Y.ZrsS[NfoI8( ǰY ~8u8/ ۸8 iq 5}RI;b0˻o xxDS-A l$}eʘ0*+%š%#ބHc/֡ z-mf3 $IK^`84蒂Hp?4_z,QhÖ,tt-A3nn4 \*1*,O|Vd+t>() JPGyNV[RZK{Me;jAD0 &mn@C+2Aiya[h3X˂9Oe4YZkÕNRu4[.Dp IH*]FQd2t٤(ڻ88>QP`c@_RgV'Ͽqb6P^GW_Q?WHᤈaKd>X( 9׏V$TњY,·mcq<6Z 2AZՔBb+2T=ǯQ|1BeiySS8k\\a9I"}ЂTTsVʑ^@Uϩ ~T _7T[^ru5!lE qEg^})]];K%!:RT;՜qxoQLEv`ci/+jKf+TL yY ܊Fƪcq *di\V= 9kKn%6Y'[,eI,1{׋ 3w& W@K#f`Gh'3'g ;0nDd%ɵ8[w(Jg,cF?uɏT#^K=WK|o--c,ұԙH11Ǘz[cN~àk\u*֟kFy;8<A!A2FN12!@EJYVXAh_V><βWXه5QwRbEow$dw骧78ZZs}tmkDžxY|UNMe5Ho迄7c)h;R @䫯Y'jurAon-[\L+)oI4"..)X>}0ڻ04ڞD$sTBѼz*rW6Gk0Sb*W{wj$ErV%jTdѠIgojC%nPU8;xmc,rivt|q2s;H-NUyaT. !(pp^_L(`x(0Cy@n{x gW'ߟ9cp;=PN?S-uhlD|c8Z?uw8Yi0DHrrr=E[/=Vtņ׷֚B9k6s?s~ rP$8=#A¨Z\kIetX s|?4!yEPWҟgON-\ 6k=_/<}tѮHUp=!f:^:jVU+7X]Hk=1zCڴz}5 ک FpދѸ>bT!5Vx?\[i$U2nbREؚ*âf·z T`bhmG*ؿ [QbtR_A,;v?z89feU˚dKVM 試Qm=jٷ +GXk#"#iVli-8.վ(ՒBFkX8ڗ1Qo6*+Q!kxZ16(KV&<=zEO*7{ilV-49dXWQƥb|ƙj;h Lb B>_\qPgk(5ufLlBqU`i#HR}񵩮ՖPO A%#v|_Q#!`Qȧ)fK: ..# AoH-V,.X>*.lp'Okz_N5[3Z0 9?ׇz "!S;NrnO N#&qQ{Y$$(lgk^$W\a5Ν,5t[9oՒqV+ iK,j@~ڸ1G]kt]_K 5V ',`;c۪#Y`7W@dL{ī,`fqZs21BbhYBw'h5[Ɏ12)+BL"tLqzDB<-1Yi$[-歀p8$jW2{ۨX~?> ^Eǡ?YjE #1YF!(j|`J.U2vn3wlwnG1 WMu,q5lD aA8c?Is^vyf2'98j[-Z]"n+7S3.< -)f,>/)^jCE5 f2[<@=s=.혰_/5ҹͤx 50d)sHdٻAU[Mk䐩VIP TNZB`urBOrn{UB=ROem] SWv`n5{4u J@XoOPj冹wm%ݫ,(Ek BPdV RڛWţ1Y ?cҰzЄ(ka2`IsZ\y'`؛f˦i|6T݌g%0AN$`kZiQ܏jp#co/\ɸqf'(n4Mufh#r|Xʟu5Lh+s*\>fd'#n:,0*09TV#aUr5!/ʚ:x:㿒F S9SP%ْuU =Wh 3Z[HR\IMÈ7 !$JJ@aMHe u%;jj KeghQ9_I2g+S1?-՝m0'qNdp;n7@kOrfߤdр9)R,nPw#a5mdkIEȷNf^c$⎨EHIk]DHs?^V&zD0Bf ׸vZWSAM1q#G ##ofE^M;sjvM O%X%2dG_^3jJ hxqcߓW}mӎpWÊݖHwQcb2w7z>am5+@$xl̸>R>@mwaiIZ $ATv9{ԗPh?墊.&q"I$zsVݬw,mH~z}=)y7+ eO!snei'b$j(B+E 5wd ā-՝@ö}߭mm9%k'; !qR<`+85+ښlSʣvAKPW5ƛNPRC 6 3`qAЮs3Tf0 S), qǰB47{\*HjrU&^FI;8S]!}YK6*S**B_CQmRyTrTW^ T,Ű9$bbO"O)M'Z\Xl׉'iTHI72+Ȇn0948 gUV`  gמ?9N4(G$>_U-z-2ZHIbq1Ϯ=QY-pYwH\/FI78\*é#'y|$=r}ZE⋣uPĒm7(-pENGk[i6fi'͌1zwJxGTRJo#=+-1@=BZ:d<@m ù@c9W[YGWϪXR "Sqs&cWo, 5)R=3@6#4m34!VE!:fBG bXc\K;$jPБD6ƊFs8W>kV oK*zZuEz MӴO(l籦ic 0)Y3*=k̋m%]ÉqM ?{ijp1*CM fd|BdC>(DOR⬀ԉ Dy'LRd^29ۏ' nQ, B4޺SlhSSCodiQ9>Rn-&A(n m`'?~{T=E *ϛ! mq kQ+FYJٌ ֘ң9YdH-G'L¼o_˛|Q!@?j4}(xʞH^}A?+2V<BWi@i{_̡4c7kB=ClI(w(^r3͕a=ܗ#t 1.UH흸<W&kBB(®Np (+>gl>=WLGABs0#bF\5I@g,<{ =AEQU\SOS#=I)244G w@6zSנC1&/&PrDXV$A S5UϪ=FL&)퟊bR60a`o㓚tN4!\qq RPq<j'4ˑk'u&eHe׶97`b Xd 0s۶*!lIBH:08q~q7s( OجmĶp]4e.Z3G=!5ͣZηŵvU#>gNS&S+ Âv^1}j%yq U3x\.9*aORZu/]G[q*o s=CZŒ]XHZ  {Xmfk\,DJ ǻ'(;$ȈUx%Xk9$BQEWZJH9QsƛԼ8&Rl0L1os<"kH -Ay6i\J[&;{+@U!0fݴ{O }~n"n6+hw)N{~r>nz7~M5۽N,QnLDlv1a[9CM[^X$i2u+60r\rqY_Je*Gp J]Mj1q8i#l2pÎG+SWm4d3шx(_$d5^4' \4|gsSQ/I&rrI&-]uĚit\d(cOo`"((B(4* V:ψFpA?eLn'QE$p 9_;ޗ!,9e+$0A 2>Ehz/iD6 hsr1>`B1ꋨ׵ |C<.q WGVwR4ElW1;-Bm-RH76x\)YM\KylCytT$ < c89Gv{uTH p3ҝ+6B2\]jBbPqV<{I;OJ?tCr\\:\3"$#&ԭ'QWtahɷ:9V6h$fg̘r.}~=Kx5YkPK.\#3>YWvͪ!#MުnZizkAwfM[!0[T 2f򺺥2m{}Us N0jdxRH$OQOiWqS]: {eh[W)GNuVǦ]suEC2nj(\wlsPId;:G`Gp+^]O{u%ԯ,rIC𚉌WnO׵Xj?9Xc8YI9$޼EQBEPQE!QEKGTA'{֧F.$%ϵqOULٸoOӂ=}~N;K`p$tp+n6I8 W47m/4k5>U-1H{bS#pHuRO],EOgqo\;ȵx`PU0"7>BxZo!M$r7qY}&X~J{i h)Qr%i{/:A,0BȭcQ9g<<oo‰7yxlބ-6oywAym"b7*r@PX s$7CoB6*W,y^=_u}cm-]$R.S> ?8_4ѧO(eO)N˷GI8#4!Oy-5K˛PF:!d `F@~ry=龻O# +r$O] /ӿ5qjxi1b6N6 皵縙V2y$c9 kwm`y#9߀2.s%W;6SnJ$06;gx'3/ d3.mB#I&<\^sT4Ԟ-Ď3bG)EPQE!QEEQBmricron-0.20140804.1~dfsg.1.orig/html/images/design.gif0000755000175000017500000000510510653733664020372 0ustar mihmihGIF89aDBD|~| >ɠA~(`!,0I8ͻ`(dih p,tmx|pH,$ШtJZXxxL.zn|N։nzM]r=^\iNL{|lw^nı_ȶܶЧɷٴq] |*c m"@j(ڰaɻHw8\ h3Vqb=$Yܩj߅$I'CШӧJjUK"Bu`Ê*ٳʢ]vٺ,pʝK]˷߿RLx!^̸?CL市/k̹̞C]4ӨS5UXÞMٶsVC ! ]x+_l9r υu}CP>}x݁%Bs7 zA|RqR(xZءthqz q>"^h}X1VX b@&%ـ7ȡq.zch+>X$Gf$AfDnX`YBt8BX~$k%\*y`v&2Ny{9X٧ih袁 裐hVdVe馜vꩦH}*ꨤjꩨꪬꫝ"cj뭸++k&첵%E+R˃8(v@k覫+ƄʚKԎ,ג[o.ܮWlOpo T>{p"Kq(2#Ϛ05K"Cܔ5+7 {#w2.@G-Ӷ|U,TcPp;3PSm>[0DבM$Ås ~疎W[[|Hn;Ѯ|d63#ys/ ܍C/ o;}?>='ï֞$h]ƀFH2ُ(HƄR ܋&L WJBHCKM8 sCE@"1.^h0J  Cm!Rteh+b=Z /&fhFL0j"0B& 6 q9v4Qz Yrd" GR!%KBGw"^|^b?|B'=(g!hGNv+M(D%J晞0KZ2Kq1$rDf&YMFv fLgJ Tpsd'pSWӂiNrКZ'-5jO|.4a??O=}4Q(IdCIRUFTI'Ҥ-%0[s3'x㘦 7ũMv PGS u9J]j*'R Q=XCfRh$bWաJZ**[] J׺)*^zg*`̳u4,b2le`CjuU,m*kOkok8}VbH[ZblXZµ-fJ߬T YU6+WzprQVrAMÏKeu`צ"JקB!Os8p5?nG[ &(_ ^gI&\ (IH7pEĤB;`qbTI~hF3cx}2q|Q;=ɗ6mQeӭntMMwӛ_o7*K=L6%nos!şm`47;w(?S9aq`g!+mb9cj^bWȅ>r̗yř 6OtWץ?u(eֵr/r{ڣA Τnݳe{ɝ%{o<wUfvwC#w}S|a+]|c.o.?~˘cs=񭏂Cz>q`d52meSfw`u.JQ:<={OOK;mricron-0.20140804.1~dfsg.1.orig/html/images/transparency.gif0000755000175000017500000011500010416555034021614 0ustar mihmihGIF89a|BDBD"$BDVT|.|b24dbdNL$"$b*,bdlZ:<TRTJL^\trt424|R |r"$rBDZ\|:64RT., |JLJL64ljl,*,j .,><\Z\|z|<:<|z&$FD|6|jfdJL^\|Z&$Z\RT|FDFD"$BDVT|2|f24dfdNL$&$~|f^TVTtvt464|V |vFD|>  |NLNLlnl,.,n\^\|~|<><|~*,bd:<&$0;w @ ( l `w||3?|A0/||P0E;|XPwmԑw|!,QH XÇ#JHET-V\(@Ǐ CqC&S\r`ɖQœI&Œ0eɓK:{ gND*heХPt4UMvʕh֕OUeرhWNey6ۑeV}KWd\mxwd޽;D8)'0׾~ W%Ć(D`|zp |a~ ğ " I|ݗ~ Bx  .HA&~nX/jc(;p=d LRqJr,(mqЀo,2'Ɉ6䓑MGєU^喷uIbiAhɦpIPhVb%^:fe)Jkf2A}V楙&(tC'0Re'h)pl" IQl|0 ?,'Tr TZĬk;ls4[Rk-*E$ : ^-)ۆꭏ6o.ܮD 7,ãFl4 'sLs$*<AlX H,)f(0rhįp{/&l-5{羻 ?QiK9󤛎ꬻЃ}$豏zG?N =F`'F,Y#LaX#&Q v RB&tNTnA rЃEHBP` CІ8!C F)M7!Ra U*/ p =!z1fHtD6ЍA#xeȣgALR@AEaD4`"T&PO]vg#(@؃Phfb{D[rIdrd(GiS2iJ[e+_K2Oĥ.yK`QAc(I g2t%,ey Z z_v'99t*s<;eOjӞ>Od =C &Nq"i|(@ |Rv?@Doa OphTP {!#Po-Mf4VE&BƑQHiAXR.m5)#r'B%Q h!- J!iL꼬-}b VJ:MYӠIR1׹>QHW\llJS"=e,Z[ԊdIG #h(&Obl $mSN=XM(HX6 U* 65o+4 M.4gFw9Buǻ ›pֶ-oU.}\fu]-);6ļ N/^Fȕ0s)l OW毇 f-0YYiD!\(J ِ)awen&DGP/ҕ0`"x"K`bCLɌP2'GyU2Le/9Oc.Ӝ5p"謗&HF #'yɄvrDc>:lDhV38y/F3FL إmByrj ź˳6'@f\Sm~7 xa^jY0{$dNTR@TЃWF0mj$`VVq9)Ҙ7@)2]`#(C==Y =zsX7 p'\>xK?<(8#*~o\KV`QB%9F݆d\.w:~[sI %N=Xx"0kAX7̹>\87vlۋwϽ+azlM"`DFBgY)`OBl)Pq%]ٚۉX~ #B0ǣy< & p1^oS?շGho{F^{=-;{ (0>|C_kqw#G [6Tl7zWezz'{W{{{R7|w|ɷ|H}tQwW}eY3|ǀzh~~~{c#|'t1`EtQNwvGP s`J\/SC -\d47ws ! " A SQ\&GS6iag#'rg äg/08PUxY]7`bHvxnRj0   k0u86x(z8MQP-ЋՈXZR\IceXOgk؆oQ>0P7prHo"n+rEV0،ȉшQ1Џ2w؍Hwu-(g4+2l:28|00 @ SRer=Bb`^4 > u~%9PyCY!9%y!5/`AYP,Ro25|QP'-Ћ0YEH%Mɑ fxsRi)Qx x5"4*xIU瘎JUGIL| )@1Џ2И-ehIr)–V*0 #PvAh 4/CEa pxg4Fs)vsS@"3^0g ;z5 us iY  w-y-0u0 ;0 p)i詞Wp)şYǙYN((@։Hֈšp Z癞@KQћ/+Z~Ifh8٩03"jHSA8x5q !gf r JђHCpF%}XRCPt ϗ#ꩤ@p9IzAz/ u~ /2|* f֢ꨡ }c5 Byc0*Qʞ,x q Wp|:Jk:ʚQTG0ځꭤJ* {ۮ{ڧʫ ZƺwвI0[zʩڭڰ^QsjY Ivzx:sC5pW %(]B/(*y $\Z }@1FGgt@ `7Yyy7Jip /9 |KkP<H{uLN[ P|R;CeRpubj\+\WaK.c[fj7ٖ*zWQ{I{z{2T [;뵠+Ge{B[Q+Mȸc廏{YQ, K [i+=!Y60y\kt۴K 0& +֔U4e+TCg& `4yvf  lsP 4 &\jW|CB&U q ܼ#\MV˺`誮Q8lR:?B0D{<d ĊLŶanFl۞L@5L&žֲ0,ȝ3Y,;; 9b.aJfk\K-6K&YW W%U;LS#U[\ܶ<zz`-L ɓg uP ˼˿Ll4Ĭ<:̽̈+S,RLٜqXr>-@`@ $nUBಮJ &6n>tX՟D~^uMN赱@˳K#mr]Z~vdQt[8 !t0Bw@$3`{OM; ݝc[⦊n}z)59;`34/ڮܮI,HvG`"?GM_~XzJ%:.횡eq>U:8s^ 01?;>6o9$ Ė~pPllJLROX?Zj1S߂ݞޙKa %?^* tp \d|sO:?Oh6aT! k` 80j <%^;w߬m$_*g_py>>anW P!DFQIp_OID@) :8RJF8eDD,!)%MDR%TL,:VN=},4#>M9zt)JIQTBVX DC)~̸ǐ#o[e^d% 5N}&\JaSr0X$aLI`8!E>%N SBqL{^7^}ʡ5uLFVQKW%Zta!7l Y]J/1ktѤM֨kزi-@T%AdPA2C,;1,`6댣+Vkft)G*#c ;0l;azDB-E6b6TK/3LWu^7|N~-Mꂍ88~8+8c=y>l ͹NHz N:i};/jߚq5cǖʳ܄r0*94Q=z"ư_Pd6R$0(L"\)0Ad br*c .r&`YbhzS52"1yWsMiMQ'u{!Fa>I@}s'?~+m(^Tg-y`4=z"ǖ1b|;ҷ/~ˈ }CaNsaO23[򤴥efw١F㛔Kd1SFPAhyEY;.6z%)ƖD\|oPL AH@"6+j3| ᨡKxldAY$\t嵸1^#@.((Yr<4/ ~S:Տ#ZXgDtC?+Q5ne0KǓ4+ c>s\2vw ƒ%LX w_>g|BuND1uNj=/+FR3oq[vR("+)RZ *g2#@"rC1fMpX@YB]zc'X&@.YQic@&ښ>豾>|ٛx#K{2???ɿ`<5;Yۂ4|& t&3$A Ac?+C @C C#3.5T ¦@à :B@qB7@-4?A?+<ÍкȺ ,$AMH۩ &"$QB @+I*؃`R9BIȅȂ3=.(:Qy$VDDpũ-R\SSEVTxX$$ZE(yAAAJ-AY+ i$ j#l+DoGBEy l) +od( YkqF@YT2<yʚ襗SI^4I?\Ȫ\4`3.3hJsLJ;ˋS"K=)kd ˦,{L|~.$d$ʮLL"L ML4+ˇKNKK/ 1, ;CBHC.a6 7Š$ʴ*LBN\tND̠lM{J{DÎu*p )K' *ûK 89#SHEEx>H] L \\PLE/`# PH # = 1 )GcKQA;EQeQMQ#ɗ|H; R1:%%mMz҉PR= Q ]Պ13- 0I5 xS:$uP6 I;)E+*G+,%+ѫDS2uTlD|7NK !E Bw)a}^Z"uaH>̎ X"F@ċ88˫ў[]h=5Xd5U%QtDs@a%ֱ2C;SeuَvV(8J<lVnVVpW3 PT.yģ۱{|}m"^XVg=IjeXn։WUTCT6 X^D_`-Y wKaV"uÀViمlوם%О5GSI\{ tA]"Ή:*K@:mC [R`D"لNH- bVdjV@x-EZi"UY$Md i EҕĽ}2Ъ]R(M\DXt\\ӘhU-|9]Hԣq݅"ح[\5\U\ƝTJ @S ݵEuL*j]^]] 37k$t #_պR8@讹M^'< H8Q808@TRÄ"0"h\9X5< \~Y , 5 CN& 1I *vք^f%aa.XYG#NbYsb"b<]!`IzYپP/cva2@>%aßucc`EE_ԑ<@+,^-dDPaCNd3fQ`rJL}Tp;%2) N> 󸷲1K:4"af(8 FQP ,\\aD??].eek^]5a֊(yfgn2O,ik mn(ҒG6y&Dg^}cf cdVѲT}憦fYlnfzqhˈIhgji?J(n"~放*ȗƽfvhf*J.=Zc ZSN"湮C$N F>+0wi2FQ=>` 03G ]9p\:`\XXЃ撴`L[ h^>Tk%w6lNnl#xj5G]f=m N_^mn֮kfT ۆVS(mv g 6fs%ǔŊ6mo6oFoV f%i D@k~Gզ jml橸>_>eExh0S(S)J*^ohoL1@ gY*6glD3/fe *NJW? qqr!hp cr:-/q/! s} 28L5* ߌ! rq=_>ǻ? rbq.7D޲d͎Hq56t7sMNג8%.фg4N hmC֨婝i'P(AfL(Ӭ*fVJNP(0cg͖aWBe%gv^gvgmq w|BrwS#PwawwW}w6vdWv`vo£MR^'U>:a@'Xst_vyx/y9y{g͖y.)yO?ڄNyzIOqxtow'yygo8R+MXE݃.)oC8/G.ym׊n{JC嫪$mF`wT@{躱O'ɻ{10f,{|o#/@Vy`!ں%-h|vU})}Nԇ{8{. ͜c7 >V/}'|sn`9XNh*x~ ~p#E0l萡9`D 'p>K"EIE*MJ!I%4)YS&N&KJ8>BtDR*Ԩ R4I HNUJ %`$!J(Ql;ۂ88#8j(JM2(`oK~Xb:[$%ʒ+MTb͊#3F"EѢJS$z4h=4J+`'hbD*LiI%:mrū_ cr,Ʊ0ɲgu4ԫ[7}86ʟo{o WroU sU]y[tQgu=w]e⑧dNfTQ!TI!~qWpQg!`sBQ(vzFeٌx6h&|+b}1lݘ[(Y(PGRf"e3FفRI.ez3h is\YJ\fQFBy+g|}ڍus1'#  IxJgyS:n*)MVjzh Gb>FjRʗ*RժnU*+k"yruޙ'~kY6cB&d-K^J.6.Jxn@]nzkq 'z1)tE0j(kjV"\nb^"QDOHALD #s(䳠F&6x'{ߩ"QP!d2vQ1tG&M֪Ȱ "E 2Jp$rV"{r[5os c}Eiq Yvx%w>xG'/&R8SȯNpyw9Zr\uرm6hͶp,wutz߀ N"c=/zl(g=is>/;c]\>ͮ}tg*Iww5&iJf@ pr[0ApN)B&$0R<&bٌBP0 &@  q'*LĖ#@9*E&Ahn (: ls*t 6SA BH $jBL(N#VL̈x.zbz!Q),rXu">1b!&:I'Fq%--M*bh8i\#*ۨUQt#G?RB.Y)Eb$ a)Ic$ĢJ̸@d(l:*o|cRZYWs䴥c O I2890d! M)LҎGZŕ`(+@)gYyLY BO8?] K`),"|@p #$btD8-GR4'EiLԩ2UMoʈFvRi rERTBUT%dZaHG-ѐa%JzR1i\qS>%**z.ڨz]jS%ԨNL,EX<+e-k̢U]gߊu')Ԕrm^;XY;$ ^$+ҫx#Hѧص;-UQ!,F]>!DVa`r#B!jVDP%e^eVneW~%g*gYvHHi¥j%kkDl^f_enCSTNfe&'fj'ܙנ`TiZD\a卂)!pB`M( %$A ^&%I pE Ym 8F~EQ`B|QggcH( h 2.<J(Z(j(LBa~hYE͉JqŊ.FҨx:G}g(i )&i.h4FMh^)dhmh"tCpi*ʈKQh z錎Bis'~WG)ƞ*9@i"z(T襒nGh~jި!""ڬȗ"IM &A( NHi捅@$N,*G"%\Ĉ#c2$^mk)\d^$E!F$f&jnEteFkk")ր.¾E B6F.5>l ;R(TaJz++l] vFZ˾,++*N8a6 Q),:l --`NkZnv,ւ֒)kFغk¬&B>DΪmOM:­mH"lv->[WP'+`EԎB%*ֹE6E)dr @fhjpeC+Bl k۲ " mE H[K)ކVz.n. fh".z/#%A..B DpS$OֺtV//jnn&.=n/ L_A/&0/*pF߫gomoBUNm0 -0ڰ 0;o1;Qc/dtq/Jbjq\T @,FFY'IiBBP#ԓjB&@+P$>oZHȱG|i%IҢ}kPDAD@!/F"3"?82ݘ$3%[Td&w9(Lp)+*)D.4pJp+7j dV)TrQq.g//Y311227r=2OD42&'5{l(#7r8+s,3<_jز=P|/0p[3"4#7A?s$[$W2C[sp2Dks(OtE `*q:2;=243sJJ#[\-"#(s&d(H'FuLF|IA@"'{D   4,W8+3)t1^>ty:+KVkFtWAXXFH[5E\wD]u^^Ǽ&_E`Gn׀xGaacYb1vqTdTeW$/f6W{5X5YvdDj5kW]5^5_m6)Qaz|^c/c7<7eKw1uo6v{vcuE6$j5yyǶrv_P㶏m7bbrG2=wL6Uv}(ȗ(DYR_K]\EPH(d"`)B\I@(BkU ȪR{W۴D_8v_mGWTY@o[8z1ϫFxď9 y?ɑKA/y?y..#lY"8mSٙ*"綹о1Tnع$z#:&)¢ 9I3Cgz$wsySKy:Ǻc:We x帶2%{/;7CO{[;gk9 :Ǻp9n9;VD^D|t"$@Mť0"exibGPA@X #@Tmd%@gF pr֎Y|DSQϑU!`FɏBǼ0|l6vU'ګ}@ۗ<ʫ|Iͫ|} '3=M8L@xco=t}-=s{S}ʷ}<v>? /}G=y@1(&FPQ4τ# h$J*-^hĎ50Δ=TJ8QѤ)A ~(P$NA&U4&E$Y")R 00N&N&` UJ]'hI"(0`ST8`D%v ҵD9`ȈÇ 8'L=y1E /8QU:1Jhrɲj2iĩOBH3 5\ϵmdʩ'B:|DDDhnE!Eb= b=@| o%)Q9$X$OR -a+M昃 *R@jNFLHaD ,3TĩJJDR:(LCHNΨ8"Ac(0$$8p $bQ9xB*S PA 5TDe4GTRJ-Ŵ)M9TQI}T)PUU\YiW]+]JbEVYØ=Z*VlSضn wr]?C]G#/N? uԭJ=)[}5Y%u8\U_":M61}6#ڒA¶m\q5׀"`]9ޝ_k_&XT5Yi؇WzbX?쑭MSnea[wx' 8aF bj5 NH(ģ RARbIع&f¯\.N> FbF*#t 4TS_ ZM;vӄxOxē yy֦WT\/{ۛ'WE 3qG01}y_W"S@3HfW}] zt0;^׼|zh@DĎ03t"%Y$,B&XԷT` D ^Wfa@@)x3HL(`/aB>QXa>XK\r/ӐWB*N1"Ls`ŐEfSi1SX0sJ gҤ5)mzgRINsS;#Ӟ'?4Q!IADK(& C9HF?.ѣ )I`RJx9j3BMqʯL:i5L!=[%M@ kFؤBwe5%4Q͈u"GC:RS\f[חuvMS>u`Y֨gcXBj*0"lV\WEҒfUmI[HR! G,bVP +sMb2@0B`r#dy N`J50F:u9ƚGTbF8r?U"+N1%E8JkؠWM{t1׾I/ 0-Q%,S!8 =J/M *U=h!A,b8)VGZx 3D];w]o{i}s* L9 nSp_6J3SهhK|b7``,cx8c@WȄ64%;ڝ2S*[˘r )b5TjŤyĩns"bWtԬ9^#T&R!@ Ҡ "푍)8TuGI2A8JL1v8L/]N am2B ı|= @*Շ>LF;M*P|pwݹ;I6N| !R@\⚠O./_u8%Hu%0ur ʑ\<1n]V~ԩp\xyx'^f7;A!'p7xwyk5xx^D;~(e%pT^\< Η8־|{Wow<ѼN6߻Fr.ӝO)QoD`D"@1+? > -WJb/ G4`"h(U& <4f0𱪆&96kgT `((>^"䌬 F$|ϜO"pP`AН4FE!*W2P`Ojw@(DHLUQX"\0c=^jxk/e0.P 7p G`,0p|sF'Sp mdqP~  Ȇl $0 KkM%Kp&ư pհQP5c[1RB 2$l+j+(nA"97"\j:m6 ``p#XGNNnӺ -d(FE2@,1H! @  "^$uDC $`0D &mqq 1EqLOi(r& b}k!% "ν&l"3}8#AR$#$Q O2ϴX%aR&UőK'2J(GL)q)Bk2DRrJv+-#B#>2$GrTR2%"%cRjM%&R''r( s0)5a1R**!LJ2=0."F3{h#;324K-24 5ߒ5 @AALB^,H@RSF7T#gN` ABA 0 vVzh"-BD}l"`,n7B %`N %!6a2aZ>3!?b?~xh@e@ @t+gBM "tBQBQB;NC2UCI&cDDE3AEYEarF?Fo4GGYC%FGS==>G??EJtJ TA/3KB%4.֔Du 4EWZE'bGuOuP5H HHQII#?T@+@STK9KTL3tLLQ5M?tU۔ OVVmNO1W5jWtG%T R.C.2a>ATx# CWKs-F?@b yu$+87/2x#?8G_#WZ!.fxj(~h3xS8"%8P tf808O`%ً#`Ř -AM=ETXY؅}궏oEMLJ ;L8C8!'Ya X)ؔQY׸QX阖c0bD-t=0(|yِ@Ksɭ9+nXcg 8^/,AmsN7!LF" bEQ`"16*8Gk|:njkBc)bZRnC(s;;_jՅla z=5 ԡC,'K1Z9ڣ/{DEQzJ]5FSv:NBrDvڋΧ:cg4KZzS$੓ ڞ::(:3z;A:KI!a7a~f!+ L3w#w pV{Ω5$;0!Z9:˚zOUX۵3ek)B09 {[]qUFEiLԓ$RPF\oxC0a^-`#@G Z7^w&+hf(R`x7 Ra%,{1>}5G<aQy$%TL7 0 N`tc|a jH>k0g6pg~Q>c~J?q^G'-i>04~>'I_MiQ.~K W[aov_?%2L>PPTQiS*jR$ES89<1Bsb 3''`,9 5Ta Ms02"TN8dԄ*UP} -F)m{>#pd֭YRjR#KM?bj4`S) :(E9zrdɓ)W|sf͛9w(Q *eiT*(+L^B,Zl:G% ]nVo #G6†}f(bƍ?&iJ.aʤi_P(5QI-\n6UU UW_5YguA'twŅ]_9mWwW^yMV{M|Hi`k<ہm : BZwqɕ\b]#浗]x0H!Ez%U[iߜlyRR0Rl '0PSS%Fpb Puۥ ȇiQIuuUGH# ! –qHsU1j`:`,&-qКmFqGgEvY{gzh6NRH%黜6"+HC)੩꫱Z᪫s ,XXl,) Ur*TBwv'( h 2(Vʈv5/B Rm/%+]+IqҺqg+xz+2\綬0ܕuz9>D|4I'W KqDgsw,kW ''#2" `JT`D ͝j65IItPDMyA0iN$ lR, "ҍtrD')@V N)'k'FQ9vUM^ زSU矇>z+:S.R5$`.:Xnimw2]fG) xQ8^W=oWx =h{a^"UM}z!9Ur838@ v@QjJi.(̏ T hi¦nr '9`NtS.; Ӟ[' JQ3(*>T|DqK^h1L1]1i4qG|]!/eDLS,9ӹ4Jǧy^Z{beR[T.婪!+ KJ*FQ'c-)4ã҂T$.u[QMRu]wڜw`"D0B G`¦qaU: p"bp!w >d&Fqca+A&F3Fpڔ\6ƉL BHHA !4γCL&Y(4B薷(@S 7r%q+>)pU3V5v]]~t}h[ TE {^ʗ /~յ7 c =dS 6Y ''հ"RL]bW܍qxk\R 鱏u ;,S|J :8zwr >-jfn=Cqe2Wfo&,:O?3Cg"YЄ^h)DNM9 Jő'&ZLM,C0jd.FPE$(*ooVr'>"}D1s- X&0NЖK`&6=#B aaϷP@΁ x?nqfkKcώm)e{6qHIwH\wûmD7%uoD>!Op'pCX0'vd+{q%hvJ.mj[7[YyQvM2/7jgNٹ<zޱ=mt CE0_NP^q>)@9Qf&̫BڮT 2 w"9I'6^P0AO&8CX>^& KS1G|&1 P>3?bru||}W}ח}'~jw~l/`~SCj"Bc${O~W 7 L[Bh/8i8W5%('('}g}'K.^}2\4hW!;~?"!A΅|K(M8" 4QvrZ(\X|_Hah9[wdhVjȂm}p7g~vy~|oXVEXJhHras@MǖHbH1K|F Υ:ҷf pQu8F0* ` D]ARCn7!p<* %[Cw:Ip+~uOx$4 xH1 5Q  YP@ b P؍~HHUU!7!A\8cRU%H*;]g~E  ِ+tA[4^x#*%YX ֈ&hȍ8=m?yBE( SIY ٕ\9< fiYbk -’t"vYxXؗ 12L9Tiyĕ^鐘dٙj鑣S)PmZCHP8\;]@0*QL K1ēd/|plQ0^$UmC-rMLYL}FNkPPk),'eԝA ژ4!qq癞εIfXɟA*JR>~E:N!Z5%zח)-ʝi96:i@)JjmYN8P:ʟ ' ڥ5 e6! mj(rZ,tx: z y}DFJIJgJy*Hq`JJѱ"Zen*\F dO#J9T/Qdh {z)pz&TElp(0ҲEsꑋAFP@@p;Ճ[С p * '{7: rP5ݵg? b*$9I ^گj(K k ˰!Ly {;#б";_VPxU+۲/3wj:誮;Ĵ zU˯ zY\{ $ ekg[j˱3 $WEzu,0+ҷ9[|OKR T%A뵜ѹ)Ck۶Wd&NvK%m`um"pv Q0" K':"p` `} ' E#(*#L_yZWcK"FX F4쩱󙖨LpyBT[bq ECж K z P "`@!b Pۿ<| o | L>[g&A "L&S AR. 0p9=Ah N[n m. ù/> `_(^+/+N5nhqߎܳ Chbbe.ᠮN>y.>1踞[e! jD `0-P ? | P=*P?" ? agሸp!`&k51p_R_֧T2 %70fm K4٣Νa k P z3 o P/+чAc!G@`p/>x46O"y!)a@}~8~X ?m O\s_w)2OW8O#NȮihbO?ehok_nq#_./16H󄅟kpGzNq 0 O1"o`&T 0A0 $*Fm:1) @ER(Ҥ)A J$ I9$Dc&#F@O JsGR4jJTOZժTVVIQ*R%;jQTHR&(iQ 3I\rPxƮV/p@#`1C A2tQ"E5rR$I(Ut S&MFpPFNP)TZc >װeɞvmoŝ[3ٵo?SX r 6|qbŋ7vrdɓ)W|sf͛rک'8~":*z*+Rp܂K.$ /.Eȃl-3cM -A$ :. 9$ M*E9ҤbQTHq=\D$ :MGF)bE$ LQ9E.)J".5 bT) R8>$'ISN BRZ*X(#RCTRK.1T]&=ॕv\&he3Έ <@-DQHךK3ݴOCRO$U'pXom2B'\wVbK:62.Mu3;sS]H|KS/.oM)W?qR(g9)`NsɶSuc`';ڕ^'L7<xS=QzQ|G0!$6JkG`?Iq,-vl^KA2~"L΍,$aX{ R$7D/DK@G.n,S}>fUF&6BSu1*H#n " "9Ξ)LQP& >THAOp8B2*M;A  )ϙWR3IgFE,t.v RZEQqMn›iNtnBt9O*'? PN=ABЇJ (:1Qz7iHētiKCF,6u&4G M)Ps̎W=g:w~buD>G~ZP:=X]/эv$+SD값@aaIũc!+Y~n;75;rvV*<!޳d=YUP֪ՠ}lJ[Z+H}We\zZ,# "D`8t)"`=D*Lj pО,bI ZnyEDEh0@"68< l(N$%v9 *+KT}PW<@-Ã\6T9`k.4<hE`r!B/a8lX"G\{5~ )Zb˘6Ʊ{s8C.򑓼6"/H\e-+Nr5܍fLf7K np5 ư9hB&F1"T\Kc:3sZD62L &nP+Z*沗q-fY`r ŞAl /^hjKڔf3mNKmnT7OOna}Yk޷^[k~o  Ep5!(eD"_^@['=A`T!*|b)4yI(Fa _n^s-S $C9BMĪ4A$HY=b9y,&="V00.t{I_iu+@]Tu{b' vQo;N~&*{QkSE/(d߿i\<7ϑ}}E_ңt~Usw'T>;;>Tk#$胘³> c4K3:a{===k;;@;J;q>D @1#@_ې) Q#>2L(XM 1M؃H*xS8<< 蓠 k26DhrʐMkQ (yZ =Tkkxer)B3@4X X0H ¸B01,345l7Ci++C;C=<R&;@DBCDD;ZFl8H/K܉LN<OE(•+,&[B3E2^܃_ F789ñCcFgľhM(İ8DSD `Ľ{DnD,S9EDQrD5)uRl;xy{|4CE546Gb,ƁLƃ\F><(?@tHCkHtmF.HL IrN<*C$<=xG:"ȄA1k0C&8:Ji8  kHM0Ez@ h&SȒN@ In92R8h+s$I@DZTJC8W *j]]pdDpKKK=˾LDQ(̎P<ƴ#ȔLʴLDL~ϜЌ)k<\LhEM ˱CDl˷t܃(KLK?NL,nj LLMѬ4MOtM, Я$,˖]KλNPL4LP>4l2dQ$ͥOFP53ML8k1828=0{LD֪>Ȅ)){+ KH"h#?@Q L1'Jk2S''| E nTH4&P3Y5Wx^X]ȁ ,38S:SM<>Ӄ AB=TRRTF:xHѹLNUQRMSEUQVW>Z-ITS6=(72[f%ghijDFVHopTMT3W? QReSݍw]ՐXUY4~Ld XeӞSS@A%0TEXnXJ WsUWeWuWUՒVMYXZЙ*W<=X>(MXs*LLXT2qpsGP@;3?܄@`OYKR`Ѩ, X\iPI0MOUpy&@Xh`3"[Դ]i۷r2۟`K[qetµXEP\+`\\x*\ʵ\ \\m7ѕ5]W\]]=e[1۽ ]u^-(E&^} y(_EU} -uٯ ۘ=_eLߍ[[߾Uޅ\k6Mm\\u`x+е` 91aBL jD ȄcL1M0@:29uKB;ʝ@6YSȞ\IH9Y94u3U:ȅV=ȁ]'&(*+D. 1ֿLU^4N5Uc}\9;cFpAB NEnd NbLX&O1j)b+,ΈS~.b>Zle{3DY^cpce9c;=c_f@0ABCNY FbgFPijF_QmboNpq&cse5uv3\]^ƈ_cag)AfDgF`޶2h>1MȄb1 ɪ #DS ذT 4kc Q˶LQp幈_f"XH‰SS@##܄ndGQ0p :<\dO1Ri#i (j/F1~j{B F\1tڰ꯮\Nk6f>0vkùffVnSX%lf:n졆.ɮv̖j~bϾj갦3~)f~^M٦뺆۞m1Nlfl~llCvj쌈nѾn>mNm^︞mM(PF% B [L/Ηb@ R jI(h8K8L`0C;cKL;L`Աۛ^0P)ҍ0D3V  @p^I;3^FF0iN`qB gLڂ/8r0r.K=Ċ`r3S/0)*O]-p//1q3'4p/'wsq2z#>o`!'rt$/%p'_FwGgƓQ.S Kp23/qORPos}97us{sou>?uZ$7NmrEFW^01=^0(;N W+KBA=0Hx2$`(;?=׫'  '0T"1#$`N;3<XwHMwx7y2zwwNڈxhK87x7xu4% gr9o9wsy_Ey3wy 7zN@_zozxxx>,Ûz#fyoXcy{GzgxW/ g|w{Oww+L1;'l >OzTٵJ_.7xf)g܈W^,s<$E'Lcz1 Aap!ÆD "SF(F|2E@{. HcG pDHB(d&`JN5‰GS"`(T('G~ PĢ)^t]$v8^O`Ө' j7olP!ž~H["F=I$J,g9MF9wthѣI6}ujիYvvlٳi׶}wwdW0θǐ#KRJ>-#ˤiNF<}M$h&H25TVj,XfUk[rś{ ,b#"CI0F'R")sSG ˆ$&AhPA *6@VD 2(O 'a2E lZ{aEC82(lFC=E8`& ' >)Uȅ&hY8b'" -5B:#BɕH*)N2V )CXj~ H*Ƞ@@(!b'&j,b'|8;c*AYIhOF”U>DiMԥ`v:槡)@k! *+ا:hX6Z챼I._e E$V&-)-ݖ#)GAO"7L&?|DX" 2I9XHAlPyS  V/rpJ Gp_q˙ḵ$24qr+1Ϭ^- *D}4C:M+̰k_ovMclsh2.,4}s;-IHMs"Q3^XG_\9b\Mgm-:6}:ީЭm1‹"<h\Jdĉ[Ad ? RA)l-"pƜaKDa`2+& E3&@>xַUp|A_9 C(g۟7SP! @4A(X=\Ѡ_8= || M(1Hk`h?/k 80 \`"ĈT'zӷ>,osF9U(P*ԈfsGMRJJ$FVXF~&ּ? a>ž2QQ&lB&RD8l21@<>SEUP(/vt^z % K mld!%,-3BF$ӢVka+OVomnTu_I!90"mh Zь! I3@Xr|8DYsJ<-ږ_eOMn3Lgعz泟-^Љ5GCzN-lhg:#T6ePC0 Mmo_,i^3lY߹fww=x{mM"D$ 2s Z`&D 7sk2C$!<#e; D( 8ˬ@}';+o)s*B\yW!s2cE*}FGҙtI֑ձs5ŮreyJjvڱ;{ G9Xby{ <9E< o= '1<+a>Aؼ{я^ #]2 %E8X"8d$ˑȪp/ҿ%4?RaSQB#BX@@U%Q"_EQ R-iQ iB`$ , f_\5Zӗ_  `m  __Y`v`_"a`  Ra ` jp ɈWDHXFh8cOJq[sQ1(.q"@P*A҅<! !9.B  b"b$"u9" AbHP%b&Y''@(b)f) +_,,"?b#>#>V$0V &#2* ):r*a+N#,bMbJ-r##D88A0c&c#(";2;`,),)DA@E6GDA&', ?) O.U.1<XA Y@X2A$$JJjeEKcL$MZN$OOfP<PZ$FjeRHSV"TTKV>d ʤ|Vd}eOBX%o%Q%G"%)[F /ed$UJU^ҤMN`#! h`A ^ ?_I4.reH-)C =@̄h%iFjjj#kƦ>>-`nR eڕojpBDq$rBsF*Fijbkzv Rmm:nob '/'q>q"r2|fYtuf~2l[hxn2Vo"(p.C§faj_&'& rxHD^*\ch$ 2'sZPh Z%K)e.&i,i>I(Y\hJ䨗>f%iLJ*):))Dbif(p~)Ƅ\6***:sFH"HP#'  jX(Hta(nꓑ&F5jA*ªj ꯺njy6 .kjjN+٪NLf*n~+k++OP+⥶+k+FDF)jR&xȘIeq\r-h)LLFERRtL`eƢ@~lȪXjTIJʲ˾$+ZV$l,Őlt -Ѧ`-**FbJǾJelNj-#pm"fY ȁxeHȀ (IHԞ@)  '`BޚBvS -n"9.䞂Rnj .Y- n*niN>ʮr-G..tFݚa)p֪TȐGPXF `EnAo8B/oJ/fN$;MzlOLV//N0oo&o/0 ?0 /Q!l$E. l LY ״@BEK/bȜe/&+o [1"|q qJ(11qjoqGA1 r71r"/2kC$gвl,HH@QG0@mǐ(,)q*mrJ28e2R2.B//0/K.D**q2 2˲3 4.2/e6k 77k+3973-sߦ4s530<`B|)Ӏr|LWdB+mF\ &(/AA#4-t`9%GLLM&F;Fs4[|4Ho6A'tI7tJ;F!g߻=ϧF@,_@W,-ŚV Mr~]/qgȰӾ;D꫾~샊OR)0>׾^]!L&Kǖ(bd93Lu5>z-+D" P4xaB 6tbDPIxP@Eǀ) h @JN1e S xgN)QƎC,y2ʖ/cάjT+NMtEp $ES8GFDa*§V֍.FZvlٳiӎl6ܼ;Ļ+߮Œ5Vap6㼑N l7'q@UE`!kjѦMGȔ LI`7_,zڷsMwiOyx[uߺ7\9s}k6z뽳;& 6"QTM)S8kxȀM#Ë/l B WIC;|BPADSa!q!dI dqC 1^b S6٣3i (TP22)tI,28s244 6K9$τJ=׼ң?rN1 -Ee q eJ'MuNǶ; R)* ~I#5_9首Y*~kre9'R ujeT㞊zxz8Ҽxk|[ypn: 8srHGA^TI NCZT)-4|!dGmX8g>f\u%ըp^}C${G2HKޙlWK=0q,%>f=*8AgTSUgoZW) #eKq^3I[-ImpIW*==Eo~/.,Bj:G'jF"SuTZHI<'.3-lM'57#PHq9RuC^}[)V3oC1Rd y~)@)JkkWEo},0BR=8>8u"RkkM"Ĕ3oeSeN}8{ȣW}SS/z"}9)L.߳ߘ\s[;9GڔHۄ'?aL[nzR*al %8ϾiF/YڼHڶJ\$| 5뚨KRXΧtx1N>e q )J'ܚ][CLsȌ۠-h9O?xx+iid/r cg^{WO HcLCqjy=Ԃ@qۧZ&G)JP R)@)JPaՇ|{Ϻ&q)ז;1|V Rj*rE$ RI")@)JP R)@)JP VpKy㮕8;zK @pG5eNt5 ׆0~UJb<6.Zw>[#1@T 'QߝrBBQR=ct)a8Z$Kle[V'W歀a^eN=dGpo 'z|tkeմۨQJ:;5gQ# dWMj^ԚKT8[iKKR6)3+hH}*S 9!QYi9<$u=[k;0&e閵>v@n9y?F"/HUKhIRN2NΆIAz#(V$cHVG\ E^úeء4O=k#h >̇%V=CrL`d4;S)J@H5JV5xc'Y!8hNI!9*5 Y|1⷗AJQM 9\w!n%6(6V撱Ń(ʋ 8 LC<+K _'.tx? zSBp z:M}3*; '8i+ }J\6cn2Z 蹚J;nuD2;a^ϨJmu=S!l>)=3A}w<79JI=\RVVj9#+ gbl2Mݝ; Dz@>K :#?|A$a`ppkUvzj3RAZwB]=#KԘIPK=ȲY ny Ty&|cі3Bǒ:STTd1vѬNo?wun:\)?^E K)Wf2ke ' <ݪtɝ[" )k!l( rAY` <睪45M'0ۑx ynJI$r|c3J`A<V[M6[u% iC!I#E:Ty_"Xҗu)Ava$qQq݉)P+Sn$P8#R)@)JP R)@)JP RDxze\l?vXC#}79p ? r%OcqnU!6XxVdF^I0sQf⇖Z6vAE9p~2~bn>ԣwa TY z#UӔT㔸[eޏiZi7Dm8}27$-g[ʷҍ=LsU/yQ [# {_+(Bx9K7"4T 83֣ZnBb?H-+CJKֆ| ;td\y?Y;ܠ,'5<^d6A^Q’݂ݵn Ah8<.%֍<ܯ`ի|wkm. l!õ*ܕ p~ڭMsߪBYVHI 5qv#iy•_7>Wd,\ rLUKztX+j6 [Il?zx$Ђ)@)JP R)@zwKu[uO6Kā3ׯS8P/vQT߃MۦZK,-~{%Ddz0x9IR90-M:JOvCqB0O5]S1"d2Uʫgq>6=;Z[_ĜsֹZ,'{Gb$V#ڙVǒăEO6d} c$њ8cVб5 )3+V#%N E^-}%N9TPa Vo@\˛ƎrJGng,[cQF4a+{יi[\PlK2j"޽<KK^p󮵳M56,`ϹLRd%"1HÍyIJI }њRF千pSf{&IL[xp/D%n9Ǹ*m<:jĔ0E!TVFsýbi.s:U!|#ڰ{cQwKgԌ&"u[s8UB=I8rt+?gG] 0ʾ(pzvS !EӅ*ѥ$~ l/Jm)ڥ*S:F[N4v}mno':Kī kuyo^&vg w5W!Khy2 Z ϧ,F\S*t BlL*݅l2v-orSdsҽ d-c)DԇQّk~<vNA?iHS,J%,JNq%d8l%)Pk퉑o~ 󺠦C8fm]@KxJH,3n[-!)HIEypve7,q+mRܘt-J?jsnQM*ǩI2~P],Ѝc[-GdKwf ܐ<_Ӿ{I|َТ5w#;b|>;ՎNgvHREG<7zqpS`zS)5Y VD/64-ۖڂzp>?ʝKƕШ7<7X^#p4\r8K7 c\S{I|Һ|7<7b;Ǵ͍+_ݧWRG?¾)X֙Md])J&4۸IuN2q 60wmrp}##qQZ OD5u"{ 5 %[9$ WsM;{/)F:TJp9czPItZT!X!ziCpKώTRn˯; #GJ?#" =Οހ!Cđ6M.nC$MeStCn9&-aat t;SUǺ%gȸ7yq]K{h‘jR\gkx6HRzZBtIc@=7z<rb} w5<Ѱž:mڎ%#y% ~N+zPہ!)}\dJ|[>eryeч$ΡBQNsGZ{.=86tH:!P}y F'*:QZdsB=->ӿB~KBQʊ$ԅ8 G܊Ztt?Q)_' *SFO*6Ң{ËʹV7U@}$)x$ֺ' WP)T>MW\mOZRuG7{nHy%$P-8KN6#fk~+u 0k#gkg`w*C €T{fF({f:_Z":Ch=2qS&0%`z3|,+Z<#Y m`kWzӸDL+[ʀ!@HZ@= ֓[K7]XN?@G7H[!؋.ߌ4HNvהd1/w2Lhpˍ RsZͱKNl]K~o,07bڝ 0jۦ1~+Lg5m#q*YKKo.$)C( +o,5֓V *'0*.L6+V1@TE#Q]ݢ`䑸Az4sԡ@\c;iYAO"{Q} 1Q2h7>;Usb퍀4HgZ-.6r TcWٟ#C DBbY~*O݌\KY?U&Ei)#T:2pR#@qnγ;BRSg{G=+:F'S_"̩JJhTq$ խͿW-+f$cӃְfp>̄#K WH-pxɠ8(FlKy+[)PXF?:6}C_!=KH "=~0h(]r1|dAI^kfRYWTB+%ȇ4ZҴ?^2{kJ;OS}Mrk<'rޜYȬ.k(lWԫ1nJR?Z=܃.n%M oe07쎱&2TWP>=Q*.~RٶÏdH *|vV[l)†3^5?sfkA%VVh!8$? ;x{(^aԢ<oWkeնJT ;x{(^a#{| Hq V2 ,*ixx7Vf)L)JJB #7mrzנt>Lye.FBT>vMPIZ̍-zԫO~RˑQ%IIAkbz򲧖YAi J`ֱ;ʁJ8hA Y&ATNp5Dq<*肞F>jO}-,vFs[4e+y +#^汔Tm5RƾVqR`sZW|c! jpcNu{CZگ(2TwJ,0cjmՠF2o.{fƆv  /ȭ gZeyAhKygڸ曋 2 : p~ J}KpF:sVFZ~YuŸ&mOHm!MT=d `pzU ٗ=ҲK߹{BraUe4y yԴ9ʄ^q l7k! ~5:.r B8u=))S6C b*ۊJIR=Vf6hLQe.9krkEU/IT{j}tu0ꓵ}IN ǎƠ=\m\ԓԶյկ==DLwRF}kqmS6yW=."jIrܕ`S{bیCqm0qԃ ql$# +tT^$(g# EAѫM8C`N wǻXҾ=~vY4Z$GybeiYPF NVd(6Q23Y^b7wypQLw$I=HP=;5n?4-jz>N;V;a6FBH¾j.Ή\J g-yxWo9ov&/rmvCj;OL)Dl-d8 u4,nQcWYIP1M+7M إą($vi{MwGIT) Gd/ޭ(V--m!3)#(R/Uk T[Q)6؁r"TvNIWqM+7v7XROjB{l-6|>5h\K(4S#!U& y.Lޓ 3]Qlh^aԿM,lz; W̛"-:y,з~p3Zғ$DK*8.|;3X*fUjG4[0Qz.yr-Sf)!V˥p@;c޸jx4WndkZ)iڢSUfO^^Tz?ҾV0B?$A/FO?3'yhw8O4Ttrh?RNq+=f bu~f"Oµ ?j%C{kJa'{UO0nZ0ǨpZ+vڿt<ASe+2=*W%57.5=O$Y,*r#vm:짭p_w 8VԖwZХe#ٗEaf\HhB{ԛ!*Am΢taOvUR.[ѷk# ʉud/?5u>%Օ8SyN 髂@!dW 8'vs^kkę gL\ڦxC$;[iejJ+"ۀoVۉ DbFdھ/6j-E+-!E& S IЊ*V}Z^r]_RryQӌZme$M$1^HBI** PROdf;[ni?:\uXRڊTB Ty5&Lk[ 4`yj>zF;>=Ne t Q)VyFhuw硆D+!\Of;v1T|ըz_%@s@r.,95MPk O;NHx\mRxWeBSOJ1>RT5n'=UB[o\vڞ p<-'4aH}`.G|:TO` xQBҷ0Xeބ ge~[ϱPi\gPB SGlלn6dCFF\נ4{,8-F`lqp1$$g"Z"3em*]-80y[j-4㏽7Ζ+&S弖[*uePAH}H( $c-jv:a \@Y m,T KV#fj6 ;=*5Sß)s3{ xP{s[2AɬWslD$"e1 8mgx*s=18jtk# ;U].ː8RHzK#)96~i 1ne(+IDPAXq*l@3БϽqt P~3 2䧌i5L'(IJ/ .9@#K Rpe9RRH Չ,,Ւrjeni&!܄ {VqV4ͨC7 ;o"t}kfDWc2H>bVz<Z/Au)-֜ F~mi2dD̤mP!%[O~Ύd\V #21_brGB+ssr|ƒSѤ#cM8Cw{/9TsI=8\)+r%5$vs[Ou&;3![Lfr=Ds!#{\ m^k(1 kn!$P g?8s?rW2&Çjqǽg~ˀ6^]ڞL qmK!4,q`?1qn`#}Q*r\Qٕj,ߓuNjv_ )~?ֹ1rr\c@) {~+4 \n%(+'S^խה|p:4[ѫ¡ð}\V u,Q"=QTJOxowJcK;,|bqSmz+BݤFS!PG5"`\e 忥.Hr)SV$PfHJ9yzkZT{i'>(ƤZ,X؟h I'=INŨnype6ܠPBvq'Ua|7g. \(R\h,ӺO|QHi I;M^ou@ ұE{97 @'3uR{{K۽ ;cmR%df"k3g”[n6 PtX0%)AIDr?n%)ZC0YAR r$X5.c`ARfB}ҬJ$J#JHn>'>(ƤqM>~S 9BI0@ONþjWO*>gjwTl3ךHN>G5#+/%#!+bE̜K8’Rv)Ő~G"EjyXFN7#krJ1[J'?(;JAӷK[p8bܥ }RR?5*f\ q z㱣a^r;W}S4v`Pb#~Td% '0zսri~SM d\:@m}DҞPl:ro*IfS~_2c/xŕt9:L50ֳ2@JeJH95 yOb*RKMKJb?mz>>jWbqr`r:B 8tl Rr<pYKJ]##?m{djC !8䚄#} 6dVKPH'\-CmoY(Tmũ<]EH4֭IyW䩓УgހrC\&1ʍO`4oRO[{ޔs]=IqgNS[Ph MZDE@vRRjL\xafLTROAQy_//J8_>_ݰP = JѬY-p~\~s5Ji BУ0n6{ү~H4g̔|Uْʶ?u6G>VxܑSMwX[4PݯI7\iq B`uSz\ZCaTEY1yHNl$: {oy6Q QR?jYum/EHq%d'r29VЎҭ-۲Siڷހj Z[@K(DJ<@!je<-L8TTouD3Z-a֛78 SjڼhZ%I>ZzZ)qid#x?qqN3>lz>DyHd+iY8H]dIuf+Y 2xzPah/>Dq]VZ}Q6m:mjBw'ZP kbuQ9jsP[8*A ߷Bӈq %I8)#]v심?]i(qC[lKjQXQip*b'd{09)\u ;Vی%˘J@Ii7Em8gԻA޸%ImӱyNo%JQcڻ;X {k>c BskЋr:RaGUMZV{wenbNj8]F @qPiNcl\0e2GLy?L)tajRḶk'I3]4Xg(NQX]m<}GujY*w%č8 L3{Ź#z'?-LzK۷ 6@O* NhFʲAતi;HGayq5$VqxH5jrR`-PbIe%N$!+eAozҗҺ85+[mi5n60n xLm! ww71 d*PȯӐVWY *!DdI? I #q $lPd6bHRZir&y˺*O4pe.B2C*'5S<ŲpG')h@&O0!=wVtF~krw uv_OB-x1SIAɻݭm1f#h}|1={W:ARWs}]W<Ռù(r3u$^526M$$mVI8:|xŢ q)WZA(g#>IP R!zHC]R7TDv~JŸT`](byw0 vv;rzc$rzdFG[km H@$$ m(SsҤ9N쓞Һ1QЇg-jX9;Qƃi `n-zT9kPI>íE4 jIw# Rjxc]IH¶BOoҸ~+v>^se>rsU0eJB:p*ymK)$c ԰5om( 色rK+{$tC.Nw#-]JRUcں^-"2J+cʻ7:ɷB &j4}e~\9Ew3. `,.A{=VZ!Ļ+ڗ^xV߼mBs׊)tvh +Qw xåmt>&tA=ʓVV 6=!.E).wrRzdyRm^f3psӟҫGMvJ 33Ҭ!dc=7 [f*I}D{\*(CXDcXԣ*W\bKᐲp?:EmrP\ R UgYЎmpC` Z]i$j#n^LX>ƓV!(?vOץ.R*;LXX#p8QMmjŹi.89H#4a6޷ƴmmi)ktBB58\@s?5~+̗ ZN[p񔤎Sz1j/Ptp\Wۊ@uO  Vu-=VgaK$$(F[׎[ZPT L_yw(.8ʿ|KӰ/v-ɬ(TRr.'óInn*9HX"iSRg = ݢұ8'zݻ(ˁJ+rjjmIj׊ZoP.O<Ү5eP}g޶' S3^ҵR&V:\aEc-J"_V2& ww'M#(13u(&AZ9*sv>SzUQ.mSmĶmlHqH<sۮx1Rmx+YG*e(ڠNsߕc9s=ܧaZ. +;=Zt%)t#keԛ7'y'OvMhuYU IIZX&vB,%Gx=9ߚYf!*Qf m%c!_\hU]Eo^㭤'Rn Ny Y t>%ܾL1¸?δ]g:.meRSYOȥJV)J<oԨn;vՎ٨5D%Q5(w<(|{"<ԱEaB!upVF I8N?>r@%vźSGb55ӶjsLˊH•tjYπ Bq1PC5\˝GOog`LF!HK,%E'WrgnqkKhO( AZQa3aK%Tr _7K~)87ccR $3UĽA+Sᱷˋ!{gjk 2c$CZڽ_OjQ%v~h %-6R}V_OjERS#Ң~*ot4ٲ֤cԶ)XϷcTډ>Rk%6֌0- Ƿ5;{䧂*@BPەФw%IS++!NWfBטS'(q)Xy?GJg2oZjZ m#8y'@ӺNE66UZFi&!hk̵ۓ9땶<[sr7M9JB'MyCxB E~cR㗜]*?œOSӭhjе3+u;?&V}-+e?b@=FGED\uuQR}&zհ@>?íG 7)Lޒ-u'`:Zԥ)@+؞ \cʂ"JH!;T9)"wV':Zb"y f(o[!,{xؓCysr-t2OuR:ߗ܃??Pi.(R2tpskIEeQRYeoԨy-:0~Α-ӷw\{(\,Gl 6kd޺o7(gyM5aRk  uJQ bIovI{pntGbC |kT^.gZuSQ;dٰ~lR \ib$rk_R)[qGvHұ*p!uvECY3a^^NƱ<-Vv#hQ1y'-Nj!Gϴq(!GDeYϑHTRseRUImg;rKqH<(N4B[O8ӓUpu9*ǥtnJ*LM]92fE 1*p2pHxfm-*2Fv\ e+QQنB؊[Zڐ$`x'$NGNod!m V,MY. SI)aC+R4Y>`R)O ))oĬQImϿmxA4E!ni r~ke䒄ֵBJPZ P CK=*!`*cȈ{ ''#? (ZG^@>֘O j*h[n xfkC $Dvo#SQ-Y5|p!sRO|s@|_RnډlUz; }>JArK/vJ?Do6n,%JzG么hk.GJzg H6=pw+=M|+4tdf<1ģRsW6sYSjb AqT+em5 /\6BccJJqnHkFi{YgDˎ 1#sT.k[I8&9Ju4[ ;桑`ݤ$/ Y78hf@k(eG$ ,iJ2`-%mIVGIˬ7JI=2W[jnH;u(fR~Tb6*sޫXnWCn)eY4uA1P7t,++)E?IFqӭaxvy{83q*5/^YوX7cp1ZH3lJx>;ⲧKYoaS-q !/Cuz?$?*tKdGھL+fZARB3#jѦٗ OcDVK:X)Pp5Veiq*CjhnAj+j`% \qλ5Jc\u-'qH'UoR<:I---v=I>GM6;*ћxIyjܖERx5͟o9LlVp8<8)|rVxekz7QZW#өNs.:}!!cN,:Q- )ˆ]p Q)6B󁞿θJҝքw5l\9hCl&^ܻ0x2Ͻve I)G%)”؜(ڢI]-Go0T)'예ZU}cBcڻ,q{ \F: =+ iCP[8WIvDv@F{vPNuN( ''MW6Q | R@)WŎ5ZWk:/ݞWjmv?)U1JRR: ]\.9@{uM j맣FFד88#35r KjT7T̆ OPjվiRӃ&u)IyI'8kZ.*;k_RZB79_@Lueq8߽M"T8|ڨuKHVqkc&?!L[#_C(# ㎙;Q\j u88DC4%Gn3xTvH?dgqb9}ywd%۞-;h=RG Z.PrpAbmF]sw#l5qeoZ-J?]JAsOcIfc~dwWZd4VԄ$ Rq#;TE<)$sZ4\V5cZ]Ďɖu'>EQRHZSnҤ##z@ *_&\!!)A$g׏Qr3IO[?ɋGqN9=lYmVz6矜CɐT p}g:[=kLaV9 Nܷl V05*TҒ[JT23>*-C)HN7ݏ06lwp{p>J ~Q9WeF@Lx e*ry'j `YHO;FI$ {@nn}CI 9 u8:_z3APpܔ!CAT{SU*{* \ibO+NN6@$ J}LYZRA8䁎PaYc;R ?Qܕ9%^ġvJR%~qVm!]bRh1!j{bװp $cG򬱙%PTZS:g >X NIp67NHzb֛܅Ş89GNy=KU<ɱh(m'pG\`^Ҡ>65*2^uJ{M7zCJS%\;nXe·JKd9_o݌Ideyou[I?qNߪL)b\I6֒.I,IjGOS_QYmك?ˑ!0 V09^Ws=.2 F!ANHj6r"o.\PmB0JpH 7c$mmؤd d {7YVܭnZ@Jў:3S )p7,-Uxo mwfEHFzrN{5Ғ"\cܢ:֠QkIIYN>+{3ػɛ=.JjT&װHpg&ikOHmyᔒһ Q*.yrJUuV^Iw݂G g^1_CrCLH )ݻ\{>._@%͇uSHP.9n+n_6V g%9vvv]}wR=:FGϑo`yjZ}OJYRPQW ~UW]gJZW'PCL.,(r cU) }"q8}n8>g5)J~m q)C7|[=:V)mDI}*Hpz8H&*R3E}qK*͵kL- HN 91ۭUmZ:#{ͫ[ʶI]k.“$wcHV!C } Ӛ|6VrFx5Wm.N ߸UkE1QM4&UO<㤀'psYBR;8Opj 6&^45.˚gnې ScjkcIZ ^$N{|hMEw,L+PqT8;$8|UG[7)ns=)oqu'AZ)@)JP R)@)JP RTט`Zq$,l֥ěxh;:p#,c5^/ysX_Cg؊[L!E*]$;v•*ҵn;TbDGP.;%l;?<}ςZ>Z [ݕgM֗ ) IJPf#i׷T:s:-Km (i:Vؖh~|Q]o VY-+I):׌7^k "4dOSNgV (ʌytcgJKso] THOdiJԔ'<^X)Xf%8QJF硩/XnR}>|y:9 J;'# (8"3JXfPJ/ e_4OXٻ Y=S;5$#O\r,rܛ[A%\gsWiN$I^(FkyEǗ!qG^qczTd%e+`vhҡ$J-SygoNY-C~\mTnJs GY_/Kv\X:'KRc'toyK)`$xpu)R@)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP Rmricron-0.20140804.1~dfsg.1.orig/drop_patch.txt0000755000175000017500000015203112307156544017100 0ustar mihmih{%MainUnit carbonint.pas} {****************************************************************************** All utility method implementations of the TCarbonWidgetSet class are here. ****************************************************************************** Implementation ****************************************************************************** ***************************************************************************** This file is part of the Lazarus Component Library (LCL) See the file COPYING.modifiedLGPL.txt, included in this distribution, for details about the license. ***************************************************************************** } { TCarbonWidgetSet } { This event handler will fix the focus indication in AXApplication for standard controls where it gets it wrong. Necessary to support accessibility for TMemo / TEdit for example } function AppAccessibilityEventHandler(inHandlerCallRef: EventHandlerCallRef; inEvent: EventRef; {%H-}inUserData: Pointer): OSStatus; {$IFDEF darwin}mwpascal;{$ENDIF} var lAXRole, lInputStr: CFStringRef; lInputAXObject: AXUIElementRef; EventKind: UInt32; lInputPasStr: string; lElement, lElement2: AXUIElementRef; lAXArray: CFMutableArrayRef; begin Result := CallNextEventHandler(inHandlerCallRef, inEvent); GetEventParameter(inEvent, kEventParamAccessibleObject, typeCFTypeRef, nil, SizeOf(AXUIElementRef), nil, @lInputAXObject); EventKind := GetEventKind(inEvent); case EventKind of kEventAccessibleGetNamedAttribute: begin GetEventParameter(inEvent, kEventParamAccessibleAttributeName, typeCFStringRef, nil, SizeOf(CFStringRef), nil, @lInputStr); lInputPasStr := CFStringToStr(lInputStr); if lInputPasStr = 'AXFocusedUIElement' then begin // First interfere only if the element returned is in our black list // for example: memo border GetEventParameter(inEvent, kEventParamAccessibleAttributeValue, typeCFTypeRef, nil, SizeOf(AXUIElementRef), nil, @lElement); AXUIElementCopyAttributeValue(lElement, CFSTR('AXRoleDescription'), lAXRole{%H-}); lInputPasStr := CFStringToStr(lAXRole); if lInputPasStr = 'memoborder' then begin AXUIElementCopyAttributeValue(lElement, CFSTR('AXChildren'), lAXArray{%H-}); lElement2 := CFArrayGetValueAtIndex(lAXArray, 0); SetEventParameter(inEvent, kEventParamAccessibleAttributeValue, typeCFTypeRef, SizeOf(AXUIElementRef), @lElement2); Result := noErr; Exit; end; end; end; // kEventAccessibleGetNamedAttribute end; // case EventKind of end; { The only drawback to making your own event loop dispatching calls in the main application thread is that you won't get the standard application event handler installed. Specifically, the RunApplicationEventLoop function installs handlers to do the following: * Allow clicks in the menu bar to begin menu tracking * Dispatch Apple events by calling AEProcessAppleEvent * Respond to quit Apple events by quitting RunApplicationEventLoop. One way to work around this limitation is by creating a dummy custom event handler. When you are ready to process events, create the dummy event yourself, post it to the queue and then call RunApplicationEventLoop (to install the standard application event handler). The dummy event handler can then process the events manually. For an example of using this method, see Technical Q&A 1061 in Developer Documentation Technical Q&As. } // From: Technical Q&A 1061 in Developer Documentation Technical Q&As // MWE: modified to fit the LCL, but the basic idea comes from Q&A 1061 function QuitEventHandler(inHandlerCallRef: EventHandlerCallRef; inEvent: EventRef; {%H-}inUserData: Pointer): OSStatus; {$IFDEF darwin}mwpascal;{$ENDIF} // This event handler is used to override the kEventClassApplication // kEventAppQuit event while inside our event loop (EventLoopEventHandler). // It simply calls through to the next handler and, if that handler returns // noErr (indicating that the application is doing to quit), it sets // a Boolean to tell our event loop to quit as well. // MWE: in our case, terminates the app also begin Result := CallNextEventHandler(inHandlerCallRef, inEvent); if Result <> noErr then Exit; if (Widgetset <> nil) and TCarbonWidgetSet(Widgetset).FTerminating then Exit; TCarbonWidgetSet(Widgetset).FTerminating := True; if Application = nil then Exit; Application.Terminate; end; function EventLoopEventHandler({%H-}inHandlerCallRef: EventHandlerCallRef; {%H-}inEvent: EventRef; inUserData: Pointer): OSStatus; {$IFDEF darwin}mwpascal;{$ENDIF} // This code contains the standard Carbon event dispatch loop, // as per "Inside Macintosh: Handling Carbon Events", Listing 3-10, // except: // // o this loop supports yielding to cooperative threads based on the // application maintaining the gNumberOfRunningThreads global // variable, and // // o it also works around a problem with the Inside Macintosh code // which unexpectedly quits when run on traditional Mac OS 9. // // See RunApplicationEventLoopWithCooperativeThreadSupport for // an explanation of why this is inside a Carbon event handler. // // The code in Inside Mac has a problem in that it quits the // event loop when ReceiveNextEvent returns an error. This is // wrong because ReceiveNextEvent can return eventLoopQuitErr // when you call WakeUpProcess on traditional Mac OS. So, rather // than relying on an error from ReceiveNextEvent, this routine tracks // whether the application is really quitting by installing a // customer handler for the kEventClassApplication/kEventAppQuit // Carbon event. All the custom handler does is call through // to the previous handler and, if it returns noErr (which indicates // the application is quitting, it sets quitNow so that our event // loop quits. // // Note that this approach continues to support QuitApplicationEventLoop, // which is a simple wrapper that just posts a kEventClassApplication/ // kEventAppQuit event to the event loop. var QuitUPP: EventHandlerUPP; QuitHandler: EventHandlerRef; TmpSpec: EventTypeSpec; Loop: TApplicationMainLoop = nil; begin // Get our TApplicationMainLoop Result := noErr; if (not Assigned(inUserData)) or TCarbonWidgetSet(inUserData).FUserTerm then Exit; Loop := TCarbonWidgetSet(inUserData).FAppLoop; if not Assigned(Loop) then Exit; // Install our override on the kEventClassApplication, kEventAppQuit event. QuitUPP := NewEventHandlerUPP(EventHandlerProcPtr(Pointer(@QuitEventHandler))); //todo: raise exception ?? if QuitUPP = nil then Exit; try TmpSpec := MakeEventSpec(kEventClassApplication, kEventAppQuit); if not InstallApplicationEventHandler(QuitUPP, 1, @TmpSpec, nil, @QuitHandler) then Exit; try // Run our event loop until quitNow is set. Loop; finally MacOSAll.RemoveEventHandler(QuitHandler); end; finally DisposeEventHandlerUPP(QuitUPP); end; (* theTarget := GetEventDispatcherTarget; repeat if MNumberOfRunningThreads = 0 then timeToWaitForEvent := kEventDurationForever else timeToWaitForEvent := kEventDurationNoWait; Result := ReceiveNextEvent(0, nil, timeToWaitForEvent, true, theEvent); if Result = noErr then begin SendEventToEventTarget(theEvent, theTarget); ReleaseEvent(theEvent); end; if MNumberOfRunningThreads > 0 then YieldToAnyThread; until quitNow; *) end; {------------------------------------------------------------------------------ Name: CarbonApp_CommandProcess Handles main menu and context menus commands ------------------------------------------------------------------------------} function CarbonApp_CommandProcess(ANextHandler: EventHandlerCallRef; AEvent: EventRef; {%H-}AWidget: TCarbonWidget): OSStatus; {$IFDEF darwin}mwpascal;{$ENDIF} var Command: HICommandExtended; CarbonMenu: TCarbonMenu; Msg: TLMessage; S: LongWord; AllowMenu: Boolean; Focused: HWND; HotChar: Char; const SName = 'CarbonApp_CommandProcess'; begin {$IFDEF VerboseAppEvent} DebugLn('CarbonApp_CommandProcess'); {$ENDIF} if not OSError( GetEventParameter(AEvent, kEventParamDirectObject, typeHICommand, nil, SizeOf(HICommand), nil, @Command), SName, 'GetEventParameter') then begin {$IFDEF VerboseMenu} DebugLn('CarbonApp_CommandProcess MenuRef: ' + DbgS(Command.menuRef) + ' Item: ' + DbgS(Command.menuItemIndex) + ' CommandID: ' + DbgS(Command.commandID) + ' Attrs: ' + DbgS(Command.attributes)); {$ENDIF} // check command and send "click" message to menu item if (Command.commandID = MENU_FOURCC) and (Command.attributes and kHICommandFromMenu > 0) and (Command.menuRef <> nil) then begin if not OSError(GetMenuItemProperty(Command.menuRef, Command.menuItemIndex, LAZARUS_FOURCC, WIDGETINFO_FOURCC, SizeOf(TCarbonMenu), S{%H-}, @CarbonMenu), SName, 'GetMenuItemProperty') then begin {$IFDEF VerboseMenu} DebugLn('CarbonApp_CommandProcess CarbonMenu: ' + DbgS(CarbonMenu)); {$ENDIF} if CarbonMenu <> nil then begin Hotchar:=CarbonMenu.GetShortCutKey; { CommandProcess is fired before a keyboard event } { we must check if the control has default system handlers on the hot-key used } { if so, CommandProcess is not processed, and the key values event are sent } { to the control by the system. } { } { Another possible solution of the problem, is to Post another custom event } { to the loop, and report LCL about Menu pressed after the event arrives, } { though it might seem, like interface is lagging } if (CarbonMenu.Parent.Dismissed<>kHIMenuDismissedBySelection) and (HotChar<>#0) then begin AllowMenu := True; Focused:=GetFocus; if (Focused<>0) and (TObject(Focused) is TCarbonControl) then begin TCarbonControl(Focused).AllowMenuProcess(HotChar, GetCarbonShiftState, AllowMenu); if not AllowMenu then begin Result:=eventNotHandledErr; CarbonMenu.Parent.Dismissed:=0; Exit; end; end; end; if CarbonMenu.Parent.Dismissed=kHIMenuDismissedBySelection then begin FillChar(Msg{%H-}, SizeOf(Msg), 0); Msg.msg := LM_ACTIVATE; CarbonMenu.LCLMenuItem.Dispatch(Msg); if assigned(CarbonMenu.Parent) then // if parent not closed CarbonMenu.Parent.Dismissed:=0; Result := noErr; Exit; end else Result:=CallNextEventHandler(ANextHandler, AEvent); end; end; end; end; Result := CallNextEventHandler(ANextHandler, AEvent); end; {------------------------------------------------------------------------------ Name: CarbonApp_Shown Handles application show ------------------------------------------------------------------------------} function CarbonApp_Shown(ANextHandler: EventHandlerCallRef; AEvent: EventRef; {%H-}AWidget: TCarbonWidget): OSStatus; {$IFDEF darwin}mwpascal;{$ENDIF} begin {$IFDEF VerboseAppEvent} DebugLn('CarbonApp_Shown'); {$ENDIF} Result := CallNextEventHandler(ANextHandler, AEvent); Application.IntfAppRestore; end; {------------------------------------------------------------------------------ Name: CarbonApp_Hidden Handles application hide ------------------------------------------------------------------------------} function CarbonApp_Hidden(ANextHandler: EventHandlerCallRef; AEvent: EventRef; {%H-}AWidget: TCarbonWidget): OSStatus; {$IFDEF darwin}mwpascal;{$ENDIF} begin {$IFDEF VerboseAppEvent} DebugLn('CarbonApp_Hidden'); {$ENDIF} Result := CallNextEventHandler(ANextHandler, AEvent); Application.IntfAppMinimize; end; {------------------------------------------------------------------------------ Name: CarbonApp_Deactivated Handles application deactivation ------------------------------------------------------------------------------} function CarbonApp_Deactivated(ANextHandler: EventHandlerCallRef; AEvent: EventRef; {%H-}AWidget: TCarbonWidget): OSStatus; {$IFDEF darwin}mwpascal;{$ENDIF} begin {$IFDEF VerboseAppEvent} DebugLn('CarbonApp_Deactivate'); {$ENDIF} Result := CallNextEventHandler(ANextHandler, AEvent); Application.IntfAppDeactivate; end; {------------------------------------------------------------------------------ Name: CarbonApp_Activated Handles application activation ------------------------------------------------------------------------------} function CarbonApp_Activated(ANextHandler: EventHandlerCallRef; AEvent: EventRef; {%H-}AWidget: TCarbonWidget): OSStatus; {$IFDEF darwin}mwpascal;{$ENDIF} begin {$IFDEF VerboseAppEvent} DebugLn('CarbonApp_Activate'); {$ENDIF} Result := CallNextEventHandler(ANextHandler, AEvent); Application.IntfAppActivate; end; {------------------------------------------------------------------------------ Name: CarbonApp_Activated Handles application activation ------------------------------------------------------------------------------} function CarbonApp_LazWake(ANextHandler: EventHandlerCallRef; AEvent: EventRef; {%H-}AWidget: TCarbonWidget): OSStatus; {$IFDEF darwin}mwpascal;{$ENDIF} begin {$IFDEF VerboseAppEvent} DebugLn('CarbonApp_LazWake'); {$ENDIF} Result := CallNextEventHandler(ANextHandler, AEvent); if IsMultiThread then begin // a thread is waiting -> synchronize CheckSynchronize; end; end; {------------------------------------------------------------------------------ Name: CarbonApp_Open Handles application open ------------------------------------------------------------------------------} function CarbonApp_Open(var AEvent: AppleEvent; var {%H-}Reply: AppleEvent; {%H-}Data: SInt32): OSErr; {$IFDEF darwin}mwpascal;{$ENDIF} var DocList: AEDescList; FileCount: Integer; FileIdx: Integer; Keyword: AEKeyword; FileDesc: AEDesc; FileRef: FSRef; FileURL: CFURLRef; FileCFStr: CFStringRef; Files: Array of String; const SName = 'OpenDocEventHandler'; begin {$IFDEF VerboseAppEvent} DebugLn('CarbonApp_Open'); {$ENDIF} if OSError(AEGetParamDesc(AEvent, keyDirectObject, typeAEList, DocList{%H-}), SName, 'AEGetParamDesc') then Exit; try if OSError(AECountItems(DocList, FileCount{%H-}), SName, 'AECountItems') then Exit; SetLength(Files, 0); for FileIdx := 1 to FileCount do begin if OSError(AEGetNthDesc(DocList, FileIdx, typeFSRef, @Keyword, FileDesc{%H-}), SName, 'AEGetNthDesc') then Continue; if OSError(AEGetDescData(FileDesc, @FileRef, SizeOf(FSRef)), SName, 'AEGetDescData') then Continue; if OSError(AEDisposeDesc(FileDesc), SName, 'AEDisposeDesc') then Continue; FileURL := CFURLCreateFromFSRef(kCFAllocatorDefault, FileRef); FileCFStr := CFURLCopyFileSystemPath(FileURL, kCFURLPOSIXPathStyle); try SetLength(Files, Length(Files) + 1); Files[High(Files)] := CFStringToStr(FileCFStr); finally FreeCFString(FileURL); FreeCFString(FileCFStr); end; end; if Length(Files) > 0 then begin if Application <> nil then begin if Application.MainForm <> nil then Application.MainForm.IntfDropFiles(Files); Application.IntfDropFiles(Files); end; end; finally AEDisposeDesc(DocList); end; Result := noErr; end; {------------------------------------------------------------------------------ Name: CarbonApp_DragReceive Handles dropping files on application ------------------------------------------------------------------------------} function CarbonApp_DragReceive(theWindow: WindowRef; handlerRefCon: UnivPtr; theDrag: DragRef): OSErr; {$IFDEF darwin}mwpascal;{$ENDIF} var theItemRef: DragItemRef; theFlavorData: HFSFlavor; theDataSize: Size; theFilename: pchar; theFileRef: FSRef; numItems: UInt16; Files: array of string; itemNum: UInt16; begin SetLength(Files, 0); numItems := 0; if CountDragItems(theDrag, numItems) <> noErr then exit; if numItems > 0 then for itemNum := 1 to numItems do begin if GetDragItemReferenceNumber(theDrag, itemNum, theItemRef) <> noErr then continue; theDataSize := sizeof(theFlavorData); if GetFlavorData(theDrag, theItemRef, kDragFlavorTypeHFS, @theFlavorData, theDataSize, 0) <> noErr then continue; FSpMakeFSRef(theFlavorData.fileSpec, theFileRef); theFilename := stralloc(1024); //PATH_MAX = 1024 FSRefMakePath(theFileRef, theFilename, StrBufSize(theFilename)); try SetLength(Files, Length(Files) + 1); Files[High(Files)] := theFilename; finally StrDispose(theFilename); end; end; if Length(Files) > 0 then begin if Application <> nil then begin if Application.MainForm <> nil then Application.MainForm.IntfDropFiles(Files); Application.IntfDropFiles(Files); end; end; Result := noErr; end; {------------------------------------------------------------------------------ Name: CarbonApp_Quit Handles application quit ------------------------------------------------------------------------------} function CarbonApp_Quit(var {%H-}AEvent: AppleEvent; var {%H-}Reply: AppleEvent; {%H-}Data: SInt32): OSErr; {$IFDEF darwin}mwpascal;{$ENDIF} begin {$IFDEF VerboseAppEvent} DebugLn('CarbonApp_Quit'); {$ENDIF} if (Application <> nil) and (Application.MainForm <> nil) then begin Application.MainForm.Close; end; Result := noErr; end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.AppInit Params: ScreenInfo Initialize Carbon Widget Set ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.AppInit(var ScreenInfo: TScreenInfo); var ScreenDC: HDC; begin {$IFDEF VerboseObject} DebugLn('TCarbonWidgetSet.AppInit'); {$ENDIF} WakeMainThread := @OnWakeMainThread; // fill the screen info ScreenDC := GetDC(0); try ScreenInfo.PixelsPerInchX := GetDeviceCaps(ScreenDC, LOGPIXELSX); ScreenInfo.PixelsPerInchY := GetDeviceCaps(ScreenDC, LOGPIXELSY); ScreenInfo.ColorDepth := GetDeviceCaps(ScreenDC, BITSPIXEL); finally ReleaseDC(0, ScreenDC); end; fMainEventQueue:=GetMainEventQueue; end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.AppRun Params: ALoop ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.AppRun(const ALoop: TApplicationMainLoop); // A reimplementation of RunApplicationEventLoop that supports // yielding time to cooperative threads. It relies on the // rest of your application to maintain a global variable, // gNumberOfRunningThreads, that reflects the number of threads // that are ready to run. var DummyEvent: EventRef; EventSpec: EventTypeSpec; EventLoopUPP, AccessibilityUPP: EventHandlerUPP; EventLoopHandler, AccessibilityHandle: EventHandlerRef; begin {$IFDEF VerboseObject} DebugLn('TCarbonWidgetSet.AppRun'); {$ENDIF} FAppLoop:=ALoop; DummyEvent := nil; // Accessibility for AXApplication AccessibilityUPP := NewEventHandlerUPP(EventHandlerProcPtr(Pointer(@AppAccessibilityEventHandler))); EventSpec := MakeEventSpec(kEventClassAccessibility, kEventAccessibleGetNamedAttribute); InstallApplicationEventHandler(AccessibilityUPP, 1, @EventSpec, Self, @AccessibilityHandle); // Create a UPP for EventLoopEventHandler and QuitEventHandler EventLoopUPP := NewEventHandlerUPP(EventHandlerProcPtr( Pointer(@EventLoopEventHandler))); if EventLoopUPP = nil then RaiseGDBException('TCarbonWidgetSet.InitMainLoop no eventhandler'); // Install EventLoopEventHandler, create a dummy event and post it, // and then call RunApplicationEventLoop. The rationale for this // is as follows: We want to unravel RunApplicationEventLoop so // that we can can yield to cooperative threads. In fact, the // core code for RunApplicationEventLoop is pretty easy (you // can see it above in EventLoopEventHandler). However, if you // just execute this code you miss out on all the standard event // handlers. These are relatively easy to reproduce (handling // the quit event and so on), but doing so is a pain because // a) it requires a bunch boilerplate code, and b) if Apple // extends the list of standard event handlers, your application // wouldn't benefit. So, we execute our event loop from within // a Carbon event handler that we cause to be executed by // explicitly posting an event to our event loop. Thus, the // standard event handlers are installed while our event loop runs. EventSpec := MakeEventSpec(LCLCarbonEventClass, LCLCarbonEventKindMain); if not InstallApplicationEventHandler(EventLoopUPP, 1, @EventSpec, Self, @EventLoopHandler) then Exit; try if CreateEvent(nil, EventSpec.eventClass, EventSpec.eventKind, 0, kEventAttributeNone, DummyEvent) <> noErr then RaiseGDBException('TCarbonWidgetSet.InitMainLoop create first dummy event failed'); try {if SetEventParameter(DummyEvent, MakeFourCC('Loop'), MakeFourCC('TAML'), SizeOf(ALoop), @ALoop) <> noErr then RaiseGDBException('TCarbonWidgetSet.InitMainLoop setparam to first event failed');} //DebuglnThrea dLog('TCarbonWidgetSet.AppRun '+dbgs(GetMainEventQueue)); if PostEventToQueue(FMainEventQueue, DummyEvent, kEventPriorityHigh) <> noErr then RaiseGDBException('TCarbonWidgetSet.AppRun post dummy event failed'); finally ReleaseEvent(DummyEvent); end; SignalFirstAppEvent; if not FUserTerm then begin RunApplicationEventLoop; end; FAppStdEvents:=True; finally MacOSAll.RemoveEventHandler(EventLoopHandler); DisposeEventHandlerUPP(EventLoopUPP); end; {$IFDEF VerboseObject} DebugLn('TCarbonWidgetSet.AppRun END'); {$ENDIF} end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.AppProcessMessages Handle all pending messages ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.AppProcessMessages; var Target: EventTargetRef; Event: EventRef; CurEventClass: TEventInt; CurEventKind: TEventInt; begin {$IFDEF VerboseObject} DebugLn('TCarbonWidgetSet.AppProcessMessages'); {$ENDIF} if not FAppStdEvents then InstallStandardEventHandler(GetApplicationEventTarget); Target := GetEventDispatcherTarget; CurEventClass.Chars[4] := #0; CurEventKind.Chars[4] := #0; repeat FreePendingWidgets; if ReceiveNextEvent(0, nil, kEventDurationNoWait, True, Event{%H-}) <> noErr then Break; CurEventClass.Int := GetEventClass(Event); CurEventKind.Int := GetEventKind(Event); {$IFDEF DebugEventLoop} DebugLn('EventClass: "',CurEventClass.Chars,'" EventKind: ',IntToStr(CurEventKind.Int)); {$ENDIF} if CurEventClass.Chars = LCLCarbonEventClass then begin // internal carbon intf message {$IFDEF DebugEventLoop} DebugLn('EventKind: ',CurEventKind.Chars); {$ENDIF} if (CurEventKind.Chars = LCLCarbonEventKindUser) then begin end; end; SendEventToEventTarget(Event, Target); ReleaseEvent(Event); if Clipboard <> nil then if Clipboard.OwnerShips > 0 then Clipboard.CheckOwnerShip; until Application.Terminated; {$IFDEF VerboseObject} DebugLn('TCarbonWidgetSet.AppProcessMessages END'); {$ENDIF} end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.AppWaitMessage Passes execution control to Carbon ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.AppWaitMessage; var Event: EventRef; begin {$IFDEF VerboseObject} DebugLn('TCarbonWidgetSet.AppWaitMessage'); {$ENDIF} // Simply wait forever for the next event. // Don't pull it, so we can handle it later. OSError(ReceiveNextEvent(0, nil, kEventDurationForever, False, Event{%H-}), Self, 'AppWaitMessage', 'ReceiveNextEvent'); end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.Create Constructor for the class ------------------------------------------------------------------------------} constructor TCarbonWidgetSet.Create; begin CarbonWidgetSet := Self; inherited Create; FTerminating := False; fMenuEnabled := True; FTimerMap := TMap.Create(its4, SizeOf(TWSTimerProc)); FCurrentCursor := 0; FMainMenu := 0; FCaptureWidget := 0; RegisterEvents; { if using Cocoa, we need an autorelease pool and we also need to initialize NSApplication } {$ifdef CarbonUseCocoa} pool := NSAutoreleasePool.Create; NSApplicationLoad(); {$endif} end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.Destroy Destructor for the class ------------------------------------------------------------------------------} destructor TCarbonWidgetSet.Destroy; begin CaretWidgetSetReleased; FreeAndNil(FTimerMap); DisposeAEEventHandlerUPP(FOpenEventHandlerUPP); DisposeAEEventHandlerUPP(FQuitEventHandlerUPP); inherited Destroy; CarbonWidgetSet := nil; // if using Cocoa, release autorelease the pool {$ifdef CarbonUseCocoa} if pool <> nil then pool.Free; {$endif} end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.RawImage_DescriptionFromCarbonBitmap Creates a rawimage description for a carbonbitmap ------------------------------------------------------------------------------} function TCarbonWidgetSet.RawImage_DescriptionFromCarbonBitmap(out ADesc: TRawImageDescription; ABitmap: TCarbonBitmap): Boolean; var Prec, Shift, BPR: Byte; AlphaInfo: CGImageAlphaInfo; begin ADesc.Init; case ABitmap.BitmapType of cbtMono, cbtGray: ADesc.Format := ricfGray; else ADesc.Format := ricfRGBA; end; ADesc.Width := CGImageGetWidth(ABitmap.CGImage); ADesc.Height := CGImageGetHeight(ABitmap.CGImage); //ADesc.PaletteColorCount := 0; ADesc.BitOrder := riboReversedBits; ADesc.ByteOrder := riboMSBFirst; BPR := CGImageGetBytesPerRow(ABitmap.CGImage) and $FF; if BPR and $F = 0 then ADesc.LineEnd := rileDQWordBoundary // 128bit aligned else if BPR and $7 = 0 then ADesc.LineEnd := rileQWordBoundary // 64bit aligned else if BPR and $3 = 0 then ADesc.LineEnd := rileWordBoundary // 32bit aligned else if BPR and $1 = 0 then ADesc.LineEnd := rileByteBoundary // 8bit aligned else ADesc.LineEnd := rileTight; ADesc.LineOrder := riloTopToBottom; ADesc.BitsPerPixel := CGImageGetBitsPerPixel(ABitmap.CGImage); ADesc.MaskBitOrder := riboReversedBits; ADesc.MaskBitsPerPixel := 1; ADesc.MaskLineEnd := rileByteBoundary; // ADesc.MaskShift := 0; Prec := CGImageGetBitsPerComponent(ABitmap.CGImage) and $FF; AlphaInfo := CGImageGetAlphaInfo(ABitmap.CGImage); if AlphaInfo <> kCGImageAlphaOnly then begin ADesc.RedPrec := Prec; ADesc.GreenPrec := Prec; ADesc.BluePrec := Prec; end; // gray or mono if ADesc.Format = ricfGray then begin ADesc.Depth := 1; Exit; end; // alpha case AlphaInfo of kCGImageAlphaNone, kCGImageAlphaNoneSkipLast, kCGImageAlphaNoneSkipFirst: begin ADesc.Depth := Prec * 3; // ADesc.AlphaPrec := 0; end; else ADesc.Depth := Prec * 4; ADesc.AlphaPrec := Prec; end; case AlphaInfo of kCGImageAlphaNone, kCGImageAlphaNoneSkipLast: begin // RGBx Shift := 32 - Prec; ADesc.RedShift := Shift; Dec(Shift, Prec); ADesc.GreenShift := Shift; Dec(Shift, Prec); ADesc.BlueShift := Shift; end; kCGImageAlphaNoneSkipFirst: begin // xRGB Shift := 0; ADesc.BlueShift := Shift; Inc(Shift, Prec); ADesc.GreenShift := Shift; Inc(Shift, Prec); ADesc.RedShift := Shift; end; kCGImageAlphaPremultipliedFirst, kCGImageAlphaFirst: begin // ARGB Shift := 32 - Prec; ADesc.AlphaShift := Shift; Dec(Shift, Prec); ADesc.RedShift := Shift; Dec(Shift, Prec); ADesc.GreenShift := Shift; Dec(Shift, Prec); ADesc.BlueShift := Shift; end; kCGImageAlphaPremultipliedLast, kCGImageAlphaLast: begin // RGBA Shift := 32 - Prec; ADesc.RedShift := Shift; Dec(Shift, Prec); ADesc.GreenShift := Shift; Dec(Shift, Prec); ADesc.BlueShift := Shift; Dec(Shift, Prec); ADesc.AlphaShift := Shift; end; kCGImageAlphaOnly: begin // A //ADesc.AlphaShift := 0; end; end; Result := True; end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.RawImage_FromCarbonBitmap Creates a rawimage description for a carbonbitmap ------------------------------------------------------------------------------} function TCarbonWidgetSet.RawImage_FromCarbonBitmap(out ARawImage: TRawImage; ABitmap, AMask: TCarbonBitmap; ARect: PRect = nil): Boolean; var Width, Height: Integer; R: TRect; WorkData: PByte = nil; MaskData: PByte = nil; MaskDataSize, WorkDataSize: PtrUInt; function CreateSub(ARect: TRect; ABmp: TCarbonBitMap; BitsPerPixel: Integer; var ImageDataSize: PtrUInt): PByte; var FullImageData, BytePtr: PByte; SubImageBytesPerRow, DataSize: PtrUInt; ShiftBits, RowCnt, RowByteCnt: Integer; begin SubImageBytesPerRow := (((ARect.Right - ARect.Left) * BitsPerPixel) + 7) div 8; if (BitsPerPixel > 1) then SubImageBytesPerRow := ((((Arect.Right - ARect.Left) * (BitsPerPixel div 8)) + $F) and not PtrUInt($F)); DataSize := SubImageBytesPerRow {%H-}* (ARect.Bottom - ARect.Top); Result := System.GetMem(DataSize); if (Result = nil) then RaiseMemoryAllocationError; BytePtr := Result; ShiftBits := (ARect.Left * BitsPerPixel) mod 8; FullImageData := ABmp.Data + ((ARect.Left * BitsPerPixel) div 8); For RowCnt := 0 to ((ARect.Bottom - ARect.Top) - 1) do begin For RowByteCnt := 0 to (SubImageBytesPerRow - 1) do begin BytePtr^ := (Byte((PByte(FullImageData + RowByteCnt)^ Shl ShiftBits)) or (PByte(FullImageData + RowByteCnt + 1)^ Shr (8 - ShiftBits))); Inc(BytePtr); end; Inc(FullImageData, ABmp.BytesPerRow); end; ImageDataSize := DataSize; end; begin Result := False; FillChar(ARawImage{%H-}, SizeOf(ARawImage), 0); ARawImage.Init; RawImage_DescriptionFromCarbonBitmap(ARawImage.Description, ABitmap); if ARect = nil then begin Width := ABitmap.Width; Height := ABitmap.Height; end else begin R := ARect^; Width := R.Right - R.Left; Height := R.Bottom - R.Top; end; if Width > ABitmap.Width then Width := ABitmap.Width; if Height > ABitmap.Height then Height := ABitmap.Height; if (Width = ABitmap.Width) and (Height = ABitmap.Height) then begin WorkData := ABitmap.Data; WorkDataSize := ABitmap.DataSize; if AMask <> nil then begin MaskData := AMask.Data; MaskDataSize := AMask.DataSize; end; end else begin WorkData := CreateSub(R, ABitmap, ARawImage.Description.BitsPerPixel, WorkDataSize); if AMask <> nil then MaskData := CreateSub(R, AMask, 1, MaskDataSize); end; ARawImage.Description.Width := Width; ARawImage.Description.Height := Height; ARawImage.DataSize := WorkDataSize; ReAllocMem(ARawImage.Data, ARawImage.DataSize); if ARawImage.DataSize > 0 then System.Move(WorkData^, ARawImage.Data^, ARawImage.DataSize); if (WorkData <> ABitmap.Data) then FreeMem(WorkData); Result := True; if AMask = nil then begin ARawImage.Description.MaskBitsPerPixel := 0; Exit; end; if AMask.Depth > 1 then begin DebugLn('[WARNING] RawImage_FromCarbonBitmap: AMask.Depth > 1'); Exit; end; ARawImage.Description.MaskBitsPerPixel := 1; ARawImage.Description.MaskShift := 0; ARawImage.Description.MaskLineEnd := rileByteBoundary; ARawImage.Description.MaskBitOrder := riboReversedBits; ARawImage.MaskSize := MaskDataSize; ReAllocMem(ARawImage.Mask, ARawImage.MaskSize); if ARawImage.MaskSize > 0 then System.Move(MaskData^, ARawImage.Mask^, ARawImage.MaskSize); if (MaskData <> AMask.Data) then FreeMem(MaskData); end; function TCarbonWidgetSet.RawImage_DescriptionToBitmapType( ADesc: TRawImageDescription; out bmpType: TCarbonBitmapType): Boolean; begin Result := False; if ADesc.Format = ricfGray then begin if ADesc.Depth = 1 then bmpType := cbtMono else bmpType := cbtGray; end else if ADesc.Depth = 1 then bmpType := cbtMono else if ADesc.AlphaPrec <> 0 then begin if ADesc.ByteOrder = riboMSBFirst then begin if (ADesc.AlphaShift = 24) and (ADesc.RedShift = 16) and (ADesc.GreenShift = 8 ) and (ADesc.BlueShift = 0 ) then bmpType := cbtARGB else if (ADesc.AlphaShift = 0) and (ADesc.RedShift = 24) and (ADesc.GreenShift = 16 ) and (ADesc.BlueShift = 8 ) then bmpType := cbtRGBA else if (ADesc.AlphaShift = 0 ) and (ADesc.RedShift = 8 ) and (ADesc.GreenShift = 16) and (ADesc.BlueShift = 24) then bmpType := cbtBGRA else Exit; end else begin if (ADesc.AlphaShift = 24) and (ADesc.RedShift = 16) and (ADesc.GreenShift = 8 ) and (ADesc.BlueShift = 0 ) then bmpType := cbtBGRA else if (ADesc.AlphaShift = 0 ) and (ADesc.RedShift = 8 ) and (ADesc.GreenShift = 16) and (ADesc.BlueShift = 24) then bmpType := cbtARGB else if (ADesc.AlphaShift = 24 ) and (ADesc.RedShift = 0 ) and (ADesc.GreenShift = 8) and (ADesc.BlueShift = 16) then bmpType := cbtRGBA else Exit; end; end else begin bmpType := cbtRGB; end; Result := True; end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.GetImagePixelData Used by RawImage_FromDevice. Copies the data from a CGImageRef into a local buffer. The buffer is created using GetMem, and the caller is responsible for using FreeMem to free the returned pointer. This function throws exceptions in case of errors and may return a nil pointer. ------------------------------------------------------------------------------} function TCarbonWidgetSet.GetImagePixelData(AImage: CGImageRef; out bitmapByteCount: PtrUInt): Pointer; var bitmapData: Pointer; context: CGContextRef = nil; colorSpace: CGColorSpaceRef; bitmapBytesPerRow, pixelsWide, pixelsHigh: PtrUInt; imageRect: CGRect; begin Result := nil; // Get image width, height. The entire image is used. pixelsWide := CGImageGetWidth(AImage); pixelsHigh := CGImageGetHeight(AImage); imageRect.origin.x := 0.0; imageRect.origin.y := 0.0; imageRect.size.width := pixelsWide; imageRect.size.height := pixelsHigh; // The target format is fixed in ARGB, DQWord alignment, with 32-bits depth and // 8-bits per channel, the default image format on the LCL bitmapBytesPerRow := ((pixelsWide * 4) + $F) and not PtrUInt($F); bitmapByteCount := (bitmapBytesPerRow * pixelsHigh); // Use the generic RGB color space. colorSpace := CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); if (colorSpace = nil) then RaiseColorSpaceError; // Allocate memory for image data. This is the destination in memory // where any drawing to the bitmap context will be rendered. bitmapData := System.GetMem( bitmapByteCount ); if (bitmapData = nil) then RaiseMemoryAllocationError; { Creates the bitmap context. Regardless of what the source image format is, it will be converted over to the format specified here by CGBitmapContextCreate. } context := CGBitmapContextCreate(bitmapData, pixelsWide, pixelsHigh, 8, // bits per component bitmapBytesPerRow, colorSpace, kCGImageAlphaNoneSkipFirst); // The function fails with kCGImageAlphaFirst if (context = nil) then begin System.FreeMem(bitmapData); RaiseContextCreationError; end; // Draw the image to the bitmap context. Once we draw, the memory // allocated for the context for rendering will then contain the // raw image data in the specified color space. CGContextDrawImage(context, imageRect, AImage); // Now we can get a pointer to the image data associated with the context. // ToDo: Verify if we should copy this data to a new buffer Result := CGBitmapContextGetData(context); { Clean-up } CGColorSpaceRelease(colorSpace); CGContextRelease(context); end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.CreateThemeServices Returns: Theme Services object for Carbon interface ------------------------------------------------------------------------------} function TCarbonWidgetSet.CreateThemeServices: TThemeServices; begin Result := TCarbonThemeServices.Create; end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.PassCmdLineOptions Not used ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.PassCmdLineOptions; begin inherited PassCmdLineOptions; end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.SendCheckSynchronizeMessage ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.SendCheckSynchronizeMessage; var EventSpec: EventTypeSpec; DummyEvent: EventRef; begin if FMainEventQueue=nil then begin //DebugLnThreadLog('TCarbonWidgetSet.SendCheckSynchronizeMessage FMainEventQueue=nil'); exit; end; {$IFDEF VerboseObject} DebugLnThreadLog('TCarbonWidgetSet.SendCheckSynchronizeMessage START'); {$ENDIF} EventSpec := MakeEventSpec(LCLCarbonEventClass,LCLCarbonEventKindWake); DummyEvent:=nil; try if CreateEvent(nil, EventSpec.eventClass, EventSpec.eventKind, 0{GetCurrentEventTime}, kEventAttributeNone, DummyEvent) <> noErr then begin {$IFDEF VerboseObject} DebugLnThreadLog('TCarbonWidgetSet.SendCheckSynchronizeMessage Create event FAILED'); {$ENDIF} Exit; end; {$IFDEF VerboseObject} DebugLnThreadLog('TCarbonWidgetSet.SendCheckSynchronizeMessage GetMainEventQueue='+dbgs(GetMainEventQueue)); {$ENDIF} if PostEventToQueue(FMainEventQueue, DummyEvent, kEventPriorityHigh) <> noErr then begin {$IFDEF VerboseObject} DebugLnThreadLog('TCarbonWidgetSet.SendCheckSynchronizeMessage Post event FAILED'); {$ENDIF} Exit; end; finally if DummyEvent <> nil then ReleaseEvent(DummyEvent); end; {$IFDEF VerboseObject} DebugLnThreadLog('TCarbonWidgetSet.SendCheckSynchronizeMessage END'); {$ENDIF} end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.OnWakeMainThread Params: Sender ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.OnWakeMainThread(Sender: TObject); begin // the code below would start waiting on the first app event to arrive. // however, if fAppLoop has not been initialized and we're in the main thread // we shouldn't wait for it, since signal is given from the main thread. if (GetThreadID=MainThreadID) and (not Assigned(fAppLoop)) then Exit; // wait infinite for the first (dummy) event sent to the main event queue WaitFirstAppEvent; SendCheckSynchronizeMessage; end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.RegisterEvents Registers events for Carbon application ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.RegisterEvents; var TmpSpec: EventTypeSpec; const SName = 'RegisterEvents'; begin //DebugLn('TCarbonWidgetSet.RegisterEvents'); TmpSpec := MakeEventSpec(kEventClassCommand, kEventCommandProcess); InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_CommandProcess), 1, @TmpSpec, nil, @FAEventHandlerRef[0]); TmpSpec := MakeEventSpec(kEventClassApplication, kEventAppShown); InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_Shown), 1, @TmpSpec, nil, @FAEventHandlerRef[1]); TmpSpec := MakeEventSpec(kEventClassApplication, kEventAppHidden); InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_Hidden), 1, @TmpSpec, nil, @FAEventHandlerRef[2]); TmpSpec := MakeEventSpec(kEventClassApplication, kEventAppDeactivated); InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_Deactivated), 1, @TmpSpec, nil, @FAEventHandlerRef[3]); TmpSpec := MakeEventSpec(kEventClassApplication, kEventAppActivated); InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_Activated), 1, @TmpSpec, nil, @FAEventHandlerRef[4]); TmpSpec := MakeEventSpec(LCLCarbonEventClass, LCLCarbonEventKindWake); InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_LazWake), 1, @TmpSpec, nil, @FAEventHandlerRef[5]); InstallReceiveHandler(@CarbonApp_DragReceive, nil, nil); FOpenEventHandlerUPP := NewAEEventHandlerUPP(AEEventHandlerProcPtr(@CarbonApp_Open)); FQuitEventHandlerUPP := NewAEEventHandlerUPP(AEEventHandlerProcPtr(@CarbonApp_Quit)); OSError( AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, FOpenEventHandlerUPP, 0, False), Self, SName, 'AEInstallEventHandler'); OSError( AEInstallEventHandler(kCoreEventClass, kAEOpenContents, FOpenEventHandlerUPP, 0, False), Self, SName, 'AEInstallEventHandler'); OSError( AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, FQuitEventHandlerUPP, 0, False), Self, SName, 'AEInstallEventHandler'); end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.AppTerminate Tells Carbon to halt the application ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.AppTerminate; var i:integer; const SName = 'AppTerminate'; begin if FTerminating then Exit; {$IFDEF VerboseObject} DebugLn('TCarbonWidgetSet.AppTerminate'); {$ENDIF} FUserTerm:=True; QuitApplicationEventLoop; for i:=Low(FAEventHandlerRef) to High(FAEventHandlerRef) do OSError(MacOSALL.RemoveEventHandler(FAEventHandlerRef[i]), TClass(Self), SName, 'RemoveEventHandler'); end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.AppMinimize Minimizes the whole application to the taskbar ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.AppMinimize; var Proc: ProcessSerialNumber; const SName = 'AppMinimize'; begin {$IFDEF VerboseObject} DebugLn('TCarbonWidgetSet.AppMinimize'); {$ENDIF} // hide process if OSError(GetCurrentProcess(Proc{%H-}), Self, SName, SGetCurrentProc) then Exit; OSError(ShowHideProcess(Proc, False), Self, SName, SShowHideProc); end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.AppRestore Restores the whole minimized application from the taskbar ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.AppRestore; var Proc: ProcessSerialNumber; const SName = 'AppRestore'; begin {$IFDEF VerboseObject} DebugLn('TCarbonWidgetSet.AppRestore'); {$ENDIF} // show process if OSError(GetCurrentProcess(Proc{%H-}), Self, SName, SGetCurrentProc) then Exit; OSError(ShowHideProcess(Proc, True), Self, SName, SShowHideProc); end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.AppBringToFront Brings the entire application on top of all other non-topmost programs ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.AppBringToFront; var Proc: ProcessSerialNumber; const SName = 'AppBringToFront'; begin {$IFDEF VerboseObject} DebugLn('TCarbonWidgetSet.AppBringToFront'); {$ENDIF} (* According to Carbon Development Tips & Tricks: 34. How do I bring all my windows to the front? *) if OSError(GetCurrentProcess(Proc{%H-}), Self, SName, SGetCurrentProc) then Exit; OSError(SetFrontProcess(Proc), Self, SName, 'SetFrontProcess'); end; procedure TCarbonWidgetSet.AppSetIcon(const Small, Big: HICON); begin if Big <> 0 then SetApplicationDockTileImage(TCarbonBitmap(Big).CGImage) else RestoreApplicationDockTileImage; end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.AppSetTitle Params: ATitle - New application title Changes the application title ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.AppSetTitle(const ATitle: string); begin // not supported end; function TCarbonWidgetSet.GetLCLCapability(ACapability: TLCLCapability): PtrUInt; begin case ACapability of lcCanDrawOutsideOnPaint, lcNeedMininimizeAppWithMainForm, lcApplicationTitle, lcFormIcon, lcReceivesLMClearCutCopyPasteReliably: Result := LCL_CAPABILITY_NO; lcAntialiasingEnabledByDefault: Result := LCL_CAPABILITY_YES; lcAccessibilitySupport: Result := LCL_CAPABILITY_YES; else Result := inherited; end; end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.LCLPlatform Returns: lpCarbon - enum value for Carbon widgetset ------------------------------------------------------------------------------} function TCarbonWidgetSet.LCLPlatform: TLCLPlatform; begin Result:= lpCarbon; end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.DCGetPixel Params: CanvasHandle - Canvas handle to get color from X, Y - Position Returns: Color of the specified pixel on the canvas ------------------------------------------------------------------------------} function TCarbonWidgetSet.DCGetPixel(CanvasHandle: HDC; X, Y: integer ): TGraphicsColor; begin Result := clNone; {$IFDEF VerboseObject} DebugLn('TCarbonWidgetSet.DCGetPixel DC: ' + DbgS(CanvasHandle) + ' X: ' + DbgS(X) + ' Y: ' + DbgS(Y)); {$ENDIF} if not CheckDC(CanvasHandle, 'DCGetPixel') then Exit; Result := TCarbonDeviceContext(CanvasHandle).GetPixel(X, Y); end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.DCSetPixel Params: CanvasHandle - Canvas handle to get color from X, Y - Position AColor - New color for specified position Sets the color of the specified pixel on the canvas ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.DCSetPixel(CanvasHandle: HDC; X, Y: integer; AColor: TGraphicsColor); begin {$IFDEF VerboseObject} DebugLn('TCarbonWidgetSet.DCSetPixel DC: ' + DbgS(CanvasHandle) + ' X: ' + DbgS(X) + ' Y: ' + DbgS(Y) + 'Color: ' + DbgS(AColor)); {$ENDIF} if not CheckDC(CanvasHandle, 'DCSetPixel') then Exit; TCarbonDeviceContext(CanvasHandle).SetPixel(X, Y, AColor); end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.DCReDraw Params: CanvasHandle - Canvas handle to redraw Redraws (the window of) a canvas ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.DCRedraw(CanvasHandle: HDC); begin {$IFDEF VerboseObject} DebugLn('TCarbonWidgetSet.DCRedraw DC: ' + DbgS(CanvasHandle)); {$ENDIF} if not CheckDC(CanvasHandle, 'DCRedraw') then Exit; CGContextFlush(TCarbonContext(CanvasHandle).CGContext); end; procedure TCarbonWidgetSet.DCSetAntialiasing(CanvasHandle: HDC; AEnabled: Boolean); begin if not CheckDC(CanvasHandle, 'DCSetAntialiasing') then Exit; TCarbonDeviceContext(CanvasHandle).SetAntialiasing(AEnabled); end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.SetDesigning Params: AComponent - Component to set designing Not implemented! ------------------------------------------------------------------------------} procedure TCarbonWidgetSet.SetDesigning(AComponent: TComponent); begin end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.IsHelpKey Params: Key - Shift - Returns: If the specified key is determined to show help in Carbon ------------------------------------------------------------------------------} function TCarbonWidgetSet.IsHelpKey(Key: Word; Shift: TShiftState): Boolean; begin Result := False; // help key is Cmd + ?, will be called directly on key press end; {------------------------------------------------------------------------------ Method: TimerCallback Params: inTimer - Timer reference inUserData - User data passed when installing timer Calls the timer function associated with specified timer ------------------------------------------------------------------------------} procedure TimerCallback(inTimer: EventLoopTimerRef; {%H-}inUserData: UnivPtr); var TimerFunc: TWSTimerProc; begin {$IFDEF VerboseTimer} DebugLn('TimerCallback'); {$ENDIF} if CarbonWidgetSet = nil then Exit; if CarbonWidgetSet.FTimerMap.GetData(inTimer, TimerFunc) then begin {$IFDEF VerboseTimer} DebugLn('TimerCallback Timer instaåled, calling func.'); {$ENDIF} TimerFunc; end; end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.CreateTimer Params: Interval - New timer interval TimerFunc - New timer callback Returns: A Timer id Creates new timer with specified interval and callback function ------------------------------------------------------------------------------} function TCarbonWidgetSet.CreateTimer(Interval: integer; TimerFunc: TWSTimerProc): THandle; var Timer: EventLoopTimerRef; begin {$IFDEF VerboseTimer} DebugLn('TCarbonWidgetSet.CreateTimer Interval: ' + DbgS(Interval)); {$ENDIF} Result := 0; if (Interval > 0) and (TimerFunc <> nil) then begin if OSError(InstallEventLoopTimer(GetMainEventLoop, Interval / 1000, Interval / 1000, // converts msec -> sec EventLoopTimerUPP(@TimerCallback), nil, Timer{%H-}), Self, 'CreateTimer', 'InstallEventLoopTimer') then Exit; FTimerMap.Add(Timer, TimerFunc); Result := {%H-}THandle(Timer) end; {$IFDEF VerboseTimer} DebugLn('TCarbonWidgetSet.CreateTimer Result: ' + DbgS(Result)); {$ENDIF} end; {------------------------------------------------------------------------------ Method: TCarbonWidgetSet.Destroy Params: TimerHandle - Timer id to destroy Returns: If the function succeeds Destroys specified timer ------------------------------------------------------------------------------} function TCarbonWidgetSet.DestroyTimer(TimerHandle: THandle): boolean; begin {$IFDEF VerboseTimer} DebugLn('TCarbonWidgetSet.DestroyTimer Handle: ' + DbgS(TimerHandle)); {$ENDIF} Result := FTimerMap.Delete(TimerHandle); if Result then // valid timer OSError(RemoveEventLoopTimer({%H-}EventLoopTimerRef(TimerHandle)), Self, 'DestroyTimer', 'RemoveEventLoopTimer'); end; function TCarbonWidgetSet.PrepareUserEvent(Handle: HWND; Msg: Cardinal; wParam: WParam; lParam: LParam; out Target: EventTargetRef): EventRef; var EventSpec: EventTypeSpec; AMessage: TLMessage; Widget: TCarbonWidget; begin Result := nil; if FMainEventQueue = nil then Exit; Widget := TCarbonWidget(Handle); if Widget is TCarbonControl then Target := GetControlEventTarget(Widget.Widget) else if Widget is TCarbonWindow then Target := GetWindowEventTarget(TCarbonWindow(Widget).Window) else Exit; EventSpec := MakeEventSpec(LCLCarbonEventClass, LCLCarbonEventKindUser); if CreateEvent(nil, EventSpec.eventClass, EventSpec.eventKind, 0, kEventAttributeUserEvent, Result) <> noErr then Exit; AMessage.Msg := Msg; AMessage.LParam := lParam; AMessage.WParam := wParam; AMessage.Result := 0; SetEventParameter(Result, MakeFourCC('wmsg'), MakeFourCC('wmsg'), SizeOf(TLMessage), @AMessage); end; mricron-0.20140804.1~dfsg.1.orig/otsuml.pas0000755000175000017500000002047611647156254016257 0ustar mihmihunit otsuml; //Multilevel Otsu's Method //Otsu N (1979) A threshold selection method from gray-level histograms. IEEE Trans. Sys., Man., Cyber. 9: 62-66. //Lookup Tables as suggested by Liao, Chen and Chung (2001) A fast algorithm for multilevel thresholding //note that my "otsu.pas" is slightly faster and much simpler if you only want bi-level output interface uses define_types, sysutils; function FindOtsu2 (var Img: Bytep; nVox: integer): byte; //function ApplyOtsu2 (var Img: Bytep; nVox: integer): byte; //function ApplyOtsu3 (var Img: Bytep; nVox: integer): byte; //function ApplyOtsu4 (var Img: Bytep; nVox: integer): byte; procedure ApplyOtsu (var Img: Bytep; nVox, levels: integer);//levels: 2=black/white, 3=3tone, 4=4tone procedure ApplyOtsuBinary (var Img: Bytep; nVox,levels: integer); implementation Type HistoRA = array [0..255] of longint; HistoRAd = array [0..255] of double; Histo2D = array [0..255] of HistoRAd; Function OtsuLUT(H: HistoRA): Histo2D; var Sum,Prob: double; v,u: integer;//column/rom index P,S: Histo2D; begin Sum := 0; for v := 0 to 255 do Sum := Sum + H[v]; if Sum <= 0 then exit; P[0][0] := H[0]; S[0][0] := H[0]; for v := 1 to 255 do begin prob := H[v]/Sum; P[0][v] := P[0][v-1]+prob; S[0][V] := S[0][v-1]+(v+1)*prob; end; for u := 1 to 255 do begin for v := u to 255 do begin P[u][v] := P[0][v]-P[0][u-1]; S[u][v] := S[0][v]-S[0][u-1]; end end; //result is eq 29 from Liao for u := 0 to 255 do begin for v := u to 255 do begin if S[u][v] = 0 then //avoid divide by zero errors... result[u][v] := 0 else result[u][v] := sqr(S[u][v]) /P[u][v]; end end; end; Function OtsuCostFunc(H: HistoRA): integer; //Otsu N (1979) A threshold selection method from gray-level histograms". IEEE Trans. Sys., Man., Cyber. 9: 62-66. //http://en.wikipedia.org/wiki/Otsu's_method //http://www.labbookpages.co.uk/software/imgProc/otsuThreshold.html //returns threshold for binarizing an image // all voxel <=Threshold are background // all voxel >Threshold are object const kMaxBin = 255; var t,total: integer; wB,wF,Sum,SumB,mF,mB,varBetween,varMax: double; begin result := 0; wB := 0; wF := 0; SumB := 0; Sum := 0; Total := 0; varMax := 0; for t := 0 to kMaxBin do Total := Total + H[t]; if Total = 0 then exit; for t := 0 to kMaxBin do Sum := Sum + (t*H[t]); for t :=0 to kMaxBin do begin wB := wB + H[t]; // Weight Background if (wB = 0) then continue; wF := Total - wB; // Weight Foreground if (wF = 0) then break; sumB := sumB+(t * H[t]); mB := sumB / wB; // Mean Background mF := (sum - sumB) / wF; // Mean Foreground // Calculate Between Class Variance varBetween := (wB/Total) * (wF/Total) * sqr(mB - mF); // Check if new maximum found if (t=0) or (varBetween > varMax) then begin varMax := varBetween; result := t; end; end; end; //OtsuCostFunc2 provides same answer as OtsuCostFunc, but is slightly slower and requires more RAM function OtsuCostFunc2(lHisto: HistoRA): integer; var v,max: double; h2d: Histo2D; n: integer; begin h2d := OtsuLUT(lHisto); //default solution n := 128; max := h2d[0,n]+h2d[n+1,255]; result := n; //exhaustively search for n := 0 to (255-1) do begin v := h2d[0,n]+h2d[n+1,255]; if v > max then begin result := n; max := v; end; //new max end; //for n end; //bilevel OtsuCostFunc2 procedure OtsuCostFunc3(lHisto: HistoRA; var Lo,Hi: integer); var v,max: double; l,h: integer; h2d: Histo2D; begin h2d := OtsuLUT(lHisto); //default solution lo := 85; hi := 170; max := h2d[0,lo]+h2d[lo+1,Hi]+h2d[Hi+1,255]; //exhaustively search for l := 0 to (255-2) do begin for h := l+1 to (255-1) do begin v := h2d[0,l]+h2d[l+1,h]+h2d[h+1,255]; if v > max then begin lo := l; hi := h; max := v; end; //new max end;//for h -> hi end; //for l -> low end; //trilevel OtsuCostFunc3 procedure OtsuCostFunc4(lHisto: HistoRA; var Lo,Mid,Hi: integer); var v,max: double; l,m,h: integer; h2d: Histo2D; begin h2d := OtsuLUT(lHisto); //default solution lo := 64; mid := 128; hi := 192; max := h2d[0,lo]+h2d[lo+1,mid]+h2d[mid+1,hi]+h2d[Hi+1,255]; //exhaustively search for l := 0 to (255-3) do begin for m := l+1 to (255-2) do begin for h := m+1 to (255-1) do begin v := h2d[0,l]+h2d[l+1,m]+h2d[m+1,h]+h2d[h+1,255]; if v > max then begin lo := l; mid := m; hi := h; max := v; end; //new max end;//for h -> hi end; //for mid end; //for l -> low end; //quad OtsuCostFunc4 function FindOtsu2 (var Img: Bytep; nVox: integer): byte; var n: integer; lHisto: HistoRA; begin result := 128; if nVox < 1 then exit; //create histogram for n := 0 to 255 do lHisto[n] := 0; for n := 0 to nVox do inc(lHisto[Img^[n]]); //now find minimum intraclass variance.... //result := OtsuCostFunc(lHisto); result := OtsuCostFunc2(lHisto); //same answer, just slower and more memory end; procedure FindOtsu3 (var Img: Bytep; nVox: integer; var lo, hi: integer); var n: integer; lHisto: HistoRA; begin lo := 85; hi := 170; if nVox < 1 then exit; //create histogram for n := 0 to 255 do lHisto[n] := 0; for n := 0 to nVox do inc(lHisto[Img^[n]]); //now find minimum intraclass variance.... OtsuCostFunc3(lHisto,lo,hi); end; procedure FindOtsu4 (var Img: Bytep; nVox: integer; var lo, med, hi: integer); var n: integer; lHisto: HistoRA; begin lo := 64; med := 128; hi := 192; if nVox < 1 then exit; //create histogram for n := 0 to 255 do lHisto[n] := 0; for n := 0 to nVox do inc(lHisto[Img^[n]]); //now find minimum intraclass variance.... OtsuCostFunc4(lHisto,lo,med,hi); end; function ApplyOtsu2 (var Img: Bytep; nVox: integer): byte; var n: integer; begin result := 128; if nVox < 1 then exit; result := FindOtsu2(Img,nVox); for n := 1 to nVox do if Img^[n] > result then Img^[n] := 255 else Img^[n] := 0; end; procedure ApplyOtsu3 (var Img: Bytep; nVox: integer); var n,lo,hi: integer; h: histora; begin if nVox < 1 then exit; FindOtsu3(Img,nVox,lo,hi); for n := 0 to 255 do if n <= Lo then H[n] := 0 else if n <= hi then h[n] := 128 else h[n] := 255; for n := 1 to nVox do Img^[n] := H[Img^[n]]; end; procedure ApplyOtsu4 (var Img: Bytep; nVox: integer); var n,lo,med,hi: integer; h: histora; begin if nVox < 1 then exit; FindOtsu4(Img,nVox,lo,med,hi); for n := 0 to 255 do if n <= Lo then H[n] := 0 else if n <= med then h[n] := 85 else if n <= hi then h[n] := 170 else h[n] := 255; for n := 1 to nVox do Img^[n] := H[Img^[n]]; end; procedure ApplyOtsu (var Img: Bytep; nVox,levels: integer); begin if levels <= 2 then ApplyOtsu2(Img,nVox) else if levels = 3 then ApplyOtsu3(Img,nVox) else ApplyOtsu4(Img,nVox); end; procedure ApplyOtsuBinary (var Img: Bytep; nVox,levels: integer); //1=1/4, 2=1/3, 3=1/2, 4=2/3, 5=3/4 var n: integer; h: histora; begin if nVox < 1 then exit; if (levels <= 1) or (levels >= 5) then ApplyOtsu4(Img,nVox) else if (levels = 2) or (levels = 4) then ApplyOtsu3(Img,nVox) else //level = 3 ApplyOtsu2(Img,nVox); if levels <= 3 then begin //make dark: all except 255 equal 0 for n := 0 to 254 do H[n] := 0; H[255] := 255; end else begin //make bright: all except 0 equal 255 H[0] := 0; for n := 1 to 255 do H[n] := 255; end; for n := 1 to nVox do Img^[n] := H[Img^[n]]; end; end. mricron-0.20140804.1~dfsg.1.orig/iconfinal.ico0000755000175000017500000007330611041367046016654 0ustar mihmih00  .)h000 %6  [ hVlp(0`~~yyDD++EEӣ쿿ہNN <<袢``/0ÛvvMM66MMʭ՚ssGGXY=>-."#  Ue8:y~&@[n~Hamnwׂ؝# )URRϊ{}#Z|]*'v;;jjobw~3<;;;? S emm%%+mm))))$' .J ++LL8722+0! AxE 11dd>>AA;;15'!O"oL-!!''**''__//GGLL@?:=6"**,,555588GG[[MMLL((Lc((6688BB;;@@MMRRbbXXAAZ==AAFFMMIIIIMMlleeYY`--KKLLUUMMQQDDRRxxmm%%\?NNUUXXaaRRbbhhSSMuBB``]]jj[[ffVV||EE6 EEffddrrjj__kkQQTT !++ZZllkkxxmm\\]]^^pp..77XXoopptt||ssssuuQQbb## !!99RRffqqrrtt``\\bb// X('::KK[[ffmmppqqvvzznnxxhhlj78 ,GEQR\[aaddhhjjnnyynnrrRRhhZl+1]LT][``eekkttttuuuull& v\hmsrxx}}{{mm__xxyyuuopolpxu,<:MMVVWW__jj||! H@qp ++::oo?( @aaㅅRR55^^xx44$!psLP2645CC<< pk!&Jj6`IZ]qψܻ<SzuY5 Qe]]zgtA]bb /12'$. ]^^>>;=32@Rcc8 $$$$ssQQIIKL:<p005588WWZZWW"11AAGGEEttSSqq33aNNTTSSppiinnffHHbbaarrbbZZeNNllll__eeqq!!D AAhhxx~~||tt]]YY **@@ZZoo||}}ttffnnb_(@:LN^]jjuu{{{{xxAA~~cL_lpmqqssrrss}}plixjiiiiYXii{{}}ii?(0>LPr7 ;- !$#%--!0F223(5388:3;?< <?1BIJJNMPPPRQZTSYYYYZ\\Z^`__`bbffggovvwwzy|z||~vuH __$  l*VTo14&6>8LMTTYg2 77::LLPPQQUU]\ccpmtt""&&44;AA[[aacceemmssttyy{{}}waO@FchkP=0AgL?689<) 3>JsuX2  1Mix~{zC+' #"[}|y;5!(!KļIE7*_TRH-,oVY4%&t֊]`G./qՈUdD$f^l\:NՎZjnWBԘrmpevbQS???(   k ; kK!& ',->/!09+;2M]PPWjYZbYffhki=jjlklooopt}nxZn[[H[Bj$>5{}{BBKMNNPPddjj  #))::T][[uu&!0793#$/18A>;) =Scba`C@? 5hFGDENegj% :OITRd`VWY*( <^JM`QUZ[+' 6pHLfilm-2",_KX\no4.BkP](0` FP<==)##hhoo eLLrrpp))DJHn[Wmgc nhhwoUo>:XTXTKGtnX tvva )'TPtnrlhcOMx },Z8wn9=:rltorlC@&5۾^sV$ %#lgtntoUQ@=  e*ft*rOKlgtnjdGDC>_%/isc:8c^rmniPL0-  wns_(a*(ZVqkpjSO1-t2155=5' #8GW7RNojoiQM53@@%00~}wviXHELTgjloqt" UQpjlgLH73|JJӞuttwwwwwwO ,*[WqlgbB?SKD3~yxwwwwwwE J SOnhtnXT:7 .zxusromk>ܱd`rmtnMIA?r+voj[RH4|*Z 4 84ojtorl<9z$ uuՆcc'' <20TPjetoql`[ uuuss77!!swVQkfsmsnjeMJ@}}ŀPP88$$ =85lgsnuooj[V=:5dss[[//צB>]YniuotoqkEBOJg "9ww{{LL77%%ߣ 20c^ojtntoqld`JFx  %vvmmWWAA he%$A>ZVrltouoqlfaJG  (?YYDD33 ')(2/HEkfrltotosnniGD=:'=ww{{ggSS7700.4:>IHF4-,-+LH\WidsntotoqkjdXTLJk  %kwwvv[[TToS_gmurmg[ZW\Xkfpksntosnql_ZKH<: 0FxxΘ|wxrsnpjjeWSIE=:˿*bxx}wvqqlb]WSJFFCb_F 1A]||~zsn^[XTQMGCNKw8  *3<??( @ ==)##oo  nhhoUXTXTtnXtva TPtnhcOMx5۾^s$%#lgtoUQ  e*t*rOKtnjdC>_ ns(a*(qkpj1-21=5 #8W7ojoi53JJӞutwwww ,*qlgbSKD3~xwwww J SOtnXT +vj[H4| 4 84ojrl<9 uu՞cc'' 20jeto`[@PP$$ =85lguooj=:d[[//B>niuoqkEB  %mmAA %$ZVrluoqlJG  (YY33 '(HEkftotoniGD %kvv[[oS_mumg[\Xkfsntoql_Z<: FxxΘxrsnjeWS=:˿1]sn^[QMGCw8  *7>0, 8EB@>>>>7:H -;>?>>>>>>JM"5bF>>>>>>KON#3c>>>>>>>SV`& /=>>>>>>XZU )>IV\^_(*'6QTW[]Y!%$LRPa0mricron-0.20140804.1~dfsg.1.orig/MultiSlice.pas0000755000175000017500000007144312147215736017003 0ustar mihmihunit MultiSlice; interface {$mode delphi} uses {$IFNDEF Unix} Windows,wgraphics, {$ELSE} //not used by Darwin... RGBGraphics,rgbroutines, {$ENDIF} LResources,LCLType,SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls,nifti_img,define_types,nifti_img_view, StdCtrls,GraphicsMathLibrary, Menus,ClipBrd,IniFiles,userdir; const kMaxMultiSlice = 24; type TMultiSlice = record Orient,nSlices,OverslicePct: integer; OrthoView,SliceLabel: boolean; SliceList: array [1..kMaxMultiSlice] of integer; end;//TMultiSlice { TMultiSliceForm } TMultiSliceForm = class(TForm) MainMenu1: TMainMenu; File1: TMenuItem; Closewindow1: TMenuItem; Saveasbitmap1: TMenuItem; Edit1: TMenuItem; Copy1: TMenuItem; MultiPanel: TScrollBox; MultiImage: TImage; View1: TMenuItem; OrientMenu: TMenuItem; Axial1: TMenuItem; Sagittal1: TMenuItem; Coronal1: TMenuItem; Orthoview: TMenuItem; Slices1: TMenuItem; Savesettings1: TMenuItem; Settings1: TMenuItem; MultiSaveDialog: TSaveDialog; SliceLabelCheck: TMenuItem; OversliceMenu: TMenuItem; N501: TMenuItem; N331: TMenuItem; N201: TMenuItem; N01: TMenuItem; N202: TMenuItem; N351: TMenuItem; N502: TMenuItem; procedure Copy1Click(Sender: TObject); procedure MenuItem1Click(Sender: TObject); procedure Saveasbitmap1Click(Sender: TObject); procedure OrientClick(Sender: TObject); procedure FormShow(Sender: TObject); procedure CreateMultiAx; procedure CreateMultiCor; procedure CreateMultiSag; procedure CreateMultiSlice; procedure OrthoviewClick(Sender: TObject); procedure Settings1Click(Sender: TObject); procedure Slices1Click(Sender: TObject); procedure Closewindow1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure UpdateMultiSliceDisplay; procedure OpenMultiMRU(Sender:TObject); procedure UpdateMultiSliceMRU; {$IFNDEF FPC} procedure FormClose(Sender: TObject; var Action: TCloseAction); {$ELSE} procedure FormClose(Sender: TObject); {$ENDIF} procedure Savesettings1Click(Sender: TObject); procedure SliceLabelCheckClick(Sender: TObject); procedure OverlsiceClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var MultiSliceForm: TMultiSliceForm; gMulti:TMultiSlice; gMultiSliceDir,gMultiSliceStartupFilename,gMultiSliceDefaultsFilename:string; {$IFDEF FPC} gMultiBuff: RGBQuadp; gMultiWid,gMultiHt: Integer; gMultiXCenterRA: array [1..kMaxMultiSlice] of integer; {$ENDIF} implementation {$IFNDEF FPC} {$R *.DFM} {$ENDIF} function MultiSliceNum2String: string; var lSlice: integer; begin if gMulti.nSlices = 0 then begin gMulti.nSlices := 1; gMulti.SliceList[1] := 1; end; result := ''; for lSlice := 1 to gMulti.nSlices do begin result := result+inttostr(gMulti.SliceList[lSlice]); if lSlice < gMulti.nSlices then result := result+','; end; //for each slice end; procedure MultiSliceString2Num (var lStr: string); var lSliceStr: string; lStrPos,lStrLen,lSlice: integer; begin //showmessage(lStr); lStrLen := length(lStr); if lStrLen < 1 then exit; lSlice := 0; lSliceStr := ''; for lStrPos := 1 to lStrLen do begin if lStr[lStrPos] in ['0'..'9'] then lSliceStr := lSliceStr+lStr[lStrPos]; if ((not (lStr[lStrPos] in ['0'..'9'])) or (lStrPos=lStrLen)) and (lSliceStr<>'') then begin inc(lSlice); if lSlice <= kMaxMultiSlice then gMulti.SliceList[lSlice] := strtoint(lSliceStr); lSliceStr := ''; end; //if white space or eoln end; //for lStrPos gMulti.nSlices := lSlice; if lSlice > kMaxMultiSlice then begin showmessage('Warning: maximum number of slices is '+inttostr(kMaxMultiSlice)); gMulti.nSlices := kMaxMultiSlice; end; end; procedure WriteMultiSliceIniFile (lFilename: string); var lIniFile: TIniFile; begin if DiskFreeEx(lFilename) < 1 then exit; if not DirectoryExists(extractfiledir(lFilename)) then begin mkDir(extractfiledir(lFilename)); end; lIniFile := TIniFile.Create(lFilename); //Slice Index lIniFile.WriteString('STR', 'Slices', MultiSliceNum2String); //Booleans lIniFile.WriteString('BOOL', 'OrthoView',Bool2Char( gMulti.OrthoView)); lIniFile.WriteString('BOOL', 'SliceLabel',Bool2Char( gMulti.SliceLabel)); //Integers LicenseID lIniFile.WriteString('INT', 'Orient',IntToStr(gMulti.Orient)); lIniFile.WriteString('INT', 'OverslicePct',IntToStr(gMulti.OverslicePct)); lIniFile.Free; end; procedure ReadMultiSliceIniFile (lFilename: string); var lStr: string; lIniFile: TIniFile; begin if not FileexistsEx(lFilename) then begin exit; end; lIniFile := TIniFile.Create(lFilename); lStr := lIniFile.ReadString('STR', 'Slices', '10,20,30');//file0 - last file viewed MultiSliceString2Num(lStr); gMulti.OrthoView := IniBool(lIniFile,'OrthoView',gMulti.OrthoView); gMulti.SliceLabel := IniBool(lIniFile,'SliceLabel',gMulti.SliceLabel); gMulti.Orient:= IniInt(lIniFile,'Orient',gMulti.Orient); gMulti.OverslicePct:= IniInt(lIniFile,'OverslicePct',gMulti.OverslicePct); lIniFile.Free; end; procedure TMultiSliceForm.OpenMultiMRU(Sender:TObject); var lFilename: string; begin lFilename := gMultiSliceDir +(Sender as TMenuItem).caption+'.ini' ; ReadMultiSliceIniFile(lFilename); UpdateMultiSliceDisplay; CreateMultiSlice; end; procedure TMultiSliceForm.UpdateMultiSliceMRU; var NewItem: TMenuItem; lSearchRec: TSearchRec; begin While Settings1.Count > 0 do Settings1.Items[0].Free; if FindFirst(gMultiSliceDir +'*.ini', faAnyFile, lSearchRec) = 0 then repeat NewItem := TMenuItem.Create(Self); NewItem.Caption := ParseFileName(ExtractFileName(lSearchRec.Name)); {$IFDEF FPC} NewItem.Onclick := OpenMultiMRU; //Lazarus {$ELSE} NewItem.Onclick := OpenMultiMRU; {$ENDIF} Settings1.Add(NewItem); until (FindNext(lSearchRec) <> 0); FindClose(lSearchRec); end; procedure TMultiSliceForm.Copy1Click(Sender: TObject); {$IFNDEF FPC} var MyFormat : Word; AData: THandle; APalette : HPalette; {$ENDIF} begin {$IFDEF Darwin} Showmessage('Copy not yet supported with OSX: use File/Save'); {$ENDIF} if (MultiImage.Picture.Graphic = nil) then begin //1420z Showmessage('You need to load an image before you can copy it to the clipboard.'); exit; end; {$IFNDEF FPC} MultiImage.Picture.Bitmap.SaveToClipBoardFormat(MyFormat,AData,APalette); ClipBoard.SetAsHandle(MyFormat,AData); {$ELSE} MultiSliceForm.MultiImage.Picture.Bitmap.SaveToClipboardFormat(2); {$ENDIF} end; procedure TMultiSliceForm.MenuItem1Click(Sender: TObject); begin end; procedure TMultiSliceForm.Saveasbitmap1Click(Sender: TObject); begin SaveImgAsPNGBMP (MultiImage); end; {$IFNDEF FPC} //if delphi... procedure CreateBlankBitmap (lPGHt,lPGWid:integer;var lImage: TImage); var sbBits : PByteArray; l32BitP: DWordp; lBGInvisibleColor: DWord; lBMP: TBitmap; lInc : integer; begin lBMP := TBitmap.Create; TRY lBMP.PixelFormat := pf32bit; lBMP.Width := lPGwid; lBMP.Height := lPGHt; sbBits := lBmp.ScanLine[lPGHt-1]; //FillChar(sbBits^,(lPGHt*lPGwid*4), 0); //FillChar fills with black, the next bit will fill current background color lBGInvisibleColor := gMRIcroOverlay[kBGOverlayNum].LUTinvisible; l32BitP := DWordp(sbBits); for lInc := 1 to (lPGwid*lPGHt) do l32BitP[lInc] := lBGInvisibleColor; lImage.Width := (lBmp.Width);//xx lImage.Height := (lBmp.Height);//xx lImage.Picture.Graphic := lBMP; FINALLY lBMP.Free; END; //try..finally end; //proc CreateBlankBitmap {$ELSE} //else freepascal procedure CreateBlankBitmap (lPGHt,lPGWid:integer;var lImage: TImage); var lPos: integer; lBGInvisibleColor: TRGBQuad; begin {$IFDEF ENDIAN_BIG} lBGInvisibleColor :=TColor2TRGBQuad(clBlack); {$ELSE} //lBGInvisibleColor := gMRIcroOverlay[kBGOverlayNum].LUTinvisible; lBGInvisibleColor := gMRIcroOverlay[kBGOverlayNum].LUT[0]; {$ENDIF} gMultiWid := lPGWid; gMultiHt := lPGHt; if (gMultiWid < 1) or (gMultiHt < 1) then exit; getmem (gMultiBuff, gMultiHt*gMultiWid*sizeof(TRGBQuad) ); //fillchar(gMultiBuff^,gMultiHt*gMultiWid*sizeof(TRGBQuad),0); for lPos := 1 to (gMultiHt*gMultiWid) do gMultiBuff^[lPos] := lBGInvisibleColor; end; {$ENDIF} procedure MultiHLine (lX1,lX2,lY1,lThick: integer; lClr: TRGBQuad); var lLine,lY,lYPos,lX,lXlo,lXhi: integer; begin if (lThick < 1) or (gMultiWid < 1) or (gMultiHt < 1) or (lY1 < 1) or (lY1 >gMultiHt) or (gMultiBuff = nil) then exit; lXlo := lX1; lXHi := lX2; SortInteger(lXlo,lXhi); if lXlo < 1 then lXlo := 1; if lXlo > gMultiWid then lXlo := gMultiWid; if lXhi < 1 then lXhi := 1; if lXhi > gMultiWid then lXhi := gMultiWid; lY := lY1-((lThick{+1}) div 2); for lLine := 1 to lThick do begin lYPos := (lY)*gMultiWid; if lY < gMultiHt then for lX := lXlo to lXhi do gMultiBuff^[lYPos+lX] := lClr; inc(lY); end; end; procedure MultiVLine (lX1,lY1,lY2,lThick: integer; lClr: TRGBQuad); var lXs, lX,lY,lYlo,lYhi: integer; begin if (lThick < 1) or (gMultiWid < 1) or (gMultiHt < 1) or (lX1 < 1) or (lX1 >gMultiWid) or (gMultiBuff = nil) then exit; lYlo := lY1; lYHi := lY2; SortInteger(lYlo,lYhi); if lYlo < 1 then lYlo := 1; if lYlo > gMultiHt then lYlo := gMultiHt; if lYhi < 1 then lYhi := 1; if lYhi > gMultiHt then lYhi := gMultiHt; lXs := lX1-((lThick{+1}) div 2)-2;//-2 as indexed from 0 and line is at least 1 pixel thick for lX := lXs to (lXs+lThick-1) do if (lX >= 0) and (lX < gMultiWid) then for lY := lYlo to lYHi do gMultiBuff^[((lY-1)*gMultiWid)+lX] := lClr; end; procedure DefineBackGround(var lBMP: DWordp; lBGInvisibleColor: DWord; lMaskHt,lMaskWid: integer); //lMaskP should have all invis voxels as 128, non as 255 //sets all invis boundary voxels to 0 var lMaskP: ByteP; lBGvisibleColor: DWord; lPos,lMaskSz, lQSz,lQHead,lQTail: integer; lQRA: LongIntp; Procedure IncQra(var lVal, lQSz: integer); begin inc(lVal); if lVal >= lQSz then lVal := 1; end; PROCEDURE RetirePixel; //FIFO cleanup VAR lVal,lPos: integer; BEGIN lVal := lQra^[lQTail]; lPos := lVal-1; if (lPos > 0) and (lMaskP^[lPos]=128) then begin//add item to left incQra(lQHead,lQSz); lMaskP^[lPos] := 0; lQra^[lQHead] := lPos; end; if (lPos > 0) then lMaskP^[lPos] := 0; lPos := lVal+1; if (lPos < lMaskSz) and (lMaskP^[lPos]=128) then begin//add item to right incQra(lQHead,lQSz); lMaskP^[lPos] := 0; lQra^[lQHead] := lPos; end; if (lPos < lMaskSz) then lMaskP^[lPos] := 0; lPos := lVal-lMaskWid; if (lPos > 0) and (lMaskP^[lPos]=128) then begin//add item above incQra(lQHead,lQSz); lMaskP^[lPos] := 0; lQra^[lQHead] := lPos; end; if (lPos > 0) then lMaskP^[lPos] := 0; lPos := lVal+lMaskWid; if (lPos < lMaskSz) and(lMaskP^[lPos]=128) then begin//add item below incQra(lQHead,lQSz); lMaskP^[lPos] := 0; lQra^[lQHead] := lPos; end; if (lPos < lMaskSz) then lMaskP^[lPos] := 0; incQra(lQTail,lQSz); //done with this pixel END; procedure FillStart (lPt: integer); {FIFO algorithm: keep memory VERY low} begin if (lPt < 1) or (lPt > lMaskSz) or (lMaskP^[lPt] <> 128) then exit; //lQSz := 8000;//size of FIFO Queue Array lQHead := 1; lQTail := 1; lQra^[lQTail] := (lPt); //NOTE: both X and Y start from 0 not 1 lMaskP^[lPt] := 0; RetirePixel; if lQHead >= lQTail then begin while lQHead <> lQTail do RetirePixel; end; end; begin //proc DefineBG lMaskSz := lMaskWid * lMaskHt; Getmem(lMaskP,lMaskSz); for lPos := 1 to lMaskSz do if lBMP^[lPos] = lBGInvisibleColor then lMaskP^[lPos] := 128 else lMaskP^[lPos] := 255; lQSz := lMaskSz div 4; GetMem(lQra,lQSz*sizeof(LongInt)); //erase all rows for lPos := 1 to lMaskHt do begin FillStart( (lPos-1)*lMaskWid + 1); FillStart( (lPos)*lMaskWid); end; //erase all cols for lPos := 1 to lMaskWid do begin FillStart( lPos + 1); FillStart( ((lMaskHt-1) *lMaskWid) + lPos); end; Freemem(lQRa); //make sure bright blue 0000FF becauses neighbor 0000FE instead of 000100 if (lBGInvisibleColor and 255) = 255 then lBGVisibleColor:= lBGInvisibleColor-1 else lBGVisibleColor:= lBGInvisibleColor+1; //now, fill in islands so they are not transparent for lPos := 1 to lMaskSz do if lMaskP^[lPos] = 128 then lBMP^[lPos] := lBGVisibleColor; Freemem(lMaskP); end; {$IFDEF FPC} //Delphi draws bitmaps directly, Lazarus can use two indirect methods... procedure SetDim (lInPGHt,lInPGWid,lWriteColumn: integer; var l32OutBitP : DWordp); var lLen,lSrc,lDest,lY: integer; lTBuff: RGBQuadp; begin getmem(lTBuff,lInPGHt*lWriteColumn*4); lLen := lWriteColumn*4; lSrc := 1; lDest := 1; for lY := 1 to lInPGHt do begin //svn Move(Pointer(l32OutBitP^[lSrc]),Pointer(lTBuff^[lDest]),lLen); Move(l32OutBitP^[lSrc],lTBuff^[lDest],lLen); lSrc := lSrc + lInPGWid; lDest := lDest + lWriteColumn; end; DrawBMP( lWriteColumn, lInPGHt, lTBuff, MultiSliceForm.MultiImage); freemem(lTBuff); end; {$ENDIF} //ifdef FPC procedure RemoveHorizGaps (lMaxOverlapWid,lColWid: integer); //will overlap gaps from 1..lMaxOverlapWid, leave right non-overlapped); var l32BitP,l32OutBitP : DWordp; lBGInvisibleColor,lBGInvisibleColorShr8: DWord; lIsGap,lPrevIsGap: boolean; lInc,lPrevSliceStart,lPrevSliceEnd,lPrevWriteColumn,lWid,lHt,lReadRow, lMaxWriteColumn,lReadColumn,lWriteColumn,lReadOffset,lWriteOffset,lPos,x,y: integer; lTextPos,lTextReadColumn: integer; begin (*freemem (gMultiBuff ); gMultiBuff := nil; exit;*) for lTextPos := 1 to kMaxMultiSlice do gMultiXCenterRA[lTextPos] := 0; lTextPos := 0; lTextReadColumn := lColWid div 2; if (gMultiWid < 1) or (gMultiHt < 1) or (gMultiBuff = nil) then exit; lBGInvisibleColor := TRGBQuad2DWord(gMRIcroOverlay[kBGOverlayNum].LUTinvisible); //fx(lBGInvisibleColor); //lBGInvisibleColorShr8 := lBGInvisibleColor Shr 8; lHt := gMultiHt;//MultiSliceForm.MultiImage.Picture.Bitmap.Height; lWid := gMultiWid; //MultiSliceForm.MultiImage.Picture.Bitmap.Width; if (lHt < 2) or (lWid < 2) then exit; //next: prepare input l32BitP := DWordP(gMultiBuff); (*GetMem(l32BitP,lHt*lWid*sizeof(DWord)); lPos := 0; for y:= 0 to (lHt-1) do begin for x:=0 to lWid-1 do begin inc(lPos); l32BitP^[lPos] := MultiSliceForm.MultiImage.Picture.Bitmap.Canvas.Pixels[x,y]; end; end;*) lBGInvisibleColor := l32BitP^[1]; DefineBackGround(l32BitP,lBGInvisibleColor, lHt,lWid); //next prepare output GetMem(l32OutBitP,lHt*lWid*sizeof(DWord)); for lInc := 1 to (lwid*lHt) do l32OutBitP^[lInc] := lBGInvisibleColor; //next: compress by deleting empty columns lWriteColumn := 0; lPrevIsGap := true; lPrevSliceStart := maxint -10; lPrevSliceEnd := 0; lPrevWriteColumn := maxint-10;//do not degap 1st line if gMulti.OverSlicePct = 0 then begin //simply remove gaps between slice for lReadColumn := 1 to lWid do begin lReadOffset := lReadColumn; lIsGap := true; lReadRow := 1; if lReadColumn >= lTextReadColumn then begin inc(lTextPos); lTextReadColumn := lTextReadColumn+lColWid; if lTextPos <= kMaxMultiSlice then gMultiXCenterRA[lTextPos] := lWriteColumn; end; while (lReadRow < lHt) and (lIsGap) do begin if l32BitP^[lReadOffset] <> lBGInvisibleColor then lIsGap := false; inc(lReadOffset,lWid); inc(lReadRow); end; //while each readrow if not lIsGap then begin//data in this column if lReadColumn > (lPrevWriteColumn+1) then begin //leave one pixel gap between noncontiguous columns inc(lWriteColumn); lReadOffset := lReadColumn-1; lWriteOffset := lWriteColumn; //showmessage(inttostr(lWriteColumn)+' '+inttostr(lReadOffset)); for lReadRow := 1 to lHt do begin l32OutBitP[lWriteOffset] := l32BitP[lReadOffset]; inc(lReadOffset,lWid); inc(lWriteOffset,lWid); end; end; //leave 1 pixel gap inc(lWriteColumn); lReadOffset := lReadColumn; lWriteOffset := lWriteColumn; for lReadRow := 1 to lHt do begin l32OutBitP[lWriteOffset] := l32BitP[lReadOffset]; inc(lReadOffset,lWid); inc(lWriteOffset,lWid); end; lPrevWriteColumn := lReadColumn; end; //not Gap - write this column end; //for each column end else begin //overslice <> 0: show subsequent slices above/below each other lMaxWriteColumn := -maxint; for lReadColumn := 1 to lMaxOverlapWid do begin lReadOffset := lReadColumn; lIsGap := true; lReadRow := 1; while (lReadRow < lHt) and (lIsGap) do begin //ovx if l32BitP^[lReadOffset] <> lBGInvisibleColor then lIsGap := false; inc(lReadOffset,lWid); inc(lReadRow); end; //while each readrow if (lPrevIsGap <> lIsGap) then begin//change from prev column if not (lIsGap) then begin //fx(lPrevSliceStart,lPrevSliceEnd,lReadColumn,abs(((lPrevSliceEnd-lPrevSliceStart) * gMulti.OverSlicePct)div 100)); if lPrevSliceEnd > lPrevSliceStart then lWriteColumn := lPrevSliceEnd-abs(((lPrevSliceEnd-lPrevSliceStart) * gMulti.OverSlicePct)div 100); lPrevSliceStart := lWriteColumn; end; if (lIsGap) then lPrevSliceEnd := lWriteColumn; end; lPrevIsGap := lIsGap; if gMulti.OverSlicePct > 0 then begin if not lIsGap then begin//data in this column inc(lWriteColumn); lReadOffset := lReadColumn; lWriteOffset := lWriteColumn; for lReadRow := 1 to lHt do begin if l32BitP^[lReadOffset] <> lBGInvisibleColor then l32OutBitP^[lWriteOffset] := l32BitP^[lReadOffset]; inc(lReadOffset,lWid); inc(lWriteOffset,lWid); end; end; //not Gap - write this column end else begin //if overwrite, else underwrite if not lIsGap then begin//data in this column inc(lWriteColumn); lReadOffset := lReadColumn; lWriteOffset := lWriteColumn; for lReadRow := 1 to lHt do begin if l32OutBitP^[lWriteOffset] = lBGInvisibleColor then l32OutBitP^[lWriteOffset] := l32BitP^[lReadOffset]; inc(lReadOffset,lWid); inc(lWriteOffset,lWid); end; end; //not Gap - write this column end; if lReadColumn >= lTextReadColumn then begin //text inc(lTextPos); lTextReadColumn := lTextReadColumn+lColWid; if lTextPos <= kMaxMultiSlice then gMultiXCenterRA[lTextPos] := lWriteColumn; end; //text if lWriteColumn > lMaxWriteColumn then lMaxWriteColumn := lWriteColumn; end; //for each column if lWriteColumn < lMaxWriteColumn then lWriteColumn := lMaxWriteColumn; if lMaxOverlapWid < lWid then begin lReadColumn := lMaxOverlapWid; if (lWriteColumn) < lReadColumn then //add gap if some compression inc(lWriteColumn); for lReadColumn := (lMaxOverlapWid+1) to lWid do begin lReadOffset := lReadColumn; lIsGap := true; lReadRow := 1; while (lReadRow < lHt) and (lIsGap) do begin if l32BitP^[lReadOffset] <> lBGInvisibleColor then lIsGap := false; inc(lReadOffset,lWid); inc(lReadRow); end; //while each readrow if not lIsGap then begin inc(lWriteColumn); lReadOffset := lReadColumn; lWriteOffset := lWriteColumn; for lReadRow := 1 to lHt do begin l32OutBitP[lWriteOffset] := l32BitP[lReadOffset]; inc(lReadOffset,lWid); inc(lWriteOffset,lWid); end; //for each row end; //not gap end; //for each column if (lWriteColumn+1) < lWid then inc(lWriteColumn); end; //if maxwid < wid - unoverlapped end; SetDim (lHt,lWid,lWriteColumn,l32OutBitP); FreeMem(l32OutBitP); freemem (gMultiBuff ); gMultiBuff := nil; end; procedure TMultiSliceForm.CreateMultiSag; var lSlice,lHt,lWid,lSlicePos,lSliceWid: integer; begin lHt:= gBGIMg.ScrnDim[3]; lSliceWid :=gBGIMg.ScrnDim[2]+2;//+1 for 1-voxel gap between slices - ensures we can detect slice boundary lWid := (lSliceWid*gMulti.nSlices); if lWid < 2 then exit; if gMulti.OrthoView then //coro crossview lWid := lWid + gBGIMg.ScrnDim[1]+2; if lWid < 2 then exit; CreateBlankBitmap (lHt,lWid, MultiImage); for lSlice := 1 to gMulti.nSlices do begin DrawSag (gMulti.SliceList[lSlice],1+((lSlice-1)*lSliceWid));//+lSlice because we want 1-voxel gap between slices //if gMulti.SliceLabel then DrawLabel(MultiImage,DimToMM(gMulti.SliceList[lSlice],1),((lSlice-1)*lSliceWid)+(lSliceWid div 2),lWid); end; if gMulti.OrthoView then begin //coro crossview DrawCor (gBGImg.ScrnDim[2] div 2,(lSliceWid*gMulti.nSlices)-1); //MultiImage.Canvas.Pen.Color := clWhite; //MultiImage.Canvas.Pen.Color := gBGIMg.XBarClr; //MultiImage.Canvas.Pen.Width := gBGImg.XBarThick; for lSlice := 1 to gMulti.nSlices do begin //draw lines lSlicePos := (gMulti.nSlices*lSliceWid)+(gMulti.SliceList[lSlice]); MultiVLine (lSlicePos,0,lHt,gBGImg.XBarThick,TColor2TRGBQuad(gBGImg.XBarClr)); {MultiImage.Canvas.MoveTo(lSlicePos,0); MultiImage.Canvas.LineTo(lSlicePos,lHt);} end;//line for each slice end;//if cross view RemoveHorizGaps(lSliceWid*gMulti.nSlices,lSliceWid); end; //CreateMultiSag procedure TMultiSliceForm.CreateMultiCor; var lSlice,lHt,lWid,lLeft,lSliceWid: integer; begin lHt:= gBGIMg.ScrnDim[3]; lSliceWid :=gBGIMg.ScrnDim[1]+2;//+1 for 1-voxel gap between slices - ensures we can detect slice boundary lWid := lSliceWid*gMulti.nSlices; if lWid < 2 then exit; if gMulti.OrthoView then //sag crossview lWid := lWid + gBGIMg.ScrnDim[2]+2; if lWid < 2 then exit; CreateBlankBitmap (lHt,lWid, MultiImage); for lSlice := 1 to gMulti.nSlices do begin //ImgForm.YViewEdit.value := gMulti.SliceList[lSlice]; DrawCor (gMulti.SliceList[lSlice],1+((lSlice-1)*lSliceWid)); //if gMulti.SliceLabel then DrawLabel(MultiImage,DimToMM(gMulti.SliceList[lSlice],2),((lSlice-1)*lSliceWid)+(gBGIMg.ScrnDim[1] div 2),lWid); end; if gMulti.OrthoView then begin DrawSag (gBGImg.ScrnDim[1] div 2,(gMulti.nSlices*lSliceWid)-1); //MultiImage.Canvas.Pen.Color := gBGIMg.XBarClr; //MultiImage.Canvas.Pen.Color := clWhite; MultiImage.Canvas.Pen.Color := gBGIMg.XBarClr; MultiImage.Canvas.Pen.Width := gBGImg.XBarThick; for lSlice := 1 to gMulti.nSlices do begin lLeft := gMulti.nSlices*lSliceWid+(gMulti.SliceList[lSlice]); MultiVLine (lLeft,0,lHt,gBGImg.XBarThick,TColor2TRGBQuad(gBGImg.XBarClr)); {MultiImage.Canvas.MoveTo(lLeft,0); MultiImage.Canvas.LineTo(lLeft,lHt);} end; end;//if orthoview RemoveHorizGaps(lSliceWid*gMulti.nSlices,lSliceWid); end; //CreateMultiCor procedure TMultiSliceForm.CreateMultiAx; var lSliceWid,lSlice,lHt,lWid,lLeft: integer; begin lHt:= gBGIMg.ScrnDim[2]; lSliceWid :=gBGIMg.ScrnDim[1]+2;//+1 for 1-voxel gap between slices - ensures we can detect slice boundary lWid := lSliceWid*gMulti.nSlices; if lWid < 2 then exit; if gMulti.OrthoView then begin //sag crossview lWid := lWid + gBGIMg.ScrnDim[2]+2; if gBGIMg.ScrnDim[3]> lHt then lHt := gBGIMg.ScrnDim[3]; end; if lWid < 2 then exit; CreateBlankBitmap (lHt,lWid, MultiImage); for lSlice := 1 to gMulti.nSlices do begin DrawAxial (gMulti.SliceList[lSlice],1+((lSlice-1)*lSliceWid)); //if gMulti.SliceLabel then DrawLabel(MultiImage,DimToMM(gMulti.SliceList[lSlice],3),((lSlice-1)*lSliceWid)+(gBGIMg.ScrnDim[1] div 2),lWid); end; if gMulti.OrthoView then begin lLeft := gMulti.nSlices*lSliceWid; //DrawSag (gBGImg.ScrnDim[1] div 2,lLeft); DrawSag (gBGImg.ScrnDim[1] div 2,lLeft-1); //MultiImage.Canvas.pen.Color := clWhite; //MultiImage.Canvas.Pen.Color := gBGIMg.XBarClr; //MultiImage.Canvas.Pen.Width := gBGImg.XBarThick; for lSlice := 1 to gMulti.nSlices do begin lHt := gBGImg.ScrnDim[3]-(gMulti.SliceList[lSlice]); MultiHLine (lLeft,lWid,lHt,gBGImg.XBarThick,TColor2TRGBQuad(gBGImg.XBarClr)); end; end; RemoveHorizGaps(lSliceWid*gMulti.nSlices,lSliceWid); end; //CreateMultiAx procedure DrawLabels; var lSlice,lOrient: integer; begin case gMulti.Orient of 3: lOrient := 2; 2: lOrient := 1; else lOrient := 3; end;//case if not gMulti.SliceLabel then exit; for lSlice := 1 to gMulti.nSlices do begin if gMultiXCenterRA[lSlice] > 0 then DrawLabel(MultiSliceForm.MultiImage,DimToMM(gMulti.SliceList[lSlice],gMulti.SliceList[lSlice],gMulti.SliceList[lSlice],lOrient),gMultiXCenterRA[lSlice],maxint); end; end; //gMultiXCenterRA procedure TMultiSliceForm.CreateMultiSlice; //test var lI: integer; begin if gMulti.nSlices < 1 then begin showmessage('No valid slices selected - please use View/Slices.'); end; //MultiImage.Canvas.Font.Color := clWhite; //for lI := 1 to 32 do begin //test case gMulti.Orient of 3: CreateMultiCor; 2: CreateMultiSag; else CreateMultiAx; end;//case DrawLabels; // end; //test end;//CreateMultiSlice procedure TMultiSliceForm.OrientClick(Sender: TObject); begin (sender as TMenuItem).checked := true; gMulti.Orient := (sender as TMenuItem).tag; CreateMultiSlice; end; procedure TMultiSliceForm.FormShow(Sender: TObject); begin ReadMultiSliceIniFile (gMultiSliceStartupFilename ); UpdateMultiSliceMRU; UpdateMultiSliceDisplay; CreateMultiSlice; MultiSliceForm.BringToFront; end; procedure TMultiSliceForm.OrthoviewClick(Sender: TObject); begin OrthoView.checked := not OrthoView.Checked; gMulti.OrthoView := OrthoView.checked; CreateMultiSlice; end; procedure TMultiSliceForm.Settings1Click(Sender: TObject); begin end; procedure TMultiSliceForm.Slices1Click(Sender: TObject); var lStr: string; begin lStr := InputBox('Select multislices', 'Slice numbers [e.g. 10,16,24]',MultiSliceNum2String); //now parse line MultiSliceString2Num(lStr); CreateMultiSlice; end; procedure TMultiSliceForm.Closewindow1Click(Sender: TObject); begin MultiSliceForm.Close; end; procedure TMultiSliceForm.UpdateMultiSliceDisplay; begin SetSubmenuWithTag(OversliceMenu, gMulti.OverslicePct); SetSubmenuWithTag(OrientMenu, gMulti.Orient); OrthoView.Checked := gMulti.OrthoView; SliceLabelCheck.Checked := gMulti.SliceLabel; end; procedure TMultiSliceForm.FormCreate(Sender: TObject); var lSlice:integer; begin gMultiBuff := nil; gMultiSliceDir := DefaultsDir('multislice'); //gMultiSliceDir := extractfiledir(paramstr(0))+pathdelim+'multislice'+pathdelim; gMultiSliceDefaultsFilename := gMultiSliceDir + 'default.ini'; gMultiSliceStartupFilename := gMultiSliceDefaultsFilename; gMulti.Orient := 1; gMulti.OverslicePct := 0; gMulti.nSlices:= 4; gMulti.OrthoView := true; gMulti.SliceLabel := true; for lSlice := 1 to gMulti.nSlices do gMulti.SliceList[lSlice] := 62+10*lSlice; {$IFDEF Darwin} {$IFNDEF LCLgtk} //only for Carbon compile Copy1.ShortCut := ShortCut(Word('C'), [ssMeta]); Savesettings1.ShortCut := ShortCut(Word('S'), [ssMeta]); Closewindow1.ShortCut := ShortCut(Word('W'), [ssMeta]); {$ENDIF} {$ENDIF} end; {$IFNDEF FPC} procedure TMultiSliceForm.FormClose(Sender: TObject; var Action: TCloseAction); {$ELSE} procedure TMultiSliceForm.FormClose(Sender: TObject); {$ENDIF} begin WriteMultiSliceIniFile (gMultiSliceDefaultsFilename ); end; procedure TMultiSliceForm.Savesettings1Click(Sender: TObject); begin MultiSaveDialog.InitialDir := extractfiledir(gMultiSliceDir ); if not MultiSaveDialog.Execute then exit; {$IFDEF Unix} WriteMultiSliceIniFile(extractfiledir(gMultiSliceDir)+pathdelim+extractfilename(MultiSaveDialog.Filename)); {$ELSE} WriteMultiSliceIniFile(MultiSaveDialog.Filename); {$ENDIF} UpdateMultiSliceMRU; end; procedure TMultiSliceForm.SliceLabelCheckClick(Sender: TObject); begin SliceLabelCheck.checked := not SliceLabelCheck.Checked; gMulti.SliceLabel := SliceLabelCheck.checked; CreateMultiSlice; end; procedure TMultiSliceForm.OverlsiceClick(Sender: TObject); begin (sender as TMenuItem).checked := true; gMulti.OverslicePct := (sender as TMenuItem).tag; CreateMultiSlice; end; {$IFDEF FPC} initialization {$I MultiSlice.lrs} {$ENDIF} end. mricron-0.20140804.1~dfsg.1.orig/winmemmap.pas0000755000175000017500000002107211436532216016707 0ustar mihmihunit winmemmap; {$H+} interface { This Unit implements an interface to Win32 memory mapped files. It can be used to map data simply residing in memory or data residing in a file. The data can be fully mapped into the processes address space or chunks can be mapped. It also provides capabilities for processes to synchronize via mutexes. When mapping sections of the memory, you must be aware that the Win32 memory mapped file interface requires that when you are requesting an offset into the memory region, this offset must be a multiple of the system's memory allocation granularity (I've called it PageSize). At this point it is 64K. This is not a concern when you are mapping anything less than 64K. However, to map anything > 64K the total memory size mapped must be a multiple of 64K or you will not have access to the memorysize MOD 64K bytes left over. Basically there are five rules to be successful when using these routines: 1. Mapname must be unique for each different case you use these objects (MyMap1 for case 1, MyMap2 for case 2 etc.).However, each process using the same memory map MUST use the same MapName. 2. Call MapExisting before CreateMemMap or FCreateMemMap. If another process has already started the mapping, all you want to do is map to the existing map. ie. If NOT MapExisting then CreateMemMap. 3. If your processes are going to write to the mapped memory, it is suggested you use the mutex stuff. 4. Pay heed to the warning above concerning seeking offsets into the mapped memory. Whenever you call the seek function, always check for an error. Errors in mapping to the file will result in the Memmap pointer being Nil. 5. You MUST call LeaveCriticalSection after calling EnterCriticalSection or you will lock other processes wishing to use the map into an infinite wait state. Always use a Try..Finally block. } Uses Classes,Windows; Const hMemMap = $FFFFFFFF; Type //Map to memory TEMemMap = Class(TComponent) Private FhFile : THandle; //File handle, hMemMap when simple memory FhMap : THandle; //Mapping handle FMap : Pointer; //Memory Pointer FMapSize : Cardinal; //Mapping Page Size FMemSize : Cardinal; //Maximum size allocated, >=FileSize when a file FPageSize : Cardinal; //Minimum System allocation size FMaxSeeks : Cardinal; //Maximum seeks available,(FMemSize DIV PageSize)-1 FMapError : Integer; //Error returned FhMutex : THandle; //Mutex handle for sharing FInMutex : Boolean; //Internal flag Function SetMapError : Boolean; Procedure SetMemSize(Size : Cardinal); Public Constructor Create(Aowner : TComponent); Override; Destructor Destroy; Override; //Create a mutex for sychronizing access Function CreateMutex(Const MutexName : String) : Boolean; //Use the mutex Procedure EnterCriticalSection; //Release the mutex Procedure LeaveCriticalSection; //Map to existing memory map Function MapExisting(Const MapName : String; Const MapSize : Cardinal) : Boolean;Virtual; //Create a new memory map Function CreateMemMap(Const MapName : String; Const MapSize : Cardinal; Const MapData ) : Boolean;Virtual; //seek to an offset in the memory map Function Seek(Const OffSet : Cardinal) : Boolean; //duh? Procedure RaiseMappingException;Virtual; Property MemMap : Pointer Read FMap; //The mapped memory Property MapError : Integer Read FMapError Write FMapError; Property MemSize : Cardinal Read FMemSize Write SetMemSize; //Memory size to allocate Property PageSize : Cardinal Read FPageSize; //system returned page size Property MaxSeeks : Cardinal Read FMaxSeeks; //maximum seeks allowed end; //map to a file TEFileMap = Class(TEMemMap) Public Function FCreateMemMap(Const Filename : String; Const MapName : String; Const MapSize : Cardinal) : Boolean; Function FlushFileView : Boolean; end; implementation Uses SysUtils; Type EMappingException = class(Exception); Constructor TEMemMap.Create(AOwner : TComponent); Var SysInfo : TSystemInfo; begin Inherited Create(AOwner); FhFile:=hMemMap; GetSystemInfo(SysInfo); FPageSize:=SysInfo.dwAllocationGranularity; end; Destructor TEMemmap.Destroy; begin LeaveCriticalSection; If FhMutex<>0 then CloseHandle(FhMutex); If FMap<>Nil then UnMapViewOfFile(FMap); If FHMap<>0 then CloseHandle(FHMap); Inherited Destroy; end; Function TEMemMap.CreateMutex(Const MutexName : String) : Boolean; begin If FhMutex=0 then FhMutex:=Windows.CreateMutex(Nil,False,PChar(MutexName)); If FhMutex=0 then Result:=SetMapError else Result:=True; end; Procedure TEMemMap.EnterCriticalSection; begin If (NOT FInMutex) AND (FhMutex>0) then begin WaitForSingleObject(FhMutex,INFINITE); FInMutex:=True; end; end; Procedure TEMemMap.LeaveCriticalSection; begin If FInMutex AND (FhMutex>0) then begin ReleaseMutex(FhMutex); FInMutex:=False; end; end; Function TEMemMap.SetMapError : Boolean; begin FMapError:=GetLastError; Result:=False; end; Procedure TEMemMap.RaiseMappingException; Var TError : Integer; begin If FMapError<>0 then begin LeaveCriticalSection; TError:=FMapError; FMapError:=0; Raise EMappingException.Create('Memory Mapping Error #'+IntToStr(TError)); end; end; Procedure TEMemMap.SetMemSize(Size : Cardinal); begin FMemSize:=Size; If FMemSize>PageSize then FMaxSeeks:=(FMemSize DIV PageSize)-1 else FMaxSeeks:=0; end; //map to an existing memory map described by MapName Function TEMemMap.MapExisting(Const MapName : String; Const MapSize : Cardinal) : Boolean; begin FMapSize:=MapSize; FMap:=Nil; FhMap:=OpenFileMapping(FILE_MAP_WRITE,BOOL(True),PChar(MapName)); If FhMap<>0 then begin FMap:=MapViewOfFile(FhMap,FILE_MAP_WRITE,0,0,MapSize); If FMap=Nil then begin CloseHandle(FHMap); FHMap:=0; SetMapError; end; end; Result:=FMap<>Nil; end; //Create a new memory mapping Function TEMemMap.CreateMemMap(Const MapName : String; Const MapSize : Cardinal; Const MapData ) : Boolean; begin If FMemSize=0 then FMemSize:=MapSize; FhMap:=CreateFileMapping(FhFile,nil,PAGE_READWRITE,0,FMemSize,PChar(MapName)); If FhMap<>0 then begin FMap:=MapViewOfFile(FhMap,FILE_MAP_WRITE,0,0,MapSize); If FMap<>Nil then begin If fHFile=hMemMap then begin EnterCriticalSection; Try Move(MapData,FMap^,MapSize); Finally LeaveCriticalSection; end; end; Result:=True; end else Result:=SetMapError; end else Result:=SetMapError; end; //seek to a different position in map (0..MaxSeeks) Function TEMemMap.Seek(Const OffSet : Cardinal) : Boolean; begin Result:=True; If NOT UnMapViewOfFile(FMap) then Result:=SetMapError else begin FMap:=MapViewOfFile(FhMap,FILE_MAP_WRITE,0,OffSet*PageSize,FMapSize); If FMap=Nil then Result:=SetMapError; end; end; //Create a file mapping Function TEFileMap.FCreateMemMap(Const Filename : String; Const MapName : String; Const MapSize : Cardinal) : Boolean; Var TInt : Cardinal; begin FHFile:=CreateFile(PChar(FileName),GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE,NIl,OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS,0); If FhFile<>0 then begin Try Result:=CreateMemMap(MapName,MapSize,TInt); Finally CloseHandle(FhFile); end; end else Result:=SetMapError; end; Function TEFileMap.FlushFileView : Boolean; begin EnterCriticalSection; Try Result:=FlushViewOfFile(FMap,FMapSize) OR SetMapError; Finally LeaveCriticalSection; end; end; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/0000755000175000017500000000000012413465015015526 5ustar mihmihmricron-0.20140804.1~dfsg.1.orig/dcm2nii/pref_form.lfm0000755000175000017500000001026612315600456020216 0ustar mihmihobject PrefsForm: TPrefsForm Left = 466 Height = 332 Top = 176 Width = 600 HorzScrollBar.Page = 463 VertScrollBar.Page = 323 ActiveControl = DateCheck BorderIcons = [biSystemMenu] Caption = 'Preferences' ClientHeight = 332 ClientWidth = 600 Constraints.MaxHeight = 332 Constraints.MaxWidth = 600 Constraints.MinHeight = 332 Constraints.MinWidth = 600 Position = poDesktopCenter LCLVersion = '1.0.12.0' object Label1: TLabel Left = 112 Height = 17 Top = 200 Width = 188 Caption = 'Recursive folder search depth' ParentColor = False end object OutDirLabel: TLabel Left = 16 Height = 17 Top = 264 Width = 19 Caption = 'c:\' ParentColor = False end object FilenameBox: TGroupBox Left = 8 Height = 176 Top = 8 Width = 232 Caption = 'Output Filename' ClientHeight = 154 ClientWidth = 224 TabOrder = 0 object DateCheck: TCheckBox Left = 22 Height = 18 Top = 8 Width = 124 Caption = 'Acquisition Date' OnChange = FilenameChecks TabOrder = 0 end object InputNameCheck: TCheckBox Left = 22 Height = 18 Top = 33 Width = 114 Caption = 'Input Filename' OnChange = FilenameChecks TabOrder = 1 end object ProtocolCheck: TCheckBox Left = 22 Height = 18 Top = 57 Width = 113 Caption = 'Protocol Name' OnChange = FilenameChecks TabOrder = 2 end object PatientNameCheck: TCheckBox Left = 22 Height = 18 Top = 81 Width = 104 Caption = 'Patient Name' OnChange = FilenameChecks TabOrder = 3 end object SeriesCheck: TCheckBox Left = 22 Height = 18 Top = 105 Width = 131 Caption = 'Acquisition Series' OnChange = FilenameChecks TabOrder = 4 end end object OKbtn: TButton Left = 488 Height = 25 Top = 288 Width = 75 BorderSpacing.InnerBorder = 4 Caption = 'OK' ModalResult = 1 TabOrder = 1 end object CancelBtn: TButton Left = 400 Height = 25 Top = 288 Width = 75 BorderSpacing.InnerBorder = 4 Caption = 'Cancel' ModalResult = 2 TabOrder = 2 end object NotAnonymizeCheck: TCheckBox Left = 248 Height = 18 Top = 24 Width = 233 Caption = 'Save patient name in NIfTI header' TabOrder = 3 end object ReorientCheck: TCheckBox Left = 248 Height = 18 Top = 88 Width = 336 Caption = 'Reorient large images to nearest orthogonal plane' TabOrder = 4 end object RecursiveSpin: TSpinEdit Left = 16 Height = 16 Top = 200 Width = 77 MaxValue = 10 TabOrder = 5 end object OutputCombo: TComboBox Left = 16 Height = 20 Top = 232 Width = 296 ItemHeight = 0 Items.Strings = ( 'Save to source folder' 'Prompt user for output folder' 'Always save to...' ) OnChange = OutputComboChange OnMouseUp = OutputComboMouseUp Style = csDropDownList TabOrder = 6 end object CollapseCheck: TCheckBox Left = 248 Height = 18 Hint = 'Sort images regardless of source directory. Slower, required if series segmented across folders' Top = 120 Width = 121 Caption = 'Collapse folders' TabOrder = 7 end object Stack3DImagesWithSameAcqNum: TCheckBox Left = 248 Height = 18 Hint = 'Sort images regardless of source directory. Slower, required if series segmented across folders' Top = 152 Width = 314 Caption = 'Stack 3D images with same acquistion number' TabOrder = 8 end object TextEditorBtn: TButton Left = 8 Height = 25 Top = 288 Width = 123 BorderSpacing.InnerBorder = 4 Caption = 'Text Edit' OnClick = TextEditorBtnClick TabOrder = 9 end object WritePrefsOnQuit: TCheckBox Left = 390 Height = 18 Top = 120 Width = 138 Caption = 'Write prefs on quit' Checked = True State = cbChecked TabOrder = 10 Visible = False end object TxtReportCheck: TCheckBox Left = 248 Height = 18 Top = 56 Width = 282 Caption = 'Save text report (scan and patient details)' TabOrder = 11 end end mricron-0.20140804.1~dfsg.1.orig/dcm2nii/bvec.pas0000755000175000017500000000626212355340050017157 0ustar mihmihunit bvec; {$ifdef fpc}{$mode delphi}{$endif} {$H+} interface uses //StrUtils, Classes, SysUtils, define_types, dicomtypes, dialogsx,GraphicsMathLibrary,dialogs_msg; //{$DEFINE VERBOSE_BVEC} procedure siemensPhilipsCorrectBvecs (var lDICOMdata:dicomdata; var lDTIra: TDTIra; nVec: integer; lSliceOrientMosaicNegativeDeterminant: boolean); implementation (*function VV (lLabel: string; var lV: TVector): string; begin result := lLabel +' =['+ floattostr(lV.x)+','+floattostr(lV.y)+','+ floattostr(lV.z)+']'';'; end; procedure VTX (var bvecs_old,slice_dir,read_dir,phase_dir: TVector); var lStr : string; begin lStr := ''; lStr := lStr + VV('bvecs_old',bvecs_old); lStr := lStr + VV('slice_dir',slice_dir); lStr := lStr + VV('read_dir',read_dir); lStr := lStr + VV('phase_dir',phase_dir); dcmMsg(lStr); end; *) procedure siemensPhilipsCorrectBvecs (var lDICOMdata:dicomdata; var lDTIra: TDTIra; nVec: integer; lSliceOrientMosaicNegativeDeterminant: boolean); //see Matthew Robson's http://users.fmrib.ox.ac.uk/~robson/internal/Dicom2Nifti111.m //convert DTI vectors from scanner coordinates to image frame of reference //Uses 6 orient values from ImageOrientationPatient (0020,0037) // requires PatientPosition 0018,5100 is HFS (head first supine) var lI: integer; read_vector ,phase_vector,slice_vector,bvecs_old,bvecs_new: TVector; begin if nVec < 1 then exit; if (length(lDicomData.PatientPos) >= 3) and (lDicomData.PatientPos[1] = 'H') and (lDicomData.PatientPos[2] = 'F') and (lDicomData.PatientPos[3] = 'S') then else begin dcmMsg('DTI vector error: Position is not head first supine'); exit; end; read_vector := Vector3D(lDICOMData.Orient[1],lDICOMData.Orient[2],lDICOMData.Orient[3]); phase_vector := Vector3D(lDICOMData.Orient[4],lDICOMData.Orient[5],lDICOMData.Orient[6]); slice_vector := CrossProduct(read_vector ,phase_vector); NormalizeVector(read_vector); NormalizeVector(phase_vector); NormalizeVector(slice_vector); for lI := 1 to nVec do begin //afx('test',lDTIra[lI],lI); if (lDTIra[lI].bval <= 0) or ((lDTIra[lI].v1 = 0) and (lDTIra[lI].v2 = 0) and (lDTIra[lI].v3 = 0)) then begin lDTIra[lI].v1 := 0; lDTIra[lI].v2 := 0; lDTIra[lI].v3 := 0; end else begin bvecs_old := Vector3D(lDTIra[lI].v1,lDTIra[lI].v2,lDTIra[lI].v3); //VTX (bvecs_old,slice_vector,read_vector,phase_vector ); bvecs_new :=Vector3D(DotProduct(bvecs_old,read_vector),DotProduct(bvecs_old,phase_vector),DotProduct(bvecs_old,slice_vector) ); bvecs_new.y := - bvecs_new.y; NormalizeVector(bvecs_new); lDTIra[lI].v1 := bvecs_new.x; if lSliceOrientMosaicNegativeDeterminant then lDTIra[lI].v2 := -bvecs_new.y else lDTIra[lI].v2 := bvecs_new.y; lDTIra[lI].v3 := bvecs_new.z; end; end;//for each bvec if lSliceOrientMosaicNegativeDeterminant then dcmmsg('WARNING: please validate DTI vectors (matrix had a negative determinant, perhaps Siemens sagittal).'); end;//PhilipsSiemensCorrectBvecs end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/gui.lrs0000755000175000017500000000673012204746342017050 0ustar mihmih{ This is an automatically generated lazarus resource file } LazarusResources.Add('TMainForm','FORMDATA',[ 'TPF0'#9'TMainForm'#8'MainForm'#4'Left'#3'c'#1#6'Height'#3'k'#1#3'Top'#3#132#0 +#5'Width'#3'V'#2#13'ActiveControl'#7#6'Panel1'#14'AllowDropFiles'#9#7'Captio' +'n'#6#7'dcm2nii'#12'ClientHeight'#3'k'#1#11'ClientWidth'#3'V'#2#4'Menu'#7#9 +'MainMenu1'#7'OnClose'#7#9'FormClose'#8'OnCreate'#7#10'FormCreate'#11'OnDrop' +'Files'#7#13'FormDropFiles'#6'OnShow'#7#8'FormShow'#10'LCLVersion'#6#7'1.0.2' +'.0'#0#5'TMemo'#5'Memo1'#4'Left'#2#4#6'Height'#3'E'#1#3'Top'#2'"'#5'Width'#3 +'N'#2#5'Align'#7#8'alClient'#18'BorderSpacing.Left'#2#4#19'BorderSpacing.Rig' +'ht'#2#4#20'BorderSpacing.Bottom'#2#4#10'ScrollBars'#7#14'ssAutoVertical'#8 +'TabOrder'#2#0#0#0#6'TPanel'#6'Panel1'#4'Left'#2#0#6'Height'#2'"'#3'Top'#2#0 +#5'Width'#3'V'#2#5'Align'#7#5'alTop'#10'BevelOuter'#7#6'bvNone'#12'ClientHei' +'ght'#2'"'#11'ClientWidth'#3'V'#2#8'TabOrder'#2#1#0#6'TLabel'#6'Label1'#4'Le' +'ft'#2#1#6'Height'#2#26#3'Top'#2#5#5'Width'#3#140#0#9'Alignment'#7#14'taRigh' +'tJustify'#7'Anchors'#11#6'akLeft'#0#8'AutoSize'#8#7'Caption'#6#16'Output Fo' +'rmat: '#6'Layout'#7#8'tlCenter'#11'ParentColor'#8#0#0#9'TComboBox'#9'TypeC' +'ombo'#4'Left'#3#160#0#6'Height'#2#20#3'Top'#2#3#5'Width'#3#8#1#10'ItemHeigh' +'t'#2#0#13'Items.Strings'#1#6#24'SPM2 (3D Anlyze hdr/img)'#6#23'SPM5 (3D NIf' +'TI hdr/img)'#6#19'SPM8 (3D NIfTI nii)'#6#16'4D NIfTI hdr/img'#6#23'FSL/SPM8' +' (4D NIfTI nii)'#6#29'Compressed FSL (4D NIfTI nii)'#0#5'Style'#7#14'csDrop' +'DownList'#8'TabOrder'#2#0#0#0#0#11'TOpenDialog'#10'OpenHdrDlg'#11'FilterInd' +'ex'#2#0#4'left'#2#24#3'top'#2'0'#0#0#9'TMainMenu'#9'MainMenu1'#4'left'#2'X' +#3'top'#2'0'#0#9'TMenuItem'#5'File1'#7'Caption'#6#4'File'#0#9'TMenuItem'#13 +'DICOMtoNIfTI1'#7'Caption'#6#14'DICOM to NIfTI'#8'ShortCut'#3'D@'#7'OnClick' +#7#15'dcm2niiBtnClick'#0#0#9'TMenuItem'#12'ModifyNIfTI1'#7'Caption'#6#12'Mod' +'ify NIfTI'#7'OnClick'#7#17'ModifyNIfTI1Click'#0#0#9'TMenuItem'#10'NIfTI3D4D' +'1'#7'Caption'#6#14'NIfTI 3D -> 4D'#7'OnClick'#7#15'NIfTI3D4D1Click'#0#0#9'T' +'MenuItem'#15'AnonymizeDICOM1'#7'Caption'#6#15'Anonymize DICOM'#7'OnClick'#7 +#20'AnonymizeDICOM1Click'#0#0#9'TMenuItem'#5'Exit1'#7'Caption'#6#4'Exit'#7'O' +'nClick'#7#10'Exit1Click'#0#0#0#9'TMenuItem'#5'Edit1'#7'Caption'#6#4'Edit'#0 +#9'TMenuItem'#5'Copy1'#7'Caption'#6#4'Copy'#7'OnClick'#7#10'Copy1Click'#0#0#0 +#9'TMenuItem'#12'UntestedMenu'#7'Caption'#6#8'Untested'#0#9'TMenuItem'#17'Mi' +'rrorXdimension1'#7'Caption'#6#18'Mirror X-dimension'#7'OnClick'#7#22'Mirror' +'Xdimension1Click'#0#0#9'TMenuItem'#7'SumTPM1'#7'Caption'#6#7'Sum TPM'#7'OnC' +'lick'#7#12'SumTPM1Click'#0#0#9'TMenuItem'#17'ExtractDICOMdims1'#7'Caption'#6 +#18'Extract DICOM dims'#7'OnClick'#7#22'ExtractDICOMdims1Click'#0#0#9'TMenuI' +'tem'#16'ExtractDICOMhdr1'#7'Caption'#6#20'Extract DICOM header'#7'OnClick'#7 +#21'ExtractDICOMhdr1Click'#0#0#9'TMenuItem'#17'ExtractNIfTIhdrs1'#7'Caption' +#6#20'Extract NIfTI header'#7'OnClick'#7#22'ExtractNIfTIhdrs1Click'#0#0#9'TM' +'enuItem'#10'HalveMenu1'#7'Caption'#6#25'Halve dimensions in-plane'#7'OnClic' +'k'#7#15'HalveMenu1Click'#0#0#0#9'TMenuItem'#5'Help1'#7'Caption'#6#4'Help'#0 +#9'TMenuItem'#12'Preferences1'#7'Caption'#6#11'Preferences'#7'OnClick'#7#17 +'Preferences1Click'#0#0#9'TMenuItem'#6'About1'#7'Caption'#6#4'Help'#7'OnClic' +'k'#7#11'About1Click'#0#0#0#0#22'TSelectDirectoryDialog'#22'SelectDirectoryD' +'ialog1'#4'left'#3#159#0#3'top'#2'6'#0#0#0 ]); mricron-0.20140804.1~dfsg.1.orig/dcm2nii/x/0000755000175000017500000000000012273003522015770 5ustar mihmihmricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2nii.res0000755000175000017500000000317012360762664017605 0ustar mihmih   ( @ 1 3333133333333333331DDFvvD1Gggfv@1&vvggd 1wwgbvt 1wwwr"gf@1wwwr"vv@3wr""gf@3wr""&f@ww"w""@1wr'""@1w""$1rwr"3'w"/3"ww$"" 11 3 p 31 3333;313333333333  ?????~>??????0MAINICON    4VS_VERSION_INFO  ?JStringFileInfo&040904E4: CompanyNameChris Rorden`FileDescriptionDICOM and PAR/REC converter0FileVersion0.9.0.1"InternalName< LegalCopyrightCopyright *LegalTrademarks@ OriginalFilenamedcm2nii.exe0ProductNamedcm2nii,ProductVersion0.0CommentsDVarFileInfo$Translation mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2niigui.ico0000755000175000017500000004220612360763615020273 0ustar mihmih00 %F  % 6 h@(0` %~~zz{{{{|||~~jjjvummnrrqrrrttt}}}lllxxx888kkk zzz֦أأ٢٣٢٢ئۛsss9rrp!pqm##"ggtPPKSTG]]Ybbbiiibbb___HҚlwyYrtPstPxzZl𒓃𡡞𫫯𭭲𨨩𥥣𥥥짧񓓓rlo;`d_eekkqnumtkqgmekhmuy=r```ͨhj7X^u|t|qwSpppplll"4xkJ;>}}IsA!G&PileJ!&,)nqF:F?(dfZllfjdTryyvҒzzzkkkШ|}zzzÍv{}wwwN``` (⫫ttsyyyzzzzzzzzz~~~wwwరeeeqqqT쭭zzzxxxTTT}}}򭭭}}}rrr|||xxxyyysssxxx}}}|||zzzzzz{{{xxxtttuuuwww{{{uuu薕Ԗ֟Ҟ___Z푑nnnooonnnjjjtlllgwwwUiii ciflnurrr^wwwuuu1ʍ48DDD^^^jjjkkkzzzuuuyyynRVkY E*XPOMKKDpeeevvvI]表*GNW籸)*{{{y񩩩3EEE```zzzzzz;'>:*^^^J몪. ~ZZZ```yyy Ď *ܬZuB47-î 򤤤l ###.#(-S2)8NদìT .L%%vxch7D+#HBRX&樰0-.#]]]RRR򢢢$ z%6f$%,̧sNuwRF쯮Mnkh-hJty% SmMVsxyyyrrr, g̒~QףW 4泲¡JTTTxxxaaa kɪ᭭𰰰c- "WT|||rrrXXXlll-B[tȡtٛK斝/!ט"(w~.: xxx??? nnn&aUb`opS'x|4079:<~-0y|8)]Zh[www5#H2_ZqrV8<?0}9#,{)w{3{7$??( @ vvv{{{ZZZnnnfff[[[{{{aaacccaa`lkoyy|Ooq<uxEjSSSoooWWW .,--,,\\YYYOnnjyqrPfh;kmEkO֧Ťyyjss]wxd|&~Yrv*sxu| v}v| v{y~%K_u}%񠠞iXrttrզp(<;" }Qbg;lpAvvtEEE777]]].詩le}{ut~{z '''LLL`zzyদᔔyyx~}}||{{{vvvrrrwwwwww~~坝ᚚ~~~lϭmmms|||giiiZKBԲ ou Ylr rxlllҬ555qqqc"yppp˪7641P~~~;/Vy .xxxü %_$mmm=좢:MഴG#OD%H, آ{~շɯ󵵵}*| (8su7E8(79(%%I   @\0K򆅑g첲N d٬0{{{jjjLfͮબT( ɇ(y{Y@ljvkkkwr%3OC.P-Y+T-<:ruDy|(JUgggE+*).5sv@x{+tx-5"" #&??`??(0 ` ccc{{{LLL{{{$HEEH&,V` ~ׇhtx;qu.uy<ӂ]ӗөѪӓ1szAx ⣣zZwwwC%(Yver| O𳴰jEN0+ꨨQC讯ް&/ͦ1i.%)%%  70cK\)P$ﭫO(Tծ魭f(  鎕(rby|H .ANS&b"k#_$9(E>uuuBBCB#)][^}dp'?<><?(  @ hf~FddT)'jh~%%&"~~wh^B N8\fIGq}}}zr{oAԬzz~䣢Z멩A1s {%ᦥo%U) ϻ(݉7a*񵴿 歭>U8-i~议; 3̦kssw"7MPb"sy^&+;(jW=tIIIT)G<}ciAE  N?mricron-0.20140804.1~dfsg.1.orig/dcm2nii/csaread.pas0000755000175000017500000004110712311047132017634 0ustar mihmihunit csaread; interface // Extract vital details from the Siemens CSA header that is contained within a DICOM file. // This is DICOM group:element (0029:1010) [CSA Image Header Info] // These values are crucial converting 2D mosaics to 3D images and computing DTI vectors //see http://nipy.sourceforge.net/nibabel/dicom/siemens_csa.html // This is a port of John Ashburners' spm_dicom_headers.m Matlab code uses SysUtils, dialogsx, define_types,dialogs_msg, nifti_hdr, nifti_types; {DEFINE verbose} {$H+} type TBytearray = array of byte; TSliceTimes = array of single; TCSA = record PhaseDirectionPositive: integer; //0 or 1, -1 for unknown Slices,MosaicX,MosaicY: longword; BandwidthPerPixelPhaseEncode, Bvalue,DTIv1,DTIv2,DTIv3, SliceNormV1, SliceNormV2,SliceNormV3: double; CustomerSeq: string; //SliceTimes : array of single; end; function DecodeCSA2 (lFilename: string; lCSAImageHeaderInfoPos, lCSAImageHeaderInfoSz: integer; var lCSA: TCSA; var lSliceTimes: TSliceTimes; var lFlippedMosaic: boolean): boolean; function GetCSASeriesHeaderInfo (lFilename: string; lStart, lLength, lnSlices: integer; var lSliceOrder: integer): string; function GetCSAImageHeaderInfoDTI (lFilename: string; lStart,lLength: integer; var lBval: integer; var ldti1,ldti2,ldti3: double): boolean; function GetCSAImageHeaderInfo (lFilename: string; lStart,lLength: integer; var lMosaicSlices,lMosaicX,lMosaicY: integer; var lv1,lv2,lv3: double): boolean; implementation function GetCSAImageHeaderInfoDTI (lFilename: string; lStart,lLength: integer; var lBval: integer; var ldti1,ldti2,ldti3: double): boolean; var lCSA: TCSA; lFlippedMosaic: boolean; lSliceTimes: TSliceTimes ; begin //lBval := -1;//imposibble - read error result := DecodeCSA2 (lFilename, lStart,lLength, lCSA, lSliceTimes, lFlippedMosaic); lSliceTimes := nil; //free if not result then exit; lBval := round(lCSA.bvalue); ldti1 := lCSA.DTIv1; ldti2 := lCSA.DTIv2; ldti3 := lCSA.DTIv3; if (abs(ldti1) > 0.9) and (abs(ldti2) > 0.9) and (abs(ldti3) > 0.9) then lBval := 0; //syngo MR 2004A 4VA25A CSA header reports Bval=1000 for B0 images, use vectors to detect if this is a B0 image end; function GetCSAImageHeaderInfo (lFilename: string; lStart,lLength: integer; var lMosaicSlices,lMosaicX,lMosaicY: integer; var lv1,lv2,lv3: double): boolean; var lCSA: TCSA; lSliceTimes: TSliceTimes; lFlippedMosaic: boolean; begin //lMosaicSlices := -1;//imposibble - read error result := DecodeCSA2 (lFilename, lStart,lLength, lCSA,lSliceTimes, lFlippedMosaic); lSliceTimes := nil; //free if not result then exit; lMosaicSlices := lCSA.Slices; lMosaicX := lCSA.MosaicX; lMosaicY := lCSA.MosaicY; lv1 := lCSA.SliceNormV1; lv2 := lCSA.SliceNormV2; lv3 := lCSA.SliceNormV3; //5/5/2013 end; function DecodeCSA2 (lFilename: string; lCSAImageHeaderInfoPos, lCSAImageHeaderInfoSz: integer; var lCSA: TCSA; var lSliceTimes: TSliceTimes; var lFlippedMosaic: boolean): boolean; //provided with DICOM file as well as location and size of CSA header, this code returns the Siemens CSA header information const kMaxItem = 1024; // if you only need first 3 values, set to 4 so if an item has 6 values the final ones will overwrite 4th item type TCSAtag = record name : string[64]; vm: longint; vr123: string[3]; vr4: string[1]; syngodt ,nitems,xx : longint; end; TCSAitem = record xx1, xx2_Len, xx3_77, xx4: longint; // [ x L 77 x] L is length value: string; end; var lFile : File; lVers: string; lData : array of byte; lnTag,lPos,lI,lT,lIbound: integer; lTag : TCSAtag; lItem : array [1..kMaxItem] of TCSAitem; function SafeStr2Num (lStr: string): boolean; //for some reason, many fMRI images have bvalue = 'X1_01_001 var lP,lL: integer; begin result := false; lL := length(lStr); if lL < 1 then exit; for lP := 1 to lL do if not(lStr[lP] in ['+','-','0'..'9','.','e','E']) then exit; result := true; end;//nested func SafeStr2Num function RightStr2Num (lStr: string): integer; //e.g. Siemens AcquisitionMatrixText "104p*96" -> "96" var lL: integer; lS: string; lDone: boolean; begin result := -1; lS := ''; lL := length(lStr); if lL < 1 then exit; lDone := false; while (lL >= 1) and (not lDone) do begin if (lStr[lL] in ['+','-','0'..'9','.','e','E']) then lS := lStr[lL]+lS else if lS <> '' then lDone := true; dec(lL); end; if lS = '' then exit; result := strtoint(lS); end; //nested func RightStr2Num function LeftStr2Num (lStr: string): integer; //e.g. Siemens AcquisitionMatrixText "104p*96" -> "104" var lP,lL: integer; lS: string; lDone: boolean; begin result := -1; lS := ''; lL := length(lStr); if lL < 1 then exit; lP := 1; lDone := false; while (lP <= lL) and (not lDone) do begin if (lStr[lP] in ['+','-','0'..'9','.','e','E']) then lS := lS + lStr[lP] else if lS <> '' then lDone := true; inc(lP); end; if lS = '' then exit; result := strtoint(lS); end; //nested func LeftStr2Num function freadStr(len: integer): string; var i: integer; begin if (len+lPos) >= lCSAImageHeaderInfoSz then Raise Exception.CreateFmt('csaread: corrupt file ', [lFilename]); result := ''; i := 0; while (i < len) and (lData[i+lPos] <> 0) and (lData[i+lPos] <> $20) do begin result := result + chr(lData[i+lPos]); inc(i); end; lPos := lPos + len; end; //nested func freadStr function freaduint32: longword; overload; //uint32 begin if (4+lPos) >= lCSAImageHeaderInfoSz then Raise Exception.CreateFmt('csaread: corrupt file ', [lFilename]); result := (lData[lPos+3] shl 24)+(lData[lPos+2] shl 16)+(lData[lPos+1] shl 8)+lData[lPos]; lPos := lPos + 4; end;//nested func freaduint32 function freadint32: longint; overload; //uint32 begin if (4+lPos) >= lCSAImageHeaderInfoSz then Raise Exception.CreateFmt('csaread: corrupt file ', [lFilename]); result := (lData[lPos+3] shl 24)+(lData[lPos+2] shl 16)+(lData[lPos+1] shl 8)+lData[lPos]; lPos := lPos + 4; end;//nested func freadint32 function freadTag: TCSAtag; begin result.name := freadStr(64); result.vm:= freadint32; result.vr123:= freadStr(3); result.vr4:= freadStr(1); result.syngodt := freadint32; result.nitems := freadint32; result.xx := freadint32; end;//nested func freadTag function freadItem: TCSAitem; begin result.xx1:= freadint32; result.xx2_Len:= freadint32; result.xx3_77:= freadint32; result.xx4:= freadint32; result.value := freadStr(result.xx2_len); lPos := lPos + ((4-(result.xx2_len) mod 4 )mod 4) ; end;//nested func freadItem begin //main function DecodeCSA2 lFlippedMosaic := false; result := false; lSliceTimes := nil; //clear lCSA.CustomerSeq := ''; //clear lCSA.Bvalue := -1; lCSA.PhaseDirectionPositive := -1; if (lCSAImageHeaderInfoSz < 1) then exit; if FSize(lFilename) <= (lCSAImageHeaderInfoPos+lCSAImageHeaderInfoSz) then exit; if lCSAImageHeaderInfoSz < 118 then exit; //Too short to be a CSA header - Perhaps Philips or GE is using this tag setlength(lData, lCSAImageHeaderInfoSz); lPos := 0; FileMode := fmOpenRead; AssignFile(lFile, lFilename); Reset(lFile, 1); // Now we define one record as 1 byte Seek(lFile, lCSAImageHeaderInfoPos); // Records start from 0 BlockRead(lFile, lData[0], lCSAImageHeaderInfoSz); CloseFile(lFile); lVers := freadStr(4); if lVers = 'SV10' then begin //read header lPos := lPos + 4; //skip 8 bytes of data, spm_dicom_headers refers to these as unused1 and unused2 lnTag := freaduint32; if (lnTag < 1) or (lnTag > 1024) then begin dcmMsg('Error reading CSA header'); exit; end; if (lData[lPos] <> 77) then showmsg('warning: strange CSA2 header'); lPos := lPos + 4; // skip the four bytes 77 00 00 00 //read tags for lT := 1 to lnTag do begin lTag := freadTag; if lTag.nitems > 0 then begin for lI := 1 to lTag.nitems do begin //read items if lI > kMaxItem then lIbound := kMaxItem //out of range else lIbound := lI; lItem[lIbound] := freadItem; end; //for each item if (lTag.name = 'NumberOfImagesInMosaic') then lCSA.Slices := round(strtofloat(lItem[1].value)) else if (lTag.name = 'AcquisitionMatrixText') then begin //'96p*96 -> X= 96 and Y= 96 lCSA.MosaicX := LeftStr2Num(lItem[1].value); lCSA.MosaicY := RightStr2Num(lItem[1].value); end else if (lTag.name = 'B_value') and (SafeStr2Num(lItem[1].value)) then lCSA.Bvalue := strtofloat(lItem[1].value) else if (lTag.name = 'DiffusionGradientDirection') and (SafeStr2Num(lItem[1].value)) and (SafeStr2Num(lItem[2].value)) and (SafeStr2Num(lItem[3].value)) then begin lCSA.DTIv1 := strtofloat(lItem[1].value); lCSA.DTIv2 := strtofloat(lItem[2].value); lCSA.DTIv3 := strtofloat(lItem[3].value); end else if (lTag.name = 'SliceNormalVector') and (SafeStr2Num(lItem[1].value)) and (SafeStr2Num(lItem[2].value)) and (SafeStr2Num(lItem[3].value)) then begin lCSA.SliceNormV1 := strtofloat(lItem[1].value); lCSA.SliceNormV2 := strtofloat(lItem[2].value); lCSA.SliceNormV3 := strtofloat(lItem[3].value); //fx( lCSA.SliceNormV3,1234); end else if (lTag.name = 'SliceMeasurementDuration') and (SafeStr2Num(lItem[1].value)) then begin lCSA.BandwidthPerPixelPhaseEncode := strtofloat(lItem[1].value); {$IFDEF verbose} msg('SliceMeasurementDuration: '+floattostr(lCSA.BandwidthPerPixelPhaseEncode)); {$ENDIF} end else if (lTag.name = 'BandwidthPerPixelPhaseEncode') and (SafeStr2Num(lItem[1].value)) then begin lCSA.BandwidthPerPixelPhaseEncode := strtofloat(lItem[1].value); {$IFDEF verbose} msg('BandwidthPerPixelPhaseEncode: '+floattostr(lCSA.BandwidthPerPixelPhaseEncode)); {$ENDIF} end else if (lTag.name = 'MosaicRefAcqTimes') and (lTag.nitems > 1) and (SafeStr2Num(lItem[1].value)) then begin //showmsg(lTag.name+ '-> '+inttostr(lTag.nitems)); setlength(lSliceTimes,lTag.nitems); for lI := 1 to lTag.nitems do if SafeStr2Num(lItem[lI].value) then lSliceTimes[lI-1] := strtofloat(lItem[lI].value); end else if (lTag.name = 'ProtocolSliceNumber') and (lTag.nitems > 0) and (SafeStr2Num(lItem[1].value)) then begin if SafeStr2Num(lItem[1].value) and (strtofloat(lItem[1].value) > 0) then lFlippedMosaic := true; end else if (lTag.name = 'PhaseEncodingDirectionPositive') and (lTag.nitems > 0) and (SafeStr2Num(lItem[1].value)) then begin lCSA.PhaseDirectionPositive := round(strtofloat(lItem[1].value)); end; // else dcmmsg(lTag.name+ '-> '+inttostr(lTag.nitems)); (*if (lTag.name = 'EchoLinePosition') and (SafeStr2Num(lItem[1].value)) then begin lCSA.BandwidthPerPixelPhaseEncode := strtofloat(lItem[1].value); msg('EchoLinePosition: '+floattostr(lCSA.BandwidthPerPixelPhaseEncode)); end;*) if (SafeStr2Num(lItem[1].value)) then begin lCSA.BandwidthPerPixelPhaseEncode := strtofloat(lItem[1].value); {$IFDEF verbose} msg(lTag.name+' '+inttostr(lTag.nitems)+' '+floattostr(lCSA.BandwidthPerPixelPhaseEncode)); {$ENDIF} end; //if true then begin //(lTag.name = 'sSliceArray.ucMode') then begin // showmsg(lTag.name+'xxxxxxxxxx'+lItem[1].value); // end; ; end;//at least one item end; //for each tag result := true; //showmsg('Success DecodeCSA2'); end else begin dcmMsg('CSAread Warning: '+ lFilename +' at byte '+inttostr(lCSAImageHeaderInfoPos)+' reports version "'+lVers+'": only "SV10" format is supported: image is either corruprted, very old or new. See if a new version of this software is available.'); end; //Showmsg('CSA done, final tag '+lTag.name+' CSA started at '+inttostr(lCSAImageHeaderInfoPos)+' CSA length of '+inttostr(lCSAImageHeaderInfoSz)+' formal CSA ended at @ '+inttostr(lPos)); lData := nil; end;// func DecodeCSA2 function GetCSASeriesHeaderInfo (lFilename: string; lStart,lLength, lnSlices: integer; var lSliceOrder: integer): string; var lData: array of byte; lFile : File; function str2str (lStr: string): string; var lPos,lOK, lStrLen,lDataLen: integer; lS: string; begin result := ''; //is failure lStrLen := length(lStr); lDataLen := lLength-lStrLen-1; //-1 since data must be at least 1 byte lPos := 1; lOK := 0; while lPos < lDataLen do begin lOK := 0; while (chr(lData[lPos+lOK]) = lStr[lOK+1]) do begin inc(lOK); if (lOK = lStrLen) then begin lS := '0'; lPos := lPos + lOK + 1; while (lPos <= lLength) and (lData[lPos] <> 10) and (lData[lPos] <> ord('"')) do begin // end of line is 0x0A = 10 if (lData[lPos] <> ord('\')) and (lData[lPos] <> ord('/')) then result := result + chr(lData[lPos]); inc(lPos); end; //while not end of line exit; end; //if whole string matches end; //while character matches lPos:= lPos + lOK + 1; end; //while pos in less than data length end; function strValue (lStr: string): integer; //returns 4 for "sSliceArray.ucMode = 0x4" (0A ends line) var lPos,lOK, lStrLen,lDataLen: integer; lS: string; begin result := 0; //is failure lStrLen := length(lStr); lDataLen := lLength-lStrLen-1; //-1 since data must be at least 1 byte lPos := 1; lOK := 0; while lPos < lDataLen do begin lOK := 0; while (chr(lData[lPos+lOK]) = lStr[lOK+1]) do begin inc(lOK); if (lOK = lStrLen) then begin lS := '0'; lPos := lPos + lOK + 1; while (lPos <= lLength) and (lData[lPos] <> 10) do begin // end of line is 0x0A = 10 if chr(lData[lPos]) in ['0'..'9'] then lS := lS + chr(lData[lPos]); inc(lPos); end; //while not end of line result := strtoint(lS); //https://wiki.cimec.unitn.it/tiki-index.php?page=MRIBOLDfMRI //http://cbs.fas.harvard.edu/node/559#slice_order case result of 1: result := kNIFTI_SLICE_SEQ_INC; 2 : result := kNIFTI_SLICE_SEQ_DEC; 4: begin if odd(lnSlices) then result := kNIFTI_SLICE_ALT_INC else begin dcmMsg(' Warning: Siemens interleaved acquisition with an even number of slices. Assume even slices acquired PRIOR to odd slices. https://wiki.cimec.unitn.it/tiki-index.php?page=MRIBOLDfMRI'); result := kNIFTI_SLICE_ALT_INC2; end; end; else begin dcmMsg('Warning: Unknown Siemens slice order '+inttostr(result)); result := 0; end; end; //case exit; end; //if whole string matches end; //while character matches lPos:= lPos + lOK + 1; end; //while pos in less than data length end; begin result := ''; lSliceOrder := 0; if (lLength < 0) then exit; SetLength(lData,lLength); FileMode := fmOpenRead; AssignFile(lFile, lFilename); Reset(lFile, 1); // Now we define one record as 1 byte Seek(lFile, lStart); // Records start from 0 BlockRead(lFile, lData[0], lLength); CloseFile(lFile); lSliceOrder := strValue('sSliceArray.ucMode'); result := str2str ('CustomerSeq'); //dcmMsg('*********Got it '+inttostr(lSliceOrder)); lData := nil; end; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/nii_4dto3d.pas0000755000175000017500000004005112306707452020203 0ustar mihmihunit nii_4dto3d; {$H+} interface uses {$IFDEF FPC}gzio2,{$ENDIF} SysUtils,define_types,dicomtypes,niftiutil,prefs,nii_orient,nii_crop, nifti_types; //function Convert4Dto3D(var lHdrName: string; var lHdr: TNIFTIhdr; lByteSwap,lSPM2in,lSingleNIIFile,lGZ :boolean ): boolean; //function Clip4D(var lHdrName: string; var lHdr: TNIFTIhdr; lByteSwap,lSPM2in,lSingleNIIFile,lGZ,lOverwrite: boolean; lStartIn,lEndIn: integer ): string; function ModifyAnalyze(lFilename: string; lPrefs: TPrefs): boolean; function Clip4D(var lHdrName: string; var lHdr: TNIFTIhdr;lOverwrite: boolean; lPrefs: TPrefs; lStartIn,lEndIn: integer): string; //function Reorder4D(var lHdrName: string; var lHdr: TNIFTIhdr; lByteSwap,lSPM2in,lSingleNIIFile,lGZ,lOverwrite: boolean): boolean; function Reorder4D(var lHdrName: string; var lHdr: TNIFTIhdr; lOverwrite: boolean; lPrefs: TPrefs): boolean; implementation uses dialogsx,dialogs_msg; function ModifyAnalyze(lFilename: string; lPrefs: TPrefs): boolean; var lExt,lOutname: string; lHdr: TNIFTIhdr; lFormat,lStartIn,lEndIn, lMinStartIn: integer; lReorder: boolean; lPref: TPrefs; lO: TNIIOpts; begin lPref := lPrefs; result := false; lStartIn := 0; lEndIn := 0; lReorder := false; lExt := UpCaseExt(lFilename); if not NIFTIhdr_LoadHdr (lFilename, lHdr, lO) then begin dcmMsg('Unable to read as NifTI/Analyze' + lFilename); exit; end; if lPrefs.AutoCrop then begin dcmMsg('Autocrop NIfTI/Analyze image '+lFileName); lOutname := Reorient(lFilename,lHdr, lPrefs,false,false); if lOutname <> '' then CropNIfTI(lOutname,lPrefs); exit; end; dcmMsg('Adjusting NIfTI/Analyze image '+lFileName); if (lHdr.dim[4] > 1) then begin //if 4D input if (lPrefs.BeginClip > 0) and (lPrefs.BeginClip < lHdr.dim[4]) then begin lStartIn := lPrefs.BeginClip; dcmMsg('Warning: removing first '+inttostr(lStartIn) + ' volumes (preference: BeginClip)'); end; if (lStartIn <> lPrefs.BeginClip) then dcmMsg('Warning preference BeginClip is being ignored (not enough volumes)'); if (lPrefs.LastClip > 0) and ( (lPrefs.LastClip+ lPrefs.BeginClip) < lHdr.dim[4]) then begin lEndIn := lPrefs.LastClip; dcmMsg('Warning: removing final '+inttostr(lEndIn) + ' volumes (preference: LastClip)'); end; if (lEndIn <> lPrefs.LastClip) then dcmMsg('Warning preference LastClip is being ignored (not enough volumes)'); end;//if 4D input //next - determine output format if not lPref.ManualNiFtiConv then begin lReorder := false; end else begin //manually specify conversion parameters lFormat := GetInt('Output: 0=spm2,1=spm5,2=spm8,3=hdr4D,4=fsl,5=fsl.gz ', 0,DefaultOutputFormat (lPrefs),5); SetOutputFormat(lFormat,lPref); //: 0=SPM2,1=SPM5,2=spm8,3=4D hdr/img,4=fsl(default),5=fsl.gz (* if (lFormat <= 0) then lPref.SPM2 := true else lPref.SPM2 := false; if (lFormat <= 1) then //0,1 = hdr/img pairs lPref.singleNIIfile := false else //>1 = .nii lPref.singleNIIfile := true; if (lFormat <= 2) then //0,1,2 = 3D output lPref.fourD := false else //>2 = 4D lPref.fourD := true; if (lFormat >= 4) then lPref.GZip := true else lPref.GZip := false; *) //next - 4D images: clip ends or flip order if lHdr.dim[4] > 1 then begin //4D file if (lHdr.dim[4] > 1) and (lHdr.dim[3] > 1) then begin dcmMsg(' Enter a value of -1 to flip 3rd and 4th dimensions.'); lMinStartIn := -1; end else lMinStartIn := 0; lStartIn := GetInt('Enter volumes to remove from start ', lMinStartIn,lStartIn,lHdr.dim[4]); if lStartIn >= 0 then lEndIn := GetInt('Enter volumes to remove from end ' ,0,lEndIn,lHdr.dim[4]); if ((lStartIn < 0) or (lEndIn < 0)) and (lHdr.dim[4] > 1) and (lHdr.dim[3] > 1) then lReorder := true else lReorder := false; if lHdr.dim[4] <= (lStartIn+lEndIn) then begin dcmMsg('Clip Analyze aborted: unable to remove this many volumes.'); exit; end; end;(* else begin //not 4D file l4Dto3D := false; lStartIn := 0; lEndIn := 0; lReorder := false; end;//if 4D else *) end; //manual specification of conversion // (* if lExt = '.NII.GZ' then begin //lTempName := lFilename;//ChangeFilePrefixExt (lFileName,'x'); ExtractFileParts (lFileName, lNameWOExt,lExt); lTempName := lNameWOExt+'.nii'; Gunzip(lFileName,lTempName); //dcmMsg('Unzip '+lFilename+'->'+lTempName); lFilename := lTempName; end else //not gzip lTempName := ''; *) //Next create reordered or trimmed image in the correct format if lReorder then begin if not Reorder4D(lFileName, lHdr, false,lPref) then exit; //if not Reorder4D(lFileName, lHdr, lByteSwap,lSPM2,lSingleFile,lGZ, false) then exit; end else if (lStartIn=0) and (lEndIn= 0) then begin if not ChangeNIfTISubformat(lFileName, lHdr,lPref) then begin dcmMsg('Error changing format!'); exit; end; end else begin if Clip4D(lFileName, lHdr, false,lPref,lStartIn,lEndIn)='' then exit; end; result := true; end; function Clip4D(var lHdrName: string; var lHdr: TNIFTIhdr;lOverwrite: boolean; lPrefs: TPrefs; lStartIn,lEndIn: integer): string; var lImgBuffer: byteP; lImgOffset: integer; lOutImgName: string; lO: TNIIOpts; begin result := ''; if not NIFTIhdr_LoadImg (lHdrName, lHdr, lImgBuffer, lImgOffset,lO) then exit; dcmMsg('4D Clipping '+lHdrName); lOutImgName := ChangeFilePrefix (lHdrName,'f'); result := SaveNIfTICoreCrop (lOutImgName, lImgBuffer, lImgOffset+1,lStartIn,lEndIn, lHdr, lPrefs); Freemem(lImgBuffer); end; function Reorder4D(var lHdrName: string; var lHdr: TNIFTIhdr; lOverwrite: boolean; lPrefs: TPrefs): boolean; var lInBuffer,lOutBuffer: byteP; lImgOffset,lSliceBytes,lIn3DBytes,l4DBytes,lVol,lInPos,lOutPos,lSlice: integer; lOutImgName: string; lOutHdr : TNIFTIhdr; lO: TNIIOpts; begin result := false; if not NIFTIhdr_LoadImg (lHdrName, lHdr, lInBuffer, lImgOffset,lO) then exit; if (lHdr.dim[4] < 2) or (lHdr.dim[3] < 2) then exit; if lOverwrite then lOutImgName := lHdrName else lOutImgName := ChangeFilePrefix (lHdrName,'x'); lOutHdr := lHdr; lOutHdr.dim[3] := lHdr.dim[4]; lOutHdr.dim[4] := lHdr.dim[3]; lSliceBytes := lHdr.dim[1]*lHdr.dim[2]*(lHdr.bitpix div 8); lIn3DBytes := lSliceBytes*lHdr.dim[3]; l4DBytes := lIn3DBytes*lHdr.dim[4]; dcmMsg('Changing order of dimensions 3 and 4 of '+lHdrName); GetMem(lOutBuffer,l4DBytes+kNIIImgOffset); lOutPos := kNIIImgOffset + 1; for lVol := 1 to lOutHdr.dim[4] do begin lInPos := ((lVol-1)*lSliceBytes) + lImgOffset+1; for lSlice := 1 to lOutHdr.dim[3] do begin Move(lInBuffer^[lInPos],lOutBuffer^[lOutPos],lSliceBytes); lInPos := lInPos + lIn3DBytes; lOutPos := lOutPos + lSliceBytes; end;//for lslice end; //for lvol dcmMsg(lOutImgName); if SaveNIfTICore (lOutImgName, lOutBuffer, kNIIImgOffset+1, lOutHdr, lPrefs) = '' then begin dcmMsg('Reorder Error'); Freemem(lInBuffer); Freemem(lOutBuffer); exit; end; result := true; end; (*function Reorder4D(var lHdrName: string; var lHdr: TNIFTIhdr; lByteSwap,lSPM2in,lSingleNIIFile,lGZ,lOverwrite: boolean): boolean; var lOutHdr: TNIFTIhdr; lInName,lImgName: string; lPos,lSlice,lVol,lInVolBytes,lSliceBytes: integer; lBuffer: bytep; lGZi,lSPM2: boolean; lOutF,lInF: File; begin result := false; lGZi := lGZ; lSPM2 := lSPM2in; if lSingleNIIFIle then lSPM2 := false; if (lHdr.dim[4] < 2) or (lHdr.dim[3] < 2) then exit; lOutHdr := lHdr; lOutHdr.dim[4] := lHdr.dim[3]; lOutHdr.dim[3] := lHdr.dim[4]; lSliceBytes := lHdr.dim[1]*lHdr.dim[2]*(lHdr.bitpix div 8); lInVolBytes := lSliceBytes*lHdr.dim[3]; GetMem(lBuffer,lSliceBytes); if UpCaseExt(lHdrName) ='.HDR' then begin if lOverwrite then deletefile(lHdrName); lInName := changefileext(lHdrName,'.img') end else begin lOutHdr.vox_offset := 352; lInName := lHdrName; end; if not fileexists(lInName) then begin dcmMsg('4Dclip Error: Unable to find '+lInName); exit; end; if FSize (lInName) < ( (lInVolBytes*lHdr.dim[4])+round(lHdr.vox_offset)) then begin dcmMsg('4Dclip Error: File smaller than expected (can not convert compressed) '+lInName); exit; end; dcmMsg('Reordering image'); if not lSingleNiiFile then begin lHdrName := changefileext(lHdrName,'.hdr'); lImgName := changefileext(lHdrName,'.img'); lGZi := false; end else begin lHdrName := changefileext(lHdrName,'.nii'); lImgName := changefileext(lHdrName,'.nii'); end; if lOverwrite then begin renamefile(lInName,changefileext(lInName,'.tmp')); lInName := changefileext(lInName,'.tmp'); end else begin lHdrName := ChangeFilePrefixExt (lHdrName,'x'); lImgName := ChangeFilePrefixExt (lImgName,'x'); dcmMsg('saving as '+lHdrName); end; AssignFile(lInF, lInName); Reset(lInF,1); Seek(lInF,round(lHdr.vox_offset)); SaveHdr (lHdrName,lOutHdr,lByteSwap{ false},lSPM2); AssignFile(lOutF, lImgName); if lSingleNIIFile then begin Reset(lOutF,1); Seek(lOutF,352); end else Rewrite(lOutF,1); for lVol := 1 to lOutHdr.dim[4] do begin lPos := ((lVol-1)*lSliceBytes) + round(lHdr.vox_offset); for lSlice := 1 to lOutHdr.dim[3] do begin Filemode := 0; //ReadONly seek(lInF,lPos); BlockRead(lInF, lBuffer^, lSliceBytes); Filemode := 2; BlockWrite(lOutF, lBuffer^, lSliceBytes); lPos := lPos + lInVolBytes; end;//for lslice end; //for lvol CloseFile(lInF); CloseFile(lOutF); Freemem(lBuffer); if lOverwrite then DeleteFile(lInName); if lGZi then GZipFile(lImgName,lImgName+'.gz',true); result := true; end; *) (*function Clip4D(var lHdrName: string; var lHdr: TNIFTIhdr; lByteSwap,lSPM2in, lSingleNIIFile,lGZ,lOverwrite: boolean; lStartIn,lEndIn: integer ): string; var lOutHdr: TNIFTIhdr; lInName,lImgName: string; lVol,lVolBytes,lStart,lEnd: integer; lBuffer: bytep; lGZi,lSPM2 : boolean; lOutF,lInF: File; begin result := ''; lGZi := lGZ; lSPM2 := lSPM2in; if lSingleNIIFIle then lSPM2 := false; lStart := lStartIn; if lStart < 0 then lStart := 0; lEnd := lEndIn; if lEnd < 0 then lEnd := 0; lOutHdr := lHdr; lOutHdr.dim[4] := lOutHdr.dim[4]-lStart-lEnd; if lOutHdr.dim[4] < 1 then exit; lVolBytes := lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3]*(lOutHdr.bitpix div 8); GetMem(lBuffer,lVolBytes); if UpCaseExt(lHdrName) ='.HDR' then begin if lOverwrite then deletefile(lHdrName); lInName := changefileext(lHdrName,'.img') end else begin lOutHdr.vox_offset := 352; lInName := lHdrName; end; if not fileexists(lInName) then begin dcmMsg('4Dclip Error: Unable to find '+lInName); exit; end; if FSize (lInName) < ( (lVolBytes*lHdr.dim[4])+round(lHdr.vox_offset)) then begin dcmMsg('4Dclip Error: File smaller than expected (can not convert compressed) '+lInName); exit; end; if (lStart > 0) or (lEnd > 0) then dcmMsg('4D clip - removing first '+inttostr(lStart)+' and last '+inttostr(lEnd) +' volumes') else dcmMsg('Formatting image'); if not lSingleNiiFile then begin lGZi := false; lHdrName := changefileext(lHdrName,'.hdr'); lImgName := changefileext(lHdrName,'.img'); end else begin lHdrName := changefileext(lHdrName,'.nii'); lImgName := changefileext(lHdrName,'.nii'); end; if lOverwrite then begin renamefile(lInName,changefileext(lInName,'.tmp')); lInName := changefileext(lInName,'.tmp'); end else begin lHdrName := ChangeFilePrefixExt (lHdrName,'x'); lImgName := ChangeFilePrefixExt (lImgName,'x'); dcmMsg('Saving clipped as '+lHdrName); end; AssignFile(lInF, lInName); Reset(lInF,1); Seek(lInF,round(lHdr.vox_offset)); SaveHdr (lHdrName,lOutHdr, lByteSwap{false},lSPM2); AssignFile(lOutF, lImgName); if lSingleNIIFile then begin Reset(lOutF,1); Seek(lOutF,352); end else Rewrite(lOutF,1); for lVol := 1 to (lHdr.dim[4]-lEnd) do begin //1st - save header Filemode := 0; //ReadONly BlockRead(lInF, lBuffer^, lVolBytes); if (lVol > lStart) then begin Filemode := 2; BlockWrite(lOutF, lBuffer^, lVolBytes); end; end; CloseFile(lInF); CloseFile(lOutF); Freemem(lBuffer); if lOverwrite then DeleteFile(lInName); if lGZi then begin lHdrName := lImgName+'.gz'; GZipFile(lImgName,lHdrName,true); end; result := lHdrName; end; function Convert4Dto3D(var lHdrName: string; var lHdr: TNIFTIhdr; lByteSwap, lSPM2in,lSingleNIIFile,lGZ: boolean ): boolean; var lOutHdr: TNIFTIhdr; lOutName,lImgName: string; lVol,lVolBytes: integer; lBuffer: bytep; lSPM2,lGZi: boolean; lOutF,lInF: File; begin result := false; lSPM2 := lSPM2in; if lSingleNIIFIle then lSPM2 := false; lGZi := lGZ; if lHdr.dim[4] < 2 then exit; lOutHdr := lHdr; lOutHdr.dim[0] := 3;//3D lOutHdr.dim[4] := 1; lVolBytes := lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3]*(lOutHdr.bitpix div 8); GetMem(lBuffer,lVolBytes); //lSingleNIIFile := true; if UpCaseExt(lHdrName) ='.HDR' then begin //lSingleNIIFile := false; lImgName := changefileext(lHdrName,'.img') end else lImgName := lHdrName; if not fileexists(lImgName) then begin dcmMsg('4D->3D Error: Unable to find '+lImgName); exit; end; if FSize (lImgName) < ( (lVolBytes*lHdr.dim[4])+round(lHdr.vox_offset)) then begin dcmMsg('4D->3D Error: File smaller than expected (can not convert compressed) '+lImgName); exit; end; //dcmMsg(inttostr(round(lHdr.vox_offset))); AssignFile(lInF, lImgName); Reset(lInF,1); Seek(lInF,round(lHdr.vox_offset)); if not lSingleNiiFile then begin lGZi := false; lHdrName := changefileext(lHdrName,'.hdr'); lImgName := changefileext(lHdrName,'.img'); end else begin lHdrName := changefileext(lHdrName,'.nii'); lImgName := changefileext(lHdrName,'.nii'); end; for lVol := 1 to lHdr.dim[4] do begin //1st - save header lOutName := AddFileNum(lVol,lHdr.dim[4],lHdrName); SaveHdr (lOutName,lOutHdr,lByteSwap {false},lSPM2); Filemode := 0; //ReadONly BlockRead(lInF, lBuffer^, lVolBytes); lOutName := AddFileNum(lVol,lHdr.dim[4],lImgName); Filemode := 2; AssignFile(lOutF, lOutName); if (lSingleNIIFile) and (not lSPM2) then begin Reset(lOutF,1); Seek(lOutF,352); end else Rewrite(lOutF,1); BlockWrite(lOutF, lBuffer^, lVolBytes); CloseFile(lOutF); if lGZi then begin GZipFile(lOutName,lOutName+'.gz',true); //DeleteFile(lOutName); end; end; CloseFile(lInF); Freemem(lBuffer); //if lDeleteOrig then begin DeleteFile(lHdrName); if not lSingleNIIFile then DeleteFile(lImgName); //end; end; *) end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/pref_form.lrs0000755000175000017500000001061012315600456020231 0ustar mihmih{ This is an automatically generated lazarus resource file } LazarusResources.Add('TPrefsForm','FORMDATA',[ 'TPF0'#10'TPrefsForm'#9'PrefsForm'#4'Left'#3#210#1#6'Height'#3'L'#1#3'Top'#3 +#176#0#5'Width'#3'X'#2#18'HorzScrollBar.Page'#3#207#1#18'VertScrollBar.Page' +#3'C'#1#13'ActiveControl'#7#9'DateCheck'#11'BorderIcons'#11#12'biSystemMenu' +#0#7'Caption'#6#11'Preferences'#12'ClientHeight'#3'L'#1#11'ClientWidth'#3'X' +#2#21'Constraints.MaxHeight'#3'L'#1#20'Constraints.MaxWidth'#3'X'#2#21'Const' +'raints.MinHeight'#3'L'#1#20'Constraints.MinWidth'#3'X'#2#8'Position'#7#15'p' +'oDesktopCenter'#10'LCLVersion'#6#8'1.0.12.0'#0#6'TLabel'#6'Label1'#4'Left'#2 +'p'#6'Height'#2#17#3'Top'#3#200#0#5'Width'#3#188#0#7'Caption'#6#29'Recursive' +' folder search depth'#11'ParentColor'#8#0#0#6'TLabel'#11'OutDirLabel'#4'Lef' +'t'#2#16#6'Height'#2#17#3'Top'#3#8#1#5'Width'#2#19#7'Caption'#6#3'c:\'#11'Pa' +'rentColor'#8#0#0#9'TGroupBox'#11'FilenameBox'#4'Left'#2#8#6'Height'#3#176#0 +#3'Top'#2#8#5'Width'#3#232#0#7'Caption'#6#15'Output Filename'#12'ClientHeigh' +'t'#3#154#0#11'ClientWidth'#3#224#0#8'TabOrder'#2#0#0#9'TCheckBox'#9'DateChe' +'ck'#4'Left'#2#22#6'Height'#2#18#3'Top'#2#8#5'Width'#2'|'#7'Caption'#6#16'Ac' +'quisition Date'#8'OnChange'#7#14'FilenameChecks'#8'TabOrder'#2#0#0#0#9'TChe' +'ckBox'#14'InputNameCheck'#4'Left'#2#22#6'Height'#2#18#3'Top'#2'!'#5'Width'#2 +'r'#7'Caption'#6#14'Input Filename'#8'OnChange'#7#14'FilenameChecks'#8'TabOr' +'der'#2#1#0#0#9'TCheckBox'#13'ProtocolCheck'#4'Left'#2#22#6'Height'#2#18#3'T' +'op'#2'9'#5'Width'#2'q'#7'Caption'#6#13'Protocol Name'#8'OnChange'#7#14'File' +'nameChecks'#8'TabOrder'#2#2#0#0#9'TCheckBox'#16'PatientNameCheck'#4'Left'#2 +#22#6'Height'#2#18#3'Top'#2'Q'#5'Width'#2'h'#7'Caption'#6#12'Patient Name'#8 +'OnChange'#7#14'FilenameChecks'#8'TabOrder'#2#3#0#0#9'TCheckBox'#11'SeriesCh' +'eck'#4'Left'#2#22#6'Height'#2#18#3'Top'#2'i'#5'Width'#3#131#0#7'Caption'#6 +#18'Acquisition Series'#8'OnChange'#7#14'FilenameChecks'#8'TabOrder'#2#4#0#0 +#0#7'TButton'#5'OKbtn'#4'Left'#3#232#1#6'Height'#2#25#3'Top'#3' '#1#5'Width' +#2'K'#25'BorderSpacing.InnerBorder'#2#4#7'Caption'#6#2'OK'#11'ModalResult'#2 +#1#8'TabOrder'#2#1#0#0#7'TButton'#9'CancelBtn'#4'Left'#3#144#1#6'Height'#2#25 +#3'Top'#3' '#1#5'Width'#2'K'#25'BorderSpacing.InnerBorder'#2#4#7'Caption'#6#6 +'Cancel'#11'ModalResult'#2#2#8'TabOrder'#2#2#0#0#9'TCheckBox'#17'NotAnonymiz' +'eCheck'#4'Left'#3#248#0#6'Height'#2#18#3'Top'#2#24#5'Width'#3#233#0#7'Capti' +'on'#6'!Save patient name in NIfTI header'#8'TabOrder'#2#3#0#0#9'TCheckBox' +#13'ReorientCheck'#4'Left'#3#248#0#6'Height'#2#18#3'Top'#2'X'#5'Width'#3'P'#1 +#7'Caption'#6'1Reorient large images to nearest orthogonal plane'#8'TabOrder' +#2#4#0#0#9'TSpinEdit'#13'RecursiveSpin'#4'Left'#2#16#6'Height'#2#16#3'Top'#3 +#200#0#5'Width'#2'M'#8'MaxValue'#2#10#8'TabOrder'#2#5#0#0#9'TComboBox'#11'Ou' +'tputCombo'#4'Left'#2#16#6'Height'#2#20#3'Top'#3#232#0#5'Width'#3'('#1#10'It' +'emHeight'#2#0#13'Items.Strings'#1#6#21'Save to source folder'#6#29'Prompt u' +'ser for output folder'#6#17'Always save to...'#0#8'OnChange'#7#17'OutputCom' +'boChange'#9'OnMouseUp'#7#18'OutputComboMouseUp'#5'Style'#7#14'csDropDownLis' +'t'#8'TabOrder'#2#6#0#0#9'TCheckBox'#13'CollapseCheck'#4'Left'#3#248#0#6'Hei' +'ght'#2#18#4'Hint'#6'_Sort images regardless of source directory. Slower, re' +'quired if series segmented across folders'#3'Top'#2'x'#5'Width'#2'y'#7'Capt' +'ion'#6#16'Collapse folders'#8'TabOrder'#2#7#0#0#9'TCheckBox'#27'Stack3DImag' +'esWithSameAcqNum'#4'Left'#3#248#0#6'Height'#2#18#4'Hint'#6'_Sort images reg' +'ardless of source directory. Slower, required if series segmented across fo' +'lders'#3'Top'#3#152#0#5'Width'#3':'#1#7'Caption'#6'+Stack 3D images with sa' +'me acquistion number'#8'TabOrder'#2#8#0#0#7'TButton'#13'TextEditorBtn'#4'Le' +'ft'#2#8#6'Height'#2#25#3'Top'#3' '#1#5'Width'#2'{'#25'BorderSpacing.InnerBo' +'rder'#2#4#7'Caption'#6#9'Text Edit'#7'OnClick'#7#18'TextEditorBtnClick'#8'T' +'abOrder'#2#9#0#0#9'TCheckBox'#16'WritePrefsOnQuit'#4'Left'#3#134#1#6'Height' +#2#18#3'Top'#2'x'#5'Width'#3#138#0#7'Caption'#6#19'Write prefs on quit'#7'Ch' +'ecked'#9#5'State'#7#9'cbChecked'#8'TabOrder'#2#10#7'Visible'#8#0#0#9'TCheck' +'Box'#14'TxtReportCheck'#4'Left'#3#248#0#6'Height'#2#18#3'Top'#2'8'#5'Width' +#3#26#1#7'Caption'#6'+Save text report (scan and patient details)'#8'TabOrde' +'r'#2#11#0#0#0 ]); mricron-0.20140804.1~dfsg.1.orig/dcm2nii/nii_reslice.pas0000755000175000017500000004140012306712660020524 0ustar mihmihunit nii_reslice; interface {$H+} uses niftiutil,define_types,sysutils,dicomtypes,prefs,dialogs_msg, nifti_types; //function ResliceImgNIfTI (lTargetImgName,lSrcImgName,lOutputName: string): boolean; function Reslice2Targ (lSrcName,lTargetName,lDestName: string; lPrefs: TPrefs):string; implementation uses GraphicsMathLibrary, dialogsx; function Hdr2Mat (lHdr: TNIFTIhdr): TMatrix; begin Result := Matrix3D ( lHdr.srow_x[0],lHdr.srow_x[1],lHdr.srow_x[2],lHdr.srow_x[3], // 3D "graphics" matrix lHdr.srow_y[0],lHdr.srow_y[1],lHdr.srow_y[2],lHdr.srow_y[3], // 3D "graphics" matrix lHdr.srow_z[0],lHdr.srow_z[1],lHdr.srow_z[2],lHdr.srow_z[3], // 3D "graphics" matrix 0,0,0,1); end; (*procedure ReportMatrix (lM:TMatrix); const kCR = chr (13); begin showmessage(RealToStr(lM.matrix[1,1],6)+','+RealToStr(lM.matrix[1,2],6)+','+RealToStr(lM.matrix[1,3],6)+','+RealToStr(lM.matrix[1,4],6)+kCR+ RealToStr(lM.matrix[2,1],6)+','+RealToStr(lM.matrix[2,2],6)+','+RealToStr(lM.matrix[2,3],6)+','+RealToStr(lM.matrix[2,4],6)+kCR+ RealToStr(lM.matrix[3,1],6)+','+RealToStr(lM.matrix[3,2],6)+','+RealToStr(lM.matrix[3,3],6)+','+RealToStr(lM.matrix[3,4],6)+kCR +RealToStr(lM.matrix[4,1],6)+','+RealToStr(lM.matrix[4,2],6)+','+RealToStr(lM.matrix[4,3],6)+','+RealToStr(lM.matrix[4,4],6) ); end; *) (* procedure SPMmat(var lDestMat: TMatrix); //SPM matrices are indexed from 1 //This function is only useful for direct comparisons with SPM var lTemp,lVS: TMatrix; begin lVS := Matrix3D (1,0,0,-1, 0,1,0,-1, 0,0,1,-1, 0,0,0,1);//VoxelShift lTemp := lDestMat; lDestMat := MultiplyMatrices(lTemp,lVS); end;*) procedure Coord(var lV: TVector; var lMat: TMatrix); //transform X Y Z by matrix var lXi,lYi,lZi: single; begin lXi := lV.x; lYi := lV.y; lZi := lV.z; lV.x := (lXi*lMat.matrix[1][1]+lYi*lMat.matrix[1][2]+lZi*lMat.matrix[1][3]+lMat.matrix[1][4]); lV.y := (lXi*lMat.matrix[2][1]+lYi*lMat.matrix[2][2]+lZi*lMat.matrix[2][3]+lMat.matrix[2][4]); lV.z := (lXi*lMat.matrix[3][1]+lYi*lMat.matrix[3][2]+lZi*lMat.matrix[3][3]+lMat.matrix[3][4]); end; procedure Transposemat(var lMat: TMatrix); var lTemp: TMatrix; i,j: integer; begin lTemp := lMat; for i := 1 to lMat.size do for j := 1 to lMat.size do lMat.matrix[i,j] := lTemp.matrix[j,i]; end; PROCEDURE gaussj(VAR a: TMatrix);//Invert a Matrix - see Numerical Recipes VAR big,dum,pivinv: real; n,i,icol,irow,j,k,l,ll: integer; indxc,indxr,ipiv: array [1..4] of integer; BEGIN icol := 1;//not used - avoids compiler warning irow := 1;//not used - avoids compiler warning n := a.size; FOR j := 1 TO n DO BEGIN ipiv[j] := 0 END; FOR i := 1 TO n DO BEGIN big := 0.0; FOR j := 1 TO n DO BEGIN IF (ipiv[j] <> 1) THEN BEGIN FOR k := 1 TO n DO BEGIN IF (ipiv[k] = 0) THEN BEGIN IF (abs(a.matrix[j,k]) >= big) THEN BEGIN big := abs(a.matrix[j,k]); irow := j; icol := k END END ELSE IF (ipiv[k] > 1) THEN BEGIN writeln('pause 1 in GAUSSJ - singular matrix'); readln END END END END; ipiv[icol] := ipiv[icol]+1; IF (irow <> icol) THEN BEGIN FOR l := 1 TO n DO BEGIN dum := a.matrix[irow,l]; a.matrix[irow,l] := a.matrix[icol,l]; a.matrix[icol,l] := dum END; END; indxr[i] := irow; indxc[i] := icol; IF (a.matrix[icol,icol] = 0.0) THEN BEGIN dcmMsg('pause 2 in GAUSSJ - singular matrix'); exit; END; pivinv := 1.0/a.matrix[icol,icol]; a.matrix[icol,icol] := 1.0; FOR l := 1 TO n DO BEGIN a.matrix[icol,l] := a.matrix[icol,l]*pivinv END; FOR ll := 1 TO n DO BEGIN IF (ll <> icol) THEN BEGIN dum := a.matrix[ll,icol]; a.matrix[ll,icol] := 0.0; FOR l := 1 TO n DO BEGIN a.matrix[ll,l] := a.matrix[ll,l]-a.matrix[icol,l]*dum END; END END END; FOR l := n DOWNTO 1 DO BEGIN IF (indxr[l] <> indxc[l]) THEN BEGIN FOR k := 1 TO n DO BEGIN dum := a.matrix[k,indxr[l]]; a.matrix[k,indxr[l]] := a.matrix[k,indxc[l]]; a.matrix[k,indxc[l]] := dum END END END END; procedure SubVec (var lVx: TVector; lV0: TVector); begin lVx.x := lVx.x - lV0.x; lVx.y := lVx.y - lV0.y; lVx.z := lVx.z - lV0.z; end; function Voxel2Voxel (var lDestHdr,lSrcHdr: TNIFTIhdr): TMatrix; //returns matrix for transforming voxels from one image to the other image //results are in VOXELS not mm var lV0,lVx,lVy,lVz: TVector; lDestMat,lSrcMatInv,lSrcMat: TMatrix; begin //Step 1 - compute source coordinates in mm for 4 voxels //the first vector is at 0,0,0, with the //subsequent voxels being left, up or anterior lDestMat := Hdr2Mat(lDestHdr); //SPMmat(lDestMat); lV0 := Vector3D (0,0,0); lVx := Vector3D (1,0,0); lVy := Vector3D (0,1,0); lVz := Vector3D (0,0,1); Coord(lV0,lDestMat); Coord(lVx,lDestMat); Coord(lVy,lDestMat); Coord(lVz,lDestMat); lSrcMat := Hdr2Mat(lSrcHdr); //SPMmat(lSrcMat); lSrcMatInv := lSrcMat; gaussj(lSrcMatInv); //the vectors should be rows not columns.... //therefore we transpose the matrix Transposemat(lSrcMatInv); //the 'transform' multiplies the vector by the matrix lV0 := Transform (lV0,lSrcMatInv); lVx := Transform (lVx,lSrcMatInv); lVy := Transform (lVy,lSrcMatInv); lVz := Transform (lVz,lSrcMatInv); //subtract each vector from the origin // this reveals the voxel-space influence for each dimension SubVec(lVx,lV0); SubVec(lVy,lV0); SubVec(lVz,lV0); result := Matrix3D(lVx.x,lVy.x,lVz.x,lV0.x, lVx.y,lVy.y,lVz.y,lV0.y, lVx.z,lVy.z,lVz.z,lV0.z, 0,0,0,1); end; procedure CopyHdrMat(var lTarg,lDest: TNIfTIHdr); //destination has dimensions and rotations of destination var lI: integer; begin //destination will have dimensions of target lDest.dim[0] := 3; //3D for lI := 1 to 3 do lDest.dim[lI] := lTarg.dim[lI]; lDest.dim[4] := 1; //3D //destination will have pixdim of target for lI := 0 to 7 do lDest.pixdim[lI] := lTarg.pixdim[lI]; lDest.xyzt_units := lTarg.xyzt_units; //e.g. mm and sec lDest.qform_code := lTarg.qform_code; lDest.sform_code := lTarg.sform_code; lDest.quatern_b := lTarg.quatern_b; lDest.quatern_c := lTarg.quatern_c; lDest.quatern_d := lTarg.quatern_d; lDest.qoffset_x := lTarg.qoffset_x; lDest.qoffset_y := lTarg.qoffset_y; lDest.qoffset_z := lTarg.qoffset_z; for lI := 0 to 3 do begin lDest.srow_x[lI] := lTarg.srow_x[lI]; lDest.srow_y[lI] := lTarg.srow_y[lI]; lDest.srow_z[lI] := lTarg.srow_z[lI]; end; end; function Reslice2Targ (lSrcName,lTargetName,lDestName: string; lPrefs: TPrefs):string; var lPos,lXYs,lXYZs,lXs,lYs,lZs,lXi,lYi,lZi,lX,lY,lZ, lXo,lYo,lZo,lMinY,lMinZ,lMaxY,lMaxZ,lSrcOffset,lBPP,lXYZ: integer; lXrM1,lYrM1,lZrM1,lXreal,lYreal,lZreal, lZx,lZy,lZz,lYx,lYy,lYz, lInMinX,lInMinY,lInMinZ, lOutMinX,lOutMinY,lOutMinZ: single; lXx,lXy,lXz: Singlep0; l32fs,l32f : SingleP; l32is,l32i : LongIntP; l16is,l16i : SmallIntP; l8i,l8is,lSrcBuffer,lBuffUnaligned,lBuffAligned: bytep; lMat: TMatrix; lTargHdr,lSrcHdr,lDestHdr: TNIFTIhdr; lS,lT: TNIIOpts; begin result := ''; if not NIFTIhdr_LoadHdr (lSrcname, lSrcHdr, lS) then exit; if not NIFTIhdr_LoadHdr (lTargetName, lTargHdr, lT) then exit; case lSrcHdr.datatype of kDT_UNSIGNED_CHAR : lBPP := 1; kDT_SIGNED_SHORT: lBPP := 2; kDT_SIGNED_INT:lBPP := 4; kDT_FLOAT: lBPP := 4; else begin dcmMsg('NII reslice error: datatype not supported.'); exit; end; end; //case lMat := Voxel2Voxel (lTargHdr,lSrcHdr); lDestHdr := lSrcHdr; //destination has the comments and voxel BPP of source CopyHdrMat(lTargHdr,lDestHdr);//destination has dimensions and rotations of destination lXs := lSrcHdr.Dim[1]; lYs := lSrcHdr.Dim[2]; lZs := lSrcHdr.Dim[3]; lXYs:=lXs*lYs; //slicesz lXYZs := lXYs*lZs; lX := lDestHdr.Dim[1]; lY := lDestHdr.Dim[2]; lZ := lDestHdr.Dim[3]; lDestHdr.Dim[4] := 1; //load dataset if not NIFTIhdr_LoadImg (lSrcName, lSrcHdr, lSrcBuffer, lSrcOffset,lS) then exit; l8is := (@lSrcBuffer^[lSrcOffset+1]); GetMem(lBuffUnaligned ,(lBPP*lX*lY*lZ) + 16+kNIIImgOffset); {$IFDEF FPC} lBuffAligned := Align(lBuffUnaligned,16); // not commented - check this {$ELSE} lBuffAligned := ByteP($fffffff0 and (integer(lBuffUnaligned)+15)); {$ENDIF} lPos := 1; case lSrcHdr.datatype of kDT_UNSIGNED_CHAR : l8i := @lBuffAligned^[kNIIImgOffset+lPos]; kDT_SIGNED_SHORT: l16i := SmallIntP(@lBuffAligned^[kNIIImgOffset+lPos] ); kDT_SIGNED_INT:l32i := LongIntP(@lBuffAligned^[kNIIImgOffset+lPos] ); kDT_FLOAT: l32f := SingleP(@lBuffAligned^[kNIIImgOffset+lPos] ); end; //case case lSrcHdr.datatype of //kDT_UNSIGNED_CHAR : l8is := l8is; kDT_SIGNED_SHORT: l16is := SmallIntP(l8is ); kDT_SIGNED_INT:l32is := LongIntP(l8is ); kDT_FLOAT: l32fs := SingleP(l8is ); end; //case //next clear image case lSrcHdr.datatype of kDT_UNSIGNED_CHAR : for lPos := 1 to (lX*lY*lZ) do l8i^[lPos] := 0; kDT_SIGNED_SHORT: for lPos := 1 to (lX*lY*lZ) do l16i^[lPos] := 0; kDT_SIGNED_INT:for lPos := 1 to (lX*lY*lZ) do l32i^[lPos] := 0; kDT_FLOAT: for lPos := 1 to (lX*lY*lZ) do l32f^[lPos] := 0; end; //case //now we can apply the transforms... //build lookup table - speed up inner loop getmem(lXx, lX*sizeof(single)); getmem(lXy, lX*sizeof(single)); getmem(lXz, lX*sizeof(single)); for lXi := 0 to (lX-1) do begin lXx^[lXi] := lXi*lMat.matrix[1][1]; lXy^[lXi] := lXi*lMat.matrix[2][1]; lXz^[lXi] := lXi*lMat.matrix[3][1]; end; //compute trilinear interpolation lPos := 0; for lZi := 0 to (lZ-1) do begin //these values are the same for all voxels in the slice // compute once per slice lZx := lZi*lMat.matrix[1][3]; lZy := lZi*lMat.matrix[2][3]; lZz := lZi*lMat.matrix[3][3]; for lYi := 0 to (lY-1) do begin //these values change once per row // compute once per row lYx := lYi*lMat.matrix[1][2]; lYy := lYi*lMat.matrix[2][2]; lYz := lYi*lMat.matrix[3][2]; for lXi := 0 to (lX-1) do begin //compute each column inc(lPos); lXreal := (lXx^[lXi]+lYx+lZx+lMat.matrix[1][4]); lYreal := (lXy^[lXi]+lYy+lZy+lMat.matrix[2][4]); lZreal := (lXz^[lXi]+lYz+lZz+lMat.matrix[3][4]); //need to test Xreal as -0.01 truncates to zero if (lXreal >= 0) and (lYreal >= 0{1}) and (lZreal >= 0{1}) and (lXreal < (lXs -1)) and (lYreal < (lYs -1) ) and (lZreal < (lZs -1)) then begin //compute the contribution for each of the 8 source voxels //nearest to the target lXo := trunc(lXreal); lYo := trunc(lYreal); lZo := trunc(lZreal); lXreal := lXreal-lXo; lYreal := lYreal-lYo; lZreal := lZreal-lZo; lXrM1 := 1-lXreal; lYrM1 := 1-lYreal; lZrM1 := 1-lZreal; lMinY := lYo*lXs; lMinZ := lZo*lXYs; lMaxY := lMinY+lXs; lMaxZ := lMinZ+lXYs; inc(lXo);//images incremented from 1 not 0 case lSrcHdr.datatype of kDT_UNSIGNED_CHAR : begin// l8is := l8is; l8i^[lPos] := round ( {all min} ( (lXrM1*lYrM1*lZrM1)*l8is^[lXo+lMinY+lMinZ]) {x+1}+((lXreal*lYrM1*lZrM1)*l8is^[lXo+1+lMinY+lMinZ]) {y+1}+((lXrM1*lYreal*lZrM1)*l8is^[lXo+lMaxY+lMinZ]) {z+1}+((lXrM1*lYrM1*lZreal)*l8is^[lXo+lMinY+lMaxZ]) {x+1,y+1}+((lXreal*lYreal*lZrM1)*l8is^[lXo+1+lMaxY+lMinZ]) {x+1,z+1}+((lXreal*lYrM1*lZreal)*l8is^[lXo+1+lMinY+lMaxZ]) {y+1,z+1}+((lXrM1*lYreal*lZreal)*l8is^[lXo+lMaxY+lMaxZ]) {x+1,y+1,z+1}+((lXreal*lYreal*lZreal)*l8is^[lXo+1+lMaxY+lMaxZ]) ); end; kDT_SIGNED_SHORT: begin l16i^[lPos] := round ( {all min} ( (lXrM1*lYrM1*lZrM1)*l16is^[lXo+lMinY+lMinZ]) {x+1}+((lXreal*lYrM1*lZrM1)*l16is^[lXo+1+lMinY+lMinZ]) {y+1}+((lXrM1*lYreal*lZrM1)*l16is^[lXo+lMaxY+lMinZ]) {z+1}+((lXrM1*lYrM1*lZreal)*l16is^[lXo+lMinY+lMaxZ]) {x+1,y+1}+((lXreal*lYreal*lZrM1)*l16is^[lXo+1+lMaxY+lMinZ]) {x+1,z+1}+((lXreal*lYrM1*lZreal)*l16is^[lXo+1+lMinY+lMaxZ]) {y+1,z+1}+((lXrM1*lYreal*lZreal)*l16is^[lXo+lMaxY+lMaxZ]) {x+1,y+1,z+1}+((lXreal*lYreal*lZreal)*l16is^[lXo+1+lMaxY+lMaxZ]) ); end; kDT_SIGNED_INT:begin l32i^[lPos] := round ( {all min} ( (lXrM1*lYrM1*lZrM1)*l32is^[lXo+lMinY+lMinZ]) {x+1}+((lXreal*lYrM1*lZrM1)*l32is^[lXo+1+lMinY+lMinZ]) {y+1}+((lXrM1*lYreal*lZrM1)*l32is^[lXo+lMaxY+lMinZ]) {z+1}+((lXrM1*lYrM1*lZreal)*l32is^[lXo+lMinY+lMaxZ]) {x+1,y+1}+((lXreal*lYreal*lZrM1)*l32is^[lXo+1+lMaxY+lMinZ]) {x+1,z+1}+((lXreal*lYrM1*lZreal)*l32is^[lXo+1+lMinY+lMaxZ]) {y+1,z+1}+((lXrM1*lYreal*lZreal)*l32is^[lXo+lMaxY+lMaxZ]) {x+1,y+1,z+1}+((lXreal*lYreal*lZreal)*l32is^[lXo+1+lMaxY+lMaxZ]) ); end; kDT_FLOAT: begin //note - we do not round results - all intensities might be frational... l32f^[lPos] := ( {all min} ( (lXrM1*lYrM1*lZrM1)*l32fs^[lXo+lMinY+lMinZ]) {x+1}+((lXreal*lYrM1*lZrM1)*l32fs^[lXo+1+lMinY+lMinZ]) {y+1}+((lXrM1*lYreal*lZrM1)*l32fs^[lXo+lMaxY+lMinZ]) {z+1}+((lXrM1*lYrM1*lZreal)*l32fs^[lXo+lMinY+lMaxZ]) {x+1,y+1}+((lXreal*lYreal*lZrM1)*l32fs^[lXo+1+lMaxY+lMinZ]) {x+1,z+1}+((lXreal*lYrM1*lZreal)*l32fs^[lXo+1+lMinY+lMaxZ]) {y+1,z+1}+((lXrM1*lYreal*lZreal)*l32fs^[lXo+lMaxY+lMaxZ]) {x+1,y+1,z+1}+((lXreal*lYreal*lZreal)*l32fs^[lXo+1+lMaxY+lMaxZ]) ); end; end; //case end; //if voxel is in source image's bounding box end;//z end;//y end;//z //release lookup tables freemem(lXx); freemem(lXy); freemem(lXz); //check to see if image is empty... lPos := 1; case lSrcHdr.datatype of kDT_UNSIGNED_CHAR : while (lPos <= (lX*lY*lZ)) and (l8i^[lPos] = 0) do inc(lPos); kDT_SIGNED_SHORT: while (lPos <= (lX*lY*lZ)) and (l16i^[lPos] = 0) do inc(lPos); kDT_SIGNED_INT:while (lPos <= (lX*lY*lZ)) and (l32i^[lPos] = 0) do inc(lPos); kDT_FLOAT: while (lPos <= (lX*lY*lZ)) and (l32f^[lPos] = 0) do inc(lPos); end; //case if lPos <= (lX*lY*lZ) then begin //image not empty result := SaveNIfTICore (lDestName, lBuffAligned, kNIIImgOffset+1, lDestHdr, lPrefs); end else begin dcmMsg('no voxels in output'); end; Freemem(lBuffUnaligned); Freemem(lSrcBuffer); end; (*function ResliceImgNIfTI (lTargetImgName,lSrcImgName,lOutputName: string): boolean; label 666; var lReslice : boolean; lDestHdr,lSrcHdr: TMRIcroHdr; lSrcMat,lDestMat,lSrcMatINv,lDestMatInv,lMat: TMatrix; lOffX,lOffY,lOffZ: single; D: double; begin result := false; if not fileexists(lTargetImgName) then exit; if not fileexists(lSrcImgName) then exit; ImgForm.CloseImagesClick(nil); lReslice := gBGImg.ResliceOnLoad; gBGImg.ResliceOnLoad := false; //if not HdrForm.OpenAndDisplayHdr(lTargetImgName,lDestHdr) then goto 666; if not NIFTIhdr_LoadHdr(lTargetImgName, lDestHdr) then goto 666; if not NIFTIhdr_LoadHdr(lSrcImgName, lSrcHdr) then goto 666; if not ImgForm.OpenAndDisplayImg(lSrcImgName,false) then exit; if not Qx(lDestHdr,lSrcHdr,lOutputName) then goto 666; result := true; 666: if not result then showmessage('Error applying transform '+lSrcImgName+'->'+lTargetImgName); gBGImg.ResliceOnLoad := lReslice; end; *) end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/sortdicom.pas0000755000175000017500000005141212314604162020242 0ustar mihmihunit sortdicom; {$H+} {$Include ..\common\isgui.inc} interface uses SysUtils,define_types,classes,dicom,dicomtypes,convert,dicomfast,prefs,userdir,dialogs_msg; function LoadFileList (var lInFilename, lOutDirname: string; var lPrefs: TPrefs):boolean; function LoadParamFileList (var lInFilename, lOutDirname: string; var lPrefs: TPrefs; lParamNum: integer): boolean; implementation uses dialogsx; function IsRepeat (var lD1,lD2: DicomData) : boolean; begin if (lD1.ImageNum = lD2.ImageNum) and (lD1.AcquNum = lD2.AcquNum) and (lD1.SeriesNum = lD2.SeriesNum) and (lD1.DateTime = lD2.DateTime) then result := true else result := false; end; function IsEqualDT (lI1,lI2: TDateTime; var l1LessThan2: boolean): boolean; begin if lI1 = lI2 then result := true else result := false; if lI1 < lI2 then l1LessThan2 := true else l1LessThan2 := false; end; function IsEqual (lI1,lI2: integer; var l1LessThan2: boolean): boolean; begin if lI1 = lI2 then result := true else result := false; if lI1 < lI2 then l1LessThan2 := true else l1LessThan2 := false; end; function D1LessThanD2 (var lD1,lD2: DicomData) : boolean; begin if not IsEqualDT (lD1.DateTime, lD2.DateTime, result) then exit; //only get here if lD1.DataTime = lD2.DateTime if not IsEqual (lD1.SeriesNum, lD2.SeriesNum, result) then exit; //only get here if lD1.SeriesNum = lD2.SeriesNum if not IsEqual (lD1.AcquNum, lD2.AcquNum, result) then exit; //only get here if lD1.AcquNum = lD2.AcquNum if not IsEqual (lD1.ImageNum, lD2.ImageNum, result) then exit; //only get here if lD1.ImageNum = lD2.ImageNum end; procedure ReportError (l,i: integer; var lDICOMra: TDICOMrap); begin //Msg('Error: these files have the same index '+ lDICOMra^[lPositionRA^[l]].Filename+' = '+lDICOMra^[lPositionRA^[i]].Filename); dcmMsg('Error: these files have the same index '+ DICOMstr(l,lDICOMra)+' = '+DICOMstr(i,lDICOMra)); end; procedure ShellSortDCM (var Items: integer; var lDICOMra: TDICOMrap; var lRepeatedValues: boolean); //Shell sort /- see 'Numerical Recipes in C' for similar sorts: less memory intensive than recursive quicksort label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var inputItems,n,t, nn, m, lognb2, l, k, j, i: longint; lPositionRA,lPositionRA2: LongintP; lTempDICOMra: TDICOMrap; begin inputItems := Items; lRepeatedValues := false; if Items < 2 then exit; Getmem(lPositionRA,Items*sizeof(LongInt)); for i := 1 to items do lPositionRA^[i] := i; n := (Items ); lognb2 := trunc(ln(n) * aln2i + tiny); m := Items; for nn := 1 to lognb2 do begin m := m div 2; k := Items - m; for j := 1 to k do begin i := j; 555: l := i + m; if //identical refs {(lDICOMra^[lPositionRA^[l]].ImageNum = lDICOMra^[lPositionRA^[i]].ImageNum) and (lDICOMra^[lPositionRA^[l]].AcquNum = lDICOMra^[lPositionRA^[i]].AcquNum) and (lDICOMra^[lPositionRA^[l]].SeriesNum = lDICOMra^[lPositionRA^[i]].SeriesNum) and (lDICOMra^[lPositionRA^[l]].DateTime = lDICOMra^[lPositionRA^[i]].DateTime)} IsRepeat(lDICOMra^[lPositionRA^[l]], lDICOMra^[lPositionRA^[i]]) then begin lRepeatedValues := true; ReportError(lPositionRA^[l],lPositionRA^[i],lDICOMra); //Msg('Error: these files have the same index '+ lDICOMra^[lPositionRA^[l]].Filename+' = '+lDICOMra^[lPositionRA^[i]].Filename); end else if D1LessThanD2 (lDICOMra^[lPositionRA^[l]],lDICOMra^[lPositionRA^[i]]) { (lDICOMra^[lPositionRA^[l]].DateTime < lDICOMra^[lPositionRA^[i]].DateTime) or ((lDICOMra^[lPositionRA^[l]].DateTime = lDICOMra^[lPositionRA^[i]].DateTime) and (lDICOMra^[lPositionRA^[l]].SeriesNum < lDICOMra^[lPositionRA^[i]].SeriesNum)) or ((lDICOMra^[lPositionRA^[l]].DateTime = lDICOMra^[lPositionRA^[i]].DateTime) and (lDICOMra^[lPositionRA^[l]].SeriesNum = lDICOMra^[lPositionRA^[i]].SeriesNum) and (lDICOMra^[lPositionRA^[l]].AcquNum < lDICOMra^[lPositionRA^[i]].AcquNum)) or ((lDICOMra^[lPositionRA^[l]].DateTime = lDICOMra^[lPositionRA^[i]].DateTime) and (lDICOMra^[lPositionRA^[l]].SeriesNum = lDICOMra^[lPositionRA^[i]].SeriesNum) and (lDICOMra^[lPositionRA^[l]].AcquNum = lDICOMra^[lPositionRA^[i]].AcquNum) and (lDICOMra^[lPositionRA^[l]].ImageNum < lDICOMra^[lPositionRA^[i]].ImageNum)) } then begin //swap values for i and l t := lPositionRA^[i]; lPositionRA^[i] := lPositionRA^[l]; lPositionRA^[l] := t; i := i - m; if (i >= 1) then goto 555; end end end; //next - remove any repeated values if lRepeatedValues then begin Getmem(lPositionRA2,Items*sizeof(LongInt)); k := 1; lPositionRA2^[1] := lPositionRA^[1]; for i := 2 to Items do begin if not IsRepeat(lDICOMra^[lPositionRA^[i-1]],lDICOMra^[lPositionRA^[i]]) then begin inc(k); lPositionRA2^[k] := lPositionRA^[i]; end; end; Items := k; for i := 1 to Items do lPositionRA^[i] := lPositionRA2^[i]; Freemem(lPositionRA2); end; //Next - created sorted lists based on pointers... //... a quicker way would be to return the pointers, but this is still pretty fast... //... a lower memory solution would be to swap items inside lDICOMra Getmem(lTempDICOMra,InputItems*sizeof({TDICOM}DicomData)); for I := 1 to InputItems do lTempDICOMra^[I] := lDICOMra^[I]; if InputItems <> Items then begin Freemem(lDICOMra); Getmem(lDICOMra,Items*sizeof({TDICOM}DicomData)); end; for I := 1 to Items do lDICOMra^[I] := lTempDICOMra^[lPositionRA^[I]]; Freemem(lTempDICOMra); //finally, cleanup Freemem(lPositionRA); end; //ShellSortDCM const kTolerance = 0.0000095; //assume files are from different series if their orientation differs by more than this value //unfortunately, GE images have a rounding error, so nearby slices often have different values... function SameIDSeriesAcqXYZ( var ld1,ld2: DicomData{TDICOM};var lPrefs: TPrefs): boolean; var lStack: boolean; lI: integer; begin result := false; if (ld1.file4D) then //if previous file is a 4D image, we should convert it separately exit; if (ld1.DateTime = ld2.DateTime) and(ld1.SeriesNum = ld2.SeriesNum) {and (ld1.acquNum = ld2.acquNum)} and(ld1.XYZdim[1] = ld2.XYZdim[1]) and(ld1.XYZdim[2] = ld2.XYZdim[2]) and(ld1.XYZdim[3] = ld2.XYZdim[3]) then //result := true else exit; lStack := lPrefs.Stack3DImagesWithSameAcqNum; if (ld1.Vers0018_1020 >= lPrefs.SiemensDTIStackIf00181020atleast) then lStack := true; //recent Siemens scanners will have different NEx saved as different images and different directions saved as different images if (not lStack) and (ld1.acquNum <> ld2.acquNum) then begin dcmMsg('Images not stacked because acquisition number changes. If you want to stack these images set Stack3DImagesWithSameAcqNum=1 in your ini file.'); exit; end; (*if (ld1.PatientIDInt = ld2.PatientIDInt) and(ld1.SeriesNum = ld2.SeriesNum) and (ld1.acquNum = ld2.acquNum) and(ld1.XYZdim[1] = ld2.XYZdim[1]) and(ld1.XYZdim[2] = ld2.XYZdim[2]) and(ld1.XYZdim[3] = ld2.XYZdim[3]) then //result := true else exit;*) for lI := 1 to 6 do begin //if (ld1.orient[lI] <> ld2.orient[lI]) then if abs (ld1.orient[lI] - ld2.orient[lI]) > kTolerance then exit; end; (*if (ld1.IntenScale <> ld2.IntenScale) or (ld1.IntenIntercept <> ld2.IntenIntercept) then begin//if previous file is a 4D image, we should convert it separately msg('Warning: unable to stack images because intensity scaling varies. Names: '+ld1.Filename+' '+ld2.filename+' Slopes: '+floattostr(ld1.IntenScale)+' '+floattostr(ld2.IntenScale)+' Intercepts: '+floattostr(ld1.IntenIntercept)+' '+floattostr(ld2.IntenIntercept)); exit; end; *) result := true; end; function ProcessSingleFolderDCM (var lInFilename: string; var lStringList : TStringList): boolean; //assumes lStringList is already created and will be freed later... var lSearchRec: TSearchRec; lPrev,lFilename,lFilepath,lMaskExt,lExt: string; begin result := false; lFilePath := ExtractFileDirWithPathDelim(lInFilename); lExt := string(StrUpper(PChar(ExtractFileExt(lInFilename)))); //.head if (lExt = '.PAR') or (lExt = '.REC') {or (lExt = '.HDR') or (lExt = '.IMG')or (lExt = '.HEAD') or (lExt = '.BRIK')} then {$IFDEF Unix} lMaskExt := '*'+ExtractFileExt(lInFilename) //Linux is case sensitive, these extensions are used by paired files: only read one of pair else lMaskExt := '*'; {$ELSE} lMaskExt := '*'+lExt //these extensions are used by paired files: only read one of pair else lMaskExt := '*.*'; {$ENDIF} //Msg('yyy'+lFilePath+'::'+lMaskExt); lPrev := '.'; Filemode := 0; //readonly if FindFirst(lFilePath{+PathDelim}+lMaskExt, faAnyFile-faSysFile-faDirectory, lSearchRec) = 0 then begin repeat if (length(lSearchRec.Name) < 1) then //do nothing lFilename := '' {$IFDEF Unix} //next two lines would not recognize filename that starts with dor, e.g. \home\cr\.filename.ima // else if (lSearchRec.Name[1] = '.') then // lFilename := '' else if (lSearchRec.Name = '..') then lFilename := '' else if (lSearchRec.Name = '.') then lFilename := '' {$ENDIF} else begin lFilename := lFilePath+lSearchRec.Name; if (lFilename = '') or (length (lFilename) > 255) then begin dcmMsg('Unable to convert images where the file path and name exceed 255 characters.'); dcmMsg('Solution: put images in a folder with a shorter path.'); dcmMsg(lFilename); end else if (lFilename <> lPrev) then begin lStringList.Add(lFileName); //if lFilename = lPrev then // msg(lPrev); lPrev := lFilename; // msg(lFilePath+lMaskExt+' ->'+lSearchRec.Name+'z'+inttostr(lStringList.count)); end; end; until (FindNext(lSearchRec) <> 0); end; //some files found // msg('xxxx'+inttostr( lStringList.Count)); SysUtils.FindClose(lSearchRec); Filemode := 2; //readonly result := true; end; //ProcessSingleFolder procedure ProcessRecursiveFolder (var lFolderNameIn: string; var lStringList : TStringList; lDepth: integer; var lPrefs: TPrefs); var len: integer; lFolderName,lNewDir,lNewName,lFilename,lExt: String; lSearchRec: TSearchRec; begin lFolderName := lFolderNameIn; if not DirExists (lFolderName) then begin lFolderName := ExtractFileDir(lFolderName); end; if (length(lFolderName) > 1) and (lFolderName[length(lFolderName)] <> PathDelim) then lNewDir := lFolderName+PathDelim; if DirExists (lNewDir) then begin {$IFDEF UNIX} if FindFirst(lNewDir+'*',faAnyFile-faSysFile,lSearchRec) = 0 then begin {$ELSE} if FindFirst(lNewDir+'*.*',faAnyFile-faSysFile,lSearchRec) = 0 then begin {$ENDIF} lFilename := ''; repeat lNewName := lNewDir+lSearchRec.Name; if (lSearchRec.Name <> '.') and (lSearchRec.Name <> '..') then begin if DirExists(lNewName) then begin if lDepth < lPrefs.RecursiveFolderDepth then begin ProcessRecursiveFolder (lNewName, lStringList, lDepth+1, lPrefs); end; //exit;//4/4/2008 end else lFilename := lNewname; end; until (FindNext(lSearchRec) <> 0); end else begin //if directory exists... else we were passed a filename lFilename := lFolderName; end; if lFilename = '' then exit; //Msg('xxxx '+ lFilename); if lFilename <> '' then begin ProcessSingleFolderDCM (lFilename, lStringList); end; end; FindClose(lSearchRec); end; function LoadFileListInner (var lOutDirname: string; var lPrefs: TPrefs; var lStringList : TStringList): boolean; var lPrevDICOM,lDicomData: DicomData; lDICOMra: TDICOMrap; lnumEchos,lRepeatLocations,lStartImg,lValidItems, lItems,lInc: integer; lError,lRepeatedValues,lHdrOK,lImgOK: boolean; lFilename,lDynStr: string; begin result := false; lItems := lStringList.Count; if lItems < 1 then begin lStringList.Free; exit; end; Filemode := 2; dcmMsg('Validating '+inttostr(lItems)+' potential DICOM images.'); //START ANON if lPrefs.AnonymizeSourceDICOM then begin for lInc := 1 to lItems do begin lFilename := lStringList.Strings[lInc-1]; fast_read_dicom_data(lDICOMdata, 128, lFileName); //x3 faster! end; lStringList.Free; result := true; Exit; end; //if anonymizeSourceDICOM //END ANON getmem(lDICOMra,lItems*sizeof(DicomData)); lValidItems := 0; for lInc := 1 to lItems do begin lFilename := lStringList.Strings[lInc-1]; read_dicom_data(true,false{not verbose},true,true,true,true,false, lDICOMdata, lHdrOK, lImgOK, lDynStr,lFileName,lPrefs ); if (lHdrOK) and (lImgOK) then begin //valid file inc(lValidItems); lDICOMra^[lValidItems] := lDicomData; end; //if image is OK end; //for each item lStringList.Free; if lValidItems = 0 then begin dcmMsg('Unable to find any DICOM files in the path '+lFileName); freemem(lDICOMra); exit; end; dcmMsg('Found '+inttostr(lValidItems)+' DICOM images.'); ShellSortDCM (lValidItems,lDICOMra,lRepeatedValues); if lRepeatedValues then begin //separate into series dcmMsg('Warning: repeated image indexes in the path '+lFileName); //freemem(lDICOMra); //exit; end; if lPrefs.DebugMode then begin for lInc := 1 to lValidItems do dcmMsg( DICOMstr(lInc,lDICOMra)); exit; end; lStartImg := 1; lRepeatLocations := 0; lnumEchos := 1; lPrevDICOM := lDICOMra^[1]; for lInc := 1 to lValidItems do begin //msg(lDICOMra^[lInc].Filename+','+floattostr(lDICOMra^[lInc].PatientPosX)+','+floattostr(lDICOMra^[lInc].PatientPosY)+','+floattostr(lDICOMra^[lInc].PatientPosZ) ); if (lInc > 1) and (not SameIDSeriesAcqXYZ (lPrevDICOM ,lDICOMra^[lInc],lPrefs)) then begin //SameIDSeriesAcqXYZ2 (lPrevDICOM ,lDICOMra^[lInc]); if (lRepeatLocations < 2) and (lnumEchos > 1) then lRepeatLocations := lnumEchos; dcmMsg('Converting '+inttostr(lInc-1)+'/'+inttostr(lValidItems)+' volumes: '+inttostr(lRepeatLocations)); result := Dicom2NII(lDICOMra,lStartImg,lInc-1,lOutDirname,lPrefs,lRepeatLocations); if not result then lError := true; lPrevDICOM := lDICOMra^[lInc]; lStartImg := lInc; lRepeatLocations := 1; end else if //(lDICOMra^[lInc].location = lPrevDICOM.Location) and (lDICOMra^[lInc].PatientPosX = lPrevDICOM.PatientPosX) and (lDICOMra^[lInc].PatientPosY = lPrevDICOM.PatientPosY) and (lDICOMra^[lInc].PatientPosZ = lPrevDICOM.PatientPosZ) then begin //fx(lDICOMra^[lInc].PatientPosZ , lPrevDICOM.PatientPosZ ); //fx(666,lRepeatLocations,lDICOMra^[lInc].location, lPrevDICOM.Location); inc(lRepeatLocations); end else if (lInc > 1) and ( (lDICOMra^[lInc].AcquNum) > (lDICOMra^[lInc-1].AcquNum+999)) then //we increment acquisition number by 1000 to denote new echo inc(lnumEchos); end; //for each valid if (lRepeatLocations < 2) and (lnumEchos > 1) then lRepeatLocations := lnumEchos; //fx(lPrevDICOM.PatientPosX, lPrevDICOM.PatientPosY, lPrevDICOM.PatientPosZ ); //Msg( inttostr(lValidItems-lStartImg+1)+' '+ inttostr(lRepeatLocations)); //fx(lRepeatLocations); if (((lValidItems-lStartImg+1) mod lRepeatLocations) <> 0) then begin dcmMsg('*Warning: Number of images in series ('+inttostr(lValidItems-lStartImg+1)+') not divisible by number of volumes ('+inttostr(lRepeatLocations)+')'); dcmMsg('* Perhaps the selected folder only has some of the images'); PartialAcquisitionError; end; if (lPrevDICOM.SlicesPer3DVol > 0) and (not lPrevDICOM.file4D) and ((lValidItems div lRepeatLocations) <> lPrevDICOM.SlicesPer3DVol) then begin dcmMsg('Warning: Number of slices per volume ('+inttostr((lValidItems div lRepeatLocations))+')appears different than reported in DICOM header ('+inttostr(lPrevDICOM.SlicesPer3DVol)+')'); dcmMsg(' Perhaps the selected folder only has some of the images'); end; dcmMsg('Converting '+inttostr(lValidItems)+'/'+inttostr(lValidItems)+' volumes: '+inttostr(lRepeatLocations)); Dicom2NII(lDICOMra,lStartImg,lValidItems,lOutDirname,lPrefs,lRepeatLocations); if lError then result := false //at least one error else result := true; freemem(lDICOMra); end; function ReportDICOMHeader (var lInFilename: string; var lPrefs: TPRefs): boolean; var lDicomData: DicomData; lDynStr: string; lHdrOK,lImgOK: boolean; begin read_dicom_data(false,true,false,false,false,false,false, lDICOMdata, lHdrOK, lImgOK, lDynStr,lInFileName,lPrefs ); result := lHdrOK; end; function LoadFileList (var lInFilename, lOutDirname: string; var lPrefs: TPrefs): boolean; var lStringList : TStringList; begin result := false; if lPrefs.Verbose then begin //msg(lInFilename); result := ReportDICOMHeader (lInFilename, lPrefs); exit; end; lStringList := TStringList.Create; if (lPrefs.OutDirMode <> kOutDirModeInput) and (DirExists(lPrefs.OutDir)) then begin //For kOutDirModePrompt one should set OutDir before getting here //This is required so recursive searches do not repetitively prompt the user... lOutDirName := lPrefs.OutDir; end; //1/2010 if lOutDirName = '' then begin if DirExists (lInFilename) then lOutDirName := lInFilename else lOutDirName := extractfiledir(lInFilename); end; if not(DirExists(lOutDirName)) then lOutDirName := UserDataFolder; if lPrefs.CollapseFolders then begin dcmMsg('Data will be exported to '+lOutDirname); ProcessRecursiveFolder (lInFilename, lStringList, 0, lPrefs); result := true; end else result := ProcessSingleFolderDCM (lInFilename, lStringList); if (not result) or (lStringList.Count < 1) then begin dcmMsg('+Unable to find any images in the path '+lInFilename); lStringList.Free; end else result := LoadFileListInner (lOutDirName, lPrefs,lStringList) end; function LoadParamFileList (var lInFilename, lOutDirname: string; var lPrefs: TPrefs; lParamNum: integer): boolean; var lStringList : TStringList; lI : integer; begin result := false; if lPrefs.Verbose then begin result := ReportDICOMHeader (lInFilename, lPrefs); exit; end; lStringList := TStringList.Create; lStringList.Add(lInFilename); if ((lParamNum) < ParamCount) then for lI := (lParamNum+1) to ParamCount do lStringList.Add(Paramstr(lI)); dcmMsg('Only converting files explicitly specified'); result := LoadFileListInner (lOutDirName, lPrefs,lStringList) end; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/nii_3dto4d.pas0000755000175000017500000003466512306710434020213 0ustar mihmihunit nii_3dto4d; {$H+} interface uses {$IFDEF FPC}gzio2,{$ENDIF} SysUtils,define_types,dicomtypes,niftiutil,prefs,classes,dialogs_msg, nifti_types; function Stack3Dto4D(var lStr: TStringList; lOverwrite: boolean; lPrefs: TPrefs): boolean; function ExtractNIFTIHdrs(var lStr: TStringList): boolean; implementation uses dialogsx; function LeadingZeroFilename (lInX: string): string; var lIn: string; lC,lnPad,lPos,lnDec,lExtPos,lLen: integer; begin {$IFDEF Unix} lIn := lInX; {$ELSE} lIn := Lowercase(lInX); {$ENDIF} lnPad := 8; lLen := length(lIn); result := lIn; if lLen < 1 then exit; lExtPos := 1; while (lExtPos <= lLen) and (lIn[lExtPos] <> '.') do inc(lExtPos); if lExtPos <= 1 then exit; //lnDec := 0; lPos := lExtPos -1; while (lPos > 0) and ( lIn[lPos] in ['0'..'9']) do dec(lPos); lnDec := (lExtPos-lPos)-1; if (lnDec = 0) or (lnDec >= lnPad) then exit; result := ''; if lPos > 0 then for lC := 1 to lPos do result := result + lIn[lC]; for lC := 1 to (lnPad-lnDec) do result := result + '0'; for lC := (lPos+1) to lLen do result := result+lIn[lC]; end; procedure SortStrPadded (var lStr: TStringList); //file1,file2...file10 not file1,file10..file2 //may be slow: not a great sorting algorithm //may be inefficient: not sure if strings are exchanged or only pointers... var counter, look:integer; temp:Tstrings; begin if lStr.Count < 2 then exit; temp := TStringList.Create; for counter:=0 to lStr.Count-1 do temp.Append(LeadingZeroFilename{LowerCase}(lStr[counter])); for counter:=0 to temp.Count-1 do for look:=counter+1 to temp.Count-1 do if temp[look] kDel) and(lStr[i] <> kTab) and (lStr[i] <> kEsc) and (lStr[i] <> chr(10)) and (lStr[i] <> chr (13)) and (ord(lStr[i]) <> 0) then result := result + lStr[i]; end; result := '"'+result +'"' end; function NIIstr (lFileName: string; lHdr : TNIFTIhdr): string; begin result := lFileName +kTab+'XYZT'+kTab+inttostr(lHdr.Dim[1])+kTab+inttostr(lHdr.Dim[2])+kTab+inttostr(lHdr.Dim[3])+kTab+inttostr(lHdr.Dim[4]) +kTab+'XYZTmm'+kTab+floattostr(lHdr.PixDim[1])+kTab+floattostr(lHdr.PixDim[2])+kTab+floattostr(lHdr.PixDim[3])+kTab+floattostr(lHdr.PixDim[4]) +kTab+'Description'+kTab+PasStr(lHdr.descrip) +kTab+'Data_Type'+kTab+PasStr(lHdr.Data_Type) +kTab+'db_name'+kTab+PasStr(lHdr.db_name) +kTab+'aux_file'+kTab+PasStr(lHdr.aux_file) +kTab+'intent_name'+kTab+PasStr(lHdr.intent_name) ; end; function ExtractNIFTIHdrs(var lStr: TStringList): boolean; var lHdrName: string; lHdr : TNIFTIhdr; lByteSwap: boolean; lVol,lnVol : integer; lO: TNIIOpts; begin result := false; lnVol := lStr.Count; if lnVol < 1 then exit; SortStrPadded(lStr); for lVol := 1 to lnVol do begin lHdrName := lStr[lVol-1]; if not NIFTIhdr_LoadHdr (lHdrName, lHdr,lO) then dcmMsg('Unable to find '+lHdrName) else dcmMsg(NIIstr(lHdrName,lHdr)); //dcmMsg( inttostr(lVol)+': '+lHdrName); end; end; function Stack3Dto4D(var lStr: TStringList; lOverwrite: boolean; lPrefs: TPrefs): boolean; //function Reorder4D(var lHdrName: string; var lHdr: TNIFTIhdr; lOverwrite: boolean; lPrefs: TPrefs): boolean; label 123; var lOutBuffer,lIBuffer: byteP; lInOffset,lnVol,l4DVolBytes,l3DVolBytes,lIn3DBytes,l4DBytes,lVol,lInPos,lOutPos,lSlice: integer; lHdrName,lOutImgName: string; lHdr1,lHdr2,lOutHdr : TNIFTIhdr; lO: TNIIOpts; lPrefs4D: TPrefs; begin result := false; lnVol := lStr.Count; if lnVol < 2 then begin dcmMsg('Stack 3D to 4D requires >1 volume'); exit; end; SortStrPadded(lStr); lHdrName := lStr[0]; NIFTIhdr_LoadHdr (lHdrName, lHdr1,lO); for lVol := 1 to lnVol do begin lHdrName := lStr[lVol-1]; if not NIFTIhdr_LoadHdr (lHdrName, lHdr2,lO) then begin dcmMsg('Stack 3D to 4D unable to find '+lHdrName); exit; end; if (lHdr1.dim[4] > 1) then begin dcmMsg('Stack 3D to 4D aborted, image is already 4D: '+lHdrName ); exit; end; if (lHdr1.dim[1] <> lHdr2.dim[1]) or (lHdr1.dim[2] <> lHdr2.dim[2]) or (lHdr1.dim[3] <> lHdr2.dim[3]) or (lHdr1.datatype <> lHdr2.datatype) then begin dcmMsg('Stack 3D to 4D aborted, image dimensions/datatype vary '+lHdrName + ' <> '+lStr[0]); exit; end; //dcmMsg( inttostr(lVol)+': '+lHdrName); end; lOutHdr := lHdr1; lOutHdr.dim[4] := lnVol; l3DVolBytes := lHdr1.dim[1]*lHdr1.dim[2]*lHdr1.dim[3]*(lHdr1.bitpix div 8); l4DVolBytes := l3DVolBytes * lnVol; GetMem(lOutBuffer,l4DVolBytes+kNIIImgOffset); dcmMsg('Order in output file:'); lOutImgName := ChangeFilePrefix (lStr[0],'4D'); lOutPos := kNIIImgOffset + 1; for lVol := 1 to lnVol do begin lHdrName := lStr[lVol-1]; dcmMsg( inttostr(lVol)+': '+lHdrName); if not NIFTIhdr_LoadImg (lHdrName, lHdr2, lIBuffer, lInOffset,lO) then begin dcmMsg('3D -> 4D error loading image '+lHdrName); goto 123; end; Move(lIBuffer^[lInOffset+1],lOutBuffer^[lOutPos],l3DVolBytes); freemem(lIBuffer); lOutPos := lOutPos + l3DVolBytes; end; lPrefs4D := lPrefs; lPrefs4D.fourD := true; dcmMsg('4D image '+lOutImgName); if SaveNIfTICore (lOutImgName, lOutBuffer, kNIIImgOffset+1, lOutHdr, lPrefs4D) = '' then begin dcmMsg('3D -> 4D Error'); goto 123; end; freemem(lOutBuffer); result := true; exit; 123: freemem(lOutBuffer); end; (*function Reorder4D(var lHdrName: string; var lHdr: TNIFTIhdr; lByteSwap,lSPM2in,lSingleNIIFile,lGZ,lOverwrite: boolean): boolean; var lOutHdr: TNIFTIhdr; lInName,lImgName: string; lPos,lSlice,lVol,lInVolBytes,lSliceBytes: integer; lBuffer: bytep; lGZi,lSPM2: boolean; lOutF,lInF: File; begin result := false; lGZi := lGZ; lSPM2 := lSPM2in; if lSingleNIIFIle then lSPM2 := false; if (lHdr.dim[4] < 2) or (lHdr.dim[3] < 2) then exit; lOutHdr := lHdr; lOutHdr.dim[4] := lHdr.dim[3]; lOutHdr.dim[3] := lHdr.dim[4]; lSliceBytes := lHdr.dim[1]*lHdr.dim[2]*(lHdr.bitpix div 8); lInVolBytes := lSliceBytes*lHdr.dim[3]; GetMem(lBuffer,lSliceBytes); if UpCaseExt(lHdrName) ='.HDR' then begin if lOverwrite then deletefile(lHdrName); lInName := changefileext(lHdrName,'.img') end else begin lOutHdr.vox_offset := 352; lInName := lHdrName; end; if not fileexists(lInName) then begin dcmMsg('4Dclip Error: Unable to find '+lInName); exit; end; if FSize (lInName) < ( (lInVolBytes*lHdr.dim[4])+round(lHdr.vox_offset)) then begin dcmMsg('4Dclip Error: File smaller than expected (can not convert compressed) '+lInName); exit; end; dcmMsg('Reordering image'); if not lSingleNiiFile then begin lHdrName := changefileext(lHdrName,'.hdr'); lImgName := changefileext(lHdrName,'.img'); lGZi := false; end else begin lHdrName := changefileext(lHdrName,'.nii'); lImgName := changefileext(lHdrName,'.nii'); end; if lOverwrite then begin renamefile(lInName,changefileext(lInName,'.tmp')); lInName := changefileext(lInName,'.tmp'); end else begin lHdrName := ChangeFilePrefixExt (lHdrName,'x'); lImgName := ChangeFilePrefixExt (lImgName,'x'); dcmMsg('saving as '+lHdrName); end; AssignFile(lInF, lInName); Reset(lInF,1); Seek(lInF,round(lHdr.vox_offset)); SaveHdr (lHdrName,lOutHdr,lByteSwap{ false},lSPM2); AssignFile(lOutF, lImgName); if lSingleNIIFile then begin Reset(lOutF,1); Seek(lOutF,352); end else Rewrite(lOutF,1); for lVol := 1 to lOutHdr.dim[4] do begin lPos := ((lVol-1)*lSliceBytes) + round(lHdr.vox_offset); for lSlice := 1 to lOutHdr.dim[3] do begin Filemode := 0; //ReadONly seek(lInF,lPos); BlockRead(lInF, lBuffer^, lSliceBytes); Filemode := 2; BlockWrite(lOutF, lBuffer^, lSliceBytes); lPos := lPos + lInVolBytes; end;//for lslice end; //for lvol CloseFile(lInF); CloseFile(lOutF); Freemem(lBuffer); if lOverwrite then DeleteFile(lInName); if lGZi then GZipFile(lImgName,lImgName+'.gz',true); result := true; end; *) (*function Clip4D(var lHdrName: string; var lHdr: TNIFTIhdr; lByteSwap,lSPM2in, lSingleNIIFile,lGZ,lOverwrite: boolean; lStartIn,lEndIn: integer ): string; var lOutHdr: TNIFTIhdr; lInName,lImgName: string; lVol,lVolBytes,lStart,lEnd: integer; lBuffer: bytep; lGZi,lSPM2 : boolean; lOutF,lInF: File; begin result := ''; lGZi := lGZ; lSPM2 := lSPM2in; if lSingleNIIFIle then lSPM2 := false; lStart := lStartIn; if lStart < 0 then lStart := 0; lEnd := lEndIn; if lEnd < 0 then lEnd := 0; lOutHdr := lHdr; lOutHdr.dim[4] := lOutHdr.dim[4]-lStart-lEnd; if lOutHdr.dim[4] < 1 then exit; lVolBytes := lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3]*(lOutHdr.bitpix div 8); GetMem(lBuffer,lVolBytes); if UpCaseExt(lHdrName) ='.HDR' then begin if lOverwrite then deletefile(lHdrName); lInName := changefileext(lHdrName,'.img') end else begin lOutHdr.vox_offset := 352; lInName := lHdrName; end; if not fileexists(lInName) then begin dcmMsg('4Dclip Error: Unable to find '+lInName); exit; end; if FSize (lInName) < ( (lVolBytes*lHdr.dim[4])+round(lHdr.vox_offset)) then begin dcmMsg('4Dclip Error: File smaller than expected (can not convert compressed) '+lInName); exit; end; if (lStart > 0) or (lEnd > 0) then dcmMsg('4D clip - removing first '+inttostr(lStart)+' and last '+inttostr(lEnd) +' volumes') else dcmMsg('Formatting image'); if not lSingleNiiFile then begin lGZi := false; lHdrName := changefileext(lHdrName,'.hdr'); lImgName := changefileext(lHdrName,'.img'); end else begin lHdrName := changefileext(lHdrName,'.nii'); lImgName := changefileext(lHdrName,'.nii'); end; if lOverwrite then begin renamefile(lInName,changefileext(lInName,'.tmp')); lInName := changefileext(lInName,'.tmp'); end else begin lHdrName := ChangeFilePrefixExt (lHdrName,'x'); lImgName := ChangeFilePrefixExt (lImgName,'x'); dcmMsg('Saving clipped as '+lHdrName); end; AssignFile(lInF, lInName); Reset(lInF,1); Seek(lInF,round(lHdr.vox_offset)); SaveHdr (lHdrName,lOutHdr, lByteSwap{false},lSPM2); AssignFile(lOutF, lImgName); if lSingleNIIFile then begin Reset(lOutF,1); Seek(lOutF,352); end else Rewrite(lOutF,1); for lVol := 1 to (lHdr.dim[4]-lEnd) do begin //1st - save header Filemode := 0; //ReadONly BlockRead(lInF, lBuffer^, lVolBytes); if (lVol > lStart) then begin Filemode := 2; BlockWrite(lOutF, lBuffer^, lVolBytes); end; end; CloseFile(lInF); CloseFile(lOutF); Freemem(lBuffer); if lOverwrite then DeleteFile(lInName); if lGZi then begin lHdrName := lImgName+'.gz'; GZipFile(lImgName,lHdrName,true); end; result := lHdrName; end; function Convert4Dto3D(var lHdrName: string; var lHdr: TNIFTIhdr; lByteSwap, lSPM2in,lSingleNIIFile,lGZ: boolean ): boolean; var lOutHdr: TNIFTIhdr; lOutName,lImgName: string; lVol,lVolBytes: integer; lBuffer: bytep; lSPM2,lGZi: boolean; lOutF,lInF: File; begin result := false; lSPM2 := lSPM2in; if lSingleNIIFIle then lSPM2 := false; lGZi := lGZ; if lHdr.dim[4] < 2 then exit; lOutHdr := lHdr; lOutHdr.dim[0] := 3;//3D lOutHdr.dim[4] := 1; lVolBytes := lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3]*(lOutHdr.bitpix div 8); GetMem(lBuffer,lVolBytes); //lSingleNIIFile := true; if UpCaseExt(lHdrName) ='.HDR' then begin //lSingleNIIFile := false; lImgName := changefileext(lHdrName,'.img') end else lImgName := lHdrName; if not fileexists(lImgName) then begin dcmMsg('4D->3D Error: Unable to find '+lImgName); exit; end; if FSize (lImgName) < ( (lVolBytes*lHdr.dim[4])+round(lHdr.vox_offset)) then begin dcmMsg('4D->3D Error: File smaller than expected (can not convert compressed) '+lImgName); exit; end; //dcmMsg(inttostr(round(lHdr.vox_offset))); AssignFile(lInF, lImgName); Reset(lInF,1); Seek(lInF,round(lHdr.vox_offset)); if not lSingleNiiFile then begin lGZi := false; lHdrName := changefileext(lHdrName,'.hdr'); lImgName := changefileext(lHdrName,'.img'); end else begin lHdrName := changefileext(lHdrName,'.nii'); lImgName := changefileext(lHdrName,'.nii'); end; for lVol := 1 to lHdr.dim[4] do begin //1st - save header lOutName := AddFileNum(lVol,lHdr.dim[4],lHdrName); SaveHdr (lOutName,lOutHdr,lByteSwap {false},lSPM2); Filemode := 0; //ReadONly BlockRead(lInF, lBuffer^, lVolBytes); lOutName := AddFileNum(lVol,lHdr.dim[4],lImgName); Filemode := 2; AssignFile(lOutF, lOutName); if (lSingleNIIFile) and (not lSPM2) then begin Reset(lOutF,1); Seek(lOutF,352); end else Rewrite(lOutF,1); BlockWrite(lOutF, lBuffer^, lVolBytes); CloseFile(lOutF); if lGZi then begin GZipFile(lOutName,lOutName+'.gz',true); //DeleteFile(lOutName); end; end; CloseFile(lInF); Freemem(lBuffer); //if lDeleteOrig then begin DeleteFile(lHdrName); if not lSingleNIIFile then DeleteFile(lImgName); //end; end; *) end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/prefs.pas0000755000175000017500000002420212314604156017356 0ustar mihmihunit prefs; {$H+} {$Include ..\common\isgui.inc} interface uses {$IFDEF FPC} {$IFDEF UNIX} BaseUnix,{$ENDIF} {$IFDEF GUI}LResources, {$ENDIF} {$ELSE} SelectFolder, {$ENDIF} inifiles, define_types,SysUtils, userdir, dialogsx, dialogs_msg; type TPrefs = record WritePrefsOnQuit,OrthoFlipXDim,RecursiveUseNameAppend,AnonymizeSourceDICOM, ManualNIfTIConv,Anonymize, SingleNIIFile,Gzip,SPM2,VOI,enablereorient,createoutputfolder, AppendDate,AppendAcqSeries,AppendProtocolName,AppendPatientName,AppendFilename, everyfile,fourD,Swizzle4D,Stack3DImagesWithSameAcqNum,customRename, CollapseFolders,AutoCrop, UseGE_0021_104F, PhilipsPrecise,Verbose, DebugMode,DebugMode2,UntestedFeatures,UINT16toFLOAT32, TxtReport: boolean; BeginClip, LastClip,SiemensDTIUse0019If00181020atleast, SiemensDTINoAngulationCorrectionIf00181020atleast, SiemensDTIStackIf00181020atleast, OutDirMode, MinReorientMatrix,MaxReorientMatrix,RecursiveFolderDepth,usePigz : integer; OutDir, BackupDir,NameAppend: string; end; const kOutDirModeInput = 0;//save output files to source folder kOutDirModePrompt = 1;//prompt user to specify location of output dir kOutDirModeOutDir = 2;//save output to lPrefs.OutDir kMinReorientMatrix = 200; //reorient images with matrices > this value procedure SetOutputFormat (lItemIndex: integer; var lPrefs: TPrefs); procedure SetDefaultPrefs (var lPrefs: TPrefs); procedure CorrectPrefs (var lPrefs: TPrefs); //ensures only usable file types are created function IniFile(lRead: boolean; lFilename: string; var lPrefs: TPrefs): boolean; function DefaultOutputFormat (lPrefs: TPrefs): integer; implementation function DefaultOutputFormat (lPrefs: TPrefs): integer; begin if lPrefs.SPM2 then result := 0 //SPM2 3D hdr/img analyze else if not lPrefs.FourD then begin if not (lPrefs.SingleNIIFile) then result := 1 //SPM5 3D hdr/img else result:= 2; //SPM8 3D nii end else if not lPrefs.SingleNIIFile then result := 3 //?? 4D hdr/img else if not lPrefs.GZip then result := 4 //FSL 4D nii else result := 5; //FSL 4D nii.gz end; procedure SetOutputFormat (lItemIndex: integer; var lPrefs: TPrefs); //SetOutputFormat(n,lPrefs) : 0=SPM2,1=SPM5,2=spm8,3=4D hdr/img,4=fsl(default),5=fsl.gz, 6=.voi begin //next: options for reading; lPrefs.VOI := false; lPrefs.SPM2 := false; lPrefs.fourD := true; lPrefs.SingleNIIFile := true; lPrefs.GZip := false; case lItemIndex of 0: begin//spm2 lPrefs.SPM2 := true; lPrefs.fourD := false; lPrefs.SingleNIIFile := false; end; 1: begin//spm5 lPrefs.fourD := false; lPrefs.SingleNIIFile := false; end; 2: begin//spm8 lPrefs.fourD := false; end; 3: lPrefs.SingleNIIFile := false;//4D Hdr/Img 5: lPrefs.GZip := true;//FSL compressed 6: begin //VOI lPrefs.GZip := true;//FSL compressed lPrefs.VOI := true; end; end;//case end; procedure CorrectPrefs (var lPrefs: TPrefs); //ensures only usable file types are created begin if lPrefs.SingleNIIFile then lPrefs.SPM2 := false; //SPM2 only reads .hdr/.img - loses NIfTI information if not lPrefs.SingleNIIFile then lPrefs.Gzip := false; //nii.gz is OK, but img.gz is not end; procedure SetDefaultPrefs (var lPrefs: TPrefs); begin with lPrefs do begin OutDirMode := kOutDirModeInput; SiemensDTIUse0019If00181020atleast := 15; SiemensDTINoAngulationCorrectionIf00181020atleast := 1000; SiemensDTIStackIf00181020atleast := 15; //IgnoreDTIRotationsIf_0002_0013_atleast := 15; VOI := false; OutDir := UserDataFolder; PhilipsPrecise := false; UseGE_0021_104F := false; CollapseFolders := true; AutoCrop := false; //for dcm2nii - reorient and crop 3D nifti input images... CustomRename := false; createoutputfolder := false; Stack3DImagesWithSameAcqNum := false; RecursiveUseNameAppend := false;//changes paramstrs.pas recursive search to add top level folder name DebugMode := false; DebugMode2 := false; UntestedFeatures := false; TxtReport := false; Verbose := false; SingleNIIFile := true; Gzip := true; OrthoFlipXDim := false; SPM2 := false; Anonymize := true; AppendDate := true; AppendAcqSeries := true; AppendProtocolName := true; AppendPatientName := false; AppendFilename := false; EveryFile:=true; FourD := true; enablereorient := true; ManualNIfTIConv := true; AnonymizeSourceDICOM := false; Swizzle4D := true; RecursiveFolderDepth := 5; MinReorientMatrix := kMinReorientMatrix; MaxReorientMatrix := 1023; NameAppend := ''; BackupDir := ''; WritePrefsOnQuit := true; UINT16toFLOAT32 := true; BeginClip := 0; LastClip := 0; usePigz := 0; end; end; procedure IniInt(lRead: boolean; lIniFile: TCustomIniFile; lIdent: string; var lValue: integer); //read or write an integer value to the initialization file var lStr: string; begin if not lRead then begin lIniFile.WriteString('INT',lIdent,IntToStr(lValue)); exit; end; lStr := lIniFile.ReadString('INT',lIdent, ''); if length(lStr) > 0 then lValue := StrToInt(lStr); end; //IniInt procedure IniBool(lRead: boolean; lIniFile: TCustomIniFile; lIdent: string; var lValue: boolean); //read or write a boolean value to the initialization file var lStr: string; begin if not lRead then begin lIniFile.WriteString('BOOL',lIdent,Bool2Char(lValue)); exit; end; lStr := lIniFile.ReadString('BOOL',lIdent, ''); if length(lStr) > 0 then lValue := Char2Bool(lStr[1]); end; //IniBool procedure IniStr(lRead: boolean; lIniFile: TCustomIniFile; lIdent: string; var lValue: string); //read or write a string value to the initialization file begin if not lRead then begin lIniFile.WriteString('STR',lIdent,lValue); exit; end; lValue := lIniFile.ReadString('STR',lIdent, ''); end; //IniStr function IniFile(lRead: boolean; lFilename: string; var lPrefs: TPrefs): boolean; //Read or write initialization variables to disk var lIniFile: TMemIniFile; begin result := false; if (lRead) and (not Fileexists(lFilename)) then exit; {$IFDEF UNIX} //Uses BaseUnix; if (lRead) and (fpAccess (lFilename,R_OK)<>0) then begin//ensure user has read-access to prefs file... dcmMsg('Unable to load preferences: no write access for '+lFilename); exit; end; {$ENDIF} if (lRead) then begin Filemode := 0; //Readonly dcmMsg('reading preferences file '+lFilename); end else Filemode := 2; //Read-Write //lIniFile := TIniFile.Create(lFilename); lIniFile := TMemIniFile.Create(lFilename); IniBool(lRead,lIniFile,'DebugMode',lPrefs.DebugMode); IniBool(lRead,lIniFile,'UntestedFeatures',lPrefs.UntestedFeatures); IniBool(lRead,lIniFile,'TxtReport',lPrefs.TxtReport); IniBool(lRead,lIniFile,'UINT16toFLOAT32',lPrefs.UINT16toFLOAT32); IniBool(lRead,lIniFile,'Verbose',lPrefs.Verbose); IniBool(lRead,lIniFile,'Anonymize',lPrefs.Anonymize); IniBool(lRead,lIniFile, 'AnonymizeSourceDICOM',lPrefs.AnonymizeSourceDICOM); IniBool(lRead,lIniFile,'AppendAcqSeries',lPrefs.AppendAcqSeries); IniBool(lRead,lIniFile,'AppendDate',lPrefs.AppendDate); IniBool(lRead,lIniFile,'AppendFilename',lPrefs.AppendFilename); IniBool(lRead,lIniFile,'AppendPatientName',lPrefs.AppendPatientName); IniBool(lRead,lIniFile,'AppendProtocolName',lPrefs.AppendProtocolName); IniBool(lRead,lIniFile,'AutoCrop',lPrefs.AutoCrop); IniBool(lRead,lIniFile,'CollapseFolders',lPrefs.CollapseFolders); IniBool(lRead,lIniFile,'createoutputfolder',lPrefs.createoutputfolder); IniBool(lRead,lIniFile,'CustomRename',lPrefs.CustomRename); IniBool(lRead,lIniFile,'enablereorient',lPrefs.enablereorient); IniBool(lRead,lIniFile,'OrthoFlipXDim',lPrefs.OrthoFlipXDim); IniBool(lRead,lIniFile,'EveryFile',lPrefs.EveryFile); IniBool(lRead,lIniFile,'fourD',lPrefs.fourD); IniBool(lRead,lIniFile,'Gzip',lPrefs.Gzip); IniBool(lRead,lIniFile,'ManualNIfTIConv',lPrefs.ManualNIfTIConv); IniBool(lRead,lIniFile,'PhilipsPrecise',lPrefs.PhilipsPrecise); IniBool(lRead,lIniFile,'RecursiveUseNameAppend',lPrefs.RecursiveUseNameAppend); IniBool(lRead,lIniFile,'SingleNIIFile',lPrefs.SingleNIIFile); IniBool(lRead,lIniFile,'SPM2',lPrefs.SPM2); IniBool(lRead,lIniFile,'Stack3DImagesWithSameAcqNum',lPrefs.Stack3DImagesWithSameAcqNum); IniBool(lRead,lIniFile,'Swizzle4D',lPrefs.Swizzle4D); IniBool(lRead,lIniFile,'UseGE_0021_104F',lPrefs.UseGE_0021_104F); IniInt(lRead,lIniFile,'BeginClip',lPrefs.BeginClip); IniInt(lRead,lIniFile,'LastClip',lPrefs.LastClip); IniInt(lRead,lIniFile,'usePigz',lPrefs.usePigz); IniInt(lRead,lIniFile,'MaxReorientMatrix',lPrefs.MaxReorientMatrix); IniInt(lRead,lIniFile,'MinReorientMatrix',lPrefs.MinReorientMatrix); IniInt(lRead,lIniFile,'RecursiveFolderDepth',lPrefs.RecursiveFolderDepth); IniInt(lRead,lIniFile,'OutDirMode',lPrefs.OutDirMode); IniInt(lRead,lIniFile,'SiemensDTIUse0019If00181020atleast',lPrefs.SiemensDTIUse0019If00181020atleast); IniInt(lRead,lIniFile,'SiemensDTINoAngulationCorrectionIf00181020atleast',lPrefs.SiemensDTINoAngulationCorrectionIf00181020atleast); IniInt(lRead,lIniFile,'SiemensDTIStackIf00181020atleast',lPrefs.SiemensDTIStackIf00181020atleast); lPrefs.BackupDir := lIniFile.ReadString('STR','BackupDir',lPrefs.BackupDir); IniStr(lRead,lIniFile,'OutDir',lPrefs.OutDir); if (lPrefs.OutDirMode < kOutDirModeInput) or (lPrefs.OutDirMode > kOutDirModeOutDir) then lPrefs.OutDirMode := kOutDirModeOutDir; if (lRead) and (not(DirExists(lPrefs.OutDir))) then lPrefs.OutDir := UserDataFolder; if not lRead then lIniFile.UpdateFile; lIniFile.Free; if (lRead) then Filemode := 2; //Read-write end; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/untar.pas0000755000175000017500000003223212204716732017374 0ustar mihmihunit untar; interface {$IFDEF FPC}{$mode delphi}{$H+}{$ENDIF} uses {$IFDEF FPC} gzio2, {$ELSE} gziod, {$ENDIF} define_types,SysUtils,LibTar, dialogs_msg, gzio,dialogsx,prefs,sortdicom,classes; function DeTGZ (lFilename: string; lPrefs: TPrefs): boolean; function isTGZ (var lStr: string): boolean; implementation function isTGZ (var lStr: string): boolean; var lExt: string; begin lExt := extractfileext(lStr); lExt := UpperCase(lExt); if (lExt='.TGZ') then Result := true else Result := false; end; (*procedure Extract (var lTarFile: string; lOverwrite: boolean); //extract target VAR TA : TTarArchive; DirRec : TTarDirRec; lPos,lLen,lnumFilesTotal,lnumFilesCompleted,lPct: longint; lStr,lOutDir,lLocalDir,lFileName,lNewDir,lTarName : String; begin lOutDir := extractfiledir(lTarFile); //next Count files for progress bar.... lnumFilesTotal := 0; TA := TTarArchive.Create (lTarFile); TRY TA.Reset; TA.SetFilePos (0); TA.FindNext (DirRec); repeat inc(lnumFilesTotal); until not TA.FindNext (DirRec); FINALLY TA.Free; END; //finished counting files //next: extract files... lnumFilesCompleted := 0; //FProgress := 0; TA := TTarArchive.Create (lTarFile); TRY TA.Reset; TA.SetFilePos (0); TA.FindNext (DirRec); repeat inc(lNumFilesCompleted); {lPct := round(lNumFilesCOmpleted/lNumfilesTotal*100); if lPct > FProgress then begin //only update progress bar 100 times: do not waste time updating screen FProgress := lPct; DoOnProgress; end;} if DirRec.Name <> '' then begin //Screen.Cursor := crHourGlass; TRY //filename change '/' to '\' lTarName := ''; lLen := length(DirRec.name); for lPos := 1 to lLen do begin if (DirRec.Name[lPos]='/') or (DirRec.Name[lPos]='\') then lTarName := lTarName + pathdelim//'\' else if (DirRec.Name[lPos]=':') then else lTarName := lTarName + DirRec.Name[lPos]; end; lFilename := lOutDir+pathdelim+lTarName; lLocalDir := extractfiledir(lFileName); if (DirExists(lLocalDir)) then begin {lProceed := mrYes; if Fileexists(lFileName) then begin if (gmrOverwrite = mrYes) or (gmrOverwrite = mrNo) then begin OverwriteForm.Label1.caption := 'Warning: the file '+lFilename+' already exists.'; gmrOverwrite := OverwriteForm.Showmodal; end; lProceed := gmrOverwrite; end; } if lOverwrite{(lProceed = mrYes) or (lProceed = mrYesToAll)} then begin if (length(lFilename)>2) and ((lFilename[length(lFilename)] = '\') or (lFilename[length(lFilename)] = '/')) then begin lLen := length(lFilename)-1; lStr := lFilename; lFilename := ''; for lPos := 1 to lLen do lFilename := lFilename+lStr[lPos]; if not direxists(lFilename) then begin mkdir (lFilename); end; end else TA.ReadFile (lFileName); end; //proceed end else begin lLen := length(lTarName); lPos := 1; if (lLen >= 1) and ((lTarName[1] = '\') or (lTarName[1] = '/')) then inc(lPos); lNewDir := lOutDir+pathdelim; while lPos <= lLen do begin if (lTarName[lPos] = '\') or (lTarName[lPos] = '/') then begin //showmessage('creating directory:'+lNewDir); if not direxists(lNewDir) then mkdir(lNewDir); lNewDir := lNewDir + pathdelim; end else lNewDir := lNewDir + lTarName[lPos]; inc(lPos); end; if (lFileName[length(lFileName)] <> '/') and(lFileName[length(lFileName)] <> '\') and (DirExists(lLocalDir)) and (not Fileexists(lFileName)) then begin TA.ReadFile (lFileName) end; end; FINALLY //Screen.Cursor := crDefault; END; end; until not TA.FindNext (DirRec); FINALLY TA.Free; END; end;*) procedure Extract (var lTarFile: string; lOverwrite: boolean); //extract target VAR TA : TTarArchive; DirRec : TTarDirRec; lPos,lLen,lnumFilesTotal,lnumFilesCompleted,lPct: longint; lStr,lOutDir,lLocalDir,lFileName,lNewDir,lTarName : String; begin lOutDir := extractfiledir(lTarFile); //next Count files for progress bar.... lnumFilesTotal := 0; TA := TTarArchive.Create (lTarFile); TRY TA.Reset; TA.SetFilePos (0); TA.FindNext (DirRec); repeat inc(lnumFilesTotal); until not TA.FindNext (DirRec); FINALLY TA.Free; END; //finished counting files //next: extract files... lnumFilesCompleted := 0; //FProgress := 0; TA := TTarArchive.Create (lTarFile); TRY TA.Reset; TA.SetFilePos (0); TA.FindNext (DirRec); repeat inc(lNumFilesCompleted); {lPct := round(lNumFilesCOmpleted/lNumfilesTotal*100); if lPct > FProgress then begin //only update progress bar 100 times: do not waste time updating screen FProgress := lPct; DoOnProgress; end;} if DirRec.Name <> '' then begin //Screen.Cursor := crHourGlass; TRY //filename change '/' to '\' lTarName := ''; lLen := length(DirRec.name); for lPos := 1 to lLen do begin if (DirRec.Name[lPos]='/') or (DirRec.Name[lPos]='\') then lTarName := lTarName + pathdelim//'\' else if (DirRec.Name[lPos]=':') then else lTarName := lTarName + DirRec.Name[lPos]; end; lFilename := lOutDir+pathdelim+lTarName; lLocalDir := extractfiledir(lFileName); if (DirExists(lLocalDir)) then begin (*lProceed := mrYes; if Fileexists(lFileName) then begin if (gmrOverwrite = mrYes) or (gmrOverwrite = mrNo) then begin OverwriteForm.Label1.caption := 'Warning: the file '+lFilename+' already exists.'; gmrOverwrite := OverwriteForm.Showmodal; end; lProceed := gmrOverwrite; end; *) if lOverwrite{(lProceed = mrYes) or (lProceed = mrYesToAll)} then begin if (length(lFilename)>2) and (lFilename[length(lFilename)] = pathdelim) then begin lLen := length(lFilename)-1; lStr := lFilename; lFilename := ''; for lPos := 1 to lLen do lFilename := lFilename+lStr[lPos]; if not direxists(lFilename) then begin mkdir (lFilename); end; end else TA.ReadFile (lFileName); end; //proceed end else begin lLen := length(lTarName); lPos := 1; if (lLen >= 1) and (lTarName[1] = pathdelim) then inc(lPos); lNewDir := lOutDir+pathdelim; while lPos <= lLen do begin if (lTarName[lPos] = pathdelim) then begin //showmessage('creating directory:'+lNewDir); if not direxists(lNewDir) then mkdir(lNewDir); lNewDir := lNewDir + pathdelim; end else lNewDir := lNewDir + lTarName[lPos]; inc(lPos); end; if (lFileName[length(lFileName)] <> pathdelim) and (DirExists(lLocalDir)) and (not Fileexists(lFileName)) then begin TA.ReadFile (lFileName) end; end; FINALLY //Screen.Cursor := crDefault; END; end; until not TA.FindNext (DirRec); FINALLY TA.Free; END; end; function FindFile (lDir: String): string; //lDir should include pathdelim, e.g. c:\folder\ var lSearchRec: TSearchRec; begin result := ''; if FindFirst(lDir+'*', faAnyFile-faSysFile-faDirectory, lSearchRec) = 0 then result := lDir +lSearchRec.Name; FindClose(lSearchRec); end; procedure DeleteTreeX (const Path : string; recursive : boolean); var Result : integer; SearchRec : TSearchRec; begin Result := FindFirst(Path + '*', faAnyFile-faDirectory , SearchRec); while Result = 0 do begin if not DeleteFile (Path + SearchRec.name) then begin FileSetAttr (Path + SearchRec.name, 0); { reset all flags } DeleteFile (Path + SearchRec.name); end; Result := FindNext(SearchRec); end; FindClose(SearchRec); if not recursive then exit; Result := FindFirst(Path + '*.*', faDirectory, SearchRec); while Result = 0 do begin if (SearchRec.name <> '.') and (SearchRec.name <> '..') then begin FileSetAttr (Path + SearchRec.name, faDirectory); DeleteTreeX (Path + SearchRec.name + '\', TRUE); RmDir (Path + SearchRec.name); end; Result := FindNext(SearchRec); end; FindClose(SearchRec); end; Procedure copyfile( Const sourcefilename, targetfilename: String ); Var S, T: TFileStream; Begin S := TFileStream.Create( sourcefilename, fmOpenRead ); try T := TFileStream.Create( targetfilename, fmOpenWrite or fmCreate ); try T.CopyFrom(S, S.Size ) ; finally T.Free; end; finally S.Free; end; End; procedure CopyDir ( lSourceDir,lDestDir: string); var Result : integer; SearchRec : TSearchRec; lSrc,lDest: string; begin Result := FindFirst(lSourceDir + '*', faAnyFile-faDirectory , SearchRec); while Result = 0 do begin lSrc := lSourceDir + SearchRec.name; lDest := lDestDir + SearchRec.Name; copyfile(lSrc,lDest); Result := FindNext(SearchRec); end; FindClose(SearchRec); end; function DeTGZ (lFilename: string; lPrefs: TPrefs): boolean; var lPath,lName,lExt,lOutPath,lTempDir,lTarName,lDicomName: string; begin result := false; if (not fileexists(lFilename)) or (not isTGZ(lFilename)) then exit; FilenameParts (lFilename , lPath,lName,lExt); lOutPath := lPath+lName; if direxists(lOutPath) then begin dcmMsg('Unable to extract TGZ file - folder exists '+lOutpath); exit; end; MkDir(lOutPath); lTempDir := lOutPath+pathdelim+'temp'; MkDir(lTempDir); lTarName := lTempDir+Pathdelim+lName+'.tar'; UnGZipFile (lFilename,lTarName); //unzip Extract (lTarName,true); deletefile(lTarName); //now convert files to NIFTI lDICOMName := FindFile(lTempDir+Pathdelim); if (lDICOMName = '') or (not fileexists(lDICOMname)) then exit; LoadFileList(lDICOMName,lOutPath,lPrefs); DeleteTreeX(lTempDir+Pathdelim, true); RmDir(lTempDir); if (lPrefs.BackupDir <> '') and (DirExists(lPrefs.BackupDir)) then begin lTempDir := lPrefs.BackupDir; if lTempDir[length(lTempDir)] <> pathdelim then lTempDir := lTempDir + pathdelim; dcmMsg('Copying to backup folder named '+lTempDir); CopyDir(lOutPath+pathdelim, lTempDir); dcmMsg('Backup completed'); end; //Extract (lFilename,true); result := true; end; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/notes.txt0000755000175000017500000002660511546414644017443 0ustar mihmihSiemens DICOM always uses scanner coordinates to specify diffusion directions according to Michael Harms [mharms@conte.wustl.edu] We to specify a custom set of directions using entries in a DiffusionVectors.txt file even for the VB13 and VB17 product ep2d_diff sequence, although I think this capability requires a separately purchased license. (What at one point was probably a WIP-only feature got built into the product sequence already by the time of VB13). Within that DiffusionVectors.txt file, one can specify whether the values are interpreted in a "xyz" or "prs" coordinate system. >From old WIP_ep2d_diff documentation I have the following: ------ For the directive CoordinateSystem two different values are allowed: "xyz" specifies that this vector set is to be played out in the magnet coordinate system. "prs" makes the sequence to use the rotation matrix of the current slice, i.e. the phase-read-slice gradient axis system is used. ------ Everyone here at WU that uses custom directions always plays them out in the XYZ coordinate system. HOWEVER, the coordinate system used in playing out the gradients should be irrelevant if one is reading the directions out of the **DICOM**. That is, even if someone specified a custom gradient set to play out in the PRS coordinate system, the directions in the DICOM should still be STORED in the +LPS DICOM coordinate system, meaning that they would still need to be rotated for an oblique acquisition. If your Siemen's contact, or your VD11 Skyra user indicates otherwise, then I think I'll pull my hair out!! Hi Chris, Jolinda, Ok, you guys are really not going to like me, but now that we seem to be reaching a consensus on the issue of rotation for VB13-VB17, I wanted to make sure you were aware of the issue of possibly incorrect bvecs under VB13, which is a completely orthogonal issue. First, I should note that the B_matrix entry in the CSA field of the DICOM is correct for VB13-VB17 (according to Siemens -- see below). These B_matrix entries include the impact of the imaging gradients on the B matrix. Unfortunately, the algorithm that Siemen's used to convert the B_matrix entry into an "equivalent" principle eigendirection yields incorrect results in some instances for VB13. You may have noticed that the 2- norm of DiffusionGradientDirections (thenceforth DGD, as stored in the DICOM) are not necessarily 1.000 for VB13 data. Both dcm2nii and MRIConvert return directions with a norm of exactly 1.0000, so both programs must be re-norming to exactly 1 behind the scenes as a final step prior to output. HOWEVER, norming the magnitude of the direction to 1 is NOT sufficient to recover from the error in Siemen's algorithm. For example, I have a case from a VB13 dataset (using a custom 30 direction set) where the norm for one of the DGD was only 0.16. For that case, I computed the first eigenvector of the B_matrix (using Matlab's 'princomp' function). The resulting direction (which should be the "correct" one) differed from the DGD entry in the DICOM by 12.5 degrees, which indicates that simply re-norming the reported DGD values to 1.0 is indeed NOT SUFFICIENT to guarantee "correct" bvecs for VB13 data. This is a semi-known issue, and is presumably the reason that the DicomToNrrd and Nipy converters include options to re-derive the direction from the B_matrix. i.e., http://mail.scipy.org/pipermail/nipy-devel/2010-September/004768.html and this snippet of email passed on to me by Darren Gitelman: ------- 3) When I corresponded with Mark Scully and Hans Johnson who wrote the dicom2nrrd convertor they suggested that there are standard Siemens tags for the gradients and there are gradients that one obtains from the B matrix. They say the former is wrong. I had written to them that when DTIstudio extracted the gradients from the mosaic image it agreed with dicom2nrrd but only if I did not use the dicom2nrrd option "useBMatrixGradientDirections" which they told me to use. There response was as follows: As to DTIstudio agreeing with the output of DicomToNrrd when run without useBMatrixGradientDirections, I assume DTIstudio is reading the standard tags for direction? If that's the case, it's getting the same wrong data as DicomToNrrd gets when it doesn't use the BMatrix. The whole reason we made it possible to use the BMatrix to calculate the gradients and B values is because the standard tags were wrong in a subset of our Siemens scans. -------- Unfortunately, I have no idea how frequently the DGD entries may be wrong under VB13, and whether or not custom gradient sets are more likely to be affected by the bug than "built-in" gradient sets. I'm actually going to email Mark and Hans next to see if they have a sense for that. Also, I should mention that I was told by Siemen's that the DGD for VB17 are correct, and for VB15 are "correct" up to polarity. Specifically, here is what Stefan Huwer of Siemen's emailed to me regarding this issue: --------- regarding software versions and issues with the diffusion gradient direction: VB13: B_matrix field correct, diffusion_direction sometimes wrong. VB15: B_matrix field correct, diffusion_direction correct (up to polarity). VB17: B_matrix correct, diffusion_direction correct -------- So, why do I bring this all up? First, you (and others) should be aware of the issue, and perhaps I should make some additions to your Word document to explain the issue. That said, I'm not expecting that either MRIConvert or dcm2nii would be modified to include an option to derive the directions from the B_matrix, as that is a rather major software addition. However, it might be appropriate to include a warning message along the lines of the following for VB13 data: "Warning: bvecs are sometimes wrong for VB13 data, due to a bug in the algorithm by which Siemen's converted the B_matrix to a principle eigendirection. The frequency and extent of this problem is unknown at this time". And for VB15 data: "Warning: Polarity of the bvecs may possibly be wrong for VB15 data." cheers, -MH -- Michael Harms, Ph.D. -------------------------------------------------------------------- Conte Center for the Neuroscience of Mental Disorders Washington University School of Medicine Department of Psychiatry, Box 8134 Renard Hospital, Room 6604 Tel: 314-747-6173 660 South Euclid Ave. Fax: 314-747-2182 St. Louis, MO 63110 Email: mharms@wustl.edu -------------------------------------------------------------------- FYI: It sounds like Hans Johnson and Mark Scully (emails in header below) have probably seen just about every "modern" vendor/software combination possible. So, they might be a resource if you wanted to understand GE and Philips better, although it sounds like they might not have much experience with the oblique acquisition issue. cheers, -MH -------- Forwarded Message -------- From: Johnson, Hans J To: Michael Harms , Scully, Mark S Cc: Joy Matsui Subject: Re: DicomToNrrd specifics Date: Thu, 31 Mar 2011 21:30:26 +0000 Michael, We feel your pain. We are working on a 32 site study, and we see just about every kind of data possible. I'm getting this from memory, so take that into consideration. I believe that VB13 had 2 gradients incorrect (gradient 14,15 in our 30 direction scan). The "useBMatrixGradientDirections" does not take scan obliquenss into account, it simply recomputes the values that should have been in the public dicom tags in the first place. I am saying this without every having dealt with oblique DWI scans. ==== Just wait until you get to deal with phillips data :) It is really fun! -- Hans J. Johnson, Ph.D. hans-johnson@uiowa.edu Assistant Professor of Psychiatry University of Iowa Carver College of Medicine W278 GH, 200 Hawkins Drive Iowa City, Iowa 52242 Phone: 319-353-8587 -----Original Message----- From: Michael Harms Date: Thu, 31 Mar 2011 15:29:47 -0500 To: Mark Scully , Hans Johnson Cc: Subject: DicomToNrrd specifics Hello Mark and Hans, I've been conversing with Jolinda Smith (MRIConvert), Chris Rorden (dcm2nii) and others (Darren Gittelman, Fred Tam) regarding some issues with getting bvecs from Siemens VB13, VB15, and VB17 DICOMs. Darren indicated to me that he had the following correspondence with you previously: ---------- 3) When I corresponded with Mark Scully and Hans Johnson who wrote the dicom2nrrd convertor they suggested that there are standard Siemens tags for the gradients and there are gradients that one obtains from the B matrix. They say the former is wrong. I had written to them that when DTIstudio extracted the gradients from the mosaic image it agreed with dicom2nrrd but only if I did not use the dicom2nrrd option "useBMatrixGradientDirections" which they told me to use. There response was as follows: As to DTIstudio agreeing with the output of DicomToNrrd when run without useBMatrixGradientDirections, I assume DTIstudio is reading the standard tags for direction? If that's the case, it's getting the same wrong data as DicomToNrrd gets when it doesn't use the BMatrix. The whole reason we made it possible to use the BMatrix to calculate the gradients and B values is because the standard tags were wrong in a subset of our Siemens scans. -------- It is my understanding, in emails with Stefan Huwer at Siemens, that the issue of possibly incorrect entries in the DiffusionGradientDirection ("DGD") entry in the CSA portion of the Siemen's DICOM, is only for VB13 (although the polarity of the DGD's can be off by 180 degrees for VB15 data). Is that your understanding and experience as well? Do you have any empirical sense of the frequency and extent of this problem under VB13? e.g., What percentage of directions are affected on average? And are certain directions consistently affected across different sessions? Also, on a different different issue, does DicomToNrrd rotate the DGD entries (or alternatively the B_matrix if using the "useBMatrixGradientDirections" option) for oblique acquisitions for VB13-VB17? [I know this latter issue would be easy enough to test, but I've already spent a ton of time on this annoying issue, so I hope you don't mind me just asking you directly, so that I don't have to learn another dicom converter. I'm trying to see if I can't get agreement among various converter developers regarding the necessity of rotating the DGD entries (or B_matrix) for oblique VB13-VB17 acquisitions -- just today I brought Jolinda and Chris around to this position, so I wanted to see what your understanding was of the Siemens/ oblique acquisition/ bvec rotation issue]. Thanks! -MH -- Michael Harms, Ph.D. -------------------------------------------------------------------- Conte Center for the Neuroscience of Mental Disorders Washington University School of Medicine Department of Psychiatry, Box 8134 Renard Hospital, Room 6604 Tel: 314-747-6173 660 South Euclid Ave. Fax: 314-747-2182 St. Louis, MO 63110 Email: mharms@wustl.edu -------------------------------------------------------------------- mricron-0.20140804.1~dfsg.1.orig/dcm2nii/windowsxp.res0000755000175000017500000000134007374562764020327 0ustar mihmih  0  Windows Shell mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2nii.dpr0000755000175000017500000000070511473723712017575 0ustar mihmihprogram dcm2nii; {$IFDEF FPC} {$mode objfpc} {$ELSE} {$APPTYPE CONSOLE} {$ENDIF} {$H+} uses {$IFDEF UNIX} {$IFDEF UseCThreads} cthreads, {$ENDIF} {$ENDIF} dialogsx,paramstrs,dicomtypes; {$IFNDEF UNIX} {$R *.res} {$ENDIF} begin ShowMsg(kVers); kUseDateTimeForID := true; {$IFNDEF TEST} ProcessParamStrs; {$ELSE} Testdcm2nii; readln; {$ENDIF} end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/pref_form.dfm0000755000175000017500000000741012360762464020213 0ustar mihmih TPREFSFORM0TPF0 TPrefsForm PrefsFormLeftdTops BorderStylebsDialogCaptiondcm2nii Preferences ClientHeight ClientWidth'Color clBtnFace Font.CharsetDEFAULT_CHARSET Font.Color clWindowText Font.Height Font.Name MS Sans Serif Font.Style OldCreateOrderPositionpoScreenCenter PixelsPerInch` TextHeight TLabelLabel1LefthTopWidthHeight CaptionRecursive Folder Search DepthTLabel OutDirLabelLeftTopWidth>Height Caption \home\folder TGroupBox FilenameBoxLeftTopWidthHeightqCaptionOutput FilenameTabOrder TCheckBox DateCheckLeftTopWidthaHeightCaptionAcquisition DateTabOrderOnClickFilenameChecks TCheckBox SeriesCheckLeftTopPWidthHeightCaptionAcquisition SeriesTabOrderOnClickFilenameChecks TCheckBox ProtocolCheckLeftTop0WidthHeightCaption Protocol NameTabOrderOnClickFilenameChecks TCheckBoxPatientNameCheckLeftTop@WidthHeightCaption Patient NameTabOrderOnClickFilenameChecks TCheckBoxInputNameCheckLeftTop WidthHeightCaptionInput FilenameTabOrderOnClickFilenameChecks TCheckBoxNotAnonymizeCheckLeftTopWidthHeightHintIf checked, the patient name will be copied from the DICOM file to the NIfTI header. If unchecked, the image will be anonymized.Caption!Save Patient Name in NIfTI headerParentShowHintShowHint TabOrder TCheckBox ReorientCheckLeftTop8WidthHeightHint 'If checked, images with an image matrix greater than 255 will be reoriented to the axial plane. For example, an anatomical image with a 256x256 matrix will be resliced to appear in the axial plane. This allows the images to appear correctly oriented when viewed with FSLview, and can improve normalization with FSL. Images with matrix sizes smaller than 255 are not influenced: reorienting fMRI data (~64x64 matrices) can disrupt slice timing correction and reorienting DTI data (~128x128 matrices) can disrupt interpretation of the prinicple vectors.Caption1Reorient large images to nearest orthogonal planeParentShowHintShowHint TabOrderTButtonOKBtnLeftTopWidthKHeightCaptionOK ModalResultTabOrderTButton CancelBtnLeftxTopWidthKHeightCaptionCancel ModalResultTabOrder TSpinEdit RecursiveSpinLeftTopWidthQHeightHintIf this is set to zero, only files directly in the selected folder will be converted. If set to two, then all the files in the selected folder, subfolders and sub-subfolders will be processed. MaxValue'MinValueParentShowHintShowHint TabOrderValue TComboBox OutputComboLeftTopWidthHeightStylecsDropDownList ItemHeight TabOrderOnChangeOutputComboChange Items.StringsSave to source folderPrompt user for output folderAlways save to ... TCheckBox CollapseCheckLeftTopPWidthqHeightHint^If checked, all images are sorted regardless of folder (slower, but required for some systems)CaptionCollapse foldersParentShowHintShowHint TabOrder TCheckBoxStack3DImagesWithSameAcqNumLeftTophWidthHeightHint^If checked, all images are sorted regardless of folder (slower, but required for some systems)Caption+Stack 3D images with same acquistion numberParentShowHintShowHint TabOrderTButton TextEditorBtnLeftTopWidthHeightCaption Text Edit ModalResultTabOrder OnClickTextEditorBtnClick TCheckBoxWritePrefsOnQuitLeftTopPWidthyHeightCaptionWritePrefsOnQuitChecked State cbCheckedTabOrder Visible TCheckBoxTxtReportCheckLeftTop WidthHeightHint@This could store useful information (beware of anonymity issues)Caption+Save text report (scan and patient details)ParentShowHintShowHint TabOrder mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2nii.cfg0000755000175000017500000000101212360762704017537 0ustar mihmih-$A8 -$B- -$C+ -$D+ -$E- -$F- -$G+ -$H+ -$I+ -$J+ -$K- -$L+ -$M- -$N+ -$O+ -$P+ -$Q- -$R- -$S- -$T- -$U- -$V+ -$W- -$X+ -$YD -$Z1 -cg -AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; -H+ -W+ -M -$M16384,1048576 -K$00400000 -LE"c:\program files (x86)\borland\delphi7\Projects\Bpl" -LN"c:\program files (x86)\borland\delphi7\Projects\Bpl" -U"..\common\;..\delphionly\" -O"..\common\;..\delphionly\" -I"..\common\;..\delphionly\" -R"..\common\;..\delphionly\" mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2nii.lpi0000755000175000017500000003560712377622175017612 0ustar mihmih mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dicomfastread.pas0000755000175000017500000005142312307644164021056 0ustar mihmihunit dicomfastread; {$H+} //this is x3 faster than the dicomcompat routines, but only works with well-behaved Explicit Little-Endian DICOM interface //0008,0070,ManufacturerID //Next values for Philips //Philips - must set 2001,105F length to 8 - allows reading of stack sequence // 2005,1071. Philips AP angulation // 2005,1072. Philips RL angulation // 2005,1073. Philips FH angulation //2001,100B Philips slice orientation (TRANSVERSAL, AXIAL, SAGITTAL) // Next values for GE //0019,10bb (or 0019,a0bb)= X diffusion direction //0019,10bc (or 0019,a0bc)= Y diffusion direction //0019,10bd (or 0019,a0bd)= Z diffusion direction //0018,1312 = phase encoding. uses {$IFNDEF FPC}Controls, {$ENDIF} SysUtils,define_types,classes,dicomtypes; function fast_read_dicom_datax(var lDICOMdata: DICOMdata; lOffset,lFileSz: integer; var lFileName: string): boolean; //x3 faster! procedure read_philips_hidden(var lFilename: string; lOffset,lLength: integer; var lDICOMdata: DICOMdata); function orientation_not_visible( lDICOMdata: DICOMdata) : boolean; implementation uses dialogsx, dialogs_msg; {$DEFINE notANON} function fast_read_dicom_datax(var lDICOMdata: DICOMdata; lOffset,lFileSz: integer; var lFileName: string): boolean; const kMaxBuf = (256*256)-1; //bytes kMax16bit = (256*256)-1; kImageType = $00080008; kStudyDate = $00210008; kSeriesDate = $00210008; kAcqDate = $00220008; kCreateDate = $00120008; kStudyTime = $00300008; kPatientName = $00100010; {$IFDEF ANON} //position and lengths of tags to anonymize kPatientID = $00200010; kPatientDOB = $00300010; kPatientSex = $00400010; kPatientAge = $10100010; kPatientWt = $10300010; {$ENDIF} kSeq = $00200018; kZThick = $00500018; kTR = $00800018; kTE = $00810018; kEchoNum = $00860018; kZSpacing = $00880018; kProtocolName = $10300018; kPatientPos = $51000018; kSeriesNum = $00110020; kAcquNum = $00120020; kImageNum = $00130020; kOrientation = $00370020; kLocation = $10410020; kDim3 = $00080028; kDim2 = $00100028; kDim1 = $00110028; kXYSpacing = $00300028; kPosition = $00320020; knVol = $01050020; kAlloc = $01000028; kIntercept = $10520028; kSlope = $10530028; kCSAImageHeaderInfo = $10100029; kSlicesPer3DVol = $10182001; kTransferSyntax = $00100002; kImageStart = $00107FE0; kPhilipsPhantom1 = $91130020;//$0020+($9113 shl 16 ); kPhilipsPhantom2 = $91160020; kPhilipsPhantom3 = $91100028; kPhilipsDTIv1 = $10b02005; kPhilipsDTIv2 = $10b12005; kPhilipsDTIv3 = $10b22005; kMaxFloats = 6; var vr : array [1..2] of Char; lByteRA: Bytep; lFloatRA: array [1..kMaxFloats] of double; lBufferSz,lPos,lBuffStart: integer; lInFile: file; lBufferError: boolean; procedure Str2FloatNum ( lStr: string; lnFloats: integer); var lFStr: string; lP,lnF: integer; begin if (length(lStr) < 1) or (lnFloats < 1) or (lnFloats > kMaxFloats) then exit; for lnF := 1 to lnFloats do lFloatRA[lnF] := 1; lStr := lStr + ' '; //terminator lFStr := ''; lP := 1; lnF:= 0; while lP <= length(lStr) do begin if lStr[lP] in ['+','-','0'..'9','.','e','E'] then lFStr := lFStr + lStr[lP] else if (lFStr <> '') then begin inc(lnF); //if lnFloats = 6 then showmessage(lFStr); try lFloatRA[lnF] := strtofloat(lFStr); except on EConvertError do lFloatRA[lnF] := 1; end;//except if lnF = lnFloats then exit; lFStr := ''; end; inc(lP); end; end; //function Str2Float function GetByte (lFilePos: integer): byte; var lBufPos: integer; begin //the following error checking slows down reads a lot! //a simpler alternative would be to make the buffer size the same size as the entire image... //the current strategy saves memory and is faster for large images with small headers if lFilepos > lFileSz then begin lBufferError := true; result := 0; exit; end; lBufPos := lFilepos - lBuffStart+1; if (lBufPos > lBufferSz) or (lBufPos < 1) then begin //reload buffer if lFilePos+kMaxBuf > lFileSz then lBufferSz := lFileSz - (lFilePos) else lBufferSz := kMaxBuf; //read remaining AssignFile(lInFile, lFileName); FileMode := 0; //Set file access to read only Reset(lInFile, 1); seek(lInFile,lFilePos); BlockRead(lInFile, lByteRA^[1], lBufferSz); CloseFile(lInFile); FileMode := 2; lBuffStart := lFilePos; lBufPos := 1; end; result := lByteRA^[lBufPos]; end; function ReadInt4: int64; begin if lDicomData.little_endian = 0 then result := GetByte(lPos+3)+(GetByte(lPos+2) shl 8)+(GetByte(lPos+1) shl 16)+(GetByte(lPos) shl 24) else result := GetByte(lPos)+(GetByte(lPos+1) shl 8)+(GetByte(lPos+2) shl 16)+(GetByte(lPos+3) shl 24); inc(lPos,4); end; //function Read4 function ReadCardinal: int64; begin if lDicomData.little_endian = 0 then result := GetByte(lPos+3)+(GetByte(lPos+2) shl 8)+(GetByte(lPos+1) shl 16)+(GetByte(lPos) shl 24) else result := GetByte(lPos)+(GetByte(lPos+1) shl 8)+(GetByte(lPos+2) shl 16)+(GetByte(lPos+3) shl 24); inc(lPos,4); end; //function Read4 procedure ReadGroupElementLength(var lGroupElement: int64; var lLength: integer); begin lGroupElement := ReadCardinal; VR := 'AA'; vr[1] := chr(GetByte(lPos)); vr[2] := chr(GetByte(lPos+1)); if vr[2] < 'A' then begin //implicit vr with 32-bit length lLength := ReadInt4; exit; end; if (vr = 'OB') or (vr = 'OW') or (vr = 'SQ') then begin {explicit VR with 32-bit length} lPos := lPos + 4; {skip 2 byte string and 2 reserved bytes = 4 bytes = 2 words} lLength := ReadInt4;//Ord4(buf[lPos]) + $100 * (buf[lPos+1] + $100 * (buf[lPos+2] + $100 * buf[lPos+3])) end else begin {explicit VR with 16-bit length} if lDicomData.little_endian = 0 then lLength := (GetByte(lPos+3))+(GetByte(lPos+2) shl 8) else lLength := (GetByte(lPos+2))+(GetByte(lPos+3) shl 8);//GetLength := Ord4(buf[i+2]) + $100 * (buf[i+3]); lPos := lPos + 4; {skip 2 byte string and 2 length bytes = 4 bytes = 2 words} end; if (lGroupElement = kPhilipsPhantom1) or (lGroupElement = kPhilipsPhantom2) or (lGroupElement = kPhilipsPhantom3) then begin //crucial Philips values are nested inside this string... //fx(666); //kX := true; lLength := 8; end; end; //procedure ReadGroupElementLength function DCMStr(lBytes: integer): string; var lC: integer; begin result := ''; if lBytes < 1 then exit; for lC := lPos to (lPos+(lBytes-1)) do result := result + char(GetByte(lC)); for lC := 1 to lBytes do if result[lC] in ['+','-','/','\',' ','0'..'9','a'..'z','A'..'Z','.'] then else result[lC] := ' '; end; //function DCMStr function DCMStr2Int (lBytes: integer): integer; var lErr: integer; lStr: string; begin lStr := DCMStr(lBytes); Val(lStr,result,lErr); end; //function DCMStr2Int procedure DCMStr2FloatNum (lBytes,lnFloats: integer); begin Str2FloatNum (DCMStr(lBytes), lnFloats); end; //function DCMStr2Float function DCMStr2Float (lBytes: integer): single; begin DCMStr2FloatNum (lBytes,1); result := lFloatRA[1]; end; //function DCMStr2Float procedure DCMStr2Float2 (lBytes: integer; var lF1,lF2: double); begin DCMStr2FloatNum (lBytes,3); lF1 := lFloatRA[1]; lF2 := lFloatRA[2]; end; //function DCMStr2Float2 procedure DCMStr2Float3 (lBytes: integer; var lF1,lF2,lF3: double); begin DCMStr2FloatNum (lBytes,3); lF1 := lFloatRA[1]; lF2 := lFloatRA[2]; lF3 := lFloatRA[3]; end; //function DCMStr2Float3 procedure DCMStr2Float6 (lBytes: integer; var lF1,lF2,lF3,lF4,lF5,lF6: double); begin DCMStr2FloatNum (lBytes,6); lF1 := lFloatRA[1]; lF2 := lFloatRA[2]; lF3 := lFloatRA[3]; lF4 := lFloatRA[4]; lF5 := lFloatRA[5]; lF6 := lFloatRA[6]; end; //function DCMStr2Float6 function DCMint (lBytes: integer): integer; //read 16 bit short integer begin if lBytes <= 2 then result := GetByte(lPos)+(GetByte(lPos+1) shl 8) //shortint vs word? else result := GetByte(lPos)+(GetByte(lPos+1) shl 8)+(GetByte(lPos+2) shl 16)+(GetByte(lPos+3) shl 24);; //byte order?? end; //function DCMint function DCMsingle (lBytes: integer): single; //read 16 bit short integer type swaptype = packed record case byte of 0:(b0,b1,b2,b3 : word); //word is 16 bit 1:(float:single); end; var outguy:swaptype; begin outguy.b0 := GetByte(lPos); outguy.b1 := GetByte(lPos+1); outguy.b2 := GetByte(lPos+2); outguy.b3 := GetByte(lPos+3); result:=outguy.float; end; {$IFDEF ANON} Type TPosLen = RECORD //peristimulus plot Pos,Len: integer; end; procedure InitPosLen(var lPL: TPOsLen); begin lPL.Pos := 0; lPL.Len := 0; end; procedure SetPosLen(var lPL: TPosLen; lP,lL: integer); begin lPL.Pos := lP; lPL.Len := lL; end; procedure Anonymize(lStr: string; lPL: TPOsLen{lPos,lLen: integer}); var lDCMstr: string; lP,lL: integer; begin if ((lPL.Pos+lPL.Len) > lBufferSz) or (lPL.Len < 1) or (lPL.Pos < 1) then exit; lDCMStr := ''; lL := length(lStr); if lL > lPL.Len then lL := lPL.Len; lP := 1; while lP <= lL do begin lDCMStr := lDCMStr + lStr[lP]; inc(lP); end; while lP <= lPL.Len do begin //pad string lDCMStr := lDCMStr + ' '; inc(lP); end; for lP := 1 to lPL.Len do lByteRA^[lPL.Pos+lP] := Ord(lDCMstr[lP]); end; {$ENDIF} var lTempStr,lStr: string; lGroupElement: int64; lTemp,lLength,lEchoNum,lnVol: integer; lResearchMode: boolean; lThick: double; {$IFDEF ANON} //position and lengths of tags to anonymize lCreateDate,lName,lID,lDOB,lSex,lAge,lWt,lStudyDate,lSeriesDate,lAcqDate: TPosLen; {$ENDIF} begin //function fast_read_dicom_data {$IFDEF ANON} //position and lengths of tags to anonymize InitPosLen(lName); InitPosLen(lID); InitPosLen(lDOB); InitPosLen(lSex); InitPosLen(lAge); InitPosLen(lWt); InitPosLen(lStudyDate); InitPosLen(lSeriesDate); InitPosLen(lAcqDate); InitPosLen(lCreateDate); {$ENDIF} lnVol := 1; lEchoNum := 1; lThick := 0; clear_dicom_data(lDicomData); lDicomData.little_endian := 1; result := false; lResearchMode := false; lBufferError := false; if lFileSz < 1 then lFileSz := FSize(lFilename); lBufferSz := lFileSz-lOffset; if lBufferSz < 512 then begin //showmessage('Error: File too small '+lFilename); exit; end; if lBufferSz > kMaxBuf then lBufferSz := kMaxBuf; GetMem(lByteRA,kMaxBuf); lBufferSz := lBufferSz; AssignFile(lInFile, lFileName); FileMode := 0; //Set file access to read only Reset(lInFile, 1); seek(lInFile,lOffset); BlockRead(lInFile, lByteRA^[1], lBufferSz); CloseFile(lInFile); FileMode := 2; lBuffStart := lOffset; lPos := lOffset; if lOffset = 128 then begin //DICOM files start with DICM at 128, Siemens shadow headers do not if DCMStr(4) <> 'DICM' then begin dcmMsg(DCMStr(4)+ ' <> DICM'); FreeMem(lByteRA); exit; end; lPos := lOffset + 4;//DICM read end;//Offset = 128 //next check VR if not( chr(GetByte(lPos+4)) in ['A'..'Z']) or not( chr(GetByte(lPos+5)) in ['A'..'Z']) then dcmMsg('implicit VR untested'); //next check Endian lTemp := lPos; ReadGroupElementLength(lGroupElement,lLength); if lLength > kMax16bit then dcmMsg('ByteSwapped'); lPos := lTemp; //end VR check result := true; while (lDICOMData.imagestart = 0) and (not lBufferError) do begin ReadGroupElementLength(lGroupElement,lLength); case lGroupElement of kTransferSyntax: begin lTempStr := (DCMStr(lLength)); if (length(lTempStr) >= 19) and (lTempStr[19] = '2') then lDicomData.little_endian := 0; end; kImageType : begin lTempStr := DCMStr(lLength); //read last word - ver\mosaic -> MOSAIC lStr := ''; lTemp := length(lTempStr); while (lTemp > 0) and (lTempStr[lTemp] in ['a'..'z','A'..'Z']) do begin lStr := upcase(lTempStr[lTemp])+lStr; dec(lTemp); end; if lStr = 'MOSAIC' then lDicomData.SiemensMosaicX := 2; //we need to read numaris for details... end; kStudyTime : lDicomData.StudyTime := DCMStr(lLength); {$IFDEF ANON} //position and lengths of tags to anonymize kCreateDate: begin SetPosLen(lCreateDate,lPos,lLength) end; kSeriesDate: begin SetPosLen(lSeriesDate,lPos,lLength) end; kAcqDate: begin SetPosLen(lAcqDate,lPos,lLength) end; kStudyDate: begin SetPosLen(lStudyDate,lPos,lLength) end; kPatientName : begin SetPosLen(lName,lPos,lLength) end; kPatientID : begin SetPosLen(lID,lPos,lLength) end; kPatientDOB : begin SetPosLen(lDOB,lPos,lLength) end; kPatientSex : begin SetPosLen(lSex,lPos,lLength) end; kPatientAge : begin SetPosLen(lAge,lPos,lLength) end; kPatientWt : begin SetPosLen(lWt,lPos,lLength) end; {$ELSE} kPatientName : lDicomData.PatientName := DCMStr(lLength); kStudyDate: lDicomData.StudyDate := DCMStr(lLength); {$ENDIF} kProtocolName : lDicomData.ProtocolName :=DCMStr(lLength); kPatientPos : lDicomData.PatientPos :=DCMStr(lLength); //should be HFS for Siemens = Head First Supine kSeriesNum : lDicomData.SeriesNum := DCMStr2Int(lLength); kAcquNum : lDicomData.AcquNum := DCMStr2Int(lLength); kSeq: begin if DCMStr(lLength) = 'RM' then lResearchMode := True; end; kImageNum : lDicomData.ImageNum := DCMStr2Int(lLength); kDim3 :lDicomData.XYZdim[3] := DCMStr2Int(lLength); kDim2 : lDicomData.XYZdim[2] := DCMint (lLength); kDim1 : lDicomData.XYZdim[1] := DCMint (lLength); kLocation : lDICOMData.Location := DCMStr2Float(lLength); kAlloc: lDicomData.Allocbits_per_pixel := DCMint (lLength); kTR : lDicomData.TR := DCMStr2Float(lLength); kTE: lDicomData.TE := DCMStr2Float(lLength); kEchoNum: lEchoNum := round (DCMStr2Float(lLength)); kSlope : lDICOMData.IntenScale := DCMStr2Float(lLength); kIntercept : lDICOMData.IntenIntercept := DCMStr2Float(lLength); kOrientation : DCMStr2Float6(lLength, lDicomData.Orient[1], lDicomData.Orient[2],lDicomData.Orient[3],lDicomData.Orient[4], lDicomData.Orient[5],lDicomData.Orient[6]); kPosition : DCMStr2Float3 (lLength,lDicomData.PatientPosX, lDicomData.PatientPosY,lDicomData.PatientPosZ); knVol: lnVol := round (DCMStr2Float(lLength)); kZThick: begin lThick := DCMStr2Float(lLength); lDICOMData.XYZmm[3] := lThick; end;//used differently by manufacturers kZSpacing: begin lDICOMData.XYZmm[3] := DCMStr2Float(lLength); if (lThick/2) > lDICOMdata.XYZmm[3] then lDICOMdata.XYZmm[3] := lDICOMdata.XYZmm[3] + lThick end; //used different by different manufacturers kXYSpacing: begin DCMStr2Float2 (lLength, lDICOMdata.XYZmm[2], lDICOMdata.XYZmm[1]); end; kCSAImageHeaderInfo: begin //order ICE,Acq,Num,Vector lDICOMdata.CSAImageHeaderInfoPos := lPos; lDICOMdata.CSAImageHeaderInfoSz := lLength; end; kSlicesPer3DVol: lDICOMData.SlicesPer3DVol := DCMint (lLength); kImageStart: lDICOMData.ImageStart := lPos ; //-1 as indexed from 0.. not 1.. end; //Case lGroupElement //Msg(VR+inttohex(lGroupElement and kMax16bit,4) +':'+inttohex( lGroupElement shr 16,4)+' '+inttostr(lLength)+'@'+inttostr(lPos) ); //msg(inttostr(lPos)+' '+inttostr(lLength)); lPos := lPos + (lLength); end; //while imagestart=0 and not error //clean up lDicomData.DateTime := StudyDateTime(lDicomData.StudyDate,lDicomData.StudyTime); if (lDicomData.SiemensMosaicX > 1) then lDicomData.AcquNum := 1; if (lEchoNum > 1) and (lEchoNum < 16) then lDicomData.AcquNum := lDicomData.AcquNum + (100*lEchoNum); if lResearchMode then lDicomData.SeriesNum := lDicomData.SeriesNum + 100; if (lDICOMData.SlicesPer3DVol > 0) and (lnVol > 1) and (lDicomdata.XYZdim[3] > 1) and (lDicomData.SlicesPer3DVol > 0)and ((lDicomdata.XYZdim[3] mod lDicomData.SlicesPer3DVol) = 0) then lDICOMdata.File4D := true; if not lBufferError then result := true; FreeMem(lByteRA); //Remaining portions only if anonymizing {$IFDEF ANON} Msg('Anonymizing DICOM '+extractfilename(lFilename)); lBufferSz := lFileSz; GetMem(lByteRA,lBufferSz); //read original AssignFile(lInFile, lFileName); FileMode := 0; //Set file access to read only Reset(lInFile, 1); //seek(lInFile,1); BlockRead(lInFile, lByteRA^[1], lBufferSz); CloseFile(lInFile); //anonymize... Anonymize ('ANONYMIZED',lName); Anonymize ('ANONYMIZED',lID); Anonymize('19890323',lDOB); //Cold Fusion YYYYMMDD Anonymize('19890323',lStudyDate); //Cold Fusion YYYYMMDD Anonymize('19890323',lAcqDate); //Cold Fusion YYYYMMDD Anonymize('19890323',lSeriesDate); //Cold Fusion YYYYMMDD Anonymize('19890323',lCreateDate); //Cold Fusion YYYYMMDD Anonymize('M',lSex); Anonymize('18',lAge); Anonymize('100',lWt); //write anonymized data... assignfile(lInFile, lFileName+'.dcm'); Filemode := 2; //read&write Rewrite(lInFile,1); BlockWrite(lInFile, lByteRA^[1],lBufferSz); CloseFile(lInFile); //clean up... FreeMem(lByteRA); {$ENDIF} end; //function fast_read_dicom_data function orientation_not_visible( lDICOMdata: DICOMdata) : boolean; var li : integer; lDICOMdataX: DICOMdata; begin result := false; clear_dicom_data(lDicomDataX); for li := 1 to 2 do //only XY-direction - as philips reports correct Z in header if lDICOMdata.XYZmm[li] <> lDICOMdataX.XYZmm[li] then exit; for li := 1 to 6 do if lDicomData.Orient[li] <> lDicomDataX.Orient[li] then exit; if lDicomData.PatientPosX <> lDicomDataX.PatientPosX then exit; if lDicomData.PatientPosY <> lDicomDataX.PatientPosY then exit; if lDicomData.PatientPosZ <> lDicomDataX.PatientPosZ then exit; result := true; end; procedure read_philips_hidden(var lFilename: string; lOffset,lLength: integer; var lDICOMdata: DICOMdata); var li : integer; lDICOMdataX: DICOMdata; begin if not fast_read_dicom_datax(lDICOMdataX, lOffset+8, lOffset+lLength, lFileName) then exit; //fx(lDICOMdataX.XYZmm[1],lDICOMdataX.XYZmm[2]); for li := 1 to 2 do //only XY-direction - as philips reports correct Z in header lDICOMdata.XYZmm[li] := lDICOMdataX.XYZmm[li]; for li := 1 to 6 do lDicomData.Orient[li] := lDicomDataX.Orient[li]; lDicomData.PatientPosX := lDicomDataX.PatientPosX; lDicomData.PatientPosY := lDicomDataX.PatientPosY; lDicomData.PatientPosZ := lDicomDataX.PatientPosZ; end; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2nii.ini0000755000175000017500000000163112153700516017557 0ustar mihmih[BOOL] 4D=1 Anonymize=1 SingleNIIFile=1 Gzip=1 SPM2=0 AppendDate=0 AppendAcqSeries=1 AppendProtocolName=1 AppendPatientName=0 AppendFilename=0 EveryFile=1 ManualNIfTIConv=1 AnonymizeSourceDICOM=0 Swizzle4D=1 Stack3DImagesWithSameAcqNum=0 RecursiveUseNameAppend=0 CustomRename=0 disablereorient=0 enablereorient=1 createoutputfolder=0 CollapseFolders=0 Verbose=0 AutoCrop=0 fourD=1 PhilipsPrecise=0 UseGE_0021_104F=0 DebugMode=0 UntestedFeatures=0 OrthoFlipXDim=0 UINT16toFLOAT32=1 [INT] BeginClip=0 LastClip=0 MinReorientMatrix=255 RecursiveFolderDepth=5 MaxReorientMatrix=1023 OutDirMode=0 IgnoreDTIRotationsIf_0002_0013_atleast=15 IgnoreDTIRotationsIf_0018_1020_atleast=15 SiemensDTIUse0019If00181020atleast=15 SiemensDTINoAngulationCorrectionIf00181020atleast=1000 SiemensDTIStackIf00181020atleast=15 usePigz=0 [STR] BackupDir= OutDir=C:\Users\neuropsych\Documents mricron-0.20140804.1~dfsg.1.orig/dcm2nii/gui.pas0000755000175000017500000011315712306710562017033 0ustar mihmihunit gui; {$IFDEF FPC}{$mode objfpc}{$H+}{$ENDIF} interface uses {$IFDEF FPC}LResources,LCLIntf, {$ELSE} Messages,{$ENDIF} {$IFNDEF UNIX} Windows,ShellAPI,ShlObj, {$ELSE} //BaseUnix, LCLType, {$ENDIF} //Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,StdCtrls, //ToolWin, //ComCtrls, ExtCtrls, nifti_types, //IniFiles, define_types,sortdicom,//dicom, parconvert, //filename,convert, nifti_hdr,ConvertSimple, userdir, paramstrs,nii_math,dicomtypes,nii_crop, nii_orient, nii_4dto3d,nii_asl,nii_reslice, Menus,nii_3dto4d,prefs, GraphicsMathLibrary; {$IFDEF FPC} type { TMainForm } TMainForm = class(TForm) SelectDirectoryDialog1: TSelectDirectoryDialog;//<-Lazarus only - does not exist in Delphi 4 Label1: TLabel; MainMenu1: TMainMenu; File1: TMenuItem; Edit1: TMenuItem; Help1: TMenuItem; About1: TMenuItem; Copy1: TMenuItem; DICOMtoNIfTI1: TMenuItem; AnonymizeDICOM1: TMenuItem; Exit1: TMenuItem; ExtractDICOMdims1: TMenuItem; ExtractDICOMhdr1: TMenuItem; ExtractNIfTIhdrs1: TMenuItem; SumTPM1: TMenuItem; MirrorXdimension1: TMenuItem; UntestedMenu: TMenuItem; NIfTI3D4D1: TMenuItem; ModifyNIfTI1: TMenuItem; Preferences1: TMenuItem; Memo1: TMemo; OpenHdrDlg: TOpenDialog; Panel1: TPanel; TypeCombo: TComboBox; ResliceNIfTI1: TMenuItem; Deletenondcm1: TMenuItem; HalveMenu1: TMenuItem; procedure SavePrefs; procedure ExtractDICOMdims1Click(Sender: TObject); procedure ExtractDICOMhdr1Click(Sender: TObject); procedure ExtractNIfTIhdrs1Click(Sender: TObject); procedure FormClose(Sender: TObject; var vAction: TCloseAction); procedure FormDropFiles(Sender: TObject; const FileNames: array of String); procedure HalveMenu1Click(Sender: TObject); function OpenDialogExecute (lCaption: string;lAllowMultiSelect,lForceMultiSelect: boolean; lFilter: string): boolean; procedure CheckPrefs (var lPrefs: TPrefs; lWrite: boolean); function ConvertDCM2NII (lFilename: string; var lPrefs: TPrefs): boolean; procedure FormCreate(Sender: TObject); procedure Exit1Click(Sender: TObject); procedure Copy1Click(Sender: TObject); procedure About1Click(Sender: TObject); procedure Preferences1Click(Sender: TObject); procedure FormShow(Sender: TObject); procedure SumTPM1Click(Sender: TObject); procedure TypeComboChange(Sender: TObject); procedure AnonymizeDICOM1Click(Sender: TObject); procedure ModifyNIfTI1Click(Sender: TObject); procedure NIfTI3D4D1Click(Sender: TObject); procedure ResliceNIfTI1Click(Sender: TObject); procedure Deletenondcm1Click(Sender: TObject); procedure dcm2niiBtnClick(Sender: TObject); procedure MirrorXdimension1Click(Sender: TObject); function BrowseDialog(const Title: string): string; end; {$ELSE} type TMainForm = class(TForm) Label1: TLabel; MainMenu1: TMainMenu; File1: TMenuItem; Edit1: TMenuItem; Help1: TMenuItem; About1: TMenuItem; Copy1: TMenuItem; DICOMtoNIfTI1: TMenuItem; AnonymizeDICOM1: TMenuItem; Exit1: TMenuItem; ExtractDICOMdims1: TMenuItem; ExtractDICOMhdr1: TMenuItem; ExtractNIfTIhdrs1: TMenuItem; SumTPM1: TMenuItem; MirrorXdimension1: TMenuItem; UntestedMenu: TMenuItem; NIfTI3D4D1: TMenuItem; ModifyNIfTI1: TMenuItem; Preferences1: TMenuItem; Memo1: TMemo; OpenHdrDlg: TOpenDialog; Panel1: TPanel; TypeCombo: TComboBox; ResliceNIfTI1: TMenuItem; Deletenondcm1: TMenuItem; HalveMenu1: TMenuItem; procedure SavePrefs; procedure ExtractDICOMdims1Click(Sender: TObject); procedure ExtractDICOMhdr1Click(Sender: TObject); procedure ExtractNIfTIhdrs1Click(Sender: TObject); procedure FormClose(Sender: TObject; var vAction: TCloseAction); procedure FormDropFiles(Sender: TObject; const FileNames: array of String); procedure HalveMenu1Click(Sender: TObject); function OpenDialogExecute (lCaption: string;lAllowMultiSelect,lForceMultiSelect: boolean; lFilter: string): boolean; procedure CheckPrefs (var lPrefs: TPrefs; lWrite: boolean); function ConvertDCM2NII (lFilename: string; var lPrefs: TPrefs): boolean; procedure FormCreate(Sender: TObject); procedure Exit1Click(Sender: TObject); procedure Copy1Click(Sender: TObject); procedure About1Click(Sender: TObject); procedure Preferences1Click(Sender: TObject); procedure FormShow(Sender: TObject); procedure SumTPM1Click(Sender: TObject); procedure TypeComboChange(Sender: TObject); procedure AnonymizeDICOM1Click(Sender: TObject); procedure ModifyNIfTI1Click(Sender: TObject); procedure NIfTI3D4D1Click(Sender: TObject); procedure ResliceNIfTI1Click(Sender: TObject); procedure Deletenondcm1Click(Sender: TObject); procedure dcm2niiBtnClick(Sender: TObject); procedure MirrorXdimension1Click(Sender: TObject); function BrowseDialog(const Title: string): string; private procedure WMDropFiles(var Msg: TWMDropFiles); message WM_DROPFILES; //<-Delphi only - does not exist in Lazarus end; {$ENDIF} var MainForm: TMainForm; implementation uses untar,pref_form, nifti_form,niftiutil{$IFNDEF UNIX},ActiveX {$ENDIF}; {$IFNDEF FPC} {$R *.DFM} {$R windowsxp.res} {$ENDIF} procedure MsgX (lStr: string); begin MainForm.Memo1.Lines.Add(lStr); end; function is4D (var lHdr: TNIFTIhdr): boolean; begin if lHdr.dim[4] > 1 then result := true else result := false; end; function SelectProcessNIFTI (var lHdr: TNIFTIhdr; var lFilename: string): integer; begin result := -1; //returns -1 if error if is4D(lHdr) then begin NIfTIForm.Combo3D.visible := false; NIfTIForm.Combo4D.visible := true; end else begin //NIfTIForm.Combo3D.itemIndex := 2; NIfTIForm.Combo3D.visible := true; NIfTIForm.Combo4D.visible := false; end; NiftiForm.Combo4DChange(nil); NIftiForm.caption := extractfilename(lFilename); //next - let user specify task NiftiForm.showmodal; if (NiftiForm.ModalResult = mrCancel) then exit; if is4D(lHdr) then result := NiftiForm.Combo4D.ItemIndex else result := NiftiForm.Combo3D.ItemIndex; end; procedure ProcessNIfTI(lFilenames : TStrings; lPrefs: TPrefs); var l4D, lPrev4D, lByteSwap: boolean; lINc,lProcess: integer; lExt,lFilename,lOutname: string; lHdr: TNIFTIhdr; lO: TNIIOpts; begin if lFilenames.Count < 1 then exit; lPrev4D := false; //ignored in if statement - set only to avoid compiler warning lProcess := 0; //always set in if statement - set only to avoid compiler warning for lInc := 1 to lFilenames.Count do begin lFilename := lFilenames.Strings[lInc-1]; lExt := UpCaseExt(lFilename); if lExt ='.IMG' then lFilename := changefileext(lFilename,'.hdr'); if not NIFTIhdr_LoadHdr (lFilename, lHdr, lO) then begin MsgX('Unable to read as NifTI/Analyze' + lFilename); exit; end; l4D := is4D(lHdr); //choose process //fx( lFilenames.Count,777); if (lInc = 1) or (l4D <> lPrev4D) then begin lProcess := SelectProcessNIFTI(lHdr,lFilename); if lProcess < 0 then exit; lPrev4D := l4D; end; //next - convert image as specified SetOutputFormat(NIfTIForm.TypeCombo.ItemIndex,lPrefs); if l4D then begin case lProcess of 0: ChangeNIfTISubformat(lFilename,lHdr,lPrefs); 1: Reorder4D(lFilename, lHdr, lByteSwap,lPrefs); 2: Clip4D(lFilename, lHdr, false,lPrefs,NiftiForm.StartEdit.value, NiftiForm.EndEdit.value); 3: Float32NIfTI(lFilename, lPrefs); 4: FormulaNIfTI(lFilename,lPrefs, NiftiForm.ScaleEdit.value, NiftiForm.PowerEdit.value); 5: ASL_subtract(lFilename,false,{subtract} (NiftiForm.AsLCombo.itemIndex ),lPrefs); 6: CropNIfTIX(lFilename, lPrefs, NiftiForm.EndEdit.value, NiftiForm.StartEdit.value, 0,0,0,0 ); else showmessage('Unknown function'); end; //case combo end else begin //if 4d else 3d //Int16LogPtoZNIfTI32Z(lFilename, lPrefs); case lProcess of 0: ChangeNIfTISubformat(lFilename,lHdr,lPrefs); 1: Reorient(lFilename,lHdr, lPrefs,false,false); 2: begin lOutname := Reorient(lFilename,lHdr, lPrefs,false,false); if lOutname <> '' then CropNIfTI(lOutname,lPrefs); end;//2 3: CropNIfTIX(lFilename, lPrefs, NiftiForm.EndEdit.value, NiftiForm.StartEdit.value, 0,0,0,0 ); 4: SiemensPhase2RadiansNIfTI(lFilename, lPrefs); else showmessage('Unknown function'); end; //case 3d end; //if 4d else 3d end end; //for each image end; procedure PromptOutput (var lPrefs: TPrefs); begin if (lPrefs.OutDirMode = kOutDirModePrompt) then lPrefs.OutDir := GetDirPrompt(lPrefs.OutDir); //GetDirPrompt(lPrefs.OutDir); end; function TMainForm.ConvertDCM2NII (lFilename: string; var lPrefs: TPrefs): boolean; //returns true if files treated as DICOM or PAR/REC - these will search entire folder var lOutDir,lExt: String; lStartTime: DWord; lStrings : TStrings; begin {$IFDEF FPC} DefaultFormatSettings.DecimalSeparator := '.'; {$ELSE} DecimalSeparator := '.'; {$ENDIF} result := false; if (not Fileexists(lFilename)) and (not DirExists(lFilename)) then exit; PromptOutput ( lPrefs); result := true; //3/2011... do not clear here, so we can look across images... Memo1.lines.clear; MsgX(kVers); refresh; Memo1.lines.add('Converting '+lFilename); lOutDir := extractfiledir(lFilename); lStartTime := GetTickCount; if DirExists(lFilename) then begin RecursiveFolderSearch(lFilename,lFilename,lPrefs,0); lPrefs.NameAppend := ''; end else begin lExt := UpCaseExt(lFilename); {if (lExt = '.FDF') then ConvertSimple2NII(lFilename,lOutDir,lPrefs) else} if (lExt = '.REC') or (lExt = '.PAR') then begin LoadFileListPARREC(lFilename,lOutDir,lPrefs) end else if (lExt = '.TGZ') then DeTGZ(lFilename,lPrefs) else if (IsNiftiExt (lFilename)) or (IsVOIExt (lFilename)) then begin result := false; lStrings := TStringList.Create; lStrings.add(lFilename); ProcessNIfTI(lStrings,lPrefs); lStrings.Free; end else begin if (DirExists(lOutDir)) and (not lPrefs.Verbose) then RecursiveFolderSearch(lOutDir,lOutDir,lPrefs,0) else LoadFileList(lFilename,lOutDir,lPrefs); lPrefs.NameAppend := ''; end; end; Memo1.lines.add('Conversion completed in '+inttostr(GetTickCount-lStartTime)+' ms'); end; function ShowHeader (lFilename: string): boolean; var lPrefs: TPrefs; begin PrefsForm.ReadPrefs(lPrefs); lPrefs.verbose := true; MainForm.Memo1.lines.add('Location '+lFilename); result := MainForm.ConvertDCM2NII( lFilename,lPrefs); end; procedure ProcessFilenames(lFilenames : TStrings; lPrefs: TPrefs); var i: integer; lAllNII: boolean; begin if lFilenames.Count < 1 then exit; lAllNii := true; for i := 0 to (lFilenames.Count-1) do if (not (IsNiftiExt (lFilenames.Strings[i]))) and (not (IsVOIExt (lFilenames.Strings[i]))) then lAllNii := false; if lAllNii then begin ProcessNiFTI (lFilenames,lPrefs); exit; end; if ssCtrl in KeyDataToShiftState(vk_Shift) then begin for i := 0 to (lFilenames.Count-1) do ShowHeader (lFilenames.Strings[i]) end else MainForm.ConvertDCM2NII( lFilenames.Strings[0],lPrefs); end; {$IFNDEF FPC}//if delphi procedure TMainForm.WMDropFiles(var Msg: TWMDropFiles); var CFileName: array[0..MAX_PATH] of Char; lInc: integer; lPrefs: TPrefs; lStrings: TStrings; begin CheckPrefs(lPrefs,False); //lDone := false; lInc := 0; try lStrings := TStringList.Create; while (DragQueryFile(Msg.Drop, lInc, CFileName, MAX_PATH) > 0) {and (not lDone)} do begin lStrings.add(CFilename); Msg.Result := 0; inc(lInc); end; //while ProcessFilenames(lStrings,lPrefs); lStrings.Free; finally DragFinish(Msg.Drop); end; end; function TMainForm.BrowseDialog(const Title: string): string; var iFlag: integer; lpItemID : PItemIDList; BrowseInfo : TBrowseInfo; DisplayName : array[0..MAX_PATH] of char; TempPath : array[0..MAX_PATH] of char; begin iFlag := BIF_RETURNONLYFSDIRS; //iFlag := BIF_BROWSEINCLUDEFILES; //iFlag := BIF_BROWSEFORCOMPUTER; //iFlag := BIF_BROWSEFORPRINTER; Result:=''; FillChar(BrowseInfo, sizeof(TBrowseInfo), #0); with BrowseInfo do begin hwndOwner := Application.Handle; pszDisplayName := @DisplayName; lpszTitle := PChar(Title); ulFlags := iFlag; end; lpItemID := SHBrowseForFolder(BrowseInfo); if lpItemId <> nil then begin SHGetPathFromIDList(lpItemID, TempPath); Result := TempPath; GlobalFreePtr(lpItemID); end; end; {$ELSE} function TMainForm.BrowseDialog(const Title: string): string; begin result := ''; SelectDirectoryDialog1.title := Title; if not SelectDirectoryDialog1.execute then exit; result := SelectDirectoryDialog1.Filename; end; {$ENDIF} procedure TMainForm.dcm2niiBtnClick(Sender: TObject); var sTitle,lDirName: string; lPrefs: TPrefs; begin CheckPrefs(lPrefs,False); // {$IFNDEF UNIX} sTitle:='Choose a folder with DICOM images'; lDirName := BrowseDialog(sTitle); // {$ELSE} // if not OpenDialogExecute('Select DICOM images you wish to convert)',true,false,kAnyFilter) then // exit; // lDirName := extractfiledir( OpenHdrDlg.Filename); // {$ENDIF} ConvertDCM2NII(lDirName,lPrefs); end; procedure TMainForm.CheckPrefs (var lPrefs: TPrefs; lWrite: boolean); begin if lWrite then begin //showmessage('w'); //options if writing TypeCombo.ItemIndex := DefaultOutputFormat (lPrefs); (* if lPrefs.SPM2 then TypeCombo.ItemIndex := 0 //SPM2 3D hdr/img analyze else if not lPrefs.FourD then begin if not (lPrefs.SingleNIIFile) then TypeCombo.ItemIndex := 1 //SPM5 3D hdr/img else TypeCombo.ItemIndex := 2; //SPM8 3D nii end else if not lPrefs.SingleNIIFile then TypeCombo.ItemIndex := 3 //?? 4D hdr/img else if not lPrefs.GZip then TypeCombo.ItemIndex := 4 //FSL 4D nii else TypeCombo.ItemIndex := 5; //FSL 4D nii.gz *) exit; end; SetDefaultPrefs (lPrefs); PrefsForm.ReadPrefs(lPrefs); SetOutputFormat(TypeCombo.ItemIndex,lPrefs); lPrefs.AnonymizeSourceDICOM := false; end; (*procedure Fz; var lPrefs: TPrefs; lByteSwap: boolean; lExt,lFilename,lOutname,lNameWOExt: string; lHdr: TNIFTIhdr; begin lFilename := 'C:\dti64\rapid\fz3.nii'; lFilename := 'C:\t1\mx.nii'; if not NIFTIhdr_LoadHdr (lFilename, lHdr, lByteSwap) then begin MsgX('Unable to read as NifTI/Analyze' + lFilename); exit; end; MainForm.CheckPrefs(lPrefs,False); Reorient(lFilename, lHdr,lPrefs,false); end; *) (*procedure Fz; var lPrefs: TPrefs; lF: string; begin lF := 'C:\iceland\temp'; SetDefaultPrefs (lPrefs); lPrefs.AnonymizeSourceDICOM := true; MainForm.ConvertDCM2NII(lF,lPrefs); end;*) procedure TMainForm.FormCreate(Sender: TObject); begin {$IFDEF Darwin} Exit1.visible := false; {$ENDIF} {$IFNDEF UNIX}DragAcceptFiles(Handle, True);{$ENDIF} {$IFDEF FPC} DefaultFormatSettings.DecimalSeparator := '.'; {$ELSE} DecimalSeparator := '.'; {$ENDIF} Application.HintHidePause := 30000; {$IFDEF Darwin} {$IFNDEF LCLgtk} //only for Carbon compile DICOMtoNIfTI1.ShortCut := ShortCut(Word('D'), [ssMeta]); Copy1.ShortCut := ShortCut(Word('C'), [ssMeta]); Preferences1.ShortCut := ShortCut(Word('P'), [ssMeta]); About1.ShortCut := ShortCut(Word('A'), [ssMeta]); {$ENDIF}//Carbon {$ENDIF}//Darwin end; procedure TMainForm.Exit1Click(Sender: TObject); begin Close; end; procedure TMainForm.Copy1Click(Sender: TObject); begin Memo1.SelectAll; Memo1.CopyToClipboard; end; (*procedure testpermissions; var p,n,x,s: string; begin s:= '/usr/lib64/lazarus/cr/'; inputquery('cap','name',s); FilenameParts (s,p,n,x); if DirWritePermission(p) then showmessage('+'+p+'*'+n+'*'+x) else showmessage('-'+p+'*'+n+'*'+x); end; *) (*procedure testpermissions; var p,n,x,s: string; begin s:= '/usr/lib64/lazarus/test/dcm2niigui.ini'; if fpAccess (s,R_OK)=0 then //ensure user has read-access to prefs file... showmessage('dcm = 0'); s:= '/usr/lib64/lazarus/test/dcx.ini'; if fpAccess (s,R_OK)=0 then //ensure user has read-access to prefs file... showmessage('dcx = 0'); end; *) (*procedure Force32; var lPrefs: TPrefs; lI: integer; begin PrefsForm.ReadPrefs(lPrefs); for lI := 1 to 6 do NII_force32 ('C:\walker\vois\i'+inttostr(lI)+'.nii','C:\walker\vois\ri'+inttostr(lI)+'.nii',lPrefs); end;*) (*procedure Force32; var lPrefs: TPrefs; begin PrefsForm.ReadPrefs(lPrefs); Rescale_4Dtissuemaps ('C:\walker\vois\4Dsri1.nii','C:\walker\vois\TPMQ.nii',lPrefs); end;*) (*procedure Force32; var lPrefs: TPrefs; const kDir = 'C:\walker\i3\'; kTemp = kDir + 'TPM3.nii'; kTempSym = kDir + 'TPM3sym.nii'; begin //exit; PrefsForm.ReadPrefs(lPrefs); //scale_4Dtissuemaps ('C:\walker\vois\4Dsri1.nii','C:\walker\TPMLo.nii',lPrefs); //rge4DFiles ('C:\walker\TPMLo.nii','C:\walker\TPMHi.nii','C:\walker\TPMEX.nii',78,lPrefs); Insert3Din4D (kDir+'m1.nii.gz',kTemp,kTemp,1, lPrefs); Insert3Din4D (kDir+'m2.nii.gz',kTemp,kTemp,2, lPrefs); Insert3Din4D (kDir+'m3.nii.gz',kTemp,kTemp,3, lPrefs); Insert3Din4D (kDir+'m4.nii.gz',kTemp,kTemp,4, lPrefs); Insert3Din4D (kDir+'m5.nii.gz',kTemp,kTemp,5, lPrefs); Insert3Din4D (kDir+'m6.nii.gz',kTemp,kTemp,6, lPrefs); Rescale_4Dtissuemaps(kTemp,kTempSym,lPrefs,true); end; *) (*procedure Force32; var lPrefs: TPrefs; const kDir = 'C:\walker\i4\'; kTemp = kDir + 'TPM4.nii'; kTempSym = kDir + 'TPM4sym.nii'; begin //exit; PrefsForm.ReadPrefs(lPrefs); //scale_4Dtissuemaps ('C:\walker\vois\4Dsri1.nii','C:\walker\TPMLo.nii',lPrefs); //rge4DFiles ('C:\walker\TPMLo.nii','C:\walker\TPMHi.nii','C:\walker\TPMEX.nii',78,lPrefs); Insert3Din4D (kDir+'sm1.nii',kTemp,kTemp,1, lPrefs); Insert3Din4D (kDir+'sm2.nii',kTemp,kTemp,2, lPrefs); Insert3Din4D (kDir+'sm3.nii',kTemp,kTemp,3, lPrefs); Insert3Din4D (kDir+'sm4.nii',kTemp,kTemp,4, lPrefs); Insert3Din4D (kDir+'sm5.nii',kTemp,kTemp,5, lPrefs); Insert3Din4D (kDir+'sm6.nii',kTemp,kTemp,6, lPrefs); Rescale_4Dtissuemaps(kTemp,kTempSym,lPrefs,true); end; *) (*procedure Force32; var lPrefs: TPrefs; lMaskName: string; lHdr: TNIfTIHdr; lByteSwap, lSaveThresh3D: boolean; lV: integer; begin //exit; PrefsForm.ReadPrefs(lPrefs); if not MainForm.OpenDialogExecute('Select the mask image',false,false,kImgFilter) then exit; lMaskName := MainForm.OpenHdrDlg.Filename; if not NIFTIhdr_LoadHdr (lMaskName, lHdr, lByteSwap) then exit; if (lHdr.Dim[4] < 1) then exit; lSaveThresh3D := (MessageDlg('Save thresholded images for each individual?',mtCustom,[mbYes,mbNo], 0)=mrYes); for lV := 1 to lHdr.Dim[4] do if MainForm.OpenDialogExecute('Select NIfTI images you wish to mask with volume '+inttostr(lV),true,false,kImgFilter) then MaskImages(lMaskName, MainForm.OpenHdrDlg.Files,lPrefs,lV, lSaveThresh3D); end; *) (*procedure Force32; var lPrefs: TPrefs; lI: integer; //lMaskName: string; begin //exit; PrefsForm.ReadPrefs(lPrefs); if not MainForm.OpenDialogExecute('Select all the c1 (gray matter) images to binarize. The c2 (gray matter),c3,c4,c5,c6 images should be in th same folder.',true,false,kImgFilter) then exit; //lMaskName := ('C:\Documents and Settings\chris\Desktop\walkerseg\zero\wc120100128_102305t1saghiress002a1001.nii'); //Binarize(lMaskName,lPrefs); if MainForm.OpenHdrDlg.Files.count < 1 then exit; for lI := 0 to (MainForm.OpenHdrDlg.Files.count-1) do Binarize(MainForm.OpenHdrDlg.Files[lI],lPrefs); end; *) {$IFNDEF FPC} procedure MaskVBM; var lPrefs: TPrefs; lI: integer; lMaskName: string; begin PrefsForm.ReadPrefs(lPrefs); if not MainForm.OpenDialogExecute('Select all TEMPLATE c1 (gray matter) image.',false,false,kImgFilter) then exit; lMaskName := MainForm.OpenHdrDlg.Filename; if not MainForm.OpenDialogExecute('Select all the c1 (gray matter) images to binarize. The c2 (gray matter),c3,c4,c5,c6 images should be in th same folder.',true,false,kImgFilter) then exit; if MainForm.OpenHdrDlg.Files.count < 1 then exit; for lI := 0 to (MainForm.OpenHdrDlg.Files.count-1) do MaskImgs(lMaskName, MainForm.OpenHdrDlg.Files[lI],lPrefs, 0.02); end; {$ENDIF} {$IFNDEF FPC} procedure Mask; var lPrefs: TPrefs; lMaskName: string; lHdr: TNIfTIHdr; lO: TNIIOpts; lI,lV: integer; begin PrefsForm.ReadPrefs(lPrefs); if not MainForm.OpenDialogExecute('Select the mask image',false,false,kImgFilter) then exit; lMaskName := MainForm.OpenHdrDlg.Filename; if not NIFTIhdr_LoadHdr (lMaskName, lHdr, lO) then exit; lV := 1; //lSaveThresh3D := (MessageDlg('Save thresholded images for each individual?',mtCustom,[mbYes,mbNo], 0)=mrYes); //for lV := 1 to lHdr.Dim[4] do if not MainForm.OpenDialogExecute('Select NIfTI images you wish to mask with volume '+inttostr(lV),true,false,kImgFilter) then exit; if MainForm.OpenHdrDlg.Files.count < 1 then exit; for lI := 0 to (MainForm.OpenHdrDlg.Files.count-1) do MaskImg(lMaskName, MainForm.OpenHdrDlg.Files[lI], lPrefs, 1); end; {$ENDIF} function ExtNIIorIMG(lStr: string): boolean; var lExt: string; begin result := false; lExt := UpCaseExt(lStr); if (lExt = '.NII') or (lExt = '.NII.GZ') then result := true; if (lExt = '.IMG') {and (FSize(ChangeFileExt(lStr,'.hdr'))> 0)} then result := true; end; procedure NIIbatch (lDir,lS: string); begin with mainform.Memo1.lines do begin add('subjx = strvcat'+lS+';'); add('subj = cellstr(subjx);'); add('dir = '''+lDir+''';'); add('tic'); add('for i=1:length(subj)'); add(' filename = [dir,filesep,subj{i}];'); add(' nii_16bit(filename);'); add('end;'); add('toc'); end;//with end;//proc NIIbatch procedure NII2Mat; var str,pre,sTitle,lDirName: string; lSearchRec: TSearchRec; begin {$IFNDEF FPC} sTitle:='Choose a folder with DICOM images'; lDirName := MainForm.BrowseDialog(sTitle); {$ELSE} if not MainForm.OpenDialogExecute('Select DICOM images you wish to inspect)',true,false,kAnyFilter) then exit; lDirName := extractfiledir( MainForm.OpenHdrDlg.Filename); {$ENDIF} str := '('; pre := ''; {$IFDEF UNIX} if FindFirst(lDirName+pathdelim+'*',faAnyFile-faSysFile,lSearchRec) = 0 then begin {$ELSE} if FindFirst(lDirName+pathdelim+'*.*',faAnyFile-faSysFile,lSearchRec) = 0 then begin {$ENDIF} //lFilename := ''; repeat //lNewName := lNewDir+lSearchRec.Name; if (lSearchRec.Name = '.') or (lSearchRec.Name = '..') then begin // end else if (lSearchRec.Name <> '') and (ExtNIIorIMG(lSearchRec.Name)) and (not DirExists(lSearchRec.Name)) then begin str := str +pre+ ''''+extractfilename(lSearchRec.Name)+''''; pre:=',' end; //mainform.Memo1.lines.add(lSearchRec.Name); until (FindNext(lSearchRec) <> 0); end; FindClose(lSearchRec); str := str + ')'; if length(str) > 2 then NIIbatch (lDirName,str)//mainform.Memo1.lines.add(str) else mainform.Memo1.lines.add('No NIfTI images found in '+lDirName) end; (*procedure NII2Mat(lExt: string); var str,pre,sTitle,lDirName: string; lSearchRec: TSearchRec; begin {$IFNDEF FPC} sTitle:='Choose a folder with DICOM images'; lDirName := BrowseDialog(sTitle); {$ELSE} if not OpenDialogExecute('Select DICOM images you wish to inspect)',true,false,kAnyFilter) then exit; lDirName := extractfiledir( OpenHdrDlg.Filename); {$ENDIF} str := '('; pre := ''; {$IFDEF UNIX} if FindFirst(lDirName+pathdelim+'*.img',faAnyFile-faSysFile,lSearchRec) = 0 then begin {$ELSE} if FindFirst(lDirName+pathdelim+'*.img',faAnyFile-faSysFile,lSearchRec) = 0 then begin {$ENDIF} //lFilename := ''; repeat //lNewName := lNewDir+lSearchRec.Name; if (lSearchRec.Name = '.') or (lSearchRec.Name = '..') then begin // end else if (lSearchRec.Name <> '') and (not DirExists(lSearchRec.Name)) then begin str := str +pre+ ''''+extractfilename(lSearchRec.Name)+''''; pre:=',' end; //mainform.Memo1.lines.add(lSearchRec.Name); until (FindNext(lSearchRec) <> 0); end; FindClose(lSearchRec); str := str + ')'; mainform.Memo1.lines.add(str); end; *) (*procedure BenchMarkDicom; var lC: Integer; lS: TDateTime; var lDICOMdata: DICOMdata; lHdrOK, lImageFormatOK: boolean; lDynStr: string;var lFileName: string; var lPrefs: TPrefs ; begin SetDefaultPrefs (lPrefs); lS := Now; lFilename := '/Users/rorden/philips/T1_IM_0007'; for lC := 1 to 100 do read_dicom_data(true,false,false,false,false,false,false, lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName, lPrefs); Showmessage('Milliseconds elapsed '+ FormatDateTime('z', Now-lS) ); end; *) procedure TMainForm.About1Click(Sender: TObject); //var value: int64; begin //fx(VBversion('MR B13 4VB13A')); exit; //NII2Mat;exit; //BenchMarkDicom; {$IFNDEF FPC} if (ssCtrl in KeyDataToShiftState(vk_Shift)) then begin Mask; exit; end; if (ssShift in KeyDataToShiftState(vk_Shift)) then begin MaskVBM; exit; end; {$ENDIF} //force32; //showmessage(ExtractFileDirWithPathDelim('c:\pas')); //testpermissions; Showmessage(kVers+ kCR+'Fallback ini file: '+ changefileext(paramstr(0),'.ini')); end; procedure TMainForm.Preferences1Click(Sender: TObject); var lPrefs: TPrefs; begin PrefsForm.ReadPrefs(lPrefs); PrefsForm.Showmodal; if (PrefsForm.ModalResult = mrCancel) then PrefsForm.WritePrefs(lPrefs); end; (*procedure ShowDICOM (var lPrefs: TPrefs); var lDICOMdata: DICOMdata; lHdrOK,lImgOK: boolean; lDynStr,lFilename: string; begin lFilename := 'c:\i185386.MRDC.94'; read_dicom_data(true,true{not verbose},true,true,true,true,false, lDICOMdata, lHdrOK, lImgOK, lDynStr,lFileName,lPrefs ); msgX(lDynStr); end;*) procedure TMainForm.FormShow(Sender: TObject); var lPrefs: TPrefs; lIniName: string; begin MsgX(kVers); SetDefaultPrefs(lPrefs); lIniName := IniName;//changefileext(paramstr(0),'.ini'); //showmessage(changefileext(paramstr(0),'.ini')); (*lReadPrefs := true; if (ssShift in KeyDataToShiftState(vk_Shift)) then case MessageDlg('Shift key down during launch: do you want to reset the default preferences?', mtConfirmation, [mbYes, mbNo], 0) of { produce the message dialog box } mrYes: lReadPrefs := false; end; //case *) if not ResetDefaults {lReadPrefs} then begin {$IFNDEF UNIX} if (ParamCount > 0) then ProcessParamStrs else if fileexists (lIniName) then IniFile(True,lIniName, lPrefs) else IniFile(True,changefileext(paramstr(0),'.ini'), lPrefs); //this allows an administrator to create default startup //IniFile(True,lIniName, lPrefs); {$ELSE} if fileexists (lIniName) then IniFile(True,lIniName, lPrefs) else IniFile(True,changefileext(paramstr(0),'.ini'), lPrefs); //this allows an administrator to create default startup {$ENDIF} end; //lReadPrefs CheckPrefs(lPrefs,True); PrefsForm.WritePrefs(lPrefs); NIfTIForm.TypeCombo.ItemIndex := TypeCombo.ItemIndex; UntestedMenu.visible := lPrefs.UntestedFeatures; //ConvertDCM2NII('c:\b17\b17\b17.IMA',lPrefs); end; procedure TMainForm.TypeComboChange(Sender: TObject); begin NIfTIForm.TypeCombo.ItemIndex := TypeCombo.ItemIndex; end; procedure TMainForm.AnonymizeDICOM1Click(Sender: TObject); var sTitle,lDirName: string; lPrefs: TPrefs; begin CheckPrefs(lPrefs,False); lPrefs.AnonymizeSourceDICOM := true; sTitle:='Choose a folder with DICOM images'; lDirName := BrowseDialog(sTitle); ConvertDCM2NII(lDirName,lPrefs); end; function TMainForm.OpenDialogExecute (lCaption: string;lAllowMultiSelect,lForceMultiSelect: boolean; lFilter: string): boolean;//; lAllowMultiSelect: boolean): boolean; var lNumberofFiles: integer; begin OpenHdrDlg.Filter := lFilter;//kAnaHdrFilter;//lFilter; OpenHdrDlg.FilterIndex := 1; OpenHdrDlg.Title := lCaption; if lAllowMultiSelect then OpenHdrDlg.Options := [ofAllowMultiSelect,ofFileMustExist] else OpenHdrDlg.Options := [ofFileMustExist]; result := OpenHdrDlg.Execute; if not result then exit; if lForceMultiSelect then begin lNumberofFiles:= OpenHdrDlg.Files.Count; if lNumberofFiles < 2 then begin Showmessage('Error: This function is designed to overlay MULTIPLE images. You selected less than two images.'); result := false; end; end; end; procedure TMainForm.SavePrefs; var lPrefs: TPrefs; lIniName: string; begin lIniName := IniName;//changefileext(paramstr(0),'.ini'); CheckPrefs(lPrefs,False); if lPrefs.WritePrefsOnQuit then IniFile(False,lIniName, lPrefs); end; procedure TMainForm.FormClose(Sender: TObject; var vAction: TCloseAction); begin SavePrefs; end; procedure TMainForm.FormDropFiles(Sender: TObject; const FileNames: array of String); var lI,lN: integer; lPrefs: TPrefs; //lDone: boolean; lStrings: TStrings;//lFilename: string; begin //lDone := false; CheckPrefs(lPrefs,False); lN := length(FileNames); if lN < 1 then exit; lStrings := TStringList.Create; for lI := 0 to (lN-1) do lStrings.add(Filenames[lI]); ProcessFilenames(lStrings,lPrefs); lStrings.Free; end; procedure TMainForm.HalveMenu1Click(Sender: TObject); var lPrefs: TPrefs; lI: integer; begin PrefsForm.ReadPrefs(lPrefs); if not MainForm.OpenDialogExecute('Select image(s) you wish to LR flip',true,false,kImgFilter) then exit; if MainForm.OpenHdrDlg.Files.count < 1 then exit; for lI := 0 to (MainForm.OpenHdrDlg.Files.count-1) do ShrinkNII(MainForm.OpenHdrDlg.Files[lI], lPrefs); end; procedure TMainForm.ModifyNIfTI1Click(Sender: TObject); var lPrefs: TPrefs; begin if not OpenDialogExecute('Select NIfTI images you wish to modify)',true,false,kImgFilter) then exit; CheckPrefs(lPrefs,False); ProcessNIfTI(OpenHdrDlg.Files,lPrefs); end; //ModifyNIfTI1Click procedure TMainForm.NIfTI3D4D1Click(Sender: TObject); var lStrings: TStringList; lPrefs: TPrefs; begin if not OpenDialogExecute('Select the 3D NIfTI images you wish to stack)',true,false,kImgFilter) then exit; lStrings := TStringList.Create; lStrings.addstrings(OpenHdrDlg.Files); CheckPrefs(lPrefs,False); Stack3Dto4D(lStrings, False, lPrefs); lStrings.Free; end; procedure TMainForm.ResliceNIfTI1Click(Sender: TObject); var lDestName,lSourceName,lTargetName: string; lPos: integer; lPrefs: TPrefs; begin CheckPrefs(lPrefs,False); Memo1.lines.clear; refresh; MsgX(kVers); MsgX('This function reslices source images to match the dimensions of a target image.'); MsgX(' Images are assumed to be coregistered.'); MsgX(' The resulting images will have the orientation, voxel size and bounding box of the target image.'); MsgX(' Resliced images will be given the prefix ''r''.'); MsgX(' This function uses trilinear interpolation - there may be some loss of precision.'); if not OpenDialogExecute('Select target image',true,false,kImgFilter) then exit; lTargetName := OpenHdrDlg.Filename; if not OpenDialogExecute('Select images you wish to reslice to match target)',true,false,kImgFilter) then exit; for lPos := 1 to OpenHdrDlg.Files.Count do begin lSourceName := OpenHdrDlg.Files[lPos-1]; lDestName := ChangeFilePrefix (lSourceName,'r'); MsgX('Reslicing '+lSourceName +' to match dimensions of '+lTargetname+' resliced image = '+lDestName); Reslice2Targ (lSourceName,lTargetName,lDestName, lPrefs ); end; end; procedure DelRecursiveFolderSearch (lFolderName: string; lMaxDepth, lDepth: integer); var lNewDir,lNewName,lFilename,lExt: String; lSearchRec: TSearchRec; begin lNewDir := lFolderName+PathDelim; {$IFDEF UNIX} if FindFirst(lNewDir+'*',faAnyFile-faSysFile,lSearchRec) = 0 then begin {$ELSE} if FindFirst(lNewDir+'*.*',faAnyFile-faSysFile,lSearchRec) = 0 then begin {$ENDIF} lFilename := ''; repeat lNewName := lNewDir+lSearchRec.Name; if (lSearchRec.Name <> '.') and (lSearchRec.Name <> '..') then begin if DirExists(lNewName) then begin if lDepth < lMaxDepth then begin DelRecursiveFolderSearch(lNewName,lMaxDepth,lDepth+1); end; //exit;//4/4/2008 end else lFilename := lNewname; end; if (lFilename <> '') and (not DirExists(lNewName)) then begin lExt := UpCaseExt(lFilename); if (lExt <> '.DCM') then begin msgx('del '+lFilename); DeleteFile(lFilename); end; end; until (FindNext(lSearchRec) <> 0); end; FindClose(lSearchRec); end; procedure TMainForm.Deletenondcm1Click(Sender: TObject); var sTitle,lDirName: string; begin Showmessage('Warning: this command will delete all files that do not have the extension .dcm') ; sTitle:='Choose a folder with DICOM images'; lDirName := BrowseDialog(sTitle); DelRecursiveFolderSearch(lDirName,32,1); end; procedure TMainForm.MirrorXdimension1Click(Sender: TObject); //UntestedFeatures var lPrefs: TPrefs; lI: integer; begin PrefsForm.ReadPrefs(lPrefs); if not MainForm.OpenDialogExecute('Select image(s) you wish to LR flip',true,false,kImgFilter) then exit; if MainForm.OpenHdrDlg.Files.count < 1 then exit; for lI := 0 to (MainForm.OpenHdrDlg.Files.count-1) do LRFlip(MainForm.OpenHdrDlg.Files[lI], lPrefs); end; procedure TMainForm.SumTPM1Click(Sender: TObject); var lPrefs: TPrefs; lI: integer; begin PrefsForm.ReadPrefs(lPrefs); if not OpenDialogExecute('Select TPM to sum)',true,false,kAnyFilter) then exit; for lI := 1 to 5 do SumTPM(OpenHdrDlg.Filename,ChangeFilePrefix (OpenHdrDlg.Filename,'sum'+inttostr(lI)) ,lPrefs,lI); end; procedure TMainForm.ExtractDICOMdims1Click(Sender: TObject); var {$IFNDEF FPC}sTitle,{$ENDIF} lDirName: string; lPrefs: TPrefs; begin CheckPrefs(lPrefs,False); lPrefs.DebugMode2 := true; {$IFNDEF FPC} sTitle:='Choose a folder with DICOM images'; lDirName := BrowseDialog(sTitle); {$ELSE} if not OpenDialogExecute('Select DICOM images you wish to inspect)',true,false,kAnyFilter) then exit; lDirName := extractfiledir( OpenHdrDlg.Filename); {$ENDIF} Memo1.lines.Clear; ConvertDCM2NII(lDirName,lPrefs); end; procedure TMainForm.ExtractDICOMhdr1Click(Sender: TObject); var lnVol,lVol: integer; //lHdrName: string; begin if not OpenDialogExecute('Select the 3D NIfTI images to inspect)',true,false,kAnyFilter) then exit; lnVol := OpenHdrDlg.Files.count; Memo1.lines.clear; for lVol := 1 to lnVol do ShowHeader (OpenHdrDlg.Files[lVol-1]); end; procedure TMainForm.ExtractNIfTIhdrs1Click(Sender: TObject); var lStrings: TStringList; begin if not OpenDialogExecute('Select the 3D NIfTI images to inspect)',true,false,kImgFilter) then exit; Memo1.lines.clear; lStrings := TStringList.Create; lStrings.addstrings(OpenHdrDlg.Files); ExtractNIFTIHdrs(lStrings); lStrings.Free; end; {$IFDEF UNIX} initialization {$I gui.lrs} {$ELSE} //not unix: windows initialization {$IFDEF FPC} {$I gui.lrs} {$ENDIF} OleInitialize(nil); finalization OleUninitialize {$ENDIF} end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/readint.pas0000755000175000017500000000226411326434462017674 0ustar mihmihunit readint; interface uses {$IFDEF FPC}LResources,Buttons,{$ENDIF} {$IFNDEF UNIX} Windows,{$ENDIF} Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Spin,define_types; type TReadIntForm = class(TForm) ReadIntEdit: TSpinEdit; ReadIntLabel: TLabel; OKBtn: TButton; function GetInt(lStr: string; lMin,lDefault,lMax: integer): integer; procedure OKBtnClick(Sender: TObject); private { Private declarations } public { Public declarations } end; const gPassname: kStr20='NIH'; var ReadIntForm: TReadIntForm; implementation {$IFNDEF FPC}{$R *.DFM} {$ENDIF} function TReadIntForm.GetInt(lStr: string; lMin,lDefault,lMax: integer): integer; begin //result := lDefault; ReadIntLabel.caption := lStr+' ['+inttostr(lMin)+'..'+inttostr(lMax)+']'; ReadIntEdit.MinValue := lMin; ReadIntEdit.MaxValue := lMax; ReadIntEdit.Value := lDefault; ReadIntForm.ShowModal; result := ReadIntEdit.Value; end; procedure TReadIntForm.OKBtnClick(Sender: TObject); begin ReadIntForm.ModalResult := mrOK; end; {$IFDEF FPC} initialization {$I readint.lrs} {$ENDIF} end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/nii_math.pas0000755000175000017500000005100512306712652020032 0ustar mihmihunit nii_math; interface {$H+} uses //nii_types,nii_write, niftiutil,dicomtypes,prefs, define_types, sysutils, dialogsx,GraphicsMathLibrary, nifti_types; type TNIFTIimg = record HdrName: string; Hdr: TNIFTIhdr; Opts: TNIIOpts; //ByteSwap: boolean; Offset: integer; Buffer,i8: bytep; f32: singlep; i32 : longintP; i16 : SmallIntP; end; function RMS3d (lAName,lBName,lMaskName: string; lMaskThresh: single; lSaveOutput: boolean; lPrefs: TPrefs):double; function AddSlices (lAName: string; lSlices: integer; lPrefs: TPrefs):boolean; function ReportMinMax (lAName: string): boolean; function Hounsfield2NormScale (lAName: string; lPrefs: TPrefs):boolean; function ShrinkNII (lAName: string; lPrefs: TPrefs): boolean; implementation procedure CreateNII(var lNII: TNIfTIimg); begin lNII.Buffer := nil; end; procedure FreeNII(var lNII: TNIfTIimg); begin if lNII.Buffer <> nil then Freemem(lNII.Buffer); end; function LoadHdrNII(lFilename: string; var lNII: TNIfTIimg): boolean; begin result := false; lNII.HdrName := lFilename; if not NIFTIhdr_LoadHdr (lNII.HdrName, lNII.Hdr, lNII.Opts) then begin; ShowMsg('Header load error '+lFilename); exit; end; result := true; end; function SubBound (lVal,lMin: integer): integer; begin result := lVal; if result < lMin then result := lMin; end; function NonspatialDimensionsNII (lA: TNIFTIimg): integer; //returns sum of 4th, 5th, 6th and 7th dimension... begin result := SubBound(lA.Hdr.dim[4],1)*SubBound(lA.Hdr.dim[5],1)*SubBound(lA.Hdr.dim[6],1)*SubBound(lA.Hdr.dim[7],1); end; function LoadImgNII(lFilename: string; var lNII: TNIfTIimg): boolean; begin result := false; if not LoadHdrNII(lFilename,lNII) then exit; if not NIFTIhdr_LoadImgRaw (False,lNII.HdrName, lNII.Hdr, lNII.Buffer, lNII.Offset,lNII.Opts) then begin ShowMsg('Image load error '+lFilename); exit; end; lNII.f32 := SingleP(@lNII.Buffer^[lNII.Offset+1]); lNII.i32 := LongintP(@lNII.Buffer^[lNII.Offset+1]); lNII.i16 := SmallIntP(@lNII.Buffer^[lNII.Offset+1]); lNII.i8 := ByteP(@lNII.Buffer^[lNII.Offset+1]); result := true; end; procedure Force3DNII (var lNII: TNIFTIimg); begin lNII.Hdr.dim[0] := 3; lNII.Hdr.dim[4] := 1; lNII.Hdr.Dim[5] := 1; lNII.Hdr.Dim[6] := 1; lNII.Hdr.Dim[7] := 1; end; function CreateEmptyImgNII(lHdr: TNIFTIHdr; var lNII: TNIfTIimg): boolean; var lVol,lImgBytes,lFileBytes: integer; begin result := false; //FreeNII ??? lNII.Hdr := lHdr; lNII.Offset := kNIIImgOffset;// (=352) bytes for creating .nii.gz files lVol := NonspatialDimensionsNII(lNiI); //lVol := lHdr.dim[4]+lHdr.dim[5]+lHdr.dim[6]+lHdr.dim[7]; //crepes if lVol < 1 then lVol := 1; lImgBytes := lHdr.dim[1]*lHdr.dim[2]*lHdr.dim[3]*lVol*(lHdr.bitpix div 8); if lImgBytes < 1 then exit; lFileBytes := lImgBytes+ kNIIImgOffset; GetMem(lNII.Buffer,lFileBytes); lNII.f32 := SingleP(@lNII.Buffer^[lNII.Offset+1]); lNII.i32 := LongintP(@lNII.Buffer^[lNII.Offset+1]); lNII.i16 := SmallIntP(@lNII.Buffer^[lNII.Offset+1]); lNII.i8 := ByteP(@lNII.Buffer^[lNII.Offset+1]); result := true; end; function MinMaxNII(var lNII: TNIfTIimg; lVol: integer; ApplyHdrScaling: boolean; var lMin,lMax: double): boolean; //returns min and max intensity in as Volume. //For 4D data, use lVol to specify the volume // if lVol < 1 then all volumes var i,lnVol,lVox,lVoxOffset: integer; begin result := false; if lNII.Buffer = nil then begin showmsg('MinMax Error: image not loaded.'); exit;//image not loaded... end; lnVol := NonspatialDimensionsNII(lNiI); lVox := lNII.Hdr.dim[1]*lNII.Hdr.dim[2]*lNII.Hdr.dim[3]; if (lnVol < 1) or (lVox < 1) then exit; lVoxOffset := 0; if (lVol < 1) or (lVol > lnVol) then lVox := lVox * lnVol else lVoxOffset := (lVol-1)*lVox; case lNII.Hdr.datatype of kDT_UNSIGNED_CHAR: begin lMin := lNII.i8^[lVoxOffset+1]; lMax := lMin; for i := 1 to lVox do if lNII.i8^[lVoxOffset+i] > lMax then lMax := lNII.i8^[lVoxOffset+i]; for i := 1 to lVox do if lNII.i8^[lVoxOffset+i] < lMin then lMin := lNII.i8^[lVoxOffset+i]; end;//CHAR kDT_SIGNED_SHORT: begin lMin := lNII.i16^[lVoxOffset+1]; lMax := lMin; for i := 1 to lVox do if lNII.i16^[lVoxOffset+i] > lMax then lMax := lNII.i16^[lVoxOffset+i]; for i := 1 to lVox do if lNII.i16^[lVoxOffset+i] < lMin then lMin := lNII.i16^[lVoxOffset+i]; end;//kDT_SIGNED_SHORT kDT_SIGNED_INT: begin lMin := lNII.i32^[lVoxOffset+1]; lMax := lMin; for i := 1 to lVox do if lNII.i32^[lVoxOffset+i] > lMax then lMax := lNII.i32^[lVoxOffset+i]; for i := 1 to lVox do if lNII.i32^[lVoxOffset+i] < lMin then lMin := lNII.i32^[lVoxOffset+i]; end;//kDT_SIGNED_INT kDT_FLOAT: begin lMin := lNII.f32^[lVoxOffset+1]; lMax := lMin; for i := 1 to lVox do if lNII.f32^[lVoxOffset+i] > lMax then lMax := lNII.f32^[lVoxOffset+i]; for i := 1 to lVox do if lNII.f32^[lVoxOffset+i] < lMin then lMin := lNII.f32^[lVoxOffset+i]; end;//float end;// datatype if ApplyHdrScaling then begin lMin := (lMin * lNII.hdr.scl_slope)+lNII.hdr.scl_inter; lMax := (lMax * lNII.hdr.scl_slope)+lNII.hdr.scl_inter; end; result := true; end; function SameHdrDimNII (lA,lB: TNIFTIimg; lCheck4D, lCheckDataType: boolean): boolean; begin result := SameHdrDim (lA.Hdr,lB.Hdr, lCheck4D, lCheckDataType); if not result then ShowMsg('Dimensions differ '+lA.Hdrname+' <> '+lB.HdrName); end; function ReportMinMax (lAName: string): boolean; label 666; var lA: TNIfTIimg; lMin,lMax: double; begin result := false; CreateNII(lA); if not LoadImgNII(lAName,lA) then goto 666; if not MinMaxNII(lA,0,true,lMin,lMax) then goto 666; showmsg(lAName+kTab+'Min'+floattostr(lMin)+kTab+'Max:'+floattostr(lMax)); result := true; 666: FreeNII(lA); end; function Hounsfield2NormScale (lAName: string; lPrefs: TPrefs):boolean; //Hounsfield scaled data in the range //Air -1000 //Fat 120 //Water 0 //Muscle ~40 //Contrast +130 //Bone >400 (typically ~1000) //problem 1: SPM assume 0 is dark [zero fills edges] - so we need to make minimum 0 //note the contrast of interest is in the compressed range -100..+200 //http://en.wikipedia.org/wiki/Hounsfield_units const kUninterestingDarkUnits = 900; // e.g. -1000..-100 kInterestingMidUnits = 300; //e.g. -100..+300 kScaleRatio = 2;// increase dynamic range of interesting voxels by 3 label 666; var lA,lOut: TNIfTIimg; lMin,lMax,lRange: double; i,lVox: integer; v16,lExtra,lMin16: SmallInt; //lPrefs: TPrefs; lOName: string; begin result := false; CreateNII(lA); CreateNII(lOut); if not LoadImgNII(lAName,lA) then goto 666; if lA.Hdr.datatype <> kDT_SIGNED_SHORT then begin showmsg('Hounsfield2NormScale Error: Image datatype must be 16-bit integer : '+lAName); goto 666; end; lVox := lA.Hdr.dim[1]*lA.Hdr.dim[2]*lA.Hdr.dim[3]*NonspatialDimensionsNII(lA); if lVox < 1 then goto 666; if not MinMaxNII(lA,0,false,lMin,lMax) then goto 666; lRange := lMax-lMin; if lRange < 1800 then begin //note assume integer data type with scaling... showmsg('Hounsfield2NormScale Error: dark to bright regions of a Hounsfield calibrated CT scan of the brain should exceed 1800 (air=-1000,bone=1000) : '+lAName); goto 666; end; //create output lOut.Hdr := lA.Hdr; force3DNII(lOut); lOut.Hdr.datatype := kDT_SIGNED_SHORT; lOut.Hdr.scl_slope := 1; lOut.Hdr.scl_inter := 0; CreateEmptyImgNII(lOut.Hdr, lOut); //translate values lMin16 := round(lMin); case lA.Hdr.datatype of kDT_SIGNED_SHORT: begin for i := 1 to lVox do begin v16 := lA.i16^[i]-lMin16; lExtra := v16-kUninterestingDarkUnits; if lExtra > kInterestingMidUnits then lExtra := kInterestingMidUnits; if lExtra > 0 then lExtra := lExtra*kScaleRatio else lExtra := 0; lOut.i16^[i] := v16+lExtra; end; lOut.i16^[1] := 0;//ANTS uses this voxel for background color end;//kDT_SIGNED_SHORT else begin Showmsg('Unsupported datatype'); end;//float end;// datatype //Save data lOName := ChangeFilePrefix(lAName,'x'); //SetDefaultPrefs (lPrefs); //lOName := lAName; //lPrefs.gzip := true; SaveNIfTICore (lOName, lOut.Buffer, kNIIImgOffset+1, lOut.Hdr, lPrefs); result := true; 666: FreeNII(lA); FreeNII(lOut); end; function RMS3d (lAName,lBName,lMaskName: string; lMaskThresh: single; lSaveOutput: boolean; lPrefs: TPrefs):double; //Determines Root Mean Square Error between A and B // both A and B are 3D images // Mean for each voxel sqrt(X^2+Y^2+Z^2) //OPTIONAL: Mask image (set name to '' to ignore) const NaN : double = 1/0; kErrorStr = 'RMS'; label 666; var lA,lB,lMask,lOut: TNIfTIimg; lSum,lRMS: double; lV,lVox,lCount,lMaskCount: integer; lUseMask: boolean; //lPrefs: TPrefs; lOName: string; begin result := 0; lUseMask := false; CreateNII(lA); CreateNII(lB); CreateNII(lMask); CreateNII(lOut); if not LoadImgNII(lAName,lA) then goto 666; if not LoadImgNII(lBName,lB) then goto 666; if not SameHdrDimNII(lA,lB,true,true) then goto 666; if NonspatialDimensionsNII(lA) <> 3 then begin ShowMsg('Image must have 3 volumes [not '+inttostr(NonspatialDimensionsNII(lA))+'] ' +lAName); goto 666; end; lVox := lA.Hdr.Dim[1]*lA.Hdr.Dim[2] * lA.Hdr.Dim[3]; if lVox < 1 then goto 666; case lA.Hdr.datatype of kDT_FLOAT:;//lBPP := 4; else begin ShowMsg(kErrorStr+' datatype not supported.'); exit; end; end; //case //next lines: mask.... if (lMaskName <> '') and (not fileexists(lMaskName)) then ShowMsg(kErrorStr+'unable to find mask '+lMaskName) else if (lMaskName <> '') and (fileexists(lMaskName)) then begin lUseMask := true; if not LoadImgNII(lMaskName,lMask) then goto 666; if lMask.Hdr.datatype <> kDT_FLOAT then begin ShowMsg(kErrorStr+'datatype not supported. '+lMaskName); goto 666; end; if not SameHdrDimNII(lA,lMask,true,true) then goto 666; end; //mask //output if lSaveOutput then begin lOut.Hdr := lA.Hdr; force3DNII(lOut); lOut.Hdr.datatype := kDT_FLOAT; CreateEmptyImgNII(lOut.Hdr, lOut); for lV := 1 to lVox do lOut.f32^[lV] := 0; end; lSum:= 0; lCount := 0; lMaskCount := 0; case lA.Hdr.datatype of kDT_FLOAT: begin for lV := 1 to lVox do begin if (not (lUseMask)) or ((not SpecialSingle(lMask.f32^[lV])) and (lMask.f32^[lV]> lMaskThresh)) then begin inc(lMaskCount); if (not SpecialSingle(lA.f32^[lV])) and (not SpecialSingle(lA.f32^[lV+lVox])) and (not SpecialSingle(lA.f32^[lV+lVox+lVox])) and (not SpecialSingle(lB.f32^[lV])) and (not SpecialSingle(lB.f32^[lV+lVox])) and (not SpecialSingle(lB.f32^[lV+lVox+lVox])) then begin //if true then begin inc(lCount); lRMS := sqrt(sqr(lA.f32^[lV]-lB.f32^[lV])+ sqr(lA.f32^[lV+lVox]-lB.f32^[lV+lVox])+sqr(lA.f32^[lV+lVox+lVox]-lB.f32^[lV+lVox+lVox])); if (lSaveOutput) then begin try //switch from double to single precision... lOut.f32^[lV] := lRMS; except lOut.f32^[lV] := NAN; end; //except end; lSum := lSum + lRMS; end; //not special - i.e. NaN end;//in mask end;//each 3D voxel end; //kDT_FLOAT end;//case of datatype if lMaskCount = 0 then ShowMsg(kErrorStr+' No voxels greater than '+floattostr(lMaskThresh)+' in mask '+lMaskName) else if lCount = 0 then ShowMsg(kErrorStr+' No valid voxels. All NaN?') else if lSaveOutput then begin lOName := ChangeFilePrefix(lAName,'Xrms'); //SetDefaultPrefs (lPrefs); SaveNIfTICore (lOName, lOut.Buffer, kNIIImgOffset+1, lOut.Hdr, lPrefs); end; if lCount > 0 then result := lSum/lCount; 666: FreeNII(lA); FreeNII(lB); FreeNII(lMask); FreeNII(lOut); end; function AddSlices (lAName: string; lSlices: integer; lPrefs: TPrefs):boolean; const NaN : double = 1/0; kErrorStr = 'RMS'; label 666; var lA,lOut: TNIfTIimg; lOffset,lV,lS,lI,lVolBytes,lSliceBytes: integer; //lPrefs: TPrefs; lOName: string; begin result := false; if lSlices < 1 then exit; CreateNII(lA); CreateNII(lOut); if not LoadImgNII(lAName,lA) then goto 666; lSliceBytes := lA.hdr.dim[1]*lA.hdr.dim[2]*trunc(((lA.Hdr.bitpix)+7)/8); lVolBytes := lSliceBytes * lA.hdr.dim[3]; if (lSliceBytes < 1) or (lVolBytes < 1) then goto 666; lOut.Hdr := lA.Hdr; force3DNII(lOut); lOut.hdr.dim[3] := lOut.hdr.dim[3] + lSlices; lOut.Hdr.datatype := kDT_FLOAT; CreateEmptyImgNII(lOut.Hdr, lOut); lI := 0; //lOffset := 0; lOffset := lSliceBytes * 10; for lS :=1 to lSlices do for lV := 1 to (lSliceBytes) do begin inc(lI); //lOut.i8^[lI] := 0; lOut.i8^[lI] := lA.i8^[lV+lOffset] end; lSliceBytes := lSliceBytes * lSlices; for lV := 1 to lVolBytes do lOut.i8^[lV+lSliceBytes] := lA.i8^[lV]; //lOffset := 0; lSliceBytes := lA.hdr.dim[1]*lA.hdr.dim[2]*trunc(((lA.Hdr.bitpix)+7)/8); lI := 0; lOffset := lSliceBytes * 10; for lS :=1 to 18 do for lV := 1 to (lSliceBytes) do begin inc(lI); //lOut.i8^[lI] := 0; lOut.i8^[lI] := lA.i8^[lV+lOffset] end; lOName := ChangeFilePrefix(lAName,'x'); //SetDefaultPrefs (lPrefs); if SaveNIfTICore (lOName, lOut.Buffer, kNIIImgOffset+1, lOut.Hdr, lPrefs) <> '' then result := true; 666: FreeNII(lA); FreeNII(lOut); end; procedure RescaleHdr (var lHdr: TNIFTIHdr; lX,lY,lZ: double); var lIn,lScale,lResidualMat: TMatrix; dx, dy, dz: single; begin lIn := Matrix3D ( lHdr.srow_x[0],lHdr.srow_x[1],lHdr.srow_x[2],lHdr.srow_x[3], lHdr.srow_y[0],lHdr.srow_y[1],lHdr.srow_y[2],lHdr.srow_y[3], lHdr.srow_z[0],lHdr.srow_z[1],lHdr.srow_z[2],lHdr.srow_z[3], 0,0,0,1); lScale := Matrix3D (lX,0,0,0, 0,lY,0,0, 0,0,lZ,0, 0,0,0,1); lResidualMat := MultiplyMatrices(lIn,lScale); lHdr.srow_x[0] := lResidualMat.Matrix[1,1]; lHdr.srow_x[1] := lResidualMat.Matrix[1,2]; lHdr.srow_x[2] := lResidualMat.Matrix[1,3]; lHdr.srow_y[0] := lResidualMat.Matrix[2,1]; lHdr.srow_y[1] := lResidualMat.Matrix[2,2]; lHdr.srow_y[2] := lResidualMat.Matrix[2,3]; lHdr.srow_z[0] := lResidualMat.Matrix[3,1]; lHdr.srow_z[1] := lResidualMat.Matrix[3,2]; lHdr.srow_z[2] := lResidualMat.Matrix[3,3]; lHdr.srow_x[3] := lResidualMat.Matrix[1,4]; lHdr.srow_y[3] := lResidualMat.Matrix[2,4]; lHdr.srow_z[3] := lResidualMat.Matrix[3,4]; nifti_mat44_to_quatern( lResidualMat, lHdr.quatern_b,lHdr.quatern_c,lHdr.quatern_d, lHdr.qoffset_x,lHdr.qoffset_y,lHdr.qoffset_z, dx, dy, dz,lHdr.pixdim[0] {QFac}); end; function ShrinkNII(lAName: String; lPrefs: TPrefs): boolean; //Halves X and Y dimensions label 666; var lOName: string; lo,li,lx,lyz: integer; lA,lOut: TNIfTIimg; begin result := false; CreateNII(lA); CreateNII(lOut); if not LoadImgNII(lAName,lA) then goto 666; if odd(lA.hdr.dim[1]) or odd(lA.hdr.dim[2]) then begin ShowMsg('ShrinkNII error X and Y must be divisible by 2 '+inttostr(lA.hdr.dim[1])+' '+inttostr(lA.hdr.dim[2])); goto 666; end; case lA.Hdr.datatype of kDT_UNSIGNED_CHAR,kDT_SIGNED_SHORT , kDT_SIGNED_INT, kDT_FLOAT:;//lBPP := 4; else begin ShowMsg('ShrinkNII datatype not supported.'); exit; end; end; //case lOut.Hdr := lA.Hdr; force3DNII(lOut); lOut.hdr.dim[1] := lOut.hdr.dim[1] div 2; lOut.hdr.dim[2] := lOut.hdr.dim[2] div 2; lOut.hdr.pixdim[1] := lOut.hdr.pixdim[1] * 2; lOut.hdr.pixdim[2] := lOut.hdr.pixdim[2] * 2; RescaleHdr(lOut.hdr,2,2,1); CreateEmptyImgNII(lOut.Hdr, lOut); case lA.Hdr.datatype of kDT_UNSIGNED_CHAR: begin li := 1; lo := 1; for lyz := 1 to (lOut.hdr.dim[2]*lOut.hdr.dim[3]) do begin for lx := 1 to lOut.hdr.dim[1] do begin lOut.i8^[lo] := (lA.i8^[li]+lA.i8^[li+1]+lA.i8^[li]+lA.i8^[li+1]) div 4; inc(li,2); //skip voxel inc(lo); end;//x inc(li,lA.hdr.dim[1]); //skip line end;//yz end;//CHAR kDT_SIGNED_SHORT: begin li := 1; lo := 1; for lyz := 1 to (lOut.hdr.dim[2]*lOut.hdr.dim[3]) do begin for lx := 1 to lOut.hdr.dim[1] do begin lOut.i16^[lo] := (lA.i16^[li]+lA.i16^[li+1]+lA.i16^[li]+lA.i16^[li+1]) div 4; inc(li,2); //skip voxel inc(lo); end;//x inc(li,lA.hdr.dim[1]); //skip line end;//yz end;//kDT_SIGNED_SHORT kDT_SIGNED_INT: begin li := 1; lo := 1; for lyz := 1 to (lOut.hdr.dim[2]*lOut.hdr.dim[3]) do begin for lx := 1 to lOut.hdr.dim[1] do begin lOut.i32^[lo] := (lA.i32^[li]+lA.i32^[li+1]+lA.i32^[li]+lA.i32^[li+1]) div 4; inc(li,2); //skip voxel inc(lo); end;//x inc(li,lA.hdr.dim[1]); //skip line end;//yz end;//kDT_SIGNED_INT kDT_FLOAT: begin li := 1; lo := 1; for lyz := 1 to (lOut.hdr.dim[2]*lOut.hdr.dim[3]) do begin for lx := 1 to lOut.hdr.dim[1] do begin lOut.f32^[lo] := (lA.f32^[li]+lA.f32^[li+1]+lA.f32^[li]+lA.f32^[li+1]) / 4; inc(li,2); //skip voxel inc(lo); end;//x inc(li,lA.hdr.dim[1]); //skip line end;//yz end;//float end;// datatype lOName := ChangeFilePrefix(lAName,'d'); if SaveNIfTICore (lOName, lOut.Buffer, kNIIImgOffset+1, lOut.Hdr, lPrefs) <> '' then result := true; 666: FreeNII(lA); FreeNII(lOut); end; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2niigui.lrs0000755000175000017500000016150212065105430020305 0ustar mihmihLazarusResources.Add('MAINICON','ICO',[ #0#0#1#0#4#0'00'#0#0#1#0' '#0#168'%'#0#0'F'#0#0#0' '#0#0#1#0' '#0#168#16#0#0 +#238'%'#0#0#24#24#0#0#1#0' '#0#136#9#0#0#150'6'#0#0#16#16#0#0#1#0' '#0'h'#4#0 +#0#30'@'#0#0'('#0#0#0'0'#0#0#0'`'#0#0#0#1#0' '#0#0#0#0#0#128'%'#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#138#138#138#0#143#143#143#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#168#168#168#0#185#185#185#0#0#0#0#1#255#255#255#3#14#14#14#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#141#141#141#2#142 +#142#142#2#145#145#145#2#146#145#145#2#146#146#146#2'~~'#128#2'zz{'#1'{{{'#2 +'|||'#2'~~'#128#2#127#127#129#2#127#127#127#2#128#128#128#2#128#128#129#2#131 +#131#131#2#131#131#131#2#133#133#133#2#134#134#134#1'jjj'#2#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#131#131#131#0#173#173#173#0#178#178#178#2#0#0#0#0#0#0#0#0 +#0#0#0#5#0#0#0#7#0#0#0#6#0#0#0#6#0#0#0#6#0#0#0#6#0#0#0#6#0#0#0#6#0#0#0#8#0#0 +#0#0#143#143#143#0#145#145#146#0#130#130#130#0#139#138#147#0#153#152#174#0 +#143#141#177#0#156#154#202#0#161#159#206#0#163#160#209#0#162#159#208#0#153 +#151#195#0#135#134#166#0'vu'#131#0'mmn'#0'rrq'#0'rrr'#0'ttt'#0'}}}'#0'lll'#0 +'xxx'#0'888'#0#128#128#128#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#147#147#147#0#0#0#0#0#143#143#143#1#167#167#167#2 +#144#144#144#0'kkk'#9'zzz'#129#151#151#151#214#166#166#166#216#163#163#163 +#216#163#163#163#217#162#162#162#217#163#163#163#217#162#162#162#217#162#162 +#162#216#166#166#166#219#155#155#155#194'sss9rrp!pqm#'#132#130#141'#'#156#155 +#180'"'#149#147#188#27#156#154#204#25#162#159#211#25#164#162#214#25#164#161 +#213#25#155#153#199#25#132#131#166#25'ggt'#25'PPK'#25'STG'#25']]Y'#25'bbb'#25 +'iii'#25'bbb'#27'___'#6#23#23#23#0#130#130#130#0#137#137#137#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#157#157#157#0#156#156#156 +#0#137#137#137#0#183#183#183#0#175#175#175'H'#154#154#154#210#154#154#154#255 +#168#168#168#255#176#176#176#255#174#174#174#255#175#175#175#255#175#175#175 +#255#174#174#174#255#174#174#174#255#174#174#174#255#177#177#177#255#175#175 +#175#255#155#155#156#253#179#178#183#245#174#174#176#246#164#164#160#246#148 +#148#133#246#130#131'l'#241'wyY'#240'rtP'#240'stP'#240'xzZ'#240#131#132'l' +#240#146#147#131#240#161#161#158#240#171#171#175#240#173#173#178#240#168#168 +#169#240#165#165#163#240#165#165#165#236#167#167#167#241#147#147#147#143#197 +#197#197#0#174#174#174#1#129#129#129#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#151#151#151#2#146#146#146#0#137#137#137#29#138#138 +#138#159#157#157#157#255#169#169#169#255#151#151#151#250#170#170#170#253#171 +#171#171#253#170#170#170#253#171#171#171#253#171#171#171#253#171#171#171#253 +#171#171#171#253#170#170#170#253#171#171#171#253#171#171#172#252#154#154#147 +#255#140#142'r'#255'lo;'#255'`d'#22#255'_e'#1#255'ek'#0#255'kq'#0#255'nu'#0 +#255'mt'#0#255'kq'#0#255'gm'#0#255'ek'#3#255'hm'#24#255'uy='#255#142#143'r' +#255#167#167#164#255#180#180#187#255#176#176#178#255#175#176#175#255#165#165 ,#165#239#157#157#157#22'```'#0#128#128#128#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#164#164#164#2#171#171#171#5#149#149#149#205 +#168#168#168#255#167#167#167#251#164#164#164#252#152#152#152#255#173#173#173 +#254#171#171#171#254#171#171#171#255#172#172#172#255#172#172#172#255#172#172 +#172#255#172#172#172#255#171#171#171#254#171#171#169#254#176#176#182#255'hj7' +#254'X^'#0#253'u|'#0#253#136#144#0#253#145#155#0#253#149#158#0#253#149#158#1 +#253#149#159#1#253#149#158#1#253#149#159#1#253#149#158#0#253#146#155#0#253 +#140#149#0#253#129#138#0#253't|'#0#253'qw'#17#253#132#135'S'#253#165#165#161 +#253#178#178#184#250#172#172#170#255#134#134#133'p'#173#173#173#0#169#169#169 +#3#170#170#171#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'ppp' +#0'lll"'#162#162#162#248#166#166#166#252#166#166#166#253#161#161#161#255#154 +#154#154#254#174#174#174#255#170#170#170#255#172#172#172#255#171#171#171#255 +#171#171#171#255#171#171#171#255#171#171#171#255#171#171#171#255#171#171#168 +#255#172#172#182#255#133#138'4'#255#146#156#1#255#149#157#3#255#145#154#0#255 +#143#152#0#255#143#152#0#255#143#152#0#255#142#151#0#255#143#151#0#255#143 +#151#0#255#143#152#0#255#143#152#0#255#144#153#0#255#146#156#1#255#148#158#1 +#255#144#154#0#255#130#139#0#255'x'#127#16#255#143#145'k'#251#177#176#184#254 +#163#163#163#211#201#202#198#5#169#170#165#1#190#185#230#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#143#143#143#0#131#131#131'J'#163#163 +#163#254#165#165#165#253#166#166#166#254#158#158#158#254#156#156#156#255#175 +#175#175#255#171#171#171#255#172#172#172#255#174#174#174#255#175#175#175#255 +#175#175#175#255#174#174#174#255#172#172#172#255#171#172#169#255#172#171#183 +#255#140#145';'#255#142#151#0#255#142#151#2#255#143#152#0#255#143#152#0#255 +#143#152#1#255#144#153#2#255#145#153#2#255#145#154#2#255#145#154#2#255#144 +#153#2#255#143#152#1#255#143#152#0#255#142#151#0#255#142#151#1#255#143#151#2 +#255#146#155#4#255#145#154#0#254#129#138#0#254#131#134'>'#252#165#165#169#255 +'}}'#132'I'#152#148#164#0#149#148#157#2#131#130#137#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#157#157#157#0#144#144#144's'#165#165#165#254#165#165 +#165#251#167#167#167#255#157#157#157#255#160#160#160#255#174#174#174#255#174 +#174#174#255#178#178#178#255#179#179#179#255#179#179#179#255#179#179#179#255 +#179#179#179#255#178#178#178#255#175#175#173#255#174#174#185#255#140#145'A' +#255#143#153#0#255#144#153#3#255#144#153#1#255#145#154#0#255#143#153#0#255 +#140#149#0#255#137#147#0#255#137#147#0#255#138#148#0#255#141#151#0#255#145 +#155#0#255#147#156#0#255#146#155#0#255#145#155#0#255#145#155#0#255#145#154#0 +#255#144#153#0#255#148#158#0#255#139#149#0#251#131#137'!'#254#146#146#137#178 +#147#166#155#0#171#175#130#2#0#0#0#0#137#137#137#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#175#175#175#0#147#147#147#154#166#166#166#255#164#164#164#250 +#167#167#167#254#155#155#155#255#162#162#162#255#178#178#178#255#179#179#179 +#255#179#179#179#255#179#179#179#255#179#179#179#255#179#179#179#255#179#179 +#179#255#179#179#179#255#179#179#177#255#181#181#191#255#139#144'G'#255#135 +#145#0#255#140#149#0#255#140#150#0#255#137#145#0#255#140#147'&'#255#151#155 +'P'#255#158#161'i'#255#158#160'l'#255#154#157'e'#255#143#148'J'#255#131#138 +#28#255#129#137#6#255#129#136#18#255#132#139#25#255#131#137#27#255#131#137#30 +#255#130#137'!'#255#129#136'&'#254#133#138','#254#130#135')'#253'nqF'#249':F' +'?(dfZ'#0'llf'#5#131#131#131#3#156#156#156#3#131#131#131#2#183#183#183#0#178 +#178#178#0#0#0#0#0#241#241#241#0#155#155#155#184#166#166#166#255#165#165#165 +#251#170#170#170#255#156#156#156#255#168#168#168#255#182#182#182#255#178#178 +#178#255#179#179#179#255#180#180#180#255#179#179#179#255#179#179#179#255#179 +#179#179#255#179#179#179#255#178#178#178#255#182#182#184#255#141#141#131#255 +#133#135'j'#255#136#138'd'#255#129#132'T'#255#130#132'r'#255#153#152#160#255 +#154#153#164#255#159#158#168#255#165#165#174#255#157#156#166#255#151#150#161 +#255#137#137#143#255'yyv'#255#142#142#146#255#148#148#153#255#148#148#154#255 +#150#150#158#255#151#151#159#255#152#152#161#254#152#152#162#255#151#150#162 +#252#153#153#157#254#135#133#135#210#146#145#149#27#165#166#165#0'zzz'#0#163 +#163#163#0#143#143#143#0#212#212#212#0#203#203#203#0'kkk'#0#250#250#250#4#157 +#157#157#208#168#168#168#255#171#171#171#252#176#176#176#255#160#160#160#255 +#170#170#170#255#181#181#181#255#178#178#178#255#180#180#180#255#179#179#179 +#255#180#180#180#255#180#180#180#255#179#179#179#255#180#180#179#255#178#178 +#179#255#181#181#181#255#150#150#152#255#152#152#157#255#154#154#161#255#157 +#156#165#255#151#151#155#255#132#132#131#255#127#127'|'#255#134#134#132#255 +#136#136#134#255#134#134#132#255#135#135#133#255#127#127'}'#255#151#151#152 +#255#153#153#153#255#149#149#148#255#146#146#144#255#142#143#141#255#139#139 +#137#255#135#135#133#255#131#131#130#254#142#142#140#255#142#142#142#252#144 +#144#144#255'zzz'#195#141#141#141'v'#139#139#139'{'#136#136#136'}wwwN'#174 ,#174#174#0#196#196#196#1'```'#0#11#11#11'('#157#157#157#226#171#171#171#255 +#173#173#173#253#175#175#175#255#160#160#160#255#169#169#169#255#181#181#181 +#255#179#179#179#255#179#179#179#255#180#180#180#255#180#180#180#255#180#180 +#180#255#180#180#180#255#179#179#180#255#179#179#178#255#182#182#183#255#150 +#150#150#255#148#148#146#255#155#156#154#255#138#138#135#255'tts'#255#130#130 +#130#255#140#140#140#255#141#141#141#255#143#143#143#255#146#146#146#255#149 +#149#149#255#135#135#135#255#127#127#127#255'yyy'#255'zzz'#255'zzz'#255'zzz' +#255'~~~'#255'www'#255#132#132#132#255#174#174#174#254#170#170#170#255#170 +#170#170#252#173#173#173#255#172#172#172#255#171#171#171#255#172#172#172#255 +#153#153#153#224#176#176#176#1#179#179#179#1'eee'#2'qqqT'#162#162#162#236#173 +#173#173#255#172#172#172#254#176#176#176#255#161#161#161#255#168#168#168#255 +#182#182#182#255#179#179#179#255#180#180#180#255#180#180#180#255#180#180#180 +#255#180#180#180#255#180#180#180#255#180#180#180#255#178#178#178#255#183#183 +#183#255#152#152#152#255#145#145#145#255#152#152#152#255#131#131#131#255#149 +#149#149#255#154#154#154#255#153#153#153#254#155#155#155#255#154#154#154#254 +#154#154#154#254#155#155#155#254#136#136#136#254'zzz'#255#134#134#134#254#134 +#134#134#255#134#134#134#255#135#135#135#255#128#128#128#255#128#128#128#255 +#165#165#164#255#171#172#170#255#171#171#169#254#171#171#170#255#171#171#170 +#253#171#171#170#251#171#171#170#249#172#172#171#247#170#170#170#251'xxx'#167 +'TTT'#0#171#171#171#0'}}}'#127#169#169#169#242#173#173#173#255#173#173#173 +#253#176#176#176#255#162#162#162#255#167#167#167#255#182#182#182#255#179#179 +#179#255#180#180#180#255#180#180#180#255#180#180#180#255#180#180#180#255#180 +#180#180#255#180#180#180#255#178#178#178#255#183#183#183#255#154#154#154#254 +#145#145#145#255#155#155#155#253#141#141#141#251#154#154#154#251#154#154#154 +#251#152#152#152#250#152#152#152#250#150#150#150#250#149#149#149#250#149#149 +#149#251'}}}'#252'rrr'#254'|||'#255'xxx'#254'yyy'#255'sss'#255#130#130#129 +#255#171#171#172#255#177#177#181#255#174#173#177#255#175#175#179#255#175#175 +#179#255#175#174#180#255#176#175#179#255#176#176#178#255#174#174#174#255#176 +#176#175#255#175#175#175#255#145#145#145#190#149#149#149#23#130#130#130#157 +#171#171#171#246#174#174#174#255#173#173#173#254#176#176#176#255#162#162#162 +#255#167#167#167#255#182#182#182#255#179#179#179#255#180#180#180#255#180#180 +#180#255#180#180#180#255#180#180#180#255#180#180#180#255#180#180#180#255#179 +#179#179#255#181#181#181#254#165#165#165#255#186#186#186#254#199#199#199#255 +#134#134#134#255'xxx'#255#128#128#128#255'}}}'#255'|||'#255'zzz'#255'zzz'#255 +'{{{'#255'xxx'#255'ttt'#254'uuu'#254'www'#255'{{{'#255'uuu'#255#152#152#153 +#255#160#160#156#255#151#153#134#255#154#155#136#255#153#154#134#255#153#154 +#134#255#153#155#132#254#149#150#130#255#146#146#140#232#150#149#153#212#150 +#150#153#214#159#159#159#210#158#158#158#227'___Z'#138#138#138#179#171#171 +#171#249#173#173#173#255#172#172#172#254#175#175#175#255#162#162#162#255#167 +#167#167#255#181#181#181#255#178#178#179#255#179#179#180#255#179#179#179#255 +#179#179#179#255#179#179#179#255#179#179#179#255#179#179#179#255#178#178#178 +#255#182#182#182#255#164#164#164#253#189#189#189#254#164#164#164#237#145#145 +#145#180#141#141#141#169'nnn'#155'ooo'#142'nnn'#129'jjjtlllgwwwUiii'#134#164 +#164#164#255#172#172#172#252#174#174#174#254#177#177#177#254#180#180#179#255 +#185#185#186#255#167#167#162#255#128#136#9#255#137#146#0#255#135#144#0#255 +#136#144#0#255#138#147#0#250#129#137#0#255'ci'#5#157'fl'#0#5'nu'#0#8#0#0#0#6 +#0#0#0#5'rrr'#6#140#140#140#183#171#171#171#250#174#174#174#255#175#175#175 +#254#177#177#177#255#161#161#161#255#168#168#168#255#181#181#179#255#178#178 +#176#255#179#179#177#255#179#179#177#255#179#179#177#255#179#179#177#255#179 +#179#177#255#179#179#178#255#179#179#179#255#182#182#182#254#166#166#166#251 +#181#181#181#255#138#138#138'^'#172#172#172#0#166#166#166#0#136#136#136#0#134 +#134#134#0#127#127#127#0'www'#0'uuu'#0#206#206#206#0#219#219#219#0#173#173 +#173#200#197#197#197#254#194#194#194#252#194#194#194#255#193#193#193#255#193 +#193#192#255#191#191#201#255#142#148'1'#255#144#154#0#255#145#153#1#255#145 +#154#0#255#144#153#0#252#145#155#0#255#142#151#7#202#141#159#0#0#168#184#0#0 +'48'#0#0'DDD'#0'^^^'#0#140#140#140#183#172#172#172#250#172#172#172#255#160 +#160#160#254#170#170#170#255#158#158#158#255#171#171#172#255#184#183#193#255 +#181#180#191#255#182#181#193#255#181#181#192#255#182#181#192#255#181#181#192 +#255#181#180#192#255#180#180#185#255#176#177#176#255#176#176#177#253#165#165 +#165#255#175#175#175#231#30#30#30#16'jjj'#2'kkk'#2#147#147#147#2#128#128#128 +#3'zzz'#3'uuu'#3'yyy'#3#178#178#178#7#181#181#181#0#149#149#149'n'#188#188 +#188#255#191#191#191#251#191#191#191#254#191#191#191#255#190#190#188#255#194 +#193#204#255#148#151'R'#255#139#149#0#255#143#152#2#255#142#151#0#255#143#152 +#0#253#142#151#0#255#147#155#5#226'VkY'#10#168#173'E'#0#162#168'*'#0#0#0#0#0 ,#0#0#0#0#138#138#138#179#173#173#173#249#167#167#167#255#148#148#148#254#159 +#159#159#255#146#146#147#255#154#154#149#255#146#149'X'#255#143#147'P'#255 +#144#147'O'#255#143#147'M'#255#142#147'K'#255#143#147'K'#255#140#145'D'#255 +#144#147'p'#255#168#168#173#255#163#163#162#252#178#178#178#254#172#172#172 +#200#0#0#0#0#245#245#245#0'eee'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'vvv'#0#159 +#159#159#3#142#142#142#0#137#137#137'I'#187#187#187#255#192#192#192#253#191 +#191#191#253#191#191#191#255#191#191#189#255#195#194#204#255#150#154']'#255 +#139#148#0#255#143#152#1#255#143#152#0#255#144#153#0#252#142#151#0#255#146 +#155#1#232#161#168#29#18#154#164#20#0#162#167'*'#0#0#0#0#0#0#0#0#0#131#131 +#131#156#173#173#173#246#167#167#167#255#159#159#159#253#178#178#177#255#174 +#174#176#255#171#171#160#255#143#152#3#255#140#150#0#255#141#151#0#255#141 +#151#0#255#140#150#0#255#142#151#0#255#138#148#0#255#145#150'G'#255#195#195 +#206#255#192#193#190#252#196#196#196#255#171#171#171#206#255#255#255#2#0#0#0 +#0#140#140#140#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#129#129#129#0#158#158#158#3 +#144#144#144#1#140#140#140'N'#187#187#187#254#192#192#192#253#191#191#191#253 +#192#192#192#255#190#190#188#255#194#194#204#255#149#153'W'#255#140#149#0#255 +#144#153#2#255#142#151#0#255#144#153#0#253#143#152#0#255#146#155#2#231#177 +#184')'#18#157#166#25#0#162#171'*'#0#0#0#0#0#0#0#0#0'{{{y'#172#172#172#241 +#169#169#169#255#155#155#155#254#175#175#174#255#172#172#173#255#172#173#169 +#255#147#155#25#255#143#152#2#255#144#153#3#255#144#153#2#255#144#153#2#255 +#144#152#4#255#142#152#2#255#141#146'3'#255#189#189#198#255#190#190#189#253 +#193#193#193#254#179#179#179#240'EEE'#27'```'#1'zzz'#0#205#205#205#0#0#0#0#0 +#0#0#0#0#131#131#131#0'zzz'#0#196#196#196#4#201#201#201#0#154#154#154#129#191 +#191#191#255#191#191#191#251#191#191#191#254#191#191#191#255#191#191#189#255 +#191#190#201#255#143#148';'#255#142#152#0#255#143#152#1#255#143#152#0#255#143 +#152#0#252#142#151#0#255#145#154#4#224'''>'#0#8#162#170':'#0#162#170'*'#0#0#0 +#0#0#0#0#0#0'^^^J'#167#167#167#235#170#170#170#255#155#155#155#253#175#175 +#175#255#173#173#171#255#174#174#179#255#152#158'.'#255#141#151#0#255#144#153 +#1#255#144#153#0#255#144#153#0#255#142#151#0#255#144#154#0#255#135#143#13#255 +#179#179#177#255#194#194#194#254#192#192#191#250#190#190#190#255#150#150#150 +'~'#184#184#184#0#183#183#183#5#193#193#193#1'ZZZ'#0'```'#0#158#158#158#0'yy' +'y'#3#189#189#189#1#191#191#191#13#173#173#173#222#193#193#193#254#191#191 +#191#252#192#192#192#255#190#190#190#255#193#193#193#255#181#181#183#255#136 +#143#18#255#144#153#0#255#142#151#0#255#144#153#0#254#142#151#0#251#145#154#4 +#254#155#163#23#196#142#153#13#0#158#167#11#0#162#171'*'#0#0#0#0#0#0#0#0#0#6 +#6#6#23#164#164#164#220#172#172#172#255#154#154#154#253#175#175#175#255#173 +#173#169#255#175#174#184#255#162#167'Z'#255#143#152#0#255#143#152#1#255#143 +#152#0#255#144#153#0#255#143#152#0#255#144#153#1#255#137#147#0#255#156#159'u' +#255#195#194#202#254#184#184#181#253#185#185#185#252#177#177#177#245#144#144 +#144'B'#175#175#175#0#175#175#175#0#139#139#139#3#0#0#0#3#165#165#165#2#187 +#187#187#0#173#173#173#0#140#140#140#162#181#181#181#255#180#180#180#251#182 +#182#182#255#187#187#187#254#190#190#188#255#196#196#203#255#159#161#127#255 +#136#146#0#255#144#153#1#255#143#152#0#255#144#153#0#254#141#150#0#250#155 +#164#26#254#168#175'4'#150#175#181'7'#0#168#176'-'#2#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#162#162#162#195#174#174#174#255#154#154#154#252#174#174#174#255#172 +#172#171#255#174#173#181#255#171#173#138#255#150#159#10#255#142#151#0#255#144 +#153#0#255#144#153#0#255#144#153#0#255#143#152#0#255#144#153#0#255#135#142#29 +#255#173#172#177#254#180#180#179#255#177#177#177#253#181#181#181#254#170#170 +#170#242#164#164#164'l'#190#190#190#13#4#4#4#0'###'#0#158#158#158#0#169#169 +#169'.'#160#160#160#175#183#183#183#255#179#179#179#252#179#179#179#254#179 +#179#179#254#177#177#177#255#186#186#184#255#184#184#192#255#137#143'#'#255 +#143#153#0#255#143#152#1#255#144#153#0#254#143#152#0#255#143#151#0#251#162 +#170'('#255#162#170'-S'#166#173'2'#0#163#171')'#2#0#0#0#0#0#0#0#0#0#0#0#0#198 +#198#198#0#153#153#153#161#174#174#174#254#154#154#154#250#172#172#172#254 +#173#173#173#255#173#172#174#255#174#173#172#255#162#169'8'#255#144#153#0#255 +#143#152#0#255#143#152#0#255#143#152#0#255#142#151#0#255#144#153#1#255#139 +#148#0#255#137#141'N'#255#181#180#191#254#180#180#177#255#177#177#177#253#182 +#182#182#255#176#176#176#255#175#175#175#224#166#166#166#174#151#151#151#161 +#156#156#156#195#172#172#172#249#182#182#182#255#179#179#179#252#179#179#179 +#255#179#179#179#255#178#178#179#254#179#179#175#255#181#180#193#255#142#146 +'T'#255#140#149#0#255#144#153#1#255#143#152#0#255#143#152#0#255#142#151#0#252 +#148#157#10#253#165#172'.'#230#189#194'L'#16#165#173'%'#0#160#167'%'#0#0#0#0 +#0#0#0#0#0#0#0#0#0#161#161#161#0#147#147#147'v'#174#174#174#254#155#155#155 +#251#170#170#170#255#174#174#174#255#172#173#171#255#173#173#182#255#171#174 ,'x'#255#153#162#14#255#142#150#0#255#144#153#0#255#143#152#0#255#143#152#0 +#255#142#151#0#255#145#154#1#255#135#144#0#255#142#145'c'#255#181#180#192#254 +#181#181#180#255#178#178#176#254#179#179#179#253#180#180#180#255#181#181#181 +#255#183#183#183#255#183#183#183#255#181#181#181#255#178#178#178#252#179#179 +#180#255#179#179#179#254#178#178#176#254#181#181#179#255#182#181#193#255#145 +#148'h'#255#136#145#0#255#145#154#1#255#143#152#0#255#144#153#0#254#144#153#0 +#254#141#150#0#251#155#163#27#255#168#175'7'#134#180#187'D'#0#167#175'+'#2 +#159#167'#'#0#0#0#0#0#0#0#0#0#0#0#0#0#148#148#148#0#133#133#133'H'#172#172 +#172#255#157#157#157#253#167#167#167#254#175#175#175#255#173#173#172#255#173 +#172#174#255#173#173#170#255#167#173'B'#255#146#155#4#255#142#151#0#255#144 +#153#0#255#144#153#0#255#143#152#0#255#142#151#0#255#145#154#1#255#137#145#0 +#255#140#144'R'#255#172#172#178#254#184#183#190#254#181#181#180#254#179#179 +#176#252#178#178#176#251#178#178#177#251#178#178#177#251#178#178#177#253#179 +#179#177#254#179#179#176#254#181#181#179#254#183#183#189#255#173#173#181#255 +#141#145'X'#255#136#145#0#255#145#154#1#255#143#152#0#255#144#153#0#255#144 +#153#0#255#142#151#0#252#146#155#5#254#166#174'&'#230#168#176'0'#22#164#172 +'-'#1#160#167'.'#0#160#168'#'#0#0#0#0#0#0#0#0#0#0#0#0#0']]]'#0'RRR'#28#169 +#169#169#242#162#162#162#255#161#161#161#253#175#175#175#254#173#173#173#255 +#173#173#171#255#173#173#179#255#173#174#142#255#161#169'$'#255#143#152#0#255 +#143#152#0#255#144#153#0#255#144#153#0#255#144#153#0#255#143#152#0#255#145 +#154#1#255#140#149#0#255#134#140' '#255#152#154'z'#255#172#171#176#255#181 +#180#191#255#184#183#191#255#184#183#188#255#183#183#187#255#184#183#188#255 +#184#183#190#255#182#181#191#255#173#172#178#255#152#155#127#255#134#140'%' +#255#139#149#0#255#145#154#0#255#143#152#0#255#144#153#0#255#144#153#0#255 +#143#152#0#254#142#151#0#251#152#160#18#255#140#146'6f'#149#157'$'#0#151#158 +'%'#3#161#168','#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#229#229#229#1#249#249#249 +#2#162#162#162#204#167#167#167#254#157#157#157#252#176#176#176#255#172#172 +#172#255#173#174#173#255#172#173#171#255#174#173#181#255#171#175's'#255#157 +#166#23#255#142#151#0#255#143#152#0#255#144#153#0#255#143#152#0#255#144#153#0 +#255#143#152#0#255#144#153#1#255#144#153#0#255#136#146#0#255#134#141#27#255 +#142#146'N'#255#151#153'u'#255#157#159#138#255#160#160#145#255#157#159#139 +#255#151#153'w'#255#142#146'R'#255#134#141#31#255#136#145#0#255#144#153#0#255 +#144#153#1#255#143#152#0#255#144#153#0#255#143#152#0#255#143#152#0#254#143 +#152#1#253#147#157#1#255#152#157'F'#236#175#174'M'#16'nk'#163#0#141#143'h'#1 +#165#172'-'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#187#187#187#8#193#193#193#0#154 +#154#154#148#171#171#171#254#153#153#153#250#174#174#174#254#173#173#173#255 +#174#174#174#255#173#173#173#255#173#173#173#255#173#173#178#255#170#174'h' +#255#156#164#19#255#142#151#0#255#143#152#0#255#144#153#0#255#144#153#0#255 +#144#153#0#255#143#152#0#255#143#152#1#255#145#154#1#255#145#154#0#255#141 +#150#0#255#137#146#0#255#135#143#0#255#134#143#0#255#134#143#0#255#136#145#0 +#255#140#150#0#255#144#154#0#255#145#154#1#255#143#152#1#255#143#152#0#255 +#144#153#0#255#143#152#0#254#144#153#0#254#143#152#1#255#141#151#0#249#161 +#167'J'#252#161#161#167#170#232#231#184#0#213#212#229#1'ty%'#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#151#151#151#9#143#143#143#0#135#135#135'S'#175#175 +#175#255#159#159#159#251#173#173#173#254#173#173#173#254#173#173#173#254#174 +#174#174#255#173#173#173#255#173#173#173#255#173#173#178#255#170#174'm'#255 +#157#165#24#255#143#153#0#255#142#151#0#255#144#153#0#255#144#153#0#255#143 +#152#0#255#144#153#0#255#143#152#0#255#143#152#1#255#144#153#2#255#145#154#2 +#255#145#154#0#255#145#155#0#255#145#154#0#255#145#154#1#255#144#153#2#255 +#143#152#1#255#143#152#0#255#144#153#0#255#144#153#0#254#144#153#0#254#144 +#153#1#255#142#151#0#254#141#151#0#251#166#171'M'#249#186#185#188#255#140#140 +#142'V'#154#153#175#0#159#159#158#2'sx'#22#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#135#135#135#3'yyy'#0'rrr'#24#174#174#174#247#171#171#171#255#172#172 +#172#248#179#179#179#250#173#173#173#251#173#173#173#252#173#173#173#253#172 +#173#172#253#172#173#172#254#173#173#180#254#171#173#130#254#161#168','#255 +#147#156#2#254#142#151#0#255#143#152#1#255#144#153#1#255#144#153#0#255#144 +#153#0#255#144#153#0#255#144#153#0#255#143#152#0#255#143#152#0#255#143#152#0 +#255#143#152#0#255#143#152#0#255#144#153#0#254#144#153#0#254#144#153#0#254 +#144#153#0#254#143#152#0#253#143#152#0#250#142#152#0#251#148#157#10#255#169 +#173'g'#255#181#180#187#255#172#172#173#204#146#147#143#16#132#132'~'#0#137 +#137#137#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#21#21#21#0#183#183 +#183#1#156#156#156#0#132#132#132'Q'#161#161#161#215#163#163#163#255#185#185 +#185#255#182#182#182#255#182#182#182#255#180#180#180#255#178#178#178#255#176 +#176#176#255#174#175#173#253#174#174#182#251#172#173#161#251#165#170'W'#251 ,#153#162#21#251#145#154#0#251#142#151#0#252#142#151#0#253#142#151#0#253#143 +#152#0#253#143#152#0#254#143#152#0#254#144#153#0#254#143#153#0#254#143#152#0 +#254#143#152#0#254#143#152#0#253#143#152#0#251#143#152#0#251#144#153#0#254 +#145#154#0#255#148#157#9#255#154#161'4'#255#165#167#142#230#179#178#194#161 +#209#209#209'J'#197#197#194#6#234#234#235#0#173#173#174#0#140#140#140#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'TTT'#0#191#191#191#0'xxx'#1'aaa'#0 +#214#214#214#11#130#130#130'k'#157#157#157#152#163#163#163#176#166#166#166 +#201#170#170#170#225#173#173#173#240#176#176#176#252#176#176#176#255#176#176 +#174#255#178#178#180#255#180#180#186#255#179#180#158#255#170#175'c'#255#159 +#167'-'#255#152#161#15#255#148#157#4#255#146#155#0#255#145#154#0#255#144#153 +#0#255#143#152#0#255#143#152#0#255#144#153#0#255#145#154#0#255#143#152#3#255 +#147#156#7#255#149#157#11#255#147#155#17#255#145#151'"'#224#139#142'W'#160 +#132#130#156'T'#144#142#186#19#169#168#183#0#0#0#0#0#187#187#186#0#221#221 +#221#0#167#167#167#0#136#136#136#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#181#181#181#0'|||'#0'rrr'#2#183#183#183#0#142#142#142#0#192 +#192#192#0#0#0#0#0#0#0#0#0#0#0#0#8'XXX'#25'lll-'#142#142#142'B'#142#142#143 +'['#153#153#152't'#152#152#150#139#158#158#166#163#163#162#175#184#165#166 +#156#200#161#163't'#217#155#159'K'#230#150#157'/'#242#150#157'!'#249#151#159 +#27#252#153#161#26#255#154#161#27#255#152#160#27#253#151#159#29#242#164#171 +#28#215#152#159'"'#175#143#150'(w~'#131'.:'#13#0#255#10#255#255#0#0#255#255 +#186#0#0#0#0#0#193#191#209#2#255#255#255#2#220#220#218#0#230#230#230#0#160 +#160#160#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#142#142#142#0'xxx'#0#208#208#208#0#135#135#135#3#177#177#177#3#255#255 +#255#1'???'#0' '#0'nnn'#0#127#127#127#0#147#147#147#0#163#163#163#0#181#181 +#181#0#0#0#0#0#216#216#236#0#0#0#0#0#0#0#0#0'&'#21#255#7'aU'#255#14'b`'#136 +#26'opS''x|40'#137#142'79'#139#144':<~'#132'-0y|8'#28#238#240#7#6#181#192#3#0 +#166#173#26#0#130#136')'#0']Z'#132#0#0#0#255#2'h['#208#2#0#0#0#0#197#195#213 +#0#242#242#247#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#1#170#170#170#1'www'#2#154#154#154#3#166#166#166#4#180 +#179#180#4#255#255#255#4#184#185#186#4#255#255#255#2#255#255#230#0'5#'#255#0 +'H2'#255#0'_Z'#171#0'qrV'#0#127#132'8'#0#140#145'<'#0#143#148'?'#0#133#139'0' +#0'}'#128'9'#0#243#245#8#0#169#179#3#3#166#174#16#4#132#139'#'#3#0#0#0#1#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#143#149','#1 +'{'#129')'#2'w{3'#2'{'#127'7'#2#129#135'$'#2#0#0#0#1#253#255#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#255#255#255#255#255#255#0#0#255#255#255#255#255#255#0#0#255#255#255#255 +#255#255#0#0#255#255#255#255#255#255#0#0#255#255#255#255#255#255#0#0#255#255 +#255#255#255#255#0#0#255#255#255#255#255#255#0#0#252#0#127#255#255#255#0#0 +#248#0#0#0#7#255#0#0#224#0#0#0#7#255#0#0#192#0#0#0#3#255#0#0#192#0#0#0#3#255 ,#0#0#192#0#0#0#3#255#0#0#128#0#0#0#1#255#0#0#128#0#0#0#1#255#0#0#128#0#0#0#0 +#255#0#0#128#0#0#0#0#15#0#0#128#0#0#0#0#7#0#0#0#0#0#0#0#3#0#0#0#0#0#0#0#1#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#31#0#0#0#0#15#248#0#31#0#0#0#0#31#248#0#31#0#0#0#0 +#31#252#0#31#0#0#0#0#31#252#0#31#0#0#0#0#31#248#0#31#0#0#128#0#15#248#0#31#0 +#0#128#0#15#240#0#31#0#0#128#0#3#224#0#31#0#0#128#0#0#0#0'?'#0#0#128#0#0#0#0 +'?'#0#0#192#0#0#0#0#127#0#0#192#0#0#0#0#127#0#0#192#0#0#0#0#255#0#0#192#0#0#0 +#0#255#0#0#192#0#0#0#0#255#0#0#224#0#0#0#1#255#0#0#224#0#0#0#7#255#0#0#248#0 +#0#0#31#255#0#0#255#248#0#1#255#255#0#0#255#255#255#255#255#255#0#0#255#255 +#255#255#255#255#0#0#255#255#255#255#255#255#0#0#255#255#255#255#255#255#0#0 +#255#255#255#255#255#255#0#0#255#255#255#255#255#255#0#0#255#255#255#255#255 +#255#0#0'('#0#0#0' '#0#0#0'@'#0#0#0#1#0' '#0#0#0#0#0#128#16#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0'vvv'#0'{{{'#0'ZZZ'#0#143#143#143#2#148#148#148#2#146#146#146#2 +#146#146#146#2#146#146#146#2'nnn'#2#0#0#0#0#0#0#0#0'fff'#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#187#187#187#0'[[[' +#0'{{{'#2'aaa'#0#141#141#141#0#140#140#140#0#141#141#141#0#141#141#141#0#141 +#141#141#0#139#139#139#0'ccc'#0'aa`'#3'lko'#2#147#148'y'#3'y|O'#3'oq<'#3'uxE' +#3#139#141'j'#3#165#166#153#3#173#173#173#3#171#171#171#3#172#172#172#3#174 +#174#174#3#149#149#149#1#164#164#164#0#166#166#166#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#138#138#138#0#161#161#161#1'SSS'#2'ooo'#0'WWW'#10#133#133 +#133'.'#137#137#137','#135#135#135'-'#135#135#135'-'#135#135#135','#134#134 +#134',\\Y'#2'YYO'#0'nnj'#0#137#137'y'#0'qrP'#0'fh;'#0'kmE'#0#130#130'k'#0#166 +#166#169#0#195#193#215#0#193#192#208#0#180#180#182#0#180#180#179#0#151#151 +#151#0#157#157#157#0#157#157#157#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#141#141#141#1#158#158#158#0#159#159#159#0#135#135#135'O'#146#146#146#214#167 +#167#167#254#170#170#170#254#169#169#169#255#170#170#170#255#170#170#170#253 +#172#172#172#255#155#155#157#197#164#164#171#153#159#158#163#156#142#141#137 +#153'yyj'#146'ss]'#147'wxd'#147#133#133'|'#147#152#152#157#147#166#166#179 +#147#168#167#176#146#161#161#160#144#158#158#156#147#139#139#139'&'#143#143 +#143#0#153#153#153#1#143#143#143#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#150#150 +#150#3#145#145#145#27#163#163#163#164#164#164#164#255#159#159#159#255#172#172 +#172#254#171#171#171#255#172#172#172#255#172#172#172#255#171#171#170#255#175 +#175#176#255#155#155#148#255'~'#129'Y'#255'rv*'#255'sx'#21#255'u|'#12#255'v}' +#8#255'v|'#10#255'v{'#17#255'y~%'#255#131#134'K'#255#152#153#132#255#172#172 +#176#255#177#177#182#255#157#157#156#156#191#191#191#0#187#187#187#2#151#151 +#156#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#159#159#159#0#151#151#151#138#164#164 +#164#255#163#163#163#251#158#158#158#253#173#173#173#254#170#170#170#254#171 +#171#171#254#171#171#171#254#170#169#167#254#177#176#184#254#137#140'_'#252 +'u}'#0#251#141#150#0#251#146#156#0#251#148#157#0#251#148#158#0#251#148#158#0 +#251#147#156#0#251#143#153#0#251#136#145#0#251#127#135#0#251#129#135'%'#249 +#157#157#137#251#172#171#183#241#160#160#158#20#146#145#153#0#151#150#169#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#201#201#201#0#157#157#157#181#167#167#167#252 +#161#161#161#251#160#160#160#255#173#173#173#254#173#173#173#255#176#176#176 +#255#176#176#176#255#173#173#170#255#174#174#184#255#154#157'i'#255#145#155#3 +#255#145#154#5#255#144#153#0#255#142#151#0#255#140#150#0#255#141#150#0#255 +#143#152#0#255#145#155#0#255#147#156#0#255#148#157#0#255#144#154#0#254#133 +#142#0#251#146#150'X'#255#150#150#156'r'#163#164#158#0#166#167#151#3'ttr'#0#0 +#0#0#0#0#0#0#0#0#0#0#0#244#244#244#5#160#160#160#213#166#166#166#255#160#160 +#160#253#163#163#163#255#178#178#178#255#178#178#178#255#179#179#179#255#179 +#179#179#255#178#178#176#255#181#180#189#255#154#156'p'#255#135#145#0#255#140 +#150#0#255#139#148#5#255#146#153'('#255#151#156'<'#255#149#155';'#255#142#148 +'"'#255#135#143#6#255#136#144#11#255#136#144#15#255#136#144#19#255#140#147#22 +#252#133#141#22#254'}'#127'Q'#215'bg;'#2'lpA'#0'vvt'#0'EEE'#0'777'#0#0#0#0#0 +']]].'#162#162#162#232#169#169#169#255#163#163#163#254#168#168#168#255#181 +#181#181#255#178#178#178#255#179#179#179#255#179#179#179#255#178#178#178#255 +#183#183#184#255#158#158#151#255#137#139'l'#255#140#142'e'#255#141#142'}'#255 +#147#146#152#255#155#155#164#255#154#153#163#255#140#140#144#255#131#131'{' ,#255#147#147#142#255#147#148#146#255#146#146#146#254#146#145#149#254#144#144 +#148#252#142#142#140#255'ut~'#149'{z'#136#11#138#138#137#12''''''''#2'LLL'#2 +#255#255#255#1#133#133#133'`'#164#164#164#244#175#175#175#255#167#167#167#253 +#170#170#170#255#180#180#180#255#178#178#178#255#180#180#180#255#179#179#179 +#255#179#179#179#255#182#182#182#255#162#162#163#255#152#152#158#255#150#150 +#158#255#130#129#133#254#132#132#130#254#137#137#134#254#141#141#138#254#138 +#138#137#254#136#136#138#254#136#136#137#255#132#132#132#254#133#133#132#255 +'zzy'#255#143#143#142#254#163#163#163#253#160#160#157#255#164#165#162#224#166 +#166#166#225#148#148#148#160#197#197#197#0#173#173#173#5#141#141#141#145#169 +#169#169#249#175#175#175#255#167#167#167#254#169#169#169#255#181#181#181#255 +#179#179#179#255#179#179#179#255#180#180#180#255#178#178#178#255#182#182#182 +#254#163#163#162#255#143#143#141#254#140#140#137#251#147#147#146#251#156#156 +#156#251#155#155#155#251#159#159#159#252#151#151#150#253'yyx'#253#127#127'~' +#255#127#128#127#254'}}|'#255#139#139#139#254#174#173#176#255#177#176#180#254 +#176#175#179#252#175#175#179#255#176#175#177#255#171#171#172#255#151#151#153 +'|'#154#154#154#6#150#150#150#186#172#172#172#251#174#174#174#255#167#167#167 +#255#168#168#168#255#182#182#182#255#178#178#179#255#179#179#179#255#179#179 +#179#255#178#178#178#255#181#181#181#255#168#168#168#255#177#177#177#255#154 +#154#154#255#133#133#133#255#135#135#135#255#132#132#132#255'{{{'#255'vvv' +#255'rrr'#255'www'#255'www'#255'~~'#127#254#163#163#160#255#161#162#148#254 +#159#160#147#254#160#161#146#254#157#157#144#253#155#155#155#229#157#157#157 +#225#154#154#151#236'~~~l'#154#154#154#207#173#173#173#252#176#176#176#255 +#169#169#169#254#169#169#168#255#182#182#180#255#179#179#177#255#180#180#178 +#255#180#180#178#255#179#179#178#255#181#181#181#254#172#172#172#254#184#184 +#184#251#137#137#137#142'mmms|||giiiZ'#182#182#182'K'#182#182#182'B'#161#161 +#161#212#178#178#178#255#179#179#178#251#186#186#188#255#172#173#163#255#133 +#141#9#255#138#147#2#254#139#148#2#252#131#139#1#254'ou'#13'Ylr'#6#10'rx'#7 +#14'lll'#14#155#155#155#210#172#172#172#253#168#168#168#255#162#162#162#255 +#168#168#170#255#181#180#190#255#178#178#187#255#179#179#188#255#179#178#187 +#255#178#177#184#255#177#177#176#250#170#170#170#254#168#168#168#188#219#219 +#219#0#223#223#223#0'555'#0'qqq'#0#183#183#183#0#186#186#186#0#164#164#164'c' +#192#192#192#255#194#194#193#250#194#194#192#254#190#189#196#255#144#151'"' +#255#143#153#0#255#144#152#0#250#145#154#0#255#148#157#6'y'#147#156#1#0#146 +#156#0#0'ppp'#0#155#155#155#203#170#170#170#252#157#157#155#255#161#161#165 +#254#156#157#135#255#144#150'7'#255#144#150'6'#255#144#150'4'#255#143#149'1' +#255#145#149'P'#255#174#174#178#249#179#179#178#254#170#170#170#144#196#196 +#196#4#195#195#195#5#154#154#154#3'~~~'#3#155#155#155#4#155#155#155#2#151#151 +#151';'#186#186#186#254#191#191#191#252#191#191#189#253#190#190#198#255#145 +#151'/'#255#141#151#0#254#143#151#1#251#143#152#0#255#146#156#3#136#145#154#0 +#0#145#154#0#4#0#0#0#0#152#152#152#172#169#169#169#251#163#163#160#255#178 +#178#185#255#168#169#138#255#141#151#0#255#142#152#0#255#142#151#0#255#142 +#152#0#255#142#150#25#255#189#189#194#250#195#195#194#255#174#174#173#177#232 +#232#232#0#211#211#211#3#189#189#189#0#138#138#138#0#178#178#178#3#178#178 +#178#0#159#159#159'V'#190#190#190#255#191#191#191#250#192#192#191#254#188#187 +#193#255#142#149#30#255#143#152#0#255#143#152#0#250#143#152#0#254#146#155#6 +#129#143#153#0#0#144#153#0#4#0#0#0#0#143#143#143'y'#169#169#169#248#161#161 +#161#255#174#174#177#254#171#171#160#255#146#155#13#255#142#151#2#255#143#152 +#2#255#144#154#2#255#138#147#5#255#175#176#160#253#195#195#198#252#182#182 +#181#246#146#146#146'.'#166#166#166#0#185#185#185#0'xxx'#1#209#209#209#0#196 +#196#196#0#171#171#171#195#188#188#188#254#189#189#188#251#195#195#197#255 +#176#177#164#255#137#146#3#255#144#153#0#254#142#151#0#251#148#157#11#255#164 +#171'%_'#161#168'$'#0#159#166#30#3#0#0#0#0'mmm='#168#168#168#236#162#162#162 +#255#173#173#172#253#175#174#180#255#158#164':'#255#141#151#0#255#144#153#1 +#255#144#152#2#255#141#150#0#255#149#154'M'#255#183#182#194#252#179#179#174 +#255#170#170#170#224#180#180#180'G'#180#180#180#5#189#189#189#0#171#171#171 +'#'#155#155#155#168#179#179#179#255#178#178#178#252#179#179#174#255#190#189 +#201#254#151#156'O'#255#140#149#0#254#144#153#2#254#142#151#0#254#157#165#30 +#248#163#168'D%'#177#184'H'#0#165#173','#1#0#0#0#0#225#225#225#10#167#167#167 +#216#162#162#162#255#172#172#170#253#174#173#182#255#170#172'{'#255#146#156#2 +#255#142#151#1#255#143#152#0#255#144#153#1#255#136#145#1#254#155#157'~'#255 +#183#183#193#253#181#181#177#255#173#173#171#255#164#164#164#213#183#183#182 +#201#175#175#175#243#181#181#181#255#178#178#176#252#179#179#175#255#183#182 +#194#254#157#159'}'#255#138#147#2#255#144#153#1#255#142#151#0#251#145#154#4 +#254#163#171'*'#191'|'#130' '#0#162#170'('#1#154#165#0#0#0#0#0#0#221#221#221 ,#0#165#165#165#181#163#163#163#254#171#171#170#252#173#173#174#254#174#174 +#174#255#162#168'8'#255#142#151#0#255#143#152#1#255#143#152#0#255#144#153#1 +#254#137#146#7#254#154#156's'#255#179#178#189#253#184#184#191#253#184#184#185 +#255#179#179#178#255#182#182#181#255#181#181#181#251#182#182#188#255#179#179 +#189#254#154#157'u'#254#138#147#7#255#144#153#0#254#143#152#0#254#142#151#0 +#252#153#161#16#253#163#170'7E'#175#182'8'#0#163#170'('#2#162#171#25#0#0#0#0 +#0#172#172#172#0#162#162#162#132#163#163#163#254#168#168#168#251#174#174#173 +#255#173#173#179#255#173#174#146#255#155#163#21#255#141#150#0#255#144#153#1 +#255#143#152#0#255#144#153#0#255#139#148#0#254#142#148'7'#254#159#161#128#254 +#170#170#166#252#175#175#179#251#175#174#178#253#170#170#167#254#159#160#129 +#254#143#148'9'#254#139#148#0#255#144#153#0#255#143#152#0#255#143#152#2#251 +#144#154#0#254#150#157'('#182#148#157#25#0#166#174#30#1#160#168'%'#0#164#172 +'%'#0#0#0#0#0#156#156#156#0#150#150#150'I'#165#165#165#254#164#164#164#252 +#174#174#175#254#173#173#171#254#173#173#181#254#171#175#128#255#152#161#13 +#255#141#150#0#255#143#152#1#255#144#153#1#255#145#154#1#255#142#152#0#255 +#138#147#0#255#138#146#12#255#139#146#29#255#139#146#30#255#138#145#13#255 +#138#147#0#255#142#152#0#254#144#153#1#254#143#152#0#254#143#152#0#253#140 +#150#0#248#158#164'@'#255#155#155#162'\'#169#170#158#0#166#168#132#3#163#171 +'0'#0#0#0#0#0#0#0#0#0#154#154#154#0#146#146#146#18#169#169#169#244#170#170 +#170#255#176#176#176#251#172#172#172#251#172#172#171#251#173#172#183#251#171 +#174#132#251#154#162#24#252#141#151#0#253#142#151#0#254#143#152#1#254#144#153 +#1#254#145#154#1#254#144#154#0#255#144#153#0#254#144#153#0#254#144#154#0#254 +#145#154#0#254#144#152#1#252#143#152#0#251#143#152#0#254#143#153#0#255#164 +#169'K'#255#178#178#179#242#134#133#145#19#142#141#167#0#158#156#196#0#0#0#0 +#0#0#0#0#0#0#0#0#0#193#193#193#4#186#186#186#0#165#165#165'g'#158#158#158#236 +#178#178#178#255#179#179#179#255#177#177#177#255#177#177#175#255#176#175#183 +#255#175#175#159#255#164#169'N'#255#150#158#13#255#143#153#0#255#143#152#0 +#254#143#152#0#252#142#152#0#252#142#151#0#252#142#151#0#252#142#152#0#253 +#143#152#0#255#144#153#0#255#146#155#3#255#147#155#27#255#158#162'd'#217#172 +#170#188#142#167#167#178'0'#141#141#133#0#160#161#142#0#160#159#181#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0'{{{'#1#151#151#151#0'jjj'#25#150#150#150'L'#152#152 +#152'f'#168#168#168#129#162#162#162#157#170#170#168#183#170#170#175#205#174 +#173#182#224#170#172#143#240#161#166'T'#250#152#159'('#255#148#156#19#255#147 +#156#12#255#148#157#11#255#148#156#11#255#149#157#13#255#149#157#17#241#144 +#152#21#201#135#141'('#136'y{Y@ljv'#6#173#170#203#0#228#227#231#0#0#0#0#0#155 +#156#152#0#153#153#153#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#130#130#130#0#166 +#166#166#2'kkk'#0#166#166#166#0#180#180#180#0#178#178#178#0#251#252#252#0#202 +#202#199#0#0#0#0#0#18#20#0#8'wr'#188#22#148#144#210'%'#149#149#150'3'#137#141 +'OC'#140#146'.P'#149#156'-Y'#146#152'+T'#149#155'-<'#136#140':'#25'ruD'#0'y|' +'('#0'JU'#0#0#138#169#0#0#181#177#215#3#215#215#220#2#247#247#253#0#169#169 +#169#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#150#150#150#0#165#165#165#0'g' +'gg'#1#167#167#167#3#184#184#184#3#185#185#185#3#255#255#255#2#200#200#199#1 +#0#0#0#0#0#0#0#0#135#131#215#0#156#152#213#0#151#150#146#0#149#155'E'#0#148 +#154'+'#0#157#164'*'#0#153#160')'#0#155#162'.'#0#150#156'5'#0'sv@'#0'x{+'#3 +#128#136#6#2'tx-'#0#193#191#211#0#218#218#221#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#145#144#147#2#131#130#134#2#149#156'5' +#3#154#161'"'#3#160#168'"'#3#156#164' '#3#153#160'#'#2#0#0#0#1#0#0#0#0#138 +#143'&'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#240 +#0#0#255#192#0#0#127#128#0#0#127#128#0#0'?'#128#0#0'?'#128#0#0#31#0#0#0#3#0#0 +#0#1#0#0#0#0#0#0'`'#7#0#7#224#7#0#7#240#7#0#7#224#7#0#7#224#7#128#3#192#15 +#128#0#0#15#128#0#0#31#128#0#0#31#192#0#0#31#192#0#0'?'#192#0#0#127#248#0#3 +#255#255#254'?'#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255 +#255#255'('#0#0#0#24#0#0#0'0'#0#0#0#1#0' '#0#0#0#0#0'`'#9#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 ,#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#167#167#167 +#0#165#165#165#0#0#0#0#1#177#177#177#2#179#179#179#2#179#179#179#2#181#181 +#181#2#0#0#0#1#193#193#193#0#183#183#183#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'ccc'#0 +#155#155#155#0#145#145#145#2#129#129#129#0#160#160#160#0#161#161#161#0#161 +#161#161#0#163#163#163#0#145#145#145#0#164#164#173#0#198#196#225#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#255#0#0#0#0#0#133#133#133#0'{{{'#0'LLL'#0#184#184 +#184#0#0#0#0#0#0#0#0#0#0#0#0#0#142#142#142#0#163#163#163#0#130#130#130#0'{{{' +'$'#153#153#153'H'#154#154#154'E'#153#153#153'E'#155#155#155'H'#138#139#138 +'&'#162#162#170#0#216#213#255#0#0#0#0#0#3','#0#0#0#0#0#0#0#0#0#0'V`'#0#0#0#0 +#0#0#0#0#0#0#218#218#216#0#238#238#233#0#172#172#172#0#0#0#0#0#0#0#0#0#0#0#0 +#0#154#154#154#2#162#162#162#11#150#150#150'~'#156#156#156#246#171#171#171 +#255#171#171#171#255#170#170#170#255#173#173#173#255#163#163#164#247#151#151 +#144#215#135#137'h'#216'tx;'#212'qu.'#211'uy<'#211#130#133']'#211#151#152#142 +#211#169#169#179#209#170#169#174#211#147#147#146'1'#152#152#151#0#168#168#168 +#1#156#157#145#0#0#0#0#0#0#0#0#0#198#198#198#0#157#157#157#171#164#164#164 +#255#162#162#162#254#172#172#172#252#170#170#170#253#170#170#168#253#175#175 +#180#252#151#152#131#255'sz'#8#255#130#138#0#255#137#146#0#255#139#148#0#255 +#137#146#0#255#133#141#0#255#131#138#15#255#139#143'A'#255#163#163#150#255 +#166#165#175#159#196#196#200#0#187#187#187#2#145#146'x'#0#147#147#147#0#0#0#0 +#0#204#204#204#13#163#163#163#226#163#163#163#252#162#162#162#252#174#174#174 +#255#176#176#176#254#175#175#174#254#177#176#185#255#158#160'z'#254#143#153#0 +#253#147#157#0#253#144#153#0#253#143#153#0#253#144#154#0#253#147#156#0#253 +#145#155#0#253#139#150#0#251#135#144#0#253#146#150'Z'#243#172#169#213#20#167 +#166#201#2#150#152#131#4#147#147#147#1#0#0#0#0'wwwC'#164#164#164#239#163#163 +#163#254#167#167#167#253#180#180#180#254#179#179#179#255#179#179#178#255#183 +#182#187#255#163#164#146#255#134#140'%'#255#138#144'('#255#146#150'Y'#255#156 +#158'v'#255#147#150'e'#255#132#136'<'#255#140#144'F'#255#142#146'O'#254#143 +#148'M'#252#135#138'P'#255'tti'#139'yzh'#0#129#131'g'#0#129#129#129#0#161#161 +#161#1#145#145#145#127#168#168#168#248#169#169#169#255#171#171#171#254#181 +#181#181#255#178#178#178#255#178#178#178#255#182#182#181#254#167#167#169#255 +#147#146#155#254#141#140#149#252#135#134#146#252#144#144#153#252#144#144#154 +#251#136#135#147#253#141#140#152#255#139#139#150#254#130#129#142#254#149#149 +#155#254#157#157#156#255#154#154#156#177#154#154#159#164#129#129#129#24#135 +#135#133#0#151#151#151#179#172#172#172#252#170#170#170#255#170#170#170#254 +#180#180#180#255#178#178#179#255#178#178#178#255#181#181#182#255#169#169#169 +#255#149#149#148#255#139#139#138#255#149#149#147#255#148#148#147#255#144#144 +#142#255'zzx'#255'vvt'#255'ttr'#255#138#138#137#255#175#174#186#255#175#175 +#187#254#175#174#184#255#175#175#181#255#162#161#169#213#161#161#169','#158 +#158#158#214#174#174#174#253#171#171#171#255#170#170#170#255#181#181#179#255 +#179#179#177#255#179#179#178#255#181#181#180#254#175#175#175#255#178#178#178 +#253#149#149#149#215'zzz'#204#131#131#131#193#151#151#151#177#135#135#135#232 +#145#145#144#255#150#150#153#253#164#165#154#255#146#151'L'#254#148#153'I' +#254#142#146'J'#250#127#129'_'#135#127#129'Z'#131'wzMN'#161#161#161#223#171 +#171#171#254#164#164#164#255#169#168#171#254#180#179#187#255#177#177#185#255 +#178#177#184#255#177#177#179#251#173#173#172#255#168#168#168#163#190#190#190 +#0#170#170#170#0#192#192#192#0#187#187#187#0#170#170#170']'#194#194#194#255 +#198#198#200#252#185#185#181#254#139#148#4#254#141#151#0#253#140#150#0#254 +#136#144#0'.'#136#145#0#0#139#148#0#0#163#163#163#214#164#164#163#253#163#162 +#169#255#158#160'}'#255#144#150')'#255#145#151'*'#255#141#148'$'#255#160#162 +'|'#251#184#183#190#254#170#170#167'n'#183#183#183#0#190#190#190#3#192#192 +#192#3#164#164#164#4#157#157#157'.'#188#188#188#254#191#192#191#254#188#188 +#191#253#144#152#29#255#143#152#2#252#144#153#2#254#148#157#5'Q'#146#156#0#3 +#147#157#0#4#159#159#159#176#165#165#163#252#173#172#181#255#167#170#129#254 +#141#150#0#255#143#152#0#255#139#149#0#255#158#162'V'#251#198#197#210#255#177 +#177#172#177#207#207#207#0#204#204#204#0#194#194#194#0#188#188#188#0#167#167 +#167'n'#189#189#189#255#195#194#197#251#182#182#176#254#140#149#8#254#143#152 +#0#253#145#154#4#255#160#167#27'>'#154#162#20#0#152#161#14#2#154#154#154'r' +#164#164#164#247#169#169#171#255#174#174#166#254#148#156#16#255#142#151#2#255 +#143#153#1#255#142#149#21#254#179#178#182#252#182#182#184#255#157#157#155'|' +#159#159#159#13#168#168#168#5#170#170#170'O'#176#176#175#240#179#180#176#253 +#191#190#206#253#161#164'j'#255#139#149#0#253#142#151#0#254#154#163#24#241 +#153#160'E'#19#178#184'N'#0#171#179'0'#0#148#148#148'+'#164#164#164#234#168 +#168#166#255#176#175#185#253#163#168'Q'#255#141#151#0#255#144#153#2#255#141 ,#150#0#255#145#150'C'#254#179#178#191#254#183#183#189#255#175#175#174#232#174 +#175#173#222#176#176#175#255#181#181#182#255#183#182#197#254#163#164#141#255 +#139#148#8#255#143#152#0#251#145#154#2#255#161#168'&'#166#137#147#20#0#152 +#160#27#2#171#178'/'#0#211#211#211#0#163#163#163#205#166#166#165#254#174#174 +#178#252#174#175#162#254#154#162#25#255#140#150#0#255#145#153#3#254#140#150#0 +#255#143#149'1'#254#166#167#148#253#178#178#184#255#180#180#190#255#179#179 +#189#254#173#173#172#254#155#158'i'#255#139#147#6#254#144#153#0#254#141#151#0 +#252#147#156#8#246#164#173'.%'#162#169')'#0#163#171'%'#1#166#174'%'#0#174#174 +#174#0#161#161#161#158#165#165#165#254#173#173#171#248#173#172#180#252#172 +#174#137#253#150#159#11#253#140#150#0#254#144#153#2#254#143#152#0#254#139#148 +#0#254#143#150' '#253#146#152'7'#252#145#150'0'#254#140#148#16#254#140#149#0 +#254#144#153#0#252#140#150#0#249#147#156#7#255#159#162'c'#186#177#187'K'#0 +#171#177'\'#1#164#172')'#0#0#0#0#0#174#174#174#0#167#167#167'P'#168#168#168 +#255#176#176#176#255#174#175#173#255#175#175#183#255#172#174#143#255#154#162 +'$'#255#142#152#0#254#142#151#0#253#144#153#0#252#143#152#0#251#142#151#0#251 +#142#152#0#251#143#153#0#254#144#153#0#255#143#153#1#255#148#156#28#255#170 +#172#135#239#173#171#196'O'#178#176#196#1#188#189#188#1#163#170'('#0#0#0#0#0 +#187#187#187#1#163#163#163#1#135#135#135'T'#167#167#167#163#174#174#174#189 +#170#170#168#213#174#174#182#233#173#173#169#248#166#170'f'#255#153#160'(' +#255#147#155#13#255#145#154#7#255#146#155#6#255#146#154#7#255#146#155#8#255 +#143#151#13#233#142#149'('#175#147#150'rb'#151#152#145#24#165#165#171#0#148 +#149#138#0#188#188#186#0#0#0#0#0#0#0#0#0#190#190#190#0#188#188#188#0#169#169 +#169#0#186#186#186#0#212#212#213#0#1#1#7#0'y|H'#12#127#127#138#28#170#166#231 +'.'#161#161#164'A'#152#156'NS'#144#151'&b'#150#157'"k'#146#153'#_'#141#147'$' +'9'#130#135'('#15'E>'#146#0#182#181#191#0#187#173#255#0#170#169#183#0#160#159 +#165#0#189#190#184#0#0#0#0#0#0#0#0#0#204#204#204#0#0#0#0#0'uuu'#2#180#180#180 +#2#207#207#207#1'BBC'#0#142#143#137#0#144#143#152#0#172#169#213#0#166#167#155 +#0#155#160'B'#0#153#161#30#0#154#162#28#0#151#159#30#0#149#156'#'#0#130#134 +')'#0'][^'#1'}'#132#22#2'dp'#0#0#195#195#199#0#183#183#185#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#180#180#179 +#1#188#187#196#2#174#176#138#2#161#169''''#2#152#160#27#3#155#163#23#3#155 +#164#24#3#159#167#27#2#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#192#0'?'#0#128#0#31#0#128#0#31#0#128#0 +#15#0#0#0#3#0#0#0#1#0#0#0#1#0#0'<'#7#0#0'>'#3#0#0'<'#7#0#0#28#7#0#128#0#7#0 +#128#0#15#0#128#0#15#0#128#0#31#0#192#0'?'#0#255#195#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0'('#0#0#0#16#0#0#0' '#0#0#0#1#0' '#0#0#0#0#0'@'#4#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#180#180#180#0#215#215#215#0#0#0#0#6#176#176 +#176#9#177#177#177#9#170#170#170#7#205#205#206#4#181#182#176#4#148#149#127#3 +#167#168#165#3#169#169#170#4#0#0#0#3#0#0#0#0#159#159#159#0#152#152#152#0#0#0 +#0#0#161#161#161#0#172#172#172#1#150#150#150#0#167#167#168#0#167#167#166#0 +#169#169#174#0#191#189#228#0#156#154#181#0'hf~'#0#141#138#191#0#182#178#255#0 +#158#158#158#0#138#138#138#0#138#138#136#0#147#147#147#0#0#0#0#0#164#164#164 +#0#168#168#168#0#147#147#147'F'#164#164#164'd'#164#164#163'd'#161#161#164'T' +#180#179#203')'#159#157#176'''jh~%'#135#132#176'%'#171#167#233'&'#159#159#172 +'"~~w'#0#130#132'h'#0#144#147'^'#0#0#0#0#0#152#152#152#17#160#160#160#165#162 +#162#162#255#171#171#171#255#172#172#174#255#163#163#157#255#135#139'B'#254 +#131#138#29#253#128#134#13#252#132#138' '#252#143#147'N'#250#163#164#152#248 +#160#159#166'8'#167#165#186#3#173#173#182#4#0#0#0#0#152#152#152'\'#162#162 +#162#254#166#166#166#252#176#176#175#250#178#177#183#250#164#165#145#251#136 +#146#0#254#145#154#0#254#147#155#16#255#142#151#0#255#138#148#0#250#141#148 +#26#255#143#146'f'#160#153#159'I'#0#149#155'G'#0#251#251#251#2#157#157#157 +#161#166#166#166#250#172#172#172#254#180#180#180#255#181#181#182#254#172#172 +#170#255#141#143'q'#253#140#141'}'#252#149#149#149#254#137#138'}'#253#139#140 +'}'#254#137#138'z'#253#144#145#133#247#146#149'r{'#145#147'oA'#154#154#157#0 +#163#163#163#212#172#172#172#253#173#173#173#255#180#180#180#254#180#180#180 +#255#176#176#176#255#153#153#159#255#137#137#140#255#141#141#141#255#129#129 +#132#255'zz~'#255#141#141#142#254#167#168#161#254#165#165#165#255#158#158#173 +#228#163#162#157'Z'#167#167#167#235#169#169#168#253#170#170#172#255#178#178 +#180#255#177#177#179#252#176#176#175#254#167#167#166#159#155#155#153'A'#169 +#169#169'1'#161#161#158's'#181#181#184#254#178#179#162#251#141#149#13#254#139 +#148#7#232'{'#129#29'%'#148#155#19#29#163#163#158#225#166#165#174#254#158#161 ,'o'#255#143#151#29#254#144#151'%'#250#180#180#176#255#177#177#180'U'#193#193 +#199#0#180#180#179#0#170#170#167')'#194#194#195#255#186#187#179#253#143#151#7 +#254#144#153#0#244#158#167#12#24#154#163#18#0#160#160#153#173#168#168#175#252 +#168#170#128#255#142#152#0#255#139#149#0#253#170#172#133#254#183#183#196#207 +#187#187#186'('#184#184#181#27#172#172#166#176#188#187#200#254#169#171#127 +#250#139#149#0#254#151#159#17#221#137#144'7'#7#133#142#19#2#153#153#152'a' +#165#165#165#244#174#174#176#254#154#161'*'#254#141#150#0#255#142#150#23#254 +#167#169#146#255#175#174#184#247#179#179#189#241#181#180#191#255#167#168#146 +#254#142#150#18#248#143#152#0#253#154#162#26#133#138#147#10#0#149#158#14#8 +#163#163#163#18#166#166#164#230#173#173#178#255#172#173#148#253#149#158#18 +#252#140#150#0#251#140#149#0#248#151#157'>'#253#155#159'U'#254#149#155'8'#248 +#140#149#0#253#142#152#0#255#152#159'-'#253#164#168#128#23#176#176#138#0#165 +#169'i'#2#176#176#176#0#153#153#153'~'#170#170#168#232#174#174#180#247#171 +#173#151#255#156#162';'#255#146#155#12#255#142#152#0#255#142#151#0#255#143 +#152#0#255#143#152#8#251#150#156'3'#204#166#168#137'k'#180#186#144#0#183#184 +#142#1#150#167#0#0#255#255#255#1#0#0#0#0'ssw'#14#145#146#134'"'#155#154#173 +'7'#175#174#189'M'#159#163'Pb'#145#152'"s'#149#156#29'y'#149#156#30'^'#140 +#146'&+'#143#148';'#0#153#161'('#0'jW='#0#186#187't'#0#143#160#0#0#208#208 +#208#0'III'#2#0#0#0#0#161#161#154#0#170#168#200#0#179#177#200#0#159#163'T'#0 +#149#157#17#0#150#158#14#0#148#156#18#0#140#146')'#0#143#147'G'#0#162#168'<' +#3'}ci'#0#165#173'A'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2#187#187#185#4#183#183 +#188#6#181#181#169#8#162#168'E'#9#149#157#9#10#148#157#10#10#145#154#1#9#144 +#151#25#5#151#159#29#0#157#165#28#0#155#160'N'#0#0#0#0#0#0#0#0#0#255#255#0#0 +#255#255#0#0#227#255#0#0#128#15#0#0#0#7#0#0#0#3#0#0#0#0#0#0#1#131#0#0#1#195#0 +#0#1#131#0#0#0#3#0#0#128#7#0#0#128#7#0#0#252'?'#0#0#255#255#0#0#255#255#0#0 ]); mricron-0.20140804.1~dfsg.1.orig/dcm2nii/zconf.inc0000755000175000017500000000127410251505620017342 0ustar mihmih{ -------------------------------------------------------------------- } {$DEFINE MAX_MATCH_IS_258} { Compile with -DMAXSEG_64K if the alloc function cannot allocate more than 64k bytes at a time (needed on systems with 16-bit int). } {- $DEFINE MAXSEG_64K} {$IFNDEF WIN32} {$DEFINE UNALIGNED_OK} { requires SizeOf(ush) = 2 ! } {$ENDIF} {$UNDEF DYNAMIC_CRC_TABLE} {$UNDEF FASTEST} {$define patch112} { apply patch from the zlib home page } { -------------------------------------------------------------------- } {$IFDEF FPC} {$DEFINE Use32} {$UNDEF DPMI} {$UNDEF MSDOS} {$UNDEF UNALIGNED_OK} { requires SizeOf(ush) = 2 ! } {$UNDEF MAXSEG_64K} {$ENDIF} mricron-0.20140804.1~dfsg.1.orig/dcm2nii/philips_bvec_old.pas0000755000175000017500000002351712321753472021560 0ustar mihmihunit philips_bvec; {$ifdef fpc}{$mode delphi}{$endif} {$H+} interface uses //StrUtils, Classes, SysUtils, define_types, dicomtypes, dialogsx,GraphicsMathLibrary,dialogs_msg; //{$DEFINE VERBOSE_BVEC} procedure PhilipsCorrectBvecs(var lDICOMdata:dicomdata; var lDTIra: TDTIRA; nVec: integer); implementation procedure ReportMatrix(s: string; q: TMatrix); begin dcmmsg(s+Format('=[ %g %g %g %g; %g %g %g %g; %g %g %g %g; 0 0 0 1]', [ q.matrix[1,1],q.matrix[1,2],q.matrix[1,3],q.matrix[1,4] , q.matrix[2,1],q.matrix[2,2],q.matrix[2,3],q.matrix[2,4] , q.matrix[3,1],q.matrix[3,2],q.matrix[3,3],q.matrix[3,4]])); end; //Next routines for PhilipsBVec FUNCTION Vector2D (CONST xValue, yValue, zValue: DOUBLE): TVector; BEGIN WITH RESULT DO BEGIN x := xValue; y := yValue; z := zValue; size := size2D END END; //Vector2D // Assume vector contains 'extra' homogeneous coordinate -- ignore it. procedure NormalizeVector2D(var u: TVector); var lSum: double; BEGIN lSum := sqrt((u.x*u.x)+(u.y*u.y)+(u.z*u.z)); if lSum <> 0 then u := Vector2D( u.x/lSum, u.y/lSum, u.z/lSum) END; //NormalizeVector2D FUNCTION revMat (CONST Input:TMatrix): TMatrix;//Transpose Matrix var i,j: integer; begin result.size := Input.size; for i := 1 to Input.size do for j := 1 to Input.size do result.matrix[i,j] := input.matrix[j,i]; end; FUNCTION VecMatMult (CONST u: TVector; CONST a: TMatrix): TVector; VAR i,k : TIndex; temp: DOUBLE; BEGIN RESULT.size := a.size; IF a.size = u.size THEN BEGIN FOR i := 1 TO a.size DO BEGIN temp := 0.0; FOR k := 1 TO a.size DO BEGIN temp := temp + u.vector[k]*a.matrix[i,k]; END; RESULT.vector[i] := Defuzz(temp) END; END ELSE raise EMatrixError.Create('VecMatMult error') END;//VecMatMult procedure PhilipsCorrectBvecs(var lDICOMdata:dicomdata; var lDTIra: TDTIRA; nVec: integer); //Test lIn.x := 0.499997615814209; lIn.y := 0.499997615814209; lIn.z := 0.707110166549683; //Philips DICOM data stored in patient (LPH) space, regardless of settings in Philips user interface //algorithm inspired by CATNAP http://godzilla.kennedykrieger.org/~jfarrell/software_web.htm //http://iacl.ece.jhu.edu/~bennett/catnap/catnap.shtml //0018,5100. patient orientation - 'HFS' //2001,100B Philips slice orientation (TRANSVERSAL, AXIAL, SAGITTAL) //2005,1071. Philips AP angulation : -8.74086 //2005,1072. Philips FH angulation : -3.53147 //2005,1073. Philips RL angulation -0.387372 (* 3/2008: updated to correct for a bug in the Johns Hopkins code: % July 20, 2007 | I corrected a small bug with the rotation matrices for % slice angulation. I had multiplied 3 matrices in the incorrect order. % A colleague (Harsh Agarwal) pointed this out while aligning different % MRI contrasts using the angulation parameters and the transformation % matrices given in the Philips document. %I originally had Tang = Tfh*Tap*Trl % which is now Tang = Trl*Tap*Tfh; %I originally had rev_Tang = rev_Trl*rev_Tap*rev_Tfh; %which is now rev_Tang = rev_Tfh*rev_Tap*rev_Trl; % I double checked the Philips code and this seems to be correct now. % I also double checked the impact on fiber tracking. The fiber tracking % looks good in both instances (even though the gradient tables are % slightly different). If 2 angulation values are zero (i.e. [AP,FH,RL] = % [0,0,20], then the old and new equations give the same result. Only if % two or more elements are non zero is the result different. I did some % testing with very large angulations of 20 degrees [20,20,0], [20,0,20] % and [0,20,20]and found that the fiber tracking results were almost % indistinguishable. THIS FIX ONLY affects yes overplus and % user-defined gradient tables. No overplus tables are not subject to % slice angulation changes *) var lIn,lOut: TVector; ltpp,lrev_tpp,ltpom,lrev_tpom,ltpo,lrev_tpo,ltrl,ltap,ltfh, lmtemp1,lmtemp2 ,ltang,lrev_tang, lrev_trl, lrev_tap, lrev_tfh, lrev_tsom,ldtiextra: TMatrix; lI: Integer; lap,lfh,lrl: double; begin if nVec < 1 then exit; //require HFS - head first supine. See Catnap for alternate body orientations // and (lDicomData.PatientPos[1] = 'H') and (lDicomData.PatientPos[2] = 'F') and (lDicomData.PatientPos[3] = 'S') then if (length(lDicomData.PatientPos) < 3) then begin //HFS = head-first supine dcmMsg('DTI vector error: Position is not head first supine'); exit; end; if (lDicomData.PatientPos[1] = 'F') and (lDicomData.PatientPos[2] = 'F') then begin//strcmpi(patient_position,'ff') ltpp := Matrix2D (0,-1,0, -1,0,0, 0,0,1); //rev_Tpp = [0,-1,0;-1,0,0;0,0,-1]; end else if (lDicomData.PatientPos[1] = 'H') and (lDicomData.PatientPos[2] = 'F') then begin//strcmpi(patient_position,'hf') ltpp := Matrix2D (0,1,0,-1,0,0, 0,0,-1); //rev_Tpp = [0,-1,0;1,0,0;0,0,-1]; end else begin dcmMsg('DTI vector error: images must be HF or FF (head or feet first) '+lDicomData.PatientPos); exit; end; lrev_tpp := revMat(ltpp); (* http://www.dabsoft.ch/dicom/3/C.7.3.1.1.2/ see matlab code http://godzilla.kennedykrieger.org/~jfarrell/software_web.htm#PARtoNRRD HFP = Head First-Prone HFS = Head First-Supine HFDR = Head First-Decubitus Right HFDL = Head First-Decubitus Left FFDR = Feet First-Decubitus Right FFDL = Feet First-Decubitus Left FFP = Feet First-Prone FFS = Feet First-Supine *) if lDicomData.PatientPos[3] = 'S' then begin//supine ltpo := Matrix2D (1,0,0, 0,1,0, 0,0,1); //rev_Tpo = [1,0,0;0,1,0;0,0,1]; end else if lDicomData.PatientPos[3] = 'P' then begin //prone ltpo := Matrix2D (-1,0,0, 0,-1,0, 0,0,1); //rev_Tpo = [-1,0,0;0,-1,0;0,0,1]; end else if (length(lDicomData.PatientPos) > 3) and (lDicomData.PatientPos[3] = 'D') and (lDicomData.PatientPos[4] = 'R') then begin //rd ltpo := Matrix2D (0,-1,0, 1,0,0, 0,0,1); //rev_Tpo = [0,1,0;-1,0,0;0,0,1]; end else if (length(lDicomData.PatientPos) > 3) and (lDicomData.PatientPos[3] = 'D') and (lDicomData.PatientPos[4] = 'L') then begin //ld ltpo := Matrix2D (0,1,0, -1,0,0, 0,0,1); //rev_Tpo = [0,-1,0;1,0,0;0,0,1]; end else begin dcmMsg('DTI vector error: Position is not HFS,HFP,HFDR,HFDL,FFS,FFP,FFDR, or FFDL: '+lDicomData.PatientPos); exit; end; lrev_tpo := revMat(ltpo); dcmMsg('Reorienting vectors for patient position ('+lDicomData.PatientPos+'). Please validate if you conduct DTI processing.'); (* //Assume supine ltpo := Matrix2D (1,0,0, 0,1,0, 0,0,1 ); lrev_tpo := revMat(ltpo); //Assume head first ltpp := Matrix2D (0,1,0, -1,0,0, 0,0,-1); lrev_tpp := revMat(ltpp); *) ltpom := MultiplyMatrices( ltpo, ltpp); lrev_tpom := MultiplyMatrices( lrev_tpp,lrev_tpo ); lap := lDicomData.AngulationAP * PI /180; lfh := lDicomData.AngulationFH * PI /180; lrl := lDicomData.AngulationRL * PI /180; {$IFDEF VERBOSE_BVEC} dcmmsg('ap/fh/rl'+kTab+floattostr(lDicomData.AngulationAP)+kTab+floattostr(lDicomData.AngulationFH)+kTab+floattostr(lDicomData.AngulationRL)); for lI := 1 to nVec do dcmmsg(inttostr(lI)+ kTab+floattostr(lDTIra[lI].bval)+kTab+floattostr(lDTIra[lI].v1)+kTab+floattostr(lDTIra[lI].v2)+kTab+floattostr(lDTIra[lI].v3)); {$ENDIF} //lAP:=-0.152557; lFH:=-0.0616358; lRL := -0.00676092; //dcmmsg('ap/fh/rl'+kTab+floattostr(lap)+kTab+floattostr(lfh)+kTab+floattostr(lrl)); ltrl := Matrix2D (1,0,0, 0,cos(lrl),-sin(lrl), 0,sin(lrl),cos(lrl)); ltap := Matrix2D (cos(lap),0,sin(lap), 0,1,0, -sin(lap),0,cos(lap)); ltfh := Matrix2D (cos(lfh),-sin(lfh),0, sin(lfh),cos(lfh),0, 0,0,1); lrev_trl := revMat(ltrl); lrev_tap := revMat(ltap); lrev_tfh := revMat(ltfh); lmtemp1 := MultiplyMatrices( ltrl, ltap ); ltang := MultiplyMatrices( lmtemp1, ltfh ); lmtemp1 := MultiplyMatrices( lrev_tfh, lrev_tap ); lrev_tang := MultiplyMatrices( lmtemp1, lrev_trl ); if (lDicomData.PhilipsSliceOrient[1] = 'S') then //SAGITTAL lrev_tsom := Matrix2D (0,0,1, 0,-1,0, -1,0,0 ) else if (lDicomData.PhilipsSliceOrient[1] = 'C') then //CORONAL lrev_tsom := Matrix2D (0,0,1, -1,0,0, 0,1,0 ) else //TRANSVERSAL = AXIAL lrev_tsom := Matrix2D (0,-1,0, -1,0,0, 0,0,1 ); ldtiextra := Matrix2D (0,-1,0, -1,0,0, 0,0,1 ); lmtemp2 := MultiplyMatrices( ldtiextra, lrev_tsom ); lmtemp1 := MultiplyMatrices (lmtemp2, lrev_tang); ReportMatrix('lmtemp1',lmtemp1); for lI := 1 to nVec do begin {$IFDEF VERBOSE_BVEC} //dcmmsg(realtostr(lDTIra[lI].v1,5)+kTab+realtostr(lDTIra[lI].v2,5)+kTab+realtostr(lDTIra[lI].v3,5) ); {$ENDIF} if (lDTIra[lI].bval <= 0) or ((lDTIra[lI].v1 = 0) and (lDTIra[lI].v2 = 0) and (lDTIra[lI].v3 = 0)) then begin lDTIra[lI].v1 := 0; lDTIra[lI].v2 := 0; lDTIra[lI].v3 := 0; end else begin //lIn := Vector2D(0.7071, -0.7071, -0.0000); lIn := Vector2D(-lDTIra[lI].v1,-lDTIra[lI].v2,-lDTIra[lI].v3); NormalizeVector2D(lIn); lout := VecMatMult (lin,lmtemp1); NormalizeVector(lout); lDTIra[lI].v1 := lOut.x; lDTIra[lI].v2 := lOut.y; {2014: dcm2nii flips physically images in AP direction, so do not change sign if lOut.y = 0 then lDTIra[lI].v2 := lOut.y //people dislike seeing -0 else lDTIra[lI].v2 := -lOut.y; //flip Y component } lDTIra[lI].v3 := lOut.z; end; end; //for each vector dcmmsg('Note: dcm2nii since 2014 flips sign of DTI y-component for FSL tools. Please validate for yur system.'); end; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/nii_orient.pas0000755000175000017500000007010212306706704020401 0ustar mihmihunit nii_orient; {$H+} //reorients a NIfTI image to canonical space ... //closest to canonical rotation matrix [1 0 0; 0 1 0; 0 0 1] interface uses {$IFDEF FPC}gzio2,{$ENDIF} SysUtils,define_types,dicomtypes,niftiutil,GraphicsMathLibrary,prefs,dialogs_msg, nifti_types; function Reorient(var lHdrName: string; var lHdr: TNIFTIhdr; lPrefs: TPrefs; lOverwrite,lForce: boolean): string; //function SuperReorient(var lHdrName: string; lPrefs: TPrefs):string; function LRFlip(lFilename: string; lPrefs: TPrefs): boolean; implementation uses dialogsx; (*procedure Mx(var lM: TMatrix); begin Msg('=['+ floattostr(lM.matrix[1,1])+', '+floattostr(lM.matrix[1,2])+', '+floattostr(lM.matrix[1,3])+', '+floattostr(lM.matrix[1,4])+'; '+ floattostr(lM.matrix[2,1])+', '+floattostr(lM.matrix[2,2])+', '+floattostr(lM.matrix[2,3])+', '+floattostr(lM.matrix[2,4])+'; '+ floattostr(lM.matrix[3,1])+', '+floattostr(lM.matrix[3,2])+', '+floattostr(lM.matrix[3,3])+', '+floattostr(lM.matrix[3,4])+'; '+ ' 0, 0, 0, 1]'); end;*) function NIfTIAlignedM (var lM: TMatrix): boolean; //check that diagonals are positive and all other cells are zero //negative diagonals suggests flipping... //non-negative other cells suggests the image is not pure axial var lr,lc: integer; begin result := false; for lr := 1 to 3 do for lc := 1 to 3 do begin if (lr = lc) and (lM.matrix[lr,lc] <= 0) then exit; if (lr <> lc) and (lM.matrix[lr,lc] <> 0) then exit; end; result := true; end; function NIfTIAligned (var lHdr: TNIFTIhdr): boolean; //check that diagonals are positive and all other cells are zero //negative diagonals suggests flipping... //non-negative other cells suggests the image is not pure axial var lM: TMatrix; begin lM := Matrix3D ( lHdr.srow_x[0],lHdr.srow_x[1],lHdr.srow_x[2],lHdr.srow_x[3], lHdr.srow_y[0],lHdr.srow_y[1],lHdr.srow_y[2],lHdr.srow_y[3], lHdr.srow_z[0],lHdr.srow_z[1],lHdr.srow_z[2],lHdr.srow_z[3], 0,0,0,1); result := NIfTIAlignedM(lM); end; procedure FromMatrix (M: TMatrix; var m11,m12,m13, m21,m22,m23, m31,m32,m33: DOUBLE) ; BEGIN m11 := M.Matrix[1,1]; m12 := M.Matrix[1,2]; m13 := M.Matrix[1,3]; m21 := M.Matrix[2,1]; m22 := M.Matrix[2,2]; m23 := M.Matrix[2,3]; m31 := M.Matrix[3,1]; m32 := M.Matrix[3,2]; m33 := M.Matrix[3,3]; END {FromMatrix3D}; function nifti_mat44_orthogx( lR :TMatrix; lPrefs: TPrefs): TMatrix; //returns rotation matrix required to orient image so it is aligned nearest to the identity matrix = // 1 0 0 0 // 0 1 0 0 // 0 0 1 0 // 0 0 0 1 //Therefore, image is approximately oriented in space var lrow,lcol,lMaxRow,lMaxCol,l2ndMaxRow,l2ndMaxCol,l3rdMaxRow,l3rdMaxCol: integer; r11,r12,r13 , r21,r22,r23 , r31,r32,r33, val,lAbsmax,lAbs: double; Q,Flip: TMatrix; //3x3 begin // load 3x3 matrix into local variables FromMatrix(lR,r11,r12,r13,r21,r22,r23,r31,r32,r33); Q := Matrix2D( r11,r12,r13,r21,r22,r23,r31,r32,r33); // normalize row 1 val := Q.matrix[1,1]*Q.matrix[1,1] + Q.matrix[1,2]*Q.matrix[1,2] + Q.matrix[1,3]*Q.matrix[1,3] ; if( val > 0.0 )then begin val := 1.0 / sqrt(val) ; Q.matrix[1,1] := Q.matrix[1,1]*val ; Q.matrix[1,2] := Q.matrix[1,2]*val ; Q.matrix[1,3] := Q.matrix[1,3]*val ; end else begin Q.matrix[1,1] := 1.0 ; Q.matrix[1,2] := 0.0; Q.matrix[1,3] := 0.0 ; end; // normalize row 2 val := Q.matrix[2,1]*Q.matrix[2,1] + Q.matrix[2,2]*Q.matrix[2,2] + Q.matrix[2,3]*Q.matrix[2,3] ; if( val > 0.0 ) then begin val := 1.0 / sqrt(val) ; Q.matrix[2,1] := Q.matrix[2,1]* val ; Q.matrix[2,2] := Q.matrix[2,2] * val ; Q.matrix[2,3] := Q.matrix[2,3] * val ; end else begin Q.matrix[2,1] := 0.0 ; Q.matrix[2,2] := 1.0 ; Q.matrix[2,3] := 0.0 ; end; // normalize row 3 val := Q.matrix[3,1]*Q.matrix[3,1] + Q.matrix[3,2]*Q.matrix[3,2] + Q.matrix[3,3]*Q.matrix[3,3] ; if( val > 0.0 ) then begin val := 1.0 / sqrt(val) ; Q.matrix[3,1] := Q.matrix[3,1] *val ; Q.matrix[3,2] := Q.matrix[3,2] *val ; Q.matrix[3,3] := Q.matrix[3,3] *val ; end else begin Q.matrix[3,1] := Q.matrix[1,2]*Q.matrix[2,3] - Q.matrix[1,3]*Q.matrix[2,2] ; //* cross */ Q.matrix[3,2] := Q.matrix[1,3]*Q.matrix[2,1] - Q.matrix[1,1]*Q.matrix[2,3] ; //* product */ Q.matrix[3,3] := Q.matrix[1,1]*Q.matrix[2,2] - Q.matrix[1,2]*Q.matrix[2,1] ; end; //next - find closest orthogonal coordinates - each matrix cell must be 0,-1 or 1 //First: find axis most aligned to a principal axis lAbsmax := 0; lMaxRow := 1; lMaxCol := 1; for lrow := 1 to 3 do begin for lcol := 1 to 3 do begin lAbs := abs(Q.matrix[lrow,lcol]); if lAbs > lAbsMax then begin lAbsmax := lAbs; lMaxRow := lRow; lMaxCol := lCol; end; end; //for rows end; //for columns //Second - find find axis that is 2nd closest to principal axis lAbsmax := 0; l2ndMaxRow := 2; l2ndMaxCol := 2; for lrow := 1 to 3 do begin for lcol := 1 to 3 do begin if (lrow <> lMaxRow) and (lCol <> lMaxCol) then begin lAbs := abs(Q.matrix[lrow,lcol]); if lAbs > lAbsMax then begin lAbsmax := lAbs; l2ndMaxRow := lRow; l2ndMaxCol := lCol; end; //new max end; //do not check MaxRow/MaxCol end; //for rows end; //for columns //next - no degrees of freedom left: third prinicple axis is the remaining axis if ((lMaxRow = 1) or (l2ndMaxRow = 1)) and ((lMaxRow = 2) or (l2ndMaxRow = 2)) then l3rdMaxRow := 3 else if ((lMaxRow = 1) or (l2ndMaxRow = 1)) and ((lMaxRow = 3) or (l2ndMaxRow = 3)) then l3rdMaxRow := 2 else l3rdMaxRow := 1; if ((lMaxCol = 1) or (l2ndMaxCol = 1)) and ((lMaxCol = 2) or (l2ndMaxCol = 2)) then l3rdMaxCol := 3 else if ((lMaxCol = 1) or (l2ndMaxCol = 1)) and ((lMaxCol = 3) or (l2ndMaxCol = 3)) then l3rdMaxCol := 2 else l3rdMaxCol := 1; //finally, fill in our rotation matrix //cells in the canonical rotation transform can only have values 0,1,-1 result := Matrix3D( 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1); if Q.matrix[lMaxRow,lMaxCol] < 0 then result.matrix[lMaxRow,lMaxCol] := -1 else result.matrix[lMaxRow,lMaxCol] := 1; if Q.matrix[l2ndMaxRow,l2ndMaxCol] < 0 then result.matrix[l2ndMaxRow,l2ndMaxCol] := -1 else result.matrix[l2ndMaxRow,l2ndMaxCol] := 1; if Q.matrix[l3rdMaxRow,l3rdMaxCol] < 0 then result.matrix[l3rdMaxRow,l3rdMaxCol] := -1 else result.matrix[l3rdMaxRow,l3rdMaxCol] := 1; if lPrefs.OrthoFlipXDim then begin Flip := Matrix3D(-1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1); Q := result; result := multiplymatrices(Flip,Q); end; end; FUNCTION QuickInvertMatrix3D (CONST Input:TMatrix): TMatrix; //http://www.cellperformance.com/articles/2006/06/a_4x4_matrix_inverse_1.html //Most of the time in the video games, programmers are not doing a standard inverse matrix. //It is too expensive. Instead, to inverse a matrix, they consider it as orthonormal //and they just do a 3x3 transpose of the rotation part with a dot product for the translation. //Sometimes the full inverse algorithm is necessary.... var i,j: integer; begin result.size := Input.size; for i := 1 to 3 do for j := 1 to 3 do result.matrix[i,j] := input.matrix[j,i]; //next - fill in edge if 3D if result.size <> size3D then exit; //do not fill in final column for 2D matrices for i := 1 to 3 do result.matrix[4,i] := 0; for i := 1 to 3 do result.matrix[i,4] := 0; result.matrix[4,4] := 1; end; procedure FindMatrixPt (lX,lY,lZ: single; var lXout,lYOut,lZOut: single; var lMatrix: TMatrix); begin lXOut := (lX*lMatrix.matrix[1,1])+(lY*lMatrix.matrix[1,2])+(lZ*lMatrix.matrix[1,3])+lMatrix.matrix[1,4]; lYOut := (lX*lMatrix.matrix[2,1])+(lY*lMatrix.matrix[2,2])+(lZ*lMatrix.matrix[2,3])+lMatrix.matrix[2,4]; lZOut := (lX*lMatrix.matrix[3,1])+(lY*lMatrix.matrix[3,2])+(lZ*lMatrix.matrix[3,3])+lMatrix.matrix[3,4]; end; procedure CheckMin(var lX,lY,lZ,lXMin,lYMin,lZMin: single); begin if lX < lXMin then lXMin := lX; if lY < lYMin then lYMin := lY; if lZ < lZMin then lZMin := lZ; end; procedure Mins (var lMatrix: TMatrix; var lHdr: TNIFTIhdr; var lXMin,lYMin,lZMin: single); var lPos,lXc,lYc,lZc: integer; lx,ly,lz: single; begin FindMatrixPt(0,0,0,lX,lY,lZ,lMatrix); lXMin := lX; lYMin := lY; lZMin := lZ; for lPos := 1 to 7 do begin if odd(lPos) then lXc := lHdr.Dim[1]-1 else lXc := 0; if odd(lPos shr 1) then lYc := lHdr.Dim[2]-1 else lYc := 0; if odd(lPos shr 2) then lZc := lHdr.Dim[3]-1 else lZc := 0; FindMatrixPt(lXc,lYc,lZc,lX,lY,lZ,lMatrix); CheckMin(lX,lY,lZ,lXMin,lYMin,lZMin); end; end; function ReorientCore(var lHdrName: string; lPrefix: string; var lHdr: TNIFTIhdr; lPrefs: TPrefs; lOverwrite,lKeepOrigHdr: boolean; var lInMat,lRotMat: TMatrix): string; var lOutHdr: TNIFTIhdr; lOutName: string; lResidualMat: TMatrix; lInMinX,lInMinY,lInMinZ,lOutMinX,lOutMinY,lOutMinZ, dx, dy, dz, QFac: single; lStartX,lStartY,lStartZ, lZ,lY,lX,lB, lOutZ,lOutY, lVol,lNumVol,lXInc, lYInc, lZInc,lBPP: integer; lInPos,lVolBytes,lOutPos,lInOffset: integer; lBufferIn,lBufferOut,lIBuffer,lOBuffer: bytep; lOpts: TNIIOpts; lFlipX,lFlipY,lFlipZ: boolean; lOutF,lInF: File; begin result := ''; lOutHdr := lHdr; //Some software uses negative pixdims to represent a spatial flip - now that the image is canonical, all dimensions are positive lOutHdr.pixdim[1] := abs(lHdr.pixdim[1]); lOutHdr.pixdim[2] := abs(lHdr.pixdim[2]); lOutHdr.pixdim[3] := abs(lHdr.pixdim[3]); //sort out dim1 lFlipX := false; if lRotMat.Matrix[1,2] <> 0 then begin lXinc := lHdr.dim[1]; lOutHdr.dim[1] := lHdr.dim[2]; lOutHdr.pixdim[1] := abs(lHdr.pixdim[2]); if lRotMat.Matrix[1,2] < 0 then lFlipX := true end else if lRotMat.Matrix[1,3] <> 0 then begin lXinc := lHdr.dim[1]*lHdr.dim[2]; lOutHdr.dim[1] := lHdr.dim[3]; lOutHdr.pixdim[1] := abs(lHdr.pixdim[3]); if lRotMat.Matrix[1,3] < 0 then lFlipX := true end else begin lXinc := 1; if lRotMat.Matrix[1,1] < 0 then lFlipX := true end; //sort out dim2 lFlipY := false; if lRotMat.Matrix[2,2] <> 0 then begin lYinc := lHdr.dim[1]; //lOutHdr.dim[2] := lHdr.dim[2]; //lOutHdr.pixdim[2] := lHdr.pixdim[2]; if lRotMat.Matrix[2,2] < 0 then lFlipY := true end else if lRotMat.Matrix[2,3] <> 0 then begin lYinc := lHdr.dim[1]*lHdr.dim[2]; lOutHdr.dim[2] := lHdr.dim[3]; lOutHdr.pixdim[2] := abs(lHdr.pixdim[3]); if lRotMat.Matrix[2,3] < 0 then lFlipY := true end else begin lYinc := 1; lOutHdr.dim[2] := lHdr.dim[1]; lOutHdr.pixdim[2] := abs(lHdr.pixdim[1]); if lRotMat.Matrix[2,1] < 0 then lFlipY := true end; //sort out dim3 lFlipZ := false; if lRotMat.Matrix[3,2] <> 0 then begin lZinc := lHdr.dim[1]; lOutHdr.dim[3] := lHdr.dim[2]; lOutHdr.pixdim[3] := lHdr.pixdim[2]; if lRotMat.Matrix[3,2] < 0 then lFlipZ := true; end else if lRotMat.Matrix[3,3] <> 0 then begin lZinc := lHdr.dim[1]*lHdr.dim[2]; //lOutHdr.dim[3] := lHdr.dim[3]; //lOutHdr.pixdim[3] := lHdr.pixdim[3]; if lRotMat.Matrix[3,3] < 0 then lFlipZ := true; end else begin lZinc := 1; lOutHdr.dim[3] := lHdr.dim[1]; lOutHdr.pixdim[3] := lHdr.pixdim[1]; if lRotMat.Matrix[3,1] < 0 then lFlipZ := true; end; //details for writing... lBPP := (lHdr.bitpix div 8); //bytes per pixel lXinc := lXinc * lBPP; lYinc := lYinc * lBPP; lZinc := lZinc * lBPP; lVolBytes := lHdr.dim[1]*lHdr.dim[2]*lHdr.dim[3]*lBPP; //now write header... //create Matrix of residual orientation... lResidualMat := QuickInvertMatrix3D(lRotMat); //the next steps are inelegant - the translation values are computed by brute force //at the moment, our lResidualMat looks like this //lResidualMat = [ 0 -1 0 0; 0 0 1 0; 1 0 0 0; 0 0 0 1]; //however, it should specify the dimensions in mm of the dimensions that are flipped //However, note that whenever you reverse the direction of //voxel coordinates, you need to include the appropriate offset //in the 'a' matrix. That is: //lResidualMat = [0 0 1 0; -1 0 0 Nx-1; 0 1 0 0; 0 0 0 1] //where Nx is the number of voxels in the x direction. //So, if you took Nx=256, then for your values before, you'd get: //TransRot = [ 0 -1 0 255; 0 0 1 0; 1 0 0 0; 0 0 0 1]; //Because we do not do this, we use the function mins to compute the translations... //I have not implemented refined version yet - require sample volumes to check //Ensure Nx is voxels not mm, etc.... //start of kludge lResidualMat := multiplymatrices(lInMat,lResidualMat); //source lResidualMat.Matrix[1,4] := 0; lResidualMat.Matrix[2,4] := 0; lResidualMat.Matrix[3,4] := 0; Mins (lInMat, lHdr,lInMinX,lInMinY,lInMinZ); Mins (lResidualMat, lOutHdr,lOutMinX,lOutMinY,lOutMinZ); lResidualMat.Matrix[1,4] := lInMinX-lOutMinX; lResidualMat.Matrix[2,4] := lInMinY-lOutMinY; lResidualMat.Matrix[3,4] := lInMinZ-lOutMinZ; //End of kuldge lOutHdr.srow_x[0] := lResidualMat.Matrix[1,1]; lOutHdr.srow_x[1] := lResidualMat.Matrix[1,2]; lOutHdr.srow_x[2] := lResidualMat.Matrix[1,3]; lOutHdr.srow_y[0] := lResidualMat.Matrix[2,1]; lOutHdr.srow_y[1] := lResidualMat.Matrix[2,2]; lOutHdr.srow_y[2] := lResidualMat.Matrix[2,3]; lOutHdr.srow_z[0] := lResidualMat.Matrix[3,1]; lOutHdr.srow_z[1] := lResidualMat.Matrix[3,2]; lOutHdr.srow_z[2] := lResidualMat.Matrix[3,3]; lOutHdr.srow_x[3] := lResidualMat.Matrix[1,4]; lOutHdr.srow_y[3] := lResidualMat.Matrix[2,4]; lOutHdr.srow_z[3] := lResidualMat.Matrix[3,4]; nifti_mat44_to_quatern( lResidualMat, lOutHdr.quatern_b,lOutHdr.quatern_c,lOutHdr.quatern_d, lOutHdr.qoffset_x,lOutHdr.qoffset_y,lOutHdr.qoffset_z, dx, dy, dz,lOutHdr.pixdim[0] {QFac}); //read input if not NIFTIhdr_LoadImg (lHdrName, lHdr, lIBuffer, lInOffset,lOpts) then exit; lNumVol := lOutHdr.dim[4]; if lNumVol < 1 then //hopefully this nevee happens lNumVol := 1; GetMem(lOBuffer,lNumVol*lVolBytes+kNIIImgOffset); lBufferIn := (@liBuffer^[lInOffset+1]); lOutPos := 0; lBufferOut := (@loBuffer^[kNIIImgOffset+1+lOutPos]); if lFlipX then lXInc := -lXInc; if lFlipY then lYInc := -lYInc; if lFlipZ then lZInc := -lZInc; for lVol := 1 to lNumVol do begin //convert if lFlipX then lStartX := (lOutHdr.dim[1]-1)*-lXInc else lStartX := 0; if lFlipY then lStartX := lStartX + (lOutHdr.dim[2]-1)*-lYInc; if lFlipZ then lStartX := lStartX + (lOutHdr.dim[3]-1)*-lZInc; lStartX := lStartX + ((lVol-1)*lVolBytes); for lZ := 1 to lOutHdr.dim[3] do begin lOutZ := lStartX + (lZ-1) * lZInc; for lY := 1 to lOutHdr.dim[2] do begin lOutY := ((lY-1) * lYInc) + lOutZ; for lX := 1 to lOutHdr.dim[1] do begin for lB := 1 to lBPP do begin inc(lOutPos); lInPos := ((lX-1) * lXInc) + lOutY + lB; lBufferOut^[lOutPos] := lBufferIn^[lInPos]; end; end; end; //for Y end; //for Z end;//For each volume Freemem(lIBuffer); if lOverwrite then lOutName := lHdrName else lOutName := ChangeFilePrefix (lHdrName,lPrefix); dcmMsg('Reorienting as '+lOutName); if lKeepOrigHdr then result := SaveNIfTICore (lOutName, lOBuffer, kNIIImgOffset+1, lHdr, lPrefs) else result := SaveNIfTICore (lOutName, lOBuffer, kNIIImgOffset+1, lOutHdr, lPrefs); Freemem(lOBuffer); end;//ReorientCore (*function ReorientCore(var lHdrName: string; lPrefix: string; var lHdr: TNIFTIhdr; lPrefs: TPrefs; lOverwrite: boolean; var lInMat,lRotMat: TMatrix): string; var lOutHdr: TNIFTIhdr; lOutName: string; lResidualMat: TMatrix; lInMinX,lInMinY,lInMinZ,lOutMinX,lOutMinY,lOutMinZ, dx, dy, dz, QFac: single; lStartX,lStartY,lStartZ, lZ,lY,lX,lB, lOutZ,lOutY, lXInc, lYInc, lZInc,lBPP: integer; lInPos,lVolBytes,lOutPos,lInOffset: integer; lBufferIn,lBufferOut,lIBuffer,lOBuffer: bytep; lByteSwap,lFlipX,lFlipY,lFlipZ: boolean; lOutF,lInF: File; begin result := ''; lOutHdr := lHdr; if lOutHdr.dim[4] > 1 then begin showmessage('Reorient only designed for 3D images.'); exit; end; //Some software uses negative pixdims to represent a spatial flip - now that the image is canonical, all dimensions are positive lOutHdr.pixdim[1] := abs(lHdr.pixdim[1]); lOutHdr.pixdim[2] := abs(lHdr.pixdim[2]); lOutHdr.pixdim[3] := abs(lHdr.pixdim[3]); //sort out dim1 lFlipX := false; if lRotMat.Matrix[1,2] <> 0 then begin lXinc := lHdr.dim[1]; lOutHdr.dim[1] := lHdr.dim[2]; lOutHdr.pixdim[1] := abs(lHdr.pixdim[2]); if lRotMat.Matrix[1,2] < 0 then lFlipX := true end else if lRotMat.Matrix[1,3] <> 0 then begin lXinc := lHdr.dim[1]*lHdr.dim[2]; lOutHdr.dim[1] := lHdr.dim[3]; lOutHdr.pixdim[1] := abs(lHdr.pixdim[3]); if lRotMat.Matrix[1,3] < 0 then lFlipX := true end else begin lXinc := 1; if lRotMat.Matrix[1,1] < 0 then lFlipX := true end; //sort out dim2 lFlipY := false; if lRotMat.Matrix[2,2] <> 0 then begin lYinc := lHdr.dim[1]; //lOutHdr.dim[2] := lHdr.dim[2]; //lOutHdr.pixdim[2] := lHdr.pixdim[2]; if lRotMat.Matrix[2,2] < 0 then lFlipY := true end else if lRotMat.Matrix[2,3] <> 0 then begin lYinc := lHdr.dim[1]*lHdr.dim[2]; lOutHdr.dim[2] := lHdr.dim[3]; lOutHdr.pixdim[2] := abs(lHdr.pixdim[3]); if lRotMat.Matrix[2,3] < 0 then lFlipY := true end else begin lYinc := 1; lOutHdr.dim[2] := lHdr.dim[1]; lOutHdr.pixdim[2] := abs(lHdr.pixdim[1]); if lRotMat.Matrix[2,1] < 0 then lFlipY := true end; //sort out dim3 lFlipZ := false; if lRotMat.Matrix[3,2] <> 0 then begin lZinc := lHdr.dim[1]; lOutHdr.dim[3] := lHdr.dim[2]; lOutHdr.pixdim[3] := lHdr.pixdim[2]; if lRotMat.Matrix[3,2] < 0 then lFlipZ := true; end else if lRotMat.Matrix[3,3] <> 0 then begin lZinc := lHdr.dim[1]*lHdr.dim[2]; //lOutHdr.dim[3] := lHdr.dim[3]; //lOutHdr.pixdim[3] := lHdr.pixdim[3]; if lRotMat.Matrix[3,3] < 0 then lFlipZ := true; end else begin lZinc := 1; lOutHdr.dim[3] := lHdr.dim[1]; lOutHdr.pixdim[3] := lHdr.pixdim[1]; if lRotMat.Matrix[3,1] < 0 then lFlipZ := true; end; //details for writing... lBPP := (lHdr.bitpix div 8); //bytes per pixel lXinc := lXinc * lBPP; lYinc := lYinc * lBPP; lZinc := lZinc * lBPP; lVolBytes := lHdr.dim[1]*lHdr.dim[2]*lHdr.dim[3]*lBPP; //now write header... //create Matrix of residual orientation... lResidualMat := QuickInvertMatrix3D(lRotMat); //the next steps are inelegant - the translation values are computed by brute force //at the moment, our lResidualMat looks like this //lResidualMat = [ 0 -1 0 0; 0 0 1 0; 1 0 0 0; 0 0 0 1]; //however, it should specify the dimensions in mm of the dimensions that are flipped //However, note that whenever you reverse the direction of //voxel coordinates, you need to include the appropriate offset //in the 'a' matrix. That is: //lResidualMat = [0 0 1 0; -1 0 0 Nx-1; 0 1 0 0; 0 0 0 1] //where Nx is the number of voxels in the x direction. //So, if you took Nx=256, then for your values before, you'd get: //TransRot = [ 0 -1 0 255; 0 0 1 0; 1 0 0 0; 0 0 0 1]; //Because we do not do this, we use the function mins to compute the translations... //I have not implemented refined version yet - require sample volumes to check //Ensure Nx is voxels not mm, etc.... //start of kludge lResidualMat := multiplymatrices(lInMat,lResidualMat); //source lResidualMat.Matrix[1,4] := 0; lResidualMat.Matrix[2,4] := 0; lResidualMat.Matrix[3,4] := 0; Mins (lInMat, lHdr,lInMinX,lInMinY,lInMinZ); Mins (lResidualMat, lOutHdr,lOutMinX,lOutMinY,lOutMinZ); lResidualMat.Matrix[1,4] := lInMinX-lOutMinX; lResidualMat.Matrix[2,4] := lInMinY-lOutMinY; lResidualMat.Matrix[3,4] := lInMinZ-lOutMinZ; //End of kuldge lOutHdr.srow_x[0] := lResidualMat.Matrix[1,1]; lOutHdr.srow_x[1] := lResidualMat.Matrix[1,2]; lOutHdr.srow_x[2] := lResidualMat.Matrix[1,3]; lOutHdr.srow_y[0] := lResidualMat.Matrix[2,1]; lOutHdr.srow_y[1] := lResidualMat.Matrix[2,2]; lOutHdr.srow_y[2] := lResidualMat.Matrix[2,3]; lOutHdr.srow_z[0] := lResidualMat.Matrix[3,1]; lOutHdr.srow_z[1] := lResidualMat.Matrix[3,2]; lOutHdr.srow_z[2] := lResidualMat.Matrix[3,3]; lOutHdr.srow_x[3] := lResidualMat.Matrix[1,4]; lOutHdr.srow_y[3] := lResidualMat.Matrix[2,4]; lOutHdr.srow_z[3] := lResidualMat.Matrix[3,4]; nifti_mat44_to_quatern( lResidualMat, lOutHdr.quatern_b,lOutHdr.quatern_c,lOutHdr.quatern_d, lOutHdr.qoffset_x,lOutHdr.qoffset_y,lOutHdr.qoffset_z, dx, dy, dz, QFac); //read input if not NIFTIhdr_LoadImg (lHdrName, lHdr, lIBuffer, lInOffset,lByteSwap) then exit; GetMem(lOBuffer,lVolBytes+kNIIImgOffset); lBufferIn := (@liBuffer^[lInOffset+1]); lOutPos := 0; lBufferOut := (@loBuffer^[kNIIImgOffset+1+lOutPos]); //convert if lFlipX then begin lStartX := (lOutHdr.dim[1]-1)*lXInc; lXInc := -lXInc; end else lStartX := 0; if lFlipY then begin lStartX := lStartX + (lOutHdr.dim[2]-1)*lYInc; lYInc := -lYInc; end; if lFlipZ then begin lStartX := lStartX + (lOutHdr.dim[3]-1)*lZInc; lZInc := -lZInc; end; for lZ := 1 to lOutHdr.dim[3] do begin lOutZ := lStartX + (lZ-1) * lZInc; for lY := 1 to lOutHdr.dim[2] do begin lOutY := ((lY-1) * lYInc) + lOutZ; for lX := 1 to lOutHdr.dim[1] do begin for lB := 1 to lBPP do begin inc(lOutPos); lInPos := ((lX-1) * lXInc) + lOutY + lB; lBufferOut^[lOutPos] := lBufferIn^[lInPos]; end; end; end; //for Y end; //for Z Freemem(lIBuffer); if lOverwrite then lOutName := lHdrName else lOutName := ChangeFilePrefix (lHdrName,lPrefix); Msg('Reorienting as '+lOutName); result := SaveNIfTICore (lOutName, lOBuffer, kNIIImgOffset+1, lOutHdr, lPrefs,lByteSwap); Freemem(lOBuffer); end;//ReorientCore *) (*function SuperReorient(var lHdrName: string; {var lHdr: TNIFTIhdr;} lPrefs: TPrefs): string; //super-reorient generates copies of the source image with different orthogonal rotations //useful for testing viewing software var lRot,lRotMod: integer; lByteSwap: boolean; lInMat,lRotMat,lTempMat,lTransformMat,lNormalMat,lFlipMat: TMatrix; lPrefix: string; lHdr: TNIFTIhdr; begin if not NIFTIhdr_LoadHdr (lHdrName, lHdr, lByteSwap) then begin Msg('Unable to read as NifTI/Analyze' + lHdrName); exit; end; result := ''; lInMat := Matrix3D ( lHdr.srow_x[0],lHdr.srow_x[1],lHdr.srow_x[2],lHdr.srow_x[3], lHdr.srow_y[0],lHdr.srow_y[1],lHdr.srow_y[2],lHdr.srow_y[3], lHdr.srow_z[0],lHdr.srow_z[1],lHdr.srow_z[2],lHdr.srow_z[3], 0,0,0,1); lNormalMat := nifti_mat44_orthogx(lInMat); //lRot := 3; begin for lRot := 1 to 24 do begin lRotMod := lRot mod 6; case lRotMod of 1: lTempMat := Matrix3D(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1); 2: lTempMat := Matrix3D(1,0,0,0, 0,0,1,0, 0,1,0,0, 0,0,0,1); 3: lTempMat := Matrix3D(0,1,0,0, 1,0,0,0, 0,0,1,0, 0,0,0,1); 4: lTempMat := Matrix3D(0,1,0,0, 0,0,1,0, 1,0,0,0, 0,0,0,1); 5: lTempMat := Matrix3D(0,0,1,0, 1,0,0,0, 0,1,0,0, 0,0,0,1); else lTempMat := Matrix3D(0,0,1,0, 0,1,0,0, 1,0,0,0, 0,0,0,1); end; case lRot of 1..6: lFlipMat := Eye3D; 7..12: lFlipMat := Matrix3D(-1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1); 13..18: lFlipMat := Matrix3D(1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,0,0,1); 19..24: lFlipMat := Matrix3D(1,0,0,0, 0,1,0,0, 0,0,-1,0, 0,0,0,1); end; lTransformMat := MultiplyMatrices(lTempMat,lFlipMat); lRotMat := MultiplyMatrices(lNormalMat,lTransformMat); lPrefix := floattostr(lTransformMat.Matrix[1,1])+floattostr(lTransformMat.Matrix[1,2])+floattostr(lTransformMat.Matrix[1,3]) +'_'+floattostr(lTransformMat.Matrix[2,1])+floattostr(lTransformMat.Matrix[2,2])+floattostr(lTransformMat.Matrix[2,3]) +'_'+floattostr(lTransformMat.Matrix[3,1])+floattostr(lTransformMat.Matrix[3,2])+floattostr(lTransformMat.Matrix[3,3]); Msg(lPrefix); result := ReorientCore(lHdrName, lPrefix,lHdr, lPrefs, false, lInMat,lRotMat); end; end;//proc SuperReorient *) function Reorient(var lHdrName: string; var lHdr: TNIFTIhdr; lPrefs: TPrefs; lOverwrite,lForce: boolean): string; //returns output filename if successful //reslice an image so it is in canonical space var lInMat,lRotMat: TMatrix; begin result := ''; if (lHdr.dim[4] > 1) or (lHdr.dim[3] < 2) then begin dcmMsg('Can only orient 3D images '+inttostr(lHdr.dim[3])+' '+inttostr(lHdr.dim[4])); exit; end; if (lHdr.dim[1] > lPrefs.MaxReorientMatrix) or (lHdr.dim[2] > lPrefs.MaxReorientMatrix) or(lHdr.dim[3] > lPrefs.MaxReorientMatrix) then begin dcmMsg('This image will not be reoriented (larger than MaxReorientMatrix= '+inttostr(lPrefs.MaxReorientMatrix)); exit; end; lInMat := Matrix3D ( lHdr.srow_x[0],lHdr.srow_x[1],lHdr.srow_x[2],lHdr.srow_x[3], lHdr.srow_y[0],lHdr.srow_y[1],lHdr.srow_y[2],lHdr.srow_y[3], lHdr.srow_z[0],lHdr.srow_z[1],lHdr.srow_z[2],lHdr.srow_z[3], 0,0,0,1); if (not lForce) and (NIfTIAlignedM (lInMat)) then begin result := lHdrName; dcmMsg('Image is already canonically oriented: '+lHdrName); exit; end; lRotMat := nifti_mat44_orthogx( lInMat,lPrefs); if NIfTIAlignedM (lRotMat) then begin result := lHdrName; dcmMsg('According to header, image is already approximately canonically oriented'); exit; //already as close as possible end; result := ReorientCore(lHdrName, 'o',lHdr, lPrefs, lOverwrite,false, lInMat,lRotMat); end; function LRFlip(lFilename: string; lPrefs: TPrefs): boolean; //function Reorient(var lHdrName: string; var lHdr: TNIFTIhdr; lPrefs: TPrefs; lOverwrite,lForce: boolean): string; //returns output filename if successful //reslice an image so it is in canonical space var lHdr: TNIFTIhdr; lO: TNIIOPts; lInMat,lRotMat: TMatrix; begin result := false; if not NIFTIhdr_LoadHdr (lFilename, lHdr, lO) then begin dcmMsg('Unable to read as NifTI/Analyze' + lFilename); exit; end; if (lHdr.dim[1] > lPrefs.MaxReorientMatrix) or (lHdr.dim[2] > lPrefs.MaxReorientMatrix) or(lHdr.dim[3] > lPrefs.MaxReorientMatrix) then begin dcmMsg('This image will not be reoriented (larger than MaxReorientMatrix= '+inttostr(lPrefs.MaxReorientMatrix)); exit; end; lInMat := Matrix3D ( lHdr.srow_x[0],lHdr.srow_x[1],lHdr.srow_x[2],lHdr.srow_x[3], lHdr.srow_y[0],lHdr.srow_y[1],lHdr.srow_y[2],lHdr.srow_y[3], lHdr.srow_z[0],lHdr.srow_z[1],lHdr.srow_z[2],lHdr.srow_z[3], 0,0,0,1); lRotMat := Matrix3D( -1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1); result := (ReorientCore(lFilename, 'lr',lHdr, lPrefs, false,true, lInMat,lRotMat)<> ''); end; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/convertsimple.pas0000755000175000017500000002112412204716024021125 0ustar mihmihunit convertsimple; {$H+} interface uses {$IFDEF FPC}gzio2, {$ENDIF} define_types,SysUtils,dicomtypes,filename,nii_4dto3d,niftiutil,nii_orient, nii_crop,GraphicsMathLibrary,prefs; //function ConvertSimple2NII ({var} lInFilename, lOutDir: string; var lPrefs: TPrefs): boolean; function FDF( lFName: string; var lDcm: DicomData {; var lByteSwap: boolean}): boolean; implementation uses dialogsx,dialogs_msg; procedure ReadlnX (var F: TextFile; var lResult: string); //Replicates Readln, but works for Unix files... Delphi 4's readln fails for non-MSDOS EOLs var lCh: char; begin lResult := ''; while not Eof(F) do begin Read(F, lCh); if (lCh in [#10,#13]) then begin if lResult <> '' then begin //Showmessage(lResult); exit; end; end else lResult := lResult + lCh; end; end; //ReadlnX function ParseStr(lPattern: string; var lSample: string): integer; begin result := Pos(lPattern,lSample); if result < 1 then exit; //Msg('*'+lPattern+'*'+inttostr(result)+'*'+lSample+'*'); result := result+length(lPattern);//end of pattern lSample := trim(copy(lSample,result,length(lSample)+1-result)); end; procedure ExtractFloats(lSample: string; var V1,V2,V3: double); var lCh: char; lStr: string; lP,lL,lN: integer; procedure RetireStr; begin if lStr = '' then exit; inc(lN); case lN of 1: V1 := strtofloat(lStr); 2: V2 := strtofloat(lStr); 3: V3 := strtofloat(lStr); else exit; end; lStr := ''; end; begin V1:= 1; V2 := 1; V3 := 1; lL := length(lSample); if lL < 1 then exit; decimalseparator := '.'; lP := 1; lN:= 0; lStr := ''; while lP <= lL do begin lCh := lSample[lP]; if lCh in ['-','.','0'..'9'] then lStr := lStr + lCh else retireStr; inc(lP); end; RetireStr; end; procedure ExtractFloats10x(lSample: string; var V1,V2,V3: double); //cm to mm begin ExtractFloats(lSample, V1,V2,V3); V1 := V1 * 10; V2 := V2 * 10; V3 := V3 * 10; end; procedure ExtractInts(lSample: string; var V1,V2,V3: integer); var F1,F2,F3: double; begin //Msg('*'+lSample+'*'); ExtractFloats(lSample, F1,F2,F3); V1 := round(F1); V2 := round(F2); V3 := round(F3); //dcmMsg(inttostr(V1)+','+inttostr(V2)+','+inttostr(V3)); end; procedure ReportHeader (lFormatName: string; var lDicomData: dicomdata); const kCR = '; '; begin dcmMsg (lFormatName +kCR+ ' Slice Number:'+inttostr(lDicomData.ImageNum) +kCR+ 'XYZ dim: ' +inttostr(lDicomData.XYZdim[1])+'/'+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+ 'XYZ position: ' +floattostr(lDicomData.PatientPosX)+'/'+floattostr(lDicomData.PatientPosY)+'/'+floattostr(lDicomData.PatientPosZ) +kCR+'Data offset: ' +inttostr(lDicomData.ImageStart) +kCR+'XYZ mm: '+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2) +kCR+'TR: '+floattostrf(lDicomData.TR,ffFixed,8,2) ); end; function CMFOV2MM( lCMFOV,lMatrix: double): double; begin if lMatrix > 0 then result := lCMFOV*10 / lMatrix; end; (*Reads Varian FDF images (FDF = Flexible Data Format). Varian MRI FDF reader http://www.mathworks.com/matlabcentral/fileexchange/7449 Multi_FDF_Opener.java - http://rsbweb.nih.gov/ij/plugins/multi-opener.html char *spatial_rank = "2dfov"; if 3dfov then matrix will have three elements if 3dfov then span will have three elements int bigendian float matrix[] = {512, 512}; float bits = 32; float span[] = {4.000000, 4.000000}; byte offset of image data is = file.length - xdim*ydim*zdim*bits/8; Appears only 32-bit float data... *) function Deblank (lInStr: string): string; var lLen,lPos: integer; begin result := ''; lLen := length(lInStr); if lLen < 1 then exit; for lPos := 1 to lLen do if lInStr[lPos] in ['=',',','[',']','+','-','.','\','~','/', '0'..'9','a'..'z','A'..'Z'] then result := result +lINStr[lPos]; end; function FDF( lFName: string; var lDcm: DicomData): boolean; //Note - some Varian scanners put in more white space between text than others... // "float bits=" versus "float bits=" //Therefore we deblank the data text to remove whitespace VAR ltextfile: textfile; lLine: string; lFileSz,num: integer; junk1f,junk2f,junk3f: double; junk1,junk2: integer; lDone,lSliceNum: boolean; begin result := false; lFileSz := FSize(lFName); if lFileSz < 1{not fileexists (lFName)} then begin dcmMsg('Can not find file '+lFName); exit; end; FileMode := 0; { Set file access to read only } AssignFile(ltextfile, lFName); Reset(ltextfile); lDone := false; num := 1; lSliceNum := false; repeat readlnx(ltextfile,lLine); //lLine := trim(lLine);//remove leading/following characters lLine := deblank(lLine);//remove leading/following characters //dcmdcmdcmdcmMsg(lLine); if ParseStr('floatbits=', lLine) > 0 then ExtractInts(lLine, lDcm.Allocbits_per_pixel ,junk1,junk2); if ParseStr('intslice_no', lLine) > 0 then begin lSliceNum := true; ExtractInts(lLine, lDcm.ImageNum ,junk1,junk2); end; if ParseStr('floatlocation[]=', lLine) > 0 then ExtractFloats10x(lLine, lDcm.PatientPosX,lDcm.PatientPosY,lDcm.PatientPosZ); if ParseStr('floatmatrix[]=', lLine) > 0 then ExtractInts(lLine, lDcm.XYZdim[1],lDcm.XYZdim[2],lDcm.XYZdim[3]); if ParseStr('floatspan[]=', lLine) > 0 then ExtractFloats(lLine, lDCm.XYZmm[1],lDcm.XYZmm[2],lDcm.XYZmm[3]); if ParseStr('floatTR=', lLine) > 0 then begin ExtractFloats(lLine, junk1f,junk2f,junk3f); lDcm.TR := junk1f/1000; //convert TR in msec to time in sec end; {if strmatch('intbigendian', line) then machineformat = 'ieee-le'; % New Linux-based} num := num + 1; if num > 41 then lDone := true; until lDone; if lDcm.Allocbits_per_pixel = 32 then begin result := true; lDcm.FloatData := true; end else begin dcmMsg('Unsupported datatype: '+inttostr( lDcm.Allocbits_per_pixel)+ 'bits per pixel '+lFName); end; if not lSliceNum then begin ExtractInts(lFName, lDcm.ImageNum ,junk1,junk2); end; //next - convert field of view in cm to voxel size in mm... for num := 1 to 3 do lDCm.XYZmm[num] := CMFOV2MM( lDCm.XYZmm[num],lDcm.XYZdim[num]); lDcm.Little_Endian := 0; lDcm.ImageStart := lFileSz - (lDcm.XYZdim[1]*lDcm.XYZdim[2]*lDcm.XYZdim[3]*(round(lDcm.Allocbits_per_pixel/8))); if lDcm.ImageStart < 10 then result := false; if result then ReportHeader('Varian FDF',lDcm); CloseFile(ltextfile); FileMode := 2; end; (*function Raw2NIfTI(lHdrName: string; var lHdr: TNIFTIhdr; lPrefs: TPrefs; lByteSwap: boolean): boolean; //like ChangeNIfTISubformat except we use the passed lHdrdata... var lImgBuffer: byteP; lImgOffset: integer; lOutImgName: string; //lByteSwap: boolean; begin result := false; if not NIFTIhdr_LoadImgRaw (false,lHdrName, lHdr, lImgBuffer, lImgOffset,lByteSwap) then exit; dcmMsg('Converting to NIfTI '+lHdrName); lOutImgName := ChangeFilePrefix (lHdrName,'c'); if lPrefs.CustomRename then CustomFilename(lOutImgName); if SaveNIfTICore (lOutImgName, lImgBuffer, lImgOffset+1, lHdr, lPrefs,lByteSwap) ='' then exit; Freemem(lImgBuffer); result := true; //11/2007 ExitCode := 0; end; function ConvertSimple2NII ({var} lInFilename , lOutDir: string; var lPrefs: TPrefs): boolean; //this is simple, but does not stack 2d slices into 3d volumes... var lDcm: DicomData; lHdr: TNIFTIhdr; lBigEndian: boolean; begin result := false; NIFTIhdr_ClearHdr(lHdr); dcmMsg('WARNING: no image orientation matrix for '+lInFilename); if not FDF (lInFilename,lDcm) then exit; DICOM2AnzHdr (lHdr, false,lInFilename,lDcm); //Raw2NIfTI(lInFilename,lHdr,lPrefs,true); end; *) end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/guii.lrs0000755000175000017500000000514410636133612017214 0ustar mihmih{ This is an automatically generated lazarus resource file } LazarusResources.Add('TMainForm','FORMDATA',[ 'TPF0'#9'TMainForm'#8'MainForm'#4'Left'#3'#'#1#6'Height'#3','#1#3'Top'#3#149#0 +#5'Width'#3#144#1#18'HorzScrollBar.Page'#3#143#1#18'VertScrollBar.Page'#3#24 +#1#13'ActiveControl'#7#5'Memo1'#7'Caption'#6#7'dcm2nii'#4'Menu'#7#9'MainMenu' +'1'#6'OnShow'#7#8'FormShow'#0#8'TToolBar'#8'ToolBar1'#6'Height'#2#26#5'Width' +#3#144#1#7'Caption'#6#8'ToolBar1'#11'EdgeBorders'#11#0#8'TabOrder'#2#0#0#6'T' +'Label'#6'Label1'#4'Left'#2#1#6'Height'#2#14#5'Width'#2'O'#9'Alignment'#7#8 +'taCenter'#7'Caption'#6#15'Output Format: '#5'Color'#7#6'clNone'#11'ParentCo' +'lor'#8#0#0#9'TComboBox'#9'TypeCombo'#4'Left'#2'P'#6'Height'#2#22#5'Width'#2 +'d'#16'AutoCompleteText'#11#22'cbactEndOfLineComplete'#20'cbactSearchAscendi' +'ng'#0#13'Items.Strings'#1#6#24'SPM2 (3D Anlyze hdr/img)'#6#23'SPM5 (3D NIfT' +'I hdr/img)'#6#16'4D NIfTI hdr/img'#6#18'FSL (4D NIfTI nii)'#6#29'Compressed' +' FSL (4D NIfTI nii)'#0#9'MaxLength'#2#0#5'Style'#7#14'csDropDownList'#8'Tab' +'Order'#2#0#0#0#0#5'TMemo'#5'Memo1'#6'Height'#3#255#0#3'Top'#2#26#5'Width'#3 +#144#1#5'Align'#7#8'alClient'#13'Lines.Strings'#1#6#0#0#8'TabOrder'#2#1#0#0#9 +'TMainMenu'#9'MainMenu1'#4'left'#2'G'#3'top'#2'<'#0#9'TMenuItem'#8'FileMenu' +#7'Caption'#6#4'File'#7'OnClick'#7#13'FileMenuClick'#0#9'TMenuItem'#12'Modif' +'yNifti1'#7'Caption'#6#12'Modify NIfTI'#7'OnClick'#7#17'ModifyNifti1Click'#0 +#0#9'TMenuItem'#9'MenuItem7'#7'Caption'#6#14'DICOM to NIfTI'#7'OnClick'#7#15 +'dcm2niiBtnClick'#0#0#9'TMenuItem'#15'AnonymizeDICOM1'#7'Caption'#6#15'Anony' +'mize DICOM'#7'OnClick'#7#20'AnonymizeDICOM1Click'#0#0#9'TMenuItem'#5'Exit1' +#7'Caption'#6#4'Exit'#7'OnClick'#7#10'Exit1Click'#0#0#0#9'TMenuItem'#9'MenuI' +'tem5'#7'Caption'#6#8'EditMenu'#0#9'TMenuItem'#9'MenuItem6'#7'Caption'#6#4'C' +'opy'#0#0#0#9'TMenuItem'#9'MenuItem2'#7'Caption'#6#4'Edit'#7'OnClick'#7#14'M' +'enuItem2Click'#0#9'TMenuItem'#5'Copy1'#7'Caption'#6#4'Copy'#8'ShortCut'#3'C' +'@'#7'OnClick'#7#10'Copy1Click'#0#0#0#9'TMenuItem'#9'MenuItem1'#7'Caption'#6 +#4'Help'#7'OnClick'#7#14'MenuItem1Click'#0#9'TMenuItem'#9'MenuItem3'#7'Capti' +'on'#6#11'Preferences'#7'OnClick'#7#17'Preferences1Click'#0#0#9'TMenuItem'#9 +'MenuItem4'#7'Caption'#6#5'About'#7'OnClick'#7#11'About1Click'#0#0#0#0#22'TS' +'electDirectoryDialog'#9'DirSelect'#5'Title'#6#16'Select Directory'#11'Filte' +'rIndex'#2#0#4'left'#2'G'#3'top'#2'`'#0#0#11'TOpenDialog'#10'OpenHdrDlg'#5'T' +'itle'#6#18'Open existing file'#11'FilterIndex'#2#0#4'left'#2'H'#3'top'#3#128 +#0#0#0#0 ]); mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dicom.pas0000755000175000017500000000235211326434462017337 0ustar mihmihunit dicom; {$H+} interface {$DEFINE COMPAT} uses dialogsx,prefs,dicomtypes {$IFDEF COMPAT} ,dicomcompat{,dicomfast}; {$ELSE} ,dicomfast; {$ENDIF} procedure read_dicom_data(lReadJPEGtables,lVerboseRead,lAutoDECAT7,lReadECAToffsetTables,lAutodetectInterfile,lAutoDetectGenesis,lReadColorTables: boolean; var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string; var lPrefs: TPrefs); implementation procedure read_dicom_data(lReadJPEGtables,lVerboseRead,lAutoDECAT7,lReadECAToffsetTables,lAutodetectInterfile,lAutoDetectGenesis,lReadColorTables: boolean; var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string; var lPrefs: TPrefs); begin lDICOMdata.Filename := lFilename; lHdrOK := true; lImageFormatOK:=true; {$IFDEF COMPAT} //if not fast_read_dicom_data(lDICOMdata,128, lFileName) then read_dicom_data_compat(lReadJPEGtables,lVerboseRead,lAutoDECAT7,lReadECAToffsetTables,lAutodetectInterfile,lAutoDetectGenesis,lReadColorTables, lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName,lPrefs); {$ELSE} lHdrOK := fast_read_dicom_data(lDICOMdata,128, lFileName); {$ENDIF} end; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/paramstrs.pas0000755000175000017500000003575512307651162020273 0ustar mihmihunit paramstrs; {$H+} interface uses prefs,define_types,dialogs_msg; const kVers = 'Chris Rorden''s dcm2nii :: '+kMRIcronvers; {$Include ..\common\isgui.inc} procedure ProcessParamStrs; // procedure Testdcm2nii; procedure RecursiveFolderSearch (lFolderName,lOutDir: string; var lPrefs: TPrefs; lDepth: integer); implementation uses {$IFDEF GUI}gui, {$ELSE} nii_4dto3d,{$ENDIF} {$IFNDEF UNIX} Windows,{$ENDIF} Classes, SysUtils,sortdicom,dicom,parconvert,filename,dicomtypes,userdir; (*procedure RecursiveFolderSearch (lFolderName,lOutDir: string; var lPrefs: TPrefs; lDepth: integer); var lNewDir,lNewName,lFilename,lExt: String; lSearchRec: TSearchRec; begin if (lPrefs.CollapseFolders) then begin //Convert all folders in single step... LoadFileList(lFolderName,lOutDir,lPrefs); exit; end; lNewDir := lFolderName+PathDelim; {$IFDEF UNIX} if FindFirst(lNewDir+'*',faAnyFile-faSysFile,lSearchRec) = 0 then begin {$ELSE} if FindFirst(lNewDir+'*.*',faAnyFile-faSysFile,lSearchRec) = 0 then begin {$ENDIF} lFilename := ''; repeat lNewName := lNewDir+lSearchRec.Name; if (lSearchRec.Name <> '.') and (lSearchRec.Name <> '..') then begin if DirExists(lNewName) then begin if lDepth < lPrefs.RecursiveFolderDepth then begin if (lDepth = 0) and (lPrefs.RecursiveUseNameAppend) then begin lPrefs.NameAppend := extractfilename(lNewName)+'_'; Msg('recursive base folder '+lPrefs.NameAppend); end; RecursiveFolderSearch(lNewName,lOutDir,lPrefs,lDepth+1); end; //exit;//4/4/2008 end else lFilename := lNewname; end; until (FindNext(lSearchRec) <> 0); if lFilename <> '' then begin lExt := UpCaseExt(lFilename); if (lExt = '.REC') or (lExt = '.PAR') then LoadFileListPARREC(lFilename,lOutDir,lPrefs) else begin Msg('recursive conversion '+lFilename); LoadFileList(lFilename,lOutDir,lPrefs); end; end; end; FindClose(lSearchRec); end; *) function IsDicom (lFilename: string): boolean; var lDICOMdata: DICOMData; lDynStr: string; lHdrOK,lImgOK: boolean; lPrefs: TPrefs; begin result := false; read_dicom_data(true,false{not verbose},true,true,true,true,false, lDICOMdata, lHdrOK, lImgOK, lDynStr,lFileName,lPrefs ); if (lHdrOK) and (lImgOK) then result := true; end; procedure RecursiveFolderSearch (lFolderName,lOutDir: string; var lPrefs: TPrefs; lDepth: integer); var lNewDir,lFilename,lExt: String; lDirStrings: TStringList; lSearchRec: TSearchRec; lI: integer; begin if (lPrefs.CollapseFolders) then begin //Convert all folders in single step... LoadFileList(lFolderName,lOutDir,lPrefs); exit; end; lNewDir := lFolderName+PathDelim; //first check for deeper folders... {$IFDEF DEBUG}Msg('---Recursively searching '+lfoldername+' depth = '+inttostr(lDepth)); {$ENDIF} if lDepth < lPrefs.RecursiveFolderDepth then begin lDirStrings := TStringList.Create; {$IFDEF UNIX} if FindFirst(lNewDir+'*',faDirectory,lSearchRec) = 0 then begin {$ELSE} if FindFirst(lNewDir+'*.*',faDirectory,lSearchRec) = 0 then begin {$ENDIF} lFilename := ''; repeat if (lSearchRec.Name <> '.') and (lSearchRec.Name <> '..') then begin lFileName := lNewDir+lSearchRec.Name; if DirExists(lFileName) then begin (*if (lDepth = 0) and (lPrefs.RecursiveUseNameAppend) then begin lPrefs.NameAppend := extractfilename(lSearchRec.Name)+'_'; Msg('recursive base folder '+lPrefs.NameAppend); end; *) lDirStrings.Add(lNewDir+lSearchRec.Name); end; end; until (FindNext(lSearchRec) <> 0); end; //findfirst FindClose(lSearchRec); lDirStrings.Sort; if lDirStrings.Count > 0 then for lI := 0 to (lDirStrings.Count-1) do begin if (lDepth = 0) and (lPrefs.RecursiveUseNameAppend) then begin lPrefs.NameAppend := extractfilename(lDirStrings[lI])+'_'; dcmMsg('recursive base folder '+lPrefs.NameAppend); end; RecursiveFolderSearch(lDirStrings[lI],lOutDir,lPrefs,lDepth+1); end; lDirStrings.free; end; //lDepth < lPrefs.RecursiveFolderDepth //next check for files in current folder... {$IFDEF UNIX} if FindFirst(lNewDir+'*',faAnyFile-faSysFile-faHidden,lSearchRec) = 0 then begin {$ELSE} if FindFirst(lNewDir+'*.*',faAnyFile-faSysFile-faHidden,lSearchRec) = 0 then begin {$ENDIF} repeat lFileName := lNewDir+lSearchRec.Name; lExt := UpCaseExt(lFilename); if (lFilename <> '') and (FileExists(lFileName)) and (not DirExists(lFileName)) and (not IsNiftiExt(lExt)) then begin if (lExt = '.REC') or (lExt = '.PAR') then LoadFileListPARREC(lFilename,lOutDir,lPrefs) else if IsDicom (lFilename) then begin dcmMsg('Looking for DICOM files in folder with '+lFilename); LoadFileList(lFilename,lOutDir,lPrefs); end else lFilename := ''; end else lFilename :=''; until (FindNext(lSearchRec) <> 0) or (lFilename <> ''); end; //findfirst FindClose(lSearchRec); end; //RecursiveFolderSearch function Bool2YN (lBool: boolean): char; begin if lBool then result := 'Y' else result := 'N'; end; procedure CharBool (lCh: char; var lBool: boolean); begin if lCh = 'Y' then lBool := true; if lCh = 'N' then lBool := false; end; procedure ShowHelp (var lIniName: string; lPrefs: TPrefs); begin dcmMsg('Either drag and drop or specify command line options:'); dcmMsg(' '+FilenameWOExt(paramstr(0))+' '); dcmMsg('OPTIONS:'); dcmMsg('-4 Create 4D volumes, else DTI/fMRI saved as many 3D volumes: Y,N = '+Bool2YN(lPrefs.FourD)); dcmMsg('-a Anonymize [remove identifying information]: Y,N = '+Bool2YN(lPrefs.Anonymize)); dcmMsg('-b load settings from specified inifile, e.g. ''-b C:\set\t1.ini'' '); dcmMsg('-c Collapse input folders: Y,N = '+Bool2YN(lPrefs.CollapseFolders)); dcmMsg('-d Date in filename [filename.dcm -> 20061230122032.nii]: Y,N = '+Bool2YN(lPrefs.AppendDate)); dcmMsg('-e events (series/acq) in filename [filename.dcm -> s002a003.nii]: Y,N = '+Bool2YN(lPrefs.AppendAcqSeries)); dcmMsg('-f Source filename [e.g. filename.par -> filename.nii]: Y,N = '+Bool2YN(lPrefs.AppendFilename)); dcmMsg('-g gzip output, filename.nii.gz [ignored if ''-n n'']: Y,N = '+Bool2YN(lPrefs.Gzip)); dcmMsg('-i ID in filename [filename.dcm -> johndoe.nii]: Y,N = '+Bool2YN(lPrefs.AppendPatientName)); dcmMsg('-m manually prompt user to specify output format [NIfTI input only]: Y,N = '+Bool2YN(lPrefs.ManualNIfTIConv)); dcmMsg('-n output .nii file [if no, create .hdr/.img pair]: Y,N = '+Bool2YN(lPrefs.SingleNIIFile)); dcmMsg('-o Output Directory, e.g. ''C:\TEMP'' (if unspecified, source directory is used)'); dcmMsg('-p Protocol in filename [filename.dcm -> TFE_T1.nii]: Y,N = '+Bool2YN(lPrefs.AppendProtocolName)); dcmMsg('-r Reorient image to nearest orthogonal: Y,N '); dcmMsg('-s SPM2/Analyze not SPM5/NIfTI [ignored if ''-n y'']: Y,N = '+Bool2YN(lPrefs.SPM2)); dcmMsg('-t Text report (patient and scan details): Y,N = '+Bool2YN(lPrefs.txtReport)); dcmMsg('-v Convert every image in the directory: Y,N = '+Bool2YN(lPrefs.EveryFile)); dcmMsg('-x Reorient and crop 3D NIfTI images: Y,N = '+Bool2YN(lPrefs.Autocrop)); dcmMsg(' You can also set defaults by editing '+lIniName); {$IFDEF UNIX} dcmMsg('EXAMPLE: '+FilenameWOExt(paramstr(0))+' -a y /Users/Joe/Documents/dcm/IM_0116'); {$ELSE} dcmMsg('EXAMPLE: '+FilenameWOExt(paramstr(0))+' -a y -o C:\TEMP C:\DICOM\input1.par C:\input2.par'); dcmMsg('Hit to exit.'); {$IFNDEF GUI}{$IFNDEF UNIX}if IsConsole then ReadLn;{$ENDIF}{$ENDIF} {$ENDIF} end; //proc ShowHelp (*procedure Testdcm2nii; var lIniName : string; lPrefs: TPrefs; begin lIniName := IniName;//DefaultsDir('')+ParseFileName(ExtractFilename(paramstr(0) ) )+'.ini'; IniFile(True,lIniName, lPrefs); ModifyAnalyze('C:\4d\4d.nii', lPrefs) end; *) function CustomIni: boolean; //returns true if user specifies a custom ini file var i: integer; lStr: string; begin result := false; if (ParamCount < 1) then exit; for i := 1 to ParamCount do begin lStr := UpcaseStr(ParamStr(I)); if (length(lStr)>1) and (lStr[1] = '-') and (lStr[2] = 'B') then result := true; end; end; procedure ProcessParamStrs; var lDir,lStr,lOutDir,lExt: String; {$IFNDEF UNIX}lStartTime: DWord;{$ENDIF} lHelpShown,lAbort,lSilent: boolean; lCommandChar: Char; lPrefs: TPrefs; P,I: integer; lIniName : string; begin if (ParamCount > 0) then ExitCode := 1;//assume error ... will be set to 0 on successful processing of any files... SetDefaultPrefs (lPrefs); {$IFDEF FPC} DefaultFormatSettings.DecimalSeparator := '.'; {$ELSE} DecimalSeparator := '.'; {$ENDIF} lHelpShown := false; lAbort := false; lSilent := false; if not CustomIni then begin //if the user specifies a custom ini file, do not load the default file.... lIniName := IniName;//DefaultsDir('')+ParseFileName(ExtractFilename(paramstr(0) ) )+'.ini'; if fileexists (lIniName) then IniFile(True,lIniName, lPrefs) else IniFile(True,changefileext(paramstr(0),'.init'), lPrefs); //this allows an administrator to create default startup end; lOutDir := ''; //dcm2nii will save nii as default, dcm2niiz will default to gzip, dcm2nii3d will make 3d files.. lStr := UpcaseStr(FilenameWOExt(paramstr(0))); I := length(lStr); if I > 1 then begin lCommandChar := lStr[I]; if (lCommandChar = 'G') or (lCommandChar = 'R') then lPrefs.SingleNIIFile := false else if (lCommandChar = 'Z') then lPrefs.Gzip := true; for P := 1 to I do if lStr[P] in ['0'..'9'] then lCommandChar := lStr[P]; if (lCommandChar = '3') then lPrefs.FourD := false end; //now read filename lStr := paramstr(0); lStr := extractfilename(lStr); lStr := string(StrUpper(PChar(lStr))) ; if (ParamCount > 0) then begin I := 0; repeat lStr := ''; repeat inc(I); if I = 1 then lStr := ParamStr(I) else begin if lStr <> '' then lStr := lStr +' '+ ParamStr(I) else lStr := ParamStr(I); end; if (length(lStr)>1) and (lStr[1] = '-') and (ParamCount > I) then begin //special command lCommandChar := UpCase(lStr[2]); inc(I); lStr := ParamStr(I); {$IFDEF UNIX} if (lCommandChar <> 'O') and (lCommandChar <> 'B') then begin lStr := string(StrUpper(PChar(lStr))) ; //do not upcase paths... end; {$ELSE} lStr := string(StrUpper(PChar(lStr))) ; {$ENDIF} case lCommandChar of '4': CharBool(lStr[1],lPrefs.FourD); 'A': CharBool(lStr[1],lPrefs.Anonymize); 'C': CharBool(lStr[1],lPrefs.CollapseFolders); 'D': CharBool(lStr[1],lPrefs.AppendDate); 'E': CharBool(lStr[1],lPrefs.AppendAcqSeries); 'F': CharBool(lStr[1],lPrefs.AppendFilename); 'G': CharBool(lStr[1],lPrefs.Gzip); 'I': CharBool(lStr[1],lPrefs.AppendPatientName); 'M': CharBool(lStr[1],lPrefs.ManualNIfTIConv); 'N': CharBool(lStr[1],lPrefs.SingleNIIFile); 'P': CharBool(lStr[1],lPrefs.AppendProtocolName); 'R': CharBool(lStr[1],lPrefs.enablereorient); 'S': CharBool(lStr[1],lPrefs.SPM2); 'T': CharBool(lStr[1],lPrefs.txtReport); 'V': CharBool(lStr[1],lPrefs.EveryFile); 'X': CharBool(lStr[1],lPrefs.Autocrop); 'B': begin //load INI file lIniName := lStr; if fileexists(lIniName) then begin IniFile(True,lIniName, lPrefs); end else dcmMsg('0 ERROR: unable to find '+lIniName); end; 'O': begin //output directory lOutDir := ''; if direxists(lStr) then begin lOutDir := lStr; if lOutDir[length(lOutDir)] <> pathdelim then lOutDir := lOutDir + pathdelim; end; end; end; //case lStr[2] lStr := ''; end; //special command until (I=ParamCount) or (fileexists(lStr)) or (lAbort); if (not lPrefs.AppendPatientName) and (not lPrefs.AppendProtocolName) and (not lPrefs.AppendAcqSeries) and (not lPrefs.AppendDate) and (not lPrefs.AppendFilename) then begin lPrefs.AppendPatientName := true; lPrefs.AppendProtocolName := true; lPrefs.AppendDate := true; lPrefs.AppendAcqSeries := true; end; if direxists(lStr) then begin if (lStr[length(lStr)] = PathDelim) and (length(lStr) > 1) then //and delete(lStr, length(lStr), 1); //delete trialing separator RecursiveFolderSearch(lStr,lOutDir,lPrefs,0); lPrefs.NameAppend := ''; end else if fileexists(lStr) then begin lDir := ExtractFileDir(lStr); if lDir = '' then begin //since fileexists, file is in working directory lDir := GetCurrentDir; dcmMsg('0 files in working directory '+lDir); EnsureDirEndsWithPathDelim(lDir); if fileexists(lDir + lStr) then lStr := lDir+ lStr; end; lExt := UpCaseExt(lStr); if IsNiftiExt(lStr) then begin {$IFDEF GUI} MainForm.ConvertDCM2NII(lStr,lPrefs); //dcmMsg('Please drag and drop NIfTI images onto dcm2niigui to convert them') {$ELSE} ModifyAnalyze(lStr,lPrefs); {$ENDIF} end else if (lExt = '.REC') or (lExt = '.PAR') then begin LoadFileListPARREC(lStr,lOutDir,lPrefs); if lPrefs.everyfile then exit; end else begin {$IFNDEF UNIX}lStartTime := GetTickCount; {$ENDIF} if lPrefs.everyfile then LoadFileList(lStr,lOutDir,lPrefs) else LoadParamFileList(lStr,lOutDir,lPrefs,I); {$IFNDEF UNIX}dcmMsg('Time elapsed '+inttostr( GetTickCount-lStartTime)+'ms'); {$ENDIF} exit; //only process a single file end; end else if not (lSilent) then begin dcmMsg('0 '+paramstr(0)+' ERROR: unable to find '+lStr); if not lHelpShown then Showhelp(lIniName, lPrefs); lHelpShown := true; end; until I >= ParamCount; end else begin //no parameters passed - show help ShowHelp(lIniName, lPrefs); IniFile(False,lIniName, lPrefs);//ensure latest version of preferences file is created... end;//param count > 0 end; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/nifti_form.pas0000755000175000017500000000575112307634454020411 0ustar mihmihunit nifti_form; interface uses {$IFDEF FPC}LResources, {$ELSE} RXSpin, {$ENDIF} {$IFNDEF UNIX} Windows,{$ENDIF} Buttons, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Spin, ExtCtrls {, Mask}; {$IFNDEF FPC} type TNIfTIform = class(TForm) ASLCombo: TComboBox; Combo4D: TComboBox; Label1: TLabel; OKBtn: TButton; CancelBtn: TButton; Combo3D: TComboBox; Panel1: TPanel; FormulaPanel: TPanel; StartEdit: TSpinEdit; EndEdit: TSpinEdit; Label2: TLabel; Label3: TLabel; TypeCombo: TComboBox; Label4: TLabel; ASLPanel: TPanel; Label5: TLabel; ScaleEdit: TRxSpinEdit; PowerEdit: TRxSpinEdit; procedure Combo4DChange(Sender: TObject); procedure FormCreate(Sender: TObject); procedure OKBtnClick(Sender: TObject); private {$ELSE} type TNIfTIform = class(TForm) ASLCombo: TComboBox; Combo4D: TComboBox; Label1: TLabel; OKBtn: TButton; CancelBtn: TButton; Combo3D: TComboBox; Panel1: TPanel; FormulaPanel: TPanel; StartEdit: TSpinEdit; EndEdit: TSpinEdit; Label2: TLabel; Label3: TLabel; TypeCombo: TComboBox; Label4: TLabel; ASLPanel: TPanel; Label5: TLabel; ScaleEdit: TFloatSpinEdit; PowerEdit: TFloatSpinEdit; procedure Combo4DChange(Sender: TObject); procedure FormCreate(Sender: TObject); procedure OKBtnClick(Sender: TObject); private {$ENDIF} {Delphi... ScaleEdit: TRxSpinEdit; PowerEdit: TRxSpinEdit; Lazarus ScaleEdit: TFloatSpinEdit; PowerEdit: TFloatSpinEdit; } { Private declarations } public { Public declarations } end; var NIfTIform: TNIfTIform; implementation {$IFNDEF FPC} {$R *.DFM} {$ENDIF} procedure TNIfTIform.Combo4DChange(Sender: TObject); var lS: string; begin lS := ''; If ((Combo4D.visible) and (Combo4D.ItemIndex = 6)) or ( (not (Combo4D.visible)) and (Combo3D.ItemIndex = 3)) then begin Panel1.visible := true; lS := 'Slices'; end else If (Combo4D.visible) and (Combo4D.ItemIndex = 2) then begin Panel1.visible := true; lS := 'Volumes' end else Panel1.visible := false; if lS <> '' then begin Label2.Caption := lS+' to remove from start'; Label3.Caption := lS+' to remove from end'; end; If (Combo4D.visible) and (Combo4D.ItemIndex = 4) then FormulaPanel.visible := true else FormulaPanel.visible := false; If (Combo4D.visible) and (Combo4D.ItemIndex = 5) then ASLPanel.visible := true else ASLPanel.visible := false; end; procedure TNIfTIform.FormCreate(Sender: TObject); begin Combo3D.ItemIndex := 0; Combo4D.ItemIndex := 0; ASLCombo.ItemIndex := 0; end; procedure TNIfTIform.OKBtnClick(Sender: TObject); begin end; {$IFDEF FPC} initialization {$I nifti_form.lrs} {$ENDIF} end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/userdir.pas0000755000175000017500000001416412002260014017703 0ustar mihmihunit userdir; //returns directory where user has read/write permissions... {$IFDEF FPC} {$mode delphi}{$H+} {$ENDIF} interface //returns number of cores: a computer with two dual cores will report 4 function IniName: string; function DefaultsDir (lSubFolder: string): string; function UserDataFolder: string; //uses shlobj implementation {$Include ..\common\isgui.inc} {$IFDEF UNIX} uses Process, SysUtils,classes,IniFiles, {$IFDEF GUI}dialogs;{$ELSE} dialogsx;{$ENDIF} function UserDataFolder: string; begin result :=expandfilename('~/'); end; function FileNameNoExt (lFilewExt:String): string; //remove final extension var lLen,lInc: integer; lName: String; begin lName := ''; lLen := length(lFilewExt); lInc := lLen+1; if lLen > 0 then begin repeat dec(lInc); until (lFileWExt[lInc] = '.') or (lInc = 1); end; if lInc > 1 then for lLen := 1 to (lInc - 1) do lName := lName + lFileWExt[lLen] else lName := lFilewExt; //no extension Result := lName; end; function DefaultsDir (lSubFolder: string): string; //for Linux: DefaultsDir is ~/appname/SubFolder/, e.g. /home/username/mricron/subfolder/ //Note: Final character is pathdelim const pathdelim = '/'; var lBaseDir: string; begin lBaseDir := GetEnvironmentVariable ('HOME')+pathdelim+'.'+ FileNameNoExt(ExtractFilename(paramstr(0) ) ); if not DirectoryExists(lBaseDir) then begin {$I-} MkDir(lBaseDir); if IOResult <> 0 then begin //Msg('Unable to create new folder '+lBaseDir); end; {$I+} end; lBaseDir := lBaseDir+pathdelim; if lSubFolder <> '' then begin lBaseDir := lBaseDir + lSubFolder; if not DirectoryExists(lBaseDir) then begin {$I-} MkDir(lBaseDir); if IOResult <> 0 then begin //you may want to show an error, e.g. showmessage('Unable to create new folder '+lBaseDir); exit; end; {$I+} end; result := lBaseDir + pathdelim; end else result := lBaseDir; end; function IniName: string; begin result := DefaultsDir('')+FileNameNoExt(extractfilename(paramstr(0)))+'.ini'; end; {$ELSE} //If UNIX ELSE NOT Unix uses SysUtils, Windows,shlobj; //for administrators, we can write to folder with executable, otherwise we will save data to the user's AppDataFolder function AppDataFolder: string; //uses shlobj {$IFDEF FPC} const CSIDL_APPDATA = 26; {$ENDIF} var Path : pchar; idList : PItemIDList; begin GetMem(Path, MAX_PATH); SHGetSpecialFolderLocation(0, CSIDL_APPDATA , idList); SHGetPathFromIDList(idList, Path); Result := string(Path); FreeMem(Path); end; function UserDataFolder: string; //uses shlobj var PIDL : PItemIDList; Folder : array[0..MAX_PATH] of Char; const CSIDL_PERSONAL = $0005; begin SHGetSpecialFolderLocation(0, CSIDL_PERSONAL, PIDL); SHGetPathFromIDList(PIDL, Folder); result :=Folder; end; (*function UserDataFolder: string; //uses shlobj var Path : pchar; idList : PItemIDList; begin GetMem(Path, MAX_PATH); SHGetSpecialFolderLocation(0, csidl_Personal , idList); SHGetPathFromIDList(idList, Path); Result := string(Path); FreeMem(Path); end; *) function IsAdmin: Boolean; const SECURITY_NT_AUTHORITY: TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5)); SECURITY_BUILTIN_DOMAIN_RID = $00000020; DOMAIN_ALIAS_RID_ADMINS = $00000220; var hAccessToken: THandle; ptgGroups: PTokenGroups; dwInfoBufferSize: DWORD; psidAdministrators: PSID; x: Integer; bSuccess: BOOL; LastError: integer; begin if Win32Platform <> VER_PLATFORM_WIN32_NT then begin Result := True; exit; end; Result := False; bSuccess := OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, hAccessToken); if not bSuccess then begin if GetLastError = ERROR_NO_TOKEN then bSuccess := OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, hAccessToken); end; if bSuccess then begin GetMem(ptgGroups, 1024); {$IFDEF FPC} bSuccess := GetTokenInformation(hAccessToken, TokenGroups, ptgGroups, 1024, @dwInfoBufferSize); {$ELSE} bSuccess := GetTokenInformation(hAccessToken, TokenGroups, ptgGroups, 1024, dwInfoBufferSize); {$ENDIF} LastError := GetLastError; if not bSuccess then begin //you may want to show an error message.. //showmessage(format('GetLastError %d',[LastError])); end; CloseHandle(hAccessToken); if bSuccess then begin AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, psidAdministrators); {$R-} for x := 0 to ptgGroups.GroupCount - 1 do if EqualSid(psidAdministrators, ptgGroups.Groups[x].Sid) then begin Result := True; break; end; {$R+} FreeSid(psidAdministrators); end; FreeMem(ptgGroups); end; end; function IniName: string; //only administrators can write to c:\program files -use AppDataFolder for non-Administrators begin if isAdmin then result := changefileext(paramstr(0),'.ini') else result := AppDataFolder+'\'+changefileext(extractfilename(paramstr(0)),'.ini'); end; function DefaultsDir (lSubFolder: string): string; const pathdelim = '\'; //for Administrators: DefaultsDir is in the location of the executable, e.g. c:\program files\mricron\subfolder\ //for non-Administrators, the AppDataFolder is returned //Note: Final character is pathdelim begin result := extractfilepath(IniName); if length(result) < 1 then exit; if result[length(result)] <> pathdelim then result := result + pathdelim; if lSubFolder = '' then exit; result := result + lSubFolder; if result[length(result)] <> pathdelim then result := result + pathdelim; end; {$ENDIF} end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dicomcompat.pas0000755000175000017500000100727212310411624020537 0ustar mihmihunit dicomcompat; interface uses //{$Define Troubleshoot} {$DEFINE read00189117} //Support Philips shameful DTI usage {$DEFINE read20011003} //Support Philips Shameful DTI usage {$IFDEF FPC} gzio2, {$ELSE} gziod, {$ENDIF} SysUtils,Classes,define_types,filename,dicomtypes,dicomfastread,prefs,convertsimple, csaread,dialogs_msg; {$H+} var kUseDateTimeForID: boolean = false; procedure read_afni_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string; var lRotation1,lRotation2,lRotation3: integer); procedure read_ecat_data(var lDICOMdata: DICOMdata;lVerboseRead,lReadECAToffsetTables:boolean; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); procedure read_siemens_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); procedure read_ge_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); procedure read_interfile_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string); procedure read_voxbo_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string); procedure read_VFF_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string); procedure read_picker_data(lVerboseRead: boolean; var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); procedure read_tiff_data(var lDICOMdata: DICOMdata; var lReadOffsets,lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); procedure read_dicom_data_compat(lReadJPEGtables,lVerboseRead,lAutoDECAT7,lReadECAToffsetTables,lAutodetectInterfile,lAutoDetectGenesis,lReadColorTables: boolean; var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string; var lPrefs: TPrefs); var gSizeMMWarningShown : boolean = false; gECATJPEG_table_entries: integer = 0; gECATJPEG_pos_table,gECATJPEG_size_table : LongIntP; red_table_size : Integer = 0; green_table_size : Integer = 0; blue_table_size : Integer = 0; red_table : ByteP; green_table : ByteP; blue_table : ByteP; implementation uses dialogsx; function SecSinceMidnightFloat (lStr: string): double; var lNumStr: string; sec: double; i,len,dec: integer; begin result := 0;//error if lStr = '' then exit; len := length(lStr); lNumStr := ''; for i := 1 to len do begin if (lStr[i] = '.') or (lStr[i] = ',') then lStr[i] := DecimalSeparator; //make native format, e.g. in Germany 10,123 whereas in USA 10.123 if lStr[i] in ['0'..'9',DecimalSeparator] then lNumStr := lNumStr + lStr[i]; end; if lNumStr = '' then exit; //make sure 6 characters before decimal, in case HHMMSS is written HMMSS dec := length(lNumStr) + 1; for i := length(lNumStr) downto 1 do if lNumStr[i] = DecimalSeparator then dec := i; if dec > 7 then exit; //HHMMSS.??? can only have 6 digits before decimal while dec < 7 do begin lNumStr := '0'+lNumStr; inc(dec); end; //now in HHMMSS.????? format len := length(lNumStr); lStr := lNumStr[1]+lNumStr[2]; //HH sec := 60 * 60 * strtoint(lStr); //60m/h, 60s/m lStr := lNumStr[3]+lNumStr[4]; //MM sec := sec + ( 60 * strtoint(lStr)); //60s/m 1000ms/s lStr := ''; for i := 5 to len do //SS.SSSS lStr := lStr + lNumStr[i]; sec := sec + ( strtofloat(lStr)); //60s/m 1000ms/s result := sec; end; function AddIndent(lIndent: integer): string; var i: integer; begin result := ''; if lIndent < 1 then exit; for i := 1 to lIndent do result := result +'|'; end; procedure read_ecat_data(var lDICOMdata: DICOMdata;lVerboseRead,lReadECAToffsetTables:boolean; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); label 121,539; const kMaxnSLices = 6000; kStrSz = 40; var lLongRA: LongIntp; lECAT7sigUpcase,lECAT7sig : array [0..6] of Char; lParse,lSPos,lFPos{,lScomplement},lF,lS,lYear,lFrames,lVox,lHlfVox,lJ,lPass,lVolume,lNextDirectory,lSlice,lSliceSz,lVoxelType,lPos,lEntry, lSlicePos,lLongRApos,lLongRAsz,{lSingleRApos,lSingleRAsz,}{lMatri,}lX,lY,lZ,lCacheSz,lImgSz,lSubHeadStart,lMatrixStart,lMatrixEnd,lInt,lInt2,lInt3,lINt4,n,filesz: LongInt; lPlanes,lGates,lAqcType,lFileType: word; lXmm,lYmm,lZmm,lCalibrationFactor, lQuantScale: real; FP: file; lCreateTable,lSwapBytes,lMR,lECAT6: boolean; function xWord(lPos: longint): word; var s: word; begin seek(fp,lPos); BlockRead(fp, s, 2, n); if lSwapBytes then result := swap(s) else result := s; //assign address of s to inguy end; function swap32i(lPos: longint): Longint; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(Long:LongInt); end; swaptypep = ^swaptype; var s : LongInt; inguy:swaptypep; outguy:swaptype; begin seek(fp,lPos); BlockRead(fp, s, 4, n); inguy := @s; //assign address of s to inguy if not lSwapBytes then begin result := inguy^.long; exit; end; outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); swap32i:=outguy.Long; end; function StrRead (lPos, lSz: longint) : string; var I: integer; tx : array [1..kStrSz] of Char; begin result := ''; if lSz > kStrSz then exit; seek(fp, lPos{-1}); BlockRead(fp, tx, lSz*SizeOf(Char), n); for I := 1 to (lSz-1) do begin if tx[I] in [' ','[',']','+','-','.','\','~','/', '0'..'9','a'..'z','A'..'Z'] then {if (tx[I] <> kCR) and (tx[I] <> UNIXeoln) then} result := result + tx[I]; end; end; function fswap4r (lPos: longint): single; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(float:single); end; swaptypep = ^swaptype; var s:single; inguy:swaptypep; outguy:swaptype; begin seek(fp,lPos); if not lSwapBytes then begin BlockRead(fp, result, 4, n); exit; end; BlockRead(fp, s, 4, n); inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); fswap4r:=outguy.float; end; function fvax4r (lPos: longint): single; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(float:single); end; swaptypep = ^swaptype; var s:single; lT1,lT2 : word; inguy:swaptypep; begin seek(fp,lPos); BlockRead(fp, s, 4, n); inguy := @s; if (inguy^.Word1 =0) and (inguy^.Word2 = 0) then begin result := 0; exit; end; lT1 := inguy^.Word1 and $80FF; lT2 := ((inguy^.Word1 and $7F00) +$FF00) and $7F00; inguy^.Word1 := inguy^.Word2; inguy^.Word2 := (lt1+lT2); fvax4r:=inguy^.float; end; begin Clear_Dicom_Data(lDicomData); if gECATJPEG_table_entries <> 0 then begin freemem (gECATJPEG_pos_table); freemem (gECATJPEG_size_table); gECATJPEG_table_entries := 0; end; lHdrOK:= false; lQuantScale:= 1; lCalibrationFactor := 1; lLongRASz := 0; lLongRAPos := 0; lImageFormatOK := false; lVolume := 1; if not fileexists(lFileName) then begin dcmMsg('Unable to find the image '+lFileName); exit; end; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FileSz := FileSize(fp); if filesz < (2048) then begin dcmMsg('This file is to small to be a ECAT format image.'); goto 539; end; seek(fp, 0); BlockRead(fp, lECAT7Sig, 6*SizeOf(Char){, n}); for lInt4 := 0 to (5) do begin if lECAT7Sig[lInt4] in ['a'..'z','A'..'Z'] then lECAT7SigUpCase[lInt4] := upcase(lECAT7Sig[lInt4]) else lECAT7SigUpCase[lInt4] := ' '; end; if (lECAT7SigUpCase[0]='M') and (lECAT7SigUpCase[1]='A') and (lECAT7SigUpCase[2]='T') and (lECAT7SigUpCase[3]='R') and (lECAT7SigUpCase[4]='I') and (lECAT7SigUpCase[5]='X') then lECAT6 := false else lECAT6 := true; if lEcat6 then begin lSwapBytes := false; lFileType := xWord(27*2); if lFileType > 255 then lSwapBytes := not lSwapBytes; lFileType := xWord(27*2); lAqcType := xWord(175*2); lPlanes := xWord(188*2); lFrames := xword(189*2); lGates := xWord(190*2); lYear := xWord(70); if (lPlanes < 1) or (lFrames < 1) or (lGates < 1) then begin case MsgDlg('Warning: one of the planes/frames/gates values is less than 1 ['+inttostr(lPlanes)+'/'+inttostr(lFrames)+'/'+inttostr(lGates)+']. Is this file really ECAT 6 format? Press abort to cancel conversion. ', mterror,[mbOK,mbAbort], 0) of mrAbort: goto 539; end; //case end else if (lYear < 1940) or (lYear > 3000) then begin case MsgDlg('Warning: the year value appears invalid ['+inttostr(lYear)+']. Is this file really ECAT 6 format? Press abort to cancel conversion. ', mterror,[mbOK,mbAbort], 0) of mrAbort: goto 539; end; //case end; if lVerboseRead then begin lDynStr :='ECAT6 data'; lDynStr :=lDynStr+kCR+('Patient Name:'+StrRead(190,32)); lDynStr :=lDynStr+kCR+('Patient ID:'+StrRead(174,16)); lDynStr :=lDynStr+kCR+('Study Desc:'+StrRead(318,32)); lDynStr := lDynStr+kCR+('Facility: '+StrRead(356,20)); lDynStr := lDynStr+kCR+('Planes: '+inttostr(lPlanes)); lDynStr := lDynStr+kCR+('Frames: '+inttostr(lFrames)); lDynStr := lDynStr+kCR+('Gates: '+inttostr(lGates)); lDynStr := lDynStr+kCR+('Date DD/MM/YY: '+ inttostr(xWord(66))+'/'+inttostr(xWord(68))+'/'+inttostr(lYear)); end; {show summary} end else begin //NOT ECAT6 lSwapBytes := true; lFileType := xWord(50); if lFileType > 255 then lSwapBytes := not lSwapBytes; lFileType := xWord(50); lAqcType := xWord(328); lPlanes := xWord(352); lFrames := xWord(354); lGates := xWord(356); lCalibrationFactor := fswap4r(144); if {(true) or} (lPlanes < 1) or (lFrames < 1) or (lGates < 1) then begin case MsgDlg('Warning: on of the planes/frames/gates values is less than 1 ['+inttostr(lPlanes)+'/'+inttostr(lFrames)+'/'+inttostr(lGates)+']. Is this file really ECAT 7 format? Press abort to cancel conversion. ', mterror,[mbOK,mbAbort], 0) of mrAbort: goto 539; end; //case end; //error if lVerboseRead then begin lDynStr := 'ECAT 7 format'; lDynStr := lDynStr+kCR+('Serial Number:'+StrRead(52,10)); lDynStr := lDynStr+kCR+('Patient Name:'+StrRead(182,32)); lDynStr := lDynStr+kCR+('Patient ID:'+StrRead(166,16)); lDynStr := lDynStr+kCR+('Study Desc:'+StrRead(296,32)); lDynStr := lDynStr+kCR+('Facility: '+StrRead(332,20)); lDynStr := lDynStr+kCR+('Scanner: '+inttostr(xWord(48))); lDynStr := lDynStr+kCR+('Planes: '+inttostr(lPlanes)); lDynStr := lDynStr+kCR+('Frames: '+inttostr(lFrames)); lDynStr := lDynStr+kCR+('Gates: '+inttostr(lGates)); lDynStr := lDynStr+kCR+'Calibration: '+floattostr(lCalibrationFactor); end; {lShow Summary} end; //lECAT7 if lFiletype = 9 then lFiletype := 7; //1364: treat projections as Volume16's if not (lFileType in [1,2,3,4,7]) then begin dcmMsg('This software does not recognize the ECAT file type. Selected filetype: '+inttostr(lFileType)); goto 539; end; lVoxelType := 2; if lFileType = 3 then lVoxelType := 4; if lVerboseRead then begin case lFileType of 1: lDynStr := lDynStr+kCR+('File type: Scan File'); 2: lDynStr := lDynStr+kCR+('File type: Image File'); //x 3: lDynStr := lDynStr+kCR+('File type: Attn File'); 4: lDynStr := lDynStr+kCR+('File type: Norm File'); 7: lDynStr := lDynStr+kCR+('File type: Volume 16'); //x end; //lfiletye case case lAqcType of 1:lDynStr := lDynStr+kCR+('Acquisition type: Blank'); 2:lDynStr := lDynStr+kCR+('Acquisition type: Transmission'); 3:lDynStr := lDynStr+kCR+('Acquisition type: Static Emission'); 4:lDynStr := lDynStr+kCR+('Acquisition type: Dynamic Emission'); 5:lDynStr := lDynStr+kCR+('Acquisition type: Gated Emission'); 6:lDynStr := lDynStr+kCR+('Acquisition type: Transmission Rect'); 7:lDynStr := lDynStr+kCR+('Acquisition type: Emission Rect'); 8:lDynStr := lDynStr+kCR+('Acquisition type: Whole Body Transm'); 9:lDynStr := lDynStr+kCR+('Acquisition type: Whole Body Static'); else lDynStr := lDynStr+kCR+('Acquisition type: Undefined'); end; //case AqcType end; //verbose read if ((lECAT6) and (lFiletype =2)) or ({(not lECAT6) and} (lFileType=7)) then //Kludge else begin dcmMsg('Unusual ECAT filetype. Please contact the author.'); goto 539; end; lHdrOK:= true; lImageFormatOK := true; lLongRASz := kMaxnSlices * sizeof(longint); getmem(lLongRA,lLongRAsz); lPos := 512; //lSingleRASz := kMaxnSlices * sizeof(single); //getmem(lSingleRA,lSingleRAsz); //lMatri := 0; lVolume := 1; lPass := 0; 121: lEntry := 1; lInt := swap32i(lPos); lInt2 := swap32i(lPos+4); lNextDirectory := lInt2; while true do begin inc(lEntry); lPos := lPos + 16; lInt := swap32i(lPos); lInt2 := swap32i(lPos+4); lInt3 := swap32i(lPos+8); lInt4 := swap32i(lPos+12); lInt2 := lInt2 - 1; lSubHeadStart := lINt2 *512; lMatrixStart := ((lInt2) * 512)+512 {add subhead sz}; lMatrixEnd := lInt3 * 512; if (lInt4 = 1) and (lMatrixStart < FileSz) and (lMatrixEnd <= FileSz) then begin if (lFileType= 7) {or (lFileType = 4) } or (lFileType = 2) then begin //Volume of 16-bit integers if lEcat6 then begin lX := xWord(lSubHeadStart+(66*2)); lY := xWord(lSubHeadStart+(67*2)); lZ := 1;//uxWord(lSubHeadStart+8); lXmm := 10*fvax4r(lSubHeadStart+(92*2));// fswap4r(lSubHeadStart+(92*2)); lYmm := lXmm;//read32r(lSubHeadStart+(94*2)); lZmm := 10 * fvax4r(lSubHeadStart+(94*2)); lCalibrationFactor := fvax4r(lSubHeadStart+(194*2)); lQuantScale := fvax4r(lSubHeadStart+(86*2)); if lVerboseRead then lDynStr := lDynStr+kCR+'Plane '+inttostr(lPass+1)+' Calibration/Scale Factor: '+floattostr(lCalibrationFactor)+'/'+floattostr(lQuantScale); end else begin //02 or 07 lX := xWord(lSubHeadStart+4); lY := xWord(lSubHeadStart+6); lZ := xWord(lSubHeadStart+8); //if lFileType <> 4 then begin lXmm := 10*fswap4r(lSubHeadStart+34); lYmm := 10*fswap4r(lSubHeadStart+38); lZmm := 10*fswap4r(lSubHeadStart+42); lQuantScale := fswap4r(lSubHeadStart+26); if lVerboseRead then lDynStr := lDynStr+kCR+'Volume: '+inttostr(lPass+1)+' Scale Factor: '+floattostr(lQuantScale); //end; //filetype <> 4 end; //ecat7 if true then begin //FileMode := 2; //set to read/write inc(lPass); lImgSz := lX * lY * lZ * lVoxelType; {2 bytes per voxel} lSliceSz := lX * lY * lVoxelType; if lZ < 1 then begin lHdrOK := false; goto 539; end; lSlicePos := lMatrixStart; if ((lECAT6) and (lPass = 1)) or ( (not lECAT6)) then begin lDICOMdata.XYZdim[1] := lX; lDICOMdata.XYZdim[2] := lY; lDICOMdata.XYZdim[3] := lZ; lDICOMdata.XYZmm[1] := lXmm; lDICOMdata.XYZmm[2] := lYmm; lDICOMdata.XYZmm[3] := lZmm; case lVoxelType of 1: begin dcmMsg('Error: 8-bit data not supported [yet]. Please contact the author.'); lDicomData.Allocbits_per_pixel := 8; lHdrOK := false; goto 539; end; 4: begin dcmMsg('Error: 32-bit data not supported [yet]. Please contact the author.'); lHdrOK := false; goto 539; end; else begin //16-bit integers lDicomData.Allocbits_per_pixel := 16; end; end; {case lVoxelType} end else begin //if lECAT6 if (lDICOMdata.XYZdim[1] <> lX) or (lDICOMdata.XYZdim[2] <> lY) or (lDICOMdata.XYZdim[3] <> lZ) then begin dcmMsg('Error: different slices in this volume have different slice sizes. Please contact the author.'); lHdrOK := false; goto 539; end; //dimensions have changed //lSlicePos :=((lMatri-1)*lImgSz); end; //ECAT6 lVox := lSliceSz div 2; lHlfVox := lSliceSz div 4; for lSlice := 1 to lZ do begin if (not lECAT6) then lSlicePos := ((lSlice-1)*lSliceSz)+lMatrixStart; if lLongRAPos >= kMaxnSLices then begin lHdrOK := false; goto 539; end; inc(lLongRAPos); lLongRA^[lLongRAPos] := lSlicePos; {inc(lSingleRAPos); if lCalibTableType = 1 then lSingleRA[lSingleRAPos] := lQuantScale else lSingleRA[lSingleRAPos] := lCalibrationFactor *lQuantScale;} end; //slice 1..lZ if not lECAT6 then inc(lVolume); end; //fileexistsex end; //correct filetype end; //matrix start/end within filesz if (lMatrixStart > FileSz) or (lMatrixEnd >= FileSz) then goto 539; if ((lEntry mod 32) = 0) then begin if ((lNextDirectory-1)*512) <= lPos then goto 539; //no more directories lPos := (lNextDirectory-1)*512; goto 121; end; //entry 32 end ; //while true 539: CloseFile(fp); FileMode := 2; //set to read/write lDicomData.XYZdim[3] := lLongRApos; if not lECAT6 then dec(lVolume); //ECAT7 increments immediately before exiting loop - once too often lDicomData.XYZdim[4] :=(lVolume); if lSwapBytes then lDicomData.little_endian := 0 else lDicomData.little_endian := 1; if (lLongRApos > 0) and (lHdrOK) then begin lDicomData.ImageStart := lLongRA^[1]; lCreateTable := false; if (lLongRApos > 1) then begin lFPos := lDICOMdata.ImageStart; for lS := 2 to lLongRApos do begin lFPos := lFPos + lSliceSz; if lFPos <> lLongRA^[lS] then lCreateTable := true; end; if (lCreateTable) and (lReadECAToffsetTables) then begin gECATJPEG_table_entries := lLongRApos; getmem (gECATJPEG_pos_table, gECATJPEG_table_entries*sizeof(longint)); getmem (gECATJPEG_size_table, gECATJPEG_table_entries*sizeof(longint)); for lS := 1 to gECATJPEG_table_entries do gECATJPEG_pos_table^[lS] := lLongRA^[lS] end else if (lCreateTable) then lImageFormatOK := false; //slices are offset within this file end; if (lVerboseRead) and (lHdrOK) then begin lDynStr :=lDynStr+kCR+('XYZdim:'+inttostr(lX)+'/'+inttostr(lY)+'/'+inttostr(gECATJPEG_table_entries)); lDynStr :=lDynStr+kCR+('XYZmm: '+floattostrf(lDicomData.XYZmm[1],ffFixed,7,7)+'/'+floattostrf(lDicomData.XYZmm[2],ffFixed,7,7) +'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,7,7)); //xlDynStr :=lDynStr+kCR+('Bits per voxel: '+inttostr(lDicomData.Storedbits_per_pixel)); lDynStr :=lDynStr+kCR+('Image Start: '+inttostr(lDicomData.ImageStart)); if lCreateTable then lDynStr :=lDynStr+kCR+('Note: staggered slice offsets'); end end; //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; if lLongRASz > 0 then freemem(lLongRA); (*if (lSingleRApos > 0) and (lHdrOK) and (lCalibTableType <> 0) then begin gECAT_scalefactor_entries := lSingleRApos; getmem (gECAT_scalefactor_table, gECAT_scalefactor_entries*sizeof(single)); for lS := 1 to gECAT_scalefactor_entries do gECAT_scalefactor_table[lS] := lSingleRA[lS]; end; if lSingleRASz > 0 then freemem(lSingleRA);*) end; (*procedure write_slc (lFileName: string; var pDICOMdata: DICOMdata;var lSz: integer; lDICOM3: boolean); const kMaxRA = 41; lXra: array [1..kMaxRA] of byte = (7,8,9,21,22,26,27, 35,36,44,45, 50,62,66,78, 81,95, 97,103,104,105,106,111, 113,123,127, 129,139,142, 146,147,148,149,155,156,157, 166,167,168,169,170); var fp: file; lX,lClr,lPos,lRApos: integer; lP: bytep; procedure WriteString(lStr: string; lCR: boolean); var n,lStrLen : Integer; begin lStrLen := length(lStr); for n := 1 to lstrlen do begin lPos := lPos + 1; lP[lPos] := ord(lStr[n]); end; if lCR then begin lPos := lPos + 1; lP[lPos] := ord(kCR); end; end; begin lSz := 0; getmem(lP,2048); lPos := 0; WriteString('11111',true); WriteString(inttostr(pDicomData.XYZdim[1])+' '+inttostr(pDicomData.XYZdim[2])+' '+inttostr(pDicomData.XYZdim[3])+' 8',true); WriteString(floattostrf(pDicomData.XYZmm[1],ffFixed,7,7)+' '+floattostrf(pDicomData.XYZmm[2],ffFixed,7,7)+' '+floattostrf(pDicomData.XYZmm[3],ffFixed,7,7),true); WriteString('1 1 0 0',true); //mmunits,MR,original,nocompress WriteString('16 12 X',false); //icon is 8x8 grid, so 64 bytes for red,green blue for lClr := 1 to 3 do begin lRApos := 1; for lX := 1 to 192 do begin inc(lPos); if (lRApos <= kMaxRA) and (lX = lXra[lRApos]) then begin inc(lRApos); lP[lPos] := 200; end else lP[lPos] := 0; end; {icongrid 1..192} end; {RGB} if lFileName <> '' then begin AssignFile(fp, lFileName); Rewrite(fp, 1); blockwrite(fp,lP^,lPos); close(fp); end; freemem(lP); lSz := lPos; end;*) procedure read_interfile_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string); label 333; const UNIXeoln = chr(10); var lTmpStr, lInStr,lUpCaseStr: string; lHdrEnd,lFloat,lUnsigned: boolean; lPos,lLen,FileSz,linPos: integer; fp: file; lCharRA: bytep; function readInterFloat:real; var lStr: string; begin lStr := ''; While (lPos <= lLen) and (lInStr[lPos] <> ';') do begin if lInStr[lPos] in ['+','-','e','E','.','0'..'9'] then lStr := lStr+(linStr[lPos]); inc(lPos); end; try result := strtofloat(lStr); except on EConvertError do begin dcmMsg('Unable to convert the string '+lStr+' to a number'); result := 1; exit; end; end; {except} end; function readInterStr:string; var lStr: string; begin lStr := ''; While (lPos <= lLen) and (lInStr[lPos] = ' ') do begin inc(lPos); end; While (lPos <= lLen) and (lInStr[lPos] <> ';') do begin if lInStr[lPos] <> ' ' then //1.39 build 6 lStr := lStr+upcase(linStr[lPos]); //zebra upcase inc(lPos); end; result := lStr; end; //interstr func begin lHdrOK := false; lFloat := false; lUnsigned := false; lImageFormatOK := true; Clear_Dicom_Data(lDicomData); lDynStr := ''; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FileSz := FileSize(fp); lHdrEnd := false; //lDicomData.ImageStart := FileSz; GetMem( lCharRA, FileSz+1 ); BlockRead(fp, lCharRA^, FileSz, linpos); if lInPos <> FileSz then dcmMsg('Disk error: Unable to read full input file.'); linPos := 1; CloseFile(fp); FileMode := 2; //set to read/write repeat linstr := ''; while (linPos < FileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin lInStr := lInstr + chr(lCharRA^[linPos]); inc(linPos); end; inc(lInPos); //read EOLN lLen := length(lInStr); lPos := 1; lUpcaseStr := ''; While (lPos <= lLen) and (lInStr[lPos] <> ';') and (lInStr[lPos] <> '=') and (lUpCaseStr <>'INTERFILE') do begin if lInStr[lPos] in ['[',']','(',')','/','+','-',{' ',} '0'..'9','a'..'z','A'..'Z'] then lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]); inc(lPos); end; inc(lPos); {read equal sign in := statement} if lUpCaseStr ='INTERFILE' then begin lHdrOK := true; lDicomData.little_endian := 0; end; if lUpCaseStr ='DATASTARTINGBLOCK'then lDicomData.ImageStart := 2048 * round(readInterFloat); if lUpCaseStr ='DATAOFFSETINBYTES'then lDicomData.ImageStart := round(readInterFloat); if (lUpCaseStr ='MATRIXSIZE[1]') or (lUpCaseStr ='MATRIXSIZE[X]') then lDicomData.XYZdim[1] := round(readInterFloat); if (lUpCaseStr ='MATRIXSIZE[2]')or (lUpCaseStr ='MATRIXSIZE[Y]')then lDicomData.XYZdim[2] := round(readInterFloat); if (lUpCaseStr ='MATRIXSIZE[3]')or (lUpCaseStr ='MATRIXSIZE[Z]') or (lUpCaseStr ='NUMBEROFSLICES') or (lUpCaseStr ='TOTALNUMBEROFIMAGES') then begin lDicomData.XYZdim[3] := round(readInterFloat); end; if lUpCaseStr ='IMAGEDATABYTEORDER' then begin if readInterStr = 'LITTLEENDIAN' then lDicomData.little_endian := 1; end; if lUpCaseStr ='NUMBERFORMAT' then begin lTmpStr := readInterStr; if (lTmpStr = 'ASCII') or (lTmpStr='BIT') then begin lHdrOK := false; dcmMsg('This software can not convert '+lTmpStr+' data type.'); goto 333; end; if lTmpStr = 'UNSIGNEDINTEGER' then lUnsigned := true; if (lTmpStr='FLOAT') or (lTmpStr='SHORTFLOAT') or (lTmpStr='LONGFLOAT') then begin //1395 lFloat := true; end; end; if lUpCaseStr ='NAMEOFDATAFILE' then lFileName := ExtractFilePath(lFileName)+readInterStr; if lUpCaseStr ='NUMBEROFBYTESPERPIXEL' then lDicomData.Allocbits_per_pixel := round(readInterFloat)*8; if (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[1]') or (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[X]') then lDicomData.XYZmm[1] := (readInterFloat); if (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[2]') or (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[Y]')then lDicomData.XYZmm[2] := (readInterFloat); if (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[3]')or (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[Z]')or (lUpCaseStr ='SLICETHICKNESS')then lDicomData.XYZmm[3] := (readInterFloat); if (lUpCaseStr ='ENDOFINTERFILE') then lHdrEnd := true; if not lHdrOK then goto 333; if lInStr <> '' then lDynStr := lDynStr + lInStr+kCr; lHdrOK := true; until (linPos >= FileSz) or (lHdrEnd){EOF(fp)}; //xlDicomData.Storedbits_per_pixel := lDicomData.Allocbits_per_pixel; lImageFormatOK := true; if (not lFLoat) and (lUnsigned) and ((lDicomData.Allocbits_per_pixel = 16)) then begin dcmMsg('Warning: this Interfile image uses UNSIGNED 16-bit data [values 0..65535]. Analyze specifies SIGNED 16-bit data [-32768..32767]. Some images may not transfer well. [Future versions of MRIcro should fix this].'); lImageFormatOK := false; end else if (not lFLoat) and (lDicomData.Allocbits_per_pixel > 16) then begin dcmMsg('WARNING: The image '+lFileName+' is a '+inttostr(lDicomData.Allocbits_per_pixel)+'-bit integer data type. This software may display this as SIGNED data. Bits per voxel: '+inttostr(lDicomData.Allocbits_per_pixel)); lImageFormatOK := false; end else if (lFloat) then begin //zebra change float check //dcmMsg('WARNING: The image '+lFileName+' uses floating point [real] numbers. The current software can only read integer data type Interfile images.'); lDicomData.FloatData := true; //lImageFormatOK := false; end; 333: FreeMem( lCharRA); end; //interfile //afni start function ParseFileName (lFilewExt:String): string; var lLen,lInc: integer; lName: String; begin lName := ''; lLen := length(lFilewExt); lInc := lLen+1; if lLen > 0 then repeat dec(lInc); until (lFileWExt[lInc] = '.') or (lInc = 1); if lInc > 1 then for lLen := 1 to (lInc - 1) do lName := lName + lFileWExt[lLen] else lName := lFilewExt; //no extension ParseFileName := lName; end; procedure read_afni_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string; var lRotation1,lRotation2,lRotation3: integer); //label 333; const UNIXeoln = chr(10); kTab = ord(chr(9)); kSpace = ord(' '); var lTmpStr,lInStr,lUpCaseStr: string; lHdrEnd: boolean; lMSBch: char; lOri : array [1..4] of single; lTmpInt,lPos,lLen,FileSz,linPos: integer; fp: file; lCharRA: bytep; procedure readAFNIeoln; begin while (linPos < FileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do inc(linPos); inc(lInPos); //read EOLN end; function readAFNIFloat:real; var lStr: string; lCh:char; begin lStr := ''; while (linPos < FileSz) and ((lStr='') or ((lCharRA^[lInPos] <> kTab) and (lCharRA^[lInPos] <> kSpace))) do begin lCh:= chr(lCharRA^[linPos]); if lCh in ['+','-','e','E','.','0'..'9'] then lStr := lStr+lCh; inc(linPos); end; if lStr = '' then exit; try result := strtofloat(lStr); except on EConvertError do begin dcmMsg('Unable to convert the string '+lStr+' to a number'); result := 1; exit; end; end; {except} end; begin lHdrOK := false; lImageFormatOK := true; Clear_Dicom_Data(lDicomData); lDynStr := ''; lTmpStr := string(StrUpper(PChar(ExtractFileExt(lFileName)))); if lTmpStr <> '.HEAD' then exit; for lInPos := 1 to 3 do lOri[lInPos] := -6666; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FileSz := FileSize(fp); lHdrEnd := false; //lDicomData.ImageStart := FileSz; GetMem( lCharRA, FileSz+1 ); BlockRead(fp, lCharRA^, FileSz, linpos); if lInPos <> FileSz then dcmMsg('Disk error: Unable to read full input file.'); linPos := 1; CloseFile(fp); FileMode := 2; //set to read/write repeat linstr := ''; while (linPos < FileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin lInStr := lInstr + chr(lCharRA^[linPos]); inc(linPos); end; inc(lInPos); //read EOLN lLen := length(lInStr); lPos := 1; lUpcaseStr := ''; While (lPos <= lLen) do begin if lInStr[lPos] in ['_','[',']','(',')','/','+','-','=',{' ',} '0'..'9','a'..'z','A'..'Z'] then lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]); inc(lPos); end; inc(lPos); {read equal sign in := statement} if lUpCaseStr ='NAME=DATASET_DIMENSIONS'then begin lImageFormatOK := true; lHdrOK := true; lFileName := parsefilename(lFilename)+'.BRIK'; //always UPPERcase readAFNIeoln; lDICOMdata.XYZdim[1] := round(readAFNIFloat); lDICOMdata.XYZdim[2] := round(readAFNIFloat); lDICOMdata.XYZdim[3] := round(readAFNIFloat); //lDicomData.ImageStart := 2048 * round(readInterFloat); end; if lUpCaseStr ='NAME=BRICK_FLOAT_FACS'then begin readAFNIeoln; lDICOMdata.IntenScale := readAFNIFloat; //1380 read slope of intensity end; if lUpCaseStr ='NAME=DATASET_RANK'then begin readAFNIeoln; //2nd value is number of volumes readAFNIFloat; lDICOMdata.XYZdim[4] := round(readAFNIFloat); end; if lUpCaseStr ='NAME=BRICK_TYPES'then begin readAFNIeoln; lTmpInt := round(readAFNIFloat); case lTmpInt of 0:lDicomData.Allocbits_per_pixel := 8; 1:begin lDicomData.Allocbits_per_pixel := 16; //lDicomData.MaxIntensity := 65535; //Old AFNI were UNSIGNED, new ones are SIGNED??? end; 3:begin lDicomData.Allocbits_per_pixel := 32; lDicomData.FloatData := true; end; else begin lHdrEnd := true; dcmMsg('Unsupported AFNI BRICK_TYPES: '+inttostr(lTmpInt)); end; end; //case {datatype 0 = byte (unsigned char; 1 byte) 1 = short (2 bytes, signed) 3 = float (4 bytes, assumed to be IEEE format) 5 = complex (8 bytes: real+imaginary parts)} end; if lUpCaseStr ='NAME=BYTEORDER_STRING'then begin readAFNIeoln; if ((linPos+2) < FileSz) then begin lMSBch := chr(lCharRA^[linPos+1]); if lMSBCh = 'L' then lDicomData.Little_Endian := 1; if lMSBCh = 'M' then begin lDicomData.Little_Endian := 0; end; linPos := lInPos + 2; end; //littleendian end; if lUpCaseStr ='NAME=ORIGIN'then begin readAFNIeoln; lOri[1] := (abs(readAFNIFloat)); lOri[2] := (abs(readAFNIFloat)); lOri[3] := (abs(readAFNIFloat)); //Xori,YOri,ZOri end; if lUpCaseStr ='NAME=DELTA'then begin readAFNIeoln; lDICOMdata.XYZmm[1] := abs(readAFNIFloat); lDICOMdata.XYZmm[2] := abs(readAFNIFloat); lDICOMdata.XYZmm[3] := abs(readAFNIFloat); //Xmm,Ymm,Zmm end; if lUpCaseStr ='NAME=ORIENT_SPECIFIC'then begin readAFNIeoln; lRotation1 := round(readAFNIFloat); lRotation2 := round(readAFNIFloat); lRotation3 := round(readAFNIFloat); end; //ORIENT_SPECIFIC rotation details if lInStr <> '' then lDynStr := lDynStr + lInStr+kCr; until (linPos >= FileSz) or (lHdrEnd){EOF(fp)}; //xlDicomData.Storedbits_per_pixel := lDicomData.Allocbits_per_pixel; for lInPos := 1 to 3 do begin if lOri[lInPos] < -6666 then //value not set lDICOMdata.XYZori[lInPos] := round((1.0+lDICOMdata.XYZdim[lInPos])/2) else if lDICOMdata.XYZmm[lInPos] <> 0 then lDICOMdata.XYZori[lInPos] := round(1.5+lOri[lINPos] / lDICOMdata.XYZmm[lInPos]); end; // lDicomData.Float := true; FreeMem( lCharRA); end; //interfile //afni end //voxbo start procedure read_voxbo_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string); label 333; const UNIXeoln = chr(10); kTab = chr(9); var lTmpStr,lInStr,lUpCaseStr: string; lFileTypeKnown,lHdrEnd,lFloat: boolean; lStartPos,lPos,lLen,FileSz,linPos: integer; fp: file; lCharRA: bytep; procedure readVBfloats (var lF1,lF2,lF3: double); // While (lPos <= lLen) and ((lInStr[lPos] = kTab) or (lInStr[lPos] = ' ')) do begin // inc(lPos); var //lDigit : boolean; n,lItemIndex: integer; lStr,lfStr: string; begin lf1 := 1; lf2 := 1; lf3 := 1; n := 0; for lItemIndex := 1 to 3 do begin inc(n); While (lPos <= lLen) and ((lInStr[lPos] = kTab) or (lInStr[lPos] = ' ')) do inc(lPos); if lPos > lLen then exit; lStr := ''; repeat lStr := lStr+upcase(linStr[lPos]); inc(lPos); until (lPos > lLen) or (lInStr[lPos] = kTab) or (lInStr[lPos] = ' '); if lStr <> '' then begin //string to convert try case n of 1: lF1 := strtofloat(lStr); 2: lF2 := strtofloat(lStr); 3: lF3 := strtofloat(lStr); end; except on EConvertError do begin dcmMsg('Unable to convert the string '+lfStr+' to a real number'); exit; end; end; {except} end; //if string to convert end; end; procedure readVBints (var lI1,lI2,lI3: integer); var lF1,lF2,lF3: double; begin readVBfloats (lF1,lF2,lF3); lI1 := round(lF1); lI2 := round(lF2); lI3 := round(lF3); end; function readVBStr:string; var lStr: string; begin lStr := ''; While (lPos <= lLen) and ((lInStr[lPos] = kTab) or (lInStr[lPos] = ' ')) do begin inc(lPos); end; While (lPos <= lLen) {and (lInStr[lPos] <> ';')} do begin lStr := lStr+upcase(linStr[lPos]); //zebra upcase inc(lPos); end; result := lStr; end; //interstr func begin lHdrOK := false; lFloat := false; lImageFormatOK := true; Clear_Dicom_Data(lDicomData); lDynStr := ''; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FileSz := FileSize(fp); lHdrEnd := false; //lDicomData.ImageStart := FileSz; GetMem( lCharRA, FileSz+1 ); BlockRead(fp, lCharRA^, FileSz, linpos); if lInPos <> FileSz then dcmMsg('Disk error: Unable to read full input file.'); linPos := 1; CloseFile(fp); FileMode := 2; //set to read/write lFileTypeKnown := false; repeat linstr := ''; while (linPos < FileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin lInStr := lInstr + chr(lCharRA^[linPos]); inc(linPos); end; inc(lInPos); //read EOLN lLen := length(lInStr); lPos := 1; lUpcaseStr := ''; While (lPos <= lLen) and (lInStr[lPos] <> ':') do begin if lInStr[lPos] in ['[',']','(',')','/','+','-', '0'..'9','a'..'z','A'..'Z'] then lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]); inc(lPos); end; inc(lPos); {read equal sign in := statement} if (lHdrOK) and (not lFileTypeKnown) and (lUpCaseStr = 'CUB1') then lFileTypeKnown := true; if (lHdrOK) and (not lFileTypeKnown) then begin dcmMsg('This software can not read this kind of VoxBo image. (Type:"'+lUpCaseStr+'")'); lHdrEnd := true; lHdrOK := false; end; if (not lHdrOK) and (lUpCaseStr ='VB98') then begin lDicomData.little_endian := 0;//all VoxBo files are Big Endian! lStartPos := linPos; lFileTypeKnown := true; //test for While Loop while (linPos < FileSz) and lFileTypeKnown do begin if (lCharRA^[linPos-1] = $0C) and (lCharRA^[linPos] = $0A) then begin lFileTypeKnown := false; lDicomData.ImageStart := linPos; FileSz := linPos; //size of VoxBo header end; inc(linPos); end; if lFileTypeKnown then begin //end of file character not found: abort! dcmMsg('Unable to find the end of the VoxBo header.'); lHdrEnd := true end else lHdrOK := true; linPos := lStartPos; //now that we have found the header size, we can start from the beginning of the header end; if not lHdrOK then lHdrEnd := true; if (lUpCaseStr ='BYTEORDER') and (readVBStr = 'LSBFIRST') then lDicomData.little_endian := 1; if lUpCaseStr ='DATATYPE'then begin lTmpStr := readVBStr; if lTmpStr = 'Byte' then lDicomData.Allocbits_per_pixel := 8 else if (lTmpStr = 'INTEGER') or (lTmpStr = 'INT16') then lDicomData.Allocbits_per_pixel := 16 else if (lTmpStr = 'LONG') or (lTmpStr = 'INT32') then lDicomData.Allocbits_per_pixel := 32 else if (lTmpStr = 'FLOAT') then begin lFloat := true; lDicomData.Allocbits_per_pixel := 32; end else if (lTmpStr = 'DOUBLE') then begin lFloat := true; lDicomData.Allocbits_per_pixel := 64; end else begin dcmMsg('Unknown VoxBo data format: '+lTmpStr); end; end; if lUpCaseStr ='VOXDIMS(XYZ)'then readVBints(lDicomData.XYZdim[1],lDicomData.XYZdim[2],lDicomData.XYZdim[3]); if (lUpCaseStr ='VOXSIZES(XYZ)') then readVBfloats(lDicomData.XYZmm[1],lDicomData.XYZmm[2],lDicomData.XYZmm[3]); if (lUpCaseStr ='ORIGIN(XYZ)')then begin readVBints(lDicomData.XYZori[1],lDicomData.XYZori[2],lDicomData.XYZori[3]); inc(lDicomData.XYZori[1]);//1393 inc(lDicomData.XYZori[2]);//1393 inc(lDicomData.XYZori[3]);//1393 end; if not lHdrOK then goto 333; if lInStr <> '' then lDynStr := lDynStr + lInStr+kCr; until (linPos >= FileSz) or (lHdrEnd){EOF(fp)}; //xlDicomData.Storedbits_per_pixel := lDicomData.Allocbits_per_pixel; //xlDicomData.Rotate180deg := true; lImageFormatOK := true; if (lFloat) then begin //zebra change float check lDicomData.FloatData := true; //lImageFormatOK := false; end; 333: FreeMem( lCharRA); end; //voxbo end procedure read_vff_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string); label 333; const UNIXeoln = chr(10); var lInStr,lUpCaseStr: string; //lHdrEnd: boolean; lPos,lLen,FileSz,linPos: integer; lDummy1,lDummy2,lDummy3 : double; fp: file; lCharRA: bytep; procedure readVFFvals (var lFloat1,lFloat2,lFloat3: double); var lStr: string; lDouble: DOuble; lInc: integer; begin for lInc := 1 to 3 do begin lStr := ''; While (lPos <= lLen) and (lInStr[lPos] = ' ') do begin inc(lPos); end; While (lPos <= lLen) and (lInStr[lPos] <> ';') and (lInStr[lPos] <> ' ') do begin if lInStr[lPos] in ['+','-','e','E','.','0'..'9'] then lStr := lStr+(linStr[lPos]); inc(lPos); end; if lStr <> '' then begin try lDouble := strtofloat(lStr); except on EConvertError do begin dcmMsg('Unable to convert the string '+lStr+' to a number'); exit; end; end; {except} case lInc of 2: lFloat2 := lDouble; 3: lFloat3 := lDouble; else lFloat1 := lDouble; end; end; //lStr <> '' end; //lInc 1..3 end; //interstr func begin lHdrOK := false; lImageFormatOK := true; Clear_Dicom_Data(lDicomData); lDicomData.little_endian := 0; //big-endian lDynStr := ''; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FileSz := FileSize(fp); if FileSz > 2047 then FileSz := 2047; GetMem( lCharRA, FileSz+1 ); BlockRead(fp, lCharRA^, FileSz, linpos); if lInPos <> FileSz then dcmMsg('Disk error: Unable to read full input file.'); lInPos := 1; while (lCharRA^[lInPos] <> 12) and (lInPos < FileSz) do begin inc(lInPos); end; inc(lInPos); if (lInPos >= FileSz) or (lInPos < 12) then goto 333; //unable to find lDynStr := lDynStr + 'Sun VFF Volume File Format'+kCr; lDicomData.ImageStart := lInPos; FileSz := lInPos-1; linPos := 1; CloseFile(fp); FileMode := 2; //set to read/write repeat linstr := ''; while (linPos < FileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin lInStr := lInstr + chr(lCharRA^[linPos]); inc(linPos); end; inc(lInPos); //read EOLN lLen := length(lInStr); lPos := 1; lUpcaseStr := ''; While (lPos <= lLen) and (lInStr[lPos] <> ';') and (lInStr[lPos] <> '=') and (lUpCaseStr <>'NCAA') do begin if lInStr[lPos] in ['[',']','(',')','/','+','-',{' ',} '0'..'9','a'..'z','A'..'Z'] then lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]); inc(lPos); end; inc(lPos); {read equal sign in := statement} if lUpCaseStr ='NCAA' then begin lHdrOK := true; end; if lUpCaseStr ='BITS' then begin lDummy1 := 8; readVFFvals(lDummy1,lDummy2,lDummy3); lDicomData.Allocbits_per_pixel := round(lDummy1); end; if lUpCaseStr ='SIZE' then begin lDummy1 := 1; lDummy2 := 1; lDummy3 := 1; readVFFvals(lDummy1,lDummy2,lDummy3); lDicomData.XYZdim[1] := round(lDummy1); lDicomData.XYZdim[2] := round(lDummy2); lDicomData.XYZdim[3] := round(lDummy3); end; if lUpCaseStr ='ASPECT' then begin lDummy1 := 1; lDummy2 := 1; lDummy3 := 1; readVFFvals(lDummy1,lDummy2,lDummy3); lDicomData.XYZmm[1] := (lDummy1); lDicomData.XYZmm[2] := (lDummy2); lDicomData.XYZmm[3] := (lDummy3); end; if not lHdrOK then goto 333; if lInStr <> '' then lDynStr := lDynStr + lInStr+kCr; //lHdrOK := true; until (linPos >= FileSz); //xlDicomData.Storedbits_per_pixel := lDicomData.Allocbits_per_pixel; lImageFormatOK := true; 333: FreeMem( lCharRA); end; //******************************************************************** (*procedure ShellSortItems (first, last: integer; var lPositionRA, lIndexRA: LongintP; var lRepeatedValues: boolean); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n,t, nn, m, lognb2, l, k, j, i: longint; begin lRepeatedValues := false; n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 1 to k do begin i := j; 555: {<- LABEL} l := i + m; if (lIndexRA^[lPositionRA^[l]] = lIndexRA^[lPositionRA^[i]]) then begin lRepeatedValues := true; exit; end; if (lIndexRA^[lPositionRA^[l]] < lIndexRA^[lPositionRA^[i]]) then begin //swap values for i and l t := lPositionRA^[i]; lPositionRA^[i] := lPositionRA^[l]; lPositionRA^[l] := t; i := i - m; if (i >= 1) then goto 555; end end end end; //shellsort is fast and requires less memory than quicksort *) (*procedure PAR2DICOMstudyDate(var lDicomData: DICOMdata); {input: lDicomData.StudyDate = 2002.12.29 / 19:48:58.0000 output: StudyDate = YYYYMMDD StudyTime= hhmmss } var I: integer; lStr: string; begin if length(lDicomData.StudyDate) < 14 then exit; lStr := ''; for I := 1 to length(lDicomData.StudyDate) do if lDicomData.StudyDate[I] in ['0'..'9'] then lStr := lStr+ lDicomData.StudyDate[I]; if length(lStr) < 14 then exit; lDicomData.StudyDate := ''; for I := 1 to 8 do lDicomData.StudyDate := lDicomData.StudyDate+lStr[I]; lDicomData.StudyTime := ''; for I := 9 to 14 do lDicomData.StudyTime := lDicomData.StudyTime+lStr[I]; lDicomData.PatientIDInt := StudySecSince2K(lDicomData.StudyDate,lDicomData.StudyTime); end; type tRange = record Min,Val,Max: double; //some vals are ints, others floats end; procedure read_PAR_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK:boolean; var lDynStr: string;var lFileName: string; lReadOffsetTables: boolean; var lOffset_pos_table: LongIntp; var lOffsetTableEntries: integer; lReadVaryingScaleFactors: boolean; var lVaryingScaleFactors_table,lVaryingIntercept_table: Singlep; var lVaryingScaleFactorsTableEntries,lnum4Ddatasets: integer); label 333; //1384 now reads up to 8 dimensional data.... const UNIXeoln = chr(10); kMaxnSLices = 32000; kXdim = 1; kYdim = 2; kBitsPerVoxel = 3; kSliceThick = 4; kSliceGap = 5; kXmm = 6; kYmm = 7; kSlope = 8; kIntercept = 9; kCalibratedSlope = 10; //1393 - attempt to use calibrated values kDynTime = 11; kSlice = 12; kEcho = 13; kDyn = 14; kCardiac = 15; kType = 16; kSequence = 17; kIndex = 18; lIsParVers3x: boolean = true; lRepeatedValues : boolean = false; lSlicesNotInSequence: boolean = false; lMaxSlice : integer = 0; var lErrorStr,lInStr,lUpCaseStr,lReportedTRStr: string; lSliceSequenceRA,lSortedSliceSequence: LongintP; lSliceIndexRA: array [1..kMaxnSlices] of Longint; lSliceSlopeRA,lSliceInterceptRA,lCalibratedSliceSlopeRA: array [1..kMaxnSlices] of single; lSliceHeaderRA: array [1..32] of double; lRangeRA: array [kXdim..kIndex] of tRange; lMaxIndex,lSliceSz,lSliceInfoCount,lPos,lLen,lFileSz,lHdrPos,linPos,lInc: LongInt; fp: file; lCharRA: bytep; procedure MinMaxTRange (var lDimension: tRange; lNewVal: double); //nested begin lDimension.Val := lNewVal; if lSliceInfoCount < 2 then begin lDimension.Min := lDimension.Val; lDimension.Max := lDimension.Val; end; if lNewVal < lDimension.Min then lDimension.Min := lNewVal; if lNewVal > lDimension.Max then lDimension.Max := lNewVal; end; //nested InitTRange proc function readParStr:string;//nested var lStr: string; begin lStr := ''; While (lPos <= lLen) do begin if (lStr <> '') or (linStr[lPos]<>' ') then //strip leading spaces lStr := lStr+(linStr[lPos]); inc(lPos); end; //while lPOs < lLen result := lStr; end; //nested func ReadParStr function readParFloat:double;//nested var lStr: string; begin lStr := ''; result := 1; While (lPos <= lLen) and ((lStr='') or(lInStr[lPos] <> ' ')) do begin if lInStr[lPos] in ['+','-','e','E','.','0'..'9'] then lStr := lStr+(linStr[lPos]); inc(lPos); end; if lStr = '' then exit; try result := strtofloat(lStr); except on EConvertError do begin dcmMsg('read_PAR_data: Unable to convert the string '+lStr+' to a number'); result := 1; exit; end; end; {except} end; //nested func ReadParFloat begin //Initialize parameters lnum4Ddatasets := 1; lSliceInfoCount := 0; for lInc := kXdim to kIndex do //initialize all values: important as PAR3 will not explicitly report all MinMaxTRange(lRangeRA[lInc],0); lHdrOK := false; lImageFormatOK := false; lIsParVers3x := true; lOffsetTableEntries := 0; lVaryingScaleFactorsTableEntries := 0; Clear_Dicom_Data(lDicomData); lDynStr := ''; //Read text header to buffer (lCharRA) FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); lFileSz := FileSize(fp); GetMem( lCharRA, lFileSz+1 ); //note: must free dynamic memory: goto 333 if any error GetMem (lSliceSequenceRA, kMaxnSLices*sizeof(longint)); //note: must free dynamic memory: goto 333 if any error BlockRead(fp, lCharRA^, lFileSz, lInpos); if lInPos <> lFileSz then begin dcmMsg('read_PAR_data: Disk error, unable to read full input file.'); goto 333; end; linPos := 1; CloseFile(fp); FileMode := 2; //set to read/write //Next: read each line of header file... repeat //for each line in file.... linstr := ''; while (linPos < lFileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin lInStr := lInstr + chr(lCharRA^[linPos]); inc(linPos); end; inc(lInPos); //read EOLN lLen := length(lInStr); lPos := 1; lUpcaseStr := ''; if lLen < 1 then //ignore blank lines else if (lInStr[1] = '*') and (not lHdrOK) then //# -> comment //ignore comment lines prior to start of header else if (lInStr[1] = '#') and (lHdrOK) then //# -> comment //ignore comment lines else if (lInStr[1] = '.') or (not lHdrOK) then begin // GENERAL_INFORMATION section (line starts with '.') //Note we also read in lines that do not have '.' if we have HdrOK=false, this allows us to detect the DATADESCRIPTIONFILE signature While (lPos <= lLen) and (lInStr[lPos] <> ':') and ((not lHdrOK) or (lInStr[lPos] <> '#')) do begin if lInStr[lPos] in ['[',']','(',')','/','+','-',{' ',} '0'..'9','a'..'z','A'..'Z'] then lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]); inc(lPos); end; //while reading line inc(lPos); {read equal sign in := statement} lDynStr := lDynStr + lInStr+kCR; if (not lHdrOK) and (lUpcaseStr = ('DATADESCRIPTIONFILE')) then begin //1389 PAR file lHdrOK := true; lDicomData.little_endian := 1; end; if (lUpCaseStr ='REPETITIONTIME[MSEC]') then lDicomData.TR := round(readParFloat); if (lUpCaseStr ='MAXNUMBEROFSLICES/LOCATIONS') then lDicomData.XYZdim[3] := round(readParFloat); if (lUpCaseStr ='SLICETHICKNESS[MM]') then MinMaxTRange(lRangeRA[kSliceThick],readParFloat); if (lUpCaseStr ='SLICEGAP[MM]') then MinMaxTRange(lRangeRA[kSliceGap],readParFloat); if lUpCaseStr = 'RECONRESOLUTION(XY)' then begin MinMaxTRange(lRangeRA[kXdim],readParFloat); MinMaxTRange(lRangeRA[kYdim],readParFloat); end; if lUpCaseStr = 'RECONSTRUCTIONNR' then lDicomData.AcquNum := round(readParFloat); if lUpCaseStr = 'ACQUISITIONNR' then lDicomData.SeriesNum := round(readParFloat); if lUpCaseStr = 'MAXNUMBEROFDYNAMICS' then begin lDicomData.XYZdim[4] := round(readParFloat); end; if lUpCaseStr = 'EXAMINATIONDATE/TIME' then begin lDicomData.StudyDate := readParStr; PAR2DICOMstudyDate(lDicomData); end; //if lUpCaseStr = 'PROTOCOLNAME' then // lDicomData.modality := readParStr; if lUpCaseStr = 'PATIENTNAME' then lDicomData.PatientName := readParStr; if lUpCaseStr ='IMAGEPIXELSIZE[8OR16BITS]' then begin MinMaxTRange(lRangeRA[kBitsPerVoxel],readParFloat); end; if not lHdrOK then begin dcmMsg('read_PAR_data: Error reading header'); goto 333; end; end else begin //SliceInfo: IMAGE_INFORMATION (line does NOT start with '.' or '#') inc(lSliceInfoCount); if (lSliceInfoCount < 2) and (lRangeRA[kBitsPerVoxel].val < 1) then //PARvers3 has imagedepth in general header, only in image header for later versions lIsParVers3x := false; for lHdrPos := 1 to 26 do lSliceHeaderRA[lHdrPos] := readparfloat; //The next few values are in the same location for both PAR3 and PAR4 MinMaxTRange(lRangeRA[kSlice], round(lSliceHeaderRA[1])); MinMaxTRange(lRangeRA[kEcho], round(lSliceHeaderRA[2])); MinMaxTRange(lRangeRA[kDyn], round(lSliceHeaderRA[3])); MinMaxTRange(lRangeRA[kCardiac], round(lSliceHeaderRA[4])); MinMaxTRange(lRangeRA[kType], round(lSliceHeaderRA[5])); MinMaxTRange(lRangeRA[kSequence], round(lSliceHeaderRA[6])); MinMaxTRange(lRangeRA[kIndex], round(lSliceHeaderRA[7])); if lIsParVers3x then begin //Read PAR3 data MinMaxTRange(lRangeRA[kIntercept], lSliceHeaderRA[8]);; //8=intercept in PAR3 MinMaxTRange(lRangeRA[kSlope],lSliceHeaderRA[9]); //9=slope in PAR3 MinMaxTRange(lRangeRA[kCalibratedSlope],lSliceHeaderRA[10]); //10=lcalibrated slope in PAR3 1393 - attempt to use calibrated values MinMaxTRange(lRangeRA[kXmm],lSliceHeaderRA[23]); //23 PIXEL SPACING X in PAR3 MinMaxTRange(lRangeRA[kYmm],lSliceHeaderRA[24]); //24 PIXEL SPACING Y IN PAR3 MinMaxTRange(lRangeRA[kDynTime],(lSliceHeaderRA[26])); //26= dyn_scan_begin_time in PAR3 end else begin //not PAR: assume PAR4 for lHdrPos := 27 to 32 do lSliceHeaderRA[lHdrPos] := readparfloat; MinMaxTRange(lRangeRA[kBitsPerVoxel],lSliceHeaderRA[8]);//8 BITS in PAR4 MinMaxTRange(lRangeRA[kXdim], lSliceHeaderRA[10]); //10 XDim in PAR4 MinMaxTRange(lRangeRA[kYdim], lSliceHeaderRA[11]); //11 YDim in PAR4 MinMaxTRange(lRangeRA[kIntercept],lSliceHeaderRA[12]); //12=intercept in PAR4 MinMaxTRange(lRangeRA[kSlope],lSliceHeaderRA[13]); //13=lslope in PAR4 MinMaxTRange(lRangeRA[kCalibratedSlope],lSliceHeaderRA[14]); //14=lcalibrated slope in PAR4 1393 - attempt to use calibrated values MinMaxTRange(lRangeRA[kSliceThick],lSliceHeaderRA[23]);//23 SLICE THICK in PAR4 MinMaxTRange(lRangeRA[kSliceGap], lSliceHeaderRA[24]); //24 SLICE GAP in PAR4 MinMaxTRange(lRangeRA[kXmm],lSliceHeaderRA[29]); //29 PIXEL SPACING X in PAR4 MinMaxTRange(lRangeRA[kYmm],lSliceHeaderRA[30]); //30 PIXEL SPACING Y in PAR4 MinMaxTRange(lRangeRA[kDynTime],(lSliceHeaderRA[32]));//32= dyn_scan_begin_time in PAR4 end; //PAR4 if lSliceInfoCount < kMaxnSlices then begin lSliceSequenceRA^[lSliceInfoCount] := ( (round(lRangeRA[kSequence].val)+round(lRangeRA[kType].val)+round(lRangeRA[kCardiac].val+lRangeRA[kEcho].val)) shl 24)+(round(lRangeRA[kDyn].val) shl 10)+round(lRangeRA[kSlice].val); lSliceSlopeRA [lSliceInfoCount] := lRangeRA[kSlope].Val; lCalibratedSliceSlopeRA [lSliceInfoCount] := lRangeRA[kCalibratedSlope].Val; lSliceInterceptRA [lSliceInfoCount] := lRangeRA[kIntercept].val; lSliceIndexRA[lSliceInfoCount]:= round(lRangeRA[kIndex].val); end; end; //SliceInfo Line until (linPos >= lFileSz);//until done reading entire file... //describe generic DICOM parameters lDicomData.XYZdim[1] := round(lRangeRA[kXdim].Val); lDicomData.XYZdim[2] := round(lRangeRA[kYdim].Val); lDicomData.XYZdim[3] := 1+round(lRangeRA[kSlice].Max-lRangeRA[kSlice].Min); if (lSliceInfoCount mod lDicomData.XYZdim[3]) <> 0 then dcmMsg('read_PAR_data: Total number of slices not divisible by number of slices per volume. Reconstruction error?'); if lDicomData.XYZdim[3] > 0 then lDicomData.XYZdim[4] := lSliceInfoCount div lDicomData.XYZdim[3] //nVolumes = nSlices/nSlicePerVol else lDicomData.XYZdim[4] := 1; lDicomData.XYZmm[1] := lRangeRA[kXmm].Val; lDicomData.XYZmm[2] := lRangeRA[kYmm].Val; lDicomData.XYZmm[3] := lRangeRA[kSliceThick].Val+lRangeRA[kSliceGap].Val; lDicomData.Allocbits_per_pixel := round(lRangeRA[kBitsPerVoxel].Val); lDicomData.IntenScale := lRangeRA[kSlope].Val; lDicomData.IntenIntercept := lRangeRA[kIntercept].Val; if gPARprecise then begin if (lDicomData.IntenIntercept <> 0) or (lRangeRA[kCalibratedSlope].val = 0) then dcmMsg('Warning: Unable to save calibrated Philips image intensity (non-zero scaling intercept). Turn off Etc/Options/CalibratedScaling to hide warning.'); if (lRangeRA[kSlope].min = lRangeRA[kSlope].max) and (lRangeRA[kIntercept].min = lRangeRA[kIntercept].max) and (lRangeRA[kCalibratedSlope].min = lRangeRA[kCalibratedSlope].max) and (lDicomData.IntenIntercept = 0) and (lRangeRA[kCalibratedSlope].val <> 0) then lDicomData.IntenScale := 1 / lRangeRA[kCalibratedSlope].val; end; //if PARprecise //Next: report number of Dynamic scans, this allows people to parse DynScans from Type/Cardiac/Echo/Sequence 4D files lnum4Ddatasets := (round(lRangeRA[kDyn].Max - lRangeRA[kDyn].Min)+1)*lDicomData.XYZdim[3]; //slices in each dynamic session if ((lSliceInfoCount mod lnum4Ddatasets) = 0) and ((lSliceInfoCount div lnum4Ddatasets) > 1) then lnum4Ddatasets := (lSliceInfoCount div lnum4Ddatasets) //infer multiple Type/Cardiac/Echo/Sequence else lnum4Ddatasets := 1; //next: Determine actual interscan interval if (lDicomData.XYZdim[4] > 1) and ((lRangeRA[kDynTime].max-lRangeRA[kDynTime].min)> 0) {1384} then begin lReportedTRStr := 'Reported TR: '+floattostrf(lDicomData.TR,ffFixed,8,2)+kCR; lDicomData.TR := (lRangeRA[kDynTime].max-lRangeRA[kDynTime].min) /(lDicomData.XYZdim[4] - 1)*1000; //infer TR in ms end else lReportedTRStr :=''; //next: report header details lDynStr := 'Philips PAR/REC Format' //'PAR/REC Format' +kCR+ 'Patient name:'+lDicomData.PatientName +kCR+ 'XYZ dim: ' +inttostr(lDicomData.XYZdim[1])+'/'+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'Volumes: ' +inttostr(lDicomData.XYZdim[4]) +kCR+'XYZ mm: '+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2) +kCR+'TR: '+floattostrf(lDicomData.TR,ffFixed,8,2) +kCR+lReportedTRStr+kCR+lDynStr; //if we get here, the header is fine, next steps will see if image format is readable... lHdrOK := true; if lSliceInfoCount < 1 then goto 333; //next: see if slices are in sequence lSlicesNotInSequence := false; if lSliceInfoCount > 1 then begin lMaxSlice := lSliceSequenceRA^[1]; lMaxIndex := lSliceIndexRA[1]; lInc := 1; repeat inc(lInc); if lSliceSequenceRA^[lInc] < lMaxSlice then //not in sequence if image has lower slice order than previous image lSlicesNotInSequence := true else lMaxSlice := lSliceSequenceRA^[lInc]; if lSliceIndexRA[lInc] < lMaxIndex then //not in sequence if image has lower slice index than previous image lSlicesNotInSequence := true else lMaxIndex := lSliceIndexRA[lInc]; until (lInc = lSliceInfoCount) or (lSlicesNotInSequence); end; //at least 2 slices //Next: report any errors lErrorStr := ''; if (lSlicesNotInSequence) and (not lReadOffsetTables) then lErrorStr := lErrorStr + ' Slices not saved sequentially [using MRIcro''s ''Philips PAR to Analyze'' command may solve this]'+kCR; if lSliceInfoCount > kMaxnSlices then lErrorStr := lErrorStr + ' Too many slices: >'+inttostr(kMaxnSlices)+kCR; if (not lReadVaryingScaleFactors) and ( (lRangeRA[kSlope].min <> lRangeRA[kSlope].max) or (lRangeRA[kIntercept].min <> lRangeRA[kIntercept].max)) then lErrorStr := lErrorStr + ' Differing intensity slope/intercept [using MRIcro''s ''Philips PAR to Analyze'' command may solve this]'+kCR; if (lRangeRA[kBitsPerVoxel].min <> lRangeRA[kBitsPerVoxel].max) then //5D file space+time+cardiac lErrorStr := lErrorStr + ' Differing bits per voxel'+kCR; //if (lRangeRA^[kCardiac].min <> lRangeRA^[kCardiac].max) then //5D file space+time+cardiac // lErrorStr := lErrorStr + 'Multiple cardiac timepoints'+kCR; //if (lRangeRA^[kEcho].min <> lRangeRA^[kEcho].max) then //5D file space+time+echo // lErrorStr := lErrorStr + 'Multiple echo timepoints'+kCR; if (lRangeRA[kSliceThick].min <> lRangeRA[kSliceThick].max) or (lRangeRA[kSliceGap].min <> lRangeRA[kSliceGap].max) or (lRangeRA[kXdim].min <> lRangeRA[kXdim].max) or (lRangeRA[kYDim].min <> lRangeRA[kYDim].max) or (lRangeRA[kXmm].min <> lRangeRA[kXmm].max) or (lRangeRA[kYmm].min <> lRangeRA[kYmm].max) then lErrorStr := lErrorStr + ' Multiple/varying slice dimensions'+kCR; //if any errors were encountered, report them.... if lErrorStr <> '' then begin dcmMsg('read_PAR_data: This software can not convert this Philips data:'+kCR+lErrorStr); goto 333; end; //Next sort image indexes here... if (lSliceInfoCount > 1) and(lSlicesNotInSequence) and ( lReadOffsetTables) then begin //sort image order... //ShellSort (first, last: integer; var lPositionRA, lIndexLoRA,lIndexHiRA: LongintP; var lRepeatedValues: boolean) GetMem (lOffset_pos_table, lSliceInfoCount*sizeof(longint)); for lInc := 1 to lSliceInfoCount do lOffset_pos_table^[lInc] := lInc; ShellSortItems (1, lSliceInfoCount,lOffset_pos_table,lSliceSequenceRA, lRepeatedValues); if lRepeatedValues then begin dcmMsg('read_PAR_data: fatal error, slices do not appear to have unique indexes [multiple copies of same slice]'); FreeMem (lOffset_pos_table); goto 333; end; lOffsetTableEntries := lSliceInfoCount; end; //sort image order... //Next, generate list of scale slope if (lSliceInfoCount > 1) and (lReadVaryingScaleFactors) and ( (lRangeRA[kSlope].min <> lRangeRA[kSlope].max) or (lRangeRA[kIntercept].min <> lRangeRA[kIntercept].max)) then begin {create offset LUT} lVaryingScaleFactorsTableEntries := lSliceInfoCount; getmem (lVaryingScaleFactors_table, lVaryingScaleFactorsTableEntries*sizeof(single)); getmem (lVaryingIntercept_table, lVaryingScaleFactorsTableEntries*sizeof(single)); if lOffsetTableEntries = lSliceInfoCount then begin //need to sort slices for lInc := 1 to lSliceInfoCount do begin lVaryingScaleFactors_table^[lInc] := lSliceSlopeRA[lOffset_pos_table^[lInc]]; lVaryingIntercept_table^[lInc] := lSliceInterceptRA[lOffset_pos_table^[lInc]]; if gPARprecise then begin if (lVaryingIntercept_table^[lInc] <> 0) or (lCalibratedSliceSlopeRA[lOffset_pos_table^[lInc]]=0) then dcmMsg('Warning: Unable to save calibrated Philips image intensity (non-zero scaling intercept). Turn off Etc/Options/CalibratedScaling to hide warning.') else begin lVaryingScaleFactors_table^[lInc] := 1 / lCalibratedSliceSlopeRA[lOffset_pos_table^[lInc]]; end; end; //if PARprecise end; end else begin //if sorted, else unsorted for lInc := 1 to lSliceInfoCount do begin lVaryingScaleFactors_table^[lInc] := lSliceSlopeRA[lInc]; lVaryingIntercept_table^[lInc] := lSliceInterceptRA[lInc]; if gPARprecise then begin if (lVaryingIntercept_table^[lInc] <> 0) or (lCalibratedSliceSlopeRA[lInc]=0) then dcmMsg('Warning: Unable to save calibrated Philips image intensity (non-zero scaling intercept). Turn off Etc/Options/CalibratedScaling to hide warning.') else lVaryingScaleFactors_table^[lInc] := 1 / lCalibratedSliceSlopeRA[lInc]; end; //if PARprecise end; end; //slices sorted end;//read scale factors //Next: now adjust Offsets to point to byte offset instead of slice number lSliceSz := lDicomData.XYZdim[1]*lDicomData.XYZdim[2]*(lDicomData.Allocbits_per_pixel div 8); if lOffsetTableEntries = lSliceInfoCount then for lInc := 1 to lSliceInfoCount do lOffset_pos_table^[lInc] := lSliceSz * (lSliceIndexRA[lOffset_pos_table^[lInc]]); //report if 5D/6D/7D file is being saved as 4D if (lRangeRA[kCardiac].min <> lRangeRA[kCardiac].max) or (lRangeRA[kEcho].min <> lRangeRA[kEcho].max) //5D file space+time+echo or (lRangeRA[kType].min <> lRangeRA[kType].max) //5D file space+time+echo or (lRangeRA[kSequence].min <> lRangeRA[kSequence].max) then //5D file space+time+echo dcmMsg('Warning: note that this image has more than 4 dimensions (multiple Cardiac/Echo/Type/Sequence)'); //if we get here, the Image Format is OK lImageFormatOK := true; lFileName := changefileextX(lFilename,'.rec'); //for Linux: case sensitive extension search '.rec' <> '.REC' 333: //abort clause: skips lHdrOK and lImageFormatOK //next: free dynamically allocated memory FreeMem( lCharRA); FreeMem (lSliceSequenceRA); end; *) procedure read_ge_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); label 539; var lGap,lSliceThick,lTempFloat: single; lTemp16,lI: word; lSeriesOffset,lTemp32,lExamHdr,lImgHdr,lDATFormatOffset,lHdrOffset,lCompress,linitialoffset,n,filesz: LongInt; tx : array [0..36] of Char; FP: file; lGEodd,lGEFlag,{lSpecial,}lMR: boolean; function GEflag: boolean; begin if (tx[0] = 'I') AND (tx[1]= 'M') AND (tx[2] = 'G')AND (tx[3]= 'F') then result := true else result := false; end; function swap16i(lPos: longint): word; var w : Word; begin seek(fp,lPos-2); BlockRead(fp, W, 2); result := swap(W); end; function swap32i(lPos: longint): Longint; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(Long:LongInt); end; swaptypep = ^swaptype; var s : LongInt; inguy:swaptypep; outguy:swaptype; begin seek(fp,lPos); BlockRead(fp, s, 4, n); inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); swap32i:=outguy.Long; end; function fswap4r (lPos: longint): single; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(float:single); end; swaptypep = ^swaptype; var s:single; inguy:swaptypep; outguy:swaptype; begin seek(fp,lPos); BlockRead(fp, s, 4, n); inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); fswap4r:=outguy.float; end; begin lImageFormatOK := true; lSeriesOffset := 0; lSLiceThick := 0; lGap := 0; lHdrOK := false; lHdrOffset := 0; if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FIleSz := FileSize(fp); lDATFormatOffset := 0; Clear_Dicom_Data(lDicomData); if filesz < (3240) then begin dcmMsg('This file is too small to be a Genesis DAT format image.'); goto 539; end; lDynStr:= ''; //lGEFlag := false; lInitialOffset := 3228;//3240; seek(fp, lInitialOffset); BlockRead(fp, tx, 4*SizeOf(Char), n); lGEflag := GEFlag; if not lGEFlag then begin lInitialOffset := 3240; seek(fp, lInitialOffset); BlockRead(fp, tx, 4*SizeOf(Char), n); lGEflag := GEFlag; end; lGEodd := lGEFlag; if not lGEFlag then begin lInitialOffset := 0; seek(fp, lInitialOffset); BlockRead(fp, tx, 4*SizeOf(Char), n); if not GEflag then begin {DAT format} lDynStr := lDynStr+'GE Genesis Signa DAT tape format'+kCR; seek(fp,114); BlockRead(fp, tx, 4*SizeOf(Char), n); lDynStr := lDynStr + 'Suite: '; for lI := 0 to 3 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; seek(fp,114+97); BlockRead(fp, tx, 25*SizeOf(Char), n); lDynStr := lDynStr + 'Patient Name: '; for lI := 0 to 24 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; seek(fp,114+84); BlockRead(fp, tx, 13*SizeOf(Char), n); lDynStr := lDynStr + 'Patient ID: '; for lI := 0 to 12 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; seek(fp, 114+305); BlockRead(fp, tx, 3*SizeOf(Char), n); if (tx[0]='M') and (tx[1] = 'R') then lMR := true else if (tx[0] = 'C') and(tx[1] = 'T') then lMR := false else begin dcmMsg('Is this a Genesis DAT image? The modality is '+tx[0]+tx[1]+tx[3] +'. Expected ''MR'' or ''CT''.'); goto 539; end; if lMR then lInitialOffset := 3180 else lInitialOffset := 3178; seek(fp, lInitialOffset); BlockRead(fp, tx, 4*SizeOf(Char), n); if (tx[0] <> 'I') OR (tx[1] <> 'M') OR (tx[2] <> 'G') OR (tx[3] <> 'F') then begin dcmMsg('This image does not have the required label ''IMGF''. This is not a Genesis DAT image.'); goto 539; end else lDicomData.ImageNum := swap16i(2158+12); lDicomData.XYZmm[3] := fswap4r (2158+26);// slice thickness mm lDicomData.XYZmm[1] := fswap4r (2158+50);// pixel size- X lDicomData.XYZmm[2] := fswap4r (2158+54);//pixel size - Y lSliceThick := lDicomData.XYZmm[3]; lGap := fswap4r (lHdrOffset+118);//1410 gap thickness mm if lGap > 0 then lDicomData.XYZmm[3] := lDicomData.XYZmm[3] + lGap; lDATFormatOffset := 4; if lMR then begin lTemp32 := swap32i(2158+194); lDynStr := lDynStr +'TR[usec]: '+inttostr(lTemp32) + kCR; lTemp32 := swap32i(2158+198); lDynStr := lDynStr +'TInvert[usec]: '+inttostr(lTemp32) + kCR; lTemp32 := swap32i(2158+202); lDynStr := lDynStr +'TE[usec]: '+inttostr(lTemp32) + kCR; lTemp16 := swap16i(2158+210); lDynStr := lDynStr +'Number of echoes: '+inttostr(lTemp16) + kCR; lTemp16 := swap16i(2158+212); lDynStr := lDynStr +'Echo: '+inttostr(lTemp16) + kCR; lTempFloat := fswap4r (2158+50); //not sure why I changed this to 50... 218 in Clunie's Description lDynStr := lDynStr +'NEX: '+floattostr(lTempFloat) + kCR; seek(fp,2158+308); BlockRead(fp, tx, 33*SizeOf(Char), n); lDynStr := lDynStr + 'Sequence: '; for lI := 0 to 32 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; seek(fp,2158+362); BlockRead(fp, tx, 17*SizeOf(Char), n); lDynStr := lDynStr + 'Coil: '; for lI := 0 to 16 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; end; end; {DAT format} end; lDicomData.ImageStart := lDATFormatOffset+linitialoffset + swap32i(linitialoffset+4);//byte displacement to image data lDicomData.XYZdim[1] := swap32i(linitialoffset+8); //width lDicomData.XYZdim[2] := swap32i(linitialoffset+12);//height lDicomData.Allocbits_per_pixel := swap32i(linitialoffset+16);//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; lCompress := swap32i(linitialoffset+20); //compression lExamHdr := swap32i(linitialoffset+136); lImgHdr := swap32i(linitialoffset+152); if (lImgHdr = 0) and (lDicomData.ImageStart = 8432) then begin lDicomData.ImageNum := swap16i(2310+12); lDicomData.XYZmm[3] := fswap4r (2310+26);// slice thickness mm lDicomData.XYZmm[1] := fswap4r (2310+50);// pixel size- X lDicomData.XYZmm[2] := fswap4r (2310+54);//pixel size - Y lSliceThick := lDicomData.XYZmm[3]; lGap := fswap4r (lHdrOffset+118);//1410 gap thickness mm if lGap > 0 then lDicomData.XYZmm[3] := lDicomData.XYZmm[3] + lGap; end else if {(lSpecial = false) and} (lDATFormatOffset = 0) then begin lDynStr := lDynStr+'GE Genesis Signa format'+kCR; if (not lGEodd) and (lExamHdr <> 0) then begin lHdrOffset := swap32i(linitialoffset+132);//x132- int ptr to exam heade //Patient ID seek(fp,lHdrOffset+84); BlockRead(fp, tx, 13*SizeOf(Char), n); lDynStr := lDynStr + 'Patient ID: '; for lI := 0 to 12 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; //Patient Name seek(fp,lHdrOffset+97); BlockRead(fp, tx, 25*SizeOf(Char), n); lDynStr := lDynStr + 'Patient Name: '; for lI := 0 to 24 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; //Patient Age lI := swap16i(lHdrOffset+122); lDynStr := lDynStr+'Patient Age: '+inttostr(lI)+kCR; //Modality: MR or CT seek(fp,lHdrOffset+305); BlockRead(fp, tx, 3*SizeOf(Char), n); lDynStr := lDynStr + 'Type: '; for lI := 0 to 1 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; //Read series header lSeriesOffset := swap32i(linitialoffset+144);//read size of series header: only read if >0 if lSeriesOffset > 12 then begin lSeriesOffset := swap32i(linitialoffset+140);//read size of series header: only read if >0 lI := swap16i(lSeriesOffset+10); //lDynStr := lDynStr+'Series number: '+inttostr(lI)+kCR; lDicomData.SeriesNum := lI; end; //image data lHdrOffset := swap32i(linitialoffset+148);//x148- int ptr to image heade end; if lGEodd then lHdrOffset := 2158+28; if ((lHdrOffset +58) < FileSz) and (lImgHdr <> 0) then begin lDicomData.AcquNum := swap16i(lHdrOffset+12); //note SERIES not IMAGE number, despite what Clunies FAQ says lDicomData.ImageNum := swap16i(lHdrOffset+14); //this is IMAGEnum //lDynStr := lDynStr +'Image number: '+inttostr(lDicomData.ImageNum)+ kCR; lDicomData.XYZmm[3] := fswap4r (lHdrOffset{linitialoffset+lHdrOffset}+26);// slice thickness mm lDicomData.XYZmm[1] := fswap4r (lHdrOffset{linitialoffset+lHdrOffset}+50);// pixel size- X lDicomData.XYZmm[2] := fswap4r (lHdrOffset{linitialoffset+lHdrOffset}+54);//pixel size - Y lSliceThick := lDicomData.XYZmm[3]; lGap := fswap4r (lHdrOffset+118);//1410 gap thickness mm if lGap > 0 then lDicomData.XYZmm[3] := lDicomData.XYZmm[3] + lGap; end; end; if (lCompress = 3) or (lCompress = 4) then begin lImageFormatOK := false;//xlDicomData.GenesisCpt := true; lDynStr := lDynStr+'Compressed data'+kCR; end else ;//xlDicomData.GenesisCpt := false; if (lCompress = 2) or (lCompress = 4) then begin lImageFormatOK := false;//xlDicomData.GenesisPackHdr := swap32i(linitialoffset+64); lDynStr := lDynStr+'Packed data'+kCR; end else //xlDicomData.GenesisPackHdr := 0; lDynStr := lDynStr+'Series Number: '+inttostr(lDicomData.SeriesNum) +kCR+'Acquisition Number: '+inttostr(lDicomData.AcquNum) +kCR+'Image Number: '+inttostr(lDicomData.ImageNum) +kCR+'Slice Thickness/Gap: '+floattostrf(lSliceThick,ffFixed,8,2)+'/'+floattostrf(lGap,ffFixed,8,2) +kCR+'XYZ dim: ' +inttostr(lDicomData.XYZdim[1])+'/'+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'XYZ mm: '+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2); lHdrOK := true; 539: CloseFile(fp); FileMode := 2; //set to read/write end;//read_ge //start siemens procedure read_siemens_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); label 567; var lI: word; lYear,lMonth,lDay,n,filesz,lFullSz,lMatrixSz,lIHour,lIMin,lISec{,lAHour,lAMin,lASec}: LongInt; lFlipAngle,lGap,lSliceThick: double; tx : array [0..26] of Char; lMagField,lTE,lTR: double; lInstitution,lName, lID,lMinStr,lSecStr{,lAMinStr,lASecStr}: String; FP: file; function swap32i(lPos: longint): Longint; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(Long:LongInt); end; swaptypep = ^swaptype; var s : LongInt; inguy:swaptypep; outguy:swaptype; begin seek(fp,lPos); BlockRead(fp, s, 4, n); inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); swap32i:=outguy.Long; //swap32i:=inguy.Long; end; function fswap8r (lPos: longint): double; type swaptype = packed record case byte of 0:(Word1,Word2,Word3,Word4 : word); //word is 16 bit 1:(float:double); end; swaptypep = ^swaptype; var s:double; inguy:swaptypep; outguy:swaptype; begin seek(fp,lPos); BlockRead(fp, s, 8, n); inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word4); outguy.Word2 := swap(inguy^.Word3); outguy.Word3 := swap(inguy^.Word2); outguy.Word4 := swap(inguy^.Word1); fswap8r:=outguy.float; end; begin lImageFormatOK := true; lHdrOK := false; if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FIleSz := FileSize(fp); Clear_Dicom_Data(lDicomData); if filesz < (6144) then begin dcmMsg('This file is to small to be a Siemens Magnetom Vision image.'); goto 567; end; seek(fp, 96); BlockRead(fp, tx, 7*SizeOf(Char), n); if (tx[0] <> 'S') OR (tx[1] <> 'I') OR (tx[2] <> 'E') OR (tx[3] <> 'M') then begin {manufacturer is not SIEMENS} dcmMsg('Is this a Siemens Magnetom Vision image [Manufacturer tag should be ''SIEMENS''].'); goto 567; end; {manufacturer not siemens} seek(fp, 105); BlockRead(fp, Tx, 25*SizeOf(Char), n); lINstitution := ''; for lI := 0 to 24 do begin if tx[lI] in ['/','\','a'..'z','A'..'Z',' ','+','-','.',',','0'..'9'] then lINstitution := lINstitution + tx[lI]; end; seek(fp, 768); BlockRead(fp, Tx, 25*SizeOf(Char), n); lName := ''; for lI := 0 to 24 do begin if tx[lI] in ['/','\','a'..'z','A'..'Z',' ','+','-','.',',','0'..'9'] then lName := lName + tx[lI]; end; seek(fp, 795); BlockRead(fp, Tx, 12*SizeOf(Char), n); lID := ''; for lI := 0 to 11 do begin if tx[lI] in ['/','\','a'..'z','A'..'Z',' ','+','-','.',',','0'..'9'] then lID := lID + tx[lI]; end; lDicomData.ImageStart := 6144; lYear := swap32i(0); lMonth := swap32i(4); lDay := swap32i(8); lIHour := swap32i(68); lIMin := swap32i(72); lISec := swap32i(76); lDicomData.XYZmm[3] := fswap8r (1544); lMagField := fswap8r (2560); lTR := fswap8r (1560); lTE := fswap8r (1568); lDIcomData.AcquNum := swap32i(3212); lMatrixSz := swap32i(2864); lDicomData.SiemensSlices := swap32i(4004); //1366 //lFullSz := swap32i(4008); //lInterleaveIf4 := swap32i(2888); lFullSz := (2*lMatrixSz*lMatrixSz);//16bitdata if ((FileSz - 6144) mod lFullSz) = 0 then begin case ((FileSz-6144) div lFullSz) of 4: lFullSz := 2*lMatrixSz; 9: lFullSz := 3*lMatrixSz; 16: lFullSz := 4*lMatrixSz; 25: lFullSz := 5*lMatrixSz; 36: lFullSz := 6*lMatrixSz; 49: lFullSz := 7*lMatrixSz; 64: lFullSz := 8*lMatrixSz; else lFullSz := lMatrixSz; end; end else lFullSz := lMatrixSz; {3744/3752 are XY FOV in mm!} lDicomData.XYZdim[1] := lFullSz;//lMatrixSz; //width lDicomData.XYZdim[2] := lFullSz;//lMatrixSz;//height {5000/5008 are size in mm, but wrong for mosaics} if lMatrixSz <> 0 then begin lDicomData.XYZmm[2] := fswap8r (3744)/lMatrixSz; lDicomData.XYZmm[1] := fswap8r (3752)/lMatrixSz; if ((lDicomData.XYZdim[1] mod lMatrixSz)=0) then lDicomData.SiemensMosaicX := lDicomData.XYZdim[1] div lMatrixSz; if ((lDicomData.XYZdim[2] mod lMatrixSz)=0) then lDicomData.SiemensMosaicY := lDicomData.XYZdim[2] div lMatrixSz; if lDicomData.SiemensMosaicX < 1 then lDicomData.SiemensMosaicX := 1; //1366 if lDicomData.SiemensMosaicY < 1 then lDicomData.SiemensMosaicY := 1; //1366 end; lFlipAngle := fswap8r (2112); //1414 { lDicomData.XYZmm[2] := fswap8r (5000); lDicomData.XYZmm[1] := fswap8r (5008);} lSliceThick := lDicomData.XYZmm[3]; lGap := fswap8r (4136); //gap as ratio of slice thickness?!?! if {lGap > 0} (lGap=-1) or (lGap=-19222) then //1410: exclusion values: do not ask me why 19222: from John Ashburner else begin //lDicomData.XYZmm[3] := abs(lDicomData.XYZmm[3] * (1+lGap)); lGap := lDicomData.XYZmm[3] * (lGap); lDicomData.XYZmm[3] := abs(lDicomData.XYZmm[3] +lGap); end; lDicomData.Allocbits_per_pixel := 16;//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; //xlDicomData.GenesisCpt := false; //xlDicomData.GenesisPackHdr := 0; lMinStr := inttostr(lIMin); if length(lMinStr) = 1 then lMinStr := '0'+lMinStr; lSecStr := inttostr(lISec); if length(lSecStr) = 1 then lSecStr := '0'+lSecStr; lDynStr := 'Siemens Magnetom Vision Format'+kCR+'Name: '+lName+kCR+'ID: '+lID+kCR+'Institution: '+lInstitution+kCR+ 'Study DD/MM/YYYY: '+inttostr(lDay)+'/'+inttostr(lMonth)+'/'+inttostr(lYear)+kCR+ 'Image Hour/Min/Sec: '+inttostr(lIHour)+':'+lMinStr+':'+lSecStr+kCR+ //'Acquisition Hour/Min/Sec: '+inttostr(lAHour)+':'+lAMinStr+':'+lASecStr+kCR+ 'Magnetic Field Strength: '+ floattostrf(lMagField,ffFixed,8,2)+kCR+ 'Image index: '+inttostr(lDIcomData.AcquNum)+kCR+ 'Time Repitition/Echo [TR/TE]: '+ floattostrf(lTR,ffFixed,8,2)+'/'+ floattostrf(lTE,ffFixed,8,2)+kCR+ 'Flip Angle: '+ floattostrf(lFlipAngle,ffFixed,8,2)+kCR+ 'Slice Thickness/Gap: '+floattostrf(lSliceThick,ffFixed,8,2)+'/'+floattostrf(lGap,ffFixed,8,2)+kCR+ 'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3])+kCR+ 'XY matrix:' +inttostr(lDicomData.SiemensMosaicX)+'/' +inttostr(lDicomData.SiemensMosaicY)+kCR+ 'XYZ mm:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2); lHdrOK := true; //lDIcomData.AcquNum := 0; 567: CloseFile(fp); FileMode := 2; //set to read/write end; //end siemens //begin elscint procedure read_elscint_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); label 539; var //lExamHdr,lImgHdr,lDATFormatOffset,lHdrOffset, {lDate,}lI,lCompress,n,filesz: LongInt; tx : array [0..41] of Char; FP: file; function readStr(lPos,lLen: integer): string; var lStr: string; lStrInc: integer; begin seek(fp,lPos); BlockRead(fp, tx, lLen, n); lStr := ''; for lStrInc := 0 to (lLen-1) do lStr := lStr + tx[lStrInc]; result := lStr end; function read8ch(lPos: integer): char; begin seek(fp,40); BlockRead(fp, result, 1, n); //lDicomData.ImageNum := ord(tx[0]); end; procedure read16i(lPos: longint; var lVal: integer); var lInWord: word; begin seek(fp,lPos); BlockRead(fp, lInWord, 2); lVal := lInWord; end; procedure read32i(lPos: longint; var lVal: integer); var lInINt: integer; begin seek(fp,lPos); BlockRead(fp, lInINt, 4); lVal :=lInINt; end; begin lImageFormatOK := true; lHdrOK := false; if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FIleSz := FileSize(fp); Clear_Dicom_Data(lDicomData); if filesz < (3240) then begin dcmMsg('This file is too small to be a Elscint format image.'); goto 539; end; lDynStr:= ''; read16i(0, lI); if (lI <> 64206) then begin dcmMsg('Unable to read this file: it does start with the Elscint signature.'); goto 539; end; lDicomdata.little_endian := 1; lDynStr:= 'Elscint Format'+kCR; lDynStr := lDynStr+'Patient Name: '+readstr(4,20)+kCR; lDynStr := lDynStr+'Patient ID: '+readstr(24,13)+kCR; read16i(38,lDicomData.AcquNum); lDicomData.ImageNum := ord(read8Ch(40)); lDynStr := lDynStr+'Doctor & Ward: '+readstr(100,20)+kCR; lDynStr := lDynStr+'Comments: '+readstr(120,40)+kCR; if ord(read8Ch(163)) = 1 then lDynStr := lDynStr + 'Sex: M'+kCR else lDynStr := lDynStr + 'Sex: F'+kCR; read16i(200,lI); lDicomData.XYZmm[3] := lI * 0.1; read16i(370,lDicomData.XYZdim[1]); read16i(372,lDicomData.XYZdim[2]); read16i(374,lI); lDicomData.XYZmm[1] := lI / 256; lDicomData.XYZmm[2] := lDicomData.XYZmm[1]; lCompress := ord(read8Ch(376)); //xlDicomData.ElscintCompress := true; //xread16i(400,lDicomData.WindowWidth); //x read16i(398,lDicomData.WindowCenter); case lCompress of 0: begin lDynStr := lDynStr + 'Compression: None'+kCR; //xlDicomData.ElscintCompress := false; end; 1: lImageFormatOK := false;//xlDynStr := lDynStr + 'Compression: Old'+kCR; 2: lImageFormatOK := false;//xlDynStr := lDynStr + 'Compression: 2400 Elite'+kCR; 22: lImageFormatOK := false;//xlDynStr := lDynStr + 'Compression: Twin'+kCR; else begin lImageFormatOK := false;//xlDynStr := lDynStr + 'Compression: Unknown '+inttostr(lCOmpress)+kCR; //lDicomData.ElscintCompress := false; end; end; //lDicomData.XYZdim[1] := swap32i(linitialoffset+8); //width //lDicomData.XYZdim[2] := swap32i(linitialoffset+12);//height lDicomData.ImageStart := 396; lDicomData.Allocbits_per_pixel := 16; //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; if (lDicomData.XYZdim[1]=160) and (lDicomData.XYZdim[2]= 160) and (FIleSz=52224) then begin lDicomData.ImageStart := 1024; lImageFormatOK := true;//x//xlDicomData.ElscintCompress := False; end; //lDicomData.XYZmm[3] := fswap4r (2310+26);// slice thickness mm lDynStr := lDynStr+'Image/Study Number: '+inttostr(lDicomData.ImageNum)+'/'+ inttostr(lDicomData.AcquNum)+kCR +'XYZ dim: ' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) //x+kCR+'Window Center/Width: '+inttostr(lDicomData.WindowCenter)+'/'+inttostr(lDicomData.WindowWidth) +kCR+'XYZ mm: '+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2); lHdrOK := true; lImageFormatOK := true; 539: CloseFile(fp); FileMode := 2; //set to read/write end; //end elscint //start picker procedure read_picker_data(lVerboseRead: boolean; var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); label 423; const kPickerHeader =8192; kRecStart = 280; //is this a constant? var lDataStart,lVal,lDBPos,lPos,lRecSz, lNumRecs,lRec,FileSz,n: Longint; lThkM,lThkN,lSiz: double; tx : array [0..6] of Char; FP: file; lDiskCacheRA: pChar; function ReadRec(lRecNum: integer): boolean; var lNameStr,lValStr: string; lOffset,lLen,lFPOs,lFEnd: integer; function ValStrToFloat: double; var lConvStr: string; lI: integer; begin Result := 0.0; lLen := Length(lValStr); if lLen < 1 then exit; lConvStr := ''; for lI := 1 to lLen do if lValStr[lI] in ['0'..'9'] then lConvStr := lConvStr+ lValStr[lI]; if Length(lConvStr) < 1 then exit; Result := strtofloat(lConvStr); end; begin Result := false; lFPos := ((lRecNum-1) * lRecSz)+ kRecStart; lFEnd := lFpos + 6; lNameStr := ''; for lFPos := lFPos to lFEnd do if ord(lDiskCacheRA[lFPos]) <> 0 then lNameStr := lNameStr +lDiskCacheRA[lFPos]; if (lVerboseRead) or (lNameStr = 'RCNFSIZ') or (lNameStr='SCNTHKM') or (lNameStr='SCNTHKN') then begin lFPos := ((lRecNum-1) * lRecSz)+ kRecStart+8; lFEnd := lFPos+1; lOffset := 0; for lFPos := lFPos to lFend do lOffset := ((lOffset)shl 8)+(ord(lDiskCacheRA[lFPos])); lFPos := ((lRecNum-1) * lRecSz)+ kRecStart+10; lFEnd := lFPos+1; lLen := 0; for lFPos := lFPos to lFend do lLen := ((lLen)shl 8)+(ord(lDiskCacheRA[lFPos])); lOffset := lDataStart+lOffset+1; lFEnd := lOffset+lLen-1; if (lLen < 1) or (lFEnd > kPickerHeader) then exit; lValStr := ''; for lFPos := (lOffset) to lFEnd do begin lValStr := lValStr+lDiskCacheRA[lFPos]; end; if lVerboseRead then lDynStr := lDynStr+kCR+lNameStr+': '+ lValStr; if (lNameStr = 'RCNFSIZ') then lSiz := ValStrToFloat; if (lNameStr='SCNTHKM') then lThkM := ValStrToFloat; if (lNameStr='SCNTHKN') then lThkN := ValStrToFloat; end; //verboseread, or vital value result := true; end; function FindStr(l1,l2,l3,l4,l5: Char; lReadNum: boolean; var lNum: integer): boolean; var //lMarker: integer; lNumStr: String; begin Result := false; repeat if (lDiskCacheRA[lPos-4]=l1) and (lDiskCacheRA[lPos-3]=l2) and (lDiskCacheRA[lPos-2]=l3) and (lDiskCacheRA[lPos-1]=l4) and (lDiskCacheRA[lPos]=l5) then Result := true; inc (lPos); until (Result) or (lPos >= kPickerHeader); if not Result then exit; if not lReadNum then exit; Result := false; lNumStr := ''; repeat if (lDiskCacheRA[lPos] in ['0'..'9']) then lNumStr := lNumStr + lDiskCacheRA[lPos] else if lNumStr <> '' then Result := true; inc(lPos); until (Result) or (lPos = kPickerHeader); lNum := strtoint(lNumStr); end; begin lSiz := 0.0; lThkM := 0.0; lThkN := 0.0; lImageFormatOK := true; lHdrOK := false; if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FIleSz := FileSize(fp); Clear_Dicom_Data(lDicomData); if filesz < (kPickerHeader) then begin dcmMsg('This file is to small to be a Picker image: '+lFileName ); CloseFile(fp); FileMode := 2; //set to read/write exit; end; seek(fp, 0); BlockRead(fp, tx, 4*SizeOf(Char), n); if (tx[0] <> '*') OR (tx[1] <> '*') OR (tx[2] <> '*') OR (tx[3] <> ' ') then begin {manufacturer is not SIEMENS} dcmMsg('Is this a Picker image? Expected ''***'' at the start of the file.'+ lFileName); CloseFile(fp); FileMode := 2; //set to read/write exit; end; {not picker} if filesz = (kPickerHeader + (1024*1024*2)) then begin lDICOMdata.XYZdim[1] := 1024; lDICOMdata.XYZdim[2] := 1024; lDICOMdata.XYZdim[3] := 1; lDICOMdata.ImageStart := 8192; end else if filesz = (kPickerHeader + (512*512*2)) then begin lDICOMdata.XYZdim[1] := 512; lDICOMdata.XYZdim[2] := 512; lDICOMdata.XYZdim[3] := 1; lDICOMdata.ImageStart := 8192; end else if filesz = (8192 + (256*256*2)) then begin lDICOMdata.XYZdim[1] := 256; lDICOMdata.XYZdim[2] := 256; lDICOMdata.XYZdim[3] := 1; lDICOMdata.ImageStart := 8192; end else begin dcmMsg('This file is the incorrect size to be a Picker image.'); CloseFile(fp); FileMode := 2; //set to read/write exit; end; getmem(lDiskCacheRA,kPickerHeader*sizeof(char)); seek(fp, 0); BlockRead(fp, lDiskCacheRA, kPickerHeader, n); lRecSz := 0; lNumRecs := 0; lPos := 5; if not FindStr('d','b','r','e','c',false, lVal) then goto 423; lDBPos := lPos; if not FindStr('r','e','c','s','z',true, lRecSz) then goto 423; lPos := lDBPos; if not FindStr('n','r','e','c','s',true, lnumRecs) then goto 423; lPos := kRecStart; // IS THIS A CONSTANT??? lDataStart :=kRecStart + (lRecSz*lnumRecs)-1; //file starts at 0, so -1 if (lNumRecs = 0) or (lDataStart> kPickerHeader) then goto 423; lRec := 0; lDynStr := 'Picker Format'; repeat inc(lRec); until (not (ReadRec(lRec))) or (lRec >= lnumRecs); if lSiz <> 0 then begin lDICOMdata.XYZmm[1] := lSiz/lDICOMdata.XYZdim[1]; lDICOMdata.XYZmm[2] := lSiz/lDICOMdata.XYZdim[2]; if lVerboseRead then lDynStr := lDynStr+kCR+'Voxel Size: '+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2) +'x'+ floattostrf(lDicomData.XYZmm[2],ffFixed,8,2); end; if (lThkM <> 0) and (lThkN <> 0) then begin lDICOMdata.XYZmm[3] := lThkN/lThkM; if lVerboseRead then lDynStr := lDynStr+kCR+'Slice Thickness: '+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2); end; 423: freemem(lDiskCacheRA); lHdrOK := true; CloseFile(fp); FileMode := 2; //set to read/write end; //end picker procedure read_minc_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); var // lReal: double; lnOri,lnDim,lStartPosition,nelem0,jj,lDT0,vSizeRA,BeginRA,m,nnelem,nc_type,nc_size,lLen,nelem,j,lFilePosition,lDT,lFileSz,lSignature,lWord: integer; lOri: array [1..3] of double; //tx : array [0..80] of Char; lVarStr,lStr: string; FP: file; function dTypeStr (lV: integer): integer; begin case lV of 1,2: result := 1; 3: result := 2; //int16 4: result := 4; //int32 5: result := 4; //single 6: result := 8; //double end; end; //nested fcn dTypeStr function read32i: Longint; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(Long:LongInt); end; swaptypep = ^swaptype; var s : LongInt; inguy:swaptypep; outguy:swaptype; begin seek(fp,lFilePosition); lFilePosition := lFilePosition + 4; BlockRead(fp, s, 4); inguy := @s; //assign address of s to inguy if lDICOMdata.Little_Endian = 0 then begin outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); end else outguy.long := inguy^.long; result:=outguy.Long; end; function read64r (lDataType: integer): Double; type swaptype = packed record case byte of 0:(Word1,Word2,Word3,Word4 : word); //word is 16 bit 1:(Long:Double); end; swaptypep = ^swaptype; var s : Double; inguy:swaptypep; outguy:swaptype; begin result := 1; if lDataType <> 6 then begin dcmMsg('Unknown data type: MRIcro is unable to determine the voxel size.'); exit; end; seek(fp,lFilePosition); lFilePosition := lFilePosition + 8; BlockRead(fp, s, 8); inguy := @s; //assign address of s to inguy if lDICOMdata.Little_Endian = 0 then begin outguy.Word1 := swap(inguy^.Word4); outguy.Word2 := swap(inguy^.Word3); outguy.Word3 := swap(inguy^.Word2); outguy.Word4 := swap(inguy^.Word1); end else outguy.long := inguy^.long; result:=outguy.Long; end; function readname: String; var lI,lLen: integer; lCh: char; begin result := ''; seek(fp,lFilePosition); lLen := read32i; if lLen < 1 then begin dcmMsg('Terminal error reading netCDF/MINC header (String length < 1)'); exit; //problem end; for lI := 1 to lLen do begin BlockRead(fp, lCh, 1); result := result + lCh; end; lFilePosition := lFilePosition + (((lLen+3) div 4) * 4); end; begin lImageFormatOK := true; lHdrOK := false; if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; for lnOri := 1 to 3 do lOri[lnOri] := 0; lnOri := 4; lnDim := 4; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); lFileSz := FileSize(fp); Clear_Dicom_Data(lDicomData); if lFilesz < (77) then exit; //to small to be MINC lFilePosition := 0; lSignature := read32i; if not (lSignature=1128547841) then begin CloseFile(fp); FileMode := 2; //set to read/write dcmMsg('Problem with MINC signature: '+ inttostr(lSignature)); exit; end; //xlDicomData.Rotate180deg := true; lWord := read32i;//numrecs lDT := read32i; while (lDt=10) or (lDT=11) or (lDT=12) do begin if lDT = 10 then begin //DT=10, Dimensions nelem := read32i; for j := 1 to nelem do begin lStr := readname; lLen := read32i; if lStr = 'xspace' then lDicomData.XYZdim[3] := lLen;//DOES MINC always reverse X and Z? see also XYZmm if lStr = 'yspace' then lDicomData.XYZdim[2] := lLen; if lStr = 'zspace' then lDicomData.XYZdim[1] := lLen; end; //for 1..nelem lDT := read32i; end;//DT=10, Dimensions if lDT = 11 then begin //DT=11, Variables nelem := read32i; for j := 1 to nelem do begin lVarStr := readname; nnelem := read32i; for m := 1 to nnelem do lLen := read32i; lDT0 := read32i; if lDT0 = 12 then begin nelem0 := read32i; for jj := 1 to nelem0 do begin lStr := readname; nc_type := read32i; nc_size := dTypeStr(nc_Type); nnelem := read32i; lStartPosition := lFilePosition; if (lStr = 'step') then begin if (lVarStr = 'xspace') or (lVarStr = 'yspace') or (lVarStr = 'zspace') then begin dec(lnDim); if (lnDim < 4) and (lnDim>0) then lDicomData.XYZmm[lnDim] := read64r(nc_Type) end; end else if (lStr = 'start') then begin if (lVarStr = 'xspace') or (lVarStr = 'yspace') or (lVarStr = 'zspace') then begin dec(lnOri); if (lnOri < 4) and (lnOri > 0) then lOri[lnOri] := read64r(nc_Type) end; end; lFilePosition := lStartPosition + ((((nnelem*nc_size)+3) div 4)*4); end; lDT0 := read32i; if lVarStr = 'image' then begin case lDT0 of 1,2: lDicomData.Allocbits_per_pixel := 8; 3: lDicomData.Allocbits_per_pixel := 16; //int16 4: lDicomData.Allocbits_per_pixel := 32; //int32 5: lDicomData.Allocbits_per_pixel := 32; //single 6: lDicomData.Allocbits_per_pixel := 64; //double end; if (lDT0 = 5) or (lDT0 = 6) then lDicomData.FloatData := true; //xlDicomData.Storedbits_per_pixel := lDicomData.Allocbits_per_pixel; //lImgNC_Type := lDT0; end; end; vSizeRA := read32i; BeginRA := read32i; if lVarStr = 'image' then begin lDICOMdata.ImageStart := BeginRA; end; end; //for 1..nelem lDT := read32i; end;//DT=11 if lDT = 12 then begin //DT=12, Attributes nelem := read32i; for j := 1 to nelem do begin lStr := readname; nc_type := read32i; nc_size := dTypeStr(nc_Type); nnelem := read32i; lFilePosition := lFilePosition + ((((nnelem*nc_size)+3) div 4)*4); end; //for 1..nelem lDT := read32i; end;//DT=12, Dimensions end; //while DT if lOri[1] <> 0 then lDicomData.XYZori[1] := round((-lOri[1])/lDicomData.XYZmm[1])+1; if lOri[2] <> 0 then lDicomData.XYZori[2] := round((-lOri[2])/lDicomData.XYZmm[2])+1; if lOri[3] <> 0 then lDicomData.XYZori[3] := round((-lOri[3])/lDicomData.XYZmm[3])+1; lDynStr := 'MINC image'+kCR+ 'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'XYZ origin:' +inttostr(lDicomData.XYZori[1])+'/' +inttostr(lDicomData.XYZori[2])+'/'+inttostr(lDicomData.XYZori[3]) +kCR+'XYZ size [mm or micron]:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2) +kCR+'Bits per sample/Samples per pixel: '+inttostr( lDICOMdata.Allocbits_per_pixel) +kCR+'Data offset:' +inttostr(lDicomData.ImageStart); lHdrOK := true; lImageFormatOK := true; CloseFile(fp); FileMode := 2; //set to read/write end; //read_minc //start TIF procedure read_tiff_data(var lDICOMdata: DICOMdata; var lReadOffsets, lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); label 566, 564; const kMaxnSLices = 6000; var lLongRA: LongIntP; lStackSameDim,lContiguous: boolean; l1stDicomData: DicomData; //lDouble : double; //lXmm,lYmm,lZmm: double; lSingle: single; lImageDataEndPosition,lStripPositionOffset,lStripPositionType,lStripPositionItems, lStripCountOffset,lStripCountType,lStripCountItems, lItem,lTagItems,lTagItemBytes,lTagPointer,lNumerator, lDenominator, lImage_File_Directory,lTagType,lVal,lDirOffset,lOffset,lFileSz, lnDirectories,lDir,lnSlices: Integer; lTag,lWord,lWord2: word; FP: file; (*FUNCTION longint2single ({var} s:longint): single; //returns true if s is Infinity, NAN or Indeterminate //4byte IEEE: msb[31] = signbit, bits[23-30] exponent, bits[0..22] mantissa //exponent of all 1s = Infinity, NAN or Indeterminate VAR Overlay: Single ABSOLUTE s; BEGIN result := Overlay; END;*) function read64r(lPos: integer):double; type swaptype = packed record case byte of 0:(Word1,Word2,Word3,Word4 : word); //word is 16 bit 1:(float:double); end; swaptypep = ^swaptype; var inguy:swaptypep; outguy:swaptype; s: double; begin seek(fp,lPos); BlockRead(fp, s, 8); inguy := @s; //assign address of s to inguy if lDICOMdata.Little_Endian = 0{false} then begin outguy.Word1 := swap(inguy^.Word4); outguy.Word2 := swap(inguy^.Word3); outguy.Word3 := swap(inguy^.Word2); outguy.Word4 := swap(inguy^.Word1); end else outguy.float := inguy^.float; result:=outguy.float; end; function read32i(lPos: longint): Longint; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(Long:LongInt); end; swaptypep = ^swaptype; var s : LongInt; inguy:swaptypep; outguy:swaptype; begin seek(fp,lPos); BlockRead(fp, s, 4); inguy := @s; //assign address of s to inguy if lDICOMdata.Little_Endian = 0 then begin outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); end else outguy.long := inguy^.long; result:=outguy.Long; end; function read16(lPos: longint): Longint; var s : word; begin seek(fp,lPos); BlockRead(fp, s, 2); if lDICOMdata.Little_Endian = 0 then result := swap(s) else result := s; end; function read8(lPos: longint): Longint; var s : byte; begin seek(fp,lPos); BlockRead(fp, s, 1); result := s; end; function readItem(lItemNum,lTagTypeI,lTagPointerI: integer): integer; begin if lTagTypeI= 4 then result := read32i(lTagPointerI+((lItemNum-1)*4)) else result := read16(lTagPointerI+((lItemNum-1)*2)); end; begin Clear_Dicom_Data(lDicomData); if gECATJPEG_table_entries <> 0 then begin freemem (gECATJPEG_pos_table); freemem (gECATJPEG_size_table); gECATJPEG_table_entries := 0; end; //lXmm := -1; //not read lImageFormatOK := true; lHdrOK := false; if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; //lLongRASz := kMaxnSlices * sizeof(longint); getmem(lLongRA,kMaxnSlices*sizeof(longint)); FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); lFileSz := FileSize(fp); Clear_Dicom_Data(lDicomData); //xlDicomData.PlanarConfig:=0; if lFilesz < (28) then begin goto 566; end; //TmpStr := string(StrUpper(PChar(ExtractFileExt(lFileName)))); //if not (TmpStr = '.TIF') or (TmpStr = '.TIFF') then exit; lWord := read16(0); if lWord = $4d4d then lDICOMdata.little_endian := 0 else if lWord = $4949 then lDICOMdata.little_endian := 1; lWord2 := read16(2); //bits per pixel if ((lWord=$4d4d) or (lWord=$4949)) and (lWord2 = $002a) then else goto 566; lOffset := read32i(4); lImage_File_Directory := 0; lContiguous := true; lnSlices := 0; //xlDicomData.SamplesPerPixel := 1; //START while for each image_file_directory while (lOffset > 0) and ((lOffset+2+12+4) < lFileSz) do begin inc(lImage_File_Directory); lnDirectories := read16(lOffset); if (lnDirectories < 1) or ((lOffset+2+(12*lnDirectories)+4) > lFileSz) then goto 566; for lDir := 1 to lnDirectories do begin lDirOffset := lOffset+2+((lDir-1)*12); lTag := read16(lDirOffset); lTagType := read16(lDirOffset+2); lTagItems := read32i(lDirOffset+4); case lTagType of 1: lVal := 1;//bytes 3: lVal := 2;//word 4: lVal := 4;//long 5: lVal := 8;//rational else lVal := 1; //CHAR variable length end; lTagItemBytes := lVal * lTagItems; if lTagItemBytes > 4 then lTagPointer := read32i(lDirOffset+8) else lTagPointer := (lDirOffset+8); case lTagType of 1: lVal := read8(lDirOffset+8); 3: lVal := read16(lDirOffset+8); 4: lVal := read32i(lDirOffset+8); 5: begin //rational: two longs representing numerator and denominator lVal := read32i(lDirOffset+8); lNumerator := read32i(lVal); lDenominator := read32i(lVal+4); if lDenominator <> 0 then lSingle := lNumerator/lDenominator else lSingle := 1; if lSingle <> 0 then lSingle := 1/lSingle; //Xresolution/Yresolution refer to number of pixels per resolution_unit if lTag = 282 then lDicomData.XYZmm[1] := lSingle; if lTag = 283 then lDicomData.XYZmm[2] := lSingle; end; else lVal := 0; end; case lTag of //254: ;//NewSubFileType 256: lDicomData.XYZdim[1] := lVal;//image_width 257: lDicomData.XYZdim[2] := lVal;//image_height 258: begin //bits per sample if lTagItemBytes > 4 then lVal := 8; //if lVal <> 8 then goto 566; lDicomData.Allocbits_per_pixel := lVal;//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; end; 259: begin if lVal <> 1 then begin dcmMsg('TIFF Read Error: Image data is compressed. Currently only uncompressed data is supported.'); goto 566; //compressed data end; end; //x262: if lVal = 0 then lDicomdata.monochrome := 1;//invert colors //photometric_interpretation //MinIsWhite,MinIsBlack,Palette //270: ; //ImageDescription 273: begin //get offset to data lStripPositionOffset := lTagPointer; lStripPositionType := lTagType; lStripPositionItems := lTagItems; if (lImage_File_Directory=1) then lDicomData.ImageStart := readItem(1,lStripPositionType,lStripPositionOffset); end; //StripOffsets //274: ; //orientation 277: begin //xlDicomData.SamplesPerPixel := lVal; //if lVal <> 1 then goto 566; //samples per pixel end; 279: begin lStripCountOffset := lTagPointer; lStripCountType := lTagType; lStripCountItems := lTagItems; end; //278: message('rows:'+inttostr(lVal));//StripByteCount //279: message('count:'+inttostr(lVal));//StripByteCount //282 and 283 are rational values and read separately 284: begin {xif lVal = 1 then lDicomData.PlanarConfig:= 0 else lDicomData.PlanarConfig:= 1;//planarConfig } end; 34412: begin //Zeiss data header //0020h float x size of a pixel (m or s) //0024h float y size of a pixel (m or s) //0028h float z distance in a sequence (m or s) {stream.seek((int)position + 40); VOXELSIZE_X = swap(stream.readDouble()); stream.seek((int)position + 48); VOXELSIZE_Y = swap(stream.readDouble()); stream.seek((int)position + 56); VOXELSIZE_Z = swap(stream.readDouble());} lVal := read16(lTagPointer+2); if lVal = 1024 then begin //LSM510 v2.8 images lDicomData.XYZmm[1]{lXmm} := read64r(lTagPointer+40)*1000000; lDicomData.XYZmm[2]{lYmm} := read64r(lTagPointer+48)*1000000; lDicomData.XYZmm[3]{lZmm} := read64r(lTagPointer+56)*1000000; end; //following may work if lVal = 2, different type of LSM file I have not seen //lXmm := longint2single(read32i(lTagPointer+$0020)); //lYmm := longint2single(read32i(lTagPointer+$0024)); //lZmm := longint2single(read32i(lTagPointer+$0028)); end; //296: ;//resolutionUnit 1=undefined, 2=inch, 3=centimeter //320?? //LEICA: 34412 //SOFTWARE = 305 //DATE_TIME = 306 //ARTIST = 315 //PREDICTOR = 317 //COLORMAP = 320 => essntially custom LookUpTable //EXTRASAMPLES = 338 //SAMPLEFORMAT = 339 //JPEGTABLES = 347 // lDicomData.ImageStart := lVal //else if lImage_File_Directory = 1 then dcmMsg(inttostr(lTag)+'@'+inttostr(lTagPointer)+' value: '+inttostr(lVal)); end; //case lTag end; //For Each Directory in Image_File_Directory lOffset := read32i(lOffset+2+(12*lnDirectories)); //NEXT: check that each slice in 3D slice is the same dimension lStackSameDim := true; if (lImage_File_Directory=1) then begin l1stDicomData := lDICOMdata; lnSlices := 1; //inc(lnSlices); end else begin if lDicomData.XYZdim[1] <> l1stDicomData.XYZdim[1] then lStackSameDim := false; if lDicomData.XYZdim[2] <> l1stDicomData.XYZdim[2] then lStackSameDim := false; if lDicomData.Allocbits_per_pixel <> l1stDicomData.Allocbits_per_pixel then lStackSameDim := false; //xif lDicomData.SamplesPerPixel <> l1stDicomData.SamplesPerPixel then lStackSameDim := false; //xif lDicomData.PlanarConfig <> l1stDicomData.PlanarConfig then lStackSameDim := false; if not lStackSameDim then begin //dcmMsg(inttostr(lDicomData.XYZdim[1])+'x'+inttostr(l1stDicomData.XYZdim[1])); if (lDicomData.XYZdim[1]*lDicomData.XYZdim[2]) > (l1stDicomData.XYZdim[1]*l1stDicomData.XYZdim[2]) then begin l1stDicomData := lDICOMdata; lnSlices := 1; lStackSameDim := true; end; //dcmMsg('TIFF Read Error: Different 2D slices in this 3D stack have different dimensions.'); //goto 566; end else inc(lnSlices); //if not samedim end; //check that each slice is same dimension as 1st //END check each 2D slice in 3D stack is same dimension //NEXT: check if image data is contiguous if (lStripCountItems > 0) and (lStripCountItems = lStripPositionItems) then begin if (lnSlices=1) then lImageDataEndPosition := lDicomData.ImageStart; for lItem := 1 to lStripCountItems do begin lVal := readItem(lItem,lStripPositionType,lStripPositionOffset); if (lVal <> lImageDataEndPosition) then lContiguous := false; //dcmMsg(inttostr(lImage_File_Directory)+'@'+inttostr(lItem)); lImageDataEndPosition := lImageDataEndPosition+readItem(lItem,lStripCountType,lStripCountOffset); if not lcontiguous then begin if (lReadOffsets) and (lStackSameDim) then begin lLongRA^[lnSlices] := lVal; end else if (lReadOffsets) then //not correct size, but do not generate an error as we will read non-contiguous files else begin dcmMsg('TIFF Read Error: Image data is not stored contiguously. '+ 'Solution: convert this image using MRIcro''s ''Convert TIFF/Zeiss to Analyze...'' command [Import menu].'); goto 564; end; end; //if not contiguous end; //for each item end;//at least one StripItem} //END check image data is contiguous end; //END while each Image_file_directory lDicomData := l1stDicomData; lDicomData.XYZdim[3] := lnSlices; if (lReadOffsets) and (lnSlices > 1) and (not lcontiguous) then begin gECATJPEG_table_entries := lnSlices; //Offset tables for TIFF getmem (gECATJPEG_pos_table, gECATJPEG_table_entries*sizeof(longint)); getmem (gECATJPEG_size_table, gECATJPEG_table_entries*sizeof(longint)); gECATJPEG_pos_table^[1] := l1stDicomData.ImageStart; for lVal := 2 to gECATJPEG_table_entries do gECATJPEG_pos_table^[lVal] := lLongRA^[lVal] end; lHdrOK := true; 564: lDynStr := 'TIFF image'+kCR+ 'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'XYZ size [mm or micron]:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2) +kCR+'Bits per sample/Samples per pixel: '+inttostr( lDICOMdata.Allocbits_per_pixel) +kCR+'Data offset:' +inttostr(lDicomData.ImageStart); {if lXmm > 0 then lDynStr := lDynStr +kCR+'Zeiss XYZ mm:'+floattostr(lXmm)+'/' +floattostr(lYmm)+'/' +floattostr(lZmm);} 566: freemem(lLongRA); CloseFile(fp); FileMode := 2; //set to read/write end; procedure read_biorad_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); var lCh: char; lByte: Byte; lSpaces,liPos,lFileSz,lWord,lNotes,lStart,lEnd: integer; tx : array [0..80] of Char; lInfo,lStr,lTmpStr: string; FP: file; procedure read16(lPos: longint; var lVal: integer); var lInWord: word; begin seek(fp,lPos); BlockRead(fp, lInWord, 2); lVal := lInWord; end; procedure read32(lPos: longint; var lVal: integer); var lInINt: integer; begin seek(fp,lPos); BlockRead(fp, lInINt, 4); lVal :=lInINt; end; begin lImageFormatOK := true; lHdrOK := false; if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); lFileSz := FileSize(fp); Clear_Dicom_Data(lDicomData); if lFilesz < (77) then exit; //to small to be biorad read16(54,lWord); if (lWord=12345) then begin lDicomData.little_endian := 1; read16(0,lDicomData.XYZdim[1]); read16(2,lDicomData.XYZdim[2]); read16(4,lDicomData.XYZdim[3]); read16(14,lWord);//byte format if lWord = 1 then lDicomData.Allocbits_per_pixel := 8 else lDicomData.Allocbits_per_pixel := 16;//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; lDicomData.ImageStart := 76; read32(10,lNotes); lStart := (lDicomData.XYZdim[1]*lDicomData.XYZdim[2]*lDicomData.XYZdim[3])+76; lEnd := lStart + 96; lDynStr := 'BIORAD PIC image'+kCR; while (lNotes > 0) and (lFileSz >= lEnd) do begin read32(lStart+2,lNotes); //final note has bytes 2..5 set to zero //read16(lStart+10,lNoteType); //if lNoteType <> 1 then begin //ignore 'LIVE' notes - they do not include calibration info seek(fp, lStart+16); BlockRead(fp, tx, 80{, n}); lStr := ''; liPos := 0; repeat lCh := tx[liPos]; lByte := ord(lCh); if (lByte >= 32) and (lByte <= 126) then lStr := lStr+lCh else lByte := 0; inc(liPos); until (liPos = 80) or (lByte = 0); if length(lStr) > 6 then begin lInfo := ''; for liPos := 1 to 6 do lInfo := lInfo+upcase(lStr[liPos]); ltmpstr := ''; lSpaces := 0; for liPos := 1 to 80 do begin if lStr[liPos]=' ' then inc(lSpaces) else if lSpaces = 3 then ltmpstr := ltmpstr + lStr[liPos]; end; if ltmpstr = '' then {no value to read} else if lInfo = 'AXIS_2' then lDicomData.XYZmm[1] := strtofloat(ltmpstr) else if lInfo = 'AXIS_3' then lDicomData.XYZmm[2] := strtofloat(ltmpstr) else if linfo = 'AXIS_4' then lDicomData.XYZmm[3] := strtofloat(ltmpstr); lDynStr := lDynStr+lStr+kCR; end; //Str length > 6 //end;//notetype lStart := lEnd; lEnd := lEnd + 96; end; //while notes lHdrOK := true; //lImageFormatOK := true; end;//biorad signature CloseFile(fp); FileMode := 2; //set to read/write lDynStr := 'BioRad image'+kCR+ 'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'XYZ size [mm or micron]:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2) +kCR+'Bits per sample/Samples per pixel: '+inttostr( lDICOMdata.Allocbits_per_pixel) +kCR+'Data offset:' +inttostr(lDicomData.ImageStart); end; //biorad function SiemensVersion (lStr: string): integer; //Convert tag 0018,1020 from DICOM header to Siemens version number (*Returned value: system is in 1000s, last two digits are version syngo MR 2004A 4VA25A //->0011 Siemens syngo MR 2006T 4VB12T //-> 0012 MR B13 4VB13A //->0013 MR.VB15A123 //->0015 syngo MR B15 //-> 0015 syngo MR B17 //->0017 B= Trio, Verio, Etc syngo MR C11 //->1011 C= Chinese C11 ~ B17 syngo MR D11 //->2011 D= Skyra D11 ~ B17*) label 999; var i,len: integer; begin result := 0; len := length(lStr); if len < 3 then exit; for i := 1 to len-1 do if (upcase(lStr[i]) in ['A'..'Z']) and (lStr[i+1] in ['0'..'9']) then goto 999; exit; //not Siemens format 999: if ( upcase(lStr[i]) = 'A') then begin //A25 result := 10; exit; end; result := strtoint(lStr[i+1]); if lStr[i+2] in ['0'..'9'] then result := (result*10) + strtoint(lStr[i+2]); result := (100*( ord(upcase(lStr[i]))- ord('B'))) + result; end; (* Obsolete - replaced by SiemensVersion function SiemensBversion (lStr: string): integer; //'syngo MR B17' returns 17 //'MR.VB15A123' returns 15 //'syngo MR B15' returns 15 //'MR B13 4VB13A' returns 13 //'syngo MR 2006T 4VB12T' returns 12 var Len,P,B: integer; S: string; begin result := 0; Len := length(lStr); if Len <2 then exit; B := 0; for P := 2 to (Len) do if (upcase(lStr[P-1])='B') and ( lStr[P] in ['0'..'9']) then B := P; if B < 1 then exit; S := ''; while (B<= Len) and (lStr[B] in ['0'..'9']) do begin S := S + lStr[B]; inc(B); end; if length(S) < 1 then exit; result := strtoint(S); end;*) (*function Str2IntDig (lStr: string; lDig: integer): integer; //robust stringtoint that strips out any junk so that "Implementation Version Name=MR.VB15A123" returns 15 // warning, strips out decimals, so 15.3 will return 153! //warning also ignores minus sign so -5.21 will return 521! var Len,P: integer; S: string; begin result := 0; Len := length(lStr); if Len <1 then exit; S := ''; for P := 1 to Len do if (lStr[P] in ['0'..'9']) and (length(S) < lDig) then S := S + lStr[P]; if length(S) < 1 then exit; result := strtoint(S); end; *) function ExpectedDicomBytes (var lDICOMdata: DICOMdata): integer; begin if lDicomData.JPEGLosslessCpt then begin result := 0; //actual compressed size unknown exit; end; result := lDicomdata.XYZdim[1]*lDicomdata.XYZdim[2]*lDicomdata.XYZdim[3]*(lDicomData.Allocbits_per_pixel DIV 8); end; const kNo =0; kYes = 1; kUndefined = 2; procedure read_dicom_data_compat(lReadJPEGtables,lVerboseRead,lAutoDECAT7,lReadECAToffsetTables,lAutoDetectInterfile,lAutoDetectGenesis,lReadColorTables: boolean; var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string; var lPrefs: TPrefs); label 666,777; const kMaxTextBuf = 50000; //maximum for screen output kDiskCache = 16384; //size of disk buffer kNaNsingle : single = 1/0; type dicom_types = (unknown, i8, i16, i32, ui8, ui16, ui32, _string{,_float} ); var // lTextF: TextFile; //abba lDICOMdataBackUp: DICOMdata; lWord,lWord2,lWord3: word; lWordRA: Wordp; lDiskCacheRA: pChar{ByteP}; lRot1,lRot2,lRot3 : integer;//rotation dummies for AFNI FP: file; lT0,lT1,lT2,lT3:byte; lImagePositionPatientRead, lResearchMode,lManufacturerIsPhilips,lManufacturerIsBruker,lOsirix0002_0013,lMediface0002_0013,lSiemensMosaic0008_0008,lDICM_at_128, lTextOverFlow,lGenesis,lFirstPass,lrOK,lBig,lBigSet,lGrp,explicitVR,first_one : Boolean; lSwitchToImplicitAfterGroup0002, lTestError,lByteSwap,lGELX,time_to_quit,lProprietaryImageThumbnail,lFirstFragment,lOldSiemens_IncorrectMosaicMM : Boolean; group, element, e_len, remaining, tmp : uint32; tmpstr : kDICOMstr; lgrpstr,lStr,info,lDummyStr : string; t : dicom_types; lUse00189117 : integer; lfloat1,lfloat2,lfloat3,lThickness: double; lTempInt,lEchoNum,lnVol,lnSlicePerVol,lJPEGentries,lErr,liPos,lCacheStart,lCachePos,lDiskCacheSz,n, i,value, Ht,Width, max16,min16,filesz,where,lMatrixSz,lPhaseEncodingSteps,lJunk,lJunk2,lJunk3 : LongInt; tx : array [0..96] of Char; l4DDistanceBetweenSliceCenters,lPhilipsScaleSlope: single; buff: pCHar; lColorRA: bytep; lLongRA: Longintp; lSingleRA,lInterceptRA: Singlep; //lPapyrusnSlices,lPapyrusSlice : integer; //lPapyrusZero,lPapyrus : boolean; {$IFDEF Troubleshoot} myFile : TextFile; {$ENDIF Troubleshoot} procedure ByteSwap (var lInOut: integer); var lWord: word; begin lWord := lInOut; lWord := swap(lWord); lInOut := lWord; end; procedure dReadCache (lFileStart: integer); begin lCacheStart := lFileStart{lCacheStart + lDiskCacheSz};//eliminate old start if lCacheStart < 0 then lCacheStart := 0; if lDiskCacheSz > 0 then freemem(lDiskCacheRA); if (FileSz-(lCacheStart)) < kDiskCache then lDiskCacheSz := FileSz - (lCacheStart) else lDiskCacheSz := kDiskCache; lCachePos := 0; if (lDiskCacheSz < 1) then exit{goto 666}; if (lDiskCacheSz+lCacheStart) > FileSz then exit; Seek(fp, lCacheStart); GetMem(lDiskCacheRA, lDiskCacheSz {bytes}); BlockRead(fp, lDiskCacheRA^, lDiskCacheSz, n); end; function dFilePos (var lInFP: file): integer; begin Result := lCacheStart + lCachePos; end; procedure dSeek (var lInFP: file; lPos: integer); begin if (lPos >= lCacheStart) and (lPos < (lDiskCacheSz+lCacheStart)) then begin lCachePos := lPos-lCacheStart; exit; end; dReadCache(lPos); end; procedure dBlockRead (var lInfp: file; lInbuff: pChar; e_len: integer; var n: integer); var lN: integer; begin N := 0; if e_len < 0 then exit; for lN := 0 to (e_len-1) do begin if lCachePos >= lDiskCacheSz then begin dReadCache(lCacheStart+lDiskCacheSz); if lDiskCacheSz < 1 then exit; lCachePos := 0; end; N := lN; lInBuff[N] := lDiskCacheRA[lCachePos]; inc(lCachePos); end; end; procedure readfloats (var fp: file; remaining: integer; var lOutStr: string; var lf1, lf2: double; var lReadOK: boolean); var lDigit : boolean; li,lLen,n: integer; lfStr: string; begin lf1 := 1; lf2 := 2; if e_len = 0 then begin lReadOK := true; exit; end; if (dFilePos(fp) > (filesz-remaining)) or (remaining < 1) then begin lOutStr := ''; lReadOK := false; exit; end else lReadOK := true; lOutStr := ''; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for li := 0 to e_len-1 do if Char(buff[li]) in [{'/','\', delete: rev18}'e','E','+','-','.','0'..'9'] then lOutStr := lOutStr +(Char(buff[li])) else begin lOutStr := lOutStr + ' '; end; FreeMem( buff); lfStr := ''; lLen := length(lOutStr); li := 1; lDigit := false; repeat if (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then lfStr := lfStr + lOutStr[li]; if lOutStr[li] in ['0'..'9'] then lDigit := true; inc(li); until (li > lLen) or (lDigit); if not lDigit then exit; if li <= li then begin repeat if not (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then lDigit := false else begin if lOutStr[li] = 'E' then lfStr := lfStr+'e' else lfStr := lfStr + lOutStr[li]; end; inc(li); until (li > lLen) or (not lDigit); end; //QStr(lfStr); try lf1 := strtofloat(lfStr); except on EConvertError do begin dcmMsg('Unable to convert the string '+lfStr+' to a real number'); lf1 := 1; exit; end; end; {except} lfStr := ''; if li > llen then exit; repeat if (lOutStr[li] in ['+','E','e','.','-','0'..'9']) then begin if lOutStr[li] = 'E' then lfStr := lfStr+'e' else lfStr := lfStr + lOutStr[li]; end; if (lOutStr[li] in ['0'..'9']) then lDigit := true; inc(li); until (li > lLen) or ((lDigit) and (lOutStr[li]=' ')); //second half: rev18 if not lDigit then exit; //QStr(lfStr); try lf2 := strtofloat(lfStr); except on EConvertError do begin dcmMsg('Unable to convert the string '+lfStr+' to a real number'); exit; end; end; end; procedure readfloats3 (var fp: file; remaining: integer; var lOutStr: string; var lf1, lf2,lf3: double; var lReadOK: boolean); var lDigit : boolean; lItem,li,lLen,n: integer; lfTemp: double; lfStr: string; begin lf1 := 0; lf2 := 0; lf3 := 0; lOutStr := ''; if e_len = 0 then begin lReadOK := true; exit; end; if (dFilePos(fp) > (filesz-remaining)) or (remaining < 1) then begin lReadOK := false; exit; end else lReadOK := true; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for li := 0 to e_len-1 do if Char(buff[li]) in [{'/','\', delete: rev18}'e','E','+','-','.','0'..'9'] then lOutStr := lOutStr +(Char(buff[li])) else lOutStr := lOutStr + ' '; FreeMem( buff); li := 1; lLen := length(lOutStr); for lItem := 1 to 3 do begin if li > llen then exit; lfStr := ''; lLen := length(lOutStr); lDigit := false; repeat if (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then lfStr := lfStr + lOutStr[li]; if lOutStr[li] in ['0'..'9'] then lDigit := true; inc(li); until (li > lLen) or (lDigit); if not lDigit then exit; if li <= li then begin repeat if not (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then lDigit := false else begin if lOutStr[li] = 'E' then lfStr := lfStr+'e' else lfStr := lfStr + lOutStr[li]; end; inc(li); until (li > lLen) or (not lDigit); end; //QStr(lfStr); try lftemp := strtofloat(lfStr); except on EConvertError do begin dcmMsg('Unable to convert the string '+lfStr+' to a real number'); //lftemp := 0; exit; end; end; {except} case lItem of 2: lf2 := lftemp; 3: lf3 := lftemp; else lf1 := lftemp; end; //case of lItem end; //for each of 3 lItems end; //readfloats3 procedure CheckIntersliceDistance (var lMinDistance: single); var lX,lY,lZ,lDx: double; begin readfloats3 (fp, remaining, lDummyStr, lX, lY,lZ, lROK); // fx( lX, lY,lZ,6789); e_len := 0; remaining := 0; //compute Distance between current slice and 1st slice... lDx := sqrt( sqr(lX-lDicomData.PatientPosX)+sqr(lY-lDicomData.PatientPosY)+sqr(lZ-lDicomData.PatientPosZ)); if (lDx > 0) and (lMinDistance = kNaNsingle) then //first value lMinDistance := lDx else if (lDx > 0) and (lDx < lMinDistance) then //if 0 then this is a repeat, not a new slice lMinDistance := lDx else exit; end; procedure readfloats6 (var fp: file; remaining: integer; var lOutStr: string; var lf1, lf2,lf3,lf4,lf5,lf6: double; var lReadOK: boolean); var lDigit : boolean; lItem,li,lLen,n: integer; lfTemp: single; lfStr: string; begin lf1 := 0; lf2 := 0; lf3 := 0; lf4 := 0; lf5 := 0; lf6 := 0; lOutStr := ''; if e_len = 0 then begin lReadOK := true; exit; end; if (dFilePos(fp) > (filesz-remaining)) or (remaining < 1) then begin lReadOK := false; exit; end else lReadOK := true; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for li := 0 to e_len-1 do if Char(buff[li]) in [{'/','\', delete: rev18}'e','E','+','-','.','0'..'9'] then lOutStr := lOutStr +(Char(buff[li])) else lOutStr := lOutStr + ' '; FreeMem( buff); li := 1; lLen := length(lOutStr); for lItem := 1 to 6 do begin if li > llen then exit; lfStr := ''; lLen := length(lOutStr); lDigit := false; repeat if (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then lfStr := lfStr + lOutStr[li]; if lOutStr[li] in ['0'..'9'] then lDigit := true; inc(li); until (li > lLen) or (lDigit); if not lDigit then exit; if li <= li then begin repeat if not (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then lDigit := false else begin if lOutStr[li] = 'E' then lfStr := lfStr+'e' else lfStr := lfStr + lOutStr[li]; end; inc(li); until (li > lLen) or (not lDigit); end; //QStr(lfStr); try lftemp := strtofloat(lfStr); except on EConvertError do begin dcmMsg('Unable to convert the string '+lfStr+' to a real number'); //lftemp := 0; exit; end; end; {except} case lItem of 2: lf2 := lftemp; 3: lf3 := lftemp; 4: lf4 := lftemp; 5: lf5 := lftemp; 6: lf6 := lftemp; else lf1 := lftemp; end; //case of lItem end; //for each of 3 lItems end; function read16( var fp : File; var lReadOK: boolean ): uint16; var t1, t2 : uint8; n : Integer; begin if dFilePos(fp) > (filesz-2) then begin read16 := 0; lReadOK := false; exit; end else lReadOK := true; GetMem( buff, 2); dBlockRead(fp, buff{^}, 2, n); T1 := ord(buff[0]); T2 := ord(buff[1]); freemem(buff); if lDICOMdata.little_endian <> 0 then Result := (t1 + t2*256) AND $FFFF else Result := (t1*256 + t2) AND $FFFF; end; function ReadStr(var fp: file; remaining: integer; var lReadOK: boolean; VAR lmaxval:integer) : string; var lInc, lN,Val,n: integer; t1, t2 : uint8; lStr : String; begin lMaxVal := 0; if dFilePos(fp) > (filesz-remaining) then begin lReadOK := false; exit; end else lReadOK := true; Result := ''; lN := remaining div 2; if lN < 1 then exit; lStr := ''; for lInc := 1 to lN do begin GetMem( buff, 2); dBlockRead(fp, buff{^}, 2, n); T1 := ord(buff[0]); T2 := ord(buff[1]); freemem(buff); if lDICOMdata.little_endian <> 0 then Val := (t1 + t2*256) AND $FFFF else Val := (t1*256 + t2) AND $FFFF; if lInc < lN then lStr := lStr + inttostr(Val)+ ', ' else lStr := lStr + inttostr(Val); if Val > lMaxVal then lMaxVal := Val; end; Result := lStr; if odd(remaining) then begin getmem(buff,1); dBlockRead(fp, buff{t1}, SizeOf(uint8), n); freemem(buff); end; end; (*function ReadStrABC(var fp: file; remaining: integer; var lReadOK: boolean; VAR lA,lB,lC:integer) : string; var lInc, lN,Val,n: integer; t1, t2 : uint8; lStr : String; begin lA := 0; lB := 0; lC := 0; if dFilePos(fp) > (filesz-remaining) then begin lReadOK := false; exit; end else lReadOK := true; Result := ''; lN := remaining div 2; if lN < 1 then exit; lStr := ''; for lInc := 1 to lN do begin GetMem( buff, 2); dBlockRead(fp, buff{^}, 2, n); T1 := ord(buff[0]); T2 := ord(buff[1]); freemem(buff); if lDICOMdata.little_endian <> 0 then Val := (t1 + t2*256) AND $FFFF else Val := (t1*256 + t2) AND $FFFF; if lInc < lN then lStr := lStr + inttostr(Val)+ ', ' else lStr := lStr + inttostr(Val); if lInc = 1 then lA := Val; if lInc = 2 then lB := Val; if lInc = 3 then lC := Val; end; Result := lStr; if odd(remaining) then begin getmem(buff,1); dBlockRead(fp, buff{t1}, SizeOf(uint8), n); freemem(buff); end; end; *) function ReadStrHex(var fp: file; remaining: integer; var lReadOK: boolean) : string; var lInc, lN,Val,n: integer; t1, t2 : uint8; lStr : String; begin if dFilePos(fp) > (filesz-remaining) then begin lReadOK := false; exit; end else lReadOK := true; Result := ''; lN := remaining div 2; if lN < 1 then exit; lStr := ''; for lInc := 1 to lN do begin GetMem( buff, 2); dBlockRead(fp, buff, 2, n); T1 := ord(buff[0]); T2 := ord(buff[1]); freemem(buff); if lDICOMdata.little_endian <> 0 then Val := (t1 + t2*256) AND $FFFF else Val := (t1*256 + t2) AND $FFFF; if lInc < lN then lStr := lStr + 'x'+inttohex(Val,4)+ ', ' else lStr := lStr + 'x'+inttohex(Val,4); end; Result := lStr; if odd(remaining) then begin getmem(buff,1); dBlockRead(fp, {t1}buff, SizeOf(uint8), n); freemem(buff); end; end; function SomaTomFloat: double; var lSomaStr: String; begin //dSeek(fp,5992); //Slice Thickness from 5790 "SL 3.0" //dSeek(fp,5841); //Field of View from 5838 "FoV 281" //dSeek(fp,lPos); lSomaStr := ''; tx[0] := 'x'; while (length(lSomaStr) < 64) and (tx[0] <> chr(0)) and (tx[0] <> '/') do begin dBlockRead(fp, tx, 1, n); if tx[0] in ['+','-','.','0'..'9','e','E'] then lSomaStr := lSomaStr + tx[0]; end; if length(lSOmaStr) > 0 then result := StrToFloat(lSomaStr) else result := 0; end; function PGMreadInt: integer; //reads integer from PGM header, disregards comment lines (which start with '#' symbol); var lStr: string; lDigit: boolean; begin Result := 1; lStr := ''; repeat dBlockRead(fp, tx, 1, n); if tx[0] = '#' then begin //comment repeat dBlockRead(fp, tx, 1, n); until (ord(tx[0]) = $0A) or (dFilePos(fp) > (filesz-4)); //eoln indicates end of comment end; //finished reading comment if tx[0] in ['0'..'9'] then begin lStr := lStr + tx[0]; lDigit := true; end else lDigit := false; until ((lStr <> '') and (not lDigit)) or (dFilePos(fp) > (filesz-4)); //read digits until you hit whitespace if lStr <> '' then Result := strtoint(lStr); {lStr := ''; tx[0] := 'x'; while (length(lStr) < 64) and (ord(tx[0]) <> $0A) do begin dBlockRead(fp, tx, 1, n); if tx[0] in ['#','+','-','.','0'..'9','e','E',' ','a'..'z','A'..'Z'] then lStr := lStr + tx[0]; end; result := lStr; } end; function read32 ( var fp : File; var lReadOK: boolean ): uint32; var t1, t2, t3, t4 : byte; n : Integer; begin if dFilePos(fp) > (filesz-4) then begin Read32 := 0; lReadOK := false; exit; end else lReadOK := true; GetMem( buff, 4); dBlockRead(fp, buff{^}, 4, n); T1 := ord(buff[0]); T2 := ord(buff[1]); T3 := ord(buff[2]); T4 := ord(buff[3]); freemem(buff); if lDICOMdata.little_endian <> 0 then Result := t1 + (t2 shl 8) + (t3 shl 16) + (t4 shl 24) else Result := t4 + (t3 shl 8) + (t2 shl 16) + (t1 shl 24) //if lDICOMdata.little_endian <> 0 //then Result := (t1 + t2*256 + t3*256*256 + t4*256*256*256) AND $FFFFFFFF //else Result := (t1*256*256*256 + t2*256*256 + t3*256 + t4) AND $FFFFFFFF; end; function read32r ( var fp : File; var lReadOK: boolean ): single; //1382 type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(float:single); end; swaptypep = ^swaptype; var s:single; inguy:swaptypep; outguy:swaptype; begin if dFilePos(fp) > (filesz-4) then begin read32r := 0; lReadOK := false; exit; end else lReadOK := true; //GetMem( buff, 8); dBlockRead(fp, @s, 4, n); inguy := @s; //assign address of s to inguy if lDICOMdata.little_endian <> 1 then begin outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); end else outguy.float := s; //1382 read64 needs to handle little endian in this way as well... read32r:=outguy.float; end; function read64 ( var fp : File; var lReadOK: boolean ): double; type swaptype = packed record case byte of 0:(Word1,Word2,Word3,Word4 : word); //word is 16 bit 1:(float:double); end; swaptypep = ^swaptype; var s:double; inguy:swaptypep; outguy:swaptype; begin if dFilePos(fp) > (filesz-8) then begin Read64 := 0; lReadOK := false; exit; end else lReadOK := true; //GetMem( buff, 8); dBlockRead(fp, @s, 8, n); inguy := @s; //assign address of s to inguy if lDICOMdata.little_endian <> 1 then begin outguy.Word1 := swap(inguy^.Word4); outguy.Word2 := swap(inguy^.Word3); outguy.Word3 := swap(inguy^.Word2); outguy.Word4 := swap(inguy^.Word1); end else outguy.float := inguy^.float; //1382 read64:=outguy.float; end; //magma function SafeStrToInt(var lInput: string): integer; var li,lLen: integer; begin result := 0; lLen := length(lInput); lStr := ''; if lLen < 1 then exit; for li := 1 to lLen do if lInput[li] in ['+','-','0'..'9'] then lStr := lStr +lInput[li]; Val(lStr,li,lErr); if lErr = 0 then result := lI;//strtoint(lStr); end; procedure DICOMHeaderStringToInt (var lInput: integer); var li: integer; begin t := _string; lStr := ''; if dFilePos(fp) > (filesz-e_len) then exit;//goto 666; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for li := 0 to e_len-1 do if Char(buff[li]) in ['+','-','0'..'9'] then lStr := lStr +(Char(buff[li])); FreeMem( buff); Val(lStr,li,lErr); if lErr = 0 then lInput := li;//strtoint(lStr); remaining := 0; tmp := lInput; end; procedure DICOMHeaderString (var lInput: kDICOMStr); var li,lStartPos: integer; begin t := _string; lStartPos := dFilePos(fp); lInput := ''; if e_len < 1 then exit; //DICOM: should always be even GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for li := 0 to e_len-1 do if Char(buff[li]) in ['+','-','/','\',' ','0'..'9','a'..'z','A'..'Z'] then lInput := lInput +(Char(buff[li])) else {if (buff[i] = 0) then} lInput := lInput +' '; FreeMem( buff); dseek(fp, lStartPos); end; procedure DICOMHeaderStringTime (var lInput: kDICOMstr); var li,lStartPos: integer; begin t := _string; lStartPos := dFilePos(fp); lInput := ''; if e_len < 1 then exit; //DICOM: should always be even GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for li := 0 to e_len-1 do if Char(buff[li]) in ['+','-','/','\',' ','0'..'9','a'..'z','A'..'Z','.'] then lInput := lInput +(Char(buff[li])) else if li <> (e_len-1) then lInput := lInput +':' else lInput := lInput +' '; FreeMem( buff); dseek(fp, lStartPos); end; label 1234; var lIndent: integer; lprevGroup, lprevElement: uint32; var lInside00209113, lInside2005140F, lPhilipsWarning: boolean;//philips can list two DIFFERENT spatial positions per slice - ignore the one hidden inside 2005,140FlPrev0020: boolean; begin //Init //for lnVol := 1 to kMaxOrderVal do // lDICOMdata.OrderSlope[lDICOMdata.nOrder] := 0; //show this was not set {$IFDEF Troubleshoot} AssignFile(myFile, '/Users/rorden/Test.txt'); ReWrite(myFile); {$ENDIF Troubleshoot} lUse00189117 := kUndefined; //Warning each Philips 2D slice can save DTI data once or twice - 0018:9087/0018:9089 and 2001:1003/2001:10B0,10B1,10B2 - this is tricky since Philips files can be 4D lInside00209113 := false; lprevGroup := 0; lprevElement := 0; lPhilipsWarning := false; lIndent := 0; lInside2005140F := false; lSwitchToImplicitAfterGroup0002 := false; lGELX := false; lByteSwap := false; Clear_Dicom_Data(lDicomData); Clear_Dicom_Data(lDICOMdataBackUp); lDicomData.XYZdim[1] := 1; lImagePositionPatientRead := false;// for 4D files, we need first volume l4DDistanceBetweenSliceCenters := kNaNsingle; lEchoNum := 0; lThickness := 0; lTestError := false; lPhilipsScaleSlope := 0; lManufacturerIsPhilips := false; lManufacturerIsBruker := false; lnVol := 0; lnSlicePerVol := 0; lResearchMode := false; lMatrixSz := 0; lPhaseEncodingSteps := 0; lSiemensMosaic0008_0008 := false; lMediface0002_0013 := false;//false wblate lOsirix0002_0013 := false; lOldSiemens_IncorrectMosaicMM := false; lCacheStart := 0; lDiskCacheSz := 0; lDynStr:= ''; lJPEGEntries := 0; first_one := true; info := ''; lGrp:= false; lBigSet := false; lDICM_at_128 := false; //no DICOM signature lFirstFragment := true; lTextOverFlow := false; lImageFormatOK := true; lHdrOK := false; //if lverboseRead then dcmMsg('xxx'+lFileName); if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; //if lverboseRead then dcmMsg('zzzzz000000000'); TmpStr := string(StrUpper(PChar(ExtractFileExt(lFileName)))); lStr :=''; if TmpStr = '.FDF' then begin if FDF( lFileName, lDicomData) then begin lHdrOK := true; lImageFormatOK := true; exit; end; end; if (TmpStr = '.REC') then begin //1417z: check in Unix: character upper/lower case may matter lStr := changefileext(lFilename,'.par'); if fileexists(lStr) then lFilename := lStr else begin //Linux is case sensitive 1382... lStr := changefileext(lFilename,'.PAR'); if fileexists(lStr) then lFilename := lStr end; end; if (TmpStr = '.BRIK') then begin //1417z: check in Unix: character upper/lower case may matter lStr := changefileext(lFilename,'.HEAD'); if fileexists(lStr) then lFilename := lStr; end; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FIleSz := FileSize(fp); if fileSz < 1 then begin lImageFormatOK := false; exit; end; lDICOMdata.Little_Endian := 1; if FileSz > 200 then begin dseek(fp, {0}128); dBlockRead(fp, tx, 4*SizeOf(Char), n); if (tx[0] = 'D') and (tx[1] = 'I') and (tx[2] = 'C') and (tx[3] = 'M') then lDICM_at_128 := true; end;//filesize > 200: check for 'DICM' at byte 128 - DICOM signature if (lAutoDetectGenesis) and (FileSz > (5820{114+35+4})) then begin dseek(fp, 0); if (ord(tx[0])=206) and (ord(tx[1])=250) then begin //Elscint format signature: check height and width to make sure dseek(fp, 370); group := read16(fp,lrOK);//Width dseek(fp, 372); element := read16(fp,lrOK);//Ht if ((Group=160) or(Group =256) or (Group= 340) or (Group=512) or (group =640)) and ((element=160) or (element =256) or (element= 340) or (element=512) ) then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_elscint_data(lDICOMdata, lHdrOK, lImageFormatOK,lDynStr,lFileName); exit; end; //confirmed: Elscint end; lGenesis := false; if ((tx[0] <> 'I') OR (tx[1] <> 'M') OR (tx[2] <> 'G') OR (tx[3] <> 'F')) then begin {DAT format} {if (FileSz > 114+305+4) then begin dseek(fp, 114+305); dBlockRead(fp, tx, 3*SizeOf(Char), n); if ((tx[0]='M') and (tx[1] = 'R')) or ((tx[0] = 'C') and(tx[1] = 'T')) then lGenesis := true; end;} end else lGenesis := true; if (not lGenesis) and (FileSz > 3252) then begin dseek(fp, 3240); dBlockRead(fp, tx, 4*SizeOf(Char), n); if ((tx[0] = 'I') AND (tx[1] = 'M')AND (tx[2] = 'G') AND (tx[3] = 'F')) then lGenesis := true; if (not lGenesis) then begin dseek(fp, 3178); dBlockRead(fp, tx, 4*SizeOf(Char), n); if ((tx[0] = 'I') AND (tx[1] = 'M')AND (tx[2] = 'G') AND (tx[3] = 'F')) then lGenesis := true; end; if (not lGenesis) then begin dseek(fp, 3180); dBlockRead(fp, tx, 4*SizeOf(Char), n); if ((tx[0] = 'I') AND (tx[1] = 'M')AND (tx[2] = 'G') AND (tx[3] = 'F')) then lGenesis := true; end; if (not lGenesis) then begin //1499K dseek(fp, 0); dBlockRead(fp, tx, 4*SizeOf(Char), n); if ((tx[0] = 'I') AND (tx[1] = 'M')AND (tx[2] = 'G') AND (tx[3] = 'F')) then lGenesis := true; end; end; if (not lGenesis) and (FileSz > 3252) then begin dseek(fp, 3228); dBlockRead(fp, tx, 4*SizeOf(Char), n); if (tx[0] = 'I') AND (tx[1]= 'M') AND (tx[2] = 'G')AND (tx[3]= 'F') then lGenesis := true; end; if lGenesis then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_ge_data(lDICOMdata, lHdrOK, lImageFormatOK,lDynStr,lFileName); exit; end; end; //AutodetectGenesis xxDCIM if (lAutoDetectInterfile) and (FileSz > 256) and (not lDICM_at_128) then begin if Copy(extractfilename(lFileName), 1, 4) = 'COR-' then begin lStr := extractfiledir(lFilename) + '\COR-.info'; TmpStr := extractfiledir(lFilename) + '\COR-128'; if fileexists(lStr) and fileexists(TmpStr) then begin lFilename := TmpStr; lDynStr := 'FreeSurfer COR format' + kCR+'Only displaying image 128'+kCR+'Use MRIcro''s Import menu to convert this image'+kCR; with lDicomData do begin little_endian := 0; // don't care ImageStart := 0; Allocbits_per_pixel := 8; XYZdim[1] := 256; XYZdim[2] := 256; XYZdim[3] := 1; XYZmm[1] := 1; XYZmm[2] := 1; XYZmm[3] := 1; //xStoredbits_per_pixel:= Allocbits_per_pixel; END; //WITH lHdrOK := True; lImageFormatOK := True; exit; end; //COR-.info file exists end; //if filename is COR- //start TIF //TIF IMAGES DO NOT ALWAYS HAVE EXTENSION if (TmpStr = '.TIF') or (TmpStr = '.TIFF') then begin dseek(fp, 0); lWord := read16(fp,lrOK); if lWord = $4d4d then lDICOMdata.little_endian := 0 else if lWord = $4949 then lDICOMdata.little_endian := 1; //dseek(fp, 2); lWord2 := read16(fp,lrOK); //bits per pixel if ((lWord=$4d4d) or (lWord=$4949)) and (lWord2 = $002a) then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_tiff_data(lDICOMdata, lReadECAToffsetTables, lHdrOK, lImageFormatOK, lDynStr, lFileName); //if lHdrOk then exit; exit; end;//TIF signature //end; //.TIF extension //end TIF //start BMP 1667 TmpStr := string(StrUpper(PChar(ExtractFileExt(lFileName)))); if TmpStr = '.BMP' then begin dseek(fp, 0); lWord := read16(fp,lrOK); dseek(fp, 28); lWord2 := read16(fp,lrOK); //bits per pixel if (lWord=19778) and (lWord2 = 8) then begin //bitmap signature dseek(fp, 10); lDicomData.ImageStart := read32(fp,lrOK);//1078; dseek(fp, 18); lDicomData.XYZdim[1] := read32(fp,lrOK); //dseek(fp, 22); lDicomData.XYZdim[2] := read32(fp,lrOK); lDicomData.XYZdim[3] := 1;//read16(fp,lrOK); lDicomData.Allocbits_per_pixel := 8;//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; lDynStr := 'BMP format'; CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write lHdrOK := true; lImageFormatOK:= true; exit; end;//bmp signature end; //.BMP extension //end BMP if TmpStr = '.VOL' then begin //start SPACE vol format 1382 dseek(fp, 0); dBlockRead(fp, tx, 6*SizeOf(Char), n); if (tx[0] = 'm') and (tx[1] = 'd') and (tx[2] = 'v') and (tx[3] = 'o') and (tx[4] = 'l') and (tx[5] = '1') then begin lDicomData.ImageStart := read32(fp,lrOK);//1078; lDICOMdata.little_endian := 1; lDicomData.XYZdim[1] := read32(fp,lrOK); lDicomData.XYZdim[2] := read32(fp,lrOK); lDicomData.XYZdim[3] := read32(fp,lrOK); lDicomData.XYZmm[1] := read32r(fp,lrOK); lDicomData.XYZmm[2] := read32r(fp,lrOK); lDicomData.XYZmm[3] := read32r(fp,lrOK); lDicomData.Allocbits_per_pixel := 8;//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; lDynStr := 'Space VOL format'; CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write lHdrOK := true; lImageFormatOK:= true; exit; end;//vol signature end; //.VOL extension //end space .VOL format //start DF3 PovRay DF3 density files if (TmpStr = '.DF3') then begin dseek(fp, 0); lWord := swap (read16(fp,lrOK)); lWord2 := swap (read16(fp,lrOK)); lWord3 := swap (read16(fp,lrOK)); //note: I assume all df3 headers are little endian. is this always true? if not, unswapped values could be tested for filesize lMatrixSz := (lWord*lWord2*lWord3)+6; if (lMatrixSz=FileSz)then begin //df3 signature lDicomData.ImageStart := 6;//1078; lDicomData.XYZdim[1] := lWord; //dseek(fp, 22); lDicomData.XYZdim[2] := lWord2; lDicomData.XYZdim[3] := lWord3; lDicomData.Allocbits_per_pixel := 8;//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write lDynStr := 'PovRay DF3 density format'; lHdrOK := true; lImageFormatOK:= true; exit; end;//df3 signature end; //end df3 //start .PGM if (TmpStr = '.PGM') or (TmpStr = '.PPM') then begin dseek(fp, 0); lWord := read16(fp,lrOK); if (lWord=13648){'P5'=1x8BIT GRAYSCALE} or (lWord=13904) {'P6'=3x8bit RGB} then begin //bitmap signature {repeat PGMreadStr(lDicomData.XYZdim[1],lDicomData.XYZdim[2]); until (lDicomData.XYZdim[2] > 0) ;} lDicomData.XYZdim[1] := PGMreadInt; lDicomData.XYZdim[2] := PGMreadInt; PGMreadInt; //read maximum value lDicomData.XYZdim[3] := 1;//read16(fp,lrOK); lDicomData.Allocbits_per_pixel := 8;//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; lDicomData.ImageStart := dFilepos(fp); if lWord = 13904 then begin//RGB //xlDicomData.SamplesPerPixel := 3; //xlDicomData.PlanarConfig := 0;//RGBRGBRGB..., not RRR..RGGG..GBBB...B end; lDynStr:='PGM/PPM format 8-bit grayscale image [data saved in binary, not ASCII format]'; CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write lHdrOK := true; lImageFormatOK:= true; exit; end else if (lWord=12880){'P2'=1x8BIT ASCII} or (lWord=13136) {'P3'=3x8bit ASCI} then begin dcmMsg('Warning: this image appears to be an ASCII ppm/pgm image. This software can only read binary ppm/pgm images'); end;//pgm/ppm binary signature signature end; //.PPM/PGM extension //end .pgm //start BioRadPIC 1667 if TmpStr = '.PIC' then begin dseek(fp, 54); lWord := read16(fp,lrOK); if (lWord=12345) then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_biorad_data(lDICOMdata, lHdrOK, lImageFormatOK,lDynStr,lFileName); exit; end;//biorad signature end; //.PIC extension biorad? //end BIORAD PIC if TmpStr = '.HEAD' then begin read_afni_data(lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName,lRot1,lRot2,lRot3); if (lHdrOK) and (lImageFormatOK) then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write exit; end; end; dseek(fp, 0); dBlockRead(fp, tx, 20*SizeOf(Char), n); if (tx[0] = 'n') and (tx[1] = 'c') and (tx[2] = 'a') and (tx[3] = 'a') then begin //SUN Vision File Format = .vff CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_vff_data(lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName); exit; end; liPos := 1; lStr :=''; {999 While (liPos <= 20) and (lStr <> 'INTERFILE') do begin if tx[liPos] in ['i','n','t','e','r', 'f','i','l','e','I','N','T','E','R', 'F','I','L','E'] then lStr := lStr+upcase(tx[liPos]); inc(liPos); end; } if lStr = 'INTERFILE' then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_interfile_data(lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName); if lHdrOk then exit; exit; end; //'INTERFILE' in first 20 char end;//detectint // try DICOM part 10 i.e. a 128 byte file preamble followed by "DICM" if filesz <= 300 then goto 666; {begin siemens somatom: DO THIS BEFORE MAGNETOM: BOTH HAVE 'SIEMENS' SIGNATURE, SO CHECK FOR 'SOMATOM'} if filesz = 530432 then begin dseek(fp, 281); dBlockRead(fp, tx, 8*SizeOf(Char), n); if (tx[0] = 'S') and (tx[1] = 'O') and (tx[2] = 'M') and (tx[3] = 'A') and (tx[4] = 'T') and (tx[5] = 'O') and (tx[6] = 'M') then begin lDicomData.ImageStart := 6144; lDicomData.Allocbits_per_pixel := 16; //xlDicomData.Storedbits_per_pixel := 16; lDicomData.little_endian := 0; lDicomData.XYZdim[1] := 512; lDicomData.XYZdim[2] := 512; lDicomData.XYZdim[3] := 1; dSeek(fp,5999); //Study/Image from 5292 "STU/IMA 1070/16" lDicomData.AcquNum := trunc(SomaTomFloat);//Slice Thickness from 5790 "SL 3.0" lDicomData.ImageNum := trunc(SomaTomFloat);//Slice Thickness from 5790 "SL 3.0" dSeek(fp,5792); //Slice Thickness from 5790 "SL 3.0" lDicomData.XYZmm[3] := SomaTomFloat;//Slice Thickness from 5790 "SL 3.0" dSeek(fp,5841); //Field of View from 5838 "FoV 281" lDicomData.XYZmm[1] := SomaTomFloat; //Field of View from 5838 "FoV 281" lDicomData.XYZmm[2] := lDicomData.XYZmm[1]/lDicomData.XYZdim[2];//do mm[2] first before FOV is overwritten lDicomData.XYZmm[1] := lDicomData.XYZmm[1]/lDicomData.XYZdim[1]; if lVerboseRead then lDynStr := 'Siemens Somatom Format'+kCR+ 'Image Series/Number: '+inttostr(lDicomData.AcquNum)+'/'+inttostr(lDicomData.ImageNum)+kCR+ 'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'XYZ mm:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2); CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write lImageFormatOK := true; lHdrOK := true; exit; end; //signature found end; //correctsize for somatom {end siemens somatom} {siemens magnetom} dseek(fp,96); dBlockRead(fp, tx, 7*SizeOf(Char), n); if (tx[0] = 'S') and (tx[1] = 'I') and (tx[2] = 'E') and (tx[3] = 'M') and (tx[4] = 'E') and (tx[5] = 'N') and (tx[6] = 'S') then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_siemens_data(lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName); exit; end; {end siemens magnetom vision} {siemens somatom plus} dseek(fp, 0); dBlockRead(fp, tx, 8*SizeOf(Char), n); if (tx[0] = 'S') and (tx[1] = 'I') and (tx[2] = 'E') and (tx[3] = 'M') and (tx[4] = 'E') and (tx[5] = 'N') and (tx[6] = 'S') then begin lDicomData.ImageStart := 8192; lDicomData.Allocbits_per_pixel := 16; //xlDicomData.Storedbits_per_pixel := 16; lDicomData.little_endian := 0; dseek(fp, 1800); //slice thickness lDicomData.XYZmm[3] := read64(fp,lrOK); dseek(fp, 4100); lDicomData.AcquNum := read32(fp,lrOK); dseek(fp, 4108); lDicomData.ImageNum := read32(fp,lrOK); dseek(fp, 4992); //X FOV lDicomData.XYZmm[1] := read64(fp,lrOK); dseek(fp, 5000); //Y FOV lDicomData.XYZmm[2] := read64(fp,lrOK); dseek(fp, 5340); lDicomData.XYZdim[1] := read32(fp,lrOK); dseek(fp, 5344); lDicomData.XYZdim[2] := read32(fp,lrOK); lDicomData.XYZdim[3] := 1; if lDicomData.XYZdim[1] > 0 then lDicomData.XYZmm[1] := lDicomData.XYZmm[1]/lDicomData.XYZdim[1]; if lDicomData.XYZdim[2] > 0 then lDicomData.XYZmm[2] := lDicomData.XYZmm[2]/lDicomData.XYZdim[2]; if lVerboseRead then lDynStr := 'Siemens Somatom Plus Format'+kCR+ 'Image Series/Number: '+inttostr(lDicomData.AcquNum)+'/'+inttostr(lDicomData.ImageNum)+kCR+ 'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'XYZ mm:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2); CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write lImageFormatOK := true; lHdrOK := true; exit; end; {end siemens somatom plus } {picker} dseek(fp,0); dBlockRead(fp, tx, 8*SizeOf(Char), n); if (tx[0]='C') and (tx[1]='D') and (tx[2]='F') and (ord(tx[3]) = 1) then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_minc_data(lDICOMdata, lHdrOK, lImageFormatOK,lDynStr,lFileName); exit; end; if (lAutoDECAT7) and (tx[0]='M') and (tx[1]='A') and (tx[2]='T') and (tx[3]='R') and (tx[4]='I') and (tx[5]='X') then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_ecat_data(lDICOMdata, lVerboseRead,lReadECAToffsetTables,lHdrOK, lImageFormatOK, lDynStr, lFileName); exit; end; if (tx[0] = '*') AND (tx[1] = '*') AND (tx[2] = '*') AND (tx[3] = ' ') then begin {picker Standard} CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_picker_data(lVerboseRead,lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName); exit; end; {not picker standard} //Start Picker Prism ljunk := filesz-2048; lDICOMdata.little_endian := 0; //start: read x dseek(fp, 322); Width := read16(fp,lrOK); //start: read y dseek(fp, 326); Ht := read16(fp,lrOK); lMatrixSz := Width * Ht; //check if correct filesize for picker prism if (ord(tx[0]) = 1) and (ord(tx[1])=2) and ((ljunk mod lMatrixSz)=0){128*128*2bytes = 32768} then begin //Picker PRISM lDicomData.little_endian := 0; lDicomData.XYZdim[1] := Width; lDicomData.XYZdim[2] := Ht; lDicomData.XYZdim[3] := (ljunk div 32768); {128*128*2bytes = 32768} lDicomData.Allocbits_per_pixel := 16; //xlDicomData.Storedbits_per_pixel := 16; lDicomData.ImageStart := 2048; //start: read slice thicness dseek(fp,462); dBlockRead(fp, tx, 12*SizeOf(Char), n); lStr := ''; for ljunk := 0 to 11 do if tx[ljunk] in ['0'..'9','.'] then lStr := lStr+ tx[ljunk]; if lStr <> '' then lDicomData.XYZmm[3] := strtofloat(lStr); //start: voxel size dseek(fp,594); dBlockRead(fp, tx, 12*SizeOf(Char), n); lStr := ''; for ljunk := 0 to 11 do if tx[ljunk] in ['0'..'9','.'] then lStr := lStr+ tx[ljunk]; if lStr <> '' then lDicomData.XYZmm[1] := strtofloat(lStr); lDicomData.XYZmm[2] := lDicomData.XYZmm[1]; //end: read voxel sizes //start: patient name dseek(fp,26); dBlockRead(fp, tx, 22*SizeOf(Char), n); lStr := ''; ljunk := 0; while (ljunk < 22) and (ord(tx[ljunk]) <> 0) do begin lStr := lStr+ tx[ljunk]; inc(ljunk); end; lDicomData.PatientName := lStr; //start: patient ID dseek(fp,48); dBlockRead(fp, tx, 15*SizeOf(Char), n); lstr := ''; ljunk := 0; while (ljunk < 15) and (ord(tx[ljunk]) <> 0) do begin lstr := lstr+ tx[ljunk]; inc(ljunk); end; //xlDicomData.PatientID := lStr; //start: scan time dseek(fp,186); dBlockRead(fp, tx, 25*SizeOf(Char), n); lstr := ''; ljunk := 0; while (ljunk < 25) and (ord(tx[ljunk]) <> 0) do begin lstr := lstr+ tx[ljunk]; inc(ljunk); end; //start: scanner type dseek(fp,2); dBlockRead(fp, tx, 25*SizeOf(Char), n); lgrpstr := ''; ljunk := 0; while (ljunk < 25) and (ord(tx[ljunk]) <> 0) do begin lgrpstr := lgrpstr+ tx[ljunk]; inc(ljunk); end; //report results if lVerboseRead then lDynStr := 'Picker Format '+lgrpstr+kCR+ 'Patient Name: '+lDicomData.PatientName+kCR+ //x'Patient ID: '+lDicomData.PatientID+kCR+ 'Scan Time: '+lStr+kCR+ 'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'XYZ mm:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2); CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write lImageFormatOK := true; lHdrOK := true; exit; end; //end Picker PRISM lMatrixSz := 0; lDICOMdata.little_endian := 1; lBig := false; dseek(fp, {0}128); //where := FilePos(fp); dBlockRead(fp, tx, 4*SizeOf(Char), n); if (tx[0] <> 'D') OR (tx[1] <> 'I') OR (tx[2] <> 'C') OR (tx[3] <> 'M') then begin //if filesz > 132 then begin dseek(fp, 0{128}); //skip the preamble - next 4 bytes should be 'DICM' //where := FilePos(fp); dBlockRead(fp, tx, 4*SizeOf(Char), n); //end; if (tx[0] <> 'D') OR (tx[1] <> 'I') OR (tx[2] <> 'C') OR (tx[3] <> 'M') then begin dseek(fp, 0); group := read16(fp,lrOK); if not lrOK then goto 666; if group > $0008 then begin group := swap(group); lBig := true; end; if NOT (group in [$0000, $0001, $0002,$0003, $0004, $0008]) then // one more group added begin goto 666; end; dseek(fp, 0); //dcmMsg('DICM not at 0 or 128: ' +lFilename); end; end; //else dcmMsg('DICM at 128{0}');; time_to_quit := FALSE; lProprietaryImageThumbnail := false; explicitVR := false; tmpstr := ''; tmp := 0; while NOT time_to_quit do begin t := unknown; where := dFilePos(fp); lFirstPass := true; 777: group := read16(fp,lrOK); if (lSwitchToImplicitAfterGroup0002) and (group > 0002) then begin lSwitchToImplicitAfterGroup0002 := false; explicitVR := false; end; if not lrOK then goto 666; if (lFirstPass) and (group = 2048) then begin if lDicomData.little_endian = 1 then lDicomData.Little_endian := 0 else lDicomData.little_endian := 1; dseek(fp,where); lFirstPass := false; goto 777; end; element := read16(fp,lrOK); if not lrOK then goto 666; e_len:= read32(fp,lrOK); if not lrOK then goto 666; lGrpStr := ''; lt0 := e_len and 255; lt1 := (e_len shr 8) and 255; lt2 := (e_len shr 16) and 255; lt3 := (e_len shr 24) and 255; if (explicitVR) and (lT0=13) and (lT1=0) and (lT2=0) and (lT3=0) then e_len := 10; //hack for some GE Dicom images if explicitVR or first_one then begin if group = $FFFE then else //1384 - ACUSON images switch off ExplicitVR for file image fragments if ((lT0=kO) and (lT1=kB)) or ((lT0=kU) and (lT1=kN)){<-UN added 11/11/2011} or ((lT0=kO) and (lT1=kW)) or ((lT0=kS) and (lT1=kQ)) {11/11 add UT}or ((lT0=kU) and (lT1=kT)) then begin lGrpStr := chr(lT0)+chr(lT1); e_len:= read32(fp,lrOK); if not lrOK then goto 666; if first_one then explicitVR := true; end else if ((lT3=kO) and (lT2=kB)) or ((lT3=kU) and (lT2=kN)){<-UN added 11/11/2011} or((lT3=kO) and (lT2=kW)) or ((lT3=kS) and (lT2=kQ)) or ((lT3=kU) and (lT2=kT))then begin e_len:= read32(fp,lrOK); if not lrOK then goto 666; if first_one then explicitVR := true; end else if ( ((lT0=kA) and (lT1=kE)) or ((lT0=kA) and (lT1=kS)) or ((lT0=kA) and (lT1=kT)) or ((lT0=kC) and (lT1=kS)) or ((lT0=kD) and (lT1=kA)) or ((lT0=kD) and (lT1=kS)) or ((lT0=kD) and (lT1=kT)) or ((lT0=kF) and (lT1=kL)) or ((lT0=kF) and (lT1=kD)) or ((lT0=kI) and (lT1=kS)) or ((lT0=kL) and (lT1=kO))or ((lT0=kL) and (lT1=kT)) or ((lT0=kP) and (lT1=kN)) or ((lT0=kS) and (lT1=kH)) or ((lT0=kS) and (lT1=kL)) or ((lT0=kS) and (lT1=kS)) or ((lT0=kS) and (lT1=kT)) or ((lT0=kT) and (lT1=kM)) or ((lT0=kU) and (lT1=kI)) or ((lT0=kU) and (lT1=kL)) or ((lT0=kU) and (lT1=kS)) or ((lT0=kA) and (lT1=kE)) or ((lT0=kA) and (lT1=kS)) ) then begin lGrpStr := chr(lT0) + chr(lT1); if lDicomData.little_endian = 1 then e_len := (e_len and $ffff0000) shr 16 else e_len := swap((e_len and $ffff0000) shr 16); if first_one then begin explicitVR := true; end; end else if ( ((lT3=kA) and (lT2=kT)) or ((lT3=kC) and (lT2=kS)) or ((lT3=kD) and (lT2=kA)) or ((lT3=kD) and (lT2=kS)) or ((lT3=kD) and (lT2=kT)) or ((lT3=kF) and (lT2=kL)) or ((lT3=kF) and (lT2=kD)) or ((lT3=kI) and (lT2=kS)) or ((lT3=kL) and (lT2=kO))or ((lT3=kL) and (lT2=kT)) or ((lT3=kP) and (lT2=kN)) or ((lT3=kS) and (lT2=kH)) or ((lT3=kS) and (lT2=kL)) or ((lT3=kS) and (lT2=kS)) or ((lT3=kS) and (lT2=kT)) or ((lT3=kT) and (lT2=kM)) or ((lT3=kU) and (lT2=kI)) or ((lT3=kU) and (lT2=kL)) or ((lT3=kU) and (lT2=kS))) then begin if lDicomData.little_endian = 1 then e_len := (256 * lT0) + lT1 else e_len := (lT0) + (256*lT1); if first_one then begin explicitVR := true; end; end; end; //not first_one or explicit if (first_one) and (lDicomdata.little_endian =0) and (e_len = $04000000) then begin dcmMsg('Switching to little endian'); lDicomData.little_endian := 1; dseek(fp, where); first_one := false; goto 777; end else if (first_one) and (lDicomData.little_endian =1) and (e_len = $04000000) then begin dcmMsg('Switching to little endian'); lDicomData.little_endian := 0; dseek(fp, where); first_one := false; goto 777; end; if e_len = ($FFFFFFFF) then begin e_len := 0; end; if lGELX then begin e_len := e_len and $FFFF; end; first_one := false; remaining := e_len; info := '?'; tmpstr := ''; if (lIndent > 0) and (not ((group= $FFFE) and (element = $E0DD))) and (not lManufacturerIsPhilips) then //Philips stores slice positioning inside 0020,9113; lice orientation inside 0020,9116 but Siemens stores thumbnails in indented subheadings goto 1234; case group of $0001 : // group for normal reading elscint DICOM case element of $0010 : info := 'Name'; $1001 : info := 'Elscint info'; end; $0002 : case element of $00 : info := 'File Meta Elements Group Len'; $01 : info := 'File Meta Info Version'; $02 : info := 'Media Storage SOP Class UID'; $03 : info := 'Media Storage SOP Inst UID'; $10 : begin //lTransferSyntaxReported := true; info := 'Transfer Syntax UID'; TmpStr := ''; if dFilePos(fp) > (filesz-e_len) then goto 666; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for i := 0 to e_len-1 do if Char(buff[i]) in ['+','-',' ', '0'..'9','a'..'z','A'..'Z'] then TmpStr := TmpStr +(Char(buff[i])) else TmpStr := TmpStr +('.'); FreeMem( buff); lStr := ''; //dcmMsg(TmpStr); if TmpStr = '1.2.840.113619.5.2' then begin lGELX := true; LBigSet := true; lBig := true; end; // if length(TmpStr) < 19 then begin //12/2010 assume 1.2.840.10008.1.2 //Raw data, Implicit VR, Little Endian // explicitVR := false; //china lSwitchToImplicitAfterGroup0002 := true; end; if length(TmpStr) >= 19 then begin if TmpStr[19] = '1' then begin lBigSet:= true; explicitVR := true; //duran lBig := false; end else if TmpStr[19] = '2' then begin lBigSet:= true; explicitVR := true; //duran lBig := true; end else if TmpStr[19] = '4' then begin if length(TmpStr) >= 21 then begin //Dec 2012.... dcm2nii can handle JPEG 123456 if {not lReadJPEGtables} false then begin lImageFormatOK := false; end else begin i := strtoint(TmpStr[21]+TmpStr[22]); if (i <> 57) and (i <> 70) then begin lImageFormatOK := false; //lDicomData.JPEGLossyCpt := true end else begin //lImageFormatOK := false;//123456 lDicomData.JPEGLosslessCpt := true; end; end; end else begin lImageFormatOK := false; end; end else if TmpStr[19] = '5' then begin lImageFormatOK := false;//xlDicomData.RunLengthEncoding := true; end else begin lImageFormatOK := false; end; if not lImageFormatOK then dcmMsg('Unsupported Transfer Syntax '+(TmpStr)+' Solution: use MRIcro'); end; {length} remaining := 0; e_len := 0; {use tempstr} end; $12 : begin info := 'Implementation Class UID'; end; $13 : begin info := 'Implementation Version Name'; if e_len > 4 then begin TmpStr := ''; DICOMHeaderString(TmpStr); //lDicomData.ImplementationVersion := Str2Int(TmpStr); if TmpStr = 'OSIRIX' then lOsirix0002_0013 := true; if TmpStr = 'MEDIFACE 1 5' then lMediface0002_0013 := true; //detect MEDIFACE 1.5 error: error in length of two elements 0008:1111 and 0008:1140 end; //length > 4 end; //element 13 $16 : info := 'Source App Entity Title'; $100: info := 'Private Info Creator UID'; $102: info := 'Private Info'; end; $0008 : case element of $00 : begin info := 'Identifying Group Length'; end; $01 : info := 'Length to End'; $05 : info := 'Specific Character Set'; $08 : begin info := 'Image Type'; if dFilePos(fp) > (filesz-e_len) then goto 666; lSiemensMosaic0008_0008:= false; if (e_len >= 6) then begin //search for 'MOSAIC' GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); i := e_len -6;//MOSAIC while (i>-1) and (not lSiemensMosaic0008_0008) do begin if (upcase(Char(buff[i])) = 'M') and (upcase(Char(buff[i+1])) = 'O') and (upcase(Char(buff[i+2])) = 'S') and (upcase(Char(buff[i+3])) = 'A') and (upcase(Char(buff[i+4])) = 'I') and (upcase(Char(buff[i+5])) = 'C') then //strip filler characters: DICOM elements must be padded for even length lSiemensMosaic0008_0008 := true; dec(i); end; FreeMem( buff); remaining := 0; e_len := 0; {use tempstr} end; end; $10 : info := 'Recognition Code'; $12 : info := 'Instance Creation Date'; $13 : info := 'Instance Creation Time'; $14 : info := 'Instance Creator UID'; $16 : info := 'SOP Class UID'; $18 : info := 'SOP Instance UID'; $20 : begin info := 'Study Date'; //lDicomData.StudyDatePos := dFilePos(fp); DICOMHeaderString(lDicomData.StudyDate); end; $21 : info := 'Series Date'; $22 : info := 'Acquisition Date'; $23 : info := 'Image Date'; $30 : begin info := 'Study Time'; DICOMHeaderStringTime(lDicomData.StudyTime); end; $31 : info := 'Series Time'; $32 : begin info := 'Acquisition Time'; DICOMHeaderStringTime(TmpStr); lDicomData.SecSinceMidnight := SecSinceMidnightFloat(TmpStr); end; $33 : begin info := 'Image Time'; //xxDICOMHeaderStringTime(lDicomData.ImgTime); end; $40 : info := 'Data Set Type'; $41 : info := 'Data Set Subtype'; $50 : begin //xDICOMHeaderStringtoInt(lDicomData.accession); info := 'Accession Number'; end; $60 : begin info := 'Modality'; t := _string; end; $64 : begin info := 'Conversion Type'; t := _string; end; $70 : begin info := 'Manufacturer'; //Only read last word, e.g. 'TYPE\MOSAIC' will be read as 'MOSAIC' TmpStr := ''; if dFilePos(fp) > (filesz-e_len) then goto 666; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); i := e_len -1; while (i>-1) and (Char(buff[i]) in ['a'..'z','A'..'Z',' ']) do begin if (Char(buff[i])) <> ' ' then //strip filler characters: DICOM elements must be padded for even length TmpStr := upcase(Char(buff[i]))+TmpStr; dec(i); end; FreeMem( buff); remaining := 0; e_len := 0; {use tempstr} if (length(TmpStr) > 3) and (TmpStr[1]='P') and (TmpStr[2]='H') and (TmpStr[3]='I') then lManufacturerIsPhilips := true; if (length(TmpStr) > 3) and (TmpStr[1]='B') and (TmpStr[2]='R') and (TmpStr[3]='U') then lManufacturerIsBruker := true; if lManufacturerIsPhilips then lDicomData.ManufacturerID := kPhilipsID; if (length(TmpStr) > 3) and (TmpStr[1]='G') and (TmpStr[2]='E') then lDicomData.ManufacturerID := kGEID; if (length(TmpStr) > 3) and (TmpStr[1]='S') and (TmpStr[2]='I') and (TmpStr[3]='E') then lDicomData.ManufacturerID := kSiemensID; end; $80 : info := 'Institution Name'; $81 : info := 'City Name'; $90 : info := 'Referring Physician''s Name'; $100: info := 'Code Value'; $102 : begin info := 'Coding Schema Designator'; t := _string; end; $104: info := 'Code Meaning'; $1010: info := 'Station Name'; $1030: begin info := 'Study Description'; t := _string; end; $103e: begin info := 'Series Description'; t := _string; end; $1040: info := 'Institutional Dept. Name'; $1050: info := 'Performing Physician''s Name'; $1060: info := 'Name Phys(s) Read Study'; $1070: begin info := 'Operator''s Name'; t := _string; end; $1080: info := 'Admitting Diagnosis Description'; $1090: begin info := 'Manufacturer''s Model Name';t := _string; end; $1111: begin if lMediface0002_0013 then E_LEN := 8;//+e_len; end; //ABBA: patches error in DICOM images seen from Sheffield 0002,0013=MEDIFACE.1.5; 0002,0016=PICKER.MR.SCU $1140: begin if (lMediface0002_0013) and (E_LEN > 255) then E_LEN := 8; end; //ABBA: patches error in DICOM images seen from Sheffield 0002,0013=MEDIFACE.1.5; 0002,0016=PICKER.MR.SCU $2111: info := 'Derivation Description'; $2120: info := 'Stage Name'; $2122: begin info := 'Stage Number';t := _string; end; $2124: begin info := 'Number of Stages';t := _string; end; $2128: begin info := 'View Number';t := _string; end; $212A: begin info := 'Number of Views in stage';t := _string; end; $2204: info := 'Transducer Orientation'; $9208: begin info := 'ComplexImageComponent'; TmpStr := ''; DICOMHeaderString(TmpStr); i := 0; if length(TmpStr) >= 2 then begin if (TmpStr[1] = 'M') and (TmpStr[2] = 'A') then i := 1; //magnitude if (TmpStr[1] = 'P') and (TmpStr[2] = 'H') then i := 2; //phase if (TmpStr[1] = 'R') and (TmpStr[2] = 'E') then i := 3; //real if (TmpStr[1] = 'I') and (TmpStr[2] = 'M') then i := 4; //imaginary end; //mixed will be followed by subsequent settings, so do not use it here.... if (i > 0) and (lDICOMdata.nOrder < kMaxOrderVal) then begin inc(lDICOMdata.nOrder); //dcmMsg(TmpStr); lDICOMdata.order[lDICOMdata.nOrder] := i; end; (*[ magnitude * MAGNITUDE [ phase * PHASE [ real * REAL [ imaginary * IMAGINARY [ mixed * MIXED*) ///xxx xxx end; end; $0009: if element = $0010 then begin if e_len > 4 then begin TmpStr := ''; if dFilePos(fp) > (filesz-e_len) then goto 666; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); i := e_len -1; while (i>-1) {and (Char(buff[i]) in ['a'..'z','A'..'Z',' '])} do begin if (Char(buff[i])) in ['a'..'z','A'..'Z'] then //strip filler characters: DICOM elements must be padded for even length TmpStr := upcase(Char(buff[i]))+TmpStr; dec(i); end; FreeMem( buff); remaining := 0; if (Length(TmpStr)>4) and (TmpStr[1]='M') and (TmpStr[2]='E') and (TmpStr[3]='R') and (TmpStr[4]='G') then lOldSiemens_IncorrectMosaicMM := true; //detect MERGE technologies mosaics e_len := 0; {use tempstr} end; end; $0010 : case element of $00 : info := 'Patient Group Length'; $10 : begin info := 'Patient''s Name'; t := _string; //xlDicomData.NamePos := dFilePos(fp); DICOMHeaderString(lDicomData.PatientName); end; $20 : begin info := 'Patient ID'; //xDICOMHeaderString(lDicomData.PatientID); //xlDicomData.PatientIDInt := safestrtoint(lDicomData.PatientID); end; //11/2010 //$30: info := 'Date of Birth'; //"Age String" type: e.g 067y for 67 years old, 067d for 67 days $30 : begin info := 'DoB'; t := _string; //xlDicomData.NamePos := dFilePos(fp); //lDicomData.PatientDoB := '1111'; DICOMHeaderString(lDicomData.PatientDoB); end; $32 : info := 'Patient Birth Time'; //$40 : begin info := 'Patient Sex'; t := _string; end; $40 : begin info := 'Gender'; t := _string; //xlDicomData.NamePos := dFilePos(fp); DICOMHeaderString(lDicomData.PatientGender); end; $1000: info := 'Other Patient IDs'; $1001: info := 'Other Patient Names'; $1005: info := 'Patient''s Birth Name'; $1010: begin info := 'Patient Age'; t := _string; end; $1030: info := 'Patient Weight'; $21b0: begin info := 'Additional Patient History'; DICOMHeaderString(lDicomData.PatientHx); end ; $4000: info := 'Patient Comments'; end; $0018 : case element of $00 : info := 'Acquisition Group Length'; $10 : begin info := 'Contrast/Bolus Agent'; t := _string; end; $15: info := 'Body Part Examined'; $20 : begin info := 'Scanning Sequence';t := _string; TmpStr := ''; DICOMHeaderString(TmpStr); lDICOMdata.ScanningSequence0018_0020 := TmpStr; if TmpStr = 'RM' then lResearchMode := true; end; $21 : begin info := 'Sequence Variant';t := _string; end; $22 : info := 'Scan Options'; $23 : begin info := 'MR Acquisition Type'; t := _string; end; $24 : info := 'Sequence Name'; $25 : begin info := 'Angio Flag';t := _string; end; $30 : info := 'Radionuclide'; $50 : begin info := 'Slice Thickness'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDICOMdata.XYZmm[3] := lfloat1; lThickness := lfloat1;//lDICOMdata.Thickness := lfloat1; //1391b end; //$60: begin info := 'KVP [Peak Output, KV]'; t := _string; end; //aqw $60: begin info := 'KVP [Peak KV]'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDicomData.kV := lFloat1; end; $70: begin t := _string; info := 'Counts Accumulated'; end; $71: begin t := _string; info := 'Acquisition Condition'; end; //$80 : begin info := 'Repetition Time'; t := _string; end; //aqw //$81 : begin info := 'Echo Time'; t := _string; end; //aqw $80 : begin info := 'Repetition Time [TR, ms]'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDicomData.TR := lFloat1; end; $81 : begin info := 'Echo Time [TE, ms]'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDicomData.TE := lFloat1; end; $82 : begin t := _string; info := 'Inversion Time';end; $83 : begin t := _string; info := 'Number of Averages'; end; $84 : info := 'Imaging Frequency'; $85 : begin info := 'Imaged Nucleus'; t := _string; end; $86 : begin info := 'Echo Number';t := _string; DICOMHeaderStringToInt(lEchoNum); //lDICOMdata.Echo := lEchoNum; end; //qq $87 : begin info := 'Magnetic Field Strength'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); lDICOMdata.FieldStrength := round(lfloat1); //xxxdcmMsg(floattostr(lFloat1)); if not lrOK then goto 666; e_len := 0; remaining := 0; //1362 some use this for gap size, others for sum of gap and slicethickness! end; $88 : begin info := 'Spacing Between Slices'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; //1362 some use this for gap size, others for sum of gap and slicethickness! //3333 if (lfloat1 > lDICOMdata.XYZmm[3]) or (lDICOMdata.XYZmm[3]=1) then //lDICOMdata.XYZmm[3] := lfloat1; //fx(lDICOMdata.XYZmm[3],lThickness,lfloat1); if lfloat1 < 0 then lDICOMdata.XYZmm[3] := lFloat1//does not make sense - found in some eFilm images from Marconi P3000 else if ( (lThickness/2) > lfloat1 ) then lDICOMdata.XYZmm[3] := lfloat1+lThickness else lDICOMdata.XYZmm[3] := lfloat1;//1392 //xldicomdata.spacing:=lfloat1; end; $89 : begin // t := _string; info := 'Number of Phase Encoding Steps'; //1499c This is a indirect method for detecting SIemens Mosaics: check if image height is evenly divisible by encoding steps // A real kludge due to Siemens not documenting mosaics explicitly: this workaround may incorrectly think rescaled images are mosaics! readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); lPhaseEncodingSteps := round(lfloat1); //xxxdcmMsg(floattostr(lFloat1)); if not lrOK then goto 666; e_len := 0; remaining := 0; //1362 some use this for gap size, others for sum of gap and slicethickness! //if (lfloat1 > lDICOMdata.XYZmm[3]) or (lDICOMdata.XYZmm[3]=1) then //lDICOMdata.XYZmm[3] := lfloat1; //ldicomdata.spacing:=lfloat1; end; $90 : info := 'Data collection diameter'; $91 : begin info := 'Echo Train Length';t := _string; end; $93: begin info := 'Percent Sampling'; t := _string; end; $94: begin info := 'Percent Phase Field View'; t := _string; end; $95 : begin info := 'Pixel Bandwidth'; t := _string; end; $1000: begin t := _string; info := 'Device Serial Number'; end; $1004: info := 'Plate ID'; $1020: begin info := 'Software Version'; t := _string; if e_len > 2 then begin TmpStr := ''; DICOMHeaderString(TmpStr); lDicomData.Vers0018_1020 := Siemensversion(TmpStr); end; //showdcmMsg(inttostr(lDicomData.Vers0018_1020)+' '+TmpStr); end; $1030: begin info := 'Protocol Name';t := _string; TmpStr := ''; DICOMHeaderString(TmpStr); lDicomData.ProtocolName := TmpStr; AplhaNumericStrDICOM (lDicomData.ProtocolName); end; $1040: info := 'Contrast/Bolus Route'; $1050 : begin t := _string; info := 'Spatial Resolution'; end; $1060: info := 'Trigger Time'; $1062: info := 'Nominal Interval'; $1063: info := 'Frame Time'; $1081: info := 'Low R-R Value'; $1082: info := 'High R-R Value'; $1083: info := 'Intervals Acquired'; $1084: info := 'Intervals Rejected'; $1088: begin info := 'Heart Rate'; t := _string; end; $1090: begin info := 'Cardiac Number of Images'; t := _string; end; $1094: begin info := 'Trigger Window';t := _string; end; $1100: info := 'Reconstruction Diameter'; $1110: info := 'Distance Source to Detector [mm]'; $1111: info := 'Distance Source to Patient [mm]'; $1120: info := 'Gantry/Detector Tilt'; $1130: info := 'Table Height'; $1140: info := 'Rotation Direction'; $1147: info := 'Field of View Shape'; $1149: begin t := _string; info := 'Field of View Dimension[s]'; end; $1150: begin info := 'Exposure Time [ms]'; t := _string; end; $1151: begin info := 'X-ray Tube Current [mA]'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; //xlDicomData.mA := lFloat1; end; $1152 : info := 'Acquisition Device Processing Description'; $1155: info := 'Radiation Setting'; $1160: info := 'Filter Type'; $1164: info :='Imager Pixel Spacing'; $1166: info := 'Grid'; $1170 : info := 'Generator Power'; $1180 : info := 'Collimator/grid Name'; $1190 : begin info := 'Focal Spot[s]'; t := _string; end; $11A0 : begin info := 'Body Part Thickness'; t := _string; end; $11A2 : info := 'Compression Force'; $1200 : info := 'Date of Last Calibration'; $1201 : info := 'Time of Last Calibration'; $1210: info := 'Convolution Kernel'; $1250: begin t := _string; info := 'Receiving Coil'; end; $1251: begin t := _string; info := 'Transmitting Coil'; end; $1260 : begin t := _string; info := 'Plate Type'; end; $1261 : begin t := _string; info := 'Phosphor Type'; end; $1310: begin info := 'Acquisition Matrix'; //Siemens Mosaics converted by Merge can report the incorrect mm //nji2 //NOTE: Matrix Information for MERGE converted images. Used Innocently for other uses by Siemens if (lOldSiemens_IncorrectMosaicMM) or ((lSiemensMosaic0008_0008) and (lMatrixSz < 1){B13}) then begin //TmpStr := ReadStrABC(fp, remaining,lrOK,lA,lB,lC); TmpStr := ReadStr(fp, remaining,lrOK,lMatrixSz); //ss//1362 //fx(remaining); (*kEr := true; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; kEr := false; lMatrixSz := round(lFloat1); dcmMsg(TmpStr); fx(lMatrixSz,lFLoat1,lFloat2,4321);*) {fx(lA,lB,lC); lMatrixSz := lB; lMatrixSzY := lC; } end else TmpStr := ReadStr(fp, remaining,lrOK,lJunk);//1362 if not lrOK then goto 666; e_len := 0; remaining := 0; end; $1312: begin t := _string; info := 'Phase Encoding Direction'; TmpStr := ''; DICOMHeaderString(TmpStr); lDicomData.PhaseEncoding := TmpStr; AplhaNumericStrDICOM (lDicomData.PhaseEncoding); end; $1314: begin t := _string; info := 'Flip Angle'; end; $1315: begin t := _string;info := 'Variable Flip Angle Flag'; end; $1316: begin t := _string;info := 'SAR'; end; $1400: info := 'Acquisition Device Processing Description'; $1401: begin info := 'Acquisition Device Processing Code';t := _string; end; $1402: info := 'Cassette Orientation'; $1403: info := 'Cassette Size'; $1404: info := 'Exposures on Plate'; $1405: begin info := 'Relative X-Ray Exposure'; t := _string; end; $1500: info := 'Positioner Motion'; $1508: info := 'Positioner Type'; $1510: begin info := 'Positioner Primary Angle'; t := _string; end; $1511: info := 'Positioner Secondary Angle'; $5020: info := 'Processing Function'; $5100: begin t := _string; info := 'Patient Position'; TmpStr := ''; DICOMHeaderString(TmpStr); lDicomData.PatientPos := TmpStr; AplhaNumericStrDICOM (lDicomData.PatientPos); end; $5101: begin info := 'View Position';t := _string; end; $6000: begin info := 'Sensitivity'; t := _string; end; $7004: info := 'Detector Type'; $7005: begin info := 'Detector Configuration'; t := _string; end; $7006: info := 'Detector Description'; $700A: info := 'Detector ID'; $700C: info := 'Date of Last Detector Calibration'; $700E: info := 'Date of Last Detector Calibration'; $7048: info := 'Grid Period'; $7050: info := 'Filter Material LT'; $7060: info := 'Exposure Control Mode'; {$IFDEF read00189117} $9117 : begin //SQ //Philips has been inconsistent in reporting DTI tags. This makes archival support difficult //It is unclear if this is intentional obfustication or simply incompetence, but it does mean // that this shameful usage results in code that is unintuitive. //Warning: 0018,9087 is used inconsistently by Philips: sometimes order is 0018,9087;0018,9089 other times 0018,9089;0018,9087 // sometimes if 0018,9087=0 (e.g. B0 scan, with 0018,9075='NONE/0') then 0018,9089 is not included //Therefore, we only use this as a last resort! on Philips, prefer to use 2001,1003+ 2005,10b0/2005,10b1/2005,10b2 if (lUse00189117 = kUndefined) then lUse00189117 := kYes; if (lUse00189117 = kYes) then begin //Overly complicated due to Philips shameful use of these tags if lDICOMdata.nDTIdir < kMaxDTIdir then inc(lDICOMdata.nDTIdir); lDICOMdata.DTI[lDICOMdata.nDTIdir].bval := 0; //Philips may not report vectors for B0 images - so we will initialize these values lDICOMdata.DTI[lDICOMdata.nDTIdir].v1 := 0; lDICOMdata.DTI[lDICOMdata.nDTIdir].v2 := 0; lDICOMdata.DTI[lDICOMdata.nDTIdir].v3 := 0; end; end;//9117 $9087: begin if {(lGrpStr = 'FD') and} (lUse00189117 <> kNo) then begin info := 'Diffusion b-value'; if lDICOMdata.nDTIdir < 1 then //for non-Philips data lDICOMdata.nDTIdir := 1; lDICOMdata.DTI[lDICOMdata.nDTIdir].bval := round(read64 (fp,lrOK)); //if lDICOMdata.DTI[lDICOMdata.nDTIdir].bval = 0 then //only once per volume // Msg ('New feature: diffusion directions extracted from 0018:9089. Please validate bvec values www.mricro.com/mricron/dcm2nii.html'); //dcmMsg('bvalue '+ inttostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].bval)); if not lrOK then goto 666; e_len := 0; remaining := 0; //if (lDICOMdata.nDTIdir >2) and (lDicomData.ManufacturerID = kPhilipsID) then // 2001,1003 // dcmMsg('Warning: DTI data extracted from 0018,9087 and 0018,9089. Please inspect resulting bvec files - some Philips systems use these tags erraticly.'); end; //if lUse00189117 end; //9087 b-values $9089: begin if (lUse00189117 <> kNo) {lGrpStr = 'FD'} then begin //see lUse00189117 info := 'Diffusion Gradient vector [x,y,z]'; if lDICOMdata.nDTIdir < 1 then //for non-Philips data lDICOMdata.nDTIdir := 1; //readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); lDICOMdata.DTI[lDICOMdata.nDTIdir].v1 := read64 (fp,lrOK); if not lrOK then goto 666; lDICOMdata.DTI[lDICOMdata.nDTIdir].v2 := read64 (fp,lrOK); if not lrOK then goto 666; lDICOMdata.DTI[lDICOMdata.nDTIdir].v3 := read64 (fp,lrOK); if not lrOK then goto 666; //dcmMsg('xqas '+inttostr(lDICOMdata.nDTIdir)+' b: '+inttostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].bval)+' v1: '+floattostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].v1)+' '+lFileName); e_len := 0; remaining := 0; end; //if true end; //9089 X/Y/Z diffusion direction {$ENDIF} // read00189117 end; $0019: begin (*case element of //1362 //3/3/2008 this old method for detecting mosaics has a problem - if image is interpolated x2, you will assume a 2x2 mosaic $1220: begin info := 'Matrix';t := _string; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; if lfloat2 > lfloat1 then lfloat1 := lfloat2; lMatrixSz := round(lfloat1); //if >32767 then there will be wrap around if read as signed value! remaining := 0; end; $14D4: begin info := 'Matrix';t := _string; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; if lfloat2 > lfloat1 then lfloat1 := lfloat2; lMatrixSz := round(lfloat1); //if >32767 then there will be wrap around if read as signed value! remaining := 0; end; end; *) //case element if lDicomData.ManufacturerID = kSiemensID then begin case element of //1362 (* $100A: begin //unsigned short $100A info := 'Number Of Images in Mosaic'; tmp := read16(fp,lrOK); if not lrOK then goto 666; fx(e_len,tmp,remaining); end;*) $1028: begin //7/2013 info := 'Siemens BandwidthPerPixelPhaseEncode'; lDICOMdata.BandwidthPerPixelPhaseEncode := read64 (fp,lrOK); if not lrOK then goto 666; e_len := 0; remaining := 0; end; // BandwidthPerPixelPhaseEncode $000C,$100C: begin info := 'Siemens b-value'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; tmpstr := floattostr(lFloat1); lDICOMdata.DTI[1].bval := round(lFloat1); lDICOMdata.SiemensDICOMDTI := true ; end; // b-values $000E,$100E: begin info := 'Siemens Gradient vector [x,y,z]'; //readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); lDICOMdata.DTI[1].v1 := read64 (fp,lrOK); if not lrOK then goto 666; lDICOMdata.DTI[1].v2 := read64 (fp,lrOK); if not lrOK then goto 666; lDICOMdata.DTI[1].v3 := read64 (fp,lrOK); if not lrOK then goto 666; e_len := 0; remaining := 0; end; // X/Y/Z diffusion direction end;//Case element end;//if Siemens if lDicomData.ManufacturerID = kGEID then begin case element of //1362 $10BB,$a0bb: begin info := 'GE Gradient vector [x]'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDICOMdata.DTI[1].v1 := lFloat1; end; // X diffusion direction $10BC,$A0BC: begin info := 'GE Gradient vector [y]'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDICOMdata.DTI[1].v2 := lFloat1; end;//Y diffusion direction $10BD,$A0BD: begin info := 'GE Gradient vector [z]'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDICOMdata.DTI[1].v3 := lFloat1; end;// Z diffusion direction end;//Case element // end;//if GE end;//$0019 $0020 : case element of $00 : info := 'Relationship Group Length'; $0d : info := 'Study Instance UID'; $0e : info := 'Series Instance UID'; $10 : begin info := 'Study ID'; t := _string; end; $11 : begin info := 'Series Number'; DICOMHeaderStringToInt(lDicomData.SeriesNum); end; $12 : // begin info := 'Acquisition Number'; t := _string; end; begin info := 'Acquisition Number'; DICOMHeaderStringToInt(lDicomData.AcquNum); end; $13 : begin info := 'Image Number'; DICOMHeaderStringToInt(lTempInt); if (lDicomData.ImageNum < 2) and (lTempInt >= 0) then lDicomData.ImageNum := lTempInt; //March2008 - some Philips data has multiple image numbers... // 0018,1020,Software Version=1.5.4\1.5.4.3\Gyroscan PMS/DICOM 2.0 MR .Id. datadefs.v 5.27 2004/10/18 06.50 //dcmMsg(inttostr(lDicomData.ImageNum)+lDicomData.Filename); end; $20 : begin info := 'Patient Orientation'; t := _string; end; $30 : info := 'Image Position'; $32 : begin info := 'Image Position Patient'; //June 2009 - for Philips new 4D format we want value from the first slice... if lInside2005140F then begin if not (lPhilipsWarning) then dcmMsg('*User: check slice thickness. Possible Philips R3.2.2 bug - scanner can report different 0020,0032 values for the same slice.'); lPhilipsWarning := true; end else begin //5/2012: Philips R3.2.2 can save two instances of 0020:0032 for each slice: one from voxel center, one from voxel edge. if not lImagePositionPatientRead then begin readfloats3 (fp, remaining, lDummyStr, lDicomData.PatientPosX, lDicomData.PatientPosY,lDicomData.PatientPosZ, lROK); //fx( lDicomData.PatientPosX, lDicomData.PatientPosY,lDicomData.PatientPosZ,56789); if not lrOK then goto 666; e_len := 0; remaining := 0; lImagePositionPatientRead := true; //we assume Philips reports the slice thickness correctly.... //an alternative would be to read both 1st and 2nd ImagePositionPatient and //compute the function DICOMinterslicedistance end else begin CheckIntersliceDistance(l4DDistanceBetweenSliceCenters); end; //not 1st read end; //if lInside2005140F //lInside2005140F := false; end; $35 : info := 'Image Orientation'; $37 : begin //nifti info := 'Image Orientation (Patient)'; readfloats6 (fp, remaining, lDummyStr, lDicomData.Orient[1], lDicomData.Orient[2],lDicomData.Orient[3],lDicomData.Orient[4], lDicomData.Orient[5],lDicomData.Orient[6], lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; end; $50 : info := 'Location'; $52 : info := 'Frame of Reference UID'; $91 : info := 'Echo Train Length'; $70 : info := 'Image Geometry Type'; $60 : info := 'Laterality'; $0105 : begin //Apr2007 DICOMHeaderStringToInt(lnVol); //Number of temporal positions=105 end; $1001: info := 'Acquisitions in Series'; $1002: info := 'Images in Acquisition'; $1020: info := 'Reference'; $1040: begin info := 'Position Reference'; t := _string; end; $1041: begin info := 'Slice Location'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; ldicomdata.location:=lfloat1; end; $1070: begin info := 'Other Study Numbers'; t := _string; end; $3401: info := 'Modifying Device ID'; $3402: info := 'Modified Image ID'; $3403: info := 'Modified Image Date'; $3404: info := 'Modifying Device Mfg.'; $3405: info := 'Modified Image Time'; $3406: info := 'Modified Image Desc.'; $4000: begin info := 'Image Comments'; DICOMHeaderString(lDicomData.ImageComments); end; $5000: info := 'Original Image ID'; $5002: info := 'Original Image... Nomenclature'; //$9113: xxxx end; $0021:case element of $104F: begin info :='GE Locations in acquisition'; if lPrefs.UseGE_0021_104F then begin //June 2009 - Thomas Stephan sent me a GE image where this was set to 2, but should have been 1 //I hope removing this does not cause problems with other GE images... if e_len = 2 then begin lDicomData.SlicesPer3DVol := read16(fp,lrOK); e_len := 0; remaining := 0; /// fx(9999, lDicomData.SlicesPer3DVol); end; end; //use 0021_104F end; $1341: begin info :='Siemens Mosaic Slice Count'; DICOMHeaderStringToInt(lDicomData.SiemensSlices); end; $134F: begin //1366 info :='Siemens Order of Slices'; t := _string; lDICOMdata.SiemensInterleaved := 0; //0=no,1=yes,2=undefined //look for "INTERLEAVED" lStr := ''; if dFilePos(fp) > (filesz-e_len) then goto 666; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for i := 0 to e_len-1 do if Char(buff[i]) in ['?','A'..'Z','a'..'z'] then lStr := lStr +upcase(Char(buff[i])); FreeMem( buff); if(lStr[1]= 'I') then lDICOMdata.SiemensInterleaved := 1; //0=no,1=yes,2=undefined e_len := 0; end; end; $0028 : begin case element of $00 : info := 'Image Presentation Group Length'; $02 : begin info := 'Samples Per Pixel'; tmp := read16(fp,lrOK); if not lrOK then goto 666; lDicomData.SamplesPerPixel :=tmp; if e_len > 255 then begin explicitVR := true; //kludge: switch between implicit and explicitVR end; tmpstr := inttostr(tmp); e_len := 0; remaining := 0; end; $04 : begin info := 'Photometric Interpretation'; TmpStr := ''; if dFilePos(fp) > (filesz-e_len) then goto 666; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for i := 0 to e_len-1 do if Char(buff[i]) in [{'+','-',' ', }'0'..'9','a'..'z','A'..'Z'] then TmpStr := TmpStr +(Char(buff[i])); FreeMem( buff); (*xif TmpStr = 'MONOCHROME1' then lDicomdata.monochrome := 1 else if TmpStr = 'MONOCHROME2' then lDicomdata.monochrome := 2 else if (length(TMpStr)> 0) and (TmpStr[1] = 'Y') then lDICOMdata.monochrome := 4 else lDICOMdata.monochrome := 3; *) remaining := 0; e_len := 0; {use tempstr} end; $05 : info := 'Image Dimensions (ret)'; $06 : begin info := 'Planar Configuration'; tmp := read16(fp,lrOK); if not lrOK then goto 666; lDicomData.PlanarConfig :=tmp; remaining := 0; end; $08 : begin //if lPapyrusnSlices < 1 then // if remaining = 2 then begin // tmp := read16(fp,lrOK); // // end else xx DICOMHeaderStringToInt(lDicomData.XYZdim[3]); if lDicomData.XYZdim[3] < 1 then lDicomData.XYZdim[3] := 1; info := 'Number of Frames'; end; $09: begin info := 'Frame Increment Pointer'; TmpStr := ReadStrHex(fp, remaining,lrOK); if not lrOK then goto 666; e_len := 0; remaining := 0; end; $10 : begin info := 'Rows'; lDicomData.XYZdim[2] := read16(fp,lrOK); if not lrOK then goto 666; tmp := lDicomData.XYZdim[2]; remaining := 0; end; $11 : begin info := 'Columns'; lDicomData.XYZdim[1] := read16(fp,lrOK); if not lrOK then goto 666; tmp := lDicomData.XYZdim[1]; remaining := 0; end; $30 : begin info := 'Pixel Spacing'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; //qq //row spacing [y], then column spacing [x]: see part 3 of DICOM e_len := 0; remaining := 0; lDICOMdata.XYZmm[2] := lfloat1; lDICOMdata.XYZmm[1] := lfloat2; end; $31: info := 'Zoom Factor'; $32: info := 'Zoom Center'; $34: begin info :='Pixel Aspect Ratio';t := _string; end; $40: info := 'Image Format [ret]'; $50 : info := 'Manipulated Image [ret]'; $51: info := 'Corrected Image'; $60: begin info := 'Compression Code [ret]';t := _string; end; $100: begin info := 'Bits Allocated'; if remaining = 4 then tmp := read32(fp,lrOK) else tmp := read16(fp,lrOK); //lWord := read16(fp,lrOK); //lWord := read16(fp,lrOK); if not lrOK then goto 666; if tmp = 8 then lDicomData.Allocbits_per_pixel := 8 else if tmp = 12 then lDicomData.Allocbits_per_pixel := 12 else if tmp = 16 then lDicomData.Allocbits_per_pixel := 16 else if tmp = 32 then lDicomData.Allocbits_per_pixel := 32 else if tmp = 24 then begin //xlDicomData.SamplesPerPixel := 3; lDicomData.Allocbits_per_pixel := 8 end else begin lWord := tmp; lWord := swap(lWord); if lWord in [8,12,16,24,32] then begin lDicomData.Allocbits_per_pixel := tmp; lByteSwap := true; end else begin if lImageFormatOK then dcmMsg('This software only reads 8, 12, 16, 24 [RGB] and 32 bit DICOM files. This file allocates '+inttostr(tmp)+' bits per voxel.'); lImageFormatOK := false; end; end; //remaining := 2;//remaining; //1371-> remaining := 0 end; $0101: begin info := 'Bits Stored'; if remaining = 4 then tmp := read32(fp,lrOK) else tmp := read16(fp,lrOK); if not lrOK then goto 666; (*if tmp <= 8 then lDicomData.Storedbits_per_pixel := 8 else if tmp <= 16 then lDicomData.Storedbits_per_pixel := 16 else if tmp <= 24 then begin lDicomData.Storedbits_per_pixel := 24; lDicomData.SamplesPerPixel := 3; end else begin lWord := tmp; lWord := swap(lWord); if lWord in [8,12,16] then begin lDicomData.Storedbits_per_pixel := tmp; lByteSwap := true; end else begin if lImageFormatOK then dcmMsg('This software can only read 8, 12 and 16 bit DICOM files. This file stores '+inttostr(tmp)+' bits per voxel.'); lDicomData.Storedbits_per_pixel := tmp; lImageFormatOK := false;{ } end; end;*) remaining := 0; end; $0102: begin info := 'High Bit'; if remaining = 4 then tmp := read32(fp,lrOK) else tmp := read16(fp,lrOK); if not lrOK then goto 666; remaining := 0; end; $0103: begin info := 'Pixel Representation'; if remaining = 2 then begin tmp := read16(fp,lrOK); //1= signed, 0=unsigned... if tmp = 1 then lDicomData.SignedData := true; if tmp = 0 then lDicomData.SignedData := false; remaining := 0; end; end; $0104: info := 'Smallest Valid Pixel Value'; $0105: info := 'Largest Valid Pixel Value'; $0106: begin //xlDicomData.MinIntensitySet:= true; info := 'Smallest Image Pixel Value'; tmp := read16(fp,lrOK); if not lrOK then goto 666; //xlDicomData.Minintensity := tmp; //if >32767 then there will be wrap around if read as signed value! remaining := 0; end; $0107: begin info := 'Largest Image Pixel Value'; if remaining = 4 then tmp := read32(fp,lrOK) else tmp := read16(fp,lrOK); if not lrOK then goto 666; //xlDicomData.Maxintensity := tmp; //if >32767 then there will be wrap around if read as signed value! remaining := 0; end; $120: info := 'Pixel Padding Value'; $200: info := 'Image Location [ret]'; $1040: begin t := _string; info := 'Pixel Intensity Relationship'; end; $1050: begin info := 'Window Center'; if e_len > 0 then begin readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; //xlDICOMdata.WindowCenter := round(lfloat1); end; end;{float} $1051: begin info := 'Window Width'; if e_len > 0 then begin readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; //xlDICOMdata.WindowWidth := round(lfloat1); end; //ignore empty elements, e.g. LeadTech's image6.dic end; $1052: begin t := _string;info :='Rescale Intercept'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDICOMdata.intenIntercept := lfloat1; //if (lDICOMdata.nOrder > 0) and (lDICOMdata.nOrder < kMaxOrderVal) then // lDICOMdata.OrderIntercept[lDICOMdata.nOrder] := lfloat1; end; {float} $1053:begin t := _string; info := 'Rescale Slope'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; if lFloat1 < 0.000000001 then begin lFLoat1 := 1; //misused in some images, see IMG000025 end; lDICOMdata.intenScale := lfloat1; //if (lDICOMdata.nOrder > 0) and (lDICOMdata.nOrder < kMaxOrderVal) then // lDICOMdata.OrderSlope[lDICOMdata.nOrder] := lfloat1; end; {float} $1054:begin t := _string; info := 'Rescale Type';end; $1100: info := 'Gray Lookup Table [ret]'; $1101: begin info := 'Red Palette Descriptor'; TmpStr := ReadStr(fp, remaining,lrOK,lJunk); if not lrOK then goto 666; e_len := 0; remaining := 0; end; $1102: begin info := 'Green Palette Descriptor'; TmpStr := ReadStr(fp, remaining,lrOK,lJunk); if not lrOK then goto 666; e_len := 0; remaining := 0; end; $1103: begin info := 'Blue Palette Descriptor'; TmpStr := ReadStr(fp, remaining,lrOK,lJunk); if not lrOK then goto 666; e_len := 0; remaining := 0; end; $1199: begin info := 'Palette Color Lookup Table UID'; end; $1200: info := 'Gray Lookup Data [ret]'; $1201, $1202,$1203: begin case element of $1201: info := 'Red Table'; {future} $1202: info := 'Green Table'; {future} $1203: info := 'Blue Table'; {future} end; if dFilePos(fp) > (filesz-remaining) then goto 666; if not lReadColorTables then begin dSeek(fp, dFilePos(fp) + remaining); end else begin {load color} width := remaining div 2; if width > 0 then begin getmem(lWordRA,width*2); for i := (width) downto 1 do lWordRA^[i] := read16(fp,lrOK); //value := 159; value := lWordRA^[1]; max16 := value; min16 := value; for i := (width) downto 1 do begin value := lWordRA^[i]; if value < min16 then min16 := value; if value > max16 then max16 := value; end; //width..1 if max16 - min16 = 0 then max16 := min16+1; {avoid divide by 0} if (lDicomData.Allocbits_per_pixel <= 8) and (width > 256) then width := 256; //currently only accepts palettes up to 8-bits GetMem( lColorRA, width );(**) for i := width downto 1 do lColorRA^[i] := (lWordRA^[i] shr 8) {and 255}; FreeMem( lWordRA ); case element of $1201: begin red_table_size := width; red_table :=lColorRA;; end; $1202: begin green_table_size := width; green_table :=lColorRA;; end; else {x$1203:} begin blue_table_size := width; blue_table :=lColorRA;; end; {else} end; {case} end; //width > 0; if odd(remaining) then dSeek(fp, dFilePos(fp) + 1{remaining}); end; {load color} tmpstr := 'Custom'; remaining := 0; e_len := 0; {show tempstr} end; $1221, $1222,$1223: begin info := 'Color Palette ['+inttostr(dFilePos(fp))+']'; (*xcase element of $1221: begin lDicomData.RLEredOffset:= dFilePos(fp); lDicomData.RLEredSz:= e_len; end; $1222: begin lDicomData.RLEgreenOffset:= dFilePos(fp); lDicomData.RLEgreenSz:= e_len; end; $1223: begin lDicomData.RLEblueOffset:= dFilePos(fp); lDicomData.RLEblueSz:= e_len; end; end;*)//Case set offset and length tmpstr := inttostr(e_len); dSeek(fp, dFilePos(fp)+ e_LEN); e_len := 0; end; $3002: info := 'LUT Descriptor'; $3003: info := 'LUT Explanation'; $3006: info := 'LUT Data'; $3010: begin info := 'VOI LUT Sequence'; if (explicitVR) and (lT0=kS) and (lT1=kQ) then e_len := 8; end; end; //case end; //$0028 $41: case element of //Papyrus Private Group $1010: begin info := 'Papyrus Icon [bytes skipped]'; dSeek(fp, dFilePos(fp) + e_len); tmpstr := inttostr(e_len); remaining := 0; e_len := 0; end; //element $0041:$1010 $1015: begin info := 'Papyrus Slices'; (*Papyrus format is buggy - see lsjpeg.pas for details, therefore, I have removed extensive support if e_len = 2 then begin lDicomData.XYZdim[3] := read16(fp,lrOK); if not lrOK then goto 666; end; if lDicomData.XYZdim[3] < 1 then lDicomData.XYZdim[3] := 1; if {(false) and }(lDicomData.XYZdim[3] > 1) and (lReadJPEGtables) and (gECATJPEG_table_entries = 0) then begin //Papyrus multislice files keep separate DICOM headers for each slice within a DICOM file lPapyrusnSlices := lDicomData.XYZdim[3]; lPapyrusSlice := 0; //lPapyrusData := lDicomData; gECATJPEG_table_entries := lDICOMdata.XYZDim[3]; getmem (gECATJPEG_pos_table, gECATJPEG_table_entries*sizeof(longint)); getmem (gECATJPEG_size_table, gECATJPEG_table_entries*sizeof(longint)); end else lDicomData.XYZdim[3] := 1; tmpstr := inttostr(lDicomData.XYZdim[3]); remaining := 0; e_len := 0;*) end; //element $0041:$1015 $1050: begin info := 'Papyrus Bizarre Element'; //bizarre osiris problem if (dfilepos(fp)+e_len)= (filesz) then e_len := 8; end; //element $0041:$1050 end; //group $0041: Papyrus $43: begin if lDicomData.ManufacturerID = kGEID then begin case element of $1039,$A039: begin // 0043,1039 (or 0043,a039). b value (as the first number in the string). info := 'GE Bvalue'; if e_len > 0 then begin readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDICOMdata.DTI[1].bval := round(lfloat1); lDICOMdata.nDTIdir := 1; end; //e_len>0 end;//1039 or Ao39 end;//Case end; //Manufacturer = GE end;//$0043 - GE bvalues $54: case element of $0: info := 'Nuclear Acquisition Group Length'; $11: info := 'Number of Energy Windows'; $21: info := 'Number of Detectors'; $51: info := 'Number of Rotations'; $80: begin info := 'Slice Vector'; TmpStr := ReadStr(fp, remaining,lrOK,lJunk); if not lrOK then goto 666; e_len := 0; remaining := 0; end; $81: info := 'Number of Slices'; $202: info := 'Type of Detector Motion'; $400: info := 'Image ID'; end; $2010 : case element of $0: info := 'Film Box Group Length'; $100: info := 'Border Density'; end; $4000 : info := 'Text'; $0029 : begin case element of $1010: begin //lSiemensMosaic0029_1010:= true; if (lDicomData.kV = 0) then begin //Siemens uses 0029:1010 for both CT and MRI, but only MRI is in CSA format lDicomData.CSAImageHeaderInfoPos := (dFilePos(fp)); lDicomData.CSAImageHeaderInfoSz := e_len; end; info := 'Private Sequence Delimiter ['+inttostr(dFilePos(fp))+']'; if not lImageFormatOK then time_to_quit := TRUE; //x(lDicomData.RunLengthEncoding) or ( ((lDicomData.JPEGLossycpt) or (lDicomData.JPEGLosslesscpt)) and (gECATJPEG_table_entries >= lDICOMdata.XYZdim[3]))} dSeek(fp, dFilePos(fp) + e_len); tmpstr := inttostr(e_len); remaining := 0; e_len := 0; {show tempstr} end; $1020: begin if (lDicomData.kV = 0) then begin //Siemens uses 0029:1020 for both CT and MRI, but only MRI is in CSA format info := 'CSA Series Header Info'; lDicomData.CSASeriesHeaderInfoPos := (dFilePos(fp)); lDicomData.CSASeriesHeaderInfoSz := e_len; //dcmMsg('CSA Series Header Info @ '+Inttostr (dFilePos(fp))+ 'length: '+inttostr(e_len) ); end; //(0029, 1020) [CSA Series Header Info] OB: Array of 80248 bytes end; $1053: begin info :='Philips Scale Slope'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lPhilipsScaleSlope := lfloat1; {if e_len = 4 then begin lPhilipsScaleSlope := read32r(fp,lrOK); TmpStr := floattostr(lPhilipsScaleSlope); t := _string; if not lrOK then goto 666; e_len := 0; remaining := 0; end; } end; else begin end; END; END; //gROUP 0029 (* $0045 : begin case element of $103B: begin dcmMsg('0045:103B'); end; //element $1010 end; //CASE...element end; //group 0045 *) $0089 : begin case element of $1010: begin e_len := 0; lProprietaryImageThumbnail := true; //lImageFormatOK := false; end; //element $1010 $1020: begin //thoravision files if e_len > 12 then e_len := 0; //lProprietaryImageThumbnail := true; //lImageFormatOK := false; end; //element $1010 end; //CASE...element end; //group 0089 $2001 : begin if lDicomData.ManufacturerID = kPhilipsID then begin case element of {$IFDEF read20011003} $1003: begin //bvalue - see lUse00189117 //if (lUse00189087 = kUndefined) then // lUse00189087 := kNo; //see notes for 0018,9087 - shame on Philips! if (e_len = 4) {and (lUse00189087 = kNo)} then begin if (lDICOMdata.nDTIdir < kMaxDTIdir) and (not (lUse00189117 = kYes)) then //see 0018,9117 - Philips' usage shameful inc(lDICOMdata.nDTIdir); lUse00189117 := kNo; lDICOMdata.DTI[lDICOMdata.nDTIdir].bval := round(read32r(fp,lrOK)); TmpStr := inttostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].bval); t := _string; info :='Philips DTI b-val'; if not lrOK then goto 666; e_len := 0; remaining := 0; end; //e_len = 4 end; //element 1003 {$ENDIF} // read20011003 $100B: begin info := 'Philips: slice orientation';t := _string; TmpStr := ''; DICOMHeaderString(TmpStr); lDicomData.PhilipsSliceOrient := TmpStr; AplhaNumericStrDICOM (lDicomData.PhilipsSliceOrient); end;//PhilipsSliceOrient $1018: begin if e_len = 4 then begin info :='number of slices'; lDicomData.SlicesPer3DVol := read32(fp,lrOK); //uninterleave data e_len := 0; remaining := 0; if lResearchMode then lDicomData.SeriesNum := lDicomData.SeriesNum + 50; //do not jumble research recons and normal images end; //e_len = 4 TmpStr := floattostr(lDicomData.SlicesPer3DVol); end; //1018 $102D: begin ///Apr2007 if e_len = 2 then begin lnSlicePerVol := read16(fp,lrOK); e_len := 0; remaining := 0; end; //fx(213,lnSlicePerVol); end; //102D $105F: begin //Philips Stack Sequence if e_len > 8 then e_len := 8; end; //105F end; end; //if manufacturer = Philips end; //2001,1004) $2005 : begin //if lDicomData.ManufacturerID = kPhilipsID then dcmMsg(inttohex(element,4)); if lDicomData.ManufacturerID = kPhilipsID then begin case element of $140F: begin //lInside2005140F := true; if (e_len > 8) and (lOsirix0002_0013) then begin //dcmMsg('WARNING: Images from Osirix which disrupts DICOM tags. Please validate output.'); e_len := 8; remaining := e_len; //qas 7/2013 end; end; $100E: begin if e_len = 4 then begin lPhilipsScaleSlope := read32r(fp,lrOK); TmpStr := floattostr(lPhilipsScaleSlope); t := _string; info :='Philips Scale Slope'; if not lrOK then goto 666; e_len := 0; remaining := 0; end; end; //element $1010 $1071: begin if e_len = 4 then begin lDicomData.AngulationAP := read32r(fp,lrOK); TmpStr := floattostr(lDicomData.AngulationAP); t := _string; info :='angulation midslice, AP (degrees)'; if not lrOK then goto 666; e_len := 0; remaining := 0; end; end; // Philips AP angulation : -8.74086 $1072: begin if e_len = 4 then begin lDicomData.AngulationFH := read32r(fp,lrOK); TmpStr := floattostr(lDicomData.AngulationFH); t := _string; info :='angulation midslice, FH (degrees)'; if not lrOK then goto 666; e_len := 0; remaining := 0; end; end; // Philips Philips FH angulation : -3.53147 $1073: begin if e_len = 4 then begin lDicomData.AngulationRL := read32r(fp,lrOK); TmpStr := floattostr(lDicomData.AngulationRL); t := _string; info :='angulation midslice, RL (degrees)'; if not lrOK then goto 666; e_len := 0; remaining := 0; end; end; // Philips RL angulation {$IFDEF read20011003} $10b0: begin //see lUse00189117 if (e_len = 4) and (lUse00189117 = kNo) then begin lDICOMdata.DTI[lDICOMdata.nDTIdir].v1 := read32r(fp,lrOK); TmpStr := floattostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].v1); t := _string; // dcmMsg('zqas '+inttostr(lDICOMdata.nDTIdir)+' b: '+inttostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].bval)+' v1: '+floattostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].v1)); info :='Philips Gradient vector [x]'; if not lrOK then goto 666; e_len := 0; remaining := 0; end; //e_len = 4 end; //element 10b0 $10b1: begin //see lUse00189117 if (e_len = 4) and (lUse00189117 = kNo) then begin lDICOMdata.DTI[lDICOMdata.nDTIdir].v2 := read32r(fp,lrOK); TmpStr := floattostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].v2); t := _string; info :='Philips Gradient vector [y]'; if not lrOK then goto 666; e_len := 0; remaining := 0; end; //e_len = 4 end; //element 10b1 $10b2: begin //see lUse00189117 if (e_len = 4) and (lUse00189117 = kNo) then begin lDICOMdata.DTI[lDICOMdata.nDTIdir].v3 := read32r(fp,lrOK); TmpStr := floattostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].v3); t := _string; info :='Philips Gradient vector [z]'; //fx(lDICOMdata.DTI[lDICOMdata.nDTIdir].v1,lDICOMdata.DTI[lDICOMdata.nDTIdir].v2,lDICOMdata.DTI[lDICOMdata.nDTIdir].v3); if not lrOK then goto 666; e_len := 0; remaining := 0; end; //e_len = 4 end; //element 10b2 {$ENDIF} // read20011003} end; //CASE...element end; //if Manufacturer = Philips end; //group 2005 $5200 : begin case element of $9230: begin if (e_len > 8) and (lDicomData.ManufacturerID = kPhilipsID) and (lOsirix0002_0013) then begin dcmMsg('WARNING: Images from Osirix which disrupts DICOM tags. PLEASE VALIDATE OUTPUT.'); e_len := 8; remaining := e_len; //qas 7/2013 end; //if (lDicomData.ManufacturerID = kPhilipsID) and (orientation_not_visible( lDICOMdata))then // read_philips_hidden(lFilename, dFilePos(fp),e_len,lDICOMdata); end //element 9230 end; //case element end; //group 5200 $5400 : begin case element of $0100: begin //can not convert sound files to images 12/2012 lImageFormatOK := false; dcmMsg('Note: the DICOM file '+lFileName+' stores a waveform sequence (e.g. ECG) that will not be converted to an image'); info :='WaveformSequence'; //fx(lDICOMdata.DTI[lDICOMdata.nDTIdir].v1,lDICOMdata.DTI[lDICOMdata.nDTIdir].v2,lDICOMdata.DTI[lDICOMdata.nDTIdir].v3); if not lrOK then goto 666; e_len := 0; remaining := 0; end //element 0100 end; //case element end; //group 5400 $DDFF : begin case element of $00E0: begin //For papyrus multislice format: if (lPapyrusSlice >= lPapyrusnSlices) then time_to_quit := TRUE; end; end; end; $FFFE : begin case element of $E000 : begin e_len := 0; remaining := e_len; //qas 7/2013 inc(lIndent); lInside00209113 := (lprevGroup = $0020) and (lprevelement = $9113); lInside2005140F := (lprevGroup = $2005) and (lprevelement = $140F); // if (lInside00209113) then fx(333); (*iif lJPEGEntries > 17 then lTestError := true; if not lProprietaryImageThumbnail then begin f (lReadJPEGtables) and ((lDICOMdata.RunLengthEncoding) or (lDICOMdata.JPEGLossyCpt) or (lDICOMdata.JPEGLosslessCpt)) and (not lFirstFragment) and (e_len > 1024) {1384} and ( (e_len+dFilePos(fp)) <= FileSz) then begin //first fragment is the index table, so the previous line skips the first fragment if (gECATJPEG_table_entries = 0) then begin gECATJPEG_table_entries := lDICOMdata.XYZDim[3]; getmem (gECATJPEG_pos_table, gECATJPEG_table_entries*sizeof(longint)); getmem (gECATJPEG_size_table, gECATJPEG_table_entries*sizeof(longint)); end; if lJPEGentries < gECATJPEG_table_entries then begin inc(lJPEGentries); gECATJPEG_pos_table^[lJPEGEntries] := dFilePos(fp); gECATJPEG_size_table^[lJPEGEntries] := e_len; end; end; if (lDICOMdata.CompressOffset =0) and ( (e_len+dFilePos(fp)) <= FileSz) and (e_len > 1024){ALOKA} then begin lDICOMdata.CompressOffset := dFilePos(fp); lDICOMdata.CompressSz := e_len; end; //if e_len > lDICOMdata.CompressSz then lDICOMdata.CompressSz := e_len; if (e_len > 1024) and (lDICOMdata.CompressSz=0) then begin //ABBA RLE ALOKA //Time_To_Quit := true;//ABBA lDICOMdata.CompressSz := e_len; lDICOMdata.CompressOffset := dFilePos(fp); end; if (lFirstFragment) or ((e_len > lDICOMdata.CompressSz) and not (lDicomData.RunLengthEncoding)) then lDICOMdata.CompressOffset := dFilePos(fp); if (e_len > lDICOMdata.CompressSz) and (e_len > 1024){ALOKA} then lDICOMdata.CompressSz := e_len; lFirstFragment := false; lDICOMdataBackUp := lDICOMData; if (gECATJPEG_table_entries = 1) then begin //updatex gECATJPEG_size_table^[1] := lDICOMdata.CompressSz; gECATJPEG_pos_table^[1] := lDICOMdata.CompressOffset; end; //updatex end; //not proprietaryThumbnail lProprietaryImageThumbnail := false; //1496 *) lFirstFragment := false;//Dec09 lDICOMdataBackUp := lDICOMData;//Dec09 if ((e_len > 1024) and ((lDicomData.JPEGLosslessCpt)) or (e_len >= (lDicomData.XYZdim[1]*lDicomData.XYZdim[2]))){Apr 2011} and (lDicomData.XYZdim[1]> 1) then begin lDICOMdata.CompressOffset := dFilePos(fp); lDICOMdata.CompressSz := e_len; Time_To_Quit := true; //dcmMsg('abba'+inttostr(lDICOMdata.CompressOffset)+' '+inttostr(lDICOMdata.CompressSz)); end; info := 'Image Fragment ['+inttostr(dFilePos(fp))+']'; if (dFilePos(fp) + e_len) >= filesz then Time_To_Quit := true; dSeek(fp, dFilePos(fp) + e_len); tmpstr := inttostr(e_len); remaining := 0; e_len := 0; end; $E0DD : begin if (lIndent > 0) then dec(lIndent); lInside00209113 := false; lInside2005140F := false; info := 'Sequence Delimiter'; if (lDICOMdata.XYZdim[1]= lDICOMdata.XYZdim[3])) then time_to_quit := TRUE; end; //RLE ABBA if (e_len = 0) then begin //ALOKA explicitVR := true; time_to_quit := FALSE;//RLE16=false end; //END dSeek(fp, dFilePos(fp) + e_len); tmpstr := inttostr(e_len); remaining := 0; e_len := 0; end; end; end; $FFFC : begin dSeek(fp, dFilePos(fp) + e_len); tmpstr := inttostr(e_len); remaining := 0; e_len := 0; end; $72FF : case element of $1041: time_to_quit := TRUE; end; //case 72FF $7FE0 : case element of $00 : begin info := 'Pixel Data Group Length'; if not lImageFormatOK then time_to_quit := TRUE; end; $10 : begin info := 'Pixel Data'; TmpStr := inttostr(e_len); //ShowdcmMsg(inttostr(ExpectedDicomBytes(lDicomData) ) +' '+ inttostr(e_len)); if ((ExpectedDicomBytes(lDicomData) ) > e_len) or (lDICOMdata.XYZdim[1]= $6000) AND (group <= $601e) AND ((group AND 1) = 0) then begin info := 'Overlay'+inttostr(dfilepos(fp))+'x'+inttostr(e_len); end; if element = $0000 then info := 'Group Length'; if element = $4000 then info := 'Comments'; end; end; lStr := ''; 1234: lprevGroup := Group; lprevElement := element; if (Time_TO_Quit) and (not lImageFormatOK) then begin lHdrOK := true; goto 666; end; //dcmMsg(inttohex(group,4) +':'+inttohex(element,4) +' '+inttostr(e_len)+'@'+ inttostr(dfilepos(fp))); if (e_len + dfilepos(fp)) > FileSz then begin//patch for GE files that only fill top 16-bytes w Random data e_len := e_len and $FFFF; end; if (e_len > 131072) then begin //goto 666; end;//zebra if (NOT time_to_quit) AND (e_len > 0) and (remaining > 0) then begin if (e_len + dfilepos(fp)) > FileSz then begin if not lImageFormatOK(*x(lDICOMdata.GenesisCpt) or (lDICOMdata.JPEGlosslessCpt) or (lDICOMdata.JPEGlossyCpt)*) then lHdrOK := true else begin dcmMsg('dcm Error: not a DICOM image: '+lFilename); {dcmMsg('Diagnostics saved as: c:\dcmcrash.txt'); //diagnostics assignfile(lTextF,'c:\dcmcrash.txt'); Filemode := 0; rewrite(lTextF); Write(lTextF,lDynStr); closefile(lTextF); } //dcmMsg(inttohex(group,4) +':'+inttohex(element,4) +' '+inttostr(e_len)+'@'+ inttostr(dfilepos(fp))); end; goto 666; end; if e_len > 0 then begin GetMem( buff, e_len); dBlockRead(fp, buff, e_len, n); if lVerboseRead then case t of unknown : case e_len of 1 : lStr := ( IntToStr(Integer(buff[0]))); 2 : Begin if lDicomData.little_endian <> 0 then i := Integer(buff[0]) + 256*Integer(buff[1]) else i := Integer(buff[0])*256 + Integer(buff[1]); lStr :=( IntToStr(i)); end; 4 : Begin if lDicomData.little_endian <> 0 then i := Integer(buff[0]) + 256*Integer(buff[1]) + 256*256*Integer(buff[2]) + 256*256*256*Integer(buff[3]) else i := Integer(buff[0])*256*256*256 + Integer(buff[1])*256*256 + Integer(buff[2])*256 + Integer(buff[3]); lStr := (IntToStr(i)); end; else begin if e_len > 0 then begin for i := 0 to e_len-1 do begin if Char(buff[i]) in ['+','-','/','\',' ', '0'..'9','a'..'z','A'..'Z'] then lStr := lStr+(Char(buff[i])) else lStr := lStr+('.'); end; end else lStr := '*NO DATA*'; end; end; i8, i16, i32, ui8, ui16, ui32, _string : for i := 0 to e_len-1 do if Char(buff[i]) in ['+','-','/','\',' ', '0'..'9','a'..'z','A'..'Z'] then lStr := lStr +(Char(buff[i])) else lStr := lStr +('.'); end; FreeMem(buff); end; end else if e_len > 0 then lStr := (IntToStr(tmp)) else begin lStr := TmpStr; end; (*if (lGrp) then if MessageDlg(lStr+'= '+info+' '+IntToHex(where,4)+': ('+IntToHex(group,4)+','+IntToHex(element,4)+')'+IntToStr(e_len)+'. Continue?', mtConfirmation, [mbYes, mbNo], 0) = mrNo then GOTO 666; *) //if (Group > $2005) then // dcmMsg(info+' '+IntToStr(where)+': ('+IntToHex(group,4)+','+IntToHex(element,4)+')'+IntToStr(e_len)); {$IFDEF Troubleshoot} WriteLn(myFile,IntToHex(group,4)+','+IntToHex(element,4)+','+Info+'='+lStr);//+' Offset'+inttostr(dfilepos(fp))+' Length'+inttostr(e_len)); // dcmMsg( IntToHex(group,4)+','+IntToHex(element,4)+','+Info+'='+lStr);//+' Offset'+inttostr(dfilepos(fp))+' Length'+inttostr(e_len)); {$ENDIF Troubleshoot} if lverboseRead then begin if length(lDynStr) > kMaxTextBuf then begin if not lTextOverFlow then begin lDynStr := lDynStr + 'Only showing the first '+inttostr(kMaxTextBuf) +' characters of this LARGE header'; lTextOverFlow := true; end; //goto 666; end else lDynStr := lDynStr+IntToHex(group,4)+','+IntToHex(element,4)+','+Info+'='+lStr+kCR ; dcmMsg(AddIndent(lIndent)+IntToHex(group,4)+','+IntToHex(element,4)+','+inttostr(e_len)+'@'+inttostr(dfilepos(fp))+','+Info+'='+lStr); end; //not verbose read end; // end for lDicomData.ImageStart := dfilepos(fp); if lBigSet then begin if lBig then lDicomData.little_endian := 0 else lDicomData.little_endian := 1; end; lHdrOK := true; if lByteSwap then begin ByteSwap(lDicomdata.XYZdim[1]); ByteSwap(lDicomdata.XYZdim[2]); if lDicomdata.XYZdim[3] <> 1 then ByteSwap(lDicomdata.XYZdim[3]); //xByteSwap(lDicomdata.SamplesPerPixel); ByteSwap(lDicomData.Allocbits_per_pixel); //xByteSwap(lDicomData.Storedbits_per_pixel); end; if (lDICOMdata.ManufacturerID = kPhilipsID) and (l4DDistanceBetweenSliceCenters <> kNaNsingle) then //some 3D and 4D Philips files do not correctly report interslice distance in 0018,0088 and 0018,0050... lDICOMdata.XYZmm[3] := (l4DDistanceBetweenSliceCenters); if (lPrefs.PhilipsPrecise) and (lManufacturerIsPhilips) and (lPhilipsScaleSlope <> 0) then begin PhilipsPrecise (lDicomData.IntenScale, lDICOMdata.intenIntercept,lPhilipsScaleSlope, lDicomData.IntenScale, lDICOMdata.intenIntercept,true); end; //if PARprecise if (lDICOMdata.ManufacturerID = kPhilipsID) and (lDICOMdata.nDTIdir > 1) then begin lGELX := true; for i := 1 to lDICOMdata.nDTIdir do if lDICOMdata.DTI[lDICOMdata.nDTIdir].bval <> lDICOMdata.DTI[1].bval then lGELX := false;//multiple B0 directions if lGELX then lDICOMdata.nDTIdir := 1; lGELX := false; end; if (lMatrixSz > 1) and (lDicomData.CSAImageHeaderInfoPos > 0) and (lDicomData.CSAImageHeaderInfoSz > 0) and not (((lDicomdata.XYZdim[1] mod lMatrixSz) = 0) and ((lDicomdata.XYZdim[2] mod lMatrixSz) = 0)) then begin //Slow method for non-square Siemens matrices - 0018:1310 based on phase/freq, so it is easier to read CSA to decode rows/columns GetCSAImageHeaderInfo (lFilename, lDicomData.CSAImageHeaderInfoPos ,lDicomData.CSAImageHeaderInfoSz, lTempInt,lDICOMdata.SiemensMosaicX,lDICOMdata.SiemensMosaicY, lfloat1,lfloat2,lfloat3) end else if (lMatrixSz > 1) and ((lDicomdata.XYZdim[1] mod lMatrixSz) = 0) and ((lDicomdata.XYZdim[2] mod lMatrixSz) = 0) then begin if ((lDicomData.XYZdim[1] mod lMatrixSz)=0) then lDicomData.SiemensMosaicX := lDicomData.XYZdim[1] div lMatrixSz; if ((lDicomData.XYZdim[2] mod lMatrixSz)=0) then lDicomData.SiemensMosaicY := lDicomData.XYZdim[2] div lMatrixSz; if lDicomData.SiemensMosaicX < 1 then lDicomData.SiemensMosaicX := 1; //1366 if lDicomData.SiemensMosaicY < 1 then lDicomData.SiemensMosaicY := 1; //1366 if lOldSiemens_IncorrectMosaicMM then begin //old formats convert size in mm incorrectly - modern versions are correct and include transfer syntax lDicomdata.XYZmm[1] := lDicomdata.XYZmm[1] * (lDicomdata.XYZdim[1] div lMatrixSz); lDicomdata.XYZmm[2] := lDicomdata.XYZmm[2] * (lDicomdata.XYZdim[2] div lMatrixSz); end; end else if (lSiemensMosaic0008_0008) and (lPhaseEncodingSteps > 0) and (lPhaseEncodingSteps < lDicomdata.XYZdim[2]) and ((lDicomdata.XYZdim[2] mod lPhaseEncodingSteps) = 0) and ((lDicomdata.XYZdim[2] mod (lDicomdata.XYZdim[2] div lPhaseEncodingSteps)) = 0) then begin //1499c kludge for detecting new Siemens mosaics: WARNING may cause false positives - Siemens fault not mine! lDicomData.SiemensMosaicY :=lDicomdata.XYZdim[2] div lPhaseEncodingSteps; lDicomData.SiemensMosaicX := lDicomData.SiemensMosaicY; //We also need to assume as many mosaic rows as columns, as Siemens does not save the phase encoding lines in the header... end; // fx(lnSlicePerVol,lnVol, lDicomData.SlicesPer3DVol,lDicomdata.XYZdim[3] ); //fx(lnVol,lnSlicePerVol,lDicomData.SlicesPer3DVol,lDicomdata.XYZdim[3]); //fx(lnSlicePerVol,lDicomData.ManufacturerID,kPhilipsID ); if (lnSlicePerVol > 0) and (lDicomData.ManufacturerID = kPhilipsID) {and (lnVol > 1)} and (lDicomdata.XYZdim[3] > 1) and (lDicomData.SlicesPer3DVol > 0)and ((lDicomdata.XYZdim[3] mod lDicomData.SlicesPer3DVol) = 0) then begin lDICOMdata.File4D := true; lnVol := lDicomdata.XYZdim[3] div lDicomData.SlicesPer3DVol; end; if lManufacturerIsBruker then lDicomData.AcquNum := 1; //Bruker varies this for every image if (lEchoNum > 0) and (lEchoNum < 16) then begin lDicomData.AcquNum := lDicomData.AcquNum + (1000*lEchoNum); end; if lVerboseRead then begin // lDicomData.PatientPosX, lDicomData.PatientPosY,lDicomData.PatientPosZ dcmMsg ('DICOM data'); dcmMsg ('Series/Acquisition/Image/Xpos/YPos/ZPos:'+kTab+inttostr(lDicomData.SeriesNum)+kTab+inttostr(lDicomData.AcquNum)+kTab+inttostr(lDicomData.ImageNum)+kTab+floattostr(lDicomData.PatientPosX)+kTab+floattostr(lDicomData.PatientPosY)+kTab+floattostr(lDicomData.PatientPosZ)); dcmMsg ('BPP: '+inttostr(lDicomData.Allocbits_per_pixel)); dcmMsg ('XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/'+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) ); dcmMsg ('XYZ mm:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2) ); dcmMsg ('DTI bvalue:'+ inttostr(lDICOMdata.DTI[1].bval)); dcmMsg ('DTI bvec:'+floattostrf(lDicomData.DTI[1].v1,ffFixed,8,2)+'/'+floattostrf(lDicomData.DTI[1].v2,ffFixed,8,2)+'/'+floattostrf(lDicomData.DTI[1].v3,ffFixed,8,2) ); end; //dcmMsg('abba'+inttostr(lDICOMdata.CompressOffset)+' '+inttostr(lDICOMdata.CompressSz)); 666: //if not lHdrOk then dcmMsg('zx'+lFilename); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); if not lHdrOK then lImageFormatOK := false; CloseFile(fp); FileMode := 2; //set to read/write //if kUseDateTimeForID then lDicomData.DateTime := StudyDateTime(lDicomData.StudyDate,lDicomData.StudyTime); if (lDicomData.SiemensMosaicX > 1) then lDicomData.AcquNum := 1; end; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/LibTar.pas0000755000175000017500000010062011326434462017416 0ustar mihmih(*Name : LibTar =============================================================================================== Subject : Handling of "tar" files =============================================================================================== Author : Stefan Heymann Eschenweg 3 72076 Tbingen GERMANY E-Mail: stefan@destructor.de Web: www.destructor.de =============================================================================================== TTarArchive Usage ----------------- - Choose a constructor - Make an instance of TTarArchive TA := TTarArchive.Create (Filename); - Scan through the archive TA.Reset; WHILE TA.FindNext (DirRec) DO BEGIN - Evaluate the DirRec for each file ListBox.Items.Add (DirRec.Name); - Read out the current file TA.ReadFile (DestFilename); (You can ommit this if you want to read in the directory only) END; - You're done TA.Free; TTarWriter Usage ---------------- - Choose a constructor - Make an instance of TTarWriter TW := TTarWriter.Create ('my.tar'); - Add a file to the tar archive TW.AddFile ('foobar.txt'); - Add a string as a file TW.AddString (SL.Text, 'joe.txt', Now); - Destroy TarWriter instance TW.Free; - Now your tar file is ready. Source, Legals ("Licence") -------------------------- The official site to get this code is http://www.destructor.de/ Usage and Distribution of this Source Code is ruled by the "Destructor.de Source code Licence" (DSL) which comes with this file or can be downloaded at http://www.destructor.de/ IN SHORT: Usage and distribution of this source code is free. You use it completely on your own risk. Donateware ---------- If you like this code, you are free to donate http://www.destructor.de/donateware.htm =============================================================================================== !!! All parts of this code which are not finished or known to be buggy are marked with three exclamation marks =============================================================================================== Date Author Changes ----------------------------------------------------------------------------------------------- 2001-04-26 HeySt 0.0.1 Start 2001-04-28 HeySt 1.0.0 First Release 2001-06-19 HeySt 2.0.0 Finished TTarWriter 2001-09-06 HeySt 2.0.1 Bugfix in TTarArchive.FindNext: FBytesToGo must sometimes be 0 2001-10-25 HeySt 2.0.2 Introduced the ClearDirRec procedure 2001-11-13 HeySt 2.0.3 Bugfix: Take out ClearDirRec call from WriteTarHeader Bug Reported by Tony BenBrahim 2001-12-25 HeySt 2.0.4 WriteTarHeader: Fill Rec with zero bytes before filling it 2002-05-18 HeySt 2.0.5 Kylix awareness: Thanks to Kerry L. Davison for the canges 2005-09-03 HeySt 2.0.6 TTarArchive.FindNext: Don't access SourceStream.Size (for compressed streams, which don't know their .Size) 2006-03-13 HeySt 2.0.7 Bugfix in ReadFile (Buffer : POINTER) 2007-05-16 HeySt 2.0.8 Bugfix in TTarWriter.AddFile (Convertfilename in the ELSE branch) Bug Reported by Chris Rorden *) UNIT LibTar; INTERFACE USES {$ifdef fpc} {$MODE Delphi} {$H+} {$endif} {$ifdef Unix} BaseUnix, Unix, {$else} Windows, {$endif} SysUtils, Classes; TYPE // --- File Access Permissions TTarPermission = (tpReadByOwner, tpWriteByOwner, tpExecuteByOwner, tpReadByGroup, tpWriteByGroup, tpExecuteByGroup, tpReadByOther, tpWriteByOther, tpExecuteByOther); TTarPermissions = SET OF TTarPermission; // --- Type of File TFileType = (ftNormal, // Regular file ftLink, // Link to another, previously archived, file (LinkName) ftSymbolicLink, // Symbolic link to another file (LinkName) ftCharacter, // Character special files ftBlock, // Block special files ftDirectory, // Directory entry. Size is zero (unlimited) or max. number of bytes ftFifo, // FIFO special file. No data stored in the archive. ftContiguous, // Contiguous file, if supported by OS ftDumpDir, // List of files ftMultiVolume, // Multi-volume file part ftVolumeHeader); // Volume header. Can appear only as first record in the archive // --- Mode TTarMode = (tmSetUid, tmSetGid, tmSaveText); TTarModes = SET OF TTarMode; // --- Record for a Directory Entry // Adjust the ClearDirRec procedure when this record changes! TTarDirRec = RECORD Name : STRING; // File path and name Size : INT64; // File size in Bytes DateTime : TDateTime; // Last modification date and time Permissions : TTarPermissions; // Access permissions FileType : TFileType; // Type of file LinkName : STRING; // Name of linked file (for ftLink, ftSymbolicLink) UID : INTEGER; // User ID GID : INTEGER; // Group ID UserName : STRING; // User name GroupName : STRING; // Group name ChecksumOK : BOOLEAN; // Checksum was OK Mode : TTarModes; // Mode Magic : STRING; // Contents of the "Magic" field MajorDevNo : INTEGER; // Major Device No. for ftCharacter and ftBlock MinorDevNo : INTEGER; // Minor Device No. for ftCharacter and ftBlock FilePos : INT64; // Position in TAR file END; // --- The TAR Archive CLASS TTarArchive = CLASS PROTECTED FStream : TStream; // Internal Stream FOwnsStream : BOOLEAN; // True if FStream is owned by the TTarArchive instance FBytesToGo : INT64; // Bytes until the next Header Record PUBLIC CONSTRUCTOR Create (Stream : TStream); OVERLOAD; CONSTRUCTOR Create (Filename : STRING; FileMode : WORD = fmOpenRead OR fmShareDenyWrite); OVERLOAD; DESTRUCTOR Destroy; OVERRIDE; PROCEDURE Reset; // Reset File Pointer FUNCTION FindNext (VAR DirRec : TTarDirRec) : BOOLEAN; // Reads next Directory Info Record. FALSE if EOF reached PROCEDURE ReadFile (Buffer : POINTER); OVERLOAD; // Reads file data for last Directory Record PROCEDURE ReadFile (Stream : TStream); OVERLOAD; // -;- PROCEDURE ReadFile (Filename : STRING); OVERLOAD; // -;- FUNCTION ReadFile : STRING; OVERLOAD; // -;- PROCEDURE GetFilePos (VAR Current, Size : INT64); // Current File Position PROCEDURE SetFilePos (NewPos : INT64); // Set new Current File Position END; // --- The TAR Archive Writer CLASS TTarWriter = CLASS PROTECTED FStream : TStream; FOwnsStream : BOOLEAN; FFinalized : BOOLEAN; // --- Used at the next "Add" method call: --- FPermissions : TTarPermissions; // Access permissions FUID : INTEGER; // User ID FGID : INTEGER; // Group ID FUserName : STRING; // User name FGroupName : STRING; // Group name FMode : TTarModes; // Mode FMagic : STRING; // Contents of the "Magic" field CONSTRUCTOR CreateEmpty; PUBLIC CONSTRUCTOR Create (TargetStream : TStream); OVERLOAD; CONSTRUCTOR Create (TargetFilename : STRING; Mode : INTEGER = fmCreate); OVERLOAD; DESTRUCTOR Destroy; OVERRIDE; // Writes End-Of-File Tag PROCEDURE AddFile (Filename : STRING; TarFilename : STRING = ''); PROCEDURE AddStream (Stream : TStream; TarFilename : STRING; FileDateGmt : TDateTime); PROCEDURE AddString (Contents : STRING; TarFilename : STRING; FileDateGmt : TDateTime); PROCEDURE AddDir (Dirname : STRING; DateGmt : TDateTime; MaxDirSize : INT64 = 0); PROCEDURE AddSymbolicLink (Filename, Linkname : STRING; DateGmt : TDateTime); PROCEDURE AddLink (Filename, Linkname : STRING; DateGmt : TDateTime); PROCEDURE AddVolumeHeader (VolumeId : STRING; DateGmt : TDateTime); PROCEDURE Finalize; PROPERTY Permissions : TTarPermissions READ FPermissions WRITE FPermissions; // Access permissions PROPERTY UID : INTEGER READ FUID WRITE FUID; // User ID PROPERTY GID : INTEGER READ FGID WRITE FGID; // Group ID PROPERTY UserName : STRING READ FUserName WRITE FUserName; // User name PROPERTY GroupName : STRING READ FGroupName WRITE FGroupName; // Group name PROPERTY Mode : TTarModes READ FMode WRITE FMode; // Mode PROPERTY Magic : STRING READ FMagic WRITE FMagic; // Contents of the "Magic" field END; // --- Some useful constants CONST FILETYPE_NAME : ARRAY [TFileType] OF STRING = ('Regular', 'Link', 'Symbolic Link', 'Char File', 'Block File', 'Directory', 'FIFO File', 'Contiguous', 'Dir Dump', 'Multivol', 'Volume Header'); ALL_PERMISSIONS = [tpReadByOwner, tpWriteByOwner, tpExecuteByOwner, tpReadByGroup, tpWriteByGroup, tpExecuteByGroup, tpReadByOther, tpWriteByOther, tpExecuteByOther]; READ_PERMISSIONS = [tpReadByOwner, tpReadByGroup, tpReadByOther]; WRITE_PERMISSIONS = [tpWriteByOwner, tpWriteByGroup, tpWriteByOther]; EXECUTE_PERMISSIONS = [tpExecuteByOwner, tpExecuteByGroup, tpExecuteByOther]; FUNCTION PermissionString (Permissions : TTarPermissions) : STRING; FUNCTION ConvertFilename (Filename : STRING) : STRING; FUNCTION FileTimeGMT (FileName : STRING) : TDateTime; OVERLOAD; FUNCTION FileTimeGMT (SearchRec : TSearchRec) : TDateTime; OVERLOAD; PROCEDURE ClearDirRec (VAR DirRec : TTarDirRec); IMPLEMENTATION FUNCTION PermissionString (Permissions : TTarPermissions) : STRING; BEGIN Result := ''; IF tpReadByOwner IN Permissions THEN Result := Result + 'r' ELSE Result := Result + '-'; IF tpWriteByOwner IN Permissions THEN Result := Result + 'w' ELSE Result := Result + '-'; IF tpExecuteByOwner IN Permissions THEN Result := Result + 'x' ELSE Result := Result + '-'; IF tpReadByGroup IN Permissions THEN Result := Result + 'r' ELSE Result := Result + '-'; IF tpWriteByGroup IN Permissions THEN Result := Result + 'w' ELSE Result := Result + '-'; IF tpExecuteByGroup IN Permissions THEN Result := Result + 'x' ELSE Result := Result + '-'; IF tpReadByOther IN Permissions THEN Result := Result + 'r' ELSE Result := Result + '-'; IF tpWriteByOther IN Permissions THEN Result := Result + 'w' ELSE Result := Result + '-'; IF tpExecuteByOther IN Permissions THEN Result := Result + 'x' ELSE Result := Result + '-'; END; FUNCTION ConvertFilename (Filename : STRING) : STRING; // Converts the filename to Unix conventions BEGIN {$IFDEF LINUX} Result := Filename; {$ELSE} Result := StringReplace (Filename, '\', '/', [rfReplaceAll]); {$ENDIF} END; FUNCTION FileTimeGMT (FileName: STRING): TDateTime; // Returns the Date and Time of the last modification of the given File // The Result is zero if the file could not be found // The Result is given in UTC (GMT) time zone VAR SR : TSearchRec; BEGIN Result := 0.0; IF FindFirst (FileName, faAnyFile, SR) = 0 THEN Result := FileTimeGMT (SR); FindClose (SR); END; FUNCTION FileTimeGMT (SearchRec : TSearchRec) : TDateTime; {$IFNDEF UNIX} VAR SystemFileTime: TSystemTime; {$ELSE} VAR TimeVal : TTimeVal; TimeZone : TTimeZone; {$ENDIF} BEGIN Result := 0.0; {$IFNDEF UNIX} {$WARNINGS OFF} IF (SearchRec.FindData.dwFileAttributes AND faDirectory) = 0 THEN IF FileTimeToSystemTime (SearchRec.FindData.ftLastWriteTime, SystemFileTime) THEN Result := EncodeDate (SystemFileTime.wYear, SystemFileTime.wMonth, SystemFileTime.wDay) + EncodeTime (SystemFileTime.wHour, SystemFileTime.wMinute, SystemFileTime.wSecond, SystemFileTime.wMilliseconds); {$WARNINGS ON} {$ELSE} IF SearchRec.Attr AND faDirectory = 0 THEN BEGIN Result := FileDateToDateTime (SearchRec.Time); fpGetTimeOfDay (@TimeVal, @TimeZone); Result := Result + TimeZone.tz_minuteswest / (60 * 24); END; {$ENDIF} end; PROCEDURE ClearDirRec (VAR DirRec : TTarDirRec); // This is included because a FillChar (DirRec, SizeOf (DirRec), 0) // will destroy the long string pointers, leading to strange bugs BEGIN WITH DirRec DO BEGIN Name := ''; Size := 0; DateTime := 0.0; Permissions := []; FileType := TFileType (0); LinkName := ''; UID := 0; GID := 0; UserName := ''; GroupName := ''; ChecksumOK := FALSE; Mode := []; Magic := ''; MajorDevNo := 0; MinorDevNo := 0; FilePos := 0; END; END; CONST RECORDSIZE = 512; NAMSIZ = 100; TUNMLEN = 32; TGNMLEN = 32; CHKBLANKS = #32#32#32#32#32#32#32#32; TYPE TTarHeader = PACKED RECORD Name : ARRAY [0..NAMSIZ-1] OF CHAR; Mode : ARRAY [0..7] OF CHAR; UID : ARRAY [0..7] OF CHAR; GID : ARRAY [0..7] OF CHAR; Size : ARRAY [0..11] OF CHAR; MTime : ARRAY [0..11] OF CHAR; ChkSum : ARRAY [0..7] OF CHAR; LinkFlag : CHAR; LinkName : ARRAY [0..NAMSIZ-1] OF CHAR; Magic : ARRAY [0..7] OF CHAR; UName : ARRAY [0..TUNMLEN-1] OF CHAR; GName : ARRAY [0..TGNMLEN-1] OF CHAR; DevMajor : ARRAY [0..7] OF CHAR; DevMinor : ARRAY [0..7] OF CHAR; END; FUNCTION ExtractText (P : PChar) : STRING; BEGIN Result := STRING (P); END; FUNCTION ExtractNumber (P : PChar) : INTEGER; OVERLOAD; VAR Strg : STRING; BEGIN Strg := Trim (StrPas (P)); P := PChar (Strg); Result := 0; WHILE (P^ <> #32) AND (P^ <> #0) DO BEGIN Result := (ORD (P^) - ORD ('0')) OR (Result SHL 3); INC (P); END; END; FUNCTION ExtractNumber64 (P : PChar) : INT64; OVERLOAD; VAR Strg : STRING; BEGIN Strg := Trim (StrPas (P)); P := PChar (Strg); Result := 0; WHILE (P^ <> #32) AND (P^ <> #0) DO BEGIN Result := (ORD (P^) - ORD ('0')) OR (Result SHL 3); INC (P); END; END; FUNCTION ExtractNumber (P : PChar; MaxLen : INTEGER) : INTEGER; OVERLOAD; VAR S0 : ARRAY [0..255] OF CHAR; Strg : STRING; BEGIN StrLCopy (S0, P, MaxLen); Strg := Trim (StrPas (S0)); P := PChar (Strg); Result := 0; WHILE (P^ <> #32) AND (P^ <> #0) DO BEGIN Result := (ORD (P^) - ORD ('0')) OR (Result SHL 3); INC (P); END; END; FUNCTION ExtractNumber64 (P : PChar; MaxLen : INTEGER) : INT64; OVERLOAD; VAR S0 : ARRAY [0..255] OF CHAR; Strg : STRING; BEGIN StrLCopy (S0, P, MaxLen); Strg := Trim (StrPas (S0)); P := PChar (Strg); Result := 0; WHILE (P^ <> #32) AND (P^ <> #0) DO BEGIN Result := (ORD (P^) - ORD ('0')) OR (Result SHL 3); INC (P); END; END; FUNCTION Records (Bytes : INT64) : INT64; BEGIN Result := Bytes DIV RECORDSIZE; IF Bytes MOD RECORDSIZE > 0 THEN INC (Result); END; PROCEDURE Octal (N : INTEGER; P : PChar; Len : INTEGER); // Makes a string of octal digits // The string will always be "Len" characters long VAR I : INTEGER; BEGIN FOR I := Len-2 DOWNTO 0 DO BEGIN (P+I)^ := CHR (ORD ('0') + ORD (N AND $07)); N := N SHR 3; END; FOR I := 0 TO Len-3 DO IF (P+I)^ = '0' THEN (P+I)^ := #32 ELSE BREAK; (P+Len-1)^ := #32; END; PROCEDURE Octal64 (N : INT64; P : PChar; Len : INTEGER); // Makes a string of octal digits // The string will always be "Len" characters long VAR I : INTEGER; BEGIN FOR I := Len-2 DOWNTO 0 DO BEGIN (P+I)^ := CHR (ORD ('0') + ORD (N AND $07)); N := N SHR 3; END; FOR I := 0 TO Len-3 DO IF (P+I)^ = '0' THEN (P+I)^ := #32 ELSE BREAK; (P+Len-1)^ := #32; END; PROCEDURE OctalN (N : INTEGER; P : PChar; Len : INTEGER); BEGIN Octal (N, P, Len-1); (P+Len-1)^ := #0; END; PROCEDURE WriteTarHeader (Dest : TStream; DirRec : TTarDirRec); VAR Rec : ARRAY [0..RECORDSIZE-1] OF CHAR; TH : TTarHeader ABSOLUTE Rec; Mode : INTEGER; NullDate : TDateTime; Checksum : CARDINAL; I : INTEGER; BEGIN FillChar (Rec, RECORDSIZE, 0); StrLCopy (TH.Name, PChar (DirRec.Name), NAMSIZ); Mode := 0; IF tmSaveText IN DirRec.Mode THEN Mode := Mode OR $0200; IF tmSetGid IN DirRec.Mode THEN Mode := Mode OR $0400; IF tmSetUid IN DirRec.Mode THEN Mode := Mode OR $0800; IF tpReadByOwner IN DirRec.Permissions THEN Mode := Mode OR $0100; IF tpWriteByOwner IN DirRec.Permissions THEN Mode := Mode OR $0080; IF tpExecuteByOwner IN DirRec.Permissions THEN Mode := Mode OR $0040; IF tpReadByGroup IN DirRec.Permissions THEN Mode := Mode OR $0020; IF tpWriteByGroup IN DirRec.Permissions THEN Mode := Mode OR $0010; IF tpExecuteByGroup IN DirRec.Permissions THEN Mode := Mode OR $0008; IF tpReadByOther IN DirRec.Permissions THEN Mode := Mode OR $0004; IF tpWriteByOther IN DirRec.Permissions THEN Mode := Mode OR $0002; IF tpExecuteByOther IN DirRec.Permissions THEN Mode := Mode OR $0001; OctalN (Mode, @TH.Mode, 8); OctalN (DirRec.UID, @TH.UID, 8); OctalN (DirRec.GID, @TH.GID, 8); Octal64 (DirRec.Size, @TH.Size, 12); NullDate := EncodeDate (1970, 1, 1); IF DirRec.DateTime >= NullDate THEN Octal (Trunc ((DirRec.DateTime - NullDate) * 86400.0), @TH.MTime, 12) ELSE Octal (Trunc ( NullDate * 86400.0), @TH.MTime, 12); CASE DirRec.FileType OF ftNormal : TH.LinkFlag := '0'; ftLink : TH.LinkFlag := '1'; ftSymbolicLink : TH.LinkFlag := '2'; ftCharacter : TH.LinkFlag := '3'; ftBlock : TH.LinkFlag := '4'; ftDirectory : TH.LinkFlag := '5'; ftFifo : TH.LinkFlag := '6'; ftContiguous : TH.LinkFlag := '7'; ftDumpDir : TH.LinkFlag := 'D'; ftMultiVolume : TH.LinkFlag := 'M'; ftVolumeHeader : TH.LinkFlag := 'V'; END; StrLCopy (TH.LinkName, PChar (DirRec.LinkName), NAMSIZ); StrLCopy (TH.Magic, PChar (DirRec.Magic + #32#32#32#32#32#32#32#32), 8); StrLCopy (TH.UName, PChar (DirRec.UserName), TUNMLEN); StrLCopy (TH.GName, PChar (DirRec.GroupName), TGNMLEN); OctalN (DirRec.MajorDevNo, @TH.DevMajor, 8); OctalN (DirRec.MinorDevNo, @TH.DevMinor, 8); StrMove (TH.ChkSum, CHKBLANKS, 8); CheckSum := 0; FOR I := 0 TO SizeOf (TTarHeader)-1 DO INC (CheckSum, INTEGER (ORD (Rec [I]))); OctalN (CheckSum, @TH.ChkSum, 8); Dest.Write (TH, RECORDSIZE); END; CONSTRUCTOR TTarArchive.Create (Stream : TStream); BEGIN INHERITED Create; FStream := Stream; FOwnsStream := FALSE; Reset; END; CONSTRUCTOR TTarArchive.Create (Filename : STRING; FileMode : WORD); BEGIN INHERITED Create; FStream := TFileStream.Create (Filename, FileMode); FOwnsStream := TRUE; Reset; END; DESTRUCTOR TTarArchive.Destroy; BEGIN IF FOwnsStream THEN FStream.Free; INHERITED Destroy; END; PROCEDURE TTarArchive.Reset; // Reset File Pointer BEGIN FStream.Position := 0; FBytesToGo := 0; END; FUNCTION TTarArchive.FindNext (VAR DirRec : TTarDirRec) : BOOLEAN; // Reads next Directory Info Record // The Stream pointer must point to the first byte of the tar header VAR Rec : ARRAY [0..RECORDSIZE-1] OF CHAR; CurFilePos : INTEGER; Header : TTarHeader ABSOLUTE Rec; I : INTEGER; HeaderChkSum : WORD; Checksum : CARDINAL; BEGIN // --- Scan until next pointer IF FBytesToGo > 0 THEN FStream.Seek (Records (FBytesToGo) * RECORDSIZE, soFromCurrent); // --- EOF reached? Result := FALSE; CurFilePos := FStream.Position; TRY FStream.ReadBuffer (Rec, RECORDSIZE); if Rec [0] = #0 THEN EXIT; // EOF reached EXCEPT EXIT; // EOF reached, too END; Result := TRUE; ClearDirRec (DirRec); DirRec.FilePos := CurFilePos; DirRec.Name := ExtractText (Header.Name); DirRec.Size := ExtractNumber64 (@Header.Size, 12); DirRec.DateTime := EncodeDate (1970, 1, 1) + (ExtractNumber (@Header.MTime, 12) / 86400.0); I := ExtractNumber (@Header.Mode); IF I AND $0100 <> 0 THEN Include (DirRec.Permissions, tpReadByOwner); IF I AND $0080 <> 0 THEN Include (DirRec.Permissions, tpWriteByOwner); IF I AND $0040 <> 0 THEN Include (DirRec.Permissions, tpExecuteByOwner); IF I AND $0020 <> 0 THEN Include (DirRec.Permissions, tpReadByGroup); IF I AND $0010 <> 0 THEN Include (DirRec.Permissions, tpWriteByGroup); IF I AND $0008 <> 0 THEN Include (DirRec.Permissions, tpExecuteByGroup); IF I AND $0004 <> 0 THEN Include (DirRec.Permissions, tpReadByOther); IF I AND $0002 <> 0 THEN Include (DirRec.Permissions, tpWriteByOther); IF I AND $0001 <> 0 THEN Include (DirRec.Permissions, tpExecuteByOther); IF I AND $0200 <> 0 THEN Include (DirRec.Mode, tmSaveText); IF I AND $0400 <> 0 THEN Include (DirRec.Mode, tmSetGid); IF I AND $0800 <> 0 THEN Include (DirRec.Mode, tmSetUid); CASE Header.LinkFlag OF #0, '0' : DirRec.FileType := ftNormal; '1' : DirRec.FileType := ftLink; '2' : DirRec.FileType := ftSymbolicLink; '3' : DirRec.FileType := ftCharacter; '4' : DirRec.FileType := ftBlock; '5' : DirRec.FileType := ftDirectory; '6' : DirRec.FileType := ftFifo; '7' : DirRec.FileType := ftContiguous; 'D' : DirRec.FileType := ftDumpDir; 'M' : DirRec.FileType := ftMultiVolume; 'V' : DirRec.FileType := ftVolumeHeader; END; DirRec.LinkName := ExtractText (Header.LinkName); DirRec.UID := ExtractNumber (@Header.UID); DirRec.GID := ExtractNumber (@Header.GID); DirRec.UserName := ExtractText (Header.UName); DirRec.GroupName := ExtractText (Header.GName); DirRec.Magic := Trim (ExtractText (Header.Magic)); DirRec.MajorDevNo := ExtractNumber (@Header.DevMajor); DirRec.MinorDevNo := ExtractNumber (@Header.DevMinor); HeaderChkSum := ExtractNumber (@Header.ChkSum); // Calc Checksum CheckSum := 0; StrMove (Header.ChkSum, CHKBLANKS, 8); FOR I := 0 TO SizeOf (TTarHeader)-1 DO INC (CheckSum, INTEGER (ORD (Rec [I]))); DirRec.CheckSumOK := WORD (CheckSum) = WORD (HeaderChkSum); IF DirRec.FileType in [ftLink, ftSymbolicLink, ftDirectory, ftFifo, ftVolumeHeader] THEN FBytesToGo := 0 ELSE FBytesToGo := DirRec.Size; END; PROCEDURE TTarArchive.ReadFile (Buffer : POINTER); // Reads file data for the last Directory Record. The entire file is read into the buffer. // The buffer must be large enough to take up the whole file. VAR RestBytes : INTEGER; BEGIN IF FBytesToGo = 0 THEN EXIT; RestBytes := Records (FBytesToGo) * RECORDSIZE - FBytesToGo; FStream.ReadBuffer (Buffer^, FBytesToGo); FStream.Seek (RestBytes, soFromCurrent); FBytesToGo := 0; END; PROCEDURE TTarArchive.ReadFile (Stream : TStream); // Reads file data for the last Directory Record. // The entire file is written out to the stream. // The stream is left at its current position prior to writing VAR RestBytes : INTEGER; BEGIN IF FBytesToGo = 0 THEN EXIT; RestBytes := Records (FBytesToGo) * RECORDSIZE - FBytesToGo; Stream.CopyFrom (FStream, FBytesToGo); FStream.Seek (RestBytes, soFromCurrent); FBytesToGo := 0; END; PROCEDURE TTarArchive.ReadFile (Filename : STRING); // Reads file data for the last Directory Record. // The entire file is saved in the given Filename VAR FS : TFileStream; BEGIN FS := TFileStream.Create (Filename, fmCreate); TRY ReadFile (FS); FINALLY FS.Free; END; END; FUNCTION TTarArchive.ReadFile : STRING; // Reads file data for the last Directory Record. The entire file is returned // as a large ANSI string. VAR RestBytes : INTEGER; BEGIN IF FBytesToGo = 0 THEN EXIT; RestBytes := Records (FBytesToGo) * RECORDSIZE - FBytesToGo; SetLength (Result, FBytesToGo); FStream.ReadBuffer (PChar (Result)^, FBytesToGo); FStream.Seek (RestBytes, soFromCurrent); FBytesToGo := 0; END; PROCEDURE TTarArchive.GetFilePos (VAR Current, Size : INT64); // Returns the Current Position in the TAR stream BEGIN Current := FStream.Position; Size := FStream.Size; END; PROCEDURE TTarArchive.SetFilePos (NewPos : INT64); // Set new Current File Position BEGIN IF NewPos < FStream.Size THEN FStream.Seek (NewPos, soFromBeginning); END; CONSTRUCTOR TTarWriter.CreateEmpty; VAR TP : TTarPermission; BEGIN INHERITED Create; FOwnsStream := FALSE; FFinalized := FALSE; FPermissions := []; FOR TP := Low (TP) TO High (TP) DO Include (FPermissions, TP); FUID := 0; FGID := 0; FUserName := ''; FGroupName := ''; FMode := []; FMagic := 'ustar'; END; CONSTRUCTOR TTarWriter.Create (TargetStream : TStream); BEGIN CreateEmpty; FStream := TargetStream; FOwnsStream := FALSE; END; CONSTRUCTOR TTarWriter.Create (TargetFilename : STRING; Mode : INTEGER = fmCreate); BEGIN CreateEmpty; FStream := TFileStream.Create (TargetFilename, Mode); FOwnsStream := TRUE; END; DESTRUCTOR TTarWriter.Destroy; BEGIN IF NOT FFinalized THEN BEGIN Finalize; FFinalized := TRUE; END; IF FOwnsStream THEN FStream.Free; INHERITED Destroy; END; PROCEDURE TTarWriter.AddFile (Filename : STRING; TarFilename : STRING = ''); VAR S : TFileStream; Date : TDateTime; BEGIN Date := FileTimeGMT (Filename); IF TarFilename = '' THEN TarFilename := ConvertFilename (Filename) ELSE TarFilename := ConvertFilename (TarFilename); S := TFileStream.Create (Filename, fmOpenRead OR fmShareDenyWrite); TRY AddStream (S, TarFilename, Date); FINALLY S.Free END; END; PROCEDURE TTarWriter.AddStream (Stream : TStream; TarFilename : STRING; FileDateGmt : TDateTime); VAR DirRec : TTarDirRec; Rec : ARRAY [0..RECORDSIZE-1] OF CHAR; BytesToRead : INT64; // Bytes to read from the Source Stream BlockSize : INT64; // Bytes to write out for the current record BEGIN ClearDirRec (DirRec); DirRec.Name := TarFilename; DirRec.Size := Stream.Size - Stream.Position; DirRec.DateTime := FileDateGmt; DirRec.Permissions := FPermissions; DirRec.FileType := ftNormal; DirRec.LinkName := ''; DirRec.UID := FUID; DirRec.GID := FGID; DirRec.UserName := FUserName; DirRec.GroupName := FGroupName; DirRec.ChecksumOK := TRUE; DirRec.Mode := FMode; DirRec.Magic := FMagic; DirRec.MajorDevNo := 0; DirRec.MinorDevNo := 0; WriteTarHeader (FStream, DirRec); BytesToRead := DirRec.Size; WHILE BytesToRead > 0 DO BEGIN BlockSize := BytesToRead; IF BlockSize > RECORDSIZE THEN BlockSize := RECORDSIZE; FillChar (Rec, RECORDSIZE, 0); Stream.Read (Rec, BlockSize); FStream.Write (Rec, RECORDSIZE); DEC (BytesToRead, BlockSize); END; END; PROCEDURE TTarWriter.AddString (Contents : STRING; TarFilename : STRING; FileDateGmt : TDateTime); VAR S : TStringStream; BEGIN S := TStringStream.Create (Contents); TRY AddStream (S, TarFilename, FileDateGmt); FINALLY S.Free END END; PROCEDURE TTarWriter.AddDir (Dirname : STRING; DateGmt : TDateTime; MaxDirSize : INT64 = 0); VAR DirRec : TTarDirRec; BEGIN ClearDirRec (DirRec); DirRec.Name := Dirname; DirRec.Size := MaxDirSize; DirRec.DateTime := DateGmt; DirRec.Permissions := FPermissions; DirRec.FileType := ftDirectory; DirRec.LinkName := ''; DirRec.UID := FUID; DirRec.GID := FGID; DirRec.UserName := FUserName; DirRec.GroupName := FGroupName; DirRec.ChecksumOK := TRUE; DirRec.Mode := FMode; DirRec.Magic := FMagic; DirRec.MajorDevNo := 0; DirRec.MinorDevNo := 0; WriteTarHeader (FStream, DirRec); END; PROCEDURE TTarWriter.AddSymbolicLink (Filename, Linkname : STRING; DateGmt : TDateTime); VAR DirRec : TTarDirRec; BEGIN ClearDirRec (DirRec); DirRec.Name := Filename; DirRec.Size := 0; DirRec.DateTime := DateGmt; DirRec.Permissions := FPermissions; DirRec.FileType := ftSymbolicLink; DirRec.LinkName := Linkname; DirRec.UID := FUID; DirRec.GID := FGID; DirRec.UserName := FUserName; DirRec.GroupName := FGroupName; DirRec.ChecksumOK := TRUE; DirRec.Mode := FMode; DirRec.Magic := FMagic; DirRec.MajorDevNo := 0; DirRec.MinorDevNo := 0; WriteTarHeader (FStream, DirRec); END; PROCEDURE TTarWriter.AddLink (Filename, Linkname : STRING; DateGmt : TDateTime); VAR DirRec : TTarDirRec; BEGIN ClearDirRec (DirRec); DirRec.Name := Filename; DirRec.Size := 0; DirRec.DateTime := DateGmt; DirRec.Permissions := FPermissions; DirRec.FileType := ftLink; DirRec.LinkName := Linkname; DirRec.UID := FUID; DirRec.GID := FGID; DirRec.UserName := FUserName; DirRec.GroupName := FGroupName; DirRec.ChecksumOK := TRUE; DirRec.Mode := FMode; DirRec.Magic := FMagic; DirRec.MajorDevNo := 0; DirRec.MinorDevNo := 0; WriteTarHeader (FStream, DirRec); END; PROCEDURE TTarWriter.AddVolumeHeader (VolumeId : STRING; DateGmt : TDateTime); VAR DirRec : TTarDirRec; BEGIN ClearDirRec (DirRec); DirRec.Name := VolumeId; DirRec.Size := 0; DirRec.DateTime := DateGmt; DirRec.Permissions := FPermissions; DirRec.FileType := ftVolumeHeader; DirRec.LinkName := ''; DirRec.UID := FUID; DirRec.GID := FGID; DirRec.UserName := FUserName; DirRec.GroupName := FGroupName; DirRec.ChecksumOK := TRUE; DirRec.Mode := FMode; DirRec.Magic := FMagic; DirRec.MajorDevNo := 0; DirRec.MinorDevNo := 0; WriteTarHeader (FStream, DirRec); END; PROCEDURE TTarWriter.Finalize; // Writes the End-Of-File Tag // Data after this tag will be ignored // The destructor calls this automatically if you didn't do it before VAR Rec : ARRAY [0..RECORDSIZE-1] OF CHAR; BEGIN FillChar (Rec, SizeOf (Rec), 0); FStream.Write (Rec, RECORDSIZE); FFinalized := TRUE; END; END. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/lsjpeg.pas0000755000175000017500000011303112204716214017517 0ustar mihmihunit lsjpeg; {*$DEFINE Stream} //rev13: changes by CR and JGS //rev19: uses Lookup table for decoding Huffman table: this doubles the speed //rev26: fixed memory leak: FreeMem(lRawRA) interface {$IFDEF FPC} {$mode delphi}{$H+} {$ENDIF} uses dialogsx,dialogs_msg, sysutils,define_types,classes; type HufRA = record HufSz,HufCode,HufVal: Integer; end; {$IFDEF Stream} procedure DecodeJPEG(var lStream: TMemoryStream; var lOutSmallRA: SmallIntP0; var lImgRAz: ByteP0;lOutputSz,lCptPosition,lCptSize: integer; lVerbose: boolean); {$ELSE} procedure DecodeJPEG(var infp: file; var lOutSmallRA: SmallIntP0; var lImgRAz: ByteP0;lOutputSz,lCptPosition,lCptSize: integer; lVerbose: boolean); {$ENDIF} implementation {$IFDEF Stream} procedure DecodeJPEG(var lStream: TMemoryStream; var lOutSmallRA: SmallIntP0; var lImgRAz: ByteP0;lOutputSz,lCptPosition,lCptSize: integer; lVerbose: boolean); {$ELSE} procedure DecodeJPEG(var infp: file; var lOutSmallRA: SmallIntP0; var lImgRAz: ByteP0;lOutputSz,lCptPosition,lCptSize: integer; lVerbose: boolean); {$ENDIF} const kmaxFrames = 4; label 666 {EOF}, 123 {Freemem}; var lRawRA: bytep; lImgRA: WordP; lHufVal,lAbba,lOffset,lLineStart,lPredicted,lPredictedG,lPredictedB,lRestartSegmentSz, lSz,k,Code,Si,lIncX,lIncY,lInc,lPredA,lPredB,lPredC,lCurrentBitPos,btS1,btS2, btMarkerType, DHTnLi,DHTtcth,SOFprecision,SOSpttrans, SOFnf,SOFarrayPos,SOSns,SOSarrayPos,SOSss,SOSse,SOSahal:integer;//byte; lHufTable,lnHufTables,{lDecode,}lImgStart,lRawSz,lRawPos,lItems,SOFydim, SOFxdim: integer; lMaxHufSi,lMaxHufVal: array [1..kmaxFrames] of integer; DHTLiRA,DHTstartRA: array [1..kmaxFrames,0..31] of integer;//byte; lBitMask: array [1..17] of integer; lSSSSszRA: array [1..kMaxFrames,0..17] of byte; lLookUpRA: array [1..kMaxFrames,0..255] of byte; //lists all possible SSSS with <= 8bits lHufRA: array [1..kMaxFrames,0..31] of HufRA; lFrameCount,lSegmentLength,lSegmentEnd,lI: integer; lImgTypeC3,lHdrOK: boolean; function ReadBit: integer; //Read the next single bit begin result := (lRawRA[lRawPos] shr (7-lCurrentBitPos)) and 1; lCurrentBitPos := lCurrentBitPos + 1; if (lCurrentBitPos = 8) then begin lRawPos := 1+lRawPos; lCurrentBitPos := 0; end; end; //nested proc ReadBit (* START Disabled Procedures // These functions are not used: these routines have been inlined (following VTune profiling) // but they are useful utilities if you want to explore Huffman Tables function ReadBits2_9 ( lNum: integer): integer; //lNum: bits to read, not to exceed 9 //wo Advance: does not increment the Byte/Bit position. Use AdvanceBitPos to do this begin result := lRawRA[lRawPos]; result := result shl 8 + lRawRA[lRawPos+1]; //result := result shl 8 + lRawRA[lRawPos+2]; result := (result shr (16-lCurrentBitPos-lNum)) and lBitMask[lNum]; //lCurrentBitPos is incremented from 1, so -1 lCurrentBitPos := lCurrentBitPos + lNum; if (lCurrentBitPos > 7) then begin lRawPos := lRawPos+(lCurrentBitPos shr 3{div 8}); lCurrentBitPos := (lCurrentBitPos and 7{mod 8}); end; end; procedure RetractBitPos(lNum: integer); begin lCurrentBitPos := lCurrentBitPos - lNum; while (lCurrentBitPos < 0) do begin lRawPos := lRawPos - 1; lCurrentBitPos := lCurrentBitPos + 8; end; end; procedure AdvanceBitPos(lNum: integer); //Advances Bit/Byte counters begin lCurrentBitPos := lCurrentBitPos + lNum; if (lCurrentBitPos > 7) then begin lRawPos := lRawPos+(lCurrentBitPos shr 3{div 8}); lCurrentBitPos := (lCurrentBitPos and 7{mod 8}); end; end; END Disabled Procedures*) function ReadBits ( lNum: integer): integer; //lNum: bits to read, not to exceed 16 begin result := lRawRA[lRawPos]; result := result shl 8 + lRawRA[lRawPos+1]; result := result shl 8 + lRawRA[lRawPos+2]; result := (result shr (24-lCurrentBitPos-lNum)) and lBitMask[lNum]; //lCurrentBitPos is incremented from 1, so -1 lCurrentBitPos := lCurrentBitPos + lNum; if (lCurrentBitPos > 7) then begin lRawPos := lRawPos+(lCurrentBitPos shr 3{div 8}); lCurrentBitPos := (lCurrentBitPos and 7{mod 8}); end; end; //nested proc ReadBits function DecodePixelDifference( lFrame: integer): integer;//Red/Green/Blue each a separate 'Frame': can have unique huffman tables var lByte,lHufValSSSS,lInput,lInputbits,lDiff,lI: integer; begin // read one byte from the stream, without modifying the pointer lByte := (lRawRA[lRawPos] shl lCurrentBitPos) + (lRawRA[lRawPos+1] shr (8-lCurrentBitPos)); lByte := lByte and 255; lHufValSSSS := lLookUpRA[lFrame,lByte]; //lLookUpRA: array [1..kMaxFrames,0..255] of byte; //lists all possible SSSS with <= 8bits if lHufValSSSS < 255 then begin lCurrentBitPos := lSSSSszRA[lFrame,lHufValSSSS] + lCurrentBitPos; lRawPos := lRawPos + (lCurrentBitpos shr 3); lCurrentBitpos := lCurrentBitpos and 7; //AdvanceBitPos(lSSSSszRA[lFrame,lSSSS]), but inlined; end else begin //full SSSS is not in the first 8-bits //if (lByte < 0) or (lByte > 255) then showmessage('yikes: this is impossible'); lInput := lByte; lInputBits := 8; inc(lRawPos); // forward 8 bits = precisely 1 byte repeat Inc(lInputBits); lInput := lInput shl 1 + ReadBit; if DHTLiRA[lFrame,lInputBits] <> 0 then begin //if any entires with this length for lI := DHTstartRA[lFrame,lInputBits] to (DHTstartRA[lFrame,lInputBits]+DHTLiRA[lFrame,lInputBits]-1) do begin if (lInput = lHufRA[lFrame,lI].HufCode) then lHufValSSSS := lHufRA[lFrame,lI].HufVal; end; //check each code end; //if any entires with this length if (lInputBits >= lMaxHufSi[lFrame]) and (lHufValSSSS > 254) then begin//exhausted options CR: added rev13 lHufValSSSS := lMaxHufVal[lFrame]; end; until (lHufValSSSS < 255){found}; end; //answer in first 8 bits //The HufVal is referred to as the SSSS in the Codec, so it is called 'lHufValSSSS' case lHufValSSSS of 0: result:= 0; 1: if ReadBit = 0 then result := -1 else result := 1; (*BELOW only a tiny bit faster to separate 2..15 into 2..9 and 10..15, requires extra procedure and more 2..9: begin //see 10..15 for explanation lDiff := ReadBits2_9(lHufValSSSS); if (lDiff > (lBitMask[lHufValSSSS-1])) then //add result := lDiff else //negation result := lDiff - lBitMask[lHufValSSSS]; end; //2..9 *) 2..15: begin //Osiris includes extra bits after SSSS=16...a violation of the standard See "TABLE H.2 - Difference categories for lossless Huffman coding" of the codec ITU-T81 //According to the Codec H.1.2.2 "No extra bits are appended after SSSS = 16 is encoded." //To patch for Osiris Change case from 2..15 to 2..16 // This will work for Osiris images, but will break non-Osiris images lDiff := ReadBits(lHufValSSSS); if (lDiff > (lBitMask[lHufValSSSS-1])) then //add result := lDiff // this is slightly unintuitive: the positive bit is identical to the offset shown in TABLE H.2, a slower but more intuitive way to do this is: //result := (lDiff and lBitMask[lHufVal-1]) + (1 shl (lHufval-1)); //where you clip off the sign bit and then SHL appropriately else //negation result := lDiff - lBitMask[lHufValSSSS]; //NEXT to lines are a bit more intuitive: {lDiff := lBitMask[lHufVal-1]- lDiff; result := -(lDiff + (1 shl (lHufval-1)));}//negation end; //10..15 else {16, not osiris} result := 32768; end; //case HuffVal end; //nested proc DecodePixelDifference procedure ReadByte(var lByte: integer); begin inc(lRawPos); lByte := lRawRA[lRawPos]; end; //nested proc ReadByte function ReadWord: word; var lbtL1, lbtL2: byte; begin inc(lRawPos); lbtL1 := lRawRA[lRawPos]; inc(lRawPos); lbtL2 := lRawRA[lRawPos]; result := (256 * lbtL1 + lbtL2) end; //nested proc ReadWord //NEXT: main procedure begin lAbba := 4; lnHufTables := 0; lRawSz := lCptSize; lRawPos := 0; lRestartSegmentSz := 0; lImgTypeC3 := false; SOFxdim:= 1; if lRawSz < 32 then goto 666; for lFrameCount := 1 to kMaxFrames do for lInc := 1 to 16 do DHTstartRA[lFrameCount,lInc] := 0; SOFydim := 1; SOSpttrans := 0; lHdrOK := false; SOFnf := 0; SOSns := 0; GetMem( lRawRA, lRawSz); {$IFDEF Stream} lStream.Seek(lCptPosition, soFromBeginning); lStream.readBuffer(lRawRA^, lRawSz); {$ELSE} Seek(infp,lCptPosition); BlockRead(infp, lRawRA^, lRawSz); {$ENDIF} ReadByte(btS1); ReadByte(btS1); repeat repeat if lRawPos <= lRawSz then ReadByte(btS1); if btS1 <> $FF then begin goto 666; end; if lRawPos <= lRawSz then ReadByte( btMarkerType); case btMarkerType of //only process segments with length fields $0,$1,$D0..$D7,$FF: btMarkerType := 0; //0&FF = fillers, $1=TEM,$D0..D7=resync end; until (lRawPos >= lRawSz) or (btMarkerType <> 0); lSegmentLength := ReadWord; lSegmentEnd := lRawPos+(lSegmentLength - 2); if lSegmentEnd > lRawSz then goto 666; if (btMarkerType = $C3) then lImgTypeC3 := true; if lverbose then dcmMsg( {result+}inttohex(btMarkerType,2){':'+inttostr( lSegmentLength )+'@'+inttostr(positon)+' '}); case btMarkerType of $0: ; //filler - ignore $C0..$C3,$C5..$CB,$CD..$CF: begin //read SOF FrameHeader ReadByte(SOFprecision); SOFydim := ReadWord; SOFxdim:= ReadWord; ReadByte(SOFnf); if lverbose then dcmMsg('[precision:'+inttostr(SOFprecision)+' X*Y:'+inttostr(SOFxdim)+'*'+inttostr(SOFydim)+'nFrames:'+inttostr(SOFnf)+'] '); if (not lImgTypeC3) or ((SOFnf <> 1) and (SOFnf <> 3)) then begin dcmMsg('Unable to extract this file format.'); end; SOFarrayPos := lRawPos; lRawPos := (lSegmentEnd); end; //SOF FrameHeader $C4: begin //DHT Huffman if lverbose then dcmMsg( 'HuffmanLength'+inttostr(lSegmentLength)+':'); //if SOFnf <1 then SOFnf := 1; //we may not know SOFnf yet! lFrameCount := 1; repeat ReadByte( DHTtcth); //showmessage(inttostr(lFrameCount)+'@'+inttostr(DHTtcth and 15)+'x'+inttostr(DHTtcth )); DHTnLi := 0; for lInc := 1 to 16 do begin ReadByte(DHTliRA[lFrameCount,lInc]); DHTnLi := DHTnLi + DHTliRA[lFrameCount,lInc]; if DHTliRA[lFrameCount,lInc] <> 0 then lMaxHufSi[lFrameCount] := lInc; //showmessage(inttostr(DHTliRA[lFrameCount,lInc])+'@'+inttostr(lMaxHufSi)); end; if DHTnLi > 17 then begin dcmMsg('Huffman table corrupted.'); goto 666; end; lIncY := 0; //frequency for lInc := 0 to 31 do begin lHufRA[lFrameCount, lInc].HufVal := -1; lHufRA[lFrameCount, lInc].HufSz := -1; lHufRA[lFrameCount, lInc].HufCode := -1; end; for lInc := 1 to 16 do begin //set the huffman size values if DHTliRA[lFrameCount,lInc]> 0 then begin DHTstartRA[lFrameCount,lInc] := lIncY+1; for lIncX := 1 to DHTliRA[lFrameCount,lInc] do begin inc(lIncY); ReadByte(btS1); lHufRA[lFrameCount,lIncY].HufVal := btS1; lMaxHufVal[lFrameCount] := btS1; if (btS1 >= 0) and (btS1 <= 16) then lHufRA[lFrameCount,lIncY].HufSz := lInc else begin dcmMsg('Huffman size array corrupted.'); goto 666; end; {} end; end; //Length of size lInc > 0 end; //showmessage('Max bits:'+inttostr(lMaxHufSi)+' SSSS:'+inttostr(lMaxHufVal)); K := 1; Code := 0; Si := lHufRA[lFrameCount,K].HufSz;//HuffSizeRA[1]; repeat while (Si = lHufRA[lFrameCount,K].HufSz) do begin lHufRA[lFrameCount,K].HufCode := Code; //showmessage('bits: '+inttostr(Si)+' NthEntry:'+inttostr(K)+' Code:'+inttostr(Code)); Code := Code + 1; Inc(K); end; if K <= DHTnLi then begin while lHufRA[lFrameCount,K].HufSz > Si do begin Code := Code Shl 1; Si := Si + 1; end; //while Si end; //K <= 17 until K > DHTnLi;// JGS added rev13 inc(lFrameCount); until (lSegmentEnd-lRawPos) < 18; lnHufTables := lFrameCount - 1; //showmessage(inttostr(lnHufTables)); lRawPos := (lSegmentEnd); end; //$C4: DHT Huffman $DD: begin //Define Restart lRestartSegmentSz := Readword; lRawPos := (lSegmentEnd); end; $DA: begin //read SOS Scan Header if SOSns > 0 then goto 666; //multiple SOS! ReadByte(SOSns); //if Ns = 1 then NOT interleaved, else interleaved: see B.2.3 SOSarrayPos := lRawPos; if SOSns > 0 then begin for lInc := 1 to SOSns do begin ReadByte( btS1); //component identifier 1=Y,2=Cb,3=Cr,4=I,5=Q ReadByte(btS2); //horizontal and vertical sampling factors end; end; ReadByte(SOSss); //predictor selection B.3 ReadByte( SOSse); ReadByte( SOSahal); //lower 4bits= pointtransform SOSpttrans := SOSahal and 16; if lverbose then dcmMsg('[Predictor: '+inttostr(SOSss)+' PointTransform:'+inttostr(SOSahal)+'] '); lRawPos := (lSegmentEnd); end; //$DA SOS - Scan Header else begin //skip marker segment; lRawPos := (lSegmentEnd); end; end; //case markertype until (lRawPos >= lRawSz) or (btMarkerType = $DA); {hexDA=Start of scan} lHdrOK := true; //errors goto label 666, so are NOT OK lImgStart := lRawPos; 666: if not lHdrOK then begin dcmMsg('Unable to read this file - is this really a JPEG image?'); goto 123; end; if (not lImgTypeC3) then goto 123; //lossless compressed huffman tables //NEXT: unpad data - delete byte that follows $FF lINc := lRawPos; lIncX := lRawPos; repeat lRawRA[lIncX] := lRawRA[lInc]; if lRawRA[lInc] = 255 then begin if (lRawRA[lInc+1] = $00) then lInc := lInc+1 else begin //showmessage(inttostr(lRawRA[lInc+1])); if (lRawRA[lInc+1] = $D9) then //end of image lIncX := -666; //end of padding end; end; inc(lInc); inc(lIncX); until lIncX < 0; //End: Data unpadding //NEXT: Create Huffman LookupTable. //We will compute all possible outcomes for an 8-bit value, while less intuitive than //reading Huffman 1 bit at a time, it doubles the decompression speed lBitMask[1]:= 1; lBitMask[2]:= 3; lBitMask[3]:= 7; lBitMask[4]:= 15; lBitMask[5]:= 31; lBitMask[6]:= 63; lBitMask[7]:= 127; lBitMask[8]:= 255; lBitMask[9]:= 511; lBitMask[10]:= 1023; lBitMask[11]:= 2047; lBitMask[12]:= 4095; lBitMask[13]:= 8191; lBitMask[14]:= 16383; lBitMask[15]:= 32767; lBitMask[16]:= 65535; lBitMask[17]:= 131071; //ONLY required for Osiris corrupted images, see DecodePixelDifference for details //NEXT: some RGB images use only a single Huffman table for all 3 colour planes. In this case, replicate the correct values if (lnHufTables < SOFnf) then begin //use single Hufman table for each frame //showmessage('generating tables'+inttostr(SOFnf)); if lnHufTables < 1 then begin dcmMsg('Lossless JPEG decoding error: no Huffman tables.'); goto 123; end; for lFrameCount := 2 to SOFnf do begin for lInc := 1 to 16 do DHTstartRA[lFrameCount,lInc] := DHTstartRA[1,lInc]; for lInc := 0 to 31 do begin lHufRA[lFrameCount,lInc].HufCode := lHufRA[1,lInc].HufCode; lHufRA[lFrameCount,lInc].HufVal := lHufRA[1,lInc].HufVal; lHufRA[lFrameCount,lInc].HufSz := lHufRA[1,lInc].HufSz; DHTliRA[lFrameCount,lInc] := DHTliRA[1,lInc]; end; //for each table entry end; //for each frame xx end;// if lnHufTables < SOFnf for lFrameCount := 1 to kMaxFrames do for lInc := 0 to 17 do lSSSSszRA[lFrameCount,lInc] := 123; //Impossible value for SSSS, suggests 8-bits can not describe answer for lFrameCount := 1 to kMaxFrames do for lInc := 0 to 255 do lLookUpRA[lFrameCount,lInc] := 255; //Impossible value for SSSS, suggests 8-bits can not describe answer //NEXT fill lookuptable for lFrameCount := 1 to SOFnf do begin lIncY := 0; for lSz := 1 to 8 do begin //set the huffman lookup table for keys with lengths <=8 if DHTliRA[lFrameCount,lSz]> 0 then begin for lIncX := 1 to DHTliRA[lFrameCount,lSz] do begin inc(lIncY); lHufVal := lHufRA[lFrameCount,lIncY].HufVal; //SSSS {if (lHufVal < 0) or (lHufVal > 17) then begin showmessage('Unknown SSSS =' +inttostr(lHufVal)); lHufVal := 16; end; } lSSSSszRA[lFrameCount,lHufVal] := lSz; k := (lHufRA[lFrameCount,lIncY].HufCode shl (8-lSz )) and 255; //K= most sig bits for hufman table if lSz < 8 then begin //fill in all possible bits that exceed the huffman table lInc := lBitMask[8-lSz]; for lCurrentBitPos := 0 to lInc do begin lLookUpRA[lFrameCount,k+lCurrentBitPos] := lHufVal; end; end else lLookUpRA[lFrameCount,k] := lHufVal; //SSSS {Showmessage('Frame ' + inttostr(lFrameCount) + ' SSSS= '+inttostr(lHufRA[lFrameCount,lIncY].HufVal)+ ' Size= '+inttostr(lHufRA[1,lIncY].HufSz)+ ' Code= '+inttostr(lHufRA[1,lIncY].HufCode)+ ' SHL Code= '+inttostr(k)+ ' EmptyBits= '+inttostr(lInc)); {} end; //Set SSSS end; //Length of size lInc > 0 end; //for lInc := 1 to 8 end; //For each frame, e.g. once each for Red/Green/Blue //Next: uncompress data: different loops for different predictors SOFxdim:= SOFnf*SOFxdim; lItems := SOFxdim*SOFydim; //if lVerbose then showmessage('precision'+inttostr(SOFprecision)); //for timing, multiple decoding loops lRawAbba := lRawPos;for lLoopsAbba := 1 to 100 do begin lRawPos := lRawAbba; //if (lRestartSegmentSz > 0) and ((SOFPrecision<> 8) or (SOSss = 7)) then //add restart support if we ever find any samples to test // showmessage('This image uses restart markers. Please contact the author. Predictor:Precision '+inttostr(SOSss)+':'+inttostr(SOFPrecision)); inc(lRawPos);//abbax lCurrentBitPos := 0; //read in a new byte //lCurrentBitPos := 1; //read in a new byte lItems := SOFxdim*SOFydim; lPredicted := 1 shl (SOFPrecision-1-SOSpttrans); lInc := 0; if (SOFPrecision<> 8) then begin //start - 16 bit data lImgRA := @lOutSmallRA[0];{set to 1 for MRIcro, else 0} FillChar(lImgRA^,lItems*sizeof(word), 0); //zero array lPredB:= 0; lPredC := 0; case SOSss of //predictors 1,2,3 examine single previous pixel, here we set the relative location 2: lPredA:= SOFxDim-1; //Rb directly above 3: lPredA:= SOFxDim; //Rc UpperLeft:above and to the left 4,5: begin lPredA := 0; lPredB := SOFxDim-1; //Rb directly above lPredC:= SOFxDim; //Rc UpperLeft:above and to the left end; 6: begin lPredB := 0; lPredA := SOFxDim-1; //Rb directly above lPredC:= SOFxDim; //Rc UpperLeft:above and to the left end; else lPredA := 0; //Ra: directly to left end; //case SOSss: predictor offset for lIncX := 1 to SOFxdim do begin inc(lInc); //writenext voxel if lInc > 1 then lPredicted := lImgRA[lInc-1]; lImgRA[lInc] := lPredicted+DecodePixelDifference(1); end; //first line: use prev voxel prediction; if lRestartSegmentSz = 0 then begin for lIncY := 2 to SOFyDim do begin inc(lInc); //write next voxel lPredicted := lImgRA[lInc-SOFxdim]; lImgRA[lInc] := lPredicted+DecodePixelDifference(1); if SOSss = 4 then begin for lIncX := 2 to SOFxdim do begin lPredicted := lImgRA[lInc-lPredA]+lImgRA[lInc-lPredB]-lImgRA[lInc-lPredC]; inc(lInc); //writenext voxel lImgRA[lInc] := lPredicted+DecodePixelDifference(1); end; //for lIncX end else if (SOSss = 5) or (SOSss = 6) then begin for lIncX := 2 to SOFxdim do begin lPredicted := lImgRA[lInc-lPredA]+ ((lImgRA[lInc-lPredB]-lImgRA[lInc-lPredC]) shr 1); inc(lInc); //writenext voxel lImgRA[lInc] := lPredicted+DecodePixelDifference(1); end; //for lIncX end else if SOSss = 7 then begin for lIncX := 2 to SOFxdim do begin inc(lInc); //writenext voxel lPredicted := (lImgRA[lInc-1]+lImgRA[lInc-SOFxdim]) shr 1; lImgRA[lInc] := lPredicted+DecodePixelDifference(1); end; //for lIncX end else begin //SOSss 1,2,3 read single values for lIncX := 2 to SOFxdim do begin lPredicted := lImgRA[lInc-lPredA]; inc(lInc); //writenext voxel lImgRA[lInc] := lPredicted+DecodePixelDifference(1); end; //for lIncX end; //SOSss predictor end; //for lIncY end {RestartSegmentSz = 0} else begin {restartsegment} if SOSss > 3 then dcmMsg('Unusual 16-bit lossless JPEG with restart segments. Please contact the author:'+inttostr(SOSss)); lSegmentEnd := lRestartSegmentSz; repeat if lSegmentEnd > lItems then lSegmentEnd := lItems; lLineStart := (((lInc div SOFxDim)+1)* SOFxDim){-1}; if lInc > (SOFxDim+1) then lPredicted := 1 shl (SOFPrecision-1-SOSpttrans) else lPredicted := lImgRA[lInc-SOFxdim]; for lInc := lInc to (lSegmentEnd-1) do begin lImgRA[lInc] := lPredicted+DecodePixelDifference(1); if lInc+1 = lLineStart then begin//newline lPredicted := lImgRA[lInc+1-SOFxdim]; lLineStart := lLineStart + SOFxDim; end else lPredicted := lImgRA[lInc-lPredA]; end; if (lSegmentEnd+1) < lItems then begin dec(lRawPos); repeat while (lRawRA[lRawPos] <> 255) do inc(lRawPos); inc(lRawPos); until (lRawRA[lRawPos] >= $D0) and (lRawRA[lRawPos] <= $D7); lCurrentBitPos := 0; //read in a new byte inc(lRawPos);//abbax end; lSegmentEnd := lSegmentEnd + lRestartSegmentSz; until (lRestartSegmentSz < 1) or ((lSegmentEnd-2) > lItems); end; //restartsegments end else if SOFnf = 3 then begin //>8bit data; 8 bit follows //LOSSLESS JPEG: 7 possible predictors - we will handle all of them lPredB:= 0; lPredC := 0; case SOSss of //predictors 1,2,3 examine single previous pixel, here we set the relative location 2: lPredA:= SOFxDim-3; //Rb directly above 3: lPredA:= SOFxDim; //Rc UpperLeft:above and to the left 5: begin lPredA := 0; lPredB := SOFxDim-3; //Rb directly above lPredC:= SOFxDim; //Rc UpperLeft:above and to the left end; 6: begin lPredB := 0; lPredA := SOFxDim-3; //Rb directly above lPredC:= SOFxDim; //Rc UpperLeft:above and to the left end; else lPredA := 0; //Ra: directly to left end; //case SOSss: predictor offset lPredictedG := lPredicted; lPredictedB := lPredicted; lOffset := 0; lInc := lOffset; for lIncX := 1 to (SOFxdim div 3) do begin //write first line //DecodePixelDifference=RED lImgRAz[lInc] := lPredicted+DecodePixelDifference(1); lPredicted := lImgRAz[lInc]; inc(lInc); //writenext voxel //DecodePixelDifference=GREEN lImgRAz[lInc] := lPredictedG+DecodePixelDifference(2); lPredictedG := lImgRAz[lInc]; inc(lInc); //writenext voxel //DecodePixelDifference=BLUE lImgRAz[lInc] := lPredictedB+DecodePixelDifference(3); lPredictedB := lImgRAz[lInc]; inc(lInc); //writenext voxel end; //first line: use prev voxel prediction; if lRestartSegmentSz = 0 then lSegmentEnd := lItems else lSegmentEnd := lRestartSegmentSz; repeat if lSegmentEnd > lItems then lSegmentEnd := lItems; lLineStart := (((lInc div SOFxDim)+1)* SOFxDim)+lOffset{-1}; if lInc > (SOFxDim+1) then begin lPredicted := 1 shl (SOFPrecision-1-SOSpttrans); lPredictedG := lPredicted; lPredictedB := lPredicted; end else begin lPredicted := lImgRAz[lInc-SOFxdim+lOffset]; lPredictedG := lImgRAz[1+lInc-SOFxdim+lOffset]; lPredictedB := lImgRAz[2+lInc-SOFxdim+lOffset]; end; if SOSss = 4 then begin //predictor = 4 //this is a 24-bit image, so for 512-pixel wid image, SOFxdim will be (3*512=) 1536 while lInc < (lSegmentEnd-1) do begin lImgRAz[lInc] := lPredicted+DecodePixelDifference(1); //RED inc(lInc); lImgRAz[lInc] := lPredictedG+DecodePixelDifference(2); //GREEN inc(lInc); lImgRAz[lInc] := lPredictedB+DecodePixelDifference(3); //BLUE inc(lInc); if lInc = lLineStart then begin//newline lPredicted := lImgRAz[lInc-SOFxdim]; lPredictedG := lImgRAz[lInc-SOFxdim+1]; lPredictedB := lImgRAz[lInc-SOFxdim+2]; lLineStart := lLineStart + (SOFxDim); end else begin lPredicted := lImgRAz[lInc-3]+lImgRAz[lInc-3-(SOFxDim-3)]-lImgRAz[lInc-3-SOFxDim]; lPredictedG := lImgRAz[lInc-2]+lImgRAz[lInc-2-(SOFxDim-3)]-lImgRAz[lInc-2-SOFxDim]; lPredictedB := lImgRAz[lInc-1]+lImgRAz[lInc-1-(SOFxDim-3)]-lImgRAz[lInc-1-SOFxDim]; end; end; //xxx end else if (SOSss = 5) or (SOSss = 6) then begin //predictor = 5 or 6 //this is a 24-bit image, so for 512-pixel wid image, SOFxdim will be (3*512=) 1536 while lInc < (lSegmentEnd-1) do begin lImgRAz[lInc] := lPredicted+DecodePixelDifference(1); //RED inc(lInc); lImgRAz[lInc] := lPredictedG+DecodePixelDifference(2); //GREEN inc(lInc); lImgRAz[lInc] := lPredictedB+DecodePixelDifference(3); //BLUE inc(lInc); if lInc = lLineStart then begin//newline lPredicted := lImgRAz[lInc-SOFxdim]; lPredictedG := lImgRAz[lInc-SOFxdim+1]; lPredictedB := lImgRAz[lInc-SOFxdim+2]; lLineStart := lLineStart + (SOFxDim); end else begin lPredicted := lImgRAz[lInc-3-lPredA]+((lImgRAz[lInc-3-lPredB]-lImgRAz[lInc-3-lPredC])shr 1); lPredictedG := lImgRAz[lInc-2-lPredA]+((lImgRAz[lInc-2-lPredB]-lImgRAz[lInc-2-lPredC])shr 1); lPredictedB := lImgRAz[lInc-1-lPredA]+((lImgRAz[lInc-1-lPredB]-lImgRAz[lInc-1-lPredC])shr 1); end; end; end else if SOSss = 7 then begin //predictor = 7 while lInc < (lSegmentEnd-1) do begin lImgRAz[lInc] := lPredicted+DecodePixelDifference(1); //RED inc(lInc); lImgRAz[lInc] := lPredictedG+DecodePixelDifference(2); //GREEN inc(lInc); lImgRAz[lInc] := lPredictedB+DecodePixelDifference(3); //BLUE inc(lInc); if lInc = lLineStart then begin//newline lPredicted := lImgRAz[lInc-SOFxdim]; lPredictedG := lImgRAz[lInc-SOFxdim+1]; lPredictedB := lImgRAz[lInc-SOFxdim+2]; lLineStart := lLineStart + (SOFxDim); end else begin lPredicted := (lImgRAz[lInc-3]+lImgRAz[lInc-3-(SOFxDim-3)])shr 1; lPredictedG := (lImgRAz[lInc-2]+lImgRAz[lInc-2-(SOFxDim-3)]) shr 1; lPredictedB := (lImgRAz[lInc-1]+lImgRAz[lInc-1-(SOFxDim-3)]) shr 1; end; end; end else begin //predictor in range 1,2,3 //this is a 24-bit image, so for 512-pixel wid image, SOFxdim will be (3*512=) 1536 while lInc < (lSegmentEnd-1) do begin lImgRAz[lInc] := lPredicted+DecodePixelDifference(1); //RED inc(lInc); lImgRAz[lInc] := lPredictedG+DecodePixelDifference(2); //GREEN inc(lInc); lImgRAz[lInc] := lPredictedB+DecodePixelDifference(3); //BLUE inc(lInc); if lInc = lLineStart then begin//newline lPredicted := lImgRAz[lInc-SOFxdim]; lPredictedG := lImgRAz[lInc-SOFxdim+1]; lPredictedB := lImgRAz[lInc-SOFxdim+2]; lLineStart := lLineStart + (SOFxDim); end else begin lPredicted := lImgRAz[lInc-3-lPredA]; lPredictedG := lImgRAz[lInc-2-lPredA]; lPredictedB := lImgRAz[lInc-1-lPredA]; end; end; end; //predictor <> 7 until (lRestartSegmentSz < 1) or ((lSegmentEnd-2) > lItems); // end; //8<>15data type end else begin //previously 12/16/24bit data, 8 bit follows lInc := 0; //LOSSLESS JPEG: 7 possible predictors - we will handle all of them lPredB:= 0; lPredC := 0; case SOSss of //predictors 1,2,3 examine single previous pixel, here we set the relative location 2: lPredA:= SOFxDim-1; //Rb directly above 3: lPredA:= SOFxDim; //Rc UpperLeft:above and to the left 5: begin lPredA := 0; lPredB := SOFxDim-1; //Rb directly above lPredC:= SOFxDim; //Rc UpperLeft:above and to the left end; 6: begin lPredB := 0; lPredA := SOFxDim-1; //Rb directly above lPredC:= SOFxDim; //Rc UpperLeft:above and to the left end; else lPredA := 0; //Ra: directly to left end; //case SOSss: predictor offset //lOffset := -1; for lIncX := 1 to SOFxdim do begin //write first line lImgRAz[lInc] := lPredicted+DecodePixelDifference(1); inc(lInc); //writenext voxel lPredicted := lImgRAz[lInc-1]; end; //first line: use prev voxel prediction; if lRestartSegmentSz = 0 then lSegmentEnd := lItems else lSegmentEnd := lRestartSegmentSz; repeat if lSegmentEnd > lItems then lSegmentEnd := lItems; lLineStart := (((lInc div SOFxDim)+1)* SOFxDim){-1}; if lInc > (SOFxDim+1) then lPredicted := 1 shl (SOFPrecision-1-SOSpttrans) else lPredicted := lImgRAz[lInc-SOFxdim]; if SOSss = 4 then begin //predictor 4 : ABOVE+LEFT-(UPPERLEFT) for lInc := lInc to (lSegmentEnd-1) do begin lImgRAz[lInc] := lPredicted+DecodePixelDifference(1); if lInc+1 = lLineStart then begin//newline lPredicted := lImgRAz[lInc+1-SOFxdim]; lLineStart := lLineStart + SOFxDim; end else lPredicted := lImgRAz[lInc]+lImgRAz[lInc-(SOFxDim-1)] -lImgRAz[lInc-SOFxDim] ; end; end else if (SOSss = 5) or (SOSss=6) then begin //predictor 5,6 : comparisons for lInc := lInc to (lSegmentEnd-1) do begin lImgRAz[lInc] := lPredicted+DecodePixelDifference(1); if lInc+1 = lLineStart then begin//newline lPredicted := lImgRAz[lInc+1-SOFxdim]; lLineStart := lLineStart + SOFxDim; end else lPredicted := lImgRAz[lInc-lPredA]+((lImgRAz[lInc-lPredB]-lImgRAz[lInc-lPredC]) shr 1) ; end; end else if SOSss = 7 then begin //predictor 7: average above and left for lInc := lInc to (lSegmentEnd-1) do begin lImgRAz[lInc] := lPredicted+DecodePixelDifference(1); if lInc+1 = lLineStart then begin//newline lPredicted := lImgRAz[lInc+1-SOFxdim]; lLineStart := lLineStart + SOFxDim; end else lPredA := lImgRAz[lInc]; lPredB:= lImgRAz[lInc-SOFxDim+1];//correct lPredicted := (lPredA+lPredB) shr 1; end; end else begin //predictor <> 7 : assume SOSss=1: previous for lInc := lInc to (lSegmentEnd-1) do begin lImgRAz[lInc] := lPredicted+DecodePixelDifference(1); if lInc+1 = lLineStart then begin//newline lPredicted := lImgRAz[lInc+1-SOFxdim]; lLineStart := lLineStart + SOFxDim; end else lPredicted := lImgRAz[lInc-lPredA]; end; end; //predictor <> 7 if (lSegmentEnd+1) < lItems then begin dec(lRawPos); repeat while (lRawRA[lRawPos] <> 255) do inc(lRawPos); inc(lRawPos); until (lRawRA[lRawPos] >= $D0) and (lRawRA[lRawPos] <= $D7); lCurrentBitPos := 0; //read in a new byte inc(lRawPos); //lCurrentBitPos := 9; //read in a new byte end; lSegmentEnd := lSegmentEnd + lRestartSegmentSz; until (lRestartSegmentSz < 1) or ((lSegmentEnd-2) > lItems); end; //8<>15data type 123: FreeMem( lRawRA); //release memory buffer end; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2niigui.manifest0000755000175000017500000000142712065105430021312 0ustar mihmih Your application description here. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2niigui.lpr0000755000175000017500000000074512204701462020305 0ustar mihmihprogram dcm2niigui; {$mode objfpc}{$H+} uses {$IFDEF UNIX}{$IFDEF UseCThreads} cthreads, {$ENDIF}{$ENDIF} Interfaces, // this includes the LCL widgetset Forms, gui, nifti_form, pref_form, dialogs_msg; //{$R dcm2niigui.res} begin Application.Title:='dcm2niigui.exe'; Application.Initialize; Application.CreateForm(TMainForm, MainForm); Application.CreateForm(TNIfTIForm, NIfTIForm); Application.CreateForm(TPrefsForm, PrefsForm); Application.Run; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dicomcompat_28June.pas0000755000175000017500000077263412163436474021724 0ustar mihmihunit dicomcompat; interface uses {$Define NoTroubleshoot} {$IFDEF FPC} gzio2, {$ELSE} gziod, {$ENDIF} SysUtils,Classes,define_types,filename,dicomtypes,dicomfastread,prefs,convertsimple, csaread; {$H+} var kUseDateTimeForID: boolean = false; procedure read_afni_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string; var lRotation1,lRotation2,lRotation3: integer); procedure read_ecat_data(var lDICOMdata: DICOMdata;lVerboseRead,lReadECAToffsetTables:boolean; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); procedure read_siemens_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); procedure read_ge_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); procedure read_interfile_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string); procedure read_voxbo_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string); procedure read_VFF_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string); procedure read_picker_data(lVerboseRead: boolean; var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); procedure read_tiff_data(var lDICOMdata: DICOMdata; var lReadOffsets,lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); procedure read_dicom_data_compat(lReadJPEGtables,lVerboseRead,lAutoDECAT7,lReadECAToffsetTables,lAutodetectInterfile,lAutoDetectGenesis,lReadColorTables: boolean; var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string; var lPrefs: TPrefs); var gSizeMMWarningShown : boolean = false; gECATJPEG_table_entries: integer = 0; gECATJPEG_pos_table,gECATJPEG_size_table : LongIntP; red_table_size : Integer = 0; green_table_size : Integer = 0; blue_table_size : Integer = 0; red_table : ByteP; green_table : ByteP; blue_table : ByteP; implementation uses dialogsx; function SecSinceMidnightFloat (lStr: string): double; var lNumStr: string; sec: double; i,len,dec: integer; begin result := 0;//error if lStr = '' then exit; len := length(lStr); lNumStr := ''; for i := 1 to len do begin if (lStr[i] = '.') or (lStr[i] = ',') then lStr[i] := DecimalSeparator; //make native format, e.g. in Germany 10,123 whereas in USA 10.123 if lStr[i] in ['0'..'9',DecimalSeparator] then lNumStr := lNumStr + lStr[i]; end; if lNumStr = '' then exit; //make sure 6 characters before decimal, in case HHMMSS is written HMMSS dec := length(lNumStr) + 1; for i := length(lNumStr) downto 1 do if lNumStr[i] = DecimalSeparator then dec := i; if dec > 7 then exit; //HHMMSS.??? can only have 6 digits before decimal while dec < 7 do begin lNumStr := '0'+lNumStr; inc(dec); end; //now in HHMMSS.????? format len := length(lNumStr); lStr := lNumStr[1]+lNumStr[2]; //HH sec := 60 * 60 * strtoint(lStr); //60m/h, 60s/m lStr := lNumStr[3]+lNumStr[4]; //MM sec := sec + ( 60 * strtoint(lStr)); //60s/m 1000ms/s lStr := ''; for i := 5 to len do //SS.SSSS lStr := lStr + lNumStr[i]; sec := sec + ( strtofloat(lStr)); //60s/m 1000ms/s result := sec; end; function AddIndent(lIndent: integer): string; var i: integer; begin result := ''; if lIndent < 1 then exit; //for i := 1 to lIndent do result := result +'|'; end; procedure read_ecat_data(var lDICOMdata: DICOMdata;lVerboseRead,lReadECAToffsetTables:boolean; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); label 121,539; const kMaxnSLices = 6000; kStrSz = 40; var lLongRA: LongIntp; lECAT7sigUpcase,lECAT7sig : array [0..6] of Char; lParse,lSPos,lFPos{,lScomplement},lF,lS,lYear,lFrames,lVox,lHlfVox,lJ,lPass,lVolume,lNextDirectory,lSlice,lSliceSz,lVoxelType,lPos,lEntry, lSlicePos,lLongRApos,lLongRAsz,{lSingleRApos,lSingleRAsz,}{lMatri,}lX,lY,lZ,lCacheSz,lImgSz,lSubHeadStart,lMatrixStart,lMatrixEnd,lInt,lInt2,lInt3,lINt4,n,filesz: LongInt; lPlanes,lGates,lAqcType,lFileType: word; lXmm,lYmm,lZmm,lCalibrationFactor, lQuantScale: real; FP: file; lCreateTable,lSwapBytes,lMR,lECAT6: boolean; function xWord(lPos: longint): word; var s: word; begin seek(fp,lPos); BlockRead(fp, s, 2, n); if lSwapBytes then result := swap(s) else result := s; //assign address of s to inguy end; function swap32i(lPos: longint): Longint; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(Long:LongInt); end; swaptypep = ^swaptype; var s : LongInt; inguy:swaptypep; outguy:swaptype; begin seek(fp,lPos); BlockRead(fp, s, 4, n); inguy := @s; //assign address of s to inguy if not lSwapBytes then begin result := inguy^.long; exit; end; outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); swap32i:=outguy.Long; end; function StrRead (lPos, lSz: longint) : string; var I: integer; tx : array [1..kStrSz] of Char; begin result := ''; if lSz > kStrSz then exit; seek(fp, lPos{-1}); BlockRead(fp, tx, lSz*SizeOf(Char), n); for I := 1 to (lSz-1) do begin if tx[I] in [' ','[',']','+','-','.','\','~','/', '0'..'9','a'..'z','A'..'Z'] then {if (tx[I] <> kCR) and (tx[I] <> UNIXeoln) then} result := result + tx[I]; end; end; function fswap4r (lPos: longint): single; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(float:single); end; swaptypep = ^swaptype; var s:single; inguy:swaptypep; outguy:swaptype; begin seek(fp,lPos); if not lSwapBytes then begin BlockRead(fp, result, 4, n); exit; end; BlockRead(fp, s, 4, n); inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); fswap4r:=outguy.float; end; function fvax4r (lPos: longint): single; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(float:single); end; swaptypep = ^swaptype; var s:single; lT1,lT2 : word; inguy:swaptypep; begin seek(fp,lPos); BlockRead(fp, s, 4, n); inguy := @s; if (inguy^.Word1 =0) and (inguy^.Word2 = 0) then begin result := 0; exit; end; lT1 := inguy^.Word1 and $80FF; lT2 := ((inguy^.Word1 and $7F00) +$FF00) and $7F00; inguy^.Word1 := inguy^.Word2; inguy^.Word2 := (lt1+lT2); fvax4r:=inguy^.float; end; begin Clear_Dicom_Data(lDicomData); if gECATJPEG_table_entries <> 0 then begin freemem (gECATJPEG_pos_table); freemem (gECATJPEG_size_table); gECATJPEG_table_entries := 0; end; lHdrOK:= false; lQuantScale:= 1; lCalibrationFactor := 1; lLongRASz := 0; lLongRAPos := 0; lImageFormatOK := false; lVolume := 1; if not fileexists(lFileName) then begin Msg('Unable to find the image '+lFileName); exit; end; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FileSz := FileSize(fp); if filesz < (2048) then begin Msg('This file is to small to be a ECAT format image.'); goto 539; end; seek(fp, 0); BlockRead(fp, lECAT7Sig, 6*SizeOf(Char){, n}); for lInt4 := 0 to (5) do begin if lECAT7Sig[lInt4] in ['a'..'z','A'..'Z'] then lECAT7SigUpCase[lInt4] := upcase(lECAT7Sig[lInt4]) else lECAT7SigUpCase[lInt4] := ' '; end; if (lECAT7SigUpCase[0]='M') and (lECAT7SigUpCase[1]='A') and (lECAT7SigUpCase[2]='T') and (lECAT7SigUpCase[3]='R') and (lECAT7SigUpCase[4]='I') and (lECAT7SigUpCase[5]='X') then lECAT6 := false else lECAT6 := true; if lEcat6 then begin lSwapBytes := false; lFileType := xWord(27*2); if lFileType > 255 then lSwapBytes := not lSwapBytes; lFileType := xWord(27*2); lAqcType := xWord(175*2); lPlanes := xWord(188*2); lFrames := xword(189*2); lGates := xWord(190*2); lYear := xWord(70); if (lPlanes < 1) or (lFrames < 1) or (lGates < 1) then begin case MsgDlg('Warning: one of the planes/frames/gates values is less than 1 ['+inttostr(lPlanes)+'/'+inttostr(lFrames)+'/'+inttostr(lGates)+']. Is this file really ECAT 6 format? Press abort to cancel conversion. ', mterror,[mbOK,mbAbort], 0) of mrAbort: goto 539; end; //case end else if (lYear < 1940) or (lYear > 3000) then begin case MsgDlg('Warning: the year value appears invalid ['+inttostr(lYear)+']. Is this file really ECAT 6 format? Press abort to cancel conversion. ', mterror,[mbOK,mbAbort], 0) of mrAbort: goto 539; end; //case end; if lVerboseRead then begin lDynStr :='ECAT6 data'; lDynStr :=lDynStr+kCR+('Patient Name:'+StrRead(190,32)); lDynStr :=lDynStr+kCR+('Patient ID:'+StrRead(174,16)); lDynStr :=lDynStr+kCR+('Study Desc:'+StrRead(318,32)); lDynStr := lDynStr+kCR+('Facility: '+StrRead(356,20)); lDynStr := lDynStr+kCR+('Planes: '+inttostr(lPlanes)); lDynStr := lDynStr+kCR+('Frames: '+inttostr(lFrames)); lDynStr := lDynStr+kCR+('Gates: '+inttostr(lGates)); lDynStr := lDynStr+kCR+('Date DD/MM/YY: '+ inttostr(xWord(66))+'/'+inttostr(xWord(68))+'/'+inttostr(lYear)); end; {show summary} end else begin //NOT ECAT6 lSwapBytes := true; lFileType := xWord(50); if lFileType > 255 then lSwapBytes := not lSwapBytes; lFileType := xWord(50); lAqcType := xWord(328); lPlanes := xWord(352); lFrames := xWord(354); lGates := xWord(356); lCalibrationFactor := fswap4r(144); if {(true) or} (lPlanes < 1) or (lFrames < 1) or (lGates < 1) then begin case MsgDlg('Warning: on of the planes/frames/gates values is less than 1 ['+inttostr(lPlanes)+'/'+inttostr(lFrames)+'/'+inttostr(lGates)+']. Is this file really ECAT 7 format? Press abort to cancel conversion. ', mterror,[mbOK,mbAbort], 0) of mrAbort: goto 539; end; //case end; //error if lVerboseRead then begin lDynStr := 'ECAT 7 format'; lDynStr := lDynStr+kCR+('Serial Number:'+StrRead(52,10)); lDynStr := lDynStr+kCR+('Patient Name:'+StrRead(182,32)); lDynStr := lDynStr+kCR+('Patient ID:'+StrRead(166,16)); lDynStr := lDynStr+kCR+('Study Desc:'+StrRead(296,32)); lDynStr := lDynStr+kCR+('Facility: '+StrRead(332,20)); lDynStr := lDynStr+kCR+('Scanner: '+inttostr(xWord(48))); lDynStr := lDynStr+kCR+('Planes: '+inttostr(lPlanes)); lDynStr := lDynStr+kCR+('Frames: '+inttostr(lFrames)); lDynStr := lDynStr+kCR+('Gates: '+inttostr(lGates)); lDynStr := lDynStr+kCR+'Calibration: '+floattostr(lCalibrationFactor); end; {lShow Summary} end; //lECAT7 if lFiletype = 9 then lFiletype := 7; //1364: treat projections as Volume16's if not (lFileType in [1,2,3,4,7]) then begin Msg('This software does not recognize the ECAT file type. Selected filetype: '+inttostr(lFileType)); goto 539; end; lVoxelType := 2; if lFileType = 3 then lVoxelType := 4; if lVerboseRead then begin case lFileType of 1: lDynStr := lDynStr+kCR+('File type: Scan File'); 2: lDynStr := lDynStr+kCR+('File type: Image File'); //x 3: lDynStr := lDynStr+kCR+('File type: Attn File'); 4: lDynStr := lDynStr+kCR+('File type: Norm File'); 7: lDynStr := lDynStr+kCR+('File type: Volume 16'); //x end; //lfiletye case case lAqcType of 1:lDynStr := lDynStr+kCR+('Acquisition type: Blank'); 2:lDynStr := lDynStr+kCR+('Acquisition type: Transmission'); 3:lDynStr := lDynStr+kCR+('Acquisition type: Static Emission'); 4:lDynStr := lDynStr+kCR+('Acquisition type: Dynamic Emission'); 5:lDynStr := lDynStr+kCR+('Acquisition type: Gated Emission'); 6:lDynStr := lDynStr+kCR+('Acquisition type: Transmission Rect'); 7:lDynStr := lDynStr+kCR+('Acquisition type: Emission Rect'); 8:lDynStr := lDynStr+kCR+('Acquisition type: Whole Body Transm'); 9:lDynStr := lDynStr+kCR+('Acquisition type: Whole Body Static'); else lDynStr := lDynStr+kCR+('Acquisition type: Undefined'); end; //case AqcType end; //verbose read if ((lECAT6) and (lFiletype =2)) or ({(not lECAT6) and} (lFileType=7)) then //Kludge else begin Msg('Unusual ECAT filetype. Please contact the author.'); goto 539; end; lHdrOK:= true; lImageFormatOK := true; lLongRASz := kMaxnSlices * sizeof(longint); getmem(lLongRA,lLongRAsz); lPos := 512; //lSingleRASz := kMaxnSlices * sizeof(single); //getmem(lSingleRA,lSingleRAsz); //lMatri := 0; lVolume := 1; lPass := 0; 121: lEntry := 1; lInt := swap32i(lPos); lInt2 := swap32i(lPos+4); lNextDirectory := lInt2; while true do begin inc(lEntry); lPos := lPos + 16; lInt := swap32i(lPos); lInt2 := swap32i(lPos+4); lInt3 := swap32i(lPos+8); lInt4 := swap32i(lPos+12); lInt2 := lInt2 - 1; lSubHeadStart := lINt2 *512; lMatrixStart := ((lInt2) * 512)+512 {add subhead sz}; lMatrixEnd := lInt3 * 512; if (lInt4 = 1) and (lMatrixStart < FileSz) and (lMatrixEnd <= FileSz) then begin if (lFileType= 7) {or (lFileType = 4) } or (lFileType = 2) then begin //Volume of 16-bit integers if lEcat6 then begin lX := xWord(lSubHeadStart+(66*2)); lY := xWord(lSubHeadStart+(67*2)); lZ := 1;//uxWord(lSubHeadStart+8); lXmm := 10*fvax4r(lSubHeadStart+(92*2));// fswap4r(lSubHeadStart+(92*2)); lYmm := lXmm;//read32r(lSubHeadStart+(94*2)); lZmm := 10 * fvax4r(lSubHeadStart+(94*2)); lCalibrationFactor := fvax4r(lSubHeadStart+(194*2)); lQuantScale := fvax4r(lSubHeadStart+(86*2)); if lVerboseRead then lDynStr := lDynStr+kCR+'Plane '+inttostr(lPass+1)+' Calibration/Scale Factor: '+floattostr(lCalibrationFactor)+'/'+floattostr(lQuantScale); end else begin //02 or 07 lX := xWord(lSubHeadStart+4); lY := xWord(lSubHeadStart+6); lZ := xWord(lSubHeadStart+8); //if lFileType <> 4 then begin lXmm := 10*fswap4r(lSubHeadStart+34); lYmm := 10*fswap4r(lSubHeadStart+38); lZmm := 10*fswap4r(lSubHeadStart+42); lQuantScale := fswap4r(lSubHeadStart+26); if lVerboseRead then lDynStr := lDynStr+kCR+'Volume: '+inttostr(lPass+1)+' Scale Factor: '+floattostr(lQuantScale); //end; //filetype <> 4 end; //ecat7 if true then begin //FileMode := 2; //set to read/write inc(lPass); lImgSz := lX * lY * lZ * lVoxelType; {2 bytes per voxel} lSliceSz := lX * lY * lVoxelType; if lZ < 1 then begin lHdrOK := false; goto 539; end; lSlicePos := lMatrixStart; if ((lECAT6) and (lPass = 1)) or ( (not lECAT6)) then begin lDICOMdata.XYZdim[1] := lX; lDICOMdata.XYZdim[2] := lY; lDICOMdata.XYZdim[3] := lZ; lDICOMdata.XYZmm[1] := lXmm; lDICOMdata.XYZmm[2] := lYmm; lDICOMdata.XYZmm[3] := lZmm; case lVoxelType of 1: begin Msg('Error: 8-bit data not supported [yet]. Please contact the author.'); lDicomData.Allocbits_per_pixel := 8; lHdrOK := false; goto 539; end; 4: begin Msg('Error: 32-bit data not supported [yet]. Please contact the author.'); lHdrOK := false; goto 539; end; else begin //16-bit integers lDicomData.Allocbits_per_pixel := 16; end; end; {case lVoxelType} end else begin //if lECAT6 if (lDICOMdata.XYZdim[1] <> lX) or (lDICOMdata.XYZdim[2] <> lY) or (lDICOMdata.XYZdim[3] <> lZ) then begin Msg('Error: different slices in this volume have different slice sizes. Please contact the author.'); lHdrOK := false; goto 539; end; //dimensions have changed //lSlicePos :=((lMatri-1)*lImgSz); end; //ECAT6 lVox := lSliceSz div 2; lHlfVox := lSliceSz div 4; for lSlice := 1 to lZ do begin if (not lECAT6) then lSlicePos := ((lSlice-1)*lSliceSz)+lMatrixStart; if lLongRAPos >= kMaxnSLices then begin lHdrOK := false; goto 539; end; inc(lLongRAPos); lLongRA^[lLongRAPos] := lSlicePos; {inc(lSingleRAPos); if lCalibTableType = 1 then lSingleRA[lSingleRAPos] := lQuantScale else lSingleRA[lSingleRAPos] := lCalibrationFactor *lQuantScale;} end; //slice 1..lZ if not lECAT6 then inc(lVolume); end; //fileexistsex end; //correct filetype end; //matrix start/end within filesz if (lMatrixStart > FileSz) or (lMatrixEnd >= FileSz) then goto 539; if ((lEntry mod 32) = 0) then begin if ((lNextDirectory-1)*512) <= lPos then goto 539; //no more directories lPos := (lNextDirectory-1)*512; goto 121; end; //entry 32 end ; //while true 539: CloseFile(fp); FileMode := 2; //set to read/write lDicomData.XYZdim[3] := lLongRApos; if not lECAT6 then dec(lVolume); //ECAT7 increments immediately before exiting loop - once too often lDicomData.XYZdim[4] :=(lVolume); if lSwapBytes then lDicomData.little_endian := 0 else lDicomData.little_endian := 1; if (lLongRApos > 0) and (lHdrOK) then begin lDicomData.ImageStart := lLongRA^[1]; lCreateTable := false; if (lLongRApos > 1) then begin lFPos := lDICOMdata.ImageStart; for lS := 2 to lLongRApos do begin lFPos := lFPos + lSliceSz; if lFPos <> lLongRA^[lS] then lCreateTable := true; end; if (lCreateTable) and (lReadECAToffsetTables) then begin gECATJPEG_table_entries := lLongRApos; getmem (gECATJPEG_pos_table, gECATJPEG_table_entries*sizeof(longint)); getmem (gECATJPEG_size_table, gECATJPEG_table_entries*sizeof(longint)); for lS := 1 to gECATJPEG_table_entries do gECATJPEG_pos_table^[lS] := lLongRA^[lS] end else if (lCreateTable) then lImageFormatOK := false; //slices are offset within this file end; if (lVerboseRead) and (lHdrOK) then begin lDynStr :=lDynStr+kCR+('XYZdim:'+inttostr(lX)+'/'+inttostr(lY)+'/'+inttostr(gECATJPEG_table_entries)); lDynStr :=lDynStr+kCR+('XYZmm: '+floattostrf(lDicomData.XYZmm[1],ffFixed,7,7)+'/'+floattostrf(lDicomData.XYZmm[2],ffFixed,7,7) +'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,7,7)); //xlDynStr :=lDynStr+kCR+('Bits per voxel: '+inttostr(lDicomData.Storedbits_per_pixel)); lDynStr :=lDynStr+kCR+('Image Start: '+inttostr(lDicomData.ImageStart)); if lCreateTable then lDynStr :=lDynStr+kCR+('Note: staggered slice offsets'); end end; //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; if lLongRASz > 0 then freemem(lLongRA); (*if (lSingleRApos > 0) and (lHdrOK) and (lCalibTableType <> 0) then begin gECAT_scalefactor_entries := lSingleRApos; getmem (gECAT_scalefactor_table, gECAT_scalefactor_entries*sizeof(single)); for lS := 1 to gECAT_scalefactor_entries do gECAT_scalefactor_table[lS] := lSingleRA[lS]; end; if lSingleRASz > 0 then freemem(lSingleRA);*) end; (*procedure write_slc (lFileName: string; var pDICOMdata: DICOMdata;var lSz: integer; lDICOM3: boolean); const kMaxRA = 41; lXra: array [1..kMaxRA] of byte = (7,8,9,21,22,26,27, 35,36,44,45, 50,62,66,78, 81,95, 97,103,104,105,106,111, 113,123,127, 129,139,142, 146,147,148,149,155,156,157, 166,167,168,169,170); var fp: file; lX,lClr,lPos,lRApos: integer; lP: bytep; procedure WriteString(lStr: string; lCR: boolean); var n,lStrLen : Integer; begin lStrLen := length(lStr); for n := 1 to lstrlen do begin lPos := lPos + 1; lP[lPos] := ord(lStr[n]); end; if lCR then begin lPos := lPos + 1; lP[lPos] := ord(kCR); end; end; begin lSz := 0; getmem(lP,2048); lPos := 0; WriteString('11111',true); WriteString(inttostr(pDicomData.XYZdim[1])+' '+inttostr(pDicomData.XYZdim[2])+' '+inttostr(pDicomData.XYZdim[3])+' 8',true); WriteString(floattostrf(pDicomData.XYZmm[1],ffFixed,7,7)+' '+floattostrf(pDicomData.XYZmm[2],ffFixed,7,7)+' '+floattostrf(pDicomData.XYZmm[3],ffFixed,7,7),true); WriteString('1 1 0 0',true); //mmunits,MR,original,nocompress WriteString('16 12 X',false); //icon is 8x8 grid, so 64 bytes for red,green blue for lClr := 1 to 3 do begin lRApos := 1; for lX := 1 to 192 do begin inc(lPos); if (lRApos <= kMaxRA) and (lX = lXra[lRApos]) then begin inc(lRApos); lP[lPos] := 200; end else lP[lPos] := 0; end; {icongrid 1..192} end; {RGB} if lFileName <> '' then begin AssignFile(fp, lFileName); Rewrite(fp, 1); blockwrite(fp,lP^,lPos); close(fp); end; freemem(lP); lSz := lPos; end;*) procedure read_interfile_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string); label 333; const UNIXeoln = chr(10); var lTmpStr, lInStr,lUpCaseStr: string; lHdrEnd,lFloat,lUnsigned: boolean; lPos,lLen,FileSz,linPos: integer; fp: file; lCharRA: bytep; function readInterFloat:real; var lStr: string; begin lStr := ''; While (lPos <= lLen) and (lInStr[lPos] <> ';') do begin if lInStr[lPos] in ['+','-','e','E','.','0'..'9'] then lStr := lStr+(linStr[lPos]); inc(lPos); end; try result := strtofloat(lStr); except on EConvertError do begin Msg('Unable to convert the string '+lStr+' to a number'); result := 1; exit; end; end; {except} end; function readInterStr:string; var lStr: string; begin lStr := ''; While (lPos <= lLen) and (lInStr[lPos] = ' ') do begin inc(lPos); end; While (lPos <= lLen) and (lInStr[lPos] <> ';') do begin if lInStr[lPos] <> ' ' then //1.39 build 6 lStr := lStr+upcase(linStr[lPos]); //zebra upcase inc(lPos); end; result := lStr; end; //interstr func begin lHdrOK := false; lFloat := false; lUnsigned := false; lImageFormatOK := true; Clear_Dicom_Data(lDicomData); lDynStr := ''; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FileSz := FileSize(fp); lHdrEnd := false; //lDicomData.ImageStart := FileSz; GetMem( lCharRA, FileSz+1 ); BlockRead(fp, lCharRA^, FileSz, linpos); if lInPos <> FileSz then Msg('Disk error: Unable to read full input file.'); linPos := 1; CloseFile(fp); FileMode := 2; //set to read/write repeat linstr := ''; while (linPos < FileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin lInStr := lInstr + chr(lCharRA^[linPos]); inc(linPos); end; inc(lInPos); //read EOLN lLen := length(lInStr); lPos := 1; lUpcaseStr := ''; While (lPos <= lLen) and (lInStr[lPos] <> ';') and (lInStr[lPos] <> '=') and (lUpCaseStr <>'INTERFILE') do begin if lInStr[lPos] in ['[',']','(',')','/','+','-',{' ',} '0'..'9','a'..'z','A'..'Z'] then lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]); inc(lPos); end; inc(lPos); {read equal sign in := statement} if lUpCaseStr ='INTERFILE' then begin lHdrOK := true; lDicomData.little_endian := 0; end; if lUpCaseStr ='DATASTARTINGBLOCK'then lDicomData.ImageStart := 2048 * round(readInterFloat); if lUpCaseStr ='DATAOFFSETINBYTES'then lDicomData.ImageStart := round(readInterFloat); if (lUpCaseStr ='MATRIXSIZE[1]') or (lUpCaseStr ='MATRIXSIZE[X]') then lDicomData.XYZdim[1] := round(readInterFloat); if (lUpCaseStr ='MATRIXSIZE[2]')or (lUpCaseStr ='MATRIXSIZE[Y]')then lDicomData.XYZdim[2] := round(readInterFloat); if (lUpCaseStr ='MATRIXSIZE[3]')or (lUpCaseStr ='MATRIXSIZE[Z]') or (lUpCaseStr ='NUMBEROFSLICES') or (lUpCaseStr ='TOTALNUMBEROFIMAGES') then begin lDicomData.XYZdim[3] := round(readInterFloat); end; if lUpCaseStr ='IMAGEDATABYTEORDER' then begin if readInterStr = 'LITTLEENDIAN' then lDicomData.little_endian := 1; end; if lUpCaseStr ='NUMBERFORMAT' then begin lTmpStr := readInterStr; if (lTmpStr = 'ASCII') or (lTmpStr='BIT') then begin lHdrOK := false; Msg('This software can not convert '+lTmpStr+' data type.'); goto 333; end; if lTmpStr = 'UNSIGNEDINTEGER' then lUnsigned := true; if (lTmpStr='FLOAT') or (lTmpStr='SHORTFLOAT') or (lTmpStr='LONGFLOAT') then begin //1395 lFloat := true; end; end; if lUpCaseStr ='NAMEOFDATAFILE' then lFileName := ExtractFilePath(lFileName)+readInterStr; if lUpCaseStr ='NUMBEROFBYTESPERPIXEL' then lDicomData.Allocbits_per_pixel := round(readInterFloat)*8; if (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[1]') or (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[X]') then lDicomData.XYZmm[1] := (readInterFloat); if (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[2]') or (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[Y]')then lDicomData.XYZmm[2] := (readInterFloat); if (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[3]')or (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[Z]')or (lUpCaseStr ='SLICETHICKNESS')then lDicomData.XYZmm[3] := (readInterFloat); if (lUpCaseStr ='ENDOFINTERFILE') then lHdrEnd := true; if not lHdrOK then goto 333; if lInStr <> '' then lDynStr := lDynStr + lInStr+kCr; lHdrOK := true; until (linPos >= FileSz) or (lHdrEnd){EOF(fp)}; //xlDicomData.Storedbits_per_pixel := lDicomData.Allocbits_per_pixel; lImageFormatOK := true; if (not lFLoat) and (lUnsigned) and ((lDicomData.Allocbits_per_pixel = 16)) then begin Msg('Warning: this Interfile image uses UNSIGNED 16-bit data [values 0..65535]. Analyze specifies SIGNED 16-bit data [-32768..32767]. Some images may not transfer well. [Future versions of MRIcro should fix this].'); lImageFormatOK := false; end else if (not lFLoat) and (lDicomData.Allocbits_per_pixel > 16) then begin Msg('WARNING: The image '+lFileName+' is a '+inttostr(lDicomData.Allocbits_per_pixel)+'-bit integer data type. This software may display this as SIGNED data. Bits per voxel: '+inttostr(lDicomData.Allocbits_per_pixel)); lImageFormatOK := false; end else if (lFloat) then begin //zebra change float check //Msg('WARNING: The image '+lFileName+' uses floating point [real] numbers. The current software can only read integer data type Interfile images.'); lDicomData.FloatData := true; //lImageFormatOK := false; end; 333: FreeMem( lCharRA); end; //interfile //afni start function ParseFileName (lFilewExt:String): string; var lLen,lInc: integer; lName: String; begin lName := ''; lLen := length(lFilewExt); lInc := lLen+1; if lLen > 0 then repeat dec(lInc); until (lFileWExt[lInc] = '.') or (lInc = 1); if lInc > 1 then for lLen := 1 to (lInc - 1) do lName := lName + lFileWExt[lLen] else lName := lFilewExt; //no extension ParseFileName := lName; end; procedure read_afni_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string; var lRotation1,lRotation2,lRotation3: integer); //label 333; const UNIXeoln = chr(10); kTab = ord(chr(9)); kSpace = ord(' '); var lTmpStr,lInStr,lUpCaseStr: string; lHdrEnd: boolean; lMSBch: char; lOri : array [1..4] of single; lTmpInt,lPos,lLen,FileSz,linPos: integer; fp: file; lCharRA: bytep; procedure readAFNIeoln; begin while (linPos < FileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do inc(linPos); inc(lInPos); //read EOLN end; function readAFNIFloat:real; var lStr: string; lCh:char; begin lStr := ''; while (linPos < FileSz) and ((lStr='') or ((lCharRA^[lInPos] <> kTab) and (lCharRA^[lInPos] <> kSpace))) do begin lCh:= chr(lCharRA^[linPos]); if lCh in ['+','-','e','E','.','0'..'9'] then lStr := lStr+lCh; inc(linPos); end; if lStr = '' then exit; try result := strtofloat(lStr); except on EConvertError do begin Msg('Unable to convert the string '+lStr+' to a number'); result := 1; exit; end; end; {except} end; begin lHdrOK := false; lImageFormatOK := true; Clear_Dicom_Data(lDicomData); lDynStr := ''; lTmpStr := string(StrUpper(PChar(ExtractFileExt(lFileName)))); if lTmpStr <> '.HEAD' then exit; for lInPos := 1 to 3 do lOri[lInPos] := -6666; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FileSz := FileSize(fp); lHdrEnd := false; //lDicomData.ImageStart := FileSz; GetMem( lCharRA, FileSz+1 ); BlockRead(fp, lCharRA^, FileSz, linpos); if lInPos <> FileSz then Msg('Disk error: Unable to read full input file.'); linPos := 1; CloseFile(fp); FileMode := 2; //set to read/write repeat linstr := ''; while (linPos < FileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin lInStr := lInstr + chr(lCharRA^[linPos]); inc(linPos); end; inc(lInPos); //read EOLN lLen := length(lInStr); lPos := 1; lUpcaseStr := ''; While (lPos <= lLen) do begin if lInStr[lPos] in ['_','[',']','(',')','/','+','-','=',{' ',} '0'..'9','a'..'z','A'..'Z'] then lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]); inc(lPos); end; inc(lPos); {read equal sign in := statement} if lUpCaseStr ='NAME=DATASET_DIMENSIONS'then begin lImageFormatOK := true; lHdrOK := true; lFileName := parsefilename(lFilename)+'.BRIK'; //always UPPERcase readAFNIeoln; lDICOMdata.XYZdim[1] := round(readAFNIFloat); lDICOMdata.XYZdim[2] := round(readAFNIFloat); lDICOMdata.XYZdim[3] := round(readAFNIFloat); //lDicomData.ImageStart := 2048 * round(readInterFloat); end; if lUpCaseStr ='NAME=BRICK_FLOAT_FACS'then begin readAFNIeoln; lDICOMdata.IntenScale := readAFNIFloat; //1380 read slope of intensity end; if lUpCaseStr ='NAME=DATASET_RANK'then begin readAFNIeoln; //2nd value is number of volumes readAFNIFloat; lDICOMdata.XYZdim[4] := round(readAFNIFloat); end; if lUpCaseStr ='NAME=BRICK_TYPES'then begin readAFNIeoln; lTmpInt := round(readAFNIFloat); case lTmpInt of 0:lDicomData.Allocbits_per_pixel := 8; 1:begin lDicomData.Allocbits_per_pixel := 16; //lDicomData.MaxIntensity := 65535; //Old AFNI were UNSIGNED, new ones are SIGNED??? end; 3:begin lDicomData.Allocbits_per_pixel := 32; lDicomData.FloatData := true; end; else begin lHdrEnd := true; Msg('Unsupported AFNI BRICK_TYPES: '+inttostr(lTmpInt)); end; end; //case {datatype 0 = byte (unsigned char; 1 byte) 1 = short (2 bytes, signed) 3 = float (4 bytes, assumed to be IEEE format) 5 = complex (8 bytes: real+imaginary parts)} end; if lUpCaseStr ='NAME=BYTEORDER_STRING'then begin readAFNIeoln; if ((linPos+2) < FileSz) then begin lMSBch := chr(lCharRA^[linPos+1]); if lMSBCh = 'L' then lDicomData.Little_Endian := 1; if lMSBCh = 'M' then begin lDicomData.Little_Endian := 0; end; linPos := lInPos + 2; end; //littleendian end; if lUpCaseStr ='NAME=ORIGIN'then begin readAFNIeoln; lOri[1] := (abs(readAFNIFloat)); lOri[2] := (abs(readAFNIFloat)); lOri[3] := (abs(readAFNIFloat)); //Xori,YOri,ZOri end; if lUpCaseStr ='NAME=DELTA'then begin readAFNIeoln; lDICOMdata.XYZmm[1] := abs(readAFNIFloat); lDICOMdata.XYZmm[2] := abs(readAFNIFloat); lDICOMdata.XYZmm[3] := abs(readAFNIFloat); //Xmm,Ymm,Zmm end; if lUpCaseStr ='NAME=ORIENT_SPECIFIC'then begin readAFNIeoln; lRotation1 := round(readAFNIFloat); lRotation2 := round(readAFNIFloat); lRotation3 := round(readAFNIFloat); end; //ORIENT_SPECIFIC rotation details if lInStr <> '' then lDynStr := lDynStr + lInStr+kCr; until (linPos >= FileSz) or (lHdrEnd){EOF(fp)}; //xlDicomData.Storedbits_per_pixel := lDicomData.Allocbits_per_pixel; for lInPos := 1 to 3 do begin if lOri[lInPos] < -6666 then //value not set lDICOMdata.XYZori[lInPos] := round((1.0+lDICOMdata.XYZdim[lInPos])/2) else if lDICOMdata.XYZmm[lInPos] <> 0 then lDICOMdata.XYZori[lInPos] := round(1.5+lOri[lINPos] / lDICOMdata.XYZmm[lInPos]); end; // lDicomData.Float := true; FreeMem( lCharRA); end; //interfile //afni end //voxbo start procedure read_voxbo_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string); label 333; const UNIXeoln = chr(10); kTab = chr(9); var lTmpStr,lInStr,lUpCaseStr: string; lFileTypeKnown,lHdrEnd,lFloat: boolean; lStartPos,lPos,lLen,FileSz,linPos: integer; fp: file; lCharRA: bytep; procedure readVBfloats (var lF1,lF2,lF3: double); // While (lPos <= lLen) and ((lInStr[lPos] = kTab) or (lInStr[lPos] = ' ')) do begin // inc(lPos); var //lDigit : boolean; n,lItemIndex: integer; lStr,lfStr: string; begin lf1 := 1; lf2 := 1; lf3 := 1; n := 0; for lItemIndex := 1 to 3 do begin inc(n); While (lPos <= lLen) and ((lInStr[lPos] = kTab) or (lInStr[lPos] = ' ')) do inc(lPos); if lPos > lLen then exit; lStr := ''; repeat lStr := lStr+upcase(linStr[lPos]); inc(lPos); until (lPos > lLen) or (lInStr[lPos] = kTab) or (lInStr[lPos] = ' '); if lStr <> '' then begin //string to convert try case n of 1: lF1 := strtofloat(lStr); 2: lF2 := strtofloat(lStr); 3: lF3 := strtofloat(lStr); end; except on EConvertError do begin Msg('Unable to convert the string '+lfStr+' to a real number'); exit; end; end; {except} end; //if string to convert end; end; procedure readVBints (var lI1,lI2,lI3: integer); var lF1,lF2,lF3: double; begin readVBfloats (lF1,lF2,lF3); lI1 := round(lF1); lI2 := round(lF2); lI3 := round(lF3); end; function readVBStr:string; var lStr: string; begin lStr := ''; While (lPos <= lLen) and ((lInStr[lPos] = kTab) or (lInStr[lPos] = ' ')) do begin inc(lPos); end; While (lPos <= lLen) {and (lInStr[lPos] <> ';')} do begin lStr := lStr+upcase(linStr[lPos]); //zebra upcase inc(lPos); end; result := lStr; end; //interstr func begin lHdrOK := false; lFloat := false; lImageFormatOK := true; Clear_Dicom_Data(lDicomData); lDynStr := ''; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FileSz := FileSize(fp); lHdrEnd := false; //lDicomData.ImageStart := FileSz; GetMem( lCharRA, FileSz+1 ); BlockRead(fp, lCharRA^, FileSz, linpos); if lInPos <> FileSz then Msg('Disk error: Unable to read full input file.'); linPos := 1; CloseFile(fp); FileMode := 2; //set to read/write lFileTypeKnown := false; repeat linstr := ''; while (linPos < FileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin lInStr := lInstr + chr(lCharRA^[linPos]); inc(linPos); end; inc(lInPos); //read EOLN lLen := length(lInStr); lPos := 1; lUpcaseStr := ''; While (lPos <= lLen) and (lInStr[lPos] <> ':') do begin if lInStr[lPos] in ['[',']','(',')','/','+','-', '0'..'9','a'..'z','A'..'Z'] then lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]); inc(lPos); end; inc(lPos); {read equal sign in := statement} if (lHdrOK) and (not lFileTypeKnown) and (lUpCaseStr = 'CUB1') then lFileTypeKnown := true; if (lHdrOK) and (not lFileTypeKnown) then begin Msg('This software can not read this kind of VoxBo image. (Type:"'+lUpCaseStr+'")'); lHdrEnd := true; lHdrOK := false; end; if (not lHdrOK) and (lUpCaseStr ='VB98') then begin lDicomData.little_endian := 0;//all VoxBo files are Big Endian! lStartPos := linPos; lFileTypeKnown := true; //test for While Loop while (linPos < FileSz) and lFileTypeKnown do begin if (lCharRA^[linPos-1] = $0C) and (lCharRA^[linPos] = $0A) then begin lFileTypeKnown := false; lDicomData.ImageStart := linPos; FileSz := linPos; //size of VoxBo header end; inc(linPos); end; if lFileTypeKnown then begin //end of file character not found: abort! Msg('Unable to find the end of the VoxBo header.'); lHdrEnd := true end else lHdrOK := true; linPos := lStartPos; //now that we have found the header size, we can start from the beginning of the header end; if not lHdrOK then lHdrEnd := true; if (lUpCaseStr ='BYTEORDER') and (readVBStr = 'LSBFIRST') then lDicomData.little_endian := 1; if lUpCaseStr ='DATATYPE'then begin lTmpStr := readVBStr; if lTmpStr = 'Byte' then lDicomData.Allocbits_per_pixel := 8 else if (lTmpStr = 'INTEGER') or (lTmpStr = 'INT16') then lDicomData.Allocbits_per_pixel := 16 else if (lTmpStr = 'LONG') or (lTmpStr = 'INT32') then lDicomData.Allocbits_per_pixel := 32 else if (lTmpStr = 'FLOAT') then begin lFloat := true; lDicomData.Allocbits_per_pixel := 32; end else if (lTmpStr = 'DOUBLE') then begin lFloat := true; lDicomData.Allocbits_per_pixel := 64; end else begin Msg('Unknown VoxBo data format: '+lTmpStr); end; end; if lUpCaseStr ='VOXDIMS(XYZ)'then readVBints(lDicomData.XYZdim[1],lDicomData.XYZdim[2],lDicomData.XYZdim[3]); if (lUpCaseStr ='VOXSIZES(XYZ)') then readVBfloats(lDicomData.XYZmm[1],lDicomData.XYZmm[2],lDicomData.XYZmm[3]); if (lUpCaseStr ='ORIGIN(XYZ)')then begin readVBints(lDicomData.XYZori[1],lDicomData.XYZori[2],lDicomData.XYZori[3]); inc(lDicomData.XYZori[1]);//1393 inc(lDicomData.XYZori[2]);//1393 inc(lDicomData.XYZori[3]);//1393 end; if not lHdrOK then goto 333; if lInStr <> '' then lDynStr := lDynStr + lInStr+kCr; until (linPos >= FileSz) or (lHdrEnd){EOF(fp)}; //xlDicomData.Storedbits_per_pixel := lDicomData.Allocbits_per_pixel; //xlDicomData.Rotate180deg := true; lImageFormatOK := true; if (lFloat) then begin //zebra change float check lDicomData.FloatData := true; //lImageFormatOK := false; end; 333: FreeMem( lCharRA); end; //voxbo end procedure read_vff_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string); label 333; const UNIXeoln = chr(10); var lInStr,lUpCaseStr: string; //lHdrEnd: boolean; lPos,lLen,FileSz,linPos: integer; lDummy1,lDummy2,lDummy3 : double; fp: file; lCharRA: bytep; procedure readVFFvals (var lFloat1,lFloat2,lFloat3: double); var lStr: string; lDouble: DOuble; lInc: integer; begin for lInc := 1 to 3 do begin lStr := ''; While (lPos <= lLen) and (lInStr[lPos] = ' ') do begin inc(lPos); end; While (lPos <= lLen) and (lInStr[lPos] <> ';') and (lInStr[lPos] <> ' ') do begin if lInStr[lPos] in ['+','-','e','E','.','0'..'9'] then lStr := lStr+(linStr[lPos]); inc(lPos); end; if lStr <> '' then begin try lDouble := strtofloat(lStr); except on EConvertError do begin Msg('Unable to convert the string '+lStr+' to a number'); exit; end; end; {except} case lInc of 2: lFloat2 := lDouble; 3: lFloat3 := lDouble; else lFloat1 := lDouble; end; end; //lStr <> '' end; //lInc 1..3 end; //interstr func begin lHdrOK := false; lImageFormatOK := true; Clear_Dicom_Data(lDicomData); lDicomData.little_endian := 0; //big-endian lDynStr := ''; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FileSz := FileSize(fp); if FileSz > 2047 then FileSz := 2047; GetMem( lCharRA, FileSz+1 ); BlockRead(fp, lCharRA^, FileSz, linpos); if lInPos <> FileSz then Msg('Disk error: Unable to read full input file.'); lInPos := 1; while (lCharRA^[lInPos] <> 12) and (lInPos < FileSz) do begin inc(lInPos); end; inc(lInPos); if (lInPos >= FileSz) or (lInPos < 12) then goto 333; //unable to find lDynStr := lDynStr + 'Sun VFF Volume File Format'+kCr; lDicomData.ImageStart := lInPos; FileSz := lInPos-1; linPos := 1; CloseFile(fp); FileMode := 2; //set to read/write repeat linstr := ''; while (linPos < FileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin lInStr := lInstr + chr(lCharRA^[linPos]); inc(linPos); end; inc(lInPos); //read EOLN lLen := length(lInStr); lPos := 1; lUpcaseStr := ''; While (lPos <= lLen) and (lInStr[lPos] <> ';') and (lInStr[lPos] <> '=') and (lUpCaseStr <>'NCAA') do begin if lInStr[lPos] in ['[',']','(',')','/','+','-',{' ',} '0'..'9','a'..'z','A'..'Z'] then lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]); inc(lPos); end; inc(lPos); {read equal sign in := statement} if lUpCaseStr ='NCAA' then begin lHdrOK := true; end; if lUpCaseStr ='BITS' then begin lDummy1 := 8; readVFFvals(lDummy1,lDummy2,lDummy3); lDicomData.Allocbits_per_pixel := round(lDummy1); end; if lUpCaseStr ='SIZE' then begin lDummy1 := 1; lDummy2 := 1; lDummy3 := 1; readVFFvals(lDummy1,lDummy2,lDummy3); lDicomData.XYZdim[1] := round(lDummy1); lDicomData.XYZdim[2] := round(lDummy2); lDicomData.XYZdim[3] := round(lDummy3); end; if lUpCaseStr ='ASPECT' then begin lDummy1 := 1; lDummy2 := 1; lDummy3 := 1; readVFFvals(lDummy1,lDummy2,lDummy3); lDicomData.XYZmm[1] := (lDummy1); lDicomData.XYZmm[2] := (lDummy2); lDicomData.XYZmm[3] := (lDummy3); end; if not lHdrOK then goto 333; if lInStr <> '' then lDynStr := lDynStr + lInStr+kCr; //lHdrOK := true; until (linPos >= FileSz); //xlDicomData.Storedbits_per_pixel := lDicomData.Allocbits_per_pixel; lImageFormatOK := true; 333: FreeMem( lCharRA); end; //******************************************************************** (*procedure ShellSortItems (first, last: integer; var lPositionRA, lIndexRA: LongintP; var lRepeatedValues: boolean); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n,t, nn, m, lognb2, l, k, j, i: longint; begin lRepeatedValues := false; n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 1 to k do begin i := j; 555: {<- LABEL} l := i + m; if (lIndexRA^[lPositionRA^[l]] = lIndexRA^[lPositionRA^[i]]) then begin lRepeatedValues := true; exit; end; if (lIndexRA^[lPositionRA^[l]] < lIndexRA^[lPositionRA^[i]]) then begin //swap values for i and l t := lPositionRA^[i]; lPositionRA^[i] := lPositionRA^[l]; lPositionRA^[l] := t; i := i - m; if (i >= 1) then goto 555; end end end end; //shellsort is fast and requires less memory than quicksort *) (*procedure PAR2DICOMstudyDate(var lDicomData: DICOMdata); {input: lDicomData.StudyDate = 2002.12.29 / 19:48:58.0000 output: StudyDate = YYYYMMDD StudyTime= hhmmss } var I: integer; lStr: string; begin if length(lDicomData.StudyDate) < 14 then exit; lStr := ''; for I := 1 to length(lDicomData.StudyDate) do if lDicomData.StudyDate[I] in ['0'..'9'] then lStr := lStr+ lDicomData.StudyDate[I]; if length(lStr) < 14 then exit; lDicomData.StudyDate := ''; for I := 1 to 8 do lDicomData.StudyDate := lDicomData.StudyDate+lStr[I]; lDicomData.StudyTime := ''; for I := 9 to 14 do lDicomData.StudyTime := lDicomData.StudyTime+lStr[I]; lDicomData.PatientIDInt := StudySecSince2K(lDicomData.StudyDate,lDicomData.StudyTime); end; type tRange = record Min,Val,Max: double; //some vals are ints, others floats end; procedure read_PAR_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK:boolean; var lDynStr: string;var lFileName: string; lReadOffsetTables: boolean; var lOffset_pos_table: LongIntp; var lOffsetTableEntries: integer; lReadVaryingScaleFactors: boolean; var lVaryingScaleFactors_table,lVaryingIntercept_table: Singlep; var lVaryingScaleFactorsTableEntries,lnum4Ddatasets: integer); label 333; //1384 now reads up to 8 dimensional data.... const UNIXeoln = chr(10); kMaxnSLices = 32000; kXdim = 1; kYdim = 2; kBitsPerVoxel = 3; kSliceThick = 4; kSliceGap = 5; kXmm = 6; kYmm = 7; kSlope = 8; kIntercept = 9; kCalibratedSlope = 10; //1393 - attempt to use calibrated values kDynTime = 11; kSlice = 12; kEcho = 13; kDyn = 14; kCardiac = 15; kType = 16; kSequence = 17; kIndex = 18; lIsParVers3x: boolean = true; lRepeatedValues : boolean = false; lSlicesNotInSequence: boolean = false; lMaxSlice : integer = 0; var lErrorStr,lInStr,lUpCaseStr,lReportedTRStr: string; lSliceSequenceRA,lSortedSliceSequence: LongintP; lSliceIndexRA: array [1..kMaxnSlices] of Longint; lSliceSlopeRA,lSliceInterceptRA,lCalibratedSliceSlopeRA: array [1..kMaxnSlices] of single; lSliceHeaderRA: array [1..32] of double; lRangeRA: array [kXdim..kIndex] of tRange; lMaxIndex,lSliceSz,lSliceInfoCount,lPos,lLen,lFileSz,lHdrPos,linPos,lInc: LongInt; fp: file; lCharRA: bytep; procedure MinMaxTRange (var lDimension: tRange; lNewVal: double); //nested begin lDimension.Val := lNewVal; if lSliceInfoCount < 2 then begin lDimension.Min := lDimension.Val; lDimension.Max := lDimension.Val; end; if lNewVal < lDimension.Min then lDimension.Min := lNewVal; if lNewVal > lDimension.Max then lDimension.Max := lNewVal; end; //nested InitTRange proc function readParStr:string;//nested var lStr: string; begin lStr := ''; While (lPos <= lLen) do begin if (lStr <> '') or (linStr[lPos]<>' ') then //strip leading spaces lStr := lStr+(linStr[lPos]); inc(lPos); end; //while lPOs < lLen result := lStr; end; //nested func ReadParStr function readParFloat:double;//nested var lStr: string; begin lStr := ''; result := 1; While (lPos <= lLen) and ((lStr='') or(lInStr[lPos] <> ' ')) do begin if lInStr[lPos] in ['+','-','e','E','.','0'..'9'] then lStr := lStr+(linStr[lPos]); inc(lPos); end; if lStr = '' then exit; try result := strtofloat(lStr); except on EConvertError do begin Msg('read_PAR_data: Unable to convert the string '+lStr+' to a number'); result := 1; exit; end; end; {except} end; //nested func ReadParFloat begin //Initialize parameters lnum4Ddatasets := 1; lSliceInfoCount := 0; for lInc := kXdim to kIndex do //initialize all values: important as PAR3 will not explicitly report all MinMaxTRange(lRangeRA[lInc],0); lHdrOK := false; lImageFormatOK := false; lIsParVers3x := true; lOffsetTableEntries := 0; lVaryingScaleFactorsTableEntries := 0; Clear_Dicom_Data(lDicomData); lDynStr := ''; //Read text header to buffer (lCharRA) FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); lFileSz := FileSize(fp); GetMem( lCharRA, lFileSz+1 ); //note: must free dynamic memory: goto 333 if any error GetMem (lSliceSequenceRA, kMaxnSLices*sizeof(longint)); //note: must free dynamic memory: goto 333 if any error BlockRead(fp, lCharRA^, lFileSz, lInpos); if lInPos <> lFileSz then begin Msg('read_PAR_data: Disk error, unable to read full input file.'); goto 333; end; linPos := 1; CloseFile(fp); FileMode := 2; //set to read/write //Next: read each line of header file... repeat //for each line in file.... linstr := ''; while (linPos < lFileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin lInStr := lInstr + chr(lCharRA^[linPos]); inc(linPos); end; inc(lInPos); //read EOLN lLen := length(lInStr); lPos := 1; lUpcaseStr := ''; if lLen < 1 then //ignore blank lines else if (lInStr[1] = '*') and (not lHdrOK) then //# -> comment //ignore comment lines prior to start of header else if (lInStr[1] = '#') and (lHdrOK) then //# -> comment //ignore comment lines else if (lInStr[1] = '.') or (not lHdrOK) then begin // GENERAL_INFORMATION section (line starts with '.') //Note we also read in lines that do not have '.' if we have HdrOK=false, this allows us to detect the DATADESCRIPTIONFILE signature While (lPos <= lLen) and (lInStr[lPos] <> ':') and ((not lHdrOK) or (lInStr[lPos] <> '#')) do begin if lInStr[lPos] in ['[',']','(',')','/','+','-',{' ',} '0'..'9','a'..'z','A'..'Z'] then lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]); inc(lPos); end; //while reading line inc(lPos); {read equal sign in := statement} lDynStr := lDynStr + lInStr+kCR; if (not lHdrOK) and (lUpcaseStr = ('DATADESCRIPTIONFILE')) then begin //1389 PAR file lHdrOK := true; lDicomData.little_endian := 1; end; if (lUpCaseStr ='REPETITIONTIME[MSEC]') then lDicomData.TR := round(readParFloat); if (lUpCaseStr ='MAXNUMBEROFSLICES/LOCATIONS') then lDicomData.XYZdim[3] := round(readParFloat); if (lUpCaseStr ='SLICETHICKNESS[MM]') then MinMaxTRange(lRangeRA[kSliceThick],readParFloat); if (lUpCaseStr ='SLICEGAP[MM]') then MinMaxTRange(lRangeRA[kSliceGap],readParFloat); if lUpCaseStr = 'RECONRESOLUTION(XY)' then begin MinMaxTRange(lRangeRA[kXdim],readParFloat); MinMaxTRange(lRangeRA[kYdim],readParFloat); end; if lUpCaseStr = 'RECONSTRUCTIONNR' then lDicomData.AcquNum := round(readParFloat); if lUpCaseStr = 'ACQUISITIONNR' then lDicomData.SeriesNum := round(readParFloat); if lUpCaseStr = 'MAXNUMBEROFDYNAMICS' then begin lDicomData.XYZdim[4] := round(readParFloat); end; if lUpCaseStr = 'EXAMINATIONDATE/TIME' then begin lDicomData.StudyDate := readParStr; PAR2DICOMstudyDate(lDicomData); end; //if lUpCaseStr = 'PROTOCOLNAME' then // lDicomData.modality := readParStr; if lUpCaseStr = 'PATIENTNAME' then lDicomData.PatientName := readParStr; if lUpCaseStr ='IMAGEPIXELSIZE[8OR16BITS]' then begin MinMaxTRange(lRangeRA[kBitsPerVoxel],readParFloat); end; if not lHdrOK then begin Msg('read_PAR_data: Error reading header'); goto 333; end; end else begin //SliceInfo: IMAGE_INFORMATION (line does NOT start with '.' or '#') inc(lSliceInfoCount); if (lSliceInfoCount < 2) and (lRangeRA[kBitsPerVoxel].val < 1) then //PARvers3 has imagedepth in general header, only in image header for later versions lIsParVers3x := false; for lHdrPos := 1 to 26 do lSliceHeaderRA[lHdrPos] := readparfloat; //The next few values are in the same location for both PAR3 and PAR4 MinMaxTRange(lRangeRA[kSlice], round(lSliceHeaderRA[1])); MinMaxTRange(lRangeRA[kEcho], round(lSliceHeaderRA[2])); MinMaxTRange(lRangeRA[kDyn], round(lSliceHeaderRA[3])); MinMaxTRange(lRangeRA[kCardiac], round(lSliceHeaderRA[4])); MinMaxTRange(lRangeRA[kType], round(lSliceHeaderRA[5])); MinMaxTRange(lRangeRA[kSequence], round(lSliceHeaderRA[6])); MinMaxTRange(lRangeRA[kIndex], round(lSliceHeaderRA[7])); if lIsParVers3x then begin //Read PAR3 data MinMaxTRange(lRangeRA[kIntercept], lSliceHeaderRA[8]);; //8=intercept in PAR3 MinMaxTRange(lRangeRA[kSlope],lSliceHeaderRA[9]); //9=slope in PAR3 MinMaxTRange(lRangeRA[kCalibratedSlope],lSliceHeaderRA[10]); //10=lcalibrated slope in PAR3 1393 - attempt to use calibrated values MinMaxTRange(lRangeRA[kXmm],lSliceHeaderRA[23]); //23 PIXEL SPACING X in PAR3 MinMaxTRange(lRangeRA[kYmm],lSliceHeaderRA[24]); //24 PIXEL SPACING Y IN PAR3 MinMaxTRange(lRangeRA[kDynTime],(lSliceHeaderRA[26])); //26= dyn_scan_begin_time in PAR3 end else begin //not PAR: assume PAR4 for lHdrPos := 27 to 32 do lSliceHeaderRA[lHdrPos] := readparfloat; MinMaxTRange(lRangeRA[kBitsPerVoxel],lSliceHeaderRA[8]);//8 BITS in PAR4 MinMaxTRange(lRangeRA[kXdim], lSliceHeaderRA[10]); //10 XDim in PAR4 MinMaxTRange(lRangeRA[kYdim], lSliceHeaderRA[11]); //11 YDim in PAR4 MinMaxTRange(lRangeRA[kIntercept],lSliceHeaderRA[12]); //12=intercept in PAR4 MinMaxTRange(lRangeRA[kSlope],lSliceHeaderRA[13]); //13=lslope in PAR4 MinMaxTRange(lRangeRA[kCalibratedSlope],lSliceHeaderRA[14]); //14=lcalibrated slope in PAR4 1393 - attempt to use calibrated values MinMaxTRange(lRangeRA[kSliceThick],lSliceHeaderRA[23]);//23 SLICE THICK in PAR4 MinMaxTRange(lRangeRA[kSliceGap], lSliceHeaderRA[24]); //24 SLICE GAP in PAR4 MinMaxTRange(lRangeRA[kXmm],lSliceHeaderRA[29]); //29 PIXEL SPACING X in PAR4 MinMaxTRange(lRangeRA[kYmm],lSliceHeaderRA[30]); //30 PIXEL SPACING Y in PAR4 MinMaxTRange(lRangeRA[kDynTime],(lSliceHeaderRA[32]));//32= dyn_scan_begin_time in PAR4 end; //PAR4 if lSliceInfoCount < kMaxnSlices then begin lSliceSequenceRA^[lSliceInfoCount] := ( (round(lRangeRA[kSequence].val)+round(lRangeRA[kType].val)+round(lRangeRA[kCardiac].val+lRangeRA[kEcho].val)) shl 24)+(round(lRangeRA[kDyn].val) shl 10)+round(lRangeRA[kSlice].val); lSliceSlopeRA [lSliceInfoCount] := lRangeRA[kSlope].Val; lCalibratedSliceSlopeRA [lSliceInfoCount] := lRangeRA[kCalibratedSlope].Val; lSliceInterceptRA [lSliceInfoCount] := lRangeRA[kIntercept].val; lSliceIndexRA[lSliceInfoCount]:= round(lRangeRA[kIndex].val); end; end; //SliceInfo Line until (linPos >= lFileSz);//until done reading entire file... //describe generic DICOM parameters lDicomData.XYZdim[1] := round(lRangeRA[kXdim].Val); lDicomData.XYZdim[2] := round(lRangeRA[kYdim].Val); lDicomData.XYZdim[3] := 1+round(lRangeRA[kSlice].Max-lRangeRA[kSlice].Min); if (lSliceInfoCount mod lDicomData.XYZdim[3]) <> 0 then Msg('read_PAR_data: Total number of slices not divisible by number of slices per volume. Reconstruction error?'); if lDicomData.XYZdim[3] > 0 then lDicomData.XYZdim[4] := lSliceInfoCount div lDicomData.XYZdim[3] //nVolumes = nSlices/nSlicePerVol else lDicomData.XYZdim[4] := 1; lDicomData.XYZmm[1] := lRangeRA[kXmm].Val; lDicomData.XYZmm[2] := lRangeRA[kYmm].Val; lDicomData.XYZmm[3] := lRangeRA[kSliceThick].Val+lRangeRA[kSliceGap].Val; lDicomData.Allocbits_per_pixel := round(lRangeRA[kBitsPerVoxel].Val); lDicomData.IntenScale := lRangeRA[kSlope].Val; lDicomData.IntenIntercept := lRangeRA[kIntercept].Val; if gPARprecise then begin if (lDicomData.IntenIntercept <> 0) or (lRangeRA[kCalibratedSlope].val = 0) then Msg('Warning: Unable to save calibrated Philips image intensity (non-zero scaling intercept). Turn off Etc/Options/CalibratedScaling to hide warning.'); if (lRangeRA[kSlope].min = lRangeRA[kSlope].max) and (lRangeRA[kIntercept].min = lRangeRA[kIntercept].max) and (lRangeRA[kCalibratedSlope].min = lRangeRA[kCalibratedSlope].max) and (lDicomData.IntenIntercept = 0) and (lRangeRA[kCalibratedSlope].val <> 0) then lDicomData.IntenScale := 1 / lRangeRA[kCalibratedSlope].val; end; //if PARprecise //Next: report number of Dynamic scans, this allows people to parse DynScans from Type/Cardiac/Echo/Sequence 4D files lnum4Ddatasets := (round(lRangeRA[kDyn].Max - lRangeRA[kDyn].Min)+1)*lDicomData.XYZdim[3]; //slices in each dynamic session if ((lSliceInfoCount mod lnum4Ddatasets) = 0) and ((lSliceInfoCount div lnum4Ddatasets) > 1) then lnum4Ddatasets := (lSliceInfoCount div lnum4Ddatasets) //infer multiple Type/Cardiac/Echo/Sequence else lnum4Ddatasets := 1; //next: Determine actual interscan interval if (lDicomData.XYZdim[4] > 1) and ((lRangeRA[kDynTime].max-lRangeRA[kDynTime].min)> 0) {1384} then begin lReportedTRStr := 'Reported TR: '+floattostrf(lDicomData.TR,ffFixed,8,2)+kCR; lDicomData.TR := (lRangeRA[kDynTime].max-lRangeRA[kDynTime].min) /(lDicomData.XYZdim[4] - 1)*1000; //infer TR in ms end else lReportedTRStr :=''; //next: report header details lDynStr := 'Philips PAR/REC Format' //'PAR/REC Format' +kCR+ 'Patient name:'+lDicomData.PatientName +kCR+ 'XYZ dim: ' +inttostr(lDicomData.XYZdim[1])+'/'+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'Volumes: ' +inttostr(lDicomData.XYZdim[4]) +kCR+'XYZ mm: '+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2) +kCR+'TR: '+floattostrf(lDicomData.TR,ffFixed,8,2) +kCR+lReportedTRStr+kCR+lDynStr; //if we get here, the header is fine, next steps will see if image format is readable... lHdrOK := true; if lSliceInfoCount < 1 then goto 333; //next: see if slices are in sequence lSlicesNotInSequence := false; if lSliceInfoCount > 1 then begin lMaxSlice := lSliceSequenceRA^[1]; lMaxIndex := lSliceIndexRA[1]; lInc := 1; repeat inc(lInc); if lSliceSequenceRA^[lInc] < lMaxSlice then //not in sequence if image has lower slice order than previous image lSlicesNotInSequence := true else lMaxSlice := lSliceSequenceRA^[lInc]; if lSliceIndexRA[lInc] < lMaxIndex then //not in sequence if image has lower slice index than previous image lSlicesNotInSequence := true else lMaxIndex := lSliceIndexRA[lInc]; until (lInc = lSliceInfoCount) or (lSlicesNotInSequence); end; //at least 2 slices //Next: report any errors lErrorStr := ''; if (lSlicesNotInSequence) and (not lReadOffsetTables) then lErrorStr := lErrorStr + ' Slices not saved sequentially [using MRIcro''s ''Philips PAR to Analyze'' command may solve this]'+kCR; if lSliceInfoCount > kMaxnSlices then lErrorStr := lErrorStr + ' Too many slices: >'+inttostr(kMaxnSlices)+kCR; if (not lReadVaryingScaleFactors) and ( (lRangeRA[kSlope].min <> lRangeRA[kSlope].max) or (lRangeRA[kIntercept].min <> lRangeRA[kIntercept].max)) then lErrorStr := lErrorStr + ' Differing intensity slope/intercept [using MRIcro''s ''Philips PAR to Analyze'' command may solve this]'+kCR; if (lRangeRA[kBitsPerVoxel].min <> lRangeRA[kBitsPerVoxel].max) then //5D file space+time+cardiac lErrorStr := lErrorStr + ' Differing bits per voxel'+kCR; //if (lRangeRA^[kCardiac].min <> lRangeRA^[kCardiac].max) then //5D file space+time+cardiac // lErrorStr := lErrorStr + 'Multiple cardiac timepoints'+kCR; //if (lRangeRA^[kEcho].min <> lRangeRA^[kEcho].max) then //5D file space+time+echo // lErrorStr := lErrorStr + 'Multiple echo timepoints'+kCR; if (lRangeRA[kSliceThick].min <> lRangeRA[kSliceThick].max) or (lRangeRA[kSliceGap].min <> lRangeRA[kSliceGap].max) or (lRangeRA[kXdim].min <> lRangeRA[kXdim].max) or (lRangeRA[kYDim].min <> lRangeRA[kYDim].max) or (lRangeRA[kXmm].min <> lRangeRA[kXmm].max) or (lRangeRA[kYmm].min <> lRangeRA[kYmm].max) then lErrorStr := lErrorStr + ' Multiple/varying slice dimensions'+kCR; //if any errors were encountered, report them.... if lErrorStr <> '' then begin Msg('read_PAR_data: This software can not convert this Philips data:'+kCR+lErrorStr); goto 333; end; //Next sort image indexes here... if (lSliceInfoCount > 1) and(lSlicesNotInSequence) and ( lReadOffsetTables) then begin //sort image order... //ShellSort (first, last: integer; var lPositionRA, lIndexLoRA,lIndexHiRA: LongintP; var lRepeatedValues: boolean) GetMem (lOffset_pos_table, lSliceInfoCount*sizeof(longint)); for lInc := 1 to lSliceInfoCount do lOffset_pos_table^[lInc] := lInc; ShellSortItems (1, lSliceInfoCount,lOffset_pos_table,lSliceSequenceRA, lRepeatedValues); if lRepeatedValues then begin Msg('read_PAR_data: fatal error, slices do not appear to have unique indexes [multiple copies of same slice]'); FreeMem (lOffset_pos_table); goto 333; end; lOffsetTableEntries := lSliceInfoCount; end; //sort image order... //Next, generate list of scale slope if (lSliceInfoCount > 1) and (lReadVaryingScaleFactors) and ( (lRangeRA[kSlope].min <> lRangeRA[kSlope].max) or (lRangeRA[kIntercept].min <> lRangeRA[kIntercept].max)) then begin {create offset LUT} lVaryingScaleFactorsTableEntries := lSliceInfoCount; getmem (lVaryingScaleFactors_table, lVaryingScaleFactorsTableEntries*sizeof(single)); getmem (lVaryingIntercept_table, lVaryingScaleFactorsTableEntries*sizeof(single)); if lOffsetTableEntries = lSliceInfoCount then begin //need to sort slices for lInc := 1 to lSliceInfoCount do begin lVaryingScaleFactors_table^[lInc] := lSliceSlopeRA[lOffset_pos_table^[lInc]]; lVaryingIntercept_table^[lInc] := lSliceInterceptRA[lOffset_pos_table^[lInc]]; if gPARprecise then begin if (lVaryingIntercept_table^[lInc] <> 0) or (lCalibratedSliceSlopeRA[lOffset_pos_table^[lInc]]=0) then Msg('Warning: Unable to save calibrated Philips image intensity (non-zero scaling intercept). Turn off Etc/Options/CalibratedScaling to hide warning.') else begin lVaryingScaleFactors_table^[lInc] := 1 / lCalibratedSliceSlopeRA[lOffset_pos_table^[lInc]]; end; end; //if PARprecise end; end else begin //if sorted, else unsorted for lInc := 1 to lSliceInfoCount do begin lVaryingScaleFactors_table^[lInc] := lSliceSlopeRA[lInc]; lVaryingIntercept_table^[lInc] := lSliceInterceptRA[lInc]; if gPARprecise then begin if (lVaryingIntercept_table^[lInc] <> 0) or (lCalibratedSliceSlopeRA[lInc]=0) then Msg('Warning: Unable to save calibrated Philips image intensity (non-zero scaling intercept). Turn off Etc/Options/CalibratedScaling to hide warning.') else lVaryingScaleFactors_table^[lInc] := 1 / lCalibratedSliceSlopeRA[lInc]; end; //if PARprecise end; end; //slices sorted end;//read scale factors //Next: now adjust Offsets to point to byte offset instead of slice number lSliceSz := lDicomData.XYZdim[1]*lDicomData.XYZdim[2]*(lDicomData.Allocbits_per_pixel div 8); if lOffsetTableEntries = lSliceInfoCount then for lInc := 1 to lSliceInfoCount do lOffset_pos_table^[lInc] := lSliceSz * (lSliceIndexRA[lOffset_pos_table^[lInc]]); //report if 5D/6D/7D file is being saved as 4D if (lRangeRA[kCardiac].min <> lRangeRA[kCardiac].max) or (lRangeRA[kEcho].min <> lRangeRA[kEcho].max) //5D file space+time+echo or (lRangeRA[kType].min <> lRangeRA[kType].max) //5D file space+time+echo or (lRangeRA[kSequence].min <> lRangeRA[kSequence].max) then //5D file space+time+echo Msg('Warning: note that this image has more than 4 dimensions (multiple Cardiac/Echo/Type/Sequence)'); //if we get here, the Image Format is OK lImageFormatOK := true; lFileName := changefileextX(lFilename,'.rec'); //for Linux: case sensitive extension search '.rec' <> '.REC' 333: //abort clause: skips lHdrOK and lImageFormatOK //next: free dynamically allocated memory FreeMem( lCharRA); FreeMem (lSliceSequenceRA); end; *) procedure read_ge_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); label 539; var lGap,lSliceThick,lTempFloat: single; lTemp16,lI: word; lSeriesOffset,lTemp32,lExamHdr,lImgHdr,lDATFormatOffset,lHdrOffset,lCompress,linitialoffset,n,filesz: LongInt; tx : array [0..36] of Char; FP: file; lGEodd,lGEFlag,{lSpecial,}lMR: boolean; function GEflag: boolean; begin if (tx[0] = 'I') AND (tx[1]= 'M') AND (tx[2] = 'G')AND (tx[3]= 'F') then result := true else result := false; end; function swap16i(lPos: longint): word; var w : Word; begin seek(fp,lPos-2); BlockRead(fp, W, 2); result := swap(W); end; function swap32i(lPos: longint): Longint; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(Long:LongInt); end; swaptypep = ^swaptype; var s : LongInt; inguy:swaptypep; outguy:swaptype; begin seek(fp,lPos); BlockRead(fp, s, 4, n); inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); swap32i:=outguy.Long; end; function fswap4r (lPos: longint): single; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(float:single); end; swaptypep = ^swaptype; var s:single; inguy:swaptypep; outguy:swaptype; begin seek(fp,lPos); BlockRead(fp, s, 4, n); inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); fswap4r:=outguy.float; end; begin lImageFormatOK := true; lSeriesOffset := 0; lSLiceThick := 0; lGap := 0; lHdrOK := false; lHdrOffset := 0; if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FIleSz := FileSize(fp); lDATFormatOffset := 0; Clear_Dicom_Data(lDicomData); if filesz < (3240) then begin Msg('This file is too small to be a Genesis DAT format image.'); goto 539; end; lDynStr:= ''; //lGEFlag := false; lInitialOffset := 3228;//3240; seek(fp, lInitialOffset); BlockRead(fp, tx, 4*SizeOf(Char), n); lGEflag := GEFlag; if not lGEFlag then begin lInitialOffset := 3240; seek(fp, lInitialOffset); BlockRead(fp, tx, 4*SizeOf(Char), n); lGEflag := GEFlag; end; lGEodd := lGEFlag; if not lGEFlag then begin lInitialOffset := 0; seek(fp, lInitialOffset); BlockRead(fp, tx, 4*SizeOf(Char), n); if not GEflag then begin {DAT format} lDynStr := lDynStr+'GE Genesis Signa DAT tape format'+kCR; seek(fp,114); BlockRead(fp, tx, 4*SizeOf(Char), n); lDynStr := lDynStr + 'Suite: '; for lI := 0 to 3 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; seek(fp,114+97); BlockRead(fp, tx, 25*SizeOf(Char), n); lDynStr := lDynStr + 'Patient Name: '; for lI := 0 to 24 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; seek(fp,114+84); BlockRead(fp, tx, 13*SizeOf(Char), n); lDynStr := lDynStr + 'Patient ID: '; for lI := 0 to 12 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; seek(fp, 114+305); BlockRead(fp, tx, 3*SizeOf(Char), n); if (tx[0]='M') and (tx[1] = 'R') then lMR := true else if (tx[0] = 'C') and(tx[1] = 'T') then lMR := false else begin Msg('Is this a Genesis DAT image? The modality is '+tx[0]+tx[1]+tx[3] +'. Expected ''MR'' or ''CT''.'); goto 539; end; if lMR then lInitialOffset := 3180 else lInitialOffset := 3178; seek(fp, lInitialOffset); BlockRead(fp, tx, 4*SizeOf(Char), n); if (tx[0] <> 'I') OR (tx[1] <> 'M') OR (tx[2] <> 'G') OR (tx[3] <> 'F') then begin Msg('This image does not have the required label ''IMGF''. This is not a Genesis DAT image.'); goto 539; end else lDicomData.ImageNum := swap16i(2158+12); lDicomData.XYZmm[3] := fswap4r (2158+26);// slice thickness mm lDicomData.XYZmm[1] := fswap4r (2158+50);// pixel size- X lDicomData.XYZmm[2] := fswap4r (2158+54);//pixel size - Y lSliceThick := lDicomData.XYZmm[3]; lGap := fswap4r (lHdrOffset+118);//1410 gap thickness mm if lGap > 0 then lDicomData.XYZmm[3] := lDicomData.XYZmm[3] + lGap; lDATFormatOffset := 4; if lMR then begin lTemp32 := swap32i(2158+194); lDynStr := lDynStr +'TR[usec]: '+inttostr(lTemp32) + kCR; lTemp32 := swap32i(2158+198); lDynStr := lDynStr +'TInvert[usec]: '+inttostr(lTemp32) + kCR; lTemp32 := swap32i(2158+202); lDynStr := lDynStr +'TE[usec]: '+inttostr(lTemp32) + kCR; lTemp16 := swap16i(2158+210); lDynStr := lDynStr +'Number of echoes: '+inttostr(lTemp16) + kCR; lTemp16 := swap16i(2158+212); lDynStr := lDynStr +'Echo: '+inttostr(lTemp16) + kCR; lTempFloat := fswap4r (2158+50); //not sure why I changed this to 50... 218 in Clunie's Description lDynStr := lDynStr +'NEX: '+floattostr(lTempFloat) + kCR; seek(fp,2158+308); BlockRead(fp, tx, 33*SizeOf(Char), n); lDynStr := lDynStr + 'Sequence: '; for lI := 0 to 32 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; seek(fp,2158+362); BlockRead(fp, tx, 17*SizeOf(Char), n); lDynStr := lDynStr + 'Coil: '; for lI := 0 to 16 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; end; end; {DAT format} end; lDicomData.ImageStart := lDATFormatOffset+linitialoffset + swap32i(linitialoffset+4);//byte displacement to image data lDicomData.XYZdim[1] := swap32i(linitialoffset+8); //width lDicomData.XYZdim[2] := swap32i(linitialoffset+12);//height lDicomData.Allocbits_per_pixel := swap32i(linitialoffset+16);//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; lCompress := swap32i(linitialoffset+20); //compression lExamHdr := swap32i(linitialoffset+136); lImgHdr := swap32i(linitialoffset+152); if (lImgHdr = 0) and (lDicomData.ImageStart = 8432) then begin lDicomData.ImageNum := swap16i(2310+12); lDicomData.XYZmm[3] := fswap4r (2310+26);// slice thickness mm lDicomData.XYZmm[1] := fswap4r (2310+50);// pixel size- X lDicomData.XYZmm[2] := fswap4r (2310+54);//pixel size - Y lSliceThick := lDicomData.XYZmm[3]; lGap := fswap4r (lHdrOffset+118);//1410 gap thickness mm if lGap > 0 then lDicomData.XYZmm[3] := lDicomData.XYZmm[3] + lGap; end else if {(lSpecial = false) and} (lDATFormatOffset = 0) then begin lDynStr := lDynStr+'GE Genesis Signa format'+kCR; if (not lGEodd) and (lExamHdr <> 0) then begin lHdrOffset := swap32i(linitialoffset+132);//x132- int ptr to exam heade //Patient ID seek(fp,lHdrOffset+84); BlockRead(fp, tx, 13*SizeOf(Char), n); lDynStr := lDynStr + 'Patient ID: '; for lI := 0 to 12 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; //Patient Name seek(fp,lHdrOffset+97); BlockRead(fp, tx, 25*SizeOf(Char), n); lDynStr := lDynStr + 'Patient Name: '; for lI := 0 to 24 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; //Patient Age lI := swap16i(lHdrOffset+122); lDynStr := lDynStr+'Patient Age: '+inttostr(lI)+kCR; //Modality: MR or CT seek(fp,lHdrOffset+305); BlockRead(fp, tx, 3*SizeOf(Char), n); lDynStr := lDynStr + 'Type: '; for lI := 0 to 1 do lDynStr := lDynStr + tx[lI]; lDynStr := lDynStr + kCR; //Read series header lSeriesOffset := swap32i(linitialoffset+144);//read size of series header: only read if >0 if lSeriesOffset > 12 then begin lSeriesOffset := swap32i(linitialoffset+140);//read size of series header: only read if >0 lI := swap16i(lSeriesOffset+10); //lDynStr := lDynStr+'Series number: '+inttostr(lI)+kCR; lDicomData.SeriesNum := lI; end; //image data lHdrOffset := swap32i(linitialoffset+148);//x148- int ptr to image heade end; if lGEodd then lHdrOffset := 2158+28; if ((lHdrOffset +58) < FileSz) and (lImgHdr <> 0) then begin lDicomData.AcquNum := swap16i(lHdrOffset+12); //note SERIES not IMAGE number, despite what Clunies FAQ says lDicomData.ImageNum := swap16i(lHdrOffset+14); //this is IMAGEnum //lDynStr := lDynStr +'Image number: '+inttostr(lDicomData.ImageNum)+ kCR; lDicomData.XYZmm[3] := fswap4r (lHdrOffset{linitialoffset+lHdrOffset}+26);// slice thickness mm lDicomData.XYZmm[1] := fswap4r (lHdrOffset{linitialoffset+lHdrOffset}+50);// pixel size- X lDicomData.XYZmm[2] := fswap4r (lHdrOffset{linitialoffset+lHdrOffset}+54);//pixel size - Y lSliceThick := lDicomData.XYZmm[3]; lGap := fswap4r (lHdrOffset+118);//1410 gap thickness mm if lGap > 0 then lDicomData.XYZmm[3] := lDicomData.XYZmm[3] + lGap; end; end; if (lCompress = 3) or (lCompress = 4) then begin lImageFormatOK := false;//xlDicomData.GenesisCpt := true; lDynStr := lDynStr+'Compressed data'+kCR; end else ;//xlDicomData.GenesisCpt := false; if (lCompress = 2) or (lCompress = 4) then begin lImageFormatOK := false;//xlDicomData.GenesisPackHdr := swap32i(linitialoffset+64); lDynStr := lDynStr+'Packed data'+kCR; end else //xlDicomData.GenesisPackHdr := 0; lDynStr := lDynStr+'Series Number: '+inttostr(lDicomData.SeriesNum) +kCR+'Acquisition Number: '+inttostr(lDicomData.AcquNum) +kCR+'Image Number: '+inttostr(lDicomData.ImageNum) +kCR+'Slice Thickness/Gap: '+floattostrf(lSliceThick,ffFixed,8,2)+'/'+floattostrf(lGap,ffFixed,8,2) +kCR+'XYZ dim: ' +inttostr(lDicomData.XYZdim[1])+'/'+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'XYZ mm: '+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2); lHdrOK := true; 539: CloseFile(fp); FileMode := 2; //set to read/write end;//read_ge //start siemens procedure read_siemens_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); label 567; var lI: word; lYear,lMonth,lDay,n,filesz,lFullSz,lMatrixSz,lIHour,lIMin,lISec{,lAHour,lAMin,lASec}: LongInt; lFlipAngle,lGap,lSliceThick: double; tx : array [0..26] of Char; lMagField,lTE,lTR: double; lInstitution,lName, lID,lMinStr,lSecStr{,lAMinStr,lASecStr}: String; FP: file; function swap32i(lPos: longint): Longint; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(Long:LongInt); end; swaptypep = ^swaptype; var s : LongInt; inguy:swaptypep; outguy:swaptype; begin seek(fp,lPos); BlockRead(fp, s, 4, n); inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); swap32i:=outguy.Long; //swap32i:=inguy.Long; end; function fswap8r (lPos: longint): double; type swaptype = packed record case byte of 0:(Word1,Word2,Word3,Word4 : word); //word is 16 bit 1:(float:double); end; swaptypep = ^swaptype; var s:double; inguy:swaptypep; outguy:swaptype; begin seek(fp,lPos); BlockRead(fp, s, 8, n); inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word4); outguy.Word2 := swap(inguy^.Word3); outguy.Word3 := swap(inguy^.Word2); outguy.Word4 := swap(inguy^.Word1); fswap8r:=outguy.float; end; begin lImageFormatOK := true; lHdrOK := false; if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FIleSz := FileSize(fp); Clear_Dicom_Data(lDicomData); if filesz < (6144) then begin Msg('This file is to small to be a Siemens Magnetom Vision image.'); goto 567; end; seek(fp, 96); BlockRead(fp, tx, 7*SizeOf(Char), n); if (tx[0] <> 'S') OR (tx[1] <> 'I') OR (tx[2] <> 'E') OR (tx[3] <> 'M') then begin {manufacturer is not SIEMENS} Msg('Is this a Siemens Magnetom Vision image [Manufacturer tag should be ''SIEMENS''].'); goto 567; end; {manufacturer not siemens} seek(fp, 105); BlockRead(fp, Tx, 25*SizeOf(Char), n); lINstitution := ''; for lI := 0 to 24 do begin if tx[lI] in ['/','\','a'..'z','A'..'Z',' ','+','-','.',',','0'..'9'] then lINstitution := lINstitution + tx[lI]; end; seek(fp, 768); BlockRead(fp, Tx, 25*SizeOf(Char), n); lName := ''; for lI := 0 to 24 do begin if tx[lI] in ['/','\','a'..'z','A'..'Z',' ','+','-','.',',','0'..'9'] then lName := lName + tx[lI]; end; seek(fp, 795); BlockRead(fp, Tx, 12*SizeOf(Char), n); lID := ''; for lI := 0 to 11 do begin if tx[lI] in ['/','\','a'..'z','A'..'Z',' ','+','-','.',',','0'..'9'] then lID := lID + tx[lI]; end; lDicomData.ImageStart := 6144; lYear := swap32i(0); lMonth := swap32i(4); lDay := swap32i(8); lIHour := swap32i(68); lIMin := swap32i(72); lISec := swap32i(76); lDicomData.XYZmm[3] := fswap8r (1544); lMagField := fswap8r (2560); lTR := fswap8r (1560); lTE := fswap8r (1568); lDIcomData.AcquNum := swap32i(3212); lMatrixSz := swap32i(2864); lDicomData.SiemensSlices := swap32i(4004); //1366 //lFullSz := swap32i(4008); //lInterleaveIf4 := swap32i(2888); lFullSz := (2*lMatrixSz*lMatrixSz);//16bitdata if ((FileSz - 6144) mod lFullSz) = 0 then begin case ((FileSz-6144) div lFullSz) of 4: lFullSz := 2*lMatrixSz; 9: lFullSz := 3*lMatrixSz; 16: lFullSz := 4*lMatrixSz; 25: lFullSz := 5*lMatrixSz; 36: lFullSz := 6*lMatrixSz; 49: lFullSz := 7*lMatrixSz; 64: lFullSz := 8*lMatrixSz; else lFullSz := lMatrixSz; end; end else lFullSz := lMatrixSz; {3744/3752 are XY FOV in mm!} lDicomData.XYZdim[1] := lFullSz;//lMatrixSz; //width lDicomData.XYZdim[2] := lFullSz;//lMatrixSz;//height {5000/5008 are size in mm, but wrong for mosaics} if lMatrixSz <> 0 then begin lDicomData.XYZmm[2] := fswap8r (3744)/lMatrixSz; lDicomData.XYZmm[1] := fswap8r (3752)/lMatrixSz; if ((lDicomData.XYZdim[1] mod lMatrixSz)=0) then lDicomData.SiemensMosaicX := lDicomData.XYZdim[1] div lMatrixSz; if ((lDicomData.XYZdim[2] mod lMatrixSz)=0) then lDicomData.SiemensMosaicY := lDicomData.XYZdim[2] div lMatrixSz; if lDicomData.SiemensMosaicX < 1 then lDicomData.SiemensMosaicX := 1; //1366 if lDicomData.SiemensMosaicY < 1 then lDicomData.SiemensMosaicY := 1; //1366 end; lFlipAngle := fswap8r (2112); //1414 { lDicomData.XYZmm[2] := fswap8r (5000); lDicomData.XYZmm[1] := fswap8r (5008);} lSliceThick := lDicomData.XYZmm[3]; lGap := fswap8r (4136); //gap as ratio of slice thickness?!?! if {lGap > 0} (lGap=-1) or (lGap=-19222) then //1410: exclusion values: do not ask me why 19222: from John Ashburner else begin //lDicomData.XYZmm[3] := abs(lDicomData.XYZmm[3] * (1+lGap)); lGap := lDicomData.XYZmm[3] * (lGap); lDicomData.XYZmm[3] := abs(lDicomData.XYZmm[3] +lGap); end; lDicomData.Allocbits_per_pixel := 16;//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; //xlDicomData.GenesisCpt := false; //xlDicomData.GenesisPackHdr := 0; lMinStr := inttostr(lIMin); if length(lMinStr) = 1 then lMinStr := '0'+lMinStr; lSecStr := inttostr(lISec); if length(lSecStr) = 1 then lSecStr := '0'+lSecStr; lDynStr := 'Siemens Magnetom Vision Format'+kCR+'Name: '+lName+kCR+'ID: '+lID+kCR+'Institution: '+lInstitution+kCR+ 'Study DD/MM/YYYY: '+inttostr(lDay)+'/'+inttostr(lMonth)+'/'+inttostr(lYear)+kCR+ 'Image Hour/Min/Sec: '+inttostr(lIHour)+':'+lMinStr+':'+lSecStr+kCR+ //'Acquisition Hour/Min/Sec: '+inttostr(lAHour)+':'+lAMinStr+':'+lASecStr+kCR+ 'Magnetic Field Strength: '+ floattostrf(lMagField,ffFixed,8,2)+kCR+ 'Image index: '+inttostr(lDIcomData.AcquNum)+kCR+ 'Time Repitition/Echo [TR/TE]: '+ floattostrf(lTR,ffFixed,8,2)+'/'+ floattostrf(lTE,ffFixed,8,2)+kCR+ 'Flip Angle: '+ floattostrf(lFlipAngle,ffFixed,8,2)+kCR+ 'Slice Thickness/Gap: '+floattostrf(lSliceThick,ffFixed,8,2)+'/'+floattostrf(lGap,ffFixed,8,2)+kCR+ 'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3])+kCR+ 'XY matrix:' +inttostr(lDicomData.SiemensMosaicX)+'/' +inttostr(lDicomData.SiemensMosaicY)+kCR+ 'XYZ mm:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2); lHdrOK := true; //lDIcomData.AcquNum := 0; 567: CloseFile(fp); FileMode := 2; //set to read/write end; //end siemens //begin elscint procedure read_elscint_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); label 539; var //lExamHdr,lImgHdr,lDATFormatOffset,lHdrOffset, {lDate,}lI,lCompress,n,filesz: LongInt; tx : array [0..41] of Char; FP: file; function readStr(lPos,lLen: integer): string; var lStr: string; lStrInc: integer; begin seek(fp,lPos); BlockRead(fp, tx, lLen, n); lStr := ''; for lStrInc := 0 to (lLen-1) do lStr := lStr + tx[lStrInc]; result := lStr end; function read8ch(lPos: integer): char; begin seek(fp,40); BlockRead(fp, result, 1, n); //lDicomData.ImageNum := ord(tx[0]); end; procedure read16i(lPos: longint; var lVal: integer); var lInWord: word; begin seek(fp,lPos); BlockRead(fp, lInWord, 2); lVal := lInWord; end; procedure read32i(lPos: longint; var lVal: integer); var lInINt: integer; begin seek(fp,lPos); BlockRead(fp, lInINt, 4); lVal :=lInINt; end; begin lImageFormatOK := true; lHdrOK := false; if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FIleSz := FileSize(fp); Clear_Dicom_Data(lDicomData); if filesz < (3240) then begin Msg('This file is too small to be a Elscint format image.'); goto 539; end; lDynStr:= ''; read16i(0, lI); if (lI <> 64206) then begin Msg('Unable to read this file: it does start with the Elscint signature.'); goto 539; end; lDicomdata.little_endian := 1; lDynStr:= 'Elscint Format'+kCR; lDynStr := lDynStr+'Patient Name: '+readstr(4,20)+kCR; lDynStr := lDynStr+'Patient ID: '+readstr(24,13)+kCR; read16i(38,lDicomData.AcquNum); lDicomData.ImageNum := ord(read8Ch(40)); lDynStr := lDynStr+'Doctor & Ward: '+readstr(100,20)+kCR; lDynStr := lDynStr+'Comments: '+readstr(120,40)+kCR; if ord(read8Ch(163)) = 1 then lDynStr := lDynStr + 'Sex: M'+kCR else lDynStr := lDynStr + 'Sex: F'+kCR; read16i(200,lI); lDicomData.XYZmm[3] := lI * 0.1; read16i(370,lDicomData.XYZdim[1]); read16i(372,lDicomData.XYZdim[2]); read16i(374,lI); lDicomData.XYZmm[1] := lI / 256; lDicomData.XYZmm[2] := lDicomData.XYZmm[1]; lCompress := ord(read8Ch(376)); //xlDicomData.ElscintCompress := true; //xread16i(400,lDicomData.WindowWidth); //x read16i(398,lDicomData.WindowCenter); case lCompress of 0: begin lDynStr := lDynStr + 'Compression: None'+kCR; //xlDicomData.ElscintCompress := false; end; 1: lImageFormatOK := false;//xlDynStr := lDynStr + 'Compression: Old'+kCR; 2: lImageFormatOK := false;//xlDynStr := lDynStr + 'Compression: 2400 Elite'+kCR; 22: lImageFormatOK := false;//xlDynStr := lDynStr + 'Compression: Twin'+kCR; else begin lImageFormatOK := false;//xlDynStr := lDynStr + 'Compression: Unknown '+inttostr(lCOmpress)+kCR; //lDicomData.ElscintCompress := false; end; end; //lDicomData.XYZdim[1] := swap32i(linitialoffset+8); //width //lDicomData.XYZdim[2] := swap32i(linitialoffset+12);//height lDicomData.ImageStart := 396; lDicomData.Allocbits_per_pixel := 16; //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; if (lDicomData.XYZdim[1]=160) and (lDicomData.XYZdim[2]= 160) and (FIleSz=52224) then begin lDicomData.ImageStart := 1024; lImageFormatOK := true;//x//xlDicomData.ElscintCompress := False; end; //lDicomData.XYZmm[3] := fswap4r (2310+26);// slice thickness mm lDynStr := lDynStr+'Image/Study Number: '+inttostr(lDicomData.ImageNum)+'/'+ inttostr(lDicomData.AcquNum)+kCR +'XYZ dim: ' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) //x+kCR+'Window Center/Width: '+inttostr(lDicomData.WindowCenter)+'/'+inttostr(lDicomData.WindowWidth) +kCR+'XYZ mm: '+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2); lHdrOK := true; lImageFormatOK := true; 539: CloseFile(fp); FileMode := 2; //set to read/write end; //end elscint //start picker procedure read_picker_data(lVerboseRead: boolean; var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); label 423; const kPickerHeader =8192; kRecStart = 280; //is this a constant? var lDataStart,lVal,lDBPos,lPos,lRecSz, lNumRecs,lRec,FileSz,n: Longint; lThkM,lThkN,lSiz: double; tx : array [0..6] of Char; FP: file; lDiskCacheRA: pChar; function ReadRec(lRecNum: integer): boolean; var lNameStr,lValStr: string; lOffset,lLen,lFPOs,lFEnd: integer; function ValStrToFloat: double; var lConvStr: string; lI: integer; begin Result := 0.0; lLen := Length(lValStr); if lLen < 1 then exit; lConvStr := ''; for lI := 1 to lLen do if lValStr[lI] in ['0'..'9'] then lConvStr := lConvStr+ lValStr[lI]; if Length(lConvStr) < 1 then exit; Result := strtofloat(lConvStr); end; begin Result := false; lFPos := ((lRecNum-1) * lRecSz)+ kRecStart; lFEnd := lFpos + 6; lNameStr := ''; for lFPos := lFPos to lFEnd do if ord(lDiskCacheRA[lFPos]) <> 0 then lNameStr := lNameStr +lDiskCacheRA[lFPos]; if (lVerboseRead) or (lNameStr = 'RCNFSIZ') or (lNameStr='SCNTHKM') or (lNameStr='SCNTHKN') then begin lFPos := ((lRecNum-1) * lRecSz)+ kRecStart+8; lFEnd := lFPos+1; lOffset := 0; for lFPos := lFPos to lFend do lOffset := ((lOffset)shl 8)+(ord(lDiskCacheRA[lFPos])); lFPos := ((lRecNum-1) * lRecSz)+ kRecStart+10; lFEnd := lFPos+1; lLen := 0; for lFPos := lFPos to lFend do lLen := ((lLen)shl 8)+(ord(lDiskCacheRA[lFPos])); lOffset := lDataStart+lOffset+1; lFEnd := lOffset+lLen-1; if (lLen < 1) or (lFEnd > kPickerHeader) then exit; lValStr := ''; for lFPos := (lOffset) to lFEnd do begin lValStr := lValStr+lDiskCacheRA[lFPos]; end; if lVerboseRead then lDynStr := lDynStr+kCR+lNameStr+': '+ lValStr; if (lNameStr = 'RCNFSIZ') then lSiz := ValStrToFloat; if (lNameStr='SCNTHKM') then lThkM := ValStrToFloat; if (lNameStr='SCNTHKN') then lThkN := ValStrToFloat; end; //verboseread, or vital value result := true; end; function FindStr(l1,l2,l3,l4,l5: Char; lReadNum: boolean; var lNum: integer): boolean; var //lMarker: integer; lNumStr: String; begin Result := false; repeat if (lDiskCacheRA[lPos-4]=l1) and (lDiskCacheRA[lPos-3]=l2) and (lDiskCacheRA[lPos-2]=l3) and (lDiskCacheRA[lPos-1]=l4) and (lDiskCacheRA[lPos]=l5) then Result := true; inc (lPos); until (Result) or (lPos >= kPickerHeader); if not Result then exit; if not lReadNum then exit; Result := false; lNumStr := ''; repeat if (lDiskCacheRA[lPos] in ['0'..'9']) then lNumStr := lNumStr + lDiskCacheRA[lPos] else if lNumStr <> '' then Result := true; inc(lPos); until (Result) or (lPos = kPickerHeader); lNum := strtoint(lNumStr); end; begin lSiz := 0.0; lThkM := 0.0; lThkN := 0.0; lImageFormatOK := true; lHdrOK := false; if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FIleSz := FileSize(fp); Clear_Dicom_Data(lDicomData); if filesz < (kPickerHeader) then begin Msg('This file is to small to be a Picker image: '+lFileName ); CloseFile(fp); FileMode := 2; //set to read/write exit; end; seek(fp, 0); BlockRead(fp, tx, 4*SizeOf(Char), n); if (tx[0] <> '*') OR (tx[1] <> '*') OR (tx[2] <> '*') OR (tx[3] <> ' ') then begin {manufacturer is not SIEMENS} Msg('Is this a Picker image? Expected ''***'' at the start of the file.'+ lFileName); CloseFile(fp); FileMode := 2; //set to read/write exit; end; {not picker} if filesz = (kPickerHeader + (1024*1024*2)) then begin lDICOMdata.XYZdim[1] := 1024; lDICOMdata.XYZdim[2] := 1024; lDICOMdata.XYZdim[3] := 1; lDICOMdata.ImageStart := 8192; end else if filesz = (kPickerHeader + (512*512*2)) then begin lDICOMdata.XYZdim[1] := 512; lDICOMdata.XYZdim[2] := 512; lDICOMdata.XYZdim[3] := 1; lDICOMdata.ImageStart := 8192; end else if filesz = (8192 + (256*256*2)) then begin lDICOMdata.XYZdim[1] := 256; lDICOMdata.XYZdim[2] := 256; lDICOMdata.XYZdim[3] := 1; lDICOMdata.ImageStart := 8192; end else begin Msg('This file is the incorrect size to be a Picker image.'); CloseFile(fp); FileMode := 2; //set to read/write exit; end; getmem(lDiskCacheRA,kPickerHeader*sizeof(char)); seek(fp, 0); BlockRead(fp, lDiskCacheRA, kPickerHeader, n); lRecSz := 0; lNumRecs := 0; lPos := 5; if not FindStr('d','b','r','e','c',false, lVal) then goto 423; lDBPos := lPos; if not FindStr('r','e','c','s','z',true, lRecSz) then goto 423; lPos := lDBPos; if not FindStr('n','r','e','c','s',true, lnumRecs) then goto 423; lPos := kRecStart; // IS THIS A CONSTANT??? lDataStart :=kRecStart + (lRecSz*lnumRecs)-1; //file starts at 0, so -1 if (lNumRecs = 0) or (lDataStart> kPickerHeader) then goto 423; lRec := 0; lDynStr := 'Picker Format'; repeat inc(lRec); until (not (ReadRec(lRec))) or (lRec >= lnumRecs); if lSiz <> 0 then begin lDICOMdata.XYZmm[1] := lSiz/lDICOMdata.XYZdim[1]; lDICOMdata.XYZmm[2] := lSiz/lDICOMdata.XYZdim[2]; if lVerboseRead then lDynStr := lDynStr+kCR+'Voxel Size: '+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2) +'x'+ floattostrf(lDicomData.XYZmm[2],ffFixed,8,2); end; if (lThkM <> 0) and (lThkN <> 0) then begin lDICOMdata.XYZmm[3] := lThkN/lThkM; if lVerboseRead then lDynStr := lDynStr+kCR+'Slice Thickness: '+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2); end; 423: freemem(lDiskCacheRA); lHdrOK := true; CloseFile(fp); FileMode := 2; //set to read/write end; //end picker procedure read_minc_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); var // lReal: double; lnOri,lnDim,lStartPosition,nelem0,jj,lDT0,vSizeRA,BeginRA,m,nnelem,nc_type,nc_size,lLen,nelem,j,lFilePosition,lDT,lFileSz,lSignature,lWord: integer; lOri: array [1..3] of double; //tx : array [0..80] of Char; lVarStr,lStr: string; FP: file; function dTypeStr (lV: integer): integer; begin case lV of 1,2: result := 1; 3: result := 2; //int16 4: result := 4; //int32 5: result := 4; //single 6: result := 8; //double end; end; //nested fcn dTypeStr function read32i: Longint; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(Long:LongInt); end; swaptypep = ^swaptype; var s : LongInt; inguy:swaptypep; outguy:swaptype; begin seek(fp,lFilePosition); lFilePosition := lFilePosition + 4; BlockRead(fp, s, 4); inguy := @s; //assign address of s to inguy if lDICOMdata.Little_Endian = 0 then begin outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); end else outguy.long := inguy^.long; result:=outguy.Long; end; function read64r (lDataType: integer): Double; type swaptype = packed record case byte of 0:(Word1,Word2,Word3,Word4 : word); //word is 16 bit 1:(Long:Double); end; swaptypep = ^swaptype; var s : Double; inguy:swaptypep; outguy:swaptype; begin result := 1; if lDataType <> 6 then begin Msg('Unknown data type: MRIcro is unable to determine the voxel size.'); exit; end; seek(fp,lFilePosition); lFilePosition := lFilePosition + 8; BlockRead(fp, s, 8); inguy := @s; //assign address of s to inguy if lDICOMdata.Little_Endian = 0 then begin outguy.Word1 := swap(inguy^.Word4); outguy.Word2 := swap(inguy^.Word3); outguy.Word3 := swap(inguy^.Word2); outguy.Word4 := swap(inguy^.Word1); end else outguy.long := inguy^.long; result:=outguy.Long; end; function readname: String; var lI,lLen: integer; lCh: char; begin result := ''; seek(fp,lFilePosition); lLen := read32i; if lLen < 1 then begin Msg('Terminal error reading netCDF/MINC header (String length < 1)'); exit; //problem end; for lI := 1 to lLen do begin BlockRead(fp, lCh, 1); result := result + lCh; end; lFilePosition := lFilePosition + (((lLen+3) div 4) * 4); end; begin lImageFormatOK := true; lHdrOK := false; if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; for lnOri := 1 to 3 do lOri[lnOri] := 0; lnOri := 4; lnDim := 4; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); lFileSz := FileSize(fp); Clear_Dicom_Data(lDicomData); if lFilesz < (77) then exit; //to small to be MINC lFilePosition := 0; lSignature := read32i; if not (lSignature=1128547841) then begin CloseFile(fp); FileMode := 2; //set to read/write Msg('Problem with MINC signature: '+ inttostr(lSignature)); exit; end; //xlDicomData.Rotate180deg := true; lWord := read32i;//numrecs lDT := read32i; while (lDt=10) or (lDT=11) or (lDT=12) do begin if lDT = 10 then begin //DT=10, Dimensions nelem := read32i; for j := 1 to nelem do begin lStr := readname; lLen := read32i; if lStr = 'xspace' then lDicomData.XYZdim[3] := lLen;//DOES MINC always reverse X and Z? see also XYZmm if lStr = 'yspace' then lDicomData.XYZdim[2] := lLen; if lStr = 'zspace' then lDicomData.XYZdim[1] := lLen; end; //for 1..nelem lDT := read32i; end;//DT=10, Dimensions if lDT = 11 then begin //DT=11, Variables nelem := read32i; for j := 1 to nelem do begin lVarStr := readname; nnelem := read32i; for m := 1 to nnelem do lLen := read32i; lDT0 := read32i; if lDT0 = 12 then begin nelem0 := read32i; for jj := 1 to nelem0 do begin lStr := readname; nc_type := read32i; nc_size := dTypeStr(nc_Type); nnelem := read32i; lStartPosition := lFilePosition; if (lStr = 'step') then begin if (lVarStr = 'xspace') or (lVarStr = 'yspace') or (lVarStr = 'zspace') then begin dec(lnDim); if (lnDim < 4) and (lnDim>0) then lDicomData.XYZmm[lnDim] := read64r(nc_Type) end; end else if (lStr = 'start') then begin if (lVarStr = 'xspace') or (lVarStr = 'yspace') or (lVarStr = 'zspace') then begin dec(lnOri); if (lnOri < 4) and (lnOri > 0) then lOri[lnOri] := read64r(nc_Type) end; end; lFilePosition := lStartPosition + ((((nnelem*nc_size)+3) div 4)*4); end; lDT0 := read32i; if lVarStr = 'image' then begin case lDT0 of 1,2: lDicomData.Allocbits_per_pixel := 8; 3: lDicomData.Allocbits_per_pixel := 16; //int16 4: lDicomData.Allocbits_per_pixel := 32; //int32 5: lDicomData.Allocbits_per_pixel := 32; //single 6: lDicomData.Allocbits_per_pixel := 64; //double end; if (lDT0 = 5) or (lDT0 = 6) then lDicomData.FloatData := true; //xlDicomData.Storedbits_per_pixel := lDicomData.Allocbits_per_pixel; //lImgNC_Type := lDT0; end; end; vSizeRA := read32i; BeginRA := read32i; if lVarStr = 'image' then begin lDICOMdata.ImageStart := BeginRA; end; end; //for 1..nelem lDT := read32i; end;//DT=11 if lDT = 12 then begin //DT=12, Attributes nelem := read32i; for j := 1 to nelem do begin lStr := readname; nc_type := read32i; nc_size := dTypeStr(nc_Type); nnelem := read32i; lFilePosition := lFilePosition + ((((nnelem*nc_size)+3) div 4)*4); end; //for 1..nelem lDT := read32i; end;//DT=12, Dimensions end; //while DT if lOri[1] <> 0 then lDicomData.XYZori[1] := round((-lOri[1])/lDicomData.XYZmm[1])+1; if lOri[2] <> 0 then lDicomData.XYZori[2] := round((-lOri[2])/lDicomData.XYZmm[2])+1; if lOri[3] <> 0 then lDicomData.XYZori[3] := round((-lOri[3])/lDicomData.XYZmm[3])+1; lDynStr := 'MINC image'+kCR+ 'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'XYZ origin:' +inttostr(lDicomData.XYZori[1])+'/' +inttostr(lDicomData.XYZori[2])+'/'+inttostr(lDicomData.XYZori[3]) +kCR+'XYZ size [mm or micron]:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2) +kCR+'Bits per sample/Samples per pixel: '+inttostr( lDICOMdata.Allocbits_per_pixel) +kCR+'Data offset:' +inttostr(lDicomData.ImageStart); lHdrOK := true; lImageFormatOK := true; CloseFile(fp); FileMode := 2; //set to read/write end; //read_minc //start TIF procedure read_tiff_data(var lDICOMdata: DICOMdata; var lReadOffsets, lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); label 566, 564; const kMaxnSLices = 6000; var lLongRA: LongIntP; lStackSameDim,lContiguous: boolean; l1stDicomData: DicomData; //lDouble : double; //lXmm,lYmm,lZmm: double; lSingle: single; lImageDataEndPosition,lStripPositionOffset,lStripPositionType,lStripPositionItems, lStripCountOffset,lStripCountType,lStripCountItems, lItem,lTagItems,lTagItemBytes,lTagPointer,lNumerator, lDenominator, lImage_File_Directory,lTagType,lVal,lDirOffset,lOffset,lFileSz, lnDirectories,lDir,lnSlices: Integer; lTag,lWord,lWord2: word; FP: file; (*FUNCTION longint2single ({var} s:longint): single; //returns true if s is Infinity, NAN or Indeterminate //4byte IEEE: msb[31] = signbit, bits[23-30] exponent, bits[0..22] mantissa //exponent of all 1s = Infinity, NAN or Indeterminate VAR Overlay: Single ABSOLUTE s; BEGIN result := Overlay; END;*) function read64r(lPos: integer):double; type swaptype = packed record case byte of 0:(Word1,Word2,Word3,Word4 : word); //word is 16 bit 1:(float:double); end; swaptypep = ^swaptype; var inguy:swaptypep; outguy:swaptype; s: double; begin seek(fp,lPos); BlockRead(fp, s, 8); inguy := @s; //assign address of s to inguy if lDICOMdata.Little_Endian = 0{false} then begin outguy.Word1 := swap(inguy^.Word4); outguy.Word2 := swap(inguy^.Word3); outguy.Word3 := swap(inguy^.Word2); outguy.Word4 := swap(inguy^.Word1); end else outguy.float := inguy^.float; result:=outguy.float; end; function read32i(lPos: longint): Longint; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(Long:LongInt); end; swaptypep = ^swaptype; var s : LongInt; inguy:swaptypep; outguy:swaptype; begin seek(fp,lPos); BlockRead(fp, s, 4); inguy := @s; //assign address of s to inguy if lDICOMdata.Little_Endian = 0 then begin outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); end else outguy.long := inguy^.long; result:=outguy.Long; end; function read16(lPos: longint): Longint; var s : word; begin seek(fp,lPos); BlockRead(fp, s, 2); if lDICOMdata.Little_Endian = 0 then result := swap(s) else result := s; end; function read8(lPos: longint): Longint; var s : byte; begin seek(fp,lPos); BlockRead(fp, s, 1); result := s; end; function readItem(lItemNum,lTagTypeI,lTagPointerI: integer): integer; begin if lTagTypeI= 4 then result := read32i(lTagPointerI+((lItemNum-1)*4)) else result := read16(lTagPointerI+((lItemNum-1)*2)); end; begin Clear_Dicom_Data(lDicomData); if gECATJPEG_table_entries <> 0 then begin freemem (gECATJPEG_pos_table); freemem (gECATJPEG_size_table); gECATJPEG_table_entries := 0; end; //lXmm := -1; //not read lImageFormatOK := true; lHdrOK := false; if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; //lLongRASz := kMaxnSlices * sizeof(longint); getmem(lLongRA,kMaxnSlices*sizeof(longint)); FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); lFileSz := FileSize(fp); Clear_Dicom_Data(lDicomData); //xlDicomData.PlanarConfig:=0; if lFilesz < (28) then begin goto 566; end; //TmpStr := string(StrUpper(PChar(ExtractFileExt(lFileName)))); //if not (TmpStr = '.TIF') or (TmpStr = '.TIFF') then exit; lWord := read16(0); if lWord = $4d4d then lDICOMdata.little_endian := 0 else if lWord = $4949 then lDICOMdata.little_endian := 1; lWord2 := read16(2); //bits per pixel if ((lWord=$4d4d) or (lWord=$4949)) and (lWord2 = $002a) then else goto 566; lOffset := read32i(4); lImage_File_Directory := 0; lContiguous := true; lnSlices := 0; //xlDicomData.SamplesPerPixel := 1; //START while for each image_file_directory while (lOffset > 0) and ((lOffset+2+12+4) < lFileSz) do begin inc(lImage_File_Directory); lnDirectories := read16(lOffset); if (lnDirectories < 1) or ((lOffset+2+(12*lnDirectories)+4) > lFileSz) then goto 566; for lDir := 1 to lnDirectories do begin lDirOffset := lOffset+2+((lDir-1)*12); lTag := read16(lDirOffset); lTagType := read16(lDirOffset+2); lTagItems := read32i(lDirOffset+4); case lTagType of 1: lVal := 1;//bytes 3: lVal := 2;//word 4: lVal := 4;//long 5: lVal := 8;//rational else lVal := 1; //CHAR variable length end; lTagItemBytes := lVal * lTagItems; if lTagItemBytes > 4 then lTagPointer := read32i(lDirOffset+8) else lTagPointer := (lDirOffset+8); case lTagType of 1: lVal := read8(lDirOffset+8); 3: lVal := read16(lDirOffset+8); 4: lVal := read32i(lDirOffset+8); 5: begin //rational: two longs representing numerator and denominator lVal := read32i(lDirOffset+8); lNumerator := read32i(lVal); lDenominator := read32i(lVal+4); if lDenominator <> 0 then lSingle := lNumerator/lDenominator else lSingle := 1; if lSingle <> 0 then lSingle := 1/lSingle; //Xresolution/Yresolution refer to number of pixels per resolution_unit if lTag = 282 then lDicomData.XYZmm[1] := lSingle; if lTag = 283 then lDicomData.XYZmm[2] := lSingle; end; else lVal := 0; end; case lTag of //254: ;//NewSubFileType 256: lDicomData.XYZdim[1] := lVal;//image_width 257: lDicomData.XYZdim[2] := lVal;//image_height 258: begin //bits per sample if lTagItemBytes > 4 then lVal := 8; //if lVal <> 8 then goto 566; lDicomData.Allocbits_per_pixel := lVal;//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; end; 259: begin if lVal <> 1 then begin Msg('TIFF Read Error: Image data is compressed. Currently only uncompressed data is supported.'); goto 566; //compressed data end; end; //x262: if lVal = 0 then lDicomdata.monochrome := 1;//invert colors //photometric_interpretation //MinIsWhite,MinIsBlack,Palette //270: ; //ImageDescription 273: begin //get offset to data lStripPositionOffset := lTagPointer; lStripPositionType := lTagType; lStripPositionItems := lTagItems; if (lImage_File_Directory=1) then lDicomData.ImageStart := readItem(1,lStripPositionType,lStripPositionOffset); end; //StripOffsets //274: ; //orientation 277: begin //xlDicomData.SamplesPerPixel := lVal; //if lVal <> 1 then goto 566; //samples per pixel end; 279: begin lStripCountOffset := lTagPointer; lStripCountType := lTagType; lStripCountItems := lTagItems; end; //278: message('rows:'+inttostr(lVal));//StripByteCount //279: message('count:'+inttostr(lVal));//StripByteCount //282 and 283 are rational values and read separately 284: begin {xif lVal = 1 then lDicomData.PlanarConfig:= 0 else lDicomData.PlanarConfig:= 1;//planarConfig } end; 34412: begin //Zeiss data header //0020h float x size of a pixel (m or s) //0024h float y size of a pixel (m or s) //0028h float z distance in a sequence (m or s) {stream.seek((int)position + 40); VOXELSIZE_X = swap(stream.readDouble()); stream.seek((int)position + 48); VOXELSIZE_Y = swap(stream.readDouble()); stream.seek((int)position + 56); VOXELSIZE_Z = swap(stream.readDouble());} lVal := read16(lTagPointer+2); if lVal = 1024 then begin //LSM510 v2.8 images lDicomData.XYZmm[1]{lXmm} := read64r(lTagPointer+40)*1000000; lDicomData.XYZmm[2]{lYmm} := read64r(lTagPointer+48)*1000000; lDicomData.XYZmm[3]{lZmm} := read64r(lTagPointer+56)*1000000; end; //following may work if lVal = 2, different type of LSM file I have not seen //lXmm := longint2single(read32i(lTagPointer+$0020)); //lYmm := longint2single(read32i(lTagPointer+$0024)); //lZmm := longint2single(read32i(lTagPointer+$0028)); end; //296: ;//resolutionUnit 1=undefined, 2=inch, 3=centimeter //320?? //LEICA: 34412 //SOFTWARE = 305 //DATE_TIME = 306 //ARTIST = 315 //PREDICTOR = 317 //COLORMAP = 320 => essntially custom LookUpTable //EXTRASAMPLES = 338 //SAMPLEFORMAT = 339 //JPEGTABLES = 347 // lDicomData.ImageStart := lVal //else if lImage_File_Directory = 1 then Msg(inttostr(lTag)+'@'+inttostr(lTagPointer)+' value: '+inttostr(lVal)); end; //case lTag end; //For Each Directory in Image_File_Directory lOffset := read32i(lOffset+2+(12*lnDirectories)); //NEXT: check that each slice in 3D slice is the same dimension lStackSameDim := true; if (lImage_File_Directory=1) then begin l1stDicomData := lDICOMdata; lnSlices := 1; //inc(lnSlices); end else begin if lDicomData.XYZdim[1] <> l1stDicomData.XYZdim[1] then lStackSameDim := false; if lDicomData.XYZdim[2] <> l1stDicomData.XYZdim[2] then lStackSameDim := false; if lDicomData.Allocbits_per_pixel <> l1stDicomData.Allocbits_per_pixel then lStackSameDim := false; //xif lDicomData.SamplesPerPixel <> l1stDicomData.SamplesPerPixel then lStackSameDim := false; //xif lDicomData.PlanarConfig <> l1stDicomData.PlanarConfig then lStackSameDim := false; if not lStackSameDim then begin //Msg(inttostr(lDicomData.XYZdim[1])+'x'+inttostr(l1stDicomData.XYZdim[1])); if (lDicomData.XYZdim[1]*lDicomData.XYZdim[2]) > (l1stDicomData.XYZdim[1]*l1stDicomData.XYZdim[2]) then begin l1stDicomData := lDICOMdata; lnSlices := 1; lStackSameDim := true; end; //Msg('TIFF Read Error: Different 2D slices in this 3D stack have different dimensions.'); //goto 566; end else inc(lnSlices); //if not samedim end; //check that each slice is same dimension as 1st //END check each 2D slice in 3D stack is same dimension //NEXT: check if image data is contiguous if (lStripCountItems > 0) and (lStripCountItems = lStripPositionItems) then begin if (lnSlices=1) then lImageDataEndPosition := lDicomData.ImageStart; for lItem := 1 to lStripCountItems do begin lVal := readItem(lItem,lStripPositionType,lStripPositionOffset); if (lVal <> lImageDataEndPosition) then lContiguous := false; //Msg(inttostr(lImage_File_Directory)+'@'+inttostr(lItem)); lImageDataEndPosition := lImageDataEndPosition+readItem(lItem,lStripCountType,lStripCountOffset); if not lcontiguous then begin if (lReadOffsets) and (lStackSameDim) then begin lLongRA^[lnSlices] := lVal; end else if (lReadOffsets) then //not correct size, but do not generate an error as we will read non-contiguous files else begin Msg('TIFF Read Error: Image data is not stored contiguously. '+ 'Solution: convert this image using MRIcro''s ''Convert TIFF/Zeiss to Analyze...'' command [Import menu].'); goto 564; end; end; //if not contiguous end; //for each item end;//at least one StripItem} //END check image data is contiguous end; //END while each Image_file_directory lDicomData := l1stDicomData; lDicomData.XYZdim[3] := lnSlices; if (lReadOffsets) and (lnSlices > 1) and (not lcontiguous) then begin gECATJPEG_table_entries := lnSlices; //Offset tables for TIFF getmem (gECATJPEG_pos_table, gECATJPEG_table_entries*sizeof(longint)); getmem (gECATJPEG_size_table, gECATJPEG_table_entries*sizeof(longint)); gECATJPEG_pos_table^[1] := l1stDicomData.ImageStart; for lVal := 2 to gECATJPEG_table_entries do gECATJPEG_pos_table^[lVal] := lLongRA^[lVal] end; lHdrOK := true; 564: lDynStr := 'TIFF image'+kCR+ 'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'XYZ size [mm or micron]:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2) +kCR+'Bits per sample/Samples per pixel: '+inttostr( lDICOMdata.Allocbits_per_pixel) +kCR+'Data offset:' +inttostr(lDicomData.ImageStart); {if lXmm > 0 then lDynStr := lDynStr +kCR+'Zeiss XYZ mm:'+floattostr(lXmm)+'/' +floattostr(lYmm)+'/' +floattostr(lZmm);} 566: freemem(lLongRA); CloseFile(fp); FileMode := 2; //set to read/write end; procedure read_biorad_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string); var lCh: char; lByte: Byte; lSpaces,liPos,lFileSz,lWord,lNotes,lStart,lEnd: integer; tx : array [0..80] of Char; lInfo,lStr,lTmpStr: string; FP: file; procedure read16(lPos: longint; var lVal: integer); var lInWord: word; begin seek(fp,lPos); BlockRead(fp, lInWord, 2); lVal := lInWord; end; procedure read32(lPos: longint; var lVal: integer); var lInINt: integer; begin seek(fp,lPos); BlockRead(fp, lInINt, 4); lVal :=lInINt; end; begin lImageFormatOK := true; lHdrOK := false; if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); lFileSz := FileSize(fp); Clear_Dicom_Data(lDicomData); if lFilesz < (77) then exit; //to small to be biorad read16(54,lWord); if (lWord=12345) then begin lDicomData.little_endian := 1; read16(0,lDicomData.XYZdim[1]); read16(2,lDicomData.XYZdim[2]); read16(4,lDicomData.XYZdim[3]); read16(14,lWord);//byte format if lWord = 1 then lDicomData.Allocbits_per_pixel := 8 else lDicomData.Allocbits_per_pixel := 16;//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; lDicomData.ImageStart := 76; read32(10,lNotes); lStart := (lDicomData.XYZdim[1]*lDicomData.XYZdim[2]*lDicomData.XYZdim[3])+76; lEnd := lStart + 96; lDynStr := 'BIORAD PIC image'+kCR; while (lNotes > 0) and (lFileSz >= lEnd) do begin read32(lStart+2,lNotes); //final note has bytes 2..5 set to zero //read16(lStart+10,lNoteType); //if lNoteType <> 1 then begin //ignore 'LIVE' notes - they do not include calibration info seek(fp, lStart+16); BlockRead(fp, tx, 80{, n}); lStr := ''; liPos := 0; repeat lCh := tx[liPos]; lByte := ord(lCh); if (lByte >= 32) and (lByte <= 126) then lStr := lStr+lCh else lByte := 0; inc(liPos); until (liPos = 80) or (lByte = 0); if length(lStr) > 6 then begin lInfo := ''; for liPos := 1 to 6 do lInfo := lInfo+upcase(lStr[liPos]); ltmpstr := ''; lSpaces := 0; for liPos := 1 to 80 do begin if lStr[liPos]=' ' then inc(lSpaces) else if lSpaces = 3 then ltmpstr := ltmpstr + lStr[liPos]; end; if ltmpstr = '' then {no value to read} else if lInfo = 'AXIS_2' then lDicomData.XYZmm[1] := strtofloat(ltmpstr) else if lInfo = 'AXIS_3' then lDicomData.XYZmm[2] := strtofloat(ltmpstr) else if linfo = 'AXIS_4' then lDicomData.XYZmm[3] := strtofloat(ltmpstr); lDynStr := lDynStr+lStr+kCR; end; //Str length > 6 //end;//notetype lStart := lEnd; lEnd := lEnd + 96; end; //while notes lHdrOK := true; //lImageFormatOK := true; end;//biorad signature CloseFile(fp); FileMode := 2; //set to read/write lDynStr := 'BioRad image'+kCR+ 'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'XYZ size [mm or micron]:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2) +kCR+'Bits per sample/Samples per pixel: '+inttostr( lDICOMdata.Allocbits_per_pixel) +kCR+'Data offset:' +inttostr(lDicomData.ImageStart); end; //biorad function SiemensVersion (lStr: string): integer; //Convert tag 0018,1020 from DICOM header to Siemens version number (*Returned value: system is in 1000s, last two digits are version Siemens syngo MR 2006T 4VB12T //-> 0012 MR B13 4VB13A //->0013 MR.VB15A123 //->0015 syngo MR B15 //-> 0015 syngo MR B17 //->0017 B= Trio, Verio, Etc syngo MR C11 //->1011 C= Chinese C11 ~ B17 syngo MR D11 //->2011 D= Skyra D11 ~ B17*) label 999; var i,len: integer; begin result := 0; len := length(lStr); if len < 3 then exit; for i := 1 to len-1 do if (upcase(lStr[i]) in ['A'..'Z']) and (lStr[i+1] in ['0'..'9']) then goto 999; exit; //not Siemens format 999: result := strtoint(lStr[i+1]); if lStr[i+2] in ['0'..'9'] then result := (result*10) + strtoint(lStr[i+2]); result := (100*( ord(upcase(lStr[i]))- ord('B'))) + result; end; (* Obsolete - replaced by SiemensVersion function SiemensBversion (lStr: string): integer; //'syngo MR B17' returns 17 //'MR.VB15A123' returns 15 //'syngo MR B15' returns 15 //'MR B13 4VB13A' returns 13 //'syngo MR 2006T 4VB12T' returns 12 var Len,P,B: integer; S: string; begin result := 0; Len := length(lStr); if Len <2 then exit; B := 0; for P := 2 to (Len) do if (upcase(lStr[P-1])='B') and ( lStr[P] in ['0'..'9']) then B := P; if B < 1 then exit; S := ''; while (B<= Len) and (lStr[B] in ['0'..'9']) do begin S := S + lStr[B]; inc(B); end; if length(S) < 1 then exit; result := strtoint(S); end;*) (*function Str2IntDig (lStr: string; lDig: integer): integer; //robust stringtoint that strips out any junk so that "Implementation Version Name=MR.VB15A123" returns 15 // warning, strips out decimals, so 15.3 will return 153! //warning also ignores minus sign so -5.21 will return 521! var Len,P: integer; S: string; begin result := 0; Len := length(lStr); if Len <1 then exit; S := ''; for P := 1 to Len do if (lStr[P] in ['0'..'9']) and (length(S) < lDig) then S := S + lStr[P]; if length(S) < 1 then exit; result := strtoint(S); end; *) function ExpectedDicomBytes (var lDICOMdata: DICOMdata): integer; begin if lDicomData.JPEGLosslessCpt then begin result := 0; //actual compressed size unknown exit; end; result := lDicomdata.XYZdim[1]*lDicomdata.XYZdim[2]*lDicomdata.XYZdim[3]*(lDicomData.Allocbits_per_pixel DIV 8); end; procedure read_dicom_data_compat(lReadJPEGtables,lVerboseRead,lAutoDECAT7,lReadECAToffsetTables,lAutoDetectInterfile,lAutoDetectGenesis,lReadColorTables: boolean; var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string; var lPrefs: TPrefs); label 666,777; const kMaxTextBuf = 50000; //maximum for screen output kDiskCache = 16384; //size of disk buffer kNaNsingle : single = 1/0; type dicom_types = (unknown, i8, i16, i32, ui8, ui16, ui32, _string{,_float} ); var // lTextF: TextFile; //abba lDICOMdataBackUp: DICOMdata; lWord,lWord2,lWord3: word; lWordRA: Wordp; lDiskCacheRA: pChar{ByteP}; lRot1,lRot2,lRot3 : integer;//rotation dummies for AFNI FP: file; lT0,lT1,lT2,lT3:byte; lImagePositionPatientRead, lResearchMode,lManufacturerIsPhilips,lManufacturerIsBruker,lMediface0002_0013,lSiemensMosaic0008_0008,lDICM_at_128, lTextOverFlow,lGenesis,lFirstPass,lrOK,lBig,lBigSet,lGrp,explicitVR,first_one : Boolean; lSwitchToImplicitAfterGroup0002, lTestError,lByteSwap,lGELX,time_to_quit,lProprietaryImageThumbnail,lFirstFragment,lOldSiemens_IncorrectMosaicMM : Boolean; group, element, e_len, remaining, tmp : uint32; tmpstr : kDICOMstr; lgrpstr,lStr,info,lDummyStr : string; t : dicom_types; lfloat1,lfloat2,lfloat3,lThickness: double; lTempInt,lEchoNum,lnVol,lnSlicePerVol,lJPEGentries,lErr,liPos,lCacheStart,lCachePos,lDiskCacheSz,n, i,value, Ht,Width, max16,min16,filesz,where,lMatrixSz,lPhaseEncodingSteps,lJunk,lJunk2,lJunk3 : LongInt; tx : array [0..96] of Char; l4DDistanceBetweenSliceCenters,lPhilipsScaleSlope: single; buff: pCHar; lColorRA: bytep; lLongRA: Longintp; lSingleRA,lInterceptRA: Singlep; //lPapyrusnSlices,lPapyrusSlice : integer; //lPapyrusZero,lPapyrus : boolean; procedure ByteSwap (var lInOut: integer); var lWord: word; begin lWord := lInOut; lWord := swap(lWord); lInOut := lWord; end; procedure dReadCache (lFileStart: integer); begin lCacheStart := lFileStart{lCacheStart + lDiskCacheSz};//eliminate old start if lCacheStart < 0 then lCacheStart := 0; if lDiskCacheSz > 0 then freemem(lDiskCacheRA); if (FileSz-(lCacheStart)) < kDiskCache then lDiskCacheSz := FileSz - (lCacheStart) else lDiskCacheSz := kDiskCache; lCachePos := 0; if (lDiskCacheSz < 1) then exit{goto 666}; if (lDiskCacheSz+lCacheStart) > FileSz then exit; Seek(fp, lCacheStart); GetMem(lDiskCacheRA, lDiskCacheSz {bytes}); BlockRead(fp, lDiskCacheRA^, lDiskCacheSz, n); end; function dFilePos (var lInFP: file): integer; begin Result := lCacheStart + lCachePos; end; procedure dSeek (var lInFP: file; lPos: integer); begin if (lPos >= lCacheStart) and (lPos < (lDiskCacheSz+lCacheStart)) then begin lCachePos := lPos-lCacheStart; exit; end; dReadCache(lPos); end; procedure dBlockRead (var lInfp: file; lInbuff: pChar; e_len: integer; var n: integer); var lN: integer; begin N := 0; if e_len < 0 then exit; for lN := 0 to (e_len-1) do begin if lCachePos >= lDiskCacheSz then begin dReadCache(lCacheStart+lDiskCacheSz); if lDiskCacheSz < 1 then exit; lCachePos := 0; end; N := lN; lInBuff[N] := lDiskCacheRA[lCachePos]; inc(lCachePos); end; end; procedure readfloats (var fp: file; remaining: integer; var lOutStr: string; var lf1, lf2: double; var lReadOK: boolean); var lDigit : boolean; li,lLen,n: integer; lfStr: string; begin lf1 := 1; lf2 := 2; if e_len = 0 then begin lReadOK := true; exit; end; if (dFilePos(fp) > (filesz-remaining)) or (remaining < 1) then begin lOutStr := ''; lReadOK := false; exit; end else lReadOK := true; lOutStr := ''; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for li := 0 to e_len-1 do if Char(buff[li]) in [{'/','\', delete: rev18}'e','E','+','-','.','0'..'9'] then lOutStr := lOutStr +(Char(buff[li])) else begin lOutStr := lOutStr + ' '; end; FreeMem( buff); lfStr := ''; lLen := length(lOutStr); li := 1; lDigit := false; repeat if (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then lfStr := lfStr + lOutStr[li]; if lOutStr[li] in ['0'..'9'] then lDigit := true; inc(li); until (li > lLen) or (lDigit); if not lDigit then exit; if li <= li then begin repeat if not (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then lDigit := false else begin if lOutStr[li] = 'E' then lfStr := lfStr+'e' else lfStr := lfStr + lOutStr[li]; end; inc(li); until (li > lLen) or (not lDigit); end; //QStr(lfStr); try lf1 := strtofloat(lfStr); except on EConvertError do begin Msg('Unable to convert the string '+lfStr+' to a real number'); lf1 := 1; exit; end; end; {except} lfStr := ''; if li > llen then exit; repeat if (lOutStr[li] in ['+','E','e','.','-','0'..'9']) then begin if lOutStr[li] = 'E' then lfStr := lfStr+'e' else lfStr := lfStr + lOutStr[li]; end; if (lOutStr[li] in ['0'..'9']) then lDigit := true; inc(li); until (li > lLen) or ((lDigit) and (lOutStr[li]=' ')); //second half: rev18 if not lDigit then exit; //QStr(lfStr); try lf2 := strtofloat(lfStr); except on EConvertError do begin Msg('Unable to convert the string '+lfStr+' to a real number'); exit; end; end; end; procedure readfloats3 (var fp: file; remaining: integer; var lOutStr: string; var lf1, lf2,lf3: double; var lReadOK: boolean); var lDigit : boolean; lItem,li,lLen,n: integer; lfTemp: double; lfStr: string; begin lf1 := 0; lf2 := 0; lf3 := 0; lOutStr := ''; if e_len = 0 then begin lReadOK := true; exit; end; if (dFilePos(fp) > (filesz-remaining)) or (remaining < 1) then begin lReadOK := false; exit; end else lReadOK := true; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for li := 0 to e_len-1 do if Char(buff[li]) in [{'/','\', delete: rev18}'e','E','+','-','.','0'..'9'] then lOutStr := lOutStr +(Char(buff[li])) else lOutStr := lOutStr + ' '; FreeMem( buff); li := 1; lLen := length(lOutStr); for lItem := 1 to 3 do begin if li > llen then exit; lfStr := ''; lLen := length(lOutStr); lDigit := false; repeat if (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then lfStr := lfStr + lOutStr[li]; if lOutStr[li] in ['0'..'9'] then lDigit := true; inc(li); until (li > lLen) or (lDigit); if not lDigit then exit; if li <= li then begin repeat if not (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then lDigit := false else begin if lOutStr[li] = 'E' then lfStr := lfStr+'e' else lfStr := lfStr + lOutStr[li]; end; inc(li); until (li > lLen) or (not lDigit); end; //QStr(lfStr); try lftemp := strtofloat(lfStr); except on EConvertError do begin Msg('Unable to convert the string '+lfStr+' to a real number'); //lftemp := 0; exit; end; end; {except} case lItem of 2: lf2 := lftemp; 3: lf3 := lftemp; else lf1 := lftemp; end; //case of lItem end; //for each of 3 lItems end; //readfloats3 procedure CheckIntersliceDistance (var lMinDistance: single); var lX,lY,lZ,lDx: double; begin readfloats3 (fp, remaining, lDummyStr, lX, lY,lZ, lROK); // fx( lX, lY,lZ,6789); e_len := 0; remaining := 0; //compute Distance between current slice and 1st slice... lDx := sqrt( sqr(lX-lDicomData.PatientPosX)+sqr(lY-lDicomData.PatientPosY)+sqr(lZ-lDicomData.PatientPosZ)); if (lDx > 0) and (lMinDistance = kNaNsingle) then //first value lMinDistance := lDx else if (lDx > 0) and (lDx < lMinDistance) then //if 0 then this is a repeat, not a new slice lMinDistance := lDx else exit; end; procedure readfloats6 (var fp: file; remaining: integer; var lOutStr: string; var lf1, lf2,lf3,lf4,lf5,lf6: double; var lReadOK: boolean); var lDigit : boolean; lItem,li,lLen,n: integer; lfTemp: single; lfStr: string; begin lf1 := 0; lf2 := 0; lf3 := 0; lf4 := 0; lf5 := 0; lf6 := 0; lOutStr := ''; if e_len = 0 then begin lReadOK := true; exit; end; if (dFilePos(fp) > (filesz-remaining)) or (remaining < 1) then begin lReadOK := false; exit; end else lReadOK := true; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for li := 0 to e_len-1 do if Char(buff[li]) in [{'/','\', delete: rev18}'e','E','+','-','.','0'..'9'] then lOutStr := lOutStr +(Char(buff[li])) else lOutStr := lOutStr + ' '; FreeMem( buff); li := 1; lLen := length(lOutStr); for lItem := 1 to 6 do begin if li > llen then exit; lfStr := ''; lLen := length(lOutStr); lDigit := false; repeat if (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then lfStr := lfStr + lOutStr[li]; if lOutStr[li] in ['0'..'9'] then lDigit := true; inc(li); until (li > lLen) or (lDigit); if not lDigit then exit; if li <= li then begin repeat if not (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then lDigit := false else begin if lOutStr[li] = 'E' then lfStr := lfStr+'e' else lfStr := lfStr + lOutStr[li]; end; inc(li); until (li > lLen) or (not lDigit); end; //QStr(lfStr); try lftemp := strtofloat(lfStr); except on EConvertError do begin Msg('Unable to convert the string '+lfStr+' to a real number'); //lftemp := 0; exit; end; end; {except} case lItem of 2: lf2 := lftemp; 3: lf3 := lftemp; 4: lf4 := lftemp; 5: lf5 := lftemp; 6: lf6 := lftemp; else lf1 := lftemp; end; //case of lItem end; //for each of 3 lItems end; function read16( var fp : File; var lReadOK: boolean ): uint16; var t1, t2 : uint8; n : Integer; begin if dFilePos(fp) > (filesz-2) then begin read16 := 0; lReadOK := false; exit; end else lReadOK := true; GetMem( buff, 2); dBlockRead(fp, buff{^}, 2, n); T1 := ord(buff[0]); T2 := ord(buff[1]); freemem(buff); if lDICOMdata.little_endian <> 0 then Result := (t1 + t2*256) AND $FFFF else Result := (t1*256 + t2) AND $FFFF; end; function ReadStr(var fp: file; remaining: integer; var lReadOK: boolean; VAR lmaxval:integer) : string; var lInc, lN,Val,n: integer; t1, t2 : uint8; lStr : String; begin lMaxVal := 0; if dFilePos(fp) > (filesz-remaining) then begin lReadOK := false; exit; end else lReadOK := true; Result := ''; lN := remaining div 2; if lN < 1 then exit; lStr := ''; for lInc := 1 to lN do begin GetMem( buff, 2); dBlockRead(fp, buff{^}, 2, n); T1 := ord(buff[0]); T2 := ord(buff[1]); freemem(buff); if lDICOMdata.little_endian <> 0 then Val := (t1 + t2*256) AND $FFFF else Val := (t1*256 + t2) AND $FFFF; if lInc < lN then lStr := lStr + inttostr(Val)+ ', ' else lStr := lStr + inttostr(Val); if Val > lMaxVal then lMaxVal := Val; end; Result := lStr; if odd(remaining) then begin getmem(buff,1); dBlockRead(fp, buff{t1}, SizeOf(uint8), n); freemem(buff); end; end; (*function ReadStrABC(var fp: file; remaining: integer; var lReadOK: boolean; VAR lA,lB,lC:integer) : string; var lInc, lN,Val,n: integer; t1, t2 : uint8; lStr : String; begin lA := 0; lB := 0; lC := 0; if dFilePos(fp) > (filesz-remaining) then begin lReadOK := false; exit; end else lReadOK := true; Result := ''; lN := remaining div 2; if lN < 1 then exit; lStr := ''; for lInc := 1 to lN do begin GetMem( buff, 2); dBlockRead(fp, buff{^}, 2, n); T1 := ord(buff[0]); T2 := ord(buff[1]); freemem(buff); if lDICOMdata.little_endian <> 0 then Val := (t1 + t2*256) AND $FFFF else Val := (t1*256 + t2) AND $FFFF; if lInc < lN then lStr := lStr + inttostr(Val)+ ', ' else lStr := lStr + inttostr(Val); if lInc = 1 then lA := Val; if lInc = 2 then lB := Val; if lInc = 3 then lC := Val; end; Result := lStr; if odd(remaining) then begin getmem(buff,1); dBlockRead(fp, buff{t1}, SizeOf(uint8), n); freemem(buff); end; end; *) function ReadStrHex(var fp: file; remaining: integer; var lReadOK: boolean) : string; var lInc, lN,Val,n: integer; t1, t2 : uint8; lStr : String; begin if dFilePos(fp) > (filesz-remaining) then begin lReadOK := false; exit; end else lReadOK := true; Result := ''; lN := remaining div 2; if lN < 1 then exit; lStr := ''; for lInc := 1 to lN do begin GetMem( buff, 2); dBlockRead(fp, buff, 2, n); T1 := ord(buff[0]); T2 := ord(buff[1]); freemem(buff); if lDICOMdata.little_endian <> 0 then Val := (t1 + t2*256) AND $FFFF else Val := (t1*256 + t2) AND $FFFF; if lInc < lN then lStr := lStr + 'x'+inttohex(Val,4)+ ', ' else lStr := lStr + 'x'+inttohex(Val,4); end; Result := lStr; if odd(remaining) then begin getmem(buff,1); dBlockRead(fp, {t1}buff, SizeOf(uint8), n); freemem(buff); end; end; function SomaTomFloat: double; var lSomaStr: String; begin //dSeek(fp,5992); //Slice Thickness from 5790 "SL 3.0" //dSeek(fp,5841); //Field of View from 5838 "FoV 281" //dSeek(fp,lPos); lSomaStr := ''; tx[0] := 'x'; while (length(lSomaStr) < 64) and (tx[0] <> chr(0)) and (tx[0] <> '/') do begin dBlockRead(fp, tx, 1, n); if tx[0] in ['+','-','.','0'..'9','e','E'] then lSomaStr := lSomaStr + tx[0]; end; if length(lSOmaStr) > 0 then result := StrToFloat(lSomaStr) else result := 0; end; function PGMreadInt: integer; //reads integer from PGM header, disregards comment lines (which start with '#' symbol); var lStr: string; lDigit: boolean; begin Result := 1; lStr := ''; repeat dBlockRead(fp, tx, 1, n); if tx[0] = '#' then begin //comment repeat dBlockRead(fp, tx, 1, n); until (ord(tx[0]) = $0A) or (dFilePos(fp) > (filesz-4)); //eoln indicates end of comment end; //finished reading comment if tx[0] in ['0'..'9'] then begin lStr := lStr + tx[0]; lDigit := true; end else lDigit := false; until ((lStr <> '') and (not lDigit)) or (dFilePos(fp) > (filesz-4)); //read digits until you hit whitespace if lStr <> '' then Result := strtoint(lStr); {lStr := ''; tx[0] := 'x'; while (length(lStr) < 64) and (ord(tx[0]) <> $0A) do begin dBlockRead(fp, tx, 1, n); if tx[0] in ['#','+','-','.','0'..'9','e','E',' ','a'..'z','A'..'Z'] then lStr := lStr + tx[0]; end; result := lStr; } end; function read32 ( var fp : File; var lReadOK: boolean ): uint32; var t1, t2, t3, t4 : byte; n : Integer; begin if dFilePos(fp) > (filesz-4) then begin Read32 := 0; lReadOK := false; exit; end else lReadOK := true; GetMem( buff, 4); dBlockRead(fp, buff{^}, 4, n); T1 := ord(buff[0]); T2 := ord(buff[1]); T3 := ord(buff[2]); T4 := ord(buff[3]); freemem(buff); if lDICOMdata.little_endian <> 0 then Result := t1 + (t2 shl 8) + (t3 shl 16) + (t4 shl 24) else Result := t4 + (t3 shl 8) + (t2 shl 16) + (t1 shl 24) //if lDICOMdata.little_endian <> 0 //then Result := (t1 + t2*256 + t3*256*256 + t4*256*256*256) AND $FFFFFFFF //else Result := (t1*256*256*256 + t2*256*256 + t3*256 + t4) AND $FFFFFFFF; end; function read32r ( var fp : File; var lReadOK: boolean ): single; //1382 type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(float:single); end; swaptypep = ^swaptype; var s:single; inguy:swaptypep; outguy:swaptype; begin if dFilePos(fp) > (filesz-4) then begin read32r := 0; lReadOK := false; exit; end else lReadOK := true; //GetMem( buff, 8); dBlockRead(fp, @s, 4, n); inguy := @s; //assign address of s to inguy if lDICOMdata.little_endian <> 1 then begin outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); end else outguy.float := s; //1382 read64 needs to handle little endian in this way as well... read32r:=outguy.float; end; function read64 ( var fp : File; var lReadOK: boolean ): double; type swaptype = packed record case byte of 0:(Word1,Word2,Word3,Word4 : word); //word is 16 bit 1:(float:double); end; swaptypep = ^swaptype; var s:double; inguy:swaptypep; outguy:swaptype; begin if dFilePos(fp) > (filesz-8) then begin Read64 := 0; lReadOK := false; exit; end else lReadOK := true; //GetMem( buff, 8); dBlockRead(fp, @s, 8, n); inguy := @s; //assign address of s to inguy if lDICOMdata.little_endian <> 1 then begin outguy.Word1 := swap(inguy^.Word4); outguy.Word2 := swap(inguy^.Word3); outguy.Word3 := swap(inguy^.Word2); outguy.Word4 := swap(inguy^.Word1); end else outguy.float := inguy^.float; //1382 read64:=outguy.float; end; //magma function SafeStrToInt(var lInput: string): integer; var li,lLen: integer; begin result := 0; lLen := length(lInput); lStr := ''; if lLen < 1 then exit; for li := 1 to lLen do if lInput[li] in ['+','-','0'..'9'] then lStr := lStr +lInput[li]; Val(lStr,li,lErr); if lErr = 0 then result := lI;//strtoint(lStr); end; procedure DICOMHeaderStringToInt (var lInput: integer); var li: integer; begin t := _string; lStr := ''; if dFilePos(fp) > (filesz-e_len) then exit;//goto 666; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for li := 0 to e_len-1 do if Char(buff[li]) in ['+','-','0'..'9'] then lStr := lStr +(Char(buff[li])); FreeMem( buff); Val(lStr,li,lErr); if lErr = 0 then lInput := li;//strtoint(lStr); remaining := 0; tmp := lInput; end; procedure DICOMHeaderString (var lInput: kDICOMStr); var li,lStartPos: integer; begin t := _string; lStartPos := dFilePos(fp); lInput := ''; if e_len < 1 then exit; //DICOM: should always be even GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for li := 0 to e_len-1 do if Char(buff[li]) in ['+','-','/','\',' ','0'..'9','a'..'z','A'..'Z'] then lInput := lInput +(Char(buff[li])) else {if (buff[i] = 0) then} lInput := lInput +' '; FreeMem( buff); dseek(fp, lStartPos); end; procedure DICOMHeaderStringTime (var lInput: kDICOMstr); var li,lStartPos: integer; begin t := _string; lStartPos := dFilePos(fp); lInput := ''; if e_len < 1 then exit; //DICOM: should always be even GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for li := 0 to e_len-1 do if Char(buff[li]) in ['+','-','/','\',' ','0'..'9','a'..'z','A'..'Z','.'] then lInput := lInput +(Char(buff[li])) else if li <> (e_len-1) then lInput := lInput +':' else lInput := lInput +' '; FreeMem( buff); dseek(fp, lStartPos); end; label 1234; var lIndent: integer; lprevGroup, lprevElement: uint32; var lInside00209113, lInside2005140F, lPhilipsWarning: boolean;//philips can list two DIFFERENT spatial positions per slice - ignore the one hidden inside 2005,140FlPrev0020: boolean; begin //Init //for lnVol := 1 to kMaxOrderVal do // lDICOMdata.OrderSlope[lDICOMdata.nOrder] := 0; //show this was not set lInside00209113 := false; lprevGroup := 0; lprevElement := 0; lPhilipsWarning := false; lIndent := 0; lInside2005140F := false; lSwitchToImplicitAfterGroup0002 := false; lGELX := false; lByteSwap := false; Clear_Dicom_Data(lDicomData); Clear_Dicom_Data(lDICOMdataBackUp); lDicomData.XYZdim[1] := 1; lImagePositionPatientRead := false;// for 4D files, we need first volume l4DDistanceBetweenSliceCenters := kNaNsingle; lEchoNum := 0; lThickness := 0; lTestError := false; lPhilipsScaleSlope := 0; lManufacturerIsPhilips := false; lManufacturerIsBruker := false; lnVol := 0; lnSlicePerVol := 0; lResearchMode := false; lMatrixSz := 0; lPhaseEncodingSteps := 0; lSiemensMosaic0008_0008 := false; lMediface0002_0013 := false;//false wblate lOldSiemens_IncorrectMosaicMM := false; lCacheStart := 0; lDiskCacheSz := 0; lDynStr:= ''; lJPEGEntries := 0; first_one := true; info := ''; lGrp:= false; lBigSet := false; lDICM_at_128 := false; //no DICOM signature lFirstFragment := true; lTextOverFlow := false; lImageFormatOK := true; lHdrOK := false; //if lverboseRead then msg('xxx'+lFileName); if not fileexists(lFileName) then begin lImageFormatOK := false; exit; end; //if lverboseRead then msg('zzzzz000000000'); TmpStr := string(StrUpper(PChar(ExtractFileExt(lFileName)))); lStr :=''; if TmpStr = '.FDF' then begin if FDF( lFileName, lDicomData) then begin lHdrOK := true; lImageFormatOK := true; exit; end; end; if (TmpStr = '.REC') then begin //1417z: check in Unix: character upper/lower case may matter lStr := changefileext(lFilename,'.par'); if fileexists(lStr) then lFilename := lStr else begin //Linux is case sensitive 1382... lStr := changefileext(lFilename,'.PAR'); if fileexists(lStr) then lFilename := lStr end; end; if (TmpStr = '.BRIK') then begin //1417z: check in Unix: character upper/lower case may matter lStr := changefileext(lFilename,'.HEAD'); if fileexists(lStr) then lFilename := lStr; end; FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); FIleSz := FileSize(fp); if fileSz < 1 then begin lImageFormatOK := false; exit; end; lDICOMdata.Little_Endian := 1; if FileSz > 200 then begin dseek(fp, {0}128); dBlockRead(fp, tx, 4*SizeOf(Char), n); if (tx[0] = 'D') and (tx[1] = 'I') and (tx[2] = 'C') and (tx[3] = 'M') then lDICM_at_128 := true; end;//filesize > 200: check for 'DICM' at byte 128 - DICOM signature if (lAutoDetectGenesis) and (FileSz > (5820{114+35+4})) then begin dseek(fp, 0); if (ord(tx[0])=206) and (ord(tx[1])=250) then begin //Elscint format signature: check height and width to make sure dseek(fp, 370); group := read16(fp,lrOK);//Width dseek(fp, 372); element := read16(fp,lrOK);//Ht if ((Group=160) or(Group =256) or (Group= 340) or (Group=512) or (group =640)) and ((element=160) or (element =256) or (element= 340) or (element=512) ) then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_elscint_data(lDICOMdata, lHdrOK, lImageFormatOK,lDynStr,lFileName); exit; end; //confirmed: Elscint end; lGenesis := false; if ((tx[0] <> 'I') OR (tx[1] <> 'M') OR (tx[2] <> 'G') OR (tx[3] <> 'F')) then begin {DAT format} {if (FileSz > 114+305+4) then begin dseek(fp, 114+305); dBlockRead(fp, tx, 3*SizeOf(Char), n); if ((tx[0]='M') and (tx[1] = 'R')) or ((tx[0] = 'C') and(tx[1] = 'T')) then lGenesis := true; end;} end else lGenesis := true; if (not lGenesis) and (FileSz > 3252) then begin dseek(fp, 3240); dBlockRead(fp, tx, 4*SizeOf(Char), n); if ((tx[0] = 'I') AND (tx[1] = 'M')AND (tx[2] = 'G') AND (tx[3] = 'F')) then lGenesis := true; if (not lGenesis) then begin dseek(fp, 3178); dBlockRead(fp, tx, 4*SizeOf(Char), n); if ((tx[0] = 'I') AND (tx[1] = 'M')AND (tx[2] = 'G') AND (tx[3] = 'F')) then lGenesis := true; end; if (not lGenesis) then begin dseek(fp, 3180); dBlockRead(fp, tx, 4*SizeOf(Char), n); if ((tx[0] = 'I') AND (tx[1] = 'M')AND (tx[2] = 'G') AND (tx[3] = 'F')) then lGenesis := true; end; if (not lGenesis) then begin //1499K dseek(fp, 0); dBlockRead(fp, tx, 4*SizeOf(Char), n); if ((tx[0] = 'I') AND (tx[1] = 'M')AND (tx[2] = 'G') AND (tx[3] = 'F')) then lGenesis := true; end; end; if (not lGenesis) and (FileSz > 3252) then begin dseek(fp, 3228); dBlockRead(fp, tx, 4*SizeOf(Char), n); if (tx[0] = 'I') AND (tx[1]= 'M') AND (tx[2] = 'G')AND (tx[3]= 'F') then lGenesis := true; end; if lGenesis then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_ge_data(lDICOMdata, lHdrOK, lImageFormatOK,lDynStr,lFileName); exit; end; end; //AutodetectGenesis xxDCIM if (lAutoDetectInterfile) and (FileSz > 256) and (not lDICM_at_128) then begin if Copy(extractfilename(lFileName), 1, 4) = 'COR-' then begin lStr := extractfiledir(lFilename) + '\COR-.info'; TmpStr := extractfiledir(lFilename) + '\COR-128'; if fileexists(lStr) and fileexists(TmpStr) then begin lFilename := TmpStr; lDynStr := 'FreeSurfer COR format' + kCR+'Only displaying image 128'+kCR+'Use MRIcro''s Import menu to convert this image'+kCR; with lDicomData do begin little_endian := 0; // don't care ImageStart := 0; Allocbits_per_pixel := 8; XYZdim[1] := 256; XYZdim[2] := 256; XYZdim[3] := 1; XYZmm[1] := 1; XYZmm[2] := 1; XYZmm[3] := 1; //xStoredbits_per_pixel:= Allocbits_per_pixel; END; //WITH lHdrOK := True; lImageFormatOK := True; exit; end; //COR-.info file exists end; //if filename is COR- //start TIF //TIF IMAGES DO NOT ALWAYS HAVE EXTENSION if (TmpStr = '.TIF') or (TmpStr = '.TIFF') then begin dseek(fp, 0); lWord := read16(fp,lrOK); if lWord = $4d4d then lDICOMdata.little_endian := 0 else if lWord = $4949 then lDICOMdata.little_endian := 1; //dseek(fp, 2); lWord2 := read16(fp,lrOK); //bits per pixel if ((lWord=$4d4d) or (lWord=$4949)) and (lWord2 = $002a) then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_tiff_data(lDICOMdata, lReadECAToffsetTables, lHdrOK, lImageFormatOK, lDynStr, lFileName); //if lHdrOk then exit; exit; end;//TIF signature //end; //.TIF extension //end TIF //start BMP 1667 TmpStr := string(StrUpper(PChar(ExtractFileExt(lFileName)))); if TmpStr = '.BMP' then begin dseek(fp, 0); lWord := read16(fp,lrOK); dseek(fp, 28); lWord2 := read16(fp,lrOK); //bits per pixel if (lWord=19778) and (lWord2 = 8) then begin //bitmap signature dseek(fp, 10); lDicomData.ImageStart := read32(fp,lrOK);//1078; dseek(fp, 18); lDicomData.XYZdim[1] := read32(fp,lrOK); //dseek(fp, 22); lDicomData.XYZdim[2] := read32(fp,lrOK); lDicomData.XYZdim[3] := 1;//read16(fp,lrOK); lDicomData.Allocbits_per_pixel := 8;//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; lDynStr := 'BMP format'; CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write lHdrOK := true; lImageFormatOK:= true; exit; end;//bmp signature end; //.BMP extension //end BMP if TmpStr = '.VOL' then begin //start SPACE vol format 1382 dseek(fp, 0); dBlockRead(fp, tx, 6*SizeOf(Char), n); if (tx[0] = 'm') and (tx[1] = 'd') and (tx[2] = 'v') and (tx[3] = 'o') and (tx[4] = 'l') and (tx[5] = '1') then begin lDicomData.ImageStart := read32(fp,lrOK);//1078; lDICOMdata.little_endian := 1; lDicomData.XYZdim[1] := read32(fp,lrOK); lDicomData.XYZdim[2] := read32(fp,lrOK); lDicomData.XYZdim[3] := read32(fp,lrOK); lDicomData.XYZmm[1] := read32r(fp,lrOK); lDicomData.XYZmm[2] := read32r(fp,lrOK); lDicomData.XYZmm[3] := read32r(fp,lrOK); lDicomData.Allocbits_per_pixel := 8;//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; lDynStr := 'Space VOL format'; CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write lHdrOK := true; lImageFormatOK:= true; exit; end;//vol signature end; //.VOL extension //end space .VOL format //start DF3 PovRay DF3 density files if (TmpStr = '.DF3') then begin dseek(fp, 0); lWord := swap (read16(fp,lrOK)); lWord2 := swap (read16(fp,lrOK)); lWord3 := swap (read16(fp,lrOK)); //note: I assume all df3 headers are little endian. is this always true? if not, unswapped values could be tested for filesize lMatrixSz := (lWord*lWord2*lWord3)+6; if (lMatrixSz=FileSz)then begin //df3 signature lDicomData.ImageStart := 6;//1078; lDicomData.XYZdim[1] := lWord; //dseek(fp, 22); lDicomData.XYZdim[2] := lWord2; lDicomData.XYZdim[3] := lWord3; lDicomData.Allocbits_per_pixel := 8;//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write lDynStr := 'PovRay DF3 density format'; lHdrOK := true; lImageFormatOK:= true; exit; end;//df3 signature end; //end df3 //start .PGM if (TmpStr = '.PGM') or (TmpStr = '.PPM') then begin dseek(fp, 0); lWord := read16(fp,lrOK); if (lWord=13648){'P5'=1x8BIT GRAYSCALE} or (lWord=13904) {'P6'=3x8bit RGB} then begin //bitmap signature {repeat PGMreadStr(lDicomData.XYZdim[1],lDicomData.XYZdim[2]); until (lDicomData.XYZdim[2] > 0) ;} lDicomData.XYZdim[1] := PGMreadInt; lDicomData.XYZdim[2] := PGMreadInt; PGMreadInt; //read maximum value lDicomData.XYZdim[3] := 1;//read16(fp,lrOK); lDicomData.Allocbits_per_pixel := 8;//bits //xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel; lDicomData.ImageStart := dFilepos(fp); if lWord = 13904 then begin//RGB //xlDicomData.SamplesPerPixel := 3; //xlDicomData.PlanarConfig := 0;//RGBRGBRGB..., not RRR..RGGG..GBBB...B end; lDynStr:='PGM/PPM format 8-bit grayscale image [data saved in binary, not ASCII format]'; CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write lHdrOK := true; lImageFormatOK:= true; exit; end else if (lWord=12880){'P2'=1x8BIT ASCII} or (lWord=13136) {'P3'=3x8bit ASCI} then begin Msg('Warning: this image appears to be an ASCII ppm/pgm image. This software can only read binary ppm/pgm images'); end;//pgm/ppm binary signature signature end; //.PPM/PGM extension //end .pgm //start BioRadPIC 1667 if TmpStr = '.PIC' then begin dseek(fp, 54); lWord := read16(fp,lrOK); if (lWord=12345) then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_biorad_data(lDICOMdata, lHdrOK, lImageFormatOK,lDynStr,lFileName); exit; end;//biorad signature end; //.PIC extension biorad? //end BIORAD PIC if TmpStr = '.HEAD' then begin read_afni_data(lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName,lRot1,lRot2,lRot3); if (lHdrOK) and (lImageFormatOK) then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write exit; end; end; dseek(fp, 0); dBlockRead(fp, tx, 20*SizeOf(Char), n); if (tx[0] = 'n') and (tx[1] = 'c') and (tx[2] = 'a') and (tx[3] = 'a') then begin //SUN Vision File Format = .vff CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_vff_data(lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName); exit; end; liPos := 1; lStr :=''; {999 While (liPos <= 20) and (lStr <> 'INTERFILE') do begin if tx[liPos] in ['i','n','t','e','r', 'f','i','l','e','I','N','T','E','R', 'F','I','L','E'] then lStr := lStr+upcase(tx[liPos]); inc(liPos); end; } if lStr = 'INTERFILE' then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_interfile_data(lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName); if lHdrOk then exit; exit; end; //'INTERFILE' in first 20 char end;//detectint // try DICOM part 10 i.e. a 128 byte file preamble followed by "DICM" if filesz <= 300 then goto 666; {begin siemens somatom: DO THIS BEFORE MAGNETOM: BOTH HAVE 'SIEMENS' SIGNATURE, SO CHECK FOR 'SOMATOM'} if filesz = 530432 then begin dseek(fp, 281); dBlockRead(fp, tx, 8*SizeOf(Char), n); if (tx[0] = 'S') and (tx[1] = 'O') and (tx[2] = 'M') and (tx[3] = 'A') and (tx[4] = 'T') and (tx[5] = 'O') and (tx[6] = 'M') then begin lDicomData.ImageStart := 6144; lDicomData.Allocbits_per_pixel := 16; //xlDicomData.Storedbits_per_pixel := 16; lDicomData.little_endian := 0; lDicomData.XYZdim[1] := 512; lDicomData.XYZdim[2] := 512; lDicomData.XYZdim[3] := 1; dSeek(fp,5999); //Study/Image from 5292 "STU/IMA 1070/16" lDicomData.AcquNum := trunc(SomaTomFloat);//Slice Thickness from 5790 "SL 3.0" lDicomData.ImageNum := trunc(SomaTomFloat);//Slice Thickness from 5790 "SL 3.0" dSeek(fp,5792); //Slice Thickness from 5790 "SL 3.0" lDicomData.XYZmm[3] := SomaTomFloat;//Slice Thickness from 5790 "SL 3.0" dSeek(fp,5841); //Field of View from 5838 "FoV 281" lDicomData.XYZmm[1] := SomaTomFloat; //Field of View from 5838 "FoV 281" lDicomData.XYZmm[2] := lDicomData.XYZmm[1]/lDicomData.XYZdim[2];//do mm[2] first before FOV is overwritten lDicomData.XYZmm[1] := lDicomData.XYZmm[1]/lDicomData.XYZdim[1]; if lVerboseRead then lDynStr := 'Siemens Somatom Format'+kCR+ 'Image Series/Number: '+inttostr(lDicomData.AcquNum)+'/'+inttostr(lDicomData.ImageNum)+kCR+ 'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'XYZ mm:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2); CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write lImageFormatOK := true; lHdrOK := true; exit; end; //signature found end; //correctsize for somatom {end siemens somatom} {siemens magnetom} dseek(fp,96); dBlockRead(fp, tx, 7*SizeOf(Char), n); if (tx[0] = 'S') and (tx[1] = 'I') and (tx[2] = 'E') and (tx[3] = 'M') and (tx[4] = 'E') and (tx[5] = 'N') and (tx[6] = 'S') then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_siemens_data(lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName); exit; end; {end siemens magnetom vision} {siemens somatom plus} dseek(fp, 0); dBlockRead(fp, tx, 8*SizeOf(Char), n); if (tx[0] = 'S') and (tx[1] = 'I') and (tx[2] = 'E') and (tx[3] = 'M') and (tx[4] = 'E') and (tx[5] = 'N') and (tx[6] = 'S') then begin lDicomData.ImageStart := 8192; lDicomData.Allocbits_per_pixel := 16; //xlDicomData.Storedbits_per_pixel := 16; lDicomData.little_endian := 0; dseek(fp, 1800); //slice thickness lDicomData.XYZmm[3] := read64(fp,lrOK); dseek(fp, 4100); lDicomData.AcquNum := read32(fp,lrOK); dseek(fp, 4108); lDicomData.ImageNum := read32(fp,lrOK); dseek(fp, 4992); //X FOV lDicomData.XYZmm[1] := read64(fp,lrOK); dseek(fp, 5000); //Y FOV lDicomData.XYZmm[2] := read64(fp,lrOK); dseek(fp, 5340); lDicomData.XYZdim[1] := read32(fp,lrOK); dseek(fp, 5344); lDicomData.XYZdim[2] := read32(fp,lrOK); lDicomData.XYZdim[3] := 1; if lDicomData.XYZdim[1] > 0 then lDicomData.XYZmm[1] := lDicomData.XYZmm[1]/lDicomData.XYZdim[1]; if lDicomData.XYZdim[2] > 0 then lDicomData.XYZmm[2] := lDicomData.XYZmm[2]/lDicomData.XYZdim[2]; if lVerboseRead then lDynStr := 'Siemens Somatom Plus Format'+kCR+ 'Image Series/Number: '+inttostr(lDicomData.AcquNum)+'/'+inttostr(lDicomData.ImageNum)+kCR+ 'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'XYZ mm:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2); CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write lImageFormatOK := true; lHdrOK := true; exit; end; {end siemens somatom plus } {picker} dseek(fp,0); dBlockRead(fp, tx, 8*SizeOf(Char), n); if (tx[0]='C') and (tx[1]='D') and (tx[2]='F') and (ord(tx[3]) = 1) then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_minc_data(lDICOMdata, lHdrOK, lImageFormatOK,lDynStr,lFileName); exit; end; if (lAutoDECAT7) and (tx[0]='M') and (tx[1]='A') and (tx[2]='T') and (tx[3]='R') and (tx[4]='I') and (tx[5]='X') then begin CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_ecat_data(lDICOMdata, lVerboseRead,lReadECAToffsetTables,lHdrOK, lImageFormatOK, lDynStr, lFileName); exit; end; if (tx[0] = '*') AND (tx[1] = '*') AND (tx[2] = '*') AND (tx[3] = ' ') then begin {picker Standard} CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write read_picker_data(lVerboseRead,lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName); exit; end; {not picker standard} //Start Picker Prism ljunk := filesz-2048; lDICOMdata.little_endian := 0; //start: read x dseek(fp, 322); Width := read16(fp,lrOK); //start: read y dseek(fp, 326); Ht := read16(fp,lrOK); lMatrixSz := Width * Ht; //check if correct filesize for picker prism if (ord(tx[0]) = 1) and (ord(tx[1])=2) and ((ljunk mod lMatrixSz)=0){128*128*2bytes = 32768} then begin //Picker PRISM lDicomData.little_endian := 0; lDicomData.XYZdim[1] := Width; lDicomData.XYZdim[2] := Ht; lDicomData.XYZdim[3] := (ljunk div 32768); {128*128*2bytes = 32768} lDicomData.Allocbits_per_pixel := 16; //xlDicomData.Storedbits_per_pixel := 16; lDicomData.ImageStart := 2048; //start: read slice thicness dseek(fp,462); dBlockRead(fp, tx, 12*SizeOf(Char), n); lStr := ''; for ljunk := 0 to 11 do if tx[ljunk] in ['0'..'9','.'] then lStr := lStr+ tx[ljunk]; if lStr <> '' then lDicomData.XYZmm[3] := strtofloat(lStr); //start: voxel size dseek(fp,594); dBlockRead(fp, tx, 12*SizeOf(Char), n); lStr := ''; for ljunk := 0 to 11 do if tx[ljunk] in ['0'..'9','.'] then lStr := lStr+ tx[ljunk]; if lStr <> '' then lDicomData.XYZmm[1] := strtofloat(lStr); lDicomData.XYZmm[2] := lDicomData.XYZmm[1]; //end: read voxel sizes //start: patient name dseek(fp,26); dBlockRead(fp, tx, 22*SizeOf(Char), n); lStr := ''; ljunk := 0; while (ljunk < 22) and (ord(tx[ljunk]) <> 0) do begin lStr := lStr+ tx[ljunk]; inc(ljunk); end; lDicomData.PatientName := lStr; //start: patient ID dseek(fp,48); dBlockRead(fp, tx, 15*SizeOf(Char), n); lstr := ''; ljunk := 0; while (ljunk < 15) and (ord(tx[ljunk]) <> 0) do begin lstr := lstr+ tx[ljunk]; inc(ljunk); end; //xlDicomData.PatientID := lStr; //start: scan time dseek(fp,186); dBlockRead(fp, tx, 25*SizeOf(Char), n); lstr := ''; ljunk := 0; while (ljunk < 25) and (ord(tx[ljunk]) <> 0) do begin lstr := lstr+ tx[ljunk]; inc(ljunk); end; //start: scanner type dseek(fp,2); dBlockRead(fp, tx, 25*SizeOf(Char), n); lgrpstr := ''; ljunk := 0; while (ljunk < 25) and (ord(tx[ljunk]) <> 0) do begin lgrpstr := lgrpstr+ tx[ljunk]; inc(ljunk); end; //report results if lVerboseRead then lDynStr := 'Picker Format '+lgrpstr+kCR+ 'Patient Name: '+lDicomData.PatientName+kCR+ //x'Patient ID: '+lDicomData.PatientID+kCR+ 'Scan Time: '+lStr+kCR+ 'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/' +inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'XYZ mm:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2); CloseFile(fp); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); FileMode := 2; //set to read/write lImageFormatOK := true; lHdrOK := true; exit; end; //end Picker PRISM lMatrixSz := 0; lDICOMdata.little_endian := 1; lBig := false; dseek(fp, {0}128); //where := FilePos(fp); dBlockRead(fp, tx, 4*SizeOf(Char), n); if (tx[0] <> 'D') OR (tx[1] <> 'I') OR (tx[2] <> 'C') OR (tx[3] <> 'M') then begin //if filesz > 132 then begin dseek(fp, 0{128}); //skip the preamble - next 4 bytes should be 'DICM' //where := FilePos(fp); dBlockRead(fp, tx, 4*SizeOf(Char), n); //end; if (tx[0] <> 'D') OR (tx[1] <> 'I') OR (tx[2] <> 'C') OR (tx[3] <> 'M') then begin dseek(fp, 0); group := read16(fp,lrOK); if not lrOK then goto 666; if group > $0008 then begin group := swap(group); lBig := true; end; if NOT (group in [$0000, $0001, $0002,$0003, $0004, $0008]) then // one more group added begin goto 666; end; dseek(fp, 0); //Msg('DICM not at 0 or 128: ' +lFilename); end; end; //else Msg('DICM at 128{0}');; time_to_quit := FALSE; lProprietaryImageThumbnail := false; explicitVR := false; tmpstr := ''; tmp := 0; while NOT time_to_quit do begin t := unknown; where := dFilePos(fp); lFirstPass := true; 777: group := read16(fp,lrOK); if (lSwitchToImplicitAfterGroup0002) and (group > 0002) then begin lSwitchToImplicitAfterGroup0002 := false; explicitVR := false; end; if not lrOK then goto 666; if (lFirstPass) and (group = 2048) then begin if lDicomData.little_endian = 1 then lDicomData.Little_endian := 0 else lDicomData.little_endian := 1; dseek(fp,where); lFirstPass := false; goto 777; end; element := read16(fp,lrOK); if not lrOK then goto 666; e_len:= read32(fp,lrOK); if not lrOK then goto 666; lGrpStr := ''; lt0 := e_len and 255; lt1 := (e_len shr 8) and 255; lt2 := (e_len shr 16) and 255; lt3 := (e_len shr 24) and 255; if (explicitVR) and (lT0=13) and (lT1=0) and (lT2=0) and (lT3=0) then e_len := 10; //hack for some GE Dicom images if explicitVR or first_one then begin if group = $FFFE then else //1384 - ACUSON images switch off ExplicitVR for file image fragments if ((lT0=kO) and (lT1=kB)) or ((lT0=kU) and (lT1=kN)){<-UN added 11/11/2011} or ((lT0=kO) and (lT1=kW)) or ((lT0=kS) and (lT1=kQ)) {11/11 add UT}or ((lT0=kU) and (lT1=kT)) then begin lGrpStr := chr(lT0)+chr(lT1); e_len:= read32(fp,lrOK); if not lrOK then goto 666; if first_one then explicitVR := true; end else if ((lT3=kO) and (lT2=kB)) or ((lT3=kU) and (lT2=kN)){<-UN added 11/11/2011} or((lT3=kO) and (lT2=kW)) or ((lT3=kS) and (lT2=kQ)) or ((lT3=kU) and (lT2=kT))then begin e_len:= read32(fp,lrOK); if not lrOK then goto 666; if first_one then explicitVR := true; end else if ( ((lT0=kA) and (lT1=kE)) or ((lT0=kA) and (lT1=kS)) or ((lT0=kA) and (lT1=kT)) or ((lT0=kC) and (lT1=kS)) or ((lT0=kD) and (lT1=kA)) or ((lT0=kD) and (lT1=kS)) or ((lT0=kD) and (lT1=kT)) or ((lT0=kF) and (lT1=kL)) or ((lT0=kF) and (lT1=kD)) or ((lT0=kI) and (lT1=kS)) or ((lT0=kL) and (lT1=kO))or ((lT0=kL) and (lT1=kT)) or ((lT0=kP) and (lT1=kN)) or ((lT0=kS) and (lT1=kH)) or ((lT0=kS) and (lT1=kL)) or ((lT0=kS) and (lT1=kS)) or ((lT0=kS) and (lT1=kT)) or ((lT0=kT) and (lT1=kM)) or ((lT0=kU) and (lT1=kI)) or ((lT0=kU) and (lT1=kL)) or ((lT0=kU) and (lT1=kS)) or ((lT0=kA) and (lT1=kE)) or ((lT0=kA) and (lT1=kS)) ) then begin lGrpStr := chr(lT0) + chr(lT1); if lDicomData.little_endian = 1 then e_len := (e_len and $ffff0000) shr 16 else e_len := swap((e_len and $ffff0000) shr 16); if first_one then begin explicitVR := true; end; end else if ( ((lT3=kA) and (lT2=kT)) or ((lT3=kC) and (lT2=kS)) or ((lT3=kD) and (lT2=kA)) or ((lT3=kD) and (lT2=kS)) or ((lT3=kD) and (lT2=kT)) or ((lT3=kF) and (lT2=kL)) or ((lT3=kF) and (lT2=kD)) or ((lT3=kI) and (lT2=kS)) or ((lT3=kL) and (lT2=kO))or ((lT3=kL) and (lT2=kT)) or ((lT3=kP) and (lT2=kN)) or ((lT3=kS) and (lT2=kH)) or ((lT3=kS) and (lT2=kL)) or ((lT3=kS) and (lT2=kS)) or ((lT3=kS) and (lT2=kT)) or ((lT3=kT) and (lT2=kM)) or ((lT3=kU) and (lT2=kI)) or ((lT3=kU) and (lT2=kL)) or ((lT3=kU) and (lT2=kS))) then begin if lDicomData.little_endian = 1 then e_len := (256 * lT0) + lT1 else e_len := (lT0) + (256*lT1); if first_one then begin explicitVR := true; end; end; end; //not first_one or explicit if (first_one) and (lDicomdata.little_endian =0) and (e_len = $04000000) then begin Msg('Switching to little endian'); lDicomData.little_endian := 1; dseek(fp, where); first_one := false; goto 777; end else if (first_one) and (lDicomData.little_endian =1) and (e_len = $04000000) then begin Msg('Switching to little endian'); lDicomData.little_endian := 0; dseek(fp, where); first_one := false; goto 777; end; if e_len = ($FFFFFFFF) then begin e_len := 0; end; if lGELX then begin e_len := e_len and $FFFF; end; first_one := false; remaining := e_len; info := '?'; tmpstr := ''; //10b1 if (lIndent > 0) and (not ((group= $FFFE) and (element = $E0DD))) and (not lManufacturerIsPhilips) then // goto 1234; //Philips stores slice positioning inside 0020,9113; lice orientation inside 0020,9116 but Siemens stores thumbnails in indented subheadings case group of $0001 : // group for normal reading elscint DICOM case element of $0010 : info := 'Name'; $1001 : info := 'Elscint info'; end; $0002 : case element of $00 : info := 'File Meta Elements Group Len'; $01 : info := 'File Meta Info Version'; $02 : info := 'Media Storage SOP Class UID'; $03 : info := 'Media Storage SOP Inst UID'; $10 : begin //lTransferSyntaxReported := true; info := 'Transfer Syntax UID'; TmpStr := ''; if dFilePos(fp) > (filesz-e_len) then goto 666; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for i := 0 to e_len-1 do if Char(buff[i]) in ['+','-',' ', '0'..'9','a'..'z','A'..'Z'] then TmpStr := TmpStr +(Char(buff[i])) else TmpStr := TmpStr +('.'); FreeMem( buff); lStr := ''; //Msg(TmpStr); if TmpStr = '1.2.840.113619.5.2' then begin lGELX := true; LBigSet := true; lBig := true; end; // if length(TmpStr) < 19 then begin //12/2010 assume 1.2.840.10008.1.2 //Raw data, Implicit VR, Little Endian // explicitVR := false; //china lSwitchToImplicitAfterGroup0002 := true; end; if length(TmpStr) >= 19 then begin if TmpStr[19] = '1' then begin lBigSet:= true; explicitVR := true; //duran lBig := false; end else if TmpStr[19] = '2' then begin lBigSet:= true; explicitVR := true; //duran lBig := true; end else if TmpStr[19] = '4' then begin if length(TmpStr) >= 21 then begin //Dec 2012.... dcm2nii can handle JPEG 123456 if {not lReadJPEGtables} false then begin lImageFormatOK := false; end else begin i := strtoint(TmpStr[21]+TmpStr[22]); if (i <> 57) and (i <> 70) then begin lImageFormatOK := false; //lDicomData.JPEGLossyCpt := true end else begin //lImageFormatOK := false;//123456 lDicomData.JPEGLosslessCpt := true; end; end; end else begin lImageFormatOK := false; end; end else if TmpStr[19] = '5' then begin lImageFormatOK := false;//xlDicomData.RunLengthEncoding := true; end else begin lImageFormatOK := false; end; if not lImageFormatOK then Msg('Unsupported Transfer Syntax '+(TmpStr)+' Solution: use MRIcro'); end; {length} remaining := 0; e_len := 0; {use tempstr} end; $12 : begin info := 'Implementation Class UID'; end; $13 : begin info := 'Implementation Version Name'; if e_len > 4 then begin TmpStr := ''; DICOMHeaderString(TmpStr); //lDicomData.ImplementationVersion := Str2Int(TmpStr); if TmpStr = 'MEDIFACE 1 5' then lMediface0002_0013 := true; //detect MEDIFACE 1.5 error: error in length of two elements 0008:1111 and 0008:1140 end; //length > 4 end; //element 13 $16 : info := 'Source App Entity Title'; $100: info := 'Private Info Creator UID'; $102: info := 'Private Info'; end; $0008 : case element of $00 : begin info := 'Identifying Group Length'; end; $01 : info := 'Length to End'; $05 : info := 'Specific Character Set'; $08 : begin info := 'Image Type'; if dFilePos(fp) > (filesz-e_len) then goto 666; lSiemensMosaic0008_0008:= false; if (e_len >= 6) then begin //search for 'MOSAIC' GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); i := e_len -6;//MOSAIC while (i>-1) and (not lSiemensMosaic0008_0008) do begin if (upcase(Char(buff[i])) = 'M') and (upcase(Char(buff[i+1])) = 'O') and (upcase(Char(buff[i+2])) = 'S') and (upcase(Char(buff[i+3])) = 'A') and (upcase(Char(buff[i+4])) = 'I') and (upcase(Char(buff[i+5])) = 'C') then //strip filler characters: DICOM elements must be padded for even length lSiemensMosaic0008_0008 := true; dec(i); end; FreeMem( buff); remaining := 0; e_len := 0; {use tempstr} end; end; $10 : info := 'Recognition Code'; $12 : info := 'Instance Creation Date'; $13 : info := 'Instance Creation Time'; $14 : info := 'Instance Creator UID'; $16 : info := 'SOP Class UID'; $18 : info := 'SOP Instance UID'; $20 : begin info := 'Study Date'; //lDicomData.StudyDatePos := dFilePos(fp); DICOMHeaderString(lDicomData.StudyDate); end; $21 : info := 'Series Date'; $22 : info := 'Acquisition Date'; $23 : info := 'Image Date'; $30 : begin info := 'Study Time'; DICOMHeaderStringTime(lDicomData.StudyTime); end; $31 : info := 'Series Time'; $32 : begin info := 'Acquisition Time'; DICOMHeaderStringTime(TmpStr); lDicomData.SecSinceMidnight := SecSinceMidnightFloat(TmpStr); end; $33 : begin info := 'Image Time'; //xxDICOMHeaderStringTime(lDicomData.ImgTime); end; $40 : info := 'Data Set Type'; $41 : info := 'Data Set Subtype'; $50 : begin //xDICOMHeaderStringtoInt(lDicomData.accession); info := 'Accession Number'; end; $60 : begin info := 'Modality'; t := _string; end; $64 : begin info := 'Conversion Type'; t := _string; end; $70 : begin info := 'Manufacturer'; //Only read last word, e.g. 'TYPE\MOSAIC' will be read as 'MOSAIC' TmpStr := ''; if dFilePos(fp) > (filesz-e_len) then goto 666; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); i := e_len -1; while (i>-1) and (Char(buff[i]) in ['a'..'z','A'..'Z',' ']) do begin if (Char(buff[i])) <> ' ' then //strip filler characters: DICOM elements must be padded for even length TmpStr := upcase(Char(buff[i]))+TmpStr; dec(i); end; FreeMem( buff); remaining := 0; e_len := 0; {use tempstr} if (length(TmpStr) > 3) and (TmpStr[1]='P') and (TmpStr[2]='H') and (TmpStr[3]='I') then lManufacturerIsPhilips := true; if (length(TmpStr) > 3) and (TmpStr[1]='B') and (TmpStr[2]='R') and (TmpStr[3]='U') then lManufacturerIsBruker := true; if lManufacturerIsPhilips then lDicomData.ManufacturerID := kPhilipsID; if (length(TmpStr) > 3) and (TmpStr[1]='G') and (TmpStr[2]='E') then lDicomData.ManufacturerID := kGEID; if (length(TmpStr) > 3) and (TmpStr[1]='S') and (TmpStr[2]='I') and (TmpStr[3]='E') then lDicomData.ManufacturerID := kSiemensID; end; $80 : info := 'Institution Name'; $81 : info := 'City Name'; $90 : info := 'Referring Physician''s Name'; $100: info := 'Code Value'; $102 : begin info := 'Coding Schema Designator'; t := _string; end; $104: info := 'Code Meaning'; $1010: info := 'Station Name'; $1030: begin info := 'Study Description'; t := _string; end; $103e: begin info := 'Series Description'; t := _string; end; $1040: info := 'Institutional Dept. Name'; $1050: info := 'Performing Physician''s Name'; $1060: info := 'Name Phys(s) Read Study'; $1070: begin info := 'Operator''s Name'; t := _string; end; $1080: info := 'Admitting Diagnosis Description'; $1090: begin info := 'Manufacturer''s Model Name';t := _string; end; $1111: begin if lMediface0002_0013 then E_LEN := 8;//+e_len; end; //ABBA: patches error in DICOM images seen from Sheffield 0002,0013=MEDIFACE.1.5; 0002,0016=PICKER.MR.SCU $1140: begin if (lMediface0002_0013) and (E_LEN > 255) then E_LEN := 8; end; //ABBA: patches error in DICOM images seen from Sheffield 0002,0013=MEDIFACE.1.5; 0002,0016=PICKER.MR.SCU $2111: info := 'Derivation Description'; $2120: info := 'Stage Name'; $2122: begin info := 'Stage Number';t := _string; end; $2124: begin info := 'Number of Stages';t := _string; end; $2128: begin info := 'View Number';t := _string; end; $212A: begin info := 'Number of Views in stage';t := _string; end; $2204: info := 'Transducer Orientation'; $9208: begin info := 'ComplexImageComponent'; TmpStr := ''; DICOMHeaderString(TmpStr); i := 0; if length(TmpStr) >= 2 then begin if (TmpStr[1] = 'M') and (TmpStr[2] = 'A') then i := 1; //magnitude if (TmpStr[1] = 'P') and (TmpStr[2] = 'H') then i := 2; //phase if (TmpStr[1] = 'R') and (TmpStr[2] = 'E') then i := 3; //real if (TmpStr[1] = 'I') and (TmpStr[2] = 'M') then i := 4; //imaginary end; //mixed will be followed by subsequent settings, so do not use it here.... if (i > 0) and (lDICOMdata.nOrder < kMaxOrderVal) then begin inc(lDICOMdata.nOrder); //msg(TmpStr); lDICOMdata.order[lDICOMdata.nOrder] := i; end; (*[ magnitude * MAGNITUDE [ phase * PHASE [ real * REAL [ imaginary * IMAGINARY [ mixed * MIXED*) ///xxx xxx end; end; $0009: if element = $0010 then begin if e_len > 4 then begin TmpStr := ''; if dFilePos(fp) > (filesz-e_len) then goto 666; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); i := e_len -1; while (i>-1) {and (Char(buff[i]) in ['a'..'z','A'..'Z',' '])} do begin if (Char(buff[i])) in ['a'..'z','A'..'Z'] then //strip filler characters: DICOM elements must be padded for even length TmpStr := upcase(Char(buff[i]))+TmpStr; dec(i); end; FreeMem( buff); remaining := 0; if (Length(TmpStr)>4) and (TmpStr[1]='M') and (TmpStr[2]='E') and (TmpStr[3]='R') and (TmpStr[4]='G') then lOldSiemens_IncorrectMosaicMM := true; //detect MERGE technologies mosaics e_len := 0; {use tempstr} end; end; $0010 : case element of $00 : info := 'Patient Group Length'; $10 : begin info := 'Patient''s Name'; t := _string; //xlDicomData.NamePos := dFilePos(fp); DICOMHeaderString(lDicomData.PatientName); end; $20 : begin info := 'Patient ID'; //xDICOMHeaderString(lDicomData.PatientID); //xlDicomData.PatientIDInt := safestrtoint(lDicomData.PatientID); end; //11/2010 //$30: info := 'Date of Birth'; //"Age String" type: e.g 067y for 67 years old, 067d for 67 days $30 : begin info := 'DoB'; t := _string; //xlDicomData.NamePos := dFilePos(fp); //lDicomData.PatientDoB := '1111'; DICOMHeaderString(lDicomData.PatientDoB); end; $32 : info := 'Patient Birth Time'; //$40 : begin info := 'Patient Sex'; t := _string; end; $40 : begin info := 'Gender'; t := _string; //xlDicomData.NamePos := dFilePos(fp); DICOMHeaderString(lDicomData.PatientGender); end; $1000: info := 'Other Patient IDs'; $1001: info := 'Other Patient Names'; $1005: info := 'Patient''s Birth Name'; $1010: begin info := 'Patient Age'; t := _string; end; $1030: info := 'Patient Weight'; $21b0: info := 'Additional Patient History'; $4000: info := 'Patient Comments'; end; $0018 : case element of $00 : info := 'Acquisition Group Length'; $10 : begin info := 'Contrast/Bolus Agent'; t := _string; end; $15: info := 'Body Part Examined'; $20 : begin info := 'Scanning Sequence';t := _string; TmpStr := ''; DICOMHeaderString(TmpStr); if TmpStr = 'RM' then lResearchMode := true; end; $21 : begin info := 'Sequence Variant';t := _string; end; $22 : info := 'Scan Options'; $23 : begin info := 'MR Acquisition Type'; t := _string; end; $24 : info := 'Sequence Name'; $25 : begin info := 'Angio Flag';t := _string; end; $30 : info := 'Radionuclide'; $50 : begin info := 'Slice Thickness'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDICOMdata.XYZmm[3] := lfloat1; lThickness := lfloat1;//lDICOMdata.Thickness := lfloat1; //1391b end; //$60: begin info := 'KVP [Peak Output, KV]'; t := _string; end; //aqw $60: begin info := 'KVP [Peak KV]'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDicomData.kV := lFloat1; end; $70: begin t := _string; info := 'Counts Accumulated'; end; $71: begin t := _string; info := 'Acquisition Condition'; end; //$80 : begin info := 'Repetition Time'; t := _string; end; //aqw //$81 : begin info := 'Echo Time'; t := _string; end; //aqw $80 : begin info := 'Repetition Time [TR, ms]'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDicomData.TR := lFloat1; end; $81 : begin info := 'Echo Time [TE, ms]'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDicomData.TE := lFloat1; end; $82 : begin t := _string; info := 'Inversion Time';end; $83 : begin t := _string; info := 'Number of Averages'; end; $84 : info := 'Imaging Frequency'; $85 : begin info := 'Imaged Nucleus'; t := _string; end; $86 : begin info := 'Echo Number';t := _string; DICOMHeaderStringToInt(lEchoNum); //lDICOMdata.Echo := lEchoNum; end; //qq $87 : info := 'Magnetic Field Strength'; $88 : begin info := 'Spacing Between Slices'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; //1362 some use this for gap size, others for sum of gap and slicethickness! //3333 if (lfloat1 > lDICOMdata.XYZmm[3]) or (lDICOMdata.XYZmm[3]=1) then //lDICOMdata.XYZmm[3] := lfloat1; //fx(lDICOMdata.XYZmm[3],lThickness,lfloat1); if lfloat1 < 0 then lDICOMdata.XYZmm[3] := lFloat1//does not make sense - found in some eFilm images from Marconi P3000 else if ( (lThickness/2) > lfloat1 ) then lDICOMdata.XYZmm[3] := lfloat1+lThickness else lDICOMdata.XYZmm[3] := lfloat1;//1392 //xldicomdata.spacing:=lfloat1; end; $89 : begin // t := _string; info := 'Number of Phase Encoding Steps'; //1499c This is a indirect method for detecting SIemens Mosaics: check if image height is evenly divisible by encoding steps // A real kludge due to Siemens not documenting mosaics explicitly: this workaround may incorrectly think rescaled images are mosaics! readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); lPhaseEncodingSteps := round(lfloat1); //xxxMsg(floattostr(lFloat1)); if not lrOK then goto 666; e_len := 0; remaining := 0; //1362 some use this for gap size, others for sum of gap and slicethickness! //if (lfloat1 > lDICOMdata.XYZmm[3]) or (lDICOMdata.XYZmm[3]=1) then //lDICOMdata.XYZmm[3] := lfloat1; //ldicomdata.spacing:=lfloat1; end; $90 : info := 'Data collection diameter'; $91 : begin info := 'Echo Train Length';t := _string; end; $93: begin info := 'Percent Sampling'; t := _string; end; $94: begin info := 'Percent Phase Field View'; t := _string; end; $95 : begin info := 'Pixel Bandwidth'; t := _string; end; $1000: begin t := _string; info := 'Device Serial Number'; end; $1004: info := 'Plate ID'; $1020: begin info := 'Software Version'; t := _string; if e_len > 2 then begin TmpStr := ''; DICOMHeaderString(TmpStr); lDicomData.Vers0018_1020 := Siemensversion(TmpStr); end; //showmsg(inttostr(lDicomData.Vers0018_1020)+' '+TmpStr); end; $1030: begin info := 'Protocol Name';t := _string; TmpStr := ''; DICOMHeaderString(TmpStr); lDicomData.ProtocolName := TmpStr; AplhaNumericStrDICOM (lDicomData.ProtocolName); end; $1040: info := 'Contrast/Bolus Route'; $1050 : begin t := _string; info := 'Spatial Resolution'; end; $1060: info := 'Trigger Time'; $1062: info := 'Nominal Interval'; $1063: info := 'Frame Time'; $1081: info := 'Low R-R Value'; $1082: info := 'High R-R Value'; $1083: info := 'Intervals Acquired'; $1084: info := 'Intervals Rejected'; $1088: begin info := 'Heart Rate'; t := _string; end; $1090: begin info := 'Cardiac Number of Images'; t := _string; end; $1094: begin info := 'Trigger Window';t := _string; end; $1100: info := 'Reconstruction Diameter'; $1110: info := 'Distance Source to Detector [mm]'; $1111: info := 'Distance Source to Patient [mm]'; $1120: info := 'Gantry/Detector Tilt'; $1130: info := 'Table Height'; $1140: info := 'Rotation Direction'; $1147: info := 'Field of View Shape'; $1149: begin t := _string; info := 'Field of View Dimension[s]'; end; $1150: begin info := 'Exposure Time [ms]'; t := _string; end; $1151: begin info := 'X-ray Tube Current [mA]'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; //xlDicomData.mA := lFloat1; end; $1152 : info := 'Acquisition Device Processing Description'; $1155: info := 'Radiation Setting'; $1160: info := 'Filter Type'; $1164: info :='Imager Pixel Spacing'; $1166: info := 'Grid'; $1170 : info := 'Generator Power'; $1180 : info := 'Collimator/grid Name'; $1190 : begin info := 'Focal Spot[s]'; t := _string; end; $11A0 : begin info := 'Body Part Thickness'; t := _string; end; $11A2 : info := 'Compression Force'; $1200 : info := 'Date of Last Calibration'; $1201 : info := 'Time of Last Calibration'; $1210: info := 'Convolution Kernel'; $1250: begin t := _string; info := 'Receiving Coil'; end; $1251: begin t := _string; info := 'Transmitting Coil'; end; $1260 : begin t := _string; info := 'Plate Type'; end; $1261 : begin t := _string; info := 'Phosphor Type'; end; $1310: begin info := 'Acquisition Matrix'; //Siemens Mosaics converted by Merge can report the incorrect mm //nji2 //NOTE: Matrix Information for MERGE converted images. Used Innocently for other uses by Siemens if (lOldSiemens_IncorrectMosaicMM) or ((lSiemensMosaic0008_0008) and (lMatrixSz < 1){B13}) then begin //TmpStr := ReadStrABC(fp, remaining,lrOK,lA,lB,lC); TmpStr := ReadStr(fp, remaining,lrOK,lMatrixSz); //ss//1362 //fx(remaining); (*kEr := true; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; kEr := false; lMatrixSz := round(lFloat1); msg(TmpStr); fx(lMatrixSz,lFLoat1,lFloat2,4321);*) {fx(lA,lB,lC); lMatrixSz := lB; lMatrixSzY := lC; } end else TmpStr := ReadStr(fp, remaining,lrOK,lJunk);//1362 if not lrOK then goto 666; e_len := 0; remaining := 0; end; $1312: begin t := _string; info := 'Phase Encoding Direction'; TmpStr := ''; DICOMHeaderString(TmpStr); lDicomData.PhaseEncoding := TmpStr; AplhaNumericStrDICOM (lDicomData.PhaseEncoding); end; $1314: begin t := _string; info := 'Flip Angle'; end; $1315: begin t := _string;info := 'Variable Flip Angle Flag'; end; $1316: begin t := _string;info := 'SAR'; end; $1400: info := 'Acquisition Device Processing Description'; $1401: begin info := 'Acquisition Device Processing Code';t := _string; end; $1402: info := 'Cassette Orientation'; $1403: info := 'Cassette Size'; $1404: info := 'Exposures on Plate'; $1405: begin info := 'Relative X-Ray Exposure'; t := _string; end; $1500: info := 'Positioner Motion'; $1508: info := 'Positioner Type'; $1510: begin info := 'Positioner Primary Angle'; t := _string; end; $1511: info := 'Positioner Secondary Angle'; $5020: info := 'Processing Function'; $5100: begin t := _string; info := 'Patient Position'; TmpStr := ''; DICOMHeaderString(TmpStr); lDicomData.PatientPos := TmpStr; AplhaNumericStrDICOM (lDicomData.PatientPos); end; $5101: begin info := 'View Position';t := _string; end; $6000: begin info := 'Sensitivity'; t := _string; end; $7004: info := 'Detector Type'; $7005: begin info := 'Detector Configuration'; t := _string; end; $7006: info := 'Detector Description'; $700A: info := 'Detector ID'; $700C: info := 'Date of Last Detector Calibration'; $700E: info := 'Date of Last Detector Calibration'; $7048: info := 'Grid Period'; $7050: info := 'Filter Material LT'; $7060: info := 'Exposure Control Mode'; //$9114: fx(1233); end; $0019: begin (*case element of //1362 //3/3/2008 this old method for detecting mosaics has a problem - if image is interpolated x2, you will assume a 2x2 mosaic $1220: begin info := 'Matrix';t := _string; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; if lfloat2 > lfloat1 then lfloat1 := lfloat2; lMatrixSz := round(lfloat1); //if >32767 then there will be wrap around if read as signed value! remaining := 0; end; $14D4: begin info := 'Matrix';t := _string; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; if lfloat2 > lfloat1 then lfloat1 := lfloat2; lMatrixSz := round(lfloat1); //if >32767 then there will be wrap around if read as signed value! remaining := 0; end; end; *) //case element if lDicomData.ManufacturerID = kSiemensID then begin case element of //1362 (*$100A: begin //unsigned short $100A info := 'Number Of Images in Mosaic'; tmp := read16(fp,lrOK); if not lrOK then goto 666; fx(e_len,tmp,remaining); end;*) $1028: begin //7/2013 info := 'Siemens BandwidthPerPixelPhaseEncode'; lDICOMdata.BandwidthPerPixelPhaseEncode := read64 (fp,lrOK); if not lrOK then goto 666; e_len := 0; remaining := 0; end; // b-values $000C,$100C: begin info := 'Siemens b-value'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; tmpstr := floattostr(lFloat1); lDICOMdata.DTI[1].bval := round(lFloat1); lDICOMdata.SiemensDICOMDTI := true ; //msgfx( 777,lDICOMdata.DTI[1].bval,lDICOMdata.DTI[1].bval,lDICOMdata.DTI[1].bval); end; // b-values $000E,$100E: begin info := 'Siemens Gradient vector [x,y,z]'; //readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); lDICOMdata.DTI[1].v1 := read64 (fp,lrOK); if not lrOK then goto 666; lDICOMdata.DTI[1].v2 := read64 (fp,lrOK); if not lrOK then goto 666; lDICOMdata.DTI[1].v3 := read64 (fp,lrOK); if not lrOK then goto 666; //msgfx( 666,lDICOMdata.DTI[1].v1,lDICOMdata.DTI[1].v2,lDICOMdata.DTI[1].v3); //readfloats3 (fp, remaining, lDummyStr, lDICOMdata.DTI[1].v1,lDICOMdata.DTI[1].v2,lDICOMdata.DTI[1].v3, lROK); //ShowMsg(lDummyStr); //fx(e_len,lDICOMdata.DTI[1].v1,lDICOMdata.DTI[1].v2,lDICOMdata.DTI[1].v3); e_len := 0; remaining := 0; //lDICOMdata.DTI[1].v1 := lFloat1; end; // X diffusion direction end;//Case element end;//if Siemens if lDicomData.ManufacturerID = kGEID then begin case element of //1362 $10BB,$a0bb: begin info := 'GE Gradient vector [x]'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDICOMdata.DTI[1].v1 := lFloat1; end; // X diffusion direction $10BC,$A0BC: begin info := 'GE Gradient vector [y]'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDICOMdata.DTI[1].v2 := lFloat1; end;//Y diffusion direction $10BD,$A0BD: begin info := 'GE Gradient vector [z]'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDICOMdata.DTI[1].v3 := lFloat1; end;// Z diffusion direction end;//Case element // end;//if GE end;//$0019 $0020 : case element of $00 : info := 'Relationship Group Length'; $0d : info := 'Study Instance UID'; $0e : info := 'Series Instance UID'; $10 : begin info := 'Study ID'; t := _string; end; $11 : begin info := 'Series Number'; DICOMHeaderStringToInt(lDicomData.SeriesNum); end; $12 : // begin info := 'Acquisition Number'; t := _string; end; begin info := 'Acquisition Number'; DICOMHeaderStringToInt(lDicomData.AcquNum); end; $13 : begin info := 'Image Number'; DICOMHeaderStringToInt(lTempInt); if (lDicomData.ImageNum < 2) and (lTempInt >= 0) then lDicomData.ImageNum := lTempInt; //March2008 - some Philips data has multiple image numbers... // 0018,1020,Software Version=1.5.4\1.5.4.3\Gyroscan PMS/DICOM 2.0 MR .Id. datadefs.v 5.27 2004/10/18 06.50 //msg(inttostr(lDicomData.ImageNum)+lDicomData.Filename); end; $20 : begin info := 'Patient Orientation'; t := _string; end; $30 : info := 'Image Position'; $32 : begin info := 'Image Position Patient'; //June 2009 - for Philips new 4D format we want value from the first slice... if lInside2005140F then begin if not (lPhilipsWarning) then Msg('*User: check slice thickness. Possible Philips R3.2.2 bug - scanner can report different 0020,0032 values for the same slice.'); lPhilipsWarning := true; end else begin //5/2012: Philips R3.2.2 can save two instances of 0020:0032 for each slice: one from voxel center, one from voxel edge. if not lImagePositionPatientRead then begin readfloats3 (fp, remaining, lDummyStr, lDicomData.PatientPosX, lDicomData.PatientPosY,lDicomData.PatientPosZ, lROK); //fx( lDicomData.PatientPosX, lDicomData.PatientPosY,lDicomData.PatientPosZ,56789); if not lrOK then goto 666; e_len := 0; remaining := 0; lImagePositionPatientRead := true; //we assume Philips reports the slice thickness correctly.... //an alternative would be to read both 1st and 2nd ImagePositionPatient and //compute the function DICOMinterslicedistance end else begin CheckIntersliceDistance(l4DDistanceBetweenSliceCenters); end; //not 1st read end; //if lInside2005140F //lInside2005140F := false; end; $35 : info := 'Image Orientation'; $37 : begin //nifti info := 'Image Orientation (Patient)'; readfloats6 (fp, remaining, lDummyStr, lDicomData.Orient[1], lDicomData.Orient[2],lDicomData.Orient[3],lDicomData.Orient[4], lDicomData.Orient[5],lDicomData.Orient[6], lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; end; $50 : info := 'Location'; $52 : info := 'Frame of Reference UID'; $91 : info := 'Echo Train Length'; $70 : info := 'Image Geometry Type'; $60 : info := 'Laterality'; $0105 : begin //Apr2007 DICOMHeaderStringToInt(lnVol); //Number of temporal positions=105 end; $1001: info := 'Acquisitions in Series'; $1002: info := 'Images in Acquisition'; $1020: info := 'Reference'; $1040: begin info := 'Position Reference'; t := _string; end; $1041: begin info := 'Slice Location'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; ldicomdata.location:=lfloat1; end; $1070: begin info := 'Other Study Numbers'; t := _string; end; $3401: info := 'Modifying Device ID'; $3402: info := 'Modified Image ID'; $3403: info := 'Modified Image Date'; $3404: info := 'Modifying Device Mfg.'; $3405: info := 'Modified Image Time'; $3406: info := 'Modified Image Desc.'; $4000: info := 'Image Comments'; $5000: info := 'Original Image ID'; $5002: info := 'Original Image... Nomenclature'; //$9113: xxxx end; $0021:case element of $104F: begin info :='GE Locations in acquisition'; if lPrefs.UseGE_0021_104F then begin //June 2009 - Thomas Stephan sent me a GE image where this was set to 2, but should have been 1 //I hope removing this does not cause problems with other GE images... if e_len = 2 then begin lDicomData.SlicesPer3DVol := read16(fp,lrOK); e_len := 0; remaining := 0; /// fx(9999, lDicomData.SlicesPer3DVol); end; end; //use 0021_104F end; $1341: begin info :='Siemens Mosaic Slice Count'; DICOMHeaderStringToInt(lDicomData.SiemensSlices); end; $134F: begin //1366 info :='Siemens Order of Slices'; t := _string; lDICOMdata.SiemensInterleaved := 0; //0=no,1=yes,2=undefined //look for "INTERLEAVED" lStr := ''; if dFilePos(fp) > (filesz-e_len) then goto 666; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for i := 0 to e_len-1 do if Char(buff[i]) in ['?','A'..'Z','a'..'z'] then lStr := lStr +upcase(Char(buff[i])); FreeMem( buff); if(lStr[1]= 'I') then lDICOMdata.SiemensInterleaved := 1; //0=no,1=yes,2=undefined e_len := 0; end; end; $0028 : begin case element of $00 : info := 'Image Presentation Group Length'; $02 : begin info := 'Samples Per Pixel'; tmp := read16(fp,lrOK); if not lrOK then goto 666; lDicomData.SamplesPerPixel :=tmp; if e_len > 255 then begin explicitVR := true; //kludge: switch between implicit and explicitVR end; tmpstr := inttostr(tmp); e_len := 0; remaining := 0; end; $04 : begin info := 'Photometric Interpretation'; TmpStr := ''; if dFilePos(fp) > (filesz-e_len) then goto 666; GetMem( buff, e_len); dBlockRead(fp, buff{^}, e_len, n); for i := 0 to e_len-1 do if Char(buff[i]) in [{'+','-',' ', }'0'..'9','a'..'z','A'..'Z'] then TmpStr := TmpStr +(Char(buff[i])); FreeMem( buff); (*xif TmpStr = 'MONOCHROME1' then lDicomdata.monochrome := 1 else if TmpStr = 'MONOCHROME2' then lDicomdata.monochrome := 2 else if (length(TMpStr)> 0) and (TmpStr[1] = 'Y') then lDICOMdata.monochrome := 4 else lDICOMdata.monochrome := 3; *) remaining := 0; e_len := 0; {use tempstr} end; $05 : info := 'Image Dimensions (ret)'; $06 : begin info := 'Planar Configuration'; tmp := read16(fp,lrOK); if not lrOK then goto 666; lDicomData.PlanarConfig :=tmp; remaining := 0; end; $08 : begin //if lPapyrusnSlices < 1 then // if remaining = 2 then begin // tmp := read16(fp,lrOK); // // end else xx DICOMHeaderStringToInt(lDicomData.XYZdim[3]); if lDicomData.XYZdim[3] < 1 then lDicomData.XYZdim[3] := 1; info := 'Number of Frames'; end; $09: begin info := 'Frame Increment Pointer'; TmpStr := ReadStrHex(fp, remaining,lrOK); if not lrOK then goto 666; e_len := 0; remaining := 0; end; $10 : begin info := 'Rows'; lDicomData.XYZdim[2] := read16(fp,lrOK); if not lrOK then goto 666; tmp := lDicomData.XYZdim[2]; remaining := 0; end; $11 : begin info := 'Columns'; lDicomData.XYZdim[1] := read16(fp,lrOK); if not lrOK then goto 666; tmp := lDicomData.XYZdim[1]; remaining := 0; end; $30 : begin info := 'Pixel Spacing'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; //qq //row spacing [y], then column spacing [x]: see part 3 of DICOM e_len := 0; remaining := 0; lDICOMdata.XYZmm[2] := lfloat1; lDICOMdata.XYZmm[1] := lfloat2; end; $31: info := 'Zoom Factor'; $32: info := 'Zoom Center'; $34: begin info :='Pixel Aspect Ratio';t := _string; end; $40: info := 'Image Format [ret]'; $50 : info := 'Manipulated Image [ret]'; $51: info := 'Corrected Image'; $60: begin info := 'Compression Code [ret]';t := _string; end; $100: begin info := 'Bits Allocated'; if remaining = 4 then tmp := read32(fp,lrOK) else tmp := read16(fp,lrOK); //lWord := read16(fp,lrOK); //lWord := read16(fp,lrOK); if not lrOK then goto 666; if tmp = 8 then lDicomData.Allocbits_per_pixel := 8 else if tmp = 12 then lDicomData.Allocbits_per_pixel := 12 else if tmp = 16 then lDicomData.Allocbits_per_pixel := 16 else if tmp = 32 then lDicomData.Allocbits_per_pixel := 32 else if tmp = 24 then begin //xlDicomData.SamplesPerPixel := 3; lDicomData.Allocbits_per_pixel := 8 end else begin lWord := tmp; lWord := swap(lWord); if lWord in [8,12,16,24,32] then begin lDicomData.Allocbits_per_pixel := tmp; lByteSwap := true; end else begin if lImageFormatOK then Msg('This software only reads 8, 12, 16, 24 [RGB] and 32 bit DICOM files. This file allocates '+inttostr(tmp)+' bits per voxel.'); lImageFormatOK := false; end; end; //remaining := 2;//remaining; //1371-> remaining := 0 end; $0101: begin info := 'Bits Stored'; if remaining = 4 then tmp := read32(fp,lrOK) else tmp := read16(fp,lrOK); if not lrOK then goto 666; (*if tmp <= 8 then lDicomData.Storedbits_per_pixel := 8 else if tmp <= 16 then lDicomData.Storedbits_per_pixel := 16 else if tmp <= 24 then begin lDicomData.Storedbits_per_pixel := 24; lDicomData.SamplesPerPixel := 3; end else begin lWord := tmp; lWord := swap(lWord); if lWord in [8,12,16] then begin lDicomData.Storedbits_per_pixel := tmp; lByteSwap := true; end else begin if lImageFormatOK then Msg('This software can only read 8, 12 and 16 bit DICOM files. This file stores '+inttostr(tmp)+' bits per voxel.'); lDicomData.Storedbits_per_pixel := tmp; lImageFormatOK := false;{ } end; end;*) remaining := 0; end; $0102: begin info := 'High Bit'; if remaining = 4 then tmp := read32(fp,lrOK) else tmp := read16(fp,lrOK); if not lrOK then goto 666; remaining := 0; end; $0103: begin info := 'Pixel Representation'; if remaining = 2 then begin tmp := read16(fp,lrOK); //1= signed, 0=unsigned... if tmp = 1 then lDicomData.SignedData := true; if tmp = 0 then lDicomData.SignedData := false; remaining := 0; end; end; $0104: info := 'Smallest Valid Pixel Value'; $0105: info := 'Largest Valid Pixel Value'; $0106: begin //xlDicomData.MinIntensitySet:= true; info := 'Smallest Image Pixel Value'; tmp := read16(fp,lrOK); if not lrOK then goto 666; //xlDicomData.Minintensity := tmp; //if >32767 then there will be wrap around if read as signed value! remaining := 0; end; $0107: begin info := 'Largest Image Pixel Value'; if remaining = 4 then tmp := read32(fp,lrOK) else tmp := read16(fp,lrOK); if not lrOK then goto 666; //xlDicomData.Maxintensity := tmp; //if >32767 then there will be wrap around if read as signed value! remaining := 0; end; $120: info := 'Pixel Padding Value'; $200: info := 'Image Location [ret]'; $1040: begin t := _string; info := 'Pixel Intensity Relationship'; end; $1050: begin info := 'Window Center'; if e_len > 0 then begin readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; //xlDICOMdata.WindowCenter := round(lfloat1); end; end;{float} $1051: begin info := 'Window Width'; if e_len > 0 then begin readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; //xlDICOMdata.WindowWidth := round(lfloat1); end; //ignore empty elements, e.g. LeadTech's image6.dic end; $1052: begin t := _string;info :='Rescale Intercept'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDICOMdata.intenIntercept := lfloat1; //if (lDICOMdata.nOrder > 0) and (lDICOMdata.nOrder < kMaxOrderVal) then // lDICOMdata.OrderIntercept[lDICOMdata.nOrder] := lfloat1; end; {float} $1053:begin t := _string; info := 'Rescale Slope'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; if lFloat1 < 0.000000001 then begin lFLoat1 := 1; //misused in some images, see IMG000025 end; lDICOMdata.intenScale := lfloat1; //if (lDICOMdata.nOrder > 0) and (lDICOMdata.nOrder < kMaxOrderVal) then // lDICOMdata.OrderSlope[lDICOMdata.nOrder] := lfloat1; end; {float} $1054:begin t := _string; info := 'Rescale Type';end; $1100: info := 'Gray Lookup Table [ret]'; $1101: begin info := 'Red Palette Descriptor'; TmpStr := ReadStr(fp, remaining,lrOK,lJunk); if not lrOK then goto 666; e_len := 0; remaining := 0; end; $1102: begin info := 'Green Palette Descriptor'; TmpStr := ReadStr(fp, remaining,lrOK,lJunk); if not lrOK then goto 666; e_len := 0; remaining := 0; end; $1103: begin info := 'Blue Palette Descriptor'; TmpStr := ReadStr(fp, remaining,lrOK,lJunk); if not lrOK then goto 666; e_len := 0; remaining := 0; end; $1199: begin info := 'Palette Color Lookup Table UID'; end; $1200: info := 'Gray Lookup Data [ret]'; $1201, $1202,$1203: begin case element of $1201: info := 'Red Table'; {future} $1202: info := 'Green Table'; {future} $1203: info := 'Blue Table'; {future} end; if dFilePos(fp) > (filesz-remaining) then goto 666; if not lReadColorTables then begin dSeek(fp, dFilePos(fp) + remaining); end else begin {load color} width := remaining div 2; if width > 0 then begin getmem(lWordRA,width*2); for i := (width) downto 1 do lWordRA^[i] := read16(fp,lrOK); //value := 159; value := lWordRA^[1]; max16 := value; min16 := value; for i := (width) downto 1 do begin value := lWordRA^[i]; if value < min16 then min16 := value; if value > max16 then max16 := value; end; //width..1 if max16 - min16 = 0 then max16 := min16+1; {avoid divide by 0} if (lDicomData.Allocbits_per_pixel <= 8) and (width > 256) then width := 256; //currently only accepts palettes up to 8-bits GetMem( lColorRA, width );(**) for i := width downto 1 do lColorRA^[i] := (lWordRA^[i] shr 8) {and 255}; FreeMem( lWordRA ); case element of $1201: begin red_table_size := width; red_table :=lColorRA;; end; $1202: begin green_table_size := width; green_table :=lColorRA;; end; else {x$1203:} begin blue_table_size := width; blue_table :=lColorRA;; end; {else} end; {case} end; //width > 0; if odd(remaining) then dSeek(fp, dFilePos(fp) + 1{remaining}); end; {load color} tmpstr := 'Custom'; remaining := 0; e_len := 0; {show tempstr} end; $1221, $1222,$1223: begin info := 'Color Palette ['+inttostr(dFilePos(fp))+']'; (*xcase element of $1221: begin lDicomData.RLEredOffset:= dFilePos(fp); lDicomData.RLEredSz:= e_len; end; $1222: begin lDicomData.RLEgreenOffset:= dFilePos(fp); lDicomData.RLEgreenSz:= e_len; end; $1223: begin lDicomData.RLEblueOffset:= dFilePos(fp); lDicomData.RLEblueSz:= e_len; end; end;*)//Case set offset and length tmpstr := inttostr(e_len); dSeek(fp, dFilePos(fp)+ e_LEN); e_len := 0; end; $3002: info := 'LUT Descriptor'; $3003: info := 'LUT Explanation'; $3006: info := 'LUT Data'; $3010: begin info := 'VOI LUT Sequence'; if (explicitVR) and (lT0=kS) and (lT1=kQ) then e_len := 8; end; end; //case end; //$0028 $41: case element of //Papyrus Private Group $1010: begin info := 'Papyrus Icon [bytes skipped]'; dSeek(fp, dFilePos(fp) + e_len); tmpstr := inttostr(e_len); remaining := 0; e_len := 0; end; //element $0041:$1010 $1015: begin info := 'Papyrus Slices'; (*Papyrus format is buggy - see lsjpeg.pas for details, therefore, I have removed extensive support if e_len = 2 then begin lDicomData.XYZdim[3] := read16(fp,lrOK); if not lrOK then goto 666; end; if lDicomData.XYZdim[3] < 1 then lDicomData.XYZdim[3] := 1; if {(false) and }(lDicomData.XYZdim[3] > 1) and (lReadJPEGtables) and (gECATJPEG_table_entries = 0) then begin //Papyrus multislice files keep separate DICOM headers for each slice within a DICOM file lPapyrusnSlices := lDicomData.XYZdim[3]; lPapyrusSlice := 0; //lPapyrusData := lDicomData; gECATJPEG_table_entries := lDICOMdata.XYZDim[3]; getmem (gECATJPEG_pos_table, gECATJPEG_table_entries*sizeof(longint)); getmem (gECATJPEG_size_table, gECATJPEG_table_entries*sizeof(longint)); end else lDicomData.XYZdim[3] := 1; tmpstr := inttostr(lDicomData.XYZdim[3]); remaining := 0; e_len := 0;*) end; //element $0041:$1015 $1050: begin info := 'Papyrus Bizarre Element'; //bizarre osiris problem if (dfilepos(fp)+e_len)= (filesz) then e_len := 8; end; //element $0041:$1050 end; //group $0041: Papyrus $43: begin if lDicomData.ManufacturerID = kGEID then begin case element of $1039,$A039: begin // 0043,1039 (or 0043,a039). b value (as the first number in the string). info := 'GE Bvalue'; if e_len > 0 then begin readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lDICOMdata.DTI[1].bval := round(lfloat1); lDICOMdata.nDTIdir := 1; end; //e_len>0 end;//1039 or Ao39 end;//Case end; //Manufacturer = GE end;//$0043 - GE bvalues $54: case element of $0: info := 'Nuclear Acquisition Group Length'; $11: info := 'Number of Energy Windows'; $21: info := 'Number of Detectors'; $51: info := 'Number of Rotations'; $80: begin info := 'Slice Vector'; TmpStr := ReadStr(fp, remaining,lrOK,lJunk); if not lrOK then goto 666; e_len := 0; remaining := 0; end; $81: info := 'Number of Slices'; $202: info := 'Type of Detector Motion'; $400: info := 'Image ID'; end; $2010 : case element of $0: info := 'Film Box Group Length'; $100: info := 'Border Density'; end; $4000 : info := 'Text'; $0029 : begin case element of $1010: begin //lSiemensMosaic0029_1010:= true; if (lDicomData.kV = 0) then begin //Siemens uses 0029:1010 for both CT and MRI, but only MRI is in CSA format lDicomData.CSAImageHeaderInfoPos := (dFilePos(fp)); lDicomData.CSAImageHeaderInfoSz := e_len; end; info := 'Private Sequence Delimiter ['+inttostr(dFilePos(fp))+']'; if not lImageFormatOK then time_to_quit := TRUE; //x(lDicomData.RunLengthEncoding) or ( ((lDicomData.JPEGLossycpt) or (lDicomData.JPEGLosslesscpt)) and (gECATJPEG_table_entries >= lDICOMdata.XYZdim[3]))} dSeek(fp, dFilePos(fp) + e_len); tmpstr := inttostr(e_len); remaining := 0; e_len := 0; {show tempstr} end; $1053: begin info :='Philips Scale Slope'; readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK); if not lrOK then goto 666; e_len := 0; remaining := 0; lPhilipsScaleSlope := lfloat1; {if e_len = 4 then begin lPhilipsScaleSlope := read32r(fp,lrOK); TmpStr := floattostr(lPhilipsScaleSlope); t := _string; if not lrOK then goto 666; e_len := 0; remaining := 0; end; } end; else begin end; END; END; //gROUP 0029 (* $0045 : begin case element of $103B: begin msg('0045:103B'); end; //element $1010 end; //CASE...element end; //group 0045 *) $0089 : begin case element of $1010: begin e_len := 0; lProprietaryImageThumbnail := true; //lImageFormatOK := false; end; //element $1010 $1020: begin //thoravision files if e_len > 12 then e_len := 0; //lProprietaryImageThumbnail := true; //lImageFormatOK := false; end; //element $1010 end; //CASE...element end; //group 0089 $2001 : begin if lDicomData.ManufacturerID = kPhilipsID then begin case element of $1003: begin //bvalue if e_len = 4 then begin if lDICOMdata.nDTIdir < kMaxDTIdir then inc(lDICOMdata.nDTIdir); lDICOMdata.DTI[lDICOMdata.nDTIdir].bval := round(read32r(fp,lrOK)); TmpStr := inttostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].bval); t := _string; info :='DTI b-val'; if not lrOK then goto 666; e_len := 0; remaining := 0; end; //e_len = 4 end; //element 1003 $100B: begin info := 'philips: slice orientation';t := _string; TmpStr := ''; DICOMHeaderString(TmpStr); lDicomData.PhilipsSliceOrient := TmpStr; AplhaNumericStrDICOM (lDicomData.PhilipsSliceOrient); end;//PhilipsSliceOrient $1018: begin if e_len = 4 then begin info :='number of slices'; lDicomData.SlicesPer3DVol := read32(fp,lrOK); //uninterleave data e_len := 0; remaining := 0; if lResearchMode then lDicomData.SeriesNum := lDicomData.SeriesNum + 50; //do not jumble research recons and normal images end; //e_len = 4 TmpStr := floattostr(lDicomData.SlicesPer3DVol); end; //1018 $102D: begin ///Apr2007 if e_len = 2 then begin lnSlicePerVol := read16(fp,lrOK); e_len := 0; remaining := 0; end; //fx(213,lnSlicePerVol); end; //102D $105F: begin //Philips Stack Sequence if e_len > 8 then e_len := 8; end; //105F end; end; //if manufacturer = Philips end; //2001,1004) $2005 : begin //if lDicomData.ManufacturerID = kPhilipsID then Msg(inttohex(element,4)); if lDicomData.ManufacturerID = kPhilipsID then begin case element of (* $140F: begin lInside2005140F := true; end;*) $100E: begin if e_len = 4 then begin lPhilipsScaleSlope := read32r(fp,lrOK); TmpStr := floattostr(lPhilipsScaleSlope); t := _string; info :='Philips Scale Slope'; if not lrOK then goto 666; e_len := 0; remaining := 0; end; end; //element $1010 $1071: begin if e_len = 4 then begin lDicomData.AngulationAP := read32r(fp,lrOK); TmpStr := floattostr(lDicomData.AngulationAP); t := _string; info :='angulation midslice, AP (degrees)'; if not lrOK then goto 666; e_len := 0; remaining := 0; end; end; // Philips AP angulation : -8.74086 $1072: begin if e_len = 4 then begin lDicomData.AngulationFH := read32r(fp,lrOK); TmpStr := floattostr(lDicomData.AngulationFH); t := _string; info :='angulation midslice, FH (degrees)'; if not lrOK then goto 666; e_len := 0; remaining := 0; end; end; // Philips Philips FH angulation : -3.53147 $1073: begin if e_len = 4 then begin lDicomData.AngulationRL := read32r(fp,lrOK); TmpStr := floattostr(lDicomData.AngulationRL); t := _string; info :='angulation midslice, RL (degrees)'; if not lrOK then goto 666; e_len := 0; remaining := 0; end; end; // Philips RL angulation $10b0: begin if e_len = 4 then begin //msg('2005,10b0 @ '+ inttostr(dFilePos(fp)) +' #'+inttostr(lDICOMdata.nDTIdir)); lDICOMdata.DTI[lDICOMdata.nDTIdir].v1 := read32r(fp,lrOK); TmpStr := floattostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].v1); t := _string; info :='Philips Gradient vector [x]'; if not lrOK then goto 666; e_len := 0; remaining := 0; end; //e_len = 4 end; //element 10b0 $10b1: begin if e_len = 4 then begin lDICOMdata.DTI[lDICOMdata.nDTIdir].v2 := read32r(fp,lrOK); TmpStr := floattostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].v2); t := _string; info :='Philips Gradient vector [y]'; if not lrOK then goto 666; e_len := 0; remaining := 0; end; //e_len = 4 end; //element 10b1 $10b2: begin if e_len = 4 then begin lDICOMdata.DTI[lDICOMdata.nDTIdir].v3 := read32r(fp,lrOK); TmpStr := floattostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].v3); t := _string; info :='Philips Gradient vector [z]'; //fx(lDICOMdata.DTI[lDICOMdata.nDTIdir].v1,lDICOMdata.DTI[lDICOMdata.nDTIdir].v2,lDICOMdata.DTI[lDICOMdata.nDTIdir].v3); if not lrOK then goto 666; e_len := 0; remaining := 0; end; //e_len = 4 end; //element 10b2 $140f: begin //msg('2005:140F@ '+inttostr(dFilePos(fp)) +' len: '+inttostr(e_len) +' '+ chr(lT0)+chr(lT1)); if (e_len > 8) then begin e_len := 8; remaining := e_len; //qas 7/2013 end; end;//140f $1455: begin //msg('2005:1455@ '+inttostr(dFilePos(fp)) +' len: '+inttostr(e_len) +' '+ chr(lT0)+chr(lT1)); (*if (e_len > 8) then begin e_len := 8; remaining := e_len; //qas 7/2013 end; *) end;//1455 end; //CASE...element end; //if Manufacturer = Philips end; //group 2005 $5200 : begin case element of $9230: begin //msg('5200:9230@ '+inttostr(dFilePos(fp))+' e_len '+inttostr(e_len)+' remaining '+inttostr(remaining)); //lverboseRead := true; //qas //fx(e_len,678xx9); if (e_len > 8) then begin e_len := 8; remaining := e_len; //qas 7/2013 end; (* if (lDicomData.ManufacturerID = kPhilipsID) and (orientation_not_visible( lDICOMdata))then read_philips_hidden(lFilename, dFilePos(fp),e_len,lDICOMdata);*) end //element 9230 end; //case element end; //group 5200 $5400 : begin case element of $0100: begin //can not convert sound files to images 12/2012 lImageFormatOK := false; msg('Note: the DICOM file '+lFileName+' stores a waveform sequence (e.g. ECG) that will not be converted to an image'); info :='WaveformSequence'; //fx(lDICOMdata.DTI[lDICOMdata.nDTIdir].v1,lDICOMdata.DTI[lDICOMdata.nDTIdir].v2,lDICOMdata.DTI[lDICOMdata.nDTIdir].v3); if not lrOK then goto 666; e_len := 0; remaining := 0; end //element 0100 end; //case element end; //group 5400 $DDFF : begin case element of $00E0: begin //For papyrus multislice format: if (lPapyrusSlice >= lPapyrusnSlices) then time_to_quit := TRUE; end; end; end; $FFFE : begin case element of $E000 : begin //if (lIndent > 3) then lverboseRead := false; //qas inc(lIndent); //msg('FFFE:E000@ '+inttostr(dFilePos(fp)) +' len: '+inttostr(e_len) +' '+ chr(lT0)+chr(lT1)); e_len := 0; remaining := e_len; //qas 7/2013 lInside00209113 := (lprevGroup = $0020) and (lprevelement = $9113); lInside2005140F := (lprevGroup = $2005) and (lprevelement = $140F); // if (lInside00209113) then fx(333); (*iif lJPEGEntries > 17 then lTestError := true; if not lProprietaryImageThumbnail then begin f (lReadJPEGtables) and ((lDICOMdata.RunLengthEncoding) or (lDICOMdata.JPEGLossyCpt) or (lDICOMdata.JPEGLosslessCpt)) and (not lFirstFragment) and (e_len > 1024) {1384} and ( (e_len+dFilePos(fp)) <= FileSz) then begin //first fragment is the index table, so the previous line skips the first fragment if (gECATJPEG_table_entries = 0) then begin gECATJPEG_table_entries := lDICOMdata.XYZDim[3]; getmem (gECATJPEG_pos_table, gECATJPEG_table_entries*sizeof(longint)); getmem (gECATJPEG_size_table, gECATJPEG_table_entries*sizeof(longint)); end; if lJPEGentries < gECATJPEG_table_entries then begin inc(lJPEGentries); gECATJPEG_pos_table^[lJPEGEntries] := dFilePos(fp); gECATJPEG_size_table^[lJPEGEntries] := e_len; end; end; if (lDICOMdata.CompressOffset =0) and ( (e_len+dFilePos(fp)) <= FileSz) and (e_len > 1024){ALOKA} then begin lDICOMdata.CompressOffset := dFilePos(fp); lDICOMdata.CompressSz := e_len; end; //if e_len > lDICOMdata.CompressSz then lDICOMdata.CompressSz := e_len; if (e_len > 1024) and (lDICOMdata.CompressSz=0) then begin //ABBA RLE ALOKA //Time_To_Quit := true;//ABBA lDICOMdata.CompressSz := e_len; lDICOMdata.CompressOffset := dFilePos(fp); end; if (lFirstFragment) or ((e_len > lDICOMdata.CompressSz) and not (lDicomData.RunLengthEncoding)) then lDICOMdata.CompressOffset := dFilePos(fp); if (e_len > lDICOMdata.CompressSz) and (e_len > 1024){ALOKA} then lDICOMdata.CompressSz := e_len; lFirstFragment := false; lDICOMdataBackUp := lDICOMData; if (gECATJPEG_table_entries = 1) then begin //updatex gECATJPEG_size_table^[1] := lDICOMdata.CompressSz; gECATJPEG_pos_table^[1] := lDICOMdata.CompressOffset; end; //updatex end; //not proprietaryThumbnail lProprietaryImageThumbnail := false; //1496 *) lFirstFragment := false;//Dec09 lDICOMdataBackUp := lDICOMData;//Dec09 if ((e_len > 1024) and ((lDicomData.JPEGLosslessCpt)) or (e_len >= (lDicomData.XYZdim[1]*lDicomData.XYZdim[2]))){Apr 2011} and (lDicomData.XYZdim[1]> 1) then begin lDICOMdata.CompressOffset := dFilePos(fp); lDICOMdata.CompressSz := e_len; Time_To_Quit := true; //msg('abba'+inttostr(lDICOMdata.CompressOffset)+' '+inttostr(lDICOMdata.CompressSz)); end; info := 'Image Fragment ['+inttostr(dFilePos(fp))+']'; if (dFilePos(fp) + e_len) >= filesz then Time_To_Quit := true; dSeek(fp, dFilePos(fp) + e_len); tmpstr := inttostr(e_len); remaining := 0; e_len := 0; end; $E0DD : begin if (lIndent > 0) then dec(lIndent); lInside00209113 := false; lInside2005140F := false; info := 'Sequence Delimiter'; if (lDICOMdata.XYZdim[1]= lDICOMdata.XYZdim[3])) then time_to_quit := TRUE; end; //RLE ABBA if (e_len = 0) then begin //ALOKA explicitVR := true; time_to_quit := FALSE;//RLE16=false end; //END dSeek(fp, dFilePos(fp) + e_len); tmpstr := inttostr(e_len); remaining := 0; e_len := 0; end; end; end; $FFFC : begin dSeek(fp, dFilePos(fp) + e_len); tmpstr := inttostr(e_len); remaining := 0; e_len := 0; end; $72FF : case element of $1041: time_to_quit := TRUE; end; //case 72FF $7FE0 : case element of $00 : begin info := 'Pixel Data Group Length'; if not lImageFormatOK then time_to_quit := TRUE; end; $10 : begin info := 'Pixel Data'; TmpStr := inttostr(e_len); //Showmsg(inttostr(ExpectedDicomBytes(lDicomData) ) +' '+ inttostr(e_len)); if ((ExpectedDicomBytes(lDicomData) ) > e_len) or (lDICOMdata.XYZdim[1]= $6000) AND (group <= $601e) AND ((group AND 1) = 0) then begin info := 'Overlay'+inttostr(dfilepos(fp))+'x'+inttostr(e_len); end; if element = $0000 then info := 'Group Length'; if element = $4000 then info := 'Comments'; end; end; lStr := ''; 1234: lprevGroup := Group; lprevElement := element; if (Time_TO_Quit) and (not lImageFormatOK) then begin lHdrOK := true; goto 666; end; //Msg(inttohex(group,4) +':'+inttohex(element,4) +' '+inttostr(e_len)+'@'+ inttostr(dfilepos(fp))); if (e_len + dfilepos(fp)) > FileSz then begin//patch for GE files that only fill top 16-bytes w Random data e_len := e_len and $FFFF; end; if (e_len > 131072) then begin //goto 666; end;//zebra if (NOT time_to_quit) AND (e_len > 0) and (remaining > 0) then begin if (e_len + dfilepos(fp)) > FileSz then begin if not lImageFormatOK(*x(lDICOMdata.GenesisCpt) or (lDICOMdata.JPEGlosslessCpt) or (lDICOMdata.JPEGlossyCpt)*) then lHdrOK := true else begin Msg('dcm Error: not a DICOM image: '+lFilename); {Msg('Diagnostics saved as: c:\dcmcrash.txt'); //diagnostics assignfile(lTextF,'c:\dcmcrash.txt'); Filemode := 0; rewrite(lTextF); Write(lTextF,lDynStr); closefile(lTextF); } //Msg(inttohex(group,4) +':'+inttohex(element,4) +' '+inttostr(e_len)+'@'+ inttostr(dfilepos(fp))); end; goto 666; end; if e_len > 0 then begin GetMem( buff, e_len); dBlockRead(fp, buff, e_len, n); if lVerboseRead then case t of unknown : case e_len of 1 : lStr := ( IntToStr(Integer(buff[0]))); 2 : Begin if lDicomData.little_endian <> 0 then i := Integer(buff[0]) + 256*Integer(buff[1]) else i := Integer(buff[0])*256 + Integer(buff[1]); lStr :=( IntToStr(i)); end; 4 : Begin if lDicomData.little_endian <> 0 then i := Integer(buff[0]) + 256*Integer(buff[1]) + 256*256*Integer(buff[2]) + 256*256*256*Integer(buff[3]) else i := Integer(buff[0])*256*256*256 + Integer(buff[1])*256*256 + Integer(buff[2])*256 + Integer(buff[3]); lStr := (IntToStr(i)); end; else begin if e_len > 0 then begin for i := 0 to e_len-1 do begin if Char(buff[i]) in ['+','-','/','\',' ', '0'..'9','a'..'z','A'..'Z'] then lStr := lStr+(Char(buff[i])) else lStr := lStr+('.'); end; end else lStr := '*NO DATA*'; end; end; i8, i16, i32, ui8, ui16, ui32, _string : for i := 0 to e_len-1 do if Char(buff[i]) in ['+','-','/','\',' ', '0'..'9','a'..'z','A'..'Z'] then lStr := lStr +(Char(buff[i])) else lStr := lStr +('.'); end; FreeMem(buff); end; end else if e_len > 0 then lStr := (IntToStr(tmp)) else begin lStr := TmpStr; end; (*if (lGrp) then if MessageDlg(lStr+'= '+info+' '+IntToHex(where,4)+': ('+IntToHex(group,4)+','+IntToHex(element,4)+')'+IntToStr(e_len)+'. Continue?', mtConfirmation, [mbYes, mbNo], 0) = mrNo then GOTO 666; *) //if (Group > $2005) then // msg(info+' '+IntToStr(where)+': ('+IntToHex(group,4)+','+IntToHex(element,4)+')'+IntToStr(e_len)); {$IFDEF Troubleshoot} Msg( IntToHex(group,4)+','+IntToHex(element,4)+','+Info+'='+lStr);//+' Offset'+inttostr(dfilepos(fp))+' Length'+inttostr(e_len)); {$ENDIF Troubleshoot} if lverboseRead then begin if length(lDynStr) > kMaxTextBuf then begin if not lTextOverFlow then begin lDynStr := lDynStr + 'Only showing the first '+inttostr(kMaxTextBuf) +' characters of this LARGE header'; lTextOverFlow := true; end; //goto 666; end else lDynStr := lDynStr+IntToHex(group,4)+','+IntToHex(element,4)+','+Info+'='+lStr+kCR ; Msg(AddIndent(lIndent)+IntToHex(group,4)+','+IntToHex(element,4)+','+inttostr(e_len)+'@'+inttostr(dfilepos(fp))+','+Info+'='+lStr); end; //not verbose read end; // end for lDicomData.ImageStart := dfilepos(fp); if lBigSet then begin if lBig then lDicomData.little_endian := 0 else lDicomData.little_endian := 1; end; lHdrOK := true; if lByteSwap then begin ByteSwap(lDicomdata.XYZdim[1]); ByteSwap(lDicomdata.XYZdim[2]); if lDicomdata.XYZdim[3] <> 1 then ByteSwap(lDicomdata.XYZdim[3]); //xByteSwap(lDicomdata.SamplesPerPixel); ByteSwap(lDicomData.Allocbits_per_pixel); //xByteSwap(lDicomData.Storedbits_per_pixel); end; if (lDICOMdata.ManufacturerID = kPhilipsID) and (l4DDistanceBetweenSliceCenters <> kNaNsingle) then //some 3D and 4D Philips files do not correctly report interslice distance in 0018,0088 and 0018,0050... lDICOMdata.XYZmm[3] := (l4DDistanceBetweenSliceCenters); if (lPrefs.PhilipsPrecise) and (lManufacturerIsPhilips) and (lPhilipsScaleSlope <> 0) then begin PhilipsPrecise (lDicomData.IntenScale, lDICOMdata.intenIntercept,lPhilipsScaleSlope, lDicomData.IntenScale, lDICOMdata.intenIntercept,true); end; //if PARprecise if (lDICOMdata.ManufacturerID = kPhilipsID) and (lDICOMdata.nDTIdir > 1) then begin lGELX := true; for i := 1 to lDICOMdata.nDTIdir do if lDICOMdata.DTI[lDICOMdata.nDTIdir].bval <> lDICOMdata.DTI[1].bval then lGELX := false;//multiple B0 directions if lGELX then lDICOMdata.nDTIdir := 1; lGELX := false; end; if (lMatrixSz > 1) and (lDicomData.CSAImageHeaderInfoPos > 0) and (lDicomData.CSAImageHeaderInfoSz > 0) and not (((lDicomdata.XYZdim[1] mod lMatrixSz) = 0) and ((lDicomdata.XYZdim[2] mod lMatrixSz) = 0)) then begin //Slow method for non-square Siemens matrices - 0018:1310 based on phase/freq, so it is easier to read CSA to decode rows/columns GetCSAImageHeaderInfo (lFilename, lDicomData.CSAImageHeaderInfoPos ,lDicomData.CSAImageHeaderInfoSz, lTempInt,lDICOMdata.SiemensMosaicX,lDICOMdata.SiemensMosaicY, lfloat1,lfloat2,lfloat3) end else if (lMatrixSz > 1) and ((lDicomdata.XYZdim[1] mod lMatrixSz) = 0) and ((lDicomdata.XYZdim[2] mod lMatrixSz) = 0) then begin if ((lDicomData.XYZdim[1] mod lMatrixSz)=0) then lDicomData.SiemensMosaicX := lDicomData.XYZdim[1] div lMatrixSz; if ((lDicomData.XYZdim[2] mod lMatrixSz)=0) then lDicomData.SiemensMosaicY := lDicomData.XYZdim[2] div lMatrixSz; if lDicomData.SiemensMosaicX < 1 then lDicomData.SiemensMosaicX := 1; //1366 if lDicomData.SiemensMosaicY < 1 then lDicomData.SiemensMosaicY := 1; //1366 if lOldSiemens_IncorrectMosaicMM then begin //old formats convert size in mm incorrectly - modern versions are correct and include transfer syntax lDicomdata.XYZmm[1] := lDicomdata.XYZmm[1] * (lDicomdata.XYZdim[1] div lMatrixSz); lDicomdata.XYZmm[2] := lDicomdata.XYZmm[2] * (lDicomdata.XYZdim[2] div lMatrixSz); end; end else if (lSiemensMosaic0008_0008) and (lPhaseEncodingSteps > 0) and (lPhaseEncodingSteps < lDicomdata.XYZdim[2]) and ((lDicomdata.XYZdim[2] mod lPhaseEncodingSteps) = 0) and ((lDicomdata.XYZdim[2] mod (lDicomdata.XYZdim[2] div lPhaseEncodingSteps)) = 0) then begin //1499c kludge for detecting new Siemens mosaics: WARNING may cause false positives - Siemens fault not mine! lDicomData.SiemensMosaicY :=lDicomdata.XYZdim[2] div lPhaseEncodingSteps; lDicomData.SiemensMosaicX := lDicomData.SiemensMosaicY; //We also need to assume as many mosaic rows as columns, as Siemens does not save the phase encoding lines in the header... end; // fx(lnSlicePerVol,lnVol, lDicomData.SlicesPer3DVol,lDicomdata.XYZdim[3] ); //fx(lnVol,lnSlicePerVol,lDicomData.SlicesPer3DVol,lDicomdata.XYZdim[3]); //fx(lnSlicePerVol,lDicomData.ManufacturerID,kPhilipsID ); if (lnSlicePerVol > 0) and (lDicomData.ManufacturerID = kPhilipsID) {and (lnVol > 1)} and (lDicomdata.XYZdim[3] > 1) and (lDicomData.SlicesPer3DVol > 0)and ((lDicomdata.XYZdim[3] mod lDicomData.SlicesPer3DVol) = 0) then begin lDICOMdata.File4D := true; lnVol := lDicomdata.XYZdim[3] div lDicomData.SlicesPer3DVol; end; if lManufacturerIsBruker then lDicomData.AcquNum := 1; //Bruker varies this for every image if (lEchoNum > 0) and (lEchoNum < 16) then begin lDicomData.AcquNum := lDicomData.AcquNum + (1000*lEchoNum); end; if lVerboseRead then begin // lDicomData.PatientPosX, lDicomData.PatientPosY,lDicomData.PatientPosZ Msg ('DICOM data'); Msg ('Series/Acquisition/Image/Xpos/YPos/ZPos:'+kTab+inttostr(lDicomData.SeriesNum)+kTab+inttostr(lDicomData.AcquNum)+kTab+inttostr(lDicomData.ImageNum)+kTab+floattostr(lDicomData.PatientPosX)+kTab+floattostr(lDicomData.PatientPosY)+kTab+floattostr(lDicomData.PatientPosZ)); Msg ('BPP: '+inttostr(lDicomData.Allocbits_per_pixel)); Msg ('XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/'+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) ); Msg ('XYZ mm:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2) ); Msg ('DTI bvalue:'+ inttostr(lDICOMdata.DTI[1].bval)); Msg ('DTI bvec:'+floattostrf(lDicomData.DTI[1].v1,ffFixed,8,2)+'/'+floattostrf(lDicomData.DTI[1].v2,ffFixed,8,2)+'/'+floattostrf(lDicomData.DTI[1].v3,ffFixed,8,2) ); end; //msg('abba'+inttostr(lDICOMdata.CompressOffset)+' '+inttostr(lDICOMdata.CompressSz)); 666: //if not lHdrOk then Msg('zx'+lFilename); if lDiskCacheSz > 0 then freemem(lDiskCacheRA); if not lHdrOK then lImageFormatOK := false; CloseFile(fp); FileMode := 2; //set to read/write //if kUseDateTimeForID then lDicomData.DateTime := StudyDateTime(lDicomData.StudyDate,lDicomData.StudyTime); if (lDicomData.SiemensMosaicX > 1) then lDicomData.AcquNum := 1; end; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/pref_form.pas0000755000175000017500000001451012360762266020227 0ustar mihmihunit pref_form; interface uses {$IFDEF FPC}LResources,{$ENDIF} {$IFDEF UNIX}Process, {$ELSE}ShellApi, Windows,{$ENDIF} //Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,filename,define_types,dicomtypes,prefs, Spin, Buttons; type {$H+} { TPrefsForm } TPrefsForm = class(TForm) // TxtReportCheck: TCheckBox; // WritePrefsOnQuit: TCheckBox; // TextEditorBtn: TButton; Stack3DImagesWithSameAcqNum: TCheckBox; OutputCombo: TComboBox; FilenameBox: TGroupBox; DateCheck: TCheckBox; OutDirLabel: TLabel; CollapseCheck: TCheckBox; SeriesCheck: TCheckBox; ProtocolCheck: TCheckBox; PatientNameCheck: TCheckBox; InputNameCheck: TCheckBox; NotAnonymizeCheck: TCheckBox; ReorientCheck: TCheckBox; OKBtn: TButton; CancelBtn: TButton; RecursiveSpin: TSpinEdit; Label1: TLabel; TextEditorBtn: TButton; WritePrefsOnQuit: TCheckBox; TxtReportCheck: TCheckBox; //Stack3DImagesWithSameAcqNum: TCheckBox; //CollapseCheck: TCheckBox; procedure FilenameChecks(Sender: TObject); procedure OutputComboMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure ReadPrefs(var lPrefs: TPrefs); procedure TextEditorBtnClick(Sender: TObject); procedure WritePrefs(var lPrefs: TPrefs); procedure SetOutDirLabel; procedure OutputComboChange(Sender: TObject); procedure SetOutput; private { Private declarations } public { Public declarations } end; var PrefsForm: TPrefsForm; implementation {$IFNDEF FPC} {$R *.DFM} {$ENDIF} uses gui,userdir; var gPrefs: TPrefs; procedure TPrefsForm.SetOutDirLabel; begin OutDirLabel.visible := (OutputCombo.ItemIndex = kOutDirModeOutDir); end; procedure TPrefsForm.WritePrefs(var lPrefs: TPrefs); begin gPrefs := lPrefs; Stack3DImagesWithSameAcqNum.Checked := lPrefs.Stack3DImagesWithSameAcqNum; DateCheck.Checked := lPrefs.AppendDate; SeriesCheck.Checked := lPrefs.AppendAcqSeries; ProtocolCheck.Checked := lPrefs.AppendProtocolName; PatientNameCheck.Checked := lPrefs.AppendPatientName; InputNameCheck.checked := lPrefs.AppendFilename; CollapseCheck.checked := lPrefs.CollapseFolders; ReorientCheck.Checked := (lPrefs.MinReorientMatrix < 32000); NotAnonymizeCheck.Checked := not lPrefs.Anonymize; TxtReportCheck.Checked := lPrefs.TxtReport; RecursiveSpin.Value := lPrefs.RecursiveFolderDepth; OutDirLabel.Caption := lPrefs.OutDir; if (lPrefs.OutDirMode < 0) or (lPrefs.OutDirMode >= OutputCombo.Items.count) then lPrefs.OutDirMode := 0; OutputCombo.ItemIndex := lPrefs.OutDirMode; SetOutDirLabel; end; procedure TPrefsForm.ReadPrefs(var lPrefs: TPrefs); begin lPrefs := gPrefs; lPrefs.Stack3DImagesWithSameAcqNum := Stack3DImagesWithSameAcqNum.checked; lPrefs.AppendDate := DateCheck.Checked; lPrefs.AppendAcqSeries := SeriesCheck.Checked; lPrefs.AppendProtocolName := ProtocolCheck.Checked; lPrefs.AppendPatientName := PatientNameCheck.Checked; lPrefs.AppendFilename := InputNameCheck.checked; //lPrefs.SaveToBaseFolder := SaveToBaseFolderCheck.Checked; lPrefs.CollapseFolders := CollapseCheck.checked; if ReorientCheck.Checked then begin if lPrefs.MinReorientMatrix = MaxInt then lPrefs.MinReorientMatrix := kMinReorientMatrix end else lPrefs.MinReorientMatrix := MaxInt; lPrefs.Anonymize := not NotAnonymizeCheck.Checked; lPrefs.TxtReport:= TxtReportCheck.Checked; lPrefs.RecursiveFolderDepth := RecursiveSpin.Value; lPrefs.OutDir := OutDirLabel.Caption; lPrefs.OutDirMode := OutputCombo.ItemIndex; lPrefs.WritePrefsOnQuit := WritePrefsOnQuit.Checked; end; procedure TPrefsForm.TextEditorBtnClick(Sender: TObject); {$IFDEF UNIX} var AProcess: TProcess; begin Showmessage('Preferences will be opened in a text editor. The program '+ExtractFilename(paramstr(0))+' will now quit, so that the file will not be overwritten.'); MainForm.SavePrefs; AProcess := TProcess.Create(nil); {$IFDEF UNIX} {$IFDEF Darwin} AProcess.CommandLine := 'open -a TextEdit '+IniName; {$ELSE} AProcess.CommandLine := 'open -a gedit '+IniName; {$ENDIF} {$ELSE} AProcess.CommandLine := 'notepad '+IniName; {$ENDIF} //AProcess.Options := AProcess.Options + [poWaitOnExit]; AProcess.Execute; AProcess.Free; WritePrefsOnQuit.checked := false; MainForm.close; end; {$ELSE} //ShellExecute(Handle,'open', 'c:\windows\notepad.exe','c:\SomeText.txt', nil, SW_SHOWNORMAL) ; begin Showmessage('Preferences will be opened in a text editor. The program '+ExtractFilename(paramstr(0))+' will now quit, so that the file will not be overwritten.'); MainForm.SavePrefs; ShellExecute(Handle,'open', 'notepad.exe',PAnsiChar(AnsiString(IniName)), nil, SW_SHOWNORMAL) ; WritePrefsOnQuit.checked := false; MainForm.close; end; {$ENDIF} procedure TPrefsForm.FilenameChecks(Sender: TObject); var lDICOMImgName: string; lDicomData: DICOMdata; lPrefs: TPrefs; begin Clear_Dicom_Data(lDicomData); SetDefaultPrefs (lPrefs); ReadPrefs(lPrefs); clear_dicom_data(lDicomData); lDICOMImgName:= 'IM60'; lDicomData.PatientName := 'JOHN_DOE'; lDicomData.ProtocolName := 'T1'; //FilenameBox.Caption := 'Output Filename ('+ OutputFilename(lDicomImgName,lDicomData,lPrefs.AppendDate,lPrefs.AppendAcqSeries,lPrefs.AppendProtocolName,lPrefs.AppendPatientName,lPrefs.FourD,lPrefs.AppendFilename)+')'; Caption := 'Output: '+ OutputFilename(lDicomImgName,lDicomData,lPrefs); end; procedure TPrefsForm.SetOutput; begin SetOutDirLabel; if not (OutputCombo.ItemIndex = kOutDirModeOutDir) then exit; OutDirLabel.Caption := GetDirPrompt(OutDirLabel.Caption); end; procedure TPrefsForm.OutputComboMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); //for OSX begin {$IFDEF Darwin} SetOutput; {$ENDIF} end; procedure TPrefsForm.OutputComboChange(Sender: TObject); //for all OSes except OSX... begin {$IFNDEF Darwin} SetOutput; {$ENDIF} end; initialization {$IFDEF FPC} {$I pref_form.lrs} {$ENDIF} end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/SelectFolder.pas0000755000175000017500000000610411326434462020616 0ustar mihmihunit SelectFolder; interface function BrowseForFolder(const browseTitle: String; const initialFolder: String = ''; mayCreateNewFolder: Boolean = False): String; function SelectDirectoryDelphi(const browseTitle: String; var Folder: String; mayCreateNewFolder: Boolean = False): boolean; implementation uses Windows, Forms, shlobj; function SelectDirectoryDelphi(const browseTitle: String; var Folder: String; mayCreateNewFolder: Boolean = False): boolean; var lTemp: string; begin result := false; lTemp := BrowseForFolder(browseTitle, Folder, mayCreateNewFolder); if (lTemp <> '') then begin Folder := lTemp; result := true; end; // end; var lg_StartFolder: String; // With later versions of Delphi you may not need these constants. const BIF_NEWDIALOGSTYLE=$40; BIF_NONEWFOLDERBUTTON=$200; //////////////////////////////////////////////////////////////////////// // Call back function used to set the initial browse directory. //////////////////////////////////////////////////////////////////////// function BrowseForFolderCallBack(Wnd: HWND; uMsg: UINT; lParam, lpData: LPARAM): Integer stdcall; begin if uMsg = BFFM_INITIALIZED then SendMessage(Wnd,BFFM_SETSELECTION, 1, Integer(@lg_StartFolder[1])); result := 0; end; //////////////////////////////////////////////////////////////////////// // This function allows the user to browse for a folder // // Arguments:- // browseTitle : The title to display on the browse dialog. // initialFolder : Optional argument. Use to specify the folder // initially selected when the dialog opens. // mayCreateNewFolder : Flag indicating whether the user can create a // new folder. // // Returns: The empty string if no folder was selected (i.e. if the user // clicked cancel), otherwise the full folder path. //////////////////////////////////////////////////////////////////////// function BrowseForFolder(const browseTitle: String; const initialFolder: String =''; mayCreateNewFolder: Boolean = False): String; var browse_info: TBrowseInfo; folder: array[0..MAX_PATH] of char; find_context: PItemIDList; begin //-------------------------- // Initialise the structure. //-------------------------- FillChar(browse_info,SizeOf(browse_info),#0); lg_StartFolder := initialFolder; browse_info.pszDisplayName := @folder[0]; browse_info.lpszTitle := PChar(browseTitle); browse_info.ulFlags := BIF_RETURNONLYFSDIRS or BIF_NEWDIALOGSTYLE; if not mayCreateNewFolder then browse_info.ulFlags := browse_info.ulFlags or BIF_NONEWFOLDERBUTTON; browse_info.hwndOwner := Application.Handle; if initialFolder <> '' then browse_info.lpfn := BrowseForFolderCallBack; find_context := SHBrowseForFolder(browse_info); if Assigned(find_context) then begin if SHGetPathFromIDList(find_context,folder) then result := folder else result := ''; GlobalFreePtr(find_context); end else result := ''; end; end.mricron-0.20140804.1~dfsg.1.orig/dcm2nii/filename.pas0000755000175000017500000001302212307644160020016 0ustar mihmihunit filename; {$IFDEF FPC} {$mode objfpc} {$ENDIF} {$H+} interface uses //{$IFNDEF FPC}FileCtrl,{$ENDIF} Classes, SysUtils,define_types,dicomtypes,prefs; procedure ExtractFileParts (var lFileName, lNameWOExt,lExt: string); function ExtractFileDirWithPathDelim2(lInFilename: string): string; procedure AplhaNumericStr (var lStr: string); procedure AplhaNumericStrExt (var lStr: string); function OutputFilename(var lDicomImgName: string; var lDicomData: dicomData; lPrefs: TPrefs): string; procedure StripNIIVOIExt (var lFilename: string); procedure StripGZExt (var lFilename: string); function FilenameWOExt( lFileName: string): string; function UpcaseStr(lIn: string): string; implementation uses dialogsx; function UpcaseStr(lIn: string): string; var lI: integer; begin result := lIn; if length(result) > 0 then for lI := 1 to length(result) do result[lI] := upcase(result[lI]); end; function FilenameWOExt( lFileName: string): string; var lNameWOExt,lExt : string; begin ExtractFileParts (lFileName, lNameWOExt,lExt); result := extractfilename(lNameWOExt); end; procedure AplhaNumericStr (var lStr: string); var S: integer; lOutStr: string; begin if length(lStr) < 1 then exit; lOutStr := ''; for S := 1 to length (lStr) do if lStr[S] in ['0'..'9','A'..'Z','a'..'z'] then lOutStr := lOutStr+ lStr[S]; lStr := lOutStr; end; procedure AplhaNumericStrExt (var lStr: string); var S: integer; lOutStr: string; begin if length(lStr) < 1 then exit; lOutStr := ''; for S := 1 to length (lStr) do if lStr[S] in ['0'..'9','A'..'Z','a'..'z','_','-','^'] then lOutStr := lOutStr+ lStr[S]; lStr := lOutStr; end; procedure StripNIIVOIExt (var lFilename: string); var lStr: string; lLen,lPos: integer; begin lLen := length(lFilename); if lLen < 8 then exit; lStr := ''; for lPos := (lLen-7) to (lLen) do lStr := lStr +UpCase(lFilename[lPos]); if lStr <> '.NII.VOI' then exit; lStr := ''; for lPos := 1 to (lLen-8) do lStr := lStr + lFilename[lPos]; lStr := lStr + '.VOI'; lFilename := lStr; end; procedure StripGZExt (var lFilename: string); var lStr: string; lLen,lPos: integer; begin lLen := length(lFilename); if lLen < 4 then exit; lStr := ''; for lPos := (lLen-2) to (lLen) do lStr := lStr +UpCase(lFilename[lPos]); if lStr <> '.GZ' then exit; //showmessage(lFilename +' ->'+lStr); lStr := ''; for lPos := 1 to (lLen-3) do lStr := lStr + lFilename[lPos]; lFilename := lStr; //showmessage(lStr); end; function OutputFilename(var lDicomImgName: string; var lDicomData: dicomData; lPrefs: TPrefs): string; var lFile,lStr,lStr2,lExt: string; lAppendDate,lAppendAcqSeries,lAppendProtocolName,lAppendPatientName,lAppendFilename:boolean ; begin lAppendDate := lPrefs.AppendDate; lAppendAcqSeries := lPrefs.AppendAcqSeries; lAppendProtocolName := lPrefs.AppendProtocolName; lAppendPatientName := lPrefs.AppendPatientName; lAppendFilename := lPrefs.AppendFilename; if (not lAppendDate) and (not lAppendAcqSeries) and (not lAppendProtocolName) and (not lAppendPatientName) and (not lAppendFilename) then begin lAppendDate := true; lAppendAcqSeries := true; lAppendProtocolName := true; end; lStr := ''; if lAppendPatientName then begin lStr2 := lDicomData.PatientName; AplhaNumericStrExt(lStr2); lStr := lStr2+lStr; end; if lAppendProtocolName then begin lStr2 := lDicomData.ProtocolName; AplhaNumericStrExt(lStr2); lStr := lStr2+lStr; end; if lAppendFilename then begin lFile := ExtractFilename (lDicomImgName); ExtractFileParts (lFile, lStr2,lExt); AplhaNumericStrExt(lStr2); lStr := lStr2+lStr; end; if lAppendAcqSeries then lStr := lStr+'s'+PadStr(lDicomData.SeriesNum,3)+'a'+PadStr(lDicomData.AcquNum,3); if lAppendDate then lStr := StudyDateTime2Str(lDicomData.DateTime)+lStr; lStr := lPrefs.NameAppend + lStr; result := lStr; end; procedure ExtractFileParts (var lFileName, lNameWOExt,lExt: string); var lI: integer; l2ndExt : string; begin lNameWOExt := ''; lExt := ExtractFileExt(lFileName); if length(lExt) > 0 then for lI := 1 to length(lExt) do lExt[lI] := upcase(lExt[lI]); if (lExt = '.GZ') or (lExt = '.VOI') then begin lI := length(lFileName) - 6; if li < 1 then exit; l2ndExt := upcase(lFileName[lI])+upcase(lFileName[lI+1])+upcase(lFileName[li+2])+upcase(lFileName[li+3]); if (l2ndExt = '.TAR') or (l2ndExt = '.NII') then lExt := l2ndExt+lExt; end; if length(lExt) >= length (lFilename) then exit; for lI := 1 to (length(lFilename)-length(lExt)) do lNameWOExt := lNameWOExt + lFileName[lI]; //next for Unix do not use UpCase extension if length(lExt) >= 0 then begin l2ndExt := ''; for lI := 1 to (length(lExt)) do l2ndExt := lFilename[length(lFilename)-lI+1]+l2ndExt; lExt := l2ndExt; end; //length > 0 //showmessage(lNameWOExt+' '+lExt); end; function ExtractFileDirWithPathDelim2(lInFilename: string): string; //F:\filename.ext -> 'F:\' and F:\dir\filename.ext -> 'F:\dir\' //Despite documentation, Delphi3's ExtractFileDir does not always retain final pathdelim //ensures c:\temp is returned c:\temp\ not c:\ begin if DirExists(lInFilename) then begin result :=(lInFilename); if result[length(result)]<> pathdelim then result := result + pathdelim; exit; end; result := ExtractFileDirWithPathDelim(lInFilename); end; end. mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2niigui.cfg0000755000175000017500000000112612360762516020253 0ustar mihmih-$A8 -$B- -$C+ -$D+ -$E- -$F- -$G+ -$H+ -$I+ -$J+ -$K- -$L+ -$M- -$N+ -$O+ -$P+ -$Q- -$R- -$S- -$T- -$U- -$V+ -$W- -$X+ -$YD -$Z1 -cg -AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; -H+ -W+ -M -$M16384,1048576 -K$00400000 -LE"c:\program files (x86)\borland\delphi7\Projects\Bpl" -LN"c:\program files (x86)\borland\delphi7\Projects\Bpl" -U"..\common\;C:\pas\d4\RX\Units\;..\delphionly" -O"..\common\;C:\pas\d4\RX\Units\;..\delphionly" -I"..\common\;C:\pas\d4\RX\Units\;..\delphionly" -R"..\common\;C:\pas\d4\RX\Units\;..\delphionly" mricron-0.20140804.1~dfsg.1.orig/dcm2nii/nifti_form.dfm0000755000175000017500000000534711454152370020367 0ustar mihmih TNIFTIFORM0 TPF0 TNIfTIform NIfTIformLeftTop~ BorderStylebsDialogCaptionConvert NIfTI file ClientHeightE ClientWidthTColor clBtnFace Font.CharsetDEFAULT_CHARSET Font.Color clWindowText Font.Height Font.Name MS Sans Serif Font.Style OldCreateOrderPositionpoScreenCenterOnCreate FormCreate PixelsPerInch` TextHeight TLabelLabel1LeftTopWidthHeight CaptionTaskLayouttlCenterTLabelLabel4LeftTopWidthOHeight Caption Output Format: LayouttlCenter TComboBoxCombo4DLeft7TopWidthHeightStylecsDropDownList ItemHeight Items.Strings Change formatFlip dimensions 3 and 4Clip 1st/Last VolumesExport as 32-bit real Apply formulaASL conversionCrop slices from Z dimensionTabOrderOnChange Combo4DChangeTButtonOKBtnLeftTopWidthKHeightCaptionOK ModalResultTabOrderOnClick OKBtnClickTButton CancelBtnLeftTopWidthKHeightCaptionCancel ModalResultTabOrder TComboBoxCombo3DLeftOTopWidthHeightStylecsDropDownList ItemHeight Items.Strings Change formatReorient to orthogonalReorient and cropCrop slices from Z dimension+Siemens phase map to radians (SPM fieldmap)TabOrderOnChange Combo4DChangeTPanelPanel1Left:Top(WidthHeightITabOrderTLabelLabel2LeftTopWidthHeight CaptionVolumes to remove from startLayouttlCenterTLabelLabel3LeftTop&WidthHeight CaptionVolumes to remove from endLayouttlCenter TSpinEdit StartEditLeftTopWidthPHeightMaxValueMinValueTabOrderValue TSpinEditEndEditLeftTop#WidthPHeightMaxValueMinValueTabOrderValue TComboBox TypeComboLeftgTopWidthHeightStylecsDropDownList ItemHeight Items.StringsSPM2 (3D Anlyze hdr/img)SPM5 (3D NIfTI hdr/img)SPM8 (3D NIfTI nii)4D NIfTI hdr/imgFSL (4D NIfTI nii)Compressed FSL (4D NIfTI nii)MRIcron drawing (voi)TabOrderTPanel FormulaPanelLeft:Top(WidthHeightITabOrderTLabelLabel5LeftTopWidthHeight CaptionScaleLayouttlCenterTLabelLabel6LeftTop&WidthHeight CaptionPowerLayouttlCenter TRxSpinEdit ScaleEditLeftPTopWidthyHeight ButtonKind bkStandardDecimal ValueTypevtFloatValue?TabOrder TRxSpinEdit PowerEditLeftPTop WidthyHeight ButtonKind bkStandardDecimal ValueTypevtFloatTabOrderTPanelASLPanelLeft*Top(WidthHeight)TabOrder TComboBoxASLComboLeftTopWidthHeightStylecsDropDownList ItemHeight Items.Strings#Subtract pairs - first image tagged$Subtract pairs - first image controlSubtract CustomAdd (odd+even) BOLDParse into odd/even datasetsTabOrdermricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2niigui.lpi0000755000175000017500000003434712377624456020323 0ustar mihmih <UseXPManifest Value="True"/> <Icon Value="0"/> <ActiveWindowIndexAtStart Value="0"/> </General> <BuildModes Count="1"> <Item1 Name="default" Default="True"/> </BuildModes> <PublishOptions> <Version Value="2"/> <IgnoreBinaries Value="False"/> <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/> </PublishOptions> <RunParams> <local> <FormatVersion Value="1"/> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> </RunParams> <RequiredPackages Count="1"> <Item1> <PackageName Value="LCL"/> </Item1> </RequiredPackages> <Units Count="25"> <Unit0> <Filename Value="dcm2niigui.lpr"/> <IsPartOfProject Value="True"/> <UnitName Value="dcm2niigui"/> <TopLine Value="1"/> <CursorPos X="2" Y="1"/> <UsageCount Value="206"/> </Unit0> <Unit1> <Filename Value="gui.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="MainForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="gui"/> <WindowIndex Value="0"/> <TopLine Value="955"/> <CursorPos X="26" Y="961"/> <UsageCount Value="206"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit1> <Unit2> <Filename Value="nifti_form.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="NIfTIForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="nifti_form"/> <WindowIndex Value="0"/> <TopLine Value="66"/> <CursorPos X="26" Y="73"/> <UsageCount Value="206"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit2> <Unit3> <Filename Value="pref_form.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="PrefsForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="pref_form"/> <WindowIndex Value="0"/> <TopLine Value="132"/> <CursorPos X="34" Y="158"/> <UsageCount Value="206"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit3> <Unit4> <Filename Value="niftiutil.pas"/> <UnitName Value="niftiutil"/> <WindowIndex Value="0"/> <TopLine Value="993"/> <CursorPos X="13" Y="1001"/> <UsageCount Value="77"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit4> <Unit5> <Filename Value="prefs.pas"/> <UnitName Value="prefs"/> <WindowIndex Value="0"/> <TopLine Value="229"/> <CursorPos X="90" Y="240"/> <UsageCount Value="105"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit5> <Unit6> <Filename Value="dicomtypes.pas"/> <UnitName Value="dicomtypes"/> <EditorIndex Value="4"/> <WindowIndex Value="0"/> <TopLine Value="655"/> <CursorPos X="48" Y="673"/> <UsageCount Value="104"/> <Loaded Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit6> <Unit7> <Filename Value="..\common\define_types.pas"/> <UnitName Value="define_types"/> <IsVisibleTab Value="True"/> <EditorIndex Value="2"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="33" Y="21"/> <UsageCount Value="113"/> <Loaded Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit7> <Unit8> <Filename Value="convert.pas"/> <UnitName Value="convert"/> <EditorIndex Value="0"/> <WindowIndex Value="0"/> <TopLine Value="1613"/> <CursorPos X="1" Y="1618"/> <UsageCount Value="115"/> <Loaded Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit8> <Unit9> <Filename Value="..\common\gzio2.pas"/> <UnitName Value="gzio2"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="114" Y="1"/> <UsageCount Value="82"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit9> <Unit10> <Filename Value="..\common\GraphicsMathLibrary.pas"/> <UnitName Value="GraphicsMathLibrary"/> <WindowIndex Value="0"/> <TopLine Value="592"/> <CursorPos X="27" Y="585"/> <UsageCount Value="113"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit10> <Unit11> <Filename Value="..\common\dialogsx.pas"/> <UnitName Value="dialogsx"/> <WindowIndex Value="0"/> <TopLine Value="53"/> <CursorPos X="52" Y="60"/> <UsageCount Value="7"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit11> <Unit12> <Filename Value="dicomcompat.pas"/> <UnitName Value="dicomcompat"/> <WindowIndex Value="0"/> <TopLine Value="5360"/> <CursorPos X="77" Y="5365"/> <UsageCount Value="114"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit12> <Unit13> <Filename Value="sortdicom.pas"/> <UnitName Value="sortdicom"/> <WindowIndex Value="0"/> <TopLine Value="180"/> <CursorPos X="50" Y="189"/> <UsageCount Value="49"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit13> <Unit14> <Filename Value="philips_bvec.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="philips_bvec"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="117" Y="248"/> <UsageCount Value="214"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit14> <Unit15> <Filename Value="..\common\isgui.inc"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="10" Y="1"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit15> <Unit16> <Filename Value="csaread.pas"/> <UnitName Value="csaread"/> <WindowIndex Value="0"/> <TopLine Value="41"/> <CursorPos X="31" Y="53"/> <UsageCount Value="104"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit16> <Unit17> <Filename Value="dialogs_msg.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="dialogs_msg"/> <WindowIndex Value="0"/> <TopLine Value="7"/> <CursorPos X="11" Y="9"/> <UsageCount Value="208"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit17> <Unit18> <Filename Value="..\common\nifti_types.pas"/> <UnitName Value="nifti_types"/> <WindowIndex Value="0"/> <TopLine Value="72"/> <CursorPos X="72" Y="86"/> <UsageCount Value="100"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit18> <Unit19> <Filename Value="..\common\nifti_foreign.pas"/> <UnitName Value="nifti_foreign"/> <WindowIndex Value="0"/> <TopLine Value="416"/> <CursorPos X="74" Y="419"/> <UsageCount Value="73"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit19> <Unit20> <Filename Value="parconvert.pas"/> <UnitName Value="parconvert"/> <EditorIndex Value="3"/> <WindowIndex Value="0"/> <TopLine Value="1124"/> <CursorPos X="66" Y="1125"/> <UsageCount Value="26"/> <Loaded Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit20> <Unit21> <Filename Value="bvec.pas"/> <UnitName Value="bvec"/> <EditorIndex Value="1"/> <WindowIndex Value="0"/> <TopLine Value="34"/> <CursorPos X="48" Y="61"/> <UsageCount Value="26"/> <Loaded Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit21> <Unit22> <Filename Value="..\..\..\..\..\..\Developer\lazarus\lcl\include\customform.inc"/> <WindowIndex Value="0"/> <TopLine Value="2535"/> <CursorPos X="60" Y="2545"/> <UsageCount Value="24"/> </Unit22> <Unit23> <Filename Value="..\..\..\..\..\..\Developer\lazarus\lcl\include\menuitem.inc"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="50" Y="1"/> <UsageCount Value="8"/> </Unit23> <Unit24> <Filename Value="dicom.pas"/> <UnitName Value="dicom"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="29" Y="6"/> <UsageCount Value="10"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit24> </Units> <JumpHistory Count="30" HistoryIndex="29"> <Position1> <Filename Value="parconvert.pas"/> <Caret Line="1110" Column="36" TopLine="1091"/> </Position1> <Position2> <Filename Value="parconvert.pas"/> <Caret Line="1111" Column="43" TopLine="1092"/> </Position2> <Position3> <Filename Value="parconvert.pas"/> <Caret Line="1113" Column="16" TopLine="1094"/> </Position3> <Position4> <Filename Value="parconvert.pas"/> <Caret Line="1120" Column="29" TopLine="1109"/> </Position4> <Position5> <Filename Value="bvec.pas"/> <Caret Line="74" Column="12" TopLine="50"/> </Position5> <Position6> <Filename Value="convert.pas"/> <Caret Line="1611" Column="44" TopLine="1587"/> </Position6> <Position7> <Filename Value="convert.pas"/> <Caret Line="67" Column="108" TopLine="66"/> </Position7> <Position8> <Filename Value="convert.pas"/> <Caret Line="242" Column="51" TopLine="223"/> </Position8> <Position9> <Filename Value="convert.pas"/> <Caret Line="397" Column="40" TopLine="375"/> </Position9> <Position10> <Filename Value="convert.pas"/> <Caret Line="1181" Column="29" TopLine="1176"/> </Position10> <Position11> <Filename Value="convert.pas"/> <Caret Line="1182" Column="19" TopLine="1176"/> </Position11> <Position12> <Filename Value="convert.pas"/> <Caret Line="1199" Column="30" TopLine="1181"/> </Position12> <Position13> <Filename Value="convert.pas"/> <Caret Line="1282" Column="29" TopLine="1260"/> </Position13> <Position14> <Filename Value="convert.pas"/> <Caret Line="1370" Column="65" TopLine="1348"/> </Position14> <Position15> <Filename Value="parconvert.pas"/> <Caret Line="1282" Column="64" TopLine="1272"/> </Position15> <Position16> <Filename Value="parconvert.pas"/> <Caret Line="1024" Column="61" TopLine="1021"/> </Position16> <Position17> <Filename Value="parconvert.pas"/> <Caret Line="6" Column="88" TopLine="1"/> </Position17> <Position18> <Filename Value="convert.pas"/> <Caret Line="1621" Column="66" TopLine="1610"/> </Position18> <Position19> <Filename Value="parconvert.pas"/> <Caret Line="1" Column="130" TopLine="1"/> </Position19> <Position20> <Filename Value="parconvert.pas"/> <Caret Line="343" Column="22" TopLine="304"/> </Position20> <Position21> <Filename Value="parconvert.pas"/> <Caret Line="384" Column="26" TopLine="346"/> </Position21> <Position22> <Filename Value="parconvert.pas"/> <Caret Line="917" Column="21" TopLine="879"/> </Position22> <Position23> <Filename Value="parconvert.pas"/> <Caret Line="1141" Column="27" TopLine="1103"/> </Position23> <Position24> <Filename Value="parconvert.pas"/> <Caret Line="343" Column="22" TopLine="320"/> </Position24> <Position25> <Filename Value="parconvert.pas"/> <Caret Line="384" Column="26" TopLine="346"/> </Position25> <Position26> <Filename Value="parconvert.pas"/> <Caret Line="917" Column="21" TopLine="879"/> </Position26> <Position27> <Filename Value="parconvert.pas"/> <Caret Line="1139" Column="23" TopLine="1113"/> </Position27> <Position28> <Filename Value="parconvert.pas"/> <Caret Line="1138" Column="27" TopLine="1116"/> </Position28> <Position29> <Filename Value="parconvert.pas"/> <Caret Line="1052" Column="10" TopLine="1043"/> </Position29> <Position30> <Filename Value="parconvert.pas"/> <Caret Line="1143" Column="75" TopLine="1118"/> </Position30> </JumpHistory> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <SearchPaths> <OtherUnitFiles Value="..\common"/> <SrcPath Value="C:\lazarus\ideintf"/> </SearchPaths> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> <UseLineInfoUnit Value="False"/> <StripSymbols Value="True"/> </Debugging> <LinkSmart Value="True"/> <Options> <Win32> <GraphicApplication Value="True"/> </Win32> </Options> </Linking> <Other> <WriteFPCLogo Value="False"/> <CompilerMessages> <UseMsgFile Value="True"/> </CompilerMessages> <CompilerPath Value="$(CompPath)"/> </Other> </CompilerOptions> <Debugging> <Exceptions Count="2"> <Item1> <Name Value="ECodetoolError"/> </Item1> <Item2> <Name Value="EFOpenError"/> </Item2> </Exceptions> </Debugging> <EditorMacros Count="0"/> </CONFIG> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/gui.dfm����������������������������������������������������0000755�0001750�0001750�00000004637�12306701562�017020� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �TMAINFORM�0 ��TPF0 TMainFormMainFormLeftTop�WidthHeightCaption&Drag and Drop DICOM to NIfTI converterColor clBtnFaceDragMode dmAutomatic Font.CharsetDEFAULT_CHARSET Font.Color clWindowText Font.Height Font.Name MS Sans Serif Font.Style �Menu MainMenu1OldCreateOrderPositionpoScreenCenterOnClose FormCloseOnCreate FormCreateOnShowFormShow PixelsPerInch` TextHeight �TMemoMemo1Left�Top!WidthHeightAlignalClientReadOnly ScrollBars ssVerticalTabOrder���TPanelPanel1Left�Top�WidthHeight!AlignalTop BevelOuterbvNoneTabOrder�TLabelLabel1Left�TopWidthOHeight Caption Output Format: LayouttlCenter�� TComboBox TypeComboLeftOTopWidth�HeightStylecsDropDownList ItemHeight TabOrder�OnChangeTypeComboChange Items.StringsSPM2 (3D Anlyze hdr/img)SPM5 (3D NIfTI hdr/img)SPM8 (3D NIfTI nii)4D NIfTI hdr/imgFSL (4D NIfTI nii)Compressed FSL (4D NIfTI nii)���� TMainMenu MainMenu1Left�TopP� TMenuItemFile1CaptionFile� TMenuItem DICOMtoNIfTI1CaptionDICOM to NIfTIShortCutD@OnClickdcm2niiBtnClick�� TMenuItem ModifyNIfTI1Caption Modify NIfTIOnClickModifyNIfTI1Click�� TMenuItem NIfTI3D4D1CaptionNIfTI 3D -> 4DOnClickNIfTI3D4D1Click�� TMenuItemAnonymizeDICOM1CaptionAnonymize DICOMOnClickAnonymizeDICOM1Click�� TMenuItem ResliceNIfTI1Caption Reslice NIfTIOnClickResliceNIfTI1Click�� TMenuItemExit1CaptionExitOnClick Exit1Click�� TMenuItem Deletenondcm1CaptionDelete non .dcmVisibleOnClickDeletenondcm1Click��� TMenuItemEdit1CaptionEdit� TMenuItemCopy1CaptionCopyShortCutC@OnClick Copy1Click��� TMenuItem UntestedMenuCaptionUntested� TMenuItemMirrorXdimension1CaptionMirror X-dimensionOnClickMirrorXdimension1Click�� TMenuItemSumTPM1CaptionSum TPMOnClick SumTPM1Click�� TMenuItemExtractDICOMdims1CaptionExtract DICOM dimensionsOnClickExtractDICOMdims1Click�� TMenuItemExtractDICOMhdr1CaptionExtract DICOM headersOnClickExtractDICOMhdr1Click�� TMenuItemExtractNIfTIhdrs1CaptionExtract NIfTI headersOnClickExtractNIfTIhdrs1Click�� TMenuItem HalveMenu1CaptionHalve dimensions inplaneOnClickHalveMenu1Click��� TMenuItemHelp1CaptionHelp� TMenuItem Preferences1CaptionPreferences...ShortCutP@OnClickPreferences1Click�� TMenuItemAbout1CaptionAbout...ShortCutA@OnClick About1Click���� TOpenDialog OpenHdrDlgLeft�TopP����������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2nii48.ico����������������������������������������������0000755�0001750�0001750�00000042206�11410446220�017723� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������00��� �%��F��� ��� ���%����� � ��6����� �h��@��(���0���`���� �����%�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������~~zz{{{{|||~~jjj�������������������������������������������������������������������������������������������������������������vu�mmn�rrq�rrr�ttt�}}}�lll�xxx�888��������������������������������������������kkk zzz֦أأ٢٣٢٢ئۛsss9rrp!pqm##"ggtPPKSTG]]Ybbbiiibbb___���������������������������������������HҚlwyYrtPstPxzZl𒓃𡡞𫫯𭭲𨨩𥥣𥥥짧񓓓�����������������������������������rlo;`d_eek�kq�nu�mt�kq�gm�ekhmuy=r```���������������������������������ͨhj7X^�u|��������t|�qwSp������������������������������ppp�lll"4������������xk������������������������������J;�������>}}I���������������������������sA�����������������!���������������������������G����&PileJ!&,)nqF:F?(dfZ�llf�������jdTryyvҒ�zzz�����kkk�Ш|}zzzÍv{}wwwN�```� (⫫ttsyyyzzzzzzzzz~~~wwwరeeeqqqT쭭zzzxxxTTT��}}}򭭭}}}rrr|||xxxyyysssxxx}}}|||zzzzzz{{{xxxtttuuuwww{{{uuu薕Ԗ֟Ҟ___Z푑nnnooonnnjjjtlllgwwwUiii �����cifl�nu�������rrr^�����www�uuu���1����ʍ����48��DDD�^^^�jjjkkkzzzuuuyyy�nR����VkY E�*���������XPOMKKDp�����eee�����������������vvv��I]����表�*���������������G����������������������NW����籸)�*���������{{{y񩩩3EEE```zzz�����������zzz��;����'>�:�*���������^^^J몪.����� ~�ZZZ�```��yyy ����Ď � �*���������ܬZ�����uB�����������47�-����������������î ������򤤤l �###��.#����(-S2�)�������������8������NদìT���� .L%�%��������������vx������ch�����7D�+#��������������HB������RX�����&樰0-.�#�������������]]]�RRR򢢢$������� z%�������6f$�%,�����������������̧s��������NuwR������F쯮Mnk�h-������������������h��������������������J�ty%��������������������� �Sm����������������MV�sx���������������������yyy�rrr,����������������� g̒~����������������������������QףW���������������� 4泲¡J���������������������������TTT��xxxaaa� kɪ᭭𰰰c-������� "WT��������������������������������������|||�rrr��������������XXXlll-B[tȡtٛK斝/!ט"(w~.: � �����������������������������������������������xxx��???� �nnn������������������&aUb`opS'x|4079:<~-0y|8��)�]Z���h[�������������������������������������������������������������������������������������www�5#�H2�_Z�qrV�8�<�?�0�}9��#������������������������������������������������������������������������������������������������������������������������������������������������������,{)w{3{7$�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?������?����������������������������������������������������������������(��� ���@���� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������vvv�{{{�ZZZ�nnn��������fff������������������������������������������������������������������������������[[[�{{{aaa�������ccc�aa`lkoyy|Ooq<uxEj�����������������������SSSooo�WWW .,--,,\\YYYO�nnj�y�qrP�fh;�kmE�k�������������������������������O֧Ťyyjss]wxd|&������������������~Yrv*sxu| v}v| v{y~%K�������������������_u}����������%񠠞�������������������i����������Xr�ttr�������������զp��(<;" }Qbg;lpA�vvt�EEE�777�����]]].詩le}{ut~{z '''LLL`zzyদᔔ�yyx~}}||{{{vvvrrrwwwwww~~坝ᚚ~~~lϭmmms|||giiiZKBԲ ou Ylr rxlllҬ��555�qqq���c"���y���ppp�˪7641P~~~;/�����������������V����������y .��xxx��ü�� %_$�����mmm=좢:��MഴG�#O��D%H�,���� آ{�~շɯ󵵵}�*| �(�������8��su���7E8�(����������79����(�%�%������I ���  �����@\�0��������������������K򆅑���������������g첲N ���������d٬0�������������������{{{�jjjLfͮબT( ɇ(y{Y@ljv�������������������������kkk�����������wr%3OC.P-Y+T-<:ruD�y|(�JU����������������������������ggg�����������E�+�*�)�.�5�sv@�x{+tx-��������������������������������������������������������������������������5"" #�������&�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?��?��������������`��������������?���?(������0���� �����` ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ccc����������������������������������{{{�LLL�����������������{{{$HEEH&������,����������V`������������������������� ~ׇhtx;qu.uy<ӂ]ӗөѪӓ1�����������sz�����A�x������ ⣣z���������Z����wwwC%(Yve<FOMPttiyzh�g���zzxvvtttrա,֮zzz̃葑LIJ_ZwzMN߫����]���.����֤})*$|n�.Q�����V����n�>�r| O𳴰j��EN�0�+ꨨQ��C讯ް�&�/��ͦ��1i��.%)�%%�� ��� 70���cK�\)������P$��������ﭫO(�����Tծ魭f(  鎕(rb�����������������y|H .ANS&b"k#_$9(E>�������������������uuuBBC�����B����#�)�][^}dp�������������������������������������������'����������������������������������������������������������������������������������������������������������������������������������������?�����������������<��>��<������������?�����(������ ���� �����@����������������������� ��������������������hf~�������������FddT)'jh~%%&"~~w�h�^�����B N8����\����fI�G�q}}}zr{oA�Ԭzz~䣢Z멩A1s {%ᦥo%U��)� ���ϻ(�݉7a*�񵴿� �歭��>U8��-�i�~议; ���3̦k�������ssw"7MPb"sy^&+;�(�jW=�t����III�������T����)�G�<}ci�A����������������E  ��N����������������������������������������?������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2niigui.ini���������������������������������������������0000755�0001750�0001750�00000001453�12360762654�020301� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[BOOL] DebugMode=0 UntestedFeatures=0 UINT16toFLOAT32=1 Verbose=0 Anonymize=1 AnonymizeSourceDICOM=0 AppendAcqSeries=1 AppendDate=0 AppendFilename=0 AppendPatientName=0 AppendProtocolName=1 AutoCrop=0 CollapseFolders=1 createoutputfolder=0 CustomRename=0 enablereorient=1 OrthoFlipXDim=0 EveryFile=1 fourD=1 Gzip=0 ManualNIfTIConv=1 PhilipsPrecise=0 RecursiveUseNameAppend=0 SingleNIIFile=1 SPM2=0 Stack3DImagesWithSameAcqNum=0 Swizzle4D=1 UseGE_0021_104F=0 TxtReport=0 [INT] BeginClip=0 LastClip=0 usePigz=1 MaxReorientMatrix=1023 MinReorientMatrix=200 RecursiveFolderDepth=5 OutDirMode=0 SiemensDTIUse0019If00181020atleast=15 SiemensDTINoAngulationCorrectionIf00181020atleast=1000 SiemensDTIStackIf00181020atleast=15 [STR] OutDir=C:\Users\neuropsych\Documents ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/nii_crop.pas�����������������������������������������������0000755�0001750�0001750�00000112070�12306712572�020045� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit nii_crop; {$H+} //TO DO: ByteSwap, DataTypes, Orthogonality //VENTRAL direction: attempts to remove excess neck ... //OTHER directions: zeros slices where signal intensity is <5% //assumes image is oriented in canonical space, e.g. //closest to rotation matrix [1 0 0; 0 1 0; 0 0 1] //if your image is not rotated in this manner, use nii_orient first interface uses {$IFDEF FPC}gzio2,{$ENDIF} //distr, SysUtils,define_types,dicomtypes,niftiutil,GraphicsMathLibrary,prefs, nifti_types; //function Int16LogPtoZNIfTI32Z(lFilename: string; lPrefs: TPrefs): string; function CropNIfTI(lFilename: string; lPrefs: TPrefs): string;//returns output filename if successful function Float32NIfTI(lFilename: string; lPrefs: TPrefs): string; function FormulaNIfTI(lFilename: string; lPrefs: TPrefs; lScale,lPower: double): string; //function RescaleNIfTI(lFilename: string; lPrefs: TPrefs; lScale: double): string; function RemoveNIfTIscalefactor(lFilename: string; lPrefs: TPrefs): string; function CropNIfTIX(lFilename: string; lPrefs: TPrefs; lDorsalCrop, lVentralCrop, lLCrop,lRCrop, lACrop, lPCrop : integer ): string; function SiemensPhase2RadiansNIfTI(lFilename: string; lPrefs: TPrefs): string; implementation uses dialogsx,math,dialogs_msg; function RemoveNIfTIscalefactor(lFilename: string; lPrefs: TPrefs): string; //rescale data by lScale var lInHdr,lOutHdr: TNIFTIhdr; lOutname: string; l4DBytes,lInOffset,l1: integer; lInBuffer,lOutBuffer: bytep; lO: TNIIOpts; begin result := ''; //lExt := UpCaseExt(lFilename); if not NIFTIhdr_LoadHdr (lFilename, lInHdr, lO) then begin dcmMsg('Unable to read as NifTI/Analyze' + lFilename); exit; end; case lInHdr.datatype of kDT_UNSIGNED_CHAR,kDT_SIGNED_SHORT,kDT_UINT16, kDT_SIGNED_INT,kDT_FLOAT:;//Supported else begin dcmMsg('rescaleNIfTI unsupported datatype.'); exit; end; end; dcmMsg('removing scale factor NIfTI/Analyze image '+lFileName); lOutHdr := lInHdr; lOutHdr.scl_slope := 1; lOutHdr.scl_inter := 0; l4DBytes := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]*lInHdr.dim[4]*(lInHdr.bitpix div 8); if not NIFTIhdr_LoadImg (lFileName, lInHdr, lInBuffer, lInOffset,lO) then exit; GetMem(lOutBuffer,l4DBytes+kNIIImgOffset); //lOutPos := kNIIImgOffset + 1; l1 := 1; Move(lInBuffer^[lInOffset+l1],lOutBuffer^[kNIIImgOffset + l1],l4DBytes); lOutname := ChangeFilePrefix (lFileName,'r'); dcmMsg(lOutName); if SaveNIfTICore (lOutName, lOutBuffer, kNIIImgOffset+1, lOutHdr, lPrefs) = '' then begin dcmMsg('Remove scale error'); Freemem(lInBuffer); Freemem(lOutBuffer); exit; end; Freemem(lInBuffer); Freemem(lOutBuffer); result := lOutname; end; function FormulaNIfTI(lFilename: string; lPrefs: TPrefs; lScale,lPower: double): string; //apply formula to dataset, then save results as 32-bit float.... var lInHdr,lOutHdr: TNIFTIhdr; lOutname,lExt: string; lAdj: single; lImgSamples,lInc,lImgOffset,lVol,lnVol,lPos: integer; lSrcBuffer,lBuffer, lBuffUnaligned,lBuffAligned: bytep; l32Buf,lImgBuffer: singlep; l16Buf : SmallIntP; lByteSwap: boolean; lO: TNIIOpts; begin result := ''; lExt := UpCaseExt(lFilename); if not NIFTIhdr_LoadHdr (lFilename, lInHdr, lO) then begin dcmMsg('Unable to read as NifTI/Analyze' + lFilename); exit; end; case lInHdr.datatype of kDT_UNSIGNED_CHAR,kDT_SIGNED_SHORT,kDT_UINT16, kDT_SIGNED_INT,kDT_FLOAT:;//Supported else begin dcmMsg('Error with nii_crop: unsupported datatype.'); exit; end; end; dcmMsg('Applying formula to NIfTI/Analyze image'+lFileName); lOutHdr := lInHdr; lOutHdr.datatype := kDT_FLOAT; lOutHdr.bitpix := 32; lImgSamples := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]*lInHdr.dim[4]; if not NIFTIhdr_LoadImg (lFileName, lInHdr, lSrcBuffer, lImgOffset,lO) then exit; //Msg('Automatically Cropping image'); lBuffer := (@lSrcBuffer^[lImgOffset+1]); GetMem(lBuffUnaligned ,(sizeof(single)*lImgSamples) + 16+kNIIImgOffset); {$IFDEF FPC} lBuffAligned := Align(lBuffUnaligned,16); // not commented - check this {$ELSE} lBuffAligned := ByteP($fffffff0 and (integer(lBuffUnaligned)+15)); {$ENDIF} lInc := 1; lImgBuffer := SingleP(@lBuffAligned^[kNIIImgOffset+lInc]); case lInHdr.datatype of kDT_UNSIGNED_CHAR : begin //8 bit for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := lBuffer^[lInc]; end; kDT_SIGNED_SHORT{,kDT_UINT16}: begin //16-bit int l16Buf := SmallIntP(lBuffer ); if lByteSwap then begin for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := Swap(l16Buf^[lInc]); end else begin for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := l16Buf^[lInc]; end; end;//16bit kDT_SIGNED_INT: begin l32Buf := SingleP(lBuffer ); if lByteSwap then //unswap and convert integer to float for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := (Swap4r4i(l32Buf^[lInc])) else //convert integer to float for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := Conv4r4i(l32Buf^[lInc]); end; //32-bit int kDT_FLOAT: begin l32Buf := SingleP(lBuffer); for lInc := 1 to lImgSamples do lImgBuffer[lInc] := l32Buf[lInc]; if lByteSwap then for lInc := 1 to lImgSamples do pswap4r(lImgBuffer^[lInc]); //faster as procedure than function see www.optimalcode.com for lInc := 1 to lImgSamples do if specialsingle(lImgBuffer^[lInc]) then lImgBuffer^[lInc] := 0.0; //invert= for lInc := 1 to lImgSamples do l32Buf[lInc] := -l32Buf[lInc]; end; //32-bit float else begin dcmMsg('Serious error: format not supported by Float32.'); exit; end; end; //case //apply formula lImgSamples := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]; //3D data lnVol := lInHdr.dim[4]; //4th dimension lPos := 0; //fx(lScale,lPower); for lVol := 1 to lnVol do begin lAdj := 1/(lScale* Power(lVol,lPower)); for lInc := 1 to lImgSamples do begin inc(lPos); lImgBuffer^[lPos] := lAdj*lImgBuffer^[lPos]; //lImgBuffer[lPos] := lImgBuffer[lPos] * lScale; end; end; lOutname := ChangeFilePrefix (lFileName,'f'); result := SaveNIfTICore (lOutName, lBuffAligned, kNIIImgOffset+1, lOutHdr, lPrefs); Freemem(lBuffUnaligned); Freemem(lSrcBuffer); end; function Float32NIfTI(lFilename: string; lPrefs: TPrefs): string; //convert any data format as 32-bit float.... var lInHdr,lOutHdr: TNIFTIhdr; lOutname,lExt: string; lImgSamples,lInc,lImgOffset: integer; lSrcBuffer,lBuffer, lBuffUnaligned,lBuffAligned: bytep; l32Buf,lImgBuffer: singlep; l16Buf : SmallIntP; lO: TNIIOpts; begin result := ''; lExt := UpCaseExt(lFilename); if not NIFTIhdr_LoadHdr (lFilename, lInHdr, lO) then begin dcmMsg('Unable to read as NifTI/Analyze' + lFilename); exit; end; if lInHdr.datatype = kDT_FLOAT then begin dcmMsg('No need to apply Float32 : data is already 32-bit real: '+lFilename); exit; end; case lInHdr.datatype of kDT_UNSIGNED_CHAR,kDT_SIGNED_SHORT,kDT_UINT16, kDT_SIGNED_INT,kDT_FLOAT:;//Supported else begin dcmMsg('Float32 unsupported datatype.'); exit; end; end; dcmMsg('Converting NIfTI/Analyze image to 32-bit float'+lFileName); lOutHdr := lInHdr; lOutHdr.datatype := kDT_FLOAT; lOutHdr.bitpix := 32; lImgSamples := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]*lInHdr.dim[4]; if not NIFTIhdr_LoadImg (lFileName, lInHdr, lSrcBuffer, lImgOffset,lO) then exit; //Msg('Automatically Cropping image'); lBuffer := (@lSrcBuffer^[lImgOffset+1]); GetMem(lBuffUnaligned ,(sizeof(single)*lImgSamples) + 16+kNIIImgOffset); {$IFDEF FPC} lBuffAligned := align(lBuffUnaligned,16); {$ELSE} lBuffAligned := ByteP($fffffff0 and (integer(lBuffUnaligned)+15)); {$ENDIF} lInc := 1; lImgBuffer := SingleP(@lBuffAligned^[kNIIImgOffset+lInc]); case lInHdr.datatype of kDT_UNSIGNED_CHAR : begin //8 bit for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := lBuffer^[lInc]; end; kDT_SIGNED_SHORT{,kDT_UINT16}: begin //16-bit int l16Buf := SmallIntP(lBuffer ); for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := l16Buf^[lInc]; end;//16bit kDT_SIGNED_INT: begin for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := Conv4r4i(l32Buf^[lInc]); end; //32-bit int kDT_FLOAT: begin l32Buf := SingleP(lBuffer); for lInc := 1 to lImgSamples do lImgBuffer[lInc] := l32Buf[lInc]; for lInc := 1 to lImgSamples do if specialsingle(lImgBuffer^[lInc]) then lImgBuffer^[lInc] := 0.0; //invert= for lInc := 1 to lImgSamples do l32Buf[lInc] := -l32Buf[lInc]; end; //32-bit float else begin dcmMsg('Serious error: format not supported by Float32.'); exit; end; end; //case lOutname := ChangeFilePrefix (lFileName,'f'); result := SaveNIfTICore (lOutName, lBuffAligned, kNIIImgOffset+1, lOutHdr, lPrefs); Freemem(lBuffUnaligned); Freemem(lSrcBuffer); end; (*function LogPtoZ (lLogP: single): single; var lD: double; begin ///lD := Log10(lLogp); lD := Power(10,-lLogP); result := pNormalInv(lD); //fx(lD,lZ); end; function Int16LogPtoZNIfTI32Z(lFilename: string; lPrefs: TPrefs): string; //convert any data format as 32-bit float.... var lInHdr,lOutHdr: TNIFTIhdr; lOutname,lExt: string; lImgSamples,lInc,lImgOffset: integer; lSrcBuffer,lBuffer, lBuffUnaligned,lBuffAligned: bytep; l32Buf,lImgBuffer: singlep; l16Buf : SmallIntP; lByteSwap: boolean; begin result := ''; lExt := UpCaseExt(lFilename); if not NIFTIhdr_LoadHdr (lFilename, lInHdr, lByteSwap) then begin Msg('Unable to read as NifTI/Analyze' + lFilename); exit; end; if lInHdr.datatype = kDT_FLOAT then begin Msg('No need to apply Float32 : data is already 32-bit real: '+lFilename); exit; end; case lInHdr.datatype of kDT_UNSIGNED_CHAR,kDT_SIGNED_SHORT,kDT_UINT16, kDT_SIGNED_INT,kDT_FLOAT:;//Supported else begin Msg('Float32 unsupported datatype.'); exit; end; end; Msg('Converting NIfTI/Analyze image to 32-bit float'+lFileName); lOutHdr := lInHdr; lOutHdr.datatype := kDT_FLOAT; lOutHdr.bitpix := 32; lImgSamples := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]*lInHdr.dim[4]; if not NIFTIhdr_LoadImg (lFileName, lInHdr, lSrcBuffer, lImgOffset,lByteSwap) then exit; //Msg('Automatically Cropping image'); lBuffer := (@lSrcBuffer^[lImgOffset+1]); GetMem(lBuffUnaligned ,(sizeof(single)*lImgSamples) + 16+kNIIImgOffset); {$IFDEF FPC} lBuffAligned := align(lBuffUnaligned,16); {$ELSE} lBuffAligned := ByteP($fffffff0 and (integer(lBuffUnaligned)+15)); {$ENDIF} lInc := 1; lImgBuffer := SingleP(@lBuffAligned^[kNIIImgOffset+lInc]); lOutHdr.scl_slope := 1; case lInHdr.datatype of kDT_SIGNED_SHORT{,kDT_UINT16}: begin //16-bit int l16Buf := SmallIntP(lBuffer ); if lByteSwap then begin for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := Swap(l16Buf^[lInc]); end else begin for lInc := 1 to lImgSamples do begin if l16Buf^[lInc] =0 then lImgBuffer^[lInc] := 0 else if l16Buf^[lInc] =32767 then lImgBuffer^[lInc] := 0 else lImgBuffer^[lInc] := LogPtoZ(0.01*l16Buf^[lInc]); end; end; end;//16bit else begin Msg('Serious error: format not supported by Float32.'); exit; end; end; //case lOutname := ChangeFilePrefix (lFileName,'f'); result := SaveNIfTICore (lOutName, lBuffAligned, kNIIImgOffset+1, lOutHdr, lPrefs,lByteSwap); Freemem(lBuffUnaligned); Freemem(lSrcBuffer); end;*) procedure SmoothRA (var lRA: Doublep; lItems: integer); var lRecip: double; lTempRA,lTempRAUnaligned: Doublep; lI: integer; begin if lItems < 3 then exit; GetMem(lTempRAUnaligned,(lItems*sizeof(double))+16); {$IFDEF FPC} lTempRA := align(lTempRAUnaligned,16); {$ELSE} lTempRA := DoubleP($fffffff0 and (integer(lTempRAUnaligned)+15)); {$ENDIF} for lI := 1 to lItems do lTempRA^[lI] := lRA^[lI]; lRecip := 1/3; //multiplies faster than divides for lI := 2 to (lItems-1) do lRA^[lI] := (lTempRA^[lI-1]+lTempRA^[lI]+lTempRA^[lI+1])*lRecip; FreeMem(lTempRAUnaligned); end; function MaxRA (var lRA: Doublep; lStart,lItems: integer): integer; var lMax: double; lI: integer; begin result := lStart; if (lItems < 2) or (lStart >= lItems) or ((lItems-lStart)< 1) then exit; lMax := lRA^[lStart]; for lI := lStart to lItems do if lRA^[lI] > lMax then begin result := lI; lMax := lRA^[lI] end; end; function MinRA (var lRA: Doublep; lStart,lItems: integer): integer; var lMin: double; lI: integer; begin result := lStart; if (lItems < 2) or (lStart >= lItems) or ((lItems-lStart)< 1) then exit; lMin := lRA^[lStart]; for lI := lStart to lItems do if lRA^[lI] < lMin then begin result := lI; lMin := lRA^[lI] end; end; function FindDVCrop2 (var lHdr: TNIFTIhdr; var lDorsalCrop,lVentralCrop: integer): boolean; const kMaxDVmm = 200; var lSliceMM: double; begin result := false; if lHdr.pixdim[3] < 0.0001 then exit; lSliceMM := lHdr.pixdim[3]* (lHdr.Dim[3]-lDorsalCrop-lVentralCrop); if lSliceMM > kMaxDVmm then begin //decide how many more ventral slices to remove lSliceMM := lSliceMM - kMaxDVmm; lSliceMM := lSliceMM / lHdr.pixdim[3]; //msg(inttostr(lVentralCrop)); lVentralCrop := lVentralCrop + round(lSliceMM); //msg(inttostr(lVentralCrop)); end; result := true; end; function FindDVCrop (var lHdr: TNIFTIhdr; var ScrnBuffer: Singlep; var lDorsalCrop,lVentralCrop: integer; lPct: integer): boolean; var lSliceMax: double; lSliceSum,lSliceSumUnaligned: Doublep; lXY,lZ,lSlices,lSliceSz,lSliceStart,lVentralMaxSlice,lMaxSlice,lMinSlice,lGap: integer; begin result := false; lDorsalCrop := 0; lVentralCrop := 0; if (lPct < 1) or (lPct > 100) then exit; lSlices := lHdr.dim[3]; lSliceSz := lHdr.dim[1]*lHdr.dim[2]; GetMem(lSliceSumUnaligned,(lSlices*sizeof(double))+16); {$IFDEF FPC} lSliceSum := align(lSliceSumUnaligned,16); {$ELSE} lSliceSum := DoubleP($fffffff0 and (integer(lSliceSumUnaligned)+15)); {$ENDIF} lSliceMax := 0; for lZ := 1 to lSlices do begin lSliceSum^[lZ] := 0; lSliceStart := (lZ-1)*lSliceSz; for lXY := 1 to lSliceSz do lSliceSum^[lZ] := lSliceSum^[lZ]+ ScrnBuffer^[lXY+lSliceStart]; if lSliceMax < lSliceSum^[lZ] then lSliceMax := lSliceSum^[lZ]; end; //for each slice if lSliceMax = 0 then begin //no data variance Freemem(lSliceSumUnaligned); exit; end; //VolSum = 0 //next: normalize so each slice is normalized to brightest axial slice for lZ := 1 to lSlices do lSliceSum^[lZ] := lSliceSum^[lZ]/lSliceMax; result := true; //next: smooth SmoothRA(lSliceSum,lSlices); //next - top cropping - removing slices that are <5% of maximum slice lZ := lSlices; while (lZ > 1) and (lSliceSum^[lZ] < (lPct/100)) do dec(lZ); lDorsalCrop := lSlices-lZ; //next findMax lMaxSlice := MaxRA(lSliceSum,1,lSlices); //next - ensure there is at least 60mm from max to bottom of an image - enough spine to worry about lVentralMaxSlice := lMaxSlice-round(60/abs(lHdr.pixdim[3])); if lVentralMaxSlice < 1 then exit; lVentralMaxSlice := MaxRA(lSliceSum,1,lVentralMaxSlice); //finally: find minima between these two points... lMinSlice := MinRA(lSliceSum,lVentralMaxSlice,lMaxSlice); lGap := round((lMaxSlice-lMinSlice)*0.9);//add 40% for cerebellum if (lMinSlice-lGap) > 1 then begin result := true; lVentralCrop := lMinSlice-lGap; end; //fx(lVentralCrop,lDorsalCrop); //next show output... {TextForm.Memo1.Lines.Clear; for lZ := 1 to lSlices do TextForm.Memo1.Lines.add(inttostr(lZ)+','+floattostr(lSliceSum^[lZ])); TextForm.Show; } //cleanup Freemem(lSliceSumUnaligned); //next - max 200mm from top of head to spinal column.... //if (lSliceMM > kMaxDVmm end; function FindLRCrop (var lHdr: TNIFTIhdr; var ScrnBuffer: Singlep; var lLCrop,lRCrop:integer; lPct,lDCrop,lVCrop: integer): boolean; //amount of image to crop from left/right for N% signal intensity var lSliceMax: double; lSliceSum,lSliceSumUnaligned: Doublep; lZmin,lZmax,lX,lY,lZ,lSlices,lSliceSz,lSliceStart: integer; begin result := false; lLCrop := 0; lRCrop := 0; if (lPct < 1) or (lPct > 100) then exit; lZMin := lVCrop; lZMax := lHdr.Dim[3]-lDCrop; SortInt(lZMin,lZMax); lZMin := Bound(lZMin,1,lHdr.Dim[3]); lZMax := Bound(lZMax,1,lHdr.Dim[3]); if lZMin >= lZMax then exit; lSlices := lHdr.Dim[1]; lSliceSz := lHdr.Dim[1]*lHdr.Dim[2]; GetMem(lSliceSumUnaligned,(lSlices*sizeof(double))+16); {$IFDEF FPC} lSliceSum := align(lSliceSumUnaligned,16); {$ELSE} lSliceSum := DoubleP($fffffff0 and (integer(lSliceSumUnaligned)+15)); {$ENDIF} lSliceMax := 0; for lX := 1 to lSlices do begin lSliceSum^[lX] := 0; for lZ := {1 to lHdr.Dim[3]} lZMin to lZMax do begin lSliceStart := lX+ ((lZ-1)*lSliceSz); for lY := 1 to lHdr.Dim[2] do begin lSliceSum^[lX] := lSliceSum^[lX]+ ScrnBuffer^[lSliceStart]; lSliceStart := lSliceStart + lHdr.Dim[1]; end; end; //for lYZ := 1 to lSliceSz do // lSliceSum^[lZ] := lSliceSum^[lZ]+ gMRIcroOverlay[kBGOverlayNum].ScrnBuffer[lXY+lSliceStart]; if lSliceMax < lSliceSum^[lX] then lSliceMax := lSliceSum^[lX]; end; //for each slice if lSliceMax = 0 then begin //no data variance Freemem(lSliceSumUnaligned); exit; end; //VolSum = 0 //next: smooth SmoothRA(lSliceSum,lSlices); //next: normalize so each slice is normalized to brightest axial slice for lX := 1 to lSlices do lSliceSum^[lX] := lSliceSum^[lX]/lSliceMax; //next - Left cropping- removing slices that are <5% of maximum slice lX := lSlices; while (lX > 1) and (lSliceSum^[lX] < (lPct/100)) do dec(lX); lRCrop := lSlices-lX; //next - Left cropping- removing slices that are <5% of maximum slice lX := 1; while (lX <= lSlices) and (lSliceSum^[lX] < (lPct/100)) do inc(lX); lLCrop := lX-1; //fx(lLCrop,lRCrop); result := true; Freemem(lSliceSumUnaligned); end; function FindAPCrop (var lHdr: TNIFTIhdr; var ScrnBuffer: Singlep; var lACrop,lPCrop: integer; lPct,lDCrop,lVCrop: integer): boolean; //amount of image to crop from anterior/posterior for 5% signal intensity var lSliceMax: double; lSliceSum,lSliceSumUnaligned: Doublep; lZMin,lZMax,lX,lY,lZ,lSlices,lSliceSz,lSliceStart: integer; begin result := false; lACrop := 0; lPCrop := 0; lZMin := lVCrop; lZMax := lHdr.Dim[3]-lDCrop; SortInt(lZMin,lZMax); lZMin := Bound(lZMin,1,lHdr.Dim[3]); lZMax := Bound(lZMax,1,lHdr.Dim[3]); if lZMin >= lZMax then exit; if (lPct < 1) or (lPct > 100) then exit; lSlices := lHdr.Dim[2]; lSliceSz := lHdr.Dim[1]*lHdr.Dim[2]; //lCoroSliceSz := lHdr.Dim[1]*lHdr.Dim[3]; GetMem(lSliceSumUnaligned,(lSlices*sizeof(double))+16); {$IFDEF FPC} lSliceSum := align(lSliceSumUnaligned,16); {$ELSE} lSliceSum := DoubleP($fffffff0 and (integer(lSliceSumUnaligned)+15)); {$ENDIF} lSliceMax := 0; for lY := 1 to lSlices do begin lSliceSum^[lY] := 0; //lSliceStart := lY; for lZ := {1 to lHdr.Dim[3]} lZMin to lZMax do begin lSliceStart := ((lY-1)* lHdr.Dim[1])+ ((lZ-1)*lSliceSz); //if lSliceStart > (lSliceSz*lHdr.Dim[3]) then // Msg('xx'); for lX := 1 to lHdr.Dim[1] do lSliceSum^[lY] := lSliceSum^[lY]+ ScrnBuffer^[lSliceStart+lX]; end; //for lZ //for lYZ := 1 to lSliceSz do // lSliceSum^[lY] := lSliceSum^[lY]+ gMRIcroOverlay[kBGOverlayNum].ScrnBuffer[lXY+lSliceStart]; if lSliceMax < lSliceSum^[lY] then lSliceMax := lSliceSum^[lY]; end; //for each slice if lSliceMax = 0 then begin //no data variance Freemem(lSliceSumUnaligned); exit; end; //VolSum = 0 //next: smooth SmoothRA(lSliceSum,lSlices); //next: normalize so each slice is normalized to brightest axial slice for lY := 1 to lSlices do lSliceSum^[lY] := lSliceSum^[lY]/lSliceMax; //next - Left cropping- removing slices that are <5% of maximum slice lY := lSlices; while (lY > 1) and (lSliceSum^[lY] < (lPct/100)) do dec(lY); lACrop := lSlices-lY; //next - Left cropping- removing slices that are <5% of maximum slice lY := 1; while (lY <= lSlices) and (lSliceSum^[lY] < (lPct/100)) do inc(lY); lPCrop := lY-1; result := true; Freemem(lSliceSumUnaligned); end; function CropNIfTIX(lFilename: string; lPrefs: TPrefs; lDorsalCrop, lVentralCrop, lLCrop,lRCrop, lACrop, lPCrop : integer ): string; //to do : data swapping (errors on detection and writing zero in reverse order) var lInHdr,lOutHdr: TNIFTIhdr; lOutname,lExt: string; lXmm,lYmm,lZmm: single; lMat: TMatrix; lOutPos,//lInc, //lImgSamples, lX,lY,lZ,lBPP, lB, lVol, lInVol,lInZOffset,lInYOffset,lInSliceSz,lInXSz,lInPos,lImgOffset: integer; lSrcBuffer,lBuffer//, lBuffUnaligned : bytep; //l32Buf,lImgBuffer: singlep; //l16Buf : SmallIntP; //lWordX: Word; //lSPM2: boolean; lOutF,lInF: File; lO: TNIIOpts; begin result := ''; if (lDorsalCrop = 0) and (lVentralCrop = 0) and (lLCrop = 0) and (lRCrop = 0) and (lACrop = 0) and (lPCrop = 0) then begin dcmMsg('Crop slices quitting: no need to delete slices.'); exit; //25 Sept 2008 end; if (lDorsalCrop < 0) or (lVentralCrop < 0) or (lLCrop < 0) or (lRCrop < 0) or (lACrop < 0) or (lPCrop < 0) then begin dcmMsg('Crop slices quitting: negative values should be impossible.'); exit; end; result := ''; lExt := UpCaseExt(lFilename); if not NIFTIhdr_LoadHdr (lFilename, lInHdr, lO) then begin dcmMsg('Unable to read as NifTI/Analyze' + lFilename); exit; end; //Next create reordered or trimmed image in the correct format case lInHdr.datatype of kDT_UNSIGNED_CHAR,kDT_SIGNED_SHORT,kDT_UINT16, kDT_SIGNED_INT,kDT_FLOAT:;//Supported else begin dcmMsg('Crop 3D unsupported datatype.'); exit; end; end; dcmMsg('Cropping NIfTI/Analyze image '+lFileName); lOutHdr := lInHdr; //lImgSamples := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]; lBPP := (lInHdr.bitpix div 8); //bytes per pixel if not NIFTIhdr_LoadImg (lFileName, lInHdr, lSrcBuffer, lImgOffset,lO) then exit; //dcmMsg('Automatically Cropping image'); lBuffer := (@lSrcBuffer^[lImgOffset+1]); //next compute size of cropped volume lOutHdr.Dim[1] := lInHdr.Dim[1]-lLCrop-lRCrop; lOutHdr.Dim[2] := lInHdr.Dim[2]-lACrop-lPCrop; lOutHdr.Dim[3] := lInHdr.Dim[3]-lDorsalCrop-lVentralCrop; if (lOutHdr.Dim[1] < 1) or (lOutHdr.Dim[2] <12) or (lOutHdr.Dim[3] < 1) then begin dcmMsg('Requested to crop more slices than available.'); Freemem(lSrcBuffer); exit; end; //lVolBytes := lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3]*lBPP; //next: readjust origin to take into account removed slices //REQUIRES images to be aligned to nearest orthogonal to canonical space [1 0 0; 0 1 0; 0 0 1] NIFTIhdr_SlicesToCoord (lInHdr,lLCrop,lPCrop,lVentralCrop, lXmm,lYmm,lZmm); lOutHdr.srow_x[3] := lInHdr.srow_x[3] + lXmm; lOutHdr.srow_y[3] := lInHdr.srow_y[3] + lYmm; lOutHdr.srow_z[3] := lInHdr.srow_z[3] + lZmm; lMat := Matrix3D ( lOutHdr.srow_x[0], lOutHdr.srow_x[1], lOutHdr.srow_x[2], lOutHdr.srow_x[3], lOutHdr.srow_y[0], lOutHdr.srow_y[1], lOutHdr.srow_y[2], lOutHdr.srow_y[3], lOutHdr.srow_z[0], lOutHdr.srow_z[1], lOutHdr.srow_z[2], lOutHdr.srow_z[3], 0, 0, 0, 1); nifti_mat44_to_quatern( lMat, lOutHdr.quatern_b,lOutHdr.quatern_c,lOutHdr.quatern_d, lOutHdr.qoffset_x,lOutHdr.qoffset_y,lOutHdr.qoffset_z, lXmm, lYmm, lZmm, lOutHdr.pixdim[0]{QFac}); //note we write and read to the same buffer - we will always SHRINK output //no need to byteswap data - we will save in the save format as stored lOutPos := 0; lInSliceSz := lInHdr.dim[1]*lInHdr.dim[2]*lBPP; lInXSz := lInHdr.dim[1]*lBPP; for lVol := 1 to lOutHdr.dim[4] do begin lInVol := (lVol-1) * (lInSliceSz * lInHdr.dim[3]); //fx(lInVol,lVol); for lZ := 1 to lOutHdr.dim[3] do begin lInZOffset := (lVentralCrop+lZ-1) * lInSliceSz; for lY := 1 to lOutHdr.dim[2] do begin lInYOffset := ((lPCrop+lY-1) * lInXSz) + lInZOffset + (lLCrop*lBPP); for lX := 1 to lOutHdr.dim[1] do begin for lB := 1 to lBPP do begin inc(lOutPos); lInPos := ((lX-1) * lBPP) + lInYOffset + lB; lBuffer^[lOutPos] := lBuffer^[lInPos+lInVol]; end; end; end; //for Y end; //for Z end; //for Vol lOutname := ChangeFilePrefix (lFileName,'c'); result := SaveNIfTICore (lOutName, lSrcBuffer, kNIIImgOffset+1, lOutHdr, lPrefs); Freemem(lSrcBuffer); end; function CropNIfTI(lFilename: string; lPrefs: TPrefs): string; //to do : data swapping (errors on detection and writing zero in reverse order) var lInHdr,lOutHdr: TNIFTIhdr; lOutname,lExt: string; lXmm,lYmm,lZmm: single; lMat: TMatrix; lOutPos,lImgSamples,lInc, lX,lY,lZ,lBPP, lB, lInZOffset,lInYOffset,lInSliceSz,lInXSz,lInPos,lImgOffset: integer; lSrcBuffer,lBuffer, lBuffUnaligned: bytep; l32Buf,lImgBuffer: singlep; l16Buf : SmallIntP; //lOutF,lInF: File; lACrop,lPCrop,lDorsalCrop,lVentralCrop,lLCrop,lRCrop: integer; lO: TNIIOpts; begin result := ''; lExt := UpCaseExt(lFilename); if not NIFTIhdr_LoadHdr (lFilename, lInHdr, lO) then begin dcmMsg('Unable to read as NifTI/Analyze' + lFilename); exit; end; if (lInHdr.dim[1] > lPrefs.MaxReorientMatrix) or (lInHdr.dim[2] > lPrefs.MaxReorientMatrix) or(lInHdr.dim[3] > lPrefs.MaxReorientMatrix) then begin dcmMsg('This image will not be cropped (larger than MaxReorientMatrix= '+inttostr(lPrefs.MaxReorientMatrix)); exit; end; //check orthogonal alignment.... if lInHdr.dim[4] > 1 then begin dcmMsg('Only able to Crop 3D images (reorienting 4D could disrupt slice timing and diffusion directions.'); exit; end; //Next create reordered or trimmed image in the correct format case lInHdr.datatype of kDT_UNSIGNED_CHAR,kDT_SIGNED_SHORT,kDT_UINT16, kDT_SIGNED_INT,kDT_FLOAT:;//Supported else begin dcmMsg('Crop 3D unsupported datatype.'); exit; end; end; dcmMsg('Cropping NIfTI/Analyze image '+lFileName); lOutHdr := lInHdr; lImgSamples := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]; lBPP := (lInHdr.bitpix div 8); //bytes per pixel //lVolBytes := lImgSamples*lBPP; if not NIFTIhdr_LoadImg (lFileName, lInHdr, lSrcBuffer, lImgOffset,lO) then exit; //dcmMsg('Automatically Cropping image'); lBuffer := (@lSrcBuffer^[lImgOffset+1]); GetMem(lBuffUnaligned ,(sizeof(single)*lImgSamples) + 16); {$IFDEF FPC} lImgBuffer :=align(lBuffUnaligned,16); {$ELSE} lImgBuffer := SingleP($fffffff0 and (integer(lBuffUnaligned)+15)); {$ENDIF} case lInHdr.datatype of kDT_UNSIGNED_CHAR : begin //8 bit for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := lBuffer^[lInc]; end; kDT_SIGNED_SHORT{,kDT_UINT16}: begin //16-bit int l16Buf := SmallIntP(lBuffer ); for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := l16Buf^[lInc]; end;//16bit kDT_SIGNED_INT: begin l32Buf := SingleP(lBuffer ); //convert integer to float for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := Conv4r4i(l32Buf^[lInc]); end; //32-bit int kDT_FLOAT: begin l32Buf := SingleP(lBuffer); for lInc := 1 to lImgSamples do lImgBuffer[lInc] := l32Buf[lInc]; for lInc := 1 to lImgSamples do if specialsingle(lImgBuffer^[lInc]) then lImgBuffer^[lInc] := 0.0; //invert= for lInc := 1 to lImgSamples do l32Buf[lInc] := -l32Buf[lInc]; end; //32-bit float else begin dcmMsg('Serious error: format not supported by Crop3D.'); exit; end; end; //case FindDVCrop (lInHdr, lImgBuffer, lDorsalCrop,lVentralCrop, 5); FindDVCrop2 (lInHdr, lDorsalCrop,lVentralCrop); FindLRCrop (lInHdr, lImgBuffer, lLCrop,lRCrop,3,lDorsalCrop,lVentralCrop);//3% often sagittal scans near brain FindAPCrop (lInHdr, lImgBuffer, lACrop,lPCrop, 5,lDorsalCrop,lVentralCrop); FreeMem(lBuffUnaligned); if (lDorsalCrop = 0) and (lVentralCrop = 0) and (lLCrop = 0) and (lRCrop = 0) and (lACrop = 0) and (lPCrop = 0) then begin dcmMsg('Crop 3D quitting: no need to delete slices.'); Freemem(lSrcBuffer); exit; //25 Sept 2008 end; if (lDorsalCrop < 0) or (lVentralCrop < 0) or (lLCrop < 0) or (lRCrop < 0) or (lACrop < 0) or (lPCrop < 0) then begin dcmMsg('Crop 3D quitting: negative values should be impossible.'); beep; Freemem(lSrcBuffer); end; //next compute size of cropped volume lOutHdr.Dim[1] := lInHdr.Dim[1]-lLCrop-lRCrop; lOutHdr.Dim[2] := lInHdr.Dim[2]-lACrop-lPCrop; lOutHdr.Dim[3] := lInHdr.Dim[3]-lDorsalCrop-lVentralCrop; //lVolBytes := lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3]*lBPP; //next: readjust origin to take into account removed slices //REQUIRES images to be aligned to nearest orthogonal to canonical space [1 0 0; 0 1 0; 0 0 1] NIFTIhdr_SlicesToCoord (lInHdr,lLCrop,lPCrop,lVentralCrop, lXmm,lYmm,lZmm); lOutHdr.srow_x[3] := lInHdr.srow_x[3] + lXmm; lOutHdr.srow_y[3] := lInHdr.srow_y[3] + lYmm; lOutHdr.srow_z[3] := lInHdr.srow_z[3] + lZmm; lMat := Matrix3D ( lOutHdr.srow_x[0], lOutHdr.srow_x[1], lOutHdr.srow_x[2], lOutHdr.srow_x[3], lOutHdr.srow_y[0], lOutHdr.srow_y[1], lOutHdr.srow_y[2], lOutHdr.srow_y[3], lOutHdr.srow_z[0], lOutHdr.srow_z[1], lOutHdr.srow_z[2], lOutHdr.srow_z[3], 0, 0, 0, 1); nifti_mat44_to_quatern( lMat, lOutHdr.quatern_b,lOutHdr.quatern_c,lOutHdr.quatern_d, lOutHdr.qoffset_x,lOutHdr.qoffset_y,lOutHdr.qoffset_z, lXmm, lYmm, lZmm, lOutHdr.pixdim[0]{QFac}); //note we write and read to the same buffer - we will always SHRINK output //no need to byteswap data - we will save in the save format as stored lOutPos := 0; lInSliceSz := lInHdr.dim[1]*lInHdr.dim[2]*lBPP; lInXSz := lInHdr.dim[1]*lBPP; for lZ := 1 to lOutHdr.dim[3] do begin lInZOffset := (lVentralCrop+lZ-1) * lInSliceSz; for lY := 1 to lOutHdr.dim[2] do begin lInYOffset := ((lPCrop+lY-1) * lInXSz) + lInZOffset + (lLCrop*lBPP); for lX := 1 to lOutHdr.dim[1] do begin for lB := 1 to lBPP do begin inc(lOutPos); lInPos := ((lX-1) * lBPP) + lInYOffset + lB; lBuffer^[lOutPos] := lBuffer^[lInPos]; end; end; end; //for Y end; //for Z lOutname := ChangeFilePrefix (lFileName,'c'); result := SaveNIfTICore (lOutName, lSrcBuffer, kNIIImgOffset+1, lOutHdr, lPrefs); Freemem(lSrcBuffer); end; (*function CropNIfTI(lFilename: string; lPrefs: TPrefs): string; var lTempName,lExt,lNameWOExt: string; lHdr: TNIFTIhdr; lByteSwap: boolean; begin result := ''; lExt := UpCaseExt(lFilename); if not NIFTIhdr_LoadHdr (lFilename, lHdr, lByteSwap) then begin dcmMsg('Unable to read as NifTI/Analyze' + lFilename); exit; end; //check orthogonal alignment.... if lHdr.dim[4] > 1 then begin dcmMsg('Only able to Crop 3D images (reorienting 4D could disrupt slice timing and diffusion directions.'); exit; end; //next - determine output format if lExt = '.NII.GZ' then begin //lTempName := lFilename;//ChangeFilePrefixExt (lFileName,'x'); ExtractFileParts (lFileName, lNameWOExt,lExt); lTempName := lNameWOExt+'.nii'; Gunzip(lFileName,lTempName); lFilename := lTempName; end else //not gzip lTempName := ''; //Next create reordered or trimmed image in the correct format result := Crop(lFileName, lHdr,lByteSwap, lPrefs.SPM2,lPrefs.SingleNIIFile, false); if (result <> '') and (lPrefs.GZip) then begin GZipFile(lFileName,lFileName+'.gz',true); result := result +'.gz'; end; if lTempName <> '' then //delete GZip temp deletefile(lTempName); end; *) function SiemensPhase2RadiansNIfTI(lFilename: string; lPrefs: TPrefs): string; //convert any data format as 32-bit float.... var lInHdr,lOutHdr: TNIFTIhdr; lOutname,lExt: string; lMax,lMin,lImgSamples,lInc,lImgOffset: integer; lSrcBuffer,lBuffer, lBuffUnaligned,lBuffAligned: bytep; //l32Buf, lImgBuffer: singlep; l16Buf : SmallIntP; lO: TNIIOpts; begin result := ''; lExt := UpCaseExt(lFilename); if not NIFTIhdr_LoadHdr (lFilename, lInHdr, lO) then begin dcmMsg('Unable to read as NifTI/Analyze' + lFilename); exit; end; if lInHdr.datatype <> kDT_SIGNED_SHORT then begin dcmMsg('Unable to run SiemensPhase2Radians : input image must be 16-bit NIfTI image with intensities 0..4096 corresponding to -pi..+pi : '+lFilename); exit; end; //dcmMsg('SiemensPhase2Radians converting 16-bit image (0..4095) to 32-bit float (-pi..+pi).'+lFileName); lOutHdr := lInHdr; lOutHdr.datatype := kDT_FLOAT; lOutHdr.bitpix := 32; lOutHdr.scl_slope := 1; lOutHdr.scl_inter := 0; lImgSamples := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]*lInHdr.dim[4]; if not NIFTIhdr_LoadImg (lFileName, lInHdr, lSrcBuffer, lImgOffset,lO) then exit; lBuffer := (@lSrcBuffer^[lImgOffset+1]); GetMem(lBuffUnaligned ,(sizeof(single)*lImgSamples) + 16+kNIIImgOffset); {$IFDEF FPC} lBuffAligned := align(lBuffUnaligned,16); {$ELSE} lBuffAligned := ByteP($fffffff0 and (integer(lBuffUnaligned)+15)); {$ENDIF} lInc := 1; lImgBuffer := SingleP(@lBuffAligned^[kNIIImgOffset+lInc]); l16Buf := SmallIntP(lBuffer ); lMax := l16Buf^[1]; for lInc := 1 to lImgSamples do if l16Buf^[lInc] > lMax then lMax := l16Buf^[lInc]; lMin := l16Buf^[1]; for lInc := 1 to lImgSamples do if l16Buf^[lInc] < lMin then lMin := l16Buf^[lInc]; if (lMin < 0) or (lMax > 4096) then dcmMsg('Error: SiemensPhase2Radians expects input data with raw intensity ranging from 0..4096 (corresponding to -pi..+pi) - this image''s intensity is not in these bounds'+lFileName) else begin dcmMsg('SiemensPhase2Radians converting 0..4096 to -pi..+pi '+ lFilename); //Excel formula =((A1-2048)/2048)*PI() //fx(lMin,lMax); for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := ((l16Buf^[lInc]-2048)/2048)*pi; lOutname := ChangeFilePrefix (lFileName,'rad'); result := SaveNIfTICore (lOutName, lBuffAligned, kNIIImgOffset+1, lOutHdr, lPrefs); end; Freemem(lBuffUnaligned); Freemem(lSrcBuffer); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/convert.pas������������������������������������������������0000755�0001750�0001750�00000212212�12377623374�017733� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit convert; {$H+} interface uses {$IFNDEF UNIX} Windows, {$ENDIF} {$IFDEF FPC} gzio2, {$ELSE} {$ENDIF} filename,define_types,classes,SysUtils,dicom,dicomtypes, nifti_types, niftiutil,GraphicsMathLibrary, userdir,csaread,dialogs_msg, math, nii_4dto3d,nii_orient,nii_crop,prefs,lsjpeg, bvec; function Dicom2NII(var lDICOMra: TDICOMrap; lFirstDICOM, lLastDICOM: integer; var lOutDirOrig: string; var lPrefs: TPrefs; lVols: integer): boolean; implementation uses sortdicom,dialogsx; function getDeterminant(r: TMatrix): double; var r11,r12,r13,r21,r22,r23,r31,r32,r33: double; begin r11 := r.matrix[1,1];//[0][0]; r12 := r.matrix[1,2];//r[0][1]; r13 := r.matrix[1,3];//r[0][2]; r21 := r.matrix[2,1];//[0][0]; r22 := r.matrix[2,2];//r[0][1]; r23 := r.matrix[2,3];//r[0][2]; r31 := r.matrix[3,1];//[0][0]; r32 := r.matrix[3,2];//r[0][1]; r33 := r.matrix[3,3];//r[0][2]; result := r11*r22*r33 - r11*r32*r23 - r21*r12*r33 + r21*r32*r13 + r31*r12*r23 - r31*r22*r13; end; function RealToStr(lR: double ; lDec: integer): string; begin RealTOStr := FloatToStrF(lR, ffFixed,7,lDec); end; function UniqueFileName (var lInStr: string): boolean; var lInc: integer; lPathWName,lExt: string; begin result := true; if not Fileexists(lInStr) then exit; ExtractFileParts(lInStr,lPathWName,lExt); lInc := ord('A'); while (lInc <= ord('Z')) and ( Fileexists(lPathWName+chr(lInc)+lExt)) do inc(lInc); if lInc > ord('Z') then result := false else lInStr := lPathWName+chr(lInc)+lExt; end; FUNCTION Diag2D (CONST m1,m2,m3: DOUBLE): TMatrix; BEGIN WITH RESULT DO BEGIN matrix[1,1] := m1; matrix[1,2] := 0; matrix[1,3] := 0; matrix[2,1] := 0; matrix[2,2] := m2; matrix[2,3] := 0; matrix[3,1] := 0; matrix[3,2] := 0; matrix[3,3] := m3; size := size2D END END {Diag2D}; FUNCTION Diag3D (CONST m1,m2,m3,m4: DOUBLE): TMatrix; BEGIN WITH RESULT DO BEGIN matrix[1,1] := m1; matrix[1,2] := 0; matrix[1,3] := 0; matrix[1,4] := 0; matrix[2,1] := 0; matrix[2,2] := m2; matrix[2,3] := 0; matrix[2,4] := 0; matrix[3,1] := 0; matrix[3,2] := 0; matrix[3,3] := m3; matrix[3,4] := 0; matrix[4,1] := 0; matrix[4,2] := 0; matrix[4,3] := 0; matrix[4,4] := m4; size := size3D END END {Diag3D}; (*procedure AdjMosaic (var Q: TMatrix; var lDicomData: DicomData); //Changes suggested by Antonin Skoch" <ansk@medicon.cz<mailto:ansk@medicon.cz>> // September 23, 2011 10:38:05 AM var lFactorX: double; lFactorY: double; begin lFactorX := (lDicomData.XYZdim[1] -(lDicomData.XYZdim[1]/lDicomData.SiemensMosaicX) )/2; lFactorY := (lDicomData.XYZdim[2] -(lDicomData.XYZdim[2]/lDicomData.SiemensMosaicY) )/2; Q.matrix[1,4] :=(Q.matrix[1,1]*lFactorX)+(Q.matrix[1,2]*lFactorY)+Q.matrix[1,4]; Q.matrix[2,4] :=(Q.matrix[2,1]*lFactorX)+(Q.matrix[2,2]*lFactorY)+Q.matrix[2,4]; Q.matrix[3,4] :=(Q.matrix[3,1]*lFactorX)+(Q.matrix[3,2]*lFactorY)+Q.matrix[3,4]; end; *) (*procedure get_numaris4_val(lFilename,lTagName1,lTagName2: string; var lnmosaic: integer; var lv1,lv2,lv3:single); // spm_dicom_convert label 121; const kMaxHdrSz = 24000; var lHdr : array [1..kMaxHdrSz] of Char; lTagName,lStr: string; lLoop,lFileSz,lFilePos,lTagLen,lSubLoop,lnSubloop: integer; lFile: file; function IsTag: boolean; var lTagPos: integer; begin result := false; for lTagPos := 1 to lTagLen do if lHdr[lFilePos+lTagPos-1] <> lTagName[lTagPos] then exit; result := true; end; function IsNumber: boolean; begin if lHdr[lFilePos] in ['-','.','0'..'9'] then result := true else result := false; end; begin lnmosaic := 0;//detect if function found header if not fileexists(lFilename) then exit; FileMode := 0; //set to readonly AssignFile(lFile, lFileName); Reset(lFile, 1); lFileSz := FileSize(lFile); if lFileSz > kMaxHdrSz then lFileSz := kMaxHdrSz; if lFilesz < (2000) then begin //to small to be DICOM mosaic CloseFile(lFile); Filemode := 2; exit; end; BlockRead(lFile, lHdr, lFileSz*SizeOf(Char)); FileMode := 0; //set to readonly CloseFile(lFile); lFilePos := 1; for lLoop := 1 to 2 do begin if lLoop = 1 then begin lnSubloop := 1; lTagName := lTagName1; end else begin lnSubloop := 3; lTagName := lTagName2; end; lTagLen := length (lTagName); while (lFilePos < (lFileSz-lTagLen)) and (not (IsTag)) do inc(lFilePos); if (lFilePos >= (lFileSz-lTagLen)) then exit; lFilePos := lFilePos + 72; //lots of space between name and value for lSubloop := 1 to lnSubloop do begin while (lFilePos < (lFileSz)) and (not (IsNumber)) do inc(lFilePos); if (lFilePos >= (lFileSz-lTagLen)) then exit; lStr :='';// lHdr[lFilePos]; while (lFilePos < (lFileSz)) and (IsNumber) do begin lStr := lStr+lHdr[lFilePos]; inc(lFilePos); end; if lStr = '' then exit; if lLoop = 1 then lnmosaic := strtoint(lStr) else begin case lSubloop of 1: lv1 := strtofloat(lStr); 2: lv2 := strtofloat(lStr); 3: lv3 := strtofloat(lStr); end; //case end; //else end; //sublooop end; //loop end; *) function IsNormalMosaic(var lDicomData: DicomData; var lMosaicSlices: integer; var lFilename: string): boolean; var Q: TMatrix; lX,lY,lnmos,lImagesPerRow: integer; lv1,lv2,lv3: double; begin lX := lDICOMdata.SiemensMosaicX; lY := lDICOMdata.SiemensMosaicY; result := false; lMosaicSlices := lDICOMdata.SiemensSlices; if lMosaicSlices = 0 then lMosaicSlices := lDICOMdata.SiemensMosaicX*lDICOMdata.SiemensMosaicY; if (lDICOMdata.SiemensMosaicX < 1) then exit; //not mosaic if (lDICOMdata.SiemensSlices > 0) then exit; //pre-Trio Siemens Mosaic Data if not GetCSAImageHeaderInfo (lFilename, lDicomData.CSAImageHeaderInfoPos ,lDicomData.CSAImageHeaderInfoSz, lnmos,lDicomData.SiemensMosaicX,lDicomData.SiemensMosaicY, lv1,lv2,lv3) then begin lDICOMdata.SiemensMosaicX := lX; lDICOMdata.SiemensMosaicY := lY; lMosaicSlices := lX * lY; exit; end; if lnmos < 1 then exit; //4/4/2008 I used to read AcquisitionMatrixText from CSA Image Header... however this is a problem if the images are interpolated lImagesPerRow := 1; while sqr(lImagesPerRow) < lnMos do inc(lImagesPerRow); lDICOMdata.SiemensMosaicX := lDicomData.XYZdim[1] div lImagesPerRow; lDICOMdata.SiemensMosaicY := lDicomData.XYZdim[2] div lImagesPerRow; //29Sept2008 //fx(lDicomData.XYZdim[1],lDicomData.XYZdim[2],lnmos,lDICOMdata.SiemensMosaicY); lDicomData.SiemensMosaicX := lDicomData.XYZdim[1] div lDICOMdata.SiemensMosaicX; lDicomData.SiemensMosaicY := lDicomData.XYZdim[2] div lDICOMdata.SiemensMosaicY; //get_numaris4_val(lFilename,'NumberOfImagesInMosaic','SliceNormalVector',lnmos,lv1,lv2,lv3); //b13 Q := Matrix2D(lDicomData.Orient[1], lDicomData.Orient[4],lv1, lDicomData.Orient[2],lDicomData.Orient[5],lv2, lDicomData.Orient[3],lDicomData.Orient[6],lv3); if nifti_mat33_determ(Q) < 0 then begin //dcmMsg('Note: raw slice order R>>L (Siemens convention), dcm2niiprior to 2014 stored these as L>>R, NIfTI convention). Benefit: simpler slice timing correction (ascending is 1..N, descending is N..1)'); result := true; end; lMosaicSlices := lnmos; end; function IsSiemensDTI(var lDicomData: DicomData; var lDTI: TDTI;var lFilename: string; var lPrefs: TPrefs): boolean; begin result := false; if (lDICOMdata.SiemensDICOMDTI) and (lDICOMdata.DTI[1].bval >= 0) and (lDicomData.Vers0018_1020 {ImplementationVersion} >= lPrefs.SiemensDTIUse0019If00181020atleast {IgnoreDTIRotationsIf_0002_0013_atleast}) then begin lDTI.Bval := lDICOMdata.DTI[1].bval; ldti.v1 := lDicomData.DTI[1].v1; ldti.v2 := lDicomData.DTI[1].v2; ldti.v3 := lDicomData.DTI[1].v3; result := true; exit; end; if (lDICOMdata.ManufacturerID <> kSiemensID) then exit; if not GetCSAImageHeaderInfoDTI (lFilename, lDicomData.CSAImageHeaderInfoPos ,lDicomData.CSAImageHeaderInfoSz,lDTI.Bval,ldti.v1,ldti.v2,ldti.v3) then //if not GetCSAImageHeaderInfoDTI (lFilename, lDicomData.CSAImageHeaderInfoPos ,lDicomData.CSAImageHeaderInfoSz, lDTI.Bval, ldti.v1,ldti.v2,ldti.v3) then exit; if lDTI.bval >= 0 then begin result := true; lDicomData.SiemensDICOMDTICSA := true; end; //fx(lDTI.bval); end; (*procedure ReportMatrix(s: string; q: TMatrix); begin dcmmsg(s+Format('=[ %g %g %g %g; %g %g %g %g; %g %g %g %g; 0 0 0 1]', [ q.matrix[1,1],q.matrix[1,2],q.matrix[1,3],q.matrix[1,4] , q.matrix[2,1],q.matrix[2,2],q.matrix[2,3],q.matrix[2,4] , q.matrix[3,1],q.matrix[3,2],q.matrix[3,3],q.matrix[3,4]])); end; procedure ReportMat33(s: string; q: TMatrix); begin dcmmsg(s+Format('=[ %g %g %g; %g %g %g; %g %g %g]', [ q.matrix[1,1],q.matrix[1,2],q.matrix[1,3] , q.matrix[2,1],q.matrix[2,2],q.matrix[2,3] , q.matrix[3,1],q.matrix[3,2],q.matrix[3,3]])); end; *) procedure dicom_2_niftiMosaic(var Q44: TMatrix; var d: DicomData; var lHdr: TNiftiHdr ; lMosaicSlices: integer; var lFlipMosaic: boolean); var det: TMatrix; nRowCol,lFactorX,lFactorY: double; c,r: integer; v,vO: TVector; begin nRowCol := ceil(sqrt(lMosaicSlices)); lFactorX := (d.xyzDim[1] -(d.xyzDim[1]/nRowCol) )/2.0; lFactorY := (d.xyzDim[2] -(d.xyzDim[2]/nRowCol) )/2.0; Q44.matrix[1,4] :=(Q44.matrix[1,1]*lFactorX)+(Q44.matrix[1,2]*lFactorY)+Q44.matrix[1,4]; Q44.matrix[2,4] :=(Q44.matrix[2,1]*lFactorX)+(Q44.matrix[2,2]*lFactorY)+Q44.matrix[2,4]; Q44.matrix[3,4] :=(Q44.matrix[3,1]*lFactorX)+(Q44.matrix[3,2]*lFactorY)+Q44.matrix[3,4]; Q44.size := size3D; //ReportMatrix('mega',Q44); for c:=1 to 2 do for r := 1 to 4 do Q44.matrix[c,r] := -Q44.matrix[c,r]; if lFlipMosaic then begin det := Diag3D(1,1,-1,1); Q44 := MultiplyMatrices(Q44,det); end; //next we have flipped images on the Y dimension vO := Vector3D(0,lHdr.dim[2]-1,0); //find coordinate of new origin voxel - located on opposite side of Y-dimension for r := 1 to 3 do begin v.vector[r] := 0; for c :=1 to 4 do v.vector[r] := v.vector[r] + (Q44.matrix[r,c]*vO.vector[c]); end; det := Diag3D(1,-1,1,1); Q44 := MultiplyMatrices(Q44,det); Q44.matrix[1,4] := v.x; Q44.matrix[2,4] := v.y; Q44.matrix[3,4] := v.z; end; procedure dicom_2_nifti(var lDicomData: DicomData; var lHdr: TNiftiHdr ; lMosaicSlices: integer; var lFlipMosaic: boolean); var Q,res,diagVox,patient_to_tal,analyze_to_dicom: TMatrix; lx,ly: integer; val: double; dx,dy,dz: single; lOK: boolean; begin lHdr.sform_code := kNIFTI_XFORM_UNKNOWN; lOK := false; for lx := 1 to 6 do if lDicomData.Orient[lx] <> 0 then lOK := true; if not lOK then exit; Q := Diag3D(1,1,1,1);//set column 4 and row 4 to zeros, except [4,4] Q.matrix[1,1] :=lDicomData.Orient[1] ; Q.matrix[1,2] := lDicomData.Orient[2] ; Q.matrix[1,3] := lDicomData.Orient[3] ; //* load Q */ Q.matrix[2,1] := lDicomData.Orient[4] ; Q.matrix[2,2] := lDicomData.Orient[5] ; Q.matrix[2,3] := lDicomData.Orient[6] ; //ReportMatrix('bar',Q); // normalize row 1 val := Q.matrix[1,1]*Q.matrix[1,1] + Q.matrix[1,2]*Q.matrix[1,2] + Q.matrix[1,3]*Q.matrix[1,3] ; if( val > 0.0 ) then begin val := 1.0 / sqrt(val) ; Q.matrix[1,1] := Q.matrix[1,1]* val ; Q.matrix[1,2] := Q.matrix[1,2]* val ; Q.matrix[1,3] := Q.matrix[1,3]* val ; end else begin Q.matrix[1,1] := 1.0 ; Q.matrix[1,2] := 0.0 ; Q.matrix[1,3] := 0.0 ; end; // normalize row 2 val := Q.matrix[2,1]*Q.matrix[2,1] + Q.matrix[2,2]*Q.matrix[2,2] + Q.matrix[2,3]*Q.matrix[2,3] ; if( val > 0.0 ) then begin val := 1.0 / sqrt(val) ; Q.matrix[2,1] := Q.matrix[2,1]* val ; Q.matrix[2,2] := Q.matrix[2,2]* val ; Q.matrix[2,3] := Q.matrix[2,3]* val ; end else begin Q.matrix[2,1] := 0.0 ; Q.matrix[2,2] := 1.0 ; Q.matrix[2,3] := 0.0 ; end; //ReportMat33('norm',Q); //row 3 is cross product of previous rows Q.matrix[3,1] := Q.matrix[1,2]*Q.matrix[2,3] - Q.matrix[1,3]*Q.matrix[2,2] ; Q.matrix[3,2] := Q.matrix[1,3]*Q.matrix[2,1] - Q.matrix[1,1]*Q.matrix[2,3] ; Q.matrix[3,3] := Q.matrix[1,1]*Q.matrix[2,2] - Q.matrix[1,2]*Q.matrix[2,1] ; res := Diag3D(1,1,1,1); //set forth column/row //next: transpose matrix for lx := 1 to 3 do for ly := 1 to 3 do res.matrix[lx,ly] := Q.matrix[ly,lx]; Q := res; //next if det(orient)<0, orient(:,3) = -orient(:,3); end; //showmessage(realtostr(getDeterminant(Q),2)); if getDeterminant(Q) < 0 then begin Q.matrix[1,3] := -Q.matrix[1,3]; Q.matrix[2,3] := -Q.matrix[2,3]; Q.matrix[3,3] := -Q.matrix[3,3]; end; //reportMatrix('preScale',Q); //next scale matrix diagVox := Diag2D(lDicomData.XYZmm[1],lDicomData.XYZmm[2],lDicomData.XYZmm[3]); Q.size := size2D; Q := MultiplyMatrices(Q,diagVox); //reportMatrix('postScale',Q); //next - add translations Q.matrix[1,4] := lDicomData.PatientPosX; Q.matrix[2,4] := lDicomData.PatientPosY; Q.matrix[3,4] := lDicomData.PatientPosZ; //reportMatrix('postOffset',Q); if (lDICOMdata.SiemensMosaicX > 1) or (lDICOMdata.SiemensMosaicY > 1) then begin dicom_2_niftiMosaic(Q, lDicomData, lHdr, lMosaicSlices, lFlipMosaic); end else begin val := lDicomData.XYZdim[2]; (*if (lDICOMdata.SiemensMosaicX > 1) or (lDICOMdata.SiemensMosaicY > 1) then begin AdjMosaic(Q,lDICOMdata); val := lDicomData.XYZdim[2]/lDICOMdata.SiemensMosaicY; //lFlipMosaic := IsNormalMosaic(lDicomData,lMosaicSlices,lFilename); end; *) Q.matrix[4,1] := 0; Q.matrix[4,2] := 0; Q.matrix[4,3] := 0; Q.matrix[4,4] := 1; Q.size := size3D; //Q now equals 'dicom_to_patient' in spm_dicom_convert //result := q; exit; //escape to compare with SPM //next - convert space patient_to_tal := diag3D(-1, -1, 1,1); analyze_to_dicom := Matrix3D ( 1, 0, 0,-1, 0,-1, 0, val, 0, 0, 1,-1, 0, 0, 0, 1); //reportMatrix('d2pat',Q); //reportmatrix('p2tal',patient_to_tal); //reportMatrix('a2d',analyze_to_dicom); Q := MultiplyMatrices(patient_to_tal,Q); //reportMatrix('postTal',Q); Q := MultiplyMatrices(Q,analyze_to_dicom); //reportMatrix('mat',Q); //Q now equals 'mat' in spm_dicom_convert //subasgn.m in SPM5 translates by one voxel... analyze_to_dicom := Matrix3D ( 1, 0, 0,1, 0,1, 0, 1, 0, 0,1,1, 0, 0, 0, 1); Q := MultiplyMatrices(Q,analyze_to_dicom);//not used for flips (*if ((lDICOMdata.SiemensMosaicX > 1) or (lDICOMdata.SiemensMosaicY > 1)) and (lFlipMosaic) then begin patient_to_tal := diag3D(1, 1, 1,1); patient_to_tal.matrix[3,4] := 1-lMosaicSlices; Q := MultiplyMatrices(Q,patient_to_tal); end else if ((lDICOMdata.SiemensMosaicX > 1) or (lDICOMdata.SiemensMosaicY > 1)) and (getDeterminant(Q) < 0) then begin //patient_to_tal := diag3D(1, 1, 1,1); //patient_to_tal.matrix[3,4] := 1-lMosaicSlices; patient_to_tal := diag3D(1, 1, -1,1); Q := MultiplyMatrices(Q,patient_to_tal); end; *) end; //if mosaic else not mosaic //if (lDICOMdata.SiemensMosaicX = 1) and (lDICOMdata.SiemensMosaicY = 1) then //reportmatrix('final',Q); //mat44_to_quatern(Q); *) //reportMatrix('nii',Q); lHdr.sform_code := kNIFTI_XFORM_SCANNER_ANAT; lHdr.srow_x[0] := Q.matrix[1,1]; lHdr.srow_x[1] := Q.matrix[1,2]; lHdr.srow_x[2] := Q.matrix[1,3]; lHdr.srow_x[3] := Q.matrix[1,4]; lHdr.srow_y[0] := Q.matrix[2,1]; lHdr.srow_y[1] := Q.matrix[2,2]; lHdr.srow_y[2] := Q.matrix[2,3]; lHdr.srow_y[3] := Q.matrix[2,4]; lHdr.srow_z[0] := Q.matrix[3,1]; lHdr.srow_z[1] := Q.matrix[3,2]; lHdr.srow_z[2] := Q.matrix[3,3]; lHdr.srow_z[3] := Q.matrix[3,4]; //finally, create Quat from matrix lHdr.qform_code := kNIFTI_XFORM_SCANNER_ANAT; nifti_mat44_to_quatern( Q, lHdr.quatern_b,lHdr.quatern_c,lHdr.quatern_d, lHdr.qoffset_x,lHdr.qoffset_y,lHdr.qoffset_z, dx, dy, dz, lHdr.pixdim[0]{QFac}); //msgq(lHdr.quatern_b,lHdr.quatern_c,lHdr.quatern_d,lHdr.qoffset_x,lHdr.qoffset_y,lHdr.qoffset_z); end; (*function CountOrders(var lDICOMdata: dicomdata): integer; //for 4D files, if you have 'M'agnitude and 'Phase' maps in order M M P P M P this will return 1 1 2 2 1 2 const kTypes = 10; var ltype,i: integer; noveltype: array [1..kTypes] of boolean; begin result := 0; for i := 1 to kTypes do noveltype[i] := true; for i := 1 to lDICOMdata.nOrder do begin ltype := lDICOMdata.order[i]; if (ltype < 1) or (lType > kTypes) then lType := 1; if (noveltype[ltype])then inc(result); //we found a new order... noveltype[ltype] := false; end; end;*) (*function SortOrders(var lDICOMdata: dicomdata; var lImageOrder: bytep): integer; //for 4D files, if you have 'M'agnitude and 'Phase' maps in order M M P P M P this will return 1 1 2 2 1 2 const kTypes = 10; var ltype,i: integer; noveltype: array [1..kTypes] of boolean; begin result := 0; for i := 1 to kTypes do noveltype[i] := true; getmem(lImageOrder,lDICOMdata.nOrder); for i := 1 to lDICOMdata.nOrder do begin ltype := lDICOMdata.order[i]; if (ltype < 1) or (lType > kTypes) then lType := 1; lImageOrder^[i] := lType; if (noveltype[ltype])then inc(result); //we found a new order... noveltype[ltype] := false; end; end; function CountOrders(var lDICOMdata: dicomdata): integer; var lImageOrder: bytep; begin if (lDICOMdata.nOrder < 1) then exit; result := SortOrders(lDICOMdata,lImageOrder); freemem(lImageOrder); end; function ParseOrder(var lDICOMdataAllTypes,lDICOMdataSelectedType: dicomdata; lSelectedType: integer): integer; var lnTypes: integer; lImageOrder: bytep; begin lDICOMdataSelectedType := lDICOMdataAllTypes; if (lDICOMdataAllTypes.nOrder < 1) then exit; lnTypes := SortOrders(lDICOMdataAllTypes,lImageOrder); if lnTypes <= lSelectedType then begin TDTIRA = array [1..kMaxDTIDir] of TDTI;//TDICOM;//unsigned 8-bit int TOrder= array [1..kMaxOrderVal] of byte; end; freemem(lImageOrder); end; *) ///321 function MultiOrder(var lDICOMdata: dicomdata): integer; //how many slices are of the same type [magnitude, phase, etc] //returns 0 if all types are the same var i: integer; begin result := 0; if (lDICOMdata.nOrder < 1) then exit; if (lDicomData.XYZdim[3] > kMaxOrderVal) then exit; result := 0; for i := 1 to lDICOMdata.nOrder do begin if lDICOMdata.order[i] = lDICOMdata.order[1] then inc(result); //count how many have the same order as first... end; if result = lDICOMdata.nOrder then result := 0; //all are like the first end; function CompressMultiOrder(var lDICOMdata: dicomdata): integer; //convert multiorder so values are 1..n, //e.g. if the values were 2,3,4 it would be converted to 1..3 //e.g. if the values are 3,4 it will be converted to 1..2 var min,max,i,j: integer; SlotUsed: boolean; begin result := 1; if (lDICOMdata.nOrder < 1) then exit; if (lDicomData.XYZdim[3] > kMaxOrderVal) then exit; min := lDICOMdata.order[1]; for i := 1 to lDICOMdata.nOrder do if lDICOMdata.order[i] < min then min := lDICOMdata.order[i]; //count how many have the same order as first... max := lDICOMdata.order[1]; for i := 1 to lDICOMdata.nOrder do if lDICOMdata.order[i] > max then max := lDICOMdata.order[i]; //count how many have the same order as first... result := 1; for j := min to max do begin SlotUsed := false; for i := 1 to lDICOMdata.nOrder do begin if lDICOMdata.order[i] = j then begin SlotUsed := true; lDICOMdata.order[i] := result; end; end;//for each value if SLotUsed then inc(result); end; result := result - 1; end; (*procedure msx (a,b,c,d: integer); begin msg(inttostr(a)+'x'+inttostr(b)+'x'+inttostr(c)+'x'+inttostr(d)); end;*) procedure SwapTimeMultiOrder (var lDICOMdata: dicomdata; var lBuffer: bytep); //data is stored X,Y,T,Z+some order effect (e.g. magnitude and phase stroed in the same 4D image) - swap to O,X,Y,Z,T var Order,nOrders,lSlicesPerOrder,lSlice,l4DBytes,lSliceBytes,lZo,lTo,lZmax,lTmax,lOrderVol:integer; lTempBuffer: ByteP; begin lSlicesPerOrder := MultiOrder(lDICOMdata); if (lSlicesPerOrder = 0) then exit; nOrders := CompressMultiOrder(lDICOMdata); dcmMsg('Swizzling with multiple ComplexImageComponents: '+inttostr(lSlicesPerOrder)+' slices per order, total '+inttostr(lDicomData.XYZdim[3])+' slices'); if not lDICOMdata.file4D then exit; lTMax := lDicomData.XYZdim[3] div lDICOMdata.SlicesPer3DVol div nOrders; lZMax := lDICOMdata.SlicesPer3DVol; l4DBytes := lDicomData.XYZdim[1]*lDicomData.XYZdim[2]*lDicomData.XYZdim[3]*trunc(((lDicomData.Allocbits_per_pixel)+7)/8); lSliceBytes := lDicomData.XYZdim[1]*lDicomData.XYZdim[2]*trunc(((lDicomData.Allocbits_per_pixel)+7)/8); GetMem(lTempBuffer,l4DBytes); Move(lBuffer^,lTempBuffer^,l4DBytes); //move(src,dest,sz) fillchar(lBuffer^,l4DBytes,0);//abba lZo := 0; lTo := 0; lOrderVol := 0; //for lSlice := 1 to lDicomData.XYZdim[3] do //msg(inttostr(lDICOMdata.order[lSLice])); for Order := 1 to nOrders do begin for lSlice := 1 to lDicomData.XYZdim[3] do begin if lDICOMdata.order[lSLice] = Order then begin Move(lTempBuffer[((lSlice-1)*lSliceBytes)+1],lBuffer[(lZo*lSliceBytes)+((lOrderVol+lTo)*lZMax*lSliceBytes)+1],lSliceBytes); inc(lTo); if lTo >= lTMax then begin lTo := 0; inc(lZo); end; end; //desired order end; lOrderVol := lOrderVol + lTMax; lZo := 0; end; freemem(lTempBuffer); end; procedure SwapTime (var lDICOMdata: dicomdata; var lBuffer: bytep); //data is stored X,Y,T,Z - swap to X,Y,Z,T var lSlice,l4DBytes,lSliceBytes,lZo,lTo,lZmax,lTmax:integer; lTempBuffer: ByteP; begin if lDicomData.XYZdim[4] < 2 then exit; if MultiOrder(lDICOMdata) <> 0 then begin SwapTimeMultiOrder (lDICOMdata,lBuffer); exit; end; dcmMsg('Swizzling: XYTZ -> XYZT'); if not lDICOMdata.file4D then exit; lTMax := lDicomData.XYZdim[3] div lDICOMdata.SlicesPer3DVol; lZMax := lDICOMdata.SlicesPer3DVol; l4DBytes := lDicomData.XYZdim[1]*lDicomData.XYZdim[2]*lDicomData.XYZdim[3]*trunc(((lDicomData.Allocbits_per_pixel)+7)/8); lSliceBytes := lDicomData.XYZdim[1]*lDicomData.XYZdim[2]*trunc(((lDicomData.Allocbits_per_pixel)+7)/8); GetMem(lTempBuffer,l4DBytes); Move(lBuffer^,lTempBuffer^,l4DBytes); //move(src,dest,sz) lZo := 0; lTo := 0; for lSlice := 1 to lDicomData.XYZdim[3] do begin Move(lTempBuffer[((lSlice-1)*lSliceBytes)+1],lBuffer[(lZo*lSliceBytes)+(lTo*lZMax*lSliceBytes)+1],lSliceBytes); inc(lTo); if lTo >= lTMax then begin lTo := 0; inc(lZo); end; end; freemem(lTempBuffer); end; procedure FlipTB (var lDICOMdata: dicomdata; var lBuffer: bytep); var l16Buf : SmallIntP; l32Buf : SingleP; lSwap16: SmallInt; lSwap32: Single; lSwap8: byte; lXPos,lYPos,lZPos,lX,lY,lZ,lHlfY,lDecLineOffset,lLineOffset: integer; begin lX := lDicomData.XYZdim[1]; lY := lDicomData.XYZdim[2]; lZ := lDicomData.XYZdim[3]; if lDicomData.SamplesPerPixel = 3 then lZ := lZ * 3; if (lY < 2) then exit; lHlfY := lY div 2; if lDicomData.Allocbits_per_pixel = 8 then begin for lZPos := 1 to lZ do begin lLineOffset := (lZPos-1)*(lX*lY); lDecLineOffset := lLineOffset+(lX*lY)-lX; for lYPos := 1 to lHlfY do begin for lXPos := 1 to lX do begin lSwap8 := lBuffer^[lXPos+lLineOffset]; lBuffer^[lXPos+lLineOffset] := lBuffer^[lXPos+lDecLineOffset]; lBuffer^[lXPos+lDecLineOffset] := lSwap8; end; //for X lLineOffset := lLineOffset + lX; lDecLineOffset := lDecLineOffset - lX; end; //for Y end; //for Z end else if lDicomData.Allocbits_per_pixel = 32 then begin l32Buf := SingleP(lBuffer); for lZPos := 1 to lZ do begin lLineOffset := (lZPos-1)*(lX*lY); lDecLineOffset := lLineOffset+(lX*lY)-lX; for lYPos := 1 to lHlfY do begin for lXPos := 1 to lX do begin lSwap32 := l32Buf^[lXPos+lLineOffset]; l32Buf^[lXPos+lLineOffset] := l32Buf^[lXPos+lDecLineOffset]; l32Buf^[lXPos+lDecLineOffset] := lSwap32; end; //for X lLineOffset := lLineOffset + lX; lDecLineOffset := lDecLineOffset - lX; end; //for Y end; //for Z end else begin l16Buf := SmallIntP(lBuffer); for lZPos := 1 to lZ do begin lLineOffset := (lZPos-1)*(lX*lY); lDecLineOffset := lLineOffset+(lX*lY)-lX; for lYPos := 1 to lHlfY do begin for lXPos := 1 to lX do begin lSwap16 := l16Buf^[lXPos+lLineOffset]; l16Buf^[lXPos+lLineOffset] := l16Buf^[lXPos+lDecLineOffset]; l16Buf^[lXPos+lDecLineOffset] := lSwap16; end; //for X lLineOffset := lLineOffset + lX; lDecLineOffset := lDecLineOffset - lX; end; //for Y end; //for Z end; end; //proc FlipTB procedure MakePlanar (var lBuffer: bytep; var lDicomData: DICOMdata); //data is saved as RGBRGBRGB - convert to RRRR GGGG BBBB var lRA: bytep; lPix,lnPix,lSlice,lI: integer; begin if (lDicomData.XYZdim[1] < 1) or (lDicomData.XYZdim[2] < 1) or (lDicomData.XYZdim[3] < 1) then exit; lnPix := lDicomData.XYZdim[1]*lDicomData.XYZdim[2]; //*lDicomData.XYZdim[3] GetMem(lRA,3*lnPix); //*3 as red, green, blue for lSlice := 1 to lDicomData.XYZdim[3] do begin lI := 1 + ((lSlice-1)* (3*lnPix)); //data from input slice for lPix := 1 to lnPix do begin lRA^[lPix] := lBuffer^[lI]; //red plane inc(lI); lRA^[lPix+lnPix] := lBuffer^[lI]; //green plane inc(lI); lRA^[lPix+lnPix+lnPix] := lBuffer^[lI]; //blue plane inc(lI); end; Move(lRA^,lBuffer^[1 + ((lSlice-1)* (3*lnPix))],3*lnPix); end; Freemem(lRA); end; procedure DeMosaic (var lBuffer: bytep;lmosX,lmosY,lSlices: integer; lFlip: boolean; var lDicomData: DICOMdata); //unMosaic var lPos,lH,lW,lnMos,lMos,lMosW,lMosH, lStripBytes,lPanelBytes,lStartOffset: integer; lTempBuffer: ByteP; begin lnMos := lSlices;// lDICOMdata.SiemensMosaicX*lDICOMdata.SiemensMosaicY; if (lmosX < 2) and (lmosY < 2) then exit; if ((lmosX*lmosY) < lSlices) then begin dcmMsg('This '+inttostr(lmosx)+'*'+inttostr(lmosy)+' mosaic can not hold '+inttostr(lSlices)+' slices.'); exit; end; lMosW := lDICOMdata.XYZdim[1] div lmosX; lMosH := lDICOMdata.XYZdim[2] div lmosY; lStripBytes := lMosW*trunc(((lDicomData.Allocbits_per_pixel)+7)/8); lPanelBytes := lDICOMdata.XYZdim[1] *trunc(((lDicomData.Allocbits_per_pixel)+7)/8); GetMem(lTempBuffer,lPanelBytes*lDICOMdata.XYZdim[2]); Move(lBuffer^,lTempBuffer^,lPanelBytes*lDICOMdata.XYZdim[2]); //lImgBytes := (lPanelBytes*lDICOMdata.XYZdim[2]); lPos := 0; if lFlip then begin dcmmsg('*** WARNING: CSA "ProtocolSliceNumber" SUGGESTS REVERSED SLICE ORDER: SPATIAL AND DTI COORDINATES UNTESTED ****'); dcmmsg('*** SOLUTION: open sequence on scanner, go to System tab, select Miscellaneous sub-tab, set default image numbering (F>>H, R>>L, A>>P'); dcmmsg('*** If this is impossible and you wish to use these sequences for DTI please conduct DTI validation described on the dcm2nii web page'); end; (* for lMos := lnMos downto 1 do begin lStartOffset := ((lMos-1) mod lmosX)*lStripBytes+ ( ((lMos-1) div lmosX)* (lPanelBytes*lMosH)); for lH := 1 to lMosH do begin for lW := 1 to lStripBytes do begin inc(lPos); lBuffer^[lPos] := lTempBuffer^[lStartOffset+lW ]; end; //lBuffer^[lPos-1] := 255;//crx lStartOffset := lStartOffset + lPanelBytes; end; end; end else *)begin for lMos := 1 to lnMos do begin lStartOffset := ((lMos-1) mod lmosX)*lStripBytes+ ( ((lMos-1) div lMosX)* (lPanelBytes*lMosH)); for lH := 1 to lMosH do begin for lW := 1 to lStripBytes do begin inc(lPos); lBuffer^[lPos] := lTempBuffer^[lStartOffset+lW ]; end; //lBuffer^[lPos-1] := 255;//crx lStartOffset := lStartOffset + lPanelBytes; end; end; end; FreeMem(lTempBuffer); //FlipTB needs new coordinates lDicomData.XYZdim[1] := lMosW; lDicomData.XYZdim[2] := lMosH; lDicomData.XYZdim[3] := lnMos; FlipTB (lDICOMdata, lBuffer); end; function UnInterleaved (lVal, ln3D,ln4D: integer;lFLip: boolean): integer; var lVol,lSlice,lOut: integer; begin lSlice := ((lVal-1) mod ln3D) ; lVol := ((lVal-1) div ln3D) ; if lFlip then lSlice := ln3D-lSlice-1; lOut := (lSlice*ln4D)+lVol; //if lVol = 1 then Msg(inttostr(lSlice)+' '+inttostr(lVol)+' '+inttostr(lOut)); result := lOut; end; function UnFlip (lVal, ln3D: integer): integer; var lVol: integer; begin lVol := ((lVal-1) div ln3D); result := lVal-((lVol)*ln3d);//{ln3D -} (lVal-((lVol-1)*ln3d)); result := ((lVol+1)*ln3D) - result; end; function CheckSliceDirection( var lD1,lD2: dicomdata):boolean; var lFloat: single; begin result := false; lFloat := (ld2.PatientPosX-ld1.PatientPosX)-(ld2.PatientPosY-ld1.PatientPosY)-(ld2.PatientPosZ-ld1.PatientPosZ); if lFloat > 0 then result := true; //if result then Msg('yikes'+floattostr(ld2.PatientPosX-ld1.PatientPosX)+'y'+floattostr(ld2.PatientPosY-ld1.PatientPosY)+'z'+floattostr(ld2.PatientPosZ-ld1.PatientPosZ) ); end; function Index (lSeries,lFirstDICOM: integer; lInterleaved,lFlip: boolean; var lAHdr: TNIFTIhdr ): integer; begin if lInterleaved then result := UnInterleaved (lSeries, lAHdr.dim[3],lAHdr.dim[4],lFlip) else if not lFlip then result := lSeries-1 else result := UnFlip (lSeries, lAHdr.dim[3]); result := result + lFirstDICOM; end; procedure SiemensFlipYBvecs (var lDTIra: TDTIra; nVec: integer); var lI: integer; V: double; begin if nVec < 1 then exit; for lI := 1 to nVec do begin if lDTIra[lI].v2 <> 0 then //people do not like seeing -0, even though this is a valid ieee value lDTIra[lI].v2 := -lDTIra[lI].v2; end; //next: normalize for lI := 1 to nVec do begin V := sqr(lDTIra[lI].v1)+ sqr(lDTIra[lI].v2)+sqr(lDTIra[lI].v3); if V = 0 then V := 1 else V := sqrt(V); lDTIra[lI].v1 := lDTIra[lI].v1/V; lDTIra[lI].v2 := lDTIra[lI].v2/V; lDTIra[lI].v3 := lDTIra[lI].v3/V; end; end; procedure GECorrectBvecs (var lDICOMdata:dicomdata; var lDTIra: TDTIra; nVec: integer); //0018,1312 phase encoding is either in row or column direction //0043,1039 (or 0043,a039). b value (as the first number in the string). //0019,10bb (or 0019,a0bb). Phase-gradient diffusion direction //0019,10bc (or 0019,a0bc). Frequency-gradient diffusion direction //0019,10bd (or 0019,a0bd). Slice diffusion direction //If 0018,1312 = Col then X=-x0bb, Y=x0bc, Z=x0bd, //If 0018,1312 = Row then X=-x0bc, Y=-x0bb, Z=x0bd, var lI: integer; lCol: boolean; lSwap: double; begin if nVec < 1 then exit; if (length(lDicomData.PatientPos) >= 3) and (lDicomData.PatientPos[1] = 'H') and (lDicomData.PatientPos[2] = 'F') and (lDicomData.PatientPos[3] = 'S') then else begin dcmMsg('DTI vector error: Position is not head first supine'); exit; end; if (length(lDicomData.PhaseEncoding) >= 3) and (upcase(lDicomData.PhaseEncoding[1]) = 'C') then lCol := true else lCol := false; //dcmMsg('>>>>'+lDicomData.PhaseEncoding[1]+lDicomData.PhaseEncoding[2]+lDicomData.PhaseEncoding[3]+'<<<'+inttostr(length(lDicomData.PhaseEncoding))); for lI := 1 to nVec do begin lDTIra[lI].v3 := lDTIra[lI].v3; if (lDTIra[lI].bval <= 0) or ((lDTIra[lI].v1 = 0) and (lDTIra[lI].v2 = 0) and (lDTIra[lI].v3 = 0)) then begin lDTIra[lI].v1 := 0; lDTIra[lI].v2 := 0; lDTIra[lI].v3 := 0; end else begin //if bval=0 or null vector, else real vector if lCol then begin lDTIra[lI].v1 := -lDTIra[lI].v1; lDTIra[lI].v2 := lDTIra[lI].v2; end else begin lSwap := lDTIra[lI].v1; lDTIra[lI].v1 := -lDTIra[lI].v2; lDTIra[lI].v2 := -lSwap; end; end; //real vector - not 0,0,0 if (lDTIra[lI].v1 = -0.0) then lDTIra[lI].v1 := 0.0; if (lDTIra[lI].v2 = -0.0) then lDTIra[lI].v2 := 0.0; if (lDTIra[lI].v3 = -0.0) then lDTIra[lI].v3 := 0.0; end;//for each bvec end; (*procedure doBVecs; var lDICOMData:dicomdata; lDTI: TDTI; begin lDICOMData.Orient[1] := 0.99872048491662; lDICOMData.Orient[2] := -0.0015021527936; lDICOMData.Orient[3] := -0.0505483584788; lDICOMData.Orient[4] := -1.12378993e-008; lDICOMData.Orient[5] := 0.99955873135595; lDICOMData.Orient[6] := -0.0297042517172; lDTI.v1 := 0.99899346; lDTI.v2 := 0.00503525; lDTI.v3 := -0.00604230; correctBvecs(lDICOMdata, lDTI); end; *) function MkDICOMDir (var lDICOMdata: DICOMdata; var lOutDir: string): boolean; var lBlank,lName: string; lPrefs: TPrefs; begin result := false; if not direxists(lOutDir) then exit; lBlank := ''; lPrefs.AppendDate := true; lPrefs.AppendAcqSeries := false; lPrefs.AppendProtocolName := false; lPrefs.AppendPatientName := true; lPrefs.AppendFilename := false; lName := OutputFilename(lBlank,lDicomData, lPrefs); if lName = '' then exit; lOutDir := lOutDir +lName; dcmMsg('Creating folder '+lOutDir); {$I-} MkDir(lOutDir); if IOResult <> 0 then begin //MessageDlg('Cannot create directory', mtWarning, [mbOk], 0) end; {$I+} lOutDir := lOutDir + pathdelim; result := true; end; function ImageScalingOrIntensityVaries(var lDICOMra: TDICOMrap; lFirstDICOM, lLastDICOM: integer): boolean; var lIndex: integer; begin result := false; if (lFirstDICOM >= lLastDICOM) then exit; //only one image result := true; for lIndex := (lFirstDICOM +1) to lLastDICOM do begin if lDICOMra^[lIndex].IntenIntercept <> lDICOMra^[lFirstDICOM].IntenIntercept then exit; //1492 if lDICOMra^[lIndex].IntenScale <> lDICOMra^[lFirstDICOM].IntenScale then exit; //1492 if lDICOMra^[lIndex].Allocbits_per_pixel <> lDICOMra^[lFirstDICOM].Allocbits_per_pixel then exit; end; result := false; end; procedure MakeFloat (var lBuffer: bytep; var lDicomData: DICOMdata; var lSliceBytesOut: integer); //data is saved as RGBRGBRGB - convert to RRRR GGGG BBBB var lRA: bytep; lPix,lnPix,lnBytes: integer; l8i : byteP; l16ui : WordP; l16i: SmallIntP; l32i: LongIntP; l32fo, l32f: SingleP; lByteSwap: boolean; begin if (lDicomData.XYZdim[1] < 1) or (lDicomData.XYZdim[2] < 1) or (lDicomData.XYZdim[3] < 1) then exit; dcmMsg(' Converting data to 32-bit float to correct for differences slope/intercept/precision: '+chr(9)+realtostr(lDicomData.IntenScale,8)+chr(9)+realtostr(lDicomData.IntenIntercept,8)+chr(9)+inttostr(lDicomData.Allocbits_per_pixel)); {$IFDEF ENDIAN_BIG} lByteSwap := odd(lDICOMdata.little_endian); {$ELSE} lByteSwap := not odd(lDICOMdata.little_endian); {$ENDIF} lnPix := lDicomData.XYZdim[1]*lDicomData.XYZdim[2]*lDicomData.XYZdim[3]; //msg(' '+inttostr(lDicomData.XYZdim[1])+' '+inttostr(lDicomData.XYZdim[2])+' '+inttostr(lDicomData.XYZdim[3]) ); lnBytes := lnPix *trunc(((lDicomData.Allocbits_per_pixel)+7)/8); GetMem(lRA,lnBytes ); Move(lBuffer^,lRA^,lnBytes); //move(src,dest,sz) Freemem(lBuffer); GetMem(lBuffer,lnPix * 4); //save as 32 bit float: 4 bytes per pixel l32fo := SingleP(@lBuffer^[1]); if lDicomData.Allocbits_per_pixel = 8 then begin //8bit - byte swapping is not a problem... for lPix := 1 to lnPix do l32fo^[lPix] := lRA^[lPix]*lDicomData.IntenScale + lDicomData.IntenIntercept; end; //8bit //next 16 bit if (lDicomData.Allocbits_per_pixel = 16) and (lByteSwap) then begin //UNSWAP 16bit l16ui := WordP(@lRA^[1]); for lPix := 1 to lnPix do l16ui^[lPix] := swap(l16ui^[lPix]); end; //UNSWAP 16bit if (lDicomData.Allocbits_per_pixel = 16) and (not lDicomData.SignedData) then begin //16bit UNSIGNED l16ui := WordP(@lRA^[1]); for lPix := 1 to lnPix do l32fo^[lPix] := l16ui^[lPix]*lDicomData.IntenScale + lDicomData.IntenIntercept; end; //16bit UNSIGNED if (lDicomData.Allocbits_per_pixel = 16) and (lDicomData.SignedData) then begin //16bit SIGNED l16i := SmallIntP(@lRA^[1]); for lPix := 1 to lnPix do l32fo^[lPix] := l16i^[lPix]*lDicomData.IntenScale + lDicomData.IntenIntercept; end; //16bit SIGNED //NEXT 32bit if (lDicomData.Allocbits_per_pixel = 32) and (not lDicomData.FloatData) then begin //UNSWAP 32bit l32i := LongIntP(@lRA^[1]); for lPix := 1 to lnPix do pswap4i(l32i^[lPix]); end; //UNSWAP 32bit if (lDicomData.Allocbits_per_pixel = 32) and (not lDicomData.FloatData) then begin //32bit INTEGER l32i := LongIntP(@lRA^[1]); for lPix := 1 to lnPix do l32fo^[lPix] := l32i^[lPix]*lDicomData.IntenScale + lDicomData.IntenIntercept; end; //32bit INTEGER if (lDicomData.Allocbits_per_pixel = 32) and ( lDicomData.FloatData) then begin //32bit FLOAT l32f := SingleP(@lRA^[1]); for lPix := 1 to lnPix do l32fo^[lPix] := l32f^[lPix]*lDicomData.IntenScale + lDicomData.IntenIntercept; end; //32bit FLOAT Freemem(lRA); lDicomData.Allocbits_per_pixel := 32; lDicomData.FloatData := true; lDicomData.IntenScale := 1; lDicomData.IntenIntercept := 0; lSliceBytesOut := lnPix * 4; end; procedure SaveTextReport(lOutImgName: string; var lDICOM: dicomdata; var lAHdr: TNIFTIhdr ; lDTIdir: integer); var lFile : TextFile; lname,lstr: string; begin lname := changefileext(lOutImgName,'.txt'); AssignFile(lFile, lname); ReWrite(lFile); // Write a couple of well known words to this file lStr := DICOMstr(lDICOM)+kTab+'DimXYZT:'+kTab+inttostr(lAHdr.dim[1])+kTab+inttostr(lAHdr.dim[2])+kTab+inttostr(lAHdr.dim[3])+kTab+inttostr(lAHdr.dim[4]) ; if lDTIdir > 1 then lStr := lStr+'DTIdir:'+kTab+inttostr(lDTIdir); WriteLn(lFile, lStr); // Close the file CloseFile(lFile); end; function reportSliceTimes(lSliceTimes: TSliceTimes): integer; //returns multiband factor var i: integer; s: string; begin result := 1; if length(lSliceTImes) < 1 then exit; s := ' MosaicRefAcqTimes ('+inttostr(length(lSliceTimes))+' values for Slice Time Correction) '; for i := 0 to (length(lSliceTimes)-1) do s := s+kTab+floattostr(lSliceTImes[i]); dcmmsg(s); for i := 1 to (length(lSliceTimes)-1) do if SameValue(lSliceTImes[i], lSliceTImes[0]) then inc(result); if (result > 1) then dcmmsg(' These values suggest a multiband factor of '+inttostr(result)); end; function padS(ins: string; outl: integer): string; var i: integer; begin result := ''; for i := 1 to outl do begin if i <= length(ins) then result := result + ins[i] else result := result + chr(0); end; end; procedure SetNiiStr(var lH: TNIFTIhdr; lSdb, lSaux: string); var i,l: integer; s: string; begin s := padS (lSdb,18); for i := 1 to 18 do lH.db_name[i] := s[i]; s := padS (lSaux,24); for i := 1 to 24 do lH.aux_file[i] := s[i]; end; procedure AddNiiDescrip(var lH: TNIFTIhdr; lS: string); var i,l: integer; s: string; begin s := padS (lS,80); l := 0; for i := 1 to 80 do if lH.descrip[i] <> chr(0) then l := i; if l >= 80 then exit; for i := 1+l to 80 do lH.descrip[i] := s[i-l]; end; function Dicom2NII(var lDICOMra: TDICOMrap; lFirstDICOM, lLastDICOM: integer; var lOutDirOrig: string; var lPrefs: TPrefs; lVols: integer): boolean; var lCSA:TCSA; lSliceTimes: TSliceTimes; lPref: TPrefs; lDTIra: TDTIra; lDTIdir,lRGB: integer; lVolGb : double; lAllocSLiceSz, lStart,lEnd,lmosX,lmosY,lIndex,lSecondDICOM,lSeries,lnSeries,lSliceBytes, //lBaseBitDepth, lMosaicSlices,lSliceBytesOut,lvolOffset,lvolOffsetInit,lvolBytesOut,lSliceOrder: integer; //lBaseIntenScale,lBaseIntenIntercept, lDX: single; //lDynStr, lDicomImgName,lOutHdrName,lOutImgName,lOutImgNameGZ,lOutDir,lOutDTIname, lStr:string; lDICOMData:dicomdata; lReadOK,lFlip,lIntenScaleVaries,lInterleaved,lVolSave,lByteSwap : boolean; lAHdr: TNIFTIhdr; lTextF: TextFile; lOutF,lInF: File; lvBuffer,lsBuffer: bytep; lFlipMosaicMatrix,lFlipMosaic: boolean; begin lDicomImgName := lDICOMra^[lFirstDICOM].Filename; lDicomData := lDICOMra^[lFirstDICOM]; if lPrefs.DebugMode2 then begin dcmMsg( DICOMstr(1,lDICOMra,OutputFilename(lDicomImgName,lDICOMra^[lFirstDICOM],lPref))); dcmMsg(inttostr(lDICOMdata.XYZdim[1])+'x'+inttostr(lDICOMdata.XYZdim[2])+'x'+inttostr(lDICOMdata.XYZdim[3])+'x'+inttostr(lDICOMdata.XYZdim[4])); result := true; exit; end; result := false; lSliceOrder := kNIFTI_SLICE_SEQ_UNKNOWN; //unknown lPref := lPrefs; CorrectPrefs(lPref); lmosX := 1; lmosY := 1; lSecondDICOM := lFirstDICOM+1; lFlipMosaicMatrix := false; lInterleaved := false; lnSeries := (lLastDICOM+1) -lFirstDICOM; //e.g. first=10, last=10 means 1 image if lnSeries < 1 then exit; //next if magnitude and phase maps are saved in the same 4D file, extract to separate files... if (lDICOMra^[lFirstDICOM].file4D) and (MultiOrder(lDICOMra^[lFirstDICOM]) > 0) then lPref.fourD := false; if (lDicomData.SamplesPerPixel = 3) then begin dcmMsg('Warning: RGB to NIfTI conversion poorly tested: '+lDicomImgName); end; {$IFDEF ENDIAN_BIG} lByteSwap := odd(lDICOMdata.little_endian); (*if (lDicomData.CSAImageHeaderInfoPos > 0) or (lDicomData.CSAImageHeaderInfoSz >0) then begin lDicomData.CSAImageHeaderInfoPos := 0; lDicomData.CSAImageHeaderInfoSz := 0; Msg('Warning: Modern Siemens CSA headers not supported on obsolete big-endian PowerPC computers. DTI vectors and mosaic slice positioning may be inaccurate.'); end; *) {$ELSE} lByteSwap := not odd(lDICOMdata.little_endian); {$ENDIF} lMosaicSlices := lDicomData.SiemensSlices; lOutDir := ExtractFileDirWithPathDelim2(lOutDirOrig); if (lOutDir = '') then begin lOutDir := ExtractFilePath(lDicomImgName); end; if not DirWritePermission(lOutDir) then begin // <- tested with Unix dcmMsg('Error: output directory is read-only: '+lOutDir); exit; end; if lPref.createoutputfolder then MkDICOMDir(lDICOMdata,lOutDir); if not direxists(lOutDir) then begin dcmMsg('Unable to find output directory '+lOutDir); lOutDir := ExtractFileDirWithPathDelim2(lDicomImgName) end; //else directory exists //lOutHdrName :=lOutDir+OutputFilename(lDicomImgName,lDicomData,lPrefs.AppendDate,lPrefs.AppendAcqSeries,lPrefs.AppendProtocolName,lPrefs.AppendPatientName,lPrefs.FourD,lPrefs.AppendFilename)+'.hdr'; lOutHdrName :=lOutDir+OutputFilename(lDicomImgName,lDicomData,lPref)+'.hdr'; lOutImgName :=changefileext(lOutHdrName,'.img'); if lPref.SingleNIIFile then begin lOutHdrName := changefileext(lOutHdrName,'.nii'); lOutImgName := lOutHdrName; end; if (lPref.SingleNIIFile) and (lPref.GZip) then begin lOutHdrName := lOutHdrName+'.gz'; if (not UniqueFileName(lOutHdrName)) then begin dcmMsg('File already exists '+lOutImgName+' '+lOutHdrName); exit; end; //we now need to remove the .gz - not that unique filename may have appended postfix, e.g. filename.nii.gz -> filenameA.nii.gz StripGZExt(lOutHdrName); lOutImgName := lOutHdrName; end else begin if (not UniqueFileName(lOutHdrName)) or (not UniqueFileName(lOutImgName)) then begin dcmMsg('File already exists '+lOutImgName+' '+lOutHdrName); exit; end; end; dcmMsg(extractfilename(lDicomImgName)+'->'+extractfilename(lOutImgName)); DICOM2AnzHdr(lAHdr,lPref.Anonymize,lDicomImgName,lDICOMdata); if lPrefs.DebugMode2 then begin dcmMsg('slice/vols/series '+inttostr(lDICOMdata.SlicesPer3DVol )+' '+inttostr(lVols)+' '+inttostr(lnSeries)); dcmMsg('x/y/z '+inttostr(lDICOMdata.XYZdim[1])+'x'+inttostr(lDICOMdata.XYZdim[2])+'x'+inttostr(lDICOMdata.XYZdim[3])+'x'+inttostr(lDICOMdata.XYZdim[4])); result := true; exit; end; if (lVols > 1) and ((lnSeries mod lVols)=0) then lDICOMdata.SlicesPer3DVol := round(lnSeries/lVols); lDTIra[1].bval := -1; //not DTI lDTIdir := 0; IsSiemensDTI(lDicomData,lDTIra[1], lDicomImgName, lPrefs);//see if this is a Siemens DTI image - mosaics in B13, non-mosaic in B12 if (lDICOMdata.SiemensMosaicX > 1) or (lDICOMdata.SiemensMosaicY > 1) then begin lFlipMosaicMatrix := IsNormalMosaic(lDicomData,lMosaicSlices, lDicomImgName); lAHdr.dim[1] := lDicomData.XYZdim[1] div lDICOMdata.SiemensMosaicX; lAHdr.dim[2] := lDicomData.XYZdim[2] div lDICOMdata.SiemensMosaicY; lmosX := lDICOMdata.SiemensMosaicX; lmosY := lDICOMdata.SiemensMosaicY; //lSlices := lDICOMdata.SiemensSlices;//(lDicomImgName,'NumberOfImagesInMosaic'); if lMosaicSlices > 1 then lAHdr.dim[3] := lMosaicSlices else lAHdr.dim[3] := lDICOMdata.SiemensMosaicX *lDICOMdata.SiemensMosaicY; lAHdr.dim[4] := lnSeries; if ((lmosX*lmosY) < lAHdr.dim[3]) then begin dcmMsg('Aborted '+lDicomData.Filename+ ' : This '+inttostr(lmosx)+'*'+inttostr(lmosy)+' mosaic can not hold '+inttostr(lAHdr.dim[3])+' slices.'); exit; end; end else if lDICOMdata.File4D then begin//(lDicomData.XYZdim[3] > 1) and (lnSeries = 1) and (lDICOMdata.SlicesPer3DVol > 1) and ((lAHdr.dim[3] mod lDICOMdata.SlicesPer3DVol)=0) then begin lAHdr.dim[4] := lAHdr.dim[3] div lDICOMdata.SlicesPer3DVol; lAHdr.dim[3] := lDICOMdata.SlicesPer3DVol; end else if (lDicomData.XYZdim[3] > 1) then lAHdr.dim[4] := lnSeries else begin if (lDICOMdata.SlicesPer3DVol > 1) and ((lnSeries mod lDICOMdata.SlicesPer3DVol)=0) then begin lAHdr.dim[3] := lDICOMdata.SlicesPer3DVol; lAHdr.dim[4] := round(lnSeries / lDICOMdata.SlicesPer3DVol); if (lnSeries > 1) and (DICOMinterslicedistance( lDICOMra^[lFirstDICOM], lDICOMra^[lSecondDICOM]) < 0.01) then lInterleaved := true; end else lAHdr.dim[3] := lnSeries; end; if (lDICOMdata.ManufacturerID = kSiemensID) and (lDicomData.CSASeriesHeaderInfoPos > 0) and (lDicomData.CSASeriesHeaderInfoSz > 0) then begin lStr := GetCSASeriesHeaderInfo (lDicomImgName, lDicomData.CSASeriesHeaderInfoPos,lDicomData.CSASeriesHeaderInfoSz,lAHdr.dim[3], lSliceOrder); if (lSliceOrder < kNIFTI_SLICE_SEQ_UNKNOWN) or (lSliceOrder > kNIFTI_SLICE_ALT_DEC2) then lSliceOrder := kNIFTI_SLICE_SEQ_UNKNOWN; lAHdr.slice_code := lSliceOrder; lAHdr.dim_info:= 3 shl 4; lAHdr.slice_start:= 0; lAHdr.slice_end := lAHdr.dim[3]-1; if lAHdr.slice_code <> kNIFTI_SLICE_SEQ_UNKNOWN then begin //read final not first image https://github.com/eauerbach/CMRR-MB/issues/29 //DecodeCSA2 (lDicomImgName, lDicomData.CSAImageHeaderInfoPos,lDicomData.CSAImageHeaderInfoSz, lCSA, lSliceTimes, lFlippedMosaic); DecodeCSA2 (lDICOMra^[lLastDICOM].Filename, lDICOMra^[lLastDICOM].CSAImageHeaderInfoPos,lDICOMra^[lLastDICOM].CSAImageHeaderInfoSz, lCSA, lSliceTimes, lFlipMosaic); reportSliceTimes(lSliceTimes); SetNiiStr(lAHdr, lStr, lDICOMra^[lLastDICOM].ImageComments); if (lCSA.PhaseDirectionPositive = 1) then AddNiiDescrip(lAHdr,';phaseDir=+') else if (lCSA.PhaseDirectionPositive = 0) then AddNiiDescrip(lAHdr,';phaseDir=-'); lSliceTimes := nil; end; // dcmmsg('For slice timing correction: the slice order is '+kSliceOrderStr[lSliceOrder]); end; if (lDICOMdata.BandwidthPerPixelPhaseEncode > 0) then begin //do this AFTER mosaics have reset dim[1] and dim[2] if (length(lDICOMdata.PhaseEncoding) > 0) and ((lDICOMdata.PhaseEncoding[1]='C') or (lDICOMdata.PhaseEncoding[1]='R')) then begin //fx( lAHdr.dim[1],lAHdr.dim[2]); if (lDICOMdata.PhaseEncoding[1]='C') then begin//columns lAHdr.pixdim[6] := 1000/lDICOMdata.BandwidthPerPixelPhaseEncode/lAHdr.dim[2]; lAHdr.slice_duration:= lAHdr.pixdim[6] * lAHdr.dim[2]; end else begin //rows lAHdr.pixdim[6] := 1000/lDICOMdata.BandwidthPerPixelPhaseEncode/lAHdr.dim[1]; lAHdr.slice_duration:= lAHdr.pixdim[6] * lAHdr.dim[1]; //dcmMsg(inttostr(lAHdr.dim[1])); end; AddNiiDescrip(lAHdr,';dwell='+realtostr( lAHdr.pixdim[6],3)); dcmMsg('Effective echo spacing: '+floattostr( lAHdr.pixdim[6])+'ms, BandwidthPerPixelPhaseEncode: '+floattostr(lDICOMdata.BandwidthPerPixelPhaseEncode)); end else dcmMsg('Unable to determine echo spacing: not sure of phase encoding direction'); end; lFlip := false; if lnSeries > 1 then begin//check slice order lFlip := CheckSliceDirection(lDICOMra^[lFirstDICOM],lDICOMra^[lLastDICOM]); if lFlip then begin lDicomImgName := lDICOMra^[lLastDICOM].Filename; lDICOMdata := lDICOMra^[lLastDICOM]; end; end; //next compute dx between slices if (lAHdr.dim[3] > 1) and (lnSeries > 1) and (lDICOMdata.SiemensMosaicX <2) then begin lDX := abs(DICOMinterslicedistance( lDICOMra^[ Index (1,lFirstDICOM,lInterleaved,lFlip,lAHdr)], lDICOMra^[ Index (2,lFirstDICOM,lInterleaved,lFlip,lAHdr)]) ); if lDX <> 0 then begin lDicomData.XYZmm[3] := lDX; lAHdr.pixdim[3] := lDX; end; end; dicom_2_nifti(lDICOMdata,lAHdr,lMosaicSlices,lFlipMosaicMatrix); //all slices in a NIFTI image must be of the same precision and have the same scaling intercept and slope - see if this applies (*lBaseIntenScale := lDICOMdata.IntenScale; lBaseIntenIntercept := lDICOMdata.IntenIntercept; lBaseBitDepth := lDicomData.Allocbits_per_pixel; lIntenScaleVaries := false; for lSeries := 1 to lnSeries do begin lIndex := Index (lSeries,lFirstDICOM,lInterleaved,lFlip,lAHdr); if lDICOMra^[lIndex].IntenIntercept <> lBaseIntenIntercept then lIntenscaleVaries := true; //1492 if lDICOMra^[lIndex].IntenScale <> lBaseIntenScale then lIntenscaleVaries := true; //1492 if lDICOMra^[lIndex].Allocbits_per_pixel <> lBaseBitDepth then lIntenscaleVaries := true; end; //for lnSeries *) lIntenScaleVaries := ImageScalingOrIntensityVaries(lDICOMra, lFirstDICOM, lLastDICOM); (* for lSeries := 1 to lnSeries do begin lIndex := Index (lSeries,lFirstDICOM,lInterleaved,lFlip,lAHdr); lDicomData := lDICOMra^[lIndex]; msgfx(lSeries, lDICOMdata.DTI[1].v1,lDICOMdata.DTI[1].v2,lDICOMdata.DTI[1].v3); end; *) // exit;//get out of here - crucial critical -- last chance before data saved to disk if (lAHdr.bitpix = 8) and (lDicomData.SamplesPerPixel = 3) then begin if (lIntenScaleVaries) then begin dcmMsg('RGB files can not have varying intensity scales!'); lIntenScaleVaries := false; end; lRGB := 3; lAHdr.datatype := kDT_RGB; lAHdr.bitpix := 24; end else lRGB := 1; if (lIntenScaleVaries) then begin lAHdr.datatype := kDT_FLOAT; lAHdr.bitpix := 32; dcmMsg('Warning: images have different precision or intensity scaling - saving as 32-bit float'); end; lSliceBytes := lDicomData.XYZdim[1]*lDicomData.XYZdim[2]*lDicomData.XYZdim[3]*trunc(((lDicomData.Allocbits_per_pixel)+7)/8)*lRGB; GetMem(lsBuffer,lSliceBytes); lSliceBytesOut :=lAHdr.dim[1]*lAHdr.dim[2]*lAHdr.dim[3]*trunc((lAHdr.bitpix+7)/8)*lRGB; if lPrefs.DebugMode2 then dcmMsg(' bytes/bitPix '+inttostr( lSliceBytesOut)+' '+inttostr(lAHdr.bitpix) ); lVolBytesOut := lSliceBytesOut * lAHdr.dim[4]; lVolOffset := 1; lVolGB := (lSliceBytesOut/ 1073741824) * lAHdr.dim[4]; //bytes *1024 (kB) *1024 (Mb) * 1024 (Gb) //note.nii files are 352bytes larger than calculated by lVolGb... //Msg(floattostr(lVolGb)+' Gb'); if lVolGb < 0.95 then lVolSave := true else begin dcmMsg('Very large volume: '+floattostr(lVolGb)+' Gb: slice-by-slice conversion required.'); if lPref.GZip then begin lPref.GZip := false; dcmMsg('Unable to automatically GZip such a large file.'); end; lVolSave := false; end; if lVolSave then begin //save entire volume if lPref.SingleNIIFile then begin lVolOffset := kNIIImgOffset+1;// 353; //first 352 bytes empty lVolBytesOut := lVolBytesOut + lVolOffset -1; end else lVolOffset := 1; GetMem(lvBuffer,lVolBytesOut); //showmessage(inttostr(lVolBytesOut)); //we could copy NIfTI header to Buffer, but this would need to be changed for //4D->3D images or images where we swap 3rd and 4th dimension.... end else begin //save slice by slice - slower but low RAM usage... if not SaveHdr (lOutHdrName,lAHdr, false,lPref.SPM2) then begin dcmMsg('Error saving data - do you have permission and space for '+lOutHdrName+'?'); exit; end; Filemode := 2; AssignFile(lOutF, lOutImgName); if lPref.SingleNIIFile then begin Reset(lOutF,1); Seek(lOutF,352); lAHdr.vox_offset := 352; end else Rewrite(lOutF,1); end; //end slice-bylslice Filemode := 0; //set to read only lVolOffsetInit := lVolOffset; for lSeries := 1 to lnSeries do begin lIndex := Index (lSeries,lFirstDICOM,lInterleaved,lFlip,lAHdr); lDicomImgName := lDICOMra^[lIndex].Filename; lDicomData := lDICOMra^[lIndex]; if (lDICOMdata.ManufacturerID = kPhilipsID) and (lDICOMdata.nDTIdir > 1) and (lAHdr.dim[4] < kMaxDTIDir) and (lDICOMdata.nDTIdir >= lAHdr.dim[4]) then begin // dcmMsg('4D Philips DTI data '+inttostr(lDICOMdata.nDTIdir)); for lDTIdir := 1 to lAHdr.dim[4] do begin lDTIra[lDTIdir].bval := lDICOMdata.DTI[lDTIdir].bval; lDTIra[lDTIdir].v1 := lDICOMdata.DTI[lDTIdir].v1; lDTIra[lDTIdir].v2 := lDICOMdata.DTI[lDTIdir].v2; lDTIra[lDTIdir].v3 := lDICOMdata.DTI[lDTIdir].v3; end; lDTIdir := lAHdr.dim[4]; end else if (lDICOMdata.ManufacturerID = kSiemensID) and (lDTIra[1].Bval >= 0) and (lDTIdir < kMaxDTIDir) and ( ((lSeries mod lAHdr.dim[3]) = 1) or((lMosX > 1) or (lMosY > 1))) then begin // inc(lDTIdir); IsSiemensDTI(lDicomData,lDTIra[lDTIdir], lDicomImgName,lPrefs); end else if (lDICOMdata.nDTIdir = 1) and (lDICOMdata.DTI[1].Bval >= 0) and (lDTIdir < kMaxDTIDir) and ( (lSeries mod lAHdr.dim[3]) = 1) then begin // inc(lDTIdir); lDTIra[lDTIdir].bval := lDICOMdata.DTI[1].bval; lDTIra[lDTIdir].v1 := lDICOMdata.DTI[1].v1; lDTIra[lDTIdir].v2 := lDICOMdata.DTI[1].v2; lDTIra[lDTIdir].v3 := lDICOMdata.DTI[1].v3; end; lReadOK := true; if (lDicomData.JPEGLosslessCpt) then begin AssignFile(lInF, lDicomImgName); Reset(lInF,1); //lDICOMdata.CompressSz := FileSize(lInF)-lDicomData.CompressOffset; Filemode := 0; //ReadONly //lSliceBytesOut := lSliceBytes; dcmMsg('Decoding lossless '+inttostr(lDICOMdata.XYZdim[1])+'x'+inttostr(lDICOMdata.XYZdim[2])+' JPEG starting from byte '+ inttostr(lDicomData.CompressOffset)+' with '+inttostr(lDICOMdata.CompressSz)+' bytes'); if ( lDicomData.XYZdim[3] > 1) or ( lDicomData.XYZdim[4] > 1) then dcmMsg('*Warning: this software will only convert the first slice of this multislice lossless compressed JPEG'); lAllocSLiceSz := (lDICOMdata.XYZdim[1]*lDICOMdata.XYZdim[2] * lDICOMdata.Allocbits_per_pixel+7) div 8 ; DecodeJPEG(lInF,SmallIntP0(lsBuffer),ByteP0(lsBuffer),lAllocSliceSz,lDicomData.CompressOffset,lDICOMdata.CompressSz,false); CloseFile(lInF); (*FlipTB(lDICOMdata,lsBuffer); if lVolSave then begin{save entire volume} Move(lsBuffer^,lvBuffer^[lvolOffset],lSliceBytesOut); //Msg(inttostr(lSeries)); lVolOffset := lVolOffset + lSliceBytesOut; end else begin //save slice-by-slice Filemode := 2; //read and write BlockWrite(lOutF, lsBuffer^, lSliceBytesOut); end;*) end else if (FSize(lDicomImgName) >= (lSliceBytes+lDicomData.imagestart)) then begin Filemode := 0; //ReadONly AssignFile(lInF, lDicomImgName); Reset(lInF,1); Seek(lInF,lDicomData.imagestart); Filemode := 0; //ReadONly BlockRead(lInF, lsBuffer^, lSliceBytes); CloseFile(lInF); (*if (lDICOMdata.file4D) and (lPrefs.Swizzle4D) then SwapTime(lDICOMdata,lsBuffer);//data is stored X,Y,T,Z - swap to X,Y,Z,T lSliceBytesOut := lSliceBytes; if (lDICOMdata.PlanarConfig = 0) and (lDicomData.SamplesPerPixel = 3) then MakePlanar(lsBuffer,lDICOMdata); if (lMosX > 1) or (lMosY > 1) then begin DeMosaic(lsBuffer,lmosX,lmosY,lMosaicSlices,lFlipMosaic,lDICOMdata); lSliceBytesOut :=lAHdr.dim[1]*lAHdr.dim[2]*lAHdr.dim[3]*trunc(((lDicomData.Allocbits_per_pixel)+7)/8); end else FlipTB(lDICOMdata,lsBuffer); if lVolSave then begin{save entire volume} Move(lsBuffer^,lvBuffer^[lvolOffset],lSliceBytesOut); lVolOffset := lVolOffset + lSliceBytesOut; end else begin //save slice-by-slice Filemode := 2; //read and write BlockWrite(lOutF, lsBuffer^, lSliceBytesOut); end; *) end else begin dcmMsg('Serious error with file '+ extractfilename(lDicomImgName)); lReadOK := false; end; //if JPEG else if UNCOMPRESSED else ERROR if lReadOK then begin lDicomData.XYZdim[4] := lAHdr.dim[4]; //do this now - depending on slice order DicomData can be first or last volume if (lDICOMdata.file4D) and (lPrefs.Swizzle4D) then SwapTime(lDICOMdata,lsBuffer);//data is stored X,Y,T,Z - swap to X,Y,Z,T lSliceBytesOut := lSliceBytes; if (lIntenScaleVaries) then begin MakeFloat(lsBuffer,lDICOMdata, lSliceBytesOut); lByteSwap := false; //Un-swapped during conversion end; if (lDICOMdata.PlanarConfig = 0) and (lDicomData.SamplesPerPixel = 3) then MakePlanar(lsBuffer,lDICOMdata); if (lMosX > 1) or (lMosY > 1) then begin DeMosaic(lsBuffer,lmosX,lmosY,lMosaicSlices,lFlipMosaic,lDICOMdata); lSliceBytesOut :=lAHdr.dim[1]*lAHdr.dim[2]*lAHdr.dim[3]*trunc((lAHdr.bitpix+7)/8); end else FlipTB(lDICOMdata,lsBuffer); //msg(inttostr(lSliceBytesOut)+ ' '+inttostr(lAHdr.dim[1]*lAHdr.dim[2]*lAHdr.dim[3]*trunc((lAHdr.bitpix+7)/8))); //lSliceBytesOut :=lAHdr.dim[1]*lAHdr.dim[2]*lAHdr.dim[3]*trunc((lAHdr.bitpix+7)/8); if lVolSave then begin{save entire volume} Move(lsBuffer^,lvBuffer^[lvolOffset],lSliceBytesOut); lVolOffset := lVolOffset + lSliceBytesOut; end else begin //save slice-by-slice Filemode := 2; //read and write BlockWrite(lOutF, lsBuffer^, lSliceBytesOut); end; end; //if lReadOK end; freemem(lsBuffer); Filemode := 2; //read and write lOutImgNameGZ := lOutImgName; if lPref.TxtReport then SaveTextReport(lOutImgName, lDICOMdata, lAHdr,lDTIdir); if lVolSave then begin{save slice-by-slice} lOutImgNameGZ := SaveNIfTICore (lOutImgName, lvBuffer, lVolOffsetInit, lAHdr, lPref) end else //data saved slice by slice CloseFile(lOutF); //if (lPref.StartClip > 0) or (lPref.EndClip > 0) then // Clip4D(lOutHdrName, lAHdr, false,lPref.SPM2,lPref.SingleNIIFile,lPref.GZip, true, lPref.StartClip,lPref.EndClip); if lDTIdir > 1 then begin //bvec file lStart := -1;//ensure this is a DTI image - some scans must have a bvalue > 1 for lIndex := 1 to lDTIdir do if lDTIra[lIndex].bval = 0 then lStart := lIndex; if lStart < 1 then begin dcmMsg('* Warning: diffusion acquisition does not have b-0 image'); PartialAcquisitionError; end; lStart := -1;//ensure this is a DTI image - some scans must have a bvalue > 1 for lIndex := 1 to lDTIdir do if lDTIra[lIndex].bval > 0 then lStart := lIndex; if lStart > 0 then begin lStart := 1; lEnd := lDTIdir; lOutDTIname := lOutImgName; dcmMsg('Number of diffusion directions = '+inttostr(lDTIdir)); if lDicomData.ManufacturerID = kSiemensID then begin if lDicomData.Vers0018_1020 = 13 then dcmMsg(' *Warning: some Siemens VB13 set DiffusionGradientDirection incorrectly. Please check manually validate'); if lDicomData.Vers0018_1020 >= lPrefs.SiemensDTINoAngulationCorrectionIf00181020atleast then begin dcmMsg('Note: detected Siemens Software version [0018:1020] = '+inttostr(lDicomData.Vers0018_1020) ); dcmMsg(' -Will use 0019:000E or 0019:100E instead of 0029:1020 if version >= ' +inttostr(lPrefs.SiemensDTIUse0019If00181020atleast)); dcmMsg(' -Will stack across Acquisitions if version >=' +inttostr(lPrefs.SiemensDTIStackIf00181020atleast)); dcmMsg(' -No slice angulation correction of vectors if version >=' +inttostr(lPRefs.SiemensDTINoAngulationCorrectionIf00181020atleast)); dcmMsg(' To adjust, edit '+IniName ); SiemensFlipYBvecs(lDTIra,lDTIdir) end else siemensPhilipsCorrectBvecs(lDicomData,lDTIra,lDTIdir, lFlipMosaicMatrix); end else if lDicomData.ManufacturerID = kPhilipsID then begin //-->PhilipsCorrectBvecs(lDicomData,lDTIra,lDTIdir); siemensPhilipsCorrectBvecs(lDicomData,lDTIra,lDTIdir,false); //next: philips scans can include DWI images with bval>0 and v1=0,v2=0,v3=0 - we want to exclude these //for lIndex := lDTIdir downto 1 do // msg(inttostr(lIndex)+ kTab+floattostr(lDTIra[lIndex].bval)+kTab+floattostr(lDTIra[lIndex].v1)+kTab+floattostr(lDTIra[lIndex].v2)+kTab+floattostr(lDTIra[lIndex].v3)); for lIndex := lDTIdir downto 1 do if (lDTIra[lIndex].bval = 0) or (lDTIra[lIndex].v1 <> 0) or (lDTIra[lIndex].v2 <> 0) or (lDTIra[lIndex].v3 <> 0) then lStart := lIndex; for lIndex := 1 to lDTIdir do if (lDTIra[lIndex].bval = 0) or (lDTIra[lIndex].v1 <> 0) or (lDTIra[lIndex].v2 <> 0) or (lDTIra[lIndex].v3 <> 0) then lEnd := lIndex; if ((lStart >1) or (lEnd < lDTIdir)) and (lStart <= lEnd) then begin if lVolSave then {save slice-by-slice} lOutDTIname := SaveNIfTICoreCrop (lOutImgName, lvBuffer, lVolOffsetInit,lStart-1,lDTIdir-lEnd, lAHdr, lPref) else lOutDTIname := Clip4D(lOutHdrName, lAHdr, false,lPref, lStart-1,lDTIdir-lEnd); //lOutDTIname := Clip4D(lOutHdrName, lAHdr, false,lPref.SPM2,lPref.SingleNIIFile,lPref.GZip, false, lStart-1,lDTIdir-lEnd); //Msg(lOutDTIName); dcmMsg('Removed DWI from DTI scan - saving volumes '+inttostr(lStart)+'..'+inttostr(lEnd)); end;//exclude scans end else if lDicomData.ManufacturerID = kGEID then GECorrectBvecs(lDicomData,lDTIra,lDTIdir) else dcmMsg('WARNING: Unkown manufacturer - DTI BVecs are probably incorrect.');//beta software if lStart <= lEnd then begin //create output vectors if lOutDTIname <> '' then begin //image file created lOutDTIname := changefileextX(lOutDTIname,'.bvec'); assignfile(lTextF,lOutDTIname); Filemode := 0; rewrite(lTextF); for lSeries := lStart to lEnd do Write(lTextF,floattostr(lDTIra[lSeries].v1)+ ' '); Writeln(lTextF); for lSeries := lStart to lEnd do Write(lTextF,floattostr(lDTIra[lSeries].v2)+ ' '); Writeln(lTextF); for lSeries := lStart to lEnd do Write(lTextF,floattostr(lDTIra[lSeries].v3)+ ' '); Writeln(lTextF); closefile(lTextF); //create bvals lOutDTIname := changefileextX(lOutDTIname,'.bval'); assignfile(lTextF,lOutDTIname); Filemode := 0; rewrite(lTextF); for lSeries := lStart to lEnd do Write(lTextF,inttostr(lDTIra[lSeries].bval)+' '); Writeln(lTextF); closefile(lTextF); end;// if lOutDTIname <> '' then begin //image file created end; //lStart <= lEnd end; //some bvals > 0 end; //DTIdir if lVolSave then //do this AFTER DTI extraction - allows rapid cropping of Philips DTI Freemem ( lvBuffer) else begin if ((not lPref.FourD) and (lAHdr.dim[4] > 1)) or ((lPref.SingleNIIFile) and (lPref.Gzip)) then begin ChangeNIfTISubformat(lOutHdrName, lAHdr,lPref) ; end; end; //slice-by-slice (*if lIntenscaleVaries then begin beep; Msg('Intensity scale/slope or bit-depth varies across slices: perhaps convert with MRIcro.'); end;*) if (lPref.enablereorient) and (lDicomData.XYZdim[2] > lPref.MinReorientMatrix) and (lDicomData.XYZdim[1] > lPref.MinReorientMatrix) and (lAHdr.dim[3] > 64) and (lAHdr.dim[4] < 2) then begin lOutImgName := Reorient(lOutImgNameGZ,lAHdr,lPref,false,false); if (lOutImgName <> '') and (lDicomData.TE < 25) and (lDicomData.TE > 0) then //T1 image CropNIfTI(lOutImgName,lPref); end; result := true; Filemode := 0; //ReadONly ExitCode := 0; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2niigui.res���������������������������������������������0000755�0001750�0001750�00000044210�12377624467�020320� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ������������������������� �������������������<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="CompanyName.ProductName.YourApp" type="win32"/> <description>Your application description here.</description> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/> </dependentAssembly> </dependency> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="asInvoker" uiAccess="false"/> </requestedPrivileges> </security> </trustInfo> </assembly>�>���0����M�A�I�N�I�C�O�N�����������������������00��� �%��� ��� ������� � ������ �h�����%�� �������������������(���0���`���� �����%�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������~~zz{{{{|||~~jjj�������������������������������������������������������������������������������������������������������������vu�mmn�rrq�rrr�ttt�}}}�lll�xxx�888��������������������������������������������kkk zzz֦أأ٢٣٢٢ئۛsss9rrp!pqm##"ggtPPKSTG]]Ybbbiiibbb___���������������������������������������HҚlwyYrtPstPxzZl𒓃𡡞𫫯𭭲𨨩𥥣𥥥짧񓓓�����������������������������������rlo;`d_eek�kq�nu�mt�kq�gm�ekhmuy=r```���������������������������������ͨhj7X^�u|��������t|�qwSp������������������������������ppp�lll"4������������xk������������������������������J;�������>}}I���������������������������sA�����������������!���������������������������G����&PileJ!&,)nqF:F?(dfZ�llf�������jdTryyvҒ�zzz�����kkk�Ш|}zzzÍv{}wwwN�```� (⫫ttsyyyzzzzzzzzz~~~wwwరeeeqqqT쭭zzzxxxTTT��}}}򭭭}}}rrr|||xxxyyysssxxx}}}|||zzzzzz{{{xxxtttuuuwww{{{uuu薕Ԗ֟Ҟ___Z푑nnnooonnnjjjtlllgwwwUiii �����cifl�nu�������rrr^�����www�uuu���1����ʍ����48��DDD�^^^�jjjkkkzzzuuuyyy�nR����VkY E�*���������XPOMKKDp�����eee�����������������vvv��I]����表�*���������������G����������������������NW����籸)�*���������{{{y񩩩3EEE```zzz�����������zzz��;����'>�:�*���������^^^J몪.����� ~�ZZZ�```��yyy ����Ď � �*���������ܬZ�����uB�����������47�-����������������î ������򤤤l �###��.#����(-S2�)�������������8������NদìT���� .L%�%��������������vx������ch�����7D�+#��������������HB������RX�����&樰0-.�#�������������]]]�RRR򢢢$������� z%�������6f$�%,�����������������̧s��������NuwR������F쯮Mnk�h-������������������h��������������������J�ty%��������������������� �Sm����������������MV�sx���������������������yyy�rrr,����������������� g̒~����������������������������QףW���������������� 4泲¡J���������������������������TTT��xxxaaa� kɪ᭭𰰰c-������� "WT��������������������������������������|||�rrr��������������XXXlll-B[tȡtٛK斝/!ט"(w~.: � �����������������������������������������������xxx��???� �nnn������������������&aUb`opS'x|4079:<~-0y|8��)�]Z���h[�������������������������������������������������������������������������������������www�5#�H2�_Z�qrV�8�<�?�0�}9��#������������������������������������������������������������������������������������������������������������������������������������������������������,{)w{3{7$�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?������?������������������������������������������������������������������ �������������������(��� ���@���� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������vvv�{{{�ZZZ�nnn��������fff������������������������������������������������������������������������������[[[�{{{aaa�������ccc�aa`lkoyy|Ooq<uxEj�����������������������SSSooo�WWW .,--,,\\YYYO�nnj�y�qrP�fh;�kmE�k�������������������������������O֧Ťyyjss]wxd|&������������������~Yrv*sxu| v}v| v{y~%K�������������������_u}����������%񠠞�������������������i����������Xr�ttr�������������զp��(<;" }Qbg;lpA�vvt�EEE�777�����]]].詩le}{ut~{z '''LLL`zzyদᔔ�yyx~}}||{{{vvvrrrwwwwww~~坝ᚚ~~~lϭmmms|||giiiZKBԲ ou Ylr rxlllҬ��555�qqq���c"���y���ppp�˪7641P~~~;/�����������������V����������y .��xxx��ü�� %_$�����mmm=좢:��MഴG�#O��D%H�,���� آ{�~շɯ󵵵}�*| �(�������8��su���7E8�(����������79����(�%�%������I ���  �����@\�0��������������������K򆅑���������������g첲N ���������d٬0�������������������{{{�jjjLfͮબT( ɇ(y{Y@ljv�������������������������kkk�����������wr%3OC.P-Y+T-<:ruD�y|(�JU����������������������������ggg�����������E�+�*�)�.�5�sv@�x{+tx-��������������������������������������������������������������������������5"" #�������&�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?��?��������������`��������������?���? �� �������������������(������0���� �����` ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ccc����������������������������������{{{�LLL�����������������{{{$HEEH&������,����������V`������������������������� ~ׇhtx;qu.uy<ӂ]ӗөѪӓ1�����������sz�����A�x������ ⣣z���������Z����wwwC%(Yve<FOMPttiyzh�g���zzxvvtttrա,֮zzz̃葑LIJ_ZwzMN߫����]���.����֤})*$|n�.Q�����V����n�>�r| O𳴰j��EN�0�+ꨨQ��C讯ް�&�/��ͦ��1i��.%)�%%�� ��� 70���cK�\)������P$��������ﭫO(�����Tծ魭f(  鎕(rb�����������������y|H .ANS&b"k#_$9(E>�������������������uuuBBC�����B����#�)�][^}dp�������������������������������������������'����������������������������������������������������������������������������������������������������������������������������������������?�����������������<��>��<������������?�����h�� �������������������(������ ���� �����@����������������������� ��������������������hf~�������������FddT)'jh~%%&"~~w�h�^�����B N8����\����fI�G�q}}}zr{oA�Ԭzz~䣢Z멩A1s {%ᦥo%U��)� ���ϻ(�݉7a*�񵴿� �歭��>U8��-�i�~议; ���3̦k�������ssw"7MPb"sy^&+;�(�jW=�t����III�������T����)�G�<}ci�A����������������E  ��N����������������������������������������?����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/parconvert.pas���������������������������������������������0000755�0001750�0001750�00000166434�12377624241�020446� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit parconvert; {$H+} interface uses {$IFDEF FPC}gzio2, {$ELSE} gziod,{$ENDIF} math, bvec,define_types,SysUtils,dicom,dicomtypes,filename,nii_4dto3d,niftiutil,nii_orient, nii_crop,GraphicsMathLibrary,prefs,dialogs_msg, nifti_types; function LoadFileListPARREC (var lInFilename, lOutDir: string; var lPrefs: TPrefs): boolean; implementation uses dialogsx; procedure PAR2DICOMstudyDate(var lDicomData: DICOMdata); {input: lDicomData.StudyDate = 2002.12.29 / 19:48:58.0000 output: StudyDate = YYYYMMDD StudyTime= hhmmss } var I: integer; lStr: string; begin if length(lDicomData.StudyDate) < 14 then exit; lStr := ''; for I := 1 to length(lDicomData.StudyDate) do if lDicomData.StudyDate[I] in ['0'..'9'] then lStr := lStr+ lDicomData.StudyDate[I]; if length(lStr) < 14 then exit; lDicomData.StudyDate := ''; for I := 1 to 8 do lDicomData.StudyDate := lDicomData.StudyDate+lStr[I]; lDicomData.StudyTime := ''; for I := 9 to 14 do lDicomData.StudyTime := lDicomData.StudyTime+lStr[I]; lDicomData.DateTime := StudyDateTime(lDicomData.StudyDate,lDicomData.StudyTime); end; procedure ShellSortItems (first, last: integer; var lPositionRA: longintp; lIndexRA: int64P; var lRepeatedValues: boolean); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n,t, nn, m, lognb2, l, k, j, i: longint; begin lRepeatedValues := false; n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 1 to k do begin i := j; 555: {<- LABEL} l := i + m; if (lIndexRA^[lPositionRA^[l]] = lIndexRA^[lPositionRA^[i]]) then begin lRepeatedValues := true; exit; end; if (lIndexRA^[lPositionRA^[l]] < lIndexRA^[lPositionRA^[i]]) then begin //swap values for i and l t := lPositionRA^[i]; lPositionRA^[i] := lPositionRA^[l]; lPositionRA^[l] := t; i := i - m; if (i >= 1) then goto 555; end end end end; //shellsort is fast and requires less memory than quicksort function SinDeg(lDeg: double): double; begin result := sin(lDeg*PI/180); end; function CosDeg(lDeg: double): double; begin result := Cos(lDeg*PI/180); end; FUNCTION Matrix3DL (CONST m11,m12,m13, m21,m22,m23, m31,m32,m33: DOUBLE): TMatrix; BEGIN WITH RESULT DO BEGIN matrix[1,1] := m11; matrix[1,2] := m12; matrix[1,3] := m13; matrix[1,4] := 0; matrix[2,1] := m21; matrix[2,2] := m22; matrix[2,3] := m23; matrix[2,4] := 0; matrix[3,1] := m31; matrix[3,2] := m32; matrix[3,3] := m33; matrix[3,4] := 0; matrix[4,1] := 0; matrix[4,2] := 0; matrix[4,3] := 0; matrix[4,4] := 1; size := size3D END END {Matrix3D}; // 'Defuzz' is used for comparisons and to avoid propagation of 'fuzzy', // nearly-zero values. DOUBLE calculations often result in 'fuzzy' values. // The term 'fuzz' was adapted from the APL language. (* FUNCTION Defuzz(CONST x: DOUBLE): DOUBLE; BEGIN IF ABS(x) < fuzz THEN RESULT := 0.0 ELSE RESULT := x END {Defuzz}; *) FUNCTION MultiplyMatrices (CONST a,b: TMatrix): TMatrix; VAR i,j,k: TIndex; temp : DOUBLE; BEGIN RESULT.size := a.size; IF a.size = b.size THEN FOR i := 1 TO a.size DO BEGIN FOR j := 1 TO a.size DO BEGIN temp := 0.0; FOR k := 1 TO a.size DO BEGIN temp := temp + a.matrix[i,k]*b.matrix[k,j]; END; RESULT.matrix[i,j] := Defuzz(temp) END END ELSE dcmMsg('MultiplyMatrices error: '+inttostr(a.size)+' <> '+inttostr(b.size)) END {MultiplyMatrices}; (* function RealToStr(lR: double {was extended}; lDec: integer): string; begin RealTOStr := FloatToStrF(lR, ffFixed,7,lDec); end; procedure ReportMatrix (lStr: string;lM:TMatrix); begin dcmMsg(lStr); dcmMsg( RealToStr(lM.matrix[1,1],6)+','+RealToStr(lM.matrix[1,2],6)+','+RealToStr(lM.matrix[1,3],6)+','+RealToStr(lM.matrix[1,4],6)); dcmMsg( RealToStr(lM.matrix[2,1],6)+','+RealToStr(lM.matrix[2,2],6)+','+RealToStr(lM.matrix[2,3],6)+','+RealToStr(lM.matrix[2,4],6)); dcmMsg( RealToStr(lM.matrix[3,1],6)+','+RealToStr(lM.matrix[3,2],6)+','+RealToStr(lM.matrix[3,3],6)+','+RealToStr(lM.matrix[3,4],6)); dcmMsg( RealToStr(lM.matrix[4,1],6)+','+RealToStr(lM.matrix[4,2],6)+','+RealToStr(lM.matrix[4,3],6)+','+RealToStr(lM.matrix[4,4],6)); end; *) FUNCTION Diag3D (CONST m1,m2,m3,m4: DOUBLE): TMatrix; BEGIN WITH RESULT DO BEGIN matrix[1,1] := m1; matrix[1,2] := 0; matrix[1,3] := 0; matrix[1,4] := 0; matrix[2,1] := 0; matrix[2,2] := m2; matrix[2,3] := 0; matrix[2,4] := 0; matrix[3,1] := 0; matrix[3,2] := 0; matrix[3,3] := m3; matrix[3,4] := 0; matrix[4,1] := 0; matrix[4,2] := 0; matrix[4,3] := 0; matrix[4,4] := m4; size := size3D END END {Diag3D}; FUNCTION Matrix3D (CONST m11,m12,m13,m14, m21,m22,m23,m24, m31,m32,m33,m34, m41,m42,m43,m44: DOUBLE): TMatrix; BEGIN WITH RESULT DO BEGIN matrix[1,1] := m11; matrix[1,2] := m12; matrix[1,3] := m13; matrix[1,4] := m14; matrix[2,1] := m21; matrix[2,2] := m22; matrix[2,3] := m23; matrix[2,4] := m24; matrix[3,1] := m31; matrix[3,2] := m32; matrix[3,3] := m33; matrix[3,4] := m34; matrix[4,1] := m41; matrix[4,2] := m42; matrix[4,3] := m43; matrix[4,4] := m44; size := size3D END END {Matrix3D}; function mat44_inverse(var R: Tmatrix ) : TMatrix; var r11,r12,r13,r21,r22,r23,r31,r32,r33,v1,v2,v3 , deti : double; Q: TMatrix; begin r11 := R.matrix[1,1]; r12 := R.matrix[1,2]; r13 := R.matrix[1,3]; //* [ r11 r12 r13 v1 ] */ r21 := R.matrix[2,1]; r22 := R.matrix[2,2]; r23 := R.matrix[2,3]; //* [ r21 r22 r23 v2 ] */ r31 := R.matrix[3,1]; r32 := R.matrix[3,2]; r33 := R.matrix[3,3]; //* [ r31 r32 r33 v3 ] */ v1 := R.matrix[1,4]; v2 := R.matrix[2,4]; v3 := R.matrix[3,4]; //* [ 0 0 0 1 ] */ deti := r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; if( deti <> 0.0 ) then deti := 1.0 / deti ; Q.matrix[1,1] := deti*( r22*r33-r32*r23) ; Q.matrix[1,2] := deti*(-r12*r33+r32*r13) ; Q.matrix[1,3] := deti*( r12*r23-r22*r13) ; Q.matrix[1,4] := deti*(-r12*r23*v3+r12*v2*r33+r22*r13*v3 -r22*v1*r33-r32*r13*v2+r32*v1*r23) ; Q.matrix[2,1] := deti*(-r21*r33+r31*r23) ; Q.matrix[2,2] := deti*( r11*r33-r31*r13) ; Q.matrix[2,3] := deti*(-r11*r23+r21*r13) ; Q.matrix[2,4] := deti*( r11*r23*v3-r11*v2*r33-r21*r13*v3 +r21*v1*r33+r31*r13*v2-r31*v1*r23) ; Q.matrix[3,1] := deti*( r21*r32-r31*r22) ; Q.matrix[3,2] := deti*(-r11*r32+r31*r12) ; Q.matrix[3,3] := deti*( r11*r22-r21*r12) ; Q.matrix[3,4] := deti*(-r11*r22*v3+r11*r32*v2+r21*r12*v3 -r21*r32*v1-r31*r12*v2+r31*r22*v1) ; Q.matrix[4,1] := 0; Q.matrix[4,2] := 0; Q.matrix[4,3] := 0.0 ; Q.matrix[4,4] := 1;// (deti == 0.0l) ? 0.0l : 1.0l ; /* failure flag if deti == 0 */ result := Q ; end; procedure SetLarger (var lA,lB: double); begin if lA > lB then lB := lA else lA := lB; end; procedure matx(var lNHdr: TNiftiHdr; var lDICOMdata: DICOMdata; b,c,a,{b,c,a,}offa,offb,offc,lx,ly,lz,lAPFOV,lFHFOV,lRLFOV: single; lOrient: integer); var lxmm,lymm,lzmm,x,y,z,la,lb,lc: double; dx,dy,dz: single; analyze_to_dicom,base,ra,rb,rc,lmm,patient_to_tal,lZm:TMatrix; begin lNHdr.sform_code := kNIFTI_XFORM_UNKNOWN; if (lZ < 1) or (lY < 1) or (lX < 1) then exit; {a=angle(3,1); b=angle(1,1); c=angle(2,1);} ra := Matrix3DL(1, 0, 0, 0, cos(a*pi/180), -sin(a*pi/180), 0, sin(a*pi/180), cos(a*pi/180)); rb := Matrix3DL(cos(b*pi/180), 0, sin(b*pi/180), 0, 1, 0, -sin(b*pi/180), 0, cos(b*pi/180)); rc := Matrix3DL(cos(c*pi/180), -sin(c*pi/180), 0, sin(c*pi/180), cos(c*pi/180), 0, 0, 0, 1); base.size := size3D; base := MultiplyMatrices(rb,rc); base := MultiplyMatrices(ra,base); if lOrient = 2 then begin //sagittal //dcmMsg('sag'); lmm := Matrix3D ( 0, 0, -1,0, 1, 0, 0, 0, 0, -1, 0,0, 0, 0, 0, 1); lYmm := lAPFOV /lX; lZmm := lFHFOV / lY; //use smallest in plane resolution... SetLarger (lYmm,lZmm); lXmm := lRLFOV /lZ; end else if lOrient = 3 then begin //coronal //dcmMsg('Coronal'); lmm := Matrix3D ( 1, 0, 0,0, 0,0, 1, 0, 0, -1, 0,0, 0, 0, 0, 1); lXmm := lRLFOV /lX; lZmm := lFHFOV / lY; //use smallest in plane resolution... SetLarger (lXmm,lZmm); lYmm := lAPFOV /lZ; end else begin //dcmMsg('Axial '+inttostr(lOrient)); lmm := diag3D(1, 1, 1,1); lXmm := lRLFOV /lX; lYmm := lAPFOV /lY; //use smallest in plane resolution... SetLarger (lXmm,lYmm); lZmm := lFHFOV / lZ; end; lZm := Matrix3D (lxmm,0,0,0, 0,lymm,0,0, 0,0,lZmm,0, 0,0,0,1); patient_to_tal := diag3D(-1, -1, 1,1); analyze_to_dicom := Matrix3D ( 1, 0, 0,0, 0,-1, 0,0, 0, 0, 1,0, 0, 0, 0, 1); //correct- A_tot=patient_to_tal*R_tot*Zm*lmm*analyze_to_dicom; //wrong - A_tot=patient_to_tal*Zm*R_tot*lmm*analyze_to_dicom; {ReportMatrix('Rtot',base); ReportMatrix('zoom',lZm); ReportMatrix('p2tal',patient_to_tal); ReportMatrix('lmm',lmm); ReportMatrix('analyze_to_dicom',analyze_to_dicom);} base := MultiplyMatrices(patient_to_tal,base); base := MultiplyMatrices(base,lZm); base := MultiplyMatrices(base,lmm);//2/2007 suggested by Bas Neggers base:= MultiplyMatrices(base,analyze_to_dicom); x := (lx-1)/2; y := (ly-2)/2; z := (lz-1)/2; la :=(base.matrix[1,1]*x)+(base.matrix[1,2]*y)+(base.matrix[1,3]*z)+base.matrix[1,4]; lb :=(base.matrix[2,1]*x)+(base.matrix[2,2]*y)+(base.matrix[2,3]*z)+base.matrix[2,4]; lc :=(base.matrix[3,1]*x)+(base.matrix[3,2]*y)+(base.matrix[3,3]*z)+base.matrix[3,4]; base.matrix[1,4] := -la-offa; base.matrix[2,4] := -lb-offb; base.matrix[3,4] := -lC+offc; //ReportMatrix('nifti final',base); lNHdr.sform_code := kNIFTI_XFORM_SCANNER_ANAT; lNHdr.srow_x[0] := base.matrix[1,1]; lNHdr.srow_x[1] := base.matrix[1,2]; lNHdr.srow_x[2] := base.matrix[1,3]; lNHdr.srow_x[3] := base.matrix[1,4]; lNHdr.srow_y[0] := base.matrix[2,1]; lNHdr.srow_y[1] := base.matrix[2,2]; lNHdr.srow_y[2] := base.matrix[2,3]; lNHdr.srow_y[3] := base.matrix[2,4]; lNHdr.srow_z[0] := base.matrix[3,1]; lNHdr.srow_z[1] := base.matrix[3,2]; lNHdr.srow_z[2] := base.matrix[3,3]; lNHdr.srow_z[3] := base.matrix[3,4]; lNHdr.qform_code := kNIFTI_XFORM_SCANNER_ANAT; nifti_mat44_to_quatern( base, lNHdr.quatern_b,lNHdr.quatern_c,lNHdr.quatern_d, lNHdr.qoffset_x,lNHdr.qoffset_y,lNHdr.qoffset_z, dx, dy, dz, lNHdr.pixdim[0]{QFac}); end; function DTItextfiles (lImgName: string; lDTIra: TDTIra; lNumDir: integer): boolean; //create text files that describe output vectors var lOutDTIname: string; lTextF: TextFile; lSeries,lStart,lEnd: integer; begin result := false; if lImgName = '' then exit; lStart := 1; lEnd := lNumDir; //ensure some variability lSeries := 1; while (lSeries <= lEnd) and (lDTIra[1].v1 = lDTIra[lSeries].v1) and (lDTIra[1].bval = lDTIra[lSeries].bval) do inc(lSeries); if (lSeries > lEnd) then exit; //no variability in bvec or bval //create bvec lOutDTIname := changefileextX(lImgName,'.bvec'); assignfile(lTextF,lOutDTIname); Filemode := 0; rewrite(lTextF); for lSeries := lStart to lEnd do Write(lTextF,floattostr(lDTIra[lSeries].v1)+ ' '); Writeln(lTextF); for lSeries := lStart to lEnd do Write(lTextF,floattostr(lDTIra[lSeries].v2)+ ' '); Writeln(lTextF); for lSeries := lStart to lEnd do Write(lTextF,floattostr(lDTIra[lSeries].v3)+ ' '); Writeln(lTextF); closefile(lTextF); //create bval lOutDTIname := changefileextX(lOutDTIname,'.bval'); assignfile(lTextF,lOutDTIname); Filemode := 0; rewrite(lTextF); for lSeries := lStart to lEnd do Write(lTextF,inttostr(lDTIra[lSeries].bval)+' '); Writeln(lTextF); closefile(lTextF); result := true; end;// funct DTItextfiles procedure read_PAR2NII(var lNHdr: TNIftIHdr; var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK,lPrecise:boolean; var lDynStr: string;var lFileName: string; lReadOffsetTables: boolean; var lOffset_pos_table: LongIntp; var lOffsetTableEntries,lRescaleEntries: integer; var lSlopeRA,lInterceptRA: Singlep; var lnum4Ddatasets, lSliceOrient: integer; var lDTIra: TDTIra); label 333; //1384 now reads up to 8 dimensional data.... type tRange = record Min,Val,Max: double; //some vals are ints, others floats end; const UNIXeoln = chr(10); kMaxnSLices = 18000;//delphi 32000 - lazarus fails >15000 kXdim = 1; kYdim = 2; kBitsPerVoxel = 3; kSliceThick = 4; kSliceGap = 5; kXmm = 6; kYmm = 7; kRS = 8; kRI = 9; kSS = 10; //1393 - attempt to use calibrated values kDynTime = 11; kSlice = 12; kEcho = 13; kDyn = 14; kCardiac = 15; kType = 16; kSequence = 17; kASL = 18; kIndex = 19; lIsParVers3: boolean = true; lIsParVers42: boolean = false; lIsParVers41: boolean = false; lRepeatedValues : boolean = false; lSlicesNotInSequence: boolean = false; lMaxSlice : integer = 0; lMaxIndex : integer = 0; lSliceSz: integer = 0; lMatOrient: boolean = false; //lOffsetTablesRequired: boolean = false; var lDTIraDyn, lDTIraDynUnSorted: array of TDTI; //lDTIra: TDTIra; //lHFSStr, lErrorStr,lInStr,lUpCaseStr,lReportedTRStr: string; lAPFOV,lFHFOV,lRLFOV, lScanResX,lScanResY,lAngleA,lAngleB,lAngleC,lOffset1,lOffset2,lOffset3{,lXFOV,lYFOV}: double; lSliceIndexRAx,lSliceSequenceRA,lSortedSliceSequence: int64P; //lSliceIndexRA: array [1..kMaxnSlices] of longint; //lSSx,lRSx,lRIx: array [1..kMaxnSlices] of single; lSlopeRAx,lInterceptRAx: array [1..kMaxnSlices] of single; lSliceHeaderRA: array [1..50] of double; //lRepeatedValues,lSlicesNotInSequence,lIsParVers3: boolean;//,lMissingVolumes,{,lLongRAtooSmall,lMissingVolumes,lConstantScale,lContiguousSlices,} lRangeRA: array [kXdim..kIndex] of tRange; lSliceInfoCount,lPos,lLen,lFileSz,lHdrPos,linPos,lInc,lOrient: integer; fp: file; lCharRA: bytep; procedure MinMaxTRange (var lDimension: tRange; lNewVal: double); //nested begin lDimension.Val := lNewVal; if lSliceInfoCount < 2 then begin lDimension.Min := lDimension.Val; lDimension.Max := lDimension.Val; end; if lNewVal < lDimension.Min then lDimension.Min := lNewVal; if lNewVal > lDimension.Max then lDimension.Max := lNewVal; end; //nested InitTRange proc function readParStr:string;//nested var lStr: string; begin lStr := ''; While (lPos <= lLen) do begin if (lStr <> '') or (linStr[lPos]<>' ') then //strip leading spaces lStr := lStr+(linStr[lPos]); inc(lPos); end; //while lPOs < lLen result := lStr; end; //nested func ReadParStr function readParFloat:double;//nested var lStr: string; begin lStr := ''; result := 1; While (lPos <= lLen) and ((lStr='') or(lInStr[lPos] <> ' ')) do begin if lInStr[lPos] in ['+','-','e','E','.','0'..'9'] then lStr := lStr+(linStr[lPos]); inc(lPos); end; if lStr = '' then exit; try result := strtofloat(lStr); except on EConvertError do begin dcmMsg('read_PAR2NII: Unable to convert the string '+lStr+' to a number'); result := 1; exit; end; end; {except} end; //nested func ReadParFloat begin //Initialize parameters lOrient := 0; lAPFOV := 1; lnum4Ddatasets := 1; lMatOrient := false; lIsParVers3 := true; lIsParVers41 := false; lIsParVers42 := false; lSliceInfoCount := 0; getmem(lSliceIndexRAx, kMaxnSLices* sizeof(int64)); setlength(lDTIraDyn,kMaxnSLices+1);//+1 since indexed from zero for lInc := kXdim to kIndex do //initialize all values: important as PAR3 will not explicitly report all MinMaxTRange(lRangeRA[lInc],0); lHdrOK := false; lImageFormatOK := false; lRescaleEntries := 0; lOffsetTableEntries := 0; Clear_Dicom_Data(lDicomData); lDynStr := ''; //Read text header to buffer (lCharRA) FileMode := 0; //set to readonly AssignFile(fp, lFileName); Reset(fp, 1); lFileSz := FileSize(fp); GetMem( lCharRA, lFileSz+1 ); //note: must free dynamic memory: goto 333 if any error GetMem (lSliceSequenceRA, kMaxnSLices*sizeof(int64)); //note: must free dynamic memory: goto 333 if any error BlockRead(fp, lCharRA^, lFileSz, lInpos); if lInPos <> lFileSz then begin dcmMsg('read_PAR2NII: Disk error, unable to read full input file.'); goto 333; end; linPos := 1; CloseFile(fp); FileMode := 2; //set to read/write //Next: read each line of header file... repeat //for each line in file.... linstr := ''; while (linPos < lFileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin lInStr := lInstr + chr(lCharRA^[linPos]); inc(linPos); end; inc(lInPos); //read EOLN lLen := length(lInStr); lPos := 1; lUpcaseStr := ''; if lLen < 1 then //ignore blank lines else if (lInStr[1] = '*') and (not lHdrOK) then //# -> comment //ignore comment lines prior to start of header else if (lInStr[1] = '#') and (lHdrOK) then begin//# -> comment ignore UNLESS it reveals version if (Length(lInStr)> 16) and (lInStr[3] = 'C') and (Copy(lInStr,3,15) = 'CLINICAL TRYOUT') then begin lUpCaseStr := ''; lHdrPos := Length(lInStr); while (lHdrPos > 0) and (UpCase(lInStr[lHdrPos]) <> 'V') do begin if lInStr[lHdrPos] in ['.', '0'..'9'] then lUpCaseStr := UpCase(lInStr[lHdrPos])+lUpCaseStr; dec(lHdrPos); end; if lUpCaseStr = '3' then lIsParVers3 := true else if lUpCaseStr = '4' then lIsParVers3 := false else if lUpCaseStr = '4.1' then begin lIsParVers3 := false; lIsParVers41 := true; dcmMsg('PAR v4.1 not yet fully supported') end else if lUpCaseStr = '4.2' then begin //11/2007 lIsParVers3 := false; lIsParVers41 := true; lIsParVers42 := true; //dcmMsg('PAR v4.2 : DTI bval/bvec support still experimental') end else dcmMsg('Warning: unknown PAR version '+lUpCaseStr); end; end else if (lInStr[1] = '.') or (not lHdrOK) then begin // GENERAL_INFORMATION section (line starts with '.') //Note we also read in lines that do not have '.' if we have HdrOK=false, this allows us to detect the DATADESCRIPTIONFILE signature While (lPos <= lLen) and (lInStr[lPos] <> ':') and ((not lHdrOK) or (lInStr[lPos] <> '#')) do begin if lInStr[lPos] in ['[',']','(',')','/','+','-',{' ',} '0'..'9','a'..'z','A'..'Z'] then lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]); inc(lPos); end; //while reading line inc(lPos); {read equal sign in := statement} lDynStr := lDynStr + lInStr+kCR; //dcmMsg(inttostr(length(lUpCaseStr))); if (not lHdrOK) and (lUpcaseStr = ('DATADESCRIPTIONFILE')) then begin //1389 PAR file lHdrOK := true; lDicomData.little_endian := 1; end; if (lUpCaseStr ='REPETITIONTIME[MSEC]') or (lUpCaseStr ='REPETITIONTIME[MS]') then lDicomData.TR := round(readParFloat); if (lUpCaseStr ='MAXNUMBEROFSLICES/LOCATIONS') then lDicomData.XYZdim[3] := round(readParFloat); if (lUpCaseStr ='SLICETHICKNESS[MM]') then MinMaxTRange(lRangeRA[kSliceThick],readParFloat); if (lUpCaseStr ='SLICEGAP[MM]') then MinMaxTRange(lRangeRA[kSliceGap],readParFloat); if lUpCaseStr = 'FOV(APFHRL)[MM]' then begin lDicomData.XYZmm[2] := (readParFloat); //AP anterior->posterior lDicomData.XYZmm[3] := (readParFloat); //FH foot head lDicomData.XYZmm[1] := (readParFloat); //RL Right-Left lAPFOV := lDicomData.XYZmm[2]; lFHFOV := lDicomData.XYZmm[3]; lRLFOV := lDicomData.XYZmm[1]; end; if lUpCaseStr = 'SCANRESOLUTION(XY)' then begin lScanResX := round(readParFloat); lScanResY := round(readParFloat); end; {if lUpCaseStr = 'SCANPERCENTAGE' then begin lScanPct := round(readParFloat); end; } if lUpCaseStr = 'RECONRESOLUTION(XY)' then begin MinMaxTRange(lRangeRA[kXdim],readParFloat); MinMaxTRange(lRangeRA[kYdim],readParFloat); end; if lUpCaseStr = 'RECONSTRUCTIONNR' then lDicomData.AcquNum := round(readParFloat); if lUpCaseStr = 'ACQUISITIONNR' then lDicomData.SeriesNum := round(readParFloat); if lUpCaseStr = 'MAXNUMBEROFDYNAMICS' then begin lDicomData.XYZdim[4] := round(readParFloat); end; if lUpCaseStr = 'EXAMINATIONDATE/TIME' then begin lDicomData.StudyDate := readParStr; PAR2DICOMstudyDate(lDicomData); end; if (lUpCaseStr ='ANGULATIONMIDSLICE(APFHRL)[DEGR]') then begin lAngleA := (readParFloat); lAngleB := (readParFloat); lAngleC := (readParFloat); lDicomData.AngulationAP := lAngleA; lDicomData.AngulationFH := lAngleB; lDicomData.AngulationRL := lAngleC; end; if (lUpCaseStr ='OFFCENTREMIDSLICE(APFHRL)[MM]') then begin lOffset2 := (readParFloat); lOffset3 := (readParFloat); lOffset1 := (readParFloat); end; if lUpCaseStr = 'PROTOCOLNAME' then lDicomData.ProtocolName := readParStr; if lUpCaseStr = 'PATIENTPOSITION' then begin lDicomData.PatientPos := UpperCase (readParStr); //upcase if (lDicomData.PatientPos <> 'HEAD FIRST SUPINE') then dcmMsg('*WARNING: participant was not head first supine - spatial transforms may be wrong :'+lDicomData.PatientPos) else lDicomData.PatientPos := 'HFS'; end; if lUpCaseStr = 'PATIENTNAME' then lDicomData.PatientName := readParStr; if lUpCaseStr ='IMAGEPIXELSIZE[8OR16BITS]' then begin MinMaxTRange(lRangeRA[kBitsPerVoxel],readParFloat); end; if not lHdrOK then begin dcmMsg('read_PAR2NII: Error reading header'); goto 333; end; end else begin //SliceInfo: IMAGE_INFORMATION (line does NOT start with '.' or '#') inc(lSliceInfoCount); if (lSliceInfoCount < 2) and (lRangeRA[kBitsPerVoxel].val < 1) then //PARvers3 has imagedepth in general header, only in image header for later versions lIsParVers3 := false; for lHdrPos := 1 to 26 do lSliceHeaderRA[lHdrPos] := readparfloat; //The next few values are in the same location for both PAR3 and PAR4 MinMaxTRange(lRangeRA[kSlice], round(lSliceHeaderRA[1])); MinMaxTRange(lRangeRA[kEcho], round(lSliceHeaderRA[2])); MinMaxTRange(lRangeRA[kDyn], round(lSliceHeaderRA[3])); if not lIsParVers42 then //if 4.2 then we will use combination of Cardiac and ASL for cardiac number MinMaxTRange(lRangeRA[kCardiac], round(lSliceHeaderRA[4])); MinMaxTRange(lRangeRA[kType], round(lSliceHeaderRA[5])); MinMaxTRange(lRangeRA[kSequence], round(lSliceHeaderRA[6])); MinMaxTRange(lRangeRA[kIndex], round(lSliceHeaderRA[7])); if lIsParVers3 then begin //Read PAR3 data MinMaxTRange(lRangeRA[kRI], lSliceHeaderRA[8]);; //8=intercept in PAR3 MinMaxTRange(lRangeRA[kRS],lSliceHeaderRA[9]); //9=slope in PAR3 MinMaxTRange(lRangeRA[kSS],lSliceHeaderRA[10]); //10=lcalibrated slope in PAR3 1393 - attempt to use calibrated values //MinMaxTRange(lRangeRA[kXmm],lSliceHeaderRA[23]); //23 PIXEL SPACING X in PAR3 //MinMaxTRange(lRangeRA[kYmm],lSliceHeaderRA[24]); //24 PIXEL SPACING Y IN PAR3 MinMaxTRange(lRangeRA[kDynTime],(lSliceHeaderRA[26])); //26= dyn_scan_begin_time in PAR3 end else begin //not PAR: assume PAR4 for lHdrPos := 27 to 32 do lSliceHeaderRA[lHdrPos] := readparfloat; MinMaxTRange(lRangeRA[kBitsPerVoxel],lSliceHeaderRA[8]);//8 BITS in PAR4 MinMaxTRange(lRangeRA[kXdim], lSliceHeaderRA[10]); //10 XDim in PAR4 MinMaxTRange(lRangeRA[kYdim], lSliceHeaderRA[11]); //11 YDim in PAR4 MinMaxTRange(lRangeRA[kRI],lSliceHeaderRA[12]); //12=intercept in PAR4 MinMaxTRange(lRangeRA[kRS],lSliceHeaderRA[13]); //13=lslope in PAR4 MinMaxTRange(lRangeRA[kSS],lSliceHeaderRA[14]); //14=lcalibrated slope in PAR4 1393 - attempt to use calibrated values MinMaxTRange(lRangeRA[kDynTime],(lSliceHeaderRA[32]));//32= dyn_scan_begin_time in PAR4 if lIsParVers41 then begin for lHdrPos := 33 to 47 do lSliceHeaderRA[lHdrPos] := readparfloat; if ({diff}lSliceHeaderRA[34]<> 0) and ({grad}lSliceHeaderRA[43]<> 0) then //DTI scan - treat as dynamics MinMaxTRange(lRangeRA[kDyn], ({diff}lSliceHeaderRA[34]*100)+ ({gradient}lSliceHeaderRA[43]) ); if lIsParVers42 then begin for lHdrPos := 48 to 49 do lSliceHeaderRA[lHdrPos] := readparfloat; //fx(lSliceInfoCount,lSliceHeaderRA[46],lSliceHeaderRA[47],lSliceHeaderRA[48]); lSliceOrient := round(lSliceHeaderRA[26]); lDTIraDyn[lSliceInfoCount].bval := round(lSliceHeaderRA[34]); //# diffusion (ap, fh, rl) (3*float) 46=AP=Y,47=FH=Z,48=RL=X lDTIraDyn[lSliceInfoCount].v1 := lSliceHeaderRA[48]; lDTIraDyn[lSliceInfoCount].v2 := lSliceHeaderRA[46]; lDTIraDyn[lSliceInfoCount].v3 := lSliceHeaderRA[47]; MinMaxTRange(lRangeRA[kCardiac], ({cardiac}lSliceHeaderRA[49]*100)+ ({asl}lSliceHeaderRA[4]) ); end; //PAR42 end; //PAR41 end; //PAR4 if lSliceInfoCount < kMaxnSlices then begin lSliceSequenceRA^[lSliceInfoCount] := (round(lRangeRA[kSequence].val) shl 48)+(round(lRangeRA[kType].val) shl 40)+(round(lRangeRA[kCardiac].val) shl 32)+(round(lRangeRA[kEcho].val) shl 24)+(round(lRangeRA[kDyn].val) shl 10)+round(lRangeRA[kSlice].val); (*lRSx [lSliceInfoCount] := lRangeRA[kRS].Val; lRIx [lSliceInfoCount] := lRangeRA[kRI].val; lSSx [lSliceInfoCount] := lRangeRA[kSS].Val; *) // fx( lRangeRA[kType].val ,lRangeRA[kEcho].val); PhilipsPrecise (lRangeRA[kRS].Val, lRangeRA[kRI].val,lRangeRA[kSS].Val,lSlopeRAx[lSliceInfoCount],lInterceptRAx[lSliceInfoCount],lPrecise); lSliceIndexRAx^[lSliceInfoCount]:= round(lRangeRA[kIndex].val); end; if (not lMatOrient) and (lSliceHeaderRA[1]=1) and (lSliceHeaderRA[2]=1) {and (lSliceHeaderRA[3]=1)} and (lSliceHeaderRA[4]=1) then begin lMatOrient := true; //first slice/echo/-dynamic/cardiac --- take slice position information from this slice... //par4 - 20,21,22 ; par3 16,17,18 if lIsParVers3 then lOrient := round(lSliceHeaderRA[19]) else lOrient := round(lSliceHeaderRA[26]); //# slice orientation ( TRA/SAG/COR ) (integer) matx(lNHdr,lDicomData,lAngleA,lAngleB,lAngleC,lOffset1,lOffset2,lOffset3, lRangeRA[kXdim].Val,lRangeRA[kYdim].Val,lDicomData.XYZdim[3], lAPFOV,lFHFOV,lRLFOV,lOrient); //procedure mat(b,c,a,offa,offb,offc,lx,ly,lz,lxmm,lymm,lzmm: single); end; end; //SliceInfo Line until (linPos >= lFileSz);//until done reading entire file... //describe generic DICOM parameters lDicomData.XYZdim[1] := round(lRangeRA[kXdim].Val); lDicomData.XYZdim[2] := round(lRangeRA[kYdim].Val); lDicomData.XYZdim[3] := 1+round(lRangeRA[kSlice].Max-lRangeRA[kSlice].Min); if (lSliceInfoCount mod lDicomData.XYZdim[3]) <> 0 then dcmMsg('read_PAR2NII: Total number of slices not divisible by number of slices per volume. Reconstruction error?'); if lDicomData.XYZdim[3] > 0 then lDicomData.XYZdim[4] := lSliceInfoCount div lDicomData.XYZdim[3] //nVolumes = nSlices/nSlicePerVol else lDicomData.XYZdim[4] := 1; if lOrient = 2 then begin //sagittal lDicomData.XYZmm[1] := lAPFOV /lDicomData.XYZdim[1]; lDicomData.XYZmm[2] := lFHFOV / lDicomData.XYZdim[2]; lDicomData.XYZmm[3] := lRLFOV /lDicomData.XYZdim[3]; end else if lOrient = 3 then begin //coronal lDicomData.XYZmm[1] := lRLFOV /lDicomData.XYZdim[1]; lDicomData.XYZmm[2] := lFHFOV / lDicomData.XYZdim[2]; lDicomData.XYZmm[3] := lAPFOV /lDicomData.XYZdim[3]; end else begin //axial lDicomData.XYZmm[1] := lRLFOV /lDicomData.XYZdim[1]; lDicomData.XYZmm[2] := lAPFOV /lDicomData.XYZdim[2]; lDicomData.XYZmm[3] := lFHFOV / lDicomData.XYZdim[3]; end; //use smallest in plane resolution... SetLarger (lDicomData.XYZmm[1],lDicomData.XYZmm[2]); lDicomData.Allocbits_per_pixel := round(lRangeRA[kBitsPerVoxel].Val); lDicomData.IntenScale := lRangeRA[kRS].Val; lDicomData.IntenIntercept := lRangeRA[kRI].Val; //Next: report number of Dynamic scans, this allows people to parse DynScans from Type/Cardiac/Echo/Sequence 4D files lnum4Ddatasets := (round(lRangeRA[kDyn].Max - lRangeRA[kDyn].Min)+1)*lDicomData.XYZdim[3]; //slices in each dynamic session if ((lSliceInfoCount mod lnum4Ddatasets) = 0) and ((lSliceInfoCount div lnum4Ddatasets) > 1) then lnum4Ddatasets := (lSliceInfoCount div lnum4Ddatasets) //infer multiple Type/Cardiac/Echo/Sequence else lnum4Ddatasets := 1; //next: Determine actual interscan interval if (lDicomData.XYZdim[4] > 1) and ((lRangeRA[kDynTime].max-lRangeRA[kDynTime].min)> 0) {1384} then begin lReportedTRStr := 'Reported TR: '+floattostrf(lDicomData.TR,ffFixed,8,2)+kCR; lDicomData.TR := (lRangeRA[kDynTime].max-lRangeRA[kDynTime].min) /(lDicomData.XYZdim[4] - 1)*1000; //infer TR in ms end else lReportedTRStr :=''; //next: report header details lDynStr := 'Philips PAR/REC Format' //'PAR/REC Format' +kCR+ 'Patient name:'+lDicomData.PatientName +kCR+ 'XYZ dim: ' +inttostr(lDicomData.XYZdim[1])+'/'+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) +kCR+'Volumes: ' +inttostr(lDicomData.XYZdim[4]) +kCR+'XYZ mm: '+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/' +floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2) +kCR+'TR: '+floattostrf(lDicomData.TR,ffFixed,8,2) +kCR+lReportedTRStr+kCR+lDynStr; //if we get here, the header is fine, next steps will see if image format is readable... lHdrOK := true; if lSliceInfoCount < 1 then begin dcmMsg('No valid images found.') ; goto 333; end; //next: see if slices are in sequence lSlicesNotInSequence := false; if lSliceInfoCount > 1 then begin lMaxSlice := lSliceSequenceRA^[1]; lMaxIndex := lSliceIndexRAx^[1]; lInc := 1; repeat inc(lInc); if lSliceSequenceRA^[lInc] < lMaxSlice then //not in sequence if image has lower slice order than previous image lSlicesNotInSequence := true else lMaxSlice := lSliceSequenceRA^[lInc]; if lSliceIndexRAx^[lInc] < lMaxIndex then //not in sequence if image has lower slice index than previous image lSlicesNotInSequence := true else lMaxIndex := lSliceIndexRAx^[lInc]; until (lInc = lSliceInfoCount) or (lSlicesNotInSequence); end; //at least 2 slices //Next: report any errors lErrorStr := ''; if (lSlicesNotInSequence) and (not lReadOffsetTables) then lErrorStr := lErrorStr + ' Slices not saved sequentially [using MRIcro''s ''Philips PAR to Analyze'' command may solve this]'+kCR; if lSliceInfoCount > kMaxnSlices then lErrorStr := lErrorStr + ' Too many slices: >'+inttostr(kMaxnSlices)+kCR; if (lRangeRA[kBitsPerVoxel].min <> lRangeRA[kBitsPerVoxel].max) then //5D file space+time+cardiac lErrorStr := lErrorStr + ' Differing bits per voxel'+kCR; //if (lRangeRA[kCardiac].min <> lRangeRA[kCardiac].max) then //5D file space+time+cardiac // lErrorStr := lErrorStr + 'Multiple cardiac timepoints'+kCR; //if (lRangeRA[kEcho].min <> lRangeRA[kEcho].max) then //5D file space+time+echo // lErrorStr := lErrorStr + 'Multiple echo timepoints'+kCR; if (lRangeRA[kSliceThick].min <> lRangeRA[kSliceThick].max) or (lRangeRA[kSliceGap].min <> lRangeRA[kSliceGap].max) or (lRangeRA[kXdim].min <> lRangeRA[kXdim].max) or (lRangeRA[kYDim].min <> lRangeRA[kYDim].max) or (lRangeRA[kXmm].min <> lRangeRA[kXmm].max) or (lRangeRA[kYmm].min <> lRangeRA[kYmm].max) then lErrorStr := lErrorStr + ' Multiple/varying slice dimensions'+kCR; //if any errors were encountered, report them.... if lErrorStr <> '' then begin dcmMsg('read_PAR2NII: This software can not convert this Philips data:'+kCR+lErrorStr); goto 333; end; //Next sort image indexes here... if (lSliceInfoCount > 1) and(lSlicesNotInSequence) and ( lReadOffsetTables) then begin //sort image order... //ShellSort (first, last: integer; var lPositionRA, lIndexLoRA,lIndexHiRA: LongintP; var lRepeatedValues: boolean) GetMem (lOffset_pos_table, lSliceInfoCount*sizeof(int64)); for lInc := 1 to lSliceInfoCount do lOffset_pos_table^[lInc] := lInc; ShellSortItems (1, lSliceInfoCount,lOffset_pos_table,lSliceSequenceRA, lRepeatedValues); (* if lRepeatedValues then begin dcmMsg('read_PAR2NII: fatal error, slices do not appear to have unique indexes [multiple copies of same slice]'); FreeMem (lOffset_pos_table); goto 333; end; *) lOffsetTableEntries := lSliceInfoCount; end; //sort image order... //Next, generate list of scale slope (*lOffsetTablesRequired := false; if (lSliceInfoCount > 1) and ( (lRangeRA[kSS].min <> lRangeRA[kSS].max) or (lRangeRA[kRS].min <> lRangeRA[kRS].max) or (lRangeRA[kRI].min <> lRangeRA[kRI].max)) then lOffsetTablesRequired := true; *) lDicomData.IntenScale := lSlopeRAx[1]; lDicomData.IntenIntercept := lInterceptRAx[1]; //PhilipsPrecise (lRSx[lInc], lRIx[lInc],lSSx[lInc], lDicomData.IntenScale,lDicomData.IntenIntercept); //if lOffsetTablesRequired then begin // dcmMsg('Image saved as 32-bit data: varying intensity scaling factors or complicated Pixel to Precise transform'); if (lRangeRA[kSS].min = lRangeRA[kSS].max) and (lRangeRA[kRS].min = lRangeRA[kRS].max) and (lRangeRA[kRI].min = lRangeRA[kRI].max) then lRescaleEntries := 0 else begin lRescaleEntries := lSliceInfoCount; getmem (lSlopeRA, lRescaleEntries*sizeof(single)); getmem (lInterceptRA, lRescaleEntries*sizeof(single)); if lOffsetTableEntries = lSliceInfoCount then begin //need to sort slices setlength(lDTIraDynUnSorted,lSliceInfoCount+1);//+1 since indexed from zero for lInc := 1 to lSliceInfoCount do lDTIraDynUnSorted[lInc] := lDTIraDyn[lInc]; for lInc := 1 to lSliceInfoCount do begin lSlopeRA^[lInc] := lSlopeRAx[lOffset_pos_table^[lInc]]; lInterceptRA^[lInc] := lInterceptRAx[lOffset_pos_table^[lInc]]; lDTIraDyn[lInc] := lDTIraDynUnSorted[lOffset_pos_table^[lInc]]; end; end else begin //if sorted, else unsorted for lInc := 1 to lSliceInfoCount do begin lSlopeRA^[lInc] := lSlopeRAx[lInc]; lInterceptRA^[lInc] := lInterceptRAx[lInc]; end; end; //slices sorted end;//read scale factors //Next: now adjust Offsets to point to byte offset instead of slice number lSliceSz := lDicomData.XYZdim[1]*lDicomData.XYZdim[2]*(lDicomData.Allocbits_per_pixel div 8); if lOffsetTableEntries = lSliceInfoCount then for lInc := 1 to lSliceInfoCount do lOffset_pos_table^[lInc] := lSliceSz * (lSliceIndexRAx^[lOffset_pos_table^[lInc]]); //report if 5D/6D/7D file is being saved as 4D if (lRangeRA[kCardiac].min <> lRangeRA[kCardiac].max) or (lRangeRA[kEcho].min <> lRangeRA[kEcho].max) //5D file space+time+echo or (lRangeRA[kType].min <> lRangeRA[kType].max) //5D file space+time+echo or (lRangeRA[kSequence].min <> lRangeRA[kSequence].max) then begin//5D file space+time+echo dcmMsg('Warning: note that this image has more than 4 dimensions (multiple Cardiac/Echo/Type/Sequence)'); dcmMsg('Cardiac min..max '+floattostr(lRangeRA[kCardiac].min)+'..'+floattostr(lRangeRA[kCardiac].max) ); dcmMsg('Echo min..max '+floattostr(lRangeRA[kEcho].min)+'..'+floattostr(lRangeRA[kEcho].max) ); dcmMsg('Type min..max '+floattostr(lRangeRA[kType].min)+'..'+floattostr(lRangeRA[kType].max) ); dcmMsg('Sequence min..max '+floattostr(lRangeRA[kSequence].min)+'..'+floattostr(lRangeRA[kSequence].max) ); end; //if we get here, the Image Format is OK lImageFormatOK := true; lFileName := changefileextX(lFilename,'.rec'); //for Linux: case sensitive extension search '.rec' <> '.REC' //next save dti b-values if (lIsParVers42) and (lDicomData.XYZdim[4] <= kMaxDTIDir) and (lDicomData.XYZdim[4] > 1) then begin for lInc := 1 to lDicomData.XYZdim[4] do lDTIra[lInc] := lDTIraDyn[(lDicomData.XYZdim[3]*(lInc-1))+1]; //see if bval or bvec varies... lInc := 1; while (lInc <= lDicomData.XYZdim[4]) and (lDTIra[lInc].bval = lDTIra[1].bval) and (lDTIra[lInc].v1 = lDTIra[1].v1) do inc(lInc); //warn if untested orientation if (lInc <= lDicomData.XYZdim[4]) and (lOrient <> 1) then dcmMsg('WARNING: DTI vectors only tested for transsaxially oriented Philips data: bvec values may be inaccurate!'); (*if (lInc <= lDicomData.XYZdim[4]) then begin//bvec or bval vary //# slice orientation ( TRA/SAG/COR ) (integer) if lOrient <> 1 then dcmMsg('WARNING: DTI vectors only tested for transsaxially oriented Philips data: bvec values may be inaccurate!'); PhilipsCorrectBvecs(lDICOMdata, lDTIra, lDicomData.XYZdim[4]); DTItextfiles (lFileName, lDTIra, lDicomData.XYZdim[4]); end; *) end else begin //not DTI data - provide empty bvec/bval file lDTIra[1].bval := 0; lDTIra[1].v1 := 0; lDTIra[1].v2 := 0; lDTIra[1].v3 := 0; for lInc := 1 to lDicomData.XYZdim[4] do lDTIra[lInc] := lDTIra[1]; end; 333: //abort clause: skips lHdrOK and lImageFormatOK //next: free dynamically allocated memory FreeMem( lCharRA); FreeMem (lSliceSequenceRA); Freemem(lSliceIndexRAx); end; (*function StudySecSince2KStr (lInSec: integer): string; var days,secs,Y,M,D,H,Min,S, l,n,i,j: integer; begin result := 'DateNA';//bogus days := (lInSec div 86400)+2451547;//+2451547 as we convert to julian //dcmMsg(inttostr(days)); //next convert Y,M,D l := days + 68569; n := trunc(( 4 * l ) / 146097); l := trunc(l - ( 146097 * n + 3 ) / 4); i := trunc(( 4000 * ( l + 1 ) ) / 1461001); l := trunc(l - ( 1461 * i ) / 4 + 31); j := trunc(( 80 * l ) / 2447 ); d := trunc(l - ( 2447 * j ) / 80); l := trunc(j / 11); m := j + 2 - ( 12 * l ); y := 100 * ( n - 49 ) + i + l; //next convert H,Min,Sec if lInSec < 0 then begin//date prior to 2000 -saved as negative secs := (lInSec - ( (lInSec div 86400)*86400)+86400) mod 86400 end else secs := lInSec mod 86400; //value 0..86399 S := secs mod 60; Min := (secs div 60) mod 60; H := (secs div 3600)+1; result := PadStr (Y, 4)+ PadStr (M, 2)+PadStr (D, 2)+'_'+PadStr (H, 2)+ PadStr (Min, 2)+PadStr (S, 2); end;*) function UniqueFileName (var lInStr: string): boolean; var lInc: integer; lPathWName,lExt: string; begin result := true; if not Fileexists(lInStr) then exit; ExtractFileParts(lInStr,lPathWName,lExt); lInc := ord('A'); while (lInc <= ord('Z')) and ( Fileexists(lPathWName+chr(lInc)+lExt)) do inc(lInc); if lInc > ord('Z') then result := false else lInStr := lPathWName+chr(lInc)+lExt; end; type TiVec = array[1..3] of integer; const kSliceOrientTra = 1; kSliceOrientSag = 2; kSliceOrientCor = 3; procedure nifti_mat33_reorder_cols(var m: TMatrix; v: TiVec ) ; var inMat : TMatrix; r,c: integer; begin // matlab equivalent ret = m(:, v); where v is 1,2,3 [INDEXED FROM ONE!!!!] InMat := m; for r := 1 to 3 do for c := 1 to 3 do m.matrix[r,c] := InMat.matrix[r,v[c]]; //v[c] end; //nifti_mat33_reorder_cols() procedure computeOrient(var d: dicomdata; lSliceOrients: integer); var ang1, ang2,ang3: double; ca, sa: TVector; rx,ry,rz,R: TMatrix; row,col: integer; ixyz: TiVec; begin //see Xiangrui Li 's dicm2nii (also BSD license) // http://www.mathworks.com/matlabcentral/fileexchange/42997-dicom-to-nifti-converter // Rotation order and signs are figured out by try and err, not 100% sure ang1 := d.AngulationRL; ang2 := d.AngulationAP; ang3 := d.AngulationFH; ca := Vector3D(cos(DegToRad(ang1)),cos(DegToRad(ang2)),cos(DegToRad(ang3))); sa := Vector3D(sin(DegToRad(ang1)),sin(DegToRad(ang2)),sin(DegToRad(ang3))); rx := Matrix2D(1.0, 0.0, 0.0, 0.0, ca.vector[1], -sa.vector[1], 0.0, sa.vector[1], ca.vector[1]); ry := Matrix2D(ca.vector[2], 0.0, sa.vector[2], 0.0, 1.0, 0.0, -sa.vector[2], 0.0, ca.vector[2]); rz := Matrix2D(ca.vector[3], -sa.vector[3], 0.0, sa.vector[3], ca.vector[3], 0.0, 0.0, 0.0, 1.0); R := MultiplyMatrices(rx,ry ); R := MultiplyMatrices(R,rz ); //ReportMatrix('mult',R); ixyz[1]:= 1; ixyz[2] := 2; ixyz[3] := 3; //axial slice order ijk = xyz if (lSliceOrients = kSliceOrientSag) then begin//(d.sliceOrient == kSliceOrientSag) { ixyz[1]:= 2; ixyz[2] := 3; ixyz[3] := 1; for row := 1 to 3 do for col := 1 to 3 do begin if (col <> 2) then R.matrix[row,col] := -R.matrix[row,col]; //invert first and final columns end; nifti_mat33_reorder_cols(R,ixyz); end else if (lSliceOrients = kSliceOrientCor) then begin //(d.sliceOrient == kSliceOrientCor) { ixyz[1]:= 1; ixyz[2] := 3; ixyz[3] := 2; for row := 1 to 3 do R.matrix[row,3] := -R.matrix[row,3]; nifti_mat33_reorder_cols(R,ixyz); end; d.orient[1] := R.matrix[1,1]; d.orient[2] := R.matrix[2,1]; d.orient[3] := R.matrix[3,1]; d.orient[4] := R.matrix[1,2]; d.orient[5] := R.matrix[2,2]; d.orient[6] := R.matrix[3,2]; //ReportMatrix('x',R); //dcmmsg(Format('v = %g %g %g %g %g %g', [d.Orient[1], d.Orient[2], d.Orient[3], d.Orient[4], d.Orient[5], d.Orient[6] ])) ; end; function ConvertPhilipsPARtoAnalyze (var lInFilename, lOutDir: string; var lPrefs: TPrefs): boolean; label 678; var //lVaryingScaleFactorsTableEntries, lEnd, lLines,lColBytes,lRows,lRowsdiv2,lSwap,lInc,l4Doffset,lcurrent4Dvol,lnum4Ddatasets,lSlicePixelsx, lnSlicesx, lSliceSzOutx,lSLiceSzx,lRescaleEntries, lPos,lOffsetTableEntries,lSliceOrient: longint; lOutF,lInF: File; lNHdr,lAHdr: TNIFTIhdr; lP,lBuffer : Bytep; lFileName,lRECFilename,lOutImgName,lOutHdrName,lOutHdrNameGz,lDynStr,lOutDirPath: String; lDICOMdata: dicomdata; lScaleFactorVariesInThis4DVolume,lAbort,lHdrOK, lImageFormatOK: boolean; lSlopeRA,lInterceptRA, lSingleBuffer: Singlep; lOffset_pos_table: LongIntp; lDTIra: TDTIra; begin result := false; lSliceOrient := kSliceOrientTra; lFileName := lInFilename; if (lOutDir = '') then lOutDirPath := ExtractFilePath(lFileName)//ExtractFileDirWithPathDelim(lFilename)//ExtractFilePath(lFileName) else if not direxists(lOutDir) then begin dcmMsg('Unable to find output directory '+lOutDir); lOutDirPath := ExtractFilePath(lFileName) end else lOutDirPath := lOutDir; if (length(lOutDirPath) > 0) and (lOutDirPath[length(lOutDirPath)] <> pathdelim) then lOutDirPath := lOutDirPath + pathdelim; lAbort := false; lRecFilename :=ChangeFileExt(lFileName,'.rec'); dcmMsg('input name '+ lInFilename); dcmMsg('input REC name '+lRecFilename); //Apr08 problems with filenames with . in them lRecFilename :=ExtractFilePath(lFileName)+ParseFileName(ExtractFileName(lFileName))+'.rec'; if not fileexists(lRecFilename) then //might be Linux: case sensitive extensions lRecFilename :=ChangeFileExt(lFileName,'.REC'); // lRecFilename :=ExtractFilePath(lFileName)+ParseFileName(ExtractFileName(lFileName))+'.REC'; if not fileexists(lRecFilename) then dcmMsg('Unable to find REC image data file named '+lRecFileName) else if fileexists(lRecFilename) and fileexists(lFilename) then begin //convert read_par2NII(lNHdr,lDICOMdata,lHdrOK,lImageFormatOK,lPRefs.PhilipsPrecise, lDynStr,lFileName,true,lOffset_pos_table,lOffsetTableEntries,lRescaleEntries, lSlopeRA,lInterceptRA,lnum4Ddatasets,lSliceOrient,lDTIra); if (lnum4Ddatasets > 1) and ((lDicomData.XYZdim[4] mod lnum4Ddatasets) = 0) then //break 5D files into separate 4D files lDicomData.XYZdim[4] := lDicomData.XYZdim[4] div lnum4Ddatasets else lnum4Ddatasets := 1; lRows := lDicomData.XYZdim[2]; lRowsdiv2 := lRows div 2; lColBytes := lDicomData.XYZdim[1]*(lDicomData.Allocbits_per_pixel div 8); lSlicePixelsx := (lDicomData.XYZdim[1]*lDicomData.XYZdim[2]); lSliceSzx := lSlicePixelsx*(lDicomData.Allocbits_per_pixel div 8); lnSlicesx := lDicomData.XYZdim[3] * lDicomData.XYZdim[4]; lcurrent4Dvol := 0; l4DOffset := 0; // exit; //crucial critical test exit if lHdrOK then begin repeat //for each 4D volume inc(lcurrent4Dvol); lOutHdrName :=lOutDirPath+{Pathdelim+}OutputFilename(lRecFilename,lDicomData,lPrefs);//Pathdelim 11/2007 if lnum4Ddatasets > 1 then begin l4DOffset := (lcurrent4Dvol-1)* lnSlicesx; lOutHdrName :=(lOutHdrName)+'x'+inttostr(lcurrent4Dvol)+'.hdr' end else lOutHdrName :=(lOutHdrName)+'.hdr'; lOutImgName :=changefileext(lOutHdrName,'.img'); if lPrefs.SingleNIIFile then begin lOutHdrName := changefileext(lOutHdrName,'.nii'); lOutImgName := lOutHdrName; end; if (lPrefs.SingleNIIFile) and (lPrefs.GZip) then begin lOutHdrNameGz := lOutHdrName+'.gz'; if (not UniqueFileName(lOutHdrNameGz)) then begin dcmMsg('File already exists '+lOutImgName+' '+lOutHdrNameGz); exit; end; //we now need to remove the .gz - not that unique filename may have appended postfix, e.g. filename.nii.gz -> filenameA.nii.gz //StripGZExt(lOutHdrName); lOutImgName := lOutHdrName; end else begin if (not UniqueFileName(lOutHdrName)) or (not UniqueFileName(lOutImgName)) then begin dcmMsg('File already exists '+lOutImgName+' '+lOutHdrName); exit; end; end; dcmMsg(lFileName+' -> '+ lOutImgName); //exit; //trap if (lDicomData.XYZdim[4] > 5) then begin //if 4D: save DTI data lInc := 1; while (lInc <= lDicomData.XYZdim[4]) and (lDTIra[lInc].bval = lDTIra[1].bval) and (lDTIra[lInc].v1 = lDTIra[1].v1) do inc(lInc); lEnd := 0; if (lInc <= lDicomData.XYZdim[4]) then begin//bvec or bval vary for linc := 1 to lDicomData.XYZdim[4] do if (lDTIra[lInc].bval = 0) or (lDTIra[lInc].v1 <> 0) or (lDTIra[lInc].v2 <> 0) or (lDTIra[lInc].v3 <> 0) then lEnd := lInc; if (lEnd = (lDicomData.XYZdim[4]-1)) then begin dcmMsg('Warning: final volume is computed ADC and will not be converted (as it would disrupt processing). You can re-create a better ADC image after eddy current correction.'); lDicomData.XYZdim[4] := lEnd; end; computeOrient(lDICOMData,lSliceOrient); siemensPhilipsCorrectBvecs(lDICOMdata, lDTIra, lDicomData.XYZdim[4], false); DTItextfiles (lOutImgName, lDTIra, lDicomData.XYZdim[4]); end; end; //if 4D: save DTI data {$IFDEF LINUX} //perhaps the file is .REC, not .rec if (lSliceSzx * lnSLicesx) > FSize(lFileName) then lRecFilename := changefileext(lFileName,'.REC'); {$ENDIF} if (lSliceSzx * lnSLicesx) > FSize(lRecFilename) then begin dcmMsg('Conversion error: the REC file '+lRecFilename+ ' is not as large as described by the PAR file X*Y*Z*T*BytesPerPixel=' + inttostr(lDicomData.XYZdim[1])+'*'+inttostr(lDicomData.XYZdim[2])+'*'+inttostr(lDicomData.XYZdim[3])+'*'+inttostr(lDicomData.XYZdim[4])+'*'+inttostr(lDicomData.Allocbits_per_pixel div 8) +' = '+ inttostr(lSliceSzx* lnSLicesx)+' <> '+inttostr(FSize(lFileName)) ); {$IFDEF LINUX} dcmMsg(' Suggestion: in UNIX .REC and .rec are different files - check file extension' ); {$ENDIF} lAbort := true; end else if ((sizeof(TNIFTIhdr)+(lSliceSzx*lnSlicesx))> DiskFreeEx(lOutImgName)) then begin dcmMsg('There is not enough free space on the destination disk to save the converted image. '+kCR+ lOutImgName+ kCR+' Bytes Required: '+inttostr(sizeof(TNIFTIhdr)+(lSliceSzx*lnSlicesx)) ); lAbort := true; end else if fileexists(lOutHdrName) or fileexists(lOutImgName) then dcmMsg('Unable to convert images: file already exists named: '+lOutHdrName) else if (not lHdrOK) then dcmMsg('Problem with header...') else if (not lImageFormatOK) then dcmMsg('Problem with image...') else if (lHdrOK) and (lImageFormatOK) and (lDicomData.XYZdim[3] > 0) and (lSliceSzx > 0) then begin DICOM2AnzHdr(lAHdr,lPrefs.Anonymize,lFilename,lDICOMdata); lSliceSzOutx := lSliceSzx; lScaleFactorVariesInThis4DVolume := false; //check if 4D scale slope changes for this 4D dataset... if lRescaleEntries > 0 then begin lAHdr.scl_slope := lSlopeRA^[l4DOffset+1]; lAHdr.scl_inter := lInterceptRA^[l4DOffset+1]; if lRescaleEntries > 0 then begin for lInc := 1 to lnSlicesx do begin if lAHdr.scl_slope <> lSlopeRA^[l4DOffset+lInc] then lScaleFactorVariesInThis4DVolume := true; if lAHdr.scl_inter <> lInterceptRA^[l4DOffset+lInc] then lScaleFactorVariesInThis4DVolume := true; end; end; if lScaleFactorVariesInThis4DVolume then begin lAHdr.bitpix := 32; lAHdr.DataType := 16; lAHdr.scl_slope := 1; lAHdr.scl_inter := 0; lSliceSzOutx := lSlicePixelsx*sizeof(single); end; end; //end of 4D scale factor variation... lAHdr.sform_code := lNHdr.sform_code; lAHdr.srow_x[0] := lNHdr.srow_x[0]; lAHdr.srow_x[1] := lNHdr.srow_x[1]; lAHdr.srow_x[2] := lNHdr.srow_x[2]; lAHdr.srow_x[3] := lNHdr.srow_x[3]; lAHdr.srow_y[0] := lNHdr.srow_y[0]; lAHdr.srow_y[1] := lNHdr.srow_y[1]; lAHdr.srow_y[2] := lNHdr.srow_y[2]; lAHdr.srow_y[3] := lNHdr.srow_y[3]; lAHdr.srow_z[0] := lNHdr.srow_z[0]; lAHdr.srow_z[1] := lNHdr.srow_z[1]; lAHdr.srow_z[2] := lNHdr.srow_z[2]; lAHdr.srow_z[3] := lNHdr.srow_z[3]; lAHdr.qform_code := lNHdr.qform_code; lAHdr.quatern_b := lNHdr.quatern_b; lAHdr.quatern_c := lNHdr.quatern_c; lAHdr.quatern_d := lNHdr.quatern_d; lAHdr.qoffset_x := lNHdr.qoffset_x; lAHdr.qoffset_y := lNHdr.qoffset_y; lAHdr.qoffset_z := lNHdr.qoffset_z; lAHdr.pixdim[0] := lNHdr.pixdim[0]; {$IFDEF ENDIAN_BIG} if SaveHdr (lOutHdrName,lAHdr, true,lPrefs.SPM2) then begin {$ELSE} if SaveHdr (lOutHdrName,lAHdr, false,lPrefs.SPM2) then begin {$ENDIF} Filemode := 2;//1385: read-write AssignFile(lOutF, lOutImgName); if lPrefs.SingleNIIFile then begin Reset(lOutF,1); Seek(lOutF,352); lAHdr.vox_offset := 352; end else Rewrite(lOutF,1); //setting block size only about 12% speed increase: HD cache must help Filemode := 0;//1385: read-only AssignFile(lInF, lRecFilename); Reset(lInF,lSliceSzx); GetMem(lBuffer,lSliceSzx); if lScaleFactorVariesInThis4DVolume then GetMem(lSingleBuffer,lSliceSzOutx); for lInc := 1 to lnSlicesx do begin //application.ProcessMessages; if lOffsetTableEntries > 1 then //data not contiguous Seek(lInF, (lOffset_pos_table^[lInc+l4DOffset] div lSliceSzx)) else Seek(lInF, (l4DOffset+lInc-1)); Filemode := 0; //ReadONly BlockRead(lInF, lBuffer^, 1); Filemode := 2; //read and write GetMem ( lP , lColBytes); for lLines := 1 to lRowsdiv2 do begin Move(lBuffer[((lLines-1)*lColBytes)+1],lP^,lColBytes); Move(lBuffer[(( lRows-lLines)*lColBytes)+1],lBuffer[((lLines-1)*lColBytes)+1],lColBytes); Move(lP^,lBuffer[(( lRows-lLines)*lColBytes)+1],lColBytes); end; FreeMem(lP); if lScaleFactorVariesInThis4DVolume then begin if lDicomData.Allocbits_per_pixel = 8 then begin for lLines := 1 to lSlicePixelsx do lSingleBuffer^[lLines] := lBuffer^[lLines]*lSlopeRA^[l4DOffset+lInc]+lInterceptRA^[l4DOffset+lInc]; end else if lDicomData.Allocbits_per_pixel = 16 then begin lPos := 1; for lLines := 1 to lSlicePixelsx do begin lSingleBuffer^[lLines] := lBuffer^[lLines]*lSlopeRA^[l4DOffset+lInc]+lInterceptRA^[l4DOffset+lInc]; //lSingleBuffer^[lLines] := lBuffer^[lPos]*lRS+lRI; inc(lPos,2); end; end else dcmMsg('Error: can only convert 8/16bit PAR/REC files with varying scaling values.'); BlockWrite(lOutF, lSingleBuffer^, lSliceSzOutx); end else BlockWrite(lOutF, lBuffer^, lSliceSzOutx); end; CloseFile(lOutF); CloseFile(lInF); freemem(lBuffer); if lScaleFactorVariesInThis4DVolume then FreeMem(lSingleBuffer); end else lAbort := true; //save header failed: probably read only disk, or less than 348 bytes: do not force inidividual to see message for each file //if (lPrefs.StartClip > 0) or (lPrefs.EndClip > 0) then // Clip4D(lOutHdrName, lAHdr, false,lPrefs.SPM2,lPrefs.SingleNIIFile,lPrefs.GZip,true, lPrefs.StartClip,lPrefs.EndClip); (*if (not lPrefs.FourD) and (lAHdr.dim[4] > 1) then begin Convert4Dto3D(lOutImgName, lAHdr, false,lPrefs.SPM2,lPrefs.SingleNIIFile, lPrefs.Gzip); end else*) if lPrefs.SingleNIIFile and lPrefs.Gzip then GZipFile(lOutImgName,lOutImgName+'.gz',true) else if ((not lPrefs.FourD) and (lAHdr.dim[4] > 1)) {or ((lPrefs.SingleNIIFile) and (lPrefs.Gzip))} then if ChangeNIfTISubformat(lOutImgName, lAHdr,lPrefs) then begin deleteFile(lOutImgName);//11/2007 : delete original end; end; //file OK until (lcurrent4Dvol>=lnum4Ddatasets) or (lAbort); //for each 4D dataset end; //lHdrOK if lOffsetTableEntries > 0 then begin freemem (lOffset_pos_table); lOffsetTableEntries := 0; end; //slice offset table filled if lRescaleEntries > 0 then begin freemem ( lSlopeRA); freemem (lInterceptRA); end; //slice offset table filled end; //REC exists if lAbort then goto 678; result := true; ExitCode := 0; if (lDicomData.XYZdim[2] > lPrefs.MinReorientMatrix) and (lDicomData.XYZdim[1] > lPrefs.MinReorientMatrix) and (lAHdr.dim[4] < 2) then begin lOutImgName := Reorient(lOutImgName,lAHdr,lPrefs,false,false); if (lOutImgName <> '') {success}and (lDicomData.TE < 25) then //T1 image CropNIfTI(lOutImgName,lPrefs); end; 678: Filemode := 2; //1385 end; function LoadFileListPARREC (var lInFilename, lOutDir: string; var lPrefs: TPrefs): boolean; var lFilePath,lMaskExt,lPARname,lOutDirName: String; lError: boolean; lSearchRec: TSearchRec; begin lOutDirName := lOutDir; if (lPrefs.OutDirMode <> kOutDirModeInput) and (DirExists(lPrefs.OutDir)) then begin //For kOutDirModePrompt one should set OutDir before getting here //This is required so recursive searches do not repetitively prompt the user... lOutDirName := lPrefs.OutDir; end; //1/2010 lOutDirName := ExtractFileDirWithPathDelim(lOutDirName); if not DirWritePermission(lOutDirName) then begin // <- tested with Unix dcmMsg('Error: output directory is read-only: '+lOutDirName); exit; end; lError := false; if lPrefs.EveryFile = true then begin lFilePath := ExtractFileDirWithPathDelim(lInFilename); {$IFDEF Linux} lMaskExt := '*'; {$ELSE} lMaskExt := '*.*'; {$ENDIF} Filemode := 0; //readonly if FindFirst(lFilePath{+PathDelim}+lMaskExt, faAnyFile-faSysFile-faDirectory, lSearchRec) = 0 then begin repeat if UpCaseExt(lSearchRec.Name) = '.PAR' then begin lPARname := (lFilePath+lSearchRec.Name); result := ConvertPhilipsPARtoAnalyze(lPARname, lOutDirName, lPrefs); if not result then lError := true; end; until (FindNext(lSearchRec) <> 0); end else dcmMsg( 'Error: Unable to find PAR files in '+lFilePath{+PathDelim}+lMaskExt); //some files found SysUtils.FindClose(lSearchRec); Filemode := 2; end else begin if FileExists(lInFilename) then begin lError := ConvertPhilipsPARtoAnalyze(lInFilename, lOutDirName, lPrefs); end else dcmMsg( 'Unable to find PAR file named '+lInFilename); //some files found end; if lError then result := false //at least one error else result := true; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2niigui.dpr���������������������������������������������0000755�0001750�0001750�00000000753�11474411340�020275� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������program dcm2niigui; uses Forms, gui in 'gui.pas' {MainForm}, pref_form in 'pref_form.pas' {PrefsForm}, nifti_form in 'nifti_form.pas' {NIfTIform}, untar in 'untar.pas', convertsimple in 'convertsimple.pas'; {$R *.RES} begin Application.Initialize; Application.Title := 'dcm2niiGUI'; Application.CreateForm(TMainForm, MainForm); Application.CreateForm(TPrefsForm, PrefsForm); Application.CreateForm(TNIfTIform, NIfTIform); Application.Run; end. ���������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/readint.dfm������������������������������������������������0000755�0001750�0001750�00000001204�10621205276�017644� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �TREADINTFORM�0n��TPF0 TReadIntForm ReadIntFormLeft9Top� BorderStylebsDialogCaptionInteger required ClientHeightI ClientWidthColor clBtnFace Font.CharsetDEFAULT_CHARSET Font.Color clWindowText Font.Height Font.Name MS Sans Serif Font.Style �OldCreateOrderPositionpoScreenCenter PixelsPerInch` TextHeight �TLabel ReadIntLabelLeftTopWidthKHeight AlignmenttaRightJustifyCaptionEnter a number �� TSpinEdit ReadIntEditLefthTop WidthYHeightMaxValue�MinValue�TabOrderValue���TButtonOKBtnLeftXTop(WidthKHeightCaptionOK ModalResultTabOrder�OnClick OKBtnClick�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dialogs_msg.pas��������������������������������������������0000755�0001750�0001750�00000000751�12204715212�020524� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit dialogs_msg; {$ifdef fpc}{$mode delphi}{$endif} {$Include ..\common\isgui.inc} interface //this wrapper sends text to the main form memo for GUI applications and to the terminal for console applications uses Classes, SysUtils; procedure dcmMsg (lStr: string); implementation {$IFDEF GUI} uses gui; {$ENDIF} procedure dcmMsg (lStr: string); begin {$IFDEF GUI} MainForm.Memo1.Lines.Add(lStr); MainForm.refresh; {$ELSE} writeln(lStr) {$ENDIF} end; end. �����������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2nii.lpr������������������������������������������������0000755�0001750�0001750�00000002261�12204703502�017570� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������program dcm2nii; {$IFDEF FPC} {$mode objfpc} {$ELSE} {$APPTYPE CONSOLE} {$ENDIF} {$H+} uses {$IFDEF UNIX} {$IFDEF UseCThreads} cthreads, {$ENDIF} {$ELSE} shellAPI, Windows, {$ENDIF} Classes, inifiles, SysUtils, convert, define_types, sortdicom, dicom, parconvert, filename, dicomtypes, nii_crop, nii_4dto3d, prefs, dialogsx, paramstrs; {$IFNDEF UNIX} //{$R laz.res} {$ENDIF} (*var lIn,lOut: string; Start: dword; lPrefs: TPrefs; begin Start := GetTickCount; kUseDateTimeForID := true; SetDefaultPrefs (lPrefs); lPrefs.Gzip := true; lPrefs.Anonymize := true; lPrefs.SingleNIIFile := true; lPrefs.everyfile := true; lPrefs.AppendDate := false; lPrefs.AppendAcqSeries := true; lPrefs.AppendProtocolName := true; lPrefs.AppendPatientName := false; lPrefs.fourD := true; lPrefs.AppendFilename := true; lOut := ''; lIn := 'C:\dti64\rapid\IM_0001.dcm'; LoadFileList(lIn,lOut,lPrefs); Msg('Finished. Elapsed time: '+inttostr(GetTickCount-Start)); readln; end. *) begin ShowMsg(kVers); kUseDateTimeForID := true; ProcessParamStrs; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2niigui.rc����������������������������������������������0000755�0001750�0001750�00000000432�12065105430�020103� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define RT_MANIFEST 24 #define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 #define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2 #define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID 3 CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "dcm2niigui.manifest" MAINICON ICON "dcm2niigui.ico" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2nii.ico������������������������������������������������0000755�0001750�0001750�00000001376�10412650546�017563� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ��������(��� ���@�����������������������������������������������������������������foffffoofofffffffofooofoofofooofoofofooofoofofooofoofofoffffffffffofoffffoff��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/nii_asl.pas������������������������������������������������0000755�0001750�0001750�00000055754�12306712714�017676� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit nii_asl; //tools for Arterial spin labeling... {$H+} interface uses //{$IFDEF FPC}gzio2,{$ENDIF} SysUtils,define_types,dicomtypes,niftiutil,prefs,dialogs_msg, nifti_types; function ASL_subtract(var lHdrName: string; lOverwrite: boolean; lFunction : integer; lPrefs: TPrefs): boolean; //ASL_subtract(var lHdrName: string; lOverwrite: boolean; lFunction : integer; lPrefs: TPrefs) implementation uses gui,dialogs; function Parse (var lNumStr: string; var Val1,Val2: integer): boolean; var lS: string; lLen,lP: integer; begin Val1 := 0; Val2 := 0; result := false; lLen := length(lNumStr); if lLen < 3 then exit; lS := ''; lP := 1; while (lP <= lLen) and (lNumStr[lP] <> ',') do begin lS := lS + lNumStr[lP]; inc(lP); end; if lS = '' then exit; try Val1 := strtoint(lS); except dcmMsg('Error converting text to number '+lS); end; //next number inc(lP); lS := ''; while (lP <= lLen) and (lNumStr[lP] <> ',') do begin lS := lS + lNumStr[lP]; inc(lP); end; if lS = '' then exit; try Val2 := strtoint(lS); except dcmMsg('Error converting text to number '+lS); end; result := true; end; function readCSV (lFilename: string; var lnObservations: integer; var lPosRA,lNegRA: LongIntp): boolean; var lNumStr: string; F: TextFile; R,A,B,C: integer; begin lnObservations := 0; result := false; if not fileexists(lFilename) then exit; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); R := 0; while (not Eof(F)) do begin Readln(F,lNumStr); if Parse(lNumStr,A,B) then inc(R); end; if (R < 1) then begin dcmMsg('problems reading CSV: must have at least 2 columns and 1 row.'); exit; end; lnObservations := R; Getmem(lPosRA,lnObservations*sizeof(integer)); Getmem(lNegRA,lnObservations*sizeof(integer)); for R := 1 to lnObservations do begin lPosRA^[R] := -1; lNegRA^[R] := -1; end; //second pass Reset(F); C := 0; while (not Eof(F)) and (C<lnObservations) do begin Readln(F,lNumStr); if Parse(lNumStr,A,B ) then begin inc(C); lPosRA^[C] := A; lNegRA^[C] := B; end; end; CloseFile(F); FileMode := 2; //Set file access to read/write result := true; end; //start 32-bit float versions function SaveMean32 (var lHdrName: string;var lInHdr: TNIFTIhdr; lBuffAligned: bytep;lImgBuffer : SingleP ;lPrefs: TPrefs ): string; var lOutHdr : TNIFTIhdr; lOutImgName: string; lVol,lOutVolOffset,lInc,lImgSamples: integer; lSum: double; begin result := ''; lOutHdr := lInHdr; lImgSamples := lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3]; if (lImgSamples < 1) or (lInHdr.dim[4] < 1) then exit; //next make mean lOutImgName := ChangeFilePrefix (lHdrName,'mean'); for lInc := 1 to lImgSamples do begin lSum := 0; lOutVolOffset := 0; for lVol := 1 to lInHdr.dim[4] do begin lSum := lSum+lImgBuffer^[lOutVolOffset+lInc]; lOutVolOffset := lOutVolOffset+lImgSamples; end; lImgBuffer^[lInc] := (lSum /lOutHdr.dim[4]); end; lOutHdr.dim[4] := 1; result := SaveNIfTICore (lOutImgName, lBuffAligned, kNIIImgOffset+1, lOutHdr, lPrefs); end; //SaveMean32 function ASL_subtract32(var lHdrName: string; lOverwrite: boolean; lFunction : integer; lPrefs: TPrefs): boolean; //lFunction : //0 = Subtract (even-odd) //1= Subtract (odd-even) //2= Subtract custom //3= Add (odd+even) BOLD //4= Parse OddEven aka SplitOddEven //for odd/even, first scan is odd (1), second scan is even (2) [indexed from 1] label 666; var lPosRA,lNegRA: LongIntp; lImgOffset,lVol,lInVolOddOffset,lInVolEvenOffset,lOutVolOffset, lImgSamples,l4DVox,lInc: integer; lCSVname,lResultStr,lOutImgName: string; lInHdr, lOutHdr : TNIFTIhdr; lO: TNIIOpts; lSplitOddEven,lCustom,lSubtract,lOddMinusEven: boolean; lBuffer,lSrcBuffer, lBuffUnaligned,lBuffAligned: bytep; lOdd,lEven: single; lOddVol,lEvenVol: integer; lImgBuffer,l32Buf : SingleP; //lSum: double; begin lSplitOddEven := lFunction = 4; lCustom := lFunction = 2; lOddMinusEven := lFunction = 1; lSubtract := (lFunction <> 3); result := false; if not NIFTIhdr_LoadHdr (lHdrName, lInHdr, lO) then begin dcmMsg('Unable to read as NifTI/Analyze' + lHdrName); exit; end; case lInHdr.datatype of {kDT_UNSIGNED_CHAR,kDT_SIGNED_SHORT,kDT_UINT16, kDT_SIGNED_INT,}kDT_FLOAT:;//Supported else begin dcmMsg('Error with ASL_subtract: image format must be 32-bit floating point values.'); exit; end; end;//case headertype if (odd(lInHdr.dim[4])) or (lInHdr.dim[4] < 2) then begin dcmMsg('ASL routines require an even number of volumes'); exit; end; if not NIFTIhdr_LoadImg (lHdrName, lInHdr, lSrcBuffer, lImgOffset,lO) then exit; lBuffer := (@lSrcBuffer^[lImgOffset+1]); l32Buf := SingleP(lBuffer ); if lOverwrite then lOutImgName := lHdrName else begin if lSplitOddEven then lOutImgName := ChangeFilePrefix (lHdrName,'odd') else if lSubtract then begin if lCustom then lOutImgName := ChangeFilePrefix (lHdrName,'subc') else if lOddMinusEven then lOutImgName := ChangeFilePrefix (lHdrName,'subome') else lOutImgName := ChangeFilePrefix (lHdrName,'subemo') end else lOutImgName := ChangeFilePrefix (lHdrName,'add'); end; lOutHdr := lInHdr; lOutHdr.dim[4] := lInHdr.dim[4] div 2; lOutHdr.pixdim[4] := 2 * lInHdr.pixdim[4]; lImgSamples := lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3]; l4DVox := lImgSamples * lOutHdr.dim[4]; //l3DBytes := l3DVox*(lOutHdr.bitpix div 8); //l4DBytes := l3DBytes*lOutHdr.dim[4]; if lCustom then lResultStr := 'Custom subtraction' else if lSubtract then begin if lOddMinusEven then lResultStr := 'Subtract Odd-Even' else lResultStr := 'Subtract Even-Odd'; end else lResultStr := 'Add Odd+Even'; dcmMsg('Computing '+lResultStr+' '+lHdrName); lResultStr := ''; //assume error GetMem(lBuffUnaligned ,(sizeof(single)*l4DVox) + 16+kNIIImgOffset); {$IFDEF FPC} lBuffAligned := Align(lBuffUnaligned,16); // not commented - check this {$ELSE} lBuffAligned := ByteP($fffffff0 and (integer(lBuffUnaligned)+15)); {$ENDIF} lInc := 1; lImgBuffer := SingleP(@lBuffAligned^[kNIIImgOffset+lInc]); if lSplitOddEven then begin //compute odd for lVol := 1 to lOutHdr.dim[4] do begin lOutVolOffset := (lVol -1) * lImgSamples; //lInVolEvenOffset := ((lVol*2) -1) * lImgSamples; //second, fourth lInVolOddOffset := ((lVol*2) -2) * lImgSamples; //first, thired for lInc := 1 to lImgSamples do begin lOdd := l32Buf^[lInVolOddOffset+lInc]; //lEven := l16Buf^[lInVolEvenOffset+lInc]; lImgBuffer^[lOutVolOffset+lInc] := lOdd; end; //for lImgSamples end; //for lvol lresultStr := SaveNIfTICore (lOutImgName, lBuffAligned, kNIIImgOffset+1, lOutHdr, lPrefs); lresultStr := SaveMean32 (lOutImgName, lOutHdr, lBuffAligned,lImgBuffer,lPrefs); //compute even lOutImgName := ChangeFilePrefix (lHdrName,'even'); for lVol := 1 to lOutHdr.dim[4] do begin lOutVolOffset := (lVol -1) * lImgSamples; lInVolEvenOffset := ((lVol*2) -1) * lImgSamples; //second, fourth //lInVolOddOffset := ((lVol*2) -2) * lImgSamples; //first, thired for lInc := 1 to lImgSamples do begin //lOdd := l16Buf^[lInVolOddOffset+lInc]; lEven := l32Buf^[lInVolEvenOffset+lInc]; lImgBuffer^[lOutVolOffset+lInc] := lEven; end; //for lImgSamples end; //for lvol end else if lCustom then begin //not lSplitOddEven .. if Custom dcmMsg('Select a comma separated text file that describes how to subtract images.'); dcmMsg('For example, to subtract a six volume dataset your file could be:'); dcmMsg('1,6'); dcmMsg('2,5'); dcmMsg('3,4'); dcmMsg('The first output volume would be the first input volume minus the sixth'); dcmMsg('The second output volume would be the second input volume minus the fifth'); dcmMsg('The final output volume would be the third input volume minus the fourth'); dcmMsg('Your file should have '+inttostr(lOutHdr.dim[4])+' lines, one for each output volume'); if not MainForm.OpenDialogExecute('Select NIfTI images you wish to modify)',true,false,kTxtFilter) then goto 666; lCSVName := MainForm.OpenHdrDlg.Filename; //MainForm.BrowseDialog('Choose collapase file if not readCSV (lCSVname, lVol, lPosRA,lNegRA) then goto 666; if lVol < lOutHdr.dim[4] then begin dcmMsg ('Only found '+inttostr(lVol)+' contrasts in '+ lCSVName+' a total of '+inttostr(lOutHdr.dim[4])+' required'); freemem(lPosRA); freemem(lNegRA); goto 666; end; for lVol := 1 to lOutHdr.dim[4] do begin lOutVolOffset := (lVol -1) * lImgSamples; lEvenVol := lNegRA^[lVol]; lOddVol := lPosRA^[lVol]; if (lEvenVol > 0) and (lOddVol > 0) and (lEvenVol <= lInHdr.dim[4]) and (lOddVol <= lInHdr.dim[4]) then begin dcmMsg (inttostr(lVol) +' = '+inttostr(lOddVol)+' - '+inttostr(lEvenVol) ); lInVolEvenOffset := (lEvenVol -1) * lImgSamples; lInVolOddOffset := (lOddVol -1) * lImgSamples; for lInc := 1 to lImgSamples do begin lOdd := l32Buf^[lInVolOddOffset+lInc]; lEven := l32Buf^[lInVolEvenOffset+lInc]; lImgBuffer^[lOutVolOffset+lInc] := lOdd - lEven; end; //each voxel in volume end else begin dcmMsg('Error: volumes out of range '+inttostr(lVol) +' = '+inttostr(lOddVol)+' - '+inttostr(lEvenVol) ); end; end; //for lvol freemem(lPosRA); freemem(lNegRA); end else begin //not custom or lSplitOddEven for lVol := 1 to lOutHdr.dim[4] do begin lOutVolOffset := (lVol -1) * lImgSamples; lInVolEvenOffset := ((lVol*2) -1) * lImgSamples; //second, fourth lInVolOddOffset := ((lVol*2) -2) * lImgSamples; //first, thired if lSubtract then begin if lOddMinusEven then begin for lInc := 1 to lImgSamples do begin lOdd := l32Buf^[lInVolOddOffset+lInc]; lEven := l32Buf^[lInVolEvenOffset+lInc]; lImgBuffer^[lOutVolOffset+lInc] := lOdd - lEven; end; //for lImgSamples end else begin //not lOddMinusEven for lInc := 1 to lImgSamples do begin lOdd := l32Buf^[lInVolOddOffset+lInc]; lEven := l32Buf^[lInVolEvenOffset+lInc]; lImgBuffer^[lOutVolOffset+lInc] := lEven-lOdd; end; //for lImgSamples end; //if else lOddMinusEven end else begin //not subtract... add for lInc := 1 to lImgSamples do begin lOdd := l32Buf^[lInVolOddOffset+lInc]; lEven := l32Buf^[lInVolEvenOffset+lInc]; lImgBuffer^[lOutVolOffset+lInc] := lOdd + lEven; end; //for lImgSamples end; //add end; //for lvol end; lresultStr := SaveNIfTICore (lOutImgName, lBuffAligned, kNIIImgOffset+1, lOutHdr, lPrefs); //next make mean lresultStr := SaveMean32 (lOutImgName, lOutHdr, lBuffAligned,lImgBuffer,lPrefs); 666: Freemem(lSrcBuffer); Freemem(lBuffUnaligned); if lResultStr = '' then //error - do not report success exit; result := true; end; //ASL_subtract32 //end 32bit versions function SaveMean (var lHdrName: string;var lInHdr: TNIFTIhdr; lInBuffer : SmallIntP; lPrefs: TPrefs ): string; var lOutHdr : TNIFTIhdr; lOutImgName: string; lVol,lOutVolOffset,lInc,lImgSamples: integer; lSum: double; lBuffUnaligned,lBuffAligned: bytep; lImgBuffer: Singlep; begin result := ''; lOutHdr := lInHdr; lImgSamples := lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3]; if (lImgSamples < 1) or (lInHdr.dim[4] < 1) then exit; GetMem(lBuffUnaligned ,(sizeof(single)*lImgSamples) + 16+kNIIImgOffset); {$IFDEF FPC} lBuffAligned := Align(lBuffUnaligned,16); // not commented - check this {$ELSE} lBuffAligned := ByteP($fffffff0 and (integer(lBuffUnaligned)+15)); {$ENDIF} lInc := 1; lImgBuffer := SingleP(@lBuffAligned^[kNIIImgOffset+lInc]); //next make mean lOutImgName := ChangeFilePrefix (lHdrName,'mean'); for lInc := 1 to lImgSamples do begin lSum := 0; lOutVolOffset := 0; for lVol := 1 to lInHdr.dim[4] do begin lSum := lSum+lInBuffer^[lOutVolOffset+lInc]; lOutVolOffset := lOutVolOffset+lImgSamples; end; lImgBuffer^[lInc] := (lSum /lOutHdr.dim[4]); end; lOutHdr.dim[4] := 1; lOutHdr.datatype := kDT_FLOAT; lOutHdr.bitpix := 32; result := SaveNIfTICore (lOutImgName, lBuffAligned, kNIIImgOffset+1, lOutHdr, lPrefs); freemem( lBuffUnaligned); end; //SaveMean (*function SaveMean (var lHdrName: string;var lInHdr: TNIFTIhdr; lBuffAligned: bytep;lImgBuffer : SmallIntP;lPrefs: TPrefs; lByteSwap:boolean ): string; var lOutHdr : TNIFTIhdr; lOutImgName: string; lVol,lOutVolOffset,lInc,lImgSamples: integer; lSum: double; begin result := ''; lOutHdr := lInHdr; lImgSamples := lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3]; if (lImgSamples < 1) or (lInHdr.dim[4] < 1) then exit; //next make mean lOutImgName := ChangeFilePrefix (lHdrName,'mean'); for lInc := 1 to lImgSamples do begin lSum := 0; lOutVolOffset := 0; for lVol := 1 to lInHdr.dim[4] do begin lSum := lSum+lImgBuffer^[lOutVolOffset+lInc]; lOutVolOffset := lOutVolOffset+lImgSamples; end; lImgBuffer^[lInc] := round(lSum /lOutHdr.dim[4]); end; lOutHdr.dim[4] := 1; result := SaveNIfTICore (lOutImgName, lBuffAligned, kNIIImgOffset+1, lOutHdr, lPrefs,lByteSwap); end; //SaveMean*) function ASL_subtract(var lHdrName: string; lOverwrite: boolean; lFunction : integer; lPrefs: TPrefs): boolean; //lFunction : //0 = Subtract (even-odd) //1= Subtract (odd-even) //2= Subtract custom //3= Add (odd+even) BOLD //4= Parse OddEven aka SplitOddEven //for odd/even, first scan is odd (1), second scan is even (2) [indexed from 1] label 666; var lPosRA,lNegRA: LongIntp; lImgOffset,lVol,lInVolOddOffset,lInVolEvenOffset,lOutVolOffset, lOddVol,lEvenVol: integer; lImgSamples,l4DVox,lInc: integer; lCSVname,lResultStr,lOutImgName: string; lInHdr, lOutHdr : TNIFTIhdr; lO: TNIIOpts; lSplitOddEven,lCustom,lSubtract,lOddMinusEven: boolean; lBuffer,lSrcBuffer, lBuffUnaligned,lBuffAligned: bytep; lOdd,lEven: integer; lImgBuffer,l16Buf : SmallIntP; //lSum: double; begin lSplitOddEven := lFunction = 4; lCustom := lFunction = 2; lOddMinusEven := lFunction = 1; lSubtract := (lFunction <> 3); result := false; if not NIFTIhdr_LoadHdr (lHdrName, lInHdr, lO) then begin dcmMsg('Unable to read as NifTI/Analyze' + lHdrName); exit; end; case lInHdr.datatype of {kDT_UNSIGNED_CHAR,}kDT_SIGNED_SHORT{,kDT_UINT16, kDT_SIGNED_INT,kDT_FLOAT}:;//Supported kDT_FLOAT: begin result := ASL_subtract32(lHdrName,lOverwrite,lFunction,lPrefs); exit; end;//kDT_FLOAT else begin dcmMsg('Error with ASL_subtract: image format must be 16-bit signed integers.'); exit; end; end;//case headertype if (odd(lInHdr.dim[4])) or (lInHdr.dim[4] < 2) then begin dcmMsg('ASL routines require an even number of volumes'); exit; end; if not NIFTIhdr_LoadImg (lHdrName, lInHdr, lSrcBuffer, lImgOffset,lO) then exit; lBuffer := (@lSrcBuffer^[lImgOffset+1]); l16Buf := SmallIntP(lBuffer ); if lOverwrite then lOutImgName := lHdrName else begin if lSplitOddEven then lOutImgName := ChangeFilePrefix (lHdrName,'odd') else if lSubtract then begin if lCustom then lOutImgName := ChangeFilePrefix (lHdrName,'subc') else if lOddMinusEven then lOutImgName := ChangeFilePrefix (lHdrName,'subome') else lOutImgName := ChangeFilePrefix (lHdrName,'subemo') end else lOutImgName := ChangeFilePrefix (lHdrName,'add'); end; lOutHdr := lInHdr; lOutHdr.dim[4] := lInHdr.dim[4] div 2; lOutHdr.pixdim[4] := 2 * lInHdr.pixdim[4]; lImgSamples := lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3]; l4DVox := lImgSamples * lOutHdr.dim[4]; //l3DBytes := l3DVox*(lOutHdr.bitpix div 8); //l4DBytes := l3DBytes*lOutHdr.dim[4]; if lCustom then lResultStr := 'Custom subtraction' else if lSubtract then begin if lOddMinusEven then lResultStr := 'Subtract Odd-Even' else lResultStr := 'Subtract Even-Odd'; end else lResultStr := 'Add Odd+Even'; dcmMsg('Computing '+lResultStr+' '+lHdrName); lResultStr := ''; //assume error GetMem(lBuffUnaligned ,(sizeof(smallint)*l4DVox) + 16+kNIIImgOffset); {$IFDEF FPC} lBuffAligned := Align(lBuffUnaligned,16); // not commented - check this {$ELSE} lBuffAligned := ByteP($fffffff0 and (integer(lBuffUnaligned)+15)); {$ENDIF} lInc := 1; lImgBuffer := SmallIntP(@lBuffAligned^[kNIIImgOffset+lInc]); if lSplitOddEven then begin //compute odd for lVol := 1 to lOutHdr.dim[4] do begin lOutVolOffset := (lVol -1) * lImgSamples; //lInVolEvenOffset := ((lVol*2) -1) * lImgSamples; //second, fourth lInVolOddOffset := ((lVol*2) -2) * lImgSamples; //first, thired for lInc := 1 to lImgSamples do begin lOdd := l16Buf^[lInVolOddOffset+lInc]; //lEven := l16Buf^[lInVolEvenOffset+lInc]; lImgBuffer^[lOutVolOffset+lInc] := lOdd; end; //for lImgSamples end; //for lvol lresultStr := SaveNIfTICore (lOutImgName, lBuffAligned, kNIIImgOffset+1, lOutHdr, lPrefs); lresultStr := SaveMean (lOutImgName, lOutHdr, lImgBuffer,lPrefs); //compute even lOutImgName := ChangeFilePrefix (lHdrName,'even'); for lVol := 1 to lOutHdr.dim[4] do begin lOutVolOffset := (lVol -1) * lImgSamples; lInVolEvenOffset := ((lVol*2) -1) * lImgSamples; //second, fourth //lInVolOddOffset := ((lVol*2) -2) * lImgSamples; //first, thired for lInc := 1 to lImgSamples do begin //lOdd := l16Buf^[lInVolOddOffset+lInc]; lEven := l16Buf^[lInVolEvenOffset+lInc]; lImgBuffer^[lOutVolOffset+lInc] := lEven; end; //for lImgSamples end; //for lvol end else if lCustom then begin //not lSplitOddEven .. if Custom dcmMsg('Select a comma separated text file that describes how to subtract images.'); dcmMsg('For example, to subtract a six volume dataset your file could be:'); dcmMsg('1,6'); dcmMsg('2,5'); dcmMsg('3,4'); dcmMsg('The first output volume would be the first input volume minus the sixth'); dcmMsg('The second output volume would be the second input volume minus the fifth'); dcmMsg('The final output volume would be the third input volume minus the fourth'); dcmMsg('Your file should have '+inttostr(lOutHdr.dim[4])+' lines, one for each output volume'); if not MainForm.OpenDialogExecute('Select NIfTI images you wish to modify)',true,false,kTxtFilter) then goto 666; lCSVName := MainForm.OpenHdrDlg.Filename; //MainForm.BrowseDialog('Choose collapase file if not readCSV (lCSVname, lVol, lPosRA,lNegRA) then goto 666; if lVol < lOutHdr.dim[4] then begin dcmMsg('Only found '+inttostr(lVol)+' contrasts in '+ lCSVName+' a total of '+inttostr(lOutHdr.dim[4])+' required'); freemem(lPosRA); freemem(lNegRA); goto 666; end; for lVol := 1 to lOutHdr.dim[4] do begin lOutVolOffset := (lVol -1) * lImgSamples; lEvenVol := lNegRA^[lVol]; lOddVol := lPosRA^[lVol]; if (lEvenVol > 0) and (lOddVol > 0) and (lEvenVol <= lInHdr.dim[4]) and (lOddVol <= lInHdr.dim[4]) then begin dcmMsg(inttostr(lVol) +' = '+inttostr(lOddVol)+' - '+inttostr(lEvenVol) ); lInVolEvenOffset := (lEvenVol -1) * lImgSamples; //second, fourth lInVolOddOffset := (lOddVol -1) * lImgSamples; //first, thired for lInc := 1 to lImgSamples do begin lOdd := l16Buf^[lInVolOddOffset+lInc]; lEven := l16Buf^[lInVolEvenOffset+lInc]; lImgBuffer^[lOutVolOffset+lInc] := lOdd - lEven; end; //each voxel in volume end else begin dcmMsg('Error: volumes out of range '+inttostr(lVol) +' = '+inttostr(lOddVol)+' - '+inttostr(lEvenVol) ); end; end; //for lvol freemem(lPosRA); freemem(lNegRA); end else begin //not custom or lSplitOddEven for lVol := 1 to lOutHdr.dim[4] do begin lOutVolOffset := (lVol -1) * lImgSamples; lInVolEvenOffset := ((lVol*2) -1) * lImgSamples; //second, fourth lInVolOddOffset := ((lVol*2) -2) * lImgSamples; //first, thired if lSubtract then begin if lOddMinusEven then begin for lInc := 1 to lImgSamples do begin lOdd := l16Buf^[lInVolOddOffset+lInc]; lEven := l16Buf^[lInVolEvenOffset+lInc]; lImgBuffer^[lOutVolOffset+lInc] := lOdd - lEven; end; //for lImgSamples end else begin //not lOddMinusEven for lInc := 1 to lImgSamples do begin lOdd := l16Buf^[lInVolOddOffset+lInc]; lEven := l16Buf^[lInVolEvenOffset+lInc]; lImgBuffer^[lOutVolOffset+lInc] := lEven-lOdd; end; //for lImgSamples end; //if else lOddMinusEven end else begin //not subtract... add for lInc := 1 to lImgSamples do begin lOdd := l16Buf^[lInVolOddOffset+lInc]; lEven := l16Buf^[lInVolEvenOffset+lInc]; lImgBuffer^[lOutVolOffset+lInc] := lOdd + lEven; end; //for lImgSamples end; //add end; //for lvol end; lresultStr := SaveNIfTICore (lOutImgName, lBuffAligned, kNIIImgOffset+1, lOutHdr, lPrefs); //next make mean lresultStr := SaveMean (lOutImgName, lOutHdr, lImgBuffer,lPrefs); 666: Freemem(lSrcBuffer); Freemem(lBuffUnaligned); if lResultStr = '' then //error - do not report success exit; result := true; end; //ASL_subtract end. ��������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2nii.dof������������������������������������������������0000755�0001750�0001750�00000004463�12360762704�017565� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[FileVersion] Version=7.0 [Compiler] A=8 B=0 C=1 D=1 E=0 F=0 G=1 H=1 I=1 J=1 K=0 L=1 M=0 N=1 O=1 P=1 Q=0 R=0 S=0 T=0 U=0 V=1 W=0 X=1 Y=1 Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; NamespacePrefix= SymbolDeprecated=1 SymbolLibrary=1 SymbolPlatform=1 UnitLibrary=1 UnitPlatform=1 UnitDeprecated=1 HResultCompat=1 HidingMember=1 HiddenVirtual=1 Garbage=1 BoundsError=1 ZeroNilCompat=1 StringConstTruncated=1 ForLoopVarVarPar=1 TypedConstVarPar=1 AsgToTypedConst=1 CaseLabelRange=1 ForVariable=1 ConstructingAbstract=1 ComparisonFalse=1 ComparisonTrue=1 ComparingSignedUnsigned=1 CombiningSignedUnsigned=1 UnsupportedConstruct=1 FileOpen=1 FileOpenUnitSrc=1 BadGlobalSymbol=1 DuplicateConstructorDestructor=1 InvalidDirective=1 PackageNoLink=1 PackageThreadVar=1 ImplicitImport=1 HPPEMITIgnored=1 NoRetVal=1 UseBeforeDef=1 ForLoopVarUndef=1 UnitNameMismatch=1 NoCFGFileFound=1 MessageDirective=1 ImplicitVariants=1 UnicodeToLocale=1 LocaleToUnicode=1 ImagebaseMultiple=1 SuspiciousTypecast=1 PrivatePropAccessor=1 UnsafeType=1 UnsafeCode=1 UnsafeCast=1 [Linker] MapFile=0 OutputObjs=0 ConsoleApp=1 DebugInfo=0 RemoteSymbols=0 MinStackSize=16384 MaxStackSize=1048576 ImageBase=4194304 ExeDescription= [Directories] OutputDir= UnitOutputDir= PackageDLLOutputDir= PackageDCPOutputDir= SearchPath=..\common\;..\delphionly\ Packages=Vcl40;Vclx40;VclSmp40;Qrpt40;Vcldb40;RxCtl4 Conditionals= DebugSourceDirs= UsePackages=0 [Parameters] RunParams= HostApplication= Launcher= UseLauncher=0 DebugCWD= [Language] ActiveLang= ProjectLang= RootDir= [Version Info] IncludeVerInfo=1 AutoIncBuild=0 MajorVer=0 MinorVer=9 Release=0 Build=1 Debug=0 PreRelease=0 Special=0 Private=0 DLL=0 Locale=1033 CodePage=1252 [Version Info Keys] CompanyName=Chris Rorden FileDescription=DICOM and PAR/REC converter FileVersion=0.9.0.1 InternalName= LegalCopyright=Copyright LegalTrademarks= OriginalFilename=dcm2nii.exe ProductName=dcm2nii ProductVersion=0.0 Comments= [HistoryLists\hlUnitAliases] Count=1 Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; [HistoryLists\hlSearchPath] Count=2 Item0=..\common\;..\delphionly\ Item1=..\common\ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/readint.lrs������������������������������������������������0000755�0001750�0001750�00000001760�10577624742�017722� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������LazarusResources.Add('TReadIntForm','FORMDATA',[ 'TPF0'#12'TReadIntForm'#11'ReadIntForm'#4'Left'#3'2'#1#6'Height'#2'P'#3'Top'#3 +'*'#2#5'Width'#3#213#1#18'HorzScrollBar.Page'#3#212#1#18'VertScrollBar.Page' +#2'O'#13'ActiveControl'#7#11'ReadIntEdit'#11'BorderStyle'#7#8'bsDialog'#7'Ca' +'ption'#6#16'Integer required'#11'Font.Height'#2#245#9'Font.Name'#6#13'MS Sa' +'ns Serif'#8'OnCreate'#7#10'FormCreate'#8'Position'#7#14'poScreenCenter'#0#6 +'TLabel'#12'ReadIntLabel'#4'Left'#2#16#6'Height'#2#14#3'Top'#2#12#5'Width'#3 +'P'#1#9'Alignment'#7#14'taRightJustify'#8'AutoSize'#8#7'Caption'#6#14'Enter ' +'a number'#5'Color'#7#6'clNone'#11'ParentColor'#8#0#0#9'TSpinEdit'#11'ReadIn' +'tEdit'#4'Left'#3'h'#1#6'Height'#2#22#3'Top'#2#12#5'Width'#2']'#8'MaxValue'#2 +#0#8'TabOrder'#2#0#0#0#7'TButton'#5'OKBtn'#4'Left'#3'p'#1#6'Height'#2#25#3'T' +'op'#2','#5'Width'#2'K'#25'BorderSpacing.InnerBorder'#2#4#7'Caption'#6#2'OK' +#7'OnClick'#7#10'OKBtnClick'#8'TabOrder'#2#1#0#0#0 ]); ����������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/nifti_form.lrs���������������������������������������������0000755�0001750�0001750�00000011445�12307634454�020423� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TNIfTIForm','FORMDATA',[ 'TPF0'#10'TNIfTIForm'#9'NIfTIForm'#4'Left'#3#29#3#6'Height'#3#10#1#3'Top'#2' ' +#5'Width'#3#144#1#13'ActiveControl'#7#5'OKBtn'#8'BiDiMode'#7#13'bdRightToLef' +'t'#11'BorderIcons'#11#12'biSystemMenu'#0#11'BorderStyle'#7#8'bsDialog'#7'Ca' +'ption'#6#18'Convert NIfTI File'#12'ClientHeight'#3#10#1#11'ClientWidth'#3 +#144#1#21'Constraints.MaxHeight'#3#10#1#20'Constraints.MaxWidth'#3#144#1#21 +'Constraints.MinHeight'#3#10#1#20'Constraints.MinWidth'#3#144#1#8'OnCreate'#7 +#10'FormCreate'#14'ParentBiDiMode'#8#10'LCLVersion'#6#8'1.0.12.0'#0#6'TLabel' +#6'Label1'#4'Left'#2#8#6'Height'#2#17#3'Top'#3#168#0#5'Width'#2'f'#9'Alignme' +'nt'#7#8'taCenter'#7'Caption'#6#15'Output Format: '#11'ParentColor'#8#0#0#6 +'TLabel'#6'Label4'#4'Left'#2#8#6'Height'#2#17#3'Top'#2#16#5'Width'#2'#'#9'Al' +'ignment'#7#8'taCenter'#7'Caption'#6#5'Task:'#11'ParentColor'#8#0#0#7'TButto' +'n'#5'OKBtn'#4'Left'#3#200#0#6'Height'#2#25#3'Top'#3#208#0#5'Width'#2'K'#25 +'BorderSpacing.InnerBorder'#2#4#7'Caption'#6#2'OK'#11'ModalResult'#2#1#7'OnC' +'lick'#7#10'OKBtnClick'#8'TabOrder'#2#0#0#0#7'TButton'#9'CancelBtn'#4'Left'#2 +'h'#6'Height'#2#25#3'Top'#3#208#0#5'Width'#2'K'#25'BorderSpacing.InnerBorder' +#2#4#7'Caption'#6#6'Cancel'#11'ModalResult'#2#2#8'TabOrder'#2#1#0#0#9'TCombo' +'Box'#9'TypeCombo'#4'Left'#2'v'#6'Height'#2#20#3'Top'#3#163#0#5'Width'#3#209 +#0#10'ItemHeight'#2#0#13'Items.Strings'#1#6#24'SPM2 (3D Anlyze hdr/img)'#6#23 +'SPM5 (3D NIfTI hdr/img)'#6#19'SPM8 (3D NIfTI nii)'#6#16'4D NIfTI hdr/img'#6 +#18'FSL (4D NIfTI nii)'#6#29'Compressed FSL (4D NIfTI nii)'#6#21'MRIcron dra' +'wing (voi)'#0#5'Style'#7#14'csDropDownList'#8'TabOrder'#2#2#0#0#6'TPanel'#6 +'Panel1'#4'Left'#2#8#6'Height'#2'g'#3'Top'#2';'#5'Width'#3'8'#1#10'BevelOute' +'r'#7#6'bvNone'#12'ClientHeight'#2'g'#11'ClientWidth'#3'8'#1#8'TabOrder'#2#3 +#0#6'TLabel'#6'Label2'#4'Left'#2#8#6'Height'#2#17#3'Top'#2#15#5'Width'#3#190 +#0#7'Caption'#6#28'Volumes to remove from start'#11'ParentColor'#8#0#0#6'TLa' +'bel'#6'Label3'#4'Left'#2#7#6'Height'#2#17#3'Top'#2'7'#5'Width'#3#185#0#7'Ca' +'ption'#6#26'Volumes to remove from end'#11'ParentColor'#8#0#0#9'TSpinEdit'#9 +'StartEdit'#4'Left'#3#224#0#6'Height'#2#15#3'Top'#2#13#5'Width'#2'J'#8'MaxVa' +'lue'#4#127#150#152#0#8'TabOrder'#2#0#0#0#9'TSpinEdit'#7'EndEdit'#4'Left'#3 +#224#0#6'Height'#2#15#3'Top'#2'5'#5'Width'#2'J'#8'MaxValue'#4#127#150#152#0#8 +'TabOrder'#2#1#0#0#0#9'TComboBox'#7'Combo4D'#4'Left'#2'/'#6'Height'#2#20#3'T' +'op'#2#11#5'Width'#3'Q'#1#10'ItemHeight'#2#0#13'Items.Strings'#1#6#13'Change' +' format'#6#23'Flip dimensions 3 and 4'#6#21'Clip 1st/Last Volumes'#6#21'Exp' +'ort as 32-bit real'#6#13'Apply formula'#6#14'ASL conversion'#0#8'OnChange'#7 +#13'Combo4DChange'#5'Style'#7#14'csDropDownList'#8'TabOrder'#2#4#0#0#9'TComb' +'oBox'#7'Combo3D'#4'Left'#2'0'#6'Height'#2#20#3'Top'#2#11#5'Width'#3'P'#1#10 +'ItemHeight'#2#0#13'Items.Strings'#1#6#13'Change format'#6#22'Reorient to or' +'thogonal'#6#17'Reorient and crop'#0#5'Style'#7#14'csDropDownList'#8'TabOrde' +'r'#2#5#0#0#6'TPanel'#8'ASLPanel'#4'Left'#2'('#6'Height'#2'2'#3'Top'#2#24#5 +'Width'#3#19#1#10'BevelOuter'#7#6'bvNone'#12'ClientHeight'#2'2'#11'ClientWid' +'th'#3#19#1#8'TabOrder'#2#6#0#9'TComboBox'#8'ASLCombo'#4'Left'#2#16#6'Height' +#2#20#3'Top'#2#11#5'Width'#3#250#0#10'ItemHeight'#2#0#13'Items.Strings'#1#6 +'#Subtract pairs - first image tagged'#6'$Subtract pairs - first image contr' +'ol'#6#15'Subtract Custom'#6#19'Add (odd+even) BOLD'#0#5'Style'#7#14'csDropD' +'ownList'#8'TabOrder'#2#0#0#0#0#6'TPanel'#12'FormulaPanel'#4'Left'#2'/'#6'He' +'ight'#2'r'#3'Top'#2'8'#5'Width'#3#17#1#10'BevelOuter'#7#6'bvNone'#11'Border' +'Style'#7#8'bsSingle'#12'ClientHeight'#2'r'#11'ClientWidth'#3#17#1#8'TabOrde' +'r'#2#7#0#6'TLabel'#6'Label5'#4'Left'#2#31#6'Height'#2#17#3'Top'#2#17#5'Widt' +'h'#2'!'#9'Alignment'#7#8'taCenter'#7'Caption'#6#5'Scale'#11'ParentColor'#8#0 +#0#6'TLabel'#6'Label6'#4'Left'#2#31#6'Height'#2#17#3'Top'#2';'#5'Width'#2'''' +#9'Alignment'#7#8'taCenter'#7'Caption'#6#5'Power'#11'ParentColor'#8#0#0#14'T' +'FloatSpinEdit'#9'ScaleEdit'#4'Left'#2#127#6'Height'#2#15#3'Top'#2#11#5'Widt' +'h'#3#130#0#13'DecimalPlaces'#2#8#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8 +'MaxValue'#5#0#0#0#0#0#0#0#200#5'@'#8'MinValue'#5#0#0#0#0#0#0#0#0#0#0#8'TabO' +'rder'#2#0#5'Value'#5#0#176#27'l'#160#175#15#161#235'?'#0#0#14'TFloatSpinEdi' +'t'#9'PowerEdit'#4'Left'#2#127#6'Height'#2#15#3'Top'#2'8'#5'Width'#3#130#0#13 +'DecimalPlaces'#2#8#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0 +#0#0#0#0#0#200#5'@'#8'MinValue'#5#0#0#0#0#0#0#0#0#0#0#8'TabOrder'#2#1#5'Valu' +'e'#5#0#176#27'l'#160#175#15#161#235'?'#0#0#0#0 ]); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dicomtypes.pas���������������������������������������������0000755�0001750�0001750�00000063750�12310411634�020423� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit dicomtypes; {$IFDEF FPC} {$mode objfpc} {$ENDIF} {$H+} {$Include ..\common\isgui.inc} interface var kUseDateTimeForID: boolean = false; const kGEID = 1; kPhilipsID = 2; kSiemensID = 3; kMaxDTIDir = 4095;//Maximum DTI directions kMaxOrderVal = 4095; type TDTI = record v1,v2,v3: double; //4=volume, eg time: some EC*T7 images bval: integer end; TDTIRA = array [1..kMaxDTIDir] of TDTI;//TDICOM;//unsigned 8-bit int TOrder= array [1..kMaxOrderVal] of byte; kDICOMStr = String[128]; DICOMdata = record XYZdim: array [1..4] of integer; XYZori: array [1..3] of integer; XYZmm: array [1..3] of double; Orient: array [1..6] of double; SignedData,SiemensDICOMDTICSA,SiemensDICOMDTI,FloatData,file4D,JPEGLossyCpt,JPEGLosslessCpt: boolean; SecSinceMidnight,PatientPosX,PatientPosY,PatientPosZ,AngulationAP,AngulationFH,AngulationRL: double; FieldStrength, BandwidthPerPixelPhaseEncode, kV,TE, TR,IntenScale,IntenIntercept,location{,DTIv1,DTIv2,DTIv3}: single; {Bval,}SlicesPer3DVol,SiemensInterleaved {0=no,1=yes,2=not defined},SiemensSlices,SiemensMosaicX,SiemensMosaicY, nOrder,nDTIdir,AcquNum,ImageNum,SeriesNum,ImageStart,little_endian,Allocbits_per_pixel,SamplesPerPixel, CSAImageHeaderInfoPos,CSAImageHeaderInfoSz, CSASeriesHeaderInfoPos,CSASeriesHeaderInfoSz,ManufacturerID,PlanarConfig, //ImplementationVersion, Vers0018_1020, CompressOffset,CompresssZ: integer; DateTime: TDateTime; PatientHx, ImageComments,PatientGender,PatientDoB,PatientPos,PatientName,ProtocolName,StudyDate,StudyTime,PhilipsSliceOrient,ScanningSequence0018_0020 ,PhaseEncoding: kDICOMStr; Filename: string[255]; DTI: TDTIRA; Order: TOrder; //4D datasets //OrderSlope,OrderIntercept: TOrderScaling; //4D datasets end;//DICOMdata record TDICOMRA = array [1..1] of DicomData;//TDICOM;//unsigned 8-bit int TDICOMRAp = ^TDICOMRA; (* TNIFTIhdr = packed record //Next: analyze Format Header structure HdrSz : longint; //MUST BE 348 Data_Type: array [1..10] of char; //unused db_name: array [1..18] of char; //unused extents: longint; //unused session_error: smallint; //unused regular: char; ////unused: in Analyze 7.5 this must be 114 dim_info: byte; //MRI slice order dim: array[0..7] of smallint; //Data array dimensions intent_p1, intent_p2, intent_p3: single; intent_code: smallint; datatype: smallint; bitpix: smallint; slice_start: smallint; pixdim: array[0..7]of single; vox_offset: single; scl_slope: single;//scaling slope scl_inter: single;//scaling intercept slice_end: smallint; slice_code: byte; //e.g. ascending xyzt_units: byte; //e.g. mm and sec cal_max,cal_min: single; //unused slice_duration: single; //time for one slice toffset: single; //time axis to shift glmax, glmin: longint; //UNUSED descrip: array[1..80] of char; aux_file: array[1..24] of char; qform_code, sform_code: smallint; quatern_b,quatern_c,quatern_d, qoffset_x,qoffset_y,qoffset_z: single; srow_x: array[0..3]of single; srow_y: array[0..3]of single; srow_z: array[0..3]of single; intent_name: array[1..16] of char; magic: longint; end; //TNIFTIhdr Header Structure const //nifti kDT_BINARY =1; // binary (1 bit/voxel) kDT_UNSIGNED_CHAR =2; // unsigned char (8 bits/voxel) kDT_SIGNED_SHORT =4; // signed short (16 bits/voxel) kDT_SIGNED_INT =8; // signed int (32 bits/voxel) kDT_FLOAT =16; // float (32 bits/voxel) kDT_COMPLEX =32; // complex (64 bits/voxel) kDT_DOUBLE =64; // double (64 bits/voxel) kDT_RGB =128; // RGB triple (24 bits/voxel) kDT_INT8 =256; // signed char (8 bits) kDT_UINT16 =512; // unsigned short (16 bits) kDT_UINT32 =768; // unsigned int (32 bits) kDT_INT64 =1024; // long long (64 bits) kDT_UINT64 =1280; // unsigned long long (64 bits) kDT_FLOAT128 =1536; // long double (128 bits) kDT_COMPLEX128 =1792; // double pair (128 bits) kDT_COMPLEX256 =2048; // long double pair (256 bits) // slice_code values kNIFTI_SLICE_SEQ_UNKNOWN = 0; kNIFTI_SLICE_SEQ_INC = 1; kNIFTI_SLICE_SEQ_DEC = 2; kNIFTI_SLICE_ALT_INC = 3; kNIFTI_SLICE_ALT_DEC = 4; //xyzt_units values: note 3bit space and 3bit time packed into single byte kNIFTI_UNITS_UNKNOWN = 0; kNIFTI_UNITS_METER = 1; kNIFTI_UNITS_MM = 2; kNIFTI_UNITS_MICRON = 3; kNIFTI_UNITS_SEC = 8; kNIFTI_UNITS_MSEC = 16; kNIFTI_UNITS_USEC = 24; kNIFTI_UNITS_HZ = 32; kNIFTI_UNITS_PPM = 40; //qform_code, sform_code values kNIFTI_XFORM_UNKNOWN = 0; kNIFTI_XFORM_SCANNER_ANAT = 1;//Scanner-based anatomical coordinates kNIFTI_XFORM_ALIGNED_ANAT = 2; //Coordinates aligned to another file e.g. EPI coregistered to T1 kNIFTI_XFORM_TALAIRACH = 3; //Talairach-Tournoux Atlas; (0,0,0)=AC, etc. kNIFTI_XFORM_MNI_152 = 4; //MNI 152 normalized coordinates //Magic values kNIFTI_MAGIC_SEPARATE_HDR = $0031696E;//$6E693100; kNIFTI_MAGIC_EMBEDDED_HDR = $00312B6E;//$6E2B3100; //byte-swapped magic values kswapNIFTI_MAGIC_SEPARATE_HDR = $6E693100; kswapNIFTI_MAGIC_EMBEDDED_HDR = $6E2B3100; //Statistics Intention kNIFTI_INTENT_NONE =0; kNIFTI_INTENT_CORREL =2; kNIFTI_INTENT_TTEST =3; kNIFTI_INTENT_FTEST =4; kNIFTI_INTENT_ZSCORE =5; kNIFTI_INTENT_CHISQ =6; kNIFTI_INTENT_BETA =7; kNIFTI_INTENT_BINOM =8; kNIFTI_INTENT_GAMMA =9; kNIFTI_INTENT_POISSON =10; kNIFTI_INTENT_NORMAL =11; kNIFTI_INTENT_FTEST_NONC =12; kNIFTI_INTENT_CHISQ_NONC =13; kNIFTI_INTENT_LOGISTIC =14; kNIFTI_INTENT_LAPLACE =15; kNIFTI_INTENT_UNIFORM =16; kNIFTI_INTENT_TTEST_NONC =17; kNIFTI_INTENT_WEIBULL =18; kNIFTI_INTENT_CHI =19; kNIFTI_INTENT_INVGAUSS =20; kNIFTI_INTENT_EXTVAL =21; kNIFTI_INTENT_PVAL =22; NIFTI_INTENT_LOGPVAL =23; NIFTI_INTENT_LOG10PVAL =24; kNIFTI_LAST_STATCODE = 24;//kNIFTI_INTENT_PVAL; kNIFTI_INTENT_ESTIMATE =1001; kNIFTI_FIRST_NONSTATCODE = kNIFTI_INTENT_ESTIMATE; kNIFTI_INTENT_LABEL =1002; kNIFTI_INTENT_NEURONAME =1003; kNIFTI_INTENT_GENMATRIX =1004; kNIFTI_INTENT_SYMMATRIX =1005; kNIFTI_INTENT_DISPVECT =1006; kNIFTI_INTENT_VECTOR =1007; kNIFTI_INTENT_POINTSET =1008; kNIFTI_INTENT_TRIANGLE =1009; kNIFTI_INTENT_QUATERNION =1010; *) const //dicom kCR = chr (13);//PC EOLN kA = ord('A'); kB = ord('B'); kC = ord('C'); kD = ord('D'); kE = ord('E'); kF = ord('F'); kH = ord('H'); kI = ord('I'); kL = ord('L'); kM = ord('M'); kN = ord('N'); kO = ord('O'); kP = ord('P'); kQ = ord('Q'); kS = ord('S'); kT = ord('T'); kU = ord('U'); kW = ord('W'); procedure PhilipsPrecise (lRS, lRI,lSS: single; var lSlope,lIntercept: single; Precise: boolean); procedure clear_dicom_data (var lDicomdata:Dicomdata); function DICOMinterslicedistance(var lDicomdata1,lDicomdata2:Dicomdata): single;//1392 function StudyDateTime (lInStudyDate, lInStudyTime: kDICOMStr): TDateTime; function StudyDateTime2Str (lDateTime: TDateTime):string; //function GetCSAImageHeaderInfoDTI (lFilename: string; lStart,lLength: integer; var lBval: integer; var ldti1,ldti2,ldti3: double): boolean; //function GetCSAImageHeaderInfo (lFilename: string; lStart,lLength: integer; var lMosaicSlices,lMosaicX,lMosaicY: integer; var lv1,lv2,lv3: double): boolean; procedure AplhaNumericStrDICOM (var lStr: kDICOMStr); procedure PartialAcquisitionError; function DICOMstr (i: integer; var lDICOMra: TDICOMrap;lOutname:string): string; overload; function DICOMstr (i: integer; var lDICOMra: TDICOMrap): string; overload; function DICOMstr (var lDICOM: DICOMdata): string; overload; implementation uses dicom,sysutils,define_types,dialogsx,dialogs_msg; function YearsOld (lDICOM: DICOMdata): single; var dob: TDateTime; lnoon:string; begin result := 0; if length (lDICOM.PatientDoB) < 8 then exit; //YYYYMMDD try lnoon := '120000'; dob := StudyDateTime (lDICOM.PatientDoB, lnoon); result := (lDICOM.DateTime-dob)/365.2425; except result := 0; end; end; function DICOMstr (var lDICOM: DICOMdata): string; overload; begin result := lDICOM.Filename //ProtocolName,StudyDate,StudyTime,PhilipsSliceOrient,PhaseEncoding: kDICOMStr; +kTab+'Field Strength:'+kTab+floattostr(lDICOM.fieldStrength) +kTab+'ProtocolName:'+kTab+ lDICOM.ProtocolName +kTab+'ScanningSequence00180020:'+kTab+ lDICOM.ScanningSequence0018_0020 +kTab+'TE:'+kTab+floattostr(lDICOM.TE) +kTab+'TR:'+kTab+floattostr(lDICOM.TR) +kTab+'SeriesNum:'+kTab+inttostr(lDICOM.SeriesNum) +kTab+'AcquNum:'+kTab+inttostr(lDICOM.AcquNum) +kTab+'ImageNum:'+kTab+inttostr(lDICOM.ImageNum) +kTab+'ImageComments:'+kTab+lDICOM.ImageComments +kTab+'DateTime:'+kTab+DateTimeToStr(lDICOM.DateTime) +kTab+'Name:'+kTab+lDICOM.PatientName +kTab+'PatientHistory:'+kTab+lDICOM.PatientHx +kTab+'DoB:'+kTab+lDICOM.PatientDoB +kTab+'Gender:'+kTab+lDICOM.PatientGender +kTab+'Age(Years):'+kTab+floattostr(YearsOld(lDICOM)) ; end; function DICOMstr (i: integer; var lDICOMra: TDICOMrap;lOutname: string): string; overload; var lS: string; begin result := DICOMstr (lDICOMra^[i]); if lOutname <> '' then result := kTab+'SuggestedOutput:'+lOutname; end; (*function DICOMstr (i: integer; var lDICOMra: TDICOMrap;lOutname: string): string; overload; var lS: string; begin if lOutname <> '' then lS := kTab+'SuggestedOutput:'+lOutname else lS := ''; result := lDICOMra^[i].Filename +kTab+'ImageComments:'+lDICOMra^[i].ImageComments +kTab+'PatientHistory:'+lDICOMra^[i].PatientHx +kTab+'SeriesNum:'+kTab+inttostr(lDICOMra^[i].SeriesNum) +kTab+'AcquNum:'+inttostr(lDICOMra^[i].AcquNum) +kTab+'ImageNum:'+inttostr(lDICOMra^[i].ImageNum) +kTab+'Name:'+lDICOMra^[i].PatientName +kTab+'DoB:'+lDICOMra^[i].PatientDoB +kTab+'Gender:'+lDICOMra^[i].PatientGender +kTab+'DateTime:'+DateTimeToStr(lDICOMra^[i].DateTime) +kTab+'Age(Years):'+floattostr(YearsOld(lDICOMra^[i])) +lS ; end; *) function DICOMstr (i: integer; var lDICOMra: TDICOMrap): string; overload; begin result := DICOMstr (i, lDICOMra,'') end; procedure PartialAcquisitionError; begin dcmMsg('* Potential partial acquisition or improper segmentation of files'); {$IFDEF GUI} dcmMsg('* Possible solution: check ''Collapse folders'' in Help/Preferences and select directory that contains all images in subfolders'); {$ELSE} dcmMsg('* Possible solution: use -c Y and use folder containing subdirectories as input'); dcmMsg('* or change .ini file to read: CollapseFolders=1'); {$ENDIF} end; function PhilipsPreciseVal (lPV, lRS, lRI,lSS: single): single; begin if (lRS*lSS) = 0 then //avoid divide by zero result := 0 else result := (lPV * lRS + lRI) / (lRS * lSS); end; procedure PhilipsPrecise (lRS, lRI,lSS: single; var lSlope,lIntercept: single; Precise: boolean); var l0,l1: single; begin //# === PIXEL VALUES ============================================================= //# PV = pixel value in REC file, FP = floating point value, DV = displayed value on console //# RS = rescale slope, RI = rescale intercept, SS = scale slope //# DV = PV * RS + RI FP = DV / (RS * SS) if not Precise then begin //return DV not FP lSlope := lRS; if lSlope = 0 then lSlope := 1; lIntercept := lRI; exit; end; //if return DV l0 := PhilipsPreciseVal (0, lRS, lRI,lSS); l1 := PhilipsPreciseVal (1, lRS, lRI,lSS); if l0 = l1 then begin lSlope := 1; lIntercept := 0; exit; end; lIntercept := l0; lSlope := l1-l0; end; function SecSinceMidnight(H,Min,S: integer): integer; //86,400 sec per day begin // result := 3600*(H) + 60* Min + S;//H not H-1 as our clock runs from 0..23 not 1..24 end; function BogusDateTime: TDateTime; begin result := EncodeDate(1989,3,23) + (SecSinceMidnight(12,0,0) / 86400); end; function EncodeDateTime (Y,M,D,H,Min,S: integer): TDateTime; begin try result := EncodeDate(Y,M,D) + (SecSinceMidnight(H,Min,S) / 86400); except //impossible date - set to cold fusion date result := BogusDateTime; end; end; procedure DecodeDateTime (lDateTime: TDateTime; var Y,M,D,H,Min,S: word); var secs: integer; begin try DecodeDate(lDateTime, Y, M, D); except //unable to decode date - use cold fusion values Y := 1989; M := 3; D := 23; end; Secs := round(Frac(lDateTime)*86400); S := secs mod 60; Min := (secs div 60) mod 60; H := (secs div 3600); end; function StudyDateTime2Str (lDateTime: TDateTime):string; var Y,M,D,H,Min,S: word; begin DecodeDateTime (lDateTime,Y,M,D,H,Min,S); result := PadStr (Y, 4)+ PadStr (M, 2)+PadStr (D, 2)+'_'+PadStr (H, 2)+ PadStr (Min, 2)+PadStr (S, 2); end; function StudyDateTime (lInStudyDate, lInStudyTime: kDICOMStr): TDateTime; var lStr,lStudyDate, lStudyTime: string; Y,M,D,H,Min,S: integer; begin result := 0; if (length(lInStudyDate) < 8){YYYYMMDD} or (length(lInStudyTime) < 6) {hhmmss} then exit; //next compress string, e.g. Elscint saves time as 16:54:21 lStudyDate :=''; for S := 1 to length (lInStudyDate) do if lInStudyDate[S] in ['0'..'9'] then lStudyDate := lStudyDate + lInStudyDate[S]; lStudyTime :=''; for S := 1 to length (lInStudyTime) do if lInStudyTime[S] in ['0'..'9'] then lStudyTime := lStudyTime + lInStudyTime[S]; if (length(lStudyDate) < 8){YYYYMMDD} or (length(lStudyTime) < 6) {hhmmss} then exit; lStr := lStudyDate[1]+lStudyDate[2]+lStudyDate[3]+lStudyDate[4]; Y := strtoint(lStr); lStr := lStudyDate[5]+lStudyDate[6]; M := strtoint(lStr); lStr := lStudyDate[7]+lStudyDate[8]; D := strtoint(lStr); lStr := lStudyTime[1]+lStudyTime[2]; H := strtoint(lStr); lStr := lStudyTime[3]+lStudyTime[4]; Min := strtoint(lStr); lStr := lStudyTime[5]+lStudyTime[6]; S := strtoint(lStr); result := EncodeDateTime (Y,M,D,H,Min,S); end; procedure AplhaNumericStrDICOM (var lStr: kDICOMStr); var S: integer; lOutStr: string; begin if length(lStr) < 1 then exit; lOutStr := ''; for S := 1 to length (lStr) do if lStr[S] in ['0'..'9','A'..'Z','a'..'z'] then lOutStr := lOutStr+ lStr[S]; lStr := lOutStr; end; (* function GetCSAImageHeaderInfoRaw (lIsDTI: boolean; lFilename: string; lStart,lLength: integer; var li1,li2,li3: integer; var lf1,lf2,lf3: double): boolean; //returns true if mosaic //will return false for non-mosaics - even if the have DTI information! //valid DTI signified by bval >= 0 const kMaxFloats = 6; var //lZ: integer; lByteRA: Bytep; lNumarisTag: string; lInFile: file; lFloatRA: array [1..kMaxFloats] of double; function Str2FloatLastNum ( lStr: string): boolean; var lFStr: string; lP: integer; begin lFloatRA[1] := 1; result := false; if (length(lStr) < 1) then exit; lFStr := ''; lP := length(lStr); while (lP > 0) and ((lFStr = '') or (lStr[lP] in ['+','-','0'..'9','.','e','E'])) do begin if lStr[lP] in ['+','-','0'..'9','.','e','E'] then lFStr := lStr[lP]+lFStr; dec(lP); end; if (lFStr = '') then exit; try lFloatRA[1] := strtofloat(lFStr); except on EConvertError do lFloatRA[1] := 1; end;//except result := true; end; //function Str2Float function NumarisPos (lStr: string; lStart: integer): integer; //read 16 bit short integer var lP,lLen,lMax,lMatch: integer; begin result := 0; lLen := length(lStr); lMax := lLength-lLen; if (lStart < 1) or (lMax < 1) or (lLen < 1) then exit; for lP := lStart to lMax do begin lMatch := 0; while (lMatch < lLen) and (lStr[lMatch+1] = char( lByteRA[lP+lMatch]) ) do inc(lMatch); if lMatch = lLen then begin if (lP < lMax) and (char( lByteRA[lP+lMatch]) = '"') then begin lMatch := 0;//We want DiffusionGradientDirection, but not "DiffusionGradientDirection" end else begin result := lP; exit; end; end; end; end; //function NumarisPos function Str2FloatNum ( lStr: string; lnFloats: integer): boolean; var lFStr: string; lP,lnF: integer; begin result := false; if (length(lStr) < 1) or (lnFloats < 1) or (lnFloats > kMaxFloats) then exit; for lnF := 1 to lnFloats do lFloatRA[lnF] := 1; lStr := lStr + ' '; //terminator lFStr := ''; lP := 1; lnF:= 0; while lP <= length(lStr) do begin if lStr[lP] in ['+','-','0'..'9','.','e','E'] then lFStr := lFStr + lStr[lP] else if (lFStr <> '') then begin inc(lnF); try lFloatRA[lnF] := strtofloat(lFStr); except on EConvertError do dcmMsg('Unable to interpret '+lNumarisTag+ ' in '+extractfilename(lFilename)); end;//except if lnF = lnFloats then begin result := true; exit; end; lFStr := ''; end; inc(lP); end; end; //function Str2Float function NumarisStr (lStr,lIDStr: string): string; var lP,lI: integer; lPrevNum : boolean; begin result := ''; lP := NumarisPos(lStr,1); if lP <1 then exit; if length(lIDstr) > 0 then begin lP := NumarisPos(lIDstr,lP); if lP <1 then exit; end; result := ''; lI := lP + length(lStr); lPrevNum := false; While (lI < (lLength)) and (lByteRA^[lI] <> $CD) do begin if char(lByteRA[lI]) in ['-','0'..'9','.','p','*'] then begin result := result + char(lByteRA[lI]); lPrevNum := true; end else begin if lPrevNum then result := result + ' '; lPrevNum := false; end; inc(lI); end; end; function NumarisInt1 (lStr,lIDStr: string; var lI1: integer): boolean; begin result := Str2FloatLastNum (NumarisStr(lStr,lIDStr)); if not result then exit; lI1 := round(lFloatRA[1] ); end; function NumarisFloat3 (lStr,lIDStr: string; var lF1,lF2,lF3: double): boolean; begin //showmessage(lStr+' '+NumarisStr(lStr,lIDStr)); result := Str2FloatNum (NumarisStr(lStr,lIDStr),3); if not result then exit; lF1 := (lFloatRA[1]); lF2 := (lFloatRA[2]); lF3 := (lFloatRA[3]); end; //function NumarisFloat3 function NumarisInt2PStar (lStr,lIDStr: string; var lI1,lI2: integer): boolean; var lLen,lPos,lStarPos: integer; lvStr,lpStarStr: string; begin //a 96x96 mosaic is usually saved as '64*64', but in B13 you can see '96p*96' or '.95 96p*96' result := false; lvStr := NumarisStr(lStr,lIDStr); lLen := length(lvStr); if lLen < 4 then exit;//not found lStarPos := 0; for lPos := 1 to (lLen-1) do if (lvStr[lPos] = '*') then lStarPos := lPos; if lStarPos = 0 then exit; lpStarStr := ''; lPos := lStarPos -1; while (lPos >= 1) and ((lpStarStr = '') or (lvStr[lPos] in ['0'..'9'])) do begin lpStarStr := lvStr[lPos] + lpStarStr; dec(lPos); end; lpStarStr := lpStarStr + ' '; lPos := lStarPos+1; while (lPos < lLen) and ((lpStarStr = '') or (lvStr[lPos] in ['0'..'9'])) do begin lpStarStr := lpStarStr+lvStr[lPos]; inc(lPos); end; result := Str2FloatNum (lpStarStr,2); if not result then exit; lI1 := round(lFloatRA[1]); lI2 := round(lFloatRA[2]); //dcmMsg(lvStr+' '+floattostr( lI1)+'x'+inttostr(lI2)); end; begin // GetCSAImageHeaderInfoRaw result := false; if (lLength < 1) then exit; if FSize(lFilename) <= (lStart+lLength) then exit; li1 := -1; //impossible - should be >=0 li2 := 0; li3 := 0; lf1 := 0;//impossible, therefore not DTI - should be -1..1 lf2 := 0;//impossible, therefore not DTI lf3 := 0;//impossible, therefore not DTI GetMem(lByteRA,lLength); AssignFile(lInFile, lFileName); //dcmMsg('fz '+lFilename); FileMode := 0; //Set file access to read only Reset(lInFile, 1); seek(lInFile,lStart); BlockRead(lInFile, lByteRA^[1], lLength); CloseFile(lInFile); FileMode := 2; if lIsDTI then begin result := NumarisInt1 ('B_value','IS',li1); //result := NumarisInt1 ('B_value','LO',li1); if li1 > 0 then begin NumarisFloat3('DiffusionGradientDirection','FD',lf1,lf2,lf3); //vx(lf1,lf2,lf3,123); end; end else begin //get mosaic info //fx(lStart,lLength); result := NumarisInt1 ('NumberOfImagesInMosaic','US',li1); if result then begin NumarisInt2pStar ('AcquisitionMatrixText','SH', li2,li3); NumarisFloat3('SliceNormalVector','FD',lf1,lf2,lf3); end; end; FreeMem(lByteRA); end;//GetCSAImageHeaderInfoRaw function GetCSAImageHeaderInfoDTI (lFilename: string; lStart,lLength: integer; var lBval: integer; var ldti1,ldti2,ldti3: double): boolean; var li2,li3: integer; //not used begin result := GetCSAImageHeaderInfoRaw (TRUE,lFilename, lStart,lLength, lBval,li2,li3, ldti1,ldti2,ldti3); end; function GetCSAImageHeaderInfo (lFilename: string; lStart,lLength: integer; var lMosaicSlices,lMosaicX,lMosaicY: integer; var lv1,lv2,lv3: double): boolean; begin result := GetCSAImageHeaderInfoRaw (FALSE,lFilename, lStart,lLength, lMosaicSlices,lMosaicX,lMosaicY, lv1,lv2,lv3); end; *) procedure clear_dicom_data (var lDicomdata:Dicomdata); var lI: integer; begin with lDicomData do begin lDicomData.CSAImageHeaderInfoPos := 0; lDicomData.CSAImageHeaderInfoSz := 0; lDicomData.CSASeriesHeaderInfoPos := 0; lDicomData.CSASeriesHeaderInfoSz := 0; for lI := 1 to 6 do Orient[lI] := 0; DateTime := BogusDateTime; ManufacturerID := 0; kV := 0; //ImplementationVersion := 0; Vers0018_1020 := 0; AngulationFH := 0; AngulationRL := 0; AngulationAP := 0; nDTIdir := 0; nOrder := 0; PhilipsSliceOrient := 'NA'; ScanningSequence0018_0020 := ''; PhaseEncoding := 'NA'; PatientPos := 'NA'; for lI := 1 to kMaxDTIdir do begin DTI[lI].Bval := -1; DTI[lI].v1 := 0; DTI[lI].v2 := 0; DTI[lI].v3 := 0; (* DTI[lDICOMdata.nDTIdir].Bval := -1; DTI[lDICOMdata.nDTIdir].v1 := 0; DTI[lDICOMdata.nDTIdir].v2 := 0; DTI[lDICOMdata.nDTIdir].v3 := 0; *) end; SiemensDICOMDTI := true; SiemensDICOMDTICSA := false; file4D := false; PatientName := 'NO NAME'; PatientDoB := 'NO DOB'; PatientGender := 'NA'; PatientHx := ''; ImageComments := ''; //PatientID := 'NO ID'; StudyDate := ''; StudyTime := ''; SecSinceMidnight := 0; //AcqTime := ''; //ImgTime := ''; TR := 0; TE := 0; //Echo := 0; //kV := 0; //mA := 0; //Rotate180deg := false; //MaxIntensity := 0; //MinIntensity := 0; //MinIntensitySet := false; FloatData := false; ImageNum := -1; SlicesPer3DVol := 0; SiemensInterleaved := 2; //0=no,1=yes,2=undefined SiemensSlices := 0; SiemensMosaicX := 1; SiemensMosaicY := 1; IntenScale := 1; IntenIntercept := 0; SeriesNum := 1; AcquNum := 0; ImageNum := 1; //Accession := 1; PlanarConfig:= 0; //only used in RGB values //runlengthencoding := false; //CompressSz := 0; //CompressOffset := 0; SamplesPerPixel := 1; //WindowCenter := 0; //WindowWidth := 0; XYZmm[1] := 1; XYZmm[2] := 1; XYZmm[3] := 1; XYZdim[1] := 1; XYZdim[2] := 1; XYZdim[3] := 1; XYZdim[4] := 1; lDicomData.XYZori[1] := 0; lDicomData.XYZori[2] := 0; lDicomData.XYZori[3] := 0; ImageStart := 0; Little_Endian := 0; Allocbits_per_pixel := 16;//bits //Storedbits_per_pixel:= Allocbits_per_pixel; //StudyDatePos := 0; //Spacing:=0; //Thickness:= 0;//1391 Location:=0; //Modality:='MR'; //ProtocolName := ''; //serietag:=''; PatientPosX := 0;//1392 PatientPosY := 0;//1392 PatientPosZ := 0;//1392 JPEGLossyCpt := false; JPEGLosslessCpt := false; SignedData := true; CompressOffset := 0; CompresssZ := 0; BandwidthPerPixelPhaseEncode := 0; //7/2013 FieldStrength := 0; end; end; function DICOMinterslicedistance(var lDicomdata1,lDicomdata2:Dicomdata): single;//1392 begin result := sqrt(sqr(lDICOMdata1.PatientPosX-lDICOMdata2.PatientPosX) +sqr(lDICOMdata1.PatientPosY-lDICOMdata2.PatientPosY) +sqr(lDICOMdata1.PatientPosZ-lDICOMdata2.PatientPosZ)); end; end. ������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/nifti_form.lfm���������������������������������������������0000755�0001750�0001750�00000011341�12307634454�020374� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object NIfTIForm: TNIfTIForm Left = 797 Height = 266 Top = 32 Width = 400 ActiveControl = OKBtn BiDiMode = bdRightToLeft BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Convert NIfTI File' ClientHeight = 266 ClientWidth = 400 Constraints.MaxHeight = 266 Constraints.MaxWidth = 400 Constraints.MinHeight = 266 Constraints.MinWidth = 400 OnCreate = FormCreate ParentBiDiMode = False LCLVersion = '1.0.12.0' object Label1: TLabel Left = 8 Height = 17 Top = 168 Width = 102 Alignment = taCenter Caption = 'Output Format: ' ParentColor = False end object Label4: TLabel Left = 8 Height = 17 Top = 16 Width = 35 Alignment = taCenter Caption = 'Task:' ParentColor = False end object OKBtn: TButton Left = 200 Height = 25 Top = 208 Width = 75 BorderSpacing.InnerBorder = 4 Caption = 'OK' ModalResult = 1 OnClick = OKBtnClick TabOrder = 0 end object CancelBtn: TButton Left = 104 Height = 25 Top = 208 Width = 75 BorderSpacing.InnerBorder = 4 Caption = 'Cancel' ModalResult = 2 TabOrder = 1 end object TypeCombo: TComboBox Left = 118 Height = 20 Top = 163 Width = 209 ItemHeight = 0 Items.Strings = ( 'SPM2 (3D Anlyze hdr/img)' 'SPM5 (3D NIfTI hdr/img)' 'SPM8 (3D NIfTI nii)' '4D NIfTI hdr/img' 'FSL (4D NIfTI nii)' 'Compressed FSL (4D NIfTI nii)' 'MRIcron drawing (voi)' ) Style = csDropDownList TabOrder = 2 end object Panel1: TPanel Left = 8 Height = 103 Top = 59 Width = 312 BevelOuter = bvNone ClientHeight = 103 ClientWidth = 312 TabOrder = 3 object Label2: TLabel Left = 8 Height = 17 Top = 15 Width = 190 Caption = 'Volumes to remove from start' ParentColor = False end object Label3: TLabel Left = 7 Height = 17 Top = 55 Width = 185 Caption = 'Volumes to remove from end' ParentColor = False end object StartEdit: TSpinEdit Left = 224 Height = 15 Top = 13 Width = 74 MaxValue = 9999999 TabOrder = 0 end object EndEdit: TSpinEdit Left = 224 Height = 15 Top = 53 Width = 74 MaxValue = 9999999 TabOrder = 1 end end object Combo4D: TComboBox Left = 47 Height = 20 Top = 11 Width = 337 ItemHeight = 0 Items.Strings = ( 'Change format' 'Flip dimensions 3 and 4' 'Clip 1st/Last Volumes' 'Export as 32-bit real' 'Apply formula' 'ASL conversion' ) OnChange = Combo4DChange Style = csDropDownList TabOrder = 4 end object Combo3D: TComboBox Left = 48 Height = 20 Top = 11 Width = 336 ItemHeight = 0 Items.Strings = ( 'Change format' 'Reorient to orthogonal' 'Reorient and crop' ) Style = csDropDownList TabOrder = 5 end object ASLPanel: TPanel Left = 40 Height = 50 Top = 24 Width = 275 BevelOuter = bvNone ClientHeight = 50 ClientWidth = 275 TabOrder = 6 object ASLCombo: TComboBox Left = 16 Height = 20 Top = 11 Width = 250 ItemHeight = 0 Items.Strings = ( 'Subtract pairs - first image tagged' 'Subtract pairs - first image control' 'Subtract Custom' 'Add (odd+even) BOLD' ) Style = csDropDownList TabOrder = 0 end end object FormulaPanel: TPanel Left = 47 Height = 114 Top = 56 Width = 273 BevelOuter = bvNone BorderStyle = bsSingle ClientHeight = 114 ClientWidth = 273 TabOrder = 7 object Label5: TLabel Left = 31 Height = 17 Top = 17 Width = 33 Alignment = taCenter Caption = 'Scale' ParentColor = False end object Label6: TLabel Left = 31 Height = 17 Top = 59 Width = 39 Alignment = taCenter Caption = 'Power' ParentColor = False end object ScaleEdit: TFloatSpinEdit Left = 127 Height = 15 Top = 11 Width = 130 DecimalPlaces = 8 Increment = 1 MaxValue = 100 MinValue = 0 TabOrder = 0 Value = 1.2E-6 end object PowerEdit: TFloatSpinEdit Left = 127 Height = 15 Top = 56 Width = 130 DecimalPlaces = 8 Increment = 1 MaxValue = 100 MinValue = 0 TabOrder = 1 Value = 1.2E-6 end end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dcm2niigui.dof���������������������������������������������0000755�0001750�0001750�00000004544�12360762516�020273� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[FileVersion] Version=7.0 [Compiler] A=8 B=0 C=1 D=1 E=0 F=0 G=1 H=1 I=1 J=1 K=0 L=1 M=0 N=1 O=1 P=1 Q=0 R=0 S=0 T=0 U=0 V=1 W=0 X=1 Y=1 Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; NamespacePrefix= SymbolDeprecated=1 SymbolLibrary=1 SymbolPlatform=1 UnitLibrary=1 UnitPlatform=1 UnitDeprecated=1 HResultCompat=1 HidingMember=1 HiddenVirtual=1 Garbage=1 BoundsError=1 ZeroNilCompat=1 StringConstTruncated=1 ForLoopVarVarPar=1 TypedConstVarPar=1 AsgToTypedConst=1 CaseLabelRange=1 ForVariable=1 ConstructingAbstract=1 ComparisonFalse=1 ComparisonTrue=1 ComparingSignedUnsigned=1 CombiningSignedUnsigned=1 UnsupportedConstruct=1 FileOpen=1 FileOpenUnitSrc=1 BadGlobalSymbol=1 DuplicateConstructorDestructor=1 InvalidDirective=1 PackageNoLink=1 PackageThreadVar=1 ImplicitImport=1 HPPEMITIgnored=1 NoRetVal=1 UseBeforeDef=1 ForLoopVarUndef=1 UnitNameMismatch=1 NoCFGFileFound=1 MessageDirective=1 ImplicitVariants=1 UnicodeToLocale=1 LocaleToUnicode=1 ImagebaseMultiple=1 SuspiciousTypecast=1 PrivatePropAccessor=1 UnsafeType=1 UnsafeCode=1 UnsafeCast=1 [Linker] MapFile=0 OutputObjs=0 ConsoleApp=1 DebugInfo=0 RemoteSymbols=0 MinStackSize=16384 MaxStackSize=1048576 ImageBase=4194304 ExeDescription= [Directories] OutputDir= UnitOutputDir= PackageDLLOutputDir= PackageDCPOutputDir= SearchPath=..\common\;C:\pas\d4\RX\Units\;..\delphionly Packages=Vcl40;Vclx40;VclSmp40;Qrpt40;Vcldb40;RxCtl4 Conditionals= DebugSourceDirs= UsePackages=0 [Parameters] RunParams= HostApplication= Launcher= UseLauncher=0 DebugCWD= [Language] ActiveLang= ProjectLang= RootDir= [Version Info] IncludeVerInfo=1 AutoIncBuild=0 MajorVer=0 MinorVer=9 Release=0 Build=0 Debug=0 PreRelease=0 Special=0 Private=0 DLL=0 Locale=1033 CodePage=1252 [Version Info Keys] CompanyName= FileDescription= FileVersion=0.9.0.0 InternalName= LegalCopyright= LegalTrademarks= OriginalFilename= ProductName= ProductVersion=1.0.0.0 Comments= [HistoryLists\hlUnitAliases] Count=1 Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; [HistoryLists\hlSearchPath] Count=4 Item0=..\common\;C:\pas\d4\RX\Units\;..\delphionly Item1=..\common\;C:\pas\d4\RX\Units\ Item2=..\common\;C:\pas\d4\RX\Units Item3=..\common\ ������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/extrafpc.cfg�����������������������������������������������0000755�0001750�0001750�00000000130�11316131074�020014� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#IFDEF Darwin -k-macosx_version_min -k10.4 -XR/Developer/SDKs/MacOSX10.4u.sdk/ #ENDIF����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/niftiutil.pas����������������������������������������������0000755�0001750�0001750�00000207363�12311045766�020264� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit niftiutil; {$Include ..\common\isgui.inc} interface uses {$IFDEF FPC} {$IFDEF GUI}FileUtil, {$ENDIF} //FileUtil requires LResources that requires extra environment variables with tools like matlab gzio2, process, //FileUtil, {$ELSE} gziod, ShellAPI,Windows,Forms, {$ENDIF} SysUtils,Classes,define_types,filename,dicomtypes,prefs,dialogs_msg, nifti_foreign, nifti_types; {$H+} type TNIIopts = RECORD //peristimulus plot bs: boolean; gzBytes: Int64; // K_gzBytes_headerAndImageCompressed, K_gzBytes_onlyImageCompressed, K_gzBytes_headerAndImageUncompressed= 0; ImgName: string; end; const kNIIImgOffset = 352; //header is 348 bytes, but 352 is divisible by 8... function MaskImgs(lC1template, lC1source: string; lPrefs: TPrefs ; lThresh: single): string; function MaskImg(ltemplate, lsource: string; lPrefs: TPrefs; lThresh: single ): string; function Binarize(lC1Name: string; lPrefs: TPrefs ): string; function SameHdrDim (lAHdr,lBHdr: TNIFTIhdr; lCheck4D, lCheckDataType: boolean): boolean; procedure NIFTIhdr_ClearHdr (var lHdr: TNIFTIhdr ); //put sensible default values into header procedure DICOM2AnzHdr (var lBHdr: TNIFTIhdr; lAnonymize: boolean; var lFilename: string; var lDICOMdata: DicomData); procedure CustomFilename (var lFilename: string); function SumTPM (lSrcName,lDestName: string; lPrefs: TPrefs; lTissueTypes2Average: integer):string; //function SameHdrDim (lAHdr,lBHdr: TNIFTIhdr): boolean; function SaveHdr (var lFilename: ANSIstring; var lInHdr: TNIFTIhdr ; lSwap,lSPM2:boolean): boolean; function NIFTIhdr_LoadHdr (var lFilename: string; var lHdr: TNIFTIHdr; var lOpts: TNIIopts): boolean; procedure NIFTIhdr_SlicesToCoord (var lHdr: TNIFTIhdr; lXslice,lYslice,lZslice: integer; var lXmm,lYmm,lZmm: single); function ChangeNIfTISubformat(lHdrName: string; var lHdr: TNIFTIhdr; lPrefs: TPrefs): boolean; procedure SaveHdrRAM (var lFilename: ANSIstring; var lInHdr,lOutHdr: TNIFTIhdr ; lSwap,lSPM2:boolean); function SaveNIfTICore (var lOutImgName: string; var lvBuffer: bytep; lVolOffset: integer; var lInHdr: TNIFTIhdr; var lPrefs: TPrefs): string; function SaveNIfTICoreCrop (var lOutImgName: string; var lvBuffer: bytep; lVolOffset,lStartClip,lEndClip: integer; var lInHdr: TNIFTIhdr; var lPrefs: TPrefs): string; function NIFTIhdr_LoadImg (var lFilename: string; var lHdr: TNIFTIHdr; var lImgBuffer: byteP; var lImgOffset: integer; var lOpts: TNIIopts): boolean; //procedure NIFTIhdr_UnswapImg (var lHdr: TNIFTIHdr; var lImgBuffer: byteP; var lImgOffset: integer; var lByteSwap: boolean); //ensures image data is in native space function NIFTIhdr_LoadImgRaw (LoadHdr: boolean; var lFilename: string; var lHdr: TNIFTIHdr; var lImgBuffer: byteP; var lImgOffset: integer; var lOpts: TNIIopts): boolean; function NII_force32 (lSrcName,lDestName: string; lPrefs: TPrefs):string; function Rescale_4Dtissuemaps (lSrcName,lDestName: string; lPrefs: TPrefs; lMakeSym: boolean):string; function Merge4DFiles (lLowSliceName,lHighSliceName,lDestName: string; lNumberofLowSlicesToCopy: integer; lPrefs: TPrefs):string; function Insert3Din4D (l3DSliceName,l4DSliceName,lDestName: string; lVol2Copy: integer; lPrefs: TPrefs):string; function MaskImages(lMaskName: string; lFiles: TStrings; lPrefs: TPrefs; lVol: integer; lSaveThresh: boolean): string; function NonspatialDimensionsNII (lA: TNIFTIhdr): integer; implementation uses dialogsx; function AddFileNum(lVol,lnVol: integer; var lInName: string): string; var lNameWOExt,lExt: string; begin ExtractFileParts (lInName, lNameWOExt,lExt); result := lNameWOExt+'_'+PadStr(lVol,length(inttostr(lnVol))) +lExt; end; procedure NIFTIhdr_SwapBytes (var lAHdr: TNIFTIhdr ); //Swap Byte order for the Analyze type var lInc: integer; begin with lAHdr do begin swap4(hdrsz); swap4(extents); session_error := swap(session_error); for lInc := 0 to 7 do dim[lInc] := swap(dim[lInc]); Xswap4r(intent_p1); Xswap4r(intent_p2); Xswap4r(intent_p3); intent_code:= swap(intent_code); datatype:= swap(datatype); bitpix := swap(bitpix); slice_start:= swap(slice_start); for lInc := 0 to 7 do Xswap4r(pixdim[linc]); Xswap4r(vox_offset); Xswap4r(scl_slope); Xswap4r(scl_inter); slice_end := swap(slice_end); Xswap4r(cal_max); Xswap4r(cal_min); Xswap4r(slice_duration); Xswap4r(toffset); swap4(glmax); swap4(glmin); qform_code := swap(qform_code); sform_code:= swap(sform_code); Xswap4r(quatern_b); Xswap4r(quatern_c); Xswap4r(quatern_d); Xswap4r(qoffset_x); Xswap4r(qoffset_y); Xswap4r(qoffset_z); for lInc := 0 to 3 do begin Xswap4r(srow_x[lInc]); Xswap4r(srow_y[lInc]); Xswap4r(srow_z[lInc]); end; end; //with NIFTIhdr end; //proc NIFTIhdr_Swa (*procedure TestUINT16 (lval: integer); //this procedure demonstrates that words and smallints are identical for values 0..32767, so no need to swap if values are in this range var l16ui : WordP; l16i: SmallIntP; begin getmem(l16ui,1*sizeof(word)); l16ui^[1] := lval; l16i := SmallIntP(@l16ui^[1]); fx(l16i^[1],l16ui^[1]); freemem(l16ui); end;*) procedure Uint16 (var lvBuffer: bytep; lVolOffset: integer; var lInHdr: TNIFTIhdr;var lPrefs: TPrefs; var lByteSwap: boolean); //kDT_UINT16 saves data range 0..65535, but this is an atypical NIfTI format (not included in earlier Analyze format) // this procedure saves the data as kDT_SIGNED_SHORT 0..36767 // if data range is <32767 then saved unchanged, if range is >32767, saved as 15-bit (Least Significant bit clipped). var lmax,lv,lnv: integer; lTempB: ByteP; l16ui : WordP; //l16i: SmallIntP; l32f: SingleP; begin lnv := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]*NonspatialDimensionsNII(lInHdr); if (lInHdr.datatype <> kDT_UINT16) or (lnv < 1) then exit; l16ui := WordP(@lvBuffer^[lVolOffset]); if lByteSwap then begin lmax := swap(l16ui^[1]); for lv := 1 to lnv do if swap(l16ui^[lv]) > lmax then lmax := swap(l16ui^[lv]); end else begin lmax := l16ui^[1]; for lv := 1 to lnv do if l16ui^[lv] > lmax then lmax := l16ui^[lv]; end; if lmax < 32768 then begin //lossless: unsigned range <32768 (15 bits), so can be stored in signed 16bit lInHdr.datatype := kDT_SIGNED_SHORT; dcmMsg(' brightest voxel was '+inttostr(lmax)+': data will be saved as 16-bit signed integer.'); (*next lines not required, as range 0..32767 is stored identically for WORDS and SMALLINTS, see TestUINT16 l16i := SmallIntP(@lvBuffer^[lVolOffset]); for lv := 1 to lnv do l16i^[lv] := l16ui^[lv]; *) end else if not lPrefs.UINT16toFLOAT32 then begin dcmMsg('Warning: unusual NIFTI format UINT16, range: '+inttostr(lMax) ); dcmMsg(' If you prefer compatibility, edit your preference named UINT16toFLOAT32'); end else begin dcmMsg('Warning: for compatibility, converting UINT16->FLOAT32, range: '+inttostr(lMax) ); dcmMsg(' If you prefer filesize over compatibility, edit your preference named UINT16toFLOAT32'); lInHdr.datatype := kDT_Float; lInHdr.bitpix := 32; lmax := lVolOffset+ (lnv*sizeof(Word)); GetMem(lTempB,lmax); if lByteSwap then begin dcmMsg(' Swapping data to native byte order (Big vs Little Endian)'); for lv := 1 to lnv do l16ui^[lv] := swap(l16ui^[lv]); end; for lv := 1 to lmax do lTempB^[lv] := lvBuffer^[lv]; (*if lByteSwap then begin lByteSwap := false; if (lVolOffset > 0) do for lv := 1 to lVolOffset do lTempB^[lv] := swap(lvBuffer^[lv]); xx for lv := 1 to lmax do lTempB^[lv] := swap(lvBuffer^[lv]); Msg(' Swapping data to native byte order (Big vs Little Endian)'); end else begin for lv := 1 to lmax do lTempB^[lv] := lvBuffer^[lv]; end;*) freemem(lvBuffer); GetMem(lvBuffer,lVolOffset+ (lnv*sizeof(single))); for lv := 1 to lVolOffset do //copy header lvBuffer^[lv] := lTempB^[lv]; l16ui := WordP(@lTempB^[lVolOffset]); l32f := SingleP(@lvBuffer^[lVolOffset]); for lv := 1 to lnv do l32f^[lv] :=l16ui^[lv]; Freemem(lTempB); end;// if range requires conversion to 32-bit float end; //Uint16 function getPigzNameWithPath: string; //returns path to pigz executable, e.g. '/Users/rorden/downloads/pigz-master/pigz'; var i: integer; exename: string; {$IFDEF DARWIN} temp: string;{$ENDIF} begin {$IFDEF ENDIAN_BIG} Msg('pigz not available with PowerPC computers'); result := ''; exit; {$ENDIF} for i := 1 to 2 do begin {$IFDEF UNIX} if i = 1 then exename := 'pigz' else exename := 'pigz_mricron'; {$IFDEF GUI} result := FindDefaultExecutablePath(exename); // "which pigz" if length(result) > 0 then exit; {$ELSE} result := exename; if fileexists(result) then exit; result := ExtractFilePath( paramstr(0))+exename; if fileexists(result) then exit; result := '/usr/bin/'+exename; if fileexists(result) then exit; result := '/usr/local/bin/'+exename; if fileexists(result) then exit; {$ENDIF} {$ELSE} if i = 1 then exename := 'pigz.exe' else exename := 'pigz_mricron.exe'; {$ENDIF} result := ExtractFilePath( paramstr(0))+exename; if fileexists(result) then exit; {$IFDEF DARWIN} temp := result; result := ExtractFilePath(paramstr(0)); result := LeftStr(result, Pos((ExtractFileName(paramstr(0))+'.app'), result)-1)+exename; if fileexists(result) then exit; {$ENDIF} end; //for i:= 1 to 2 {$IFDEF DARWIN} {$IFDEF GUI} dcmMsg('File compression error: pigz does not exist in you path or '+result+' or '+temp); {$ELSE} dcmMsg('File compression error: to use "pigz" place it in the same folder as '+ paramstr(0)); {$ENDIF} {$ELSE} {$IFDEF GUI} dcmMsg('File compression error: pigz does not exist in you path or '+result); {$ELSE} dcmMsg('File compression error: to use "pigz" place it in the same folder as '+ paramstr(0)); {$ENDIF} {$ENDIF} result := ''; end; {$IFDEF FPC} //Freepascal has handy 'Process' for calling console applications function runPigz(var lImgName : string; processes: integer): boolean; // abs(processes): 1= default (as many as available, 2..n: use this many processors // if processes is a NEGATIVE value, application does not wait for Pigz to complete... var AProcess: TProcess; Acmd: string; AResponse: TStringList; i: integer; begin Acmd := getPigzNameWithPath; //+' -k' //<- to KEEP original if length(Acmd) < 1 then exit; //Acmd := Acmd +' -v -k';//verbose, keep files if abs(processes) > 1 then Acmd := Acmd + ' -p '+inttostr( abs(processes) ); Acmd := Acmd +' '+lImgName; dcmMsg('External compression: '+Acmd); AProcess := TProcess.Create(nil); //AProcess.Environment.Add('FSLDIR='/usr/local/fsl/); //optional AProcess.CommandLine := Acmd; if (processes > 0) then //wait for pgzip to complete... AProcess.Options := AProcess.Options + [poWaitOnExit, poStderrToOutPut, poUsePipes] else //do not wait for pigz AProcess.Options := AProcess.Options + [poStderrToOutPut, poUsePipes]; AProcess.Execute; if (processes > 0) then begin//wait for pgzip to complete... AResponse := TStringList.Create; AResponse.LoadFromStream(AProcess.Output); if AResponse.Count > 0 then for i := 1 to AResponse.Count do dcmMsg(' '+AResponse.Strings[i-1]); AResponse.Free; end; AProcess.Free; end; {$ELSE} //Delphi does not have 'Process' for calling console applications procedure ExecNewProcess(AppName, ACmd : String; WaitUntilDone: boolean); var StartInfo : TStartupInfo; ProcInfo : TProcessInformation; CreateOK : Boolean; begin { fill with known state } FillChar(StartInfo,SizeOf(TStartupInfo),#0); FillChar(ProcInfo,SizeOf(TProcessInformation),#0); StartInfo.cb := SizeOf(TStartupInfo); CreateOK := CreateProcess(PChar(AppName),Pchar(Acmd), nil, nil,False, CREATE_NEW_PROCESS_GROUP+NORMAL_PRIORITY_CLASS, nil, nil, StartInfo, ProcInfo); { check to see if successful } if (CreateOK) and (WaitUntilDone) then WaitForSingleObject(ProcInfo.hProcess, INFINITE); end; function runPigz(var lImgName : string; processes: integer): boolean; // abs(processes): 1= default (as many as available, 2..n: use this many processors // if processes is a NEGATIVE value, application does not wait for Pigz to complete... var AppName, Acmd: string; begin AppName := getPigzNameWithPath; //+' -k' //<- to KEEP original if length(AppName) < 1 then exit; Acmd := ''; //Acmd := Acmd +' -v -k';//verbose, keep files if abs(processes) > 1 then Acmd := Acmd + ' -p '+inttostr( abs(processes) ); Acmd := Acmd +' "'+lImgName+'"'; dcmMsg('External compression: '+AppName+' '+Acmd); Acmd := AppName+' '+Acmd; ExecNewProcess(AppName, ACmd, (processes > 0)); end; {$ENDIF} function SaveNIfTICore (var lOutImgName: string; var lvBuffer: bytep; lVolOffset: integer; var lInHdr: TNIFTIhdr; var lPrefs: TPrefs): string; //image data should start at lVolOffset - this should be AT LEAST kNIIImgOffset (=352) bytes for creating .nii.gz files //important note - when converting 4D to 3D to .nii format the lvBuffer is changed :: must correct this var lPref : TPrefs; lVol,lVolStart,lVolBytes: integer; lOutF: File; lNoGZName,lHdrName,lImgName: string; l3dHdr,lOutHdr : TNIFTIHdr; lHdrBupRA: bytep; lByteSwap: boolean; begin lByteSwap := false; lNoGZName := (lOutImgName); StripGZExt(lNoGZName); //we want to convert filename.nii.gz -> filename.hdr not -> filename.nii.hdr StripNIIVOIExt(lNoGZName);//we want to convert filename.nii.voi to filename.hdr lPref := lPrefs; CorrectPrefs(lPref); result := ''; Uint16 (lvBuffer,lVolOffset, lInHdr,lPrefs,lByteSwap); if (not lPref.FourD) and (lInHdr.dim[4] > 1) then begin //4D -> 3D lVolBytes := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]*trunc(((lInHdr.bitpix)+7)/8); lVolStart := lVolOffset; l3dHdr := lInHdr; l3dHdr.dim[4] := 1; for lVol := 1 to lInHdr.dim[4] do begin //1st - save header lHdrName := AddFileNum(lVol,lInHdr.dim[4],lNoGZName); result := SaveNIfTICore (lHdrName, lvBuffer, lVolStart, l3dHdr, lPref); lVolStart := lVolStart + lVolBytes; //SaveNiftiCore new filename, new offset end; //for each vol exit; end; //l4Dto3D Filemode := 2; lVolBytes := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]*lInHdr.dim[4]*trunc(((lInHdr.bitpix)+7)/8); if ((kNIIImgOffset+lVolBytes)> DiskFreeEx(lNoGZName)) then begin dcmMsg('There is not enough free space on the destination disk to save the data. '+kCR+ lNoGZName+ kCR+' Bytes Required: '+inttostr(lVolBytes) ); exit; end; if (lPref.SingleNIIFile) then begin lVolStart := lVolOffset-kNIIImgOffset; lVolBytes := lVolBytes + kNIIImgOffset; if lVolStart < 1 then begin dcmMsg('SaveNIfTICore Error: '+inttostr(lVolStart)); exit; end; getmem(lHdrBupRA,kNIIImgOffset); Move(lvBuffer^[lVolStart],lHdrBupRA^[1],kNIIImgOffset); //bytes 349,350,351,352 should be set to zero lVol := 0; lvBuffer^[kNIIImgOffset-3+lVol] := 0; lvBuffer^[kNIIImgOffset-2+lVol] := 0; lvBuffer^[kNIIImgOffset-1+lVol] := 0; lvBuffer^[kNIIImgOffset+lVol] := 0; //next - create [potentially byte swapped] header and load into buffer lImgName := changefileext(lNoGZName,'.nii'); SaveHdrRAM (lImgName,lInHdr,lOutHdr, lByteSwap,lPrefs.SPM2); Move(lOutHdr,lvBuffer^[lVolStart],sizeof(lOutHdr)); //move 348 byte header in place //finally - write buffer to disk if (lPrefs.Gzip) and (lPrefs.usePigz <> 0) and (length(getPigzNameWithPath) > 0) then begin AssignFile(lOutF, lImgName); Rewrite(lOutF,1); BlockWrite(lOutF, lvBuffer^[lVolStart], lVolBytes); CloseFile(lOutF); runPigz(lImgName, lPrefs.usePigz); //DeleteFile(lImgName); end else if lPrefs.Gzip then begin if lPrefs.VOI then lImgName := changefileext(lNoGZName,'.voi') else lImgName := changefileext(lNoGZName,'.nii.gz'); dcmMsg('GZip...' + extractfilename(lImgName)); GZipBuffer(lImgName, @lvBuffer^[lVolStart],lVolBytes,true); end else begin //not .nii.gz -> .nii dcmMsg('Saving '+lImgName); AssignFile(lOutF, lImgName); Rewrite(lOutF,1); BlockWrite(lOutF, lvBuffer^[lVolStart], lVolBytes); CloseFile(lOutF); end; //else no GZip Move(lHdrBupRA^[1],lvBuffer^[lVolStart],kNIIImgOffset); //replace data overwritten by header - otherwise 4D->3D corrupts lvBuffer freemem(lHdrBupRA); end else begin //not .nii -> hdr and img lHdrName := changefileext(lNoGZName,'.hdr'); lImgName := changefileext(lNoGZName,'.img'); //next - create [potentially byte swapped] header and save to disk if not SaveHdr (lHdrName,lInHdr, lByteSwap,lPrefs.SPM2) then exit; //finally - write buffer to disk AssignFile(lOutF, lImgName); Rewrite(lOutF,1); BlockWrite(lOutF, lvBuffer^[lVolOffset], lVolBytes); CloseFile(lOutF); end; //else hdr+img result := lImgName; end; function SaveNIfTICoreCrop (var lOutImgName: string; var lvBuffer: bytep; lVolOffset,lStartClip,lEndClip: integer; var lInHdr: TNIFTIhdr; var lPrefs: TPrefs): string; var lVolStart,lVolBytes: integer; lClipName: string; lClipHdr : TNIFTIHdr; begin result := ''; if (lStartClip < 0) or (lEndClip < 0) then exit; //no negative values if (lStartClip <= 0) and (lEndClip <= 0) then exit; //no change if (lStartClip+lEndClip) >= lInHdr.dim[4] then exit; //can not remove this many volumes lVolBytes := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]*trunc(((lInHdr.bitpix)+7)/8); lClipHdr := lInHdr; lClipHdr.dim[4] := lInHdr.dim[4]-lStartClip-lEndClip; lVolStart := lVolOffset + (lStartClip*lVolBytes); lClipName := ChangeFilePrefix (lOutImgName,'x'); result := SaveNIfTICore (lClipName, lvBuffer, lVolStart, lClipHdr, lPrefs); end; function SubBound (lVal,lMin: integer): integer; begin result := lVal; if result < lMin then result := lMin; end; function NonspatialDimensionsNII (lA: TNIFTIhdr): integer; //returns sum of 4th, 5th, 6th and 7th dimension... begin result := SubBound(lA.dim[4],1)*SubBound(lA.dim[5],1)*SubBound(lA.dim[6],1)*SubBound(lA.dim[7],1); end; procedure NIFTIhdr_UnswapImgX (var lHdr: TNIFTIHdr; var lImgBuffer: byteP; var lImgOffset: integer; var lByteSwap: boolean); //ensures image data is in native space //returns data in native endian //sets 'ByteSwap' flag to false. E.G. a big-endian image will be saved as little-endian on little endian machines var lInc,lImgSamples : integer; //2f : SingleP; l32i : LongIntP; l16i : SmallIntP; begin if not lByteSwap then exit; case lHdr.datatype of kDT_UNSIGNED_CHAR : begin lByteSwap := false; //single byte data - no need to byte swap... exit; end; kDT_SIGNED_SHORT,kDT_SIGNED_INT,kDT_FLOAT: ;//supported format else begin dcmMsg('niftiutil UnSwapImg error: datatype not supported.'); exit; end; end; //case lImgSamples := lHdr.Dim[1] *lHdr.Dim[2]*lHdr.Dim[3]*NonspatialDimensionsNII(lHdr); if lImgSamples < 1 then exit; case lHdr.datatype of kDT_SIGNED_SHORT: begin l16i := SmallIntP(@lImgBuffer^[lImgOffset+1]); for lInc := 1 to lImgSamples do l16i^[lInc] := Swap(l16i^[lInc]); end; //l16i kDT_SIGNED_INT,kDT_FLOAT: begin //note: for the purposes of byte swapping, floats and long ints are the same l32i := LongIntP(@lImgBuffer^[lImgOffset+1]); for lInc := 1 to lImgSamples do Swap4(l32i^[lInc]); end;//32i (*kDT_FLOAT: begin l32f := SingleP(@lImgBuffer^[lImgOffset+1]); for lInc := 1 to lImgSamples do pswap4r(l32f^[lInc]); //faster as procedure than function see www.optimalcode.com end; //32f*) end; //case lByteSwap := false; end; function NIFTIhdr_LoadImgRaw (LoadHdr: boolean; var lFilename: string; var lHdr: TNIFTIHdr; var lImgBuffer: byteP; var lImgOffset: integer; var lOpts: TNIIopts ): boolean; //ImgBuffer always offset by kNIIImgOffset- this allows rapid nii.gz creation //loads img to byteP - if this returns successfully you must freemem(lImgBuffer) var lVol,lFileBytes,lImgBytes: integer; lBuf: ByteP; lInF: File; begin result := false; if loadHdr then begin if not NIFTIhdr_LoadHdr (lFilename, lHdr, lOpts) then begin dcmMsg('Unable to read as NifTI/Analyze' + lFilename); exit; end; end;//if we load the header from disk... lImgOffset := kNIIImgOffset;// (=352) bytes for creating .nii.gz files lVol := NonspatialDimensionsNII(lHdr);//lHdr.dim[4]; if lVol < 1 then lVol := 1; lImgBytes := lHdr.dim[1]*lHdr.dim[2]*lHdr.dim[3]*lVol*(lHdr.bitpix div 8); if not fileexists(lOpts.ImgName) then begin dcmMsg('LoadImg Error: Unable to find '+lOpts.ImgName); exit; end; if (lOpts.gzBytes = K_gzBytes_headerAndImageUncompressed) and (FSize (lOpts.ImgName) < ( lImgBytes+round(lHdr.vox_offset))) then begin dcmMsg('LoadImg Error: File smaller than expected '+lOpts.ImgName); exit; end; lFileBytes := lImgBytes+ lImgOffset; GetMem(lImgBuffer,lFileBytes); if (lOpts.gzBytes <> K_gzBytes_headerAndImageUncompressed) then begin lBuf := @lImgBuffer^[lImgOffset+1]; if lOpts.gzBytes = K_gzBytes_headerAndImageCompressed then UnGZip (lOpts.ImgName,lBuf, round(lHdr.vox_offset),lImgBytes) else UnGZip2 (lOpts.ImgName,lBuf, 0,lImgBytes, round(lHdr.vox_offset)); end else begin AssignFile(lInF, lOpts.ImgName); Reset(lInF,1); Seek(lInF,round(lHdr.vox_offset)); Filemode := 0; //ReadONly BlockRead(lInF, lImgBuffer^[lImgOffset+1],lImgBytes); CloseFile(lInF); end; Filemode := 2; //Read/Write NIFTIhdr_UnswapImgX(lHdr, lImgBuffer, lImgOffset,lOpts.bs); result := true; end; //NIFTIhdr_LoadImgRaw function NIFTIhdr_LoadImg (var lFilename: string; var lHdr: TNIFTIHdr; var lImgBuffer: byteP; var lImgOffset: integer; var lOpts: TNIIOpts): boolean; begin result := NIFTIhdr_LoadImgRaw (true, lFilename, lHdr, lImgBuffer, lImgOffset, lOpts); end; (*function NIFTIhdr_LoadImg (var lFilename: string; var lHdr: TNIFTIHdr; var lImgBuffer: byteP; var lImgOffset: integer; var lByteSwap: boolean): boolean; //ImgBuffer always offset by kNIIImgOffset- this allows rapid nii.gz creation //loads img to byteP - if this returns successfully you must freemem(lImgBuffer) var lExt,lImgName: string; lVol,lFileBytes,lImgBytes: integer; lBuf: ByteP; lGZin: boolean; lInF: File; begin result := false; if not NIFTIhdr_LoadHdr (lFilename, lHdr, lByteSwap) then begin Msg('Unable to read as NifTI/Analyze' + lFilename); exit; end; lExt := UpCaseExt(lFilename); lGZin := ExtGZ(lFilename); if lExt = '.VOI' then lGZin := true; lImgOffset := kNIIImgOffset;// (=352) bytes for creating .nii.gz files lVol := lHdr.dim[4]; if lVol < 1 then lVol := 1; lImgBytes := lHdr.dim[1]*lHdr.dim[2]*lHdr.dim[3]*lVol*(lHdr.bitpix div 8); if lExt ='.HDR' then lImgName := changefileext(lFilename,'.img') else lImgName := lFilename; if not fileexists(lImgName) then begin Msg('LoadImg Error: Unable to find '+lImgName); exit; end; if (not lGZin) and (FSize (lImgName) < ( lImgBytes)) then begin Msg('LoadImg Error: File smaller than expected '+lImgName); exit; end; lFileBytes := lImgBytes+ lImgOffset; GetMem(lImgBuffer,lFileBytes); if lGZin then begin lBuf := @lImgBuffer^[lImgOffset+1]; UnGZip (lImgName,lBuf, round(lHdr.vox_offset),lImgBytes); end else begin AssignFile(lInF, lImgName); Reset(lInF,1); Seek(lInF,round(lHdr.vox_offset)); Filemode := 0; //ReadONly BlockRead(lInF, lImgBuffer^[lImgOffset+1],lImgBytes); CloseFile(lInF); end; Filemode := 2; //Read/Write result := true; end; *) procedure CustomFilename (var lFilename: string); var lNew,lPath,lName,lExt: string; begin if not FilenameParts (lFilename, lPath,lName,lExt) then exit; lNew := GetStr('Rename '+lName); if lNew = '' then exit; lFilename := lPath + lNew + lExt; end; function ChangeNIfTISubformat(lHdrName: string; var lHdr: TNIFTIhdr; lPrefs: TPrefs): boolean; var lImgBuffer: byteP; lImgOffset: integer; lOutImgName: string; lOpts: TNIIOpts; begin result := false; if not NIFTIhdr_LoadImg (lHdrName, lHdr, lImgBuffer, lImgOffset,lOpts) then exit; dcmMsg('Changing subformat of '+lHdrName); lOutImgName := ChangeFilePrefix (lHdrName,'f'); if lPrefs.CustomRename then CustomFilename(lOutImgName); if SaveNIfTICore (lOutImgName, lImgBuffer, lImgOffset+1, lHdr, lPrefs) ='' then exit; Freemem(lImgBuffer); result := true; //11/2007 ExitCode := 0; end; procedure NIFTIhdr_SlicesToCoord (var lHdr: TNIFTIhdr; lXslice,lYslice,lZslice: integer; var lXmm,lYmm,lZmm: single); //ignores origin offset begin lXmm := (lHdr.srow_x[0]*lXslice)+ (lHdr.srow_x[1]*lYslice)+(lHdr.srow_x[2]*lzslice); lYmm := (lHdr.srow_y[0]*lXslice)+ (lHdr.srow_y[1]*lYslice)+(lHdr.srow_y[2]*lzslice); lZmm := (lHdr.srow_z[0]*lXslice)+ (lHdr.srow_z[1]*lYslice)+(lHdr.srow_z[2]*lzslice); end; function NIFTIhdr_LoadHdr (var lFilename: string; var lHdr: TNIFTIHdr; var lOpts: TNIIOpts): boolean; var lHdrFile: file; {lOri: array [1..3] of single;} lBuff: Bytep; lReportedSz, lSwappedReportedSz,lHdrSz,lFileSz: Longint; lForeignSwapEndian: boolean; lExt: string; //1494 begin Result := false; //assume error lOpts.gzBytes := K_gzBytes_headerAndImageUncompressed; lForeignSwapEndian := false; if lFilename = '' then exit; lOpts.Imgname := lFilename; lExt := UpCaseExt(lFilename); if lExt = '.IMG' then lFilename := changeFileExt(lFilename,'.hdr'); if (lExt = '.BRIK') or (lExt = '.BRIK.GZ') then lFilename := changeFileExt(lFilename,'.HEAD'); lExt := UpCaseExt(lFilename); if lExt = '.HDR' then lOpts.Imgname := changeFileExt(lFilename,'.img'); lHdrSz := sizeof(TniftiHdr); lFileSz := FSize (lFilename); if lFileSz = 0 then begin dcmMsg('Unable to find NIFTI header named '+lFilename); exit; end; if lFileSz < lHdrSz then begin dcmMsg('Error in reading NIFTI header: NIfTI headers need to be at least '+inttostr(lHdrSz)+ ' bytes: '+lFilename); exit; end; FileMode := 0; { Set file access to read only } if (lExt = '.MGH') or (lExt = '.MGZ') or (lExt = '.MHD') or (lExt = '.MHA') or (lExt = '.NRRD') or (lExt = '.NHDR') or (lExt = '.HEAD') then begin lOpts.Imgname := lFilename; //will change header name to image name if required result := readForeignHeader( lOpts.Imgname, lHdr,lOpts.gzBytes, lForeignSwapEndian); //we currently ignore result! end else begin //native NIfTI if (lExt = '.NII.GZ') or (lExt = '.VOI') then begin//1388 lBuff := @lHdr; UnGZip(lFileName,lBuff,0,lHdrSz); //1388 lOpts.gzBytes := K_gzBytes_headerAndImageCompressed; end else begin //if gzip {$I-} AssignFile(lHdrFile, lFileName); FileMode := 0; { Set file access to read only } Reset(lHdrFile, 1); {$I+} if ioresult <> 0 then begin dcmMsg('Error in reading NIFTI header.'+inttostr(IOResult)); FileMode := 2; exit; end; BlockRead(lHdrFile, lHdr, lHdrSz); CloseFile(lHdrFile); end; end;//nifti FileMode := 2; if (IOResult <> 0) then exit; lReportedSz := lHdr.HdrSz; lSwappedReportedSz := lReportedSz; swap4(lSwappedReportedSz); if lReportedSz = lHdrSz then begin lOpts.bs := false; end else if lSwappedReportedSz = lHdrSz then begin lOpts.bs := true; NIFTIhdr_SwapBytes (lHdr); end else begin dcmMsg('Warning: the header file is not in NIfTi format [the first 4 bytes do not have the value 348]. Assuming big-endian data.'); exit; end; if (lHdr.dim[0] > 7) or (lHdr.dim[0] < 1) then begin //only 1..7 dims, so this dcmMsg('Illegal NIfTI Format Header: this header does not specify 1..7 dimensions.'); exit; end; if lHdr.Dim[4] < 1 then lHdr.Dim[4] := 1; if lForeignSwapEndian then lOpts.bs := true; result := true; end; //func Analyzehdr_LoadHdr function SaveHdr (var lFilename: ANSIstring; var lInHdr: TNIFTIhdr ; lSwap,lSPM2:boolean): boolean; var lOutHdr: TNIFTIhdr; lExt: string; lF: File; lLong: LongINt; begin result := false; if ((sizeof(TNIFTIhdr ))> DiskFreeEx(lFilename)) then begin dcmMsg('There is not enough free space on the destination disk to save the header. '+kCR+ lFileName+ kCR+' Bytes Required: '+inttostr(sizeof(TNIFTIhdr )) ); exit; end; if lInHdr.dim[4] > 1 then begin lInHdr.dim[0] := 4; end else begin lInHdr.dim[0] := 3;//3D july2006 lInHdr.dim[4] := 1;//3D july2006 end; {if Fileexists(lFileName) then begin Msg('Error: the file '+lFileName+' already exists.'); exit; end; } result := true; move(lInHdr, lOutHdr, sizeof(lOutHdr)) ; lExt := UpCaseExt(lFileName); if (lExt='.IMG') or (lExt ='.HDR') then begin {$IFDEF obsoleteENDIAN_BIG} //OSX PPC lOutHdr.magic := kswapNIFTI_MAGIC_SEPARATE_HDR; {$ELSE} lOutHdr.magic := kNIFTI_MAGIC_SEPARATE_HDR; {$ENDIF} lOutHdr.vox_offset := 0; if lSPM2 then begin //SPM2 does not recognize NIfTI - origin values will be wrong lOutHdr.magic := 0; lOutHdr.qform_code := 0; lOutHdr.sform_code:= 0; lOutHdr.quatern_b := 0; lOutHdr.quatern_c := 0; lOutHdr.quatern_d := 0; lOutHdr.qoffset_x := 0; lOutHdr.qoffset_y := 0; lOutHdr.qoffset_z := 0; end; end else begin {$IFDEF obsoleteENDIAN_BIG} //OSX PPC lOutHdr.magic := kswapNIFTI_MAGIC_EMBEDDED_HDR; {$ELSE} lOutHdr.magic := kNIFTI_MAGIC_EMBEDDED_HDR; {$ENDIF} lOutHdr.vox_offset := kNIIImgOffset;//352 bytes end; {$IFDEF obsoleteENDIAN_BIG} //OSX PPC if not lSwap then {$ELSE} if lSwap then {$ENDIF} NIFTIhdr_SwapBytes (lOutHdr);{swap to sun format} Filemode := 1; //1366 AssignFile(lF, lFileName); {WIN} if fileexists(lFilename) then Reset(lF,1) else Rewrite(lF,1); BlockWrite(lF,lOutHdr, sizeof(TNIFTIhdr )); if (lExt='.IMG') or (lExt ='.HDR') then begin end else begin lLong := 0; BlockWrite(lF,lLong, 4); end; CloseFile(lF); Filemode := 2; //1366 end; procedure SaveHdrRAM (var lFilename: ANSIstring; var lInHdr,lOutHdr: TNIFTIhdr ; lSwap,lSPM2:boolean); var lExt: string; begin if lInHdr.dim[4] > 1 then begin lInHdr.dim[0] := 4; end else begin lInHdr.dim[0] := 3;//3D july2006 lInHdr.dim[4] := 1;//3D july2006 end; move(lInHdr, lOutHdr, sizeof(lOutHdr)) ; lExt := UpCaseExt(lFileName); if (lExt='.IMG') or (lExt ='.HDR') then begin {$IFDEF obsoleteENDIAN_BIG} //OSX PPC lOutHdr.magic := kswapNIFTI_MAGIC_SEPARATE_HDR; {$ELSE} lOutHdr.magic := kNIFTI_MAGIC_SEPARATE_HDR; {$ENDIF} lOutHdr.vox_offset := 0; if lSPM2 then begin //SPM2 does not recognize NIfTI - origin values will be wrong lOutHdr.magic := 0; lOutHdr.qform_code := 0; lOutHdr.sform_code:= 0; lOutHdr.quatern_b := 0; lOutHdr.quatern_c := 0; lOutHdr.quatern_d := 0; lOutHdr.qoffset_x := 0; lOutHdr.qoffset_y := 0; lOutHdr.qoffset_z := 0; end; end else begin {$IFDEF obsoleteENDIAN_BIG} //OSX PPC lOutHdr.magic := kswapNIFTI_MAGIC_EMBEDDED_HDR; {$ELSE} lOutHdr.magic := kNIFTI_MAGIC_EMBEDDED_HDR; {$ENDIF} lOutHdr.vox_offset := kNIIImgOffset;//352 bytes end; {$IFDEF obsoleteENDIAN_BIG} //OSX PPC if not lSwap then {$ELSE} if lSwap then {$ENDIF} NIFTIhdr_SwapBytes (lOutHdr);{swap to sun format} end; procedure NIFTIhdr_SetIdentityMatrixx (var lHdr: TNIFTIHdr); //create neutral rotation matrix var lInc: integer; begin with lHdr do begin for lInc := 0 to 3 do srow_x[lInc] := 0; for lInc := 0 to 3 do srow_y[lInc] := 0; for lInc := 0 to 3 do srow_z[lInc] := 0; for lInc := 1 to 16 do intent_name[lInc] := chr(0); //next: create identity matrix: if code is switched on there will not be a problem srow_x[0] := 1; srow_y[1] := 1; srow_z[2] := 1; end; end; //proc NIFTIhdr_IdentityMatrix procedure NIFTIhdr_ClearHdr (var lHdr: TNIFTIhdr ); //put sensible default values into header var lInc: byte; begin with lHdr do begin {set to 0} HdrSz := sizeof(TNIFTIhdr); for lInc := 1 to 10 do Data_Type[lInc] := chr(0); for lInc := 1 to 18 do db_name[lInc] := chr(0); extents:=0; session_error:= 0; regular:='r'; dim_info:=(0); dim[0] := 4; for lInc := 1 to 7 do dim[lInc] := 0; intent_p1 := 0; intent_p2 := 0; intent_p3 := 0; intent_code:=0; datatype:=0 ; bitpix:=0; slice_start:=0; for lInc := 1 to 7 do pixdim[linc]:= 1.0; vox_offset:= 0.0; scl_slope := 1.0; scl_inter:= 0.0; slice_end:= 0; slice_code := 0; xyzt_units := 10; cal_max:= 0.0; cal_min:= 0.0; slice_duration:=0; toffset:= 0; glmax:= 0; glmin:= 0; for lInc := 1 to 80 do descrip[lInc] := chr(0);{80 spaces} for lInc := 1 to 24 do aux_file[lInc] := chr(0);{80 spaces} {below are standard settings which are not 0} bitpix := 16;//vc16; {8bits per pixel, e.g. unsigned char 136} DataType := 4;//vc4;{2=unsigned char, 4=16bit int 136} Dim[0] := 3; Dim[1] := 256; Dim[2] := 256; Dim[3] := 128; Dim[4] := 1; {n vols} Dim[5] := 1; Dim[6] := 1; Dim[7] := 1; glMin := 0; glMax := 255; qform_code := kNIFTI_XFORM_UNKNOWN; sform_code:= kNIFTI_XFORM_UNKNOWN; quatern_b := 0; quatern_c := 0; quatern_d := 0; qoffset_x := 0; qoffset_y := 0; qoffset_z := 0; NIFTIhdr_SetIdentityMatrixx(lHdr); magic := kNIFTI_MAGIC_SEPARATE_HDR; end; //with the NIfTI header... end; //proc NIFTIhdr_ClearHdr procedure DICOM2AnzHdr (var lBHdr: TNIFTIhdr; lAnonymize: boolean; var lFilename: string; var lDICOMdata: DicomData); var lInc,lLen: integer; lStr: string; begin NIFTIhdr_ClearHdr(lBHdr); if not lAnonymize then begin //next: put PatientID into patient_ID array lLen := length(lDICOMdata.ProtocolName); if lLen > 23 then lLen := 23; //24=size of aux_file if lLen > 0 then begin lBHdr.aux_file[1] :='!'; for lInc := 1 to lLen do lBHdr.aux_file[lInc+1] := lDICOMdata.ProtocolName[lInc]; end; (* lLen := length(lDicomData.PatientID); if lLen > 10 then lLen := 10; //10=size of patient_ID array if lLen > 0 then for lInc := 1 to lLen do lBHdr.patient_id[lInc] := lDicomData.PatientID[lInc]; *) //next: put PatientName into Descrip array (*lLen := length(lDicomData.PatientName); if lLen > 80 then lLen := 80; //80=size of descrip array if lLen > 0 then for lInc := 1 to lLen do lBHdr.descrip[lInc] := lDicomData.PatientName[lInc];*) //next: put StudyDate into exp_date array (* lLen := length(lDicomData.StudyDate); if lLen > 10 then lLen := 10; //10=size of exp_date array if lLen > 0 then for lInc := 1 to lLen do lBHdr.exp_date[lInc] := lDicomData.StudyDate[lInc]; *) //next: put AcqTime into exp_time array (*lLen := length(lDicomData.AcqTime); if lLen > 10 then lLen := 10; //10=size of exp_time array if lLen > 0 then for lInc := 1 to lLen do lBHdr.exp_time[lInc] := lDicomData.AcqTime[lInc]; *) //next: put Modality into generated array (*lLen := length(lDicomData.modality); if lLen > 10 then lLen := 10; //10=size of generated array if lLen > 0 then for lInc := 1 to lLen do lBHdr.generated[lInc] := lDicomData.modality[lInc];*) end; //Not anonymized //next: put TR into db_Name array lStr := 'TE='+floattostr(lDicomData.TE) +';sec='+realtostr(lDicomData.SecSinceMidnight,4); if not lAnonymize then lStr := lStr+';name='+lDicomData.PatientName[lInc] ; lLen := length(lStr); if lLen > 80 then lLen := 80; for lInc := 1 to lLen do lBHdr.descrip[lInc] := lStr[lInc];{80 spaces} lStr := lDicomData.ImageComments; lLen := length(lStr); if lLen > 24 then lLen := 24; //10=size of generated array for lInc := 1 to lLen do lBHdr.aux_file[lInc] := lStr[lInc];//up to 24 if lDICOMdata.XYZdim[4] > 1 then lBHdr.Dim[0] := 4 //4D Data June 2006 else lBHdr.Dim[0] := 3; lBHdr.Dim[1] := lDICOMdata.XYZdim[1]; lBHdr.Dim[2] := lDICOMdata.XYZdim[2]; lBHdr.Dim[3] := lDICOMdata.XYZdim[3]; lBHdr.Dim[4] := lDICOMdata.XYZdim[4]; lBHdr.pixdim[1]:= lDICOMdata.XYZmm[1]; lBHdr.pixdim[2]:= lDICOMdata.XYZmm[2]; lBHdr.pixdim[3]:= lDICOMdata.XYZmm[3]; lBHdr.pixdim[4] := lDicomData.TR/1000; //convert MS to second = assumes xyzt = 10 lBHdr.pixdim[7] := lDICOMdata.SecSinceMidnight; if lDICOMdata.IntenScale <> 0 then lBHdr.scl_slope := lDICOMdata.IntenScale else lBHdr.scl_slope := 1; if not specialsingle(lDICOMdata.IntenIntercept) then lBHdr.scl_inter := lDICOMdata.IntenIntercept //1406 else lBHdr.scl_inter := 0; lBHdr.bitpix := 8; //1360 lBHdr.datatype := 2; //1360 if lDicomData.Allocbits_per_pixel <> 8 then begin if lDicomData.Allocbits_per_pixel = 32 then begin lBHdr.bitpix := 32; if lDicomData.FloatData then lBHdr.datatype := 16 else lBHdr.datatype := 8; end else if lDicomData.Allocbits_per_pixel = 64 then begin lBHdr.bitpix := 64; lBHdr.datatype := 64; end else begin //16bits per pixel lBHdr.bitpix := 16; lBHdr.datatype := kDT_SIGNED_SHORT; if (not lDicomData.SignedData) and (lDicomData.Allocbits_per_pixel = 16) then begin lBHdr.datatype :=kDT_UINT16; //Msg('NII convert warning: unusual 16-bit UNsigned data format - may not be correctly recognized by all software.'); end; end; end; end; //proc DICOM2AnzHdr function NII_force32 (lSrcName,lDestName: string; lPrefs: TPrefs):string; var lPOs,lSrcOffset,lVol,lVox: integer; l32f : SingleP; l32is : LongIntP; l16is : SmallIntP; l8is,lSrcBuffer,lBuffUnaligned,lBuffAligned: bytep; lSrcHdr,lDestHdr: TNIFTIhdr; lOpts: TNIIOpts; begin result := ''; if not NIFTIhdr_LoadHdr (lSrcname, lSrcHdr, lOpts) then exit; case lSrcHdr.datatype of kDT_UNSIGNED_CHAR : ; kDT_SIGNED_SHORT: ; kDT_SIGNED_INT: ; kDT_FLOAT: begin dcmMsg('NII convert to 32-bit float error: datatype already 32-bit float.'); exit; end; else begin dcmMsg('NII convert to 32-bit float error: datatype not supported.'); exit; end; end; //case lDestHdr := lSrcHdr; //destination has the comments and voxel BPP of source //lDestHdr.dim[4] := 1; lDestHdr.datatype := kDT_FLOAT; lDestHdr.bitpix := 32; lVol := lDestHdr.Dim[4]; lVox := lDestHdr.Dim[1]*lDestHdr.Dim[2]*lDestHdr.Dim[3]*lVol; //load dataset if not NIFTIhdr_LoadImg (lSrcName, lSrcHdr, lSrcBuffer, lSrcOffset,lOpts) then exit; l8is := (@lSrcBuffer^[lSrcOffset+1]); GetMem(lBuffUnaligned ,(4*lVox) + 16+kNIIImgOffset); {$IFDEF FPC} lBuffAligned := Align(lBuffUnaligned,16); // not commented - check this {$ELSE} lBuffAligned := ByteP($fffffff0 and (integer(lBuffUnaligned)+15)); {$ENDIF} lPos := 1; l32f := SingleP(@lBuffAligned^[kNIIImgOffset+lPos] ); case lSrcHdr.datatype of kDT_SIGNED_SHORT: l16is := SmallIntP(l8is ); kDT_SIGNED_INT:l32is := LongIntP(l8is ); //kDT_FLOAT: l32fs := SingleP(l8is ); end; //case if lSrcHdr.datatype = kDT_UNSIGNED_CHAR then begin for lPos := 1 to lVox do l32f^[lPos] := l8is^[lPos]; end else if lSrcHdr.datatype = kDT_SIGNED_SHORT then begin for lPos := 1 to lVox do l32f^[lPos] := l16is^[lPos]; end else if lSrcHdr.datatype = kDT_SIGNED_INT then begin for lPos := 1 to lVox do l32f^[lPos] := l32is^[lPos]; end; result := SaveNIfTICore (lDestName, lBuffAligned, kNIIImgOffset+1, lDestHdr, lPrefs); Freemem(lBuffUnaligned); Freemem(lSrcBuffer); end; procedure MakeSym (var l32f: SingleP; var lHdr: TNIFTIhdr); var lHalf,lL,lLines,lH,lX,lOffset: integer; lV : single; begin lX := lHdr.Dim[1]; lHalf := lX div 2; //we will not touch middle voxel of odd data... lLines := lHdr.Dim[2]*lHdr.Dim[3]*lHdr.Dim[4]; if (lHalf < 1) or (lLines < 1) then exit; lOffset := 0; for lL := 1 to lLines do begin lOffset := lOffset + lX; for lH := 1 to lHalf do begin lV := (l32f^[lOffset+lH] + l32f^[lOffset+lX-lH+1]) / 2; l32f^[lOffset+lH] := lV; l32f^[lOffset+lX-lH+1] := lV; end; end; end; function Rescale_4Dtissuemaps (lSrcName,lDestName: string; lPrefs: TPrefs; lMakeSym: boolean):string; //takes 4D image where each volume is 8-bit tissue map, saves as 32-bit float, ensures that no voxel has more than kmax or less than kmin intensity const kMaxAllTissues = 0.99; kMinAllTissues = 0.50; //set to 0 to ignore //kMax= 0.85; //kMin = 0.000; var lScale,lSum: double; lV,lPOs,lSrcOffset,lVol,lVox: integer; l32fs,l32f : SingleP; l32is : LongIntP; l16is : SmallIntP; l8is,lSrcBuffer,lBuffUnaligned,lBuffAligned: bytep; lSrcHdr,lDestHdr: TNIFTIhdr; lOpts: TNIIOpts; lSumName: string; begin result := ''; if not NIFTIhdr_LoadHdr (lSrcname, lSrcHdr, lOpts) then exit; case lSrcHdr.datatype of kDT_UNSIGNED_CHAR : ; kDT_SIGNED_SHORT: ; kDT_SIGNED_INT: ; kDT_FLOAT: ; else begin dcmMsg('NII convert to 32-bit float error: datatype not supported.'); exit; end; end; //case lDestHdr := lSrcHdr; //destination has the comments and voxel BPP of source //lDestHdr.dim[4] := 1; lDestHdr.datatype := kDT_FLOAT; lDestHdr.bitpix := 32; lVol := lDestHdr.Dim[4]; lVox := lDestHdr.Dim[1]*lDestHdr.Dim[2]*lDestHdr.Dim[3]*lVol; //load dataset if not NIFTIhdr_LoadImg (lSrcName, lSrcHdr, lSrcBuffer, lSrcOffset,lOPts) then exit; l8is := (@lSrcBuffer^[lSrcOffset+1]); GetMem(lBuffUnaligned ,(4*lVox) + 16+kNIIImgOffset); {$IFDEF FPC} lBuffAligned := Align(lBuffUnaligned,16); // not commented - check this {$ELSE} lBuffAligned := ByteP($fffffff0 and (integer(lBuffUnaligned)+15)); {$ENDIF} lPos := 1; l32f := SingleP(@lBuffAligned^[kNIIImgOffset+lPos] ); case lSrcHdr.datatype of kDT_SIGNED_SHORT: l16is := SmallIntP(l8is ); kDT_SIGNED_INT:l32is := LongIntP(l8is ); kDT_FLOAT: l32fs := SingleP(l8is ); end; //case if lSrcHdr.datatype = kDT_UNSIGNED_CHAR then begin for lPos := 1 to lVox do l32f^[lPos] := l8is^[lPos]; end else if lSrcHdr.datatype = kDT_SIGNED_SHORT then begin for lPos := 1 to lVox do l32f^[lPos] := l16is^[lPos]; end else if lSrcHdr.datatype = kDT_SIGNED_INT then begin for lPos := 1 to lVox do l32f^[lPos] := l32is^[lPos]; end else if lSrcHdr.datatype = kDT_FLOAT then begin for lPos := 1 to lVox do l32f^[lPos] := l32fs^[lPos]; end; if lMakeSym then MakeSym (l32f,lDestHdr); //next - ensure that no voxel has sum probability more than kMaxAllTissues if lVol > 1 then begin //for 4D data... lVox := lDestHdr.Dim[1]*lDestHdr.Dim[2]*lDestHdr.Dim[3]; //this will be done in 3D, not 4D for lPos := 1 to lVox do begin lSum := 0; for lV := 1 to lVol do lSum := lSum+ l32f^[lPos + ((lV-1)*lVox )]; //lookup table could speed this up if (lSum < kMinAllTissues) and (kMinAllTissues > 0) then begin lScale := kMinAllTissues-lSum; //add to 5th volume (soft tissue - non-brain l32f^[lPos + ((5-1)*lVox )] := lScale + l32f^[lPos + ((5-1)*lVox )]; //lookup table could speed this up end else if lSum > kMaxAllTissues then begin lScale := (kMaxAllTissues/lSum); for lV := 1 to lVol do l32f^[lPos + ((lV-1)*lVox )] := lScale * l32f^[lPos + ((lV-1)*lVox )]; //lookup table could speed this up end; end; //each voxel end; //4D (*lVox := lDestHdr.Dim[1]*lDestHdr.Dim[2]*lDestHdr.Dim[3]*lVol; //next - ensure no voxel is more than kmax for lPos := 1 to lVox do if l32f^[lPos] > kMax then l32f^[lPos] := kMax; //next - ensure that no voxel is less than kmin for lPos := 1 to lVox do if l32f^[lPos] < kMin then l32f^[lPos] := kMin; *) result := SaveNIfTICore (lDestName, lBuffAligned, kNIIImgOffset+1, lDestHdr, lPrefs); //optional ... SumMap if lVol > 1 then begin //for 4D data... lVox := lDestHdr.Dim[1]*lDestHdr.Dim[2]*lDestHdr.Dim[3]; //this will be done in 3D, not 4D for lPos := 1 to lVox do begin lSum := 0; for lV := 1 to lVol do lSum := lSum+ l32f^[lPos + ((lV-1)*lVox )]; //lookup table could speed this up l32f^[lPos ] := lSum; //lookup table could speed this up end; //each voxel end; //4D lDestHdr.Dim[4] := 1; lSumName := ChangeFilePrefix (lDestName,'sum'); result := SaveNIfTICore (lSumName, lBuffAligned, kNIIImgOffset+1, lDestHdr, lPrefs); //... end SumMap Freemem(lBuffUnaligned); Freemem(lSrcBuffer); end; function SumTPM (lSrcName,lDestName: string; lPrefs: TPrefs; lTissueTypes2Average: integer):string; //Sum of first three tissue types (GM, WM, CSF var //lScale,lSum: double; lPOs,lSrcOffset,lVol,lVox,lnVol: integer; l32fs,l32f : SingleP; l32is : LongIntP; l16is : SmallIntP; l8is,lSrcBuffer,lBuffUnaligned,lBuffAligned: bytep; lSrcHdr,lDestHdr: TNIFTIhdr; lOpts: TNIIOpts; //lSumName: string; begin result := ''; if not NIFTIhdr_LoadHdr (lSrcname, lSrcHdr, lOpts) then exit; case lSrcHdr.datatype of kDT_UNSIGNED_CHAR,kDT_SIGNED_SHORT,kDT_SIGNED_INT,kDT_FLOAT: ; else begin dcmMsg('SumTPM error: datatype not supported.'); exit; end; end; //case lDestHdr := lSrcHdr; //destination has the comments and voxel BPP of source lDestHdr.datatype := kDT_FLOAT; lDestHdr.bitpix := 32; lDestHdr.Dim[4] := 1; lVox := lDestHdr.Dim[1]*lDestHdr.Dim[2]*lDestHdr.Dim[3]; //load dataset if not NIFTIhdr_LoadImg (lSrcName, lSrcHdr, lSrcBuffer, lSrcOffset,lOpts) then exit; l8is := (@lSrcBuffer^[lSrcOffset+1]); lnVol := NonspatialDimensionsNII(lSrcHdr); if lnVol > lTissueTypes2Average then lnVol := lTissueTypes2Average; if lnVol < 1 then exit; GetMem(lBuffUnaligned ,(4*lVox) + 16+kNIIImgOffset); {$IFDEF FPC} lBuffAligned := Align(lBuffUnaligned,16); // not commented - check this {$ELSE} lBuffAligned := ByteP($fffffff0 and (integer(lBuffUnaligned)+15)); {$ENDIF} lPos := 1; l32f := SingleP(@lBuffAligned^[kNIIImgOffset+lPos] ); for lPos := 1 to lVox do l32f^[lPos] := 0; if lSrcHdr.datatype = kDT_UNSIGNED_CHAR then begin for lVol := 0 to lnVol -1 do for lPos := 1 to lVox do l32f^[lPos] := l32f^[lPos]+l8is^[lPos+(lVol*lVox)]; end else if lSrcHdr.datatype = kDT_SIGNED_SHORT then begin l16is := SmallIntP(l8is ); for lVol := 0 to lnVol -1 do for lPos := 1 to lVox do l32f^[lPos] := l32f^[lPos]+l16is^[lPos+(lVol*lVox)]; end else if lSrcHdr.datatype = kDT_SIGNED_INT then begin l32is := LongIntP(l8is ); for lVol := 0 to lnVol -1 do for lPos := 1 to lVox do l32f^[lPos] := l32f^[lPos]+l32is^[lPos+(lVol*lVox)]; end else if lSrcHdr.datatype = kDT_FLOAT then begin l32fs := SingleP(l8is ); for lVol := 0 to lnVol -1 do for lPos := 1 to lVox do l32f^[lPos] := l32f^[lPos]+l32fs^[lPos+(lVol*lVox)]; end; result := SaveNIfTICore (lDestName, lBuffAligned, kNIIImgOffset+1, lDestHdr, lPrefs); lDestHdr.Dim[4] := 1; //result := SaveNIfTICore (lSumName, lBuffAligned, kNIIImgOffset+1, lDestHdr, lPrefs,lByteSwap); //... end SumMap Freemem(lBuffUnaligned); Freemem(lSrcBuffer); end; function SameHdrDim (lAHdr,lBHdr: TNIFTIhdr; lCheck4D, lCheckDataType: boolean): boolean; var i: integer; begin result := true; if (lCheckDataType) and (lAHdr.datatype <> lBHdr.datatype) then result := false; for i := 1 to 3 do if (lAHdr.Dim[i] <> lBHdr.Dim[i]) then result := false; for i := 1 to 3 do if (lAHdr.pixdim[i] <> lBHdr.pixdim[i]) then result := false; if lCheck4D then if (lAHdr.Dim[4] <> lBHdr.Dim[4]) then result := false; if not result then begin //fx(1211); dcmMsg('Image dimensions or datatype differ'); end; end; function Merge4DFiles (lLowSliceName,lHighSliceName,lDestName: string; lNumberofLowSlicesToCopy: integer; lPrefs: TPrefs):string; //takes 4D image where each volume is 8-bit tissue map, saves as 32-bit float, ensures that no voxel has more than kmax or less than kmin intensity var lVolOffset,lSliceBytes,lV,lLoOffset,lHiOffset,lVol,lVox: integer; l8iHi,l8iLo,lLoBuffer,lHiBuffer {,lBuffUnaligned,lBuffAligned}: bytep; lLoHdr,lHiHdr: TNIFTIhdr; lOptsLo,lOptsHi: TNIIOpts; lBPP: integer; begin result := ''; if not NIFTIhdr_LoadHdr (lLowSliceName, lLoHdr, lOptsLo) then exit; if not NIFTIhdr_LoadHdr (lHighSliceName, lHiHdr, lOptsHi) then exit; if lNumberofLowSlicesToCopy < 1 then exit; if not SameHdrDim(lLoHdr, lHiHdr,true,true) then exit; case lLoHdr.datatype of kDT_UNSIGNED_CHAR : lBPP := 1; kDT_SIGNED_SHORT: lBPP := 2; kDT_SIGNED_INT:lBPP := 4; kDT_FLOAT: lBPP := 4; else begin dcmMsg('Merge4DFiles error: datatype not supported.'); exit; end; end; //case //lDestHdr.dim[4] := 1; lVol := lHiHdr.Dim[4]; lSliceBytes:= lHiHdr.Dim[1]*lHiHdr.Dim[2] * lBPP; //load dataset if not NIFTIhdr_LoadImg (lLowSliceName, lLoHdr, lLoBuffer, lLoOffset,lOptsLo) then exit; if not NIFTIhdr_loadImg (lHighSliceName, lhiHdr, lhiBuffer, lhiOffset,lOptsHi) then exit; l8iLo := (@lLoBuffer^[lLoOffset+1]); l8iHi := (@lHiBuffer^[lHiOffset+1]); for lV := 1 to lVol do begin lVolOffset := (lV - 1) * (lSliceBytes*lHiHdr.Dim[3]); for lVox := 1 to (lSliceBytes*lNumberofLowSlicesToCopy) do l8iHi^[lVox+lVolOffset] := l8iLo^[lVox+lVolOffset]; end; result := SaveNIfTICore (lDestName, lhiBuffer, kNIIImgOffset+1, lHiHdr, lPrefs); Freemem(lhiBuffer); Freemem(lloBuffer); end; function Insert3Din4D (l3DSliceName,l4DSliceName,lDestName: string; lVol2Copy: integer; lPrefs: TPrefs):string; //takes 4D image where each volume is 8-bit tissue map, saves as 32-bit float, ensures that no voxel has more than kmax or less than kmin intensity var lVolOffset,lVolBytes,l3DOffset,l4DOffset,lVox: integer; l8i4D,l8i3D,l3DBuffer,l4DBuffer {,lBuffUnaligned,lBuffAligned}: bytep; l3DHdr,l4DHdr: TNIFTIhdr; lOpts3D,lOpts4D: TNIIOpts; lBPP: integer; begin result := ''; if not NIFTIhdr_LoadHdr (l3DSliceName, l3DHdr, lOpts3D) then exit; if not NIFTIhdr_LoadHdr (l4DSliceName, l4DHdr, lOpts4D) then exit; if lVol2Copy < 1 then exit; if not SameHdrDim(l3DHdr, l4DHdr,false,true) then exit; case l3DHdr.datatype of kDT_UNSIGNED_CHAR : lBPP := 1; kDT_SIGNED_SHORT: lBPP := 2; kDT_SIGNED_INT:lBPP := 4; kDT_FLOAT: lBPP := 4; else begin dcmMsg('Merge4DFiles error: datatype not supported.'); exit; end; end; //case //lDestHdr.dim[4] := 1; // lVol := l4DHdr.Dim[4]; lVolBytes:= l4DHdr.Dim[1]*l4DHdr.Dim[2]*l4DHdr.Dim[3]* lBPP; //load dataset if not NIFTIhdr_LoadImg (l3DSliceName, l3DHdr, l3DBuffer, l3DOffset,lOpts3D) then exit; if not NIFTIhdr_loadImg (l4DSliceName, l4DHdr, l4DBuffer, l4DOffset,lOpts4D) then exit; l8i3D := (@l3DBuffer^[l3DOffset+1]); l8i4D := (@l4DBuffer^[l4DOffset+1]); lVolOffset := (lVol2Copy - 1) * (lVolBytes); for lVox := 1 to (lVolBytes) do l8i4D^[lVox+lVolOffset] := l8i3D^[lVox]; result := SaveNIfTICore (lDestName, l4DBuffer, kNIIImgOffset+1, l4DHdr, lPrefs); Freemem(l4DBuffer); Freemem(l3DBuffer); end; function NIFTIhdr_LoadImg8bit (var lSrcName: string; var lSrcHdr: TNIFTIHdr; var lSrcBuffer: bytep; var lSrcOffset: integer; var lOPts: TNIIOPts): boolean; begin result := false; if not NIFTIhdr_LoadImg (lSrcName, lSrcHdr, lSrcBuffer, lSrcOffset,lOpts) then exit; if lSrcHdr.datatype <> kDT_UNSIGNED_CHAR then begin dcmMsg('Only able to read 8-bit data.'); exit; end; //NIFTIhdr_UnswapImg(lSrcHdr, lSrcBuffer, lSrcOffset,lByteSwap);//interpolation requires data is in native endian result := true; end; function MaskImages(lMaskName: string; lFiles: TStrings; lPrefs: TPrefs; lVol: integer; lSaveThresh: boolean): string; var lFileOffset,lMaskOffset,lInc,lVox,lPos,lOK: integer; lMaskHdr,lFileHdr: TNIFTIHdr; lMaskOpts,lFileOpts: TNIIOpts; lFilename: string; lMaskBuffer,lFileBuffer,l8if: bytep; l32fm,l32fmean, l32fmeanpre: singlep; begin result := ''; if not NIFTIhdr_LoadHdr (lMaskName, lMaskHdr, lMaskOpts) then exit; if lMaskHdr.datatype <> kDT_FLOAT then begin dcmMsg('This function only works with 32-bit float data.'); exit; end; lVox := lMaskHdr.Dim[1]*lMaskHdr.Dim[2]*lMaskHdr.Dim[3]; if lFiles.Count < 1 then exit; if not NIFTIhdr_LoadImg (lMaskName, lMaskHdr, lMaskBuffer, lMaskOffset,lMaskOpts) then exit; l32fm := SingleP(@lMaskBuffer^[lMaskOffset+1+ ((lVol-1)* (lVox*4) )]); //l32fo := SingleP(@lBuffAligned^[kNIIImgOffset+lPos] ); GetMem(l32fmean ,(4*lVox)); for lPos := 1 to lVox do l32fmean^[lPos] := 0; GetMem(l32fmeanpre ,(4*lVox)); for lPos := 1 to lVox do l32fmeanpre^[lPos] := 0; lOK := 0; for lInc := 1 to lFiles.Count do begin lFilename := lFiles.Strings[lInc-1]; if not NIFTIhdr_LoadImg8bit (lFileName, lFileHdr, lFilebuffer, lFileOffset,lFileOpts) then begin dcmMsg('Serious error reading '+lFilename); exit; end; if not (SameHdrDim(lMaskHdr,lFileHdr,false,false)) then //fx(666) //msg('This function only works with data with identical dimensions.') else begin l8if := (@lFilebuffer^[lFileOffset+1]); for lPos := 1 to lVox do begin l32fmeanpre^[lPos] := l32fmeanpre^[lPos] + l8if^[lPos]; if l32fm^[lPos] = 0 then l8if^[lPos] := 0 else l32fmean^[lPos] := l32fmean^[lPos] + l8if^[lPos]; end; lFilename := ChangeFilePrefix (lFilename,'z'); if lSaveThresh then result := SaveNIfTICore (lFilename, lFileBuffer, lFileOffset+1, lFileHdr, lPrefs); inc(lOK); end; Freemem(lFilebuffer); end; if lOK > 1 then begin lMaskHdr.dim[4] := 1; //save only one volume lMaskHdr.scl_slope := lFileHdr.scl_slope; lMaskHdr.scl_inter := lFileHdr.scl_inter; l32fm := SingleP(@lMaskBuffer^[lMaskOffset+1]); for lPos := 1 to lVox do l32fm^[lPos] := l32fmean^[lPos]/lOK; lFilename := ChangeFilePrefix (lMaskName,'mean'+inttostr(lVol)); result := SaveNIfTICore (lFilename, lMaskBuffer, lMaskOffset+1, lMaskHdr, lPrefs); for lPos := 1 to lVox do l32fm^[lPos] := l32fmeanpre^[lPos]/lOK; lFilename := ChangeFilePrefix (lMaskName,'meanpre'+inttostr(lVol)); result := SaveNIfTICore (lFilename, lMaskBuffer, lMaskOffset+1, lMaskHdr, lPrefs); end; Freemem(l32fmean); Freemem(lMaskBuffer); end; function lDigitChar (lString: string): integer; //returns position of first number in filename, e.g. c:\x1xx.nii would return 5, since '1' is 5th char var lP, lLen: integer; begin result := 0; lLen := length(lString); if lLen < 1 then exit; for lP := lLen downto 1 do begin if lString[lP] in ['0'..'9'] then result := lP; if lString[lP] in ['/','\'] then exit; end; end; function Binarize(lC1Name: string; lPrefs: TPrefs ): string; const kMaps = 5; kInten: array [1.. kMaps] of integer = ({graymatter}4,{whitematter}5,{csf}3,{bone}2,{soft tissue}1); var //lFileOffset,lMaskOffset,lInc,lVox,lPos,lOK: integer; lHname : array [1..kMaps] of string; lH: array [1..kMaps] of TNIFTIHdr; lMax,lMaxV,lV,lVox,lMap,lCharPos: integer; lHOpts: TNIIOpts; //lFilename: string; lHBuffer,lH8i: array [1..kMaps] of bytep; lHOffset: array [1..kMaps] of integer; //l32fm,l32fmean, l32fmeanpre: singlep; begin result := ''; lCharPos := lDigitChar (lC1Name); if lCharPos < 1 then begin dcmMsg('Error: number should be in filename.'); exit; end; for lMap := 1 to kMaps do begin lHname[lMap] := lC1Name; lHname[lMap][lCharPos] := inttostr(lMap)[1]; if not fileexists(lHname[lMap]) then begin dcmMsg('Can not find '+lHname[lMap]); exit; end; end; for lMap := 1 to kMaps do begin if not NIFTIhdr_LoadImg8bit (lHname[lMap], lH[lMap], lHBuffer[lMap], lHOffset[lMap],lHOpts) then begin dcmMsg('Serious error reading '+lHname[lMap]); exit; end; lH8i[lMap] := (@lHBuffer[lMap]^[lHOffset[lMap]+1]); end; lVox := lH[1].Dim[1]*lH[1].Dim[2]*lH[1].Dim[3]; (*for lV := 1 to lVox do begin lMax := lH8i[4]^[lV] * 2; if lMax > 1 {255} then lMax := 255; lH8i[4]^[lV] := 255; end; *) for lV := 1 to lVox do begin lMax := kMaps; lMaxV := lH8i[kMaps]^[lV]; for lMap := (kMaps-1) downto 1 do begin if lH8i[lMap]^[lV] > lMaxV then begin lMax := lMap; lMaxV := lH8i[lMap]^[lV]; end; end; lMax := kInten[lMax]; //if lMax = kMaps then lMax := 0; if lMaxV < 25 then lMax := 0; lH8i[1]^[lV] := lMax; end; lH[1].dim[4] := 1; //save only one volume lH[1].scl_slope := 1; lH[1].scl_inter := 0; lHname[1][lCharPos] := 'b'; result := SaveNIfTICore (lHname[1], lHBuffer[1], lHOffset[1]+1, lH[1], lPrefs); for lMap := 1 to kMaps do Freemem(lHBuffer[lMap]); end; (*function NIFTIhdr_LoadImgAs32float (var lSrcName: string; var lSrcHdr: TNIFTIHdr; var lSrcBuffer: bytep; var l32f: singlep; var lSrcOffset: integer; var lByteSwap: boolean): boolean; //function NIFTIhdr_LoadImgAs32float (var lSrcName: string; var lSrcHdr: TNIFTIHdr; {var lSrcBuffer: bytep;} var l32f: singlep; var lSrcOffset: integer; var lByteSwap: boolean): boolean; var l32is : LongIntP; l16is : SmallIntP; lImgBuffer,l8is: bytep; lPos,lVox: integer; //lSrcBuffer: bytep; begin result := false; if not NIFTIhdr_LoadImg (lSrcName, lSrcHdr, lImgBuffer, lSrcOffset,lByteSwap) then exit; NIFTIhdr_UnswapImg(lSrcHdr, lImgBuffer, lSrcOffset,lByteSwap);//interpolation requires data is in native endian result := true; l8is := (@lImgBuffer^[lSrcOffset+1]); //GetMem(l32f ,4*lVox ); case lSrcHdr.datatype of kDT_SIGNED_SHORT: l16is := SmallIntP(l8is ); kDT_SIGNED_INT:l32is := LongIntP(l8is ); kDT_FLOAT: begin l32f := SingleP(l8is ); lSrcBuffer := lImgBuffer; {<- not sure if this works!} exit; end; end; //case lVox := lSrcHdr.Dim[1]*lSrcHdr.Dim[2]*lSrcHdr.Dim[3]; GetMem(lSrcBuffer ,(4*lVox) +lSrcOffset); l32f := SingleP(@lSrcBuffer^[lSrcOffset+1]); if lSrcHdr.datatype = kDT_UNSIGNED_CHAR then for lPos := 1 to lVox do l32f^[lPos] := l8is^[lPos] else if lSrcHdr.datatype = kDT_SIGNED_SHORT then for lPos := 1 to lVox do l32f^[lPos] := l16is^[lPos] else if lSrcHdr.datatype = kDT_SIGNED_INT then for lPos := 1 to lVox do l32f^[lPos] := l32is^[lPos]; result := true; freemem(lImgBuffer); lSrcHdr.datatype := kDT_FLOAT; end; *) function As32 (lSrcName: string; var lSrcHdr:TNIFTIhdr; var l32f: singlep):boolean; //takes 4D image where each volume is 8-bit tissue map, saves as 32-bit float, ensures that no voxel has more than kmax or less than kmin intensity var (* lScale,lSum: double; lV,lPOs,lSrcOffset,lVol,lVox: integer; l32fs,l32f : SingleP; l32is : LongIntP; l16is : SmallIntP; l8is,lSrcBuffer,lBuffUnaligned,lBuffAligned: bytep; lSrcHdr,lDestHdr: TNIFTIhdr; *) l32is : LongIntP; l32fs : SingleP; l16is : SmallIntP; l8is,lSrcBuffer: bytep; lSrcOffset,lVox,lPos: integer; lOpts: TNIIOpts; begin result := false; if not NIFTIhdr_LoadHdr (lSrcname, lSrcHdr, lOpts) then exit; case lSrcHdr.datatype of kDT_UNSIGNED_CHAR : ; kDT_SIGNED_SHORT: ; kDT_SIGNED_INT: ; kDT_FLOAT: ; else begin dcmMsg('NII convert to 32-bit float error: datatype not supported.'); exit; end; end; //case lVox := lSrcHdr.Dim[1]*lSrcHdr.Dim[2]*lSrcHdr.Dim[3]; //load dataset if not NIFTIhdr_LoadImg (lSrcName, lSrcHdr, lSrcBuffer, lSrcOffset,lOpts) then exit; l8is := (@lSrcBuffer^[lSrcOffset+1]); GetMem(l32f ,lVox * sizeof(single)); //lPos := 1; case lSrcHdr.datatype of kDT_SIGNED_SHORT: l16is := SmallIntP(l8is ); kDT_SIGNED_INT:l32is := LongIntP(l8is ); kDT_FLOAT: l32fs := SingleP(l8is ); end; //case if lSrcHdr.datatype = kDT_UNSIGNED_CHAR then begin for lPos := 1 to lVox do l32f^[lPos] := l8is^[lPos]; end else if lSrcHdr.datatype = kDT_SIGNED_SHORT then begin for lPos := 1 to lVox do l32f^[lPos] := l16is^[lPos]; end else if lSrcHdr.datatype = kDT_SIGNED_INT then begin for lPos := 1 to lVox do l32f^[lPos] := l32is^[lPos]; end else if lSrcHdr.datatype = kDT_FLOAT then begin for lPos := 1 to lVox do l32f^[lPos] := l32fs^[lPos]; for lPos := 1 to lVox do if specialsingle(l32f^[lPos]) then l32f^[lPos] := 0; end; freemem(lSrcBuffer); result := true; end; //function MaskImgs(lC1template, lC1source: string; lPrefs: TPrefs ; lThresh: integer): string; function MaskImg(ltemplate, lsource: string; lPrefs: TPrefs; lThresh: single ): string; label 666; var lH,lT: TNIFTIHdr; lV,lVox,lHOffset: integer; lHOpts: TNIIOpts; l32fs : SingleP; l8is,lHBuffer: bytep; lOutname: string; begin result := ''; if (not fileexists(lsource)) then begin dcmMsg('Can not find '+ lsource); exit; end; if (not fileexists(ltemplate)) then begin dcmMsg('Can not find '+ ltemplate); exit; end; //if not NIFTIhdr_LoadImgAs32float (lsource, lH, lHBuffer, lHOffset,lHSwap) then begin if not NIFTIhdr_LoadImg8bit (lsource, lH, lHBuffer, lHOffset,lHOpts) then begin dcmMsg('Serious error reading '+lsource); exit; end; //function NIFTIhdr_LoadImgAs32float (var lSrcName: string; var lSrcHdr: TNIFTIHdr; var lSrcBuffer: bytep; var l32f: singlep; var lSrcOffset: integer; var lByteSwap: boolean): boolean; if not As32 (ltemplate, lT, l32fs) then begin dcmMsg('Serious error reading '+ltemplate); exit; end; lVox := lH.Dim[1]*lH.Dim[2]*lH.Dim[3]; if not SameHdrDim (lH,lT, false, false) then begin dcmMsg('Image dimensions do not match: '+ltemplate+' <> '+lsource); goto 666; end; l8is := (@lHBuffer^[lHOffset+1]); for lV := 1 to lVox do if (l32fs^[lV] < lThresh) then l8is^[lV] := 0; lH.dim[4] := 1; //save only one volume lH.scl_slope := 1; lH.scl_inter := 0; lOutname := ChangeFilePrefix(lsource,'m'); dcmMsg(lsource +' masked with '+ltemplate +' = '+lOutname); result := SaveNIfTICore (loutname, lHBuffer, lHOffset+1, lH, lPrefs); 666: Freemem(l32fs); Freemem(lHBuffer); end; function MaskImgs(lC1template, lC1source: string; lPrefs: TPrefs ; lThresh: single): string; const kMaps = 5; var lTName,lSName: string; lMap,lSPos,lTPos: integer; begin result := ''; lSPos := lDigitChar (lC1source); lTPos := lDigitChar (lC1template); if (lSPos < 1) or (lTPos < 1) then begin dcmMsg('Error: number should be in filenames: '+lC1template+' '+ lC1source); exit; end; lSname:= lC1source; lTname:= lC1template; for lMap := 1 to kMaps do begin lSname[lSPos] := inttostr(lMap)[1]; lTname[lTPos] := inttostr(lMap)[1]; //msg(lTName+' '+ lSName); if ( fileexists(lTName)) and ( fileexists(lSName)) then result := MaskImg(lTName, lSName, lPrefs, lThresh) ; end; dcmMsg('Masking completed'); end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/gui.lfm����������������������������������������������������0000755�0001750�0001750�00000006773�12204746342�017035� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object MainForm: TMainForm Left = 355 Height = 363 Top = 132 Width = 598 ActiveControl = Panel1 AllowDropFiles = True Caption = 'dcm2nii' ClientHeight = 363 ClientWidth = 598 Menu = MainMenu1 OnClose = FormClose OnCreate = FormCreate OnDropFiles = FormDropFiles OnShow = FormShow LCLVersion = '1.0.2.0' object Memo1: TMemo Left = 4 Height = 325 Top = 34 Width = 590 Align = alClient BorderSpacing.Left = 4 BorderSpacing.Right = 4 BorderSpacing.Bottom = 4 ScrollBars = ssAutoVertical TabOrder = 0 end object Panel1: TPanel Left = 0 Height = 34 Top = 0 Width = 598 Align = alTop BevelOuter = bvNone ClientHeight = 34 ClientWidth = 598 TabOrder = 1 object Label1: TLabel Left = 1 Height = 26 Top = 5 Width = 140 Alignment = taRightJustify Anchors = [akLeft] AutoSize = False Caption = 'Output Format: ' Layout = tlCenter ParentColor = False end object TypeCombo: TComboBox Left = 160 Height = 20 Top = 3 Width = 264 ItemHeight = 0 Items.Strings = ( 'SPM2 (3D Anlyze hdr/img)' 'SPM5 (3D NIfTI hdr/img)' 'SPM8 (3D NIfTI nii)' '4D NIfTI hdr/img' 'FSL/SPM8 (4D NIfTI nii)' 'Compressed FSL (4D NIfTI nii)' ) Style = csDropDownList TabOrder = 0 end end object OpenHdrDlg: TOpenDialog FilterIndex = 0 left = 24 top = 48 end object MainMenu1: TMainMenu left = 88 top = 48 object File1: TMenuItem Caption = 'File' object DICOMtoNIfTI1: TMenuItem Caption = 'DICOM to NIfTI' ShortCut = 16452 OnClick = dcm2niiBtnClick end object ModifyNIfTI1: TMenuItem Caption = 'Modify NIfTI' OnClick = ModifyNIfTI1Click end object NIfTI3D4D1: TMenuItem Caption = 'NIfTI 3D -> 4D' OnClick = NIfTI3D4D1Click end object AnonymizeDICOM1: TMenuItem Caption = 'Anonymize DICOM' OnClick = AnonymizeDICOM1Click end object Exit1: TMenuItem Caption = 'Exit' OnClick = Exit1Click end end object Edit1: TMenuItem Caption = 'Edit' object Copy1: TMenuItem Caption = 'Copy' OnClick = Copy1Click end end object UntestedMenu: TMenuItem Caption = 'Untested' object MirrorXdimension1: TMenuItem Caption = 'Mirror X-dimension' OnClick = MirrorXdimension1Click end object SumTPM1: TMenuItem Caption = 'Sum TPM' OnClick = SumTPM1Click end object ExtractDICOMdims1: TMenuItem Caption = 'Extract DICOM dims' OnClick = ExtractDICOMdims1Click end object ExtractDICOMhdr1: TMenuItem Caption = 'Extract DICOM header' OnClick = ExtractDICOMhdr1Click end object ExtractNIfTIhdrs1: TMenuItem Caption = 'Extract NIfTI header' OnClick = ExtractNIfTIhdrs1Click end object HalveMenu1: TMenuItem Caption = 'Halve dimensions in-plane' OnClick = HalveMenu1Click end end object Help1: TMenuItem Caption = 'Help' object Preferences1: TMenuItem Caption = 'Preferences' OnClick = Preferences1Click end object About1: TMenuItem Caption = 'Help' OnClick = About1Click end end end object SelectDirectoryDialog1: TSelectDirectoryDialog left = 159 top = 54 end end �����mricron-0.20140804.1~dfsg.1.orig/dcm2nii/dicomfast.pas����������������������������������������������0000755�0001750�0001750�00000046465�12204716236�020230� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit dicomfast; {$H+} //this is x3 faster than the dicomcompat routines, but only works with well-behaved Explicit Little-Endian DICOM interface //0008,0070,ManufacturerID //Next values for Philips //Philips - must set 2001,105F length to 8 - allows reading of stack sequence // 2005,1071. Philips AP angulation // 2005,1072. Philips RL angulation // 2005,1073. Philips FH angulation //2001,100B Philips slice orientation (TRANSVERSAL, AXIAL, SAGITTAL) // Next values for GE //0019,10bb (or 0019,a0bb)= X diffusion direction //0019,10bc (or 0019,a0bc)= Y diffusion direction //0019,10bd (or 0019,a0bd)= Z diffusion direction //0018,1312 = phase encoding. uses {$IFNDEF FPC}Controls, {$ENDIF} SysUtils,define_types,classes,dicomtypes,dialogs_msg; function fast_read_dicom_data(var lDICOMdata: DICOMdata; lOffset: integer; var lFileName: string): boolean; //x3 faster! implementation uses dialogsx; {$DEFINE ANON} function fast_read_dicom_data(var lDICOMdata: DICOMdata; lOffset: integer; var lFileName: string): boolean; label 999; const kMaxBuf = (256*256)-1; //bytes kMax16bit = (256*256)-1; kImageType = $0008+($0008 shl 16 ); kStudyDate = $0008+($0020 shl 16 ); kSeriesDate = $0008+($0021 shl 16 ); kAcqDate = $0008+($0022 shl 16 ); kCreateDate = $0008+($0012 shl 16 ); kStudyTime = $0008+($0030 shl 16 ); kPatientName = $0010+($0010 shl 16 ); {$IFDEF ANON} //position and lengths of tags to anonymize kPatientID = $0010+($0020 shl 16 ); kPatientDOB = $0010+($0030 shl 16 ); kPatientSex = $0010+($0040 shl 16 ); kPatientAge = $0010+($1010 shl 16 ); kPatientWt = $0010+($1030 shl 16 ); {$ENDIF} kSeq = $0018+($0020 shl 16 ); kZThick = $0018+($0050 shl 16 ); kTR = $0018+($0080 shl 16 ); kTE = $0018+($0081 shl 16 ); kEchoNum = $0018+($0086 shl 16 ); kZSpacing = $0018+($0088 shl 16 ); kProtocolName = $0018+($1030shl 16 ); kPatientPos = $0018+($5100 shl 16 ); kSeriesNum = $0020+($0011 shl 16 ); kAcquNum = $0020+($0012 shl 16 ); kImageNum = $0020+($0013 shl 16 ); kOrientation = $0020+($0037 shl 16 ); kLocation = $0020+($1041 shl 16 ); kDim3 = $0028+($0008 shl 16 ); kDim2 = $0028+($0010 shl 16 ); kDim1 = $0028+($0011 shl 16 ); kXYSpacing = $0028+($0030 shl 16 ); kPosition = $0020+($0032 shl 16 ); knVol = $0020+($0105 shl 16 ); kAlloc = $0028+($0100 shl 16 ); kIntercept = $0028+($1052 shl 16 ); kSlope = $0028+($1053 shl 16 ); kCSAImageHeaderInfo = $0029+($1010 shl 16 ); kSlicesPer3DVol = $2001+($1018 shl 16 ); kTransferSyntax = $0002+($0010 shl 16); kImageStart = $7FE0+($0010 shl 16 ); kMaxFloats = 6; var vr : array [1..2] of Char; lFailure: boolean; lByteRA: Bytep; lFloatRA: array [1..kMaxFloats] of double; lBufferSz,lPos,lFileSz,lBuffStart: integer; lInFile: file; lBufferError: boolean; procedure Str2FloatNum ( lStr: string; lnFloats: integer); var lFStr: string; lP,lnF: integer; begin if (length(lStr) < 1) or (lnFloats < 1) or (lnFloats > kMaxFloats) then exit; for lnF := 1 to lnFloats do lFloatRA[lnF] := 1; lStr := lStr + ' '; //terminator lFStr := ''; lP := 1; lnF:= 0; while lP <= length(lStr) do begin if lStr[lP] in ['+','-','0'..'9','.','e','E'] then lFStr := lFStr + lStr[lP] else if (lFStr <> '') then begin inc(lnF); //if lnFloats = 6 then showmessage(lFStr); try lFloatRA[lnF] := strtofloat(lFStr); except on EConvertError do lFloatRA[lnF] := 1; end;//except if lnF = lnFloats then exit; lFStr := ''; end; inc(lP); end; end; //function Str2Float function GetByte (lFilePos: integer): byte; var lBufPos: integer; begin //the following error checking slows down reads a lot! //a simpler alternative would be to make the buffer size the same size as the entire image... //the current strategy saves memory and is faster for large images with small headers if lFilepos > lFileSz then begin lBufferError := true; result := 0; exit; end; lBufPos := lFilepos - lBuffStart+1; if (lBufPos > lBufferSz) or (lBufPos < 1) then begin //reload buffer if (lFilePos < 0) or (lFilePos > lFileSz) then begin lBuffStart := lFilePos; lBufPos := 1; dcmMsg(lFileName); lFailure := true; dcmMsg('Error: buffer overrun in DICOM read.'); exit; end; if lFilePos+kMaxBuf > lFileSz then lBufferSz := lFileSz - (lFilePos) else lBufferSz := kMaxBuf; //read remaining //fx(lFilepos,kMaxBuf); AssignFile(lInFile, lFileName); FileMode := 0; //Set file access to read only Reset(lInFile, 1); seek(lInFile,lFilePos); BlockRead(lInFile, lByteRA^[1], lBufferSz); CloseFile(lInFile); FileMode := 2; lBuffStart := lFilePos; lBufPos := 1; end; result := lByteRA^[lBufPos]; end; function ReadInt4: integer; begin if lDicomData.little_endian = 0 then result := GetByte(lPos+3)+(GetByte(lPos+2) shl 8)+(GetByte(lPos+1) shl 16)+(GetByte(lPos) shl 24) else result := GetByte(lPos)+(GetByte(lPos+1) shl 8)+(GetByte(lPos+2) shl 16)+(GetByte(lPos+3) shl 24); inc(lPos,4); end; //function Read4 procedure ReadGroupElementLength(var lGroupElement,lLength: integer); begin lGroupElement := ReadInt4; vr[1] := chr(GetByte(lPos)); vr[2] := chr(GetByte(lPos+1)); //msg(' '+InttoHex(lGroupElement,8)+' '+inttostr(lLength)+' '+VR+ inttostr(GetByte(lPos+2))); if (vr[2] < 'A') then begin //implicit vr with 32-bit length lLength := ReadInt4; exit; end; //if vr = 'UN' then if (vr = 'OB') or (vr = 'OW') or (vr = 'SQ') or (vr = 'UN') then begin {explicit VR with 32-bit length} lPos := lPos + 4; {skip 2 byte string and 2 reserved bytes = 4 bytes = 2 words} lLength := ReadInt4;//Ord4(buf[lPos]) + $100 * (buf[lPos+1] + $100 * (buf[lPos+2] + $100 * buf[lPos+3])) end else begin {explicit VR with 16-bit length} if lDicomData.little_endian = 0 then lLength := (GetByte(lPos+3))+(GetByte(lPos+2) shl 8) else lLength := (GetByte(lPos+2))+(GetByte(lPos+3) shl 8);//GetLength := Ord4(buf[i+2]) + $100 * (buf[i+3]); lPos := lPos + 4; {skip 2 byte string and 2 length bytes = 4 bytes = 2 words} end; // msg(InttoHex(lGroupElement,8)+' '+inttostr(lLength)+' '+VR+ inttostr(GetByte(lPos+2)) + 'x'+inttostr(GetByte(lPos+3)) ); end; //procedure ReadGroupElementLength function DCMStr(lBytes: integer): string; var lC: integer; begin result := ''; if lBytes < 1 then exit; for lC := lPos to (lPos+(lBytes-1)) do result := result + char(GetByte(lC)); for lC := 1 to lBytes do if result[lC] in ['+','-','/','\',' ','0'..'9','a'..'z','A'..'Z','.'] then else result[lC] := ' '; end; //function DCMStr function DCMStr2Int (lBytes: integer): integer; var lErr: integer; lStr: string; begin lStr := DCMStr(lBytes); Val(lStr,result,lErr); end; //function DCMStr2Int procedure DCMStr2FloatNum (lBytes,lnFloats: integer); begin Str2FloatNum (DCMStr(lBytes), lnFloats); end; //function DCMStr2Float function DCMStr2Float (lBytes: integer): single; begin DCMStr2FloatNum (lBytes,1); result := lFloatRA[1]; end; //function DCMStr2Float procedure DCMStr2Float2 (lBytes: integer; var lF1,lF2: double); begin DCMStr2FloatNum (lBytes,3); lF1 := lFloatRA[1]; lF2 := lFloatRA[2]; end; //function DCMStr2Float2 procedure DCMStr2Float3 (lBytes: integer; var lF1,lF2,lF3: double); begin DCMStr2FloatNum (lBytes,3); lF1 := lFloatRA[1]; lF2 := lFloatRA[2]; lF3 := lFloatRA[3]; end; //function DCMStr2Float3 procedure DCMStr2Float6 (lBytes: integer; var lF1,lF2,lF3,lF4,lF5,lF6: double); begin DCMStr2FloatNum (lBytes,6); lF1 := lFloatRA[1]; lF2 := lFloatRA[2]; lF3 := lFloatRA[3]; lF4 := lFloatRA[4]; lF5 := lFloatRA[5]; lF6 := lFloatRA[6]; end; //function DCMStr2Float6 function DCMint (lBytes: integer): integer; //read 16 bit short integer begin if lBytes <= 2 then result := GetByte(lPos)+(GetByte(lPos+1) shl 8) //shortint vs word? else result := GetByte(lPos)+(GetByte(lPos+1) shl 8)+(GetByte(lPos+2) shl 16)+(GetByte(lPos+3) shl 24);; //byte order?? end; //function DCMint {$IFDEF ANON} Type TPosLen = RECORD //peristimulus plot Pos,Len: integer; end; procedure InitPosLen(var lPL: TPOsLen); begin lPL.Pos := 0; lPL.Len := 0; end; procedure SetPosLen(var lPL: TPosLen; lP,lL: integer); begin lPL.Pos := lP; lPL.Len := lL; end; procedure Anonymize(lStr: string; lPL: TPOsLen{lPos,lLen: integer}); var lDCMstr: string; lP,lL: integer; begin if ((lPL.Pos+lPL.Len) > lBufferSz) or (lPL.Len < 1) or (lPL.Pos < 1) then exit; lDCMStr := ''; lL := length(lStr); if lL > lPL.Len then lL := lPL.Len; lP := 1; while lP <= lL do begin lDCMStr := lDCMStr + lStr[lP]; inc(lP); end; while lP <= lPL.Len do begin //pad string lDCMStr := lDCMStr + ' '; inc(lP); end; for lP := 1 to lPL.Len do lByteRA^[lPL.Pos+lP] := Ord(lDCMstr[lP]); end; (*procedure AnonymizeDate(lStr: string; lPos,lLen: integer); var lDCMstr: string; lP,lL,lDateLen: integer; begin Anonymize(lStr, lPos,lLen); //put 19730316 into date field -Lauterbur paper published in Nature lDCMstr := '19730316'; lDateLen := length(lDCMStr); if ((lPos+lLen) > lBufferSz) or (lLen < lDateLen) or (lPos < 1) then exit; for lP := 1 to lDateLen do lByteRA^[lPos+lP] := Ord(lDCMstr[lP]); end;*) {$ENDIF} var lTempStr,lStr: string; lTemp,lGroupElement,lLength,lEchoNum,lnVol: integer; lResearchMode: boolean; lThick: double; {$IFDEF ANON} //position and lengths of tags to anonymize lCreateDate,lName,lID,lDOB,lSex,lAge,lWt,lStudyDate,lSeriesDate,lAcqDate: TPosLen; {$ENDIF} begin //function fast_read_dicom_data {$IFDEF ANON} //position and lengths of tags to anonymize InitPosLen(lName); InitPosLen(lID); InitPosLen(lDOB); InitPosLen(lSex); InitPosLen(lAge); InitPosLen(lWt); InitPosLen(lStudyDate); InitPosLen(lSeriesDate); InitPosLen(lAcqDate); InitPosLen(lCreateDate); {$ENDIF} lFailure := false; lnVol := 1; lEchoNum := 1; lThick := 0; clear_dicom_data(lDicomData); lDicomData.little_endian := 1; result := false; lResearchMode := false; lBufferError := false; lFileSz := FSize(lFilename); lBufferSz := lFileSz-lOffset; if lBufferSz < 512 then begin //showmessage('Error: File too small '+lFilename); exit; end; if lBufferSz > kMaxBuf then lBufferSz := kMaxBuf; GetMem(lByteRA,kMaxBuf); lBufferSz := lBufferSz; AssignFile(lInFile, lFileName); FileMode := 0; //Set file access to read only Reset(lInFile, 1); seek(lInFile,lOffset); BlockRead(lInFile, lByteRA^[1], lBufferSz); CloseFile(lInFile); FileMode := 2; lBuffStart := lOffset; lPos := lOffset; if lOffset = 128 then begin //DICOM files start with DICM at 128, Siemens shadow headers do not if DCMStr(4) <> 'DICM' then begin dcmMsg(DCMStr(4)+ ' <> DICM'); FreeMem(lByteRA); exit; end; lPos := lOffset + 4;//DICM read end;//Offset = 128 //next check VR if not( chr(GetByte(lPos+4)) in ['A'..'Z']) or not( chr(GetByte(lPos+5)) in ['A'..'Z']) then dcmMsg('implicit VR untested'); //next check Endian lTemp := lPos; ReadGroupElementLength(lGroupElement,lLength); if lLength > kMax16bit then dcmMsg('ByteSwapped'); lPos := lTemp; //end VR check while (lDICOMData.imagestart = 0) and (not lBufferError) do begin ReadGroupElementLength(lGroupElement,lLength); if lFailure then goto 999; case lGroupElement of kTransferSyntax: begin lTempStr := (DCMStr(lLength)); if (length(lTempStr) >= 19) and (lTempStr[19] = '2') then lDicomData.little_endian := 0; end; kImageType : begin lTempStr := DCMStr(lLength); //read last word - ver\mosaic -> MOSAIC lStr := ''; lTemp := length(lTempStr); while (lTemp > 0) and (lTempStr[lTemp] in ['a'..'z','A'..'Z']) do begin lStr := upcase(lTempStr[lTemp])+lStr; dec(lTemp); end; if lStr = 'MOSAIC' then lDicomData.SiemensMosaicX := 2; //we need to read numaris for details... end; kStudyTime : lDicomData.StudyTime := DCMStr(lLength); {$IFDEF ANON} //position and lengths of tags to anonymize kCreateDate: begin SetPosLen(lCreateDate,lPos,lLength) end; kSeriesDate: begin SetPosLen(lSeriesDate,lPos,lLength) end; kAcqDate: begin SetPosLen(lAcqDate,lPos,lLength) end; kStudyDate: begin SetPosLen(lStudyDate,lPos,lLength) end; kPatientName : begin SetPosLen(lName,lPos,lLength) end; kPatientID : begin SetPosLen(lID,lPos,lLength) end; kPatientDOB : begin SetPosLen(lDOB,lPos,lLength) end; kPatientSex : begin SetPosLen(lSex,lPos,lLength) end; kPatientAge : begin SetPosLen(lAge,lPos,lLength) end; kPatientWt : begin SetPosLen(lWt,lPos,lLength) end; {$ELSE} kPatientName : lDicomData.PatientName := DCMStr(lLength); kStudyDate: lDicomData.StudyDate := DCMStr(lLength); {$ENDIF} kProtocolName : lDicomData.ProtocolName :=DCMStr(lLength); kPatientPos : lDicomData.PatientPos :=DCMStr(lLength); //should be HFS for Siemens = Head First Supine kSeriesNum : lDicomData.SeriesNum := DCMStr2Int(lLength); kAcquNum : lDicomData.AcquNum := DCMStr2Int(lLength); kSeq: begin if DCMStr(lLength) = 'RM' then lResearchMode := True; end; kImageNum : lDicomData.ImageNum := DCMStr2Int(lLength); kDim3 :lDicomData.XYZdim[3] := DCMStr2Int(lLength); kDim2 : lDicomData.XYZdim[2] := DCMint (lLength); kDim1 : lDicomData.XYZdim[1] := DCMint (lLength); kLocation : lDICOMData.Location := DCMStr2Float(lLength); kAlloc: lDicomData.Allocbits_per_pixel := DCMint (lLength); kTR : lDicomData.TR := DCMStr2Float(lLength); kTE: lDicomData.TE := DCMStr2Float(lLength); kEchoNum: lEchoNum := round (DCMStr2Float(lLength)); kSlope : lDICOMData.IntenScale := DCMStr2Float(lLength); kIntercept : lDICOMData.IntenIntercept := DCMStr2Float(lLength); kOrientation : DCMStr2Float6(lLength, lDicomData.Orient[1], lDicomData.Orient[2],lDicomData.Orient[3],lDicomData.Orient[4], lDicomData.Orient[5],lDicomData.Orient[6]); kPosition : DCMStr2Float3 (lLength,lDicomData.PatientPosX, lDicomData.PatientPosY,lDicomData.PatientPosZ); knVol: lnVol := round (DCMStr2Float(lLength)); kZThick: begin lThick := DCMStr2Float(lLength); lDICOMData.XYZmm[3] := lThick; end;//used differently by manufacturers kZSpacing: begin lDICOMData.XYZmm[3] := DCMStr2Float(lLength); if (lThick/2) > lDICOMdata.XYZmm[3] then lDICOMdata.XYZmm[3] := lDICOMdata.XYZmm[3] + lThick end; //used different by different manufacturers kXYSpacing: DCMStr2Float2 (lLength, lDICOMdata.XYZmm[2], lDICOMdata.XYZmm[1]); kCSAImageHeaderInfo: begin //order ICE,Acq,Num,Vector lDICOMdata.CSAImageHeaderInfoPos := lPos; lDICOMdata.CSAImageHeaderInfoSz := lLength; end; kSlicesPer3DVol: lDICOMData.SlicesPer3DVol := DCMint (lLength); kImageStart: lDICOMData.ImageStart := lPos ; //-1 as indexed from 0.. not 1.. end; //Case lGroupElement //Msg(VR+inttohex(lGroupElement and kMax16bit,4) +':'+inttohex( lGroupElement shr 16,4)+' '+inttostr(lLength)+'@'+inttostr(lPos) ); lPos := lPos + (lLength); end; //while imagestart=0 and not error //clean up lDicomData.DateTime := StudyDateTime(lDicomData.StudyDate,lDicomData.StudyTime); if (lDicomData.SiemensMosaicX > 1) then lDicomData.AcquNum := 1; if (lEchoNum > 1) and (lEchoNum < 16) then lDicomData.AcquNum := lDicomData.AcquNum + (100*lEchoNum); if lResearchMode then lDicomData.SeriesNum := lDicomData.SeriesNum + 100; if (lDICOMData.SlicesPer3DVol > 0) and (lnVol > 1) and (lDicomdata.XYZdim[3] > 1) and (lDicomData.SlicesPer3DVol > 0)and ((lDicomdata.XYZdim[3] mod lDicomData.SlicesPer3DVol) = 0) then lDICOMdata.File4D := true; if not lBufferError then result := true; FreeMem(lByteRA); //Remaining portions only if anonymizing {$IFDEF ANON} dcmMsg('Anonymizing DICOM '+extractfilename(lFilename)); lBufferSz := lFileSz; GetMem(lByteRA,lBufferSz); //read original AssignFile(lInFile, lFileName); FileMode := 0; //Set file access to read only Reset(lInFile, 1); //seek(lInFile,1); BlockRead(lInFile, lByteRA^[1], lBufferSz); CloseFile(lInFile); //anonymize... Anonymize ('ANONYMIZED',lName); Anonymize ('ANONYMIZED',lID); Anonymize('19890323',lDOB); //Cold Fusion YYYYMMDD Anonymize('19890323',lStudyDate); //Cold Fusion YYYYMMDD Anonymize('19890323',lAcqDate); //Cold Fusion YYYYMMDD Anonymize('19890323',lSeriesDate); //Cold Fusion YYYYMMDD Anonymize('19890323',lCreateDate); //Cold Fusion YYYYMMDD Anonymize('M',lSex); Anonymize('18',lAge); Anonymize('100',lWt); //write anonymized data... assignfile(lInFile, lFileName+'.dcm'); Filemode := 2; //read&write Rewrite(lInFile,1); BlockWrite(lInFile, lByteRA^[1],lBufferSz); CloseFile(lInFile); //clean up... 999: FreeMem(lByteRA); {$ENDIF} end; //function fast_read_dicom_data end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/dcm2nii/diskfree.pas�����������������������������������������������0000755�0001750�0001750�00000021350�11326434462�020037� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit diskfree; { Copyright 2001, by Michael Hopper This unit provides generic functions for finding the number of bytes and available bytes for a given drive volume or path. These functions work for both Linux and Windows systems. Note: In the near future, getmntent should be incorporated into the Linux version of the code rather than reading the /etc/mtab file directly. This is for future compatibility. } interface uses SysUtils; {$IFDEF LINUX} { This function is included (necessary) only in the Linux version because the Windows version is a little more intuitive, i.e., 1=A:, 2=B:, etc. } function GetVolumePath (Volume : integer) : TFileName; {$ENDIF} { This overloaded function returns the number of available bytes for the specified path or volume. I've mimicked DiskFree in that Volume=0 indicates the current directory (or pwd), while values greater than 0 return a value for the drives A: through Z: on Windows systems. For Linux systems, the /etc/mtab file is read, and only those devices mounted under /dev are alphabetized and included. This means that a value of 1 would return the free space on /dev/fd0 if a floppy is mounted, or /dev/hda1 if a floppy is not mounted. Hence the need for the GetVolumePath function to verify that you're getting the right path. } function GetAvailableFreeSpace(path : TFilename) : int64; overload; function GetAvailableFreeSpace(Volume : byte) : int64; overload; { This overloaded function returns the total number of bytes for the volume or path specified. Specification of the path or volume follows the same pattern as for the GetAvailableFreeSpace function. } function GetVolumeBytes(path : TFilename) : int64; overload; function GetVolumeBytes(Volume : byte) : int64; overload; implementation {$IFDEF MSWINDOWS} uses Windows; {$ENDIF} {$IFDEF LINUX} uses Classes,libc; const MAX_PATH = 65536; {$ENDIF} {$IFDEF MSWINDOWS} function oldWindows : boolean; { Use GetVersionEx windows call as defined in SysUtils and explained in the Win32 help file to return true if this is a version of Win95 that is pre-OSR2. Otherwise, return false. } var MyVersionInfo : _OSVERSIONINFOA; begin // Get Windows version information getversionex(MyVersionInfo); // Report TRUE only if Platform is Win9x and BuildNumber is < 1000 (pre-OSR2). with MyVersionInfo do begin result := ((dwPlatformID = VER_PLATFORM_WIN32_WINDOWS) and ((dwBuildNumber and $0000FFFF) < 1000)) end; end; {$ENDIF} {$IFDEF LINUX} function GetVolumePath (Volume : integer) : TFileName; { Return the path of the Volume specified. If Volume = 0, return the present present working directory. } var loop : integer; tempstr : string; mountedDrives : TStringlist; begin // return the present working directory if Volume = 0. if Volume = 0 then result := getenvironmentvariable('PWD') else begin // Get information about currently mounted drives. mountedDrives := tstringlist.create; mountedDrives.LoadFromFile('/etc/mtab'); // Alphabetize mountedDrives.Sort; loop := 0; // Loop to remove entries that are not drives while loop < mountedDrives.Count do begin if pos('/dev/',mountedDrives.Strings[loop]) <> 1 then mountedDrives.Delete(loop) else inc(loop); end; // If there are not enough mounted drives, then return a null string. if Volume > mountedDrives.Count then result := '' else // parse the entry to return the mounted path. begin tempstr := mountedDrives.Strings[Volume-1]; tempstr := copy(tempstr,pos(' ',tempstr) + 1,length(tempstr)); tempstr := copy(tempstr,1,pos(' ',tempstr)-1); result := tempstr; end; end; end; {$ENDIF} function CalculateVolumeSpace(path : pchar; var AvailableBytes : int64; var TotalBytes : int64) : boolean; { This function calculates and returns the number of available bytes and total bytes for a given path. It also returns a true value if successful, or false if unsuccessful at determining the correct values. If the function returns false, then the AvailableBytes and TotalBytes values should be treated as though they are undefined. } var {$IFDEF MSWINDOWS} SectorsPerCluster, BytesPerSector, NumberOfFreeClusters, TotalNumberOfClusters : cardinal; {$ENDIF} {$IFDEF LINUX} myStatFs : Tstatfs; {$ENDIF} begin {$IFDEF MSWINDOWS} // Check for pre-OSR2 Win95 because the GetDiskFreeSpace function was not // available. if not oldWindows then result := GetDiskFreeSpaceEx(path,AvailableBytes,TotalBytes,nil) // If pre-OSR2 Win95, then calculate the free space. else if GetDiskFreeSpace(path,SectorsPerCluster,BytesPerSector,NumberOfFreeClusters,TotalNumberOfClusters) then begin result := true; AvailableBytes := BytesPerSector * SectorsPerCluster * NumberOfFreeClusters; TotalBytes := BytesPerSector * SectorsPerCluster * TotalNumberOfClusters; end // If unsuccessful at either of the previous attempts, report failure. else begin result := false; AvailableBytes := -1; TotalBytes := -1; end; {$ENDIF} {$IFDEF LINUX} // Read information about the volume. if statfs(path,myStatFS) = 0 then begin // Calculate AvailableBytes and TotalBytes. AvailableBytes := int64(myStatFs.f_bAvail) * int64(myStatFs.f_bsize); TotalBytes := int64(myStatFs.f_blocks) * int64(myStatFs.f_bsize); // Report success. result := true; end else // report failure to get information begin AvailableBytes := -1; TotalBytes := -1; result := false; end; {$ENDIF} end; function GetAvailableFreeSpace(path : TFilename) : int64; overload; { Use the CalculateVolumeSpace function to find the free space for the path specified. } var TotalBytes : int64; pathPchar : pchar; begin {$IFDEF MSWINDOWS} if ByteType(path,1) = mbSingleByte then getmem(pathPchar,length(path) + 1) else getmem(pathPchar,2 * (length(path) + 1)); strpcopy(pathpchar,path); if not CalculateVolumeSpace(pathPchar,result,TotalBytes) then result := -1; {$ENDIF} {$IFDEF LINUX} getmem(pathPchar,(length(path) + 1) * sizeof(char)); strpcopy(pathPchar,path); if not CalculateVolumeSpace(pathPchar,result,TotalBytes) then result := -1; // stub {$ENDIF} end; function GetAvailableFreeSpace(Volume : byte) : int64; overload; { Use the CalculateVolumeSpace function to find the free space for the Volume specified. } var volumePath : array [1..MAX_PATH + 1] of char; volumePchar : pchar; TotalSpace : int64; begin {$IFDEF MSWINDOWS} volumePchar := @volumePath; if Volume = 0 then getcurrentdirectory(MAX_PATH + 1,volumePchar) else strPCopy(volumePchar,chr(Volume - 1 + ord('A')) + ':\'); if not CalculateVolumeSpace(volumePchar, result, TotalSpace) then result := -1; {$ENDIF} {$IFDEF LINUX} volumePchar := @volumePath; if Volume = 0 then strPCopy(volumePchar,getEnvironmentVariable('PWD')) else strPCopy(volumePChar,GetVolumePath(Volume)); if not CalculateVolumeSpace(volumePchar, result, TotalSpace) then result := -1; {$ENDIF} end; function GetVolumeBytes(path : TFilename) : int64; overload; { Use the CalculateVolumeSpace function to find the total space for the path specified. } var AvailableBytes : int64; pathPchar : pchar; begin {$IFDEF MSWINDOWS} if ByteType(path,1) = mbSingleByte then getmem(pathPchar,length(path) + 1) else getmem(pathPchar,2 * (length(path) + 1)); strpcopy(pathpchar,path); if not CalculateVolumeSpace(pathPchar,AvailableBytes,result) then result := -1; {$ENDIF} {$IFDEF LINUX} getmem(pathPchar,(length(path) + 1) * sizeof(char)); strpcopy(pathPchar,path); if not CalculateVolumeSpace(pathPchar,AvailableBytes, result) then result := -1; {$ENDIF} end; function GetVolumeBytes(Volume : byte) : int64; overload; { Use the CalculateVolumeSpace function to find the total space for the Volume specified. } var volumePath : array [1..MAX_PATH + 1] of char; volumePchar : pchar; AvailableBytes : int64; begin {$IFDEF MSWINDOWS} volumePchar := @volumePath; if Volume = 0 then getcurrentdirectory(MAX_PATH + 1,volumePchar) else strPCopy(volumePchar,chr(Volume - 1 + ord('A')) + ':\'); if not CalculateVolumeSpace(volumePchar, AvailableBytes, result) then result := -1; {$ENDIF} {$IFDEF LINUX} volumePchar := @volumePath; if Volume = 0 then strPCopy(volumePchar,getEnvironmentVariable('PWD')) else strPCopy(volumePChar,GetVolumePath(Volume)); if not CalculateVolumeSpace(volumePchar, AvailableBytes, result) then result := -1; {$ENDIF} end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/Text.lrs�����������������������������������������������������������0000755�0001750�0001750�00000002201�12147215554�015652� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TTextForm','FORMDATA',[ 'TPF0'#9'TTextForm'#8'TextForm'#4'Left'#3#161#1#6'Height'#3#224#1#3'Top'#3#195 +#0#5'Width'#3#184#2#18'HorzScrollBar.Page'#3#183#2#18'VertScrollBar.Page'#3 +#203#1#13'ActiveControl'#7#5'MemoT'#7'Caption'#6#22'Descriptive Statistics' +#12'ClientHeight'#3#224#1#11'ClientWidth'#3#184#2#11'Font.Height'#2#245#9'Fo' +'nt.Name'#6#13'MS Sans Serif'#4'Menu'#7#9'MainMenu1'#8'OnCreate'#7#10'FormCr' +'eate'#10'LCLVersion'#6#8'0.9.30.2'#0#5'TMemo'#5'MemoT'#4'Left'#2#0#6'Height' +#3#224#1#3'Top'#2#0#5'Width'#3#184#2#5'Align'#7#8'alClient'#10'ScrollBars'#7 +#10'ssVertical'#8'TabOrder'#2#0#0#0#9'TMainMenu'#9'MainMenu1'#4'left'#2'p'#3 +'top'#2#10#0#9'TMenuItem'#5'File1'#7'Caption'#6#4'File'#0#9'TMenuItem'#5'Sav' +'e1'#7'Caption'#6#4'Save'#7'OnClick'#7#10'Save1Click'#0#0#9'TMenuItem'#12'Cl' +'osewindow1'#7'Caption'#6#12'Close window'#7'OnClick'#7#17'Closewindow1Click' +#0#0#0#9'TMenuItem'#5'Copy1'#7'Caption'#6#4'Edit'#0#9'TMenuItem'#5'Copy2'#7 +'Caption'#6#4'Copy'#7'OnClick'#7#10'Copy2Click'#0#0#0#0#0 ]); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/perisettings.pas���������������������������������������������������0000755�0001750�0001750�00000004655�11450447636�017454� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit perisettings; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Spin, StdCtrls, define_types; type { TPSForm } TPSForm = class(TForm) BinWidthEdit: TFloatSpinEdit; OKBtn: TButton; SavePSVolCheck: TCheckBox; PctSignalCheck: TCheckBox; ModelCheck: TCheckBox; RegressCheck: TCheckBox; TDCheck: TCheckBox; SliceTImeCheck: TCheckBox; Label1: TLabel; Label2: TLabel; Label3: TLabel; PreBinEdit: TSpinEdit; PostBinEdit: TSpinEdit; procedure FormShow(Sender: TObject); function GetPeriSettings(var lPSPlot: TPSPlot): boolean; procedure OKBtnClick(Sender: TObject); procedure RegressCheckClick(Sender: TObject); private { private declarations } public { public declarations } end; var PSForm: TPSForm; implementation uses nifti_img_view; function TPSForm.GetPeriSettings(var lPSPlot: TPSPlot): boolean; begin result := false; if lPSPlot.TRSec <= 0 then begin showmessage('Please specify the TR (in seconds) before creating a peristimulus plot.'); exit; end; if BinWidthEdit.value = 0 then BinWidthEdit.value := lPSPlot.TRsec; PSForm.ShowModal; if BinWidthEdit.value = 0 then BinWidthEdit.value := lPSPlot.TRsec else lPSPlot.BinWidthSec := BinWidthEdit.Value; lPSPlot.nNegBins := PreBinEdit.value; lPSPlot.nPosBins := PostBinEdit.value; lPSPlot.SliceTime := SliceTimeCheck.checked; lPSPlot.SavePSVol := SavePSVolCheck.checked; lPSPlot.BaselineCorrect := ModelCheck.checked; lPSPlot.PctSignal := PctSignalCheck.checked; lPSPlot.RemoveRegressorVariability := RegressCheck.checked; lPSPlot.TemporalDeriv := TDcheck.checked; lPSPlot.PlotModel := ModelCheck.checked; lPSPlot.SPMDefaultsStatsFmriT := gBGImg.SPMDefaultsStatsFmriT; lPSPlot.SPMDefaultsStatsFmriT0 := gBGImg.SPMDefaultsStatsFmriT0; result := true; end; procedure TPSForm.FormShow(Sender: TObject); begin RegressCheckClick(nil); end; procedure TPSForm.OKBtnClick(Sender: TObject); begin end; procedure TPSForm.RegressCheckClick(Sender: TObject); begin TDCheck.visible := RegressCheck.checked; ModelCheck.Visible := RegressCheck.checked; end; initialization {$I perisettings.lrs} end. �����������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/wgraphics.pas������������������������������������������������������0000755�0001750�0001750�00000005074�11326425450�016707� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit wgraphics; //only for windows {$mode objfpc}{$H+} interface uses Interfaces, SysUtils, LCLType, LCLProc, InterfaceBase, FPImage, IntfGraphics, Math, Windows,Classes,define_types; procedure Draw32Bitmap(Dest: HDC; lWidth, lHeight: Integer; Bitmap: RGBQuadp); procedure StretchDraw32Bitmap(Dest: HDC; DstWidth, DstHeight,SrcWidth, SrcHeight: Integer; Bitmap: RGBQuadp); implementation procedure StretchDraw32Bitmap(Dest: HDC; DstWidth, DstHeight,SrcWidth, SrcHeight: Integer; Bitmap: RGBQuadp); var Clip: TRect; Info: BITMAPINFO; DstX, DstY,SrcX, SrcY: integer; begin if (Bitmap = nil) then Exit; if (SrcWidth <= 0) or (SrcHeight <= 0) then Exit; if (DstWidth <= 0) or (DstHeight <= 0) then Exit; DstX := 0; DstY := 0; SrcX := 0; SrcY := 0; Widgetset.GetClipBox(Dest, @Clip); if (DstX >= Clip.Right) or (DstY >= Clip.Bottom) or (DstX + DstWidth < Clip.Left) or (DstY + DstHeight < Clip.Top) then Exit; if (DstWidth = SrcWidth) and (DstHeight = SrcHeight) then begin Draw32Bitmap(Dest, SrcWidth, SrcHeight, Bitmap); Exit; end; with Info.bmiHeader do begin biSize := SizeOf(BITMAPINFOHEADER); biWidth := SrcWidth; biHeight := SrcHeight; biPlanes := 1; biBitCount := 32; biCompression := BI_RGB; biSizeImage := 0; biClrImportant := 0; end; SetStretchBltMode(Dest, COLORONCOLOR); StretchDIBits(Dest, DstX, Pred(DstY + DstHeight), DstWidth, -DstHeight, SrcX, SrcY, SrcWidth, SrcHeight, Bitmap, Info, DIB_RGB_COLORS, SRCCOPY); end; // ! SrcX < 0, SrcY < 0, SrcX + SrcWidth > Bitmap.Width, SrcY + SrcHeight > Bitmap.Height // ! results in mash procedure Draw32Bitmap(Dest: HDC; lWidth, lHeight: Integer; Bitmap: RGBQuadp); var Clip: TRect; SrcX,SrcY,DstX,DstY:integer; Info: BITMAPINFO; begin if (Bitmap = nil) then Exit; if (lWidth <= 0) or (lHeight <= 0) then Exit; Widgetset.GetClipBox(Dest, @Clip); // clipping: SrcX := 0; SrcY := 0;DstX := 0; DstY := 0; //ClipDimension(Clip.Left, Clip.Right, DstX, SrcX, lWidth); //ClipDimension(Clip.Top, Clip.Bottom, DstY, SrcY, lHeight); with Info.bmiHeader do begin biSize := SizeOf(BITMAPINFOHEADER); biWidth := lWidth; biHeight := lHeight; biPlanes := 1; biBitCount := 32; biCompression := BI_RGB; biSizeImage := 0; biClrImportant := 0; end; SetStretchBltMode(Dest, COLORONCOLOR); StretchDIBits(Dest, DstX, Pred(DstY + lHeight), lWidth, -lHeight, SrcX, SrcY, lWidth, lHeight, Bitmap, Info, DIB_RGB_COLORS, SRCCOPY); end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/nifti_hdr_view.lfm�������������������������������������������������0000755�0001750�0001750�00000074465�12307406616�017730� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object HdrForm: THdrForm Left = 369 Height = 418 Top = 154 Width = 542 ActiveControl = PageControl1 BorderIcons = [biSystemMenu] BorderStyle = bsSingle Caption = 'NIfTI Header Information' ClientHeight = 418 ClientWidth = 542 Constraints.MaxHeight = 418 Constraints.MaxWidth = 542 Constraints.MinHeight = 418 Constraints.MinWidth = 542 Font.Name = 'MS Sans Serif' Menu = MainMenu1 OnCreate = FormCreate OnShow = FormShow Position = poScreenCenter LCLVersion = '1.0.12.0' object PageControl1: TPageControl Left = 4 Height = 395 Top = 4 Width = 534 ActivePage = TabRequired Align = alClient BorderSpacing.Left = 2 BorderSpacing.Top = 2 BorderSpacing.Right = 2 BorderSpacing.Bottom = 2 BorderSpacing.Around = 2 TabIndex = 0 TabOrder = 0 object TabRequired: TTabSheet Caption = 'Dimensions' ClientHeight = 356 ClientWidth = 528 object Label21: TLabel Left = 6 Height = 18 Top = 6 Width = 80 Caption = 'Header Type' ParentColor = False end object Label1: TLabel Left = 14 Height = 18 Top = 35 Width = 269 Caption = 'Dimension Length Spacing Unit' Font.Name = 'MS Sans Serif' ParentColor = False ParentFont = False end object Label2: TLabel Left = 16 Height = 18 Top = 67 Width = 46 Caption = 'I Space' ParentColor = False end object Label3: TLabel Left = 16 Height = 18 Top = 97 Width = 49 Caption = 'J Space' ParentColor = False end object Label4: TLabel Left = 16 Height = 18 Top = 131 Width = 51 Caption = 'K Space' ParentColor = False end object Label8: TLabel Left = 6 Height = 18 Top = 297 Width = 30 Caption = 'Data' ParentColor = False end object Label7: TLabel Left = 294 Height = 18 Top = 235 Width = 41 Caption = 'Offset' ParentColor = False end object Label44: TLabel Left = 16 Height = 18 Top = 166 Width = 31 Caption = 'Time' ParentColor = False end object Label29: TLabel Left = 16 Height = 18 Top = 198 Width = 51 Caption = '5th Dim' ParentColor = False end object Label41: TLabel Left = 16 Height = 18 Top = 230 Width = 51 Caption = '6th Dim' ParentColor = False end object Label42: TLabel Left = 16 Height = 18 Top = 265 Width = 51 Caption = '7th Dim' ParentColor = False end object HeaderMagicDrop: TComboBox Left = 108 Height = 20 Top = 2 Width = 239 ItemHeight = 0 Items.Strings = ( 'Unknown' 'ni1: NIfTI separate file (hdr+.img)' 'n+1: NIfTI embedded (.nii)' 'ni2: NIfTI2 separate file (hdr+.img)' 'n+2: NIfTI2 embedded (.nii)' ) OnSelect = HeaderMagicDropSelect Style = csDropDownList TabOrder = 15 end object Endian: TComboBox Left = 231 Height = 20 Top = 291 Width = 210 ItemHeight = 0 Items.Strings = ( 'Native Endian' 'Swapped Endian' ) Style = csDropDownList TabOrder = 16 end object fTypeDrop: TComboBox Left = 56 Height = 20 Top = 291 Width = 152 DropDownCount = 20 ItemHeight = 0 Items.Strings = ( 'binary' '8-bit S' '8-bit int U*' '16-bit int S*' '16-bit int U' '32-bit int S*' '32-bit int U' '64-bit int S' '64-bit int U' '32-bit real*' '64-bit real*' '128-bit real' '24-bit rgb' '64-bit com' '128-bit complex' '256-bit complex' ) OnSelect = ImageSzChange Style = csDropDownList TabOrder = 17 end object xyzt_sizeDrop: TComboBox Left = 262 Height = 20 Top = 87 Width = 128 ItemHeight = 0 Items.Strings = ( 'Unknown' 'Meter' 'Millimeter' 'Micrometer' 'Micron' ) Style = csDropDownList TabOrder = 18 end object xyzt_timeDrop: TComboBox Left = 262 Height = 20 Top = 157 Width = 128 ItemHeight = 0 Items.Strings = ( 'Unknown' 'Second' 'Millisecond' 'Microsecond' 'Hertzsecond' 'Part ' 'Part per million' ) Style = csDropDownList TabOrder = 19 end object Xdim: TSpinEdit Left = 80 Height = 16 Top = 59 Width = 74 MaxValue = 9999 MinValue = 1 OnExit = ImageSzChange TabOrder = 0 Value = 2 end object Ydim: TSpinEdit Left = 80 Height = 16 Top = 89 Width = 74 MaxValue = 9999 MinValue = 1 OnChange = ImageSzChange OnExit = ImageSzChange TabOrder = 1 Value = 2 end object Zdim: TSpinEdit Left = 80 Height = 16 Top = 123 Width = 74 MaxValue = 9999 MinValue = 1 OnChange = ImageSzChange OnExit = ImageSzChange TabOrder = 2 Value = 1 end object Xmm: TFloatSpinEdit Left = 164 Height = 16 Top = 59 Width = 74 Increment = 1 MaxValue = 99999999 MinValue = -99999999 TabOrder = 10 Value = 0 end object Ymm: TFloatSpinEdit Left = 164 Height = 16 Top = 89 Width = 74 Increment = 1 MaxValue = 99999999 MinValue = -99999999 TabOrder = 11 Value = 0 end object Zmm: TFloatSpinEdit Left = 164 Height = 16 Top = 123 Width = 74 Increment = 1 MaxValue = 99999999 MinValue = -99999999 TabOrder = 12 Value = 0 end object OffsetEdit: TSpinEdit Left = 342 Height = 16 Top = 230 Width = 94 MaxValue = 999999 OnExit = ImageSzChange TabOrder = 14 Value = 1 end object TDim: TSpinEdit Left = 80 Height = 16 Top = 157 Width = 74 MaxValue = 9999 MinValue = 1 OnChange = ImageSzChange OnExit = ImageSzChange TabOrder = 3 Value = 1 end object TSec: TFloatSpinEdit Left = 164 Height = 16 Top = 157 Width = 74 DecimalPlaces = 4 Increment = 1 MaxValue = 99999999 MinValue = -99999999 TabOrder = 13 Value = 0 end object Dim5Edit: TSpinEdit Left = 80 Height = 16 Top = 191 Width = 74 MaxValue = 35000 MinValue = 1 OnChange = ImageSzChange OnExit = ImageSzChange TabOrder = 4 Value = 1 end object Dim6Edit: TSpinEdit Left = 80 Height = 16 Top = 223 Width = 74 MaxValue = 35000 MinValue = 1 OnChange = ImageSzChange OnExit = ImageSzChange TabOrder = 5 Value = 1 end object Dim7Edit: TSpinEdit Left = 80 Height = 16 Top = 258 Width = 74 MaxValue = 35000 MinValue = 1 OnChange = ImageSzChange OnExit = ImageSzChange TabOrder = 9 Value = 1 end object PixDim5: TFloatSpinEdit Left = 164 Height = 16 Top = 191 Width = 74 DecimalPlaces = 4 Increment = 1 MaxValue = 99999999 MinValue = -99999999 TabOrder = 6 Value = 0 end object PixDim6: TFloatSpinEdit Left = 164 Height = 16 Top = 223 Width = 74 DecimalPlaces = 4 Increment = 1 MaxValue = 99999999 MinValue = -99999999 TabOrder = 7 Value = 0 end object PixDim7: TFloatSpinEdit Left = 164 Height = 16 Top = 258 Width = 74 DecimalPlaces = 4 Increment = 1 MaxValue = 99999999 MinValue = -99999999 TabOrder = 8 Value = 0 end end object TabSheet4: TTabSheet Caption = 'Reorient' ClientHeight = 356 ClientWidth = 528 object Label24: TLabel Left = 10 Height = 18 Top = 184 Width = 9 Caption = 'X' ParentColor = False end object Label36: TLabel Left = 10 Height = 18 Top = 218 Width = 9 Caption = 'Y' ParentColor = False end object Label37: TLabel Left = 10 Height = 18 Top = 251 Width = 8 Caption = 'Z' ParentColor = False end object Label39: TLabel Left = 10 Height = 18 Top = 123 Width = 61 Caption = 'Q Offsets' ParentColor = False end object Label40: TLabel Left = 10 Height = 18 Top = 86 Width = 76 Caption = 'Quaternions' ParentColor = False end object Label46: TLabel Left = 10 Height = 18 Top = 46 Width = 109 Caption = 'qFactor [1 or -1]' ParentColor = False end object Label38: TLabel Left = 4 Height = 18 Top = 9 Width = 150 Caption = 'Quaternion parameters ' ParentColor = False end object Label47: TLabel Left = 4 Height = 18 Top = 157 Width = 118 Caption = 'Affine parameters ' ParentColor = False end object QFormDrop: TComboBox Left = 150 Height = 20 Top = 5 Width = 260 ItemHeight = 0 Items.Strings = ( 'None' 'Scanner Position' 'Coregistrationon' 'Normalized Tal' 'Normalzied mni152ach' 'Normalzied mni152' ) OnSelect = HeaderMagicDropSelect Style = csDropDownList TabOrder = 19 end object SFormDrop: TComboBox Left = 145 Height = 20 Top = 150 Width = 204 ItemHeight = 0 Items.Strings = ( 'None' 'Scanner Position' 'Coregistrationon' 'Normalized Tal' 'Normalzied mni152ach' 'Normalzied mni152' ) OnSelect = HeaderMagicDropSelect Style = csDropDownList TabOrder = 20 end object srow_x0Edit: TFloatSpinEdit Left = 34 Height = 16 Top = 188 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 9999 MinValue = -9999 TabOrder = 7 Value = 1 end object srow_x1Edit: TFloatSpinEdit Left = 142 Height = 16 Top = 188 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 9999 MinValue = -9999 TabOrder = 8 Value = 1 end object srow_x2Edit: TFloatSpinEdit Left = 254 Height = 16 Top = 188 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 9999 MinValue = -9999 TabOrder = 9 Value = 1 end object srow_y0Edit: TFloatSpinEdit Left = 34 Height = 16 Top = 222 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 9999 MinValue = -9999 TabOrder = 11 Value = 1 end object srow_y1Edit: TFloatSpinEdit Left = 142 Height = 16 Top = 222 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 9999 MinValue = -9999 TabOrder = 12 Value = 1 end object srow_y2Edit: TFloatSpinEdit Left = 254 Height = 16 Top = 222 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 9999 MinValue = -9999 TabOrder = 13 Value = 1 end object srow_z0Edit: TFloatSpinEdit Left = 34 Height = 16 Top = 255 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 9999 MinValue = -9999 TabOrder = 15 Value = 1 end object srow_z1Edit: TFloatSpinEdit Left = 142 Height = 16 Top = 255 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 9999 MinValue = -9999 TabOrder = 16 Value = 1 end object srow_z2Edit: TFloatSpinEdit Left = 254 Height = 16 Top = 255 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 9999 MinValue = -9999 TabOrder = 17 Value = 1 end object srow_x3Edit: TFloatSpinEdit Left = 366 Height = 16 Top = 188 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 9999 MinValue = -9999 TabOrder = 10 Value = 1 end object srow_y3Edit: TFloatSpinEdit Left = 366 Height = 16 Top = 222 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 9999 MinValue = -9999 TabOrder = 14 Value = 1 end object srow_z3Edit: TFloatSpinEdit Left = 366 Height = 16 Top = 255 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 9999 MinValue = -9999 TabOrder = 18 Value = 1 end object quatern_bEdit: TFloatSpinEdit Left = 94 Height = 16 Top = 84 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 100 MinValue = 0 TabOrder = 1 Value = 1 end object quatern_cEdit: TFloatSpinEdit Left = 212 Height = 16 Top = 84 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 100 MinValue = 0 TabOrder = 2 Value = 1 end object quatern_dEdit: TFloatSpinEdit Left = 332 Height = 16 Top = 84 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 100 MinValue = 0 TabOrder = 3 Value = 1 end object qoffset_xEdit: TFloatSpinEdit Left = 94 Height = 16 Top = 117 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 100 MinValue = 0 TabOrder = 4 Value = 1 end object qoffset_yEdit: TFloatSpinEdit Left = 212 Height = 16 Top = 117 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 100 MinValue = 0 TabOrder = 5 Value = 1 end object qoffset_zEdit: TFloatSpinEdit Left = 332 Height = 16 Top = 117 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 100 MinValue = 0 TabOrder = 6 Value = 1 end object QFacEdit: TFloatSpinEdit Left = 140 Height = 16 Top = 46 Width = 100 DecimalPlaces = 5 Increment = 1 MaxValue = 1 MinValue = -1 TabOrder = 0 Value = 1 end end object TabSheet3: TTabSheet Caption = 'Image Intensity' ClientHeight = 338 ClientWidth = 526 object Label12: TLabel Left = 24 Height = 17 Top = 163 Width = 58 Caption = 'Maximum' ParentColor = False end object Label13: TLabel Left = 24 Height = 17 Top = 129 Width = 54 Caption = 'Minimum' ParentColor = False end object Label23: TLabel Left = 24 Height = 17 Top = 28 Width = 37 Caption = 'Slope' ParentColor = False end object Label22: TLabel Left = 24 Height = 17 Top = 64 Width = 52 Caption = 'Intercept' ParentColor = False end object Label30: TLabel Left = 6 Height = 17 Top = 4 Width = 113 Caption = 'Calibration Scaling' ParentColor = False end object Label33: TLabel Left = 6 Height = 17 Top = 103 Width = 192 Caption = 'Display Range (calibrated units)' ParentColor = False end object cmax: TFloatSpinEdit Left = 94 Height = 16 Top = 165 Width = 110 DecimalPlaces = 5 Increment = 1 MaxValue = 99999999 MinValue = -99999999 TabOrder = 3 Value = 0 end object cmin: TFloatSpinEdit Left = 94 Height = 16 Top = 129 Width = 110 DecimalPlaces = 5 Increment = 1 MaxValue = 99999999 MinValue = -99999999 TabOrder = 2 Value = 0 end object Scale: TFloatSpinEdit Left = 94 Height = 16 Top = 28 Width = 110 DecimalPlaces = 5 Increment = 1 MaxValue = 99999999 MinValue = -99999999 TabOrder = 0 Value = 0 end object Intercept: TFloatSpinEdit Left = 94 Height = 16 Top = 64 Width = 110 DecimalPlaces = 5 Increment = 1 MaxValue = 99999999 MinValue = -99999999 TabOrder = 1 Value = 0 end end object TabSheet1: TTabSheet Caption = 'Statistics' ClientHeight = 356 ClientWidth = 528 object Label35: TLabel Left = 8 Height = 18 Top = 14 Width = 57 Caption = 'Intention' ParentColor = False end object Label25: TLabel Left = 24 Height = 18 Top = 46 Width = 78 Caption = 'Parameter 1' ParentColor = False end object Label27: TLabel Left = 24 Height = 18 Top = 83 Width = 78 Caption = 'Parameter 2' ParentColor = False end object Label28: TLabel Left = 24 Height = 18 Top = 118 Width = 78 Caption = 'Parameter 3' ParentColor = False end object IntentCodeDrop: TComboBox Left = 76 Height = 20 Top = 8 Width = 218 DropDownCount = 44 ItemHeight = 0 Items.Strings = ( 'Not statistics' 'Correlation coefficient ' 'T-testation coefficient ' 'F-test' 'Z-score' 'Chi-squared' 'Beta distri' 'Binomial distribution' 'Gamma distribution' 'Gamma distribution' 'Normal distribution' 'Noncentral F statistic' 'Noncentral chi-squared' 'Logistic distributiond statistic' 'Laplace distribution' 'Uniform distribution' 'Noncentral t statistic' 'Weibull distribution' 'Chi distribution' 'Inverse Gaussian ' 'Extreme value type I' 'p-value value type I' 'ln(p-value)' 'log10(p-val' 'Estimatevalue)' 'Labels' 'NeuroN' 'Generic M' 'Symmetric Matrix' 'Displacement Field/Vector' 'Vectorcement Field/Vector' 'Points' 'Triangle (mesh)' 'Quaternion' ) Style = csDropDownList TabOrder = 3 end object intent_p1Edit: TFloatSpinEdit Left = 110 Height = 16 Top = 46 Width = 138 DecimalPlaces = 5 Increment = 1 MaxValue = 99999999 MinValue = -99999999 TabOrder = 0 Value = 0 end object intent_p2Edit: TFloatSpinEdit Left = 110 Height = 16 Top = 83 Width = 138 DecimalPlaces = 5 Increment = 1 MaxValue = 99999999 MinValue = -99999999 TabOrder = 1 Value = 0 end object intent_p3Edit: TFloatSpinEdit Left = 110 Height = 16 Top = 119 Width = 138 DecimalPlaces = 5 Increment = 1 MaxValue = 99999999 MinValue = -99999999 TabOrder = 2 Value = 0 end end object TabSheet2: TTabSheet Caption = 'fMRI' ClientHeight = 356 ClientWidth = 528 object Label11: TLabel Left = 12 Height = 18 Top = 145 Width = 69 Caption = 'Slice Order' ParentColor = False end object Label16: TLabel Left = 12 Height = 18 Top = 8 Width = 75 Caption = 'Time Offset' ParentColor = False end object Label17: TLabel Left = 14 Height = 18 Top = 39 Width = 86 Caption = 'Slice duration' ParentColor = False end object Label32: TLabel Left = 12 Height = 18 Top = 74 Width = 66 Caption = 'Slice Start' ParentColor = False end object Label20: TLabel Left = 12 Height = 18 Top = 105 Width = 57 Caption = 'Slice End' ParentColor = False end object Label31: TLabel Left = 12 Height = 18 Top = 178 Width = 134 Caption = 'Frequency Dimension' ParentColor = False end object Label43: TLabel Left = 12 Height = 18 Top = 214 Width = 106 Caption = 'Phase Dimension' ParentColor = False end object Label45: TLabel Left = 12 Height = 18 Top = 250 Width = 98 Caption = 'Slice Dimension' ParentColor = False end object SliceCodeDrop: TComboBox Left = 87 Height = 20 Top = 137 Width = 274 ItemHeight = 0 Items.Strings = ( 'Unknown' 'Sequential Increasing (1 2 3 4)' 'Sequential Decreasing (4 3 2 1)' 'Interleaved Increasing (1 3 2 4)' 'Interleaved Decreasing (4 2 3 1)' 'Interleaved Increasing2 (2 4 1 3)' 'Interleaved Decreasing2 (3 1 4 2)' ) OnSelect = ImageSzChange Style = csDropDownList TabOrder = 4 end object FreqDimDrop: TComboBox Left = 146 Height = 20 Top = 174 Width = 215 ItemHeight = 0 Items.Strings = ( 'Unknown' 'I' 'J' 'K' ) OnSelect = ImageSzChange Style = csDropDownList TabOrder = 5 end object PhaseDimDrop: TComboBox Left = 146 Height = 20 Top = 210 Width = 215 ItemHeight = 0 Items.Strings = ( 'Unknown' 'I' 'J' 'K' ) OnSelect = ImageSzChange Style = csDropDownList TabOrder = 6 end object SliceDimDrop: TComboBox Left = 146 Height = 20 Top = 246 Width = 215 ItemHeight = 0 Items.Strings = ( 'Unknown' 'I' 'J' 'K' ) OnSelect = ImageSzChange Style = csDropDownList TabOrder = 7 end object slice_startEdit: TSpinEdit Left = 120 Height = 16 Top = 73 Width = 112 TabOrder = 2 Value = 1 end object Slice_durationEdit: TFloatSpinEdit Left = 120 Height = 16 Top = 38 Width = 112 DecimalPlaces = 5 Increment = 1 MaxValue = 100 MinValue = 0 TabOrder = 1 Value = 1 end object toffsetEdit: TFloatSpinEdit Left = 120 Height = 16 Top = 7 Width = 112 DecimalPlaces = 5 Increment = 1 MaxValue = 100 MinValue = 0 TabOrder = 0 Value = 1 end object slice_endEdit: TSpinEdit Left = 120 Height = 16 Top = 104 Width = 112 TabOrder = 3 Value = 1 end end object TabUnused: TTabSheet Caption = 'Optional' ClientHeight = 356 ClientWidth = 528 object Label34: TLabel Left = 3 Height = 18 Top = 43 Width = 66 Caption = 'Data Type' ParentColor = False end object Label5: TLabel Left = 3 Height = 18 Top = 8 Width = 57 Caption = 'Intention' ParentColor = False end object Label6: TLabel Left = 268 Height = 18 Top = 116 Width = 49 Caption = 'Extents' ParentColor = False end object Label9: TLabel Left = 268 Height = 18 Top = 76 Width = 76 Caption = 'Sesion Error' ParentColor = False end object Label10: TLabel Left = 268 Height = 18 Top = 148 Width = 89 Caption = 'Regular [114]' ParentColor = False end object Label14: TLabel Left = 268 Height = 18 Top = 8 Width = 35 Caption = 'G Min' ParentColor = False end object Label15: TLabel Left = 268 Height = 18 Top = 43 Width = 38 Caption = 'G Max' ParentColor = False end object Label18: TLabel Left = 3 Height = 18 Top = 148 Width = 50 Caption = 'Aux File' ParentColor = False end object Label19: TLabel Left = 3 Height = 18 Top = 111 Width = 58 Caption = 'DB Name' ParentColor = False end object Label26: TLabel Left = 3 Height = 18 Top = 76 Width = 38 Caption = 'Notes' ParentColor = False end object intent_nameEdit: TEdit Left = 76 Height = 22 Top = 6 Width = 152 MaxLength = 16 TabOrder = 0 Text = 'intent_name' end object data_typeEdit: TEdit Left = 76 Height = 22 Top = 41 Width = 152 MaxLength = 10 TabOrder = 1 Text = 'data_type' end object CommentEdit: TEdit Left = 76 Height = 22 Top = 74 Width = 152 MaxLength = 80 TabOrder = 2 Text = 'CommentEdit' end object db_: TEdit Left = 76 Height = 22 Top = 109 Width = 152 MaxLength = 18 TabOrder = 3 Text = 'db_' end object aux: TEdit Left = 76 Height = 22 Top = 148 Width = 152 MaxLength = 24 TabOrder = 4 Text = 'aux' end object gmax: TSpinEdit Left = 366 Height = 16 Top = 44 Width = 66 TabOrder = 6 Value = 1 end object gmin: TSpinEdit Left = 366 Height = 16 Top = 9 Width = 66 TabOrder = 5 Value = 1 end object ses: TSpinEdit Left = 366 Height = 16 Top = 77 Width = 66 TabOrder = 7 Value = 1 end object ext: TSpinEdit Left = 366 Height = 16 Top = 117 Width = 66 TabOrder = 8 Value = 1 end object reg: TSpinEdit Left = 366 Height = 16 Top = 151 Width = 66 MaxValue = 255 TabOrder = 9 Value = 1 end end end object StatusBar1: TStatusBar Left = 0 Height = 15 Top = 403 Width = 542 Panels = < item Width = 140 end item Width = 50 end> SimplePanel = False end object MainMenu1: TMainMenu left = 424 top = 72 object File1: TMenuItem Caption = '&File' object Open1: TMenuItem Caption = 'Open header' ShortCut = 16463 OnClick = Open1Click end object Save1: TMenuItem Caption = 'Save header' ShortCut = 16467 OnClick = Save1Click end object Exit1: TMenuItem Caption = 'Close window' ShortCut = 16471 OnClick = Exit1Click end end object Page1: TMenuItem Caption = '&Tab' object Dimensions1: TMenuItem Caption = 'Dimensions' ShortCut = 16449 OnClick = TabMenuClick end object Rotations1: TMenuItem Tag = 1 Caption = 'Reorient' ShortCut = 16450 OnClick = TabMenuClick end object ImageIntensity1: TMenuItem Tag = 2 Caption = 'Image Intensity' ShortCut = 16457 OnClick = TabMenuClick end object Statistics1: TMenuItem Tag = 3 Caption = 'Statistics' ShortCut = 16452 OnClick = TabMenuClick end object FunctionalMRI1: TMenuItem Tag = 4 Caption = 'Functional MRI' ShortCut = 16453 OnClick = TabMenuClick end object Optional1: TMenuItem Tag = 5 Caption = 'Optional' ShortCut = 16454 OnClick = TabMenuClick end end object Help1: TMenuItem Caption = '&Help' object About1: TMenuItem Caption = 'About...' OnClick = About1Click end end end object OpenHdrDlg: TOpenDialog FilterIndex = 0 Options = [ofFileMustExist] left = 456 top = 72 end object SaveHdrDlg: TSaveDialog OnClose = SaveHdrDlgClose Width = 52 Filter = 'NIfTI (*.hdr;*.nii)|*.hdr; *.nii|NIfTI separate header (*.hdr)|*.hdr|NIfTI embedded header|*.nii' FilterIndex = 0 left = 496 top = 72 end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/ROIfilt.lrs��������������������������������������������������������0000755�0001750�0001750�00000004172�11450450000�016226� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TFilterROIform','FORMDATA',[ 'TPF0'#14'TFilterROIform'#13'FilterROIform'#4'Left'#3'9'#2#6'Height'#3#190#0#3 +'Top'#2'k'#5'Width'#3#240#0#18'HorzScrollBar.Page'#3#209#0#18'VertScrollBar.' +'Page'#3#196#0#13'ActiveControl'#7#10'MinROIfilt'#11'BorderIcons'#11#12'biSy' +'stemMenu'#0#11'BorderStyle'#7#12'bsToolWindow'#7'Caption'#6#16'Intensity fi' +'lter'#12'ClientHeight'#3#190#0#11'ClientWidth'#3#240#0#21'Constraints.MaxHe' +'ight'#3#190#0#20'Constraints.MaxWidth'#3#240#0#21'Constraints.MinHeight'#3 +#190#0#9'Font.Name'#6#13'MS Sans Serif'#7'OnClose'#7#9'FormClose'#6'OnShow'#7 +#8'FormShow'#8'Position'#7#14'poScreenCenter'#10'LCLVersion'#6#6'0.9.29'#0#6 +'TLabel'#7'Label42'#4'Left'#2#4#6'Height'#2#17#3'Top'#2#14#5'Width'#2'Y'#7'C' +'aption'#6#14'Min. Threshold'#11'ParentColor'#8#0#0#12'TSpeedButton'#12'Filt' +'erROIBtn'#4'Left'#2#4#6'Height'#2#25#3'Top'#3#143#0#5'Width'#3#221#0#7'Capt' +'ion'#6#27'Filter VOI with highlighted'#5'Color'#7#9'clBtnFace'#9'NumGlyphs' +#2#0#7'OnClick'#7#17'FilterROIBtnClick'#8'ShowHint'#9#14'ParentShowHint'#8#0 +#0#6'TLabel'#7'Label43'#4'Left'#2#4#6'Height'#2#14#3'Top'#2'1'#5'Width'#2'K' +#7'Caption'#6#14'Max. Threshold'#12'Font.CharSet'#2#13#11'ParentColor'#8#10 +'ParentFont'#8#0#0#12'TSpeedButton'#15'Filter2NIfTIBtn'#3'Tag'#3#128#0#4'Lef' +'t'#2#4#6'Height'#2#25#3'Top'#2'k'#5'Width'#3#221#0#7'Caption'#6' Save highl' +'ighted as NIfTI or VOI'#5'Color'#7#9'clBtnFace'#9'NumGlyphs'#2#0#7'OnClick' +#7#20'Filter2NIfTIBtnClick'#8'ShowHint'#9#14'ParentShowHint'#8#0#0#6'TLabel' +#12'FiltROILabel'#4'Left'#2#8#6'Height'#2#17#3'Top'#2'Q'#5'Width'#2#22#7'Cap' +'tion'#6#7' '#11'ParentColor'#8#0#0#9'TSpinEdit'#10'MinROIfilt'#4'Left' +#2'x'#6'Height'#2#24#3'Top'#2#7#5'Width'#2'4'#8'MaxValue'#3#254#0#8'OnChange' +#7#16'MinROIfiltChange'#8'TabOrder'#2#0#5'Value'#2'd'#0#0#9'TSpinEdit'#10'Ma' +'xROIfilt'#4'Left'#2'x'#6'Height'#2#24#3'Top'#2'*'#5'Width'#2'4'#8'MaxValue' +#3#255#0#8'OnChange'#7#16'MinROIfiltChange'#8'TabOrder'#2#1#5'Value'#3#255#0 +#0#0#0 ]); ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/license.txt��������������������������������������������������������0000755�0001750�0001750�00000003210�11326425446�016371� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������MRIcron uses the BSD license. For details see http://www.answers.com/topic/bsd-and-gpl-licensing or http://en.wikipedia.org/wiki/BSD_and_GPL_licensing MRIcron medical viewer Copyright (c) 2006 Chris Rorden All rights reserved. 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 names of the copyright owners nor the names of this project (MRIcron) 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.����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/neurodebian.txt����������������������������������������������������0000755�0001750�0001750�00000000446�11423642172�017245� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������This project is described by BSD license - please see the file license.txt. This was written by Chris Rorden, with the exceptions of DiskSpaceKludge and GraphicsMathLibrary: The author of those units gave written permission to distribute this file under the same licensing terms as MRICRON. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/xcut.bat�����������������������������������������������������������0000755�0001750�0001750�00000000123�10426762020�015651� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./mricron ./templates/ch2bet.nii.gz -s 3 -c pink -l 40 -h 120 -r ./example/cutr.ini���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/clustering.pas�����������������������������������������������������0000755�0001750�0001750�00000017727�11326425442�017110� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit clustering; //USED by stats to select only regions with a given number of connected/contiguous voxels interface uses define_types,dialogs,SysUtils,nifti_hdr,nifti_img; //procedure FindClusters (lMultiBuf: SingleP; lXdim, lYDim, lZDim, lThreshClusterSz: integer; lMinNeg, lMinPos: single); function ClusterFilterScrnImg (var lHdr: TMRIcroHdr; lThreshClusterSz: integer; lThresh: double ): boolean; implementation procedure FindClusters (var lHdr: TMRIcroHdr; lXdim, lYDim, lZDim, lThreshClusterSz: integer; lThresh: double); var lThreshClusterSzM1,lScaledThresh,lClusterSign,lClusterSz,lClusterFillValue,lQTail,lQHead,lSliceSz,lQSz,lInc,lVolSz: integer; lClusterBuff, lQra: LongIntP; lBuffIn32 : SingleP; lBuffIn16 : SmallIntP; lScaledThreshFloat: double; //lFdata: file;//abba - test const kFillValue = -2; Procedure IncQra(var lVal, lQSz: integer); begin inc(lVal); if lVal >= lQSz then lVal := 1; end; procedure Check(lPixel: integer); begin //if lClusterFillValue = kFillvalue then showmessage(inttostr(lPixel)+'@'); if (lClusterBuff^[lPixel]=lClusterSign) then begin//add item //if lClusterFillValue = kFillvalue then showmessage(inttostr(lPixel)); incQra(lQHead,lQSz); inc(lClusterSz); lClusterBuff^[lPixel] := lClusterFillValue; lQra^[lQHead] := lPixel; end; end; PROCEDURE RetirePixel; //FIFO cleanup , 1410: added 18-voxel check VAR lXDimM,lVal,lValX,lXPos,lYPos,lZPos: integer; BEGIN lVal := lQra^[lQTail]; if lVal = 0 then begin //should never happen: unmarked voxel = increment lQTail so not infinite loop incQra(lQTail,lQSz); //done with this pixel exit; end; lXpos := lVal mod lXdim; if lXpos = 0 then lXPos := lXdim; lYpos := (1+((lVal-1) div lXdim)) mod lYDim; if lYPos = 0 then lYPos := lYdim; lZpos := ((lVal-1) div lSliceSz)+1; if (lXPos <= 1) or (lXPos >= lXDim) or (lYPos <= 1) or (lYPos >= lYDim) or (lZPos <= 1) or (lZPos >= lZDim) then // retire and exit else begin lXDimM := lXDim; Check(lVal-1); //left Check(lVal+1); //right Check(lVal-lXDimM); //up Check(lVal+lXDimM); //down Check(lVal-lSliceSz); //up Check(lVal+lSliceSz); //down //check plane above lValX := lVal + lSLiceSz; Check(lValX-1); //left Check(lValX+1); //right Check(lValX-lXDimM); //up Check(lValX+lXDimM); //down //check plane below lValX := lVal - lSLiceSz; Check(lValX-1); //left Check(lValX+1); //right Check(lValX-lXDimM); //up Check(lValX+lXDimM); //down //check diagonals of current plane Check(lVal-lXDimM-1); //up, left Check(lVal-lXDimM+1); //up, right Check(lVal+lXDimM-1); //down, left Check(lVal+lXDimM+1); //down, right end;{} //not edge incQra(lQTail,lQSz); //done with this pixel END; procedure FillStart (lPt: integer); {FIFO algorithm: keep memory VERY low} var lI: integer; begin if (lClusterBuff^[lPt]<>lClusterSign) then exit; for lI := 1 to lQsz do lQra^[lI] := 0; lQHead := 0; lQTail := 1; Check(lPt); RetirePixel; // check that there was anything in the cluster at all //showmessage('head'+inttostr(lQHead)+'.'+inttostr(lQTail)); //if lQHead > 2 then begin // and do the recursion to get rid of it while ((lQHead+1) <> lQTail) do begin//complete until all voxels in buffer have been tested RetirePixel; if (lQHead = lQSz) and (lQTail = 1) then exit; //break condition: avoids possible infinite loop where QTail is being incremented but QHead is stuck at maximum value end; //end; //showmessage('alldone'); end; procedure SelectClusters (lSign: integer); var lInc: integer; begin for lInc := 1 to lVolSz do begin if lClusterBuff^[lInc] = lSign then begin // measure size of the cluster and fill it with kFillValue lClusterSz := 0; lClusterSign := lSign; lClusterFillValue := kFillValue; FillStart(lInc); // now fill the cluster with its size (=1 if the voxel was isolated) lClusterFillValue := lClusterSz; lClusterSign := kFillValue; //if lClusterSz > 1 then ShowMessage(inttostr(lClusterSz)+'@'+inttostr(lInc)); if lClusterSz > 1 then FillStart(lInc) else lClusterBuff^[lInc] := 1; //fill all voxels in cluster with size of voxel end; end; end; begin lVolSz := lXdim*lYdim*lZdim; lSliceSz := lXdim * lYdim; if (lXDim < 4) or (lYDim < 4) or (lZDim < 4) or (lVolSz < 1) then exit; GetMem(lClusterBuff, lVolSz* sizeof(LongInt)); for lInc := 1 to lVolSz do lClusterBuff^[lInc] := 0; if lHdr.ImgBufferBPP = 4 then begin lBuffIn32 := SingleP(lHdr.ImgBuffer); lScaledThreshFloat := Scaled2RawIntensity (lHdr, lThresh); for lInc := 1 to lVolSz do if lBuffIn32^[lInc] > lScaledThreshFloat then lClusterBuff^[lInc] := 1; lScaledThreshFloat := Scaled2RawIntensity (lHdr, -lThresh); for lInc := 1 to lVolSz do if lBuffIn32^[lInc] < lScaledThreshFloat then lClusterBuff^[lInc] := -1; end else if lHdr.ImgBufferBPP = 2 then begin //not 32bit - if 16bit input lBuffIn16 := SmallIntP(lHdr.ImgBuffer); lScaledThresh := round(Scaled2RawIntensity (lHdr, lThresh)); for lInc := 1 to lVolSz do if lBuffIn16^[lInc] > lScaledThresh then lClusterBuff^[lInc] := 1; lScaledThresh := round(Scaled2RawIntensity (lHdr, -lThresh)); for lInc := 1 to lVolSz do if lBuffIn16^[lInc] < lScaledThresh then lClusterBuff^[lInc] := -1; end else begin //not 16 or 32 bit input lScaledThresh := round(Scaled2RawIntensity (lHdr, lThresh)); for lInc := 1 to lVolSz do if lHdr.ImgBuffer^[lInc] > lScaledThresh then lClusterBuff^[lInc] := 1; lScaledThresh := round(Scaled2RawIntensity (lHdr, -lThresh)); for lInc := 1 to lVolSz do if lHdr.ImgBuffer^[lInc] < lScaledThresh then lClusterBuff^[lInc] := -1; end; //8-bit input lThreshClusterSzM1 := lThreshClusterSz; if lThreshClusterSzM1 < 1 then lThreshClusterSzM1 := 1; if (lThreshClusterSzM1 > 1) then begin //Next - START count cluster size lQSz := (lVolSz div 4)+8; GetMem(lQra,lQsz * sizeof(longint) ); //check positive clusters.... SelectClusters(1); //Check negative clusters SelectClusters(-1); Freemem(lQra); //END check clusters end; //only count clusters if minimum size > 1, otherwise simple intensity threshold... //NEXT: mask image data with cluster size if lHdr.ImgBufferBPP = 4 then begin lBuffIn32 := SingleP(lHdr.ImgBuffer); for lInc := 1 to lVolSz do if lClusterBuff^[lInc] < lThreshClusterSzM1 then lBuffIn32^[lInc] := 0; end else if lHdr.ImgBufferBPP = 2 then begin lBuffIn16 := SmallIntP(lHdr.ImgBuffer); for lInc := 1 to lVolSz do if lClusterBuff^[lInc] < lThreshClusterSzM1 then lBuffIn16^[lInc] := 0; end else begin for lInc := 1 to lVolSz do if lClusterBuff^[lInc] < lThreshClusterSzM1 then lHdr.ImgBuffer^[lInc] := 0; end; Freemem(lClusterBuff); end; function ClusterFilterScrnImg (var lHdr: TMRIcroHdr; lThreshClusterSz: integer; lThresh: double ): boolean; var lX,lY,lZ: integer; begin result := false; lX := lHdr.NIFTIhdr.Dim[1]; lY := lHdr.NIFTIhdr.Dim[2]; lZ := lHdr.NIFTIhdr.Dim[3]; if (lHdr.ImgBufferItems < (lX*lY*lZ)) then exit; FindClusters (lHdr, lX, lY, lZ, lThreshClusterSz, lThresh); result := true; end; end. �����������������������������������������mricron-0.20140804.1~dfsg.1.orig/bet.pas������������������������������������������������������������0000755�0001750�0001750�00000041765�11540266274�015506� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit bet; {$H+} interface uses Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, Buttons, Spin,Process,nifti_img,define_types,CropEdges, userdir; type { TBETForm } TBETForm = class(TForm) Memo1: TMemo; SmoothnessEdit: TFloatSpinEdit; Panel1: TPanel; GoBtn: TSpeedButton; AboutBtn: TSpeedButton; CropBtn: TSpeedButton; procedure CropBtnClick(Sender: TObject); procedure GoBtnClick(Sender: TObject); procedure SpeedButton2Click(Sender: TObject); private { private declarations } public { public declarations } end; var BETForm: TBETForm; implementation uses nifti_img_view; { TBETForm } procedure TBETForm.SpeedButton2Click(Sender: TObject); begin Showmessage('You can skull strip scans to allow you to render the surface of the brain.'+chr (13) + 'This uses Steve Smith''s Brain Extraction Tool [BET].'+chr (13)+ 'Default smoothness is 0.50, smaller values generate larger estimates of brain size.'+chr (13) +'http://www.fmrib.ox.ac.uk/fsl'); end; //lCmd := extractfilepath(paramstr(0))+'bet "'+lSourceFilename+'" "'+SaveDialog1.Filename // +'" -f '+floattostr(SmoothnessEdit.value{/100}); function PathExists (lCmd: string): boolean; begin result := false; if FSize(lCmd) < 1 then begin BETForm.Memo1.Lines.Add('Unable to find executable named '+lCmd); exit; end; result := true; end; procedure RunCmd (lCmd: string); var AProcess: TProcess; AStringList: TStringList; ACMD,PATH,FSLDIR,FSLCONF,lS,FULL: string; begin ACmd := lCmd; AProcess := TProcess.Create(nil); AStringList := TStringList.Create; //AProcess.CommandLine := lCmd; {$IFDEF UNIX} (*if direxists (gBGImg.FSLBASE) then BETForm.Memo1.Lines.Add('Using folder specified in mricron.ini file [FSLBASE] '+gBGImg.FSLBASE) else BETForm.Memo1.Lines.Add('Warning: unable to find folder specified in mricron.ini file [FSLBASE] '+gBGImg.FSLBASE); AProcess.Environment.Add(gBGImg.FSLBASE); lBinDir := gBGImg.FSLBASE+'/bin'; if direxists (lBinDir) then begin AProcess.Environment.Add(lBinDir); BETForm.Memo1.Lines.Add('Adding path to environment: '+lBinDir); end else BETForm.Memo1.Lines.Add('Warning: unable to find binary folder '+lBinDir);*) PATH:=GetEnvironmentVariable('PATH'); FSLDIR := gBGImg.FSLBASE; if (length(FSLDIR)<1) or (not DirExists(FSLDIR)) then begin if direxists (GetEnvironmentVariable('FSLDIR')) then FSLDIR:=GetEnvironmentVariable('FSLDIR'); end; if direxists (FSLDIR) then BETForm.Memo1.Lines.Add('Setting FSL folder (if incorrect edit FSLBASE in mricron):'+FSLDIR) else BETForm.Memo1.Lines.Add('Warning: unable to find folder specified in mricron.ini file [FSLBASE] '+FSLDIR); FULL := PATH+':'+FSLDIR+':'+FSLDIR+'/bin' ; lS := 'FSLDIR='+FSLDIR; BETForm.Memo1.Lines.Add(lS); AProcess.Environment.Add(lS); lS := 'LD_LIBRARY_PATH='+FSLDIR+'/bin'; BETForm.Memo1.Lines.Add(lS); AProcess.Environment.Add(lS); //lS := '. '+FSLDIR+'/etc/fslconf/fsl.sh'; //BETForm.Memo1.Lines.Add(lS); //AProcess.Environment.Add(lS); lS := 'PATH='+FULL; BETForm.Memo1.Lines.Add(lS); AProcess.Environment.Add(lS); //AProcess.Environment.Add(FULL); lS := 'FSLCLUSTER_MAILOPTS="n"'; BETForm.Memo1.Lines.Add(lS); AProcess.Environment.Add(lS); //lS := 'export '+FULL; //lS := 'export FSLDIR PATH'; //BETForm.Memo1.Lines.Add(lS); //AProcess.Environment.Add(lS); BETForm.Memo1.Lines.Add(gBGImg.FSLOUTPUTTYPE); AProcess.Environment.Add(gBGImg.FSLOUTPUTTYPE); {$ENDIF} AProcess.CommandLine := ACmd; AProcess.Options := AProcess.Options + [poWaitOnExit, poStderrToOutPut, poUsePipes]; BETForm.Memo1.Lines.Add(ACmd); AProcess.Execute; AStringList.LoadFromStream(AProcess.Output); BetForm.Memo1.Lines.AddStrings(AStringList); AStringList.Free; AProcess.Free; end; (*procedure RunCmdX; var AProcess: TProcess; AStringList: TStringList; lBinDir: string; begin AProcess := TProcess.Create(nil); AStringList := TStringList.Create; AProcess.CommandLine := 'bet /home/crlab/t.nii /home/crlab/xt.nii'; {$IFDEF UNIX} AProcess.Environment.Add('FSLOUTPUTTYPE=NIFTI_GZ'); AProcess.Environment.Add('/usr/local/fsl/'); AProcess.Environment.Add('/usr/local/fsl/bin'); AProcess.Environment.Add('FSLDIR=/usr/local/fsl'); //AProcess.Environment.Add('FSLOUTPUTTYPE=NIFTI_GZ'); {$ENDIF} AProcess.Options := AProcess.Options + [poWaitOnExit, poStderrToOutPut, poUsePipes]; AProcess.Execute; AStringList.LoadFromStream(AProcess.Output); BetForm.Memo1.Lines.AddStrings(AStringList); AStringList.Free; AProcess.Free; end;*) function DoBET(lInFile,lOutFile: string; lFrac: single):boolean; var lCmd: string; begin result := false; lCmd := extractfilepath(paramstr(0))+'bet'; {$IFNDEF Unix} lCmd := lCmd+'.exe'; {$ELSE} if not fileexists(lCmd) then begin lCmd := (gBGImg.FSLBASE+'/bin/bet'); if fileexists(lCmd) then BETForm.Memo1.Lines.Add('Using executable location from mricron.ini file [FSLBASE] '+lCmd) else BETForm.Memo1.Lines.Add('Unable to find executable suggested by mricron.ini file [FSLBASE] '+lCmd) end; {$ENDIF} if not PathExists (lCmd) then begin lCmd := '/usr/local/fsl/bin/bet_8UI'; if not PathExists (lCmd) then begin lCmd := '/usr/local/fsl/bin/bet'; if not PathExists (lCmd) then exit; end; end; //no bet in home folder... lCmd := lCmd+' "'+lInFile+'" "'+lOutFile +'" -R -f '+floattostr(lFrac); RunCmd(lCmd); (*AProcess := TProcess.Create(nil); {$IFDEF UNIX} AProcess.Environment.Add('FSLDIR=/usr/local/fsl'); AProcess.Environment.Add('FSLOUTPUTTYPE=NIFTI_GZ'); {$ENDIF} AProcess.CommandLine := lCmd; //AProcess.CommandLine := 'C:\bet "C:\txx.hdr" "C:\btxx.hdr" -f 0.5'; AProcess.Options := AProcess.Options + [poWaitOnExit]; AProcess.Execute; AProcess.Free; *) result := true; end; function Bright95Pct: byte;//returns intensity of 95th percentile var lPos,l5Pct,lCumulative: integer; lHisto: array [0..255] of integer; begin result := 0; if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems<1) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems<>gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems) then exit; //next - create histogram of intensity for lPos := 0 to 255 do lHisto[lPos] := 0; for lPos := 1 to gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems do inc(lHisto[gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lPos]]); //next find 95th percentile l5Pct := (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems div 20); lCumulative := 0; lPos := 256; while (lPos > 0) and (lCumulative < l5Pct) do begin dec(lPos); lCumulative := lCumulative + lHisto[lPos]; end; result := lPos; end; procedure CropVOI (lVOIIntensity: byte); var lPos: integer; begin if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems<1) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems<>gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems) then exit; for lPos := 1 to gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems do if gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lPos] = kVOI8bit then gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lPos] := lVOIIntensity; end; procedure DeleteHdrImg(lFilename: string); begin //exit; if lFilename = '' then exit; DeleteFile(lFilename); if (UpCaseExt(lFileName)='.IMG') then DeleteFile(changefileext(lFilename,'.hdr')); if (UpCaseExt(lFileName)='.HDR') then DeleteFile(changefileext(lFilename,'.img')); end; function Mask8BitImg(lImgName,lMaskName: string): boolean; //should be two 8-bit image files of identical dimensions //all non-zero voxels in the mask are written with value of img //Warning - only works with .img files with zero voxoffset - can corrupt .nii files - would need to read header.... var lPos2,lPos,lC,lSz,lMaskSz,lBPP: integer; lImg,lMask: bytep; lInF: File; begin result := false; lSz := FSize(lImgName); lMaskSz := FSize(lMaskName); if lSz = lMaskSz then lBPP := 1 else if lSz = (2*lMaskSz) then lBPP := 2 else if lSz = (2*lMaskSz) then lBPP := 4 else lBPP := 0; if (lSz < 1) or (lBPP = 0 ) then exit; //next read mask GetMem(lMask,lSz); AssignFile(lInF, lMaskName); Reset(lInF,1); BlockRead(lInF, lMask^, lMaskSz); CloseFile(lInF); //next: read image GetMem(lImg,lSz); AssignFile(lInF, lImgName); Reset(lInF,1); BlockRead(lInF, lImg^, lSz); CloseFile(lInF); //next mask image for lPos := 1 to lMaskSz do if lMask^[lPos] = 0 then begin lPos2 := ((lPos-1)*lBPP); for lC := 1 to lBPP do lImg^[lC+lPos2] := 0; end; Freemem(lMask); //next save masked image AssignFile(lInF, lImgName); //1/2008.... //AssignFile(lInF, lMaskName); Rewrite(lInF,1); BlockWrite(lInF, lImg^, lSz); CloseFile(lInF); Freemem(lImg); result := true; end; (*function Mask8BitImg(lImgName,lMaskName: string): boolean;//should be two 8-bit image files of identical dimensions //all non-zero voxels in the mask are written with value of img //Note: the mask file is changed - not the image var lPos,lSz: integer; lImg,lMask: bytep; lInF: File; begin //showmessage( lMaskName+'xx'+lImgName); result := false; lSz := FSize(lImgName); if (lSz < 1) or (lSz <> FSize(lMaskName)) then exit; //fx(lSz,778899); //next read mask GetMem(lMask,lSz); AssignFile(lInF, lMaskName); Reset(lInF,1); BlockRead(lInF, lMask^, lSz); CloseFile(lInF); //next: read image GetMem(lImg,lSz); AssignFile(lInF, lImgName); Reset(lInF,1); BlockRead(lInF, lImg^, lSz); CloseFile(lInF); //next mask image for lPos := 1 to lSz do if lMask^[lPos] = 0 then lImg^[lPos] := 0; Freemem(lMask); //next save masked image AssignFile(lInF, lMaskName); Rewrite(lInF,1); BlockWrite(lInF, lImg^, lSz); CloseFile(lInF); Freemem(lImg); result := true; end;*) function DefaultsDirCmd: string; //Lazarus for Unix does not seem to execute TProcess commands to ~/.. we need to write them to /Home/chris/.. var lLen,lP: integer; lStr: string; begin {$IFDEF UNIX} lStr := extractfiledir(GetAppConfigFile(false)); lLen := length(lStr); if lLen < 1 then exit; lP := lLen; while (lP > 0) and (lStr[lP] <> '.') do dec(lP); if lP > 1 then begin for lLen := 1 to (lP-1) do result := result + lStr[lLen]; end; {$ELSE} //else ... assume windows result := DefaultsDir('') {$ENDIF} //showmessage('x'+result+'x'); end; procedure TBETForm.GoBtnClick(Sender: TObject); label 666; var lTempNameOrig,lTempName8bitMask,lTempBetName,lTempGZName: string; begin Memo1.Clear; Memo1.lines.add('Startup Timestamp: '+DateTimeToStr(Now)); if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1) then begin showmessage('BET error: please use File/Open to display the image you want to brain extract.'); end; //showmessage(DefaultsDirCmd); lTempNameOrig :=DefaultsDirCmd+'orig.hdr';//lTempNameOrig := extractfilepath(paramstr(0))+'orig.hdr'; SaveAsVOIorNIFTIcore (lTempNameOrig, gMRIcroOverlay[kBGOverlayNum].ImgBuffer,gMRIcroOverlay[kBGOverlayNum].ImgBufferItems, gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr); //SaveAsVOIorNIFTIcore (lTempNameOrig, gMRIcroOverlay[kBGOverlayNum].ImgBuffer,gMRIcroOverlay[kBGOverlayNum].ImgBufferItems, gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP,gMRIcroOverlay[kBGOverlayNum].NiftiHdr); if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems > 0 then begin case MessageDlg('Do you wish to protect tissue shown by the VOI drawing?', mtConfirmation, [mbYes, mbNo], 0) of mrYes: CropVOI(Bright95Pct); end; //case for protecting VOI ImgForm.CloseVOIClick(nil); end; if gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP <> 1 then Memo1.lines.add('Warning: converted image downsampled to 8-bit precision.'); lTempName8bitMask := DefaultsDirCmd+'temp8.hdr';//lTempName8bitMask := extractfilepath(paramstr(0))+'temp8.hdr'; SaveAsVOIorNIFTIcore (lTempName8bitMask, gMRIcroOverlay[kBGOverlayNum].ScrnBuffer,gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems, 1,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr); lTempName8bitMask := changefileext(lTempName8bitMask,'.hdr'); //SaveAs renames the .hdr to .img lTempBetName := DefaultsDirCmd+'btemp8.hdr';//lTempBetName := extractfilepath(paramstr(0))+'btemp8.hdr'; // showmessage(lTempBetName); if not DoBET(lTempName8bitMask,lTempBetName,SmoothnessEdit.value) then goto 666; Memo1.lines.add('Shutdown Timestamp: '+DateTimeToStr(Now)); if Fileexists(lTempBetName) then begin CopyFileEXoverwrite(lTempName8bitMask,lTempBetName); //the old version of BET corrupts some NIfTI information end else begin //assume new version of bet_8UI has saved as .nii.gz lTempGZName := ChangeFileExt(lTempBetName,'.nii.gz'); if not Fileexists(lTempGZName) then begin Memo1.lines.add('BET Error: unable to find BET image '+lTempBetName+ ' or '+lTempGZName); {$IFDEF Darwin} Memo1.lines.add(' Try relaunching MRIcron from the Terminal command line, e.g. /Applications/mricron.app/mricron &'); {$ENDIF} goto 666; end; //convert .nii.gz to hdr/.img so we can mask it... ImgForm.CloseImagesClick(nil); ImgForm.OpenAndDisplayImg(lTempGZName,True); SaveAsVOIorNIFTIcore (lTempBetName,gMRIcroOverlay[kBGOverlayNum].ScrnBuffer, gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems, 1,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr); DeleteHdrImg(lTempGZName); goto 666; // ImgForm.CloseImagesClick(nil); end; Mask8BitImg(changefileext(lTempNameOrig,'.img'),changefileext(lTempBetName,'.img')); ImgForm.OpenAndDisplayImg(lTempNameOrig,True); Memo1.lines.add('Use File/SaveAsNIfTI to save the stripped 8-bit image.'); 666: DeleteHdrImg(lTempBetName); DeleteHdrImg(lTempNameOrig); DeleteHdrImg(lTempName8bitMask); end; procedure TBETForm.CropBtnClick(Sender: TObject); begin CropEdgeForm.Show; end; (*var lTempNameOrig,lTempName8bitMask,lTempBetName: string; begin Memo1.Clear; Memo1.lines.add('Startup Timestamp: '+DateTimeToStr(Now)); if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1) then begin showmessage('BET error: please use File/Open to display the image you want to brain extract.'); end; lTempNameOrig := ''; if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems > 0 then begin case MessageDlg('Do you wish to remove tissue shown by the VOI drawing?', mtConfirmation, [mbYes, mbNo], 0) of mrYes: CropVOI(0); else case MessageDlg('Do you wish to protect tissue shown by the VOI drawing?', mtConfirmation, [mbYes, mbNo], 0) of mrYes: begin lTempNameOrig := DefaultsDir('')+'orig8.hdr'; SaveAsVOIorNIFTIcore (lTempNameOrig, gMRIcroOverlay[kBGOverlayNum].ScrnBuffer,gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems, 1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr); CropVOI(Bright95Pct); end; end; //case for protecting VOI end; //case for deleting VOI ImgForm.CloseVOIClick(nil); end; if gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP <> 1 then Memo1.lines.add('Warning: converted image downsampled to 8-bit precision.'); lTempName8bitMask := DefaultsDir('')+'temp8.hdr'; SaveAsVOIorNIFTIcore (lTempName8bitMask, gMRIcroOverlay[kBGOverlayNum].ScrnBuffer,gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems, 1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr); lTempName8bitMask := changefileext(lTempName8bitMask,'.hdr'); //SaveAs renames the .hdr to .img lTempBetName := DefaultsDir('')+'btemp8.hdr'; DoBET(lTempName8bitMask,lTempBetName,SmoothnessEdit.value); Memo1.lines.add('Shutdown Timestamp: '+DateTimeToStr(Now)); CopyFileEXoverwrite(lTempName8bitMask,lTempBetName); //the old version of BET corrupts some NIfTI information DeleteHdrImg(lTempName8bitMask); if lTempNameOrig <> '' then begin Mask8BitImg(changefileext(lTempNameOrig,'.img'),changefileext(lTempBetName,'.img')); DeleteHdrImg(lTempNameOrig); end; ImgForm.OpenAndDisplayImg(lTempBetName,True); Memo1.lines.add('Use File/SaveAsNIfTI to save the stripped 8-bit image.'); DeleteHdrImg(lTempBetName); end;*) (*procedure TBETForm.GoBtnClick(Sender: TObject); begin Memo1.Clear; Memo1.lines.add('Startup Timestamp: '+DateTimeToStr(Now)); DoBET('C:\txx.hdr','C:\btxx.hdr',SmoothnessEdit.value); Memo1.lines.add('Shutdown Timestamp: '+DateTimeToStr(Now)); end; *) initialization {$I bet.lrs} end. �����������mricron-0.20140804.1~dfsg.1.orig/landmarks.pas������������������������������������������������������0000755�0001750�0001750�00000014460�11450447434�016677� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit landmarks; interface {$H+} uses {$IFDEF Win32} Windows, Messages, {$ELSE} LMessages, LCLType, {$ENDIF} {$IFDEF FPC}LResources, {$ENDIF} SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons, ToolWin, ComCtrls; type TAnatForm = class(TForm) ToolBar1: TToolBar; SaveBtn: TSpeedButton; AddBtn: TSpeedButton; ComboBox1: TComboBox; UpdateBtn: TSpeedButton; OpenBtn: TSpeedButton; DeleteBtn: TSpeedButton; procedure SaveBtnClick(Sender: TObject); procedure AddBtnClick(Sender: TObject); procedure ComboBox1Change(Sender: TObject); procedure UpdateCombo; procedure OpenBtnClick(Sender: TObject); procedure Update(lIndex: integer); procedure UpdateBtnClick(Sender: TObject); procedure DeleteBtnClick(Sender: TObject); procedure OpenAnat(lFilename: string); procedure CloseAnat; private { Private declarations } public { Public declarations } end; var AnatForm: TAnatForm; implementation uses nifti_img_view, nifti_img, nifti_hdr_view, define_types; {$IFNDEF FPC} //Delphi {$R *.dfm} {$ENDIF} type TLandmark = record Name: string; X,Y,Z: single; end; TLandmarkRA = array of TLandmark; const kAnatFilter = 'AnatomyFile|*.anat'; var gLandmarks: TLandmarkRA; procedure TAnatForm.CloseAnat; begin if length(gLandmarks) < 1 then exit; SetLength(gLandmarks,0); UpdateCombo; end; procedure TAnatForm.SaveBtnClick(Sender: TObject); const kSep = chr(9); var i: integer; lF: TextFile; begin if length(gLandmarks) < 1 then begin showmessage('No landmarks open - either open a file or create new landmarks'); exit; end; ImgForm.SaveDialog1.Filter := kAnatFilter; ImgForm.SaveDialog1.DefaultExt := '.anat'; ImgForm.SaveDialog1.Filename := ChangeFileExt(ImgForm.SaveDialog1.Filename, ImgForm.SaveDialog1.DefaultExt); //10102006 if not ImgForm.SaveDialog1.Execute then exit; Filemode := 0; AssignFile(lF, ImgForm.SaveDialog1.Filename); rewrite(lF); for i := 0 to length(gLandmarks)-1 do Writeln(lF, gLandmarks[i].Name+kSep+floattostr(gLandmarks[i].X)+kSep+floattostr(gLandmarks[i].Y)+kSep+floattostr(gLandmarks[i].Z) ); CloseFile(lF); end; procedure TAnatForm.UpdateCombo; var i: integer; begin //xxx ComboBox1.Items.Clear; if length(gLandmarks) < 1 then exit; for i := 0 to length(gLandmarks)-1 do ComboBox1.Items.Add(gLandmarks[i].Name); ComboBox1.ItemIndex := length(gLandmarks)-1; ComboBox1Change(nil); end; procedure TAnatForm.AddBtnClick(Sender: TObject); var s: string; i: integer; lOK: boolean; begin i := length(gLandmarks)+1; s := 'A'+inttostr(i); lOK := InputQuery('Enter a name', 'region name', s); if not lOK then exit; setlength(gLandmarks,i); gLandmarks[i-1].Name := s; Update(i-1); UpdateCombo; end; (* MMToImgCoord(lX,lY,lZ,lXmm,lYmm,lZmm); if lX <> ImgForm.XViewEdit.value then ImgForm.XViewEdit.value := lX; if lY <> ImgForm.YViewEdit.value then ImgForm.YViewEdit.value := lY; if lZ <> ImgForm.ZViewEdit.value then ImgForm.ZViewEdit.value := lZ; *) procedure SetLandmark(index: integer);//indexed from 0 var //lXmm,lYmm,lZmm: single; lX,lY,lZ: integer; begin if (index < 0) or (index >= length(gLandmarks)) then exit; MMToImgCoord(lX,lY,lZ,gLandmarks[index].X,gLandmarks[index].Y,gLandmarks[index].Z); if lX <> ImgForm.XViewEdit.value then ImgForm.XViewEdit.value := lX; if lY <> ImgForm.YViewEdit.value then ImgForm.YViewEdit.value := lY; if lZ <> ImgForm.ZViewEdit.value then ImgForm.ZViewEdit.value := lZ; ImgForm.XViewEditChange(nil); end; procedure TAnatForm.ComboBox1Change(Sender: TObject); begin SetLandmark(ComboBox1.ItemIndex); end; function NextTab(lStr: string; var lP: integer): string; //reports text prior to comma... var len: integer; begin result := ''; len := length(lStr); if len < lP then exit; repeat if (lStr[lP] = chr(9){','}) then begin lP := lP + 1; exit; end; //if lStr[lP] <> ' ' then result := result + lStr[lP]; lP := lP + 1; until (lP > len); end; procedure TAnatForm.OpenAnat(lFilename: string); var st: string; sl: TStringList; n, line, col : integer; begin if not Fileexists(lFilename) then begin CloseAnat; exit; end; //will load the TAB delimited TXT here sl := TStringList.Create; try //load the tab delimited txt file sl.LoadFromFile(lFilename) ; //for each tab delimited line n := 0; setlength(gLandmarks,sl.Count); for line := 0 to sl.Count-1 do begin st := sl[line]; col := 1; if (NextTab(st,col) <> '') and (NextTab(st,col) <> '') and(NextTab(st,col) <> '') and(NextTab(st,col) <> '') then begin inc(n); col := 1; gLandmarks[line].Name := NextTab(st,col); gLandmarks[line].X := strtofloat(NextTab(st,col)); gLandmarks[line].Y := strtofloat(NextTab(st,col)); gLandmarks[line].Z := strtofloat(NextTab(st,col)); end; end; setlength(gLandmarks,n); finally sl.Free; end; UpdateCombo; AnatForm.show; end; procedure TAnatForm.OpenBtnClick(Sender: TObject); begin if not OpenDialogExecute(kAnatFilter,'Select background image',false) then exit; OpenAnat(HdrForm.OpenHdrDlg.Filename) ; end; procedure TAnatForm.Update(lIndex: integer); var X,Y,Z: integer; begin if lIndex >= Length(gLandmarks) then exit; X := round(ImgForm.XViewEdit.value); Y := round(ImgForm.YViewEdit.value); Z := round(ImgForm.ZViewEdit.value); ImgCoordToMM(X,Y,Z, gLandmarks[lIndex].X,gLandmarks[lIndex].Y,gLandmarks[lIndex].Z); ComboBox1Change(nil); end; procedure TAnatForm.UpdateBtnClick(Sender: TObject); begin Update(ComboBox1.ItemIndex); end; procedure TAnatForm.DeleteBtnClick(Sender: TObject); var p,i,l: integer; begin l := Length(gLandmarks); i := ComboBox1.ItemIndex; if (l < 1) or (i >= l) or (i < 0) then exit; if i < (l-1) then for p := i+1 to l-1 do gLandmarks[p-1] := gLandmarks[p]; SetLength(gLandmarks,l-1); UpdateCombo; end; initialization {$IFDEF FPC} {$I landmarks.lrs} {$ENDIF} end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/prefs.pas����������������������������������������������������������0000755�0001750�0001750�00000005207�12332435212�016030� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit prefs; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls, Spin, Buttons; type { TPrefForm } TPrefForm = class(TForm) SingleRowCheck: TCheckBox; OrthoCheck: TCheckBox; XBarClr: TButton; OKBtn: TButton; CancelBtn: TButton; ThinPenCheck: TCheckBox; GroupBox2: TGroupBox; Label1: TLabel; Label2: TLabel; Label3: TLabel; ResliceCheck: TCheckBox; GroupBox1: TGroupBox; MaxDimEdit: TSpinEdit; ThreadEdit: TSpinEdit; SigDigEdit: TSpinEdit; procedure CancelBtnClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormShow(Sender: TObject); procedure OKBtnClick(Sender: TObject); procedure ResliceCheckClick(Sender: TObject); procedure XBarClrClick(Sender: TObject); private { private declarations } public { public declarations } end; var PrefForm: TPrefForm; implementation uses nifti_img_view; { TPrefForm } procedure TPrefForm.CancelBtnClick(Sender: TObject); begin Close; end; procedure TPrefForm.FormCreate(Sender: TObject); begin end; procedure TPrefForm.FormShow(Sender: TObject); begin ResliceCheck.checked := gBGImg.ResliceOnLoad; //OrthoCheck.Visible := not gBGImg.ResliceOnLoad; OrthoCheck.checked := gBGImg.OrthoReslice; MaxDimEdit.value := gBGImg.MaxDim; ThreadEdit.value := gnCPUThreads; //DrawCheck.checked := ImgForm.ToolPanel.Visible; ThinPenCheck.Checked := gBGImg.ThinPen; SigDigEdit.value := gBGImg.SigDig; SingleRowCheck.checked := gBGImg.SingleRow; end; procedure TPrefForm.OKBtnClick(Sender: TObject); begin gBGImg.ResliceOnLoad := ResliceCheck.checked; gBGImg.OrthoReslice := OrthoCheck.checked; gBGImg.MaxDim := MaxDimEdit.value; gnCPUThreads := ThreadEdit.value; //ImgForm.ToolPanel.Visible := DrawCheck.checked; //ImgForm.DrawMenu.Visible := DrawCheck.checked; gBGImg.ThinPen := ThinPenCheck.Checked; gBGImg.SigDig := SigDigEdit.value; if gBGImg.SingleRow <> SingleRowCheck.Checked then begin gBGImg.SingleRow := SingleRowCheck.Checked; ImgForm.DefaultControlPanel; ImgForm.RefreshImagesTimer.enabled := true; end; Close; end; procedure TPrefForm.ResliceCheckClick(Sender: TObject); begin OrthoCheck.Visible := not ResliceCheck.checked; end; procedure TPrefForm.XBarClrClick(Sender: TObject); begin ImgForm.XBarColor; PrefForm.BringToFront; end; initialization {$I prefs.lrs} end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/voismooth.lfm������������������������������������������������������0000755�0001750�0001750�00000005061�11545433540�016740� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object voismoothform: Tvoismoothform Left = 650 Height = 222 Top = 241 Width = 252 ActiveControl = XROIfwhm BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Blur VOI' ClientHeight = 222 ClientWidth = 252 Constraints.MaxHeight = 222 Constraints.MaxWidth = 252 Constraints.MinHeight = 222 Constraints.MinWidth = 252 OnCreate = FormCreate OnShow = FormShow Position = poScreenCenter LCLVersion = '0.9.29' object Label37: TLabel Left = 12 Height = 17 Top = 46 Width = 62 Caption = 'Threshold' Font.CharSet = ANSI_CHARSET Font.Name = 'MS Sans Serif' ParentColor = False ParentFont = False end object CancelBtn: TSpeedButton Left = 94 Height = 25 Hint = 'Save to small-endian [Intel] format' Top = 167 Width = 66 Caption = 'Cancel' Color = clBtnFace NumGlyphs = 0 OnClick = BtnClick ShowHint = True ParentShowHint = False end object OKBtn: TSpeedButton Tag = 1 Left = 165 Height = 25 Hint = 'Save to big-endian [Sun] format' Top = 167 Width = 66 Caption = 'OK' Color = clBtnFace NumGlyphs = 0 OnClick = BtnClick ShowHint = True ParentShowHint = False end object HelpBtn: TSpeedButton Tag = 2 Left = 21 Height = 25 Top = 167 Width = 66 Caption = 'Help' Color = clBtnFace NumGlyphs = 0 OnClick = HelpBtnClick ParentShowHint = False end object Label38: TLabel Left = 12 Height = 17 Top = 9 Width = 143 Caption = 'Smoothing (FWHM mm)' Font.CharSet = ANSI_CHARSET Font.Name = 'MS Sans Serif' ParentColor = False ParentFont = False end object ScaleSides: TComboBox Left = 12 Height = 21 Top = 84 Width = 229 ItemHeight = 13 Items.Strings = ( 'Adjust sides in Z-plane only [SPM]' 'Adjust sides in X,Y and Z planes' ) Style = csDropDownList TabOrder = 0 end object xROIoutput: TComboBox Left = 12 Height = 21 Top = 117 Width = 229 ItemHeight = 13 Items.Strings = ( 'ROI is 1 [reslice ROI]' 'ROI is 0 [SPM object mask]' ) Style = csDropDownList TabOrder = 1 end object XROIthresh: TFloatSpinEdit Left = 175 Height = 21 Top = 41 Width = 70 DecimalPlaces = 4 Increment = 0.00100000004749 MaxValue = 1 MinValue = 0 TabOrder = 2 Value = 1 end object XROIfwhm: TSpinEdit Left = 175 Height = 21 Top = 4 Width = 70 MaxValue = 40 MinValue = 1 TabOrder = 3 Value = 1 end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/graphx.lrs���������������������������������������������������������0000755�0001750�0001750�00000027711�11425734216�016233� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TGraph4DForm','FORMDATA',[ 'TPF0'#12'TGraph4DForm'#11'Graph4DForm'#4'Left'#3#230#1#6'Height'#3#173#1#3'T' +'op'#3#156#0#5'Width'#3'I'#4#13'ActiveControl'#7#6'TREdit'#7'Caption'#6#18'4' +'D Timeline Viewer'#12'ClientHeight'#3#154#1#11'ClientWidth'#3'I'#4#4'Menu'#7 +#9'MainMenu1'#7'OnClose'#7#9'FormClose'#8'OnCreate'#7#10'FormCreate'#8'OnRes' +'ize'#7#10'FormResize'#6'OnShow'#7#8'FormShow'#8'Position'#7#14'poScreenCent' +'er'#10'LCLVersion'#6#6'0.9.29'#0#6'TImage'#6'Image1'#4'Left'#2#0#6'Height'#3 +'b'#1#3'Top'#2'$'#5'Width'#3'I'#4#5'Align'#7#8'alClient'#0#0#6'TPanel'#8'Fou' +'rDBar'#4'Left'#2#0#6'Height'#2'$'#3'Top'#2#0#5'Width'#3'I'#4#5'Align'#7#5'a' +'lTop'#10'BevelOuter'#7#6'bvNone'#12'ClientHeight'#2'$'#11'ClientWidth'#3'I' +#4#8'TabOrder'#2#0#0#12'TSpeedButton'#11'OpenDataBtn'#4'Left'#2#11#6'Height' +#2#25#3'Top'#2#7#5'Width'#2'_'#7'Caption'#6#9'Open Data'#5'Color'#7#9'clBtnF' +'ace'#9'NumGlyphs'#2#0#7'OnClick'#7#13'OpenDataClick'#0#0#12'TSpeedButton'#10 +'RefreshBtn'#4'Left'#2'p'#6'Height'#2#30#3'Top'#2#4#5'Width'#2#30#5'Color'#7 +#9'clBtnFace'#10'Glyph.Data'#10#218#8#0#0#214#8#0#0'BM'#214#8#0#0#0#0#0#0'6' +#0#0#0'('#0#0#0#24#0#0#0#23#0#0#0#1#0' '#0#0#0#0#0#160#8#0#0'd'#0#0#0'd'#0#0 +#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'/'#0#0#255 +#156#0#0#255#185#0#0#255#202#0#0#255#191#0#0#255#12#255#255#255#0#255#255#255 +#0#255#255#255#0#0#0#255#13#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'2'#0#0#255#164#0#0#255#240 +#0#0#255#255#0#0#255#255#0#0#255#190#0#0#255#25#0#0#255#22#0#0#255'j'#0#0#255 +#153#0#0#255#194#0#0#255'i'#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#0#0#255'c'#0#0#255#229#0#0#255#255#0#0#255#255#0 +#0#255#255#0#0#255#228#0#0#255#8#0#0#255#15#0#0#255#224#0#0#255#255#0#0#255 +#252#0#0#255'a'#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#0#0#255#1#0#0#255#136#0#0#255#244#0#0#255#255#0#0#255#255#0#0#255#255 +#0#0#255#255#0#0#255#238#0#0#255#24#255#255#255#0#0#0#255#145#0#0#255#255#0#0 +#255#230#0#0#255#246#0#0#255#167#0#0#255'('#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#0#0#255#151#0#0#255#254#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#255#204#0#0#255'`'#255#255#255#0#255#255#255#0#0#0#255#24#0#0#255 +#231#0#0#255'B'#0#0#255#148#0#0#255#242#0#0#255#234#0#0#255#144#0#0#255#16 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0 +#255'e'#0#0#255#248#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#222#0#0#255 +#127#0#0#255#6#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0 +#255#162#0#0#255' '#255#255#255#0#0#0#255'G'#0#0#255#203#0#0#255#255#0#0#255 +#218#0#0#255'P'#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'/'#0#0#255 +#226#0#0#255#255#0#0#255#255#0#0#255#252#0#0#255#167#0#0#255#23#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0 +#255#15#0#0#255#6#255#255#255#0#255#255#255#0#0#0#255#9#0#0#255#171#0#0#255 +#255#0#0#255#228#0#0#255'B'#255#255#255#0#255#255#255#0#0#0#255#182#0#0#255 +#255#0#0#255#255#0#0#255#238#0#0#255'}'#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0 +#255#12#0#0#255#197#0#0#255#255#0#0#255#206#0#0#255#6#0#0#255'&'#0#0#255#242 +#0#0#255#255#0#0#255#245#0#0#255'f'#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#0#0#255'+'#0#0#255#225#0#0#255#255#0#0#255'z'#0#0#255 +#132#0#0#255#255#0#0#255#255#0#0#255#135#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255#175#0#0#255#255 +#0#0#255#162#0#0#255#195#0#0#255#255#0#0#255#215#0#0#255#3#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0 +#255#142#0#0#255#255#0#0#255#181#0#0#255#201#0#0#255#255#0#0#255#153#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 ,#255#0#255#255#255#0#0#0#255#153#0#0#255#255#0#0#255#201#0#0#255#181#0#0#255 +#255#0#0#255#142#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#0#0#255#3#0#0#255#215#0#0#255#255#0#0#255#195#0 +#0#255#162#0#0#255#255#0#0#255#175#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255#135#0#0#255#255#0#0 +#255#255#0#0#255#132#0#0#255'z'#0#0#255#255#0#0#255#225#0#0#255'+'#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'f'#0#0#255#245#0 +#0#255#255#0#0#255#242#0#0#255'&'#0#0#255#6#0#0#255#206#0#0#255#255#0#0#255 +#197#0#0#255#12#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'}'#0#0#255#238#0#0 +#255#255#0#0#255#255#0#0#255#182#255#255#255#0#255#255#255#0#0#0#255'B'#0#0 +#255#228#0#0#255#255#0#0#255#171#0#0#255#9#255#255#255#0#255#255#255#0#0#0 +#255#6#0#0#255#15#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#0#0#255#23#0#0#255#167#0#0#255#252#0#0#255#255#0#0 +#255#255#0#0#255#226#0#0#255'/'#255#255#255#0#255#255#255#0#255#255#255#0#0#0 +#255'P'#0#0#255#218#0#0#255#255#0#0#255#203#0#0#255'G'#255#255#255#0#0#0#255 +' '#0#0#255#163#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0 +#255#6#0#0#255#127#0#0#255#222#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#248#0#0#255'e'#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#0#0#255#16#0#0#255#144#0#0#255#234#0#0#255#242#0#0#255#148#0#0#255 +'B'#0#0#255#231#0#0#255#24#255#255#255#0#255#255#255#0#0#0#255'`'#0#0#255#204 +#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#254#0#0#255#151#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#0#0#255'('#0#0#255#167#0#0#255#246#0#0#255 +#230#0#0#255#255#0#0#255#145#255#255#255#0#0#0#255#24#0#0#255#238#0#0#255#255 +#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#244#0#0#255#136#0#0#255#1#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'a'#0#0 +#255#252#0#0#255#255#0#0#255#224#0#0#255#15#0#0#255#8#0#0#255#228#0#0#255#255 +#0#0#255#255#0#0#255#255#0#0#255#229#0#0#255'c'#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'i'#0#0#255#194#0 +#0#255#153#0#0#255'j'#0#0#255#22#0#0#255#25#0#0#255#190#0#0#255#255#0#0#255 +#255#0#0#255#240#0#0#255#164#0#0#255'2'#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#0'@'#0#0#7 +#190#0#0#0#171#0#0#0'('#255#255#255#0#0#0#255#13#255#255#255#0#255#255#255#0 +#255#255#255#0#0#0#255#12#0#0#255#191#0#0#255#202#0#0#255#185#0#0#255#156#0#0 +#255'/'#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#9'NumGlyphs'#2#0#7'OnClick'#7#15 +'RefreshBtnClick'#11'OnMouseDown'#7#19'RefreshBtnMouseDown'#0#0#6'TLabel'#7 +'TRLabel'#4'Left'#3#152#0#6'Height'#2#14#3'Top'#2#15#5'Width'#2')'#7'Caption' +#6#8'TR (sec)'#11'ParentColor'#8#0#0#12'TSpeedButton'#7'PlotBtn'#4'Left'#3 +#232#1#6'Height'#2#25#3'Top'#2#7#5'Width'#2'?'#7'Caption'#6#4'Plot'#5'Color' +#7#9'clBtnFace'#9'NumGlyphs'#2#0#7'OnClick'#7#11'PSPlotClick'#0#0#12'TSpeedB' +'utton'#7'TextBtn'#4'Left'#3'0'#2#6'Height'#2#25#3'Top'#2#7#5'Width'#2'P'#7 +'Caption'#6#4'Text'#5'Color'#7#9'clBtnFace'#9'NumGlyphs'#2#0#7'OnClick'#7#11 +'PSTextClick'#0#0#14'TFloatSpinEdit'#6'TREdit'#4'Left'#3#240#0#6'Height'#2#21 +#3'Top'#2#9#5'Width'#2'R'#13'DecimalPlaces'#2#4#9'Increment'#5#0#0#0#0#0#0#0 +#128#255'?'#8'MaxValue'#5#0#0#0#0#0' '#188#190#25'@'#8'MinValue'#5#0#0#0#0#0 +#0#0#0#0#0#8'TabOrder'#2#0#5'Value'#5#0#0#0#0#0#0#0#0#0#0#0#0#9'TComboBox'#10 +'HSpeedDrop'#4'Left'#3'`'#1#6'Height'#2#21#3'Top'#2#5#5'Width'#2'x'#10'ItemH' +'eight'#2#13#13'Items.Strings'#1#6#6'To Fit'#6#2'x1'#6#2'x2'#6#2'x3'#6#2'x4' +#6#2'x5'#6#2'x6'#6#2'x7'#6#2'x8'#6#2'x9'#6#3'x10'#0#8'OnChange'#7#15'TrackBa' +'r1Change'#5'Style'#7#14'csDropDownList'#8'TabOrder'#2#1#0#0#14'TFloatSpinEd' +'it'#7'MinEdit'#4'Left'#3#144#2#6'Height'#2#21#3'Top'#2#6#5'Width'#2'R'#13'D' +'ecimalPlaces'#2#4#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0 +#0#0#0#0#0#200#5'@'#8'MinValue'#5#0#0#0#0#0#0#0#0#0#0#8'TabOrder'#2#2#5'Valu' ,'e'#5#0#0#0#0#0#0#0#0#0#0#0#0#14'TFloatSpinEdit'#7'MaxEdit'#4'Left'#3#0#3#6 +'Height'#2#21#3'Top'#2#6#5'Width'#2'R'#13'DecimalPlaces'#2#4#9'Increment'#5#0 +#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0#0#0#200#5'@'#8'MinValue'#5#0 +#0#0#0#0#0#0#0#0#0#8'TabOrder'#2#3#5'Value'#5#0#0#0#0#0#0#0#0#0#0#0#0#9'TTra' +'ckBar'#9'TrackBar1'#4'Left'#3'`'#3#6'Height'#2#29#3'Top'#2#4#5'Width'#3#204 +#0#8'OnChange'#7#15'TrackBar1Change'#8'Position'#2#0#8'TabOrder'#2#4#7'Visib' +'le'#8#0#0#0#10'TStatusBar'#10'StatusBar1'#4'Left'#2#0#6'Height'#2#20#3'Top' +#3#134#1#5'Width'#3'I'#4#6'Panels'#14#1#5'Width'#3#250#0#0#1#5'Width'#2'2'#0 +#0#11'SimplePanel'#8#0#0#9'TMainMenu'#9'MainMenu1'#4'left'#2#14#3'top'#2#5#0 +#9'TMenuItem'#9'MenuItem1'#7'Caption'#6#4'File'#0#9'TMenuItem'#8'OpenMenu'#7 +'Caption'#6#9'Open data'#8'ShortCut'#3'O@'#7'OnClick'#7#13'OpenDataClick'#0#0 +#9'TMenuItem'#7'FFTMenu'#7'Caption'#6#14'Power spectrum'#7'Visible'#8#7'OnCl' +'ick'#7#12'FFTitemClick'#0#0#9'TMenuItem'#8'SaveMenu'#7'Caption'#6#14'Save a' +'s bitmap'#7'OnClick'#7#15'SaveasEMF1Click'#0#0#9'TMenuItem'#13'Extract4Droi' +'s'#7'Caption'#6#25'Create resting state ROIs'#7'OnClick'#7#18'Extract4Drois' +'Click'#0#0#9'TMenuItem'#9'BatchMenu'#7'Caption'#6#18'Batch process data'#7 +'OnClick'#7#15'Batchdata1Click'#0#0#9'TMenuItem'#12'FSLBatchMenu'#7'Caption' +#6#17'FSL batch process'#7'OnClick'#7#14'FSLbatch1Click'#0#0#9'TMenuItem'#9 +'CloseMenu'#7'Caption'#6#12'Close window'#8'ShortCut'#3'W@'#7'OnClick'#7#17 +'Closewindow1Click'#0#0#0#9'TMenuItem'#5'Edit1'#7'Caption'#6#4'Edit'#0#9'TMe' +'nuItem'#8'CopyMenu'#7'Caption'#6#4'Copy'#7'OnClick'#7#10'Copy1Click'#0#0#0#0 +#22'TSelectDirectoryDialog'#22'SelectDirectoryDialog1'#4'left'#3#184#0#0#0#0 ]); �������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/examplefmri.bat����������������������������������������������������0000755�0001750�0001750�00000000305�10416600172�017177� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������start /MAX mricron .\templates\ch2bet.nii.gz -s 3 -c -0 -l 20 -h 140 -b 40 -t -1 -r .\example\fmrir.ini -o .\example\saccades.nii.gz -l 1.96 -h 5 -z -o .\example\attention.nii.gz -l 1.96 -h 5 -z -x���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/ReadFloat.pas������������������������������������������������������0000755�0001750�0001750�00000002165�11450447710�016560� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit ReadFloat; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls, Spin; type { TReadFloatForm } TReadFloatForm = class(TForm) ReadFloatEdit: TFloatSpinEdit; OKBtn: TButton; ReadFloatLabel: TLabel; procedure OKBtnClick(Sender: TObject); function GetFloat(lStr: string; lMin,lDefault,lMax: double): double; private { private declarations } public { public declarations } end; var ReadFloatForm: TReadFloatForm; implementation { TReadFloatForm } function TReadFloatForm.GetFloat(lStr: string; lMin,lDefault,lMax: double): double; begin //result := lDefault; ReadFloatLabel.caption := lStr+' ['+floattostr(lMin)+'..'+floattostr(lMax)+']'; ReadFloatEdit.MinValue := lMin; ReadFloatEdit.MaxValue := lMax; ReadFloatEdit.Value := lDefault; ReadFloatForm.ShowModal; result := ReadFloatEdit.value; end; procedure TReadFloatForm.OKBtnClick(Sender: TObject); begin ReadFloatForm.ModalResult := mrOK; end; initialization {$I ReadFloat.lrs} end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/stat.pas�����������������������������������������������������������0000755�0001750�0001750�00000033472�11326425450�015676� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Unit stat; interface uses Dialogs,define_types; const ITMAX = 300; EPS = 3.0e-7; kMaxFact = 1700; {<= 1754} gFactRAready : boolean = false; type FactRA = array[0..kMaxFact] of extended; var gFactRA : FactRA; FUNCTION betai(a,b,x: double): double; procedure AlertMsg (pWarningStr: String); function gammq( a,x: real): real; procedure Chi2x2 (A, B, C, D: integer; var pMinExp, pChi, p, puChi, pup: double); function Liebermeister (A,B,C,D: integer): extended; procedure EstimateFDR(lnTests: integer; Ps: SingleP; var lFDR05, lFDR01: double); procedure EstimateFDR2(lnTests: integer; var Ps: SingleP; var lFDR05, lFDR01,lnegFDR05, lnegFDR01: double); function Fisher1TailMidP (A,B,C,D: integer): double; { use instead of chi2x2: returns p-value} procedure InitFact; implementation procedure InitFact; var lX: word; begin gFactRA[0]:= 1; gFactRA[1] := 1; for lx := 2 to kMaxFact do gFactRA[lx] := lx * gFactRA[lx-1]; gFactRAready := true; end; function FisherX (A,B,C,D: integer): double; {FisherExactTest, use instead of chi} {FisherX computes odds for this specific config only, not more extreme cases} {alternate to Chi Square, see Siegel & Castellan, Nonparametric Statistics} {use instead of Chi when n <= 20} {A= X hits, B= control hits, C = X misses, D = control misses} var N: word; begin N := A+B+C+D; if (N <= kMaxFact) and (A>=0) and (B>=0) and (C>=0) and (D>=0) and (N > 0) then begin FisherX := ( (gFactRA[A+B]/gFactRA[A])* (gFactRA[B+D]/gFactRA[B])* (gFactRA[A+C]/gFactRA[C])* (gFactRA[C+D]/gFactRA[D]) )/ gFactRA[N]; end else FisherX := 0; end; function MidPKingFisher (lSmal,lCross1,lCross2,lSmalDiag: integer): extended; var lProb1, lProb2: extended; lA,lB,lC,lD,lCnt: integer; l1st : boolean; begin lA :=lSmal; lB:=lCross1; lC:=lCross2; lD:=lSmalDiag; lProb1:=0; l1st := true; //set to true for midP for lCnt := lA downto 0 do begin if l1st then lProb1 := 0.5* FisherX(lA,lB,lC,lD) else lProb1 := lProb1 + FisherX(lA,lB,lC,lD); l1st := false; dec(lA); dec(lD); inc(lB); inc(lC); end; lA :=lSmal; lB:=lCross1; lC:=lCross2; lD:=lSmalDiag; lProb2:=0; l1st := true; //alfa -set to true for MidP while (lB >= 0) and (lC >= 0) do begin if l1st then lProb2 := 0.5* FisherX(lA,lB,lC,lD) else lProb2 := lProb2 + FisherX(lA,lB,lC,lD); l1st := false; inc(lA); inc(lD); dec(lB); dec(lC); end; if lProb1 < lProb2 then result := lProb1 else result := lProb2; //result := lprob1; end; function Lieber (lSmal,lCross1,lCross2,lSmalDiag: integer): extended; var lA,lB,lC,lD,lCnt: integer; begin lA :=lSmal; lB:=lCross1+1; lC:=lCross2+1; lD:=lSmalDiag; result :=0; for lCnt := lA downto 0 do begin result := result + FisherX(lA,lB,lC,lD); dec(lA); dec(lD); inc(lB); inc(lC); end; //TabbedNotebookDlg.caption := realtostr(result,6) ; //TabbedNotebookDlg.caption := realtostr(result,6) ; if result <= 0.5 then exit; lA :=lSmal+1; lB:=lCross1; lC:=lCross2; lD:=lSmalDiag+1; result:=0; while (lB >= 0) and (lC >= 0) do begin result := result + FisherX(lA,lB,lC,lD); inc(lA); inc(lD); dec(lB); dec(lC); end; end; function Liebermeister (A,B,C,D: integer): extended; {A= X hits, B= control hits, C = X misses, D = control misses} begin result := 1; if (A+B+C+D)<1 then exit; if not gFactRAready then InitFact; if (A<=B) and (A<=C) and (A<=D) then {lA smallest} result :=Lieber(A,B,C,D) else if (B<=C) and (B<=D) then {lB smallest} result :=Lieber(B,A,D,C) else if (C<=D) then {lC smallest} result :=Lieber(C,D,A,B) else {d smallest} result :=Lieber(D,C,B,A); if ((A+C)>0) and ((B+D)>0) then begin if (A/(A+C)) < (B/(B+D)) then result := -result; end; end; (*function Liebermeister (Ain,Bin,Cin,Din: integer): extended; var A,B,C,D: integer; {A= X hits, B= control hits, C = X misses, D = control misses} begin A := Ain; B := Bin; C := Cin; D := Din; if (A+B+C+D)<1 then begin result := 1; exit; end; //easy way to calculate Lieberman - make more extreme, then calculate Fisher if abs(A-D) > abs(B-C) then begin inc(A); inc(D); end else begin inc(B); inc(C); end; if not gFactRAready then InitFact; if (A<=B) and (A<=C) and (A<=D) then {lA smallest} result :=KingFisher(A,B,C,D) else if (B<=C) and (B<=D) then {lB smallest} result :=KingFisher(B,A,D,C) else if (C<=D) then {lC smallest} result :=KingFisher(C,D,A,B) else {d smallest} result :=KingFisher(D,C,B,A); if ((A+C)>0) and ((B+D)>0) then begin if (A/(A+C)) < (B/(B+D)) then result := -result; end; end;*) function Fisher1TailMidP (A,B,C,D: integer): double; {A= X hits, B= control hits, C = X misses, D = control misses} begin if (A+B+C+D)<1 then begin result := 1; exit end; if not gFactRAready then InitFact; if (A<=B) and (A<=C) and (A<=D) then {lA smallest} result :=MidPKingFisher(A,B,C,D) else if (B<=C) and (B<=D) then {lB smallest} result :=MidPKingFisher(B,A,D,C) else if (C<=D) then {lC smallest} result :=MidPKingFisher(C,D,A,B) else {d smallest} result :=MidPKingFisher(D,C,B,A); if ((A+C)>0) and ((B+D)>0) then begin if (A/(A+C)) < (B/(B+D)) then result := -result; end; end; (*procedure Sort (first, last: integer; var DynDataRA:SingleP); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} {less memory intensive than recursive quicksort} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n, nn, m, lognb2, l, k, j, i: INTEGER; swap: Single; begin n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 1 to k do begin i := j; 555: {<- LABEL} l := i + m; if (DynDataRA^[l] < DynDataRA^[i]) then begin swap := DynDataRA^[i]; DynDataRA^[i] := DynDataRA^[l]; DynDataRA^[l] := swap; i := i - m; if (i >= 1) then goto 555; end end end end;//sort *) procedure qsort(lower, upper : integer; var Data:SingleP); //40ms - very recursive... var left, right : integer; pivot,lswap: single; begin pivot:=Data^[(lower+upper) div 2]; left:=lower; right:=upper; while left<=right do begin while Data^[left] < pivot do left:=left+1; { Parting for left } while Data^[right] > pivot do right:=right-1;{ Parting for right} if left<=right then begin { Validate the change } lswap := Data^[left]; Data^[left] := Data^[right]; Data^[right] := lswap; left:=left+1; right:=right-1; end; //validate end;//while left <=right if right>lower then qsort(lower,right,Data); { Sort the LEFT part } if upper>left then qsort(left ,upper,data); { Sort the RIGHT part } end; procedure EstimateFDR2(lnTests: integer; var Ps: SingleP; var lFDR05, lFDR01,lnegFDR05, lnegFDR01: double); var lInc: integer; lrPs,Qs: SingleP; begin //rank Pvalues //ShaQuickSort(lnTests,Singlep0(Ps[1])); qSort(1,lnTests,Ps); //qSort(1,lnTests,Ps); GetMem(Qs,lnTests*sizeof(single)); //next findcrit FDR05 for lInc := 1 to lnTests do Qs^[lInc] := (0.05*lInc)/lnTests; lFDR05 := 0; for lInc := 1 to lnTests do if Ps^[lInc] <= Qs^[lInc] then lFDR05 := Ps^[lInc]; //next findcrit FDR01 for lInc := 1 to lnTests do Qs^[lInc] := (0.01*lInc)/lnTests; lFDR01 := 0; for lInc := 1 to lnTests do if Ps^[lInc] <= Qs^[lInc] then lFDR01 := Ps^[lInc]; //reverse GetMem(lrPs,lnTests*sizeof(single)); for lInc := 1 to lnTests do lrPs^[lInc] := 1- Ps^[lnTests-lInc+1]; for lInc := 1 to lnTests do Qs^[lInc] := (0.05*lInc)/lnTests; lnegFDR05 := 0; for lInc := 1 to lnTests do if lrPs^[lInc] <= Qs^[lInc] then lnegFDR05 := lrPs^[lInc]; //next findcrit FDR01 for lInc := 1 to lnTests do Qs^[lInc] := (0.01*lInc)/lnTests; lnegFDR01 := 0; for lInc := 1 to lnTests do if lrPs^[lInc] <= Qs^[lInc] then lnegFDR01 := lrPs^[lInc]; FreeMem(lrPs); Freemem(Qs); end; procedure EstimateFDR(lnTests: integer; Ps: SingleP; var lFDR05, lFDR01: double); var lInc: integer; Qs: SingleP; begin //rank Pvalues qSort(1,lnTests,Ps); {lStr := 'sort='; for lInc := 1 to knTests do lStr := lStr+realtostr(Ps[lInc],4)+','; Memo1.Lines.Add(lStr); } GetMem(Qs,lnTests*sizeof(single)); //next findcrit FDR05 for lInc := 1 to lnTests do Qs^[lInc] := (0.05*lInc)/lnTests; lFDR05 := 0; for lInc := 1 to lnTests do if Ps^[lInc] <= Qs^[lInc] then lFDR05 := Ps^[lInc]; //next findcrit FDR01 for lInc := 1 to lnTests do Qs^[lInc] := (0.01*lInc)/lnTests; lFDR01 := 0; for lInc := 1 to lnTests do if Ps^[lInc] <= Qs^[lInc] then lFDR01 := Ps^[lInc]; Freemem(Qs); end; procedure AlertMsg (pWarningStr: String); begin MessageDLG(pWarningStr, mtWarning,[mbOK],0); end; function gammln (xx: double): double; {Numerical Recipes for Pascal, p 177} const stp = 2.50662827465; var x, tmp, ser: double; begin x := xx - 1.0; tmp := x + 5.5; tmp := (x + 0.5) * ln(tmp) - tmp; ser := 1.0 + 76.18009173 / (x + 1.0) - 86.50532033 / (x + 2.0) + 24.01409822 / (x + 3.0) - 1.231739516 / (x + 4.0) + 0.120858003e-2 / (x + 5.0) - 0.536382e-5 / (x + 6.0); gammln := tmp + ln(stp * ser) end; {procedure gammln} FUNCTION betacf(a,b,x: double): double; LABEL 1; CONST itmax=100; eps=3.0e-7; VAR tem,qap,qam,qab,em,d: double; bz,bpp,bp,bm,az,app: double; am,aold,ap: double; m: integer; BEGIN am := 1.0; bm := 1.0; az := 1.0; qab := a+b; qap := a+1.0; qam := a-1.0; bz := 1.0-qab*x/qap; FOR m := 1 TO itmax DO BEGIN em := m; tem := em+em; d := em*(b-m)*x/((qam+tem)*(a+tem)); ap := az+d*am; bp := bz+d*bm; d := -(a+em)*(qab+em)*x/((a+tem)*(qap+tem)); app := ap+d*az; bpp := bp+d*bz; aold := az; am := ap/bpp; bm := bp/bpp; az := app/bpp; bz := 1.0; IF ((abs(az-aold)) < (eps*abs(az))) THEN GOTO 1 END; writeln('pause in BETACF'); writeln('a or b too big, or itmax too small'); readln; 1: betacf := az END; FUNCTION betai(a,b,x: double): double; VAR bt: double; BEGIN IF ((x < 0.0) OR (x > 1.0)) THEN BEGIN writeln('pause in routine BETAI'); readln END; IF ((x = 0.0) OR (x = 1.0)) THEN bt := 0.0 ELSE bt := exp(gammln(a+b)-gammln(a)-gammln(b) +a*ln(x)+b*ln(1.0-x)); IF (x < ((a+1.0)/(a+b+2.0))) THEN betai := bt*betacf(a,b,x)/a ELSE betai := 1.0-bt*betacf(b,a,1.0-x)/b END; procedure gser(var gamser, a,x, gln: real); var n: integer; sum, del, ap: real; begin gln := gammln(a); if x <= 0.0 then begin if x < 0.0 then AlertMsg('x less then 0 in routine GSER'); gamser:= 0.0; end else begin ap := a; sum := 1.0/a; del := sum; for n := 1 to ITMAX do begin ap := ap + 1; del := del * (x/ap); sum := sum + del; if (abs(del) < abs((sum)*EPS) )then begin gamser := sum * exp(-x+a*ln(x)-gln); exit; end; end; Alertmsg('GSER error: ITMAX too small for requested a-value'); end; end; procedure gcf(var gammcf: real; a,x, gln: real); var n: integer; gold,fac,b1,b0,a0,g,ana,anf,an,a1: real; begin fac := 1.0; b1 := 1.0; b0 := 0.0; a0 := 1.0; gold := 0.0; gln := gammln(a); a1 := x; for n := 1 to ITMAX do begin an :=(n); ana := an - a; a0 := (a1 + a0*ana)*fac; b0 := (b1 + b0*ana)*fac; anf := an * fac; a1 := x*a0+anf*a1; b1 := x*b0+anf*b1; if a1 <> 0 then begin fac := 1.0/a1; g := b1*fac; if (abs((g-gold)/g)<EPS) then begin gammcf := exp(-x+a*ln(x)-gln)*g; exit; end; gold := g; end; end; Alertmsg('GCF error: ITMAX too small for requested a-value'); end; function gammq( a,x: real): real; var gamser, gammcf, gln: real; begin gammq := 0; if (x < 0) or (a <= 0.0) then alertmsg('Invalid arguments in routine GAMMQ') else begin if (x < (a+1.0)) then begin gser(gamser,a,x,gln); gammq := 1.0 - gamser; end else begin gcf(gammcf,a,x,gln); gammq := gammcf; end; end; end; procedure Chi2x2 (A, B, C, D: integer; var pMinExp, pChi, p, puChi, pup: double); {A= X hits, B= control hits, C = X misses, D = control misses} var lA, lB, lC, lD, lN: extended; {AEXp, BExp, CExp, Dexp, } lSameOdds: boolean; begin lA := A; {convert to extended} lB := B; lC := C; lD := D; ln := lA + lB + lC + lD; if lN > 0 then begin {avoid divide by 0} pMinExp := ((lA + lB) * (lA + lC)) / lN; if (((lA + lB) * (lB + lD)) / lN) < pMinExp then pMinExp := ((lA + lB) * (lB + lD)) / lN; if (((lC + lD) * (lA + lC)) / lN) < pMinExp then pMinExp := ((lC + lD) * (lA + lC)) / lN; if (((lC + lD) * (lB + lD)) / lN) < pMinExp then pMinExp := ((lC + lD) * (lB + lD)) / lN; end else pMinExp := 0; lSameOdds := false; if (lC > 0) and (lD > 0) then begin if (lA / lC) = (lB / lD) then lSameOdds := true; end; if (lC = 0) and (lD = 0) then lSameOdds := true; if ((lA+lC) = 0) or ((lB+lD) = 0) then lSameOdds := true; if (lSameOdds = true) then begin pChi := 0; {same odds} p := 1.0; puChi := 0; pup := 1.0; end else begin puChi := ((sqr((lA * lD) - (lB * lC))) * lN) / ((la + lb) * (lc + ld) * (lb + ld) * (la + lc)); pup := gammq(0.5, 0.5 * puChi); {half df} pChi := ((sqr(abs((lA * lD) - (lB * lC)) - (0.5 * lN))) * lN) / ((la + lb) * (lc + ld) * (lb + ld) * (la + lc)); p := gammq(0.5, 0.5 * pChi); end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/about.pas����������������������������������������������������������0000755�0001750�0001750�00000002445�12151703722�016027� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit about; interface uses {$IFDEF FPC}LResources,{$ELSE} ShellAPI, {$ENDIF} {$IFNDEF Unix} Windows,{$ENDIF} SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, define_types; type { TAboutForm } TAboutForm = class(TForm) HomepageLabel: TLabel; Panel2: TPanel; Panel1: TPanel; ThreadLabel: TLabel; procedure FormCreate(Sender: TObject); procedure HomePageClick(Sender: TObject); procedure Panel1Click(Sender: TObject); procedure Panel1DragDrop(Sender, Source: TObject; X, Y: Integer); private { Private declarations } public { Public declarations } end; var AboutForm: TAboutForm; implementation {$IFNDEF FPC} {$R *.DFM} {$ENDIF} procedure TAboutForm.FormCreate(Sender: TObject); begin HomepageLabel.caption := 'www.mricro.com :: '+kMRIcronVers ; end; procedure TAboutForm.HomePageClick(Sender: TObject); begin {$IFDEF FPC} {$ELSE} ShellExecute (0, Nil, 'http://www.mricro.com', Nil, Nil, SW_ShowDefault); {$ENDIF} end; procedure TAboutForm.Panel1Click(Sender: TObject); begin end; procedure TAboutForm.Panel1DragDrop(Sender, Source: TObject; X, Y: Integer); begin //showmessage('x'); end; {$IFDEF FPC} initialization {$I about.lrs} {$ENDIF} end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/manifest.res�������������������������������������������������������0000755�0001750�0001750�00000001434�10724275506�016536� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ������������������������� ���������0���������<?xml version="1.0" encoding="UTF-8" standalone="yes"?><assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="CompanyName.ProductName.YourApp" type="win32"/><description>Your application description here.</description><dependency><dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/></dependentAssembly></dependency><trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"><security><requestedPrivileges><requestedExecutionLevel level="asInvoker" uiAccess="false"/></requestedPrivileges></security></trustInfo></assembly>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/mricron.lpr��������������������������������������������������������0000755�0001750�0001750�00000003214�12303377330�016374� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������program mricron; {$mode objfpc}{$H+} uses {$IFDEF UNIX} cthreads, {$ENDIF} Interfaces, // this includes the LCL widgetset Forms, nifti_img_view, nifti_hdr_view, about, Text, ReadInt, histoform, autoroi, ROIfilt, render, MultiSlice, CropEdges, bet, mni, voismooth, prefs, perisettings, graphx, cutout, ReadFloat, landmarks, batchstatselect, nii_label; {$IFNDEF UNIX} {$IFDEF FPC} {$R manifest.res} {$ELSE} {$R *.res}//windows icon {$ENDIF} {$ENDIF} {$IFDEF WINDOWS}{$R mricron.rc}{$ENDIF} begin Application.Title:='MRIcron'; Application.Initialize; Application.CreateForm(TImgForm, ImgForm); Application.CreateForm(THdrForm, HdrForm); Application.CreateForm(TAnatForm, AnatForm); Application.CreateForm(TAboutForm, AboutForm); Application.CreateForm(TTextForm, TextForm); Application.CreateForm(TReadIntForm, ReadIntForm); Application.CreateForm(TAutoROIForm, AutoROIForm); Application.CreateForm(THistogramForm, HistogramForm); Application.CreateForm(TFilterROIform, FilterROIform); Application.CreateForm(TMultiSliceForm, MultiSliceForm); Application.CreateForm(TRenderForm, RenderForm); Application.CreateForm(TCropEdgeForm, CropEdgeForm); Application.CreateForm(TBETForm, BETForm); Application.CreateForm(TMNIForm, MNIForm); Application.CreateForm(Tvoismoothform, voismoothform); Application.CreateForm(TPrefForm, PrefForm); Application.CreateForm(TPSForm, PSForm); Application.CreateForm(TGraph4DForm, Graph4DForm); Application.CreateForm(TCutoutForm, CutoutForm); Application.CreateForm(TReadFloatForm, ReadFloatForm); Application.Run; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/cropedges.lrs������������������������������������������������������0000755�0001750�0001750�00000004534�12151704170�016704� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TCropEdgeForm','FORMDATA',[ 'TPF0'#13'TCropEdgeForm'#12'CropEdgeForm'#4'Left'#3'2'#2#6'Height'#3#142#0#3 +'Top'#3#209#0#5'Width'#3#142#1#13'ActiveControl'#7#5'DEdit'#11'BorderIcons' +#11#12'biSystemMenu'#0#11'BorderStyle'#7#8'bsDialog'#7'Caption'#6#10'Crop Ed' +'ges'#12'ClientHeight'#3#142#0#11'ClientWidth'#3#142#1#21'Constraints.MaxHei' +'ght'#3'A'#1#20'Constraints.MaxWidth'#3#142#1#21'Constraints.MinHeight'#2#12 +#20'Constraints.MinWidth'#3#142#1#8'OnCreate'#7#10'FormCreate'#6'OnHide'#7#8 +'FormHide'#6'OnShow'#7#8'FormShow'#8'Position'#7#14'poScreenCenter'#10'LCLVe' +'rsion'#6#7'1.0.2.0'#0#12'TSpeedButton'#9'CancelBtn'#4'Left'#3'@'#1#6'Height' +#2#25#3'Top'#2'h'#5'Width'#2'A'#7'Caption'#6#6'Cancel'#9'NumGlyphs'#2#0#7'On' +'Click'#7#14'CancelBtnClick'#0#0#12'TSpeedButton'#8'ApplyBtn'#4'Left'#3#0#1#6 +'Height'#2#25#3'Top'#2'h'#5'Width'#2'A'#7'Caption'#6#5'Apply'#9'NumGlyphs'#2 +#0#7'OnClick'#7#13'ApplyBtnClick'#0#0#12'TSpeedButton'#13'CropFileSzBtn'#4'L' +'eft'#3#136#0#6'Height'#2#25#3'Top'#2'h'#5'Width'#2'i'#7'Caption'#6#12'Save ' +'Cropped'#9'NumGlyphs'#2#0#7'OnClick'#7#18'CropFileSzBtnClick'#0#0#9'TSpinEd' +'it'#5'DEdit'#4'Left'#2'9'#6'Height'#2#21#3'Top'#2#8#5'Width'#2'H'#8'MaxValu' +'e'#3#255#0#8'OnChange'#7#14'CropEditChange'#8'TabOrder'#2#0#5'Value'#2#8#0#0 +#9'TSpinEdit'#5'PEdit'#4'Left'#2#8#6'Height'#2#21#3'Top'#2')'#5'Width'#2'H'#8 +'MaxValue'#3#255#0#8'OnChange'#7#14'CropEditChange'#8'TabOrder'#2#1#5'Value' +#2#8#0#0#9'TSpinEdit'#5'AEdit'#4'Left'#2'h'#6'Height'#2#21#3'Top'#2')'#5'Wid' +'th'#2'H'#8'MaxValue'#3#255#0#8'OnChange'#7#14'CropEditChange'#8'TabOrder'#2 +#2#5'Value'#2#8#0#0#9'TSpinEdit'#5'VEdit'#4'Left'#2'9'#6'Height'#2#21#3'Top' +#2'I'#5'Width'#2'H'#8'MaxValue'#3#255#0#8'OnChange'#7#14'CropEditChange'#8'T' +'abOrder'#2#3#5'Value'#2#8#0#0#9'TSpinEdit'#5'REdit'#4'Left'#3'7'#1#6'Height' +#2#21#3'Top'#2')'#5'Width'#2'H'#8'MaxValue'#3#255#0#8'OnChange'#7#14'CropEdi' +'tChange'#8'TabOrder'#2#4#5'Value'#2#8#0#0#9'TSpinEdit'#5'LEdit'#4'Left'#3 +#224#0#6'Height'#2#21#3'Top'#2')'#5'Width'#2'H'#8'MaxValue'#3#255#0#8'OnChan' +'ge'#7#14'CropEditChange'#8'TabOrder'#2#5#5'Value'#2#8#0#0#6'TTimer'#6'Timer' +'1'#7'Enabled'#8#8'Interval'#3#150#0#7'OnTimer'#7#11'Timer1Timer'#4'left'#3 +'H'#1#3'top'#2'H'#0#0#0 ]); ��������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/graphx.lfm���������������������������������������������������������0000755�0001750�0001750�00000023235�11425734216�016206� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object Graph4DForm: TGraph4DForm Left = 486 Height = 429 Top = 156 Width = 1097 ActiveControl = TREdit Caption = '4D Timeline Viewer' ClientHeight = 410 ClientWidth = 1097 Menu = MainMenu1 OnClose = FormClose OnCreate = FormCreate OnResize = FormResize OnShow = FormShow Position = poScreenCenter LCLVersion = '0.9.29' object Image1: TImage Left = 0 Height = 354 Top = 36 Width = 1097 Align = alClient end object FourDBar: TPanel Left = 0 Height = 36 Top = 0 Width = 1097 Align = alTop BevelOuter = bvNone ClientHeight = 36 ClientWidth = 1097 TabOrder = 0 object OpenDataBtn: TSpeedButton Left = 11 Height = 25 Top = 7 Width = 95 Caption = 'Open Data' Color = clBtnFace NumGlyphs = 0 OnClick = OpenDataClick end object RefreshBtn: TSpeedButton Left = 112 Height = 30 Top = 4 Width = 30 Color = clBtnFace Glyph.Data = { D6080000424DD608000000000000360000002800000018000000170000000100 200000000000A008000064000000640000000000000000000000FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF2F0000 FF9C0000FFB90000FFCA0000FFBF0000FF0CFFFFFF00FFFFFF00FFFFFF000000 FF0DFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF320000FFA40000FFF00000 FFFF0000FFFF0000FFBE0000FF190000FF160000FF6A0000FF990000FFC20000 FF69FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF000000FF630000FFE50000FFFF0000FFFF0000 FFFF0000FFE40000FF080000FF0F0000FFE00000FFFF0000FFFC0000FF61FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF000000FF010000FF880000FFF40000FFFF0000FFFF0000FFFF0000 FFFF0000FFEE0000FF18FFFFFF000000FF910000FFFF0000FFE60000FFF60000 FFA70000FF28FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF000000FF970000FFFE0000FFFF0000FFFF0000FFFF0000FFFF0000 FFCC0000FF60FFFFFF00FFFFFF000000FF180000FFE70000FF420000FF940000 FFF20000FFEA0000FF900000FF10FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FF650000FFF80000FFFF0000FFFF0000FFFF0000FFDE0000FF7F0000 FF06FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FFA20000FF20FFFFFF000000 FF470000FFCB0000FFFF0000FFDA0000FF50FFFFFF00FFFFFF00FFFFFF000000 FF2F0000FFE20000FFFF0000FFFF0000FFFC0000FFA70000FF17FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF0F0000FF06FFFFFF00FFFF FF000000FF090000FFAB0000FFFF0000FFE40000FF42FFFFFF00FFFFFF000000 FFB60000FFFF0000FFFF0000FFEE0000FF7DFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF000000FF0C0000FFC50000FFFF0000FFCE0000FF060000FF260000 FFF20000FFFF0000FFF50000FF66FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF000000FF2B0000FFE10000FFFF0000FF7A0000FF840000 FFFF0000FFFF0000FF87FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF000000FFAF0000FFFF0000FFA20000FFC30000 FFFF0000FFD70000FF03FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF000000FF8E0000FFFF0000FFB50000FFC90000 FFFF0000FF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF000000FF990000FFFF0000FFC90000FFB50000 FFFF0000FF8EFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF000000FF030000FFD70000FFFF0000FFC30000FFA20000 FFFF0000FFAFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF000000FF870000FFFF0000FFFF0000FF840000FF7A0000 FFFF0000FFE10000FF2BFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF000000FF660000FFF50000FFFF0000FFF20000FF260000FF060000 FFCE0000FFFF0000FFC50000FF0CFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FF7D0000FFEE0000FFFF0000FFFF0000FFB6FFFFFF00FFFFFF000000 FF420000FFE40000FFFF0000FFAB0000FF09FFFFFF00FFFFFF000000FF060000 FF0FFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF170000 FFA70000FFFC0000FFFF0000FFFF0000FFE20000FF2FFFFFFF00FFFFFF00FFFF FF000000FF500000FFDA0000FFFF0000FFCB0000FF47FFFFFF000000FF200000 FFA3FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF060000FF7F0000FFDE0000 FFFF0000FFFF0000FFFF0000FFF80000FF65FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF000000FF100000FF900000FFEA0000FFF20000FF940000FF420000 FFE70000FF18FFFFFF00FFFFFF000000FF600000FFCC0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFE0000FF97FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF000000FF280000FFA70000FFF60000FFE60000 FFFF0000FF91FFFFFF000000FF180000FFEE0000FFFF0000FFFF0000FFFF0000 FFFF0000FFF40000FF880000FF01FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF610000FFFC0000 FFFF0000FFE00000FF0F0000FF080000FFE40000FFFF0000FFFF0000FFFF0000 FFE50000FF63FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF690000FFC20000FF990000 FF6A0000FF160000FF190000FFBE0000FFFF0000FFFF0000FFF00000FFA40000 FF32FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 0040000007BE000000AB00000028FFFFFF000000FF0DFFFFFF00FFFFFF00FFFF FF000000FF0C0000FFBF0000FFCA0000FFB90000FF9C0000FF2FFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } NumGlyphs = 0 OnClick = RefreshBtnClick OnMouseDown = RefreshBtnMouseDown end object TRLabel: TLabel Left = 152 Height = 14 Top = 15 Width = 41 Caption = 'TR (sec)' ParentColor = False end object PlotBtn: TSpeedButton Left = 488 Height = 25 Top = 7 Width = 63 Caption = 'Plot' Color = clBtnFace NumGlyphs = 0 OnClick = PSPlotClick end object TextBtn: TSpeedButton Left = 560 Height = 25 Top = 7 Width = 80 Caption = 'Text' Color = clBtnFace NumGlyphs = 0 OnClick = PSTextClick end object TREdit: TFloatSpinEdit Left = 240 Height = 21 Top = 9 Width = 82 DecimalPlaces = 4 Increment = 1 MaxValue = 100000000 MinValue = 0 TabOrder = 0 Value = 0 end object HSpeedDrop: TComboBox Left = 352 Height = 21 Top = 5 Width = 120 ItemHeight = 13 Items.Strings = ( 'To Fit' 'x1' 'x2' 'x3' 'x4' 'x5' 'x6' 'x7' 'x8' 'x9' 'x10' ) OnChange = TrackBar1Change Style = csDropDownList TabOrder = 1 end object MinEdit: TFloatSpinEdit Left = 656 Height = 21 Top = 6 Width = 82 DecimalPlaces = 4 Increment = 1 MaxValue = 100 MinValue = 0 TabOrder = 2 Value = 0 end object MaxEdit: TFloatSpinEdit Left = 768 Height = 21 Top = 6 Width = 82 DecimalPlaces = 4 Increment = 1 MaxValue = 100 MinValue = 0 TabOrder = 3 Value = 0 end object TrackBar1: TTrackBar Left = 864 Height = 29 Top = 4 Width = 204 OnChange = TrackBar1Change Position = 0 TabOrder = 4 Visible = False end end object StatusBar1: TStatusBar Left = 0 Height = 20 Top = 390 Width = 1097 Panels = < item Width = 250 end item Width = 50 end> SimplePanel = False end object MainMenu1: TMainMenu left = 14 top = 5 object MenuItem1: TMenuItem Caption = 'File' object OpenMenu: TMenuItem Caption = 'Open data' ShortCut = 16463 OnClick = OpenDataClick end object FFTMenu: TMenuItem Caption = 'Power spectrum' Visible = False OnClick = FFTitemClick end object SaveMenu: TMenuItem Caption = 'Save as bitmap' OnClick = SaveasEMF1Click end object Extract4Drois: TMenuItem Caption = 'Create resting state ROIs' OnClick = Extract4DroisClick end object BatchMenu: TMenuItem Caption = 'Batch process data' OnClick = Batchdata1Click end object FSLBatchMenu: TMenuItem Caption = 'FSL batch process' OnClick = FSLbatch1Click end object CloseMenu: TMenuItem Caption = 'Close window' ShortCut = 16471 OnClick = Closewindow1Click end end object Edit1: TMenuItem Caption = 'Edit' object CopyMenu: TMenuItem Caption = 'Copy' OnClick = Copy1Click end end end object SelectDirectoryDialog1: TSelectDirectoryDialog left = 184 end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/render.lrs���������������������������������������������������������0000755�0001750�0001750�00000043655�12370426516�016227� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TRenderForm','FORMDATA',[ 'TPF0'#11'TRenderForm'#10'RenderForm'#4'Left'#3'9'#1#6'Height'#3#0#2#3'Top'#3 +#165#0#5'Width'#3#187#3#13'ActiveControl'#7#11'AzimuthEdit'#7'Caption'#6#13 +'Volume Render'#12'ClientHeight'#3#0#2#11'ClientWidth'#3#187#3#9'Font.Name'#6 +#13'MS Sans Serif'#4'Menu'#7#9'MainMenu1'#8'OnCreate'#7#10'FormCreate'#6'OnH' +'ide'#7#8'FormHide'#6'OnShow'#7#8'FormShow'#8'Position'#7#14'poScreenCenter' +#10'LCLVersion'#6#8'1.0.12.0'#0#6'TPanel'#9'RenderBar'#4'Left'#2#0#6'Height' +#2' '#3'Top'#2#0#5'Width'#3#187#3#5'Align'#7#5'alTop'#10'BevelOuter'#7#6'bvN' +'one'#12'ClientHeight'#2' '#11'ClientWidth'#3#187#3#8'TabOrder'#2#0#0#6'TLab' +'el'#6'Label4'#4'Left'#3#152#0#6'Height'#2#18#3'Top'#2#5#5'Width'#2':'#7'Cap' +'tion'#6#9'Elevation'#11'ParentColor'#8#0#0#6'TLabel'#6'Label1'#4'Left'#2#4#6 +'Height'#2#18#3'Top'#2#5#5'Width'#2'5'#7'Caption'#6#7'Azimuth'#11'ParentColo' +'r'#8#0#0#12'TSpeedButton'#10'RefreshBtn'#4'Left'#3'('#1#6'Height'#2#31#4'Hi' +'nt'#6'"Generate high-resolution rendering'#3'Top'#2#0#5'Width'#2'('#10'Glyp' +'h.Data'#10'z'#8#0#0'v'#8#0#0'BMv'#8#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#24#0#0#0 +#22#0#0#0#1#0' '#0#0#0#0#0'@'#8#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#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#0#0#255#255#0#0 +#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#255#255#255#255#255 +#255#255#255#255#255#255#255#255#255#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#255#255#0#0#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#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#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#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0 +#255#255#0#0#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#0#0#255#255#0#0#255#255#0#0#255#255 +#0#0#255#255#0#0#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#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#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 +#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#255#255#255#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#0#0#255#255 +#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#255#255#255#255 +#255#255#255#255#255#255#255#255#255#255#255#255#0#0#255#255#0#0#255#255#0#0 +#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#255#255#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#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#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0 +#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#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255 +#0#0#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#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#255#255#0#0#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#0#0#255#255 +#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#255#255#255#255#255#255#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#0#0#255#255#0#0#255#255 +#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#255#255#255#255#255#255#255 +#255#255#255#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#255#255#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#0#0#255#255#0#0#255#255 +#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#255#255#255#255#255#255#255 +#255#255#255#255#255#255#255#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0 +#255#255#0#0#255#255#0#0#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#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#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#0#0#255#255#0#0#255#255#0#0#255#255 ,#0#0#255#255#0#0#255#255#0#0#255#255#255#255#255#255#255#255#255#255#255#255 +#255#255#255#255#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0 +#255#255#0#0#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#0#0 +#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#255#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#0#0#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#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#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#255#255#255#255#255#255#255#255#255 +#255#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0 +#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#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 +#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#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#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#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#0#0#255#255#0#0#255#255 +#0#0#255#255#0#0#255#255#0#0#255#255#0#0#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#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#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#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255 +#0#0#255#255#0#0#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255 +#255#255#255#255#255#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255 +#0#0#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#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#0#0#255#255 +#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0 +#255#255#0#0#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#0#0#255#255#0#0#255#255#0#0#255#255 +#0#0#255#255#0#0#255#255#0#0#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#0#0 +#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#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#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255 +#0#0#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#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#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#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#255#255#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#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#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#255#255#255#255#255#255#255#255#255 +#255#255#255#255#255#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255 +#0#0#255#255#9'NumGlyphs'#2#0#7'OnClick'#7#12'RefreshClick'#8'ShowHint'#9#14 +'ParentShowHint'#8#0#0#6'TImage'#14'RenderImageBUP'#3'Tag'#2#2#6'Cursor'#7#7 +'crCross'#4'Left'#3'h'#1#6'Height'#2#12#3'Top'#2#8#5'Width'#2#12#8'AutoSize' +#9#6'Center'#9#11'OnMouseDown'#7#20'RenderImageMouseDown'#11'OnMouseMove'#7 +#20'RenderImageMouseMove'#7'Stretch'#9#7'Visible'#8#0#0#6'TLabel'#6'Label5'#4 +'Left'#3'h'#2#6'Height'#2#18#3'Top'#2#5#5'Width'#2'B'#7'Caption'#6#9'Shading' +' %'#11'ParentColor'#8#0#0#9'TSpinEdit'#11'AzimuthEdit'#4'Left'#2'H'#6'Heigh' +'t'#2#16#3'Top'#2#2#5'Width'#2'F'#9'Increment'#2#30#8'MaxValue'#3'h'#1#8'OnC' +'hange'#7#10'EditChange'#8'TabOrder'#2#0#5'Value'#2'x'#0#0#9'TSpinEdit'#13'E' +'levationEdit'#4'Left'#3#216#0#6'Height'#2#16#3'Top'#2#2#5'Width'#2'F'#9'Inc' +'rement'#2#30#8'MaxValue'#3#180#0#8'MinValue'#3'L'#255#8'OnChange'#7#10'Edit' +'Change'#8'TabOrder'#2#1#5'Value'#2#30#0#0#9'TTrackBar'#9'BiasTrack'#4'Left' +#3'`'#1#6'Height'#2#29#3'Top'#2#2#5'Width'#2'x'#3'Max'#2'd'#8'OnChange'#7#15 +'BiasTrackChange'#8'Position'#2'2'#9'TickStyle'#7#6'tsNone'#8'TabOrder'#2#2#0 +#0#9'TTrackBar'#9'GainTrack'#4'Left'#3#224#1#6'Height'#2#29#3'Top'#2#2#5'Wid' +'th'#2'x'#3'Max'#2'd'#8'OnChange'#7#15'BiasTrackChange'#8'Position'#2'2'#9'T' ,'ickStyle'#7#6'tsNone'#8'TabOrder'#2#3#0#0#9'TSpinEdit'#9'ShadeEdit'#4'Left' +#3#178#2#6'Height'#2#16#3'Top'#2#2#5'Width'#2'F'#9'Increment'#2#10#8'OnChang' +'e'#7#10'EditChange'#8'TabOrder'#2#4#0#0#9'TTrackBar'#9'ClipTrack'#4'Left'#3 +#8#3#6'Height'#2#29#3'Top'#2#2#5'Width'#2'x'#3'Max'#3#231#3#8'OnChange'#7#15 +'ClipTrackChange'#8'Position'#2#0#9'TickStyle'#7#6'tsNone'#8'TabOrder'#2#5#0 +#0#0#10'TScrollBox'#11'RenderPanel'#4'Left'#2#0#6'Height'#3#224#1#3'Top'#2' ' +#5'Width'#3#187#3#18'HorzScrollBar.Page'#3#187#3#18'VertScrollBar.Page'#3#224 +#1#5'Align'#7#8'alClient'#12'ClientHeight'#3#224#1#11'ClientWidth'#3#187#3#8 +'TabOrder'#2#1#0#6'TImage'#11'RenderImage'#3'Tag'#2#2#6'Cursor'#7#7'crCross' +#4'Left'#2#2#6'Height'#2#12#3'Top'#2#2#5'Width'#2#12#8'AutoSize'#9#11'OnMous' +'eDown'#7#20'RenderImageMouseDown'#11'OnMouseMove'#7#20'RenderImageMouseMove' +#7'Stretch'#9#0#0#0#9'TMainMenu'#9'MainMenu1'#4'left'#2#16#3'top'#2' '#0#9'T' +'MenuItem'#8'FileMenu'#7'Caption'#6#4'File'#0#9'TMenuItem'#9'Settings1'#7'Ca' +'ption'#6#13'Open settings'#7'OnClick'#7#14'Settings1Click'#0#0#9'TMenuItem' +#13'Savesettings1'#7'Caption'#6#16'Save settings...'#7'OnClick'#7#18'Saveset' +'tings1Click'#0#0#9'TMenuItem'#5'Save1'#7'Caption'#6#17'Save as bitmap...'#8 +'ShortCut'#3'S@'#7'OnClick'#7#10'Save1Click'#0#0#9'TMenuItem'#15'RotationBMP' +'Menu'#7'Caption'#6#21'Save Rotation Bitmaps'#7'OnClick'#7#20'RotationBMPMen' +'uClick'#0#0#9'TMenuItem'#12'SaveClipMenu'#7'Caption'#6#17'Save clip bitmaps' +#7'OnClick'#7#17'SaveClipMenuClick'#0#0#9'TMenuItem'#6'Close1'#7'Caption'#6 +#12'Close window'#8'ShortCut'#3'W@'#7'OnClick'#7#11'Close1Click'#0#0#0#9'TMe' +'nuItem'#5'Edit1'#7'Caption'#6#4'Edit'#0#9'TMenuItem'#5'Copy1'#7'Caption'#6#4 +'Copy'#7'OnClick'#7#10'Copy1Click'#0#0#0#9'TMenuItem'#7'Volume1'#7'Caption'#6 +#10'Background'#0#9'TMenuItem'#19'RenderBGSurfaceMenu'#7'Caption'#6#18'Air/S' +'kin Threshold'#0#9'TMenuItem'#2'N1'#7'Caption'#6#2'0%'#10'GroupIndex'#2'w'#9 +'RadioItem'#9#7'OnClick'#7#7'N1Click'#0#0#9'TMenuItem'#4'N101'#3'Tag'#2#25#7 +'Caption'#6#3'10%'#7'Checked'#9#10'GroupIndex'#2'w'#9'RadioItem'#9#7'OnClick' +#7#7'N1Click'#0#0#9'TMenuItem'#4'N401'#3'Tag'#2'3'#7'Caption'#6#3'20%'#10'Gr' +'oupIndex'#2'w'#9'RadioItem'#9#7'OnClick'#7#7'N1Click'#0#0#9'TMenuItem'#4'N6' +'01'#3'Tag'#2'L'#7'Caption'#6#3'30%'#10'GroupIndex'#2'w'#9'RadioItem'#9#7'On' +'Click'#7#7'N1Click'#0#0#9'TMenuItem'#4'N801'#3'Tag'#2'e'#7'Caption'#6#3'40%' +#10'GroupIndex'#2'w'#9'RadioItem'#9#7'OnClick'#7#7'N1Click'#0#0#9'TMenuItem' +#4'N403'#3'Tag'#3#128#0#7'Caption'#6#3'50%'#10'GroupIndex'#2'w'#9'RadioItem' +#9#7'OnClick'#7#7'N1Click'#0#0#9'TMenuItem'#4'N404'#3'Tag'#3#152#0#7'Caption' +#6#3'60%'#10'GroupIndex'#2'w'#9'RadioItem'#9#7'OnClick'#7#7'N1Click'#0#0#9'T' +'MenuItem'#4'N405'#3'Tag'#3#178#0#7'Caption'#6#3'70%'#10'GroupIndex'#2'w'#9 +'RadioItem'#9#7'OnClick'#7#7'N1Click'#0#0#0#9'TMenuItem'#17'RenderBGDepthMen' +'u'#7'Caption'#6#12'Search Depth'#0#9'TMenuItem'#8'N1voxel1'#3'Tag'#2#1#7'Ca' +'ption'#6#7'1 voxel'#7'Checked'#9#10'GroupIndex'#2'z'#9'RadioItem'#9#7'OnCli' +'ck'#7#13'N1voxel1Click'#0#0#9'TMenuItem'#9'N2voxels1'#3'Tag'#2#2#7'Caption' +#6#8'2 voxels'#10'GroupIndex'#2'z'#9'RadioItem'#9#7'OnClick'#7#13'N1voxel1Cl' +'ick'#0#0#9'TMenuItem'#9'N4voxels1'#3'Tag'#2#4#7'Caption'#6#8'4 voxels'#10'G' +'roupIndex'#2'z'#9'RadioItem'#9#7'OnClick'#7#13'N1voxel1Click'#0#0#9'TMenuIt' +'em'#9'N8voxels1'#3'Tag'#2#8#7'Caption'#6#8'8 voxels'#10'GroupIndex'#2'z'#9 +'RadioItem'#9#7'OnClick'#7#13'N1voxel1Click'#0#0#9'TMenuItem'#10'N16voxels1' +#3'Tag'#2#12#7'Caption'#6#9'12 voxels'#10'GroupIndex'#2'z'#9'RadioItem'#9#7 +'OnClick'#7#13'N1voxel1Click'#0#0#9'TMenuItem'#9'N16voxels'#3'Tag'#2#16#7'Ca' +'ption'#6#9'16 voxels'#10'GroupIndex'#2'z'#9'RadioItem'#9#7'OnClick'#7#13'N1' +'voxel1Click'#0#0#9'TMenuItem'#9'Infinite1'#3'Tag'#4#255#255#255#127#7'Capti' +'on'#6#8'Infinite'#10'GroupIndex'#2'z'#9'RadioItem'#9#7'OnClick'#7#13'N1voxe' +'l1Click'#0#0#9'TMenuItem'#7'MIPItem'#7'Caption'#6#3'MIP'#10'GroupIndex'#2'z' +#9'RadioItem'#9#7'OnClick'#7#13'N1voxel1Click'#0#0#0#0#9'TMenuItem'#8'Overla' +'y1'#7'Caption'#6#7'Overlay'#0#9'TMenuItem'#24'RenderOverlaySurfaceMenu'#7'C' +'aption'#6#18'Air/Skin Threshold'#0#9'TMenuItem'#3'N01'#7'Caption'#6#2'0%'#7 +'Checked'#9#10'GroupIndex'#2'x'#9'RadioItem'#9#7'OnClick'#7#8'N01Click'#0#0#9 +'TMenuItem'#4'N102'#3'Tag'#2#25#7'Caption'#6#3'10%'#10'GroupIndex'#2'x'#9'Ra' +'dioItem'#9#7'OnClick'#7#8'N01Click'#0#0#9'TMenuItem'#4'N201'#3'Tag'#2'3'#7 +'Caption'#6#3'20%'#10'GroupIndex'#2'x'#9'RadioItem'#9#7'OnClick'#7#8'N01Clic' +'k'#0#0#9'TMenuItem'#4'N301'#3'Tag'#2'L'#7'Caption'#6#3'30%'#10'GroupIndex'#2 +'x'#9'RadioItem'#9#7'OnClick'#7#8'N01Click'#0#0#9'TMenuItem'#4'N402'#3'Tag'#2 +'e'#7'Caption'#6#3'40%'#10'GroupIndex'#2'x'#9'RadioItem'#9#7'OnClick'#7#8'N0' +'1Click'#0#0#9'TMenuItem'#4'N501'#3'Tag'#3#128#0#7'Caption'#6#3'50%'#10'Grou' +'pIndex'#2'x'#9'RadioItem'#9#7'OnClick'#7#8'N01Click'#0#0#9'TMenuItem'#4'N60' +'2'#3'Tag'#3#152#0#7'Caption'#6#3'60%'#10'GroupIndex'#2'x'#9'RadioItem'#9#7 ,'OnClick'#7#8'N01Click'#0#0#9'TMenuItem'#4'N701'#3'Tag'#3#178#0#7'Caption'#6 +#3'70%'#10'GroupIndex'#2'x'#9'RadioItem'#9#7'OnClick'#7#8'N01Click'#0#0#0#9 +'TMenuItem'#22'RenderOverlayDepthMenu'#7'Caption'#6#12'Search Depth'#0#9'TMe' +'nuItem'#8'N1voxel2'#3'Tag'#2#1#7'Caption'#6#7'1 voxel'#7'Checked'#9#10'Grou' +'pIndex'#2'z'#9'RadioItem'#9#7'OnClick'#7#22'OverlayRenderDepthItem'#0#0#9'T' +'MenuItem'#9'N2voxels2'#3'Tag'#2#2#7'Caption'#6#8'2 voxels'#10'GroupIndex'#2 +'z'#9'RadioItem'#9#7'OnClick'#7#22'OverlayRenderDepthItem'#0#0#9'TMenuItem'#9 +'N4voxels2'#3'Tag'#2#4#7'Caption'#6#8'4 voxels'#10'GroupIndex'#2'z'#9'RadioI' +'tem'#9#7'OnClick'#7#22'OverlayRenderDepthItem'#0#0#9'TMenuItem'#9'N8voxels2' +#3'Tag'#2#8#7'Caption'#6#8'8 voxels'#10'GroupIndex'#2'z'#9'RadioItem'#9#7'On' +'Click'#7#22'OverlayRenderDepthItem'#0#0#9'TMenuItem'#10'N12voxels1'#3'Tag'#2 +#12#7'Caption'#6#9'12 voxels'#10'GroupIndex'#2'z'#9'RadioItem'#9#7'OnClick'#7 +#22'OverlayRenderDepthItem'#0#0#9'TMenuItem'#10'N16voxels2'#3'Tag'#2#16#7'Ca' +'ption'#6#9'16 voxels'#10'GroupIndex'#2'z'#9'RadioItem'#9#7'OnClick'#7#22'Ov' +'erlayRenderDepthItem'#0#0#9'TMenuItem'#9'Infinite2'#3'Tag'#4#255#255#255#127 +#7'Caption'#6#8'Infinite'#10'GroupIndex'#2'z'#9'RadioItem'#9#7'OnClick'#7#22 +'OverlayRenderDepthItem'#0#0#0#9'TMenuItem'#7'Search1'#7'Caption'#6#6'Search' +#0#9'TMenuItem'#9'BehindBG1'#7'Caption'#6#9'Any Depth'#10'GroupIndex'#2#17#9 +'RadioItem'#9#7'OnClick'#7#9'SetSearch'#0#0#9'TMenuItem'#8'Infront1'#3'Tag'#2 +#1#7'Caption'#6' Below BG surface [max intensity]'#10'GroupIndex'#2#17#9'Rad' +'ioItem'#9#7'OnClick'#7#9'SetSearch'#0#0#9'TMenuItem'#9'Anydepth1'#3'Tag'#2#2 +#7'Caption'#6#24'Infront/below BG surface'#10'GroupIndex'#2#17#9'RadioItem'#9 +#7'OnClick'#7#9'SetSearch'#0#0#0#0#9'TMenuItem'#8'Quality1'#7'Caption'#6#4'V' +'iew'#0#9'TMenuItem'#10'CutoutMenu'#7'Caption'#6#6'Cutout'#7'OnClick'#7#12'C' +'utout1Click'#0#0#9'TMenuItem'#9'MenuItem1'#7'Caption'#6#1'-'#0#0#9'TMenuIte' +'m'#14'RenderSmoothBG'#7'Caption'#6#17'Smooth Background'#7'Checked'#9#4'Hin' +'t'#6#14'Blur rendering'#7'OnClick'#7#19'RenderSmoothBGClick'#0#0#9'TMenuIte' +'m'#19'RenderSmoothOverlay'#7'Caption'#6#14'Smooth Overlay'#7'Checked'#9#4'H' +'int'#6#14'Blur rendering'#7'OnClick'#7#19'RenderSmoothBGClick'#0#0#9'TMenuI' +'tem'#26'RenderPreciseInterpolation'#7'Caption'#6#21'Precise interpolation'#4 +'Hint'#6'"Use trilinear interpolation [slow]'#7'OnClick'#7#31'RenderPreciseI' +'nterpolationClick'#0#0#9'TMenuItem'#2'N2'#7'Caption'#6#1'-'#0#0#9'TMenuItem' +#11'FlipLRcheck'#7'Caption'#6#8'Flip L/R'#7'OnClick'#7#17'RenderSmoothClick' +#0#0#0#0#6'TTimer'#18'RenderRefreshTimer'#7'Enabled'#8#8'Interval'#3#150#0#7 +'OnTimer'#7#23'RenderRefreshTimerTimer'#4'left'#2'0'#3'top'#2' '#0#0#0 ]); �����������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/ReadInt.pas��������������������������������������������������������0000755�0001750�0001750�00000003434�12332725756�016256� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit ReadInt; interface uses {$IFDEF FPC} LResources,{$ENDIF} Buttons{only Lazarus?},SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Spin; type { TReadIntForm } TReadIntForm = class(TForm) ReadIntEdit: TSpinEdit; ReadIntLabel: TLabel; OKBtn: TButton; procedure FormShow(Sender: TObject); function GetInt(lStr: string; lMin,lDefault,lMax: integer): integer; procedure OKBtnClick(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var ReadIntForm: TReadIntForm; implementation uses nifti_img_view,{license,} MultiSlice, render; {$IFNDEF FPC} {$R *.DFM} {$ENDIF} function TReadIntForm.GetInt(lStr: string; lMin,lDefault,lMax: integer): integer; begin //result := lDefault; ReadIntLabel.caption := lStr+' ['+inttostr(lMin)+'..'+inttostr(lMax)+']'; ReadIntEdit.MinValue := lMin; ReadIntEdit.MaxValue := lMax; ReadIntEdit.Value := lDefault; //ReadIntForm.OKBtn.Focused := true; //ReadIntForm.OKBtn.SetFocus; ReadIntForm.ShowModal; result := ReadIntEdit.Value; end; procedure TReadIntForm.FormShow(Sender: TObject); begin //OKBtn.SetFocus;; end; procedure TReadIntForm.OKBtnClick(Sender: TObject); begin ReadIntForm.ModalResult := mrOK; end; procedure TReadIntForm.FormCreate(Sender: TObject); //var lCPUid: longint; begin //Jan 2008 39448 if Date > (400003) then begin showmessage('This software became obsolete on '+datetostr(40000)+'. Please update to the current version.'); //gBGImg.LicenseID := 1626; //ImgForm.Exit1Click(nil); end; end; {$IFDEF FPC} initialization {$I ReadInt.lrs} {$ENDIF} end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/perisettings.lrs���������������������������������������������������0000755�0001750�0001750�00000005714�11450447636�017466� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TPSForm','FORMDATA',[ 'TPF0'#7'TPSForm'#6'PSForm'#4'Left'#3'"'#4#6'Height'#3#142#1#3'Top'#3#164#1#5 +'Width'#3'r'#1#18'HorzScrollBar.Page'#3'q'#1#18'VertScrollBar.Page'#3#162#1 +#13'ActiveControl'#7#12'BinWidthEdit'#7'Caption'#6#17'Peristimulus Plot'#12 +'ClientHeight'#3#142#1#11'ClientWidth'#3'r'#1#21'Constraints.MaxHeight'#3#142 +#1#20'Constraints.MaxWidth'#3'r'#1#21'Constraints.MinHeight'#3#142#1#20'Cons' +'traints.MinWidth'#3'r'#1#6'OnShow'#7#8'FormShow'#8'Position'#7#14'poScreenC' +'enter'#10'LCLVersion'#6#6'0.9.29'#0#6'TLabel'#6'Label1'#4'Left'#2'('#6'Heig' +'ht'#2#14#3'Top'#2#25#5'Width'#2'G'#7'Caption'#6#15'Bin width (sec)'#11'Pare' +'ntColor'#8#0#0#6'TLabel'#6'Label2'#4'Left'#2'('#6'Height'#2#14#3'Top'#2'>'#5 +'Width'#3#134#0#7'Caption'#6#27'Number of pre-stimulus bins'#11'ParentColor' +#8#0#0#6'TLabel'#6'Label3'#4'Left'#2'('#6'Height'#2#14#3'Top'#2'e'#5'Width'#3 +#139#0#7'Caption'#6#28'Number of post-stimulus bins'#11'ParentColor'#8#0#0#14 +'TFloatSpinEdit'#12'BinWidthEdit'#4'Left'#3#232#0#6'Height'#2#21#3'Top'#2#16 +#5'Width'#3#130#0#13'DecimalPlaces'#2#4#9'Increment'#5#0#0#0#0#0#0#0#128#255 +'?'#8'MaxValue'#5#0#0#0#0#0#0#0#200#5'@'#8'MinValue'#5#0#0#0#0#0#0#0#0#0#0#8 +'TabOrder'#2#0#5'Value'#5#0#0#0#0#0#0#0#0#0#0#0#0#9'TSpinEdit'#10'PreBinEdit' +#4'Left'#3#232#0#6'Height'#2#21#3'Top'#2'5'#5'Width'#3#130#0#8'MinValue'#2#1 +#8'TabOrder'#2#1#5'Value'#2#4#0#0#9'TSpinEdit'#11'PostBinEdit'#4'Left'#3#232 +#0#6'Height'#2#21#3'Top'#2'\'#5'Width'#3#130#0#8'MinValue'#2#1#8'TabOrder'#2 +#2#5'Value'#2#14#0#0#9'TCheckBox'#14'SliceTImeCheck'#4'Left'#2'('#6'Height'#2 +#17#3'Top'#3#132#0#5'Width'#3#139#0#7'Caption'#6#25'Data slice-time correcte' +'d'#8'TabOrder'#2#3#0#0#9'TCheckBox'#14'SavePSVolCheck'#4'Left'#2'('#6'Heigh' +'t'#2#17#3'Top'#3#164#0#5'Width'#3#145#0#7'Caption'#6#25'Save peristimulus v' +'olumes'#8'TabOrder'#2#4#0#0#7'TButton'#5'OKBtn'#4'Left'#3#24#1#6'Height'#2 +#25#3'Top'#3'h'#1#5'Width'#2'K'#25'BorderSpacing.InnerBorder'#2#4#7'Caption' +#6#2'OK'#11'ModalResult'#2#1#8'TabOrder'#2#5#0#0#9'TCheckBox'#14'PctSignalCh' +'eck'#4'Left'#2'('#6'Height'#2#17#3'Top'#3#200#0#5'Width'#2'>'#7'Caption'#6#8 +'% Signal'#7'Checked'#9#5'State'#7#9'cbChecked'#8'TabOrder'#2#6#0#0#9'TCheck' +'Box'#10'ModelCheck'#4'Left'#2'P'#6'Height'#2#17#3'Top'#3'@'#1#5'Width'#3#192 +#0#7'Caption'#6'!Report modeled, not observed data'#8'TabOrder'#2#7#7'Visibl' +'e'#8#0#0#9'TCheckBox'#12'RegressCheck'#4'Left'#2'('#6'Height'#2#17#3'Top'#3 +#240#0#5'Width'#2't'#7'Caption'#6#17'Remove Regressors'#7'Checked'#9#7'OnCli' +'ck'#7#17'RegressCheckClick'#5'State'#7#9'cbChecked'#8'TabOrder'#2#8#0#0#9'T' +'CheckBox'#7'TDCheck'#4'Left'#2'P'#6'Height'#2#17#3'Top'#3#24#1#5'Width'#3 +#181#0#7'Caption'#6#31'Also Remove Temporal Derivative'#7'Checked'#9#5'State' +#7#9'cbChecked'#8'TabOrder'#2#9#7'Visible'#8#0#0#0 ]); ����������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/mni.pas������������������������������������������������������������0000755�0001750�0001750�00000002303�11551145664�015501� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit mni; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Spin; type { TMNIForm } TMNIForm = class(TForm) XEdit: TSpinEdit; YEdit: TSpinEdit; ZEdit: TSpinEdit; procedure FormCreate(Sender: TObject); procedure XEditChange(Sender: TObject); private { private declarations } public { public declarations } end; var MNIForm: TMNIForm; implementation uses define_types, nifti_img,nifti_img_view; { TMNIForm } procedure TMNIForm.XEditChange(Sender: TObject); var lXmm,lYmm,lZmm: single; lX,lY,lZ: integer; begin if not MNIForm.visible then exit; if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems=0 then exit; lXmm:=XEdit.value; lYmm:=YEdit.value; lZmm:=ZEdit.value; MMToImgCoord(lX,lY,lZ,lXmm,lYmm,lZmm); if lX <> ImgForm.XViewEdit.value then ImgForm.XViewEdit.value := lX; if lY <> ImgForm.YViewEdit.value then ImgForm.YViewEdit.value := lY; if lZ <> ImgForm.ZViewEdit.value then ImgForm.ZViewEdit.value := lZ; ImgForm.XViewEditChange(nil); end; procedure TMNIForm.FormCreate(Sender: TObject); begin end; initialization {$I mni.lrs} end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/periplot.pas�������������������������������������������������������0000755�0001750�0001750�00000071077�11425734502�016565� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit periplot; //peristimulus plotting routines interface uses nifti_hdr,define_types,metagraph,sysutils; function CreatePeristimulusPlot (var l4DHdr: TMRIcroHdr; var l4DTrace: T4DTrace; var lPSPlot: TPSPlot): boolean; function ROIoverlayNameShort(lROI: integer): string; function numROI: integer; function ROIoverlayNum(lROI: integer): integer; function NCond ( var l4DTrace: T4DTrace): integer; function ROImean (var l4DHdr: TMRIcroHdr; lROInum,lVol: integer): double; implementation {$IFNDEF FPC} {$DEFINE REMOVEREGRESS} {$ENDIF} uses nifti_img_view,dialogs,nifti_img,text,graphx,math {$IFDEF REMOVEREGRESS},fmath, hrf, matrices,Regmult{$ENDIF}; //need to specify path, e.g. C:\pas\mricron\npm\math //var gOffsetError: array [1..kMaxCond] of double; function numROI: integer; var lR: integer; begin result := 0; for lR := (kBGOverlayNum+1) to knMaxOverlay do if gMRIcroOverlay[lR].ScrnBufferItems > 0 then inc(result); end; function ROIoverlayNum(lROI: integer): integer; var lR,lN: integer; begin result := 0; lN := 0; for lR := (kBGOverlayNum+1) to knMaxOverlay do begin //fx(lR,gMRIcroOverlay[lR].ScrnBufferItems); if gMRIcroOverlay[lR].ScrnBufferItems > 0 then begin inc(lN); if lROI = lN then begin result := lR; exit; end; end; //if ROI has items end; end; function ROIoverlayNameShort(lROI: integer): string; begin if ROIoverlayNum(lROI) = 0 then {$IFDEF FPC} result := inttostr(ImgForm.XViewEdit.value)+'x'+inttostr(ImgForm.YViewEdit.value)+'x'+inttostr(ImgForm.ZViewEdit.value) {$ELSE} result := inttostr(ImgForm.XViewEdit.asinteger)+'x'+inttostr(ImgForm.YViewEdit.asinteger)+'x'+inttostr(ImgForm.ZViewEdit.asinteger) {$ENDIF} else result := parsefilename(extractfilename(gMRIcroOverlay[ROIoverlayNum(lROI)].HdrFileName)); end; function StDev (lSum, lSumSqr: single; lN: integer): single; begin result := 0; if lN < 2 then exit; //avoid divide by zero. We divide by N-1 result:= (lSumSqr - ((Sqr(lSum))/lN)); if (result > 0) then result := Sqrt ( result/(lN-1)) end; function ROIoverlayNameLong(lROI: integer): string; begin if ROIoverlayNum(lROI) = 0 then {$IFDEF FPC} result := inttostr(ImgForm.XViewEdit.value)+'x'+inttostr(ImgForm.YViewEdit.value)+'x'+inttostr(ImgForm.ZViewEdit.value) {$ELSE} result := inttostr(ImgForm.XViewEdit.asinteger)+'x'+inttostr(ImgForm.YViewEdit.asinteger)+'x'+inttostr(ImgForm.ZViewEdit.asinteger) {$ENDIF} else result := gMRIcroOverlay[ROIoverlayNum(lROI)].HdrFileName; end; function NCond ( var l4DTrace: T4DTrace): integer; var lCond: integer; begin result := 0; for lCond := 1 to kMaxCond do if l4DTrace.Conditions[lCond].Events > 0 then inc(result); end; function StError (lSum, lSumSqr: single; lN: integer): single; //= STANDARD DEVIATION / SQUARE ROOT OF THE POPULATION SIZE //= STDEV(range of values)/SQRT(lN) begin if lN > 1 then result := StDev (lSum, lSumSqr, lN)/ sqrt(lN) else result := 0; end; const kMaxEvents = 2048; procedure TimecourseVoxinten (var l4DHdr: TMRIcroHdr; lVoxel: integer; lTimeCourse: DoubleP); //could also use periutil's VoxInten, but this is faster... var lVol,lVolOffset,lImgVox,lMaxStatVol: integer; l32Buf: singleP; l16Buf: smallintp; begin //if ROI else no ROI - single voxel lImgVox := l4DHdr.NIFTIhdr.dim[1]*l4DHdr.NIFTIhdr.dim[2]*l4DHdr.NIFTIhdr.dim[3]; lMaxStatVol := l4DHdr.NIFTIhdr.dim[4]; if (l4DHdr.ImgBufferBPP = 4) then begin l32Buf := SingleP(l4DHdr.ImgBuffer ); for lVol := 1 to lMaxStatVol do begin lVolOffset := (lVol-1)*lImgVox; lTimeCourse^[lVol] := l32Buf^[lVoxel+lVolOffset] end; end else if l4DHdr.ImgBufferBPP = 2 then begin l16Buf := SmallIntP(l4DHdr.ImgBuffer ); for lVol := 1 to lMaxStatVol do begin lVolOffset := (lVol-1)*lImgVox; lTimeCourse^[lVol] := l16Buf^[lVoxel+lVolOffset] end; end else if l4DHdr.ImgBufferBPP = 1 then begin for lVol := 1 to lMaxStatVol do begin lVolOffset := (lVol-1)*lImgVox; lTimeCourse^[lVol] := l4DHdr.ImgBuffer^[lVoxel+lVolOffset]; end; end; //if 1 bpp end; //GenerateVoxinten function ROImean (var l4DHdr: TMRIcroHdr; lROInum,lVol: integer): double; var l32Buf: singleP; l16Buf: smallintp; lSum: double; lMaskVox: int64; lInc,lVolOffset,lImgVox: integer; begin result := 0; //compute number of voxels in mask lImgVox := l4DHdr.NIFTIhdr.dim[1]*l4DHdr.NIFTIhdr.dim[2]*l4DHdr.NIFTIhdr.dim[3]; lMaskVox := 0; for lInc := 1 to lImgVox do if gMRIcroOverlay[lROInum].ScrnBuffer^[lInc] > 0 then //in mask lMaskVox := lMaskVox + gMRIcroOverlay[lROInum].ScrnBuffer^[lInc]; if lMaskVox < 1 then exit; lSum := 0; lVolOffset := (lVol-1)*lImgVox; if (l4DHdr.ImgBufferBPP = 4) then begin l32Buf := SingleP(l4DHdr.ImgBuffer ); for lInc := 1 to lImgVox do begin if gMRIcroOverlay[lROInum].ScrnBuffer^[lInc] > 0 then begin//in mask lSum := lSum + (gMRIcroOverlay[lROInum].ScrnBuffer^[lInc]*l32Buf^[lInc+lVolOffset]); end; //in mask end; //for each vox end else if (l4DHdr.ImgBufferBPP = 2) then begin l16Buf := SmallIntP(l4DHdr.ImgBuffer ); for lInc := 1 to lImgVox do begin if gMRIcroOverlay[lROInum].ScrnBuffer^[lInc] > 0 then begin//in mask lSum := lSum + (gMRIcroOverlay[lROInum].ScrnBuffer^[lInc]*l16Buf^[lInc+lVolOffset]); end; //in mask end; //for each vox end else if (l4DHdr.ImgBufferBPP = 1) then begin for lInc := 1 to lImgVox do begin if gMRIcroOverlay[lROInum].ScrnBuffer^[lInc] > 0 then begin//in mask lSum := lSum + (gMRIcroOverlay[lROInum].ScrnBuffer^[lInc]*l4DHdr.ImgBuffer^[lInc+lVolOffset]); end; //for each volume end; //for each vox end; //for image type result := lSum/lMaskVox; end; function TimecourseROIinten (var l4DHdr: TMRIcroHdr; lROInum: integer; lTimeCourse: DoubleP): boolean; var lVol,lMaxStatVol: integer; begin lMaxStatVol := l4DHdr.NIFTIhdr.dim[4]; //result := false; for lVol := 1 to lMaxStatVol do lTimeCourse^[lVol] := ROImean (l4DHdr,lROInum,lVol); //compute mean for each volume result := true; end; function ComputeMeanSE (lCountBin: longintp; lMnBin,lSEBin,lSumBin,lSumSqrBin: doublep; lNegBins,lPosBins: integer): boolean; var lBin: integer; begin result := false; (*var lBins,lBin,lnBinsWithSamples: integer; lIntensitySum: double; begin result := false; lIntensitySum := 0; lnBinsWithSamples := 0; lBins := lNegBins; if lBins < 1 then lBins := lNegBins+lPosBins; for lBin := lBins downto 1 do begin //new only base pct on baseline if lCountBin^[lBin] > 0 then begin lIntensitySum := lIntensitySum+lMnBin^[lBin]; inc(lnBinsWithSamples); end; //samples in bin end; //for each bin if lnBinsWithSamples < 1 then exit;*) if (lNegBins + lPosBins) < 1 then exit; for lBin := (lNegBins + lPosBins) downto 1 do lSEBin^[lBin] := StError(lSumBin^[lBin],lSumSqrBin^[lBin],lCountBin^[lBin]); result := true; end; //ifunc ComputeMeanSE {$IFDEF REMOVEREGRESS} {procedure OutCSV (lTimeCourseRaw,lTimeCourseRegress,lTimeCourseFilt: DoubleP; lnVol,lC: integer; lSlope,lInter: double); var lVol: integer; lF: TextFile; lStr: string; begin AssignFile(lF, 'C:\fatigue\td'+inttostr(lC)+'.csv'); Rewrite(lF); lStr := ''; for lVol := 1 to lnVol do lStr := lStr+floattostr(lTimeCourseRaw^[lVol])+','; lStr := lStr + '666'; writeln(lF,lStr); lStr := ''; for lVol := 1 to lnVol do lStr := lStr+floattostr(lTimeCourseRegress^[lVol])+','; lStr := lStr + '666'; writeln(lF,lStr); lStr := ''; for lVol := 1 to lnVol do lStr := lStr+floattostr(lTimeCourseFilt^[lVol])+','; lStr := lStr + '666'; writeln(lF,lStr); writeln(lF,''); writeln(lF,''); writeln(lF,floattostr(lSlope)+','+floattostr(lInter)); CloseFile(lF); end; } function RemoveRegressors(lTimeCourseRaw,lTimeCourseFilt: DoubleP; var l4DTrace: T4DTrace;lCond,lnVol: integer;var lPSPlot: TPSPlot): boolean; var lOK: boolean; lKernelBins,lncond,lC,lVol,lnCondincludeTD: integer; lHRFra, lTDra: doublep; lInputSum,lOutputSum : double; X: PMatrix; Y: PVector; //lDummy,lEstTimeCoursePrecise: DoubleP; lOutT,lOutSlope: DoubleP0; begin result := false; lncond := NCond (l4DTrace); lnCondincludeTD := lnCond; if lPSPlot.TemporalDeriv then lnCondincludeTD := lnCondincludeTD * 2; if (lnCondincludeTD < 2) or (lPSPlot.SPMDefaultsStatsFmriT < 1) then begin Showmessage('You need at least two variables to remove regressors (you could add the temporal derivative)'); exit; end; //cond = 0 if not CreateHRF (lPSPlot.TRsec, lKernelBins,lPSPlot.SPMDefaultsStatsFmriT, lHRFra, lTDra) then exit; //getmem(lTimeCourseRegress,lnVol*sizeof(double)); for lVol := 1 to lnVol do lTimeCourseFilt^[lVol] := lTimeCourseRaw^[lVol]; //compute sum intensity so we can adjust for shifts in the mean... lInputSum := 0; for lVol := 1 to lnVol do lInputSum := lInputSum+lTimeCourseRaw^[lVol]; //convolve each condition... DimMatrix(X, lnCondincludeTD, lnVol); //lDummy := nil; //Getmem(lEstTimeCoursePrecise, lnVol *lPSPlot.SPMDefaultsStatsFmriT * sizeof(double)); for lC := 1 to lnCond do begin (*if lC = lCond then ConvolveTimeCourse(X, lHRFra, lEstTimeCoursePrecise,l4DTrace, lC,lC,lnVol,lKernelBins,lPSPlot.SPMDefaultsStatsFmriT,lPSPlot.SPMDefaultsStatsFmriT0,lPSPlot.TRSec, lPSPlot.SliceTime) else*) ConvolveTimeCourse(X, lHRFra, l4DTrace, lC,lC,lnVol,lKernelBins,lPSPlot.SPMDefaultsStatsFmriT,lPSPlot.SPMDefaultsStatsFmriT0,lPSPlot.TRSec, lPSPlot.SliceTime); end; //convolve temporal derivatives for each condition if lPSPlot.TemporalDeriv then for lC := 1 to lnCond do ConvolveTimeCourse(X, lTDra, l4DTrace, lC,lC+lnCond,lnVol,lKernelBins,lPSPlot.SPMDefaultsStatsFmriT,lPSPlot.SPMDefaultsStatsFmriT0,lPSPlot.TRSec, lPSPlot.SliceTime); freemem(lHRFra); freemem(lTDra); DimVector(Y, lnVol); for lVol := 1 to lnVol do Y^[lVol] := lTimeCourseRaw^[lVol]; getmem(lOutT, (lnCondincludeTD+1)* sizeof(double)); getmem(lOutSlope, (lnCondincludeTD+1)* sizeof(double)); lOK := MultipleRegressionVec (lnVol,lnCondincludeTD, X, Y, lOutT,lOutSlope); freemem(lOutT); DelVector(Y, lnVol); //begin test - show responses... if lPSPlot.PlotModel then begin lC := lCond; //response for condition //if lTemporalDeriv then lC := lCond + lnCond; //lCond + lnCond = TD //if lPSPlot.TemporalDeriv then fx( lC,lOutSlope^[lC-1],lOutSlope^[lnCond+lC-1] ); for lVol := 1 to lnVol do lTimeCourseFilt^[lVol] := (X^[lC]^[lVol] *lOutSlope[lC-1]); end else begin //not test if lOK then begin for lC := 1 to lnCondincludeTD do begin if lC <> lCond then begin for lVol := 1 to lnVol do lTimeCourseFilt^[lVol] := lTimeCourseFilt^[lVol]- (X^[lC]^[lVol] *lOutSlope[lC-1]); end; //for each regressor end; //for lC result := true;//SUCCESS! //next - search for optimal fit of model to data.. //if (lPSPlot.TextOutput) and (lCond > 0) and (lCond <= kMaxCond) then // gOffsetError[lCond] := (OptimalOffset(lOutSlope^[lCond-1],lOutSlope^[lnCondincludeTD], lPSPlot.SPMDefaultsStatsFmriT0,lPSPlot.SPMDefaultsStatsFmriT,lnVol, lTimeCourseFilt,lEstTimeCoursePrecise)/ lPSPlot.SPMDefaultsStatsFmriT ) * lPSPlot.TRsec; end;//lOK end; //Freemem(lEstTimeCoursePrecise); DelMatrix(X, lnCondincludeTD, lnVol); //adjust for shifts in the mean... lOutputSum := 0; for lVol := 1 to lnVol do lOutputSum := lOutputSum+lTimeCourseFilt^[lVol]; if lOutputSum <> lInputsum then begin lOutputSum := (lOutputSum - lInputSum)/lnVol; for lVol := 1 to lnVol do lTimeCourseFilt^[lVol] := lTimeCourseFilt^[lVol] - lOutputSum; end; //correct for changes... freemem(lOutSlope); end; {$ENDIF} //IFDEF REMOVEREGRESS //old TimeCourseToPSPlot - each event can contribute to several samples e.g. both before and after stimulus (*function TimeCourseToPSPlot(lTimeCourse: DoubleP; var l4DTrace: T4DTrace; lCountBin: longintp; lMnBin,lSumBin,lSumSqrBin: doublep; var lTRsec,lBinWidthSec: single; lCond,lnNegBins,lnPosBins,lMaxStatVol: integer; lSliceTime: boolean): boolean; var lOnsetRAx: doublep; lEvent,lnEvent,lBin,lVol: integer; lNegMS,lPosMS,lVolTime,lTRms,lHalfTRms,lPeristimulusTime,lmsPerBin: double; begin result := false; if l4DTrace.Conditions[lCond].Events < 1 then exit; lmsPerBin := lBinWidthSec * 1000; lTRms := lTRsec * 1000; if lTRms = 0 then begin Showmessage('Unable to compute plots: You need to specify the TR in seconds.'); exit; end; lHalfTRms := lTRms/2; lNegMS := -lnNegBins * lmsPerBin; lPosMS := lnPosBins * lmsPerBin; lnEvent := l4DTrace.Conditions[lCond].Events; getmem(lOnsetRAx,lnEvent*sizeof(double) ); if lSliceTime then begin for lEvent := 1 to lnEvent do begin lOnsetRAx^[lEvent] := (l4DTrace.Conditions[lCond].EventRA^[lEvent]*1000)-lHalfTRms; end; end else for lEvent := 1 to lnEvent do lOnsetRAx^[lEvent] := (l4DTrace.Conditions[lCond].EventRA^[lEvent]*1000); //initialize bins for lBin := 1 to (lnNegBins + lnPosBins) do begin lMnBin^[lBin] := 0; lSumBin^[lBin] := 0; lSumSqrBin^[lBin] := 0; lCountBin^[lBin] := 0; //no samples in each cell end; for lVol := 1 to lMaxStatVol do begin lVolTime := (lVol-1) * lTRms; for lEvent := 1 to l4DTrace.Conditions[lCond].Events do begin lPeristimulusTime := lVolTime-lOnsetRAx^[lEvent]; if (lPeristimulusTime >= lNegMS) and (lPeristimulusTime < lPosMS) then begin lBin := trunc((lPeristimulusTime - lNegMS) / lmsPerBin)+1; inc(lCountBin^[lBin]); lSumBin^[lBin] := lSumBin^[lBin] + lTimeCourse^[lVol]; lSumSqrBin^[lBin] := lSumSqrBin^[lBin] + sqr(lTimeCourse^[lVol]); end; //if lPeristimulusTime within mix/max temporal window end; //for each event end; //for each vol //next compute mean for lBin := 1 to (lnNegBins + lnPosBins) do if lCountBin^[lBin] > 0 then lMnBin^[lBin] := lSumBin^[lBin]/lCountBin^[lBin]; freemem(lOnsetRAx); result := true; end;//func TimeCourseToPS *) function TimeCourseToPSPlot(lTimeCourse: DoubleP; var l4DTrace: T4DTrace; lCountBin: longintp; lMnBin,lSumBin,lSumSqrBin: doublep; var lPSPlot: TPSPlot; lCond,lMaxStatVol: integer): boolean; var lOnsetRAx: doublep; lEvent,lnEvent,lBin,lVol: integer; lNextEvent,lPrevEvent,lNegMS,lPosMS,lVolTime,lTRms,lHalfTRms,lPeristimulusTime,lmsPerBin: double; begin result := false; if (l4DTrace.Conditions[lCond].Events < 1) or ((lPSPlot.nNegBins + lPSPlot.nPosBins)<1) then exit; lmsPerBin := lPSPlot.BinWidthSec * 1000; lTRms := lPSPlot.TRsec * 1000; if lTRms = 0 then begin Showmessage('Unable to compute plots: You need to specify the TR in seconds.'); exit; end; lHalfTRms := lTRms/2; lNegMS := -lPSPlot.nNegBins * lmsPerBin; lPosMS := lPSPlot.nPosBins * lmsPerBin; lnEvent := l4DTrace.Conditions[lCond].Events; getmem(lOnsetRAx,lnEvent*sizeof(double) ); if lPSPlot.SliceTime then begin for lEvent := 1 to lnEvent do begin lOnsetRAx^[lEvent] := (l4DTrace.Conditions[lCond].EventRA^[lEvent]*1000)-lHalfTRms; end; end else for lEvent := 1 to lnEvent do lOnsetRAx^[lEvent] := (l4DTrace.Conditions[lCond].EventRA^[lEvent]*1000); //initialize bins for lBin := 1 to (lPSPlot.nNegBins + lPSPlot.nPosBins) do begin lMnBin^[lBin] := 0; lSumBin^[lBin] := 0; lSumSqrBin^[lBin] := 0; lCountBin^[lBin] := 0; //no samples in each cell end; //find volume's peristimulus time //note: we assume periutil's ReadCond ensures that Cond.Events are sorted in ascending order lEvent := 1; lPrevEvent := -MaxInt; lNextEvent := lOnsetRAx^[lEvent]; for lVol := 1 to lMaxStatVol do begin lVolTime := (lVol-1) * lTRms; while lVolTime > lNextEvent do begin inc(lEvent); lPrevEvent := lNextEvent; if lEvent > lnEvent then lNextEvent := MaxInt else lNextEvent := lOnsetRAx^[lEvent]; end; lPeristimulusTime := lVolTime-lPrevEvent; if (lPeristimulusTime >= 0) and (lPeristimulusTime < lPosMS) then begin lBin := trunc((lPeristimulusTime - lNegMS) / lmsPerBin)+1; inc(lCountBin^[lBin]); lSumBin^[lBin] := lSumBin^[lBin] + lTimeCourse^[lVol]; lSumSqrBin^[lBin] := lSumSqrBin^[lBin] + sqr(lTimeCourse^[lVol]); end else begin //if not after - check if before lPeristimulusTime := lVolTime-lNextEvent; if (lPeristimulusTime >= lNegMS) and (lPeristimulusTime < 0) then begin lBin := trunc((lPeristimulusTime - lNegMS) / lmsPerBin)+1; inc(lCountBin^[lBin]); lSumBin^[lBin] := lSumBin^[lBin] + lTimeCourse^[lVol]; lSumSqrBin^[lBin] := lSumSqrBin^[lBin] + sqr(lTimeCourse^[lVol]); end; //if lPeristimulusTime within mix/max temporal window end; //if else... not after stimuli (*for lEvent := 1 to l4DTrace.Conditions[lCond].Events do begin lPeristimulusTime := lVolTime-lOnsetRAx^[lEvent]; if (lPeristimulusTime >= lNegMS) and (lPeristimulusTime < lPosMS) then begin lBin := trunc((lPeristimulusTime - lNegMS) / lmsPerBin)+1; inc(lCountBin^[lBin]); lSumBin^[lBin] := lSumBin^[lBin] + lTimeCourse^[lVol]; lSumSqrBin^[lBin] := lSumSqrBin^[lBin] + sqr(lTimeCourse^[lVol]); end; //if lPeristimulusTime within mix/max temporal window end; //for each event*) end; //for each vol //next compute mean for lBin := 1 to (lPSPlot.nNegBins + lPSPlot.nPosBins) do if lCountBin^[lBin] > 0 then lMnBin^[lBin] := lSumBin^[lBin]/lCountBin^[lBin]; freemem(lOnsetRAx); result := true; end;//func TimeCourseToPS function TextOutput (lROI,lCond: integer; var lPSPlot : TPSPlot; var l4DTrace: T4DTrace; lCountBin: longintp; lMnROI,lSEROI: doublep): boolean; var lOutMnStr,lOutSDStr,lCondStr, lOutStr,lModelStr: string; lNegMS,lmsPerBin: double; lnBins,lBin,lMinBinCount,lMaxBinCount: integer; begin result := false; lnBins := lPSPlot.nNegBins + lPSPlot.nPosBins; if lnBins < 1 then exit; lmsPerBin := lPSPlot.BinWidthSec * 1000; lNegMS := -lPSPlot.nNegBins * lmsPerBin; lMinBinCount := lCountBin^[1]; lMaxBinCount := lCountBin^[1]; for lBin := 1 to lnBins do begin if lCountBin^[lBin] < lMinBinCount then lMinBinCount := lCountBin^[lBin]; if lCountBin^[lBin] > lMaxBinCount then lMaxBinCount := lCountBin^[lBin]; end; lModelStr := ', Processing=,'; if lPSPlot.RemoveRegressorVariability then begin if lPSPlot.PlotModel then lModelStr := lModelStr+'MODEL[hrf' else lModelStr := lModelStr+'observed[hrf'; if lPSPlot.TemporalDeriv then lModelStr := lModelStr+'+TD'; lModelStr := lModelStr+']'; //if (lCond > 0) and (lCond <= kMaxCond) then lModelStr := lModelStr+ floattostr(gOffsetError[lCond]); end else lModelStr := lModelStr+'observed[raw]'; lModelStr := lModelStr+kTextSep; lCondStr := 'Image=,'+gMRIcroOverlay[kBGOverlayNum].HdrFileName+', '+inttostr(lCond)+',Condition=,'+l4DTrace.Conditions[lCond].ELabel+lModelStr+'Events=, '+inttostr(l4DTrace.Conditions[lCond].Events)+', samples per bin= '+inttostr(lMinBinCount)+'..'+inttostr(lMaxBinCount); lOutStr := kTextSep; for lBin := 1 to 11 do lOutStr := lOutStr+kTextSep; lOutStr := lOutStr+'Bin Starts At->'; for lBin := 1 to lnBins do lOutStr := lOutStr+kTextSep+ RealToStr((lNegMS+ ((lBin-1)* lmsPerBin)),0 ); TextForm.MemoT.lines.add(lOutStr); TextForm.MemoT.Lines.add('samples per bin '+inttostr(lMinBinCount)+'..'+inttostr(lMaxBinCount)); //next report number of samples averaged lOutStr := lCondStr+kTextSep+kTextSep+kTextSep+'samples in bin='; for lBin := 1 to lnBins do lOutStr := lOutStr+kTextSep+ inttostr(lCountBin^[lBin] ); TextForm.MemoT.lines.add(lOutStr); //next report mean signal lOutMnStr := lCondStr+kTextSep+'roiMn'+kTextSep+'MaskROI['+ROIoverlayNameShort(lROI)+']='+kTextSep+ROIoverlayNameLong(lROI); lOutSDStr := lCondStr+kTextSep+'roiSE'+kTextSep+'MaskROI['+ROIoverlayNameShort(lROI)+']='+kTextSep+ROIoverlayNameLong(lROI); for lBin := 1 to (lnBins) do begin lOutMnStr := lOutMnStr+kTextSep+ floattostr(lMnROI^[lBin]);//floattostr(lSumROI[lROI,lBin]/lBinCountRA[lBin]); lOutSDStr := lOutSDStr+kTextSep+ floattostr(lSEROI^[lBin]);//StDev(lSumROI[lROI,lBin],lSumSqrROI[lROI,lBin],lBinCountRA[lBin]) ); end; //for each bin TextForm.MemoT.lines.add(lOutMnStr); TextForm.MemoT.lines.add(lOutSDStr); result := true; end; //proc TextOutput function CalcMean (lTimeCourse: DoubleP;lnVol: integer): double; var lSum: double; lVol: integer; begin result := 0; if lnVol < 1 then exit; lSum := 0; for lVol := 1 to lnVol do lSum := lSum + lTimeCourse^[lVol]; //Sum result := lSum / lnVol; end; procedure PctSignal (lTimeCourse: DoubleP;lnVol: integer); var lMean,lScale: double; lVol: integer; begin if lnVol < 1 then exit; lMean := CalcMean (lTimeCourse,lnVol); if lMean = 0 then exit; //can't compute % signal change... lScale := abs(1/lMean); for lVol := 1 to lnVol do lTimeCourse^[lVol] := (lTimeCourse^[lVol]-lMean)*lScale; //Sum end; function CreatePeristimulusPlot (var l4DHdr: TMRIcroHdr; var l4DTrace: T4DTrace; var lPSPlot: TPSplot): boolean; var lBinData: T4DTrace; lTimeCourse,lTimeCourseFilt: doublep; lCountBin: longintp; lMnBin,lSEBin,lSumBin,lSumSqrBin: doublep; lCond,lncond,lnVol,lnROI,lROI,lnROImin1,lLine,lBin: integer; lTR: double; begin result := false; lncond := NCond (l4DTrace); if lncond = 0 then begin Showmessage('You need to specify event onset times before creating a peristimulus plot.'); exit; end; //cond = 0 lnVol := l4DHdr.NIFTIhdr.dim[4]; if lnVol < 3 then begin Showmessage('Unable to compute plots: You need to analyze a 4D image.'); exit; end; if (l4DHdr.ImgBufferItems = 0) then exit; lTR := lPSPlot.TRsec * 1000; if lTR = 0 then begin Showmessage('Unable to compute plots: You need to specify the TR in seconds.'); exit; end; lnROI := 0; for lROI := (kBGOverlayNum+1) to knMaxOverlay do if gMRIcroOverlay[lROI].ScrnBufferItems > 0 then //current implementation only one ROI inc(lnROI); if lnROI < 1 then begin lnROImin1 := 1; end else begin lnROImin1 := lnROI; end; //allocate memory getmem(lTimeCourse,lnVol*sizeof(double)); getmem(lTimeCourseFilt,lnVol*sizeof(double)); getmem(lCountBin,(lPSPlot.nNegBins+lPSPlot.nPosBins)*sizeof(integer)); getmem(lMnBin,(lPSPlot.nNegBins+lPSPlot.nPosBins)*sizeof(double)); getmem(lSEBin,(lPSPlot.nNegBins+lPSPlot.nPosBins)*sizeof(double)); getmem(lSumSqrBin,(lPSPlot.nNegBins+lPSPlot.nPosBins)*sizeof(double)); getmem(lSumBin,(lPSPlot.nNegBins+lPSPlot.nPosBins)*sizeof(double)); if lPSPlot.GraphOutput then begin Create4DTrace (lBinData); Init4DTrace(lPSPlot.nNegBins + lPSPlot.nPosBins,lnROImin1*lnCond,lBinData,true); for lROI := 1 to lnROImin1 do lBinData.Lines[lROI].ELabel := ROIoverlayNameShort(lROI); end; //if graphoutput //repeat for each Region of interest for lROI := 1 to lnROImin1 do begin //compute complete timecourse for all volumes... if lnROI = 0 then begin {$IFDEF FPC} TimecourseVoxinten (l4DHdr, ImgForm.XViewEdit.value + ((ImgForm.YViewEdit.value-1)*gBGImg.ScrnDim[1]) +((ImgForm.ZViewEdit.value-1)*gBGImg.ScrnDim[1] *gBGImg.ScrnDim[2]),lTimeCourse) {$ELSE} TimecourseVoxinten (l4DHdr, ImgForm.XViewEdit.asinteger + ((ImgForm.YViewEdit.asinteger-1)*gBGImg.ScrnDim[1]) +((ImgForm.ZViewEdit.asinteger-1)*gBGImg.ScrnDim[1] *gBGImg.ScrnDim[2]),lTimeCourse) {$ENDIF} end else TimecourseROIinten (l4DHdr, ROIoverlayNum(lROI), lTimeCourse); //next normalize signal if lPSPlot.PctSignal then PctSignal(lTimeCourse,lnVol); //next compute PSPlots for lCond := 1 to lnCond do begin //here is where we can remove variability predicted by regressors.... {$IFDEF REMOVEREGRESS} if lPSPlot.RemoveRegressorVariability then begin RemoveRegressors(lTimeCourse,lTimeCourseFilt,l4DTrace,lCond,lnVol,lPSPlot); TimeCourseToPSPlot(lTimeCourseFilt, l4DTrace,lCountBin, lMnBin,lSumBin,lSumSqrBin ,lPSPlot, lCond,lnVol); end else {$ENDIF} TimeCourseToPSPlot(lTimeCourse, l4DTrace,lCountBin, lMnBin,lSumBin,lSumSqrBin ,lPSPlot,lCond,lnVol); //percent signal change and std error ComputeMeanSE (lCountBin, lMnBin,lSEBin,lSumBin,lSumSqrBin ,lPSPlot.nNegBins,lPSPlot.nPosBins); //report results if lPSPlot.TextOutput then TextOutput (lROI,lCond,lPSPlot, l4DTrace,lCountBin,lMnBin,lSEBin); if (lPSPlot.GraphOutput) then begin lLine := lROI + ((lCond-1)* lnROImin1); for lBin := 1 to (lPSPlot.nNegBins + lPSPlot.nPosBins) do begin lBinData.Lines[lLine].EventRA^[lBin] := lMnBin^[lBin]; lBinData.Conditions[lLine].EventRA^[lBin] := lSEBin^[lBin]; end;//for each bin end; //if graphoutput end; //for each cond end; //for each ROI freemem(lCountBin); //12/2007 freemem(lTimeCourse); freemem(lTimeCourseFilt); freemem(lMnBin); freemem(lSEBin); freemem(lSumSqrBin); freemem(lSumBin); if lPSPlot.TextOutput then TextForm.show; if (lPSPlot.GraphOutput) then begin MinMax4DTrace(lBinData); for lCond := 1 to lnCond do lBinData.Conditions[lCond].eLabel:= l4DTrace.Conditions[lCond].eLabel; lBinData.HorzMin := (-lPSPlot.nNegBins+0.5)*lPSPlot.BinWidthSec; lBinData.HorzWidPerBin := lPSPlot.BinWidthSec; CorePlot4DTrace(lBinData,Graph4DForm.Image1,1,0,lnCond,lPSPlot.TRsec,Graph4DForm.MinEdit.value,Graph4DForm.MaxEdit.value,true); Close4DTrace(lBinData,true); end;//if graph result := true; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/about.lrs����������������������������������������������������������0000755�0001750�0001750�00000003227�12151703722�016043� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TAboutForm','FORMDATA',[ 'TPF0'#10'TAboutForm'#9'AboutForm'#4'Left'#3#171#2#6'Height'#2#127#3'Top'#3 +#153#0#5'Width'#3'G'#1#13'ActiveControl'#7#6'Panel1'#11'BorderIcons'#11#12'b' +'iSystemMenu'#0#11'BorderStyle'#7#8'bsDialog'#7'Caption'#6#8'About...'#12'Cl' +'ientHeight'#2#127#11'ClientWidth'#3'G'#1#21'Constraints.MaxHeight'#2#127#20 +'Constraints.MaxWidth'#3'G'#1#21'Constraints.MinHeight'#2#127#20'Constraints' +'.MinWidth'#3'G'#1#9'Font.Name'#6#13'MS Sans Serif'#8'OnCreate'#7#10'FormCre' +'ate'#8'Position'#7#14'poScreenCenter'#10'LCLVersion'#6#7'1.0.2.0'#0#6'TPane' +'l'#6'Panel1'#4'Left'#2#0#6'Height'#2'0'#3'Top'#2#0#5'Width'#3'G'#1#5'Align' +#7#5'alTop'#9'Alignment'#7#13'taLeftJustify'#10'BevelOuter'#7#6'bvNone'#7'Ca' +'ption'#6#8' MRIcron'#10'Font.Color'#7#7'clBlack'#11'Font.Height'#2#237#9'Fo' +'nt.Name'#6#17'helvetica [adobe]'#10'Font.Style'#11#6'fsBold'#0#11'ParentCol' +'or'#8#10'ParentFont'#8#8'TabOrder'#2#0#7'OnClick'#7#11'Panel1Click'#10'OnDr' +'agDrop'#7#14'Panel1DragDrop'#0#0#6'TPanel'#6'Panel2'#4'Left'#2#8#6'Height'#2 +'C'#3'Top'#2'/'#5'Width'#3'3'#1#12'ClientHeight'#2'C'#11'ClientWidth'#3'3'#1 +#8'TabOrder'#2#1#0#6'TLabel'#13'HomepageLabel'#4'Left'#2#0#6'Height'#2#20#3 +'Top'#2#10#5'Width'#3'1'#1#9'Alignment'#7#8'taCenter'#8'AutoSize'#8#7'Captio' +'n'#6#7'version'#11'ParentColor'#8#7'OnClick'#7#13'HomePageClick'#0#0#6'TLab' +'el'#11'ThreadLabel'#4'Left'#2#1#6'Height'#2#20#3'Top'#2'$'#5'Width'#3'1'#1#9 +'Alignment'#7#8'taCenter'#8'AutoSize'#8#7'Caption'#6#8' Threads'#11'ParentCo' +'lor'#8#0#0#0#0 ]); �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/multislice/��������������������������������������������������������0000755�0001750�0001750�00000000000�12360763603�016360� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/multislice/default.ini���������������������������������������������0000755�0001750�0001750�00000000152�11424063524�020501� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[STR] Slices=24,28,62,82,92,102 [BOOL] OrthoView=1 SliceLabel=1 [INT] Orient=3 OverslicePct=0 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/���������������������������������������������������������������0000755�0001750�0001750�00000000000�12360760644�015014� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/gold.lut�������������������������������������������������������0000755�0001750�0001750�00000001400�07152673362�016470� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� !#%&(*,.013578:<>?ACEFHJKMOPRTUWYZ\]_abdeghjkmnpqstvwyz|}�  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~���  !"##$%&'(()*+,-./0123456789:<=>?@ACDEFHIJLMNPQRTUWXZ[]^`acefhikmoprtvwy{}����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/blue_otto.lut��������������������������������������������������0000755�0001750�0001750�00000010344�10360600122�017521� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������* s=byte index red green blue S 0 0 0 0 S 1 0 0 128 S 2 0 0 128 S 3 0 0 128 S 4 0 0 128 S 5 0 0 128 S 6 0 0 128 S 7 0 0 128 S 8 0 0 128 S 9 0 0 128 S 10 0 0 128 S 11 0 0 128 S 12 0 0 128 S 13 0 0 128 S 14 0 0 128 S 15 0 0 128 S 16 0 0 128 S 17 0 0 128 S 18 0 0 128 S 19 0 0 128 S 20 0 0 128 S 21 0 0 128 S 22 0 0 128 S 23 0 0 128 S 24 0 0 128 S 25 0 0 128 S 26 0 0 128 S 27 0 0 128 S 28 0 0 128 S 29 0 0 128 S 30 0 0 128 S 31 0 0 128 S 32 0 0 128 S 33 0 0 128 S 34 0 0 128 S 35 0 0 128 S 36 0 0 128 S 37 0 0 128 S 38 0 0 128 S 39 0 0 128 S 40 0 0 128 S 41 0 0 128 S 42 0 0 128 S 43 0 0 128 S 44 0 0 128 S 45 0 0 128 S 46 0 0 128 S 47 0 0 128 S 48 0 0 128 S 49 0 0 128 S 50 0 0 128 S 51 32 0 192 S 52 32 0 192 S 53 32 0 192 S 54 32 0 192 S 55 32 0 192 S 56 32 0 192 S 57 32 0 192 S 58 32 0 192 S 59 32 0 192 S 60 32 0 192 S 61 32 0 192 S 62 32 0 192 S 63 32 0 192 S 64 32 0 192 S 65 32 0 192 S 66 32 0 192 S 67 32 0 192 S 68 32 0 192 S 69 32 0 192 S 70 32 0 192 S 71 32 0 192 S 72 32 0 192 S 73 32 0 192 S 74 32 0 192 S 75 32 0 192 S 76 32 0 192 S 77 32 0 192 S 78 32 0 192 S 79 32 0 192 S 80 32 0 192 S 81 32 0 192 S 82 32 0 192 S 83 32 0 192 S 84 32 0 192 S 85 32 0 192 S 86 32 0 192 S 87 32 0 192 S 88 32 0 192 S 89 32 0 192 S 90 32 0 192 S 91 32 0 192 S 92 32 0 192 S 93 32 0 192 S 94 32 0 192 S 95 32 0 192 S 96 32 0 192 S 97 32 0 192 S 98 32 0 192 S 99 32 0 192 S 100 32 0 192 S 101 32 0 192 S 102 0 168 190 S 103 0 168 190 S 104 0 168 190 S 105 0 168 190 S 106 0 168 190 S 107 0 168 190 S 108 0 168 190 S 109 0 168 190 S 110 0 168 190 S 111 0 168 190 S 112 0 168 190 S 113 0 168 190 S 114 0 168 190 S 115 0 168 190 S 116 0 168 190 S 117 0 168 190 S 118 0 168 190 S 119 0 168 190 S 120 0 168 190 S 121 0 168 190 S 122 0 168 190 S 123 0 168 190 S 124 0 168 190 S 125 0 168 190 S 126 0 168 190 S 127 0 168 190 S 128 0 168 190 S 129 0 168 190 S 130 0 168 190 S 131 0 168 190 S 132 0 168 190 S 133 0 168 190 S 134 0 168 190 S 135 0 168 190 S 136 0 168 190 S 137 0 168 190 S 138 0 168 190 S 139 0 168 190 S 140 0 168 190 S 141 0 168 190 S 142 0 168 190 S 143 0 168 190 S 144 0 168 190 S 145 0 168 190 S 146 0 168 190 S 147 0 168 190 S 148 0 168 190 S 149 0 168 190 S 150 0 168 190 S 151 0 168 190 S 152 0 168 190 S 153 127 255 255 S 154 127 255 255 S 155 127 255 255 S 156 127 255 255 S 157 127 255 255 S 158 127 255 255 S 159 127 255 255 S 160 127 255 255 S 161 127 255 255 S 162 127 255 255 S 163 127 255 255 S 164 127 255 255 S 165 127 255 255 S 166 127 255 255 S 167 127 255 255 S 168 127 255 255 S 169 127 255 255 S 170 127 255 255 S 171 127 255 255 S 172 127 255 255 S 173 127 255 255 S 174 127 255 255 S 175 127 255 255 S 176 127 255 255 S 177 127 255 255 S 178 127 255 255 S 179 127 255 255 S 180 127 255 255 S 181 127 255 255 S 182 127 255 255 S 183 127 255 255 S 184 127 255 255 S 185 127 255 255 S 186 127 255 255 S 187 127 255 255 S 188 127 255 255 S 189 127 255 255 S 190 127 255 255 S 191 127 255 255 S 192 127 255 255 S 193 127 255 255 S 194 127 255 255 S 195 127 255 255 S 196 127 255 255 S 197 127 255 255 S 198 127 255 255 S 199 127 255 255 S 200 127 255 255 S 201 127 255 255 S 202 127 255 255 S 203 127 255 255 S 204 127 255 255 S 205 220 255 255 S 206 220 255 255 S 207 220 255 255 S 208 220 255 255 S 209 220 255 255 S 210 220 255 255 S 211 220 255 255 S 212 220 255 255 S 213 220 255 255 S 214 220 255 255 S 215 220 255 255 S 216 220 255 255 S 217 220 255 255 S 218 220 255 255 S 219 220 255 255 S 220 220 255 255 S 221 220 255 255 S 222 220 255 255 S 223 220 255 255 S 224 220 255 255 S 225 220 255 255 S 226 220 255 255 S 227 220 255 255 S 228 220 255 255 S 229 220 255 255 S 230 220 255 255 S 231 220 255 255 S 232 220 255 255 S 233 220 255 255 S 234 220 255 255 S 235 220 255 255 S 236 220 255 255 S 237 220 255 255 S 238 220 255 255 S 239 220 255 255 S 240 220 255 255 S 241 220 255 255 S 242 220 255 255 S 243 220 255 255 S 244 220 255 255 S 245 220 255 255 S 246 220 255 255 S 247 220 255 255 S 248 220 255 255 S 249 220 255 255 S 250 220 255 255 S 251 220 255 255 S 252 220 255 255 S 253 220 255 255 S 254 220 255 255 S 255 220 255 255 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/surface.lut����������������������������������������������������0000755�0001750�0001750�00000001400�07733772670�017202� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� !"$%&()+,./124578:;=>@ACDFGIJKMNPQSTVWYZ\]_`bcefhiklnoprsuvxy{|~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"##$%&&'(()*++,-../01123345667899:;<<=>??@AABCDDEFGGHIJJKLLMNOOPQRRSTUUVWXXYZZ[\]]^_``abccdeefghhijkklmnnopqqrsstuvvwxyyz{||}~~����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/2winter.lut����������������������������������������������������0000755�0001750�0001750�00000001400�10314612026�017115� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/red_otto.lut���������������������������������������������������0000755�0001750�0001750�00000010257�10360577472�017374� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������* s=byte index red green blue S 0 0 0 0 S 1 128 0 0 S 2 128 0 0 S 3 128 0 0 S 4 128 0 0 S 5 128 0 0 S 6 128 0 0 S 7 128 0 0 S 8 128 0 0 S 9 128 0 0 S 10 128 0 0 S 11 128 0 0 S 12 128 0 0 S 13 128 0 0 S 14 128 0 0 S 15 128 0 0 S 16 128 0 0 S 17 128 0 0 S 18 128 0 0 S 19 128 0 0 S 20 128 0 0 S 21 128 0 0 S 22 128 0 0 S 23 128 0 0 S 24 128 0 0 S 25 128 0 0 S 26 128 0 0 S 27 128 0 0 S 28 128 0 0 S 29 128 0 0 S 30 128 0 0 S 31 128 0 0 S 32 128 0 0 S 33 128 0 0 S 34 128 0 0 S 35 128 0 0 S 36 128 0 0 S 37 128 0 0 S 38 128 0 0 S 39 128 0 0 S 40 128 0 0 S 41 128 0 0 S 42 128 0 0 S 43 128 0 0 S 44 128 0 0 S 45 128 0 0 S 46 128 0 0 S 47 128 0 0 S 48 128 0 0 S 49 128 0 0 S 50 128 0 0 S 51 192 0 32 S 52 192 0 32 S 53 192 0 32 S 54 192 0 32 S 55 192 0 32 S 56 192 0 32 S 57 192 0 32 S 58 192 0 32 S 59 192 0 32 S 60 192 0 32 S 61 192 0 32 S 62 192 0 32 S 63 192 0 32 S 64 192 0 32 S 65 192 0 32 S 66 192 0 32 S 67 192 0 32 S 68 192 0 32 S 69 192 0 32 S 70 192 0 32 S 71 192 0 32 S 72 192 0 32 S 73 192 0 32 S 74 192 0 32 S 75 192 0 32 S 76 192 0 32 S 77 192 0 32 S 78 192 0 32 S 79 192 0 32 S 80 192 0 32 S 81 192 0 32 S 82 192 0 32 S 83 192 0 32 S 84 192 0 32 S 85 192 0 32 S 86 192 0 32 S 87 192 0 32 S 88 192 0 32 S 89 192 0 32 S 90 192 0 32 S 91 192 0 32 S 92 192 0 32 S 93 192 0 32 S 94 192 0 32 S 95 192 0 32 S 96 192 0 32 S 97 192 0 32 S 98 192 0 32 S 99 192 0 32 S 100 192 0 32 S 101 192 0 32 S 102 255 179 0 S 103 255 179 0 S 104 255 179 0 S 105 255 179 0 S 106 255 179 0 S 107 255 179 0 S 108 255 179 0 S 109 255 179 0 S 110 255 179 0 S 111 255 179 0 S 112 255 179 0 S 113 255 179 0 S 114 255 179 0 S 115 255 179 0 S 116 255 179 0 S 117 255 179 0 S 118 255 179 0 S 119 255 179 0 S 120 255 179 0 S 121 255 179 0 S 122 255 179 0 S 123 255 179 0 S 124 255 179 0 S 125 255 179 0 S 126 255 179 0 S 127 255 179 0 S 128 255 179 0 S 129 255 179 0 S 130 255 179 0 S 131 255 179 0 S 132 255 179 0 S 133 255 179 0 S 134 255 179 0 S 135 255 179 0 S 136 255 179 0 S 137 255 179 0 S 138 255 179 0 S 139 255 179 0 S 140 255 179 0 S 141 255 179 0 S 142 255 179 0 S 143 255 179 0 S 144 255 179 0 S 145 255 179 0 S 146 255 179 0 S 147 255 179 0 S 148 255 179 0 S 149 255 179 0 S 150 255 179 0 S 151 255 179 0 S 152 255 235 97 S 153 255 235 97 S 154 255 235 97 S 155 255 235 97 S 156 255 235 97 S 157 255 235 97 S 158 255 235 97 S 159 255 235 97 S 160 255 235 97 S 161 255 235 97 S 162 255 235 97 S 163 255 235 97 S 164 255 235 97 S 165 255 235 97 S 166 255 235 97 S 167 255 235 97 S 168 255 235 97 S 169 255 235 97 S 170 255 235 97 S 171 255 235 97 S 172 255 235 97 S 173 255 235 97 S 174 255 235 97 S 175 255 235 97 S 176 255 235 97 S 177 255 235 97 S 178 255 235 97 S 179 255 235 97 S 180 255 235 97 S 181 255 235 97 S 182 255 235 97 S 183 255 235 97 S 184 255 235 97 S 185 255 235 97 S 186 255 235 97 S 187 255 235 97 S 188 255 235 97 S 189 255 235 97 S 190 255 235 97 S 191 255 235 97 S 192 255 235 97 S 193 255 235 97 S 194 255 235 97 S 195 255 235 97 S 196 255 235 97 S 197 255 235 97 S 198 255 235 97 S 199 255 235 97 S 200 255 235 97 S 201 255 235 97 S 202 255 235 97 S 203 255 235 97 S 204 255 235 97 S 205 255 255 200 S 206 255 255 200 S 207 255 255 200 S 208 255 255 200 S 209 255 255 200 S 210 255 255 200 S 211 255 255 200 S 212 255 255 200 S 213 255 255 200 S 214 255 255 200 S 215 255 255 200 S 216 255 255 200 S 217 255 255 200 S 218 255 255 200 S 219 255 255 200 S 220 255 255 200 S 221 255 255 200 S 222 255 255 200 S 223 255 255 200 S 224 255 255 200 S 225 255 255 200 S 226 255 255 200 S 227 255 255 200 S 228 255 255 200 S 229 255 255 200 S 230 255 255 200 S 231 255 255 200 S 232 255 255 200 S 233 255 255 200 S 234 255 255 200 S 235 255 255 200 S 236 255 255 200 S 237 255 255 200 S 238 255 255 200 S 239 255 255 200 S 240 255 255 200 S 241 255 255 200 S 242 255 255 200 S 243 255 255 200 S 244 255 255 200 S 245 255 255 200 S 246 255 255 200 S 247 255 255 200 S 248 255 255 200 S 249 255 255 200 S 250 255 255 200 S 251 255 255 200 S 252 255 255 200 S 253 255 255 200 S 254 255 255 200 S 255 255 255 200�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/blackbdy.lut���������������������������������������������������0000755�0001750�0001750�00000001400�07152134660�017307� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� !$'*-0369<?BEHKNQTWZ]`cfilorux{~�������������������������������������������������������������������������������������� !$'*-0369<?BEHKNQTWZ]`cfilorux{~��������������������������������������������������������������������������������������������������������������������������������������������������������������������������� !$'*-0369<?BEHKNQTWZ]`cfilorux{~����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/GE_color.lut���������������������������������������������������0000755�0001750�0001750�00000001400�07152134646�017231� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ !#%')+-/13579;=?ACEGIKMOQSUVXZ\^`bdfhjlnprtvxz|~�  "$&(*,.02468:<>ACEGIKMOQSUWY[]_acegikmoqsuwy{}~|zxvtrpnljhfdb`^\ZXVTRPNLJHFDB@?=;97531/-+)'%#! �  "$&(*,.02468:<>@BDFHJLNPRTVXZ\^`bdfhjlnprtvxz|~� !#%')+-/13579;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}|xtplhd`\XTPLHD@<840,($  �  $(,048<@DHLPUY]aeimquy}����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/cortex.lut�����������������������������������������������������0000755�0001750�0001750�00000001400�10303212520�017020� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  !#$%'()+,./0234679:;=>?ABDEFHIKLMOPQSTVWXZ[\^_abcefhijlmnpqstuwxy{|~  !"#$$%&'()*+,--./01234556789:;<==>?@ABCDEEFGHIJKLMMNOPQRSTUUVWXYZ[\]]^_`abcdeefghijklmmnopqrstuuvwxyz{|}}~  !""#$$%&&'(()**+,--.//01123345567789::;<<=>>?@@ABBCDDEFGGHIIJKKLMMNOOPQRRSTTUVVWXXYZZ[\\]^__`aabccdeefgghiijkllmnnoppqrrsttuvvwxyyz{{|}}~����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/bone.lut�������������������������������������������������������0000755�0001750�0001750�00000001400�07177672754�016501� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  !""#$%&'())*+,-./001234567789:;<=>>?@ABCDEEFGHIJKLLMNOPQRSSTUVWXYZ[[\]^_`abbcdefghiijklmnoppqrstuvwwxyz{|}~~��  !""#$%&'())*+,-./001234567789:;<=>>?@ABCDEEFGHIJKLLMNOPQRSTUVWYZ[\]_`abdefghjklmnpqrstvwxyz|}~�  "#$%&()*+,./01345679:;<=?@ABCEFGHIKLMNOQRSTVWXYZ\]^_`bcdefhijklnopqrstuvwxyyz{|}~����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/NIH_ice.lut����������������������������������������������������0000755�0001750�0001750�00000001400�07152134636�016775� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� !#&(+-022111110047;?CFJNRVZ^bfjnqtwy|朝~|zxusqomkigedb`_]\ZYWVTSQRRSTTUVWWXYYZZ[\\]]^__``aa`````____^^^^]]]]]]]]]]]\\\[[[ZZYYXWWVVUSQOMKIHFEDCCBBA@?>=<;98765432210/.,+)(&%#!  ��|zyxwvutsrqponmlkjigfdca`^]\[YXWVUSPNKIFDB>:51,'#����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/1hot.lut�������������������������������������������������������0000755�0001750�0001750�00000001400�10314612026�016376� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  #%(+-0358;=@BEHJMPRUXZ]`behjmpruxz}������������������������������������������������������������������������������������������������  #%(+-0358;=@BEHJMPRUXZ]`behjmpruxz}������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  $(,048<@DHLPTX\`dhlptx|����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/spectrum.lut���������������������������������������������������0000755�0001750�0001750�00000001400�07152134634�017377� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������þ}xsnid_ZUPKFA<72-(# ������������������������������������������������������������������������������������������������������� #(-27<AFKPUZ_dinsx}���������������������������������������������������� #(-27<AFKPUZ_dinsx}þ}xsnid_ZUPKFA<72-(# �þ}xsnid_ZUPKFA<72-(# �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/gooch.lut������������������������������������������������������0000755�0001750�0001750�00000001400�07372336774�016651� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  "$&(*,.02468:<>@BDFHJLNPRTVXZ\^`bdfhjlnprtvxz|~�����������������������������������������������������������������  "$&(*,.02468:<>@BDFHJLNPRTVXZ\^`bdfhjlnprtvxz|~�  $(,048<@DHLPTX\`dhlptx|~|zxvtrpnljhfdb`^\ZXVTRPNLJHFDB@><:86420.,*(&$"  �  $(,048<@DHLPTX\`dhlptx|����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/overlay_classic.lut��������������������������������������������0000755�0001750�0001750�00000010074�10360667412�020726� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������* s=byte index red green blue S 0 0 0 0 S 1 250 0 255 S 2 245 0 255 S 3 240 0 255 S 4 235 0 255 S 5 230 0 255 S 6 224 0 255 S 7 219 0 255 S 8 214 0 255 S 9 209 0 255 S 10 204 0 255 S 11 199 0 255 S 12 194 0 255 S 13 189 0 255 S 14 184 0 255 S 15 179 0 255 S 16 173 0 255 S 17 168 0 255 S 18 163 0 255 S 19 158 0 255 S 20 153 0 255 S 21 148 0 255 S 22 143 0 255 S 23 138 0 255 S 24 133 0 255 S 25 128 0 255 S 26 122 0 255 S 27 117 0 255 S 28 112 0 255 S 29 107 0 255 S 30 102 0 255 S 31 97 0 255 S 32 92 0 255 S 33 87 0 255 S 34 82 0 255 S 35 77 0 255 S 36 71 0 255 S 37 66 0 255 S 38 61 0 255 S 39 56 0 255 S 40 51 0 255 S 41 46 0 255 S 42 41 0 255 S 43 36 0 255 S 44 31 0 255 S 45 26 0 255 S 46 20 0 255 S 47 15 0 255 S 48 10 0 255 S 49 5 0 255 S 50 0 5 255 S 51 0 10 255 S 52 0 15 255 S 53 0 20 255 S 54 0 26 255 S 55 0 31 255 S 56 0 36 255 S 57 0 41 255 S 58 0 46 255 S 59 0 51 255 S 60 0 56 255 S 61 0 61 255 S 62 0 66 255 S 63 0 71 255 S 64 0 77 255 S 65 0 82 255 S 66 0 87 255 S 67 0 92 255 S 68 0 97 255 S 69 0 102 255 S 70 0 107 255 S 71 0 112 255 S 72 0 117 255 S 73 0 122 255 S 74 0 128 255 S 75 0 133 255 S 76 0 138 255 S 77 0 143 255 S 78 0 148 255 S 79 0 153 255 S 80 0 158 255 S 81 0 163 255 S 82 0 168 255 S 83 0 173 255 S 84 0 179 255 S 85 0 184 255 S 86 0 189 255 S 87 0 194 255 S 88 0 199 255 S 89 0 204 255 S 90 0 209 255 S 91 0 214 255 S 92 0 219 255 S 93 0 224 255 S 94 0 230 255 S 95 0 235 255 S 96 0 240 255 S 97 0 245 255 S 98 0 250 255 S 99 0 255 255 S 100 0 255 250 S 101 0 255 245 S 102 0 255 240 S 103 0 255 235 S 104 0 255 229 S 105 0 255 224 S 106 0 255 219 S 107 0 255 214 S 108 0 255 209 S 109 0 255 204 S 110 0 255 199 S 111 0 255 194 S 112 0 255 189 S 113 0 255 184 S 114 0 255 178 S 115 0 255 173 S 116 0 255 168 S 117 0 255 163 S 118 0 255 158 S 119 0 255 153 S 120 0 255 148 S 121 0 255 143 S 122 0 255 138 S 123 0 255 133 S 124 0 255 127 S 125 0 255 122 S 126 0 255 117 S 127 0 255 112 S 128 0 255 107 S 129 0 255 102 S 130 0 255 97 S 131 0 255 92 S 132 0 255 87 S 133 0 255 82 S 134 0 255 76 S 135 0 255 71 S 136 0 255 66 S 137 0 255 61 S 138 0 255 56 S 139 0 255 51 S 140 0 255 46 S 141 0 255 41 S 142 0 255 36 S 143 0 255 31 S 144 0 255 25 S 145 0 255 20 S 146 0 255 15 S 147 0 255 10 S 148 0 255 5 S 149 0 255 0 S 150 5 255 0 S 151 10 255 0 S 152 15 255 0 S 153 20 255 0 S 154 26 255 0 S 155 31 255 0 S 156 36 255 0 S 157 41 255 0 S 158 46 255 0 S 159 51 255 0 S 160 56 255 0 S 161 61 255 0 S 162 66 255 0 S 163 71 255 0 S 164 77 255 0 S 165 82 255 0 S 166 87 255 0 S 167 92 255 0 S 168 97 255 0 S 169 102 255 0 S 170 107 255 0 S 171 112 255 0 S 172 117 255 0 S 173 122 255 0 S 174 128 255 0 S 175 133 255 0 S 176 138 255 0 S 177 143 255 0 S 178 148 255 0 S 179 153 255 0 S 180 158 255 0 S 181 163 255 0 S 182 168 255 0 S 183 173 255 0 S 184 179 255 0 S 185 184 255 0 S 186 189 255 0 S 187 194 255 0 S 188 199 255 0 S 189 204 255 0 S 190 209 255 0 S 191 214 255 0 S 192 219 255 0 S 193 224 255 0 S 194 230 255 0 S 195 235 255 0 S 196 240 255 0 S 197 245 255 0 S 198 250 255 0 S 199 255 255 0 S 200 255 250 0 S 201 255 245 0 S 202 255 240 0 S 203 255 235 0 S 204 255 229 0 S 205 255 224 0 S 206 255 219 0 S 207 255 214 0 S 208 255 209 0 S 209 255 204 0 S 210 255 199 0 S 211 255 194 0 S 212 255 189 0 S 213 255 184 0 S 214 255 178 0 S 215 255 173 0 S 216 255 168 0 S 217 255 163 0 S 218 255 158 0 S 219 255 153 0 S 220 255 148 0 S 221 255 143 0 S 222 255 138 0 S 223 255 133 0 S 224 255 127 0 S 225 255 122 0 S 226 255 117 0 S 227 255 112 0 S 228 255 107 0 S 229 255 102 0 S 230 255 97 0 S 231 255 92 0 S 232 255 87 0 S 233 255 82 0 S 234 255 76 0 S 235 255 71 0 S 236 255 66 0 S 237 255 61 0 S 238 255 56 0 S 239 255 51 0 S 240 255 46 0 S 241 255 41 0 S 242 255 36 0 S 243 255 31 0 S 244 255 25 0 S 245 255 20 0 S 246 255 15 0 S 247 255 10 0 S 248 255 5 0 S 249 255 0 0 S 250 255 0 3 S 251 255 0 5 S 252 255 0 8 S 253 255 0 10 S 254 255 0 13 S 255 255 0 16 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/cardiac.lut����������������������������������������������������0000755�0001750�0001750�00000001400�07152134654�017125� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������IHFEDBA?>=;:976430-)&#  ���������������������������������  $'+/269=ADHLOSVZ_chmqv{}wpjc]VI¼}yvrnkgc`\YUQNJFC?<841-)&" ����������������������������������������������������������������� !%)-26:>BFJNSW[_cgkotx| %.6?GPXairz{vqmhc_ZUPLGB>952.+'$  ������������������������������������������������� ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/pink.lut�������������������������������������������������������0000755�0001750�0001750�00000001400�10402253742�016470� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%%%%****...2222666:::====@@@CCCFFFIIIKKKNNNPPPSSSUUXXXZZZ\\^^^``bbbddffhhhjjllmmooqqqssttvvxxyy{}}~~�� """$$$'''')))+++---///00022244455577888:::;;===>>???AABBCCCDDFFGGHHIIIJJLLMMNNOOPQQRRSSTTUUVWWXXYZZ[[\]]^^^_``abbcdddeffghiiijklmmmnoppqqrsstuvvwxxyz{{|}}�� """$$$'''')))+++---///00022244455577888:::;;===>>???AABBCCCDDFFGGHHIIIJJLLMMNNOOPQQRRSSTTUUVWWXXYZZ[[\]]^^^_``abbcdddeffghiiijklmmmnoppqqrsstuvvwxxyz{{|}}����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/x_rain.lut�����������������������������������������������������0000755�0001750�0001750�00000001400�07152134664�017020� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  "$&(*,.02468:<>@><:86420.,*(&$"  ���������������������������������  $(,048<@DHLPTX\`dhlptx|����������������������������������������������������������������� (08@HPX`hpx~{xurolifc`]ZWTQNKHEB?<9630-*'$! �  $(,048<@DHLPTX\`dhlptx|ǿwog_WOG?7/'��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/pink_old.lut���������������������������������������������������0000755�0001750�0001750�00000001400�07177672730�017347� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%*.26:=@CFIKNPSUXZ\^`bdfhjlmoqstvxy{}~� "$')+-/024578:;=>?ABCDFGHIJLMNOPQRSTUVWXYZ[\]^^_`abcddefghiijklmmnoppqrsstuvvwxxyz{{|}}~� "$')+-/024578:;=>?ABCDFGHIJLMNOPQRSTUVWXYZ[\]^^_`abcddefghiijklmmnoppqrsstuvvwxxyz{{|}}~����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/3warm.lut������������������������������������������������������0000755�0001750�0001750�00000001400�10314612026�016554� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/6bluegrn.lut���������������������������������������������������0000755�0001750�0001750�00000001400�10332735000�017245� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~�~~}}{{zzxxwwuuttrrqqoonnllkkiihhffeeccbb``__]]\\ZZYYWWVVTTSSQQPPNNMMKKJJHHGGEEDDBBAA??>><<;;99886655332200//--,,**))''&&$$##!! ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/16.lut���������������������������������������������������������0000755�0001750�0001750�00000001400�07362474124�015767� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 000000000000000@@@@@@@@@@@@@@@PPPPPPPPPPPPPPP```````````````ppppppppppppppp��������������� 000000000000000@@@@@@@@@@@@@@@PPPPPPPPPPPPPPP```````````````ppppppppppppppp��������������� 000000000000000@@@@@@@@@@@@@@@PPPPPPPPPPPPPPP```````````````ppppppppppppppp����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/5redyell.lut���������������������������������������������������0000755�0001750�0001750�00000001400�10332735216�017257� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/HOTIRON.lut����������������������������������������������������0000755�0001750�0001750�00000001400�07252515352�016660� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  "$&(*,.02468:<>@BDFHJLNPRTVXZ\^`bdfhjlnprtvxz|~���������������������������������������������������������������������������������������������������������������������������������  "$&(*,.02468:<>@BDFHJLNPRTVXZ\^`bdfhjlnprtvxz|~������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  $(,048<@DHLPTX\`dhlptx|����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/NIH.lut��������������������������������������������������������0000755�0001750�0001750�00000001400�07152134566�016157� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� "'-38>DIOUOJE?:5/*% ������������������������������������������������������������������������������������������������� %*/5:?EJOU_jt����������������������������������������������������������������� %*/5:?EJOUZ_djotzĿztojd_ZUQNKGDA>:741-*'#  ���������������������������������������� "-8DOZfq|ztojd_ZUZ_djotzĿtj_UJ?5* � %*/5:?EJOUOJE?:5/*% �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/Rainramp.lut���������������������������������������������������0000755�0001750�0001750�00000001400�07154025260�017302� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� !$'*-0369<?BEHKNQTWZ]`cfiljihfdcb`^]\ZXWVTRQPNLKJHFEDB@?><:9864320.-,*('&$"!  �  #&*.148<?BFJMPTX[^bfilptwz~�������������������������������������������������������������������������  $(,048<@DHLPTX\`dhlptx|~|zwtrpmjhfc`^\YVTROLJHEB@>;864344456667AN[hu� !$'*-0369<?BEHKNQTWZ]`cfilorux{~~xrlf`ZTNHB<60*$ �������������������������������������������������������������������������  #&*.148<?BFJMPTX[^bfilptwz~����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/x_hot.lut������������������������������������������������������0000755�0001750�0001750�00000001400�07152134632�016654� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  !#$%'(*+,./1235689:<=?@ACDFGHJKMNOQRTUVXY[\]_`bcdfgijkmnpqrtuwxy{|~��������������������������������������������������������������������������������������������������������������������������������� !$'*,/258:=@CFHKNQTVY\_bdgjmprux{~������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� #'+/37;?CGKOSW[_cgkosw{����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/french.lut�����������������������������������������������������0000755�0001750�0001750�00000001400�10050007430�016762� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� !"#%&'((((((((((((((('&%#"! ����������������������������������������3j� !#&)+.1369;>ACFIKNQSVY[^acfiknqsvy{~~~~~ºzrjbZRJB:2*" ������������������������ "*2:BJRZbjrz� "'+15:?CHMQW[`einsw}}|{yxwutsqpomlkjihec`][XVTRPNLJHFDB@=;85/*'%%$$$!  )8<<<<<<<<<<;83,$ �������������������������������� ;]|~����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/flow.lut�������������������������������������������������������0000755�0001750�0001750�00000001400�07152134652�016504� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  ���  $(-159=AEIMQUY]aeimquy}¿}zwtqnkheb_\YVSPMJGDA>;852/,)&#  ������������������ "&*.26:>BFJNRVZ^bfjnrvz~¾~zvrnkgc_[XTPLHEA=951.*&" ������������������������������������������������������������������������������������������������ (08@HPX`hpx����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/NIH_fire.lut���������������������������������������������������0000755�0001750�0001750�00000001400�07152134640�017155� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  #&(+.147:=@CFILORUX[^adgjmorux{~����������������������������������������������������������������������������������������������������  "%(*-0258:=@BEHKMPSUX[]`cegikmoqsuwy{}~#&*.159<@EIMQVZ^bfjosw{|xuqnjgc`\YURNKGC@<952.+'$  ������������������������������������������������������������������������������������ ")18@HOW_fnu}����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/4cool.lut������������������������������������������������������0000755�0001750�0001750�00000001400�10314612664�016553� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/bluegray.lut���������������������������������������������������0000755�0001750�0001750�00000001400�10601057642�017343� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  !!""#$$%%&''())*++,-../011234556789:;;<=>?@ABCDEFHIJKLMOPQRTUVXY[\]_`bdegijlnprsuwy|~��  !!"##$$%&&''())*++,-../0012344567889:;<=>?@ABCDEFGHIJKLNOPQSTUVXY[\]_`bceghjlmoqsuwy{}�  "#%'(*+-.01245789;<=>@ABCDEFHIJKLMNOPQRSTUUVWXYZ[\\]^_``abccdeefghhijjkllmnnoopqqrrsstuuvvwwxxyyzz{{||}}~~����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/actc.lut�������������������������������������������������������0000755�0001750�0001750�00000001400�10313662070�016440� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� (08@HPX`hpx������������������������������������������������������������������  #&),/147:=@BEHKNQSVY\_bdgjmpsux{~~{yvsqnligdb_\ZWURPMKHEC@>;9631.,)'$" ��  "$&(*-/13579<>@BDFHJLOQSUWY[^`bdfhjlnqsuwy{}}{ywusqnljhfdb`^[YWUSQOLJHFDB@><97531/-*(&$"  ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/lut/greengray.lut��������������������������������������������������0000755�0001750�0001750�00000001400�10601057300�017503� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  !!"##$%%&'(()*++,-./00123456789:;<=>?ABCDEGHIKLMOPRSUWXZ\]_acegikmortvy{~� !$&)+-02468:<>@ACEFHJKMNPQRTUVXYZ[]^_`abcdefghijklmnoopqrsstuvvwxyyz{{|}}~~��  !!""#$$%&&'())*+,,-./00123456789:;<=>?@ABDEFGIJKMNOQRTUWXZ\]_acegikmoqsuxz}����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/reorient.dfm�������������������������������������������������������0000755�0001750�0001750�00000003601�11014405764�016524� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �TREORIENTFORM�0j��TPF0 TReorientForm ReorientFormLeftTop BorderStylebsDialogCaptionReorient image ClientHeight� ClientWidthhColor clBtnFace Font.CharsetDEFAULT_CHARSET Font.Color clWindowText Font.Height Font.Name MS Sans Serif Font.Style � FormStyle fsStayOnTopOldCreateOrderPositionpoScreenCenter PixelsPerInch` TextHeight �TLabelLabel1LeftTop(WidthHeight CaptionPitch��TLabelLabel2LefthTop(WidthHeight CaptionRoll��TLabelLabel3Left�Top(WidthHeight CaptionYaw��TLabelLabel4LeftTopWidthHeight CaptionX��TLabelLabel5LefthTopWidthHeight CaptionY��TLabelLabel6Left�TopWidthHeight CaptionZ��TLabelXlabelLeft TophWidthHeight CaptionXlabel��TLabelYLabelLeft TopxWidth!Height CaptionYLabel��TLabelZLabelLeft Top�Width!Height CaptionZLabel�� TRxSpinEditZEditLeft�TopWidth.Height ButtonKind bkStandardDecimal�MaxValue�������@MinValue�������TabOrder�OnChange EditChange�� TRxSpinEditYEditLeft�TopWidth.Height ButtonKind bkStandardDecimal�MaxValue�������@MinValue�������TabOrderOnChange EditChange�� TRxSpinEditXEditLeft,TopWidth.Height ButtonKind bkStandardDecimal�MaxValue�������@MinValue�������TabOrderOnChange EditChange�� TRxSpinEdit PitchEditLeft,Top$Width.Height ButtonKind bkStandardDecimal�MaxValue�������@MinValue�������TabOrderOnChange EditChange�� TRxSpinEditRollEditLeft�Top$Width.Height ButtonKind bkStandardDecimal�MaxValue�������@MinValue�������TabOrderOnChange EditChange�� TRxSpinEditYawEditLeft�Top$Width.Height ButtonKind bkStandardDecimal�MaxValue�������@MinValue�������TabOrderOnChange EditChange��TTimer ReorientTimerEnabledOnTimerReorientTimerTimerLeft(Top@����������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fastsmooth.pas�����������������������������������������������������0000755�0001750�0001750�00000034243�11647465712�017122� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fastsmooth; {$mode delphi} interface uses // LCLIntf,//<- only for gettickcount Classes, SysUtils, define_types, otsuml; procedure DilateSphere (var lImg: Bytep; lXi,lYi,lZi: integer; lVoxDistance: single; lChange: byte ); procedure SmoothFWHM2Vox (var lImg: Bytep; lXi,lYi,lZi: integer); procedure Dilate (var lImg: Bytep; lXi,lYi,lZi,lCycles: integer; lChange: byte ); procedure PreserveLargestCluster (var lImg: Bytep; lXi,lYi,lZi: integer; lClusterValue,ValueForSmallClusters: byte ); procedure MaskBackground (var lImg: Bytep; lXi,lYi,lZi,lOtsuLevels: integer; lDilateVox: single; lOneContiguousObject: boolean ); implementation procedure MaskBackground (var lImg: Bytep; lXi,lYi,lZi,lOtsuLevels: integer; lDilateVox: single; lOneContiguousObject: boolean ); var lMask: ByteP; lX,lY,lZ,lV,lXYZ: integer; begin lXYZ := lXi * lYi * lZi; if (lXi < 3) or (lYi < 3) or (lZi < 1) then exit; getmem(lMask, lXYZ); Move(lImg^[1], lMask^[1],lXYZ); SmoothFWHM2Vox(lMask, lXi,lYi,lZi); ApplyOtsuBinary (lMask, lXYZ,lOtsuLevels); //Dilate (lMask, lXi,lYi,lZi,5,255 ); if lOneContiguousObject then begin PreserveLargestCluster (lMask, lXi,lYi,lZi,255,0 ); //only preserve largest single object if lDilateVox >= 1 then DilateSphere (lMask, lXi,lYi,lZi,lDilateVox,255 ); end else begin if lDilateVox >= 1 then DilateSphere (lMask, lXi,lYi,lZi,lDilateVox,255 ); PreserveLargestCluster (lMask, lXi,lYi,lZi,0,255 ); //only erase outside air end; lV:=0; for lZ := 1 to lZi do for lY := 1 to lYi do for lX := 1 to lXi do begin inc(lV); if (lMask^[lV] = 0) or (lX=1) or (lX=lXi) or (lY=1) or (lY=lYi) or (lZ=1) or (lZ=lZi) then lImg^[lV] := 0; end; freemem(lMask); end; (*procedure MaskBackground (var lImg: Bytep; lXi,lYi,lZi: integer); var lMask: ByteP; lX,lXYZ: integer; begin lXYZ := lXi * lYi * lZi; if (lXi < 3) or (lYi < 3) or (lZi < 1) then exit; getmem(lMask, lXYZ); Move(lImg^[1], lMask^[1],lXYZ); SmoothFWHM2Vox(lMask, lXi,lYi,lZi); ApplyOtsuBinary (lMask, lXYZ); //Dilate (lMask, lXi,lYi,lZi,5,255 ); DilateSphere (lMask, lXi,lYi,lZi,5,255 ); PreserveLargestCluster (lMask, lXi,lYi,lZi,0,255 ); for lX := 1 to lXYZ do if lMask^[lX] = 0 then lImg^[lX] := 0; freemem(lMask); end;*) procedure CountClusterSize (var lImg: Bytep; var lClusterBuff: longintp; lXi,lYi,lZi: integer; lClusterValue: byte); //Given volume lImg, will generate volume lCount with number of connected voxels with value lCluster var lStart: DWord; lTopSlice,lInc,lXY,lXYZ,lClusterSign,lQTail,lQHead,lQSz,lClusterSz,lClusterFillValue: integer; lQra: LongIntP; const kFillValue = -2; Procedure IncQra(var lVal, lQSz: integer); begin inc(lVal); if lVal >= lQSz then lVal := 1; end; //nested incQra procedure Check(lPixel: integer); begin if (lClusterBuff^[lPixel]=lClusterSign) then begin//add item incQra(lQHead,lQSz); inc(lClusterSz); lClusterBuff^[lPixel] := lClusterFillValue; lQra^[lQHead] := lPixel; end; end;//nested Check PROCEDURE RetirePixel; //FIFO cleanup , 1410: added 18-voxel check var lVal: integer; BEGIN lVal := lQra^[lQTail]; if (lVal < lTopSlice) and (lVal > lXY) then begin (* //next code avoids left-right and anterior-posterior wrapping... if lVal = 0 then begin //should never happen: unmarked voxel = increment lQTail so not infinite loop incQra(lQTail,lQSz); //done with this pixel exit; end; lXpos := lVal mod lXi; if lXpos = 0 then lXPos := lXi; lYpos := (1+((lVal-1) div lXi)) mod lYi; if lYPos = 0 then lYPos := lYi; lZpos := ((lVal-1) div lXY)+1; if (lXPos <= 1) or (lXPos >= lXi) or (lYPos <= 1) or (lYPos >= lYi) or (lZPos <= 1) or (lZPos >= lZi) then // retire and exit else begin *) Check(lVal-1); //left Check(lVal+1); //right Check(lVal-lXi); //up Check(lVal+lXi); //down Check(lVal-lXY); //up Check(lVal+lXY); //down (* //check plane above lValX := lVal + lSLiceSz; Check(lValX-1); //left Check(lValX+1); //right Check(lValX-lXDimM); //up Check(lValX+lXDimM); //down //check plane below lValX := lVal - lSLiceSz; Check(lValX-1); //left Check(lValX+1); //right Check(lValX-lXDimM); //up Check(lValX+lXDimM); //down //check diagonals of current plane Check(lVal-lXDimM-1); //up, left Check(lVal-lXDimM+1); //up, right Check(lVal+lXDimM-1); //down, left Check(lVal+lXDimM+1); //down, right *) end;{} //not edge incQra(lQTail,lQSz); //done with this pixel END; procedure FillStart (lPt: integer); {FIFO algorithm: keep memory VERY low} //var lI: integer; begin (*if (lClusterBuff^[lPt]<>lClusterSign) then exit;*) lQHead := 0; lQTail := 1; Check(lPt); RetirePixel; while ((lQHead+1) <> lQTail) do begin//complete until all voxels in buffer have been tested RetirePixel; if (lQHead = lQSz) and (lQTail = 1) then exit; //break condition: avoids possible infinite loop where QTail is being incremented but QHead is stuck at maximum value end; end; procedure SelectClusters (lSign: integer); var lInc,lV: integer; begin for lInc := 1 to lXYZ do begin if lClusterBuff^[lInc] = lSign then begin // measure size of the cluster and fill it with kFillValue lClusterSz := 0; lClusterSign := lSign; lClusterFillValue := kFillValue; FillStart(lInc); // now fill the cluster with its size (=1 if the voxel was isolated) if lClusterSz > 1 then begin for lV := 1 to lXYZ do if lClusterBuff^[lV] = kFillValue then lClusterBuff^[lV] := lClusterSz; end else lClusterBuff^[lInc] := 1; //fill all voxels in cluster with size of voxel end;//target color end; //for each voxel end; //nested SelectClusters begin //proc CountClusterSize if (lXi < 5) or (lYi < 5) or (lZi < 3) then exit; lXY := lXi*lYi; //offset one slice lTopSlice := (lZi-1) * lXY; lXYZ :=lXY*lZi; lQSz := (lXYZ div 4)+8; GetMem(lQra,lQsz * sizeof(longint) ); for lInc := 1 to lXYZ do begin if lImg^[lInc] = lClusterValue then lClusterBuff^[lInc] := -1 //target voxel - will be part of a cluster of size 1..XYZ else lClusterBuff^[lInc] := 0;//not a target, not part of a cluser, size = 0 end; //lStart := GetTickCount; SelectClusters(-1); //for each voxel with intensity=-1, change value to number of connected voxels in cluster //fx(GetTickCount-lStart); //we did not fill bottom slice... for lInc := 1 to lXY do if lImg^[lInc] = lClusterValue then lClusterBuff^[lInc] := lClusterBuff^[lInc+lXY]; //we did not fill top slice for lInc := (lTopSlice+1) to (lTopSlice+lXY) do if lImg^[lInc] = lClusterValue then lClusterBuff^[lInc] := lClusterBuff^[lInc-lXY]; Freemem(lQra); end; //proc CountClusterSize procedure PreserveLargestCluster (var lImg: Bytep; lXi,lYi,lZi: integer; lClusterValue,ValueForSmallClusters: byte ); var lC,lXYZ,lX: integer; lTemp: longintp; begin if (lXi < 5) or (lYi < 5) or (lZi < 1) then exit; lXYZ :=lXi*lYi*lZi; //ensure at least some voxels exist with clusterValue lC := 0; for lX := 1 to lXYZ do if lImg^[lX] = lClusterValue then inc (lC); if lC < 2 then exit;//e.g. if lC = 1 then only a single voxel, which is in fact largest cluster getmem(lTemp,lXYZ*sizeof(longint)); CountClusterSize(lImg,lTemp,lXi,lYi,lZi,lClusterValue); lC := 0; for lX := 1 to lXYZ do if lTemp^[lX] > lC then lC := lTemp^[lX]; if ValueForSmallClusters = 0 then begin for lX := 1 to lXYZ do if (lTemp^[lX] >= 0) and (lTemp^[lX] < lC) then //cluster, but not biggest one... lImg^[lX] := ValueForSmallClusters; end else for lX := 1 to lXYZ do if (lTemp^[lX] > 0) and (lTemp^[lX] < lC) then //cluster, but not biggest one... lImg^[lX] := ValueForSmallClusters; freemem(lTemp); end; procedure Dilate (var lImg: Bytep; lXi,lYi,lZi,lCycles: integer; lChange: byte ); //Dilates Diamonds - neighbor coefficient = 0 //Dilate if Change=1 then all voxels where intensity <> 1 but where any neighbors = 1 will become 1 //Erode if Change=0 then all voxels where intensity <>0 but where any neighbors = 0 will become 0 //step is repeated for lCycles var lC,lX,lY,lZ, lXY,lXYZ,lPos,lOffset,lN: integer; lTemp: bytep; begin if (lXi < 5) or (lYi < 5) or (lZi < 1) then exit; lXY := lXi*lYi; //offset one slice lXYZ :=lXY*lZi; getmem(lTemp,lXYZ); for lC := 1 to lCycles do begin Move(lImg^[1], lTemp^[1],lXYZ); for lZ := 1 to lZi do begin for lY := 1 to lYi do begin lOffset := ((lY-1)*lXi) + ((lZ-1) * lXY); for lX := 1 to lXi do begin lPos := lOffset + lX; if (lTemp^[lPos] <> lChange) then begin if (lX>1) and (lTemp^[lPos-1] = lChange) then lImg^[lPos] := lChange; if (lX<lXi) and (lTemp^[lPos+1] = lChange) then lImg^[lPos] := lChange; if (lY>1) and (lTemp^[lPos-lXi] = lChange) then lImg^[lPos] := lChange; if (lY<lYi) and (lTemp^[lPos+lXi] = lChange) then lImg^[lPos] := lChange; if (lZ>1) and (lTemp^[lPos-lXY] = lChange) then lImg^[lPos] := lChange; if (lZ<lZi) and (lTemp^[lPos+lXY] = lChange) then lImg^[lPos] := lChange; end; //voxel <> lChange end; end;//Y end; //Z end; freemem(lTemp); end; procedure SmoothFWHM2Vox (var lImg: Bytep; lXi,lYi,lZi: integer); const k0=240;//weight of center voxel k1=120;//weight of nearest neighbors k2=15;//weight of subsequent neighbors kTot=k0+k1+k1+k2+k2; //weight of center plus all neighbors within 2 voxels kWid = 2; //we will look +/- 2 voxels from center var lyPos,lPos,lWSum,lX,lY,lZ,lXi2,lXY,lXY2: integer; lTemp: bytep; begin if (lXi < 5) or (lYi < 5) then exit; lXY := lXi*lYi; //offset one slice lXY2 := lXY * 2; //offset two slices lXi2 := lXi*2;//offset to voxel two lines above or below getmem(lTemp,lXi*lYi*lZi*sizeof(byte)); for lPos := 1 to (lXi*lYi*lZi) do lTemp^[lPos] := lImg^[lPos]; //smooth horizontally for lZ := 1 to lZi do begin for lY := (1) to (lYi) do begin lyPos := ((lY-1)*lXi) + ((lZ-1)*lXY) ; for lX := (1+kWid) to (lXi-kWid) do begin lPos := lyPos + lX; lWSum := lImg^[lPos-2]*k2+lImg^[lPos-1]*k1 +lImg^[lPos]*k0 +lImg^[lPos+1]*k1+lImg^[lPos+2]*k2; lTemp^[lPos] := lWSum div kTot; end; {lX} end; {lY} end; //lZi //smooth vertically for lPos := 1 to (lXi*lYi*lZi) do lImg^[lPos] := lTemp^[lPos];//fill in sides for lZ := 1 to lZi do begin for lX := (1) to (lXi) do begin for lY := (1+kWid) to (lYi-kWid) do begin lPos := ((lY-1)*lXi) + lX + ((lZ-1)*lXY) ; lWSum := lTemp^[lPos-lXi2]*k2+lTemp^[lPos-lXi]*k1 +lTemp^[lPos]*k0 +lTemp^[lPos+lXi]*k1+lTemp^[lPos+lXi2]*k2; lImg^[lPos] := lWSum div kTot; end; {lX} end; //lY end; //lZ //if 3rd dimension.... if lZi >= 5 then begin //smooth across slices for lPos := 1 to (lXi*lYi*lZi) do lTemp^[lPos] := lImg^[lPos]; //fill in sides for lZ := (1+kWid) to (lZi-kWid) do begin for lY := (1) to (lYi) do begin lyPos := ((lY-1)*lXi) + ((lZ-1)*lXY) ; for lX := (1) to (lXi) do begin lPos := lyPos + lX; lWSum := lImg^[lPos-lXY2]*k2+lImg^[lPos-lXY]*k1 +lImg^[lPos]*k0 +lImg^[lPos+lXY]*k1+lImg^[lPos+lXY2]*k2; lTemp^[lPos] := lWSum div kTot; end; {lX} end; {lY} end; //lZi for lPos := 1 to (lXi*lYi*lZi) do lImg^[lPos] := lTemp^[lPos]; end; //at least 5 slices... //free memory freemem(lTemp); end; procedure DilateSphere (var lImg: Bytep; lXi,lYi,lZi: integer; lVoxDistance: single; lChange: byte ); //INPUT: Img is array of bytes 1..XYZ that represents 3D volume, lXi,lYi,lZi are number of voxels in each dimension // lVoxDistance is search radius (in voxels) // lChange is the intensity to be changed - if background color: erosion, if foreground color: dilation //OUTPUT: Eroded/Dilated Img var lDxI,lXY,lXYZ,lZ,lY,lX, lVoxOK,lPos: integer; lDx: single; lSearch: array of integer; lTemp: bytep; function HasNeighbor (lVox: integer): boolean; var s,t: integer; begin result := true; for s := 0 to (lVoxOK-1) do begin t := lVox +lSearch[s]; if (t > 0) and (t <= lXYZ) and (lTemp^[t] = lChange) then exit; end; result := false; end; //nested HasNeighbor begin //proc DilateSphere if lVoxDistance < 1 then exit; if lVoxDistance = 1 then begin //much faster to use classic neighbor dilation Dilate(lImg,Lxi,lYi,lZi,1,lChange); exit; end; if (lXi < 3) or (lYi < 3) or (lZi < 3) then exit; lXY := lXi*lYi; //voxels per slice lXYZ := lXY*lZi; //voxels per volume //next: make 1D array of all voxels within search sphere: store offset from center lDxI := trunc(lVoxDistance); //no voxel will be searched further than DxI from center setlength(lSearch,((lDxI *2)+1)*((lDxI *2)+1)*((lDxI *2)+1) ); lVoxOK := 0; for lZ := -lDxI to lDxI do for lY := -lDxI to lDxI do for lX := -lDxI to lDxI do begin lDx := sqrt( sqr(lX)+ sqr(lY)+ sqr(lZ) ); if (lDx < lVoxDistance) and (lDx > 0) then begin lSearch[lVoxOK] := lX + (lY*lXi)+(lZ * lXY); //offset to center inc(lVoxOK); end; //in range, not center end; //lX getmem(lTemp, lXYZ);//we need a temporary buffer, as we will be dilating the original image Move(lImg^[1], lTemp^[1],lXYZ); lPos := 0; for lX := 1 to lXYZ do begin inc(lPos); if (lTemp^[lPos] <> lChange) and HasNeighbor(lPos) then lImg^[lPos] := lChange; end; //for X, each voxel freemem(lTemp); //free temporary buffer lSearch := nil; //free 1D search space end; //proc DilateSphere end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/imgutil.pas��������������������������������������������������������0000755�0001750�0001750�00000005754�12306420740�016373� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit imgutil; {$H+} interface function UnscaledMean (lOverlayNum: integer): double; function ScaledMean (lOverlayNum: integer): double; procedure BatchChangeInterceptSoVOIEqualsZero; implementation uses text,nifti_hdr,nifti_hdr_view,define_types,nifti_img, nifti_img_view, nifti_types; function UnscaledMean (lOverlayNum: integer): double; //kVOIOverlayNum var lROIVol,lInc: integer; lROISum: double; begin //proc ShowDescript result := 0; if gMRIcroOverlay[lOverlayNum].ScrnBufferItems <> gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems then exit; lROIVol := 0; lROISum := 0; for lInc := 1 to gMRIcroOverlay[lOverlayNum].ScrnBufferItems do begin if gMRIcroOverlay[lOverlayNum].ScrnBuffer^[lInc] > 0 then begin lROISum := lROISum + RawBGIntensity(lInc); inc(lROIVol); end; end; //for each voxel if lROIVol > 0 then result := lROISum/lROIVol; end; function ScaledMean (lOverlayNum: integer): double; begin result := UnscaledMean(lOverlayNum); result := Raw2ScaledIntensity (gMRIcroOverlay[kBGOverlayNum],result); end; procedure BatchChangeInterceptSoVOIEqualsZero; var lInc,lNumberofFiles,lMinClusterSz: integer; lZeroHdr : TNIfTIHdr; lFilename,lVOIname:string; lPref: boolean; lMean: double; begin for lInc := 1 to (knMaxOverlay-1) do FreeImgMemory(gMRIcroOverlay[lInc]); ImgForm.UpdateLayerMenu; if not OpenDialogExecute(kImgPlusVOIFilter,'Select volume of interest',false) then exit; lVOIName := HdrForm.OpenHdrDlg.FileName; if not OpenDialogExecute(kImgFilter,'Select perfusion images',true) then exit; lNumberofFiles:= HdrForm.OpenHdrDlg.Files.Count; if lNumberofFiles < 1 then exit; TextForm.MemoT.Lines.Clear; lPref := gBGImg.ResliceOnLoad; gBGImg.ResliceOnLoad := false; for lInc:= 1 to lNumberofFiles do begin lFilename := HdrForm.OpenHdrDlg.Files[lInc-1]; ImgForm.OpenAndDisplayImg(lFilename,false); ImgForm.OverlayOpenCore ( lVOIname, kVOIOverlayNum); lMean := UnscaledMean(kVOIOverlayNum); lZeroHdr := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr; if lZeroHdr.scl_slope <> 1 then TextForm.MemoT.Lines.Add(lFilename+' Scale slope is not 1, please contact Chris Rorden ') else if lMean <> 0 then begin TextForm.MemoT.Lines.Add(lFilename+kTextSep+realtostr(lMean,5)); lZeroHdr.scl_inter := lZeroHdr.scl_inter - lMean; lFilename := changefileprefix(lFilename,'z'); SaveAsVOIorNIFTIcore (lFilename, gMRIcroOverlay[kBGOverlayNum].ImgBuffer,gMRIcroOverlay[kBGOverlayNum].ImgBufferItems,gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP,1,lZeroHdr) end else TextForm.MemoT.Lines.Add(lFilename+' UNCHANGED (mean of VOI is already zero) '); //FindClustersText(gMRIcroOverlay[kBGOverlayNum], lThresh,lMinClusterSz); end;//lLoop gBGImg.ResliceOnLoad := lPref; TextForm.Show; end; end. ��������������������mricron-0.20140804.1~dfsg.1.orig/ReadInt.lfm��������������������������������������������������������0000755�0001750�0001750�00000002000�12332725756�016235� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object ReadIntForm: TReadIntForm Left = 334 Height = 95 Top = 206 Width = 600 ActiveControl = ReadIntEdit BorderStyle = bsDialog Caption = 'Integer required' ClientHeight = 95 ClientWidth = 600 Constraints.MaxHeight = 95 Constraints.MaxWidth = 600 Constraints.MinHeight = 95 Constraints.MinWidth = 600 Font.Name = 'MS Sans Serif' OnCreate = FormCreate OnShow = FormShow Position = poScreenCenter LCLVersion = '1.0.12.0' object ReadIntLabel: TLabel Left = 8 Height = 14 Top = 15 Width = 448 Alignment = taRightJustify AutoSize = False Caption = 'Enter a number' ParentColor = False end object ReadIntEdit: TSpinEdit Left = 472 Height = 16 Top = 12 Width = 120 MaxValue = 0 TabOrder = 1 end object OKBtn: TButton Left = 472 Height = 25 Top = 55 Width = 75 BorderSpacing.InnerBorder = 4 Caption = 'OK' OnClick = OKBtnClick TabOrder = 0 end end mricron-0.20140804.1~dfsg.1.orig/templates/���������������������������������������������������������0000755�0001750�0001750�00000000000�12413465015�016177� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/templates/aal.nii.lut����������������������������������������������0000755�0001750�0001750�00000001400�07463231170�020240� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������==����ˢ����������Ƹ ��66^^&&QQLL����^^^^^^zzHH��˿��ll��ff==����ˢ��������������LL ������ZZvvvvvv����__ee//vvCC����������������LL̕==��66^^��QQ����������Ɣ˰66$$EEEE����//�� ��HHffff55��55ff==��66^^�Q����������e�uuCC��LL BB��BBZZ����;;����VVVV--CC����������ee��uuCC��LL̕��66 \\88����������ll''��CC@@**//66SS��LL CC������ˢ����ff��66 \\8����������FssCC�� ����������TT!!__��hhDD;;55PPTT��11����������FFssCC������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/templates/aal.nii.gz�����������������������������������������������0000755�0001750�0001750�00000477504�10403121566�020075� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������u D�aal.nii�IrIa"'4{HАJrL�Xܵ܁ mAKD>y o"X9UE"#17W s?K?__?o?rzυ1?į}ۧ_#B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!Bhaܔw@ Wik7 D,}@Ri=<4a:I@gA&D3[!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!wssS7|1-}stnJ-MNй:WD-P4B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!pv@TiS?z=6e37@_7= Zۈv`Fg`kg͜ - hAvB'7 pwwvvzojIlU[!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!o릭4ïnJ{ыP+%Uzj =c5uS <e]X)Tګh"M-W޹3itgm&|ea֥-B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!~nJ+Y ŵo>4iгgG_?Ftұ�Μ}-8;�m6@q4e6hҬUG*nhK0;KoբRo` ڕt4w3:Y&<؎v@g0kbvn1Lkfs3;GK,Q*F!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B'4ïoJ[YCSi! ={=_6:!G_Cֶk)a͓֙9 7牶3jҬ�m2軺hM4G=WKoբRo>M=Ou%зgAj4f-$bڊ63I? s�).2O:7=4 niB!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!Lp}*x4Ϟ5'@/c]M. ̙y %$kvA9Њ؉m0flN&VŜzmh~wgU [<ĉgv1軙nȍ]}@n|f mc a^Z1K7= RI>4h-_y:;{:Y ך9vI-]oEg0tپg֣kbѶdL3D3[hF!B!B!B!B!B!B!B!B!B!B!B!B!B!B!Bn<C[iC77z=o|7jyﻮ\B3o4eYăy :Q͓79*م7fdN1[fsQj Zˣݝ:%l@[MَIv1w컡hG' VP: ۂwhwvRF:Ǭ]F=׬gffttI=.o'T`ZovC'5z3.hv@KOmW. M\<ؠ\7#rfvNAn٥ -ьB!B!B!B!B!B!B!B!B!B!B!B!B!B!B!Aǥ7_U}S7R7h^ZwsolCShllyh֡yv)7@[m3m5kftbByľk*v3*hG`vE.};k,hw|f΋af+Z1㚗n~hbi4f縲N`Bv龯6 2f7'tBm4sl=:َ&c1,?U׳u0󤘙\u?�dnޕ1IfV*ef̬!B!B!B!B!B!B!B!B!B!B!B!B!B!B!BXi[JQݯ79_ų$4uN߈ 7yBo>䞶dnN~ywklSfAxz7Zd'$zΜ m2kZMknДY֛9u۵e!䳶Y6Y0Q[ܬfU}wN0.fQ}䬎vMNvg oc]зaT,FmFu1mR'Eϙ@s:#:نVs@�+1&O4SuOy^9Y]`}v|/OK7}lJgsCqD'3'FkF÷]Â&c&FnSbnLsLh"d&]wː&ˡB!B!B!B!B!B!B!B!B!B!B!B!B!B!B!}zȞl&Sݴg=Y_72_#$UEu`l|ݘwƵ;:'l'bB7oRmfZg΁5lF I61{ev36Sh_)>軂h;ʾ*0*hgsB; aз3DvmbFv6{hf;Bى~xm $ώfAfOt,?tlzx:agS<Y$*,7t* x:Y 7f3Zάobn4+!̼2:TU&Y s'Z!B!B!B!B!B!B!B!B!B!B!B!B!B!B!OӇ7MA}ZZ6㞵\E],ד~ڙ2٪q/K:6fF.ﬕ\WyZͱS9DR[~ѝTmN3j;Y֢3CzMm-i/ZuZh9Sj3g'AE#]^*ˁ@noo%sI˜o8fDT;oD]};CmGZvryNhg:#:yh gf潣g0zhhkEOCG6{E7l74wt|r֙ fWt9էj 4$;:V[=~tMf9TۧYQ' 9uK<q!B!B!B!B!B!B!B!B!B!B!B!B!B!B!>t*-aBo,> kM?(凫1yhZ\כkdzٜM<5nZ5_+]sC;Iݳsf7C[ `NΖ3 -h-Ӡmf}7\u{;ܣͷC.]VHDi>湠 Z.K@+ftN<~;B6H j?0>Pt4v4ZN4�͊k」,7<>}3=Б>&Nb6fG2̂<o0kV]lӳ*q|jfBedH0iyD\HUD3B!B!B!B!B!B!B!B!B!B!B!B!B!B!B%\iCo>-H7 Gx-e:2^A)?56Uti`p;HBn ڄ:mݔ[`zLSIsVsD5AVrGg55gM5hb 2֡oLNpW;Uz֮sD+Nc~m&YBK;?tL;v)6ǜkssQ'B{o8]}86]<ϜUeaE;ΙBk~D6H j?0n&uy=}shдCG#Yq4FO\zxbQ O|:&avEKO,f>lR͂:;Zy\egD7ئ5)&V3K3Uw :nyT3G榴 %B!B!B!B!B!B!B!B!B!B!B!B!B!B!BRi=<w4!?|6JkkއrpވP+s}Eo/ZrAfC[TΗd)hzH}bv3 MЙ؎9fMiv)֙ӣ=Zk>湠l/jMe}Whk0[2;<'YBى63v[#ZVcA{ 4.K@+fgt^y.h/3ohb:4i֠)eAg. =<뇎gCK-nnhoff4*no. QQcDww}"Ru迭fVkc̬?4,L1LE^k *KM2hӌB!B!B!B!B!B!B!B!B!B!B!B!B!B!TۓF4![kί~-Ҁ&ucWJM޿\7<p F+g^ZթUt^q>hB,u5y4u֦9_{o2i:Ϭ5sV Fg3M:3ӳNh67iufm0'Ϝ=Ig5www@\]Sߜ+mǾqǾru };GDZv]팾wvEߚ6 $6p븝+}dD+fW4sU3:͝M}ڸӽlh9th-Ь4 \?t4'Zzn1tvCSO.fOxV33td3cNhݓ\5ev0?Ru$o3a3ȬQe{1LCG'בSk1J*Kt+6iF!B!B!B!B!B!B!B!B!B!B!B!B!B!Bh>%8O<y)AOmeR p<w5 u3Fk]* fZ' R^y^h'1se^w%=ZuQ^|dF[<L:v9<Оf'trG6o_y]13w ~oЦgֲm0sYVHDѺV2Dk?#;6AҠB;4NRtBS湣I:KeK;ˠu,ߧM$=qГgGhf#gG3 ;7}K Hf{닎efAhṞhz;:9#͙?fD3IZ4/قYl!?rQ͌iD.={tZ3 4,K[]<jeWeff& iΥ%B!BȝU6v@YWiOg{B_5q7*MD^ -7G hټb)lKb?kgXs՜p՜CSКsnͬe]93saE'uާKRХAnldvxD3B!B!B!B!B!B!B!B!B!B!&t+2A\f G tN6<l YO@/֚SU  TBflDe6t^Dgk%ͪFVg|ڍ^\sM;Ǭk%3vbsZNnh:y:onj9j��swN&킾GGRo:sW ;N}N4jgֲjLz򭐈ְo\ъ::ZI5+jMUs0:msfMДyhN?Ѫ Z2LQLhAO@O6 lMiu|sF�tYݷtsqȃ-<y| ͣ?ȭC)l\ hyNfZcdQݺь}HGt|Vw#oNnқ}etJo=:y6c5:/,inΦEB!BՕFxvv<Y6iӄVMg\lNZz5J(Y7g`hGќ~в99x:Z1GjgSlY =o՜SSuLޜG.mf٘HO9K>/ƸH4:[ $Q]ځB!B!B!B!B!B!B!B!B!BTeJg.~D]5湣 nFsE?Kn~?3ţKAwB`v zß=os~>~|ލRF3Z@7@_+P7`6m |ʌr Sܡh3_[Z՜|{]1{]W b~!N父4NA}+fw]0;><'YASh<w4ivF).vьj]M(Zdh74R&]ј炦/Ԙg~fL2;熠csQ >Gl2c`6g+<^{ȴg).f:lD3QF5OD="9FnDf�3E6ptz?Ze6*etb&O3W93 6rfV-ьB!k:*κbFBY)W*3xF(hʜ 7jEg^F�NȞ6so(UsJqޞKbN>Fftl֙S[vZkN>֛Ӡ# ٢M湢hC.T'C%NT' :c3e>V'BMyˢkv+3ٹïeѡl4s#gfK175b6jlIfB!B!B!B!B!B!B!B!B!Oykt2JUZsj;kftN6 :=nhGu!{.Uj֡fJ2:=̲ꞇJ}swꇧ(7kA_soTqJRוL~Fvv9snӠo=.W;кA2hyDk͵:m5df{][];AmD߼:YO޳΍5,Vv]팾wV{hzs՚YB+f'#ѕa*bgDyh&ر8ѤVy&ь@ߜB6cDhfEfG4M}lX$~<lzyTwFϵߨf&o-s%&3:gVбL0+12YPCp@H@d3BtDs}1q͌{%tî:!hS qf,̬8t"Xb6*V٩Jh&=Y83˙Y.gD3B!B%;mjS}Yձ(6]Qԫ3XBժz*`iΉnYAcN>^ا$;@PlνAȪyh՜}ܴRS쏶97P?ݜJݣ5gC̩ݰZst>>֓6si'蓦A:Zwpz*w;}ĬrI͌5nO?d}:Y;ZVgE362\7YYtpDF4[ "S^bZ\D#B!B!B!B!B!B!B!B!B!L9;QqқK_WyhRLm|lyhX9.fNv2lBl?<.Q-||vy>hGg2Ue$L*>[UevV7i3Zp klD׽*FkVtzjN0_2iv:k4Zc~Mo\Ќo;hӚ};ԉHsNA<}+χ;V3~DD贓ndbvD?9K'hnl[WـO84e֣W`k\wwЯ%h7Я%hNqѽَfYN=N쀮 6ӽh}p0_[ƏLOd+0puTfe{H0̈nϾ=Hv8Tj3:1(S?6Sh? :YbDfO hS3<珦ةRfHmf2;NS67yx!Bi)JkͧVZeCWޮi^uqSJ ih}*$>ZxUqde@GbKh9Zm1lascmh5'FMDۣ֘w^tt7 |MќjiLhޣ'C-R@whK|,\-ҙ֙Oҙ9q�Z+JcfǤ mgD8DfFx=ІWbBqYa+EPF95r*efrYfY?sB!B!B!B!B!B!B!B!B!S}uVmQk9�Zh9;$9 fOt>,Y6vBg9ܡ?BjsPps{gwy3.JxP}C{Cb?n6h\Uߣ}vuF-<f}mAgT-S03łՆAM\]Zc~|E6L߿??5M㠵s֛є:u5hcSk̯9ֹ+ּ o[w Y99\ׂ4hx>&;ZU3NMSG&<;":hݯ$4Uw4YtHf>hHfVsBC[?zxM@ԹnhN1戊N=삮NN]xa*ZehEMӘt�7+f ͆Nfnܔۏ"h&̙ސͧyvؗ&TtRsA趫fƈ?(JmQ?&7ٺ:YَN!f~h;GztW5l&Wm!hU}X)OVIthЦ͟,y!B(m<^[V{BZqEC흶MCV)ѧ| :LZxSQ&X5BŶh99zd3m3Gz)FEg]KЙAhG՜r'isb4ƜqjǦ.Ir4Gs>91 u>nsFe@莭''"Zy\6+hyIlڠN̩yqdt[3әgx mWD湣ܞ*@֣]_"u\d23#:"uxT5ʅY\yly%B!B!B!B!B!B!B!B!Behϸ?CկJQeYFф&\F3ǶmbNw5 lDdv7of>gvvrh?sVma�;3 ]Nϋ p6YB_m<Fٯ^B_sf-Hٹ6ysOn65hلfFH&/] o}VGJn>DyZ<3f3EhN>נ{3E 1 NLoth~m F!#Nkix$w]YG}+נdӘiSK'$lf$f뮍|@Gt; } =LGD@;+6{Ts1t2[Kltf4#ĺ2ͦ7I[6zU5GtAsnȣMl[lP+ :JBVF55&�HS;D'2Ǯ<b֡y;#Nh\=;REBDRM-;M[̓3&7[67fBjb쬪ŵ|֘cOIۙW ѧBq+hټ驢`/m6m1m3@#Th<kΜ-'UFsvTI6S}2T}0t/Ğ ŬOjʏgNVgL,estdV̓c)!2Vl.VsGӹ0/ $wf Fn[%YF4ܕ"Ut]hfK47-O\D3B!B!B!B!B!B!B!B!B$%?BշRIe2YUͅYv:3MǶyVvDgp;:Nv6djwaj97h6EDMx@ƾ}BoN}M{sc*}=Wug}֠[uf3nYz7@W]7v}vF}C& G݌bkl@Wzvhٌ٩4*!ҡ26evoN6Y0:O]N>עkdZUG{W<?'ټYfߊ軻+h*|˫�CFw:%gw\?8:=όVv0OCO4{o] 9RoaI }gCU4MNJm�7Kǐ}uuEG% 0-Z3OІETT@қUhݠޓA}ԠdߑёM2>_rN!f z_^NF $)]":uƝL*&sB\#`Ҫ:PӔѪ̅9_2{[vHږhF!Ѫѱ٧m,ܙ"ޓl>^^qe@*uytzhyh9ZeG6m5gALewTsBtQK>3eZ':qS Xmb@'bG1c9oL#ɝѬcOeb>f cem$WM".|h%f]$/gA-Tu*LpOZ'#idEGmdƫKKZifB!B!B!B!B!B!B!B!B}v&,RhE BpyD̹Z1D:[<kVqvAN?o7Ўft 9-\N1gaDz3iվo웧9>ܤ03~E_%@﹮ R^k/DsGٯ ;u�Z6@w]Ke"3,|٬Aeakz<}=c~h;;\1Д9=Z1 W߿f+;-zJΡU +yw.œx0E;98c%4ue |nLкo8s6djf={ul}d4C_]}8􏪹/-2C*j̱I3YCB ?c36׼jOcц5;t236]j)*2E[$+|+O}E#jjnǏW ;Ҳ=ݬcB./#9t͎#b1y"tL揹͓81l9fֲK[!ТZU6ʆҪ,^4h>Uڋ\i̱д90Gbk1Ы hsD[3D'7kSnz.f5c<3D6ȱ'*Â>D>0sFMi:I|3ɖ.l$9':`B,}q:4_\Ds~ Ю J^NN NV47M33:)ل(#f:Z[-ьB!B!B!B!B!B!B!B!B{->\Ac_Մ8]6n j\gVsf <15Jn.8gG"j'tN w4 jvGwsgsA} KD=; ojO#o߾y⫽U4gJHl\߆ncZVBU3YD_;o˥d2|| ]/ivL63\N9[ rUZ4a.ҡf;;Z)u)╜;aNA͜V/LwE5uзUV07Qo]:Zw S4ێ3B[tpwBj }gD_Gj?] K#AMӡiݳu"Z9e24?t̩%d3֫~ɫ^M:9mZR5gmD;ԡYE_MF='~FGvD_q7UH*:&TnSvt?J<sq&Ϲ:euDY>-FT.BiUW[F^uV}ggT&}*I]Ԫ90 `51XngT:DZ3 4b6 vsnAkѧsvB{}||c3=Yz)vW}쉮'-}rr2O񐇹&G -v" S@hR},V1Д:%:R+h,# u:t4N~Nݱ_EDʕ=le#Vu9j6}i6Ɋֳ}י{bfF6E0БC|ČCO_*9vK4 B!B!B!B!B!B!B!B!пBQڂVѯ sq:ezs)4)qWăv#6z(s's9lG<~>ي~%* =mfRJgV)ф8 <�k>@M>@}.4L#5y5h)h7s*>7]_ʋv7_whf,#;`֠]sB;f Dљf3_kB\UF Zsyexugf+hOs>ngG ٣o8s?zbѷ nVK})Дy.h4s螽D]0zyNSw3Cu?hh3g&4!ui6B?4uՕ]ݛŬCO6l=n0k2cUڰŬ/B׻ҳcƜD/hW̲dtJ*J1BdžI ŅmT`ёd:NS{1EM0 V%J+Z-*-qo4e™bEAO])xl Mcs$6i1Ыh'; ̩;U@_ni7z=F:Sw%ttڕ+O 5S:-eON{s($Xfl3{[I!vZm0t!*RN1;Bcp OVͮh|j>8c퓎bvd1WO"mME.%יzyhW :v6;cMhs^e#I~S<t 1Ǐgf΋Vɏf2: !B!B!B!B!B!B!B!B!Bz-<F�R굒0a.V͂2Sm yLO6w>̯]yFvkGr3ڮpTنNxt Xx'vf@wMϓ_ݹIsAe#nf^h΍>?g}oC7CyV}]v_hrlA;3yo֮9KEt]N&DtYGB_낾*i* }L6j+;R}.fL?뻐ìomwwwIlMIЗv'l)Z<g/}AՓS?hfAO3ԙ&u635 $Y==h:3zY֢`3h-{:P\Y{L-hقbVԗQۺ2#%d^,9z=-cTsTkqmi;.OFTvl)lёr9:hёyt1}haQM&/J#Ds. @(zVm^^ ڦ.Ùb A$tD_r6)ъYBD 8xGm6OCSfI^Y=M'Ϻ8zg{S v0wv|ٻ;4 ]{>hGNw<ѻ3@7:[q0$ЄF4czp!w;sarDN>r[nwD)N7cVS͌5j>>>8c;qZtn~4kǥtDi/D=z,Z. D/Ή6.hflWG4>svPGEkٞf:2bڂnV)LTrmhL#tJ,YQG!B!B!B!B!B!B!B!B!PHGfMˣ 3&]5hZ#F_;sl!s&لNzky::qd4aN>ͩ-0'bKh{S5 Dlلi֚ U^lYE-v0+Axl7hv471}cz榉1gu'2_EZ͐;;7 o AW f]b.;zh t2/}Y_oFlxZ{8K|raC}0̥sw!ѫ+;<?зUf}7#,(v~#nFK g _^wIf ZzDh 2@�:+tUsDĪDGh^ ݦevE#:YaݻҳcƜ,9z=-cDj$slt\,c_]R( ]*$U":SH1OG`I 4NaTNA)t&Et fƳcM2h׌תѫV ѧC;WgMӥcz/z }'A<^ED0+ipbGfv2-wv?6FhyfB葽m*D:V'zn΁>hGVN2]]1{Gv|: it=tI|sjI"tߟ>iZ$)Z\}B?;g41sh}ܵ^o>8 $8">fKFl:6GAr v0G-ڍ$tIG1)G q|6=;Îv@{oZa4hAͬ?mG)M:ԜͳM;Sh@O1FIfF Y3;`9MeZ!B!B!B!B!B!B!B!BZZ)(jфyj̱Is['}=`.>׈&ʂv gc۸cngHkndtZǜh} =ݘ|r2'dkith7Zc֙M~hYECe ki0{7TK8c=猽ojr:ͮk]σ7W!4ʥ<Rh);z+WvY7m6%gVnfO㯗D4+@Gf}I-֘k]2Sfƾ I:OGOTooocmd,ГV4awu$;;8h}G'|% mR'EKWKif Zz@h#]=8h!VcFli@3FmdmCMV�=к8d퀶}ɷ^OExf^}<%s\t\raa R;}LU*:vLA/Tu(bB_E苬X苼hָ'/fƳWaWs@4ħӾ {C]UMv 4SЙTt^ *%6轝f= nGes\4a>;l'nS->U~McO5hgnST?;:\n@;)tA]:֙Tz7;nu{fvxHOXts>$ݣ'Ul(hݙ7D->ghnLC3}x֢<?{}|ܣ8~tD4;胖|-[x8 胤hY-=-4[I6h ^t IkZ?&QgBkZ6G6Y:Z7ަzg'V!qbݬD:.SG=qM<MifB!B!B!B!B!B!B!B!k%7J|G9 3&M 1h9?=Vcsv͜-⭇;3ǽд958] w6'ffWޜ1klyhفmC';l|nNI9nV_=ͱff>W-A;9W]n\~gon|Б؞f}3{t}ߪjM6_woݠםjD3vՕg7En,ot3-]ϸwͳm=現[Xy4mVcscYfv}0e3.C)З D_jѷK@[=lE+*|wf[ Ǐ;=@Ds cO5@ W,-X mMd3ֿ)v @3lCG1+K+zdӏر`^њyd_J^":92BǎifsLtTa`)LBtqaD_44ަd4ܾ8h:ͳ804F NCZG@_\W<9#{/sДUVBlbٺN` ־SJ>%ڋ^)ht蝝f :Me,&n+z'�jNFVѻ3Bwl΂mw<ѻ3@y6@t}@ t.sI7蚽3 ݳi-}ѭiS}*i\EgxBcEz4t#:R'7Dp`΀>̀6kه$]OM1\cmWeyG샪)>(1'5 ֱit]z@d@S@t>Pʃ>h,D3Fx,3h"bA{E'7E03[Ŝ UIt*yldsD3B!B!B!B!B!B!B!B!BKRN!#Z5�}y6aKz*|nF%4g\Ν/evC瀫Ǽkh<M5lWpb<79f۬4ld{Sf˜m7Ku~h'lծl7ʣ1Ѯd]-P<GϙBGb{a^#?B_[ig퉾~}tfgfEЬ?{ށ,fmg1_^^vf }s3=Г.Lf2΄ע%v1%RgƱLJʣ9wo<{}։:rCyf=psBZQ�mѷ EIf+Z" 43YE٢9wz?~ f#Z˞hDݙ=fZZoh]ߤC&ٓ12ҊCWuAձLO\˙f̳UtU^:}W4GF_(ff0!.^/(t"3ٓ*:0u"oW$N틅hf{:"DNDHS9jݩ&WCj葽ʪ 'GބUOǺ`8ؾ,質8ܺS]-wЫ:T-:t05i>;leq͎hO2縻6*fw:,YЮݮyԻ?:9:يCrC t|tl4`sTt>Tc2ݱi4afS "OBъJGj2|-%L@bh9ЇѪ: hIf3z>>ֵߓ\V ZޗETBfs@;&ӡ7'`hz:eءR )t]c3v �M's43Ġew&͜z6h>i6:.YN af4;6u,BG03Өܔ\E%B!B!B!B!B!B!B!B!ZfGH1f-ˣWVUIN6&s x0ʮqs}498] 3ufdN֚I91d+hN6牶 : n_)fÜ tv5Shws\@{A{;v8:f4{}sX}Wk}5[t%nģf fˡLBvӔfeG;/;3nN\ DoFvՌ�33&4~4dfsi̾߿&vz}h9߅Ώy)G4Ӛѓ$|`Ǐ^ʄֱ]slvEO4;sAO5Sh۠父hmCShlF+8'b&=[,M|݊b؄g 3;ل^GFG3sl6cuudtTDqh+4{/.hRщ{Zf'? 1u9-ytt:nbNgRS|qЫ\`3S̫U2'^W8gnJ%劂^Bl = d9.hO`XwwUPl^13<Mޞ]YS*;Uah=wѻ3@xwItTd9FkڕDl^Z1/u lGLB'I[;B4,@f-v ΰ׿fzg2zxDBO0Cܴ䃮#GJ}G'G_)W=E}CL0EGr#Us8o>9Ɂf@O0wc}"׉3#sG3'yЎRhHB;ݲң÷tV=ٜ-e4e`ؤ9*:E6ё{Itˎ)n,Ylbf4;u(BGrE2w1I1wEnfB!B!B!B!B!B!B!B!k)7beJFd~F#WeȖ5:ɉf1'97:īu N]=]EU~.nT;ӫfJN66'ӱf=< m7>$h'NvC慠':6լ=ȑlws˞<>?Uwz&~a-ʣR]^}Vףiї}Ez{h3;bW0]oHuY;Nf r 7mC{:kW27g4oZegF欙{L|w݄6G٢|:?mь?g=?Bȡ17th9ZۮlV9 jQB3>=5i4ӘNAhF]FzXP_Şş }AcϹAV*@U90nGu:zg6þШ쏖)ܬ'/t-/dt*r=kJgj{+P\טϹnOttBmמ<Pt[5 P:7 KR-%9)QէD{{gּbzsƼIEϨѻ4蝺 ^zw1wˣẉ:99z7ۜ)Z6FV@BwC'0[;BYv5i^&ZͲ"Y t"Gl2ŊG>}5IO Pl43䁮gmD4Q􋪌A=? mD{0,#^<-?޵і~tI~i'IRjNqw)`>fLOAy#sGR tf2ZeFS/CthUAdsA\3gؤ9.: Cd_3>lܑ4 SHf#"iudP,3+dcWcne!B!B!B!B!B!B!B!B-\os#Z6Gg6~M߼Q\ - 7 ks>հ_ubN 7uh9%bVlBSÜf_)ЎuC0t@tly.h/3O̞Zes[e*�,2'熾˜fby̗yh363<̾ �v<WLs=<8}Gϙ'lf<bWhm"zJaΡhs"?66:ޝecegsuh=0iݲ5few :>-|�f&-~NǬGK_3NOOT:t͖O^G@sL^{)v}^¶Ы5+Z2ЫT}*^ CSym5SUb؊ym2-{UmsP+:^{]^f=z03~&ѫ*aFU"4e>Sfsܗ+͌@[WMzddz-chټb6hj֘%tv[G/nЩ"{]Wwl zA{:wT.uw,v"ѻBzbvG&Ȩٙu9Ye iNV@Կ⚳GGѲَL@>{lmI3ޑ ͲjvE3ͣiQTtXcEo7h1><\ʼlD?FH/~Ft8:v {,H39څr#Y^fm7uh>2_?9Iy<$36wc})Gs>P:nfN}GzJzDC=cGSf?4K٤gg/=ќ-];.:ՠEdNEt 3lY9YÎ+,Yhf֠j)4Kcf*{j9]Q,)9gK4#B!B!B!B!B!B!B!B!ӱ_skO.CT:7EC_S7o(s>#ʬkv척b[ՄDv@r*ɜAmSfYnN%:ndjNNv3MjG9/.vE7Aj@tl9WeWuW\K@жy2Kh hO4t,w94~ m'E_RKUD"h+YLBFP,tt5өSn9W}k2qh-;'}3@9sD[,hWYP_)ϙlh]=oNnWv q[ĆcAMÎMD/h=A/H6>:z5諤SnkazMLhx4芝מhBJko^ l3z化ثUA]}qARo߾uB_H\hټn^x^GwUB"Ejռ6]PIДY^F~'WRѡd=zz%WmXN&ͧ{chbsB+w,PD9%mI{掽dbchYB]I{cuff=Ύakѧ"ԣ%vFNCVs:S^zW,2Zo>UYKD]9,mhO,оf=zgW963牮h0'@f+sSDTtij<FW-f чvӮU�Gqp/04و~/^HXhzxy ψ0G]/Y|ߍZ|(>}t CuEmCn<Z|$*ZT3>kД:-߾W(pM7wj#U;->frzq-t$zq::6YOC辟'M?4=;&:氣'yv&t 3znFt3?=Gs֣ckt+1g3:+ҜܶHs|Icf ;'#DaGe!B!B!B!B!B!B!B!B-CqO׹ffs!իϭ73C2Mz n2h9h&s&<GE,v1th'3dND]frEa9sY*C_ cEU!w)4D_.}IK/%s9#:)<W,7H4s1]}xb.6[�Ih�toC6tvȠd΍TvxJiltَV;J'D<6 m\'+?wVzٌV >=ՉU~t_У잂ֱˠU˶ŅM'Od*2Z>!]e=*{U^%G쵐+Zd"u*#f *uwU<z2e3z](PάCG֚5ʦsGf1e<:3͹"[k&ъZ<۴vAis1GA;&扶&w-۾^nu2{ufdѻ Zr[f@wItqJٌXTݢh`z^晠iв9?ڟ;I{3mSKm#(z裄-:i̴�3zm*}k;m 4fa-<͌bZV�z[B4kЬCoMDsFCru-!6c%adh$4~<-?B;+ f4~e1'FM,nz rhOz�?CnIᱬzE;UA4c"xry~4m:J>fF@>n'rs|r2}E3gdf!ͳMoCGs֚l+=rAO33g b6 CVsn2hFO43 MfȞjfBg7zaf ׮OTy03~bfg7t~"mP�tD3I(h-ON솸{,YbfM76B҈ENfൔ;G׿N-L2_7kE"s.S#{ftХjvti!=Akѳu z/>-c_8S:ti̖cVZl%lfB!B!B!B!B!Bx7S5V@GwާQz5/kbo^}~QjY,κyC)6si6Mf 'S<v\m/ݭ~"Nv"MծNvFfuLtPF+:Z#Wtڑ^^1k}I$uf r: <#]u:ڏ,-Ꙣwu$'l־sfLDWKGؗ/瀶8t{]]=fCW|>==t4w&dt*m1$r]$t%7H\4^:jxhS3ڲ޼"Гa{>k&zrw<V\ţ {EcNzZBzo"ZNV.JZ5y}Z M)2O'͎hEZE^{ejEzPO: }c=ܠV){G*+zO&7:; ݱszG Ы9Єz%T3kЫVSSf-hYM Dե"[;i -KfV;_tFЦ_1@;KB︠dhYA89t}&[fm_C9Z81sݝmJK3wvՂy78kKcӠw裸h޵Գ@{g3{ �{e/ m΀6n$ֺnңR;GoAުsCm<h 4kfo 3֊Y)B"(5dN>C[|3F oQj[#Ճ!h,}ݚ_ThM/,hIȋԄ/;zd'B537:Ĝ Kپ3wАREpY@EF3v|,>Yn+x̨9w͉ic+*E]j؂vZ=f7lh=#oae~ =ܱ5M1;=\VÇ,r ޽{bhʬColl@gM7{M7|S͵Z%kѿv5|D-dROC?D 3пd5jWmuls-OD�y$1 ZTfNM76o)ZgF'3F}6ߤLf{ڈE@@H*4S \E9]Gv|7nlA_:CZti1 A+- tleB!B!B!B!B!B!u.>j(Mh~<jfs]5JYdъX`t]NU4e.ֈ%\o2m+/G3:nvsCNv1试yh'sN @] +;|ΙKU"hh\})EIs&LuhXhE2l΋֚;!*%|əKUtps93гEGcO0m739qا^hW}{rG3 ASa]>K.;ZD̘-q|afܝolgVσB_Tԑҹk M mcXֳûGZsLz4tnNܙ5h;>zO^̈^%G5i&O^G@S7=Dl9!z={^k Z6�Z1W.Hʈ~h:3fBii-{Nh^@S<{4AV3À^BzFUJ&F[ b@4#[k=\IAh=[kV؊(ZVѺ, vFthZ3B hj#;%Zo>U;VM6O%qآwvXAw\KAj^]%(Zu,ޥ-{hY>D v֬E-}4ùOJ6i$oB$8iơ{fle Pltob!Ь}j&P1W*sבY.hqЌ-KQk"̑lzDSXP6&3EgBw3;dG= kD<?᳞AuѵE oN~-C/J=iK{]2;f}`DMNf} C)>aw4A3v|,Zt>i6Ot[fhyÜ ]zgȌmvÞ֙7֬'lSwbbP5вن~8C+ }ޯ]T)bôӣi-i'Gkf?vWU?z9 b7ts(I0:9$�}p`hvc*=ufM}sA͌3{Q BX@ ZMFg2sݓev~tt¶ J3].BƎKKΕ=S=W3V])]ڨHг6k6/ݳ&ti.MйZ$e<0s_4*K_/\5bf-ŌB!B!B!B!B!B. OvnAz5/=&\JuH6lY 8kN.Ki3֛ˠbaZs,ڈΧ6yv2gQ<:ݪ~e_ЩNVI>CT;{;}.2ɳF_JhL3e4tM,G֬K{9q4/CtY{yrh?3>/B@SDGS ]ЂXt'|Wiv_BIĂڊSاzo/Z>;ysHϟ5ol5Ž&NIcnqUuB_Բ;IbџК#-dCZ΁kZ%Fl#YQhzVثvFŅmB hC_Ph'k;Z6{ZE/NϐQ}Oes~~WuAW+#:KQD-u[aw 3ftÞˤ=ЫU& y.wxGW ;z5͕MU~^h66ݩ=ufRZ!kͱYkZVZAfa=蝝mXlF蝡m^n`'DzG@[ѻ;By2w�ZbjsFJžydAl(Zw$CECwptˎ>t}.hάC֚Sywlz[>ꛆ>G7)V:S }Aal@C:4^"92zUYwt4L۷<pőـ&֐+Ts4cԜy ݶEDjhmP[wt4]j] o/3Z3g LuϽ/lhos" ,hI=ͫtq4ޗQڛw6S胃#LE~ R:tYEӹر'ڼ]OI Yڲ}pBfvttYMN֏mvy)5FWx_f^hYO@w6\u!cԨe$VxqvvD3 na'BM](ݭPvz4iVI2΀jъYBGw/ GSll.n&ѪYA? @EkБȱk1!`foG+ Ί֙} ;So*: mu|3L} C HFu=Ab,V?=1+ZVA߿~PY;Yys�7~`6aFdu1M}�zZh u QhW).[$zd:e̟P:yFti.H4:_khfKleY~4B!B!B!B!B!B9t.TZD8(Ѥk:]7h\ m0W6d'(@y.hcv17Nh's>?ڤ"2Z,З]׿~Wrfu@̹ZB_Lly~hcyv,hːEc N2`@ ~oG6=hSuՇhXf/rtqf:;z/<r< ;F}q`&‚^EFJU.9Z6kق^EF+f\..VfΜM%4^ 1YÖ%@*ZAhh<otV O]?{͞6wZ6ݘOpC{Ԡ:W{{*-Vْ9 6*z1;i7-ǀ7i;-ncbfnL0Shٜͳ;sg&ЊY`GCYNUsi4&:3AZA<Кfֽh͌ A4hÊ3Bp߳٥;ڲfc޽Mvy)(֬B@&FG3alh螭7B7Ŝ}>" Al8�}hDoyuf}V[U= =JooG [ z3n7f(zK]yzv}$ޚޖ=6OEEJ-H1GCh־5FFwxQ4Ӡ*$OE94\ a&v�eɰ۞-\}5eІO $nN3+0_pY3AB{ww}оf_;ł* m).ߒho-׸ARܢY`؊a>Q7]ך2l.jP30]h޼wυT̅ ə]:'h~-Z8.yMif=zDA?,4['I-C]=ѬA+f mB?$_1' Z6Г'\30jC'2l6Hs^t$3Ng^&Z]:ttd3֚h;YS ]{gTt<~ZfFߏd#$2m=gl~PVJ 9?G#Ѧ-]uD!Kl ].:ti#zVfGP1MK+ qKF㽣Qi37X84Ό.dD,Y\sf,-]V㘄.qmD83[!B!B!B!B!B蜯4Ƶω+^a Qf362ۄԄZOmzs)&:/܆nlNh;EuAb; *څܣH: W_GSZֈUzo5|d|c4kc36�UVςʈGMJ;k\>#e@RNA^af W [~];8?65?ych4q$}z]e"z <݂^{W0!F :Ԏ̝snʃ>5U3ׅ^ZFfY[ѪڈafӨkŽ&2zOgfZP_DSf=zث&њ]3vB6 (r~S..ޣorwifSO@<'R}R;IhrN\ZU(h9F_O]%N.Vo? ZCSjjs(uifl֣=^=\5Swb֢-ꙢNQ'Ahe9 MDuI1 hl0A:5GBkoZЄzE3@ Uh㚳A͝zb7mSHYW]I.lWf>c4ە>LV#w4˃޵&uf,zׂ>G桘㣏mzo+e~h>USÆ}lG"G7;(m M9ߠ_n5Az[R]D!OFwjV9<r H5OFvpbGy:P\z+h殘{mMh[w눶u#֨IA BbhѬShm*_9#%s!/b/ОD:u 3ޯҡ-ZQCsjUlT>.R'پO7ȁXBl5у8f=<Utn}4 m3onn:2E1l.jf538:){9y\E37~"> If-r8OH=lzfCO3&mC?~ܜ)=ё+3='M=e?ʎޔnSbѿRrC? Y7b'|~f &._]ԮAK@+04NFN<M3)rk$ydO@~~Ff+x3Dߧ΁|вz'<A G?(@^(~0c- # lWTt {d:,Mњ4ihZC94gWȌVM)ti @x(TZ$-dmzY3=]ڦM@n~�2k-ݤrOf#-ܠ_/B!B!B!B!B!Т;}UBGwnD\x+r:yDhy@pyhc%vQ E%%<B"yh,s0_zs-ޛG^yD\eȌNv7WfGt{jR6:%<e=8fA-^bYwpp s<J@EBv;]ЂY8T:<^7MCO`׳FS5sE:^KFj硋!9 TɄ^;E V&l.&̆ 5hnG)KIfb#gDf4eNӘ+& ݲ~O3FSU޽KDˡi9mЩ2-.w BSUgڃ==iZ6@?C l`tofќm y`3&Isf)h<m0[6gsa4Zo6o<CvQ*L `nѻ#ɾnXjl.m=|4#G3G3}@6ьT#OŶGAC!5&[< 8wWZDtۈޒC׿ڮM{ ufF]ѤTE-5>N$lѲyzd3VZ&AhyZw6mlro qЁh=CGڷE-f2bfD{5/̉OLu#Ϝ �g_@;5YQz˄֯gF⓪} eC{%1wjB\ƶZ>0t"5 m3oMG,<ͮGlYbt0яwgAi]=޽GTcMeғugV$#Z>?y"{>|DG4 DAf3zYf̄nٍY<(}c0?{F=lBrlG?=&̛Yy'BL.-p-dz9:4Rٙ^zs2:CPֱ(gC?$ё|,D4G?$Q;ͳR{4mN`fnhU\~a֠<(�ֱ̾s/ͳh\=тYÞ+AAvC?�:D63D $-<TtFsǾgAwg{hʙВtD` GƎKKѥbnJ)'tiA(ti4JDc;Wݿ!Gi&ZnٍyUf&7fnB7=, mB!B!B!B!BKk\H~X 8]W +e͜ЕߋMfUY[.1kCѫ;=srET`{#=OWZ.(6}/DLU\ha7S%kt^yW7OyDFu3UbKn2dFWîa6|/_t#;8=N8d蔳NN4kN5k96]: zoq/sc}6=q./wtx4z$mdb i:}jFkԭy~P>:GytEB2ZAʙyMVt[5F5hMZ5k˦̺Q"hLjlBwr=و^o-ПH3ڋ֩[s&ըWeфmէw${hJ2,gdNVo\@[4z:i#>hwzO54h\'?C5uf5$('uhY m0[vfZCz <h3h㮦#;dGi!i Zf͎]�d3Y=]#ںnOe:hg֫ybA.\]іь&BkaŶWbag>zkL;4SGGCWt Ghfs0%凮~] FM@vhWQФTE -7<NӢ]4z|4AW)hEam̡ qytS#6'E8=z MMaw8ߧI6x ϼy~h9́h=[oG5j{=^2M H#0b?>hPW<&Dh\~12ZR0hAM5%<{*ZTBl(fff*>7?14h_78-h͡-G?C#m'RAh:G#7􁡨jː\&3wj٣6cYTܧm#Z~,WOE{Z=ޣ6-#ќ{a;X?Q=Ժ}=ɬC?Մ~Wk^4cF920gj4mϞIW7)؏y3N8kռ67Et=gN .ЛZx{~R77j Pl֡7_eCuԿaSMg4&A+ʙ:v*4#͛9 MO:wo)_ 臦<M_o2 h-J\s2X<y:&/Z5M7 Zu*¾֩s/-5ys4vG fz I D.nж&t.򈾷$tǾgAKwꙅC7p7H.uO=jsGDB?X Ԯ;zTE#4SLHE]ti @tɣ4Of4Nf&#G7ho$3=, mB!B!B!B! [Uio- ߛrfYP>e;4Mֈahbpyy.WB":'fѯf炙CR*V-|hԣJϥRl|9s4u$e(?d_4hAe}/*$ņns̃v3/UB˗/CfX:sAlr4S_FFJ2GClOY}=Ed\ zs|YzsdxTA"#}vz>> D Oϟ|tqgJh-П hG*CM> �zZ6Adw0gA^+Qaf=Z5.[:M ֬El{G6hlBShb#h7OП:97b}i<[oΜ- www"{Fߖ΅~KG߽Ë=ֈe#3KDkQ6YFn2|xm*-w;9f4l2;`rAgO@S=ճI�v7T##w wͣw6GhF&GhDh}ֽ#l92 Mh˺#/mhxD3C%@o-֠>ьmuom{6?`> Bh֡GVgr27NOnI$tX@6hfܞ ٤yhټb.޶iag43B< jѴ9%&ZcB]4ܟMgsA6y9hMϗCGڏzZpEt~.dTM+rKh/$Z"ڍ-MCДٌ~2;IBgVf5œMhj9zlffd>88''SF# `Z.jzA33,G{#!WxhƬC GRz47OѲ9?g?4qճ&=ˡ)z c=Ts 3$#zs>Vf[Z4s| h΅Z4?)y=G?y{lcK7=O3~ʬ{&OnblFojѲy#+ZfM,U1W{fGorMg~H&-78ȕ,MlG?$MZqUVK!63fv :.WtVż$�}?]v~hsF?!~0 M##5l<L/}>GSTf֙ѪYF'3x/4aJozc.N∶ :KAvtno tvG.ݳ?VYХu1K{荙tY5{@/l16?1Ӡ7$tizUfƙ]i)fƙR!B!B!B!Bh VUoR&f\0C}jl@>QDg&3GY5d7trh#`vFVwb[Ĉqzrp+> qglEK=q8=Y@R}*7ͩUj%:[=\jjUbJA_ɵGY6` 勢վ#﬩9_q/4zycݴ~ n;;Zsۗ/6tΏ&n芝MgD7nK%~=SS_hOL`V /scu%]s@{o@tTu6t<˗nKDqi ]Y$4w׎^gЧz%}vG}z*ϟkpE�:X}*-M=V,TɎ^hSzv gBT4Ǟ zmGYj4c;CԪP7=?0HMUu&ZtvFi3AД9 Zc&،&y:vڄvϟ|1>h͞U7ZgQOCޅh/5v2lC5}t&[=Ѯlo4~kDf:93MB6d4c=d۠h,UZ5{ckl9ݳsf:#shy=vGqZ<wM&&;}=4*@];R Zfgл];;:r摻3Bݥ4S#hR MާUj>: y0M-RhC-?bzBohjևb"zk3SGGьI-'tǮl; Z6W2<d|y"N< )-A)rJӺ^*Z!}�="&у:셸A0h;ۂ֙i;:슦l͋к9&y7v瘼;t ݡhw;y[ z  59ߖ*/HբO i"ۗ/^h쁖Q4z߆֯S)~mXM1gB j?43+YF|p׉Xc>7=g2W�עMDI}!G\h鑃nhgfl_#9R?ȏQ '׹K1zӧ$Ϟ)nӈV N>ȁiRSf ` +&zd)f76{َl> Vf[4D7' M7 =;a[)td ŒU&¬{2766LЛôq"R|ݳUt nћc@jв:Zbz<ם?]ut& 1dI5f-78�H㙙<ܧuVi֤:26>kvF뢠V6ιAdI}?]xfgg0wuDЛC@L&٢y2::Bzh�ݻG\t􆊖"m"%7`tzwQ~Σ 6am%; v-oe ]dBoL\D T{K;'f:3<fhf{D3޼QG7_xme~/@#B!B!B!B¯MJ]ldlЊY](R2g&Juz|l& yIbن#;l t M<0 M?O1ijGV(FkW >^V7Q= r@񙤹ҜA_/@kU_tf Fe/ 2;y4PWEx*/#Uv:_fAe\ eTW\dDGcmEY\sYˬiS($z@ן?ϟm}5^Z6s8Tn<tQe473Sy0UsTɎ^hN s6zq赐sBgֳJ4fDSh M#/.\p<oƬB{tT[&q.΁2rПoߎw~;Ky<;n6A{[=Mf'D̫6Cּ2<ßSG;3Wԣ[lݕͬ f҃EÒu@yۣff.zɌ>Jn'7w }4-kT=[}A3b6HΎy]2=hh&a?ICIhh9(fZU}:KIQ�ڴAڶگ8%>-z[)-ݲDZ*fMSmb0slҜЎ /M{4m.֘h9?څm1/3Da;z*IAiU]m3Otϛlly |nϹK|ҡkss _\ʾ=^p]M1h]q=R.h?37, b7 hV oE3ibڶ|pP: 53Yy4`BU|#]'RSF�HTtݾ)vb-zW`M*[?VңGvYFfj~-3Uqenҡ{v94evCO0;S>i[}*fO1OC'FO2k<zss<Vds!lCozes~ћM&t}яL[*WbE~=et Ww~ؕ)Iw'3#2zYbo\wŽafV!i3BqUZqǖ"ێu1o8=Y_r~483#~`y B?*~`@G5l~ τnNкN`&h]z,86C ]CU;&NOn{Ǽ$Z ;:x ـ*mt&¾w _L|f&؈Y`ҡcК=m@g6sp ht{UD3 ],D1 N!/4Smd/3_Ygхu^ ~a3#B!B!B!BXfKk7G}q~-],3S0ӳ}.hJ.֚ bbyhժj7BgV[VVćœUm%SwjʜmGO~݄6bW}zR{{{!\ M///+򹠾ՠlRh}_6EgESKG/_BB%ݧGަe_uh<Mӡ_BdYБՙQ/#u"˨hm/F@t4vȜe?8[$:ھ"_fEuM3NF+f,H 6>lu0YdtvCx&5L)V;ch>UC2z`hœ 6;9 z-FvnNu*?Z;kŬA_$FSha4OGl ڗMYuf;ڋm@;ACǘZo<h-? -?-~n跳Dw[ ͱӡ{9}T�Ǚ%;upu:μhj2;n =*t'̌}n@#ѻvY<PN ]+Pz4:ޠޕɻ-یvSC#ע:tOdk<A3BYq0iGGq{4zǸl}X"86z+Z&1o=GG-s,v4^>%~JV]2H m ,z{�e[V[h\ okCIꞝ0йдyh.֘晢Y! 8eh;;lGOEQ=9Em9jـv5=yUm!ft~W;_4m߱W6s.ˬ%sp>ZbvE{l=ŋ)fQEyGWxUОfJZB?ףV7gnlFӛdfԔ hzzA> 6jn"QZxE 4S\Tuv"J2+_=8 ݡhfA?R>H~ʣ>C?3GvYAsMUc%tYFws=-/>wψ&?-$wZWFW샃Ot}S6=Hg~}# &w CٳO+߬oyv៥ЛN zB?|H'UcA?|lA?X3Gn VћbԤ;49Cx ̞lٛd2b?g&:YW+\dtզ-LD# zCر.l7~}QqX荥]: }:b^O~2G}}<g?x<C>Lf ţDH{z4V;zÌ): M<Hfst-] z`7heFW"F=0N%dD;g.e&ĮvfcDV# YE߻g@2<eun\dY9s,Yno;Ӥ397㬙(hLf/ĤѥB®Ooh6{4c41BzsCfx [!B!B!B!Be-qK4/-5߹r ~[ 7M/-G~joJ-J),{{YwtoyhRlx)lF93֚s=&<[ќ殶{4毖ͫ޳W=J1=+҈^@gj[D ˙_VY؝32_vɧH}W[<;5rVZt#[>&]2ЗC/d tlt΅~@lxsitDl: ;2x6+Ŭr"QgM̧ѪyEOzyhg\ YT4M<΄gJ9 jfzHFp0U>!h|J$}qeN>h9ZVh9�M֘}:ч~h֛6>(l:8TU?}ZSmo~zn跞ho%֛?և3Qv=UZ=]Dn <)}"'zstZ%m43@=M 4Z:[vޭrgޡfzWB׿D]zGE]2rheM灦VsF4Ӣ _)ML:�]4hZs%$Zz ڝݷ-lѴ9Ze֘"&6@:ZsqtȠӡ!;46=SsT?YR:h E9fVюfgUM}^/FdVf'~ޙ}/4X"\+5bhSSݲ+ -_迴hOsVZnz/?{CƬG[ӘIqٶ4,u=Y0k"'Z+LF@s_Ӣ$~g辑].~}fl_~$f,;gtYA?5A$5P ӢeS{lBAS칢eA;Gvb_=Jf ɀ~怞`fYbgR'Bן9U:h4+$p IevLfC< -7>R7Џt{6,m~LylXAb =4Mq Zgfs\Twf٭;}43R,Us_h05w:C"?]i2J8f,ha\?FƆK@3CӠy6cpYjƱ(}O@g߿ϣCGvY}_B@uAF?eX zc&{3Fl7EvzDy7БVt֡7dȎ-Vҙ6uvC2LB'1[MA13< A3c߿c;z@fwt!sS(9>:ݳˉc3t>s<tFAgc1ˉG4D5sK;: #ѥs.4[t#6o3B!B!B!B!f8%O֩o::i\/ 4Х<yDߥʹi']W)*w]@Gf-f3Zy66dtY$ZG6)v3FKPf :ZspEtKͳUt~uyc:k=0XU;؀0tZ?k#zr<<Z7&z򥀦g=3KMMSevݩףs_z~Ҡӫ_Т S)%[9=!ED+tm@2'EW%1DGKZsLCGQ̙Dwl :ά#v_ }u%;ڂB ѧu&gSqMן..Q}E}^{W2x:nu&@O}qQ}ESEBl#z6/<Al|JUqm-F/﵌�!-z퀾(&w:s4f25gUkș~jݜ5载EuPvUǸy dg: =G:bhW㧪)/�wGW^ w񎒢5\ţY=HPu Bh֢+gomfAhs{T8:ԜYDG=w"v h'wjnjnAݪzW+蝝͘-wsv84{7w8s4nz2 WChڜnvtn5 {!&fmX,bWCnޮʄ @mQ%4|lV}Q6viVhW$1zhh/iҴ9b9<=<>ݫZ֚֙'Ԣ#!M'Cvt$5I:d[6GtڌO JfhI׹{&PYF7\bHg+~~P@)i>_>h-ItÎ~V#ZeE<iѾM9ĶB7?{A\G5gG#IqfQ?%.ni07hni_U_ ЏG>\~aBBOJGb#ҢZM~gV?ȄEc9ѬAeS̚S׺YeGS`4Ӣ{=ì|mh6|M4hB T{_uB?yC?J c3Z?T:(lz[nW9f]Gd=ŬQ^]eD3-ZVBo`weO*i"9fJncY͈]iћ<P4z@ D~74S͌$j9>Ԩ'RZKKqZ|J?et{*M9t3knY?OѤG![Л<Z=n]K]2h`w޼0Fvټ}<%ЍyFh3Cͺ/ =.ay1;3o;Gz4cZ3sh~Aa{|@[4376eB%--C'j -gE~lC+oyKF?H&֠sR4&nyh<ˠDݛNcfYTkoD}F=LEݩԚ=rHf]\Gk _Jn`/&tR { :٠5Zvr cfMjS3OtQ34T33 4S_Mn~! A]ټ!B!B!B!*_~oOCz}VZe>Ԟ=_B:6[%W}-_.RA/";/\6ѿ;4֛݀)@w :dj.696)&6Ѫyo7Cׇef_*;08vG4tlBfbͿi =̿ѡsb}y g2s=˄VesB;.޳ -ϒ4KO c>-+W4yӤ3{8;> 0њGdiYuw鳳Ӊ+Ҡe4iW(gRҘ'O'?gG ?]\\ [DEl̞,/hݳ.ݦCV9-OI^sRhܰ^ MGIj>:bkσ֚֙ه DMÉ^COaׅn载t-؟?<}QGПGGݣ@k? C Gzxh 7%AWo]_̑ ۡ5蘓Q2e蚹ř5裣hjKhќьђy6hơYˢ5*- Z`΋jԊZvU.Mн9%go ;[&ޞ9ZoΏ7ʿ$tÍrh{KyMaGmYSk.JVis4v\[̹̳AUHVYA,3OC'==Lv1OA)CٴJ3 ZgNSA g4o~1hGSyfnfF afFO~A=K7W2B٤YAW Z5%s~E{;6a"۾ Ln53YvXQ3hH.Q<$i=lFIS A3AK7ChgZ6U,Ӆ%7hDQǏ]F3eSotDG4ӚI~ MmGg*3+h͙]&mflW='U3gVIʙẹ%D.z:HB׿zEg~"es~ =ǏHha<L~'4A\X@O5јݳ7L(dV5zSA?M懱UxHd?5[FxS\ݢ۳M}dffΏf;9"l̀˄7+)tߊѠEψd֢wݻdcf~6BA7f;%~ z#Ze'"g}sAߛ-ZK1+4uSZf ဎl!:y Zo~LEm0sfFuhA$}_BTfv>ٶ=]ܢUs]b]Ҝ ԬeOC6/M} f%E6+{(.kUH/ZtA�gBcfyD>L֢ѥ]:f6 hF!B!B!B!;D]՞8^GREg~}?_h=#4'~oy_Jh٠_*hD`~.ɖ޿ul e56)6oC I+Nn#&ɹɾ5'Ƙ]|ޡٍזW5ǎC# !8и@fME5DM96L٪ѣ>v4.MV5bN%T`[3]]=ahc)(:7ѢS1.Х?M͙GY6 c1"49gM qa)a*hEARs=6m̡44B >DwOd~oesFKC=џз;u`>kmџз]Q3'me(=(??P4c.ECs=¾Пƍ. FQ-w}}wѠ;)J}mnQjhҍ>=6f_j -zhӬooKB-qf]?j}<ZG=]Yn@ZBwo97`h"'[F)2A[]AJݝB̖^[A4AW#ݧGDEӣQр`h&0G3+u_chrDg~]L۽=!rF\yvT.qgc+sضh6.tɮNK5pj#n15aSl|'ѺUAhA:4bVf"t_aVhDm#A[UtB\=jC/ oOwhhYh?G;:zIiK6k\\�zC~dJ^ )[_ eRWg'mHr[BW6AU;;Wj @ uPtž4wj,Y 98kT3l $W"I;moFw-o;l Bب\Iп9Nv]Wmzvwgg\jѐ7ϟ?/촍F3 m>5DCަ�ˑUgVЋiQЊ3+S�͛]͘~eYE;v \=Э-K@dcY0Ǜ蝈g_[m__W]ޑ~JVEgR{v~6jnEYA+U[s`=-qt72S@3`h,\Iv~.K&d~Y(hܜ ݪktuB#A_}tڟ](s@6~ڣce!C @+-uTVA{�U?at ҠA.}lO4V@4[C-ljՒYn ZQA-ZrK z hF_E)Ёͼ}D7{tGVa8k ϙG0!6:^Ѱ*S4<iœݳu{:=B5hpP7ps֣%c#(fC'0pG*qHtBBEV}DK>a?\vf` 1=41 MVeЌ\.r\.r\.r\.<jOO*D(}4*;-9z8lGA+f}CkzH~=h$hho# al wWيYAacn*Z5Vq]<0lȌ!hЌ]}Z6 4lNu2g#fa4nNF )Ѧphcsf$:2h'Df}xm)&;tX6eqD {WshYAɡUQߓDJ_ ݳJͣIGE2fC`"Э-џLѶ{Z1{?hݠm4dCR25?h4hBfs@hl ghw6d6C1+4KhBhI2 ?IfC4AF?] L;yw,8i r< ?90 nV2g˟AоfAqOd'Ew?50fc迪z4(<Aՠ�РãkvhgܡRЎцj<ZYK7h^M[M8&@Cfmd6B#%T\ 0KUMZe,-H4G(ZY5 b}5c_hơYc{FPM0ZaUiIzz/2ZfޣN Ǚ7(epl 65a -_#kMI{4lWE1GEkVͳ{84fnah֙MT<B43}Uuׄ}}\(ۣ0BSC/Qzyˮh52"2_o98{gT_;Jh{;D[,ENJـyh؜miN\ 5(١ . f}vHvY9z18�a@o#h8`. ( z;�zav2%AtټQ!,-jWƶR~^k�!stHstNas tˆ_1zlfa[Fl\{6uh,G?ՠFhݳ6a9و9-7fKDl$QX.Qγ4нYDWfmfO7̡�o_"f|:b~^_  -8%0f]ß>%2?# aOtw48hTAOZ"iöBO4<{3:6Z 5A쯚DA/%4יM1"!-V4h<.2aW*lff^?:1<� fh-Qt`3S(:9!nF"G߿9ÇcEC懱Fl=470@'7Mқh`hw+=^Whf -1űБ wJЬmg@K=Bzhsfi<6E3uflf53=9r\.r\.r\.r){]~pEufGZѻ}!D,AR`(0>h<$ z(lFG zL5#j0Qm`6@Uf;Nalѩ԰T+fF ٬>]UUS1h p:3$Gxӛlx1ݳmfC9%3h|GD Ӛt.A2C>$C=VmmO-:4D#OK}q&h@MUhU}AsL?b?CPl ٤?unO$sآ?NDkjfѺAs?4hd+mFfS> 0oo9[Thw6dЊs)=jvEf#d*Z`FOy\hI2 (2.?&C%=*]hN޵FF`fCI J֠+e;u=(Z>]0wz4c!O f*B#nwu32qև46�k7ߔuhnGmx߃5t5/F] ͩ6ڝ`Ң[1o*p@V22ãkBhY .薍9s4ƮE<H4G(ZY4$5&轴u01Ƭ`ZYfhY{{}В ]ĚWNnٕf5 芣C~ #E-aMy4b@ j{x�ј9*Z�h^B֢cl`Wwze1V7[gK,<tvG%*:(Fe`z }I^.c<e45.e<6]4f+Wh^n5hq֡-Ҙlj٪yh؜miN\ 3@j q$4gg.Eaị]Ԇhѐ@Y Nf�;mBoch:gF>1\k]6obϟ?GhW֣;7^PhU�l{[e}嗧m@LQD~}Cϭ  f"a#w ݯ3 4o֣w"96S [0W螭y DO5hiʞhy8Ou蹌/Yg¡+6n|IϧUhFwvUD?o׌IР5wS ,ɲYT#f.[u Gϫka3㜒R/A7H\isRV46]`EMth@1'GOM&=<Z`Oe4xuFgt8ќBq ֜ݲҮ֊GcEWz<h6:4~P]ȡ_+t3~"Ќ=,jV Bꇄ:c~hR+ de&94g.*gÚ̍~p1t`s<t|ZdqE76hÌ96.K=gJ}Q{z f@2ll(Fվf퉎oBfnp@f ܰy-*{"w{@K ={{ BkA׏,֡SC:fc6~ݙgfwŜr\.r\.r\.rwY~tEu ͨz'!+s܇rs5zh;̣UphyʂcF]GBpp3АYl wwp bc1!sY  ι1hȜ  4'Gc<N4jң߿OF6F#fw<;̬CXhC] )4>th Kvy:7C`œ 3<&#,<,33FG4=)2EΕ 30ZcDZOEinٿKCџzs}FZe!؟H4ЪIHFCw;4`fǀD}Ѫ};0KhE'`hw6d̮h쀦aѰSe+1 Nl4l }} Io{:QҜyhݜaCl|6gh àoa=7Z|)!_4Т9<&fWh[ͯ-iЪ+x7߄@0{k7Zh샖 Cdf 4ҠU)"EW2n*.Ѡxd$4<f3s84Ʈ?<y幚_迌{ѯę1=z*%5fD%Gjӣ�^װh!ޠhh{Bã$(f FW$C5VVј-u5GE<(Z-Ң:Ƥ1kIG$^.ã ̣Cw#}5v47ڄ}vXh^F/:j^6b/`>D//]LM#E5ڇ͙IՕ+z0FI{aXTc'g摣as:ݲCE4ζ\1A/"āЋ;ގ ~i 0ZŬ!s<p<r"2_>/zhm#Ern yIhݚE4l 3 hm[w"6`ϭВy!sc44h&Ze#f8S znV͡%79و9 7kЪYZ0+-4A�γh<EѐYE4[tZ tkѬCO;nef�7?cui.EHךKbۢktUЬA?ϒ{6.;m핊R).2SJ9fWh!єy2œ}'2BS'ݲhh4藠 m&W~Tqr`4~^l *:^ Zf+?|P@Ke/!dn؊Bl[CpfА9$1\{4썾_ oNf&0C߿ãa{"BfhrOk :Yt$MҙU45h;t4Bv4ٱ<Z6;b&*4 ͼU~a~ ==Ke3v ufGhjeyX6ܢ͹\.r\.r\.r\.wg۟AЌ}5qguwxNy?r{w&6@a3Ɍl}p0<Z2ܛ+f]8hygJ-Oazdh`f3 8n~!e@l%}T's ιFh w?VfU !ul3n͆ҝQوY8]k>z!;Xz@tjC] mj֠A3>ԛG>/D`f�]x<47f]>0ClHhH3ã- Ovc\iUhP ֘VEra#Gj t 6|=.̈9shU^2:lVOB2shE-7fhݤafG7?sGrb$BEahjZU+hDA;!s�fѠO㣝Ԉ%C1tiK1(�%4|֡C0; ffKh47].k }$%'34y7B}-^Cߦ 6[̙݅5_6s:jvGlo w5`BK|ӤEcf MZo`vCa:[1iShޢDCa-[EDhL75 ш66 Я˰Q33^bte~-μՌi{u)ѯ@4_ ^Z5<;m_w{BC@3C{<h@u_q;ir#y+@j{thA툆zs(7Zamt=KN=cM^El/Wmw}  gg1Q˦^hM#ʹ zgg5{K^f+w>Sݘwv4hitnjn4XM%zaXTR/AH24[}֨mV0a,au"-z{;s[Ztq{1hHmm0\ z{C6/- sAj- BL.Al'4ci˞Cf_3.y>*ZU{u[VC賳eiV*ZQ'Cf}@\;4b6 -wXh46QE4zGFhHhp̱˯U6ba�Ihw3O5%Z5BOpBS át--tϖ  *ygYUHS4<h͌ <T[tkЬCOktmn?ib%x]MfňzwwBl_K'd.s@7+\DginSn/jqu@蚭^ 2]3::uT,.h=Ѻݜ>h=8ZEotWuߌ%rD4~P+KFA B评cup1vGe~Cy@憭K=m~0Eo$gۡ!ÇAh^}7{`ЈCGѡ$cЭ7G{6nC̓CG0{R>8fMQ4d֢[FˬAhEͬ=Syl6";fJh4F'7W12CpCbp6*i=u=,Jg9r\.r\.r\.j@5ՙ?# 2|0jV9A?}0*t)~WޚiНD91ѩ3GlN9sB}1AϺx4ӞnV@s D#oh@twq4_zv7beг!V^A20'`GfStIl FC[$b3QC,K5OM:h̘b؄9Ai 30N峨=ѐ9$0;Ma{{4i\7C#wtht=!5L ά1 :<&#et [Z5? "ZA�7f3LE4lCь@ь!jlęNJV} 0;2DO~薍:Z y( g�MqؽYmqxoؒ] %D}cO.>E�-] =U4 b_*FfSrM-~hъ-(h.5y6b6ehKj@fw| G|VHD#b/40i [ͭ-_̮U=[ ~qhܜ[xC1h 9�skz/1uWQz4c|^SJkZA3}ysJk{-Z^EUF={l h`=]7_gW &VG MVhe'sC[.c*:& eS{Uy�}ltvG/%Y`4l25%WcFGӓ"4hlVقyY2.;U^DE/Q+h-z'Z1])r2/8ha=sh{6g蒍 �m?рD=4Z6GClm>?Wc>wD[8mkVh؜ֳf7PhdX 1Yaoh݋7AoJc@/3v0ZdͫgVk-fۆy>в9.MD쳳ySG> 361@CG;u:|hlt sc4lf!z{[#f-3 cf= in y4N~j&M(gύѰYQHS4l D?([gsSnWϺo8�hoUy:2[.aݠ+Eрc\[wwyv{u #IѬAO;֔в9e7]~3Kl^>m*ZCx2%�iFg*[E!w�^m1єyhB,ʕ(he{xKke/l!0ZgAj _mm&cbG?najC?E}CXfW:A+j}_Ah0@pS4` m 4z? }OO#A=)ݗάe]@+fc4#ɬm҉yjvEG7wtl.5Y!sNjьiӋу9z8)zd&=>oIF׍Utf6ns.r\.r\.r\. 1hHF:g >(D4+EafW ]߽{s>3C ݒ5=|6hT=.44:1|抖 3WbNƞT42 D0f$a 4VB7\� ҳg>Ъ9=Z<QFh(MI'֬a4E[1cg>42*Zt63ŬCБԈ)Mml~?@grs`CrР:@3cGYfw4h6 (== 3~kAw#wtCЬ5Ѡ33#fi#:v1fџE˳VAsxŻI '>kvWCfo'�<?|ۥ1ТӵR}؟duovFEjݣf?u,4`ĝK?J4dԛMрڍ yhݜ} ̀YcBW@� :ZahpwDD/I4BٛE-m+|� } kOKha77~.9<"Ve5Ha_ˁhV̦h 5E+3 4o f0-]70 D!mѪ[N-i#)o⣁IS_Ҡ5H\ơU֌ z5jNVfk_=GGkGJկu|L1Խ&#sk4Nͳ_K76pq-ohy5ͩSL{J_莭GUYDl$ZUE<oCM AWe2�DT_CGd+^.c㠗KQ]]=˥>G//rb$Qcs}^BgwfS^huމ^.ЎV -%/f>ttJжs0vSshgm͡ }) !C#U?E^ghE+fФCsj E4}3q# =--U6>�1h[_(62iI %oڬq؋_XLuj[SV4دe&ؼ|iU+_H1-,5FݘvRtg}v6_rj<`ѧ7 hk5nϟ?KNm2gN=ѧ@�tvB;y5cZE4 ^]~ -9 hs /x Еu^ȣ9�h`@OQ5v gς%3SЧ4YS9lis<gԩUEg:FKB.O$tUgJhmWf^smb~˯JhB2^](s$S4~Q-c{&ۂYb~ zWB3̣Us<tpMAҌR=Јz@VѰzHr)fGEWM9:"㡕+1˗hhJNj~i6j :AFhX UTA?x�%KI0}00fYMAÈ@ >aѪD33?d6BeOC՜YBh0Qk80W6CÃb l}~S!Cw%3C{RhP-eR #%}Z,­вYThlYBot&bh1O/GbVĦ葙4yj1NAWUۧ;\.r\.r\.r\.7\\C[Lۿc}M ѳ*PY4lf>zE$!`4>�Cgws߽ӱqtZ8o+hܰ]ѩ3jN)h ߥSgVhƎ8@Q]ٰFh՜ ty<G):):aw#&hhFZQC C{Zձ@j>40B;ܱ 3k~5S 7#9yk4l> :>㻣 =l"q1u٩Ѯf {d }п77CMI4%wxh3DhCccB}vt�t{R ˾v@à3mEZv3nn²Uug+0_CCfhĬA)G`c1Qs�4ATvA%t) OЦ' :4Z6ۢMvth$ k}60~!h�b+R/j6Eh@/&86%s{OtfG@oBp@;0gWDt84<o%sztuq==yמЯ%>:j45fFfcca.*fЌCCae-ZR4I-&qswD XeBPsVl|&fvum CuuWl.W }%ѩ<&zY }ЦK4w_j0=.A/);z)T11Ъ%`п">?_DEf<2Z1 賳_U)ѭ} ݳ!q{kvs�MѰ͛Ckhf C3ٶepydzGAH6smEw 4d<f摣Vf'4?7@C ؙ!fOḥ z 0shhD3 hk3fZbY719_h-f^U^sZ%ьFo)t/*phܣu0h忄/<ZN e ,y4bK4VZG3 3 ZehլVhF>&a(:dOh`(:iΞh֌E3O`dݻyay e3̡OdtYofLDl,-ѵGcy.z{v{Ɯ8hݳktʣbTbͻ�4Bp1Wh9B \]]4D?} zw_qs\ʞ6C�Z: ڛd/0A,Оf ] _١}6)~9jTh 7vho3SRh3~ ,t@330"e?PC?,V~ :^1=-{}ЌU|%+Ҝ ԌuWL>f}OBM>nkhtm :t)}mChLefD+f\llҘb kӛ6S{C1Kp;pbwfm[y]*fSK49r\.r\.r\.nkhiw =E75 B -DY>Pg3S=trLaigMgw͓˼Љ3$虂ه&h=CѠ@;7;PeN¤Q� XV*<;%5Ysv -A4Cgڠ3̡E8q3=S͇zsYP [6#f k8iN2jBN-><ь)aXFQVՃ5hCA~ &h]1k|{]Ds7gy4i4ЬE:3ьC8gGt ]A׎sF:t�usݙV&GZ96�f?&Z=Wv4G#vXs8Ѱ9 Z5kПzIMзh�]+"O7@W@6 5[?f 8e{~D>N{o 4hQ Ze3E~V6hq:f ~O o|KC-i70B˗ݲáQux:WUK[k_n{M5ThS^;^Srݩ%vBtKsqv23'A~¿2ͫQ6kEZЯA4{{#EKyá6\uI3Ja $ e{aEW8hXhjSWcE_hPt<=z�"uHt\Qc*/?ݓ=\J3Ous{yqRVykt}@s�VEh4ōE/.ETlgnh,K5UAfw+̡P[6w-69Vhu;@ADfAlah} 4cElجEۙ� civ7sh`Զhͫ,hCV"M-Zl п)CьZGo1Ug;¡$4_%4]E;Ph`ԭzΙeμZd3u_6薭5hYݚ4Ѳd<L֢/<g!]<hYݙ an՟@l]}5Z5깂F"nj95dѡz\TЧgfVYs-jʸ4hռdЌcg}!ЏES-EɣOy~TNU3fdϞG?%ѵG3m`~/+^.J㠟f%f$ FO<@eXZ3.е[|ژwz..6sn貔9&S=л˜Yw[2 Mz&�S HS!7/3@|Ib- [>͹ W1:YmA*vB'jl X�Èhe ѲY~+ʜQ=-oiN}n!猡U5l}%߿P)=.A^_AÇ $nl>nVĊK4fެEoɓ=% 4?PGAKpONV4=0h,K4cz:Mg13t"/рQ'5361G==XPۡ5jc:m�fRK4~9r\.r\.r\.nkhiw =ڗZE7sY],z[43> z&$t G/& :! :A3.8lXшΜ ֜.B!zs}*|P1@q]J۷@Z~GCl} 2C}4�zG@䀘ӰgAChǣ@sV44hݚCC;FwfޭC{uheWFCo)M2Ϝ F:*삾 8j'3_=[T̡7o펀2;Kv˱Ʈh01\Bþv4.Os2;h=�i-rG{ѷ#Ax;6@F3veC~ C14vFgA>hGC=O zg゠Q�h;2A;ڒ<豣{0hw Ю D m60 -_~fFch׻S&[}dlC;pz14C_7 \Іl#ERZ7HF3H4fuCf#4lGph,Ut8ЬAKaYBphn4mb#[yEe쫪 }60;/3WWC/ WeƬc/G۳/= ^Oe-\{bBD-26]>tBfB=Z>9Z5ys<r ;/ءQѲ9<2Z1+h4ͶEfsKc@][mnfYEbnqЌa;B;s6aCw 池}ͯG!z@3M94̶3GM 6ЖfG4FZeۚ!pBV-l#hvg co[^ߔ|AЋh~[)^آy -yJDc(\Brh-6H\BVl,ev @fu*,y4f FlŬhyG342iCz^an*ZdϹ ezSI|%zO9vKs�fJDdS\:lѴS9ʞ?W֘Hu0{Eh e3"Ih3_;̆eOҢmb2I62GE3 ݚ7f3jnuǤ|:<Ɯ 8Awkq5zFchVhiF׍i&%FO;.r<3јM@Ϙ h΢;Bq6j~Y,4m'Zc6@h@h/3Ʈ~f[DDѰ9-z _aDSl4*yʉ v~`~AxL/^�KH@kѐ9f?�#SymC yl֣f\9b֢vPf }C?aF+JyZCf}6{\5" ]k4`. +5z@7+{R-e_T߇kkCR}ܬqt|˻c&ZUv|lGG3wplVq%H}4hcObG?Bҙ+6р(6z�ĶE#Cfns8вG 3MRWEh5ᡥ\M`.l5r\.r\.r\.h7ŰٌG_]/5nf>h(6۲q 虔9v`tr"&ziC汣A3.(kvD'R#f7?9Ch (<B ^!%ՌQ2WhU „h\BAׇRZQ :w4}Q]=CX* A3&*͡Þ)sN2kǣs s1A ЌoV!)YAG`wg7Q:4`v4.gdWC:Fa3f1Ѥns蘳&#8nyjQ̙@swN] b5;8t &n-4hL 11gFcE_hr!ZU{Ї9.}{{dgZIuBt֡o>l\G̕FA.m~G;a5wf5:]чu7Ѡ?֫cfT( FϟGh*hK A �h!Ojl>A~f|#3o6D{:"~h{FG'ޡGU&(sJ4e 0= sX&RWzG FB24+ׯquբYVG*,Qrrf W{a]$U3{rЈYbC'7"WߺqU"0XG_]j/4Eq%hDVM( "̸B#//>\|'B0#+ӇA_^WJJO�m;^Ej 1sz\;uF�|e|z-V9(h%.hH襐 3KPhкYkЋ%`vGhhпb?_hA42f[ P%ܲ\ vmn&hs3ܚ=ЭbhFUt3huL/!Hh@-e4Eu@3-C942CC`_t+f ࠇF;"R'Acl,%T 3DmfѲz[0h r~m<M*0c ЌʵaA :EZx7:e{aq<7'R*ͩwQh2Cf-]̂#wu|.O*6[B3+4#ЊYڑ̫4f%[1+hV=Qft5ktǽ'Ŕ˔1%f כMf˴蹊>к!^+/<3E2kL6h~R3EX@󻚥C?~EK=ףy6Of-ܠ%5ny" -~h?5~Lf�h.JЏI334әc[vwY/.zʡyxw9 uzttw9fCϨ\ww9\K~8iMK6hB͢Y£ umN& b?hxG8Y44m6@hyhzizǁhT=D|R7)�{Lo:FjzZt6#K/TG)~ u�t~�ECpq¬G",mY3TWf̌5"RWVѓۂAA6D̀&5课D‚!G߫%+uF]|-_޿BիѕzKFw cL�t@ܴ ;B7Ȏj2:СA3&#:-9hA}_n�t=!Zs7rtfyhЀ(VPO\{ٞ9:lw]YÖͬfХʋvCZ4p51l\.r\.r\.r\.-滀 74 #TF)sH-y|hի 0p ePhD sNEf ])t:8e+4mg̩ѸBFf < 35mҡf=%F4ll3h$h̡Kiq-NOr42 C<`ROIo}flGivjͩFfM@}S Mw4ƶ99mu~t<3_.^kFO##D_h"K3v:,իT3cfhs73Sh`ųamvړ팾e#Al=Öw)gѮl|mtՠgEk-??><?:RFLBA[ 4ĆF#;FVcBcWKft�yh,]ѾMX/ݎ?DC ݳ)%ڂLLh{3>̱f N޸ѐC\-Glf7h ]wxXkw½.Csdz )qi-y/6df9&1k/4C%WE~%UQz}9:(n8|�-/(t "}�%Z-=Z6A۳)b� ^~eQ ^FB>e|,n8?t<zV-;;z)Ԟ|vChD[.ٱАeqcпbnֱmѪXрyٟ2^1ڄm֛q4# bcb\K6h،W-fF}Э90h ;3mtṇMboo3ͯ큱SuHs|Ȗ 0 h=,t|Ɔ@$h` !q6E榯YE K44h=7Ot[7%F0Eo@3+{)f Y5YmmFâL0ѕ ̡Ѕt3 hNݲ̋5NOy4an"ݚq@hs.M)kf-zw33H2hO9hzf� 0E-Т9bs}zڳIsn$Z4huаD{{\Ř|ْYAhLa;:`Wf-jgя4F3$ LE<~G?QJ23ClP h� Qo1'EkhА9<hj u$3Ә[6twZWcfh ]QqֳQsD4ct$3ƞӣu8fڅMlj֘94NF5F1w=E{x@ۘ}[k/gDZ_ 5mЫBf\dbVS�Mc[dB/u`v84dѲY^CAE2W!fv(sxf.ƶL++kH*z^Ѡ@l]Š;LJp'ccCfnf3nE7MAch쏎dVh^! [^J-Ndض낆,Yh@<T$0a f!\�{LAT*c=: \͹\.r\.r\.rM13 7o/:h(7:Z! F} q3J %3!l AbЉن}< .$:0MNJFh }àۇq(:6DTA;K֒ 4KY/MF<ܜ9a>쪥 |_fCl֣ՎHt`ᠭG ub3SI4l^7776=]b6G11d mk%hr쵶k y2<>54 hS[03fv<̌1 Z<6ړ탦 -[-@Є:"Z17lS4柎ِ.};4_wiE}{KGW R6& -bkC#׎ A]|,]>YNhYP1ja>u0e?dFѠ%5>E[c5#ch쉶7. y `fҬj.{{#E34b~ղyth.efS#u;pCAh ]wAk ǂ.-;UԾhl.},|V01FM8*4E.+./U44žh"̗v4E"#(<B7ch9$Ҡ%奖MMzihїr:ZbiЄz )b2Kjдyh2B_u hZ}C7aA/#wq4`n܉ЕfY@Sj:0 ]epCvG?aP/xCUrnt@3 ;�ͨ)ьD/,ЦBMY? ]A.u^hNGfF BjT4u9 h /଻u9ǚ4u9hؠѬRSt;W-a7z#4 8gSs͒I hB eboC{ZDjxGMmkfҔ[![84#Ј7%K6D/hؖhkz)hb K9mZz)ozSd-{l>иAl{4#"k>է<Z2B=zTF,Ok5S2z}ܩ55VͺgAzv"G�ܣOO{BA`hWoۣG�~H6^Т{v| TEChuUSܢ/fe֢YE*h\~\j֣h~̇a>A{4?ϵhu84j͐A>Ig~ͳ MЌ7 'JЂ$+j̜ͩ13fCK �hsX4 *Ɯ,ACh͡Ʌp4h~5 If1AlSK.L'Qr4tFelwd?>vzCSjܣ]رw=;)oc@O zDAclYDxBEZUZU 3|f}@`v�s^U ѠyzM(H&WVPZ 3[5dP=*[2F EW* . KVѓҠu-Y'-]}`45mF73̣":K%ۡvt3֡W(t2C4Dfm5ZrkАy%hFh )`̰  uR*T3@ɔp=: \Yk̹\.r\.r\.rˡՏ8q6:h'aЊDH<F֌6 ephP sN63И%>`)yhB<Zy hZ ˠB3̑јy :.5w滂У.~*Uth><ԡkӰa3>TӢ3>lЇ]W=Ahahܡs|YFMS9s{w"۠E:�1~h3gІ1{ R0htx�աhq;Nfszsr*5:>?1#h5V;CSl[?ghrL1a;Z17l=" ِ}[ & 4ľm2Achѣ+}汣+q4Ζ67f ,m,BZihphMO7-$Um }bdGC ͳoo1DSh 1aCfs4s2A3{sۋ쉆n#l;hS4b&;7Jޞy�4x�ј94u毁u{U�7n}ck<C�@XFt[} .hf渷<..G//qP }) ES.D?(D_}!ІlA&34ϾTJ^jвyhṞ@滀V |\hlV6ۡff]5[1shl󞈑?|華twD҇CsП{^GLq")zznB},}p6A繟U;lW! Z2Wh izѠwa6?z4狮z �tkNި*]4sh]ްBwf;Yaotŕ96f1Shi%Ŝt˦:'0  }7 ڜ} nhl27l@L)6`V*5zCJ03He֙Ɓ^Dh] fϮjh3?}oyt])h7f}Zԣ%3پGZto Q.fkv,^/rh {s> CEdЧ]YwlwiЧ -]5sB?֠h~,%0{E?\C>@<)e6EwOGьD? iF @C7WfDסfFV�&hx=9!YE<G+hМYI239LxG̱Џ3&}4oijʞgvAOzգ)лwuWл赑w@sBEBcU[^J^ES 6*Y^S gVѫ(zJupf*/^EZscfGOQ  ™9b^L 'ѪGf Mâ -34izBhƄRf z20b6c rD7#艄E7GG0#p4̎ef *;9<:h2o -Әâ9+h�\'1zs9mEb(|Cь@l#*zX)WcfYEꔪ̌1\ţ!5fk49r\.r\.r\.90>fbsW ƣ0@lX<F 6 tz5$ѲGf#Ub YFdҍNjFN1MOY5m{/tl5f#5#w9uf4dN.У0:9Z94lWVw4zFvQjܣm՘Gj7A.&/8h�!>ޞ.Ǜ@ Іf)my -%t0l<8 <kHhmb6F܄G_h[);Cf]9ޖhJ-|NxDl ړ} ѽ4D_BsF£;Z17j=[J??0C}}[f2iT\ F??Eu84tթ© !аz(464}D6qըca4a蓓Nm*ldžbhK5`F-w�2p=]yDc}Q>֡9a14!F6ll>�Ѡ@ /:s 3G7ߑ|B )&hnͣtx8=HC_wLsa2#GD7aha; ZF=H=$PC`Eyk ]n]E`hY0UB%:&_K->zfF #ׁO՗D_\KO!UFfA}9zCsj rFNjfhaxF{ 0G^ ty,lB>|'Qܞ^[v\͹9t]ན ݝ|֢aHнMiЂ-q/h � M}zt? !t:�QCgj͠MMMѠz{Whx PkEt @"7`:f̡Mv1ZQohL5N#y467.K$ܸhDmcfJY@^Vf9`s\F3 C7602֨VvB-x"RVъ-' -m8�@l ̿'zC0G鎖%] w@t>Ӓ7C͌Ӈ d>@WYu3>=ѢCwl{~D+xkا5[2 ~TG93eRBf ݲ8z,Q? Q2S;Zd;#1W}ڥ`K`Чy]- Zfe1ۡI>k<(=6EAT{enq-<) EL59d)g&ODcȬ C%G7k`д1�Y@яA4Џf%lw 0 ~|'я;QqgV zhR yZV}[e3w=${t]=:ʖF٣Ckk1])\uk{u׸RW& W4f-zM)&z4hy-YbJ鋞LGnaZ6詄~{5 Eيyu/Vj^tj34if�E1u'2[Ah́ѨAo+ucBOzv2gu`=e0b6c艈F7#I8tx2d.h Ccdqʾ梉";Nff튮ME fL&}X1p]>hF6WA= @7(AR%տ*=0h6^s.r\.r\.r\. Ls͌#Bϔ tuth:ZnodVhUܘ~+4F`mh�:%2ѠA3>ТSA[%tMNJ&Nl;8а1< 4f3[ӱq334hM+ &s61$A&{XS a3>1#CMӘ{4d;4 ֢!x twhG4[CK6?'u;aQ9xq}3Cvh3"Ҍh sEfhzlوzb֠B[M` }Q1`_kв͟JO�hL؀ٗ� á{6<Ze+f/ VIh Gsæ5 xFѷA&4{ 6nyk4ľ4f0 𐗢V# }E?1!bj:hpHhcCA ;b3FB}"mZ|RTzˬhA{4v Ǚ qyܵ/6ЯQ\1)1RD45hԜ-\yՠ-_9hĜ ,ҡ5'9.Zf]Ta^f })4hC /@qL-^ }9z)D󂰵f-D/4fmhhM 6H;P5F45hь!3K6%3.٠Y@'2c,O5WU';s?jI̞Ţ?Sfe=7FclXnz? cS 4o+hܠ~M}а]}ہЋHhav>?8af�5CoTh�tg&af�Z5- 4wlͳu`'kmcf3Q"7oM�mefٺ4gvfFc6[ [ 7@ f�cex84sBf=L+6`*G_vNP -<\ 0/޴7+DfY"~S-;HBIlѢ#N\%Ϥ:>=Y_7G AяhA^G?BЌt>%Иy7=OT4jJ[w!6#t 7ѡĻ`6AG2RR={nٱL1h،c2e#f oI�lV) DFf͒ev}j6!ZZa$h-UƍFVzs460'AkVth4v[7M=u'L?fݲÛhc Z6[awz452hӦd3FGt 4^[K֙F!hO3֚R*n1-Ze G"z-)z4kkJ1ѫ(zJ_hk {Unkk _t!Z0b$ s8t^UUYCiГE$FIӖ^);2fKt`JgГf> #f.h|72}28ZeEt�wCTd튮)E fL&}X1p]>5W١6�=UgC 35Ӝr\.r\.r\.4h?뇺bBA=չo֘EqEA~4&v@*n<z#7|4iՆ} S!3>РA2>Т-cGf]t5e+4; ǁ 3}Qհ}Pөq334hM+  0C$h%%rTA}#v36cC ͱ3VC՘G+`4/Ph@ڡEnhqpP[ԭZ?чGGGjkE-^�hlkShYТZ4blh}td0j}m>:B[MX |њY+q;bΤв}Ahvd̾kрSmԌSv쥾Fh6Z6cUߙy֠ժZyЀVk5x@⳵p CkaF{h1�[3t864=Rl C!17Qh,`f -ohuhH}EC?2%Ph| _z|,9 >6sьFhe֌QhceVf]}3vRO̾hzqnu[fe@[ws|d6GhA]}7hB|u叆:k3hlF�>9{MB W23.%G_D/K-Z] 6DKjtCK5///s_ n"З&fE}}A/𐌖 \I}fDKcї~hC /14k eh 3f-ShʬG_fh$A([ƈfs֡/0c41 (`hJ(4lsU]87=V7 bGPBP,q!a f֡;μAsn͟~] f Fã/�  Юކѿr }ޣM>2�]AfCf�!haf�Z1/D31# ]Ly?6Y`j:Y@s"�mefy3K蚭GoIh;2cYY@'Z OZ |s@fp͓!}NwMmoF=c8t{2k&7Ȧ?o4jF]v 4&et|Nz@WyYK,OO9`^hG99ĠAYEK>S&Вz}ܢ9n dA�.V#65ѧm*5CW ;Cc҂Z0芍hH+%{x:T?V؍y>7BXf4͘1npO⡑Ycf�j3V Gûhh]]]-C; t)$91Vј901F3ZIBCkV!,ͳhStw]v6Ǐe7kԌyYAkF &GO5:k@SJG#j?s 42PhD3Ow5iFZkM(z5 Zf{1*ѪzM(>zuVO-k:@6f-bW~A{t^ښ])YB- ݱWsUgV20G$ :!]D :BOV+8{Ҵ%WVVƍ.̅z%ҙ1$ :O*Ze!vDʞEPẖàӘ{#Z`'3C#wlgtN+.+ͥD3 zr5a @3=F3== uTīlhfV8͹\.r\.r\.r\.^QW}W$^C0:8,ތ =j}ogJ5zDmYF!ЪX=4s}04a~_BGl<yx4(w~L0N&Ž? h}p�ӰAM}]Ut|yhK!:.6 G%Cf!4KF 04[63#AkǨ)^:Z!gG3C4ϋv2All|ANCk"[a$wO4nC?oنã#st}8 7oMЇـ &"e۠a kV膶@f__4घ�Z5fd�fO6l71ݣ!6`kMhgk ]ÙVaѪD  kpmAU&}|Looؐ};4+c}egmecf3�h e6c<ND?3ZR>:s<4| '\s44r5>Ѱ9^d+?{@hR4h|dE~իѣ?hA~ v1mM_ݣ_:ؘ 513~uh _ AhYה 4BfM)E/htgf\ ϤB3^=<.4W{RhdEezل= { ^j$R@ ED/3RԠ/�%c>f})hȼ,<Z6MP3ǖ.MѪYE &h?ADžf@A챠U32ch>;РY@GQ~lA6$N\uF/.(t Ǐ:Z4w%s.nbGb@f7to؊CclYAclw4f3Z5Ww hqECf4s@ݮ^SqFoX_�{HEcԎ.<#W8hq)(_T6<ZAoX ɼ�-7HWE ͙ --a&3ol�fݳu.񣝙G4hm.m6AdxlZVC.Zl6{)Bhx1s4~TM7sE:=янYDrEt#% ]D+Ӫ(E�fcC޼^w�KEl͙ҡ Ehh}*y60z;t`C-ndm-mA6–g23Ōa36hxF eGwX13fhG3`"a RJc@Co1:$3BSkahԜM mrӳY`hnF{OـrC#MgM?w"h 6O-LIqծ>]tA{w kki: z A{Q,!ZWXDcUЫzj^C�z0+hάWQD[!2{Unkk _tUb8U%_8B;*RgJpfF'#Ec\ģ[]Df:dO&5{KJ6a8zҠe^ :EOhJW:s tp3 cГ`Hf�>q@Xf>l-S{$:aO<;f7tBsbЌQ薝جe�==Y2= D7)AJ"GeC( f6Ns.r\.r\.r\.׬N⇲AlX{7EQτ9Gia$=3BmEoD+beGwlpCq`,h¬tZy6� {w;%A'cfqw]at6;qt=AЈyyt3kMlj):.rR'G3t Ѹ!f�]]6`Vvmf&惃4ZcfFfA1)g'P3C3A ydl6=zm`F"[BT_;mՙE2Lͳ%t0 Nݝ?-uú#t51ahNMЇ]GG8[RD_ADE_[6g__jl?)f_lՄ}p#Z3jA3F 6=1[!6`kͣ33tY⳵p=:ٱKF[Fmn:�hǰBޚ!ǵWP4+cD}vbРGZEjyj e1U2ZШDKcONԟ66k' ^|,{ O̩ѭG'6GC h֡�Vl[4c_/l̾h_EWŽNFOhA7\q#Fha[jЯ^t+l4k7E.Ф _ Ahy{u˥nRU5/E`Pߏ."t= Ӡ^ɥB/!FV0yKDtQ=wyyj@/5 \}Yc}t_ό^Ze%@؇0ȾrQ[!mp҄Fl̳e46hլ?~0eЌM}5{,爢!Aty =<<@g~=ѽD_\Plw! zў -ktvC/3(SfMѪZ!shDM{u,:�yӯá}톆̜Lf-2nnW,[e z@#.Kmͳ?rCoPhDr5FVшz3zBjl rg&ɣ7l-Z\F$/vBoldn:aͮn֛.An 7t9͏vf#Fڈ`G󣣵ly<V3L& 5Dt4=yi^`@hL43-OO1448Q"Uމ~$T\E zOu@�-•1'Чz}}o ͆h,=Ӟ efy)ͳ&h;]DWٓxz8jFN:(Z~WF>e~ErO1u$s~,'tlCtCfWbV-1h M 1Il4fE?y-+13AhemhNQ;#B#h M5V4V2MfAя ~nݳe<$yHo-Za'G?!CF4-+/L&ze&4lW~f66 QBkF5iFѫh֌WauQC (6l^!Zah*I4lnA{UO2۱CWHtsܱasު/ kǩ4OhИ2=8ROjbiԓZ%K5vbѓ&z-EO&1f á!$:YbvdLp9:SO\;QO+lB `.R!aЉZ-CfzP zXpf{d2�<"EBM_z`6Dsf#'r\.r\.r\.r͚ZoOPg|Cѐ:<NlFۦq1v@"5~5NІ }pӲ)>"D'ckҕyhߞ!ӰaшYn:><Clmk fM03 YR4a؀@&dff`>hâG EթشyhL COo>%qgE[=ό1M`Í}]zl{ˑ?>,o"E}#l>4Fhwaё͘bhn6ah6dv 948]x%!szt gkF!dl]Aو8 h7AqU?|A+ ʹnѠu~ †h64+rB&-3,EN8;3@f�]ߗil>9Q7}l65Bl1] \KU4fƟ׀{AχVlk3iGSޫWf0oЯ�4�heh~EI)ZƟ{%Я^Q?*z _hɟH(z _VW~ooJ-s@hx=% z-<D" ->4B_]x}oTR@ї|j@UY_ Ecec(R֙MѨ¾PB�0h1tUѪGaЭ?QEl i?CP$]Dрz4d؂Y�ڄۅyBgUnŢ?5XvECf74;Q>f ͱ(ءд ٲWBBl;4evC6E[*g.5;u@ۘ!,7LAKE5~ +4SZzBlt2lrCCfS4SЪy!7%4slb,6BI7ha aACdAh\5s 3@3tP6eKf-l>fo AyF[{O "z) ;⢷%:9>E;Џ$&3 -E.uв96ZxJK6V<qf346hmmF❺gυ n0^ ܥLЧ{Gxc1.{Q0;Us43@? gFئcn<)ͮ'"5+lݲ�C+$ ;1Go#hdMC՗"i<4'Bk%Cm j=ݳe.mv^9"b3aֲ㡽VG ]UW]AO;3lr:<A}ОfmkMzUc6A�fE kB!2zEO-kЫRYA압58h^يWPtͦhތ;6bn[E[0pfF'Fndh0qau*dh{ B iK3WH0c܌'(Bzt slt3eVѓ`hf> k6G@G6 g0FItsǞA23LeJjsb&ъye/ aDֆ@d;xnm0g[՘d+yCȚywol\.r\.r\.r\.Y]C l6Ieo~(R[[8ѳ8g m B=SS5~74`ѩĜN64WfN L@dj-Íqt*58:6k8:18:>̡C[y3,0x�&f\b,)'l k5hT&惃TjbA14ݩZ3gLUyfqCf2:,[7hz2vDF___[(4!תZx} -MȇhmZ6@G L!B hB]&l|҃=`& ћnhpԃvd.h;8Ѡ+(3*!Ahv@Κ4d}\FhvB7qݭ1ݯ]i['ЈYB#&u2fhY}OIGc# 4x F�/h\|Hm6Gc(}bl8JL4pDkƟתyAχVjks.ѯ^g|ՙ4llUB ԯmFKWW38y _sbKs4SOrvׯUtX++jDK%Bwqf M,̆j in ݲH^.cF_\%c3Џ b֡?|�|,"}�0ͩ/21 %DUiuHǺYEwꑡUB$͙;;;ID/Wcl_`[4k YF}3;;5P>+sD/XPn_,飠?|�ܢ Bnbc=Ѕ5}0hƝ{`4A/3C[ =e3ͥ]{qBolXzsҶDolj{doՅmCoXV&ћMNfV# tLA+7РchU3 b̫asRd*"m^AB@h9�uTf mʖZ�0[@oCyLE5腄ֽآ!V_e/DmH0?MzO1#Zl[JB!i`h.^f 9dyxd�ͳe^w5#hNݱsD}z ϺygAebK4G3AniwSf ZovE3X590~Gs.͘~K? hvcn<) ՅYO⣱C-wpJThh݊™:*Z2qr LҢIshz<CfW4RfmXV 7Hfۺw]# t!R{Kv44fˬu<ɻeF2kє|,i߮lhX=� גz a{qTl_3DC굶f֬WH&L%pȞjмzeBWѢWyL]a!Z0P掍Иyҡ:%9qFaѸAom]ݰW(t`34mqU+RC'z܌'(ӣccAu0t$2B3+A3S tdjsttA'1wIt*rXeJbrL֠D'i0f?@fN#\uh&Lv_0]Ss\.r\.r\.r\fEs 1i&5$7]? imQg\=zDۢqgEz%3 z6CK0l }V3мߞΣr k<<whɼ$ SaшYn2:3@a�4jf]�Mlj֘蚭Q3C]>tymJ6e6EhlnJ 4֘hF<yhM-qOl6'6 lŜ�3۠ofnfSMt}R:%͆f в9 ?^Ef#bVÞh}$>ـڟAS汢I:[5)sL4`6Fh<v4h_NA=]}{a3>nLF$iwe6>9nllf$5KNGOt*<hf`]d(.#mlGChJ;twuhs3V4f^.]_WNg@ۛU+mnCRѯLa> Ph5Wßyu(z&~^ tmžGS?J(z&66'i5lݳb.h _sh6 5Shcv`^'N[67(FC) ӡ?X/5M3.@sW<3�/H�B0+S?X/ $h}I?6Csḥ?&G:螭9Gxh-Sal_h6ASْDljG'aǝtEUggh migŢGM펖~Bl^Th 0wh]~2{sg{Z4/Qh+3 Q厖 l{p;h6E3-ܡw Жf4ݲAs!mLA慑9>ŜyD+{ZA HaM b D/@o{ Z7G0h=wp;= m[J\Cc¢5%:{TDAlHBI9>Mk"zO~h ͛;3NEqarGlGoASf-+8fԎs3q3֛]0[Ff]hR@M8Wq.m?:Ǔ0hiGo4VO�q4<ipD{ 4=u`2W3: 6Fo hZ"19 ZIcA[ǙuhgåX滉ֳ"cAЌ̻UnxhL~΃1eS tAlC쵵hyhY@C쵪 6hʬt�3^-0K5pf hȼ WP3^Ykz-zEAq[6=3O+C4W*ƶpv ;YRвyE0=lq/VDO4o~QM{ \%Uv -E~abDR<;FOFVٓf[,'A |^YzpsDF/Nn6`!ľ� ==4b3v 5f&ULάufmr\.r\.r\.rf9fe7m? HSFs~#x8=;@hf̡RCgRDoahޯoB+f ̣r kqG=[Dbqݲet 8ff�h<d0*4<195[EGekЪDq`3.I9ktM+ ]+63l֘hFѐ;MӛMфfmw|R3 v4hN㣵fͻqXyht%͆f в9 KEf#b34?h|->�ڟE4e6Ahlh<Z4eաѐyhM=m?^hfiuvef}ܢGݷ31u8hL~FhFɉ ځ%1fd|c>zeۛ0h/4El>-oȋahRk4`V/BU ^bh xzL4ZBzejfWsԍ@Ͻ RѯJf=Z`cOE|seF_$k.D<lsXḙ#Fw%_~=<b/՜ϻ 2gՠ)2CuJaxmG7lH4M]g)`Ėm`Ptь]E4kg\`Umb�/.(%N7�B0?@F_Ӡ?EEsh̡w7z3يgj̮ni<=:SozabĠU46Gjq4f;=%]?k/lsCoBA�g>V-QH4mF*;85m^phVԲ90z+C1htPE1-ycΙDl 4ι7whlC7 7|ЂY՛JNf}:  *Z4XZb3ݭܡw(tC2 ݩdfE77ӡ慙9> ~_,5gņFw3S[zu�36VhRŒ9|>7Cow=:=E%gݞns;4z{vأ2 Vhq'0.)c j}:64vu udh r h7DãdF5[BuG!s6mW4]̨Z|Wl ݫїaS2 WVR(hHBK+xfDcmԺɓ@z@h0 4)'hYD#ˠ'  ~OȒ�4m-ZtӐ#Lx1C }-i")ulo.Bg}Ќ5Xh#VubG2S/E\e1ۣHh 20{-=VlN14^[woVѫVf Ğf ΌWe ™AjzD0dP^k  ns A[q1sڢ+C4WaIU&ԥ7c6Լ›Atp=lmnbEjt-@f=@&W)hEl~!Wm/f= fs4NB$+0dA= NAʊTOIEYl&Ð!1z8J7CmB،衝JҬ&dFM.W-8r\.r\.r\.6}K}>|EimX3  zV#Ǜt4lEQoFA-<CyxL4ihscAϔZxhze<:-[5@~c ;dѩؔyhL[Nath,K1Ѩݲet\YEhk>8(?Khl,,)0D3tV*6mfyh4).(b75[)M_UWG6DhD웮pk'9& foB?&ZJ2{obg׆ЊȌ7sφ,1CgkєyhLyvhtAD뎾h<v4ha{iMvenq1>>fcFf ]_ ݲON\d/ W| -q4^{6_ >9MkѼ94Nk0M}v\4 mjdWF⢫+)tYFYestj&3S] AۛCi]<za?m®vLAáu>Xc cK#(t&P荍 _ݚy}9(3s !ī?V@fShΌE7AShܣw784يcE+tto(AGw͢hXU:%L= VEl|G螽1zٛRAf-]ܳl>;0 ;;=[1slw<h4=h n-BS;z1н9f h"ֶB[*_]m̾hEB0h+]E4nEonCw߁n  om֢I F'=b=lC= +(z:*q* MS#ECw=BâV}< Q9zN[bNFjKQcBf;zt^5^4 StZ-Z4۠a -I8bnf4Ffmm&M]oL]hi"MZ^EFԤU{\k70~Ek V*8ISH4f2( n=^ B?!K֬is t6_MFk#BwӚǁ;I4fYZ;9zδ&vjAzi׮ mφ0{h1z E{-Sךb^0h=5F�f-J8{ (Cz!Z83^rCPf61BJWmmh#s$lуc+^%3WVPꤨFp\ԘƂ"+z@7kГɖVBi8zy #t3ʞ(ʥg1 ~adBٱz 'h,'Q{[,'A |AWV?-$Z65:7 z�37G%֣ǀ.-Z&+X1͘ڨ4Q,2Uy:s\.r\.r\.r\aw w}|?'K4a,l&ϹMujf(Uo쭃CǞzG7Bτ9W7oۺ0z3N)h\ӲUHрe|q hb$a+$n  Fd]Att5f1%ݰtTlѴ*0 c 3@GMRشѤ4ch<FlNg7InUQ\3L1Gk ZP3}}M7Qe%#h`[܄W_GFD@_Kd_R zh\eBF;gph˂hLvhvЮhp+!Ѡهm>nҙS=}ܡ'Uu>FfG4b6FlM 蓓Dh, 4;A;u0/z4D71yscȌOLh<}r>/Za0C#rM?IpD%Ӡ~eWr ;W}m@3W~tCiׂGr5FS껍fcCt2#`h-πL@DLjֈG֛7>0 Q?G :b2l;7:3՗cU"}yu*47giA՗Z4Eos (zGvP6՗jȄێ~-xFwjͳ7MzcC1@o6EW ;&@+ꍍDhn}Cwͱ-2 h̩Cݫw@Ͼhes8ѣwZ6vBbB5~Ң7Eb?[ _УMz0@Ehl @s6D03*&Y~qCt9kMo`?Foh~3/W o}OC7hr4~1E}ҞVC3@[=PR/mivCs`Ӣ; 0jMCb۠vB[٣# Djd>3@=ZUsy ͘ɞvFqZtDsf;zte%o+zn>LF'DwO[xZ|44Z1FÚl3EWuf no&ۊ}*XB2jʬYL!X̩2NnUFǢ2Z Fc'M!јFS+':chz-,Z`fZs t6_MFkQvDAӬc/;cY Ɗ&ԬR-4icMNl4֢P=mի}8f{ m0{m S'FOk(lbhÌWWàU@xUY=#k(:B j,EP83^mrFCȬWЈ(bE'53ܡ _89$c+`%A'23̡sztj^L&Y`#蕕tf=i=[$S'- J[*zE)WOdt]~Qfb Od  'h= Gc4N@+/z%f7t 2h/H2lG)f[tz@C }[^ZϚ衱b ZQM*4c3h6>sVUr\.r\.r\.r\{ﺆViys~3* 477\5mf fT.o0͈3%@h0WlŬEcc1Qso0: 6mr4b֠sk[3/A[Edf348h}p� 3#6Gbh|¦ 4+hR\xAym*@hbKthv83}"F$BWأKvO銋֛uh֡o"01j֠Y2h+Zd�l|-nj4FU1QeB+Y@Wc`13l;i 3MhhsxpIXIT }Ц ̮hlfLvl##3ۢO$hԌU  F˥ ^FBK n>hYisFٺg{W;Dk%U4L|՘]=\/ziͯ1}E~&bDht?/hY[z)0'Cw_0n摢isFB(zs(tه"Ǐiн1zCǦh|ЊY@_4]vAh@_WOt"b1D;RѨYb_"c;zCAoO?@+y6ٛM*OKCf 4+RnٛRnh-Є@l=d+fvа@h @Sf3YBl f I ohkno e4y$h{CAChmw-E|n.ٱa�={O$}!BC}-9Z6V٧$KU3;f>ݢ$ehf=*ɏ}5 M67]Џ,s+EӣG- g]s-fG QޖsGz$Zh ݳ[zU[J&hvіfݲ<BE[5lbASh-I3_cB \Сw/\ FS+'M)0\ D?! [k< Y z"mnَKhңOzh6�1 =-2Cq/LGIs-rEuh<CnWFWW2U=l8f[ iЖd aZS ZDh5,zU-Ø!4z E2+&,EXX3hؼ�1W2E#梐fFkܰAqҠUVҙahh+ј0h 蕑5d l+CG0DeomE+RzB_#A3fc ~ah! 'Q�{bٱ2Z6%bBh,iNܣU: 0[2#p3f=57hS^Zd+fڨTgl|\.r\.r\.r\.뻮UFhÛs~F@5捌~3>]߼ègF7(:zn-uj\NMoߦW_'`t6l֡J5dNFA–Т�Ѩx;xq~citDl:;6GbæLw%nLИ:Af�udT-:4[oѪBcf ECh k v ZP3T5o"p1B֠[`֨=7b;}#-Ces wEjBklҨY5HAGP-n#B~ƃiu6!ȕ=6l4fƙL}ԦGwyc>͑DIYC3 1+6cj�8nvfOLDKO/ F33a˲hI!˦hYKK%5416E+}gIf>F_kR_hݦ}]^0s-Jn'Dm.xqq4[E~^uFh6fLN4}e6eҜ miHj#Z#> ,2zÇMDk^h,/.@4Ao(hD RAjG6�4xJFє f-RhBAh,/8s:zcC>6�z3�O ShMw6{t'2W8Mm-}yIYo j=BhݞgEhBà5if#QK4sj: ZV#hjEjfNnyg9Ff,I-\AUtȋQJy4>;-ģ1s C /3i@;DEWhuz>GЧE "=g ІARhX/ZsU)?U3Itp43,ާKܢіf2?B%ClG4qܴFGJu=עkvOn,(e?zp r6Gs^~Ԡ?9ty!z}ୗDo/v-U.օB++"j],(3SSu'>JtƂ]ȴZBSfdSknhB-i3|YhLhvd?FRoC75~ ɥ`$nj)h$t' @?fO"Y9B3r"ß1.:8}l\w˜Ѯf:&ݬ5evetTEShuW#{ucO�kDOA4^[[K66E굺(h BZװZa0l�=uF0fYFi\pъYBjÙ VhؼL[tkkBk5A`$z*^]h<FlhG W4f z2+U7ꉪ.j/VqTfDnj'0z^Ɍ'0W[ z‡eJ*3kV)WRu�t|vʝ,}ѩFk^ [5ۡ�B#ncpfCUchrf/#n2F Sв ,֘EШ\.r\.r\.r\.<뻮UFАҾb+z;7?0FAA7Uhx3~3"L FCe 4 +b<!ؐYРX>8�นB & Fgcfxc@bdGci~C5f펦胑^0æ  o|8JAtf-Ӣ5 +SmݘKjE'1īL?)曛h}5 ò6F 4c+Oe_GB7t }oƏV!"<0`_h"cs`6KAD3lc84ve=nAAM ;9hw4Ɔ|vhW6l71;k9څD3</(zYf�l(4 #h^s9z%&E ^ i_ShY=)yhYF_yLm"+Y+=g6Ah=GWXh[F~^ mʶCh&͡nDohW̡7isF`<J(zΡ7 777?FCM4-VMWbN)V/,UI% ̡e%g.8C7Ic&"Go?y/f+-4gShKO9E쟻B3A4R$ fg�t(S<\}C$̌0Bwj\ԚOOa4h AeU1GA{zh8cS{G/P?5DZF!9>2C"2:࠙`a $0hKsf F0T?\Џأh~Բ=qA*~Ԡ?�?Dyt? Z~{ ٩:IGCآ{vFw0MfX֘)z}EFWJ~TU6ɛMǥMMEaE?~^K%C?O|OhM?kZt7SK4lNJh1gi]D7C쵵f }8{uUc6B(h/3^m&;Az-zKc֢תWg*@Cph,V5\x &-B 6hÙCaZX3[[h\ȬaWVpqx3h<Fl<j.^Ѡ dRZfz D0FG1kГzG1EG2l[ʎ'otT38Ev\3f=B g77:YbO<%;XDf[t23W̖<щ]O%AhVĻˋ1]C/Ŗ= @f66sW"cy7fvW̹\.r\.r\.r\.뻶Q@0W7{+YDo~aDR=Ӡko$۷o7T=z&ߴ)!39 NV̕Z&7�:0А9j }�qxф@!l<^4*Fv):*4C79k7ۡ>#qؔyVb @,!fܠh\_j=YZ5(& Z>뛢h@sAns6T͙@3ּDqHui4o9 s5Wj?0`_KAf=-+r9 Z5 MѠy84pB>>P֙a}<04k]@+15sA_E#j�ݫ9)u԰9M5^zV,a3�]6yZyVp 9=Z}NHFIf <G^9Bhƾ@RMERM^6 "+Yٖ3Usͣ FA![oֱUb@3m#cMgmWY"c;$z WSޠP�$`h1AoFa!?~܌԰FKoG4fA. Zl/bn)ft..oGKIcFhma֢sVؗ}Ѫ]w6Bƌ% z }igI}ihͱ)z%֨n}I?I6fhB "n&s2:AGf$Z:)[)zP٪y>WW7z DьDh8էG(48է:Z.>Fh% =wC8/4))F?BBo.s\}z㡿.nw0ɬC+jML2p27sf Ao@hx^u/5GbL&;5GIV>* 3n[?Kc#h:AKH4NJ^Vh:F4=[v`4i3Z7ufNm^_w\:3~#nX-Z5W]nKST2' ЁOsFO?wwwq\t'S[4lc#h@컈^ mk8C@hTs3&m9@*ZתW<k 3 {҈ 3K-+T`3cWUOZc^ m&м;v( kv8z梀fRѸyh֬QWVIE lLC)HAo!hBݠ� o&ԓ* j+Yl(f\=A/HXd\mVz⍎iȎk 'LDwd=D d2':Qd[tZr}z8;z@7C]C xx121L47" *mL2owr\.r\.r\.ra 1K474GJ5R 6=!fԐ޲NBaѳ&b>3Bo+4I⪡3<.L 4whll~;�sl=cA[٘yhԬEl35;q36фa+fMh1W *H5y b=]Qb|GTl,k&(0.}|M`>QD\Y@R`I} f *4_u9 Z ]-?S1aE+q7[6_f4dE+k͞hlViЀ}| DqNVAh }ؐY> I1]A1t`>>rA_]A14cJAq3fycva/= AK#e2Y80yZyavCp9zT^h͓$CmK!Cs]*b6x&mWg!f[v+lV!z6~UU5h@;0Zo6gh3Am3#M<gzoo4>Prcb)q@Fp4nnNIO!asF`fWsW<F`fP5@ljپ蝪MW-X}rY<%=AEhV6KЪ [RE+fZ5ۡ/%4<h_O?ib_6IO^D蟔"KVͳ@_:v1;a%?s #hz ǍF zhۃ\OƎΙ@7ȼH]�;-zDtoА9zDϛNA1Ѱ 7A#f'bMn<$ZdQs[0/  à? HG)fr.735 .47}^^/yLGH*;XghhS={+Syv8ѨmR\_iZǀhl-[NFrD[zv2{GM< a1mO|ј9I 4cO2ڜ=-*uAi5DC'nf69Ӡa0hS6bNgO4;@hV5@%EлRd@"hl0z E{Aji6@ 4@赈h*^K^%@�掽 _aޝqd.� ,-U7}7*tCJpwn?L23c9'<t~bdq 5ǣM,@5 ״�ѠL͔h;__l \NeBwtmej�Ѱن&6[ыS&4g[~hlV4^\7mK|X':7R.t*sJt23d3chtB3^DUvZ3^F'6E$cHtF_@7fC"bx,`˙].M0T @ ] b>5K,o7 3qqqqqqq Wb+q`tw' ~Mϳ~T+{^I ܆;a.~z0RVl}Nn*l~Bh&:70@bFQ+h' C0ϞlFߗCcf=NvkDf Ձ,sm1_؆9�Hm5 ЌM}cѹf:觿lb|E&A;9m *[ߐ.z ~Jћ%>-z0d쿣Ц2բ7 ik ՒiaS�sU=S@M4h6hÜ =чiwwg'>tAh Ǩ! }q(V0)tl>bɆ>c ?l*,-4p�թѰ9ݪ7Eb4bG[1;-a6M>3Kqj,fB4~fE89m׸5s0Ԏ~5s(rfrLGn & VпG$;�dhZFf;5B{-l t�[A{=gAtm\SCdwir'nwC:=dq.%_#@:$Т!N8ZC`V02?T[[<UM'X4d6!w|52Ԡ6#g4跴zІD=DEo6Qht39z7Ц;�1Fk $D+? m><TY_(; 6 h6?H |FՊ?;8 `g@D� ʣEZ2 ۨ ѳ Y 2ӣO#- 6lA\%z$zVس 'ڡ&DdebNhM$Tj-,�Rex e̡4蹁67hSM:57"#'+2;$zdgBC7˭yr@v833Dl:s0cQ_`3%c�Y轼<]lhQq/wWп_FIFȧ~TӧNOgtGωt_bC{AH3 ک託Oas?h)p5SP4f5N^V.P2Gf7z-Giث.9ǚuJj zGV++ e(&0wl-I4d!@кi^ӚmA}}mkO4 hQs,fs_kl \Vȱ#9} -br X, 5l}mQк4jr7mK|Xh(FʅNevdf*4NgыxtB3̎AkfXG'6XtN/ыXtJn9{1 [|C2t9s<ـ{K-]<ti)`DBmףˢ|qqqqqqqq=(ݩ>^*c*BÃaV؏Jry@?VŽg?>?VrOzO}8OE9U$aΏ~RBw˥i9 1c/цXaߡŨn4bN5Q3?h\76ɉh.N-p쿃64d/T@`Fo6ʐQ&@}b /IK+o4迵@n&cw2`a{�4d>ENs�/գٺy h<ݰkQ 6A7QJ'>Gm1@,hjb4`'y.A3>6.>H&m^mZ}@Cx4hZ70dzчi΋> h(4lOr%1C莮^cD /K[f!`~L\aq6k~5SƉi4ǢU-~ƣנh- B\<RSD;+2:H2zLhkVsQjц пk"4[cѿ -4G3U0fMgooW':YEDvOh1hsIS!3xFSQsh|Ǡ7{@+z z7$7FMW6[쿊-3`\h;{+5Z4&A$hsؾmE ?!h^J6~hshH ϥCFF0(_VZYG?@왔\ z='AόҡmѦf Gy4dN`� }ujnD6F]2ǎE_Qy;eFB*; kF#J+'W$:gpn7D�aBdaj@[mK~7 IlQөH΋T!n͟u)s?!8s$vA8s.4lEǽ?} c#OD)kjsFuCzj 0Rz A @MJbv`+=ܳW`9 ǛŜM`>)M#*GCg0e6a,f {qJgwx \1Ǡ}zVtV˲-C/ns.DlsnF&a/`MdεGozt3ȶo21brtfMNk tb^ӋY >-hnn^.˘Ǡ \9s<ـK6`FIf1sWO3)98888888;sehxFפ~ЧmxQS $zw^UwfX C]�˗/eOفί~C0˥扠9O8N.V8z`1*b ǢӲs:\cf })/lݬ" Amv@�B9#Ics/w< ىMNЀFW*'ؤM{:+o<ifq~%UWUhѢ!s._-] Gu31Vnʵ ЦolP ;p�?E/50}SP~u牾C\OˣNqhAGkpߛPCf;؆V0Zhs3hܡ#ՠق ѯDݣ#w Z< %Ga5nSb<:\ w;ܩ;kN̽?cJ7)m^ӠEJì!5viVٮkT~!H`h5 &וh9UG>4G{<[94=g,O7e3:ffth믿~}EDJGr]slaEZ�r3%0GZw_ h? ѯNt }D~{ CaP0s>7mh4dC/| =jOf A4G7. L>_ћ %W 1OG4Qoh4nEh#%zmg{zhu7Dh._m wBu5nK@cj Z$CơFulPEYQ-gr.s%YN|>@όҡFM]hmeχb6ޙjթZY@bxк ]9*%s, ڄGs;eFKV1hv~̻BhD=3mwLt9m јnBd@<IiUhkޟJܡߧ@Ҕ=4,DAFj#K(4$ڡt_91ڮVͱYD 83ڥ�)Q'@mc׀^3چ0UHv S13^VAfVˀ^Y`D^CѡuJb@lJj?G枽C͑3{}}mW ̧`ʾqh1 ZaMhc-d:s�ZfǠ6bPѽ{.y̸zѣuiVM5^c@-V4C/NCBeF  %z{iD'1j- brftn^Р }Nl tr&@ |ٹ0ƠeȣХ&Vzow).5DBIfK.澺48888888㸚z軻+mM6O}ɏ=^*e22Ã*@R9}e ̾X aRKvt_N1Kv6K_~ }dF?)J9 i$l<avlz:+Alu3:< qh|o5 YZg;+Ei;o"mբ5h"Ѻ"$ }<lw4X 1/uGHȆ;==4h?s1i>@DhӼ34hh|y`tî}p+NzO~Oiv#aG<*{x4lч`Q!Gѱľ}Я3VͿ&Z َ8ZS&+lbA#Whfm\EqoIf ]m͊"GlY$} Xr0i!35t$Zft D{\9>/Ŏjjh!ǘ)о젧:QsFt9=_EѸ9hC_'Sh=k?{[_h<#~Cgf'~Ϳ&5@nvDfƠMshK:6|~_IeBwQ h]44ɃD�3v-84cG>-h V?ޒϏh;D/g[RPjc)N_tDh(/}+fR,Z(fJqzV `Vس0�8O2eI%,+zN{ =4%<)daթQ,4@_@)@|Al7ڶ@L8 mJ~ק<m&~а9mx#6NvϲIc`s: x[1)o3HE]hݜ%u.6KVt/hhmGg.vs6mh ׉8; }A Wq֏6G&|C*0{f5kh U6=z?U^)Ye8%zeA1fF]_Sfa1ǡm5ZgchyM#>qLb*6/5AMh^:Д44ف:zٗnj=Z7_f MlF )4F/E z˘ǠF'1l?R+9}s1ߔ4oʙiЙ�;߬us:YcfmC7ӣ3xt.1%:Ǡevn�a12qbf.uLmZ]k&ati!BHf1 󥋹n%,`88888888]iw'p{ig ZU?+$ T*J`A+q?=}b/_2;˗'m1fVWdG/j4$l>0jԾj.4 ]dUш6{!sNQ1I @ }۔ly3BSW4>`puQwAU5hK;}.C*8T-d".},h- ' ^u|QJt}e>{c6ȇTM1ni>lhN=1ژ]1]D+j^4 n ]Zs0VUч`AǫyFчC0zcկ0@ 3&Z *~}J#[Eah1~a7hmfAy5Zk7 \$ore5ŪvoJ!r;ì2jܫ* 0ڭF[*S~dѡ8�>qkZVׁ}.V:j gNR3ٿ7T5 __M~#B"_Hhdt3}&?CzyC Aoocѿ?=C'@IҌSx25LC$YXF#C-T<Gb'O?6qtTV&B#Rv#kM "A -?ŐOx8:RM#'G~hǡғD,h('/}N"ׅ E3!z6K֢Dfv6haj2G`RM�ȨO*သ%DOQ l]"&@b6GSs(46.h]Fۦ Qh!,hM?1] 10>նabh/Yh@ƒޡU^*4/hiCXpt9.-"If�k@t"/}:ٺ9)ڪ?-4?U;ȧ@o(Sбj4ьDGӣmX42Ш: ]и.^j?ZZDAWh>WVթѠzf5hE Uv:T+zd1[W5c‚hԼ^G% HB %i^S6b:A[ʹh5%e3 }RYєdzXH!\VѴf;6ї2-E-Q4S/N`@j]daB EgX텾9D'2Cj?Rz͹R#}#Ul!u8:PHtZ6E6+jӬ2<ǣs%htns4zY4 ]D rd. >^VV2YMP(=m'rG2gzpf88888888p{i_vCߝ<QS}_Ad_z|䁾 fG#/_J_\ fT<!:ir'#`. afttl\71Nvѐ9':`Ѡ9 :|ˣwN�Guc`\hlkFvؚESw4n.|w<i; ZT!q;z`j͕uEFvFz{c΅h)@կK�<C+f�ݤчK0ah<hȌ �(xta }(FaC03ǣ_OZ>h~ Bӡ_&U۩M8|"F58:mA#Whfm\CkvbSV1~D^u4r jA7lUi.ԬߔhΫPL~}Eۯœ@M9Mx>0bzhѣ͹<qvts%Fal̜m3QsL7G'03:l`(xt*sJt*rS*t*o["t*nω\ʉTR)">S>w/F37׆v*N0hh*MzUZ7CBmggDңMv<z =, jyhN;(z~mӡDh<{w*z.5S :, >J-m3SBbR5z7} DА9m}fb')m>Vwfˠ!/}:0jGCl /(ZÁ6 ʆ/p7'Cb/mgעCf*n~?ܳ3jCCѠ8 ]h6jh?m!4[٩4d t6VS̡OUq\%z0A6#%Df'"4aOF.4Ħ(z%ՍErWh̜ }f5heشhmi̧ Ze+њi.35nF\+>V7@/Nik@ӛǡo< h݋\xlI6V(:9}3AMD'3[ }#eG4c5C/fa5ǡ%6`B0 9| 4sz]B<] }f�Fy+3_Bl@fOۥZb!4h͢f%<h88888888z8՟<^b^w$y*Tz@?֣~к3?yB?w˗Rx>K^:DN~2G/jO2hfR0ltlGTh�:iFCiw<zD@t$!}gv.ѻLhJ\$zgexww<C'Fw={U>]Rہq أGKG==z> D 6M� W~T&u>B{T}6K f\]-hFǣ =:T86j<Fј9z}Ahk:L~x%Rſ*6x pte#W(5/Q:$Lp52~?BCKdh5YEנfJGwhF~FۮTh:ݱ Цnt`W#EOC?Zf YѢGǛs;xs!JT(U1s LN`NNaC9dSmUWE[7lیnL9�Qܠy<zs)'V\1KEJOeьhh"40hh*ՏIz~z9`W~ɞYug3JlfWMlP006umZ:|>i8%z>7QhӌǣCАݻw1hp߁YY@w}諫+@|.Xm3ӡH/Fji}ueUAJ6yџ>}2s諑3;џ>j?D1ϧH4dςԡU?gJʊ'_.s;F>諄h]eޤGn~F9ZCC C0ۥ~F?. 66ubt4٪РT'[1OZWA#jOtJVOuqѫjvmfh\=k=^l1^ 7z]ZkCj+l̩-ۄkSe؄S^k +}b\"!Z[-:�vg^.+C/ }hzmSGoN)h-/xdi6@8BHb5C/fm9=2sρ@t^1B7jt 1F2Cj_t93D5l77*h!j65ti#>d>fX<&H88888888уTio4ƣު$x+e{p+B?hAGr'/}E6Q˗Rf*e498t>OFhE*~4`Vرl9(:ny|1iiNvh}o s]K:?zwʎv.t>3;z7A :{gAT x,Y֏K;{Ԏï\/En)fS$$FчnKi-4>)zSGf}7hzL2hz< 4h [V 65ch90dL>!4M6bB1`9-?p4'Eiͱ>KQU)ێ4DzQ480aNVXCcWP_<=HSr!%*,@\W!Vi\m 1O�mF7ѐv4hgDh-5]k΅gG-*@7E4f~ ON4j~ QxVt(a :A@U*t*o["t*nNe#BoRahЛ7@]f%FEܠz{nnP,ՠCn�Sǚat"lhɞJbG&]JDM=J"hݜ =o8{.kshĜуob1bO!6*U nB%aCwI|F B:fO;ЭӿVcqRhK9>=iпdEG @aǙ(7_Ś&ICmqh\?0ѐ|.˞":ҜmcDǰ!42}"1p'Oݜ Z9VÜ 2C-Oft\褻2ПfC֗TJs ڊ&0#XG]_}z5�zΆk4f4fN>X\l/Ʈ ̞hދ/!>jq _n.trSS=:Cߴimg>}NfFxәmEh zD4.k tr_iGg3_́b t3GC3l_tIs,ـK{<Ks yK�EK2Żԓ2sqqqqqqqq\JS;YKc<&NNUHh�c=;}T]JD/D?~ɯ~dGߣ/_r&~rɡ$i&YUǢ/t/zaNW}D;t;n 4IS�FѻK4< dgATq<C,h6}<jJ:k/gwiԺ }h:yw=GG7b" ~ezG}0Avl[x.l !3Ծ45cѠ@f}bOK6F!f}tG1chU G}V>A4l6Ոyz;}0ӣ_O}iѯa3Ǫ_h!oM̑j ^54rIB¶\!U4v5U,$w- ~b>6~ @ūMt"fFi֫0s&B <i} SWŢA4*A[iB5Bn鵘 ŔDMI)M?->y4I޽chjon ݵICoRaTKDǦt6@]f%FB@oOumW B�BV5cz֔EM=J=GI%#0 МN6ȩx@͉h؜=4BNArO;!6"UHnB!eCwOj@ EѺنt_ F_F \ Ǡ!G; ¤ҕ= l }o 7 aǙŌ?hXB>#џt4~V_AEסE5�R{4gDX3r$66ZD"B0A71?Tj a ShaЪڜj({: E0mQfWfzme71ڎ0j XG]_18DV^Ԡuv|nvA__j?ʦE[5GK\.{, X<$hI}@ghzaSID]ݡo4戩68:ٮ7}Aә75-(tR3^,jF.j6 % ]pECptQ<` nym9 ] %0]<]l}E: 4)]+f^f\~Kt,/j%Z490qqqqqqqqq?@mwRǶ6'*ԝV7Q}_}V}_ͅ{rمgG9OD?)Ea?M_cXhlG#hݜ {m!shLNĞ$zs SwD2ٻ why΂=2wR> [ } sXAڎRhnѺ9'Bfm^t8 ZXv-@>p~ ؐyj w(lQv aDa3>TF(@Dǘѯ.3:'2S_K6/s& 9Zۮ<Z5> Fض+4P[xӌ-XhfF7ٯA<h6@hWUv_ht(M&EǚKV-I^WfmN5U:*@4;R v!3=:TIHVT֮hNohP%!0A`Wfh!-*zسYk(�: u( :ǚG'AqY[%< =z&6Sgѡ7 :&~4`NĞQas -"NѢe1c]4zۨS ";-l;cWІҡMsh@L֣Aqh<}f#hYbǢqsztYXIgxَvǢ#4ft(bWʅF_SDG &{<֜1l_a9џ#O1thygV.msW S%2j$zWFah<us<zg^mh,0D#1Bŧk7z\[5Sh2hkM6ҁ^)>k Mt-}md)َ&6[7K4Sl_tn4mOgDҡoNЩ̱t2 oPMh o*G7:/9:z.8{. ]DK^*z1|j.!Bf}.gѺG4kpÌKYE&f!`tiZfn5יaТ^s$NS4sqqqqqqqq7M%hhNcM;~RA/t]}[==.~jz~rمgG99O/OJcyO(0W~Dk/_2-hLN6ޯCSMs0dO G:{aہ0:{7A.Z;7)g}v{@Mm;(zO,j }�̗w;D c}Dl݌OHw0h}U\hE-P}bI-ж}f[t dz!30^1=T Nϳ>Ï z$-DF ѰCsv hBzxkGG42ڊƞeؿՄ\w9!Zۮ踝m35XcE7:T.an_mj h?v(Z'OmKe2�Lv^U!}U$Qh5Rt_G&EǚKWF sQ:߅:|BG52ht12FB ݴIHVTKОp=hN1V*o�%!0G-mm{n߅"?ZݠZ/&y:L# z6K;Րyzv. HG䒀hPz 3oGCDyX@I9jNQO>7f ˊ}h' m,wZh\ϯ\bhL}u)Ld|(n*AL֢Zh|5nl<zM[{R1fӢH/@ nNUDwtي~`C2ѐv48D;Թ%:rMՕiCf z DSm-hS =\}j 9|Uϟ-hy$gџ,h9zf5׆^u Zk^J/>%)Zch^wA\ )mc7wl'Z7ߑOS6 }vu__i_́^4멡k3:hb{(sQ!Tw;>f+lEcsݡRSDg5;ؾUNbmo=qSm āSofJ4g֌F{ӛb:YG/&V ot9Wg/>hpq&E4:?i.Cמbd@}=0YQzMN.3BhhQ?ZB$=5 M֚ˑqqqqqqqqqå"wC?(GRҡ/}U/Gz0S ݰtSeSB?C?;o'%ق"d1I'm0tz6nm1@'f3:[7ۗt )Cd1 ѐ9'c4'ai̖2?Ɯ'GéxR~ @wJ}*5wcAw4ٺ'GfVsi_}Fwf 6Gf_ Ӡ: 43\4ffCK%A#>}<DuH3&GkW%AC7uVlAdz_A485hKf[@W_|п) ǯɃ\B; {xL~B651h7[fʎA)MV-W!ѠWUv_،eؑfkBOx'z)=yRϽy:RC{\W={9j ocѡQ 'Gћ qdUA /!@17F1hm4ǠFKmY(RY ш93ݿvhӼ 3@C d@ܡ�f\_ :Jгг(8s,z=Hn΋4 ͦ@ǢtOB_; }П 6h`_N\ &;]O95;؟{)=H'oQ95eGfލC;q4Hq%syU_hRvaߵѡgѢ:/N>큎4_p]|OD&jts{:=Et(:<M4^`6+Ռ^[# }>B?Fкy,:t}8!zVeD׮-oٞL^ؔhȬƼV)kO%6>Ҡq3 mjqJFwlЌe:9'Dc5}]^,:ut :MlX ŵV(L^V*z9A҉&7;./y ʶonʙc7df FH)DBf<`vz3^Bg0(t3-:`ǡu"լA聝[,涅ִ`3.j6^bu3. B |S4 K �5񥋹�qqqqqqqqqp鮫4ȣ]Af?JJyB?<O=j3[ѽS}wB/MeSB?C?; }F?=!;=t6w0|-lFgbfn3Os:{,nΉ~G[IԻ~l[ hjE~O9чS}n,9C)ѻ~}5whΆ|�Pëz'gu/OӢ/<g}2S' UI Ӡ: x/h͆#Њ9 1qQ(V;9HˌGUIЯM6=Bؿ+hS_y%o~Po{p17;&)"@IY_dq OEƛ;55aE s^o}DW;v4-3ZZA7߼рFH4΄Vչ@ >礧B{]n5K -24hpuhWb$Zh KwV5EDs�mt {qj:tѧ6M:=nPR[hËEo[:(1Lޞ6ͩbg89~ bhĜ/)oz[=m::!0AuM0ف9DGўsXDbeO}{eMO0sni?uS=j6hvo?IMv 3<Kh? 3y@Jѷ9Z9'7!Ѹ2Gٻqh9N[WWUʹq%ј:M.0[jC]-'Cso}R;Wf m#BjT>-6U?} AGApѱp-:ڌ Вz&Ec f[Ж^nBc^cǑ-jxk%jtE`r H|}=oAr\m3Uy٨/lܴX(fI (3z%?k Ofl5<0Zj/}f;OmQ/P$lQOX\@_׌F ztV4.޼jS@'1ǣonl9}B3[.MI4Nkv+EQ3} ;P#^,d@}8 1hEfB/L^=|^$ 0B/ˉ!4YE_{KυKk`2.m@,4ti!f[j*ܙqqqqqqqqqqzhk+mab;)ỵT)܃21{�}1A?]r t^ՠ,S< |*˗l<a&A'fthSM\0lNŶАyļYAh|*n4bZCSw(:`-}<Z xɍ'@P}FwR@7Rvm oz=={OAl;cC}14dC< ІmM4lj[7̾@xZgE87akDhVnm1?uc}1(6}fc40vˠno:U EO�MCp9ٯi_\ ~ 'FG5�ުl_~1Z4Qh|vXQhӜрJX4f􏇎=}v-h5UWţa6qD<1P4o =2;m=&9vMo.Ao/Ѿ7BoҢM| Z7Ǣ0#0ϋv& ":Ќ]X453;Mi Uy#9%zgIsR -Ĝљ; Fnؠ6>5C4fGШGF8}WWǘӢy9)anˇ =h;z6[hФl95:lakC83~79>_46&.:,YGp =kf> {ΌǠX}#4Մ+^q64C-Q O-5YX̫6Ntw=f^Әl,zن(6?ZxGlbXI[xi̱he&2;R#n2%=:^H]ko,y4mah"Ml^zcj:{@/'^z W7}Kv 3:܍kAg6[پiqψNlFc,fO2wRf6^LlVn4/i+ggv)0bKb. >.atihDJfaMti(fVХmhy@zqqqqqqqqqW_M⮩4ſp7ԝ<qS-]CGz0@)&~zЃK[󓮾ՠ.}:3BI')Ic9OZh%::Z'ӠӪǠeN6O84`cs $i;9 ~mh4ѱ14zC!3%}jKhRE-�ާ@>Df nz}.-z3tк92 stæDSMǣ!>>L [F87a?j_LA8v$hy'41mCws6_�-XZ<IcfEJϟ?IЯ#џ;k[T�Ǟz_�ف&W%,[r?LMߪ([UVoC4W6 Oٮ~3ˆ!h� -b m$IЮkbјьI>Ĉ}h5UWţav&t?ی΀8h0=\;4{2:~^4vеKIрAoҢM| Z7ǢP0#ΫP6 &Bw(PGvu,dsiEC1Y@Ϛͱ=,zNQ|>U4Įu0Z`fB pV5x*dĠ1M5 lQʮ V4F_]!^nǚl[o}uZ讌j`ǠQ6)?8-:ƌW0pbE & N*�m=БfVZScXrJS]%ڥG}:7SXw[*m DG=CBЦz$h@ hc#E8zeXͳ>p =f^ӘF}j!h~{}m=$dzVTA/ɾVЍ2;ѧ$(ڢ^Hk }EfrZhJ3 guQ?z9AMl^#z:8OK5oS7}>f1$fO leG'3ϳ=֌kGqdX= wRf@=be6!*;GA2 :7Ya{OL<mC1wE(e3 GM-ѥХ}0.MD-o/f]qqqqqqqqqq7/=8Џ #PIjK-b}ߦʘ;\ >Mdg1W~I|ft&̵,f -|6=Etf4S'C+=snr%xMޡ `}N 4:={h\ff =h*.)Z7ӠwF&ۅ&03ʦD=АنVs*>[q*&ax"1+fݰӠqsZ},,/F/>7z2h�zƺ3У_̵_<�DN2@.zWG7Gh\W fџ544Cxe%O~K~}~1Aסp4hƯCU1st gCiюk,huIѮkp:Fӭi]Jx4f4xc1Xؙ͉SҨM2ls*S7DoUTb#%8fLjhs>Et t9'3׌F͌f4̵gdl=Dϒ jy4׌>]6}4hlaCh//ȎAfi5 9Ž1Fh폾B=>eNjWVzj,+z51p(3 cSWUa*mRWD":Dt*Hs~'E=, s.x] Ƙ}{@:з@@Pz4W[ƽWk-j͌Vvk*m5KlO7|vkyMc>4k^1QȌ }dm*n^'zѣbABZ+Mi@/avz9A Ml]lmcׅ^z W7}KvsZt";LlFaf.cGg0q<fZt&g9ѬL.t^1 :Yb;v ^D /- 4B^ Ba]FhN#=<ҡ4ȍ|L/lf888888888~a=8Џu YAoӃ}_A B7i/MOdԆ>�]�Msm>މΨ~I|ft&̵,f }Y }بyjaEbq>_{+:{> ~wl+]J=Zf;дQKo#?~a-RchBU[Uz`TΩFd"n.t.6\SIhȬ�Cl!<ԊφmhĬqnE+7OqhiGkO@HG\}aG'(f4%л0օ k-6َgf o3FdrE6f{X3џ13ofo=U3~r,}"BDѣOlx۱J.y5!4~jsNKm]hu%gJsc((EhUkd3::ThZEGlx'ؙ̉&hitz9 ̀l6Co6uMZ4ޤ@+j6՛m,Z ȍj΀LB.IތD; a7)UCѨb4:~v*Fӡg)fyfUGA5 z6A;iEJ6hmh=#@dB{zи9Mʎ0 9 A|95z {vي+}W^[tWZռZF[4N.TMN BcjJp(3 *+Q>m<qhH6WFh]= 6Ѧ�2PG{!{zYlf,/1'DgLh+Ԃ Cwњh}6$h`FW^kDlZk2t˶-hh5Vc>m_#tOns;ˌr;u%�5h*MP׊@ԥ- 48{F/_\)zu^.a^.}dCc΃v5)АڎA'!j͍U5Ί^SQvh׫1uR2DgX= %bD1Oǡ>] 1vs%" ݳKǢ˘> EB@ڮtiLtc\Gnj%+&7]qqqqqqqqqq#p!rd}uaؘy@W~zrb5,; ϕ0OV_df3: DC;\Aݽ'zk0_>hS18>)5xʍ_mЇ*$:U u!O힞vm6!W5.fZ7E Ã!C=АS%{ц6q;y ۍ>U4ha{asmh-DՎφ>#>Q8cшك}Ý-hn =?Sջ'b>hgC /߽$Zx'Gca ?2?#ZЯZˣil,�s-h,:}/f fDVȓiПdT nAEo`tht4lCшj4fCClz-Dlosh3e@fo@{< Ղ0Me3::h āF F3_n`SҠE[@o37UmMٛ6:ћ ;&Go&>;F*Eo$F1-Cb= >Жkfm&=?͌16)ѶB^S)z6KTѳdhNEϓ= Cg>ѳIgF*<miѺy<[a%Acf4l1B́h^qi1?|\)BNŚ<jEѫ㍩Z>{*UUBv}dK4hLJ6D+)jiA_Hs;}6,6Кk&ֵ@ZeCK/h SEf*nΉV8Z\І`DCm3TkS +B}}D=ZJ raә ^ŢYдf7zѢ^ܦR4zѢN MlF #}sMoGDCl7$f/sSS=^>hΜЌǣSC7ՠM6GB0Pt)42B#G96WLn}.#>b8tYsYcK{ѥ]!T5ݱ �ns^qqqqqqqqqq\J{xa|Q-N2݁#jS?( #OUF\E'X,A/_ʙO]8Es%h%IɂAgR9O 2)' _{Vm/j)٘D}R4`чxʍ_m~C-ܢew}@wg}@hѻYc+usYN F-hBW?DRu цLmuBw 3}fhLΎPCh-D>Ҏͻg 4QͣшvB7ɵCVs"t:Zx՛Dxn^֙˜.4p$h,ßSկN<Fg2B܆K6t>Y.o[т1m ?Nj2/]oooqflEc3sZz zֱ~-p13 U1ZNǣAr$Tӣ-R{u噒t1+ǯmϔkF{._26W+ch=əkFBsAh4&Bo%`r4rU zݾmdiPɵЖmfcNfcU_UU%Go1y<g'FM4<[Qף7Ri2=}I1#qh!6h9g8rM0znEQpt73ڡF،D٩ѳhXMAj*lz,SgjzcGjDQJ. 1ah<-ps S;1f!Ps(Ta|95Sf cXs4N^hl95:Ҍ3; Jtd)AT]jJ+mU[n� SHBths͐:}6|fcf4g>Кz] mrAh mo]cyBjaSEj=a -lGkj;zUxrъB+j75l KBk2y}ݛ5ۼ\ =Ln4ٹWGF&@Ԅhy]ESx4k8aQ/QB1jmQS1B5CS^hr3^!h/u4@S!Цڅs}dtfעR'DNkv-8tjclQ G3u0<lFb^hx~myKE܊.fnC%]|'@tiB_آV>!_EQ% b -.48888888888~.v09]:c[lVsϾWz\#bvK n2K6-ET~,~G?<l<aNڶsQ3*z*GhlRSnR~`NnS0hTlC"Xc臇p^ּ2N ^ z`E;# q(?=*GPtЦ9-dgTlu M 0zH?>_(lAAѰ%yw>]e[-+/f2I ݱicYA Otۤ>;'\ YAh&Bcɣh޲S_Ah6a΅ AsB _Vth _:j._-Dhmt Z跄h}tw>g1af9F~}  0T6ݰ߀xL]aC G8t8G#[9 ѯ!3'AWhcm3ӣ09򌶚YDh]>EۮCcfǢuaۨMoo6vh\WѢ7hT(6D80S1sZ z>G-|`s&t7hh;;lq8-za =ks=Ѷ%BD;UgC~/EN1׆2BY"gIs :lrQJ6Th<c6 gAVtقطi;L@V!hhlw11(:Ҝ=!xَ CvQ @~MJ^I Z6ӡ lZ1ѢasJ󅍘#9&_]3 9FWBfFңАD6[:ۅ�{ Ms ʶˡ?hyMiv'k0_481)^3Z)ܖ}=MfF/ctf 2;ڟD/=Ѥfo䇦6LV4<n Mo&AhtB'1#R<:B/{aNi&Zef6bCg0pe9FkAg60t~xtseЅ ]N.j>b. >..3Outi-4uu6Ғ853qqqqqqqqqq=+aj>uǦ2L5.^鱏Ѿ=dPW~g=r~c1?@a) htz5fІCKM:Phs> yMAxLbV'U_�D~ GO!�A?GZ9M0gFz4Tѧu/죤~Ȥ蝑F{&d(®}lj+eh<H//̻]{0&~!BC泺C_z[' ͺn>ہS /hUFw7 vsLB??[QhDBl^hI΂;ЊfS{48`a4LcŢ!h{ 4/xзVGZ_t sxeD+[2::xM̧D;e#9Znj1A룻 <h9F~ �h3ݲ߀ʣ?fV4~$�əfFklo4\sm5c3@ԄW;dVp\J6;G#h+9P1 N>}QoxB1aS-TƊ.\G c:ݸߦvhS%DoތA[FMDE_L =-Vn·Fu;5&E[aM͜г6*HIf=kDfQhz>G5 zz)AR58ڃ\-9=mIѳ�=Aό3SaI6 Qs4%BcV4B:&WЫ 44;XݫAv95zP$hpQӡv4WFj*]hO z-dhơ%9b4lF_;6bD/_Eؘ`{eUV"@[ik+hBf= rvʶO46Xq }}}m B>F;kJs�Z.ܔ¯P^Gыh:^zIshE\D}Ax͞Sofϗ mQ'0[h\mQQu4Ft"3^(yau23^Рu¨~iE'5EtrD yg6dE/KYͰ:L-FA"q2dpԏvM5.&S@n?tiMKBѥХRZ�N5TCFig|A ݲۿWnj%bB=488888888888zTDW~�27?6=8Nf�}˰Zn6ՠ\{م͹OJ6|Ab?rThlM 3E woAKnw1?#f%7:%{@fπ޵ 4ǣ+4.fՁnz ]*d>9{FwJN5i; ͣ zg4,&d aUO ! SrDK:sLn6tvh_aŜlu3>aNΨ?qntLn7ׄ71 "\zadfC?'C$@ÍAXJiǠh9)ZvSa[<bCoýka>55[h۪~KF~K6U~s63v-d*5 fDZshȜ}  ,ˢ?kEvHM;ӯvs*-n-Jfͥx/-t)t6׀~ /c1: ڇMLDǰѾЦ1l7vC{#vXf4dNV?{lF)cL[fAB/hmٌM:-zF#z_mςгl(3A8M=ˀ4h>ݱ)гDh<c /X@=Jn0,@/EѮfF5g'`Wޝ\h=E=Vh|c6jrU9>SW$ub ɆvFh̜ =|f>!tn7,py?)ZaAo_36we6ì-o91S -$t3Lvs 6gC/zgC )i$leSic^[4s蛾fǶG73leS,4iq?gFt�:ao.f4C Ѧ9Ԭs$:ܳc:;Yt&shDf*tV3CS A?x`ch]<MѥMCKs7J�ZݢK3dv{yqB2wZX҆N]qqqqqqqqqqqMsڈsEtpN}m{cW1'@R?==f�}˨ GO]N=Tm54n>hΦnNj#B 5}dM~_ 0toA}1?#Tb~w郁8:%{<x֬uz4^-%9p˯$cnC ZW'` ׯ蝒S*Z^ը9Mhd @sRêFN4dNfvA~B~B;gAlZ{%%Z9<S!~zF&bqEjBw@ܙCИL@E5@+adTPe `~"DCAjy bvGmQ�s(:9`El6[2::mWūGus�VeUQDsm ?I#|<P+ߠҠ yР -ZqI ?6͹з�;4؂dڶ۞e1Em>2h셶a~ŬP<tcӡ7ѰzE_NvN+hiNv#=ÎG53׺ nwڅv57ׄT@3�;lF.@h!}9=m<ZТK @VtY^R֍F? ڢfhi:<-zF\Sgm(,9гhgгg=M=eBwlr4rAehyCs4 >cɃz}jZ1 &[mL#pGS3$/E#nF@C4hǠǘmj叆5eW5N^ ; z5N^!Ю6f6hӼ27l 9}B膽f!ho頶CiEThLKk%̜4#ht@/.FӘ9Vz5-3j}=ы>g)vbeyhJo ]뽐칪GmMo\#)~/xt48s<̌}\K;;B/Ii $G3{5:SǢ5v&#94{%vV3Dg�t~3B0Cjot0E4j u'YcO-ѥm\#.ti-/!K3 D(M'no!݃888888888888Aŷ}merYEW @f}_|^ }ZgTn3> `J}h :ف>xVAJц4?[͇Kgpw stwxIE. Z8+>B�ΆC6t .mswJ>h\%5ѵekE]iEƣs64fv!s4GѠmiC??Ӡw�إv )lBXͧϠB[K3 QDwtS5t7΅)πy3E?;F`4nNF-l9]n~{Kߒtbh~+nNeUP*2V3!s*:^r8hΆB<hHG 5GCnA%@;@;iK8:Mn' Jh\w2X3usM%mh6Ao*DZ̗ƠlFEӠe:: =~f4̦AClN5fB8jE;t<S@f"8mdh(S 1h،#FsΎ1 VsG&!z:,>KRlP1s 5;6z6̞CѦ~4`v.hL1fa1AxiИy z6C$h<)IӘ+Gwohfttf414G)_4>JOmWDh.Z+5z5 vuA̱hӼ2Y ێ>8h%68mi4ى^,Q0΋6uWТ:t6BAЋ@tMtxjI1W^q3%^-jv3-A;ա LhtMAodc2Әh{8g[.f @'5E0d5E:Y/bG@1L 0GfY=Xz`6SA/.a�];]:{Ptio[ 4 fCR)otib@!fE>6b f88888888888y{*MaZ3m}cS`v˫!ѥ᰹V?Fq[~+h>}v3>40M}f߻љ64xAP?hCﻲ~KѻS26;Nj8%Վ>Qt2.=:{: {-h|wJ>hlGӫA]-]+څfрC 3m64feӠpφ9-Z M~6MG zoE ;$" YNBи\3&#ˀ s[$g LF̣ώzv1huB4nNF<Z "ǢߒAcooк6NnUY22V3׊VK.#!=MPȷNFG;ng+XüQGޚsg=,H52V ۭ.v Vn6(Sc~ueuڥ&Bh.\u4:mSe:: AzV׎DhЈ&%�mE;(C=j١G6r:0gA[_� =z=`vƢ!236`BX :{"hMM=@tY{ iFгKahI%Bd95z6Ct(,Z]64׏U] i T<C1jޙftjNcs%h jFw_CIQu)ϒ(^Ƣzف١-5N^hE^'BcUVjjecumA^&zMnVgw78|QShIF/an"ыŀ0^FG_h;;'6u=ڦ·>uFD_4ky�sSE+I ]@t]X k6ujF[!h6t1U4Agi~:TШ:U1u:4X;!QlyhC h]mA0Xә̝4G3Ojke13D/!/z)J/VO1*t<R>.p!ti 4D]J2 ,',ZvA qqqqqqqqqqqqу9B3l+Cf}XU}E1~n=.>\}12mG?胂6ͥ_C_3x-胂>hռoׯpCmy:Z5׃ tAH4dN]E9-{hN;Qjs4Vv4Q3j!sZ4sp3ј95Z[ Afb'68] |0whݼԗaxռy4?+T2t :ň<a@?hxр8 Af4lE7gFl{s87Ӣ. tö vsoCc02-DI4r2hyd=hѺ9lA&M)ZCoXB7Tf}[;--|HŜ i2zh9aѷ S7VրxhDb荒lxr7DoHv6Z7Om#2BKcElulZgC jcCClk_hs|(GOt=h-ǡMstYBf"cА ǣAf6!m,ZX1hȌm8 T6^Ŝѳ gn65z6@GRڼ;f=˂6X4gѳLQfxA6z>ACѠٱ@hMusB(՜=ܲQ3c3 ^\-fAO�m5g":^FA2[ѫzGDClt>:'z^Ku"4^I6&9Qz@ҢWQek*s^YE/{4b)aC TSBAۢ2?D=_ǡ~ }fK)FSoڦ^fG!tӲJ447:f;zjfzAN`$4Df  $<M{:hMfB4&z1_xUvi"],rfYR Zf6SAvy,`Ru8S7eYj0 14 CvYТvsԚQo1sqqqqqqqqqqqqsN<>>ByjPd}X|=�= 6+{]Hݘ~CP?_ wܣ >TъΩ{-xt35>h zԜ O>| Z%JԎjѻv:zՁ#lN]\@sZ貎Fc�g@ƣF͑htw0Ze;HϸقĕÜ13ZGf_4n&V(Ȋ M678Im%mB;g_^H̓4_H͝/zg}^&0q61ZFd{6Fwf\0! 'Aw'vbi02VmZYun·_:֎6oJ%зբձͅ(x:`{- :DߢhɇnAo翿%Yngm/C#f }{-h] Ж[xނ荁&Z h8!z65?y&Co&#v6 Gب.ԩ1hN ;mWSuvպB{Su__mhs| F ;{Hm%:,3 1hm|>G y3Vv}CQhȌcͧ0xHQӛ+F4hMIlbl6;vAh4eAǛMLj,W3Z*|NՎ'Fdתv-l4bGQs3}Rh=m13m3?~̉Lf BcW�GoJϽwbkLj2^ GChjЦz\C6#ZV/N-:<T"Kɼ|Rp�cSc6XtfZVch!;Otcd�H4م>eW5F? 蛦RhU O-5;6n*kt&S/%rvDv…)2VČDf AcTfFSD'4{,8tJ3BfAhMtz3=:ـ/&^-/\A"{atyuzY, /zY ̐:]<] eID6kɠe{R [L7YHf]E3Ze)h1!4qqqqqqqqqqqqǕAƯ (L 5n*m ҈ceF| B?{Uϧ-sb>"hf >z{BnwDGچcWCN;C{bE3w�:~yjE̵$ܧfzN zkG# hрٻ w$h!\hRaAf|ԯny.4`>e7Ps !zx>.Ya~Ѣ6?kf<OnA?[ ; aa{u2Fl!BР5;Z\h"5n~5N@ɡ]ff}{kGoo%зCwB&loQnMz{A̩ЛK[-SYF۷ FNvЖ[yѦٍY&{c4u[iN~#A3\JCKc#[Ĝ-CK%Z[!ھs1OVX mZ<AcѮ-F}%fCCYZ OSh}cDh!,9f+ZgGx3%Zs%hm;0vF&I@ٌ΁nشf1 ĊaS~p-ZoRO-8TnlC,2cA\#n>9|.8}G,^(zYI0pj)VmRmUZ9ڽ�z}yѫ2c46K� SW' Wh=mu>B63%ie)m5_9 �MfJc59챦iД->E4ɦASsQ $ MovB'0;؝:CCߔhk; @'2:C/FONh١h֜ :;ɬq>|f=|^nܲmhW, І'@1BC3p?ߌO ].m$ih1-s`>!I-6kf888888888888=ȕ0=x,b4 B?>W`C}Kiķo�t9WC_7x<oE|t_ݞgA7lTw4s>RgpxqkD^ >zjGCj ?W9[ a&F3w;{ؙ>}ngFNЁǰwZߐ園M: ;hĜ јf4jgSL44vOqI0u(ZBnR4YFco~h[6ӡ/@/Zf#Ekt3 bAksmiԞhlE76̜=@CTZZŷ:"-vjN<h190ˌuNf }{{kGoї/v /ڮNjh[ݫmB ֏5П/)mIfug)T�1j2 ΎVu4ڢ6Nt7n륎G0օ[/4B7af4 EoT*!Z-Zw&2v`S/'mUu>ŦB['{,gZ~9{,ڹỤn84dfh}igY8ڸ6 y*cs h]M7њz<ZfgBkl\Ӡg3LMFVu4z^15ՓC7lZlV =,0+7ꏧt<cNlBlaq3Zr6 JV>Tvj1?4UamA;(t˶? .pw} G/ˣ`S+rme'EѪ|Hz*ZhPЫ .^Še2 O^Š{^hZy?%hIݟ5U< ZaBVYM@3FVBi,T7єfSIVvv:-W=Mlv'^Q.48ahzsB0m{4fwkY}!t"k/Tf-GQ ѐ: A&<Oek/t.<yiF4oF_ɧ6?8 xh^%ꉠU-]5I->e.b'&7]qqqqqqqqqqqq=\*a&~ВxRf>H}3ߊ91ߐͷKͷ ݰkm@7Z͇)lX}[Nx>z{FءfEaL蝂V١Tj1; =fyҚwمSwZhhHIh); =Ѩb4ni 5'`Kڍvъ9ra&F?{Ȍ>CCMN B~FA/J4h9=_ru sCـD�tN%sMhlzN@\ff}>Pڎo'] $-zoGoںZ %=a?K=fN8ПBGo&ތBѦنa,~IGK6ntgaV72M*%Z; -ui 2#Lhu,h@kc+Dp}ͥhvh\ZgUlap}I菅G Dwh<D,ͧlI qhFX:,3/dhfa5DNl>ʢ?hM|D6ٌfзh̜Z)asQNy?[v|YX�<ph3<}fZ'R�m3Ǡh!fݼhsbJB|PdzNvM48Ԍệ=֜vGg/;$=ٽCEЫ>bQvJ* ,^E C�n�]h3^OђYCp1.4f^ӛ5)tw8 VJu@5D/,hb3aS<�f'Z f0B'1GCicV+gыfNkыfNmNNny:z1 ^lf>,s30O�m̧gv8t1s4xh XDKBХ}Fu~܅.Ժhu:z8888888888888Εf5APiD?)}{<WhUJofe1<{5.66t>3c'@d2 3zϦ/AgR\Q;:t7;C}nG7}Q$uyN h~4Ի f:zGF;:}"JNh<'@+f@ |='Q@<жM>CշCB7r_FqhNoUjhyřѺYG }hn�X藗J8_p l m3wlN="|UHZR;HZ]f}>Pڊvg�} :Wufp޸\ iћuڹ.޴ucoKvu2Ɖ̟nME_@oƠ+;z>s7نӝ1"]&'CdɌ zYXA/A~J:fE<hekM}{˂VbۚП}TjΎ}m7ϟ?zJ.v&V͟gKC_N-vt {4cÃÙ:ڦ@)c тv84jv?ʙ(:^ܢq2:B?-eg;TV^<hZM?), ѫJ~F͹&B3,-u0ǘMl5yZC 0[gf`=ʇ<Y4F a3ǠW?rNd?N^G;nNj?`h7; F,z |G*ݪ t78;zJ&0K )Ѐzet>ۆh26шZ%VTfM ;-n ̊f@b%JE xή zhFӠlb3awS<�BjrKM70;َu:Nc u b6>kblQ/FS1b$:9 :D"Щɰ{:TBg247W^h0+YRO }a/&>n�ZAǣ[ElFb7M.MrE [4SK2w$zqqqqqqqqqqqqqqX_/?WBe+V-7R!|/ubpܡ~E-x g*X90K(sAZnk5{swDSwھ},ּսw{34׉h1Tѽy +bׁ>L}DgaK顑w4=Y1O >MK^~Ј9$͕{I\zL3EqThZL-Ccg\5n=kFZg>ݍ3~f!&=ʣYEiFj5ϗnv:Ɖ\z@~ $z39F*b2߳qaF[hمF:ѣ'R:ZvRAchcѣ؄hN<O0�63Z] z8V=/G:BD0l/3hE7qfo�dujގ5 sl8jT*́XzvɆ{,7׋F�[E ჆жM{5n΅nXE>'h|f+|ddnA[mhcQjV.X̞iuGJk1i&Df}`>k|>04׍F�ZD KA@ R+ ݰ?|`]4UR4YX A74 ^xיѠ_"6pA=ִ/^+1ӠCV4Y,Z>}m,i^0KEm7׆nĽ`GkC{] Ş"Ɏ{GLgN`vC0;نX:6_קnn0NgG_+hӬk>:ьCy0z1 #9zn6؋`t 3:YǢse -枽@{Gq^L }A6G5tas[(-].mbiBv*YТV8U]ed�4'=h88888888888888zI*{_'$? TJ5ti&=˺ZG +B>,}uѩΌ~~~62p8>+61<]w΢ջ=:A^^>zC咣ht:nLYлz!>G/B\TY@NN{<^qiP#gb&F_~@!t׋\bs,$dhn՚/A$ d =MWAcg9M!7$j2&4;v7"]ݲ1nGWǠQt}D߂nv[WbCoP'G#oom@57 h';!z3=f@^ $zcGo6#v4#]TEn}thYGcA(puCΆ -%ZX;ڲ>z hE]gQ zKF:DQgF V#9+@G9¦z%,ic$z3[7zǚ>3~ ?jqvmsuqcyE^hL�=dEpSPǠa61zdC O4/vkArЭZжUB9ف^Vh,ѳ(4M׍F>y� fqI=>|b0f4m_+ ߨfg<bE&\!yOy9ȧL`>]jQ '^9\uEhJ+N^4@kjB(t38WP-zQ-4zy1clr4lٶ@l i>k:΂k'Z:'}mL^G5mGwњ88ZبK-TW1׆2hR]MdhrͥtgUEneNyOB$d: SݯEONFMm@̼GvnhLi G5t2^ģ"ll#љzBh1b6^,h|`t&tisZLpѥ`ѥ}T)�- ti$4 [FBЅU4I4qqqqqqqqqqqqqqWG]orEUI}Rj>(}U= 3wch|AOarpݬU s>}umѦW3{JEN!(tτ6;{rZVtJn]$fYح\|Իىγ@tнaE`?+iƠl<}!7lZe֦z/9ZA^/97O/m1Klۋ<gĬeA;-gGh1A ZLݍ6kA#јy[{h_}[.ޜj*convZύ.}H*i� tW>&s7@8R=[m7##SH 6ooѸ^@l;ZC ?>_Gwhm>FwgGO4hْWC/췤h`ig3;#0|9 VVeXI9ж.h`w�mgӣgCϴƣ!8hᵢulu4@<=,84dәͧN?4ݑvb#Єy;1hv|>Q: \JL1hEiАgw Q:j$:D"ї-јl;b{H&2[Q .4BGXwp}fϕΉڲ{\-+l;+YXalfa5v4ή : ]dpf+{kы ?1:91:?:ًv#3Of!IDhAyC_KHBl-DeЋ(hY�{$:|EYb/ѥz1)FKʖB0].m @A]X8Еř@s 88888888888888bzx۹"w_boT&WD$ojTU;~+m˪yq}9%2nЇp}]sm!W68mߗ6л&kjOtٍwe {>bGUy :: yԻ]$Tىδ@Zss_t٪N~~ȳ(tL?Pк@JM6V kIg9y*-zsVj1,D_n m7Bԅv[v3ΎogGS=bz8O T3;Thun4-̧*B߶>{^ԣo`5h5ݩ7}u7!ZBomӣjѷYAlJ4@?dAb>EfaS!:m<b&Chَ9�-ËOkzݱӢZ3},9̳ QIE-跬h`[Bl@tXr] ZWZ:-؁v$%:$t 5v43% 4&F(;'ZL-b<5j@5lj+4lpР gENwنFdg Of*,=<S;6g` R'Ӣ!3Ѡw&6^d2D{OfT[3ڡ&2{=Nu>tїSh*/h@ GKMUWpOEM~hHܨAC2 a10jt>M3fJ4: wУm :G/B<E/ B'1'F13:aӠ=zsIgԕs탆SD'5uvZsU__KԼjvm{R7Rz A':TkZ qL\DΟںK$2˘"]J<C "ZhQ1Zh#K&].M@fjhK# ǝ,D7jQ-i! qqqqqqqqqqqqqqU>oR%dx=Z7<[s _Q5ׇVAgwG3lU**hAQ(:?4/-6G'z9 ϊFA}_Ysh9bMgb{>'~>EةB?ѣS'~V C_^R!a%jD7S_AE_|/2%7?f_dD[=[P4T^a E�z[zfTՠ7hѣm7ZTHh1m as.Codu7V1׈[-;gCf{aƨh N6X 0#?љ؞fPeАW1^{黒|BcfG%hԫCSA#Ǡe8f0tsecEϼ gJ8zHG8;yЉЬqtAf*rv>~׹TZUv.4f,ޡMz{F<*Bό.΍O#h^+4 {897D/th<ј9z!?xQ|Mu>Ng_6 cKsn3ZPܣ;9V3kՇ^*hȜ> ZW df[G7tf B7G3/WЫ:{%5F_7z-G ZHbD(ff-h<M4Ξ"gئ}<ú7FY "t23^ә)'�}E'D'4ekM4ObcJt#NxOCfDe^3J7}zLb1h!y)Y<] Muh @2E0^L| ܮtik_�4UB];v}6}ykudtiw?O7E88888888888888Ze<mZ=:_[/wWW}U頩8 _ئYG+i@lN~zϩF*B&C9ڋ8ׄljL΢~+:ٮB'~->?;\$6C8K%- u/Фj^^Rq:@Ei[ziEo7D7öLj-:EGs7h!3ekImch؜ 4+.Mv5N<N}B荙pChMF6zTSr Y=Oԩ?8rSGw5N5c-rh]GZeO-Ց;1ZO=PtsecBϤ| Kg3Hmt|Әv;^yg{c=Oy_hs[*;Z84@6G[ɒZ==hgzCzm 4tp=O6ͺ<m܍VЊ>"-ǣE 4@fݲIYsXСiDnG/$?4nΨs(nEݳMbSri:&w퇖kЗ3xm `04d͇^h>r郦3#UN*-ޝ WЫ:{%VH% h1gMoXC'0NAquhT=EަhThXР: rtf�A'4SO4:N6)a0REl ?p9'NMv5vz}U__yrtgѶG 'Ǝ.$2/.cZԈHtYr$Ebh1IAM-LtS]ZŴхuHY [TnOoʁ|Х)M<Q4qqqqqqqqqqqqqqq7#O*w�Ǫ_ vwNKef_'Fׄj#. q e>(:NA1orKF4h@ F#ht.eyϓC?@c?O,Y //i)/ Fh>9n>hѦnfDbhݜn=U Т(Z]hѣqv:iAhB \7l *=7 D%3 nzEcf{14*MbF0 m3ߋQw%Zg1CE  g ar692 ݱSg Cϴ*zHG`hNaиCK#4s.Ō;εrmfn΁=І9Z7chlI@f.MʦGfECh%4hVhȬKAOA6d6*4B/ҜhjV7m^SQo5fZtjBkwl<VY̳x^7EfJ4buчkFjUWA Wʁ( WգuJJ^ 5W#љ (,3:hV^4bz1A4@h\'f/~tޙءhhqF/HI{Nm=K"#uς`Fl%l<؎FкylY J7}TN1:ـǠK}7աe6@2_Rwi_tYs9]Z,"Х]0Z]ک.sK @8=K tgfZ 0w*~0̢~3qqqqqqqqqqqqqqqq?fOsݿ}V�ժ*}YwPsE}`_<UATU3G]Ձ>VB`\0}ۿf}tE Y1ǣ_ң14Q(tNN8mIz`Eݯ$K$-:ɺ~֛ z 3gڦNv5P>ϦFi|*6ѧ[}neDFˀ6^V th[P =ݽ:0D'X0z̡hTMv+Go rZeP{2V/ y,{~1#D`'w gDX4J-f])7mC <C@hmIѳ6 ?i3ݏEmBLo TOM!Nٍ慄KnG[mU,!'F;GIрYE#g`hМ I 4v4MfῦQGsg0�Jotwlp>48ϋ҉&4D7f_{ynḾh}B3)ٲ8dv zm<L111V4͈U7ѽz/ڽ_ zuIV{15-PG D-3ǠsP8:aCf*tYѩ(z1FabF؋ h #ygRőm YNL6 I}KE :Y_ԓD~ AGhBLbS3q5˜^�-n sA0E1+l}3 1׃ptay]،oPtir4 \Dh!tti-H='4Ύ.C=͒RMՓ'8888888888888888̥M'k+A죂*i42 &ACC5:()f�]mG`t9f} 5ņus4:3׌FQLISӲ'~nD_ D?'Db?O<]l8кy h\ygٌE'@ћAh\?0F#.uTƷ;_gmeѝ-ho OxMi\'EA%b;>^߫Fl@l*݌D; =KO=E4-c ;>4̜M =SX {h"3  =?eSMs z %>}9аمfs3>7mT ݏz)Ю,ڵ.1E sz`莝nm3imfݱ<頗N4�mnЩ0z6e o4 cjCKIF"ZB'0#{GǎAgZ7C/a#QjWգuOF{J ,@3:! ;LjC5Om_ SB GIHtb3^Hšӛ=]t39:lǡs)̞h q@tF׾27KUV3̓D2Kpt9 }S%/ElKQ{KBѥm Evh!n@vi`ՙ.K˚bTAh")988888888888888883K#B.Zc Si;9i;ꣂ=P>]}D۟C;4ъ.ž G^*C+Cd}8x_'<lJtFȀ=Es tj3Cg{$G?_JNǎG[)y'6?::'gtIo |վAf t?-bMmshB7_QmϕEwf}57Nyy;}nkQS;rlC'lMUDxJfM G+nB4B7n+z`}`І:_ v4Do3EoˡmfETTd>gYhpjg4=2Z=&zf�ђz~*DC-SUQ/1c菚Ym@sz^ђDϓ]-`sh8hgBBcf}aEٔ&3|NMу�tqYtsPpSgA/Yh~;΂^xM1&7CX2?zAAV ^Kd GAҫZ>R @gqhCFW Ы6]PG Pܣ[v9:y`DTSXBf*tV3':ԣi2%5M{F!lA/̌,:lǡs)̄|fO7:YSk4YZBj OV(fH7BKl K9Aե'Q"]{A ]*gKC <yi\eO1+b&إ!!MqqqqqqqqqqqqqqqqqqxOO'`գ?9jh֮>V*uRNu$n>h_:̧jC) 3Agd0hņus4: љϞϧɡ/ѣ-G9 y?3ڶyJѶ]ZF'b;-f'z+}6o 35na~ Cga+df]Bo simAoP>TF?I،UshneLݱyФf=;SgQhQ=_6txN4fif]C;̔hgCFލbI.w�=ψ=[F7'p=0ׇ>',-nҽ fT'v;v 4fѨGcǍg6=m&4_0mCӛӣաaG|hizY9(ݰˡAeEZ zA&7HNaNNbF;\yudHz-L^B;?zmR&^&^ buv^MݱWZS@!�|K<MsAXtz4&{豻G@̑<iUψf&D3Ǡ :99Tft^q ziV7}y)Mu-n*F/&AtiV-].-@g*0͗z)fj88888888888888888Iut<'NEE?9\YjHu蠥kRBQjAnk@2t^:d{3Dbш9# ˬmHݜ|.:!bmW"B4!;QDj.DdֆNn̛/ZF7DAoG'P?B%K't?D7Y2%Q#mAo@Eo'fEwǥ6+k GzݱbthZfjӬِVqVmZdFkC(?deK*4`;5NhFV񵽻\%kDhBCB` {v݌?։vSh}>ۉ'Crںa2'3k ;H3, %7,WȔuGt颻oѝG2y0^ݼ'苌wSFߪ/ǻ~wV\./~5dzg^>Gע#?^~+: 9Rf{7wF߳~;DD߿mn/'>L<ADo/G O-㣔Zv!a,?We=$:SRP'[蹓au_7EEw/ѓ'Uݮ.!U_yGwl#IeDWEFWv|N{$zWE?]%gwEW=щĢQHȮG_\g}MD٩ңcS^,;HtҺ"ٵjD. Oײ>7WFuں^ܫ#f������������������Jr?fK26:z[;KWoeDjik"ѻ,7WS7:U6ih5;{S`9GG[cʎ7r,٢GǮe| /E7=<}/ngg6;{Fo Wt<z]SJu`7湢W ji^Mu+yUĭn)g<.zy=QswE6]Uї]0 E8zqTZ"a[3ыZч zM-jEEM}oE$:6?\4ŢO޲ZtJ<]%hfonN蟋Ϟ&9lџɣOz݇Esn1rnOs >GO}nѧ˙]FǚcEG#Mi9}9FginG/ ^~+:=}nGWPt3S7wc*~>s0o??֤n7}.'O?W%E艛?-ߏvoEsݕ/Dϸ{JFlAS?=kE =*Ú47E׳5?D߳5ݢPBt,}OdtgSލάyTt^ԙԅ*[vU՚zvں\ܩf�����������������mOk$%ODv9WojWwgɢDwYGoW i]1ћv9{NԪ4lCclzs_7=:=_ܢr<٢F.sd\fٿ(]-_hnE?MGzDuM)"=ѓVV/G)w#=S7iWmbZuO-{C's׫j=yc~h9]2>f > Z艣GE/F=<X E|v4DыѷG/aV>ĢɏHQ$zYݦo~;U{"I@:}scE\tDѝFw'ǢɣϞNugb[thuw"ٻ=ɢEv1/zEYjDd]Ś{;ҧIcշcK^`Dͭ巢왢EWPt#|跁>{wXDGMDGsYItEUܽ@έcOѓ7Kng9QO]eVGWsG7P1{5z8:Ew4W{>aJ] ~uE5N܊^.;G!sx]uE.UGt૧S=:aTtN'Fu0ϩ3C:0k|"z>& ������������������ڝxήk!uU]ѻ謳34lSeoZ z]eDzdSPC9F67ݜtٲGE n5mF,٢Y}:wYu@\яiW߈5>]칚n^OڼjS|6g#͵ƧbA0X=UxotU朣/@ѫVs'yF7=,:┵X\K^$~;z.!U[+z`NVs6tGG7M~eEE{ۦ7E7O<PfO}ʞ*9d$G͑BOD=WIџED>N6j~H\٧K>i0z*{ihk:=as#ϟ;X-)飿7?={ϦmF=*ϟGv) ӈed՟ёyvlF-9z&]bfvf9G'oe򃘪;ɚGlu!ѧLOr^]U;:;4hrj~6:uM<4ѩ[FD:ԕF*S񿳏\Ϲ6ߢksss):uJl������������������$uij ]|5R`n;;Ma :]& wE]_toGގNP<*zy>WGcUs+0z;6zcɑYEU-zѣwG\sE'n^5E^G.[lͫvtwz=[q3?/xv=7zyXcSuǣǯVsU<=Muw虚h.2:lnF>X'EEߥ~{{{5z跷՜[[Z8*lHt{{_b跸CGw4E7/jzѵӂSD|&zai?=s,z\dOEf2߈|=WIUMl#?B3EwV9hrEs>BiftA!1ܨ)zv-{ @t5"]'zpMLhѓG;Kt-?DO]Seg}ttdt /]==WnOtz(zGvѽDKnU[OF'hPt3;Ew4^Ճ4?Cs}:r2UU/2g(1atyEwi:!>ק]ѷ/ud_}:2|ꞝ.#sYG? �������������������L&uX_FR6i[w5ߢwFw6ww9eo |#:Ux_sѽ[ͽٳeѻ̢#ͭvlL٢E=K虢c͹GG^הDOuUVtyUf.L#:<C5ύuoѫU:SvW՜OtgkL{g'/0z_`谹Vs#pXԈ++[tV)"1ы:<69}x2z_n%~蹢,0}蹢O $d(.~{<!Zt=as4zDS6ǢIkˆV[SDO??=K1yWa7EO=sˌIfh?=Njt6?M4:/:z޳"CtU#;g6]UCi+褍=яU:F kF������������������)|=N详9diǿbśѻ̢;){rtMwv(:Uw_սѝs=kEYsUѻsUG[虪E/zl3Eǚs6?~Hn^鋿<0jzUy|Jn<G*7SGw$QݒDGfItgr KDk*{0z_`}[͍aQ#zlѭ跇E7M&~ńGOD>,:*zs-z<? ΢|}6+DOFnE_((v{GCѧ_>jgjE/KG`0}zrHQ<n}\'o鋋t/(zStj~9zkx'EeJ̓se\$ߌNT]kɚˌ^N\̦*ע7?]U$?<EG?N{qoZ*{vVݚ묣sF׫O+#j4}ͮt=NVdCg'mTd=;usݩ^Pb3��������������������3K] 75W|}]oF_.|}}).z4tas ѭF)/:Q?=wPsу#n7wEG[ٲEZ^ߥn7wE^FWяy _뙣W5arUj>yio>zaLt4C6ѝͭCчwDw7|{W⧣'Aᰨ':l.!.1zsCS\ޢ'l>zBI_nNˮ-ٍ#E/zoEh7E?}=]S`?zZva8=}sjn Uݕ=Gqї岝{tjlU||[:$-ZOF~6z2BtVsѩE9~&:eIjFWU>ͯDN>hsї*/N%gnTdt3aѷMihF꒝iEFSf��������������������u:Fo:^]pt[t-y={nތΩz>av@t0NT#h6fGrn'-GkѢ{[շ+YG7WD/^^Eэ6jjwMm-gVFh ѫc;e}&+}(0PPSVw'Mϭ E}X6DGSDcG7ëjқ˱gk>$z樁ꉳyt3{ zDDzk=\&Lu谺跾L^{w蟋Udz~fӋGG3>ɟ:4GJG/W>FD]UeBٳUWsvasUkO/D\Nj36E^Slͱ'4GKnU<٢Ed?2ɍftU5(7GRd%ʋթ: %DWEFWAtU@rU>/":9EFS'<cvW ��������������������@6wۣpt]}6ѻc.M]}5h7?wFGٿ*k'zi'z0[艢e:Mћ9Do^gZ^_^=$zՊn˫GE׵uUC}zg^cFZR6ч̢#ŭyͫ<;W漢;WCN dds.z既G7| D?si57E/zLt,q{})5Eݗ~[gk~d7,虛]w%CG-7=Q壡/]dGG虛F,Z #Ei^toEj~.:neEg9ɯD.^N|ztƖhs'eU]}ьg.4W%4WAsUBsWtڨaKvʞQ")sƫGf����������������������n67vm__G iDջݱ+vTnޅ͵]GtMkݻ"Gw6wFozw Eg%ɪGg4ODgSVtCѭ3^=.^gZu]HsU]+p( ˈ7yz-zVsX}o%:R܊>+3zet<}QH! G6mыEk?E5oD7f{'Pc}zl,:܌)>zpETt,~{AџGVg$'<Q_#WDWܙݳ>c37GvDkf?/ ?/ -=Q>:Asё`gOV-:ꧢ$G{tB\Gfɍ:\}nF7SGFDN[D&e'Uxyɵ"$}R.F����������������������~}wu.nsѻl7wۻȮKM4]B6 zSfwMt]+>=Wt;[\ɲ7vwd94?N ^_.(.0zuݖotws=ͳGUѫYYZtUH!辉5oEElbk}oI==c9*zh3ѧ˯szl^v܈e?<Ut9sEˏn-wEE\ffUџ#gmn.Xt3{L7gof4ģO٧w)c#7U20.=]qVs-Z蜣6GDm~-:qKѩˌ{S<Թ]\fCѩ497WAs=:qYe]>e%.g0%6W/(����������������������l6v۸;nRulTonNבWDö%zFzVwDwI 蹢٢NVV;uydћX7׉_^}^}~<IQ=}GGv{tgs)Ǫ)Uy{O})£{S'DwWEE*&zю自9lߎ>eI\6D_v܈5-n7}#zvuџF7Eϗ3ׅDD_%FsGcXt#{btk cMStVr96=Y20.=it\Bt9-eFm]i/EnZѩOԽgOF}芮ZѩKkjU# SƉO3GNDWEߣwj&ю>f'yB]"٩^Qd4�����������������������}xWћl2ܣWWK޳{ѩ7Fo"ѷz-z謲Eg#ugE3ngwGʊ^}ʬ5g}\ך>\ݛ[4z]iW }8j6>:Evyn5*/D,ZOE/Fy`/NǪ>}~ޕ]Ct؜g[osovsoF'~*32:U]Dt݌~=s0zHv@bCљE'ine Svv2h~O >)1:a)E=.:u蜣S'<Թ\u6ǢS EN׭;:uYa}я켛SgGhh>\՚R�����������������������Y|e9j@W~՛-z{u]|$ܪWߢOD'V,'ףoٻuѭ"}tKnם#zSdtkOf?.2z}y^}\ WPU]}ܣ;E#p8zu:^G7_eۜitBt$zfYF/DE{ε.'zqi>V ˡ:l39 ?:^<]UF'av#*ut:D'n\ ͭ13}N?:)e;=i206:i _Nˣ?3GFmEn~%:ur1ѩ{ϞN{};okͱԅQѩS=љ77ٙ7ǣ; QB�����������������������|xW_5[F<z{^ (-*zsGMfv.1z]Tl}Wͯ}ݵsD'mEٻ G?Do;LUMx87_Hf*hE뜊Gᰎ'z_>5wDKn5/0zOD'hvtF'iVtvdUos#zȣE1m9D%D n7V#:茲ngWgѱ\o͢_G#:Is+?"uqt o05苴e9e/F'm~1:moKNdN]\:ԵWOEadt̶0}{I]hEN]!h.#\xt%;{siro������������������������Ig:e'_M zΥzsrII9zɞeiDwUKd zU뢢wg̲_NV{G=VuV'mEwiA.g**|YԇC6׉SC;ּ"\ޟ/чuSNU-:NעEDkjTFeF )4ߋNFN\67?]^ݖCt\Bt9zw1o50:Vt>o%DϾlob͢_DuVJ~.Qo4wŏxYFr,$z02:uKiGFWEFWUy\N]|Rdt={Dt؛"OFFl*2$n^R,*hnF'nTdID[2O.4�������������������������W|դnb³u晽^g Gvgp3:Efӽ>nf*e)0zӊe7itG7wGvڋU}׹4<#}gh^kN\FD COtCOtף6nf,#E{-_.1:l9,zvhc͹FEEfFoU;6ɡ;<qwmGgѼ5\ދʊ^D -Lf9SFWUѩCUbsUb3��������������������������TCJ.)<f3\FEonZ#Ivs}knÑG:{1R^ݨ?V}튏^};ѷ z]DtsM߫S<&zj5ߢ'uЇU#z;ı7@t&Fю+z/z2FE3:]PY]`tY=3{F/Byd[9苰9=nWݪ.?,zvsџ7LQ]֊U )Gd6GTܜG3nT/ ^>ʈ^6L-ED٢'Ud*(DDG L.4���������������������������% Zg=j_]_3ƶf{ռ^盽).zsƲsS\^g gJѫW Gv;:XAxtDEO}}( zD~Ctq;St67ԝuo͏}Q7VvWtlљE/ ^n%:~DWUyU$:isս@ʫ4u] $uW/s5/^^UU9 :u֐eCꚑnfnf�����������������������������~zN:v^g]gmg95Df\tV٫x:]X}8cDcհ?zd3>}qF\N^JGթ pq3:Cѭztn#t673 ~:}SRM՞٢>~_`"Kt<*ps\ J.>SgXթcEyDaY:f<�����������������������������>K]񤂣 <z{^Xzs6-爞nfD׆^:hs9{ѓ*;z?":]fSy_E~U}O#;MaĈ*\K-Kg%6W%6�������������������������������>IrK <z{Һ*m:좢W [):c~om|ED^:GrUb~/zJ%GWUGt"\HtUD߳SE9苾lKݻtDϥ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������~߿q{l���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/templates/brodmann.nii.gz������������������������������������������0000755�0001750�0001750�00000525016�10403121544�021124� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������c D�brodmann.nii�q#ۀhP: ,FZ ƀa,[f1r` 2A u˛ʬ<;$PC2Q�[?'??_/w?!>KTOwy0_h׎ǽ_Q zT$zV}凕=q:{ǭǢͳ(X48Mz&z71GiX>.:]]?*Ewzu]όv]O{(G膪%dIơǶ-h"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""":t|E5m:%g;USam0~quIǢ6C3BQZ)AZvkg&Zj_}x#wFVρ~耺ԁdlgP2RҏtC/n QҏЍaQJڑ=Ie\ spCJFDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDx[Pկ> x\0DLڄ5Л-Gm)3 ȟѩt�FZaҩuZEtϼzcu:`חC_-kz8p_^ѣz0xk:n͵ 9Э$XG$P<ݹ:Xj^Ât-Iw{crdf!LDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD{ : cAY[;aA'&\1q;4q̈́Gk :j_%sZ6F@'4wԕ]gBĕNB?v6Gʞ -()DhhP`$Eo:.eo\ۣ6m[nV")yF|9Y-^Ujd__6GY?et<-(qQc&ykGIh0[q| vZahcl|Qˏ1g=?hq*0;_lW@{fn4|MDG\uZ%t]Um(ntӸn#0FҞ^r:h|vVk&6_JD2j v^LF҉yypH=d:"A_B_\k܆噽v*$ڐ[UV%uzI4M-1۱o89j>h?SZzKuꪃkjI,ONоnfC{z\jfmi޼qk/fn3+mX}s?u՗kPwĵn64g@w?9m{,mևOE͖3U[Gnг|}ڔ6+S-<tw$heض5ѣN:q<WVjhmu@?<|qs/Ehltuþn%ϼ+|/m4t]܊Y4uE)doOb#{E3Q <X}Hq:sGxt (T>3PkuG]y @^ŒךZODkL~ 5YcvPÜnVǫNWѵZzMTn<lN\kCr{7yt}?eN1G mi\tϏ͂z-YR̶7j&hmW/-v:/..V~E Sn> Bl2hSͫݾSC-4yx _c2ӷƼ~yX~awT\?f\2._wu߱U8U2:Q]fu=4H⒛CVbkRys,נ�]y8ZwMkztéƙ떋P_wB+}5Om,CX.E\s['qbCxO]!WMvQnG-V=z ėYR;[/tRm`N h]Z,=boxY묌 v&ZB{թaٯVØ4kYe.th[]a۫]_y䅮46G]qDn kcJ'uctVhx<<GcQWk@{53c\ySxUH5' kkNR{t9>9: Θz]yhī=x32e37B7-]jFf<U+22 -=qtI,nW9=6@[;#ּZ4l=t\]]knnNZ:utsU6ȹhY]-sY9/.۠ktl¼60G_Cm̏3:=ژ]FZe_ +46mƄPWk=Qz/1/[~"}F5XTǵ}<k&pƪP5'k]:_9qlt7@^dyu}տC_a1{8u(lZ]U7ABwzBKzp^'~ \uu[&^=!j7"d-چa|\-ѵIKcks:9aDGHBW5{Y`g_\6B@ԩ#ls6Co`^nO1mh9->m{Fg "[ !sT663Vb2!h^ǷlwUo}ˇ.ejŹj lV'8&Lr`8OsUtZ>^neGlm\kʐ/^iNrI~sxf^us2+y$tֳ)ٗ6jaL}<w3t?0uFnlǤkqn+'j+_Ff?zq5~$fЎ1/YU5QRfODA-#CqUI< ! ]\:f~qRgZ-ڙ!]31="%hiz=悕ȋb"Zy?~t 2Yt,'֘f*B*͘l­˔LDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDԼWM?rTojΈ96C ֚hWYkyܱy`ykq[]œZQgnVK*ޜ$/Ϥ3DTb5>6CiGNCWA_OħaynϬOxwF_kݗZFzPq:sGt_8YP_ݒ}KrMAWQ'S^pmвϔ=ڠ I@[히Db\nkN]sd/4&9-+B JuѳЂT5�z67A^m_<a~Rb'Ud{H܋GOwVZ[&hZ%ZOA6\yF_1@ +++* \?#>2g #7Qcj\+ =OP.^Ֆ;𰕷^ёaWc_j7A'iUyĕVK*>$WeݑїKg8Q=^_i6 2pq諍C?F=N7]6ttt^E8ݺn]̚<9ёfa]x푸wk6K6Hl}S폄w[[xw ݔW[ϸ91/2'•Gљ{C%Jtkx�}Ew6:x税vUhY? У{KWVase-nY-3FqU~o=mАlW-8H3<aA LVʹ-Z-sgS8]q6QBDTϔ~> [o^zX.B:^̸U\h#+˭l.GUyvoYyuP}W oux:_CSגR肕>:Y}}==/T9}IC_.;Is"2aTE_e.=q~rqvuq}=^W믳O}+DO=5zqGKk z˕@GJD7GW<KB[+bb{)o?Qj5!*i[}82ϳşaCȽZjGb - {>u突VIml8QCODis$tB1czhuB�Y*'F+-={CG{5Ѳ`E:ND;c�]#ڳ9*Ez͙ڍt4iV@,L '2HC;*mk=aA ժ5Oe34}9H˽ mz=1>s�kG)sYWyyũKѼ=y93237}f*Eobnϕ8GY>"K?<JKЎx^\G_'A_CîwW8үE^th{{pSm+jS Мp<JyS8,UASz8HG{k^t?Iî 5}юOmoǶA:OK"Zٛzcg{*yW%*Uoz"*bOQ5[ԃ; oPڛEOAw?TA%HQu|枭qjjm "c>5;5 W5:ݻ":wkSǬ}.Nc^1*Ճۢ &hRgţ=͕^ ZTG�mnLɴClN\ ]i،; ~=Y;aAD1ZUhS1]a6@Ufk3+5}ގzKUVцL9Uٝxm/5d*ɕ.ՓO@NJ0ۺɶ˞)Wyz>sGh/;kGsf_W+ }~ o`V`~);l}MF;wIpwϚ- hOuMT{ǩvG]n ͮwB7&W7Y> ZMa_}5;|ו.D7\ȰETt9k'n|�_mgyc}諁 q g_aI sI1OjmhYmˢN!/k&̻׉}j:8ІS}ID+{Sj.Bk]F_RѺ8lB]u{tԟ>EsvCas;SrA" =<Z} .w*3$>sE+ IC[^iw_FÛX loƉm.La#}^_^TBX05vhC3T'W-ʃ@7E/"Gi79ៃQڣОB39}3s\]oT fN;V]eh{*4G:3mk3ʦ,a*l�%"""""""""""""""""""""""""""""""""""""""""""""""J馷(eNXc5Xau@7W7FUGMp>znzOul>$Zz~cC?1*y]*ۈU}׷YJMZUh5ՙ;y _a2v4M訫3ϵM|v2o^ԙjpɇ$OcuCWz z{0+ͼ6f:'mmmT$}L˫;=|NtBWWc.SЇ!t qsNkNP!؃kZ2d=/kw-;.[WD_Х,NG_wDKNQ7F]A~iuts0]lNG'&OWDs k*z:{z:NS{>t7AGԗ:)-.\l s yWG{W..Aw%I}ivst$t^=П}~ h[݁[uuݟr[^=}\ 54Fkh ~W i82Ui#w4* |C�a^u6z60^=C}ZV#穄O ,5JݍyjJk bW}'+D[lQݘ-=( n̖pZP[ŶC'{lje"ό5Z+�Lk) ѪLۚU!6AZksׇ[;X|:x7X3aG|8c͜C@&3=#0Zmҳz tC}Tx z\-עN/b\5j_\L^ xeUlCꬓt#f`FHwfcN m^Ec?S>?w%y3_C9c v2 (4{Nz'byBǖl4Q\pgtaވ̕^6ӶGwT5J;2L^K\-yh}+- r5}e6CJ˷WY-<h;}DkѪsÃyhxu\RaiV* =zuu1ѥdt:]lN~"ͧA_ѧC֘)ٜ6ofӄ엡z>pAufu㔖|/R{V|BKm(0种n[6GП F֑hVm/v+ }�})@_U2:.VsC0'Z1XxOV@i4t<5bMm Q^s m[$6Sm onJhq* m$/IO3z:У:dk/#OK`Ef<Yh5=z)@ TGwq@q&=(Q-2V::fYG1}y3c@^qE6hB7P/%cl2J46,U֦҅`iBDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDfhEw4zG;:y~EנG7ZJcmW}SyFGW:GJ퓯D/&ڣ^͛UmtLzvlVKUgP^~Et38w';]ʬBWR4_Sj ͪ|FϚxo5\> {jBBV|#s?鈍@[ݹr&o s#m\3$se0ы\<\.:[W2/#7tF_8ڿ:3VB$ =>&Umw^y8:v2IDkw>6O՗4i84ai6d~rJCt}~mnN\hU>D_f$u:tƬg$ܡ84r~\~YT3^-3Xq ɼR}r֮AZ=B_WsF_ڢ֣?ЧBw= zα-t'/s):|}fifC]{wjZNRkQDўQS}38yCf]O}<JyspM$}YNZn}Fwis;E?!c&=ωǥNBlP5+u7+Go+ECGm:QcFdPEettJS=\ 4\+4t5^kPSk/tͤIL1ڙ(ۢ׎_n>Mj؂՝ff]v!knhk  F;9^9I{p`̏yS=%mǹT|<V[@q*{5]8@v@C@%~tz=Z'_j-ZRAD W@'6APD34Di*ǯ[խ#%36fC}J [jЬ}>1.N�Oi4t.Dm7e;i#>vnDEY]F:0].S.Q\U[;f7h/P^ anVá6_qEE+ ;-\og5k`{ "�}ծt9nn^/|p뵣G"t;u }5JD/'42GZEЖ)O*V[SWzTЎ9naʋVBs>:V:t*EvCVfuz]&z_7e9yp;igl%?U0{Џ3nj?П9E/ S~K=kOq�}12z 7m>UDuѧ蔥L&OG) ]}?Пt s4K4:h]-jS' G}4Ё$9装V{cB*jmsM,Yq, 5%\ut3^Etg%ձu9IZG$0]WEkeqfj+ECp ݚ.s堵ErKyV1*H]eJ?N05atii<?D+zj?U7a_邳j:} CG2` U}mڛf9Ll]I]qUgD+iS6F?{xm>%j-u~:0P%tܽ=1T[tDm?u蠺 �bW@/nVm~zQUEUIYuD[?yܖ+^>zIwH9gH1!9_epcC!SgD1+Q<~?nsqc^%zIGž[ft>&yhA]19U}+U�}|Zt<xf9r*]ݒv4*zQ͙ƤEY'n9h5)mܥZV_F Z.לj,΋| hV'gswbt\}]JGOg< *-m#QZ;9"h :2VAzFeyЎ9.2磕BN\WܧRtP} ,=:G}Z!m3K^Ђ{܏w(6bw72i9ZG{/ bJ^igW,%V1tzvVhY\E鰋NHE/cB9ټvK[C -O":c5>D=SF^h)kBgC8J"kDŽ>+7{]G?Tyq~k˜~FW oREѽZnibhj";se5<^Vwi(%k)oSGrZ #hN=Y&tDÉhU:^`8Wkӭ<A6Z6vVH]"gth6=чV0>A+"=8y t]?k =iW'ު>u f,zoCvޛ@DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDnfG(b)jot06Aa' 9A| yet^s2jY£T[rkIǪS MY C݇y[麹k-Z罵F+ MkѶyNPW@W3`F@7[kj=tH}} =(kGDK[f8$\BU}:/!UO$W=z7#VA;ź}uCv.UVsV>w (HWWEu۹Q/S0KhmuhݨMWOA=h|Gs"qy4<&7 <}SPyї {H5;[C[KگnihI}ѣ;avDЗy骑E_tu74t9 } Td=OhbNP_%u}m3gS6@LJCB~hU6l)6SW.ZyW&:2T_-u ZѧUB+4_7y϶qyOmAkTVx"G|ռA{Ol^֡vr>Zo.C/褅.DL}y5گ^n]- "fhQ3F†dMо'a \6eJwgw1^cVM:>Pz:6hkA}S`\=yJw-az]*Hɸnl(GJ+2+gb:4`nڝ`Mha s]UBi<JB27&UMsb<]=WQOϩs-p=㢝Ѝ6^Yhy:ښ3 qv|@OR?W6[5E5Ygϧ&3w8*jc_m5ިX:{b "y7pFB/\i+/(Z"""""""""""""""""""""""""""""""""ZջΣMW6c!VΘ= KYN9ѻnWE̼ԕ~WZm͝p~U7JYvhw:٦}*:2l1;ihmR3-WfթHL Tgo<ѹ*ױ*M?lN7'>xݺ'_|=}Y1Z '=?z:<-udbrwMWxls=q\hJ뢽;(0Nww2Zbǂf!WԯhG5=^vnc.Zs?^.ڳ?2tx^} {l.R {J@w%I -SΤM6V1;i W" uJF3j^."rHH[EnFo֟}YP_ttG\Rjz:>Ed̹Wdtxtn>'ncNA_k'JB?}: =+z,}m4_-E+ni닡NAg=SD_6uufNPQ:df_moSyD6Ya7 #A9$6k>:jϡQYyͫZWSz+ZӜOlMv=QCk{#3E0й+}^t٧OC\*.T< umͷz̠A'oM-oh NAcC pAހFPoRG +.;<},q{3IY`qzhq|~k nS29`Օ\u>/7' #_z{[p0Շro(a6>ADm.[d<v odiCm-ytvG6сuq^5NR>\h54ýJfhvipwsy]hw6hc6mܗzSgd ,`>h/;s$sv991bC B 4k?yfl&~-4i4IhJjMf.k=vx}}szl li35 lֶz_h's_差%ٽ$!DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDsz;P:YuFY7]|Uz@gXa|3O~zIמ_2A zm 1x]삾Z~q:hw= fQ۬㣉b_^}1oV%bbh@Rg:Wtw;c(W*2TlnS Zs-:r{Vbx7c;T,Ew?vum<|jzOVѺ% hWq] Q@{:kWs5tP}~3\FQ_-MTKgEre>O̲C.U%hW]}^ԁѼ8Vo>z|$%pYCy:l˶)Bw9>괡KiÞih]}nN6 ^TgUm+VչIvƺ< z\ED_.jm\3z\;GCt_/N2_TRE_3 :I_љ+gnNT7K:wO7@_GrIDg숾vǟ錤O6k'0h }]A%)hˬЗ<u&UAeKtˆ}"z2otRO=~yAe_-uVˎfO+}:=堕s͋kWwݮZ5BA1uQ է+>vGf5Wkl}ƅ23ҞRSZSS7ꗑh1FZB׾Z{} H4F4t'w߆>dtkG:gug6X"{(F{B2@uZAG +miZFjMu0Vzp蜑\s+tpO {ژ삝!+r;0B_g1+s4>n^0}G =:YףmwCz4Bԃ}pizJ豝FahUɜWٳ=*?-u5z ^kgf> -n-uk1@To'JF[h vO"0jm1K׋@ Cěߦmb7ךG$t -D{#Vzo!7�zh5 W=ԳlB{~{^f[ihh{zIW40zoDn~Ex{^MDDDDDDDDDDDDDDDDDDDDDDDDDDDŽ;9Ld d%9ClΟNo z =c4rg˙(5KU)StҜ� ?u N{6V mLR}{K`4ug1V = 71ۇ;ZtS]؃źջhFJEn'c%pwsRO6ztXU͠}e3vA3GhDO3נO=UU }ٯ6iuG}>=FQbfosX]^6`.CK_=ޗ̅hy$|N@l<D9-Bt9']uu/9աi2R}}:<I6:2Q4'n={YѫmG.Q}WsBbW h}h#B_K,rЗnνt(NV7D }ЏeJ4O7?C_}IC?za'Ntj^/!tJG_їN%5ݝĜ8rNhN =drR:wl } / ]V~e:ܣlP}~~ k*:'t uhnǹ[9X_NeSDm [}^muw\2\ϩV6ښ|Epm#42ѳ{O Z;H'OhqcQkS^_mۇgd>.nV{oHp(@׾ [E/O".;P̉O~6NG{^YD0耹 _\ZW/TG{>tx01ozVtt<tydۿ}Et|, }o2`ut66e@6z3&-VD;,fy?>>ou6;k>rQxA|v{C~Av }?`. ğ\EAS =}mz8l?7g?&j٬eFehW\k%:lYТY5^f/ڼ3 k3 J+ uc: 5u#V4ŜԳٴk2滽-=uA; KknՏV;KZ` >:ޛ$$ngG>h,=F:$Z9XPh?5Z-2OlzEF*Z=elq هT+_7#/[DW4*zoAA/&"""""""""""""""""""""">zVX}X3c!Pڞ-lJ3ʺr2ɃS=跩qd]m{4@fԉH߳СDtdI  _}NrGijq?UV nb׼�= ̣jݹhcaiqh^ `aW3VGwthhGrK(}nξ+W;he謑r+ ]`.T"5}|At Ћڧf,Q۟^mW+:0PTCg8s>m#1`T 6M-4LQes7LD{վQ<9 -3DA~wC!s Ӗ:-ux<`dq{x7Hl}LF1NΥCF$m<-k?{j',u::K]`]2 vtIs]W tuctrF{:wGsDϣU7gh]}D'wJ@'>e/yO'@_Ol@׾dC }^3ЏdVa}M7碓/~lANPWkZ-k:<nսjS@k_& 9 @s  -e/CCpąЧvT`ǽ)0⛳M 0gZRLLC/j k8r^~NVW?<Fs1zy~sEY٪ ި6.#U> kqGUЮ젏&'\^Kж%kKZk*w9s1G.F\ '^s!Z^݇&'v5w/::}{w- ~?9䮜aD&j=i8P_egD/cGkҏs+8rn6>CD8sR7B;I-C쟍g9j6c�[ }}RJw) mtpOn7XZA-n unQso EfgD2 H{ bCW>/u}JA;yl ̳z٧nB ,gywɓ[# P{z,>(RlԿp5c~tgGvDIh3f{ZBcAqRTN7*~օNDt EMlVVX6khytvSmwrVڦozj Z&z@7*zWUDUe̵} s+y3ތޖhEPoϦ~+<f,J:hDyDd9ц4 l~_JZx3{ m-t K7WSUC7fۓBT;sUCSS=?ZJb[g%\sby_th)f{"tpЛ=�qs}wlHgw:<̶D(-=V= =,Qm?-txGs<PA\_Ѫ/xfz6Ja,wa?e߭Fָٙ؆Hx:W5;YH2Y-:uj噓&m%T=OUtZU.2DC=3x,ggyuhk $*3cuʼghЎ=Ek%Qbm9�":O=QtH-bQs"=9 cbWSChՑ!tRǦ>VC3-U.Z[TtG! )sǕ1~s@;nv%OMll1{7hZ Rmm]^9dr9k:K}{tD_.Z9ۜNqA\R34@O% {ANyK+t@ Lt; _У!zIB_/ĕ.B }]*|N7 U=yMRo6Ѫ::EO?ty^'5tS:dsDjD_ C:}Շ KG:c~.<J�}\Ǯ&Z) Ͷ58csZc 홭2}Zvh.]i5?jJ_> W5=Jg=꣣.@#l*@ś^N$t9(lu]`:+lfn!Bc^Ђ0jS8tc]D5ƨvԎDGF}B{ m-J~w �QM}_*O/,Ws@{>TO4^r_šۢO]z8h9W[Mfzcxa?&rMALwTzN_hG0g܆hƃЂ!70 hak}Ǯ"?k}hC): J{ a+tH> .u-t.uE \Ѝ͋Z|1sk`v7I٧nAف•VhxtH8{˕^2zߛǾС0R[qz at`IM7W-#tO<ed_t=ݮ߯-%x޾PzoPm$m/}ό?v/V 轉n.MlzoK{o6nzZU.̯v~Iyk-kCӔ/c&""""""""""""""""""z&67#)Zoa[m{ԏR6ĖwYtoL~[+oSq2ߗYe>w5w9[)e̍<-Ֆ٧.@SSCR 3EѲZZIT%DK"s<U=t g&휙nND>:zfw[j<)f[hX-#F{-Ga6\K;q2Z\ БMې4qZh~�:`VH\k?:p<O=0blA7z3ثZ.1Qì g-Yu74kax'x~_]=LTA;-T;3 5e͋.k+c䛏Ec;.3k5 gs:>s-MWQ^t-Om첍+}J}곌NX,P;_[9WE{sW-hAQ3Ў:2W+9 mB+cSChw::SEk9\KiT6jK, H^eyu G,>I2fhV:K^\ӋW}w}ѐ#N3]]-lh[6:U+zQZ|a8]Dt><E]lrs:gn3YˏVv%}ѧSz@%?NT%}IE6kgT=uAEWzzm 뢞P5Ч+-˗{h=Ej???>?? sdGgz@hsͯ:R?5İZzS m oO=֡,OCwYJOm66zdOf?:[;5u'l>Mb=E+zJ6>W6qN*:\W6~t٧_;!T4 Wjf1}@_\̏jj<Jx8/m+-23jWE jcm7+gCw:a4~ &o=C-EwyGJup=?jXp4+W/Z:SE{fXpO5GN^,ulVWcVhWwv9D9I+1UFf m퓃_ Z>7h>QDtD׬]<wX>iEZL!g6h90!ZRWB^ ̖͑ڤ'\:N‚dA]l&C/4=XfP\Co;Y陭ڊfWZ9hh5L*=_0~hν|A폖u;8vx;_=[;&ÓdjϺЦ:;$:9::doUzo�|z{yoz$᳛_}m\ӓe^l@[%vyt߼�zgW1G{{!simL$~֛Dƒy۟P{$.D&~t}Sĕ~|1wmKn5%{ͻ6lm*ZsyPmibn6f <cw-*|FS;fZ?)JM0}Gۡʼn^--D<-@r~m#bAWWϣZh; 9;n{X^hA{ֱf{%Zb[_lC 6VvKZc\=ë=-t-EZIohJt?O1qWi*yۢ֐ԷHڇrG.,qs-:NDg0KՙwG):<>'to<EWDj]2XH+8ُǴG0ܣ1[g -:,w>ꠣb8[s }稺%:>hmnsyhssm'o+}Mu:G]>'?aKUw탖s"̗ �Z`3Ю:<Y->gmudFhCA+cSC5D͚1Edq:<m slV2l>2S4FBksO@w>^gZXdu{>/Եҳ0R]~h8]j$/uԹ}/ls:uLD_8ǨѧTui $.s/OLQ%jVLzE_39h7ūk9/χ=ie;^ge"ϋ|lX)6B[}^g_`GZ6r֧G/E}Zftyh-٫ѣODGz6{1]ס$Џkf*�tW6q>课LpR:Ӝ5|V:jFYJm1|IT0j-vdse8fvԱDs@] }{<&ZREu4?efA}y?<fGO񡗀 -[mH=hu8baיI.ݝ~~Q~GgDk0?Du|n㾷@Vm@Ϸ5{Ժ}ߩuֶE$G k>d&oV>K=c&.z-*duXڳY&z%ZxRpane6WE }8|{r]bO]lWev ^v5sģ9==&Y0Zy_w0 sJ=\9Z$zd0/ C.%%0|w_pK)AGw精ʳO{kǒφ֡I ^^{Ksx˹hI$Umt @4;޴@/V>ޮp2zoU,y)|C*h""""""""""""""""""Zݛ1{6mF4k7^z)[ov $59j~zc󣴕.~|[sͫ~ߖ=N7֘۰&Wn2k><\mL1vjx2'mDt;2\ wG;2{*wn^&lZjqq֠Xkaoxi!sFC mJt C 'g!<lйf<]a^tgNW mv-/孎vCꤝѫnuзd?}DWZVD[y91c$עo7F:ORϬf/@먍qmw-=1hEgxWa$S5Ѣ62kj-codFgnMѷ :wR[蒅.S-t\}<JCq_P+0M^jgcg|~Zܫ]tw6ջCz=C=YR+C훮1|{9 <tu>36Cu[>g%up*hvԕuC2g#sǰ9>k-vIq9\o wsN.zp;^Z9/sTGCr(}hc]Ez=m?Lu":]-.V:?l>EMm];~s}t3E=Su\.2f/#IK9$/{Qqp: _OCYTY oG3їg@;vt o+U<DjqXhtY-4=??>??/Fqd5G-GmsHYꋡV9ZWqu:=5v;UY|Ih-1W-LQ|e^L9Іk<{[uNC+5>G?N}9՟?h 厡sS@ExRЙ8*zɳOh Es|mc:8}4LZImul<\- ux9t2~wW>^ܳMACb͏='Jڧ z̽ۢ!hiytKfgۡGaVO*ֽF쏏gG;C~$^gv~~3Z 9֚VKQㆯA߽sh b^3Z/|y#Ƨ`KjqMy●j҂ "h[2171/҅-u}EW%u rkЂ-yٯn6QRw|~sN2fQE+7>w[l.:腝J BlҚz;g "`Vj{;CZzStt-#)I1:Xφ+}KDwhY'F7{c^~M]MaRmtf -v 7;D'4 -E{q^a,5膙A+*EDDDDDDDDDDDDDDDDD Dַ)!@}{ o ެwJbզ6Um+R[@X-ߜϞnmN7?zSu灥]Hbǽ-Z^ MCoQѲ0oG8T@o^Flk?yAdֶo^FOFd}m=vjA3lVj-hA'8k͗m7uގhgA;栫͂z<b\vm K]ǭM:A9oҏ1]lV5vFM`{WE[�=~y3iz=o7QmN|T5lUmR<͒OP(7N]EK+m@hw/\ Gѩn`:\BlM.Eg'7ئw΅|6E"u9BlBq@{. m>}Pihit7׍L7碅ꡭ#WDDtOcB,|{6:]mgks;_SYc$:Y>>sZVWљjFK|UЮQEЮ:4]vQ19\eO,XV2z#1bJB t:YDm>mB˝<EuO>hï-YNG's2 9/D{wr Ë,SGӗGmB_.u͗KCR<J@ )fЃ:|0Rݣ9}I4̉U}Eg.t !-_@$:NQ?Z̋f -Wzg_}Z^XQ)-=kֳ.|n=;4g̟2+KisK@yԎ,m9:YyW?ܯ$iݭۡ~՞LjM2Ħ:Ι.vX 3%}ejLf7F_~C4ԥh td-Т>#v uYT{L'Ђ0S8F 쟻E{q?PDYC껡nw7Yw'o8 <z%mna@;}wы5;&Etpxcnu®6oц{e:dYjWoЎzFU4ݵ^OV,G/K8z8hktdjQH w m\]ҾI֣8e^B:kOţqNw|m4fjlԂ~KuM~%U9?gw9n6wHXВ-ZP7E2{ɚ;//eTtEf7Bw&2҆!VRѡ6G+9} cy#i'td-c?mXiX]wDodV 收Ew%-f-/!:<ЪB/I3˟{_Tۗ<%^�9zIt(ٞ\pә{ Z atľDz:bW~ޝXi^0o=:mf""""""""""""""""j ԽIN>F=O1KǵaY24JW7;- " [0xѢy2kh룧ۛhk|:[@r?9ŏTonNDK?;ݦyŎq{ŻU[lPli?y {#46U!}3s2mB/[3Г~u\کсSg hm-oD}ܥhsj mgF?雪wi%AaѮZDqp=u Ee%stks^t<VTG/Eԫ4U y\fJY=bhSYFou% Z<~2:<#47 :{o3g0&̼-B? KGCriڹ:! {Z$ݝ|\upZyT*mwU2oSϏ'D|O6:7g-ݑmP^qSgں'Eh{{ Eut# +-ۢu?.[0hU m ]liKZ4E]тW@`s+Z(jMao%SAk ;6ZIhsѳщ!̉SZ[!Θ!CދΓpFkOlt:cDCB{'}gyͩӣt<͏(:}^AkOch5$UENVf/23$%knVЉJAA[ Gvg⓬tZ߯PstzVD\<tߟ\lj=Z:EFY}A9jƝd1gɗ3WϚ h]8F^ߐBcP 4W?^O!a~jZ~4U Zh=b@hA/`6̙hYBig$Kk.@7AZ?W@tYT31p?\=.1K;&,6z".3 FO7~ilC{n-??lهon2ƌt>*4֟LaZx|Qѻ/֯j⾏9 h8֞d=и9 =0]/$uYGEXJr�m^wxVt@]=?r}-m~uuж5/j9zaEmoKhKd3ھ{<5FO}?jQ+qGuw[uK%~8|ݭ1~8N{Q 3Kj6S͡Eu:nVy%߉fGYګ CJfɬс6Fg4jP&:;TMVZU0o ~1şGxts$\Y65M6Ԃ]=dthG{;Z=_I;ǁK=8ٛ;=='G/4xRA77<Z%FڹvoS9hfSm߲,M|.~%B/&""""""""""""""">{3ۛԛ] qIPI0 d&/7>*:oWz{vX7?ω?t>ǀz^䍣Onm5ѾnlcaGѿKкԿ'T45oĎ4m?Vn#hETdz9ދV[)Govg=:qߦ]GKm}fZF--N5;ohmm̲8/rtcޅ~Eu B jݳ=o۩oLN^2R<TN7lv[E-mz-Iԩe ֧jN2zIjܱ=t]qzjɬQ WP̶f h{/olgVg5s̳;oM_k /.Rϥh3gIVףڝ%}F, F+˹U'_[S=8)ALMfs}>gZ]^toSGDtg6:]>h㎧Bh\sC9Qfl]A̮λz,j h:0D1:mѮ:N:fN kmu tp*c̬ODK>ZZ峃+9}كE [ڱsTGlɬoNhs[Ouh[N\R{!goLԧu"zS:mg˴yͽ$ygtO~di*|:3D?nBNeiz?^NHA/zXLsQ7)Cn6p^eO5L@|t#!`{4A+C\F7B_vGgK.::>mv->V)19Lor=Wߧ;vpxX}*VB9dz%ZeOO𱟟Jfg6:C%й9GXmW: 2љ(ZP/'|,z? \ZGEk3gc{EkA%O+m6&.@ j/8ob'yK[H�nC請=f^Q<ոlڸ|q�z9?@ӮOMw=?ubAKuҩ¸x.>Z~V 4}ߏnV:Q0jl 4k̶ڼ4{zᰨ80:=ue [=!MUuج=fKCW˃9ZDЃz>>xcB;r hUFO V�D^_=-gNz=&dM=j02>MrT?|n~|]Q4 ZBh]n]- w%Lu3Z6m4 /}*chKĺ37d7E2]6EMt{TBo_Ɵj۫U nnѫ͋=z|)R֯s64 5ѫwr1?t@oh]{^-uoٺOdogHMKE6_/wOk $pY{+>*3>5ov#7r>0JalhvU?-;ԯ_>#лW zsvkiR;h>t>5,uևO6GMy3ec 7'Ǽ?:nx7TO/~5NS8CL=]Mԏv~o+㢗hnr77V7E;3yVrZ뜕nNFG,Vjw"r ݸֵ@Wx}uZ~&nL[c%/c5{1&+@;VEBKj-f(+Ϲ_N_y(YDC[]v�_-mzZFWՉ#ż}XyVMK.ff}yD u,[*DW+UfG=\6hSm۠ .0o~z$Nl8S3^Lm/sT_5tZ#Ӽl}hmlsAiw ^.@K=#9=VGF6,Fg $_흰:b=O>]Oa!GퟲqѲzkrUB ZbFX6 -0:0c"m&hkCd{{_ۢ-d>;{ZXD_uNAoҀFfw~h&{ RѧZ\ò Z>/Zڳ7SNS@0-Н:ݭ?/pi( =gV?n1:K^7ZMfms͙+0qz#}:壗Rf<tӠ }mDA_lݫwB[4e푢B']Jyhg)#5WASm5TR0g\&lX ZZmthYڰ{gB[֋Vkq4;[%Ϗfe~~a�Gw@ hw1{?K_n!p2V%$aW`2t9o?-Б!S?>>ƿ>t92c)Su=(muN.1 lmel͝.4;j~eM~-(cj6ߵE{ܬFIwS/jch8G<VG?}YIޛu#pvaZMa5Yy'\:h|Y`n;V1Ǽ0<qT${Fs ~i4umYBCں6jYW+=h{saŁѮڞ.ԂYSO9f/SQ"ZT7A#k^~5ts(~4ffE=hw'p5<Mq1C%0yKC!g!7Rmߎ1펣C\hg Eo?,w|}ֺ"yP+׼u.1uJ@5ucYfV7zwMѡ v\mᅎ~&ttiC*A6C4h5Wus_]<ۣǢݕ|NtJ7RonN@G]I;bskG-h+&Ѿ&Ӽu쮝Ё=7ẋ{b$Z�Z7Jg*ͪc- """"""""""""""I*r2zk6Toa{8$Jalk_"G>9C2'9Z'kh[lV͋>|9^O~s?35:W9>}Ks/ۨSԿ4sk9W@_wfS/hB;jw١t{S[_V~=:6�L~'yQW ==et}gɫwgh<*O_r{d'_\2>s%Gxx3WF>x*@�} =j Ud߆.u@\M}rz2RR6[;?׫ok*V}jQ<j-Sl-QxN7P{N%I{bt7衕6^kcfcm~ͱښo$2u2zj+E1f[muu{UGteÞb2H`:Z'Qǜj\냺3Ѫ�͝>J$xAsg Pƭyl(@5D:[3QRFӠY�Qova!OjvR%s-wBA ?XRzJ2ԑ/?Vhc4@^Xk;<~:yIeOA-}2:#ޣh /'Җ^B/CFX^}iUXi;a7z84u#6 }BKN8,tR2ari7nd'LYLu*4/`#gg\Φ:IlMu&9{" Z3УmH@OSZ]L[8=:a}IAw mN:L<hE_@'li5CҠB3y+j挖.>XڲC2A~~ { 1~RtEf2K1/id -,0G?9m:J>ϒݣTy<dC,:}2s� IGW13sVmً=V <R6<4E >:Dj~_Wݭ x"~XCat5l.zaVM|7n03nыZ<_ }^Q}jAꏏo|5LKUН[w}0&a *m]mmxiŬ*-u t 2Z9C fZD;ZC >H{SycFO$.u5uSZRo̚z:1Ѫ γPFqw!zQo}AN=^lgN;d]SD >߮j 5MWzP<�*ݥN@kmw%AZט#K]lZvj֣-qUj׮]j~e0-чۢ]zm{mQoDaa't8zZwy0G6@yV^gM<U6@@5zs_N8#v0'מܿoorx9_ o&Kn|">5:%yJd˷;Yϧ6{Esޛ@DDDDDDDDDDDDDD�(p؆HoN6Idٕ(찒~[!;I~_oQg4G;C洕^7'UɃyQ? Ij5߼73Gؿ!o~OP=}Cc{^ȭ\-\~tGvHڝkv,ׂJ37TgRDRS=OE&u{Dm\bh%+-Ol P "PվyU4Oŝ}{|d\<f zVF;wzOO~{EZЂ;ZMJz{`{ꦩ3Ej/:̵Է[Z`iGd- hq -ξᛘC;ru<o<t6r`6mxmpHBG ^s^}@̅TL7:yWK1t֠RMзuj =n1Wľ5E#vXg?ٷ$A9֠j^N0sO.EsGa4ẑ֦473lܞ^fEKɚ΃IFU06eP{gl>;heS]X-SEtARHP3hiog񵀖ԾIѧemhc4txN>vZܜqG-{y*:3#hSMB6C[k. sWp]rֶ.:|B<4r/CSn>ZhgިԾu23#yyQ1r6V10vZT' ={t)~3~ Ns4i\.QO.zٲ~#=" uUSm?|s=σ6etW# :Cg V:ʮ+eXS耽u(D|=:V!2OX???JɧZ-@?cыo^߿њomS809Ə2ͨ'qhFQ=l=%;c}ᎽcUюaXN^mtMO){?~Z5xDBWFf3KxsI-P{Ǭ,PsF+x }ES#q2Бz^mb1XuZ WߍцN{G䏃WC+ Wzq-:Vʫ>Xܣ iam8E4 C" q뢕3qZn[c=#[Q7AKf]Lrm?{%QovGz|\Pg=pŅCߚ]k{55&Gθx8o]A;y퍱E?rUCޏ_Nm6OX8:Uzfg|}}5Ѿ-6ha4A4G[ף۩}ncV>sw <eYPwcj2YC3[j"胶Զnv(ZncgO]nbN9>lVYnjVue32aUZY|z X4t]Cw~w0'@o=p~:t'hЯF,dUB w] 삧5+gG2mO DDDDDDDDDDDDDDD܏e~ެm d=YHf*+|>XFS 8@տ"G>9C5G۳f?с<gvбG8|fZ\h?}>fz4wjpXeO 옷PГC%12YBwdzjg螈dknv ;/Q-wFû":g{'dlFԕjy"qihi_C5@{&˛tuoЩ:71q,[ļ o'zjPzoe|hp5~u`zGݪ2t|5Eϳ5gtPٻE|h境[vs"ߋ6"6UJѳx{m*+/;zs@[5ty:hnq砣#7D{.:\N2[ٞQ NoI1K%n2b2jv* NQS\ii5f#+e=ߓ`6B=og}kg~zP'3Gg|>YCwryH^o=Zg2=M ׂVgT?h<ע"dYhhkucُ^iZ?ft ^uĬj@e>Uc֡S?û1m`5o,*0g|Xz=t[%K%8z�=L}s>>Һho gX^}YJ;oFn>Zfe{8rJA 봵ҩCC-3pO\=G>賋o =Cge>;hnh6@/1*^KhmhmV>>UxO"aS8GzFezAqɪFkWGѶZwѝ5Br*com] ۣ9:qп [Sm kqehl[f6п?Sն<b?c220 0_yV{QtLpl-k__Yjp[,~2ѶLD皕6ID\<VD32s~دYYיDc̅hX^EmOadOCJC??"WfKWPSJ@PB GvNtE05UiRCN6K@+�Z}7wVz}竀񮳈63aur7]1P[;`o }r1R}8jasE6V7z hSFWC@}oIh-.ZIhI=\Ӭ`6TOyhe tgz! A'tZ:wJliCEz^߿e&ֽ:n헪~>}0}"v96kF[CSOKh]}m6;~w)hoAtŬH]R7hg;v;$`^51u- w5j9WYTwcWOǧ ]=CzۡobjwM [We5,ۣU=U/Qst]uutwJauctѫS ɖefQPyDJ(:~Ft!χ?Y9I᣶GG큻wӎުz<{V;}RMV~N򋢻'6w-&b3"bW4w I<Л]਍il{h~>jۉ+Z4/ݝ6ȑOi`Gq9uVͦ:x7H+=܃߆|$sKD/P9 [MQ8пttB7W?&X折_)jk Zb+KFjw/Ѽ:ҲyS0Qp{<vth' -r[67@{& VtuoZtmowSk&t▮g~fc_ιxk{�7zinVzׅg`2vEk+;٭*:_oԷ\D<5~wlg2G+,ԧj^_\籠x&vsҚ*`~7Ƭͷe$"n JŽ"5.:llU9G&Ϗ9bu9|4hF,s:ɜ[虞NiND/$qVutysln^6[y>~wu#:9:eiU-N¬}Ҷ82z2О9f糁~|߃хjcz~=%=y<&}>q=UEZ<ܝxt>k賉2R~cx^*z-l&us3tًnlgmc!Бu66Nԥ mK]{{ܟ?}sT$s:탥O^u<acj9qt7AJg|XW-e>G%tGЎB;d~~&8Bh}ROK lhmyUhsQC =䑏[WmЂZͅVjlGYR<p6hWA#h֥Bfy础V> <4vB;Z{~[ mU"yhM=,u^6l|L}2Ϙ<T>ybF ;eۓ蠺z_w=w߲Om94B-nvAW~5AC^ԺqFj6.pu>h=2Ϗ.2jsȓT0wUC+-̖iVX,:u|YYma4mDL C2D[3у;!xloV ѧu CmL= n\t Xя>ltBh+,G!H_0~i0}ivx3gODۧ+`6FhO\Vhw@C+嘕s F+0e^&[ώq=`Ƭ 1[hx[ꃭЇ�zD{ՇO=]q|8ZT/cD&鐀PWBkߧU}kz~x)h[m"k<w>h5t?aVB_|[jjuҽ&z|Bw&w�A/횠[>Wyh{6w9 ?V@ q-R:9]Ր㱃hU m9DVۡm0:ho h۽:}[-wFuSO+k럲UmЉ BĀe[0Xi?*>}Wiڣ#5QF4<ZpQlvԠk'']OЖ:BhV_p<z8)=)DsctRGwo*Do+uΝy_/hڷ2zohOm6difB/H&"""""""""""""ބ$k̶Pov(sC_v*vy͏6;qnQ>9;`I!<AvӐ%п:Zra_3ы~{ / ]m1gCS@o4sK=SEt3;SƿLEh-J_:nB-O3h[3Q.ZվyWZmM>'q9C{C;3Q7//Z~m-F3w 7f=K}GOџ>x=_=Yo<SЎo.Z_\ ,t%M�Y*ov֪%4O#>#lZk^u_km \[1[W?1͋Fdvfzd+#>]N0[6![Zڿatԉn\?h4l%% ؼma{f5Z1[mtٜgzyV蔫8 * mN~糅>߇߲ <Z=L tKNDd`y@=^+ ͓aO<>5u{NCk硏@~=hT s3QyeS՞3:}кz2 l5ui 9ע# />pO621)K5 }lv z(p8KN#KѝZhsK/K>}|%vyK3hn2iX:geG qݧ6<*tEI# >:h1]c!o(1 v-6S2B.Z9㵰?ȇchC2miFgcvz/ߜ*Ů=y)]y]sѦп{5ȏig Ϗ4a3c|֡5Gӿ~h穰%jw{54YjUW@ѩc&|%ZTɃJfS #EGRg9I@ *,)xѿWAlYtPxLg+O$V,uzpE@li[9yQݱ-om"5пѧUdnc >laOl?3ڠc"Lߥ^?GizzA+-Ս͵ns9^~L}#,t.4ٽ <\GhCڡ\uYI}C\] @o>AF3h<S룕>]OyY|{)hWm]<4ݣEVz9<[@W0~3S*?k\wVF+gm潶yT[?*|6 ZXU-HӇϫ}?܅~u%9}<ݟgغۮ29S!co6Ό~uR7X;D{s( }FK]yvi!5w% ^e^I=QMb[m AvuAY�PEоnbhz_t4kx=&.tZVWDv-p;DKkhk/0-ж:}iNT?Z3 Z!n`[߆nb6_djcAIF72/ЍSttCq.:~Bt|}xJGǞ "AnVm~/V#c7d8b yDDDDDDDDDDDDDDկ%ⷷ7=ܷ5qk{Гߜ=bܿ ӫп5W谧#Oz7_?b}!szf?>V|q4aߒ~||XH}s4^^z&Ջ~VE >ltc>Sxhn6ZƒѶڞ)пefjwYՂZ)jԢ Zk^M!Dɷٛ}S][5Γ,aOoN]虭�<M~2ymk nq|7X_Ai>x@=z1OUtzJhG2WRm.G&+ofa9mWS}GJ"kؓT6.aĭ9֚RWfZ#Ld*ul_Lĕ^EMtEn񢑂.Vѷ͋X'FAg կN2ߌWtRGO'@o}V+I|uydFOo%-ѹf{+T;wYE+]m{cBOF[ݛ#hyr9 yECoihkR1 =]JeiiѬ4�ڡ3IE{Vrȼٯ̣U4>T }z^}vԩfhlۡe)Z4!wF+nAcCFvu%)oi\.D[Oesϟܣ1Ihm$i<oк!=˚gs>+madlcjL˖xЎ}AON=}iأ9c1zأNB/+\8̧֟ #/ ~\F[zF.}&#oL>րߔC8oVû~rtPSoV~tV!hZGY$}�iQ}mЃ)1l.D~Cg=t<Ѩyheϴ\e+,v^۝< Z_ggɳyK6Vo-j6oW>dњȼAWUS1rZ'kB59] F/|he"91梕> 蟕hcF5cyt#TFIӚ6D-^O34m6C|uߋgh"ɶ?6VhmWW#ѓG2msGXNC['Yj(KOC GOS}N8ꂕzl4sояV黉]GMGwBA{Kf}BAJ{1:8.vV'+JcKs:AN3B+}9 j {6ݝ[&h1|[m8kg fCCtp_2ܣ%Wں6[}wjbG6y!ծxЇ<&diMF]}N2 wS:1'm}]Ǩ2:oo0ڻK]ŬwkU\=?M]wR]`7AjWo.6{ՠ7LAvψoA+ͧj&e(I#-辨zD@-g"ᶤna/J7mNVP qO6,n_unhV+yt 󠮆vVh<ʬ{:ٸ앣fnx3IcTxl@+EψThWY@+ycٙg-`$ ϓːgp3K,d"""""""""""""okhoFF${8Og{+7q>}{۟nݸFC \D^jٜޅ,CGf_@BG> 9:j6Gg1A7>zޫ~>8'G ׻^s^s=̠zg۪˯|oZƒѶڙ*пWfjiYTKRST~-<Pg&Xaa7o"/Zk7Zt*t]uZ%Qezǃ;=oҷ\rj&W{Po?fo7?+0w^]<˼:fu\M}KV;3ߴju6lWS}5g멝ĭichϖknp:j6jly:b/&j{6sԼBjDG̓Z5AE+z#{ead [EO'5@?GV ԩtZ#Z_Zk ЙljKXIQC tKv,ͱ<t|}~ў9TynFO7I:'G?mNN=OE^W)hc,p,R:Og56HH훲\h8- ЉS*d mmT4fh[^NYjvCZ<mL9CǟGX?g{S'OC?!k=w,u#yԏ_3F;]m K~" v׬?Jع8vm>j -,G+徛/Ҏ6V?^V::tV t[9#y&#K[]>p6Э}fi:0hg`yWzStB.&%zS}m>JY۠3́1CgTGwMP&nB23z\fA= ?MW`V^ˮF蓋qUVZg7D/%ؚ|NS2o<߹h%m󨶇t9CSΈVZ Ssi YtPx{yOQtLn:6g1W\i-gCF;5a)=3c0qOr"a B̄?"g]>Q|RN?'"sa=g ט]#}-B i>6CeUi8rHs7eF]C}A@?|g2ёVm~7ՅfYh2K( ~ R bhyh63ZrNx81)*Q|ǃ/ZY[je쓿HpW@dmtpά^F߿ .ZgEmbGu\ƞyPߗh;t`;oq .>yFkTzo>l]G}wf.S a1Uouz,zyfoIzhdtR׽Zh\7@՟Qu !w7KFt=r]`A]d@ f=ڑ57[-\l;l.atё_ =sE[){xV?z%m뢇bKTB7@)TM6VuF=:e~@;Z;yDE,M1ᅨ X>&QN^h<f~&ߵ%zYJ`[ tӛ\: ul35n7R't[[1zkh�=E -ϊVŻOw^`3]Erh/`VP:>X)KDDDDDDDDDDDDDޖ~ J1Kg{8ޢƷ'b:/&xp~ұ7'a)>Y̩"%Ce \J9ij',fZ?|;{бh՛C}&|ߝOq " T1s�=ݿ{5vКXRwDsK3UxjL-M3jiFjy<sU&3o}jDA/pumG3.o_?ZM!^7@ro;hڃ~S=JzgKTzŞ|Yk߮s=u!k+}rJ0oaq߬XS&Q+l[QP+,/]I˼6Kꙫ痗d*uz`/PzFZ$tVG+/ZЏGLv踹uEL#ZܵB'""K+nfoDf.YՉ>^ʴAҗx#Vچo:oئۼ}<Qtp a5##7tVCS7T:ښ#cpzy|%0{V&szRfR t_gSI賓2WIh}LP3C5{6X sfODE/{Z+US͓gmgB}^Bbַ->wZ8Xcn'v@W>ϟ. ޓhmK?e}Vs6a'wt}\`+=|D-# G<qy⟴ZGЦzyG?ڴ #cǃhgKm5m]wS6?zj-/1E+ݏ1 #MjAqЏoGgt?{-Dv9{m_At90Jz:}^(^t~nky\1jOqtVai5eW k'o'^OXD'^/^ƭ`}U3^jпl馲fB ̮zޘ5 h]nUYz=Z\VFUha\ksd z:ZSAș9;9j=K] \s.OC9߹f24ӗYtLxjwOGj}ӷmhS}:Km;2O3>DwkO=EO_D/'qƾ^&+FϿ ø1׍8oRsg~̹?l#֣~adCxBYSG}4 =͵=sn'[ujY[[:zT=,TtF_m &:rsw cheevIfkhceAQ;y{>1 |+heӻgp@Khӭ̓ 橋3SE}zwk^39&OK<   W{C ?%OJ=\h5n?ZvЕE�>E[?*][-]aZ^3 8Z"QZfd5*bͽcW#GYifπ6ՠkCjUՁѶ@[N1Ż|jy_-dxLv2n)?mJ?;Y蔵x?){ߺd?K1s=.|^t-9R$VZC[l[b?md3Zi@`/,9LuݎhAg@ۯ>N`ۘms? uĤ"m65\�Z[t߿ *[Tk&=͖[zmzĂHݱ:xqG]+ѻz7R6zo$9h"+$;E-;Cп"=eR> f/5Ir[5g{8=O6drgUkvtOoB"Z]Բ$G~cCN<YR/Gz}%Z`s9qOE㽵}/NEO56kEqfZIWD|O#7URdnE4P#<UZ5-ԞbfACW&%Vh<~GU5Zfn~^- mo G25!N[`ͷ[Dw{d6}OԮ"Bz[D-OBldٹjWݱ~En< vվWcתf-ӽ۸:ly{~30<t;JWcKVO_6VT qvދ]Lb,/օ ]N2;Ǣ4th iml|n>ռ9 e֖Z{@ <=s}V+Թv>y2 0 tY1>oЁwl>f=TNWMaJq[Y>OMy0Z泾cIA/^xT<a 6Zc5:M-=1 =]Zj<g4|m]3nk+=н[_??zkXqS{fLG{{BcdaΙU1A=UND؏iگa#<? G#mo$9ЖAi3hCѽ{ {Q97_wz�@5A? Z>y fI= [;dnqfDOmOZ^kѭY3ǧ.0;jmt>16/^iF"󤖆cjK~謅Vkk9ܫ#\QVo -khBcVhQ mOTh%̢cZG;j}UGO\ZgE,f_�L4-3Ȁ?_ pJS ZBX33'K)z`kn#n h~n*ZȃZ6#&.0+|m%hgtPt.B-td^w 1[h?LthS]j^|"f-tVmtK=>DчmۡźZEЇtL̷l>r*|d茡QA/eAX¬GkC ^-:Z=lVL2 ClCmLU<A;G`G]lU.B]qcf-{"t,Z5^ ]TL\7"Z_Wۇ-u>:0pvnLP5_7D!wgQGFGձD〮BN`o G[3a5萺lvX>-vn ۣl"?JMT [F?$VF<?k>#yrgY꫼=mT?nj"cs;A_X5|¼ gA{"\sԲfzVItR7{_7#w6A[WlsRKh>Lo>hE@7a;aӫ\ x%4K}Sl#RA'GLخ0OnCÞ~bs.zo`_=IdP3gotٯB{h]8DDDDDDDDDDDDD[/= d`v}Cѿi_w=z<oonk<r8cGۇ-J2{= jP~q&z;vجӎ Hy1ߧj}}-<l֊c+4y=jsڙ*jծڝ- @MО"d: -]_މj8ϲY|hR%2:<Հ�}euO=Z&oҷemtB*"v_y~ Tu3ս׃ 3}zy=_|h3Rbj<#]=]wەFG6Kp<Ыށo[~ÜyV2zN/;FAjp9f^ oo":gQs"ZKի�;fK .R.zuE72o.W^}3ZQۚ~|-ۜD߂~KyjS re^Y0.|!]I8cckd dqV>{Cգ2Ւt,BF1.rtc<4e^4m&ڄ;s!mWŎ?\?Oz2"coE+D-4ZAEM!Wsfݿ�f>@[.Wz9Oh yG6ZikzFwGyTVMnWņy" eHj_LsfLuz0Z"d24[`d6`/6t @ۢm[C~dG5ݓѱd7Wb#?&k̙Nl-ej9:Rp힏 yh~" ևl9d,hK$h]хв]}t>; dB`q8֜Ιrsh:l,Ѻ}OAk˃2(4. ^<̣* >kZGɪ- d^fZ$lJ>:6F% ւь:%zztC/F;=^9|̣ڼ|G6HW;4fy,zNgYO&M]ѫL4ZZ&%О?�0=zƢ͋5>hxpt&0zc=I7?]UO,z(3g~A=͝zg(kUC@A|Nh׊h'`C&u~2h^K}hV~h4:\jgt[ˌв+uI+zDo}Сdz:N"OKg4<jN6@6tB86 =[*')W0vC3FoӾnZhLnѱo* 7a3B?::ڎy7 @O_heku:4*GT"#t,BI".!0f6'CR^t\UTS P,qC{t˥rY'ڪNgΆ{BhƩ7׫!p }^P6>ЊGSI]+7jr!L &45y+z]T:U[ <hs+5Yc3tA' Z̒ʆVkAoi"eДuV4qd qeXMk Y@Hk)kԙJG?r'E1[kp;zB2}2g,a!+e]ӵ&y~`.=?ĎYC"†܊)A›7螠sҥc6Њ1m[K ecKZHmWJV@ j6Ԡ;oQ!2D;Q,]`Ȥz]O2#ھ %p+ZTml.j;w_h⸅{:9r=fti50WBtI<ϱ[:Y(uDc*1qGOE2Z$=ƾlC;Ֆ B#Zޙ3a'RVK؜K}fFSe2VQI-EO:k4c5NfH] -5&]H-7#7yD 4?ԫKs=/˂)vKNmid Zgv2U*>޾<c hߥ-~9j6iS5m<b2^PKJZ;݆Jg3jh5_آ%H0xa".tZ^Nt B1jGa^}юIbV;h0,V ƫ1Tj %xyAf^�Zdnq4NSK]fW3}>#D{gvìᎡh%FG=<_^aX=e|~i/tvh۴y@Q8LwGfݢAsF3<?spVѣ ~?~5]&??85hˋ'Ӷ_FěM[ۃ<'-^.[_{ZМeThm6ǣi}xm-OT/sT_A׎@ V.a!O۲<Fͬbn }mQ'D[*PmCO]>&hգ#N4#s( ؆vHm-:~"͗Y!qati/[˰aаLF~@0Ԓ 6D?ኄVtEKv XUN>Sc2zñd~}N}р6jI+d6:=<mASE#& T^Bs0.}ES )qœ}:@MэZ}'>onN]|BM4nG7eע4Y=@c}MkMyz-w ~?@Xf njz}G&_41htpG#Asc/?t{t{6+<TSt~@+'tsvu~t�Nrrt(G4}7WuPBk-Z Q"hdNv_;Vh:5/AFhb)x#Az<,;z*"0C6C+YShxRu~VtJ)xhMK&knzpof܆[0 &ujAh\J/@Se.ɮ,h�u+�4o4[A{ME)if =\f8mwKckyVmH-qtS w)N&CS⏦*eRDTtS]-&;mE{hzlXa.nB+Dc5ZWA6h3_d6Asq6iьͨYд:ͫW\s M!МZNfV܋1:WCB4R!hM9+):€+gheCo9/jGOf:eB'J&ԯ6&,1iVM-^QŬi@k0xݨ;ǭHэz<2Yc-󢶛KdNnY?jݟcg~}>Nw [,B7^a~> e4wy|WbY<5o0vR=f,E}KpYKsj64Z Q<-io(eߗkjjjjjjjjjjjjjjjjjjjjjjjjj[ Y!ei;LT(3@nEKCz~/V;e"7 ۝0$zޭB3.@>|}fF�濝"l9E7i׍}#4yqU(aq DOU2ZCqݥB.sfݖV^튡=͖]pTJ љD#; R@Mw"3S)Zt5(`yjیԥRG،%dHRVya4~$EnBZBn̘lJکV5\eNV09ݩ.^PÆXN7P3dzf.̦3#~Zm+f_F nm,UcԎZ_{ծ9':Tneku t]B'FzY3&KQhA>iҳwjIQ8'4B-h{9ezaM l!1]Ooь}/Jcn 4�ˀ}v>#UƦ͟qgibUۨyF�sMr5[r< ѽrv47Ht{?Z@ \NG//_ zapL&̨_ hx9m-/Z71%цmfʠQh+YG5m3>-ӡ5 Յ?<XMIѰ?b?VAmf&)Ijv жg/qvL.2zC͓6F]\[ j@*y' GЯ ak?BɀKf:J綷΂n^:S n" ݰA}8iiDMV5n0r  brgx ҒD}DEQ{U35[hJd߃mۜ m>2`C+Y*0 tADG> *>КC{}0r;vZv:P~&"h>iЄ1?35f~1UQj=bD uvtCbO vڣnIѮ1?�mVyB/yB-Lv m�WGn4TFZkق6}V詄e6[FՄPO4St :Zi|,zݠpQ殊<0h٤cS-ފڔ9ͪSJnmNJ{L6o:}3~0z0q<d}kgҝCS^=#FTwBi4b1|&h93)1gM1rn3u2 GM5BOзFšz {I]͠Fˤ#}\^nu%)ک~D4hR4 ٮGE[3hӄph^mmt׫z&-t+e;:ǽ>:rRtoBmҠ'5&V$TO=Gӓ..բg,}!^ m3pʚ}f }Mΰ 1qßI+pALUzCS:Q=] ZgjM-jJbQ;#mjjUwYy:zxʬ;v>9nk&y h7}<8yݯD".}c;9La~ fKX9,ה3l q13V<Z-lv4)mtkhFh:qzu̗`sMMMMMMMMMMMMMMMMMMMMMMMMMMM Y!ei3L\h31n=kBdg0Y ׏z77jnwe՘O@sV C> [FcYp̽oq<gw}ƻć5J;л2OϜ zDw)fj/`E#&:ځ7DEX}Cc*VKчТ7*bR>w9i$PKl>r1::b>N1:d}hMPb|S^2 -^6!zjEe~On~UNs*tv1ҿqM4ɇLMoxն_ 8D$w.Q#4"@mt/qjkaWDGue[Gv#^eЮs8:P,ˣrh2tY=HjCnfKhFEQA=t�z8c! >A~2|, -G=Yhj-3k>HG݃//3z== v9FhE\dސ;~2h?In_t>7NE7g`eE7yD~ce9j}>2l[#z*nC[eM܀1Κ?X:&@ꗗ}:yDh[Sen 4+l%4hգ�^`cIj  E+:14TC3u)6«RgGS?YЄoo&vF[{@j@DK^? v4UiNvLPkdm s4fσgmmhX3I̴gb6U԰5vtLtB 7h[HtHo7=m<S6$nn=L6qhn '}:'71Oj{xGF㒸4U@̭:ܪh%4@ׄ{0 WQƣ.z4 z~Rs˃u<h=hs6==M!fBj|_BdF͵Cߧzf.٥l"_I#SV[ʍ=T$4Ҭ4'Ej1tPWiR�os3d* 3 5+ܡs@_Z0p]GK*MIŢ(6F'-w >BK,:Ьp^31OTj^`!+ZQQV=ֺEBM%ac8B?CE=(%56 Z;5ɍN7^::@.=WڷK6% }3ҕ́CuM WB(@f3Fˢ`btNivǤ{!rkaFw&6Dٶ<n: Z4q%ABsY44V+ivo̗DQ|w\.I-XC]dhWh9y,C1 }t yKE_+jRf1gP_ʢAeфA[Ջaӣ-ѳiBBrj4m7:ȥGƱ>Rk1t+z`B4ɩ)v3B+EI$ mU67uusi+kМ Wޚ+QgZ}%셞s ڸ-VM�4 Y1MˠgA%Io[rs_#p`nfzI===zBVLO.an9؀{c˘Qϐ;Q!I.3l Y̨׎-ţSKXV^Z;4P/]SSSSSSSSSSSSSSSSSSSSSSSSSSSv}fY A=ڼcZFI[,lVnuݲK'SqzeԤbϠA .sQ<QT-s[\a+P{wڛʢnn2 zF)fFj?ϡ hudEh~đA__&}@R̄Z&j2 sqdSSmd+DFΡfHVԜ\|Ӫf򥸌ZnlN37ک3'Dmhۙ ɗ#vo<gԊ-;߿<%}F,VӜn#qMx4W:Yl:Vֵ̱jKaSXC}AeQkGژԮhgY Z!~Mj?t:= >�уs.>aO"6h֊sSQmhr-yZ3hslݟ鉎#fC+"-&EE[)3ZNg{I?iW`ENR_y@yz%1Ǘ> #}~fZԃ3iv0Ak/ QȳYSf{ähÈEъE[:=!n>m5Rh«^hZ^"4Ύ&~ {ENr=+RS~Ж6ܓ_継A7mYȌME&an-aVtKm)MU˘"M~?JU ЧywNIІB :ly(p~Dh$='v ,NSy`{5f}A-:uUSQW/|&!+b& hsf'CRs h}�5CҠYyE gB FI3O]3 Dֆgm3Fe)oD07`̄: :頳62eh9fzڏܠb"K8>b&>:& =?c3YImm7f5:= dR�Z34pMFZpPhe` n$Z 5Ol;ˀ~2=0ZšdhW@+twL"tcZ'|՜8ߕyM'=S х̉=z @oNxu8G4:jmTh*n_SnsS)fЌUHB|o'bo3@6O1G6& ASO-b404hSvm~$@LN80~HJHѴz+E_.t=[: ;YmxxB"E'2=K[]M]9%$@+޺ѽ9"AJoO3ͶhѤ1zC撓:ѮbRt_*?A_.Z1F[O:xf ͪ ͩ ' 4дzm e.:&YG_bW2ȶhF}av&)GV@ShA" gթ}-2 K$1: WBs~4{Mv:#YÉn}KWV:Y:4Vm]гzT'GWo2{\fS2{Jny]70ShCB 盋~B3raZܱiɖ@G6GwqG4s\yH4FU�U d5zipقzY&!o=9:'Ycv}fY AF=lV=Po�C?l9qsZ=9N/m&BndnLT4}pa6ܜ y>bjy׊%]PmO]>v̥ü Two?o3hzhtr&V}X)Z} [lIgB\9WCe3j9=ns6iEh,y_#:,^ il|{قqa.~ېܛLx_mS-h4x23'm{5S.uwf9)�͕Vt4m mUh#ն24Ǩufs>`;QA63q1eNh u$:D 5,>gcxMs9|4"7XP).0{'2x7ǢThGrf״zМ&&z>EWUYVt>Ѫo1YmH=~A i藗~/#-Ef旁/=Rij ̍<\`~~I$E wj)ZQf4e<պ/0 Ff 21x3/4Ύ&~ F'XԎ 9W46l_1/b4^,\;*`)2?h@рeGlv>`njZ>&s[t56m9m�qI;{־l#Ѡ:f_9Gzbhciѭ:~y_N$F:4f P5yOԊh Ot<! YFg=)NeX}3zhA9sIS ljЬ9%UK)_[VnƗZMI/F.97}G91/Oy=h.hsTml8=0Ƹ7E}J<ʎT͔hVJ᪦DxF\O_m<D}Ug1Sm4[` B tyT[VGbE[[g<??v龐S̀y{ jF.F 7'<O¢~FX]tֲfeFߵT~3~Vڟr=!ڜmF Юh;vDkͷ{UB% }mxxӢ5RC7)-tg7ƬJ ә�Rv 4[ 99+!$/z6JH-n)l96/Ihf}5.:E<a?g^,G#,@h q8jwth"R7G (ڸ;67jgh:<Z�RoMRh#3'E;qzE-fH4^yWD3jLEm46XњtpnYuzz@s^;lWTꫦhV}MLLN>=kMMwsfSO v<Z/}%>-i΋%$z@sWNmݜdAoK%;I>T˞]hs9IV4DvkF8hMdEoZRu`)emTtprh�8b37G3I.Xv 4.EČzbbbM^ej]DnC]ؼ.&"R+'벴B$W2Tf5}KokWC$wm܆Y;Rwa]6o`kfԤbϠ Y\X-4jfAV6.v vҫP[׼ ]6N'ec5C3c'P }Cںz!m]RmW[tVѱ2jhNFM(T*g,l3YsJtb5oNN%BKBhZnN]MBn@<imwbs轞Ys2oNE 4K8݉c507V7?L]dE"4ǫPKG-h.͊RZLڦV;ʾͶ2hH0:PhEeADhPk .ǼAQ(4ꁹ}ãu8:,Z>m( =v 4S4LǮpsp](-@7E藗0Ֆ2\$fm4e&,gfey@{Sit>71//vSy 2-hu{'Giж"G5Cp=m'a^ -6q�-U[kh44P# 80 }f\ t1skD(h⪧,jW/41qAE׆6DC8Z9`'Zd^ZfE#mȼ<iܠݜYGKJGkZ`J {Vϟ<cG'j�jہ6gCM5JVG>IhnЉѴZXǗ%1~uFeN@lڜ'1ivX}: = FC58-@4LAhoC+9 WmZ;YGsEs b6Ʀ>+lݺ}>hˎ| [}B3mQ?'EW*Mn +U3RDh]ؖԜd*$fMh"ڄbx.*D')_e 72Oy~~Әgj9xeI=nq~ c!Z_&{1d,VzOZȁ~Af3@kҨmy@4ny_<Z?]{OKނ~6fq2j\:644>LPb }â}rI7=S<}9=_= L6;ӡ/Ӡo 5M� MD%19:zծfVuV=$Cl1Kt-E&ͯ%. ѢE=![e7:t앨;cs : "EohNv3hx92/ 0їlhD7- }I T4h^ex-PhVͨnK9e ̨sI5m6 }Y�=K7μѷ}^=mcF2^3:hk,+dF-yu16zP'1W5zȫpf9zׄ+d3f1W4@-mN6WRfu?g':ٍFdv h]ٸW4F&Yi6W!FCu1#yb3k?%#S$ 9''Ymua &~ԶKQcFfTѭGfܣ։ ՋiP3׻c&.+21J{!2>E|\uy<qMMMMMMMMMMMMMMMMMMMMMMMM?]`9XgCMʾ kN"p=7f[L54qlcKY\X-4jR^˨-3#y5};|Auļ2-PA�m|cљ&+6̿Ω>dCgT'Ebe-7Sl'93Ku5gT̈́*eNN2fۊBoRmoĨ韴BoAL7ݐ̨mnFg6nP@lS-3{ǛH/iDjt'vZ.@t]FƿL]Y+Dw#|]hЖYQj[]E[kGu-f/5{zUT@=ajGkU'mjFsUޏO&?C�qL�z fs_Q{'zm F]#єG6j2Հ֮hCj n!j 0.?Vǻ&н|Be%{e,&ZGeDwD=6KK7?~/spy*~OVN\Z?5@+d3EkSF0=Ri<?ġ>魽J?gMO&ZΘH~@|6M\@CWdChudy eGs5hEt"4<\$hv̂IB5^O;i8U)MTH6.BQaGMF$,>.33UlFϕZw r'%}πڤESEѨ{ ș9WxP#l[=G>FOCbì7Lj鏈\3#P9sz4V'@v+BC5!Z͛-jyhmCZ9ִgU=fk|hvTΈ(zr{4S{K"+^<]n4oжLhjKFMnJh_6u|])::Q73:9kf?:M9 UŠ@[3"F_s-!Jgpk 6̠MĘYF6<Qz^Z{.&g:ϟSKD"}.}n7v×6~~Obmr 6h/]! CF}á/h=@'N_ihxJFECMpf-}I`f#L<m47 MzK>Þ ån͊2.2sat-6c޺GZlU-VO7v@ G=ZǸ@F7A'[+qAtvu,MZUߘ4oh[Go)mh67D+mʛ ,5@wg -Co)~ۮ 6wYX TiOlVͦ3ov!zGb6N+jCk27:T_&u*@[E+oz-^}&� sD`M=3)ՊCo2hN�}-f\WR"mzK+|z\)j 1P7s55IkS~JV&hMkMVs~^m|WrFƻeF[^4C6yF14^Hn>Arf7$4+~!4D#ȥH 5x^Ԗ% KΦ.wez5&ێtrP3F޹hlu0Ukjjjjjjjjjjjjjjjjjjjjjjjji墨#;A 2RPd[7u-x f!?pIq]TZ3g,m6bAnogyxpsÆ.f zgES[ZnK=;t^HcK.LnANv'ZЇC9[`CSK;!: O}h�0ggC3|TRdJRk9"3#GGJE):ڂ>hcX!3aZ ajoN~PZ6{=s.2b}Ͷ=f-3x 3LMF@NUi7T_it]Z\]` !z[P_B"lH5_utwm] (.ThJe~I}Gޢ^:T~U>Yjg<hš2�?gMgB+z8$2zh>΁Ch{9u@st}!+GC5r&{ K0jzѠ{" T�5]u+Nw}\#ح ,lsvն2ݱ3~pu _B[˰=H×^BLզ]ĠO] ZG BkN_,h}ߋm=ӉVϽ _`6fۓ}Bp|!6Sh-͂F[z'ӥ Eh@{, MhE Ӣ"&'=Fk_pif4R+MM|(bkJ\K7UK-|ҡfo;4;^5?i[XV4Y!9xiMnj2ݢS!ƶM>XcV‰Io>Jo\Db7MIh91R :=XŠC'33]>,’痥 [HKX-/H-/ PΎVzr[ƆSfWΈ؞hWݬF?Fw옢thj[zMJMfI:'V'(&Ѐ^KfFG^/Y7;:GuqҒsLh[3`߼mx-P=gHgW?Ojz35&AY|$Zy>l 9 ueL} Ʃc(:tG cII"vA?ݣNЪmB_ϛ5Uà/)skZ]xMR}6p$0C웁͓zBHN`6SY==Z Vډ9+Dtޮ =9rK{uiEѴyX[tK^ݶmL[shV=!۸1es hN=i]԰AQ#[nu@cꊖ(Z~nV,Ec50ހ;0.yʅnWUmϵ:ziNltve-@o6-sД: z&#O=^eѽpqFm9tM ݪ'5z~Mgнzˡz˪ Ś kZm93BsМ:Z} 2sf ݫۭx!@'6jr};TuN2phԛAzsCꍎaᧃacN&ۈGǓyRVc ZۚѬ3Lz8] %2O͂f. h ?e`㧝{>Jk/V3hOnC4w heE/A]H zkq̥ћU:s zfeК|Qrд$weћҗ9&V:]lpkjjjjjjjjjjjjjjjjjjjjjjjjj&;#KkaXCMھ Y c%O:)~7|C$Q,h~ zF.¦$z16cΆ.zgGSޭ-7|0t yXDؼSe]m~]=ފj2 UzQ{<|f9ՇMMDrxznǨ!gdfY;9ԬYWGSEfnyfTєvȧ%'ZB;vyruyv*Y xJ1N3uf?9WP~&QuL5N6$h,6Cnh;^D#ՖAgۗvm\ zB[$z/7Ǡu-A 7j{m-{Ԏy6[G* XT#v \ZTx!v SesḆ>ߏm%ɫV̠m衳?8 gq +Cͬh @0hCawA: vq+{4JA 暥B)tnKWX:<ZFG&^x4xE_,nԃFYRN'?{7E~1Zon-4jT> 5~/ 4,FwǺڷI'_/ڇ7f)z<؁~v])@S84eBdAMẙ7K/Ạ.]pޓ&`(VKcAךk/ʂƝht1_!t~Γ.nG擢t G˅]D75nh_=l .D㿷(pc(%uS�\ljaEr\;t�iNNvSh·v?dl륆?!.šG%�u͜s҄ehD'7C0dDhګnQ!297ppNCcaQȎ)JvI&6^<gonO&{@ LȪ}.t 9lv1O%:%:M %Y+]fQq-VPwhWUs ]oc< G fYm> EkRϻpWY?Ojz0CeZ%B?k@s IɈYGMtqv.q B<wIsf q4hPrMn�=} 7hD-ǯ7Pǣ/�Ehe~9ogF_,̳QIzꛆVyROiΌ&Է [G(΀F  팾Q̓šKh %7:fhVR"s4̄Z;oVyьz4Cv͜{ҝ_m'26OJ%U%[]vy8ѲIE7d7mI4:�zx4K^ Io>zilVUxӢ639OW =ˠ9wAnkUdmLܡ^S�[ܣ6~r krÑGCV=!W̚Fk&:5HP0C_Уz^ˠCNkhhCf]=, Z e]82H3@Ol < \?z`ܖ<ˎw'4l05eGwjqN2!1h +AE{4s['^<Gwc }mT#n4(j[Jz"@+S*E=6#hr]S;WaՖ}KR`+%JLy̷]{v8d =E‘uP>s,}{[Kg 8/ׅ.n '=@rjV^4.yU^:fR5X;:; ڍ*=ieȢz%$P paCvAH2劘{aAV`"47xXԦT,S9PV5˪i墑Sm1cm+V }pZBtj:|?&Mg4O)f 'B5Ө}t\fb:ۯes.jfrhSXp ](NFT5dWm) {bѝm^NՃ&P[7o&)t V@4q΃߭f.rT;?nF."лU7W@jRg+@+:D-F+E+cLLh/9 umƛr,?h>ghnQMcф\G0wj,04Q]g };9@MW9B8|z>s"B3|\NVCոxylg4+5zTjyyy}}-m|£2xQ//{d,n/} Z ۑYԜr:84PaMӱo{7 [3[{}2hlj~Af>OZ|Xr4:GC ژ| "527qfO4b!BؤhLM N46@rܨh<󤙕YV񓶢C4SЊѝ hlRV}̬<}V5~S0hCE4L>Z8&稍Ə}7_ }WQ<,F<3ap C)j_a9=)"$}((7IjO{mD[ރ-hΊj99Ue&ݫUO а)wZ^4n64N6:і.yQ(|VBs 4|V2t(hY!hkL{(:߂Tv͋E bM=!7\hgtI=c!-: 4:IvWHVѺq1 -(\a4, <~!*Y8 PyTg{ULDKfGg-7g=p'U4Ng4x&Q5+Z~vWh79iEW'M.:TOaL+rhc5<khz*ruy=W`"\hMZ8Bvۚk BCG_�Z F~ m1q⾋| T mmoI O'fZ}g#vv m8r!ԶIcxn Fc@S̩Gr4nty`̱h\ck0vTj,@vȡǘBcmi]ˢ5tE;oN o[Q4: tN7QZnF@SjЦY5 k4nݖBnz# ŒԔw ݳǝJvaN 1 uՎ֗li5l9kmuܡ8fg}M5Y׹ C3Vkg ɠ^3 ;ЛM^4io:Y4NV.V6Sjz ɈV=; twFgo2'Fm|sG<͖wmh/{ȽZM'R^2!9ې׬m*O&;ZY9dS޲؜a|Vi/آ ^FQ-YƸGBW,a^1z.n6ߎy<"t,/tp99z9# -\SSSSSSSSSSSSSSSSSSSSSSSSS n` c`#qAbsd.<khFx+=з^ ՘kO[d!zWZzy7>͢fG2SL$�]L-5l{ [ZnoU+v-4^n}ns&VE}mfxEKчh@cj5+!`f'Bf}м.8[rf.hf hm+dƗ@fNݳˡ^hG}IWv{Rhw# źb+ldjTP+yRKiDYV.q4][)fh|Xυ4WҾl\L>Q '=ۓ%PfT[B'mw7xU $z4~FM G '=a~?XWS:v$3~RSW:Z@]%~s ,9V\}f[zM0h<uY9j|Cd#D+>#1MLh>ɨQFlV3G{)+z|nNsV}m3Xݩ^hyx닉V"ڣ̤~yyQ//ܠ_ srI2Dv'4> El|f~i,>)<9}hf,f_@gRl_J2ߩ5g8;2=A}H&T| 465Z0h͘OeGr"%Zt=Z񓖙g5yMC/4ZhC⎜5Ma*R fO Ak9x莜^h>1:4QI5F1xajM244N'QJt-˜M51bNԧ ̜^蓇wKͩPH D^ddI E/=X6ڮahd -=GsG+ B<>2M%zhtϲѸĠQ`:\}ES`+zGU2zK~tOߋƝfJ/NR_`NfVtr/ӫ50tY+D fDr7Y:&^eO~YĪ! ((mɳ6g r`o4CҊт$9�Z\h%FapԤ'1z ,+7S/ǯhxwDxqBO_BrYh%|^֦Ju&c&@GV G g==%z^&yD BEwꮻAmqŜ G tU#&7׎ o0?OrO̹`mo)tzcU׎ 膭ƙ[A';~%a&3hڜ}AD-̙臞%Ѱ{ ~F7'mY4nޠްZf?rC·"hRM[~hk~L[Oo7m[dnv @ &jBg1k} 4ͷ<7owD_}o&D&1C4IFYm1;rmy)"{Mt^9Ȧl`TǞ|5/l2[)MNstb!>hmkV̺mVò'sMVIЙ[̆dhP(3YƨfufEetvh ,j ϻdUq?spmj%[ny$f8g9sQo[LmI̫j,I5cEf-ڬzq䚚Gy50` 1۞; Z)~fK'~#t 8lys4R:qͳ\Hm3j혎9346hRzQ3#;Mwntz[$t ^I4M>s^}}!t{KyyĢwCv3^y3ZYm04d_:̏؜K}8x%éfn֞'x\H;@WkbUI}a.>phz6sRm["*\Σ,BO|{R-E6S`=d@'POh<%4h\ۣA[HM!S ͘CHZ͙ \hnZ̑h t{v0:N&A3N::V9�\`ҊV' ,hSKЈ(ɠϦY ʆ>y7^zM e=ăuTFEOC7{}hS͢njсmbc%Bu>Yt4{uFukV6yD-PSg{BN`_<^}~9w%B{ۛkt//ˋqP'#"^XmH8dE<Y6Ϸ:݂_:H<<Кyp <r5:ӂ~&>CvIDNgPm3G5gh̲ҖchDvܯ=;џ4.&CICht͍KFj 9i^Ey+ jϮ&l@WQw } E]O�8@\ts:"QUFiotOeN&^hmYiwyP ͉X-/ ޞBlG95=~H\:ćD]I+;Zo(hh: Bx fMmK}jձh 4,kʄǡ1cY/w,D7tǎJ:!nivT_PӔ/fڭM[7]C _R5xH ѸBmNU۽rYWY߬xd46ygE~62jahNmC??jI0hi< &"7Gr~&Q5j$B+~<19y? ϿtI/&>- NcD+'ڨ5[\|KBbWKhtH n7=<(ܺhì9t_uIkнfA?}ǦժUxg͜D?AhP#?P7LwEwm%7fڢ+@qZvsh꣈ ^.E5wjܟOӣD XOg̩&zv Mf&]}fOi΁=_jmfаy~s0:åٿj[lsc14s&ѣmTMkF%;9R xA-}ӡ "(гZКZ[o&͟=0/PJ]]hC7 {6w/Iע^Ә2QkjR'.m~flFFt C&25Ι檡;C#5i]g4# щEЩ͊4G7Kg ɋ؄h2y#\LV2&;ZD+,fzk7b&kNowZrmz9_fC3]lm*Z7M}@t_ڿ~e j zAMYlUShN -h<},Wlyw]w7&BMھ 3/eV$B<˱'~o9A5a+POӟ<r}{Jf#GkY̢wVt95=]JM7s ھZ0h*Q3g"ieQkh眍ןy!heC͌zGe+VZѹԇ9B|K}8xk9 J{^Ҵ9=2せ/AGK-CʁN&þV1A"y雟R˶*2tsTj;?YѬuN޵ GE9Ĵj6.s*54#v|z/mfv.<5" QӅuukƿ|Y.v!4AfOq2lLf'Zlq0kDjњ~PtZhNQ Z;):BQPh֊T0^@kM؜}¡QUX4|hE$ wJ 3B57h.@j͔ia4h] _} ZZGS3}xGRrhqCæ}@/L_+Ån>>iuQ+}2>m.IBJ`՘:]4,h?SSsW OOf5q(7W׫BOfH4ǚPM_^niT ]Ga+Cgp%@wxFq~JжC;649EZRtkv4U!шw9Nm?6$r4nj(4>W3Zo4m Z9`9CxWF>yV3L4Ze^ܜ'3 [GY95Cjlf;%Gs΁ǣ]Ί& 5 ͊]n*Dv9VAñǠuY0 ԁh%CSax(Za4JR6F 6{|h @kD[_*m^SFxDnhAmh& h[,SD')^xiKٮ&hI^ ^5xHtk^.twh}OM '])4"pS,G _xqY=:ZuE߾(4ƟwL%{?hYg!@Y@t2DhhrAՂ _\ґ.c˥ 'I/}]]j[h Brhq,zoШr2E&aE_'A‹/?"rk"An]23jLӫf.ta%CJѐlP/n׋{46ircċ8I4Pk5wjMӣ/|MbB;G}< v9%3@_n =%Scn/'79:Lafڳgs_o}ܸJ |`J g Iͣm>`4:S4M= :-V蔃V4k ˤ\juMC&zE/Yܫ /͘ɌћL]Tl#;h}ԛpfޘe[,7</ '5wS rh6BtN=G .tj37Q#Dc MdFlىV:yP2΃Vmc ͭZj7&#<K6 v�=<7Mj@;Vn:MrtaC+p*+D+q 2<Z2f+BI l6+ڹv o@/<&A/<hfBaɚ](y9bf gA/~^=s~ L3a̓fh3!ܡv6tA5@wɎ.vumؚc?j'=]$Gu^c72jz/чDA͞ymfM9ՇCVwzGJUw5si|vCf\29@2gAp|<80-E'zEc<j'*4'</ KfV5׎͎+$ϣn˽wg> 1iw0'EOnXfdw3= jg2SjbwSq]n- 'RCHMfK͕f~1hjv.s |\-G3�P�͛hR-CGДzQ!/:F:B-Csf碶Cն"kMZsĚ)&ZWa0lM<d,2<d7QBЊA07L3ZAAt]3Մn@3\P轿b3>khZc{u4DOF^-u>v'bLYe@Xɬgj.Ld}ⴢCS)t�sOv ~A+/ԇ 짆Dy7Fϧ,O͡?1e//ZO@wG_ 4~D춣MaGSmЧӧf.th`ZG3CogJ#E]ǙasV�v:׬byN 荌a9:_=jwCL_oQ;.BĢ #$` u9CjN6-\^df!]:mo0'G]-ңCˢhw41jv9'dk#=ZŢ%^f̒QJ$qxI 45jY*0m3ͫhFNՂWbB47jϲxnbKpmhڌ;%CS ::Iq9%@ZTˢB5Rhj?==eB3O]X5SHV #w<7D?@e僎@ Ԝ`y{(gA+99nIA:/-oG JF.mIcim/Mԍ"fBm/EhZTiiE+EV0OU.bfD'1Mԧ|Ңo7]F&Me!4GSm6Ʉ[:j<i+ EE64mh0{vM_Xv˛G5<6Gus[7_9 iVGr 0kh=79r3 =%ccۓ5M5ookF7h2>H3M7{A6!:ZFOCk}hbKIOhi 4NaCO(Z]C ܡ£7MC6rJu_oLusi'tN]xi�(Mf;<b3,CLmЉNm8�m=6YIn`6̳ZQCLuN,Cotԙ̽ZRfnrlnl nq5Ml:;y8MtH aCM%24~̳07>5VڗTr 5V˚lXEljT:h5 7yDsMMMMMMMMMMMMMMMMMMMMMMMMMMM9mWLF=UzI/ "plي^ ;}y769 `ildY2Fw= y15}OCׂ{Ҧդٰ)nrj'Z ޳O^ ]e2"eЬ-|^ _C{#R˪j6NWWU5sIf>)r Xyp+&,W|ɞ葍0k]<\Ţf5rդz3^| fZ# :)>ej5s^KtQ:%I9_=@Adw}eJH-4DSQ{:o)taS-$C6Wl9ѱjnVtE3:wkF+_�$({ҌzwQ<jPja8yAtsm]i)4cmMx<]4=t C`M"g4jo>R2B4- AWefLdhP轻b͓ڸ<;ZBVG<EE{O'{w,-oȼ{=cZok=ܪ{u&GkC_L$@#ܦ-ZЯ$Z@hš_h$}BóЯ  " Fͥa[?5cCS-v^ht22ѯ,Z?Q_~&ݟYִOS=6wOCM7DInˠj9:nԫBKstԨY4u#9iss<ͨdƼ\ڬVOb6E@^|z[6b^ܜ ~8 O~fRvI/F?\NqHUgGГuKRt7J),YګIV`6ԥa\D�kUhd&hq(L2EKк2tIKfJ?Lɖͨdh-G7פh91j9h:#Iu:Kx1tˢWc\,TD+G>SP+XΝP? mn;{W~XOSgozʣvV>CM" &b!<T@{sfxT{0gc$5;F w0Zorɂet0\hiD[4*b߰6͎BSecFM'zo"d象)U@_FC^Fas�MIѴh.à7f4SI RM]hH6 o.نNnF�t͙ۭ:L_?8vkCoitA3/uPM7(0ۄ =кdF75ն;ztfn79͹ozڣ' =&Y~{btY?Bt2-h62:ZF�7 )́hzS14�^Ӥ:Y]Ict"qf (|̈́6٘ -=:'0+ǪnPzcפhCnh<VG_h[֬QX2fmUnfb!$7'F0klG˞SnP);9':WfJ36H'ZBk�C$Z lٍ.vgufܾ9pIա+J^!C/䕪t\ڷv oƻ.qx˺ftà;C<&Yƛ.Ǹwvd#"dh}>5^ۂY؁^J ;%./ Z˳ $4SQhCUIZw:DL}em<!PNݴ:z'VpBw̓F>wW/;m\~_Gݽz .cxi5D+Wa}И6U}0™cwdXr6V<hae+`93 = U,lM/-B5@QNfytҔ{׃:tuSAh>Qteӡa]R@.9b̖C9Tӵef$ǰPC3ͺ+͜^hɛ*}t:hKY =`&IwyD%f4Vk-ӛ;xmKRsFBhgQ Fr}>E>h. }D'`Ej+zuZ) $L56Oj~uu}+-=˜::X8[\l. 4}zyOԜuliyCXC1sW U6FO""6 COaW-"4l>__}Ѩ:VzŸSWz.֖6zGfBBEIn&ֆY}ϩ=5kSA 3?uk8Z6ȁ$r~c΂jT\'"y4'PǠ1%G; μjmEz844;0Ǣz1hlxL4nR՜J^G]sj=Ԭ<jsztz>!QD;ǟAׇ{*i'T?M@΁Vhc>O')GZţ's tw04fRzw[vAf`4T3jM24MMk׍6 <Z}τюi$Eq(DU]ҥI &{G|xt#GBX!ǗC?==%*EK/~ E 9OO':n;{~zIrBYI="!'~us], &-*V+^Awo6J ߡfrѠƚ6.b~GY86+(Zh5>\4*拙讕Yf"Bk)IE?q1Mq[~6@ghZhP3M&[ѩM-h0/Nl]2| zۤ<>jnw.6ԷیnKR_ÞM`D;oAFnwcͮOMFi跷}sGїGgBhf,ZWf):6K "CQ?i$:pyӘI-P'7>huf 7Nt^3M7Z;}sӡյ@ױMcy4GL V7)ڠFCo�zNF6w{S̠Q0f)Gnr2+7N./DţnVlG˞R^vκЃɹ:'yPg@4o j5r<A{glwyϤ2dQ!B诊B.]*gcr zyH6D/-] ი2?= <\&_vK[1Adx>KDKZi�"hg�y7A=v1 l?)˒M7`1%X@YtY5?]RMߓUZF0nUz~3Fy3} w I!GW`4ԮfM5U}p;*AgTdP}~;:`QO1CjvMɨWl|J0XܠZA'{G6,W ع)Xެz;b%K �c]m54;|im>D΢V;z*f4j\4WFʾsUSmӣӨ m^Z<eTΈN^�voiбjZI>G;|qS{,v_{C+e&<uzZTse#Vxx kaCOW8M S\3>NYgf-D%g+\-.$ WxrGvG{2jh^ӱQ bܖ3к?oՂ~Ͷʊȡ='@4<x4�U0O4o$XWmZt3D'z.6AFvh4VgGӉͧUd-F{_l O9Пą:A~fF f:3ZY|ф:mɓИgvIDυ/0ZFfMxDA6򺜙wZ4RhGSɊaN?<2juȀ\ ˡ%UZs۪mU"]= _Ӧ==/p9ICuxz: 2+ôEM2Sa۰/F; qeJuJvB4vV} &{sIR=W]ڏy |HEEVHtS]t;�Ԟ(YO!՟i]if? ޟtr3?Mu 9RBcwi=77.OZw:'}/Gvs],6,qx'uYA߇n"Inفh/@ jͭڨwdAFmpaQǁ&46ªɓh\7 =XZjZ8Q3kcЗ9 fԴTj/h:<č9)Ѹ-B?qYu&4˫ghZ͗4&l9:5%юQ5͐īQAIutY6ts�A�:,z)Gn�/kP;I5=j5[]ܤߥ5c΂VnrC_ m/qDh47v#̓ :ΣfiӐ4hCbJ MZхˢG"3Y:$=O6a͓[<SsaB3b߹f̬3 FYzq.͆Fn5TnH,fشGV3s!OnVؼb̦`9 ƞ,G˓ Q&:] tsUB$MW30uszd=ZZ K5{Z #VfQթyyH^<!C m^ >5555555555555555555555555555l7^ev  @ w_Ω2k8Y(1joب]˹Bd6e{=3K56t1{ac3Lnj@#9tQ@ɶs?%4mE-fr -͡`xXiÁEkc8}:}(>hzxΩ>л C;a>z=,jJ}p Cϝ; o+bO-h̬hd-}tp?t3fZYnCMmMj{iz.}n5~SC.)`[ʾs$\Tj[y4~\Z0gM6BĶWNvT΁V Þv5OA{_W8uz~,2+V/_ 1jIUjec|Z9Ѣ@gYБ,iZ#li>}p1sn93\/J}3@hS$FD 57:D╢9艝-/d[Z[=&3_L5F>NwՙȯӶiʴW'3SOњ;ffʊfԧ(5Dfz4__}Nf@*BΓnD' эd-hHYtU@݃vډ_Wj\8r|{1qOt-jDM)L!qۭ4vEqGlGYz`gxtKh~a8n=m}Ov:MRQ{UvH"='xC'h:4m̏ݾhQL{�x22pJ<ʡU"4/q2hJ wż13wP˝U%-Q2 +FX2=>4h%GvղCV7+/Q7gY{>DGOԟ)S˂shӘ0tWɆN+. =V1Q$DvU2w辉8݅fM-9Rǚ-h7R.͉Vf5c)] #9zTh̉;їKY;R З Dߑj}084,6̗1Ѹnz4JP2s8PbF~bGŇM xRz4&hFmEt͐hNՉѩ͏&EfmG3>sѿpёf6Q=RbЂעv0Dh%0Alpbu3Ll D !.fhN {co�G+ΙZ#D0yhf!:,oASN4RR="z9HG_Ǔ.hXjA<͈^+O3V!AM ztJQ=y4+ЍHR =<2Rcۏvn2ޘxveyW)54?t4~YDGeDDf/Q@źm Zk#[E2uKb.VcBo<ѝ˓Ec\W١w/l^ "B/DA{@C�r!¬2ކbitDy5lҗc}A o<*n1jo] C۸񔽵p3رzCØ=˰&k гʚ1ZhSJ:$CBt1&^^eԱGέ>L];EԳ.A{OhCSB=0� C }莥}͏Em|ts6 lL~�7Zͦ>8?Q1hDP;j'ssKׅ.a~oWo5ꏡ\>)Yӡay=y>EB4Q?:RG;u $]pIG 2 s`7َjWa8f+z'DGuKT8M4Vwv,2w[wT%ưL%#Т˅β>`#Y-j6DtaAw1]G2ق>lV mhkGcjq%=qA|$@ܣOJuxPӆQmu'3SO ѯE8nB/Asj<_9'hh$fCI3ѯRgA]@zt O-"�՛Dl@t͒f;43DSj_ 7 0Z{qt= )VEȁhzw|hUp|Gb̟}>4]Nqw%c72{QîhѾ/Diњ< z%%B b0$B"u0fN5iS_CK̉PSx%h:$5nL:}t^]Z vHkL98Н[= ZEjoL}J&>$CO˃tF1q0|^REdöqOZxI6͟LC>3C CPxv5X%ڕ$h%lI|CgZ"Nf GZ\8'ڻxՏ觧ЍɷtXzn1N>vA =k8U'BkM*OEZ躄=Ύzc]n޶&ɖݜ콖Pǚy/Ծfef/,ܱeThMFn#4'CP5v,Zyɂ֫F$,dfqReL&Qh\7 =U_Z)F=Cu.FҗK/LMLR4[qfN]Ѵ :SM#̤ڊFd259̔ڶ: 3@$h{YGPs2iSmF+9oC O 7VЮ)LqΌ!:ΣF+4ES-QHlSn[:'Y@'%1Aj<I"6OuS(B6;Ws <UMr`Z-ZGlM[*>u򣋚ӠӓqF;@}Ŭl@/uΠf6F-! iќ3Ĥ)Ӡw~cyJlٝ:yV]-8*?yV 8Ճ8f7IޔABl .fNк%툥̏v-$G/-Cm&|u`۪S px^0{<sKr~kED;/(CgP<~x ڵ(y߇07z8co-[lµm7<ydck52qJsr=9`�?áYvPTMCr(>$DSBv? |ʡzsceyՇ6Q{mS=Q0D[oS˘yRinضmѳ{>y!2cה^y~X4F_Z-2[E.;N4d29m(ky 6>.4kuӪa45~qUNFGԌ#)ZMnGz(ILFCэN>pf:)@K&͕.6 4W:ZxҜ6GǪ]uv8mh'^1G@cˍe3Y=B-*JfϙVK3{ iXC쳶mɶtu_hcAZԨà fi 3,GY�=- _)LѨ 5]ih>艝�ոx5485._ZOGCkKO<p|fцu:>52Wkf~]46S(]#ѧ 6z7y)B�=ŃCG~z5$C5D75l_3T:վ hYviX2?- 2lG"h4hN: PDhrq$GBWM;KF4x,ʡtO';&} 'rJDK%'@la�nb_? &}fI[.ڠ-E[/Fm^lٳ:|)ִ-l$/D-V!?#̩wm*M&Z ?}Iu^.p$)-)}4:ۤ9;=C?OxDC�VAfB 6?tĨjcz%ZRWf&}5+9ۚyЙ>0G7/bsI-/]i8q9ӓ7iayb|Ш~iB? Ɍ6Ztպ%1߉vfjL!Nm͚Sfw]o> ; -7'Bj_7K͍͂[dNa&Bs:G[;%Dӡ}5vz.xi&UAuJFU#Ѥ9#mE)NM+FS;% }iyTt!tS?"MLMt5ѿ`\hZЩhӊBtR{Yqfm]hqR^!N4T_7 i΃6ao}@lh\SO{d 8GN`f葭�YNc&;ѝpAЃ$@'4+MDNIt:-u B'V_0hYSy9Wx"D65xq&Dj3qdIY+d1@5GvfiL/ʹ߂@7fX xRWboI3ToXsVkehnv~~2V9gTmhk,h<%fzSh%47EաU* y;A@/bvG,dvm3;ؖаUۈKCAm1~ӷva+JAupёAd=B5P>=7iV`r b \dF@`^;޹U{IBVhá$L0ʱfL)R;>P8 `)Ez+ `_ ˨FO,e&cYW#hsEfZ`>cKzΡtՐÚ/.cViY6;X 3!ȼ|ĕr?>4fSjGwjcϥҩsٍɼ|1Z݌葍R^3U=1")hkGzn?*b9tK^Cx3 эfkǪyDlh.FtZA3W5COjD36fBKҲ͞qWPZu>َ͞Vfr؄z59ݾnM#;MtJgG׏>[g_t,䇦G=H @Ol&&'6ѬG:<~擙'~E NTzҡ???S&ac7[(qb^g:gaqffLm̃6MP=KRhOp9FWdfQ[8#ׂ&O 7)/̏7W=}4P#$ >jp0@ hP>ch9\ >5e#:kwD r,!jT<<Q虍_^Mu_ݗi@sO">G"'m-7E^A5jN:uZEY}R?$$hfS~47kCE[; WX6b+\t=HuD} @XB9W1ibS 2[!WjE: yFs_5?kqWcUM?enº_]y=K?==Ѝzi|ШC׬}!s7zZ 9+6 3'"99~j[B+1)Mxs }l&YCEQhDIГ;ܻDh=CJjN6A&Rs2nNW z%9,Ho @;֬: c:9פm% }m ̌N3P3&ƾ� &n&TS=}DSh%E&f-Dǘ_Rhv#h&s 4q ars/ahڜeyu8GV9͠eD} mX ѹ;N8|NgCs)vNN'&<v7`ZXsǦh <"1ʛ^o'DC=Ĥq%\lGo6jhbzi՛!wIs9nPZxg :uv5jJճ㹝EʴЛFI=69U(`6Uxh%4Ѕ̊0Ӡ5v$@4htqk NA/iȬe<|/ziRn@jm0m)~�\;f wNEwP]m[R7~v/bc/$D!&t }B>!xߢ<GcIHcvL~*ɽVgv  mT)k!z,RجO1W)J ij`O)6zp<)iU̒`t>5P+9Z|CK#tXn6>O?XΙe4[O0yŲ3}(44xLjc>O9׬a^|ZK3l<B{=VLn*~PdK+~$FPyڟqL?(gI$Ff8)\+G z@3өq>9:" AO]d_tsu6Gvcc]V4zmzWfpLz*$ B÷n_5 >nP3g4_<ZhRO~dQh4[:F?BIf6.|Aܤw,Dݝ~<?̅Tt1|ƻql>Ѧ<ШW2ъFf}qP#BV gR-D8ub4eAu,369?.H ѯSyh 2k~"xhVچ}s&)_Iqdi"[ԯqz6yd2??W,$6^6ӈna]61:%ꏞ~A]hRLƫ)50аdv4utURt薹�Z0h{IC4TǭGE_yЄڧmuڂPKFj+KaLF%xߚ6* }Q["[|I#4DP,T3͞9m>N<D]=NRsb@^ �95ntѬ^7d S u~ݲ~4⮟}?4:,A{E�sAG2RA|01fFmY9Hΰ<M!hUM6 @sfbLhtCA}C3D}I_}V&F:*1<&u&ZZ*?+==*D{VOOO3OF4>5Dzdz=fj&^mzCD+1*#]qhl@߿)/ZArF+9 R[[lN6!&Rs24+9:^-6'D+$jjF +&A% ڬs\8u 4V/:›Ӡma N64ͨ 4NCP3&ƾ#fGSMM!N47j/×dO׌݆3ׯU]h#c5!7w:zY�l a~C=4'Bjxlٲ)Ѹ=2 ̨R+d҃vdfO4 ::86:U!V4<<\xW=^hheAlCEWjx4㊉jnZ7 u" If6_Do65Ҳ&՛MjnZ䆵_eʹٺJ7Ov62n6IMbJMy<<EjhAE̍ZZ?-I.g~!'鎧٦54+za3˶~?1l6mf@ěű!k'o+n:^Beٿa6xY.oۓ4{w1}5zG6~ϒۑ&SNrr<9ѥՇ6e_[Y6l$p �/>``ZqJ̒fVRtN5;j ļuh%zn0Gj͌ROKsS2ÁFㅟ j�uagÒ͠Ç?Q Eˡ=&{AYSE<ɪtPf&Rsh:Z7xlΎv<MOQ8^~wN:VTxoxKN"shcδDho&Cm&g7.3ӢjDݨw?#MClQVNpvqQ=phSG8mUǙc$賖f@:umG#.2&FR. }I>:g @#s 9Zg+lETc&4+|:glV`NZ TGB~hTh6B~~BsIdB+}øH[}:NM2_gނ՟39=u$cƞ3́ԓmԅM_'~AզOzAW6Ƣ_cjVWG &&Յ%OÈ?ݪ):^mQ2;^-N.vж5'�}zZܭ~BWQڸ/R$3$aLhjj #y?.C}Jg} A@7bӢm>yh9&:|$u՜`Ҝ0~v'PpʌvuȀn}σL{Vk>eWhQlhQf�s.lL枅' FO"̠Ah:!L @{33}0g}%EUЪchVy&+u0DiHF4j|mV}SAܫOa40j#D0E!vր&#zhE8SIu[@N-\.9P{Ԝ }F+19:[lNV)Q컳[J=\$1L2i<FEЗԋY;Ϥ—84lh3aDj6Cʹzh&zb.Wn40ѿf}E×N93W8:,Bǻд:1Yn4Tcɴšh 0r␷!<-~.ڞ6~[h<hlCәKShY4UO.Ĥ33ݲv8MVF+ 9iF灊JkZ7WHZ4b2Jf;zhlJ=قtm}h76u2V0jw6SvjL3 uuQ>>2dĶy4v~fQںQn;مޔ4q. ݨ7#e<!MA nfܡ^^lٟa.n<zi)$mh$F[5RyDsMMMMMMMMMMMMMMMMMMMMMMMMMMMMM?辯w_sQa/}�}1Ćܼޛw}k'4~g!UF^lSg}�Y]fxTyBB>Dg`CS|�( y揤Go<ˈZ|x-?s~}.REpfLJ] ?yY65,HmF B@ K&W!d΍ͺM=͚:/ M5Ojl"5S#<iԁ:^7wե&@;jsWW"t:�sD7 AǪ]AJgG>DdBY Ǥ;g/9ΎsRh1ՈHdw7ӹ슞jZӬ~jjmsq*Gf:z-70>g =n}t/wNq t`WsѨс>[g7 RN65>[g+B @)qfͣ0hTfXD> 63]O< Bv>8هhW8__S9ѼiA{}Ѡ/Hmچ~5kg{UzT|u? iEkHݧ}{ F^j&h^.JtܝTǣxS퇶h9K^+@MUɟ QjX"rMIr�hSIn̏6Yǽ  Ǽ 45U$'B[f9t.ka?D r;v/3+~`%Ά~lf?',V7/XΧ0}2v& -agA}=F2-'+Zх~-j'zn6KF4jb6OOZ J_)аG?ٰ~jIvQtZ<i5SaTFӿdCg-6'@3jThvS5wyr.$Ao9P|ͩh w(%:Vh%5'E#hҗ6ѰfAKGQ˜_&^Ht8i+ }i6Hxt"II _3TKп~eь:5+g-jxV'67,}kC& iݳBwLx9!Y::(ϣ83DgTt&4hY4UαIkgF_@Mg]+` Vt ׬Wr3+F+ j~,7|Y.Yi}p`Q.-G'D̛MiUj>ڃJmVt.3LhU#f@#ǘfɤ,Exvk RIʙ5vY;$yV~}[Av ܿ z?Z_˘j'z)MB/gVUlUe] 4xr@cVNnbxNCn*DKi쌠K,#yYol}͋fF̻]sg4vg!54yVчM. 5/zP<gS nCgC`5 p4cTԬsέ|$Er?xmb>¶H|4l衃D6>kry$- :׬?j('[vY͈\5,ZhjNb2`/2jN&ʻO�Du9jl26Y<:.jtDjӬl$h E'P;j^ԷV8^.vU&ѝ5U:VTxC/ bM|?,@ ]O~7엠ۖhvjDGE>Qc z6k?QeCͤZ)lAҠZG+̢Fچ>[ }\ݻcj6GDYdBCs p4sOw<xj>hMGQnP Ќg=DG5"OjLSM)L٬-F#]ON ɱs&%S߿u`r^8 lShF!jSDz50Â[۸A{!Z=FEF3j/4,V4q'm<ݟFk v!;m A[Ah~̍~w+ڂA]/mN'/VxAPSѺQeңmwEMQkZgo>I;4{#& ̓nwOˠQ]@i;u>N&muĚcѨ^ $4GZ:󴋜8~89TτntX Z<|WΈgC{F`hhRv>tKR_tZςQW΁hYhwL=;WjYpt7|Dϣ=K>ѠCӓM ;;uGwY=x6j`V93Kcf>j50|lABw1tiuY2h@c)Ф: -1'Aߍ^OomMdhf6N #ծF)ѱDDlgpyЁEѡfuS@[iЗ$fmQ3%B_jkS$C !KeKJFeZͪ)/+' ~y̢1P6Vub35!7,SdZ}L]Mƨ0R:Βy4f5{8hXd˚}oyѸ2ut-Fkᢙ_WxW:)"45MlElM༼fht^ntʠ"4>m(On9W`.C$+RF`l(uV AHMMNt.Eԛ)Z۴yF̜Zlfyͦz|aZfe ^T�YSh?tJ.#٪C}Z=zL׭&ịff>Ғ9~herDcmaf4=\.j:{N_)jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj0+~-;I3s|u-=vãA+RZy9C<OlMD^'xЇd3Y| 4[āfZL2nKPtnei?1#@͟i9mc|汅MΦ; ύ6eiΆ2@dv3+Ywq9æ&^~ԏ4Vs!Ɇ jMi~%h|Ӫrh.VtB5U=Ԭ%ѩdmYEt]Mj-IMkzjGi(vUjR+.ESh< {d+E*MtnGRa{q7::h먲]8qJNVFZ^ -f.jݪ?@@~>?=Wnjh+ؼ'VMzZY)qqg6g'6L`>QGf}fe<'Oi3ő juFg"49<Ӳ~6Zܫʱ]L߃PC,gs>jh1D @Ͳ6`fџ9h w(:dQxT;М F3jۅF53gNڂ&nЭԍE[x\`6u4qӜpɎ\ԦYFR% F 7FQbɆt߃탖KKW@5KfG7klj]Gv6|hn0&mvENG N7oVASOar+$ǡ=/$FSr'hzuLhOy':mIEs!gŅs=?0y͊! oԏʂ0,n]2u>WZbv3Ъc>ujv?VbZT3<z!tМUwrQ͊~$Ӑlh zfJ=i&_!OfȆ@Id΍M>jB[<ѬMqn4vIΏ0iu(X#AB8mUMvX̆)!Zv$(%:!#9KsR}:Ƭh](Dii_M?fABԲeMG}QDǙE& Z):s|<f kAuAˣ߼6xMI 3d P~]$37f 6F97ƌEmv 'wЖU=i4~z^}B_׎&֋W}MB @Sf+e heE_f*B2uDղFy(J|"ȣ6 1h! <l,:pBLhc l FOw.a mQfM3Qf!nW@f8yb̠UJo-%_83V)%Z hK8^(V5w:qhf9l5/U5n0$ohEm^ fĽWCNWV=,4á J0Ig{>:Ћv(?&A}5UX5g�ydsx?WȐhfմT+m개]m RsfuSæj~r?S+3-ljbI/:VnִM=w]Ӝ =5zg:;&Fh=fgEWhL.Y4i?LChbN&gBSShתΊ& Y7-Aӛ$joWsShYSO}li5[9^$SlGh+Awާұf I{e1/v |lc%F5IEcxtophEiqNa>a'|AG=jт&{b@hV~6 :ݼSKr]GT?P0Ͱ]ɜ5>7sfOEE?Dd <2%6PT#&JMf ɘ7gu՚yПs؏a?uDՄJGnO;SwNCM<Z!jڢ=G-2'@e,Gw=<̰85@Cݤ}8=X5Zfhq4͡aQTht FENkECuZtd âu='iNnEWO;w==fA4�wJ`U!7Ɖ'==+ m1aWd]hCJ AߋC^<4/8}ռ< zcO@{~8о-VgC{4}L^3hIuu٫c7+YB7Y݉e| ǣ\�P'Gmo{y<"ګGyV;;VRsc~Sv! Ulm6H~ ;5SA6wƓLoK3 D  ECuV4N4 KT'FɋF(w1w4` sw<[`N6ߡfr4`J6h�naNG;ёGBDOhtYЁ}iξtuF}`E/W(zDMMMiDNBi/?t9C'ZͫI"ׇ&WщdCsj ,=M4u.bCt:L4Nj4Uo 2ߛ?L/j<K!;}0zz- m A+Ķۅ~-B'5aнmf˨tg\/ M<++z}]5z.tbتvUe6jziE}<}07ebPj<z~TB eT\f q:hnQ͚7Bo(EldGfstn5ДFot~VDoI t_xjDӋZ/ܢ,q9fʊf/ bx(fHъԭ<ɭː$Y9&[vWN}~,SќڶՄ4/*¡KbiٞPV cZnt EjfflvsYG'.hf�MF\tn |2Nʬn||㊶ޗi#Beh766hɨ4ysg3r/vsQO 4o-ff3>"K Sxs&G<+:GS6sY4i?L͘)Duڵ@ Tqۊedq D'RӵZiVBt5SBOLjz6FU0n<Üe6-3 r@'*uq"'8"Ь|lc;t&Uє[C$alY4ѻV#_sr$h>pPhJuIЧO[ƁjEwi$O 64R %15@#9@kG=gI 46eOi5X1fۥB~~2 n&Dr| f>ȳ:a 7J2߿Ŭ^S;П>zx$$#:Fs@62b=/Sf "9(r]Q|=NGѭ\0zρʎMЃAhMT{Û@s 4.MkfD\DhBYAK%5ÊYЁŗDkG<<A)z6Z·-!/GZ"+:mUf>误1__~/;=3xE<hPK_fvujtsh+y!z3|` GFZdulE? z5H~mD3=}~*~&O(ߔ:5zHIЖCJΌ&V&AFe rn4dǠ&١`\2ha:&l: k ̢͖^к;�Ü7ߑh%&u}ܰFG = Qg2}4K_/]/Cb-=6hFD'�#u9tZ$Zy,�tm跷Y=N|N@hKNjK646rYAє ͽz@uz0 6͓ ۯ_0ZYWL mEaY+_tZ}н4>=Y_"R4,K:#cй^}ITJ̙W/z.tr F<ѶGyͶ u8/YW@1+bD_;6Bк<!:Yo63oGo}R^LhQ#طY ]0zcAo,斛]x=(dv3%@G yFdnԛų33/na6f78bi�YXi^#ZYEL(ъ= Y&_ vW^~Ȯsi;{"n-ʬ|*ˆ4Ͼ/=4au,ƫɘ Fa̾Rf'5'/Cv[̩!:qAav.¦7vC7w.f[EQuCnrY]hz(lUkQFT O.4R^s<ż{.LdQZDh8k!:G3>sJМa@'Wx/f?btZg>,&cFU"CRӨ�sBv_h4@D6j >f.bsvmvTB;*"'4"ЬtSNG׷=T>Fӏ}lhsCSChcxܪ(>ŢO}Q;=9J=OЧhI#~)̈mwXLw4 6�Bh%tܹRPlo* 46j|07hƧ̩Пmrz`wuOz>0h.CiџԠ55s'W,hF~7CEh=4Y3 ѾjKJ3߲9ޓ2Di_s =5 5 ~'|'E[ yV.JhFÞXѿ%h�4r Шf$h;$,͛Ւ!3Tʄ EyaŗDχGB??{KU|UtEY@GNSf_Y}VBY_.}G% r6 F[Չ_hׄV@{V^ڷmM`J<At_&B;rI_|'@dD S=^mF'=ߙFI'M&)T ;5{zJf~jru4!hj!hȤKMA]�Lr~Qs<QA w*pIC2. ۙŚ-ҡux�ܜ}Ov5JFG = aW_}/Bс}R�7E_x CP`Bp: :Z~2b>xt2ѣ0ڢ6oâ0nta0MC= X!hqa�; Lr4|3ՆyDc5>s6̄zlAO!ú վqWYɆM{L@6 Ѻ[~i͊73h"4,D.tjtV ФW</D1:Yj{GiU ѽPw3єZ< ]xq(ycD8HeVs$n)?/MI{F8f޽o_!^m uIsf3dfe73荡-nv7.tY-BfY<i3,IԌ[ԍz9;"cI5+m3s+zaqo>4ܿ, [R։ֈօHXSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS3nۻ\M}v{+ثЦ@l^2}: eϠgP>נ9OvȚwXŅ}2;samUh& 7g.g\EtFbίfC,LJ٥e6Njo6OYգ2j}]LWi9ÎFٽ璋b֝aQ ̄(_L?6MLE[ѐγ:Z-DUQ<GfA& DqhʜLM^9?Ǵ_vg_N[�SEiءZDnShLj Zl@{[vh:̀>9 {O9g>q|ӣcԧ!6'vCO%5V@珞O5:o)lω>ljH~>h0+9قFl:`Nb&'Ys>[ъ7' gA.nsϭPg !Z iџĠu4s'ˢuo| ɢ긛IdҡhPnէݲ߲9{ ;~C߻ 5J z ^_4+7Z5ʅ@kѾwض-5Ս5cwP{�ShqԎF5В~_UτEehAhTWլ"ayɜXBG煖W]]=D^ssFl٧GկU| ZΉnj<k?Z@O2ruZ44C:+ڻtEB ͩ?0Ut:X2tW)3zh=HqhG,oK8ZhBmOOМ :wF7/1{R4;+/Q+L>jzzR h +#S8D߁KZ4th,lk]{Y)ё^]mԏ ~_fB_Abͪ),uuAtDSjψzaYNM*:&}Q %#t6&z<@XY!s7jA2ɽ CߌK1kt~ ~ 8jzh剞YGxOh43}e�= 0|h%GBOt&^˃>=ن ٹ\F.snۤE\f.tlfeĢlS]YAji/t^3�rnҷ/ͷuA3oh# L79(*6ФAots8zyV2+yNē3E͝5wQZKXx9腥8$o6of5vx55555555555555555555555555555555, fo/dW=f<jZ&EeT&}82 NS3CGrY4jYGoe< 0rjh[33Ssgf[Zt2]6lhV򛭳nT/Á6ׅa?>B,YsvIG~b"2(F-6@Ȯ6[YV5D'WRtb5NDjTE qqөAhUMH&&Rӵ>ol5 XsKl!Z [lny :+E32hA)@ǫkFs#էZ0ЧS4Da 4&А>chVЖ,Zo>O'M|>?tOv2-lG+|RallÚig;zPwuq0_-s3Fh5 ԦYG2g@+ɠ [~7975~z=R}:y4͞]ztm5Qw e&ѿ%snfP|_ Zw27)h>lQ)Z5/9Kt8X}؀ShMp ZF‚CZ`иh,|>N-=%B4*,@K>Nr>{Pk@y|UMbOيWђ-"/}Bg$__@}y[?Z΅rۓS=~C<hhDKIѱDKWuEB'$;mgVМLm3Cu<c'A-RdCk=hGZQ,oZmߔ:Bsg΁ꚭBO(ѽ<͘=TR;=&wۊQc3dՓ$Ώԡo91zfEhV w7XU:�wЮF)ё^t ӡy/3>tK"QYu>}"ЗЗ`.U=e%c6ۛ'>n,lij@$ NN7jų /_%x52#ݡM[RWF C]}03U12%YJI;߽`Klj0,|g~vAڣ6Z䧦VlfCbM7V@sM fFГ. ؁Y!wu7WG#5h^Ή69Oؚ, r[B?yClhvmt3ZN&g3jbg Ϭh`·hnկ&$ޞuФ|6x|g] tn3>Clnzh} = 8L~,QѺf(젦-mj܌?r4+e C@] @1 iͅGՔFW%jҌ-͏c|{>kеznm7ķqq X"H$D"H$D"H$D"H$DJRRO#Ԁ 42.N a\xO90dĠ:-ѮClEi!c*m8<0D՗ O|@y̼).QMWƘcƮn ף%nhW߲5&9EOʢ۔0m}X�=d̦�2.;hԷjfC}ӓ|4[v^F[v ͬhoP$�ͩ2EH( ˦j6FK!?խЃ˅NyԸYGOXY^e6�/^4k\`{<r zٳ_Ta �s2,므?А+L1ΌEw61iA4F㯿)hxv4Cx�H+]W Z}-x'zȄ�fCo-X ǬעA+9Rλaf_<p~8$ܣCԠ2\0JMr u^фz;Ѱd\u??>DңǐhhͫC<|G[+G^SNs4f@ʻъF[ .7黨md@x>־oLwnWKf"/,N41_ūv0tX\hˠEW·^mwUл:NЂvkʮButCdKC6k*tF*uy}_n ?kC#>vL$FYU7zyZgWC- dFk06ZЂD}kK^ݛCXxqxt9 If 5.,WF+|| dCG svt_QG|h裙GVZ~<(:5 v*ȌV; x8kl:QVDt;Pǣd4X#6ԏxtmUtLhͭ#jCP1:ڳ#O"Z9ѩhK>߫Џ&:Xc EX^E>f^ dB_`j5/@j|ԏfsܫ'48J,h&w m/FD_gՇFsmC_>3b?J̺90m j<gW<AѬS(yhgȥC7~"N}g&s0o�uک&<ECtn5 L}^#.E G;6fCS3i~>f}Y s 3>mUvT 3>uGݏgC=ՇaFgE03T}e|2}=?~hUج?£w0Wguim(ZG7zjբd-�= i:6iب<8ڧ 4YypKAy&A|yD"H$D"H$D"H$D"H$DR<mj֤~N ʧt@ lS+9_(lJG<œ'/QK  N1Jft1)Xt"2D!'l u @W[ z 6X s8_XF-l�~vDW7hԷH.K`f7U[}ef 8/u [�Z)k2w ͮ=unYF{KyKUT,ڮn6 ͨFoԎC+?Kv֞o x�GV6ѓˁfQ{їJڏkPo2ß0l]i:YMuM4.Q/; 9$_o\ $kH1_SЈDxo8G#3A z3f==}h==ݥ-Esr< ׬)g<<8YO*עCꡰnT/ML&@T?Z~hUsC}rnVAj�ФxAȉJeu {u׷Z-f zL!4p Pf OF46YV],7kweg2:B%9ІX�Aq͒YUVt;4U]Ev0t mۯz+wZySc#uݮ:z_ Z?ͣ4Xc{耼"zy?gVEl�ϔ*y8 ֎Fhmuh]`3~R:}^Ca N 6@jABjʉV}áFk y)s} G,hm*>vt[UGfЖ:0dE΂F{>y<2nwt#3V'NmyяGNC?5j{T'&לnJ`fG(9Mm8|A s=fDCv#{hQfL6chC*?iξp5ttɁ5 4w:ڬBK0/"?bMy<fh3yPO ř[x`zWCM4W+j}je5e֒F�hB?3}67 BTGB͐l1heu4I06h5 ~_c@r'aWܜQvƇ5/|hnq;@g0;G*:WguQ\FgCDL恍.ڲQuݲU LsVhSMY4ZWSL Dàf\}6Գ0WBc곡�}̘?@?FF1#3T|I}ѥ?@�GU u�p=!5Zw"FtZY87ydj{AF+D;Ym܌_`e&wus %D"H$D"H$D"H$D"H$ɿ8cj;6'$VU|Xl֫0(OtM0pס؃F/ 'A_.OLqݙޣ.&r g'|f1zf]of)R 43˒W)iBP*W9ͷvz}-yJ eo:loR߲ 7շY7ro7?9?�ͯ͗�2`;jG/aI]mVAUhVU<ʬO9Vlh>]:KTx/[@(d5y EE_._D>D6/LSAuyDd5U@JK]}C_>`NUuF/Oa迒4C*xPG}@6@5&u%pגhyHנcC=֭=i=mf}OC]hYVk{"zPwOx[C?]qes3)B<$t?[Qh;pYCN{Lo85|fWD ʹkAB Fzюytqp6z.k4uɉ6Ku?xtPߙOoP4W/zwYLT@N}UAK`ۅ$Ojn݋ש7nG^V<O:v6rhLm Ac+WWVw#k>סTEwu9?ꆪ3�vsmE~Dn& Mu<P}H1:P}(fjʌ>F8. jD_}=W7k}ɀ'gVhÊ KDgMI"B?:=WDzc>y<2fwIG?N;6'kYяB#FQ[s: (~0Ͳh$V*?ZҮ(&:h[>}߂híe۳_4;3Ⱥڽ<GaD{VbD'_jOtqŦנG9h5UYԿ^z f;e=:=RĚ:}3IGpDM5~yfP̩~<~K׫ͣmY V@׫VYj 'F_\'ZݻuK@UNjt3j A_VYSI W(jGcT(~ZW<Bkwh{AQ ԕШ>kZ4yQC4јGo<{_ #MLhESF=Ϩ<Ўй̽zT|MQU@CLJ͘|6Ct8ln~|:f {1}̈l1ϵіZG|11*igXxΓ2Ȧ Lkd-Z~{=:-}PzAV@CkVցPe5h4fZ _m Ăvu.XS-7oH$D"H$D"H$D"H$D"H$S[Oژ| [].p[{hb 0_?.ݐu(傢/}&؅P_*'-NqT1˸%.zz> GT 3yߒ#S[17۲a,/M9.¦F.V$hRMm."Jjs5fvh  "bFmN,'TSIFgRV_Ao!h|4:FO`wjot@ ]}B:jhh5!NC\f ;B|j5dE f]}\ʷvamLyԏQ#uǬ#qxf^~B'f5ZPӿ⮣DMe&dUd5UD6]mB/t:nҞ\Ri@Ҟ6{JAfe/h-wH"W;wv_ۉVrfZDA dM0@qh"U@hAuhS V@qy? eorA?sn1kqM"Ю)]Im4fȿ[ /lՎ@EmqQ4.n84.FX93yw\hJ ,4zt> _+h7w9Voahm!E#v]Xޅσ_@6^ps&8tXl]Djs1tfEN63nmnUѭ'9P?m;N)EE:ں+:'EM= ɊHBkB�ZENBlCA!Ŭ3צP7>Lߧ: L2Dk#NGu&kv\hN@cz6ȏ>1d&<`Z5{1&##Kw*^CM69 ~<l3DQ 7Hh2C?XS5hЭރ6dFuZ5Ra-{ě:hqd}K8#k;ҬL hR|tuZAмz=:qOB*`5|cB?x߉썞п]֢F{ѿf~DŽo5KڿtpDkA }ݧԛ h]b03Z;jAEP>=4>Oz38c$+Z u~ Ӂ~{F? 4ykdV+JCcl> @+zQY4z@+ݬtiVF<mO+8j(9cf mB?+$Z!h@f4S3+},YGb?ۜ.VfG#!yˢ]z*+:yPc>mPωV|JWpt>s&͈Ziiih4یϖ6#fZGmmg}s t3@fK}cVQtWRk;:ZtA5tmAע̓ZSs4' 9X;?46ޞYQ썣k ͛Ѷnu>HW7.DD"H$D"H$D"H$D"H$D"Z>?k VsImJ`>xcmth+5^|5eTMEckX%2¹@Nb\Ee,4.-3j 7.=dRÌ~f/JKcAaϋN+k6n]XK2-jS%s,v0Td7Ioj-h#h|w( 'u˭5[ΠGKeF+M['vpE;t r3bK4,W=f&]ֺOEռf5ZR,A?CB h0vYNVSuo6SF2C̈D'I3�FԙzIk+_Fw jb-OVMAw֠ܯd/I5c,{2VĜUhK}gFE='&'Ag�ZAN@_,?zǠK:7h-\^̹dA:#M-ŇDNs!&tp4VD �=?Qw{:#:g-(!<hlSYkӁsիͱ_?Ж:/mCU#GD=jv&f3wt hg,h]tBs'jtPl?ј=FAWXU6/ZMho퍡~~#!v(OeO c uO z_ O1+ˌ*\dCZ%z�j&~'M}(>ЇBG-PGacvPUSXsUF>aBe v"kd|<>/cG9Tc-vNBX+h̎6hlMF?X z 5ǡ zHC+BYB?XTqX1PǠU@ѦXo>4Aej:h#=\c5&9\EjR|h=jO-t aЏGǛu(ODZSȝg NK$]SB_.A Mf~u9EC_|Àzҕ|ߥ WͼѠ"j�W:iỲni3#hMoVyRhlhzpEW=I4#YC?W[mA\bh~@%g)D_8Ch<C_Csh&D#ım'N#h3Qu2:PVoV)s."6nXFjͽS+L;5>OwEYͭ?f ׬w66K?#]l2G1h՚yTit!>菏Y1QtW٣30>/V= z扭,AhU UaZ=^άY^X=iZ@ˉV4؉R+ofhپAAJ$D"H$D"H$D"H$D"H$俒1S'j@%L|iCF%<}/CV}!Te#{`p=h쳷_*Aq!C*dTm67sd4uA5.ܢ;aqZ7c5E\C݅}mѦvˎf^ fSSfѪӫNR\I}= 2Oj]0CT̗03j<h Üͨvfjq3bKyވ|j,^Mj3k9<jpڷ9_CFYhOhbNGSoQf]]\Q;z^tRyA믿Gw 61k|}mv}f-{*z)hXRsV-=& ʏ^C{1lz֚7⬞@G'w6.&FWKZzR1MTÎJu/RBqW:4K׿]_VʎF;W==+xOݭNht̅T7tzf:.-77zZ2)Yz'mC&<  15Fw-;蟟Xx&π^gV9@ݯڬsUjϏﳢaiXtsSkeךQ!#`Wfn5$11e-`Ci֏GCsN4POG83zt'lkC1!1O<hɍnÀ>8fC}%Q؆ݕ$ԫ"6R'u2Dj]pGuu Q]HB ;`VUG*ŜU'uGdaJdVX@ÀaP+Xϡ 2(t6uyzNAS :MVњfяk@C&vZ9FH3y;i hgǢ{8IO$]%~Kp%jZ?E#~ːhf贱r<hh|z5/jhjb@tVdDo4zxFSm~̵g }g9?ѐݣ{}%z)XR>lc 7C\aBwżZje{Ѡ&y%눾@f@+0_h{{d1Bg'Wی56z]04nX?ި4sA3f^hDf 74rDQmnvѝzU7FGy$z͞~fB+*]815fգyQk~x{EFg#+|[};:=8:Sg }ݡh;ݍbfLmsK-`0&YWˀ>b @ ݦ18Y:cQLj]ϚVks= AaRB!Y-BՄֶOmAN֎i͋CG=UYď Dh& #5U޼�Q"H$D"H$D"H$D"H$D"H$|~~&ȧښ,X=Ci҆Q C4rQd>{vw2 PH_Qqx}~".2hB?|h\m_K ndG᷸i~n ]uՎnmHt@&_y 6;mocrmb¾)nouO"ou͋vN'РlÜfWg==/n|ho�4ڱ7t`/Q[EěQQ=fBѦzM5I5f ͢@79ZW7M7_Mb:*&2ˣ:k'V֌#:|^xW| ~OCwY^~}J"U{ȾTR�agAЖ mevC  k<#SϿh1z#:#:=Z@ΎW׎QAЀφWuʡ[͌߂<=,/Tr4wEMI{hMWvMF{ZQRއzyYvzק zX0v,d CFyIZ 1uaEv#о3;9+SOI!?vmN*;OEwH_LhtVﳡ+JUiP'B CŠC/ZYhl^̀V99ԸP;W=Nք3[{M^�b^*'x4G;c<G:,sHꞶ̀1NGz}UyP':M'v" ;CdEN1 @C6HD\m] [^Fi#EFzZ8^27`5F4= F? Щjم^B?X:C?ЮT-Oyhp*| )D:86oE`u)t~3r`d@;;mCGЫ;] x탠 fC6/f&Ιn({h^~fC7X|>t;(j) n=<G~5v3ZeB;OF=eG|߹$&pW_;Yͣwμ2j;B+,ElhŋZُf7y }-z@9 5賅"l^όf6#mhT+3E/lvЮF?1tV?3;BCxQ"߬󨶅ʾwhHіcƖUg&ZFt 4ڳ�r3W3ݥ-sLO f<^X>Q +۬f+PF#jh`F{`\l1"ZhmljwMuA6:اވY8F|5̓lcHO>U5sGpU3R,hD];B@kfD6̶1CuU۬?6hA]Fmn+H$D"H$D"H$D"H$D"H$3KjS_dHy+Z?/]۰PZE˄Cgm/fC 2`+ +`iӿ`[ e=P8IClǵ%)b?ӑ1Zf j[SA}QO >+ۭ0k[LW}tNtv-�z$:4/hr.ά&�POdt.5584[M)fVBoho\ɇSߴyж{0V\fC�7>4ڮknǛg·h k 4VGS7h /͠& 7::njnlo~>U<UD<7:MMVESttݬ$4Uہ6~o|%P} =TjhX":MFk%hCyf{7z7ݎ>WOWcf,(CY!hSMԏE1E+ 쇉dB;_*\͌qö15c%nyZģmvftua/q 6Gۯ G5mTI64�/<@&y&\&+vI=-RΥfE/KE rQ^fcл$ыSڞz{PgEcdMB{jvS7*;]É޻@hޛKĢU2ۢ}4Ct,Ӝ~>}&VC 1WͲ%o?'z* ]o}GY] 68NCFzUm5:=;tɄjf^v1N@5t[7/ j7K^wB DV胖PW z ǣ.辞Nx9۽=W3IBb_C "ꈊN3ۨgc:9&<p"Tr;ל}LC#=@ AA*Z"X~~FqQtV42?^NWnp Qi>4 ~(BcjW{z&ȎFkAؑf_?Ǔf63zDVpaoĨhsN$NCF-tz50hl7עv<5Po+~:IfWC= Ri3MʹۏVk8B;t,DVVO>heߩx_~\yЎysQ/e9ѿsӃ^>˯9We6j}W gm^b�4Pُf5+AchTkV ͋g.&F%lۣddVW:YI}LQg>h{cFgl5ӅV82ИF_W3TڀE#U+;gg0t>2&8aQ7i rH0@#.a6ԊFccm)1z=TBbfMmB]5zyQ3FS<KMfa&W hhuY=MǔmksFԛDhh[ ]tuM OCu-"=?9C̓ۊۺX"H$D"H$D"H$D"H$D"H$:9cE>?=hY@ r&91~FW*!s7T[D#`Kb&П;]ٌghZ]&O7KwCх[;"_>OA;}A7'ZDO8FgV `YAyՄ/}6lt'O:2:QNtV5E/=>Qʵ=r<6;t>5769 tβoEGh^mZZ }9@Lo43o7*-yi<. #1gC7zF!f`c̈́6ތj{U=1dB+L:E7lP#UŃ hj3&='ѢM@맪}ʻxh|4u-tD;PǠ~tFǫD],j~ށvT^gj;ЈV軣j^Uz-,́8*=&w_mͲn F 9H42BA/fRO@IM Aj¼Hֳ.kO[j|xQзOM6gz!נEwf"pU\0FEc/rnݮgMɏ€ի;ޕG/CvU3;1QZJQ_ =/BhF^ ۣ<Z D+4vV@t0kt~Um/D;袬U[m_ܡ~~dv4T_vDhjMz3-3{߯Ev(=/۪Wۂ|{YGkˡW7U{<hZ7da�thXo^cCg^(z^{ }'玧z6m@tpc{|N\VKO)΍ݑ<v B;nq zf. mh˝p4N�UG ΁6qzy[#IxIfrhNA;gA}e95* M`@E^x>я~ǰZ�Zrc}Fqdz~hb Nsf~#Ѽhêcд :(MM>ZO$|hp"ڬFaFwt'cy:purۼ:ف.|54_KAkh\諁FS=.oWSLngCheRˣ8ɀZ/1ϒ_hNE?ox\y15eD5xwݟlhi JgӨ}&W gg6m91+vȃf5jdK' 3{HP3Zdh@3yR4T<M@<)s|>F霽6АuHwhcM"B#>0KeC;#<crz>^<S+DI2BsnDSQl5`̺B#:]ȬNhPMnZ] .5~yY=ŏ2OlV={{z:dU[߬ȖMĢ}|? l)y@N|h[f;V [$2k3V}$D"H$D"H$D"H$D"H$D"H$|mX>3b;W5qt{?!Ex@\Y٘f 庠jaiw } ٣vkiS]Llt\Razj]v*F͟gB:Gc. Os[v}VV?Y]} p Q4vT3}n>STM'PiM3}i}AEw=IڅΦ|mvn|@[8Ahn-I?м=^nލͩꥑʁVK0soZugmtT/Ɍ 8ljhd;dnM_̛yAf j>O4g2Mk7~Vu]fo]1h5RYb=@XFS1j\ nt-y^J+v;u`GU]LODuh맙m =N5땵h jEʫ 02H萟BGȬχV}Q46-m1jj;aǪg@BwP5 Ayͷ}ώ6@=Ƃ4>.n>n AUЈYW)5aj.zNjU@;3e{5ڪS=FEU%{6PDT5Ss=Vև>za띏@Pk-[ {z R{z_�g@TDE~~j~~ޢL5~n5nGO[ImΆo+͝gT#3m.??.kЈW윷יy*ҼPGn>Ʉ^C5+웷`qM6ma~4(fyꀫ#697zfǙmwˆ!q zf.H5%v m3@Qh"G+Z6ݱhZLdf&ȁ^IhG,c*vmvVU,D?^w�z*֎8#=?vVT>ˣ>hXDVh 2%h݃Ȇ&WC/4mfD[4Üa{<7@v6t6{Kz5 {3a%elV&U]E?}54Cz>K3+FEㅷ&ZWM/& k�]ts:~@4P?жKOC=ί> FO\vx4g̀Az|h^>~CYGWCjt'D9fItD̺ڋ^g63Tcf -5YYd^,bQhLM999 Q}FPhH@!U=nU+~ъ@w̦ZC@}ΎAsj, #ˍ>m6Nu9TPN*e ˘F+EUaעyQJyaǦV~ua0 juqs^5 -%Ѥ_M!xo@[r1e>]6ڹ* Y"H$D"H$D"H$D"H$D"H$D"y|~^x2'`L9+\rerѶb1!;傡+Qr@[5~<. ]ҟ'lT%3vwX%s8P|T 6[c}-v$ Cnոz<:UMti4ã/Yєy-4Xc3I|NߨoJ) ozn_FSltMχf~|9&:fu#ІyD3oz|[ 6$-zi9~) 'pfg3n)فV^<#lhp-fQe6ix$j{Xf.dZVn4ܮ ;fkfP#E++ʅXX0 HUc%cS h#w':M484Q}gFw]MMunF4Rqu3Q>?sLtRnĞf8s-7Z (Bkv4Tt=ꢱioDD̈́FUXKy.:F|Vz١vQ iuf.ފ^#Z/ܬuСЫWq퐂htxnWʿs`|#XkDž.?]z5Qf?$�Cj,hRjFStMOMݹ{3 g>Yv^/O5^~{~{BP\Y֫ע;s̜ ݩe{J?9z?;Z̪zP+gDmVס1^mv֡vnt^.^=*ҼPG> G58 Z#}vZiա:Ҽ7m]~4ihP:aw hC#ñ #w@qhc۽=W;h";ۏ؇X`1vZspMwYb&+} #=c>4௬ܝ& IB/ח~It[x Mc!>.UYDxП?| 腝ȁv]hGm}탠AkV^3D_^Սkg2ATy(XA1QjM3D?HU͢F oѓZh}k:oF_P@3[:m;KhmmSa m<:<G4$WRnf3+] F_~P?KAqNc7C7 \2կ?ew[<Ajv{B/jfCcqc@j~3P?\YzL^Mc ;zj>Gp4z!\m C1NBlB̃64ڱ`V˩3tɌV =@g6CϬ 4Kղ^YG2;>!9 i7yR | դk8[3ՕsPo֬͢]7͚ɖnM,dO?10nFL%UB^,H$D"H$D"H$D"H$D"H$D"Z.mjV2?ț˒9 rAmz~[G# z\ڴgheCF7gHAW!{f/ RN0xQS |6^-F;F5M3fz-:�݌4h@T '|Rշ5B+-mchZ/U_ևfLE):Ko$Yn�ͮ&hf@(/Za�U=ռQ1B߲L .egTkeoӚl1Fщ6Yg 43 LwM̓Z1dFZzb!h5R4ތj=mX]!lT5aX\284,®~I4R53z<SNM%*X7wܪI2ƍY+l˚ѵvuO7eчX?诱#<[xy%Z%U:�ek+}E_UWE&K3˅MN2@:e^wH1^(ZwCuІ,Àhlt`75whEV4z8{ggj4}PC=ntv9fRcR̼hJkE4 ;߈0Roo s[(ۨFkgCGs^TB h՛Ff,Ut;W)@!JV3zY9wc*[͊v[F1CG^m^v#={)tVkKqD⡰oN+4X8=ш97.3'P'MG=SK)9ј:uY)L-m[wZt꣹;tG] h9zfӷT_"t,莭hg\h2/~NGo4w:U|<$=W@'6SO:ZG=d}탠!hNE+hL{^�C*Όޝf!k x5cM5;ܗy&>$mt8dZuӍkѓztVAfۃUWts"D_PDՊ\vvw毸j9'˂6ڼyƓԦ9̶B_Pw2;}],h5 @_q ~E&}5݅׬13Z}ѶFD::yV?Qs zQ?sM^ЊG/dԤAc-9;z>mB2hضBfeE$Zah㠪Vf =3.@e0exI|9zx&NWwhjpyw\L+D\h ̣ڵQ~tIveͽ:Gy"zd<Y;fK7xJ-G70$ =XP3<\G3UmлahD"H$D"H$D"H$D"H$D"H$D"YKѶsrb+Q|`+ l*i㲪p E%!VWb/Nv?n{ =*!.4X rdB_X7m}7SMUo>s30;i0IC3oS6뇡 y-v 7 E9:/kNjlR:I Y}KCϟ6 {whVU}VnNLX0tз[Z7:+|fTu8:MFYT֞٧|h&YC A:XC7#BFm j)R}J"zïvv$TaG#:}wihg@ sBU ;N1h]?<T׊2@ST6vNt!uc /,\BMf@䯙 fD P'ZKAtBM?8dMɻ.:hK͎a@jn4 `]jG*YPª'wd]Bu_^D"hzDM-Ƃރ0~3haG#rns&>fE~!kѣ 翇!ihfl4=ob^MǴUhZi{PǠJW# GCעY~BD{Nˆ}�Z?-BUC|NhmG:=W: }@͌hM}HD;͜h\>v$1B(d 3^>xT }v4Bw$ZiE&;=EPz�jz+h^ 讈s vt`_ߍ.ZdsDWGUt݃> :EM}I@/٦rY A_ ~ey<Lhb5L"hWE46UGAxM^SM1OeH<+z'f= GC~>2I=|:Р`\f77ډf"59Eý*ih~R0SK_ oDsʣusD/Sp5T?-3>Z ~fB+/l#8 (Ѭ!k6g.\ܩ<hps*l.65jA 4yQ@[kq36hC\84Tg!jl>enF3;zBi/U< G[$/Zfs'Vg݌u,Z sg Cg6pjBb1ܪ)zf-8CC23cf5d9QF;GgjTW;W Wf^ToPS'kE BOOjcՆ̊b+{іN6Ѻ8GlsoF~c%D"H$D"H$D"H$D"H$D"H$$5e{z\􂩷w_�_9bzZB1?EH:kkQܭA9.L(;| %aVbO7kkMl@YQ�v3iih[13bi#GtNͰMOgBj-VS%a#6qt>mFCE{q|73]sˤh}u3GgPkfjufW�a!( x'Ǣ7Fs&t?WK@\fmeЬ=hMYyBƄgh6QUk#qImVЦNEmE:\, }6]ADmxW*GYLh¼S!~5ٱ N3%bFGzPǡ2v}7w(Y.ρ#AF++p898Q MTτN\ƳUΈZYk#R7RzQHR8˯4VuW ] ѻd^ Q]j̍ l8?zW]<^c;2. ̎L8ͽX3fǣ~MѸmכmףߜ\~Bs{x[MЂWWG.j&չk ֡)vz}8sEC:h O$`^V='}8h,fOz~ \  #Dϛ<άfN>0чT4So Gu1F,hsB( @MCT#g{ԋD8ȓ^ŅV;UZ%πNFGBfM=rSYIjGG$\M{6:AglGEmUBwT_Q4j^fqhgt4]~~ZٯY_lq'; +}EƫWO$RIJ0h,s8hZ ׌O&SC3m dCi=h&F3k�q4ځ?neFjhWSsjI6=; j>BNGQtg -Q4Q3hL E_Lfxv G#}e~quPGu4;yQBG sZWgA+m+LNM-pA/l6V~hZ̓YDGF+dcgFwl,f5.VZ[\Ck& hC7O+#T1P<Lm˘M 9UE(0hKhjh3Biö>W꘽j7Z^dY.MwHzzR$ $akkXfU;Ɗ`a.ZD"H$D"H$D"H$D"H$D"H$D"rL  ^",F7`LOHA#yׁ,EAr2o'`[ztiӢB'' ;ɋ?v f\Υ f>l XRi3KQ 02 D7V)4Nn7K&&;ji2G-:t>BNh5 Q}Y|n]]/j5zz73o aa=I=MwFi7Q}MFWnF+ypj*ά0c eGj`he<4Et,_axh^^0ɅYQ}ix!YgfR[e͘ڪ΢ޣͶnP6Q`ޕʁFSw͋:=VGSufPG:N4-€+"t(4Z V&j5XTMD)xVtuJ zChuvBG؂8:W/-td___S~ IBG~}yл6!E[MD濾&2ۂ;5fZ+#s=}zb(Zu˚h$[} bDXcDˌ&hB̏Fih| _~{ы-f2Kt˳u: TgEBEGh4G7Zk::8=,坳VBNEdEKDMT=k-Z!+ (}cPJ_aUz`f+iKoXcɯ&ͬ裾L"s wlmCv#m߆9}0+WO5u4ZyИ{hģU?&#j Юr}Cǣ_B͞0Ύ^],h-p킠I`P?>z`1zձăMqi M�&뱡X%;M.^ W_mtEd }jx؋'A?3 @_QJ`P.p: d3[d4 yGsˡԻЅ4ht65髑ߵA ,?nNOnZn̓i*iRnr{k)5#Zafj ṱ"9#7Gm5YG#j fV_Œm^m<fmuc*ǜәEєAcMEԔ}sfZ͓VAsv󠞜yDnlV{VyQ�zfShkh{@hF1cц< =2`rQ3ًv Q`І1әf:]lr^R 2bҎ̕Kꭚ5k {R;ʼnHʺoo.V[ ~>3neӵD"H$D"H$D"H$D"H$D"H$D"26#0#Bx13rᚹ`Gj(uF;l7"F_ͰǕ=&tG% 8p+c B4Mw٨/nJ4 ϔ1kM4,I~1@7Y!e*닆nA14ѷf.*̈́ej}I}!HUC^%L/3%wkʜ}X+1@Ӎvo#[xR爋nԷRf ͯ\*:7fG|EvϏձYJso=6voJ7#(LpXjͨyfaN�Km4j4\Nm$TMfMJeP nSh Ա;; mWIFO%efu +aAeu/AaE$^E'W{holxu҂OUW:pMlй>N(5d ]0Q5QA}9DmVeE9DmMDA>߾K٥%}~V2B=/uN^$=GEvw󅨛~Yѓ-*zϋCߺĘkWiAO뵣Mup0s�5k>4kڗ`l#{?8BB0/^ev :}K:gD+|e^އV=i-ZaK z(e/>h9IF/%н2sQu3+S3lhhZ̏6hkadFWȀ>&5�uN4҉NfAl"@cvvBǡΎ^]zt%s/_}탠DO4 ԫZ~LKa6z|'lFk*eӯdYC# t86`^^�WT {jP'VCgꁮ|nPA֡\Ɋ~fǡكfUfj )4 JE;Y4r܅B_CKn)8,Oݱ`NۇFQhL͋ݨUI<q3賁`V3V'9MS05h[M3z E1;*ә̝L4@N=MzѭNgNPt>M Ϭa೛Oa܌6{w̚@!feC|D-ώ^ YSF6g;W urJYsz\GFo獡]CS{L<)徤:_tvЖ:]ll Cɾo̬}_%kWP;RcOj[`jx&^ppK5bPc[Fw9^M$K$D"H$D"H$D"H$D"H$D"H$D_˥?D PH.b1<+.b-5<hMpYe$Gm=6Q:yagKy]f;hiM[ޮ4i(r\yDM,Q8m4,Qhh UcfECiХѐ frj$dѪ6#@tN킣ESgnշkeq~DRzNzϏ<2 Թ[6P9=˥э>M3Wϕك6vˤyz}3g>oFo8J _Qx,ګ'̬mϠD{:\ƏXF\jK{.I‚JGhk/a@jw$ ht_[dTǠr*<h"99Щjgzuhwm}#ѾI\t:[^CAFG A ?RK Uy%חGʋ^sPͪhMLiY;,.ihAWW&KPv='Zԑh‚^ƒ>W@otaۛC[]*Ȝ m2oqhՇY6=*ˉG!�ЇXTǣj,`Km45#Ы2FsA%<oA;f@+}`AZѣ^kYke>$AEwZx"ɼh̀V:mDsv4[#;Mς>Fo;+h6cbdڳ�@JbW3ctpfµ'«C϶3>z EkeaĉvRLhx\F_q&q6X+n/V=|Fͣ=ueztV\f=䇍~>~=ȃK8>�dFUϚA߄~hmӝ~P;݈Wn %IJ ?lj`o5~^%y*<+Զg$D͊VYEm5yq[m(ں=s{8Vhpm)q4r9фBNXbOE<ӘvNjD##ZQhEO|yOga9=獠^K#wA^uo�EIm( 1+KsZ� (NW%; <�6PzRKjmN8U PtT^]̂.m]#w!f97DM&mQ=sn uydwZmΌ+㨪J+VY}u9fD"H$D"H$D"H$D"H$D"H$D"H$eNmɊ-^ 9Eq6`[i -TG/D5p4ie}Z(Lnl'ڨqÙrϸiϷiX,z8p'u,z?iw7T7v Kc[=6Rh2SL3os֜OվTsQj9 MSm{WȍoԷ[F\2o \֋g23o^t?lwBT)K}&8:^sDD;ͦ GM5fR5]},j̋|^igB#~g@-y%#aNs2Uuѫ+Sկv׎Fkt5΋T[kg*A,:+J,h;F4oDɲл___^6^UD_N6^6CV}|V:"QfK#Ѻzŋ D(ޣaFtBڜhgoNs&|m]C BdA{tY!2h>{cV^5:}G[MNc]}8]#R7mc4G"5sA[>#hCN~0>GME)ϡ dVmj.rr[}ȪF2[CDdim&nTٖQ`C[D'_< :,ifAM4A_LpUX諁{~jNf|Wcs8а tcD_ 1!.8zR+ tP{/ocZ1 GeZRӚ`V+V<~~݁&-|>]h<z S B43Fc;v$^C E#jZѶڍ~dA?VmBlCČ~GPwpU@lsB`< ʂ"@6 a0B[26j8<jr9Ľz^F(^.3>A=sUq Aw33P̋Vv4VzAt4j Vkci9cQρmMt{De2m|6[Z腭HNlI 6R=`Cˀ ֚HfVGfُv�A[Ԏ5amtU6+ʶmyG//6Վ][ćÃk|ј/bV ~DD"H$D"H$D"H$D"H$D"H$D"H$!T33*8<فތAC P:z;ĉF/R9-惡,Ҁa$iz&rCqƳo\SZݫiFLgy\cP{�T4BO.U;7vo1fW17 1Qlr 2Ce B'PRM_XvJQ$SV_oZnYѷ<jeTЍq˧J{msˎWnsqN &#C>Ij80sh0{D}hch)̓6ǻ;>ÏC[f*^4.m6I1z*voqgD窼 †6vrBCyz*S ;M&e^9юIh9'cNs*]<.}/^s*;Omw,Ft:Sl3UN|nˀ6wlh_BexKޅVTٴ~`fP=ٍVtYNʠ[<$^9utݡwqK$f:=iF}:�=Ɋ},nj6{__jn-V="1{ZO4!Z;ч)Hm`WBcX/`iY 7<>:ʃ>:*'gU}@0Vk>__^8FcV:2# 5$WDǚú)h}藎F+Q}w9Aex:/HGr yUaS9 $+ L+;W;fFcſDѫ[f[,pt:YЂ\ڥC5똮}{53d2Z}T(zb}%Z/ 24fUcA>\.h5?~}/^1t[S1FB"d&#|nc,h"ںnF?!=܌fXv"n |h] D#j.h}C3){hnFp:BЏ hD :F?Zۇkg2/`b&PJCljY>Q:ZfnsW:[ F߼rݦGFF&53HV>4gF3$t>2 ՅD^z]kO5D2j+ˢM5|4Zou~$]{GO'Bʈu77z'fnlP!yEtq1.oNku oPoKjY`}(2 ԽY^}E2d5�<~DK$D"H$D"H$D"H$D"H$D"H$D"H^7!Rlb@a7�w+T|go,OSwi]:Cxig񣹴2uo| ]3Akv!qER6j/C_o~xS~&�ܪ;Z-v#>5=W}s=fאjLAcrڤ:!ۍMǺy7F5bΣ^g!gQ :2r˩֋/})3ڇGhVmZGmuVOM֣ViˡcDh.ϜΦJAѰ,COnJR<;3 h0 ,e^d]teΉǘGӜ}FͩhOz5ϋT\:|l3Ut1t+w]2]VfE8 k$\ETsq ANnժ&UNj'͂c}Cb n> ީޱ{\'zo3׷=rh| _ohr�kѷHD},hdm5~,.<]!HmA +-ݡ 'ϥ=h&jǣf̕nr*VDqK4h76lzNӶjujfB#k&:֬f>F+ȃVhݗ}wG8̭>R!<X=Sy<]� 1^u+bƋU6a.̶/h \h]pOmze/acdNg{^<5th+׫6׫YS/O5+B_ ݗOp߳&TH9cVc!GIhb1EC$Q ]C"?TOuzhrwֱf.~腟Ca%N+ /B[[@:6bVs{Z wg4"`5x~Za;Akձ?Ȁ~h%p6qBӬ70ƍ4wQ'C=J N0Yo=Q&ى>蓅>~S1Ѕ,f\=EN4O dJ=?zkT/q,qcVnO}6nғdG{nnq J )>$J ;B5;{bc33> 5sJU-ՎSJU2'keaA{h? MAo)ɍBV3U]zfˈ�%D"H$D"H$D"H$D"H$D"H$D"H$Ip.K=\PkبfS繤JYުy; 845 <`reSe-ڀ\)2`:ٟX'k7DQmVy3zhc֐h(284Lf6{HBGT!vkݲoe˪CS39/9ޙCLͫ2gR972hK} eUhBhfͅt?Z㸙Wmvx J�D|jrͥJ+j^|ɀ몹<nmfR[ugAߣͦ3 h0 ,V^rV=ʬtxU6],ans*S=?iyFvtNTWA}3lԯWSyKVݤ69`VjU^J<7N4[?|2k'Tw:oD'͂c{6~OvФ::0feGD]>ZǣcκEn?<!h2WS__~vNF 胙 'j'cc@;uNBb9Tu q;8ہ֧f@2n4UTG__t*�3ZWǛUѓ< }HBNG/U@hVBRh:$:Å'}pw:` =% MMutJ߈ˎ??Fh}$FFn}DHy5h[51B'cG M$ԯ>:5O]j6W8'.u=tv D-G\/Cqh}}]2?FF 5sG7yX#OH4^܇2e t&1i98 M�ه6E4G[Ǻa㌭C@фChkK[hP[Lh􍸠A,h=/<: LyZ jh[MC=˃6$xѓ^fXüh-OT< CSer]`B1 L3ע.lՊB5|f|=31/QCc$1fh˭?7аjsy>,+6AFbN+dj7~T=j<OS%jR *I6hNYp|kfe;5 =Fߥک*fWJ%nqzꍢ=m}쭢WUͻj0K,1//"H$D"H$D"H$D"H$D"H$D"H$D"H$\V>[Aňt 55T8On=fti~lsl(Ӄi&"-Ge1$$xU*=8TlĆTɪ>cG1]WE4vq̀gQmļ"W4oعymO]x,o|h[VXeDso&^r˫Y c.NPo$zj<T fW;Oqsn2ط[F̓6{ShNYcrhtͦ hVE/pv+/lNJ0}Hm5V7lQs6ƎEYT{Z,jvYY˜vV0jg{BtMtYj ZхV]^mBvѰtYم!];\;4W-! khfg~ψ yC@'y|i>7qȉszo hz&{Wu$zO_mЇ1YvqA+OK҉h՝<ə_]ȳ#e>V2j85jf hA#l&=*Mi\;\hMV!f64PS*DFY4ڵ~ ghUm}@KW`GwD,<] :xZ y9=tR5^=9,Y}HgȷP:=5zO]}4߱hVGWi]m~O׃NRLf?LHu@j $0ž9Ct]A%OH4^+-NJܧ!+"hbӢƐ6T MmټMFhXYL89՜fJF#ō%) m@w(t5`?c\N^lz>j!ZKQ]Uq4<] kH<fG >hJ&#挠FBq@t>糵;[xf5cjpxNh`,F3Mt@Ejr۪8Xυ&?J`bS.dqj?f5l&ՄyA$Oj~h̼\t :4vZm=ɳJft8ejoVoǮmQy!*+qFGym(_D,H$D"H$D"H$D"H$D"H$D"H$D"H$\ gcBrCbs4VᣪAO':[?-~W0p|�id=)meQX%+ںd/4@is049@6d;x'a1yC݊/~ro7}h5x˫nkjͨ5fSgÜMumW}3;=%igItRo4x l/z;X }XaͬJ{̀G̼LAМDr2;t@++17;%"n%lLhVΈǙ55^GMNDSeYt$4]6/aԎ/VjWKAvWOZ^sftMtѹ&&ifMYӻ)h2z\C(Ϊm E(z(POfzaT<辜*^v_zg'3z'FCdzƊ4K̓w4'gOG;mRhټ!/  ω6kzXX}҇yhTTqsxmvp+>z__NOYx mfT*hb\#:kTJ[ˠ밢'x"ڿ7s'VFQѩuQ"a8СKCF ]ȏƑP}S%q`{hp40^,4*zAʈ>=i2ZfB]]  6 Q]wڬ@wqߝ& (yfO莍,>MiG%M GGu< ɍB4y[Gm5PhtlDr)m:@krKmZCZC2f1C ifmku ' ].GL@3#jm&9yFk>#93 C14xln>2Qm7(ڼڭ_ވĭ}PlgPTjChm?>W@% \j\ =U$zWܼ)R}]fL=3y<9V!Юu}\ꭢa}ک~E`3.^t"zk56>*. eD"H$D"H$D"H$D"H$D"H$D"H$D"/r-/iڄiVI38 Խ6h U_iBhPhll<Q (o6n/$>]AQ㾌rG^o <eW+ؽ2v˭Atї[nެnsF ClΥK֣Jm-3:: aU/am2ٷ|hXf$j<C>3/~;сe{^3dǚAfTߧdC+d@aDvXKCH4ZI3khCSeIh*Q=<U_XԮD(Y=iy͙9j2TS5] e{WYN�3̂a =c )S> =~paٽf}DBLh)݌hs1.~CemtR̓6:s~KB̓ooIjs Kǰ OAU$ hiٸY<*>0 jp[8fEi\pGMY(ӝHVzcu%$ͽZ$2͸ }dDCŕh4rhJhdn!cE /sB=dT�{s5ܫYQ=(6GP`Kۣ*=E.1ф?49 t됵h.szC%+j,>`,tb^~A U]sLՎ>MOS&4"/'&K Wsѯil lv`LTy�:?aЈ;()E<'>e6#jZ;.kmu:he3 6l/ZMF4ڥhh6:F85.D[=OZ֊pI jR2'31(A�qB)E/fjSϑ{sTY4zߜ0Nv3kbˀa 02 52hz1T7@^[ Ԯso"1u;lsnDCFtyL'uC%LL(5yv hBM9Nm0u||<[hă ~0b+`yx :fD"H$D"H$D"H$D"H$D"H$D"H$D"H$Xfu u~5ؙ4mYgȦYGGhnp4rl PL !qC ǵcZ/CnfrVܨCk56;m3oZe-zDu-3nO}C!sWљ[љ[}[A9sAE -N@;Է[6RXh̍<jkrcy6NuPއ qdmΈkdN ڪ̧K̆˦Fk3ѺЫBhnV=MQ+y,jxzQث \Q�کP2{3ՙj zUqAgD}T~OdG,h*#z{#5Ft<zg6?z̃J3{x[hVyo&m:ݖR щ;43{vCfC췗D'Oz.�j1ްӢ襀ﷷtZkF%mޒ躴y : ڳ4FaA9*AcYH)1+MSUo$<?.Ym8턳K,,ÆVZcus޽1 DP4/u(N%whBN�Y!A59![v*:haL(:ĞxJD-^$=&DѾUAnt`J͠iy<> 2DCsn 2~F!klf}6̽3 gsD# h`?>,u+^Ч#VENjANXAn5gGgR{шyVGEsK[@0EԌ>bhD Rs=o:n_Ozvz#,fK66Hv69Чf]ma^ʉcvvLgf@OF JlVd(OZ2f[A=z>hƿ{d6+13ژ߆hW+SЌ}NnK1[QI,VEu7\Y49V/c;hw_ hGU6o�ms& ɭf"T {%4c"hφ7D]^Ѭ {U"H$D"H$D"H$D"H$D"H$D"H$D"H$bb~P1 T4mF yO@iUa6a<hE#Gc;Əah!_QBr}te'ntYv9==ݲohzr_=}o8\}CЉVg0gWnk's0g:;]-z6~XQD<v7(ڥk fӇEꥲ<##l"nά :u<fVt_>WgD껕2ZWhd4Z W2C5^K-h/GMΆfQ+UEO`.Q2:|U+TP"U|&d7͉NVлn)ޣѻ1ZYzY6D3G&NE+pNYSѣ;tJ zN5^mV23hg-lcn!ͪ~Ep-ƞ{hCLȀfWCVh[2+iMdḒ@ۤE蜃r)$wqCFh&G*0|h+ѩjC UW>9YUnBdA'<U  h7;Lzb.8zĢ2hP7+29aǤ|h}d0(hCmuXGv4aL zݗh8W :`y&;6Ӄ[m rh﷜u&dV#CEѮuhy^Dž#o}$:kx0]K?=m0'dzE<'D(jg4.i+^Єl_f@/uݯn&@RgnL7~s>?_7)KW\>%1uq 7ZBjN߅7hm-Z3- AfsMu13bv͈&wurz\St~ jQh\b 4B @gjchF 3Tc"v FЪ6ZCՖu̎h�u :YM AtE@+M߾Kdlxt!1d"m(5Xr[Tgo_ #{n Z7hjhRmx+hׅv M5ybCfعI% ֮XݝK`%D"H$D"H$D"H$D"H$D"H$D"H$D"Hmi k4>S7T% yQ5pz𰣕27�;?[4tɇjT~qߐ=-ꛅfή1kɯ΄Ϊ :̼}}7 /:{l47:G|Wy˧*96fˇ깲[l㈙};p0nVN~6ߗژ_E#jXY}!cF;Ԉkh:XKVIVT9կǘ:ОFeLjze3fmd.5]>ܫdtd}G{vk5Yy jG}ݴhgxS͋u}QКݘh̓=3w9G\莭EAhmyRn3zύn=tpkh4`sCўFyNLgKߒ9af͋~ѭďV>4ߘof' bVJ^Bk~%G` ЎͅF;N1BO4^>C^o{,41KDˀ< 9YQn/ܼ�4M+ GU0rNq㷝}4bh<<G,^1襬!ϑhňuՁ]놡͇A.^m2yԦ.7zGU(XhYX'jZ*Z r/po^ˡApC>|1NtXr1G%uhy^Dž#Bi!hF3+~| ocۇN>4DꊀN>uɁ:д:?DW[ иM<QF_15,?(~',ߛ'%$ڨu#<h^Q]'J=y6o =vO ѭP"%6Z=sUИ@caVڡ;ywF h_Lo cuXC)6WW!F/jzi\p<T<Q2*&1hU̼nTyZ̏v_Ty\ʚ!0=QǬY T2x^>cݽ4%qZ jDӛZ-Ն[;]3Vl|1M 4~b[.4ndbf{םDoy:fD"H$D"H$D"H$D"H$D"H$D"H$D"H$$&͒*1BCc\5Vbx9QosG[C UD8 !@ŽV5w\<=cRiCd3G7ob[u9<`K[w嫑b^̿;tbΦDgRwh]M}Ў(VCe(8S4ј~Ks;I=Fw k = Rp,m6€FM:m&<mfU:<A*U h/O]ͦ~E4^<: =槳)2,0cl͹F;+2Yt}j}$WYũ{C wCFf^QлU{[͂ z}v:LσV0ڀsl]G4`s't��o͑n~{s!dٜ&:oo8Zhc ReFVF `$Zf8{{ -׆[vޅ6?s?LvZG[bXAZ4譶:=} 2Wi pρ[M-SFtd4Y}΄>AѶڜ h)ǼhﺱGqhPv qQ`ݜh. 'BrZXWCFʈY@+�9h!bjItB/гîCNjA4a#A=(&?eF8xkzBSЉ'LOݾNY94M؀GcG}Zж⪮xRzh~>huHlfR<ȏVׇ^5L3Ɍn>jkVW+>}Ww7+yȺ[|ę$-ΆVTzN֌d }jU{F4 __QjvuQ٬(ҷIx&t^I42jN*V@riT9XcK2ptў-]1i~Ӫ_Χ3>C*MhQBNn}zA=AqK)PSeah{nݝ,Z;e4_&6+.6cÛI/͉jD-3#/~It.K$D"H$D"H$D"H$D"H$D"H$D"H$D"H$iƄF}Mc<YKh ;Sgrt=wÕw :Jk6f5[Ft u3 1}yu1o0_\uyȮCw+vCTVv~E͇~_sXGgRw]KwYq\7Qiu'9z(|SЈ =KaLT#μcbjNHS؉w,BwQAW-F++Ɋ6Ki= *v7ZkDOpeЌhF\Sk3B+7Mw&\h4h&j?^eDDvE}zFVQkA}zOE@z2ʅ6C=Ly`;Ӳ7nfDw|9 h/Z9КMs'.>Oooo|hfQ{ШyAB:'pw*h{�a(MB1 2jHKA)EkL4a6snm O89 }�ʆ> ánv~b Bv)� h ̆z>)zaQ 󜢚&:>e* 9Nx64 zcVAE=U͏^5V5/ϭW I5A8z!Xv9ԼDǮ[Ӽz-6nܐK2{ֲm$:ejjp M/R.'zi`Д<}Ti r̔mN^h~:4E|.\Dm>'#Wu:ͦ:;|>{ ؋nBO7i'~R=uhm@vzNZV@+RmsMshEf:Zuh}H!Af.\vBՙͣ!Lh!^mhdG? gح#*EvJ%ё2oC^u;Ǥ!Ш:ݝ,f6sU9m%UȬD'Zu :bJQnpV/?yꩻ?g }[B-˞ jk =n 5 و>4wyItЕ0z8F+.GMtU"]==mX 4rBd]] H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$u4X3\݀<i6эyN?S=Xv56ꃃF+9g^hô9Ouz?2{mbFQ:%ԡptr{P2֘o[E;~Z|&pt[ٱUg :+|is̆;=̄}N&Vw-JS2E5tSqڜomУ.3ZVFm*ve^ѬjY6N #{ќ hӼpB}Z0Nڷ=|h6:'Duf ?5תmx^ﲺջqQ v~<ˊ R^YODÊvSИ+ޱ=|$A+7mȹĂ&k8[[8Q%ڱڂ>ND*Sg|"@ݮb>L|Alem fnv5z3:큘{QfY7i}#ΣIs&s4:j2F4۬l5gVz:U}E[FfB#<m|H&d]tDJ;oGB](:<A!*gC[4@;D2s%uںS:_Ŭ #Sf3 >2zyGjLhehw E/|ֿڨY::fȥ1hk:ڿv:hGڵy/f4SweG?;Rdj"K+MJMZHޔ]2I4m0m ?)ek󔡞E dG)kpg/z#"<7$O^u'!hzC)nkfTa<[tTxv<h͎ej/Zۣ"ZhEE*O}0yRۂ2֢G$@Vg6Z}">3]F : &::^>QtTGlQm1JʢvݔRd7{͈:fGm.DC*h琺h漰ZAqm.j{跿ڟ$ς?�p>93h5lzwmՆ.a]ImgDݳ-|t[.B+ZL3Qw!_mHep5/gb+lW<d]%fD"H$D"H$D"H$D"H$D"H$D"H$D"H$D"tiVL`lvҠ6(z>AԍU@*hؐ`rk>F G(Ny_~s4) !"PG0ڽ~ ::]Xcnns琣tfK>8xO}}xBj>tgn/4:i3G3vfmAߍn}%s݁huagpj7Ekq;NGyN݋~W ;~g3qsEa^.v;NTx'fQM-yze|]A4RGcjxz2sQ}7hT@kX4ν;(aЌlJcf5ϱ2ld hg?̅+s*Zzwf hվUij~4bf񐶶}Xv`'-dc3@ ޙl^&'M6m8ooo1-ѮЮƅj9}ۼ )>􀰷>LD] }8 eCwkPa9t] �뀟b>`h ؾ\bE4.'ccqh] z_mf/=tBѰ<1G[M$lcLZ!hMFW'#Zgfjp\wj#yF?HGۂ +͍hޯCV]<%ќ+ hNWt/(Gj#1WBG^`v{o~戾 ׹vy}"ߴf4�^_>Efdi7m&-ii#O,sM6?Zc4fMmrK#SUy }ӑoMPZ}'lf{c<>!.2+Əވ+UD}>[jm0gW/f]{yRBA;tbhCr!;�}Z3ڋ6ވtNV'6ܛZhU44Qй̓G0 ˘϶y=؉bfhN q돭T/tF톗\}G2㭎vyNjt7xT8t6#A+\tg,erskuzFhyr\qH37V=mTtY#Uhlv&뢗^FgǵN,_ 3uʟm %D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"O3;QUSW4z>A{#m@7ڑFO}]OLfrp7gW[il[##SV3&w'd4r;Pt!]DmQD-rƿh jtwPcr]c,q~3Ng0rFt_68gswN!lhP`wN;:цw,v gqfh#;1 9KWD3mf 7C|3&6uyqȤZW0h2ZMhZbkKn]=|1V6@ﲒm40khV6yFj-( =/BIBÃLUEv&cA1]qhk0wښJ4GݿpM՛!{yk`F*sy}`<W퍫\h}l.w#/TUѺu{8ͩh~Bև>LoIj4P ugDf4Z .rЖl"vTXb: 4+ַܣ&[Jk<6V;*-ۚ ,$T{pPk{&R{֝ BNDϘFߏʋރ-e}n4=V;]r{h6!'y;p۬Ձk&ѩCdz:{ZF4hܵ!`&B(E<s A h`w4zB{ND37dAWD1+cͣj#֏z!cRTE]#4_>Nht.Ɛ6=M͎'$Ά<Uhz{x^BR']<Eg n2W6ښUT}>큛D=�P,zAj^i*9;| 2+Ʃ^V9/Z mY :զ 6ZGYSS9'hV>OzPqs=^Цz:3i8٩&;Z7iEkXWק ZjZE@V<yI/c^/ec(ٖ<Ƿ-RmlBKVwdd-ghQo H 306y(,Zm<|ѮmH$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"y4C58i06<E<^5kQ5 40ՈOOHlH15P F(z#f+iV3#iuDsn{]bja Q3uFWMAPfFe5jǻud{L s3ȋpg%q;!NY}U]8gwi.{wzsODwܫsFiʁV$_:s}'ݜg+~QhEcqP4hXB>GpǠBʪ)VGgO/޵ R~3GwWh<&='2]?ȽYY$O#IA 9ӻp&t;v`,5Ã,I &ڲCfjh:/z-=﵎k;mĽqjj?Tc⽚fkŠ) &׬fF(cc[7 m9zG5р͆~B/ t~:Øч%Jhty8l}΂ q6=z�hņpzPgX=c!-~6ZG HN͊)@j}j.CZ;5g3mdkc:=O{b;k4<{͏AﳢWH ͉V> (PʂqLᡲ8jn8:!utKbQ[/8h+jin' 1ѺG߬^Ki_L͎ʍfVd1V@s_Bv0!^5_c#R36::C1)-~wI8h~CvFOS5n.}-$zX{ 蓖v=2.d;H~ɹ Gm*ns EeOfC=]Lyv%ڸsr FʉV:٥~">=d@ps-BwB%.i4幞iRF/hS=VmNF;єZG1+~)ea68SjG&u9iϗDkt@VN2hdˣW0V hDma3ol[w!]%+;ۖ~tqQHF ܴyE|= hwD"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"X>qiQ@Dhi582<YԍqDP j&܎X!cFnvՍ[ƍ3fyjdQхغ\Sk?܀_i.UE q\{}G0sƅ.pcfp}7=}N|Wڔ{Ϩn܋>r9_w}D'QM.sõAnB:%h�++j{E= U@Bvh� 2#w9ZGSwj<d0EO)%'j4Fޜٜ=XG{VWFGw;&mV={ ;P/zCfc�g6<X|\2yKSk.tb];9=͇ښ{+!%Icfm\h8 se,跷7'9=UxomnƋ~[>Yl ݑ a&۞f30˛d=i:8FAg=1 fE#" v9Ї =?xmV>/ըfE/^,G=6P;huTh7 mu{\?:qp@3!uXA5ϖ/0#= W%:%Ceq%m(c!a/8A(6Y E+՜fhfˠ.#_hgΌ>@s_C278Q^7k3ˡן8ڔTs3W )y\l#f ~q/�S2zQBN3z-O0GrVv>ߌHt@t^lJ~t|AoD}}2|Ό0{="!g{ hD+`.F[G[[R#w 𞇛_]Bv<2# :&3i^O9H<hRPF_PAsyvbIvISWBVBe1!/t[6B׶Ρ㵩K(ۆEB6my͒Ҝ8Х)yED"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"NDM}LmZf"fF&r~8Z?#7JÈn э ECAcCFn!/mh Raj9jc]W^M]0ѕ 3z ev<@)Pݳ{v0) f{JQw~Ϗ~7pJu[t/+`_66O?6^Px/F,۹}_*o, ό6MQu%*Ӏ];n&s}h #ˢG 3gSw;ݜ&7nLhKFɬ7]�SYӼm^I˴?vo=4gngEaz2v9`'ֱ^J66zFSx4\Y[<: ӽ$ϾJsh۬'=iyҡhDm`Ȳ8 6.q*ww0{lE07Sg4'Aw(}8 4p/a~NةTd=R:,doӑYB[f }4fGEu4\HkӈMcjVr4E;&dA/Fje㫡 nȂ9<}Ύ^nɰuଝ^͠!d#h+ w3`>S:E/8C([unN2^p qyj5Ex3Ulź;:yaA]Ff,g~MKLHzΊ9YđKzh:sJ&y%ʢf M^z{dBz\86t:5ms5'niR):f2DܧOyb1CtmH)<N蓙Jq-qsjg U:Ԝ=DW!ģ#VυѸ{fUѰJl}&7 p=1o }BДMrϕ3ki43\=ZM uM,=[ 9q8V;I$ځvk琶 kе DG7,VJ#}14v. 4 *۸ك! n4 %D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$e4%4\˱;`p@5[U/ƅ8ߦ=@7m\Ec>akFiFoExȓ tau֠j{m谚jtm =^22W2/ZwU-4%hMm*t~wucwszP%d,ٮXsRi;qrV}ЦYܘjfOS=c~*hFn ?`heцjq5 48:z.n4(t6T~+aB ?wsTZKnx==ZY+h[=_ifyZg,n2pD+7Z wS}m�R)^0m1؆fmi\|l;^VԾQ׬XamXGeʣFw̡,Z@w9yz{0<f mg7fۛvoáBz}j2-aOinͭГG[x54ojh>XAڕhmқmNGlh6 㱤`#Oc#øuI Ԯ)ыja7ы1l}Th >^5Ze/cq+sJj]+Pهlu`6^1=T1O;W =h JY b΁V&Zo-|f ͗h|.у =)CMe"Gl7^9mL W&UfMXgVSp3Oe#|YMͣZmi}S=i2ܱSЧ }vv| IY<AN:^x2SKeUZ-|>P;hf0\ <&x4Bj*m~u)Pvsh\6R?nHx,h7j } :zuIZ ͪ0rH~mF^f+U<A&C9P=߄}֡kkoPtmblڌ㕉Hͻi4.ݨKW`yAD"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$4iS[Jӌ™̇Q,7VF[_Æ`Sjv#-Q/r| j}u EWO4϶ٳCj|T x D{M&hV6u ;V[R{?UyFA$!9=5%?Ew "mm؄~NN߫MS,tnVh 7D5^hMy:;ZNjyVG^meYknnmq;~ ?DOnw/vBttzyn44sKVB(4ɊG ˌVx-2.Yﰎ=9LX4x@;ڜ<L%; Q{ @MlÓA6n(;s`ucjSk͛&gRipԁΤ~{s 4|;;vth[faޕ =G ,3Z?LOj8³n:ih8s,m6M4=5;m~iC t!_֚czws\ws؛w[MvMɈvjhkCc4o|=2h2֡އj5:`wl O�ʄ]H)r3GJǜ hYDYf4cNs'wЁСɍ2; ZmݶjAh61+wG.A>Z⢊#AY1eC蕗 K,vam#fhJ\'ʣ-M[i$Lf>27\ UNT-wh׎@&|ǬFkg6\=>)VhQ9͹Vcjf[JWD"3B]ҬγSh5 n&;htkSЩ:Ww6f@+\-z1 mݙ<-4/6&kck3ݨv ^Mm fD^^ѬzvmD"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$I4KM/PM'P-١@7DjQ$ʼA5~tje{l񠫨 @WP[# 'šxo^`afkW#<n9YJ>w]i5wqSE;a(ԌmʠMͥ԰&]ihFуl@,twmXG!Zݏ~w$~t9uMЫUԊxˡh^}F;/ټ ZhÅ6.>WC%ZX4zG1VB+66z�m_spJGzh5㵂EvFl1byO@tkK١ ?u%55= \q,,Ymp@;6lljYo;TO-evǨG<[=PE@P8 ֦ h<+8XG=מ4z͜e 32J)Nfl57h34hܬjjNu&@ZK了LF9NV3T{%+ чjhM`7́EBhɄV^q:ʝB,Q CC5yC20KX�J Ջ:zE/5p1+z*ܫ3-XognՅ>W ڼ ftZ :kA}"fm*՚%.תʹKy~ /'l;sy<{:gOm '/d5 G d5z6E#lEIѺXGjghs^9Vq7zhLUa2̧لp�@CT@Xt 65nuC@FhyppshE窢$Rӧjh渜am e309]iN1<\ʄӝ[WyItsK$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"HciVL}kި25Xج76Ey{lئ۬}{w `Kк+E>>ݒxfgN=?\WT"噹[<n"=2xf^69Bd_X-Pl֣{-5"%>+3=pzsR?K؟?NX\ U5su9sZu,\sR] 놩dk>~ [۟{+QDg<DZݬf:m>/o^]_W|WU0@@tsn ??c|0zx{t'TOɏnL So^n9:{;n&xrM>r$gDLwVNu:c饱ftfu:%z ^oÇvxV=vưiΣ>u~9/t?9X"h?𦏼zG/#AW|r8کLs646ٟ7׍Ǎ6wqvԵ gu3:9S/Q\ my:~vu՟kL/Dar1x}Ssrܧ/HǓEoILc՟ HS>={|<Pu{ƇIh~VMto54EFLQnd^wg÷z`V$z~E')H9ZWN>XW5jn杤ѷGU{_gETn}Y{E>g}V^[7uNw?W80"ۉ`MOO淢y:M<&lW Gnn͇?̹;Y5E7 lS݌/ѿYzSQi]^o=1Js>z:\oO,&ɮM} :o*hܔ~EZtLtU ^n֣K5luҶSt0:)ۣW¹|gQ_t_TKDn\,pwO\ZT�������������������}T: T5ud^G"މ.[WQarI^[!`] 7Wp .N,| :{E$9z-]%)iteߖ'g굻W{ucϰzڟsbtwhdƢ質Dk4/UG7>y2yQ?QwD9h'Ϊ^۟YԧT͙7۫P+f#b}_֚>0kы?ΊVwOPӝR36<?;C'e?ܷ͡:dzg|W8::jfz^йgxSߌ^k/EoNu>:ŵG㏶݈n񰳫k0qק̟St; RS͗X8j1,:!ncg?UxkDsD/]>iDݦoTFdVD]3O7`G7_>ݦވNOm>==yEW/Oh87s]>Lv/Ol%rvtDOve?=_)*Iͷ>(L\tR|}K#E~ыk7ĵbgs>}4 ;{甊S>卂nwFA>:F/MGǻ].mbc�ܮL}F(y#vJdO57QNӻD>w7nl~T%DNq~HuI>,={G} /v#AG7qjOލ>ow8I9zz3Yg7E}y>Vo>+w;juDt}vsf5Px&[\W=fGgGSMX~N7As&/Q2?~2}nf<prXonNCi=͋(?z7%QQzu<=MUSZu:VWtv:ף N|C%C#Ǣ&^U_=#1_ ������������������ߺ;qᘣ=$T]=v.Bp]IʴƊbً`W|=,.N:z~.)|of1[ᅣd.Y]3Q:l躱zx4VfNfj. o`Ot}uէMu4O5+CqY+Vo'sN?+e%ik[ы7'^M/O[D߃ruj^N:):ngΛyE<Z~v/sύ~|T~sĖ Z8Se|֙4:Y+8-uךOȎy'5_s$y|iZ uHk$my|:r k܆C'~ǎs՗uM;W=e/m=xcGdNǢE7tSїEB݄ħO\tzJf<;GGuAfs'y]p5"~8znh%Ty9]nѷs⯠tneS+'sGgEdCoeJ|gߌnέ#cK[If?!bѫGk~Z"PInǚoU4:ۏ~ͤwomN7hptرu< d?xu5_},silL{#AI47="oD9,ǣ819}pџ=OtؿTUt-чk[geGU:{~㚯;ӿӣJo k+ѿUGgGSt)*ކߕ\/u4}K'iK7c&^MZ+YO1"lK~S-TNuI<ij]DG^Is %;cm͡XbF0+ˣ܅5]tEt;8~76������������������@GJl5WMѕe;̘õUGz=:ޗiRs&-^bыhҳP,zk,g~+'{t]Ӎ2~2Jfl~%upk]:Z ]&3@xD7MnTGѹnc$lYn?'U'm>[_sͤ>zxVtqT7я&5V/W=Nt|ly4_3^424˶A999YkKӣ AJt'S3XNӳNn6^4P^+x;ǝسk\T_9ulڼ}ouH[qtG:n|4rT6<Lz^\>YD1](}9eF7DW7D2-Oc:5SkOz kRSJTLW?FN_I6?ZsM䢟_iG5N7⫏F/{ +md?L[Am:2}tZ|*:<\.\|Wd|zz%6^&zkךE7qhEoe箝�>z(xew1llrNtaR2jlVWT6`I^_5>/z;yanoeU=5 zhsEshn«n΋nD|=׿:}g5:wG2z';l'5gtoZ];wPcnUYcOkJtͫS{}FǗ "Cct.#~f'tgU/Ԥ2ܪ`!s +ku~Q'F"| Q\j^ c4R/H+uYn/.tHZ ͋h��������������������ݣA{XRVtOE)h4uvR2?XPQv1=u<JG^ti/Cxp#Z-E\o#.vsP5]7<iicϙM 0ԄP$:\ ]s M|ps\n5O+~(zetkc%9|S zm> > t-:m>;z|077swbrvtܜF'o EFtQ0zٶ[,'7T n:?g82>R+kы)R?k{Zw'\(]n5`+z|&*~%?i^md_[<|25?56ڦk>_n^F_VFf4hjZ/iZzec$}Fo58)nN*i{w<;i_kyU6:&n2wfOh⻁c?_GgE0a</mOhN8Fn9m~yq&ZՅ.dWd $<TItZ],zeIO,>֚O^\Q.:)y`GGKE'}0}m~-j*ޭnzVNn.t9TxtTB}g/zѻ=qrEd]x<1dD#"DW\E^ѻ/5V+ћL\-4oG>^^yuBch:E? yN6.Y^|M~ҙ9)zo(a@H+k=~_LcuqmZϓ-q]$~Cs_]:o|e4��������������������XRwz')edT,5UߏD*f:-m.RktB͋ီ]z^]=5æ=Mqt88.{]Vee{ft^kދ\ᄎ>/> >&[Nϫ':jÉ{ѯOnMTF7O2?yc+ף͸Zw3\,,~?egv꟟{k].Qs|s?{_ѧz}3^^u̷8?=)їSVu:ne|~<c/z1G3?_i.gD?.1\飯Qw͏W?ǣkdFNՏ6esP%40<3}0y5z%5_ 3{8:y N>6_f9m\]+1MmF=~]$?Hzsդ3C6E<s6Mф8:1:z՗Q*zxeuLW^MuVgǏW^T#ŢoX}lAxx?a$WtӬ6D3so<ͯ{ՇG^'盛۱CՌ4}9|SBa6w~Nssix:蝠ѷ4}'/}>ѵDcG~.zM1i^V1XyYll}KοD*F=mnҒzܮ9Hk;ǞD/G+xm9T7Jмo^L74/;hgkj~TAcv/���������������������o677W'Em[Q^W\&TGaQ=~^/J 2ҢKk/5DϏ5Խn|;G?GIAb)z"_]dϏ]gKw xTWΧ%AJNX>:\ǫS}/V=^-dע~/=EOI~6Ht0\n&NKEZ4gF_R6L{26,՗i~y~^n~\>\gQN~| ;Fڶ>cdJ,T}fN}ϲ} m}6AqF4Wm3DƒWg~|Nts .鸶]͎Q٦Y\zegz_xt<M0ǡe|Ѽ楕|9ѹʃyчfv5=!z%9x0ΏGO&z=M۝ ~z1g5n΋~_F/o OhFk #|)ѷ9ttZeȧD/yd9,o9c'\}%:F-XLud\dM^iќȋgmMձ:覿ȿjnnD]Շ-@u<5'w:8Y~%&z?V[w}N @әJU]EQywl^T;#zy56/p`Vftסhs6{ǣ]scPx!I*}etQ͋oh^.#گhN3EH0<<*_ ���������������������p>;5ժuc"j r+GiH<UL|"z*.ca߷踻G8MSXF]4z 3p]ft.Dϲ UwyU^S蹵{=GZat:v <wEo2ѹnӣ+/iu$L8]엽/is4pp_fVt.F<=>a3yy i==ρ򬓫/k.>G,rOEjqPi"gãŇ̷qꮩGxLZ=i[8xN$z5竚T S~Viu>nΎ^y{%M44,OGO3~>XhgɅEverW.h&x}i"y5z_ *Y?z<|G;3}^i%ѳ-S^V?չ擢_NяE/r F/GJGGo4G38Gu3&|cGn.z;ݛFo0Tؼ:D&'l==EW.wхw#:u]Tڼ?VBqIvkO৷/EtErz]:mb ALږd~EsSk|C2:ѿ����������������������{tŪ|}vvЮ:{e=*З1DO{ 4tt]2M-+%(J}/:.cMI}Nc]df޾7u]Lz!z4:\*%yKNWJ 䞋wU'ClMȗD'CuGqvMܙ.M#F{j4,w=/iK.[Z~6?墇e\cyz|~q,O~PAunhۛ}c|S5S04Ô Gt;s>?i%͏6nǍOp~<ws ^~>iIu5.ecfVnD/=XS8:ݳDхzߌڢ%.?T<$_i諚ϛeĢ0=.i~UG-z;zju][Lg:rɍlLmO\tn}́E]4]Q}vWg SUU7o:g\/G T][:;z/QGolQPxC}ѥ·|&};Wao.[|apb濬Nb{mDkbwK3Z.{˖¥х;#kMz 5#G7_]ozt-Q[ߛ2-ؔ9lE䛢G_ ����������������������w_9$w;:wWɤjǢ$Kk8(~GՕ,t踺ŝb\/ݤDZ[.<En>xtLya.8KgtyW.WDC_-'&.&sH1SAQt5E?5|IK_}ѥk^1f<(sy=/qxxk6n {Feh605uBτf}|<y!T/.n#էFͼ(4z%LuKWs|TGwtr")UetڔXN.{qtSљ5]mǀ-߼|$£<ruѷ~3VS/Y|q'6"EΞ[B{湛72Gύ^\}YF7rWOb^n ѷ='6Z_uE7FܼxΎ?@^u 5oމF߶5|>濮.w٥?*m0y'HtޛѥsGaJRXmsl;t݊8hkILlD76oo^.!6F۲]k[RM,s7,�����������������������Ⱥ'25G,smgzh/v8F]=d ^7 tZv=~f#ߵUcrW/6n5\s6vnn~CFUDD5љp$]|lJWG<]&&yOљu>^.W Fج/OGK@sوS}y%O 룏~xy/OIKTw]|R\kP>zC`~f/O)} =C 75u"GɽQEҼqܟU7A:EF+EWfFʛ"я 'uIfk{n2)w z{;͋Ş܍eSu;|;+]}xo[6%ExSE|/sFm/}ۈT&N~;_ۛ3} ۧGߢ/%[ƹ#D[>;:ѷѷܾ=6gRms:?G=7E)ܼ5AS(yz: 7{/75ގڸzEo)׼7_K6(ykB2:?V:igTټ!QgTW]DGK孯zXO[ѥ֭G.۰]:lKQe8٥6_hnǤafa ����������������������{ݟJG~8{-WIQw-cKۏڪǎWyFVt/MzإمZGL[.\HǍq5ipXEљ^TCu~a&.Ug|2:.ۋ~U,-ގke3ir]4tvY=-^N%]:+x %}Iv|FeS#sF_# iz^z|}ef_CӋ爡)nׅӛ_ ?' )=CfFmIZyrtVx'5zrs.z&{6nŚPWfo|Rn.U=^{uVWoӛ8|+XG__^6M6woBѷb:}>؏FVoY}*.R,X8:uNoޝovGhD5QQfQTaVr7_VƑסcuE$gtꯋX4z#|c|ӛ]:M͕G9%KC[jFL\]2mC ݤ_<e&u7V+%H"yȌ7?`�����������������������ﺗص(?(oUwgCtϮ[4O5?Zz7EOM ջ@Ms碻@%{csd_:;2Ձq8>=rC\uWSr l,{[%<Jgte/ڢrI9.80^C5n۱z*/=^}r=f? E?c{N}89dIUVQ%ͯ6Nã87I4壧1 4v6Ds||5͕Qvt[7(Z̎ˬՐ .y'zyD +^Ft%+zѷ].|[%]ho_}Z}ss]&y`@-R86lO4;/}oQBڳZ[iͻ{5DG4/2Ff7%'s󀂽MqWuk{K5EW}tl.Te4zVtzY[Yky&)t,d\t=Y$~A(\!n&4ϡ㪽*O=ݦt������������������������^:_}Xuٽ{ݏn%z-O^2YnjͫH]s=g19.05/ܦfs1S_`e 5F'$: L]E].XR3t5 \LV'5\22q@].hK5_趝qtr^w}yy=g_\Iţgvn~댒MP;l<K!nFPEtnE1Vm$nѦ(ds2z<In\jsbx@t&X&U$oDkN3Q%'SԖ-ND/bt5^8l7&ѷёѷP]vV3lHmVGtsۉ%NK?Frӆ4h-[=TWX Dkމު.לV/jMdջ~+ͷcJŮdy0:_3\cpf]Vid \ 捩.>6ogͽR]vKe?{*NnМDE"d �������������������������QT:]]UϡKo9GtLW@R,TMe]{u=WT}TT^;k{/vi`vgDEƺn?z.#UU_fkѯђE_.]:7_WIr-;\},~FG'ڊ۹? 8Em;?I5"7ڹ2:(ӎfܶDa~&Ӽ]L|)A2z%9󃛕ލ.Ud*lN.D*ln\Vcyx &owu4"ܲݺbCѵivg.[;:}TX?m I_oye4i%*%:9 #eWtܵfmGg vl{͙C e2z)Snsd&Z4?m&UڼLw4ol))Vws`o9:S](萕B5GU?��������������������������?~/]/뫿-eݗU?rZ ݠ >UJ}vP]TGyɮioU˼to~r][]PtU՗^Ȕ. hfz#z̾^WNi.d_\IrOF۹:^ GGCt0 ?)Œha#Vxt=;0:m_ 37_/,:3^D7z<9+)^{D,nV߅f1VD]|! hoΜ[m>JeEVKI;E['VKtn"ll#km:l.='6nzEmM(,|<U}#}Vr0`+k3zBF:eYѷL"Tgd1-4v+i5抗ǖoln0yV.����������������������������YW:=ݠt[/^uW꺪u]WsJ\Wsr$K˃ۏ+̸^Fop5Ǣ抢Au%ZclxHąDN)[Fh۶uG$!i.Ngس||i~ =:.if+^)9X~檗tԷ&Lgd9ٙ~3Eh_&Pte+k:U`i[Œ_=ͷ[M뫺눞"h!N$6?FJT&挃E*caȷDG%{ѯ]*LunIA_}k2:VyJZ}͙co[UU.C����������������������������o^_=*ʣq]km]իi]՗jYї|ݰy@kR UE_1; +X},zy|Jf\k_EI?۶ ۧLt[gt;m6zT*q),L[]I W6;"E󢪾fќ&y%:<Hs4AmsyHmuё^*OJ|P\[Ft|h[}{*avޒZ[&:=/o 9}~^mckmqWat]Cftk}{mpzں!V]s3+*_#0�����������������������������LW:/tԽxOzz-n?J۸qDU~H۪Guʎk]яR}YחA&9vz}-Fm O56Gm&0Ώcm iWwt0:63Z]uڜ5vk#Uct3ltU2gUenE5~m3㣙*ƙnyEn24������������������������������ѕ ]}]}]7VwUW˺@Ra2SRkrY1z-ӑ!geptfCs߹뫹ut~צG ==h0Dؖy-2\ZW*(w7VY]:Mh�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������6Lq{l�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/templates/brodmann.nii.lut�����������������������������������������0000755�0001750�0001750�00000001400�07463231644�021311� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������=��ˢ�����Ƹ �6^&QL��^^^zH�˿�l�f ���Zvvv��_e/vC��������LmQ=�6^�Q�����Ɣ˰6$EE��/� �Hff5�5f B�BZ��;��VV-C�����e�uC�Lel^�6 \8�����l'�C@*/6S�L C���ˢ��f �����T!_�hD;5PT�1�����FsC�v����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/templates/ch2bet.nii.gz��������������������������������������������0000755�0001750�0001750�00005044016�10403112316�020471� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������݃ D�ch2bet.nii�ےוsD8$J$-<F됕}c Rx? -*W5AZ3݉`u7wڵ;"~ɭÿۿ͇:Ç_F;?W_Dk__ӯ;i淿O_Eo ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Dt���������������������������������������������������������麮qE?O0Oct;$04tKG9[7M8DOt yz(1Z:]8Mct;hۏt;kǡY:������������������������������������������������������vwC:襃܁ơrft8t~n,gki躶ivK9x8}|raq^:qGI=Ƌ(o&Z6C;͗;~������������������������������������������������������Ii/lQm]yt;aa[ty<tM7]sq:}Ʃa5N<vp8OC?|hr0v/}r>mOt;<|3 9.\L�����������������������������������������������������:OC܍ uSuK9_Zu7ԵYVv-L0ơ8iΔt,WK9W;L0<Nv0qa:/lpp.eW/硟Ltam.Qsu˗N��������������������������������������������������t;Jgq'ә.e\P KmK3t���q$]:ŝ+"TN/|yǾrvơar0gaꇾn{ K9O>t;<uqO<0uwSax8~3Q>q/Q_<Ln.e R]D mo1������������������������������������������������7]7;mYcA9}AuU:htj_i٥#>F3) {S'nuJ-^:v;LݨzoRK(8ʹSTe}Nt$SZ%/"2+ƦX:Y$md\Ud+yG;GsAE[>ћo~Fi塷6H&K'Sߟj<nNq'i6?>-Qt('aεy~v0gR}?cqK81 740L_Sn8c{!3烄q Y<8Kqi>2Qddt/|(1S{A2žBZ+i}uA/����������������������������������������������~,^:y:d w(CNt,ڦEjiδ͕֡*7 z8mQSeQdtv<?jUUuS6mM a.|˗V۝Wf1 yHط,9_8 ~})Szln{TZ{gRm *4z>}K֩=%!h6a|~IVs.Ym,KMU5+xnoxY7g]iY6F_Gެ֫.l`Tu碪>N9_Y>#w^,&mmTZ}ٶˏwrS9$elh(=fǑȑ4<vVڜqU;K\*ɾ9rUDn?>pA<YG'q-,+6~{MӍЍsToi;n}M8Ӝ8}ӞqL8}7$Ep88K98wvɧTǃ| &<<̒{>iIIK4uo1u<͇iz)\Huq<ܚ/m[м͟QixO����������������������������������������������˶l6Kgm\Sl(g['.Ҿ &Y:̙6JRR:eSYWupK:*Θr_yPA- yk]m.m&E𮨜V`^+VRƩ:/ʺ(UnUS>bnVuϿ$:OYQVe(۠lMi-'/*gn,;,ƫ6tGs/>nvxsE/~./&!SE3h*}P>zzFofuepemcS5}}[Ǿ,C6ۺzRy$7^Zv:4A^PoKwЪ4k&Ybt|n<ƵUյM7 :QsU0.n()÷Vihh|f|<I/+ yOT\.6Vir[ʶUNچnghѥ&89>d~SQ;^義CػԆ}08':&Nכ7.ūkjl<CR?Plz%ڨ$QYf7-gcmF•;EAïIo,l&Z_:͔eBy^GJtTУ_H+]e}{Yi_mnX[dmi"D'Ge-M]wx5F+g-_{ڇ*$!6?JU+u}s_%66^8ڛ8}}S>3Y !f:e<}g?}?]y_^= whq]:yiu$)0Ji<OCs[{8H^:yay2qS}]8OJ);d>w- rRcts5W/cs ʚQJz/8nl9v|.?���������������������������������������������x{2wKmkmMrD[1Yf8lsW/ ^:9n<lQ|U$KG:XP鲮JzUxv+o3*7Ua܄Z!NW_DWk㽷zЫ]Y >z"NޗIR[MtvYgJ<e.ɟ_>YŹ,ϵhl}# qYk+NV|\]3]8]ꪦmڮI`d΍W<^of){}Wl9kBR]ԭnvyɝ8WIՓO?{ѣO>v̩1^%uoVI7{tJے9WYW?>}+L7ۭ|UΕ֡,KUrԕ٭6ý/ō=F<SԉWZ74!)ʺԺlPh[wMYt#N)uJҒօ`g;]߼:KUh|j,J&Vr5}:Yf.eaI;(4z͋oG4HͦnP6* .mPj;;tLS:/}Od|J^;)?KP:XжEir*z}YRJ͵ܕlN_+/iJRu3 m-M.<• 4W:zuKyj侨x劺r×Si9ʒ,mSJ{>2szgVe7OJ gyR-u :gO=O2o+J;VvMW?\اRrWwemnΫP(*.m\,GE_8Wv* iԡGY;]>m@(faIsk-|S&l/^<B*E%ܖZM"SU0_ʶTx$ZBvgO<鷣O{#;ץJJ_e4JHxIU}Gߤo?G˪ĔE㼜7q^HnHu"70/_dM%磠 KMZroUhyW,!?$Ǘ_>y/oxIf#|K>G|4Іz:Iɒ$:ܷU3N >z6^8e04t$Sa@2ty>MDW|z%9\G(<{.#(N0as-; +St,CJ0etd%,s__D4Ǘ+/?PM68?|q��������������������������������������������%jXgtt;Y'UTlrUj]/;.bʳ,m[ ɋZ_MNäJ\W$1f^yq7$ύwKo*5VIn6N9%u嬫-e/69*^u'Olvg}X¾kR~ZҺd1yoN~_7_zlgL.M&0\Evۿz_l6.ˍ2{.Cf?tI]QTKue%Źyq}7\p#6m2LQ6v}ww̱>e.C!tySY7IʛR-ݮ}[|ԲU& ;[2˵t<3ZiO>6T\~rEpF*5MvV̒@Jd%B0_8f{,iQqwש~eCUIЉh@vMD:*6ɾk[ifuQ53E/M3l7tmTݷ:6~7s%r4�N#?hZTߏ2*uSYSuMU;]=tKWq9.%>Mn4NlR'A|y8K.rǫW2t֐jeBT>Sȩ.J#ѵީ{MK<qU5NST-dΊ<w߄M;Jm&q^cB,v,υ r +nX(kol.&+d_ WUdܔ*T˪꽎Ss3ojEe1vC֡.>}js[iVNkUXnv?}vL[J}c.k\LKʦr~jښudè+HG76ul7ֲ}"&tAjANUS꼨% ZɉB~]}j'_%u);Puݶ8y*/`ӷM'y{, * 9MH]ua2U2)GFZWU)tLqmEONliFNժ)l^T&ܩgV/#-2OC%mC%e_r4!/<B6=n\Kz~jijH0RKuTiYv+.ėA2˦*tx/^ }>zVX)YeȺSwj:0EGiE9~'>6/_ϿgQ&1,)*([JlFՊ8F,S?bVR͹DF6QVu8./#}?f]GrJ#̒mO~cvD=fS *kJ \<,j^œ'_>>8qVa>&r]e[ܚTɣG^N6T4艬Hrˉ~w6?LvOatsc/qyq#qi:$4K:p<i|'Q")>9z -3=/2C%k4ϳ|G>CޞBRӲ/,jx9^<<4!+nsW\2("-[EO3gK��������������������������������������������z�w=7K6Slݬ6.^:<w޺tЩu.;gjH?*ѾK|-2X^?d]Ė)I]xe {]7$Yo__|J}US:m˜pz}xƹNkzk%eek}UZeܽG^'y 3]Jp?„Ą-DpEE\R{ko@ >ERc)<40�Q>y2>Hu3姝t]xo-]ZsM9!CW1>UD@A\6q*lj5ypθ  5aBpƄZ!ҥx]`\TCM7ͅb{qvvzs\64MbV/*zWTsV~p�((gNÙւIBkŘ@JETx_ ?!璳j{OY]pc@FkL7j&Ul1 b0ƠgBֻo']Q]NBt4ʤcX{_IEttN`@r84Ntף -+kO`%TE%eHU õB ۮZ_M*/B+P&HP^5ʸE46_NyiccGM&e 3H6h!BEBeGӷEӒXq 8p-$8l;UodV4L;SD#EԥM򴴭[P4 \rMAaҒ*6ƍ^V1VbNB5kދީfA;飠t w;Ř4N$-X\'ЦM霬pM;>Jd:W.*! jcXUs!h}F&c5)ZYC?8ZcU4uʒ"crk&4*v1lɔK*pc|<d%B-kxI}i1 mw}[SD 3TVSDAqbXH ѨO;FQfu\ĵߏ]K_RSՊ+;j$FS#!%£Ww䌚`eJ&V!J>N:GQ2߮VK!Ldj-<y.c$'Qǣ2gaztph6vŪT%J*8<Zc(3Pi3wt=~I÷[l`q@ajB5]K5_1)&`ɘlWT5߼o^u0s=T =@9jF#CՆaf>=yuG~Ǘ16*jABt7#ZU\Ib4srܜ 3<TE,X}*ٷ}TC: 'sK9DٺxO1(tJͶ.*sLᦅ覬@ Wʢ"nC$ -;)NOO^N֮OJI%q'ۤz%ϲ[ηuwW?}  'G/ݦ뭧$i1hfM[mHU{g۾kv/߼}+ZV|p^ovwz80ô)c_<sLJ/߾} I8W4]]_ݶ =!_i~~?GAψ,CV 㰟q穻mE_y'4 m+TjOWim *84]ﯧ&؛�Ŧ륟VƋ}d2L&d2L&d2L&d2L&d2L&d2L&d2L&d2L&d2L&d2L&d2L&d2L&d2L&d2L&d2LO~|}qqY1Vom+ zzZԄ+ۮBiI-߾;|WJA1F+Y3m!5$a9\�mQ_b#9l-4HF&5bsuzFboe_YUYڮ//B_Ŏ);gZJ1]Hj+(KO;o2A1Y/0(/ojtJhtpFm޹FJ҆9gO޸[ CN?tYҼR߈j{\^ѻKj ͹&}Ҝ&XעJ/i$QW9p0 03ia;Ԃ+%הbs[ )N۟Mk&M]t}gqҥ.IR~9;G_ՔTv8Iп_CHKo.Búb˚j<37T8oьq b>~j\/y#t nb)uPW aH*8ysdQ9Zr\q肔Hn!i%] Id(gJpdxSeVS-7"6VUK~REȷ;'Rw֒K0m)7[%ZҖSJ-.V;o* .v4)Ś9!ծ&õFc\#+Q`θVpw%ka5mm&܅v?8-J6场SԸ.66M'H7)c.{+׸Ιq|S2v iNdJb&"ݕD88r§.jeY%"z8Xd SB7S(aԣrrKAv@: i5AJ`,[Ν5*4ʊ:ێQ"IB(lV_fh*-*$,D r m[UU skTՅ MlF>ZLv1WPDZ.-]J�C):KjXYTڛцawzŜn[A#q+? i 8uJ-D%= md{zrl=W73 TpDUtrTs)u',&;$CZLMXI І1>;/jRC#olip9.7 m:&Er%tQqB<X<:pA\ $Ss8RcRܞ(}YYr؉9k"C^<cIFa BNg%>E-ӼbMmˣkGt,{瘌={y{5ɋʚajCRc#.7˕\rI$\Vp L9#Ku!DM1"ѳqgo!EzjԄԩuş T C⮵ 5%1{a b=yx~oųOvخQP&v BbclcmbҒ?Ȉ اuhZ%q.ǪOV'aj;RT<g wwI R\@} hNsZAlarBA rΌDEJ3Ƹ lGgbl&ūU{o:X ,kZ6c-:̎c5IIٰ@.O^ī~$w;ӍзǧmH%^Vl6[g?+ح L)yf+o^뺶Q<yuqvRˤ؝W2ukO-<~˧/iBa~O`ap[vw>yvn~?]<ʧw޹޽/Nᅦv񴿾ש9s^?>\XD.O1B~0NSmE_ܶ_>z$0?'M4⻩|tpۢ1մfCqxE}F~Į'ѫУ4@cNm5_ x7ы[C~?=߶L&d2L&d2L&d2L&d2L&d2L&d2L&os9#x A'R$Z @{sM78 { &fgcWTlAլΛyT*JRT*JRT*JRT*JRT*JRT*JRT*JRT*JRӓ7۶m>w|vn(g\jke;>? eTCЬa{TYR(ŅqΗ?oo4C\]}盖Huj#)Uݚa#۞1Jn..>fÃW!Y@t`R2]5ӯte\Y75mrOzℲ~{wZk1d9<2!1B ^ Ԋ7u7wܺVX#Aڕ=.x 1a{c|Nk)Gr* Nkw?>_r1(&Jr6$9a6gĺ14R"p<IqS*6?>ůF};b."qTIh%2u=Y1f|TΖPuH*d Ɇ7_8;{PLjs99cD!%g֋FHk9ڤoSԓ߼|x_yDIǤ)S j`{S265#FDs1C8D%'m{ͽۧ MTT!w6 5~^)4 A-):OEJ/^<{?|WE!% (i)7O9nOr6q-ᥟd tEoҌ"�7OwWPN E ʱ,Ƙ=5vR)B&1pin.xݾ}fæGR<No9y<'k:AwH:y/:`JcF8e)ov`r0N0{#4fmwH-Jh2 & GA9!pњͳeaoT1Y7)[<C:dYl6lB/~qhL1) "rB(g^=+^ 4 4rH8B{EcZgi;Fzcd\+Gu̎epcq!`9`@reV>&5_#a~ 2F Ӂq6F- ZEV6plBRAUc8Ӳ^NAh%J?YF:tĠݣc6X*!(+ДNCdLiIͦKk 2Lv;cpvP2)g2.Q-\ə4NBrDϣ"0Njg1hVqHotaK ?^8{NB|JCaʎDzGQAEpZ*7[hhiv$MAI=WUe}y o&OH iI0Rurcf!yt;zҘh8-b7)&z<yI2s\$XAl@rLq>W 3ۏbaX@qiA!m+1 ~BxQs21Ξu,\ԫYSh5 d0d`P3tIƆv}Y~ j0ݔY {Vg`QCh̗!4MLݷU2'EZ4z_N=uUcP_w<28B2CmΖ5elNA4 W9R[FNLG/gw<:G<8g)S0 aIד-MLrPpc B d<& w$?_=Eb ӒnxG3UP2ֽXOA2 o}ݻ; :`2)x}yx̀ %f/qcz]ŞsAl5uY8b$ʗEA`) u`{jˡpYAbcC9w;lx1;rae^ثaJFOt GgG1[iUo;۫5yqL0Ci`==yv+j_mUUun-S[.G_2i>L</ÓNN<-|~{i }vǧ_?Gjk}p}<^õ{y~rv=k m6īw?x{>NtXxxv~rzroqu(_,d9·om2?{r\CQR#ǒ#F}<}>bd~~QǒRy:~scñ4r>-zN,)FIOѳ7?wPEcj`??~ֹaW*JRT*JRT*JRT*JRT*JRT*JRT*JRT*JRT*JRT*JRT*JRT*JRT*JRT*JRT*o8}۷M|,{ eJGoGp@@9=WAFBiB 8obm.Nݵ߾8gKZ[}@rQY"li-Yk:2EEC /_?/HpL{9ƻɑO&=S.ZChbSqSzo$Ma): bVV*Hxoփ{eu/ca_XOp8WH&$twwo cQB<83;#)ևP2uCfϗ1"8t2i6zC{IB [%]!':戎kܨfc114 ɇ͋;@F(T(z3+z+\pyT4z-Iݻǧ_랳/ZZrI<EIAy=2o֋YZotVPЈ ۈ=4?~w_i0P ]ǜ!NN} z0\/%P[DIڼ֭/q/[0ɀZqDj29f㜝nT>Y</D@aʱv>;=Z]J;χ, a KZƄDb!ͷw闧?yE5@%JxZFCJgC}ː# "&&Oju|y=QA ə4a<,^Ihb14 lcDYtqDR㳳ӲWZ0?"FGW~!":$J ]4(ŝnj!BF U{7V.(.,pJ9a'D8ZײvkHu=um"!Ɛ= Iv5v0Fmr,xƀ|fVDC~@mnj101aПQMHAŮLb(w)KP dۚpR1fL++q%/#bbq#h \ߠ\j$FcNQi9d!mFmPKiAs\HK 1ؔ=TK)Qo$MpSNZ1i+s_8B zY;GnKO0fVq A&N(վ<.ɈH$&_HLA[1Kt<:J;je$KͮMf/HQ^#yv;u=DQ|l<w a tҗ C~ˋYKl9ehB %bx ?u=L+5G8F=4srъ=\9;?&�i ghСK< ƐrԇK Oe4cКR"#㉜ er/gJRx?zm Zmofd|4)y:)82ᣔު9=5<ȇI  Ow{v3{T)';8 ._|D "@LH3qy@+ߠ||te (U`{/!L2piV<{]׀r4J+Nl9G G3wełCǟ&vMC |Ur@BSWݾz+/_g8OJQq4="52 Sy$h.M0 FVGUb Wwǵq1(nq(]ݰp�P=0![皬F#YZ,Zwy3?nvo_=ܾ *OduP FQEJh^^n16hC{�0-6N-/޾~w<xr0) 48cag  0V3nu~Znc;~9ɬɳu갛5%v5̘0(p^v Kup63~5-g*%D'aizԺH#)pQգE!7Mk4 :ߟBzBSlgS!-G0"܌SrWʠhyzuHn*Oq]V8! ҲLzUD6q;9h7,i iFѩ ]U*U*^yQg<q}zMQZ-fS784_ֺ.}Ȼ nk.K<a<Ooگ8tIe8·+&^]r={}|.q3/0z_<-~<{G9w<OTelN[<ݝ|/D< {j9n/M�!۝|u==^kea`h.r߿{' O 9?m帮eѸd eΰvA΀d\{8<l,@<kۭW_^.1d7کz81cT\hⴎ)?h                             .7[oCk1ZY>hu8m|wںi9t{|ވJ8==;=(jW}블JkɅ4.M7ۦL(k/RwqQZIila.B|a_\8=!a(ڥv}frɦe{Rk`{nqGܡD>d Vހgl4E'gEutB(2.9W>Ωk.9T"ARn^s\wGW|7g:R%RtN8Er"epl_(T w[+!97N!)#qj .3jCȚ餆ů[tW_;GBE4j.]veaq@ջC[- ٳ?ZqT֭IG-47+g=Z7\R{۝|y0OZ 7NAf䤴Pe2QI`8! *j`ٳ{=0ɣ!y˦4L`^ICÝe[K-,?ʅAwo}[}zڡx[! y@];q^'$ZxDHRqL@g"(&dѭ_stŠ9lBxBMϽe-?2;K୴MC$Eɐ/ݹɭ[tZ +cwa^`CF4<%#0lJN4S8`1#ύ\yՓwoݺ}%mqNZH#AtM[)7p ;?MgbcX[1HmUٽ[4(a^i5 #)L{#=WB*sEojZ!th;uȄHӧwQw<w3˾1n48׭FI !?'wBPvTL:oV(g>lisƿ5HS:L3.!(OS#bL4"1\uʜK[{EѨFD4E0,:d)߿5fk<�ixYiN6J^Ug Fjٻet۰#Q"O;ۼf=R&\wahjb2Nš:Ô*.DwӇũ3-tIpNyP!ۅa?yPe򟃫yw͢%!y#=\ \af#ۊ#"'w wGFN El㱪Ǒz5JUyR8=jCjn4QFW8!�:KB(kRKJdlsV24ȬyO:<L`ȼ 2FneVF ?Z qLk&S!ם;Jnۺ',v iiѡm̨13YBU 2\N˨,>YvJKMn4 wagh㕉Ѫ}xBt{mxSua7U 2~cVFWm:1)T;?LO_V( l-D}di0*&ݖcUQ)k )zk s4<N|~xFhkŹ1ӈF㪿i0qEٶD?ua>E0Ӝ-d53k:h)>M $1MB ƴ_fN!\{ @j\NV"&Ua::{9@_ܻ]ܾ}ѫF$O:hiqҌGH}M] K*Pc<*P괠nnC[PryvPHfoU2Ţ́4mu[rKPPebX?-�!EǺg;}q S)eX#Fg]!7kŠsq>VxdWcc/I9G<*67hZiP53Πyn-ƦCSUk9Ɇa:<9*?}SWD$1&ˇ՜Om:xͼC`:$4ʣ۠w|Wx~ϡ;)0˭AS]u|w:ţ5-LÀzW=.SLG3Cs M{[y[u8>¢Mu]<{٢5/~k充l-+־mwiS_yCwS<+-盎;s $6&75^m>,ZǴ!y˰{_<(=*!O{O(nΠj7o7n|~??~aew~y7-gh붻xUǯ@뚕?e:޼-^}=7kyn`ؗ<ǿy' x\y9u͜a|LpiDuyvV8NxZ00_"hL>_Z^7eʏ-7aAAAAAAAAAAAAAAAAAAAAAAAAAAAAqs~Mڮ6[ЯXN?k~P/;ݞlaDRZCΦ!Ye;V][^Y/?{4m10c߇଺`]'uZnǟUm=ȎI}LzvC,ƥh㜑EgmB0 SpONf4W-`:׊޼ȿZq5R iyRp!nDfؕoxo(XRjkr@qR3kXo̕6RxןX}aS}C HYes`٭QeR>Fk,H.}?]n[Ww mY؉֖mQ"r}y )`ə:Tz[ FϭSU)n _Ojf1RA!knārBLh#Ra \rۯZ3Қ2%!pT&>`͜S" %oNsa>ڋ'^FB[-;Pp1˦ʩC\vgWn@U͈aHz6Z_ZB-$/%:7mN;T],j(1Wb 釣[[SPp9.J)yu<8D)|}Q ~brmZ8m/^;UR oySO0d^A̱Yw:g.v $A3zʾ`NtIf}jaJc0A5rV7]T oF*6޹`zy{G]<.`&Ab>`8F}y꽅r"Z-JXIzc0m>x|/<F F(30^'0èT{0rZ"e%lBZٍ+<|NB7^={5ZBu@Sv<va79Т3}Jw͍ƌ!ڄ[h`˹07r8@ \)jk]/jC߷/ h/M+vBhgHduKi%*ctVC~@hi8z^ZsS.ti@h%)2%~WR+hN\Hl&'ۖ)~vtD.02a7a̺lfVioR45U&D >O!bkuB6]V5Dq0͠uz1ԛZ�}vEwmr P%lXAlB5EYHC[νvFuFyj&}x s5g3,EOWi R J%YjG0:r /=B7}p=L=oZ4Fb'5QG #̥E3UKd*9o_=d*1sf(C?GM›ĥUp5HodHBh b`ggا^2,섙 L|s<FƤu>]ucC^YfܼxZA̡."NdA_(V1}4LϤ/hqrJl;/iBe馄m$4ﻏox4VQ}$Y8$QU26T{{AW]rݐ-Tc<yagVXm毀_<Zs<#! &P=gY<" tj6uNT8oʛr9tFikX+lFNNeiق8m3Z1|ѝMW$E˽ok[],Y"+G'/-$`A՛G?pJw 0aO׃SpUs"nz7 CJ'#Da4ƝFɣ^Ąz=4 r,lU {7efU; rp]^*Zz_ZQ`F*?o;֎1Y,rqZE]E<glYDiӋGG=?}w1i7la2CojEB"ִlV�Fs$͈vq3>A?{pggZ z|ُSC(&`?͚9͙,덊t0lZp%o}#8}||*aWn̢c kdlՠET6F!:xh3~YטYhh=Y?j<xZ3s pAQ pX| :ZRՇӳ^1|,Ƙd\3 Q.7b`Q x:b'^n;z/0&xW\vłmV+S)C<kIۚZtK H azgwjfM/0!nv܊b1;kՆh#z_{kJ &_8?8`+E;}oA0npEbqڎanqџ'x<]|.jZ;!O_ak6O[/\봛P0ð/~'Oxv7uw'd&ϯ_/qhJlqn>CtN.Ϗţ�dfR`s47[loϞ}'s"!7;v_ak \8lhnTipk5>6mLinuQn׏;<?;fl210sCz4,Z{UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\o?Z%iWc 26J.P3.VJ|UsTYVJ#Pu>cytbJ!8!L%iW򚱮7uGS>zoj~gnR&zY? ]Gmǔr18ƵMTqOPCy}7x{E q)(f&(7-?Z+)j{~Hk%Q.aw5z}EPիuR 8ft?no=P;¥eWmڮk[PҶMhP?<{xE\+8f 11~wMKVpZVY8`0 e^㸌uƸ@rNgvB;-Wt%#&.7#|RpH %7^i�q:!qAfm­ [0cNZٲ37]ԐZh×/.9eJ`ώh8U!rha˽8L Z;v yBYkW]~[t4mH 5 )Bլƴ &~:Ai&$'ꢓGsx{Jp3IJu{xv>Լ7UMEFuan<ڭ`Gu96f|朇!G1yaN՘)d $hκGukbHG}<J7MqP BqRJx;>i|s?( 4:~h99kk{ L4)8ˣ┼UJRXbmK{ it4 .Iz(h[BŚkm E'гPqnvIޝ={||oŲ gW*%i:LCG/7 (0̘S~kuiS(4FF,j Ehl6 0s5xz~fiػ=-e4uCHPuӖu0i,L҆b!f0hMF8_d;%lh+/Ǡ>kn%X({aus0Ĕnb˜p" nc]ww.!b72'0WW$Z;Mc )'c9޶ 7оw+#`wK"L;9d�[4d".9AݘR ]5bQŚKcL#/mwF`eH/bqY4rsy V vY,\a0.]B ӾZkY;evMo,ۮ85g#4U%�=k Ą)[~cH=)_9h?"wQatL4+GB^*Lu7h%y;yfw=r{W7r%6»K")/R$%nܨP8}({س$GT*ԤZ]ꇇ2UF?>K*WJI7qo07z ()V6[ѠizZ*kXFm+bR$[=o0B2e4oADCkw^�NQރ j@ۛ9)l٨VÑ8 MS˥�Hڮ-im.$)f HqR=Z@G[08j7h4SYU"u ?ԢD`d~5 ʟ$K8?cAa 3C٩'K 3 �m4N3Ci OV:*oC2P޻ }+8AD8L@7,+`iݴFT0Rd e\a*z<~w@OFcfb}a10dzJzSv έ,Vg)nF-䥄c3H.ޓ4 gƈc 闭sզcƀȤ(Ei?e <SS+K- 3#HuN{YI8+kт؁4dv5^w HS9ć:!w(ְ甝xrw7ڹsn[m0_^ctc[*k*z=[)\b=" E蹞0we،Vrk.4m;:oxan&#Tb"2Wa7,;f'klJҗW;PeyNr{ãW_8IL{.-O#Ǵœe&c E*ltjG׵"(dg.WgZ]% Wд t!0{"h5Bh?Z HW`eś%,>,1Ag:k|N0$Y"}9 UBӲ(bj.VJ^Za:gxX%q}۵=�s {p ,Ivd@q4/lIL ,dՏS{N0<I )Sv¾tw!9^-;7x~E=Eq~q=vH糫G?,VYjGjGViAWC?<k=ang$xy F§?:8[y q\y1Gxxa@=ѣ<!L~>ظ᣻9y_8fIQ4?}>yv>áUdA)՚ޝ{N>sG<|09<:{{xxǯhHײYQ2z l :E>V!4̓CKI6=E]rgb4!~ҼӼ^w Ƙk[PyT oDm{ <^8 .hDDDDDDDD7OJ~ب9ѳN\%_}~v)ާ/o~?})ǧ->_g˿~}g|:t-ӳ7_.u8g,/;7 CUٻn?:/xfeq?1VÇ. ?HC7v~|ӟn}{;_;ߊ[OŽ?ai>>}cU %vF:/"< -Y䚯,2RUU}6󬨪~86~0"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""Y>'wWgyCrZe_;߄EE9"ܒ|a|/} \J%esC9_eeU^7WZ֌6 ъ0&6Re@H$*'~?7)4$BB寮0r&WAs<{W_C4VUUVF(bXBw(?RSeMaJ,?y]eUX0\kiQ~OQ$J6o&?K܂ó43p^]#fC-XSY^Nk3\(gAeR@?܊UHz` vm*UZ6ujPH3H�X RE} vՄhI^Ci]Q_sIS(纪+B9U2܀ϵ*0eYcPZaUy}7J W1פ*!s4GeC %g.zJVXmuäi-b^UCs.´ũE#5rYW\jR\jF0uwNԭӺI]SU`9ZpVU@5%gu2EQS(F-7,)ӁM̵THCkw@[R!W e:(mΪO,QB԰KLH] m7kD!2Nm;O�>kBhbq gm*vc흳j!\ Dj,Cw!dt, 2֭]s00RJΊ }| E#/p�p>Wjy}wg;y[֧KpNCbӵaU}oza8$+ ]gCC-Rr !?>Fзnmm%[ۻX7"1AY!t;8՚GsRGkū,JX54|њd!gEho? H�5 5COtSɘ?u`/X (eEJŸyꃕ']!դxM6q*_euאΉ+hi&4 QaΚ60K"YІPn\Nr$= l`֍)UMHtE+Im2hb X9rxHÄӬq)Q<%+^ijA"禝.<* ysR..vo`)K*c䣦&qaJƂ?>:{!>MJ"ꇨ5ᦹw42 [g7H y–x#iD4 lKrŒij=B3=NMU{Cq0BUg9HCh蝠k0(܂Tp~t1QSGŁ"ks=N[TU }l,]BM?_"p[5㜩O'#ܮ6pIDQ_\"a2Et+ifC*}eaf*I#'%}ogɜA:=tC</ 9Z2D$d[3s-21ˤlMɗOzar8,ڸK s-mG¸5m뇾FnPkR|~=tꓧ74!׆1a/YzԌ#Kԏ0Vf_Ur 2} Y0(FE. ZYn\6wey kGׁKzP4ú4FDB~txk+ ʣs8 W/ a]4Yq ɴc /̈́PZ9T:(3`m5m x;=tN:WiVHḣk"Ti%NZ@OFbIpFf KJ\wx ;`&8(${׋U0[9uA`9@nQP'(bb7yt6K ̬qSԴ_ip UaR@4Ǒe[,Jb9J0dFdJBw݇/O)[9-ĐZG폃w=\H1 aghuh]~GysխGb<~l?K3$֏`NQxg"fX^F;4F*˖,4%lBFClM;{;ONVuE8Z$FRۦd]'F}PiFE֠=ҥݭ>w7w7gYؑ�s+0L`Z$>dwtz(H=:Qk֢S1rZyxٹ}ٳWʦjfF~:d!䚶 ,+mnʲJlɲ"oގa!);85yrejTwOز(@sυ=?FiZ:I 1Ncs4LNFuu}s<UG|E"$J1OnY9Ly=3˜Rk xѰ6w ݾjA}>|\O'zR5:?.2NE!.r#$2o`Dz:[T%Dk̹q|b{#QWd u)ƹƳb2 ɈG*ӣ+:=9鶻DlDuAt!T쇱.ew.A,rSUTf织u8?D \]`B^l1##:ЮfY6/.-kw۲:B JfTcq8;GmY2{$M`N,ksPJ9yYxfY[k;;[{<sRvoZGbY|bR5\򻵍յݛ ;flZ͋&Z3i,@O!2πf eոD+)wI�#[HwUVo6WVFG#hc})QuKSC'&jz~`dZq^gs!Q&i/c~4{ hg 5jԨQ!\r{Vw8ße-vzo=iy־[ˋc`k=&wK[;|y~{trx:-Ǜ;iOKW6VqvoY武+<-|zwj=k:~mjy<~&fSsV-k<ow:mo=F_BMd1ς󍳛F7h_4N[ ÀnO@/MH5�t_<}v|y槍3>no8U/hpt?tN1d8vOۦn{O{!W?{췯o_.}<z_[ /,<Czo_>yܸ9?:w[G˯_-ׇa[``;Ozqy}ݞg~~r߿_|Spy7vNnZsm~x||aiyiiϾGCl}qe{yZ=h4'dٳoV>{v︱g1͖+K Z|nZc㇧K~~sW* [K;«Mu=—01blwBO.NY߯=!=kR#֏ w/wM}py)NϽow/-__ LQG<斵zsi[;(MHq* `Z8o*#T$>Mkqvէ4G{5 DJץ22&s|$#=`dMh0ֳa.kԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQFٶؿzT?َٰҟiyfze NIow{ko_ɗb<$s Kq㶩TBH!8cw7_:֡Op"$ht|.R)% .Pd3TYFϭKTJ2BR۾V<:`&TTQUb8WDIď.L"黎PB)c`j㏺#$}*8K8X*>¯w)2s/cJ>Qe߸u@Є0k%%Ƃ}ۇ`I|S`SqEUICl]{dDI24L8%Xv_&.aT V70fCA恝[ؘ A�\bI Ddi%'ETFirЅ&u8i'8FեGiARw(8%om9ݐ; ':se9 $: T:(S=ƉBS9ZwG.:xݷul'L1D2u}WI]hOJeGBP?dA)z C ɻOiێg6AS*cCefY&Ƌa,s@n(1lN(V`%pAA{kv;h,P*N:&9#pI)O%UC.7lgp =8 8MNzs~(Qi=4IBr9x&Ӑ1%f,=5܂YEclL0w}աus0Ju&p<<Sta!]<(CG #x$ y+? EHzIC|';I\m"L82f\LQ)*? ȱ2qUDUJZ͌FG0mRrDGH<Gk0I308.OVӏnf�j `Md2aӏ UgKj/ ڣl1ҢX) 2Lh9>6 qGQ<R]N*\l^8_J#A?SVsL5&APYQa9 E Ӗ}30tQ0"CEzu!qdTmFQ\, !0HBT""KSMa |<n Bp4tRJ ("C *l.+c Uq1Wdh5p!GTgn@:4[V08\!<+sr?zc+fgH(BSjl�֧1[jrc<;GXåJzXB ΎSR=I xQLS Z�5QR f]i6|vJ%(>lX<2V+(I2ULI9&yug'>|vP- (p)؉ ""�4V$+REd)gQ7*.xTShF!t2LDq& aEDOAhV1NC=[&"y&$ NQE!bUNJUUU,3-bxhjZBOȫ*!n81kh5W,1s : ]EUD'f6+~$q\~HUgYQV9f#>F@إ$ 5uq7N`OTkՋ~z<Z<P/ELLdALlso`}6̇LcY%'{eJ3${:Ia3eQ.QzZ4!.ðhB.hE`(Ml_C)a&9',23!5'ԭ"ԉ� ƿ ,"411*s7dvA<Ilb$*QadaBe:.ݘιlčjc܎):aba12Gh^%GK3="IFC JؔcU c7F+ t1;%tϐpacf{#;OSz 9gQlx#Y=rZ|wr02La@q>HiT\,c7\mChThpy5Q9Aiapˆ~Z\;8He>Y#0+$bH3߆)mP�p$eDˋI$g$@uWŷk[;.ڶpDR-),a0Tfx<OFþg0>14aDУqb/llZo߭nlo4z^$Ԥ6i|2f9~ >$ „cM+d!ZGkkk[[La^!#?0]D4�O) (pZa10ㅒ֭ŷ7ic$ 1ZLgEɴ '֧i.=_cA.ȋ,00mƖZ]]:1wк깮볈 }_\7{WFe`  @ B+hRYY[^%2'`;$zQ'l*T[Rf@ (ʒah1B#du%vU[($0..;CAV+(^ v98LҕDo BO\A`ԜC}Е ]: p0KdMQnn}mVzWYB$mEW//aWVy`랧7ITc\muZZXi%^!:jݨFk(@b *9C,2uy|TmZ"H+Ii'Yp`EXVii_uKBhV@|1yP>/EN:M8kp|pX:=5N䨦R@t0u..j^v|\8 Z %4~,||xRmT+bʌVr:VgRhHI/iճΧ?n}.~>'H9k>YO3D0)1MiF߀ 7I4M)n90@9|y>riJ�!M:PV" ߄;}f̧`4l4o؉B_/h,SR U-X:$ˡ򣌴dZdT(/`Gл5ǦOl+39r $+YܵjLF/r+'gVR:9 ҪטxEQvFャZYR</%j[?=*-A)P.3nٿR;U+I7*fxz|T<hTNys84鱓\*<Ǎk_mTfO1EZjvwpR:;;.7N*vq)bWzv ^\_x_vKau4xjzl.Gq\8|W1k/V0w7׷h0$U౅S@;V"[λ%PVUE [c eܨTĉ,==|S]~|uia8ig#^ SF'KEоxqxwig0ULO[COzx|v}c_xsv9DK<Q9,M/^+jfo7ro>>mm}]lFOT;e2֊76?UF H5~)?=(ASk$PRU9.UJ׻WG|Y}PnWUx׍UR}" ?h\!чXN?'ֈ׿Nt( ՝bGTsWͽכgc2 U} GW@C CW5 cutIwGKV¼VsԲ)Weŕx|fYݲ7"j!1 62+u>۞Plޭ]6q_M4B ˱f:5 j}|mKcocsԸwhK^$el^] _,~/mE1l/ÐʷDy /_}<lvG}WD=y:oxssk1Xl\0&˹6u͵AEd͝|~ 4R ҵmHOuޗrߜzwPsw|$/!<?:'IE9~ir9G9rȑ#G9rȑ#G9rȑ#G9rȑ#G9rȑ#G9rȑ#G9rȑ#G9rȑ#G9rȑ#G9rȑ#G9r?PꗇBa( uCQzҝQjIUMt]7-4M/x <2*j Ϊ¿t\ǶE|65u cЫ=fhNtp5Lkͼ ՞pEݠԠ1-W+מkPu0m˴LjkF4v@cY2׶wy짟W7e]wẕ(f v0 =Iv.w@RL=Du*߽~//,:i-CX!2s]*@c0[} d,xZ{̶S+ #jyfgGOG۱�{Ev߿}paK$Rpnax&#}j+}? ѢHA |O\ fbۤDM߸xQD 8gmT6C>p̵R2JT"`|i˂(9&=81o+c"ac< `,.]jHA,C|,瀱v0IݲBB^bn-|3@d w>W\lENL;JBa \ k4m` !MUQBŐQ0<vꢪJ`a$|"h4R!(r%QmcUôxc6SX JjM}|Hz>emI麾G>o!K(+iP; Am-A/SdHĀ US;wXfR>/nHY{/~hf.+||!c D pP�b"wƒWCIY?ȆHMr`O&|קCi <.`yNG#,$--!nt'$1S#,@^^l%J8wOmh̓DPP%]KX&YBCy2/{EW-$a aN< |ж!1Hs~?]]#:e%&P cÉMxBҗkD45 3⺅\?nCD�ý ^?T5c 1 γ̀*) J i.A.B8 <;<QY/Q垨8Q!YĴ^2ߡu, /id(<4�~p-^ GUr*M6Cg8ւXt:#Bp>eY/ꙺ(iEXh6i)\)w$ ƪ =aդC)4Nlj[,O#d;D0quep|tC(1?`**j8Fuѫ4P5S)nB gӌ8- f+Yx` ٳ iM#0Z톑Cf*>#`\aHiOfX6t=F;: uƨ. vogp P0I bl0u1<J@Vz2<,\bf<ӝZp:On( q: GKhT4$7StC*pndq'(3!+T*^M `aa&m^z353(.jW怋0L3D\?M1"~R*aI$Go"on.׏g3^)<(uuvEЏibu!EXgFNܐ CMۂLAϋ&tMÍo�N;$eGt~IGf"|=utyRU*:zt>z}'`~v8iȒ ,RL):Y e,IBg:s)72/ƙve")*\5믉k~v9a6Ma2yt?!w; Tl6}Xy xGHgq!:N*kaQv=ëBd DN 0N5=U5DhDwЃftzo%sb ,3M,zpPUw0p0Inz9n'FcbΗG`ܩaTepһ;F@ \gH LxQ4VbW#@4^ M='sA<륷7^(,Y46IZA'NaiL6r31?h,߳,pĿjs2&4kAd<Om7KQ|='["gDq %)|/q�e Kv[Ayd:J k@5)xo wWngE>ERN( ήThێglzX Q}hY^8`W9\>8뭡s<< Pٿ"+(jD׉�."bđ4 "ݠZmb>Fܦdn œjWP))"j_ϮC@>Mo-3* do !!$Į})վWe${icݺu2+ugUZ".tH% 6T [CfgAR;' -l8"I@d9}Y1_&\:A1'iC8 ~kڨOVkҌ,fms+~e&A|iˌ HHS4fZ:/v Ɋ_1;uV'm'Dp4%[Jl3 %(<N0!x 4a=ֺ`0T]:GބT?5$wT7Y˂eBu35<619[W^sy~qQ!PXVVt8p1폆ۣ.ƊnA$Ü0].?(Cfj9b{:H"[Juqqvb$4I<KhՏ"zK:+Ϯdz3Wǽf+6t-Eu2ljǗխR"CqgYLu~>oxYӦ絎ڸ;Pp&Yq,xp:5%F'y"\Hg+W_wMVȴ?6V_H瘽NGZ#QH4 8=I#[[{盛a>;~Ou ?GN"ˮ#Ȳ 4c}21o^~S9=5 3h08g "Ec(a6\ WP7Ar,Ex_hK)ᥔ;hJ6{0rԖ, ƎQJΊ"O0RW,l4'%E>0zsE1/~c.HWQ~=ιu0CJ#E)K$%iVfź?~*&y1 +I+BiotS]ƥBfzWwov+w.?}=͐Uo(\Ӿ8?=㚧Yur=lT^=NuL?~ߟ7{)ۻOڻyR9<g\4jFݬl9h\Eqc4K'hԻ{ը:jvϸcrPU'G<nv^;yj3VgZR^Tnk/w6: h̉OysϸJ9Fh]YA<|lc=VA%PDA_4M9>g:찁:qu]uw{͋/6*GO/XQmKٝJ0S+R0%~SӿOh\V?x{>$IQDQUE=% n2:d~]=?;ikXf^&^w,MO;BELjurv==+x[9߭5m>~O&, q>$;>yrvT@hkvF}͛hl4C'nd4aYU[ËAZk^<?. AV5zSHkO &vux,(k s_g퓓*NyUV` &}ZV AG Mu9oW<~_rtch {IlC7tG~2gU:/ ΪK#IƟ-qZ(ʖӹ1i?ӠY>=ó͍á*|_i Z( tEB_74;kW>S$INEc.Ȃ0. $Hp8u^l=yY9A?TeMtl&tM$eE/vO;1Pu&. ױVOуlдU|Z ݿkY!pcyW>!^!kO܅z z曧*0AAvU. 6Ҫ! 6~l$DNXtVZxhHTeFzUۦt?\w}ثwG?6гi$E3l iqJ=dž9>e_JVJd�{M 㗘X̰%J(QD%J(QD%J(QD%J(QD%J(QD%J(QD%J(QD%J(QD%J(QD%J(QD%VSf<E$Mv2}F뺦帶fن$k1DX Xi:iSv,pw)2?eYUaNOwy7-۱uiOrs$+CtMt2ˆTՄu2ir05=Jjmq]~jC>^ bq\?p5@p }/ 4,CAkNlu^ϷMǓюGj"SaٰԿH_=O7"6[^8 WHRu-=8MAWq,MB0[6}? q('GVR F�\n @79Ovo|1TWdնmĦOGDI@Utqf mNa�Oセ1B7*/>J4U15D3ݎ3:I"K3Tue-w;"p!%=㓷_ :;p|Qň ‹5mUUn/MǏh4 /\\k5Z'_h<Ayc> �gK0AuS0p+ 3<Dp|hQpXĴ </ݮaۆmpdoD Z!,7&H EB}/c+bB-?HE0A$DL.#-Jv;zʲ(]Y&KO7{4 YjnHC�%1ġgD4mݤ\C-J8NU @LTA\譗/?or|EjP8&a!X,#ǫ ǥJi4d|(-/TwUw[?]o ]Ed;tKV ɋY&`)/ܲSQ0At5J�)H#a/& I,gjoׯ><;mӲ I,rl/N#$77Y*sAZ:vAp Q�.FaKP>źnQv \Ih?y٪&"'(rSQҍc*ljφBB"p:Iam]xz{=S/XYQq),dG,2 "jKށ cGN iE>*"eFo*é(t' ,GaQf*/AX>j7 ]Z-7iuTb?i*fw]x yN9N!H!/˒$IiJ()r&g6NlF=KDX UY,M\LcoV  SNDt>6jxϨ^̳tQ$aNH6 SBPSlM$mDE5T!4siyrtC<\CEn2)T ~]p\%Q6˳�Ti@E.0CT,TrQ5xzBd䜂n"h}ß !I>0Z0!>A'3k7yD�t^%ATD꒨Ww( W + kgEB4U`7p@44bt,TO$~J怰]L22]NEU8Cmߋp!(n?G8a(h8diqDA:-5vjH"@{r0r,"0CM0AZD6 pXᆡt2/NIƹYy`R(m/mvDY %u)jGb8(xqy;ns<OeRAwqHbr/*ReQ?{TA> &D2WɊȚΐgv!|E0H}=.WgT8͋8 `h:_!!Q1 P4Tfx6"Dž$ao>,r˽*QQfy;<qmP dQɝa5Ǵ8宣1f$r!㟷7bFo[T\ޭTݸ `h?//EugAoiMTUYi9B$?~X0/B/ϊ< ~<bҌ6h4+2 ߇ ;d%ޕ6m,[|S'7زd+/\@b_}%�dKԳr\S(>}z0`c�.Kb&Z#$p .||{{SW$h<B( nO =b.Ma#:P}DM:QXXO*pydQ֊D+)"+oǣD <v5IQ̳#' |G#؇RW,D$CǼ Yun`,dKFF,߼krȭA] &˪=QcFر ˏiߋ 4œգ,-2_[ٿoVz<d͸~s]HA'׎cf6$tAn6Y:PsV-Xm)ny#"->KrQ5yfTOn'<\e@lק5�!b:Et8I϶LU:^ZNחMT,.ۛAxƷ<nȌƋ@sH\K!&?aoď Ԋa66$A[[;^kպ3*jr}{{;)r7 N z8� ]10]UQjO4 ,Y[fw%Z^ixH6?L8CMB U 9[hy,/)+D4]fUj0zyy .Ѻ(+Woehȩ(ln~ &tvŦʃ(Ή"J[[;84qy.*RoW~O+(" P7zg@5{f~eݝaڠ'fhtArB+bGʘ)//[Gg_+RVjĖHf˷ή..NOz:#DzLtıҵ O!?!;߆9;F!S*i&սsI4 *8_=*flOB!UYֶZH׸̳4y^"ǏU9 W/-o i( Z;"Qz/6՞nEvO<"w9D`jQ++j;ҳ/6NWڂ싋^#(mca^nߞ>{~pٓ~sB}v{I`Xk,0|WV_6g2q-e+Щ ug#d׭D _ڜOh.M liYqMrZu].U=Ev< 7'5[UUד+@o%zTLbÈhYh|]_j Z CJM"Q5FF"g?Z\ӈeYVy58$Yc;(/Οҳ/6xkC2w}%/|0?<^mN8ngSԝt5U.qrܷ|R d/=}| +eJ;KK{{k;>hgeh}O<Y;9>=DU$Q/Z{{+>`ccʫO~ybyo'|?zSUCTykmn|ߟ<'Do?<|U "H:;9;;<q6Z;۫KKG~44R;ҿ<>93N:;/[=Q9t,]Ute0w|lkm;'Ͼӥ/JYD ή.{W{O'/76۲n>p|5Jwz]ݍgO^lnU^TVgS:??^~%iҠ/(a(6=QT]<9<[ۭ󫳝}0mBjYgmٶART]k]FBYp|x i| m"-c食/ z}EuwQe$ľK0}Y5K,۱ޡ1S/;"H8皺i 4>ѹs^Vxl8U.Sss٢Eաe]N!wgJuu-.gK=G' 7 v+%l%$L$qmpblÂՀ=ML|y�NrjeEhs\ˋFFz&ۭj~U.e15UQb5,iٮ燡h*(t |7"<tL,vH]�vt>.ZlbĺnBM6uY6>mAop+Äf:总>䏀P +moGyUO"χeVx#GHs@JƧ#(~Vx4U%It׀1n�UOۛ&'a{,hTf}5�}.�O^{"Ӡnٝ IGa">g@-m?4G ٍkw!Fuh|*yBgwh:E;DA*,%EJ�R k4Oru 4hРA 4hРA 4hРA 4hРA 4hРA 4hРA 4hРA 4hРA 4hРA 4hРAj""ɪu|8Kbmӧ R̆ Pױ0^glwY}Y3, g6q!'(K "뉳} _/ϓ5ER Mw<2ԥrËɊfZi* wy1 ?#4>|jSfu؆iϣ&Xtq+~K8Iu1) $l}-ؚjP/(0`X}\3:�o'H"cImvojql:~Qϵm Z3u>g# bwHt$u+$Ib:ԟ}; qq7yЃga'|e{~'q"4ٴ:@4i )f MGt" �ycYی`7M!=*aZwmli Dr8`0`t۲meÕꖁLagqaGiQ] E_Ԑ",KY̜ E1iM}QcΌ\Y0K8p-T٢ \jBX(& 70g?PߘMYC|QE ,C@:AI, *iƱd念MfAx8VWեqqt ʲ-bX E|0.˦Y7Qmjx3%L<AI6,* <;:ʹ,bƈӘ.>@&"#Lb覩hKMns܋w;:tiHaI;9:bÍ]kV|DleZı چf9#Van~؞"Ƴ#\ToRߠcsm瘚EPASxA bҞ :ms ~P0E</b{5%4pm1, Ø% r7Sd!+%]w+yx(iC>D`;AׯoFMfw4B13EG,2Sy#*H h}smGde7'iQr{S\8qϳ <8y`Gq}WD$Qj]otWtXl%χ1%^ZV$C{4IsGDd2Aa`t8L, 6u6 a6W \FW骜esQדIJaCHŇ.Ӓnaw\߇eM ] Ƌ-iڽbJh281I5^3)� k":!JB62㙈OᵄUCC-vMcp|t{EtLU DRd͛QDHtRok;h89D$q1WY{4ʺd!譡�µ{츎~;T$f:y}SQ/`.d+[xPF a06&"I=M&]BhB6kr$˾-r]�ұ)NYσD97]7 bJY!! +Q`36mXz}i Ow:AYrrs;)GxAl7WQ|]ʳ JYb"AtD 㤚87Q:Obu4"!"W 'a$pӔWY@`Ðͱ f4oA41 2|t=*8?߼~=ʊzRku6q%Y SI"L��$(O4ݵU5@QUs\B* sn;$E=ܠ.'~ȮCLat\CQb{A>*c"gx?9s,oŤ8rô,+bL>h<jK1ZEf  7?3Sߋ02S#$'Y57s0nI:+ꋋ鸞WW@z]Ӄk$[xjQz =n?2 ,0ɸ< W0 t]U!d2d~'b>/E=(B q=D ÚA@ԀP+˼LJ4zR-~ॣI=JÈJAW7Q=4+gW|/%r8/AO{rlf|$G9.b:9A:ߍ('Za8l L'(- <| ?_..gUUO&E`p ] C]RD\I"Ifa0A?HH#HTxxxhbrz:NuUgwx FxeTqh y]^\ (Tc|QDe'^ۡ:7.W]t\UlfDHGTAyдBo%I><g طMfgSo(GX\~g3FOȗ*/ D f4Z(-<r,/(j8*TU6 M~6u)OŁ8ŴēSOWDɺV�î,ԅ5hcq5Q5r \v]om2^!:u=ȫjA㊌8O C%KCA1i>G QcXua3x-"&@xup<>m:^<x'Gy=ʢ2,p/f^q:WZ\L`C�f*ó/vg{;'t5 OǓɌ|1))IBkiQO0MM0L]U@R¤D 2" ILYVUtsumcssǪzűJs|2T`,* Ub[a%ɠ</2G cE E#旇mwyf9|t<I#aC+, %ƍ?AtR˪n<.NK*lM[ӃV7q_Vw<}|:4m&+3ͥ GQw"heq |XōV"iFKTvOAjDXDPN47P;yk2gDMZY<E-y1+C_:/3ZbȨeQxvﴻ9΋2ϒ1x**S4ӣv6r) e;NP/Kp6Þ h ;T%E74Uh<\D6EeEUfQyku6Al=U,Vk?a".W' *x-a_QY#G#4ڲ T?]L[*nkhdaKIR2:q?3̩t{rc+/O!}�TL Smlnoyd3]Č$wf'k{O]ӆǻۛ;9<չ;<k3syl5]>^a;gO<Z[{̲k󬪊,ϔ 0?uםYDQK"6`(="_r[x? 9$_!"qbӲ48!+c[nA^SvUƩuC$|:.hTE5a](MD0~*Ԩ'zbtݨ,r<1&?U)Q9<>T˄R.|<"RWeq XbbGyJFjSuh4)8۔?g>>+s_}ý~| wh9嗟ݾgkۻ|1+@8#|{pΗw79%.Y%`kƹnؖI8 ?͗y]bo/_p;CY4 GG'.{9<yݝOvOG0_~}ޏﶺzu)' o~\{]}#n9~mA6Eлg ٳ駇?~<8wX4of<Î@r^qy wyt|8h<UtӴV a=da#!$Ey5Zt哟8wuiJW5q*rE74ڑeH$;gdV s3Z6qWC\ZbwEa!K*N޴ޱAw_wiJ/,[s酾g/OUo>rlC p^DhlkųBKli_/{OBow%Mz�W"rlw $ ݱi�G*JSOBK= UU$὏$!QO5˂{mK貆&*o"mEUU*UF9; 1*5-S7 :\W5]{H9m#7tM^0*<2Qn +E%סz8AفgA|viYaZnŸp\BP p-"}26-xƣ:ZRŞmbӒULM{5U0]tl/ʪt>u='k{[N3i~jDV^z69&2svUK?0TX^4˫2OB,2`ٴ va;uMm¼yIE*j먃"8;!Tee˹o ,M:eޡ—߀P~c=up@*F:-7y߄J0VU|m&!|G'7~\�àq~B`eMez^L2ⵤ{=?c 4hРA 4hРA 4hРA 4hРA 4hРA 4hРA 4hРA 4hРA 4hРA 4hŀ8{Cפnݰ òl]׶ 7H[\ul3_{rgϯ/dqfm꺪iX |?w:=|^坯޴Zmuk8>ujЬty, p@f?9YAڥĝa{>+J$J))(ko|WItw,;tP=u0,r}&-ʺ) xadoͣ`m{G1u'3cI6K@5öD8!-0̛CD||?&;�* s9?j횯w` å/yaqRs LB:P�7]wVdU$`e{^zEYl:ۡNG黖!ZNgYaȢKvxafus23[e>8$/FW#={e QQXpC1 FicNΦ]s qhԋ4K(" p ngE#(˼&)?Df'߅n/ jXD'Փ"$nA')Q/�d11 ]%M@35v) \wW s/3"ўaeWLojD)QtVe 14tVaP]haGQcixf6Qȡ 7vˎ ^~BY5x28 4Wp귪\&ID:Y`,Ơk׮:<h.)5i5\\̀ )\j!m2'<6~'!Q: q֐ 0lCUxNNv4E5|VY8a^ճbWgYoCpɽE$jIT 9ɫ2&##{ζKk`g=Ɩq&e=ίI" qW;5ڵ}CE7<l"͂7Ŷ`"8 %�/b2*ʴ((K(Z31t^,<! $1L~^wL k;VFge4^L餮"O0 8Z*?\# !O̓a4"{dѰ׿V]\x0G&yYeDaRNg3jM$yy,S') FdtQVE W#P;E!G!=A<,::gY7 (QF{i$%n'MloȺƱ8jUR%bAo$:T?ghovk'rB-2!^{Ϲ)(pi>�yȫ(4!њC_?huPPkd؆)G)( x4 \a5"$ Ke=P% xw;)=Nl<נUy=9n7Ze4z'^ nQ.(,P#cBsNBv@uc|g!qR%AͧB}qwA?zC2F̑EVN&s<&#!Ve4&TbA6EDye1-,u,vZ=kW ғUH`O(tf9γb~ƴ4�-cp&6tbQˍIAz!=7+<lT Ѥ~I4?4ilq)9CD(VPQ{iۇr "qQP:GC9R)Bu!c2 "/1;N"Z$< Q1tgk_=7WdD.-cطiؠg/ʒg:pr$cǡp�q1gx|qs{s;G 29\@#eYтIa=.h{L"BgQ.Ua)2ѝHQa96hIx{s=ogPg ȣmhY%I떎L )C*FwR�^dr ɨ b,E:޸X,b[bc}1LQ_(qRNK2MtgT(sV%t8~1Tq|&JqXx\ @nZ$ hlN9hxT!{ptYRh ujVCeY^Lonn7śj j2`Szx4Ŭ(z9$fAAaN (pUHzC&t,߷CJݓYOg󛛛;XfY\VeATHXފ␁#+(.TAdfI^Nh6S*lc6z"Q Uk81~C8N(50VFbYH 0zdYDpAiM>)6'N-S:']p(EtR뻻55/A8N-O !G#%z!,A,h8Ƴd2ɩNtj.R4Ig׷"o oV'c$08A7(Vd3xBu'~Xq%t^@OEQGlI(Ko^;|%0VGʌVAGW!ґ?iK7|FuNs53˝Z'! ҩo`7\V6Ph iƴM?p%G@.֛ZLB:d;MV<<<mnb#:B-<^{(fFL |RBazG QAk:OtEc쬍rlzՂ @ÂoI\NQ0,(!Wh4c@uX΋1m М{ٖ;zMz7m: lH�Ǩ&QhHp y*FPI㽉GEd-E��J('[/6?m^^EqzS:r(: u!8sx8mVXNlϿ<{:AU]\&2!OLD\߷$(Nc*Rx-Z١N?8 {'-NDJl˶QhJvcpS:r; R|W<uP:3U^C=�DչY_T#Qj}mlCyf mvB_ ޻0 ء@<VJwM,gy'ypv)M#(FD!8>hY-,MZ.[p ċe7w/9<hPTvGI/=qGQ0<ެo`T]:Xً=TL9ZSdȰ r(cN8/x1 M$}sX)B=[r~J]aj͋Kn1ƴCֹ!#-X0 w~&[r{gG-%NBGqE#gЪ%j6JoӐ:ͭR=ؖ]w_|u,9#xAy;kpߏ!+TyQfwww5N8TONW,n 'avav^hqh^//;.'|wU\™Qr)mG+nObF^7Fӳ?a#. dg rL4ь8r= /YeeBeN-Q㏃ee9-$PtR?՜?5/(bYEgy9kW(h#M%#E1ɾSM=jooYRsDYw)<^_alV-9GkUX"Y#e� D4Kf%})Mu L,o!\b؍kE늠4p s/0 B| O0πxs{qWo<xz$Pp�=鋝>d K]ჯ|m<󳡢_G_}ɏl5ڧ?opлj5G szk6_:`6~x?mllCϷvvۂH_BD`wzVvv`F~:x fӯ>~'icsq~Q;k+Nq߭6|H:f{ݣo<:{ziAnt?TM:*g S5Z״W;1o٫ZUUa-pm][B+D.5B׿2?h0yqvgLho5/2.Yՠ'novvйb / 9A4: ×۝Il|}ܼfD:mE""&<4ٗެtLM"mu=.fwgIF }ԇCWYttne0.]@S+bك?z}Z۫9:MM]I3FqgM@w?;t cZnC.`%mxu7P!؞.K ?B2ߖd}!1 uxA^/ud듫Htbi}v2C450~7=}q4@..DUe7H8`vwO<RѽtdnZN<$tYo֣r~1TMwUҵZ"r4LiTrK rfZ!^ͪB?ʦoӃķEdBEA&r TAWSVe8LYzV]z`*"O6ؖ.J2Z xEt>>f褡ZBЈ*/Xhۖku/q,v8]9ȥm]{]W2h.w%l{.HFY> ǣ�Na:ġ ̵4{9jFsx٧kA5T5~0UN 07݅] J畂lЕ#B4)2vh +x\Sk^.Cڐr/ fTŎymꊰrMG9IߩT]XFk-iu~XTAy 2| =di}tI/4Gt�]%Z}:틾EB  2ll&h9aZ1lx b5 tjXt/߀smiTB *TPB *TPB *TPB *TPB *TPB *TPB *TPB *TPB *TPB ^x}ǿ熲eDWowToA%Fվ︶E/ѽzƤtgħVRdM#DSE[l[x?'ҝ"0~/4M4E༤w?p\6O5EdQxq(( +`O}j!lC#M<˵ w膛;i0h<ϲ</xA{Y}}UtXo2{ِܦ#I65SQ5UC^T *I_Ga:2F~mp?kw^GKٺ"-%Y0Tzt1GNMŮ /( \D$b]sc# BtE7e-CӉiiP#NwywѮd<nv=w׺ɩ++D'QXX6u`α 4`G>^쏢(Sz@8 <i8k$A_XX&x2t;ٻ䊿 .k{wϮdI( Ft{o�C%yco+ )': $>b̝;_0ac�b>'GzG,gUdLYQ@x[ 7vɥ'{Mۋ,{^u5O4N"rXEE6m=jVq�mD^ 6uk^s2˪$żȨ[,lw�IQpFȊ�kQ~'0kчAGЄ@*>r1$َ1(t; @>�Ti-jB=!eָ.ja5i9�eY,fvpcxb)e�rD} *jv<0p.teq\oUUEZ&OY@1'pyUf8 M Pu\w0O[?bEYmV %IԼ>ojDA>t+9#I׋4a_eTn[Cz>$MպJߜD`p0vVO,+r^QuE>4h[f31:L5hsaMܩHn\%"yFN~Џ+S OҜq/@\5[QZEb4mV4 U{C7VǠ6L"tD"(DzA[ZNgIT(jd3\rj銡ah<%|?nC2!!󲚧jUw F Qϙf< Բ}P"B(ܨ{#X zDfWT'vXg,v=_TvL#s8>h6!dD`׬Po ,qLĺ(DY( o$ra6=w2c`0qr8ѐUs`FBˠvL F]" L9yN[vqyEJjmV�A ZA7ߏe'޴t/I2>DR3) ' 'C`nZSvNfinغh߷(wp{r }|xȦsdQ Ms"r_ږeJ;uWeyS$bōfp d"Gtv̄2OE|ZC> rZFc^wnEf8zCES YܓB![P!aZIdp۟Fi^2Gf<"eq`SW9m9HΆ"Dn#6k/ʲ(K85@`_n9jZ˽w{ƎFx0TW@M]y8TbH =OS lzM*l<8fKMUVfx_cd518l<f#D�%)5d(&u#̊.i T-@o>�tQkȒ,R AيtIzY/ 2T)6'J(K 5,<4wBxno6%A\qZo@p4MfSpެyIA^ tQ0ԓb@VPn i`k a{[n aRڇތe p DZAf*SҨ)H7\dfB}-,'P{"(A}u1Bd43;!0Q N]BZ "vLM3st[xn!=dCiiFL&5ꃕ NG ǙTf(-Hk%'ŠjQ.,t->tJzCy8fMb@h.0 C%re~6f,s-p@ 7l6ժE .%Y;vM&wEL$IQA!4jY̔v@hDF7H1 'ͩ D  k_'. xI1 NP."kX7�0 @:/Ax:Yꢃ݆FB'9o"4@' Q[JɊepEY{垌M~ Wq8~x\9RRtRE[﷿R6 tT%]%Yl2PNxd1_"WYhu:B0WYGhZڃnuCpN#yV;p&Can #EɒrMm䩈ܲ(f OΛ7닫GK>LPp~x7taakHkՇʇT@nZ L\.XR[1hr==*z³x Co6G@m<4Pr0̍"ſ<d~̡B+ӫW/O.|vrхTz%R͸VLN7RDA[4_u@ \FDqB`޾wWwG,K/p~ŋ~xEdu�b=jG>*<Ρ~'y8V} ] qxꌧ -(ktw<}r4Ċ$~r pͪX"u;j" 5y�ر\T) |G݈Uh(==yE+v<J>VE^%"#tlMhHib]<duV(Hd95BYFDvALF+rexg35m1BH: $J&S$OqcҴ(2VOi:s=uQ(sJP$8 {׀la8g,t ҇ 9i*vӺPd4ГMan"{>-23gː^f \�J4!4ϨNI|Lq|}E/ae]C6'Wp$H<x̉g1MъAD)!)݄flمR1$BR ȲhȺuHDS8;&~jJunOuWdﵺ*(( g/\dN[wLcȶjmݝ'4|, a~w SofUs7_DV }I:IfÐovyE cV 5G#fT/rPjICb P<eQX!<@zIOXo^EB3aX|F:fh.ݮH'RLBkEBzRmf,ִXZR>ϳb\T?FfaW X. ZVZk?xM Ls4:j*t[G+ s-\dYV \L<fK>Xa?`hw�t\[6jy>i9 P(zA%dcOWT^DyEӍBRP{41m$'B]`o^DfݰU�40"9Γ OWN׭PՒ:t7cNxu-ws?ӿ5wۗ^|Rӟ/zٓ|g}7_}_goN_^Y>Ij(Uk45_}qqv?_}goafT 9I4F]32ɫ7\]ykNtx<g>5*i+㘪0uG"3'/A|<{q:?⛿}; *sfCTGao7}y@-MSѧ#=Es_^_܎Q1hH4ӕ#Ȫit`6eVdn6?Z=vn4^_i4;WϾǗDUPTa4U8U۞ڭyͲM]憍NϩI;ĀZ=4Lx h4^^^5o^i{xCAҦWWcvrX565xuҚJtiVPMSwtvryIRM1,y2V5m}zy~7s<3h4U{"tLauDY5<\Fa&UXRaAO9E 07W7cQӧQ`~ǏzN_ߎXćI Aux`DYyhaIʲ~xpk^!T|/c1>o&Ht<,?~3u0šcӶXK68qHRPsCT+62=z0`С%ZFT?" <ofN\?<lW$ha7QјXftҲ7Bz~o 0M'Y+Zn(G0ƘgxHz#/9uae N*{WjIEx=EíDpud[BarNզ,3: , \pE]{7@2;~%('iv{?L(i /{yhvD**nvn8* ͨO3]e@XvH쎴 /68 O|߶>;l -8*AL۶=1Mgː9�\]y;`%<}1l:Dҳ,*0ȁ�6L9�N(%[�@�ӧmS"Ѝ+) ]ɒĐ*8>:9;}wi? ^w;& ?db)x~lUgcJƒNoԳ |"* SǣTNXU5Y ^Tup%""Fr6ܭoHNh::æOm�MTW:\vt[~cSqJ U]AIf]\d'? 2:Cd"E1{bzmPu=|z}>aPm?#+ٜ 66 üG>SF{ѣG=zѣG=zѣG=zѣG=zѣG=zѣG=zѣG=zѣG=zѣG=z [㘺&)miҧ0l0bطǩ>_%<u<{Ss]Gqtt"_ ۖiqx?8ُ7 ؞gȍU$</KGQHcyk`ؾK'ڀchc gYW5]$QDA=8اA p$;<pX"D)t ӱ g.y_{jiBh�: iNlލ wskA>Uײr΍w]a$4؎8BBݠq}24MQeHLc Ul{X4θu{ "/8߆w&u XXihYtL"׆.2g^jh^\/oXde5iʼ,JAxVK&Ȃ( FnaqV5LUǁG.֡3}ρzҶȓ<yq@fh4Q (wT#ϳoMWMfJ<x,BeUM)<hr&!Y1lFrJ^Apm\u4з\F) ߄sCn$Ҭ̲<Avxm>X>848qnm40'Mqi2imUBjN]guӅ_#|s{Y -�ow]tҽAz㿨h瓆 5\Qb|Ȓ4.*a! ?IQY&5;cV1U ,'E3I$Y1Pu:zKUM36^͹B-sk_5ƴCDq3O),NSƩ;9 ix <!-$ \Fؚ& lz`x|;eT`<T;%o.9^Aֺl dSy7Btv4ʍ aX5sPHn @f*s8,'L/BThEIe(eM#vSPٖ*Kept:fUN@14Lsp{(+ BIc9k<CՎtY%с&$+,$WSVV ðTQTMKUIPO ySgIh[p?2NcŵFc%w8.$z} b:4Q]ef,نeECt4d:5"<|MP޺ȲNNA P_&teن*Xp`Ev~\i4yWܐDsu9E`U%b(v6ET!;)bp ZÅ.cֱ!X1VEU:ͱ HAZcyx6LTu3'5:Z( LeyA<krZ-&!(4}"W[mvGGԍg] ̗%/tbB@Z7R;quuyzsu9Y'`(,H\]۬n9nt4 @Hc&3#I1;]CL`d0Ur!DShSɲhkdjv|~vxxx4b֬lҀrrBj:±{v&-0Thhx:ofK͛y[a=5M[#Q*s~资 tR:E,GV`Nw%e[`E̖!Z]_'Ț&%*;<;??: )'ji4:/r=YuRFq\Y,WeĞ�d\+xnx18=lARprqM mT%yFm#関* Z~l(HjFљ͗Y xhdIQ5I=Ex1cm^>>AG {<!mvb$-'s4D.^_Q,auR#:_SۥJnj`]F}fwm6!i< d_ܲ4Ahnz *;hjB! ұ 5^IfE!# Z yKtiDc+2:&!+ Dy" }ۯWStf:Z:^gAs"tXna ]Fv7ME( ˊ?Dl]XR@4 *r48AHrz76CLmG41N$էQUXחmZm6JS}@Z-?X'وep냴 + ;ߤNZJuLMf9%BtE1^{V7.eIPSNb 9DE /AQ#fN 9+&ѡ0D0BGqwd%(<02 A C1޴zL/qu&i+_ 5xSGVe <Z4yQn!I5Ŵ4/hPr[|E=)ڒvlFr#"3|ǡ٤KEWʗd)"/K04K' 7-D覃wlV~ı[g$]Do5LDf/hܳ,FAQ&SSXIDIFW323{Ib&5Rݗise 7׋* ,?Gf>M*ѤꊠjQ$_Q]]R}4\L3]haй?zu&;o0Afd|J;D5zY!(Iw*NDxd ڂf%,vqI^Z3ͭW[;;^v̠t2myNp+Z-}zVnW5^o:#$͟y/NYv \+vҦi=ڡL]ʹ z &@U_&vp!*_>{~z 6sL#D㢶4 :EN76,CjSkȲ$m2/< WE-BZkR%O>gC5 ~!2C_�,@ZM&8FY :mLBh�bd}>0V$#Wlg;c=um}xu>"єkiʺ^nGqds_JҤę3T4>wŎxu4,/:c3*L,YڴXz7dt$OZH'hO<3 %#JZImjLӢL|?uxrx] (ՠxu\v= wp GӚ{vhtҼLs4ߖ2:}탱w1S]M' XP„an,a;mdiJJMiwls.kzm2LKaHEedj2.\g<D Ϋ$DnÝ[x=м; (#A_D�֠ACu$5)ucvΎ[_lЌtp鐅aF2Ld:b܉C^+$v,8m(¾TuFBiLaہ㬪5QM۳i�r 1*nb=Ϥ\۾QhBр3lgӶ"�a: jwƱxYD t ! *1:؀DڮEcoc3aH{[qAA>eՀn)IX+]LŲ,n.Ɏn!.jk ̦էiQ-fzGQ -=GD\_|>*{+Z4ɋݷlph!H jRtR[֓呥M[7]"NOw?k!**i޷i1+uEX#KD,G '-qQNp0 YQL6_||"Fe=YE 2mWiꦸg?wo~&GH iJIs$УHE)C}t"_׽]@h'|NJ_!/?jXhٓO^=h{x_|_>_{s>fSF7tvfap|qtxvz7sˍgO>g|?f5P1=˃4=A sqg?>}ol|_~wwښ<?9n#lx6b'1뵭ò(DQ"<ƍPϾOؗƎhx>$QD32<>:4zŸ>Mcφ9~ pۃϾ꫿>*U+ZAZzs+=.SE}"3cx}1 7WϾ ppo_G}Ŵ -厥þnip>'=|a/|ӗ0o?<Fx.oy\km7Tsd0zo J^4CӮ޼:'/~z#0DH!ͳJzvs$2Yke z2]0{;w<ySElsƃcNO5zlGpspѫ+vGYJmjw/ ݋Sӣ7:mI{b 7[ϤP.ccȁ & =1m]i+l}|%H7^(\f<^0Y%׽&j n?]\8q)aj =qKf1Urbs0 J @7%`gL.& a1X_0 7*),ݒt/k:#lݰxË5ȓ<V1tmy;.}j1}ybzi:M!"Wq0�SHkPL'v;˳ln7 z5'_ iŖt{�8px2}Ǯn"mCNGG]RV!4e4I&v/tYH6)ǽ߶f|((jN!:NE8 4z]ӣ<`:zqEBQP7/,g32)NEO;< +fk#M_+< p3ZcL4p-:`@Ki|?Cnưt:ռ<~u͑&v*)p~ȸU_SzM#0$B9?ȹ%ݑ~VGtmxFyK.W5R̾2< 9 g= -pԴcPGM%C_;}l@xyYD?±7?:DxhL8sqy or_B!m�{{_nQEAzp[l zt;>pvE h!mw7A]G#/S:Pk1vߢJx..b"X)zMpsr5OiiQڛ*ʯ?1P9Y?Bbl}>Vj(|2ՠMVtreyejs췸E-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢEL8icfd~0WoGuRSM?B""C1w^w7h6. ZVA_3g#1#q75U'0PR'a/CQۺf=NMSGnsWI:ZzSR[RBpf:|i W⒈?R[QXeޑq=T7. a0nWa9LiQM4K#J}OJ[YzRwuORwxN-b;.Jp AeYΪ<p$wQvD#Ʃ+&0I\X/;c3?I|VIY1 %V!"&DfaY qD~pr5&eHgYQL(_zeQmjj~ :(4)&DLX67L˴쟝ul6QմR (ȤM/# (YEF4p5۱M! =~IxiGD삦f(?/>7zb;MuRG9 -˼*sА%Ә3_ב / iKWj6830K0!?^UhyR@e=e&F�X4ha$}Zr^Lh,|a١@Rn=!-ʌz^CSH Y-�KMgxsrB�1L){\L 2LiDG`Eq &4jb$ IyXǫˁtMaK`Qu@07I$p!TRX:I5&9MH|5.aǁ,E# O9+3PevCDsjt4}0gYcPKzMSAܣNTb5ټ1 ln"p"zVߪJ0/$%FTȳBWP_4' $yǂ+$"*f5 %/%3XbpV~dٓ/M=4aIGG>& sYMf<1#s]s( yVϔJ~ޝ-Uur4޽<HFsHZϗvѼ2l*a(cC>1 _[,WJBJ<N@cpId�r瓲L`2:RnUi^񉚄Ki[6ٴD  ]5phJ$Q@ϻccf$44}_/*bXp ѨC*bNj(&rZ,&Y̦EsYCᔼ9 GE1Y@cwKHd:/] er"A!C,4 /B'la7BhYmn.gnV"AA]w{Aľ1(s@3:A2Hd(x8 /$nu*5c./. 8菺.%4}gP7bT48c]WRݑ2GAfMnnnP1G2]^u{Fi&2\%l}5o7vM B"MC\?u]u:g"}NcWP5,.s[dYZo1:0A%I6[vx!EIlk{ջW VMwGoOގQTn�HUčH .L ;=AiK0Lt="#I 1Ï]xT:.+doHanz0ķƸ׷]0XO6-9vZ 2$S`lנnb^8`Wo 7 ވ%AT4m8 '[-+/t#% ֐ Wum4oAIXn/W.#MSޒ3"Be(IVCB3\i5(5dFFIKnkޤ* rh\ &| qkȒI7nQ%I~mڨYM΄eH4;zC RG2 =/&奶eYψf};EB }9&+ՈЪńa"4AL.R6zE='PJ!!n80FQ.jɖaQ[R7zcV3HM@to٦m8l1H/$d-H<Q!UeFY" z! }CjņAD=vF"xV4F!Ʀ:GMd ( [YYcOo>}tǕUӖW1j ,fYf3JՈkܹYC"5KX:ͥO *b& ّl_n 緰iMDѤvUTM*dRl 6:Աq5[147ƚvQqY3}vOْ~A>zCOqd#B TcǺ'vy*< v ͭ2{D!"$dȜn\X 7B54a WtuqD7$#krJ&r󳏊=NE/qcuM5�k7$C6ɩ.fd>0k(v+O>b?QDJ\Ñ}X/aF 5=>�QqCϢ+2M }jb06?1XRW5aжwO߽>::|73蹵`\lֵM} HgR9|M -T?d@AUu L_W^|d;/ޜs:�q9p&^ttj_p4(iJ(۷-QpeX y\z']-;A!+Z|T,vݘq|n)C24vO`"H|ɝw]EՆg?>}㏯>\_wQH+zfJj�IfRFYLe SHdF,pWȎl6VI="_?zrrtUC]%U[Ы2.<颂,U""NP9+`^LWLJO *׵0 *W_<GO?UCX+koH3ǻebNQ$@hB$@R9EM$vhp| *Ohr3=}Xcfa:ȗns-^UFQLP VGpSQD: `#P{|k;Í hL,]'=bKƿ #@=ࣲ!nC$ xѸ/y1 <0rAYApS$˓a yW'i۫A 3*흵fv8ċB|rr FDP99=xhP5#o>~u5bL^Pݖ#zr!U^E2Oyҹ~ cL{fɳ[;_hHqXE4+ GtoY)K)Z42=a-lPO$8̱i }E5U`4$G�<{FPџC8'Z|FyG%"Aʁ*vaR|nGǢtHl(KJزuY wYAEL ;^&5ERkKc<"�#2xRB\*zM<웦r׻k2 ,Nj|(`t︋{s[#z`Ró%iqS/^M&EO7_=>]�GgeUd6xF/ÛbGlmUP"GW``꣡9J?fAMb1=ѓb'/S9&v# GrMPV#!@pu=VMG(&VD0ޭߴ}^3 %S,U57mGMzL4P[zZCI7@\QgR,*H]M_#\#dSFw6A K]d!89ٺ{+=_H~ >ԕ!^J,*'ɡǯ7*kX# !~OU >niK]YGBusMUU_ ?|W<{v֭o<Xz^o)d3tw?ڋ={i}7y>}*>RmC]ً8ۭ~ڵ?xw|o<m K?XΏ6;6=ͨіeͳzq5G~7?ԝ&.Kt}ԓQx/v9,{yE֏~7]Ű\׵5$J.>VTefAfiהڪrk%_{7}AB)w=6%ZhGŽּ0Sꡱ--;/_>*?C|縯 |vwj(pk:-GX{'z[r |{z'[n0N|V;* uiS'[MaV/C~L|k^%jZuhe=s LhOOo&ݭR}fcm"!zG#IEͩPr}IyvwɶLvdX V#3z{[/DqkwN-:J;&T7r18X{d*ʪHP쿾pm?Wxx utgʽb˼5*'C=~+ޠ.AdxګZۇ Ipxq,LEuȧ`9 ̓7v{rZG{ԓk"ӛ=jdrMKG/,඲Դr<x:M>Ωh嶬]{]y^Wy~2^/ȃ6-1l7!c 6Nɤ}Aw[3hB;=;ḞUٶX-+GQ:* .r:J>:ݮ=:LW MfT,iԓURPhY=];tNxxv^"HRD]) [aG>I6,.qs.UDۤ\Z86m'vD2,@eg}Ag0YqЮ(?"|ZIaَkZ_IKG/5Xpo(.TvӶO[>)Aq<G5{z*)Z`0 : VgOfnEӖ/cHZZɘ O,uZ2QdI+ OW1<RDiumNƎoo:&i'bK27e2z9SڮTߣ.^oe -ZJR`y2C/ =ag%fKCh@>3r2 ih- žND*[=PH\k6>cG{]G3Tqa3z_zb* |Jh2#_LjO,YmP裫9>fXAE睴5R,zWh$K%VT1\m9a` N(֗QDQt01 `9.vHQK srbwAtfP ?Pţ= 9[}p#JVJ0tpAͥ'(Q//X؛63f|nРA 4hРA 4hРA 4hРA 4hРA 4hРA 4hРA 4hРA 4hРA 4h9L9nڐ$+JqpOa0+ssi4~6w+߾)Bpfx0F8mh^ӡx, fܹ): XB{4 <ɒj2q.'\e8fcL?#ck Mz ;;8B8 h:> h+鈾4imZo&薩h8fyFa>%[(k 9TK߆a/濆"nãAGږe8aͰ: pcj,`�;$ &p|P7Wl@f:h;Q6\ilID6cJpAń  :|(NR&HM~` 7$бy>B:nU2ij]`4ض24kG8x@ &r98l ~ '~yAj`AwXiwomp,(Iz'8}'NH4$8aNӢ \haqu]0_]�#RL9TEN+P7H\ce6={ gY|8O,vmҁoZXW6<|cLw79;MG iLQ]H9ʄOC?8a4\=(gq^�Eq@Aۻ}0!Y itsYM7=#MNg0Ma-4o<F4\8cW>94Md:y{etmX< )X'EHSdejB=`LFjW;OmTy1H=M2#ij}3& , 4,A݈ )郞h$,ALw\t~@1U;MkDbLVJ(_Eܴ DnZі9W0 xn>ݎ=ƣ΢4ўЎ۲I8{:yFM'(MrgQS_˷r�T|("^UVd0cO4:UM @?>)'ggY=B3C״^GtNNȞaE!cAAzZz:&~+mB`1s=O?W9>>IQMnkQ}̙Jmr9ˏY>J4t5H#侥%tC͋tXհK)V{"qCڟca ᣎx�q5Πc)"qCC:C,&*;<y\^\M'W֓zw=hβf´-Y d ?a\}2 +rQ1˂6i,c~yyr> Qh* F}R%2}uUx d;(tZ!\ܢ)Q99 OG:gy>yy1#TH -I}ݒ%ߓmɰ,�)^E5;ʚ" ChpYI(C;<bDx_\d9Dbv'NUn꺡q[$zX8ZWChx9p t\Z 3B8>/_\^y]5;G*}E,ih�43uM5'E^T FR9 keWpULC`Ŭ@ۦdEʆ0X0 ECM9BRF:=; ?AxctU4Dxxp=7.h%_0Amkz3uhm-A'Nb[Vsԫ%S {! AR_otR@ZQlK9{3u}xޫTGTX3@%&WxгtRLJW{40<;=;}GMȲ&6 7c^ew$LmP~rJ"v:&#{4"g4)"$p{'!4}pRI13vzu=/f'5%CI!w*Ӊ D: Ή&+|4(4ކRcL%E3N[LwfVEq쏥UP˂TdSeDr p,;tPu0j|.ftWwHEh2acZF% ,ʺ(t0/&#(H0 1`>/JyTĂ9јF!'=4uQ`P4.*dZ@KS4�%a0NQ)~: hr y\TTIi@S2}>';G}s90m(BE)!(@0fwW%AhI$0*r*v#J(<g|#xRWe >  idQ&N C<ג^Ĕ|$ib=KW_9om7qP98Pe69ݨ.�ޣGOd z )]mѢ ӊ"7td&cBa5'?Ӏ|w34nZNUE9V"$g7rf4vgy۶< !oAZ�\j_nqc4n/"QIKCQ axq>/CBW5ܝgay0UmԊ熁md-~$3w7UFejHBפdڪ ySZ )%4fq2-|6rQÍ^*峲Bd߂Ǿ!i+jd77BDP)9zBޞ _Fj yz҄*+ =B)PnYH_Չa*uy ;HIпD2P sA;�tRh)l\dE ǰÊduu;C0Y-7wu'v9ǻ'[[ ~:U=KŸԨH`2)L&۔D"?Szvp5t~ vTMjBX탭F_YKPrF&z]үS=$KS4dA-Uhj]^[�dB`Mwڴ"f>>8?ﰃjiYY/ЩڹS,(*F 8gq2h~~sA5O/ǜn.nn_6v^s'w"iCA1u mc>[= ïqyƉ6t-9_{zkkjQQT*7:oN[dy6fV3Da8vhz3Gf+Qxx W0zk$;+Y\xoym*ɠ3SYgGGM)&Chs9RDѪ2o7׷wE#8A`eeq!dw>uKko\74t a`ݷG,F74.u>߬.ZZ^:aiK ߡ^LˠMQ(ߑgj9Zj /!1OpP�<{sג19yB!(C #=BFHyQ ?t;\o5v_Āhz@BZ3Ў(?yazj~P%R-5' *[0H@FG?ut[8A$͔.ݕy\~ȴ ;E x8�E!F c"Œ$t%vi&vFGv/Q`[kLip\ĖQGZ}e 9M}D~ap4(20.˲RQO_Β>(}\g>{sJrǍ*ij$Q<V%x8 afd3b)V^~lT4B '1%y B$ѰvYQ GIy* Jq5QRK;/#PzH+I Df,"3,7EQȽO.HF2҄fawZdMU.EI6*[X$/0}Z(4g )^Gt($۶3J}j9 8x ƐE#FBF}(qd9 #ԂӘ^}gS{P砜(bhrlٿҢ*!H4+W_7ϗ.>>~뷪]E~32:W|n�MLp{oղ8tt"jo>ÝDݵ7,,Z~/>ja}gǍKaۭAr)A⧅\^mxzc?p* ( |y2g/^6N<5li< N_/6|7-2a**q}A%9;>lt[, .c$t<*][S?,kϾɗ_=a[i#4]vgmNst "g%rس-Mnd_ˋ?yW|{"=^ev[@0![a9Y^5xy9y{te~\Z~P/׎;CnȫI\/A \"TR5 55 P18] 6pk?ŗϾvaeie;xٰ]S{b|FUۢ.ak[v~aI 8IQDrY}67vO,'v948Hj: 趩Fbeͫ$5T)twŭ 3/(v<t<HV늬(aXMfG3L'QAqN;Ov76O'{]^3"t޶D9yhK1^sCTMo.#QZ^:C_hyˇ[;NѸp9=dc<A:슌VLF|ġg+݃' |JIi 7wNXA5?8h:QŪ"#j0GThKL'TEh6[_fcc}$YuG XZ@6MK_W~ ̓ $^4̓~^9'ܭfFd:h/Lik?)֞Bp( ZbmWP1('EH[ن5.{ZaFMEi1UC9*WF KUc*VO Cߏ2O<9h eUw3iԼHGKɧYhUε3a;AD.s(&ZI159F[HjdE,irj$ $$j$$%6G 9eH�v{6e#sV*xQ1t5;bFfKcC}^Ԗ%a~@x|eY0! ԄO;,Ӄ<5,qEٌ6Ss,rW$Sp){t:1"t^8`ڗAsB߄bY0}T䞮NxY#SFh+#K7TD;8j֍j'U7]x4.]}I0$g!'O2jVeєљ9~sܑhZjOv J"%'HcFcFMZIoN.Wr{2DK>D$3 ]ϲ(͎Q .feC Ua./.auw޲(ErPP,x_gWW,$zGI[%R5 ӍF>N]FC}BISS4L#f: }^>>#2 - 4R#*25BMAضXq֥NW%= NjhZhsf>ɒĺebo2L&imk[۶PD:ΦE^ny3I/Hb>Cx1*|So7$ӴG4KC6m#ҠKgQe5m1x늶"0Fo1ouԵE6ݙnYh^r4-Qx8; j �Q~^-%? ˶@}z ȵG;a$I$Q+(ąяܬUk\ږS5?ʹm{B5\F5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5j'lz!$ 7VZ:϶t9t"k*ȒJEo{{wڦi>:'9^/j)gËyELӴ赃(@Y꺪]uq-Y}Zle 9眦{ Tci%�MCuSn7,4e{2mus=6mi4-+�Mxgـe,<?rw m)舭Q%c4av_q$jnHj4UQTAxgdOgFˬDI^ie:Fcaixyƾg8 K.7[󊤈˖GIeqYaٸ\GH߮NҸ$4ßR-۳t۲T 6lni 4{ pCW73 CI2˰}>4}FNƾ ӾZ_u\ Ĭ(jlz!X6ce�4uً::C@'툂iGc{ag1li< deay8I/ ͿQT6xO�QEi'H`8`dxv4 b|F:n0pYSeEzݎ ! yf5g0Aw1 ;wIdyd lv2| p(̡'t t$/A`i FO~?k*p.*Zҭf0T>-@y6t)FdaIJ-�(/b6M}B 7d&,;zCH7*ÑT`iz*͹ -(r0 FtH{~@JҺ*gZkYY{WN3B%Yd؊yo4P'J(h2i;gG�b6W<Ł [& e3%2tx`dCYІ(tEYV8+6T))iiP*iZ 8^gNP_8ݿdeN4 0CtHPU6Q'S'+є(-.$!, xAGh,^w1ŽUcħa"O@�k(/#jd Pҽ0|^Q LQԥ +)u9|D|k0y!dA0|Ǐ>fDyF| gIUYąJ*Lgj\9)&&?T=nu;egk8{8bhŁbJL^,U"`!Y*ɥ`Gt\,WjJrϫow'Hכ ` +,IzT)FA5NCAhtb\/ʹTV eTGrI;{"; G"4_.-ӊ6&@e{,/o"aCQ|^/8t!N!о> .h�'N(y lT4E3> BO!AB)*V2zWi^ٖ!2#TiD6:d"0_j^r NX̊؁�5sTѾ@"4Ň|Z"z,Q5͡X�Ly$yކD8lH@*^V%pfDjY8ayd/8nɔW @Y`s#ݷ6<2o Esr 5γAAF ԲĒ�z)뫫 Tçm'cȌdjR!IKtTwHZ< a;;mwzi<^?�5R8\ ي�:7jq) �I,hwIKĺ$VZGo.x_1sݷgZ5}|\@t3@I 6XF~F-zpz+E"{n;v3öӣ 7p GoA}eA|(_DB^ylh"~u3;wao0s:^q?=|o50߼7EYfAP9r0phe; ,5a^VN[9Q^o+VX6�+B5pWyGO3BOe $"-" smìZ!WkF4ylʺīѬ?d;uCpqhoNc,8 }[2<Y7@n CDBgMhHN3H@Q)qjhs J9`Ê8yO\Viچ& hjQi>@I2P.utC:CP]`ET(qt)5؎I|7/u?|NӺ8XڅZ=7Qu`)uy41dAу$^"29{Q"I"?lSP184ZP}�*2!"_%T%EQס\/tQ֫b#"kbZ$`PWyQ!n)5Q2rQFiX&d!k\  4bq[ȩi`zEk ) LWkp?޼GbmI1I njQBBKw:N0rN@Vբ !jbJj&3GEWe9q x N4x(k*.^nJf(:QO!]ߞ z\NK ̦PT< |C( 勇 V$M'M닞g*4Pt h̐d+ f}`E#75{ Ь46GX6{fw/p\M5iώ4*GB8ES]B,Ʒ U3`6t[�tFnGi:<{1vw^yȀ\mħtrd;hcU/Q JCSFK,ǛrZ5%Y$C!JS~|CUjZU=q렵bw}+ytgU K#jj=/<33.i,+G,AA+*t #dO;Q7o۽38?>P`hanImud^ VsQBY IT bKyvxz{uvw{˽V=pJ:  dd2 4oӢ7sNfu̫UވKl~gO>{{eT?4Ȗ3\F(MPYqOuEPEY$IF;|'=ɥFVլ(R\޾;<OXN>8y:{ Rz$yѝ׹Ovy8zHgeMŭݗdkw5S ГqϬ!z=E* 4*}w|9 ?i3r}6ޫOwAuߍd4JU;s-_6NXnМ[GLd2reg Uڼ:ny}p1^)  (IP,Kl .HH5 gsC1>q"F5 NZ8($Թ8]F檚:Γ=#>ʤ|k\M.!Uf Y6J^`k3 ?nv[֥DWޥimA-@;lAӾbP2pMpSZ]"BA"6:( "iAu^׳?fpqVXQV7^Yԋ".:ژ4ASfaYxBU~PO4$@$` 4]L˲*3G'mF>[BĠF!Rp'p KQN{w|7ã+4JvNdt Q{g e8+((>'Ј~?l>4/i%�>29G 3C`锜@gRU'}_u_ *wO yT󻜾L)A�]P9`锞t[4Cyi7O� B >UŢg[cR%=GoAr5<E2͒9YL7?y7&ٌlJ^TϷsDY ,A8EڵXҭh%q^ݒ=;z_~h>V]TS9͈Ep[?g`|WEݬzsZPQًoW ԤY'/K8,[;/?_>y{їl<8|1wZϿAz/2v"i]SЫQgO<[[q0{>_v~o\VG篿͓gvkQ1\CR.vW>}仯{ۗ"gKcNUݫWYyv ?xW 2E໾g w>g:E_7ϟ<{_޻^O|/ ldMWyl((&:GG*;鱬붇/NbqMd٣oWyg?gy^9˺eKxrm"m^iB/ɪEt34'5=կy~ޗ}x o*-r 3fUw%JrGv>ndY6)C\}w> *�F=CǾZf( Ù z| IauznHs2;ճ?>|?_|7zp)4ql4K>&T:Gpik\BxfŻ՗~}ٳߏ)¤,%s#7Ț,2˅ 2**8nW"C b9÷3zx>Wә JE*#(bN.*ƞpq3)R4d=ۿ|ş>~d~ ytnl_!4=SǵOõu\ BUduFEf]zyo._z+3.sx"�=InmH؝> qksH>ۯԽ|ZstBȍx^ͲL$φR|}oU* DLWuF^=|{oGIլJ.4wu3ұӼzqdz{-v,$XO{ǹzg}uczf3EȜ*6< &oyp0ѹs.~z0/??{~2o댹æ@b? Z#/w]S$9?4PN7k\^|0w}- ^HtҌu[vGLFiRELt ?8f"dxQw77#@M ZQPWsH:&`4FOMm\EpUYZ.KyXp<h>(:VvʽER&Y[!'-S$mJyT.RA4h^>u{=7`ADð"ݛ,fǸq'2̌U4MːVP,|GPޙX1 LAt#Hr.qB 6Λ i|l̛GÆ aWR4XEUp {gQnp.]T<b2cqq]1)A qe0:m/':4XMO!@f{^EqY\56tGX>jݮ'(} v7 MB^Ӭ:L~6 Fk0AׇmѺf2x`̢,~2<|0{IӊY6<m3pZ%E _�}41$E0D>Yb}&P9%Fy>B͓ph`j)`4d1U/E٬kz. 7}œ2>Rk YmX.扶W[cdh(AJ246z{WKL<I0hD,h6)Ǣ|6׷uNL H*Iv9=xr\@Ӡ&Gj~P*ICneMCje'xc`V75@FEn --ZDdϡ~Ddz*v08V*Kf_Vdm>3CI`34&c0-Q(M 4ot8eE71BQTiϺB&MofOf HǴSeygɴYI]'{uqNSωXo . arZy }$(do@vq@ɩLgyûj,OS$xDUs~>9 f|$BܢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZkWZ% ,7BHf_ `㘖z16>mN%Q[7Y ι=vC hAX C$fAu,@HRGBO鯃v fs;mI6< ܿDC=\LsGq$PnťF IdZ6~=j 8LU$$TF=Q>g~*3j 8lM?_azNfFyAD"퓛#rZԕ:8ٌy9i"JU=/4Rƈ Jg;gjxlE6MQ0V.N,P?lv]Q869]se"1 !2ZHxcj &IQDH?DÁf;h41 ڜKDشc} _cqC% J n,W 雦m^o4 X Fc2NJD4*EkMF<JՌ:e,`8^WDS<ܐ#8TP^(ӘEc##OoulzQied`:hܿ{gcT- ~ <AD!zmM * IcHM Lrvt4XMǚiiUoԿ:Oy|x64l$~ ]4ϳ|Zi*a"ҼRBdr1?Π36LDZppvOhdbD!#@gS%`wczz4=R&N<wtz8r4Ku?rgNXdi^N51F`a]WIQV5țkcP3u;#>m|y=ڤ?߅(j@WUU!oAٜI"U2j0H&NdžI(v;xaMd*3nU8rDްQw  hȋ,c#$BhfX>zNg0wG8G(/`s}!@ k4mgf _O�iԗSfroY0|{PQ6 j3#ZD!UVD!.`o&jn)$5=`P\u# ԉ\]un:Ab9A8bVPF* CGe#"0Ɋzu jR<Hc<ȭN|{sqymz%$ͲY4'5UYT,U|<l~ݮ/B t8JT=:Fh�ڦŠpHEP"�CH(8ip4bjoa cg$XT"#<BD\=4Mk< Ki]67=7'axjx @-Ȉ\=_ﶛae5Zqp2P~.a(5PKGm70t×I,pYdq_PuNlw5y{w=nV9S9r;.R8 \Ƙy16VfX.Bߦs<n{X}8U]SI& ᳧1yP ڳ>�+p5| H<Ulg|6[rq4껻n E:"T0:9h�yW>�F/̳FDr|ཬR;xwN!QEIu1=P/fa  5cLtw{@P︻x{AO 1{ytN#Ԉ�­CPw R,h/_&0=|ٓѷayLRṎlI ܼ,K9\Aj,SK8 DYV{%҃zr7zRS2D<Dz#`MK-}:}#O*U f WZi:Z}dž"ՠ4ޘ1~{>\H~w-M3WIB#~LD\ԫEN4MS7{W͗D %a-l~ ÞePt2.-OW ήE rlz&4(8 z"9F-=D~ZmǬPEdV~gRqU ΪrV7Khrԑ �AԋEAV R_%a$D1rخNߣhz[ ː'0}!XAχ#R;1"M8ZD@p]rrP0( pX/8̢^Ve~#Fې=TJ^A4:}Tkc&O}/T3�jyHJ4xKjtG =BFݮ� RhEcd3^n{:5"=͑V5wDeHayA4oq�9RtjSe2$r]YB ^ph՚A<c %;B~$7QB$4eJUTdo|蠗+"0 |_#:dذ=&8{U7{ő 6& X !@93;'<AU|~lΜY0HjTSSn"c薣Kxb ŭhDG34!aāE%0S�InxyQ�˧*AU#Y&,5qBl`xoP%"p gNšIVRUn):(ǔ}vyylgt]1˘LZϊkˆFMtʦwEv88,2ҸN6mV_^s +1FeBLTQ$~`uK2eFVOH7ȁz" CPn{ tZa`GWZc%SY`Z'V7@ 4T&NG,ń[ABa{cUnG^�IqaQE,Q~?5[ }aqnfh>l |:BM ЊA;,05/ӡ8^`F JdLE@{;{[LJŕCc/RjYVw9<-">�QT6\Mt0WqS, >W& @SdKõwKk;[ gfgA]fX", ed�-_q`gs.5= TQGY~c:...[Qee xAlnyg͒az G{.XM؋�+76NOOO3 dȡ,?#(uLqa] .@kHh�[cV''f޼]=Q8C~(sVvqA䪧~yp=We P.'sK[{m$aQnXdď"dAVCFٮc1B<N>gd ^@9< F(>Z> ,d>yO+F P>P6£o_ >3+0CU'քl)} 4Ér4mێ$+j"MKYlx|9PucG}!S 61#Xge5nfY6_ouvl`rʢ;\}7p8Xq"c ~qۆ`a@2KV#Rݲϣ4vV߽Y>1jipmz]{~) iG=0ve{%YVZi:KH/د)D0s.KuYBgsT­bv�F3 ?Cfp+V8`UpP8fpO<\^HݜRHNѦA qRk+IZ;BtT恬1&Txߤ瀠cTf L0Z |*@\1BGwG ^?*m%b0iWV =  H:#;:+AY|m (4P*h"gya>(:K ƿƿgf(ds ~IP5U t3r&8 8Ч(y| 6/r"FNn}B^eN`B` u QS8@(Ɂ2a@)33S333S?>o<yomt+�5sQO꿞?zrɃG3mkaquOvf?|n~ճ%?k~ ԱPMOOOο~o{ū8l1ͣ9|Nx{|lray $?~rrrj7vT/v ,eS6x0oϟ>z<pؚ튲4V~`"K^ax(rc<y귷snc D)}?׷>ylz[@3Rsp86DVpVӓJ!ӶmSm-zgM꿙‡=U?xoxUw,dr͓Џ(C[,6,*r%_2O~he--Ϟ~f7qR#Cn$ltz] Uf'4qMCQa蠡Nd}z? k+o^Mzŋ?L.JVyTfIu}1])kZ0W:]bгFS}tؾ*+?Mz֐-SP#\+qʒ$kgSzyF԰P lCtwv7FcmzW;.M" 'Y* r4"_jEnI5mֱ4D>U+TUmt빍Ý#F$ Q" F4501Qn.f&8wpcq馫4'_onmoo4 `R͊ABcQtҼ#KnŠC$=v>:;VΣ7 =r}yea9 E6$B],B]Dz0Ǐs['nRF<v5Hkk7javqtP$=F^�ECBeտjK8XkJ-Ȃ(ntaqeH-|Rwo!4r p#TTi,s=r_qC݇Փ!~h( >o(twuiyqquISU`"WZӂcŤ'z԰lt_.rPoWlNjo2XZ I$< bx[nԗ}'bcueS<-]\`߼*noc{gkL5xL~AR F^m(Xp>lx(quyBt4*]5Wotĉ<4ww7|l-NY?u "iA :}Ҭ:a$_m,*˵w{g2O4/Y;Tu^e**$,tuYzlkfMEuA6  B' D FWW<Um\K6 ;*s~e69�w0<wψy+ 18vpkb'y:QH~E٠5U7 TEV&v mH^k˔R 2 -GczR˳uT#-]*Rĩ6 k'Jpe7A:/Mv-xy%mR7Eȧ,u&pA.N|STΉ |Pjl@ ݂: #L("B{vC7F# JYˉgYh** OphχF0'!.s=Bqg"(ݰ8dbYl[Iȣ'k.0TuyI; kdI0dXTqb-�T` 8t6<^\*Buw{(I3wXrf: ʃZR 过SR:H'ͱ6N:,ZKnRH}A:`DE=϶BSڇDW6p!,t YiՒVojYf'Y~BEi{pFe^V^Xܞ@ 7l婡4vDg痗wȐ,܈DS4+c]!$=QE)-9,Ʈg( Uia >eWe"DqPU[ۂjfgWedk_n Q][JU ^Z4(<C9>—_P#6_&iU_jpWbv[THUͶm2PFN{A |""4%5;U} s >?}=GI\A $'ԳN!(ח{;5t5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQH9'$pqϱLStxY"DdPM>'$.ܗhk*%z #J$QIu=% r ax%VjUU]Jwk"MT{N T]?@bUWU0L\64e^2܆x'8 %*ܭ"YKNʸw&|kxz8AeA&=th+**-#w%AyB%ڎb߂ 2FJg<%e流8^txQJs)'kjDyAV-C6N" KX:n'瀕jG0h" s(5/l]Q`z;{Ga:X$?#@h4g{tx?ZnE0)@LTWgef}ݚju(V~R-CF\ 7hG2 p>UnjQQjCt鷓r.(}哷\*,]pep>L6MUV / vh\mu~۷vǼhZW<ݶǍyLSDU%ZGIF3`C,m1$57)8pPJ;=f t:h<bƬ4ff0١ h{gYt (zUVޜHʣLO%򲦫dc9vh# Qoo}r8NzH?JKui2GfnX[LtX*?2pb]<l9f3 F񈥘ifiACoi}TeUEI ?b%NM&<tۼ |Œhs&Jui^w>Dip#a^>�#/ jgQE<F3V5s" .I50M$�H=!G=<LQXp"iN#6)=װ ggv{# b2b0-I7UQ6x=닰(QQgU C` 5E5w@2h&z?skЇ ;fXMML5$  EAY=_̪" Lj@V,tsd%uǰL7byE �$4qeX0r`+p(F) }[g:s^'|1�Ih@a Pp?H9RDUYB�ILldd6xDa�? mϳd  хH^~r ;A{g敆8)xQs|6GlZ5m ^`c4A;냵I02`9(/4h~Bep&8BNC$C-bZ- 0I";8qex0`k" kf6,!nUӺ'YI |v}AYJfru6*EaSs-"JG,i1ϦS$/0e~x!Ԣ)D>tOs/.V `Qy |64+PTb) HeMIQ*ķUWETBh؀pV>uKcZ}uqZjHG0k 9kLI o`8++@{V<GShde3A /6(;;F8 st]{[::fx:6 *-8"ˡ<s<oQ#IAc5iR 6#4(֋-T_]AT x a$"1yjN* M j>/HxQ4:F!Bb7ؘ!P&7�I4;bYN, uH sJ >?FIY&F|cEAadQ@J[7gSNZ+Son$'T.̲! 'hΘCs5uĽvaKQt) i"X5.p%h*ˋT,pFhbi6 x[ &Ѡ-] NY/zbPV�4. jyly> MmڤӲ(@Y�"kрr,4;%sba#@#ɜitM| $ je=M#=0F$VLHˋM(5ٌlYV~@,hWWAil{rqI+^W<@B$,o=6-Q)_-(ɳ&h8|bHUIfME�1�@7&\I]؁< Ph:kVnEX6#q$6U ,RX^ ch?Afs0GzeaQ%>LvE Rh҄ .D-Iu;j隆Z�L`YJmYG�c pvaqNX\ƺ.\,̪٦AUմ 1O I,(m'I#~ä#цg0�h2݈"ɚrm5..G[U9O"Esei*r, ]`m&z=/ гK7oX1e@B~'d`><M*6J4#4 2[2>n #Jh{4FФy]x&Jc*yi4ű锴h #Cs( ׳Ϥpw~ ZJ|.WDڳ* 6qxfNAsoÑ v б$c@ t~Oh|Bb//}]TpSUVNDTVMt$Ja гi G鮚IwX<[WYE='A Pw?-<iȊ۝w_h\&%}9BYw@W7BOu 1\S7nZ6/؏е(0VFq+ OBso>}>zɠ:;^,'եMc=JdDQ)j1[Њ莋n dJ}Gɗϟ޽}| NA"rQ p"-+f֧m.$A5=?*K#|yoOOO?ydkggȄL]`yp5V ,`P+f,$*~w :vr$708g}ֳO=9Rri�DqL�rcAI/m1fǦu0˟IpB(iEIp_lS[O=9~KVO`JAI/]սfU8OGg^I6팡%KR?9xlkk{{{P@7h`'VR[Wqo]VSB5]W0?~=~up<O q/|Cwda=4p.v1;ka'QBXR 0P;GɵR,*$)0p<G,XAL@[ԐTe齁Q>˿X:h[3mxմCj!Iǡgii�%u4Q !_H O>u<jihT@GOD\9lEQKׯb-b: 㔒 |�0}e Ƅ6&1HYۥ2ËףbĘ}qIS|U/v}1@e%ԍOI]JpYIe4M 'Y>!Mğ</wx ҙ4^Q%5 z iN젇ԮEsm5mсAO@�wO J^o]e+F#KA GJs;<˨hyFw.sKPƓ]q^KiH vDtSAe*!?-\-JH |SA7j~W]l"*o2L@NbuNࠕ!0\H0HBvvĒJL)ޜrW\J<rz@Bl<cat1)4;$+zZ>9u&q9;okTxdQVM/o=zy[n^~ᛯwb$ )iJ O ýݽ[o޹ǭ\X=o֠ɽ;y{c5!\}.%ɫLr{kgo;ܸu]AdQ]{O~scO>ټw߮_:EQ76>zrΟ_ jڹ*˅*tp2ǝ흽'oܼwo8AUUe;Cqmmf4h{y[w<c׈{έw^7`UM[ߨ*S{|`o1?q$ %ɺ7xz4dY`7;o^88r ='k>{ocݗxӶ(̩AM<"xrw?xtC_-/UTPoG?끤:zCt0c^ Q/|ɟ{LnIn �{5H{^?y`ۂjynkHT-[uϮ9T]p %nns<=(Ѯ5~y7[>lN- XE_;;~h}8n'”YV|[#Ky C5<SG73 M <۲#tv=WH޼|jу;lkudkV<i4u;ͲFTyԳyޕ-%0vjQ\@ž$$?'jjA%fT Azw./^wnKXr, , cYkm^ZD.3 'krc/ׯ^ǫ~(p7gu Y{2^.0m[k +H1F'e}e g_fr>{Z鴻6L kٌ|P:6}q6}<f~e99lývضy`(~Tϟ<ʦ_G t[7G՛g?~2_k˛7%eW&+vkдS݊LӞT0E쇦i(Wg;ŃfvP5]ۆpw#[AqI$)q_?"vmraG/=^⧋ ðxݍ ]m70tuB? v˧ m~nZۮ h]zw}qvH_~d}ktVO <ԋ"qZ^/_>7#\rsͶ鐡x~u}1Ͽ_)fߞ1DAՊCCϟaInEUϿ>7osV>u,R˻?=|*\XFn5g0(|.L6@#Gtg="f.yƗO3j[DU<n).c}㫂M/:rLG7! Ey/g"ץ&p )߶?<zuEi^hARlv//0XX40.$q7?} A>?)e*ѩ ݌_>O%$ 6M&e$} $su~S/Ya ߿vSF>Ձ۹`~ջOC]R=7(RP:{E|16h_ꌓ4EJ6n2K"qN$j~Tqw+1l4Q{ǭY?,Rߎu7f*@:wO"pxyR[\hNmBei5{B@b'nY 6fO!'{O+ yj0țNm2/*UcJR$#l]l]20Sb<^}<:Ru_7ްToiz\ڋwOn^(<U/6YHC ;:,WI4z#ҢlA|<M(ӕL'dRb8> ^1,x.mԵQA>|l͞bþdomPo:c.G c 3^3AѶ0& 1?Vg3nxA6rɦ`آd ?̋8]G4h<2mK閩K{͆t#_0$4?Om/ۂjs"=̲:..y;6sWAV%0qu㙳kͧmSӣu0:|jCg'i xys<K:xZ-jQgi{ElqQr$Ӳ-EԼql ˸I@է|/Ȫ.4A?tD'L;js^]y9<P%S= jPE9@iI/[)5u)<ޢLJh"]UU]%_U2,u.3& 5ikb;oOO,HYއ>3)?<Rz/tَe߷ B] K47P'W4f|] @t׋@HeM;U^Np) &L0a„ &L0a„ &L0a„ &L0a„ &L0a„ &L0a„ &L0a„ &L0a„ &Lp,}#'H:[,DyA3L4 6UEVt9ٖmp q4EE5[42uC'΅Zzic 6m ^, |3ˢ$%ݤAGaX6]/,F,]zT~%o&au</8I<zB4-?M&9IOkOvL^VL75 ( 0N" ]ǁ[Zq#^&qIY˧˺Yyu1Vf'4A0fQЦ0?,pMMU5t=[~xp;b1pQuS a -YH_idH&;2/U4[rwOPr;y(]qf:kj/|-=F㸗Rң20׮x{a\JSQǀs(wKY34EF;.$}fb&3My5ʋ"O5[q混 YÅu[*{:[x~v{3hbTp(=L[ vlvzYa8z* Zq N2@r]G7�kvRs|6g%;"]庈=b:X8_g^U Хb%-M4e;>lz@|Z.AVKa P#2ȃ[?a;̫:-]9I] h$40dm$^JՒ[qPhM3 -A2zuyBj##�Y`MZBS`Ǖ*KZ~M'.cn4G:]j۲4 WW3\Pu"}DOKa:L i#cЃט =?/M4aSDUdAr[x@;yFu%mW97d"28 >4aa6+%1'/{(ɫleUׅLM:daRT%ñAۺ?;?]? Ҷ.SyDA ^ qΉξ0LSY)̦ih:(i1U5[ <).bbCæSx)edOC\x"hI쟤 :,j1cT$QۨETS?r8xyۮ$J)H 9Zb!!3O)H5֑ZX]0;̺i7e)$K�/gauGch7n.<)b�Wcw: ml]3tfҠ�Jl̎9́ˈ<8E|l~;CCG)uqd JWS, j`*v3bK29RuB?}$ݶa7#$?΁lMHj"rS @?XO7m׵4(3p"LY" � on?wݸ񑮩$B~NԢ\TQV28EP%|Bm62Efҧ 2Ȃu3xB{(FQ"OgNq%ز IZ!j,ź-)HjHqrԵ× B4< UI yK(Oc [Xd.M f\WMK0FYH:a4ꄲl,궊v d[x#}wx9^^vmݬ,ϣDnjBfQs"P`#M50n !c>"~\'p1(pmGw6d۶}F e(c4~&X)#zZPxIqa=fڃ̐BòÝ jZc[nDZÞPҝ#">rX(` {-\|D2�Ҕ$hw{U_qGIt+48U "h~+2fH\_{*H!&x=(4uChA)47Mʦt)DEIS .Lb4o4 M*"hz@dLB_ lYqn]MeI4#뙫(;!vXd gR4nj /aX6cr;"~K&<%΋ȏ^o,~'3y[Bb4 RtG/J,zh[4P-y@IUYb(DYe cH 0v]m#:ҽ|S|zPJx4=ne!B?5֪]8K='gܵ ,pwqKUx wu?qdi]Z[-Kk1 D1$HDL9 A{CdsMUA/|nHh�+`H+ n] YE^%5O$/0'` %A8HX`L sMQ="v717|ӌa'YI%}bmVK4+-!`jFd>z+xX|eπFdX+ʊCdy;FX0 1A,dF tQ>-�#Q?! Ym>0q%bYqQH<eŊ!9Dd%E<1R&d$ *%Ʋg!@cO: = c_-/Zـq90. " +:^>_dJLMosFLuG8j $aV`YCb~?t KA6R/v3C!U7 &(1yP94 2jg4Y=LYA慞* a C5#%Q?Pv>F %iW!eTyH-H˨X 0L"WmiI;BM]z !?aAP}T4<Ea/ "'(-cJ^f }ՠy: !1e8@C^c0䡡*b*D&u9E-)'<|!C9^5Ԫx,(Q.nT<xv%% sE ʪ.Q-p( |V4#`FcQf{1*S[%]B 4)&qҘ|AƔ42mFAk^48ÆEEQꡟT)gAL7xrz^%:FX/jñh0 >a |^tfdy @L( I�.Br 5 U0= Wi4Q5Z^m  r"&&E>iz1.+ش%과DL7v@;ˊB̼kk+oחkPH0Z Y&;}"=Ŗ[']]�JDC{}M^t2'iEn{gmݻ啕o "GF;@JNK![ xn5獓ٖO1 GN{{о]Y܀iAʫB] B[YsvI{4hցW fa�b$V6 Y)gP&:謯.a5t|Ы*o`be V0 <cmuuVܬ1cl9 ߇Ǜd{H$)~IX2@!ƮoJ϶?կ./.h,Qb+;�fvcA˖x9nRb\Y5χj%9~'B9F$"8fnbiQfFAgxՒ"xeP0}4VEp-sP: *ق헼 dWd8z<TJ<KtK#t :ɶdbۧt6EWǢ�#X8�"@y)x4.Z by[Jwڒo/t7 קA=>U(c>P9QBN$3vS-Sb/ezW׭}u8zaV)�oTG#V&K+u =la3 ^;B} 8q?Hsqk/üDP+9dI4Kl .o>il=i!?+Spw?�\r$�c~  gY`N||=%Ŏ"$Lf) T SL1&4sjcG4C�:}~B!y`9<"N!1HD`i :ntW0<CX\$Y_ l\rUi1 $ܑ%e8)PCYA;*0�?,9yVr "x sHSsEo߼|<{|M̗OCLJČWªլ^vo^~}G}^$_?~7_}߿~Kuۍxwy~jJ ˑ%2V\y[_{}ݷϞKD}rJOϿo_o^^~_xv|Y tIw~Z;l[߼_D@wIe/Oe}ksͫW`bOY\$9=><4n@Usc,w+gwxQ[~Ŵˋ%|חwW߬|hpnm ߼|7֏j7F :K O7WwN/_Q=JD<i2:?kM$O|h^DRp竪?W޽Y;B]_C356>󳏵յo68YvRWiNTR˫KO>x&8~j_:=hE3ܗ7G;k޽?];f`A@66'kjEgytds ~oSI ' m]tcZb!.S:6k۠yed14 dIk뛵.C9Q FF(F҂�\%Iy"bqT侮 QpW$ YhԽ{ynipWZ6Cz`kkzcӝSHd{0TF244,ɧJ-6dI2TT@2뵃vaĞ~ :SxrWr8㲋 W2)Ԓ7iRb=h|evMNd>6/8ϴ9.dZYDJӒ6-Ѭb~T5r~0-iM@gY |8T9)_ 4vѿnjK|z;j;p:.|C5uf:4Ey('EY!WNnofgY^|5:y3/'" \.]wn\\t!~6"2-F(d�79^2}f@dg05HpoL:o6ϯG F4sSdiY*Erx@cPĝ۹g*DByyy0.yŊЪH79Y&z!:Rl?A1 wo'%1yx:J-vۭ]_\\5@fd#M :8ތEh-((6tr3TdGv)sd0ߪ_;�M`8/ol:@`k !ע^3ߍ"Sw8qX utNQ\_7}d:nnoo%V҅"4M/rW#4'h9OPk.v9hS^!ið |+A("f_nW_̒bWT,PYm@iT;OS}VTB]k6L 'Qxin2ⶳ ft< -t\xōʻԵMƓiaY#^[G@ d6đ܍iYB&v}`g縹ĚddīO�Ӝb 'e E:l6: }!a>;mTMww7l>N\'=ǣX{{v{M9j2  MyUf]RRL緷w4?lYa?qYjȄjc5y1]z4> ӼN3c'}׏z'kSأPt/-&3(@J"<Qi:Xah^6'jfQg bȇ)�di@/2 ,'*4N: -&<@=u?H/x<"DOf$ <"C\Q< +ҽ>.ÛNEd*sV.xO 77’'[ہ�4�Z레)BT@LȢ@$gPD= }-Jxj"+x* @/ppY?<oт얥+"|RY ȗ"Bww*24+طػ6#_'XN,˒I //h,x̜-MO> <@^-^qZܼ]>Y]x me<DDf1q靶M|y9Rx n^|-bgvpSd >t vDzpceN4`ԋOvyqt?jiߐ}m9Lձmm-v}%Mr]U0zOH" $>aRv=ݞeFgkvL$ˎ] ^|odүmȆ  M_IFܫGܪ~zǡXۛT EwD-w>4Xh}${gFG 0ҹb{.SN: C2?qFFea9gg *<]|`0v1C1 T Mv?B],?(u^ҁv"wX~z^ɅBfӆnb변=7~}~ 9I髧W!Op n$/t{r&>zA􏩳4Gg̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƿviٶm9B6Fc-KfC\׶-SMt c0Q\P&>c#66EIw~nK7[t<߳-e0dAqsR!~պ2F2 N$y=cllr(:0'$U]Ӏ1+),K( <\7OlDI%H0HxJ,t <m{shK @w[Q?4eUEU52YQ$ a)cpa<$۲<uw{}}Zo%gkMِ%YU%7nX6g8dON޽ga2LT]67w:?˲"+twBj]TU7tcS7$I^AY%` }znerYUYlUӤ z)h<ђ[YU_9|4ovu}q�yR\hw=WEyf%HzFi0خ=Bĕ*K:F)de0!]T᧮벐#ǔgjWkQ,{*{ٳ 'k� 덬#A0{S3)s Kf؆z܊ۮHԾIW0fiI[ܲ}v˽({=<�|B{c+F"SEB-(mfѤ~bm>ҪʩY&DESr\+eB|t#ujco"$ݬTS7Me<*}[dl<&eҎuӈ8#ͦ\ DiGQiQh,B f!D6t#-Zmɓox1m{~ˆ|Gri0j?BY.&>8 PhPuUh-is`]5f;,mm0EiJL-(Ǔ$aD01}n[&%g.;NBY7?l ahAi&I/lW G1\r сXOjPC`Dȥ‚(I#d+w7ky7 }S4;iRlYTN)kSJ-"k YCp9O�rkp^E8 XҨ<e'Y:~H~M^$ ȢMmx ?%F zq5&ں9HZ!k"lKx<û{4< ]!d.8,@ȞL,�^QDh\bAiV4Mu8eQj<"r:>ޝЖ[dY^ڛfO L #,lBE ~ߕܳi0i|MԄzDx@Ot>?qd}I2t:mP&yQҔںhﻶ -e)hu+qw Qa}>gxS=uƧCm8v@5/e#hÈn##D%4|4LLY �_<C2-t;4nXfN"ESI=V%GC5X�9NXD|6"Vo5Ab dd҇QmYZVqt?iiW ĞJc-<T03MNR$0iq�pU݉C$0"c @: Qpy9V$+cd)v|c̹QmדNR4l8ON<2^x=7<!lAr"b5Ew#+1'(uE -ȆPN \V6tu R/ ?7Mk $nzǦ; /vPn &iAf,sU- @8 (M4 aG:2ORѤQU,۪?#A|K gRiT^v ?4EinP( /J1'v8!1* c&Ji0h {6]É~'!m^$IV5{a} "tA%FvtTvTu~%O$%."ǥ)iMdBWc^ =5YG-+# wQ,&GB&4m Ԇ"nV-$,@5YY(l57"xM_ 뭆(m O_E%@0[cfP7hyIBKq t2i6KvB$.ǛdlٙK-ӡ),O%˼ 9#Bm(0~�Is uUĠ1Q@Fe>R;i݉遷i$4l?N &kPT:Q(k82ov!%(^qhc2 -+ GU�?wk 4Ά,,)( & :bݍPKH뛵77M?t@NDqQFQT7প]ou*0"H(i :&kӶkсu1mq}jN>qO) ̵P&z>o,B3HfAAI1h0h0j5A!Z%s=@j tl>G,r<,S'Oduت<3(H2(HN<6i X"ΰT_7aU}J"9GKcV8b;~)AZq37Ùx%YHx<uQׂivkg8\ }@q( Vt Z-iBBb4qtv`ˎ/U홪-gL瑃 ]FU A/3O$fDÕTaU<VJl'Q&e7LaՔ)[lMaɊ[k q<&#J/mS֞;3Nhw 4 ]g B Z!u[G[ė\clq͑Q08o]aFyy=HAنԵ Z4v2Yʃ8SAvZpzd6+Vl4 MށE4!ur>0=;pؑ  30(HѠ9!׏I拫H(zupU{OEԧf"ASm!(ݩ>#D. |"D ,pW߽͟ F4&DkD}Qay*^k <e I%y6J0neVv:}W^|_=^(QhHM>@kKTZt`ʍuEєZ^-ֺ/; :qMŶ.Ϟ_</�^<U6M4olAhG,\9Y ^Jƣ̱R.ovAP1JhEWUO_|^\u[<fOJ(vO<6ay,SuHVyųϞ0@ ĵI?iUsF\I>Ed"e3+hqi7ϡ/.=ŗ7I6-HuŒMUجk_dE^v-"c4Ksx4oԲHNeZ(_|R=`68Kʬ�ESՠϡ77o/^ՒUeޒt1`(=5YI?u_C9w\﷜b$ b{b*Tu2S ܲ M׳@>nhA}UcIq޼W5B#wm͙ 8";lKM�q}} َ%6-R*UĢLOwOwo39az#Ln ҬP]ԙlCFvy#@ӃMLAq$=6N-YBLMpo C%[ln&Dc8n7$IR̐ = kGf6Y[7g~B&|}YR"o&Lx qM.(*6&0Piw<LBQx*po9}㡘 ;'>{yB#輭;/Mq8|C$v[/h}<:qSԩly-Ks98 ~!ğg`&agVMN”kFz4I')hDGhG_Pf͑FFLF_Z_m2C! ,hU]vhodjϓ\i\v4$,V:SQۗ~QH L+y ؉5g DF$ ~G~i9?1x+&˒ 7ߡ^Q/p 3W 3Xޭ6v!ovI61 ُڕfS4 =)\IAnDW$w={|{Ν;LՔl{_Wzۧ'oxsg7Yd~>ezݽ|h_$aaHsܑdTyנo~>FVo tQH/ Co~}ǯ/u,65)[u$O*˓ݽ{ /:ީ({^2>?oI0t`0[9~'O: LmcNQUIl._|~޽-Y%ts_^}G{1Ʉ>:MiW7` ~՛ÃF$5*1ꛧO ɰT+rgoZN #\;xhM[vv.ͥ,ցlbMj^a=7,ãɫJ~TI"MNVEE_{ΉFwjjrpuK[X=z3xgy M uяlF_=5΢QD5QGQ�U\ƛaXL|d\58뺖ϏΘh՝ϫ4l. &wpI{{l ''M^neC*B0Mc}elWbUO]5UEQtNET8 MaI?|rcl*v/l#X$Z l% <ǪDg` 0|:Tl@E fLkgOԆa>`~oMTU#V6ݛckzêA6]M6A^iJ?dwrT)'/ј&k~1'L&5dQ/K0KD4o 4]ϧqdV~LS ܃(UNxݩˏۚPҬ6+$asLF!|G7z=Xgia)s [(&:1(-*j9?O=1oO\Cj0l7IF-RwZaBJ?M MB;Nw<F.CZZ 1/T[X?j//+@.+RQ@(gEnb `n(tX|:={ {iP̫ЬeNU+o.Ӛ#,fEWk(,_.f1Uv%bj~gQ |:ƦMV1K[Ǐir|Xo]6.9`Z_,p:?]ͧETJ ] Ek˫wȳ7Z؁% `o?;+;Y]BWg3`ֺl6Tmd"jl1-_^=0@b(;(jDWzzcwNܼ4ぷp6{Dd;  zm:˦i+kîMlP,؛#u>?`LxYt` 7fӫj6Ei-DUNHw囹vg@h]N(MU]x4=<IzzrRDem  A�[2/:t5p̿XTP=LDytZr>A#� vaJ^]MqbL4Xv.ժ?Ƒ98j5A![ȫ X5En8X]9D#|vЩvSi R/gìQ>Y.`XM˦E5QotTbfbA<`ubVs\4f 38Lf0CfP2N.PalZ-'/F6lnVHݡAdЀbVZ u-"nr9m7̇qvv4=jL_+,4P <S؋/!v2O{Yw%4N_7BRz=pP7Mt0ETλ .bh|T_+ZGu.V5݌g�']h2MS) bw`Zd>#^OӜ$U&|9p+Z8"mQhlfl% Qh҇0P^j `vabҥDսO =NGZvp:8;:<<>5Ɓ\7O!+mN^Ŗh~5qd"-I-a:㣣6 gP'/CĖ bH<Bb#ʻ Ohɲ+S,ɺB^SӂR!HcmjFqC0AL}om'3 Ce ~{:5]v3LQ@ӄ8Ơ_݈?iݬW*2 4qij%{ ZKPUACnZx2jMi^9Nw8 -&s22~ m:x߂ibfw?[NKpN!Rv:A/匊 G1Nw6:G3$xGD):4-UbxBL+ <*AD1\7s0Jl>, Snan)6lܭ )FnWG@ô0ϱln ޒ~[Q,'8*ABq`j|5$ɭjihO/b b6/Vg4}#AUW'U޸'#gon]vMHhiu0[̛+{mda-B(i,A~>[r%J(QD%J(QD%J(QD%J(QD%J(QD%J(QD%J(QD%J(QD%J'Gӌy˶1WzkPLgzV ױ |#6#h5@8BPxIp,2ˤ:1 q}Ǧ_ }}&!<?=h" li m/mn?DK‘h(,]dtpmQ3n7mUH/(_\"󂬚c9n�"_2ETDce;ڹlK:\2\A.Jn/%0{eI6 h>{sqqױzLYVdyi~Hgl3TN7iȒjj sv̗rf^o: $ A`HffXTBk\~qrrrvQk+̲]=sneL@4q\#v:kzW4UәqP *v ,Mf�r� [+5U۴_ےк8u$j:./JcbZ%h !iz@]hĹۦi2ǾXI4,_Gm&E)Ț&/ 4 ]7mN1`r<G´EW9�8p6(l^5N6MQw-v=P*i &C0{S8^ב Ш6c;pp.`@jpߒf*M^&.3HAc14#[ B)S$ I 'p,nUx@ a`7;m5Ќ{T nMА_ #DUuX:�l7q7$#݈NF#[a u79l$ݼ}-ʐ $2## Hэ0΄V ,j~XD߱fq<TKהs˹�1|urppWsureThAg*rᾣ#|*h揆t!E8`AmXcMw"I8 6~?[S! 80k&RML{.1wAq g1]ib0.c?XE"9 iVJr׸^7ыS#?84kK<u3[Y "񤩻IލOlfU47 Y:XO\KRIQ+Dh*/ofKZ7 oںnf8v𰡹~y$42Qi z2 {p;k:$I^ՙ*2$qm v[ =NrkdG̴< K8�եP ̘ݎ膓hڈm}fv54mwMKivl?kt4 :;X*IiT4^i*]O7tVin0Ò"$bU^Wv=< mi-nȲHr 4ߐƐ/8YREh,p6dMr-4EBE%Y[ox ۶L>i`]+8CxA$27݆.xEz8gOY Ua( 0$DR4۪:yq$GYV0զ <F~�ZE봸#Os=S/)b"Df ̈́ɋRd`HX0"d2(}؁Y@#\4Qh6խ啖-xnS$,0ڡd)072M< C/ +?8Yހ@aT"u]D 5`jě HA,)Mbʇ,BKLkX` 5DAɷ}x֠)pT '` Ep =Tzb]ld7uB A#±AC.w$ cXBlD"Eg>>6MQqwkIQ6-0Pԅ� z6~No13":XP$n֖ 1RcUc'y]nTE^ hA].%`T >lv 2 :yL!$Ǹ�v�E7%zYVĔq<!;?e3^PȒmu:#O5zSZ򽰨mrȄԻYB%J3ٱ +&4XQQWme>n. >̈́3-e\i$@ 8j)DGݲ'(3<GC ̶ )V4gIR $> Gs(0dűs)LxNX'؞l_9I Z-17Liq PI`dV=ZQUߋԷ,Q!ej IQoNv5Ae>Z(UGKx7%JyئQ;X\JEu({}RU(cC+3a\iLOa[T`?fʐ9ykҠ4SqM\5U? E6]OW\\YTAfc;^R4;1C(7{W+797G}қ4}˳m"NyJ=]}tDY% #ᩪ$g aG܁:,RBUןF4DRO?rY$ *MӠG܄cϸlZZ/ifہm7LDI^nּ%@W L[\M-6=~8< .C۾F3#=kf_OԲvLK[mpX@USvlm Z(L =IL']i<Qqpnw$VcisBZ̙ ПDI Zay2s_Vww3EM/' y1qѪh/ }H s1Q<~ z8OFRg&C RYOjMKePFӥu&A?b3!k1~櫥ꄮ$i&bǂ49Z A&[EXUw3=]q=_ȃˬ�NnK`LHI-&{qʗ khRa1;l ݛ= 203o={T&it"\_ECd$RI sl ~%@W%H8r;+)Ҭ?xfievm}m%>tOZjdcI D¬@OC][f%\:8-U$@k3ԩ@xm 6ӧ囮( Kni.-oͧOūgWaYW9kZLC”f9ąILjzw;\57�R6Ϧ5tn߼~}rttt؋h ?%ȏ ,G_tnV+|iaz~e:~~>Z*B ϏOON^ ]1n*K y1ƒy7p6t< 5<Z2 4^Q ًgGa>>:@ aym�wI A5o慨oqv.M,i QsPQ$2} >:<9|IhSQƓFBCg9M8hOnٜn$`Nъ "q2yyt A>D., V-'1NX2s<Lo (yFY bNE,Rv xD/M !';l' C}[sf馁5[7Q!r:<7oXTWMy2d`oy/M'%Mg[QN"i/'B�!/!h?/$Luf44ᛪatbtE:^piiy%IV洐PvE*Mi8"SԵ9WZtC>CvOla Q>*ZЌEPrbwځg:30l/<-t<E&$" ,V1#/:;qLV,yIV߄=U <9Zx2\ۄ&1X88Ә{fV&<KEI[kUw(Ku]&)~ iɏhAh e12oͅl;94(^ <J aɔ[2tպ ?Ttd80#P/2mӾ??noU95$6="^&nѻ_ &G�UMI^2 h~);M[zhfGf9 <>0iiZGc_RHFwsJ'EGCAw7m#9FPJc'K͞am(HB5p>}GK.LTMn<430β҃V" ~4?l[]ڎ~pa/^,?7ZP]vt3]jiR I???=;9~~vիWSEUB=N?_'lvn[:&D|` dϟ=?isRfNzzmӞki2yw,謨oNOÓ]�[WW|oxv<?t֛-dMSuM==9:VOR!(?Rj NN^>?{L5,?5] wc_ݭh켢H}}p))ѽChzW</mSIZ,sןNO_xXec|`r87m^͌�2 yxw<NnҒ E*KRҮ_<qqٟxQX"6v&kj%}e L78v;/uq;gwC?V)힠`g$ (,S_aWoϯ+i+ U4JW˜eZW骡z8L* e[2 <mӔnz( ) j*Qu )ei\h?]\^O嵲 U#df w-Ɋ-_ GYmأw2ao3em-\iMߎ-zmm@~ʒ}Tmqs~!:FԸ tzfi:^R5*rXʳt3G[̘+QnH9l/D <q*UoMLlسx L&x Tf#C-iz9‹x[d?|տ <|3산LƵ٢ �xƔD"Q ^fvwsb MQ Njm]꨷oƷw.RU;!y?|G+kE.9,[OQ}G% o"z90J l } 8dvkR?݋Mh,H֧Dbs:: RXN&tLMu Ť=!s)+w|/G x/~\ɛ:!d#larN4jsxi-8n/tDח!vg^oӫxͻ%xrP:6#VCh4(}V0|4iT+r*|B,V8zt.\^`;DY4W!'S .>Gܮ᰻3\e7YC D7#B/av ie,3I}tl]{9~Xj͟%<"^x:t) H>MsJLmG_h6 iDd'j.5Y" 4uޜ޿?nf; @-P[EW9 -ID5c&̶ U , {"ElEJnw:o ] '2ǻ?--QㇻeCRMþ ~?*xڄSwϻi<*f DZh \~ͨ<$FqWq}PGz/?H2p]^ʪ}+ݝ3'3bO$LJ(у47 T,�x`r>v:>B-p,˅ ;,wu]p]s&6$ (b4[[U,= *<BPp;˙$MdHBvߴD5@frNZ-Utt:])0BIƳ18 "K|`zݫ9Gt]#|XPoH]54 *Jw7"}S<n>/oQUBT )MU2]oۄ˥AxsL$['V�߷BQ_}7/#_ue-бxvu}fj[<M8l#r$pc8TXyx^ԚOf%Q SS ΋ *+!e)u1zxb ?$ONP[}Y%i@He|ZY7MFYUyh* c"xަǽ�l-lWy0LlPnP@9~].5þZJt$Ly:WMH KGZ?jOy,]xI3ia"+\m�PBat@�?_5Yv8`f?au B:'Xci]"vC4R{[`/Cպ v. N `+A-<xw~%`;,wxAT3!Nˉ-#QSs["3kIjlSI:!_Y6M.,AJN' X*-'kWAt>Y|ٴIp~U #t7TK@'[-vQw~bn߆zOxcTtfiVum%i3i&V"f/?wmdz2txtvqy�s^h^vM&MC'OobUSg9ć\R7ƄǮi@i!jbRVﺼܟ-a(5 Kuz6]Йg+OW;EqµFinP404/~G PEQxt\w^0C5ˮ?n"S|7UXPLoo.<}W#2rglܨ(m9~{gta;UU=?0xzBm;/B/A6E&_Vj2IweI21)uܙ2 {8VHó/ーΔA~W8 ^_2` 0` 0` 0` 0` 0` 0` 0` 0`!M]/,/:3K08= nNgһ>/[ihPljmyá~<<r"bhPv.nꚦ(>q藂lf?Q%/ar$S$w<[O粩Lq f<<d549 8KMc.5~i:\x5`a}|2Oex/`.{\iS]<IυWq0C)uKW3 ĸG JK}Nf*$+Kw7wf{"-Ud4Xsty*faƀ s_<>K.'tZ3x"awt= Ǜ4 #MB\$HTÍK3̉{`b@x$nC\\?=x<|b(jX X@6H]WeBEc}Arv+) |NIM8MÐ㎊/8/8G3ôM!2WD De qoa{1V�TO T'sa$ 100:qA/\ǹ}!E={j3OuմlC7@qEI{\1){_r0 MSQ(|σQIn4x _CM z!Ru0AfH,R5qmaF8R>aY^NCy ~>!3hVJ3si0lM�#-2y4nF]"4M8B:!%͸9ɊXK)  a8c<ѦB\ 3 _9>ndQY̰q�+d͸~,7tU �|(!ABG ( (a@8=ܵ:FE!<%d>^.TJ 6e14ew:m8M(Ycd1 CvpĺYQ"6$IҦnT:Uݮ~jW&I$jL p#H Bp0$CJq< oH&e44)nݮ㲹~wiV⺩�`B "!.>U];\Aj>k~٬;\s[]yt*`߷ 軉C׃y͑&JPxI?Ͳ5m4eE3׶i2](@yvYDByH7~krmY |Y\G`!py m^Ǧ%iYmBLT2_ IR]2KxTdiRîMx8>Jk MW7'B|-pr/ .@\WWt6_L^Y5U{d(qsOdq, CDa2Ⱥp--n=8T׭.ү.a Aq[3M`ڳIt7wzoU&>$RsiFqhJxDJ�jwV[ vծ؞@Ki"/ܷUup\jB 'IoC9㌔y p nuy_%.vmWXM�dÐ'\zs-r ,B}ϠӞ1t rUF ́KBd+/7fݠ)08IӼ,jT|[A Y+Ա4,_g׷E{_`v^֚K \Ch&\YZ\w"2-$;#?guqiKmB(pWSttU&\ U JC<(ˣSU�pWj .'ge@ai^_" uPmh%ӉW  8cWBZ$@ݸ,}b2WY"C *o/%I\DݵLRG "j]*HKLЦHcߵY)@qCkj}А !M1čM"Hb!W$;0!pk<<]isȒԯ؍a,:mݢ$(&A} x,h^!a.2шVƄ۝X+: j0 nʀBt#쐠nڦ;M(:}V *9M"b@@g r_tbjښniEKƖFK> ʁGeھeʺdyq:<t=J[c:Lw9'^-s=%~K Ijj0 C!I{*6~?- p1ÏāαiUTłLJ-t'x_䪒D-`x`h`4,QښZ9- \E=-ŌΠCjQv:x6G#3�B$#lUqS5 ՑhNR(rEBjPش t7ijՙ*Y숳L?B|‹<_4'|1=QXNNQ#GesfQcCӜT֌J:!L -S41ȲGjQUA`;M0d�)H:_B14N]:I:Jvԭ֫Mɧ3\ӫU*[`"KS$4VW3Gcޯ>U1 MC4(`C65J[ [a?L$1{Av-yµ7W畁@vAv |%qm5 =w$Ł~J"&y`JL* Ԃi:n.xiY?l\YQ%UmTOTtx:zLef`鼆2:-|L6}Z8x(v vXISD=W )kj'Nfo`g׫ 7i m 2m ҇!mx\ϊn`Ɋe�^P+Ki4RJ3ăDYF0PQ,T "rQuLQ]c+-H*m12Ył fEA9AzQY14PvxYՆ [(0W\Y٦I`GrU / =o*:!A32dv9 }|RZ9UŒ8-ϒ4F55Ѕ^U|^bz^FZNuWAژ�5$^9D4|i8D QxR. }*H'3b3dǫV1# quT]u߂)ZHmL!1ҸzON\V}ES؛41�wbr jD0?tC:) 3S )f7n"Ap5FY5z^7^UN3lEbw@Z~tFhˊ#I!(4LPot2Jr0}k(g'WJeos+tGђcIROm1%2JIݣ?Bys�&/V@O'�t:+RLY8PF{cY׺}s�ueFq4$NO6-}�M!ӂ`=/ID\B{gpZwCR凫C_ɁzA=ӷ o~ h( Ì,/d GAak6*Lkpu4pi`J%< ̬O3Ҽy'>�"*㼈tL?/ ZS8@mLF(PyYpAyue= l9 w-5Q%cvVJKB<jw L#bn'Hp+Hsg|9v9rbx|ƿ9F@5ZW5d0]0ލDM s,sBv E0\a%T j?~p_p.*:d`QZdHvJkO]m["D8E [JS[UASvrx'X,~Q4-&_ES]QIy-LfZgCC`$='ռ1:Qb۴8JP4UyI~uF7jTzZ'UA{$Q Z@N夨>CGM�S ^KdRo7AQS& *IeɹL!5޴ ~ 6=P #Vj" 5}~ dӊl[踂hk+?vG$3fobJ.H|P0AIHuQvgb>Q/z2g jg(H(&I <3IF_,g]K [Y#B!/?J;:q3|$C/gs=4z?n `pIeeߊ7YJ<c6ck?F2f?)9Hee$H=-<f|dr*B HcUMe)hǴ#2!!]PV&mC &MHG@snftYH;h>GLaO9=?=8<>kZf JiM)H&ө;lm~rttzYm<ϱfk:>EhNtR $f*2&+nW;{;G'xGȦֈEI=\iF"-Eg:_E\@nn\W~>wptzvrf;!ώ]8O;ǷC^7ED[?\i;5VTdG!9Y*IFHto8|pttxVyYh%0!>.hA7Mݔe rvvYT,/**7FrR BYDPi]l͓;_OΎH֬d)"aEǎw|W,/ <׵un0fA56jniխڴS2)FI8E/׋ӛuƒ䅣,! "#ο dDM]rC㇌ j^؆z^k?릤i3BF)yX ȔMz'F^DY, &tO4rm0,KeL9,,jɉC4:ƴ1ɛCԾ;ި6g_n*-NDtLy㑠*h~XnX^E9d".u4EUnZͦJPɋ7s^JnYRD}}zV,Lg,{Pnjq@( `xto9n<{z^NB6tdTH멋f|[o]f:>)Y™�<M {yvyY85VÕpnK|[:SQ6~,̵kY1Ueiz3Zz'$ .e^b % aD:$_.1{W"wPIy/_,N<uE#Twwv韌y8NqB]L88:_^<"PX2'/Oi9m]'tX~{.]F7gHX@۳yK ݝM䦡$0}N??/r8|Q//ReQ$IQK _vȣ9*}9_v6N%B|�('35 ɡ9ղ_fc 'c _W?eaP_W^O7+#Vd~\IxBkkS{W;Dd.y Qe[>f* cR] 3`Fu{7TcYOO=?%7rjضZ! fЙջ$zY*UAzo]Nί7W7ՍVѣ b 9oOw[ '*TYۻ`r>_=?S*P VuK_7F9 .H |`EO}Ez]1o4%zF8A?{~A误P!h |u[F TtmÊ({23Ēy5=,Kv1UVb!0շ_^1^}[ARCCeНnQب(+Y_>=?Cp,4$!mx a`>!/OµrN7 }ֻfgdan+!0.|}PchE()<ǧoLHj e>oFZM֏tw%<n[IZew`&s$tRw|ORwJvı5`7 YM_qiN&~"s&\!DՁ�arj&wY͙jt=}gntz8<fI!E3QΡcqwz~ <w1s\F!Zɇ^Wx z93`ָG(�NE2\!(Q }KFl @X6<=G^ertbG"L3N{ ( �4B-<,m4Ho%]^"t Pkixk-ط(MQ`C!l}McF^˱|]yD<4kOOxͿ %T Rz~@9 FxXR =}[s6^6MT{͢;>=|}l .Hl|2?y:gOmWDuh./7t+BeᷟUe燒#dy}<dԫkL._z3laߥЃ<oܼz1wLQ}TzHAG4rG,BC7o7KOz{zDs*yo }u{rl{2kQLJMyR5atN'7M&EUIrŒ*#}'84 Hŷ/omW$8qI{~ TrsWHy~f)U ŋ'#�mA9G~1%p]<<kx[ItT1D`|ha'H覶\,tӗ5RaӶM2ۢ(x?u1"lZcñ]XDYTއ#j8%ZNA H6C)sӛO]h!PBPǮoj!t?,D!TūG(:#? ߾ԅo>">Psd1ۢ"ͲչBX%K>uc9tnm<} 6D3,=8aGx&Z\|:<b1L ۢhpms Qovw$xh8 TZQ#wB`WXҝ]l^'qQW=ҧCY[tosz5* m4|Od9BY7]bޠpCc0GE#'DilTI(dwoYmUmtT"8btL"a#%$T^Oyٚ$v6n]q=s9sZ9Tz^~MI1& t}ԟ(?oϾG=TTyZA{ȣF@uBg|yx\UVRp 4 %v:*M|*6)~ڄ#J6@s"~�t3>gPS(c"ïm}A2iZ 0` 0` 0` 0` 0` 0` 0` 0` aY2=iκ8Ka޺J5rxQd[#!~+$g<`U,˧^{yr4tͰ>y) C#!|RkBW xF~yFݎCL n. ndq]sf/\<.Z6s1Ӗk.htqq3d+ʬłieRDy V3 L x ?sInmk~3x^s}3fʷt[(j9 WW3ުB Tax J $s0].$]0݊f,/_\Bsm njb*8Q.ȟNM9G�6]薩k۫SM7-X ;Zx"2~{JEp^Wq<(ksls9.MOHQ~gz",9d25dt52 WK&|q_HĂs[Xl0+ߕIS15*dy7 b ̙a*I@%*"Kp;!.\uĭJr_So_ͽ<Sr0l%Sa zVqge(,L|5=zn9 :4z!=a2<㙇w3Ya(h0$_jT%yA#*KD}64,A|g s-edY-榏Xv./RiA\4ǻa4ft4!0M2Ym*A2i'C<q} mLq.!iRIZ6!ff]SQ$l2gkTQ%3uj<J/~4,9fa_SkͺL |zg |]c;:8UsEi;Ӆm4z!oJSn =ow۶nWfw|xد({JiE zWlq L8Y$)8AK <Xܞ2lDzkQ~UӖiVU=N&ǿ6;[`4="?ό.SS۪ #<.:<5&c,:[XX*UYmN2Mg_4`qU$2|kCIMEc#lC& jݬ Keʊȏhyw<4)_g5L06"<)㢡 eU ݭϳ׸bnT`L5Pvۦ(J$F$|*~[H^Y"cxF#F~tW+h/+@Ҹ̶Pk[d趔w$f@*RI0Qy"F)t4چ:d4U-Ȳq4:grrODԴu%֥b!'ւp9 0V%r*T4)HH>uni.G2xg[$[\_Ok A 0I@b[p~쨟gPMtR@]:"6mD5*N9O@[]\,V]-~Iz^c.vm t.)k[}Wy)< Bl:-Ԡ݌u7ɦJ){"+eHDܔ;T,0rP(C]ͮ˲ < ^@!jԬiRQk&M۶ݮM} H~ 4(ou7(Rw|ob&RYݔU] )� Y̰Pjb@]E&g +-2z4Ȫ_WDhGQ4K36ڽ_ 0U]ڢF mfqjM|h9La-QG1moF<pEoPUo/J|j+RB剺 # ];3()n(zwJg䙶d!FPy #ā,"؋)sCb#z(̍$PRA٦Z-,^aH!@Hz%nݶ0m8HUY>K"WjTn*Q‘YQ�" ̡4V4ټ"Qnib8 Ag1$Ei,*@SOc )dYٺgA`6n XGTL |y( )* 1f\+eR+o:1M>`<O#a:AphcQy�E#iM\Ea*95 {vөE8#t2]窈͝S]% 2؈yS Tirzb1AF8CU!Cċ\rQ{:Be4V BBI{K'P1 FYbT9 9<G؁=A檪<[iE5QR9U#5F ܙ9(0_-?dB+h; $n1$I[꯫37qɴ(=ld[M蛆@g|سq&CYxLgi,lWe,wcP "ċRIZ_O*G"~_hu&m/͛k&qP ̈�8"D zO3HՈe7}o:ͮԵ?k\ysW )o|]qzzjyqqG@5 ^qOhRr|oRsTx2?4)J"ڴ dE/KʪlaIӱ#zڬvXtrD1xP4lP[-Ҿ_Ww ?)կpkBIPgS.4е f:>;޳C(95Br {z ̞Y!]D5UݺU_(YE TuMYlCns^o: Q҄xI]\4.+mܔH|v=%ʊyAf^&*vhM hVEu;:* ]S0]K7J㕧T� [9<;y{>I9�<3TY/0urz`s5nuQK^jP(,bLi9B1?}: fK0<֓7HLP9ki+;k"lEmQ�aD| +rcJ)OP8zuRU:"5+k?yH$ZYTh{&W7QZH-I^bl�b:BըV;0(O.<ՕJtUn0|&AH0Cfm\m"N ˷� ǣP1f#ʳNc*Zn7'œݽw;+:n< x(ZhMwT_yY$JUo -q@i*�.vmÇ͝k+A7(^]׏plhUrE/%zYԴ˲0(G8I❾յշo߮]=*ɳaADEIӳkZYoPlw Bc9rs8NQq\Y!W74X K PެY4@w/+_ h^ q[z4y7͋bvʛ7++Xyى@H45CmKCwh li87u9NP|eiaj퓕ߒޫ8h4O'VE2 "Ϯ,= &AdǞTk叽O}ڥJPЀC:oã#Ӑ[mw} ~yQ/H{4/ 4ՊIt!i7^][yYKJEG4@i몭Z{;mcJˢz 1˺IY=Z[y~$"8<۔X(uꨦ{"gfgj^ؽ \$#WɄFrhs nDCc:~`>TMGZȐ\::RUVFQMuB=0b%+='IiM 6F:oǖa]_lҿ. r+sd-6q DX7ucTqR(-}3JQ(0ERT~Mc X~o4�8> n"LB8]ZE%زc7,+Nc:/3#M8^L+Q0u`Hm@ED`^%:69d;N3|m`bL}@]84d8ji4o %( l)[¶Uuy9)H�0z SZcB2eUHPׅSUM>ӧ57w$>Z˱x5 <^u_VjE!}!Y/6@4vkWMR+"PKP &i Mk-KsaaWۺ*WDrZ K3#q(Wao.ǿE~//^{$dh]Ow ^Wp(^w0"p"S4a۽$ yeO>�| Q`OjZozkw'#X/wcDiw`Vޭ8:,V[v_%* F;ßks2|M.G^^}Lg.B5c>movQ_:, kZxׇ;{?m???~Q#W[OWj)&a�wu($0OomlTV7v/Ɋ|`eY%Rm6W~y[UEZsWzL_"'] >@&wޯmvv'eNUw5S;Y]۫/ehf~tpvyQDvAN(RvviC)CZiG||W{tl˂"Q/d*)WϚ% ɲnu5H|D |[Sy~t~Y4"'.z( A6'6 \<}qwNST?eݑPʨ (麖h\l/ {O{R WTIh_c\UIiL/&S;n<=ΉȰ GµXEuYV%7EnrZ]Q:e R6~קy]paIY?1ʏ9pw KV`Ғ 7LhIҵҌ(ӆfgTQrAhX>,_^_ηL<1wPtuՍ͏' h 2U5WQUE.Az/$ 'w~ڦ%ñeo8E"Ӻ>??޸p}̟p+fOk[I El03dx{| _^UeV1 t?fe|Q${�5Y씛 ޿Z.0a3$u%A_tA$۪a`*b q؛񾹿SKFja?SŦ"[$%Uc M<3My{ovxفʥRU7A0}Cڢd2̧_\Hc'Hw^`[*Nʢjfih�ۼrtO[[x(<oq}?Л[k;Ӽ,um'w;l-^T^xa6}Ƕ"*^L籩,#u 57ECG ӳkB*RZ A>Avc_6A7{0Ʃ3ˆEyf!kW'mo>;y\}tV(ޯon_uYSyVP?f 61K<˶, hy4a 蔅̷[f HZO7m|؂*ll}\Yt>uej&%|[|ԣnon琍ImFֈ+H >ߴv]}V(m6V߮aYt:5o0LnImćNG[/ mCl/ong퓷(; t2 M z|o]Ke^{l#;p@W՛>L]k0+| ySд<8wOjiW/WkRԆ+l?.+bKU)=ߎD{; tm!3/|O@hOqEE3ϟ'7;2m7TFxyqg{nQPْl81u;5ҨLcqCyl"malUuYS*W,}quyvzv| ?X,]]+k^P, &`~#<R<\(eMA?TMyZ|cLTz''gg'ǧڅy. "nYN Frw?d/WZCtXȠ߂EϹ?u|GWV`M'GgJ?~:8;/AUǣ~6L| /07lNYe24`uo?n0s*_x;O{AS;?/35p0\8K\ x94Ħm0Rڐ ox";^HLQo=yݝmfppP,:+M+ABoww]Cj˕iڦݬ%x{{@ NYgg'V Sp!VOk^N4oSn3<@Tl'R>S,H{Ļۻh[q]i'/9]>X_KVb ( &Bn~GjE<xMd^כ_ygfVʍ `I({?wőkdYC_֊٘qǶϏx~,uUm<ӪF(3iUi`<S(*֑_ޏ옠y2XHdw`!AUVf^x,4; _S7AJtU`KDEݍFpI?M�2wcZE+7nxid+_=&n+'WYvoNgPu3e7pdrw?GVtgog=߀+ ORE?}ZKt~ 6v8Ъ6,./_>OAtDrʹQ̧s ^kJ}]E4^eq_o<)4kgGuA]D8f`?yBgu:(͡ zȡвLRt:$ |k0l :ge)ԫgtN矧[׋]s!Pr9aEMvvpw;CS%..o/NjJ^.Vx/ϟ|Q Hͦ|[~ĥ,'Tqp&RUQ*۲(|Gvm{q^)\EiNWDrt2߁Lc{Ag?Y:뻾Q0;,mRDtAt]iXhs2 N4' _~n%�d1$tJ7^l T"S6x/A` U]gQ:ɋ�R7sfx t^k8j\{~o/6 (weZ])c$aD0”VY,?1>!] &ҿ3?(Z8ǻ{W(\mq[7Eu{c!vġ%WᄑT,<cBM3Mofȏ3OUըҟI~O@-z8MvuWvm(jp-?o/>{AVhm؃jȢ/`7j-TxPv} wϔ^;h0F>?FT.uhU.ЕQi*=Z4?v7B;~śo ݰ" CkHAxuA2 ܣZʸjca;ן+lF&]딡_y+ mYJ\W�(<Ka^fG 6�Qy]Yh_z�sc ܧ WP"V2750jEa٥?<{<,%TvNc^M'q{Ύ _?\q%q2..ކy#ZWT^R,e)KYR#%?~k,e)KYR,e)KYR,e)KYR,e)KYR,e)KYR,e)KYR,e)4h_ UEd~`I]-SWA,t5ݰlC:MIJ\nYmbZϯay.Z4ET*uVTò7Vo7|ބh<&jIW[Ʒl-ζC~aH<ۮW '-ٴm?4]`t[1[dESzb$2Im^<,6ن*K2_._y8,=nƧ[+喤ۮOF+Nƒ)UDJ\UJզ +f.Mg7fE lS8;: W6 _plSiuU%ªrlbu3uXt *2{۬U|}' ﬗ+(%D3]_4 �t :MW^RöMzL5mKa[prAx^F:)#/i,0rGRu81 UųqDd] ۮK!'eQARW 7)T?ERUf (Wqi0tE7tumvӠk�pM<oYiVZbn9~`女+,Hj9APitX4;\t/Vt1ȕ[5A,7;M9vـOQ?RU_mp0+QK;@˦z~""p‡ Eønƣ~?Ǔt4aOWyF5^ C$E8 򃸎mНD L/ m#ç/T]cGQ˥ tGgG#dzx<Jiw/vuWWnE 0L8#EyTv] A醁ӊ|,;=M^1C07OF6(ŷxIP-/㌆Ҡ>MN`8=Wt]LH ( `}h !Ћg"c‹f e5E58Gpјf!cUG.]O�Έ~2"n6Xq%<yOin* pd˧X2 e0z~䚆dnC]D}ZáË)x: {@F_)q솠}4Lt46b6 M/EfJbY(u8 {MѨ$i!<^y9p$i07vPcH*|1".֚$ZFU_4nDQy9 D0!%0JBaSq(Y7 $k)cYH)V"kx;H[ьBT|q:sߑ,4`u ~kQ�=`}.OjPqǽ4unkvHU\G{% "넁ؒady%b/Rd<Z@Q!bS}s`<S.uTM8jHmZk2'1%6|`TE0=)4zXzGGf,4-V<@n4H# I ؇\7�[fҨ6~[y:!҂zzZE 0�boQhJQ֚JE2hs xi tI%s7I<a"["]E.Khƞ 0)y"i UQŴڜ @l6P{?)mIF͖yRa13`u/SmGU]tdD9rHcâV�tl4Ҭl<"K"!n%]KTjU=vS4�uii@CF [&wZ+t׽cӣ h/@j!édmMq;&u ʼ!eűi d {C^K\y�cE2A* ch=MF / DT,+muQsA=]`M +tSS ǖEQ4ɟA6$"2in/s-I`J*8 >Qgd#:ĭVEug1ŪZB,#聫zuQ»)@: A3A'P2nR&IEatv3Oz>`ݱ,We2gۉO HNj`aM+|].GoeOJM|&bia+-΁5h'-QPh/Y!rƦ%ImJA:1%OaSkԤ"P'd~x=^n0@M*Mh3:->O+eWiė0mԓ;` jWCT ECs&J[agnqTBa2MhpM@ch:<̑eU/XJ750ڲۖ,D>„@ GM"<xĦ&yNs&pӠ~-δT'T]\./WeeSr|Ӏ]l: Yp4DZF|p`O8gf& 6-k5oȱYÕJ~z˜o+ '-WXV4M0B P.^6dBk^H_PRzAP{4a[T$wlbГ%^4RCrX%xn؟ॹ zYJ7u~~Ѳ#dy$"MFd}"YxuF(5k*Tu*#*3NK, ~?M4%vwZmXDNj~٫AC&AhVNs--|k‚(bŸ)5@C9~oK)W=?j:xM+#(@M�5x CuPiE,oruvAܔAUg4*45{.~elF]8tűUzNj y7%3"ڧ^x6@I?tCuGiLSiS5ŬLQ0,E1Y#LKB}F#-VW՝j 5nE@aM9y"JhKo</":QWion~x֦yr㻕�M(=`Qh蠦 訲@ <+1MaWO/,j0]qIv8~tv5&A/&ޔw$G^7jF+5엊a@ddč(sB!P!+kk;{GuVG{{;kzPCAFh`ęVAVZ?7CM8�?PP?yWo/w6^]H_ƱAb0UtԮ$ |ԕλbR߰(I0OiPy2vymcggs}f w4g9!OY;Pls4m9M&<HǞ]q Ln@=cω G 5˒rt]_[x厘[sH4ljk:HNqQl~vp:).}zԔa I4rM?)MPrNQ|]5k)Q4`IJf=O75 e@g"6ӹ:k/Ix=>e0LBv43iQzPs;, co'Ib瑣kjH8͝v\o^^8U_�sZABSZfƾ g4Rx?OiJ3Q߬wZ#H7YY h qa�W:h\FϯuT BDY꜡ТKHX{ŋ?3('ԏ#;{=l"yR�zEIQk/HvE18>3S%>5W7E݉-e-ߢe PI2B0PSڋuXzm}ccF%H8M# > RҮfHg[*^YЉF4( U$BhUnmn�7{{BIF3L}P=7eNjGi@'z^߷ɻ͍W2NI{zPwQY\>NM4�dP+R(FijpaA *I?BJCQk, ź` V  i&3&0QhoL|8eג0ܭ#svd*v>"2%|?I2{I^&յOr¶pW ~2[?GA+¤<Mi`y44칪`J0:lk3:Z�KߠiK5>J`jƭ>tQmɌR=.RLN HhJ4fDĦ'eEk%wP-B^abfrJrtAB˯̷(S>@j_uߣis|ӨQu:e|Ww?e8GR^b}P$C'ٲ/vgC b*0=Hx8803Go>? .Ҩ.?{vҲ 6ԣ'Ni rS>Y~sPnv9i}'n\{{8zuj�>BdTR<)4~Wۇ Kw:'"߭޽9n]yuHy^ah`J8f 0ߖO߼Z~_Jzs߃}ВbCIyGG4GJ9&"T󃝭'ԃʲ*,s7k?+DfTElUNH$>J2=Z޿y}XmBӓ+ADnnݔ5҅v_*/& :D1ZP{^1;|9;T/yM-W[go;}=-.w߾hW4@ߪ(/.U5,)0aFd~~cqvꬢ^>HmY6P*YET-u9j` :exEtdUеtYd/NlMO ٹ ⅃e\Dۖ S]^7mKN7ܘF(ga-Űl�sSeYI~9"wOʧgJ#:^h�ڦWH?zIVxګsVp;iaiYz_k.u/thU@CWgUTL"PJ4@}"}8UͪV /_5<llCdOm\4۵wt"wz@� e^nl\~#cplCi^5F`v6νg2 &%o"'+t>uEfmId/O޾L4$C̔ aƿ^|r2 =4d#{$q_>RëV~p£[ǩj<[ P͆l:{bsM+ʳ!-W)a}J:rJF*ӕx z-PbKMgQZ h S9jxC# rb!"<7X;['Jd$O\]trSzҧ"ͳ~y2dE ­MQ󛁣*gXH3Ə;{U5&GK>ˁ%ūWۛ?]r3噣ld+fX  B~z{ m$]Sj-MC(͵E%u?j� VΠO:fAuQyI,zACG̿m O4 ]^I7iȲSە6]tvU>:8(N$#>xwrV! N&xF6IGl`~҂a[^4Xa yv*nBoUOw]W[N.*/_|]mKyHƴЦ,!~?44C7{lϋϟ?zk|QU B[NjPzͭ흝W;�͗ۇҵk2H&t$3*/n{03.:`f㐴p~7540$/G}v]zz!"p}퇗{Fibq=O5QЖ`qsel4Wi(]M<E1,P)Cn.]T ߛWztPz>_rCyg٠JLX馗-aO-zyvDqncsks}c jqYi\cT4ތ\JsWUnGeM֟sˢ .LJ{ԣ?m:^)~Uo/vvr[[~|nQ^\%T!/^OSSF<m STeZn#r$QfQãvptr|||tR\֪`vփeQ5-Y=iרZLU, ;NӧOM xz'YhVB }vr~`Re#+FkAv+l *=kњة๦~!7ȒМX( ]UӓU|zU%{ov:{xf CZ<ڢͧwLd(Or6kBӼ,B/ώ T6x_肃N35R6[]AXZ ) XBls;|B8>h hnVO)w47oO[<{v `L� 0@o\\Ժ儂٠ED nNaiت^u[[|ś݊Ξ_]oH㴗ezw@E(weyl+ (G Y&E@Ԣڨ]y(h+^ӕT47�7;z!(rK:=?#Z(U#bŴ#FcEVOeXZ;(˩zUW,-<н?s FTWëgOb wQN~Y T~O!+6;|06Jue( fb6CNy�b P}X?~t="3UG?9nP1UNҪO2N}[Xi zS[nҴcG@8�qiy_>?.Il:' 5 �9ou:SLJIYtPuit0Y x"G?]O,BQ-7n~hi,l?o4gxJTPl|-ġG)nǻgA1Ge=~ܢ#h#2fu*)N x 9-$)5%I5L6THߟ6!m_OR߶ H+Pn4Tv|8|x֋UHq(i ! g58Vۧ%Ai$]hvq>ʸ0|kk !M:{U!1갣}ujӡ-_~G[.dMC"$-=Ϗkx|!Hqgn2fuJIo8{p D$3L5{?-H*r Y O_?~3i&H洔m4N7Dй<gdWWk~y)jT%:'H~1?~T~Gr3%85!jg_iaS*WTO$O?ӟAX [t nno$?|f_NH OGH`דxvĻxZ*ڲ"_]/oޔJuQzڍ[:--Ʃ}=�|FR< I A CWGX F`W˛�yJuۥ*7o0&7!_cX5$'@#PwLd8 YK۩wK壟)_xZݱSjɚi%ńrr3ޱwl!/mid%IvqeVZ:?ߕ~ZzӳzME�̇!Qlls)Et:^:f>{i&?U׾8.\鿹^ܳWҁ;!UtzCZP_o4zjjӿCD:"+9-vߗ?~yU <B[#SD�;PʠWx7>-}x(͟:<y6y&B2uF{� ;(4_!_*ԾU-N4UUL'Y 3<o{uxT)]~�=WjteS}9�ҼbzY֎O+o~3WD/Ruw jvZt37/CzF3m˰ikNV|˃/_Yrxr/FR (|y? R8Tׯd,fi#[H7#| W"HV`%+YJVd%CޠF?g^_"Nd%+YJVd%+YJVd%+YJVd%+YJVd%+YJVd%+YJVd%+;"H"m΁]j}>JWw<EN1~~vonЙ-VTtS_z_"O&w%r[lskYQWe4u8tȴkMW$U*7eu}G10Ctt9-7uU'ԧ~)N|:TUj~*|qy`$=۶lKSz3<+@lSVj]ٰh _aE)=k[nM7 +E/B6dYQdj֫]4ߣSEr[gWCiZtod;%Q <_X}z̒i&3˓r4;p.б[ӂˣOTmC S*4ܮ(X!0$3X+ u`{1Llɺ:/+t$ku.;"�5Y LQZ&\ g(a8qsע37%YYY7OQ,:$\WjU|NU3L4G, \6gV+NFq =#'0&q͒2 %߬7d? \<ˏ^,7eaH TjMlqFaHm 7ťk+VO�R'vtqXg`2N<^Qg+KmA3\/I@ \צ.Nx�%Fm۾8”XT4$JSvqcH7K"I<M#[ێk(%v-�j`Dے /ԙyHmh".|<0�B툐=${Ye2/N&njTCMAtl՝ctW4/@X`@kS/LC&*y^gClWҝL.P& } $ T^2T^d#(!b�!5-EM*t`/ՎXoX,]`5 ( LGI 8lEwL7{rMS8Kיh<,r,)ώϢ S$7l8 χa$]ϖy0Оӈ+>5^!B},ދ<K8c (]FhQAUd# @OG'}_NOޛۧN izfᥩK(Ɋˎa{.* Qxv4Ȑ,%Ns|J@Q( |2$/)� p/@^KT]TUӉG~ fH<>Yq?e+\ohh:;tdHǵډTP>8Oܣ>O1hP2J>O[8$a֖*u/mEdLX <hgA`e#!46QOfI!i݀Ͱ?ށZـE�.Ix)Ǟ5[Kh W[Pw#!ukP\7\菘?]?v 92ϵfd:H(yQ0,:q:<f#`Uˌ C3zkٺ2[?X.jsg x p"aFҎ0F0,i⚦yeщR(t7 #(-6Eiip2e�uI,I;<|t<q l-hHf5+ȎM5}Ԯ绝DZ,Q(o8Ϧx!<u.+:J2Ն8_RӥgIMyN\m@B% w9)ۢ 3ѳ M\QE=jUeBE-Ud-[y(6 :QRq%R X(|~~%:@jptO'>h)@;LmZB6_]FgxްPD ^TyCpZC|ω HbzTХd:Ϩ㴏 na6bٲ,?-]k)~K3<n`mSSd#T�v�(fj` |H l*A$2@b>ɛm{rGvGqۑ5.[-ZEOeF&¿MA6g896 Ʈ*YQ=j;Mdv= $hkZQ-WY[`YWD&fGATp]Kԧ5 1w +(o2ܢ׹c{P0e۴;e0]fuycjfrl:AP[/'ǨɋApS*NZv%5(/,m*I2o,&vYg(b tܔF tPgA7EuZ  i(Vm1%Q5Ӓ)ƒH˙~:M @z WS5]GCd4D] #~X|3A/l%-ee Wh~D 0%NP O}o(Hi(F0S AŀGdA v*VkU=̂HoU%/^Vm-15ls曒ȅġͷTqzRtxx.j^bL`^�AR&ڨ:|1A-�J ICP{;2Ѹ a8L `Lc5Wb\rTtC8o+J:AA0`?oP^4FQ>Q̐nķemvZ]12kPkኑQSrt@>{)L#`ң^�xw~cw u ݵ7i)ܥdc0g]Wl4D:IƸPvh_+nP�F w"_,:zG}gs0vE HNcٴJa9?ǟ_eE4w/ICI h}%~t%$"%Dg}lb6ŕ-A<ss&xSwu6{[4 $Ga!�Yd~a'${wavm1pFyz8ml bK&vYo81,0#h|,Խ{߯=\[/_>Z{%(xᇸ3|z>gq ƅ86Jv;ŗ«f1պQih!0#qVr}m5ìxD-wGakcRug�]Ovv|m[e u\B)Jw>wlH@f\dy**GB{ltACz90Dlqx>p  Ͼ}dKcCUG J{]Kl:/w5ClmS]vGFynZV87"eV2}Ah6=G  7 0{iݴ;lfj(s<Þ/EaGz @Ga^M&Y% 5~mT]Vf*ʥB[&7!V3ExKaw2"K4`U;<G/zNd<[fЬUn7jұeͿtڝv03pЧTƾE h�ܿW 8\L:x b۞*Px/U Uzvtlnݮ'~tc(i4?kK7${&.$^4p<)AѮzojǕSl۪ihw8ܬWգ*]8kFmE ;biݧd2[;|vc`}pGO=˰~qej{jteJ+h% }]1dj#=|{ߓ/"lq'3z5\Q*cNr,b^wgo y8ւTq .z'O_ ד#vAh m/S,)%j^�<YFX6-b{zWFY*hȆP普祥# or I*N8\Ҡem4C)pnILmȚ'NEIzl{Tm-3*p\&4< in <bOڮ]'0dp@B1rP>%р&|Ol_c( #%"]3m)e\ I-H3l2LBBaUR? oXbϴd>ϖϞ(Z/@Ӱ ,3l6JP_-DpV1Gɢ\ۜQ؇44 11 QY5ٳ"Q p~c>1'ؔÌr% ZrҢ6ҥNyZvۅt\hԎ26\PhApGd!#nA#J'Nw*g2݀ ތbFoS>`HRa{{'i$|=^ SXχ,Ft07䗴FNA/<;b()Ժ}ԜLM{Wҫ믄U` KzSl M'uN?=i=%(뵽g_5%f$WzYz"6"cRfMYa-Fc^4h-nkbgoOyV`b(_8~h(h.!р{˴8Hh8Ń{aSwk??罝ڭ=( -S;g[njKna'81\ƻeA-C].Q#5";˭gzi~.zˉ<w;V w}W?wje=AI /֣0WadKc4NVJxӝWV]m{0ES>0jR%ܪbtPQeI.JJ(oi(;Jd+dq%Qz3)77?{pn)kuEzSTULS?M__ cTe $#.R)w^望2%7"EO ONX̴XEwHVGw/hFPHӖL/\.+g*lbM:jrR䠨A`1Y :EPGIrUy=Il79մ UQT3O@ZTZ fu/4@'OE`z~CkDF, G{ŏY[poA'AN-o1lN28@EWVLv$]Qr̖8irʇ/^1Ķ% "a^GCk<}/J]pMIEs41d G&N/31#ǭ.'JO/]Ը(TU Mg/R5jxbdi֞f'- 8x49XLP�Łc<^T]\<(|i2߬ l>PIi2y*5͋,=X_{TiI1? 4-NХ0nӬµbHK�IOf*1 ӂ/ DTj!p766嚨Ҟ#=ĈV(bSlܓĥ{Nh3Gb2 Ru+mE=GZ?3N: 2)<~f7r6픏YM-3Ftjprqq~z2MAZ|pɻ}q3$ ۖ,k "--,f;>}YT$݋ss7-T[&Ҕ4#[S8WIxq@;~t"NZ YhibRt'tUQ?,e ˯r9e)h$@dfIHVFrv2Ht`3NJ-_WXʹp0xo/R:FCۂ{J;>zDW=;8|٣KG܃RCP~ z2g'C]첊7HLHx~in2>9z<UG/G Q3(n7*hՋGk=~O�b#~; (A?'g$>xZ,f gH2,z.g1i=;["PeafR\@5AWm<ydmmmc}}_˭=|yP2@ɏuc`Ƨ}]`X΁n!ђGwhvy9%j`åaP@<6ǬgӁG"׍`|~> Š 9 ܳ*(m8dt2<�TWM/N [+7U?BL^__c@o狅::|[@o40N'ny^໷ y_ oyhnbhovw誧kx�_.]ItFQоfatfǰl׹}x !M?\h$s RZf>.>\~'>|eiReCj?Y,i2벂"ӃEi[e˝\a&A(:A:,R[[[( rR89^ hv& atAObꚊ&xhѦj $U rug)t:D<i6vo@W^|/q+a lCm&%)bWeV j?%*\__^/gg|VYir""NyT>ɕr"HNa7@>�fhbPDI* |8PkŴm2EJCg9U3uwc1LPWU`/7s˽n$N'9"TeYQrM3(dL; E1Sipوx=ΗhUNl-^t{ṣ̂вPCKrNN.._עIKmfx'Wo\̡j卮~xC&rF  p| K/wbiL.r8<fcuZf{�}?8; ꔿsucv?ZLTNrѐU3 &^ 92͞ޞRrlD5ȃy"dc۴J-( &oq?FLǬ(<c%]x1T4i?Ų b>[tg?SZË7o.P͑&STarI&N|HssmtxY5?|d6/뫋)-5[P:__|H?<3XuuӑGKZMϮxk7r OT4u:4j6/f}6[[cv4&U9go'~#<ʿx8RDNi8/Aʵ4w/umpF^󸾆M#g,[O=wl~t 鉞gQ.dϞ ܪ,/> dqYJcْ5V Up4_ [^#5yIUt:^$d8;'wje}hl>+J(\b-EM*p/Kor"Hp O8}Ïx_^N#iH!9m:9_*U`/eyx5`(Ll6Z"rf\KQ%QdA\ a#G./޾9 6oxNC/gC$:iBY;fk'_>¥u EEfE�,? x:M'S|okw5%R!hBfx]i/hK6@f=5EՊ0-+=j>Kt1Ktϴl~} vuy}}>&T3 sսRR+*o~/anu\i7r^<: c9rE?Nǧе4 # SA1/6~_}7_Ь/M/I|:I^AĹQ\OuIǑer^XJ/zmW9\|C:ZrH V qa-ňN9^~vAAZ`w#2}:JQ@p+Tdhj8@2rpo뾳/> ¬{p �SE3bGFry(lע#Jd 'ĥuc*RN_@_ ˜Ц&2}Z:i:�Vj=YljVcߍquíÿ}L~oxrX<U&3m:LCļqU4dK9�8*n>}.|7_Sx[{7cT�WDC9a]/L:EV~G;d_ܦ[n)2`ªĈ۾ǿ*^;Jhzy\|qXk_Sgq' ߧuuy,.3n}N"OW~3n'Km|M~bߕn2-P}aWDV_ƦNR]_~.EGK-hROVk5 qޯ.A_GΞ̼_YEN@d^䫟"ԐהZO `%+YI.O^~ vݷ|7%w/j?@d%+Y´g:tE:sML%-|𛅓{۟oNf5SzyM~kd%+YJVd%+YJVd%+YJVd%+YJVd%+YJVd%+YJV0"O:,zc~PW�K:/KLihSP,PσエbK]Ur*vZͮBgާii"(f.fZ.ƻYSUC[ jXk$rKݜf&f(\;<re;&ۑ[- Z<kY7isڎt$jGՖl;~r=7`ȭa\c{m)-Hʦy@@EYy]7T˰\GI#k qŃJ |:T D{1(E Sz*o]fy8)#+ajۮY9~@W<wwAAxmkcAVlGbxl♨=F(jBqG=t2%äi-PM#Z]I5]4D#q屔a'%mzQ!UrDqSDUV^WO-(;Bߐl*Ni`ݯ1yG}4ǧf>ex,9FBEE�e>lnqS7? CC#[ [ =kQC2 l%QD}jȩ cOu7 wٳz);iQsZ{pV04\IZ%Ը,%Q,#hۤ|O47=kJ崫mՎFOBpl7JbG_$ňb#I##Ba 南=Tٲ)G3m^nxKo~DlSVA0:4xV*晒n|Sӣ4tj0ru-# DZ 2jՁ-Jb}Ǿ;G9R[6 lDDt'-Cuᬪd[b8<tJdC9,-7r޲Awkc8^2J6, a꜂xOBGVMՌBr]$]6I Z nj#2붩{1+4/pt7xTe$IN2[5U`A{"['ozwyP/5`3TN>{@@@NY⚶[1 lŃTöL *v;2RSF`|GLNS/:* ZzT{ ^QRfڡ S(A&Ƞj9 ^4bw5W7ϐMN13M Q u,S RȂ8:a0(cL'6vI+9Vpe^5d=pk&sM1)N` g8LGa?apmNtz(eD\x`AY+wwM bah",r"ui֨+*;dC$ ċn"hh^C`#ד\/ڕݡF,EcNV*ʂ@9$Y-q6HiՎfUOHo(bۼȍ.'ۈeP\-̺:R,!d{$2D�B':DnԺ,#҉f2ͦi?]!bL:r Ͳ\Om #МN#2^Z*'0%ETn[(<˴ݔzt1NX�Z!>4L˔x"%ʖkX@-6][+_`Qm_5^ ,KjrۍxL2#vjw8Y|)Ӿo9 F^hatQQ<r9vZOqTV-ɩ" j8LU׎z9_F:tq 4@$DٶFQ6HSQǔ>P#9Vahj kXj){%.e̕{VrLTBHȆ#dvrrBG`0=l6ƱpD7ٖHyHb\"ơa.[7Q8 uUB{f^ ZVQS33p BZM|T;|nT-NAhit$Po`/NFԎH~2#ưl0B&iJǵd ]it'(#U9 MTۦCv0 Bwx!5CDYDI6`8& dTXתoȯ/sԕE}PL J +4\mg"Ì M,CAJtqzq 8p =CDmU% TÀ~p @@t`8H(?�\XtD5RL(BTD5 :E xU@X'V:(`l#߅}H%7D"K**jf O`ndi:m S-ၞٖghԬumvl`MyU@5*Nks6`@kD5A젱,TMFhpEFt3Maqب+HR\Uٮ v(A w7U@R/ S9z>08)in:ŏVzg9 s܍ݷsȁ�3g$U}oms@>% %As~UP%r2tѰ c߂,A c h;3G˼X/6D=s%8�6`.�^ άr50 5+CA0]-]QFؕgt\k"nLk[1V=?v6!G]dJA YD6CP}:ւ8}G1.4+ {'f/l;_~!DQ][+ \R>ː<*7rUҝNް X۶nb!˔j5" R u@)b>B_�9l䛚59 OM歹" q9 m�= Uhfghr(@Q ~uj S(q%�ly �!Tc!w[AD&ᰇ6<z� ZD8XAZ\cGUVpڝnEz}T;C9^FX8Y]X>* 1FނLŻN.U %%Te%q\ c(č 1$C<P<Yzť0p C|IRq2b@G䄵 ] _^%*6C|Q8< =HKX2}�zaay瀘f' dqnz>]!T"_g4Ui`3j]VUrAـenqMaD^h/gqaaiyGAiTz7}3sLJ.{v�EcUg%� !Å[� I{"N s */,ʋK|Ո#H?]:mf^ro&mt(F)7L o)}yV!8й\^X�, #"�=-aa)K抅eJe΢zJa;0vHl[6䁯rf9 o0\.,}X\ƾC.@7hX6$RAbz#s]ͤs<rJ680ἡĢq$p+ 6@iS;`/'X`[I=wrrV,|\|&uU eEn9&d|oN@L�S-<L4Vb՚�.,lPQi}& S|t Q3L.vM ŧ 9^+IBY (kɕbt%wrzk,Mgt 4et5@bS]qhȆp#ai HzIY0KҒP9O,XnV RuV+.yQ3l:!#3ؕ0sk a@ ? <~;pV 洪tN5^KatC, fQiR8Z_YW5<-v0< ͦƳ�&1FaH� 7g%7-1׶E_/s%ܟv* H[COyTΤ UķYW.҆P̢7A҆a"B.fǐE굋bM|2 ,[Q4j[?=dEll,[Qf=8yqo8 m pNq� T$lp SSնxJa8/e3|^>:UTc 2(8bm~@6X;N%>hnġ7-XھŊeB&2y܅Zt?~˷=!ip0�u0,JaaJɃ,�11SXoOj(՚h++t<4v&TDSٕ.stTӪz X;#0Z8-4DU!-5 z)VgXRӵR>>>&S*J Ĩz;ŸVvۑ ELbrFpşI^ʝguFd \lk72 oYM H1llBJ,~"4'JǔIp7wACC\)RU_oT'RgýClUtVW6u;Su'ГM3 RJgJ2rlKJW9�.Yxgs}mL:8 KP@ap#)R?=)( 3UY:YpZYiqkm\^fNחwVjW#4i=}WEhvaf/l-Ε aW{-7߭)BWdr)BWwUW47Mu~[ݓя8ͩq 1`̓}|z|v+ nFfkmyeu ېqj3gʓK'%QVf{JK|5{bxtV<ͅP穴ڽlcskg{{'] Pӣe4_`'jD_7R .eM7cW_ei+(nru\|-omV!`n[fꣾJ0G[':ó"=t:_'R`hzگlL_aaĹu/ch^,$6DO#rE͋d1k"dM-/qW!3^f'uA!^)^Pa��RW.y x(T#Oedw{@ʕz9{ulbuFtbQlTZwz~6WeE*-3eQ$: o'Wf๯[I@]?w} F^Fst!s˶mBt\5-RZ[N& ,UlFgKy [ BW^7 Z 3~؎u 3$$4K4E]n_=[g\u<+S�}WEYstI Zgh\ËIZd<,9lu�nZ%܎QKtE Cu�QyZjBnNi:4HX_Y^* "_VJd5_W׃7n6xΩR<Ĉw7HWHQ߅Pd wAh;7S&,%SNzqia  f 13HD'wv�y+v$9͞ ]iВ׋ѷ5tvW1"b¸ )nyuyeeD+Ď[* Z2 D5Г͸횄�,)k ٓó2~+)zzHB iV.壥 st�mu^Z[<.T%F녆 67q׋ɪ">$ry&IFwPce{{)BDtKL/nl(4B1ȰsZb%LERްn &]lТon&+2ˈQP.WfЛ<~z4MEs=UNvUe73 |.�(m-/--;0^^M¡wd2N4oЬ(w/O&- 1UUF0:ًm<[*g)L*~tVnG&}s' LnZq7l4 Vd Hq==UhHF 楈IRzwmmumz_hw?Q*.0cS3^YN Ɓ~kPe_?xU:akpO dooZH�]g)b%}2"v__?8�Kon\rٿ@Bw) n;oȵ$LjSӊ@pC(5t T{^f9<ox �|blZWn�qVmmql°MX5+^1Z0OˀbnH0Qvh˼h- }_\vwzDUPzyyyue4W$gJZ&peP%IߛQ0|+\҂nU3+*T�t%A-c嵃-h4[l//J~[9i>ߨJރXc:3oQ9* ϓEZL( l3/-/XXP6d\vceyO]]܀ ڐp,/J�ђ$ɯB00V$Rnot}r{4d<xIJDljz$U;KV?m~NZby9lG%tq_j"_8O.7l7uzr+[!Nn ݽͭ݃T<wYq7](llxro:VUEd|N^_l�v= foo~srp~=t{|^g3gGGTK; p}Dzm[c | !ePZ*./�3vhfrՍ=ߡKף~*P@WζϦ]&Fpv yGUj(eXtOw>K iZ5:hͤL AW҆*T1.#߆)۞`YUN+/j!m `=7V.9YSDOwA+phpxN=X-(h.7ߗJu-lJ-+\<Aac%m` K9 \܂?;xVϏSB\&JQ4YMe-lY*)ȱ&U8�r=H [\4_ǐs,C3%kd? F!d^a[m}K% d]GE X,JnHTp]?Nӵcë y/ �<tOt{5O$-]Wd I<7dI]aVgx= 5nsNe*e0}!Fww+`Dtt;O7W$OﮯȷAea+]241<דn^,q%J$M~!( Y/yw\ GOA'v tI"KR<)R%ӌN7IB @bz1hv{YSe+ϨT9ĘI"f=B2tt߂ t2#Ih X�z|wnz &hj5 xror2&NۈL%qs.3(Zø vlE`%@ܥٙ(D ^Uֿ|;]_OnPwӧ۫~# �Kgb:L:-H:'9+D"QHA (ղ1-,!ܣkMcj绛s`KEݲ0t9AǞ^58L۫2f0+ئ?E\{x{Q˷5Y.m.Wq:qk<w~q|`kg8{~PTd  ̮5o�\vdXFӚ HQx?j�s< 4[?No.l?sԻ??{wgG'{}ua]5pL۶g.Ǐ{] OD6\FM�9`Hl``eq3K| 0`9YO40{s@6w#GLdс Gwn$۫Nx`@Lpǣb9 H}W_}:vv_>g?޾mKSM4Ӌ|}F;Vd dhS/GVwR9"W 5zB@T8A[׾*)IuV0E0Ŗ*q  BNu[e_}=4W,utxvBJ"P!-*{s:c9#S v0 BWx"`cy`+mTpt""8pBv7ŪXM:c6u>EIhB fLr{q&̣`oM/6?O c Y'-M)C tFǽzr n q.PQ:wpPz)LEaE铂I% 3?RU ;.<YB䆸|\=/e "UL bᬡ{(f];MDE5 Lxgup/5{_(B]=T?K*Cb;A`Zov<P ݎ^/tpm?L=hiٍZ@TpR+\(-f cT@e\TNw V9/;_ qo! Lin�T+,V,7p MW2I MTTX.s,7)_"~w^yiRRm?NW> ~㗔$ˊ ߸`</~Q4_,tee.s/!'~:M1?nwޯlxK˫ [?xg.TU%{tqq ?#Xʗ[k /y|?(,xZ9vlS*'_|@UȞR_@ P??YÈG-~#AEy_PiK1b\? n:V_Zȿ"m\2e.s\2e.s\2e.s\2e.s\2e.s\2HUP$_x\̤^Q <-hqgW-&3l9O4_Ie Ě E:cʲ Zeig5ŲlUKQNcDS?7mK5"I5mDZm64Kg9J4UaipNNwa;3s@LCݻi0LC%" t ]^ ^lG NԌ|2dsڛ8U (| ޷BtUUEQu"*^ O 4ò?<d۱5d 88.Dj[SOM]/N+;&5g13y^${XNۮJχ0"kyU$c gIu䎫x0; mM <T`4<onyu\$�#|]"-*BW->}&:o21lYYlxvVmAdbtKU5Ht!.N-qt!|~A7[G8^w]M4L@[ǩhSI1,l N&wIYnX* d}>K$x<a$pLӆMn(Nؾiׄ0`bAZn~c'bRL%=Wd].});A98d- #[ ׳CoF] 28H}8>aZ5aY$N,LVr5#߄ 袄= %f:�F~ Z^`ֺ>_f{ BWiKqՊ5&qymc@x>0,Bm3&g"'3#be^967! f,�~8o[Ei GjayD󎯾j;AmU;\PXW5B7Sfd3]3N@Hd@lTAL*y&_|WyMer{�Ϻ~D$q U y^MDQhfXZ-led:<ĪY+<D?*TEwalc�4f;(�׶(0Eᚪ:Ө7d€(3a*ZŲ-ABc;rEU=Sh4x{\S$�^jAT!Fz`sd/�{~5!L�GYIua4"eR;-y O5ŋ<CSlje|L4&ſ=J7!PKC@`)D1lBT!@j`^(%O& J4C실h\.6pSlwcCTݛ؁dES j 2xYdXʰ(Y-S%H + CӨ!0< n7EqRX%IVl+ $`0CWL$YT4 H*�oi%ah"+U!dH ǂ0Nwf7]`z6<�0DƭOqԚh(h@T^Uh)29% [ RjaxȊ V�t!`烟�6pK\ d0J ƶKmI@$rY6%V;P%AX,u &R�(GzC8/A8-JC�a oh᷀>;-H-LD<T]3 Wa{=נK4),"b`9;";UiņqJ25|g m͞(dꂩh�w1(“6$]x3;kS$`�s9<oUמ}gvvP&q �,ܮU{Т昞rJS/DAHƒ/X+t5 cAXeX` %iaPH`6|d:=MGx2;zp]AP6YpZK9Mrڧ- {mH�Xqt:ay(Jw.ò4 W`<{q3EYZf%YF-_*�uNT m\h5 ud }[yGp4Bth4; mS8sk"O=Aӝn[ڵNd2;4M7c/lG5ؽv{�XF4"�ya `xۤLlSivʂ2K Ec%X1"yCHO=1pQI4 #Q2{)f8EЧ2V-t'= Vڢ{)Z إ \`HU`Q8M'=R&PhڃIIK( 7pV{3U097f8lXHbl$ Þ M*|!�~{h<;:6e5lc6^PPn0 S(Z4y {DOF �G9'LVC۽Fdҝ !JIMʦ$$,[uT$]X |=Ta<D=E=x Cܨy_l6/caF'z}x/hb7j{3I0Yΐ&G}tl;Φ1A/ |?B^T02AAz6*a=<l>h4H ]:1aɬnp Bu: pD!سŋh= n�ii&Od˴ _pΖɶDW;979_ ;̇~SAU5B^0t t �΍�m4 CC|D]n-i`yĘ^nJD%�x g8y3.3b ȀH5Q>ñ.P6$CӆD=P 6$' -4rEh"MΆŐᛍԄc�a`CZA_XVTgjaB7Y)8xÕwR 蔲--C s $nTWr=~TDy H$Te ,!@v!RC*+Ko׷ɕF|ؙt<Ah1-ZqZ-So&H Z="MYC2vzҳ LaA -۷KKK9.'ж(B d[(urf^K7&ZKkM BllŅן o(&ztǕݮ|Wz  ɒRn4O|`YAy-:$tUb#4Y"㕷?.-]^^ZZl{!@ ' 2:�TFT(V #- <2Zdɭa^0AeGQDRne啕et+eml;ѥY_VۖA] ,ݪhr@+Y<W!6k{|H0t0ʚ|O/:`$Y/fҭt�PK(ΰIVwmD1&HJoq.P@̀ ƣmؾ!](p|\*W$\^_f#:#hZo nz;1V�, 4^9L1 2rЋSQ`(RTmK4r+=�\+imRdz3+K0"o ,~/cn-k+"Y AN˺ UP/Mu&#U6m3"]Ӄ>;Ď~3KIt-tr9IwA,L.oIeJb^gnRUJLJU_)VzzRD(:#vho遜]J.CnYNB,e$qHtN$4kFY N7IFT>XUm^n ] ̾>J~h̑y:\Nosj(Ғ=KRUKF&ZVPhRojl&$± ˴+bFM+p 3\!IXt, 0tٮ/ ]f[tu'f?٭-e BN{nL4p]jdS.KzaX&.(V*DI AN2tf?O^`7mV<ŷ/¨Zld 9 - מ9ҭ.ץf\wZiBK1<z�}_c(ݰ[*u[cDs4{R`zaIcLLVo]e,:դHj+btpo&uڦoj9uZa1 Io BT$e r �T<Um�1hudAlf}F^8:<fwOI@ۈ|EUb"wLMǐYe9�0%Kݕ ''bx8-nReV vlԊ;[ۇzR8ʑb2;cHOG1 1dmTc aKX0<\`ȒnXjk:W8.[ O3@"t2Il5ar*bK9^&C1H E\N@{/Px!\[JݨTfϾhexp\Э: D6@{=.02zSPE Cnڢ�Kon,j벦*[z@OXJ5 As㣡'ʌJv5]ZdD faj4'*"G[- YeSP}=qvmݐ NSj6kE~eMFP=TZ899mџsKXiGH⣾ɜNKnY!&sAH7gGOr'ذ=EѰ卹# TX7ZL>G]͠+6-7]2deKsI ǥRdըg@k*Gíͭck6p.!>E1<:]keE7(M$7]HF5:zb!i^ KSw[y g AV2_7Ozb5uFjd8�D6sͷ?,m68tLӲaJ5w$ #jg*5y_(d[t<GC\g$Ab<>Lfa._6֫T3a|x(wPn yDYj4p@mvG뎥 +{t : YGU8 f}RXOT*+,CŊӞ& A `|+dVߵ'8ULv|{vQ@agcO!rZ }yM P{:$S+[0 EI$+(=pZIT T Jo9џ\^_݌}F8:6E0�&/Ar#fqQ<3qb"<ILfđ:ɩVΰ, �Fm4nC[M1qyIb:+00ŌMd*9*"O@PKin0}I3Ї< WЏC%gg%r i*P٥1aεEx_~ T*jmÛIAY"OtyyͮnFXv'5N&t\o׈ZۋedW{g=!6vΐ~ atG#pzrN8ټV7&3CYA ԞƢ8\2tE$ՙ]Ht$-ȶ(Dtbxhmy`9qi�t;`U`HÞs:FUջwn]쐲>H4DVl))<1@aGi2[iq Hbpz4tES˾gP$4Aԋ|JVtN_Ӵl g5ڀ'IR=oFs1P `yn'ӫURRi�}\В!e Lpyj+ZGmOlNo/Q_ -Uh<Lp8Ɖm&ZO=?4 OgD9Ś\ܞE 25i4+ݻf̶X]^<U!Nٶ 0F7ozʼn�lXe RԢ뻛nd{rt$(YYbE3Ga5+"64;ʖ;ʺ01nل@@H"S H>y xW9Psɍ _㺒=ȣE3_Lv2ٓZN:v & >׶vˌhNgx/ԭu$dna8[5N?+7CMjlvvbds3wK$ LJDžrVsVzm ]$JUO%spsn ReEyrݔ$)h >M߿; En'jz6==Z]Koo'zawgk{g?;Llnol6ws-Q ϯ.ϧAX_[^dΦiǗcM�k$mgT;-fZ_>wgT;4͆�t> *n%[Tjuu}#XMR%*tܗW&`|qw7Ѐ09dz)_ls(Lˋ1<>>\y; %].eT"Jm'WW$Dre%W)Q]_φf=L.g[�es4cttt\jѼ +n߽{xps6ݸM#Rz7p?9oS_և(^m2]^]Nt wi$=#<rbE2<ϲ4%Џwwwד z@{8MpzuN&HIt:6yTnq>{//,d;:L?[4Tw<MSWAwpws,Ƶ}PAx2ǓL2^OăX]ybp<,A|g&dRb7蔁5JX`N\~M'8Hx*dS-@͍Zzkk+ȵTJpTp|MCȬu‡nX뚚8^epvx{qqspC}{u1E{"UY 4nv#ZfUR׏4ǩ};rਦnpNQ�igjړk{7{tt|?NgN'Wr)ݣq&DudxѰKpAXK O]׽GW ?|wg�njfE ;H$6 [.j5'UҠw�bRȐ |TOf,ϷO_ I7On/{dp$1w #DL%%�nlx<9�Ɖ8�ӂ ko3q (6?Ǐ=xoϦ!,vKuNodir'eckBNbBfr~yu y77@j棪*X+K~M� b+dR!HlGEiD"?(Wep<L :x;šNguݛ\\\޽)5U%iKGj[E7P'LR)np5t)f5)} Nh&s!Lo/8ttk* ۉNGv39(InQB90{xOŮE4#;^>|=#<# G7*ŃJ 3ς|4.` x0ϱh0׷sO>|xwsރ+2@?|?}�.e2޲nQl6WS0JGtG6Yot!`^^܁|ZvHA>>]AJ8*Q8IW;n*##GD%ZjH*CO0^G3 |W#4,/||x{*aljΤӛ; QϭoAdl ?MzcJD6wp_(ǭ(}JlPqo0,@ch@~yqf2GU<mmHoC.OV<j'vSbF1. ݴ Iekp P= ;gP,+&[ oG.9WMB.-6AN];)5-2Z>0 <J'R�l@L Xp:]: 3dQ`st|NaӐa~?\Jlw*[i/8 fegz{*\7<jX ^9>__\]\ގMY Rzgҙݝ @o^?\zr�"/JSDaE\ߋ^": >l']`8͝Z h{`#^]ݭrȈūW_z3 dak=8GDs|3wh/݅6,79]@v|v%QiYo0ۻk+ǵ|\W_z T ;N&H?1O+ioBT=\0^gj,bDAp\L$-d7~� $(==XK0SBRUS \).c +}]A} a>BMavƲV+WW^}'\vv~< QpxO+Mu.h$öq(JHd&D,_]Jf3o}Ӑ}ׯwq|:e;j񊪪2צ5w=>ϼq|1.,p7dEAx&KNfㇵ 3Ws@p˵t(ؚ^DKX&hU/1Q1 U"hҷ#a:ǀhoӻ{UI6p~ 0WoAgSß?t�pDg343V@)Nb ()Cϫél.>Q|7?|i?(U` F3,C@Ĵsp6ᇾ쫯=^7o|8Xt~:M|{'עb*!粇X9O/G+믾=V5;$闺+9m<}2VTodҿ<w?Z۬*~Bd|w~ϯڜgϝ~X$ Ѝc$Z~^=Imx÷puo| ߅-la [߱oō$&Wvˣ,zs;5<z >:DfT"?/8'{;e_~AKZG3ӃqzzEYnMs_9 \vu3ٷ{d1խD0XގwNN,la [ocہؿ6S3ob/y-la [-la [-la [-la [-la [-;k"6ay_[(:(xTۜ(@ 6`]^346Q(ӊώfv?g$@mDXUk]<=RLcߢwc xz9v鴭Zp:N$Zǰ0=Sq!(yAAL^iiӹ!h f-4xVR42帾eihp_k'&Km515]7l'B7 EV . s5o:ۦv;W`dM7zgi+N訒$/сe("ɚ |ױlϲVUX A* Bx`<=ϔݦh" v"a39v= ׅ0 T XZURHxXU+[A? :8lX. </ajMól͠ (sZ:l;Ėrg,7p5,Gx ͈ Ljv4.D 6"tk5^sTϖ z5e=ʎjif$Y $2@ht'CNhD ؿj}dKAD"HTש>*Xǡc}/H3َjly3D$)V':s?IledWdS<_'QkjAIhȪ({ΧIhRfـDmrc2K(k<qLˢ@s5^u l/ɚG0nz ]? iārILfę]#cC@gsВD/ <ϵ F,&9RF󪯳ZՈ:bn'n^jW20QR(6yAwbR`@P㸨A( J,u~# $reŎ"ۉ#'zqdɺ9D9^D*xt.>sm�b霠 F_D^6\>^^xĉ:tZ@}<\.|~"ʊ;Œǎq aXh v)-{]ѰlS%8  # Ev_1 T / Cz(˪r>, ]7,?mGCSlH!Q1b_(2G,oȨ.)hJm~ G u(�[ƞX.ZY #=C[RԜ]&oy{lD%Ǩ绖IG{p@n'~HqÏHe- ALyfD#[.✇%[P F@hY!&qWå9(ʉ܀nLdжtvȭP3B!8Q4#Q d{[Q]:WH}CUP4Oi(,SDPSOfn$`2ȴ , >l(%3IQiڕ l#IU$ dzlv6{V}m%qoY# Y]Ҕ_ːtK;F@#z�@ad4  (y@lYu`{^/KX'TAyPh A=&t ͓00h2^G >MMB 8t]t,ڶ QCPLQ8tlah X1)/4II慨|6$N6<&i`ں":rfltDc=l4jvEy~I!_hkQLgyQRTjM1i09BR>.t YA "cE[$C8mO|^n%�t$I#=]\\Χ4)xT*A"ev0)!b _p]C,'NHU@:5UsX .4q4Akix4ƚ(aYQ LƐ('C|_�x"Gjz&CWc8zҡQEV6@:3 Ki$ƣafI3(h2q9$ Jb(dЌР-M( D*u/kҬ9^YOb\ N݁9^hf4]cC `|>V- 5-X^{h(3/k2hFh'ńZAK5<MSbDy? � u!5TDwCK 3c0l ;4ln1<tQ3,4.O AAܶ1:4-,Y`pW"9.{\eX'#^ <J # Csˊ=Th)r�VGf}xWkA z�8B�9#ɼM -,R /a<h,煹!0Jgr}a ϴu!r7G4]ˊ Dy ʇ/,Uޑ1$Ek'TF(1LDOo4P: \.6$Ӭ) Bh8 Mѩ/ALط>,(yn`;uޱ㳓RxGvخjs+QQL"Yq)0ďi <E1ZWt%U>)WJ} &t;=EH­�iIR-hxH8WPQ'4q2EM4J ⛼%C[Rn*gR7A[h7e˱AȡiH aH)%ˠ<C`E ܴtd&IyXQ$5fZ9VKՖ;J$,1aOb_D$y!eNN˕yq#?@ARAh2~h5J|rVj6j<xHOTMiZ$Z$h94 BL)\[Y\\:`9R#^ӒX`(iEe%GDU%otxP,B�-)`͝ϟ=QVM&�`[-a�9/NgJW gUZӐ"j-["{iUL ;Q䈴rgp69řN&%l~Ny34 lU'r֤ٷ̲FʂGhܯLd=CpAuPZ ϳ( 壥 p9=h�k󼃎:.i՛=\4GG4 ͋N"55+ÂhxN,/.-.,,,Wv6Rтk|bQZiu)#i 2jƕ펠۸@�M͋bBdIb~.. ;OAϥu B䴏:H( frz!a<tվ(6-xTu;m^ BMv mdB0>.<f_P={g�$#"1ݻI}mtz֗e=qچڮ"]MP8 -#?zA7fA{e99M4`C· l U:e<=etMPpʊmhLY9ZUXp4@ j'Wȑ &Pb$5BSNši6)-tR(qQvz4Hl]*~Ȧt'@,xz1DVS@~F dlͱ|4|ai%iQ`iLї IW }8? ȁUQ6zVn ^ 6Rꞡ- KY]I<Aj%h֮,AVGԩȥf`ꉫ?T۶{NTv^ڝV )qʇЩ;\vVdZ2 qd-_e;]V1L]7~ ~ $˪9zpLRf\�J4*9ЇkKj>ΘͪfqNz ݆ �B+ PVGP̓Pw-4!=%tQ$Qmpz(Qv! ՙc=R]X\X:(6q;& Q1|RbjIF<L\A+6p؆MM$N߮[Xq}7 Mi�nRmsy^KC ͳ Ohs<DiW6cUaԼѨmE>+3pZPʺ0F* `N"{ANw["ZH=\oBeMv|b||YG*ۢk̳vѬ5Nk�/+H} D5K"!ٞDh�}۝Y (l4i]*�oiE=s*?@" %L\9;ˊ,MVT=L2OD;F,x,}ANgtzB=őN2m8:>9 At4$gv|ܦP EYg5%g@<ӏNG?<u]o%-t-WDdQEQ5,òtszxtG?/\EAw7Ó*}$ʶ[从c5Z/pqTY(l"O~֖uNTӨH$ثnojicSLr;=9==8iQ&$qlm uCr=_Ѓb:'jVcfɠNyAqEUVE쇳iԩvO A^` @ƴN7/|}R ~0آf� La[G1.uyQNe; U:ziiZL _3#gTp\],J z6l^9Zwmp @Ɲn}dw͝nL+Lj) ~f- I| ,E]ym;|63P:ةs`ғB^vNteLJ-p02@ dpi _9VN*$XCOg$Ruoﴏf'qlO'ЭUkkNO|{ք{Xa>$ˇ`\o/_̆@Ygǵ^,/ 2CaA\SlM@NO !Aʝj5D^C n8/?\@t V_@ ,+N:<MU6<H: bLC' �vrőH.5MEU^v+'>@1x>t8<+-R&nqqk1ZWWQD?}6?_y,t Rk*TU*B{ouϞ3MpRO՝ i˫XS#8.1G]OId0J۷o^߿.B #_9^"?]1U#9a_AMc8b<ѶVV7Oj] 2PdD݊gWD]ww7,:?QRv\ÑQCN[V$/8m(΀N'tkH/ÂWpa҇&0_"*P%9ݻ ]/ ^2Ù۫R8Qw0z�hrJxw+SAw#ZJIZZZ[ٮD0 gb8+ /^R53\ex)s;O #l]onb[a%ݝ\e�.oyRH&W HK�>n`~.oxPQH(2T^Ԃ ^_ߎPiYOt]EX۷F ov{T&~Ν3<3s4$.hz1.nUM@8ƾ*Fz=V@L_e%saa| (V* \ہ'oNw_\^)6ݕN\VGQ IkȆӋ 3+ LKn^]&LDSjKlT B쫖7q2ѥlG篯 Χ1<MqꂶQ Zim5Jh{^:>أׯ\"`{S@Ws,p "il]ߤ~vq{}[&S>;dv>;c@ ^=[[+eFs*9H^C(<@}Jۂ᠈dtO}C:d ۛsϖj`<`0&fw>5aʘzXx͵~M5{qy>S8Nu7__%&is0(O"H>hx퇷/#Kvwl]E'8l<VzyxvMBijꩈBzj<�eOZDmG5Wt ﾿+E2(F^\ίnRKA: S*UOvw[IVX_]/e38@7w6v9fzt;|L  9û7y_]F3գͭݽãRi}೓I 12Wӫ뜖*Hɸ6퐲?mݔUmlUxSH7}4ח"I <+.G׎7V^x4W6^,NoΧaZZxBL^a|C'>iʖkb'?Ho.w@, '4hqTvr*wˋKK+KK&xI.-/,<[nMo޼SU5egSd~Нt#C޽}fdQbhcilTz "?K+k+VJetz I狋K'ݛ3ߢ.(\( vZmb^~}3Nfƒ 58M^ɫuR_s{sZx߽{X*($nnv^U^Ŵw߿}wi4j.K X^:_ X#«{=dmiTT#U6lai<'fږ cXκ</-C7pBrҞAن6o,;'ťۍ&#=*,xQ2奅%dҖx}1t?{OцpX=<~}3<#dbfXy%H+(u􎵕W}Rؑnʇ/;MFmlH,\uz7J '~evs9y=\OӀ sb+6&Z4>>fz I_YvZniwwwT>0`~ ;  ݇>X}jQ"wJ4+pU;[+ۇgRv&۪FwLITv>9Ҧl-?G>z}v:LEʻ w}vVV�.G"݁lo:8<ۄӊ͟Ņ0ׯ홫�͏DD)n^ܿ?~ yK>\ x:{_=\[Z'O ã*~l,uA ,L ٌUu1H,70Og7w`)Cm4ho[:wKGS.7LxHV7^ϝ~[�/@DPUO?D;4!U7~?D~P>I=�-{|ޫnU|3Ѹ/'ȵMUtz}D]r$K|j-#;6 MFXZZ\+V_5Ow*m]D2Z3{jz}=Ʈ?gjZ~HϮޣ9IsZ]͕NFOO[ҫV67�8 *4qMgi]v6yŇ?#|]/0UN^)/, Cw6xNPiסǚh<9~:(5$Id[3i+?eAxJDD·oSeZbhvv(2߭7:NE%# %lo__@Z^~r$3y Q~}1J|zT'{_o_,l-Sz,-,yY^nmomKӎ$k<HĠn<ECpvzzPϣKWORyRCynmqCtM9}[C߆4F!MJ6)t Mpx?o+|xo{Wޫ͵},[/wNkv+/_J-NhwYvhqML0J'yU9 [iG|~zITd"tR&IRi .;ݽ"mo[6 d7W}N1l8Ͻ$dt�J[/_m6Ύ\~}s׶7琎˗NI*i~ mdx?3v;ۛilt rgc}c�JvR*=~W_|_k6kG/͕oKJzxH3Eڊf HڲaӕĹ>qj4hekBgav^mol^,<m R_7n7Z寑5ʍJtvR tU Da;͎>Bt:z}3 =.Ihg{z`)-8___~W]<,R+-g +N4{= ]Cw=q>}?)fC|7yORyvwR9D@R,lvЕJ͗}WEmgV_?jvX/tX .Ҏ9K#ε8-8~ :Wo Մ^WOѫ!gY*0/_~対>}vgϞ:+unGfK= &>m DV-r9 Zrl4k۫+K+Nr8o׿g{|8H^]|Wb{jˊb FwH!k+nˡ'+V":&7NSǿ}_7wp:.0gyqqy$NʭGeax",{A2 nGNooEr&ٸ{ÿ" Wl4H#uey.8u:4+BF,5KAW:j'~BÕ6/ _}1Op^^[^5CnV*N/Ǡ,  sOՍo]\Y[.ďgz_}V遬)r섾& So|[^͖׾#W ۯ/ѣ~o=ȑo-,.uu6V8t?wI[`$,\]B_XZ^hy!`}">?&ߘz;Z2 jEהw_5}oZwۻ+ǯ!K~DO7ULZ>?P^]yAwOOO ޑӋj_yY3lmͫk?;ikG{ uۍx>m-ۍ9W=j*qLsF|xQ씻J+#NO"?i[GKW7CPyWHʧ?!L u/48a~_*U)dIp+7ya~&?WKOuФcKUtd%_Mzi#\eNOeqSgoM Fz"ixyN KdQztsj-QQ �Z/>?=`Tg?ޝ=b&6?̝M[Z;/=҂gW'Nieu/ϟһ՟ۉjչ_e; Zen'ɞ=Q߈ƈ<I|;KnɞɞɞɞɞɞɞɞɞɞɞɞɞɞɞɞɞɞɞɞɞɞD~~B$i{ҧ7ɆkB'語INq`z- %؆)sїd8Eu:Ғ:_$Փl(]SL~bykj6k}EC9LadNq`);+ʚiQb^٦9Eu8aۆ9?V{!naEMatݖxZ6[P::'CQ6Vx64֤Yq&IYcͶ츞nt[Q˥ZAJciyʺ"ue,'^QDҔCѷtE{Mְ=0utr XC:ߴ4kQdY40nj?,GMSl7 JFA>,saxQD&HcB͋Kc$]U47$3x5S2uS'44ro,g�&l G4ge75 j  Xir[!cY,#-*p[U#$) A"n;ǃqk[Ԫ;?'Liٮ�\ BВx0,Q(.ڨEk8IA Q3ƳxrZ!I~R:B^2gx~6 +}Nw<|"xEG`+-ϛXY5kc1}-m;L骶9-ʫ`Ѽ_ [|TeoJ݆]x}nltmNN]Hm1k}얿o$Ft\VmH! 9d)weP AmOTlM5~ߪ59Q5kĢ0 ,A2v@(57Hcx+ӐmQ9QòPnA,ˎ|U8ۖ ːXlX~Ҕmg(f2T7ڬf~<yp>/,q.McEhȷI%!),m+ 8>(BeA#P[>Qhۚ!q?aufy4u Zea!*'/r848B !j Y2ushfm&i92)H>bӄt澪Q]EI?Ã!w4\]CS95Nx,]2l6 jh�n=uU<ۊQx.КizUG ڂ p�h�a~^B㒻fѠPkI'I>3I؇p1m elkUX߳ԵNXGVTP(4thiН |z>=M08(d{6L#OYY +dq.p ?K5;/b2H"A4hr Oa/֓xUݘ%ʭ9!i{H0dGY�G11U[QEQ2lvq>i:gbQNAA]q|[GԼc$#g[kE$&,%?(49wuEV,EÉ ^d!Y1>$TnLO}\ /lW4um93 Ht1x9 ԣH6(/0@22T:h0Zt Xa! {:4XrUL+Csg~>y8Ll>SQ<!8$<zPyΣe*zu0-,f݃ hhLYVPgƙg͉v4 ؎d$\czMR^<]�J6-4tL&0JM8Ɇ)Ez: 4U>p6<K�hfĄ&6uhD0*5T~E׍i (0}Hc ,v-ۢU@~T` +MCiRC1}#be8W]O]aY�?_p!<ЪhǣA^d�5&X&/Ķ=1$=k4kBO&uj@K&.;<t"h *iˋiuI0Pf\rdr}u|I~s 5%Gza�1c @DWX dIG96y2urkHGv/m �A b.7܋=g D@ 踘?h<�o4[LǶ ]z�eOhhXB@]qqQ&0@M]BJ40C%VJ5۵NfR6۽Gto�MbAgu k8JyESJ%QgQFLHAxJf@t4~z8Bs_~,X8F 3D`ܲz0&4,$ wD:ƒ!9MHÄ́#D b״ {=]8Z,|nZL! I};L| Ѓ$G4}n9Ri4nd406~2q4-GAyD]t+RDv6<A<ƺz2Jq@{aL8ac 4}]B <$z n M34<8M 08Gr IIQFCy@l~hi;gnyV@>Qޥ"Q&FjzRR\g))Xie9"hfɦ(`P8"Dr` F2YlȉCs<[~j14iI6 t6AYh2*&D\ gĚ@} jy*\Rwiqyajy*[::X ؒd P#!KfOv^Ռo( !LsBK�ij12]w.u )A`yB_&Z(<J D`Y67_"#J#w# Pӓj HNW5+�j/U[b?}{[ɑ-~w\{G$ HAx/n k}jd=L3ԭ:ې)0T ؏s()OD ǐF$N3L/jxL`w8NE& ,U*<Ђ;}@�v\kIJ)+i@2j~? !ι=oAѥ"s8A߂#& B *ۼ(p[*ٕG)T*z 7q%Dգ:8Z*'jdH dh{UA@7U*7t-xw_8j x.VKrD;zpIm͖75CTZ|}}m}K?Su,͏ ΅\b%UZ?Pm5sQ7+tE+ǹrD=ȗhBcDb}$NZ8aI J IZc28Ŵ rF'ggD;蛪(U2!\l>BUDJw)x3=Q䙚x({2X3uFЌ|fi<2TY:li4hSՉ٦Gx KIy]eSQ`)*a#E;jXh Rm f/TzVYym Ms QhFNo(a+nZ8 p!# +QY@7?eLF"v$ <LXS7Q-hNðēV)<^wz&YnْɴK!H ȃZ^z}7=sҞ$ "[u(2߮%S4( O7x4~ك2F<_;P~9^4 W�PvaV=F8.} w^}FyQ<73&+ʊ,qm#~`iGeYԏ~s(ֱ�ɞwn4ڝR{li8 Md1=>*w˶@Z=CY! ҙY }uN7THeNtQ PYlh׺zHs"lܒAs: Y(ȪvNY+V*;aqRk !`eyoR攗g˒؞mW :#|Xa5o0xLU+{*x0*Ԁn2m+FlCYE͍ cP⼈uF](ZpCuY)V[[^`P-TCNܪIDD|JB6򥮢**sm ГX(HMӏ$F}Tn!Q&'8a925ib%  6t UBQLz"m(G4AJ[dYMb; &Ԫ; `@44;|@66F5]dITrK2$\hJtTY+YHFHԿfum$dM<nJU)"==  �#;a 񐅚uV4YxB4RU9 IZ@5Lv%!J5ELyPD "̓v9PU d;ʝB�5< P-Nw-UU"fJj*x P3 E!1NwǧuQ,L[eZ ˂J̓tbAuqzUPYəudkԘJcnٝ'ZA(4}Lt6{G65Uu zWe<۪6n+ PD.̾i7-S8 97V-CwYmUKgA.){#Х#ZZts#Z"neyC'.[!_F~HP~tHŰ -$g>TS+Wr,)tKw//+sN q^R)?dq5Y[mi gjL4PSkB-@rݫ1\v S)ve90_~"�xNZ ~u+z<SG0tf NwSBr^ 4}_Эp<_\̯./g~:x)S%ebR.U<yf0&!Ƀ|?o%GQ twqsJ-QR5;<==,F};jȓ nÑ�EeXv~;]0>9AUbH':"�26T0 e?{}r7M/o`{P8^u/zMwնM!4WgJ%R ASuPVMM(]S-^g=1b㋻ח+dMET7<\[a ٢Gӹe8Ϩ`JÏ�(yb3}ViI2dkfTws'4 ts9oɱkb c.4d0q3V4颋SmB!\t4J!8J|: S*##zѦ (…4R Mnf0pAMWl(=ot7$Nng6|6ov@!1x9_~Ъh?>gdDM& pzp :*ĪgEׯVT.G]#DNO5K'*WDIգT>@뻻qh".ؔ)i`3yZ7wcփВ+eq |)~ p$+mR pGWܤ̯n@oϛI#r%)3}!į[Ww7[k`>9 ,?M(%-ʻLQbqEM&s|x?w-P{oR /kH_^> L�=A5)n|TgbIh`:[.Y:;g|y}{ssj~y{;4(93 j"L}r{1۲MYRfjǧgX7ZPre  neow{*SYhQ"ӕG r ?&8$SSRK'Uq=Eۛۥ3!ȋ|=N.>xⶎ|[7wWKqunP^H!#R"A7ϯ(;SfZ<Ϟqa߳uhu!Xʯ$2GTzБ0}Glfdi7(^\K /*p\(Xy[E0+�ctwy9E͸Fkl&;6^&wa ]svxH3C^Fm.W:<oge#x@P̾H8lSv0X<qBstz1+{)IgRLr#?)٭l6JݿCL*lo&JY.CmswpIϠ?{tpthqI+oe83IH�dz#HRPaS{7S w- ?< 4&#BqAajH�H$76 &F23 ~,kkiV äb·MVt-^?|חY&{tR G}C嶒dpk#\!Hv6j/^F{yz~y:4"D iZeF)۪iL7ˇ19w* ][tYȤ67TO[lӜ4ݠd~~~.*`Ȥ ֚RUdw rz"=,6XQ1ɭlfLἕ瘣D<{.hhAWqwG"Ow~@mpS_fZF޿B!srAn]n3%jrv2>\QЌ02dSl!7 ~zx" Q@if}39DH#@"בi$ D#m^wN6A %Nbk)lm[vf==Ü*<mrJ4}x~&/7cfbP?߂%7V&UuѦ6[7{zyz@xv5zi^@�?þl˾gQ&JP\<=>Hnn'6wrnn3wHe6GvG^6 Λ=mL?}xw&O<=". |?F8RAvk{{-~Knf[¦,C"Q:~tqswjYha&/zQ~}~% z>T|tD`dYJ67[6D5,CxQF@;iaVyot |gp~q1 ÇopCٱUíwkvv<M%wISG.Ue3܌p=bKGz"o#o W@P4DLf~ d#%Tfb{;{ցQ6hݰ?˫{ 0移ŤG3 u<1B_>~DL\LG62+omtbLlo%S4iDHe/Z#O�0|f9)4?X;y}z~1ҙa* Yp(`HgJk'HIȽ|KV,uh0YQ_^^Ǿgȶӡ-M3~P|E�N-萼"j,IiA:hm$"!QoOLMsx:$Yp<}~7A%yZ{Lmp22ȶvR8қɍtB'66AE)|nn+1iZG921ZO+JKPcUkT(<3i#Ql.ڎmml*Шߩ-s2_w3ۻBi刀3mߤUPw8b}6hpOqtQuO?6>#C׺PL[nl;NnevGRķr OZ]GqX /XvZuw!~ZDVv6w?Jv2],Cxr˟fLhS;cQ1tgzl� 0 ozDe`hv];ہ|ɟ!4b[y<G._{Oөjx{njgÓzئ]RE,_F!5@@X:rƃ x}KN(MeNv l`#>m5J9$wf-jgvl I d&rM/d wth=iU>=8K=I|};։7~a-{\j1jn}k5'bQiv*..TS[1Ѱi烎Fz໋\,vxX8/՛ӃZQUη⹲lc?_g?~<.7|cm�hqfe[Ɇ\>=^ T ak4m//z`q;Qi,vT@?Rv:X8^'~'?oeAlss95AyYCt;L,&[Vxx? tc4HKC[˝_H�]feECf94K\M/fceO~Baxn}?ٍHRHrObFnL-^v0c^:fXorᣤ#<:Mqf`:vҿ@WC\LO$b'ggZJi5ObǻUW]a&0Vo&MuY5>aOX'jTQXmm"Ө䳱Wpce=zꛚO3˚nD1u7'??~?$fwLX6'yg( e`<]l6ۼd6blU$o~qz#?9=ʷUUdeEQuG YUX-XXnl,Yݯ~q#s?)z|/?:<*DSw7c1 xq31{?ɦP?g4>xeOϊ"?~o;GGGǕ*hE?wxV騎. bm PIGKtw$biR ~ǍRpުZEJ13tE�|A1<5$\fm }.ОRzNm/F4yEzl*2;<D0<fإtˁ}Bl(2N6;,T:iǻ& \Wщv[`W$Q] l`&kiv3j'еr~?W4Ͳ4Ir6'|OmѿOYtWf@cеZنi(tfOZ'p?5Ykq& CgǴ~}>9P']o ɏ4öKԖʜ"j"׹cȖ:\5m:9]h9zyʪTvJ}((tMov|#vڔ SV|Whw]|<->dd(+xcLs y^0`~lŚ5mbmjE-qozp3c5j|&Ќ ėL)}lkkCkR۱e{hKuSlk6<͞r~XTS;_Xi+Y04]S'm,s3h65P1'^,֌^K0bE' g<R_ߚOldXsʱ96.a:dy3"9VStKgcu�\n]1CXnDtA:n;WD|:渁H(uZGUs;ֻt~C=-OO_0c+2Oov~\i_̏�le+[Vle+[Vle+[Vle+[Vle+[Vle+[Vle+Z_; xc;R k2_2VjkdMv [,J n&kv:Mpwv(5?CAн Cߵ kn|:+Sc$ӵ+Eؖݹʈ]@t^4Jn#jæ(,]uF+H9tTٮK_\/;B.*[<" ˻LشL _r 7Н?tx?R%YsL0C"tv14Uh՚=+LvzaxT 08t&l <~*4M5rN?-Xm<.]a/fVWARM|~ñj-VEˁJ{0(%J;g[n4QM0[Ӯ.ݳaY^8etg05:}ױ4~77fE:GFzgt༏DBXT*+<�9YϢ;(4(`GPd዗5#."CtLU^C\;,@+Z,ɳFDryǣK ˜E8K9_-NY.زL:Ԥs#_k. ĎZ)1,ۨTl"p|S 9^la!MEQ $t7iABw9iBdX]or,T< c=_a Ịw̪x:½پM1jdYifD&ۭ 'ipg./ ߁盼^Sxgd4;GMAUh*-QyaKrz|ZgtGS,`/kBT;ܞ/EDUjwz= I`r|M'jn tnss,U,XIFR 4Jnu_^C2-Jvh ϳa}@`²,TgTM] di2jmxVCFIǀ/jcD˲GEp;H~@DWV2'>ݚmɺhm"BP|l}S|'txSrș?ȟӡk-"iweEu(*o8`:]-oJ $0[h0@I=hу~ڢʕmF0oP"a@D =l[U}ZF7\\-.ŨMtCЖŦ`xѳ/9F@H (^~, AZAqɕ '$ΐ ]y骶vV?^6g=6NȝQ28 b^~\l2mAqygjH#?UE0AؠW3E@ᐳ�p0+GuI 1]iU @#H&s5 UYQeL2/2%2v@-ˣxxOFe dCF\P\5Ex^l* ڴj:n@ |0N$0Y-0N]0UU4Z@6ZJ. aNOAC0.FhjQD\p6F;p$<.,˓ $Nle7%@(6| C=SzzSߨhXx5g<p\/'74M6cj8#֛j+s Hwߒe)�4kmA&PֱgZc"{:_Xxǃ,1RC0(/X p߃`6M^xoBh9بgd 8A YVRgQSwj$,/@RvsEpCː;^+(߭:ʖkyLU<8R[˦Vp!5^@(-T|v)xwD2rMv (D]d'`:fѣaK"*x#>P)z0l?ʲVETy/r+lUg�'&X#T *I R) M17p�AHXn iUk=]w(E-(njc%cZn �Hz0�]@Y ƑYV�jkFYZj?F0P=wej%@YPx&1,IGrr@hE!e�mZ{N 7+-oT ˊP\[ nh |A CdHh@DQ &(߮nk&xWQ`)4Ώ*<W?22,{ H1ݖ @-(R# /Ly뒈H^b䐟 CI@7 "tCc0L?2L_N7zCLӲ- *xY ( kæيb&!R#p<{bqC8}0GiJS>\Yqp"U{sRi:d189ƦX[h[L(ᶬK* ]!7Ar�YzT"0MC6+5O]A ^i]5as<˫h+2w6d 3 xt\Q�$x<#ˢ9 f*Jݮ]Wڂnλ^ f%h,=Nl 7</} 19'B="j|S4"K:sSF7ivϻ,崮Ԩ^ևb GGjjY%H(u*TVp7I zȭ0A3P-f[L~~T1qk~a=IG%*|%3깫K:a9"mȒeR(XG P؂n:cZU)5&$z^32J !Zv.0ȑ!AfFCPia}x�)yDP. 퓪 i:*�4]/p^֓#k DLWkJ^ۚDql2i 8Jf_+F.Q:A'AH vU Mܾk!o 9ZQ3"+b(ny<A}Tt �FOO+  R</Fe`JƦJہuzNe\peس:#�W nZ*ki�:[�`kQ=l(g7Nv.H|f2H;=M1hRTDr! �JITeE @dx4ئkwՓnȂ6$G:wdKGkYY&[ -;A, @FkʜW0i՚Ϲ2nv^Wt~@0L y\H 3́ DFuTR!^ o1vt NJ2I4gCG^Wy bD&=S M!#LCa[쾼x`NIi)zFᅦzKMmM'YN>%ڋ:`2x2fSR$j`@idVh&~ufq۷B^Q4/<]|Lu�GAf7c0+{&j =뫺*j p2Gt`a]9?+o޼y[Ĺ+' 01@=Wruq` /6/,+heEYAtm$3Xt�%|ͣ߼]|C> XvX*$lZ 2`!hzu5CMz/Hh qrZR5N+R*�'ۍZ<hf㟐ȎťNzHA`A{J_�څqA03 Y/㼦k(Hz4)lElY* ,/ʠq{*{O2Fa^nU5D$!!VU;|BG7, ]^x6Hf2)MaRbu"t(�iKix͝Ex~tvE+6AhAY{>-' iCI59Cv&,H u_zUI NK<P_YzwX74ɥ#!>0D]<O tH\?>ޠϤVH3qBb,sW,h OAŊ3*1սF)/"[8kN1L{D!n`8Z}ZcHf|G]iEF)$8AhȈuI MdXRU|WXbEg(QRDKSJaB6hAYCiW(UǍ˱~ќ#F"MV=+ JMO :F3EM GF!iY>Fh?X] K~Cz2 mVU]d_ӎ2[T)3ha<i !j3ziкt3:>B3v^Z}A>rK,eGAdQU ۲-[DiҺ` C౓o5 4qQ4a}۲4^Ru7 @ ]qF@h(Ld fOpY,mQ6;>jUJ~0vVCJ|튦1DZb bKmv4<d.dItA$shAՋl D2xR?[V/zf4Ҝx@8-�%kg+XAԅ>/1&^T}hy2!Etʊ&kkkGUY0%�{ 8- zߊK(MHDe)|_A7Ӏ+ pCɁ}6f7稧д|c8Res� ..gkj<G ofC}jI Lk ihf�J̰;*n<=_H߳ٔcZgz;SP,Q�pvy5tTz 8y嗧iPmz\/ 9IzƦ?MT"7U5|k}eW/MiyͿ2 kGcV_(t0+qZ5kԩ/[6b|sxw}5)1RPJQcMFPz+Giiq$,ƗAwcm'ի^ы 8^]MeQ0|?y*ogROo'b(1%^өu4uV dB&C_&R\Y?{5�fxy  W|~5ʾ&rN2gOna2J,Wz8\SWV="=#m!A..d/ңTvWΚ;‹PǦW]rnZ~*;m_,Ƿ1"ubE5Ѹ+˹S|<'Pd<WVjm k}<MdA: ,><@soy' C?|Çk_EqgAJjOheh21-i5c isucǑz*F|{ 8O“^ fؕ-?(X?}ӕ n'xDWTDUQi1"r~ :AIl$3DZԬ6:W<\[ѥJ2).1$?]$22V􊫛1ZBcZ_8$+샂0a]!(拤J\]DJW7S*HzEw\(C?]sGpz�xzww;F<Aʜp6A?_^8kvT@q #h|H˚5xx. 2NJ^U%H,>7+6u0ǧPwpp%4J9ɜI uzP2`}k"[n~^f"NF׏3Wʇǩgh ȺrE:Iͺ1Qo{R[uotc'TO;ɔrb<O2_?ljV8)FQ8 \VyEp&mH<㇒6:zO7yf?xױ5>TE崩i>aƟmvu;\M ~쨢bF7!*@Yˋl~RzSqkN/rzd6cG)hNJ=DU=:Z>LCffXNcW`tw>I4o`L/2bŠ LӧOw`0ͮgpr}Szz=9 pWص͕͊`xÛۛI 4pf<<<݁ hQLo鐼}yΌϟ?L|s*nf<rruge\y{ϴrL(Fnyu&eZ9 ;~/nPחS0b)H $X4ceNf'=pj}{memiNޭY o[]Y8f7ab[*{qΦWOO@kCI<  VEYdX^ӧfOΑXȅyq9zskue}mu}co/.oW땣efœq |z^?=<06A0pg-~E5Idȡӗϟ?p.oKI[:NFgwsmmuu}^o[\Z^Հյŕ#e4f||سhVX6ؚH<?B%ŕ.,qË͍Mfq:~u*Y`YP'~A 0 - MڪJZ↾cFB]G?"gեo.o6ӱ-_TvVyvq/\l7dq<Com/}|?ZjIۂ8btWX/O?~ݎf4 n6 ~pkɱBn//o$h}um{B3-W9X^?G½ bWe;ϙ�&Uˏdĭ$E[Tet4rt0{sRR///c�VWQ`KoB zzxpGZ$ }~o4[m ӗϠtkWNtHVu 2dZ'4\^Kk+o7wOpzBB`w۟<=(WwPYJ;giB!ARL/>/_>`3idi*:;xK+-T0ӋLE%Y{'cp}}xsuu5 Ar\Voח__9|xێch(m:ir]%=;J ySefXቜx5nǧk?wodt/@?ۿ}˗Oy-SX:�w닋Hw׶ζV7ϪLId:Sx � f=bv?}?}x� &ɤ TU.֖)�8n^܁5Au]T> rvu1N//sg:A?_i>H|{5ĥhS }3'z_ŗW޾YU.qW `D犃0J|�&=Ag贮>k&3�Qgt9~`9-p$^[G%յ7oW?48OAp|usX?~%S0j?S2tGD?|B)M|`�Tw<Gō7?駟^\YXY?h 46BQdP5GTď7E@� x OCћ־:Mwy5aN.(Eˡ@7.Q[=OoWwwA'/mZ G`8]"A0)/oz$}^qSZLW4/˟|"h$"|c zBQ闐[[[Ufh}ȍpT Cf7O,NWOosih'\g9:'^>}xwI,rKLW~egme}_^w/I_O")A2 ㈶e3tXQErOi6_s-vՋwkksJy~ng{`Б>Iӫ{t |5=Q?LT5E;?}=)SJ [gv6wW Ks[Y_oW/v T>eQ) (AŶc2DK"jh`E;*!�Q }z% q|jkrx|szr6/bѢBM뇧z-{]] dej|#=!^J2jv0 8NQ9G/Zy0ն@}N7wOwsՆhb\A"mY*0W Fq_*G;;{{[K˻}nX%zZzzxxƉ #+B븉XëۇksTM' ~4e'^t1ݓ'tj1zk՚99hƻz8??;0|l[~qywEZ8 e͸:CuTG;y_N`mqiU?oޮ5FON@NztЯ]4k'{vP\�A> zqu}u3ioT:Ud{뫛uk0x?0vWr-@;߳Fd7`p}w7R],ېb iYNh塵sL:vh*ƥ9<ѐ_ln,_4:<Gt*;[{f瘝A&$5Kká# $I-&ew_?UjK@ÚÃCu=Dz`Ɨ1lBQh#lYo0?qiTN<0Vӓu:HG鶴1]]>\t|߃f"OMhtˤgFNEd޽?JߌbKVhS]N*&Lb2yx4:bI,5tEfkՀc6<9Xi *9j^e@CR{[-ڞ2m00ӵ]SX4%i-H%Bkֻf/VaKQKPi;zZe$nnVuҷO:RAn8nnW y0<׽]~~M3-NPkMF&jBc+N$I8ϛ&hXhbٗdUm6AQ7~'H �5Ms^%q:&mÜ M۲v%.cT]monUfbY ~Jک tozMjЕ8rR֫G[A5ivoU <tBtSlWN$K‚YovSj,,7ǧgwG]^6$\Gs֦?>(@R[kR t=H:UEnUmxhm0ʁgq*>;bi0?oGwߡ>./hZtw{wwks}eqeң{zUg9dlrUjGt˲ 8^,ϐ!6Oz[lu'{8v]ً8~}P_t�,('uhv7J' m�Rz{aO@ A}; Siۆ*K/;U0ޥje U#H1sՋ(PiNðW#rxቬa} $R:P w{n�o{ye-~fvio_qUM/+}H[<vV í:=zw"OzS$vډrZqn1 M;N1# 黕�^>,:mC>=ndț~_6ò $-77; 7N&+ [?/i4c=Zʢ|Ov槅btxZWR mFї~5W@ZBBD,*Q 4ݕCw->2vGQYp[kv.8N~ox7*}i}=iTVF{ 9EHIטC4uSF{+v_ǃ;kGV麔ڙm[#Fwl菴u|Hgo AJSdm0<v.i{y>/+W{W{W{W{W{W{W{W{W{W{W{W{W{W{W{W{W{W{W{W{W{W{徴yWj}eKN7G/^v8QPtRKU4tEq>ӧg<ϋ9tf!4MBې7xY j:Fa-0rt/c.M~okk,+t1rR'k}g;f&K\xZ˦%kWU7-7=*~;$iøt#{Xq♪I>oG5]~ ZIض7O8IZ[PKkP/Mw ε:g:q( lxU 4r U{ta r=D0Iǀ㚕阿D˲9ﻖ)&^KfL02n8{QeZO=R]KkԷ4:]-c0^^KJL r0 e̻.u ug*ZJE_8mk,[H# ,>˪*` ޺7n@]l|=wX_o8n+4.3j[t|  S׫"I ͥ˦YzVAQǷ;~ZV[umQϪ"Je /K8R[^MW^CۭjrilŠKRk' ]Z;�pTR{t]G8d"p°S:^49zq2em ,kmi`x]| =LMz~%I{,uH qQQd#]ݢFr- oZRUQshK*ƣ# 7[LJmż+<,Tгq|끅av[u�xRa⵻<1kG[GX\/H("!2QAX3L \`vyUU"t4dz #UU`,iH8 ŹcyvG?n~氡1@ ϡݺ&=_"wE7]a1EQY@ZL_ԀD"FBi.8]u8$('v\"4-yct8ᠠ~ޱc bͭS ߒuzW&eA$QGsQ- /q &_zϦWj`e;fhp?B`c`wN51 żA7O ķ 6,SuBѐ!b@-Qa czX[|Ws~YhYy>( UjÜWIbtV.tƫ iS uAQ EF QT«�:#ݘ2/G8VQ=H<\pP#Ame [Q"@E$0 axx0w=dIV#SK"65Í<ƻ=0!/w6HJ| vTW;IH6ALr2>( a["u0/ou,<~ P2!<C򦌪ityI^ :3 Lu #ZAg:N�`ROķ-;LQj+zӒt6+.N B&zF]5mš^ 'ɰL!iP px^ VCM1Tc[Z@~C1< PyIG>D"#]d } Errx:ʢsf,?%BD|O,&+j?Bwu9Np\#:MҔZ$@Q+T:  DUK=UuqNSP(Tn<u,u0nǶ 4YǨ.i^Qyb$ :,02rhLju'Oc<FL ^1$ҨlɠM"4U: n6" �c[Ah.kGQpvpQ9h=sLc^J Hj%zгj!M1KʑIaZ�N8ȋqdkg''5~>oeh/]V$pQ_7MŦ`~:TaZQ>0 j(ԩҥZ8!VG_գC0`(˒v:VtWyi;/ufh8 @q M$M{CPOĬxgx:J,׮UF!^@Y+"۬tyeޞ6MD%Jㅨ PY@ gZy3@!mJBBڍyɣzx2ID:pLjf_PL~pSx^ƃȥNcpA$%h: bˋ51H\ ՚Fѕ-=bt$#v}TEfXűd CC z- h:t(yF6 ߷Ì(0ᚕzhO(:* ,8FL]vGT \Kߋ+! E!QrȀe4bpښ,SQzVhk-v[Lcjuk`p|4xN8XEPZViOGx!EGE<N(�IM5w^ 2HyZmˋ>ֻ*Bo8qQ�Kh9I|U!m+vE,b\$ (A NF ВƠK$x@\CT"t%r]wὨ\+heQټ8naɖ'Ԧj塍>8"�d" Sq *hZ\QQ5Cƴa Z|@ \^;nWCi !A|<4E9L Pƿ.k lf>%ڑuGư:, ,0eCXƵ23eV, ;r_v8n20LI% $ _G ~I a4 BŎA QQ&ߡ(/x RYL/~m6xQm4N@T#ԕc�&q _׍ôȒ43=VY ̦CP_IGeM7.p(b'2}YW,G(FtX PNd퉢)jQzGc!?M \ѲޞP&&*uX{l:Γibh'+A$ЦbINcV0gA!c1$Ifiy)v-Vs )dN1]?NRWYN{^O&N3 sNbX'!L#h1]S<;6 CB2)P BjKS}Ww|w~lZÈ`ITU^ 'LX*p\\'U Tyqfm & 8AX8qP!\K5'NJI8nRbVSmހv6MZ tr\qj,]Z]__]iZ'*?ѪiEd;E3h5�}xL^tlӚHm2LjHI>j%e;,'&V- A7�U=Qk]JP@ /_s{Eq% kkkZʢ57%IqCG+kM8ªۛN-CC߸WOӂ, %Jg�1Nh\(tDUg_\-ddύQXRbz[b1WB2 zND+wǓlۚÛ2W J}JlUEDQ7Oe+8c c94W{?Y cZ0ڡEuh/D Ɠ67%dM S8)l Sj'WE%S+\ xwa9r|mm j5+'$V TG"e9N_;@=׫f=-.SN%%<҈Dp;M]Su90[mTl⚭[_[mm]�S7'4SXή;r a!15:A/Y7]mgNX%˰J,+fc 9*Se 4&u𺯲0gώRv=Z`c}V5I 3%0ٛK4fp |>A!S9sik K!P&"2(,k/!<ׅoYɪ<prd`uPi~@%hy~˦0N:~|ٰƄ \&- p/Q Jl.~qհZkԪN%{A JWIyƖ%NVB$<� ZQ/K8-gVw; ohP(=W[p~ѐr*JTswйӄU6M"/U5DjY0rquR]VJB ~۪#8Иݏ^^izo<Gpo6jjb !ڞCT<'Mgp;is^h_u%,)eH%Z0)\4 IL"B"-LEjdmֹ Wmt /)VPؖH2mL<o֗h"N{2qZl) /�)aÉiXDi[Y 1Gn^qZm0&rXsUȩejs b8Dm {\zUZjZ6:DɰmR96NQ N(Iu[l2ь~畦Dͯ7xK[ltbfZt *Q/r#Z:%"5tqXT `.lUQE#'deGZ@-k@ l>5i& kOJh;po9Y(eK\%}&5PZ4ifžd4K xQȥ9xh8^ehNjۈV:CiirPʗ3WwNFt{nXn~nFžٸb9ZEvqA`F9FmUJ`{DV.sJu-A�9pYi]jL@REkzQqo m2J儭_5T1[Rt'D"vð1|Ӱ]咍lGػUz穨kFc|IK6fΎnGֽ^?w;+o]fonb `i{8hP�^;q; ?}z4Q{w54P@iy@*7w.J2ߦ6/6bI4*)PPPS⋬bO!@-#w{Y} l%LK]vGҔK 7q x7Gm7[2u\L>>皯-ٻMMP¨;}8?,:|FuEso*xPmxyo5"X8eT4}-^,/N;>}?u>n3,|4lQ?<=?<??҂X6~di\֠vvPFұDN6U%Rg0po7۽|֫{I|xSؓ|HR~:l:8RN'n5[P.ZEKqۻmĹe=�[7P'٬_! `\% 6;NC_*rQG {KrAPlF^O p*X�H}QX^3|ү H{^M-uEMÖW|Kd* BI;GV휝rU"MJ+zsX{LG}/x~4b8PjNQ3Zp;CeAhw'gWEC~�N ws$Y& "ٯtHTUr_Gx~,>uK/;3 b ]hEpquxtVm8]®H EROrq^8AզeIFFN A?'`44>e۽vwQ)@Lw4٨Ss|WA٘f겗BkvKM@] ?o5YjIFu:u;Z]CHiA&\9:u5M;oFop񜔞:@aoouuŰ;yKVmzמWY[=SNl^ <k=t(QJԼvԏ 7ի~6gSO%&wND-2L7Ǘi;jMn"EKm?N5 >b%#GUM&W=PM7kG)gd?,GHt2վ�dmЉ6bM8M#fwkRSjt79M2g{Xlc2k򉽍jȥmz^NGEbЭ^38f͔:ecUGܜĠZlktsc}c3;�e=}CMj; -XEjg2Lb^ЭL ݣX\}Kl�|.s;I^Vlshg}m}}}4EK:xZR0 *Jo_Al '.!P.Q[lz|zv֠]Awk6E`b)dz4q�5WaD1pqV nM[amm'K/+<85ifoih1OD(ޓsU0r:PȉbR'G0Zl{{熫-<Yx+ E7m?>*@[zp=,&Dӆv6V7 4M%oV每hsln˹6HOn\5 Ťm:<vy IФ=v|g#vaZj&?^ܺ*0%5][Yر:;`K (olx>2<F&_>~zφJBkBR7L$0YLYb;[H04Y{kt{HKҙrypF.wv{vz)^H^~ӧO/tn炢­V'+m!cuw>ؾ(prv耼Q%ӌ%AfKo aD_<|Qڏ-ZTiWEeSHflsz{m};~{}V*+*M}fЙp<,pǥpO/xM+�wl�Z;w|򄀟,+E> VdŶQbb(X᷻;P6UZ+Ϡ~u^> ?no=3\<?>Gs]v#\9Bi:kݽ pov%OHT>ȏ|AB) ȩ6WH~ة#W^{ZOG]ppuǠ"]yc'G)dc<f4WDj%dEieZm@vHxG Drd86}mW߭%P3h[zS2BqE\ #(6b?|XE1GdaKŎz b ̡bn6#|ss�DҔYɬȥ{"Fqz0D?\[] 9X]6ֿ۸(8AP"THX?Mp.˼AVW,ףS,]eN˧| 7ZԱI㍍խe9Vs?u~8#RT/G|{) [{aD~{, NY:O/D;DIkoif*c|k>FemuJaq,ReuXgQug8E0}*^k0KUV.o ^WjAK<)Jb)u۱%:=\[q6RTuٗ 0YPjOg-xfstdRcd".6766ck{[;W LMQ'N[d1 Bj9WQO(ߴM](j*8::;Olm2mqZfy<h3 *f*,dX#$/tQ??h5Eק{''G;Pus}7U^vw7IMU6S=Ip\6TE: d7�rNs7ldsũNb;$ۣˋ˻RKx??O67woXC$YN`B1usB͛HQlvyR,˼ aZ룽LVӫ eJ M6}qy*O\\$!syuw{y{\�qb@W V7! W*s;xXZ5 jxspxr+(]2&riowkl3g;wyaʙdES ˳$ v&q:sK%.1 ^uzרtpvt�,/ٻح3CT3ٍOMʢ[ <F]vh6n.VT2a‰@F؟ǽi6\_vJb=c-kǃnraDuوb쒒qLǽmB|с geAhCD=˫I:RuhXܜ܈^ ӻmDR>;CSH2"zXUx/j;)+uz R"ҥ9�e'q?~ǵ4֚MdtjXwq (h&6%6L֩:Щ8oY.3. �ʊ$|!]UOM/___:ud~u_ <V5j:,&KCKhV%PdeE._lbg)^QbE >TWJmo<p_w#:Je_thfwٲ倵#u(2\er qtRbm<dN ) m[!]K:o-騪AmzUeZAr|}|x~詅&tVacN2P D݈Dɤ_4/k r(pyAU%BZh%r:^^.+a*fWuۣۡO1WEEH$`_XϢ0<+ WhiRPLJ %:eF*Nվ3.iKKdȣ@}Q5ICddr`q%~qWe- S{8MfyUķ٫[ goô}K|1:UE^EX5T cZ2ǰtm,1ɜ鶩*4kr"iN7ֲ<:ojbqא$m6qr%RxAހB]& Iŋ@ƶLm][I&Z߯9R݀ECBh(۵$VDD2x_|Xgo )[lJhF qV aP9Fg3!s :/h"Kd2[,-#uWt"U:(lUNt5:#X^U]LRFThNտ-]?]6~qzpz[`Ej |* [6zz 09Te CWXPZT ҵr]vzhѝƤ[ȷ$ERD˞Gyt˴FБ.ݚ-={ V./пsVhqQwku.nt mޤj jB֙e݋͝uڅ p}]Inm|I`H3+�ַxY{Ǽ;٭;9ܬn �خopy,#y;C 㿵?o :UVeA5 S;@BߤQm:wWVT_ ~;_/aa78(mZ_deY3jˠWžo+fpjzQF+}&{SOa勂6=%k5}"Nۍjf*kVZN^ө9d�w^;r+&)+ Q"GN X�{QXZ,:r+~hq5h糡[et>E;l: 6ޥ4PJ~KE.9}VໍZ53N--6ðQso)Ldӫki9 2e_mM G7\QYJKɒu[5ʊDqn߽HJV־)sW啈8s01>)BKF=rrBۻ`{o(R'rrF;lo!GĽr%"yگ9 #;tuXA( |{pɲw3օA#-DZز˻˻˻˻˻˻˻˻˻˻˻˻˻˻˻˻˻˻˻˻|c"%ݵP;])~k^)Bwr˦S+ٕ|O/]3ٕ\.WakArWQ.v .(b;P\ߵ2|dsowqTjtHxA430R1VlWKYEw=(ljɤk/\KCno4&XReA`̱e,^F+NO))s|6L,s*H4-s<Ƕ[@韮LQjt=ݽnz&|6.Q "EVByGA]WOU.t <*qܯ1)]bxaXU 5 ?XL[.4L_`Xs,|zNs动6deyOKӹ[>o7TtN _&yҼW2Ô N0lӄ#y,$ZEc=G/_^o>{A.L.S( |&]$ãm�2YQסDiӤ@7xHm4^s仳*ʜݦәd6HrB.W(Wxxg._xxÎȀbEy4s*׷%R4V.WL"V*$!sp]äJWV]qiX e«E6/E7}dtIeS( gx,EٲMi̳c-S6J!_b8Q\,RZ gy&"#n`z5tKS0uWt+QD%QbiYH\E^^Hjo5G`Ukl3lSs pQtmVΦRr)YUKGP) }/RF0Pu[MnCe+E 9mtir*SJ'D:s}D߿,rUkV'Ql^T+O78FE^f-u5◧7YPJ_eЯgn[NjuK5[BjT6H;†!ݾ mKb T":aCVG^E4؛5Gz;ޕ9H,"Ђfz Um/GIdx3fMiHPF j"Y(%; OL%SV,zEMٌ)5`sCz!Cpfj۳dmw R]xrU<XPt"qaP`TrÏ@vuyUlZ^ }rJ޶@}`/s X6^V5 <!ay4٬G5WPk]_\ jEV$dH8F5IMS ʉH|Dl9|FDrD,i ]}\ڭvh5a=䑧L3$lUr dATB4|IooVrB翬sEW+0@:d+nR Y#"84vZЎcɒ3 U"ufhudFDBSTM=�ɪsIyx\+01Tz*9S%6?Q ގ FN͟T6B]<y)�y)K-DZ,dfDȥvL,!Ǚd>$>Wgkv LDJrւ L:˞Ք)yÂ5@#ȸd@/{[&Y"9N)culh$i1bwğ gXEжu2si*� AF}UE5l0SjL @q<ºM[m+ AkNȊZ%38I?z^ӄ}zKCgy/b�h D3æҮcnvbd\'x[7- + ѓo/5T,5VlYY^Q zLDH/AB.R ~Ewyqݸ<8hդ]VLl?`I{ EɤCRjIYƮ@((M w/NWNNHO!|gճ3a)1BL3}�`9\Z_cY:ٜ$8�<J;"XI+6Bqvzx|rPqzJ+WGut<_ڂqE(%dN ڡC !,Jm> s$QyC!ӳӕHv?k0MTv\988:�;F!. Kp6_UmVþO>熀CaZ!4uVY'ۊ4PNhtk|kM0 -EJ<+$襎n;SSc$yW)*<D! J[6VDˆbi%Wϵl2KbR몺tJSuj>).MM˒A@,(id�Q#)oE-bN4p0,kV c,(]mҺ&cYЎħy^@EA*e}`0c* s#4uWt6\/ƗgںSmNI%2r2uv}yQeQǢS94p9ϡQ@*$&o/?p0VXɔK-Ǻj[R Kt&^9OzC! U?ڤu٭_T{`sXz;v(ǼBSeYTaeK785݃@lʜÏb46 BB [W " 8G1Y0'F*DC崻b‘)H^%�gցjDjw+QD 2vL'OirE5TYka]v%A^ٺ!X(0)m̅N'$x.ƭZXRUGB[x ȵL;Lr tRd#eY/(:xFh8OvBYR,lU蜓ƞ ŖbX@gCa⚸٨H@Nښjƥ+* |Q9Hd![?Sau68 zKS|Qyt$<G,c2IHKQYUi(! Hn]툺. GUTB!:$!aV&t)K@^ʲp</j(ݶ%K̋4u )9?`ڒHJA4t֨z0DEP<--4)a}�n+ZlsJJxD$F;Kr1Z^1 tK{` B aPaadO92?HA!MoNd!xK�[5 'O'iET{jv|< چU[O$4 T7@FdЈCKXR�2W�6+uL{B* ?EP}5_kZF)v¬LG& !mib*Yo+4a�KmL" 4/X-}Jc3&5/ZD=s0bszՂ,? 'IHWIЫ6nب1H, ^Bcal+BW T Y"_>VMpG ~#F sp\_e֕;ǫyKn1xa(<AmmP?Š@s/l^T/ KU̕Y n(]E% B PØ.@WȀ:6r7%" g*>gY:A5o3 ꛫ?~Rͱ Tj]VuxL,]L (e}U{9UIh_tg޴|6A~dfFULm|;UfH'O} ^ ҵ8uŊABLiw]ڭM486"r%M度k2Ǔkp"xe{0{Ͽ,hu /tA Sjs]$&l:Lg0"?C}9djTҘ.22D{̯Ͷl0]#"@FU7Dߎ,"PUԙB0Xv"bU /8j_ovx1 QHb˔:ZSP@T�c2e'B۫/AW6!-Y$N$M@`zQ x9uz+.I(KIF@lЇLY%dǵ+�P})@_fF3< g 쥮el>t%^L8H!e啋Ed!!JI[%t"I2;/�ʍi-D|dH`Ѝtq@0YfI` OފBFtH2ȤS14� InQ5(}Xk2^w!Ţ~ <> kL앓f:wj 22 3NOUlߑ+GG!fbAUӴ4vUchEs-:G^Nuղ񤈐*tT$3WfdmCP3B99c*# Z;:lE/[r'|:Kt قޱ6t,d )`y� I } YZ~Xv<J[NI{(߶&ym0h &U5۟N;v%W+< K`%߾=7ё-ȋ7?<>?.wt6=Bl4l"C1\k2pRH{ =ǃ.޹) B8/S;aYܦ(&ÏM7e!<g Gۇ{d|2O)Cn�kCV!+ G6%dfKYN>~8 kNv>]^QHC?}|z0h<wp4z(G!1ءzezCyc(]ڷևOuW.lH|NuŐMhϟ???Nz/~|p7ŷyL+lMS!,`TMp4(_Q0E}yavqxV7bN7yKc^B a/na2v +o_l<B ]$̓NoH {:hm�%XTǍKv+/}l%)Ӊbqs럿MEhЧH||/]S o TOwMV9V*¥aYGtuw6+ HٶWLg9w7tz0+EB,Tr驴Q zCXe !qM1fkx8L'~0 O6.,eO\̰ɢ`&ߔ`r ̘Mf_}ГG2R<)7秾 Ҝ8 .7d"r Jx<E�'~Q"g3懣>Y fS4]ajŋ{L˷^B/Q;md, =>EbC�UrzN'gp6p1Sy+`4ho\t4: JK�%=ye!=8@T vd�}TB,yxM@=.&mt*p:r@2ce9`<O/9݊�e046HwOϟ4h*6"h5 ! 0'ww7=ߖrFУc:�eݣk{Ѡ�qšޏLĊyzAaeĊCyxircq:><y߃~$bގl7!iz4]H2=?h1?qLA=~h؃G ),!h1M`'!iN~x@n u<p<B`=I~/==>o{7#=Ow7PDnrP nB/xuu9~BٓjN2MET.f:]-norI'x@iX^㋾}rs0//`pd<I Y6#!UUh:ceܴq>X:P/,@/=GםMcΉ@uX+eN ~{=cowbAf,,/ {x Y9dXT/{r['bdeil (@Z ƽѯ/`k3п ǃ>bϫn:h3dG晦+b;n6#N&A>{)aϓ4+w]<|0N:3}:PkԶ>Cd6EN<@t,ǃ(s6<+nEozw*y{wqs{7[n/<XeNnnoաXϟ' n.\}ح#̑EIA>كX_x[i(P%?a#E,gJ_ |#LtvlV (rMB$4[[[[G -Bs2=`= AP77f6<?pܨw2SJ̟AwtȳI|osmmmumsJ/76ޯo@\\ 3 ! un R,K蜭,'f?}8=[ʖ;|qV_]]Hpi%7O//?mo}\];ۛkAC,yҽبLQYP$na4P(!8 <}\UI Q};YW뜜}Xȍݽ㫋>ne0Sl)d=<do{Ya:ѝ[muv6QЙi^뢾UT:oקS<ޮV;xwyym{+[;{>ncZuhz;L5vP]HNjz<Lt?C\Fg_̭w !0)jdb;$ڧOەb{q0k&:n'3hy{˜+ VgQ%385Q<R~lSomml}uu]&ۍӒC>,&#mHɗf0~$ &8)_ ӧ `*xk6<Vi7XVuk}um}s2$N0y"//aQ'h?SOO&̠ucJƊpFN@li|=ԵFpkcP)kN1'@";ۿ˿ a~-בq{VASVm]8z(&Tc=$ez|%I q$T/yeE{ʋۗX~CضI S& \yuH}Ж5:I\Iw4Ɏo4z$9a>.43J$0iTiW٫j:h ,С-Vo߾`¡f^ya b{}K1 o #:|e4Ӻ.n|X[FؿCpk2=-,:ekNG#E KI;cU0Q`'EDt/O7HB F5Ӑ>`)RJӊ~kHjDq'c53~q;@y]+^#@g Yp{Їɠ_I'(<7-mD3 <:w( (>2`<-(? ? 2<^}Hrcʢb{=ڲyGKiBYM<s2*V#X(-VgwƇqN'!ۨOGnr<#2pwSƃgF0מ׼[S(d??ǣr0BI"d~S~F{P1N5#S6?_O; Y4p<u1j$nn{Ueːsa�=̆@c�OC4t{??[p@wy@dsR$"Cɝ?!È40pxM ΰH]1)Eo04 4:M ;$Mo6771HETNw/0 wpǮm5z|Y�wJjI}i\lQ(k8;:><KBm1yOu� "zȘtOw>m6[7vw>nb|quޮonndIDI7a Y9ѭl{OQØNKw7[ýF_~{yIkWNO..Ϸ׷{|T鶨I+f!F`8l&U2X01?J[6??= Cp9<wNOjX?zd<5$4fõ|9~purry~VVU9ܪ˨w :u-M-)܃atL?9t5`6?Y_&8jU!NtqvJyxո<<j:wy]!a~>^]HPA?!" }5 rsx-E';oe󛻑uw4WN?TX^ c3߿n{â>&n'7 (UD'�:,1&]=?~Y\|SF4nT XzODKXhWgOQˆ],nܳ䠦.mchE;;y޴s!i+Q^Q<āQ|تht#.&<s|Eb6DtˈnG!IS źGW?w\S!\"HWyj&2v:GY?׷^j)^9]n놨hi;tMgbW'*QEN ʓ4wjew>3[끘e~ c뽪 `MFgbB{v* @6Z jG4(Z;դa&1ĶK]TݒT%z^ZC1먕$iv&kq:e/}yu1 8_u*c, mj|żND$u!5 E5t[`os"^0%) O>:AFTϋ UPѨq 6 Xtݷ,)nم]9cb[F?d̓67$R-Dƾehp< H4Y<%7%x~ Ҭvˢ̳d٤S:-ԋqaNAݐA?LԘb(%ھGzϡD^0YQ8dQ;1sJS)+B_G{U �Hh* %1WCmLYЬ ,#VO< $Ÿ#QA{}*5�R=O>�Mm?_+7Cyץ9ؘE}/ NT$) (6Y<?\%ۦ2Mt Qqz/yX+N],zS_H^}vf`:ZA~B'5\dhl?={f􋇼|CaУ�kQG2śnJ:l' C&𶟏yK|zfft%vK46fӗT~V$w7$ey G/UXZ"W~!K+ZKSV5Mwb4|y.99VðYݍ(yB1y({uEMb0H=u9d8ޱYm :`LEOD"ؿ} k Ae9& ƣ:@q`s ruRGJj2s�y˟$Q4ȐԷ[?DRU]ԫ:ң6ZpcAQ؍SFW)mto3h^t$ѕ?(YXpw {2 ~EB)$/l08q ŋc9ޕƣ0u,^% ^~`(k6Y cϬ7,?<&M{5M&7uA]z?8@0i妳kIG5*U=ܠ|?&(|Qh3?)_ifs%w^\C fq1Ž+s&^YA:wŋ08Pt&7Fn3ni9uH0~[?y4g[k7-NXf5e旱:=w~u_0>gJa>@4H],V\AA(icoOrr:nD6k5N~ym ݘ6v[ #uZ.kt;=\$ ؤ_P2O 5/e;mBti꧿gk/< 2X=T\ϵW懬sxQ937AX~aruU3t< .OgY+5\[6sQYkG |)G *Als?0djK䳭Z(<hiZZv^Gɲ(g?~@Ŭ4 ?+y>G {Gͥ e#\~hz|^93ىe/GGe/w*5cӺ}e~Bw MMfWM/̲GZA!9:l]ۋi?rJSg@ubA ŝ| GMZU4:byDak݈^5d:qvyC_6xom6xom6xom6xom6xom0?n%B^Y11ގ}ֿ]Y98kfcq9$JyQTZ-/w {^`[VI-~,2yo"6̵ry]otnc' 눚IΟc+- v;zhS࿿mrWdg%$DٰwO :J~LEըb!($:5EfKs0opCףj\t2\ B~P} 'tEk#vja;M"%Rfv8KwVRc6wG>~lԨСX=d,S;f�1w .&]$*Omjziib^vUEdAP- j \{ .֐()>0"q\ {AکUWj-r3dۮ7:/OF!.K{bU)*YҒvjpR.ϯjMJ"\`\\HfdD휙+udg5ˠ4b{Z)H^T,['nIMLE;6KQye3ǐ|jf&uFL N]ٻhtq)61;L}K:4]颢8Q}km<Fn[j i(0a׵VёL֘jW6,,*YF ҐT"c_t]kY8Ԗt \ܼж) B~]drɐ]ZD.,4 rqCA]PUz],v]Ulrq)d4V891 BB@8gYLr4N<E #`cHXX+5Ni{ImGVYdeQXs}~v~pWYVE+}Y ;$0"-Kn7Z2|K?$,pd*6NπwWĽްdMiiŶ ڮ\߿4A m3FGVqqQODjD40`8$Lݔ4%idu: )2A'S֖l#$/ȝWqÑ:H<A ix0*,fAnqCֺNM/-]RQ\C31Uby,!\1^2a\+%>ɝ'!V�[d qte(+ZgN] #jR1WVt3O \`L;9>QE4uK˺.PЂ e˔-b#rqs1<(Lޠ0552#ČGH, Fu'T4[$~~~̜jJ]+O~!Of, <^ i  pĻIıH, Ag Y6YՎ.M2'irWU-`"uC5,mX!g@Drr 7E2Ȣ�52@PSsÓ˫&j]ؕgrMBL5\^)gŘv`!`(j&"˃UHJpwTF4\-B]ˎ7m{q ЪjZndRD \moW M~%8^[B�Qe18%L2w4,3n ]0С)h5.uL]4tAZSl;@3O]St 5Pu^r4(�iIWC"f$%$`> + CF^s:3T_oh!8r.<9:;98;;o]UTW2TkKNzaD^: eظ׮E]u�* գ_k 2 ?v HvP9>T./>]qרT/O/ꢁG(DsA"Yl4`m$w*lW(D5HlZox"w./˫N.B?2$CtJS@: i QNjDQV(*GK�i,hBV? "PUL8MOjU!OndhCs4׾Zپ\VPhc?K/,$XY?#;yYhY/6;M SvcUvVtzYiH]זfhqlلdmVOW.!eZ!]_Lqmr4pt: +5sA  nz mQ^Agh+25*Վ*4ї)�T8)zeKhli-e0f 6{ը[ -xES:Ն`;A>GdZ?  \6YS'ϸwE""�Thr0e ݸOaQp pv|V A(f鸏_;\R.Y6NF "VTmσrtKB{DW~* iKbvrUe)ߑyf6)rM(W*k lKi׺(Ѣn{`GI:!ӥ%wK**d젟�5J# cW6Glvdv"\Y0x<Of7 |QDk  TIWb^F͝@ O\7#IÔE Rg|/8qm07K3:U\:b.#%m Z䚢FrlF(-ijGɭZGG%JTݠ3g)]BL3,E⏥TdX HiYB�$4Pp$t/L8t QCԡ'sߦXѬ+kˈL#cQa5OfMRd[bSvm?mȑ$\ICze#MXkj-%Ԙμfۆ0BOT24E1nB+ �^1 )L{eJ6+-\|e;DB41XsTӋۉ D=@?bNu]gɪEE]£.hk@zP䐜d<+�yh'̃hN氘uU2xr?pt2_J%Ys::'JA?VxK;QQ6yzX{A@K<1/3|5s 7}]ӉwFkAJjIT ? T^a,Kˊ j8A0&0~K D`QcuZa䶄Qԥf [Y$#e�io6.YXH-M> ?PHS2]sA+A@E,,b|$@i+ r#[7-oF%\[eCz`7Lc#hztVkw5O5vmid)SXfZ_$.[Hw(%['6f#޼ 7WLoߓPwy3;CF0Ѣ(Jd9޼7K;a B[d {ㆍB&fүYe*<S ݪlKUp@Z!$RM9(yqӧyDzG\s{uF#GQY,dQз2#H\`{6jXW%6|�] Zhuq]EªFK\Uz-,PDIsUh7tI,cWH�$MoSSxAQ3fXճe Vh2DN1<OACb,T8ӥ]Qq#D1.5-aאbYl `$VQQ,om\ӂb1"5*ʱD$~U zDܦAP<Pa+dlG2b dtr-7r*5GRJWhu;}lQ.Q \R6|҄5Q\E~g6 TD41]Z˫ypjGrs SruӁX-Qe,~e4|ST36B=$koGAnS(z}<GId`ZFO ĕp>K, ێغg*0heֻ͝wS[,X!�ypu&0dGp2Ac:.pð ݝ]R߯ s�<\Q4\'6P@͟77Fo^or./Uq] -VBk;�`4%nFGQecIJhēqMD5* /�oD5wt)uÀWuj{s06j !Z3jPt\-DF<긦w(=ѠAQIBnhɀ&54ٴe+\4_ #n c$t 9/ׂ/doK&b BQ-eD! "AH;-2Gd,S'uJ FuIZٸ% ,SG#+Yk!&|3aDT"Udq4O ݐU9J[z,Qg8{pbѰs]OWQvU8kkiR,xՀLxVV`\*UaEp454,d/擶+\>U1[~m}Fc-K?=/Ԛ5f ֣V޶.NSySLߦy ZOhC"gs~ՏP-|&u "UQhi,i1{W uٳ0">E *zu+oYgIa]$]p4�+a4٫VD!ێNNʹLUt4_Y7t*F<jz %9%OEC2K^ -?uzzppyMxbp<ͦÆ IS/?|z4u*lEx㧏O|VE l("Urb6:]<QJ{b7۫ӳ;<?U֛(IeE ?~6hZ&_/Ql׫/ˇr*0Sj""y>ϖˏ˼wvEq:j|țvd"Y yJC:Rv6]Brϟ~bk7M B!WuNj_^&jwf][8MElF^ۊJ5ZhjТdK&OBX ݐH{Sb;z~y1QP aLHjvG珿ghj +pT~4< pz)v7:<%nuAX~89>90UA(bpF#kV ݜ=?/g^=Jby~Fk_MSD/ &Mwt>{y F#6G=^o04{g79'Errf:%$`)_՝QV,0/asBJ_ĤΖ=5VwڈVvw됋!vG"t &ge=L\ʋF8}~~y?bC|U ÕS)Kl)6D =(=k^HmΠ:z9wȷiZu󛇢�ze^ H`{(ii.ji:)`ZJUk!2QQ7c׬ pQU zV7۴ۼQ![ 6|Y1˧y֣%FO 1nS:Ut7=E`͖t:u[t2BY= Fnt?J= ݘo+buO//E?Z$�o.ָ}Z{EVО?=܄{HfsѠ7,A֘kzZ6?9ITt�UQ{8]aX(t} $gEBs^MFYAk�ʬvɈdzl6@V*(-pi eߠߡGE7h<8{&S ^Twz^-^qRP$PZD"ʱU@h4NWycgvg0Nf mE¡n w"F,Yz2N7$4=mCUI~\vj`PflMG h!Bp,5uƀ~5z>m3Vl9@FphO+VܚVtL 2Wmrec`sMM -?</uA9mX@;5gOoV*b�/7R A0spzU4{6lԯEp݉gVD9bڎGUv_|P yنN͏&/O n ık5L(_!J|hK=ftݎ^HJٰۛP'vݧ>W\T<rXMgD|)Œή}>bV.=DV(=dYS׬a8VӾA%@Ӳ&8rE\i }',$Sľij~4*M$Z> - FvP>;NĶOzs,5z͌dqOiE@)5� |zC*;^@g;ݼ|�Sfu*yW=ֻӴS$x{q{5P*db]fVUE<-VHyw>Gj+N͟?,F:j/OObʜ$U+t +~:|q>ޝ�K_4۲UED6t}?!q)<n C3X<2B0M1^탟%bQ_Z3bPJl{sx<?)Il:=l=/1[ڔwQn+`g*_+`zuh _jg?]xgJ]P6m0j6_HeX6{qxup_$OҏeGEWiM1f\W?6<ZޣwvU Ŧn PWDI>Ho8-h�PU3E2xȔ ŠKfv6w4jy;,m9*KF #lG(ThoL?}[Wۻw9Ι.pC /CrN Co�>de]6ЮoEұ}.pgDr15q{tLK" BF/?~Heo4% k鼽sr̤K\,KLޜn13&M�0oZ^GtzӧOD_?^f]"z@jSnw77? ceA<=>Jb�la\V&o" FDnIkJ'UhŴ (e>4?I_UhV]{}tђ+dQ3T@(  J:S~zzBZ[|8|1" }HqUnvv?d뭝˲vzA5EӉ~\H/>۾a~64z~@Y~am r>h>1~h\Qԅΰ&sh΀Sim%G 8qR~~Z]ڧ|;͞(6hk'zgr>CH@'t@,wwwBBSEtt|B?OYԿuz{<z�n7y6_XS2Ԗ%fgw ZR }'ѓPkR޲b񳽑Wy~7[N{ @K2 k<? և(")w{N[;(2w3ʴmf7W@c@9gȢm!lKZns K,g &V3t$eSX&zwxs:$;QANVV;NizQYgJ`oAKk8'S "'n0x~ڢ T.sG(yrU P;i*Ct,z F3h= ghQpYrTc,�x4^~6>wMF?{Eu2`R_{$:ģrrUkJ#r xAy'{ϛ05iI~UTw[? +H<!zklvj!WdH_Ɔ,#*[4Ot3",:Bo cbWߞ]iwdk;[b:O'`t֭9_R&<ׄ2th衘>~ȧNAv2a Q+u3=:uTe0kQyCӢGOdn. S%.ϏGOOw4 l\͟gJ'R\,K) 25SR2xnНҦVPմ ~6N\?Ԓ*UgG;;G|@ 99N^&/R,3dT}ؖH4jGB3XLc I&./NCswW{[[p:MFx:@dv.nί.n $36/vi(폿d:鴅lJms7I.n(l1K^hnk<+҉[hr{Ggǻef0ZtیbA_ 0#5W -/n6:3.沥BC~tuV98>1|HB�ZH�% _A钤#^j8&. VoO.6t鋥<jUD].\YY^5-,ܧRt1H|�y&$\KyҜ VA!V%6uvP]ߥ6)8Mxd,'DIM*f9TOM[:zmWǻnN0oB0Vm4v.oJE-jux] 圀˲B/VM!E : pSHwlԠFꯧtva@sM\↋85A�\iNM8[` _Ew¸?jws-xurr~(h8P/W/ua7;M[QEhvhyU#B@p#wz.8SуfѠ]h؍f<%3~ۡc~hǑG?\MR9:KTilqN'[kтvv#]p{p)zbo+ZZu,eVQ52h4 X6Qh6[rY1@U :-%+d-*Fu Ԏ_Q 8' AJ5U;S'5]Td]%Z;rM榠鵎IIy.wypQVKDFY]@+QK)vt_.d=nŖVem[A/vuɰ~ Rvr,qMj_:C8GT.$z@~K@uf.51 }| gQCGJ4,'mAh>]$:P57a|&Hk1N Ulv=]nv7,)[v`vJJ&Gt6 RԶ|m;^Tp$럵v :)vR"D@قix^ha5ƨLnۭfJe$}rJҽWT 3l*S=:eh)u`E?DNn51"B#MU[bUttS*YIMS粬`|{d=|^2| :bwZzR_(WT iO&M2QLe=mNck[ Оc߅grF! E*+U;۔M5' N=Gg#><D�DAQNKIX3Wk]4;ъ'eNUͪzdy3ƨmj`~RHCYe(-b$UfПDԤt1t}+ah{:3wiŊ-u}_ :ԺUun ;+*8k[vӘ{� 抺 2 }^Nj~AS8QI.TPRMd瑭SS-->adI6п&U�v3e`8McT7YZ2%#!@|oV*L)!Xn؝Lۮ!勚M\-AǫD^`Ag:mzc 'P8!(AhKww<r\vjnM|]^<<[#`.yӪ]$}+z~c2o{(#UíƱWZ"_wq8~4FzaTҪhZEt۫Uӵ(mdPw2o  b"Y~9 × Xb!'a1^npG٪mt+{^+ym6,# ^JǓI0_6qgFqxD&~a(bV5k]_MV-38.=\o*WuHLռl-|Ԇ+l|%)ILa+'i!ע]:0~ёć+|CEb]Ywa)qt MZ(0 ^+LnDt\|W1f}}.J_Q(^]4ҊYն#oֆ`b?ȋiz~s-[۸ S)я-5,Zq~+|fǝu(o�8m?L[FܨtnO`Gve*}aݎGƟi,;P)_$e/:r^|'q3UkgPMs$Xӏ:5b6H-|W0Bacc aڟ ;ZV31?/ĨW-ZWE t- 1(@ OWYQ:ͯ"ÿv{ ,?EoFɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛGbΏzW{7s Re*b>/p75òjgg2l@ߖ$˕+2Sr\/H=fJ3q, lRLϽX,3<@v0_]LH+�YR)zL3l6M?( *]OȳŻ۸fҹZiZ0/rU9W*=@\6Y?CasWo{tM\, , +J6Hb"H4˦!o/-VXJX]bJ\x|EQU`*z2q{++c4v3UYx5rw6 1MJN+&M\P5זN& l8>]jxރ"(S顇[-ooӕdfӠkaa9nyVN#ВDnGuLCU$t8a_ɥM}Kw[Qgw>:-f2z1f&]bd޳)g2НU(S9& m~~}6Tse^$I\.Awg@j\D`x2[Hذdfk;_\^4qc%@c |O ai|bX?>/]ҥ*͖|K7:ǡ] S(qr\Dzo (pi%N9C@X S(% EJKi@w%Z!|=rbW0ETJ%NdX=?p(yHw/?=d3a=Ȓ,QĮ.Ih Zk: o3;,@0 zx?ƍg[p[>IiQѨtpf>o"g ԼlZʎKݲJ]e|~zrrpn)^I0ۤ$0=W6hWhȽat; ixHSG眡 [/oYeYCL42K8MhL輥fhϮ4G99rZdEI?^hPk4V7 $Ff3:۪6|ouVoYNꥶn>0nC4V견$ #%I(! NBOkU: @ e IZ׫JuT u٤,qF,AY UJ EۑlCPBJh:Z3-QM7|]n֯ { +R峖a#5!ZQCD!ģkf;YBL,lU%UT3\~Y)]*-^_9fJ͓+E<xt,H@!M}wbO#ߋ[Kfv�eR 5_ +y,qDž4F^:LӘ$ti4di*ECGlIeNJk(HouL弬q3]VARD<3 z 4 6F5c@khQ( 2T:lQ/8 b$C誄0t4Gu H` $Q ]ԻBpQ(M'촫j ./ ཌྷ$@rQS۰SG-PD%EVت͡Lө^]\BH?uU4}c*+ B Ydj4Gj - /4Q xf:f';`i( "C]v\i7ranrKpCpPQD7M*z}nB^$v^K#82Ŗ=Odԍhy�A9@A))v@Sڠ"/k9otAT&xG�ӹՖOxڨ!=ZEZ:Xي,;Wz'-<uY-+hg94%D٧vBTN6 sܸh ݺ(:U 1lA_˼u.h.5iŶTn 930[.K8H<Njdr~\T:Q!`�z$\0bn@)21Un +"fiN@K`9a Bg)vbt~Vb o'HAM\ӒPn"WTnRA�AөKlzvGu�[ n;}KSA\bf t)4JJtUjJ.晪G)NˎȚeQ*%|5ʨDXkDTk *-LJ^t3NT,Y@'4AlYwC;$ Q"`kBC4v8n:{EmB6.*'Ȓ02L)ozh N)ėTs2niz^- [jF9~>BU>G 1V֛V܁pAb"H-Cރ5_CP<4 ՈRcu25S쀙veXRrZ?ze{4F#U\l.Cf5E !D�NhvAfB%M4Ɓ,"gBS2hot9FD YAY$q?F⻂NZ- ckB[bې%LJLDeyZMt`iS v% {#ijXjK oլOr(r�Ae@뻥hh04ES6p,E8%p> {yy! @J6͢}לp^itA?gfqdС(FQ͈Ri<BnC{)NCy? QvNirAƠ(|J6H�?hÂGGL+PA52<e.qK3>�IWtyg�x$DZ`hP^v1oY~@G1�Y<udI -ݥh5s#e6-|�1K(48ի1h42";ZҴ?Y,fAN'mpK74I4"#ٶB{gsZt^0pm�<Ukr*18]܉o >\s~8b<Ex 4C~ɨ}Tؔ 2#˘4Eg oyr8́<CGUx@ N#Hy i(ei@Ƴft:\C>`"PBש5Sԩ{B44,O+FijUdԷTHkhH젇@pp -fA8̦}߱_ 2rt]e0Q'!Vp]^֐>`L@Gn vF�Дd@nK%,U x 5!�F)4(c4;/3^<~$?n"8u'"5,`lXsu^4ۜ渑+H^FPƛT4kx^h]xyqE Ph;neKj~C{pז"/2B&7ONjY wx͍ $vP먖 `g2 M-ƧfX�0lmn FװuV%hfSPWOW$!+A�&7 DjNjj=PYv:CiǞ&VP*ؔe( n�,8O\UZsB[?Z <d(%qWN7CN-PXa9N\MIZ4[; 2ӡYF'MT CWmu-9L%fHV4[ " p_9X76eACg[I `y?hF�p�dtH;LF|٢9^h)E!艶ԑ]Z!7:8;DGDNPMz.jtŊ?b(f!?9CxJWRA@Έhwb<vX  uv3BRD |,t z@ MÛ,eY2Wt6e458NsqGWlF MQX;=G iL,I?Y,2ߖ9of HDђ_#ؤ`0&.3ǎ9CC&g9Rdv &$wVUOO^+<#1 BuBj";|�;\Cp\-r6&Pw_<MXr)b(KS,A3wRM5Lvv^ZQh֏'7"no~6(bLi58xp9 a LP!@bd3C%nZR㥱S_XIW44o]BcUdz &B&|Y4�\5N{Ih\v!ƒ MkP.K۔e^׬$۟alץ0ih8?-*iJg ڒMO^i>Ҕ5Q0wcG6dp#M$l5QmP3S犻jf/S}6[irgLQ AЬ|Md,u ͏Ѳ^cо oh:eyYUD�A"#0D!i1Q "ފ4w/.5pQ4(>4 /¡0dvhz ѳj.M~*סiY0Dd70MW?IL4*DT,9^6Aovd[<,PVTgN2(fy{Xй2"d�l z˕I 8%fCmU8ZhC[=hf:ץփІu=i� N?=>>M#PȀ Nrb5R%/ͨi/'׏_%^x0/vn�ڸ]ǧ5*R҅0x[6 GrdsiXvZdg~@7#\- WϟU$<SҌjh)2ب&�!^P2MMb �p'{Hnf:YxQ۵vpCx$C8ɲ,|{ѐh\af= XN@ FnċmB,#7�oQ`_V5Om4`vvs!Tl/eYE1-'"kxwIw^s*`߾M{!PשD'v(ǫR׉OSOZMh&q/x:mxާϻm>'h�Lng.kиo=.)-4zGP,:|pZwrno0ޱ=8{ɔp82{_O*@ytہG*&44-ӛ>>z7iFcveT/_dN=m %-YO|E)hg([햎 |2lMU*d$\5 < #0z[3ӷ,7N /B+SMiX`f~9@Ȁ|<q7e? <")9?MZ9><)NwEB7#M3O~e4Y$(׌(M EQ*==!=$V1ۻl<Mǣl lQdzt<Gucɘ==lIMKO@ !`̗-Y? Š+!j�lk N!3EFpvO!q(4FHh4C2m< 쇣L;<oȺݛLt`q;6[ct=LTͼj|v�|nǾH[ûb\,l \t�pA�&IU61.WN惛zAk~i$ _'A07Ͻ tӛocG4or&zbZkt8$dD? ABmV+.7t:syKoohW -CԽ*Pn ]f9~ 4ՊS@q߀@$2Q. GCDp�CW'-JqC<"q Glyww۷4~#A#W<@|"p=ρƣDmryjwd @hdz}ܟ9(=,-g d}{x7Tr>fQzY:T u6Z MwwOLyN#n#> @@a'C2�)h%<;;;S3.aY$F �h9!-j!Vkx#[^:[ܟ,=>,%(nĺFj3=$&ӛ03h&9rzG_FqϷHez~主]rly3 <5nm_<q:~x-^J-⽾k[>7|$56*c&T#g/;{MRD I{/n@<Y�|M+/ ߾=߭VwO7tg]3&;h�htFl{-"D=s6 7JhAMDE5Uv[#n  P2/J2{5\/vQBo]MH§nS4;N;ZWR7MgP|8[9#_?0x e�s0٩c\(C }kGEb}__7;>|{8i69@%*˦zj_/^ .'+g%gjNsCaw*EOIF~a9 'qcl2i(,s~r~v|VVKǟ>}/sr\Q0R<Q! EDw=߭WgZ hb0}f<=#!qoO-YW Ŕk'{G'u=y_YQ:=8<(jf>#PFhaS`l7> -M^aovbv~!:ڮ"nEzWr_E:IOY$*N{t�>�Wz]�}ӌGRZwۇ¬.cIGѝгt3 A~ڦ<=8;9_h r˧BѦut0 E@CA~pQ*r|xZ1�qlUXZ�`A|~v ;ąm~=<8>Ǐ>O_>j4q먿lUa琝"9n�V9|9'l!IzG-o�vwPDWG=C/>eg.#<Nڸ)睃2X(xxY@4%xy+@o?xP,c15My="_oo|zq&;(in8=ufSӛhvFd=}eJom<pK!HCMww#Oes -C$wcloV%)^prMɖxaz&׋_ >)&~fnZA2|ه;7!(O6}::Ҋ˚?ޯ֫5i7Ȃ$& &5�j¬:FiMӸQEM:Vާ&пP?~tܒ>B+[dsK7 êķ^mid~t iPnu3ak [!c6E_>>}AR6oP.iH8^ozXrIkΠYDO^hesӏi<'[;jm)rzS/_|U6Z*8߬ (=Y[7u7̦Y?tot;H‡ǻ"<B? H@ _>}OM6aez3ld7K4MB;~f9xgYaOyHK_Yj+W}p =>AeA_mhKde}0<43|c$?hcCр(lW40_=YѲQ:ӛ,0գm@ŗMF\(>�@7?Ne CO,ۋ-LJ2zfyH0>Gt!]S貪z t'<dYQVӿ__w6Y%A/ubl`e!}_9ٰxX-Fy?֖d7Y0==ߎ#z(Iq:mA(_ 5vvwO|;??rX<Fq .;_NS#!uiYMFi~'.PG! 凝☭6=NǷԡ1)eЭ^^_moZܭ^\E~Wj_ᅊHƃQp3m锖Ud)!̗5h1=6qLH/^/v>|-2r<H|UȚt^V>=,5!Htp6gѻM LӉa1&OwC4%j$2S+Q^"{xcN1`ї_NFRUk!-FhD7|ʑͪD2WLsg2u@Uh]=骛]K4ç0vF^-?윝잗*zz~ViW G{U:@3Y1LT!jpu; 9boý*(rmOO|rvSz?CTIeMi_CB]Ĥe <m~d#ߚ�4PQV 'GW :a*ۂvW6/+nzfhlX\Lގ+]~9 r,[De[y|)BӮ_^ u"m.竝2qLIXW<it5z% g4;~+l= C^olѲ|ݬg=TAQ-_QO*&bl/0g]I]QtnC"Z`u)_$&"w ,6蝰iǎ#yT)TAU)]eKםϟWۢl9 ,SX.F%�j]i_=* :(FwUgEӦw5s儣WV:B/F$b1O;_Ok] $*-nb+M|lQ-&Io "0Poɚ\_q4EΔeM(6$|eeӠ/d{?b~4уQ5X=1#ZQu7rtytƺNɴ5E#ZO3(5}c*ƣEh b[nI뇠ES(d:W(jV#K%A5xZ,n&ѵuj.BM?Gرڽ Ȫ �GQ֟L $z򅖪 lH6t |C)gz3Rz9 ՒM?Kjձl O|CWӻ`DN~oy2l{0t TA,`ɐv/ۇ--С "' iZ7=5-T_M5#G+KMtUg<tL1t3PjyCa.sC?i ֽj$Kcz6;9Wa g3W-2N)Wy%e?[ޮT+N &Bs+@تD[ GO^JPQfݎl"{JB5f!Ҭigˉ3d8Ao~w^(tvRj;x..=+{#\>(Ƶ=YjW0flad ˇGa8ďκgҺO66E7cWPdYn{&_gbWwŬTqbϛ3+zZCاTTg#eъcm͢zzhiN!4!p/="F�^/{)X+uMYd353O]K) -߯Mv؟/(2{z;:E $�ooBcym/c_$^ono}}[5x=Eg@) #ag[ښ 8˛|S+`�eX˻ bXo@({qr2V. X:�.;hȡn[e &7mNtbz*v1B9i13?<ō6WKc;*-q^RSl YUQEϳZYݬ3-&iơGkxA=)KJ7Y.Gmt+]MWKN۲<qLXQ]WtБSQ?>&9"c:]ߎ]ˎV7`-&7ct.+B.w ːw)]`rB4kгv:zjVUÎ ';X \/5y+o53[ Gw`Y0=(7E1(Djiv>9~9O,r$|9|$#'r*65A[~g2Gn]Z4VEr谦`QuOY!q` 8'VW͞灭t60j[XN!z&4:iշʊMCdjhm1=L2F[v孎a=-nvJi+[WN1ꆣ [F>a:ltCŌדЖ[Ŧ$K oiՋ-zb@fxQP0l-]_K�Ep5=o[cGm]n,%Į9n͚hlTy`󗧜 Wx#z%; k-^ot1}kg ^ϗK68;|}/MB`fMiW*] v mN} _*v/ԩU5ڠ,luuMT< #}{x)9pmrl0 HmȅFr anQrc)Y@ifUʆ;&ɪx:_mmg[YA< dvAx'g'i/촽(^4ʍf[rA4?ɜh0GT82y:m%q*oN5%):S|Gš]͊G,?sU5<O\r%䴱=&DYD^V2$ hD?س)aBG'$YÊy{ x/i&iB'`xn^Vi>0^R盠3໽ۻۻۻۻۻۻۻۻۻۻۻۻۻۻۻۻۻۻ$ې,=?N? f5AQ=fo~y(t.Ʒ[|m_kbX4m7uRluZ]v P9Q%Aໍz߿[7gbT*כ,rޅ#ogNl4߿nmKk|a^._]]JF*D v\-_kr6<S+^mmU/~]hXt< _@J4 /6ggUe[G{V-cPf-nc/[勳b\,׻lIcvBt}A3]lU$Ed 1B>v$oXC캼!cUqUlS^v6,jg[zRDg< ^ne$[VeAxID+N'ngiʊ(86{3…e: uAeFPN+u $ˊahw_.7JrV,Qf*-Y7; ޾ѣ[˭BetjiMaKz][rX[F@9n ]V<Ԉ S/\^mkµ*rP*Z,e)G7?8+4xRdQ<4A k eXA|JtbUirn /PQ+pt/N_Tۼ뚶J\ժֱZ!n0mHe_"pGj-_7gJW=vw=bVU ԰v:j\V (T@C'[ԭ../AADQqo~AwR^)J-kiWJYl]jM&Ae^pTí6Ӡ4K^?hjf4Z1Tm*a4WJ[A'e.5=5u^8;:?ڪ7F%Y/ z1BoYjT(ZBBxUTk"5:"{Ki44[8_o]^r3AQo2<!4�Jb]:=.WEަ}ȁtRmo]]t]_]]5lpK UTHj:^[ WV}bFy}yrvq]W Ns 0 ,$8mJ]m]t}3Mp-YV2 iM3QKV6NEݴǏo8Ff`wMB&T~$FE>>,iLR.]_+oA)1}ByIj7RG:}ma i1~? p<{3!Hh. E&mn枓hțG� 'IEAjN㇁OJ8ɒ8!35a_齡@SvX*q "t.tdM38K,EШi 5rELB(KM^}&ډm("aAA?$I4fҹ:+oid{4X׳hۍv].FTeǺ٬Bd]wUe:CZclP)DJ<ˁ`PizqYn2J ]ۍcnN_g~PYf;i^QoFDlM;AuKhDV4q;Z*ҟ2<F Q MGI%t$%Ȟ懖'f)z\1T k[@FȺ z: ℡) U tebжOyx*:CfqQQoyiԨdAib/cԪV8YyMSW%YoXo+fjl4ڜ(rBQuEیs t~y:oæzQD&5QP"F3-x -,GJj8pmH. l.wE?9ji*tZIsZ q"ꁯq|ꪫA@AyS/ʌI,#i4}x$KU=F`lf ['y/3</T{vǑ$Y{۳$! @P ȈH!~7S U^ ȴ0v[`4 7g~IN@d MF@$5@xw'*kؾC ePCۭNN/JŹ9Y?»(5RA!-"۰�==[_})>(칁p ӌ]Rrs0X za=i)S"E6W"؄yCNw׷ &@!v~xQ"# R#Hd&NфvhRa='NT[ 55 8�hmSHL1I,B,J�:ʌdoVǦhRj]Aɠ|hӨ\F�H%np �X�݃e%UEFY Z6*$z^ 6Q< "Y[BY- '̡y`h'}0É$L3jЮ!M[.(Kh22f<3DNȊc }Y|4|Uލfh ͇jRNUlTDMgeUGyl�su;B^."i^eDHzI eF 㩟>#L(ml}=+߇ei?Njin&t5!l_APmjUdY0 !*J+ZQ6PW@�hRo9.ǣtZbm /AO K:{]  ^ N�3'sA(l^9fꆓ-l`0xKF1ʂeH x?3ȳ 5~P^Ks/t^L=8׽tqʢ=DuRe2�@΍h% . i1by :5BꁄcT̘,5Bt(&ܪ1U8(~^N A<hRxt E8vv#$A ;|TȳݬpQ$QP?(B\ayilIimpԙ?(8Dt4 y|6*y13 U�Q&cL�&G)< F=_$E0Yv|ܮ.(7R! h_-?]-E9-Y uJMڍ({\ɴGM/Dl4(A MSF ^u)! g+YgnjʉdȊqhZ.)K4/lZ|0 ch"6ݝ̀ϭJ] L7:!5nRA M3Q[Ʒнt#Fa8\՜x,=Ԛp2]e DBFt>/MsXa٦xsVirY);2 6,a& |* !Uss|R~9<n^duP 1j꟬/jx$QhVaY8:j[xNt\D!lД7rO<3`S|e穣4*[ KQtR>\>Si1 MGA6/y}i/K/Tl4jYВXJ&Э\GĞ÷R6+lvjL& &>H"b*>El:$n@<�Ы"p(L,5"i*A9nuxt$\j#:?^rLT"|^^LYpt:Yϒy+yB P-uoQwtEj_> "{*C튮/q}67yryr1HqMN+}yJUCnDjipL )j Yj�]\U:`֦7MDT;ʫYJ0^઒fe5Q64Ii<;ndJCMyrBa+f6)PMͶշ`XqFێ�KenT@_g%s|7(/E9ΖpjAJ(g0T> Xu+-KW$='aZ.M-µZl[pjm N f __ .D-kz)~}eb {Mz-A2d6CU^'fѬ:A(tPj7ՐUxvù Uǣgbi.G~6ŖՊ67^! pCHWBݝr@1$J][M $�"sY,vvlmi&tR5+R j�H3rzp\-MAx? C[V܍<6 eN:< ͦ.=P5U|*Ow8Kv[ ;jٖL 0ʣP`t1Ob@C Khg0 4 DoxXІPX^7QwhMPCG@7 Rloγ^b6/T Si58\kd&(N1_.f`ZiYfQfSC4X v}p۷ nBbQ"O\5♦?<M4ӎku:&訖ԧvQx&A<Q6Z;g:oS4X>4aWwpq bQLp:m}!]?J8:)$97H~<]K6^:1CL A:^2}X[l={Ej#;> sS `6/(g$ V]l׋4K,qhjۨ0'v 5T#5?>3(Q$gӌ&X\d}p;M-C3D놳q$%"m7*'Go.Y,'^Kf"jut˥@ y(TϏ<,H^jHFiT͓CU촙{;\|/B?|{&IPeYwNfO?^ٿOZ?Cxq >]A&ppwMS / KeB۝*HAJrλ*u,"י (J ~27wa3*FԠfz.RjQZШ3&q+ KF+Udv; 溃IO?Ӻ cPd=�X| )>>?=><av2:i;ǃ2L7F#?ܼ98~\Q%Qz|5A|r;!T0 ea#h-J6\====>Ӛn3i Ajҭ<씳pXm] ʇݓ*OQ5tx#ݭb9 v|駻!M9(Lw7Aۧ/?}Yg&Vy{`2j; 襛H)ɀ)u=*o^Y`rU/W4$u7M #V55H'ys5^ww2l0gI?r5W.& WҲ0$e9j IyrBӜzDO]K6Yqۍ>>tQoIO.Bûr\,d9sO^Kd<ye{>MKS'Ӎa9C�)$pO\<RWA"MzfF+V AHQSU`xw$Ƿd< Ɛi9;}84DEA F"xJTl<ϧ9/r=AyQ'wcj=kao7⬮x!=}$*0A-Уb&3X\�F:y^\zz2(j_O''f9|>[gV]! yn3bzQTBOQcjf3|W<�!<"F9.菆ox9~:G L|9'!V�'HoR )ntѽLM^oz ??>܏Td޼?/F1%u/}d3Al6h-�Faۻ; *9-^|8 xFuT;刦-'1=kDrA9Z m͞Tp1pOK�/eYFsRQyBgn:[.&-nj1ho7Z LJ[PʉC7؄~w >Y·ۻ{0hftkZ>-H!t<CoiB8nZQ\~26ta۵�6CH~|wʄ~IL,` mox`k7xB.29e\Y`M3J/Y65::-dGմZW{{Ăm0 4/ߞE~ЖBt= 4(b8OQsbya6<}ן?? ??=}.+i!rv&ai ޫڻEPD{ p4ʠ u{w cOO˞{[fS07p?˯~քOv)iKi F&7*MC뿽z'Б~LJ>6XD`K&z+.s`2}~o\y.!r? Ͽ/?㟞۶#L 2 kVEF~S~::0-ۆ[?2 7xϟ&�Z'd 㴘KO0~ӴX4á jxg{v:lh+CAJqݨvK3@<EOv?�w KO{geJ}^;C֪E 5>~/0韑4@gہoytrh_~իw o7GNkZG &t%ؘfD\?lN6رIuX�'^\LW?0WQ}Ǥ!2:1%\mn&O9:~vǫXhdקtgG.p{OMr9E|3Tm__{W,p:l-( ;o^~xw^;le'5 C17y {FBU?AZrR?o@_pr.*7kt,Zļ_y&ӟ;ۯydVUiVYvw! Jdr> 2ij4,HdبTDu2omXL&뽊ۆG>CvEyxihE!]⛞DaRۯn�3U:yڃhSIUrm]|+ww^o,~Cfm66_ԭz[M8hv\ !pp$RZࡌ߭V_kH%=]0Ql Xk"\ll|x|覄 [BjSUh$l^)ގ6|>bYC rh!|Pg=|4eоI_�>xKޥ ߼z@z Աyzf?酴:صd7A2q7p6߭P}8ҙm 7w;$$#;46C@voB~:^ϋ}S + {+f=)Kv~:|5iWȐN`{|7;{'MNƥ@Dg?N_6!-W &{4%7A;Aأ�1ͽiDʪG=?އ�(B! $/Gx?l:rk< Y9(bSWը@zB^47dfjH~gATPNo^|�Thv(. bt6-V[7-Z�qdP( Q[f [="#ZDq.Gvdj{oa k= 4aҳ-~틚2h!^}jBlF ZKd8.48w jB"Tio>vv);py$W ,&&mFih("|A<K렵%ڢq].JDeID5o^m}57m~gghs\R-nvE% Mv:(贴.C9? YUC4i+ҲХ3~ѻO80EQi~<i}DVn? Kk`QF 4ݟ <-zeϦaGǻyᙆ;obw{o?rsx g<r5v {M|CWlCZb:4K\LSۂ[Ws0oX</eFKWZ9bl\Wmᆵ콭CПd6`vNO^/p2!y'rъ{,-LC�IGu?ή*.B>]}8J[ Rrs0wx0^@d7H~^4nC<7j MR�lr{; ṁw/ ߭W.?W{j(]g.>li&c}nU$Eަ'[d,}V;m�nMٻwjӇ4\z ,SǛVv}]\fӛ&&n4>??>?x슪ձcK7U^ 5q7رȑ\~S4"W h\PtͣPJ: E[ot*_=8Yy)v6euhڼ(͇i�'f5+N<VS -AS$.fSNĖLimudo˫woON. G>=~s7O)1Pf5' pfN>ٯ'P8Y�<']88xM&nٷOt>.D:Pi Ђ9dRWL[ؓݝ1!S4z9d6 xiUineB� 2pkci4j+֔&kۓkְ2U$ t ψ|0h]-M ϶.޽E>89<H4"[7'F'dT43}|nfk 8ibiRNGR +p&ɷDFUDsTIeh2x`}CtˉGsfoÀQ1Fy<===bZ~1),n5aFJt,stK`n:M CS$bdibTw f"DJQZf8p60ȆpreX~Yz.*dP:1:~{{Kjɠ-] .Ti;iT;(d2 Um%C-_]˖SSoTt"@2ݨ[xlIYl>[g#h:x6G^&<uIsˌ@W@`[S 'I lЃ`>]vUZBh/C;"lHN$P/C|`i]݌ĥvr13o ө\S f<?lZ cЪFN^>A}G:6%y4eihʚ%z 8ӐjOf4{u49?2?W^o@ۢziovGXVр4cI6WС=wKc,ZCF%9zT1`P|22nW,nɷ@ƫ[}_y0mlhaY;*:fԣ#>DVYjhIJ'2&l9F7j"'v>>g4@VщS_ݘ2D/pfCDMԥ%u 48&X`U:d6 m%T:o^2`VVݠ.fm ᖷےWwuw.Bč~:"#xQ1E6 [LLpt :w9-ǒN~lԬ&#$'^>ƨ.0d1,4b?P9/Bɥt�e\ĦG\~h*f9;<-j1l%t6YĴM t֎zbp 7' GdtFwSR#t<*9kj%m$5Lb5B_طڵxn-q1٠L|WR 9-L?Pa*^Di\[k`!|iѐxxBIYQ%9Yii^7.jyWaJbi7[o'km+? L8r%L$|#glB,/Wđ*WwvV뜳Ah <ە~V8_60l6OlCim@r�o*?|Z&MpoC {̪v~Jlj1+ރb_h4uI$Vii`x쟜U%@yscDf*{̧-`K:&չ.CݡIuw}rH'Mec\ ^_".zQXD6d爬yTyf$n^4/]s|箩\m/#Tjz8ﻺj>3ZdA uö4vЗkmnVE-ױ!k`A!o ko;^qgGbZkZ<9n'tjBDb=g]6DY|^4_eXf؛S۬lZf0'B 5?\ CrvXrnnu@DZ]�x%ǧ=f1KSUl]�Cy,Y}Ά;tuZl劵г-4kk- pi; d1d3FP1<P<|]ռ"vz6sǣeXO5Krd;(R`|>T?,wce^:YeN!T7NN<λLz ̝tVzqLDP\,Y;JIjUvo^"]KDſԂdNFTmdNkZ\VKF)'֍atkkѮh5H"lD e40I n(|5bgЮl1*sY%WB 3̦`A Z"t5J`:T=*R.�XN8z $EuY[1l'àaYH⼌`ȦC'<ΏDn؏Mv:_DӜE'L<on'C_u-]/7PwAyl ,`5 kj2^x/e2^x/e2^x/e2^x/e2^x//5?a i5n%uq%kj_txem-:'oj6+qY0'۬_Wb94[rBC82Nnm?tVW-\Kwsg^&qX2~5i6j v,+J"j349΁5 jv4F zxi3$i.cJnB<7n_7C˛i\\]VnmNRI?-^k1vqu~&/?^TFlYsnZ Bxe 7uGj6[CAn5 ɪ&q@DJvy Фq" <EY"dQUn !(a"ub/?;ӹnuBhv(MCdElrp{߬4c:Jxv y@dityEYf7 ISu=8}?qtr|VmV*WjnuVviJgu#5UU`YM7t5C8a&wU }uhI Mf1UUWe fvAtsn R_SxT+׵J?V�0 ٱRq#p!7{{dHG1Ca7TըkוJa?2B`dn1͎9!=C%i/ڕ;{;A QFJ~5uzs}qQ"3$Gfr^7Z6Dz}2nG(:kc7l]^jH!Q.8QvPt#xK7*㏗G:' N,I,óMMWgWu W?dCyKntStM$ZW?lIAM=}7 jԸ[[+ujWQi$K-8_tdo;zb7jvDZ" u eF>;bښK-60t$[cRS7P4i7V6 Y-˔DIEex8`uYC0̆f0:aXا=et}zz^]n{A%tM'47BF֔!B:F> Iy׮aGSBPQQg{FRHQZd 癖Xzd6gSs>|軖""q5hI:?hVe0dYP|.6,#Ay5we{+GzRn\(Pw6m]1Q� Y\m5m?H"%16(MpgxT|jXj} ) dP` } SGуq LnR%oNH=e$NCt7W Q/vkĦ<=S"vy&G:^s^lu૦hS7fh8YdjsLMax'anE0Dd#"J.J-?g\ IP!Aبς섾!vU솶$ valPU ;REu{~MkFb!]PRj z b<4Z1bfEòvr4F}{q)6iU5P:yUE( 5TqS$7;B*(jR" 6a<PZMa:7:-S f%4.f J'$l:y#۝G-jtYŽNˀo]$-ɛƮ~<vEUEg[0uuQ(|ǔοm>>67No$DQd=jRh :vBh<=e#<{jcؾc9>)S0x&hFݑ<C5 M� q4:^b(dِT8 Dݩ>6Ji:aliJηYU@]Sxń>[Dvu.n3 ly蛺 'b Hz~+RIVЩubmJ>5sn5r=-9 N6u5TW 4u'tPԣ0pM~4,Sg8 ~ꙪaI9�q`8@5ڦNoH|0.Q&Q':C@=4/͉ -i0ÄbH.a/apNG z%HFd·jhtd6ZR8t%($X{eE_9qUWAIdsg�Ta욲btm^4s#1 ^`$Y t�uE[ԗT 2J.אxQ5�ˤl^ Ԣ5yu8Ƕi7^/NctNQa;x&M|  mjNFakXAVy/W/Vz%R%ZjAp6Ɂ1LWuը|ղN,�a8ı. hQܤrc.ŦFYW!Ӣ@܄'eQNtu?Y}S>)7ɤLzy|ğU]hvQÊ^�Ws(mOȘƾilRߖ<$! *TTڟ<fGs{CĄ-ˢEԞ CvP)K#6ʛ 4#EB%ˢGr0L!bH3;lNt@c<Lg)eOkV8$5Aa sݨ l$6ŕft{E;$5@I'~6ϲ𳔁QhzZ U ?f) [05 2^fMYxM ;.ESC]kp**zjrkstQďʼn+oh.VO?)GUD3(׷~dI/Z?p={6xd>6&Rc2l95+RخEAzq;bdj)`;p ZBu}Rlf0o7H+93=E MWo >)Q�Du7w89-nzCEVl3gGHH˘>β4a4rxcKp ӹy**x UG /͗iA#nޮWxb1I}m)̰l<7TA�Ȫ<B"H<d'DL{|Y&"/"!dZvwE'jNO%0/׫"~1CaNo>,4bM FztX7cxڦU$ORP]Ejm !<lvYMXL<;|3^ oL& T{ 3AԽ4Y֚ݲ#^UI"�|٦jId4rTkMw0Y]>˶MWSgxj g&2ކ0:u;' p<I8I`,u[ }AMh9Qq,,.u80 LcߓZ�6pWh_KGA0aiG(ZPtwSZ_p`)vojЭkPqPڊ,p=M;UNdbjeU69&^a�̃^ - 3RjK=j 2J'=4*6ԭtxË Tn%,vՇ tz ʻn$>.ϫX˦)[4NM>ǩ+c?Xf!Kz2'aj�p0H)˫n`",RAڵKLa bL 6L Yٟћ"=^@H*j4Z.z,(^?|9('E= ঠִ(7U jȵdnˊu< o+4nMfp5nOx5r4Q2ܡFح4 ԁcrPULu[v&z^ x:Lͪf@˘qY# is8CD>ŵnyl=Ѡ5Cڤa,r!%P8y K\j,Kn#^ ӏ /+Yn6V%^p^ @{:d1" uw-t2> IdUSmvEAj׺aS)7Yb[Q#dgieAnږ8ZEr/ F+Թv6CTۆخ5xl* 􆹫JFj5l[i>VE7T.>RR >qVte1uI7 v4{h>eC@;@ހg<p Mb;]<Da&,BF7K"Ѷۻ_cB&iIlrUxcݰNWU;MlVv=l~I>&sПL :,BU3)_}Kޚ.22g!]^s,IV'YE/?4MT'�<vU :xdڬi3 ,=(7$t<'GD!ZBjj8 Y@%JcLI?UH4&7\5:LrEkզyn<^==yϔ%-^@7f$y '4t޲IQhExa6>?={³<4Rfo1ihY@ծOi/JRd[3 Fg}MMw4#6D ,V/3�5<:sP_jb !7۪EUfJoYn>MzE~tIzYxr}vpXdb4Ups ADy=(MYh<B 兠dib9I,}L$vS??rr4RCD n>;8>>ѠEv"}! v<{<lMsI j8ħvҮq}y^O|oCfER5~ˀW?^%IA $^OɧÃãRMRL 0HD!yxh%L^ԇyO'OehH`t4`TH1">|tj,.O47/?~~<X]0vdX{ep4~د6!(p,j7I/6n(zXo*KEϩ]FFaFO2|vxfDQ/�[3(M-ן^&pʡLãӼMyJL[oe92/ F#0Tz(5O.lԃ*OS7nOO -NR'--`ixT@% TCgޯ6 v-|Eu,/h7L1b0`i4E0Զ$jd3tS`l'ȔH L՚\6,]+&#ᩝ`}4pUVj êl8NȖ[p{dtQM[[l@w�`/./b-#hPP^irTpu!,It 瑫 ;ڬ琍sZҚR:f1Y/1# >$Ÿ{Q4;Lr l|Zb^k_Th S_`Ych9hr>N(h!DTD 9]BWѼh\.&/i^SPMwחZ ">j[TkiKuzspbZCR><śl6׋$ C`2]j2Dl\h it]ۉf/OO@2մ $Y⿁Q.(w1 <&`h0-CWf&dtt N=Г| zܼ~ ~R#b3˓tF}^Dx Qڇ/<ׯ7݆D!#Q:}y}u5GU?d^GQv/|:p8 R #G*N<{Nj9L[֛ؖh*ReQAF$_ U~Q/x&x�Q Ȯ]Jh4q7;}ݟLgSN{EM"Px$-2^_{EpXb,ϟdo__^^-Ot][s"O9'`6ǃsOm4 'Ժ:8N6ǻMsNU #mQ/ϋv=냁a \j/^a`0}?~O_G.BUfK C0Dd@і?~z&wGg5͎09]  �4%| F^g #v& lu@*W|ZAL^d4 i@?9yVkr*-BȢHU0We=ʨbBtzۯdO?0 Ũ޷.VTY FS@l>}_#LlL?=s^\b)DIe-2 1r7|34ۼ'd72;1_j C:@SHNX}!: ǿ]s)gו6H⊩<[@L~^2[o-|Ȗ/OK$o#w?38;l6Am 냣)Xc ]6Wk E1MrW @}}}_?vp7UPL6]iO0&W 6� *B—`ZCLfҬW0jZZ(/ WPj'(u)0: F�0a~ ރ\6FS7ԺTRRdG_=yyYe78AHWeJ7<\oy>*$`,ZϷ/~ߐz{;6,ϲ_#}}rXy<6]VYQ`m8ZvA ]np;{W Af$VFC@D! !7Au1mFaѾO?~<>Ǐbp~xVf%EhJ,+r N(@5OHxހ2c{AmM]7Y>| iSgSep N_ R #bFO?\Ȼ]Avq&{ڮ;# i~~]&,:DEp47dx�^FRT,gm٢eۀJW*GFi/mS4&t뚗7+`jSg -[?͓cppMO _)|#T~TbJqBq*{I#Wh?ZHTع:>Ra, ϧCp(v޲2{'X pJuӁ6Z#U>™'ۧM*p+Q$E;ێpl<6b+AZEQ [mvvWlD."RY*vzU ? $#OuAqT1b툒" z!i= DiCha{o-,C<YӲr>o`  K#s! e-uOV>"YHi< r\հ}؄@+w=׋{ fA,55+|}ެ|<΃(0L*UdzuztzH&p! `Dkύ4L>flLV ;Gh+ة{6Έ-L_`4"e1^R!i?UuÎOGԟϥeB:`6,UzA6/v3MMT~{ yL5T:[nn2A#qGF2xq|t�~=٧('8~숴&ttsFixnrp {ض~Sivɗ`ܾ/In0}]m|AE \#NgUu$>mR85`yK[ֻ5a$p@FaQ,ZzdZChIhV#:rӞFN!%UsYl^D3ītuwRZ{v ,R(mzU̖+f{e`^2S1Ӿҭ=^_]}>9NgmCh6i}9|}u to6,:LЎB4/y!R&z'q]M7L#UOϾ|:o;js Ri˝?~89G -;;gZ;(IF35#ۻ<ƥP}ngc&UvQ[&w }phpsq[+97g8q: 06?|pQi^M Qbۡ=Q>Sԝt1KT:, .--_6rԑ]l_|p}uyz|+7Wo{Rq~|RRjn {G4bpv}jؖfFmz:.aUn*,emz<]q}rxuw~qqpod4LGH\׻ntDD> Li_6Wm7a3_~>.vlA_ROt8]|t|zUWZ"�onn4BZ ^1X\oȄ투9?z=SWU֨U;C] xyztrqp\.V+7Onk]ZTuX*z!uh{ "6 Uhܜg7Oh!>vr{qr||~J(dZ\` #hLQgdw')Ҋ)Hg''w6]Y�QnYO^C)QE*; Ggsr.N`eoh=lsZ@勫:Sz. I& 'j_N oy*rWeAC| |&WΏO/Jӣv0C4-BH`hwrz~yyQ:Ph2_:xX:{8<8k噪kJ:!Ѕ ff<t-۶F\GG-I1^b(;բE zq4{}t|:Ku DfljgӍ /'7,b&Owٱl2%9W~BG,Mt℆.V Í]UdUmPxcWOAoEohŶ?[@7&ˊZ8HAWZ .aeNuMU`iFЭ lOK9^<Cx*Y]mЄl>a."J I=h5댤x_3J'$9$Mƣ)팩ˋ ;m/+<%j)JmA`:ft<TuǾaίe=On e8z\/WOh~8=B}::;>=|N+?]#iB%+<' 9-Ofҕf&XB}GK4flC5y�cUNJh;IVU-SRg+Sl mj0BcEy2:~vKhTY(W/_ CX�ýlgoD,d hQ|e W+pa0e7ekYt"3u72Xsr�]۳-iu[zG6v{/cW{"qi>^m<45nG2z XQ)dukݖnDn8,p_n 6ZB{M*B'x<[gJ&u]7#wHQ% z~bϤcZ8z 0tU r&LuG�Yzo-ptY ubtTb客ڽj5$I1#ddR՝b:d@?]lɳ/ױwxo7Ѡztp.DafpPYHFOgB"`h6t٥@^!GH|:&lF% ft]/С`If0&/?<CKgjUCntt;^n6J-*TMW3ߖo69hL"HXg`M2DfV9N1҆op̷C7MY58 f/UMɉ[vaǞbx鍃ѡ (Ė6GtH(_?]h>/sϋk^=ߵ}~^{)UoZy`uۦk$D-/ֹ%o: |JչґyRSt__ ^⁘3ddا?Zfٮ!Jbfݳć;{f,[zRsׯOKpǒt?e0<h޷vuwAيV˺$߬~Z<[ u=#̣j,ۻ*qEZe@'A}~9JEHo#4bٰyzV8χ~b_ҐTv KYQGCx~d2vjEv6}Gt4Vnjׯȋi]D)LN-@m< ~چ._&RnXt&w][Dm7k8執bʊ*1D4 ,UO@4L/,"Cfe ~h3 %XN]]uNt/E"A?,6|hlxq97HMdebnDtG[vi E:hy(]$Gq~W់V(Bv18ш6XktaY(&#wxw25pa/t 1_ljNd̔WhͶ䫧YJ;,s?}[fy?rmt"a,a[`): ؂jyf!u4 U mY#?A*ur5Ɗ, fǞRkfI}pmyO|Wv]8sT Udm7_MK)ly|ST8q{i`^wF'/h/{Yl{p1-WsC]6EK L"]\_db6׉4gefսhA4ZXdxiB uy= aٱ2jKA,kf8=1T3V%BC֫況k3{ae!ݵС.%?z O/@o chXa_N 2bUuw= $c=/?^<~\șN6m5;yFq~DfXͣmziiRMNf!YyfqPE "+)nGֵ4/tztl/ֱfvGt\Gv6c+2ahAoexfthL>).ɼ}t o$0q/tOadB,VңH*;4¿D0x컆ǎkȠfA[=wt:`:Ți%iCul2}fwFbxD?ۺՐ:rGn9iEqhYih~ ahKGlKۼTu=ǎN}fXӎҾ?`v/lywU]}/lkPcL? I}$VN Дx}>x}>x}>x}>xOUXU S]4#󝎢ș ۫w[5FSEըX<CDICܐ-Md_FZDQk1vP,nŶj(lhuVIJzTor i֟d<|߻/<t4F\|Ѩk? fNr�͋<v7w-^@`WZG4[Mؽf8Ift;FG4'J32w]Kin+U-UFvj;]N ۨ6֟`/7W4yߵ}ުFj<Y D9+`$öukTڪ!KjZ|,+zK4jxZm�*~6[]eXU,4۶4m՛0T,j;y_#:6bV7*(IBrl֊ k̳.n�,r!<ۼ_\ݗ6n]5É"͈j7 jN|~S9:]^DkRaUUZ|Xx!l\/O\_ rT˥RX+=k-AV?׵]*),M>L&Y. Ջ/t:} VMfQ+>VZf:pW_GT;) `YrsqxE wz:E䚕bFߖ-0=揰{iRlUv樺&\Vd|z_ cYxRRMZ۽2^ty"ʊ$]lj;0REv_h.nę~>]*ϴk՗B\MxZgꬨ(tw%ȳQ .}w"ݱNQ~qHIm:ݗBZOsvuk:;N'C:k\=v;))t'RtU{y%j^yBYPc8Q-Q?:L!<GmVuw`t⺀|_.=< p#ԩ@MPnL6V0,/"eXQ6@ V ..%ǽrcM0caDٖM798Q4Ķc*+q, "oV�wyj@ KJaL )VaM]N<76޼$I1sUAMgI(QHF{Tyn7GϦMIn9g7 uX$N,N(vВ&'</?VZ]G HF Ѯ]ZBWbc2tϱ<:9v5P9! "= H4S|؃L趛?m4۩W N2d fcCݐ鶻:4,?I=S3IPXͩ0l|"Ϣ !#CmCa6 |qHȇifJYLΨZګaÁNxSШ\ItO ؎g<'*D2f.0"؋EHnwFwV 6 PX L*sjR4˔dCO*+ZԑWMǖyr1o=GWZ?Pv�$!mëB~0n "r(Lmݰ* ,5U(bqE~.޻)&BYQ3bUWMxۤN0Qktsmnfy.jIYV^uOhC@9V0Ҹct7+B6a6:|n .I[=iU-3-qao'rL~u':I~MԊ-IE͡&Z@d9j1`c9V[6v=⸡@g4ZɆg;2\KmCn*#VA6=K'ZA-]7ڼ-A*Ө1Fi>bWv^.9{5 H׮TU FX$ j D<K�ݑ][d]x<,q ߪTmr׋4CK( ^dѝy{}@FԱ0c8Kb*{ Pb\Wqmw-]lw%2Z_.oot˪R70}~/rlaG>`O4'I [ߚaQ_n$c-_Z A:(FQ(7PT\&v<qGخZ�"A \j�2At}'(ک>>4Us*d<K7 哎4*slYx�lJx"# S)w\V('Fٮ1U�$$݅ u FdElK[CB (549 IfՇǝ6`8$o׋$pУQGt`?K0;jS2   6 BxH__fGjM "rkaPxGu4u4rl08 ޖ6%~L ;^o<*-vwHL@\B{ڊI˚"ӪeӋ?6�|C8CKݥ| Eol>HvYUSpx,ڜOqh>EQHnGA`IZ(Q76R%1}{|ºgYJӲfY%wN}(G pr'x Ї@3i)rsL"%ʇ)�"Ŵ<#B K_zjaҨl:jcƚo6Wjd9L�ǂ3kV2!U uJWv(1%]F <(6gxWy:NCr;1%̇d3TQHF"SQ,Gϰ`+NP":n n,P$  crcOש"'#rhnܟ Fb%۽ufR+RDeZE2F@T ISo^>C&_"@+q ꧾe@t#NBx6[p݌-TZ7ڤO."M7fӒ֮"KNl@B{ore ~Rv|B ƱJ zTd]Op#6E7hYޥWF5&}jIMDg1uvІ9ͦ]Gڠ9i )5%5 dU"B�AЏw- j9Bۑ9=<m2[EQwjͮVd8-775b`<`:�hB+e)\GHf|E<I4ttϷASlhbJ`V8{ ̄8oojG6 9 A LW1Ø(\ouOECt❢ںfmD:m7Ky4^+$DK y̩Ch4ܷ{ ԧРspy0 " `fae= A|iÊc]g[,+V jI"v4>oWl6_ͷKCSdX1NFhZ'4!u1cd9"{$mHVJB =0geDٔ,L 6/fbd~TSJ-]MTJfClPxֳ.5l@E`GV�h%J M9<mcEطX?mg| xVmvFz!,h1/&yқN|Cd#d j1ٖL0#Σ"0DP-SUA;ۨ՚Put!X`:lArĻIt9b2+5fXA(f'Sgdj?ݔ*`k $$n7c/N ǐe3O4 ԕ `{:�x(x4E4qy$zU 5QQ(pjQ`$ eH7,c 5f�\ ݰb f8u( V`0m0޶Bd&Ѿ8'2GeZUYo R"rhDܲvL Q:7�R+a 'Hi7B((ƣrk"]R|LwcF}"퇦 j07MIDCʱhZ3N3еr<xJ uv؝nn.b 0ul)^/5#NUc[cJ!jqۢ:I覀]1}͊xT[j4a,Sb3<?kȈb8pEL's[q7: ,uMi�'{`1V.9䙎oX d6K4qu7)M7ݨ;<.GXQ1^::h/3w=iS5h_j+jT#M[*| K9m9:{ l4/FS7ϦfL9H0K<Xl/5J&hDo6@@, YOCJ�Mw03spȍk:oޕj)J ׮6ӝ;i>z%q:Xma8dqƧi: Pl1LQ|XdÞŇ؝,+6:W%?pZe bB5<պ h:zq֟rٮUfeܷ" 'p!{C�2 Iv7͛#sT>(3@b` mt; ^D6v^-ÆEA_ 4Gs4#RTai; 6UFɺ#`٨!Io+#4j0oݻy&ԇv8xZҳi?`q 4LەVb0_@4{A}PW Y82 =@xCڢI+6Ί<Q9o�%E0O�u, |}|1RX@g2%PηO[2;#jm?'�EY|>Oc#Y|Y+VN|ttrt~uzWm&Chjy|leAy;(]dcO/JoUZKRbLyΛybJ:GcM z45 |]pp?|>pRj:.B9P :#61:C ,m_1A[f}EG? _L+VӞKLWɩPYYa<JT {�a_qv�;!B\J<fw7ZǝvQtv?OYdHi~C|N'+v0: -dvuItʫjHLVZuLEw|?liyK(o~ gI'=fO 1DLf*b]%f RdaA(vO9pxrN`Y(-I#K p Q.>)V(L.O nw}zzZTt`KkmTLS.hY:U~V6%?Q)`{*ֺ)�VוFz"" Hd)vw٬'-8^ՍXLN:Wbs!K"t=M~|$0Np7[ëg! Xtގ]fY-Ǵu uMV/,۩廲\>>\t aq|5V*N:Cz!CY|Atj!ZȆ$q#;6ǀkKb9<9gI1 )*eU[dF3dayQd*'9-ģ2D(HSE<^ImAyqK=[/#F2<t<]LÏU|2&`:[,Wq~qlR elqD`߮Ekc._^62TFQ?b9b?LiwEVqYԠ4dl<[gi>^;6#Lwa4⢛>N qi:j$n//"̖@@!~ dIF )!3AƞdA#x9R9PZRzxv:rx #>{b|L_f3(P�tLekhd<HNFSxLpska6`4.Vz4 AH6'Q>\: @\ofɈ C!I.̦#Qq'O|(MH;xE7ƻSb,yK V]sh\sE?o߯. Zw#-4 yY Fq p4 yJX.t ;fѠ:#6k O^lCL }!;�adY?›_o_=14M&Zb:cA7 ;}|rްCi 5O0(m{nȝ5fOޮJ_5gz^wߒm?%~o {uZC3MlKZ:=)p&Nwoob ' Q;I f//_W@la|:+U]op/ۧYX:RQ,@Sn~bp8I0{Ļ?ȸǷDmCi7%2ISRz ~z~wZ?-" "]*/S=6_ߔ~ٰUTئiBi~޿6;�bd]}RbmKu9ެ;oP{=,(Bz)yl­;k1P* ^vޤ@*w]ILQI pvdHyQRA^`"ֱf)xZ9Jx$6Q!Fx8#d3|wxS~y.iADzOXjeTOVkA,.+[[#2@Y6_7^ `)u}:z-տ!lg=]prL2[3H ͻ7g6$ہE8FA(ʍ|p d>ȩjuۣ,t7Ƌ'hz=T7=غt|pmu~b/o׋d2ٻ`*;+ FPFKo�x|y\{zAՐl\ g[Z/XA N*LK~8=.˦%U/?۷�׷<44!(|W{0f7T󺃔5 ^? ~|V?V69!~=*ha)!Ļ@F0f=<X&.$9Es=ރP!aEd!C"dY A4rLiû߾}'7FH$>18켚&?-U7 _YX1.?{܁$ŗߟRMY=ۃ߿} )n JHfmOvWzhȝlKoͲvW||q>h t-:X>F$}IRSv=f荣wPwo޾%oK eZ99<m͂v]jL(/f 6U�"7!jڥR6ɵw Nod̯W5 31cY\]atBr׭Ckv(ʼmj5$<zs`[ĻE3$ٽEܡs`y^g2/,+ Z�a#[;Wz.,_�AB-V=>|x~󗿐H>݁g^qj^.z۬xHB8|1W|QJd.,Mz&ɮz8E)'Gaj(VR*PYnl!;CЃt�YT`ۯ ĩʮzeq'S*w>??qݻGW7vKr*f5Jz`x^H2ii;$NKsl4%R$t Z}tZ/jWߓG' NM jPi+I:Kf\X_ m{L#Ix)5+M߇WF1( 6pmSWߝ6WM}R?E\]^;QEA7L=9I+HlFTN)"gJ)(_|<:Y6e1<9CrQ訔Pq\?E_iw6Ilo ;Tc}o$cr#7gj0 vW\[nޝ_Ea::'Bѭ1hN]sALA$`US;Z%軋ta;u&cs{7ǃ,s,|8B;N?_Vzz2 b߾9;PJ@^b2u0,lV-B_iTƛe/p ⦥9 B\oCώ.OUo0/Kro9_dwܳ뒧i:q h2Hi-Gc F\ZSB巴C$UNjAeWWDǷk\|~Z6Rdc-A#~>pVay.YBXĈ &q<]Jatޮ x1ݠD9^9u4׸:9R`FQ?.O>_+ۻl;n84Go5@#/KX t(Ó{Y^# 'Jĝ(S*uf?_?\]}^M_NȱzCYUf~gGg}lsN�hCrH*?~]#IR׼<;h?XZ4jS5x# 9N>}kpFQ;K .Q;6g$Y>yp7-T·wk6iŧϗ7wny/m\9SlW-:MN<pEw:*5;e}}A>|pT z1I�L/:!Q?C80MEH(k*5|[b+Ý٫ÃOwec +/ G)5:tm=:=MfXY3,<?: #㋴ րN>}hN1H?;nA@E[u7Ċ|qhO_ZBp$UN+P.tRڔ9^q<-q󶬛p! ߎ肋qt4ᇏe Zێnb LJkF:{vpptɛV�KˀAbKgu쨗t4FE 3ёA5ɠC\:8;=�"7]o˚*Kg)_Qlx)K M@$IP HV:px^`>%?: V0ډ X:W*]^YΨAC GҌgǖ«ب+V0㐮PGDݱ.>^YŲioҁH5>גh^(f؛-ӱk2W%0e$[FPt'ҕg9NTKř8|qwuzMl` жpA9۔[rC2|1 P5&N6긖Q Ŗ^v%fYݕ\<ts[=�sbC]VbU;.jl0w0ZЙBh\|X7$ \Zlm<לuZ:@іjHsQMsri3UVWmyd1á7yzĈ":> \%iqZ?9 Sv ڗpl\AV o7uEjU߳ĚjrIw{iD+>$Ǔ 'Eh.< mZN(N"Ck ? U4d{\UmYuAlzDTO٦KVfTfA|58sʝhXn6,�=p f31]$VV 4J'| LUmbYp~w= 6= M-/WN]*j@*KN&ɱUmsn1[.67gu''"c�o7,UQ2G& *T5Hőiq/9xnX:Ȱ:9hBm8t4xմx=SdHl^y}`ӱlI7 ^-2TLc&0QXM[kζf\i*=x7_VJ%^-EQt$q5E|(is؊%Gxl嬞c$bzE S@7z=n*5^]5^X DYYVi3mWM͖O"=힆UFr>R>vC3 cOR%?]ai 4K9x VHn<>-;-ByZxQF8=Q*8a.z IM49jlM1nl<[=o2yAoНQo㗗 v-U4Z#2vfJJk,/*Ж-'Ofiu {g,a� "T3<mwMBK SOXAtף-Xr= _߈MEnqkzzkdf:h0&2%y{zD+/|ҴgK_ývx} Yn<& ~gy\CO '/4#\.tdU/R%~{H�0!XQs<Rڒǽ~9iwdމ Gc/ɴzu�ʷ�.?%t")dNd[.lMuXxaO77,GYE?s%KJө!O{izO1h]w<۔kMi;+Bۊ&ϋ2t!Ԡ3k! ~NvQ,ǵwqqEF.yz#z;\Si^,*¥խh0Vy-ʺyZE8/.z?EgjX e{xE/q,LMC,5uj v倡7mxt&;QFH"vMU(HѢ&B<Vtؾ}Evj5hN,k,<]s{ ?*~^'{T$O<TJUΑo /D;] 5m ̕58 ,7N 5# "WT(=Qi6Aݴ#ڒ/l yiou}G)L4(;==s$?AݿWJQ놣/qFqd彻lAz<t7{^gvO[XTƕZ.$Y),ṡ{QIϓ9#]:aƩk /R'BD+??g:&_,ٙzQvsmnw{<cU/NnHlGYf5dpǎ7$/N=mI`Ab9v6A7&$6eףг'T=fqL]jV{zr1|xn{ 3jmd < pvKuLWT ,S]VNpl:.OeU?"x4"%EDij-29Za1VsOwXjyGA,R՟&,Z'?㤽jRzy :?+eB8YUZۮ'Ͱ=ǂi{ҳo1eybv:@6HB[闗ͬțoWQv}'SK:ϜYlנYM=wl8M]c_=׉&0s ii`"w!lz{a1BLWr`\%<+,Fcd"r^RϨǟӹ]cxotKtz܌bG ,LS;jikNjV&wG>vUկx_>3Ch#8, v&5]?ѭ*"[Ԥ/.n;ۊtNj+F}&u/"jkZ@ͧsX:QM,_K~/%_K~/%_K~/%_K~/%_'iʿuuܵ|{RezOZ{.D,V0l;J\:UkǦx͌Xe!ϞժW[0A/w.-"CuwEnjSmO<uo'y?SCP<`[?ѝ6wP ˍ㢗\hLs'j\4 Q.߂_P) 'ˢ(kvT$Aҝ ;E? f./0TZ{nkJe<1Zuˍ@c;ꧮ$y4{Kjöz j6ahPZEvIaD4)2˺՛f^5me[9e,NjFTi/:V28V8M =C-@U(l@kmFjAv }W~7:cqs,iEMF(b\oL\&NDVp4*[M%YfUuV͊qj]80DVm4wFgTϯn,y&ſ˳WE*hmTQi(_]VjmU#E5RtsQj5WƑV7jK5t-YۍrMPu]>T5vEr_yu|_IScu]Kfpsu@U|th>_^acYFh5]|}~`5'Lз?)ɋa&4axAfMNT䫏󋫻f:.KKUXm?�~q$YJi渪nnRt檪zᮡ.�K!Z?Tn>_\Yٰl7p4?]eFwKԟ5k@6>;-}t{͸QXIǐtS�wgוZK qt~ltu%4Kг J-νCɧDkNc|o>TY4PG<1q%Ůk:DhDl0:*K6L)b\%^wn9_ C 6u8Mk3n4R+P*gUYg48NdEd9I4Fb} < yO:]ngG fN؉ZL�Kn F뺮59MO\nצ*v2仉ADv\2 ^3\,82z[nr SXB@*n;_gY4�uUbR%ZVAm"ڈҁ Ja&5E#Q} MP¢.db<xm<G 33xST^3+Ϡ�m;4uDwUO+]TrxJhY:R!aL)FZ ˍ#~Fh [jsLuԧ8TyaWmjZϷvT9BP4* ?!V&%b <Ϣ@$U fEUcT˥VȭR+) m6ۈ_yeي@Kt07oOHPt$:Idqj2"h`%dCP{aKWV-eрx*$7]C[xXߪ#˚&֛iTJY^uݦ ~zXu8DC=U)ѵ4ɩ՜\[8k<ScMN!ʊVsQDoTi "q: ˡP h"'(F肪3 |0q|ϖj7N�Jh&JF5T`Ѡ%ƁYcLao!R[.a %uf;�do2+[�xSGlYF8 ȣeD5Y3lK#7xI5 yhW P2�maPz#L^G ݻ57HEf҇ x8e`Td ^ARwdQjd´Ȋa[jF3䱃|nǶ~kS~d#3#ƶdHDW &rN^,W{%I%k>3dMHi6][;0s4NNv[WUA9�Q<cDJ.loݧCf(QkBwdAʭ`2Х `?"0QL�LH2G=Me)LmrjM$L218ҩ# g덧Q7Chpbʹ0vZU?fіܸ}hRcT#X &ʶX Ɉz$"kǶ;ox4Jux< 26 *:nP:,7K%|TrѠ DV( ڲ Vx+k8.d7Aq|[lW.Yӧcj�b�z9@W`ըۀ; 'ͧ>,cꚆgCbD9 ދhXٖ3y.4vVoUjf9wt4 G٦�x`ͱ|(vl܇- мp-ېZiE A\eg4Џi-١ ȢJsM;: ,WFpN :K�Gp6G=NљP36Wܵ%K#.*LʑFc#%]ꂦʨ7yQ1@U^Cđ9]7NʠRag:ƞպ~ΪmΤ^\-Knƶ$6�Q}[ l7 W~a~7i'IiAw2)|W-['1%Sܯ( ) ~?@Am-Q$FF4äd5QVv@OeJC$FVgU&pD0IaIX zn]znE$ۑӨU8[X45A=i-9d&X`5@I-v9/<[iܗ$�r>uJ?vC6`k ;v): 'hpq |Mn} 0Sp1Mq ߖ V4]Grt{_ m["cSPK=-2c\ӎW 4TMU*A>]mأ+|1*UIҐљ%^"5"+-,�#zsWM6tA9V+@o<腚H3 mhF4s^cڐyhJ"A}2E;Ymh'V�b# (R6Q&ge $4eɺ>&ZnZBGdEY zКulvFxƫSn.֛ib^mXSg1Ůc�8[BYIL%J9:m[cGW5뮶.g˧YtCj�lکk{^sWzZ|6#�Q2RQ-dmQ4^Gb8eX]c mADmZXᐚYzMwsrt#@%KR'~x%;*jD& @4bˣ.LH! 8!$z97Quǵ^ f#bij>vE`hifFƒAiy+L\dd$nhdYqrㆠd4ۑRq,G75X=nd6C.Omڦp Sl]wj>['d8,P:H\BV,ϓyAXE `Eh+'Dy9"(ֶMҰiʉv^-f|4ŻIQZaɰ;:?gl</")V9V9�Hv QEG7=m^bZpsM^u|>ht^ 5Jǝ|ҋhsC-Fz44 %PEqൖx,.:t8GJS$ t7 JtUד[50 3(BKQ׽J#9)?XV^Id7D٠H!4= ?/f$��<ס);Qݥm6vIChF"pޛh$قs^eJIĎ@/@`3?נ7o$Ug2)-<̯nn^/r/դ{7Eܛ͇_.o:8A" 88ĤDޮw #H͚0iYwplQobU�ܬ汁wiLoj ,ϧ]B KOӼRwq7#r[:!a  ]銁bhC;dmF&*E;5p\NCV 6 tU|.ǻnZNb�#Ƒ*h@ԒnNVD3Uv,x:wy\DZr qćaXdBF7rqlrL|CLzGT%4KF!fe`hv6ebPZGնa!̫t?ܳ2@Vwl^Aeч^ϖ+|5Bϵz"fQodISe=z\v-U18w3-f駱g\3-UQcgNyO*k~Xbgj2Z 9d "55;]�XFڎ|U~鲤a]h`)T/OO.//P.Wk -.]=oP\r}n`ۊAB * Vl[avc}tY1Ldd|t9Nft�tjm8ԤTee&eTbb0z]jlk2ZrQtP f4¨.ċvU MV ;\vl*bƒ"zU;SS*m@yyIrTy Ai㬜Cz,S0RPͰs1%pa1zXrDDhH-ծW$MT;?IOӧ#tAzNIFp\N#td Pڹ"f36#Rz2QWXa%]aJLR"RY7/$ /?\5;a=6V%lе}}yVNgiNd_kpzҥހfUrd!&t55`.>}8s nB˦FI ޿paXES<v<ZGa8LAw\z9ڐI Cnj e4b =kV2y3±l-NIN}˺yXq-`v?~bڔI2Vӭ|9dz3l̂xo6qZΞ_F- XnY,GD&Ɔ/މ6" ,/`?<}hNTehPD5oFf`ȇn}rT$W +oqQCfKQy+lk@Eusu"4`0`/kN 85ZlƾBmOg/_.9Q^ 2=OQ( ֎oV�m(QR7uq`9M/I0uq˻�4,˪],mvȀaՃ+(xK)?i׋lC] s4u{IF3 ,n:?<x~Q ݂hB|"m $}Oݽ0�܅93JuȇWIa4s_8)Ǔa0L'~d+J\ ɫ fdtb|4Ux\/`B7@թ:vR:5O ٔ!ԱF㥥󗗗u3�d#LdB<qix eH;u1˽3N�b7Ne}xЩhb<D׷/UuP[v /ϳ<JG 4` cgX>t }FLH�l8_O:xItN3'^vΆن^7D pQQ_mU[P)5]kvI`4"``2/&v"@OzI`4y%q9_,L9'ZQXm86N@RIK'{iϯ|XLӂ4o|> p E;[9g'57fx5(hf>[@k =v*izNSඛDA6{{lAoAz=͜7QGK0Mi%zEo/OW,x:|sugͿ[*=xEQǰ@F7oR|<l/׋xPJl 1�48M s&F|q PAE9LcGl/ 4Snn//0A%:at{~ܝ_^@CEpwlCWi^㾄̓2˲,ԇȤxH׼9`(;P|y`O6lI(nd V[?>I_m4Erz??>l^&-0oe+5>~8ap[>XiYY`'Y8:]-<PVj33__7I׽M\72?^|'o׵� df)}XW8G]đ$O*t (]\qWй_f7qxoUXtlz'8y`(t!tj{oi3s4 p8uS۷<Wt~++*-A3hAw(ȋW|ysL2 j<T V7FFoav(ӊN 9=2d2g껽wx8t;H Uia&MS,775ɥ|-(덦!ZN̮(x^}^Aee4op4">'b�r6%uXeӲ- �x19Lz^v5W+xvZfQH ?^Qc-D|ڳ=%xT}O-@%D>eSjjukFM.a7͍:\�32Ϝhh9L)Gs| gnzSE?<$5RG., n:S-tOCPwxn^aW%h11,_^o�7D[hd/36w|Jt\#[<X3J<j|21ՉƉ*AFi$I;Iy�[E%IA~7R#lQ zo,z}l^ǙGwj$.(a2G?SL4ǣ\e%QZBi]\BP$Xn#my$InGiSx3?gPT0ج.ZAS{jK2_tw>6=^d`azZ.w YIXA`3 R8,=s$"_&[9Hj)!-o]]]]~e'~$3L 8rr ,!LUe &g8~6v2KIyg>V ^^7w&eY]~}p%vE.TNo䰻-M<5U8A< R:~łvފɒ(6C.h6.(XK[\)!{{Do~fD씧Ϯ|o3rђ m(mѦMyߴ gN6)RͣX&ED/ttM}+޻vxr-yyGl#jh5YKs %m݆D<3;])`#Dnx8 fZ-f%t@wvw`Uo'~-IUTvC9.Ľ ?|sHtc[,bx4v0f '#2Dt B;z;x=l{ pQTYBaPiϘLFqEi[o==M.|D xT,E?s`dgAR`6PYt& U;�n {x|ҔXrD "x4O]KJsU6!3镇' J$-1b4AtE0tR5wpy}iڏG{)?^D)}ϧ~qoPAOf`5Շ[Ѡr90DtvųMEI^a/\"]HF)kPG+WWA{Yw|8+QZ^{pM ,uڜ<逫7EvЫ*G߽ ˋR1ZǗgcZt-ͥK&0΋W:'Un]*;dqZ0 ^[-vt7 !NH{qǻOGǧ~L4ihYoOWtKӞk˛j|Hoۢ$M?ytkS77gW{8f,�Fu ǃw5 "K)#յ^pXxzxvSM<|3/\S;(#TnA'G`u.N/p:.Oo߾==}7x໛R(5Eu{QX##*C{- �sX&骮GEQl֖m%G7w7Wͺh|>ϼj/o 0Bm&I?4QCki./N4z~ 4j;jqdvyb x<ytqb*W|.(~mWYVA톦6!,smHx"lϺ۽##ȵۭ6t(hbbLy~NNg[gOgg'Gǟꬠ.[^3r9PW[rpJf]@ {ᜑjOn4x{PkIjJVt pry}qrrq�\hۍ#+k,]s>=WjorMHbyӣ۫Ӌ õQ'q'pzzuzxrSeXEe5;LSdReƘjܖ /O>?u nj9DaqkZӇwo>\T!UE:3nwGehr\tX#jP GYjb ÃkV\*X&f"|pP(z[Mw}B-Se/+GoWGd]!#Zmjʳ|yr|~@q~uq¬0ʀXO?}<I 0 wDV,1 r}|t~ FS|:+<BCߢNU#wcfB_]s 0hl˰}KQ/ONYUCj.nv\$혘cÓOwblHi?j^0t݀jl]ݝiƫ4FuhK7,o`wsW0VMlX:tpL?P[&zwtɹd/5;/ƜiuͥLJ;5+4e!+δ[an.>|8BpQ#m=hWWeaBpk'v4q4CfZr>vВNMb4-1-lTOO/~OoZ:^72FcâNpw*.-DuVG*!z[neD r)g005׬<VjxUq*E[(۴)ચ" gWl28낪Ycg{7Q/ݼM֫$6hɄͫzkջ6HX7mA&-0B�Sє]T?ĂHl0a~yw)N Go4"ɂ3[IO-DR-?drL_|9"6T:VU1M/O jYʈ[Z*xu٤e/*T~Ԏ. tQgEad"Z8Cۘx0$<wǴY2SmP}/Eo j'xb>.0cUTu�cJ{E?MM7H?=3jL+yw0Ӯh<_0d>[SU1L\-bK/6~9$v c"ZaO+ M/3!X<.(|,&w2*Wؖ[J谺_fUL7OniHAEƍ'3O[T|:_ wʀ/;(?X B d9m`HLEd(bA&I9T J7ڬN[^uŢmÖe.CZ#1r|Q:UA7Y̦^3*n2&?&W5Vub9,k iNo9-y=->&O`]z&/eX*%f>w ~DZ[GzQQ|[J.4̶ϫ~dcWd5]U+0 鎧C^xf4d"gxYn\ qxX'iw0l6]Gn]<oFm Yj[b5wvsXSCv|/@Y6w;mPZMrzYe& r/$"=JI;|y^Giw q4lN5oԪ͎ fkqit9_S2l ~1xb4\?sφo7XH Y"0N"eNݭqK&'H:֠WAoFG kf5AZMʼG9|M/5EMD'I 2vdQTʃM'P5vSD#S d<yыğ,5H h@ɭ[ƏsmAuq1J[3U~|Mp 'n8[kUogE瓗?7IZ l4ڐǽ-TȃoSn(BwǓeyC L u!1)ϓ"t&UOG&wUsL2*ox ~"F/m? r3 SJmїͨ[tglG=a: gT& /4: 3 ^Kc,K:/n:dIypYܪ"b8߾at:+|1Ei^qd@jn?1Lm;aɖ$_gy֛(p6Vҟ/K=~czz!agquF?B{qM!�;r yœyf gY^:ZlAѝ.riҊ;QI M]E큷bS ?xcٍrTdv-Ngjbqo6o~%A+A g7J{绝6,5M~Mtyp;֢@ 뺟 Nf!ťAh.!&NrP6h[oR֊X~%p%e0nmfEde?A0N#G1 ڒlv? CnqF<{|Y [FW2_Or~ I�ܐݨ7LCqSQ㛍$ǦyWiחqhxq7Y-|tTA3p "UDг /tlu=S~|̺ef,,HXˣF#0HdjږڼcQG_ce'Y~^f&jF `Rw/Y4 a!$S${l <[M<qFx4lo_7o :8U'Ӑu]a1*u2 u=̇ Od#p8gу>cWG9fYMj_֙9qoZd]%}'e*5Ck8&lADuW̿1KYTӳ5-6tQ%, 4fqFGPaud ] "[! Wcr¶odN<0uQUC݋ lC 5;(_n֫voˊ,ppT4v؁3M+lU7j{M+*қIqEo/r kL{y9L8@dӭ]DG O7P[7 _nbUvAt|0(s?R{#`Cz9I\W8=j֧ˢlQ- /*OdT`=/|WØUvMSUEDL] byj Fw,NWW`,OHc"YyQ=m[A9!;Lf҅y3JB86X߬S3K@C ֋$*ʢt4q,,5NGnADzѰ v U/&t#8K/E8^CP̀rݢ8at 9wR ЌSvb~okƯkƯkƯkƯkƯkƯkƯkƯkv,k% YXt{auWE~]o8ʼt+QLw)~ʮ'XEً_J+Vf}e gun/7;NKNuf% K*۝Z^}Fp(eF,=rh:9ڶ_ )0:\^Uv}xYA|C7.^?5NzWZ/kIVǓQu9Gp20]JFCIfVKNPT׽ƓApp6Ӽ̧<j7kZTjR!T]kq*.Xh6t7|4 ̪4uBV͛Fh4oMk>Tfw _ml67 a1͆E$<Ia`~֛V`tXݪ8-L| rVjPiI9QUǔ9Q7-nZ ˱p{w_gES:,?˂3Zh1u'ȓ꒦KrFqZDsS]*U+ʛr(ʢ(mSdi:xCkY//o2ǻ'{>3jaWP4M4YH>=a~C%*Lrq|t|q_kuVVor~;Z|hԛ0#4R(&CŊ]jC0Fv~z[k&Y/,I5Px[WZ5cZRkv<x}q_o:ϊi*7Wfxx(vȳS(Xx~Pȵ ͱ wZ*OՇ뻇\4neYE_laL.T*mVe*%۹===zwpuv}WgMa[I|@01 #9qB= 8͒Lw"OCst06-ۋkFFd4[n*_i _ix҅GGKd.5 th T_Vըk.>]?޵Y$em⑩}+6<,O%!LM+T+oiz><RL*x%-BOejOFG6㻀7o0\# }nfZT9\K3FL|kT ʲ8Ӎȷm.r0Mq51&:5"ͨS;^ѩ +0Yi,yæ1}zN+V;!*wzaOȳTQ0,jX;]Ueo/e2:w"S/(vEǰMxXfM8O"OZR^IZV�FXdZ٘nm_ac[Q` mt@ěVQ%:,n|2ӆ ,0t۴l`my%jp$bc(TGeJS4\QSE {8A(m(PAY ]j7FP{So'tIs\^X Ln;vuA/l !hݡP 4<[T+-Q6u%oBH6S5Հqnz!Ȣzvjl>^)<[$UR Rj3jM亦wKE-jDxE68r""!=,J1?Qp PYdVCxhvrT"ݒYQQR_澥b>1"8*XG9I c,rר@A$E&mQ&ϧz[^@)Cj&HWI�j|P}VY;I|1hp*|CFпN^Wٰٲtj-k.C!qߕ!BT[ow)&Tfma4f�?rh[ШS(q< JW j*cET;<u@]džw U[+Nr4O1`4ޜ;fRZOtL?iCS|5P@ E<("EsCTPԦDI>LGE@ #m@ ƏB 1 C ~/[L tj= Dx}#YP,7΁Adδ'L &I{-je2vuIu6l(/SdF=vuzv{{y~:ԅ� 9vPL> jK溶PEjsG&,�hyIXFp$ڢk#*\=\:ayp߮Iu+!UK( ]C5+SK/|0u9`k< f9 aGF0Xd:f%-8{"qr>h)_<_bN@,)"Tkߢw&_iH*@H78yt<Oo1wG&G ?GƎx:f>a'i$&$s;EF[tX~]~k pj5%ݰ12n ^z0@SVSvSSټ`Ipx_O}Lul,vCb<HA*H,O=x,aYfˊ~lk~summzx>\C1a릑<.f}KEl Q/Pv}rfCP_VHBi8" eܢF8^ "K^uЎtLPfQ}/Pp'tE[_ Kd>뇶butDUa*o)K#Pwj(؉CkvB]L3(DArϣ ,Mֳ�fM%@W > BG:@@L!uɢēۃ<VQԿ ,aV b]Qg :B{9kz=EYnFqoɱ$EdCCTWtIxJIxQЌKX'$/yj{�7-vJq,HnX.F[ sA ,M[L�z(lcO"WA軦pi/-֛EA]m:SRɦ ?� {m~H~9Y!oeMlZ5d8jfbrGmv bPhm\o%SHK3l>=8ŬG}im4 Y|9@fJib�bߍ @<fy$QRS8QVK$- rs^ 0ք~ou)Eu0zؤ6 ȲOg9ت׫u-\VR,* fAMpN `G2PHȨs.~WZM-chvYF~XLV> 9E:VqR\v[vL.aBVD#)`0 8~J&V8ZGXnt`<I urNi֛2 e2*fX",B`ऺڨtH:A~ XۑA 8^ݭgM6b 1);nzJO_W{Έ&0]% ,Nvr4jcjǚ曦 J]]+,׋a8"hzl}`Ũr0 j֣"ԡ?X rQsP;ԕOS;,؜ð<*{ In@(@t+m2観-@ۃ$n}#ٓt7n9c$1dw}\OW;9-ɅԨ;h1!<&mE #QAy"VYjBSzjZǣ!m.B'1jNv8Bt,):]8 58 (;JV}ߔ) wmH-iY`kBJTѐEt:[ �/bE-f9-u &I1!=b>WlZ�d l "u5@a'#:`=PWo"'u#bT'B bdU7ɼkn4(e\,X'{ߵGd؇$H*###Xk93g{d@g=,�ia~^wsaJѸk52BO ;+ϐi!ᛡ�mkA*/:[�?0d8g PS2K 6p^VSXBb޾f@C~[�"&UNMl2'9t<,CU^誶/V`�8 .�Z54'|Uvu3/R '2 r<_O66;'9`\�4LJ>>O"&PNCTQѼ9�Sd Nea r=KϪjZ㊰#VTg�S.WSpRDQ1V=A2O \�1ir4K՚YU4ՈێiʚL:4vw|8-q�|=uMŲJl0g;?d4*cxE̵MVr�L&@nȁ׃>՛+3̞_0hHQ W_XRauM|\aob~R6mej%�#ExVf�G9 2% fQv9sT"aq]-EP* Y+I3+|Z㚰<Q`ln7bOr8߀CKVZc츧HXwN/B(*sLXu-POm!� k%LZ5mݞ~?:9޿$ŵ\R˂Lglj-VQU3fU}�E=:8�r0]/2]ռuh4@#sDRa1i+DFM6% &Yq^V0+4zY/ ׫1Y7XּVc7k a,y԰'i2Fۄjp}GV;�x00c3zUي ȼݥ# NPBR;m;@ⱅbj6͞kkcw%eS><uym6�כ x [/nK :Y~,7!WGX f@udhZT=x! tgJgN$ãF`eK (H<Y.gl ~;Ō U-`bGfQ1t,ShDi)TlIY%Dyyڰ"@&ΚjGqbܜ_|rxy $)*1M՜r>� ,I6bV(i~oRË_c3+ $~ͦc)mLV%s؋K,aO7/7cY`e˒ʴ,:7ȨܤȾh h2 cxZO0X[(<;LoF:>7]^\%r/׋Al߀#S 7MK7{q~T( pW#֛en =Aj>*YcI:fWǟO8XL8Iܹrvt sUX^ea߼mޗ D&I Oi{ngi^-kl@MRVn/*08j'NwFgi# ĔeUAa>ټMT ;,eHS^e!dLABO "bT@bPf{&"<M'&xIrfZR$DP9n(GIOכ*FYkQ>M}^m&qG@yKm#![(\ M3si^Ex2L]41,KNvӼ98:Ү'r>p I32R!b&LKb<;ust wFQ<v=dlVJ5'tZ4۠x7Q�"=ӂ =F@gٸ�6o0!oXCE,7vjyD.cI2bU.n#f22ӱz6L5:`T/Ohh9z<f@=�o2V^TU L{nO��D;58Gjᱸ:dFٹr0�\G|ld#.'Hȧ"<uMY�a� DQт(v5eEz'B60GPӜj F1=UzUU =!�cUx]tt9~duF$)7/5a_O";G WUq�G{ǖ-]XI/3঒a AyֹUHplf'{8-d1㛻8XwϖH`7*"'dW}B@j@AoHE\ )5 6tJ !rZt<U%p *p7+sh`a0^$X-`vH jHIkxT+n>0U 9ѡ|4iگFڵ#7qD7&F+]6[췷_S }?H4qXl=�{le R]]^i�. z(0I7au5UL?}]a#^0z0xۮ*iF3QO�W?h@7-pI>X82^˃6 *~Ϣp+پ;8}d^ [,@$路AۯT {SAm%rs`޾7~σP jg"EYd�< q/A7<٤1Eu/�=v"7Y^1}绍Mܾ-�G{ۼ۰ h@kw';ZY/<^O0rEQ,=GʳLu: ~FM b(|=Qx jM|kpj#ǚ5|!(�e"[= 1a}Y1+ _JQ)r1L�Ym7HS$ 1 Dpc1TyFn .�̉ 9maYUhW|oADIjPǩ!fk" ܲtf$7Fv~pWh! nvZ%0  bWYC x_< `9Fb[>q?:EeЏiG<[di@=YlUqL̺53^l!(Ю]K^]ފ* �XIh@%ĭmʕn;Zg v!Iv0vjcKcV xvy0$ dX+.2KAp[xD"b.`2"`8n6/MW![;q: 82 <L=h<�M e湋+д/ ZKNQKgG'tUb\}S e:,lTúחFur?DŽdc 9y�c9Ds N`^OOΎ5GZK?}>:<8<{sEauKmDth^E`E}y n?ea<Tyb-!hNcޤ KSFӭ~rq{vtqs}{qx2'*ôI@Eϛ+dGS_x@"Hb5nOaV!=N J;nYHjv:2n`"~<<>>iE_u9I Ր8^{]jܜp@Hp{z�:TI-J;L5w -;}H.Mal.geX>&VHuI?}~guqtrqqv| s&+uu�Vsx2]dE1, 4-cJ'Mwmss�!7dGs@Jax *u_??eW_C<xf,�(r x>OC <p6Fv 诬9͢G>B]�*O/_NnoW?}Nqfw{N|8ϧjSԐb@`(2^ '~PDIQ0+$3!̽^__}6?hӧOO"1%†Q 2/`4U*AfuCۏÄ]Hkf:&aUtlc-oeg BۓWuEypyF/uTdd�Rn0c5 oOuT&ڤPnղ5EUd# a-l5Ov$>_rtp##!gmc 1� % 8Q;~i `~hNvkPF[v|9 ,ΆE/$&Ѹxy{uRV.ۓ߯9Ix=|?٧DQiiQ>HH 0lJ@NO�1(<2%h;_,6w/wgoU zӭ$x.yGp`\)Щ<IFch\ )X�M/G ٌ2\ ءq^؏g/=pA4!SSoy)b L݁IUg,hzuU㻮<]߿<ݜ^^}>yѲ_<J8 sӋfxA1-D}͌;xd34Frz9t^2Wmю)f0ϵZ:/ק]SpF{秋O_n^jzPEa%SxRm. _MS2t�Otv e`?]_^6im\ T:}rt8.oRԘ柿8"Xߟ,nPGvt{߱#:^v(pm<0ujܞ?6^ONn;}9yi5(r g-Q)rӼ;7vPV:>nɰv7l) wrBm qyC~^y Ξ yLma9yϧwu{1 _^ݟl�PWm)j ]% 9j:|Ӑ ٫1xt!Sϗ'''M9  %4 Kx"k?ҥznxGi5#WgOGyC-;ƹ㋋'0,>tYko^I%L +�ęBxۀtqxy:)SI!}!VgGNO۬@Up7�;FZڏu|px�07Am doy{tŬ?o5mL3CwO? `B.iU3,سUAj4tvD[Ti|xfL!Gǧ/,l21WO͘N E$li 8()f\PKWW]dH8�8ś3({Nrsz+i\F c>?%rI) ^Gt9j4߯AϺn)!oV\Cfz/GGg ^ xX!"u" {gɻ`C@_,Q?|tU5E tA MYV˓OGwQ5!*?o /v{bpq~ xi€W!s>"ʮ)ã}�`4ǫAӸA 'NS"cah>eh4= ,^׽m2Z#yDyͧ]]> ]g4?M�m9-R&q{Ð tdN441$LYj0exo“>)N`9#daf՜jF߮f|! jC DNP ڨ<`]Qvl6Fz-i'-f7Z$IZ<[.wy(t}HJ&؇{Bcwz:AxI.͵ 4/8ULTKǥ-ԡ|ˑuzbڼoK@?Et;^}Ä|^/g} Ud:M,Cx`E}CiFNT.7jѷu,MDѱu@0q,iv0-0::_Q$ZPbhûWWRU-rJlt\#[&j40L=/:U (a^~'}Ӛ˱+ъ F[*&s4[MULO%Gd,}5DX%ΊAX Xa-?"~9mqfcb4x �rLG4j'3 aigX4 >ˠ#@cmh;=wAbk"+Di |*Ernx$qUUj8}#դ,~,;jx!?&8Ew,k8ӫ!^F)Bu'H'cAI&m QGPt<Fx4&Q(n||?In<B9qVt05`YwŲo=Nw<saut>�bhuEv4\nxD*Uw,0?m4EJeASS4gR-aɴh#!r";'"h}U8F6d^zY͊$Pl}Z }z.{0Gq1YlV}C0eyYM2C(x3 K8W uX`!IbǗ=[ s(Q3ly[:iZm0yJS-}ײv; ml?Te/<D7dc 2089�{nǘYLz6߾my@ Ir]d#PcMB͊RbG,| RM2"3iB�= |`4n4/j (,lھ-wX<W!x@ l7V py`qNa'V:Ŵy? jY"иnqb^NB+T.L6P/W];�#K$}̧ ǔl=46rTd_ojj r]N' KuHO�=2:x:ICqknɊiR9LYGdOxH0z nv SEY\+i*"-,? 퉻뽘7XYwtCC;&a"js&s8�z j#dz@ dw{ps̃.˷d-j)${gk-Y�H 1Xtg%ʿ_NaG)XF4�W) x] om9[lcG@`ݤ\`: <w-S <miN8a||`\& 3#Kg۔EU5xjn+[aY^(BP0i0|6_ QyZr6-#YKa@2:�ufS۶� As|VV8›%;?_@|[TJYIEQhكВa9W/=4-a buFWƮ fb; Lh?~g^mbbŖJtu/,vNAv}~. 0L]j%lm {Ȫz9-0}cY`vsdF<GE\W6%xT#t+ b]0}$<` K K`v^z Yˍb_h< ]b';^!:"LRbI-j5gԽj9`vh .FI?[{h~Y&=7.tX3_G}n=퇶MVϦUQ̷_g g^FU~q}E0q g;~)d -�ɋafr#<@xJm<NJ!GNbЯ-(k{~Z,!:J .�'յw%uulC9Xo xm<T:x6L~>�߶gtf2�/ D|p}2]qS$8<+ +v}Kʫ^OG`pIP; PGѢ&hYA۲G jF ;l.=Q_z>:~PՕCc|;:bqVp afFcSU;ˢZ2x:aC>F]FD$Zl nn/m4OXyt0RD3qbz>[i4HMs1zEhV8 ĨF諭cűƞǓYի `V쬚uu@Ky40WRHy))fU<Z\E|y$d^r6VҦP<J0jIy-2`0l@Yb@;_L+|%-߾)]>ƨF/k=&Nt#za%h6ָU /Ev nؾ:;ʹ_LĔY1-?D &skߪ/Srz[&Q>^LPdl,zD?7X,MP=0zZ.t ܺ_i=m �s  yׁt3ہ1Hm H`|K@cp lw1t;Ȋ0ul#q/_DZŦɷ+޷YyD~�ґsoSan-LiY?u|G$ ZRe{{{{{{{{{|tH}GW \Ex' iXƣjX?MQ>w r<F*weK*9q"?8('.G*04?s_-/jɦOǹ#^֋*0ZwZV}5y1esR>ͫb ;*$2$nnb8Q?K�9T/Ίr<NR-k/PXͱӨ<]=/- ۇHԃGvtC"I)~6G@=,FG5//ϯ$-5*E)Dx6)(+ƳQ;2Y±.A{=Fn$/^~.佸-`mŤigY8{RPKM<PIRba8b$E bO Z4,^"hlnמj]2TYэkgeFiQX'Ţ:N2U'QZE&d^oet &`kM/teN 40ei bBπX7(Xl^nw+pcKcU}F l8BW)2ElY:R+RDͽfVkR`3jԛn#RǦڒ A6۴+^+08Sx ^PYpn @zC #ƯA6/C:uUdb<HMQ]@z�_ (r#bK*"0pPdwvU0v}mw:Vx|}xPhrSPlC*vc[u qPE3wܭ]wcaMju/aMi؄N8A|מ/1f$UyYķpl]eѮXEyI9кN*:O@ <WBv42L'u!�Rz"a߾9rr{WkYZTDnzpn6JmBu|<E9ȓ(%Av\P6a1nsBnڠ "� Uy~@T; l4F~BŃA1(aYY2d=D^2 syvqtwW]!5% <.0=VVMwO<)^ Ar-|%LnXLc|Mq\Dz ] b S۵<&n95eMZ&I䙪̾.FИA=]\`/YC7Q6^Dhx-"Bn) 4HwM}{pt}qdE¦8QNd' أIL6nDiJ!)|L^ D YbqUFrX&覉3<8ڎkaa/UK>ηI*]V>>4WÎC<E]ĴmIN@ckMqi{‹. ,dUUƮ)ʆwni3fk<AXf.4a,It/Ov0Lu4ז8L⼚`1]Z\?@30a^EY+ 2M*~Ro8VEN&ɰmft<H㏯ t=CMFEU rX8Hca]ò*mʂCZ㵎ѹn 2pq*iWE Nj|CUKrvvp4Yd}ם{jbhXpy CׯhڮS~ JqjŶ" |;i2 ,~(QQ�Hk"IȢ绮؞#M< N=yYѢ&0q&jV"^'>PPmJ"#" a Ger"ÂLOw4wU)Lc^^^Dk;G�(Q!x=J�:=ed:(lA2榱% pTO0ڮXƍfXVTnb$]vٱu�Дhq5O-x( Q_c5'ɚaDZ#3%h&400L]{]e CBQ�t1 AzaR8D$ϫ^alIA@\|Ӏ}+7Dh0 f@NbXYFpYɰ\@G怑2qH<,`bb ҏ@k@3 XoۚHѺMbW! 8%(5p +Գd4g]؇ æG"Q} {hX?p7&4鸜`f-;$3le]y M�StE $O?4;Xõ`fZ{Dz"Ǣ"ypb<L=[1]\L^ 3vFҨ7  +@C%{:vʹr[8BD( 򮋈愃8T�iJ7Ir&{f�Gf]C8ls*vT�ߦ^n0OdjD:`BH Pi&Z؃d{:߫=P&b ZiH :q143# iaH4I :t1:fR׀cЀ�5,v)ǛkLCtVGZ5J4qQցS''HT>ƙYyR RNY �1;CemN7eU8c%}z`9(lWrMfсq4M;.q"D,$IY?-rMĊq@LMY˛Ul^ êȎ�TihA泾X@P |2"e@툜u$#9dyn@]- J"[&lL Q9畧t$) t<M-BCD3'~�9"SM蒌nQyP6ysX2 \g7 n4ŽA$[b8Ǧ˻NȒbas@UfTy;t^6\"hL莟 rZݦk=*G.fF|\PT�`Yiߖa1P2Fz $eUB8Ճ(EKa1/}4nQ Ƌʰ�N[b1sXbM#l>oj]IGfjH,-`7cȦH%R=@<HU\,[= ':V'KG.FQl\F@FhN"b;@%Р%VXɂ&:ݞl wбj5ai1S3jUAeYۀ8 =ILA;`cj4’EINMڥe瀒tMC Bۑ;/hGε A[ju V x(wg暓/Dj <4,#+K.j]FAp |XH4 +υXT0<Uzv$VWiR,aAtjWۓdZ<_ g/ViX|4Jx'7`o6Im϶C%<:]yQa{-Xݮle[]~jV%E}wG&ǽH8 o{}UwU@j_Dkfۛ=R5{1Q4@tfdeQ@e;Hu�dR):ϪADCtl. _z8�bY(#ek e�;UUښtNJ[mfJq^V��jOj\/q#qkjVI; cH/YXxXl]wx$d:AV@Eբ ClSzCԬ(qMpyƫ&ŤZ.ws5<ۢxQe�PztESg85уMvXߕdh€,MȲ_|*7-%ԵlYb~bS:4lRNfKexk*2M#ǣK@f1VX7 D6&^ψ@TUKW#b\E'WK0>ː.%8ŏiUeXzQyl�#d=Î"@KFG,lplј)\Jw 1Rh>O57lAb\t.�k|KݘכQQ~It�dܬyer"l-.K h]5ƚ1�jBq P1ũ2ofn 5Gh%v\D2iv\Ajnz:" B\I;*%r 1/\ ~VMpV EfWT=(8˲û"d&s;+]e:Sy,zjʐA9׹o&j5Kי[f,sAnqO$rH$͐`߲4<U I(I PqUZ�fIZ/2Tq@oy8žHaa Q|1NŬ-j` &ŚUCUh)3.; &3x}Eytݮ7IB}$2,=�;5Fp7ai2YI=eUrR-1d~(+Ӛnxw$m7w mO74jV,jҁ$}CON΍)QsժNaIVUyI�';[8=-(A9 :><ovGT`/Eu#w-v#j`]׻yǓx2@ 0 VU`2cy$K06<]`ܷg{G'F, yJ60wX8(04r}`)DIk@O[0/xL8ehy\�3 Y`�98{{>>''RtW#M|k N,2zx,Cj ׇejV2_ _t%*.@8F0s#�ERw駏'ίoOAJ`Dݻc�^ ר4؂҉dUj@-H'5tZfqR1^W@?? QħeEe="u4n/.fݼy$FmB<�,?P&PemJGX;ylUb /;5*y_B<Z̘<?n%f!|<9>yFFޥ ݻ% ͆]QYd;t9:rk߼;(6A^L02VJ-W" ̈ɍ�1=s &$1hZnϸܵop $ z~ JfbD&n3]\ ȳlhf@pFy??;x#8ܜӦy^}Ԥ%%#c^ %mPg<c8v! ZѤ zyjFY#*|'Qq|e1xr^U!2a�9w{'9ꨧN.;*`IsKZ hu{3xj E3$3F82 h�4Kuq<tuyaag"$ً! H[@U/"�C64%xgqaZ |ZNXkFW[^՟LK?(%5pԡ-\a41-$ @~-ʚ8A2aH.e-.۰ójH]Z5>^ͦY4)Rr,l2Q$�HhYߍ (-;@ cNj /2 a 89e\̮W;j@ b^09+4W:1h 9zaC (c߶w ӓ>'ZIq> @.y:oB9xGK=_X]'>! >D1D4lDѽ10Uׁ8֨sZVa8rSdkE:&(�VFk}\`sȁJ @85ò_D$N#�' Vf?z8ʋXm~l3S9 AL#f .\M!2;gk_ᓠ�݃5{- AI-R_q,ɤ.qG倳q4hdQWCLz #q_bL�7jNlMlWz' ѾjqnjMWz3U\IX:yMcЇUPp 3rs\�̼ 2+VzXfW�, n9xD)*'Ǐ5F5S&Ì3F9υ( h΄xI5ލIdzy  '3v}ւ^doBYm|Xoӑ 8]-� ӽtQ N<ƟEN̺9Х�@W Z8IJBZo__>�eWc89HWWa|i_/0O.kuA9M�e(*e Kᚳ~d�&F�lB|^_ӯ6oc3LƆ8? 6iȁ{<P"}$ ,$ʺh`�Z%v!f1~[lWk_A�H`=ryp^׫)87d{$"trԛlʢ̓�B8?XpÂ%N�$OYB\S@rHOVI8]VV|g]=Ëk�l[{u_~|k@tCp v.cQpZ('JT$@ҢDBD՝llֳ6^z:W[r(h/+ `:,p.MUl32",EŃྡྷ�vi)HM⤫c*"/7B>1W+ͪ&fZע֫gb'$Оjw�(c/u/KCL\rp%p z8].w7g8&d\kT;ME+4d'gy1 m>m`yi ΁yX ?׳XŦaQyv_ ϱPG@ ZJ_o S$͝@ԞdCo@MmvӕZ¨t 3kO�B7�ì,a" uxhj8s*׹pi,8մ|Z`0_3ȘV+ʆ*-_ћ"{^NBZO}8>7tZ*p9?;8<P<HYl 9`"'|w O{#b <WsEbe͝Up4 >׿%h@OӪz EKL8̑x4LSx q|*x w{qm,? y. H!4s(x˪pD`ޯ Тp{pM 'Hd49Zc_4z[z!BR͛F{^Ӄ-tbxLQI щOWW"NW 1^_t2[uAԸ]kԿ> V3#:8Ox{zX߸лY&h�|3hM$ 9rv4IYs<^?^]_JE6Yb\̓"rDZI׿:H^(�?d3$kdF}Ȏ63cU/;izɵEps?T0'$gHQ`n;I :~x<^8c7V<p�1ltLZkYfY.|8\Kpoa,ڮkܟ77g8k$EW ǬL w`ظM:D>j7Ǡ3h >ϚyLt\i_(wtww}aQ4 f$۶txpz2@ ܆!96ؘNr<PvRug[!qKq3pjd>܃ ;1h߿?8H>z'wwQ(q^bGߕto̐}cw$̋!Fyt9MiO&X ^jឰۃ!A.?ޓ̸u_ptHӜ"aAQM"0+j6 bFuDwntUnȢb(KB2Jy%ҩѹ|$9~/'c^:_ VI\s8<]'&.1UpF̃$cIu-hf2ˈZ<¬sQJ٣Y;xN<OܜvzO{$ml@sZXn*V+ʮj`G zD2,Mvڼa*%b(QUL,%^NAͧ)"s/'P Xi6\U,qϳ0H2O%)'>J�; X{NA�M(Ҡ'jQ-qm[g:O7{{Άf@Orŋh43b>Dkyx>iI5`@W1d= VY$#% h aBrʲ.dMjG� y,?L'ti9R2@< �&$Js�ĨiO@./?}<7<ӭ O>}<{|z"UK+IDv`efeOڂ^)7n;b;_?\|e�rxlg!X/У*푒HWN~yXf/VQeyg&09>i|>~wGA>@Bo$5%U,Y#K0(`l1D $ vT,XJ=_G'.}鶃 /:d58']O9t3-?8ͳ@QC4}W).sLbݧayϮc6nHVm\}:2=k|FoPT$iFXehʊxlqM޹\oXc;!p#" م8+}tv:f') 1hްk'qc=[�뎪I8DžHEb(4#xjg{0ր) azG Et�|r)$Յ|)iF\,zxs~էxu@ LI`Kn.8~50q&@Uq{sxgUa$U0,Y/>͈f>ޠ-NwXL0Ow!0AMpa�=tEрdy%XpZߘ_E�@Q0g_ аX养w U5r�#Qhrh^zl$tL00s3BߞퟶyIR!Js%zuzQG T1!V2"az'Dϱj9A,Aub,75YG=CtzV={ "F ۫㽽à c׷/t dlld׺tdAiKw|C/Qu<]˄A' L:I֢22oJ1 Xd5Swxt_O#N,pX+htbi_ϻ X5>ZtI{BB%ȳ;R"|XݧO.on;�yQwhEY?:6O/O~pGċ!Ⱥ$ n` f�'gAP~߽SJ/ C! ai]%ȑ#eY^v=Q$.?^>0'NƣXlODR �4~"xro]5`~Mt3dwPa O6%,'kaE7%a_:$C3ƺ#IqŬ u3X#^OuD둄(k}M?^0S$ZQM٥Sd|O4'x>Њ5/5D>%b)ad�0qc5Lo݈a#E~I]VkPeYy28*La_Yt(;$ūכTe°T~x3RNF:Mvv8#�a՟WzKM9 '^|9s"Es& EHuZXM "aIntr ,p|^-154ʇkBl] ?8Ok,/( |lhu 3P;742b 9x/>IAEGݏEQ/VS[azjvX6,O$ժ O*!H#1od& Ԙp2)lTIa,Eǭ Ϋ3O (n"-fY``ei:]1Ep㼑7q=b ,%1 L=3Н5ڃ"ҽV.c_^W0p[]yUUji*vhRd{=TU30;;V؆#XUNJZ4_4AXsO)AK_`?Ɔda#@>7C~%EX.6U+.Tlf2!>Y뉭[O6/P λb^BDB7,MJSa]&h5/Ss 4t'ji`գΐ"T~8*9VM o1_^o(RFemk lo0/$1db((V?o& vKT3 !eylNy<Ⱥ[,RUuUaĎT;]*4m]FVU8;ϋ/ʇ6l jn!ɫ|f v`oQIN276Zם7TQw(cSd+ .BKQdOQX5[?o_`ّh`' #ų*u:G+eNzfi �S@؎*l]M3,dzEѢ5TtL}8D+NvF3w-+ֳȶ:�+<t, Ci<%C $ "f-7//4}Sه.I1Ql0P0T3M]w=ꝟ`Zyw-FGo[*Gs|ĩWPz>>dUkDҢ0 3+=45z8eU&.y'\n7 i]Ț،BOKLe lf<lE/fzϯ75nv9QCR�n[$SEݍ=*S=8 LMo$ � yyӣif|.qu,CӔƂe/Ue?'@҂*51՛fϷT7}a:/|y?<aʌfEfm"s߲LsKV3.4@/ 䚄yL"aIVLdմ^"StLzp(x Aav.ח/|u \[}p*hD MdirWAr5BwGÎRhFURp_>~t%P*}^z~Ay~Z*lgY>YLlӺDm@ 430 8,Η dvLq"G.3IVXOC۟L=3ͣ~(Ŏlt4,oyqh<E/W+-`p 7p df^Ggsj% ,](BC a\E]uls!ˆd0U_?ohXt[hfT8u{{d0S2 VڏL"eU*```!V+p˱ٮ֫v)`;1!A쪌l7ULwsSW2�Jo_b,hᕋw%>!^ ]Ҝl,KGNXL4gX!i 'N}^vY8a@\Fjl$VwwDpl?vξ Ӄ% N52qTy,+XϯhK_[^wҷ%p .Tѫ#]cDl^xiq9D,r@M |0t)ciG<)F$p,Yz7,۵p@ϯ>:.I/Vk=ш19Bu=1߼ tw]-FaFElɜϘn_u(^m0 +PTּN]뉶v#~tݻxK &' S}oWpBK]kFN}]Fj)0oAZn*v-<$d)z߾|bb;p<d:3$+%z*C8%EGnGJ ^McP'WaO<=v}i:4<./"@ O$w_|J>qw+ezlƾgXНrV`Ig}t~[GB`8")03|v Z~f5feǡk$Oʞ6azo.>~^'"RO0o`tY*վnX >c@SD<q �OX5!X:ߞ.�`8xjcCzVEEf?~6O>*4hT=(`ź+:aӪ$Ĵ}MP g8H7M'@^JS?ǻ4Ew3XtGkfسЅ R~2(bm>K ݭ"u}_4#�K +?CdhjbZV֔pU6^\VXKǶQoN`0X٤H82؁M MSz1X(Qy< \*�$Z6ᄹH�ň2[ ,xsq^I1zϘ-u2]@*S~SgS~O)?S~O)?S~O)?S~O)?τ4UVa"?[X $Ic@( l:i`*Tk]0ɧPv/U9iIgmWFV\U|1f˺#-3d$z8bZM2Gևe@n^&IN*YŞkyGJDi{Q)2ve[ hf0Y̋c/RвP41v J?>8Mj].'y$afQekiqߢA֠oO5#-ɋl\o8 =Lz'ٮbUn`ƃ.<=>><>y4N&8iV&@~Ru]vYqojĠC5wanqM֫H޺cXj8va^&Z@zenwzhmwF[i%iK4)M;̪z^j\gQ*;춞no�d8ͧf=uͦ'9U\(8$dAqټ,w(}G^ո}G#yD ڍfoDH^/3g&3vW3lښ(q5+@6v2mF?$q'8+L"[T&q`k=0 VydXj߷Utf;#Gh<FJjIQ0?K%y`jЌьȞ`VF 13U]"!inB|o8\!qn;p8a' N ;j8cm(-:vL >7&Ѷ빦 NQ 2.vhwo 4EP#Op8*�e λa=&k+�~WMS溏NnPQO�aE:M~`'Փr7~|[mFqVD4MVOcISC3 q=ȩ+n�Sp?*żbMwh@N\֬2u1Xzi5?\?t~0)JTqF;IQyZ몪5�,jM8lbh/b.bW%!anܜ_^==<bIyhaihJ$޾ɿj#v."[c47H?^_߶ZfacX:{2x2B \fReQ}ovg=Mc�sDv' ۻ8>^6cqt-Ñ9&$i/{F@C4aHe^dy^dZf!ZMl%`+ Mno.>]IZhjy⼰Aw,M^6k9u~Hg^ 28e7un34˰<Kӂꊢ17ŐcXfT}@W" \"ό VP8WaI![ѤZEREԘ HA 8{^ MVeE:CÏ'4oZ*n2v-0iLъu|ϐ>5! [2$D];CŢgl+k8^XjqVIR4_$n<ߡc&cpD<9&6[#ƒ oDU阆M j>bWÎ5 G8[R,X*s7 n*3�+})`>xX3Yʒ0n-?)ۄ%/~:ҚGIm2� dz `& 3MY? fC D>N1EY*'�ouH(qUQu3d lCz}N�P |"8T5SF4bfS)"kn9[΀МpHӔaijn2p!.1,0ګ, 㱊a h3& Is=l�V6VZb9ʼn[RD7Q &⼩),Ol0ԴM@<Z!v"!ËN\&JVPӒvuԧ;-cS S^Vͫ( gR7udקn>�siFk�WPnijժc‰KPoZ2svvXT3"G` xj<18Iņ�DuRP |>rYxa(Q vq7-|ЙVuY4Xdv�ueݬI!x^d?#9ih,^7 pCޤ.ư٣%3�:84utotCAK0"N//X@%*eb[ILgopٰ4=`=ZROBge@{cDH {h|<899<x|ܔE+Z%c#/K_',v5W| iXk[i<AYO#K yˏCuG$#c}gvΩJCNaj G@v}[Wc%mc80W8 !XfYVT5EylNѣ$]b'$4l% 6ufRyFRn8B쎙sA�EV0< 6~$40}Lqغ4z~1pJ Cpt�3(�[FuJMn/OѝdZSg pDCXNO'nr^}틦M/tM ~ kcx�<IB�i뉧2f�@4 !>iǜ+xNUcO<zHXC#N!0ξ2|%.+8G^t'MBAiz8T|b,p<&xU"m !v#t0u&$8 *-SL<A-/J<V-摩$L �lw-5;jaitwpzXM,t,a vdt p׮  Iu]หq$I�EVjU!Ȟs/͙؁MΌ11Up/_�G$ (?)k@ h5p5M'_,)Jv+@V{C٬z8~33tTQoEm�key^Vyl+"L�R¼͊s?ryK3d\* ]"l\מԆi2; 0g+ǝX�QA7lpNA^UYNtm4(@Χ v{{`bDj2WWQg!a{rZnңB4�MQ-NƱzA#Q$Eg:}RP,+Pma$@ˀ-R$@ADA6"Ϧ+ ͐&)Զ 5𛗸?=G$n铀M((E9ݲ8)j^& N9Tp h~&+=ƻw^U T$L y"Xӭ[M:7 v %j2p,f vgbhgn ,֛ͲhmKjz&! vy6T1 ^gЅQ!921̅A Q(r0E^qbHɰQ`H~' n/g [C~YB;O P4gږ(暂`;w5T!mH:�u;&18$;:&SQUezaUGʍƀFnz5M|" DgX-Y3M<؀@Ȓ7W P^ mNEl&CC 0>esB ew:1T~#1r1-rHЌ@ MCѶeIPjK}GҢwF- � ^<j]e$tZr[ υm|gZv:jQ)fR!41!hD\/肛�cXLi'Ao�_\@Sۑ'2*\ilwwma,R�0KjDya5! ˌ&ou%1vx@j=H FmoYFz4Ê5QfpR FzYƐ$#Zn7):na=Cy24H+zF}Xx2Q]mu2fTpIE`r305[uzfv b,Tzx,(fIm}1x"�"� 1U-"wERPęސ c6 %-<Th+kBV?(%cUEa8wU a5 Ʋ$E$ϰAWQTT;RVQQ!6</in`W\@AMTF1@Qy5"cHҔe3Yl6g}DL;y/ie9ejX4u]ÂYo-X&\D="%x.K@u ?.gj1 *l5-j<<>mkkC{P -/- E9@Z܂рƖŢPBuv�tX`ݚ(,ñ�ux1!mEUϗr*d><ᡉ a|Q!<Pgs%6+˦-"$JcR5gT&$)Z`�FxN`Z۠rN clM92$<( !$nzXAD Lc[Jwox) GAeEJ݈gz·i Ǽy\#8#3͹M�0wl@>WauC Ks R!D[a5"(IG9 CRT2*%׬80я9jWż rŋmwY 2hUm6qLyljíG2Oڌ O.no/"uKkw^ob�.A9 f]K|PyA,] 1`U>W[-&a.l7QXux@M DʹκY&EV c $Mg PN$^zr&,f@: J 9IL̆2*2dXQxwG{G^k^w̥E� Jsne2N F?;U�j^/.7|^1{oG%^ԑccU$cQ9Yf KeA;8tOίڝVwwyW#eC1VZbqY*"T =63`t/Oef!4ăo;azȲ,XPd"pɰwraU#Gwyu|r>‡GJ/|s�Ҝ .!X/4Z@uHL9"� :X.l -Dhy===;`<2U^P,w뫏>\Sԝ:@>xv+q'8@j| II(\)QaDSM3Ґs[ 64BP?88kN'*[ǽm姩xt*Qzag|@0)Vzk9cE3�"Xޱk�De_ @jj48활b MyБ 0읍X<u}sv ^=5G#1`)x3YE`C} =%!foyi[G` !|WFĸ Xu I~yc @a_ͪ)$ʊb[MgY!1?#TC|Ȫ8jLxA؇Ǵ>ֻ2z .˴ZS?>&R!a )ʒ8`\  5,̏ܛ|sN0�p 0Ìtpt2D3) gy9)mEҬed:8{lsb.Znuc* SS $B,԰^w#爷&wUp�\F^*̸>:U0MXRL/^n:>JjVS Gel| )0jg=O ֔0g2KeZI1v_8AtZ/:խ@4-9ہT0<nyYMպ \{d@%ǭ  x~2-reɂ6t:+W윜US%0X5`7IZdtҡeՐlgHbLяS6v0q�0uܼ %TŨ{(ǻs4 W\މպ!"< w㍭Y]Yoku < p$-$@{y|ǷDw"TÀeA$1 *Joc~ҿi+Z$OKݧ3<K^#Z@Suַ;Cn}G#1 L8TfE��&V)0[LRG@ 0I4Nb$Z:;Y\UMMED�V?c%קځ(RZU::,�O= >FYࡢ:y'Y/4B@7$#@٢Efj`éFϐ}x16艃tMd# EMr+Gӧ(Kt8MqޑY&؅Wo*|&$[{)pYer- oQg6ׯ(o$G]ML]pHP*2;� S` Yd@s�,/: AovY-:6x RHQ\ĎRlFܤj -{__n)Gw\Tuyw<#-4 'a贬YH_CR�Z0VOYQZ)^s/5_Y$gp_lFQFȵ7᷆ ӻU%)p(rSi Ie4`= ޕ"%J `E@p(6�6 ] YTvg4/ϸ-X2R9aPɁ: P<t A,еqq(ea96Yen+:5WeXȱBleiN}ڑ&Us]?J"5`E;P�vqт8HڀJܔEaxH,�| W˅ GZ#9-pgD mNWxc%Gu<ZP+�Nb^GO2 Ԟ$4,Qvx.4 9$&W9r4hG4Wl/BX6/57<7 `oѳHxA+,fS\ j>}{8v� }9 7";&r["8$iH`퇮4�d`@VSW : xwYgW"Sր9&DOiuL@un:|0]CF^2 Yn>Pکib3Cq�^4ꟽۻbt)Z1.R/~?ߛFA@=~غ q#Վ DUbAߧvx]e* MDZvTo0v(6m]^\~|+k"'i 1}x"KK�ne{{xu9qF;tTW\RS}=d3i߫F*a-&j0CخVwVۣdM&]wi�t\,0dσpsfܜ_�4Կt;C{+f D D]b9<hx X聵J㻑74Ӻ]GjQe: %0<o/λ&. �wR\uryk',wˎYH{!R`"hY5nVlڔYOr\&!qNHIl~0JE^_.j9:e`5{so_6N_1 ,Aź)t6ILHHݟ^^wayǜsRHiY˳];rlfXd3�)aɓv͛@ﵙ <* Ƥ`4ށd(}w3]x:בYݱuquwy|~t:3UW%T8bl�d-H "dM,p_TMi31~ XCPWeeSW 7tٓ$|`nVJdN*?|<tuyI€; s<e30tXZWܴG1CNӝji)2@F4qAێࢅZ;&Y_^9܁G & _gB�9l_9Z?ldBC0WZ4�{HG'LnLs0&w$3:iWt xay벤VճMW0YBeZ4 )J*eGs2({?e 9?돧#Cj8#hH:7Ms\t˝nd=jfY&,o_>8e46% v醝Ϧ)ݧ;[H{ږ�&“yARjQ;+XuDW8aZXJpw,qԾ8;=2=CR~IY`G}"9C'Hg-qXf( H?h4p$X- 8U 2- ٺ8kv5}oUۣ~t c�FM $KWbyd[A m^'&/ǒdyc[v,+{sz9~{{û݇=#pt|M$8@wKWZ :5kkXR0s{0J8[uwRʂM{o?Ln?}>|>??xj`t�K5 6#^Ux&X r7´}+օUb6lH2;g???�6$>9N?^A@Kly2}}ҦD= "iW:s4E:{H}^ MS!w [/<:iwnONί.Ir jUlm'c�j^5 �[8gXBca'ų)X-ǣvm#j[ǟ͏LF'?y ї=WpHXy>?kF h ۇ007ވ }-݂Qd5gi1zgmFԢ*`GzwMN1fx$hyYV2 N޿uP$iat8t2ҹ-7WExi:RwG,܂N�Fioj Cd>,7#ᅴG@m ,01ZWzrie#S ehj{>]4`/$ 0+oUa?]v T `ۉPuyl$T>d#j?|SN3�o{{{7ń#̫b�~9<1tOBR%4ta۱D‘nDYs RwKcKSo}B\1nW"T�dWylr, ջq:M~“*lOG_PV"XF nxwݻχ7f I,E,+N,OL^\xz:*'XP*�Wɓ%U 0T<:noe+]Ù$=#‡O`}.Q6,˫z<%gc޾pHJZ.j l%^s60�S>a eä𓻣OONNOonn{CjM�y27>~pzrxX-0wKӦrkwm7'8ExFb71M`]kJ|\,*,fw|[u`qm7Rd,&=.=INw! È`p?jП�M7´Z,Mjaf"Y98<}~~p:XHTW5jTEHi;ei|Vx ,rK.Sb@bGdcZNGD I{5(]o֛|APaG]3ligVO]/k�l׆7+nQc<5$T7+ 1 %8U#Yn41ezחN3mTWC6!}G}L(ɏ]{ ~۵K^ׅo2{<E=YY2cDͮq0/jcc/(&;a^xZw Mwfۯ-MpQ(`%�${y5YIBTjlWo-B 7fI}W;9Q>7|-bbaCFtH4qB+FX;>U`3[Tj5r17u3_,Vbn3֡\WdnAد'\XeaF `*NњCwah {^QV۹+ Y {N-b54fg媌]6UQm_ǘj̈R l20hfY%nzXXwUj*G<V~,HקUA֢Y4IlSSyż(i@jf3H)S(x|].KbZVt9 Eu/OaXp5~!H'][Ju׉lhvNԀi`,\Xf[NrĂ5V+"*ٞe=I xbnHQ~"jn9 dTU(*׏,+ d<llyz|ڤnYfmf0 X@y.iG@Nܜ]5��)V1l ,vFS ЎvBuIZ5eHk.,tP%Cx:pQvvDQNwe5DM` d`a�/}U /pQ|kAmw^^rAGb3�`0aYX e,O5Е%~<`E<*9K^MDV-_E\ `8]7N=M]QIpsT,Ǘm#35 SF 華_<"M$ ݌X~x|¸^~?cv5IHzG'#p]yڗ_kx_xpNۗ{!IӃhx}%v: Wddkc~}_֋fMTv#rUW <Yf:ql׆>-kIqN\t'a%/�۝T@4<>FVPׯB%ض"A9jo{3|?A)0 Zq˺",p]b:F lE 'c׀kЇo<;QI]vz֑rx+O x-PtxՙnY0nRU5溑X'6؋@4֘EJ k4qKcn>C]pz</l](O~@\ΘiNug zTQ!?lJ[b%0d6y༺êDYhVoD F t/ 1L]?7z <3IU- iI} Y;.!fX̦#yͯKO.qf;8,|+X85^_1b(ra6N1M} @LKe3*]}u ZS?f)VECꖛ g|\gV8_$,*Gd <'|[x7h Pt+4J'\k_r]Lhɀǻ2NWWqg.4H ;zB~BkdYi@Y3/BI7_Ǘ)f%!*a5EaP�l: TNm`=/*:,C \838BVj$M0is ςg~VXeWT"vYf7O̅5M~N[s P`Y W&0[ ?os莃u(ʛGC*Ib$&@ ' sa"0ܓtۨXԼDWF62?i{ k,%^9:cۆS=~o@`dﶰ '/rPP;x hޗ%0@3l+^?�$@z;Kg Lq<'B6orSsWo(M3�ؽW<DH=CHlۤUO]S5xfBӬA&׸h뇹gcɉ̵poڶ)3EznαhT[`4^ 80zL1 ' ol~[r_JM`?d"7[Y`m1=7^9L:0IG4?n -i |i;O\L/_ioi[AEZRg^VHu}cVŝn!DufQx$n>CjVgoeL&?x\dvr͐$YfmnĀ+<=n!g(702I!٬M $ I}�OM`"7xZhN:Xˆ!P(ILOCTQTӪ)ɦkzG꯫Pѧ7bTr0evDkf8<nztq}KwPRv$JuiYu `3We#jVzwu U~exEe$;5n"< /_Q"EY t�6(ax QOPgfyxFLU҄ǎaD!`gl|}t^p<8bQ9_%?`Mvgk[eCkBpC1*iA4]\x`LLdMׇ`Y;ӿsu"O<pThR[5D2$ZH]0ؑS ! [*p()oCHIҙ?&ۮz[ xed4L 0Y"`hn6_>oHB2l?Q {5~_5~_5~_5~_5~_5~_5~_5~_I? 0t)` IsN4Yūd{:MʙLQ#BXҡ'EQ[3/oeۀ˓u5#}w1ѧi<IЪͼiࡼiN<EYX,zUEfLXMCS?<$BEUfMSQ>V EbI3a7c=.gKw^UyϽφFyUQ("F&ۺ1<ѣ}jXfV/7Ų.s_9?o`b,-ՊUh,K$9ڽ==yfsi!I;)$_" *wBӖB{Uu׺k (KV5.klF 2R@Ϙb,IOC߳zivNw0#kN<тpQEXz�l |ig0aF!HMÏʆ fKijԒ% 2Oge7H(lv[WWhs4aih=H,xRFlne۫4PbWf5/J#x軛 c o:M54OU8ϒ1ĿnFܦ0Bh _Y#� ^nDNdYw-Kd^Ex |t59׏n: 4!-3ח"'$'rd'] "(^PeX7C7J"U i["o/XA^bk]9"Y$#эva&5Y!,u=n2&oD7L3ĨN ś~8hph8n K) (Q$'X7<P~zG BIy>͎cOv8iXxD΄g#5Д~ d+y뷛?F5bP�w=IY-[jk [Ąߥ)gtDŦ(3@�HH3. uӰ,0aY2Wc N{wٻo.hjհLU5LgslWEr˵z%SCNU5ë*5U]adBN7םAOGcJYj |Ya l !?-Qi*b�{4do/f%Ӵ3iM E:͖%RRmjԳy=M lZb0^-r[5e(E䉋ۛXpluБ\IQVMHqU]3X%07ueA 4o*dh u4ఝ(۽>=;vzq-/UFlBGC=ńg4vpϏMV^�t<$W!�b:>>:4Z6MPt"Мd �i#CÆn4uwGƍHI&3w!%Ț:I[5dYU8pW"  ;钪[4ul#Nى[!rw+8=C!$v}OЃ{X' FNE\!$3�XkkLa;"aI*c IR49u!eήAzdjijFuZS{j29Nj'櫻 [BpUeAqj = 61͒4Ctm˲7y]r�qC%p<`jff%:xGQ Z!*JKܾ0%(JF޲! WmV3-yDP72@ɆeH# 4zoD/Mb[҂beih&4Ң% 9Xpt븣j(2J_\uǃNwDr[FC%b+j6SEYGk6ۍɮslnGbwv2!+ 4EO(o C$oG&`y&,1G] xY]&oHOY*L&p45fj9oPLXcAPiPpĴ-EwtE1H]_Bpm(Vyx&Ƃj"ˊ7 b1K„"ÄP"/МDuzCֲ,TR2~2wpr" I\YtcD0(P'&D.x 1H/v$NH!�ֱC i+(3˻;(`=mɴtHDد:fITgʃLtA>_Gk+E%wj29&(W&iQ4lHh& 01dќҏ>nכ2o" Fa9gUy22 Q `gN5Q+zpvvuqraL1vܡM#�…U&+#aD/޻?y3' )o{}Vf)Cŝ]}]W?.DEƍ8f8?<rBA>;NX` K/ѫ8yMωBrs 5͛GG''g$'Jd]ݹ9q% vzKQS虄s$OA BVW&(s[WF�J!ߩ"7^tsHܣ5e8'8*<$Pe  hр4B ]Վ?+Cӣ$*(ut1{n*h̑@082O _}&bfYRPH CDԐͨY/Ñy=F�Ёb| 7Ǔqj!8Fwww#ŒC8*tPxj<NG/&|&^4S`H ʒ�B2jsBaK~4ce#�Um!-szCGcry�2&iO�$gP £TD)DA4Iq" (ԜbOy ,K Q˓$#&-B7A4!P*w$@~Ge!eog`^$�$MCqa_LD3ueG/-O;C @ ҇.fj7`3=N9UGMykaHCYt/-8!Pγ)1" :&x놏Ss*z"kVP�^8YT@a2C";Xl݋3t!Ref :ʂχ؈VxT lI}vv9g[um R ģ+bf(,[$8&cQXLTw4,d kM9 ">|?!3"KA(� սA7m?մʚ{v#N^5+%Fa$TLnp8'$ ˱ٔ!X6d#/H =T UR6yX ȳ  )&qׂle駉I(�l:q^=T"߿r`bpקspj\oڦnmь0/�?R!P>ˊY@G Z#BY:M3H@ۓAq|PMC "Sˎ+(]guo{$ ulwHY~5a׉c" S2ϺwS^oZ@I0α%pȄ}8t'|632Gp2']Bk ;)ŊfmQwU[5 z2A� *^amY2ǐ_�p,4I1XuSaŢ3gggAFrJTÉ61a|Q*\>ef@Vnj42,n,EB#<]{i 2k 54?�5luS= bEr@F~aGڍfp�8N-4yo£, &[Ȇ,p@ ғQ Pmh�.³6¢(Pi\nֻui°JnX0\(FAP!ѽ)+H|m`R],q1%Q KІP4h*F/Be H裨'mNaXyZ  D@Vn M=Sx� y+;\^^^]wm*򽫻 Ȋf n]%Hn$nY m P4.۪>+{Գ*p0ĠGHts˩9A4=iA܀ӋrW-*vm@]ݶIӲi�o#R ~>80V-:� Rzn2 Q!\Djڝ uhD y  -@!5S11HyE@nvV>pbT=MxvTsuYL x ` �a<(P[ڵrd2]l;:cٚD:=ƒEH,3N\.o*4;#Yc62@M\H߆ <Ĵ&{X6(H,.tȷn'$. |iSFgF GU<ߣx^:qpqq8FDTt'\T�!K9}a ^jbR\=eK&F]�f5j6ZC]o\a[:zN�gQa(;2#14 VBJQ0FQyY_uz,($CYG^dWU;ȚZ%�Hǧ{t0z"AsE<25a: Xَ}wAAs]ר L6<πҿ谒D1:mf 'f5U4; (15CVtk7( U!X&SJV`i,Kx7O2QaPPE}}Ci<*2= E2T(d0{ ۟S}B雘pHugiX3"Fذ 8^�le^ B KP)^Dɪi.J7 5UwxvH){Hc@`\ߣɻ]@RB=3" i,rP-g&Tx,f -Lyn훗tNiݜ|6&p=2A~  Pm O\/B߱i40]U%-�Ր n+I@Π}<<y7Wί>}MO/z &x6A¼aUj>(u_1U@ Ω0v*,RM2MA1!%>~|<4ytã;�$� J;s, /%g&HM&ckOf-/YToJ)o!!)CeHV^|f,WqCٳSaO�nEPQͼt/]k4FŌM:X�wah 吜w2cܓYg,q>ўٲ0=9F 8qGo|2�QT½?lkX}aAyX@k9 熇lbpm !XyoliU.g%pggo~[�G�Ώh(Na?|<3BG- (Fm W۽ׯ__(Դ S.4$mcօIHh4hI`Yc3~u":,U{p'00}x|O3(\vA QOO}f~ќl[UB-@f.\EegQ-,y39xuϋLg帎'>_A wz) 7Ӷۇocv]ȟbıP e�+@3,C]dE]˪.S7vQV4DQ>B˦Z�!fv9huOp# j}I52jVem箋%Z|�>9@e[~cJ 0m]^T Ìxxq+ͪ.c);^o~Aǥ!neijHMw!>9^$<ԖgM(D(p0 |Y%&սF:Tr%ƓqliT A7aiWka�lLԠ/ĕGl\$Q?"c3Gaкj7H ! :,mU �xMRj/1gd|A`6fb0Qg'hV#Q q|*9Sl+|(RV?&KZBARv>!y >n ;*d]$$MNNj@8�NiZpм4MW>NU1 T?]t:i ae|˫:G),7LJ-~E8Ra34t0 TYFzsCl~Mb#)R=-`$v"/ ^W\_<gG`F<>} _oQ v]1:T5I8a/K]?-B5XA拓$N"58tU4tQTjmV{NW[nkZRubzNc<al6لQo{ p$$ґ$#a;&+({$"ݶ, ZՁi<|T~ڲmqeppѣ!tUeUh|Q&iE #<t,OtDNx\nX�"B O= h:g-Nen� u >uf,R,k X#LE%ecUB?|Bω#˄*Hfip `V [v237W!a|%qc? hB C1 f JX`5$0)JfWw|zx.ٮV Y7AHl]/fm<[}ж/J-r/}z؋a|d\Vk>Z\ynx`"K~<$t]:XSf.zJ$h/ -OI(4hW~yc1|nrCw,h8hz$̉)iGJ@F`4dмnY =Xq-/Kg9$TMC/m{/_5_xrj7�M\p-` N u�E >Np|csw$S@'j>t6yx ʾ|zB\?<ޯ2qQu]=C{,| 2C!pl(߁=}wD@H1x6Wd8\xڬ�%`GΈdNQ6ah`lxX",`$o@ovۅ2h%j,]kM|~#gQLB0h@`4 3 K8ߟk3�SX$Mp3^ rrєQf-`]op^zs%^dy oF||}x8NPKce p7f%(=a5o!4ʷX6[!'Z2w;VA�H{vg^(! -L?ݣ]w>hݴ-ؠ" ų1�7gn= Ot݌@o"l[1?:gsQ笇2O8|~իWoN|#YFb;8;??R*xXzԫ*2F, U~>= Oϡd _@.XbG[62ĚwF˃wSLwOOoToӚ}Dz od^^AU bC8y~"-=8}i�1vH$Xs.!، n9Dt$2i< k<פQAьj>#)e04D,N v$V ?#Jb'نX$_jzʋ*<8oQfQu H)O-MXpRp(�᲼E,^6uǚ.C)qiJqYc@:#@ɐ )\ĵ0Crv&�EVo·$fh8; nyE[be( U`1.%aU9m P(OvnIivY)]"ض H9"M;?f3ɌEx:հf'Y2O%lES4SZf.\_]7cS�pw `]d+a3_@C %tue@ZDjQ{yhuS:K&$'i3hH8\$"6E{-V l~~"Oi{ju Tb0!>! ?^2ޢX*247yITئ;�,Y"l+YoM2x42,ֵ'FŲWP ]bgmg�La`-R=LI(2�<gkx:&*~i!}xkc%v6. x}OU�7n-C1e+LCz?NiT6BV.Lu&qJ('ǰC _)^$(QYx?s"0QMbq@D5>zNj]g0&yzKF94 /?t|.Ae0�q F̑z6]"xef6D�=<MI,;ɳ e$%܅qMX5)s9iEjr WOMT=4 #s7]5Ï>|pxpxxxz{%)/e" @ FOS(x&u2;x֭jo^Dz@{50´N_|}I:'?}>===:8:<<993*SzE o\FI~hjgM2O>@Hkt`|GONO/:ۛ뫓ΔWA $)(rx #]xl8+J9>1`Q$m &dkRDx)|Wwmȸ{}!$ðC8G FX +k?`4FgQhJiY-<AHSN_oxf0 q4 23O]J�[B0eQ?`^4NV|%@ #Bfu } zû\D/_]u{쿟"kF-!Q}:8Ϗ?95sGdz+ ۮJ&_~"y$ʦO.�m*(wo>\ <$^Cr #VW8 U\_^p1%wY!8x:+ax۫;C`YG^~iV IO޽O2T= !،N,O_z{9%1Q(b™gF޽|1+`f6}�T8p�5UO_;-: ط-u o9ᛗoQ" H^~'o?~x>cq)Veq&eY`�`toO4ͪc�r,<AclL�ɻo^AvRےT<R]}z㣋96\ BbYU<] ޮ0ׯݒ4QÞ}UxKPe|( _~wC ;)ūP9` OG޾ S2=ܔkHYvvӋ(At`AH|>M'߽}}0b%O  lhǣkV s</aH O XrpO7sF )x؛/a,x"4m <%Ab.o>}9 &TQv4\^]\\^| Fɜʼn|,} SP`㷯^}<{0f/"7Tn*%cDa~q~u~q@8:`AHtMr C3\R Irtۏo/i.eE=в(R�:^dcaBA_^S@* �sAɠ;! 6Zq0D#-#n?& X-W^f0jn$ERTgg?i>aF}ZV`5RQr'rGKAo:Pg8p)偾A ьg|HDӓkFUMk$'M-pjGrı<U ʹ Dd'O 6fC,KHdZ~ É3h|/ˈEH{ޢޘUiQ w* `- js xQo^lyޚ+exHӪ]aRamVn>!{N ;Yv;l7=KEj2-M_j, q$Jg8pٴKz?c v$;Ըi+[8Q7x(^-$u.f]ef۶N۱}ܥUIqVl YiUc{zI-X IVgiܢQ7:�xZa67O4Z0r1+T^[WXUl@%ivs],!YQo q[)<jUfBm~!iS0_!ͭ/]/_ MVڮ*`82"� ־&+z߹Z%غjnߚ ʾ9U4lߎmxyZ-|]4mF%Dl`@hqڮv*|>flY_8L|1^ѱD$~#ije_B6jsZjFKx@jXj.E H z{oKG/i ~g7^C_tq٘O8_gA|?Տݶ t1pJ-uXb\.UhhxMmA?-J3EjLZ-7mթ1awk3 {3UU@lp-t¢Y5|| y.wK9꾎m5 +Z&}dw`KD kB/5O +!:nWYkijI13xAw=KwU/ۭS5|"F\POi8"OrþaXbӡ$ƗZ2)"<:y{>zO \I8I8jrR=za1)5&yT<ژ\~<P"?=dd ͟<]lNelƮ!͆S F^͗/O;W0}w.,?Iۃbڦ:vv͟4?Ee=iaE~] Q+ѽl|+k3q)`[ї!tNW=Hs P+I]W W* /�v 캢e.U[eqy"tJ2/hdHy#!єOQ3kzSj [^ `'2 A00gVx?rަtL@O7b Id%g?|.z,#мnP)U<П �0uYe 7YAٔKO^Ptg&M)k96lC>By.�kǡ)ɳNo4LXZ&ޅYZ8$o~^1㌒3ɯ2] gJn]d_>&t<1X=gVӏK Į=*n ,syU};2A+^Eoo]`}nA3 KO7Ȋ`~( bq�t--"|vs|~*<_ c p eh2w5 Eiz7f4'߬8TT#%qfTmh +Ej*pJi{k_dHFeRԌo`x9 Kjn)\-v+Cld/YZ4 N}؜m܀+O#Kxl cJd.jjjmw!0 uYjVehh G&I3z]E)ڗф`Ոvwf^.#Kf}\GEIp֟0bt*im.Xq2+6OׁƓټy,*/n HK.ܒe3ЦFE%ϑHd%Vr]/ch"=N&bm8}yG(= ݰ-vlC,�RɨvYDEr*0$&fӻa3'_a5]:oDnK�ϛO�>�XJ@M+V8c6T;krchj|vM{EIh4$]aÙRSUԑA9FDrS$)*1UfH4vl</h` c0v-^ ݛ+AlQb}~L7mKHץX�HUy "K^ @cZpHnN-~spﺣ o�V�O,\7vYׇ1<GgIRn)oȌuhɊ łlcN@zf($~N,cYz !^V{<t6B?GSt+ѪC[Oy? @2H<=D_gsZ]:FԱi u[45CIM$+]y<k!z8=l3Cd ͦYݴ0EFy羆.Ao3ތbQEx Bg'�d} aiŲ)Sѐ<s/YVi#lW8`&Ty?I @0tHMYqZQϐݧV|L\"TwZKWWI6u72toxu:jS|;Eu*vG9zŒ56 .2? *eY�]9X7 &?$087 j^vB;T˴MӲ5Frl򺗷?3%YAU `*1~x_$^U5]"Eǃ �^*2޷ 'P^4)X~Oxԋf@|Rp\hnYUEѝgKә"Ub {̀yKuX\qh),dz9J"so3.2_~_~_~_~_~_~_~_z]6 K>^aп혟y)IVEY(8)Lfȟ|S򏭩eEմm]WU}_5wH(8X碌hV^+(F|ʪBT+̖U"L;*PYHqo'B{0U{kk)' 8E#? 4Zm G]1yʁB\T5WŲ.ȓ z6 /F5w[W\/X% ViYB,J{͋ɇZi-7[5ÿhlPFA<-U2dAV$z6Nw{ 3f *Nm:/\H ދ,h=(8cJ׻t:]i.2Ma]W%Ω3cl,,s>})Ln/no0x1tBJi:mӏgqnPOM]q NQ2Ǔΰz j*ՂGI^(C=c> /}ƌ;g=MfkF :*}G_TRN jsG+Φ {}~FSrN01f/bHNQ{}Zx1V7j_.cKax;fD`|ԽpQ QB0]ה(<=aZ)(,"[f%/-3Wi݋< zWh8c$EGa`<ImxxXk<7,tb[%o@ZণALq#$r)Ծ3fg<x [.gEҔԝ( V ]L#,%R꺈=xѬR( HdD ,T "d%8>^!28?!X!;fkzl׹<ڎ?R6L]Y 4Np|p4ns9Cq7&İ: D%IƐhD+Z zmZn;{`vG&)Ii^V5 nGJCGG1MC�Gㄽ F�- <8D1ei"3`<\~: %1Ĝ%jQ֬2lZb lƵ<˙^HlArY�A+8yRŧdt~(I,tV5a!@1Q gBʯrc - (�SZǹHi48\\ Gw''pLQ$.*7PObY- 'z,(27_,kmUj X% r4COo:wa;SV0 <L&Q*Wѝ0 0O̫.njf'u,(Ϋ*]"v4TA i__|xܛFRPq{`ZnR1UUdAs iet A1LC&S(`ݬZ*3 ]cs!Fݻ{p؝\G+BxĀ92׫^p$+/Ͼ:Tm]j' 0Pf'lJ(ћ%O )B9JaEdw\SQWP_675"$+, 3,J ̬Q1;|w|quw;Ux:LN=%6/;A]:W24>UXE/@鸲۴}L{)jNޜ (�l gbe/\TUFɊUk?&6(VAG HL,]$8%3 C)2$&Gnst{hɑ$١nh]ZfZk#Rg&f% j4.dZxnnhw&0Vsny4Fej채Ut-,zg np�bESĜ"gs,X8:<#x="z_*/a7?u-Z[vﮡ2`b~>Lzq,u3ߜ^朤ێKjU*W,ThȰkK',RPbNզKG@ A-EMԽnب'@IH8;Td+mUR9^l257.2 .-zkTef )[,aHb$hmE2zL_E`ʜl-҂1 dHӢbŪnY8 v GOoh2;~w r>{� lZlM'm)"ԔBxD$�EU3͐2CLǂ vLp@_]]^|xjΫ5疋<f[:#h�B4`ՠ_f5M(k*aWbۆhO&$kQ8ۗOz~*JF@c瓛+ڶ @xSu2 >3G`w[Di5o ËWM^}xf1/UHjwGgWWfl$UpHVPwUn‡"rQ8;Ő7/sU/kh_p@8�$B2Ļ# OLK/Z]ck=( A>Б 7z!2A+Zv!AFL3A2dPOG0<{a$؈BW׃|!t<_; jVo\'fiboQAe#Fi:!1 ,_A)PSP9Ps<'4+bjScnf:?y`irs*0d@Df:%C4f8eH鸎*3K.)I@@t@z^w3Lir,Hw3ΰ-[|&al,MnQ_&Q129gA0 $HD Le�z(7aEU'(S$bBMgL6=uY#bAfwSV@I {u8De" ` ˶8-)- r2ßv#25f*xi h<I4KST2ll|>"pEVK Ld]<4&!�(, f%VEbiqx=$T�~k lͰX0-DZ"cfj\PeirXB m܇K; ( QwrN9.xC>]%[Da~`.(PcTUBY¢�l@EyԷ!0Nܬ׫2#,<ୣ0?0($3dDJ2+Kd*d>j 4- &uu� `W@ v @�kxZT`D4Û)-e.*z6yUӝv`æj2 #ռnPԐg9L\}k^ ذl:Ӛ<9&Uz4NK48ӻ[ dcφ:QY`s8:/�XB|;;_wTj ^d]v]k$3vz=T)qZ`GsdU.DM]o{.žneGCfÉ OYI`5T"L 0H[8 oof ' <MA6Ah=%3-[qj*CeaR.] ӌnoͷY9FMHX6q-$[uUcQJ[:9?9بMgF3NHٳx4w#IY\]ܐQU^sdPH۲ݸAu3 R6 #P#"f$5LC"+K V%M7SQ�3É88ppj!bd|r�K,62w,[Yű&"OLiAIUl4xbݬ7K< ]"]\! |D*@TrtfdxK:~C5Ym7 jsj7%Pva37uj <Ď7,A@lvx5fܐm2w5OGm*"ӻ1; ko*O@ޭ"M�kr㍆�H&"J(z|,'AY˶3� ae~uMj,&:gg׷#VZAvkl _vPyO_+TL(Cab徃4*689@==B=5j9Ӑsq~1!1ex@W<9<�mUݤ i4;.qr9%&Mk}JTM< 2Qkx"?GPu@e"ˉ0? 3s h P @ps:fd\21QmC!Lo1~v<ֽU$,e)?ާaw28tf8@wkȄIޗL #Fȋ8c!kޱk=q ,Ij<EEe $Yе{`x?ˠg0-1K6'eXzˀڪ<4eQK(`KOpmy}.ó 'C n7+om$`?-'aL(GSH`h^-Kp�֛b?A�`FG'D90 ,Ώ%0v:�?뻰TQ)�SӺib:O߀?T Sقȓlz7Kp<Ҁ+JEњK40TxU< q<)>maѪס %lпQrl6?Q,p[Q"A! =MPO#CEfg!R`*uE<IlqGCw�H/ר(̈́A*R:DSj2vB̢ᄆ>0 dNg\eɂW 0xu> +[q5 ( ~}/{8G6Ԁ]<�ڢj*U,:X )aX@3Qf8[\x$ JԸO JP /岟l+vMaIxXr@edq)miI 9<D ~WOnG"@ ӿ,^^[<.ϲjpHEۉ~sIW Y<w�r}`XGxgybo.+`6}/*uXC8 dwU� 13VErlkK/?Ib(Bo_) @yݏًOa27&R5 Kqz3T:<<|z<j3}lq^MBݦ+<JCvS}� geyݫ^:i*K3/\֩7-b;^0)nA-/_> ~Mb:`_!o^ei-p]۲h&P0"<#9P)` KxKBDڣ1!4xX fB脚A0O &2p%ev8ѦM[HCp�_x18LL]� ,O<( 4˫f)|]|~_<6a1jgoqc3SWb5Oy*K]<{籒s؊̝_Nzy ^1¼n!*-669.\Q6a`),njabȭ$>*%O<}|aH{N$ѳ +vZPrYCh�>o灏@8 Rm osm~B" jy%eSc7-d^IM "+nWXgo$ |l.w/ݐD~Ͻ,ZV8. iS?a g:h;\d;ֲɊW.C]+B? </}Àf?\~£ ~U"A9\;50Ȉ9"rO(oTpUe(.amy_+ݏQO/MK <RReZ#PK#yk)sr$x�ٖ'IZ:< dzH 2o˚CXmi1@^6�~#NSH:3LeJa* #dWp3nF+7i4(6ģÃ?5x H%ޝAѕI¼Q$H8;zv$xiEif:$fsa>kGvs9HNpNrAh % $TQ 57 ޜrF<ãsC0>I$M ޼*ﻎ/�|+ws߯=xՙPi|dz<j1x@1-:Ib=FWXHlض҃7nVYDp/WӼH}ee\)( f-I0aPrM#da6 7"z5^f`_1㞄f۸5Qw/?ݓ<"';�Pe'y@u /L{txow@j"OM噏ϻ[EC(`aQgXliJӛE9<S8Lq\m$7t8:Jv 3œ&uG @1}/i 1Y;J8M w|zsvt51u k.K$HT_"?M^p< !8 ոA5,�Hp)Jx [Pu<{N{D@- >^|"aY .[qZeUV)$1i2O_}s@]t &j$PY9%V)|F t =Hϰ(zz;c< �V^^tA=ʢ,p٭ۏ'w2dC4>Q�_U+g=hԌ,'U1aJ_.qz q`)x<̒<C`D_ʲ�C1j �LwB|T8j`ӵýueC(BX`֣+!_xt_>*CQƮn]z %VIA3%nzJFBgO (%\0\Y..Wj<0 h/y~ѭmP:l\av]�dpEĠ/z8/NC^𑢱L`0XM/&CBf|QdNUgx&eK|2`5۟m\{9S O0 .tz>0�dY18/(b< aA\Bb5^Q)WtCjZ fUT! *h0yS9WU[@�EagVD0ِä*4( p{=UxPB?HnUD]zj=<3!a:K_Bw}@w?H fDg'DnYo%D�5V%v|9X<e;�w:uM�Y߸Gy[6Gd&Itn6-Dkp?^\N�H! ͉|@Ymq jU`ܮĔdX tr('V,Y+i--?đ,V'$2"٠/_=s! A ,Qb4w>hq  }qf"McQ3Mǟ`E7yieY�;wܴdݒA50^63u{|4'$:SIP}^=7xpb Vm[*,U<͂"q˽ViI,%䊪]bx*ֺ*|!Gu#سdv!vbYQ5<C0N8sWA mf"P06B~(%i]@ M+,Сw D �Xϊֲ߲�8I:/{nԼCT5^OR!`'|1M)yY58-W.wGͪk`Tp7 &-@QI TGk /G'ɸS/<NPv+9Lx/G,hQD{{Iv] W&$YJpv^Ea=@IIq D.O;a-#W Hf-J�gT6]U#cZ1j ٱ ՑB;`p{Fbf[M'*uYՉG>"J-�&J!r*x*s 2  3fEe  P_.وy^ON"mRvItzljT ]�|r]<exPҺtrAibSy +%QbS$WuwQɇsJ&/+˶TQ;bwQq�*&I2M h+IӶts3,jFWgY]yr((Q]T}?ɻ?FX&)Sl4+ >l B3 ȣ&0}>'QS^] 2!L qZNJ0X�OZqjM;0s &ˤoC Q 7tb8y3N h+31GXf'uryY7 jzP ޴@bh^dMŌ#s0f@cq*N`8H/&dkyrd+7QGj'fhWb"N/bF@|W_K� !3~?P�E$IƓl6]�o0`u{^XȐkteI5h4׵I9)).ŸAxA$^^hA О&lrwy;Q\j*0ZTWUǢ{ ū?|}(fyiAVb@7T[/|5sNJi9XMJ�m`-W)K(ai(pi[ Uaͧo7gd8)D3UŀP6kX (~vuՋW9o p491xJ|8X̖K�\mj]-ˍ! ^~U "+2u5lkFǯW, T@yj0cކy^.n)7]i\G6:}zꘊ$~b4Xg nrO?#q(;F%-s>Cˣw"l~"73?{WNp#pA%vW W}q+^x7r Tn)?[?}y@�KA5^B%)ӷ7swaC-<aN�./A\9ϧMXA^GaD/>`Tw.~a,E޾ݐ*(|LQ U}ΈMM[Ǝ*hwOF|[e.eJ]wLĻ_zv=fD4) $.gӒxގ({&a�0vuɒo섁獊rFC\,d^?7xyp ]ORTq˿0 kzVui%ޟ$ir?_ tm~k%y~ǗG*U w8J놡-usR07m`zz[r�/g{r�ẗ#5Z6*7޼pr;Zi+P=͉;"�ok{s),q #ʁxQX$ . }{g̏Du ӓ,тi m@ ὗ3M=[U(mzĂmHR60�G^>{d +rjA?{qX/N_,HHl$'Fa?fani<.wsN*{� VM ^%S_p>@OQ89a9WG7w%iĊfcKI`l&u{|*U FaOWMk`L/0cNJGe|l+N(e/qWGW $SͺbiwYLn#a3 ]}s4\_M(�Q٬pWuM^~}2e^ (#3fw6N/BːCO2k4L!)Aխ6j[8ꇪ×/nW%:Sy=�qv<# cjPcXZIg,n+Rz0DI H .sv�m0W:u_]"'lĻP!0AQ-)~3 YvL4hJ (AZfY9\X3Z(0 �5YA3%VqU,d4 IF^HRx[@%=ba&pm?L�Elscgӟќi2EI@;lVS׀ 7Y*ݦM7k(,1x{%Qq2q fگg?*"ۜ^jhC�%+Nɤ]vx K ˪eW.^~tt΀H%5+úD߮ӪYaU6MHp ؖecFՂρ۾n`ě;,tu]6 E@xQc i/pכ}_Be,g6:4=[DUܴ^pgN¸bI/ שȢD_34z6`|x/xifNJ6xGubzo Ug0?3=n�DQݡ�"ЦH\-l,U{,$9l(=j>'D;n] /VV|jpB3Hs%p eUx}7k&wV?j0U%Lp4Ӫ%9&pa*M,dzsJ /JZm78 6U- % z%;dkb{0S تh|uEh jLn#$18:@;XNbe=2ǡ l˅%̖&]tfbš o)h{`$=n3 I] ote<uNDht}|<A@__nE﹮Nߞ3vFS;b=5`Xq๶mZf .BIvhaMg'C |ضX$ӡ�(KxD|x}2JV96Lnkhrݗc08!t6 kVDe[ ;0gá:"fК_?47>|�⭃i xSVD4J\g?װV ,qw=8&}A(0 +=[Ux *xqlkXꖍU<#^AB.%^ >[:Pu4Nl&5[bA I4euS쯱sǺI0,(aCa;X\C6-' uZ? _,o{: Rv pfz[)t44+h&O_>  \H3eq>Y)Z @UiZ W=^v 5fwrbFp*@<,JXƶ(VD֑$^nUb4\5skZWH< 2L=VT%̵)KӋ9foсש Aâۇ6zpg,zL캲DR5ëᾎ,$$yzx;GN҇o|~hlkH�OyX(:^kެRKbEm~DA<o=<%*t]7s ߜ\\'SJԂA> [4'[[\orz[]{:sflqdU`20.55RH�GWW33YH~+4 qsTy{xئㆸ]Y|6peQװC_{Ton2sCғ!=l"�VobmMTOmdci9$ W _%)%hb[ c<4סyYxgXw`T+wvd[M.Ct;@!זL`Sz CԂbx2RqL/}@&tŽx߇pq: h寿Bib 靠q!W�"teSohsTȊUh0lWIXb�z1In> ]d' +q`Sz7w}_Q,~~Wp<0XZm7%_}y(4a ~{+)eE$)%?=і:m*9$F I5}sȊaNXbs^{x6ݛ}j`I;9M +Zswc�S\9'�nM3 /FU%w|/#/,6/LhYg beR6wv8/@'xp%,I�sAAz=06+?=11Ly:lqX2 f0v/޿}14z{�ĢA׋z!r[7u6<6n֛51gחN^ Ψ3nڪ(Ҷ;l j .)&$& bliF_ի5Tiq~V7mV-@7o,ouZE\_Tm_قམ4E8Mi_Ehnj60B|o!]U |[&M(~&6K ew?{5YK76ul9~y ױh%.Axؕg3�e_FR(XG@.>Y ͨnֱЂ]W`-EΡIq%2a$c+@`1r%m'3ʷH57fl=Ag邇0/ S8K16zk?lE6nNMh=�T|?ӓv&&FvO^<,\a;][ʛEYpQYņ<|jj2FW?:XYoȊk'3ފ{ݍb#A"-bIArXZVrINrMP +&2Ug_,f6Ͱp5xBG!ҢMG'9[Ժk?2<h{{{{{{{{30,pA<!5#[jUEU1ľazETTQd?~kاm"Ͳ<AUyd~{7 j] ]m>"뿕Ȗ*+YUmZW4V+=l4|"xq֮ꬨ*yb^.˲n\JD b1z"i]n#K٪lOij4ě3|\?^떛 ^s-_g CeT`4JiEu;I,/dx dėn"bWFvE,tMm,]N̈́Ӽ8ruaƴ<K~^הGt|j8BѢ+Qڱ-zx3oݑ<ˊ$7,eWXzu2cHvӪ)-Lp8bp9?ʫnYD}S{TfeU8^.f(]I躦0: )ާCMfr0ٷ>DKyܬ2%o抝QZNn/nɌ5q|yrM9imeߑ86Z?8Z]d]`yY2\\^& V-nA2¬,s:Ӽ Ai0 U #tByQ8ƸH Ɣw Cu ,v.nk|iGxQ^o˶6un"GZnq7iװ=GV%-K"Mє,W5jۄ0qbW5^ց%0ehpb b|u187MӪw%r_f7!dD2�Q%*:1,56$j|yv}7$e۵to$v!Qk쫩2̯]S^35WBu0DIu3}yA)vx+؎фl](<53ìA]mAԓx^TMb31xlsiB*lmhԌbX |KDMh<4]T *6(2(pl Q 6TQE# ۇUmY*("c,W/U 0 Fr#LjrŞ:(#F"VwS, `SXNì2N&ówHfE3a*H ŏ[W]Ss]!s!y*TN6Qϩ t ?M1мWdrwr麎if(F 1ueŇ4fdUfX {]Eٝ }ywV]+ zF=sv<輯"#'32rAM2`Wπ)(EY nt΋绎%?Uˑs"]F2asJ2quEKP } M1x?'h! wuI^Wۻ@M*$Ow`IIVPV�|'x-IDӋɨswq|><:>R4ܸ8r!flЂ`(K.BSm CL H %Dʂ*ČaI˗O/]zwvyNfqlXEӴfԉ,)Zq.#|vag85n0 h%Z MM pA|suuywL8:+ئwf ORsky!N$<Cs͌PYz)gzŒ:c>;۟Sh;29F%?E215i>d)34Cpr@]Ox׌] �N)DNlAr\5+Oe-,џCaɊVM"3%eXu(ub(,ؐdZ�'xvsY- DiUX"-ZjMSy/XRر/^.qsBrM>^nZ @?5'l@79eTm7NGfPm7+6[B_0 *~Y/כe`sɰ?%Uxi%o?~|v=T q`m,`.Rq~^DҬdEfY7N#Q 8D`LJ`V+t/ǝkFѲݛ]!$X\,g7<{1eH:Nq3 +O(^+?æĂS l69DrXABlV=3 4hK ͓j YLYN*iS݈h"KNa:w{/ƣݗo>M<Fh!R*j kY:n.Nf u[2 !FKd.glLCh>W?{J_p^D3b>Z2 fA.dP 6rU.h4 D‚M*L?/s�B~˛>zwA08IPl̚6[Th=jW�fGE恣a*#[W_$�GpTqcnCz9`=4duOI3 5yy7l/xA-hhZԷ5�<զuk PeJ/ȏu >)b3@E\\HAUFN;h2/xU Rj5KWf9hqR{g+8üjC L~cC)ŲUg v]<X�S9& ^kX5z~P"Ҵn/D*I,˗ io׉Ul*Ԅ7p|6SԤwi6\ݠ0#9<QtW1%K ڮ .c y8 -]/ /`' 9N$F}<MQ�`pz^,j 8.1 <_E0쏧`xz@)"*Q+JW jK0 =y_Fsa /O`S7`t$hӐY�Z3u9 J,uӼnQ,^£ħ�]u4IBS*kuZrPܲYQ yHV$MW ,LsQ/uF}f CJ:([ѻ3cs&$`K"v�MJH|\G ፋ &dUB) h* r{ ~f'Lm䔠hr:%YlI \&<<;TJGU,UD-"l .2@%ɒ o)gNDYcgM~AaS_NT5Ȯ>j?a/3w5ZJ+:Y.#/ y%WW#] UEDi~۝zjzf^P!~oI\"^Lg #`jf�S´%ht�4f_<63=u.nm9+^.q,5z c{%6qiodC Z$GCb=xM񂢅u+qL< }K1 Qegݐ5tOь`0c Jr:i7?p (:@<;ad)p ^n ZcuFQ`)rJ&!+41%CX{1Iӎzm7E֖ :42GDUZWn>!X)g߶*:7ct$fBpJ$y{=t8M5vmM`Z>* lenO5j0* `U7<Hm5sxD$뻹"x3l h98Zp,V$o/[]hk%թfU |ĦJ@_(oÛ% US PELOn令L;]0xfxRYsoAG"`E`v($)!l2 l&!ǞЙǨUV-[I7R�Hr oMa}5|z7xƼa9 h E�% Wh1v]D1t5ɕUӉ1ںǢa{Q:.FTDe\V[C%Tgg=Za;_f 7$Cr2b %jκl2CA&o;D a hvhuP?jFCtʲ:N<bׇtKuS_שX1Jf_ίr&k×h4uN& 3y4Mþ^cֻ6:VUb% "/"Ib/!655$ҷL P(]੻ӽ&aۛ"b+4F`}?ê5vxIͩN_Tؤ<h$x4Z d`m8R$j,{Q́a_.LNr1x)?>#Qux؛\�i 5ȗ5R]+vi$U�xє34+-3D{U١Zp*$<;M/fq@Q$[Z1M'..9Q7R*,^`5{T\ڮ!,m0#Œ(1Ş _b \p7 Pgq0\ho/�Jøg! >uخIໞFvUA9; hb>_\ðV&)/q'9ET9 \Qo8hhVx}2e7GTeh8;kX8&rPpt_�q ,ef\oA5P_Pх^v!mL&%$M~+dw3<4 "QKp}˴o6s�[~AfqRQr0w᪦),m?YafZFU%F1#X272ө% 28Z@ArN+i&D.("n٪}XL%WjAÑh HwLtnFb| K,1c$Wm86%dc()4sŤæG>x*W:^E)^inb!\c(0{12Eћ7/'|p~9h:?#Z5o,ӳCP a=7X،咶dqv~$ւݸLڠF+\ }/s3O:3{g<OW̋M$ D,Y#م_dkaO-uQf&yFՈ\#A\.�( H^9jprtv5ƣ{KW^xɝ0e<�7B {T橖U: ^mvmz"pJ h' >b_гe0ֻGG/ߝth&!R;g޴bsUe+"cOOIdXZ8[o̱�D`u]%  7y꘍0t[=X͗!Ld2WTkʪjְn`߷ZsEX]a=>] 1T|gzy SFC@4XV(8nh`ͻWWfE!Be7x/G]5麩qߠ9j7aT.8DYaV jBBD!UԖtRv'qhK<8Q?ЇI^eMSeA2T>oCۭsnIDާ=eP�AƙFHSI+̏il幜$$#'${eD 2֦"<wHcg~@iصu�X�YOSH1uov]fci%)y7^>�4m0U`Źajgo.<)e,Wg<G{SPBUYUw<qqJ֫4D uQHxX[( 2`m l^-O?BpXm�vN~.-Hh]V92 334+5@]<@Ӎ"K //vCN5}XK\*0/�)⎻\yq\r? c]W\/m8&'[B|g0b:lL]mx x-LVpC `� fRxѝ_VnQe (ۗG@.p !'%o!),Dܑ<l�9:4U|zLq56Pg_D!i0]Gg셨`>؊wo]btҡ %')n뵀PGi}$-JBvs8#E64EQ `(O#H-Vsp1@d?|$tA8 ;jYQ}لGvvߊIO<uM`lBZ>?~EYQلG~9y|18hy/pA¿G�&н>2+r^0Ť@$T=P]UQLE}ܼw7dɲ<ӪcbN(%I,fU\64�(4 %4 v|rHR +Ctqk1ax֟^GB&SNl_PLK]̱1<ʛ^w;}IΊQG;Ҷ%oN}쎧JeZnӞo aGŭLPW,39YM y>_,_ތ2Jp[<uL"-95x0]ړGo?]7sM>-{"SŌ2[}:`_sj,~Eq Ll1XsB۟ Ux@pVajh|( KtH\97}[C;( :TxfB.(VjOv `unw"$-N..ޒ[fI}YOz"olȾ^W?~:-0:,zZ9]_]6ӍfECM oaM4ʁ.F j|}ˍ㌖`b�~ ,ʪ{Wo0xQ�{;PE&ggt/N45<־M%-[ zzwuu7S`|, Hᝁ4I !8{QVfyK"oٴ{z@9ESb2]_vQB'Zn%rK*3 ]qG|#^z@ii \#I β4S60d  $y?೼Tj"N*':d8Guxr ` t-FAe3oO-7N4ѿ铒n�,[H0X,[['N]{y[3Hׇ{Ci:$*f>Lɔ3ܧ tDP >.}f:v!|Fáx.`<~@N!E2Nib&xky@\ x9ݓI.Nc�zip]<t Rwp[w*}ם^]vM 7=y&E6ٻ)vV-e<D4$ӛAIO�a骩3DhHFR"_FBR7JQUUck3)n{`};1wW#tB[4 G%Er8r70 +SKP6x>oy fǃNo&˲,ҮY{-oB,g<`r*~Ժe^UyULex|/ڃD<L32AX[/!6-8 L9 /Cpdtt6<y~U Nw,<a ÅB骄QC}Rm-xBTܯ4 |UoǞ'r`=pJ]q 0_!cQ g69v͏5U q ea-|`%5C ݰ'k�V[V�fX \�p62noL-RvBsVfS\ ?Zmq,"F}4=(W5,wx w 췂 24]qZD ,;l* -VP\XZ*t6#q<n@;ES=lf5l1 F4Ƕu2]<ExIm{٪Y4º+JV5JD,$PzF0_mj-ʼqW/l| r t4P}_>-4qI~y��T %3H@xQuaT Z?[Kxׇmar�1qQnp1Gx/k.-݀F0e]$Yb 4|ƈ*X*3感-Id r~0RJZU]zkb;5Yt_cG %6D. zU8̜cDxx$1�8m+lƝ' g˾e\x[Kgs^ S\^n;BPQ֪_g-$@b�&NT9ee-0dʠvR5Ud�l ؈,w’$=ʚUY:eeQ l0sJTKV}RQXP oHpEw=蓂I7|CS~jzv3[yM&PEvxVEΕ� @"oo(Tx_ u qS*nq#zKp~r7`.|巩s7KHOiH7 x'Uw&6}�Z%*1 P cћ9%YX_v=mH˪p%Oz#NP *ƈ *vT,7 >Z6LxÚD aoDQASv,H<gT"ӣqO{C<$X1 uvE\(?ElqÛgec|xUU{]AP+b&t ? i |9\Y@ܼo>Pr82O\Sdga�: 2%f% An 0Atg&;h׫܃`׸B7bX]㣳~o  #0dQCێKX,5>~ڝ"*B ,$BtI6dK-Di_ RCoxAE{`Z$ ߼zKwOP`fWEЃ}:yw6dDg/q:Q,4 ^ S7@\0*O�m "`8�D}{ͻ ޘ(\wt`TcGǟώ֛ u"NZȌ?zwKK(^?Xdizx-�1O޼{uܛQ�e !.Di,<-ۊݻstet YWI"=;y\KD0Fgc`I:oLkC ^^�lHBJkc +  <`UkvW.W)_S&z{�3K˪KWJU[45>zy Eɟn f|xּěX/\#Y6ߵ}@"?zE7uEJ;)�EW,"^^bXU0AnFT�߿y}I^~27/>\,gH1 8eR�3CxՒH5ogMKFNN "Uli2W{ݫH0ےUD<Rdy퇋s{5FYh|J2�_> m ^(2`sڂЏDz ݫWG}Ndȿ|W۳(8?:=;=:XLsxIt~/ |Hu/_$gaQF^,f:3ܝy4׻O>wFO,z5 Zءk˶- FۻV2t%r<IoFx8;:;>:z{2DOFA 9x'Y fXe 7/L*!B-9~ YX�XL<S0W_>}c% 9׀3Os<)g.@ :8k۪@u98W.V2 a=&L\XH+|ll>\~8%T4%nxz|yMz&]/nKҝo!]hV1)w>޹Iò 51'/;:̳}d >?4kql6m*X$:S -xUCwzoͪQ]g4X{x1¼ꤡ*ΗOS(x7-f }f!sxe(n4!ai<1W79 zGB0LXFbel:gw F5vme,n _�caNj+� \nᑨEvk+OB_[hmBM;kfd&z1NXx֞ʢ*8'$Y0q^jU7[<ՀX,L 0 1%1;M6KwT9?^B0\'Nt)繌 U nJ_cm̈́cD5fu�!Ɲ;xT,@U]8Wu`8n ´j6 P F[a$DjCޱw4ίZ'xJV2ȷ0#H̊bo!toܜ|ze4n}:&KgO0ȭ֦aaxpijxq1h uj ն4 =Tγj/]SW$bӉ-#kv.޶Mpu XVWB^azvw̃ש >>cA)|nEMa։k-Ǡt#JWxҴhr]er{~SMSܬwK�6ê2ǯ}'>zMׇmsVbMthAĢm;,SϋWX &@dI&.vAa!z3N#C.l5"dwXE6($%)*Ggoή#bDt++M;nXP<9.QȤxQ ysPfeKxEq&I�jkBC$piH1-~}xXܼ۟ǃ*� 뾊pwÿ5 PnxH=&hNascKX3l-=~}/Tn޹݋w>V]i*y\Ԙ~oJ3dKGty'Wc.*X+;Ma6u�F~+P3Fߍtآ@a[ q �vrsvz=%ҺUr*k,j$,M𖔒XjGNgiد{?C}zv$n6 CO;,nZZb' $֠P}8O6݉߇D/xv9L$ bzw|EF%$Mak2Kp!%mpؤƑlk*~xo [ֺd`4,}5gan 鮭H߯| KmD: C$\b J|(|4T $ݢޮW%,`Ė;KSN4~%N� vE/w_x;Z_Pϖ]xUeG! V56H}6TYKw_0g}GY7H?;Wۇ H}|N沐56uň6e�CsG  x)6Hgy%j9j,+L/u{^5вH=uɛW8Ym" OnxSo8]MLxe#X. }8)7m__R{fi#ͪ \u7m�="bgKQYMOF\(.[xn�C <B;vMd54[_wxane`ߕ^dz}5m*Xljo!;Yu:T(R�[I�EQb3vb+Ma4-mx,[9A[nL^X`e_طF&3}%sn9/a[ a>|q4~ ~~융Ғhhum~*qw_FĬ{k a_&TA۷bU%2VFy+l&�L`-%AhzE+uӣ8.XI5FݮjX vYtb#QQ [pHV }["I"k,X`^[p`V9ߥ@Dr)$xe[ ~c^~Y_fn(|߻"|>HIܕXѩwط@r <uyJFi^ݜ~[gI^яvh[ `*KGX{b d# /V 64q6a=zCi28zzU'8>m2Qo{64TZj]2HՈ#ۃ7RSs|{�X"~0-'6&h$rG@k�_ $3ҍ(vAVv_4 (_ad2vO߽ybQ&eݥ*4MU6m@ *OgQSt1y 7`S^nK'llOqlwݛ*Mg=qḐ?I\I7ؒHZMa!Y<RKSe~v[SxQ( р IPM1M7o2GFZ+OcRGP+H_{7'f۔j -F`3pƏ[aox]G&GJxP_b<rE|DȐtە6Vu]D}7O4XI^ t\e(_oG�A̓l l�/m�@!9#~ᗕ#RtNsj:Q[ջ?2hk-G _;55tBd[i6vljNGh7u_ k~8థ[^U"g3V6WD=r08]4 ˶a,DYl@jV =ũMl+\nbkn>" J`;zhdhhB?i8I$ >$5*vh>UXVu¢iXj%:Ҥ9BJfi<}_cbU'_m̱-D)PrdZ ?1Z> 7LPA7lu( `x#cx Cr߱pOs[fVz6c,pR82jڿX{k<h )?2r viDN ~֟gƟgƟgƟgƟgƟgƟgƟgl1_;su2eQD39nY6T?;L| [9zU{? ;[= t[Sv/ NU^\O0-|S3lq &lXIf< a4^%?ӵU/5ӏcׄI^AuWYL|й]XqYov(jUYUm#q~XjQZ.:O"' ;aۮmEF5J>?GUSnaQbZb2duonG(ka[>"{!)YAik֪"⼪bEӒgt(:W6VUYI 0& ZͦY{UŚdG*V@e/~ n>L'$FRc%4ͳLfke6"৒Uo[:71͇˙EIZn$MRA<_4m](ASB,ZAQ&QږJn`8&4K\V(:ʚ$?,fSlۦwdkY9m~7i-~ءX.2F *0*Lu`v/ 7&$A Lvg,fmoB2ƖI ǩ^Nߛac2NeyQ+WaY=\ֹg1`&Wg7; J4y t R*J #"%C-5g%2qPvG׽툂"i; /0ѐwb۠(uGLE1rrVoBt7{\G\P,'�_oo{キ̾2 )I̮>1�YTe *4⺮ w7sWmEnl|fb+Q""v03`0WьH",^oĚ^ښFY0O|mEN̷LTvE^ hzIZ,JG[F+Woڎx^`Mv[Hߎ ȹ,E g M'&KXUd9= _a{!iL/iSOdl=춻MbkȰ:CBi -]PfL ːYp=[nӛ-ۚ:noY^:+v}<c[e+\xLPr u~1lou߳pLD%M[+M9׻;== ?kYl!,Vڦ1`F&O"t*CSdYUf4n'~oɮ 7mTU\s6@q` C֘mwƔWtCEI`B u *l)t0Ɠao\x 8glI@,Y, lIpY %34 ?-.t6 'K^T"zܧ .(E")(ɪ5<z]X(kas Qouzk8Ë]6DZ4WE퐒D~$=CX(W 6Ǿք\2q!!8pSV^L'/^_\ry޴EPGo(8#nִ%01>l3'kVXq[5b6VWc�]CU#Z O8u M3If\xnc]%v6ӒG3PӼv"kcL(%jt9_NAeE66v8mctUpE\BFa)To"y4(LYS 4K\޼$㋳tAҼhmlrсRnEgJґI?<Ѱtd6m|@k;m4M cT'8F׷U[M!X`Q6/^gy% B[zdQqksӢ&9h\f2x 5P'prŰ ѓt Io$,8Mx�`<kАXFMᢵU:u %ؐhNJŊ+\|b@Ɇqd l>4 %"-q4IВSnM,ZrYr6N %A` R@TB]s\PM Ё74a>tH̄0G5zZoכ\gtNHMGD"ٜy۷˫ )4?ffjy F+F2uLQl6Q)B P hF"G>/%ZٔQvZ(l{YSŎt&$(QcMY%#Y OCPyr8Ztљo<ūf8N+XMZԼ#zP֩ɭXڦަ?݃bN1�xP* wcD^u]m;DV0|,ҋAF^=zϷW7O_]{3ڊ++ưjp?"U(/##l�?D'b 5̃I<+**1 `ɢk'rݳW(H"L><jڐ&Mx-pKGy)?iA3UE{0<65`r l[ oFKZ8:yv__? �xJ�wwkO Ev%`$vG B-6-h@DSojBMI}]dfќXM{g޾?y~<(N3 Ĕ B¼�pbOEkIi2Mt܂ .QP c!0@FEr1흟]\|ʺ$ʫO7gX ω FwAPPYa4 AQ-E (:̿ 5'ef90xE\Φ9<jɦ!b8&V�6�x\ZSr8ࡀG0L y[pSGnu @f)mHȐjnMĽETBu=T|84T\IxB'x)d%fx{h(6iPWV5)Itmma۶g^CRp%�6"F$ 7^R~$0?JW8HS�eI@il5i�lǒaNf)%rj0WyHr 7�$jy_4~bYv9\�^)?J͗'0FV D}SBeIq*g tEB5C"YO~8hNV NzJ؆„;l3[+l5znao2,9a|'HjԖ�x] /nb"+&+UWu|![& j7 % vmڳ" q,@!&ؗw" ~(+'0.cFT�$/3fWg#^͈Dj)&L56?PW3`~);)!|@E*ay !Kѱq_gڥm_C];'H^E֨ןk|ƘbtM�ZIQb`u[A6!1sq֩gh0<M|Y�CyJ&U$(%kGcVQD\vi&2QYWXs@ C E-$U+A<l.Q4DkﳙRunQ!s4NCV[F;v: ԺRxYI*=[&7bH"$qM$J[leqV[jo 6,EZ2A Fe L Vnf- 涷VqG`G?8-@ \`N5yq{%/I,daeoP"-U?W (eO]V PN ^FVomPUUɔ$sv-4uJD5]JZ$u}ۗ t1B~ώ5E :P!%*ʓtrώnnto.8wI,=]D@@DZD9U˺H 4)r}Pjh< xnYeqzAB|8|�=(ȲOF4mw(s]dKX,D�Tؽa4RZ桇v26aehYnt-mj"I n./VP4x\=Y*pez9XY K PkRw(*&gy(w5EUM%Y5nb i]S%iwy:[M%9{~BΦ hy޾M;JWj.Il e&9F@} FT>Siר>;@% o BUSVbv]Seitp3#)Euc ma>"|;dMΚuUĞj*yv >$vM}2Ut<|6D]LpwKUT}Մ`S�jGN8hMT|{躕7U]ͿSEzO]-�Ј"9 fcuQlP.4Atd8~ 4|iiZ~8$&:=4҅! =trO0m["#ss^%T,IxVkZGfN+7Vɮp7@w/tQsὲ�sMSa@Qj]WMS"K@-|:K<ttNx#YGуB#q-o@J6LO%,zOSBP."1 `Scy;ʃ]G2v<X-7`2;"'5#i [,/>8\1̊j�Z ľc[:%7Zӝ*^qj`w zS"{7ɪxuu!*ĔEQӳ1#7ÌREe[AtO_ :.om~^>]ܣ]U^-2 pML_C>ܒ&W_pqOߞ )4ZVrWWU>mAoK}Ǿ�0?hˊm'pz]w@ %vVQ 3=|^דէ߽W_>eAQs � ʺn7#Dw,a'1P0Ҭ~z .x캢%4:4H϶:=Մt4d_~C`[˖ 3lv9c|ǾmQ90P,[Ѯj;BVN%NZ4m]X= @b0?{ !@ pWOn +H [l ~#@9uQ�Nذ$84v/;˺sTkQ.X'2CslO4CZu'"ӫ%Ds ϴjui٭ht<xhtW2,/jE:Ln4@CAn 5Jy O.^?s8.b!{_iȃumMʄ__sϙc;l#6jT#$hYy%PP-!JA\^{bEo DQw8>(^PSn2ϐ<JaSx��D% ؠ:#�U7 ݦinT H.4E+% K}3Bn/JŇk0o:ifM<D M Д Q@myA/#U 2](tNBȁJJ܍lԕ/~T <}?Bk%Ulj7ud69Ahu]�e�!C\J '&trpbR4%U`080ɫOb@9@ls(NN&<<p,*@˚v�yktT^ 1uXq:E/R5av{rMS5r3/?}|=vwmD<O8/>.90K"HJ{:"Rf{1N:m'Q{w(b2vU$rWT_@p  YU&jJ~t.t5.a,[!gX\ID�f5Dfv2'F)M085L %L/Q �|210Z%rp͐u?I <CY0 OۃW/^A(RyY5- |^7z`4V=i^VP c :~ @ g!!rG!81N3Z\|H0]UE�Zש~m>"ڨ~QZ׾F/j=!}~GʀLm/j<X7)sQ'I a$aF0uh-2:iĐi!.Ӷj�jókqaLM'f%k X_1 U2~z7V 8Hb@8 ,MUzr~z$xVg)NeM!@:Vŀj4O+3+Z?Í�aJ*L\`HN/߾9`RQcHBDžh_){Y n߿L3uьCy#"5|Έ,^YA6</@y+Gg$s ӗY.Y^´_5D蘛}+2DZuS.]p8Iz{`Y+R( _/ЗwMYdE#)ZGƾ8OFś8E(Ͳ"ϳm]Le?u\G+TKt(\ǃ~@~n^ +*xT'$r@ Sāgj7yܯN4/,a=/]ef.TVD{oq $ Xr<O?M0MXBed}Tc�w76Eh){}, W^qF'y Q+.<M Ӽ,<G7xU@w0ɂ@:o[@E.p4n/x~Ǖ4&SݾFAt]a[LSǐ7#MvB$E x4*NTT8JR �Nr:wQ#nk?/ cq;rĔɫ1 �5ٹtAxElRlXfpx\_42r;>oDA1Тc0?�/.� qYGg)\%@I0LW}DuˑWVp;78/<xUM7lkPz QqؖiѶ*tوrh[g@3,__céG5Jw@ᆦӋ¯8t<q߷ہc2G4'EKv=[) K]WI9|v1''cʰ<-j 2e s]Eeiy #wWQRl5d]8I3 Dm /6l93PC0sMq<"!f(0 ҩnyeAb\AnrpwtYN, j!`Ixl}ۏA8xبyUU9,B okhj%�@|N|]H@4.̱ Ŏn%6mB cwEZ7`.*1S(d̡5ۇ}f7_ܬz% XpYXkxZ$%Js0 UX+ t }+4E˱ : ]h]lV~RV%9ɾƉI.9fy u ;BB{^ *HH`.ԍ<" ;TFMk5MVܴ+L!ط TE75r"U9"n�`7QIjƒ3ᵸYPbz4{eW� . 7ip縆 v$tg:z`l H u+� @, n9QSGW3fӸ L; {6t2*KUqf>@4ء),<vuQBF#6V7<:CǓ%zR]b RD['4rjQ<Ջ%e]uE Dihq0s +]aِm,$y*hܯ,)b0o_ <V.>V;!v%y: ӂ^2튖Ms!!6@j^/\*C}e97Ĕ 5h&ȶloK_yb0�1Bnd։k6^?Hn'0˿9!� M.*D㈛ٔmqw-i æW]B<!IaƲ.g2wԴ׃ xA4L+#HG^aUN>1lb8Al %:+wT K%yI4<"MV=F)@f2,hre�YH*8fzs{vI`4p.xryq{6%qEjM-F* ĸ_?J=߳4X"8 <+x Xb48LbXts=CCip`{|EbsA)7 $AfjRd/ Jhv_NW4'{X(e³d`(=.r U #F'/`9]l)sK%^Qd-ٯCCF(AA.6`i�y" MrF�n6z`3fA �3+g^-ü^7"2"DĆ*^=}d3-f]mpzLшolRn|ZQt>o{@J@2aeYV�gdz8 j'ԥfRSUȳ{vyY NfMtHtS@y^.)[c.D}F 3o_,yA86 o�BLT j>ҭlؖ4"ew;5vr6L`ڎ`~ATªb稫7o^5nRI&8E|JjASq\yV�fK2 '߿y|+2DBw  Z+sW|^ y ?nb4 @3;{uF躈q ͋�t'^ 21'l^π?fxQn�H)]`y8ŋ�аAnK\"WUI+Kw$dV;G`xU@튀E1D<=l%*TE 0qUc&cъ9}kFҪuB Ij><ϓxc5 /Lj%UCHTRC"şEǟ{ +hA?uč/>|Oqx /\+hY<T;/NxɊT+;AfC`9D؁4Ed))(7 yƒ2}Շނ $ðlxqYQV$.nBa VxR5o"#$@ "fܪ)zSwox{5|rM2,+ 3f `,H.`wNEx* �<x=Շ>,柳{M(XG=z˷o^^PX$yulS "|+49tIQnA!"6#Iщos<PɳgOߌX^lY9!ؓ~wzy/=8 E))X*KfαɳW ȋsf-HKI8<%5usz~7(h׃ <U`N+jy E /yܸL]@K$i2 _I3#~ ΃LAHݴ@&MeA`߼((z{U8 (/7ۦH|mp[ ˮN>{y>!i%s@+UɭwWyӧoN"�T-O Ǘc$o]+M]c _by_=x#"ÖX:_1@^ rzu6'xΑehptŊ5]/8�b֐\tH0JNilxVMbڤKd "^UMaWS~(ho?]L^v8ZI(~zjIӬUcw5;N =p&&C93f!Yf ?]\AҬ Tc0b~Fth[_XIbY~cWp$xL*cMKt.¨O+^{EEyT2 w`? &FϱsZSBiD鄔%!@GlXjYLokq[:f,pcI4Vg=CK6mQ Tj%(ob\:FӖd[IV.`6a/;b=MU$)B`e3.a7mUoʙ/`uS;$c<Sai"? �> L7oe0&rp6dR> fG^,=ו*XdQPQ\=V;&E69_FeUv<譇㮱IQ @Z3,eHcyJiSI>t _'g!lXq{%ZpM,#vtXS}ܕ:B:X-+AeOIhnxl<},o[Ǯm<;�eusRxݷ ]\ѫ?Yv䗯_~]0ٱj^ W" Jê m bp-ڌSwņPW+f+9k�j=]WvwTyVʷlIf\g:>cU vr+28<6hXdM4v> ae6O<϶w` x]N Nq62G9zW_.ܒQ^/X,Afs@RYXU4V<мoJprW}gt.Ӌ L ]WWw,k<L$;fxާ  u,7 YdJxm`pbL;[O7o_~X6R`Zxz1$Ͱ@pxF·3l/kJ̊NQ$ٗ/3if28ɰ/^ݗnR8Y,Œ;'0P8#EA`\ĵ4tm]8L(d+SAQ+r0kyAwabM ,%+%0ts߅&k֣=N8)*n0 +b6_.#vEI`o?uG3l7Ăū %('qro:rOu%Y-Y#nN~96@@r.v\CeC,%k4X1 =wxaƖ0[qu Ug$'W4.iaiN=O 9A$A3ϒ V~zoF;ZT4n ;)v :FaWx}*|}  &]b)/ߖo_x4'#y18'3#XAus)%n_<8kvm A*Wj'9^EuwGEwz}G0vN*0ɏ(Bͦ5XRt'|.ۗc,ȁ^M ,`ԎxV>DPk~T#*JobCaKb bKH:K#'%̷6txPO:̌,ww0n{:Gc?V'$#_oRPZ+ "㱋w`YY(0q_ ؀!.Xo�n+PESzgOiAVmdZd@F`hTiM$+/xç) ߿~Xw=nY<(D$Ҝ1#bpح4 \]FSZ' #^p_lNcd&5yKf)N 6ȦvZe$Q`7/Ɲ$7x&f]WEBS+wԒUsW&?ݮNC'b|y>  No6+cZ7_` }{/<Mm|J49O)A6Blpաj0ƠKkX~m&dISa6ǖ!rtiz]'E\L[xW*Sa=07hXh~kEgD-^7GdlCL,˫K]oc7 sCle;oMSڦX[KeQsgĎ*NZ<ܪ"N Iu;"7٘[n+SUq{ga;^C yAOoŎaI9s /qVq-ll.1Flt.}U9%z-zܦ,kc]Į9b "�T?vH/u4~\m76=C 1St7MܶMU `*ĕ"odTB6Fvct# 4q8wMhȜw3u4a@z~/x]V5Yx]@M&xr6x?W`Ii2#u�{K!"YnwrSWհ 3JiAV.sV w%Qɰjyl"ׄH<ykV[3[Ga؉F&Xn�-||4 [^$ŐT(HڻmYnzhx79f*.oGqm 5?t �nRMk"HZ}9n:zos``&l:<X9(A5 ]OFCIVmJOhJ !7xQ9-߃7NrFZXq[9X)^yLe5^iAsW"hex{l +_$f+fwg$'C%4ɋ ֌[ȦʣhUxVi˲ =[Pu g(ٕ8�7Ǽ[q{DgO?'Ku(M;ۢgeJAvDX ѕl U5' (I *:7,A�ysf2d`tU(AV7!3TGqhÂ6#otwʻLw3 F[zKOAr(϶5~_5~_5~_5~_5~_5~_5~_8lł 9͔$|=\1f%IGUDԜ3NGh\<C&ل\GL)&( ^-(2G4CRfj:wEK]' ;N˪H\q Ӝ=dUՃImT|9}EQږc:aRޟVAwx-Kv^v'+&x6t7H3jxQQT6,ՠS"L,1gp Ei^ڲ,j(?%Y" 準2pWOz|2ODr`qרb[E\DŽ{(F؃h(,h<fe:AZ6()q3d"g%\O,s]xwN4lNbYAePD{mJp4xB#Ŋ i$-ҲE9̃渮-ήc=8lQ}DRAxs/wTձ�Aiwכ;RL("y"#Ό}}q3I&XRߝzUr,w Lz m ޲e#,ɒwm7v:}^4C $ʐm]Aq#uRqƓiI*{,sk6I'j73HCëqxQ#%RYM c&3v6e(wz&jS=a0t>Կ XשF 0Nj^%FN|c:f1CjtPxU%{fY^ - ^@EZE: !,iufIU!?;i䶤95JSr^8o1ZbIMˊCpNZٿd4rLszj3+JWQ8vJnŻ^Wjw3ևM2fی/Ww87ǒV;5=S^/W{ik*i#Ym[ӣ+َs_0ڵLukw'F穧jjcZf?Y׋ l] {2 <hzɲQ^:@,VW-Q~m]C%Ţ"eZjG $utY*7տݙfhˆ`E3 غS_v}[\tж|QUuY&fY/CېH2#ifPdwG!l{*'q*\;N.G,ҭx_DYN4Is[ oPsg;egՙ׉k/'[�֘h9 |KxI]L QE˖̐dvX%&UOԫ;i`}V#[utsWa83\,#C4w q8Zj*3 3X^5uv ԅp9lhA�m5w=UHvT=n\Ɔn Pcڸվ8uƢ0j~\eYFj^n7m#>B!ŜU3wԨWeyqʶ =Nj Q$q8\_ָ$.{K5k?~+V٬b }$h~y{ǘhv./n/^T$X޴9AT~LԦʳ扯&$ E„5 7vFMumsLUbqÇv/ulv:Sj톌+# ˵,~;C:TF/-Hn\~0 6ݓ7wo[]V4%0&bCmsdYd*D[$.D"Z>-;\TCӣ٨{7uw<v[UlLgv>aSp &#:Ok14Cz5mޘ 'Ѽ\ǨOp [ǧ7v*)Cm*i4שisE}nf“ #(�2DfS~6"2ixݺ8sIsui *8:$|@Х鈣& @Wc^-৲#ϵu& W^k}47eʬ:a^bU5Dbx?z:3 3R�@Q%&C@jL2{)'0o/ǢFf(= ^V7߳yEtuw2#@f3#F_oMD F3фIW9j<Ν5U- W E&x®FQ%j=<M$/4Hi't~L Sh2eF/~yijD ~7^eJ}QjuKh]oօ7gtCb�f'?yo<l6u46۷Hj]g8L+E'SY`rL|Vz/]ۘyˎ9iKNן};l~g]m$q$?'aVPe#X˂D޾]RKtOCGԈ - ;Y#Puՙ</N?/?y޼xWPiXH�uM˚0_4GݭW*+Yӹqz0p"ӻ|xusvoOziڮm"ۈ%55b) �8'kHru.F$�1^yp%3˫xܻoO??:=?aGoAQcI@p]fT]S/~͋_1Wuv0E;6H&*c,@`Ehlps~Ƿo߽ol|7愾1zH:J, E`Sw|",MjKVjgHLfִঃnuurt4]`ywўD! )l /7ڇbXj薫as%MM5)nE`r 0iU!E3CG x$q˃VQ6e>.5eN4'*ioNSA'V@d@ Y[H� L9#]u#Qnc`}p `;7x ƪ&p`헠AAcpx#T)QXqW&޺pX1BO{ݙB=2? A<]mf&­/{غH &ܓv co§hܣ_y`a*f!-=O8ŌY;xE]tw&x0"Z $`ŞZFֱQ`Ȑ<JQotddE+�E ^}hDrS$:(uf LzCkԞp<̮F@yc4V V=neN H;~߂AXxgB+;1fwV W'U[XHūxvi?>5 *VZI[ZXO7`eݰc27$W9VrG@["@ɰ\^OUTNS|<efGg3E7XUxiyu2uiLQuWc޷ RE%j{ݭ$^j|q9(l&)b0૖8 Fo:>NȉHs갸 8`X,1Xy" !5kcA_I?twؕ 5mns0)|P $Gud0ňg!XyI`Gx%ݑ2pڑ~N=$/eXVԌIaMV~43)kE6|`Dj|u~1MW0R$IDWcYA8f:R⨨-45RKxae9Wn/ES /䯑@vi" !'b #hKڙ&!�''"B~xL|^JL8?W`/}PTEb7 w'׹!l6=)ݫk<fxuzv9-`jog 8+?&i} &q{8l0Il"" ;auhStM]x#]7Cz=et:pں:HMaغ>;99(mi i 4*Dc XDx0" ƌZOsDݺ Ga7d@ QJ[G-A3񧓣J)h9RgpCSҖ̀h͞ұ͘:Iz9E*YMMYk:V@"o8=i)݉7޽ UEub8ED|Dq1Kz[^Vmv2?z� Uѓmݲ;l;"0UY$A`J1 랞޴N>{q:u.z,ð̸כp0U ]GrG_ֹ).6ڲ8t(RP kjI}>L,$eYAƿD]}<?kZH3777Wob̮ƽ7O.ڝ'%uILԈ_eQW;0[#*۴06|Iz # ! 2ABo8UU8(#LjLON/L ȄDd聂?nEږ P[VDvJ(&]ժ,hIH DDr/;Zu/{,|\i+,S7]DZEI?2+Bצ.99.J $ZZq,H<Ì)FǧO{HE}ҏ$9;3� E 5<%SdpJ%Gz5 Y/YJG+H�d"%'G``57N[C|5.c:d8B|l?K*R qSF@hw;/CCN$%h#f*RL+jO!߂+2\*\ycg )/jijd$lI.ÁBhQ b+l=j,v?6~vn8ߓAKvw{HZZ]EmgcOXEnG!%^5p] o=3f:},nLm;u(4kјb5] F1]$i~r}_ŋw'_xU˨<Mhp+hlf:~L8~ M5B`4՛Tt=7hXYЉ ܰ7W5ϟx/88j'LQU\#}`qDe+0K?K#A-iՆ&z f˒ķS#Ⱦ{aLήڝ_фE+M 6ͪDoN:ۅPGq&iy\5x4$PT{ewf)CȢ$$~y3dn:& ]bԠ xcu5O?߮W9QR9SdZAd`w v�T`q.)EZm-?HIm=O﾿hW, *-F%"M|31da:b3FPA!#eNhQSo y9Z jUĶyˋC�<,7?;*qUoj%" JIft:ؑ↋-LG%n6I9F">ӰڃIwn̨?akoj0LEGjP;9"͘a$Lsh0X&]nbi�`%nڏy>F13 ?\fSNt+,jq| ; hU�I;霎n hЖ*"^Β6msG8ʳ #^.D72@o((WP9AIZY0) 폯޲&mӵٞsxē y`ꦮyb�ԻF.qFHa=##>0{kB eKgq<Uk9q7*5 F$1ד*&oWi䐦=&CS477ڲ A@�7tRMecpIt8ix,cYd aad0"1mE7o܃paI4.Vk?Q jeFCfKɽ9u8Rh*Ev.<~Ṷa;D=˖ Gij궆fَd}f˚R.zYE֣5L&k斤 1U()H}VV7hN!, =>tt8}ӎ0<U:h1ͤ=IBϺZ/}z,̛NHNRX5"p0*i௏EM T]WYG0O!hGRn:=UihwE7 b 0[2ХD̫ZaG+fJ}A֛GDvēƑO}iG+No?q~WY֚z (?zPحeBfvhT7^`_NݷGW$Ɓfk3u|qrzr[|tI?" :Rif< 2DtTNV( a[Rt ?o`le؎-e0T]Jp/P $|g2֠yo*UR4'e�|pҁ?2\h0PyX 0ٚ19Eiv72ddF4X-W*CJb>/riV,s:OU8< ̕%[27"1fqj8oѕC6MQG NF4IR~ kEe:ɪZ$bQGn��va]5e-SRM�瘎 S=o.FFeYr)B(P}lIa?/(zZ^Kdd4~(]V+ (Z,SLȌp81Ûb^$t:u nxMyfQXV6g䘹(sE:%>f-^ M@b{BfnJ@g <¤r�WMK3r�>P7Phסd$EYS8Q:< +0e�߆XnA7G�W}\}Ӯ>Q8xʪ8>8?VPTšI\v9HUf񒤎sRi%Gf݅;y|]."N6AYn֛*VD!#0IP6īFe% M6Ͷغɷ˲«-<;]= 3S4 ̭ %H P<\΁]aS-"$2v9e4&~E.Xʈ^ K},NJ(7bZoȁOXcPD5 AC 1<ެV@V. d4@T_`[7 ` 0O&`V }[EQQmvsD<I I4u"7QgKҬ r]SnW9xQo%BП:R-7^UXJx&Pm}Z�Fvx\.+`{a%-YN!d=*C'XKL7X EE5FsGk`exB"t ׻szMȱ(U(Qktl9iucJ,d#NݮCx{[$F0kT}�D ;(G2܀6l?NRG͖䊬N oT |'cmU8�7K^ V\(k_)!6e ?NDx3HST 'Y_1t7s <tx<MF! Q #4ƪntD#T.PQ׊q*;XnCri2 7F%wm dt�þz(/`y@B'Rfӱ(yY9 Jjk>xd7-I]+6eQB@b/ <զZ+D<@c׉ 3-dtvsZ2wO__1DK:0SfIdtc$Y bt,+E{]ڇZ2n]}-Ot^Z Kٺ. ~=mkƋr[ ӟ{Z);U-k, UYlj.\X C.(8 E5:>SC'67'm*XFW;S^ aQoPsz{"de{j AJYSy)~S^*< KiLڈ.W+H&7~9`-]Ʒ;t=^U:X2MFUi‹jTs',2IlCqD]?䛟1Iuljm�.CdW_9S]uƂ}7[2`N,=͒^VC1s9dC/ ԛ_vgx8ǹz_&!AM\~8YLfܣϵUDVu'\-}-7uAA@ t`W7CWwh63x=%N\ . >1Wn w[1rU𲤻@vpEp̮e0ZBs,i�g;F7u'y@u7m1``@ӉÜb&2· uUV@&' / |CܴrWKm24; '%qbce<@U%|<g"=X.hspM+Hc\{u9A"w5LY¤w mh G a;B0;6EC6_ȵ#B@x c 8 fq:çlv8L'H>)셴hSն}/'')~aLcJQǁ )JZ+:fz9g*޽ؾq"/@?X0*�kێ$Q-E �BbDȞ"eᩲ\әH'pyE`h7#9Ewdִ.tǍc;s5 k6'A#̬;ӓ]$e|/% < ʋZ_}gs}FЎehxƘ{,pbP'?@ %lo{*qI1ІI5:0^@T|s|z 'QӬ`"k#TśJyh"**qхiꊨβi*ȋ=;z+^b!Qh;LBA&\2|N`&y G2OvRMJLjJTƣ- ѹ1Xoldu׳K<]Q<L4,/@2qH޿|a$i/-ѩ*_]7u:mxX4sكNgj!sׯSބ ^>f2i TfdC~\QLO)`T>G%1<'":M4LnW^hSbG^&MYͥFr4ͩ5ebq/^�f4Ԇm_|x3,D�4 U!dČ߿yheQ*NE/XYWFDkHSf_<{bk_]Ox*PAY=xM#Ta" /1/ (p[�  , r7 y|O$,aT ,/{է_0M@0jEmhilX%$vvlz"ޱa4wV^j],Hx{tW( +I;}t~y]|+zc XVԗɯ3z}5vaKn0:=y/{EV4 黏]ueP8_e [6�<cΞ=gy- XFhf*.B@[yo//.yQѤkRٛ7<ݺ3^qjC~9%hR�mcϞ!LMC"֔bUSB2٪H_|ŋO Of,ػKFT|ޔ� @ejrٳokT$m7jj7( {۽\3$Ґrc;?|H,fϫLl8zg#RWd݈X&]荩Y'�ɚ&OOOZ@|zw 2 ˣӳ+(][Sƶj'ϲZohz^nwz0~2/3d՟d{Ms|#O[Ѡ?fE#YM򞪟;zSM]qZRRY~n6uY4iΎ/t6j B1LYũn96wWMU^DI`^TJ|ۺU^4r=:}Jf#'^~EƓCB:c.c_0  ?3WT(?hUDn:v"mW̱lɺ+"{؁o>dpڦeP 4k̩~ 1 7=}ۢ[Zwx!f(m#xR:ulǒ'OdO=ae D 2Muf r])d 6{( >|F<GF`:9^&<1f ` +2O{^5eF,Vs4W0ݻ:TDk*Ԩ^*ݶ/$ m:엑:Orfr5o. ڏq]t (jYnvMa0|=UA6Zў좤M"t<gP1z:yMs͎nSM8 .mbWT4Xg<,򹹇CmŶۚNbVJn/TV }2)kn#ct0DBux0㨸G k~k:9>Ȍ~ǹpb꫟&Mf3 '�N3rm@@&@v&GHSo￐[+-QM--i')(aƬ744G0"p0wkWn.Ȳ0t39X$o^u9Ϣ ^ ҩ“,ʼnP{NUM~84W0\bϷK<:[8atM3<"Ko-wĥm?~t 1y`k"lqoNwy*<(p)FVP pהw*2T?Ik JjiR9QEw'ۑA78"Im&.74M6uƐFM̆NVl@&R 0|x6DD5 >F}!Kܔ^?' hjG5ÕOMhZqIyvK55Umu%йA '@W5PFD= cK! ?L�S :ر4tjr\R-ծ^a%eTFx0L٠3}G4JMmaDy0rK~{h1H{/b:Qp  ĔӐZXf:_2pN}wOvWxUx?2!K�Ő /&0#XE Fî姏m',ݕp `P|^+eτr~4e -z)ljSZpF):s:*J}\Vl2:B@dn>:Ƃ4ovwtYM;,Ctp>2x8f%#w;TjX|K 5Qxë Yɢ^r)&K1_wuj+M۹Ix-3vw;7t/~ݕ@<:5䦃DR,:2MNjn ,a(?? |]cl ;sj՞mvkXaIgw~ئFd5NUhol/q6njtZ/T6Onu=L J&(3IVU* Bbս;2 U4lI@?^ǜlf<:T]C~mW^EB8�wB??>iQǁ$)կ68s�M�]8݂w9BhOG}˟|,(c>q ٿ)PG)#gɚf@T·Asy|ݟ "ߦ'Xim }Z8AM|:pF@"El)Jck0_c^ $-4__-䉀 $,eܪKrErѝՂn.@ӳLv148 ?I-΀h2?FܑO" 1!]݀UҽVjIM-.+]Hm<(1%tUQUr@LF`y*dm kbw_FUV�Ҵ1b3@To׫E-M-|!v>=ΖDn&8<O|E"% .dU@r[)VM&|WGv ۟SvI4 $}d?j$XT{|&kA}y/6~yp5RI\i$*.]hv2vj(R�Qζ=wTd�fBScr^ֈx w݆ ϲ<집XA'CoCSAl/p܇Җ:Ӓf:)rh矿zL{Q>>/˦8^AI=j/ηK4I/o(bfĠvpU/Ƞ|5ۖd@KYn@f㛩lI_]5-: {:T{1k嶤RIUf-Uj Fwtt̍nOO~v c4|.&] 6U=]ڷ~Մ0 F+t ؊͝',ǘ dԾ@ U-"gf3O7<M~f;z[UZd4 YQE7svˢvf ;yI柰!?Pî޲nNaßz8zd+uyZn`4aHh5cYAQP)ڦ:V%"E•d<n_~^M#]7T𯎦BZǡkQ}T�F":�CD/R]iL+e0`" 蛢Ο-+V<^n)F 7Ox�*{5sOt7[׹EBP4KE$*cOc0gbfxUj `ߥ>!D*|fP[F0iN#NIyLuNc?y*4U *0i*+?ǃӮc?Əc?Əc?Əc?Əc?Əc?Əc?Əh14ȵyJ:1[I8XkO&˰dqDHV8ͳ^c2?е]`rf1a=8lQIIQ'|{ッj(hݷܹh�tTVdĉsb{4ՠDEXEd܍}SjV淨?Xjh!8nXUmH" X7I=q$qD\&V%f((XLaǑ|6yfHq"U2VIxLdEE5$#n &Wt2,ni4!>2<RaMYI JӀx4NMӛ5E JTD[aƆc ƀlbN:w-`Izݐ7d6O) YmC)D_5T C7Zc%jDYMj~t1 AS*.`zIѡ 5MS'_ NK!WRXuMHRR,xM`yomN.g0-f}mw]Ou-Uiqb 6ƶkbO*L/ ϕ/08qGa74e$o/e9#r%x(Lӕ"[a$M"V_j,ylv]haXt% P(vё3Bi[[nV<YAef24nf/@T8 7-N׶X2zX"=f6GZf!1,dzņ6P 27/Px O umdp�o<YŶ` Ի+5L=...'J s,X ϖD U$y|nI�9ge uԢ/BsyͺIhu~4�"90ńsBuu;b9$`d $ZP7X;`[l:Nkʼ6}AoNY/jPspW+ZWNwVoQo_zԔHN|9qRd"K[wM]\;4)wB!=#Aʠĸ\"L)8 '-f4l Ҳ/ǫ˞ 64<B +i/-6ackRu"j`ːE;O\YБQ֣i#� VV5Yjd5xn[’j{s1'%ô*W~N*~/=mO"[w}rq줨3ezȍ` vVs`|Kh3/cd J:Lx%n{"oҢnX@'i)GuˏvL:4 }0mhc%|47úN-Yؑ9ɋƒY<);IĖ$ TCî΢8-wR{E 9H0f_&Qf;t%ӂM�2RTwg7aEו%%ZuFitߣȵ<PYX(A::G~V#0Ee0 ջV(apm)< |G$u |Nl2U '<4DHwx݊M83.Bиt>!z%yQՂQm/͜Uͭ][q\P2Ǩa7I pYxY r<#W1AA7|՜SUB:,2*&}XMQ6m<)X~_#&GHݍ54&^]@:?-K okFsG& Vq?i12 xPU݊ȖZCHWy*BEց-$/(x|_\^ xQ"+MꀸQ]G}&e+]y=-9Fi7%F!aCH$.Pl:ǫ%ONNOnOO'y @eYN}=UA -"XwaKlFuS�r~u9,^x6qRw'8fuU7%eQMAƩ*m84(8u]Òl^NSt]2$E fQ* |4'xUص5y + R؆mdH}C%Ɋ<MGk!ѻkVwBN2<CT8.Ge1!!+B7۾EXВW$m:OgkJuՋgob0 8 !YN@Bp{@W92=hcYN2¦EE#.Qx!)NؒT稲Ho5 o/ޟ_<A1tMeIL x(L4>weAQ$>[(U+B MrFKxd|Kb&Ib=yO}KYXF􍴢ȋz<�qkWΊ,ˋ]PN@ƴR6ŘX\/'d4PGBB-v蒄y�)R'(>כU7  F""aٖB 6< E$cɿ˓ߞ;Nפl&7nR ]w[$P;}7+4U^7iM05KZ˨T!˳br?}qzv1\yqN@xh{(^0i ā~$aiv Og.:yb18;=??;yr|j&h89:xWBp퇻.C9ȱgB^L 4X*IĂS�r:DzMON')0j13 XShd=>l|;co*ϲ<~KZH>-Baw f;uɛk55k^W8!)"1] % 1ÇD+miHִ1 ? l{UzH6Md2j!Ubh1Mݴ v`AVs#μa�Bp{( Wjd->+trPfy-̆C2N$ntF(AيH/sADEH& չY.[nʳb%6EF!lSe|U+mS$@ĺp,Ò5lyB$@3pJBaVD}]H)Ʀk|5JjU=lăpgs[IbE!+ruBϯWj@r0,5==%!:hFn`Ywۻ '<Rkֽ<dچUGP�̀}$#(]Z ePAw.-Q1PeW+]zBj6,WsAw#Wyf3_рECd /k~ZNl=0} ŋfG5}袠J5x Fn%fq3_^=9/I$^514>%L1gDԹcbrsB�ln"~AxvX<7!A:wt Au ^FbÊi92~3be:dt$5 ^ >yPESqFW8"u͆A݌�V6M͈pui3YR)QwG4r{ L-A֣kJaNOHx�Ft+x:H\Zg_\+7=S3$z SԬ_t@ENg%g* aj2a�^;hG)Թ;m�(XrC2k1-}M6kEpI`3LJ8pj2diq9> lV,K )SJ1c�* PQ0518HeVdxu COPWmLVdht';qF֮da3ĂQd59[P.G. ,=;^Un9^ eܣd-J9B�e~FP'DL앻@rqn}Y*Ob.|ܜNX>Qbkyz)!BJ #f 7ڍ*$) 'IڀNq<vEhոѾ#<Mdo.F FLލiMqz2MGWxbQm*5/N9H{ ̵P+ECe+n~DY]%B QBP)D0v}WW)5rD~~gl8fr|т PKwgs*`qEP}d%kS7ٮoduM #HlO_1#4e.^<oK 1vfyE�5!ɪaVvF(n(a€K`x2 v |"%E)ti7Ni٬V$F/'7j9yxr}6\,9iP\o;w st/5:~+rmR s芼&is+)O_Y!I> $Lx\$~ C+ag;Q4ʽ@d Ug`h5eǍF@j:A!! !(Gɒ,O,⩆LEe>eKr>]^ J+m#0pkTpCL3g}n k~7Eרvd;h1<mSm"s(|1Z8Xע"'cf*/%E+lGjr73$iڎm}(*P^性PA8}7tMS`bLQWS^^ʒsF. 2)c)�*S 6S" *~L}7(';+4lAKojG`(^/NOf0,:Ypj)D,/q{Z]R$|]Ho,˨==9H N@.W!RGib qww/~1D,wS"!q0xci[,Mr#07#L8b0,auSrmhARKX(�sWa:A\rɰ wCߵyQg>$H"8H.i;Fs_NfWW㋗O_9Z14ځba_#n< R]z8 gV0�<\NjEil٦ex$8w_޾ߐIxٳǿ=-gPYٴ]#?mq# f( L!PYmyQqDjo9ZNEzcoޝ^^z_~y/}͆ AR2D~[k"8?+jq4&@ zT$p Pe80T"0lO<s1^ߞ|oW? Hl`Quى;|8>2!bJ%PUf]ߊ* P 5Dt [ A=P(r r~ukaն]t0}ۆȋS|` A\֐._bi(Ae-;t"4, NKJ Z60C.qcVgbC,xs<qY}nɌy:Xd)l>MǣɚE5ICDPTnY?{L^P(N9=0{MEHMOr. U&+m2qvE {% GA4>f&f5/\6>=-;TNXQn;댥U%DEڪ.ԓ'gWZUdl? !q7]<ᙠY9 էMZ5Phf$eXA (LU$Q-SO]QƌLd4̂׀i ٪aIތ|N"gDS0E(zC�Ĕ�r4(SjMqL| T+Ir 50MٳUU15>d:4,ӂR Ϟiձܤxm"w#3 !e *Pp8O~k*ե./'+p< p<|LvQjcוiQq�fk^[kd|7}8>b�ߺah” J n&_z'a.s>](1ɘՄq펀=`4vڜ؁$iUpɮXIĎ?Q;˪sSEC|GްQ(k`t(󫋳tm;"s<Ç2c"~{rPne{EDY9,A4)X㳳rM(/ ]?4(0u&7߽]Wi{z�P&]_C5jb6Wa�lREDžgÂ=ܫd!Fۭk\ӽW޼*Ax2ȃOOO 4C!L{v/a/ɪ'eWU |0R wǡ:ơ!NZib.N缪. ϶8_EqHȌ'S.K(KCQ9P<08(Z-iQu%X/[?2buWQ/4Պt?J#ׅMq:ab':8tŊV{%m)~cvhXzwݯ!m+q] cuHpCI�k%&xJ3`4,)bQې54mp `/u 8j#CmAe೛ 3 Qݡ-bHïp8pC|WfyfIU]W+ ޅq`4W$$8M@Qgwݮ^v�pDHStC#t|Ģ`Wx#EE >A|\V(eG)z8 ̊6@ X\ * <0xl>Z@ڴr E=WDksŊOZr_id;xG P')\ wqjəʓ+@cCo7 M7ju7]b` K`$>8&I@qiRe^{nwWY~^754Zmw®5#ɺzC~13daZÚgGh}UowOll'z0 xB&Q;yؼ+=4ݶz9[�IL[v%iV~h�jC wM}-a8Ihwh48u8 !05gJ|ܦjWD$FIClcHh!z_ׯ&ߖ{K�LdJR `s&f=KS0;rp6)!:j.CdB ϗu+vyH)PyW=l׏,ݵEì!2_CaqZU)#mXp5U,EY<&"EmfZ`sPL1QTao!Uu[c\4u 1/@[AdR=8Uא%Hl<dF?4j]EY5PŌfSVCrK P7-梂 mHkACH"0lc-;G6dBo"M("da`=|A6<�ӷRsRuT0 F*+i̊%*Cʮ z~͉j1l~;T1Ru95tEqv5DRr{(,̕Xm]Q,ײiEɇysrPS}@&w3GfG4Eb� (/�RQq{<Ԟ&c y#$2̤�}L~Wxa\0XFgĖfQvUd7K^0Ҧpw ˮ-|㳡y�XlS<Պ�HgO\ 4><۵c<_m(xyRA̰](lïwmS GN^p ҆ 坐GsB2(Ci"-jKliq*3Tᆩꡢ]BxJV,; <iAQ 8Y'3'/ւj-i�.o ø>/Vʅ0,޼_ g&y/A�vp<S /ȕh4*aKڇ^8{5 G"&jzq`~ьK-�y{2+ItSK#zf�I|`PϿ\ 2^[+t%`P e/||!V*;"j_>p /♓x`({DE#C<9_P"ajur@T .щ| h_7y] +ivT$E^qoЈ |]aZ`R=4[Taꈗ?tʪI84 pM7!Ed Ĥ$m)_=NJA `CjP v 2p~aȗ?|ۑ(D{B~MfwThYzٛ)[U(zÊm4@k *5;n 47U`` \=//x;`_@tA^reB�vkEnर-�+4E5!vͨA"2lCav[Xfg&OX:4C쐐XSTY`L͛i2r�<rW̎_<zU(Ċ~oS? qO&@e<'H|<�s`)6 &t`605Mj&B6[7jvǿ]iAr* n6܏<o1mpo4a:Bձ56kFF偭ɼHd0xM� !e vj菟/yyy. M۸_Xe貼xfڂ2/J9-E~sW *axRWR$vm(UwT84(=\ C+ѡ}׆;BT<n@"6vS .,qAzpCv1g%Abn; JzF7iE`&s`Ә%1,C$M57*6..̲ xt8KT+3f8z1;߾fE!Y5*"ސ_IME%f$VUaYzb:^аyDAR,}㑨P**PǓY- : TXW3NdIV rW.))� WU5JqC=gm)L/ hp*/[ů T5S*NP&-_Se^'�%xqn7a4MXݳkd<m+x9\~a!\PQXGOh.F]]/SwScD#Q޷X(q=81oǸ(?E xlzi@(s�< Ϟ{\" u<e ("wĎ&rhǛ5'}фgQoR1RP9#pg5[xER&صΣ_Eic f )PDQͻgO_,w#O:PefVN@<pbh3|g"/X2yxSaqKMVauv?ۂw(H"/Ϧ0Ӯg|D?z8UZɓ'nhZ[�~HSo^HI̐o_]l >oEPEI# !8_~u)0h Iڜz ƫŻ3`Y95 /5j3Rh阦ECigۮ@ Dn}??⡆SoL/7^y|<qIRfgs 2|_V5A:!æ wXrr?!KFq)�'plPm?8!ɪGC_d%xzB.l2a/~O?a:ހ6o<)H+ [6@d_!YМ^ʲ|+vHCL<y_y:3ZL r) .q%DE7a,-#}!aYѧO^dSc;4ji7cT]ԕ�jIq�l._NyJ/z N2*XxK#HpY>%Q[}~Jr1xy1,(GLfɋsJP VP=W0J<ύ"Y-ɚ]) /d?cHx$!(Ȅjzt9eE+kp8ԸYۮJ,oOf ͚YC Vxxmd[}9y<gkp<ϱn?AؼyH5Ų9ͫ}=U']}"07O NJA*y EWˋblb`^w>wuUZxHj@qwW`S_%__'^sŞv1$lzc�cucHnebs73j$ /:-Cbɫ^2pxp8HB"O.rÈ6|ǑߞqH,撓]ۦ^3p"kQ䮟^ F^w~ u<5O49ʻîJ=;!VRЖ`@ų=6* ]Ce  I3vsf/hCGnriQǻCWPn>Ѣne0 xk$|붇?tnuKɻ)vTΰo2vv[ {kNI5AfV~F#wx-i$e`'}ow_gP#=1U�ݶNM5ٹ}Ywѷ6umuu�ƃ%w?Oa??u݇18*r�I;daxm[=SaXXnq ƻ8Co' kbi>ag+vౡ h7n!ߒEf<ghj|w@q;4b|.w{ݮLpS{1Ű K+"7[|<-{vpgLx)`$Г%C9 . n-ہ8O|[c,ziI ԕ (7qcr Aq=ْ(8آ|G:(6O.v`G<bܫOLMFA=׵mNj+Ƀ޺Tl|zf?(S�O_3+"0#ø1~f(!�5jNǾγ,s۶ݨz?JrD$2A VRo?{ǧ>ak]X{| #iȻ$p{Ď*pol$2ݐo,E@1؂VN>q7؛Px5ëUqy~Nq}$ӫ5ށ� 0<B1 )v͇(cGe/*YΚ"l{ px$zā$+jNPbXӟ0M>A) U"+C%PTb'p3ɁU7 n` ͛jqK >rTpF#^EyBS8F7۱V$ lUAsq76fy}~<,l!x鯡Sv P+x\Ncլ Fq,gѰ17JS@')rvd !Ϊn_mc H^N&U U�KE=x!44#LY+19?yEHH[e"x'0 c?}ck2Kƣb#<�R$4+f FE!pC\M&s( !C /ӌ.= ,Edֳ!5͜UlwH /rw7??0SAfLf b#i|w'L4ލƧC@ r5xWr~z@dyxdd{m]N)^R_n}_h.uX=8p pw!*ECWT+~x2#5R) `7xp4$M0 !P]a�arwE u&Ob-)"7y\-kň >t2XkuAm몞DİZ.[lY~t5_o.oV$'G{d_Iw*/0TcjȈy]0_aqFtߗI&G5]W4T�@vfOǮZ 1^,PA]G,GwܵxQ!sHNqabR',"}paMo-s)37 _]i`#^V4P#U߷k[aIӡDxꮊ}o}4]=&<*R(iF;hhS/ XLLWAlFPp#p>˭EDۗ>\,j7P xI CX3] WaEA 0;Z_<xbx>h-=JS>|8@a@Q<Y+S iıTHe~Ox,=]'g9$(Ț*MU00l. +7$btePK,ryi5+5r7K*>"$+im=LU<Oh-)Aewx.ӫɚS5UdiNB뻊Ц6IGnoMDF8{h)~P!BWyPlt9Z x �]7H;{ut\&h1]=RQ,+5l16a\k,x@x"g+~L]3Z6mԢ]ة~$Q!񾨬<T% kwCt3A$\SdUp&#ҧ`diZnd./;sSYCWfv\%0w6IģKi\;$0>rJ7]b9` ;ܡW^ytvBlٗ-t_!)n W»vKL){֚R;y'䟿?nma]jH2k[${Zls9X+,uG�UYʎh<#ը5mõk QY,a K Z1ĚC34YQqb�5n/H"?K04AJNR灡maYKV(p?sXPƩ#4qu� ߌ xʆL/Wр +k(t&'cFJ+Vޙo,_o>׼UԻ~1~1~1~1~1~1~1rOk?AʎqqF*]lIWtUXAE?t4jAlC'1~aT#$ϒnqk…eYX8ޘCaG)oƒ)ʱ8/%p!FHm$"+jq ä2 <An,18 M63 YB>"r1]?zdEQm tn "%Y@gYYD4NGrOƏ7UY]ئWmWāh]Y,TdŠe-2;.G|v3<, }TNm Ȫ~ۤ?IgJ4a!f9^0 /G"|zt݌7sڊ<Uj $/~RCymXx&/AhvҔiYl:  AovMSg֒nǡ%6$*m[%Ou.{~^+0gתD%8=}z6byqzQշvZYm9$A \mr:gY5J z y= 0 *Ia)cY !st^-/Nѭ$+I,stհ!dljx/zB:&=@&3-۵lq>0 oPh-<]Ru]Dn4ϮQEw}Y/湯sˋ weS؊e]:RYliyg %~s3^V <݊Mt4TrZ^]I+Jؐȱ}W5ҽ�ҪN)AdSRurl;ћ3TX5LBKwWs5H-奶p RlQ3-4 "CuݾJ &iڶ]zqvvuvvஸmEKQh{ImE>2gkAiE`g"Ay*by0 x֩oNCl LN$rF^.G.=[A7_"r-;:i*M/CZ�8]AR$h^ \SmUDN߷=%,F1 |9r @a$7Ll[ .I qA\nsm;3TEm ׮րJsO9b%�׀l )}nud55)ĊҒI=�K`{>@n >c!P%/.D(\ D.4YR&0C( )ݒWoV~Zס*JJѷCEIb뇷4A>V)l$BڪS@DuY2AṺh]zQlQiɐ`vfy,+Ȋ< >rG%Ymo 2cY'L ձEӾ;. |֦UC=رK\;vpFI,&D7+BԿC&WWoOΧKGrE;"Im?\DZ˺c6@]e`]Fbe&a-,eM j@s=^KŻ(RH7% qayc=hQE&ɭZUPup '"q9s`&~{^m$;hyJb+ʃ^Z- (2WwY5m;AF*3YGL.FsLƫ͛ņW4UjP< ~H:kfk AqCSjσqm YMl6P^]^||JĜ6]jlBۻ~0z[z9%EYUiY#(T6T+_L�j>VDvqyrv}=AO"1gI-U}e?\X/&0єfٶmx{\Z@ �ut9{7Z`]q)x~5`wbv#]u� W`lYyi Η'و2Ӭ.CWb /)[$u�Z_ͩ|!ޮ8,D-@׬};$vDfz5ߞ=9Ż}0wǻG_l%TbHwuq,C]᛺U춻”xzCBGBtAP?/?QJw\U0)E!X%޿%"ϳ<&ݶ 4ՃDK5uՎ.VEn5o?=?~ Xa Ma$mgF@P$#iME{ R(� `XI#3ݳ˿/ﯗ?^�LKӠںE.NZXAVI1+Gsvâաag؃0kAM~/_xo3eZ.DX \k0 a9Dµk&#nw: .u `UݯdW˫7o_g/ߜ-6ѻ MN@%q]7v }@Ԧ75۬^$šd^+rYlk\Ys- Y޼xIk]SsQs0IX/-t%V�./ymo4Y` QEb�Lq]6%KHwr:^'�2KnFA l#kFM 5ih4dvK:|=Kԉ* 4{17Tf~(QSBbF -l"YjF wӶFr@ ڷR`\e^dF9ɰRRv) *#Gpnk=}zy  ӌ8qnhɖDΖUXzsJFGܬ݂g7U>ÊA@3qm;"E$oNH(a bY23^#atBfZAN*~�k[pO,, F9AxVR 'E޷MGþff3VD*=Z@JDU8Pj(F �4tqFs=B0*HW_7K(pƉ J۱.3єS 5B893}7l>z4 SDPJ*v Sel|hHBZY U{mܙ<pA_$q=p6/Ǹtss|z}uyrr6^]s&\l=,AD|fd=B-a#6Ee$=!PtȻ fA x@a" QlWB\f)ꊰ:8srh` /d> >lM,q 2xgHu<$ Y:Fݷ0J^!xxBCI0K3=[yċӍyUeIV/q_* _Hp!}w\G~ڒ(f6oߜsv`=?=J2<c[>Tl|5'KpAhzM(!xQR 8?=|w`sKMQ- -NI WEBXp<yE>(Ȓ߅͊R|8YvVS"-qW981O_ (  `Bw|2xR̰YǺLO˞,wz pؕ2jj4,9^^&rrN4'AԂ7JUՂfw..%13=%pZL.NG/Ah*29͑@̮aȊ[#̓jq5+FҌocHp:u�Q ;?+n>L+.4C^,x88%S(` k6T"c]i�WN�ZJ6qN +UC*JvC \yӥ/$hnhs'+SE갌"KV`M"$$(w̔%/�;N �^2@1+%[wMS�gSNR0Ά+@UӃxp GK20:w^s@""KRDU $ߒYAP85rыllޖ"f GD! (%LOˣJT ?CC3n0Oi~ZĶ ϲ1lGwh}-6g`pyzb5< ' ,I\~ ?~sO8Y1,|IpF )Fq=@E=DT;0ٶen#HXxj</z5PŇ?�hZFOr̭h9ޑ! Jos_=`mlhHQnw}^fTZpB4l+!A, pxq5Ã& ()0͛'6YZo0ADᢪjDX_zR<9|G[5msr><t>^-I)Уo$?[% ' IL 1 lm{Te mB (12\Ru;t3�8z^-u4=sb9/&oޭdRxȁ,UW(x=`d>3z�a-%.宊�5^VМ:z93#u캶 y-Hv5\ 4%>P|`,Aho4rE fB^ Lt貤 ?n_Դq3em$!spӶm*Pج ǃ羅/xqv@ K;dW`oh~_oYtn`-!^�:J!-_ln`}fк~%AC4"PbO.ǣ)$݇ϟ)02q( L7&2Ax_Kh6#e헻^f\9PP,OLG/YX#!P%sj0|~Ż|N!ͱ- B m3Cͯwx3 z2r%kk[_Uuܠf4H o g/(,i6st~œߞ?y/ߝ"lEUq`Wݾh׏MI,+1xP͌`Qn}Bt{dK0gMSU:OȄwۯO>?Ka!gPW!#f �oɻ{F{~tPTpWwH8d-xBێi<H&x\֓ɫOA/HoO>�mmq@SÛ9$fx`rX$+9ͮ z+)9lAKR, /|7/>{/IN0i6xm� Yj{nڵ#[v7,ho|@h^랝ߑh׻Mgϐ�$jXW7÷^Lg>~~!RQ%rk"ͦC.!}繯!Iq' t8 UTPC <G?HM?>}uF�"?a ˖Ixf!bMZ�!&)C2S2DJȰ]]渃_K0`4u=𻁫Ϗӱ*ܳ-޿xy`*0X5 G:cm޺2K,!VhPb7_}" f{;.D,M UX=vDbi`-?Љ~' 2NͦzS>iCt̓0m7\H඿@ovyG/E\U?|(%a`G9 &ea \%2 ķ4M9<eQEDKZWpICz(w{6zM%>QЄY Ύ>xqeWsI51q ^;<>ĊQLݴ lEEBע7JM\Ms]kV}5[nJwvkMH"uf&0qN`:_ }:EY}dv۫㣳˕ UQWJG`o7`S!UU&i~К鷠iHtwh`(!ݮ1Y1p*"ѐjH0縎HuЏ0!dfFȸ<-U+apV"Q^f_�ZH> X@+i)G]EiiJ,7BmMz8\iֱk` tȴ %_BNhv犻E{&s=PǨXU,pX<yaK!L6<đ<ngyF8 t<2xOB؉9uW56_\w`{#'LmmWiYBa6=P� GC0 {zHU7NkuIZjh B 1)i`R,OYg<_caGS +Hd6mPϣ5M?NSm q8ǰEݓwHDQ^YD\SuMu2>ob5A" rB$W&qN &VԾi tQ!9WQ7;$GlLRz�z�0zEKW'{VmR&rJEim__Ⲫ3UeWղ4 t,Ob0)^C"_uYusok1%�wȩ*"C jlZw9٪zc iaV9U >R�Eidaʱ byȘYO6]4�:Bia5]r_MvL sĜTÓ&ow ,(vůb :ϲ,+gO0/t2"uSci\3 AdҮsm)o,mʱU=@ϳBUw`jp4q<x3Vqk!\aSVi7U pͺuDPVHfiݰ0e9 J4+�ji@z[(W&(4IJ@y1U, `m&,Qׅ* 7Js44ߔ$jf[faW. ahujXe Q9Lr2c$'8Ӡtؘ`c0zH6zA{ \!@&OC�0VhVu/D,0KmHM־]SAZg(r7 "t܈YLGaUTI (M]u:$bl`Gx=mFU |0;= Pdvm v5"FF[BOnű+N$(.d,V1�1^z=߻>ua'~̔fmGXFMbGiM- �,@5Cf�4" [,v'Q)B]X͖`he:Min95fd"KXF-?w Rgeb0|m8]H37g^ F\"^LHLX+AŪMoڪ$У)zv#:A`ͺgm-7LM}< .263_�x t:4EzØA |iʈз PbwA{C8#2xIm!Xtv(t $ ȗ('F}HFchF`WTU3W S i\n gc *XfxzQS-jO_.�֞]7z܆Q3(nmŶ.>Sݺ3o\g9j:P"9{5<;<Q,gS-jxRXfQ$ө -yY#$qɲ ^Pz۲(QYge|O3ZБ 6 4v<:yw4%7d۶X\"b n~ _\ =8} 3x8-<bP%D#Nb]XAԘ~ dO�gdz_{ ^qsVh 3s˯l'e Ɯ(x2-k٘XNg Wb%EhߑIhxd}De)cO/FSoWmƽh LR_pՓ4eU`�8.OAA̢ 4n44>jK*G&xi0!=@4izN1RII)@4S~}| qw̽zb޺9c]O/ymiIĈVL迋PSJ�E|kr%!%6 ex# COeYvۍb<3�|ˈ_x%m#Mϑ<>W<)x‹h-̀'2|tD0@,LdėO~3g{&19xȶ�%vxO \ }c^6'߁gJC߂40rY^$zqLnhY6b<YSy^j' �ќ(1_|\ rPg"P`,0"slہ_MI kXg ~&q.}Xzɉh �ņƍ7%ȋxK.HSpa̱Yu5qv8桡X1ki( AfRIxMu;NX!LiaOaɆ `1Syvś3Fq:6տBE:6XoK[&^=}ur>E)ԕA�&vז Ϸt,pn<ËJvzQex|olc3:Uᒓ<:-q׶0on=OqA˷/G`U/.v),T-.U6h3;óͫt@wӲ:֮"Gd,Ğ)O``^M0Pb=@ i*ER*v,It|RL$8+OO·sZS?V)+>̇H˥d,4(qm&cX:E2!_FxAhKc*f$AZՑQKz糋s,n`Iw3jee)h*Alx/ <אxNPM<*p =�Yl[Y[˰$Z0yhp~:{\H(%=Eڐu24yG5 ga;]|>5aXI@ `>UЁa9YWyAB.քgǣdg.fGoH%╙aIH,�e ;�^P�K^DQ6UMtx`C E&>dyof+N"L_c)0&@H`VgB7Ia�t�?tMy8UF/-X3�쳓<_lUeex9&}8ur@,6n09HBt1AhLaIԏs6c*^'(Ifh pEJ dY[}ŋO+Q_RC%<Qhpq⊃:ÆyymtHcy (3]/l2'jU0G>'O>,1 _b#]8CLDau;*H/UB?H2<j6 ndf41դ4XDusd~yg>h +U@KbɽM՛hIP!^OHZayPCk [% 2<y;Ä`3A�STbI9'ڌU>}v8DuDza뮬"l (Pr|fŐ`- ޟxnc6#8N*��8ZJ2MtGGB`C×zͦ54x/<y3@"I KJҒN0L|4MA 4uي<,&\S%qUP1L]>oO~{r>T7: \ OC3+ر[2ӼXfu ^hm@a Ȝnvb DUW?:@5/KV3柏(AL@u$3NN"MCN-T�iTǒgy���Z%7SA .lvT_i"[1<pyBp*�0f 4Xh8||}DKV7wA*qPX;ʛe%>{1h+`Yg1 Ċ)z|mS$60Ϗ&%_\Ki>nӤ`0J v]0 m1PoW N>Rt+.a! 3.]4U`fv+̶4kڸI &9pfmЕt=eM$ Dل �$Xo=P?BQDe[z:фw7ۦZi<{^hrG6<ΗKbXR]WkZ#4 #- -|vRbQl1/o_ɰ2joۺŒ$\_>d84 K1]YcyI lez u'޽0,Q6}nmdnE` 8k*L{6Kv^b<,{,c. Kb%qXfۭ,}LZvq 虶1m: !-A/ 2k Iao4]/v}na̲ĜE -lfTlMvA1C$fc<q\ W]U%˳S K-vTy�YiTukP""L˗/߭?*֍ߛ30 ka_ƌF̑ܣ ʳF m% +w&%bbخE&@Vу="mx>?0(ͮ2S9+%b 8nG{Eƙhb!:FUb㦭Phz{/5ʄ-h 9C4Y20`x/9F?(ʌՈws!sR6y_c_{%^u¾B9z<!qPS/Aqo>v9i_'iC]oy6`"b>bGӠ2E\M[ؘAI$bhfefӶ &F_|?:a6"j6QA#GS7w}j E5]ߵDMAĬ60|fl>~ }33k+!jzԠ9zuKhJlX劑54ww1lg jP(vUk,@_/Xfѣ`]4ZЂS _ǀ !;y1^Q7Dn֮@K|JJ+ ^n `jq¿<ͮ-b<4e;u'I9}|wߢ8ReV,* F/p.qA'|P%֟do> ȃ!q[XӼ[ .xݗH0\Ah"^֠U߁o H}b8`MWYD^{/x2=Mbz54C6k?_2<o3Gx웄ϰK]�A܉|57]Ɠx<&XgӜXgY̷Q'޿Ͱx"я)�T!$0·\ߗJ˷ÓO.Q-dU/ϵe,r MR}!uHO;%n9%xkoibm J g7G4+m�Z'_{PYZ+)$,St ^Kۦxfzv2<8ٴm2Mӊ�΢>[fxT/Pc&n$?+U {Io# 2\<"x;HH0dR^? U f:OfjC:$$w`q6OK8ClW%fy9#X7-|ȗ, l;?W5ʹ0 㟾"_p<ҨCdEDV{Fȧs0}۶ו4W/f` >νo y�QDSLr:8:Inxedïw p }`1@B|՛,M>~,i)G غ[%lSl~]}_M /mis}]oxbY}<t"ΆKVr〲n3_fEŏ/7փ@mimg`ؿFpH 5JQ)Ԩu% Ԝa/< ?B3uYzNOހlo۪l6ˊ}o 0 CHufzEK45?da,k8&1 I%c{l}q/:rI8q0ww@ �K`vъyI R$rӒ<g?wa뚸Yt4ZUt$f ^+ Fj_V #H Lӱڃ(+9jGl9 K7feJ1BRT70GDX<ꏔ7`AlG ]~(om,iVߖ�bJNEzER9, }ESoZ އ<-s&6"YaU-fSB@/AGleMA* !oCV:|5]fxke0JD"(4/x6öD4!;ET1߄h PrrT ] "#.JXƎMYX[Z. �_ICƐ|tzt2fmG_+bO%ejI G*Ɉ] 'iWX.pfE@l{>Y`J+@/.gg'ʺW6"J�1iIbɠNI^c LUGAfy樲Ld͍S<ĦߟcJnByYgy>!EpzK,dmx@ޅ64'-iXn<8dΊ>PS~M-2%ޫٔe} :N8$ةJ(Y-fŒYX=~,rhIW1Ks?s?s?s?s?s?s?`RSeQ50քadi`dׇ6/wRmS?9I*Hn{.2xIvu]2n`iHI�<lۤH|jHmpcƱģvbǍ 9 k|/>c'YVu:I?\˔ r0 u׶lڊ~0Ă"r-l eO8bl` 9Lf;JBYҋt:|H4ͫDQW!MQH=E0$/< ǔD jOFVAV-1my+w#yKSK-l^Yyܔea~9NGlf+|x^oas*ҷ&UI'HBgu1^ӳttq~1zyIal6ul^mey r٠U(4Da_`24sR1pp1i'I<Uve*eSͨ%.l ߬DFcp=W8BϤ|(N[lE^%??`< uNu㪩[=uza{`0 /YTءQU<DnP[%2UDz^uפI}T\}zquqrƅad8aZvf/ pma5%r]]Etc ܶH~`[xu|r~r21bCw]#?bXi"+z&2 jO.~ޮ"/kCUvĮʰNNFy` Kau]%6VTyp7,fr0E8 _nR''qlJs1Q0Khd{[QEFh!ǔb !}¦DV.N40xV>]n !GySFQ)ew:뺶)x*>#{wmn.(3߱dضIL?,*r r]R {R\0؜j"^N@#˳A>J 7ô(D8)nEhNIۖ!^aowE pR~pM/˒GTu^w'c~,8Jc2!IHlHn(V#ԮK-8Y8GQYVjGe-gK<K. Jɒa1gP+#]cCړ9T2~ xUձ!ˆUH/5Bа"/"Z0f0 TxDJuZu [\#W+2@=r}A6^hd:i7lnI[ 3jŚ<0C N8 0^6ʎwݶiY#A#!&ULVL]lSI2ߔjTpB0~-Av:$5@ v0#+_`K+6 DsUUZ2-*qr۾I%,  `vCZ{Tнlp|3 ĭY E`Wsk,d�1AE G` :M�LvG`|QtH-�>G"y 1?!�@ }_.gsvT{f{VЂXGM;݀)`8M]1bY4N[: a(b%ik_߶pRM?BVG|u9D=9U 9`U~�Rt ¼0*sk&7)~2 ֖KW'%[B"f]Lǃlg[0LWe`w1U02.wMbIsipD݃ϗt4$UbCz]&ڳU$'jM&ϱ(  AS$$.MݦU3,0Av ]|we^'HAV$~B+4EGEg1 kyEX7?xt ЗsN,Ҩ%v\okږ"r MTy_�bS=ExY+Nq 4x1 _ N.NOb<_�-6:ER0أpX+D]8?T/u=/VI3>ST7N#($GVH욱7 7+pt=c̠F/�s^Z羡H*gt4ۛϧ+Z$R%5W3c;YVLpM  +J4TeD{0kUMU?<:/~yɓ^?4/_F`ai~ibM) Is`5Sl-dҸ%O k<[]fn>8>9:<x//>].)m;�n-7Xsws5A6@*M4?fZ2,'v&]m+be` ޼xoo<}o (H ‚,@#'L ĵ;%<0S}5[ zf s5j�BuD*C|>9y/էNxrLe`n *Ķ]AXtKjEQ47hFRxE}TvlכP YH{b[N޿xW/bWW'R!)BS5Cfe2dl vH>A\/Hg%J�z#62 &M*H&­߿{t$+$g3vs[d% U~}w% fHb*UA,K-n۾bd O&]CxznD($ӰEqUW@}_]]j|}im^ JWϯ4$)Qw 絻9o�ytr`#<2<'Ddgʦs']a번�w m J(v ?2rav $#Hj9OXat6au [ 51b`pQ`?Zc"KB Dz=}VXv{NV2 -] o"/0bxvAʆjN?-SRa?u"Yu�f�&s-'+$0`4c``_3&5RVM)+VssFx!Ȓ(Y-֟&%ƝA*S0Iߺ+~݇{J,?[D 3m D",tmS}<X ߼;0n6Y v` zMuQ{2f2rMcFR!$0MRЍvs_pieq%GiZޖaSڳs4H{V 򅹑=,2HtxOק'gJcBX4VJ:@"Վ<?&j<CQ> oxV8 Rp9<&8qӇ/WS%F:tut>la3Jn!)2B Q6 8̧9\3(Wu1;oWHGX&Rsy( OޗadBVoF^�s4 9jEs% Sk˖[`![Wf^5@}2,x-H1Q` .`Q%,A&Ż^20t4 /3?/ bt<VZ) \#ye ႇ }UzCCѴ | ^D"sC$�]CxCMGlN{ݞ.#<SC o@2SŔELVYjv|z�sy*/./:g' > &1M-d(iFz\xկ*`Asa f-| xn<'%B2;>Alr>/fW#W4iX;p=fDp^ԩ?\Z䠝vM<3�XN#edؗt@lMx6ڗ8_} = Ύg"u?3]s<5Cj2c$+A�D}$17koYj2,�v45Z.�MMVB'|257qC97r2 .P�js^{W:qZ.;%oK_h0aaXQw\St>*J.-@Np|Ȉ@jy q|yӛF i%k(qD`J 8)'=^P t8F%md5p$ X6lx~ܣNiNLuzy|9BhWV�}n9ލa(Y;grL'*Pl4R ɒLOXfY߆G/:)sm>\Ǭ"A9^phf U[ Ub-k7VODZXEjcSy0lkd;u;@Lwξ|r>!݊m uGd\Wݷ3<\RT6Ǧ$Cfa X72FPD;8ɀB߻>98mG/O!YSWǐItFf38St5+\x1>l?lUd�ph5!L eU(:&mGX^_ 0>9_šw/i>4 <`8I9n dvI bWQz]CKAf6Mvp؉ �py/%Y Vw$jv/ńsuO)zgPL%2tn-{lv.J pD@�HQR.ݦɽ(o9BPh΢s>gŬ>_cR!�E7,nZA5`n\֩c>JC [$đ-7;R?lJ, uVAl^)NSvgi#<}SH!X^$/в |t(7Ҭ+x U .%ի�o{oU͘nwf"<R4( }? _z}|uvs% "/%VUf3W]v$2�1;HN 5(Wmoo "-+ʖhpљ6d`5(%`/?/ߞ 1'+Nm ˪s_zn"k8lБ #|g x;YFN `*S`İce]8PUz1O/yO?y?XAwk4e�4x ^()hI>8L 3daoCH3 ]WgCjST=J <{ BxcU?ɫjB"X\뛻51mKCTw`XeCLh^M0 )[zy!Gښ,?{勧O=B? W"䆶E)4άס҄]X@V*ߑC3'B"*^2)^#�nx:O?{/|勣9R%nm�h6l־DO&R!0e(y2g^C 42} mI9IEjB,_?إDH?*(Xbo�Q tlWxP*t4g T"1sz,E!W~!t _"b*"Q8@,$n.-v~{{`!zVġ _X ztrs__2cނe0 rBd^:ǺI�ԥyiH�*/_?\�_`>ӊnنi2'bZf<x66$<1\!Ri4vq}nUW͚pK׎Dq^a:;<<z h</o>s^mDvBl%«DȉH Z!O'V:@7'W[n]aRo :b܀;'5 N?x~8A,LT! Q@lχWs̓8Ȱ臎&`eں=܇Z eY n7eBNW$~Hʢ&vtzpytB-ct!)C]^&NbXo v,K1" Vfo+@  =3pTo*w޶u0',dRݫlM)1#$q6XpVܛ4r5ȮorD�dTz BD 7+#7L0ӆ2 ؍FyPS rgdxyE. $Ѓq9Ζe;GoDlG3 IqoUfnXZ!vT޷E32�wl4rlj>w,}OQ\,:Eè@`u*�/h| R `p?�`#?j Y-l!'됝Cf^eyi>O� W}Ds1c}rbժH�U ɜioHي0 L�{k[BS&!uߦm2қ4Ym�}+ؒ$D )kd�^5&ڄ`%�{{iP%@dʇaT  44OCl;pkF;2 $ 9ɋ4=4ZhV dұp .diHxm&+8,�u#MslEq#Dq>G^y&.k{\Bf-QAJgo'# 4%]*/17Z!wkU;aEly]W jHI GZW-V2Te%TdyJ؄&Qכe2Ȳ, is 4Ku:(,TN4ud $O0j06*@să2bs{LUFi&X-?TӚM7Ȳkb 5&M "ط4.4�vnr jY׫IZ"Tx\%XfhyD'S8݌0ēM)&a.$zJ*4y<P&x u* ssu)DŽ0rRŶ]d݂6dn>v"�l'Ewv`I4ŁIsVy "/rP07h8 dU&{9udHX2GMA[[0<9>Q;Y hMY )cG�Wc Q##;E0U^"nL Xɫ :^cYW)ﺸͨ4>:2,C6poC9 Ӧ -:v%@ط:,2kt6%<\+r΀!-֡J�Aj XIU} 2>e:IQ` 3 ;+$Nc"M]n& I}AACХx)Xr`top*) 1`ջs}p70lWWiwU3]ߴ�udq];5 x(F �õ_hAJv  �ݲ-b_.8Zn7;d}~z;<?Iۥ/`dzcV0\?m|۱#w 3j/Fv_DZArdRHM.$dnz~ YβHWW5U&+2;eyUӲcմDGڀۺq-Ȟ(WgKK<hw[DK4'4Iu[GهÃ@h?,L Xd=_`]ߟvh R:ih;<>t͊ZXu ((lL7]޶2ca� !*-֨2/O/D}ts9>|)10L3vz]J,ï6(\:y<,v7WX(+ S ,5E9.2yz̈F�?CJ*cu%  m7D/iw jX־7 D'?%W7O>m* WE�?.r�~D*~iA`Hg+1Îz AԌӼ V ؋Yn?7ȉ "Q@�Ტ$'ڡ` rlqҦ:7KF I:nZ�6 i9%X'Bh@�I1R�*1<٧bb7*xX2|+!<6K# l�^gBޥEdAҥ&X�b.PË-Htcb#Eb]|P/OSbzaNwV!^::`/L14Λ}qŒt Bُ4HdNTo. wz4އZNCt0"9FM|/C1M�{Ys�xz$G~¢SB#i;]V)/Vy %7]!, RX$YBv?yEp]k8K _m@; l|(|jTXCcfmOxY .bBYvg$N!q8{T�CN<+vǐK2xzn(ʀ@bc~UbY�(z`B1+=�a}?wڐGk铧&x: j#��Ug_1Ml$h<+iVPnUQӧDφ6أe_LH+Ir ڒ^e hSMun[)f~yzeѲn',]? M`.%De4DՅ-eY琻dxʃkJ\ PZoڶ)Y8(x:>u?xqblIdi?VU^x'"|,@Xb@\VeM4P ¿〢: jzJ߮pG1OusQb &Ȫxg;_Bm<TEU_(+ sjx I`BHT;<&r䪋ߟ@Fbpu"(2=5  ݑ>.ۉ�\gaS:,b}y/X)1mi. Nxo&tgӽ>SEi|<yA6KH#1/oĜ,t5ʜ>6e,tVLUUuCd' Sɾ5UxfveF/{C�S $S5Ž$a;Ȭ(�SSxW7CYfTuE >z v `.wc.TU^|R"q[4 f馁:伲j8B2#NhPXvwDbgD�{pEݻOo?_3P3bNX2~B t8" DOYVUn}UQo?C"/4AFJSZ=~V\8,D*-H v}^eO^x!X*;'h8bƑZF\I+/#0 Rÿ@\/sJ"Vi]|Lac?׍=eq#oxi̳ 6B"c, Zt\ te>4ox5�SvY<ϝ?{!+s f_x?E9T+K$9WgSNLˇ O<*2=p\<??xًwW-I~ *(- Z8%ҙ)vQIf8OvY74\/˪Xi 0Ϟ={s:q<Ɍc'} Ȋn> ]Tjl Qd#Μ�Ϸ C-w" V<L>/GXubD߄mς5-G"[Z~hax' j�lAc95:5"hZQF'У(F-찓U#FK[of)ia\A9D4H Fh k'&"p@S Te&<#Ǒ&".VU p�TM%1 >\IPR|8AofUN\Ė*]Y|z*9ֆAeA aq7 `isg΃y9R1Ń%Fa>8seSUe $M 3!`)\lL'p%9?bo| CGZ3+zqZU2{ѻC^Re;jnT؏M_}>2e3o ^̓ԥ*fYǚ@]?yXf%N4LEj[7u[W3^HM@( D:}srUzBU voHQb[B6;9pIK֞]8`t#c7$tYV^lgg׽1+YYv tIړ@bq9cX-iڧH3Y`Œqbcu5>,Rea<ft [&^-v}+4hG-77XH6#24oXݴy*1%~r~11(68ף-jUYTu:vHfJUV]aӺ]&GߎiW26K�ʬhVܔ*hi(#>e[B^((Tf5mXnثSn/IKrLKHVTan bͲȺMSidZ1 M2�G6 %/F[_ժ %e9˩NeGaYnn}Y-[q#1G#goq]o<-la[%HlTM67vy{^ƃ͇sU %,\W8M+i۴dFaiڔxk^QN%*-h+lGúƁ.F bQV~ܓORz{Oq ,cz&�,BSZmG`WMXJ7,^j[ BsB# 7ԾrxS'2,q^ ]}5+A[-B, xa ;;|sKd (ׯ%UUYx!:I%VbQ)?Ӱ_ämKuv1@v�FԬog햴`OAi2ǘ �>:h6[2vוAyQﶫ(s_|:gq6#Z)l_%*PfxM$Z.!K7{pxDW.}X{O6v]'A  m+7w\?H < uZGk 4^6]\"_?TPThԎ6tpbi86X b32oXwM-8SŮ+DeZwpKޖұ[9fԝtv 5>g~ai$-8og7;u# ApEGSwKvU 鷯(=1@;�#i蘀?{cA֤ +Qg¾*ޓ RvC Seo:Mڵ 7(ͦCe`<Z+%U fJ`} [^u &^G}g#~93E[98Q]u[kӌD;V?vs, dvL9rR1qֱc&Q\YZX*r+,t^;�8Uw4Ob/:4'T"U" ʵ)e!7 +$C{4 iG]HCvA֕xjt}uyչϧ `W_7D;q-԰�v.a>=-DfxU% NOސB#%Nѯo6DiYQ'ݫ΀pI6nn�f˽1xA<x;s£A Xe_آ~{K. 6El GgW{S5CDݐF}>ǽ`2N7Z8D oybF<4 7)cq7\h%mך1&$&5rs Tz9 ?EfNKY<�q AʑXzM'tXNplj.ͦ Mܴߛ(gJ8^ق~Ӓ9%v8G퍨dd< ̍7_oyg j+Y3K uՐTMfb�e}9Fgǧ *EK ݶJ<p�~ 6ce\B]Ʀ!^pl>]N(T<x;GWJJl!-W5 �|?[,SQ TBS|]�0 �g {s^2 IlooV~zq9CLg}-X%vt= [D|fC4V9"ϋ`X%!m\]_МKQ(Kd,'m3Sgә# Uy{. b)䶘!v'aKjW,�Sc=R_,^5tq&XГ]E u bGIhKwތ̏xX*l^4/^R7<j^d|&Nss±^lw}ՔanʖD[ /`vv܁@˦&Dv9JӽQ Ct(A|u`iX! sl۲TEhPQ/кR{{לm["|΀WrW; *�"zQ֐m xUY @2akw8WrMed*=\_\t_l<Ap& 6'`{* fՔ8U)BDSe#Hą*λ{{G]V&/e@ӐnWMUU py5cdڨɤ$b"a-4z4wg�-";�~J@8dKO`Ċ榵Q?qSuI@n ɂjYvc1?\XY5b p w.D;Щ&qcY�`eD9h9)kzklF05+g 6wmsJ%w x*Ql<ٍso11+i 3Np"?_ ʜuj IQiKΌMq�Ih"|” �뾋2D0>%@Ss]q^#Ftv\g)Y<|"I $U:<X'/KcT5 ?N:dEO#F[i~_~_~_~_~_~_~_E 2I$Lר Ȣ,qO,ޙ?qqNhs7(QN4Ki߱ý)ˊJzkl1Ң2 )UbHŏF{*kVmloض"=)@Wf3<%a䩜FY ,FUu{ʄdLV0#Ňӽgi l!i۪fE+ :c1ޞXtU3ì}!XwTuIU<Oа8fɰ߹ܣ uJ,Qcњc~(SJӺN,وTx)oܿ/0)$oVdgulIB-Lq7m–EǡcW'/=>;w.NLKgV%.x;mM/{ZCI<I@L7IcG^MXY\w./N6lt-Ox9pf-$rBQs$"4e=7]E8 ?44Ns~~>2mSϨʺ%3e>^S?\țeUʫnR /RV 2I'i]\#sL$FA.0ȟ]AMp Rn*@g'L0AN2am0俕0E^dI媩ꦮ f1n B!NyaMO򺉽hht 7p6)Vqő'3nhχcP R9~ڦ\YezYz&|5Qt1볙H]%YufYFz&jGi` w |?"24di_$XdU|"lLR A/c l3PH'p8[Gr{@K0H{OOcհ!Z"3]U|,{iۜ�p)\+ZA\E8:/X9‘SC[s$~:dqbNUeGUӒ!iŕ)l V'!6 7fSže)EngL?klE"D::&o\sNE (OJlh^E. kKF'tm q$jāH^tǜ$ko)wO%'/%3/$pdȑ}]"p6&ׂx[dfHZ/PO +*T3\eA찢L͕\"=Rc:V1fU8 0g9w< )*,f0ª<TEagX@Fxcp"aaolw!NGdkDq,d"k^\X3QU:ȶ[<׉�#)47k N,ԷB\8d Ʒ nšV9sV"#V i 4k.Ei٬VUkYM*@tM�}9֣�:'q*EҢ׀mdo0i] \Mvf6mSe钌&%Rӭ77ۛ5#C8GqB{";sX_523YAGxh%&B"SPY!5VC`|\ $�s~\A0Tf0}K [&E/Gw5Vw1M+[.;; i_A^ouNG54]xQ'LlHAX �Xyhrˆ }=\e3J%4J�N\G]FI5ʅ_` |s.w+y,7 *ǃQ_AтW-7]mk,у1-cEYqd/'ggenP mp91닋.ۖxucM7H2qpr0-޶t~` O=IF;f+-2syU- 8^~ew0vǂXE<%bl2 ʮ3[%tQNJ6dã d#J@Axp`t{3/f nPqMyj<#Y^l 8\dmZ-SG'3H<7Tqd~uxr=\EY8i&;2Yt@F/^^<X }IY6}"-31%Hv0p՗w/] ;H5duh<\YWQ"Mq">'1kV8gM:2=˰);q/ǿ=w_YNUIjcN-@jb0G Q 4/%fY�,,8Xij1O_?y'?_ 1CZo n[8s( luoؽ,hNxAV8F ޗ&xͲ)]t߽_~'>w,3OUfH!3hBӰ¶$fxg w[m"*Ѕq!jQ42f,ɓ7ig>p9YT-5 1U"4M?A2XAE:`.*AV09Pv9xF2#n2]RaVx"-sx 8c$zSEap3班q39 f7!cgPWExOw݇D zxt<M?.6uM$YR-*n=2װ 1rYoi9Hkzi& /тSOӓ!�9HT%#C*nvhAӖ7 7;! t7DZ}THp +5`<O\M]\^^NsN-@0-RC*ί[2sD�Hy3"K ˱{؂fy4Vz:8AWyb8AA8\]_L^ӧWjGWN][Y,@-0OqX1*$pRzB ",UqanOi8Ɍ*rA[ EYv;ғ/s4K[<NP|kN HZoރ;nʙsNUxs9U$%y~>d{f-[M1��}U Py3 qe! ZQӦLI|0<߹oz,;Cyp|F^v\/S(6cɢNni'n qռC6T~Yٍ k9$"] \ɕXYuz:n|퇞?'ķ9NeЃE`$gqcBYZX#wײ Zȵ<Qn:0dո{7o>;#jaBUԷuVvL`Sm) @"E6icHf COg/Gpf,h̍W';['7Q=>vB '׫Ais|ȯDĚf> ?T=60% MCNd3Όc>- S ϭ9IEZtc $-4Cu/o;,L$8pX%Na:A^A7'i'+4A1)\?I$NDa5VƶgqӭDi^NwS"j^ZYH୾1NaE+ᇬi;M&,(ָ+B:)ZP6ar6ahd:Ȳs]Eda2})C.}CEa1SVh6DɗƓ9^Ō24;$gK7EeGxp %- Px(8c,dd0 &CgQuRJnS8I <sM I*lO{Ny"^풝kP09'%�m'hwmƱn8~>cd�l")]b]n2&vits% G9 4}|m~7e;k\& b>[LR3X5 mDõ"DI6c77.pIYbՎ H ^8w?>J(VׄY$l6&K%3rYC ; __3 LV<e̛.լ4yN�T ]#I"G掷./Gd:UcГ˺WN8t vIz#.3E ח-?8F)EaSND|٦YBRE"qP,1ؒӏ{''#E^^qOeT%JVM#&Ym4PSƼLUoiƷO4m˔cU´o�Bbw4"%?<!~"wT{}qpi/Xq B"P005 | lAML@q!ja>wf|1j~ڄIfIܰ u7-bS._mQhUWo.Dz~LHQ(ű2 4K<20&el[:K3<8knْ=O,fAc Iwv??<ttqHy.QVea)vdIM4)%tëZ' _vAY4AIer<O֭I ~t2ʫËno8o_wO魙RcT}ẈF 18N'k.JrLAgBCf'NR]}|w%H E^q'o_S-,XEIaw3+ڰ 9-I^P7u87ڇ^@U乮ey԰Y!kj+ EySd#ŊGO/$q|ps}u{w#4eqޔFWo(qnমo,;4緫IaxMVHggeE1:\E%I@|x~4F^={wW%T &- SV{uz Mq cEhoYmըyN ?K?$,lXΡBôWY@WP;ߝ\]|z޼{w#MKf:1jA7E${J8zX$�v:&/6Ȑv vR3T;&8 I,zg?}dz/lYNP7gXL"p]2d^I@ގ4Q2bC(4wmȷtV"@3ӑ̋`),4$x%.pO?{sQ^Z,a-&*WΒrr<׍.aCdiY}Ljgjôܸe {7ZAGB}M$rXI[%- AO'џ|,yy +|UxL.܇@NXlj"SKQqcxY5?}̅dԖLB̃f: )w?) glSatYI[W$ҫELh'Ёߎ>nF=/iS랅bM&*#u^={֫Oxݛo0CX";"s\4)r>#"WΆ"\ <jKLGrʉ]?_(Aj>a|ҳ݄}<?p y /s^=\{>&q`-j,ߦe4 4a] %EY%HE[m C o^1T ,EA8 T}7g~D;{G7`@w]FpBMV/஧d=7ofP<Y=eG"/&l^>;a0h)F #' 4^/_`/j@ ȿEGzaY 8~Cy")Oֳjvu_oeN2Tdi :OC?ş\KH"C(3IRcǣ? 47iPI8j(EipL,ߘq)fR6ROR,0(Hk )#Kov{gj=2RgY2އKjFt*PJi<5�:GA<땛ϔ TVؑÊ(0p{ZI]1ɂ`I$qE^aq8(Ǿ^<DC \֌Z˶]K%c'áDRvׂ#q1k$Nҫm@Ï~&j b4�QURi4%󚀅np̗VFfH|]g|7jzd;/*Q/2@ՅKq ;VqO&#/KW#Cm,K8C_.'E\/0,KR1(+ֿ58vrKp^Op{&3dDe NNOæU%20MӥIb{㑩E g%C8"eQ�Ϗqˀoue[¥>j~dTPCHy/"hI9c I OgI EE�(nPo|]Ɓ+nLIL8%HVl/їeU$qF֚&#ܫ=+HR24@J.RB{EӢp CƃyPLH֣FS o/$4@AUΧ<W 'D:UI�yHڀLҘ7VdYΤ.)I^ /B߃$gVM]{ ֊o]r"59{ti[&K\VM(!\OK6 )3z�uJhu xOL*T(ss>tj IK˄Y"лdyer%8v!l7;rRrNrQhGd=G$yS70ml#!EG}ŭk% `ywvI:"]6󪥀(! / $%C;:Ҭ(Ƥ fsnq m̼ݜ26+0nuMFRWƲArjpm:QӚ^dF9q\Eut^?48`BӇ)ʞ/ZTTe{N ω0 DRpaN6E&%^XE$5Y G+h$"OB\IgV584ȱɚI۬rkY^:&4BY͂ *Ouf;Jt 6ݧch`']x~. ˰'3,cI 4lZ7e{~) f*t0 c}P{44 F (;qXH'mPA4Y2R?J<%E%By`S\S,<(䗹oiӔaxij)`C[M뾨 jK=?#q�}ҋǑ!, /t_ l C fBnȧ~B/ @jmĦJ'adS[t}e7NwܘF^g6mKGz'"_wxDšN_?Sϋ2q%z{59 b+&mwݹ;'W6.Ee$jpH?" V/)n_乂W@Yps]_1bU(#wyw^t2룋NIs8dYKz NH\cm22xe[ۡd'%[kSuVW)h[mP$# ʎO9Ҵ_o#Yx4A\Oj ;bb-~0{lR�&MMzY"OG@pضϦIsw&w>}uh ߇SnC\@I*|vO ɩYOҜX3h~~ؑb:.mzqwn</%^;'nydڈl&SYD&�]!xG  @u pC2v>) n \fjnyFIF=CuU)sze::~oƪq%Vr#ILu_BDR~3f(ãxPRt+( P6RMR,@&uETo}kAaE(hDUJ;Q19l(碖vCh6|NRLnLЙndY}OG h, QD{)uэ"ݳI e`ᴚЪ<{98=&A$ qtMpQ>i@>RNa1GʴCŎZQuYmIL4'[Ob^UxUyV %(q])CxpEdo=mO)Ol)dUQ8Iški|UƢ(U~d%kקG"߶0}?tx$z͂ux?x7t,?J*AQcD"2=57vNJbGb[6/G&G�+W,vcK&CJ3DBP nO{$ӎ(evtUޛwOK_ 7? Dj闛4xq&RCwR|/?w22Yh(mKi}B[0P2<}Żuz8X3E/ xɫ'yH&=?,FKxnԌ |2 ,ͦ;@e)y[(WRlE||Չi;+q?ϥ`t 'vvl0Q*SKz2/Ƒdt- C!HJߢm4 \ݏp%@xq88]z5R57m5;%yMM�4ݎ*VLȿ$eeQ3р+.͚rtO:�iϲC@Kcxx27“G?'a:q3irzVҗMJ[< ؓ,o=qdvm?0鬚> ;P@C\-m~R<2OPT.xLR/cJwL']Ѱv}лg@"%01ﻸ@(I^ a>Gph1;9C?o3TME&>xƏυ_vЮ(*Mu&z}ȏb2ξ]8=0 EQL"n1y#T AV::o=O?!�ic~J(RX#GFr܁6!N0@Sp%}R,U$n$DBV#{4<,ٳ?ȅ&%ߙ&|]p H,ׇ{\ V dzճEzxU{?6A%P5Ym̆Y\/)I˔|=kxųO_J:%{{\{{ؕHAϊ8.sJH ]L4dzP͇ T} 5tЯk'ue{IhۑN޾|Ň }ǹGON={qS_UZ~RdqQSSww˲vzUMzϩ2/Hr(H@vnN yОuz`j7 5ژ/Q/vmr^oMrR4-0yZAƦN@P4nk0VԒ)ƞ3M|e,eRZTF6%Lro 4Z)6$h<$62ϋ%~2m\n7~ dQ FisX"ޖiV@HYx)G$kGتC'v? K"hC|:alcSAr{O[vS(YmV{dd?{p]w${&ٴRУQ|9`M�f5߹gE8>DƢ5!#o'5 9>2UKOn8 .809)NQO:BHl y1JoI<'5azRY!oŖ*QfCu"‡?k aBg\IQiFrNLc6t\�zeoy=M4}3J[q9-ytP IGɧC:(휏h㓤aOYՋAq֓/%IM*L08=M0Ǎ>׻=l8Hng^.y$uQYl&SLr]>qr69QZb&rƔؔ y+woN9|w?Tqt|8zmĤm@t/ /Qe%Lz3 K0)#(W,TXCz@gSGǭGaD2u[`f9!G.ҳ墶^4 Dn_b5qw$f}{>:t~>Oـ.yJ󽃞[moh^jkwBm"(_ŐfA.V:\P#[ MZbfKN˚#P0$~b| )^3GP�/wtZؚpet,"827A6c|'jQSOQdUBqhAz^E`vf9]&o8HmŤ"qgΊ}/#g&% RoMedsO QieM&7F}^wvrkKγsŪ1ڂiJV_^̚ߠ0s8TƝO:h );GfB9>CЈ^o(jVX-gC#ԔaRLY₂0J( ̣^s=y!/Y^T-Ps{(tFsj'K8qve?k@%~\N+Y9FKߵY5{z1qD~=>sb)w,�&l}7O\<¸d)qP' \e_wysv%pkS bR7Sޓ(\qVֳ 0*`ckMɭ7+4Q4rd k|GT"](}g@S4;I! jܰWp7UѝXyuA$F-s�fܫ{d˗}x|1C9.C1�u''꒱n 6D"^-Ώdo\3~ԟt=˗_\f0Bku L rw{A_5/ tQF%.Z߾__~/d=eC=uhJTpf&6kr&@c>m z0WH__S`?Ђ<\V PJG{f4SZ*]D2mj j0iOX8/&)(X/9|zA*hsraoQqM)I702`&WLŬrhﬗ'k(yҞCE.y{#<|j#5y&ÛCyno$ggezUݓւ o6;-LY,fa�OG}'x5!Ѝ9?Ƭ*,Ӻ˜1)U ay1?}ntCW`u#Nd`wO_|q,gu;%XIlyb6$% 1wp};$Uy8㞜wo70:8? U(:Uc Жmc壛m>A~23֒`$`''WސeݍbH_EOZ2F[TKQe>Ad9nthFq˂2g2q;bI?ız=ŗw<qNS@?Y#e zP:Yf!/rt^c\Bh }kkh@QL|,q(U$=&OX&<{@!?9tq\IgK5Qok[5#*m.῭k6JwWَ"_8u("8{v>$Jis|E_w?Un,-7w}곹L| S_?;燻;G a*U^Ԭ|]8\wGj^9LtXTf�@<t`۹yK f:ata¦q QtYlJ"/[{cuʴW% Ύv:^ZTE%Qu'kHEl `4)-+�טlc\bU߿y sug xMznOݲI<jOam7E1(JD^2[0X~;Ϟ 7ק{CjKBwD#jV`t@lK9$,utUjɆ5ouzQQoػ<>j0C ,(^:RQIMKkA_V,Rynjr ʲEO_<0w敫tvm f%yÎ) ⢙ rxwDo8c *)̃jBzd("? g-ѕ8 Yht_xI=MMexs6$ UD0CwK{i}|2TFNvVġg[aR ǰ93'.yZl-UvA(rEnw'=Bl#< ,S<ˆeUПH7l7-䘣|7|Mp7=Ot(yP4T~51'4JR0cppƩy ?e(t rgEbeaDBiNŽf knFb.ArqpCFeg?Qf4Y=yUL'ϔE4^ɚ*[)BV`X2W _ACϴ]stdJ~?'=#@49aVUܐ$P(*<Nfw.*Ϟ<uĦ !UwQ9S%MȊ(I]]|] 06ײIzн.i)+qRR(#^48.[̏yW?矬! daN0~<DZ7~)Af*Njғр<]mYǼej!j:kt,#鿕 dBˈYhıwMHڀ Z'\Ua*&{O.*P0ԟZ}tRt~ ')N;wEiP*o~.q7<FY!uC<Q)6adOk),쟵a97w?;_~_~_~_~_~_~_5T;HS0̓$J|'4SMYd|U 0̿M%hKHj" *Pr1ŷ(}Ɔ|wiarY;ofɿ7=_eUaNU|RO'9VUպ]W|Du,E]S0)}7V]uTLŌ6@knZyg`sQ>fy;#I>p]‹$tV 8 ]XeAл<>jg9^L" L^LEcR$^9IelA {yzx.ahYVi`T_̗U߻̴<f9+1ew0(b{}~rp`_;/{=iW鵼q))y[@r6M,''s =!wrxt%9~sxq}qzۉjڂb{#j$יXwiA#/m 5ӻ|szuz|v4u;[gkQ6[ݮ&enwgq]a1ByY[.7NdžcNlz^N@@ai?W?l*+)F+Mh8*|I9㻶ruiLJ<# KR7ؙB pʍnG ihQ05}ZF6|G?^i1R+g`.� 1"XĶy NKS͸EEpEӯ?p ?j:BK^ƈ(l^5Kß�d6^ GW^.& 5)~x@ #p҆%㟙T{rxex?Wfo:QM3"ECUv~TNgmtZaXR*4VnM\gOхK0D3RQ;%i8]_4ukbF`A]5S̖3BlA?ݧ"l0]ǜlXE&=L=,y㓱`;ٯYG dR.r5 ~8CN$]O8p4�az Dgٖe 7&3JR0uvjP5'3҃\]:1ݡeεeK7,6uwPRF)''ɆnI$EYNJGspDZ z\^B†<*Dm=INٴ-@x'=nYz1 cd%ezdS$ - HFO[V%o8bY*F5ȞfL&=̱U9fX(oNNr$P+($g fvJ7F<aj"7x\`َ O?Ψ.Dz[Ztm<c36ƲWMAJߊH#dD]f"db}`yK7h L2~`DZHu F_W)/IآJЕz 3Y~j8TC9>�'ZQVE=~-H&F9dŒRXGTNRrǖnu emT rqڐaq&0WljL $}}M d'*O{t~mylh~VϚ< (_hb%l{mf=Dd 3ƓTYBރXz lSN5lu{D X |SktmۺINw dd,2?JKxjir1['W7ՍfȇD性m+E+vF1^iYM+a:2 2~8&wZOf<fƈlhl]RwϽC@Ewr5E@ (Of ԰gRkZ7``if3mj|KC7wG jdo@}JEߨ ؖE٭*=b@Ef:۬# Q8Tw Oy c )h/o{ژ-=&VD]54'oRW!fHPo_^^uze)fMW2uLS[hD-vX2TbV$dmdsɤcLP^7׃ag`&6qu^={+mPWL?K l#;]fuSM,fg%{#I]vz|?=9(,̠]6~De婪VQ4j"@! qUS6n7:Ѕh؄ F_>8ʑ%r1uNof1KG$.R[Эo=(NOcpl!WI«iZa1ϛPRxoϞ=}t9Dק@r%lan]yf?1f92vFjVww>&@Po^=}ionx088x/,cx-n<[c*$&vYM}0a'_.JE{Q9[vLj26 N:&wyD |wd8^aL֨^A(h0f4HA.J} [ ]~Hh'Mh܇"nJ'9>^yFdخGa-tn@<]V)KAF?|WW3 K';rx'"ओy4I6lݹ7(n q^GcO/eXc Wov8bEXT.5= ?M0}bÛ}*kJthxI.7-I]])V6&̓ڀs ae5j_ ƂHqn>aDPhz:CTd-ӧ*c8Bw (;L;_@Gya:$lhęI2}0 bŌ,aX ;'k9`ok+㓃 GNLqYY3Ȳ[26$E )<Ycq|a* T5$*şgW}YxA_l (D=}Wn1D6-$U$c7{=NBJ'ɢ2-7u^*IC#@! y{ޛ{̵2TϏSﭙ=@Yo(䉌ؑw~L儊1I;;w޿;�ח|E.lNT0Ռ }|5/b3)d <HDCʖiAZAΚԂL*dDetq_|iOz#`~ZDf| BYL߆jdLdz(S}C&P:=5KޭSWu;nd37~z~I3_\qLb1[.fEy)* Pni`*1O U]D3M,R(r h'@eRj_v<Fhw�ZIp]o�"2IJsZ)fT_ ir}=T`R%""B EQ̀eQjM*5G!FӽӾ@2fIV/Lc4S8=6#B?@0eؚ<XNTLP[8Aԑ.;TsӢ{CXIRuIW/ Tl>a byWp–r9K] +tx{w?gͼ'lY1?ϚXiFE?r=5xgsRBͫL,Qfg pp%GiY3l$J ;xUP,*(nGH8ǧۇ4&E@.rn\,|{UAOvTن8Œ1/SlE^C]I<{u1<8<>9><}uIBܷ͛hd=Es#p&�PwzOimϬgД&E2x0:QcÇ)E lݣ>'=N4MP-& ^]*? IIk[ xȫ6UMbd`T_2MkfV*M4{ĉz9}: 6&69{6yX]Y:o!9 zF3B!b$ӓSJExg)e~haYA}9o@KKڒ|p?h"Nu)+ %S>Row('ꦥ 7ks-.ph8&l Hv?s,ףcf\aΊeK!%aDv\%/8B 'x6>mvQ$)Ax.tr"T (U&b4Y3!^Yֹo0:{=H_IDrrّ4r$MfH@)Žd1pjhy c֖,.X)뷬e֔!dܻ\H0-L?$a ޼|6'^_JGCa>ӏͧSz_slYĵzE[׿NHK!#XUd2eJZ<O|n$l9߽|ׯpًF!QW!ߨinөIE2UrJ0uǵN5XC^B ݡ`"-,Q2p:G ] Gן<prk!Bjds$r2z-oZsL]غUۅ yFT eG'nwGe־<sMR4P'/? ~s{be�; *Uۯw8Ơ @&=˰聬;tl[K<栗P>x04ȈiY@4@EdpCo4xt`ׯ1BnZebt *W̯Q1=l~ޯ^C:ґp9?U6?ZЗjB!]"1gݣ?y^iG7Qs4e˻5c1e[PɵpQ \49@IVhB\<"BuTUY'8O?/_nѫ2Ì DK`k" p/撥zP*2X@4tl"ܶZPxi^݂|s!+T7m]M%!?>'O~{׿>}i<dLA$MūcbyHhyڴAr8gNan1f1F뇷G/o(݆K(񂓑lVIP{ߞϞˆ{T㹗8|%庛9!]z,AZÌ7=tdɃ7Ԓg^B K (VEB~ӿ/yg=Iu\Y3ѳ)"MT=Ji\?! q7Y 'aSdVy̥YyLwgOi<y﯏ M8V<YCyVX/EJo GcwOc߼s':9l("EϲTU)( 9O??8{Wo^?'xKtntcV׀/R*lWkZ8>j4C>An�p `KiV{)Q$VynxuW.O_>{'5!Ỷԅ%<-fcI"5 $AU5sS1J,˰(@ebeY3M5+(KsW{?y7,Kں\wOG'_(+W꓉jC_WSK &3~f;ANQ'ߤ4%J%V�1w.v|AVo\^~s'9LPW0.dFaXS[Q ݯ:f^|JfB<-m^Orͷ'VDa=qorhvN 3jLa蚕46q( �}랞bS}O@fCcEtLu,&SxT %UP6yg/N$ZAM{pveeLUdlf34 F!hXSRvMl�h)R".$+f̲4bϦ8ǚ@~'Q \VEQqf^e!6-:迳ܖXO 3?oݲ-1˺A͉w`wN!ćieĄK54mGI@GQX9Z/EseG�OҢBYP}ȉewM sV!  ۦH oAᚭB TBP=Lv@Α%T7 ?FIQf*p D'T_hXV|sSSť8^`+}(EfEQ^192SAiP싨ѥ/H*cBC #CĴEq9cD.@QF7 +YTKtM/) /s%l(^7mynYd8NHg ]F' cO %|N!LYUó15n!"|1u_ܮ>$мm],%Ҙahg]B`q)Er 3- `0V'KM8;Su0uyݲ]<ovc(k\Y1e.`332‚ѸE/sY۱)k''YN{;K=p5ͱmINY#*e6iEc\qX'4^fFE(^A謮X׾gtB* U 9"rld؈l+2FX٠hifȹxcgipnP;I.伙S勇w Ϯ6%U \U" 6TL?qvQ;wƺsc܄c{}C/~煲LB5xMaݡ|[5( fQuj@ʈºA wlZFLY&27m8h* *{C1'?e4rbr=}9t<ePй;8mfN],Ԫn:2pk*B*iY V�YN�Rx:%~ܬ؆�:ԫBٔs۝gϻ'k \e.rJ+{,M OиGjp잡wlJlMC O=M&d-j %V).JtC~٥G{3T$iOˊ`iѶd:I#1nڇ32ŝo7Z4(u`~Ey*wy9 kJu ESO 44h΋< 'O < L8h M<ަ& N>m~f6{piLVأ7s <C\^ dtjuwlP0(;Nێ)!@,AdP$`%bq]µ. EäTmj\c)rͲI}l>Ɖoks/R '_z ;3r Q>6:#qfC( x"Â:ʊ$-idkA #*+]\i(dyjHTrgLMRuCJS45朜{JLL_'TJ&yH< KJ_myz?<>s:Q&htd!] "OOF o·Ώ>dn�uMKJd:2Wb,B %2)&x:JDK UXyK{<:A0y=SH^pARh1FyFFvvU#plOPu-AŜ"e-6kHÏ/"l'7b3mpCMF?4vXLKiqǍbb \$Նx](k!UD7 M}2 B"5pQQ&g_Dk_<듭12ZlOL]lG]A ^ײYoj*Ȭ H4F֦RIƂ$|EQO~{W4ۣOx!0E0ӼJ R IFh"{#Y Y&I4_VrњRhY܇#Q@PAx:T5g[+%+Kg (ᑦ@&4]/`㎨|;AL{mސ]bݪE!A/ٱO<q*]m Ђ�ȇ`gEbG۔U~{QEPaM<du*w I Φ{E4M;LhSB՚EcXQ $AR�R'Ϟ<yu ik1sRd!S t% q3RIT8 m3(gsoTFm['ضBY9�]\cOgO~L *304mCЯ}W >?p=0%խe'[?vIY>["Jy%zZiz兦S\+ėTi{g*"W{b ~ȫP@;nl�g_SBEAu#WQ]8!"k2KB?5>ٜ ,DE;*t*OȦGБ T*L8`mrٰPH̪/=>$M�),#4CXx~ iJ>xOEiK#c htًwz27X7j{A^QFД_ܽ4 l(V>6\R uJJjc[e̔9 )zg6?g_?$&dG?3(NBl:}e Fq*Vܨa'2-+ZA^_ya2=6=t Z|;yj6fMl!u^qgDV^6vI&)KR]@%.vZQ pw*D)Qm"M˰f;󽱪P&=ԧ}ZJN*}Qd kz T}uR̍-A2Fo\E%vX7%ˌ(ĮH˚yxDa*MoPMqc!UȰסa^]1?H ]-Iv)]ZOND.Ms)gǗ*<?t5MG#xp=**1R2EM;?3ro*TYZZ^LZEl1苮7|s>Ķ֏D262ƹ>|^JرSBe}ENЕφ& T2B|KMDyr v^e0^'ndpZ;o^_ yΆ 'Q6K5tu5q4'rSt;QQ&qy6 -= b9oF)Wn 8|hDŖAEO!L "πJz` kfʝwF4r}TLʶE$YLY4uH v޼z+hQ7ufK^uv4c/Yad¦hE ՛.' Ǽ^Nסc(2}ޡtg(D2qW_<n/}DZ?2|^.kƩhQ$(2-7sTwc'Np0bBC-e!oaX9ٻ;cAzDEt'J"j:Ս2640u2ZTK8iʄPjV[cF"VYN֤-)Jӧ>~:c(DulG):u9n&-�/? G>Yj1[rlZAQUyIyUC/ͅ(4`йR/딵Ų&xP<Z9'{[ͨ"z6ƃNe&h4ɒC`&l mYE1]PnvJs"zb,f4uuYAGh?KY,ۤl;ܨs omvFrI8ԭY־C$ vmR{Dh,Z\󧮌�?2XD&dhPUd-) KAbvWX�Sܴ�-CN48DAVU1HF`-hg}]ri5y|}2%na=w;].aZã3}zrP5>]!V;L:k%UMIƧ?IUC[A :&<jƳe{fUs?-_/o|:޼JK.Alkq=O-�d?:?:zQrnS r|'jW4Zۏ_?&D(U{5b1#ڢ|Nn'X{ote9lfMKVMKW!(g{{!hm\w{TR^Z.')Eƒ[6vV3.֫ƕgׂ4E�(@VK7/Gc< k( Gg8lF#^iZ.StQiR_ŲImtRIUSgXA{|->%:g%[Y$է'gWp4,[45 wHGnb/;&!g]Û;qljQ qs{t~՟zZ7hYqX>58:~⨋|G'6\\aC;ۢmJj(t"l*!2qs)Lq=;<s3mg+. /lI^L-aِ<k=Jy;2W_(ԝt:%ħe)J$#Te t\w"%Zoh.Zd:-pՋFz2*r۪<@P?'I )L{fZ)B |uLv=ۃ.pk_hACݢS$$EVKA /.{4OiV(^ףtz{OM >l<%dfhNY! |$o(ʹ~ #?z'*q[5EzUqxwz[i4S[o}In<Џ.ޢG/`[U%1(AZҸs9$c}sFxk) XnajrgqΈKsX=_3Jh&=Lyq\h2 }*̀fu3& B[2~rr3Ȗr{sF㏯ww_DkƥĢc{z~"Դ lەW Y(NW'GiYh?a#龒l_6pmK9p$.9snҴݱӇElhC*W120d*߭p$}2ۼ!ZfPe&I>g }pd6{І*7z=-*vE/ч`'/ &{`Bw{u!i-)ۇ`1&A  hJFCsPZ"aţhE"}d+k= *挒d[ЯwlG7葈)mdHHP q+[u_ c֋*0E@&ASf"[R;f7YԪo[d8ĵ`ЧlU̓`$~o^qAןV!c}}u82@L{铣h&l%-= =B n4T?N;Ќp6&BCd^<,MF&Es uz~7s6Q& K`*[¥?(fUVX0t1)PY*?8: 8) )`^7v&1ZMSg?, 7g2n X<\uzcz8&EA]2_+�^F^@)5ǕH/UnACTÉynZ[|>«&[g1Ֆv7s gǾ[':*C(f i=cHX;%H_![i!hwِB?9 &b)>zXy3I sǧkۓ劅Y]iAuϏOOO>v<Ga%EE w.Ņfq #NA?<Na*-7HLz^7pN ,gTcOՄW]  -; S_]u>?elY8`,XMA0S|~y_o xYzTJpb,$N6P'aTMU)&)<O2L]Y*17m1\L3BJe�u]:䢫EUj|qL#ћ64-GɮXZLF3Q�>V']§Qt;?r,bݲ}3uI? {g[%~)!5׃z}Ӧ)@?hѴ\ @D*.OZ|`4"1˽ݳp8\8<ٻ Z 8}lHsfM-(䟤phCGS&g{ׂ"f¾@㣋x4^m?88?t2e"[{=%�OR8 $t;?=}{_M}e9ѝO66{Ӄ/ْ MD"*8˄nCelWT kFKqaoY"12iܣ7gc^UnPT"43C2 ;ٻ6Y,[9yI `۪C+ 9dpy=l1@j rd#^5? 0 &G=+znI9a]PK3jwcJgzy?fO N#c⬸q$ mJnZ^T4+8<t6U݀;M-? 'ߡyFotE]76.q|30a>c/fIE^0c"\s竚*.Mc!An MnP;t΢Z{]_c% %o2бMc݉#'ۘ(L_yipg[tV+Y` iΧ)O`Cq.~3@27X%tM+F(~XGi]C{Ng TF?yx֮B؎fd"q \]DqmU6]M*\~LLdKǽNo@dH Ӎ1T`Bf(3 Nu�ZOlL1ݍ\ 鬦d΂D]^]\X5"~[;8(\ʪ&6@res( ~'8q[<6>5!?Y%1l 87,&\0], Sݟ#H ƯkƯkƯkƯkƯkƯkƯO9GOdpV2c1X܂pndiho)s}O,kE oO[g 1VeM뼨<ѿ,(ݟ8 mc4rvVغƌtlAu;kfM]Y:C 4 嬴dp(ɋf@oD$K; ^7Ţ.#q[#K ܚiDwLv^Y7svDr16#~==6m^25k٬ mVMFl&„Sb6oaG'6IbHf8 O& Q7Wǟ7ղI<W^1^e Y0z9L3sP8qq}y~w*qfE,Д'=;YK{cLԘ&&fX )QyGP8<?=>7 Wl9OIbdepm{Wupy-1PCqW뫎#l]m]q>ڶ/n*[z 5iXNfh9I8m꼠;18U}qMQPMi-i;_c;ȋ.%яf6.2+[D;^v=53O+^FЮ>~?zq4+`2r}1wԕK%AF^F6";Q J,?. ΊYj9?+͉3)4M"l9fHi؋гgHN*͙[isvlyjcÏ h%)̖P)(�@VDZx|B2''o46/!4!^VFv)xMŢE[<K(�_ dUa�--M#onLI=[btN|-6u3ۊ)TijLq"ixkS"(¤^id@Y.l9*+1~WI5㼘M(uNL4 lѶIIO@QhZLAfyAu KDi$My/zAĞm~1x̚ U.1Ӿك|d' |CuZ|9cێcWyr y]zf9nԮ@ YѸ̳I229BI"i'0:w^\iQ`s]5CÊ" ӼE[&\W;^Je$#NA\Snk2r<ֿTM8e%�H@fYP" ?]I !HǙvP/qڶ_4rI c=d{ `T@WǡkHjswiLOsNDSHrLwruE8@X62Xp璂]ۖq΃%77"J,M#ʙh:nx#K'vB{d6[4|AB*h3~r~R*ys75CE B~5A-@f>kk f;0Ъ" !"p^=N%1 &kC+hbk85ðՉzo'pը\,oFL.J@~d<72rcsi ˺io$*Y41-^MCNjM~ HV"O}Z{ EEhoȪOirqvŏCi 2׽,C`c6! n!6:1$CN5݈&DMlIe5S'/c'/}TFB׭3oFECA\ǝh1/5_2&p4 ?LJr yk OGPL{bgwkghHڰ'{Tq=;r]u8 ~n*42}G\ӏ9Dj&wKuz&0Q픂4T$r|;h.KORH 8+]1{L- Ey\=e)٠"Hkg풉/Ȍ6XqR~/{Zh7Ϯ ~]ԡ)L4랠>WwϧyBKGRW QUhʜdx7)(ҟ__ nknȗ,q~%Pt`V5\L i d(hyx (HS)FIh{ӻ::<:W)[N"]6EyQ7)tJ$š] ]{IRm ZBzVS-/)O2 �1:=8<<v?_S1$bOE5c ]&{Q,}v=wLVHҊcw(A/}$;.: XL??8=>|fKd}X~>jvخoξbQ}_,Ei0Qc�݈q$ȪQ:yF:[T) mfdcT{[<}8!Ȣxmy4ٙhxoiN¼ݡyPM6<KfO7y#)Sx9Pm9:Cʎ.77:W_>õ U" ̢tj&ݭm$r9 &?M4 Ge"J1%OΠCTRO''[ýwoƆFa\4mB0KLUT*BB-+& i*SLDŌ(s v?Gu wq&K"؏&1}/2~{ } M0 M3i(ʊa3+hTtxߍ. +N=vp(hw4 8!]DINvHLP,. %4~\TX=xd*'_0qwl6jTEhY똪p~If4菇_EvN_5hgo-vE,PlO@ =|3ޝN,+cBA`ϫ)=YF|a{yttyohgs``&-Jl/)!0@\!r'(  6*$ gƔ s.�iΚX ĝ}ͣDƃ q Y,WTx,C&JjO5<|7e5вRabg&?%6+ZPmmz}E̛@Xd-(o㢻%H(Kb?]Rh^ +-$LDHԬnԵvjX"?ﷶo}d{ZR(b;:,!-Zy{^@~&4;=sv 63{S$@!^Ȉ/FeT3N\d!qi(#(TRSAd-\jX'MMQɃdչnDf@S+l:6Ϝ P+'N3ڰBqاFsT9M X.(V)#pXUPQAFO^r&BG5! o ƒq=)n9R#iqHpiWU'�XѓG;@HْH^쐯vZ}qt{n}dASq(|`0BStcF;xrʣ^&|13J1գ~f9AD9#t(q|}|pM̠ E><t6NM%_ɪervQ<KP@8AOo^NGTBTСnR;Hǻ]Y i*}eKX%Y;w4ՠ,? )u$S2 ^4MeE]&#aJ^*Ɨ,l>Cwyp|sx@>-hNMr&RyE+CYytvK8),QO]S S2]—/Wx]lm:-t)}GpJqR4_HeNR2fZE\F˔`*`Qp}5'7\LQi9qV]t*wEets+J/MC:?p12K22GrK5B2 3.!%CȹPM;*rt ^ Y,tm/I@1%`Jýۍѵ 2cN>&|J1r83}CFTXΗwkvP> .]9)|! p(D VAMCx\8740o&wv%\}8!$99r E&z+@.jG)SA7^J>:nؐXff5[[W#\LþXig'q>_MSBֱ{e.!IOȚR*׻[/f)1M<*NXP::mAUd줃 ~QN8jУ׌* B_:5.vzW^*Qy#>N Z^=G,A;[`& z+lͰyH{naC^ U4ʡ*L߰VQEGHI 5"9cUJ`$tY zh)Wvn`I[`.):"\|:޾}X~"hA540MTo(|x2C74{aTyˊRGM~- n}U2JhzQQCS>vK|߼}jhKKqUYDeVץϝ7J,Ye�RqJ0FNiql܀BDEW4F9eɉ}!&UUBh<(ƅʷ?m^k߽|}p ]%Z7/W{V8[�CCN{,sCe#]Ÿ'iR&ޗݯBX&WZ|xspvz˗^zӶy! rJ؎ٴpg(W^,'0$itO36n~y>{x-WNf3P +F?lmۋkpy꛺SLp?D"'?pչg@.{aqЅ2 4Sb-i{FX* 4fӊ\ܐo^yū{/MCST*:%ӣ˯ )'2wfQ`{r7):^jVLPyGAv1+NF(!˧&Lwss>e8Ur;4k oL@&Y"3/ E b}1ƱgٖOpd>=ՎJ UtS\ ݐћ_~FSI2?രs &Μ|AiBETt3 ߭ږk R15d*HěŦ > �!]Ũ QW/~{o/;F0[�26gjZՈ+.PU7Qn贻CZA[{L+®̿><h,>2(QB8z޾}G tT+KI�{^MΦciug6L1zf.x}KdV<3ql%zT|$O~~|on^@ 6$ =(IϩQпzq(L6͛Vv{~w(cLq%\F M;-$(#E}Wק{՛7oxn[6r[p 0c@tyIBTxq#D,M.'ȵٺdK1 V<օFyD)6l]\: ̓>:ӗ?2`PIl-!VjH7-kMNj0<JK{AtJmMvr9U! aW]]\o~Tmw[p[\r3ϫzcOidW܃nMo$`LA}B)DR}̓9i+*8Mm880 |~и=zɫ,+*HɼʳgJЫBИ$ w,\O@f̰jzx8iL@._dIiZR4 kُaEWqpo'e#1|\}lRTAqC|7IlbMopkMN-H9%˭QgQmfDa+vCw·0}42;J٦a>%8DRQR_xߖ-!-ӡQl?p2&S}jjt|񓫆G4qxi"~EZaT( ab{`;o0tUǘfKBSzReT@,=EK3UF=CV]=h҇z{l;6'xjtO[†`OI:1/csQ1FN2L'v3Ka~90D }4li!AUUwL{.͐<AbHV `&v BӃ;UAc<*aj^TsTVe h Y/7غУwf̆唫1Mӧz":!w^.04]x\p)4uÍJ'Ic[C S]_ :ezȋ;,FlހYəRB,<=֖4d3:ߢTF atA,1c"0=T\JQx>niGIdSbe rFn4uö [l#4I2]G@}4Ac©GW`e5)8pqϖdN8�4zmAm+ݯc8R9Oϟd4#ff%EeLbZi^. i8ȭk]8hQ65pNCD'Tt/uNX]TMIc868l7UH 6kޱI]d2L')kl%/祯5a_KB#ڶRh} l ǫ45q~9$<;װq(}~ۗmEX^) OٔR`ճI*awDC5Sxxu\ *m EI32hU4&(XQ[U]ɤf<E5 Sۭ.9^UNg(1=՚Y`8!ᱞY*yY6BsɅo;#$qE%/+\LOGu\to{h֧(14]1mR-5-6~#(U'dFN"tOŒL`/~s0}ݨBxR) zP7-kwy.= ŋwՊN]G_EIUVL!Δ1CT~ 4 ARƒqJu;}Zᨊ<7lHTh�,+T»1#p-4XoE@]6 鮗dtB KZ I#_ϟ}Ms|r eȹUEFFTg{ExTdpq_k>߈RJ0ʽIQwQxk~=lKr< ` qVW yd85CEH^MXw܌>C9¢|F iI'Q=8 Ɯ>ll_bGs KJ vc(sTLW/aqGuу4ϓi go uW܂'zp4Cݰtw6߾?FDi鑭B5 K2|9ʹF4rH^Ds#2WEI/�b4U丏-ʻPit@4sl\ ȠCV!JVh^~|{`YD`ĂБ_1jjR~�0߿ʪ<t8؉V7'yǛMB})Mnl@/?-[}O4ULA%udRr<KS@0iġHUS\5ʃ4.?AxTs ;ᢈhUj AM>gzYU);2 NH9 P+ؖGřC@/) z)<R fEfY<8#Ϣ9pHy1MbK.Ol|9aU["FA�000IהaWr:.4Ƶ6d TEAMt9Y4G>9!kTT^|΃>_FE`]2|^,v kZ)=n_syl*x2bc>ʕ!T8'M[{ M10 d:2\͊(twޝ LJײ,~ox`R$dm[-23:<p$ѨKy,/_>U47Jؽ0Z8麾Oo  qaY?`Za=S&סxv$Gx`)QOS"\y͙dcn{f)3fo2Ѻy}-jN\Gn(ʖPȳn7w/H.1*0!Sʒ%ܝBX^nrf)ă'p4?\|zqDPt2 }BD%Ջ~E;rughE@4 ߋ62BD3YiRd47㽍 ڊ0A :k6х㍭6O%*(Am^by_-k\^3l4M"vatHŤn'%ta#?7e). Tтa;P[mEi3bBX~�[Ȑx42d*FPLRYk)dYNjhOo�-b8?FXZp#45쒗UJi xsmȐ(F$(Jr[m`,N"׳mlY`R \N}5]ruN!xT2 ]ve&FO"$}J"+ 0">ΰ}?­x>Y*b/w?wp9& /CW囯}G,ڡ�`:޳CKVY5$J&=( 1657 rۗ)_rNAGKTU5l-ʠ!]%'\MmgInݶIN1YF^xE&iS5S<qҧ̂S>#p`Q Z0XI掴)ثKK]ǣޜFz[G;~� Z*>n>;;?9)Sh}(6ⴊ16 87þ*ildLex;PLw\+БQvv ta ;;Wg]QUyw?tءQs4@%:, aS rD,]8ueOP{gDUM=%\npMyI> Z7WW7?/@hny!= 0d){h1K({ JwI[IUn0-gJh^<<;z}B/nDXW],230ѪŃrxEU ܔL6)xOό&ug1v‹$Q,h~`ХfVB/e3bj͞ٯ:6hz93*z ۣAyFdOYep &(gcjoh#,9 Ѵ|<fDFG6(IOv1AqnL ,vvlY7By(Nj̫GT«qp" ZXΣ{75' GihG="u3;< ^(0ZIinXT-TUظҚݫÍO?mmo~n!`\ԳIwɗidNK3;:~%<OqB9�=dV +vQvLNy?TD:lC(@r YYh˥}ȉn(gzPdy(-1zF#VQ}]U=n\NgH1AI a8 V!'8UaWcN tNs*' <G즏4zSnf<ɜFZ|mXUЛe{h^G`W(�=dSnw[W7vKRh(B+GoS2`2V>޵散w.B,c̺n^R/ơWŴ i)v>Vr0FaK NjPplRaV:ifqO3KYy:(|:8$<)=)#nys١:<:-ַwضQ,Xq\^ϦYT@N8b>|ZMٻQ&=no.UϑvNA6x{- 37T*ⴞ#1CT;M a&@mTsW(OH~U '-|;BP^:caG:Jzg("h 19x \-iۗYKч<ս7UIww:<%h/kfݼ uͫoAGQh+'~zebMϧ*jt&1? ^Ѡ{'M^z:[ޮ!;ۻj*7w.)hڝh'59t�Jq=mRavOfUCKʼnG:%{}w1|Y.'.Ss t6Yon}6lkܴEAO h]vk4mvOPt.Q/ (ࡹj㛝GhlM@ ';4 @EkT8'n\\UJ2aF5'w;Otoo>ۻp:u=ǷoU;ȧu*-^'6  G3Hv}?-@A8K `ȋzJ7n)'\߾aooWu8&O:Z_; ថ,]-q^S^ k.P>w i~5]Xj2Yjiz)zU뉰Reȷ)b'v4_+Khaey[KGZOz^]>_po\$/pQ,I<{H`<l4 DKq=]1 L3rB7>yo]0<0՘;P? eIN ?P&0c־+.ޱfu,ɀUlڎɌ15??1ƦF߯ge=A!ٜ{]7"XO/^=#&z ~Qr:"Ó'OI+060t34FU=CcIM33G=E4uoɖy.fPݱI?,#߯"  JF臢+B=s $ 2SL<f-Pڽ!/`Aef+`nɣ1$ oo(L)J�d}eلć�l񘐓,\KN-@`[<#෿A(PNg UR>{<#|PY>Y2{8`󿅰egs N3r f3V {^z֓5ۭV̧#-3c?`ݪ,D$w6-Xypo*q<MıfD6 .J~fK~^8tnk}Gv߹ bߜM60z9Tؤ, 'N- ɬ Ϳ/?L5e 7\GM霐9B5YL0�d\$QΏiL԰;Q6Zp�}r,ۉ+vfwFKez5n*,pR|\FD M}CuՔ-.>ĻoYwBZnNU:mDt#Ԓw̙ndx;qTB_;a~GŚv^F^P,m)VlL*l;i�bY=ŭ˜t MSdxSM`)n#HPw,e DgD݋hZ"fZ6߾-B:p)[9b@2r;o /}iH⾘L%볎 A(j#o)}["Hvc}3}D;p./U,ng}keтS cO:]1zAi+88L <LUq0ş�#ޖ} 0ܣ 6Kް B}UXk]4 #`D̪+;Ϙ1 fε' BQ1MY7{Tɯnp2ZV$&wZ=Quj r:=y \ngm^NYn̵;2KtO0mK%PD9APEj̓N57=`yW0JFdJ qA* :j�'MAlyO5fFi~ٳNvjf2cT[l.KO航c!筁 ZBc4[^bggg_.{,SnNV8p,i7j�gT"QͪmnQX~p'>8ڽ zr6\/F"Pwm<xN-Y[#6 )%=Czq2F=;>9v@%"=E-يu QF3D4H Qug.:&cؼ|Z&..%0:3wlKWAO4"=cXGS|dZwi{Y5bG^T3`"0Rw;>ُ8@2D5k,&Yᓻ W*C[n>T?I`?~ϮzFJai>u;2];/(nK"uz*Nᅤdc/$vZU*kT<%%Ɂi#O40ڄ d_M74藏jDjH볳B'tSftk�vP/X 2"1P*Մ^t vOe T'*4kY(hI*t(|JMV<RkYp n:"@ڑ(  {v튺nh&hLFܓ 3p 4filmA *= 7I=0sf?:DX�1)uC`ii,m6[,ц :vO8zƯkƯkƯkƯkƯkƯkƯ"v8(IiiO{ieyL8 6#z&ГlDSP_Ӷ$ LI/ +|´NZ$e=*:?rG =IäFyi]9&1r ̳Y98M"Z֡YAn,W#e}7Fu>&==qIHj4f!kJgNۼ] *&H;lB#Hiv> EHN'IfٳVzSBz0 CTI&=#L ,ͪjTfƳV<[WNrGy]NeI[ {ĖlX_r$KP 7Y< ׍k$Wve)m'-y&evR.fyR*ܲTew8)gW{"b<YsWͬ_׺)~䫂憺?Rף5exs5 ~h?8<8~ͳ4Eي3H-" 1 !A05'}Ht:=ӔZWCMA|{xug밫1īfE^Z͠дZ<r~1D;Ŭ݂bŬF;@ Sux~}u=4Ud < |9EO1|<b*r3\Gu�NUGebnRFj=lZ4ԡ`ѻAO.QMk(ި >IFee#YMR4N'#.<6qBWQܤPtZ/tY?ihE]UkL"K}S !L$ 5+z1y]OP*0- ̓ϗI='(ĕ}Y0 a5X'PN*(0`I8_OUCqY>Y,! ے:!cRMed`I^ sR3g/JFl9A2N~I#k!'*bV+�[K.MjETQ kerA.K. ܊8B~Y^ -?Q隀S35E0aM3Pׅ+/\C5'tEQ@m1̘o! AC\wFY515֠[*Ґ,ue][.LlLL c*c�PěMNܸ8+D/$@FF93 \RTq$nC UЉ]-'Ӫ4"H&D ~x~{^T1 :41q踎nh&<T$K|'NC2)*[˪ q0Q&M& 4-&"Erڢ)NaPd,ү2{8`G̙a0z# e?#jDTE5t\D29eU*v>6ѐG ]s^I!4WV &K};+ 1\�WW� aEf4aF0{Tʙ]q͖hڰ!qPdA+QMk O0_L$Cz aŠЈGdkiat:WMʀe?C%2Zӡ,F-kZ iO R TN N1 h|PeLxe`=?]ߕN0eN3 Vi9xѿV) ȔOfF*VAH 8VR[L$JYq?뙞k5oq,(.M."5,I钉i69v\1z (ʆBb:{>N0\ 6Yjg`yxUCOi3&O En}y+le(Oxs/*XEQxkFOZBsZȁeqZF4!]C~RCa1M iWmQ˪\=N(((^q^z9%103&2tYr^lwM^TbP^O?N<ewwud˜jQSnG0>d8QxKn &P圖H$�*_0[_6%CEãBC~yY6Ӕp?N&48 pzI1egWr[.6vϮ.n:B:.oE`[{n۪ɨH<?GkPg J%[5-"B_=<bfu|x|)Nc7͙vF #e&:UQq04M�1H2O*C XJ<bKwNîiBJ=u.|污:<gZ1 PnORj0-]B$ArZA6qLp`퇃.C7}vTiקcDcz9Ɉ)'tmjn*ݫ׷ww+󨢭SlzWWZ{_w>zZq `gpCZ`뤜 cZYJO|-?A/@-;V�P %j뗽Ãݍ>%#Jܴ|\oL>+Ǒ뱿h)C$ԓž q85v`LGCC6}OǍրG+KcV)[+h.Ơ_3+Ȁ|bTv86t wN3V)TFvwXh%)3|�A�[ v7y BOYE-YsK W&+9h5Wero۽6' zAso뜇WsI}�"WLq8tPl20pM"P5=2zОdqzg[~9n\o}nH:d:O| ZܲI57,ɊfS-l?[o0L^ O^_`Ѹin[>~|D6Dnϑ#J 2A+$w?Jcӥjӎb�U#xܧLõG9Iپ>4ݫ/m4:>9rE �.Ŕ0%+I~F_GH&/Sj8+&a rF{*Fcև߼͓ۗڑ/h݁{|6r\MB#+{CՈ'uN)M "nHs4BcF6; }9׫VȚx+ӧ)O -մDbp/?$ )VHk>GBDZ#tl94,Nʤ.7>l]m EBO= fsJK. ޠ 'CxF;+$ttWeСR2V&T ݭ+sn|> 4ok]Eju_<Ԅ5 ´B̕�y3e9&*wtrwkJln\/o"i0`|ۖ,[wIu}WtoD M  eEF<Ofd<͊7Wէs �r^`~џ 7dfxAR0|S\^1 Z~uQIfK -5vՉxd KfH'_XM!˒r2@>s՝ z)Dr}G0ՅO'(7E=yH'% q0 wf(nxa@RKbvvxXV$r$p㯝aLeͭf0cz.} x i!2ܭp :`�쓙I{GVKT~ 23T:l~zwxEwxfpeowUo*�s5ƴ4&2bY!Í7~bu"RV5 ]Q2E2dO9q?<;?}M.cI՜g&QVYnV &۸Xş [d N5LU" fQ"s;k'ss~kS 7í?T΀t-|GGNSEφ{fP}<_3e4Hㄾt]pqnɚs2 TAjqtz PL71$ڧ'pП 7�ˆ_,!0a.E?ǎ.씕5Uzl W,Ev:v@^hX\w:o nU~"x0CiH%͘eFxb^A~k\VUEe� DE` N/�vx@ғ|1.WpJթ- ( cJSca|F$rVOakfDHv9$�C3H -9v[/[ggSc~{ | lGma+Z "� ;`ംxp 2jv04EPK,pQ_?_3t;w[[TW�?Rǟ? L Y@ }(͌G#ңNws5b<n&6ɧ�8'燮@1MNu޼"}SCY0Óz_F&dpD?2G,af+<Z4{;WO� -k懷yI(j4)}~c^Ա@?hYeh*ϑ</Ό^t|l v&LmTatl|Nj˭(mEP:5'_D �8 H ~xՌxɋط[̜c�E~ݿ!aP!^J<|ͫ?_rDZ ,'9F/n5]yB3_n?E͌fQ�KY9�FQ[Z+`�_H jXe*Ouv_ony/^$ \Mdƴ`(!#&W>IHJM($oCԁd3Q&iֳāl"x^"�g,-q<lXaLNed>|⏗o6?p 'WTJ_%f(LJSF ɊU#+Q c:'GA"r/*Sypv %EH 嫭G^K*`r17Eg R r`IYXʏriR|rԍLp3OE I2�+,߳<;x?|fC9V\%l@l ӌ;\(Yjan:M&cꄁ;M }ݫ45$]},#Y5$(F-p ?^~`<w۬In :W%wnpK@AVK"A&Q l6+K  kpuwyKD[O wucf':7!q M[xBT6Oe,oQH j<\�K9+C0e֛7߼y폟OvP%za\эbz<HF]],t>Z@7 "r&ψ~6(�X T}sׯ_}kJQ#Gd5+y Pq4'q̔{p kC(+vĭ c $;,ч}mGl~~ekOrc)YsbSҷXۄE8PV7]RiFvXqP š=%bbH+HS=ǔ'W=NQw;!5nY�|?LPa^6Eo^x:v7,E!Hkl{9nu~2 i )CЎ2Lں oڴ}/LEaD" [?j0$˳<遹MIj~4wZR �Y^/,p2|x#OT+a![.�b;_wTC38Q$eZgw^,Q�@iZ{}EwΘ`”N{"Y>'V/H~<(~1Fa(!:8xƆ*I itK`2`T"5xBM`8*EOP4UEu- 37"=+r@ qۖˮhz JJYp&<oŽ|jus( }z~&;ƑW1`d<ĉ&XPkxFX9x 33ng@qלԽODK^za},Oi-iP<!B#y٠1#\E^),5|< ̳빶enh}D8/9A\7YXJw"K96a,GY)48'u1` Dqe݃G7*oSwM�WԳэ{5xeQJ[&7}[)#PzNpS+�m2O K< aqG^}xaZ95d]#ͭOy!W'Q)�!p X�=Vbw+s+<%gEY &G0֫mJ|2<bt>A/<,|TMS+.XB"5z&2qܔy�2X9`VW pfX8dD ΅Lɟ/_|5;f�gf3 ohM#/ I|Sqt1P[L}nZ@.1+ )2?_m)EsӂpM O L=`˚0xpMXq K'x<M1O�mQ `  bDAZ"]iYR@Q{ϵ@">/|u0ID#D Čz"&Hxu=b8{box0y!"Q.Ǭ`UCK<ƛDiF(eg"aA=th'PA6`^ rów['g7."}uHӛ;ěxulst/nj`E:AͰ 8$BfxUZWe2 48�,vLώ"Xz{ͫjįjWkV- Ga(;f'LP I`<LjPF p,Sj`3"*@EO pn62 {{}+<ͭ|yB~`3 j9.\,+[nV8vg%9&t0XaN-U|8ɳuȎg_&,sBm' &# n8[߭JvOiceNt5$OR=XJ%,]ZF˂Cq9Y�|uصe,'+V#SJ!? Ds,ۻe 3^]9-I" 2v�0(Txl$O[/_2j%Y TICxǥX<(-p ܔAa ZG�ПbA mӧ1�>�B< ~ ӈUX`R%W6_~e$ �`co8 Ol r E+BŇ:UD0!?Ǟ)_}>=N}0:H]cr,aB/%F2 ~_X5K\@;l!.7<)<"*'E2TPxzk^ZNm%i<E#JcKzyv*�� ucm,2SKf uml牗s"ε?]s|7< }7 $),*B? Zq0OQ3|kux}s*O Oǜ�-YUJSVQ/cZH (0@X!!.^mnMU�By Iz`$gk;@UX=hż MU^If( 9�84�za ʼn44X Y77_`�ZCǧQ'@B*C5 sէ.#92UJ&;?2&Lu BG⭧, $0K,ΦxrŇ,.?kDTbj6#[d.uavIkCjioX@d'`70|DX3)|#sG8)'1~ *UǑ�A~)%ja@Sҟ^45o_] UrkGntql?X�ZJ%k/_ܺD7:HtG!fT3|:l~?YjX^<9HPuQ7p2P6|%Ű [:yifwaƑ@I^nnn>X 3fa$qLͮj:G7?xsKDͶ_ĩx-NyZU[o{)o{o3 )nTUa!mn~:ZdaB^٤uLl*C/-N6"PJ&p5 aO1͛y)<pܩ9-Sk?u.$MS ]QDJBCIw@{ 9ԉm.)4%wxgh <]�#Mw=FSR$5:*R[2Х8$2-CS�"+𬠜nf(*PO]DT%~t|1f@EA!)]$0aƛekTu/b ;�ҏ1r&cᇞ*�&w?>q(&P͟j¡"4/@%`` Qs&"1nQzՄ2 "x&q9oYDo1miٺM[diр9o?>%QDoL67n$rQ;$2~f($5Mt׳<|BJ_^x񬟭VêΎ;'S iC)a;8>Yl\ȁqG-19oG�"qonZ!VW)=v\ W<5M'�Bydxk0Hxwm˴"M2�_@XcΆ߾D<m? haUBdž `|Hw&Y5_Vx]WSE )#XmZxIWi'!Zʘiw^Ѣ@[nn7_.7)rQ0|0aM uSKaߞu_;u�{v0x7 x\T1ݜ|m1ƐzƖi#&1<2 / clhZ5�z̋ȟV^ Uw8 ֛F$ppC7]?# ^ a@BYV@;;6:i&|@<0|169~㞴?1.,N`E; +VaMy:-JU+B: 8lӫJHx 5%~a*!o�4?  Q@(tfSb+<1/י`u2<%xq3E i "yRIQ 3m|xd%A4~U'$6 '>Rqn~IdBӌ`AP!Y;ð,b̋n(ST:bK† @Q<}txJӿLC,0ɋ2ug-^śG0V'óeI<I2餳ES1T{w{SOP5'WM$馋Ea+ !XiOi#9 @<B6rc.G'_.cH\lY#Hj9[L/`4 Q7-Hb %W%x|MJ08<jou4Cww1"ޟ!?q^/m Hx`3N~גE,ʪn8a yv2<N)dwx8dy~t=7$3D$l9Ol1CNJ~qsԗJUi%.޴uY*)#NTw@R^7Y\2Cb!]afC1jW@m[lg)qK MPZ%3AzW#d\z"A̰ěAv4r[ɗ:X+6fHYŬs,i<rQYZ: UUhpiťbb]׾a/.N2x†CO "bX.7HwEj4<FI; "/;]KFܧ]nyhpj J.SuBcoxGE�vt# X̘Bg뉤؁Vg*r43RдLlK.otu`5g"W$uͫ xqex誌P'"|"xE{nd (ߥ$ՊcC'|-H:gb[2Ӿ 2cS$M.qԘAQ1o\uO߿6"qrnn�\)5쪭3.Cuk+c۹ss.`;G)A(qWrL-�9G=m.S'+R64X =_OX7|@:(*-p5m7eNgu`k(ry@Uxå}!szWY4p0�6=z=o:6Ew6ۑk<řWѱE}qw҆yJ}2K$9!בcRX= a0: KfwM.|=ǝNc$1^??<a]sljK;_isquqv~CK!<UL'2Cotp5`o+bbb6mdT&ǟOoLjei>;1jjVw)kH;[o& vmn߾ o5Y2tYc3jw'_\`I//4+pKQ$&;gmeܠ}}&!b$],q}њ;g7Y֧֐f ">^F=~Ok9ISԔ~Jyq1 EߍF\|GG?w[too|M߿vy3 5 rǏ.Y߮d=ڍ�V闽f%; _׷oĭqf؆[3,MÂP\9}~w'/0޹ Dz:,>+_=oh&^&IebK7T+ո{ `AÃ'xT�Ьb�9gY^4f!okҩ~U`?K9Ml$U ']-4rGRţ5Y씢}t\*5c+r$n K]ܨh3u4761X}n%,%<+bS 45U~f0|A>3q* }Q8j@R'6~ch^Yؚ@M%ݯp7DqO& B_l3?/)f<I?OYjeX2VX,ҍ=~˚볊[7)'oV㻦.2MzHAn yDB<xjY;ab闷12NݴZOߑ{Gr÷ C‹2^ҲdZh:9Af8`5 tuDx?xV篯Hwy[b2ƱP�Uʲëp lZ~34i3 CTIәʚ3p=\?`+M@aٛrw,?aRE ^Sg6]EKn:~.|DDɂ�o`!¯C<&}pQap<%WC{И;]?8FmW%`~tCjw&SpxACR5o,<Nפw$FȰqF?:G]x}ʚ?=P7&? a!JfXz80�J)q ilQǎ.sMg((WF=a:fD< \Hl-%CƬrZ6ه o~x;U0fplj-݃5WصUiTbF<ɒЅTc�D3[._e ٕӛ+ywIf G "K _u{7뫫#EIn&:7L(V fwܖuWٌ&<YLΜ0p2;fn K^_L9<66}=:Jɚ PB 5ty�~<o ev pg>@l!RG:9<tӻ[[g'ΐUsY�ghn'L~ C3 iUU;,PǝNuyvcE2921$n2RU61Yo & 5>lacl8!ol|9:<=<k]8kSx J�ПV:}K~ݙ1 a18&X^U2Xepj,x=m PC^4!BG8M 7G3g_Z}Z|ƫQ30 -S+3znX/Ⱥ+'4}WqI{HfԲW恡FC?xB.2mf!d#ľfɉ}NwZF48g󣫁(Y#Q({E`#XnPGW!# 0Le ?I%k(}fAZ*xcչ Uo:&Q6~u;d4ENHfX`?GSDA kfEh)h85 gWAj�zB hNTe )˂LW~6*bl)'A:PdEy.q[btŠϩ1;*rO9z<�Rknd4r-�Ao@M??/IVKd<psKWc#Q<0KސاєrS 6ePOpG^�ƿvJ '16{Fc's_j0X!*3 '_ ؿ{{{{{{{O0FW,2]W`HW ɉ.;*B_# 9w?>(*ƮH^k0V~E';QC5z^"IHdzG~=Uҿu<cdؚlIvX iAꮕUYc<} ?56R1@<r #(Emm1fƣ^86/1l^'&/ȳ"u(~}=>1Z`W*ՇY ΖudjF#/ƶz̳,v荛^wyҗT~:hq57ˎ(Ih[Ul9|;nf)ƾyF휟іet#'b^h`ų&IwyMS2*IXX9nq-f|@QVܬfi<53Y1TӲ-ՎKHKcue)%FiNTFj}S$\Ar9 yE+@C^7 Ht.v jZqZ: }柱5n֔qZ<G:4i|yt=urpz|a-pY/"MHA-Qe5ga9#hT%[Et,Q:61ڻFaGciVM!Z-(\Ps/2˪yE͢&o`'&klY~QbKjZ3úFT芑53x<Momy/Uo%ȚTe P)3-Qx t9ƚT3 $5,?Tv T vαHs*zEl+k (TDIxY5e1Ҷ~ъy+4gB*)*/@ѓ4 K;Wʴ$U3EK`,\m*)LoU1(Frlrf P>}7ܞ(@|`r14QQO5C_G<NYE+Q8J9A3lkꞏa,Jc)~b٤ώt0!ғTPQED"G>Ӵ lѽ(IgM]Ur.¶hW¿eՌц5e^1tˉtNX^(eE8# 5$`˲(2^[㭣U( J?5XI 2&FC&[$*!v�0!VGP(#L![ߡVa+"/\ 6~Mb{AdΈPbƔq#>Q''s"uVƗD)ahܯ? $ÂZ-w, IV5vE&)iR@xMUQh]/ɩ8�\]C 3N4VI6$zd1ȳdNb 1̛YAT.Wxn*mDf~wN7m1)DD/tjakLnqE'fyh嵚ceh?UJC8/6)zD01<'Dƚ(_{Amx>{ =CWI“=jBn&vLņFzdQbCHQFsw <='솁%ť"zVw4nn+]20fK` @( <PZKO9BaxQ  TU}Xu.7t'Qp*@G`MP C>/хUg[!K<`^?HqxWFbQ7Ẇxv!~慏|FTM88GaIࢄbϺa֟_$i WshbXhưK ,OB B:xCFž-k\H1 >cBǾU"p<vGBIi5*QН *�ޥ2 UKߎ,-Wʦc9g9O<'Z# :  &UjB>1o9. ө͐(Qor#K򚪩2;q =pt&f$ŊԂX`wY3fu@.pLerx:St,?CTz;Ƌk-C92gqMiID՜$$tz(u\*'`hhpȐb(\cT+^Ief4n 6�xs Y`r5Nz5Ɇр;iL4Kb&.=VvwH ?xEݺ+c)ZR):I'y|NKHqQֹEw;zƙq#WolcӬ@ȋQ+"mū TT lMbE$Û'ZߐYn?jq{" zMTp_ l2͡.vV6Ӳ懶*p̔EWw J�h#DRuq|r\< I@QPt@U8%Pti[sULDuoH&m"p Q4r5m}~xegp^O2 6"D�N% v *."Qvh5 ۔P"KԲ%js.pFUp͎o_746~C BT%S@�M%A30CyW_S'f^)[Dbx aPP`)5n}9:tx0I zQiMCfߟW(XZIl N&h!B@XdwD(mD\~b'#JuEvrB,0wBn;<꾤(fP⣨lxtz `-ucuλٲmN({3 gbl9&4DY'v@/7%yF(/8`/?wB/~<OpۍDϤQrI�"ܠO3l x6Ddϐ5G(bKW#A{_?n|d{BY7jVqVl+FI"i�PD$w1EYP#A.Rv5€ۊU[0BSa ҝ/o^y篧`ewP0FS% X�^AE9ĭ W75 ֤J1c&y"|~{^^UE]7>{Yo4ѭ~aå2PڰKo�T`4p0K|?Alep(z Fˆ(|e: [M["v>޾,azHA>8If!%e݉*udgJ,FXlT[a='%~ T dGgY ɗ#J6t߂J|uv}׮Q4ڬ'QǠF,zYi  {' fC0pf2hQГ!u? CJ+Fkw9sO("bΩPVs`2$|zk I ]QE]q$I" P�A FjZk##R#svQ=ӳ;M}STH"-=ͮ߫_Z+t*!z +=Ƴjl5l`{a"ͽ>,#�f%!^|b k3*5dHbˣZVehAPá岧Uk0eY6Lq8½7ۨ@jQP9f9c) }\qldīerf�k{VGzvԃ�g=.#wQY(XTȬQ;5](Ä-gYB8^ホv>oot89I5'd1nӇ:Yt$˫*P�v|Bh`23 Iț?z@Npg,Tyy퇛u^Bci]_BzY e|L'* ~C>nCQs B谀C'm\Ut`]/vo(NNP;P )&(X$R-jx9+e.H+K7ϯ[Cze@Q[X38;RДl^nԷ :%1ߝd#A[6uU^lB$5CG^,z(p` րx[0ѵuu|E*_K]|>eѐ:k4]Zn0FlLoon9 J`ek=RDY٣PѬ%3 <jI+"KCF83u_!}sؽwݵez e9<tͭ` \egQ4Mtd@ <r';`RjpoJD("]ԿnH|Nv߼ynǭݎ " `t1"d'x}%˰,!ڍ%Kpa[WM(=>Pr|ڒC,1dMUW0"2dSh|ttފ!9näԩ-4Es]X4ɊnZ"#Xi_΄C;ɰ҆r=Ak(Ǐo^vs1T%Jn>ml6{bC؟VU$Lݥ" l*i140ݟ`U9|>5/.n8qt^Bo(\{oۍw_x#-%y`#t:yֶS, T=,Ry忷43) $-@q!;ژ߯Ӹ! YXi\@Fo߾|/x$V 8G 6 H9]6b` w!�2EY4Z >e" kq^8tJjrd A.Ce4%fxiccso Dݱ,SDQDu p:f_|۶\@i{tiV9+1aԜlNN+礳 <+bYS ҽw`5nPT7w]9${"{E(pU+&ԷU;Cֱ#5e|Y,;ϰ:Zr{Rj~|v-xDke" <$IבQOQA.Hi'<EzC2M;\rSx` LVq3"đ0L{ru{aoXWv8khA^I` U-',֏˧m O4tb ;A|-CH!#NX0" A4%~~tq{ׯ͛ontVB$LM3|ˇazDA TT#)h`Oq!:&9H2!<ԇۧ9޾y Fy; _잍4ue(nn憡'<Ž dh*GjnſfYl22 }vì9=KMApi[G"]Vث۫ͷo667o6޽{ws|i k qQex0'*<; Cw.gnowo3ahּjRXPr3�4`L~ZH]2O#nwޞ|;`vzAMjĄeE2;#??G�i3zGl:'6rAUPlGdBo '~SAu۝;_>|ݻ3=I3a#dax8Ӽ~AYߞ=Ctd9QX�᰽L�a#m!˶+i\q<Q'gӧݯۻ$yF1zX O'0#A<W¦,; [)w=XĀSgzFv=i`g8ţg:\Sa}tprz~yQw"l@~` h%}ArbYڊ8o {!�#܁-I2K ֡ qpo=8J,-, '适%^8  *-)Iw)f092$�STTsr|?%揟*XE+2bb4`݈�aȌ(&! u*O .>=xu,7 >?',�Pbz58:swpQG?@0l׋sTSA$iU?ټM Hn'?Ӓ2C9CP37#xX<b,ȳ926:dO {q 31PPm f+RcahiGۺ3-$ٳ3A(bd3e<5!)N+r)slˆ_t]D8xBGYBlLd HCNza@$2E@4Y{}4P$� +cxHYB ň1w>95b Q&݇5C^N<]Q.$Vu'Y]NyDfv/<0# P�GSN|o2ރr6ƻ"aNmۭ|teWI6MN/m84=$۠gAH!|p: ɸ$/p\�a]HS}m͇ԇuyIdiJ%xEXF9ͬrec<@ 9 [PhzV:GYneE;ؑWOz-0Րb�@LEf~|3 D0$;5DIG,%!?E\JVjE5itx-'<nX .cAy)e=FQMalN"0Q ^{(hvs=d!3h42 5zN[f" ۍJ|e,)9- :Du\T7xiG+yz$Ol_PUPふ^>Sm�,#E\/eh(1⠮iENoE4v]ׯ_3nSA^ oNZɳtxxw0DnQΐ}N,c4V$ TM-?BLOS`kfE�qto.r|2Ҽ,&RhA 5#+:&lb89pf<[E7YP\,DݝQ*E!p@ du{PCh3X ,d^jg6N|G;=cT"4dyP.y\!D7qt\Y'M<|:V\2l?A/S߾9A:I6ֽ<HȔ8v<]ys{*^ER%(A1ay8ҁ :l5|xwݸAL^xS�n0w%!CtmcLx}j${'IlŽ\6 س w8gh)VesIQKf`oCP'�0Y$]0Zxy4qrb?YN]W!$J;ښ$G_vd#rr tYN\-֋6_|}'/A_<y9vɄt` Tzݕ� J$1i"=|:%`#x8rǥ̳ 2aUr9HFuk?U%@ĜS&xx8PA| O-t-INB"ol)!.w/v 7!cx(LEFvPL :zԻ8 2Hش!"Q%Mc皐$ MkIEa0 u9HPB)L6|nzR!ɢCXl+d&RLi/wߟº ش"$L O2 D{%?yw!.03{LjeW@`;:xwF,-hdu/xQhAhaE2 :)oB6�( h+@YyʵG$6ЩHY^Z@#O>RF5]QT;0t 53β*\mfo % (Z-Jc/tuX)�͘O_ы| *x~vd9۽Û_a jAr)@   vC�\"6gv8^ڊ E.OW茱O]3b$`gH택_z'ج@p<{qk&�X)ūpԍcMT7޼ȊKDOp' 2c YA>iFZ<Ïo7L*,C q?8?k [CvLOMi!1ִiF�I)dģo|4aN4�wv};~x6q@lQ.Pmoл]o@qox I4sp2/3ӏ^olt>"bM!$OpqIO 6?߲[FphZZ}{ `*>{E{V[1^X9טC >nЄZo1@~ #/M`Mh6[G{;Wbĥz)syvjJB <x!AqGY/l}z]1»Ib 7,]EmV4wsF,CgU�>XE9m~=j PcEA6O3J�#rvvYC.L+LSr0o0Ѹǫ偭w =A%Zz4ý:W BY:otYh`ty ōqF'Lz g9eKb<V_ Pzع==f$<M�Ov<؆Z|+Oby=%-] 0H�k`�~BƳ^__the 03l_~:Cm; ȳ(rpq+Bqa4-JClTxA�0p-Gر<pt}wpNs̨w{v%X柳kGS N:i�o>K ]`!w$$mIL0ۊ$P�R7.)AG&|?j^}{~x>]X/I%Lm" pW.&xۻ'7)k<~6�IBH*61vS9%xXQ1hypİGnPf086nr<-śR |㝚TxSm`/$7S(#5 '۴L]_.w1q6ʨw7;h/o%/ ,-p00j�v=ݰyq-˪(87]*Kx-;%K ?>5E%i_i;xx "@ UQr~K出a8w\t63<(G>QPl߼`K+|rTuՁ*"Tޗ}Qe6'HaT1[lQE `or}omx,87Pȫ o5}9nѼ(  Is2 g´nR&>i2<-B M,Yt 1HGx,Eqlpp/+0H.6TI5ô%trVP܈0e#"qxZyD&CDїMLCNh8.< ˴)l�$]tGE$KWeޏQ̦Y+<VFɷKsv{΀a(? ʠhmeUMZ )90ZMHFc 56IBQA--bc$gtU恛vTa)Mm KtbOf 794q%B-! %w5.ے"a?bL0t8">0�aӮHG%0Z7,8"حYѸLNP"<QnwXy)C|9<>r1IV P�蟦Pcᶴt$"3Ux%˰⺈\Tp^A�?vCY Vb|<O"7,_'RBj rp#2j2 ³ylRFWx?؄20g5^B$!͡ ,jg8DpWO_jV%~X[A`F?xufmppX^$!EGh) Bj_W5Ď9i"oMcHEƾK ;;{{_k/fTC%CÔvCbt6_-жL81^<jXjc.*My&5;ػhsTX?X +(Lt~X/r5K t2۹m`3ޛZo+ _) nbcfOf(!MX'!�5.֋Zex!`~Z*R.z}~U-V.&h*gռnHS>?}T঺n(ح71{nx"H۱_(`Fvo'8] 3>7h({TqB! 4_G[�\л eCdFOo aXDOg+rnHwZRa5!~ؼf9ͷ+ WE8$R[@5Nw%u(Aj ^N'haܡ4B>yu>z>W"P뻑lXFw\ʋwYY׊ /6!fz<Zsդ$nH≵Fm?dxuKtEAfCڻdaK/LG<F`ؒPV4Uw2j^ `r+uLXHKzX?y�&J;[=9KpY^+.9ݎɴJK06v>Yct픤+P/c\r{A5J*TJ )A١8( Ii_$mYՒ\�=MgHWuOHwH<Ħw.ڬ;z<Z}NXfK$t|jS0� >o}p<R,?Ep c^Nh|:?y YFb}݀t7/9k5CM}~^e#B^=<hM9|E]Ʈ!3/ 9̰}shQ3L/!-$,? 3yZ.J([IX!Fo@krט5~ mu)*ne49QR1I+ ^|p3&?>bXXBQ�K֗ƈ&cX?>}4'97� $iE@ [�H{!h=oI=MC 28ݿ?Lߓ'wұյ P'ex"'oMi%H ~x_j|<jrӂ(  R9z9x+ qv]$k<_2hH[w2T//Pw߾)Z47HFK`h(�^PTO'$3݄wl.|kc<cl Ys{'D*~ ëdyτ3X 83U0e=LNnoH!zFRx;+mQ׀śth8X5 ,OO FcCaAs_d-S4EGAS�[a>P$x^gbQ($H<%<I^r?~<yR7 F@G>_b=:'$Ҿ&r 5܃S7&!Ry4ӥxԴv{Ȫw9\{f FHsh4 hk @&1nGIQׄP|OyQ%A24U`f5uȱF C�\S׏hpeƾ5=촑ϣ˼ ,5jv�4�jxāqީnbA {w GCh VJShB�Ǚ^lT�J5r3Mzb_ڝ<TYq;"$Ex z"{9N ׀Տs>T]A1<f(JP`U3!AIqitkriC(!f<,S5tgIiο8ӠTF8$>)7KE~4 ?ā뺾rT{ j/a>Tk"|/?" nO'zPϧEhN$Z`0F4^$KG #CY O$H[8[ M?E-@Мr92;@v{|i5T?܃_"@w0q`BMQ)X yIyst8QE"←7?ů&tnV.aX SF rWn ސ c°COz\ҨْaF?E-@VPE]$D~*7ĽI^zہv<0dCNh^& ݹmuPh Tչ{% @~$`y߼>~ꨋ,3yc p2vk@/\WKܨӲ.E3$7CzanήVqsի.2όXެj)-n9MMiݿv^Hq5!'% 41q}3 fڞb /* .NVuH�sa粒oB5)Xiuш[.2 b3`3=]|S4:)PrEx3zjgP_Z)RT:e.?Wd? f9Lcl't[GGםVR>MdVŎLu.iFM2U K'&Em#ߎc_ͪ<\79& ǐ ]xH~RL#leBpϧW#9Lsl6z'hixaEjc[t]!z!ͫn1_Nu;5v4g�<,PÒȜg@_ټC0nU(=S2fA>9c!sixL BW3$CjmZ<hFȬ UTlP ^P+<UDIFl꺊'2R8+ f^h]AԼ#wج0?p`ODx5vׄ4i-HX okT`6Xi1I.`ya%HO\a2z $?12j9&Ë}xU)$yc-E,_?ͽq³_5~_5~_5~_5~_5~_5~_5'jcijݼ$HDm4mx Cc+-I4LݿC9jaT1H2ROe,~hQ Ջ2 M<V9QA*\c|RY/Fٔ8vH3_NCG4pEzm"ڔ<FوxR2|LujKZ꿛euW:-:Ñh)q;x`(+t^50I7h]]#4߯?e~Z`d^ydtY2iQD>Ay{ "jfT38`~r$=ыǨ1F"GY >MAvUy}I~Ԗ|ZDFbRpɆmgug0q`i*i3w~ઌ5/(CY²M6c9ד2͔0o 'Yn/O:fGv\C rڊlGd>_-yIMzDyj ֋:qM7㺪*Q0 ͠su=_;:zΟc3Nul jXƱ[F52 tAC sqKMT Ǔ4Piti͜r ȧ*&*"Cٓ<t8K0$ttY6ܴ-jO1(ʪ/x/l c[]5хU`_{Kt{�'7$;}O5;O:4\ԔjJ?lG: yJQY>e t:]Ҳaz%x2/H iUO~OmW%+3Ta Vǡ ϳaԄ1A:E=("9Ei)E䩟)NePb:~TN"S5U}ݗ/3tpg|8y я:^U1n{F2#"ϑ>A%DzK #7*!^=rV,/Ȏ#sLHV2@Pj9G6RBɦ]Cm9`EfOr_-拉/4ꁌ(;AvKR@6T;,zQ|$400յÍxY3 hQQ &3L`Sȋpy^y΃ߓRxY5<|FC zDw4Q2,�k V" 1'6ءʹ5/1RӚ2fˉ:æۦe ?ig(+0=jƓ98CȈ( 5X -j`!_ ^רCBkGl ѥAM])q);~HA$CnKkKƀC ( ?P4o<Fz=47sۮZ*?ae .7">ɍadġ$PePɚj%19HEu"na|+ӆ[&d9<^~#ؓhtz dzbq^XPLO\@(bW9 ߗkkVoOQ,!iȫ~1|2֙]7innD%kX h/ j)K/DF q lY<Z'ٓ8wTqp؃+ W3iW֐H1$Q&p]۲ E/T5k=CXe%" b~bjlH r)PrqFATL1-S7MIq_6o|Wgj2ω2*xY wd6Nv# y#}-DQ |c_#H꘲*|}d`S<lJ""晊hAV0!=r}^T_t+5Py]5L]YQL ?i[BZ/QL+0~ˍfiQٺ&Q#dNB %/34Nj@b^ݠeEYaU�.Q""ryZ` Sۿ(�iFZR-*ϒ$Q8 7MjwEq`La1JvXAsf<F@AI f$iFEE~h5Nj MIȺ4ٖ"HUTDATnTsI *`DAd2yU'{_:dHuB4ٝ%Yjɂbٚ$a",,U+q5]>B")P&>*-`\?T;HMQyC@;%)~`"Kj^Z?bipk&XM` F Q1,̣mJǹe!.>/]ʭ#M`I,TχҬKOy[FPd@ZLDyTh ,UYW^hV}x>]p)toR7Qgud?y\Pͤ@Gf 7J&f8VWel<ˉrhyM�5ǂAE?[bv=ʭ Yu[*,Ui5ڋ8dp=?;:tʘNR=uƒ:/CXtn 3]frYaƓl5(Lkq}Y* qp,1Rg.`ɥȔ9�nOmo}i*�1)>Ŭ ]/,D3" _@SHS(?&4d͎B2r^dÚ61  �R@5O?\^|>u7IA)y5j:Ø5ۃѐ*!Wed'tIQh('H4o䐂ΚL#q>L O?6%s zk[̱ B}"%1:4Gz*f2 AO0A#0C!F<Otr /{[w[u]ޅ% h0)R, tXP;?) #VCP.#c�z'5p7 A{$Bm~8Sݣ_KQ4CQN YP./<$FI(!I.?H|~u |P|j:r8˘)2�| 2W;?l|ty{vI"h!Z5'zx|I',dY.ECs IqX4\K׭p:0]i x}U%0" N>ll}|0;[/E䮞.!O'Ӹ0L™(Z:(쉀3ȿ?rv{B! =eh4Nv]2=dEh}Š,��2Ǚ" V/@':6(X?WiXHϻo\ J b-׋Y]iUe1#VO t{~ovc#52@ $# j{՘BMe@j PXpPxP7ŭ"gd@PR48o#pצ9s#H͉kX-WF,`f1,>YE풼~hY;Nx8�Og jXj@y, ͎]2ͽ7S7qI"BծdvdE1OrJ#m eA$ʚl^jٲ(EuK_hioz#"(QnђaNQ\.J{8p|9K�H�ټ%~dTUT͉{Ǒ,b|34 ]y} #}^\yq ~= dEFȌXkʈٱ!<rJ+?tyN 2x(<1NusxZDӂ{DS$`!+EO8?)'O_ʅp=/?$?~H֨7:BeEr`$!�M}UrnƾĵַZӃݽVn|0Y\:#i!&i@T(PG+:[l5dfYd8R+)�MhҁJ鄙?}v.))ehvQ_>\[}w{y: _7^}#D㏇Fl7bx 6) C!18 8-ĒVG l]=Y}eggw-WLx~+^odl nLgbO%4ؾ>Y!+UV7 A$ӻ`PĮmvw޾_(~h2Nz&R5otO/=u%&o*ppG}:9ܻQ>߸h.~<;]?i|MK6"eBq/ˏ+oޮ0i/pW<HOQ~hK?A*Uq56A>.OpR;۾BwBfGUR:fYy(o/vns xOmJ0?m6b:Ib)ש^]6EU>ARSm^v3vz%/[G-J99Tw7r+ '{66wv7VM++b@@VN@)_]9?pВUEMJyAF0z2Ɖm݈aoۋA뫦q[{W߿͛>zԋMYnJvw2vNޮoI#r1CLOK(s5SЎP}B+:UJGkVGB;ofJ+ж6vWef^~ʇJ[$<m%ՕG{G5A&PKm,2U +*4RI;)@xH?\5 $E7Z# ս+oVV߼k'5^6KQ>:|8}rqyO~]yMd -2]]j^5<WKp)% 7%=_Ly[$L(+4ʶ]i !ӕ+޾~ayqP+78P|z}r~soSJ\#cG%c"{!vpPTH>wNvGsλWK+AHhrBvy_o߬e\\mV*mN °,o/V{:}d]((! f*fIw`'0)ZMOI.uT+<G!}"TyB+zI\Z NHiIjG9 K &y#Zdkߙ5|]42Չ[O1(15@oNmoozzxqq|3ZaY Ms+ /EV,*oL;U·',!. Б4& Dd덋OXެl^U+_NNʅ eDz#<~}fo9*pC/%44Z2M׏L9/>&>%qõju@vׯ)N]q[ (BYKs}7]|}\knDQzQܗL�04uKwဢF>@5 QŅt.DiJ˓zGP w כwߐ}\[ܸt�!l˶v|S7(8h3Qf|Y5O.PROW8c`ca?J{dkZ++o_TC;ѹrԃ^)(TD $KTg_U{t=}GlG/' T|)7"?(_\C!k+';[WF&y7.,Cx)T^B~}SmVՖa9Uz&4fl|" s*Qi�ᇏ7iKnlW q}TgHout+poKm͇|Vw<, l m2݌ݹf$RGv0}ek>l}Vޯmmh̀dt r/6MQPd‰&В}GwH̺=*WUNR]˖%poŸ q۶õ/mIVW?f\,`1%hǾ$U;ma אhMm'MTT|PA\!Nc&kcP& Qh3:X]"0>XݼU294͖=6L]c34-\26Mx;e6f2-"]ii0= IQN]2&Oj2'ֿ|pP8v2ʸGX>ŵ=I>k,>\=L'g.?f үܙ anN7iD;@7Ԏ?o]S)}s^$N9ę&($Rט%`QTu;#VM<au+8:p}QvkvZCk0:<Srvtz|xz{+Tp6Dpz6&bXfDQguLmĢJ7|C< @L6ffeq# ǵM42ǗN*f%9$ 31BݰT;,i9 =^A1{ǼF>Fe8rÍh٨ 49a7FWW?^M "2@T eP Ʈ,[-&ޕM7ջZ7`|H\Yx8$B1bݼP"z#flK_mw<a.M)Yv1F.r!KVlsw䁮~X˭T_2バ0Yh@L1u8)VV:>}vbB&0:bᣀ[#ß A:."C]6%3k78ʙ':8|TP]ENPX Dk7%hClK߽XQ s )yaJ+M N4'&t}\HGH!oB}݉\!7T[ N9T3͊HGKELFhBe =ytvެl"pxA1<uK1b|.^b< ڐVT <6j )AG%ivTLG8o9-ʋ 0f\iaa BF'oVn{J=.`5Nw r ;#z?pn >qE=!2mCEtX*wstD=AhBfp,_[yP8>-4fad-j'|Y@[H2UG"da4E^ّӠGɜy-JduB mQo2ϻ5N4+)Jz1~,o[~o9S>;ITdABp@6m|90],x^0ۇ)B3&>t*d'zx<P)xU>N(˝Retڧ2Z(]\ВCFOS4"tϓÆ_.S;X32BGHsB)HdJX=<+Nw4bg6Ŭ8JA!̆ '|nqwŔd#[9 @IMPW_jD<%YƮxy직*χ وcK J܏܀6ͺ@֋,pBHYԬУi⾊i­|uLFv]2iDNj<s̋"5F~}!0u æHd7`Z>L*O,dz}@Q'crD27)H]]:`�Z:TI/P3Ў%ʼ0]󜀰s )C"c9l2W9<h+f'RHiLynCH#ڵ7ۄB yN;-1IpIŐLyt ?6[ޤtw./Dt0s$B5ʨ/'ll:p-z6tMeF^c ==p ݻiHҍ^`iwgc&Rws-APw8uu'GK0A4p*9X@O(UӢ"x#z5s`u=2?؉:^Rֹ:~#aQUa%Qf 'fi7|*iQ`@o[(I>tqsV~?u45Ӳ($ {chǵ0)]%̐-5}C=ASfЛwn$M$ JyR9 zIL;KBøZ.Z٠_8i\SWZWqK%h2jn?OY+p7 R,׫еz #P(? ;-h5?s FAENUOWMN:{ar ,P$ޯY9u/ +v~㠿 $Z^+]lxMC.?3]X!777v/.6׶jF-X> - !]B9JD*J�S(ˌx^Su(5 nЏC~滄X){F zʻ͛Ub:OfK.UwNNή+>|9k49$ډ~XJaErC{nLA2K@NRR5I3׊=H{[VVV겝Iߞt.nKz^[[]ݽo9 U"Ya9( a{v~8;\H\2c_)Hwg;>l>w9(ě?$|Ak7[[ۗO%,Z(sx .}z۫.@G>a%6�8MST:O[?T;:5* =8>=oҖɊ<eǥ3@]8V wWJn@D%@ 0: =]3A[>}>*Q==OS OwڢkXahn7E)"$Gѳ9*+ͱUve/}oωB1eRrZGW Ywi~H\ln+- ^đYui c$CJ qU^ȂM°@EBBH& wN)\7y 2ʺ?93WWu\򍇃33g. P 8e"ܮQEAhBr=N#yNZA$4eݶ)<<Z~ţ@7Nf+=S5>5(5cةop()'Ց*1 l2LJyNBuM[U*@Y5W?itgbRryʋ2SA%i[b:�Iלdb職{CP|e%v\ړ ["! -!*2ߪ5EUU R|qnK<ԄV]/(cy_4]ll y2{Uq{T˓ј4k7mIP믪:wOFhshCA4"?t]CK=as/oÕrwBXF}<,PS(9aU6MI6M_|R9?"Dip ~Aqvp Y837; CVz{mN^YŻ*ВeATM6K6PH;Jm%l6l6'U6Zx-hqNraVYCl[^<t{]XC~R|ہ^*~.MEWtʧo[f8L  `0NЀ(?</[fϴ{hVΏoZ#g, R\w*Sm'8(ρtTv(Y(AA{z:kiCȳ"gC)T@g7.ے)/btu,0 M$9_\ןNG"JͽݺY%MѼ߲hK, I?]"VdIn_CRy rVE%6Eb`c)6=6Eid:}8\{X8hIEϻR}Q;\P UՍxwh$NfhܜTx֤y}@Ö\v.(L,E)**>]*w(ü,MU-2!VjN2ߵ%,H/b Z75JE2e pMK#MVY/_WdM7LwMA ;jَ;+^R.$A,UbS*`aoG> O`%*!/N&n677Jzt'"?#[>inU0RxM>X !)9d6vJ{ES6|r5&vwv4qB>p<?p7N%,d>|(kh$ol:&prݩޗ/C _AJb`!= ّ>6p ]&6K+<=UId"׊lHS\MݿpD&>mޑ 4緸{ ba"+e+e~*F+Iњ\9}BƝE=:GU\&|oIl 7KiUn9#8 Q'csüΉa9˰~ypU$d4o(n: z_1(@8 AD->kqW0Z%O`Fx6Uܾ>,t [nuv]&AHV"* VM)iP?۽1xzMMO~MK=a3 Lf@RlgTtxN4)xkS5U\Fs2'[Nͦ~zwZDp4b>|C, ۲b9!\_h25ODI Ѵ]껵sδ rccghٓ>PLt}W$9/Fi+ڦ޾ z6a3ݨڽ1޽]' F?'^0”wENGzzz"y[r_ƠG箶//eIEeR'p n8%#w!=}6iynI;泾tnN8Y:޺lw68g-ݺ(A/Lcz4(Yʻzf`Lsy|Y{zG6HZPAx mC. U~ hc廒YQ^ST1aѕ<-Olɠx쎿.(�0ʕEj۞yЁ ^iRb`H(-DӬkciNQ8r\Fic> =Eѣ3FvtYQ5T {yk^M!஡B\㨲%Gm~z! ]<L)jN3i6LY`%Me+&;C1_MZ?"a߇A\S 쵣a~OjvW5Z?}~~^`BƌӞ06fUAG^<;mAz-}sn̆I3ӽ2cgDFʿ*ԏlؘ~z5c(|Ps)/AhjR`t83A 1cCW 4 c]~vT툲A;#A4LF*WBQ)[HEڧlۤA+"X_[پkq3|JbӯϘ[W7g K5L 6m0 ^rp _M,Ӟ+}ׂ>ZbWI~>Z%-+;9ڴ 0?ވ 1d2`O`>c;yץ??=5\/>qgd/Sq`?#gsl-b%i|Z۸49ٍ"-& o:~SWl'T4'ͦIS ,#ӒmoF?Tڕ/[8Պ#^l}R(]]>4TyzQZ p5U'ah A�CdصxywZk's [~~oxҵp㓳;y3^h<~Խ/2/{gp^L''tFcp[&Fؽ܄-C*W-Q4?uVmKTY.`2*.4  SՇZ!ze| }<٫ӽDe_ITobN/ <4 Ή2Z7$1;jj7kz?~K@ 쥶.w7gRպ\-(_q^0χuàa E[הF+UԚm#~ lPm^8Iy[SR3,'@h]HW=<6Q"߹PW*FMX@,z10oanfEl-A85F �mH:7m[Mם2h똓},,Xe*qd,^5'N^1Ji쫄X{Jxqdprg� t\Nslާ~E'sn8 " Iw| 1`rYmoh`04"MW*N3\bц)T]\S~||GP #V/xa狁ɷGƟ,c�O&x(v~Z;{^1\qXҟء h;E_*5 Ɲh`ylhG/qAq# lrBSe:u" m lPmj4Q 4;զ`<jZZ]!~dIc[(U.N/(%|ѷZWMWPf�*m٢@CJץ(W'M$ho3&*W[תN7$$/tQ,fҼ* e˧OLɢRYquz $@O8+|qyz[R |<؀:&gUEѭt<HI//Z\ao2rūr7*:&LW%Q!301e}Y]jX]+{p U\%'ԱEN`u4zr㥯[S¼e9Dn1(!)CSQqih KYULph<uy~1oȃëPD͐idi20j(Փsi*Ҹ#陋)Ϳ=Y6r \-X 'E&E  t8*s9f]G__D3M]V '}�%B <]H VzsoPu78o`Et:rⶩٔ9Ŵ<A ?C dJ|=ڜp$ꂐkjے`u˜ g!C3ClR\҂ڒPC5/f�q2L=C1_~jp0v0l:\],&Ab&KS܁G8x:Bqhhޕdbl3P?۳KBv?l6$J;YQy�"8532L BU{Ȑ˜%M"pb矨ܐA`#6h eF Ɖwd*Mp󍓍(EJdVӒqN5xx G&#QdY5u�Z)'YDg^oOTtjwDڵ-]Q9MŰ MG⹗x:{?ϟy<?ϟy<?ϟy<?ϟ梨ڞ0]]Ki $piM/(Q=(#E3N03fX9}_zVY {Ll,xIllcS2qynhB_CxJ",kAĚ6kF1q ^_dW%&p&NcXF>U#a|̥= pXUdMb"n_$ztgܫl?t(Gh4覑e8QC:=~ӰJ p#q1M&]F-zY&]kvI@V^^L Ī'A?[R1Q4&aPv<O[!Ϯ8L(s[R>z];PӰ<GnV2aqLK Y'%; J<An8/B/XVԵp0b<astTv=ZPyuq_֕j Ovb9\U7#z ; 2ZjR4.%c9~^Dj縩 D"9^s -f?^`IȦlk^a1[n78W[eŲUFNޔlڎϵl!KސNХ˺ L3u1vu:W7 ~CLǁ!籝 χ?Opd:.X{lAX h\|_]A5bP4LEQ۳zMh6w>(hXf)("W^L/3@5n^ڧ@CHբOӼ0�TΡ(Z; NRl 4HzȐ:oΑLQ7ޘOF`0o:h=hjc{U,+Ɛ{j][ۍo<%+2^h}$HeRrsPAS<@h8]@ATXq <s~-mMUZdvgL{IzqضqUGJ!81A6 C?hJfY{[aoaR#m6J>,O#lu&wbP}&$8AyXWM#rwۖx8M'E暲(;Es V%uAz2]=FM;$MQKu^F6H| Bɮ<sEɏ<V(f)Mc=i7WE54NM/i!<ikߋ<H`ƈ4HXNw$ƪfaٰۃ@oJlLqK@ASjו8A037_>OEhJm<rLS50dAǐD=&_!kz8 H<M=TuJDL:)!¸V1>)B$˩htyY64�vJGzyux$m> KčDĘf 9j(FrX2=-jxDc#,hߍfS1?p^60JW|OXeXs 4yZܸK؂3 eC邂k!BGZ+nAM܂,G݌xPKq[ *X kS.ˠ�Q Vknu?w]F0}vͧ,@i&"/±og:1D(?Vf2zkfRbG1궟G $Q=F1M/b_>Nx!BY˞)4UY蒰dq5$q\iXrix+^(~ا+i1�(glP)v8.K&PL W%CIQfw�*1q[o4Ƕ/%OR[dQP`SDЈ͖pEh+|Ή aJ4TƏFF8r;ŃB\/EgZzf߾}(%G9yGŒdq`ңmYNQ{iA* azs;:3\<jZC] ]CϦЪil| FCok8/c] (8AXJ܀!%HyR)@pjG[K[ },ct[E*b.}HSR^!dY >ɰ Jq,bRGCpO#_wwk@~4[ ~k(_? P^yGT.|312|?b)Jio",(iY}\.Ch}1 NͺA/TU禮ܪbVd `ԔC 6U{xq}wS@p1ч#"@ꨮT/GNm^RT͆3gHVj R3P Żօ'Ɣ1;ɳ>Egqf.)Y(׊LײyI49p+Cނ:`%7—V_l]Kv4 G@qCaZ_L#-�z.M>L兡pG-tm)�^TTnbbڧ !`%A. %w0H,Ei\Eg[<8D<xtM6S)7>A@J&U NΔ虌"d12"E֏9G(D fA^,vx->ڸ@3v>UL:_vޭ|ZqlR(D@%)R}4| N{9y')E n,v}C-'b:L r9M|ɾV߬~ػn)ج!TsWDvB,� LgU :W(<(K q1tR[QhFT?zȺiZ~FMCQ(V x&$e\kBPKvlԇEЛB?>Q 6BƸ.2GT'M|ɗ탳 .d>-5$x#9яS$!4HrkY5.2m `148{!<3 *F DtA\&pP�V it�N)5Dv4%HMZ8S^8bGu͕uGQO P.>}:o Q|ݿm8zAC~ ݆i˻1 5q=v zsVh#Des1愒"#Uc{f)ΕhTQ9'CZ2),f'{l?P$ 'Nj`rϿ򂋋8㖶PoΥT'|)f*\iw/_l47! dE/]̞d/Xu>qn(Jsn ڄHba3op*\t~)7?^q僣j}8T2U~L1!*~eHdkğ բF~IMh{>>5"&}eoU/٠z'pݰ? Әd +ÚeN8;Q>D`!)e.\}R B'EsNӡp{u'A~SEC߭ˏ_'%9$ւ!̨j&ҫˇr%H%|/ xǭF@VbNT$drqeۦx鰍N7JnhKYxZqeK) #@CB\ソ7{ܗO^O~=2{kQB w"^)O>?.~0G /p{ӏ,]z}|Wi~nTq#'IaXZ_p%drKN#sw|v㽭5]7�W/Se,eJ5SNƀʋZnUKW.1Ћx}Sָ(",W%'vǕw{޿988}排]3 :r*ѫWGQ-Y鸟C%0t pq EB{ H8=PrwS)}i\Q.sz+k;g`W7EUq(V-~7ެ<rK@CYvGա̼;~}!p}[h5w-ٲ囵7^[X?(;}+<XY]V]~Li Xq9Z"4㻷S@b6kwE-fh r-xL(QmW qf㋛fY:fm4}I(XY88:2?)c1FF.EOH߸*MRQ/6uE%RA;c;B4nr$мZX{~sckk,Q/2NwHߝ^{t(&2h|F1,tm^V4S׾#dH C��+z R9/6V׶NZ+>CoU,6[]_[zE;zQ˵Z]̦k7ON ȗݳqf t�!}~*]Y�2 )rgT]]p\q)AdXbo/W^|je}%vGnb' OA:Y',0mϵ4+44uKFA=gQ)%JVwj�VN'lrv˗/_m_[ݭJ%oJWF~U�tY,6a/(=/:arz-Ib;JY(pitO�.n볜<6NS?~jիo P2t#Gva и=;:l|B뱡v2Q&IQq@!I]R 1 z�h`U*x�0x :B+k+$$>hxLLX Ç?/ReI m7KRS}[R 7eoF4%X9UE:aN$C~ceիk=q oQ8Y㻲rwnNvWոp ܘA o dEiv$U!b.*r$g"J8Z]od*fh{fFx?5"<ʑpswFƛ~p–6*Z'kh.ISN@IvO6rzIFdsh{E׍WtzOYۗ%rK$I;m %!,IH֝zTNy`tT@n;6oO.pg{޽Y[Y]! r׫o?p[c,kNJV2 &`1-ʋ)ԌoyipGIojjV&KCG?iLT|\^Y{o>CCȵhǑ&]N"]8I�Iv X۲)vd}>JiaO)sCYuKd<"(9NO-6ly}RM8YL=U4sD1 JOZhy8c.J` x 0 S |fV 驒*S|֛wѐVŦO51 LW:nӡ&ZNWo,@ƞ^>qz +R�w69_M*o?\�ȅ1&@ ==Wo.M KV־5#vT=O @&izxYi&0xJB:CmNV߫%QG/Xl0bp<שW[`~o;lwusI9nԨɂx%q^%;E՝YK77>A^ԇ .DL"Sy#a:YirYJ)y<+c7%lcƾ۞ ߄نHvWo^ot5qs`gI&WSŚIZN9ַv2-Elu(94 zP3v7裯頇λ,ʈDڇRݸz]%g #{ClNL,zl|먃$}O:&E �5B =Ң?bj(~BhL$vNJWgw[]z~e*GΊ �TSw#%-Awwuf�]&5~2{R[ �\bf)F?Z646Nw.϶t5]$Y(ˍG(1e=.y(% 7ηֽkJ顎Yd$VSR;@z1%䛵vr+ܲmlF 9 zZPǣ̒v%()&8\liz^et(.3`9i8ErO_VKoY7)!.[(ԳQ(<KvGv<V,+# Emt8FLJ2P$iMlyP"c{XH;HYL0fniR:wKF$GÉVn;6{pq;G}OmApp'q8 (A'k/wG6J=3d3$iQ]Hv&ha|Mk\:oϤۛǙux!7O'm5!TTۗ/) ɭ�<HTWL/a?PdU ">ԥVSC"d8Mvܽޯ5Q(5и^p6R( .Y 'I<.4oE::#4boഇCr9ޢUp(4O<蜊$I-vpiB@*]lPv| ri&bf:xINaKe7t:yL'òl8 dux Y=r�)Wʜ s2: {hN^ )QvC! "`@vi1})ب]uM7(0u"y!|O/8%A *!|2:=8Du(fqHRQDh jo_r*kAh<"}&#יxwQ(-sJ0:zO *uR+ۛχr7g^$U^d /VSNnH1m(͘Դ}̧oD7#t%ҭ|OX G]Sd=}KIFZ"D #Qk  M2qY>J|Mq8$ti{oKq ,inɍ:谾ֶR/4StyUCB5 zG.eMdp3zPjǡ(`gWuQ̴n%cɹ6F'{{%i2 TQPLrwq5 ʒ>pq#_r0#KV<' AA�Bs뗂,c!GJGoݧ�C<L봚iM3!-`Th'4Oʐ<aQ $VۊDIG)i$1cjkЫf>$MZy!c%aۭ^WLXG3B`[3bLx1-CNȞO#-!̔REVVv%4]Y'm^L2AB!NiYN庩Z 1zwr у,&1xj'Mv\׋3O`y:Ge0I:f<J|j'q@ f"dJwGȁo|ВŸS5:>@k2C­^J!vGY9FgoӡF=$D O?#\-_r z>YyAXkmNXP@qk 7l^"ɕE+FFFhw~m 4  1(5b:F9"+No�vt˿O_P7\xyAVb,,s`mޥ v gZP,CС*is<|8ʴ M(ԾߪMQ)%uK{?~:?iuwy;r)|&e=fɊ!@Kkn|WQ)q4" bH#yh&eY?7n6oyՊ)=eԢe*nkן>]N�BSLeZ)cLbOYy{{mZ6<; =d*I/M{4<<0P󝍵݊�>em?/F[9?9:wsICr˜ Te=jGV^ Ev !]C',0H%W67+-#vy||uW*uKo67$H~`QX}2)!KFNMkoޮ() bXy0}+s~ZگJ0L5޵`A[g?~F~B߶zDe7w$HT) b w8 lUj<jf<,bdmƏ} 0pU週QcG3DAQqHj!佤q}}IV54P9e]tbS˄4@`s"/G"YYN]-T)ײ1e$د I ̏'Uo7? Q XBR8>z8)SS( lJ駣bxYX֏ ]qUu^$ِӥ 7d|%!KzHez6/zVQz?�C,-$G"4%^hԖ@L.;C((}RUG)I"?RϠC5|Lz wM2dҸ2)ilew/cB[G覙ci}}Օ$^.791IjŚ|͉#8 ݤv=d$ҤOYȑt�5Nom&kȊոq哶�+8f5ʩtO1M5%Ʒ5 KGi_~Z7]Ew#�(O26~B/4Ea!\,(N|"BVMmtI1(",{ Adv)U듖 (ڸ4 <'NGxWxQ 6Eg?(sK511+KIPEFhz"yt>. הk)Bi )dL̶ cfp+2uMrAy<9as|m(2e˗=Xyj>с ,$r7d[,UFX =ϟ)€xpt|xzu#Ц�Ϊr6tjPP˛rm娿EQ~^,W)_^_eKIS3'uiysr[o#dJ8N9O%xip)ݿyj^=o׼1@iI]'%.`Ϋ][ճO ʳx5ymIFNƳ,=Jx鿾|uU;. PJL</ Jn)Jtpn[sLvSD|"j!) �՟MgرRi뷗'?PDMeǮ2ˢ&%he{A]My" j&vB Ê( mXmËz cd1(ybGN#RK6EҔnI к#C*18r$d>n]Ha Vϵ^0D'}p6.=x@ ʝV%JM"㪵+'RHR'(v) +*d7_nyՍ;ѓ(!IPQiӴH_UӡRm,G/SFפWP(N.x4fa`]ׯ_mӤQf8JM+Ls6}1T%-Wkztvq mmG6:̦d8L]?Y}} O8 hC!jH feN]cRc-$l?86VBdog{AaJH1y ?[ C/e r?!�BnE`i.qT+m��:�F}U7g;`vOp2ʼw=X{_2B];P~&F?$CmI'R"\2UN:j BwW{5ejӣ8Ɋd\�vTζ^x<M[7)V29<>Rʐ]Z:(+`Bgww1ҫY,}$i"qs'#k<#/1 (ӣz]b:Z癖djGNϏϛZh\<,z6L~8nkioIUI�,o<@PY(]5Ym㢏OPlC07)^5JVjx"Gi4wDH�0À4휐d@Tp$f嬠<p xtR〄bv-7RhQWUɤ[WFVAޅBp~e:*ԏ7Υs6ɳD{=�Mz!E_/v֐2O�\H~m^ވOy&]NUvZmtHK`0a[+׷.b^.bTvޟ6yRy# a&K|\VG432p.o9t̐s&Ywocue} ;||xґi.l|8<Y:à ]ThkΎK:I?mc@ ֕o7Q6LƙwNR=<bT{-FWkZc"a>2_-]^ܵ`iן>UNgG;.7"nzrT]]]Y?FX<.D F'WoV4Y28iN&% %1`+ȑX?U @: :P6IHdxask`i|L8ѱq{̜SYV:&:(�atU7O}\H@ejRSI5ɱ^Nt׶ޗ''Pi'd i??.f%yۖ)]6 ;c[-?HaMj'dyOC ]+>S_`a-)A2GjR Jk]/8`5]A.#nS0)T0x<K?da�K?}łJd!h_J]$;EgSi-'hiYؓ:/' yBYIOb>9`d_4a>Cn@i(IY<Zm[)0Kf f12fHbP>yR &#mG6[GtI}p?!h͎�Me(rOSڏYϷek6a�$~g*Mg>g{Ԧ�wgE^h7>J`.DI Ćݼi)!FѸ |a8>M'>n\͟ƵW1) `ƌ/5z>Ȃ~ $vՃzWsya@ gCؑ @2f j>IWjHт?fɤ-_Ë%LZЭon=ku�x`$.& \ 19ӮHQ΀u?e$KO=,Jov66?ۜ_ __KSxu0ݸ7ZPPBIO B֭7! 3 X<^=@//CلB!no;Ѝpq>,-v}<FJ7N#xJ #諟5c$6 Gxgneku�D*~_&>jWg7UN4u~~VC8P"0m`Gc$0OfkO>AY%DA h~`=<]W~{~VspWݣPR l`1)͞<۪N*kis\ bh}6}s衸#vۍqMFѳB1$㲌7zGG&gIinurNiuvGqٻ]>~a"&%o3TyVK3 ]h]ܵ 8Q/-ٞ}~F?~EX( |qf|S3xktp W& bgUnRӇ8@LoiOmC/zZ5D3GbjڑPojѦ|ۢ@aa=�a qj놛w.nvQTmN4ђD͘{\2^֥f.jbGt0UN5qyN|Aǐ`S3r8a1NUyL[`م^ E5]?7vue f:^ w%hWZzSAJNa/A@ dݍ)ERˊ: <~94<Mh[\F8ZbYE˩j_Q8ϵDm>MY8ڭ�WX;uIe k[)$e  B?fC6MgfeF+O›F8S6W&Vo[A\|NmͶkTp$ʚbc*>> NW(+?#ta?7jy?�A M[VYF_s$~}yxl?)'G42Q>^<LCYJʟ!aI4Լ#wF"%B Bڝ-JBĕk] W0jIUU,z6MR xQ!(t"7F|IrIrQ@bE>-:lbd7ՎzoWK4~9ZNV<368)z#G>K zYtRQTʄFaY܁J_Vݗܶ XKJ%EY(mco0I,+(m[:khKƬA9ؕjG5I'4}9jJɪ6 aXmkQo5^N{<I?M^(;Mo;%XbF0;R աD+K )f_GQ?] ~jMDHhl_5 ŧE=sh. zQ)P_iᣇ`V.RezCo#O1][y4VJ]r/EE)jՂ_)4wUK3?# ,`dl$r+?uWIL:a><MuW*6e3d]6|hNo'GPVb%n;è腶 莟 %o Sz8^�=?q&x� ٙPi5i$4?/^b+JSz ZnMO5aNb$ 0^EVYŀbRPt糱UEUXOBUWk{ 1]Z:0q=[?BuMܘϱHGpIn ]74�}`Nښ`hPpa1 M_zFh6/[A9z X<Љk~_~_~_~_~_~_~?qfNl$%_iʎg et~Zrbb0"՜0r94iWZ\[48/hw$`~?RZ5&lU4?lӞ[p8Ԓ?0jC�B,{uWd?R&Y1Y>Χ^ho4E/BsSz б7YNv6eDCBG.Ю\{C#يz 4Ȥ�kN؛L& F찟$e⺐Y/,V´eygӧA/)O_IyU鳒Yaf ΋Ľ0 gR^7N3 $ (c'q}C$ g0SН Ntn"'l* MӠ ;Ѱ8$]ȑng-lV!DN}򓫭QF#πKF'Byơ'x{ i+xriMg=;" q) &0LOCpYƋu 9a[j>[rLMv|6o%hwO=2mh4I<<<Ǯxq޵]n|'[+%N Y*Oj¦8CY/v2%jԲ(iM#UCsA3Eh6fˆfHxv.[W QSUdqGYOkK@Sb>mU$�0- D{&=eD³ !1\Sl|q{ECTtw䇽x6/ f@&{sRsJ&85l{9@X4ǚ2#y/ �(bX|$�U6m ՃTÁ#ce4#A mHiU8Hƣ )@*!/ZI0U)pL)ЏFjc0$2%v̫,9�#: z O 0]ÉGQ?h-DQO'qH@KLFAU Gir9-KlgBn9'+sߒ$ [s$Ig\O ap>( iB%H0?.!IgmQn2 _v:LJ4l:q�!̖@MX̗Sade>:$#+ uI `eT#7gJF�OҬ p93ALf8\;|Oe&u6]khDZl$#FM9'0ӪuLr'+ g30.^,W'I"B1+A2[�1#TMlt4`QH^x;v%d н0n C_ 3uE 0ۊS:``yx@cH]EN}ƆXf@ՙ`Ar2glvAz wAyI9$#xKp^>(GW>:g)1N+>i+|A+#ѳ -8NiYjNRĕxJt�ܧ# sNf~ `{ ĉAa-dW#2:V`R Rp݉xN=2`Eb ]~R>~3cHuc4hςo[^<Mob̢D 369`?ˊ M}KJfDficWLS$h z VZbjvŽfNTLF`S 7QdJv1C FMBW;?;S4K!3>Lo*n=$"^Gǀ>G P<]K)_v<ϕOl?IMIP4+}?~/ryZToͦF/ٌ PQ9̗3x;V$k\5豴랟r[ ?y̺d'PFS,2EBsлg=,,9Бu[lkwњRIJ>5 ΪQ '0dI=7/łJ/(up0=M CrrYMS\l4<)V , =_>.I?>?̗\Us&ҿ?^ߖ 7- p_ Fl�36h(>{﹦Ηs1l q;oA=<̦p�onEŘǟD:E%f�'sf :C`Ďkӽ2jJ@G=y"Si1 '<:UTR40v[TuV.ĈyTeݽP* 'v3=Ir;6ȇatr^hm@h$c80G>?' �Dpuc2{dlhρIIb꼨cFy \1,AMpST+!M^<.gI_ 0ӥUz]M!q N?/d/ $`98>e?u[ӣaJAIT~x\L珟gYRGTF` m=;kBK&xi-f}k'ӂzS ؕh8-@) âg>8ARQu}~͏e1tupM8 ࣟ="5\4UEY vka5< 7b)8ݳ4Uzzcm㨭XkMN#FEL)g'tTf)O+(� 9rAb4_,&ҐwN=T(RZ;o^nmaTR$Ϳl<zubc?/JmG~pr`H"yW@$B/mZؽm:Y,Uv(.,F8:N3MB0 eQ;w/瑩iQD׺;g'{:ih(R:ffv9`"%;.AyS3?cx067,4zVow]k^~ؾL/e9~NnsdcGfudx "HK9*8Y>uOë7k C(#^dw5NDq񸥻q8l̙Oiő  u2CjO{V4 td6h ̘&$~muǶ.@^坭Ӷ(M,)+v#c m]9s8e%KB=~hu�eX^dxD,2!9Y}u=XRhK!qK\x[-\p)Z~BI'Ɖt18c). nlX Nfxgxaѣe2⛗V^W&WP /zI|xU۽=( YQq 5z30#Yҏ$[!t7By ggյiWfqzWW_VI'#2w(Ŗ:AϿXyk>|fh�ڕ<4;-NAjCYi �P{_W 1vt'|}]q|k4G1M0W_ t�&*4=@ 2STE:?R.& F鐑 cVVֶnAZ#^9Rmu'RA[b&qz23p=�JԷLCSNP'fZkp~VxxVVV^sA@ ׸OYjwۭ7{ߡWdߐ G � {o=ٝՎH+0遪|72#~\35NVW./_gd rP|]i�~ꁈUmލxI|,!òN)Dxd8<}ͭ# z;˫v垬o&0Jr],eBV jIܰ;dQ2;` [G{7lr\<�mfDK:LehW~u )3%(un[}(ӊzusm?D|:_n=>8AlYÔ N K,Y4lYLCVtW7,2,CӼIlgnbkc}'i~8A'rݭOr'kQ hIc9TPFXj3ֳS/ .97g.UTN4TfhA֧m>89X_ߧ' a4.+k;'.b0jL]Dd0G7]Ø! MK3]Jw{t*œ !'rt_~AC0PvMZ>X{p~p={,�"y%9I\J<?$zN/H[%Yagty*Dvlϟҿ Z3(XHƇ^�66(Ɋr MwJ.v.bpc{@A{**lӰ8r~}(IlIAG̉�ag*YwDz2L!om߲*SOIVM xOIfrk1��}petqeq{gKQ� j?O3ӧzQUUD\+`%o-igx \=ǻ;ǟw9ʺx4)xVwK5]WOMFdC%Ǎ 6N+򨧩I辊2bѫkۻ;=Q!f_Խw!TGa垄IA;o320vgخ_54WA8Xn\L,i6fw͇u.߭owL͙lI98OOx5c>2!>F \ЄAIx;[9 [PYwؽOQݽ[Z_ ɫ$5lj*<c.w@XlFPK7=gxVK$ )U]?9fc &z"ț[o2 E$!>%< ظ2s�{fe$q㎻4H)4m8,EAb  n ֳ7߽][[[AWWqf@C8TEADR3Աl50CL,y(V:4rBD8 Cxo $-L,]5ק'7qWVW6 #پP S,7q1fBQbn*D"]#B%JKa=bd^y '7=u&.7VWbl7޼td˵M]aoYil`yN q2FuRjX% Kz$zL�Ԟ"*QYUejQGEWA:X =v(xFuox:i3Y9x@"QjfY.;S&eY+[yX`.| ]QKGp7w6l:0z\f\=xPZp:`YHQ%, ]5pƖXLo Hk+[ӭ D2ˁ@U.ڪ*ASz`56;PJ2D?]ʲ<wtQ$Q�8ŘqUf JڶE"3V?wto?ue~P0O(�;Wfa!1ouFRKn00:*1퓃p4'a q<S4s](^;noo7(@",0=|%c4X 9tZL׷0(o4z,Ӭ)ZF bBb0=Ã|k{㘾ܽ޾9%E7MERyEQhE'nO:s#ef uӺĦS4QPm&xd�Oʲ v$~oisywСZݠ.gg9&WgWKniGL�=3*CGE7<ϐ鑠!!)%y9.Q\~St^dF2%$f!J9~.@ӅWs邀}oGIjh|brNjٺD1Tv Qt>-VU' a{@ޑرTXlhE3Gw�AfiAw:q5Z ! MJlx$�sU=%i]Pf%KtA&˲v7NHlH))"/5dH7BC!(՜lzʬHngt,H}. ur8_PCbvI#lAJjvs/Yp3I5Q p@2)f&kB)yfܳt\opҚ 6 ? t#hKP5[=\]lZ,msiPcU<Ÿ}X"?(ϢFqUxwWN۲aiMecq[r9lJ6RCX[Y_� |btMx feZ��:JHB= 5^SЍU u~\ccZRVy xZsLK{~%B<LR1v$.}ъ`4:MccARd} $`v2}9=284ˉ[5Nb0TpmhFq <V'ĢV%͛lGO�B<v4T-ϝ3-͋*|i3SWxN: –>-=bj>rO.>O<NXa1R�*EY A?\"ӢdCلSNhz?#S9(+ 8+2 \Í+2QָĆLt[f3X>eZ:!PA |;y)B э*4WH3L`%3јcdxӰ2�Ȱ/A=/8o <c'T/,Myr΀Va=jtw(-# (u?˲C4L5]5)Hy9 ɗUxsn(ri!O"]6[ thQ5bR@<Ж 3Rl3M7{C "Y_Jk pWTqi }}|coNVhcvhAz.q {=&y:5% QFy +L&HPl @u]PFaYab2nPDpLpo5[8A6MGz4T&SlTb%!7Џ 'x}$F 1XDxi�/?:Hx$чi tW# q *UNաR ,t,e89/ 5*,$q HIfA`-dXy=`}\bߑp;jI : E1e)/e;k,U D1 I#^5f4Xg=ECȯQ jH$ ,=aw뻪B J/24I)Nswx �`Y fѰpWbƐ8uw-Y3euYbj]a�{U*pLãojX8N@n4~̧Eljs1d:ZSN$),o›3b$1aŞ ـEC65C#? B@軾nU юec[?x&8NئΠd5[;?h�zL,)vfP` Ѓ&o^K 0 M3QKcӏLp/$F , @E`W!or�wiv@Ԉ3 gjMՈ'䆤CxTsH@̌S xfh"tvPu xSal+,۔ۋΐj F8)E %b�[}ܹQ ,D(6 ~(!٧h+YdEEV}}VH<ghp�Iu]nCaw6Sr#?ƷfyM:LhomྣCMuAL (]Xvǎ[kۗUՒܧQ(El|pʼn*G0gYQHcG;{{M# Ex$/"Rr_M5>mmp(+UiXϥwSD<EE F~!#:D4NY0QJ6*Rဃ�`1, b5Ӽ;}/ R*x5wxbT~ r z:l6J@<;i&BL?u tY${!Ti@ w`gh5ŀDfbڲ-Un'"� 0m5v95vG?H_ a2+x`w8�ˌsP L׿9Ix ]YfT ʃ+(3]3j3d Ş$!x\Dְ9jB%'FVZ sKn�R0>$9<�93-@,<]]kT-2�DTD1E*ftYIĸ+C|FI 4GrZW4onG].ntlM֠s!jy4pxq2mSN^F\1yP{!O(EI疒%NgJ E7,vTkR8࿰ ROvxWT}pBH L[a0'nhl熍)2OϾ+Fҍ׀6F~{CH3�|Psljp>&g 6F,ƝWwlQ{u[٫^  {Vv�|3C쉍77(z\RQ*L<'Uh,5<"1K PK7eUa,s<0uN gqm !sH׫?_yps�>Ra! &dف0nɸl14-X==8:m丏%;Ēe0Hxډ 6/C=ƍjZs0ٶ(ssK/?<i~>kwNN[#a1M [PXes<J$_+#+IW.9umQ: /#jqa<=Oeӓ4MG6;En~zQ,A6+v\3z뿬m 3G]|:UB,-%[NHy,ѧ~=eEboC%>8H&O6aئckVU. ԧ^6! XތM& V&r?Xk^vXOlEz1 Eo VH5K&;at>( o?VK1d,�h-ö| QVo xl>!@_AEQ�Yef@NU�E-T0,Dq ,zS<6~^(@9d$<M0xy/T3oYTt4$'fNky?^[mwlrx0I ([\�NUi&zZA8bʗ8Q$GT綇@0ZsbI=B*#9<Օ6neIx��3:Ik`qo��pCW@=Zvj@KS46d(NOvTfmXBk+W, Q*4bd<J`y^]PAćɊ*/IkwE W'g7!E`EkI`{e{rD NHq' gF~Cͅ_g@ @dY~p}zb$,B&_^yK~{)iBL/28(p~M@>|1 1O~# uUDZg BKͩ\?j86,厛�B"`Og!p1تkbn%%nV5mﯭ٧:cV7ΰC&�5L(d -jJ@.0 �7ݟ!-ºǝؐXpkPQhgeHZ[O[TMVqQ,͠81~wWM<6Bd^*w+="hӿ|p8QL9R(eGa$DBhc}Z vz3EEE5lK' UK&!% ̺qEǞA$O2R''Ƿ:7im^llt|:'ǵ=\xjdX~6/| C�-,#ᲃ|բn32ƶwzx.-Xxom1քmP5bA,lDƞ Q]]Hxoƒ>Ӌ Z  23z ! !ci\|ΝN7�z^owiVsz#Ao>ྦt EyOHzw~R' ,=5!z7+o;5cO^wddJg {O W 'M`pTo~o0bDu[?�5eXҢD^ݕՕ+ T.qY,Rp}e}ӥd'.ɭFw0b97.ϚTu'_f4;92j fƲkLQ*Ӂ?. t�dq=Z]_{s'0z15v  ;1Խo -i^wN&79`}n?AKay *7VWz{P2Cx=X$$A_l4M7Ɠ*q mX0Q\IiHo6㗧~O|?[U=#l#z@7i30^J6xR!L صfCQ*vx?u{(wDݝ|yzs<F<EPw|bTXxQXhhVvіuxn4L(YE`HI=^δ#hx(O򕩱mn9ݓ+".譏ǧ_K^,>t,  QUY9?ipZAȁ/NZO Yyrϋ CMit愒4tSATg@%ǖxn(1s  K D\Qi:g؍_B@x|\ $Te/xE%AԜ0LJ2'͏KJ&ⵋǯO`ׯ`, i]5g]瑸>N~44ep>UY/̇`fagfey'p\, ,T|yf U#4`7،?.�%Ihkʿ fUǧ3AͿǘ۝pܢ_M8qhBTS]/DK8 R9B1m]28TcV/zr@QQ{@愌s8O|X7= |V�Sqm¦sG\}�e.o i3R(1{O|SAtG)#(#i#rUs͇w'}V ;eABW]"epv{`~}Jɘ`.n{gxyV .>4l _E$r,RaؼB~$qL,;q_I>�>l,ajwUE9jtE�4j\f$$`-"�S dI 3MNseXCGW,C3?WR4ԅPW]AY2F#P ̨ssv9P3|k� oIn*xz 045i1(�$$H\%^34aԺ89:R$l7*ȋ1iLRW昻ptp V+qI4c*/V PgsIԨj6Z}Vk7)'': )Al?;V/8vN!SrLIOk< O5yd;yVX'y\ci/@_a1%uL塦F=I_"8s a ,7/s31,$ޏcyeT{K.˸6d|{dkYL,kp5gJ1ԐHg<?$!Xa ›Ã~ UIsKdZ>#Jra S+2n翇1U1҈VtbuRc ofImXe#X"7Uy o>l uq4G0VP[8?;z /&HO\ їтh^1tg{]b!x jѲbn܌ci,�_L3ȫ*TW}FfYѪEK /npUիDn ҷ22۶ v�j{?O}c igo ';0jIѧ[8^A0i[ܐPdf*bi?zP]#,b)Ӽt;{%9,@~^s_߉ 8{Zc`MUR :W�%h PSA&̴OF(H|zgӌq,R==D dUN#c `=a2xxApSlˈi /W,/īDC:ƶt pƌF#Am 9svQ#DChG =<RI4]PBF*w}JW䥅WGϣ9d$[e`],p!M HV%eFiՒD٪6cG?IjE9D EDիmz,&uF#Ӣ`!k9ЯSKݹddxD_-:bœo5Hl ڭF Lz8>G?4Xpv8KR H,Law1oBbFFWW7'XX(}՚zaB..CVHQ0\?,y`52k6SsXEi<nwF֊[Ar/<gjܿ=AANII^pvx~/_tޢ» ,-Oz (zRѧ'%x$m&|:[O@3dx)6л߾sxx>< H7'K8t%%}Ktwe#'.ttS0/ #& E TB$Ux,Ŵ!L0u?ՑݠX/q.<o;_܌0LAY5~_5~_5~_5~_5~_5~_5=^ޭGW2t3, nW0lߵ05'^~<H#|ߨǰN"m(=Aє䨪0+bz@  )׏B?^渆YZUOWF+8-SRQiӯ+&L]t{>8u.g[uyR*8Fzd>)|V'h1jF:7<GG+6D~ȼYl:0ω!=F# f`ۋWrlIZ| h?HցW@;QxJ>JB0^7/z>OLrz}?gt7J1>WFnT/y(#UU[sŝu/PP(?086-O& lzgy`I~,\b&ľeiۆt\ދ-t?p2$MAEQD+�%^v-HGM;L"HSPjq=}5<>oE5oohn#pYdȵ,իcu,Y" 4ueձAS*~ƀy<'{JEͧuy5&#yLX.yݲ0N(PWbibkGF،jVeh*ZPLJ^e,FNBjCtuf~0-vi/Ob"Jb8a9_^A:Y,(;NĻvFdDxhJ iHW,]zKwnRA+nEDi\#th|C<އ8al] e~G]%:t1GaF""6k{йA?N?o 44:j2Ƕ n(f<YL!t^EӚ_'U伄~>ZjxŁozmG ސ'EQ>$̵G@]^r8O(/5'�(eh aζIܥM_ ~E3?6X#TQ7P*DBt]7rK6aG8В>p*<C)5_QHN/<% nXҷL w@$D,Wh9kgQ^V-'(<̐-9UꏼUԸ Vy^/e�b.�Kk$MS"Yv :p}O8ݏ£7z&d̓/auAÂ]2rM(HOx8I|oH`DY9#ZD0mjϧU5ME+wUK؎`3`pxQlSC1tJCu$סR.Dnp"UjmڐcI n9(aLj յQz^@zF4~{|z@0�.AŒYY$38 m.P u"΍DB sD�}营9,+V 'ȥ*=c;g>Jě HkTQUHPm\-Ɋ|6P 'll7#OvcM3l\t&z]9AF&H/ * ,Y~ъeV3x?pTΝC|'vX@΋MY"tlZvÔ((s  Đ%G:E<K?}A /wBwq9[,E١t�d]BH/~;Z밫{##Ԕ~ 3B@7dD\P9;Ű!?i,� ~\f0u׳XF#G9am/@2Fu]LhSlsq!Q?N\a( zr?7LL�&2#+tՋs P#&:q4<&$�}wB[Wސ-4J*jIpevb0inwXg !&,ը AN(0}ZִUU@D+LKUd{h($(VW-,{ ~Qo܅6?aV/Ya1b-!ij6ۂezPк5 &җeqBFfS~ X JWF^N6-6#23Peh&;)ůp, _RbqkLvgV3jQuKby15#a-gYBQ<xKl1PE1 (=O_" 'D:2$ˍQ_>Քq#A,#~qEWK . \51D$E'=:UI Jnǩ#ZRծ 2 0-bP3ӓOo#F +HJJ㓥f).^62_ u $uU~D3B׈yBd`.Jdto 4R]@m5%Fw//<݉ i/+(^9P /F\_/eDa) .xp4߿ aq8ȗ' ŀAj́9YeEg}V:ވ$c^6)4B˹+vjrD<]_q DŽt:`Gڙ#[bG:,/jFQf YJlMAc %ݳ#W QPu4rtwj3}\tfd@YMK'5 J6pᨪ2J<ܶNg:Rx=^<-K=dhy!jC*swmvm-Йf@pI@*{FGR Cb:vQn A<c|XSf+X?D}Slol}{B O p )8w^H v"jGjEoz`+{]$fpJYewqhH!sk\ӻ7onxA1d*P *Q&1ϲ-"aCT;�e!S;quZ4$%B_n݁wvӥdDj *: 'sp;7PFF!@-i&zYB=EsI/d.�<f\h^ FN<w6(iՏP <+,e>aN/ k1߮n\Q/ψ�07;oO;E .>^Қ&KnոLsɾKJT%jǐ܎Ͳ:_a1[vpzoPFAfYu{>4+g(TbPwB<x�]Cy_SI&Ρq9]!Gsgecmll�owOOϮ^0[dJ+,UO|1yAcXIQAq%>爑"O`6jVX �XOyEWuN%Z%qus9DA7>SۀVx^(oMr,Yi<ojS#"eVPvme}m*GYKxNuZk3,Ǣ_N1PL(P>d�L�dR ǰ=gG=($z"iyILJ05�-Õ}woI4pxv26[<8t/4F P0`amK^ '4zZC@=bx?@NM=N6 7/ַWW?ej4:ь|p8Ftg8[ ok\ZyAeFc@\30J!3 % �!O -kkkY˼oDͲdqj|SUȁ$݋++ dHH}?N,rG^ E͈ w޾]luj"oD쬬y֛wabkbϑp)V]/;dY_"2Ȼn{_^swFd3s�1sC^.n&*+m7LJd7&8pSL{ɪ"iTĺ],GO'_*F!yk[Om\r tۺk9Q1}|s{vF |>u7w{`zn�`! P|zz}je@ akHm=][~js}奠 !3V$'͗_Տ3]dQuf@ƚcN̛)Uw'>+2t-!Bt/6~|!ydKkn^w'tIRSWӰ(��$GrB<�(>nn|R@F!aqsy}mh#N 0jF{rl8GIKua\2{@h@I�j%Ӻ,�OW5$˩OGw67w/H0MSk=__ɈfzʰÈ䐱;W;/OS5F?3A @!0uwT@JH2!tTVx95ýv{A <2jm_IktyٌM7o~zORsG yx)̼u(Q$YR 7Z|G*Su:ns&\}7;kk[//9�CwmV=XojS\K$iB crѪ�hI8Ar%w,3<G#pxE^eQ2EdIu;/?nI(w=Zq %j{ۗ'oCRx+9tgK J<2ö4KT�.4[.Qե* HQmUz16{} :7GAPfLN:؛N@I&kZdZRj6TW/ȧɵl:` k >@ THgr{cc.&Zd,"ţh3rzWl)J,+}k:H9x<# qwr* �h($-:{bm}kgMƨ4(j#" Ȝ�QBHEN~ &vLfu7@tgeH>5d<Jѷu}nusfol~BٽtLJT# 'IL_&9 Rt~M$ua[ Q6t;lH!5uOut\XL>mpbXTBr<y#xx0, ;t #~f�ip<EFrq]arv:"ouW-`:>y ƸhWg-FTJsCԒf1MTW@\2vc8 -jf:}F%#Z<,R"[w*B "3Db<�r{g͡:`FϷT1FX"!DZ,8ϒ"s.5(s2mS_ Zgy= >EWeIl6|h˷}U!(rGA�,H1'~x}t;gMӯ!x~ IEqYd,U ~V!@XԽOv_odokl: ը,&KHdl &|75qnCƶϮ0eDFQEƳhBmG)])aq.OmxnwouKV8�y[/Ȓ8& 5D .-6OLwOOpP +(V9#N=޸*hMQuOgo{Ți>1~`#95! %0K,Ov{ C?p[]fRy >W$9?o~=6? D<@fϥH7sr@3M^xb�b}uu4iHXEȺ-8:L5I(PǶ O_}uн4DoN(nuwFS#zn?(Yro>fQѻ.މפ6oK@ VaD=^{ьo}98{cc6 *+ 4o(|(!#kN6lWj8q^(1`EhA)+HAy2, | C4|taɧO7 VEv:}udA�6[A $z"q4>#yYZACNL,\ѻ.Hq*$Z9KؾhH 2+pxFj!iڅXzQ{YߜH +ȋvY.V3 c-8|sm !Ku{5YPM te%1Ta!@r,#[A ߩXߜS v%tXj&#:*4EWʠؐ. g<? rR7\N,pݐΒrQ`'sxR<aB?#Y3Nc:xuY :>s`-@٢zk#e%>4P5t?uZH*lp\3ZH1A)q5&K {"ϳUL[/^wdUE݈9)[5÷Fv9Z*Le“1$ ux%h9Ϗzo29>崠 :aw z)JGFBJw ׃8Ksh 㪆%wt;*k&d @vB ID'uyQUHVbS\wr!䅳 raFGaϞe]:ΦG|sۓM7.jؽgo2 <qI0)A(StlDਪKǁc|x\~�޻nU>N_a|׹)� QT a8&l 26 @:$ p|bTy@AW5#qyWx!!e;]pSxyԓԁl럾Gg-iur FkIA^AgxҀ@|׆�HwJփJ6B(m5F~Ǿ&\3ȱ,oiG,uk:ʰ`]a|M)Rg!tNC#/xA;$X0,iۏ Jw He>xY)fX\ e8q Q�1LMZW 4&<0'eiR 1L#/?|x-N\摥Ⱥ_1qAM /DGRY.yM jmi^ Ht&IP9<x8/I|g{ۋˮ9 $\FX㇍v'2㉠bz5E; JU;#0 R(JPh ĉ p!*jR%녨`}pH_'!Cuh݉*6G)Xg~_lG�W, w^\ܙD)l1dphaQS ӠB!d&<^&t˃•98<~�g ^0ÇY!q$p+!M>ؘcGCDQRH ; �dh@=ՊFehp4&i .f5*o}ؿcHy4" ғ19^#q,M C *K <r+b-D,tXvo9"Ed3%nbec#^]^nox4Nsxe3)4lMʈkiFFtCelG-<0w-:*,)TI *`B!d>3s@~5AK >]7 IQI#C1N2&BGq'i<GWfE u,dj{̑ [Rr(RcaF ,a2^5+-x cM<>5H]ĥZx�"<GUysfcZAj`i,F G Bk$±@4H grʈ� ^>=zsFbB"Q}E(gn^mn}$&^ x(<tr@T3,"?MP��H7,t18I2:Hx2 Vy咠QN)rջ[Nձ-u~㸄ɵC9D$"1`tIIaj^;ּiwE8et v\!VhUm?k]EW 8jLa*su-}^2Ƈ�{fد5_:9kQR@8,�3RzQ 8ExyΎ.)4;cqf{^*tڌJpP08j+y6\~:8;T2'!5yt` 1/ LU-GmA=pO!J-�F@VVB!c[xSrh\zY5eYcAm/#e:@, uYf>to[?ݲ}G. z<h)LYXjJa~wWec+^<u Y׍>/x#EQ/f@N/OagN DShQ{UP|LE <ۋc[8ɐ-I"3@o@?:fV; אpњi8,S n57HKxv*oU &4@hC,fۺȳڱPx^4"C�Dyjځ7H nG>qkM[wlqQS )Agl.~eh ҉xݹ%-LH!T?"skV%27r deAǍ|6S勍HkÍ3xN:kV ,!/#_f>b1�"$$DJ̏+aihX0܋pT #l1/.e;ZZ#*4xB~AU2w'}XwI:䉞iZH:-\钩uu{{R4 0#()neg؅6W&\o=_^xM[�$Gi?8pzwNhQ \<?:j@{kܰqwx~ۦ,,\x$HN0uU1z|-淵kkrmP8t{a^_ a|,3%y.r ]f!r-\#)k^E%K܎; \ēGqPQpf/t)^kzVWhGʪ)w[$]p4e et:fx' Ww/{?c?Y�#;Ɂmݒ$[QORz\C<So`P-x^ Ldwa9$䁟w=u9sslM+YIOdJ#A eUud޵eeڎB 5@k߾m` guMxQ44^nxYuCGP#<H="tGDh]ǣDUf4Gn`.Q s�uwo (f 8,%nŊA!S�~ғ4d(+ -@nXȃZ1$XȌ3luh"{}_ ؐwg긮Pf|KD�(<[;Az : >ʺaвL]E0;m3-Ȃ- !Ώ< q(<;h|8pBC <}jmnu4M {ww훫fӃQjRyCLX<�+wy.e+p: � 4e:Z]VTO!OH ِ(a^N ^JzAL|x| p!LSx5~5DI`' У?d V^Q ,s ^- %xR7e⚆qg[kkk/o֫k{},4t^? x /UG 6*ᐓM;?}�s0lĨ`2i^Fkj*8!xu8Ē$r�K|Pn8'NcRt%)ۿ@B`ya`Ƭ.5Lwm}mcߍ)(F1�L2Ϊ$E @7 5K-OՎ'}kCzYE'�XdHe: lXy06^78R!(`OI㱄ET/b=}г�<-qûO{· Gb�ET}vs6 %1yIHHMu>�AE?I QcU#w-jUӶ4>ܘǣ(5jQY>mƒԤ}V7^> @לt_j �?&xnF!ՄP S1wWwC Hd84蛣k[{ 'MI{[oq/&8 m:.S6AU[XL :Q^Xl>m3wG+nN&B|jڤ 0FX Gµ)/ႳYӺ #3lC yO}ܶwl !5Td*[-m唌+dG~\OӣH# n/0T ~O,KQ͛hD5 îix ޚ}ƨ8h8~f}s}\G#]�oDܝ}*N<?H 5EMQҠa$,':5ǍͭL8&`,6j,叶$X.p$T%!XCQ$utqH+͞,t`c=(o8)}F4Z9U%'/r]L)qluf21i6ڑ(Z<FPt7ʱpʗ >7 ݚ5=iw{x M6<K43&*uhAwb,翹Q?Z,3@f4p-n"1*VE-c Xr-muj|T$#> 씞hɣ!% F(ynA\(Ǘ@/Ll[.M_HƠa-^b 'RyE%@1dQYݫArO+e_;|yߏ+Cj'×s_Ug>_ }|X"w7|;BCuCYK^CAR&_PG$Ǣ? $ T{"2 ?y\zl'�ȀߺGk[ޑ^^/_ �O6DF]Q ofX7[)=~xGEYPo8z~(Sj0f6jWB?>.SMVX8w2y{/QAUh=}%Ij`h%x G DAf gwlrx_pڂ?j1|DJ.R`l?c&[=ߓ7R],&?߿Y,{MI!N-!0</n˱ =BkEAZafSFܮUg,cí"wyb,?x{pӧx+ ?.q^զO]Ƅ=,yrd؏F[z xAN ^ (Z<lѝ�yNyX-j24v:=bhON7ȅZ?~Gn!Km|sESbx^hm8? *X*- UHƾ;KЂ#%.ԎL,:ov@h'fpF<f}?˓8pLCZ4>19QjH;Lv:6ceO/hR87oOzjT)kДYz&S+4f&�G6Ns _%{rh_8<C5>0aX_#ӕ`lI<rX?0?Y X$:9<3&<?8EnYJ&җ.zC<zl@Q Ռ(Z<|gΪEL x0un<ߤY~e�>3$u^պ,E-$$M3 l< @뇮GiWnpޤx&d3D!8&EC -p/kOx.XEI ϐ{;ѝr򸘔lh<c j<IRu9zHs,c{'cKŦ(h{rQNiF7VzW$ ZXe3!/hxq-!ޏMEcx$1:'$?QB5(' Bhzh�85IuSv۔ .󖀘Ȭ}wQ8^b5l>e\;&^hUr9*,D~i9E(oo }6x&q�>+Yu;8s|8{5x]ùWV-]k)N~D `GϞ8NFعJTFwu6a%Ip\Kh>!ij*My )߸j85CYI7h7>{ hFXqC2 cKh~nx=9eFxRk nA&0V:޴|K wWgϮXPj?}&:“{Nvbxq C?Xnb+Z*BSnpZ|R4O.:`ٳ;cuD(0љ׬(kc%}]2; iȗ_0 ܜ6h^Y[uH0KBj #]ˑ-68v#GqϝoI DAaY�4yjItw(+֒q9C@Fw˪^әoXN="8Qp.Dy.!*�pES4wD9P쑣t%=M�XSv(iG {쌖B|)<)PcEQ`q΁p<6@e.agM^g$_t}RD)sD!FhB)𷊓r3^>@75ٌ'E CYr5!rQ`<%^I?Z ktɈ$ٝ箆lm{wV єIb+^*~!RD#:`3 r4ܟ Gƹ)n^7p Ѧ$e8XS;p4b0]3Kf kW!2P! O;o]ZpYnk ^вLZ+~+XS$Onnb>ƋjOU-@ϲLƣG UT6EC|yRCS8 +�\k? $-ZiX?g>-8Kj%da^2?�3T^k: 'im[<omo%WbkZ֯kZ֯kZ֯kZ֯kZ֯kZ֯khQ߾(Y1(Mqn`ֿe9pOr09zc B$O#rl xѸiwW:?8AUӳ%5zc~<7W m}|aiY׹[Id%xż,'-[6{Ptl_vLmn7φXRUYu=mbQ1ϰy+qWQ ÷$yÉO3+:EG#iEɍTeqmQcwwW-Z)6BI|:.B^ %GЍH3-f/8FAʿ[z3@a7E5 D"M5)rQOܗ^3eN04 ~V7bL̰ -u',*'Bx:,K @)~^Fh8 Σ^,0CUBǞ)a瓮ǖdz4OT t&wMtե$Y,FqAjdJ k= \UA=&k~xBW1rM28 l8-F{c=\KNtI3j {DBF)xQ%&|RY>FB" ܯ#5q4|QgYlӬMu9BD5!/BȮF8y5NLUE45-ÉҜj:Zm!*gq~7idhGOr9١6OnZ͋}py@t8EFɢvd0V6]#MGwr18 nH<Pc/&u (i5aQ,G5: }rj CВ띾EDRelMjSu]U~W 3d |`Y'8xŴmˠ?7 ;˂C hs4x�Kk}u\Sfh :MxpAS5R)oCǵ]YGⱑNC'*'#Ț۪ckn?<9i]B[U}N%k>3ػ[ ;VTjNϰ-^{SK-q h=8bM{92 ӏ(mCv8z slFbZ8ѷ-J}M q@hJq!cj!$Id[­-ooڼBo2Ž~[`,Rw`O5ҳhZ&#)XQ6qN#.ےV7^<,rW=ѡ%4( =/ s7*t8 <_캄.$-l{CB92AO|K7~z3)ȐZdf"N`f %!m=4I]6015K2&m|X~Q'(M !A4ΐ/|;_brCp:) n$p- 3}z>_|yAYoYqn䀮X^;N8۟0.4$#.<퐯;pb1@90EYz ;Uyszd" + 5'J_PE#Qr=:j2# !C˪8̟D m<xWӣ1htd ^ l}!$`$-q l]tY]Bj�?Sga{qJ=#t1{2 &R�q#aL�yeN9D2 ]O^:/@3y}FU]s+S2T`2wW"gs+ pr5`'DsZ紆 -N\3ć4t“�8dmG(G /Y &VC[\MGTk($U{yNΔ݃Og~<utP5aMG8) ΑIy_@q3@-xP=|ϙ@k& aq^NpW$ cJY̲<#,o8IۆݰD�i#"iZ=]~yM|%!;= Occ)8 �JD�HɻN'EJM;݉Tg@윧I -:<Cvf8Su8k6FlS~  )A-v07 mDя�#v{H<ܶ<odSdVt `p< fPNһwqŦDv 8m\SI8�hM5X,(Xb9lMtu88TT/tKaEF#.ԕtpHU zBy׹;;2NJ#15i5&|yĞyjB7d\B3y@ 9?bf?,À[A: FĔxnxuxIu "W7R\@=<8>g!GjFb'hܶ8*Hq/Fc`uU DT營n L'$%db8!ӛ"(V�@tCKOhu[Q I2 pO,߉Z:*؈ +EsSc@IXh6CBghzd<M|eI7AtXJ<V4q };j6ʼnA TeokᏚrFNȧb1*,En.zXTm�^K qT}َq\)"|e>~<1הFc9GF4ĩ]�]fdqyK7lw f T|j`V{{@K|G[e2�XG^y#j20SȈ!M4<;cq|iD^bՐ$+"ig eio}iHz!2<l6:Iz_坤/q߂xEYd!'# ɲ, noH :CAϦ5z:׏58eKU-۔/w^|zӭhq9Z]eRP"-գ|/ldla?"s[5Uxa9wS3jH mxK6RVi*`o||vgph*)ЖE1@ֵ"@mUV*(fvDEH182RC7$D%c쎣 ;?\~~#=KG:xz!fYmC*; Bs(vV"DȾ ]HK3ɴhLpc㽔ⴭ" Qknz{|rxagb'UX<Nc 7qAx:x y�&"N89ETqx9[hoַ jڮDa�vxfskgǽwa+)b0 ]-:^j||: NC$,,3IEQ$ؚ٘~bc㳗;?nu( Y~~fqiJP<%kr~A>ku<3̏Q /|3! +"P1ئeX|٫R]˓k&$5^]Lฉ]lf;x^]5Ά$(uR6`.^1pdYe!Av+`A ]8][ݍ׷V5/>7e4A1 �ۊ.L G ԑV껥nEp{Gj%ݫ`N#($-# Z]]콿U tp6ix:d#GqOֵ (!أ ddqW羮HӃ;N:~d)xwpqr땸xG#ȉ#^uRȩ:2FZHn#%8d~Op{5w27/@u67^lm_D;$RNI hߥTGdDnP̓=<T984EW)% sk2xl^&P<M!v! ˯D`wܻAzx۩dkfy$AاG/ѫWd2CSymlCI+dY<,(?xR\f%?j3vVGDd]G |pԸ>౜ '''Go_^ظcj X} ~9yFhA ۽B:9;:ߓgb6)D*LL h1% 8WA4mJ?@JxܕQ5][ix{j'By]x>'(HMfV(Y,y@JggUhCp�@?I9 IW/gެToml{bjz@Q2EH_889)jzQZYYf=qN0  Gu!z*Oo^߸p^~}l}c}gI1xzI=xtru~n/??xrPDĒ3-< }="�˰cXJM{pޜ@[YrۓӃw066^nos¨֓[;/O?xf*dzAs<U{dCIb>YQoLPjI[)k'mV1m/[ٝ:2swvzkccss.ËH=d-Vhwݛb[>k�%'8 QXwsdAPzw�P"�̦P</:~A 0j2@bura ywn L~�`* @ YDnk`sSR@U5exyy#O/v\5 BXSR/M)22*kQ4dC=<IƛݭwGgwtҠd*|^|vP]!DDQFm9CWש)pT*b @ EYfiai�ŴJ78N`y*L}:|vNZCN9T+ XKn|V&M# &"Y" 5ЀOFf^~zx)$2O$a~(娋ojk}}ks}ck7G#A!y)#yX3T;F~<X;d-бy^Q�坮*FLΩ`U@Wƣ1Pn H>ڄb֛ AR@UQfi"^QǷR5NsqCid}7n 9j`z(Esuyvrqsuuuyq͋×@(=ɨ 6CYSjJx,G4 цf'qʆe�qu9AmqUUUbK!;5w^^vQ-YQU�3 AqR0 *?K`x!+\aZJ2Fxdk�bĴ8/Q9 @ߨ7;761xUҫ;"ۮ5C c#E@i q+qX_p7C7bZ R(X- ``klj Ͳpoƽx/|||,i٨ _b3&C} Vu4CHJTM4d�Xw%FI0j9Q(6) އ=H#}hafPŬNL 2J83 Q˵u5<LP{~Y1x 83S< /n�IfAN@ {O5 E\Ԫ4@Lt;hv1d*Tauw@Y`)fR!T"|(`2w޾}1&iDhW�lA@yj $vt/Dy_<)l?&kI6ڲTg< �Y=%fB^$=@9N4+0۶e6ݽoZg(1ɣJ #uCըX^@mk}7^i(P$Jdeu|YL {5U�΁xP$%owav_\'x tӐ%MJ_`uYwW.h-?f@e Wq0fgiv,_=fx{'on 6{^(NR++ׇۦcZT͠,#G;dEY7ݤDV2y^Lpư!@PMNB1Tˀt:{]yQ꿌|ߏn ~y[4;b(gEFi< QF$ }*h"Fg!̟@w]F(e<t6"M'ҺxXt, {BF%mC0m8q| {y˨fyY T;cIUi *Oϻ\߾U51LxaG*<H3{'jB4tp >(dQ7t#[!@,3VjI(t(~zh</A2 gXb2-]\j!S? 1&LAP."=^ fR)l]fI&1udž j{{-myui\`x^ ih;˼P0f"vݧxFw {SK 2)s$b`PMA3]@Iط`8oPq`xY}7P,)j+b\:ݧ[NXLW7*"Nص }pܓ|6U(?pMMZ8<a` a2M`F7cxh5d(fܫC+cHYY#`bVa8:V>+b0"`~Ŏ&O  */tZFn;iY9)#p":`vGQOY ~i5'gZ*nmhuDUS]bΠc fxLtF I^EUZ{aFyU�0^�f2^xͅф`h3 )}_@_|�KОoxf@1dϲ'mEMN Tv=hz^Ґ~*t b%e|e4.E!* '̓P`3dY|He@xd}tCRϫ|O IDRD[uEd0zSR�6TO�uRDBaFg?{t,lІqNMd�xyWNƅLQ"iN , ,��X,A/ M|yyU.6 gÛ,*ψ_geh?~,# =/gM+Ǝd"TE‹'E OUeauQ|Ӱ!rT!~+UŚ^2 ^1 bm{`;;[x3lZxo7FoHï'u rpaoF<@]S*#Gȝyxp̨c5}j{Y"(!b y {=&ꂊ%qG`6$1@yE:r�{-Uv�䀔 /7<f,E}%?T찚ZdAlTjJRm X~Dz#8V WD* 3Oȵ> K(6Pzy4MJDAR�4eǺXd5vR4r3HPSl1秧WwcF*9}btI0:GSzw<?NУ*spDqI9͵ !i D"ϏZcwyuuե8^8)LXWz)rIǶ&ߟ%Ŭl,WF'a 9&I bp,3<ЇB?Cpi6iVGl;o{$QrHM輂J d�ȳ綎F�aŰZq^ 0ḎCV¼$f48}*c bY]CFYb.>Q�)C !N�7(̱R늪PJ</, Nq/V9T]H-O�a"{R”+&>I&cM7p[Ol@sy!=,&k*7vTS)OCEs.lzx:Iy$lR&hJ^E]1pB4F�rYLNO[cYw|GcZ?DC 8-P۾EA2DŞcOc@$ a%뛻!/l<bO 3:+BX<pN3AǪP>ȭ(^pz er$ml+рaCէ OR�PO4v^ѡs 2'd4JmЎb^Iվ,:~]TPsݴKF]wۻk s5%^K*o<h冗7EpxJ`6@@. ]R"E@1uQBJmj3<"tqPg&b/ � Lk\QT=-6 4i(tE&e\H aW)c=C~{eW00i*ElC˔\U%&<�ohQӞrV [N K7$`zO(`T[h4mfgw>;oRaE,o"V!k4MzCQ<SW)A &T)t<xEo^ @cL4fGۛjIOˑĦ* uŷ7DEiDTC=^ Bڒv<xDok*ݡ%3%[`u7LɭfKٲ[oo�7"@ؼf4H< ]_ZbK+v6)ԨwA5fN 瓂 9BvÒ q7ݞtv7?,܊NT5$ | *4<WZYq` =/RWSvΆ Ci pr#Ei͍OpxŖ쯒] U/8͐YWLrej[#duYtnn:ΈU !#[#m{,%^o?Z٧wmo絬D86f Xˮ$td? wWdfM ,O~lG#X,w] y-LEMӛ20da̓UBbK;TD ewi_I�` xblGh!q2F-Dr<Du6f7eYP` .ƾȣ{$Q~bTj a[ o )J@ŋNܶEͤ#󄇒}Bg[' AOqA&Q~Vg1ܸuFI#9EV`S<${NZ>w\(tV&8,yN&Ϝl9|<�ŐDuG:/6ԕ̢Vs~gcepT$o"މLcY1-y鿦g^si2YLqci{]YX5?#,~Ɩ 04<՗e &Z^2Խ�'h5L[N2 ޡ)xw}o_mZFO ~E 7LWx~x{$P �a;OL5Sx` KwFFDIwa $(lo^mHxoxC )|M\ڋ=A<bU՟#uGnk\h4A*'I#v-c3}o>Et0϶ !흎EQ2"_d GG{ e0ScHAiS 2@BUN-X{;ϞGZ<8V  eA5};<Isw? L|;;83Kl +l$$v`occ&P%1(ʚiN ❈ސ Z" Tg9.a{i:ݾ@ԤEĆ2iR u fTMNlE6c)Y 4N?04 12JюC҃lw粒!^m`Z}ݼ?Atpt6usvuvW/p6O oPaY 5 rw`Oua_L]-gC>}}B%4"Rw=@ 5:OKXM7,6V$iCWVGФcR~ α _Cyuo*]]SZ0 8._ @Q\ ]UZW=׎i#jëͭ$$v7\Qua|ׇ!C{̐ 8zA`4Kt&gH8:!,oo=ؖ<K!z}֟ED<?N<; @?gu˵5WdM;?yRքi/fǶ I"]9 A1{xXH !aԧ0 0).s)NX!Q#NO"L~ctegS>3<|JkR !|Vѫ׻0&>#ôʠ%q<MpsZ_yrz4d?7C!dlԃ[["C !|s}Gʏbt"= ҷ~h�%cȈDə`,�7_)6/WFW=VBo=:׳I`hҸuh8<`)~:=VNTeqiVav7\UKp|b^o7?fW`6}U#H7Wd墁2O1`B%iC2v<�"䖇4x 6vz7Vw WPjSddtv]WDvUl?-35iSaO*IF:Ci( ii.W '# B4֡MՀyzxVNPaa,)0SL⨏&h(5_b$RYf{CN Bra>ɩ3Bdxx=0T0I ?<l@Nܨ&g˛_ȽUS霸 :~݉u3BV�A=ׄ?ORh^%O F %wai>?A>>~m^`,Q>X)'B!Tn &hb[sAnb g]QSr;ve T}}xu C %iD _3 \|gx')63fW^@\6SproE ~?WiQ@Urtn#5>#}$ _w5I|/W$k�ENjwFK:% }A>'$#C52c~XGi<0i-s ߽?12C9jgXHsϲp1 -p fF0qn %^ >C 'h3DE_tg }ۉr\_{"ό4ð\(փ9DƬ&U$`#^=g!-X.G|X 0 ’45HbHd : :4EY`|ϯ`r6pcVU0bx#A;Zy~vۚ¸jGJ_%;l*U;'K(_0 N 2u|E9EXY=< -G~^TM)kZkJ<dw�*bdn 7r~:9\۽i B1Ag.-aY4Eп:tfȺ#VUbeϖsE1&Yft0,Mp7<ňQ>>Y]kHl5j`}Q܆L-4 0M\/C @^g6+"$g 8_UQxAcRy_AY3% $@.z5=sR eΖ_=6>rj 鷮op YNI9jpS!e:y~lus{},/Bcڤ/XNv#, <dԾ@UKL F`nnbQy2x1Uƍ//{AUC3C4e,ͯ|ARצFr_͜=UݴYbfWA UjټI eS㙻{n,F2EH5rթߧ$3{`&ntÍ=qJcdpSijp%ՉI%Y`cnX!*O,DATi^ eutB Z&^7Ta0ķܴfmvD !VAf={,Ub?G;P3 f~ GV" :dՐ_s](Ѓ1׆!뀆l?kVKֈ;dS e?Cnd$cfz2WG QbdNTWʒunn #o$#! , b�]SWA.3̐XS$\܌8AM试q",>yv9xv<m,OzN.q_~Ѡ8r)$5"2񈑢]cy凗kkWcR�qӇo4\2>ttG Yelhswौw` 2ݵ+Ŵ,0@ Zwv}u^!#ܗ]} awTO�\5۱tt>%KDGW=hi�&ZzSo>] Į:4kc0 VйiճG7mZReD2qT]I_o]]eA0yj^6т^ɦɁu05)mMӤ@1#5 YbYǁz}qx|;ERNaO^1o2 8~\|6a1 +rن ټ t|gB剃tطucBkDr5XfYvqCVn}Nѭ\~&{*F#q�ب7b|q<bĖ2<U=Tql^&纖F^aFNʕw#ӿ>_x1yNLU^-iwWڢĉgjmD}=٘1&܎`x8XU) r).wѭT`4s+xuӺгyϥ=lV�| _or1n:* &x9Xm1%edirɁx5Xf@ �]`/[cĊi34XZm?kP(#U~3ccX}{{{{{{Q̏6uAVS;kc21fv$Y+Jȓ9ҽ0 gNlFY5Yh+='Ʒ3<$6ftG-i'5^Z"Ol u/o2+ƊXpLÔq6@W8.뇌ڑH5̷׼URsYclH!UxQS |J5sT6nd/.;D"Dȭ6 V<0)8{|-rBMkۻ"pQv<w-pl\ Iy&޾?g̤/=]kk۳NIe=Zw<WEE6x $Eјcf }{~'K#t%Y~i!:v'iiΘW& 26dQ57 ?Ct<mѢ&Pz^stRFtrm|gbYeiFHV7$ttu?de7.rrA*4teZ dFKqYA̎ P³M6smx=f`4! "ltMqx3EaȂqqY:Mkxw詐$fޤ(_f*v kԜGN<Skk}V))ԩ-II]xֿZϓ<Iz1ofXɤ]MDf:fԿ9OBRԵ\,JG)}R�2 63BNDI=yR8ŋc^d %Q+ j&H3ɐch:>8xxt|95/RQ>0kfc8)Uy?mt9kKnEDG*QxssRue|3v\gJ-)iUV|g/ŞԹ aAdqC5ya&۵J;'*zXPiZFp:?<!K(6{u)$۶M_kK@;*2zRDi\'buaii!G"CU)W9 \S-qlW:\)*߻K2 !k0͂`9MוJvxXH?PYFڶ,p&о<?9mjzHt�-!\T 3 gO*ѬrQe7r$It6Pc:\ 5Ð?x;0X7lKS"'&K'UꢁV>D^XVЩkĢCZq<C)Ʒm:{ԑ]V.,IhЖiѴmiga0]ΪVjZ%eEeZ1(_*Fd E> h?ptAR~yc2E6 !B)^nQ4r`e庮ŏDˏ+V5VB2r Iq·lQ5,(oPJ$@*ϲȤG619T�q8m+(H`I>FRpkdq#B?+f:ګQ̟۲Ŋ t�61@DAvp=xU0¤D)ϴ15sqd#L4v_ۺe[(i#o<gH. ݻU0/2Qu2,/pTʼnf! R>̛orA' Ӕ8XIDuN(Ɛ ~&SVIu *, IuNv\ &2�0) <Bk8YClfn>V3 ھcZ&TfaَgmA oT (WCW0J䬨0qy&+P4uVrR(v@E uj'J #_( V.TɪB!*J~@2B:a1EUi{[־PN0/*Fa*EB @!dPY")*XV7lpJ ҚS!D%E =O,W(P!䑧j#`+4u%ɑ*'jRL3;-nORKEp tEMǞ(ϋ 2�`4sϙ~^ߞlߎ{Yu\]@-ME-D H(+*Ҽufp nYpޱ8]wq&jBrϏ�A095B7}gN6-QdckYQ�e.`DCm.̈L:|(o`P8maQbZ`Zsܴ|Sy`JtFi=_0?RC(|ͫ1<iT9�ڷf3F<X`ZT0%jHM,d̦F^�VTDXL&INP3H/:c9(ɧ`4"&c +R"E$;O+[w_PǴEƋ˂KΛ= ux8d$TQӺ>SY^ yFq3(M`љz 5K7d$՟̫D>feX~ ?Dؖʲj;*Twvpl6ElQ5ÚaY9dĆ8# OA/>^g9gñd⚥f#d(x3pY ht~Ժj~sK!?eYD^.TRx6}ZA[ߐzGg=",Mz6ɠ#Z<b r(m$"[?i!"gf5< ' _[0pj7x'dPns4G5j62z<Nf2Xbx  ,*q9]ı`8no X:|tH35<�F%{YMK9Q|m]Ԯ&R oY P6wwGC)joߜ\P%jŋcz<@*\ ZsBX4ny9 ~"Lj*5VNL\eUFE3ly˽h@X;r5s& )n7l!ej?xǼ3f1jCxiQOW w�yE˪. y|{͇r|LۃAY~HCF|J89D� �bPl�n7zL}L?WWo(ރÏ=$p̨O;/_ڻt <qej0܏uK7>QN\�"Y& *d(?#_cj< ;7mZ)nJ=ѧgbO#^QUEPHxbo՛ݓiz@6t qJNq5Y v"Xgy\ {rLէͫRq,wfn(l] ~8zq`΀nEOcg#M1ug(܏t j8.8ل̈[̸.^fwû JW/޾;�t){F XC3''e 1 GNh" C</.wD&{0?|^#Cۣ>蚮\ۓݻ<^y#N u슑mu=@:\M6%V[|y)S_{ R($ ?hn Qaz4&"1TJWWo^\2ʉ(~Fmx(Sx@!=) ǩJq Xx(.omom'Ԓ%g/^x~3EW]c|3U_ gC F eI~4#h  ^dΚDq{U~}tj#`9 6{hǑ[H�mʬ{o*`KwEdhޕ5Ϣ-4<f9Gwc^\'M[W; hvW.ٍ`{�X�kۃ/__Y\uοݭ(aT7 _pB߯)Tb9k |kHr[[ IsRdxK<#7PiIHKd}�<,M"Gwٳͽ{/v6_*"EUdي7}<Zz^q"/ ;3sbV@~Y@0՛6.:^Nom=}{)i�%t=>G*-돟{6ExdR,\;XZ2sY1Ɨ80_c_6A_lm&)yrsz5f!ODHv^F1:!MlO?E(Ez6;ud88}bՙȽj;::8:yls.D^԰#ٌ:~<:9>;g ,1$ dl Yh~Pپ`5`d R`� ** NNgyU^ GMSN/≯v%e(Y) 5Uא3̑EG-�̳7GoޞR[UU&6)PP;H8M{INyHJKB71Ѿa@jAqbkv<-jZۃ/=oU#;wy:yommo|~tsy&H,NU{L?roYq\<NGR-пв$_N;8 RDӼE|i&Ϸ0#H{67ۛގrӎjZWUNn/>}<eK"] !t!j7!Kz][OmikI2^|@Ƿ_޾@zwo@ó>#TU ]agLJTzhR`&�,)*rV!";ECaxbL@ڲ)m̧U‘:NF�  Jw=~rwk5vU&.~{h`V"491`M aFy]U:`d<MGF[-D2$!h iA 蝾 흝ͭ?~: !#eR$ŒFl~P݋'}ꛏ}yň2 H-]oǓrWϚt܆/x*_�o^}yqn{Mw/&"8"Ċ�QɆ#r@h\HMN(r0P/w~@ \yQ$xӍo<Ht1kOHijܸsyrֹ:?KW'_m|ٟ ^b&և6I;"b2!A2Đ׾yE+*[ڽn Ajش^!2S"ϱܹ,7FonybwE7h/^tDGK(vُqswwws#9RE6oӎH�92!s1/#?[nli !ϡnBXق c9ܻ�M G gfxďrQZr,M1H1C栫ߚhImOS`( )MA4IqkCV۲`r�vA!(=bh-"e5u;%:Ć�Ms~ІđK++8ٝ$Nkpw{|eJ$(Vh^nOowwF i zW-7Bj8D^{0y 2 gS]w=mh2-^ʌ4Q4A�XO'#BffڛB�ǁg 'Fx;>ֶ=j~вj@ j8,)bZr*#"M`-\xÇ7o߾rͼGi `Bس1ⲃ p9ʑ2"k$AhMĦ!xR~cHZ~%eG{_.bZđn!3l-[E{һh>$U$ER)ؕ!,H떠մ=$O*in]Hk2/bD]ɗ_^?{q"dPT ()Vj k9fV#Wi]'kX~ )J<!)k5(<�v\!I9],fK,/;;v9^G7mׅRLmRmUڬk^W5ݤTFpdZ X5Ò=?ŢiUY !, Ov>|yy"z3o OPx`k:1en7x4mIl]6%e^bt[e Z"zVYOۯn4}!fHז]T3Ȑ{,ڦV/lwrX_ n-'02Di;8; 2$Ajυ$�s|wA/!7ݦErJ:}?.@5( 8Θd լ!ok A os:oUBb^cT3z4ZCe=@!@#ܴ,MW.e7Lj.Tq9C/CG4-pXl^&ߟ(v4yVq%X繮R+6$p0*xt)SlS%%uMZ޷_s,:JhEjZY6=܌$-Vl t{|:ư];P4.@kH*_YL: ,Mjf]*J;n:oC`OeK\>ΗƠhe1�?hz._m(4x \u%xU eiu�K,qGh"3��>l@Z%*Ɩ,,  ĉ]P O` JVBLILk'`u=5yئ`nЦUzB\J$NP6HZ`_*ugx^Xxqd<KeX?[IXN3)nna!b+[~Rq2=#H~!ݪohפc捼 @zw qea3 l ٶ1|\ස#3Xj(ZN��0q M/y Y<wY`|Ot.oF @b^ X :> ,6EoD!Nd؜ԡEdHxprj24ez"hYlᾳZd#JZ,gyL;$Yt9mNJ퇾iкMV?gg$M{ ɛ7f9l.Q;b�!c9Tۚaoz3s=Ly;]Vm}t;eC( rv'�KGa 4X�5s_>p"�Vq4�.q[hj KASLĢE;1@$WK!}D0u^@B̄Vb|mFZWg]뤪BCQ5+oc?yqiqw ` Q`˃h ^SJ6#įFI VEP7yi giAֿShZT;(=@;,fYBQZWy8FWC `Ax@y3p0"[_) V7p WZTH}2-LNφ8xv`ČH BVȓ1WIȵcxz"yƁmȲdk^a( ~@ pv\Y I #Žʬ@hX @v;�!l�倝<@dP*a$qh"ONe"v-gM4i֐/lgA~8MxшIBF2o;B3RaL0 k#x+y)C "'utj@.!h<xۅࠫ'!ʒdV 1H#+Ӭ_z 2[7 YQz`sP3)ZC,0 *3w/6IqYi(L?fCFv{r 2KJH�F^yҖ") :j)⴨!V)f{JnY7!`r -H/`/_zddGi i �q"Fc R& 5;.5v)Ak<,@<ؽJP@_ F,ݾ>N �O.%p֏%4P4~Z1ɋlQCؾ-PJ,tF:Rj2"Ũ2˱7DzJ {CTn)UA>%č{c\VFEG]u2L׏I$7w` #¼tB lX8 Aןa�@~`]|`ZB:n aI(}fR(W5m^9>\uZ,aSM" m&59yEA`WCFR5<2?|oX$02�< "q&P;BH*O V�)u.&!^ex4:I!F$ȷwY_Ơx˃'Ls_z/`ݠe'M s=i8ޠNO'M#D Y ZN$ <(a{CQ4-U/}JTFjjMg hB;eqTeau4ksw{)bbcc@x;|SD+fdŻIzAOf $% 0U$`!@`G^x1Ξ;Nn8 'E@hA :(-#hF▋e$([AV؁1څ R<@3cngBΧC^c0uǂ0&5m-- O1^%A՝t6B}; fRN� N[vu];;ݝ vs3 ,ELJK!E-K-LMAR *u~% t^g}l �Ӧ?M֋+Eyۗ}l:áAc`G)"cCbtM j ;~)?4φt$U.CCӘ>1!ްOJXԉB,{)"? x}><r4 MТ5`CXb:`Šӫ!Bi^ۺ Bڼ_ll>o_w!׷brH/(n5eb֍.p[/q?�iJ0ç1i5K@�fY,Vuښ,6vۀKj6K{}7(<O \ђס*N/~D _kXDI ZbJhrª!:#gUX.1;rz7xI+v) ʅ\<\ �ѫJ[:cJ:�PP,pzʷ]S rc ŋC^Ϊ�F A&'u]k ͬTI )yY6@zh;r!:Qܿ|Di4M@?a&ǍfGǟ cz8"O[Tv1*H-༱*~Մv{}B}~ØeG KTߣ蟜X}$| h䏷ExYOT݂jap|h(Phqjsyy[H8ys(y}SFW#@M k Ͷu�5# <MAL15>gyj/h9 5lKH(s:6O4x<V aT࿬1PD?,Vt`G d8/V4mrS;|9!Ê�/43, u!3^e.hjXęt $9&H"> ɉf qU$ֺϓO66_<{{)`1WV5/5'q 9pVēM(^(J XrD\[u(;$)Vtj<^<ܿ{om[^;܀{i7F"ʊبVd?&(~bkDEzm+[WUw79!i0CU0XwJ&lA5sa]>Հ 4ac7pph{lj3!q,g\�+GR$xvVCV: 4{1i&}_r?i qQ�[YH� [+'/6am_C4Lb.,j0Q#< on&»#4QYs X48hJs:mtI /D֠:a9VyT ',zm$ш'V#ȣ HK2W屮r2~RQV-/H /V8зw(j}pN^ /9pG93Is>8͌wrVG|@d͎9ZCht{ ҽOwPVdON^l=ьv˶@),vޘBVDK�,�<);uke;O~w_@β͸,>8|ELm{Sm5 KѐךX*qeO <$\.΂�fǧ=,T ԗ,} zɺ%^K/Yf^l>s2ø9_rk<9bi!%xHix)B*=a$ eֵhV{)f˶s� ktb j*43ZW=Fheu46i"p>%XŋiK% *Z`{<nzy.enVa1!}[#VNKWWٻ/C `f]ѦƘ?pW5a|ӡDX,* ,!#v<lj=lux{Zڃ/wXo0N}M꟝w #-/Qo@{bY7$+3�lSp[/20^om?'V[ڢy,ƾv^egb+ӆFNo"B p�W_I O  - [6tݕ\HJ[�vG-8iU̗+9~[1Ԅ*ǩycC9ĊnX^q"E],qj"JvzރZ7v6*up,b4@Ɠ=U;6hf8qkry]$%\dU𰬣0o@v<Wۈt>ιSX;\9e=> 5v8D7D}q{q=[PS3�xzN) >'u{։y>ZiP; iӇ^F^OW7I7mimZ M~|?K=:hu }}ZTu ^OĤhnZdq%vb-J+"?7 'ewoY=([I[�O%hNZI$(?qNof(p.#zeUbz8C# p4e&HȒNkW ]&�_o_AU Kd4O0 J#B,Ł&u'K-+FgiŸ5`]f|_o_! BMoG QE#q Ў|l !nB.'Ŗ.ʛzA/P7m [WMxHwpاhvd(* B 43cjWf2JKX.oN5}_i>|gwpMQC'Z *[k§||(qjC< b� $C@47hkoSZ<ATs`ws� o}4yu&NHn:A:[܊ �QW$$] `GxĉZvl<`V 6~U}w,7$ūUGX4ڬJ ۆBو $1$d ሜ@.I=Cmg(WYXTdǝˍ�T/hV:kF*Ӊ�P4M5!ǽq7‡t7[_AC sVU_$ݫ WmkFd /IN6nGmV ymVd?~ɢN\ؗ:$fxw 2?eQWmh GѼǮ7>FhaUHb xo+W<7vր%pLAl+hZsQ)S@&_/o:ԄbpN-<SW%z@x@E[NcP:\A1rwHju=|y^V5n\xLRm2o@dG *P֕ιD1GGLPNW&.:7@Q؍r2f% Į[[S}Q�jl)"9V+J+K{"-)s4q3#Yl*op j2qdٲl+L{4u<][ lUiI g <kKG)ልkaM-Gq'Dz8/N˲CF&,3iyL9 qjJx";98FL^f,RC 7WMKCij/Ot&؃&{h^nzj }"Ɨ M܂y!w;緤ռqrM4"ˡ(K,!>.}ﰌl;xjg/[{9K%W 4dp*:r<tiq΀,@B&t<^m[Is=q,bqӥdznkNEn8(F J"Tshݸa AHzBǍΈܨ?Aץm*xG0, <;=3 yri~rTxedxw3,luۄ뱉-,{ YI6AձulOJSq8Oagpzppwv:omuQ2};->vI1XN@ ){d?w׽ ?C y�`4|K>dm&,5\SK#EОP?jS<-b@Q4QkU+7BMI 8#J̿^8s�I=bUi`2(V("I8P҃fXʿr,񣼚c2 MEiFMA5 {i}o\iXIX-ک*y�.qn" 4�цXq?_Ӳ@l7pG;.ߋFagcr.ˍhoz5Paq]O벬[�I$N kZ^JJGvIA)݆Ft|`Ky6<d&8ΊP}ҟF݌&5CN6 n/D35uԴAkJ8\?N-R?4~_~_~_~_~_~_~_5bDаGt'n9)B$y`d%q\`#aEPwAQCJ';d16OӇy4Ie%\ǡ%aO?9þ٢Aߕ{Mʜ{6p GR2}@k%A:4‘{C[q=M4=WS㼊4YYӄı4?XKq$hx̉B瘲z˜`_g{27ewm6c;atUncrcMjN>_dlIer5@~6c9: Ў۳+.fԏ0I i(',ZG]Vh"Q;d7muztuۿظb,y:rje&J]tO]Cղ]ur}=<“,H o],jڬq9E BO6,?\ ,5ɑ Iʹ(soB;G#;/2[0+qȼ4ԖY9]51 q%'j^1obqm=ϵƕ 'zB2c=jd'O˦U|ޮҼϰu)c MCP6"Oa˜|4q?GhŲ׌\8Yfib>'ĨG ΰNUH?T[KW $H2wB-R7{:8%crdQ}ˍ j&`Y!*A'7ꂌފCG}x7na-rQs Wu,WmR_|jN]ɭpi@!]=tx?o0 }"U`W<Nfg=^ G`WuIv.k W#f7wm+yqUMH=I% 'JMʎxU;eX{ʹLlYw=d{2sn]:' rr,Es81ҪźAQ08e68U' )5w 4npÃo t -p绖&?i?[$ZT:/! <.2__UTeA.M~1t]ؿ yV9Yվ,mM0:dF=ʧv<[O/ŽE=EeM,v4ir}xtrQK T+t> cZӟ<w_,$ݰn"^6kQ3g_ތUr|PTU/O7L5iWY5HXNy̾GeK:-,4ɻ.y^Gb6qz^ H ʼn@6N|CX$Zw96v6T.{k87nN-Vu9jyH_Z~b�ktٲMtIC{)%0¶,{P4mfIYvr֙S 3t;prx{UOU2 ,ͳT0tmtJَk1,2;%QpgA3[vx a-Mg?G,Mʼnv(NB{&NSʳ2])q%8k(Bt�M#?|m'`݃Q.fey? 𯖤H \vq,lj/om@iQd)ȷl#;+fix3׵AW" vN`~V ZPtrZ Ni#hbȷD/1s=qz/8 <o! vM!$b0U̍IQ-!1m9 j'u%�-q e1(,tMDAurvyu6F<늬mc`�Ls0{#ȏYXc Ӣ*.,T´^<Bt):x[CVdGw!rQŞ)?n 'Wvu_)VU8 r\d>xKbgMq ^8)xR?�U1;<!ɋ-t /Fj:C-p܈@g3v~'CZƩ"sWVq50,Ê4o2_w:e_wâa9R/;MOBdT<jQFeP*nS`*aj<9@ 6P}!*C1r <uA>|%U ҄"r>r6dZaYHrꃧR iN&jYgG[:�GZ޳pjٚO7h̙Iv:N-!?͒U5$PXgղ$x맱%ϻ$ǷgIdo(z%6u*1$<3W̧L g4/_67[ɄU"VjVxñ9uۏ4v}VN](Vr<bs5DA25gl"MRORR�% :r U@?uഝ$O/ItԈM�Ӓ,7>]Q<<`o5 P`vbH\~ME9fBOVZ1,/ۉy`k2F MiD{3L~71q.#@^ s -`͓֫&-�=WO.9!Q]EmOoCc7$KBV#>;::.IUߠF"D â.P S7z((TvdK^=[wc9R,NFCUp/).QPrfM9=f-ʅ `yl2999=\~SqUF 7eQVB`GcѸws=!iGs~qcA* `ĊֈkЍNA_�p~$+:xGSw1}2`4uH9{էw XƮ)3aBYewyzޣGk?>K<+c$^[ P(L@?Mw8t.oݝë[]P! trz5(|َ2dfڦwzmOR diO8P>m}ᏸu`$�rwowwwx#sP,3 Hiq};w%„y$<cCI{ssO(A+gG6"ooA>5[op@F#&Nܯ)64X,id(?6˦gw2 :g_ph`?r.S`Կ퍆ݻ>CAw7w޽~F0J1&QO?NfѺ;�N͚HDb rӋ<K8ՈAaAMOϯP` '`}y޻SJs!DI"m_<̚ǚ额P?Q)\ЎUY7.!(Vghʛ7\!)M롁)//6w^|<{3li@*s)Ziմik?P")mҴN'eDկۍ֋G9?ރ$IF)w;%_DB{;7+JꙻQ$% FfdAqy{yig y< q2 盞p蒰b,rtMgKR5 ' GM8$|r`>�HwWWWw}Jmן^89eH[MUg#fH'\v}C! $kGdD` Ngdow0 K(=@Aj_lo|s40bCnBiwx[Л/6gd< Ӵ8R[~vE@qYy%SԐMe$&IY7yi۫n/.kF8H(˓qj:-O8Mtу,o~\]DhN]d1 g?z+gY$ WvyoTaY:߸8첬鍷7iڌ_s@ӎzQsSsI �Ӱ c aXgw\oN!i5ITn}~g43b>=ZGo_Oi!X lyA)%3MZ-po:Wr9G/g_n.?4Ɋ1TѼy$~63,6g6?׀ A ~h ! ³qCGJf`bӛxntw]o\}/]ަxR^8p|Fa‚9bYEIӈԶl.e.rKqp zY0N?}Z&5i \q {GmKA{}|v|tz#WY9w-]@jkjҞK6e8i)Eetӑ d/jͻfo4̛mwoO?]ksfdj@:zv!qagwX  Ԏ5,~s+/(q H[{;r)Nt2}㯟mR0Q^9|qCbggT =e idI/L O^y㻓Ei|<:jwow`Շfo$HFLvB>ԅ I�xpP" y!vFEI.gs `ʨÃ86g{ן^n=~K <*,7nO>}9`GZq�(ʃOko"ez�VYs.|cڄ]d}yOoO^<`TeF j_,Kf"ӜhTQGd@ZX >;9@9*Sk}EX ;/޿yY˝]pr3el|N0U@]Dp,37.OhMhp<d<a!W+X6GA3O l_8?| Z O5 ,$6r[?AAf ()Ґ]}:hk,iԷ 8 M(FJ8^%{Lmn8{�I އϯ_?i$*UTIT\g 3b"w/15v7&|ѦY㸦ĖKS'$yQ-Z ?h4ovH?yZ3Rʚ㫼x$nY"3 B<,bߍ>X]wQNZR4J@@ BdYrpƗ/ >8;xs|yseB7̉Vc9^=}} kiLa]̦w< )9b 8dVt&,8K4ƃHfݿElHnw?\(…A(E<S%;_<L ςf08PH@eHEЃ,MG'<dNZV% J=CZJGXじ}A>~:n 4 @G| HW%R$,9$XT-+8=4u;4˱=(q /NDL;n541p$R$}AtֻG=b2&"E]Dp�p F7,|]036Ğc|o}&rh\?CqQU fs!i$r4 <ǶtdzW"@::J8-iWȻciٵ*/N<�n~ XH{QDOp@*E�# ;A?Цp_<@$Mr0r{efӻƽ2Bu8V3@4BUUq<g �F`1֗y ggN^9|!"uU0hfCp!CטE`>|[,O' +xӴDM ;BGg0%jwUZ/7G޾o 8:g щ$\23QS DiA� %$ >+ɪ0DIlϻN>}Bwkokkr I~:܇Xc<ŌgHG&l<+sTxyUQN RfZsyb>4En}~_ 4H Plؑ 0V0HD\  )drLRA(Bl,-B|/3lOgX 9ށMcڧvwޟ] xR>=?&D^m T0Yw IJ$L\. _Y۽~Iyl"3 83d(Xs.#/LGv^lx#vhq$&uQDI(-%yXڳt˯bNI>ys'h4%l'1gyQIcEe@9RH QHNqg\gUڨNPUY@ �Ir6 jPg0~(짃KVD�$  [2q7Q_XMH} ?5eXsvNy7(d�\xfG; 1dP OIq4�G�ӽ;U<G1Vei[U<W./yC% 0)c|NU#$"}9e17 ArsPHxDT#*B%7Mf z=xT@jw/:B7$1о |{ϻ>"'-OصL Ci3nj)9S%ܾN&j <`UhN+/L}M)e γVlw/y)_R  Mо}E|ARQj^YG_ȶo4+ѤXHϻG'b <vhO_F &n�ﱐeY.t#%yUa:-n.{"h'4T~@AlXrƳ k;ǰLf˲zhGOa)^1= A{Aj�#Ep:p) y,4ɪ"92~T`�lAgUө7#Sܤ'IL5Oh@dp͐Cp@ !<p!R 8߳,d~|I)f1 7fda$sSܠA4�',A sT{B#�07*A aL)xv'f-߷i$K79ϟ/&X/P6J)!yƒ2NKdZ/!EJ}D87Jr[LdV+a&}fLd Ä| NA; !8@Sw-�X}(|SY@,?#&0- -LF�bFta7@p . B8?G@O=PHW٥TM[k҄Q0S7>PR@9Dd k8Ix*+(L,7A Q.L 05?,Ym ~ aj8tǍ{4Rg6tnĨ!lN pNٸgq;�i"E^%| K&d9È3D1h f t n1LxLe<5 F#kz}<b`\fԇȉBN_n}t*!B6 +^- 4 ">qz#@ڤl*}[j9Vǵ!'h J<Ig)*/dK)#> `0]`�`E&@ͫuIE@fw"=0yYk?v 99XAv4C�`w!� $aq5b>E#L4h ,Q#@2`l^55{Q6|~0%I=KVf(;4?pv�J(E* !Zܽ !w$j#xI/�9HL ܿҸl*(.>?XF3p0yO$Ӎ!zj )VMH =)Frz�CυHzAyaiH24uuԱ.Sj>ƏBRU,R>}4AoL %EfbpG뵮dTG2G*QA0u9wq52Tufa*?Rs+JYLP q�bU �c`~ 'Sٿ)ӰDpD,dT$6?q/JXiS3NP (WXX* ai^^W ~v0TaAbA֑=  ߁B ڦ BGG4qa%YOk(Ԝr1U*jNUi`:KɄ]FNmst|û2 f6M<@HKw2ѝ{<*y}~~~^Ց$8n9s8&23LcW7N:J$ 1iRrH! =,-#N`վo=.J5 CfY^eCe(V7+�B 8ad_;|y%BmOA`|H,õȔ4k}FfA!<ED3 P3cӉJLhX4hD+- <p(火Nؖ,./+w}bKM ߈iͨH%`xr}g+5^W=O9?xs=V 2  xZchjyXѮl1ހWUYȦM;*t?)3!BVF\ ք}]?=rwʓYoS~s)<갂%:nHXGdu4lB['l4n;(oO <o;Ӄ5|m61uty79mR4'Rw]NF;8�~DhP(_T @M_ @3&eܴH!Nl eQ80:y7}Y g^Ȇ(Cotէ,5xM˰~HhAòLKyju 'B>T vU[_m7ow@Z<=$| 3Z G3/w^fz"e?nM�#`'wlS϶r w|bM}{g5}gy`>yG�p[cN%e#vn T"@ZH!>|2ܠ8B ׀<{{y0dOwyUxXG~/x@*Ѐijm"5 2S00N$,!�p Eeb4<w5x>~:f!kALن& jɳL>OG_tV83X |ǎ" ^0`TiYNR-KQh샼74 UT#Zva2H[nO +/S<# +!3LdY``cĿ�mH1MKbHbK_U�^r* MTZc%; vh1_OW@*\D  "7M8B74s͋�Љ:5SSqvv^|~ ES;0-g%CHhReGx'>HBoq"p`ܵ'RfQQnêVJkp;/^(*L B,s4#aaE?miO ۳Zfc*ą$`Z6*49HItUSVPU2@1x9`q(saш2=tVtw2M ?U;*01rR߶w_exPu/)ۑU-uc"& zS?Hڍz;my{[hN%t 4MRC qb{o/_gZb9z>5O/:"kY2 #G>M�hɅw^WUeDfv{{goG%@L~aF*mW E -{ �7%pg_C­ C#0 ]`F?9Y.S1z;G;X,wۻ;/oVU޸=ga7Fམzc@moW7psPh,`aE+ G4Ϥq P} _w5Y tN2rhQĮEZL swӗzD,e9Ѱ toB9:ovwoL&iDasREހDA 5n.ZXKfE9p2@TU obZwwwQw>~z�[/-hP~tףD 'g\D1B _9Wgbɝ!L{D;{;laow]!=^%&7Ƣ=ƒ�$I�8<H؎(H.̈? y|{Jy"qgIT;o?Rg\"r1X ̳X}bӤ㧄Ȧu-,,kV* �=yw{ѳ@_}& vpZ.!G6I@Lk(:$>DʧxNz.܄@N 1mX4}דVT aE3}��LHJ PEXvH:٣qzь+Te<z3܎$uwy,.<Usu7$.\5,7LJlѪ&]ZHX/QE8zIɦ%KF$o9//,rWek eE,K|aak&M:%2)L6d}"`?v5N-mMlj*WX) w�F?ͱ0eYM$An4MMJ4gX6jO˩Z.x-"BST|ķ{R9�xoiKPᅾ3ۛzxka# L:uT<Za(:Q%V@5 mŸ3 d8 i>#W( $ ɒXAyu']H/YIE>ئ*rR0M!>=>R S~v1WU @&gE6_'m;(Axdɭҧ'6 t|1N4]>5͇wx` _=Aq#&w- ' _7G25i�m+z1.d q1NǴэ?~}z�Mx~,6IVO 4 䞨،Mqxp.7dſ¯?࿇2V &[ή{1zb<OslWCl?V2_^`Y +:%>}[Xli+ �?>.*llhhL?C{>z,Cց@?K/c8,ME , .>m'F(IJJk7fT VD9vi dEh< w\@׋dŰCk++ =Kl=(5k_\'T&trajꝉSOS~͖q#ՂD'"$_7s z9,Dn󴎶 3vV KҤwbcغ>9 _"@֢bK5ZH%3{%|?> ưޜnQ NC r㔿-ׯ3/OQi_W � h+׆\˟{$ R�-2f*>mQ4H߹ode4?X>3�|KSDsurكɼ%+v䛪8툊nX?;\(sXҗxk4~C +3aEfSMRT<TA_K<+e(2us˪qzn\J]DTX{u[C<F ߜCIa}?�giCTU^ve͊|ʁo1- G0[o\jn8F�"ͪO|X?/{;I!.̂ny 'DaK'F�Hl`z? G,}|}\TIԐ7b1$EǽhXeEh/{|\pxU1]>p4(!X|,f񸮲X<WUt 6V� dǦ,Kh^yfe Lp%saOfyAoi��i 2{0Cn;ؕa�2ǂ@kl k $=AO֋5,`qRiz\ZRdO NpOɈbX:o`0 |DH1UMŃY RU9,/@a2�2l\\a 2EpCAHX~(,f<]`g%MW2rV,s-w;GN=]caYn*ui#(6qLYpTk떒bQIS}n1Hg;;J.#^�%\hZl:É,GCNqa&%hu�SǿM/X颊=]NXa*=N"l;m4F{HNE;A3ͭ. MM~6ǣ-S܍UMW13gǃon^o0fE+]}khX: ̴'!:PWȔtyU(3nٺywuOh,טc>>taXwJz8s1 ƮQ[{2N!ངݗV˭:'a-Hz$B�ʤuԢes_ 9hi谠w,Ùв&c2ٮ:o0_$lyx^%n�1HVNxuB%Xn>򼊷j;SM/(s(`ԿZVU6А=UCH_luAtG16e`D*3*ָ#a^DX4?Pljtf<G:!z3&A%�<r!nТjCrflUz[;kߤc` d-7r!5MEФ$^'f[7pa/Wx9ɫ%%�7IHk&N ZGdͿ}ߐ,3@.yaGt~X,9b*j*n6}CZ�_eE f <]ˊUIH!sRIK9.~Ll/M;M#;=_CF AL-}ƿ%*<tmIZ6ƉܐO}A'S TAHFp)W�4F=@WA;A2LCU) c=`|�2oqkJ~=~=~=~=~=~=~f (ƛb0i}^֙P2i#xLtlYÛfUiMO]#,YlІw4j XӢcS4|qwKө(zDf3ENCe'"K6JuA`xyD|u?9ݶT/[@Ah.f]x+W:Qצp]ː%jj_%?].'S42ۚ {s=͋$e^dI1M{ۼxV٢buU}vQyaFZX=_Uh(v.+М:I7$uu3AgśBqZVQ1vm zO0h>u)[[;ƍYb5eʟ!!xСU?l6𗕤@˪JgzkR"֫Y v<X%!!Ȟ~nT]0E(+,1'<TJK|sN3r||\V<UeͰY%zq䛤V<Y̰?citˊBcޜ'VX=>U(z`2p!*,TI-~ơܥxX?-#M<2t#߇dqIx]b,@jC mEWt iT-x5ԉǢ4Lgca 9 ڬBFuw״M _n`Z`U=& 9>8?i1%Ȋ0Y#WEN_{_4]AkY4<kn^Jq-gzk~ߘHtn3Ҍ~֋ (2p%k(&|V;BOgiA_-3أ`-!E^=1旋:ųËSעk54 {<W%Sc^5%G?gx69կZrLHȻfy &ң K?HT;�RħYҔOzR1)^k3l|3�"1ݱf<3ɞ绶tݗ!Sj̓YHPTgF#ZPyM$ ;<"hUfIh2(0ݦ)37㹮N~pѕUcS+lncA{Ĝ? 22oSW`M$ɵoۂa62itÍlc#o(ǜ rZuS^=^RA:1hm\!Gb\vZXeotwн<aUYbZ̢u�["O:_S%$OC*@jlkJڹ $*GqU+LmJN¸QM׋< u\^`"%՜N-z$n\̑rгiI" vd[m ݃5}q^տ\dm06dIX47ZdDYM_}_=Ë$Jg 62F޺ȄձaokҵH ۉn%o ]i9 &5sj9BUϰdt}2P nga$V Nv-<T带L)ь%i3`"]Pi7/qsvz7Vl 04bn<[S%ƶi2;l`ob|*Sym#;�qe!<Tq}3E?= Y0'I@_?Fk0{1 [rS|rX ]炈aM:m#Cߔ([YTz7=[yyߢ!i{8MOƬ(ђt&īöap~(6GhWѢnaͦ%s@,zY0ޞYOpwү7 '*nUR.=̳2y9鞫sV�f˲}[]}ZKMFoX~`JJAƲ"3C0Ų ol<>"y|N0pd);[7Mi\mL1z Āf xz(*455¨9iz^ԡoϯϮyADQ;MV-9jbdAP_YA7Me\{$IlRHM5q-6̒NW8F j0K}~y1GıFB8I!YiɃ,"^eRUpOC LYͼ�BӘ\uDz�@h͋0pbgL.Џ'vgU'`γ,K^汦,MEywXVȦϏNޣ L)0ZŠ  3]BBa$ IE"3 ZR R*xȲL30DPUzj6۝5rY$nC;c5D!*j.*kKla<lƢjY4ds�`[Åi&=<ktV74li\(lVA,q}~JxH Ǧ?̗ 0CARFsA5� W*&5jc^S9QѥƓq/IT~8*w^)%M+>U9uicS lƈ#l 8,axBO'a8v(�'CꇟɲyeY-QU97[> "_H2AhP+:2gB|€>4[I>l87>3ǎص7Qc7?@<Ya 'KGZxfJ=Ru $-` 3u//ʽ3h6QZZ Ip 'E(>$< 4 i@E[8{h4nd 7IlK.ҡJ#^5yXXn\rSUetz]%s n1$k1YI7Bv fh 7Iug"1nDɹ]aРe!˂}}b]R5 0 ! %xmBBPӛZ"uZc^V.BlvtHD/_cwCI91Qސ޾l \(Q~�P 0 aY?.uo>�dSSu7�Y^S0wYAsSkA0I`wo={'tG,)KLFϱ(` 11yk˚Q4k]F_Q%5]w&HF ~<l^?}j:m,I( Eހ@x UOR Zݹ鞻X63bo eIkc'_(]Ddȸ-OjyV8'= :~1Uï 5>zMUa4b %G^ ]i^}zw�$pT 4dUQG#;] O`q9bE?YuIZjj�W:+3vnk{;_>�W4,zG@O.xqxToGHNj5UgSPBq(NT�,f+ppHyonysn{iW2t L1 {xFA~N`cF^/ 7qy.)N ;r(} Z?]{ꗎӃ!EqRW;|7qL1a'ں~ |5/b7,ь +,�V 9%E^Iv7҆]o!;n;4C_N;<v-ְ]]Sp4g$?M@ZWS@BzfRɼ  l:IH ]a>8%~wqUز0j6WWЭ; λ;{GmpAmJw\Sݻm}ītD%qBJ(I<'{Ѳ5¼V4pMMU4SpywqZ@l�;gwC_چmx~!m)ݛˋ.#jqfDg Fz-^ryB{۴0"R{F$u|tp|r- _ 1W`^{ow՛ZG,/NNo2f?H^/ܡ&-V5w!}CH$.GGB7vi#?jYf$Uf..j Y38Z#35ڢC+BӢ:nR?M ~?:>=?z&WEy͎{;<vGg5t̨B<%/=IL1ZUy< 2)5P'uxQjBL2sm}vv훏]FCN`c{wwwiGvB[=?~\O1 0( Y+WW{szBB|FQ%!F߼49TaLtg}5;P2 **K5{$`%vC@xQ?Ĭ )jX^3L{A/*a=Oous.Wb!Fw�e/m`d /~rNP>=֨]7!HUj| @2L⼜-$c_*hoޟܲBCX{_P.~?<=z4?"J2Ho7n6e)ު5!! xh4mcGNwԑb|{6$AgNbZUkyst}qvv!РUe85T!pD )H ИE:�We20c>~w3N0s 3B~w)d#QoNn#Q.ɩ"*f #]EWwn@Q,|@fZ9G(+J`7zw.h$xI:j#f~s3u q{woG5OGNg v Bs,/:SY.G"?xZC.|vw鏧}xE#H)]$.RF+<CYbpo""qtv|rvuʩΉ'OIn.dFstYb6k|OH!gaΘaLVV?qUxф~6I4"CH; BscޡghSr>/ = MHw1QYqaIT]9J"~,, r;l\j:T4eF]Tiְ�^f0fY zg>F_iZ,+)maЋQDq7 >U3N*7�-0S'C⨱HDw{]v?/&h[w߼ށfO_NQpŊJO#:ziZ" ŻE-H0uĈ2AbdY6 S'߅4$I w{XDq.h.r;4V_Iz\TiMZijX3 p.u]dB4gcj̑b2?U$X]݆ewooŀGPHj$Q~C#\qVNг@-"d,R*錐njŊ <:* ' Bϧe^Iő!o7c}wW 44|RM|2{&$_^IIi8$2n3de$BĶi ܂�C�Ϣ(@L}͇/ᅬdBdR j ];aã (2y_Zen}0m7u yt%IG&!Ηן+AR?I ȍ)%V3k< (�ص*)N3!tC!Xe(LaC  Q) fcb$rχ{|r+D,' ކg׍Y;&2mBo89[ s0NB[yV|d=!cy` g?8<lILN I-lܴ`Y"]>l<C-@$$4ҖPlJYK'!rb('o̒(P G{O$“1U52C7)1Ԁ2)<6DX1t4'.%B<pE9 EFQL8 qMU>zz-grϧW!?o0A<e3kGǣѓ!{WCzcRaJ\ 晢 P^{'_~8>M (ˉ.*XIZTU[2d*~_.- Og+<ЊƐg*V\A�\YLd8xtr:6tv=/JHC6$b Gdk$0XX)b =/"2̧!L'@dېJnTmiA1*(Ћ<@$s�A_N."n{�+!Q)́zV@!0I62)=ÍUE${b6AǷP :M0[vr* *vx#:^IJtz�W Hǥ,-Nψ B 3xn4pl@ `&j 7)|=xisQ9KWy0ׅ놨 $2`(_BOq<ݶI ԵUܸdl*Hǁ;𲤵Ix>D,7x~>wVҬ8PM]TAaZr1 ٞ=` %NuiZ Ni@= A#䱶hDž#kߖNŀTl9ej#s䁡}<Hxr5,ߛnFayA'_%??-D>Kc$Bg e4nk!<FR/-x؜&g^!B/ ۏ$ ^ )5؛o'MXe?Gpx5xr`XBG)jH$qYz08~'Dl2"-J6%7tۅFdeP%-+Ї(@01{1 [P<lLHb yY}%X~Vmk4C|{!آw�#;}Ϧ(@e` $L/x͋1@h+ "x@Ӡՠ, 2w$]/~6AA'E Q7~<CdSO4n<T RUr#L PV6f4!CKQh,JЩ1F`$6;;<UM/@R !Qۍ"'v&Zౠ }_*y9rgql۱%F6uod0k]ǽs~|1teapJ'qX}P vr%~֗E18+a$a2,*x,PjȋCHp0_8!?Ĉ/r-!~[q!Oʶ֦ۜSOxdTS!u}y֑A;Qv8 o�1,HkkXB98ljSeʈ;3얊0i6_ 64hѹ]G[/,'i1!Ϟ@Nm:[t$De�="jR+M@MKT^`j'd ht}ţԛD R`�RS|<$=kvhN`R8 p[ b5:h!S񤄄/]I Ɖ-<SxLkrI݋&Nv=",V`nSrEp2]{lαN"+Ɇʂx6pP ]* <u`] +ϯ[C7ȏG4=*F Tic(gK9*9qUyPgdɎ9DIH# (/|OKǶp5gX65YQM#C՘CidbD"ؽj>+}kzzv"̥IE NCG]]St6g"Px<TTSdÑak ihO0S(џ80bIͫ[�H<Dׁ94FgzHs,CwےrtOHT4Tx_R*mo̲cI<Z dSrn~ c.Nix2uiC5 Lpa4ݻmH7Cu usd#?Jə"R #c8OD<(k:7Z}Y`UY!+KS~>A %zV mr=kA6[pa<+xDa|Q࿸nklxCTN1ULޣ(PEޞPbPɏsm z1l~_|j 7{Y0"yJW|y uљ{ԣ,ۺ =?;ώZϖCO4W! 63Gi[oP?`Sf )[vZ1$T$=A3rDGXVaKpQIhj`Gʳp e }nHS{ a*+&=Dh0E=w@"5i=Z b)AO�Bh 0 NY; RK`Ey}LjWg>%AnxAr 5$$Tt. olvwȏjͷ;VO!u@Q(bXpYhˢj)ߩS 5,ٙXyW=~devᔠ("xaW \5^!`ZW{{{HreT)8Cu2$v DH}ِϚJ$yFec0ߜ_-Ms`Oľ~Ԥw `)(]r,@ȏ88tXAWI = ]hU;1^[m,:Y}v_'_Y Hcw@{onjFRٲp-!Q;ɷ>=[P̚ )CsP]6y#A]A؎_r( wwww>?{ {NOS&nQ?K/ yY7r^MR/@IC<o ɛ ^eBs7ovvwww,'ƽ$I8= xǂ[⇵x,V!r!g}Folgǡ= 79"ۺrh]?+B?"XF8:NWov@s &DsxUH8NEf0d+gdM{H;Yi.:3(oxV)X V H%}KÉS|{{g]eypp`A5qXfG3k"pd' ͂L U+7Y[_<PۺU!Η.6P&cyzǍ `ɠSSf1)'k=f% =/$a6AH=uMr- 7vOOaÿSda9޶Ű϶ Q%\E=2*/f4dQ-6gxe@łwϒBC;f8SU祏HԸeAohcHXdx|U4?{21]pςEY/<s.tU% .*AiO5TnCrgx:i:_}t P@:6.W80BL*<D!l>ry2?l4ۃ1ˌU Yn<Ď< 0x Tl;~{ Bca[ G<e&*-$u<k2voO?^u;A$ i*eX?x, 7$ ݏ`Nn +R� ;GRN,*v<)\I15X^d_E&2 Ea'cv{6Nw^ll 8Bd^f,ynx}t5 xq"O:mlM!)Nn/Z<6f0I|BlC~3yb?_A&KZ?vAdV2uPw7-@<Fw 2o x#hn8 'ښMZ0)v$ bs"& Rv1/ƃnm:�܁Tt̙.9ծ$fb )E.ix.WߺPC |$к&ؖT^(l% n;{U3āqI #դOOmH]S9>~F8/P6E~Po G]g0;ESܣC- r<cǜj>"-agTb=7g}N }::"ea<s!aሕdWgGx`ȬQ؋WĐc!H6Nn>_;Iw?Ǒ<lpغ 1~] EòmYi5PT''ֳZ̫T%.S OY\~y% &o/U}»ë4CE5(A><U7YA@Bob/b yxr-2d v~csvl>3R<5ypy[74<.f̏: ^RPA )JFfA.4N?M!ƽV׫<BYkS+29`͉MZt80_mx:lNƟmVƮC!iB32RҐĹ߹=<~-7F8{�L.PѼtx艬ߤP5@jMgP2āO4fT̪r+'Sl0[<N/<m华^ ᮖ”vǡ H3j*<M &yZ Ci؂KhQQDZ/3K)6S^AW6uzmAz!W!0":o*9G Ґ߄ efHvKU$[=)>.z17#$ÖzUi'Fͦpo 8{Nfi{Bo ]aSFb%6\UP""#2J@ y\-X摻:TrLWaaPh)pL]Z,QedIPƦFSl =f܋|e B2R>|- BвY~YEG|a7~`oP2HVagq`~Xsue2߇M{REZbOMQڵ~x| CaO0f&p:k"?@jx@cA}p{(d9UFDdd=>7w@8!99^%~$FqUD[B$aXkrzNz$a#x$�ƈ&еO_nƜE1E-z@B~,bl*s2X':G fZ]a8=]ӈܸUkt~HQ3nGc`R]Ï?Ml4g\//zMFO##NEq=Dfx<#ޞw)McP/"Pp@|n-"8&ZuY'YdՃ<?1Ced#r[1k4gֿ'J5ikoF<"n̩QU6褟3pGdxkA=MLֶZZ R#3T4X柏W[887ώkCrCW (3W8U$;ST?~'|<2n  t+9lߘixx(LF=%Q_lH'w_X˝-İTvybԛ4 D!|-UWƍ6/+ Q#RM]`%?7?~l±O[ ñTvrPVv<_ȋs(-LM7W!b8w{5N=2~mxyU ,o:ǃVp<*|,UTH&.cL?H4y >aU@Iܸ}uS7+/*nyq5&?A }?#L|)a^@if~@#K%,ԷcV_Rg:(.UQ,D],7_5ƪxѐL?9|&?,cNP(4yvMgHx -5\iHij~^K k]q "1!>P4ðzdFdF\pHqjJRozKeǂOSGSp vqT{y6 #g#XO\EDĂ` ӧ%!шbeSI`؇.d^-Ilhxy`U[բZu u[1LJYba,$7ni5ݱDbjV0qO0*5h73&{<xy_A(a<"pPxfbںn[wffI!ľeȌvOrWXAs</.?iɛi)k 4$ wHƏ)j0׷Ms$X`$I&c-(2']LKcARݤ9u MfUq%dܨ]?ں]^_^jX<licá&䬉62`DI7uEb sk8xH'jW׵Ɛ+y<g#LH.hEo�Ϫf8E*W?kqΈ~L!W\>mm\__ջ-x9x-ҝ-H$GTIEɦW䐉B*NX<laI@}:n>-XC �Hxғ(xfVW6 *(C;A0y(7wu ;}juzCbM r�[`jSgX>uSpz=@H;귮ϯ7w,IWjAoϺ+G/`Óq$Ӡ!=JG!+7W__om YH /Tm 4[#S)u=y qkBfE8m4[͓w[[ /kAc^1|AHX<@0_#ӰGcl I$|3OtNE9Ofiײr8,DQ>#Lh?)h1zj|+"ڹt obud E&J@"~|xT+K'8_.3H1IU'1M=Js]\2AV(b^M[f;Pu$ x2TKa;L&Ep@(;ie9Ҷ_kۖ8%!6VP8Q-@7#6v#N�i`1;7K0lv NU1AKbW`k*PaǢY}^EDJAqm(mi4+H؁1Ӏ"ã!ai+jOSq\]ʿ-?/JM�u?$ at;q7; <';+5"8/ yQH�G0`?equ"Y֟gY֟gY֟gY֟gY֟gY֟gY֟2k̰s cK4iokKe3ؑYm uI! R�5OƘe"k$AVoӍط Mڜ2X5J\sם^{/aV<|P/3hNNFV8x줩k#jqX$yiyֿQlF ]cq|z~Ԓjk&cۤ']kXY3Y OңjQi5Vw4QcN1mѤ/ۈ2S=jn5^:tVLt\8-YA[T3,M(D9 }}ń,7Do~?d9 �BX{vHܗXËqfe1uq5Δ/V3_\i x"I|el1UVE{lSt=:;I^VUvVe٦/u~m#^` c|BDXYz5mw}`yŬ*Gs'S @׆q^\,rjaD,LqPa-ǣntG ǂg15Y_ٜI^m(Oq鉬͖Y89됅|xVEOWcA$U^f"$ɦ�1%re_?|ؒVs4$vR\e1{hVBb_d `ၰoOK׮"u8u=44W*h5Ci8('O\MgEQ͐l!FhV̷:IٝS3l"PS$QD"5{,W3 L!U`/`;xMMD2P9bG@K HLf bQ{QfQO6-)Aypr+qXxJ] (xBj8óT^j5/S?C9)h;W5cYS'%' 9HGbV3H]eY`4HǮ.*f~GiL`RT#BL$ #Ja>Q?b*y0"s`xԲ' z~ s2 Ehux6 G_~kLӧƼF-[8ck!dslP5pzʴMAfpfW yX(VLGiF(> P23fQ3\("hiэl/rF9 h:?YR <c 9jL QE(r̿\0 -!FdpC9-Oԛ]Z,ӲP E~jnY)V2`~H@ S6YD2y"a$,H?h j=F6r|}xMl-5,?$RGrav8ٲ5a_ZChi%2cXa(g5 =lO0,=:~+*Tw,AxADk S^Xj@@ӟ F, dQ<+7κfiuy}(KͮuΎ&S;+HYpOmFRcNg6lEcl)ͲuFU2bbk%{jh@{ |P5I|T_8lae$+Ch"Gy9͡Fڑ5$U7] K^Қ:a<w5S-xqb`œ#AQ7ZScE}ȈeFZ9`$* * *ݯPiw"m@E)9t4h'�0 zW_Fȕ[Ş18H,slGk|=- :勇m8~sՕL4d,Mû.? לe޻ _=RH²]ӱՑDΐ /@kq~\El*qq5RM/ (XD$AN : 8eid1�J(t-3OgL|P0 @l/ q&-J{)d2u7E%^HjQV`Bx <E "!|Y0:M,B84D\){ ꖪځO8mu=U%5\ {P/)]HvƠGF0e|Wъš+?!8VVT>MMT]_Qܙ$r(!B!۲Y_WW4ؠfhgN4%XС# Qc%>D%LAd(_ P3< 9zDp=uÎnN/z4!J y6]Ӌֲ];=|HJA^׏ґEY Yfؘ+E oK79;< p<_;^7V02%M޵<<N9M ۣMB_!E]BP ˃6 &lP@M]rynkthhBjICsLCɴ"ϱŷ] YKM ^˺抔ڳ^bҼfDix6i1Id7߾S ߧu$jnuYl%5)YԠI@WO __-&To$I$)ܠ+ X-,Oyyȱn1b1*# @{9jG J&χZ > lM72@H W"Oeqa'K,y'GO/a ; 1BX:$k l؎&\vՖMCntɶzyY ң!h Zn�qUږp<�ӂb , -fx8($æ:K 2% Yq5qh Rې8ȩ,'{x9O\,' i'v$g}GQCRAǩ*urER}IC[`jS4đ t32BquwC{hu$٢{EZ 9{M�%͚yo�TDPqDFȌ[аsP[O }emTg0JufY@CV,F6eCH/{BL=9^޼n<s 4bJQ$"C~6% �5%z Ȋ퀫2 M{7G^~q_4v$kaYPm0Lڃ87Q9"yFCSev<tZhN\oj,B.=DȌarp8^Xf<[_z㩈ְymlAs|1OP pws_|X׭+5/3p zA"˲JH@݆=YrY /u RNg<3+@"CNG0Nםd0?[;E, ]nܹ 58{*TPs3QZ ]:=L9EJYB[Ae(LXϰ!.sc7>9 4&ҴHzxr'^P!B&,iOpwL9J5t9^-iNRCmrJ�EY^ "v|Ⰷ"",~a(dw[CMHp5L/j2ɡ%y PeIË:Q >ݽ*Gz>4M{ \zo?CXa<<%}ץ5yiK /Q]1-RGy:CxvL'M<p-(jrIlzGե 1nEat"[OnyYƴ2Sf}û[$&$aKA‚H{rsEqOz\#o/(WzYۯw߼; C[$\o%ڼ O23AFG'fx'C!^d=9EX5$gR |>|篧b3QH%vHv^;^nQ.4vZ(5~^CaބD)5HH(a.(rFL47G>x M2'I,yr׻;;[ixr1tꮍjQ?~r|)T�ʒ#=9Yc�`Z`e ]*zwr7_lTElI<-^|֫7{-3iij48f_xC<Z4Uu>3igxpY'8țXbUz_( _ C˭߶ww_:k O�y _ϩ^.9nc�2Ob9 FEfNDZ,w_ջ!\O•Y#kzugQ^[M7*&/B>]S$sP4z!OC.5.H@Z�zx/?xJMUPJ"}><�QOh˧q),N;! S\ʀj4T˂@Y:bk_|zYT%ԂUX(:x:JJvo흟=E?.B{sz|~}  g/ьeP+[/qwkbƦ09|Av~T_Ӽ$sps}r|r-OC|.Rv?t{$G]7l�&K 50TViyh@9iTzsf4j:dq7/?v7_1mV7*^]_{^$rҽ#A ?@t�n?PvTܚDs oQjDnxBzxŤƍU�I TK뫫΀,QAEuu~x~P҇/)^3i:"˩Ew:'_noo=lHIY#bjӳti%'bMugIJձVy=!z:!3v4Z"&"":ݛ헻>~_PkA :ӹ%9a_6i:aaC8W"" >lpt+y`yfgHE�ecE T[;no`mU�P#Q!c!Ã�l8#KK=ۺ {QSHXW%@@ؠ&Ҁpf!r4҃ۃ'k\^}(單{NQ&61lN"Il .n{(nB;jߐꞺb! ]iӠ5Ƒ&4u^"vۺ<9zf)˫?}xAjzL0ƣ:|ױMӴKSww"$ G {E&jjdqsV(/<z` !FJ̋?]\^!St__\6ezTYYwFQ< U8،n<DÌ uc$4 T*Ep$~ݽ.чgǝס맋)$9.`T|x_ 1kC 'mH;J&iՐ&SUq7j7[ۻo޿zO-Vhx΢,#p7֒F{uk4D:gW1A1!e2N"Wy! @&HLzo,ɲ^uB\؛wܿk wF>%S?!fP;:�ʭ9kl 4z(c|ݧׯ޿1,hv0N20Lg(@FXNNT\?k$ml/��XGWBA@ʾgh=²۽ݝ޽h*yyhtV@:]19t lBC? MhTM[N|0hDMyҪ aK\SWgu3 +uǶ-Բ"7޾ SDIdƑ<6"Vl^`,(F>r&mZـ7i�‚;�(eFA4@I_޽ç:&Ȟܐ Xny(@-J: (e2)=Ag8!j6Ȅ  :2'A@-;5\|y4™(-QoXFt83�0' @@V͐,pl]3e'$0ΦUdžIv�yQрs:91Sh0:$>mQ|9x8R 3QVX "n� fP9*CZ̗2piP_L#1uo)%ulJ0͘KX_x8 +P~wO;�a$t8 P\ͫr;jBVe(<'nc X ^%~}{}}qrX)N T7gxCݒZw<DuUh$Fc‡0的n9 -]i^8J'rNjmaZNg*AOJBmXDq?n�nE(5X.Jڼˠ8)ccNb720A:=F0ŞT+ƮO)Ep^5vt J]oa@j.SR-Brf1:LlSC:CgdZǙuuTs,K"Nt $rtX@!Ȅ|7U\s2H_BؠRCnS 2÷~)I/.&']וd9N28yxWɼ*p0HFf`N{ an<w��2 󩥂y@뺌lˢnG*U2 f U ޵ yY$  ljkGԢ4K&3xPRCC׆\Pe��3wN*0. K.(u"wع0×9ޭhUÀ m!8 5 %F>(aѐnpdÌ8iQg& A)Y(1|q6uۀ$>"ˮtK,s4OBf="1Ij!%]BC�Jx)E9td(O.(̈́ ]K\22MKEO06 %bz(FtFxtZQ P4z@βBmvԦT\p$Z/cDS  ،pց* RmNUݍ'FPm@:i0`OOǀXM;H3$8Qb:ٶ̈�v8a%BЃF7 :Q`w翟%9yE;a1"]zcǂrwC|XJ �E[Ո9D%`{ u^ < $BzW�I$r K})G-Vƒ9O ~9wO7ǗGmB(_ D^Ubrpp3ڮ#shCb5z>&` ~LPz[=Ɨ-~q2jؾ>UABOqm9.۽~#0D@ Z0p Nl%v Fz<8(hm9?u8;M7D }]ᙀM 0#@q'pXeWCehxт n]AIEcZetͣ$"&Y(ֈV>߿fАnIwki^71U%%I caG=yR$qg+i<͐U^B N7Uapsy}駷UxpT"w/OZOyEsy !#�'p 0Y*N}h<H $iOJ_![ 87<?GO8ls"d7lcp$و#OaEcZ IriNT7(MU 78FxtrvglEdm5 u㙚Ӥ�!} d,as^݁csgZN(ЩfZ! x&, <ۻdqC8n#lH]y*NyA 8= O[( _>zIya>@yHlh1y;F%X'h=C:�]�ő4Ѭ7Su ֆwn^ox@`_B!yyiIUqt{ue\7Pq ϼ~&9P^"j4DI4OjOn$<LqD1>jQ98Q4zA�FC^ܰs{Y3`07j_ߴg '��:}ex~1޲=0w2MB du7`u1P FH+Z =x,B3܂ut2L�L:oW֤; SVA .2f)[9)^ςq\?S:1c@f̐鴄$g`%+q*[im"b*A f I?,dAI~}A=>td/(=/(1 $0d9ofU"7ӺhrK]aFxl2M&1 aw~g!Pc/h0']R!hxP GFUq|їg27yc'6ݡ D ղru'=MV\7ht>%0)W;;ۯ;#̣c 4GMuU 1іC̔xy*業) ~zp%hJ4"kPijόcmnu8[HdP:UW-I.)A)bI/A5,+HjYG*ܝWGӼM']|fGGˉ+~sZۣ3 E>fXgz]AQx_uUi3=g| 6RG#cǽ9#)8A~2!0T@}7,/):X%Ѣ)<o~=DE 4PDIsiݴ�ԨfǴ "p$z\5yhE'n{>RW,'9Ն"D%PE}=趺7'y*܈U,?r9h#t$qup)PE崉 tW6TI~߻2Ia>",;-J܈QpzCQ5}3[Fm>[] h9 ­ r0$tVD$x�dZe~ o[η= 7p!q=2^ "CsMg aR 3\Mx*Eܟ" Y#j/*p|í헻Ev/PmtxV-Dv?jYd@Eed'%\T6-Ϣ tƬ! 64uwV`rxۀ?x \Rg/ 0mPp/(鬉-uoƢl f1ob cf BR�ځdo=?H%Kxn ~Z.n'/_n|וH'6EOxu2iwC x mХg4)DRtG- vbxgFc7S]W-?#u5q^B.Gӟ}=pY {w{ 07ዀV wa%čC0z}ݱE;'E 4ґxUS:MQߡ5,? =9<<P6*m$tVATA, 7OW[[ '\XYn,Ҹ^RM`x nA܄ 4ID7~�! `=(7Gwg_,v x^lpxF!3Yv",*Xݱ* /nDMۛI xHQ,|IiewgwCVx(v3-jR[Oǰ_c-'&qǖ.= ȟ{緽!vQF,{T1){�Tٳ0z^?;Ltr]KMj"?ⱝn~\1& [!0[lձUvXȦմ.ߎ,3/ov=^:c�(`�Mr29;Ú"̐ @nyM<iS$߷!B=kj,Vx@dHÓ;~;  C؉gyE!}}pK 3.NFwD $ 17B`1. lf,956LB0 q}_#]흨&异n qb bƳ +f(f#B] C(7jX2yz_A㷶_PX\)y0!x@3 ,=\=<cT#~vǫi2CtF3doRJ(Z7cwo7cwՕq7Qoo:cϙeB'탩!+ϐ"~Ks Hlg܅Û[܆a/RԴx=nk39x퐻oN{n[)iz\-Mq%ef"Jl{%͇ȊG q n;'Gw4#g)Zlfyg%N;~`FfǪ8 |^ N^RMta6�-Hχ7;=LW!=xpV3Xeqp$"65i@j .iZ1Q R,(IY 4p% vob;wnp@KKxp;(@ǰh+}m9iYE9!M: Le@XZ8%mT wvޝє\Ӽ:хZPd x@ DP|>ld,3)B[W` t_w_}1w4G=H5iz?Id)˶## 9IE* !+"]ixZlnã'a1ˀN7@_!9>Dofo+Kб-@W;_Bլ0}5H&lGxsa\^6 @(8Ϗ511*^]b,zDiG*xndY"ycvo,6=tq7 L2L?oXؤ?lǂ/ Ȥ w\͐Io. UfaXO? z& ~3lpI�:K.r~G/7WUx!ƒg7j&bh_ t/Ac9tڬ7k 2aC&}+W ,SC}wF3JTN-G??Mgy=S܏w9�x؏d͓ <jQ�x۽1{dRn&Y6 zχ:q9$ 2^1ћHqmW۷ͣ-Ӫ,2B/LLx r`zSt')s?VuC[-I;#1_x>rIRƮZx~˧[Gn=`3&?\-Sld@z֓βza{ s?}{ qK2-- oPxzԽ:; }P?dZ>~=8PUɛ~Dx Oؐ8!WCPΚ*׿8t@&E[N4b-k7̙I CO ~2XAkYs*?W6 ,rtaeY<D4i,ywg?^м$rc`sP@^|OqytuҾhv_eYxuW7tdG`) )CSۗǿ~B9b}Wy�vzD=^sL]|¥1B#הFC8EbZ-. 6G'*GO ^[0iMRC+W5t?̫:(C(PKֈ j"Er_<ge$s|~qyݡ^c#/'>eQ jXtv?fe<fb'#([DoӢߓF?CS>4_zwC^ Pي !xq <ed@P#zBfyP7[ᕫuQz<T:޳M7M/.hLqSLjrIJАyN2OW5+"m[Oh.QynP-V#˪iR /!lESK+ a!KOKCSE#,o?&x>+WzˊG^&A䨗EIlq=-0 +u``VL;*5CZ5''Ya8P%F CF'9 L@ %Nv4PJ ˰v o=`D(Ò_*FX y4 |E|FfbYֽ8DpshPv-4"Д$pLx4 iAWLCx>-]3EJ^$!1ʩE:1z4Re�Cl#j<dDAD3 *:w֙+i?M@«}t=tv/h$<'y PL"u)dp {Fh Ղ\L2ꦐkgٌjN >ݿ<8 2;QzMK|5ng=n,IbIa-?UciXvPM#ëO{lƳ5)׹*xK5Ыnu{co#F[y9I=2OV'K^|~w<t.L9 Ң,ؗ{nwaRY _OU IlMvыw_G 5E�e0�}Di`dpiA,M8)'isl "YUճM)~_"3n/Go'PHe]N\An!FӀt/&ld9]ߖ̰uvrv >1�5(Zc^eݴ;T4ˉf2̈́MVܨuyq'ܸDu@Aϩ0H14K|A`a=]Πss$Ŏ*3c92ݤ.g񲺙LJ*FI9mQxfp dƾ* < e8 iX0P ;t]Ƞm|J>ogC8(%M3E`4hyV5}ڰۮyDn|$[�TQ% M�V[C=A ۃA2t[ewmJ1K'FSUǦ�jBzgi?cmCI޴FGcEXx_J=i$T'Pv8lG94&,?O:ގ.#A154/3%~2gil CƯkƯkƯkƯkƯkƯkƯ#f8j7cɆxVe? Ju<#</U}^ xۛkq7T/)ɴ9_ ,W(Os8΋?bH䆶[!!oFy֟R/י+Q|Cɰ-^ Iڼp8sxGm)SLj'&sL?zDeWey R >i"^9yxedYxrEI/0yt-/"%EjZYq_q1I =YgYJ1!d/ Rͬ:^/^^q5K d#ټNx 8i$EU6SD:v/F^3}?d\g弊\Ƣ!duC),Pj"ma/_ ݬV5 f: iiiY"St^ܭWxh0܋c;C哦CU`ecMCQWA¥oFIt`L/nB+'E^/r ?Fi IRw,Vh;^헃a:]Ej"^,nhv,Ɂ@/Y\rω':n>T? #kfeDJ$Ѹ рu]U^2/f5ZH֔bDPxq LW!NlX$0t*Ze[͖M@9&L<ȃ;&&Y,TDۘ}H]y4_bx;hUZFoXD2ϊuwP?8y|^nz:hy>}2hUih]3"p3x)QYvy*y\, Oz9ICPTJO=Ik˂Tx/e 3GDi:xHL;*}!/Y* lbTsÏOcV`ŌKVSBJ3_۷7VOs\wpB@}1!&7BȮ1\w˂l5!@T;DG~D\$3z,HH<vc_m^n[>u ;~?C򒺉9e9iZ4YR )ʹF1. d7ڣ�~R5d99V'u;"-b9<2yҭd of"Si7CXQ}FM<ēɂܚWܵ~JBL K"+D8f4b25m9z3F nQ9zx\eiC͎g5J"1Iu~>7UIVg$(ηn+Ț/"!=xr wg̏Och1̈́hWv`0X#wJHïѴزMY=qSlHEis Y#ԕ=ٺL&]MBӰS?|"GG^ =<!φʱ|Kϯ8 sj4|{\VyHtEtB:I?ꬌ=n"Q۔ s˱h \M$j)%Rf{*p!&JŁkÂjdVBnxYdiX,7=Ik?Ԡ6GHOcj@Sn>q:QQUo/U!z3=,s{1%e;*B:JQW6\nHo*쀂mH;AuԖBBY"!$ֹaX}DQZ0c*H`ʐzqcҪOP*SaE�Y;P q&r%B=)e4]: [x suz`3@k(e44,F%E4*oOs$Y{M@Rnvˣ0 nnD?/4PƼ_I[-sGbC 5NJlt ф*xB,1,'=Ƚ"!"5 _:/WJY z+ԐtR3S?D?"4A(��A EȝLQ�5QdzR@q˷{:,*a.+y@e妡"mG8hP*5u*EQgIxM莭/b&)�MC0ڊP I##,KBySGpxPb1+8rWu#3kT(Dg)MȰ n=抅Zo14MO8%X#F"~E DXȰ, U9xr^[a\TS4oBUȷڤF2A27T-Ӄ;uc^8vd@F PC:we C#R`yG0(NWc8M^Q!Fзג:7P<}vg0 ^]aVa]V>GN5?7܁<y4xM iL*Si[!ROSUPXQ P-iޥdC'5-Ji֌T).dmQ6�PK<D^IP$,rN9uƚnH{(h(cm׏Wk(RFҼF6kz]Iđl<c}/r%TXE]%ԡ4Įc8Qi �N?Vjy!JX!sE_,K3r{H(pi_'y5Cf�<^P&js}{|}̰*C ĈearP0fdDv>dWT Ӽm`jl~@ѵmI WƎʊFSXy�Ua%\]{�@Ӭ E?}zɒ%q !$! Jr}#rOIT?y=={J(fA&VOC #+6VMh"3ԐF㢫9<qi "(āHs0=v\tPM^:-km$8Z B'~1{[R *B$sQ-(QݕcA×6ոs #a%0%̽` l#ҋŬQS V?NAmt؋Q?ƪ0PG2(M{7_>|<<V8=!ĨGѿrAHiUkt1^z3GAoH vPT󩥴w4be ,W,2w{>|hLBs\w<o3L* J*M 3^A0R f,i6I94d́bZS%9e{c[Xc/* +DqJ62h�Z%C_0YǮ܈I|d9[M[WQ)^<PBa%b(JlP &4(l27]F_$P4qx֜3!z u`c<BpY@dݟzv{qKED EsȗG:666}8 ;ŘPųrd%bщriQD`V4;8].Wê93Uu{ks0胥dPsI;<~fcsaB<,JCN=]ߌ((57S:_P䂧0!ՙghXҮ4~0dX>ig67|<eB9REZPkц7IBaiNT8vC 0̍O\kHPUv3+W_&ҍ7`YXI<'ƫz܍[o$�A!{yco#VT/Qv*K2 *̖Ycssk(*9yQW[ys{%XE l"ʚQ<Pw9Onn!ޯϦp<ݾiQގ}8Z[;}feDȢȡv6xf{ %)#cY.uӒ "05Z,KhAG}6+֐e&2=VOpN6dL\̏.xnggkcO  F{9nΏ/_K->^ ND6r[nʨgi&O߿;PVwRЂ.Sқ;oG4n?-(/"S, }gRZ-ZIgG9Y/S�~cqa F}�7 5;E"2 v\_ 'rKCjQ Cx{nz~$ЀcA">{݇o6ӲQw-p`uYbi,�,fU嶎?~r̡D&pSb:+HȢ,a1lPptG(XԢJ=@%N޿9vsN4ꪾ#.*^BǓʼ>Kʧ3=@Q̳˓)!0J<} ~jj(1o`XǕi۝WNu%PY;zf}[e" 1B9{磃Y�qVo\}k@3̈]IcX.qx݃k)"-r {q|xN\Qr.;/.~<%V @ ۆB%Iyf޾lHs N60bR4A! ?l}e$P-jlup~}!?(,Ɖ~?EzƳΰ}FX"Q##> Lay2/d([]1Py!`䴨Q~.ēݣ󳃷q-d6sP7YJ%Ӳ]hL;f @JdJIs"_on9/߈=iRϗ'�Lߟ0Ȼsyttz鋲\>~Ýv.c�W { B><o1 V(4%cĒ`9o7[=8֠pwwO=U6-dӼj%D}gWKqx�M!qx6@׍dۃ&`jOD{~\*UNA]Ubǻ[o6oV?vZHpi[vp#vIL1"Ga /g H,d#Mc$ikk'h;xe2=2_nRֻ([w7lmooD̪ 0U 5ȝPGMTB �@5tDS0\oD|*z zp=Xp@M] 4Ώ?{vwgg{kwwkss{gwoeE@"9|$k zuQTtR.Y:_oZ.e?} hJJI9FӼ>y۷{MG#ֵեhwuD n2C$t2-lC�^UjL2/(xA߽:9 PYnnih(v4~x$MkYJ$�ACFC ϯ: -?@@LqUi�ỽOۛ;I1[J4w9*AԳl�iۻRP7$AUkjbxA"Um j_Eb.?:~k=/k`uդOB\oE,&eR89[Mu=7*r3 fX jO&YSɴHW|V:6<8|`k`]F 4„4at҇\,֣ D5ifTM6l*bxI4e8v[{8?,pc6ݶ\V͟^Y*tͨc[ϙiΰ\ %6vImh׸,5$g;kvr۝ݷ;U1_hy9;EYIbAxY;waY*?:F5UJ1lx:%!O(&Ilu7ΊJ|> 0jeÊpyk{DjBLZ6V6[U?Lr2uRU$Ix�EFUUr21DŽm 9) ;*rb4Jsy*qBݻ{ނʫ.JF|2Rx:ׄU iA<ZU4/a!O=Fn4ó/( гgu LxIh4훫A IjkDB+0~GD0-Ե (vB2"* Z+r/|N U!]6nv͎!T58鸂Β$ x"ɔq+ \ wK-fQD ;~Rc<A:*{sy٣P.ֳI=BIRexXCMaQ~ Le;爸 F$:�xvn7h %�+6u߸:+�0j&SlL(<PZժ7_{(1nX1'DniV_i�G\|@K+xs*Ay0~0@\Ceoaf*,C� BF"QEY¬1@")0Mug85agWxT+"<rj\_ܱ&%lBɫb9~Yʮ) ,Cæ�,ոǐ b%PNqF#AL9!x4on st׸`Gi1Bi<%8˱,!B% 4e!>exݟ5]a3w{Y,5bgM#, {lZEQRaOpakmz;EO2�'E=+}TH�luj6myZ<Nb<ӽ u~h`� $1M]qK, 6J2GEԥJ&qB7]` %mTYu{ZGg^jQҷ8ں8a$I-?Ii$Ť1!eVq�|lţgҭ�:i( X Ȇu!^p9=zh~ '3! &}=8 QX*/"Z@׃@y]B`.U$2$F�w%G]ߵ:}V}9TQanMqiOdz"MrZc(K<# x4�EU:̠IcE7E>\}>) ]z)xI /Z)$hŞHyʢ9L{ZC)*Ӄ J4 MWgpĈ jZZ^3`Qd@qAaƐr\@"`�(l`J)G=I5MCZϰsrt3El}mt#{YU뗯]<xM>')(L�LBZ~bDz,1=AQt " 1o|m $-&`{ت P7'CXXn04+]4n%(tU%9X4| sUAvpUQnM1 W49ʬu fWuP\5 0 5<^~AB|r+Ziί{Q'd{ EYiZWwRݩq !G:jIC ۃ'7a8iKpǐ_#H˓թcZʨ?dVQ ]/ͱEY:�uOec.?1< jm{{rEDzj~>nvЄ!M#/hq&App봇(h餂3Գs4]\nNY?fY!)ԕEc+vZׁDw& suAeyq(a%B瓆* vjFͦe!F z1#0LC4{x�ⵏ)IϳżB•Xֱ. ] |XUYǠb_1\&~" *W$%~Z(cn[nu,¢FYQ;TTNrW;wCQm(^NHZtZf:7�_̬3x);ȏyp-7yF8 klyI\3�3 Y<0� b2ne&�?aq>q0yl>ŵX\+C2 ̀i&|R%1)>p@wgWDi"£KUILg(L\ pZok1<s?z !&ٗ4�G̚)fz=R,>m SKԘSe}q1_  hlUDoN�zRCOQqHWgvUQiWpV$AaOyAήxA{ns$ UUx(؉$AZ_ -¶B7a7;ba8x7)bXAU 1I#GEq9uZ*O1a>gq==<fah=AHGx"l9  ˛7Gۛ;'#I ^rw<QAn)sx(٦R!+arbSbٹ;?r#Tӹ^:!48Gollokۍ͍w7ÑL׈| 0ٸģ<so F@cX oȉ+*]ׯj!b{~'rl^[%6s1 nQ@U] 1(&3ۧnUT0[Y/0zeFt\#Sb.:l9e@Se+~5b-; m yB C/׋k~5 GPr@4~(@Z!LtLЂU58| o lV2 V9C(Y<Ӿria& Oݦn(|;- @ :,xb2ʲ!2_7k}c5jU8TH Z=N2iyxq@ xA513�oY@{Ti8ɔ\HH߾}۳`N| j?|D=��̧ҸW}ŗxJF;Ƹۘ*WDоWm5(?޼޼<EN,ӵCrW~{1 ȍ(Yj)Ct[-F^tӭCj;xl dx> ӣJ`#X/wLVt6l;m#J3<ْeU|1Dyj/516-F�ePį³㛍oNoo&ӂ8mA:$ı6-AVO1铓_u$iAN)ȖxEwO `@>UHNla_9l߽CUwR<(Uu/eHG^L \pK_e rwlB]hBS?6޼9͛c3 X ::1''ĸ5:>`? zD58�Q$~ؾ=a% {i㢚WG7ċ @o?axPIK xaKP'k2T "Iۦ0E/^Uj޴NjJw6f4rPT4UC>_ؾ֑Mcn\Cǁĵ.9xfO:F#j3;ijb�p4 12" Co[g*s룋ox&8eyH%=@N{xf=a>3[aq}S-A`-;33 E5_7_KFLW86Db>C-eb2,tiWt<}Nx?u| F7a_9h G7We7"w&MפAF�}vgvmHHwXɭ{}B\�ޢ`w@7[(Ug'%(c m vx&Q ,~TȤg7]l+`h,sMЕ @7`7?7o6q3i:vt@ʏ (X\|Kc*FM崖u{p5aķlm~&nsssP݇ 뾶‘$aX׭k5)Igu!H#6%'%5�`3,=yF,=.BOn [n|xn HI3rd>O -b̍F c �,M!WH50Dz4C`mvq \ai_w6@wBϘYt�VISta@`Z+x: %[z!⮑}`&2~,;q[{=ڸ0@$Oޡlj̘Ey.vm9f ^lS+%nM2ޓXN3RaCX` a$yd`3r^A1f !m `_|}<-"tϫBd˪wAWy=&}j ro�iVOg닣P(x r<=$uf Z}9�4R9캅;.=f/HGI$| I oȲf߈MUQ.ހ\B)M;DgUd*F50/vww�OËKҠ%JE16*">7^^�L;3rDf`8MEy3VӜ?; roa4mLm/ |lϗSd ߭- &qQ;`-*.|�>bKE&lVOsA0I&$Y1 MrU3V#R A&C(&lw="l\YYEUJhN?f\-aa3Эج8 >(\s_#BV"tA(�ц`=J5ο~QH~Z?>F?=̰/@MAS4;Ȓf?~$HzXmz82dX3w9{?Fqm?ƲݭWN';AIM1^&ЛJS`S_0>� �Fx/ƍoOk񁄫'i% b{ 75fIV/@|dCq&)'#D 3ly\ 9+$"OO`*kfCe6hMwj?pOԀR<j?_$'+ 'SlRs٢i%^Us FV$Jci~GK䥧?Czfht \+VȇH�.)�Of3lC͌χx:^dRh?qdmm7I]M9CUטdgHX*;[G?10DI[3,,g5+" q 3w@1m5:ttT 'o$DY6?r.AZ=~,"wtiԼnqnB_ |u#H$plnѲfOnlca "KZU; ^ o O'zjV'ov8QiIIyy7R:5X >ydv =N^Ұ$=ծppy؆\RxٰˆgPqTѓӷ5ޘ&ςw~@㡁FH. $XI {Z)Ku4F] ;.? }âJy&sLxoFz;a ZAr'<8LPݣ׍nÁh8WC"tV.L#/Ⱥ 0cn;H+c: @-CSE1ŷeb(SH |Z$~ď_>5C: bR "N*ߔt,X"(1O/ fɼN +@2@Ez5ĮUŽi] P!?oVc?<ڎH o Շ/i^,5R \�tծ#}Y ܝ6tD4q6}CdvLq l]}2-J[j_Kgk4  ɢI\w bP!`B{[fY#|C%\CN jIK&k OS#" FR~/HG`ێYղ p`Z1^B|W rf"m4 W0x(F43r `1t4˱v΍ p4�2Sn}A1~$?Z]|n4> /rw-HiHF\{>ꊚB aX05\9RH4wHS4fJ55<h#z �[F.e&18`iX|E4F -oܸIz!Jep`4dPVjXOn+pKod~>w{gV6%F%k㬹,�'2ijyx_'ZvX %*;xGLmKю5jE0ꪞVhKO-; lW;'CYKD~#KJT%p߶C @|z\ࡿ NH_VAڲp~ Op))(G9Jh^P<L2Gx"{YW9MGߢĩۅDV,pea.SC[wͻf z�ŋjUGDu I45_E0ǭ@"vחgG-1B["Cӽy5;LȳU0q #<ˋz  *VX-ړ9ᅾmYY(v)}W>|H l\-$k_!X4lDZM? &ا9*n'Wkd*OQ4C5 m?OCLܴ�6EFqp$H(P}Bz`sHLοɿP15LҪש-,g:-Bf._ 5 أ$uạ]*~:Ć{K8/X+ڏ"$pc)s`ʍeYO9b 9곐@.B Ue+s�bdbYqZ�v`5?7? VYi {{{{{{{y_ijd.[At1,yՓ N(M2OМ~2F^wzqQ da� $iI5$|u׸vT4A#&uU:68C< 3\_޷;97Bgw[\XfozJ_gEI{=Z)&P$ś^IJN̋в 7_,2tC5wdV\K$Ԍ4$WaQY,jaf‘j٦nyQ%rbU"A`tJL/ib9vdZS?{/"CU9ʧS˜cF^;W˳M&&em+t5zBgݗˣ^R5R;LROh Q1GqUƁ8aQ..vVϧʵ㢮g$ _qYWBU1x{=r:D"ԎO(zOլD%Ŀ3KuBܥب Ed{щ}u&er͖DFn>!R^ E9sbQ8\_A٤J=Iu)AHA2S}߳Xn6%ʡIlk^uwE]3ͫ.x45%-7 ո#q5='9NdU2 �[S\ޒ}X#G4~p60Q^f .y׮?b ~w'ʔorzn%!a:lS^+ \HiEbc胃̿? 0|Kn_rצ$q~M .0&i^�+l /027rO!֭9Ms 穫э[yE5-Q80lvHan?nZi QXe<="j;b+쾪[gnea(ɀ|%e "Z@}ȚIvP y /?IyӍ]oV 3cH4!44:.['_/7g~C>oY]4@oSe ]mZj.OC!( tReitg} ~?H׮ܺW LMQG玲&:L'*:.Dc#T?OsYCͦUYR!5Ca[|Us\UXN7�mىi;*E(G". M3TW!h>з 8qU<ՇEH3=W; Ddk(KH @g Zpй@zbK >0%ƹ2%^ZEI9C\, ?hȹqu%VCx/ .BcxutѺ>:m˶*CDF9/Mz@2Ii(ώ֊z"ʵIB|Ï'ww듃OM qm]%԰s=D%|]aÖa?ҀUJ\MKT"_.6p3ߺ>>;)e[n<,'#ArNFOId `1FUI[rMF74o.N(s! BJ�qP�HJJ?ȚJv$Z'SŽ<(J n쎕-QF  iEՄ8w"$-Mzjt>2#FB٢ !DIrxE ۭqYtE1r]Ǭul>:>)EeYҽ('Dy̛MϷ$XGSŭ`h]8NTNbZbyYďY?D2P#v-jӴ׉i.v[H 7-ñ)Sͯ<|3{y=~Z!g"jxROC5B)x:[X֩=lЖeeVl#}⽬.(d>r*`k>)B縵#ʠ&!H.HB4۾:;tx#&=ׄTt'!VG$ 9[кzNZQeEH*&c=a@$(R컮 bP) "1w֭r(XH҄$12Q1@ 4J !rZ�αDW$aD *}igY4Mż"@�9LH; 2PRʅ/P~@$F[c jJvY&i~^Vā tdKj R9) OJBKUxSt\0maucj̃ͮ% 3p1$6Mϑx;+"GHӣB=N#yd'B׉H�фN x� M> 8DžuAu$,nDu@+ŒY5*�Mi5?MmF+T$Ae,uN`4bFNbp xmEub2a 穫"K̤$Q/ط k O !Y]uC$�~ i`! @$ -k>D Te)7?w% 58?ɡA'X k:NA yH@OU4Ԋϫ9:p AbqEYA S%k�].?fž'xGiP1*FlX!. }5xP*M~趤Bx4׌;$:/y Ў#ID[$�*$$tZk-2#%�럙'k޳U,07n~o-Ne|)}{;oʲ[xM²Ȧi# CC~.>Tp"@on揍c+f GYd�Vޠwzxzx4\ İL= 5 G ,ityBno[}"˃Hi$ڰ BHq}.6%A=:]X"Ou`4 +C7 m3kVhj )p$n3^Kz!S Br |bV.T=3TUY`gZۃîbEiBr1LO <4*<^te<áK %0^ "Uye/ϑz~X1:srC8A:c�헝㋳} سeJ4t7oYnk džȈ-r(@�]S{Yv=J3Y-gwݠ-$#�UU*f罽!ɚjȐq(h ejǭ,r1JɺPL#b̋2tKWƾ>tU�z ͜Isww>eE8vХe͊la!+X"RaEdVD4%nC51 C婂r-7xV྘$ eK`s/;/iaw9qQgJSxZ(}5dB'<.%ғ5p(�ljFu0t;`!{TdU2K?mlnmZP5CG2iZA@P]7H'戚?f^P.vy(:8<T#Lˇqckcߘ!A]HXE_xf7Y]EQ{T݁2I҈qHM0hH(HD/jƢ,I`6@]˴ca&||՟ch2r6_o{nck7A>֯ HxPMf&(/1n & ]}~EvIΰp=rXϙ~N;5P!/rZ<9o6|+Y4'mP''QjB<7볲aVe;Dï֛KuT`pC1. *<?~f ~"%)H*X$} m_SAk c[x|ݧ,a2=sR`nmlJ<FVyVtux ﶶ6OXJCKgoNF<uwgJ dԙ":# Y p7=$pjՌp^Μ/sc<5 UGG[_~ǝ;ARW`/*&/ HXu.S9,[$9iq]d9'B'|\M݃/;{ObM]mΐS84d'8u|tA/0/ ֠HѨeP@F״v9u KAt;LE \LVMFۻ:i-й7_; NXzZZGn`=;I h5Q6ID<ȩe5$)Xt=h]s i�7l ,sai^>Au̦6vv>~:>H}^&螆#өc[ȡ<%Ӷm�C( eAn,Q5P.iLۭ?|QJ?䉣#V325vs󗣳Û6Rlz w#AF>G}x$G iEFU5LgD, dB5~zO [#p5?x?  eeE=iPZu\igGGgG =~5`q!6IjaakH]ew 8:+O't n0utua++L_IWuppF_Ǩi"q u %8mV3h::/wOϨ`@m2y/t{tkx ʠ6yaއOVDaT9!4=L Uvo.XH#r$ ͦdo\\^ut2=4w뽋ݷLp{pWh(:Ŭj1$J"~v}C)н<DjPc:ʜLUkT5&Kۧ;C>::> `ʥί xɋsT49N=뫋2BP~~0ճ9R YI]I8dg[޽{1 ')F԰{~e ^Ifcs=}?;wwgggmVT^}x!vYl@(V3K(,j|ځ}ex*}q薩V+Pmvrh0(p矟h U_ts�,jr3@f1/]a:߿:;܅eۏG緔Dפ>'x$Jfc:̪, fQE345v@&[5$ ).YXKA>-Lgg;[o?\! `2[]=\$SH@%3U^_ µWA/H gq>odnnǃo9܃]s\*~lĉgFg�<.fEV:rgJpuvlG]S2I%kPxt>|{ΈPvQUq:G8@TEr^eY^VS|qe�Jl wC8*k"y,i�a4r/iQ1-A!L99`~ \a| (bKV<hlT .ҿ[%MҜ5;H7tSx.L}>y==P[qxU"8'Ԁˌ&2DtǏgP &&l9ЅRZ=hV\S CYQhcx .Uz FRZ0B_" U@�sni(V jYǙPZbRw fIq{Pq.\|<ػt͐P nX}C?ܥ5o*>=J3҃23 Q p"S\R5 ]Fw-[@ =8nO ={_6/>ʣ$ ^.WMjd r^c+ ?hq$(Lsz5P8Ʊz!vLg M\A(tۃObct(*|Zy ?'"PgTY!Qqt, !A8 cQZMؖy5lyZWeEV()tRP{p+N 'rZaA1”8 7$/ QB `ш <jdys `~w_޽;t(v�]m1'F,efqC_ ,o':˘x\.s~T&ZUg#<FK$+j o\C[t\DPv9Bwǎ /xv KO]^\i D^Ýo @F. Xdq9Vm#pFru?e0CI⨌%L59>X* aQ=J"ۻ<>8H*84>mLӝ ,crXijaLtw!0YYkk$(ˠɡH׻voo]]1T\3%KwwnՁ~,%:Ax\1ӊXÌ1ʉX9$Ë(T'( L C̦VwC!@:{iK2ps}#QdvH1| oZ7PaWjMG59P~*Drj,4tm!Br,p uZK=w_uhTH!/ڒ;? hAVT uQMeNP5FJo\:>̭b>U-{+쟞lϬl; Lul [%ʪQI5)Ns1WQw ض|x,IOXgUNkCTj]䎇9XX7'-VQP-ȗ|\LcdXC8DY6ٳ9�`xXU,&*4Ud)FZE0O{w7_OPW<G̨w7U:ro^6E 3`8j711"8HOZC*I+Ct鳝/G痷v}ygİ C4łOp_NX]j e3 Z]Y1!sLnG{Л`$S(]* ugu">a^$G4ճ!Pz(ׇnXa sK�$!_!D*n(]!Əl<g`z^'9B<Y@0:=lij +=R4=o[nװOV6\Lqֈ! 4]h1f414C2@8N�F*R?=P 5^!IgՈ~v$iNXNV>`^!&5N#4Â8PgE!<x@aUBq?_@QE\]hpQKlT +PUl 4/c.G, d (WXmc!C!L-E dϟi]_B[|{v=U+])i5M �5q4wMl vDͼ" jj ؘ{ѥX6`ˊa<_x`e /2J{+ 2JӦBT "b@4(>]&9!w`5Txm?2%lf6pwF˶m"7?�(vI),qY' ,Ѐr1�#'ԯOo7X|2,0L!hMe`H Gݟ_^ȡ"; Z>* -˫Y`8ha4XM�6qs"p'w# kp?~D$*W^2x5ePg_қgXf5)q"ϲRCc�}! jX�R2,5웎$clbY9D9 n)L/l:1K0)aNqryN { z-F nfkT1]3tszen(Ys-MyB3- ԁCt~C>ǒL5 0S\e2ƥ{F]OZ7�541.n+�F1-/)o𝋣sp;|1ɳ(qU}=oGk4!.2a-wn?q9diO8FiJfGhB9( 숖ufϿ:Q].qHN4y0Km.Ƈ=9!dN޸}�5{$7j Jcl<-gJ8͖p P {V Kc<ь䩣*dnk_S&Xfc�mf:-"quYΆOpeWUv c?Bm7g,b5M,�`R ?5x'Q6!F''ѣߵ46n>m|<(n <֤J4.&ђ,dwLԬiEfeJzxekº�&\IA&hrD}yfuͭ/-Uܒ$)Ԉ1iTM #Q.~d#H\}>Dxwjb[_^ &4E!޽}iۚ|Oonnl}ei,.!`xV4>$HʢD)s|axn O(+P`ܴڽavsE?9ϪRW ܺ"BMꀨa:Ƽ4n,K]FR]Mj0K'ɸ/_/V&Dq#|eIO`x7D`՚"ݽ{OByc-Թ!X&G:PU?9>SN RQ/0-RHr9MU!Rw%S MH !ALl:Fx7~.+XP) OmZT󋾬:tVy*I$/1f ogY6C9N]ܻiEDj͛wL I#=5|˸ă8]0!<=.sAG X/۔ WO+lhŝvlo@'s�>ʟn7'o667RANK<p�+&~_ |;oӋl:o+xGjƣ*͢r Uyq~�^yĭ%}<5c�IbRzoCsi(h!2<eKu `*2 XX\FTL�T >=čp75 5Ĭ"߾c$ d�wLuMmE08x0uPEvw_oF."eb<1<؁K0zxQI2g ^[4X#/b4,  ̕$Ed.guM`;h|LJ5FZ5xlīiX>4 h=,덳4r_V2{}rdȈ{ۦQ7.$ZPjcA>uK݀gyKLl7,3l€b^/ѥ$ܳ M)` @jFMmCFO^~=V4xir|WPQƲ85YڋnpxǰLxEy^Rb\gԡuoGۻ;bYPa{:&-U]8$p(1/aO3wF_gg1VwȞ.߽\'xMҴ제j&@eT <u.^!I̐} UQ$!MeC#m^|ͽ$p;?"$1eRu"Ä /ĴT6C ;g7_ۂe-Y=H&w>ol8H}4e?Gijml 2�&INP㖼<KYlxהN3`[9٦Nw `ћpyK�H+y4j0YbrZ*ZԠi(^m<0M ҩjK8cpM/hIfEhv.Sn 8Ȃېam;B6CHEMb'1w'{{GW}oՐbQʖI<'x,8P.S=Az1V{zsoy[o7?w9r.G }+.OP(4R+}FoPF`UR &W�H"3{4|Z;Rnrsx}i7` Y�Ol]AuPߧ 3T6]srW:v gFv(V2J#:B*6ۃ& =w<,ǞC<bUrrD!ah�c䡩 >^f;:?^p-p#,V0ax}9>Q;XL3zͯ^ZQd0�5Taps~فrԛ, cvhs˭V̗J08E26|`f\IӶ] Ϡ^dDͫV; 4 Zi4W-.]<Qґk7`3W4 lMhk_Z$ |u~ �uꑢKPduxz02nHx*fܧ u!=2!y(<0?Ɇ id|"4Db Y2OOtB%=y%kE:I,HX"w޷oH)? (aQ>-Yd1ѵDޝ{Ή/E-Hz0O`5N47b$gm~EYx"le‡= -Ԏ r'h s@b/i^h_7O }G z㲎} ݆č'G?~Z=@aw0_}uyIjJNR ++±sHF@.a"76'=I|Dod^ a1Bڝ"5edkM"aMHLwpl: ܒs )MMd܁\=iz1cc獰/+< &ByVOc dyUYQ㉹?<?q5/ -p݇SB^{OdxXk_BzDe<ś:ADwB’EQqg|X{ ǧiƖjfEIE =^Rqؾ, ا K/`1;#N%/, *p#Arf2^'WIR@9Ҏ[i9'\ON9V!!afszGm�EG\~OĩMr%CR"iPY#za<!s{uJ p`W?'i*ܻ@;2{ =U)o $UlW *"Céx�>F^<LMᇭ{Fm2~#5-+|gkW4$IHTRz$p$J,ҭrA]sΤp-^77C3Lp  RO1r` byi1#"t[]U^,IFqZMuz}v Į0%=v&2Z!'F,!p#8j8uxSi 1eײP!UXHpH>3}B~Ҧaj* #�jc7ɯeVpO«1+nHo&d.;vn4'ȺA\G׬ߗ.вahu~-yk v{CL,^q%Gb'/www{h6�[ 4F 嬩snj[ePXՀ+_U:rGUm*@՚tMIn#bcb_BS.r7JW4 2O@Dr)$:QR L)`,3"4Y3Sx^+mOu XMh|!fqK=Furs溞pc*݃5U�a"JӿnZR Pݱ~LSO|.+€eA Owbƣ V{4]i>z&9GU3].Sa)Ǝ*Ũ"=ZurLg,&�ZHe?Xvϱp,,栍y@jj0dq\6 P, T T1R8ȍ^=~od^\.HuzY8HTZnya e!J˔x Ul>ɇprT#wB\*^bGן_AB( `5TZ uZ3XbiEK틯>;4 u2GbŴDjMG+FTrkNur q]ΧH50_:_`5-Շ第QOߐĦj@xpF$<.lG0/c{ƀ5 {n_ݲ%$RcOf@CGGOAB)ߖ~t{Hp;8LNBDQ +j`j!0u8jTxC3PprqV3g2N_!9m}*k L]喎"^jш݆l>sWa@RY4 37m2ԸP՗!pԴ�<MLU-/`UpÚِAv=r]VD%RiV5s(.-u8]~5g:ctUv(L{r a2Ef 9{t ơ uQ'#\X�w-t?C.Idc_vnY/C%]$"EPwק e#($G _DE څbCDG>8iLa}CU/r6R$+VӃp4^ y/fMTn>׮S7n;c@E1H (_ pq<3ЧjϏh$[QYª##U5 G4ǎUrwg$AT9oj7D_4$ӁG`v@()AVE-jDlw[{{{{{{{T59Fs[sHu$Ml_wJN2LǺ`u&IA=]V쨜Nj\gkN¦iWWx)[x6m*_HuOewf9Nm7*+n<g `u w,7kfD(ڳYLq43y$a~!`'iq7ڭ[&.@j}k%YlZqǃ 8O#ܸ֬d_Ÿ4Z-JCOc<ҵY55=+("yh`uuAtf\[?=࿼fh1N53ԯk%V zǦYt^xĨ9*u7&a:Ey4;Q;]+v\Ht0+ztit)# ffX>w9)LԙDE1^Oa:'12,f2r~͙^\N:GYCy9[s_R gJft4$ y\8~_h:P 4s4+1NWU}&:3հnKpaIȊ"}_3 n`mH<k~=D0�+Q` Y=Pzg:.P&ȵ5wIN֬fťfΨ\4/pn>Yf؁Oz ]"~_]K8ޟ_uDQrYw?}sħlP!Aj66%ˈB6]Re~xuަFDL#g/vǑp΄RE ( ,_ۇʡT`irIu3䟆NslW5@|r-뺓ޢd;/0W% А?cH@)縞QjYȱE`ti_AEOͰ.#k$zX_~|\M"L7)Bfebq-Z=t^v4N0x\xuwy 4:Vd8 ij+1ǝUQ]GHWܕ0:̴hF8&z9HI` g'qRZ2?X{\~z:0c>`8Q=K (^8XJ1dJC"G;lj=`ä*ؕ 2f8ӄd1 Ţ =A|]Ѵ,8oaTSIȁv34-vEPI2 ͅeQ~$˒p^%Fs'|:nE*"Oڌp^40Łעo} -Vق<> ۷E9iZ$Mڢs"թ/O.^XBpihKg7=jp{&;fanB�0mп:�`;.OOДA|;'GwnDC$<<iQ6i/۪"0,ԏ'O|,]]R\XVVK ?>wšx8~[JEUXWwwK_GvfqHǍq̷߀1#ۮچS۳kmzd__Yfe5] UA2a_yk`9k~#r@\L@ >ʯy+8i%] ?Ph,Պ 2(<=,E<}0 i0ʛ9!|Xo"\ 7"e⣸eL 祥9u7$LU sm'<.ZO HmӒ$X My^-Ʃֺ`.C[qnDZ}U^ߎ<M*w5-(j8q⚺ QQfO!h2 /.䈏ȮPsxL[-ZB*rYYw~͛jǫ8~5Nlp[Cdn2eZ?J0gHp 5Y wwy~a5xAo;V`3׷=NQuGpª)Mj:p9r}c�/Q/oJeUH$b>, &J45DEMǡnXjPj@FsOx<{xB%a} �g*�P3O D P0 k (+Bq�B] }]fm\WrDdEm*b)%]3L̬a]= 5:9A7M((:JvWEsp UxR Jt.bP~1,?75% C@eY(U/t (.4ej5Dd#yEx;!;tEdI <.`6HEKY@bLR]S ewx88^2n խ= "$*_ Njokfa:GM14M'k WSB GkYIC26"Kӭ[1CEMa,Ew2ϔ$ϒx3u{ `^i+ 9(:x p3(Tb P<8!Jy|\_?qdR$Y? Y,"21TA:u#t:-nhBrW "+Dٽnxd2c^.#ds=S,ư=H?9EE(L - 0hLydӮ[Q[s<&{El=ހ@{7$}ͼ{9l } l~3h"#VdF~ ;BW{+z T0DG^k .F hܚ-qcy`z:3F:_4fa;G_e'eɎZm r-vh@”<M ='Mc7mP7.*'#uܯd$hIDmTT%KuC4ENr$0yV4Uս".U :5,E`yI C;hc^ƌd%òa@>Yi/PJTQf)PU.t&7֩$0P#oօ8h�A'��2}zV)̈́/g b<$[m HsUUUYٚij݃<t)27FN*ȔHTdz!!xmc<5RI~sXD=|l^i.k@t]!,UJ"i뻙#}Zުj2NaYPH<pT<vQI\oyՁ9 ,M1�sq'1Ctu8AW;>6Ūdz,Z6@Xx01G OpTUf jm;+CGӽ萖i�ȷ?݋ބҬzgHsB 2/jm(#LQӟ6ռ[`oAXYTo/>Js,k@D%*0o߼{O'5]W7p!¿4E?Msw0p'Ӱ�b0 ajs Ppݚ$z {_.Fn*ƒu 6IxD2RA *�xV8 zʂSCxm?olÔH`W/?|fPr<M`yJ%zuY(69l:/)X'0Ԩ;�k5TQU-^rUSo`W޾|z,)v Cu;(*i8,|y!F!4 P=4>8PAUQ(̀s~͡J!uay'5yzի7ov^}PރVŤ7! ಙj? 7 6Ӻexu݉ Sp v޼{ӕ ƎN?z7;/_1�y> @-^sFPcM3�F@-CBޱ  j_Z$/|юgUrjLy.rɊj\zoO\~O;tV<l `!K!R0oXD[ |M~nwnL. 5 5zx>-bCP'USG{\V[]|:M pMpV;(=$C?kL>}28&@01X_~P4/Cpd|nB2ÏQ&W^żۂ#q ?!9-#4TG1NBmam66lNmA}FyPKVݼ5ljE׃ýuK3$=ǶYvAZ<FC2\Yb/ff1Ko_~ժdea4@)/*k˦&1ĉBo}/{R֮JDRt#$KCǕ]*}A*d0-',m^.n/D9zݏ?g(Q{P&ݗ9iQ"IKlRhow?>PWuQ݁&H/ j!"AbxPCxl?ߴ"/304o Eˇv=uw:|Rف#IĀAbmQ|"ӧm^)| F7؂gW{G_>~e^"FIaYeN?}:<l8~YY2-lT!鷤GY 4Cm }+v #je r`{pϏg_/jԱ.^w/) ֒ʆw~|͡k �"˺ `'1?ꨂB\=<le,znNp4Ó~ӗO[ ]4{>7oo6ܻLkU|maQk?~,v{J҂8?y-|zi]l>" <[>+Au@iϧ_}֛]a1Ći,~1+z4fjw�u`^1 ND> MFc3bEh\Yh_?~޽yC۲Hëه7Pk~�C .dvx;Tï1`j J7͍Ū䗄ߴ2uttz_>tn[%JLw8:`3x+&40݁&̴cm]]wa5_`J^v0VOg_rm_\_}ՀU0%]xn'2CSc KbP?`AÄ |+ Xz{ޘg9vVI"d5 AV48z<|6 XJ4\nOnoN" EeH8ݟ-)\հ6 E [o5Ѱ„?.aŬY-Q IhiA誊e\IIӺ:?::xEYvtsME݉$o8K*,@>׷jSTpuUŽ @ AUˢN|V9f͌qolϧ~C/_a{^]~=9?\]\ܲ*Sax[l�Ёtd�xVJtwj9dj'5m8ۊu`^,:7]ۃ~ / 9�b*8`j;9uǝ➘@!>>ŧby l:-/M8<oN?~?O!O`?L*5d~ rnѤiQ>[Jcha3o9~ 0r e_v; R@`r$HaƇrzU֗/^~S QR6JdLcKŃqcgӦʞh'O"ҡg7oWp!%!v]'W>SP@J"INvI?�,999${n2*>7*Ai+ ~ AH,cS1k٬]78(!RݚƵ^ N^t|E\1V#1Df pGCDgJ<KcDziZ OoO`^sdp1YXS KnZ:l.< \QaN]u~0Vr6_yd|Vd,aDy C|)[ @45O;d/4%ZrfYSHILڶza~ϫ֗CNE}d�:ͧtWr2f{FXkp�!.<rJmru i(bdIUR_4i>VBiX޸P=n:Tj⡶h^d"~ K} *S! xIjDAץqAm$Unj�_5C:_% s(+48~#C {qat}/)QGH7ϴ!�<nϲ +T+*0]& I03܅àؘ<llxp9*8Ӗ #%'{ZA)CKb4',SfW7 s 3FjڏUJ^_ߜtA< \9t9rQ"[zuO,pqRDC�y. (!A; ݽ8>=<?>)P^T((b![S dk04Y~92 BBx.Tw3שS]Bԃr2IE<>'EYm\hP67Y!:Ė,u~9wXQB 5��\]y~)ΏOO/n: YPfBjv:Y4d,5#0@qhrA܁TlWT%8yCWTCjdZgG7C;i=S4O9 D,:K Yfg)ڜ`k&d"v;"<6hr塞`0(2R㏇$ {*%)vls{~~|<WnARŲ+sgyIE2$"^/Lv=M~i=`vt{=`=h?$I'ݛ<^k"Hd^U8jL3tts[5Y%Dj6Go%V0"? _Y}xIYV׳ dIߞ]|?k{X"gC\?SbʳĽ L0})zGr\Ctjʺ]4 #'Wz<vtEÛN`o3}E!,2Ӄ:,拊сH!왆bML"\XRASSTGq O9f=|rnMQ'6tД8G7%Ί=8߸2"rB̕t / {|HB 5"JPD~>폩w{};"m|QG^+sS{ag (ZXΚ"/P=ŝH ; `;}, x`kl g)xȌ(J0-£[8ɨ{uvvvcmC8xx/f ( e3RgwOlH7$1i^K <<(QGgH3<c! ^?OxtlSnԘ;50aQ9fFKQL&ȨX5 ~*-T<etsP1ǶOmo* 5cؑ(<'))O"XV0@}n _,$>P¢0='�EBIt -DԎ#�tH_mC"Ҽ^,uxHƐ ̢L Ȇn&1\˧Ϯ& -09omi:gCn�+j&]`9^vX62? =_Lh<z5) yo7ljRp|̙P03MSl$:߹@uGiHh 1wyRH4DnOs֫)u �aϝB.r`X2M<wLg,چdYP{% DH|$6-Q Riɠ;?rmo6Җ�[c:UXL l:[-Eb^3�9nk<oS<wF<$[x7_ ɱ{࢘-T  Q )p(SDF25d"\_܆[cA ypm *- ͉*!6O0O7<rCբ=�Nܬ2^ fsͶn=ይǝ`ZBHo|BB6f5tFOg-EY@EgƳY"sctKN<MSxI jxনtY&bbkt}sr߿dxiYH�aFdyguP+vq݋.%o-[m>hv�77bj]Ays,b�DT^x|91Y{Gy|C+p<N :lڔI^ 8PM`NlM b^E)\aݎ,Óa5吞?^�ѬrxL ?^07u`tN]a6|[cQ2f{ { b7K3H]9ӎxL9OWƝ%Y릊 HJHM4ܐe/-˝ק,)p<!ŐՓ٬�4V,>b8d.CK7iXOyKW,-Mߢ8/ƴ +qGͼt(u=^:ש`˝( 6gD%g'ڍh75›tH]^Gql6K~a;}1g)nqg5,+Ke p=K0i)!v ΧRc}l]rr ՎdxS: Mf2L ÉPw jQ�Av|EU˝wܾyuɑc r" f'hܿ8iq n3g5;<E~MwL Q-/YSY=-MBX;ty'Pv9a5j<S Ջ%2 |ҨKS4M+\d;{e�EMOS,�6*a묂EZX\o|a-}<78+XKb H>81QDEW.#} + 0R(d~sv<Ǒ і;',X4Y:e6q}yj?Bl4%Hз^*XXECaFkx0xKlF$I b9^! 9-\9=A2hH`"7@^̧pN]˂:"@'P@&_ϳ,JG04M8xchcg[~&(D-\Ӛ 'ra TqQPKt{UJCHuzXL;1}|n. `ufI<>8d_ؿY9d*@YSuOO�9;m@Q2/bălܚ64BFx VmIn%N/WmbE9#;9n3Pjbcӯo1GK@ x,xWR% OrgmmO\o;??<?^m"+渱SV hfxtUX>xiVJ*n{]<$T�5Afc: b5eSx <{t1on�^a0 +6TXQ\!7e&B-'܏gPQ{m( TDw!r,/2YD~r)'CnmA1 $v4HU6 Pa8 Q\(–P <ǰM +rQ6s y/Nop_ %c#M_u *xu9P`iaE>k : kK`Pƶ#4d>qXgW`?^^ 1aNtLD /JĪHB϶!0'G7 $DmkJd9Vm,#4c-sz{kNF:׫Y(s3�+%iٰ xl?٦0GnL[,`&<vcNgP}Fow_!Hzw}nwgn@.7tQdMMCGc:foEU~2j(#E*n 䐳!ñhXmVc)ãF1pe/_^fƇ5Z5*T<ݿqN̎iɊFP '- ]gXzZe!; �/(o\PnYX @y˩֤qAE1f%*Mk@,ᐖ8pC7<z ,aϿ{g7"_tR0cSlзG_;/qrQ˂q?Ab`Eᥳ.&nBYxaAC+P󓞨gsr"&js ԙ^~^ |\s^Pxi<qf>we 6xQd%#YB${utx9 ?LՖWΜXŘe=l[2GsVv3<YOp�š~wPTm5F*Z#~DV'{sOD;`d?D;{2l6 {5䟰O b5a G8[}g"~g|qu&Xd5_)ִnn2}vfk$!;w钖?ܭn,_ԇ?FA82i>"ŦY?T0":$e"lEY5#)Xxqَj$[ͽ@-z=dKFaS[[.,HD(}ȔZ uяR<%/h3 br^EMI sxfooX#" F|4{h`Γ�KQb7>|{.'reƋc gC! HQ2ߝ/I$V|Ga.摥2?Fll/-^B3LtR/lit~hmp{"rO? %O`52-.0RW [Mq+n{}| miݿ3JT52uݯ{9~ g8%gX^R qHGil{d%JnU$Tk~-!T7۠ABqx!k?V'9"Mn\ ߙ?sb^yF)6k6K\ēp/3GI^ճ4 )t<^]+ 6gE@V?6w"FQ;fx3d?Jp6 @ռ)RID]f9HwJv 6ߣ,{AeMPc�&2qo+_hZ(Y(sL~FD"l5u,udHym D3l.B o\tnh3$r1:Go.MzOXP{Iq@] S[G\ྍ*Ͳr2Tm!^te]Dۗ#A@ ^m2{*;3d vGUdɈM[aMƜq}] (Qdvtsr|M)e>?�YBcjH`$o۷xC&C<;9>D[NmDpsGB=ޣDj]LdUvQFkȱ6. mYRaz;mzN aLkbU*?W1L fdF% fwH#9fŲ <g.OQvoMfHYV-`dPP^Ju/wĕ_Bj(Y&D|N æd~_ mKtמ\)jwG2ps{L8IV�-FjhE+��?�1XI퐗U7`&6&&R$IT dcn?^S$A>;(z�?J ip3ѧ9|>ֿ>:CRי1!xyQu?Mf!k)a njGUQ{Ae;QtΖr F $F>Mˊ.Kt�-UHu:4"p7H~+l M {mJK-2Gd[-jW7Q Rxq ܨF.'gc $;x[dS.%BMt6�KQ}[gJӬV$hoJםj*3=w;,<KRnux4EǼ(r3 t;uig�:bl}ueJ&Ld;.+5[re.% Dۨ 68pW 3ۋ/I򤥋{RJ߯sCf:7 P=N%l׫pɻx[4'gYeR4UMfq7v%5fFYB^�5)?q3 in}̯ٝk:fsyR- @dt'5~| 8i<z}FM'D_,PP/&s{  !'[." ;[E<cD |A$}$BzoMN!׆bA5+w> ԫ4$W%-ˆmAl"P^L~fI= M4q!֯uH6|6%E<"iSb&6~4߇xqw2?\Kk<2a(; `j˱n-UlbI={e^ָ#z[oED8=Gfiz<EIj<uU{ 7LS5L{q/,lUx `0RVDCe(<{֛pP2El,"mQ uy{Dٟ#^4u*htkH:kSTkK-hNDOtp[g5GzGeƌ)0F9 EYl ,i˚;Oyl@M M:&q2 j OOSU=`5`BUMw?@ZHLix3\c BGlgx5 {N\y) HfoyAwj1 6+FQL px 6<ϨNץghgf@SN,ܿgP[DIQLd8ROYc(cu7DO=~=~=~=~=~=~=~=̓U|~3F2n߫=aWUjy/P&*9(Wv?~4/r>ì*#MSB>ڰ8I=R oL)2nQ;ۿ}նb1,3f<7Ђ҄$Y ̸­]9m;`AL? P7Eō2GyyaS{3 1rnE2o.Qist{n^fY}R* o;d#LKO&%*o_Rv&aPfrtg_e`Xj{|ĚYt',zHe;or^q"ټI<EΫ˾!&˻EQ6SG6a920-g,QoD5GfV͖M)~pZoȣO!/ńb Տ<p!EY̳+;f-oNXirR8?48yjjYS=*%sdjRRW|&`j&f(BjY Vso:A,)\ :se 㢮cX``(؋WM3MlU?^3\[e{y|VD[Y]\_ =7) WOfݠ_�c6f]g'}϶ u]FuWLW' [402l׫^EybkXs$e8Fw.ϯo/Z(XWUVqSH!7\\TSI(kȵEi =UK_=N:}a3t5RyLEax rI:fO+w.}c%ٯyUf&Ԅ( y옎-8"㶦*:?^~W7Yd2jmd- 'H혲SI׹' {￲~H̠F JJ|e}ǛnO@y 7K,כ0,{i�E]Wo|>8uG-#BZ%Yؑ_(v<M rRy=DtkCiy8CKcwôk!H!7Ԕ$;j澮/ũi 7Ue;COjwQP~\oIIpwM7SPdW-d> pc5ӭnm&({I+ټ|[8d@( Dd=,R\ LeMw d2Ɖ&N)uF{bj#;XA츺{X̉/!"ydT`V;°;"@sԒ=پ98Y-pm<8B(H{+=*h$F5˛Nuyzޢu(j"kBYA>o1LwXT%z X(/"O7UY!-Sζd~"4FWmΰmCn9A9|A` !/1x\>=JAAd4SՃ \VKf<8/wGiEY5]oYXaDi4$VqJ"j=/"w3fD:6ù~hJz nNW5*MapY٦:Q3JJ&-X,J y+e=M5xCr Mrmǡ`p'1Ԕմ!|h@md |"bg?hU喏5aFe.fqóL!(Ѭ7͔'b{A$uQ^K[<5IMNj [ϳEEdY ^ׄ,Y=āBF! ]fGק}YtiV,#\zن"jgE VfetSAm6[&("vڗɸur5xi" 2 H2YYHocI-v?jnܙ$?t%MFMUNl\D#3)MgKpgL)fuO9[VR 5{A�2jIHPN+47h$vzd�PhY4ayݬVg RF:"SŒ>q]E MSD|TV %HxXϰ( TpᗳziO+wPYC N78Au @Pjk n(D8:9(BqC a;ICKWuBSOf { \wŔUR{cAxD"a۞p [;_x/$i`I+Ur!<Gȑ\Or QA@ G '1vX6`4Ұ. WNT@E˨'|x@dA,qS'#pJњG,-XN3JX}RL4uUp0HS%?U"on 59nEٽ1lOF| '—nzKxf:M ] k|qDU l@,RxΣHB͍sv]`%YB6fUFOEy e:_C11 qgF<džlܯ=xbdX~t{rKIt{!ѶmNjUjyHXR䫺 m0P&ŴP(}3Ѣv/:W_G稊 l27";y\g@}I TI>̀? Ӑ{I>q辂5i@gP::K@NFO@DP{UlF#$-7{}]SV7"l53Т7odĉs8*EjJ:%�oxAyQ2;y ۟6DOVIN]MSBqnmg'o?;e;}SX&jB[,֫ENW ֘a_:5痐 oBܾ2�%bŤrQENt$N"')p*kI9'T C)AwcP3m8:Rp("JbN!),{41,泪@04Qξ'r#eU1�Kx^̐>%;ܘG=0yfZ4'+b*204}z9 X.»Wʲ\VZqY$,X,g8jW@{ejPJG7S^ғ5몈}D$eY^Pt9v{+D.1 tC"'~#TrBFT< c|)efӒ`LMDQ!e� }rDG 0#F+pg^m:q%J":2{>\LPP`DeY@&JBb0:&4Q3-t t9i àx4~6KvDjz:y3PibdeJ}՟o])^3<%~oUB'+_ Վ$�d}uQHsU:pD 7Yw"/;;[R=*vI^϶߾yէ[agD)󅞯Qۨ$;')߉8c%Ez I)C˰E ;ԛyu g Vy;:yjpC 3XYU([['o o01%yU >tH-ce\e_ Bd8ӻY;OS9V[v_@b>LsT𮢻w"ܰ\ΛHRLvpO2/<9SǒN /Qu ޱ,o)<Ѳ)Tc'{nl=p<'o] ܟ{[m6ܖzCׁd_D:նHW*۱@Rov^U:󬞆K|~M|>a#KҢl`6_W?QRYd ɀb Hg̴Fa)z [SC7 )n>~lc*8Ϡlmz"z\"=fh ~ݛo3 I|慫�jQP\\4ͧ&űe rdCȠZYc|xPPQ:y˝.͡"aZ&fE=>7\~Y!QgwxFDO@ ieƉ9KƸq&m/tչ+O[[/?/13nPB8OON?Kr0f#eS k8M]Ӵ0DE(7YxPK`9# !{>jX L"KsXwzggEv"nO|=SWD ~ݸ("/ '&<NqoYx >ӧ~Ze:PΧݯ$YQmN5fZdOպ03Ë� ?uLL$KC[G�?;#w]3mM߼9BtqUUf{^'[Gu ڣ!Ǿ$t 4\xpjٙ�G|/f!d2<xԶ,?LpppyDmbU"/ FKj@4o2' !)u�nE5ѷgMz×3="4%N٫ӽ7o{X)*NE9vvym# ݋f7 md\IFPDTK8STs_۫v>WɧOא_nސUPA5/ҽ;-n3 L4 LO"~#FWHx5_Ts4Ҏ_]^_ i3pǟ?:zHsJ"jꮗ.o NCږYd<Q#}7�PI{;3ȜVeU%tڭ ƴ r"9~|~r>c xN^�$\L7cL,q#bEm%z�lgɡya Biwz~mTrz4^s~tryy9T-+tDǢ(kυ~GECdt�(am�geBNDPgr4/0ZRBvɊ,4 5oQNr{pȳG 0V5QB Ixh=E20ra<$v#씆BmGf.7!dIxaMx35#ad"+B hE#5Շo�qJk%%}llJt]S(w7 ]8J UʶiНaض2a4/E1ؒ n")+4zY>Aec\X%1j1|ױvӁa% P4sq~q|V&5a%nLEk@[Lm9J:G$&wT3�p]#MӅ@UZ>8M�4$-灅2ཋ㯇-A `Ѡ{*b uyvLGEXn[hgD0"D1sL <Hy* 8"2@)k!*I`$É S#uƁ縎p~WMW׷w{&?P.c[w)H:QVeTNx<t- [6=Ѵ}"C[LUX}|-:TQ7 daGjś?rvtprETr(']M֔܄Hbᎇ̎'fS"u_L Cn更^WxVx߿x.2D0N`$>#<Bo ~QL'BQ]!0CMFcV{KT=*{Cr43o\|׏>~~y08Gſn` 60x!{r�ddO:)tg92XaQ/ȫj:L {EHWy'jA*bnq<p�:+~_=#Qa'xQ۰ $fOV;U]vN(D&_*yhˌ�J(]Q֧ћG wEq<rN63,!\2-:=ZDm6pmxzsm~Dz7F16*0 7Qݼ:^jQ` 7ǽ{g`c{nj9S0׉V;dڨ|l'! #ˤ95Q]0 0BՊqbؾS2j_^48z~uה7ԡ-19̴kTݺD~]Q ~C&1*{dMdž%.Ȃb#LLqF5U]\$H9 r\*\�:7/JB<\anwDN3>svO8AJO'!5Pf ~!P' >nc̑%�e1I&zFRLׅ(EDv2CBmpԩ!eLu:{qb$)K BI_cZk$?u ).8:� -Ue1Tu<cGMhй:;0SOhIS<C4QhuZW_&06�q�)f�ҽ _y+yAovŔ(;QT:wip.2r I0n\ 8t s͍GwjS5M2KI DžE*wI^�߈p@%qj4S +@A?GId4�uMܝuhER /94FZ (0!fi̞_'"DF6( ,VSݻ;\7ܤwsv~bhE!6}.M_*҃M[G#EAa͖ g*PyY/-N#*rbF<!.n~O:׭۫ɗ/{"sT3|W"vDNr VM=W3\VP^iNT]TEs=dh� %9!,a+�9Za뷧c<& jC]ZB)j$Qk#I@>. r v88`XDzlC͐ż0CpWqJ " "onoN|5�b4U~NJ%fɖ bT-nZI" HЩ]jjJ>vD14>eYWy 91K2. ӹ>?9Cz. $'/x²ԄYDxWEJq!baBܺ`X q[-E_Fy^q8- l3i<yIGt Hɧ^3Ci<Jz$FRAγ|qD/!v!.i"X�hAUeU b;vB!r# @x U64PlCdW`}gԖkh/OE�U(2[@\m ?T :^yd( ɩ8"0w`YcUd2 xenQBEBn hW_/[pX1*r]=":YNPb� !cD9}P(_;~ OCY.IDPCP&"(-};nZcv#p\i2�֕'2фFv) H1.Nc�,ys!HQ!+G$܎I5EdV<Q]/b/k2_V-jWNAj :%TLԝ<0hj|x[֋i:&Ah)P] <|-|iw6%YIhچtV9b $,,� Z੽ԜiObQZW"q<nv.&wq!xVLcu3m6Fg(s-fLzOmbK"K"T`c�NSgzZڬBc al j�tت4#hlq{P:�k`"ODl"~j{8<7p2;nwT'i q%t1 @m%eIB{x|~v7Cڀud4�$l*3)P4̪*quE`z>^CFv# zAH: yNr$8Ca j\#S|>5 .?2f$AtYjb䉧P!-^9 a|NhOR쨌,LDk?�V4!yɓb1KkM<́$Rfr)~}C@僧|D7ۀ8tNJ I|2`�JD5zY8q[g"0JRCZX"^omoQ#gxϗO;{yI| eqR �D! ZRxQǖs e=2l[}mɆSbĪ TE&W Ů c,$<q;/wlac!s#6fNgɺWׁE$ >2:4E5HրaY+rBM;˭?oɇVRȈYʆ s?A+ؓ<k_ԒbbSWxJP0JfBԅ,[/_n|Qۻ[�WbYϪdF(M #e&yzx,a2?;WE~BbVƀ{�{rw/(@݂H[`&Ev<F. dҕMgecDRG`9A ,SO-  $SH)"3$|x9^Q10OgMaxL-(qtIb({;gϸC&w|T+Ζst +xi &CN譭WcMZ l+�Hin쇇2<Uݰff6< s ^Jv"+8 d,?-]ܽ9z gM_ēPx-0dq%bB H?᧡,8ޙ\f-0B>P F/<G`3l(r r%,7PvQ`~xY\)Y*tcnZ.#c=g*Ax+4.rτGÒKx<*wymUuBg[^`hrA"9 ̓ x_`z#^1 H࿺)ZSxDjDRhQeeaGنR�/2h/1~܁{-iخO1ͱ j.[/L[ @\G³55-_;VCy. "Ӌ,O!Rw_>>cgg{g\$'Ȧ3ˀL}G['ÎO? @9v(ATb(Q#T`d ]jJ۴.!:o:BfzDNlS14D^8MklP[1EVtob"IP S(Rx[U}p?N zl<B;1M75^Q0'Pئͺ?M˜c R{x$++�@=WCѲh)h .×[gh3 ;Y4X ͱTT/#jy4G,cwV' u"Xxly7qƤ`y5q/$f~XCpfd(#Y/3Bѵ @vS )x?v=Ȃxa6|  A|Y!/.ۻ<^n:eP>+zCY^DӦ=ZU /p8%~&n"=3 *)2+B?mm__|s:HXR@5cFVɝt*=l}><[=AH"Àj�i^gȤC܏;đ)a_B~MC&2g[$~u@|="Ƕ <>C% /p<=:q6cс7Hyh}ag Bn#d 5%wr9(j83gy> ǂhGV wM p:<4Ty2)_}y6, {|qO,^Hl+׫ynBzBp�9 nȉjsɩ:EWb,Q,raՍü-YyM&͗fW'ׇoh9 \ 58�Q"GӼ*i XPEmSl؀1U-'H֍%ׇ%i6MsPy{&V:OIYLYP0Xa ES"/4+i@9;H47\;otFn)`l"pm, tl|lʼnH {,-axjsmF.Eiu+d]Ln[��7_`Ft=b  7ۧ|Nb#͛z10Cc&p=p0SMܰj؀Yj{+\A^ ~E@5f?^㥀wr_>>kȐ08Nԣr[N]bÞS N6ƊM{t>';_)mW84O5~j*+J͎5c+5xE!=Ƥx^ի|I"F 22ѫ:<7Hh0;[4U?D4o6g`g{2x, _niŃE1'so .(?14s2tt/ E brIZlFȂWofellݝ/dGb#~(<2Dv8U[n?Z@ zY||(;{M&Z"<k(̇eHtg+`e17-5- #*^nyMitEVjYlkBF⵭fz@5|S O`CN<Mw=?H3bWlC { 9qyA|*t$&@r9F <M [ p4I�ULp>ij.{C҇M+wsxzx{~Esog"xG!24£$)CKCPMqlqqm4I1tF҆]`QKьcItn4q`gCD d oEѴ$rt 9doyMaDӒFbc~ Uȩ-!؏@uy5.)؁pSDtQ ++mJ\y5V*+x1b4027߃Rt>]<Kd=^";&>kMarGՂQ>՝7o,MZ2?CNQD!G{K9ś? r 3Ί0y:]Q> 7]ිd>m]Zxf;OK|ʅQBo߈GXi#R49X2CsdB"@7 e` OxǠ$"LŞt}{$/ 1>9x*>f207!ȇM*=΁ckPдŚoOcG9b2<N)^MMCvMJ\hU_`Q "K؁{5KH5�%EyqzKn"^cgoAlotlLd(FMDEFW:3$Qi{|}wsFh*|<+$/2[ϣ|׃8v ds}Mq9d!qpe:'Zf4.1ǫn>e3,v5o7%E=-tqDXF8$~t +V$_z S%?G%;[̀AQnt@&0饞񣣣xW/X,{XފiƵpXWewDk3f4�X׉k"OBR !1É�S7W z Riք' sWfg -%]ǃ}'x<), w=()*L Hj0l1.`yF(U̒ )*e4lx]6Kё$oXSR]xz)!Td;)/*% aYUejKAswݢ 9WE͌6D8jY^ă -b)oCiɢ"h|# :x<궺<�?ΖpWmQ`D iM֛>ב  ɸ<JV %&0^~C/"E{W7}0Fw<� gz#N1,4 .C ۷_P /*B\=lWy&G^Z?HƐ r"=5ۧ_P<f;@-7iAfqӲ,pN\.Ȧ?tL-'Qݯ/ƼlkȰєgTx``2gi"kpɛ%sb"Ia6ۍغ-HQk??!Y<yqmX^RDR! rPHYbd$ҋ'`etB%q«ǀQSaYL#W(8|r-?rga]4Lۏ5/'3hj4fՂPkRWNwX4W-j":)$dO|\Xg07x0=lX/Ѡ7JaW0�}5o,2iL]5vڙfDBnjLFt1rA/'IVj7UzK<3ܗDf20ڒyKFg �,q^ͱZ9%Ŋբ3C-s`4d"Yr\@<@&#VR42K,͒< ?_0J:6HАUYYiO^O& Ec8O(t}yZhk QY7/2F5'|BJH9VP SË 9ʹ]`6P) E'`�A1KnH,K*I4G=~=~=~=~=~=~=~>&4=U?UT+pε CV<x#; =P?*ZԳY^1-IIu1w[qG-i7QB.w6Un^TV:iYo5yTMM )"lUUpfLiz672K˝sͬA¦V "rG/:/N=Nx#=H2nZ3peT*ѣiU`Yz‹N"--*b9aMgoh ,"ē_\t/FN^dfEOY(n8(YYžں$D=$r!܋㛫ukJzX2()өxHTMyō9WL,Hz^g=&`'F\.rVޖlk(tQzrS* 1H^.}xcE,U \cϚuY û,JuXJf %<n8j\n8രX y`cT˱ Ud9NJuWe0]#ΛjZ? $0֯63]ͨmlVUH(7='PeݷzXI~^6o52(dmZ+9D"2(֊~n"Y/ o4|3ǐ ѝ[ y0:Axj|$$F]~eEVuh<'kEA{5u]cMQKՐT잎9ﻎyGED(x%!xg4aRqre wםˋݝq e&3-b9*Eb~\- P|H6wE~2)A=QY ZBݝ||s@YbO:hL vDeX+bC!п橥֘(<\W~zqy+IT/țEiwBpF]e;bƳM^9Q7@5Ehnȷ@j ӆEDp 7ԯꞬAh"P&.L52 ZB< ]'NCOyaQWy/ ^,Y}*tu9]ʹ`DlCI0ɫh<\7 ؑ,2{Ah[YC ռ֫LgGfLjYΏPJi*ط tu7ExD Yl7ee#8uW e5ݯjη]G*JmAѭ n�i ^&D1o3O`ťf @N!cCǒfjQ+ [NO8ݍIh43%angL~͒"AEؑ`D [6ylX̣dHIn<ci邠{a Y;#>mziYP_tK�ŶkakbR PS*F<DP(=ST*%!&?<}osvBWyެQV;Bb1jk'jp[! "p@0#SӾl)^~j+}}i W[vk Gu亪Y s"AFҺY=ޯӢݗC$MVyE /-4$$.T qhwHr EP""R#ԼF MF 'ʚ Q"ERaX/VHMZg&MaK /pPϐ@ BWch^j8w:ŇEj-wfZyFw/S lnr A?KxLbIY_'cFPt] O]W\.ڎKd'2^u& $UU5dt<(XFAS$wyܜxwGzܟHf:-3_*َG7XII=fYe ۏ%)2ݮ0хâJ㳛!=XBgH96e ]|8QYD~�Hn{ڦmYN0peb&n=FF5I\]S lFKQTaT2H#ϱʒrh ]j=Ltz8zzDZty}[(ðj(s �F#m1VEgu,pUQ暡5 N2f�l2Wb$;I$6x{}yՅZ#1=47R_T;`t:'!Ծserb {Txe'["MmHΥ'LNݧhS׸>j"8I&KN,WM%տ(x~5,QTPeBS ߖM#) nK0`΀Ҹh>(v$EngB Aɨ~a("b(IPsE Ң@�4H �Xx\]UT+mC͋z�.mPJ(P4~t'SL/JMU!J}/ʦ=BhQ$.v< ƭχ=ft*fEWSWݗP{7E!B!5-Y3elil*<]%2_M(Q!E3݋۫{G?ch[Ҩu﮻f@i.8Zn ~qR=:X@Y$t  ߾r 8Ճe1vXaѳŨ"%5ӲTmm@TVd4 /6Dž|-IjeEȟd}O-tCϒP'oΊR"CUUh ,`݆@%NBEQfnJ^/.)Q2= e0OpY',횺( 70h2O]Fug#fDKb0a1` $rHjx{Ш2R㽽[Ni^<n( p$Iuw65վB70D<sSAp7J_OC;cI" EIt �M{什2j=�I{(]Y!AV<cw?!8!ِR4E/ݝϧg 0ϚAnTgN'`Zu͌("|!h~fa$MFk20p;^s?G7wH`wVh1]$Eؽ_}=8<<u oSL)! 9ip}iFr�u6&e%iJf)6~'P>NARry~SueőP>kG*— ķd5<)<P5t1'aO{Sˢއwys8PENѽ$v 3|MK8IL& (f9чVF-Vu̫wz8%j|u]R"\ oopanNcp©Va@J؃5-Cͤw @& �!݃k7-C =0 ^M!5k2 (w^ޣG9Ju( Mexk°Y9k׹n8aQ(` -5 %c>Pb ܧܗ- nm( FZl(7-'lf G#/"2ω2wt{ w䙚N@ !p 9}jnsY#/z}&Ȳ(Z �$bЩx>| }*i#o tf4s^y:CxJ ߽z} +5FhB^i׿~)<ˊ$5uI6m2~#0d$#}"}VnZO <^ ޤpC u+,Bj|zji(ʱUL6 7wAϧBTAGZO*c64+_ 0fU*jvݽz282$GST zZk$O^jS,eT|Q@AT3 FFXnV$51}'id,λǟ. 5dRC67w:B{AЙmH-I#nן|F:˘'&,ò5Q�|Ք c1ꈖZ btzƫGi"wzF�IB&x)TtxI v_&r?qP%:A>p0g"zg%qiy>T6Q@o;mYѼizӠ̺]Mer1vY¶դ ]Ic`KJX&d3b2\Yq6OCB1-MǧK )Ү(λ7vr G1U? UY®{M."�-glʼO,jlzw 6ONvnZYiJ`h G=_QC, <h8Y lfICu�A78u] 7έ:}>mGdu]f- ;w?{s|ᄔ"HRke_y9hckwBɄ r [Oi Z6 q\R=IX)9vw&ff?9;;k�6E>?jkZl kW32Obv'.- L^e _ C| 5l)ɫG;o~Q؁p~xvO*Y*˂{>}ENFՙ"ZRɔ}yQ!GeMć8+x »ן?jɸb8?=^�lA}|wtqۛ4Xf]2/EbnƾHOIxղLlF*Dzi$yvixٍhvgYHeq83LyV$noG.6COe@~B =Ų!Khjf~\M1}첥Fvo9ioQHa N?=T\aAH�fj~j؂bOQ* *=ts~ttr>Q<WP-SwXӼR1tڽ2œ<N|45T%B.4IrjA6r]5!y>swADU:TXJ�aJO@JA.FSyS.%w=IW!e8uTyܧ f^/ȵǻgJSJh$U]+#؛#lgq ׉:5e'[>e2pa9VtC`izL? 2u�9UCg[0r>iNTu\<!vU"`R UͭA!<qs+VJAdRybӐ1")mKց"ȣ7FI$U4EjhLGw'c.w?t JspgEYeb_O k7 t%FȆTT NF?|LˣόGkrRa'Ѵf?-(w8}u蚦 >du|Pc_PMi۪&ޞriUAkWMmMJ dz4lVO$SVܠDf3hڲ+?,M\Ǐw޾~sxupERQ0Fjgrh �=Lj}Nw۴:9N` \B^ۧMVKqC9 '`tL() Tl}{sk{D%W@LBbR/Vs� -;z5L1C fN{7` |�9A\#K&̔NɨpzHݽ߾WX~:{P͢d n�Q@$Mwub]؛IZd~LD'. $}-Z?vz&M|'3*+tVku9|-,>'r}ZP9$/[ I8 ku{*]GqNqor}yRCnкi1fYƳCP.,r M6#! BOPp늝/Y7o޾3Q7M&^ uJ9cޡƋh�*&e^ah5;�GxoJb<Կnv_-)CEi�lujgwc.#Pv1Mq)Pl 2}ZVi=Eu|ޤ!AB.(\\ݜ_ ) Gq:eyLZהnbwP0 ZV IIk0t;w~"HT^*O_:jInh �(w{xruq~q|R +N|Je@$'b;:* QLo<GxSNgTzWwIH!A{dyp BK AI1';(BS/RtUGSͣyF/bMє5Zn^`M&jGeOT5;[̈́(:BM>[T 40LS$^+Od]`ߏЄmܜ_C=s[9lg*˳4KQCZAPU`35#lPSK2ϧCUw \§iQO*\#s*S77NqzprhΚhz XCܑ x*4O1E ` :R* f4&ɽÃ'CUC3 m\܉)@7W׷7?7+:TrH%%ȣȫ(P{7-I7 b\/ID{(χG'CzZVEkleл;||~y@ѰKJO.^`iz>醙" jWe5_uTݸ 28::)51S2`xѴ)I+K˓O'?]UFTfJ&ZVe*\%B/+7#= IJexH.V(F^AR 9i%`#H(琢>98dؽmE͎b�|M EN& CkߴCIC~PtHc?bD *8Ц4 CB&$F(&yJ/E{O Ub|q'"$ /o^kg+{/[|(Y@u," ->u}aؑ3S2y6??uEaUyL i7xB^\_uP'uL9EɧjךmPY'iR >CKtRCe>޷B5 MմpeBkiFUƵ[2T ?.BO/[tQjRlo Jh5`>\^HJ:IG<A=<yK]5F&$y 9ii/, w#Aj؂Jt bQ\RT@DpҒHťr{Sz !l/Gst@K%lWmv 6>{:UuI1.6e>m!Bu\75%AqNt'vdYOkl$T~K >U=7LCH7Jrj(lM*tmN ɢrQ*L9xŶؤrL:EGu4Y9}َ2{/#ŌV<6Yczȃv>-$O',EzX1H7TSz3t@Q '.] @h!ZB9*T qa}]Ti6Bav+r#U.ÇeO.Ԃk81ΝҠ5l/HroP=v"{ F 3UV ɆK$H!&UO|b-/WFO&WbYSOq�ú|Ȓ~?"'iʜs*G1h1;3:qyj1Vs_~AxF~6|]Et?UFjjEnKA9d 咰{qsSS4 H%;4y꡿߂QPu8,uή/g>u{qhg=毩x݋ ` sL!;<*=㮶7~i:I(_ysVt;T̩8ΊɂDd߻rlF8,uWx>}MxCG! ;.pS 贓՚'Ȉy2>ۗ橩˭}!߼zŋ"TaXy(Ɩ" }I3ͧ8SOY)Vo?. mѻT34y,&I%hr_sbNa�3~o/7_n:d;ANc(&-�r-'R|vKv3:d*#ѓv&9 -m( 0t^Ew$e҇_6_nll~گ6kIR /ɫI(lyl6"WeF5ۡq8EiS9 FrPj|bd>0trscG|GSIs0sTt�dfh'/ ?>NrkT/Wf:_; sN|ij˗lGˏC^D8;&`Oh@A VlEdQ9,S T :YhRBLS4!i*C.˫#<Da;#tM)Vt9R  zU;bu*gے%Y2~2>˯5*p,I.�%I 2Q j&3t~W{KomMN(fвI+Q$F׾*"Y]s.ʢzL+xwb1ZqR;t}ۺW fr<3iZ=!]p@fEeq92urVi<r4Ep[l×tLE.Bel% %4  ' (bObS4P <Tb}9Nz@&#\ʘq^(m[/<LolnP 0M'B~oMu|oӴkݮl:s6UИ`>kY$ge54UT6|Ɍ>؄{l*-'T2~oL]^.U2o(m=*3l'eJaC׸ /7O?mlS~QamUv@ feZ^<fMQ lRJ <%q I˂~;{(nX&Ť 'RCN7\~8Vt2çeZ`Ei%l;E=551))#M(b$;Lk[S6N^'lbS=I}ԏd5%'0 M+go^;iTo#i8̡r>39dܾ!A%oe=ޘukꜱ3Q!jDp4SՃ* 8¢&Q燂hS0iɣJe/"YdFгG\YS E! ׊x^-Vc6ErF-;q;L+q;d3ˈ7^nQx}:Tp GdBl1}.�0oag(bi#IH)QVh tL�m=�ѿlnIp7C&ăh^ ;hVa^^\axʐom5>bfo9H:K7`){×1C4<YBCǗi8 HJ <'3Xq_#-I- w5~݋fZn<`H7o,OPHy5`M A'DNUj0ˢί[w8'G}z+z{m=:CbOV) M(ޓ<h;̋g0yPMo2Ψʕ٩)Yao{JXhh1z_nlpidБ쎜c\&| hP\uh[yzh?b]7�xpg, ѿ.ыb0bJc$BsI֑SgzL3B>'Ρ{EYJu} [\ 9gRř$T(R|h_ZH::%3p:o^3\7Mp1G]NcWð}P#k{vWldɘ~seTƚcZ", {r}/�n>? -~@/ j U/>uLpE(Oo-vyqM?eG{Ú~ၞ%wxȪn! ^R)"J|tZ;XY0+VPѠ'9~ho.(% 'k5N}r`WE0Y_r}z=|yH MmC1ݻ&9|3^;|;g/ĂP~I ͠{v\�3&/_R?7;w}I \_n/=xt5E*rɭ` d>yX3YLƮpՀS-N6V֐fٔ-(TOl[3>nųK_bq?W%K?hETBc|zi ):TlXXlTޯ[ן߾=izC5eݚ:Ğ^e9Ψ)XNp%о ?+%VJmm oNE1;UCh܊PpIM OY;?2sMSL*)\{*;J*qil2=F8}gvf!Os֬fs>1n.B/MM>b.T}Qc):}/J66&cy78%(*3 z<hl~l9yI5FʚmK\_5:vg kV�3xpIrvx7á`2v5'a,l<>" Dv]?+{،+T*Vo8%ͩi$%| 迸%'J,rM;2HFS]M8P>ʲ[jtDR];ktE#YTŝ7wKB0 qw<h%Q"hX1J)PVYIN5T?6H}(js-oˇ_X@� V|<Rxa:|9s  ._ Y;U<e(B% |.E9v&~⢫=?)_uif("aeqn E�޷eOΡMO/~>ރpV, HAK_,y n_mxwvJ{<-|Mǯ:,Sy#S΋YL yE\2ş"W$GS<Ԧ}榮\˩ϙO|etܬT1nr Erۡ5_=A<U}i];+PVUUv]YjIN×ɪR$bp1]րb\qU/KV-E:l㻻tnbxK\i|Elwïtq^ +v)NQ`=yQe~o1a;a6�wWUw}Yvmֲ1l,eq<Ӵ G"?Bܨ#}zjRLQ=Vu%YbWJfFf 2 iw,?){RL+[Ofl G]+<c[Z+rN% Q$ܱt8HO/{iWS4(.�'XZvLRPX iWt6;Ex?Gǡ Ei{: iyh n_K˿ Cqkak ˝dOc@�O7c5tq'yze2vb Kx1P|+)HXl~ ËnE2G*ξ2t_9$ Zw'0mn2abbT$FĿAf06^)سV<BN+V]/SZ./N?P)Wt;a.D<W[z,Aſ.7|:.`^bu%T0Rt+zYa-% i~ˠA\ip̘tw7T xy(-Eaq�*;/Xظ'^-֤!lŤV /:kSl%ׯL MPf vDo]I`ؿjqpggTl|e}IU*_PvTMܗbm^bo #:y#aÎaWL2AVH͋RqQͶ؎|Zq->1^Kd)?jyުFx)˚)W?`+qz1)з)>Sڏh/n Mg_d5hvv*G -8=Cu{f?wk{qh!Wr_jSzn @Dvqϔ:&g!ɗ[<cpKyɚ/ #lgxqzt9cN|7CהhL}5EP\"AzޣV)nP2$.C$`y( (v߁<bRŴS4с[W'/j1vl|d*6:^:.Cʆ' 7MI蘭ܺ*T!jBwķ/GOaaZ`|X�̩WyAX8wݻ!r ڝ8RKܓ<C3֩'_,HsK_o~Jf`ߥ7_ ʢe:7$*vz~vwCI*>xs?s?s?s?s?s?s?s?t`q"0?9ׂ8cP+BOy8 埈:_64_鬑%b22zچ]^bZzT ish, (qkZF|22!3Fq}zJ;겞:7rދm[sLgT- ώ&eC1 "}+rpj9,^\7n8qM'/(?.+_h[vENW/ e[*@:\yyr,4~XNѳ>O4NF: c]?)#_Rt4jF8'?_6̤@sH/{i/5DAZFU!�nO&g6d86#FnGBWeU3"m4/i߹ٌ5ۃR h{n(Nb3ffNYO&=<l7/cO>>dx9' J;ࣙR"m;m Y 2M-at%T^4Pb)r<KWT\,feHw׿=nZ#eCv3ѺY^u:ݦ d xcrZ̪4 s=} 훳;v~2M5s|3eސ3Z0ҒEY h|oL~-CE -<ȺjR%9aY͉gu-d*e[EA:xj 64T]ix]4<ב:25tȕ2Av6.u?C444cmn(/.fO?zɻ KguE#O;:u㦪_3r5"Iqݶbb\k4ugzQ?J3Жy %<>bt'i~\MжrbդLr~e*o}ކ 3G]Q8e>xqbh 0iwH2MDtX=C0#/ݤN!pUf@N_%E1u6"GUt:/BFvOϫ<SSGd{࡛�yRo H2?/LT'PqY "v0<(/)fUTOQXKm?4LdrSe=לwsZ/,N,+"OkNxP $ꟕ%@L!ut;HN\ʐb9hdXm{3? /t]F A_R)K�5Oj9ɕAF%v<FNN۪fy22;gg'RH5Gr3}a zx d( T` )VFm(ɂX1J'ْwQ|M3)/A͓9_Vx#snA2,rEΎf!d栧={Xǔ`:7v!-s>Vr~٢`g(E=P=نj0mLl .^LMgZ@wP"ޓ.O2v4rxb1Y6V +#G#J~YEÿ́ <gXڝ"GD}#jA*qM7[!ၙ-K>0 F E0J!>7OŚQ' Cդ.grdinŸYZ-U47&1 n^%C%tkqZ3ѿBSK7ZCB&9q:9j=-cW3"ƚhڸ^ /LKs /75(M)*[Ėt %˂{7=%rTWrٳ:uM;cl #`m;gGmY}p?9E q?yc>㘢, 6V3|p;bl :|re@W-CZnL %.a՚qCݪs{(K*łHZ8_S~sǤ6R%ͦs}]^ & ڍV_%%�dquyk jTHO5WA!i*?ymPJ+~^F B[wo_ܘ;(N)nC0* P83 PпCE^I+dm6ZN@rEsUeyqhB`7o ASt9èpNjF 80]Ybؚft] .v+ZDvOs0r_804Alܚ4w"fS5; fz0_FUd<�Ud~3sF -i?` c2}DL+]I$K`|ްȑI9!!L6oqN/ )C<= ݞf1t!A(P4G5#}\N&eD.A *T@-\d{7`ހj0]UP&?.Wk_a(GmkW1M0p1tWq]AWQ* no<w€#8"`!@ e4Ӝ|*9q'fC[՘jR7w,L%7rK߰}q~Ĥ My4B㎷K.%6șD+I C5y�1|<e #b(EIeYsFODϵ=3^?swQŜmM'V=C6GDQϱcJrGv2!H?N=3\ճXݶ7ޛu7rf_shQEzZ.z!'tM*F/!к`7TNƆ!D:}Do\B̈ϩ@=^b"ShE,X.䂐TzC\w-}ckH d^ي("HLwdI%^KE=2^ydq]Cn5:Cs\EHa8p3bDv@'t> i1o</?}{nymYsJwLy<'sz7GFli8IUm!/*T z.ɧ¥$I){G{Ƿw{ǒnJ!a qQU= IP! ˦f*tAD0f|*f(!k;m'zPN\t[iB醿>uC3}JtU=E^Ф/2Uz}w{'H0ʲ"=3w!ݨ٣^IZa|XG+|Td@NWȺ&M}UϨP\M]E2 M zP S[͉2ߺPԊlM]5iCjdrhJ&v> U#TMꢘ;?C 羺S+l@gAȀcA7 =[0qz{/%࡬y%t!`{ۜ>@8`_5IbF.u*8Z= stli N>_y^B"<: =ԑ[ЁrPVF״&t!y]TB<v۸}TO7TVu#^ 9 5V">|ESSԫ|�Qe* M4yNq2dgiXR5L=,v>bأG5TTa: T [[[g1ElV. /٠?{"uT1U/ռ.>޺(: 8ANaKכȖlyS10x3mYLrN͒X[T{Oߕ N(rg숵b�lr/+NǮ&bbS66y.Uwo6mm~''6Fx}X_{n{hb:0mۼʟ}3I&)֪-^UbVzX)bn:dIw.x$oV|{m<`n6}/ oѩl]_d%:EW"yץ"WNNB&{XB112uL=z<?ml|;?<i$uZwD-La 8[]gYG-Vtf50V̆Ɗacmd{x|<q^ |@68V|~csQd 1uƞbR^?l+̗42 M5bnyW!)m:J,?L (u-MtD(:$;zvpԥ8 zŷ*[owK$KB OD'ݣtbx4TU'3,{G43W졭Bas,M@DaspΗO<Lu6H\ð}|DOnX5%q_˳ Xx G=kXBK(m`PqfTǃ㧏}z: Orx *fuAM~E@/K򝦞u]S'c43 ]sҭ~^*&HtÉK=Bzd Z7>HiY=<>:9mʪNhFЧIĝ|ۮbѲ#5F!&6i`%ڢ   A{{?xIh6o^\sr]ES!ɔdq_>7$Ȱp.(cّG{n膋۝n, ?ldo?n1Y>]^_f@?J{O7/fŽl2$v-K[ Tt\ LXsqXhͣ$cɂؗ.gKtkד닛2>2λ Q8b c6vqAF%Z1y.mqe9]VC@GՔuԉYbZIֽ9vu.&/t؅ 6' * $@؎i{�Fnl'jDRq#JﶷwNvqD¥iOο0= ,n~99?uOOP^vg 0vrlG|teYGM 5H,&STa&b8> {';N+! 'm;A#1Y RW?:?H!<p,2 ò�r.ӹNRGᚫݐu$ 7 i;իd!-_-3ZGB&aĔҗ_г|~vY8=SOlj!5HN%Aעwbg_WLĬ r-}FB4Jmҧ쇯zRTҦh# Z#}EA>!}ܪ]}vUrKgjR5V ytÔkh1Wg't2s[DU1NE$qD'Iʉ[)o+s�1շۻRGu y !Za]%�Kctf640C+Ŏ֍ I}Mɠ[nDTmlJWE ,N2ǎϏOm1@mdͩ'치$nB&N^8J:ؒdQT>2)L`K.DY_r2m?]uC´Rc|jwF"$/Uh4d6@A(NpB!(0ƸZ/dmG}S\Ѿ~ [%F|hwP)NO f\iYPsFtSHb֍A40"܉\9/?_^< 7;O*q Ch:තN} R KY1u vj1CUYlC"r $vî:wgss;ȑ`F)hIO`yw~PcC˝jTn;-CzLXZDYLCo~ Fd<O6T"' ~ jprߐMn*A 3ŽyQNN6]sf!Uez Sx- MkkJp W`/<!pwˏ$3BLGBv:Hd 1~:LAZJN#4/  ^-rCr`]] w"lu%U-A{.b ¿ C'v|y&L>C]NGB(b|uzvSnpF xfDޒ!#m@&갆ӄIujw67n|= >&ϏFtqErtVxW(*jVʉ$FH AQZwW7w]SAx8y}Ӓp LJUEb]RhrH 2ij^?=-#$kmR ̤Eƍnn^ HZe3$rS{*t$N#ޑL.:ڋ j mܴ 2|}$ jf"c=՚l 'K\PU _9eEa=R *nnnv}29,"C}㴫Bi d6$EG~G!Ӟ)0t&7Y([qOP[gRt<φ\뇭A>^ľ͌g(Q Hj5KAgM ȩ;0pb,UjDU R81:/sIG0Q rp7& ]G�mDh)*R߮aR͕!VYmbhyַ!XG;AV /YM9C8a8>FjBx5Ys#Cf"rrDThVR&/aYqBRV[Qau"(R;<K愸e3%[1XRWᮞ\iDbW1fUoMMQWS<:(#6߷1µ N%U5l@B܌`L!vl]w_?n_ȆnydAs0 eFᎶYi q傴FBRDT<m Miʈ% 9�&]LM)^_l^ilGĪA!tJog�rӳAhO[<W\NEeG6 NEFaڿ3tRR K/$@4|Hq M-3yj 7>"W8 dfіp,"b6SY+9 jUʕfz|\ӥNb|#={eii</;MksItQVN,6xCWӡ^p9ZKM:&dzbM$3 GZ>jv/M$HG4& iqеu:z.tRurF0®Z0�*j\6#Mo=MY2s&2{) -aЬ(\ ax V"J^qL8UyYVu >9"̘IZUЙ& @&OQEDZ)"+t 7]@)(޷\haa[pYRU65vwZ@ p N[f/N| ta2!3\ӝ o,% LvǍZ2G4H^t0S2IB;ͻj m9d%wnfZh6$-d-#$❼)Q.T]9( /Ddh" q<NbY`BzP+FlKrZI7 #=9q!R!A9=>:jձfÔ}bW\3iDh+18A¤Pmy\:QQD , -|7Aa$ iv,mg]Ž3^\k ̐<Aǖpdu0㻚$7[˛'tZdzVkv:_̆aCi_O\ ܵ NV$ eG9*4&y0HlzB0 'DoA|z6fx˗BgwV&n2&dnz93mIFu$>!:�)R6)Jy{ek-&yF9," \=ՉW$FCbRR 'MIS9d%yLf#$Bc8(s5Q>X[kž\9^cm�pSƑb& ֭WڊO}\RF7N/ښ#DG1ө&vDI2a ?HUې~yE+F* ҅H0oDӄNU'a|w:\SDrqLROʚDC&4֥>f&oyO56][{o7607&LA&dB'h=Tk ^۽|6s Sô,uILq/GYVadOC-?,5@B(=_cBi9A7E]./Ž;}$j;W>SV0O_l+ЮM^c2)A{-#PvzmHY'x{IFLzGF$)Iě`w3'$ߵ fIhVJ6'ws#̽ۧk;ܷ?zlDIV-g y!'vOH2hFNDp::A[mn># 70$G#(;6I2}&#J>&g`p<C"ߩ9B!g#CBF7e @;`.A?Cg?O(!G7"f+\MH=v^tBzp,*J*4.j738uS.D N_F-Se/D=S&DaKhn-VXnkls*d'f#8orb2*'Glt!dcfzh=D؟9,7.VVfIi~!R|]xq*(KhD-( ^B!{P>?vW'f}nߏPxZ ?>k&}Pg0A]P.`m-cQz2f wpU#SB]]%5*!0R2w,wJl5IeLzĚ;0"DxqT݆kׇ$A@:$}BօlF' ,rKL"Ƿj/vpmQV>^Tzڊ@ДkۜKzQqBI]?ӄN7p]1@tYMHcHqҹ@T^hT:[ /N -\r_ˢLˢcVES;g0$vM?a, X~2vdfD&Q`dF .M`MTLz4 صjJ 3Y'@赭,I୺z!&20)2�m{d^ހ8egf%< R<y hs8 L=yN2N2fmܓ1piAY]OllB�Ab1YWxdgnSױ-\&Q7޾]{T$VcXctebh2:3OV۝Xr:. T3=|K} tRCp�YN7<zA:XԩXlnp ΏNh*U)2IFSQ%=ӷAy >%L ?S'K>G=NGA"U[AJ\ŋtdq&APSv7RVM]:W_n꺵O6N뒂(7cΐ,C*r)t6DX M ۵VZڭvpw_pU8Dz鄬95b7gq}b/n9ȷB4tK[hP�ܖOByiy5oO/O.k(FI 援K$ӊ,͛?}n7<T �$C~`0/-ٱZQj"C<7pQI̸zJ橑Ev k4кPT>)oQM?M&EH5L'ybZHv巠w2=w_vog.OeI.˲hɠFQ@}zsw,Fs{=HX K&pJ'%׆,OFX.׹>:GdXLG+rmfDΈC[/% Dat(%tMMRx}%j#x6y$;NA/P6͟G8`at[/h()+R],;z0`=!No9!t?VS LeDm4d4yzzd 39?qH_>sɺG]MQ,@VR?DɮG;.EZEIf~6 X3X;�LPTXD/~&y i,#4B 릆8$^2YG6 ,9BE s|aO!EYaZwK41<\s9+XMgy$َ9*+ pYG�rLe:>iN{ĺз CߤV=Q(22( ZLYS4 UQiz/t2vE�1dQqh*l)|9o>\\579'V9PKMiYt#RpyCLC'[)14z ]`0:_*w_ЖܨJ I=n<fYNjE.OxuRm(!GP`} \|fqer\n<J]Uo4~A7fG-Ct*qjEӟh<p%j 嫋 lNɲ$p<w,УIxTDp<Lujlخ"H@�=,Q/?Թ6ølG�LL_&<fy__/e|H>aq k<K5a6wWiKVGYhW4;j"#4xŎ/ZmD8VXitcAR`=F՟6 kR2Ӟ fi V?IY`<[n.q<Bn%OV_@,Yץ=P"Ew/Ɓߙ,%aߐN~Wn$#:E0 y<O]�i86" .]_``{ Y3nZ 6=A M폠O<x&r1UY.5:"} ,Pk+CL x2edDkJ&9Ddߧ<m,⾬z!$xm'(l^:1i4;zFLv-zG2w-]n\yYxDBV.ݞ&Dڭ�LAȚ 5kO\[ kFY/8cj=`΅k>{n/ mId+FM]6!pN5 uZ-_Tj&/ˎS߿P/}/Vl4ʷW%Nz4^̃U%O|M47"GtRLv}F:@?{=W".~ܔrZ~oI8R)bAd%DOCGECp NZ.WcOO9qz(~*%Ɏ"Gm ?`MG:܉r,;Y5~S/OӴ׵,aH_'8(~hK|GW,usd&uAK ,=mm�~>a衪MuIf}U,Av,6]ߖ6| P,14i &@IohCA<pʔq><fJ"nَۢ*q%:K?@ld`8 Myi՞F"A0 t8ѰTjHT*󢤚(6t,e(^6fa!6(JRN:;H5t~~<ywMZ3tKۺ $CKvl}Yߏ_,15 e{z7!%ήEŔ?8**eQ_-yA;]:jqS:|հ#i'\,f}F@4EX18</wCuݮg *b'ʵLvPTvQ)ވy] &5,]]k9fM\s!A9Bx{uMc)5  KfNC^*F1NPӜcdSn7Mʦ|QjÔir 3=.=SWAAmX`Q "ӛb^opz81!OFLXk =rG6AhRK-/DKHGl}ysQiu8%9A!ZKZ^piU 7M\|SWL7FhOiu ,_)X*\6eKiqf!ҕI_Z"֛b{,|4҂<?<ooOߔ@ YÔ It<BVh"m q#UG?,(%WQ0En0P'ۄF F~d?2>ψ_&ص7oEH qyyc .˵>|)um[<?χQL8Q$+ 0\yLJԫ_]u)crhTK4%nN4{:#b%|w<$c.4%5H?WERCh:mACIRQSb8e<Q@oN4fOϏ' t\xQ0 yȞeڷW/yp Nc$/{t<M l2}PdY#Rh[f߰Lt왾Tqdl'+vw580 ؿf!lEg2C;'I\9QPwZd2mjZb5I]߳-4e;mѰV0ݫ& MS4NYGi5GA\ZZmo+^z]u^z]u^z]u^z]j._\~VS07oϤAUhqqBV\+OyzwiҾTl%nD�9^"o @&䤪S./BT4mEUKeˈvV!VjEƑ^Rj^Kיs&`qLmvDyfMKS1Hbok 6y9If:r٤я ӛ j&YHԸHnvj~OݼF(|W0'KTƨxešQwYG5)X被)azC BYٵđo2C#7P(??LooO;zX[YDxUxF ]-:2XΌaҩ?g)z:wo(͍CW]$ Q~uj:nE T۝'&եyz7f鄢'cogJXBUK 4OKv[<aH^֤-1j<^=ƞ<JnV d),$Pe8/, L]VDE'J&vcA-e|YaDOy=s2H")?2| i.h</N&RFֽ(ptG$4C1.hVFhՄ2j9˓$<ʞ]ccjzA<-Y:^ DHjrL 2NFquQ%|S)=j*߻T,5MϪ*4D) /kr.x6h6G,0dMNe}#{sHiAZ%XYqLgX gudOoyYg DrE´ii\-Bn "O_<TFY7L $4EF7KU9r29 msup"xJv<_Eb NT $vNdYfTΑml?- KԠ(bzVWoz^w= 4+= [i(8Y<kTE%%|@ 5Fe6LEՓaC"4e " ZγKTS먆M=!J^ Hj/VMe,P4kI*g ?,K0)�!By`"Μ~l^V%~7BOԑnbSw R8c %%Pg!avf|B/(@CU$'$*}z4A2 ΘX׋‡/HQa$/!,jxA|VBVyj¢ho:4:-ȋȓn.FRH|Vy<m`5)n,4@&X[k)L1͉Ď. EKD>o* FVC q!x&*l 7QV gf51*O|M1SS!bicYFp<T~:=k$5TOiЎ9T7A\L!\u{ȲaCe(MEͱZo3UU%z򳡓Q@hȴ,<ÌȈ.R8Lng(!1ƁɲVzr.!ȴ8%(SȊ8],# w'YU[| eq@@fR(Н9Y%YyچywGQi^Hoxu rEHGxL<?̊ĔT;4i:T4,8^vȸs̷XScxgF~[ݥ:mnV1<fh$H0l\%,]r_?7R<R>E${?xܿI&2()'m u `$z)Lч㉬")匰z~Gc,zm0ɠ7FI%j"pE᩼["ATAVX i|u͋_82}5ҭO2鄍n*T<&1"?DEK̔QOt<DEJZ6D.ҹ[}sy; 7lx5 ;G[G"2~ԀXEEzPǻySIFGyû/Gϧ ŽH)$ՠ"RU *COr:FRL_HEv3.9$RIyb:_/%2N4!X"@i$�AVkCDQKU],6)P0 +v_%B_(Ѣ4:QlXG#?Ws"7_}C;B9 ċ u $@QaUŌ%aD\ϠCԪj% >_cs ͼa:|C& 5ĝe nbNJ?9l$ \SBY|9�ɨƂWaaێ4bL/ʋ ~e?9<$]߯켄YE5 =JX/DY\͂0>~(cT#ARnϺ/ r,Vm/NgJUlDbP yCh(1ʿJ^k.0n;.9QQ*_�Ew߽8m(S&Z.m38+B!x3jj! .Pal8s5ZY5/-u:1 1#MgYQV `rղ)�!~RFa {1P?b0i!jy?4 P2]\u òL J4zl?SNQxG8aP*"Jl 8H'麭JpBER53H2,N% s}xr#އ_?|>c .:S'OUnfH&sy6@L) #5.j"ң!ŠrXX,"Pr_wx<Oӛ>~vBψfQ3/xѸ?dd824|SR!E%jVXS^RS0߭#6>]"=F#أ߼yb02XHf 2 ;T0KP `*ruփC dY`k#AкL.^a7Ó>:yFn²E5Ǫv~Gհx r<H D՝kCD(Nq[Η~￙Bȃ=}2a8|v{x4s%ՀϞțm VʺQrϰp"GYS,3snP`hspo5x=e((~ORHU]Uv6r'ÔFi?QR ;{-$ vP. 6.T ^hwv>5*ٶrHG.+ؿ߿SjYy aV|r=%I]YX c$D{DZX:a)nE@lRb6k{OGyEwa!g߉O?Htbdnm!|֡e`486r Tc4x,LN֣9`&O�^}0a^ulTePܾ?8T90ڮ[<I�@mZy`4s{&SQc!jhNOE55,?GQώzz ϣl#h02lbnC ~$H<T+C[1bCH؇ˆq*m5TQvv>ӲcɂdU,iEZO_KO᷅&4O)/}LVT)X}̿+n%Ѳ_<}|>#DX~bo{eu ͼ}ɯS U{/:#yt 1-sҺ%DgEDz={oXWfUS|vEYI4^X !GuvOFo 7"@Sbz,CZ}0I|-H~゙̓}9v$%uj̔>yӁlĨ(L8|7%a/9/ rӴ-IF"!O542j0(ܬb%Cr"1v^t_tziMI CV<{u‹NbXUE?QcL(GrVH̔WM<JEV|Of!)!5w_DP}b;Divw= Zܩ|y/w+"۱* ϻĠt8U,{$[9h!򃸜!>$0_~w_e2$nio@5?Gul wu٫]G,6 r'7Y7 �"aw cr¼5J"e[5+ >}1+B,=w_n.YtPED}WF�C`fpJ O,U 7CREaQzcmj-v<RQ`G^f.p_<'Fsdwo<{b %2# �E�{nzH7DsF1Az۸W'v , U޽>8Ib!e.6X0<ܳmZ^Z(' 58q۸ӳbIeQE9=9;9Q^")<_޾|vЫ|$sDzxs$UÞqutA-@M)[4}g￾}& v;/#`@ \'}}K7f&̿+lОŰ]|+aaK4~7W''SZxY M݉ $Ek?>z'sMDN إ.>7t`"Es5f'SqwA"̿MS0:/% ޗAg~/^nNPfȰ �v"}[bvU$B*}~x|٧]f %z}~n>l'ʑ^,uNd ł(:O z[2`tJ`[Ax�̀Qu Gw]xލZ-"/8w'>~CAqR&Auo,C-kVT7$+^f8w;b8AMN^<?tv8ai/G(pGD PP>{y,ᅦY8u.O:rEBuCfY�TX<(k?~�͛WA#2ĕYob{Z XqF*1@p#ntpsu {4Ad_ɴ$CߵlԦ݉RJ%K=WC塘 @wu=CɨgAL0mB%L'aw{՗Θy(>n0ʆfehWל-bP~tsp.|a[ g=#!0%q$ Ԯrr9#CMf;~s_FO;@Qh]dI7m|CQÅp}VB\R < :o+L69ik5ˣsƇ߆F/fشˋ΄uΥ>K,=D D0l^ĭ f_z=^u$$ydĨq}բ RmHC0| :}MacKf3G>@! �s@컎ztgww==tǵkrSDMatdq AVag'WC wq~y<Z.XU%2lVR2.["q}݀�.nO^ b΋+@v#ݞdҨG8GO/zaΞ~ 1UMӒQ y 8u;6ŗW{;ۻ{;;;O?\%pRAeTVۤ{O(3~TCH]!ǧCt@'|T4᫧{h˯Bupȍ/Y!< o#ĎgG7G7LHE>jjؐ4B߃$d90|�v{{30wYԞ|tAie)ӱ(+/`T\hi(4YD3_V.Swݥe+aj,h2(�'mu irjgo&>agm )/Jl5|;E Nهy0Egrlm,#p*U;�|@Ta OwJjaRCJ8! ѝұyh8PV[ a5+KqE=NmmXCc/*l'/x}lT*jr-T\zgƃ +H*S2Ұ){Ǻf;ŒBkb" OWEare)GBJcl"hλO>=*? 8I^k(< P+Ǡ ޓ$~8n4avsW$ץsBn =/|,Hd_N>?flD.�{Hy Y|oSSfk�UD /N* 3R[OW&bX`t󧞠(h oWY0Z=xP? q7b k0,}UF(DzB >y\`/Ai Y57T>%%R؛S}9=spj~@~ M!eij Gh,TBpTYYj>MM]<r$4U9z{ɚTӢ$J]A&6smm qÆ\r|KqP1-�ʚ晭D45I ~x7!1O)~>Gh r9bcZwPe<iߏ"(dJ"{M%@`dɗ�\E D^11ŒՄtJlP@>*nxI9[@e &F4O^}<栎h�*rQV ȁOn>IPi̖irFA=/ Hz;xLsqi#1<R|CzX44 li$  \5W" <4vCc4.Xi 5pz Fc*n2,MK=JaJ`t8Q֘\pAWgrFSFQ 54f8`7765LC(��W Epeς`D58xP[ �,<`;60ϛ& o9l܁Q{ZZf%.48fraZlexRNcG0`%] A0YNgUύ3|ApZ2l$jdaVŃ ?A6ͤP Ij^aqt@[/3 JtdM v<=) wVxTjrj>O D b^w͇iL,#AZ/: 8Gkeb`Ęb;=g`V ltM3xe%OΏNoǣAH1Nj`16|0tY&FR ҫ ]9z,5 ƭ.OOlGل"7%!|2pv_=JW<Z? !UIцp&pK^4; <9At7̚lûpv:oBa,oxɳX. HD \8H7{i>TזҬmۀ*{ĖeKvF Qwe ;_>{?F_.IR^D DcDW`ЦdJWԖVԝnKO *e Ҭ[_u_{l;oGz5~);,[}�r iNTJlC"`l/rzh{b%oaܜPRq`cLLffxѶ bΓ'{Z^~wh%1)ӳShfl�ؒ0#XyUbDžoPg]ѴHL&Xh] b^xos~i(\@fbO<~sHMy�oAݚ( ס,-E#aE aj{[y9lM7p1|�Y<j0,۔"ǻO>5Jkj `C[γ4dsTηyWpN!<cAM~}?P>DyE: f()pS̸$ZRf'8"\쓝>R`ꏬ(Auq+b8G,8z9tP4ߩo<ʔ! >U0VDE" 7+jH/P&6<;w  $ 5Pz%y XjI6@c*;1#B ^ >s)< oO5 %~=zFZaB1PVrnalۙcYnXNIf? b(P+Ɓ=|ץۯע5i؁ >,=ET.\l($Nnӡe:#E-l3|()bNlCս&¶-<Bfh{w΋'4z_u 髨j"섂_�Gc/ETs7A6ܤm<hE4(}U@QDش"d)VMzsm!Ol?doggɫ Fk�jsԖa}fG/Zpwqa?y`_fAV?-6 '2u$5`)^^ݽ7# "rj2 !3vAQ͖v0T+C1n:P IK"Tm'P!Ϋ+䁍C�Z/w!h+|j O4/)l;p0|Uࡲv;=FyƦ;*IBy^P_oHCoh:/�O>=;}~uFH"ShVI 87/dE ǐG<�i'=  -"u#Ɛd6S2>֖ G!n>:^0?0we %d癫 R >pcH(~tU8Ý]s(p*lX`{-vD-6>blOG~\ețb@@nZ3?5"~9{&J!ZG;{;@>QPrb46-1zi4&a�LIiC-|F�,s�k586WO载靗טhi7mēߏ Ž3ROPfyAf)G�,�j[T#y9T{a Gxa%U /{lڢH6yUś!d:" f!h*8ZJHŽI`B S=yAL_h2/NI7٢qd̝Gcac 1^IX�&S9Y踶_GwRJ"+�;;Ͽy H@wx}cd:2 P!M)eah CG8$H\g:4,WebLo=x/3_}p o3#0{Un�&OQ׹<= ̢"\^"/_|PbeP2bk `~Lzlq0ZI$l=pyT%`DwΎ//(DeS׀W1?׋B9떈Yg/;ads]b7`;m׏Ң|cx4ضKb2G'eHec2&U_n|.,TI X_߼~jq90, =bܛ@4i36of9lI0x$Y0Y[ HCq`o1̘P^\Dz˺2UB7@N%"cV 'kk$Y�# 68ыfťZa%`+fh$3]Oտ#H FL6^W_a;l̊,2!g-a0 X?$Yv 8,pLﺿf uڌNf8>WwqlH0y8%wM Fd3Ecl D �ȭdb_`pv'Ӽn8捈4e)6jr3N)>dzѰdhlA]B9`FcK`�G#曖fʊ4ʯ-7@*"/cF$t#H:q 6hy!ް}0nBp7xcdA0%~|u94?kI!s& r_'[$'.Ff(!.Oo:,*c.HҼ]nFowk3n4ːz#. Gx͠Ftu^6m( ïx͚rFIx=F 9|wn Jnql)T3o>zV߈# O iE樓TMG2h7܎E ^d+7nݓ j*R4?exT#~[YQYACM p8 fTxQjg;BbYP4T4b\>#<4TS?O⠛JxA,éI D .QIoxňlk7qgIOǷEb65\8Ëc~=.C52,'⅑ڋ ^+rySEγf?JlJj9ok}MeǷ7FXS0Zyj2E°xYπc#l^qnyrxշ|o#Gn{UfCV q~7�ݭ đk<KA=<֨ (XF`"[YހJDq<?*=&!N2)*g2ϱ,oUb<ap0 o͆ϗ]h1V\C^c)"D87 ]N\،szP/C(nzݓYC "(Ai:|. 5gt+$rQ7##?7b5&)D[[  ou"}{MX0\zʦ7wk(asx gHX!?)O~ܿNF 5Zo2+ZĀƖE^Ԃ<T^.(ej4fxArI\Ap̾kRc5n.λ,½]di H.K]Ywꩂl^zpS>@/nSig<wn'3KtU(99*&BG+nH7͈fyQu̹mXwxtnrT9a18 l$0'[>iTlݯM (%Hi.5MZb$7њRSߓaҐ=FpY.& /ɪ+-Veza|& w:?Y*W8|3 qBWXUvD@E։+%\y5 `3%o~jXARx_,L'R_lew9OF[c<#)ZAM(6qjaI.Ȇ+<T`{_Xf}B;}9XbZ&g#^D8ܢE>flK׍#ˀ6^fk"#-xǡp :!KSln1�Ñ`eIA؅ڊOFL*@(MpPlW%o>3lLݜƃ#:xS˅Ɩ6�Ӳ,1}YnA9N/<mà: $]_^h4U%lGZJ rEZ0:p-ezy9׉5=|pwnGӐۅE* ;XE`U G'׼*`&lM*zdf:7O)FR IL' : Y$Po#^%dM= Rd~|z09-m.fYJ!Nҟ4dFao >-"cKdFG[[u I�ЈwS__/NV w#DMUlMyfSy\pHeAŷD ]yc57&t {gR T?>$ӻ&ҵNTaATڊ' +dTw2lbe2tnm %E7hyqeT+`%c)AMhu,Թ锡[[<ԨR?nWwMhEӖƣd`&EÉh爑,>�WĥaK|N ?(]PC# v `a�zX/"O" bC R.nvkK�Q6 8OW(\t*x]!DzSN66dvB^Xƍ=?q@s-tzYpӰe" ˄6/(5D5u:uu}b �Bu #IJrimaېn86F0XY.N1;Ȋ4(|0 X#`Y#vKE^775E V᯿ݺؐdF܅iw͢qM$_l!w?_o%<~~~~~~~)ןSDBA@/ڪ:0 0I=ziǎ;N"ϱ=v-H4Ҳd6R5ڒ;ӲLQєWT TIs}֖A:LQCμ_05o*>Eq=oeǡt/9 EAE}d,Lg(i] r96pe"zd8حX둠muJdm j։Gm]m\^08tUgM|}24m0NZ@m djlty6]αaImW?e?xT"ty7!r*(UNnDv,N Jz2+9#<\]̍f;'HBX Ot<H"ql?蔬0kIˉ~ո Ö"@<-XQX/hʉb8k8bEIE\YZΉe'E!?\<cs7C-n9W31F#7AbYJlEǶ(BmΏEhQ$Ivyʣ (~$oim,2N�(B[yIyNBTMmx!Qfwh[7YbP΁Is9 j~ylRyy)ЧjWw>ZC\-㴟_^zf"�J2KlGt!̓$ 9d5n5If9_-si($8bGnop}H1a9C>cCi^6gCn! *8F=['~oa)`ߏ2KXwV`<&7 hb> ֋:12h=zEbj`aÂAm:Qq(.@o {a6EyhN3_ sY=L7ֹ ;G�B94β2냑 2?[n<h$ut9+�Z�Mgi&oF|}QiEXQM@Qn}lu)ǫ%5�jx:4cN9uhfH(λk$L/0cQ F(z^HA衒BMak,1Ma}$e)CGyeE+k$YY/IEl9 70 ( J�HBb5;9p"ICnjPM\` B wKd%~ѪCEp7]jqB{[Y:ԣYhBF0n܌3բJ8QPg,@TLu5U PÞHڍD>| ;E؃̡)xgȨ }Uw8WS%冁gɣ`Xѩ\cڠ::`N<B"-d 󚚐BDMD-dM#B1IߖƌOOlxrdڨ g0Y\EVi=IdtEnڀ +&grcNO拺DB-H¨f:ekcƉPcH#G5fGuXAd Mpq2 g+4-写t.,$AD)dQmQ[Lh%`-&u=Ei 敋ڈ ?jloH�hg 7fՠAٱZ -.coU?qU$r.zQy^v�ȳ#H^(+0jh?N(U5 ٱhXg5FZ`>c" 0B4+BH:%p<GuΏ(G6c3)Bx>Y>&WM&DI25|xspҥ+A#)*vÚDDȖ- C;}A %~(]hw`EȒ MQ:gdd(|RICdlVtdNT-7JBT՟Ezjyr꠸#J N^npҒ(:sp|>o}kG1[< fN DDHl'lO**Mm䘑5+ũ[-52i"dUѽ`ؾ89yc@f! ?H}]ْp-f(]XZHE4C$evT͐&cj+&]wWHE2 <߫e%"<Ir6kh(Y?Lc#҉\1ddM&< <$xuxݛS4Ҫ܈2g%MyN]/QM'pVS$%]oo^! P!juN{{&inu%CN( țQ݅űb=VV݂P "6 !S s!yzp[N0؞h{ $&&ES*z^2ҽokǩcx^R ?i+Ţ*A S$C3IXf|2tCi"Z.,\Ef6[no' / ?*-(ʏ<~Ub'(_&r:E3]M+_FAD Ht^}B6=a8V cf|^aҟMȽ(K(୨*XpTIC)K5Fb3g> p:On$A>zr\EAVx >]žn|L?Ӑq!{ZdXG"c2=va6K*e$3', "/߾v=zG_[Eufussfu.CtBc.7d(W% hЧD֞y(T.f2�G 'P>~8n)q:Bj& )\}0:#S=E̴,M7 HJYE ~$<ziMC3�(A!_g'ix0h4o(ulLdWz^f*=Oj qg5zdZ&%?]ۙvwd1= z}0z<͛sהr osH�,Yx<BY`yX<:`<d#Ma%vѨ>n$p QE.O/xUC p"\nP 5:' kP]j4x0qQË3Z5e5V#|y;Ͼńh1NRxi Edip|=8aPf kʂQLauV/1W(ialHtg�=9B&`Aǝ81l1.[5x "}OP(R,P6*l|>( 3ͯfodE{]5V뙯f(zz}3ȧ=׆&! &J<L`dWhDMxݧן)ru?(eȚ 9qXn NT1POUP5` Q>I lE;"] DyO#ILq46! @UILIu[Y %rBex̎.Ubּ ZmZK#D UOg{;D"P)7%d_>{MGTCWQT OZ3+"0D%03 Թ#f6 A3f}AσݽgϞ_'0 O4UX� ;y%N1Bk t(!. MB&Uo3-B`ՔG<^YBQ[ 4+<Q;ϟ尛BQ뫽gϞ3JPD64R}oD6z)+ik ?z"ntQ8:+.Cvhz1|A`Up45잽{fXp/`wVzg/vC\O1!h0<ר)hƝF Pŋן>{ ď w&a=Ei*Tʳ޾7kzEei@ƚ*jGY.3djdn53jNFس$*D(8<+W(La(0| LK�{Q{porEQ2E Ef& MY}y`cUg!5J7E*}#n{o?~>r96QDfw{K@ǭ9o_?ox܂[Pm|2+\ PA8b>ȅ[e3u|d;*/v^QiPO7eq|ݠd?oAJO;a`le%S " s@R"AY-/ ѭUk!~xpa5:8YEt˼O/>Xoķ*aQ(]UFj"Cnh,G&"ݗ^|| TRYuz¨uz|t'`3\Ho_q^"PL<Dru<k*�;v$C ro�'v=Y]]^)Ջw]"SN>y[C&J4daI$@D\5dٖ'NB5ƺ~ :eYJ횴 Iwoh�P?fz^bc|=ύx’\o&ua"ru4 }ϱݨjv|Ž١J3 u|v9fD#&/w}4I^ҝs ߝo1U<ʠ.G>Q1l#4>/k@P.P瑦81<h|<EW/�HF<ͲDs)k*Rza&y`Pnڧ߾>Nr<# q] <->5;[oDC]VӅCTKPPp:TMKQw #OZ˽ @gG/v?*Jr �簰pw{0`|7-PexŰ6zQ D^ȦF 2:݌y`Pk|ggهُrm"y(nW{4dX_T$zkp6>O&k% ɆgUDnҠM_@Fux+C!RxNz<g3TOo_x.N!K3hzCKCܖ4'*&E=ɠQ! ]&to,~Z>u&xыg_o.39=D bf#w@LC#q"qЇN|z X\TFcUu#;?`L?QbF"]|ؿw[. La tn;/BUޗ`9>r\siB.4Weap˫ӋVw$b]8ǐHBƊb8~`C% i@ퟝ:׭&~Lћ7.NI?<~ݧ!"*_OdI_9zxry}q⍍BwǺ�~ nx(kN6"AZuGTEm(õ'w[RP]쟳^鰉cS_)v:W7Ou.[7Ƃ-fQ|KKF* 5|A:M+mkOYeɾ{sp9`9AE'<C_Jw@Np7*BK^\CL`8;7ޘ P^K%pI f8�Cl5UYʡ 4p4fs͛o߽}w4!D5=* #%؍4h_ xB+fFR>h_$=Jw H_ FEfwa4;Tt#oa*;bIC5cx#鸐� aУxlEgIXܘ`<GE@J"5uՎ{tfq) ϯ{;gJ${9 uK2LN TtB˳`(pYQ؏jԑD#n.CYLD<AU2zspzrwӧۯ94 n4 맓P>xw>`,f cU;Yz�A"(wif)=(A\Q <C� "[FۦiW_^4;on^ Nӡ( E|G 5j4 *q(eyD. kb)"e9Du�J qo_^8xw4$7øPU sG]8\_ Es|PQ(]⾩>to_8VT=4*t�SD7p@۱=}pi?^}VwZtiBiÚ R)"Ԗ W~[}XɎFZcAN \t{.%pìAv `[>yl_rPoFq_T&:I-ia@&yG طQa%cȼO� ],nN`4*q ]f\sfg;{/^w4D1 #fZzʦ HGŊC`LE|yKRLqv\Z7$q\(1$/K]Ĉ4"r>{_,r*&6q.uX9 c8kVLQP/+ -뜵ƜXII6`rIVU?b�*/v_yquQ*Hh>X1BTݲVsPP\,M=t�DɄT*/ +ヷ, ' `mR=qß}Kҁ)ԅ#aPI9p\b]o(L{bSS ͷ?oPfU3et8LI1 |rg?u!JPnv Эxm�<1<]fb&$Hyo]c-?ƫ6]SFQVd )` hśׯ:g'^⁉b"׸@#>1ge8W Q5]AwI( rPA`%`'KAuE>{ 9(ljNrdw ^A888zuifyُoL[G:v"h1%)v3=6!%a,&st*"�f:='qV=7�L_ڸ=D.̯lj^R%փMj5牺&0#ui-gH�5ڃ4٫NG^u qk&d1B%.O[~Bx(bX.U5xѼiG4sA�~nc!PYwAjp,QnqY^aG*i<3ƫ$wRWc7ܤ0ΚI CCX &(݁%b@p4)yFaU9'Yhr#�?o:P!^}d[D,;bwo&xu?E|f׵&vJv0�zċn(e�K.e<0PcěA-.( їW##VPZ> 4eb?5Jl 'Y `}'9FE-2<'c!j h{?~<;>(2؉MaԆ?w+,+c?- H 9fAVc?Y\e�O=\s)LlF] s5].WHiتxsv~qjܠծVM4Eΰ/Hj}Ž(r= Mq7�'<bnȱoװNX'*sw=|sě qLBDP#s,)gyfC̴zQ)R,V� Fxt;l#QӲJr \Ils~j|:e,O.PҰyQ'E�m{QE`(f\$&f Z= tre2%}h"߽{l(G<{ɇv"0`O,yS$#�փ z#T6YHӮ,E@t[x<N<4Ey#k'OnMfj%p5sIح%Aa؀?EB!xvCp&{| 068Yj2vqjaQV%zs 6Uϯ?<?y.4M-< ie3ibM Dcچm1ư>![wlC5AX`Q)*OaOpʟ<}$հL+"yW[a%i-@Sҳ3_GO!v%AƞYT'J� ʽl&3 `<ro<ɿ!'&�+jҁGy.K`0Z&.5 Kxd`AJ*#Q<>N\u`Ÿ=y s?d;<C4T܍ 5b2:5)@1iOTaA-KsmE`<@B6'̱s2 ԵSUDO$${~| fP3< Rx:\->VBJ*)�«e6R.!d2̪M~.8ǟ026�eK U:`x*P.S%EbhE#w>lXz(g ͌3ᦐh7B~/;ٓ}<z4LC̳ iN '9GSZڣ.p'�s;I !)PEn2 3-ˣ7>}ys lt[ai 3 s{��<>ː ;t3)ZHz@{.I`8OP2ϱR|^EZFCX&Laitf( Ҍ 1+,ۗސ4+1" xrscCBBM DI9U}C'흯=TT3q:'x`,6%QYt:bּ1@]_lLWŎkNkFFfGAk>p6Nj'Ktu* R#rCRag #fZӾ(Aw"mEHjzAr< _�`g移`4xN rrxXl:i()@;`ꏾwLӤ!jV:<qoȊN1%nbǓr6zufzowoK3j+YM ^n9dj05nX_`1Lf%N Ρ0ǻǸtgw~M˲3ܙm.ibI ;}[%,k*D]hK䁩xH f6ʮ|rMCтKq@k:.p %i[6 ]il!\0YKiٶA;3WEz>-Swxz(ЯӢ7Cj;F^lysIYmKE]}ƀ؊WU 6[U@QL-@`.={fZ^�}>RL0̠GV%Ke5 tᕓ~k5 / 8yV!o~U{zާ+ dJvAeI ͛`x%4P^D/@?u% lRE|=E`XfN?C;dun:;O7;I& BC<k� -㓋'Jx[ol骕6bDzvq:f;4%;.vsowP[2,phV%T۹yE0[>zls�|88Wg:_2)%"wȡnq[lV A*nnN ͤ)qz/ !|nO'6jƸ^`Gq#㧋}p_fq� /xA5y|oFDp1x>7}mw0ww߿*G'qɰHI.6 _$bH`ݪ/t}/؇i t^[x5in8X4ܯԵ&Ee$H3};41 a hL& \c$ql 䢎쇝[!VPB9Gz .66>4a0D,ܹ. #Ls$!wؚZL38ܖACr<.VZ#K$ftY]`M KЍ wO }]&&viDcORq0.eM["IBGWsr1T7}o?j3<Es7ЛyYw }K3;\C?&q{Ć=',s�-HD&ES!XxAZY`d#9cH^s9&k2k$ngLsrof0Sj}C@A^a $ɥ+9Є1oAR"g4vN5FZLCfYnxZhKRmb,9ù]N@3dl11 7:0[ L / omRza�[vDp `)G&cz:kEB*+?.ZsP ;5"Oכ(dp;b/}9XCA\3[QMs iW}|YdV*٤!:9fGĞ?MЁBT~w.ݟ$hŹ e5F Ykb 6sCBSP,oeA�mK�Z¾o]v!>5ErM 'Bt1?n(w%x%Z >%%! ƭ+Z5MgFxptdr@|cQˊc*؃0,3!ݭg%ioƪc ?JRUY5X} pU6gspQ$2-,R4$'"0ngEںwh(Y=FL$'N; Xs,bO v9b8Niy:cN-IP'a#ې^CKv- _mۮ qy=fu 7[#f7C^6Xg4L{^y x8$ң 8WS nN%.�iaʲe%T<?p`5MW7h77ˀčoA"Y;?^2lz$a!4.s[U//|M䙭C1 M& A7|HW5`%UADSh bnXo A"m^ a?}p6 )-+yp<d�@<Q鹝% n.MtbJ/V詢n}ppقdLjɅ \5ΊL6 nt>/`Mh<%4B<){ >yTwY"j>S߲2€knUa{2@īVw6t;$G|UA#\,sro)] /_Β ob=4Ӵr 8#Tf,Vg"'[-^dz<�D6M+X Mh?H?6 ;&?"j #9&y`�VP(/Za>?Ƃ?0{!Xyl7[it&}GŊ"3 x׷Lnk�٫-J ?ōa^]D3 Hn $H/clZa /F D.k$+ LICo+@;M;A2-i+_š'OgXU �-n7[Bt; U? G7_(c</<yO|hP xzT0hӅM䑐/ N.#l*걛o釭 ciZW挊w~*X! kL!YK$ծg4zSܮ煫JX:ug.(Ve,aϣ%Yo`:~DaT̚m/E+AԫyxocG[[.�NFz)<DcW~2n&NgJa_ ^WsdP! W[?^tc1YV5atz^9\RX ;::rW~@7=Enќ-}BeyU\|&0;LjUjXZm̈w].Bbw5 gٙ,�+usUaz.C)RG^u!H�1a)@i#() 0-*ߵ ƈ2E{&Iy5% w ;15ofg<xIP)^F!% c;5D(hyQ5I{akN{Ar9?*D%(T.C�ŵp4$0HaM}ykU$ܨC�Éh�1ո7VT/o!2H0v\t7o+5hXaĞi`Ljv,lC큠Zx4Bۂjd++=m$:a{spA`3B-'ėz^ARS7jcUoСOc;┋$ǬPB░. .Zey|IkpFDAΪW-fEhi�_`u&˾`D(ԉ=hyJxr35Fϑ <PP8]Hb7>[St�c$>XpZ U!`"JgK:ibFPq!'" xm I0z Ac0Yƣ/,~͠j=~=~=~=~=~=~=~=~o!P7~ C0F[zl0+i127 /q"vM}ebѳ4'4ɯ'Wf##yU? 4;7WN@$7$ou[[tD0g6)jIhHةF87EE<lKzly, 9]vtozUrO" SpV{u|eS)8Mgフ$՛zkZ9$fZI{$^2]/&%J΋F$4vmq<uOrjڠwl+3tحK)9,W:%^2lShr:73KʰP冔t֛-ɶtnĨA" ēƜ/Y.,D40"aE3[z(ֻS`}9F@Ł6z ]GHj<=)Q&UĪUfɬ<5c3>U,\yA 4V`Uq訊�C@wv\?)&Ij,2T(s;~`dVo2.k8+St<HUc<~|ڔ|Xvt o$ (I} F <ɤH!*β�X5ly<E5JsÛ,eEt\|Z+Hҵ^V;hCg(2%my|8sv:E>ԂEŖL@HPI95rH.s~ڿn; DɐTp->-LiQס1>?7M'kXC:b{a6?$_hnzgpf'H߸^/ NЅGdB,hQU(zf0 `UʬXn7ɟ^V4#UoHꈔ= ѽ',拦Hr3};$;jֳ7e 0~UMau3dpr"A%aۨLʒD =}. �{! #j_!弮p*&GD*jG^]L$mt2tyDY20+KBK2K]U@F7d5&Q%WBfB_>u4=?BUc\5vَkBnoR~*Y_'|o ;%^(.%(8Y" ͋0C6Byh ,GNAiw:ϚPV.8W AnKt=\S%Lg;XEds܃\%xv(e@EhPfy b|󨰚HCK<Aq;v/JY' [V1ʶ! !B`&~ jGtxs0�EQ$*" r9k愧k8X)Cd?h^3zt>M WaU0HQB߂#4LqQ|^̛/ϙ`𓽺/*& nCZռ,+9 u!@(G1IlZq,ɶ|nj$@]yッj/" k= :;+2bGf VTB&EAejn'? $q1֧݉ÅɈ78@^3", C]yiIXjxz ȹD^we$e^l^6\L!Tj=,KS,4ti)PfnBXfmIb(O,"`I�o/ vBp?<pS'GC`DE&ݿՐ"OzYQ ݿ.67n_uD#(X Σ]"# " A$PP8YS%ĕBf.CAtQ")G' B@Iik$t=I8Y3mGIdم k"G 58|sGs=댩I˻!cy#>, dX7ļ7[ ?aÏC <x E &YwH]^W'_?Å%*( jf`WK�dy!S9 g`0PCMt v F<qd0< 7O}=]/EZ?s34 mXEQv+|B\}蜻 �^nR(vX/xόJ S`r\·þ!< ?rDBFVիbAXE 0jH"Bo%ceUn~\�h?^Yb!` GxgibFg_߾pt\Ct|\Hˊ(omAPW<0 PPDngJR"xs i-pxD5K|lԠ}ݺrp]wWT5f(, "%\E2 "9MIг.4Pu7׷ '/Zn(E @E^",U`D 9܃I)伏-T`፣OSxND Yy}Ʉ�nhyWw3_\RiWuw";!!rï׊CcخSqw,o/:`xƣg!'c#Cr?$_#5~@*ED,<AOw$7m?JÛ%`㥧 C3|(˒w{AMwh7M3Z" /i:@/~>>8: 2/(&lHU8udfػ&, ,5a8!|ٚ#dt96 G5<`Y{b 0?1_}owa7am9BМ5습d<>`Qʄ=$IpՂfx4X^{"ʊskC�!/}L+Qqkm\ (9x,$<MuDBYFV*My@nN˰6ux*1 ɗ+ˣ tP֓z,_@}G�>Nrg |*<'~q\Fxc躮*(J˓L$!Y9M))+V?V7bY,Wj`OG}TFrAOS<p9z\ a:LXEHMW_z݆ Sx dee K- ˁMwo޵y2d2+izk)²DVG' +C$ m8:9g`/r#�")Du ytô{ |{k 1L&j:x\E5 9 .0%E {)Hhx֫s,Z"D0* ǎO_X7<! 2 spS2?�D;N,KETeY5bMAy-=q"N|Li>-:.JTݲJ¨CrXMb$2UTs @jm]x8dґXPZ.fDXbȽk/` W ubGo?}GV*p"AMRf: 7^.r6WTi9ȵh)80u[cL ffwU411!?Px#AX^ �Z!m`'t�"̵/zHZ@Ҝ">CcQ PqϡtF)X:)___|}#qLUEV0!<aL4<~!UdDI3dtDrE+7t'?^_(TmBg`/YfYyXQT#x5s g1�Nk,C45gǶ:uFQ3Y.or7?JD@kje A lBDǔp"/U]SՋ16UD魓&3}pӥQy/QSUms91iv_y`c' mwgŧsgyh^L xH2/{-f*W9(hX 9q80uX AjS(9B8v^~~O"2 G;϶ߞ �^CʂQ*z7 \&dn wGђa^?Q {>w8Dde]G/~*9o9z<=pKy QҒ\Bn{Q'#xթkj ikuTyF Ej5_d_񻈞#!C^}f'JKȃ67oޢMQ{`Z`6nwՉ8$wq1`ŎkL茬5y,}ǃN2I"?:B)͎1_/w=K""*mH.x3py_E0 E,ډF QDrwxLn{Z'GLJg=dq/>zѯQj{x*ʳyw4 q,Gs\6:γ|?sq%ab�buquqz䊲"x~?yF/ {l>[0Qmpg44ϲltcu>~oEMSX!R^_^ 9vDs(~}b瓹^5 =t7iE 1gn D:4 ]1iJۡ&߼ҿn<2';4tݦ9FNF/v^hDjAYh)72iilJ)9'G"@62/([,^>}sEq(V_Uׯ?[?((TH0\ÔF@%A*ƌ"Y;0>>=V4~/`_|PDw�Tw,6b8,K`ea,{'Zіd>}Rf� rRS闰 60v 9usq2,qDqJ/4iAye`@ 7#_D뽽omd֤"!K8O$4Я�|TerFua LMGrв{~�j:^MZ9)1}mD`Ӏj{_$͛9T58Nu|g~ !,|(FO-r}l>H9j0d]?t mt<4)Nz:˨ϻۯ;W@a9VuFUي�|P(;!=tF<$ܱg[ <di웪4v:`Օ3\QKyR�p<t\cxt:2+ ‡K}5yתGh^X:k�n"4₧Nz{ q$PulJtwݫs@ =kr 2k@.>?=9E 7] =9z̈ϖUX;,ɤ!0?]}H;)k G{vx<ՂT0Rw/h@xz !jv!]CL <r((pf C_\LTRQqr5-2\G'׀ez^߿!3(2ov}\|߿(IPp8Q'{CYF|{sND_rd$uҙpL˙)H=WyAu{]6_w^|z^WQrZ.[u'_¤Y")+0u0mz*[CaGሡg-)"-t-0P/sԡ,qwd*v˓.{^Qvz:xu()<#^«RD<NQMQU M!c%khy}q8LwGv)}|3Rvi {VpγyDzH(n( J;ʚ `@hZĵ` 2äK,-*Ji(γgo1jFՇ<C6\!֝ѷXUV TvD4}"@dľVo{ L 68Óy u.HzF$�v>uޥ9wEIMl7o EY-Ee{}Mdxx,Q݉8x(=B-ݷ;v2$/aYh+�t$:7jGD죡&%.jbӅ) 1y2H#s=H4?=t{š,kj\!/' +qK6aVCxj;?V�;2JyʐL EXRB;뚺>88l_OYK I.6%7:ԸLŻi<9C<4n;ǟA=u57pc /."FšSM{f%%)k3ܠx7 CEQ2 H&rV"H#<Q@iVfI}  7ffM+Pci <E/xJX\_ y^ qR7M;,R%MOF״*x.wɽA}?<yJ|˺aH+ 8 -;w,Ț9v(/Ժ7FA`c\1'iNEIU?b8BTS9?xU0'mcT PL={m1irDGjy!04/vi'dz"2w#QLu$.D\G7iΫ~`\^m{<Nb zΘuUxzk! *ZRO  M,v-^uf(f\J%I`@g'/8;M"oGYEưd 'e " 巽h1x('|*rO[ ؛)~>C3A,&.?yA a!v%Uޡ�{!0ʈ!W$Q/Pm-ǓE,2؉_|$q;6x#`;CpV<9B\F(+堧N _FUWe�% =>\J<u,Q2uBVy�pZ2U<ѓbp_YFaV:y!]x 3\hr9MM[hvUXMx38` v >6T eT#LZ A_y&JߘYEb0)iƮ OWDuv uܯEr( qJif[ldNN+ iq[ G#E3ytEL™QupDBݤ45Uo4gXoHbMbִ,D) )a*-@&Z9apWːTsvIES<:U ̄Aav4z^6},Z^bDF@@Ƃ3yXeA8oqER֩j}yպ>"`~|R w'ذxL,tK9=::8O_{9հFUh1i[&V9_3@$A�^ĕ$jG>L??$#7^| ^^gCFNoHE�5`ݸ_f<ܬw pz.DrAd0`*rײַ{OQ>ldzYd`&drlgjCNq9o=Xl�HSqp[TeZfa�CPv q˧O8nE0-˒\`J4!s2^o-�$:_&:JX,#Sd9Vm=-&C,_zrg雮~ s~x@C&`A^6W`xWc 6;xS&i'{ A󫩣NZex+~@Qnbn +lLhf +<} >^(~ӧO}XKezG x5;*f?/Vq �2Kin z|0RM-*vD8/z>%9lp϶LO?=3Lg`U^g`�EC֋1۞5E \ks&>OH ܬs,U?  {߲Pœg0>.ٟ:0DN3 XN0$DJ?9n ]*skrfHM0%Ӟc)JV> ߆r--n0'vN5mY5-ֺ, qNNJ+:{e$�j&eO_r#/XGiO?mgOw/AiY6r܃XQeǻU[DeHLF{@^P|؛$1G^iLC&_~(&cPтk,h,Uė/X賤H E3cLV>1C&N]FmAn&mZV0X@/mS_˕OE_\icb&6`A}tVI73Exl ;~>ӷ&et- Ԣbbn~`Ha%,.SﱮY^ڂUrbN4tWFu1+ٜ52jn?FW+z(jb&YШaxˌvesytx5d%�7i/9h],W9oJ2` @iLZq0ݏ7al'E|`s9<x^*M+gCEBg&\/;kjR9ӳgf6z;G,DTxzNU$l]|<3[byKao*JI,Hi<pTI|^cB<?5gޏ?&'OOm }tHU"XWU[xT3rKrp$aR`U"CGa]/2ȏNdZ`uV!g}?P*;}VE!-rEfE:2~`Xq<d,6Sj7 S,׋!iO$댝.:!H?Bn eӇZ@. ,Cqz:#|E҆. 68ؽwЬw>\Ro3tj<dn : w]Sϱ  =pϊДEgHjJWhۻo_|&~b%+HyB?4\l�cnzX8Z&�K P,ENcNLҨ7϶wvIY8{ٳ/Er|FPl4)DAr54nLaC EoASD[\F"Ki`jM}fOgHmȁRޛ;$F4waSNf"5;nor/ C ;םF*,\ H "Umb+XK% Fg_<&a18tpЂm#<OmU` qUlSz ֍GJedNRzcVd׻xJ)@EJ7T (is?c,nܬ,tlq 'W>#a$ܸ$N^�Bo~ݝ_{vA }ʽzȫo6$jGon67DyS7-0J"c;dHC ?rsZڧ-c7k`{X/1b,Ůq%?nɼ؇N:xM3aI� 7Li5kʾW? [q'n60^|I*ަTH�_̐xit3_-/.2u4Ѱ,d$,+_?Ų-fw2sRDK DD +M"01[4&H(~u[Hf!xER;/4h' L%FZ\ܱ2U }cFF&|vS'r]#.l/a ./iQ%ƈa徹A<pH} ^ R9 Ց4YO!o6Yc%cݜSm3ܱ2Չΐ$f@$t;T do4S]U ހXMws\e"BfV$5K(Ɍ!&Fw(ϏVw ŽnHFƱ�J�pt~)bNJTc!}~};NFIZFCjI6x5ϣ+slYrzWIxȓ]LXBo&zMׯ{ҊAk)I<!Y= u,pW@w"UnGWg׽L(x}t"9H3,gUxȵj|1&4%q<kh$9oZv�< w=Sn|EPdCY!O1I|~?lhq}cCV [2 ]uXIwOYOH@ffDSݫv℺?EHMY^*ܸ{ A3̸}=5"<8i럳&945w4g/#$mlY~gg!xH<e=jtWkWXDi$9:44z1Żi!=5%ԛy:X /PV5 {L nuyaU5R`7XL\ϪH+&kh' -gh2|Sr௛[_/]iXTehƜhtE"gYa4̹b`ѬȤ�1#l=0T~dG"UR.dʷR7fC0XԨbhIXfp k5. qrJz<@<&HT�\cBDMfyۀ^#Rd%`Z C0OF4O>$$={D7Ri:č_ܕeh L7-a0)K_hnh21QMI("O$�ypye-]=UR7i9[)[$$k^qΈ'ISar̛0"熨�!}t͑1�k/谈%} gN�ft1,3ϺNџJ1, !BS] z(' :kf>6z?X#0VP48N k)i`ug9xKǠBIN@\[*w4ի`h fDQT]@+xݺ )VS4�wj%WJǠB:|v o *XeD=\lHN& <#/ַ[Cl!WIg7~\&7͊NnH;9^\.of ;4'_M^x24 ( <vxѧ 2g2y檒 -d:OcLW?~�`!=aְYG `xs nFNK2 t{aMNZ�< 8) ˜H69dͰÊ"$Rh0itˋdx fss9f2%;]\HA� �2^!I*h$f9@>䦖Lpthk2푻rn%"ԛM:ygjol%Y0fs3Wa;)m9(Y0g| X͗R ccxpSa!!Lz0 & v?  |حrT>z3 E 28N�#s nz^i;0hǬNM#,m oɸ}k(pXMS^$nM{ 꾨#LTGwC#5~۠?C2!GL0a(j28ں!;06+X&,HeX{Kaoձwku Fc=KL kCxM&(u: , ;X$>)B6 A20U�.odiz!ӏ 3lc"959e"C~{cvpzq3?( (x4:wds۠M;#�|8SJrD)䃰mUxvHXE*Y32tg]K=0ԩי20@ Ͼ9؋1ep1֗g$x̝y<!KD!j Av|}tx1ԏwcYqdiャ6D6IM1uu8P$qu`\b)3l_ �|(W=`jBBQ[1RUL뛥+ݺi;'? cw%݆+d1 ".\n GV_gZv 庎e?[j/H6d2(C4M<]�ܶq鷭�VD,63OjPtmF6 158u[[tPr8_j#Z&0FW I^wFכ1V t{S.}pr5bdF@LjG!UD\nmuh^"Mmu=bE i2HdC : F̷4U|M#Ik.g{1{^4w{!q~}qboXq1Xfthv:M �@7;[bEi䙆OƐnxI&8V1f8$ Èz'�CAL lU9go"tø@ GT=hA~H{{{{{{{{_Ts#,XӼ@ґ?ߩ]"LuHq I#uEȺYkשR`2bYL^fUdu+[wom1~)Nu?FNMPbIxsKR,:׍P'÷HAx.x+̧ɌKq&ں>e [E’1Rab0 ώy.Juu}r,"M<Ym:)ZUyaG=\{_/V,- ~L1]Ot"pc۽8:t?FŲv~8`u•zgҽn ;rX=CLERD7sMջǭW[FǾx4& 59Pٓ&|Q%-ɔ7"K.Dl,Z ucB�iEܠsyxAQExOPGnux\.࠳634AXU_ Jm/ɫ*ʺmGV UUH4vBIet0 ,-upa`NguHiz^.їg!^N}ߖ0[nXbncᏏv,/C"ѶNGzm%(Y)p%+ldEUb& t"ztҬ_g_A[l,stʌu�[ŔF6u솈cYKh^:IR3CF-P5jZ28RRD@.i=?0-Cn$Fe N2_W`Guo Ew\SS {ʊtd1膺{:+,EtM؈ ވ_7Uj#zN W5՘hF`D?f`(3]YzưB!F!`d=X׉g r^T-? B $#(MwNhքu4CƢ.Q2]̉ Bk�tMe`@w~3:b%u*H%jeLJsaiKMÌŃ Y Ncߖ#,{jGoG[,2pT?D!|At+nj3".qSL!qQQy,4^2 nr[n]ֈfu1Uv5]ʫizF_~v=$Ɉ"p/wFXY[`̗i4UaKn4f V a$r+ " qst|!R xM< ߤmQ:Deox<59=-SO`uD=h"kYG{CsXRĭŢȐGKǁchc&1Ԅr5UW-Yj%Yi2 јv ٮV !Bkҝ02@OKUEq$"r:PCHքĶ&b0!Ic=@=I%|EY JTBTOvoUi ' H1/zǼ,h+_aGptu:G$w5J-mtAl=D,ODzcVZgJ k& Q`뼴#GWdarv84t+.c&u3_NHxRC`8j49Αh9'N" m#Φ)䆬E@#ltn$JhV.W.uڼ(QEAY8s+Bl nzYVHe`PV[6TEu'rY#1n=k464mGY4ne*Au|�J,"K}NFIhׇY!f !tn~*ne *(0 ++܄0%qRYl+T󏯾LnO8K0zysCx (.<U{(($1j&L%S8'釗zi%> *+�ăܑ##%NBO?,'\@iWAl2OSK` " |xK�T,{T)-Za% 2t@<j'`ϲ(!^= Pj0e(~;ݻl]TR[�-AJ@GST4HdC3Ȅ�pSwwcM!B" 23^zz 2?fTxZPzYDK`(, HE$cVDvQȳ̤R;Oz!|>feU0f3L5ycSjѲ`, Br8Tk"CHhǧ{gAlJnyQ^qD8ml %$Aixu5fNapㆇnf5˪.c8hx<79vҺ>rce쌓Tx3fy0-|5|`3dQӧ6)V7= ֨^*  $C}:<;=i8b""pأ˜"!~ .I<(aK*DAY'Hf|#D3Q{Z;zBhz3W?}?iu:KGg2U5i&=uUv B0r. hYc>OsrMNno׍TYJ뷐O=G⨣_^MPknwǑYgICXz$�w-_YnW{+}H ÎΊx񞨨�@UzBpMxf!E?P]61+ڨ"Gv{TuULx2Lqh!D~:nwtNtj0z,17QP4J zq %aQ)¨;dxaH`* cRTA_u@VːbG;lCH6y<A$TrVsU?le9("= ^qXN e Ǖl*+ }2>7`8@ fE9�&Q(hoAF5,?Оͭؾ"n6Q(sOC oY 4lX3߽e\�l>E-Ŋ ^,C DՍmy ?wgɄ >8 ol+�d5"$�U۝7wG"P[ʨ/xV#Ype~<DaG>2W~1+#c$(WYXY#MZNKL(:2ކO쿿�ig ^MMSOS*ϹhoOO0)�Nƭ kdvͧe^J>`O] x -<~fe%/ÿ5?tFrJTPW<y{uyPS,H~jZ5e~jP6�$[(ӈݫW Վ$DcU-e(fE=qEV/{yfJ"$ ՙig4#a VۈQ8* .7>("ht{wûGfeh@�т9G W9dEe77c bV"a<2UY` ]><%.jY8;OxH aw6? -uP u.e&,XBLאQ EJ!sND=Q_X*`֛aE"Qi4 1-j5M\=>Ҍ(ܘ+Pm>c!B CS F6'f +uΉSK8*Zd{cck6 rR= 7Vu<CTu夳ӡLd,,lD]GdxSfA7.xPfˏ]᭒ϡ_ 8N_n*PDc6/-($~ ȼm(3!Qj-!:(DH-*loo|OreI Y?Q} o*{zg糾X703TWbA9rg23|O68' xQ5kH.HF2X+XlF,KHˍSV4;*-_Zn>o rU Og$鎭O6zu{s i\k|uO[ FPwf% M7 ](5^w%n圼CT,yaBSD;uo̊V͏Iр헯?~K"2aW~r$ʚɪKP&>m|󚂌hp5qQD vr(sG(LGbD&̜! wG".3L/Scxuqzr|zvf`x2ɱWK_y^ψgU&b]e:aVTrQ7jۮMiF&_mlnpfOQJ| Tëۛ˳ˑaI^?{@:rp#Fb5Qq]?by䘶AI B~`6$x5}/ڷj$|݅~Dž~\bEb؜wp'ҟV 5�!fYqRK);"k pn2d~IBOZVҽл^mܹ͗<$`I圥dS/N0l˲Rؒ�xBBzJn=x�KCGqDy| <x݃ݗC_x݀8 у!ZY1#R:"ҐiEVٛ!?C0SUݷ!IҍW? x 9G;!7k^"H*݂Y3M MCzbJT ڵMMSUUfZ_.V/~V~|qhcc& tx>ن-pXyR§!w)|ZN"$u n)�ON6Pv#1/aMhsOX6>i1o⿟ɚ@ $Tg?Y%UtY}puzȷP 'XM*Ë͍O^QL[(a*DI9ϒD<xp.7 Gc *ރBY* ŮdDr#rQz xfa[wڒ yRTqOCzcX/+<|׏?FN=(BRd(q3NTpl׵mp8 x0HSWUGg}( h}\|sx{q#Z`6uu.[PpTNwq/=wxlG>n<1uG^A!Úf+ˑVh]Q~ OaceunCK\;@"uh×˻N3]x ,ږ%/g7w%QybrY"!|i F G#" 9jwovw �o1h$XݳV .&R>v�dExK}<hNVA&i Y`i9zus,sG~~wֹ<]{1s['P72Y;}X<&#a(hDQrF3�/aPo! "4BWH*< /ĐGuZ?iWo޼~vlm}zwM Җek uwQV PCx  xfK*ʬDxaIUhT^pfI/K·M(jH*/ώ}ŝツ?nINJ+(ؿr$`Ohx`'&NaL'N4FPA<+ɗQ@P򆞨'{7w[ΆHit:cq8&'PdٟXeQ c#̔8UM% yŀ wóu뫋V3ݨQ 6*=w}|\_dEÃSQ UYrxGc}g0qhU1qU~Qin4jPƭ\[on/.[PyQ"/q8S :a* W+S{C7 #xl˜5*WۡCrT27lt8k^_wc%x,/]0ވgBO1#"qLim^`ĉN5/E(Te7 ;lP!q[9>CIczEKNxtC!_STȰ hVDm^`@I ͩؽչb5ͧ{1x,4jlGv#ֺ3cI�4?M Iݨ�+G`(6G xv+.yV34Tӯ x.I숑V]WǞb?Ue\Z!#�H&ţTgGc^6\!^A[DCHOۈ$iLDMIhNR䁉]O43lx$*IkI&; ^rXĎpp<5!{DvqvU+!mEa\n3F]JjlȰ&-=֩Nhlu=(Oc�*U 5O-MH< 2�N- 맵qt= ,MGF U"F.L? ҎoP [C( /~E !1`H Dq`(7ipx1u?0bA8xptpbaXnj,urB)#b.FDPlơ* jYkĈv<*- +u `J^<>zO.YE J̇$L {ÖIw(dUȫ"d�Ş"MI^C|<ǪkOYfB^R! ("td0m_p]�>Q.&?: �΋t,%ye:CNr8r.擊đe�e-< p,a ^)x|Z2 (B$s4T؊!}O&t c  U _N+yjFUl<hZ&ˉ"�U@ Iryj7)@; 2T 9eaod8> 4@1ݑ$A./)k&Y8i=.@TEy |F>@"T }V ]Qey]^[4s!!wҖ˃Kڶ#W\dlr E0>Uf=Mde3S.~ 8[ >ҹeLIfzWv;*xkNge `.>#Ȁ@ : \z͗uOl]ULԔqg1m9Kp Qq|#]nv7_Xo'XWEN88JD֛fqO|F.-;]52sZ tˆ)D9IU!uU�=TE]_^y}*ƙ?m# (x̘6L;;CVP4+,nu9�G#jV\v" =[[1Bfw;,2.%$86+->lu2/ַ|& A>  O#P)i_΋ FW<* @an\&hnc+{BV.ab]|wk}^ <o/i@YA2Pd7u1|-l:A.]e/*lL0`csw/n7xA(K$9ILA [quNlMW3Ʃv9-l Fr45Y2/V<Ɠ([o66_)yFoulF|-b,c! ^U(ּmF+Oa5+/]}tvub>BHEs#Z!,b,?GcD8`_xb|i;$7/] S[}VX/\$Mb:OȤdBSC5j Xf׿غ ZՋ15 6LI/%xFО<U [ãd*r茩g! x@%=6rYXNoMnWNq}dž,CIwP[cqMjqs:Ê!相^De~�5:�l|<Bp WA5v/G_zP /kV ƒ!ї[ҰGN1cRĵoO{f ;(H+tvM]y�jJZ``LE:OF}!zJoB " E]3"]&ퟤjC *,V'~d1ԅ]KIH:Wf={qzc]dp%m9~e2 OUD0ὀUl:UԠRx^3B#ܧƠIM,|K%zيza_ZbF6rd ]^CB=>8)*'cS�~ᵸ~l@x_1f/_4z{#K jC5|^e64ooZV'yݦ 0؉j?Y<M6] X-| J(sM4ycc_x?�e HUdn� \AA3b$#IY='@*̮f⊴4iTGL]g.�4 ?7ً?/o0}3='8Z,&.P2K{`@D=Bt5 ;M J�a V2"3q!'n+hƋͣi+'`1oFpk�a3=YӞMs}OaOIV>¥.Bh2ؼ;rųOo71|$�L�,xbcvyMɫDzGG33߂e"vȃ*&󭑸tx&xanZm9mbf_{=R>#�H `]K8prτ*IL: ĶmM؂vԴH=e|{agsc[rn͛3b6-�\'YM(c9GgȢda ǔo>l&|u OTS_gNv_nl?2۲MܔJ'08+>`R5"<LsnZAf\7Xc3&2ѻvշ{<Ϝ/lk@,ƣnHs8^i݊}d򗝍Wm9(dZp]l}~^1 cW3LqW#N,'<ahzؾp -H6cy~B|q68)rj:6!gunVsR->2m|m.(fSӢ&BjNKF!TEeKu4KT2-F'8 `YVih9\>|zug8J6l+nݰ ֛ 5ohU2qg!Η q 4<<zxmfUϟV Y] 8 (Ԣٽ1&ޠxDnl`'WySIxqJ4k 0m` oL#WjvΆv5YN 'J)ftj8{O~_io u=3$BA28@ y$ i֩/]=Uc7|YU,�@)|4K8֬#}dN^}USU}z/Jt41Lգk5 "qt259dqǓD [$a?]%?zX`# ٵ$|m: 级B C�)!5 fP |U!<5xAo¯F&.?}A{X5b^:c;M boz˿G)X Hk6ƒiԸwz[aMʫ%iFF+l@~2<LM"=!,YN�7Ic)#㵂�DŽTlKrUÄԛ�pVl�eEYt`FVH fDP+rݻ]~DѼg3GUdCfm$]0;ПDEV9id2)۸8y͆D DrCf$%D3 Doh6eH )h͋]qdwQ n8kBah)g7XYq"" WqH)jԃ =}?>jzCf9ڴ57&%9{*#GWC5CX{m~W{NF㸴α䐠aO4=w:g:IMYދ͘(BSx-5F7%cJ.2 6A??Vv,tZΐ­x! dHi)Px,zo7zˆs6^=OȅJK(Xƚ77W'g'(y,3JTqEђ#MxD1JP~߇>{,OVA*#I 7ʦ+jÇ Rx<.t ;ҬMI齘7LFq۟P6E )E{ݟktDxa90-X8X>"0\04`fԗd:w L$'9Dl7ZTu0pI@%@8J'UGOw`2̸wҰ^dDg-=̋4 09U'F0D+ #&v\$2; zrM eۦGYA.lޱ:~)Z"q'n#Nj%stG^hޝ=F<q?l4h81!'0~#+S`Ƭ8Qh= ˫ΈF{^N< Z¼73Ru?b<#{b,cŁ^Z"u7xLG'7'_/7V|(`}5'. LY4=Ms@Tjj 3O죈e OrR,벚gCqeb]}}$͌p l~?!W&p-D( 5I/_v$ayu?ES V-C:qFSHNCmY)8˷J,U`C3yz35ڊ&-�0K,8%D^ %{ |,/,eOU_ܐq epud1 O^R)|O$4A_Wz��n>]$vHM-?-fM]Y!{֡9A6g[HD i7z8KQ_A- y,mGԭ Ϋ<atj:\ &8]V, *5Jo,:{=ʿD2pRTxu"N�'xم-K<=`5~T;$6Tn�%ٲ -R_.pq|FUY]^F$^hȎrPܮ ^KS會8Gш%= Q~շp2ޝp D +l2EAuxBB7PR= Y yj83iG!,6uԄҏ&{BI!0AviCV+Y,T!,2UB9 50D$pP҅UJh<l*؅+R4.@z1lO!8+Z.Ra;J"]nWJrqG j (]-]Oc&đPXܶϯq#ۯ6XCY"8dwk'ހ⍬)aHKص/CJ9\y<ۋӓWcQ5�k_|cLoT߈H *>Gc4/)eXL7zO-�J ṑkغ l.VAB,=Q4ɬY-bet}>!1Ot� q,WgKy~Z y wOQ`Ro31- 5pcP^ԫt/G,qS?+!^2Y>|[ Gs".`dـ' 0Zn\O WjY!SNsm&V[jWi}cSC o2+Ocgow3?ښS} "S{{4K?tXX* N֐Nmgk#-IeU'Жr8wۓy$1q~ۅ F. 1fHUAmA~K*loi2KȀ\~eDel2 ܨuA*< Ɯ4P࿡j_1:DTN%Qn0Doʨ>"$yO7#…FD!aF!GQJ{%x#m ҏb=0k@ѐ+cӞ?~~?~~?~~?~~?o _ȖŬM׶R=}6Ȥ%/C˚zC!$A^LzRаipf4)D<[ =UMg=(-[BFX0e|;[Ӣ4 MtզAmlX^R!(a D5;LIbAٿlxbgplYY蔳I`}~eb:+S1ôL}gOKئ?l~`_2Cƴ|jҨ^T-q2vMGaW1ً׊OKG ɤm`p/uM2ԅڿUL/\7[|m?G׀ܹ$ x"/el iI`&1W_PXhfe2ݾ؇{aAeh)<Pt=�S[7C0ݔsڄFzV~ԌcS8Шj/{ϟPOZG415'LBf;0�cU2͛"?i{aEY=4K(�yWZeYzwkZNټ\,gٹ) ZOICٰ}U"rM'h4E{g+*_E=V`[vè'JeCf8f%͎gyry訌WsdP-iZGm/#$yjQn9qǢfܯ éDX&lWt:tOeYEG(4zWY7_<ӟ*4uPٛ)RB42(L'@*Cq h=ap/5X8F55t#.3[Sgɭ[8/9gO8f8l?dOӜlڎ8d:#43i_0 ShclQ/+m:<fIg`7tjѼJ] � s]7QbJyzP-ʯK 2]4=/i NP\zQ),isN&C kj(Fמ*6Ũ+BhϪPcHS(\M"$ *1VE|?tX/B*"~PAv ipHQ$-e$\-4!Ǫ| )0rP6Ѩ](Ԩf.$̞xָ͢ҔUˇej*3.n$ZX'-^/WGEYDI׺s+;aQ!#4;h3~5 Lwcu6,7\au:Duj 2MC;=iȣw_pN yQE$G^8 Mn K6f4G^:Q(Q1n7QST r<,K4<:cx~\]hN)@ԛA E] ]cqh{iBSxи. iThbcЅj?2XB)Iw~"PG]YHISH3O,IԂr:]L"3-Aql~.Sp$U' mCI GPfgV f +3n ϛV2$ Uҳ7A9IsjD"tn0T4u(i$Ewb y�5'є8=aSTIEIz�6o"24'j;"ل+ye2Yf<1;tJVSbR 6ao]κ6X2l',A <O$0"+d\'(Z! ڝ^0>e$Ϣ +^M+wyOY?/ 0UU Y$HT0,tdLCzQ9zx|:~;kbi W8 ?nXQ0 Yn݊)E"BS4Uc{7}eU]hWL�ip>N[~<3qbiK�x>oؘ;bG PD.A[xw//.~X@1$e'*x􇒪0~G*4M0aUEn0�)D |ׂOaueω" /OoNhݱ=<0ϖ6EQYcFw]AT4) 崍xm^qZ EFy,Pyw1MuήRv/oZ_* R.ḨXt]w49f̲,:vniAVV7P?E#f\ލXc1tݺn 4[AnE 9diG.S'7w?jmJ>APܲ-tp`3ƳD:suu}{{7U&`'9D]&i軎Rݪ8<> = zŬ !A<II7 s!KuN@Rty"iTĀQ7']аg\K+Ty x'5J�jD�NGd.05UJX/fSA݂ϑ bșS5d~Q"*jڋoK"Έ" }XTL?5}b9穻=I5/DX;C=#j ?0,=ᙛ!_=u˶K"3x L1üFm $OqĮ 6Rg-%+&ŬF:Tn pFDhA Z,=SCmDAdf ;j`E:zg=^u{eTE=:<brÚȌU sCh^Ky *%)f2 UF<=ɛ-¬(j� `z&×5;$Q׭VeOzs1B]cq{~\<�A5-`ѣP+r ao^$( oqA𚓹7 4Yf霃TYO!\D"߱QKU%Eb>Wx)TI<=d5}5F:IP$⌀&KQxˏQPE\ ?lϩ1Qth"F ]# ,lEj+ϓ_y VEP0BfPI2R{"hN'G"Ha4<'(JwвB2 -iWf^)8y[&RC5Ia#\EHǏD1I]E@l}e oRBrF :Fam"1Ͳz^R/O/l弌g?{#ԁ3jAxQe"մ| :D ezxwۧǟZ'q#ⵓ)b%GO`4^vh¸.YG֌GWƃ-V(ADBWue]?1}XܨGw?.\U:TQ Cj$Z*(�k�&1|9Ia;s$="Oz@T {/_]%hB\HzL,fW@W,F`'6~ rR4eDi sJE3GTFP^ĀU7;[G9%TM u?zz}ey-&MDpU=|]Dؑ`4;P(�'2yyR5n-Da�(ВE«>۝;/`ۆ*7[[;;o/F4ĨrVLO "gDY|9/-*<<Y4TSc ^VOBRx/_ cI'+ׯ6w>4wWnۊrTKltGp,1颟C,ks"_bXe}y+:)3-weƇ6Kd&|Ys^nշw.%5f m9b�3 (g_Vг3wvCՖX,ԩ*?6J, H@&` tx`xY',uNY¸p_ilBR8-~}ME XؾdnKe.B z@vO\  ]\\߱,HI2hHW;!.E4ڒXcW[+fLDom _'$2)"<4?2uFS6-\l& }Sq-˵ͷoO)4>�˗6ɝLƘMSۭxDOݰ>|6� npLtpZ̘#r17#pQsWWWg $#qYv|;[He0 &%Yk{ľ @JeIDN)Y*ϒu\Hcy~y&G?Vo...q/-޿}s}"64^V$(M @YI$*]RtckcsSm46zZ*u[8IQZ,$@$͊Ihʒw%YG3t]pr�.aZ4(wM3sskstagdc\uD2f O97&1Ҋ{Vɶ96-r"uuuIEYEZUU*[E0ȾnpiO(L1W!F= C'a!Hq 4*(Z'% O "be>z!q-nssDdFMP<&�4Mr4ܨ6Ъ\:q Fk=2EeyP.�7ZƲSˇ  u+(A�ַABOO1Ҍe5YU3>;v؜l{K$/n]6A0 vMeIL] 8Fި=^4|A51-K[[۟@@~S1EcY'v۷[om lz2=ȪNH= <S]Fnt CGhB@i./G_.< @ji�Jn_yHHy^@+jrEԗ~|:;;!,|raC{Cԃ4gg{C.b:lwF n^rkڲ;V{xwsuy7Qi^�Ttep|JU (W7_}9}=p1g4M/ooFG[{gw-IYvj9ƽS 1:XWYECM` ?LX�|ן.?ۧrLG|Et]4]K?\^^Vzwᒅmck%|Ӫn"O.{ X "w'7<z4Ss!0b*W7W燻{W>kFwe@ ׬j8 @6-,)2T\ruvtpJ/t:}n}rqg͓zj޷-CrˣNy\VʗKR"V SzXL7tngy#p("x fީ|hWoTv?|$ݝ%yݺx[1E@߽;OKu�dK� ]Op �ʘ Bco4@k`7vaM9gi|vUiԮ\r̀(cHK18rIMAtw2<Fn@.vIaNn+676ַ.}n_lR:=UNNOgG4'0.)An-h-aL"ڝ@wba=F L:PCY_~èߨUۏ)3b:p&%n}=WE3,:lb؟xM _v)̋!;O3MvTٸbiuן;SW%3C@`X9#霤ھoK)7Z?0bQ% hNGȶڂeWD�΢q<,!c{V;n@wpuwSiS`3jG<w.gӐո"KQ"2SLǡƱD)𭇾d"\h�m"CnkF}j|xw2:g{zpב° T?4?+wC^m9dNrljS1*,$a VN'0yD2kVD]<nV4?І(EJ*Mˌhbw^#,`"YaQX\ aZҼ|4l@W NV`?rt=Qwvc#�[aJH(U0&cNsG2ElȲl\l1VM8Ls\ҬIЩdLaɡ(�,|UABuEu Iy@v=\/c<V<bU9~`M[\CW $KFASŴۜ(qbB+Q8r,Mgv~nS4h�K&2at'7]7 0ud+D&4xG1m0X[BJک:=(q6XW} D&mTfEh*"{sTyn;b`:[Dۦ�p^[m0`#N)cXnaU7j_N�Z}A Z4A}鼠%…L*R)v (J1.iqqƋ6)u oq=d{:ۛ˛JOl%Z٣Ap#Ѹ^⦼dgyz6�%d06mRbZ Iy2n.uz"~{L}5uϯn.tuS[RLK:js^p2RDw$3VN7 /d J7|ZD22 QƱt㢢ZóvNѩvj@bay"j1-n\`q8 Ř?ŷKymQMA9>gn=n Ɗ]YdGv;C7ϯn닝wYAIie$�aBknxaq E[({J5Eqsq[+\̢c�b1�FU8W~?:;iO|k>yh,kBfO'@OOdQpVn}.7/[3pqKpY9=nOoԇbTU[6R+^1<bi5}SY+Y:B#PCNƥ4\8|xw㽓'WWVtw0GD#,0q>EŲֈzM' Ny@2T`h\&e ++\\KvnvWWWfck _8 YUɀOn1YVeU^sAɴ u'/$�'l 4G=\=<}]fmmuummcWɚbȒD&I} k*HO"4PsD텓m7KO'GpiZR,*p~uW Na~Tn|<5nIV l%pQ�).?²`5�Q8WD!pL`+Jfq@iyv_Y6um} axQa VKq'3GH*W413<Ba`.(tџ]G8aO7(k^MWb"wHx:!pqm蒧f4}90 )<N"_$$|[( .6 _GQ>e*7L !Qw$)Yo,H|Rv(N�4Q-exw]Pdg@!]}s&)c wI؇i hx7#֨L׌I` 1y'$#AVvЦisL, v"s_Õ<_7C8Z.CbΚx 1#<et<2 CV ]OzpIѼl%ˠA{Ӵ?|'ⱶq5|K(#0FeaJl,|GdH6$IM9#<cZpk xDpom^][o$v�DH� I&~eJ;%E`hnIZv`5s&-J&/ lgEk탺}38QeN'DL /I<Ӯ lZSMsPz]ZyK+y�nj}gf k<)Erw-H7GM}#h,bԀQ[{q<(Bg.мyF|uujV TuE7(*OuUofZM6g@EU7 -)^n-m0�;&JIaYIΰqBQns0;"7`V=}ⴆVhn8wiPlBJlV"mml�[:}a;(?BM !q y5Հ_9 h+>N�L>o�ѫk;~Gx2DM_,$lƛXJ޷ytL{Ca;%F91_e*R4FBjm#׷;kٱ/v?X_{wbDU5 -{ޜ쩬"vqFfܥ%irEI yqh(ar�떌Ӥy}+ʪe) }&kIU- ]kk75:0I`@;edͤ,-2l] =xۻ`�İvo9('@ģuO ذ [oZ$ 9Cbm-r`U+:f競h'v4Pw_ޮo5r<ʒ GH.Iٖe3Xxb="v;-.<?J`ܽDŽ=c'6(T.(̟Qg~&EcEdsE{˨bHXǥ(n4 DL//I76׷jN*}AR^}{́?{yyF8!QSفM:gOfzVmH]QDKf0+Ǽryyg{skKSO0L\nIG[> ɳoC3~*BX[a5ÒYݡy'RH t]m;hY9 cuYYu<U\18̾)W%MWvy=,rrz/D3b ۃ }Ǽ, zN ƓɂG28kkOmԪl5%sNz%ן??~ӸlQ&N8lQ¶|yeE(�.xXg`1a#'E.�| l,2N/ŬU?MM7 k_\^rdR+U$*#NH2d0Dw�/D, 4; ,U`8#kNmH=` B.3:J o5S2L@96GYEo ){ֱdLѱ%˖`DdbaAjlq%_x& E.+h6f$5:%϶4owwct{<}y)oS1O; L+VK'uHWa\{mjhorEzS[C>h%҆!y!M 5;_xaĪ.<ݽݻ{Nf)sͅ@Lh,<?|ٚ$L&#Y fW2R5 F/F;2OzLYgL8O6.>-MV)HX_ mtxIQ01Q d J'2hׅtL'�/aS'Is /_!K aЅ>ib@RGIaֳM\XlCDjbW;~_CdrD)f~<5 QphYFY="WW$,]'aFp$ 6O 뉰O^iKk)D�C2g_.\EUɦ?|b`VM@d(L h9ásZH 4/f9@GpqY鲊!ch˛15iFgD#F…ݛ~ohxXC)gX9BF 7+-#ƺ1ap@KAVc^sb$ҽ~׸P}NdP-CI(Χ"[1GfRf/c"vQowTpG_K{CL2vێ=Pwnާx~\w:@1uEYUQ;JA<MbSg:A=X82zyHJYxߩ7zrX<IXn4~" R) `+ .{B&h"#%@oԩ>k=`(;]g=FQ�` |:_Hti֞'OߑRzi֪w6=d#.C4&+\{!bUČGSt-1BaXcOnѪT652| s ?=;")UFGn6�큛襄hJ-+C4u S]5>(N]H'EFG!ahN<[Q4'_2|E%$ ob:OG/fK X#%ޯ/߮bqtCsCĥi*{~4ϋe g /WaptJ("7??<6@ \^R1U~Уy ؖ~Tr˶cN@<eK\G03_:wuDZ}D@'y:pe~Is,2h'i^ӟ [bqV;�UiT`~rx|]D )J:|C)Hl,<u�lѓ'ƹψuȐ';_W<ׯ!3.Vϛ@1v` M� i\cWӉOk88p xqh `fF6FwR$i}+`�>DSB4dy 6bEŊqc`'RYAOpϧXQk; \0$'ipLg w[>c?h�֚Od?U'b`QV++MBsFx= *P~垒FOsO}U{Y5) )N22t 9Wl3cR鞹Y0dPm mpU0pMKQj;L1H S+-7y�ytj�Y/`ߕ Q`z\dEI> Y{Uj Npo6{7EcM Ui=VhF#O_+`(ɨY@ ]9 %մ}2G\&ŭ<t{V1yJKP.cH˶/umDtpvZYQ5l7r_^fy<r]Gf ͈nAhVEbkYhP;GS4j 6G 2lzp9eNJnhp@:CE3,TJ3$)L*bQ8:Bb2w4 aѱ=bq v< pew<7r ʀu?%K 0.;j6НJC $#q4ZC V":c=QV,B6k=n%Y x<BEH筜8@JEhdbɀwdj<4F`r$}+MBHطmdp0YA 8?$[0*'YV` |lKL@n|ex D7zT// ~|VD1aG}'ܐR�5(ӓtQ8tӓ nE(e9x>qހe :Wg:8\6Z p=vӼ #L+llKs$z9 |ېPw=2f6nY=5 2=Lܨӗ ~;4A[e)X\gz fy3WiIsKsN_IHf:8Fp?s{; Q2__ G ;p_c^lUK{4AwN4_c)3`kdz^y=z^y=z^y=z^y=z K/Or-V\wL&qzBЎ9wY_YS+54uqvhi$,01riIdfč urg9W9}ˏГy=FWG+'Ip~0cadkʭrwuYm?&cNuuND45Qq8P9=*BiXE)n)EdN27$^Oj`.7Z[$3A .*=rd۸7/?+c ] Q|�Ka~#FqنbDdbWe [t_PSb'#]7-7TdǞ|c'Y8BfŎtW(YW:o c[)b۔ڏBVD,6ŋǤyk OU!Ȇe1BI3m74< lS >LMCLBtdX,\]3(Dݧje@4`g#d["b)zz=z@ ϧY0 b>O#{wۑ Ijk`f3n2O6O V8),>d)w6?\QOp]ήfYbB/*/PT;LrOd;,G8da;4{޶ o\[QV,QDD$%_S|3=}u-߶EprzWpr9ϓ$_̫*h̋L%`|z45f$͘EHqDӉi% w q1;eQ-m% q[ΈP'p4WƚIL5T3̵0G2M4cKQtn ٬DxEĵDZdEj ,h5eԤYSB49D.yTa4ǜ0'4GxY%b"N;*xKDX`I㶠ERfYIbH!~ ۭv eyYY s5eFrКzqZsR%zsU͐{ <v-?=6(|X":= c1qT}ĿYίt7J&5/)թEG<gdE�{p7D+��Ahq뺡CugOo@ҽ 6RWb+``#Ӛ(u5yM] 4r<G32xϙ'[3O Pٺƴ|>#e9Ek(׶#\ fJު<>rKXziBn8ͳ.3#^j`q5e;ʽsښY1XAέ22LJX~EGe"/JBl"F(R dh,srC>55cYL!*jJ{BhIQc t_+4t՞ Lw4BTf.k/mIY2q<\>SUӆ'Ƃ'<{ZTDЅA`A1 t^ǟ2 %G9&OK@9~_U!f|}6dH3&�y <4Mqij ehe#J2DF*1Eb (M R* 6ˊ,qԈ+& O$�J,E*'> =KA4AmÇ=]5^<5$ /#YTFcV2ij%"ͦYhԘQTLC|9TJ9dɟO*xG,Kb*=gdudndazkX0-'4tn:7 ؐa;:9y*B:x ȇl/ fMUEfٛΖ+8`1%C]@SxLwON.:TK[ꍡAӫ%'[R~#:ԄEdJܐZ4AG2C܁RUAJMyGj&[ϳ̪:#5S�(T3v̗H"]()0s9A描ȃA`E dfw=GCђ[C�7 $y&bh5;У]`xIsF]VO(4"_MLl_R |r4USbf%�# pso~V$3b8'DMx<ߧ?HeyZ׆usrǂyy1 PRT+P'- p,KS^q^+ˠn:q&^ Fd& !WޘaF 'ʢȁ$/4Ya1U9.ck4Ljĸh(kN@@ ~$P9j@aik :n/-FP v Dj:H&oKP*&�/ DŽ3(۹p[îPsJFZ6xJb#:< 0Hhq|{P4oN@ 9_v@<0I"SkǼhzOtzA掅AhTLH3K>K"7ƒ$.rO :Wg7}H$4;.0~\  tP7Oó1hm^_69de3]DE."y>Ϣ1~G`3^{IĎ닻 ɪ%H]`$#eAQL?rD]}$Aս8ɪ(f',SdYEg)5q`{BD4i ! >+BԎC[_4 ѺG7X1SZ$0K /!YP;p& ,=fթ* | 2YOtЎRQvrrR'#ֹNhARuC7c,GM'|5O)R߱eAyM9r�dkdgQ e}[D+X"MˣB ?eT~9GJ,߆� {CޘDp, Y樒dƐd їǔP#B*N5n,:#*$!eV @^e@ yh=H Q!6T͈nQHI\$D7@X =Mzx"t^AH{EN2eR6Q|, l!p!-i"oYH*QU/ ogGxDt,ēqPP\MbȃrP-HKmhBw(<Vb"&VbDUm?#7eD2 �2Xi}w8iso�&.9c*C!Y> uF>>)}Q~H?-2 5H3bBGI|/wAKf"'fq  }Q$ohxփ t$|f/0Aczr}a}aAc\bgdҗ DXNRM/% Ef!J|H^͋weo٬Ԁe>^mAWVd4,_L3)01B{`9GI 4Uc!+!3S&}f.ƇmeW fMvrrCޫ �^퐭VP-"./H³)Ț?-i@Y/ y\M0D Fy9n<E N\nml }B)7%z1f쑰/8N"r UUMvk+)5{|a^.j&j흝S{N v77?],˛Ӛ<c#9+'^0P."AVxc0JHeDM3I" DL:;[[[9HmUM]d[nPIBq:vP?1{vLAm&:diڐ+jENYw{sckHtñ$BUCE#ϧcBMX2琤4xD~/njzS`. y2mmmlll]s,3Gcv|i{8knF&H9yu,*'&4A+<Cv?2H٥YfA/Y wX֜_u._`59#Z֛[[[;fVvA:P88D&>9~o@M+AM$ryM~] |5Qa BoWWNOcNqRZ,ـƫW-:!T,gsBIs dS=۶,?^)}_Folmo7cBi\WEfvn//G6R q~,<GB.rB\6oj{4}L(R6-I%py  rPd@]}wyӺNVY g:|bE(aXRԻi{dy40gzjZ&4J 6,bc Eɦؠ)3JvB/C'z=ĕt[ lmno 1| ?,6擉I@?%4x$S'epƛ{gBaVh"g6?Aהҋ"nzFOl^ ry.vCdza1Ku 8( Nڛkk[t\ynU9ȎrBawVauZ: AV5 -@qk 9Q~5un;2$ DzH !,| Y*Hȇ2KReEU(U@kNvcG^Ik &? R*n5ėk d,?@_2[6cF7R_)i;c! hVF#[xq퍍29oԍDc)k 9H3h.>վ8vqۢXx3<1E2 qmxnomW1RۭolV?YK|SQʴFؚ2@QSnjA<B1$~n %Y][__{Ӈ 25~WfJLJvv?3g[aќx\ˏ{7'_>~> #\03Ȍ#F$t.){ś<<tiOwzDJTcJXvpxqcw0}@*/EٜgӨmz~A ,Y$QdHUYaZ'=mOf{oTM$ɈI%1栄=q4qtuA*S%LM)S^?l<sh}\Y"~qۗlY7o빔c. ,O"x,>~=z zMǖ Tx3f9Qw<l$^‚;,;*yMZ&| }/kk~;rmeχ_?w.?o"O Gӽc#{PԹk.t}}TKYMWW/-#;,y4\m|}p}`a3v6`m᧏WIA=<+cc|seס(" 'VoNy.8ʒP"-p DvYrÛb:~Npss;/N^]ne(L _߾@:b&8,~�?[ϭi 7YcJP�t:98}|Mr6vެol]˻Exrbh:8UËYze褢ƩU")"x&i^$@|IهwW=oX$woOwNhkT* Yԡ`LA" =*Ŵ5zSWK:#K8;Hsؔl%P{%acoT{~'_ۆBGbKc bcJwq&XrB(?l b&r^&iGt)$;NWIboëjA֗cJH|>&LJp U ObQW `R2-U4n4/)ag(C[lRaI^j)5/Znu{fou Y@ݿ=xZ0iV`r1 _sB8_.ДöQ!<:Ȼ!97ე1![9i: 1yQn/ZNrZ_"]~O5Cn 9f-2jA@-):UD jt{2ƶVt l�ϊւ1f́&*|k\;w7ϯo;9d$tu[�}> rOYEy滄jFFjuEƴ;  ;44%A\5统jtdF·&<߄D)DalzI'/ypgz5Eü,krk(h6n$?�;8a8=A=f\o__lnn(E;2%u!'*#U>+q=E<2)̘58$Fcѹkdo(7͝#F5b yܠJ ʙĐvt3Ux Uz< Q;^I`C !C}پ8ݿ=) Gv͛cFѣ (` v9@*C�{N@SCao,k< (zqJƆ$̐ .F5 5ڍo_wO o67ٌ~,;%=<PY i6r g'|d=^V@h&xı4$;x7}A\~~usy{(%w[_kN6)6r%eXd 3DWK¹Ϡ!HdG0i4z*@ڀIvQ=Q&ÛOպ}?ʌCK #y]YX%BBD/pCmʶ><]UF xpufqsvqNON1)!LIvaZT"|nD4 мN)N,`4)iE Oޭ^]{}eTo@ VTt 3H%W"KcB`'YUϑ@ڀso욎Upቄyݐ% cɈ^9yܨпtÛ7oQ 6 ]TUf3=y+%FT`x&̾(YgR,Ix{=MB`އ7o^;6^ʼnUF>j,9TydPUٖw2L2@Tgᔕes#ռu^*IMCDyBYM�VZ�/6<1N;馉Y| HT|>L{hs<O$7U )Gy%l}}{gvShPkkCl*s3<!'^a铑9@᫶͋ڤG܋C]f Q'E8H qFv q@#X;JIO%/z?cS /:,QA�~]шʉ6}a3@0�Ծ !& ^Wffd~  3E}_7a>Sߒ /A!M1x\BqrP:H'i3@_{zmt,b߰ :s2uQ2E?p5RG$>%{r{8MSFx^^;e$IÚLNW9I%�ښ4~j u?XԬ|e8M"*6PQ$/py*67O LoN.u73ӂ\_ A5plCx5^MW2%U46!z)8>\[f}ppz?H0M#�qgD99y"0#k^h2VbEA1+$z] LC#Q=xm+$W.p# *FHĪynܩ Gh@ fJlZ7Mce];1[BOdqAbb\}kCe[cKE]j$ 2DHHMJbwV7l\ɝM(�`_o: ȡ?5G^K >?9iт(~^F#1,˩~I|55χcƝރXG4ݷkl~i2xy}}�*pV{@6QYṾ43l2uFM0ƍ1MCuql"a_̐ISg;Ò^;{MiYNR'0,4UE ۽K6Ƞ0ܝ|~z (2nFUSC3OTQAAiXg@_7j۩ 2^BH *mgx`\lػ ӞjmOUY'G'<ȈQ\[Y ss3,zim`&Ӳ\dg:?fej〵OeAy�Q{;뛟 zudqYO.Eе@Qуzvx 'v<kY^=<fnpf6!ZO#ncs5joIn$|[S$=Z� Vc1dx+sVù)*zN4TG;o68A\Fi`~?~c=I9b[ub#E}*eE\x}jN"k  ֶijO@#ݑc ]rhy7ZRVasHi o|strGI/ & "r s|?_l)xg?Y6c6;VNJU}3tȕރh٢Vo¸Sd:tx+tZ'Ȫ;|Az"SOv~Y>fC}up%h1/? %1ΪЂl%uYstxŗu�@ACvdrPx2.WJY}|rsjGEb dyyqmB/Cǧy^feK֌z( e j5}G4^9#FXu|?t eАFbj?qu*Xܑ|u 7 )b=:ȩbU/.S2?𞝂'O)9"'.w\ַ9Pg'2hТao(՘# ,7sDk~<Tö]wrA%j *.:}pm~=rt504Q5[ ^v GoAR4;;"mKb[?[zVeT:KO}>jsJP{Z5uK֏y4YfIA'l>{HSU Qdg[[%XlyɇZae"4vmJuOHΰ8$Fuhap0h^* op5!9YRݬZ=֖H_\U4D2"F16OPż"jU6Ip,}C~LXPCD�@ԙ?Qҧgt}84 ]1̐KIw؉%yx5Nxѯ:(0m^ Í^I]rdKcKeKa#c:Io{V7eșj-tGd^PE#*qO>,6 쬖Q۽Ec΃%>3TҖF5U+/ )hns鴞0(L0||oٓPW{Q뻯mDSȫ V*h+x";]2o\_~%C2M�EACk@Uh"qez4B[Q%VL6> "GuqUג4;Jdsf3C#~$͉̑X G Ūyf[c!Ty " /~4UМ۞뀴8>J9$aWC'˜j ^5e7Γv}?%ꦁs(x.iձ}Age`лҢF,r = )ZKkk\U6-&e@\"~B=8s҄48$co^CQ'Eaͬ$$$B:(H�^jM%QG]jD@l ~ҟ!taR&ڠ&~it)SUWA"+^gEDm #, [<Ax$>k8A>M "6Ga5bX%xG@Eq4ؖcWQ)YuM7L/?W#yA1i, ;a$ ׺\=P=5 Q5E~9`"l$D"IBą,0c\U8Cݟ^6zJY48L48A&A^HCVIVZg<aY Iӣ1KV"C> 'EYңa@� T^ onE3�T0P#>!QQg�0/gKd B Nv(Q]ٓpVcш]~| F?I*O9`c鷛hNr?=B]f;͉KC2`*)8 J6&~'7i;i ake;Q$y3AᇺYKr\(-H`зwc͘ߞpڞtNjt~[ o/c.Y :~x\dnAUa$#me@ӂ}?LgUi,*dxDLJ|i"?o =MZ!k`~Y4t<'s"F; 9ATlEiV27̗tq [^wΏO/z˲N?>gRKf<>fȂN\Cr6 -4t @ĽIB!CpeD&g˪Hly3B˰\3e%6ZCP,p z di`;tI b OߵN8c:@9~E!S\vEo~NlW9E)=ev Pq3:'L`=4(N{IBi|yJ_b$\kꆣp^U_E<$´"5 IcP%iu0,a)0$-fRr7pK|/WZ՚B9b6JҙDy)e)4|LfQgj0y.W- /+p0YPoZ۟) ]p} y?趚UzʁԚu^5D]xz(4!`M~54A ;}"V�/WMњ2P ^߭&oA p#D@9kxu`֫$`/ˢK8R{^)dLXKTRh=Na>BERЅrZh<^sX1H$q,< Fgu�~M]M`xYR0h?xMJP2 <fb lE: ^|=`%pj9?EfDxҭGW$ ' DfP馧iAf^&]v; FBH []P(lZr:#m/Z2Kf3�p#Eb҆A$YpT2W}�2 <A>P{4ǍH{MX=J'3:Bv=NQ<^7.P&iv qV" P< $ ST8o>rZ&?uK0l?N8u @EgpAyi:؎eAEkԹQ눥in2_Sb{|@-P!&Dhs2M] CiP!Kzp/aNjQpMYű޶-AѡX&/}Esm~~~~~~~~z1M{ߺ:)9ZS^Q3q;]~bt1%q"UXdk1͆PPCj+n9,&:##q` оMӶTq—f1+ZPTv'~~poߞ'(KBϖKn=ghvmzIQF:XYb=vwu,/Ϊ7xF2]_a'A r_aTߧXizuP7.'q$ 'hrW\Wc'̫e;;W*s /γLۗ=d` rxTիWCxynP< Ҏe埮CBqWp̶鳶2f;}PDp0#]OVOo_Cy.^0T':Iz^5dRϴLE?FwXZq KL@৉#Vj#ڊˆ &q5/ ΐa>/`=J2h?Ynuwđ2ɫ}3NB`իs|bYUM,?gO2ȮDHYj݁ fi8!UGx ]ҪE`*[v떛3KQ󹮟(Q !ǔ e*DCl- 16l0YN4[.U sg6ɆcPX>1vX<.#C`3F"i `g `x'ME eA"?5Rr`q4EyYՃMU/#̈_i $J"V')!fp:<Geo !iGbEj̈޻<>"GUDP1,tr ߾|uXx#/adsPr;k,2_EhUa|wtxA> I} ERdw1 բ* mϦ-aEf=Km_. BbLgy6/?7":+ fđ,N IuB _),yff T3PRqxy ga\ )!B|G6> 5<9W p-UŪ,1brBSyl+w;.~QKMTԳ5GcnZL{E`ЍlYA³L|bDuU[ ݌5`uMXiev4X͗1cWOCCVv*BFACx H\O=MDÄ9"A5P47Idj@xH)-B;3n۹?5n_qB^P 1u ؄G/)f*I["\Xht^L}vݽ;ގ8^\3SmQK!Bߐ#n:MCpEMvBoFF�$1vmc%;G4L+DqlVLdUMhLCS^t;cnI#<֔\m̰GSLWăgiB)x!(C{<T 7QhRgyU"j4ؖxR_ t L)fB, $mQ@xfY4?Ü :vVþOKbZJt7!m/%ze#!5Ad0XA҃<|X.VxC4r`$]_ 2czmLWp2䂙W؉E@1-,<xIudnHy3*N`CO40HKU|{A-4Ƕ8#"H5rNv!g&e`A: I8NjEEXREjć""M/ί_O3#͒`<Dm(<GT\H 6vUG n8/G%bp8D p&%@HQoggMNgTxոm  fe՚H24W@E[}>/Ȯ9ݢ3DoWc<u}qysL%b9l 5.-H8C( tR"8tl< h%AVE9\wwް}q^mE! .n²L#~+C( FoN#+a{qtE`i jGv}0Jӭ˲t:.K8j6{4>HwyzZlP /E'n㗀8QF&'@/dD@Ng4MPif!1{FPF= (HG9Oe_B"aW7d8bqkv D#A !-O}*Z#9o$ޔ\o p7"9WWCr�tVVdĉsڲ!p{eEQh}nbG3Y, �$Q>PcG !ux)/,? pv>Ђ,4ä}(MK'DybI?}ʲ,T�@NTG[0N7@8@̑! ̠ӣ29L}}Y5L<y�G$^Xh곢@& ;O?}lßˑQduVtN_(ȞPxdr 5hd ,ZӬa ZF"O° 0(.x?v k8nPkHᘘQ !,q6-9<xdz7G N4-v}{~|RcpC^4SY9Tx4<X>/`nxȐ~ B % $Mf6h3T:D$o_Ң$Pfn{^2}ߖD{^ Pz65O!JCbȔ~uT'Ah0f LԸsIa�Hmۢ�fYhI,f-'Y8z_>^>t)VGHq3yzzb 6lAE8Nf:meqVBhi% Dd h,<0<u~񊑌8/} LP` %�MO\e2gD}tڐ_i0!&X+3`xV)AAU thZi./JH bKۗ-[Մ�"*fS;$$]V> h8|2i:_RRi)If77h;ݻ{)QqF[Xִr/&a(G`#֓C6–wBiUقhb($7Q<e׸[n~ꃋb CR;;}3\SCm?|�Vb*okK\NCBgD`\N*ae%>a&un,]#*$rb"RJfODS,uys{0%^z<xQQu)a- )zA:&lDPF(N?h�VV.T*�4Yab1—9[WEJ9YH̠=ZP"YI1"+G/"Ajo.;ހ5R "D6+1اjʍC;lv :f;r�ax"qpfPɔ(JraN.}g(pd}+"Jqu%`�\y !V2�y1+б tВ4mR?}}g"e] cjuxlVp+Tg?07 {cyGV ['qGqAq[Cinnd,\w8<_AvREzE{:g^ $N bOwZߡE3�熣TB񴬤 Ϫ=Ov/yI#!9oo:#N3<Z #ࠓ"Mea#P ;�%pnXmYNT lgd`c,^Id�d4]?:l|B*1& qo-U.:R:^IZz�/ad�tBTM>-‚d�mY?%15u!99:y^FGDhPR0jz&uUg1+&t)T~kI[ŸrElo?_|~sk$lc C('~ځGtfxX NKA۲"<V' ؑ*y~zUM IY y)y{{ȘJc0//N m3d{{gg̟Ol)\H P+,muuVV (Ό?JRj\Sp鶷kɤ.�˛8Ͻ;xݝSoY? SrM yY@vODZ2I(sTHѣdͭ-=+VeUk4Z$;gdBtpUx!. KcZ�E0UE>6!fn}ik$ L&}QRyrfCJ0pe.o\SL4/ؖ+x8Wf`Y<}w�i2 w7j9(ˉ'# 7a*ۻok_IQT$ڗ0%XWʹ,"Gܘژ)DyvZY؎z[v``WN4HaiKLbDƺ äwDs0Õ�0i+kJSף6Ql7.j ^Q5׷677 rYŷβ Mp5{_H>'IBS0a:IMsy%[V' e%!lmolnn|TɜWan7}T¨d 5�}V8AC|`eMWcPHOkpTEY)(G"mX9׋ꈜ_\RǯvТww]" Lv@11\5fj[;"X1=d}}"ۣ!.f┒̯Bonleo`9ΛIVEo$=C]_]\{0ie^uf`^,<>J0*ˑܸ[)DεMrlh{ ,{H ͊}CvwN\9uds_ w1&&36 "niolyu!h;$ [ż~+=,ED^Ԭ`:zu4V8j lV⛊S`Fsupcs஝,NSئO&sq.W7nQDsbQ`+" Ӥ^Ǿ<:RT?E%c,(GCCbp*<84ݍ͍7޽}׊T'<v,h|nwg5Fd:ƃw;�2As0U9dteE6NĢRyp�TETBI8A? 7NIFã׻`ԯ[T'zkCx^vt什Lmg:6MVCy]Uu=--$D&xP8 Ƿ`oyoG9޽ ~~{kCz"WYC_fEp*Xղ6 v:+A8uz-4 O^]H?|ݧw[[0^I2Wf }&Un^JgedaӋ¤aA$ ]uzy[.^>/?Ÿw/|"]dh<_YD ͋ 9{,MY B[P*(0_DeQEPQu8ؑbk`7{kGOGngP=rz~n{k㰫>)dgIsBTΰcI uTzsuhC>I@DBSD=$Mx`,y?lxXj[W4E;ĦN_ːg0Jqy' 2wEny˃w.O[wM`-BNw \Z_9=<|~sx܇f}js}AG++%<IBUd `x d'(xiԾyrWBۤ3c0mQ 1ib-[W7o>GHVxv/I6/6R2Q~,Ş9H@-*I쨲fZ:�XHEYN.0dΫ aR80ebo=ͤg7[|NYO҄Ls)2^QVl(<G3*!(Țb ɔ X>c5݌0!HUۃ͗}x9z}>ӳͽDo!5ueX>$/PvPDy5L2!l� D+]4ZGDwuFiH\/Jb_z{ra_=�0B$yDž +VbѵJ&pt3j2gv&bIY*D�WYN”IGIbl˽˛Ooߟf mm>zUm]*)RO8FYؒZiN ZV,)HT}l4t*MMVB>HBKLz5Ā}|~}xr9q%j^͎18dpx+)qǴoO??BƵmYU JB1g<F!}ь)EoRF7doo\{ۣw|`l\Xa^V Dv�}r7%2WX]H+>0ӟwŽm` žb 𼒺Wg>zks}m%bkf$L"4k܊.T(!jU8N4' o>$NpQ GN*;AdDL'N.c˵56ɑ>(Zq� TVM/䎶Zg!A>EuşDNJGGGX8iQ>6ovx52i[!䛰5v X.+./Mj-DpvLTvor3Ή$e`tڇ77Q}c Xƛ:&N+ k9:9öpuJ*� RO]$ְDɯ~`%B` Ó͍mK2,7C1%UL!gr5=bׇ|مp5&=3r0> VwAF`nmc{g{ ܽuڷIS"?#UULL`KLKaby$9F/ j @P 5p]wϬ৬1yۺv]& ^ˆ{9zƲ5lKi>&jrHH" >xʊHԔQT` hȶ^' q"\G ycS0!Y 1J bUOM-$qtmyZUgӪY:%B$bYٵ?>W/7_6vYzU彂I޷w7%~X;*~G :uCpۓs*& %)HI`amYA\s~w'H`NUU`'I:94TDDЮʦh-U3̫嘎/A Jayaq�_Xs'ȊagdnuNF-{6Z,}\'-C_UUuf:$/ $2X6Ў77>+qoxR R/I:B%UQZ"]S[R) PVg /yՅ RG؄',oT=yCUr[2'MRs"nR9C߳-}uA*ߧ"o2%'ͫ+aX )yZ[˗oxI6 EB̚8R%ۇT@{hUL_,Y_psЄF:67`&NzTVM+&`2&S&g�co 21;u("գEp@ȧGeB|D,^߻WzGۛK48dqA?MyBlfrLu8T?@Jx4+Ij\24FhI<7w> ,4n;i~ o1%2߃[Z.LhM 45:|8ia[-&{x'M 6H0MoLF#EQ3SMUin5WW. ~,8{7_>AgbRAUWȦƖFPNe%Ŋ 4jQ'F-AƆV�H&2UYi'ljokT[퍍7Wn3š:9VW^!jc�<>4iR-Z=|-^PLq=˛UwV5i.h+歝ˮa kCwy{LN`IٴG3]_6B^]aE;NR߀Znh0*ΞX}\wӠb9ZӅ؄w/܇X^wMFT_b;wٶ[iAIbJ%/S*+G)ttgu׎tJnLΞ!rM<<ueH5 N#$PaZ:w0�O30>AֽqqbQ iFpR|1$t0C쀕Pw �T7l Jby㜴2x+|iockۜ1?ȫnj/Ogf&MK=_m_URfea,i.O?6vk//+DHiɼ7|{*Bl{U��ګ11Drժ:f#)}xx9`ֳI6Ҝ<K16FY4򑩈d5(^՜!蠪>B~/X"sǚc& d*eu|lͯc߂" N# u i9PNRnZ<-ӮiZxW$$,a͠cbYYVwI}8y&) Z0´qa%H.7XyZ"+)BH[MZTAըH6HM-R9dvjW4/]fsf"K'4L'QhD"r-,ULV  j'Xb"v1B�iZZ`_uz" N RF*Ti&<e<zG2Nb~#$}GҏjT�ly/Rϔw>EӍU[ɀL?Lr?R,B%<AUvB2R9kb6_ _M]Ui:'&s3I?J=oe)A~FQB'u&&XL Sфk[b0[iw(J^U�/D!Vx-*󘕁m?Bk* �}"ۿ*MMt:T1^ЍUUO�Dc^^ImY`{?z NiQן& 4_Tח2LU^f8X[2)6@nMUF A8+;ϫUvZާ!磐e /armR}H9zɪ0#y#y_J2A[+~^ZwjW@u}'P t2/q[L!y9 <sY9rMg|S;822'4я<)G&Kz݋Hw"),$:TG<c)P͉ C٪!oc[?^OR5)ק%9XN:]ʊRhʁ % ۚ*ۼвEiƏs#(c<H*ܖ^,X[yZ @hϭc:^X, xa:{ 5f%%眈8żK.7#^A}yxֆIGQrv1#*rYGqQybɢuon9vrAMѡvb9O\_\5:*K(ZN s1|Ga,/x*0j?|1ViUS~>=}ARLp5 MYx>oY' X;t,2mUdwyd3$,QpH@1f>H f54AEYBųI.&j8T!ѬN< I,1Ȅ Am\?Q@|Hgd%YbIh<cRḦ"qp4MӬay&s ,\%ۺQjШ5)Vl2'gc D^ŲݸL#b+5ZGE#CQ0uA1WDIHx~9`+Y q|%xEwHoPşc3kH4]Û(;Cd =UЩ�x$$]]_߷4A6!՞ɬ/�g" EV MOC[NV,dF1U[zBg)d$2Q`;?w)7%%A`%k=V3I 2$MUNr!Se"4><1xgLH_*44FR/`Hӯ_Eo\pB3<'Jq׼#cy=HizNx|IӸpH|M XA'{163ܖ85 X~ՁfXu$&E' L _6+릡(?}}l?IK$& BA1`tKO2v",pq-S~Niϧt$Y8|;γ"s'rڃA2x!KvWySаb2}UmtM;A*((A}IUG͇?jHbN垦|><OR'hا v��%DP{ /IMk'L |BdiYIu`܇7 iKzU5X_B˪f( ,Uȍ-N<Yz>*a8~psG9I0%D'A rr6R%,ſ) ]( <h\<uHa5�Vv~RRcS:7)i?%iHTV ӀSaNglX5u oC#%<sTkfӑc[lbÀb;Yڀht yjU~bWk)<xO,QӴWi80kaEih,'_CD v 똆;1Piԋxi׸o΄xOQg< tyAriڪ 9a3.l0^ҀK[/><4[}f:>+t}¼|r}VBM,/$Rb/J0 ^|wl1ǻ2S[xi$mYEoG p-I4IVdԠUxO+iy2 lXGl@wNKF%liWdA~/rB ^&aEG6=[Q~|v1m(<J)9 ~߾;zsqi`F件vkߎVLWpTeӧ?G[;zbyQsr,>^DbrpB/ڒ_3g6E`-$d 6ij)|I3M]i3F =*egeWlcܾx8 -elɽ�\|v^<.#MIyµ!xf zZ/s,*=U;(^m/q8">DfH]J)w"4ϱ>Tenq_ؗ 7`qQ![l5Vq Q#Gk*>c'QĖM !_fdd# ^/bY�Y!f,󙫈Է(I Ed 58z98<!sc hŮ ?@YK']-w~GG$Dx{<Ȋ/ +we6ad?/{{{{{{{{OOhcǀuDZm?m?Q<o=Li[ }W$'*&dh9C^*B ‘5Nj_LRGUL۶ekXECH>2Z/:0et2}^To!;Q1+Ftov/mQS5 2=ce6R٦zǶˎ7\U A/xrrN^xэ/kiw4Ji92u;bc&a6Wgɷ70NFdUtEZ]<O(E Y!еR4,XrRueo*W/TxTqJ!ƿMr iMZtwYA֒ K*ȔW%uiݜ!)饙 'ɭ3(LZGWlkCo4il OzS8:f0rmq\W dZǰ _ciA|>Ml/o8IǑ4_|~/?JdzU ~IѦRzy^4,A~6=Gt {4NM׃"5yݢR&ZQIsO_9X"jDISmք.CfX'1F87CF<jltoރ9rh858gcԿ _}Ks(,ԗ*<M@x}xxwa !˛%i+jP=&òtQ >&9|cy{}UGIs cRxc@6)'r&xtO/:XsOs4&~dE9*t>hɺ'鸨( 3#8ibx+kWe;[̧#Ї)ZE<M"!<9z!a\w."1Iw};,n} $ O}m8"V&x ffB2j>}0JBDӞbZP ӽgdOY.K׾5_ v‚“C}隖�%6~74s͛L_?(k6]{5 (GAC<~pwqyOmhْ{V%V-*@1Z8Ic+b#YxPQd $M�DD9/S[ۏAT1a| 2*X)52M XIh$ssaֲKFE6&*2D>x]ǷiVfiVR:é"-A%d7z>LBe0X^ B#3j2SZCt}]q0^v/`#+!rJBJ&-ds OQ7{bO32Ђ[WTN3~[~>t7- <!:$N>>H{6=?WBE{aBx"3.tM4rHMÙ==AG2I3<mi+bE7%݋<k%Jt<.J%G$4W'=pG9f3w�iܦ h^YsC6\0Nj( H`dqqB Xn>TtД:opT$(&H$,&v' V3bIhi.�[�#Y74}|'>waPk+nN=y2 C?Jv;$#J IL#'0L;}Z?"[G9a.C uMQ??(c18: r)Qs~҅$"@Nݚϐ~cKe 20j6ul$Ծ>9T'-t2hV\d'&> ?u̔IGI5 �5iA@zjܜy}X̗"u<E<sz;EA !99쓑,q</*P8/eeBBYCG9ߨ7 4,G7nZѻCmIj5VOOp ;,B*HHNQ1?1[á.0zҢ54s"1vw+p:M,nX7yQVu{x<g35 xTsWTȉ"+ou^7|`E#Xs8d7FM ܷ490l~�rqAAbRV*Rz%rtfEHqZ5FЇ�4T8ܐKh0EQ zS^}‰a:~FÌ1rR< uψ6oVFKy4Q9GCd'dG^b^A Ͼ) 6 M; ~аojgMSP@Ô�ؖiВ|"o?><<vXIrB'ɴ @I{=FTpsfnaҦ$[rz(bD(hPW͋R v}ߣ(C%SX4oO?}+ BOn ',q d qpv vue' )H=M'sTr HK37 ,5 $ia#]3h7lE#QSk|>RACm‘y",΂ LC!^0:c14kwx5\ &LE1RyOPp ׮>(@.N.YXjevH¾*3Yd6eH~dEَ,mi8RFwY5p+B|\ Xq 9)UxUqS7̞(3AsA71D o<I'IGX'% I9 A CuGw`FwdbCrCCp䨟 !0~o,e Q'jyc�= @ixLjwGGWHTE"So:2$EYCwQ2vc_Gc"Iw{=@0ÒfqgM8e3@,L3V4;[kEF$8Q.q "( 7kQ6 z@΢j nji^acX @-{f7O~h\CWrxiL>| F MQ2Wn M*uJh4 +т=S `ww=+7-/ӄiFD̽Ǯc<]i0m_GӜdw%MKo,%d4) nw hu֓eDXiL!HHp5$#b1yC{r@;ͩ&D sd.5+24YmDiJ*}A �!.Sߺ%`yhîyShDd!h#S」dy:>ݟuPza3!8_wKY9$Pru5Y68G7ڐf4UNLˎJ%_C(9v�ydBh3!&<SJwU E#,GwjWm*m`Gz+'8ҷ`\7!<7ol|F#Im{</$Ⱥ ,C=E?2^4K WG MʸͽfPD4r1%$IrViP peT)*�z-*3=6 H 'P {g8<ro7>~sj~yN&KqTiTIALIWU'wi8DbJ o/Ȭ~<>hIaD<=jfR:nD<*H* ct>/<me>d�)fXL:y>momm24xS珇!!(raҝLzH ZA%WS[Dvy~ruZ�[)XK%A0va'@Q, ct" avi^ч.D-H|g59$8ҧ+v?( Zgۛ[TwojwWwWL(rx+vRů�'dI#Kg +/}zmrл~#ngfOےgD7 oi?Yr۝ \97AqK^ > T>QGgb9q`xўجg]$`,v�wɰASnΐfXWg NoO=coܘ.վi霬j+Q+x{&yI6=/ܢ-WΡȊ6y7g(V3Fv0TG]<H;%bjFVzd)Kvwp�pzFGbDG 7dU\<:4G Zgh HJi½׀k]bBUցɄ/vY~cɓ^X{?/|HoCK |ܸjyA4cq][mogo4ȋa4# asT9>nIWQ:<lY ,PyzIc6ǯ}o"k,Kֻ[ 0&3,G>?d1{ur׻+;M y�='1=FVuaBPAS ۀ$pԵNmT!lyF0|K4pwxXO*㍮%nG7xfsz#&ogW7yz/m9 `L@gV$3vscn?' ;9?<x//~@k<Y{xӓo>}nZ%LqCK7StNSPV@ ij^mL'0zEA6@\yK?c%+xlgaQYZN8 5iLRDD$V34@@ނE`4 i25�no>5ܰ_D%`e;^@Pf*$N/{@ ԍ(N,%l;"VI!P7~g6^92x<u!(uS@ݓd,90ⴢ ԉNHJ8ƯQSjv<s+ xcShJ"XkI`)ľ�2M0fi ^Z8yIj  d#`:N({Ϟ^쩫(cZz7}8>8h.5�~304д,˅{ıX \9g4Y\{ ;^>;8y џto8l>wxxDM@T[UTƽysE`S$! Xꇅn|Hm8�z<?#J5w/ oj6~~!jŃO▜ąX&UcUʤ|ur=-(/]ܓڟy>pu0G4cz/>zV;:޻ ݳoSӓg\N:vU!XSL|Lo4ɒX)Z(�!VLGpӓ×/ q;;GBkг 5%dc=뵭{z}zܻGrP-IP7tG3 5(%x{{{闗{Ϟdq7o^?#G%YT2qv(++v'[#+˳7޾bEWֈ e,K0$}6GrTr޼HQ]#nD~en*E9t扣m6Tp}F7 ;Ɍd1XxձIw^қivǷkWT"R <p?\h\Tx:(G߬=W;Ƭ-2 ť"T@ �Kz{ޝ0>|owwuWwI9Yu,-ۋRzYD•pEEI}U4%_$MqJNb3xpظ=˗{{;P_n]EV]P y6 :e$S/Ɂg5'JVK3yYA=p5#%[vF,'&kG/_t~VT0a{bTӯ)Xրצ0o+JF* 7HpʁcDŊ0^�Ǟ� wϏk5v;ۭmݮ+5xqJn!<Ld!3',8wuOmsQda< L]H8I?x 6p}-HoWOkok;&1Ed 6%?F/caT͛#*|ВXywȲ5R' f"@$8lv>H)'k>81(#�aɢ5vj$:VDmtW錬I[k@@2}�:q;VekXtXL#׻� bGp $/ BPqo%Ά[iI҃d~$1o\>�-e|Db=\{ B];~ߎٰo(1; o lgqA:x$=ǺbYӢfx< ÎWqEָ"ԫxZ"9(ރ�<v 8l8P-Ƹ*< ijȰFj<MW76\ Q@0CDo_5;x6ؖ3SM!9&UfD_2|tN7{Yʪܘ(U�|A@="O}Av&_QkuDzB$L\b#QDHΌ1O5lIV d8%5[gHys Rt n"}y1#w8a6३fK4U$Qc<𧓍€B yPok*/'ut#U܎@@S6�X3&e8-o;`k $L:*Ly+M]tzAIdNl4 E O;(o_+yλ>pBl ) J"<֩'ȣ,**}^߯CNmE0}<hs{40!<Iq՘0# ws/ 4aZ΢JCRWǰloNzg3uUp6&ΘR拊E(L}<QW@+)2:1�")`(2]NZkXUyƓ%�nB#?dVKZ }` La.PlV 1g\A]e7Q _|FfmMSVȉLh,6 &<#˲HӢa#bPu|䣬jS<2q 0:|^!YۨAj9U^NdVpणINL9%<poJ<(idʥE靖mZ~Up{5>ଁMNU)UO4|4JN-lO>CAUT]7mː%n4R$PB[,쿹<>17x,7N4IBt\;^UTي�8Y7-?̜ 2:Ej$t__ֿ{~@~uHb&eYCJ0gjrq *F266Ì;;YO(3.*1$]npV$N}sSWwv]Њ%ݢʪtټd:r~3ɞEk0ܡn{`8kk]$X`#/>|.yLB[_mg:&$A4~۽_ߴ N.n^wji#yOzVfX:2=PZ>xK!zb%M ɳcYţ y!6K\ғ~է8ɜmBJȦ䨥IpWӭg(T: :{vК~PB$\51/<=h[I2NMt늼Ex5*Qrpf']!9ВD$D6}bA=Iruf'vn`dq6K+JODg.Z- ~Lw;{{G[t7i"716#}泵\΋<F "ӽe4~; #^RAj H抁RS㽽w-$[bjQHֹ,/+mGB0ɒS*+`y1A"n@n|qW =L~JBN.k6O" qM$@ԍpQp8|~9Y]?JF"Ǩ]�rGuX-t(lmV,B7sKX8%Z^,Nsqe=�AjH.+0Kgvw?O ~u5%ۢ ?zqr3�5A KUe'\?N-9[Nr-J/<_I&_!HB"$ %Ui𼺈,UQQTҵ[9i^wuZTc%eU!VVWZwT_־K^kDQ@hj~WbAᘴ"Z"))Z py /䠋JaVA ciB҇Uea0i4{͔.æex)nF8%YbӔTt*ՑMAb਱QdUW_p7g.�\V͓r@oF٨}K[ɀeiu�B[ 1 ?S߼F o& 井ĔIeVc/3Tp̩S4}XfaR[WX? }�E1[aUu+:_[yrI߻N7,p+Jj�|'~ax`bҖ 3D=^~jQ�ȣh4b0GQyWU _@\ȩZ TVl*vOJ0ܯcZ Xy K :^|É?ۼ�@<"4i-]EF_ũ$l@eU8ܭdI '%Yhi*?^~jG4Y_#Obr&q$b6*#=K8h-Ԥ~Y}zmBۖƣp*). Jc[h6mM FTÈ�q 8n" ߤ'aLd`'E1/:$x# pGbY!9c2F.<ne[:LC_T٠qǺʒ GlIUX0=8d%h!,WTi<Iz#wS~wko@;`cq1*BQPn�~20e VsO,(n}c0{%$oPS gϟ;IqҘia 8^VIefkH摥0MLk,%y:2Ϡ?Qe&٫_zʞ14Ż|6Dg b`xIuS6'jG$fniB:.yUׅ*J4qLpx4j|z{9cX1?+IՎ~be0LMWCY3LEy]Iֽ pL v\8a&hDdU}<tMssScM4A"v4UbG@Ҕ͒Fjul̤tx!?JZ"Qnqy12v4Xv$Mۍ%ej ouÌb�a6tip 5UB~G{ G0A߮>iLF4J \SR BKUfBsX8'%=p1@H=Vb,'s`jQ.I<Ы;5O0EkBkY>;%�X*>!/ L&rI x# ,8yh84.NcFW<%}Fg)4Mc߳mC$6Q~Ѭ?`+L0℁ԤQ~59{1'/XFz .QfI> r X-FPe!& H1pP'_7Za >e@tK۾vZΚ"GS?(%v] bWuLסV6GcɧpcD}Z0CQ.ƈD^M_IǪr-q_5Fqpn.E,@pf NjuC 3s"Ns[E*+LaO]38A5܄T)a]WX߮cټ翧.Á ւ9˸U\{8_1*؃dUx7-i'5G3dҼENT?fWW7=oo#f@&8݀j/R/B]Ng̡cs+Yn< ɊpAN\À!pTo>5УZ~Vݑscg ?q,=@V' #SQy%84Py!=iy6\&^ f˻-7wK 40Xd<,H+<E� bԫ_t׃,U SLw#0`&=۹Q ;PM/X8=mtGN6�(֨E2Gxl_f .Byg-|MD9|ﶏӝG415I15aQ2(SEdQDsLm91ɑFs0<y(OG.*F ʶnG,xc9*變2e<P>̀yS^2T{nIT͙Yq݃` +:;h x1}DK5ka !NZD9 & GR8.Rq5TEI5:HW.Aljɠg[�IaE ]Q@uL lFغ,<gg2gD`F[7Q5tUEY; Cgz|vy}v֤]LX^ Wg!=ڜ?;P8\: 0>xp~כnnw'Jc)^JpAԼ(TEKV==I1ɯ;S|uѣX é_S_-^}EOHQ,L`J:�NzQUMfUVĄW ÚOihg Q~Uh۾8ý, : MdizJ\/($:2@\[K�9(Mnm~x.25 =,]0`/^'i�@<Qӛ�WXߊSLj/_fũ K\ZV҃aLn?]űc\4�ԑyh 1ou֗]M! ֦$d=&̊u$4%vvD-7ʋ1TŒe5XhX"D>DN嗈u[ �bZ&dBoNЁ�@pqKtqw7SD>-Y`x U7Ȗ5hY taWc @ Í;#N6=834?eASpC?،!N)+ A7m1�f ?U  1^ \{bR|_Eƿdc幟WЈ?d================HV5?hIPM7p-u8jkKMFq왊jk'VFB=M ǵmzIY,eҖaQhCNg G5aKiۛJ V�fPLi1zh8X5W[`XAK]uSY 6.wر褉65||k,geZQ Yzkkljn2F |"3 %o=Uq(Ş3˦"huZiY,>yuͻq>+3*&qsG6&ZL˔ǜĖ2#\*qAּ! @|iA>$pc<7'Ԧ% }KL`65OfeLs\~r(,9 tn0R-zF?!:}ݛMߎLP,P9I35u~KpS$VTβk S{}@MQuK W=Ŗ}җ¼M<3Q=jwYIcN̳ג13$ evO]ɗe+ L26YGqӐ,~v6V%uM~ӐeUz6,8MCC$;ϋw"qٿ�gGipUd7n_vEٶˏ]W%lKrJ-Sd ùd;7>rt4 e<jm8<uVmNc\ѧDu#qr&ceIox٫oi[.q Es<K%Oƪe">* 'O0Ӓ"s}Sc.#3zGQ3iF4z<m-2X9xku&tjRRGڦJ\Y_D8eEee1> ?|Xu3zc"ci׼/C!>h9jsT7 @t'=ZwTOe"]M4=ҩ /8!n#"p@& 2seW"=^H dVP̗9LCH)[]]\3jϗw8x <]di^QqdSYe>x4yUYWo黙JzW+0puY˝8i^Ff}(Ih8Axgp etz*G4=i)@SX-مy׼l)<CpD}؉H4 cAS8*bi2xL_T4Mb'ۯw5_-Wc $tw5|ex-NpJ,5+s+Qd@W`j[T^]wHQpaIS[IG “)r$2v,MslC|J-礘%#QcKUt'@Ł+":3U6chDe"pf0Ì'b2X/n#bl+t32=A_~ ]1qګK6{E1(PA_}㎩ 1#~ yj,'*;&;2=]~xq^807.(]WƷPC$oC;#ْ! �"E;ڗޛ.7"7owgä%D#*+2Fdw c8a15.~%lEQ֭jYӖCfMVxVrv&t|1{}Ey.fe0�8d϶Yv*RY(H(0'(}0ͲU&/犗B�j|j8 ]uxUEB{c-FTE*,~̩j&QUE1 p_^}Ҽۉm<I7t }�Z15T5LQ5qJ-nȫE`HLeqt1N%9*W'}V m#<J܉!i5:BXuɌ$Us"wv&jhNS1 %2 <\ǜ("G c릝\:E*hI s\Tp< sz>OME,KD']EHB^6Ǟ.)Dw"<G" -P�#$(C<?DI3aWE`D'9$. jU3 /kLsEaZX bj,)2ڌd+δl[W+qfE؆_5ZQAtе- |{w�ҡXnert/l*l9m7\l}QlS) Aăei܈55&͎<lV%]. *vfgs* ~3p�|lOА'=IugYy\eK^d$T^ҷu*E{gATDrbA()gX̫gMfƬjzYT҃<0 g.dqdq{.z ňl2;r2x͆Pof5IGeE͎2s4YYNa*{~9XAWgxӠz5R͌ǟN fim'g�5ӜyDoEկVP$^4%m6W+$@"p ^F=IaG)R@(`LݚQ51Pi !]Oe+.ДhUDMxc<y$&kqAŲ$ʲ�GDָ-3$o Д^QY0:1ǡjUhnj_�,u AdFl"�5%#넖† { XlȚ"elEywҢ"3!۱6 ׿?}>Ѝ!MdEt0ڲIe0hؖCy.d5u} ; Cq124íV;Fi;n"]Q 7kH㇟߿{鯿__@ؤ M9fV\-+"=ϱ BoF[E0XD@An& BkW;,*<5yռMMatv|v~ySŢN`9B( !r^&xȷP*Pr[cô ih .UA@G ڶˋG I?^+ITer"(TbErBR. 1!/Xa y#"5Q !{] I$xn9a'Px�VϋqjAdJӘV UebCȕ7*%-68s iQRUV(A9Zc%AQ$˓/e+UWeKT[U+ Sͬ ?"Eb%sFo<jIF6jQ �ꇣwpNWҽS2Zz_f,Udf&iٰ8ézՊ)oo6*DL( eɣHDN UyQk�L q:0; ~djjA(#mvIF>ug*_{ pz+YRL]!K%Բd<�7\<T*uu^vUNX8GXУῺ&uHW>+QJN*7TE #FPM5o vPfX?m] #$"sDih Pq&YX<dݛ(H!o?% FSMgٶ$2j:AjW؍6$r=ߪ}DVҟO^iKDR*gO>xh 6cl0qIa E0K <۾q^djtQIrIrGd]՚(י!*PgO?V%q7Dd^>=MD mz1 LƊA T 7 +*ZC.I<Ǣy>|ų͵ ϝ=<<N5FoNtZ NGIUU7|jf:RHĬ$5щ#1ӷ޽:ۊ rCUv* _c 7 ޽2f&SG 6ʄ#L3~s!>Ȗ_? zX;�(]<8::oVMNDJ]v\z&_݇'�*Ѿ ȿ><:x2igPBvI?&kT!$C~FZב ŨطMxImpg{܆ŧ_ 6ۈ.Ě_G߆.9ͮ_](P4ܪ #e\ ϲ b\ L>xx酨HgիW}GENi'_'y �)- ]+l7Tӊ,ÓD%v 0�9IIӅ"/V!j)ZL%]#?߃Xs)ƒ.LGttqr|Ɉbtڎw7հ] "'Tu["I5m~I A%`[bC<BV[X#%{a/.ɨÇ|hqcr L@e(7F-L"ͬc~Ҙ0jw(kf>=|}gG)3LDzO_!8#rx Y_'jA[#_7o{><:PzrBDSxGGGSLO\H}M]<Y{Ozѩd!Q3nā%j͢&e<oy>>y""L3O\߇ Byf2@%~~Ǐ'7.V2 \ѩ7g=Όb<=W1]H I,χ 9}ao|dO4^dӚ'5YUMb`yU} G;pb3W A]"d$t`+4MM'ǣ߾~/*p!ꦋҠ~>*ϛ.4Ó%>8 C!N$<cQsC&^wvȆ7%7̰YݫES,E!("EO>T׭�,{2((MVj4ysu&E.ӦĴ|Ѥ*Cޝ/ )]&egݚwy�%dV8EYcB`~%9=`o4뚺5 vq0lz.Y(^W&2X1nVp%8da*Fpł>:׿4 Z]ųO!<Lzt, ^Qi5�OcPExQ7<$nF>6D68ZˤFf6 >$V>^z1+gf*rCUsXƒ6}j86ClqLrq/Ik< d!<s (>p~L6`}ϋfMwJMKR Ouj+R4h쁑Ϟө>"+YjSA +g{<?!/jٖ)V%qᴡWWTkv.\ѣId ɴl/ ͷN8u̼>iqýae]$?yx=5_fT"[fX6lx`MXঽONǒ \|$Bbp"$073{\X I.I&Ei#KB%PRz�/?}{& h_$Cx{`jcy6AG>8:w�F?=u0ջ\P0b6ۚHW~(*,BtLM<|d{u"$Ɛd9|�lFBb&_@V8zzmI$)J&ȫg~Ix"N5p<t@Iɞl'V?xa}pftibvU7F{[;r|dž FFv 0D/Wd60/`Y LH$\w GhF/t4$ߴ(\E;n[b1#\we1lf> hi| BK߉-</ZzL_סc r{p{Ń1ѥ޲VP6-dKx7Qə /vv ~< vPY4�+^eط"o~~UBؖ1xtdև_@0A/IP$u߬T%f?M%fZ˦,fA`ć /TjX!.;CS}vo\Z~ )JN:aׁ)OgCYz#9 ;Qo P-[]KhbYz}0yot_PLd@ml915zƮ1S> /!kjqE[ɮK/$KB;ރ_ܿw)kGV`,3Ŀߒ6uvMu <H(]7H7&  ͖*fXXy#]!'CdE  k4HCv0CW3[Wq\WW$" Mن'!G{D`'=v#9 "cDn�HKE\z|(nNlHZåGF="qHto>:؇W X/Y`$$]64\U. tp6*W;|@k-<L�"u>M7P9&5i)~0iKb^kEm"L8 ͼgO 6tht02kez>͇?<O~O-o ˈgZˤ(vtx/Ge+֋YfzYK7h"Uбu36G{$C?Y{JҌծ[ ݮ )b�<|5Vp`Άd31H4u e)Yxh/=}N?| $Nqؓ,4CIU'iәєUB,TG ],\> 2!δċ5E z.`MjZ+r# ~ލO2M cKEŲ q\wIwEWE3b<X=cL.dޠ`�@V\խz|h l%Dy7޲e,/O,Q-r m g^ѳ5],#qSk `94iwv HS4Yޜ%rW=? 2,%M4H*w;"E_>yE,|1,PP?m7@fh_-kܵ&my}S%n|sK-U5/KlG6w[$K\׵7D1HIHԜd"HFN<T7swh˲$p0byhsU9T 96@x ~rTc#`1,6?ARUd${9&'AQ^-nlNTkXkQct*z3IZ_-W/'藨9X}K1gxtI�854DNkh\�-kX\ZؔxNփ$T'zIb},=.=+i"P�kduC:)"HWؓ)B]60Թx2ɕ vLW(/w=kUzuݠ??zq&9Ԁ pޣFҍV|*\C/x<Ol+XwW_Tc>>zSԂd ұ1|t16$W>)oc‹hH^sաiV6p9RԬS{ũTNv\ TÓ2\CrQx&tUd ^Hi�Xq;Q W-)VonmT-_:Xsl~G +ܳ[-jw{4VSz T4 y;+vPwix?F3-?J!aொT]zAۄxiؑNo2=eȫ͖:<r �Oئ?̃ͨŏBqz&'鶊rkHlӒ vWc'],LJxA US e7[)Nn>ށ*< } v#IR?rt =;r^#'[[0<!0j*a *c{A@BeHo`ۖư]d 9?`٩YwvQ^sGвinZ#|n-*s�53d�6^wtΆ�-$2ͱV/Id΢mcoAr4[ޘrݡwѡ䯻e[I  M@2k1jQ:r؅MnW3"xjWI[].<dn}kfe c T>D챂^neT99Rf IPt-.Z. Gt&cwil7`rIe?xQ FCݬZ<" tY،]mE r\خpoul#CU`cֳ-˱ zk~ok5 cEdӉg?8g:wW Y]8Ux^Խ&Enz%iUSĴ&X6ȼksWƟޞ]\>KGXVw!hD䦹dxZManw{jެ#,(Wd7\Fܐ;y.W z$||ٔa8-2جAciTwkY�XY|%'Uk̻"TW4|!#-xz8(.9֢suMk|-G Wn\l0rtY=6,#TRѶUo ,wgI^O$*a9AL E^⪯C;lֶHFtۚ¹&W<`]és i͐$Iau^5n劯+"/ja:C:ͺmǏ,�kiOv 73tҷ1I"CYZŞӳ)_b#wE6ƚ4ITx^6,/LU~/yH7ooT NM; r) ([Hk |,E܈P /GG2:)̒8Nr&Ưqn.P2plUN"Bywk6$zO<y"Zfq5:)nہ:k :e/y9>85M.@yqђ=FwL :^COD݁<V1ұw' 0!9m3)ںWs仠SQl^xK$<UnņlRT}f2^vIU\{մ!KYMvy<7,0J)@;0peLI'zM:d4Nyn<woVˊVA; :,`uCF'c|>jNrpȪxKA?"H'޼xur.-G},,y[Oc.?xÍg{6?uM<tKΰfJă;xDjgP-PG^Yyg9iINoo [EN/0έ }(P:xp^: jG'J"^⭇w?n{h"zW;`'7  XW:qmrjW8,mdp"fM'+GA=t 痄Ccx2Mw7D2C$v@K(1gokl.LG6`;j ۫k@\׎e5IXs4-M' ywNw;`{h-G MJ2`3y~yu@ O? ݛ Q:ڣ!\7DxIdYQVͲ* A^5 $EhKӠW_Ffz^t/'8|1Ng޿;e%cq^o牃CNuΛ*K=ɒ ޭEƊub )ydӟᅵ||v1pN[ 9EUhxivROw# I/4$ό%N52`ԫLa ,vT;}|2f3!^\[ku<юã}GG2|aᄀwBjR lI-yxȲ� J6a<g"w wC��dh$cE7A:<u#)7XdUI;6w =\fcf:Olwߌ6͊�StR|EBثV&ë@2f|i8QeY'. sVސD49MnwS  -7,WDŽퟞY?Kj^гWk*7ۯ�2ŀῳ\?^5bNrFoPu+26sb4{#&nQ.oߡl'g 'ʏ0z ) "D5p|&5< U}y݇wB$9UeY XQ/ohVG=`}Mz.3>}TR ZZ�7 ?cxy0j/Wly]am [̐!/q)JirQn{UQ pʏ`b y|cԛcmApYA8*e$,UA^ ^Ze0O9?f(a\l5-T.q皚]1{𜍡NȃG*Iw mo6ɍmO f~BuD1o6˦bCPR5kRfPd1xR"+鲶K ӷ WUU-LPh*;5$SfY*s/(#-1q$A %:Ǩ^ hQ& ^3ɌZkp9'syH'u'�LiZiڦ` +.Þ_ <3tuEJw_>N "U-; 2 hG̷ 2L𒑩qCkv5`56א޽{o|ΎO+G|EÛUq]3(;n2?c�˫[r_Ev}pyٙajgQ@kYa[<ky`?,cAx|M6վJ-�>5lXAE WM1Cг LLǿd qr(]=KR�P.wصx,rB>02uj$ML! ]o]0 4UMws"zZ:JܤmYL&DLXf:�> E2AY FKt\pܨh Df}}]Y2q/7(WORA (NMۖsP //B=JȻD;Px_}r9L5B~u * /<4Yu<<U B}P-$[1BMU#aWUFk^F}ɰ?>:"ٴY4eKYZQUW;MT@#RUB ע!;^V)f!uI~`uDP`�k<ѳ"OPu[،C-9xKe V lxF)sx"Ng(}vSLt 6{*Q*^7㸛'Dۿ/ccx:A`9~9~9~9~9~9~9~9~9SIпyDIKq`az',reߧaQdM/.nSryXr|T~ؽ[ 'gysjP.H\dtviZ̲Y9N8 j'/z,yrS1xC׳bl3SªMMi{})mӟ-b<w)'NP0gDfgjQE9 M޽<IeW&0MeEՑi( ,K[4ߪ-г,7 V[Qٔ0yb8~9UO^_-ʑkE~}rf5q3$Y-;ڿbTs4-NE)'CoujrTe`M>!L(r!UȐV'f~#kEdO'niڬh8Nؕ޼Ӣ 5"ga.*6$d\px^3D&e٫VkfY.Cw26<EX̜|!@c}`U7jP"l2<|ΪY_;iѮ6-ϳөW1YNf`KiKha$/5jtdŹ D5H19մ<J,vD1m?-PKmWgV8[l'NALqڿř$:56f~eYg76ڙޗO_>0<[%M3X+JwJءYQw&s-X9j>$u~ JËgo.%gERrQğOe iuF >xMnZd9:JgIٖ.:O4'))#NuW# s+C?0b$"*,XU 7T7r;&~Rq<C!/*}Ɓ˪H&^Gs~e,+ ?L6%[jw-#;Q臾 ))ؐ, mU1l ceƵ?zĊČ3\}ݖ*^n`XnXѦ+vyutȒȨQMO`>~S9A@0!cy=EvNH!?꒬ز^]ѡ.ޗdꏚiFUxdq|64 tJL\;aԑ9ٰ44͑ڣg-G5[ܦudQQ- 0G;ZnF%ncG3m2K<<Eqry`NԄmb+6Т^B˄q35RXFTPvE:A6GnQ1`tY?y!-hPr!fR ;7z%� `uٚKh 95r-$:R_k&2f]7&|H7 7o4*@4 \]~_0+BR5DAU*TyH7 i"K�.m^"fݤ #笊y<:DT|sųC`G2 r;:̗M[aBN"{Ǘ?0/Q <3X2b(1z7|<<[^^T'wDθ4EŻow{{? 17NEX rjHi`UeIh !;T_`^<3Md!B"E\yyW22t2<eO+N T Gfp0ӂeC!NOώtTjDBNmix4ew'"Eˆ̍9 2"a^QQ@ qy4D֢阄5aGWȘ|~sK!( E|q<BX^E�]fncr>`J`|Tҽd|mX*)̩56_%zt2rwtU ;*,A=A gQhB.9EC_04?df A;+!X꺉v2\Y$E�c5I*+JǶ!pu{95qU`4&? WM~*5atE:1iJH@( l�Br[�6^AH BSU(/y04vVIe RAJ٠G_͎� iEIuð oBxZ,2w)y.?UӷUӭŊ Ӡ"kۦ8bK){�;]yA�_$У hw<H mb(S+(ƒTy]u eeloꖄ2v 5,M :6/ ZnҮQGR"1CLxsT,C [xAe>WzQ-&*_I^\U<>4 ה*/Ӱ05;.SIs 3eQǂ_*jyvbԺ#$LF<�C{S(t(,X Bq p*!~Tt˺m鲄f"x,0h:eYt; M{6f4ӌfM$wN zXH1J}CdpnQD{d4fdk\f{CrpK 2䖣O+EGcKGruwzr@XF<3/kVTwm"Ȑsgnj̉W&) IM!vq.(ofBz@PȖD膪w, ƒlMkd?P@ $|X$RYn7-MiyI^-%DY%pF7Dg)r-]pB8:0 ynpv}z۳ UN20\�ƏV%  KA':DL  *O(/(S)nly蓋ސ X} AfsxwpVBzSH)319vD15 m'of8čl IhVAX"΁ NQ+W>p*4;/$aϗ!_us@Da`I+h8ђc^< ^WK&Pd &dTlj= 'T5|]ۮJP$nܻ 䆆<M&r%"h4y+ "]gopvD=ʧ%%\eEE"erd ~X̏h29)UD'*Jѵu~ *~y j$Q d;mnYVйU1dIxqDb{6ol2Kf[ΙFH+ {ZQ40>=JD6yrjnRI nY[Z1V E7_谀Qz'+NNȍa2$*ޢX75'*0TE�cDFz6?6"0o߽8Ŗ$�o #iU9T9 (J"/*U@Qz a$qw S <:3TlM&_P~jmJ#bT[rgZvFk(eQ�LmTVK<$.:zP 3J38|Twz�%C.]+5IY\265̌PAwXcg%+Gf69f y_ڽ<{Ϯf>[lYQ 7O]Cyg7 NEz!" Q92So^\xY\}v%54u a,c iX(KyaVUk/˺ab ɚlTs %Ử΋^$dMїE~�(HWYCۑc5yGD8E6oX` ('%í)rqT0Rh8wӧ-ofȰ#wF^I`];Om!xϵ oUg,J,U3_aN0s|5J658{'&. \H&ı P雝ݝ?9VS\_Rv[²X. PLͻONϯ/.oF'Ĥ,ڲr^/./.X >1wvv^MvNzI* /(`ϟ޿?8:=}^~p2rMBxwoggw@ޜ^.Ŋ�ATӭ <ʠMЬvu �!CMG$O7ggi.9@Φ.]ݝEue/jom:~ۆ}O]ӅbQ'F;A^e]h^eò##3(9> S<*݁aGIJb:#0WF&J¥ILa߿:zu~rtr3(3xV5r|u-HI=2>Cx"?id󱦢[ۻO~9\:st1ws}yq~U4?KSDiۆ{]ovUӗp(을M\5a҄Y0@vvq 9Ύ!X9d;nI߮)M43*($/hBQZo70u]7e^QBT2?{1H$AakMe'K`)YH"zLY@ rC*d p?6H{E(+,)s9<h)nan*Gn+Ț i:>t3C /E8$^F[ʳ6ȴIAkvd߂}}w/h�E2LN(k^?L汢[* 77jbÚf\dfso{KqQ5({L'K!h'N2nh5큩jI5mW_"Up&A$&D<Mw?) JEYy<߄mރ ;%K7vEwuq-@LL驪bV$<!]fYGDɟ*;@+�Kgyúkv!U"-9 h ODh<a!~ Hׂj!kSxC8'ٕ1݄ڛU}2Կi,?LxolQjiМq|re q��Nye IT5N'T\~{h5XJUEU>g3j.|IlNbTo0!gzA◻{`԰B>paR"IȊD͋u 0x%z(~ځni$J >ݘB0LǨ <P'f(*M %;NРШH<ʱAjp+ a3δl/>\@BP RtUYt|֎9 rQ4S"no[۟8N@X }|x BX鈵ʭin2Sy`·7G'F7e4K GC*hyk{Ma0sΟnmnw!1urɵ@xx1+cǯx.MpU2 Con>yFE'fcyv7%APIh0JV wzځ\֢Ŋ('HJw^͝M=y>-:O`ʠ6s,-Ɂ3D6'vjQ>FyeEI2u$'bu1|[{l肭n=7}Bp $%o~I/*m#-3zXd+5M1S#M^ =^igL/SEآr!ſ$ #xQ:k4n-LkX,.ø/ M6`Y]", ESA{F�</3Kă Jz}gu'>7y:?orH&,@"Y%5yg;]ޑ?A% Q<-rOc= 2RvTٸAEIG8TO-SsA-tE'AqZ䎂W"a&p "?h>d7zեaZ@?4"kY< 4;<>6yiV-tI3g ЅMbq?q|H&D.iLHZ3z!]i`2f<tQ}(Jxj,K>O-h:{9WX?f MT*M#gul;2qq97hnMZޛ {w^khkQj/ O-S{cF Զ^7vk% D,QD$'o k 2ohgkçhۨlm.UMԎG~q,)y:|k¤wuvjά*iXD, 1&)*Y:% H1͆ 6U9[ e珡.§o7f1v}[8^/�Ƴ'ndP뚑xA`|G]w *2T%'xl}`-)iC1( �iH|o?zB9gjQה[[4 iQX4mai&Kxo'mQsgN7d<"=1u#)u 4oҾR;l36-'(V,FKL ](ޯ_yF/<|0F̄ >G.hse|=[ k;D!ZW \إ hKݷ/awG^!Q 06@=2Q>U+aUŎƜwƒ#%hb$}ں:`Mzyil[QR4$qc!/"V2;OUE7!lNђ AftZgo{v<ӻz1dW4ڐ V:7�za>Ӽ,qTLtxXc]L0jLԾ^l˽�~vN M`BmKužxm=xǺ kARTL˝%M5bن~ڣc+I<'[�^@ޏ+IX ɒGPt=yxfZ hRIbCb /oa1{{:)Zԗ;^bxkuǎ[D}"Pۮ/)m2oLdrgHY0zm=@q~s|"7]8%ɉh!̴%\Jfi_?2uK}Me^ +Vgzt#ƈ�D= L4#G0[U{^r~m+LuÍ�,/NHhy 1/+8}QJ,s;O�[5tY4/CC晩b1f`b@ףc[RNp"iNHֆ81Hһu/>3^AB^L¦xjXMlˣ.+Ⱥ5-R3-@x0F^NYwhmI(Ϋݭwit46~=%ea2Ąm*BëV4S  9Myv<Q7IZ6u  },([ۣw]'ă-ɭaWK\?1Svc}eo߹LxTt7*|?i宊oWjR[@(J M{ q!InعM$):_ߝxÉؠ/Ͳس N$}/9 n6r2fmfk\$gkΎ{|}X f Jmx%zE6˪w#"At'x-/H iD61E }2tM__ ̉Y T6Ⱥ'mAiv?%׵xX&:VU$N|J.B#h (UVX]TLMk8q{ $ 5Fbq Չ0D?+*TG}GKi[z,)dE6Æ%]_(a}i;rj" ρIrB$Z8s@�N|FNHA2(Cq2Ha\מӻvΒD͢- ^Œ<K[Ȝja軦"+X fnb `i gp>¢҈I5h8*?;qQh74BI'iXMN#`9h%$}u7dz,ȀIpqYJA\>T؞/ Sy]g:mI!Ө}ƨ, f^#*suspNX 7T\R QaUOyx"Y[Z9 f3;:<g4FUK<)sϝ#9?nllv444poH8V/a̢ {ǯ^>9�!@ 7el5\2xYG@h_ՊM8њ&9]ݧ)^A5ڶLaFg/O[5X9NM3ܤjY-1ojO$'8pE2^{gLf&{ˋ7ד pu#yd6e�9X>d{o1[Fx 8^TlNڞon.J%S +Ma?a4#+RU * <~n݂`bT$_ޯ W;H߳8 0A=4u{'C�+zGD>x)ccj㌒!-Clˉr63dƁ7Q`/2 SPs$!9D@V<3<jF%)uR]ز4v:FZ^\dC^7jYB7ePf2&>tIXM94E(՘KjzY$Dlz`4eʹm44%| �$O0I!:+$(]5tBո]4u e fIk uX= e\?50YmT·qPጤb2TM%n@3}:a s~0bL R2m47[% <.*Dq<0]x3W;j. * 3<`9.<l7.5"2ąkU8LS~'f GE`F iTpqUrܮ# 3to/&e`x/hSG7QڬK1+恭AjβPIj0ḩ$; &H{SmM3QLD�UFf9D<<)X<0~oB9VGz-! 222T@ʳ/\03d-M /0Vt-l,Ӟyhc|d{y',ᰋ;2c=g/ ^}a5&ᤠAcb+lf^zs66]2]5Q_^O**=qŒN߾z‚NM&A VtJjB57*78?tʀ6PH@b4/"r˗O2ܘ5/27,\\uX$.p.{C^q9٧!84MT]n*_uG9(!n4h0:s~x1᭒VQ[|75/ķipcFu"s؅!Jɛj|1=& m?e�,*k&n C^WD8\g4u8Ol_P?n+VmuYmAaFao*sP£#?S6|2}p^NwAvp[̻@S�d5&?VMha7ƦROW(뫫˫T g0uU/AmNCxv ^P^|yuqXѫ+FD{Uo^4 1,vh$1]򝳱v�hc>q ˄ۑ[!QV8vYE*e6uô}&y>RQCT]᧓Ny~Ѓ-$XhMG?=X AwTxU b!B\PS[w9%ur=6&.v|xbjNeʴw݁P�0}+ SnpwDH2s|p HUK$+9ZPq#t0]ۍ%JK4yQ$`gI5p2ey~pIQiE^ xuJMd=;8su>x3i:>^8^v3]-F R#݂Se&Dčz=F% s2^Idϟ~c5(Hj.^Yn2߬>OYV6ݢ() 2()ȀQ%T*?yRLܠ\޵Xa:CSX8?HfS x2SX#WWA2Cx̲ jVU&d=ֶ0ŌpFn$>ZV>ÝeɊ׬͙M:$�#QT8VP` \KN}[[܀1EX# �JmLgr[<H ۠YY=! + %Xe#Fj" Yanu(=w>6*n5N"v8QIѪ1l!bD3Y,bm:;[d nEtN`'+IUg[Ğ. ó!?8m.HzUztk~](Jm7KpӡWg oPeԇPr`[G^wx ̤s=}IeZ={77W]A-'dLg&6>~QwSCd.ǒs]MY;2-S\_LX B܅< ,M@?8:豒bqʏ{SYݏgP2bp @EY 89KWӍ'7sCj)ElR٩j9sd^%{~gECoA1C5wq4`=MS*0E! c^ QCQ\8.bENk!FN- iW{vo51-/-4� a,pѷhnQôy(t-�,zw߯i)�CNplN+,YE% kLh;g;&li" Yb(YKeI7t0Ip~ב)K cjO=}-eQl>Dr|\ôCKD0r!Tئc6{u~=J3k;m{ul)rbHBՒq®ch&%ڶ&M'C1ߟ%rT�� ]f  ;MH"G2HdH ̲k2(Kw*^#Ii?]dn�sY9Yr�0rt*2ez '$)(5ۆЅn)#*!,n?>pxıq~6!|$N[j2a!׼Y$ʺʈ8<A#fco^x\q=z\q=z\q=z\q=z\oFHx_;rgb; -7Bi kJ8'frfPվV0LfQTߋ_T̲?F fސE7;ol(>r(*lCu!^z%8Qbe[2'yyg8{q~~qq/ nU1 )B]6rNߏ6N& s$8 +mfq%ȦO\kQXԾ(d_Udl|ѵ`'qx=]Λ:X]ј֩ǝ ^dt&vY6zjC 2-1Tݰjh,vkYO4'D6@*$R (x;cvQDNnx?6zQĖ_YgI'F czARo*"wk)rr{QSu]0ur^&~5 lMϵ=:ݸymǖon ?՟7aXazY;ܰ\.l3d�0# •fizRGtm0[U�Q6oׂEM&6dj>,MU498leJ? S?`ɺE()U[ƶ>=<洰C: a' 7q9 }w 0fE4?/^WD 8ېN? $\$݅' NwF.X~\ 4F2ƁgO,/n>lGvt%~ 4ˆz�g<$#K8 57vC=O 1Mb?e`dK w⧊g 'B|Rsz5v8gEKHI 2؆6PTMNU'#lWnkONI$.ٸb3GS7 8{HrA&<4aU�cʄgLJbC'[.m$v Í "2:o/iEhIZ.lO0(q@#圪w 8Kjmi<0S[${VTuLήmJF3ݨ"[ V5O%\tq$ DH`~L  CKh(8D>:‘|̫az ~Ry9h(K?^pd :-M%m#]+@̘tD'ט#ٖcE(b&&' �}U@{ߍ{ITW>'TYRrW 쪜Be6w4z 5 YP]4dY+P_D+A6S%F Z]NSz6]p"U;n4\V x*rYr%oDD"NN'&Y徥M2,0$I7wfCԼw{c`8`$lU_$�mnprh>aķ@is6R'rWֱ-JV59ձc`,L" h"ñ#]Gg g*ӹ)99.Ѧ3 et97,)2H5PU2GٜfS0Z&5҉vZ&ոT1#1C0bKTJF7}|W3CxEf:!&?b>fd8D> :w{AdF"Iuc&^RchHH0Vi ao8 \X&f#Ѱ?:1jU*mי)/o2i"łZ1g:^o"̒'WSEzuHXz!"C-d< Vv&͛Đi_$v>?_c1 CQš"n[jqȞ- 5|n"RV<2 ACbB"oeTjr*Lj8^s4Os r,Rܼ=E@H{d6< 4KC϶ bOE gT;4). VE&oLNb zmApEB|ń {>] ?Ng,Di8Jz{q.mHyYxll,ʲD&%TK6UQv&lۻ/:OA ]S!.JvhjCɜNX9qŀS>Qa;K%��E?IHzU)bᛏO xH3^m(a*zTry"ȖgJ˹E ^Q e"T%mWsz&U  VdF3X(T\|J 8aݰ]\R(ʐ�rv|H?:l>AyF) \_ gPvCXI'jKxx:2v2?DIjjڮF(Ud�)I,(I߈$v[%0J6]%I2"haQ.xYP'`*JY6)B%JM(�xYe f1^< @AB. s4:.=|C,utM u�tNc6(5hMr .Lo!D "M\@60̰(S0Qӏ `; V5pYEf-\xd4N #M#󛊘DJ|r ;[xDz_g]O K}Τ ߪv\KWZҗHfFThCXվkDs^i]@5Q#iz-PdP Ͽ`jqĎ8PSZ sOuCmEkË́߆Cut ӯymO( 5Ut6>˵2` <8.j隨78nAP/`oZ׵35*a_eXMSyk~ۮ;O۬ P4? +j(\teY}{&,wӂjAa־* ݑV5Qt"O!P}i؉]Ӕ.7Cf8n7XXr"757䧐y[]̊k}[LfHcɑi`No~mRbQEׯO'#(~MD!-+KmrM`F|TKM Sf,S$xNs2b5Dw4pD;"7| vAm'Tdn鄴mȓVWV.R󓳫d0\+E7PbNKT�e4Q8Uk^BbSɩ;MWl֝. .u=$T%vx~6� dd3*,7Uv]>=e$I/]`_w`nOOx4B{PÙHۤ>ıK,X(ي4enDH!8D.BK⩏Fb-- 㷝̦Dm3/i?Bs+]V$p`mHۺRI!Q_8UP[*Yn=Cɶ 4Gѵ?<! 2 9j5lb-D*S$i}Y66ڎp%ᵻ="$ϛ6E%aVDNCe SaaKLCiJd ]YN? e"^YIă_C0W C5 @9iGN:Lxېƌ&UglD H{@2B !P3L|%8uO$yoxF0"tq5fM@]N@ E0|fdib&ݛ?D@PYҮK6\`& Eq[i۽VsE7 2SYVP 륢`m^\uig'Sj(ͫZRKl}w7z鞡u"NiցI'=t8 _v'G%Ӄ@\{NN.c/(I<yjԭ=8Q&"e(Ë7oO.?}xᬷ䳦08g/~VY %!ғUcD" ubd_ٺs.""#,8Dy1�GFg'G uzTE@GW*coU8Fۭ͘T�QSRB"G:J1XJI@PM׽Pm=6ŋQl;ϯ :j+_Lg8^}SO^JO(50tkXU�{AE=Kix= |(-_???jIpo\El: `WŽ9(m?J<c@m"z<beqыW!|",ش8?(TCJcKXb8Pٻ;QNBQuAˤX91S S >El"y]YD W8~-Qmہvd[ P~] _c .2*Hq7D<.LG/ڇ [}+uSpW\"Z^ӥu"6 $EF/f.Oo:QI�QR4;JG$~<1j6N%(88~nt|}A uꪴ�JyT (WDXtUI$"@ZZu`ٺ'U8 1ۯ *8UE!+"3yٱ�|(�Z| C7eVox/ f(˄O^}$Eiw]SiR ~]t:_ĨW=/euV 0͋D9{yG٫zzElyz6eӋC6gabHDqGd=CH״l^^]>sAIQCSg/~VN%FyS""iU[/-^64/j(kuI%.%r 5=?&V>$V)a΋"uo/1H}X{T$lqmA}yKs_cZ7LEm NV0Շ{F  _ lN~:<Ə i77{-x8SYBYpYsư70=!DE'НC3U&M} d 0]7al @G|ZZ36LRt[A#3J\k#tjX |�X~sQA8loaҋe Qf/NuW:&6sԗ(b?%,߮tXvuB;,CM_B=q3*\>Y2vMo"`U"^X;o1~[xgĸ:4[ |m-B 0q-1KS` s;v$Ib+1$ϻ}xfb# /WqĤq9|7 mw5�9&rtIјQd B]@2cnnFO/9'!^Q ՓٳRTP)(/ǭTsŰju`LX- +8Q /#+̵ĺgY=|8 ӗ,h+jݐS[lrY,NTTć�*N3U8N4*G'`of~!Yy W7kmt< .V^ ?YQטlwBt?)![Rb\g˥9zC8$B1M(48vdCD:-D4n[-mSEM)]> zM!}+Xx ! \<6 Ѱv͎}*'}*Ӫ`Tv $*\7HWdb/z9gd->jo#fp? 2XĩKɺA䚱i؅:L7tۍ$?Zm8: Q(*6z?~D==hs}U4uA uﶤYWezNzSAmHk"_[Ku*6'G iFܘkH�oBE/W߹_G dN ݃jآ>F Ƶ3Yo$z^Ptq Flᨀg=F5$oppXЂl#'w%.!ikX'x ]nkO{q!x}rgdWYB ?_PTi@IfZ'sMm PJWS#|ݷVi5VŤ3&,CQl'{^\0M[EmtBcK&@m 6՛+Mxy7DRϏR~R66pV{#UAu{ =8ua|/Lnlסu<Zp�K_Xߞi]y.RiԸ)Z@,+xж< 7[WokYQuWdkѕo_vb,, 8WN%7^n laxEFBõ}3\:qM<:s>TL `L7d=;<5cEMC}~ϟsKHZ+RnȎiI7X>$^=Ia'Xɢ.[ul$a?iCu<6F`C(<:5r u?L)7G@iڶ. vyzji)g8n%vAHXj.z2(9G;5cP셐ڼF!,Sl:]w?ysE@xpBkMd Hd;<Hd<4f'Q:u6ӝxTښƃlop|Kdev@3.;I׆hrb]ܡ%7EitElVYwr%/҆babX(�Z˪ НMw &6O< %]&-z1[kmӒEHj ,&QXmJ# +vJHw7!I&Os~*Jy4jZJ / *q¥G0z F3|HJ-1v-H5@Ѐ.w<C=}0)$Fo^T�uZrg1I;oEY@ @J Ų24LǂL#ߤ'.ʝ}c#Ȗ@/)lyNӛ:4UQP /59Idyiڦ"I5҂fGioRlx6M "ďgb\~X' ЭL{g[N!?q+^KdHtȊaي(|!&'^ nwnH6ÒmZ]IO(Z+L~o0WlՖPNEzyUEy Řb ]3 Eg9̓D@WPn7ճ )ш0[Uh/_/o:V#r/}gNUmqѲ!5O=UE#SuݗvZ 2*lpoU5Pm:4p/X\)T, Еx[{6'ivR&-zf>s1I5lQW{JvĚ'ucaMlȢ$Q}ܬ~>M*=է츁"<ðjgMi3g Aˤo]a M\d AGdo[~"EM7lK$vru6e<hz<bvHOxm;@Y@m6mfuO3n  xDu2ݐMd(lD ]ːDIrӂ*ɲ|`1jKR+<_q-uY HNAҹ�~eȰ 0tnp5,~;[_B`0H_, NX=֛ug5IqApթU܄=פ~mriR~,X+zG"cdN Q-t{ /�eT>$$-(Hn Pt즻TBoGIQ#` w/xH4"ٹ}Bs"w}Ip[zp :twvTu oڷܴM'ci*E9iH)2!m#2 5~# iIӁ; kI ewװESb ִ,O�aEE>;x gMF j1gpgfTeMoQ7V/&|4:ﺽR*r ̈́a wCbwC,SN`Y|)dIT|AK]So]k@d�N߽cr<+{,lhNUM3em`wct^vx;:շ; YW&gqld6?6"F N@ʂfTP uVy`$%)0pl& 'g7 w{D[ jȖ Ni୑:2!(Dә7uݥo صec"W!kv` iGO4QI_Xrԣ< N@pGX=UjY@NQ t0r=ܤ&}`2&<<GҲ m݉�y1hAR4f g R IՌ$xtSHW :Gbk0:HoB9ݒ[B֚& )^4euog+@.Vȫ mQW ۮD �1,Ծ&sAt)ܥk DO^ȝcU Lu{{wGw3MzLÛC_`�PAV_u+;Lr2䙥?3:X.mAro [G ppN ?0i ɛ_{c0ѹ ݦ�]�>Ve?볛1 ^/ᖸǾͼNd 1!{7]õGXPiؐZ c9̵Wd:r U_tz3F50[^- yh |j`$$ңݵ% ~d"$W0m¹2lr{o`vФue&|?9Mi o믇5x Q Y]K?UL(dxﭖd�Tn餿E($=)�q{PuYG�fgoK6Bُ3&(4>eI!DE'ݗcϜtVb|Èz>]g�/f]=賚P $8XNz9(%. 6 `1"WغfgX.G+ 񐦧 ӛ7ڶZ2^-dU 1! > [l?OA< iU7nrzͰ7=JT#r.᷷TM?.}[[l<:pβxkʶxַl2b(ՑWn.f0뛫!%hɺ+P6n|=V mSytD[�^H<8</fXKK|6nz |k|tn7&(vZN9)j1'SJ,/{(DKS__pv=X@u@zib3 UuZEXj:OhX=][D-9x4npꅾ) ɯ`jj 98We^eAߎ1#04`* <?H- q G_ )ruEt64H٬24S o`<s]zg*UiqvŻO3A s3+!TJiRwCzh�. A3N cX^Ro!5`ËLHz dЃiˤ*-NX÷#m*04~6ƀ u{�Wq3. 4M5\LptLT~#hE? a0Β4ZFi#fCn<MɴmX~d̨fzpu0' `/l[CVг ̀ upj 7}銀L0XnBEן>\.ޞ.xA[k#0R/HS[\'tمݚLf:fvqvd_\O&,|svXo8[Dۖ)FƜ=$Yq( <*msK`0Y pbz˸踧RU#ܵe8~8p GU ?^-44򠪑 b!4AcC/TqcjHjGJY#11.|˴̓R9̱۔KS1Pt 5ɁDhAOjrdUl7v!(<Erc)hfnd SIEE@&Hc&6?)P�4֥r Fi]6 l`;3]1aq쀂( VN_cƜ@"ZIߛ0+bӌCf&Al< ~M棅F6PcAw*Eˆ_U.Th{(O^@)]/T; ޿a9@4o.p>nW&Nnx&SXJKWW(d;n0CѠ= -Nu 2tћмA*iP5;.3Oh S!fۮo2t.^y&| .^=98`@5CE[2;^h0Ar\0٪l:t.͗ :56*0ZvpjJAx%$vM c,Vi`#Jx] v E^?8#Bk| +IsX߲g됋8N,:^ W I◠C]nAUD0?#~۞D,ox2O1v-|*Oq @EY7}L>x鬅薻 *o$xLbɡtkPl>P-0T٨? n.<m蚆o�+ʄM\"�mSץDuO'g73g:|F_I՜l6&}9T66:xwҟAm�v2XPٚ\4䇟(ȴŶF FYn\ gHU dk &}? Nux8>0u+MTU, !z?Ƃ @Qqid+Eaaa? ]qDnn[P <X? ,T2Ɋ,b@BYgY&:(/2V]8Xߑ�I<ZLBeEyqOi<4xOi<4xOi<4xOi<4xOi<5,XiC\6J)u7L?;MC.)Hy 'g|8{Q^ΉvRfoɺ2N((o"-^ * =weIyk1]=anWưVBPz丮K\ԱA*LOf-AfUdKS[|%_dY5զJ7V3qIUM _"\UfLoonD1-%$ /9z:S\5OAn�#f]Ɩ>{eXLiۖWl6MU$Kcr AtoSʎ׫ĜvjUH\)~cYjȨVz)"5 ;H;&~2q -LΓ@|i+gP雋.j<]U٥셑oi?x5M*jiI^5((+Q1 ,B4/3D=0:5䣢\|FA1NLVmùͺB5R1 |#KגzW sZ^7v-Ih #Yj;2>u;Fժi,\2p8 7+ByK] $u $ȇnKM;v$NoYUdɢ(+Oχy&~[G_ā9<n*so __ Z-/j`4u5D+EB|LQp֟.^1: 0p9^PhHRQ( l*ȚDW(U0zP4mksWLǖYIUdUfW=:2ͳ\NlgӍ?Ļ<MP f Gκ7X2WDBQ9NwxpCCM;E!t]:f%-T ߹"CK"-%[ȵTF4uf6Pu Tli% Xa'T *4X֌eOT, A vx:;,7&Pz~Ǹדt!r$j.~Accq .j�y4TEuK¸/Dn*vF2ݤm3dU*.#Iӫo6%j_Q8 ct =P l[+v~iCdS)|Jdڿk0~mGxьW& t+aK=[exAڻJUMbbV}Z4,*YAQyNfh) Rbf4Q_<Uj*aprYּm*V8MD1mvsL0k,^ԡO[Tǜ84UxJl9;FfAцŪ0bd 5 NnX$|YŶf(* ㋙neeOJMͰEurtJ=SZU5E.ӣ麓n =r#?Thjh 1JCG`I`'qi 1eVr rL~cN5Rǀ| ;Ŗ2d/ijz83BMqmx*bd1BfYU$Y>8ݭZGY tD=ypr ,tˆhn6_nwg"KMǃh<enfEFJS]/7{N$�CO炤Q980GThDnՈ9fJ I5GޕŜ91pIva , ùJ_^2x1"犀nK}1*ĥxm/!~$bCě@W}JDa~ٛ ##Oj")fP#KzΦ,D7T gqA4� L-Ҽ !xoSblId'KcUǨgh<+QD;dXKbVq󩢚٪%"ҫNM)w Rƴl&4EUƞ嘲X WEkDP4em4amhlij0g9DSfGEH׆۾g*ێ�p u %iQ1肆h �a D%5$j2NFdПIz!ܨVVY~pȼْ~,;' Ci%5c5X qw}՛ $,dچKI&M A‰*?> 6iCk)57ExQ!nA_E̡bxu3\H8[dQOuZ8H) yqKP4qd~aċPKDiEن'DXשּׂQaPx[L(\KtbԟA]gDp�?M.>Is#cGzf(,X-n<t EQ3w=TFd/"P '(fBfYfq) 8-l L*OFGy0PwZ%x$-fhЎ! h $mNCk5|P줪PDYFYYږx_' 9,!5*VP4XIhǠ-d>T 1b۽f J@UQspg;Keɇ?/!T:U%aE4q#aRD :u5+Scԃշ۵U z dߢ:Q \^V?Pĝ 'l(fV7{5܂;|STSDw$+d5BTYcJ_D51ٷu'ce5p5'yV~>$r_%R-G8 L^RM0uD۶٠VgYId<N?͌ &+(Ee0`xokUY`3Ln%SSvAR-9ҠؐK*g(جCz~?+^M;;hW- f.`ApG5+j&[IKVPgEN}nHLp,ϖןzlFFno7Mm lJ޶%q䈎.CCbpcY6YHQx^мlD5a�c@ uxM6D!fedC"$MI'CTD `6= WE sQcg/nJ1x!@ 7Vݒ,?W̼7ߛdysX VW&skQw|BAYue+,u_fH|+]*$b [HЃ1B5˔ q/[+{ŨjPW]ƜV"mWZyT k=y,'"R9<Z|Q+t`{pf8 i 8]vU]R ?hv! /bUUEiμ{HR\M@HhN` IಃR< *d0E;n9^ܦP!bI~]rn=#�hc(Ѥ9?cZ y- ЦX@f'!Vؚ?NyHLT]5b[vMw?' {Y&(p7_d/O08 6%.*ZnuS�xK*[8w8pL j0)i NEyy7cYseY64%"OvEvY(jI ~]IR(GDLDBm GAh! uV+ BX𹱍9'on8 q%YkuKPZ/6V``n0!²\?E^@4ݪ<gQaItauTϙ^qIaIq'6A##0=xx)me%D[VVE"(,nHI˝utA;%Usٛ^L#]SElwEZ4;$N89o"}EׅyK ͱN+Lx/lه~{ֻiGUtp"Eg&WOA(6q?9>?=f݁ M0?2,2]^8/̶ o߳tMSp⊨,c^E.O~LMߜ&f5aLgܫçoԆg"tUMfy&m:{ݳA<YFML+" ${MsQdG7C^ALľ6L;&*9*çGOO4b YJ/-;u!֡&Ab8kZWng ˶I Nb02xvp5 ! D_BR˥Vã w$K~6't22C7\f3E8d"eٮ`h'Hb"a*ƨώ\.PK)GdjH~>prԎr,RCRq7e9}vtt@ՠF"tۆgOGG,H{wH*ua?=xPņu-D!bh؃@ s;O_L wE"Ðu֟DY<8B]>R}pWd6a8<_IDnif@;!~HC1h]TU0!H' 9s+}i6>/ E?6uKLĢkMU"&$Cqgႈ<y c.yZtW 0(A, `9_H<;zP>GOc;ƶ..(v%})q: D2yMW3\S3L~E2.~�uw'}w>.iKSdDnA}Qer)@lLDzDnX L?_92rKO~G(A]@N|U}2-oQ?u}O8[;^킍,@|z 5tIģ\lt.2u4[t ˘zi[ڬXX3L?v G^ ?J2r]}Kg4X5sؕ-$W̴E`Xd4AKtϴ,*zDf&(e:ߞ?59.$6aoh톾C7r\f6$1,6Y V(.yijl:zD6?{73|tY,c^ {K64{@=1�dL8=/=~X#PNN>^X*EX0]dEWxAx3 4xUQv_UH+MYwm\ϵ j,?=.1?퇓TT#9l:4||Iģ~zr|Q~ s g? -iؐvNm3:Bǃ}Sù3` "M(!gu|zO/x//@NOpmFjЫm;~"SVf cY+1J5[z*4E]t9ؗs>H1(JJ+??/cu7zMe%~4s%iSQA?¦% D)FXB~O`/cwI΂DpGEIv{B6KWYg}ez$b۠^ c!`k;]XoP>{;2S8fZp\Qp]~@gFhͷ Ij)p%+2v : 0uM T4wČoHrdwz_{ג,˗Y?[yw$B"Ƶ;,VdË<{%)IyG;Ѥ�F;^u ɳ7=9Ŝzz@W ʼİE0fմehY؋_$ΩWQM;,}<A$?$" A�q8)π}<Z!E&3|8oBx1AiꕨZ׶X0ɐ:)n(%Lbr€eb^A4ЦG?.7]C4 w1&u�kh<KzjթhdIM*urX<9|clϲĞFbjX4.k'C܎MlKٔǻ0dxMHN$[Mهj}؝'h: wXkԬ-(-[ E__CsΠ>';)JsYCD>bB sJ ^|n 2[FKV DIҵ!9rΘ[SO9nv̩yαd&UG D4.G9'Lg]>g%GZCiv7ځcsՉ2~�1h," eխWމ] SxIK7}5X{+V<ݧM4q?V$ B*`r>,l*nzKt]D *'/gVZ?/ѻi rҲ@2~~ڎF+jDXviuoˮ t0e G )pך�/G//�� _/Pp_IK25?$(I•8ڨ^*[ν%3lVp5'j/DC|�&Oh/9ʊ֤6{?NEh.N!-2$J)=0>i]PƘ锖4ʣ]S} ߽sDu8(X>|4SHbEӂ ,E TeQ]W^>K]9�/f{ 8˪\:Μg ~)/!6^z,Z`KsU Ux$93H|HEѫ vKo}<b_8GYXxutJ0>VZRd qfC 7xNܐȖy{2Ek#g3=r�k`օ?{K0,&|1)Ҵ7I6\3Hw/ɼ[N\4{jYԻM[AH7H4<3z@vWΔ6"Gt9JcϐŹ`ê3QsV)^+ 5s0 {|\5]9jXŊ4ƵZCl!B"*!`(sQL+ڮ8ptir54+ʊ[H߮$R~8xzc߭Ip<d àSG*ZN�%YE 4M]B�Æfeۆi̇W}F_n)㠷"_>yTiյ1nT;wZ"gk* V|R2 OE ļ" x@{Ӏwzk֤dMqM]L>j@Ejtd]k@d+yb"75 m΃D Da*6nYgގ|I(!FX< ) n[h \KWWv`^ ;ZWAo0m,)nit/#Y5ծ2DB}'"1% A+*ѫ̐2se<X^M=A'=R Ug!ؑٙ AEHZW4775R4( 7WeD'WF۲() ?x5OF`*hVҬ᜙ Fi:Ieѐ%{sw ̤YGG/:�8]ҒDn8vzuv>`nOǒ5y`L2A7ncA/�$ϵE N^3'Te-!Lg~sÉ? k /al!58wrA$h;@cw5)i-IJZM-$H"0[39b,Sf?U7 ({;qɀ"78;L9a.`u]SW+RT7ÉvN}w→pN =jlNH( IѰs3eo (ki�#2L9?|a),ZrҘ#�;s~R!&6 \Ƕtizz2#1&e\\ ';xyG7wmԤ KY0ӗ,ͦ󈆄)ALZ.+0]Qi`Ȓ"H̽s;{%^srx~RҦmRLz0 T/q+#} <�?T 0p oo`K o9 Xq thriSat-iiEcDٶ%| ^6rkek_Zr"[Da{0JߛVD #Yg?\1$Մt u 4]gXn'yCH-c +x̋,+0F�ƶ[1Mu4sgK৴1ѨKYATu liyU&"� CKH�=ܵkh&<75lj+K{h z]<YIU4߱ sKnBВ<b5j_Ɯ0fx#3Z$!MnZɗiFTmUe 2jkY T?6%Q.pAFǿ X^~I%䅐;e88*7}ɰ i2&w/N JaP]풶Γ,;8?㤠sަBMWMmat~2 @QlixK I9 |4~-{G'G4qE~v|βswYUQj}˼*b4"2\BKc\8ֽx@$E$s nÀXhdqRXE.)\`O/2xI OT"KQf82( !Jة-#PJ12~^q٤aw^٫cg~s 0 '+TQI9^F8^ ̞ϿpɚrElGaC&V4LT.L'3;8KMQ!>kHJXQ"0Q04@|3kz WןSvs7jggAG`ZCOM,`7Iv0@2EdG![fy:v|�qbCE&kND{6wG4Q //~qtk\SE;F8@ɴ]֥h2u3+.PlhO 9AW1x9n7c´30a{QD v%ZW2;]asr27;ޠP*n"9mU&7}f.iuoP]EĒPY`-Ǐ,v3JAmd+lUTW={7x/.\ *@:ev85]4ujh*@0Ó&-jODJw1M˼\8;s0<p=$կZ6K!D\33 Ǩͭ/?h(k@c4e[q$<e>=pg)LC&qUJ,fM\9U˺U,Qgl7E;Emx<9N|jƱӛ`€Wd:*-6,kF10D6__1&҂9U WlMhjzPљzKX,Ód ,stMB:Tap5S +<'dq{֞Wg`#! E9q+Z.q@gL*"\;1�'*\ʶJkwgA;Z(v۩x:eOBC7e$+ֲ|m.+z*p;{i:^>'anVtn?m#`Z \Lg8:}|ghs6Jԧu8)3*ـXq mb몦@>*Gf߽8|2xA:vPEKbSd=|Fcfp,=~709ŸF88bp,̙!Ȋ‡Mڊ-n8C}VVou.+ZmoC[2͊-&Y=gcs~rH)&#�$Y#j~&2IҀt|ltA&`OAc+bH-EKB"tx(jj$1E•W`u)*;ٛVTh;jūEMٔkX-0 )iIlrt6uImfxoqYc[}VX ~dg DCnXQV$$ax1$们q&uTL\.,lGXF n!v4i&q j=phWt āKkƫO.\2O<S+AOs.qSkht AL?mP$t{'dbm A8.TX*5?҈xcNT<CsFr7AjX(q7JC Zd tn47mCFְS:eo|%fq4+ehZB A8ml4e7!,趨-�(Eێ1o =l[v}?\ s6d3radΙ1' g5ku|ifGs?$ 8+%q<ߵ ~,n3ZDPS{oh6WlgԾ)9*W KvqT%E;ۇqڛoq`pt0aE1㇅Ni4@n+<Cf*h0MCGNn."xFnp{$k.SiCK2q– 2 Ѳ<M0p,0fwGte MW3o9eubU 5': L(q\]a_ �v$n4f7bYl:C/y<ό Bs7M״\ܷN-;Kt= CdFv:X\7j叆Ga{A6 5/XPMvoHaG{gXъk8hm>C R�1sK�|~6}+gJ3!&%h )2iAQi- Y0 ]S~(M4Ӳ4~8 zl"tu썟˪X(8@tM~߻:=;d0P@&EjI*3ӫ`knnUyeՎJ+IlÃPj,5QS O:OxI=ib{䮍dYOiC#%s; *Za: \5*q pPt~U=xo|EĚe2"Y{cXARu%%9"?pJx򰁄GzGzGzGzGzGzGzGzGzGzGzGzGzGzGzGzGzGzoHn23h*d7;4t?cYqXU[vS8[.<EУ,טݘ8yooA#"Cܴ*kR<"0NjE;) Naj$z\->_],A4Vs@reݛqYe71,흟 XAe,ِj,"cf/Ɋ:S20WzRW8Pyp?}sf9^t6dڮq"Sz [ RvGtF\E}*9|wڟL'+~a֭*O#{ǏZuu39,ue YQ׽{e+X5n/5ٞb>BkFhhզJ}?ժʲ4rL7CG=8Df;Ⱥ6 ?7г?d8yfkO\V 9IkCK>Tv(& 8}O{�(Ch4皕tmrCӋn"BنLM[A{D Œ9ۺ,Oo~ɖ@Z%6u??m. "'p%oI^5&]f{}<47ʋѿ*')nQY-mSxߛzdAJ<GZ:w!l[8U],4~ /*o<30W uͶ -s~3d\B+Q2 'IB@\Ҥ8pAU {f9AZMYl.Sr܀Z!ιq0: 8A%S W|C9㜂Ǭs{,J[zdq2>cQ6d Le.,e~HnEyͩ)Oƶ$eWm4;SZL�k v'SPe '6;O{ S!٧UD1,-yj$�ϴjFW"ߖՎMZ:#a]8fp~&ZY:(SpaNޟ6`ߔGcY+"k>I<d ,uȨ~F~o%yY{ql wGL -3gd`9g οzd{^Gl$jz*^I<2sN ^ʬBܨq̦M{Mj>. E~nv.MEe'i 81PJdJ(<mjheCt;*54jz՘FH4cΈ`DAI NP̰iN( {"#pJ0ij_n"p`?K|%骈YnDKoK'~lQ0.6d@`@Qݱ yͰhon =XkV}WX(8�"[$ (S }ۜ`e}jh�fefIq >(P"7R'=IGu+ qa/p刑dv Uaǟ.ө6HIM^0OЄՔℇꑪAg̠AQ1 ӑ^HP  }l1|%n*q9By1]&+_Aߗ8(h.jns[kb%Uf+jN3ˋnDhFWlo}܊lqlFsp(UD0䠖 I ,跃2Dd<>yYPKY]󒢲秜i-:-~  ;A?XtTDZ�+uҎlS:iL .޿30t6YLN8 MnNA; HNhػ-ׁLsѢDU%80J[d{"7$Pe]^-8_hJ6r%jjJ+&HT6f+mcV"a0:S BZD)4 J %..?'׋ 59-Y横P!-d+nDf0tU�l]p d$:^^BM?N8yGGL_rVEe j.߀!s 8Y:auzxEA'+}vG%?sG&d:9?ĝWA%C"@b{dmRn,MW Z.p^AwD~G vu}~ӈ(65++. "繖ĪazۓFU%lʝǢ<5DWrGPMWOSjD "EHeDjt g*<d%Q侶Lt݄zah�g DĪlb 2X\̏^"9n*hM*l}p M'@3U$\Ь }m5g� ҹ<6|KJް]Y(6;H~y�nF8y!ud'5%_Ȱ=KX^Uk*OJ7i"ukd[�,ޯ4ןQ uֈOSI*"~Ef(W+cq!#i鈢슑#p-QT:UbAy\Ӻu$W^iJ9Hmȋy=A|55,~2! k02fl$>DÃ=aH'_g�XU/oY~x3}E Q EQ2+ҵMiPv[͜ Rx1*P|?x4[p6Aov7]P@DiCX^uzoα1 is nG5:%~ w QYTBMK^|}1@!*; > `Em炗0b7AEN/z,D_k}c'=Q-%y_}~qMg% x' Dor8,2+V ޢTlU*FW AAtfCϺ;*-l?BZ-%%Lӈ Qc" 7=t<(U& edN3h2IU{"=VѭZ~c[5p"IԖE^PI@] I^0cA1&CVZh8^HogyD&kYLiB)J az(~#uꂫW{]Kwm.Ny=Zvmww"(Iuk!Ol_>PDl)HIA/C?B-ͣ?<4 URp- ٶ/<{Z /²'gD }320Z\ :vQ<4i]Ďpd$&TCDTjׯ~xAIUu;9l¨8hj@͗,ѭ\ǸkeAz-34(n[KTwwGAkqx=?Q(tv?(!A6t8{Ho*e'a<Q@?m-g$n֎P׏Ndod5=BQ71#p" Vq 0#' PЉ4"=@ 1F(Paz״jmrzUӒƖX„8rѦG1N`LE{P#;`[|A.p<{ ޮm?L-ׁ5( j$eŸT[*hˏӼD94TI/J4˫?H'xbJĭE CS駗'A�8#$L _X7hl8LHv%42}6 V4T"փ SA3%]oRWK[7?LY^$=jm ?dA ~wMj 7  !3fG(;є'ވc c]j{{ipK j rLDSnz@XPQ6H*N޼t1hQk">lIquYe65^ňbrI9t|2b$j3H9o @E[J|e/őȹ}>t]_h mW ZTJ( n]]\x?Hfi9bf |D W@[`I&5e>C=r,,/)NBhrM6Iڲ ~yAZWWsxEe^r^HH,";CeE6FK<TԓM;H5#?Tݸ>yG]h>r嶇"OlNV*)6mr1gddfH)2s!}X^BAn'O<<B Zx3Ȟ_mձ>Rӏyͭ*QL$F*r-y kNϏ+�8:q~9(A OO=}!Ojk�Iy- [ ,hAW8B1G_A{]Q a`XePbHZJQ<nHDz'<6vڢ , Qv~'OB9 VsG:.2z.xuM P|[6sDed{]mS6'O^1T'H ?=}Q6(p4P(wY8e9iUl2咕pMf Pnl#lG?9`k&eՐUᵄz 6?i4Cf!*=,, ;#΢B i!._=y򊉫aKMȦ׹z˓g?>y`4�[֛a5EznuhfMG}�Uc̲*W{<Ԫhb~Ev />y_�6F gh}fWz)VqV}}шI-[%w0?~1xȓ_G~U.T4W˟=]E6oCO2;f'X0a$M~nVmt 5ǿ uYø[e,У!}si=M[f@()�t0yAՆ*~.2#4[.>M\,26&5usГݓ#šb/"�;W!0#vQCt7XT8| \KXH Ր;Dct`MBw&oKfs`˾ѺZ]ZYjmF.xM8OWGxZM;\| f@$~3sN,�S>t5#; >3洢*gI$>~㋑@F>xu\GO_A}p{la h9D`;릮wo||1E5v5(j<">ۥSVe,㧏=)<CSfnXu۱:EX"OM.j6dkϰOr&%Ѱ9"OFO?~d"jY J gcez϶Z'tMAYW$uDiM~|^'O~+Pĕ7~PnHj'nh跇g�~vvbP~wם a!rb.CVX5l'Mzó7K@Sbm?n'É>F!1ychV7 yDp[ #0|�ZA</Dx u@U5ı�® t8I6E3Tנkݠ=lKLUkvq\o('`4xO-}�cR PER-d!*TG~9H'gD7A,z{Y)Z )㟅H!j1 Ql.K ][:]GQF CI%C^b5&'hg/GjTspջOـHIm="NWS8mSe(K`3ATVM u'OɏfǸ9 _{<yǩ5ypAP<Sn6MC^]EVNVru&d! 69 s</`tgi6TH8C Fm }\ċ%=T'궻a1L`<ׯǬU 5&~YICr_d T3Nѽ1~1^H -Y^~^KwWc_aiAaFȱ<}y25SǸ,Y Q皜Npσ@Ӛ$; 0ٛ9.0ej;\7 Z3Oj@5UUhdueZC낰kux2p+l'Җl3^a'X6[WP-˶R~_z]'Gne}i QV6E#~3?!~ۥ@"SwPSgo9q(L.a͋~Zwxoש>RޞjI-Vq)'ݾZM؛-Bgn_{֤ĭ^{17$N- c^խ=:9#-k~-;۟ޮ܂wX> g>5y煑8 V)-Iyt ʹxKs rzOs`WzC#'/ .G7ܳ@ ,)Qak"kE`N tIqA=Á~n-}㺭 !|V?BPlk}]d . uQ5-4_ϛof 6ZCYd;1}^auy1s+ؑWρM*F;.֣kש1t:-Y^{˔)F&"쩁\I) c@D>)TlbzVxeI΄ !v˰t_|zq5%E!/^5+7y-Oo_ϵ^Mfd pRO" yRDr!6Hn D+]\m/Ƀ"Tu/Bh8D$^Sݦj_үHTNcxg?e=与d"4<lSMSs8,ބ6c֤ḧ́T[~+?&#G96$ݐɼw&cf]CJo0�yu͛$ ]gg3eňj pN;[3aYFc/N:M@�Jz&yveMo:qUxYbՈ,ha;rBG�wTmy"2\ x D%\ɪ'> ’34 s xN2]$#&Mi=&m־0fu{a{4C}qGΔ1 t}v )l}пrhF'WKNy_Yz�":o /VY䇮&]lH9.7'4TEWlpJMs_TՂTM?\ģEWn9>Yݐ9*5$siM$t88 �2ƣh:E Qs4t@3ZPfEJ"+w?*8!xG&,G>-iWc%t8RUEfqurrv=_L'W uZ3&(g/|ӳlAsÉ4<#$:M{X!Ir0! fMhs٘bi]}xy8is5bD19ْdhɵ5׈•bz⊥R%;wd=D0>=}<)g_I"4Y,_~lDu'fý57m3+^yChnOz �Y/N?A8ݗ a3OOώ?tLC *%3CS_Lm3݄%|쯚W/ʒ_/QԄ Jy{Biuׯ}>P<_PTETlw,ٸH]<78yEdňyDAȅ"4Tqۂp?s8xhp-۱ "5^<\ ImYlxݔuU6S8V5`iң&q;ݻ[!x9Q3mANŒ׻%l!B /'`&6Şp=uBWqAU"q2;Z(O#2 e.X q5yr{ߑH�|䨳WS�/a(R[Uz)$<H c|ūUR4ˑ{2C@`~Tvd>\Dh?f`%bo5] 1E^xŎnjRĚ�Ҧ0Fqёy8uht{:Uћs⌤"np*@ױ ,ciJPǶe;u` FuFd4o*ۑ,iX_ѬTе#!8 Mg9Y)qS9\BipRZ!0}j>"{&(MsVAPiwCOyx/wMWh u*b[-KRS=~=lvcfNhRUɡpSA*A8>!IۆBO9IraΧӳќUM"ww'G!_}$rƐ<[r 'e6sw׼0=b4ǵ{?݂6j!jne oml7U�X#:%5 Rw__\(|5=;[j57d<c6"lp1pwjۖu2 ~G�ZVǎ*F><p|KWDnvy~5-)Teu~:窜ecSD^ tfE-2up C.@C''4+!>)"~A؆br%K^D KӰ݂j%/~f{{ijΡ:<C-/fU@ .]G6!Ql6`:(lsqЗ/F=yC-^ `/1PB(>ɊUMCR!gUX2 h@xL>\g:}5_r:g8%qFLQVUJ|J^ke`S.F A˴tG{rM9WCxf,-N8棳+ló@RdH $ _BbϺ?YKE LF|i!P"( L2}C[~|s_a+o@T _\Iw)xk? |~$y"ܐ&,cEfC-/)|<nr`SyPsNbӅ .*xs!dӆo#bͮӯwsT<Ȏgj6,) b7Xv@?Iְ"5g%!Y yp<l\, rdu!KjHPaLuSDa~r"(PDs }0י[$Z0ׄrE(ϵ (m0t&Zk<r*ƺ/>A%9ߐqnN--ku<00l4ڶNj+pؤӼ귘Th^ 04D~ "ÊL7"I [GϮ眂/.CO-@y~ݗ/_},KG~:ӄmW^^X0CeZI i>0p ߿ׁ& moK3F+uU䗧_] R IWb6dYU`g+V^jK3pM/_v5>S_-i}KSI hp %N K~x߯+8y"%}pr "[4{0ͦtUqnJ\]L)‘Z r\mRrf "5:1)R yErxw!m;<Ep.)9. `T5ܜғ0F@VG|olKRXB4�-`W.LN^SxF=t`tk\6wmJt+̛ۋL75NH|l }jkx@ |x%fUFbG�P7jj8N7o$㠛.l킦%g5ẙZiyMh($C'E"luڄ9 x䪆^xh?A+N} =fTDhbY;ܓkTn]ei}"hWJ~�aZzY/`kSUb89Z<ljq7ʑٶ> 2vuY,QR-)n]PREh loMGWQ&8UrI- Vxp myi^ė.y- ^"MN # fMi>x trɁ,]sHRJ<P痬vqc G&R`P t49jz|o:f$ITۺ,HS\3ے[x7osz=CКٮ]iSo9~AyYqB�~15Ɋ|x8by*sNѝ{-䠚Eﺠ*˥l94yzLjϯ.W��+<CЌW/oS ےMx 8>b :[~U!'GG/G".;MC:'Z_=Sl<A38oGGih"Ud{ѡ R,lCf')tP_ MuVv-f+v R_wy fu܁^WM5T]JT Rj`QX%/d�p m/7u+�y* d9 bJsˢ<w(ͫ2K<SdeM֑sQ*Ka[oRhE\tGW `/{P�|@#!#?HlcM<;kY|tF �?'g7LYJ$FEP.Ff1_�s4=]334HAYНx@Gq̿^i7y`k*x %(A|?JinDݍ څ(i~YF ..C%'˼32ԁ^:@U$?jKMDH#0CeG%,mmI'S!ߗ<0k߇,kk%jcB,|-[/z0: ,p}fg%w7GI,oe9 _(LtkvM bjT"UH%I a{_Af0k.cٍ.sىM] j<4Ra(i?,9;Be~S:T*#gU%icˌoc%AGϷf+45wgG)e8Ï"[=j!:_Gy+E7[g>}ʆ妯A,'bћOcVTdIq>M-6 iʜuLLu߆G%żѧ+Z\nuX)Hד8݄ .fFPn"Nk$ˢ�jknU%9d(NӢApTM/SrҗT [#6gU]z4SE ڎ n* ȇ88辧͒a']aj5ao]UՊ WGel؁|ahT#jLX|?`aIQ#_}&F^l3݁~m$|8D <5fT?85a@^905GK)[_6*K9\sf}tƼjXWMljlOhQAa^؋x);<5X$4sdDo|A7�SkOf+ˏt-J&i^mn 74UŌP%u(򳓅acp+:-Hm7iRY SӰn4>RۭKܔ7]ej^IRՑGΗ\eulH̊ IsB~iRa:^;oBAq\>ݗ/+LY)^ і?t^"Ml&kn5yh)~]F<N),e+Yg~RSNP\|y?mĤ?цD9wTj*lh1syP3wme[LӮYyF~SŮ&Kbɝ]V>X G*x.3_k&39ox%3),%Y&8ivZ(}QFW8]!>ncGD kYE,Ro3릡 9D|]=B#6k2_Ҝ(/;)Cٮ#Gx2xT *DLօ)仛/#cU*T¦kRK檉Ba0Sr <G4 LIF ydTM?t a>eT+"ǶۨKS =4]We V"e[qFifm-4Qs&D[+b:þ'�nTvH@fCel�:v4MZ.$ul}9$)g'aE랰yylMTn9.V4-q+I߿vAv#/E-&Tazbv|zMB(E_-t+\iilKCQF5 Gҫ%]w8Cϱ4$G}?-B]"?O7O8^]_кuDdt|\!3R%qWb0J| ff Oo89hZӞ&O_?]}xi4x&hsBŞ�\{*5 U,Lld wqˮd3`KOSN/O޼3<7ЂK:f+zdojNlޭCUTt7LbPeEUeD͠$"{(%Q $>GѻW'Lx|>#whɘUxM|]:nTk| ߇  KUuNT!!-rUߗ>|<|Tu]f+Y L%#\m ;-Mb6E~RE! (= E@J?D'7d\_[z(<4fZXE^!U^F*!t}�Fxh ;�1Oxov>$^QhqZԼĖ'0ƇP%ᵠF*5=Q{5BgiAA5&܉y;(`#*aqC[9IҊhٶmJcQ8r {"1.!;|4DaxY5 DNdֺN<x)f\0>dE: <KTH!BCޯ[dN|lzeVP+-S $ga9ӢfUHS yȼِq>~ @)2(ڪ,1 *#_D ?`iF�IV: %j̏^>?-Q@,(0?_xA}b%(.s+u@4@ D`k3;*2 ||4]F CʷM N"O<}%BhUuabos bTu{&/^~>-%Z <Lt$y �n I&5:+ )]c*Oqjt"De( ,U"]8]z@j[5a 2;;0(k%$:*ۮ})r9 $#5 hjW;u|.cpPߞLx9%E;t*pA&y[x=f)d6N?B-H�7`N۔e6g+o^hj>V'F? q'Crф1G74R+r:CuQt#ZǨTxQŨd"'3^h!A_Nc[Oia5hpI)r< ,Hnࢋ+@n)� Ŕ67N-!{ j4(أuۓLGTo%᪦(gE8ԤꕢkAրӲ6d0FöfFP7+B[W?`/gGEvrW=!ZYhr"@e<*dBԕD[R(=C &AL$4@JMc?s$!#Q!`O$�'Lҧ>4bѴ)B''֛B֌][D3춇h"x4T U a UjBp2>/N|DjB{Y!²PޑBNtQijV4 LG~۠o* k5[O2(噚/hѪqD 5]&̯>?Z֠"Jf0Wّ~p-.!7D(<T@{3M5Q8KD-BpOe"&bݔϮf+v X\ B HK=xeE^1pZ'QXbSdHkAh"?zũ?^u _>N_qVEd=EP�MTBG$eid.S~4%%˚c>�;U!.@_i殩ޣ(8A:(ҒH$k iK@ȫTz]]oUIgY}ّAٍ@FF0;d0| z(2+]aqZH5~xy:HM.F8 Pi4#$p0+JM96; r"0k,!q<sN5u|gB(u͎tC)PYEtx#5t;CbM(+(}!Hh46l&[sXxH2"]m,#i 4F$)t�}-S&B8%8F!B[^ QZD Q6ʼn]F59]23 5 JKh4xh3 ~z�mM<p nM(rxn e%n$i` t`$Zo).ĉ,-9  !_ϗXe)BWYc3\KF5 :9mҸFB5=hn*R}z,_lp`<ݬ#�,-2׫G:�\gg Ë".CHQzPj#T6)HF*?.F06QuGJo_J° I)ӓ>g_mKX 8 w.\]_\޵gK'1XqNn;m �.^7l ̘(tO|=>^j;u�]mI| "* `{ PnpZTp_x3 (=PcC.b䶛™G'afǬHgO&lo?SuU,C`tHFrxBov̛J/PFDcH X<~yd)C9.؎b4ߛs4E|Kӌ'jFz, h?x7j@A=BՍ i[7�BcRP{q24/' Y9}Ǔ9"nD*4e>{⛋PB:-q;'"sӤo_lE)q0Uj*4R!bu\$d;i RE a{/Sʆn+] n 1ה_z}Q)q?Ci. Ns2K9Ρ,Vڡu"߱Hsetr'nCUT\zcxrHf~I$=q]̯/e>,noh~GBO4 tSL_O"*"uzx=O"Ba{vdRUT@Mv ms].2r_=_|+$d`ѱnp+"~a|˯8פUJǛ5ă(QAduXo0w\dtyZ}D1zދ슘 ]% &o^zZ)~R#"n;a!�"A=V+4oeW|wmӴd^A]O$*i媬# o& {~xMz wf�ۇzRghY;JzRJ,)o-,=*ؼϟ|/*j[}9-a]veQˆݳ]O5\x&j~Gq;F_G(ӛACQII=nCK z p9=ZN^b䐬PA&.It|2_2j:eޣi"o h*XoFV4˚(5J[XW?IV= INoӸ2pCE[lZ V졙v6rnH-CuYmDBxͱ1Dq #ZFfn!0Xc&Y&3ް{^8Dx^@HxQ_1<D#\]1d՘:EAL^M[z0۠Na� (nJ q|t1c@7tĨm;^5, &# xID{A΢,ʪȋG�bj*xf;:Vmx#i:fj:$YAxB@׻ĥ` Fx ˺,, /"|q^u A=|PeAb# :`3t,|gA V iV'{^N+ېfSC#u@=x$B|_Ǔ0y@:KsnA,,CqCZxׯak̢uz6_R "�]~q 7,.6-ZdV+�7 'm癏ڑ֨`J`%@ք�F "ڴ!:w48c[7W"#ZaaIқHR{x_|t57a1)HRz4=h!/-Ő55r׻=QPI4|Hg_?uG% ,c+!ɕA1N4A&;ɖkfe$DT&d=[tI{#} {&W?~ 4&]*P8e2VdIQB5/|]:M:kюR%09o@C\/HJ%R}v$ٺ=W%SpdޟB1K,',j|>DK€-j+0x,Bl+sڛ[`$r[`MN56j _u|/>mUG2}#6p9f{ j @*Gq1QCR{z7l_Bh*pMb`I]5ԤҢ79Sh(5 [o^~ =)+h3dXӁ/D ߺwZ]M WAm 'p '1=? 3�Õ {&F/GiAw$K << B0\s|=Mui5;[HtOaMYCI*]K kiuzoQE ߞ/-2&(1]so"Y'iܲm]s$__uW$@K+oo-Q{G6<Ym8+k4[z$5@/4:$F18~)iI)eu$Җ6Aӣ} P,a>U=/X*[lϷ#Ά4[ Ha}a�~fBdXͨȆc v,/"˰Dc_wy1$%0tTv.ZKkdvfȑ r񧿽cҮۉ z]$틎#fM�0xtqy9̘5]-$E/sUbhR`C0TOrAOe!۶pt(+RD{?gE'Vb6_.܏<AvܼPvUgbM\NC{M&#!ǙK.ȑ$0&mm5} L耖c0]4cdYU|9@v=, ScgfD:Jށ�EW? `& oH\HC[$h*ȍ%QQ{{w4t-Ӑ'/ D3L.ɼYC0j5/*Z9dbt@ќL \hlUCay[~zlr()ض (HBW "}ix#8,3uKx%ab "PQ>[YCq%YV4+&ţ T8p$8N,/RGNjIWleɪ`^+&~gFcJˋã9p;G*OX&{P<|bɲx$-m<#i oDa v=a0F?_XA`IU@fVlHmq{rmHÏ,^O;rH+Ӛr K1#/C0Y=p:ź0=;/9AXVt䚷-+ɍH'5·pDe'1lnv>ՑI˳rXL.N/sF2 3M:;>o˰]'kښfR4"3exQ!pC[yY7EŻtt~E?t�O߿xrv5N'%/)&K>-v]CH +lѩ‰aK MHZ$ V+Gӳl,fW_V{5axFt!nKc,�<+,h8jL#=JL6A%`U\^LY8\)rq>օ90z<ΧRPf3wyF;`$vaʎcEG$%V$5ficx!b>Ѝ^Jpo~uxǑqNW d[J%4}^ "QyA+ߙo)%}P?oS,]OFcv:,CW:zޕ(NPb/~J%uOR.lںo61a)f| VȲfڮ.$f6]uݕkAhiP8i{[o*$) kgz8ǀXj }0^.&0J4\GŒW|kq\FG�o\/yNIS1G;E cZ�yIF2_!n I-I\cG ׂr'fj l>[rgY9^L4M:h>JHF51˟(@Go63fӆ)X$`1 "'y>?xyղ'<�0�>dztYu.g8g8NA+MOzwӋ֫6Q;tLd[QյEUob}T@$rWخNh 4{ҕ 7c*r9 Às)UMC<; wsUٖiY^Pw`FMMlZK뤃,}�n3H0Zϗx*].OJ&mhaqxc@[yKgM1B *5zaU$Q`~w`ޤ$)ۅ#>B]^CG:g7,d?1[Y"һčo4X�OW,geYd+%=u.^'Wɇ؟7,HuU 18oO:sfRA?@hv97KVt#x1z7` _\bl6X@£䕗1`j 8$B5ø]$αOq:^xmv{",'g޽;<0wϔCElC!-Et [~E*u6 ;]*w瀪LEE#-]Ž jFg)6 jB?S]'(l\L,'(V~}dd6 m幻Z8<4UfYf6^ rMb<xAaKgSVR+؅QD34@ٌٜdknq�Umv%*i߮xALx(wU_3mȝ>ʠ1Tggo5h^X̥ l*ؑ8y~Î{?b%ovy] xMYXU> NAb/?\Ɇ g0Pdiѓ"JnkE w(1Ɍnk#P,iʐ$q*cF,;HIsG`u<}%yWD@vJ|bt:%.ε(^! l]Oxu\F2W9I[줸B̀#(HzLI-K%٠5]F@L0ܬ}MyQg1i&4Sޭo>m78Ep gA֗@y1 |'ȬQ=Н&u<k"M!u}Syi$8&%A"4dSˡ* 7Z$A?#]3 0C]YPԦ :Xz؃X ҜTߢvhd&0+KJ >=̫%m:p0귮*.ƗS0-oUy`ُ<1A{z`#Qږ1񁜆,̏ Y00e+xk2,�J 0-z*wvF 3 `;_>\d,.�!I>nVeQMG|0qt_/>X׷ _]Mk5%q~vqpl$(}@DnnomstUZO$3'MwK(IҼ|u$h4 *GggSGȝMыjO e<Vֺk/ˍONw]F mBتPuji1t6;p P8 ;zĶ&.E]gkKwjן@u!(t=CfK39dHZnEZ�Ws6:f7E蛟WK. ~i@[QU p8>uM[E~t*ˊdPl8Qmӓ8KMVDb:y,mk~c� yhUEQRteG/o7!.^  _hU8d#aq� &4ulix5$d6\*gL0'A@][6CS|s, )5F�4+q:uti|�sloI6)6I g ;iY)1�\`Zp6a̅yRl]CC/pW-Y7eg+p"gϧKe+Edt$N=�~0'-CYUͩ5$Bl|t]4烳d>53l2G^[J ,kA"#4MOJLR! E U>TÔXl$zxDx`2?$xb8<YzM[&]=?`@LU90ZN3{qm~N^S^VU+۔ LD.n>{ib gh‚TұO=":K*[DƜ.8Dmq"kVPSonJ�#Roo[&rf8?iO0Ad5 1'`r{g9EVu�77)Oy^ {Ɍ8�KˉlyqlA?@PR; x]6>ޒQ66\Nu{DG4L*,5܂@Ds \)\'�o?<+$5%&^@`4s/mZ৙h fv-G8|63@3%'Kk)ه<5G)8\XtBϦ(tqՌiՄK Cפ pumJv[e8Eq ϒ?RViķ˩kp1�gӺv-ǟ> v ȷ uv2ќ<0Ж-dpURքџ-?dXKt9I ۦ.`8+PPSvef N$8Żg1DT_ ƚ-Ypq65 ʝUbPxSbLI02 H^ �~>~VDF( \k)8MuCE\RsMCk~*~dE\ }dzZOi=zZOi=zZOi=zZOi=zZOi\!Κ+6YA5\ZEԢ4 lzdOnRf4¼ʐJ7dY=IdmԢa( Dʡ 1fM]gl(jB֝U˅+K]Mw!73vST r"$ &YXYC-H?clX4 }x+<;ÙuUD_m7U9QUuLMɊBSuwgݹx k6Cb)2Kms/W^TЬ,=m1Yj>X>~>(-ʢvH=PM!̦6 I~hMgK~aiGiͦ M/{r핹c1G O m3A][KDQZU` ߌ AvAt$#+{b /6~5+,fh]4QWmW-Aڒ:Ot}.|k=aMyru SgmQV-\ASVV<M;RKV{byq6؃"BSʫ3`;a{sC/UhۆHN|&'ݶu pwjUQ 8׷2T 99]߳hC;A0Ͷwo?*˲T8�> h*OéB˾b.=\ū+KRgĎE/])؋e57xDMk 'L~IxmcrL&qoih_-4z}ss23,WgAoKsΪ^o|j8h'K< )o'} "xYտ/&HCWEQ2U (|p*[aRДƊ}`b@40F5%w m͝vɋᐑ=[jT-Y1ubFm8%DڛuڈuS)^4U!Z?h *4C3 /ĒF=8w#Y;cm}s-ēp}[@ ,bGmW:7AіSO-t9q7]⩊~y$ C.ILst}PFPh?ƙkf}W?qgIdiOfrn[ӦW^C|f64Eǿw]$Y5Sk829�:sr$Op{N;x1ck_W`9oj<}J׭(#,7�O An9t]fjˣ L? l9 I_qj7-V~h8lckʹkiddh8 ɽAؓhgSIs 畖([1܆70(Q6C_,u›Qd0Eʛ?Xn|΍.,̦ D2j<ZJcZ0qI0HP#G{W{翈Ȇf;=f9Hq#2^(6]�>TaGjB݉sw 釟xp|. <L;W cf.$Pe_|e;m`rؗ(j߭" RJrҮ#kK>]]|zݯCNX 9ɟ\Ȗ_ݦ$XXʂm?N@R=ȴ!P Fns[Jl]'Ó\t /=CLL|K(]mJϰB-9$wL*vhϐlIoHR3` pn5q2Wʣ$/C[=+_1kTYޠl*ѥҘ&ԮHu#qўqUM}.I0TR}xHܬ뮍l;wD׻ciQ# EzSaV#%@zGRmm1*%3g@F$:E4֌}ϘIwCR�o4@4$ixFɆ>?fR*?53P w_a�VҍhQzӖyN'H<jBvΛva6 ؒݺ4[< Ӳ Dt ؇ݵyD( LCPUEEQAeV4L] ǰcFep֡&9 5(➩cJ7H|^l8dN_!PW(t*ejHgLjͼr0T9 )VQL[&pM(|䓔»4NAk/6֩gB}th뻋A?y9?S&. B@Ҥ("ҥeUwk|C"LgmUŖ/$+):O,Ez4S%AUjlI;8A4 >4ʑi_hDFA-#SfHoշ)ExQW \-<JGb1Ec[̈;$ z1@�$I*F z #&2VdVdThHX!<c~Px[:)R25.wp,pl@/FHZIjPQ5+ZaC,ia%fi:GYOF#D|8J$&+}0w7!ݦ,</sxƋ$…g =tK*(`u]c^M @酒J' r1DHNQm2$ :B@D:2j>r#?D(#Oy$f9^T`guEi+ɂ+P ,"yI8Rt 58J:N)l@qo\%X@"TGd%MRuH/"$&ibX꾌pBSEa>_q�5H5,M#[NE %AIP̅,a0TG9wD/2Z)I>x@GrlwPB0*`Uc$9ZE9 $Q%r&ݵ .j}"<vA q{v{ D}xL4:=Z;ѵheLhM/b|s%xY'=L#~shZMAVѡўȍ?"DJpxn}})n$Z2i�#s L UZ,$sB :aҝ!)ip eu(|{OnUfBey>}`0-b; D C@#SԃEv=U$,N^JH=Ug;RgII^omd&GW05 P!F,3,Fm߶.w]7nV=<r騯]V!N_<PT#H@b;f]quF9 ,Ņe$5ğeCHlkP -ɫ]6r[HM{~ Wd5ItoPמ|t؋&/3� 7m:(L=:u ;ыw8e=6t-Ž= i&<duط,kDX,|JLNvPNI<1@ƽmJ/`YjMHgs#mF*1 @5GJ/ 'teݛ.δB[[Jd32)MXAxR$o@ oe߰>N)S"=ݮ/J,%ie<VnتCB lҾ%9[|+L(h8y J`yGc}7Jͻ=4j3`/Y̓ReF҇aP,21@IP#~@4; |ABܛ:蘑HqDCh7|uF"aI?U.FԐmB[:8(%RȤr�9u A 2YTszK;UI#/,N!J/m2D<pm^I΃W Toч PR86{@p]R˺\Rt;nv(_JY h6y o@hH\cɎ SETl@MseY`%it2|=5LI13M*zF"7TU_ &P&1JRfEʵܢ閶&M{gg痃 k?Nki ?bŶnoo9 tج-QggW+*&ڽ" gcO0۹򃋋pBW(t?8:YpW0e&lvzk�x$Z2v=/xB_SD~'wĨ:?(6e"'@�mXulӾw()!Κ5ﯙ(im2/1vPV']R0Gppw:~f]Fp)&B8\F$\&6C MzC3SFh3lO$MJ90.֩6Ĭ$bdAP]]Dw_Gմܸ&Ž͡?C}G}$Awr hnc= S<^1c#y=:㹹aCCsYYͷLF+4eN'߅4>xSc%2K-C oHcg3XV]aǁ:k`v>}_OԚ,e΍APӸY rjcޮJ4\ˎ*oDɛkHC{ԝ"իo6Kk6*R뫲,8𮟐4Kw& 5rk3ϲ N1 u;q鶐B,3]WM?^xù[a5Z(3?Œ鎠AIM=Ӿ߬!E3:p2q-'l Ck>4u?^|͛yrgtYW~zv>w: f|Z0+R4gQ˖撑mPwtϿ˿3b P442~:\y!|�^No) {<<]!AXi8xu�NyGWM`x퉙ahȫiѱJ_/-yEf&A0MҚ)[pH|xeN%Êj`-tVsp뗿 ]UUһ勗/~4Vx I`M_\w}2g/F4ݻ kdՄĘz{X0p6?-Ͽ; "Ǐ&W5+*!]Cn_"]O9QV6MȳJ}Lq\?&ȎiHoׇRex3.Q_b, u0^~NLb.5Z�K $Yf;'9~l�hrQ9مw TTEUu[&0Ip`lIL1.ӿ|rNXȰAUjs@ bn1B@EDi'xn\z6.Xnop_yo(qW!x4WS�R`)B"C#W3^EIQ M{e0|H1�֊sb0G YTDŏð9L78__|~Ԏ>KquNnʺβ*M_n<Paa@PkQ"^<hl/K{o^MYBT{fw6Ԋ0_,{<y=ЅaupKEK�pԙ[ȫ.|B2,2c~F_e V^X;ҴG3Cx) =(ͰńJىuK\8\pWTby\hk;R 5ZׇmI[!mGo79t:W_2!G%ő?z͋<2'XnMi+T ʴ?y1~:Bl[t�b(shsUQ/_'az[j[wVYenN{<`K1f =h:CeE*(/1%3u4jT]J$5]n)x<}~?>8j]x!{féSoeUh~ݳ< ͤ}eE6Amzd[ņ8zLu' { :MB<F�~f)�$߽4;{PA.j5ʜ>mW+^ {_n. uYːy]Gɗ/"1`%0uPԮX_w=F)E=Fu,+0/Xv4/тg~>Q3B!+f6q߄eR`yةkY+q2/-ٮ8)|AyEi{:M x`mENJE(lɹ]3bNlH ;~>6S%|{w E'[ezO]?vnoHXo8>Ϡb�*m\!RZak^dGorߺn\#s$>NV|Yܐ{y΅5[YSakp.|<ձɍx'L󪩰og�:nuL_خ'ָU^0*n J芼Rxzrt(f6Iv,9<wS 8Roby(.Ѻ'oY[o߮av9e Ca&MVxi6;>kM=er4\7(pr ̼=iw,~P2cXa)5{LdeݥcP0@a%)ܭ&Mj`54 'w�O$;6 歃m%IjudIB{݄m=Njj(,f9<~HG// O/ű=MU^uU@Q@9ʗ)bInmݡUC1iWAL"TE�0`. *|MC;*%2ЪMeB.+۬}-\-[n|Dg5'aZkx0"Tox ۆtvLtjƢ"\:x0Zp<1p7"qalxVE`#Vs6 N<:t: qOW`EF[`gǓ|d`[}8q i.Q~.R߿:!޲c҄姷dEդ$Ztņz)߽p7紜NQf<^P{ 㩬 !h쮆~o,Le18xdM7L7HpʎN?`BR|x3Λ銺 fv u arnȼς{o!Z^y.Ύ> Yƻ N9)["۳]kݱ0w\PMSrRfú<tl? =X 7̚];C͙lC]~p<U3Le( :xBP^V4d;dR%ޔD"Yayqy4 p0$bMO?}c()|ױ!(A 9Թ?R5Q>Io!؞6Tm(R+,]}q~:gѧB"rzsDRTa?Քaڶϔy]rqaC\ VgFt*&gц/"rL熗WWVF@dp_;O((`vT f4Ybd;IZ!в?jcJg!L_^u0Fܿx4DEh4]Bqloys( 7|ƻij ]jBw#^}* 0Fo2TXVf�Zo|U$ P-fAHZ|ewe\|0$U٠?K؆WWu g#,1hlX%R:<pYTIQa;m;-%'QU^] r= k<U6?^ZSd4!B ^65A_1 Av <H�pp̫xm 7ۆi s1ԟ/x5f-ݻbH_e; ^uqd{]z3qU[Y0 4tޜg[mmחEʕ3Ƅ�9AVTwTu vVX4%b ;`!Dx_QCiΚ`=չO4x}4g*~y^R?S!8Ң)Vc ~xe?ܷٲ: -US,W^W(O1u옚(xr__]𦟷PA<{�Q+-Slòٲ+?6uLEqcB( lNU�N0R x.jm[@Bn:4+jvIkf9.^nLT$ٮ}@nBK/CPUD�hjL$/Mp$ ,}~r*BV;vc]\E;X\x09DZ%C-&lzPn_P'G %g8e*G\70AZttos}8Hc;�M/(WN*_�g)oVP⩣'G?]`cgo?�1zx ;*~K/~><f ٱ5&ݑѫBlppuyvz~ŗT1 ;S?ToW,qt#rqw?-PDQsgųUxCd 岸~?G˰sv3SR$&:|{&�|to=)JxBp K1to[WG /ڏAF5�%�K"ŀ(QA)LcAҡB c} oE3[[\_' ICx~y-} Cg?^xnpO[xZ't\r ~!t͒H7[\gJÓdN0s̮?Ϧ8}xwʚi9گ(!v\]㲈�?y~r\҂民'F4mH !)A)2,|L.e]:,ӫ2n vrs>_9Ivr<7mR $\ ۦe>*;1o^ *oz@kb(2%[&(>}O �ղquX>c-uB?T; \uQ9!*]ow׷o"Y+GsQּĕ9NjR[*etpyMlp#(/f†<PanfĦ4ƒ"1ӥ:$?(%Uy~|TPxv6TІѲMƏFagM#|oh(QNwD�!K\i 'aai8N%`y4cӂ+J-M /k"MjVu8={T?EKWdՉ+x,7X�Y;*yV v_944;Xv2DR+WYgޤpG�W͠F�j^pC:,@h$$a=nF~+a_N^)uxyu|$"erA LClUdVn|Md6x3Tˁx65ul;f.zlj $'~u׫lcKs+TǾ7`Iȩfgam IW`]#L)¬wz~1x7x Sz: wS�*ƯŴE\n[, )WǣՇ"@zN%O3 x!=nD'mҠ25LG.-AApż#nCGB ["A(#g q6*q ]`ɇasY!FޯC6!r("K nqne :L |%й8^F8 @-ȅ<oԣ+8JaIVv 4�~xq_ŶEYiE)]m[dbzΦ-H*KWU3_M-ǝ򬤓jy=\WDY5P<z6xj'ij0]3G㦼f}M倅a&ֳ "D S}L@hBPjG&}8.k~ҒN՛uQi_H:0fxc6�a{@XlUO35@nV JM8DL)Tqc,"֡wo)l8Iv:vy|q~1<g@1n[,x0?EJ2� ^ ߉aoz?j,: ZGIR'z,-sh ZÙptMQijߞ}x+VY{S{<z.-$3aisM[L;9I5-x0:Ž^!N՜ *-'A`4,R S yv"wKCO~g<ly5"m0<Ui28x໖Ld_|6Q5g-R?)Vtu:T][ƽT -<9<qqn]lFJ4jhr岄�dilUdlhؤg#@<�_)V$Y9fcS|P?Ն �jsKeT~q6w6qlyֹS�ኪi-scw'YVE+ R?QTٯvk8X0dp~&g)K.=K`Ul"׫W )_|.g82gjY5 xl>ҐtPEn:D'nNF W/dz`<.KCۤLQ f9ׅ#^5=00f=]7 VsCa乖ɒ 4vl$Ը"o94J5oOi<4xOi<4xOi<4xOi<4xOi<42ʟuQgs7g( ^?7;9[̆&FT68qwvp=K<�wTlǐfM&nI`5M 8Yn׾ UD#,7M8/J` N%F'c UTjkJA穫jAn «7$+nBQvU9╭e2$5 Y%UEs}9rԳǟxY6MGsHYخeϦvX@mMVD\zk؊kU`_az9PHi2 ]}:yAgQ+ 32j8j@ǫ-̵ ɂlKYQ=zhޠdzxr"-#]h: טvKVҠp)+fDֹkN{ǻ~7A@@̃# |OJ v.ӿs/v*#E9~ajH\=ӈbߞ=Idaz_?埌l:[3*v ,iP|KSj] JբV:Z_D3P{/,73?\fy<DYC[uƟ*Ǯ+ݬb[EMWfY&?a9R}oS'(+M-#1̰l"U{'nMU?f㹎_8iZ@5znYn 1l_j˳fE4"v |L73[U 7Un޵iiDhM*nW5z"xɢUI~oE[/=S ]曊XzkQC{8trVxEUͨl7eKJ$q!RuM޿UV!FZP@57*6Lakǚ 1pk1yؚ$H62ǧYRƟ[3;9Qެ8zFF^}n'۶]f4bŦBIX56ī3ɋ.6U)u-χD_kꊤhYMsr68ĄزʪLleW8#[$t0oȖ o%gs]SEY eno&%`.Wmp#gIBpL~�P|Ϝ]qft[j.QNu DzUC6-1$4'a65i6͸t g0i`EODE0F; *ɡѹ-+v@:-Q)j Y^\,UXV]Wa][ .?[^B0eאT'P\P]yEp(@P,J^Aq5CY4ߜ 3E&g d/Giqx|os"eX VխP5>Ikda]:'j[ٚ&޾<_?&KA7-e|laz;UV$t8QT8Tʐ0Lȅ߶e!9:RN*&J[ go߿ `(AdajELVjyw٥+q<.]"L '"׿߂3clb]6š�H3WsY~ƒP:^�]J"u ]WK0jچh<7H zw0װ-Er|K檡q'oࢪ ceȵplxVƬ&D45WU6ղeEo7)u''!%4Q'UoZ^ڠ"9ilQcp� "ߖXbWz*?ej&&{jk}{ CDfYxPR 0X}?FQ hIf֐O<P[5ӃU\P"cBOHk& ǟ4`TQz(ke[iEur'Uf1Io`%/ƢfjlDaEp=ڼT=c  HQiKtkINR8UcpyeKKA5P>oծ::,$Id4 AXem |8Ius!H>*dv/<#& ɜ8JvZ~4C#B6̑rz%[}s Ur TȩA4# 6iGyyvT_/]:-f3N))zdvՄwL} rSc` Wu44$"- N *l>jaYҌܸ9PCD4͂_4]WEntFC-&Iٺ83NP }zG;&W e͎cK&yQGwR50vPEzYh+` & ƣ )iq0Ins˲2s2v"(nEY#NEIMI8bU/yƘ,~JxCpf闹Tґ^>C(-x5\]T3W(j2-5%'LO:nX@"Mzޮ"MW烙2__bLATP�AQ,nݭ0TI[d+7g"2s[j^$ӟcB#M^PQj0MPBEB%d ``2k&u vma L(*uձ'}&P)*WÅ(�4S6) HFknx'9%Rs׬֐Swt&#wwڹ& 0s42eG9fL%5tQ2  ߧYѱ1~bCu腦Ude>?f<.sm"ZD SpIV%Pp" eڪ4t&)V ҉Z}={Xj €զ[lOM`6@4+3n[:ȥoKS%ߜI*U;ݐ 'UYl~d%2&XU=b2 ),M0b&4u ǟ.$pq%*DrwX OdrA�)"䙇)Qg*lxuy5"cEL/xC"$Z#Ex!*7A#σb .AOՐL =heeًI�';]dO Ґ!)D0\12 %[R@)$zP VCB_I cfb[w*;nH tUVF߿ňP'xH2 [[ȐzAfZP&2_&cnRdʈ[*L*u,}C2Em:&qrCJrĶOE<]w eIp �n}PYF\ƻ-mn vS,mEj.^b<$}0>KOhRLU\g0bycGcCM�PjNi!.mנ<oMC er۩Q]ݒj60A>$+GA6j@JU9=b׋DDɘsCIvA 6u.r_Ci Un2C[RivGiFU +lx0wmP[i �FKR[0cԹKi,t|:ޖBE8ͤJMYԼeaU=VEka/(Y OP PvPoIrwCjۙmж1e[I2Aޮ ![Ea޴kRkQĘ:uM Ė_Pı1 5$Ml,fXQa;(yI@ C`qBJ /.;zePq鈆t7ӌv `3%݉5A>"!d2!Ptn7<%6Yebpg:3�\eo-b!>c#6Q%rBMbNFMIێfݤ8?~FkfG&5鋰a rMS�z@u?-=d>@Y-&`@mCJrUed*[.ݳÂRQ2<b6,T\^i91:Fkq XWI,ytr|@] VGPF1qCQݐS8d*3m4df*ˋ`=|2HQ &eAfe Ot]? m{2D[XۑRͩt aA�p=C:1�VUSa$ Umm ՎA G* CϽ*6&e^"!@OsD-|Ej UZYYW0}YEVQ~RE"pm7L˺W"ǾR<䀊I%a>9�Omk9v?" +dC;?"-ْ%"Hpr9 �HݯU}]oڻBF)- q]o {0&dD$u�yN1O>⻻]?ېxO VA5o/Jܯ!}9<a.&JN)YJ J~ _>=֣6^1^EԶ}PbYnc6$г",>6pOÎ[0u?=Ǿ8~8Zqur ,ɮ;8iM=\&ޅ}4u3� nh,_x N7TH"(~% GڻĄ�6doAAW$/v*q Lz$'m C}|3)G{$QR L/'Y|(?E^pd>{Y,$ KZ2[y]wSڊ嫗~{!{ܛYu\;n6@a;0ysֻ&�d@) ߒ.χb(l4aVՋ\%͒ͅ,70/˟L4{Ϡunp{D.<sd,`J+yErBU(3&_zձQ]/mza>t޷us ШW+e8k!4/_zf񂌤j ,_^|qQҐrmdGobxZ VSŚpVՃٟ^|3Gq%^9~�/^N;t䕻Czf)怒s~80W{GΦbPʂbe;2(G xbкSW/9spCN ubWT? 5]H(FсKt 8ބ�|�m˲MMkDC[ARHVˋW_˩BYaQ蹲 ߿x<J җPӶ4S qj� 0CDQMOw C 1'?}Јyei^Y_zqETI$ U$ Ui9i^ߦ;$dՇX'sp <m-$(2(M�Yȼh}vmX9UpӚ~.6p^ӛtCFݦï_ǩvdYŘjQ"_ҿ0 EEib(^`shsfW�Kh`tȠn®C~[7J 7M|;H30$yQ,Wo;kGbl OXg5+JC�1YI d6@%%P^c- c D:ףn; a6+LY =OD@-W<[0D"~B/'"r +W6շ4fD{ TWX\,fW' 7:Kn4:ӂiZAz T 0Yp38y]0Ry|lH nzf\Ç+F1{3Y 7 1LQa Ӓ,a[} vЯgFB9xǶ}b'AڑKGP߮)*r2Dͭ_,̸ (+P~lzCa"_t"2یX$3#=޶C `ԕ90вuy :˒(w}T^ըK(q !#VĤk4q&dcYy`ꆉqHypxiY~'Kv9QL1:73 MaD8ucmA�*�:b$ }AhY7ݕ&gx^rq #7l\14XJQ�T-*ʮxHf#9F3 Bwq:V@̹%fɒ[#"!.iiv^Wѱc$ҎϩmQdC R6Ulnzy9=рl�S7M@ǥO qn *X<:(j՝@:[YT={EF*] F Ač&qtGB$sH"~'++`P7=\/p`lJ(3Q�+@)I0'/ l5ሷ�.ȳ/3 cw@8~Vw5x8� 2h7Q-܋QcLxZ,detۍʶ Ƹ l\@o{r[KQ*̓WX b8Q8%}H!zuYNRޗe�-fҽ7a8lU\-KŊ>;ܶҦ!W(cRDY鄢Iƚpǂ[;D$ދ�u^Ϗ..xA[9t!k`:V76*C37a`3h*\Pɵ1Ý-29^_ CS"$>u}R.ڃ ő :J3SLk;k]_(i}М$pн}&+|5!d%/SH-]tN$=OC!8I|'$c@4銠ΓV%ؚRUMRT5+@> WTF}`+k8)*df JARa`]w-^>O@OMŵ57Gw7a]/&% ,V^yA'2帱em*2iI5vЀF6Ŋ_;@'�x�qn|EQ{90 |p طh8=_+pMd R$, t2w Ś$okWEĻntI8SMDN`׃|SxerLCSJM6ٸ'd>Ba[\^}|? WN$ <:P f,\S4'n>XhJh)Z{VAkgI 4iw0DjyvAqC87&bhk2caY* b>>_8 >Lf`/@8z Cs }h6Dk>&�[]@-ޟQ6$i(QE^-�TzNj߼~wi(FKev18dpi$$\6MQ1"wma*/CL_3],QJGb6<;u큗w]l0h/#i>AIĘJi"/ <fqt0G zk,GO�8qc^[|>+7IH75y/$isGPt E.3$& Bޞkѐ܂)JN/6>2DX>hGdgڮC Y-WTc|}2?LbIlA&MYaUJ@0֗LqV4{.TfW6׿_Z<Hcћ9Eky/M/dnC]dhG,-Zr%2, /ݎ$Mk\ycOවbw[ w?A=2Lܒ 4| jA<( /jͺ>Ub}D$H-t,s1Ѻb%};RSEYd sy5nIuD7m-?ltq`�e1Pq}Cț|Ȕ8j 9\WtU,xqfx΂$yvDKW|6_vF },<ǂ'b&?4iw$+9}،FO$i% ն ʼnXv7 "XhZ�/bE8v=]Fbз!e&ON'$2j|$&kh%^XARt$WrWE}j>M~{M~=n1t`)9QǓh4 .缮iBuXQnKdѾlODz۳|�oHr1cV=T)^Or4 19:GE( a |߯i)g7Dd,"gōO/'r:S,hi͎\!+?m`R92>+$xoavı,Ы$r' *+DߝbY^6vQƏM'�h_Ůݐ{<wUdsd+0"aD1 ;"& z9@Flν5Gjဠl0l&D:T:tuݐbMKU@CˬǧW$T **-+}M\]]W<½fؔCv-YLƊ;FtE</YQ8"8Zӳ+Fa{m�o.&4H =CBkldzXlA-@5Q22R ٧tBҽ$P�b .6$)sn 6lB\k�c򏂣U ߛWaՐ5z $nE j{/O MS,lwES*P`} Az к6׷f%nM^?;ͯ4'% `M cn6T±O&b fQ-IㄽMtq5U!]"XP}lHP Π(�,&=CSVu#o2,@]\'w| (F"L,/J(˚eUG27T%Ŋ/xhUv-`Ռ6>z�BkvnZVɂ$A.' )KXJ0Fe[  ;u< ~Bb L*Whd� ђ Ե}#ձ֠P/W,5rh }rLbnϷi]k y׳0@vry5w.Vx/t"͈X\s'h_$ ՟?ݴ<hb\࿩pI3| zQ`%KSl9^)Zi3Tﮱf43 85o؄,Fg'wkW"Ŕ֤[OU10]+B۾n9̯ (n-엦rpqo?_N49&qtu~&96kжJ}SlߗlX~a([u`0e^+iϐZXMVp"EQшć^LE#aǚM ,1r<Qm̉2 |`2&bZפXψG�Zeΰ'8H+:V2ȳ0S c�(x1hxq%5~ޔ,T0_�$4[R< ;`緡`]TCf@tױ < ,C}Xjv PiR߶ey/f-Ǐ<sqx@s2S]ϖ+Fz:IuĎ3?B~h~A7(k/5qagqQc/ݷnyc/ ~:m / XӱMqIKԂ٧hUM $vW|RԬ `o�)=N"s~~(v]r;9^k_* \DqcOn&]Xkt i[xZdai"m�V48Uvyq�ϊ.yЂ#-\O)AV} ,]Ŋ$770]5k!0NFJ,֬V_N>ּ _^#U}͛@M1 _Y*�s-hw1uh28j>׉*~G? 8;2"s0J*5p׋l?IA1ƲY}xo(Y>!JéjDkOB b <!,`$vvo梪;AZX $>M$&,/S+w5siFs]�2ţ1@/KC-KQ~Ǎ}GqZa'WWGnBz|o= /\ϵ]p/] $8(yT1ܳB9?n.fԛS<{Pwrf�['ǒ;dCw@0В&cL !`SnWEId&&1gNq 4R`�6ioZa^r*/!X 쪭"41?z:?zv5U@TfOQ~@g']5-1F8@Db�ͺg?<i-` Ɋ7GG 5ְ!X{j$E "y &->z^y=z^y=z^y=z^y=z^߱pJ/IٮgP"x]dxx͍\)u8rw,J0avTu�ǓI͍8+"4/e5 0.]drKvö zvdIMY^WEeUkqh �kԌbolwHB31 kLbȊhJF'ϚCx2o𺪉GcK(ݮ-cϖF|Yہ&58cfM?]3YlK18f'tiѸs cwY/秗qűk0C1)%*>o[{%[>ڊ2vś&fPlpd?M};lw̺gӉ1NVջm剜$+VOU(C[qlonnqKJg->v;עdpMip<%Qݾ _V6dTzYͻU <CגFG+UaKA} E6]6[e <3V@y!VoKǑ:=];J[%.gG&+euh?81*M\ɷ׵r /iOVJ ɥL0y%ݻ @›MFQ娌,&m:F; 5Q,?zeEhrnO-X6m/n,/�(Ei^Ѕ@U])rCCۤвô#Za[hQhGuEyl?:5`tu>츩[wܗ5v^:WvϮd4u)KyQ=Ɋ<KSx^U3sagoN&ѳW\m"c10kIV׹'n=s5L]הC~SAI*,]VTMbf{Q,iz4f: ;0{m*7f*tIZ*wT=h7TĐF3F^Ed \P`01 mQ:\14f$2c h-#[ׅɌV!cY^F8^] qk`E>�GAwMf3TGRTMab3S1SJT ktu0,3Ӎ~nW8g8uOA$aEEt*/%zintu`Ht1/Xq,S2O~,gy.7gc 5xgV NI_DzM4]r[Mg|0fBrFwu㰣|8V5t]/F8׮LIs L#goRUX$EZv1,lCi=_,+ja]}nL 44S괹JGX5ʕAɔo5bkZ.2>X1B3iq41^M%p {3tHp*J VBf ,̷a{M9Tlbds,rqDXb[Q;Naoo'ذ[#P[& k<%:�S%ܢʒ ,ukl1l|QRFV<'V)n6Vi{iϳ+}]b9 pb&ќf.HMm�7dnSDa]'+<M{ț&r,-6_e8^Nҷ TN=N۵ѳX /m[g9(5Ĕǀ$ 0[2@~]UV"CZx e9ؓ%NtŐ +9 ~ƆRض = b&>VOe0cr0.`\KpPD̂7\/15Z` tOg5m?BSy$c+8;nt|qJm%2K=SZhr*Ϋ_;AOjt}R[K^F3  U~0Nv"Q,L^N(<6O#:HL+jHSs"4l4ie=6ِG@N5˳ԒbE$ApOWm=^us [iJ+OfدZij!OBN$�@�~G_׳Ɖ9 hby!~gy/YqU2w`9&W5 Μ6X@3L3fEl>`UfɌU.|ӚF?6kKiUO>.xa89aFU�pĀ3ag4@7Fl\gsxu:D�֗`8PZ8ov@S!ѥؐ%'I8'sJajZVM')d:}ܼZa4E#v Vk_8L=7]'YQE`i /EIm-AU[l^#mw+R՚|8[efΆ PlE%s#j7d&kMM,rKQ5n}g(4mdk}?}g׍_Yk˦LNrα+W~y޽ޝ&)9z$4!|6sodU Z}?ʦUaU֦n,"[it6NQ(BI p~ Ze\*qoK sr cG SԦL 韈RK7&*EaNIˑHp1wOux-"gy$QVUm~˻1fG>xs4Ld0H&z* �y(NV@M&H7p=ؐƭSbE&kIYy.`D_502-nS>^+[4U3܈+CB8p:㢄t:gd"sg6HɈH5#S'6]b#- !¹K6Q b: \ J `m<֙Y .oKtKP;d(zC�.K͝L8u8UērD2Gj@ Nv-� ڙ1a!B- CzxyP28ϑYҖnr;Y L0: 6qx$1ld6uYVhUH`�XQaHO>HL^maJ"7DR2n F&;yэO{F+0Z3tm,`'`ÆH'2ib62 ܔkIU]`S2 hHC�aqƞe�u^}i8LJUaCi?l歙( րTY0Ntȯd6HJ\H,: ɪ rJ=r`Z $ )>h^2ˋ8 X;Ijbx88;A}<'A;4` ~T*>y˘uT2R\9GJԊGAԎÎFd'DQ$UҜƼ%Zn9/ƯEg{Yӵg6Uɣ?%k$/ޞ`ӗ b":7.=9Z 4#&+B:fNfmՆxjEiU^,]o(:uwbsF%ǂ T�2 ?btUI]9V DVn0|~S I ?')oJmYRfgLHe#.y�îk~yוY~dwEJfKDݔE2V#*o߀Fea[M3fF-?0ǣrG W>ӀxK"pʢF8cv$2Z"wk8βHMQ}V֜Uvj)L% |Ԉ[g o%cPzڟ>=0V5jc@)lB,qb6&Bv-W 8 MQ`]vAJn^B,\L !\_͞t�Vm `jwx!u>d2[{%)\T-ρ}KD&d7'PfD^qREZhfTw+B㺩7flmvt]7ap:C n7# ;a|qK?zN2nH%V1Ѱx2)p8$-wdִd$a^ ?]I8STj�$D9Iz[NB #m7ĤI{wMl'AA ((g5x~L%f=BӁA aڽFF/ Z�::-[Z3#U Ӊa%xZ7L=J/ =ZT;FL| B`V!:6 Ѹ`$4&v@$UA*4�+iOZ~`/8n>gZZБ< \"(#dI=nX2;T@FRoD ޳-;*՗å f"Z.|r<��p$t((-*\uӑB̨;BzCRv<mSS6Kb" zf_Q?< |/JdFɛG)9Rl|Otȟ;A\zO̎x"\7(θ)p9D1 $'WWEmӎеfOc|`VXUXeN?9ӵd abvi,("M�GWxDiL!B!HY~ķzQٺWlϿkص}b9;=B]FY c81n]IÌ4AXIZ?b)'˹nրR@-8v,HN|&hGf:|"Sxi v[S] c:j5@_eaRvum =vmUK]ͭ,yGGOWʶODFqSYC`*\\] ;2'{mж ReOԦ%kB=Cy2h+Xßo=Ќ\;*/,s` o-eX7_]6`_WY�pPd Y|<z_qʸUoGhIqSg5KtGjJj`:V0ǘyƍ&a% v+44Pzfӏ>C!X.xOy6wd{7~#jt(a9c0Jt{?rvC5I-U</Itv\p}८i L̬"XP ~?2rj˻ ^MJc^*x-Sv<zjl+ SZܒO%YL7(y~TU2b3R}󧗋.V:,Qʺ4_zuؑ]ǘ}IH ^,!pqcY8 EDpCXB"iA%an~mjvUSߔI γT:MgӧDNM';v%M= YRnզ}jy^E9f40Epz?~?R@@IV'~<ؠMd<xFs2ϲ4eM7!<xE;?y2 E?Mw-{?!$BGI')ㄔg@{3~19C *2I+D0 (1n)VmR'u JCs~wwu3LFp]v WN惻V Ǜ DY83,H/mʞ/P"O#cz׿aQM�pK3}9&oֻ%H,ڜ*9R='^L=nڪR&7M�,:Ub\ӓSca.|$*qq<a}Yn*I D:! Kfn(�)%@SGQm%dvM�.GoxD @L 2-юN:ŁLV*�QyzO|ظk b 0w/GnqaND.0$zOB s1x$~˜ʖT'A&8JnNI 8 5ub)"5x:gyAjai8~*:xwq̈́򲭰DCyxI*эCHS[z5i]g( DjIӑk8A$+?ʭX&NlA"p&YOJݲd0ݯGa$�&?\m Gq¸�n\읢/Zu &+h$nQHk )%eⲋe8* DV[L"?b~Q6Uq$Ѭvw Z;+'5u1LY6]MoCApfh^qSq7"G\sf4,` "MQRe) ٭w-x�۔LQ4gDawMK! F[.eY=_3s:] ti6/U Dz'tVA&3yۑYՑkKd;v)E6p[!n$ZP4cKI|<�m]Ƽt8\wn# @ k{B_-i{ؕ1p3@7E n9cAAMy: goޙWGin(*v,a+\EXL{ﮧrܺSH1nOxһuؕo Y<ΓyOV`PP֚b~v?,4j4HnidZ@hv Ǣ uWŮ.KDQ6).j+2C %{Cq/@[oYtA+<1M7wԕc钸8J<w䰮AyOyH*xb@B!/Z^@wn &vˠ.�"g%XnpV,ۅ0^N.9b {UF Bb7sn:h`FŐ|yv%�U%*#rR`7�-4ېo>3Ң#;5>Ă'ֳ Vn?sguk 2S_`|ŚЅfJNcN;%pb1k*ٲ pޭH(¸Y3ljYEљm:sM2}=OJryEaݗC'L/_}JHm3ćZERW '6fŦl}lo$�93@HEo=q-D0!/oK8dY>0vJj.^MӲ-4ŋVzV6 V/*p2tJ|㩠`a2>0{? aצڋm"' G6.KlPUcssm{q n !KS Yk2Y ^"7WOƎr+mdL ɻXb6=1$nwQLTtZ"K0_ʚ Tv|̎^7 z܂WzEce 2c6Yׯ/ǂ8 ,<&* dhpF;V{dL,f8�/FNi]?w6$,4t7/߾}/i_bh>7wSI /̚)c+kJr0_,p&3|Sh< pT liK}7Wt9p;maje~vy=}v,/E˦5+nWEa6|nr1&)/˪L5KvXnu[TJĕxePsݱBVnۗ>mg`9j:>SϑY>xidۖ严$.EN6Gj"a(tmZr~moԋӪrNq:h,!A ABcs@X +GKK~9z9Ym!}Qv@}MdMOǜ`ovݲ ^q !JSRV-boDŽ2,My@}:V(x f* jbt-|KxK$+�dD&}9v!?M/NT;ʊ(ֶ�G4%3/D[S= )6ktXx A-R%e(�[w޳"%1֫]mA/^Y0vMnkN&=pXc8 K bc 4ews3p<N:XN=AVurf ~ݾxqdaѻk9ؼ8Pb%l2!ZbL|v\\6 mo@hxp5Ut-/`κX|{+^T ˙w 5c7[L.m+[N>&sݡ 7Xy={wu�|W/L# vr.Tzp`vEl;iF.pMe|u=Sq6V&#l-@T~8"m3K9qc+'[NIL Oح>B*IM_dd#N�x^(p*tSՑNcĥ0_�ڿ,RcDSbF-1FIVnaٟ IKw;uUeѐ?^ۉexQW>÷?SP̶`NRuÎ,f:tY`u<".m0,r>].oڲ ]S7c-ܓ'Z-3p ^�w`:2 ;ͣ/W),E1\Mo&uo&*AyI;|7 D/I~ɹ$sfӧ]ÇO3UQd|3Oɜrgt4`}v+ǐWc} @8t/;N z&yB>ܷ>+2vD .o/^ w,W%"OB[ /N `/=SǗb>wlGVd]"yS7#AVx@NdUGfi蘆~ѡaǀ9~@ؔ7JGKkTMEN:vձc�E66y`d9_.I3>< ӗcb1rϻSq6q<I`<ЧȄT�ztN|;:\K%3(RGx Gdz:|` gl*K 3 @wX=ht,Ax_l\\SADJ6Lm6Mg>*ڡbr$/ǒ~ZaFdI'#ݯ}lKUyCbKI$0rp,m6- D<k6fK�WcPDˇ6$I[l=\e:r Y-4. Ƶ!5nnX^LaԶp�. b9p5r`ݴjr5{�*܄d8L4WW~e@tSk"7Gyn./V΢t&юO-(_e\ޅcrҼE;}MlK]J"5QnYㇷջSm~_E&1X'~2l4N{v[:w_欃}jঃ~|ӛ7zqry`�`*6[_kܦi;A5*X2 EK3>3z} dpD4㰭2p'Km}p�*K?3`1L ! g ]'ԱK <1EIu[p|ˋB+t/4ul 6Umu1_zugWcNU %bP#pT$nT- Q5̯8{ ,V%p8plK|95"?\MWojlXCE@_Ǽ$IhËxugPkꎋɪ\ymL~~/>>|B1B*KS،Tz[.ND)}qyj{! lsۿfiP?PUswS:Ls]zX5l?^+cǒ R 7]>6h~y8:DAX^0S57]P./|5Q 怃!LmV*^zSs4x,,Ǿn:ԮSoɁSaM7'Wotܨ'<޽/?l(}u-KLl/n�ob9 �1x^\]oD٬PMh(÷Y2Wlɱ7_Npĕ(·Cak/r/i 2w ˊa: Isx> Fw!ϯ8 p N?\HZ|][La:ޗZH mJ2f?Ftoo&hfO3m_hp@[p�lpR~Lo xvUV|#r,JNmS4;׬3*m h_E"%Uwmeh],u7px'�fY8R693t|[ovME8faN9 P[`wAch:Wo1_293-v�-x !`d8[~'gMUَ@h^ܣp _64PBVTz0NxIq%Ǎ/5@* " �*g pb+N0p j?55fe@5D>oIU*SyyYVot/oՃz^y=z^y=z^y=z^y=z^y}IX?-^"Z]S^/.cU08vTI߮_dADqZթ'^~k*57ҼaĞW/ J|UVvtlSa8%x>\hzU'g}f,3Hpq)S.nl6ay}o~1&ZT68 ۦ\%pUJFNv-۶Kh48<9NB..' p=uo_|%Y;tyQIsǥZڳjyqK4]W ~dQnyxg/Ŷwŋt]aS=#*v۟;IA8 YSͦwawQwfX*Asؗ i<8% ]Wstum$쯥f'R.my8M[.?j_aS8rMbfo''9G:3Żr;DaЖ1uOoDOi[خT C\Ak`' jz=+̻n}hA<ibޏE+H.k  GS%Y]ߕ&ZJpA3^꛽p { RЬ7mI䩣W$ߏl?ʫUs=-[*TeKWHq })_Ar% bWĖH˥Qeu$Xؿᣪrax%aQ)FZ l<fUh~ʼnbN6MF+~<~Y8ie) ĜևrMQo_ MjYу'<zu滖8rh]h/ߎUCny9iaWTWM[-lX{9epw7d{ao>m*_\.}R6 [+O^auEEEobA}[ɑe}YLeP<=�Ş߈|`k;EI{NR6+722n5 Ùh:bE-j:2Gvp`_8n{qܜwED: MNtj[e)`5 XF뵠7f‡8a G2P2xSWs@JZU4;,P`'·Vv3g5;*۶tÎ0x<Go&!h8LnpÖ%6 f|Ũ?"Zax]M^`Ѵ쇟ËnɲvZJ_c[mis|a{0i;m>sS)TmW ~f{LӢ@3:FfN͡$bS#醉#@4>̔.C~x%q{ioUuSe9ï6K<+4S$F=oj\g�pfn 9K[de`WkEj 8p `BV�Ѫӱ 4לl<Eb$M;Z6a3 9Zv;j^R6F 8VKhhN"IĶJRT;MO[}mCm9m?u?i=-?Qb<0DNslCسe+Nrk򔂊6s}t'"ho ̳,fV9|y�Yф&"\ml(`)85TH<$J#,'ҝp#pT2G՞4∿j 5 >tdmy3 T~eY*vuǛ.ґS>mhYN}<Uz +0"<n@F:vqJ8@Dي֡8#�P$7ax=A4QoWu-<EVU!Qdk5FPumuz4v$ILHчdfY<%Kѝ|<"G%D"A?i9ϏkXniNQ&L^M xTUdYQD:#ף`>ԑ!NRCf�nxu[_yNmQOZc8BfMxx%4q*,r S_&x.՗9`!ycd*ne .6Jl?.pZ ?~<"2W4532aZ>wٕUxlB2Œ()G58RVw+@StpJOmt votƑM[Wxz5]-'J(>cf8C$^P4֮*E4aҗ(\%rN%CKNĢ'Ӥ#`7jMa"oC H9eXŀO)Ɋ5Ƌ$Ag֥% L1wG' b@8@fil6_Q,|oNKaP5 5/?(V}^37äJPĔ8Y-oꟆǟ2Cf~$pF$Y>1U�6 ŞwjojDkLuB 8x^4=ıqxЅE~6:�^]F͈ A Қ�8p{"ZOoMC3K:~8dByK<K﷛n9DQӿ Z#@aUEU(nrB%(!#Gqa]Q<Hj@4d$r&9EFY*D$O [X`bX6~/(Χ^H4a_/}.s0Zс"FOw Z@!%8Qΐ6DUƱxjD_nP]dxGwtxA}zDdj.| z]`e<2jղH "x͓?a1LK;N]˲.t&vzӤ&p)f* ͜z'pӖFe>EB"ˊ,2p;x@ї!1<]>i2O4'aZSg-.M ͜UQh*L�~ }JHdQյ Nđ^? c"pr,*([Ax8P~|}�eNzDM$ ?W@X86D~ZȪS#b)b B2Gk9o[³vxņ@==w{lf_`"1i $rTmZnƺ$WsI1Iq$@ 뙈x4;~~Dyհ:dA@},"ȵɟG"G?q<8JՌ;ARMСܓC> )Fȍ TPQJ?u zIٷm0 wq$YxQ&f8CiiY7 eDLn�0y"y5{,FհҞFa8AQ(VI!?LY� }h aH]ӂY\~8r0i|XCchO*HrRe&JHNjf$ˌqPnjx:Û=+Nմ?lBtW�fF%ph]y @]vZUN$P:I`T9+LI\۵VzуD_ #T<90ҋY~R&&'95xɈNv٧q+&NzęROտ|6=Q'}=#ÑN!6 (,]VJ3l)Em48Tyu "ܶ=jOlUtQ _>#PUID'-+f'CEeG,Ҷ=K"[h%˼,׿((NE}857#)ǐ\x[/ӊb%b MG;7%20Qe^ _ ]UG?/(^.. MezK/WO)H *&vLEDIAy<I2X²C͋ى4ѫ!^ND7\®DLE3)]y,C@2/#QF5t*Hbks0#S-Dmau 1fc2@mYSRlop i1 ğADeS[\,E4mjϣ$} S,ȳo(<0~~/AOz:rm'iϧ`3l0pQ0 E^fꪢ9 >O1]#D)e nD:o7w#t;]Jt%$IVa~ա<Qxn8AZ Dz60Ο}$N+OdL6FhPv Uf(jd08tyHLۆh,Ȇ~^ja}D]Y5G }$L4-I,] �"n>n�$0cBDL _[ā EeIlh3#8{%QB'@%@nBQjǪf6h#H1@Lp!LOrgkx66kdQh9_k݆%l<9SX>VGeYRB-Yr&VO2I&r f.sfe}-Qeg<aI33j-:HUk[Ϡ<#�RJt{#ڎDI�$);)s_z"kNZ aH:|?~?&I#EڻG[--ofkQ7!o8N<S"<2H}MW]uW8W2ôjGG(V| 5&8uUՙk2Gm#)F~9xH&uDmPW >W)*</* },udA;FPM"ݞ,&܋˖#%uRʊ Dj<dTQX�CDøӸH(CnAحYcUؖ?% ,Q`2&Uv``YfU{DI:it:NQNuR*m2t/g_݂ g!4U=QRǨ#ƒeDJ:48U:W|uˎG]jN~dkN,*7~J89|ՙ㷅؆~*�s*du6_a[6b[-Vx4A +lJc4(Rϔ?[+*KF"4O$9(xEOmWj#ab{W}uEl추Yax-Iww`[7PCw s:iI)dwD%<5-{fJvӊa-�~ϱdT jL =탯E̬oV<o&3J3UIF&QФL˲/׬8QRȳ٧bDtzltPsƭ(blfaGE:Ӆ RZ `W@PslCVKJ.{0,KWJ/O?<0ew|4AHqùeeyG9'ݙmxFUG8ycWQ(d ['Dղ<`iҼI3^>C4luWZey?Pa(3.SVi/TH\4%{!O#&UֲKx%$N,HZRA-Ă+ }?Q-$6WE@VdLY#OHé:V'DPf1eD|SBTOl.=?lUb~y}Sp |!=U `bn3J bQeТn{EOO? 4d0C<Qv^"X=^^Jk(ƖbT " ^,*s$faYbE@HDB@e|V|ՁѦN$#3¤ 01N޷SY� i@.?n~R^UK v ͇ʘo*X^eOXI]@u0 - J~N2`1/G!|VH_9]"uu&yAk wS WL? 21z؀bm?zH) Gy|͛fcʁMt?n/:(K^}zw']Ƴ< pqVM{?g> RV0! HW'Pc (Go?�!3U|Qy D3鶅p'f|NJLe7wQwbF|Nuˡ o*ž4y׵'mm)M^whn0xFE C/odM+@N0j0x} ,ȚA%I؎e5Ô{mzX!4}ar"J<tdq=F=9FA)K`/4_TV)cˏ>.)U1!@Э!y蹦^c{:/S޴num}zA 01dP]Ҟ'\ aF8S0@6$"dUYi;Ocښ&BT0].˝>@cU t 4X{I=kŤo ;e1Q{S{U z`G.ŧJx$$uv†O3f&9#CW䃞]^nYx_]2,u9|˝r/8E1 mP`- QyDTB`\O冩NC"l`kw7p ^y& KjrJJYӥp$nkfE--[zta6Z}x$jþ!Q͎QۉꞴYG0rANJ~@M]m1Ӗ%uS*"SS؃&։ohxGSlXNB*n@ja$eqӗ r uƭ<buGR:^zRM,Ҟ\A f-uQ:+ԞS'B~3o Mv3 La nӻ�h[YxT=X.jK~$0kؖy ǩxOny.~=ݵiXO`&ԍ:6 ~-YYL?BiO`~F <tƟ]y=?oA`Q]O8 ]~ \j|U Cjyw[nܧ>Ý@)Wu>ФNw C0C&;^{[JKKXFʙ뵤�O$Il_[ma?qM:*񢢇8\0_Owp-v?Q,~Wt6!W,G~Gi]yjۦbi'�L]/"Cg<`E8HkHۡMf횦Ř<;Lyӥ)+OCEvEduZ= 4~P�,vpc�oGr3N";\t5rZLXi2>Ė4'a"2UQݎUM/ l]4Dkô,$0@T4+~~P6釷 ըiInm{dU3MKz^~xOc'+wqg~ӎyӋHw,#:% *|irP75-㺎Pw#+< x�B^hgS5]Q2\2Rw͔qjWV+VB%V sG=b~sEK &F#=H֊,sÖl&EZ @jk+6@(jaԖj[*x 0A-^jՐA$ef?_h5Rߍ'-g"]X={Y8&-�2x�w6E7�v4<iqjD$|y Kt'MEs@Hg_2Rv J`GMe8KfJb&sjkp14F+b9޾a= RxiLRY ;L.ǷyI:_ߝ`>pjp_McN#F.,Cr"0xiMpƎpT92v|?N@eKWH $f?䩡/!뱟KMƲԞ:~5˩ ^ N;qhs15Y=3p66Y`=9NK5 CWrZgכj'^y$M6fjƻ~h\NҞޭf?Ѳ!f!`a"l˄|(b)V%Y՗4b @90PL^x?5aW׬ )-?,xwzE>,xq1i};[P٫ww[|)0 |j9_S3i<xWa!_̯^Nfб ~bs{8.qɆ˛3y>u NM�(HiɊZ8yGqLf- D4qF9y/J˺% t. fk8Z(A4K{œkIMS )^S 3i.k%<^AYT`B.wM:q+~ӿ8a�'.qlfmpH3߾[bLk&LIZS+cא֟>-7vGq�{oV!\7bazI{z<?ضH%O|,Y1-Yo?W|bTC8�.Ͱ!]mm]X|xw؆U2}6_A:L]'I1Dema<M+! nx n߼nw{U�@�RTͧ%R@Og4!`ݫN>U�/c`D%M߁Yıp 7wpR5|~ Fk=lg'jxyd60*v!PdMWÒD T`xεgjV,ş{^Nmn3xq6s`J&tDբO䝹f$8{@h'Apun �Wfum9EGfxzΰ/(S6w{ATMO/60hЂRG7xÇd\=Ӣy27q¯Ԑ`t]B!3İ�[5>d�>Y]g].,B Ŷv|�uĎAִ.2OJƨ/]U|C3 /h^:eQw[^V�Gؐ+8chކGe3ϟ>P7y0ɆU/6AVOԌr|?™T4Ufs^a~I H:+M϶o.@%J< pӖd )",&%n=Mng9�khl.nWDGus; V Kݬt~|9D=(=\m,G.>r~R \+ijMr:Gss),+ "πC?$ O1|-㫟n;d=EdmmjO}%76=%QKX*r^߽㫫vXG.iU9LyZwmJiEQLZXݯYv|Jv~c/>͆jB(xԷtF"|q:Mb[2J}[Yp{x?ĦJ<shQcwoXŃ(9T"wj _r߱ף"]|*UdWK#(!�{rI?D=hC*J/ `:³b�5[Vh~t_CRV%HPl3:໐> ;]$[G <,XW` AuAk3,bd`:ctOf *n3.aƞm6fT3@MAtO{$9̵SٖYU'o~z\o>I9yj-cVp}:ո7@ >1F_eQRԹk)?\}�Mg|@7?'�p&߽a2^=\{qm2nWh ._=@=N _) i 𭛖]O-RڨH]zYX`vVA!/~/B8>XZӺ{ :7) CwחlI9wN2#6w򻫫 2dIbԇW bGe9oY ɵ-fGzq3N{R S#y2 L-15m3[{^-6Tq2zN8|�8`Bj WiY~헳> CjiY;~\ckJj)iҢH͊N 3좪!e.ߣpj9kƮL'|a_XQd7KHJ\˶ﮮV~VGlP3Ϳ'k+*@ӊSmljfh+6meX="/A}}S.kZR/#{Wݒ (lb'h!6Me9zUħ9XIyaseUN!3+ySi\4ϳG~El%Sgk͖pOQ{)bq^zY/e^zY/e^zY/e^zY/e^zY/ewmmK=5Sa)$4:  9?2vWWEqO~[n�&u5_ow?2Q+>L⼬jȟ8'LbTe>|1 X]]$qa"BŇu~W8 ŚEUn0WqꆾRSyQ^0i^QAZNa'P8A5 ]}m0Wol:f31vdp"ؾ}ڊܡkzP]YӴ\bxA3t@QVD'uݻ_j̨vh뺈}7,ǁK2M'<zO:$*%Q_o]QRIe'1&wN:69` DIV6mWgiY7kP~3W-4,;өo4qD@1#\A\D"|8@--:؏?1n*ị(pL]-SXҮ:ǟ2l?k$7'u[Tu;=oR`޿ ]8թ^El?=lj+fY^[ĦoYR&v= G5/f)ΣboS53m臶dl1P[T3ǡoWSC TSՊf܉i?ƾ#א51ulgތ6 ꎃo!+V'";675# iF|UdjLoyÍMuS3Hp uy':NVd;n6o QB8& L}XSh]X{vrO2sqwb+} M>bYWٌZu<8^mxE5c@g+7ׂt mQXnzydhϏ}l*e qyݎ.TIVjY5Ud3,S>p/oWzp( wsphcwb$tl>5L*CT8*KSdE`3TrH23Q]X7*=?kƱ q,nc% �"~[=E()icb= 7-׫z|}S3 ]+~B9u%8c8INn'uJQ5E!@<D %=w( P4CSߣ^̰:P)Oi`lx#" (cp L@dR%xXvUiL*oF-gí.D:+N Q�W]yf4 \tXxL &} cÆ_{Fk]N1dA6|d�ЀOSlVQΠcq]/(!J *@u!=2Xx 2S<zd)&6t�6"'S!nͩmDx~ 8& Jgu FoȬ9>uFN !_^(tyhh7 |ӏF)4>a$R[2Q$.R<$ɺLE 2Y5Iv#5Y~|8cN%H6zD.Kp"1D+$˒ %Z;ꕧ+f:?>ophgS5Eݬ?`Ñ]j j}:vv/4P8/Z>1[4\A9zӼKvD 쑁KCa{͛3t�_{u.uA5$/4,>ց.+ZFqQl0GZ MPGs8!tVҴkA Ua5]Q)�$8AZaIͷ{j?sfX`Q t cXV,P%f )px% .p 7XH@Qx^atTI$ ,ҙEZO}m%1 ;*ݜ$#mz<֑t;jpXq @??֖ e7+�xR`3dCIUdkN@ f]vA"!GOG7ՠ0~ ݙ~z^ΟϏBwVQWXQ�|٬ PDTp[4aonw8i&QTZ-RT&-*X{~i=$T+>%L(~Ij50( XX+.Ufx?ly3ESiRKNMImpTl`Dg%+ȱh3n(#P&w*ZC;RQX"I0ۮ)Bȕv#~^5Drb^>(D!Tl%FM p0, !!%/vZ(r˵y^=J怏md!tf -_t5pPa8I `XIv}&@K;|<*R9Epv=pҲlȾ78]?;#? +tb,{x=B'.0#q@w:d>vP˵4 [J =xRo<@PdHM[<-1*sIk8MqdopDx<u.Q~(Ӭ֞NsfNJ*N")BN +'ls~btMT1qO\io[iP<|jf[/{QW@e~@7 ]z}ײ4+_]j]26NGhA+t+"?'( ya H<pNäw|$3S!AX􇅪xUF>xis W!'DL>^p"̗*?.*Dh|,n0j.,(u,ja~ZJW~d>Q!J*x@Oz}t�0mIZV⦉)4�&pn^z~$Gk Ғ<C^-e-J<ftdIalRh|qykEjssQ^,[K�ic8^T1`H,7f<RI1 QfӔ\PEA?d.P#Ed6ٖ n+O03Z�*䫠&Uݱ'Eqѵ#X3d~s.e$�4G5Vb!N<MPḏ4]V9j2*%+vzm]q䨃2fpBJu4|Co7 /uӢ:?'._O+R8ZVHÀIQ.^8E~RF.hi::Iꧏ�pIV8"-&8NnVCJ "O:3NtG/&G)R8bW*"nAr M C&Bt8;OKPpDOw\ʚSuM3ve@ȍb=�=`2#m(Z^XiCB8q ܸxcDdt&mxW֊ USHi۱+0.ŵ|qDuo[Ip 7 G=!x=9Im<"ZHZJSҋ56 �5FDq& U[buU+X?e׻s'j4ADOhRU!oǶ0|?=I էTyHyQ{qKq7ܜR\F' )\ҭx~S}Kפٔ3zG+H7m{܋kЁ麮D-JoƢ^o6aM׎`MXK$pS+x {G-#[{PƠT0Mon*1TI,Ѕ*'iX!Uhi|Ɠ5Hu6GTA6(pRb"$N2_an?k=dO.-K5q1D$$>O·<!>Dw"R%QpsGTATg5@v43@&U>ypWn7a7߃tĠi\M]. �˦VtE 'Rbrd2´lAn1ޖ6QU#^ aM0r܀M^� k@YwXA:>䢌ȖygD˝Ŵѣw'4: ZG |\@OCJpAsԙG.64m6hMBrn HkpՁb0%b8bt�$7Eĩ DO/=LwmT(Aup'?~t=Ne 4°r0 w8bS_Dρ>FB%N,pBEAZNFH0Z;Bϻa/S~v9Mw/ez}{ O*kAFD I_-^5/`6 Py1MUݶJ#ZMe9>Wn_4|9D�*!еjV(`X@x:ͯ7+nChXJ ]yp}|^E1=-3O4t\= el!a[wzvTMSxKS;u EY`bL/sB9v7VnGo?6.B)GAUMnӏ#FL]`i nGH{E/M4+3Á:"]WmzZa]YU͠ArY ELvCX~YO~POCL5];e; #74Yx_zTm`EQ�]&Cy5ؗ:Vοܲ-_G|$;xDI9]y_M̡kmZ!kk)GMg^MYb2]˟$mM:;Z�]E86 9X):5}Jow/L4v äP<'Q ?b(ϋב\ U;q3rC >m(<g&QUi%YY"uD�~Kz=G縪Quᷱ % xģniL pQ$E݄Ճšuބ+ӛa!�צ퀨$(G(yFr~P차  ԃnav߆DVt>=n./n9O gz4~\hDZfXѾAYn0cӔ8�EDa.޼]iMJRnC/AKؚ/W/౬nxuBjh2}rd#�ѠŁ)sE "wO3ULp6Tݴ(g=veٶΖqjN7m"Lo]g\8uEo N0Tnw(SWO D(H,xcr M)LǏڨl ⁣l5:K\*w{FMEs7t)v: 0@ţ[R$؆pFMI8zu6q�^YyA (5x tM5i): -e Іu|j*=t ybhm뤍ut`=:8AP PAׁ!+"nu LGRmn eYQo:O#FSø"tĕ1z0.(\PT�әHxO ,ϼEIKXG>ceni:WnׁfalQ ) T92-*,p79JX Ruӕ!.mMMX`*.ԉl"ϳm64O# l By"Ib.DL-(1гѕ.|a 6IBi%m:(P/.ƕ] >k1q"I/:XVDz%ep�QÒVMbNpݶ)F8 0Z|ᛩ7BKK"qohN`: |un: P]s[�< n(p6GwA $auxƉ5 g?K(ܧW_'' ;̪&wueNٱ/=خ磌łn~ӣi=2UwzWPº.(�`6.p]kϐO,HzP1RUYKN?fi$F[jB,s˛7�J. ƨn5 _J$-]x]R8y x#ڗ]?ȵGE]�Go. rDf(xĩacQE y7U;&'ytn_Ef0m.T�@6�R< 2͍ގ& P'`7QA&Ȗ90Y[V Y̞-~81*p,VMj9gtQ\:<, }MEo) 8-Y[J$FGhS? 5faɄV!!qmrNu}Kة8-lC=i ʊIk9vSN8U]e3lb)2ͰBCګ :&kʴ:>ؒ1:cKskHh >�ӎZ.AT`=R 7cfn`~2ҦswbWyb;B! DS4x:/6xFdꐘΜS,cAӬҐ䶮AM܌W*]VzjC*~O"P3`ҳ a5 _ Wu|=׸l%BeU�sd~5N/?&Jf?GC<0`=,@5FY#,.8Lvć,=U'NG]D.VMT U|OXɳ J4IoT:mqu~fZ <cR|�AAU):] , =gNoOTm7yp1Gk4`1N=Ը pA/[8 nt|+)XXCU%va brJrrĆ@gg!M뒨ZA4<^U6(͜{zUl?P=dVFix؎! 1Ӈih6CV9"cvmPAj~y{>e9l7`qr$ȴMohmhTbꪺv*`Zf08Fo ;g$xP}3ͱ?.XSe*ۿr5nPD׈g� FOeZ1혆&:N6¼gH9\y<{DԘRq74Yx'r̨&Xt2nZdU@ Ɉў]>+7^$-{eVh^tGT_-Uah'S?YM<]ȵA4aM3 2(lt[0NBnh+1nw,'T*,f G9'Kp|;)D3"XN@=pi9Fk"=ljVXi 6t;T!/GRt&opGgJV5#/  E4x,)ddYo?^fa]vbM(4;gpg5MDb9AٹP~p)aE`f7+h!:U g}~ )Mu(4�,\6=H?HMa[&/n6Eī0/LJeUἓf(9^ġ>LcbT;t4Pr,jK*~!aBѮ}te {x8@XKkitl@łaW $rEhUǹ�v}p2s?,!ص\^4 ѭ5Sx=vΙ[:PӉ#Ԅd@`rAG.,wwˋRӞ! T/+P>MoB.j~4+H*E'Txs۷vq8q3h?hCέ"L]DY%W h)@^gXa;imeef|0b:~C֠2cl]{%h>gcQ:CPy{X$/ Dhy헙<6E1 /vrxdyx9 "LG I cл;VAbE&n1z@m1#R3m,ahG4T4 /Y1NR L x*: lSAOGnxcMs[vwN]Ǘaj=}ۊ>ZG/+t2^3pR&jO2MSG`8R%nӏ|2]ArK]Ekö]:�h Au )򪧽sC`d]("slX bD ۱t^OOm؁I奿KD-~2m/*6OMKq]X� 7]zxAU;hp{}]8ijqXGa:`dQ g1??&Ⱥhs:h[k1DybaJQуrttdS]..Gv`/9KE"Qxn(g<�O+I7|=?#` X @kDIPZŎU˂mCYoFsAZZE'3Wv �eEP{DdknJ &ìM㌨}YXz=Fo'Bh'.7;Oy D!A*PjWg2ʢjX;yXjnE˚k# DO?׶*h922Lm2C� ]1Lps8#,8|D$QfW<q3!r> HG-3mS'k6)bǓ|za)Jfc܉v|pQ9NmSmJn;+̱ :|u\ClCti pwxb^&GY-xQuc*`o=q~saG *OiʼQ,C 397-la�9phK>3U,'ӥ ^، IyDO#r c=^Ӣ*(sws8T'C`mHaAM8볺OL 4/W" XNϤ= Cױz>Ɠ&^U:iYqZĂpْd+ܖ܃=4VWSul !Þܜ `ڳ&0%fu㩫9˃5fe=nWp}IIM=LMt`uD׿}K?كF,f@1]۶t}*, vC_aVf<t BS�mxyQ$q|%kEe 77 QdlaSy8~xOgX Aie8L<^NطOWkxE }xXln}`ݟTogoF+Q՗ y|Xk,p΅K'`, ',XjE;D|ӛw ^�ϪYy\R09F_u3NÆ∳_5;}Ѷ<-CgK.V=m" jp۾ &Vc!RDYVz�u8|zGhFEpP0:{wdK=8\&ʷCJ\Y$ٵd l*ftBl tio~-8<?`h_wN_ si L ĸ5_>} t8qlꖗ JFE&bRd,¾X.x[pᴟ?cCZͧ_?Cc'%5:L *\vdJ 7gg38 ;[q`.w? H%%D28 5J[_a?b[8 tȴ&y|?}<dO^ET43ZGg>|Ýq3i We9P>4vх󻳳1N-އ>2Ň~[(h eOOtvUTtEA�|GU{࣎3nD^S:|&�1Zӛq,B#BK sX{K l:!.2b)QOh+0hA +`p [5U#. uuč|n$Y'H~ەQ7 btSphG{p1=5sci hv]a~$L/4,2v NJÉ<hl?'v4= _G]LbũKk2rRR\ſsQ5=BI""|~|"2__!Io^^^^^^^^^^^^^^^^^^^^^1ʩE]Zyw;$QH3%aDߣZϏҼRB}Is,| >~^892LUJVlfOܴu5:/8O$o;|8a.΂?;[LffR^ , _fz)4d}x$Nbߜ]L㫉mubz+'AbMB7/562oFS-p~;-)ZLl[MN,SIlDZ@.g<-=QtuȖ޾Bǩ8v0v&q[N1L;J=Ògݶ ô"/&߿ގ,*ܗ焑ki}rm:?g+*֮1=pci$"\}~ۻ{w] i%8wZz<v+0ݤ,#SAнHH֡%\y3W5C;7ٺ|uJe{qQW!q<. UQT/ϕ}[<utÐ=4fXfzII ׬c`6k)dQ ĵ&~IDvŎ{ARtmr�Ys3$N}SE89JܖY0)㬫PoM/ b%g9ED8NnZźDlOU)& m,SF%nF35ȚMW+<h~[8Sq?l2^ƪ ?A ]"Lf4c+ɚث7oUXsq0Z[N8>Xy۲7hl]cѭԖ YWugݴe`H7?^ tsvfx?ìþ { J00m:ESͲ5 r߯\M'̚}"_Rҳ v,jb 7i4U\0qsqBKPW8[> }\UYJ}r<Y,QQ nY4ƦJ\$uSӄFvdqNUu L0ϚBćLJ|y>Z1M_v׭=~s[ܵi: eeDEIPkfm(F* Ȏ./FT1L ː0kd$/V]x%e:8ZY)nhS6XNsa1\ܪtye'7srpա N\U#`w]j &Ӿ+qfuW2JL $EU4}c²6tY$V\ドDq�άh^ނJosG ;lO>l[T|a8>�t^vmcpWGʚiȂjǡm ʵk*5:0g*Ȩ/BDwȁCg*Id-. 5Aqkv'n5D|< 9(p'ďS񒗑3@zn4uCu7.xTE~DEkOcu7LC0}^ۥ̫.XA2rarr@rkOB`�F_=q< �jDb$)]N0ұM = #[qA"C_xIC#P2tȫV2 pZMZnֶʩ6Ǧ j<}܅8dXb]7.'+QM][d8֙O�o9IDU%/ wt%&T#@<dGwR&|`1G%Kv2JqM,fU%qOfmSf�O2SeKUg;G8zD.tOV&]-XYӴ b6.8^E^6Sblpuï.mILٽlZ%5Iǵ8(|~ޭ-ӯ8Xᗌ ;q]4]ӽp=ГmM $u[<YO /@Y/C9#&v$$zѾo_ @i~3e^l4 u2Oc~1 y`*ݯ1^ ]aoΦqB9Ifo$2{f�EBUiq*vJ֦=i!Z~E(!y0-[SHA~c۶ qx@h_{ /*a wD3ZWwYsig&/ ‰XҍAQ"k'_"?g6 ?L �g{têvP-# bT"oKFdrc: ]v}MB- LCR<teUEQ y R$krW+Y8Tx@Mx `; @ɰCje2!͋a="E2^PT#Wx{ vdr!#!! �ۋLa~/AzpxAEaƁd" -Bd"g=&rweT' 9LFG,(F H/Rk\;Cp0+^z�J⬥ܟ;m ڒ ~(!$6GJ>A L!lUUy^-8I|2sK"KG7ubH<enHM_?O`D kJ߬ 6a9* &H[] )ٲgġ+|⼀\gYTgMBAI> iz_Ǣ VK"i|\|]hW&ی=Eط4LAARIB)yggDEw ]]e[}*8lYǡE3>yު-]r )܆ЗS871 5G I&%U%c nl5?A~DfQ6[ z+ �QT\m(2<xNPG(!M_ǖ([ې wt@a9')Իn$ GJBnLv ā,ɫ>7u<׀'ԊDGN~`UcY? U=,A6gS>RV6jw.rBC8ZVDCn�qq{^&dݫš,Kjdv>FzB]IvivNY9D #dBnwY.&vbx5U9N6Ll񑚂=?&�nQfLݽ(kA@BΨX4~tcX݊; ¾պ)֡;v<}Y!,1o>©4" S;br7v[LVQYr#40{5Pal;B7$ݐH׼,[9-*]N:q8SSB-F�:Kl q4;=Oh" y'!Ϋ\0,(4>SXŠ˒s<?;Ź͉/5H3dxp$"I:d)juᬣ4=x|7H" CCW# tKW 0^9n^ �ZBNj-$ #W T�0L2YN7 UVTŖʬ8FL Tl$C`d\_hbX%䤄mfbtp,Y>gEL6,`1R Gj3DiUU~O~iHQ Qvg>{rHvM7RV$21S1zaEþc0E#?#Y{A"="0?=%FTs�D@y=(A?1L=܃ŽQD~> 5*�2Ȭ:R ir�c:{BxziCz Mr88l~oC^2]~'5JȣG*IK#oR]7FRԦO #rDM[ �h<n(bږd, ,KQ#塧蔋wEmpL'Uq;J}(�,OXQ0 8܉[0e +Vq {B}>NDAD柺Wb +-4Il3I8 )$ػSj>6ȳgxv8K*uOI1mSSȳ_fTB&G^PA(IW �o6&tCĖ.1tTțݝ6d `A=AE+n%y� z< o;Y< G)$ |>oyz[]7tӚ$z~Pc'#n h*tQyO/g6˯G>d+T;웇]$.gwF~vYv ͭrЊ#2<h3'ѷ|ēE|"@IFu#'62a,+0 Dcm0n>r,m}F4ʃ#v Ax3@ͻԟRVBmU/U۵i;o۶_pd1s6\iݔi 9I9ɾ I?Ln?l1>u>S湋xhNZ$~xΛCTgQa[U~vQt-,~X9xpʋz89 tIXNu>Shjs}~")ާD$Gu'&rp6_lE4"r!ߺ'z"?Lbq!*47LZql8>~z G["YJQ?[@S[D#xQPqD;[S}:~SQ~вcn</ ~/b8z I!R MY}h:-{ˈFӅ4Í&8@< ;|BЎWo{IøH84e5 GOMwuU3!RT .uBpr�{Z!&-,"Ctf+/Y#Q\!N!iE t m%Y7"t45*U0l:R:ۖWWu;I!VyNܧA]s',_--XY5Ӷ]7( ,uhP-U<ak@&rh@@~Zڕjb`T`v'gZ6ٖ >;hm4Ʈk-]ެ C5+`hB((N&d61,uϏ]�vOcL(R"݁|6ZRU MS=trxA"6Qr|^ېEf\,[~;7ݏ?puroVAhuOꁚMB8FQnU5Pd=b#nxWet2h6R7l%y81 xWޭ8Q෬dIEL #2/ ߰<W7oFc8e[9/#6#:-wNmkE F`4xBՑ}q( us~JVۦS5%x&1рL}ϵt񜴇d9QZ22 *RcѬh ؃Dbx S{V05MEIhྗX* [quuE`ܸls Iђ=$ڈ%e%`TUqWI a)&= J k7Agtۍ*<j{@p& 8$E`Vڞc>QM&z=bE6!H R?IyOl݈H܁tApC&ƶbjGM]!.zS=Q=t7b:25^\x:*Kp*|$A5&v<'')QRj-S� BͧHc}O=C’QU;CYYSܠT5U9~BZ8Nut4*KxLSVooDI9m,I(IE]pV]{�upI5 qd!!bx:ɩ)Eអ<[e]x#wi'JvDbW,b�0MNً-y0 0_bt]#vstU`N�&[u_N#C<J|;MVka9 B cX3Aiv"j:&ʪ- 8*L.,T>Rڦ OGq; N}:$0giݤDyY>\}cu?NpᾡFtU B+{n̪`ȋxifԉGXA :,nm uyт[xOTST?R'6)Nۛ7] X4aPhK#oiGqv28>(l ;$c3"�R:I9&v&HPVƒ Wo׬dZ[!hhCa .< -V=|+-3*^\`r0|?8 qEI֌d'я@➦!7bxJԏdhk)G&I-`N ~Eu($i`w$7.}D�.2o9Io!.JcN 6hQ[%?C։ +&DI'IѼ :sWV jueM&y�U@!g މ7nB<<+n=|8:jhdIƷ*I@@&ADD{bbO=@`)NG#dByq\9 4tux<p<>:(+@& GK4b_Y82eOғCh:=L�D {y=eF1Lb(R9f )�hGR̂nB_8Mahc@5h0? i}kw B3?ncð{F�[,A\2nZfՠ8@E͞艹ПrC_Ysveyhu%0ݚ*8�%fQaIoaffR!ZB2�뷓-}wuI\l>6@!"p/!Сy'-UEvVS;bT趶?}ljؠ:2džm^qܼ' %kݮ.` gi-cg+:.=ɻ`H.d#Z#}¨=gt-*_vةxt+z*f +vg@O# byD~wH~AhM0T+$QϾvP4W�YDU3+%߅ e6gyLy`-T�],Kܾz3 xAeӖYYZ'w YSx"`ߴ,?h+ H io&VjFbC�̦X綋wAZS=$*V"D.q8 !mv&  UdlEvz8+[;Z4EBQ!3t^7r)�b?. vu񶈥 hPan%%[,~ulvOxt:_m;vW:LK.&rX1TIr�7o#h nP0 kJ~Eh֣̳ugVjwo{s}u/ĬfY`cTEBѭJcY75x#mE!@ja陪Ȃl{lyՍ{jG무 m_cqk5}}} Y�'HfRSLKk_ԟkT5TC";=F}fyw{^бF|ݾQb[fKV 0-8Zr+N3i$`2Ė]O~z�c``!ۦỰ&."H]?'!p=i $ �;_ݮgo8^ y5v>]{`7lA~QBU I怱u}u4b5ywCZ4rN "8 قTY:gy۵g+BXGO=9|kŻ5'>](J0u`|)Ze@ƀ58L=i9) 2TIX{`!4^=ws @|v#"g"3mi~%3h-ФiF%5Y޼~l֋#JVIx4$!Lx 2F#<(N3hqNdcI,U?rOÉ6;6KXrD9)o45FVKWO}AW \BU YL <] _^툭$}E{,Kb,x~9R&VzLbt ӧOOdkGnI0/oIփwjxiK[Qv-tYą_m;O 3@�9uOc_(NzD.;2ְI'ӧ]`Y0'N,  ƞYB@Jv-E__oA5dIcHMYdի2LMg+8~:믟[OXIn_h # CŇ$s/kiBx,=d:rua0C0g1 vGP]b(�-WSp ( r30y .C3V~OG 4i lB% ĵ-C^2 R f=Ǹ~@GDa}}E̓pd=H:�pt3x} .0S㼨Z>;8kE<K=jၸ[IңA];tqW,gn%!a98v)s( 8hc~~Uy}{ϮgDUrx]Sg9=@hmhFϰ '?X:!#‚MyËUys{yswӇ &NS_ mvq8H|6O lUAt5>1T@j~ugRjGՏϱӾpcKo2�ؘSwSS +]^K :0E%qF.m /(NX힞:_Sꮡ,nܨA떏ucL! {_`(U^L*z˰_6easo$3,? +Yfa<M+ (ϱmɀKsr1d Uqq9S ;$O)^NV F=D[f< L;!#aOn8UBP ҆ƾcf`XaZGM[H%xHms~eASݼ`F;46dӍ.Nnʷ$]CjY&cޢ L]UQXb)yGL:q-,~~xj" G@bi+/"͇IK/Ga`:H !vq RH28*˛:,Yd[t6Ċ~FVV-Èx sp/N?NjWw`q@Ele nh M dq`gwbQBNFv $q@Y*֯j~wEηNrw5�lz .ojӭ ĶplL0~?כ߁ ֤-fo}~(2?]6 kрeZz6[8<96N[D*:1Lȁ> u"]؛{n@~p[K]//.i~%:x}'0,]niEG|ꇟ>NA3lنt]5l8O"ì^1W5OvGh!{?]D)NDT䃣xXk@xD�?RM| m3Ҕ^]0nCf>Ũ6!H|^Ӏelx_pfϬɄUVlVS;dX1O`%t И8pcSan_}wĒm~X"tr kn]wx: 8@D8ܢ�X c~r6 ^|r0mcH,Cfr] mL1Uġ6ʟ̲o~8pзoA=�VdhI7J n?u+x%l5N&v3|GtF$C (mwcᨂLK Ma vn2GE%aZ6k?,ESF1-UV͖ؾq;1̓[lyI3&ɝIMqG 뺩|ח-f.� n=8?A6_j79c1(^zY/e^zY/e^zY/e^zY/e^zY/e^s*SňGM0 u?ѿZ], VžiހIwkj2v-rw5k N($ ?^KÏa?ֱn{]NÅfYO֚e]a0]/X', =bq{'Yd&5U,CO^QN;w_]NTHܒy )(F @??Fm2BӼcsy8>hhʺ#8oo޾~mT]߳?‹hpqJjj=nWm$~XՑ^ӥ'eӎ|v:R"e0INoUYV6‘ۢԹ?}{Qy9>=78tql#Mn2H@a]M`rz=nXasvLSp4[Pf2MidVnQYY#EUY//ol1Pnٖmk 5/926=r/vخgNR![:х7sNd)gUl#iV~,B~&iףf Xd]8CisusPK=z{'X:N;z$Y]b-窗8";LӤ*|-EXgoX7 W[|l8ql cBe o(||־V6LڑG=gHD=<{M947"_ҬZ5 )v7@!^7"3J\K[-xET+mV?C,Aх-M?k2q<\vՒa9^ZD[fM[g~\[r^\Et0Av¦:8p0:؜؇$[>*,u>ݯ]8.6vT c_E upi7n[o[ߏga$]U1]a+cEa4Ѕ77W-} j>}2Jfom5lbCš6r]RnWn*n(Y~~X̯>-PU^SYZLvcZ~ui5վTS$"xh?ra/)N_8*P7iUSE]n ׶s IX!v$z~ghߥ j0$H4M�}2)mk8T_uokgul OMӒ@d?aqy^88 6TQV<Q"CaOQ( Qk бH=KdH]Y(!GYdy_DO-E_V9+F;rKbEݎ* Km ?ɉKgVwՋ!U׼�&g__O_<i=tMgqeo|CBaǞƉ&C Peh( 9vhD!$]g Dq(Y %WIpuR6fz #pSqSќ`%*DK U]2[ep/_Oc&(D;z( =ӲV;bSPXFvI49Vk̊b64xLD.t2+) ŐfdWyeȼHS&_bP{⊳u)UFn~tV U`paj _�Dl˻نD5�(!S)#G%+j-P_tsSn^zv"[dTݩnH-Qv+S>.[UzM1Y4;[:�e?eQq+ʕ%;CnۮUf!($i+}KBiDGbB<:s�<KQ!BPTm7n(SU %@S"i׵l8Tk̠?gf2.Bvqx<H12dLfineIU2L>79Jr S7U#aja: +? l<SلMC AMD75+} m{{!m1%ZDn@bYU [ь{2v:iv>54җ$^PPGy؃WDbEAS| c{InO#q2=c53HӌS P<Pt: M ,O}#Յp⤬;Nܶ#ۗ.Ȇa4D\j"*3kC^/@z.)s[h@p^jj8IE֣J8 W4FbtD{$R_@5ز]b%cC.|HHTSUY^UUs@i+iu}eXg\(mFRTu ?\t5eWi�-ʦdFT 'Jmj˪ea `p ̣*þME82I2b(Eo跌m[TUI4fJtQLeٹdaX kC08~}+(,IJ"{6Ӻ|]@u H F7#13|:ΒX)<3j/Bɲ kM qAyaDZXa2T%Lv;T9bcIDt&&~I>Z+1I#|X6Oi~;++ٓ ŷh&K Y'uvN:W@a)' V dQPIN8Հ~u8ex9_rԄ@X`5wCtIIDDGDZʪS>歪<ɚfDZN=Wׯ} iy0C7Tc4IVr4:%2 9 c<_G1LS5Q>DZߣQ7gmg ˇv�$MDzaQ ،ω8dDNjױk4^ 5,E_n6൸rpQj7i5. d 1w?a5?l^;"jt$+ObA'BE\06'AVgJ6,45U4'*v{tB]e YiXFQ?8=y"I5gHK ͽ@:,Ch^t -4h:QK/ *#?[+c"ò`;Hوq.]diaMg&8gV&*AuIM23G9ݒ(M-2B^syĭ&Y [cOn״J%V-fiet8*M[ΣjH(,tÉɲqDBG.~#(=ק3Q@hP$+ EEҙԻ͚q8{ARbG9"Lt:)NydEoWViK6 `:ao$n׎IbO`#uPfh8\_J@v�l O?&%IDv$2~CˮkKW9Y-lq͏ȷT5]7'tqgҧQܗ6]_\K&z$8aJQMGu$;%2%dp֞c4kQ((*MX-hǧ8H I"r#$M<-=.3}f히CXtzтaDi`*6ga;%1 DD~P2, W2jHw5)"OzH{vMBNFSbsrWròFq71̕ g/]<AܼDAb>ɍŅp6U{QJ8XE-9I[A 9v!<9gwH%ukxyuh8,y<cSb�Ѯ}Soўa4 !^Rf,'$>`Jrq0_|e뛌Fnf4OZ)z- ɾITȺnږy뾊]KsV5óص4#@ȘlnqT6 >?y p&QED/l]KYGgQjtº"Pj$ 2]{GJU퉵-Nt]*mg+)nG@cΊnsyvҦ+ҩ9+[se`z `7guݠUd) =<jDyO"~-^-i+aa:1Ghk^ t}A\W0Ia>;Z6@nCBm%L$48J<ЦPÚtEg)[&Ցk(ScDQR)  RuYM7VT+YZFv0a?kMMjvq”XP$n%Їfy )izƎ$ ;F"Ǵ.-0 ہB59 .!E~O_]i;`$-:YG,M;ɬd1uUv*O=*|fʟ-2KȦHô|&lb{YyH/* *fi�g fZӺ,X;V! 7#kkj)U`Bd% 8cLp �p[^Q=9-B@�QH{!V%#oҷEy",�+z$2 js}(Uh2q"ͫ]tbہäNe=!-ECLf` qiԻցv]SugnYq8}ReE] y90<O!e{v} \[fpG@H2Q,NMq3"@h00ohB׵mT~`E"1|q?! )SC1I%},4o-3qZ�Ub|ǴR%vh3=zN*تE0#7LKӞ=$3ߢ+vCL6ds!Q6{䩦n @$MK|5qCFeCl!y=e-g+=t>Q;8Q”."4u=sV~JCԣ|vkZӢ,MM&È`GR[f3TJ,%H{=lı9smJ4LFI('UUs=4P$x 9$ 88Q8mh:DܛL2.Kcnwww5MSPb[mX"}XE-d�Î0jo("CU׊epx:>%M9Cd=Go]DIIඔ֤8 n19t q|yG+ZRY6=:t7AD.�(Zl+i"?aS�^ iH4bτeNF+;\K[YRU yG fxdj2-K` :%m˫ Dô»#�pah"JؐDBb:i~ ]۞%&=<<<l eZ~ت  9`: ,やuXAlh5h3*= be!I0Y�{iey z3WܒX m(d//f]d !Q&$/"-Cb[)$r*Nl3_UPA&2hE@3av".=GW'Bk^w$90,϶o%` tXms(N)=h `t3THe7[^bKC #$v@c$RxAdW-u [ͬfF ȕBRH&^�+ļv`R-[zR�nʋQ +*v HSw3w%ɇRtoKgשFEk4SW\}y+L,k\Ht?\ OgNF[9C[myUȂL ȋ,iAae$-) �A r#R [ADYL4O5>jW,KX;^ Ud[NuBxzW^q{G|GBL |:^vFqFOc#|v8q6S f�To\"@&z,ǔQE Ikh@p$ S� x}?Ն!^@_ 26f^֐hxe?sjgٜ݇O X-YORM6x</%f9g8 #o Mn|K SA -$FvⲆh[ܓ$R9^1Tܱbws򳚄=ٴ @rfQh4͙@M+};YM@L197%qeq{$.B}Yjv bm3UdOϑ1-s@zR$Ș3S45ִS'I 1</)B:u2mGꞱ\<yߦͪisk7<ѭI:OXooYGt0]aa%w ;IĶ_p 2&{>4"xB˴If}OR/15Ͱ*o"|͊Qם ZF5L,!8Z^0yS:�/ 4_=Q4.:HBx!^r\89g2)BUL~-zIX?nFh1+Evޓȏ 7Xo߁nӍcYi\MR  <?0  #Ov6�3FH_2C.Ók m Z1mK+BkYxw e<" S={)\D fP^ :?ɢã�{-wX@*n5eJ(^KȪm;^ed9#b#)X <cD]t!wMC!Q <Iz ơ`mxarp GN·&{m0-2`?{X<B4#zJ:Fg q{)ľjxi<K.vi4.HD&ݖ&w?m_piw/A (^VT;Ԕ]m2T.#^[`V[Q|&oNM0r8vӻW-͊|9QVg 9ez z4|Il;{rt{ZQKcR,DzjlB'LWAX hwQ3*b6`#)PDK7��aP"QXxQ6Qo>|0B C"G^ckZ!fwu>+,w.Q"u+"7eQi-5&4YՊyٌyWmewaqXڼm/] 1di{LXf%Ôr�!#q6毩 xARVKfMym3` sS'ѫYV.kLhΧ WCr ,r0ͧ/jW 7-d xi5/+A=.8&U0af8_\oYVO#{Nxw{GX!!ӛrc1Y,7 wZ##VUn}`5Ҳ6.e$K綋|eػ[3dI2J�e3j1_n0Onf[AQ_Ӂ<kB90rt <K <JtlB &^-W-֥r/=0ɫRFө;D챋UXj9[|qF2d4+cOΩMdjX j j:;028 |$U8zCݿ["мI iK?yXod{a lM<ء^`̮YfgMa{9EefE-'gR}Z*5%#b β(\n☯`}*LU&cKSA&ʢ,wYيz:Ӿ#G:&_ɬKJ$}a,I"ߵ_S-{p}e0<U&m]QdaqFFvJ-IG(ή-oA{c7^\#.G925HIq*jMmf,}EcM~]GEZֱ; aXXǛ!WGr/6hZh벼%JJА+Ҵ82U9HiY-! 7^�pč}rGe:g?YO.uU`쇏+aXxJ&$g4=.` us^i9=>~Jz=׵x�~I;,^p%TÚTX̸5r𬡯�Ͽ TR?@ǯ'I@~MU(HeYќ)ڑU@n9Xp'{+whO6}RSFn9$S㜗EQ.׶ |>mi>0S�fdZz8>~gpSZXNk$E3,4V I靰4+nvsm2>&>=T Ziv+G$KՇ ̻Y;U+(ia g^7),?o">25x&unHX@1Jd! t7/Q*A^P4ɚWx#C;�f12x4Z/lEIK4v� |?sOH a^=h#L Y(*v IRӿ̐ OW`4"4(X{ȳT 9M'wu78_/FYUwgm`UdQR�HO;O;4Zl'U@>E#ڑ̧= ;(vZ&JOC|O"D?>6% NRu]ay#a17ӗO?{ȚY'f˾<`ͩ_bƃ]CyƩd 5'qLZE%]vMBM,VfZT n=:]6W#e`O}/hl j Q)TD,x K�?iuӴc%ϣ(N#@oA0|8K酮=anCS+attۺıhNX~եWEWׁeCh7ayENK|wD�'LMڬ >#wUfK_;[^w3%IK̰2<K=u`fM\.zQĨ%EΕY~M~)gi)v%][}ߔIft~?6yұOJ6y-˻ܯn5\X|L;C^x4 `HIE VQ5Lw�f HvN= k 7FTBE5$1HW n@rʫ?^> \"6OT?}dž~O94mkͱdokmhBV+l>kD<VEzIKW{Ǿm}O6]R K鞇(T|RTd[}fS#a�-tOpsIy6@a]P6mlA`.t ̎zah$Lw]N:w;Aj�ժ.oono/.$J~JH+v(c"3F$HJ8�A`oԅbJn/Wfx ߺ3u&fbT9bMJ|֭gYq7ŝH'r&u7<IKl1?du e�܊a[D: ܫ˟/>yi/x `q3w@!d?m ܱrbVַ>`x!șmKZh{IMN Z}:U~bX{?>J}'~V2 bi6PJ rCrsG!.? Rם ,8{_~@hٖ&blesj Kx8.C[_0A37fw*׭cD2Sx^{< i_w-KOlM/֜vKo Hl/Jo"ǍpL}sfE9U Iݧ $!?[-~㐘:xI<D* ?]W�C0EAy8Ԯ!+c�:,{;@8:ve�ZڀtE\iݮrUzN˚i:./lGnZ<:{?ccŅd#!ͳ,2! p;h۲~]biBӕ)HFAsHf;x?h5l<X㎿ij}Un_Eqo V`ߌ76xom6xom6xom6xom6xom6/x F1Ĵ g5q~66DiQ-.2+(V$MB /N߇ef%~P=2O1pqKqN 5(] %@4.nFZ+&qO4ȕWc۫V2nEr.$t]vCŻ`v|iT< l竏GT)2j&@.)9(2ei=0Voi|IُGch[c3qㆩo) 7žc_f%3"uw?|Qpz@hV8t�y4]5co8jeEwI6Ư? k:~㱴IK*蹎[Mz1<[ N1,:,4y+ b?|ݒ>2MP"wmk}Io[rPѹ%馮nVѼx_X S(nm/z~63(ҷ͚k5nr[R}<1/\}y]ptv9cwK=,u:*` ;L#Pz>odm뫛w7 D>Wr;ZY1& di1)*jF$v4-<,~ΨEw4orw7@4' pؕ|/9Qp%:(5ۏ"GbCkr(/ۦ]CpaU髟?^~|oƨ:VYQɥ'4/mijll_;]+4EoPnzY?]~oz|\3aZhkln<ncY?V�Beh}3F5L*̤oQKQۤCׅ-_ח3JaSGvgc_uᶮ|70$*p?b}}/64C w< G_TxB`h;)Ė.pxR_^~w3G^Vʲ(Ԝ3뛍$u5>1ezheh2|B߯u'L<Wg?-^qD<x:CaSǮT>6hJ2/yvˊۥئmz3P*^G0si CR=ZцajC%N.3`GqdX +a'=S7} 14k-@̑ifw?~=Дe3�a`8ݸv%=cQaוJa`C />om|Hen^Dztuo<35S*0i8RvMv}I,j۪j{%NӖk.!,aFc߇<zݾ;�+.ʊ&:0Ub7'¨]*`eu62ް M+x x` ZzzlIw?pm5{:Bԍ'e1D7`E!N z4E8 OB]h2 V,sz(Xa{؅DֹkX8&FW:Mn^q e&5<,]X3 C*%'rWvjc".4 *9Q$n݊?F%CXX-l~l2MBKoo8Yy=+ӌ8 �%Nw,i8};LkFqE8O=ا>M%Kvm3ۀLGM7U  ѳ=agwA&UǯTg[Y3tE_S( IAJ:FiTCZUdI6h �S&됾^(ؗ^ Lzl%&| ݴ\,j&i.љ;J7l`I nD'>$sCG)�AboX$$A+V Ԅr*,DQ"tjcb2gv :kSg!j« F;'.}TžrJвMIשbMϪ/Q쀝آ( " Qb\ !YE01 F.x[b#⾂ ?.sOCˍF$<<cp 2DZL'']WI蹞)$ =(9kRs;G)?ʢW(NIfe+*%Lau>hPh m|oĮȲ[`UDaDz5G8 $}y\nW Y|ę~,;ai D4ֶ)/ ٮEDtHl?�/H"X8 (X/y*  4�EYM*@ $l`9f0[l{_(4'?< b F"gq e+ر&}W$q֠!TWDE/ 0z!P#(ĔhĩO(Iv,?^&(!B@ !:i s/ -ч#sk< ꆡJ*DYխ&t7Y@ő8Е?TZ5-?Plaw}4iI,0 4{Q\7Tv MSgƀ#?"u0\i/ZlK@EvEh̤8 F/7< sVUݫI x 6B%m??} 8 _aX_~#g@TK(2y;xƀ� u/3I `5c$3][hFPqacY5!!~CKz6_RlIXbmR"r D)Po4j!|[a9PKI�r�Ni*D=.(;r}ZD ,nKZjg<n:[N%B(E:iB4p&ZWMDbw+P/,;7)oyFy (JSd` (#`,xa&FG6¿mlpI$ ԇ?md&`E-%H*էI ݀o;F+@<̜5')aO reӓЅ:aa <OkT Pڬ!e=I!RL$8v i}}a9CeauoNx$AxC&MT{|Y5K1(-Io>0dut`eG�g8IG&{Bۇ0ece<eۍYu]SW0TZ2[\aXէ?EٌL!-MK}㑀źL=x<'Y욺៷  FM4G9Y7 ڟ$Q cvlEۛkHI'4H<L4qmh<�KZ6B&,]R׶X(b8]6a'#AE [9zYn p .ZTkF),PHkt\fUTC>@j[,~ f�+zN:Dr2i—xg,@j#Ai0 fS&{d YFrçn86Yf;84[noV73˛n�Yٽ79)QY_| jb9/)Yq� 3 ƸX]fgbH]z%J a= Ȕ92r:#/($ y𾭩Q�YXQQ 7�n2©wCn: 077;IUߝG48 =YWuoL[]G;lIxܓ$a@&y~sy8^t 2e'<Ә-iǴw/g_=Lbcx!%CzU�1>W,=+k/JDe8NcC#_:IeQ 7 L9Q@bfE:3,A\NDF5Πq#ʁG`IeY^"ɺne='?Akf-Nڣ2v1'/ 4D߯DY+b-ޒ &?: SCq*e0Cq@,˶%4 C5x]qjqL$jMԣ;*8".|CEj$=ݏ-BMLxVֳ Zؚ&b5~ΐۀ u$M:3Eěَ_BDşNcO"Qxjǁi}<ǺHؼvM:ـ#遈9.r AIhDN5bOkQ![=ayG氒X 'Ц̳x�KܵUL/`8rԳ4ݎ#:3FNR#Z- IёyǑ'Mh-Ȓ([2s^,x 3x$`s ~.V]$:94ubJ\*�iYB t8TU29g(࿳| 4Xy]0c]{DiΙo 67,u.i_NjO!o c(kn"{\ Y]߬w 9▓ߌ>mpѣEcҷ$*5[ܬdE2 @9xHbf&:۪ıfV^㠚=%k_N-O,E�>=Ң"OE@1%$3; MeȮnf,ZAUVVlUoI]EpQCc0=qLߏyDn2*ՔMH^gI8& �fzB'x8֎Z2ВYN:iXQw8v%-#|?xV;A:e:)Y4xf'8~ıh;ۚʴY?EUM1KK_"Sxzb AqYl<4<&pc%I/R𕾞t1psxKl^b=?em"yd(`_Mf| BS/@US:*5)` iEdm|gGeࠅ(*b79Au"*LpRԵUUK7(_DPDbX̀ԙ z>o0<M B8 }T'Vu MK6F٪6CDVZLpk3mz EVz3hVN3S4UJ L28atS.ڞDWO tDfzOt6fA"|Z^^Al9^b;;'*>=[FJn^DC&BS)IKvhtd2 { ʗyfO]DM7o[Z�ȅoI4*k$Av$ 4Xfvy-HS_$a2Ueq÷ɢum ܎9X.gkp~&)qP? ,@[SG*5+%p)�ON#Vmaסɬ<‰a< ^|kN%^q!mNv%:%;]ziтW�"ni=#P{rDp=z #4`^^,P72=!>QăMOM2�K597@ћISZ@s ;ȉ''' c67R[S};bH, &]]&ҶJ0(+j4{}^2٤Dbj$izi68̓'PSal6 VNTkrHӛ5>։>3;|pw? ,-b GwaD/B4b.)Vڊ5~dN'=:hNs NsyӬW.75ڂC "{[]0| vz<]&U Ӣ\&vp:MP*,0x-/Xɇh1Z jqlSw'ÈL|[g+N}8�4E:eҽpwhzqγߡ^$5H\RCmY٣ Sg<yP"tLi73*lu,A sVw򂨀"މwSTVU(35ù8U QG"f'bןxb= cK; J#ͪ3^5puCI9ig7kvD,"`{~:j!5bB)Ua6=cm9;au?Qn=ozjn SĉFT]Hw[j N`o혢Sxv190nLubIS|'!t}NV'X1& y-^1{%I3U~gEy9zð#ޤ:}XQ$v1Jiެ(Ϋ=i H)Zwe#a2uY`qvtDd Rj);*�89w ?u M?ľ-nOO/6F{7$sk3oкo~:I2p ĈRysGfRS0 x)t 00&RElk}&Ǜ[c; F};K8ݨdIl4f`Qn`kX4)smiM !K8fG%o7/36f 9a@wJ/hLkBOc.<ev4%'᳄ 9n;ч4JJ XsOL)t=eIlhyӝnIySchvFI:�MM`,"kvXJr194iGr!*iOË֧)l eh7, 6? 7O30,/aAi%NjaJÜT|z0`U,}O7; 4۫'I˦KP®@%ghQQ�66eFmRUchPͨcmUDS Q $Д{c|xXo(FQO|`I(@Lۮ6lEUf0[) 4/*vRmڦagS|yO_yXK}x5P SVѓziHQ3�M ~K$*o?`'cy-$iGsce>gy%Ї)gi`WwbP F?=8 C b֘ʯ}Sؓ DQ/R=VŨvTM0$y'$-sJҬ!$Hr<"`v,Gp/,]7+&qR \r3w.CJ%N5]X^lx$1({['y*-oiMw zy7}Ӧ[|ݖ؅Hl SZHPm@gW'<^Ph%D<H dADSb[ ;F0ǝ 4!\OY6lj8|#ن8vqOfg;IK�˧Kq<�y`kNT4t7y`η ^QeaZ`AwD5.d*Ǭ�5Xn jnep8ac{P[|vskm @LmSSMz>< MOC-`Br>-9^wM̚e�S0:lKDŽXz^-fwof*Z~ û[V]M vSy]+m $D"ϳfK][pr[F@-$f-,WjPj nm??ݗ8QSȤ#]2]98^x5_XK*޵-VĿpC,FM!Y{ 3OI#6=&`ccX:構�s$cv8!s뻫-:Vʩ vEpG@Ӫ?<rN<̂�/)S!Dauڭ'>=`~ I.=]bj[ >!yEk eIV0BB߇tcƶ,I# qb>yIډDvE^>` ;k׻exj'EK1T 2^\T5Ԇ$޾_uT&}?吡i2]-vxo_dƷd.P`y/S{ =n*Zid|CQDIPjMXa 2yo 6i>[st1 pm(-D S&Z60iqh+= KA耳o䉵U6YE['Yܡb<+9rꎧ|hp {,>oEA%rQ?LZ4|bp|l˾PA3p@} kHQ ho&gw@eTS-L!Vc9EDY9m L slX"F4I`z:_ĞV+wyiVooZqO}X}xXac@"(*5zģeW*ɲgNHXZDxY끔׿>q쀽fk[/ڹF3MK49OOXh3MRe-Iqer Z B/ '0KԤx_B,wzѝ>c4 R,sycpPm.%2 b)Qփ"\&:%N[<q4 |N&/(H Cn^Ufþ<ƗyI֌[|I1n 9C{ND`o�>REW5.]Ƕ &q%Py}i+:z56N5�@+ʡ<+.~+LiPIДXk?jW7`o߿=_ `W6Dj0$x,�&HXwQlۚzv.XaP71o>~Zp Ruسudox 8a ew@x @Zlvnyw Bc&fe$ j8(@W>mx�$ڭ3GV VA+*0K@=I-9+I :R8.t>�4mGK\?ClJ:,, zv$ MliX *bP~Ob$} N52έApl#SY0T$Y.9%Jl4Vg(b_VnI+F>2 Z6bEmy?|G5�aMѲ=L@35i BX,@߭v c,vTѣbd|] %^n R1^i"-bP L'fg4 z>nlxŎ0ٚws5pu!^, ߗUa&x q'kK6Wi'f"ϯX;F66[pya9y<Xf<>,kt2˅j[|g)^6,B4K<Ž@9wMUY98+&�=nÁ'.ehݗRx#&zvx86xdkOgoW<lt�Bc@طucv0m|?𘖆e2 qSN\]lʊ,l>{;dXK3>NCtXyg8rl_Iz&'tuf.*Zi-, 4˜ \@kxAU[}2X7Ѡ6ux8N=QLM.~>R%Zv;rg {YJf6$Xo./?¯ւn5Fq1 |FR^jEsz iMvtv^EG# Y5 -* 8~u{@@Og?rxQOГx#Phggw馀2ߏuycia><:6!sE}sŒ#й|8 UB1߹XY2$'B@KQj{}vUˋ0,ØZ@o%4ݴ~>m ;]qz u:Gan>l!kXÎq|xcS1;E7nTnxΖ2FD* $ƺ!nlh-sѓВ)/}5ўTTOpTUcuhi89GΒMyI>wTIv]l( ҼMdu?;LRipO?bI~肨 ufg@Y9@:id?~{Qc`TT+i5lC8%m<^ߟ%f%F$|ml*32F`.Ҁ\i9[uMg~BSH:q$K#ߏ2Т~cG?Z$ӴlEa`fJa_j񲊭\IJZT_#7/JMH,, %h!^z]u^z]u^z]u^z]u^z]u^z]-G7-Q7[Q~/^ 8,H$ TF}K}y}}?:۳3<|[KMlQEw*vg(7i?To#yI݀P[J1L''~ִKƍʓ4 Շ{#]1(ʛם4q,gן)7ׇ#Ǘ?Xl)W?dHmic�]Y:{ۙ}ا>_(Aj)%ò}іgV4vz8 ;1F&w˻f챫ӸU , P/G7%g ɏ 傣 zߧGyꪫwo/Q1<Hiٶedl�&6?hȖנ'qAE]Și晻ϟ..?|qq5͇¶>P[sG ۴6lf׉)Hcr;3m/Dˋᡎ>uۍǡ|C߿x"},rmFv"u=7@?ù#;lPn<<ud.('ص@-3TQ 6Mv^20O ϳŻ5Κn$ff gtwXqWc۝b8dMdjz!6MʲMo- fF[_ӛϷRbohc* ^+Nҏ]?oW�hmlfN^g*5?~r>y8/LӋaS_ւfZ(Q[:+꺦ʰS|Z̖]nLY`%͡ խa;SHz吚VX6]WŎP Q0͂7,Kށ,3X}znzڬ;iX\aͽl{1Nj3KV ]UTUwKr=[n8}kQx�Ysp<BuMQeY N~#ZN\8͖Z\m5,./5'<Tg[A {[xRݸh~|KWW<l~b>RKޭ]b+–DM21ѥJ3,es /sӇg8ִڠ-]+šؚ yqLaL/k0XFp9N:v i'UV[<H8dt(G0ꡡ~ 膗TMY$8"1*xͺre]I^]sXwO&05ƐT<`2U4#v 0v HR>}@ʺH<WSBnSO[pm*.cSEzϰ`$)(0ۃSaX#np]%e nKէw;8<u vU}|rl 86E=Ms0a 96xJv8ЮK j.zE DWx^xek/h P(kȷU5"/ȪCmSCPlH@KVO:st]z /n6q+l8bPܭNEAxI^0 y XXL,G斤U["mE%3@UQٻ<cF<k˂5œ"G3? e:M ì?7YUsҢS1MC 39N'öuUz [N5ľZ >,i-EGm['8;DUXcaNjlP*nqx"U5ˏ}^$qY;Vj!,);;DCpˋ@[2}uDDSͯcx=A֮@#L515/,fߗ  gl#ܪ 8k+Nq9ο];M,dif79-c'9m}�& +iڀ)L2{�>ñ ݽj�=2v豽BEQ$zNz"kl\zĶǡwÖdxhlE2y菱nDqt};ӵ/-q  w lp{>xPq\/+4MZGd45oV lkZau|F]n/3n۲T;̅o$<=snJ?l騤Z55i DX[pÑDW 14@6 9-%91a \#0^=_bd ɶ]c*VX޴B$DJUD�EZyMr:*sqB)9,-I]9@\4"9WBt3mM,KSeɏO Mj޾$ ^.V8""-߯|p; �Pt8?|34u`/`aXHvgh| és#k_;E#�qN1 Y-[NO# tX9>~ 62_j8Q%<K4]^W!_xGt ^gkW\48Y %9>Qn<y n2xЦja!55!aFɦpf6#Y6%+ Ea`0jd66|HJ"ǻ {S( a{@ VOpHT5vtN8^ROhP9T#J2.4ܭ?ªšP m],%5L*`i|j#`T.$T]ajF�MarMm)}C v8 ϐ#0ruй%)'gB[$H!\+qKc}i˲vKl7τ@ ,+[OҠB,2$ l0. ̉6:#O[lvw?#%͂VG+ c MIRFv+з �Q_?d!n7<X H<?-v�;DAඛݏn9pۦMhxؑQWayzfBX̉|DH Qec|.}p8{$^<6'@w1_$LϲT5{>~9%*Vw:R|Sw?l!QDfVa]$PHuي+Hӥ@&M.RȖ'W`�VyRp Kl)p?$ӰGѢY) #&/G~ 3Hhl �`EEy ?W;q3^(48q@N8x fކ,ń+N#2)hv6_ WߍTgAapn0C|ZBGF`/5:* ~fTyEŷMMlİ{]7ZCp $ Yr4Bm+ߧ f(8+t;fU�[9Vs OtܸM::<-bEEYи!@Zi^K H<0/̺lõ5a,@`dMy7򂑖#E@ vZ\8W X{6ep@vSB /+|Ӏ=JguUwUdU#-sl5 9ms&d=R$Zsl|$#ųXؕ-F'#{ΐ^JEa& wEU6"T` eMwka(^#͔#aAtqߧHMi)h}IqN4V MDDvk! pf;Gj,vbKvIhy##@bqe^d?L <H}۾$h:*t+(BaZưu,R5?&c#4*?U'ku�+= ` ҘKLǵ4_-yޕ^#+펤? Eɂ%f JqM>ɒ]K貿h?.銝g$v@i@9k0򆳫 7l+^6F�k=YMu6ABO*#!Ȱz$K-OgWM<I7F5x!Uv|0Z6%˹ot&PvLtnLv&ta "|EKr�  F4+$)%z3uXsQXy7lkp2Pn-T[)b[̷Mxi_b,] K- _*f3݈:xԳkYuӪFbo I3Wȥc%5M.,(-ήr07@4`Lp7^j4 5V.CbȼG:uL㡯k5]P-PK2ѱ}&@)�';[6vp$!GX7uY 8Ymt$JHb>4n ]̂)]4ۉK qxZWU3,mP#y{RSGEfi2иOKQ7j$Bxf8e؆*5Uv:W_ Oj"/tGJlBX\#W*Tf!⠷!N;V>P鵌IR .Тom*/:,/iq`hа!r jU)T%v` V M yQk37H PŀTEA{ZA}h�g>?u <<9a%auF˪F4G]4^1ZX$b 6-U52_nohQMLJo}wJ#%{UdU;띸r뎸=tޮkpw@\:947auЧLh U }ps knOH<lK4']7mZKSƆ4jX[GdDVƠ?tH9, bqя⼪нBKLCK;1.4x@ںLMY`9I lĨGO֩oiKo@D +o_i:YP F6vW/LBs%ZeރҢN!3 kh\~</1 z &g ǥehͯ?E# )8*>nz|Mh0{aə茭g&Dh\ ?Cb􎰨8E-O(REg7ZCbc y7* ~!@AMR .EaHw� ~^v!zyrˀ`k)nsPWJ++p##Vf"'u ΰ�<|)3[kVv j` `ف- qu"EBQV%v,ҕ,ݧ˩ QJ2& Lm?D,lL%xMA'Y1m �OPSO@fH/{X Ɋ X}A̫-I}Ҳ{lMuqD͘"^kYu[6EnK gG[*NLGtU`DӼ"`ȷ.QzkϑUmFX IHM|EH,eycb#{LvFA"~S%RGпl-7An gߕI`n{QlESGBJ6ual7V3s6>@q7tlyqn0/#(y.Y1H| o|s4'7u?lYNK—ב0<i?b+~ 0$#b 3o觚2 zT?L(dQ7`77ᕠ Tơ2/h]xh˛H`kLCx 9t $낿K#nV&�\ΧC6a%c�zEIQ&)I3 ["I?"G9@3+mE(9k'nSbgHa-nZ/Ω#I.a49r;v&"¸2<b8;#DߣqT) ȖmેhE8!Z/x˵DHp:<H `C%Σ&KGf(؇n9EIh-)L.l]X=.2X^;n KBy:VgןS1jhy1&U5x N Di܍X�|)@K*y(q:{dz!$qyc?'$甼?R"K Kf?.4iG =Ob\y+A2C`x|8u?h)b`oeAV;"y;v -{#fKZ O[Չvx҉AC}Y/Y^ )؜$g@ Zmb/is/x2dS]1V㹠1@[97P;A$VHf<(C4l7Lx OZe7e�_Lyt6Ȃd'~{\b kݍD챫##('L+"Kb%us`!noDp8�mR}ZػI7~\$"sVՑtd.\_0 Jr>3Vƃr A0X?`,1`uqet<=ٌ, !MS'!/(2 t;b== *Ʋ)Xt,_~M14�(=Oƚ:*}ÐtcDH{4ެA3<a, ,ƿ63DGDL]:9v㚦(UXe6$Gm`�AT{.UU$kW7*U 4q `pS{G]}^mhf-I,'$ȹ@WƞebFP N5薛#W~y>7.E<qÁE+kI]w@w!xċ ͰlgkQ\/ʻ.m>z$U]O:6dY1 4y!тv!_pGZ3?m肳l.:<vrL~HK[xgsjW )!+^:d �QsV(P[xՌ꾫uG56lÃr:alAȻ'+Y[0$ zʼn=؜B]Z35Ec± nR ry^RUexX2}1 oY^֏v};O/V4 uQ4Q>| .mD(`NMCe^tXȖfI@3J2&*\&&/)k^Ђ]`iT=}߇o溦J?mۥmްsmCZNׂ da좴al dsS8v TEԤ#O]ߤ O«8K}S7?<lxƮmhQۖca¦=HV1HsOXi۔a駵 ( ̖Uv뿶l׏7V|^3xM3^zç90f@%p̺.|1XF}[>8;OՖWt�tlRE=ˬ7?ܯ^~[/KRa4\)iIc,ժ*zptm^Yy'Ouh2nfu,[¾}-(H# J<&04;$i{3]ͧՖ&ǼhB\ S2OoV׏Kly0[ap7{G<Vn&;GW- j3m0@d yػ Ӌ%#s"3g˫.eЮ<$jZS$~9&lcǴ"Y0kzB4̃!x6Eq^wo53(T>Qt tYmA[O_NC!z8CsF5_Eiζ {3I9i 7CymTQ5{EwҜ.�TɌ^^C Zt_de)ӗ/>it,v; vvƂ263c۰5YeK;D<Dp/nf9;<xŞ/3hK}D_Xz!0ϑE dQ\�jnA2NUD =?QXt“F\'*!=嗿: dyӑH>15!̧<,Y{IEi /ɡ< "L&8˗/`OHh`47p"ԧ;^Tg]4#A{7$دx*dɏ+_f{="p``n@i'j@cYr\<?^#Xkz׏B&7G>v ,f- %%w$[_ @y:e=tu&ݐE/ )X0$\pv`:ZeEƾMRdG 5ff$),/J"|~9` [ܷ |9eA* elH lo~De ~ i}[Y^gHaR^ܑK˚ !'8JLkO|^ǍFIُVXzEK>sl +y ;&)yF-UWbHQX[V;K۲( <+SUx 'nw r# p srvEQV .LMFw-^!>ѾL#rl<^>)>6,W<8R[f!sp|<D?L(o+ <�[aʭxՌ'w*lیat=lh(iݩ6jbQ`nI$:%ؒ2a /kQѬtmyx!VD򂡊=E$)ފrZC[$aןiHO]fC1��}KMC,P)#Q1ˡY' (M37ˢmM)|xwxO:mxq$H&ԶV`x)V7 blr53PZ^L؅iG 2߆TZ-9os +ڷ*KiaZx"Ǎ u;ca*NODxR,neOF  |,?網^n(^^sV?Vċg;dm~mCe8!:%?O>ha ۟jSz{>BT}\l(kH@24"@²q-0Uyɻ)Ͱ:{ ]HBmogпV<rTؙF� y<f`&?PUr̀)[LYp6҂�RLw_5u]tۘ, +ͻS0ST嵉Z*G1\qUCʐ!n:#eLm d#}^ϓnRA*Sf3ؗ{-D_"Cb\ Szg[=L>o1Z&N|CPg^ęGـNDXpM>, ha +<t-k3U+mS,΃+cWS0Xw}ɻOsE-!uSW;(Mv¯%uXco5 u,iA44x bDз- X%v+XJ}zbkg6UoC8q41^48I8U6|P_2y@ᬷ=䵠S<L-7�"a g/IߥD$m>"]}L;< �8tL*?rwY3 phOc&kհpZ+z:c^sI`"Ӏх5%l^G`7l9v!3e51ApϽ lS586^9a׈3,]<S𖍍je 먬ע7Cl+!UAư_xZB6i;Fv >]sS1²x|q",Z}W2ᘬ.yɈ#�k+y2^4NblMLXgG_o?Aˆ:nv98�hlEŰ-\e]S?? ˱/ٟlxQߑ&R>#PRG,/4Do&o&o&o&o&o&o&o&o&o&o&o&o&o&o&o&o&o&o&o&o&o&Z?Cg6!. =u^P4O{mW(נ?G*2|^+ٸt{u3Y5 <t2( m<(SOgfK\/<mljF,M`X *A"ZdrQ%Y$@CJ ۔_wH)X<av8'#1Jf1Co?ׄݸ4ۏ]x)KDG!>u% _9֊x$iٝdI}^gwߚfP'&yQe \%Qx2GN ==[d䂩PʼnUIPb8Ֆxr]/Ud^ਬ>^j;A\O]lQ>6ڽ/q7+QM6dū f?o(•824zÙ5&ԕ�+>Gk`u5x Hca17Yϳϟ>{KiǧJeQ6Cȏ =Hwt]S oꛙ놦(fX WvKwO dGr6yKC 2l{?ZYw*vF!)- =OW^7?7w2!B*9[vXX\vPuE\@2TEw&6Rv]UfLtq.n>~43( dl]]2_T]= y>-I;pȮzY*ͯע1 3v҆ Il%Y=q]SP|ZOms\b}=SYfi8q[Pl z(yiu*oC(LӐX\sPrϐӭh82Y<_?rBb78/{0 A>umCX~#ךl= I' 贈l-E4M"GSKN bֶg߾_ڬ<na"j>̢xs(j@giaMnFNP{[i[L2q| \|fLMf?�>O} Ǒf}3Jnf8P}߅*]5^[HROn2#"32>QI:D\U \lcoʕsNs�sFzZrB2G.OQo{v5fISu9NPZƆͧSfVJCz\i!zu!ފvwx~'%.<M&?ꎇuwI`MOE᧮iP᤯"ːUYZ։Εk#�rU>v~| ]{/j3Ĺ؊na={� 1 WE[XbжC(OKGCY߳_ӡK\Q1-mq# v6ߣ ϚY:lm۱s8cccrq5yਜƾ퇝+,SS4M]=v6p7B>]t/ʃϨkآmu8,HUT/VjYv~iɒS;O ev'>j�G勷bܢ{@RZ}f?ioELSeY/j2MdUa7emZ$x= ]7r!39S.쫜V>?ܸ̉> ӂɖ6=4BZ;fЏ0w.sIO],qA*FKG?Yքia{%a\I}ϱBX77kU{0S‚xmH߿ǚQ<6Eꔀx} ^/VY󥁚 d qǎt녝vCC^Rz\qaj �5;nںjX.А=y7Ȫ:EՒ}SL(|c.v'55vMc}=vAJ7+K2Ti5jH!¸]]sG6F17!׀Ua 6R 3-6Kn>v箮*2/*<ȋ,Ngȴxadm G=xL ,!-�_;DlV:Z^ڠP_o8v q:kP7O�ǥ J<3[:blL:YW]�˺幯͹Bp|GA<I2LlCDզ‰ /J"/Ȫ<~ȨXY-6FDD~?H iuL$`"RKW$Ey}lr\&AQ$^PXzeƮ[>ƞ;[YNmԧ[Ծ/h"*7ظHJjA$Нd>e@TY6`8a#ZiiH݌al>b#xK^pK~ծAѮkV[VslOw<ǰl? #H `Ҋ3ƾ&2T )} T#PN@zQBs-D& Np:_@ #ƺ.c7l} _4  JOc"[9 QCn{$ lD3F8>24, &}=S]/L8LՀ(R:Ǿ0b#T{XYg ވa'>OhԖ(dYg9 2ئ}k*$p+: SJIpRrg7oWZ8P>k܂#H[X]FaR@ 3W^C놮籇2vt3@Ǔd*3o-Ud5n6n\̗~Bƴ?{>ٮf@onm 6s<~ylfT%h<@$@f]/~,@6ijcPu8u@BE@2o9- |1[j@x͍ORp]GQ:]'D4zfxt bEď=6GN@&>lRbWж2jVX3n""@]z 2*<o_ݰFeȀ@4F96ōܛ aA -"/+&Zص umr4lD#p̤"'0}u(k B4Qz&#`~LZ!\+LZXBÁ2¤pK++q,]]f9O3ؽ`\D2jحrDqOOܹM+75+DUF$YIbʎF<'l|BVܚp T@OxE4,mqT{KPWaQZӁhEgQP{CA! XRq"fL wQ-=RZut_?<'6 a>!n~Hx5pAM8RAvnҊ*+h\5ic;m]J]dDxt3'dL q1g%{ڮN}9ED$|zfX-Ɇ:y"Fkԍu 7E(a~\94DQOۯ W"T팞6a׹Ѷ;3nL<S�D (@hl 6Igؒ(Ha-LnQ[Z$%UknBQ\2QS$DQ1؎GK)@Cp騂W&swjfj/-?\aT0=M5,G[:)&QSiI|a*"Ma!E^R6㗉A)Ï7,$I(y;QAE]X   CFDn+"K|E^X`kx@pc\" OwL7qgxk@t9&p*Ԩ4o xL$1;&"Bfxd뛅9iDF[?EA @Gum76kwiFF#vyL^?Ava?l]U[*zTD{: Ģ4Fx$p^9g].З+V�;Gi"Tܝ %,u`q-ζߢK=xt_FB:P@&"fMkHHt<Sb,,.V\ Q6 >RRʰ6<N446/ao'>/C[铠^\ۑpLw!dqi-knّQ&@s 0;|ЦUXr neQ궭2gZܠ=*V?&MKOԕP-Nv @Y"2O uӶube@TVG;+ Yr4~~6Æ'k@:\FՃI ]t~Ͳ8p@ $w�2w6 \:g#*%N;aEܪR8p21PYUBi'j ELM9#NLDF#=K˃C[aSPʅ&FA<c*[r'35|CjF{󇥤iG6)ѐdϏ-G+0[2y#W'`7�nx܎˜n5QEX\ *8szI\uzm]tyB(I0+ Q*PRD%Fr_J{_q]`M< slM|Mk{Y[cE$iYY,^?<Ama uN0Ϥq@{w^g='$=~4@DWCZh ӖM[2Ϯq ]'-~wf ;�QRc,oQ7mXqI;!5-]zo6cUt0g04uK${<7fV a,p+mC#AMZ֒gN2B a=` F!9l/*-B4ΨRI#!_/$ˉq+-Hl~ bCY^ѣ#FwGą sNsj�eSŜ!WdKyV7pGc ;-U+gםw(}!w ('*5R�Fw!'~E!DUKe>m 7n>i!B6�n*`BJR)΍;aOZO׶ 5'j$H# V,0BDf?t;j/ߵ08h@_=/@c&ZN>t%,%Gz.mwb{^>Z2" $nRs0$c:XMu_0')lfIؑ+S@ĨgqiQ@U)޾]ay|#:d# zP# klbچ[=<Η Q;$ IɗuC�5A7/LS7Aִ3xM嗬̮zD#zHЃ@lypF|H]aC%DDhy+.*`5J*qXkX bQ�Y~~Hx@Cy!Khi0z"ѣwfj:d*Ǫ^x%%y+ m`ik xa퀧HG B, 7ML_y$uȲt'z=hB Κ<8cnx s+ ]G= q=I`f&.p ( I2üU#<^^'uItW&nqٝ�TӐ\иݧøEdz­FbH&i \%Id+|.8Y5E]kv8�CdSʦ0@B2>Mx5A0_xs70N`ti"kvEaݯy(p. 7YwߔiOC0Qu)lfXAK8\p􄕤7ԩ1*,=K^?ܬ-])&ZNT;4Ȗ^sτ $B>jR�3IŠ8O頇kUrrSZ^XqٔMÔ®UuS$fѐ!B/?wBb+Xp p;a=rp뻍E[qi'mꊂ૲%+KDj"ёDMp/I3eH 144cǡ;ˆ6:v6 N<~!޹A;tge&;DP ^4 HhM9x$O)))>/D?;|B薾e0?Y<sWAWI]6XKc>: EBCGwYzgfg¨hD@۟BgVhjǁ4qW傯 }W[?xg_J kʼn&t2:N;#`4/DJtGxG~]u5eǟ?~dxǑfOJ4rQZxP+b=nw"_1>/Rrsl-o狇wK,J jLe/鿧@. ^<y�89, =Otrpx9Dys nj^?~�>] TA5(P+ i 6/Hl < ѲpFD֋ŋ%k9|,֊Kh4y>Djqzt}p<Njvgv:>5{AChz}oX糧|^==₿}k $CTXXn6=oH>էf#؜BVnE|,))$G#!Ȏ\v/pWp,^@!.=OsVA)N!`u;jL:]To쏔x`Eaヰ܌'rщ1XlimobF41ʑCs&qr7E3@wE^3O3ip9N%T*tςcɺV7(LHÊ4ttQUXM\@Di[uM$6%qƋ2#CڦƯkѰАf';M7U͖_@dkWEY3l-f RlXwLȞH@5 8Mėkfz1μ26v~o2J4Do/X|ݪ& ˕HmMbSC s5vVp^Y Cxi`^|htflOqܸt[$IuX*eHF kp7$�2 K= ڥinWMU$ݽ{i >R$ R�DW +Ivf 䣣7s{rNX]W]U]%:H6{n-jf=v=L_pjI sUY=8y@2YUeCLny8J~cUu=Qp8 =: u4"Z etpܦqww;zu-iu7,\x򶉖-]a"uꤹQLzk�qtzGFɍ!f)U=I�ha==kX%̊Tqқ[@[Z\jݻo}n%+|@Mg5@ƁoC/l!uqLv  &.п\?./L<fh?E/!W5'[;-I*e,_<W1<zHޑ5~#,P7?ʚj1xJv`DֵLf[`}⼻9$ہ4ŊpO/h@^I,xF]ʳUSU3ް찉 >Ewxy9 `] {j`\Mϟ噔)<u'R@M3](Ȑb' x^W7a=\'WG,?:jRpOrL.Kz&Ŗ%9LM%{=bycznj{ 0ȁ $#Y$EVYXp Akz?lmMEk&Z ;cޙe)o1p?~7zv,nx()ze;hUj�P } ;ahl؆ ؇yqaC 4+7X$-FTYa߁ya^Á[9Y �\U,'9 /LK`6_&4n>ڪ}azCo$+F%$g"_+`3)E45ƚ?-`!pܨ莟? fw)s]ڬW?ᓠ>@Tr:DVRG(m"7m!&w/U_6ᄍM1"M#G5b +,~v`EYǎ[c0A鶷N/&TVJ"#H vblVw~sȐe%4^�ϟ2ha,Kb4�F[N"y5bEym9ĉv`Ŗ.7_dհ=ml}tO0wXN'K6-'z>A-ΰ(QϏƝ^?~݇4ȑeꖗ!}FyQw7xz ,oSؤ,bfObЬ/u]"[t#0sGe�o+,+"'$w̳/ &o֜jb0 G|P vȒaZe7u_ז.}mº~E䙪ȬX ߆Y+ a1P{& iơ˰E" l>^۶vo1WXHNqh-$ۯIt?!S {솓H޷@. c! 2CaI;$5~&wuː~/4φľmh˫�xQ i?Tyh[= {ywUUY`m~5n2g92V by4\4G;b?0Z5<V9 f، ,+f�a-+f!!tcί_lf_m!?eˆam;\T*v ՃF^:(V !Q=D4W?/Xe <%Ԏ[-ىLQDY: K:0\Œ l T8,-pnᰢ#3:07kŎal>_3]_˩VPF;a0m)<VL<w05?/֖$9xiZV ]jf;1D5UI U| ~ zؒg/3- K4ߥA8g|}fQq� L1|3WP&I EmJ'Nk|؊oۜ f pBM6;t@H* Þ69x[Jփ_F~fԬW(+=aȶn8ᶆ ;| /fv(bShz 0#0Ay Ϻ#|g×c:揿_daBJ V0x7)qzjO[]t\woT.nUuWL/8\TîH#9v#cc!f&Rr(7WW_3$ͫ }Sbb`l�*$xr1/6ik*fÌu;Y0xL4⇍󫚖t4Ŷ;mXQt؛f%馛-myY82?w%Uaah*ZŎ.<|uu5-7k`Ѷ?n?t_D^XrB8בmʷT @k :|9i`rL3n6Xa V&Bޕ&u5J{#G\YGޏ[4DPzng`ֱywj~-j^'a{#!8A=w>o(|ަ][ 8N866qyu(B:}^<qcL74 ,_SK1FXkl5xq5p~0u0M_L n__{ZZw˸˸˸˸˸˸˸˸˸˸˸˸˸˸˸˸˸˸˸˸˸˸Fނ? sݿy22{_^lt0y]yro4?#O<ꄞn;Tn(lᐷV%ίžx6s=dg3}eõZkdվ=dfWd0�ù16NL,~WH TqREc:/\%RLԉ9Y+p* än.qXe6=G.g >>?c9+(zVʖX$U"$iWu^pFve'QVã5y{NPmϵJs4+,/۾N0MQt=G4;TǧΕ$ M,uS$u冗p,EwmRf>۞ C@ud3~%A+^RD|EYfOӻNq:Ҙ+֙ͷ|f{7p<Nn(}qz/R6K2 fԗ"߰FT}X} |t#&ȸv ÎNc~\]K %)VTQ1:s q{eQ?NfW~{8v62 8NcF ,kNҖo69ƎHCK|IA(;Ɖ,1dI`񬙎c7+M{qm;IS&ee3Y}[$:mq84f3ܛ~đx׼WX 5 g ; cnn%쮶L|[;aݭEM״oY}͸=ԁ|$<iC٦/+On"M[Ho` Ua#E +N]Kxۗ9<fq im >RPQdYͯInc Zv{OpJfQdKmu]痿Fr|B]>uǐaڦ!%'?;Ә܆ѽ`Á+KW_brvupzj} "x<"2u7!ǹiwccL(Z &!4iRK,+9"oNs(%EoMCa?Cb*-EөbKK^q<6A;ZORo1_vDՠ~:ؖ~s4D`tcnC F dz,n6.5qZ< j{!߮9ݶͅ8筎S/U]]7YHM's+G@i݂MW9I^4cAhQGw9aWeUw= G=2 ma`zzzEkv,8~K[-CJ#q2-wv|f mn45RxŭZȬ)n/$uE'otxuUd{=+WYQKq#ˊ]:pa̵ Oz$Pjj Vx@?J@۫c瑫y'jOA_\i^Rw3lEkթe~-鐒䡣_ P%IY?]/E \meQOu躶x;P\C5/9@X(˫Z>=o5j!M Uqjz|1PA[ Y %9p+zz=F-hmXs Mt[]>Nڏx(-}~9_^! !5edSh2D�[~n2 (,4kq.;Ԧ./=J^=.Ea~f\ίnh#OXI Oojh!O.sm?)!ښ_K8ۺl5S![&f U^<>^~,_-3QǮZveItr62=r`,H_dE@dQxQ[Bzb7߯os$ze2t d(!u824K5MCSlXdDmy'`Ȓ,VPNyruExfC|Y"#N$T%d<|qmM8_23Mgjo'5MaK#Hp{~4TEȞȠV#|ɸ牬Aɢ̗膴xIYZ�H:x, oy)?O|-[7ǫ zrfq^<?0ٷ%@p3/7';j /{j8MQmGUBxwQElSWp$4 cD0o!$UUƎNSoZW ,TGE @i!'"U ]>=)^|`TݲqGעn LD 9(\[xoCu۱50n^T#-HÊboW,NWU$qJg/ۋ?"4^&h֑=~yՏ848_'5Kh{J"{\X8lZ&FVئCŽc:dQqO,Cyma;Qlcӵ$O<WEhowVG4'd{``6dYBMӎgj$nKa'.x:vovD9 qPN q4 ;A`R n< ovUkHkm0<DzԚm^0?f̒A4Qx<o A (zv@Z1B|w{Hj?q9T)F.mOyfђ#!C|~J m9hn>B!u 2=t: sR,3獇#`dG h&LgUb�83rq&z"ۄt5~/<)4'ȐLf#zSN~$ΐغrt\[8 *3@di>Lc3W%`Վ(J!l Ru#/Ad`tW߁|PuC�É݅ :#Ycq'\ǂ@BᙐAVV3 +HH0lן}_\[4EAXL;cM8H2C,3; KWy\9fm\uQ"{D* �~[ -jBΑB'?D6i !3u$q a,>^Qt$  Tn Wo8I nh4 yuDp"w$ka!(=pWYcNG~=U%Q`i5-%p p}Oq&!=~"|G2JkЇgБyj)(U pbqprɄ@ͧ `${B5n#!u 9 E&p #k癧  i7i'o"'>M$d�aTH$4|_k<D z!(*9D7y <l,q|c0Mt<QiI bUփ_EU+c!_ӧ}]E{|`uaG.q,Y7aF1J& hS8Vi]`+!f!d.z@FO?o'>�0C 1QS%iWkfq9LĂH1v{8MS&Ajl�/A.S5áO|Ȇ20fI &<̨_ZKɋa T P12 גphweJ|^qfG dH>0KUxjq{Җ %hm(@Gݼ!Dci=gO`uy#I&: W:4#TqZm - SA` mE[&|�]Փlj-~lʮ$(GصuqypnFl0w-r,}Bq5|z!&|Mb<#r"Ф )KWRA@fG̞muq'B:NM K_Y I:IAv[i1#ߟx�f0^G+-cIZҺ4$# ߒooEˍ푧}dƾۂ$`;l3lj$M^( K4Qiu;D-AC;p'U_^њwHF $)Y@Ӈ" J\RJ"G :!jOHۯ#uϱMqGkv|>6%SZ68&=p [x&uI˽nLa9L9>4DS^\}e͊1vu~[a{c j" )^:⹈EL<s[Ph,'&<�t�Rw7WKV3|Ӑ缒4]6voeصU'!{B|"0lv:efI 53ۉ�&»7a .iy 3$&r+1iWʎGpCau@XyR Yf/6nvfA3:w@g:u]Kg/La,l@,m5TV4t//$H |yA\Gׂ3/Z+MY]?%oȑ)GgH**lS=:$H Ͼ!ӍXL6@ ge!j ą 6grBN ˯)%yx1׏x)<o)rZH܃z@<r*f84._oP)Y!q=}DT|[݈դJHEFffxIVu;, W4GҖ6x#:[IiQ=C@^٭zRF9@t<á&^$.6v:qWD-EY԰ ,Hd~R j4`܋iF: mxI4SGXWg79|EBmsj -`گTm/]�&+V#4!AT6Ķ ˆD#~87N$ q[$<\T`(k"~*H 0-W AO%C# SH y1 D7LAhc' ǯCV^1l[s<-1A3-#d+#%[o'VEMqv&߇{6@ART-2my}H F\<|DQSgd+v~1>if=FIl]dA][-ZhpC+bW%"kː�7;rL<7j'턞QfkTuO>rSĂϰ,oIuH1 =&Mh<|˱yz׵Zc~VU h=jŪ'JlbGX^@y}Yk^=UQEQVu=XIY%]$ ⴀXQ̳4Nqlltt wa@AJD$PE6�#!Cs@EA8S�9vX1%mP=6=觧 t 7e&qش.J5ME�O-" ��?,?m |sV1SR]o@FBD&D:N,Sm ֐<>aє�z^}lS@Dhs 8~zVXrHEx*FK!Hkz 횪̒(mi:"X%Drv$/ׄ' Rcj~ÏӰq|1qLijoUiD⩽l"%X$'ZÏS%jԍ]?ԖY%o.?8=`^XuB[`$#5OX7KV6 UO,R@cy1 X[d)hZ~Iz,PbSW-Њxl04`E6቗X"y�aCtsc$-w a}u1s˳$(<pl{s';N;/ /EUa9#m?a }Ps,uXnnu*8|iM>FėBJsD; ʅo򊃑# QƩ<:tS4?ZT!f|l9hiCP748GB)1фLj͚Of~CR` 0%&N- 8e6f{!#v7?Җ'֤c<ˆ'\X3 1ғw G7CWa[exG*޾܎/1 kZ&Da~=&\Q��ʄǥ(?D2 1 r C ^wu[C:~ˑc$'0k#ȚYCLJHގSm0 o(tz M.}[p[܁'=Oǂ/[5l&2M竛RS ̗kn֐ە!^7J:8:\Ra˻v4㑜TL鑜Y0 r@#U n�%$|vҁ#Mv2i`_Wm&ˮ 24Ym^ �uq'6D޴nbH7ޡoV1z%fuGDH47xRi2L 6vf/3.Uv<-`_߱+!DeJe;MӍOch8=Ho֢(ʒ(iA= /o8 W!J1!2pTwh R$GTS$g5}2!w lY}{ITteTSU'>חZ4m'puva&BujYgd#`s;o6&Xv"G]rӫZ0 ;n&0Wx%~Tt^G5 M$Ei{|i+OB g0 ʊ" Z*V^cg$ܱIp_[Pa <C3*#nC,;?z!Rs|#܊uYuh _^%uJ5ez(f7Nw0`¬n8lw<dzIa܃QB~AtER^N)B,ׅ^^5yU.>ݞe4|"}IǗë#7EN<KSenS/dp*dN^[zג=7 xaˋE6ݎ9Iw#mc6o/w2r2!p:�!gPӺFgoj;g$<Ws^ړ.8@m �{My�NۀS"]Ք4OW':UW ]]Oob&Cz܊iD´h~PAsmŬna'! (O4)I$8DKE$0W6_o4w#uΑrr&ks()OBK^R hy^;cx˱t@x.yYOD4L=BVd,0W_kdYqrxdZ~`UUb$,A><%ae^`ZT2: -0,YdnxSQͤ})qbYɈ@yc n:iCNOdw 26^'14̃Q31-n8p0$vMMxj~1;,iKzi?XHʢ}O-8U4+ч 0I<g,�(mFrDPiƾsx7#ӧ$ GVF uJf#A{t< qv;p^ o{&"LT^ZG^T0=x3 ¶g9svܿ/U58]ۦ~B&*/i>s<'Qlai�ܕ;cuB 6 4͛q8�5t6D*OS=PxY /v!Kt!Qפg/Xey me{xzmzm%kf\S#("]ŷ߲4lO67 ȱaH$Ԁ�|z5xB؋RXN5vȏd\,W #)6 T<Y2^$m eimwCc9a1HGo}H y "mc"[/W˿Q'r;sN-Gq1y-aB}} %?|5fJ8Ō G"v}%ɚ&`;xTM7)Aȇ"GSpf�3ȴeLpY +Ō{p-U4C-\Dr3'\Xb.o9 "X ln[ɰKlTyCΏ$nKl QnFEA%UHRMlܿh�fhC`dt{Vq�&ey<|Y{}cVCyc'n#])-1( R*/CJ8c!RU9!}F.0yG$Ѐ=/Di?y+IFo\c4U5`�V1d-qG~6jp rc#O )Vd:$Lu9Auz EW~sa(:* <`@<9S MCisO<t,U+Xj2:֜OzD6OPa:,i()ԸjZƫhcvTaTNJ1#P'B撓gK[AҼY{Kl7- PQG,5 Q2ALuhfv$Iս4ʇ�[tsTz:vuEeZ?ujAxN]3X?^N@�c1[-+ 4*s}Z*!Wug*i^9fdYl@*ฎyHL> 8@Na_T/ҷt/Iy`iM<=z$_ <!i rb0^cVfK<=ɬW;FTy7Uq`a5$ŭ%3?. f완?J7$ptqPϿ?cw(oXtnIʍ֖w&ݡܯL-`1m 3,1eXI{bw76t8Omxp Ɖ:O%sM96̨n4 H k \]6iu"]C֫jEuh "k>޹=^Qr3y�v3|X%ײPN[%m -Kp)&] PG+ u=AbI}$7ށ4ً 9]z;(ڦ0eYV8[ 8.~/s)F ئ?B2\Xf4m?/3O2NaV`<;n9A yҗ@W&/+nL=E(e<N9W�X o嘮r4:4w8//ʴ aZ,VA0j[_f}aqo^1s/rvAj@߬VO[b;-XHM s h|`m ~Omn?-4y>nyp�MӾhRp. vWNCn,:l_S< p:32pJ"浨^bKin�~F\#R# P ||)mh%sjNT̴/MZ0n/K1pm[5$?U3kQm8h٦M׷IhQ"4_16Y7^i,0?!^%8tjo 4Dh~I`|DMUâfk| |>Xc}>Xc}>Xc}>Xc}>Xc}>XbKl'd2WUA!۝NF5-yw_By:0d ѷZL "TIei4AdϾCq$rpV`i;L~97#Nd,/=tLUeUMxz&-g %ieײfe'467Q7m\Kmזefp<kO )4:<q}AӁ]'m m;lvy&C!Cmzʒ$MSO8垗dEd#jKWu Mr=h2Jf$UuH,}vhz8=j2[m8b'2ٷE0Nmz]b [Y`ElhHheZ׫/.(- NB8Hn'Xnk"˯y-W)7aAmp_f[_n.=lU׏8I dc0$?Boa&YqVܪB]Yb4]_\nݞ4 + 76RXk_K`ܡt-[A5^˦_"KXSŁm(؋]^~);qƊ1-r_"J[ xylcƁEo8sLM]d2؛˵qC[6n(#2~ 5u8bcs%H-Fz_Ji`iG@[oכvxsba2{ZP6kO ꬤ*<sphMd[Vb ɌV]zO7 .\Ix}4F%^Ėn47Ű4ZN܌}jʋbMjv^{|GAdXs/qlYv?GfF!o̖V[c)-YR6>6h8Z=}d?ND~ e(? eq枮xjSܭFT~F/Q[z{1ro5$ N"تԷ鷇9iw0 aT�Akq*rs<|vRjH]JEv8uГW_GdE<K U4v;tW†al A˻ͧ7.vKō |#m!@:v-bsYqW�8#*9Tn?__}e3j#E{I g04URpcbȶ=m:\3t'VEhɂcnF&-Bo:v\�9V8<=E@4MkW,iN}UbYQSfJ vlG n mjWzr/8̀!O]gU[Vc8i*ˍSn1?nA>U$Z\*usцuN=^ެ8y ^nӽ|J ꞑ5|oty V}"[]|E Y+9gEBIYnwyu9RJS$a:> Y`/S\s>$: xm^Zt'@&'Nµ' k2):Ѹ^/nx\KvS鞎mQөU6!3*Y)`w4QV5͎:+x(XD5Qf͂ZW}^W_n)^xjW|z*N}☀8*Х>RUhͱtMIa3w Qv:EU^G$uzye.*,̞72GNfbؗI V>Mx|Ž"v'NuNn Mnz5\h\abxe (g2L8N< m_&f\,q+q l6ٹ"Gk,?'dC/?~\}o@Zdw8?T˼lY{ ']8{Nse*"6t]D$ɦA7wnrR�m^-_2\\MMErݚ53ⱱID`[3 -V&Z[j]=Q# 0<&Bʣ $2ͫ Qݴ}'Vt.240Hn JXgi) $2sx pH, }7W`j-I4ӡ !x^Tt#aY9~*"R K?iz^XњI2 G.i\zFZPۅVM�IQPmM S% HED&F:�[e_W9М0YaB>ehkˉXO@PJ 9ƛݞ³|xʲ?G{@^=(^\55  :$B!"5{a,2XՎZ74]&ˇ.s |xR4|o4ExN+d P3]5{q '3NP!=5lVG'#T6/t1 oKn>Ӫ *OkUC< c0;DUQ S ~vF ERj"T"BGӎN]&w𙆤.Ŋ^;i^Rur""C$d+fNHkFiYFvz &m6( ~D*2zA-!}dBx%f0o3 t<F|u}O8GQ^98o{ЅEw <9ca˚"Ma0*>^QoRj "(zBN09*JŒHچVv 3FHޙ}«eyYk銄vl-pȿ/( b!];ۉ|$QŲ q,}{x�!a{8u^X&ew=R bX]9*=#!_Hs^m"ow,1v9Od#y7ұ/#Ϻ0u{{�RV5] ~Je K%<]-{Kp5m}aX^P</jŊe'͡ U >rг0utS&�f ݰZ<"D7BbC 2m`ۻ,' Bxai8q<'BLt}ˇ҇DBT 5@h ?R8iPu@kF>5/m$̿fkk6-Mx'Ȍ΃,Ϳ_#[3Uk5$5-UIx) 󛫛nGo(rۭRnܷP&)RWc\81Aݑx8hnK݉g}} &fI#pI-R5iq*?,)VU*"Y~O`6;{h cx#I/> ֶ#}SW϶TV0}ja 3Ka5 d v�|,7"<lN=@8BYL}CJf~U{(5˪;^ �d#Gcum(2yzHGu;Ȼټ#Wx@l:%#MiitpH]T2*I:6zm[hi;J4�SBDw@GYGǘ#osW7HGxީbˢݴ?}}$0bR H SDB/k{N8 i:2@fL0KCxg&f+v 40b 63tƛpXh= /-7k`GPZ؁$,={Zl5&|8uNOMM<@D-_xؗ. SA*ZajgXL"դs'ZW,vn)A+Jo"eSz'Z4t0Sswm' 1#ESP|{{X9.V> PCޮZQŞ:^ u P%q;Y-3aٖEM(3<3:Rý._?QJUqX~@UDI9C]yX)76n58W<9TW NLN4a'ťvF|EfAKjd$p\NDR_ke^Ξ4�%$]FW-�JX0ja/ҋ A@p3Ve6%6YnEIUMpH挑pO"><,<je4nכNRɏAǮ d~T$ĝ.E̎ڹkrenp6KrԺm$fN(0ߏ,J[ob7~)^1`.D�Ko7:NS0tTQW2� :2}]#05 DcG54S#C`9V!9R3^dMߦ@{΃Xhʛ;Zӱ+0,/ Ѿ]9n]h"r3g [01�`,Ck|U!r4U-FҭxuHlMT0|@FSX_Sa q3M➾XAE ].L$Ͳ1Mi 4> 2)mBoDeST�#Jj�Nwg%C/_vh8qqv 0ty ^R q4ؤ`!/;`Ő쿾 I˫[0 0:(@Aq_ma?oЛ`1:=#? ]-˝ba5@@jH@q*t Vp=,ɚn+Ow=$fGO#M TF8!zdt=8O͜Wl&,o&yݑ2:Ѹ npm7Dex"4dnI #$6 qeY1z yᥙ.cvb{xhǩG=Yh+θEA ςr9d+hP`Mhtصs\[V%JMNij)�],Uɺ.1k 8ѠH'z7"5{|0aIwd㍞}T~g5>|v/+~ōȫŖr4߉*dN-7F5hQgH^vQ%%AN} JXtPaOQP,gv?>/&-sM[5]qv<]icPuO@ӾCWB�:fYӠfi ( -++j`KMCfknA.<3FT~C& ~n4]NȮEM2@,홤"XW-&Q`tQ™+ɺn*Oa\hl0m؆D`xQZlv w3 5 ̸ GʇlAB BozB8aA"[7v\0 @HEOQR{޽$ CS16W 3´~; L ۣq?|GWu7F:)!9'(NޒO GԌ40ϳ,Mz[34{1C|PIW蓢�}IfP`p!(B4dC=nN}0FsD=QVF +�q)!pLYbV;6,`i"<=GG2HHb9GM^D""U淌 !Ίhw-h\E^'a卫cgqMӮyӜI^) XF첆 9Na: 7ՐdSA~e5Þ3|:ŒEY64)�0rIhL:ps=}n>0vbsFEIَqՍ@.qbgI됇@bNg+nЌxi-w1. g c3UذȬ,Y=V�v  \=A0+j$L-5&$ċnS:"_,Rú))c1?>mHr+m9+Fy]iֲYӎGEC$BϱG8vDq, V_˫ߴ&*c͸-+AyaLϋ*aX=p1q;2'p,1.'"k?` 玏YںMi|#Z˛DCJtGΐ?Xԉİ7z#of<#=b.`:n\>vaūn1pf{AF!恬$ j<])Vϐz\cG, 7iY4t?FqM,4ӹ Nzؠ2vtX|~O?}}iFz܂J&2M٪俐 Δ1 TH=d>öHA"iGϷ/ي!̆9|Kx3j\ѐXA9}J!V;c<@>9NƲ�f� v5Ki:*f�a5EnFx3ҤK:\cyTXtuVe6Q7Ϥ|~$aBZĬfKGV(с t+r 5<woGnCʒlx/qZi\[WՒ$<^M X�[uڳ4r$hj (V< i^R~<a>ǒcHRKzFIW}9,(7'z1DWU;FMNaK�iCK"x~Do}<:}W*lJˆ \ۄ}${:diQhf5+cFή6l&�V:r 4vbZ.֠]b}) {F$6ɀupaU?֜xfI<'|FeUW4YȿER_lJɆ`{Rz2t4ɊM[νTxp՗%�q,$}-'4A|$-} Ԓu<z<ɇ@To עVelm3/Җw@9zzazԏ8{@ycY,@M6UnuL< !,g5į/ktz#/ 1nXc-uDUU0r?¥J_~%@RԭLcuXnO yYOqthDrp>LDYE-<e)`l*[Y*G</d J^e<-֛aJ% 8+ƛ*bg(,liAM ;s\%S<i%BNuN*UTlXŰHȋus;SVR\"tK"KnŠi0=85#͋$W׿@& Y9P5 {0xζDz ^c[wŒI\Tu˺7e7 ~.dN(p2 txk4pkBx~[n0Ɋ@]ybEVFxqI*֎ ܁4QXx!IEUD$%kfPSa ;%3cCrf2R[?Ygr4xtȾ"W< ߽#<$ϯxtp# pK ުAܷ5]3"]x7+^w-%8=1`8p<1gxu?g�n+ϾM]ǖeEeY_+M0?ZP4v##)vj:n,V);aߧE^ȟ;Wl?IS؅mxq핬&,rb,Mjv=+ːԤv�ؗIn%j�Sn@n|$:}�}�v:BFxяm3% 7YPva߇{v#i&vCgE'h'd q&Bptl2ל [LkzO; :4v[Afxĺ iO((ŲȺ́܃<xVR� âş;o_-=F.6)x7A5RW(a ˴(wlOWcjIKXrկsˆZ`!h 0^ ~ 1K7i</ҏΣvT;$0kO!ҫ=%IQT[z)�@e:x'IQ;N̞8F並4ivڝv-<9YKjbLKմp[yW`VOܿ~%-WLYE\p1"d' YG.źp7`-SH\CMV$ԘWx>@@גYN4h:Xr\ *}60Gxo4eLۆ,Vegy#n:`3*vle2{tKױzCmY؜++ 5䶊%5I[ZX 6 Uff7Ŝ;+[]m͎Cۂ�^UMs ;K0q^îݤ<tL{@2}IN1u4a+& o]e>EfCy cG6f' !y]? fqZs@}eFCbaGZbv!-IW/j ⁳ӭ4N$nTGZT.HP&`oJظcLyg?'iX@/ ^+]9&ƶmUYMyX{\:>]laYY5vnWec85'CC)#JxpzL <a7dAE`N(A1Rx%Mn|9[v%V+Z܂3Fyڗg<TEb8=pw5g!w ; /c1w;Yzvɀx:~u=tɀdIt(fTmBo>yX6-DfqB/8 p�!񻗫&8׷}R0�ց*C~ėF ۳Ln$mb8Qq\ȬDC9[gv9Qϴ!W+kņPUӁ׽{y|YUb׫n,90%Oo/3ca3*Co)ݫq̬W*n KaU)!Mg'N4�bbw󛫅daa(Da%؟M5[}ރ# 4q҉8Ӹ}y3y<+|`q Ho=~}=M}pdqM* <S<?mx1?c@K$ˎa 8x$8pDW`Z|v$)]&n/ Lʉ�@xX4Xa9�朕T Cw'@V?#iKs"/w}r!O&7!G+6|2obЕluðrPLo|,@ki__vd� }<nq</'}#<q%vZƼ?ъW.Nn2GĦv}hK B\FE ZkfW˗_D+lPcdÚ 8`^gi-Rj?_( uw5<Ѱ'k3YG=dGoӱvt}suڡǖ$S'�ƍwޏT!"׍cP7a@ ЬcxG8zj[] 6}n ,7M /Kx4T`ag3ɀAi?t^?F҈|!]Dztbʼn}ao=' ~]l7,8gWWu 6q֖) ÏX4k5<ǧS3G/r\"E.r\"E.r\"E.r\"E.r\"E.r\"E.d)pPEdU755"a例 ~LD(N'v_IN'Dqǁ�&/32#/Tz`k7c~L IvDzQ'Q.^S}H<^dEyJ/ϷL .x]5A0ױ?a 6@7J2]xax9RYSq{51=O5 `!4wpV [y h_0Q�}u?+^e>aQ v n1,XAҗ?]g'_9^n u]m=a ; VkŲL *?xssu{|5=y}YL qiƻ8T'Fe*Ԝ'C|S'/1t7D%#J$*E ;om۟>A2&4%׶eں?}32"r;yd$߮˝/w Mm(6++ڮ. hi!jBгzDM_^tc75ffɾMwvhu,CeƉojjq:O}J?=ʎ"!7/%'@_I^H-fvvR̤(/a>N)Y^ /nE]=g/"(.R4}(/D'Z4v23ef殺><ЊmIOfqHuv=k^ښmDpmoଠ׾Q,WwjZYz~`mf@DR|/Br49n5X +Őy5Pj.XQdqsbyd]jeWFPbpQx\h5ui*l(]I267֕3 PUs35O-@rNtuST?A8U36KpضR CNX5ژY"?.vv%>s:voo3_]0� �Q/N H$4u%90U'м- Vq+de'i#^O`J@?_iYtVfz(#˜ h"roF-Rn3- ó26h ܾd}EQ9 *և,H,}> 2N60$h&4r-50؆W) /𛥠C,8CȒߜ^5pT;yQYEaw/@8Ӭy`U:+b^XH| NݴWp<X*+HV؝Jvsl>fLלn&T$C7!Z9ϴ 6G%$í9IY- S2>yɕ)d7.4GHsGߗa'G=/zhAs,mGr+HTIkf -@Ww-S5bulַ;]xaYHEzz|{W$:-K&7=+OSt'KVz%fw�}j‗Q$2Sd /K^%e.eHSd@{Ufyc8Jr穼\עf5r4U (G)%ld8`Y5/ V�$x$cG<�,58u>)vX]xCnZl3s]KsJ2T͂AZV-�`m=A֌d/e͎] lMaϳ|1[P,>6˹&uaif=!j:<q@Ǒk..jjF<`#TUw]ZKgM?"CSb@;%d4욪ֽ/#> ބVy'׿C# ~vl$ Ӽ(�`eJoE\�y= KxUW$ ibDV>ɿ[U$[`=pY#"y(#GNs?<Cf$5OQZ0m?}Sd%[7lהd vd Ц6!ڒ 3~d[Π׿�yoEXQo rFqIUm_E qŞ"(^5ve@heUV)+ȆmPd̸(c;^Н~δ$ VH#K|ʞᨆjBZJ-� ?#\rMYM{8=#=xꔇ,?WL3{Ɔ"l(Qea׽T0{,n4ƩNVz xe4˲]֭t<`F28-*r+"f}bT( pN9rMOc|W3-@" ,'kvՁ. NS, sa{,+OrQ *�0 iT۶%Eȃ.-\ |`qcE|2rPc}r)�\hysiD0P v_j[D(Pv5ObְX'v:UeGbz }M-\@h>JO(` ZQ/w3Qxf  a=b|&j]mj‡D.N_њq۰(z,C@}u6ml].3l�kԿN*P`zR/>9X.+Ջ(E=b(xw~}3lhI{d;ԝ&ob'=g; 6NJ}_j/pE pz<&^u(rF *[Q4;z*q Ni37lKaImA}W@ ]OIDyp*/;@ͨQJt3 ij&Mr3%$>Iy$4! PJ?r@Q ф`8FHp( <5{\ *I2$t!ue?(Hdiҥ)p>B}ŖaXQ!ɓr2$)$|QyQfwjE@ ɵ4Yn('Ec܁e5 uYȖngz Puk_&o˛dmK߀Qւ]("P!?wl*8)J)/ԧ X 7βАǧfchĤM%i{eQ=z٠, r89p(bR$AXxCnx|{9x y=7! !o}G@FTU %M/)ݑ ir,P ,qb儢Ⱃn0ҩ�~4 ð7H~reyt_Dh{f*auM)�V 5oˇg ۦ $� ~0�MTdI=NCu8+"ʈaܶLOT? ޡm433W u 9(1>IAgؖizqUfy^XPEMc<BS+@lQ׹'*a NT�=I$U:I<9ntUv!ՇtywWֳ$4jtB>Zp@LKPy^s_~M۹WtB N]a[>m"2uG~;-, Z44LIr rk ➄ =S~ 4'sy&`7]> OMiK~='Dց&&frҢH)$@Vm[@-`EE^ɗj-9 |RbEY߮Şzo" VZv<)cל8] S $7L V3 ZMڦo57m$T~<&. |Ք`ntz��ړ6aPD�%̡2{泮QWݱ,uUlO7~Z5-RؖDi-Ɋgi$1/6cԜ7t^.kClZ `^vh ln[O+*E-8@>iI}JD]̰=ID2fgjub4+n u6D"5_&*![cن`L3k &UEwd>?ʢ$[@dJ6*(dXgf7w;r' QQ}zR󚸾Y]Qvr!8ByzLo;3u)H7ta}9chV4 BHӦOdɇLae'ZRPq3Io9Y˚|3c~}% fi;^N+p:`f�N[L>`ؓp|/6x=ۡ4&h]oEEV!W dp= !$^o;xJ3U~b$I*m^ttzPczą(gbN :te[V<do|];QՁ[‹dAR<5|Ɋa ia\E8Hb-C'9$J~`Y\.vMq7uZ}@n##ka֑㗤`ƧSZ, y5ݍ-_�޾y<6m+҆ |Τ d|(fՖ"1˝X^R_e`~"f*ӋْU2ur!X^ P,`[zɾhz< Ş3Xd+JKЄu�Kz NCpZcIc;Ji"Etصt+”9 `E �JJ�!",-)G Ƃ{-qݢ}Uݴ(;@-Vn|SfdԉǓ׋tFLMG 4Yi$=|(nAh2dki?BLw;j>RP7 �(aGb&ٷe 90廦r,v[f/X2Iϝ`,:VXehNMa"TUķw hAJ*'q$bf?hzuXS Ynn<U*,I( I=T:vD zZxAlA:~QR4i73Gz d$5T >z3䙶AVQC,ͷ1%z47\LEK@LUװWrb-6pFN_E7I2ka4( yϴyAE4'A  5} DQ sU�S] R űC('|?uU<\sKÏ83fU]}S+ePAdط{ϋ $[?Irp7uŸ�onYGk+⺖VՍ@unY6E>" vS-G7MK5{j"9H@@~V 1h}VοCp#CI2w(Ǯ2Ċ%ag7R^JQq#&1=N Y A0&2Vs=Um3I(QX3Ͱ]:񒍅@c�(,y~S<L}$0dMǩ-`Q {5ԆS蝠j o%�3Q^`M/P6'Ebd#zOǦ=n@%.֪o|3l":42g&r;N୯|RE +a##)# dH}@~J cDy5#ۡӄyN Q q:R@(>%K[oZirOXDO7N޼v�T$ A%�|䩇on2eBF-Q >d-i�]S{5o[%@dզ)C"݂Eg94!2NN4ww)YHk@HI^ 2ZoKhL[ oY^`>~~-::�BKx)oI!>&>99 uG)Uǐ<6NP"gB%Ht tb@p]N_P�w`F!bo)dT4EQVe$3.?Ϟ>9AM1i7dY>bݓk \k< õ³LDk2ϋ3p~͊Z>A05Fq:ܝ_cz l�C@HY{r>'>ϓ0WKc?^E9QRzSdq(#KvB3L NYYq8NsXg\,OSDAԼؕzƫ8%)v$Lc us�|2[^ZaiAcӀdifpzRkl&05/)VLfi ô` "vMI ,u#L[7�n#N=ORHa1FLyNTVTW)G̐Dy,x :@nh�xHը>OC.->$NibnyY Y`dIY=se UW@=Ea pc$'C$ S#$p H�a ‚D>_KإWyjfe lQS7J U;i{!?χӹUerԚx}\lu{:= {CϊAރf׏w7 zg Ҹ&}/laeY~8gn;قʹ¦s !Cۻb:Icǹ�>\�@K,!'wWX]\ᨸq{&il"ϯS$f058os¨�Z*N2 Ӱ28F1V6}@iAeVzxbziInϱt]=4 ul4i:|KXϗ'|5Ud3_Ha!+86h)Ί< Вȳ o3Id q+Oc1 ׋{=^]^}~͞ Jed8Na}$/[h8Af,N:zNhi W G[=:"͌4]UB@&BNEqyqn0YNp9@zC%<iqޮ?/9YZl} H)M4 @,eq{i^oIzP]w㑔l 9lP?\lER L ׏$HּP4aΒ8LYn~zX˪{=0ǩ8CDh`/ e9B>L{][NJ"u7fHhY"Amd*PH2GSj�9/IO` C%MS{P¹X H"iݰ= B3|ޘ{nͰf&x6G׍/騞* 8yc 1e0� Mmd ,c^Eng (ÔNk N% ̎֋Ϭx92'+lCk"~8Ywk6/a),`i ]"ۭ~h%v D.)؅<ľľ(i"I53+2`+O*2j QzC鷒gIJdžA iuyy{E2}ALN0}=cxfc:`%RĮxDx@w'P%,]XX/<7I kttӴ :lFn!_۱mUVdw({WS~ Ga:#=p?L^" ">8oK4zX*dg9iP@f,x�' xmyGC0[ZTqGi,.mdӲ0Nb߄޾GنD_$e`hl>_odY1F‹;`,P O8:ǣ-@i~$P-> ҲAj(B!-I,U+J!pVx, }uM-y+tu_}`yD!գb8קסc[�7uw:i&AM7!xY@.xc<_:wf5RVe=g-p8Q(x;nGl+% T@IԄ8]]=l(S<|y SZUY≸nY-?w49S;nu` Aq N-cW�4T~~y~~Zo)^K1O!?܊#H}IEHEX΃%WM/aS6e|�U_}-.>'!?4 <dvl_-8`mP;7_2<r]󫇍bW5'}[_z*F2⭭֗?%ݴ:Žb-oC8GQ9)?/$ԃ>kh|vN?PxP/+5@e #Am %ZueKG2-ސi0OE:[@K֋BaE٧Q?g|!mtR ݀r.Nmh0 yuT4ٱ]Pk^3�N*#E<acW}K"!G kki5+6^moX.K\6xx!2* \Sg2$B?�'бc_5.>d~7a I޿변CB,i 8ҝH#W׹v~+weԋ5m>s p0.#۟.d<ov x~9Ɉ XKȋ*|+yͲm[H/ GU+{ҙhYit/ \sKŪBdfnѴ/-lB?^AlMxNc[Aݧ }SGo`#>:f!H DxHc?ֹ7}1 xG|zls!. ACf-HDXL|_SM@y9[ }gPwtyQ`S\<pE>&vExe?}T|{2 ZU!NxVu<�0`خmu&AM ;fޖ; kP5,VRT #u\ͯ3m%dzco֒㙕"kZ_L琧N�#~f+Vҷ)uEp2S32�E_:~?M۶yP7-ۿ[c8(eyv}rKVz1^lvIk+ zx!CxܭxՈo|Q#jj|6/o&Ci>̀T/n7cط]ɆMA "}o_P8p*7CWeoY.m]wDrwl[^yDC϶ɂJPcP(#Bn4V<zj�ܵ۾-[:T<= =HNj[״)}_ge _l,g;vlg;vlg;vlg;vlg;vlg;vlgb;^ѕh-)ҿNTqlq\۔ly$C[6fQߣV{4 zO[@ EPc){?IՅi?]U-|5,8|-t'Y 6E3We9<O&GplY0  %M ͛55K'kaYA`wT)w}O]F{TCߠJ+879a(ݦ2_ا+ $NxPύ(-ɠDÍb`ւaZ/~ɟ(j "v17]bbd)^ YBXf/?, q[ZT;ADy$XEiև<r#|ePAi*RR#ҺJ]\㑦!뇛ٚmϑfW<ˎWt%'nP:Q5|p6O /*ts;v3 e_xfؾ(B'Фd?-fqخooJ OKJ!>}_PϷVrҮK feX~܊vYQ݄RӡO-v#*5"tUYr&(nY4ُ+f}'MV_gF7LgT7bXA1ԡ.n~g ֶ*K%-^4|cA=?WŃAt(}PӱV4no˳;3*ه˝EAưtE1zǗc[$C=*~(=//tijeH:lg-/*Nrǩ@k|LM,?oR痗Е/70I_+A3jur3ϒ7 +&U3m6x7d'iģD<P)eW"^7d 8 c@9D[2f&*'QLY~`5=4~Ym۲,}m$'j47i;><2/ijDFs3YEH %vX'4!u}@M]q.8.Uv^64!>A찞 Se0dHWql}5 )Qr(C oytzmgY<$$rCi $4q[">-TҊkN 7LgNF2򖂟xa, +MRQh6M_W%%CaLrǰaoSkA7L^OVeCG&iĔ֗lrvgoEQ$'}s9aonS+{PAQ==(�‘TM\ݯD'2~7ʚR4Kz|Cgn/C$QL"-yKwj؎m&AaͶ8fxj˜:CYE7mfdׯc>ѷs -/]S{'iyQ[eǶ͒5]8+#c+֡Ԃ</: ~y&b>2dӃ$, Ҫ)x߱RcGUTȑԧ&A<#k2+) #GO"@}==R+N; e:Uơ)[=֐E#W'pfDZSr2-?mぐIdv*`<y{eYCfUde)a U!;ϢfqzQ6u6-(LrȻ ,}!r\MV1¼0H_/HM; yxLduh;*4z\"n=aK<+›z )SWTe;U a@$c@^-8<S6u-+Ĭ9mHcKN5w"DĢkiB?06= p|Ƞ"9 eoqD\S-}<F9FҾtF0=KT!GƟ9615M75jd]q0Ȋr([<R瘶c*T r"xu:>G aL#k[R@S'NpY +H 9 d8DYY }*O6B]"7s`,dPw ?)*><q()VPǯ]^&hMl+^SxHhŌ�tG\{nl#]R 1/M "f{IoEw();dJ,"ᐊ3fHW. U0mMs˾;$NwL]s@�yaZ%N˼dP /^uyg8I_-Jy�{X]זiYSړmٖO"x٦ۑyڨ5n}Fp|T4=BR - crKG&x`m)'q}l�"nXUT;9P]nUK[ݚ摥9_ ra ٔ10]!5UG"o@V&o2f'=jx̷e8ü';P|v wwu :e{Y({XBDX&N.sA@mzx:2puU~sg%CWE=]說~r NL(U {~A7k l XW H<qȬ"=�!2Ū, d8-8*{B{g}0C"ׇ&8GxH>HDwmEġ* GmMkeDՄ&gHUn&w?-)wa)>nD &� LQ-S4H0r"}X,Coqwj�uMqÀҨexV'>o!F*Omi$QX Rmj;N>o�!l۴mHbhBX֫ PR^ a5 6~<v>DbV5IO3`p$BA:i; F*U@ek 4q�܂ @<Nߓv0"'|P'Ajt5P !ĺ 1NhO_y xN zy6bԔ,.RqO0A'rГ(=$V(,b y- si"}ꦐ`8ޱ4epww)")dČz H4V5'aw w pv8o *^5"o[Ncس�X0ю '߉ܘP"HaDZM(Ub凥(,̖ 6#SRit&5?@T ~yՍ{SVY^6Fb<h ―`ۺ)-fn>eiX F]BǼ߯Bl�p !u ? ްyÆI4tNT0D)M14MѫOF9$X4³/z@M=!GqqէGe" - Xbu"wڊR{q p$0=2Ou `Qj6iدO_$ ɱM ObYt zA90<F]W#a CCWK^w0QcMU B(;/m :$Yy .nx~@Xm #V֟<mY^{pM)KK<GBw% 1_)=0�xd̨8X0uӑ, suE/-d>. ܘ8=A#>=̖u7 $R_]6Ha0q!%Wwyਢ0a(̐I"{u0`f8Vqz4>NTd^�:oU q)vPN.% %. =l&0�UR[؛ #ˉ}{v}'ow5vϞתe{XҗqZ& J#W1d][Q(9<bHӆKrT ,iVXʫB ]jkv) �w%bGE ?7={!ka<U ,'oSzr1_Y`O/4mdr=fKcE4�y�tMj%_8�?֎43[f7Vt=[K΍uZ櫕 tHfoVE`Бln|�"rme {0]סְztkHxk"n mXq ޼߲`"@.ie]qƥFe|YAqKJC7K_YLG4$};Yn a~U4"H`z/P[l�|t �Cֽ~BvҤaMaKWBN%-+Vo^;Ψ/|@/c'<ijta~wp]$QLBnG2Z# 6ȟS6;LJCH-j`iC.md#x!d5`f 9CC}Ӽ (f즟NL ƕXV\#I9#AZbӣ-ߑx#}<j`V Z\qҶ mU+ ~#Ljطc*'A a؈n[XWOa!fv1%***GY= >CV<[ŒS H{ B0A% Ax/ԹkMd%,{o&9Qd=!9y+c n6j5_ !pUDr@nm:7"˒_n)Npu2zdnL{*�B$,0tv@kqbeM�X:`q.jx[X*,:~ps7ov][Yۓk4IOlxsn M<4z=n5øE81۶vQj IPӮ03:4c4 }X CQ[Lv`Iia֡qExF Dxq K/@eQ˾ۉ;TLj ��K*Kќ(ːW U%F ^߭%#j<,�nd}tuAk]-K�!猟Wa<ejK 8]-<dNA<[5 ?�ӸxOfTuK <k�}YcA<Oe4x<880zZ*^RU쿚M!glj|!3$VjL�eU{Ѵ :y]aO<]N-E3?_խAES`8BOYVG=.dA+̫X9jEgJݓҀ'X޲Cדw5'FӼ Ȫ +؊]ߐ6gOAg`Ҋ 5Kh+r'pIm%bi{\woOEˉ)4/ ϐUvE+A? qDK|g ËzVSjӹ9!0uq%k]hMZl)ȃ8<Ђ DSG\X�Uv=_ѬSIu$~7YS{dqtevAIo/ ?UQ㬂\vOQdLlA?ޭYNO{zSUiw:TV:\G曷8 $c2O+Z2(+vtnAE")B.k.pJƤk0U-cO)|CC[D MeNo( "I06z%}5'ĺJA嚪:~k7XjUu</iV8ͱĦ U`١-4<E畠^Oc(!8'dڛeD[IW5?NCs{Opꀶ?uǐ:) L4Q<iFH鴂XsT]UN-Ϗ˦#wI3#Y.⪉#8c"Ym7 y@X |F;@ gX97ud3(Z৒T 9_W|v7_||i=Or8U%J%i6l^Ougwjh#y8 drXɊD-+IV9t# TG' [/ˁ-܃dH=]*qZR* ),8$iN<_P8v޵# r$vZx�"OUAuߺ IQArǞ`tIO(|  ֝'�~{<ȊE.(>!J#3O%v&w=u޺FA p$"6T ҦB/n|xCx0ԙwUa}{K}`1v0kӞ)Ըr� c9AwLP"<sB~=L 8# GkӢ뻙`QQx?J<1GRY!yxjdC][LS M{<GH^*rC,u4N7y' o;Nj tNR*Oo95Yج9Iu>H #ݿhi֛q5s̵ϤID" APKZEa=| l�N@zNyz~s7Hf'}Ga5v!;~ ;Ҏ@B r߹fxtCќ0o R9LJ5+�f*"tNP7VI$d[,r&29I]J˟?^-V׷NL.7}$~yj-^ѤoEQZ7maic ّ4 ܊@iV-J󠷉F${՟Ϩ8"n~ +.3~{QYcb[~YL+j'${}Ŗa- "ϱ`dS'i∽*_#ojDo$pթkA<Lm @CnQ <)춰u B Zee?v$s`wd+mn@ndj"mۧ嚢^%p*^"?flbI\˩l*^wڪSNaj[*<4sa>4{U+*DO_|rysH0vE?1 'cTc(MI^}|xmyyJlߢ[oVs6fqdr0#;K &mz�uH۫z0۲bfaj?I%ۑ&㾫,+*pKehy?y I%A5lϱ1k"y6N.dis~pa;%TC cَh/.qaKA$c6 n#cHݢ +l ]2IX8hѭ"g@>YJ}K<< 6U}#bOy%ӊ2M*l]TqZtTm,pr!H v'iQB̟a_­V /]oa 黝 ۪!6)W34=~%åeW˵uqW@] HvZ5(=ʖE SiYr nǓ^"p�/� {ib*D'A n,*TXj_>?Pݍx8UCWXF4\k:lЪyJ:uZ4uh,0ϟ(52tz9_iNMz!?ITc׳G`W xPd$uMMU! ҷ_nW dWa@C.do_sx%CM'*XY:cV9>7@kIbnf�HD|psxQx*rJU�J+Mm#ȺWὕC�^MJ滱00qp2ްҕg`0-hYArܲorX ȸZlMN1: kL^ڝ&LXjr%nyQ . ~YQM3z I7m7L" ]db%(6f5p~panj9ɌBL$pɕ; 7 0MҬ,@UL>իaM*_<%~A|~uOl8V l$t<>#`Dӊ[6b'ݸ#(IJCnfsxQKӶ,=$ * =[1X]@'I3Cl#DIC_^$:Rm KofQ!9s vΗ+ ZhcЄ&n nD*)C\jpso$ B<[y.L+H,;~o"P|5,搘sTٗi/kR|/,ky*(`Ko7kIt-i=Tn6rt[t2ſ}z\mПE!=L6H"w?`T-fDyh?|ba5!NLGQg^Вj1ׅ9zgBy\X*Ŏ2rp"mv<,`ye Zp5>z8 4.]Ykͱm[65Xac"rG)H<%לJlqjr+aGU D0IcLQŚל�Zm bt صK Q̥ڝ/:!:>Sfe!տdYچk-9ys B`؃=x9Yb}M}JzZsˋ%+dU;f¶-]en.�d�ߵC^|n qN|hX 85yr+a>EBD2 6(kHAskaaV{_V0AzpQZx.>s2d$h_.gI<VLez|XP,2[2v4U觟~P43t E- , ^,74C<Ƴ 7<M7Lo?5;iG'.%eI}.8!KEܷ4ػoRt<=MJ;찃\du^԰&١Ϸ<.enXֶ Jɴ쬨= .__c[&in/hZ >^n"/$]|N*\MҼ6/_CC[_e|XWۉ]imgeUfsyAzn> U2ur;EUk(x]3Hp::}gU38%;t^y}ֆ/b2)nye&..qhQF *8l O9 b&tt筢FÐ>-C[BPHt4wb6 5�@HA`9t f5!�?$E6&Tlc\ĥ,rZa 󯲅0|ox ]iFU{_p/F@6ͷ+Y3\'xA)|u{Vv37Fu� 4-W&N{g9Yr,g9Yr,g9Yr,g9Yr,g9Yr,g9Yr,gUX^.gYgwQ7jdp cHIq,+ֲIuֿhQuUM?ݮ(e%/pǖ$ɊF]avE3^ ʻe.W"-Eє_L^_\(QM7u UOTA$CYՖ<azi9tz͗K$(̑oPzHa# e Zǁi>|Y8., {۞ )0N$pٟ㚞<BtEh-?*<qR6}A/?/0/"\CZ֒ ^#le#%~8업> XiۓKV4m?.qH[*ۦ͌t}iî M~v!o)ۍh3ײl~/fׂDgongA]23_r=}c}I}z"u a#Y7e컖r<#U3piwDfս ե藻ƓLC=nQ'RiS"c۞ko?-KP%̶`<d!l3i]qɖ3Fm,oȂwwY6(! qNdf%t5au`AXԵt )\ Г%?qhU[1w#iQp5k'XFeM?:I,c'U 6/.4@=iߩ ll<zl5ӎ']K}yEj9la%C_(=C 㡇R7'Y3Ԉ]>aGc3K=y2, Ō HC#N.K:e'HG!f{GѴOV[羣Qw-rU C<fԏC_Y=Hgl:t &(Q}@6`:Iw8Yi :L3F 7 ٰxJzU#v#V6zX-`1V7)uz}na47m^xRrp}Yl8*T tjCMyL,f)p<!wicĭH[ݲ (9HsiɊEĴl]+OCL 9<\(Pyݧ%G[֧l\2wkN64I K&q/$?bS\^vh\++0on5bLeDB<^nv 츥} "ʺ*sqDqv?Ʃ0wyzOai{f*d!wnZ[*nNeh dQ5<PvkAP[939Ծ&ϏT>Mt`i@޺׷2AEsF=PxyQ# qo;VY~`*&~TQ\bmŝEUU~VE3b[tcTl!DVʛf uO e�@ahھG g1ot@TuT$WԘ=++n:T6MZm0ͿMyzApQN Sq[]*>0^ ]]UƎUYh0oza٠t8Ҟ0ϧT"鼏}[eYeUE%answhhlc9Y$ډj4eYѐ7 e`J+ ' C ̀z7>�mRA`ެ+J^ݳWwܬ4bJ"DhD;S֑k;~*wձ_Zᴾ<N'@kqowkpbMbKkjQ=D#뵮ibzyw Oq CJ<l6ۭh�XoB�%(A^�3YFtP(ղβ4Dtu"'}L;>ck*4YfJ`x(Xį�>$�rq2�uN{TwvUEon9As71=jfױmS&yZt'Λ40:0ئ t[SRHLh qcR*4rº> 줭Rħ2[d+0 4SۺN;cCSUoZ0ԨF4;a%9i$w% ʫc l3-tـ N4qFNoJpsHgy=Nt-8u^Ħ{ U-xHU0|t)@TLOmqbɹ06mwC\ua i`$R2 T1-򢪛,#l-di9 W$0aO\?N Y2ƨD{ ق=z'ʣ8+붩PW۝Ϋ6ЉziH1DPI¼ftx;MEbȳDm?vuϚc蒌i+ -L!iPũ~T}zIQIO+BD)BMFTj�: ~(C/LRDu!)�Cٞdi^} qj};~,5d '-ȶʋS((\SE]tQ+ vG0#¦Ø,g@$D3lRAVevysÙIq[NVW-UЧY}x}fI"/<ºY]rfCŽv=7|(%c(̓@"_Q9tq۲ J=(ǔT#AYp ׄo[jEXDWeQV Lll@K. W{ m4s"Di_f@-/O?\mQ$ XJG\!c;ž NH}!ɴϥ]3L@~6~|̓OWEe8(3?u~iiDIKO�X64K`%L<ڵA%nTSWmW=N}kSm^{%ZTo@wMP`A:ԙV<8yͬj(#^{E7P_4o=ƁFJuY=_D($;Nv{*|z< 2q@i:ߵ-ˍgUuׅcZ!Drqӏ ฆj#]TH{ߗU>tMCk'_/%=ǩ+U7$,CzR:VcWBv^#$r%-Fj^BXcio}C!MW2l7<Q Hu§9[&h;. i@> �KGlov5'X*u@I8~  0!pCk`Sqh�A GD=ưB#H.GA\NPZ뫼詴:,.4q(}ހOOf9)EsrDn6u]w["Zk=pQeWT/+N4 &<&Gx,afB1'(AXUAءN^mPMˎ`/F=ve*ol5L=KaqgHaz>̋a51R+.  pFXngۻGh-4B@j7'/\xc: b@OO樾^7mdY3 k";(NLz D_줥H \y+a)*q_?r5ɒY-^r}=7@ P/n_WEI'~\P?O;€LdU*_ʚ[u쨲lfq%R"m}4 jHߞ]4mYB[Y]]R%n7kĶ4TYTtR` a'n3vE. s;ލ^lXNj,v m9a=^mZ?\/[>w=t]Y eĪ$\0$U�|퀔T4a\-j'X>;jx.d*rshZpё" .갅'k<9D4D b#B@ڭV<rvZַǏ W!!`{Q8*i)?��ly):P$jb8k�kWYf9l.$۶pUz@1#rFt+$f몮r^&Ivތ>Mܒwdgu)2s')�jZueل!PK`%J dжrkN=QaKҼn?gfraIn^W$oHv2KW�s7Þ(?\~PLX]͐I@$}jfjGe%[oѹli'.oU8vYh<݌a+b黂Xä sǍ{;ky͉ٙ!6ŧ+x""mۏ:,�]XɺP2C91BH4 d=M!?]4 7͙ԥkW UEP prwߧ,I6]G"od`*�) 3i^V]Q{Z 7ַYU>vkHaUMը~*~n $&f-‹.%lrW{jlOK쪅1ƵZ|cv1�Vʱ%I[i^(L|�nۂH0r`Ot]\-`n0zi/! *[Xx⦅_$ Ӫ `3b?[ $x$ xXV`4/)*c�]�CScd.ф-x:vuɷ|q>[?n QGeQR@Xh& <RM[–Y|I&2</啸 F ,%D mv4'm29xLךN\vCkāPMqa5e�FnK3T*/S`Y`d:V,䠪 Ꙃ-Kf0 hW![ I≭NUO0ϡ9~FvmS\l\e~TP]�Of4>31o^Z�n+nDejU-="K8IT0|_#k"Vx|Fyybެ -]ux GS9zG߸lj"3V;: [z2NZ.˲] `M�$ poh7MW[.d;nEۛGE,+:H/;-"bK�݆)=)7LJ;Dn塧?}yت/BWu\"}ox;*rX?(l݊bj>>'PϨZ=գ$3Amcߑ?oZBE !<2[@8l\W3!hB"Dy\n:MH{j5e.Xmrta\bP`h3/-8PWy Z6+(F3i@Nų[7OdaԌxN'23|Ycl'N5MZL8͋z`xRTn VRX[pk+-p3XBldw%A<2a+iyQU>ML.7!RŚ�86s +Lejrߖ9E0� SW1DI!%oM7R\@ ٮd0r3; V=9:�y#Zւ86o}Tl@igZΕui)ai]؇NR4E.Yٮh~#�q׺:xd3ln 6C(BܼE_whhevDa鷕dU`q>2D�|k4?4�)XgF"nLJi>m8Ш.(<nnfu垓v.*'淂<>Wb&FD$fq#@Kt zca n^1,FAc|^^pK0Gt c8 XDȋg}h�!\EW'葄zDz2[-GEV4bԣ;}la-&! f F!jEKOeb}w8e?bԇ([mU'ǹr~!kO,^bhxus VƦJFxĝyzmŸ7.'8NRTOöxZ9:рy84*x/>J:m0tXgsL2�˲ _WHV̳XDY@|aּ4. {tAלawɚqzEqyn]ێ { s뢙5JKYuSv,t+ ;o9r;XSWO Pl~Q`-(qG^=_=`W[⅌\RIt to25v_zgZN ñN R0Qgi )܏-̴")e�jnRv&g!=AP[y Psm�ѵ+61~N֞~;c̐N~Q1u8>09Sח8W7q*vϟ PRV4<MH8=F7@T6׿0;[-v�R4,|e $5}QB>E;Z'4 HJɆf&W_~pX|x}1|=cM/cOK ıο+¨`IVe6�/M0;2p \( F�E}!;to7DmX; "=jFIǁ㘆f_K`ti)jpC ËH#voF0Z$~x|@�v5Q . ĹZckc�tUW_?`eg/&UwtE}Z�]p|c1? uXB\E!a`#m1aBr܀ti,ovN�˧0\?==m2#ޯ!yL+ 2(of)W[K9=aY="^]0j?=^_?nJ = 1TiR s.C2{O+̋nᆶHҼȊl2MmT &ƪ䬌<\z[CR7STi,nn>]w$+f|-/pOx&augx"o{Y&Cs LķM xLM`7<S$ Ȋ˛XAwJLxFa:2tmBPiʛδlȢo59|tx - xř9Y=>,n~$IܨfF|Y<rV:`j}>6.II}k6l \8CHr 7=߈(ڪıˏ畤ބ+<L+DӃ{<<f)oW՛EH̿�=;>؍?L}l> XtʾSHypU0 oU[4[uMQTokQD|ăqpkX`" okI14#h" w~s|y9r+y߮Wf+A 7ɪtqVKG3{}D_v2^^ V!ߧӆS�8󍗃f<˒ 跘1F(\x8}30]]K+?b~�?(k0F1fJx2=^k:Nu&Qތ$( {q$06϶ B3!?*col4'Ή.v'@PsPŶ*"/x`|@.V EQ4E|!| {�vYQG393uӐM,KX"`,ѫcy,I60Q6w64WT,c-u]Dd<l�{nrPe;tS,CVt`$A1=2[vh1el.XE5fI..pҤMl:Pybҕ3,'̒( w&o`{I=M7R復w"^*:,:z_g~b$=-|/0[a 0w,kDn><&BF{0sW \w?aU8Wuƅ.yc,+aWsr޿5uWQ!%rxRH_>L{HpoË.C,/yyU>%:A6-?7ě4h5N#\~'bA`�7_ $ߒ9َ̙mH;V}8]|aDXs@+(-]3Ő@Ձ}OFmY"#v~ʀ _d#d8s MxraɁW˱tnߠoa"l8Ywƒ^- lG0;wMC\k{�æ"K@ֿs+*H, ' ԸOw;#cQE <Xç)\S>2*wmx6 jЌݎ5'*w|H]Pxƈ7qTz,VIO>Ŷ&dY8|ޗnyYw#""n!B aG͂B3~tj#k9��wj@-ɦW~H pr"Ȩ_DChZ/�s,D@j?VRU~\2"�6ӝjlaO}ܣ;Ą(h#l-'mx-ߞ+k[ L 6 <e[Y|($Y҂f�M0_/v2Zgl:do:`1TY7.xUÎ~T8ʖa7W2 *g7 ctw _T_Bx!:^rj+1#˧~^mS[K>[s aE oc>x!imRd{l|]em9<oi@,,g%%UWon�g 4o݇ (_`4$6=k&VmF,Q=`ȒeEYyiY^~^+COvafb]! F׭j"]yՏ Acsy!ZZe9>,/*Ԕ%^N{ .nMW㺎cqsL *3�I<[�̈́T\|e43l: k�Y4Lv 9q&n ҷc;Yp7�hI FZ,ݬ CV?vm*UЭƈWyf5e+t_;^Zx+�X39 �V?k$o]fren=4>e 0n/. )r2!lXA2ܢ(I Цky`ej 6bul �j`Qibѱm&qvW?8p2 5ɀ>x}>x}>x}>x}>x}>{gEa~Zt3:KUYyFu~6f@2$$H׳~~ }`" wnpNz3@|UQ9#F\{Y{??Г?-~m2`xQǼat?ϥDFyaQ/&;xFqu8 $߀tgkg. t!ŖE ^MR(X8^$^8çˋ߿Nj(z4&Mtܿy Me "+CbMQRjcqS_m:!v-!h#t˯6,|xhK;F44q VTd}<(Pn~[m`з&Y 汎qмRߑzTaۏooaxq4-з/oV,sq$<YDjuRHXg&&![w(L.+yƞx/W/MK8ei͍ ln>D2_v6-rjPL?#߶d~ fajbߑь�tmiܬg5(QvoתM=Kݤ)b0M۾y(NǹM}u Ѳ}ϛq◍tcغx`dZ6y@LAs|ʢ@W i(BouS3]6_w}Guj(aoy?綈\u'Q]xÆ$MQs冈6;tP|0x>0V~َGc$ӡyN7CvcF<Om$ZY AIPҍӱv �- :Y&)54:T}_}d}'8[EW %N~S?&Ծld:eFUVOvh"z=K&F@<4 @3pޠtH-Dc&}@X½c fFfr߱ȫlb{I{܌bh |Wr_ B&Nd48riZ\:7sN.w&] .-! U}5tiS{G_]_F:INl+sh!&y]SSKټV ܨ<Md $]xfDp,iVG }qN|Og\3e97[O]eEyɊfh#xe6 ì"]D\흠i&3lsW=J"Z0Rj+;x+콪)㩡t2tiwe@:g ˄h Pxv>Nki,hR!uf6.QU+?̩3<qGk jB}0m?imqZ||s肮 G{:rq'M^s6׬?%'"kNxJ y0حNl?3}=f*|O(x@Y6C!Zef +uLsJVX i^@n>1kw`nq>}tz<u!^BI9-gQ N}a =M@I[IPMVݐB91 4Hӕ^'A!t8@v|Cn㘸nTΈF@_23a_uW,PG5чYdU7/p N{< e3`F@)Dw@+g8㧕gK/S+Nþ)A6nD%2O09~ ,CS8 Kg$GL|~D@QP 1CX/D@=2+7Wt( cGOXH{5gקqތG,y2PYeNlo.5YnS�*hCxi=R=C\ajaBcwTG* ܞ=\]o$UU}Q-rjG fPf:'N_^13PHr6E^M}^m"UÀvxsK4T 1q'FBhA%2 NVdqB.CX0te^-EGфJ$n:/rBuH46BV$z5.kDp)1{F#4 rm-mNںX Cߵu<8Wv## p&<]$n-4MspnQ4H74ǪQyo8ce7zz0b$u8΋t4ڝOS^P/"J$3GcDiV_ca#N) Q5TYô>9Eݏ1/aXISD4$2ƶAdGhKPb>-[o8i3GQ-ʡ:)u]KLh {D:|QVG:C l5@ڒv ۙ ١A% R�:bDxt<ex*fT|2ȡ$& b4I'*jq/)p,bAArPWi ӭ9q` eY I$mS7t,uEBܭGX^XOFhg:Q5[P XO߹SA5*h]UVMb˾@@JUo)hc2j`*E?Brɒ,z#j]#$ _/oe 񐊛]h* 3rK4t ]V2Aȥ57Pa;.gMy^^3Ŝ>}]FubK$AȂ$"f;P"'A\Pt+n: #kk"$IYNL?Bx9Oy#Dz=wtM �B1enaKxlǵŝ>(a¨ *$F&nv'yhVG6/Pᇩ</b- '@}gIo45E ',㡇byX Gmخ[F4al߮b 3 <.H_VJ;5̐|J֑r=<NO$F#rN|$-bEQ a!OpwDZ}>q Esj)q !yp{^!xI3bօ@*]Sa$.; )c ?(dUåX/h < ȰՎ*taGex3.$ҪFB ,AwO BX}X$r\#e9ocWeg}LosXx.t6+Ⱦ`r^~Q Ö#y>eEU<wn6 0{H#duH,hIxg:5u@?̥wvmǓq_jI¬j8ICa3!{w/ufP`+zQe58LiN-MЬ?GHӋN%1,@gEpcVu]UEVtB%q.FA_n*{FVU~aQ) ဂJOlѱ?2`XEO!v�# q,#E޴&;LJAXp߂bilBOc ߮xVX E94sQP 44E0% xQN Mˋdg< 4c]>^pjPGDڋ4F=5k*{6ܤ_J?)8(zGqHIV =]}` )<qh\Oa tɫ}liB Mĕ.1Dٶm?NǞa/IsQ |R?mLz]xAȈ.LI֡@]wH/n8z 㚕/twHC̵q^$p4λӔZ2V>C1?hb.PGyU JaQ "'C3QhsKI#ЧSjok4euqiF"r͎D- bN}jv ڶӢɉ&~M"q^C$Y;HTnVuh9M- }kE0]Yw+PDAC+_V芀JZ6* @K>aiJtUjf~Ar wA Jwp #xX^a11d~_6|U8 aP$5dvڊʈ0`�)_#Q~;,2~ޞ')z{#ґx=;=3$K!!IGxVXfh<dAkkm6հpUqqD++MoVC��Qi!RD�[ޭ 1r{缢{YcH Ӕ7JE~ߵmjX'Ivˮ MUdwNntv�n|$@OoKAO1dCޮzA"q^=*jwq7W+P:-#Y)YqF$'xka?ĥoXIۆ,K -RP.l%j> |j>xH)-iaZH`CK5xMOׂ|ǯw%1nTxjt 7eU"dD-+G`:vLwQ_Mav=u7 4BVF|tXo8Q^�rX(|,Hb%Թ<$+J9^ [6$t->(An܂Xq̶~0`"ee(Gz~Re`K݂s�ۮ$I$'*OAŌf)Z2KVќj$aњۦ( 2ZyIm[?"RuRv}t�n^@A:RD� ñp3NS@O 0w*ϲ,GffG,Ңii4oC7u]^=5D$#_ _$zU:6.ZP^.V Y < ,$x6L|P! Vi9^80F$5Mvm8'{bmyTnRl>Z1%V5*M&SZ b1;Eyc7˥% zb= S-q Gx-K+%M,$U,ymySo 7̱1*Kч'�CU bغ<9]P" '}$`990J"D2EkqյgNPw=?-ly�' א#8HaWhUTP㵜XCB$Mq;eeQZ 2י#kz?-FYә+"'zS%6!*\%?RFWW,8Db˙脾{Ba\qSrb僾�gw&`ulp% ,BeQ�ؤXvV8hF t㛂 x==yJ i<7|j~Tv聸D!'Ԇ9vu�Knx*aV@a G3Ob-/< EkN%/[b0 Rb,Ͱ5R /j~d5B=) 9aH[$Qi=YV£8S7ӹGY:h̕aҜ"AYb-9'HcX m!?rNt[Dض 2BGQjGYXW7X5X{+caS0]JLN@NnWܨ9q5mǪdOv$v"U@LF te ;܋E}5 m 3*-ab}q!4-j")c]&ѹ͚8]N)NLDdܑ4a'!%m"c9?A`ƀO͠6:i<@tTPxZn8QDz`xKcO;F>#xP&zީ1|ir&.F"GGpxUa;ne#Tx耪Uz,=tj$�&#f-UU гO%/ $an؇w8:(={9Z—qdž5n[65$kvӓ( _nȢIIkHv/-f�Y ѯ,Y"ʁA 5U%NբY=k}]cq+ 3. CC`+@<t @zpvG|b]ƮƃX$v 5@4¸Nìl�wu!EE3t I!qRn4:u av;QX0&Fr7D,a5҇sf 3MVH Kb6vq vpc4qIw) G_ha%;*EXN[Vyא3~=٢)ņ5ݬIsObЀ^=hāsl!W5a %5\SUZ>xri,d MX2dp~݈d#6 F~ZH-sOVzC4pLvK@0đ<Il UޯXV`'7M:}1Ԙ;o˻[АQT"O"uێN"@ J%6T%zʈ<yAv $A؏|8o ;6T4f jM nh4D}AbC-yaVGvij|c:t]x10+&dϻziu*"9(Z~Z1WْBɆlٖ7׌iC^d:AҌO0e^oǎZN S)/W7͠$A60FEnˋKx>m]dyaU O7,nH}EX^?W) 鸬XQMt4jt$ïOnY[\ `=:M<t 4ū֪͈J( 5S]b7/";0,::W8!4Q2ӯWjom9<9vFVGYI -M!wdE5vx:[+cqHmY`]῾ 2EUEQDЩZ)X5f`܀gJ<u?2RaGVcl{va7c 2 Cw]f5Ů3Vs}ZnRuZȩf" -E&7XeHN}y� NǼ`oT2&i^s+�@Nڐ#l#JBߵP3yI &4M7γvvs<h:L/$k~4+i7MqO,J9V{*u-<Qi^~O_6&b9i@&Ꚋ [Vj8A\ <dZ`9/-H=5+n MIAoz;mLlU7My7Fxo1)uHY/?} aŘv! <MԚ7|N_l]@`"5!w5YQ#7<dtg2T7O3шlO>4, C\x bRYZ^.)wϰL6]5" ,OEH>OXI\ێp0}_kNM_/fA-JQ']{w*Zڦoaudw 5SZp7dG8 a>יא*nBY #dE7mAzSMt }>1Ճh-66dIx]3/hvdG[N=*AP*r yl5^[pȖA߭51a H6{/!xzK>9<Tc$P'X֓hyԨ;IuWiVf(o?t=Wh$c64a7&aR0\YN{"] Mqu'D[DilVQsAuxLȊ!I+n/'9a4,NG/W47U@L"ֵ- a+JP CCauedMϰJb:aא% Dz,')mLԵ7>MO?DW<#JXC8~2nAti oCu ӱ\{X{M P KcGa\0sQ^Z @f脞)d7X.T_op~'9~AzIkoQH?<�ž6aTwطF6k[/X(yT,]Ah Ç[b=ӄ!*I_Ke읢ʫedw!=}$yd=ރ#Xt1 rϓ k8cOnԎ!>0*c#,?2US +0SvOVÊ%n~uȈbFfWcxo#AF!ݬw [P# Lixq(W` vٷw<|ԣq)~Fh!]wg'K&<㕙~ȀAZ}\,8dw<Pr 1[?Uh�_&Y/'Q1rW]a\WfxAm%^߳azp| 9Eǜ\ۂ:kYYQx<,hA]kj~785�M],%U�w�Vے.yTaojQ%I%]dwAᐿ +6[)bmT3 !pW,x^\V>E07�iDlkEtۼdv1"Bt~<i^R!?8[_֫K뽧#Ybԃ "ev|o_&x<hӄ͗턦s>/W%*ĦX߾n0y'aь='r~%g8ca޽ȱ x-!ű"`M4{ZE]}`/)3XHX:d4<< tnIev?vx1S^^^lK~Ek;86LȤCe,سڏCϱl?lV�ğ4Ѱ{(LK�3HC4A_.!c]ּ=Blb3o~'A[8$ ?੷9Wqaj꺀1i�? K\O=B ,$ #A'U~#urr`Wgi[Plg9 7Z󟐍 xjP&˩{ ` M MYO�? hٲx%'i C mASMtEVB,lV�yQZ3" !,YE? Y�!M&wp¿ΓzA0m4Ä5!9 TГ ^o(�DZDwdCɏO?Yr,g9Yr,g9Yr,g9Yr,g9Yr,g9Yr,g9Y3ΝNmԟrGb }u75 m$ "B7j(7bBmyQynQq. *4쟗 ǭodE dϷr9_fۖFp.E᬴)7m*tl]BdI2zIN(-bba;n+Vt]۲F ӟ n&&Kr}RW_笢[]]HAIB8EWq3<\[ǫ_>U:܂%_>̖4z|R(_?'jZla% SkTPyfגa;&\nXEoWs7wC{{˙f+')}e3]Q2-yYo5;m>U7&MYTTi߮* ?(6}:tpsbKK VI?n5Ȥ1!fLF d͇/K [{pte1Ye<#W_;^\qMwo;vjA[u3g\"0땕ɋhAfHA҃pˉ`خe 7[%'/|c ٰCzQK<u UW88[pvO=*^?% kaZ43D&n)Q+"deIWEd*N84AT]n9aU%-*:q�VViiWӍnu]gY=< t҅M}qn6q;հ-b@lYթFHԘl'mۊ0u+iʋϭ e+зioEg.DlDZ-d}P /ꁰ  uu /ؾlsQRs㡲z0vXJ˅EU߾/DOʞ( k }[)1tS=lƷ?H=p܌,ilXnڗBj9}z||\ʖhm d]ǺD=2jݶk-#5ɮ+~SYZyAtQkpaWWK^+tR$pTy`e+mm?~N, ,~)U2u3wػd(,c1uLdH44u#>*펇go)IWvsnSt0ޅ0KlƷ9gc7x; yĩ6]?:  tt`o3l(kqfքhОٰ�1@ mNr!@x!pV,ךdy؁ҿ=}J?yU^8L}KWfi5 cL?+�WSoF>JXirKdƑt/ϿYĔ-?j8pC n:5n-Z2C*1d~VE:6]c O#$8,ˢk^Pq_;KtQ(uUgݔ+F u<<yL޷:goXS kef^Q$UĔPU#)GOȊ2e<JV?_^~{A6w#ԡ/"[xQD7-ꖥǖr{#%0`]?RK#FQP4dOh2:q i3/wH'Q[MmU+mm2=Ro' eXJpoXKEQeYQ ߡeZh.z -CC(׋\MM /WmH`=w k Σ2S\oxW�q+>c95�þI,b!ya$ngd]W8HjɌU YW)e)We2}^|0L*89nbߋ2UM<Kq"gcPZ *C"]*Rm Y6pv0!G 9^q*<76X߈:�ĩe8ZIpB=qZa[b򂵖<$[I@WdHWM8q3U4yuHؔZBަ˂b#x VIa^&foYMݶN|/H]_~�n�=4#s &3WSxV @>`lYTeۏKsov@QԵPBoa.FQ�Pdf٪xDY b$GZ5z> ge)R4יoEUX-MYiRqv쿇W+,yvxI ?؃{ WYbAUuCw`ڧE޴#[wґ5%-Ij;R(X flw8|/#/kX ) ` Q#yE]qv=kIM@ɏLeiAƼ %~ݚ2 q0g@x0yW Wz<]c�wIhᴰG  49x]wHlfYD " \K)L4JPC]nzCm 鼸?$qsMg^q-q&nz>$&,o+͸ў5i3K$ cE 1^EI\?ޞLw/œ23C(QFmKDSk/w"l -Z\Hxw;�u]Y27N_k |PN11J T$.8!.6J=Ӷ&Ñ"}@6uUֹg�4}h' y0{h*8>=m`ۓ&Z"JDOdZC"F2q!cbF6KFg?kAp,R$�8-#TeAOKRHKCz>R9_7/`w|4Lk{LgZ҆!=TN7k8NDPU@]E)� Mezb!fxQO~~p [!<kNԌ<0rF@aß֬m[e/0n׆:77L8}Y* (s%[u#I =>n I|W3n7o6/ 脴H^sմz /3<D8-WEVdhOH8c,Rd?E3 i1e oC]kVVN)AO!dw`C.A.Bi }1{w]4XCH]MEIlns veM�Hƶ�D} U(6L8, C f`ZX2u%q;+~ / vHF~�̂0I0n+ߘ<;]ɖe+Q3yr9se{f$(%"6}@ 8%uM{J/u'HCKE>**Qf><|{0J"8+SM?< D (Yp~DZN瀧^Art8oWҝLa:ay5yXgYէ|}mH[(}3S$#n:<^,8 bwda{� SjUF'mԆx~4_zZN]sǁ3`>Hd&2#ɺp/V1-L_e,8z]'* Enq|7&amN|+vJlm)#Zy[)zD>lS_o8PzS_&:}ǍAX hX( a\ 5'aOgH#mh@ )qNJ/p` a�d3U6ۣn-Ns/ћ4ei*V46#Y1C8oi"@xj>[a,bpޫxV`/ G-0.rOC8HRS柧uE8fe5ay3N\lr:+<o6El<a5JD@:M<Sl-tuyڊӑ- UIaWKJ�Ey bLx:Kc-m)w= PtǨumh~#HVZ]9+7|h,칎|^rΫfѺaשּׁm+ZsK~@`w$ߵ2V+-񋵌s:`Nq�<rV$QLg5;uGf@,%1VT$OJ|: qzHIdR('uH&L_9 <"M<KSpb\H]g+X3bH!`ʖ#JZT@ޗliQHS xs~a&6Çe8ޔ޳e+&ђn]7xI¼&F~J7Gl3Nu?cS6,ζv"v/ ÌYG/]6MLEÆ} 20_>kV9H+,)z;۰Э/&$| �ʆB8pȊ&@%o?!x4^r2?ʐ4W6(l DXha%Rdלz~>d7eYVҺl v*goFԌnٞgˋg#@U q'p<8T;֒Ue8z|8^N+ "fI&Q:}f-(Wt2\p a7bGNRc2 $:<Yn}I~49z=lc ns6ؿaG( \KPZN^UF,s=q.t ue 2_>.'�VXQi7Es=K -WEE5Y�j"0 o&%<8(MdaaǛ^ ^eD;!(=쉧mNUt?�/  uHãx'"( +Xm"^ {AZ-UHIR0ZrD1DAiAsDI" H1\ b3 !.k`C:-Z/Tߏs6!GP.QՒUEiK "|+$J?YfyyḷзdM*_Ct1 : <}$ *Mb9bz =_ 3gkhrE>g׾=JKÃnh.Mӣ8p^qL^;y!:ImVԈJQbG O)КcV]8VZ9xsqǖ4|̎?{oVc(x�>M]:~IĦL϶N,P=.zp3@( <28sD,)aEWF9&W>2KcڍҚ@xw,:g`a1 %i�O4hKR6hhVO6)f%W^PO˺4m&,7N<̶]`Wen>6Ey6KXMkOl˚:l$@\ij1`SؓҔl%m�DZN?/huQ<nA6?i|B&zUbW~~R&l$I ;@߅Ù�XU$K6i�pN�gI"jOOŹ1A x'JAW+]q 홤P;\QdHzCQ�(įWtq9i̬MS pG` ͫ`+;GFw0IaGf%M㢟#zx=^`q,z-~!K;G~-H"=m{S5n�Nccn 8q^�+ 8F:Xq> J-vA/ՖU՜[-psp$�'9}Mav-�9dzz4Kdv=lS7uVZpi9a7^kl(B?>W!cXfZXN� VBN`bŞ &ԛlNT 5YYuZg5$[N"h]XN>WmUX@y6*1�4~uӤDmzgft\C+'(<Bsb8bY%Âȉ*=s\{Ζ }xl#Ҫ@@+Mpj"wTňs@dȚeO6$C;|-%%|g"tI]fPՆyz3zXEQ<8j�aHLIÆ( mYoEIW-f_}$9<U>S}ӇɚMJXV4 FjN�KR}Q[s <!HMtI^O�4 9%F&+w]3K¿Ei׳&�X,?ˊyFQ;,&8%=w=H|$ EUZR-:EHXWyXX! G5 J,Xr9nIbBLykMٖ4{%!6}SdY^xb'A  4s'ȻHp�P/_MnRTX)AgpCf5BͮL~ P-n9^7W:ɹmm!aRa-YbO?4Dp¬ "tH#`bD (MmoaFe79RyԜ] h;II$rOwS,&4꿢qj[RC j,pP)Ͳ_E"fD+š�NJFB!5'iUfC_g͙"< wnP`_KUU釟)6Ӓ:4-4pmMV+Qm +[s̴TSJQkt.JUCb%r>-}"X ..UxA"i$RŦ`  k`$`\86 /#n:UPn$0);I!n[zn`%"#/a?. X�df L6uô ZXy\q[F@PQUܓrb�߄ukG7?" U*0[hcs9\멺Ks Uz/E�o5(-֔Ftޟ<}1{MhӢNMGe3ICn~kޫk<rdyvQN6 <m㫒f%` !OߏV<Xuݝro3ׅ6Q鰇5l"�3aQƑx)==G3!Qt[ZՅ ZX*47 mǍs T*GxUu;&`%lzwnRTzaEf`&XV=}] ` ]v:W} "AoF+`-p-�&O~@E4*C/wP_Cޢ`57KXuP9^3 e8 ؄@ߏE�":F?*iXr�/[e6qp sgEٓKYj2iD+f#PCoO/Om-WYަRޟ>&),!ۜq\_FkRuK8g> Ğe3iC 3cm/YA-^xc�C6]~Vz=S,|r;<Ïj_^w]?~ UD 7*mZP24Tq2#ɚߒ N,vsw@x7ZYÞC=$)u mV+MXJdb(f#C>O&6Wp㎔'.UK@ho4,Zn?*rLM7UŠn;O"< @UKE ~{\H&FDÄ7X3Xyrp$lFפ$56"4lߕl,M7F6(ߨoai 8tul(fRMU ,B">?|xXR,r=f= Y ®m~݆z\d=S;"2t]S$%߿_ icAFYda1ٴ8I�pfMKͰK[!W.d [#$-[04r f,G e3C�e<]2Kx=enT=r<]kdLalAs?ծ)>$P(e߰a T@5M)x�{^_G`GeݙZאYmʯOkavm ``ᰉ^͂ާ@oV#JV1Êx8paI> oߪ A~_;ӻߩhΧϠ\inoFsNVuڟ>mF�_(c>�ڀxt՘Շ_/4KY<Sw>7k9#p�7#GmZ[[=]*O?nWy HrUإXD2msMMn8t楀⎄9Ňx-F<߽ >[,4O6[7"nږ|ZN2�s9G'�BxdxUg<,uAt ntVuRѰ?Zo`?=N K lDE_Ӫm./G]]$ٻ'VV ;.w/M#'|m(<4}xx]W�(M{LH"-\$;~߽©A >wCF5EYx!op}n HȒ @RӫG <5N]duα~/(˰Y_^@^?spӤ]1"l^rh1FaeSI8EUHm^EӀ~tO?%0.;`(}^)n%<\__>i,7M Zۮ\H]ewuyHmv]׋1FGAZztϪͩᆁIq% iatdx,3^߯ 0c ZC:o/3RqٶMSPBFOG*0AFx|ޚаQeY:aݷ`D27Ppl%@g^3{ښbht3�ZYp5Yoј3 ug5-Ny>='T7`8kxu, ,cOjXke|�+`EdZPu}裨ߕ\"E.r\"E.r\"E.r\"E.r\"E.r\"E.r\"E~waD44} -nxej#wE+0 =vtu+q-?Xe / БXVZT>>x1`Hf%kQoTHUh2'VzW - 4\(e7?G2OSF0t?i^略, r|zm$#[VW|~vyIAା5ι_o%cih5Nt("q<y|AZik[gVVW#>H׫b6{eM>(&G2uJEذO?>^ mUy!͎0/i5>oirՓjǑsa_.|˴[pG8xm6hMj+>yHM[b:U_%1؃9y]2RŞ9ѶxY.]CO湫>=a cq~u]Ӎ?V:B^3zjhyOuC[fpm㹙y`[n!t}oOYk[hQ1qA`;Q̄SScG3v=Ƕl:N]jC!ҞǢ&3:TˍK3<yigCͰreݪCFay>v/ғVTwKg)v:ӊfeVks9vdTv7Ĩ4mQ{a>.TkvsnegرLL:q ]=Ke7 pDev0#ܱi& *nڝN/f64["Vò¦v40ta;2aC*3M 8#>&l[pvlȩf8A6(Ҕ9ImjzwzwlL6"=m/ECO喲i~SY/i Lb=~zX bʒ( kXހ}ܨz!6:AG༲p(e|#Z Li|ɲ8Ȇ)MhEq*훶tyuT̨("XҞYBT2@b9;&`AK56Ϫk2 177KL' jP)0ae�fz<CۑS5U3nW6 2%#O~y q㔼(SlZY3QzW&;ldξj װݰv[ܨH|?ȚUﻺjQZQ>O uNq(o x2kWb禷22"Sf a:UZAGƏdq=J֒ءHU{='l: l6adUG`i[C;]+3QR5hrCO'cP]WeY�|zS^h vT!@mX�9ÐGq1m:]2uQ۾�rmW>�jY6гֲ6P[WugxKp�|HXb -]�۝~a'SNG4Tn<cW' pioJu 5md�\xbHAc Ex@i8t8^|V:Ar}X 5,fwZk2U&cp1!n#3q* z}״54jꆡiOb 4X[˛O%#b놓4NoW>-ͨәud5ȶH-_G7h;.qZN�WuSg.0d8@^hYoԢucn2Oы wdyz$3G{v&J]U^fzl59g;A&-sL@7vmmҰq K F^9{}{-U5'yH9_C1b:@PY7|�MҪKɰd#l,/F;[�1x^8(=pBPf+.Ao-h%ߦW2-knax)2t,25+}$D<?͖w&kVќ88#YӐ.Ӵi 0oI{- ѡ!ÞM`(<# {n<8IT8߀&MG\f#p?pz%lGTEh[= ;̫#x8\%UU9v&׏ K"K+pbKZ= 4S`]ij`dE}U6l h(ZF+B?"{ʱK-v`䁯r_>=,(^sk�Nq$"g-K ~4QT bedI)ќu8zO1]Xf؟Mnk2YE0]4{mϦ U(0|9q8f>�tYpۀ%'n2�/3TeVWq Ku'H捐#)A¶KLE)j><R&U5|k�jI718c . y.dcS,LN]l8ڜr_.BH߅Ʒ{=X2k(*tޓ4�0i*+St`Gs~`4 [튦#.k*QtT0B15YV?W ^VG4 f{1/!8>›a5a @+ lV!q=E')Wٝfn3]TS+^t(e`^ǧsp0t(vhGpm]1Т37םbڶ: d[ 8(] J:=<׃IE#ܵi '}]BFrSܵy=7xa;4ÐyiYag߶8q=38|k^"ChmᒠH3*x~S29 |yeURY_Dtnqe~ xȉ& iIJ Yh |5aCG5Mee~]'?S5Dnw> -i{7L/=^5n:gI],ݼ X�Pv R0Z@N۔P頣>nqn_:NpPmL qG›ؤ�+l۱ lnR})@ .MK+Ѱn\ݐY8AP7< d>MWt5. =v۾C]]}x̂¤g!U[ɀ(Dt8%~;Vgr2 1%`ewM� 8iLp۶*4+SSc?=*mpstߐkn{xD_fI/(J_g1K ښ9?f#Ŗfͮ !ԣb2%Ml֡zVhxѤ]KaEL2 pkͰ,M$V@̨|xɒG*ɺ*{91Ua-hvHzx8~?Ď)eTT?*sOX@`@Kxօ{/ĺ-u\)*wfסip3^c҇@DSY|}�`T}_;쏛yxa%c*˪*$�ӰNqwgJ խS}�{%ƶՌ77H%^ _yd%]eٳI#�,>x<_4 �&o3zbUP%8λ6'^V,5Yc.r�~!8 3Hڑ~�wڏp}5r=(6͸R\T[4+ Ceи~zK�M_EaS0P4kcזs�'hBQD!x"~zUl]۸m#k UEGjC5*||/+$Q qwV$~[صqTʎ-]JƠPÓөPGIlhȵ MoDrj-[-E׌] lˀbm&];8ZZwT] 7# d�(]N,QU~zĕ8)}JhO8>l@ VKɰ9 S.IU�=%Z'.8F.q[p:'�k]8TUd-AѴGxLP}*/ʦ =q)j6gW8 $ npF*Pt$ȺfE8%TtoEhKaʛICn}8IEv:sDM�-[2QdU(=]ŲEi)d]c=hQq?hW}b$J��?;XbgOfIhjҚL KbXt8y'h�ƮLUsrL徽puj.[I�sylXUcW5Í5y*pLVL'qz/-oia{tXZs&U↉o'^EO4,�pLt?+\UUy1eDWtMpdhŃݡ4[  ʜb".:cW!P[2+X�wlY!I{,6PZbya".8yZJtC| ¸(<2"&'3Meڶ!U{HU8 éq`AрFÔ5КS֎/\?jت.gv̗OSɍo)iqӵ4P�j}C#IoW,0!h3�T)� \Vy[gZVne3s}#EIV{p!zA [1 HAw؁ Ep4ˀff?{?h6�bW[~ђ4o7N#u8{*݈ڜ)nXyxyYYH 5jg !j `IP)lל JԂ,Af@9 nNgM!/s\,BRd7cu}{H"'?>aVRȳ@#`Qb^<s'FA%^6b K|{{=ӮSKBb~g"}GZw ]SDp;LSAlJ�sܚYoH7uJ(D_kQ(yF1֋i3b#kz%`==刈 M$pV=�eݦoeGK <zC'@~[�5eY䝽7ܨ(i Iٶ*ҀYV AnL&E/׵Y`Fu7EBZY4pu^Ϫ?B( x{Y f8qzBQ5q#`EOkIjf+<KC̀Y^R%ٕh~E. ~q)/F.CڧHO�:)51Cŝpw/ k;,//8@Vnra�ZIDpwkqTջϜ* tR:&�:{ĂT0gWYt&_I@\mthz@k 8 q9-SU;~37'G2o:xFHqV5O,>gF{: !seiVUn*lw#Vz afU&2 ' `EUXͶmDiǡ A0ty_ +DY5,ngkx"+><T pIl'.ג3Ǖ6XD4D0)LaZ6q\ˇ' ?+6H00ӳp}X~94op2E eiӃe4x5u>"| ɐmG2d}``!:f6LtJobi d-^p,,i#;5?0nD?Uam1ȰಮgHЀ1-̈́Xy0ȩ7+C[x^ gf M/QqUs:d&suOinY ?x\KnicŽ.V '=eIC-V,+ʹϯ8U X4U K7xlEī=}nϯoJC e[�T0~>&l x O"ϒy@h@?Xӫ6'޷VX摕e8 xj{<۝JeUvbYzn *T,L}xXަ /-σI+Mwc `MXWODkp* `-= w?~ZR&IF2\mJZL!ƀ#Y}[ RTXxOq4@80eS춋t Uv(/_Nh`G `N fqۂ�S)/D7<l4 }ڑgC;ߍuHOJ�Ⱥ$HdJ7d"[6` o`xuYt؝Pl(mwve?@ouw�Hlm*im+83dXvPSg�X<]߼I tRz(N״&,>ˡ+x uz)H`u &4rFUۖWnXz%Kv�0#gcD-`cC4upT~ȯ5܋&8Ѓ6 ֻugnA%:%5|!鸙][1(BtT@}Dl0 ːWW?u_ TCb+DSI<`<8*`xTɄU_rKA w]vTM]-W(I`qtOCX.,iG�.u]\ jz| -(H عlJi寢VU.1޻%ƐMC*dצ.1a+R"$ŷeH E� *oroIg e#|puUnN.ХJaP P4pnq7Pzy9>2em,$8�Tζv `&/3^k�?y ~lJc<ޗ^dV>?ǍXQ]',w(dpo'q:ScŶʃ~C֪ 2'~ !'J'AVH :_$`e{6c$0Wn[ 9Iߟwd,/*Rʚxx9D !iv'Dfo?~L%l:jwvq+"̺>v_jc{aVM TNF@*P(b~4`Zn޿t", GGz*N0Ƕ,]~K"ר$=vȯ6EEx<0%buUUϔ%l}[ P,Q^ߋjn~Pi{ M:�)L~(C`D6\<n<ҌTI3̣ IY 0e��`+ k47@5H׏F3�C{궾b3I/7۶Lun?0ApwW CB{P<M؆2̀Rpx8KwUN%>Qok)i@X qױCG-pSbMJot~9YWE8K>ʶkΐW=%XXvy =h�w7U0H/bK%ӵh9 ͸r71 zc3 Eb9]pDj)dbB T!#V p2x:ެGX#[Zq_Sv8ns.M~_q()^ /&*0 �fv{ ao(MuEXfddo" @$$㻐LX,BBwZnZ3,�FAIރ-z0MEsqU3ҡ lu6xP\}X$ȱq< x>fM9op5.җ(1ݲm $aRBB|!T$Ibn}&ࣸqS<DĒxZ:F� mKBt]MyAMh7_ Ks=$%ݟOl?_1'^B$IRHMo3 Mqі>t%9/dﰞǟ>N4P:m~ƶ.;\9vZ[=o7"/.½*Ϛ.#[S<by96ЛݧOaMia~~$` GEX^Ve58!ǗO&,{]p8C qyӻRij$Y.l^gEٌriu2oM0u,r8n<{ϓDyh@Mzd$fv[aX,v8|__~�(eYv^JO4I h0U?u,{d(xPf>0TMo=}: =ϸܩ<K}7"�ҬK(˪ЛmBLqy$v'$m_eK擯4}[J4!0G@>?0-4@!9Vc&T<v2DžF5#Q^V2n9`,�礫ɇQ7!4[D5� K<5] ɋ[669t3ywHT{` 1C.?8x͠K00J(Lj쐲kbɻoK^PT JwXk@F% :nO7 V:@ o6*cv�0[޿`[*gW}b?6(Âcl*Y (ͯh1yIBuS9:/EV,=y(lsyreNܖ)$P\^M"Q'W\� Eӿyn\(&V0`.Wo*} �jw?AhΗ k"p,vF\V+ *+[J»ACɲTdj:풗hX߷A /Y]GN֦ㅮ%]_ʳD0ل^ i@1Zǯ.x")Kh:0-"rlU(@ �%�Lhe {7aM6U?m6o Z;H<g\"E.r\"E.r\"E.r\"E.r\"E.r\"E.r\",8_WIuz1~dM$ŰlƤ`(܅䟒/N'>S脷Ka&9cą$->_֜(лX(~nή8_A->||8}?$ = l_}n-Z>ħKÏMi\/o~3')v|`�3M_}t҈k3s`oj3&A侩X?0("CwVy-aT3sWy+zazi`Y\4L;"#i0 0I?<1U9a&]9 "alꦈGy& t{X '<}2rl+V$gchOS3ic4zq8t= t`NVMXF8FŮ eO,FEmy&e*vlU_Mf=<oҀ&q<Y.{{Y]V0O}kpm_y=l]jvyH4~ /JP^6TNc.|'>>NkhL4]X"k/ϕ'\;kOY,/YoCt$]l~w#@0k:*I~S`q7>KKX:"oFe9ww=9~ [˔XcJ!qW@'rEӷ};@\äpx9T,[[?<(^:doݲ Y6L])dd׏zZrDg'%&/z ewDbyU +lk[via^24.zp~ndo[}m\`X>$#PK~Ǿl@oaXud9~4}`eUs5A41OFM"/a(C9,cq]&6ǒ|('oֈNs(݅xh813fB_ Uj)[NMͩۮy!AU f:UY`c7y.[_n6=.pҐi^__ӡ*tݤNLezb�g/9 zW+ڌxxb~w\&$Š"pܰ,/ 8lӦmlvc_cY&2@J S4QGwʒS"Oe\-6L\aҴi3UCdE;|xîFV2b�h]=!`}7uh !o<u ɏ um8;mA+\K3qsVV{78V@8,p1yTQd=frpö�qy.t`_6yq\0&n,/L}u2/iNxQd^փjc]iRqjz<%4kg0]Wr|1,!@!*E3TV00tT6mK9Dp؎t]<6w#g9aQ6]?M 6BG ڰZXnԯ@ v%LD[8ωVᘡ Arw*|`q�h LxĐ; mLJ)˲ VMdZtBH-Y78mV4O )mpu_0pIKX뷇嫭H+fyu-t33O0q~w4 mj!EŎG\ J_B Nj3O.we`,nnfFA@aE'ls#P~|4gXf4#8!mAGQ^q%vqyF�,mY"^3ZXC~<r^vcxK△b8.O?<d)~o:b,CmY~Vw}Sqʿ7g? U⻶ȹF$[sّ4ڑM{EHͿ߈fRHlRʊ732c܌#JmL&3 COӥ`XgJb8{_̲lU³70"vkn!0sUMבpv X}?4]ׄ銑4;J  F^_6`YxӺ2+oc4DTB5臮*`fJ؃WuQ h?|=%y\19dvwB4;6ud R(G^9 ,l d xg=md1~R;۹qh͌ r":M[z7 ͮ.WXazX r0SzqըMwUp1?3DM FS =7N~dX^5M�x87;"yNdPxQxYS?QD^آ89#Q%BdQ4⮍L!:ŘG]$Q1j$%7ۢ3Yq(]yv3DQ?7f(!,z<#a:Tl4./=QS]%Q_<4F+"7^;vʉ+bσ|x"G"'(x:ǘQm4a\SdfE+6î+CUY :�rx-ɂ% g^GIs C1D"~BWeY.pޔizAӒ\ 0}@Fڑ(pݔ E�,C3n!_Wwg0!GAUD_4 |ҀywՁ m=ĢGBZ�0M?.EE^Գ=aЛ4,1g] kPМ"*\6h8aacS%#ȑ>*,Et)2ŒUȕJ^qq8<ob(ɓL<]PC;sekڶxD@�|qa٢k5X<T$o3n]h;vy6%0bP2YJ�7=&#\Fs~[x^e~ChӒ̓�!X≒5+Txqu@i~T(nӵj8vEa8m[eB2T7-&40EV/P!ﰍ1e:|vؖX"-J)|(7l,M4MPy˱M6uiTU:\)Ie(,C�ݦ-aZ.pi]4s!qՆ؅U{ЃôP bS]߭4-w EQ]]g ={gݮKǟ/{&?MׇD"BD&㇛g5ӅECȣ8PVW%o1`@N-}y6^(io&@�n&^5~e-gf٦9"sЫ݇d#GJv+ZTtEaXGWdWtQ4 6G³t&"6$Г <b`CGckL ~ MWϬN ;by>,EI֝<s4[œ{#)D6VXe2k`z8XYH?}_yQJodwd îlc㗛 I{n Gtݾo L2Tby=U`5LE6hJ3 ͦ$Ϊ~ 0a79[,)Q]XD<IC7�X,'l5 ӶEW-<ˆATtoazmKGF=Z)!pSAk`?6p S<⛾obEVr�u dk2cEI8Ȧ۵?�k_NPVUhR[(-9:|5Q;eOM+XXN.ԉ[C95KW㻱dpCm,C\,8$~ɄJ {YO~'ς2[ZQ>w/;5R/@Яay%dxCr#CfKVSecEh8Bp~rS! _*9"K`[tar3!-�g+Y*@hO3LHZ<CO|{\ a9KvONJ7\}?@O ^ a0Mdn_0eL=L~cnj6#2}+ "@ yvY x$EvNrJh_ @ECYgU\)Bdױf6Uu.y,;-Kw.$X*@Ý鮃aמ rLY)NTY.$ݎ-@6$jC<M6ήY"%1O$rF9�-E6-vnF 6* a-ʢ;Z'8'5<0 յ7Uˈɟ-Uχ;,)IKpacWL ^Ȣ(q 0!dʦW;;p!]eU`yćc.YlDxF*ķTQA! ~bG==3�P|qn1־*[~f֋x^楚Fy&,slw} D`D݉1{'^%zz&+^`'øeNhló63 j1rXwE]E:yȫ1mG1p%\SKՒEY5MMZW"{Y^=nA(FTTUMj�3E.>xFMӝgY�b޶!8UZB$j& 'v3߆T'NQM5O�x1#^![V XP�<`*OMi5,(F-kY&%P$y:�'"p8Dyi3 ~IU$˺*̓'iMgAGyB3}Z0lkI;0:H*&ie4m�Ve_xZ+^w|}Т$o=<mJ_d2y̗nV�K5+? \# <i۶Mu;,1H"1 rԚSlhEs31L `G �M=S$Q֡aoj*dtQ47mY Y+X戛1E.AոC GG>pf`SXy]7ya힜+!`5I W�UýhWQl+� ۂf1pKp1Hbm:C5X]ZRܵm;$rh'ah ˹,t vġw|0�$, էUd5.L~uu65U ׅ$2W/�{ YgzIAsX,Y sp/GIEl \l%*M uS."~-\o"(q-M9Vvü* -)|Z =9:*H-zH%v,RQOx,ϱX TmG~WNzl!bɎEJ ac,�Mj2=yO{2hPz՚8t'x)1| 3 @.,ekde D۲Ȭz@O7x-LC}&"8qzdD͍ҼFк [D,"žD>uuH/q8MX{CJ0=YL)3�,j O*oP]Cn%-S΃NlUԂ6UM7]�JdV$AJj4٠cPn3db Q0} 4cO*`2s Y%uTVq@Cfx`AU5 6L< ? U8 C=�`ZunQ ?ٗEmߋ� A�jCzK�z6тfq"F40/z\�% ?{gexwyB݁48HNӷA6#QSPx<v`]bT?`9ַ9ң<&Pwp.MwE빖eh&tDŽ (jbWSqOyy`EkQ!#JT=# a7'<9B-g1!ңIZ~dNq^,[<3DI|L`iR.byi_rS\%M`ElFɎkaU`ދ L>DMH~B"|x3Lk0#mG @d.!upoiVC#kCUۏ 5DD҆lb*<?~;EO=;k`PLMky/0#ôr5Śl~F]GU5�:CBu_] x6xХ)3%z�BR5,8m_FV03c?ǁ#$Xg}x7?0LXL o`4ۀt Cܴm|h8eRy6 Ðjb^RR?LJt9_HUݑ8#`* mUւ3t�S30DIl&)vSܶq7,~5ЦH#j%=GMTkfw>onb[SU38Z B[͍[xh\C@R۔l?<ˁE*'AMn!�SQ#Ӡ7fMX -ӎ6!, y"c%b5a(:\Swb MּY!dD`G<|v2`5xhHN//''D7( [  T%f uYAWaQ0b�䔾g0h8pqH|.!H鴯#TU0t=R4~~xtO7eQlہw Poۺ.!�h\<RU u ׁ C<śrƻ#tjf{t:8Qs!>4yVںF<~CB6A1()f/ꄷdm�XIaVKF9D k폸?D "4u5&oZ7=O4 NŊsӶ4yrZ2W{0Qxx=M/TKp[1l|E5"͂$SuY ƻ=4YiWxК PKe 66WS aCܺ2=:y-ȪX2{7/Ҫ> r!�b1ӖuU0?267g%YÀt&.3'c8PZIT5Yz1pe`'Y}<z%QO1@IӛRmM  :p:AV+z~ 0G DmL]GS"G׺[_36 G9 >vmH$AJsiW"0i`doS)0ÑG0tq:buyˁ# q/V_e+B/"d^9XrI]8rzE=)N{9rmSJV[R]$vmBg76v{qnlֲnoIFSC%;C<]V'@Ԧ&vK <r }bJݖ"M7Ӳ-ċ<-QACޓ;2;8N}|!�Oa^;x'0L6Ǘ^|dW`kOeauy>=S,/ck`-RkvcjͰ,YH<3q6 ¸DE~w&]Ao??.ymؖcVXRv%Y0FPB9m|Yo?.kѮO:ttn>,lxLrRڿ46m$t»6 ~M~\}h<_|ݏDNzred_%MnHW`]H]a(oȖgs0B`R3L0ZHn9a'2: ;f%74YOѩl,m1 � ÇG<-H[QszwjZ-l_)6r*1#X*kiuSLoAqȅ#ZNޮd@<gYM׋$tݤ*my3P7;r1 A�e>dҖ ~MmS_h%(xTfŅ NWԱ) h- 6Mte$|Fy;m]h49}@6cQYz5l'uy U7qĨXVCXr'矾Kjn7 xFDUDs[ئyv Epj NM%aui42xHl1#vS<7uM7w$P]%}0jm2e]W~Fk<< ;qYt& k˷{VH/ے2 m%c뀿�.F>|<H%طo۰V<ulM1@S<u +|R!2oj'hgiKZB �M<n 'jfv.& l8hUW9}/&Y&lw'#_3#JT ".9vm!_^R5lDQ6" l/[?MZR&T*,u 2ACMy~70EYsnbm'_�l}[ptҺ Z-Ʒ;aX .p!=mza\lM yzAѫw#VdQ%͉w].dg'j.stX{ уe<eTJkYL3�XIuC 1 z.(Lјi/ߢ'emUfk0:Zb'Fn#76Vm,f.`Mݎ8H{,-4FJ >.}wn[z2:cZl '`e9_5 G,�ޓ+'-b(&Mhm.Z8YƒNiծv]jWծv]jWծv]jWծv]jWծv]jWծv]jWծv]jWT'o~?csesٟ`M o߲i Kq4x"#WXYSaRJ&y*Z-GouϷ_Z83,SSsN]-wSFEc[[݌ tUe^oҌX:-dI& <G"aQ8EMHX; mg)hn,p## Ӳ*;/Up %Κ"E[nxIEʂq3<-ՁCaS&8ÏA][WY~U>)ͫАM+J+|m21P0tE;_LrX0 k뢨~M4N:2st؁‰ϱK6--11 m903~wel |:F{}i<\gxAuIbǟFvZQAFBs0Ϊnӓ6 (KQPkOc뫫_| (w})(cw'n{Azڢ**a ԄR>֞qsz=ǯGXc#G] 6gqR,^O<wtaDmiL>ٞN}_hr'cuLCЭ0-~헧Z ]w~lvքgYe(nQ`UPO$sE!wkܢL~J}Ty|?g8V2yoRC1gZؔ? >mye 5f]Z"϶>MYLV; %w×Jvp&E#d5v)Opmdy+ғi=6U{QŶrS&}K;gR+<cOk-2%V6,5 m<}m?m7aw1Gb4RM;ikqĉZQo[ 'yI[J3MSYW�p'399A5*&rwjA-_}lay]hɒ >"*%尉MMXDr߶v1B=5-LۍǦ 麺Q$b[X9B3KJMl %<LyweຶzY^\6y6{3V(Jk�zq=n3WW̴q,DK<\q#K Fڸx@}HB~((j ]U'pT8n"- vumab,ɩvWt&U|,ʺ?X�}cfk^Rms DaPn@1ئEDBQnؐ\l?c/J1C+/7 k-4öbU?\>1jri6Q)IQ5~JB!VKrq muyP2 {kf08z/˜azZI,&z'" |+:6a:MʦM-U, Jq0M=`w\Ό;g SO^bn�8"@Ք祬bwi~~z= 6ggo=J͠yw7eqtm\a�JX�7 Ś^$QgXɅ<0`"E @:7s f __-$7<s4rD�)W-GWn"Gl`O8j`Sh4χ:П(a[aD(Ŵ0 vmb@YԠFsv<Bﯮ;UMaWS?=?�cyd(,'^\�,4M?ù]\':i(#jqЂNWkˋ*6X4$Ƃ>ק!QoWDjMp6FX6@`ۺ‹񪗍Ӡ<n ?{7JJQS8pF4 }wL^'p"RƎFmO:uW5VS7Ӽc: Y^|%8gm$O؏C]`S(lcwjChr?f3 7:/8J)7 Վ4@4]n/Pٴ.yDZL ؗna Y\\gђcNMhҜU3i2Ķ3]oo/9륟='OUwCxB oM3 [$dˣ9dѻ�@}zѰtvqOxYgv~m&@I57&O<رc!ɡMLޒϿ{+g ]q?pj}U`ȼAa澦HHJx-5QhF0=ٽQhDr~s{X>|uۗM?~1qi*a_8fַ%V!/ZO/sDL �~*8xOta J0(㴝h<{) (o X:Q1eDb:;%8FS\u]4Nܣ),>]_%M7@SCUa#i+k>6AM-j6 ?EhJ4%hn\z4e|>|KKJacrЍf;6˘Q; k,-7$^ ۱K.Gz !ta$+?>(x3�p^{*<5?Rw,sFXqۥ8J|v$~pدFa'ցɲ{T4Yҝ-z6s 4,/~|%YVԎNz k7WtkK[V 7o-`tyՙo GqR8r-JESSerq"l(k8T{\rêk,M<Gt[}GN08<4eY5R܈Njl8vXW EZƙ;JώhUL'ʲ,;s ov.;A.>IbcdL1,18M~ڪj\Ưi#?!-Fkj-'�^R$~R?MR\|-p]}ihKlM!猪yErcԚUM a^7U>dךVɶŠ|k2{TARMxʎWTY9U,0Mq<x Îeej [| o)+m R,i8e(X~&%38a "S\2y 祳 /ԇ7 3$#Kl~Pta_?Jw\iaCp2ΰ91 M8tu"Yz}#!UtHQnK. =߆D,I$Gh>zy912DrqӎRsZvV y?Ծ" #˸e;6jx|A�;CגqMGN Uh!%_9Js(/>,tYuS<J\g tV7/ z{Ǫ>df>S6v;M5y`[xĵ�$bG黶55ķOXvYV3R5m:#ELj{ã"4݂RM':=V_4kYAY� RDzIiM;_2q M$֤ I dSS*{XIDK~hS~]P$!lK+ޯiVہQVR%rMp(i:&h-YN#&q-[<{v~>|T[t} Y{KO7_/+nLoJc߮)d2dI(; poGK,XհR]˦Lqj ˆC?q&cRŕ#g`oAd掐 t*+Ns@*9 87eRE8<'8ٰ5_e;`3.H d@iMJg&no) # 5_b߀,$ICS3OfgMEZX30z].5~$Y1n2!ZGdP9TFeMNh&Vd�y[rzy{w*@]Gn&0tB(C-]ӸsL=+M}Ff9jMQܜxUQ9 3n`�4 @�IY10A.2tax~x9c]`{[Ğ&[Q V]"EH«cmL|�0U`!0q̆` N[6*~E9(; ˺ "Ħ4PlGA\v }(8ac 8 ȳ '{=Wt/�BIf%t hLPc(Fq`#Aud t Ӫ`)|qZ AaV|� ǫ9p Mo`¤&3OZT]Chr $xٜ%ew�![V䫦 (KMn4Ȗ:o0jT2vEhASq,b2zXZVڌ 7 fV[RpM?9V[|}Hn{%ɥsNL�|.NfIt7 [ey3#J6~Z @w =E۵aV8Bi+_7wke8vusdXk_fOnzJLNCLm/}Ipnu{Z줌͇{-=ѕ/ԙU\C?\\<М qE龩<K!*YQ�?d׬0[ή5jaZDG։ZcltI2'\ Nͱ,/dBT�k8(~eGS4'R7za#8F9-w'^BUsHZ@;LGxZTC_%ӔxM|&$,y`Rk7̇;bp BױL]Ә{ZRlR~9b~:VBd8}br j\NFE5` adD)02M5?+* Nx"I 0@ړhз^_ɻj�u]ykwZCD]]!/ s0l!}&Ɨ0)fN%)3Raw3/Y{^,uw).Ҏ! /ol\c{U\4i uiZljϽpԇgTp" fɹq>aPitϔ(H^5a6} H`Eٲ 4K"})L|yX<rlEՓU \Oʪԅ;A䨇->1Ж@t箲ORnCB)yo]oI@EI n|e8*+(nX^ŧ9J?>e }u:J{n!:6l ۷^Uٱy(I�􌧙3ǔktS`WE;--Q8á87ܨcH,Y1(yl:wmx/uVr)4?sj8k`,HO3QIB yR`oWIX _bɄP >|:@8V- OiVv:FǐX&19S O>=^\ lT<O ,�pOo+[JaSq5AOPd!yEs( !vSl ]O,xJ(@+=q7(5v!AۋJ]ڳd%5L@U=.#J8ΑBSq˶R0e� -J>8MTUvj�(>4;ښX"szC\s^RM*up'@c5s`%, [Ldxk@@t6kwW@p?a_,kʅ_ p >޸X8|]פB鮥v "dV֝NoJ98MA.DD~<MqDY]C*ҕoj L� Tr50Qe2$b H J� n_2(򂂙i, h(tM]TC54M~ˠxRW P1F` tܵe?Ib@)~ziNXiHcm:f{�.=<@cpG,&>{υ `94uU| HkĤXzz�dvXT9&=227ftD q@GmǾLxΥV_cW/kز$kXpx:|:$,@4p7 w&z&?#"vMSlt`XpWUUҧ)Py;b)7e 6 (@}1 `£ ?c[+N0M<XjnEs" *OH1'0ӄݚQtC, DI+z&Gb[N<L4vT1jxY3Z<P:@aIXtɰ[_s �|@`<R,,$^D0xb'F')jE�Lb"w FSR??ޝ^ Z(^5,aդ+x \z1@>MJDM ʚ,z:E8cU9_z_RRu:+$ &~ve#GUy|s}Zw� ps],+"rG 7&`7#7�2? UE+\%d^i,TL7X [s�ST lAdդth􃄡$dOO=pdgo�t2-Y^~|~:mQӡ 4&ylyIp#vF^Rpc8Հ$Oد;{E�A ayu;-CpkGͯ~7_ҽ 9±tױ¥G\m k_~#҆i➔-;_߮@bRg͇ i'aR%)E?y#$&hs q[=ԆD4>h\L9^Dz1=(X1SMP!eӱtf޾ @TCo˜ pN1Sl7De6u@S}I J ́x7.<(Lvxef.wm�ȉ53p'z c"u7xc>[Z ˦rW =wmuu͛A;R8tu (f7S:填8 .?W޷-C~SB`ylxX{ ;Pl#/A}|ρA�0 G7=:ou !AX.CD€ܰdx2G#KbF Ч)uԛqKxEבia7X"ߕoKn2^C'k6O$͉f~ vX*^t7z``_IV᪚q *9#짣Ðۢ@/~a'h)^y&kpssF6Mʰ 2 ,CKv~:>fgb' 0;6,w<{%Vy;.` ELWͯڈdYhr]>pІ V� 8}-'V܁=C `*yw@Ֆۇ/<M<P/\_.j IUl^/",u,|ؑ <y6SumS-D ?fz:V;"#k':t#<2yy&ް4@0ږ@aQz�1xyj1cM�}_?, -m?|@in} p7BiH*Z~)<Ў\92^|~6OT4:p6�ӀvAc1>;_%v86 ĝ#튠XV@kǶ0-q6/k2+XbZa{3q:j,uhwjR; 0`-5XhɢH?@рք[x }ߩL`{`XXʲ1`K)1i( SqaT FpceX /:8♹.o%ߌPI�=0oߘ'9ݿQy@3 Wc(ZXGYEUgwHS�4ػnS 6m@^~wl*gSdT9UNJd`wXzS&ľ?_ƴdXtAXZ 3@'Y_,}U[wOhq 3xo n`-N5 ]woҊ%f*O$*"u 3WK9xx|l=#?Ly ™X{x;hV:[W&wd$@ՁW *W i  j6Ӈf*[;LdYwNG`!V�ǶT;]o>rKAn˩ڷAQmv`ӪAkzqkAd#�,GEiQ]iAT�lV߲ +ir[PUc~u;QV~C,g9Yr,g9Yr,g9Yr,g9Yr,g9Yr,g9Yr,g9Yr, zeGQ7~doؗ-;ɲ7'|e{{Hf3z4ЎY]9uOךmz䋵Rf^ )_4qا}מT%DuL{&lұ=6c-KHeEa=??}:6yyԏDq BB1$ \ eV|`yݴzm"W0^M'D <ϊ<' 6.RxՏKS[fn6>>ڷwu8Qwvd0۝u3몬ǽA9J~-ꦓ OϏCȷ3!Lgk\웶U1,]IҢjØ{YzpGԆL8/ &9#4yy4{laDƕ;#O7%zpۿȖm6ǟ ?vB˺I>M{f^ovحxQc[ (jn$n3OkWL(뎏Ǿ.B7mM]iXt<=={p:Ewy{1c\?ެPD[^.oW;^$IiHWդ ɱ^vӯp_?2 Bָa޵d?ٰCoW//q|Yn6;á2SgEYrVz|~~ڛeyq6 MĵAZŒןg \\ 5q Oy3tTaKX+9tխIbrU:o0 kn9 m7cl׃e3S|EhDRr_[uJ_~(+"+BzO$,}u^h0Ǯ_oh5hƾS!wjX9MkBקN=Sܸ"CsC񵢌e/Lc*%+\U -L a;Mdӯv p<@k3.}ޛazIE^vTTY5/ko8/^{,Kfs_ׂ}W�=~"3}%AȈs2#u8&иn!zqfjIF}9RQ Z4²ݡCKW؏A"$r S=mõð+Ɓ*/'dْx8_wgzx0/(vT㾩 ;?"]gtw)Y`ߗYVԣb;gTVO}< 1}z^ f{9BQ$M�eԙC Юr6#&ZL۱tx7Ol,QrL4qT-n'Kgz.|?TG"bQͽtd9S&7 %$dzbͨ^rZPXPIH (d+#*aE^6Hǀp]CM(.m(0r(eJl! D0StWUS65-.~TB�G,1(*؎FT]9d;6K |GEEClyIU,.9wj{=9cH*vUiIZ:ld3gk2]cvMPnɰm2?�x=Owo,Gmзkc6z~RQ(+*CZ=CQvܑfr9f7\M㮾NQVPwPl`]p�~x2xL2uUN)%oԂVܬmRϵt7*[ef†*DI5!qi/6 #k8F*ZqHð0<KIӶN\bX 0(5y"UQ˅U�:!Ć@ٓyK7UlT~a,}UfIZm<DZ)4DưߥO_HA1/$xxs6q-*I1^ u_Uݖ YCJ۾NIJAV$ctz%dYXEIn Ӑ<Gi)rN붟5-?‘>UيԘ_S_p&8f5ƨi1(/E7]?.ڮJ Ehcy9v}x# S0DǪx[t':,ur2(X|1IjC0xOW?!5%Pd8D uy`KR^2©V x6֨6:9Q;lceC-=$ĵ W58x0o( Mj<NOUMTG|8 $}eroQc*r>R1<v(χ2lG,.9%3А ||\VN93pE+[RV}=kK&3$^No~ݥ#DF0q?jf"$r%'1!? !ɐA֙+@)G`EUU U^/g`oPc�#jPîʦǩfQ�EQYFpdS} ȊxlQa϶c~ W8~(vQX"EJ]6E đS٢o[;(c`^�Ə] NZ0qÑk<|eQZ> aiCZ62.!9Qr?&u5v#[I+<KyzgY: |Ԁn U[*48л. qıYp_Dնcig2 5QVĎ]tmdv{ r!"xb$3߶][Uo!2 X TicYz"+/D'<l!xG0 7(̵޽@VPaW6J)Pp\ i!$-4r,~zdy *}w&@? ~JeȫHӕȚV0 �?kijӒ[dN@Q4*O犌sUU:? 9ή9� &�֏3ޖ-Z0 w/CqV4-^?n[:}}W<(k%"AObGiz ֮F m�d9N\f",KWnwo_-x0M]%̽Ck,(Maي\)نBܐ۠<0@HQٔ(;b%n)i2NO֢C4|U\|~d 7n1KrA̳0=(,�?Q%MldU'l"ϲ(�{)d$SQm}u;nFY:Qx^V5EdK~ny`8FP(e ?zNs"K*SATG\:#p4v;1 Z$K gLC sfquC󼸸'YbQ5<0~m)mX k5u?xc޽@X"   քQT VQ"Cӗ9IEQZ0je;"xoԚQLQ&) IFnL DqEI|) /ܶ|x\,g_q26- /^6b;9=<<[iF@m3Uދhc/ϲE4 `kP'Ak0z#LÊu⣺;&D[PŁ <GPQ|L$ F743 ,X=QǪʯf%>^3̯ VTQwҘ׷m2^.f N3@;[ B㚓TÆcD69=H 0jȋo[xHQ}DR}[�@8/1`�|'M�yci`1k@]Vkfe\MBߎcRꀤ릆Cj-J|ˋ&swt�UPi9ƌ1v ]$/.PldHnFzGc}]`ؿix) " e r*SގNoX ;:{&<nqIF"#FH,1;`u@&Brmئu&uulSe#Q7!Z Q;>T7�JՁz>}\Ǎ?x_Cy%놡oRueX^/f+It~]ǹ2GŜ2$P%p'q- <;DWMRCXĞ-!6jvF3)A ZͶ tǘC ^I-%9IuϷEvP*m_gq;:O;W!%0r<YÍ 53,-cӅ%:T!KOsjlH, ܾ;dU,iO ne%v1(W9)𠷐31y!$PP=G\]Nkvc/ wU꛲ B|eeq7EpH 7i� 00gf:&8FZ`篗_xXnBT�C]g섈d\K;M}O\+T dH^=?B#2SX7'+׫O,;F2fa/c_O7 le�Iwo8Sn5cUf¸#{=|07 q/Oa`wcbu)bXô$gJx@߽B{tSCQ^78c(tE14K\~<DUwF3E�>j"^mY e2I~�er?=s�op M2ZPO5+Z11ceK[e)DaJNR5EdQӷ`^_.U{K[}CE$sb `$lC1Dq L$JR0M"!4;ގ͌ (TzX|=ŽG3qK""3ϴ麞׸Ja!no]Uՠ�s?Lx'brӧ+GYۏ 3H6-uiZ^VP<oZ82E HqCueX ݰlSԠŭ%:pgr۵u]~OK덤QZUvaV!vQTaU]O_Ain <cɂ:ӎ)o1[ӘgokEō@+##Q{4 m\Z} uM FUc:wǁFZƮPvqT#*@|b߽aG z~\hJ9tk $ ,sOrm )MVf7$mhc[WALn40[~B iAIy7p{}K\9<EAKz'h b4O�h)<<*3dAퟗ?"/,pB]5/�M=Ԙ3nf+V5,Ƕh~�?*�%3:t`)3{Uu:N橭H)ŋ"O?m$8+yAzdhoU>W9˦I)Ir97�4`J E~W E8 tmVOߦhc8C`71d�ѷ Mb9 WU�w8x3VsiH>+RdouD^ /\M9wQ+ j�44�uk<K6˧E4e9Ii$$9VlYf:~륱 rq.(*LDIVu7K!7F8B"f:Hc'9@Z03չaBP +JquX*N)ۿ>s-@.e%!E1F5%;N: <˲n zbk,EAs$r|#kVPotL&\[8[+ȫPK>n4iY5Fe3A(=K rj_NY/ QgR5'P؊4ʃZU[)aK1A]R@',ٰr]Y64�+lQq]lf#;GB0πN[ acoBK}ҭE"t4W=xZN d8FxWz:+}ڑr5 W\ױ,/ZߔfsrbCĶS[ǧW@80fi,m;jnxD̷ߵ@Z\y_><W#gYs8^֏[@�Puw{q5EJn1֖"kYB!mڮ&8 &. 퇗C@cYg�%}]V헫3$t !3! $ wMP4 X_^^ 0M08aNSݗْX*p@tT69F`~9_ Sp 6ݟ\�|߳tО6@ױa`$6 [ q||vƶS7ӕ[~OLq(P?x 7uY _58o˼25G[$%- =)`O+<GP8u0OB- zғ :T`ML!!mg^�d8o<`K^VL?kq6DJ0,Haw"[HHx䴇FXÇt~�_^VgL t B�xr3\"> nF�fL=8Ys<{#E д)KZGKDݶ[Qc�ۿ6-M!Yp~r]ubHGX^`V-7,m3�~tGKrl4ϮgˍkGsG87qÎ0[�"'~9Vd��`rښ (.`sTXȁxB$ .ȵR+Q8^= 1@�x�+/9U `+NFq q*(j۔YXX6 '(<JKaqRb?XzRCOAUq>lC˺c)OFlu7<'M?I"[mhK[$6Dд P+fC{_e(,qQ)_^wE#�&`HM>m`*f'tEQ\l^~pf%>mq77,VM7^__*WDPu]} ;TfdӃ4Kq&:WKl׮D>֋5+X .<.9 @iS K<1Whe|Q|bPSZe�RWA:yCCfhh�mr[cbɠ K^ 3vbZЩO0a�hXaY.^Q)8zEzcz؆f0.yY7"]٦! ǩ%E89ge%As~<TI.n7[CV jf x�d(utEXjx#`n~Y8�lKcٰmw�ΞǮ&wjE{^ۺJ#s ݐ{lE0 ;᙭jiiUWu;__ZZs\ m 6?dGg'۶̒0mGm}G AM-/C[m3gX巋5Iq#a7%lW}L?o"r-Z&"lx1K=nӠ5Ǒ3Sɫ?4%6}f?DZVJww#[WuL~v/杭)KJwGbl}.VlVápЋϏfimFADlZt45U WxdMMq?,7O1"L%f lM/܁l6zv{m Vw2PCe5)Pr4MF]k 'r̆"VO]h4Ix; }U:rtCL6a:Qyigk<M3@WrS8ON*im̚T r}iCЅȸ�}<�7j�^ -`%�6i2I5\T8:ϛqdVö-FTa#C+V~=Cn@VJA951L}ZNǠ%xׯf|5 IW xq%.(vӦ h7a馝v[\|"0=e&SreA01 j=:&>TM~\B<F#CGXRv�q-6j qKGim1UƎV%jR-CY\LH py_2_k7X Фr6[53Tn&°Sdž`e5A7uܥ`&Ci0.! t^zyA`ߠTۚqw%ˮ6@Y<VQ1OpIn^e^M0x��CߖifyU1�G9561؎^UQm׺g xأ5dc8/.XQ5uYYY毕(&&4�CDϯfY@b| h4`lA2`6 mYMi3�ƮfW~aT5;=7rxbbIbx ;�znG>7_ O׵@϶1M t&3sK'MĦצa9| 5^m4Oi6v#'3*.Bivlg;vlg;vlg;vlg;vlg;vlg;vlg;vhQTԏ›X/ o^GBbs]۲Ea;xOLOrd pn,{Kg)TqB0"C?e"9NXEy<E#'Mm/$KtI~ /_ nl&:a u]f=7Ң(!3uEī -^u!đo_%g�(2ݡnm3-][ʖ&}<(WƾkZ7<hxRQM]8QGKU M׼qo_w->LR׵:ί4d|Asg(VE=te&i q[vc턲0k)S|_,F[?~mDU7L7$KGuH|S Q uvM(A7qOx '}W|׫ۇيddöm a?][vPHsG ]#_ۥx|zs3 AߣN_N4n{}}=yv a7?|śxtqޫ.O[xHÏw̨EWOf%CnՂwAy2tdr)a7)er9,dȫ?TrXh~2/3x8lwtnzy;3ổXlH;Y(/wR~Khozϟ,\8tEF#K]ir$, \zCz CVHF{f;"إӧN e{u&9aeWwئz?qŁf$0wC[X 'q6[_?5SDbX̞D;rWݢF]N Y78FV5]<$˷db$%+h0<"t4")^%::s-dbiB4t]SNT(qfMWn->eX]$;4%> b ǻRyh2b�Rwhd(]0VC 0B- U' tfꚡIF(dŰ}HY^r|Cy .MM<^:phrx=ʑx^Շsnfy:On`ja"XOmwbQĹnJ1J Uxip3qL @m͖*K f6]W8Nm%`8J,1|RQg(=ˉ2OWɌbxxþWu/.D$N"͒)@$ѫłTQ oi>nWnԶԒɌ`hf^pχcIUgY~yMhbCːv~VJTx~@.0Y&W9yIսi 592:UUEC.Q4+k k8Ilhn@bxiYz�{oq@ X#Wrsrh-hvT,/+c37s/!@n_UM=UY}"^T@LC,,ruv1Ix7fC5F4mSmKNaFha9J]Lּ I_Pxސj7rB *.L9mĵu6`w@ C*g 3\N(^%-j_~{n|ސ nY̬ւ<넹 { HB M;Q*Qo!5:m0l! C" 8 h ,zVXuU]: MɊ=I_m3}6[B~Mu][9-5aPMyz3X Aq�t/j`% Ф眦nT`|bZ._Q$+V{ͩQH"<bS<[6SpâۚjڧԢPXNՁAKҲWlEEo_>:L'ɡCT9!H5u _pU]tdRK 7UjF&U&ت㝬;IVÇ JP[Ե9&ms[%N ECӬc {a3  \ȫ[^PEcԟ9@0cf688=u N3;ԥDBԔ[ϑg կQ-Ǩ` @64Yǟo$VR:3ʕ85~~sDV(!9˳4'LáQ H(ICT5gK嫤[Ion@Q|Ć0,KSjغ YNOiU3�e!7OaԀ-UGD,5p-6߶fbw'Jh 3NP7$ݤ¼/bee ~ܸyd\<p/^n; 搦*!/,:iTy>\ Т~!O5o 1(`;-R T^ʹu$ѭQ$X8bΡq߷uU5Mo4/-<K 5b~7̓98@!YZdeL͠kgYuPQ ibȇo4/ķOχ 8}b3%JDd ɓb%ـGY^XE=2S,h�r% ٷ1%н$r/8JIm +00=$laDRdհ0PůA5hyez(t("`BCSַ ApƧT 7i@v"M|K\]N7hCt@ڪ$SYMso(چI^uz:m(mӧZ0Ӧp\qT<ViC׶44u#,I<tYRaњ &i(( ]/\C* 9+ P#ol=guLX0u(E:j\Anӡ>JR d 0XQG�Ը-,˽a\TuuOJX°$9dmG;[BUفo(<è-R* 2,'AHR%2`[6M]Ytm@9IV-<!Kr=b5ps"5KB!ZW$@]ݨtfxVT!ka.-)AtBG4A-LD}}a 4 _~/_?xAWkrun�RQ2 jo5C LnV+DQ&{.djL]ۀM 3zx_~aQ 2^Rp+ũ-VCIuSo|RDJ?EouBUX&W~O_PJQk@3Jw;tP0MdP!Pb߲7/0.;�‡8b ?u̮.? CT~vB8 wE8O3,YѪd]�̱޺[㖘r'z~pmz[( /w_tʖɑZoxIua;df+:\S7l\ �[g:m* ޲GP_vt_FA/~Hf*L` 7m{Pb[CVDYɇhIޛ9forMAiƠFabN_}HIjnHHwxEnYs,P'* `b&1]ʦqe#Htf8}Dq%Ђ)[ Rz3ET,%dͿ2I SuThOZ0mzkOC x!vUh-R?\kN7uۗό)FP p=i'�:Ǐ9a(<uq7[CeÛ4M]7+J; hJ5 ߓħoz&6%#A5 o ?\UyDop4LQެAcJ}| -ٶJczLy"an2<K>'�`ۑ7i8dY=1̐VE„f_"`:4�QgYU-܎A ݬ +@\X {FLcF4 u"@i,pNC5dzz{D*o47(fl۱Kӗ0 pXQ8tI\N0^GYIdҤAq2%<v X>lxqVur׺,Q Tbф\( <xuq}u5#{V# ,<b�P8@*L<ͷ5'2jG͸8Էcn:й03O_/>%5 RDٿj\ k&gli}ixQZKQ "\ãqnOaYfsï7^3#~ڙTcB:&^eY9R*:Q)3mюYٚZ.Ų/b(�vX{͙olIEjzKY9q~7)T<G,=&)qIsx>\Ζ v: v.r)@#=Q)7;6$MS u\'6ž"1H_CDe+8LraE *ø0 N7eM15<yXaVf5T]u0r[)vc c +C,\^|P}0 c%P0"TeMddIb.6*⾽ŴzJ圇|&JX1vmm DXB fa ~bc `Ryo+O[l z1q;,JR!^,]#Wt2HҢB}NWP|rOG!S`^d݅1䥑t; a7⵾{{ c+F$! ?%ew~rW< }qÞh+oطu fIlenGT<cY;&atR_Erk’d݄wGF!m 9:IJ&ms$YM4~ZI 4*FP5N|+uI%aqNHE88oq^VFo):g� ,,7�aץ.SkUrKD~0`'g"D\Vl35k~�i?^Ep db ƞa:{)F:_<'TvwQR\ǧ9 ZdO㣁]10t\R�nXrwO1ԔaiS)5復O Sj*\G?}<G-?|]ʒlV*R5q:'Y)[<=QPa\`05�' T@ܙ; 'ܬ>.7-ԃ,/!v4(Fq$|;Q7:0)2F5WDQYt-nKSej~}K ,l"n56UI !NxʑB4`0L}>LLxXn:%U[:Q0V$(qԡT~5HpAۚ"+"G 'yU7y9'=C i~#a6ER1/]xq HbsFQMpɲ0ex"C3ߵ pzVU,"ă/f/(.Zlt 5nrזIJzLxCxwq<HA!+ Q�<A'm]rSZeuUElaWxhV2:4T\$IZ\?q z?l ;Kl#mH}4Ov>`s-'Nz<=-n? U�$roP ?iuz+.nacA[fiy[9 B�t[=(̙kR݊a]ߤq}H7SGܿh]C2j{WFf�*R')aہ` mev<nAH�67.kVϘeٍ[8+�8 㘧>Һ&VxV+ =?`/+cV�L?\ݒd~M56 \0ɫoi'y5З]j)2-(v܍ѩ?rcx̥%*`Js}ᨢfiUó:uAR?;�fji,8. ^4"*7 Kf6qWh* VcnIn̙S5d<Emiꖗ!w-�u.͇[m q)+kxCP:71@�vcV,ۇO^MwSԀiaяXmr3RPsr U7hëka&F-8 ҲÐiBuk=V)#:`~ &)g`e+Z+ЅTDx´1E\K%Yӂ>,TUG l{!QRpqkHBFp0;m90zp,U r$3L6=P8x7�"w1B,v "ezX`^?upj"ݕgj=)_pر/£t8l!"͌&!8jdcTvJ@FpCo_`R~) ]SnC"]zN?- $@v}]5nCCf\\ǵCEĆhㆱg<Drjn'VQݹ/]( H5qjPFa�DL nz9(9 K&cr`^# ]h G6x9K" ԛ UYwi0ybIQhqv[]~GS丕RC?-X4n̆stAVۍl0DHG#o&W4aw PSpNgZڽ|U(8"0 k€�zWPv$�\}~I ZĞH+հ�+)ej%o[>.)8A?6I_U^7 ?<2ēַ7/_�*0IquCx\>38}Ͽ,n.pu͊f%ĚT+ĖgSFՀ_@.8tiO_~RP-rKL>X8/vQ9 N&mKIRߎg2 S%oxẦwBR5'u'stWQ$ٶ\S-Uᡨ4!ij8$3S = lgALx:}طFaiQۮ: w(7 CA>�v'͗'Ɉ<ؗiƞ^\G}<*dx&b1쨭m#zOYsdi7ߞ]>ٯvx�u,UL6jȻGxH^^@G:֢i̯*; b2S> �@?Oki)<޲뚺pI(VgqX>eL:2@Ub 4Wۿ@!p۪q;)q_[ J[▮ N"*{߹ 0yWg@l;<t,EZ8_?.iIu;-/Gt{U6O@SAByϋ^;t 7m�gnn-CxM+3<_g <;NTgF`l2KRGz3Tva p ,.x 'q"`r&e4*œVO]C$Wkx١cM!O;^3l?׬D>0ߓG Zs&rEx?v\T(Y7xWy#Rדe+A?r7&32dWdv]x�Y'[q*�C esM$ᏺӈ7dGދBᡒ]UC&ue1!g-<F_aCX 9`= .Mm[#!+9:hlB ^>.{FNE-.(daھ s_rK&yfbX@GxRFbk6\Så {GvZ]W(pl(JHdVTcW&2?~?V^k1a6_1&eWGjQ39k8i&'IrHTMu m1Y*=nLKlu/\̸?8۲.q * N[t NA5 q^Y`Y- D`S/�$p*J<6k85ϛBG>Lw42L^Iw\ᶨ Ku vL'uW/ׯbqVH,ގwY$]]dҚãp$pm<hQ)e7l-^ L0tn Mm^"i?6ȱܼ nx~Vj2nu4 H0zu7i;o=G>ԄqCzo5fvlg;vlg;vlg;vlg;vlg;vlg;vlg;'p`5PԲk^ e5[eUkQo"莋"׾fד3a4q p 4K0xu2t-ؙ,C l \wuO[pmnU'y"!k>xӱm׏zԾ̛N5$'v~l]yaimH! uMeyj,oi{yx9uo"\xk)6aS,mеk蚦lfaEwx9tn(<m5vd#(혶Q^]͗o[^(jG|W<)vS]Wgˍj:Q==*~W6,s}WWi`tCk%8ux^\zTtP&$/r˫_ogO-R#5^rZt,v +X_,Wb/7n׊.T`K^RTIz(ݧ˵kqk@jFQa/׳b<«d ///ϻJ<]_f2(aNKR5u]ѝ(Ti͡R'{߹Wv\gן, @9C'ӻ`+]˶$6KVSj*J<C&*dFTp߿,bO q`o-X_xujC^6oJq%DO9%9~@D,V$`'EkN8U] ]W%iDծO< @ո ]^p(* bQBE(EyIp~Im]Ig�]b¹(nI6AuQ`#݀oƁQ5|۪Vů֬Yr:%&<꥟/P\ �a\TUbamwc\,@80uex= F5aÙ./e4mij}7_pf4[u2[amR6P9\�pa9XrOf÷ebi0ӎ:XinP]rNiɒ&~/YQ6'@ Q(tU $N<MxYI1Hy >PŎRCWYZPy#5I$ҫla uP lWMfn=q4Z4>ĢACW̰l� 3d]di&Xqv㶌l* H9ES{،/CС}aV摩QO??[TaKitɩ|גwE()݊$Bm1 � C_w"GrTϮz:~*5^XA)ԄijLa7}۠\`:^|#?S<#䑧 ׫O/\+F+':q-D!m!KۮL}n`dIt?MY"^iԒ `iﳚm" 5fq{C-Z;Xѱp+D Cr&~rA隇zn;H4P0{RqA3jjUbGc)jCP*2;@ á k\P]Hw#jl}= z$7$)$[fzySyv9 iq3F+M~<y2dՋ0ѻVl%c֓ X^V!'E< a9dM�9dqԨ:G C//&e]+ҐQi ʿ!C]LYO̒dl:nY"ɠK*f _%}jOUTUJK?z/ �k[I"dԠ]Wi�~#X~ҥpȝnEC9Yinw@`g&@/!#8NuP~}aZ:55JIua ҂U 'uFvTIFa’ *{ keX~֎n;ӣ| J!*$)qZ84'w*na ë4]XlEdO,at/yt47* ;M,c%P /GrТXf_Y Pv(ceA y&5o@J@|mJ E�P;,<pmM=!^(T!E3be+ŭ�Wz($r ߓiQFilXvw*聯5j[?M`T<4+Ha ge4. ۉ8G 42^v-Q ,Lt?/1ا9NPUR_]5.@ԼDm `>QOA9)m:a۷lVN 3]߱9ZOznę Gy'NSe^YqVOUၤyh+$kX6l[9lud2DZ0CPrK1OJgP+TKV7 ^9ɩjGzGA>vٳC_^6�) Ȁb{<h Eӣ|ꛛfIAIz蛮eNuxpG*ta1mz.;e$ˢ"ϓdި]\:T,Yм HPFIiqý qEQn{RO"T7E,.X63bH'P_Xv#})S1N< Kuip"E9rbӳ _LSWr#Z7J66Q(|HiSC9ˍjȡQUPq%xr9~bψ& C2Lԣ(,TEb]ˉBC$-)S,B$ӧۛgi6'9fA|~?*�)e9^P|S/$ϑ4D?d �_ݴ<x~ AB=F,]y`K p1o.*y \<</V˫X&֌2Mҡ-@(ߙќ< :~ִm7bQ%M= bDC gxل6Oww?$MH2Q{b۴G b $'l>%yTdIeBxSC WӇ߭EU~7*:lH37YAO]XqHݪ"�|,QŃ.':z2 Y;|�:q$ɉ%G]wM!v\7Yx'iVV(ʪӷ-CnHhaۄ*\AVrE Jm6%PQpJWEFnjDe37\o6{%L2cŸը Æ;xPOׁ۾!z@V\U8T~=e)jmjitJ՗?}bd FWwD~BB7N&$jT0,`|MFxJ�!,]W#uȃӗ4"Y冗K˰ERǼPN*Gr⼅R No0Lcd/x  IX]vvKV-]X(^w--,kjge]Vng8K3n3X �Y ^ O Nb?|baU@^6܇|;Pt*/sOs^kZ×۵bxŰ H(.|K NCHmb?}%Q�y?.~xTL?-_jI}!CH˧M[<8RX`e%j\W\<*U;x4 85َr؏xLoDdvr}ܰ|['NjK1GcTw�+Uj6_4M|A\~Ru=:=q?M%Nrk7OQIbzq%:Q72 =_0tyE?}yҊaxaxoR Ƌc4kSlz m@z2[H0e-t=(CSaj~RMʸPh6k-Xk:Ai$y +W %_[[*=_(ˋOy|(M?u\~Al,uaA˳ +EdQbtPlBl�Ѩm`l@ʫ|͊xzwMJ�a+΃GY3{Tѡ<i=pN_1߼K�JtmTM"яDFqnC1GtO {N3Rdq<J{'hQ"�&>sԀ|.f0m0@M5"Xqu#,<r6t#7cws#)V` +ȐP_#>ZZtDm p7]ĆZf)׍'lM3 ~8K#m1N+>HҢHGq=@FDXB`ꦅ9Ȼ9(4cp%/gRl,2„Ҍv#ܾS;N(CK7)laZ #Jx7f@yud:sW-YQѭ ͜韮XpH^&Wq;β8UL >!_q+Ct)qpŲY@x^T6C\ :꾚*1gIMٿC )aFi;&>S6p*0(UQ CHulku#E>vtv6g )`**ç| �w4q!K<E�iO/ 4?DxSWy6m$P?L挤ҼNhtHDTpi;<d?IQnjN^m4ؽ&ޡuAݧ )\Ӓ e\J*VH{g*PDo>MA{iD=~z2lh"Kwc [_S tUb?}}Xj5yɆv8׵M~DiCe%i繧醤%Y K`z>�r\3c$R&>^_>ΦO_>MVl7gWj 5[pْ̓ }ﻹ_؂f96B6,]\E E> p8̧;i9u �nE�j<%xp9J"3N rAOUYecJ5 b}D9IT0vrGyARx5wL#+Z1xx•bP G}Q)ڰa< mm2"mIgwO.˺n,x?�f'г-*]8ՕX>ɫxD46yteXZɀfLm(93UB` aMam愰1jqB "J7Uѧ-rđ ]]Aq8!~lcٽPUxnQ{.jo'X5Ykbf5iu9} +=n1H(, y~~4+̑Dc@!0#˚%@9MU[ ۿ%OCU2g˴f-6րD%a<F]UBa7(OPOo>�'<rMm�؊|^73$EpC HH_VdPdNM"9\C!:dJn$[@=C9I5Gcy-^?z|kROIfQ�K{h\C^<fi{=>Mo}(^dDU ZB<s o90 ifjJp`/PM6ry嗛)Asmxh�QiPJ4+haTi͛E; XAIR6%Dg⨲e:nPZ@P[DAhZ~ xڶO`,JZv#b 8iv/6Z'6#,a#n� QcԎó_ .yg^I  �c%e7Kn>HՆ* LH-{ZF?uy;n5/riejh+C'Ui;/|zd3a׶L ?jz 7 mr^.7xC`�CǠxhܔ1|(6!LچjCb!v7 rA) TW�4~;;~E+`JhDRuE �eDq[T<tte}Dۗ�Ǟ{r9W[Hx� }BLi�UP&2b !W}y$˻ -[a6}y3a` ֍)"9.02�!!CjIb%LwCxf/B)%eKr8 yCN_P H;�tM,f:�u/�ݛrn>o;_$v�QP%br@0P[4Q`  ḙaM _5˅�۹VL}D </J|VsפrXX J2 ,, ]I/ 5//RWwlq?^mhr}n&+Fv;|iY:-7@n"Z OFyIj3n P:\dy?}~3I`>8m*R5,'bKUl4blY(fC3"+< v *5|񚪻I v\j#XX?zCǿm4$SG-񣈐}_Ty}`/< fx1y"vF^l+f.Iag)Hu`Aћ5AKzd{ߥ.^/DM彩.rE ([qMLlay[/(ra�oy9P!׳ z-JuG Q+Rl: �"7o(ic4ٲ(͠}9k D\tQmFPTV8@].HhwZPɢ Iba9]7ѱ0ǣ*%KBu8kKW_.Q6ƫe �,MQ iQ8ŷ8'f=/_Ã2L�:UaG;J3#R�z.CVPCy`4V@T\P'+:]�/3y#{>{ݱXZG<Ajc<uUA!pN~ovu 9׫9+iV?|:F—u-d' 4RI=K+3Wnw04 ; Fڰ<_[עnh{lM1t;d-cG&uuɛ{}-rʯc׌-5J.-n، {_4 :m8`�Zq^^^|yiCG&VoE`e: X*6}ֽl@N/#&nC�ƾ_ƎSuue<|=lub˄@R�(j+H~� ܉ 8c*W2]X�B%ISS-a Wku"ճQw"V{bu RJ"ϱzK$8\, 22O'(z{f5Ez5a&Xo@ E te^[Y$XP/xi|><=m4.BSO=DjfYMr-Wz d�+A'BIݐZ2oPJ4C?Qwr Cm>6 (ㅠdBA�?`b3k$4%揇/<J⹣ oZ;#$Ӷ/SieЦ VY9�iX7/m+eӴmc=^ MfEY$xInd$+vUPlxJT-G.}p&FҢ h"VfA$i7Ml.kKϔV9I/{,ۘpM+k8Ni㯌7[aFr\R"b85gLAѓ~cK~c!F,8Lr]=7 O?vlg;vlg;vlg;vlg;vlg;vlg;vlg;A܀(p\2MJ(Jacd ul{Zm<׵~?/xi-?5(&7|t9 3ԓ-^&8 ҺL8`ik u8âm3,p}!nwCIi./hEA@Ua!*0^]^_5 K|?kz»A?rIɰ=?,|۰~E̐_x ˡ ܰj#Gﰂ8 \Gbt] q.^}Cwqy(n2O>tx%n\שH +POV>mRחsr~wئATl)=M'V_glE 3v94TwUeo?<ÐysԌ,p5 j~ӧ'BY U rE^mۮӲPR#o~~!L44՗ǵ۾|]8vд(kjF~"ttq}sّHh k)?O ]@rQ,bwf7 ߡ.l&SDD7-/Q 9!Yfm[e0E/nXmb:y~^h Q<7Pl%ڲMER-@IV7n<=3?8q uXq5h'Ǟ9ߺҰDgYU\ 8@5.yr|H)8{p@JC[Wdkm+J̳sNQvp~KP!]|pU/Lo.M&4V`;㸒,-==( HB(_޻2�7"6Ӷ iϩ@2ލC:H n:3 ϒ,MK/K5χn_Zl2'Ӆ*tj<$̋2𧤨W+ɍҺkBSy  AȻ/rDݨm Uq%5YP!J :^^^~\G~hs_bE7d vf ˧9q(0}׼j)ZLR&KR30zyrmXm;oE~0ي5]V vr2zb &=}Fҗ0[֋CGNs2OPCLK%T [p_ʷñ+°m1Q9g^oy\f| =?P)*W$3cM2\Sfhzinqu+]4\-9Đ b: X4 ӦO,Mu/7 +ޭđā fkokȁ0+SRdY:d[YܥJf(',gu0*Mʚ/ =E&>,E쟿-uZ^Zyy^p'xɯaA53 2koV_껺(< 0uYijIbPs&|m P[Jߚ~|ZmSkwRWM:k7D@1ueՠļKg 'A`$<:.ƛi, ,\2wZר]04e.PˇZrQ 0l'@jCB|4c#ּ�?mZ�He-kkv˩ sQ;m p9zTXMm^4+VB-nTsGXI-&YZo:?F_Uba: %ALSC 2<| B.Emk(l>$^M/iV cFQ߾)$EgbGi]@l~k(p\v(4ھ2ybM2$ǻOnYYSez~ s\XU0Y,D3G`RrN3lSeW[bI-` qUYV5]ryUUk$ɇ1)Q0JndI`Z42D"6^|" $W]/u'Q/n![mSSD)�{ T!*vrvVE̟VaI@vt*ẗ́P�9F=պPk,,p4Y^L`y@()(8JÎOiIixߒ:٭k\ /6-]@:v�]u{NQ$Wt˃{T=!nE2OoNkV4H]Zj*) ϰQ{7&8GU�'n xf>B0C.3Ė�SDY0faDz&"LP�d>8|ErԮ�U@ez@mqLm>eݴEdjIIPǶM*9uy1K׋ˉdxqgV# =rvB*ط9ÂN"cinR}42"Q|Pxj1R,3} -!Tۆ1u~3fEUQ �J4ݶ2hP0`MsخٽƗXjq!/88/o9~~9ܷ-kGͮArIo5Mմ 6(WkWf[^|k3 h+E]WՕ/Q՚UI\mE0Uu>r> lh !o4MzYa7D5߈e 9JIxzXmhūF2DgPԴUyQ bo)5aw_3vǺ Y^t:{zoۦ~i(֕̕jodTe#t@~ Ż+G)DTa;@]qVʆiosy݂3ef'}(pIz#ȣ,S+N 9 ۄ&ŀ EHAA/+NHU?E1bEya~?#VSˡX^ B<SdAXKG-IQ`.ae (EQ5 vx\' l9{ Lʺ24ץ1P{[ K04Ű,˱4P]-\oPT;ʲ! 0mF M8(D(&7 `'Q$/ ]?-'zxeI;-sNTgXI X nW8( FxQe`z ZlY.#]H\|O?>?IQEEEW75 z (Ҽ()Qv?V4*AQM?- @*ơFAUbx\O~nҢc;d@5k| W gh&H-{JT A5Ct-P?Xڊ�,K>]%(aG^ Z۔ PB:hnky*r*^fyM? t=:<5G`㏟h zK G9 #jǥH~n@OP)n֏ʘpUGML]!?b%Ej ?J'UxSaz:Pe <X (c6}xlZ`k I[7 ݒk#"g�3eL4` Z6,l7'u`mF3~\#\3 =tr@a+27w&{n-?J vL A3!N4 fC, -Øik[TU +?~Efpv(q.B !0 %+k"0-ԇzXHɄt> tK^n���%Q!Jlyv=p9M"PUTCc鐙b :64m|Z PVPx7Edta4c8@Uf?~Z ,2Ѩ7,i$?nC0j8o'{](Cc-t<Z'w-O^Wz}c  �Tq,0U5UiI` َݘ qIH3<D88Ը%Wīo }z| nDXK@\.ߙ-.Jx%~LcNĄOl!:1Ha)|^ag@s+p`n%(K-i4_ X|}LˍqF_@V<=q[lb@3t y,T7m_$iXN_i@kc2T^_<KO0kr׬j^�Q@]tA*,/ʚ]7Vv^Gy{?|nF E3`vmMjB1cs 0r'&+$>SY<nk}#(<#!"$j9ʭ&5aK4k^=a p^V?ޯ2):ϾRj 8C[zs@yY +$o]{OT) X cPi:P\׉u5/79)ӻ?.vkS*NA^IjD':ݏ<-L.[:LIAW̰!N.x4uyǨ׬r]+\9ʇu _eB7ækBǒ,TFx"`'_Pߐw7+>B~`~YjT=[nT,MCKU6_o4fwf-yx], )Sopnq?\K!c/K]d:m\44iu3%cmIZr!I=w4PuئUAp k�ŀt(3OXիFzߏ9_Qerdh(yI% 'qaRtA08 h)o0cc k,Cï E,FԜ Bk+|ںEI^U4[�`$8U|Gz7 vU`#a8`3ya9XѢf ͘2ȢkJhQ'�}oWV8*Fǵj(~sa Ps/[POfi廏LnBa6? ޶t JF4- rX.SK\M=]oyJqZ:XQo>|/n'sNPtIкy<k$r4 :4o4#h^BX18-.( [0Be;n�/zu><>]NiVjlu58+P+v8g6خzމjat EYx(cPFr,GS#r<GL}! ~>eWYPk t A\d[׷ nu $+UKF >aL] ɂj;yᑔ5]YQQ4+!8`V/2{f؞uӁ)F֗) Yq7nKOObw?-xU3B%G;>H7nYP�i2j.:ne}ۦ@Va~<PW,F X\ȣ!R߳5Mjl1,:ܴN㾍 c})6vkɤlwWi$ Nќ(ԔX<Еb/DU8$]H'<9б iYo*l͸aF9&�15+̫_+BCUÍ4`G]V*;԰qCYa8QҬU%x_LM0^wޔ#p&Kn1 5\y`F5p3 !�z^H0ֽ8LE +MOM 9bE1 <}yp㚚KFܷiU_4Qנ2%"DYF>Y2Xӯv]nլB5O l�!n?[BȆ_ȀuW$#?;M`ԏќ|҇Gˆ؋7@\w˺]CrۮEt+nP$|RNjz `7n/,^8u:~{¼v]8%mM\Dž?.*sTf.M@f}nҸ6nmGpZ$PwǗ!RLӶSti�"Q^R8xPC63'(n1{�{ܣ҆M'J`։TMUFzX~Gf .2 B3Kp]9.ܥ :W{}-+!ʇԳiMzw[*!wxy,+<3jV5V >rt\aGzWSLHrܵi๎powe <LF[Uf^:1b$a15$oƄs8V {x Y|5Y I(ѣۏ{XB/c-9sRnjPԎ C_8+U l-,ϒu7SVW#`fC'~tX*bIKNt[Yzt?0]]u{։,7Jձ@8VI>y)-c5Y.$/vm@lKl?u ]d !f&oEX<\\NPVT0$<ͷĺ*0l cioxrد+?� +0w7a_z,.aI65c‹٩ Y1>ɻf%rcSɐ?\eeJ!/Op./S( PTı?C!%@'j̒4LZvXjjG!gڈ <Tq<�W7$2vwe>֐01 :ۆfDV{&St Ji<޸ p;]n/5@:=R3I3= WK (o{Zl`)ng"If/jA>f) ##Rc7J4H2O7sGN4M0Fؿve`Y!'@nRaH&?k|h[I3N7%Srt0# p NEuUmtT%W-TfP.2ǷvBOqCF0tLIQ_QA>]lU𲦇9C&lNR>AffYgG=pCknD:2[W+,l$G%gzchvx-\�L,<KZx;F xk( yqH7\g<,PoZ?ǝ;0L0w%W3fxfZLӟ紨@tθS<c׆ʊaƉ B�(-+BԈ/OZz#*tquHrnC[%/yn7dHPZ~ՙg×GR2muud`;cpv.Eter gh4 vA3݌S kwX6utFP丢�[Q?o-8VPۇ9A î< ӼH�u'b{+5B1"r4j3zf:m*NWUxē8ePy_V L~%74%xMw?J"*E/ubϵF8KfhNSUE|0opS*.@F_7޲mK\0i>n#PEfeLKɰl cx>T8yӜh z6t3W'ciX.oO6*p,zd�q^,D݊{<K۷1F2z|**$z0p~Ht 8/nK0lwi@kX2PYCHzX42/u_ڒ`xQV(Dģnnf5+[* "]˳G GBmw*-p zeyBӽF&kCkqqwᩀ?\@#iNGV P߶-Ϙ0ԸM!AK<YWOv&tgoSz)I7] T۷I -K`g[4t4Oj$ޛ0r-e?yjڀ)AؚkJ?- w#-m۱~=W6cFү'Ucƪ@;~Kc_lg;vlg;vlg;vlg;vlg;vlg;vlg;vlgh /P%št5N5mE}QrOb9~e)(wSI_\8fIǮe)冑oxd0 SB? ~KEm7s_W^}KMSa83R~|9s7]bZKY/K#yٳMy`r(K>|a,ۍ}˂׉`Q9/;')fh0Y(8r$I]\ûaW,o]^}R9͖$IObV&+".8J]h}`U^p6ruyu{xL&tCUՌѝ|ط&kNM:'Am)<Nn'ۻoe}; Jj%^94l[˦nc"yI5!2ݒ֌lm_\4>m?kQ"В?gc8MU.$ϛN}S7_>2$ p~R5yb2#+[B~k񣤨*,Än[ċO�^ZwcDq{&~>PְP}/8 O8~(j^^U�.li2}AY>|uSh#..daߗyWMJG"ח׋vk"išⰫI6fE�o߽@^><}Ӽ폇^Z^Z%/y'**uNm6w@P۸GA&S^vDӂ}{y9I7nst9Q�Z?|D]SCyvCJ*쒔~1~~s̑VOjyM塨4xk7`XI2*&7}-d׬Ofep8~oJqTP %!n75^3ݴʢЇ$(CSbm]r8�Z 0MfDh~$cioe֌Q; mچ�L #/@aeMf� eSpw}g{#q5WZo3Ìs9ѿ+Ke˒zL$U  #[cuں*RRPjHa׉kȂduskJ XM iitS7COa '.�|f5]C/À5 A^nʒǖ@3=�MXUoi]Ӑl,I-K8$ʯEN|CWƖf:$.R5>+ &i^āk§ɛ"�urUJRQpl>}^~tWCB1nuIѢ(̟Ucsxڕh4})>"7Uny֣=,p-B_ᛛ$Kƻ?>?ANuI$m<.xv,W Թ/Zu;Pr!l6ۈ3!weh*�q1 ǐh%/0K[|El7邒Q ˲},Yѓ-i`yk}8+=g/?64^ϫJ EzBw#iP {<mkNw}C;d 6xO q|KA>֓|Xofu�:r吨,dDI:*Mv>畄bT]eg0=rnf&IrK7oi(.=٪#nv]EPJ-]fK cGiI3u(^oli/�V�|CMĦCk|楡vuq-C̢Ct |S//v%A^eYOE^.hūg f vb<Trv\ɇ!Kh >=AH�U0txvEkI`q<Mkxt+AR6Rp�R9�9"|(tOwKdN[cQO=ޡ Bp@PoV${F8f>x+s5-lqvHe�ZgmaA2j*a0Ue&Y:ezz73pU;n&4XɯQ*TQÖxB2HB$}X2G. Nc٦.N~jq.G͚ ?*v(\xJ{}4U$C EM75@Y*]&)wu!`3Z]Ivm85fziW5+&[֪cW}Lw2Pz9YL? <ul%3bpDO oIo?3u] CQ<䱼Cץ �dkv< fn&)J�1UY|^OIP4r4zΙ%|R^ lZe+2]ha+%?hx�!OenjDJ]- fwMJRim2˞ m5#S[,sSi1,W!i$-8+|/,/ N%IhF[=? <5 ͫ%i>_W#n6b{IUi8͗[-`*v 5-hgF4ˋgkz B�@[a)rz:]a~4l<ԒKrĨ**bHUI_KS 6N1Kf?_Bu iDv;)n7(e"Y(g7 G @�\V, ak +qtAnIp�~;%:;6+rYn"\s@E EXs2xQ%R}i$'Q)ñ K%;@x8zp)%YEi:oM tBh)f6%?ᶤ Rw+rK,CsSrJKb#vCTo;, ^<j J"mokZ2el@K $Xf?f[z~q쯰mIlKH0]V db'hc(H{q5!+ݾkz=OsFB0:F` ~p�J, ôl7(@·M$+[^/f˺H7ar 5f1/fj9>`LGQ.xz@v6Uѽ2Fcl[6PHPպBۺ~ꂚH$I?[U@1{8 قDu72 iqQ$KӢ`8P7ơD 1Uތ[(WG>H5WYH.7Kތ\9[0rY9ەY9o݂eb^L H*A/F>J[cef1~X \LFKr(CC an� Ӫ( <7tpz 7Kh<!>`&:Y^60Q1�yc:uP3IW&c]8~* 9Wץổ J@>~[)1ElUT wq5锔s8f/Ċ i Z" }81F#-8WCWT3^W:�\ϕX`R臮|$[!uwx0ӌc|ᡐU_!:Y > -U9j(d{AxhX/)p|Wu QSd;� P7򗕻~vmg` +2SF%(:r|܁Ӗ ;AuQ`xdn OzʦmCIl/>R`&I<kX~` 36b|Qe# V 4(}D *ď~IU^�:} qѣ!;DCVmhl&deۼ覶U l2[o7zGu?Đys$#J=eFY >BeD7gKܮ4x 'Ɋ<U ˉ/~]al$ nKOx;sr; xIy;+톤ibu?o cu_(:8Wt@Ky^a&^�,$c?#!jxj@{2L"/vWYIrP F=vtSFp27jSDVGLH7e>{~HZ<LUFqٹD`[]7b t@˨h+^g}*=* Knfq�}S13)Q&� n aȃu MY.8A8rEa9>$"rLUtJEsA}ˏc'IQ(ר*I> r]O'_qċt#Ƕl&nQ]ǵ=h+�w0dlDqZ"}'082ϳ�b2Yj|@é_øD & ǔ <]k y{ƍyo怟4`AMM^ߍV|30 N#^c(pmyB++|OoVDuACNJjNB߮])g~Kt0 $վ&SDy'e"T͈ 9@&'Ǐ_#z! PVtNyFˆi9ifP ݱm7b!@le_|f6GL2~ ҖiF2Tvo囃7+OtlSKB2\š"]/>~_QjJU]+r~!&M q/t'ErVe<st)zjVޗK-Ql6?%%j"đFן]OU՜ p+mt>)Yck :r4zH:8} ƮǷ?7׃ђ[-B$'{�=\ U Aئ*0$H*[?huK53pl G݇ލ(7ZDdˣ3Azݐd/4Kifv7t+l X&h:hHrM_qorA,PlA خyNW[@e~ڀ" _)t˗x4yL6bD90=N k -wlG?- iؑܕ LMpzX&Gݧok<4s<d6?_ti@3ڷ=ʺvX .ۭjH[!%&ѳ?wog<50l'je;]p*R8۶x:鹺`4<0;\:]:L׾`J 1> 8 išTLs,�LQmc^ L$P ^LtWxLW{oSDeÇ$�Ppӡp&0^^]EľgwY6 .H7p-OO&r+,q' ]^/�Ɩ*P]ey$*}<sM]7ȅL3,/Jd][F2M ƺNm_z %)pi+슼wLGT2+<%6̸͖-=a|clҩ2=!ApH8J]Cei {s{|K 1u^H}ۘdI'+ GS4 hR$nN(i^=2`Qv"#kgv@VMܷ˲]vJb7q KIԒCQtjˀRˇhE}d[W٭m=.f9)U'REn{v!YmWSiʢ <K,)N_)ƂnB]7O7̊ wQO ,j|@bS藷9-˪Nq7=*bk>%XȆNTRfj@yGEt L4>@-1y~B xz:mh 2na 7iH9(o:p0r rAzNTKT�/SN;L,=lܳ5v9{wiLʧCAJp+zgycAU w�&2Mel7iD@De׍KܽXtR=9bi�nфd;a-̀M/kOxH0IA]x@,t >TD=+@ؕq*,Fsf%׏ >CaS&b;6gwm+fUKitmºpa5М HV/BPxfq};#\M 4^-x;xbRX"UܡtڦJCZ`1e�[cmlEp2$-Ħ+H Q^m@SM/vP -3w`{ } Z u[r 0$ `}@@M i=0\KuhiRv~x=tHZ 0lQUJO*"H{{�KP}w?e(rCb"IWo$&$C] ev=c~&5Nc1W>FI OI`6L-oon(/p[ S[~>ݾLk YNcl*FL֕6OW3Q՜ Xa'|Êj _8e[_j!@Z&+Z~mH&;քû)@v'D"-V?>hfIt-H9fRv0M!3f1xp{&G(G ѓp:NW3V8B·wEAwG`\-1l29IxLgcUp*Clx`)>  WZu/?PC,,RņxunB4ôìn>]$ެE{R]"M#J;m{c>9!K.o&㪗=e_sѪOOϸ%<pz chZHUa:&Snh"=qi9,<o}= 7?^vr< 5h?`vyoo(<MU[P(i5X6OǍ]Bci?9/v5ր\`>ݏ ь6!xunyQTcߖm+_`EJyz$"89۲*5q+z�Eo8/h"v9%ۆ8pص`L5.<a`k*'H+mqO'�3uW? ʢFO &qs"v;4MZ)]*Kq-qu[h$@sLa9Y~$,ϋS("r}[E4nų+ѴK^O)(qA2 63jl\DZMl[qc T7WKŲYTO)bK $ |a EgUg m7?c,naN1Tt pBEUw|*Wpk"ǑgSQ&^o5C<|CHkvd5 Bxf}݈ t]F4V<3[Y[m($xp`eFZA"&5Gd+hc MJր*p</i[NݚPTT//ye[9V햤nʇ_JќZG o#yFH:8�\25-sC'`l[E Y/@.i3kA<ME6J;/x#F1i� `x/-կFADe՝kFPAcM^ߝٶ77RR¿.v]b.v]b.v]b.v]b.v]b.v]b.v]b.vKo&Z8tV(l׻hvlKEs^|O,yӍB$mu5V2o70cʰ,,'"KS_x~<&4?}Elhwm \ LXZ$~gl/մlj)I@o4,7z^~y,m$>} O6gK=,SG' -Lb߱$|c*7Eجn< 3jL'V +S2_h׳O| n]{*މ~x;ߪV XHN *ѿkVMP UY=nwʲ8t7vuEuڔk(aoE /] |dYd͎]z,Q?XU4V㢪< l]ȴTӂ[Y ײM]L',H|SUonIpxj]8Q֘`Du. 4oں8^iTEfo׬ޟSSDݶ-]bt2LԿmT>.^Bi梬v]jEw穨幍Le8,f%#ic}\*X /݋**x&F7oDZ˩ x:'X$ v#ơc-u,'IndTuG]P~A,}}CtCS$ ZD$RgogV[0찀l:IVdi2]3GB (_ڝNO6UI10CI>`%Q9WȀK^uA/mgCmKǵb21n(w;>=2 ^nPJB$ןK DP6 CW̰ o^lрa6eULOǶ̒|wh3GDY"d[~Rbs8ei뇕:$v>5B]BxK:6ܤwm.D'1WY7>yºMŏgl%Ǭd eEa14;G}" PɮS ]x\^VD~a,)nvmMdW }פ )2?Y:=?w˗?B(VrDn*rT;:C 5tb%ͱ93m]m$7ĸ,~鏧◼EQ@he(P1@H^�µMܹ &־#UPXvh2?tTn�9{>V|uj⫘q]"ԡ*\=L�(PQz %PGRjXMydZTUM7�$ =R^m4a3!T;.8@׺!Џ@x<]+^7e`�J2Sp974dQDlej|7fca5h >uF*=N״dj<TqE[Ǧ*w Pt\q5~n(m\I'xmI(R ȡFsFt#P[մg{ ~砎|LJ Q]O5LUǵun B.߄5�Qk'J\�1J:#hu Ͱ, ϟIQU,׬_zy9w)2ٞtJr<G-_zi͑-[md2ϊ [;2 XfٜxҺiBR~y#!}I` 䆦RqPWlqHmlqcMwĪqFZ_\O Ijt /C߷TũP``=Uwmp 5U$$okˡ;LЙ;AU5U2OI&婗8VG2�zؾ}Imy/رK@;p\Eڮ rƐP7s|44mw?3*z)فbsqE2f$ne u#hCkݮeI0dQ5p–(0ma6uUw?kPG<{u�NKj3�6@6뺮)<i RAE5ܼŐ1$8iH~E ` wTMˆ7"wmsOY0vvSH8(LM]|4$@o@=71eY�4XwQXb<^}tE�*Tl ?3Nu gH–$dY{ ?Ig5p*qMEĊRtCWˍ5D.F"�|vȻƱA5~2"&^ /yj> 'j(ZV%<Tɪ3Ej ,́NWiZg;P66tWƖ,m&K�^e*ό{MEVh</<,y6�H3eeϪ(p%v+28Rb_xr7uApv@�BAl򑵓fI딆-$E^N�xS9fP~zǵ7IsaVU]f[|4CfHq��zK̥T#tL>Ż"�+1wׂoe dKce*Dy씷� Pz�T]91 ot"Utv ė9IuQ݄DLE$fP^N{�] SMq=[PqSm <ۼȁn:|e۸~8k[a4س(n"?XrE0!Pe$aeiP1#~YQEP,ChYO&J0RZ͐k2@7Z4ILVPtGȩlŨdiZ5&_-?e� 740U᝶$*2؍۶UaY/qe)4^f"9gTP4͋wUڥ0#&pjA�iP8 ]Jqb4?*p > e859aAI�Qԡ_A9z90U6~Cbzi)hg -y^UE[ C\) tO.(]5xӶIblÒ�v'(8a#vM6MAVijKnHЇj *Cu]XcS[%j4T˟~ќBQtf nLcY*][o]jQ(eEֈ\?ʊ>Hq{(Cㇶqexzi"?o*|؇A'@/Dou?_T. uBR;Ceο4ĊI,$#Zi]JDVYi?hSɲ]۸PT>6QPض(I{Wn]sb=Z?|İ>oD 1CjUnZ61!>Jjꖳ!^iz ~ d4r53XisElxVR7]†`R9OȑEoEvm`4� iϺyn]n6ᗧB2QCp/ RgCsb8wHT3I{젭7̷/)p)/0 'ޟIx<uRbsbQ NE{,ejmplpJq|!@D'T|?+WKCt`o8Wm]!CJ,ًei:IP|cӘpڥ:tɗc~\XR u42TZ"Kc_P�5 I~IC�e9`ݔŮ*¼Y$VlpJkpǟ`UY⣁ Z<L�R[iy).b&6N}  #`Ҩ1}C\PV7 욆 db9z3"fK>@+(Lo۶0Y<E<OY+,(վ3uS hI=^]Yk}طrTibLfD=oNCY,(N (8M7 %.#�ŠCݠtMj W?.B6nUێW[�+,D-c :sR3�fpZ\s*yV%f>MU8.ҧI,X~ r�xmvl0{]:wu| 2kNR#!o{y:Z5u@,$y2Iτg!;M8|1#Er)뺡)-:9S ==<WbG]Px6ܹo2dhI: J^i=n%sNh2"= *{WO^S$7I3jeWDx>\pzE <'Xb yI.M^ C޽ˡel!<1.kq;o$+Fy@[WP!9{_Tu3 DH{Pa\*As>LcPkJ b1$Md x%0t-SȶÇ='p[|H|;eI)C}ೲ}\H*q -j: /ǡ!۠H/^\8]OBfH@·25\ԉ{ E3yaŰ-' lPI;9ۗvzñbn ]9&u %W1�#Io!E"tt �eUf.S^ *é-B˔V+I>BC7jO$nBZ7N2]D`دMcd0gjbHA!+̋4a>?|yÇK #X?POil{�H\[֜fG\ 4oP^z­ C?`%*?qJ14+�sKx�D|+;b8AQ.>ڋjC>8y(<CftSuPeno?F/^*, WfkcjMi]x;TpgAJ�:45_x9~4'):e8+3؁HbT >v-f9^1p)ׂa\t)0n_yU4+֮OҸW4_MIфx18 8R#4pmiM*fXkKWYj=޽hYH 0=yO;O#WdC~5$5$2/{K=sv!؅-x~&㧻w߽_*0[x^4;3%cXg)hyiYfnu' Y怙VbLxt2[ylV70VE �,"[ea&qzd_ y~ZUyۆ! LdM;G:#y�tM%1%:q5!WU"2Dl%dXv|?JeY%I5 Fچ^:q;r_<YE7Hqc/@lwy<]Ӽ~dqn2Cn6kbE#(R L3Mt &cߵMMF/xx wO+.vm [rCǍp/mk2#)b6_Ѳ6orCB78z > mQOOkŠfEkdf1 b K|_m .�`YAҦm}s?UMݡ'405eu�fyQ63K ІR3b <rWYEmm�P/V.b!�ë{KoȎ>=?ð;_^εI$zhr.\m;k楑Ϧ8p莕iC,p%9aiWOpw8U.I/?;RF dj TIK;>9Fa?; O/]l+ӐX|0][``umS~k_*P_~jb?< m}heȶԷ=4˶_WaŻAx7!VڮƟ>XI¢VS4\M*(4$G!ɷ٧jC4*O<Sp')TrAVwPu^w̳-~Lj=GPg$g0Á362-}~0Pf<XCӜE:oAp!hnr)X,TϏq}ח#6m#B6{2t نbDww9@O|RV!$[„( d篸 .̚ 7k@mq;*GOF!�Xa_a~j0-w![0hi{>!�*h8xaNZuʾt&% nZnA|Cz10fa!Z YأSn~40$YRv_a5dbIԖӢ*Qɭ֪z~TcM>GX r2퇇GRA{ı\m>Ǎqs>&4I1M'#!l'ç|<�ۥT?N8`^~̵/A(0Js>M)K`+SI5]/ؕRwςn{)�jӷ9Hvvzi|a%*:@ .TxnR4#:<-K<pK㙙=Y�ylkX w+b8A)"3|9`])9L4,?:@e Z~飰ux>_RߝNWAQUy<UՌOTyYL>?E mVg:>ө ^<dƐ̵LNpul2pДj5MHAh<\)SiA^CaVY]O8Z35�W P/_o ٮ_ 8=8ڀ4]Au?5 P(JRqf_&_y$D DPP*.v @sx8k|UxѶ/{ 0r{Q'xɐ&9.n4eUS<y }^<t-aF)^m֙+P2ƴ'@sn%m_a:IYpHVa .˲!)�Pq{y[ˁ�$E{9A3 pmuC~ ~9]^"m'4Xk#An5É=VI $:;e !6 1 bn:, CGR 'Jw�>b$<6ߔcSMۂ$M�)bM/Uh[,Kb<!ڷ]WF)QuT"EjER 5_BZX}oʭ{G4m`j"YN[�s=~1@bqIKxp{uWƮi*"|_#"K"K.'_n>/I\0xQߑh[)oƤ rYqY5- X-xjeKgklnFㅿ8�m]/ i~ҊaE.O?z5p}i..ܯMDd`/.g&,C~" 2޲k?2R [z"NܙKq<;@HY7.ծv]jWծv]jWծv]jWծv]jWծv]jWծv]jWծv]jWծv]j$濹aʯ:Tm۾g>Xv}[f ӎR][< DǹZo筨ڹރm7=y= nhw2ޯ8>~x&UlGB4к9)7zd? hr X7%u\.xRO>Ρvk Pq׹т$ ?o_W*ЛaV=fqݾ.Q-xK-bZm[/YI$"Kǻ7ö#gyٮEY"yr8-4Lb!:sTYM7lŇC͟X cOёʹmۋ]Ua5{* _Hմxx)jغ N{Hʪ9~^v]tmx0x7 } l, 6i4խW{ԒfC<Džew<ԁt2V[ٰ$r5r ]ַ/>C']YUx rS$w@�5_e`j4!(Az_v~;7 v<{t{78-ty2}7a"~zz:)J,'}ܸ?Z<KdAouvl ˮt~DoxtkmlFVPP5U4U%;j[<A9q5~fpǩV�p¢{9eYө$w3ka`HoEDajsLY '�5O!$@FwgQsۛ姯˩NÉJ=#V;цMS& qJnxDapzǧ/$(?|X qs:s36jHhk(h(H>o ?ٌ3d7d,^5>u/WiFqٍRz3Pq$YwkhntҶsJ8pCwi]S/( R0*!<0Gr!J*l et8!e+ǶL!Jd 8]�YvsӾۮLiAIߏ&Vwx[D׊$D|p;cx9i$Eo֌E^70IwN]{@~qSD/U%ñ AQ8SPnt>mVcESix$JB P6sв&spƛ~۲�H jKZ}xL 89֑!5M\3ɋVG|j Z/PU| mWe>}Ң1K2ݰh$QRuM>MIj^./?~2}3|mxQ9[vLW4˼𪎂Q]DPz�}+$I>ebuOU8V2 q5%(̇cJVUWYOr@ ஬}]ѓd<#h^ >nT +1$%X5#~}iwiiQջXqZ[�AS$ LpiQi9JwG29YbCQ9F!m_uPPܔcp]ipd5'%؇0ˎ8aXwGNM*$rGA]U"Kw0#(xB+4%ۮŌw[ FY~)^q<В!ahQ�OQO0Z>B8a(sf;pqt^Fy:52uZJϠ ?wXa:V.O( uu@k*P' GW- 绺=F6?y.JA٩]2=nXhwhSGnbLq_g9rȦ^氋('ˮ]ލiY7 _ge;2]Y}pp#,vt8iO[E>c8)IpP N9 GGK/t*l$H^w]o);Aeʮ߳ E,O 09g?u̇w$ =$"Px^v*g5AwyVdN+{$$?R GuZ*R!qߝU(lg@"=3%a{>p&oI`H9zh/#sG%h�%wIe~Ɯ)(ptfIIu]K :xpPf0phe ?<|hU"jF> oi nz 0ľچ Z'@ ilO>߲Z 3=l`azAݙeUmG<:qLu'4K[TUKgvzW}e d%>ZMW4rRdu:,T۩ɣdJoq9" 4'H"G #UΔ3=2] u0YRw\giA<aE1q,h*'nK R@-4sZ%pA0 :.gub}@VD4]Uň 8f-٧}HOn~8v zÖ6Jh;ր4(k㶞/ TBtEba"VE9`ǡry[ۿt; if5/dh [iAiGЊ*=ɀBA )f:<Cǣ|:3m%o+} Z�觿 EZqGĞ=Asɨm[ndhζ�B)<OGќ ~[`H��>&O$A7q]|#𔋵l%n{@3�Q0u[<Z(Nfv$n/5MiM43 Ǯ3kcy@NI^k>,�Ψ_V,no!YA)JX-dݒ]flֿロ͂tSBFq,W7%H{^.j8^V |bZʒXU t[eY֪1%�".Hfbr=>kU[9tsNa϶[ Bϱlq W I ,7T4J=?J[r8߷{5Uyjֻ{6`| ɫȋTUg AGn *@u@Ş].+ A:xuc>rI|Rye9F[qԊ,8^Cp/!cxl %y:t6_.拵 b#5.NN x{.wy 0PuښѠ@Q-qk@OwOwsa}+yb +fio5%QPEM @_w6i� !,3}z|Knkw*5p  F* ]ζDxa2ZOEhay'Z H9ԨwϏ]ֈm5yl+k6%yF GL:җK p ~Tкuqocw2#D4,M[")VG+3nq zƤgr(�]hNZohm D;Wl&v by@%x704v�y+6c|V ޣk0K(i|MI871(&wa>s 235b4pSϔε I{qZ=i  ȝ'Qnʺ[ߐEDgaq(ol6敏Bvbn]?*DCU6v.xUP#zZ D~" �U4vlbfUMFjs_`FdyV8<9MXTJn9J<6~@&Zo�<E +x _/ 0A⇡'i-Jk$ukb6.HF2AM7MKm^b7G.7!!`v7`-[=HcZ=֜$%]@*]ВnAcr˾J"g4 ~ ke[&ph~oA=?,l7AIH>*>u7ٶ=ÅVSS#^(& Z7( n.wݗ߷DM/lѻZa =qǢi+55rmkdfŸlMWwnoGd#8<"8 Ȟ( $a ,de;ҩohQ9VqP_&iV>6<?>Ι}�煓rx؎t=Ԋ5bZ_`:�)?D55Q39R*"OM8Aj;Ey:iZv]Md:?u^sS��y mCWn1GH+nklc5;nZu9mo\CW^&ֿG{��$о:�SHs u6FrÃ*NҷL4y,ZO:+6!s; p<K`�rǙdqÙpea.sMi:Qܵƭgӡr7Lb}UU`yY!~ XM=:{ǩkuzhfێO+ēܞ?l ^Rp6RP57H0%NO=n�9< 7XVMX<?x_@rzӾSӏálMC4Cc4?`Ӓ2ww7dYt1#.A|mC  i =Ŵ]2ncKH]Q7IL"44<ǭm"̡ӱ�ctLe֝q4Ed>_^~<.cV &i,{KR�vO(i{*4&bAسHM/OGTh!hv IG1kݧZ#]:+1"pԂ\s"KͦʹϹq:[o;,H^WY'&d,~~-ސ V˯G"OYQUtJɦ \9AVX:6\l>%G]j<9 \$AfܴKSC!kJҲL_Ȯ$h~ֺiDaS実T+:ؔ薥a,v<<q8)vkӥuGnk lӧh rbԵ<}jKq t |ŀ\>^4Hu]תC$IJvm}h4]OY mh_F2#KOٖu[gHp 4$ˊS+݊믛W}昆*G9-gx.<GqM塘հH-PF�d-CIVPM],�îJKST⡷!k/J,a G),9ӎ~X |d~#jly?L7N=.6MBКz V lضӝ В lBAv""Ӟe"AsX�PCCc:Ϥj.<S%<wn-^}m*niYoCY?I4Gw}+q$at},Nx0%Qf9Yo >B,|l~[*7`auje)T?[,5Dvt AIQg /w#yo ϋ g;XL}~d4<W0sG4 8nԲ%D}b+P,s;(2@U�1(ۊV(FVR ̚_1TƎμ<@z2ha U~0\߳M:W>~iKebG> 0mg}? HSra �[0U~E(,ܧXIsùcc˒s(o]MC{~L.(&iL9\S׏ Yv4{�N_-Y:yÌ'eDT hwʹL]~Wѹnxp,5~.# A@°sՙ5]kgu]FP$Ř~J#xAZo* C֓1XQuh��& W_&GppC. ]%n_n‹yWb�^bGhX>dVYT5u`%\l5�*<CM^:SN*\q^_aXtln7f<}\;\=Dqkb(j\ fp41_vE M]yOirl7۽&4H[C lYbxs/jrB^X7Ke 4O8&vTN@Nanm'g׃{vq_;�m!oQ6!^q<x@mes:G o>jIݨ5yW_RC63KOo fѶٗ@&b?]5=fSySOni75|<M@`x|~ZCbfxһ{ޕ>̟ve&O^1IWa%pщ/d<:pez6n5xZ $lK\>D�1'), ۉ ci.ȆNܧq{%sE(TER@IŰÚ.Ʒ}B1m'=L?d3ڽO5R|SMy8.̊zs^Lg fD?|x TuSuE`MNX Ƶ`B+�.uyUeHO'/^[૞&;pBPoĚ7_c^Al"(LhIvK62"Keвb("Om?3%u a?||6xv)~GI&u <Wf{~裾àCmQ?vz!."GYd7sQj&.CVqYWu?:F2]oJr5M(a!鵢EIVw:XԖ#͚Ӭ6xnz[Ӕn"/H)Fy &伺zӒ )ǜCGxSIļ;rPώ ++Ŵ(P2@jpn 5 A>^]-@YLhb _3>)71y)"~e,5H:Hp G~6ՠhP , _.4 8: "K Aƿh hn^ &O_R�@Pefl>xr8Q%UWC4^?}y~^kT@oVbwΠT5H]<'VzMͧ?gu#Ͽ{XBt7 _wYQHwiWNz%(@?j?OnouSۿYC-)A&ciC+`%[ sq%.qK\%.qK\%.qK\%.qK\%.qK\%.qK\%.qK\%.qK\w?cW._f٦*в.WaX,,$qlw/[~C0w`UK7exۭ ~]3 mrϤmyT=8붿zJ54 <K]PbcS&t{R0(NB>=(K<K/97,W/WK}l,ot7L,Mb bh@G$UEVEe;)HyՔfh0I=yۖu,לb�2D^ZYY2w`T+ul_v$g5 fZ&,eY)Zn"׶3%ʚNAXe@ʖi  LUuvM�\RAՏ"@GRjfp2~oH Hx͊eI2(˪azqm+eԱ!lrj)t*Cn4[DÉ6tKVwP󊦈Z.h0ŒcǗx>MTÂS̒kNOzlRW&۱`uRYj9NH]tjB<,OW}r 56mr5Us]ezYșPhjr}NFDfwD{eMՇi%;mN*9"K}|Zeф_kAO)j9/+-z)F`($T1zUf U&u{=_H7�m<1tGŤ0Q41A1OW#޽ׯrJP[s6EɈ*O%HՂ9/iJJ[ٌXH|G's*;zZ6";۾0!:iߣ_;_ S体Î5>9AEz2]1k'{W#IrݤP&vbN>Ze)"|bɋj@p=vU;hǨR#RQ$jNk^^2;iqQzȂ$me2M7c;ln0L|!%4TfւnvhXd^֜m"1e~ruU(f<�Б],q-27NͰb 24fx<ZI^~z{רAo-j&g^ѽ[CŁcHdƪ.1DYkFQwCU5w-]ZaX?Bwsqw)iӫKbz}};֛:DMgԚwlj~Pt A2ϝ]vbe7keÃ/%'.ZyD^Fd8Xg\ޑ}p,0`IYCۮ\'̛22%Dd>j/-[KhH.3F1t= nYbɝ{BJYWyQ5j~2]W3x+$.Q7.Hb6x/G$UYol,�Z!6N;`Bk/\RC˱ڦq"JCwYIir^l]mv$AWŶ:iӺr'j2V렯IK~y{;Nm72ߵua'DG%+mxK`G]ԠFg"dMQt%݌7$ )^imf/uo3B@�=T -[&1Sp%2)~ X2~{*OGn۲tFEGXgM΁]w<48nE"ߺN+h=:7|-4ӂ Ad4(@g#(+֤c&)QaR`Q5`F'0S<:J'pK@1f=YQ̻"TÃ8yѣW@YC8ߠ<Bљq7!?-AIš Y |qʌdHlr=ey@a+n0]zMG,$"/*vA蘣.wUYEfEXkEy G]<?>>|Hv)�Uٚi/5+hiQW@$ l{c芇ړaX5]يf~S,$͐'Joy:3}>�WL )F 4TUI@RLXv: A~Nv?}ǏњmHݮDU]hZI`矇f4E5&mz>S,տy`5@Z2?yDž7( Zizάg繎i9a䳛 a|, ^�~zdz3b{wl~)vhԒ &O? %uLu7O"6r\Q%x& ,D ^>r3S,PŰMW@ҥQk uvf+AV5y_^zofMːd:3UqI? DryS44r}u4RXw%Uc`8N]]vxq<>=g+FY.9;#t$Ѱ�JMJvݾbe˵Ydaoz9L^&thz|.Ir9> "*8A55yydAR$۔6t  T3nh$0ќ-Gj w7No<? 9�"9F�,AQ'Pjv_jFq< xit鄫b0UDk[)Ω5HA5۠`נac@l n:Z,ǃb6Gϵ,/Bn Zþ(Ht$f{9#UU'ںjU& CS+[nKZʶlbE $};E> TDL~D%.2O7/s>^,'doJxuY8~y.XgI+&47ܳMˍr2Gi^bX}[-ӥ*ctW1l7o;b𦆹W3eNw L l#N (+u^8J{eBbu~*p^apOyAxM9Fb'ljjYҹ ENRUwDFk*O04˅9amY�tZ0 [Iɰ/n\E]&dE[zSps ot8ay[0KzTm>62:!yy/K?U 9%c?<SU]LFutU_/OX0ױ{67y]C5>?N%NպnVyi8^ A+Pl{x|/ȔHbl~K)_.xQ8U)|:t&mKԼxq~@"K{Ͽ}jw{`&4O x7Yhp+ͳVE.:`(O#W>*aZqAHT RBM&@~.: gF4y׌ؕEs ,R:ѥ8ܑ}c2P0*绾療%yGS쟦/zFw *]&ie4_\zԔ�O43Кw ӰB1\y:5Ue6MH7뼻MrdLHQTǛ/C{jOlW YQVSSF�k:0p@S,0uEQ5u'k&x횅.б3S؆^Mdu_(M]Q)OmY%yEi)=&71\el :*0O|)O":T!ŗW_4AO6v]e jZ*Mn3CnlycB\bwaHuS_j~ٻ[19|8کP0 NV.7w)#YA\4 WfUwi�z\wq,nӶLUC<]Gʹ۲e{ɎU\uˇ1⥯`&e@uIjK]yгuBDf(=@ш=o 5>e]P^dEdZ:8րY2+iY'pNeٟyUC(jM cW=U*y%GoNoFvDhh?`X)egi8D3л X4|[>ǭMOl]\dt&x<5m2lyAānH=: ]O5h䵛@#чCm+s?_cw,_K6*e nJ4lwنY1GG:x5�r2[&ja4XˢjyC77T1JC4eatˀ$bM5Z߀*<[ڸ3Ib )V.LfbKVFJF7RǂDKFCA.6N<pj>` mS|dhqx2yѹ: =%m|dž)^pd|"sЉ0??k>TL˕e.;}N1QT2tE<?iɡu"` 6C0@yzKBI]XMJr-<x4T naZ8oɎ|8т@4rt6#ؒjGZFAtamOdp=?LHtQnKFNIut�0y*:Sq�"ې״&TOM$&:pu|V5iT 1u=yAUݰ8o ,I[pTC2wR}E}m u^D#<dz)+Kf]CԳ,}e,s!٣M6PK蕱k諫|s8%HA_yYFDf4|-'0�J*]ےg3N&IQ"oowp}고al@17 }3/3l6o9ngg$%@0#^w2BaB"@^$ggw_%'&i3$+>6S کtF_y(3_^ bU 웬B;Mf�>伏do'+ nˊ8ĚDӣd t<+][2Q7)OoZ]Le"hZQ^ƶeRǚEiǫ pUġi$sU޾S(3t.>>S7aDUE4gD;ǶMyUBVeE6v 8-tO%h*ȒeL_s)Ŗ,JnSw)v۴As9Fzs];P,T* YmL#CB Nv"Ğ*/#Ig([ kbxWV`t~3T7B^zSL7NCeゼW)ݝj0lZ5D:D( ŌÆXfR9n.]2n׭`ƎS㬗l0U^}͗ (N? b_r6\f9T%1|- '$%\RTNe=`31bCI՝d/ GO3 .Q*m=_x4"TxR[ʅ.-Fh.!+pYfo`H sۗWS �kǹjB[}uι/qɎ REv ܬwX13dC"B+)'nUhjcrb羝( Yq[T6ן?N+޾מ.q{PŖN9(|C=an\֑JO{= HlxHzaq0f68$ݣK]T:m`@x6!.ͥ3.Fl+ lK"Oצ_?_Զm mׇ\Dvq~E5H|(DfET鿭eYE!d5qf,nCv\CQΩ:]+2zSAd:ODP5Bf…)=-HpA*:T{촾X^nx"16g*tƾ/S>_Nm{�=f2zpֈ5j.3m*u)~vuX*̟oW[oyŰUux]C_fKQ:lRW%Ը+..ۭ>/+_6uƘ]fN]jneM/K^ / ^Wpx"ro[p,7Ajh LD\ɋ&/gnI;C�j6?v޿nM$ij:,e1>LpW; kN{+z9כNZ*Q/}n`tX•lRUʼm0u[9EACt Cz ʶ$3[n.//.nZ2ζ<ɚ0uijȩ&?j[ xm-bon}tBr"G2"[W]<(W�%ֻm7<4lC˳noz26E /|Swc*EuӦ۷7q sfڹj DE,eE.sbٲg58KXǥ[ܒZ_Zy!iI%@C晗~e@/{E;EYwwT & 7|3 I_֚~d ;[jF`$4iVtԑ*ׁk?+7,�~l~4eEݞfRqk$twW <3S*�я ka ,ʊB�eҭ"ǿKk\Ĵ,CZx?bxYxG-yjT}6J< bs-J7t\[ Y:i~zSWyBиq7V],`$tƛ4j}֛r�ت2\niA92;KNxſXEFr" uϷdsECr4sHH-=Ӎ X1L8cKcY"B|ѿk\3d'Luz!t|<v2ԥL�lZ*}!ٻ$˿2ĉcJ"}}Aq{IN>}Vnz==P ~C'TEuο*e!ǛZUy*(,y� ʲ, ޿P6,^xK |y_}xˇ_ D& *g?wjac?�FP4ubQ`o*NUDtp1 { zv(5/+ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZwHrb?#5lgJM1}m ?>,f|kt)ZƪQ,_uj8 z TU= 0qV Gh~k2g=t,嗙% :yLM`'tEgQ2wnOAcz:z٩M$Q9n֥@]wΒ3jا\0'uSb$8i-'Ȋ"uYn!hZ} !)r1|0V?BT((8VVW\?iVƃ~iBH?ElIC0,+ʲM`z?n n=N`%g)W9S\8YmIi]hԻOS#kdKaKdjP¿~sauƝcF*|1HPTvoسtEЩZ-q٨:WIb8oun]cx|~&D�/~{Eɽ9YWulC)'jRC{|ao@kN+M݈9j9b#-Xm_DjUr)hwQS�ůr:z@ OTyDt K|</`{<BáI!+,T7F)j6Wbܽ[.XpKw,:ÐK]ȹlx 2-yf5]S.4h#$ $Nͬ7UM3^O K,wDMuVCQ%%-lYY-8aת%e]hN:У / hƪ^5A [WX%ޗn0Ӏց$e Wvy u;Țî!8^@>N,a=yPOjr˧5,E*\�qNR!ctM;^Qݶe 6q* CK` ]SuJà_$^E0drpɈLS n&bCy8H/ʜ0-ȩpty2rÒk,5 ia8G n>z.TYU"T�EȔm8]S&<!e˵˞J ]Z^_W k1)p_ kL *?,bKSdiYPwO|: 0+@+&r9%l6eZ),^}BC~*sR ǧspvCfmo} b_G?YȎ}9Bرt(pUjաl@yE2V=Y35z|,j@ߡ|E/ooǷ.8-;֩o1Lq Tfs"I CWa llz~הi_~:_VBfHW_+O֮ ycKAE~46GTo5@ugs ]T}fɫO}BlD¤ol**vnYU@_^ANXrd M=ޙPkk7XQ@ZƦ<04D a0I =$ZcXyGW4 zjwAc( X1pâiO7+զ*)䅃ʲ0Nbw}� s4v#Ac?0z ~hZf2P8&$#q;ޟ p v6LSNsA\^ȥA΢%Ͱab2ϴ"]f&0Iz 0.!2mwwIݶXk YlJB8zsL}s}CBP<5ϱϿk(&0ñT^-3 DQTUfF v<(v;Rv!M1l~~մcSKiHCʋ<K�1S�~tcϐX*5/V6~n$.ͻuW&[|sz |džadsDvٻSś|1tOylֻ~͘`h|ڻ9~yo#M6,Lhe~C,59kG'jvHB,xyX!!r5|_$VxC,k|1|zZ {O`f{v7=8Up0'8 *]:g|>of"e؄q KM$-Z`?p_hS~qVR=̈r2@~x4LӲn9(q#b8/\2՚Wh{8!q\y6,5yNi 4 ar>_Ӭd@o(ȳ JG $N$20!ww*ԖR(hrӊ`!3Mqȱ zH2 ofUf1È5IļgZU[W5Pr_O7$~ƞ%/9-Hguo $d裃d �Kq ~l p8MkN((Q'Kz4-kxYl?Ζ8,>Ȟ ڬUyҜؐϧw* agF7ü, 0PnWW(Ϥ!gF,9k{Q&qU[0t綩Tir�7"tEjF�hC(hH'0ɻ^` ^fgZ j["Wt݄++]D f׶F(i+$G+,3AcN&Y CU@c%j֛|+P5mq <QXA9]dymMz~7Qt^۶TB{H ]`v$ w>ݤ8ArU 1 ^ JFuMd KELM &[tCF,$7!̓g[Ȓ2 =S<P0CS+k ,f5AGx4^^>qTc8TY)-iɿE,)0  )ۖg; =Yk"r5j9A9A{$0K}gau2K<P 2CIQX sL <6eyfDQyn=tQ46f9Q-X X#(N&J*0%| VS:;[|dV\n! 8nû~4Os*H=("C%s }S7h"pt{@&?~(Pg! 6q^ech2{c$+;a'& ܫ$O\:GUACn&yvrJC60*F0,;}TE keVH*FߝhюF ^_=Mͬi29Qv2Qgq/CDL00hA52mdJݎDy8 8;<\:hcqxbmHgBM ,{'r MP?/9_w86,;BF;:pwSriߜݑA^'B ]1?R4$FFO`X׹Z|=c q8 *�i-Dft\?~\}7;L+`}<ZP>E+ wA1#2\T! ftC핞�h4젥N"g[j„uP2a@H(#P' ޕ6'$Yv: @L O$S3?Sݳ} UY/B`r"=44UhbwAzGL1I,n{g }/Chºc:G5tY`5'#D_>V8O'@?@!j*8A9oJ ]z^7=8>t&4MK<Q>b"?ن`>r/7c�_vtgdF"}+?#Kb7@tRM?M$ոd ^W%J)=|ySNffg;Ch$>Pdk 4<HT$XXS x$(ܲ�ons�j^dW ?JQF@ !+ xDvrIdQao¸"{&C SZT]&*a�٧#̒"4h2�>LԌ[LI9pٜ[>/t&Eƭ1�$҅g4 KQ(K^oDc\a@@]ZoRZ?c֐ W;P%@o&Q`Vٌ!@@P@ZB>4 fѿ Cږ4 q2pj,!y0Tq]HתSt+(@H |69sЄ O%HE]M8CwPVS\eo&kv%i^`-u: -/.IM-$ x l߱ε8ĕs,ܙԮ<{öF3� CU�i:w ! M]M%<׵i~ w*`\_dhD>-2IVo%h#4ܡDYTE8ű3C ʎwS�hkľkԻheI }h)ؼY;Qw}aŹ:UfK^% iyQCQ1.ԡ{noﻏOKfZr .Q&D\<cl5 Y3m7Lv/u -NhaLm@l)=7Mw2-Xe0CQ )K LVSe¶CG8)G#V˩d>6EhɮhF0ӫ0or|hX3T,c dHe=jqUl($<|9Ib< ŰdQf i$)h M{in%sP/b Ao<v{l :RGc׆t zyhb](ZVƸj.T9zAMǃOZa.l_~*M;.[=N:Ն@7u0GCx0tzy'1j>܇FITmSZ27`%޶N3V&,C%6qJq!ͯ]JhOUm|U#VbQ2pLUx8 3tMחuk TXQUs~Z21,/J/<Ce/`Ay܁bwi�YS<dn[`L7HwX7YCDW;�Yet?`{܆Jyc@,7L9[Q#a[PjZt8Urq5 4\'lr^Z5`һƛMZdrMx bQv+fdIq;NRɰL H ڝCP,(*1̍H0cZAJ.)"KaV#L عq-#`rQAd< Y"/vC gL0Bκ8i2mYi.Z$p+p,J+óE`^v³|t3tma~f$0@'֣!}]Wgߟ8':vx`Hg^NDii#E ȔTQ$stuևi{*)HDk@֐'~j3] V+|՝s�deXMC %K`*2Ͼ%h l35Dlx8@6!Db]UwDM&[/kT5f9[+5̀mpM59\Vm87iYv:Gj 7}ķ5B@2Qy*V-3#ٟ)}<=y͉AU[B5 52ypo[|ȿb̃m`*x8YDǰV>@J}o*nA:zDѼ|/*;jt8M޼o鏱p_6nYE7C@YXMZ_O+Eу LĔs R2l)T.G>L (k~Ʀ! A2Rs9dՌ�=lS tCHgY�}zBW6T೻TǛU\v XmU;0{ 5*@tr8%q6_|tݙH=h0hp뻦wԯtZ]dH!$;7jк5e0c7kbc "\zSh0lKm,8H~Mfe*r:?R\X=~qsgdILS7fXl5H zK4/98 SYʹ)a]g֗z]?@VɌoCA,,!$isc+aǐ$D"u[A2>L>}n_5H<1 UTv/H L%rh+oW{ )g&H\5i@|:w]K`.i]*0<O�Y,]8~?B6l}ZP43(^vVlbw-30/Ev\t 86W+%'[H#yWmUg(86eIRTA0~{b"H8hJWgkR,} qDZ(J gޠv %q A1+3Y~<ͰUOQ8TR4<Z~7wVnyfQ&UwݸmĈrȋ(o_ lYUϬ qg%f5/}˄Ѝ5W\ *+6nH[h6pdƠtuh0B*"%s47(ťEUa`F_vuSLF2 kCieh*}ʿ[ny`w`eɝʛkԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQIoZ^^O3PhD͑g,17ea>Xoi_jVcXk4#^A6׉׭�_KD6_v:fSobS^pᗉGrEYUUN(VV O8^TL׺o5ѰcbtXL\}sbxX(ѭLFu]`4m}-=&ضeYn\Jh\]__sp{,\vޘUa(-s+?_/ebxOleV j2[,&B- u>aNt#ii!s<5v_pJ-Y'`yZYU4#{37ImGCգd# uevu=aeYo/s瘕h%ވ[AY&i(dH8^vPK_Fjj27<OgA4'k^^E*q4r qXpFYVww4CSW-^u#~zwOqj4xt:+;1qBGQxX; ӘbLu:Iyv|f !Lv*il*<uW?PKo\"@Run"/GK=f ;(4l6ڔ(ϝGEdH~ ̀ha@.x" ˋ7ylvA&;O75LE$b:Y;TXesV:ɴ=aw8%R2uZꡲ(MjLyҲ"d~x΋618)ܥ,M#y,}|{|h4ga{Q �/K5/)< mLMś/h_gvmdKve'A-Hsh9fߩ, ,ܖ-آB^tayQl˸Lܞӄڰ<}~i"46(E@:DNR8kfn:*Z˦N~:Tү8֒"m[ Pr9Sj1g!sA֒*RixϗCfi*^yٽ2"LNQbm$Я/sG 1g'_^^D;: , m3xhau޺$C]n^J[Ee^TsKXO__ǫ-~N@$(/?~MCuVjcͮ2uE #V�O{W;OxLe0 +%hԭe{�i7ac*ʴl>ΦW{Pum=chl^tė|tܗy 皠~ֿ-C= xͰ#%[]Qk:E9N˲<<}]H[fت\h@/$ |KtKW_D\kP&J4sYWQ=L˱m۲傕ƕ[TpYFa5N905;] 47D0uaqfYQԗXwzM:׶f ! x0VQ罗NT3[[}TQ,+I-**VRT4CH4Dסs\'fU!ުfǠk sJbSY|Ɂ&fz#/=Q3 J,-^Pc9A`gъMWm$ uf4CC}xjA aV�$6un?~\o9x4U6F{.F2& (QEYxWk9,8t<^TC^>Y< l7SϹZZ="vt&As;@HLǶtc,Ef6[. yd:-f@ 91]g\8æ9|KE,֛KW4Lb VK@`m]n_Zݗ/w/ǏshO}3kX #6ӟEf<OƯwHi}ni֟;~[ݺL`cdl^wiij �"ap,G#l}sfv>N/9Iao>{XX#>[k~iFXfl7b~c4zv,n/=)vdMbq6 zݗgt cZv[jH6%s `1t'*�`:o-5y0aR+_} ކO;#Ys} 3|<3^mSOF /Q~s"Ȫ"76&{}muv~×)K0 BT-fXG! vN`[W}}[wv~Vmm{D$N MIw}QQ:qxe6eٮ~HC':1h:-_~H3 � ~O2t;Rw[ݼ>w;ԥn}IT 8NsR$+`,)CJhXZu+ɉ<j LCSAu/WA<irUe eieY5-AR:ׇ}lplQX|"hLl>{R+2c׫e𶅆bk3(P<|8&XcN#=UIS_w'LOUuI#MNOiC [ҢdU*Kn)GD~`R0$A6{ /͔uUQ๖uFkjh&0=2 -~:"EOE#zI\u U|Dӝ %_^epfU]Aq']eۏSHBO�@*"K5CJ Q'.t-Ɇ帞;P~ Fp& ew1f=*j_;SUX"-7}GfY<[`u'**nfYv\_z$f 96`u/L�Ȝ"p<TT8]aDUFs-ȱ^p'α(9~숣86kAK$J-BOfk|8NMO9,xLZc#( Q_X&|ZVt�FuqEM>ˊxw-;, isG$*=DM 2' |É;1A(T3¸q@L7Vѫ5aZpBښ:2@e =q\{=eH{]F~{7-bTi ЀUq-9ӓ!v7^߾榢H-R_<0N( =_YA 6f�LM]}<N&Uݒ uнvwW<1CxIu<U.Z.VM@[¤iۯ,;ūwBi!)fi<bQq@gzΘ@*u]dZ@J }Y&�ϔQ ˩ *gUMmked]5h|u1bQiొFWUD]gicY5Ђ:l+jUSgUeA wFvM(2ҧB2]T,1 -c\b$,ZkMq!VZr(&"DڢsQ[,JG uȭi`\'�?o"u&Q\Cn( 䒫M&_1hKTGIIhkhePyB4Gʹ+t4$zh֚(X7^%J.:ϖ/suowES&^|CǦJ'z\�<Ux6ɪRHq"]U3!9@0u7"_U|E]|XY:l1tQ+ҴV.҃RTlC(�n8p$,A3*$Z~Fu IU<358'u;$ :.2IXop]S{mf9UMYlnתx|LExqĂ[ @Æ`5pKL)8X2~Aۉʐ6KGM7!n3׸zr/@t8 MmY& X}.VF|$>b 묚 ҁX%(w(IPa#a|MI>@./+Y9u p;}�Y.myt3YlVy|?k@ wd$u U)v4>4<WɤMCc͊RD ue_xV%Z~4 Ӊ莇UEkVTṀc)tpgo_&’j"\۵2ݰ<K~BlN R IVɘgR G'ވTҕ,m(7kNT/tEM=ntGF!DϞI'0PtHC_<O9IQ$9&FrmBTAP^* f )FXkPfЅ<^|t.S n3~d 9sO&TlD-@d�ݱpUARu"/d_a~z䮡iɔm gD( }>}{KFU@)5r $lVdד߮ \s}7Nԧb$1voĬ՚7&R7R0`u[<ʝ*55#3Xס4zl ;AV4U3´⭰5i,VfMׇ^oѬaZ/"꺶m׍bϴ"۱[fxհ\VDF/ue2b-@;?L#vXkFԌI(t׺:[Vy|oS[[ d96/HSUll.˔QƍD\0-ۃs,]l_F`f\L^HAdF^cNu6XZ@ FthIEU9AQmAGЭpIc n3{e3{V>éB205N#cEXf>gxY5l7{F\O|vmiH ss#n$r׻Yzd[/ytzU^0?GyGP!@99GG2&;.Y&<M1 %7b8^2x9&DhND ˗>г`:F!z|{sc i_jX:X2^u=}=CQF奷$)!:X2t0lGW?54@]g# pZvh{soRqWovK[J^vb)iFl9a \D7PPjXi#^ G ӧhA,Cz9ȭW*7ޔDN+s� <7TDrvrI�S.uI`:-ih_ ݾ}Y"sٳ�bi;^TI[6%ԉPRh~УEE]wsOJSFe G{$vc%VUM⛺nLw'T;e6o?ЪH$P3PfY&+KaWT00AB"vޞ옯T!:'LS" Ɉv`ˋ>cXA_c@UyZԀ�XքH( $zƈ@`(`ʿ~v:dEX_0Gv0ʳ5Y!_1+Pv(hVwTBBMB3�vfse<oq^5#i}@5.+KPmLe$ , \CFď6t=d7w NQaf LV*G(l9Y[LTT7 Q9^(H*.6*1wui\b@Ix"*Rݻ!0,=ڂK8<I>, _8rFݾB t0߂Y+"o+#f tɎ6RkH1UwAtu{3!Fl f"qq4e@{w9:-RiH�*uUVl0&0m "FktZ&wlwn Aփ-:Ң15~RCwfd._n0/P׉r >w?>(<5nokCNT}ӱqv2d~~)ʼn68VA_pfA'>nTn>=Tlͱ)A)/5*1W'^ڦ؁/qQ̫�aRtP'!$lj[ վP*XA8@'fM-E)�1y1jSF7C3TW9pb؟T ! ?01s(m Φ_'N]}oEboȂu|18fwڭٕh/ tOQvINt]Rz~Wrm?:.[ M\`FaU _3e$H0(]CzIs.HzEG:Їhe;,ɃB. T1(' KѼynz9u0JSC֊$ssBѽMIqFH4TYl)8&5Km]Q<m闪#N2@elvh|wmQX L+Cdb`'t6 2Qs&T+@1~ꪊyy rnȒ_m eY`oNPC\\UE.=&,dzIK4%ղM_VT-?KtٗEkPKM{,9} (P@ (P@ (P@ (P@ (P@ (P@ (P@ (P@ (PϊG۷M`MOAwSDUٯ~* ~S <?ʴ Xw7c|//?a+ZWHj+蕥[g7I#sHIJz}׌UVo0:/0?q#)$,IKŞ뼔jĖzt:H?trşICRU},M9Ey+0S 'HbD t!eo˜DEtrQXl:=/%kVRGbyIB ZśuY$~#Ț%QK\R.:pyx9.^o8¸Ty|ug;)1N,KէӘWTMV /e^gH 9]ٖ: FRQDTW: ?0ccm.#j}<Pr]6+1|LCW8l2??ᒢ>#ˇwNivdCkB6]%sox1rXys@vj`,êl4,D[t,'Lu8LQ3ujF鮢(\*L!rX}z;O7^^yIVGHٺՅ8v-.HbC stixL΂Ӣ,EJȊ N\5U m_oS;JH=UWS.dl/JiI`0&؆t$EY{+e^\ w(HMgA,YϢ$\ t6`Mٸ l:l !]hZ;N'0_ Yבض&q6+)N/:G$RK=]Yv,gu1϶`W\65E`;5ZRfȱd}'xYL\?Xw8(DБy E`[98%`4dYtnO/1~A f4XOc]feVY>.*R^}=7m6ZqNQ}_2\;6 lk̬αQ汵 iV57ٿR4ef!&b2/n5V%H ${ȳ~kh߿PƓZp> {qjϐإG 9t4a\k3&P,S}jK `46Zkl ҼBACB$&He)*eh2ݨMI)vk-)$>)Lf@sj>]AVŧuGk+{Jxb!o&}VĦ$SLT&k$k"pv:h"r QI8Gan6v-6/D(sY0j"S%k{ܝQPo]FqnGfP$jAh6+K\;geE:SA(\3ɐ}^*P Hyc@´lSE6m5XA>@cG ,^APZK0"kP#W>]<˲jdiM$9j8МT]^H*߮L ,-Ozpo۶tI9~=Ǝ{n^ Qj[YRԢ_ms&I&Q�~ry>adFI!$S^Oo{O{SRPDJ*5 l~.Op *KHYjVT2-1[0׷׭bjQ-/ <x19ZQx@~cT!Ja|1-1Q}4CyzmLyeMے'O}{y .ʜHVqZO75Z0Ŝd8U*xЃ?^_K6h< A\ar˲$qf{ѰtWn aV~52''KVA<r76n_#:zm~Լ4 ]<ib>\? hcJu`4DW G boT?idVv|\[K4.A4Kq^}s)D>b8GJ,nVt]�Гs<`4[茗q1S,W$'<ҙQD%[~ylϵpg%fXjxo1TsCOw+mnٮ'Td,[vQ$�4}I OeT%!I^4nm<|^-σ;;9,D]S�xuo˯_I}Ӝl?$Ip\t\=Hߦ/YnA{]<Nc) H8IIi^`.,eeÓl< ʡD@y;2 iČG۴e!⺃o &L.Ɯ*yQC¸j꺡Zm4kxm9-^{y],_E;7TyF97&{!m[} {tv/w�ыl@$еgvSGp|ti?[>n� е-cx'-xC|qyATxa0t:~駅͢ qIٽCЦtH<:Ow(L4jNTtkqZ6pO,˳4,QlɅSVUEz1~J%uVC}kM3ՉD<a&qQmnRQ U6=Y,`")h2~\'U:q'~^M[$vf:۶HE:k/m&Ԩ_LEUVzK c,VoOVxVUT=ۗt1rYA$o'MT/k=m ˗ &WM_g=<,'Vd,v KSt6cy2 sJk]4:RӦL(룏2|K'YMFqC{v#:>1-tPeYaf 7뻜ޜ=3R!A 'ɝ�=Ll[_۫n.f0Ŵ៧) &' 5IN .kkFܲBYQh$t1T27z4%l8 C϶>aXp:% n�&a,\ z4xsht`U{vJouhۆN5̛6"ϒe߾WYn\ӑT1ե99[BsZ¤ |;UAz�`4M#Т4ղH=fqߍ眰t7Վ *V8#( z$IR~8>k^ˋ"[* i^}\Jtb! \d uI,@ıύVqU~.I<^0Dޓ|SÜ`I]$bj2umy89)RWY <87+8g~zoAMۏm% !e 4rLDӜ/( \G[[T2![t,%QpHČ JАYR 15 Q*KJR"UޠqĒ8~ـ i\ !;jo=|´?|]$0v@+Jz`oU}.r%exEZ*KH~Rx鮎l]Qɫit+F hCVgKJXˉƬvO.q# x40q+`RM9e^ ھy > K+j%-�m ~kom:]r>t?92bC\�+ `*/WH[$6TNw8St@5^9TvtYl?%` N %4L8I}f+٠u�|kFBcGy5J/^GWy�d�x4}($кqT{Auq:o+牨NTpF0 T:<^"h74T4k-0-_W {pL?ֺPPAPV;6Cz~d1VWt {aD#xH404]udfx| aD2Un@gө�5謌!^`joz*`F0۶ ][}8$L?Y+Ku<[piYU㕫 nYfX5&5)&/o_ag`Sv@}defAT!b)*Y/'L%v-`N"�&܈̦06\$ z:Q Ӄy�RMk;M_6<h} |$CZښ<K7M'IS2R ¸SFg ,Pےh{%41INmВdtr6tO+A|bZl\ݿԧEzM1uiQ͜' &f9\6<Rq=-ϿVT2<2y>s5LWO㗃ELNr:Mq4e+(ݖѠApYGb)=6w]dJkyp�-F,!~1Pq"ZAo 'cNo\?O\=tAu&2/iMg+ݶu` \aA <E[ut$[q74SfS4tM{N}Lh8۶8Rqy^7MC>u(oPM= ?)9z-r/Vu,;S+N}8v,�ϵc wEYR=&҇VgSROdQxL㣫Ǎ(>xa0zaǴe\ ~mJ& 20)4nl}j8^ :YLdCSX1,s}v&^~ž&uo~r=Wu7ΫvK80/ag"ҕYAsתaŷ[rK ud~C'GSY3݁骢ꇿ"rRRH-t 3_.:vw.D3VE.)|zePÊ.+-i�|Qђl1% Ԭh&c-}yQunoHRئ8M$V6*v�/a"p4ޅ�&w}?V?Ȳto[Td,tV^vgǛۉD;w"C<Sig鷓b>_N5jn^xAX.%Fx/&Մu~'t\?l𻡀S.{eh(ZnWv*L]gGs0bY`>ԗo8@rAgE=no)|1{eoo驍O [HDImZǓSޥf.,Vv4iz�o}Wzw~&4J7om,~$Rk3'4"n4WW椙n;)ȍ?n'nKd-aBf w-voBWENOgSHnv՘G"/\x 1LC5v:9`OyqF;<[3j)0TYF7Bp=D3nۉnvmԳU6&L_Őz]4q)Z~Rm>\yT>@P HrmjX #�8| 1[9qu0~Zsl5E6Βe{QIAU&ϟx:@ G-U oN>|2S~-٤z,j: br\鋨[nA]L%x0!ge[;mV]n8nj`.#>(hKbK%ͦ! *>i냉^\W5m/ۮ,C- Ogoy`yBCx`o۾3�m&[ٲݸH] Fl/9@K''35~:x]'=%6@ kcՠ~K A6I_N~KT>yl_ѿ s/): u2pnׄzt(2^NXo6?f b ƨW!t_75ȥ ip;Tq f6?Em0~ߠ*=atz||(OcǶ\d1Cy7aK4lHa@5~޽5!ӹjVX4 2~\uM{"0\mM6XIlEOg M@9uUeQE]cȏZ_$,̍˖05= '$N$8IP5QLϚ=F%{nQM[ćq,v]nҀ9<Njk32ԗmeieUu6-2?~!+*Ӹ~uCӉnzKQ?-|ȪGбLػ6g˲d6`@Dbvm(3%'%NBPcQ9;;ߝ;!x4&t˲fٖ@$MVT,CZM;$CToEE8zvrV?Ygf[�m,:IDc8^mÄƿ7<nHE䂚NUey^NaO@ "Yy ^ER &B *TPB *TPB *TPB *TPB *TPB *TPB *TPB *TPB *Tb/b~_ ?lڐ$y QÒdEv"J-虤z<O-~KQ15G8#zt ;d1e_:!Z04?|8clNBPϐx*}sP9=] h|LG?)F:4˖g bn7NNQ؄:;DYut}ϵ4Edf7DlMnۮOaRd˚<?UU>{&vXtU~x}=9yl_]P, \4N9/R\!S$qIaI2t.nK&w'$ <'h^A̲yb݋55 -ǝ*D룕(Ik<!bW&:/61#"~ )#<lS|ԩw(*Eo)2<]\\71 Tx՞i<gXy:=T?կ3βIݟ3TWmrڦ*.Wb|SjW _u}Mwwݹ`D Ioٜ֞dy e(NC<6NO}W5Y;?StO~+"C[Ggӄ$ m]oH$ҥaPusn9'/;C]ڿߌ%&1xv(n)GK#y~877.;0�A3v//ߦz(ByDՌؠ ' d:<k~P#4b[x2m3dH@~xNC\IPʚ0:h< 䇭^hI#Dz v4tX,.[7(b[ٕqfk)xñp3FN"*zkW\VROφ#r77cNpo"ێ |Ḱ>(p3]+{Ic8Ef C7tW3Gv:l, GeFrN|R7l+7%RqMo7/IzK2n77hK_D$MI�},pX@IXm̤n:}P.tv<#۷$w YbG@ EհtKtzKivejR>3Zo~tZ쿽B2G#uz hGaGm_Wj /,SWDOcYyi~ j:x{yyy}}v{RgyבkeF{"wT:)nqk4-P15b˸^R4C74(hGǬbSm;㬤Hlyra%v<A#I!ؾ|8t+QYƖ~̋ ѽEe*ve=e $oWfEYdY3ËND#9tPǀ:M{ �g9 @)!iygt?"[[hI !g~qLW24-ÍRO@Ƨ\2<ߤʊzK^^3leb<lcպz"9Y3?YG~A?7iXȠ|[Η&V`Q[2h?} u8kڞ)Gm2�QXM \ b:Q Ϸ Ezn|DGKaiۖG0 W3b8Ġ]rIH[bI~9zc:MPݷNk@w]^`.?mB׬ich~̻T_QѰ/Oƕ-ukmZP )z[>\@l1( ;OH<$F~:nE>6#ٿ2z` ׶q~43YçmJ]<b 葠nsk&&L_^E/) A:fCMyNah2q5 4ܠu{(2dIdu/Uv(l^Mj}xZ-jE 8a@tˋ"fkGX2;~-J/>tJiNX@kA))h]˓BK[a&Z:?Q,k>"&. zmr[k]vA A_Ҫ {;ﱈPγGMS9o g:4˲D꫕A e UOL_/Rh;;xAdІプpy*q1kFs ;L Ku39~=b&:&ŁY lw$`<(b25=bZAe"]Q ,!ZlKH_Aq!hFx/ OCuL >9[%X1Ox`.KX&y!aNz͛z/ςbxIvH(HC϶!f lNjcߵq AkVjpHP8O~i^&(p$KS 49G7|Cc8Y+%Z]q.f#{sͨ%éNYdZMA>x$N>AeGaz p bm՜v $BșK dDËbWp VϿ>BJ!ɂV#�e -֞t{+huybѠj�%9\|-_ "Dg5 ,mؑu'ʠcPQwMsu3`ռ^ QekGĔ6|jKpx/.}]ҡD AA ߻> MȘ(&lO߷bL.n8&$Ia{x $AMUR<GO9ګ1)1E#@-+3={|X D%s,=my D6H$&ԋjckނ:)E,$6Ŝ8}۝Q7M#"1_@Р)c~ACqk `bq4p׮8E j |2N&yc"ߚ+ RQiLG Hy ӳ/ EXA^ ڵDiiLxDz-}Syg2ծ( A(&\ǠXu/s(r.X  :N6l\9hdzf][{gm tT:JPX}sB\GY 7�Ѭ?x'.բlksH@@OO l,ƞ,~%!CjcǖH!<_=a5mU=:: .~6|Fxri oOA[Ƕ#8MҷY\k <F]NAyksM/u`U]7pt. Ɂ=Dtج]O7AUc%%h0@X҉\քw.R4T L2T,QJ]s MH9fI<^_`;Hy00hxr&IS?}9bȓ3ԷM(|:ًQ4[mCmAu* 5Rx5K0 @v# Jb %Aʪ 4L&[yËc@dB6f.~{:?8Y?$J'o!PD1q\ o(r> -#[G j&G$#hA6gx=%Et3`~yP,2ŒU Bńat<0uf TfȒ(?wmIe'ƖěIH�q7軫>)o&Lx/% YUfU.ynؔg8Sp3H8t-ه:\Y 3 ў٠`[A*2UB؍q2ХT82vh$ڵU0&AG 77FTvm,dъGA ج,g@>CoPGW6 ^P.oÞ^CPV0%ΉZ~liq@![9TCtE]6 kܓ945U@$% GXBM- �dtp"r?H&OnðP"X$y@Tޥ#L=lʁ,{8L}>StNΙ�)RI=)=+_S^k$ dkQs Oˠ3AQ,񖛀҃6/_0t${]i`{D!K*wIl@>�16 o'lzȂ-O(C]^LD<AdۢؾC(Qe{{YoYˊap E^DQ ˆĩ1tˉ6K%`ϯ X7!);?xS5~3Hi"�HTym?uj4KM֙A5"_&fn5??ކӹNM/-[`�>͂dq CSzҟ-}6LW#VT>P +,v6I;0 O ] NKX0҈0?owXO҈,K�z}- Zaq$,M>DZca>ds- 2r>Tl۝$;\uy F˴x:?P2-8y( 2aj.{@.!{kT8QZ<:ѻ)m&˿4'{.REO]^yE;SU7L^$;$-Kl+*Q׾;*c�߳< {%mC\x쾑Mwgu@n[v4lڼtbdYABY&*z s42\ x0 79tRߤD퓓>!m ߌ\X{MF Ic##fLۦLo??$4W9Led=X^q2 pkԏЭ>5ӆxt9Zz2\y3afBqM+ Sv4%vi>"5c=0{^z�|W7^./cf2fD;mJ޾C]?^]4zsz. Q +m}SovT6ӏmnWKi>+ ◩.ĉ.6Um@Q y,D2W4dM`P?iLdYx"+F�I(typl#PFsztgw_>]ܽ٧FA= sKʃwhc\=Њ>=y{XӃ㗋G1rai<e½ -] eԥ#ع_:_꽅y9bL؅8o}b)k(×rt U4؟πi9UKn-Bc2jGjIMVu5lS,MCy9 )`niY:t*Mrao֫s UenZoK4:Ua4-2_ڦVԠaYd/Ec̛wҊIe 8bzQ61 r*=TпP-0fi2/ȱkVx8@ع{;ETÑX)djHxxQˆKKTCርM{Fmg@v/u U-�7g!'?@ 7 WRjﻞ'xU?eQ+ʱ9q3C>0WpOetfbDerEw iNZU2;:oX�bJ`}c!)Q(qy6b-mu` L }_to"]Ӊ8}wx$-~~+{S},b.u4i޻=isb# 0Q-@='0K&`Naq|DN?_כQxrߠQ.(H£ yewV@%~ĕ=wXҾgvElYR\]??w!sY�?#"W>ok6%Yx~-Tv>TDYƾC ?[0"լe&y̏WD4? -0,ǵmC;@+�⟻C[W$zYXTw7Q"#YPc!z|_D%2_'}-U)QTY* ϿC>Eqh�7}K]p<s܂ekG,5 G;xJƫ~4w7BEm NVkg@QT'BxMƵOJoِ\d ^$*Kܟū^L~d^c[> U+Q~/沪*|*�T)~1t_\B *TPB *TPB *TPB *TPB *TPB *TPB *TPB *TPB *TG /oyoo[:?xnꅢ7_CDUP&DjI^|6#OyzZ?caC[? : ѨMj:Esф:NX MeXɚi9mYA4{Tdjj@Mꐅ/qcRt3#Vdyk?{ZwwB57L"u $ii`cĔo_ȪJTqܺk}644m?-(IW~q{QU< 9 XQiVzI)/NĈ>k <8բ”aql'5, l;l]_6Ǽ_2Ue;>d7ߕK8LM];3Y͕3/Gi|5?^5'aa<;}l۹nS q,>]? j4fEYRX;"1F z^|߯hQvGޟܾNxLaQNGFۧ>+i~ F P.;rLaǻz>bo2NFcc𽓳#R3L6$63n``kկ_#<i+ӛB8 Mӄ{d(y{2wslQƞulYc/է`,q2U-/f~k˼6i\h40L׻5oUKt#*3_ 0P+ԟXqKA3"mG<7 Y.OUrUfJ! Fy3Wmv/ε Tó)wtjFe)Wc\Edmbʏ;fg0|~d愫ݮpg8Iq> ƢK(bUVTKۍ`{f;5O} Ǧ?݀˥۲А Aych vhRa(mR~'qꇓeՊ lן~6k@<4Tǽ%pdݕtOOX+ݭbWxDgnIy1 ʏhׯ<dKߵ#&>}zvS<9>PNkgwO/ϭ뜦`O_?~ VGU*|_oVp1}[8WTX`_:v>g9Mv?ow`1XZEJ:dsFRFHnWfIqh+{e!T3~c*q-^~*Hx R=Ę�_w(WҔķ[VŠλ}XǮ~M )b: \!o?< h:E,OH?6IXopzrfY`?yoޮl)0 H9 f09眑(ٿB\vD }Oӷ7fg)/}ZI,,6uKi;,K?>ϨA{7YVAY˖K?`ǿ'dF%s8Sh?*[cѯOsuɜnjԹ 4/תMƺo#А5@V7WAg@_\}{tZCg5t! tޟqv[nD5%|\.n{G{W^^ܿS,L6_Y!i,8tfrpk}([r2GE]׷vz{=c&yjv,Yp<Bd@>U~5LIU^'4VbZ;!VieW6/׷/oJgjjOGGƪڕ{7^T%H06?'ubdnr6 K^A&9Hfs`ɭviw/wَY;Qʌ2l%۾| gvJs}*t=5 I@HC<tt<3�Qjן˾=tkIn0g{a$TAek Ortqv{~ﯿ|1xL|G#%aR\ Ft4Iv*.ENDҕ}g{k]qMfXջ|wuMЎ ם0-$<dd [(Vd)2v!&aM2tMQˏ\ H?R-t #܋Tσӂ埌 <|op4y+,i5$"|SxyF,ru9|;,p"~RWO))o"*$|VǶ* [SW֊Du[f1䁡(nR%qHC9C%Ǐ,9̄iQEX]~*}T�* 5Ti�4u~~h[$AJL t!^TcXnQ+R]Vq"OBS`Pm2{wOcZ^kdoX#|Dan"mQW>fz#Ȇ5^㖪#PK`5irW{^~ڣ$cߏ8EC#IeA(9vW׾6(r )vݴ&[3 mM?ѥy֡8'm׹JDжFTg,t/ j~YjpԚ-Kݝ rx痁fy)3d-YV، IY3y/ձZqZ<ziN݅RbhAON~^yʪ%I1+ZTUa>^l;zRgRIưS5on@ ԩ-q$T)-Ls8O, 9j2DLz97@9ωb }KE%~N2N曖cF?_ݴ]%< 4e<|JF8/+cO1=1=꾫DQP*6I c ǞY<˔7I5ɉR'e06 c_q†(:A(,;SNB(68Y-WfG!p"&_/G'Jñu26ytD؈0neӔLay+1 -r@mfof74j^y*we∲aP q0t,<y<M~3ῢH k oޯ{ТN#c{Y' ]{Zp(Fk'2Nj<|y"MzY }cFPB>|iH0\Fn鳩~Gx gO=u2*R+<MM#Җ"ݞ(޶& 3D> 0CTyr5Sq~g%@=jB" NtY:Ok 6rA$975\|Ȓw_g-=i(sG0 Ä&H$LU }H#.Jir`NUrmtJuJ8֑+O !p�b\l"f' y$DNDlfvsWi¹dW 6=*uM29y[gd>l! ET^LCW@C`/l FocG4+_J-4O +U3lv\a2mYz\ =|<%'h8FWd' A&4X^Hݖx0t]>LΰU4+,OY3,A R\#<lu1Z ;a'U1b~&άIvvUs֘98 ^sy<>WQVe K9وNu*5U7-Ma9Mo69qlxi#6#!9|&E ޜo猠8 r.:ᣱD8Dvp aQ-_ xꨒ mo׭7фZ:*kRZ+}.%Ƕ @ +gkZiԭ&LºNҒ~hFUMê:OrU+ S A,C=cM! Et(y~EHƊMdkB򎥧sNsLꙪJmt39qӇf:Qܒ%؀6a fXbaZ I*bG%~1cUsQ-7ٕTѝؑ-H?xjQ"S 7li^BZ- 5fT+&d�Fsz}汍n6dv{yx`$x�K l(vU}o|i(] ϊ_@Wu\8?.J.][NwGb1p1b*pъ)#3ENԉ^\Ix"8δD^xEq;\MxDWhMm4x=rLYP<+O7c\sCԶIq՝ndr<lx$c(q<>$Qb]d;žsUе,SVք#HһOgk h i�n9b_زQՕμvKFԐM\d\sɲȱ:rɠmwH8:! 3yh60<<pGN/Jt{xH:2uqԧexϱt8dcM՗?#D3sA v�yض»N}Daig~Au4Tr?tݧ˯=x,5,ɰ|wqH?y~]EqF]0zJX7>s.D۬x<=|}D=/KS\O߻O7J6C¡i|M"6CE+ 7%礡bYv=4oGjByXVU8jѾl`8aIV"MjNZNTq{-s7뚬9Q Cf>[lX~UYYEhN'mbP,0``޿\3lǶT}}աD O٥=lGP.`Cgqf56&<at4{h޴' v}[!kHԝRF&k>aw<C>j̝3Hs,xzz|O.p |t n6J %^I+g  rX&JX VNBPE~1UMU+ 5z}jy>@\u{PޥEcJ7r@ +(:uq!]g3K1qH]WsI]YCnƘGFRVEj'oܠFt'ͰSg4-ENwUG.dFZYoac*\o}E2!pT|EluljvvF$`j[92{]PօouH9u t }ZȺ̖U+mCUVύBRdͫ;%(uiA˳qF i B-DJ@k0nMJy)i!q1~sŴ}*`j,['00�s0׻vv˵ٮ'S$1з믏fe 2Ry<T%B5.BH2Ev1xt�x\lͼa haL4̕yVTEd( P@L m EE^5Ol)">LE .o# s T%M �;@><@y"=MZA؏jC$H":( }4 BxE'O} x1tI?@SD<0 4]j!+fT䆀uz~|EǞ=Bx۱ݸ#d# ><7x"9=ј%U�F;@ $y�X۰>ir8Eى|Xz'P.2˰G@ cɌ@S';4I|ߌdE}o(^S'?%MhAh\ D̮֬Zgn,�[,гU,Pyz@@GhD P,œGv4YFoP'4MA$Q~;kT^7�;%/BfY^M)`SD@$/08F$ u,z)+ 8QWmV$9'ɻp,<ђ|)!/p +@$˲[SI[Nk+b?,#_aC,L5ISյz󷳹B *TPB *TPB *TPB *TPB *TPB *TPB *TPB *TPB *TP ?mŏgV] M]A 濵t=-Y4KEb>δ X~݌eq W+h·g<1oekmh MtBCUE7t]9'2{:oNJf)jïeۮkjhl%xxWY>n FdY<GC{8 466hf( puk |uᡶ(dIo$qF'/)hH-k|vn[caVOmV5Na-c/}Fq 9EY5]ϵTZͧ~ٙ`iv8?ƼK5̑vI jxqE&2i;'yCe6M y:7i=چ $y?YDϙGEzv܀fdVhbP/0RJ_Zwa6ݮ@]M' lHbչh@ ꕁѹAbWMRA7uWU+9Ya͋}-Է[ K4[u2�i?1=p,EWڐF- =e~?6a DY;/}#X#*3KH;8yZ+of%ݴME~|x*(".St$|BAKz:N]x:p,YLҚ&y;7K^r30ߺ2m/e'+|\VRao|SebQ ƀLWW;Y` UHU38-r5:"6^sv}ȇgƈT'*hxI -_,nACkcz~HyNGҢ͖zgpeUdM`-_^voȊ";Tf춻XO . vkIry{trٝm᛺?^^^iZ.SrV3\4P5Tŗۍꉛ%Ii0^rۦQ|9( l]y3NTШ2O槧 9xemXhjh"K> QiJW^^@bbGS% '0㣇5VeQdz~<7?]OIcՆ1|RfiQnp$<I<L]x0=MiujN+ N "`qF1V}m_^Rt г-t8 xꥁNd%9n$XjtzEXp-9,9nu0tS9F<2?jD'%/_.WfEN4-.$PsyI (ɜi8[z`-h|ˈtĩ2OGoƶnI6giЛΗ[kvTel~|x~`1`Uw5ijAǣ( `iE WWݟl8 fKVTMSD{z\ l^gyAV-0NA`g`귷oۏy?ې<6;Xr`Y♖4j8J2f֗Do.?MFxtt_BXoFwi杋~+a ե(V]r~8zwMRMtjj5vvz|hFh<ܶ;՘QpCJel,Za;ZӠ@f ub;V+FXr3t.kAX]r[xEHY5t=}{+m}v吻ki" )~^{Xۻ맡b؁gk,Ƙ%aD%sUl=MCre{hdv?mPӷgmZq-ؼ29A6g~Bgi蚚J(qY )ơg4Y>-Ga%q`q+N^kדc $ϒ(J vy^\-o2upt&/K!{ �3:cqQUt'v/H{vE8~xݷ({h\;/roVZ1^Y2;iEƯ 8 _8E V\PVs$7RW Zi%iB9DbeoCKVRHeBQM7/ gXɉ3AQi{% ȣ8p}(q( "0"4%p阒0pQ:ݢtP%vkOr"16q鶗JmNP 9Ar /o5mfY*nEOӡ%n&mQ0޷,/iHr*śy @"J"71"w(ȥy~(PB ՔnErz5Z68Veo`=Ls<4K|SOFn"kz)yD:صCd|o# ίzÖ3o5 zFc(<GNd =ˡw]? T?5 NC:� " $ HrDU{-AT<r45+Lᛈ'oՀzOYd!V"aiDw BNQh`_j6/}:QuՈځcϑ)q]KƗkEsg'c$<xWDLj?sL_.z}ȩ'S 淓bX>y6#uR` S79ezg֚ үmKoaEi�&ˊH.!4FfOSF1L sdb;ƒ58tB J8@wBE:mHCō#q PPnG73FTT i$w:iE3A.S\>Pމl{ 9 ITaZōp0-t�tx(M(A{F 4R][X`czHtd3=DB *)O7y�НhI$+OÆ5 Ȳb|S"x"{(8 mԂLJ3-m<6aY{r"Oa$o%-7hF%bIh qӥq2v IA!HEm)b8hK՘f"^�H Zu H�?S"4ߋdFl[< +FKf`JF+e6o(&%Q) t7\$}}ns%L^H9U8.\˾h>^ه6 e%TSJ%)EF%-wqtte@,xzP Ub´{-PU젞l pgN2w �"tm�t t}h bT8ޞyM03AVy:5D+Lt?5@Bƈ&/W6=JltrA`B~>_�c;12^lebQ @ Fli"v% /�e$kn X�PY\(<CQLk*'KJ]tiRu&W6F獡eٖE!*aCٔדQېEsc-sEL"PҠZKU4Mנf[!T׷W`CUx4lъ:l[Ǯ-#AG'2[WuZyn1tB1&b1%dS(cnBA\WX�DECVSG EV5 ~\t\҈,ooB#µZ#=&XYFù$Nܰ#zUlЅ{=+w/ Q6q=zݻ L}!Ǜ;AA%\''_?sɰ ;4ve"/Co/>h8}siD?"2*h] ?&0t37^KWU:ӌ3'JG^^S(QNgl8ƀzDm 4 j蟖aX ~}f``D ^^(a@@ji#b�)bsc8CH"/)M:ڱcO>AӛQ ߀ⲍmC@%A` Ud43rPkY~h҅=yP4ĆȴcˣYXyXEKOwDS998>riKV1v�!>FBMY3x9I]4$9t4,eԹjyأzhS.]*Ahq|<kZȺ&`!q6R/ۄ"k?T,K47A}+ȥ;aУef\~k oؤKFل'M"A?TEWu3`z[@CYt0m[o0q"*.,W KbH^_\jHU$5]5\1tMb*s trƘi?x@萸k[6QgEV-6th.C"Mn.g`Q-<$KQpyU;r MT~� dln[N fa +ŷnP>+GWHve2 ;.~m\ ZRn^9>w[߾0nB&2̈7"7[l\.]v9Ц)"߮7Eqܻ'FBčisXvD8A9n'ې6x<=ϿF ϴ̲]QGև G{GHPl$�%F,tbhq>l5yt$_8t :1q 3\P?@WQ"Tשor5Y";X4?4 .(6; w-dh n$HZy H0 m#'ZS"`ˏl@grSV"@[MPv5c 7 iڅh0e-E�u$Ut⭨{J!e }dbF\:` [OJbаI {\nT%3 ЬUhǮ#Tˏ eH}ԟ89)^eD`Ŧ&Ҋ9oNPk&)# !HMis}nCd6yNJ \NtϞ ^Zl~u3\WHP.yagͶpMmrOm*ȏfѠ-4<B5WÇNu9,ұb<kOE aiVWH U#.߮xȘ5dC5Ɋ́nXQ3EEޣ94ǁ|3?lb[KHb@jIU^ΖceN/15Cf�E< 3, MlP`tg: bu\|}2 c@*2ΪȳdЦN 1>/cC5= ƶԦYh ";ӢYd!t9I^'& vЃGڻ *6Z^>$iY D"h8ֈPQ:?CP]W S>LhS"Rüwn&q6vmԔl8bOW[t-ME?>Q{-|Z>ÀFl/BGL+inyIQ<8LFh[B(?ݰuzXy{56av<e`J#,7GPDwD`C=Qj86B 6/a!j`XC =OZj` FOiB9w/3 l:74c@́hhujc!#-TCAGr=q&N1EG"! C}ԅ UmpQn`+(:N'd!Z\#H $qBCtMӌc:~{ tSIQ `n\:迃sUU sf8b#+! `5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5jԨQF5j?8'7? l.ᐼ "1mzՎ6?ˊ㜷89p>=,zpl}VqJxq70d^FaK< 'I Y|=?>Ҽk3 UUEőXE)5`e w9|p߹c'Cp -[(:gׁfqڦi( ^3鹦| >i_wG2y|lCz kvRm, <ס!穬sݽLT^7ubh }^|b`w Tz|E!e~> v=Ξ7_!=X~Լl:x½YfɪWe:'nnh00Q8'.cG8JGvTeD&3Ѡ-]JӇV0 v<KatOΐ}7I[Uoa7VQo{Y`U9i >c8mkw zY*xL(VZXqvu 4M"4ע{6l \K=)ĝX'b]bÑ)g~ ̱o<K؉aͰ4O|'\u'K_e.HZxLվdw]z%uN[(sv^x] ݵZ/@yxzTwY:O"&t:=1,[f>~p-vy'F։/wR·6QNՒxqYUKcl}@N&o0#;,ɚ&*e,CF'Cq(BZJ緟> v6 59s4bEYT@a.}YKz[X鐢eI[DZIۼDr]`msv߶2}muJQ饛7/??f@ȭeL8oaFK//ނ^-R9S A?}{<I4)h J=dƾL{XV D'ZQr_Df} nI/: 8j \f˾ھ}g.(<K%`aƾg*yWavӋ]xUFum5d[Tw0ƒ@y{R@/w{D'RT NFD Iu{sYn 9V U-g|\;_$-۶dL¤(<w1G/+^ƣќ ۱aL׏U'n֚465xV KRJ\dpDŽl?ކڼ=.qƜf!Fy:t;ټoB]0E  ^e C_?~:<>:螝 3$PuϨW$#.P3(bUZvߦGӫӀ~6>9{zֻ^hKz<<&sAc6M $֥x sǑ?JO}9yҟѢ"sstmqնe&2}|>~3Gyʛ^M'oק㋉DRզ-a"9$XUUu>φ$YG7fV C&Z׬(݁ }϶Q7a[ʦCKXGjmF pahŀoa#p0{ aYzD{ʓgŴUd KN6f\pHpC5sͷ }n0GwW胸J??>n ؐ0o6\MsƤ)S%ۏ`q)cWݞHVܢrÓ^- к!: 9{n" 4!x|pì,�'4l"{9>FD|==[wھ#j.3"Gzھ,\pAM l+ֻon`ݔEߎ.ߖWh\隷ݝ6G8=-Y^T4jԌ1*uNtMSy%(Iqp0Ej**":"Bg?8Wg*3v{p˛maR5-8A7 teGSqW4)8Gm^M]f{CKC?Fo9~V Eq%`xxq塮~|?;Pp{[Y׫+QǏ^ِ^s _猨i9AtC}AUGb%uKJiV m"qS&29iqŝ ?r<}(a9ngoj s"( /AG&X]&z8?9(Ei{"3ӏ,zb1h8` Ϧ_S鿿dˉ?dLEd FYjyQ :=c/¸0ȆIb4\eˋmU`Vϧs0 1 ]c_RUq*CK& 7mi>YҼ>^T֛&s$f9z<p!lY*'\'i5Y ^V&!-YlL&z+0$ 8y,L/XcWdp}zpJ]mK$ 鮧KZ(YZ $tb@?Jbg1ˆW3Dَ&ңKAM8;<i` ]%ht7fXF?Y<cQ%@r@EY~ea[CѨ:ǵMKTݲ1 ;i7y Wܓ,2cc `mm>!cc#Ѕ6b-}ui%jzKI(ڢEIL �1] xn8 _.]0`mm?<XaXw9Hg1 M=m.`pp0M.`Gۀ-1}zJqP@<i[AdaB�}5r/ _E|1{yypaL6;E]g#մ1 'i`vTY䚸^1|eIf$iEdJ1+߉K@]UWk}&iվT( BMkyw)J2ĎMֈs2%4n`,E`fwG?n8`-vو~`[ܬ1U0 lUc2 i� Tב&2ӧ߯YIה4ё�i%r\q2־NF۶I= ͂, K =~neEf(Tȓ'Q"6+\g} 3"coJ1=CcMdj:DE!#fc["zR6ef2lOL IQiS3t4 ]bA#|$Pl>TG[Crehf+ل#$\@HBI,íW+͋$plD-)?Ҍ XA`K2PrAen1hv-igd*1%zM޿MW咖vE~B=4ZLffZi t߅[ՁAJL}Kx$FXbhI八p5 ^pAjy_ȦXQ =ăj6]O0֗7ȸxf &%oPWݑÜ4HL�vUoBS[%òjٰ!)~c? ap|g#iSN ]Qs15&JH]+Of3l*anJ4~h0댴oOYRupî[H9%]e:Y~L$EQ9a)(۴=ϱLuޙiS.g2%Dmp@YX5ª WopGuhRԝd EeyuK(K<Ko۶м*#ƽt'ަ&,iYr,* ,E2倩 jM`áfRPn~ :{򆘥ՠ(DeSDAm(_AoEFڷ4Xҁϊt"F7KM; ew Ҫ*0\Dΰ3+-N]Sy>Vw^D=ݶOƼfśeiE ;0h7 ^E:Lv5HI26yv鞝]WfBbLKhd=[_*c[ 5 nF~ ̶eydU]wh} +N9 j,pٖi}߮=@VF'5TFFjW`Pr&66ic6[~ٴ@D'1+Ö46 `8 M&)E;;OD,S,ObY`DG~ojF)Giْ%9in J/U_OΟ dkT­GvxU#y ^ R �3Zu 7@-M $6%Ogçӣ݌CG4C]b?;#Y*5eUaoҐ !s_u!ڵR⊆_ds=RbJ0FP~q68`FpnZ_ώ{CV zSd'P�P3c%Y!ۅ a`#7 ^|ݵ`9zrӡ6En"mą *^g0c!|S1wmh<Xb—@ˊH { R=U$Ĝt7uѷ( (D)|S 0/nh0œ#U:|FYa"a\}S=jc۫ъ8Nb[ǮMfPD~tѹUP(#Ie)ZNo:būN^zMb.qOa^FȂhd ȯGp%~ eZϞ~thM m [F4Q)ac~k;s{qoB[/A #m s H=g.;S~*Fsd <-r jy))-`Βm3/ɞby9j-{ۆʋ΀U')V /u^I6>pLY0f4_9,ۖeBBBH %3_�\>\S3H<E圗仸KK08xd$dYBՂM=[Т "00uW-sUvyz*,J{I,荞]gPO>WMϷpr JEEq%fE͛>#Cd"CKB=(b¼C\GΏ,�KwQ !d}aJⶶ@q5Y$4'WU^2 aj PKh!0M,fk ѡ(H|x=$\Uɲv2Ot ͉A % }?QYoapW 7cAB@JķğwƒAR,uw[<]šPF ݠԒ4s"qت´~aAa d`(uJx-Ѐ*.Iw b�⏟ىoH4N #I&:cZEq/ABaǯ@|go㬳%xCPi_As<m6Ѻcn=p5A>#Ce)$w;# GMm,QX8 u'D8V5N~$ɋH[Ws'� <�?cL3B *TPB *TPB *TPB *TPB *TPB *TPB *TPB *TPB *TPB *~ L iw,?b)#8AaH#M7,25]e)J;Gj~{m$: jwdIw^=SN )$iDHA c=4' $Ã_~}o4:88'e͎<=KSe[svw|٧U롉7"EMvc3}-ŷA,qw DEI}?غ+fr&8Iu n"3[ 0UQ{|L1mS78@N)`0hw'$#y͠ڻ' ybH5%a`+<={|hxڈߋiٷz՝3<K;dTRB9y"b/s ő7(0hN2nںN';s8|+|I2] ^ZV:,)I;=GfF8N沣/ߠl3HϷl߁ J>fcYo"h~ArŘsf˫&*qwsi7N@_ ץ'O73q2Cby)Qg+-ޮC]7)ANYst'>}.,KCo+VzxIzS63xSq/&`ӗחͺ(r<ŷtMx9ESG.>93ߖQTsiVyaрng+H^ W݁`uey:ǙXt7]&~ij-d}EoO^>G-'jy}-r\Ydi[Mh 5ir>Cv=h0wpup8: ;(^_�)ߦC[WhFd*v|\:dbQGa9@ܪy `e.|"/7//Oc;19Sr8:N.n·蚢e=e "\foTx3Jmixt+vqKDY@bɫ1/[QϷbej+ aJ hJs 2&Eb4b%+ d((heOg&oAʀ<T<G`%o3 0rɗۅm!۟3 C#9/{Q6L7חחXe9Z.)b>̈- -18r]e8oHA35 "HE|!bZ$HT0z(ty~yh=Mƥ0nʲuR WL4(|7C_O{(p̊Sl<y $íf']VlX{<{Ț!04K$҄EkOg_K(7w_5Z^݌'d QjTIx*Pn׹<חB9#+2ϼV^~&*>p(\ǃxW1fknC뜞漆?bVJ8܊Mǰg Xa-4|uE ˿HYQU$i+{},y8oSKx2 `d%aꪆQn.^)eaKfgSMHV VNP uX8մ  ~pyޡج[$=\GR@";HveڶX J6CDOϛ,HkWvi>~�L[d8YYxY!t8=B{툒n9�qmz"!.-tY׋׏o+8g`$ J M8u�g3BH}SKŅp.bTn\;h7Ͽ\4ItNϛuhV5(>Di k)DZ\~Ct?|z!+>n&OBS< ~ޮwAMty=/N/3xR¢Hc<tUMWw?_if ;4BGh $:]E~ű@.8Ax24P2vt販O/ A.3 =P&.a WWcK{2ڑD/(,IQI%`͐Ǣ,,<Xu噧/C#.bVTM?v #a>  uQ'O)&N r6m.g OJ'iB-itB9-(AC/G!?>#PTDxR2\E1זek=y]`ˋo7l6ӕdxTiO",Z:هcB3˪!0%Ap8lSݫGo{K]G PKA%xٸN9xU+3%炚 ęX,&vfnQj{y5nY�:դۛR,o-t30:DkGkei}'q'Y{LpfX!ini+Rv<:}qkMHW3-gٷsڶcܻ$;yfDt\%8Qhu`pǶj ',ǐnٞ Dmkde (}~;A�_I%e;!DB%8xQTݰ?.7ж6Igº@=ǒ2 }9ue?/G.  {6$,'�Bo7ta|st[&BE]0 z ˇˆ%<y4SDx[ =ǦC_ǛI䙺4m~jŁ|Wtư9$�GjAs H<{IMx.O_.rIQ,J V])T(+,,9ieP+ML 5itqA؁T=<ü<0UڶOV�dcN]ghvy9S-HŝͶtN"HC흃zyv_Y }'N�JA)cPt/T#C:aQn5j|af)�V0!k $[A]`$;⊇n[|&!y((Mb~IqA8<owwe0DRja"X ֠8)- Lə8 :ߞtM$^taҧ,oSjuAA? A kQTe+LwF/7gSY3o|hA\.y=so=`bK#r?e:n{'O.Rޙ6$ime%QDIxqU @�$^rɢ{zw&ƳaE)bDVȔ(deYU@Z9rSibbi"h;фlo? =<m@ZP-i(3<Jy{~x|49IUUEÛ֯E 74]No@ϿGpFsAJ52,T|?bݲJSh77s>+ h7䇃V' 1$P-"/7ˋ'^t|/ >7̧Vo(Hj\=u8~4>uq`c"Mx0RmV$Ii/Nmߜ2=IC^4)rF:]6őF0 BoA՝y6j,˫d6`/fm쀺Tc.;:&[q {G6;#s]kC6CNt}0"p,+jA| b-C !Cՙ{`Taf @lCu!7!7w,qptcy3EDcz<sxܲ[!t릈#݆^dej0# 7?Gċгqn'V PiH4iċs dԈ2GXtAy w[HʐGW I2r&5d�T&@5-<V]^#~J5tv<Ő~Ww* "^$.ǜqxYWcO9i1M8-.t=( )ΊKbz]dD<=:eݙmV3۾Nɼ]Q }G$PW LIEcTFt$Fjvt\{+_^1zӲ`:]#b_܍TV[Ӎ$�AԺbC͛n6sO2(y gKt|" -O0J$_:v)ݟ2(a 2Ace2$""P T0J|^3W,f%ֿ<b8&㍋Ա#zhZ<"Sݻ@ 4S7F6AX-!PPW"v�Mwh4Q:պ j?.{UrK!Mf>}1C2!ny<=<Ag<!`j@8EԸ; |& ] t_ A98AFE<ªo^}ʀʷqZ,ˉgaC%!LC[n3ȱt cpf l9agwy I6-Y�S\0(+S [T%HT u'==XHmB0t]~4RYtz~? 0cVowy`d'rk4˧n?"Y%A+Y9_~% N Pn\ qX'mjj\40|j"?'d$ }AU$2šj)H8Yn#b!UaRQO1k4 iO3U3,3KB)i\I.apص{Ŏn]7*elyn>D<ecpK]IΐE21TЭ2O1(;F2s$ݴmJ8jYW桥uXGEi-(2ʜԟP~vFH!i*&2/D|$ΏR |CzFyQ@b4$Ä2/He}ATUwuA q>DMfy:M ڢ!lE U2?`!B8Lp_0y@gn.dرgU doU񿤇eYFj'r@-.IߢB 631&%#,2d^T$q,,( c{?μE૪Mڔq'P릡 h4)2I`D,m1/ri~ P&FPh'"nH0ld|M߆ Md9^1I�E .lZ\])*H,-LmcU8F=*»TU\NŠ8oE"8:.v;IWU m}𿃧3z :P鏐R~N"pЯ"|S?Ls{~}l/F/xITTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT6ͦrV1ɻ)9 vqdJ^Ne/h</qA } َݮ?m{/\/Jз-$ ?[89Y7M;뛧}+ci$2\5Y}F%_l:m8黖!qi`%Հq CېN!mCq{M?i5}6ݴp &nD~m&飩ǻ[骺.\86/N~^תa"H'"w `cM6=$lN&;{5E�f9:Q'.:jM_u4Bԇ#ڎU36כ ,s<0Jҙ KMP.W'ϒyZ둝)55o61+H1؟/b՚=颩ڎq{.Rߣ+vc]In-"ãSW3_[7WC (eHݿ`WL27wvpr[lR~s{v~:+W< ݦĶrFv"+,&a%EӄcAYXBqu|g8"`ەA4P7J"Jz'YQƦC~A?,/QLl{zۓ?6u(uwʪZn@{|>h^ ئi5an;>"u4׳&ҮM!>ޫVZӒ WA不",2A_$]nOK%G&l>˲,$iGg8ES^7bb^7kږp'4ݴ7r'dO>}={鲜! _t`UJ.iC;N/Vpil\y)\bU,?KKGunZa:!\;#px}?9d:+fSz2]gWkYbK~XB,<be+غT;"YQ.ׯrYS[|"׏&)TQ8ƎOBr墫eLczMoͅ`Z|fky~+IJ-FLm7F`<vˎ cuq҈ 7 F z3T?~bWߕϻ*vպ e׆nzkSmYVO]6dWiGܸXr[?kv85O\S}kI*rg_!in'Ti7阌n%g<Mtŧ~vr5"q/ߎZK]L[Nn٭(ygt͗7g^Z{' b;FC)re _ː.~=h28H^ �W;xd wЪ/ͳ' Cv!х_NvO_nf>5NjmI>$ Nw&96KZOƠiF*{svAzOb">_ހ$'9$9mIGme ;[:g|(|N#ۢ b/-ł86rY9dol\p NI'Ӓv/2wCn?ZOȒl"$LrNӯseY$QT s]Zi? ˩܃8zT8;׃J&XĮDFy1/0Ҵ<d9oޕ(7r#؞nZ(Q$%w }WR|&dkf#lwgRGlu/K�~8]|(rB]}9u>=YqBd*f@FM%CQ,pIY:^Ty j]o!\|XI70GzU gG@QmTi䪻 Zt.u1: ,aޖIv8 HS!>_ f5WEŠ?ϛ(je-mL/u]I zM:* Hח=hB^d8 jױol.JO2M)Y^RWg4-RO|P ҊXؼibxaZ5uygCSdߜݛ!u0 ݍ| ig#;aizQF Tڃ+K @,-4ۊ^<,x%v~Z=4(Ϻ$+Q/nf K| `^8trá8y ӓ sP�gB%0_ H`wa?\[Nm@+س:Ù{R([a'Il6tF^~9dgya=yXwݽ[iu0w~p¢!TӟB} Fd 4N]A6xDvh0֯o<;EUY^}ԀH¬wP`ƛZ ,8ةH" b0$vӛw-+Mݯc'`Tׯz&źyEl9L8I5h:Bܕan ISgC.'|@opT!Y_=\eh:ЁTAp~2N8q OQ@XחK7m8bVq%MiĶmYtY XMi J(;.۟n f1럏0 yM \F)YI# #m|j>-e24ͩjN8& zdeIk"> W'/H }q{^w‹ 7">FqRx@+܄l{WVAѹEUB)|uܷ|jqjt=?}/8Q4'J0$:dh`Iw%P`JNP3ZJj KܻT^POP5OF�: t酵Pm.YYb{A6fώ@<=އ v~elՍY& ^$Q&>ҝpXܰ{vqX uSg<:�3i^0OԾQy?>"@|Ei.j�.o]TR�^PBbTŗ ".M˖yC>Hڥ5觝F1h~.[āHac]^}`�]|~yVyr "[.[tt|HNJECy G Ԗ_"i &7�~Ojjy.eI <썩aPFaɺj )SF”<h/EbٶM CwvAS彖 HM?ReϿ|vĀ/uM9^% K2Njb2/,skEC<,R .h�ϩ],BK_?rLYn5L=Fڳix~LW ]ׅtL<[3W3A2y"k*uMey{v!w{X,YNAĎ77/-ݲsqG'3,NAfʴOzWBa?6@yk2ٻka'fg!m'g ioʮxi>6n1ϧwLgcb;~&I!{cL˲;_l }ڛKf`M8yEUKlQB K\Y?DqbETM zF]Fsf#0)AINbhr25`t eYW//" ~!^y`6Hv3#ήaǧySEX-Euha5@Аvن0gU :O|W=hJSߍMM(CrS]g+,+LjxRGMf" ~ k7.}Ri̎+19?dݎ+JϏ[V@[ݞ3I3X�)<;2&^]pA5܂HdEHEY|i_WD4Jφ#^^C(.ÙlF秗M`TQo]Vm].hq]0eo <,S3tIJ]6!f>\K~N@~aTY-bޝ0cI` ƅ39ȚM;]7@Y#_ҠD7E.ƽL= sȈDBy|~j H6m0um/0_И 浇i(3(>" ?/_їcJ7 @QDS-hjuQXHF'Ҡ ק: ɽ^WoY__#D|<W xS0%?1h'#2 e.!LKs6@bHݤ:C*Htxl�PT G^pIYկKP:M]nPrME facacbfX0uSWuN@|ceEIIz݊Sm�\)CPUï-Qj]pyubp {}ޯMRQ&s&n +l)UFVĴ.qFta^we @8ѭb ӌ:eN.GRrEBbK5DEC !yH "i@wpa9$s_1^ 1%x LMXޟ3nb$ q �[.Z3YA]DK[nBC^h=34LR{G?1ٱbz6 wlRPpL Y< &SpA! aȓG&q*+QT] 2 X܀Ѽ2Mo .phu0+JnI⇏3#ӪapuaI鮈1=`c4-a]G#=˟AĂb!f@z]L<Nk dȢ/@=I-1eXYHGW״t1103Bx}Tp8gY@X172i?UOc4b `YV$4hcƜ>cu{==4]4Yj PNJP}~LC*Kǂ|2"|8KF6_�}7!�VJh*P6Y}ckdbOѾa\5Nb4{kzLA#1|M w}|!!L+]tkaC.8�  j_s_~N|FE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-ZhѢE-Zh%xEQU<pRVg'XJ:V`CB5q=s_o3f<NЌ-d Nr)c%H>^MmgM3VB놉|He&@Ӳ !rJRi6da\ $0Ŕ^!=p)xMT{i7 M%4uw[i)͗wd`SD䗥)ú2g0*V-g/>kȫl{tyUcsZ'Qb0׽Ng@=Vp>Tz5BN(Au(];aW!5*@U;;iq\G 4=U5  sq o}9^|3Ǐ̷c{9XzCܘCQɋ@NO +l[gǜyՔML/3uŰ< yLlNQY"I )ra[vXw]M$˚rvveB^j2pb_y8q_43 P*;3El&6 /:ҥ#g{ƛm!|Z6-ۉYQ%n_?<+zqĚvOCq G>Vök)l"NGww''oɜs7eerU{zP# ֕beHgk+w<ݐS7l}|BkASkA5J?lUJ!]Uiq(d b)z]غ>$6MЅ݃'cw uv_:,.veƾaƱ ׉ȉV<jQC. L$>xl!u:={Hn+#Pdv0%bjmcןU\}vmi)"ϱsmU;3My*@#BѪh\,9 }Yȉ4v_u\|wmE<#Q;uX2\&^>e3АoNӡD2|GkF\VU~+q,?< cAYG3aki{MunD6ddU#γ8ɫ]bJ։UIx5ؖ{=Z<*_]z0 OZH7t}CC\]r19,DqiW$׏,X4n)̭dL7Zz޿;os:vӪ.\mhLed.VQ%&墿fո:Pm '.uËP" ny@T?&~y8׃s)<,u֟Wo8LD8C[{}\nǾ57?Ɠa1Ԁ2tׯۧb?h݊"<nVI'He1m\q88pl<xzXj8"{|YqU�=#q\)2lЯԀm"at2u'H,$m(1{֞o?x4 C(|edxYy/.nNUR\ď9.n+ryJEd: UeqZfޜ8c?T` +7[g*b?Jz Xy{VkV,7l{<MYeY6?z{~NǓݏfo8ŦH|=pEYmv*Y;ҁoUdݎТ_n[39IYU*#sӂbgM (V%Y^W2 3qA7Via'ciƼuYfiQ\\ۿH7K* !M$@~VqH@<Կ&䙏L|.03G[:K[_f y<2%w<,>QXՁV @$b lj?({i33pU/pDtmfY!yIXaf�r`Ff\MR&@ & hsj <2ui{+^^PKJve @.MҪ m5A#UQ;Hy60,ɲ" ^NZW" * #W; *`d64/Ju>S@ I-'6Ux<  7{֤ז~Ƞ]M11KK "{i,|<kTuڪjuK^E~P޾S ?Oz+VE^  /;PC&WzC6侪E"Xa 3oЖ+r<w>r:Z4rIMJ2, C&mx "lPU<64]qqm8] lگ/sV2&iK W$i' gCF95%S=`гy*;_%f1O瓗9it 8DhR? uz|SkN1c@s#/ s04U^�=ٸxPG)HhL_v*`8)`>Ym¬P4~ԾHG]�:,;`M03͠\�=!ki8[tZՑi!h :y<d1xqڡc8J83!U(,Xu݆.$IwM r8$@�\W&!!,t][w4ۉ2h:H_:)~zPk+mU/Q�AtA@!`;HI9 ~6$r>JbC\4kAR Ŧlz Z:r(I7Ujh4>lU+@)e)Ik80zn-4ˋ?j@B1 ہZ@UaTߏw 2KZp7v#}J A gZ`E@|D�c�b]N*,,:Us L'"6R%nBv O\Sus *́ۉqٔND&=Q9<ߵ�Ei#8T$*ϛkۀl�3yz2_b}6klgܠo.d7@P%+p&qmvLd>.aGX%8�-B N];gYKVLX$EC0vt#6Fu 0_ lZ~ o@\rF1WC!ha9IU$Dd�gJ>HбAO_X U;[ !ݝ<OO;UgEۮ$BN%ޫ K Pyg3]LJFJ4d1t^4|ll3Z_5zp,owSe 9Ut@;b}b6U4 qaw1hш7NR!]G헇PРfӰ iGXpj i.a< &rvR,[|\Az6ΨYAA3Xs|$g+^#QFimNt 끕r4xc @C\><U fIWS6pLQGw16 C@aJgr:Yp*t<fS]pM7IkA%t@#Î䮡_Yj<^ . __?8 :4dz:8$7ȪM)^>Q lʁތtcz5W"Q?S6[IȊRQģM4"~Y} r<Nc./KF�8zW0n6$#(\xl&Ѕ5B[e&ۈՠ` ݺNkA`wCs+P޿tm՛2mSn G/6q[$ }*2v@!^JH˕{iYȚVX7AO[$OA;=h{I>$5B?\ fw=q. zZ�A-m&@)M lPW54;Q./st~ ?~X- ؐ-�貸x/m .$.C)`]Ǻ.oEv@ TV:Č?/<@D,,Ȏ\Kӵ'Fɐ2ߔad Ñ/>W'%LrKeigpBrd-4o <Shj(v^6R8*GPԁQ'<4 L]xALЋ9[j3-35~:Yp\ =.iz-PPil#XNmw]mdrG#I8� Cxޜ;8j:F;sccw:( Ade6;*bg ^ AݸJ IZs#X6):ॡ!#{K(Ka 'xR$`oXFPпNsJ5,/@4b"]JZ6+p,?!pu6rO'H KLY9]PYRy.Vܒ2tUNhpŊHuԔTPu1jނd$AeNwzI3Œ(@Йً% IYaB V'J"ܦ4za$ 1yxXuH5)Ky?ᕁnQ$oZ@ӏ"0?p++c`cȈH$_26/E5YPjiqwF=[J'/EQ߅$7%@@,]<8sQuuˀӯ`B0Z~(WM#t0#GgPMT],GjPM0~1F?yQRj ~10r7 Ic E`OG䙅ϝr/b'?(W˅O4�SPD%J(QD%J(QD%J(QD%J(QD%J(QD%J(QD%J(QD%J(QD%J(QD%J(QD(O7߂ˏK&_}w编G;mxuve@Hȴ_+8}9`B H0Zv ρ0Zg\ S2TNaɆaJsj\!>IGc} ?\N^j^H B U%ku+al<>>|hU&I_NWOSU�: 'l=V*) ~:!~'Še:,V@PX^ym?v!DIDߺ2Fv11HgBe]F*<9:\Ԣ"t+nIJLEJu1>#{8v7<6 ]/nEҪ2!N!!A/k&-䖴l' <ҳ yHn-7}Iu}(T2!b~lSҠ::5X $eozT8nyLMw՜UE?WlesdcmuxXNK%^m2W3Ixc~k<4 Mepd,MrFm]6Z.x+3*1Ɉ;,DYWew{Kf), }zZ$ ފ:5I7o_Fh"#:B£e+_H$UELv-U *.N<Mvf)1$AGdʳ&M~ϴn6qܳv5A OvA~{ۥy@lG z.t?U^7rVWR%^$ˊvevg#!ͬGid]DV,č_..H7sI7<{jYD9b5w׆d"'ÇFz\RR887fvYa!ӃZ-jRNJwXzjk7'ƄEjޭh )v}IjrT={Kx Km{QՌ (vY|ի.R4HAb=^OE屣x#D2 MC^u4 Y߮VNi#< h:Z{.1s+xۿj1YI$wW{q3R[yOW9G; ff"ːD!ߵ A_�l<[9]TmJ:Bm2zm 3*R[f9~\TݼpӀT8+Y\X û12 pL&x9srd6]}-yV(ؾ%¾6j )^Rl4w# o diE(3ju&ES=Y!#䁥;~L35 v/QZq 9!kRR4|β<ϡ.Cg0w<)8[u1`ۆ2Aۖxոn(*Bݴ@iu~V?r|^}xQnֻn@) EXz!ȈO)5\exh9<O7�@ƗNӇ';~ެײ8mc{ 1ox7ϧFBtj`, ?)rݞQԴCKDwR=IvɠqᬨqqXˆ:Z$7M\K֩-e~Ιv5\E8zYjQ懑煾% hCv>qOEdpX{u'1I h_:4Hw%هJj`AqLI8c8C1tjĂy$ç :Y%TDC%H[xPA$ˊĒ{]xC4I2xM]y`:xnTI3L43(:g!1u v\|?Luu$ˋ,fPڇ Jɾ>[Vob8fy\^Qj4An3ZdY$ɆŁ-u<B tE_[^#,bփY�َcۦ._Ϛts|6R`Ly~u9%-q<6^3϶LV؋!'Ɋ, dq{q'3]s4/`IM'.yd<ߞ}ԑMX<1]8_KdxC diwkX}Ssœ %0O%g.͒wus0i&iV,FoE/ƃ:^vҸ]x {]Isk1 �43g  pɣEz \U 56\.uv0N׸tc L| 6ȃL{_/n(/} Xs2O,0-pM[: %my<P&ݙqB8IpG~)(ϙEp%8zG~4 Ěϖ|ؠk  |#H!O.;ȶ}egi[Ƶ>~;=x6Rh[vP!eY�7wfo*ݹ8K2nk=&XMm$c1lxo6D�|Sp"UËqZc]]6'>T%<!7li)RPoW]LEi|}t\X|)^5pu_xg =CUlXfn8ww gIOyеg66䙂t*� UQUB3(yAoƻ2Šum4¨fXiyȃ)ܠ4L/׵4`b7n}x`zC|t,h{k zߡt2ؚ*3T 2 ;o̒eUB8KC5VOH*b _񹇎 N2%*C5U7&Db% ?o*M<Z97]|0V[ED!Jr~d Ԥ]{,xcJ gIn姛&\ +։ˈ_5Sb1&[&_}B\K\SqU7 @V7m}]ݴ_{σd4%cysܒ0ı}fG ]:]O?};UnΝ@Jt:9{k_w(f xGٛ,hYFB'Ӛ-_owSbDd|mRȏNw}ؿ6 )8l fsb%Iٟ» ToWzp|Hב&C_vUb*ӂ KyX-s _r0<j /)ug(b6zoon2_6E`lDJ oOb2j:W09e7<WS kj2Լ{||^ ]@WbBtm0tv=BO7c:XxԣбXH\M&K RO=GG>0>Hwܷ*Bx!HUC{)*yL]fjPv7f膗}]\rAt )Ѿm,?6i$s/5SaЫPNDm0$p\]ݛ6 b4(ؐJBv ?u+Z@ Sg# }Sh K0ݽo#CfwZR80QӚހѱoSb+'>tL8y݀&VsȆ#Ch,h/ 'hA<K\M&l NB2}օ1Oق+@0L@YƢt`ġiP6%(b?1UFi&HAfK$ò2C|*GHxiN=o ! H57rhvLoBHӍmpuo"Y9 I¢wz>ٔ�GH0@x U>$,'JvHdir>eT;+"[Y󲱖qFP-],@wض_\kHY3-Ǐbe" U6(,L(/B$.fsht `fZ遊4FT%eL^^@'Vtql rtc㋸՝WAaiFpFcZoBUFԚbG5"f3TQEaK '[YRFq`X$ILBG?ZA,, o}N1MꙊt΄b%tUB6�]WU7`(n1F*F;$`t e:!h7Ai8DR t_W%= _G¸AIi߱07(yx >q - 2]슓V_&4CS!`tV& /7`ё9IC >%xYuҪOGx x,%a8 pj;$fE9McNs>4x6 Ɯ}�Py_#5śME#J*ұ3 ]I^n$ K5;Ч__Om25􋥎?0!7+*t@u)c"$}Hf$;m+wf~/Xqodvd!~3}02w^2^oO,ڃ 1=mh}bK8|=]:yO2AϞei~<2Qp=tp?_ S]hI6MEįdUxA(ih[W{Va%d2Ug0Q.+^Q%xZY8<HU±wmlYJ:)dzOJȯ"<x%[y̨荞3VrSƞn3+%$=+h~'{}jw㵤v[Y dejl^\Jo3T'+ Śtn^#ǮHsJv6c%p�M*e%WDmQc=3cB% ݎMgg(Kxfnyj4{fGJl‹rWxd$i@[SO$.yvWm~rosK>Y"L.ՀCNTEo߽<7,vUmaZ7~Hck(\+㙈-5KXx[CsLP( 6tU) 8[C9󟐺x/ QŖ_%Ê$ӻTFNQl2O˖5Ti|j)1lJׂT:7{kƒoa9g\B]\oON.n۳ TD~lRuZlɎǂx (^~a6!PۇJ;B( ޚCFT>0rxQt/R[^uO^f9=YvvwGɪ#C^Kl݊ UgBǛ ŷZVi5 zr}=_+m3 tG[1x\GWW-BMef6i{J-۫d?r uA_@"MEx?ric|珬|<p\[>j)NqZ@,^񺛖EȢ0:9oz5e׻lsLf/ _/yܴ$H]}򊡫ow_ ?<v X~uѰ+U74'3ɉAޫ $'=YNm6`%RAfWhp&Wdr:XvRLHª"򓳋lY;Jw.-zbd+L7Q;t0%Cc{Fq <f~ZT/ݧ!Űkf=iK[>%E9G51C x_hg۔y^YUm4>U͉tWYVl1k!^m7?&ö @Ip"ٶץbŦڔ*ӛVd~Z�E0D;->jpgXc`YB~詳m6F9ͷflbXetf@M$E<zsN|V ЁUyD;Pg=ͯg# |qbW("a@i_n=*]~mRnZpHGM"%*Oy(e*Mh�:|`'C0HR <P:OeꙐ <tx+(h}vEQxBIIH�-y"y)3@C_sV+-m:y̠ܖNhIL+3XL603p=044!]mY,/,Kb 7d]q &l:WoZ#>MxjڶQdyV@Q Mr;>_o|Hdu;/ݗir|ۓ=PXks|DMfXm;4lI�G-&FRxf\|-;-̲,S=dcKiQXL./fp lI@qHu]v [}kJJ g l y/-"Ͼ|}80ѕ$ :$%5^ݷ|:=^cͤ^%pzHOS|/ }uoG+#n5z͋煰&sѣEC VCa)s,B;o Qw06�$FH <m¬}y E =~n6VP.JW'_M{!V\(W`#M?߮]7ȊhCK,7hA ~젿 Jsь1,$"~t>7?aep4iMv?]mEnSĮ|^8B; dLxV<=;X$ٖd"ufl#Z, 3"e d(fuտ*=Caj7ɂ^HFm uvAzpMyaDgcNlF/�,\ܞ %]Y)cRԛXAu R +24(_"%oy԰lyJY6M0+כ`֨v ]R e��&NNV=6Ea)|6zP}yE6ֹ6LD4 fU~OW6G8[ 25*ɀy&ƺF ~ -0&$&w&՛Mj1`eyCRN5Mmʫ$&°(솠 ySbkC0;r̈́9(aqFns9i/L'b Wnd!ۄq7(Z߾% !;%CU5epK E!~ŪN :s917iy @DBXϊ<M]zWTe_уp%tef2u]W}1}ԝ |"M;D54eݼ[f d<g_M^§LO>gEIAs3Y$toΨ뛗KLyo*4zmdz5;=t\,YHHԐU?9nڝ\J6~y݇Gq>btt+ɆސQ0]}隆ļbէ9?F B1oҚwn.װi[0CHojAp#hj7L!ePԂ>vTq9|t;;ǩXYqC ф ȫ)NP3g[8�GtHA:$ \ r0*5[�0ATed`%)" AyDH2qO*<0&jAjQ샎ul cG|^2ptҘjҲA * uIw<SOq> Vc% cN-BlaqZm _Wa؅ U`h?&%z}m^^: E<P%:-<ɷU~Xʺ뚧9ǨtjH$ _P2L7̡VHrrMG=al A PC0T0ñLDւ@b$ӏ׌Ӝݜq<(N@R<ԓ44Uƒb@AXgo c]=ڮߡ`G1I*2# 4`AUGyDSo%#U~(MQF,&$Y!=NMR}AB${[y ō "DwTUE:!jӴ}?1T[s2CH6 9IUB7\Ūd$6Seێc]\6 Y^>08 "ϯ\4([dǂH@�JZMz/TCNE T $A/bSS|6DBM>GƼrـdǤD5׊o̐SȦ~^Xh05c(v Tۺ [ZaЈN8Q֝lHu{#W1]~?eVk0ZE&w+^654k0 wheHw Y�qph6U~R5p;97j%{eBS2!Ʋ9ZKZT厦05EO'#^U! r�KSyG󊑖)-vp$yBKTsDN(yk+SX0g�FV ˑH ®(idBscUE9a!sQE2h$A1'plSs̖z�I܎$ 0Ч VbJmPҼģ¯@ߏBV hrH.= -k ?4S=y"?80?W5a{߇)P DY\jkŸ긇Q#& (>]SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSaٿ}{cŒuւ$}a+OQ_z$|B1(kHZ Oj`U{KNg\Tտ} ɚ;}I'@7) oaydZߝw8yr[xL>=N'Y6&=(ٰ= k'iWDd&U@Oм<$m|xIզ]LڎȦzjH_RSŌTe// iNEY*inKK:"O| Y6vHږbI.S?]4H,nZYi5R-?)ݾ\]n'kE#Qw&r�f\Ǟ. ,v0`edǤ%o2QO]Iv7l< _}4aJWyZ&%ILCA#MUj,K;yXD妬m e`^f4!xnZdBvlrbmJ"1)z+ň*vtiѽ;?ylL,K7oIv/B76]j*$i'0; 2uyھ/~m i4˲ns^RCr tu(c7[|o4޵MBGa}f! x}gxEO'$ly=IG9Tl꒠{ܖ9ٌPO J7,?p y8?o 2B2;y{zi7[IW8m|e)A꟦_40M/[6Ìթv!Z wei^$Iiqyy}o_fOtoqܟ"w >гqn*i<FzںknҔx kz]:ro6J>+Sr^)4["?]]Vfm dUonZ$  E߻a4'<o5o "0TG*6Dp5*Ndqvє '.SV W]Ln# T՜$OПjp mSwZĎ%fxɱ녶2 zk䂂rr>W׏Afwr-3ͧgqw:4o0I㾷DVU&O$"c~q~qc8 7eYn;돉dI/eThiw,G |<4||xgD+*3lKטsk0 ,�jI&W5 P5/l=#^fzʤhϐWl2W\b?-cu73d*uuK68+*6#\s\8Bb_́hǑ1퇮-2-Ή"x=^ގU6&%8EQUʹynL:1MZ@"P7@8K꒻?Uc0, =GFO]g'<vTK?bYgNԷdLsr"Iil7* L}Hzc1X1*z#t1eTD`bߏËG,,l,\ 5'̫2rAu0 tJ045%ЊaڮmI>E'\LL'7a{Nzx}7n.V'Ƭ %QHJ"GQiٖ̮FP#& [,9A.N+մ8 hpu9�# , <w<;yFUQuJqG.+b58)~Zedklpyv~Z<(MbboIB2cLif6Σq$1=]%Ò)$z:G{oHg{gzwgK!Tt&"#KAB"VGɏWgW?(d{q_+Kq&c7G |ΰ2zyȧb ~ˬ{azaQV'K%ٰ5ANա,Mk4 $M-9ͲDzLSSy\tY2+AZE@UTh/yYB=܃B HuS>ɹJ`KzBe>q]‡UP2L]WCH OJZ] ֚m=Aм0|ϱM{rXԢ" 8$ <*I]$x }Wy~�Z""u4V˛(8LC<Q琹(~~N z^t tpZ ԇ"=}8rŢ*@]ue%0eOO$ $ЇT#.\Տ< ]SwZǻ֐5L/$0tr/ t yAԇqnqx?YK.l ǬSӭ f1rtmۡz{d_^U1/>$sv3V)ǫeܼ#Áą/ښjQ+հX؇i<NsxKp "HiUкVinR[tBH$;??c^lL;q7/{ T梀'.;SqЁ!Xf^�tTtд GB2LM CFpU]>PsQ7yHn;~T4(X]8b6 2t`xځi{<q E'r,C+шG|l9V֧^IjnuPXM@BBjuti>w6^<Ϟ D㑕AԡkNXVeqxN5ns;XZXG"afuVV0R( W:6syܟ.B@` Tk?2KVqxRQ"ܪwj=u+A#~j=6cxc2Z+5|%U74$1sFy:[m'/_lD7 iegմҺ<o-Ðd&RIo~^bkyMU ,mu'`Ҥ޶nBg"a %PBH=gd,2pHf/A̬כM YA!|*Oruxf2HNX4]ogrA#y-8I} 2bOSyI-na0U$ݗp<<u眢"Ω,r|Hht_znʚaʔ_ ߺϝNǬ&KvEBϡr ~ f#zf+[&z#`IC)ZFft�#n0~zla"r@5`eʆFHcj.)V`+)$, [KNFj =?Y &cq1D )XI+k4rwi,3MjHLO (h{i {IQzDE2[veB{Ndy/£�7Q!'+D? >QݞEK v ڼ +ywG hnWM ' چW$]$!;H7sI ߇+_gjK 1KvҦ]{=BWWWovioDWzt/* Rdb}/$555W4VYb`)�_.5+@"RR Wãy zdž*szs$Զ gp8M"+l8I*f=A/}=}双{Q>+/ 7Mq#FP쐘_bgSo@⇎~A<e3 ]&G8]ע)*+Cw>kےWG_wAJrψH?[U ØDLmїwx?lftʲ%.v ?YȖ$ؖH J2hZʜDA@V,ϳ_d^a[?ܲS6q<u;/|yK@ @ @ @ @ @ @ @ @ @ @ ^ML?f1cmSбn~"_lXQph ^/>P덈'0$rWDI S~_ys|!_Q7O-n V!f(i}j4MCNt O;InxF\]dq.t<ۥx(LďvnhRPX<nB*&;ߌ)E=ױ0+@Lkij0ı)J9z}Y+ȉ#48_Rw<2"dxfJuF$&ȫW7sH@GuUU7dICV/k3$oȼlyY{E5(CЪW4'"su^!'kQ A#I1(ȏJmM9hAáH(UU$z 0?CQ4;w`Cy^=ˮ͇1hQxnGi8AxGXT�)Xekcg0żxӜpeIޞqu<OF65Ơװ*L斯߿]ܶo/?nGqGI3_Q26{9t _.}u׸nEie5H7iR_~,祑/oOחm 3/g%[s5 l$,x-7U}.()~ڦ@VRjigY6U"lO7novAZ[loRH)' քS-dz5q?m__\^=5r>xnMPh$&aASzˬgZԝ(MCP8m>4ڬb**,`ՖAsJԜ$OA9C<c6B =_Y{X#Ƴ沵L/-[ã=\\9t,%Xm8>^5Z4TpTjJ̬ ?-3Kd!5/ې^;:=CeɓۛۇgZ.ض& ոL|D3,mwfaih+Ғ?~އ^vȎ4 ,OMnLqj;YY,\u!hDI~,ܓ ԽN(jC^RTe^Y6ݫ �_eYGj0N1>rAK!MXD IInkxy'AUؼXӏ* O9uМmpԙ F>]w^:O;Ms#Na]p>7s n{8muɪ Y;sO 7Uưa}Ȧ227=Z:3NOXC; me|&XiۙE0Ѧ}~?E < H(2 uaE _f,ìgZQW/ U')u|G?{`"tT0=2)MƊ 뽌W'z0]٠0y6Ҝ(`X6x$cڼAZka/^8;NS9+Wo^qs,,M|C># \yB^3T_]v?H%g[K摾ic^dq@л˙ayPSg`4Omr:}"& 4,s~1rYJMcP"]S8XAVַCN,?a.YlPAg2@IbZt^qza*fϜ|pb' 6xqY{gœq}Ӿmclo@BJ}q7 ۉ7/v'6_ H2YU\{}$syQ&Q_(,szAWc+sȖ t[Xn $3Lάt[upddMhH4=-{\>P n otYAD\dLo4t v{~C<StK-(v6?AsG<b:cm}.,-wVכ˫ b!M'𮅸~冂:xQ߸2hfw@xt̛LBJp=Kh]q7 4Ɓg:׺ I3 )Rطio&\:Wk=pE1b]+�&]T'mƫ ei.03[8L6S+䞲n$]σXOY uS3BR1* =e?ZMrbߵ6zB?idꕪtj1D ,y<k:M2WkV<h n9t8]fcjA8,`~~ATl({cA>De[H7O%"mgj^ 9:yJ3n2yIt惻2UeiƆy>Siyq+??-?:u0x /Xv@P E@\.,Pr¸?yL,$O9R37#նm/{x#q,.}91SaI~~jΈ&q؎zvG+ےҧ]l$Qד\н5ҏiX\ >>qLv.d1:(S/h<nt _ N$a}fAn!*~K75ZT/ +tD:dPɘ|Ak,v) ZRG#4?e/j!KpBhQ*WrhL*>?eع`fV7~ٯݔ;dB 2<A@yM3rPPCje[er8hnCil7 :N\떋wbР -$2nxWAC54 WN s([-ȳTaͰ$qLf*t8F#0۲ ;õ$y&7?5.Ɲ%~JEUŔ&Q8 dqM$-^UaږA{1>{.E@ХjFxrȆn y{w HSTۤzoP])QiI4xk/DU)*[o @`:l8WmQ1_rh?xy.yQ(y&(*ұ� )_9$>UPSQQ C$i\:bxO +*"ힰ@bC%kBn N MںRc`n}D f8oYT"pfQO tO9]ॏ"M7@C"q\CHI`"mUI%ScPX9<1a)"MUeqn͗t rJD|*a7xw&3Ы+IE|:OfKyyB/Q1*gevl|E7֒FfU=#O~V2>BרT )#f/*~I+Z'NV<ˠ9Uf5Y2&`2_b><=ST'KCSS2yFe v])M/6,TdE-΁mXC:eIz]܇klVt<΄<w\R*~o* Cj` BRu?vҾJEv@-/a6oO.$ JAm@Y so#'Ak3ʷxf F 2z.zE*d ̓eksc 9LׂB2 Ѿbɲ㳝o-K@ @ @ @ @ @ @ @ @ @ @ @ #2l^4?@DTf,~4Me4dk <|ăufOrO #EUY>R _E!v ?" Eτ= UIђf*nuih|ٚlPs0uS3QU;0Utא8<5>%#]W Y^ iG&Cx; '*5Gܢ!:Ȋnw؅bS+A]Օ 5S(uz{5ZA]U6OI<@?�ı1s,K"KhO:lu/?&YlhqBE Kq5vOT�W gfB,C*腢nM0 \$(ncm�Fk1-24E??b^#3#,ruO՚Sv#u UV3$ш__*R1wU+m(p <=w{WhxHv -a:Qd4'=M\]񞺼ڼm;gbpSNw[u=ԕV6ֳ^귿>Jחc Ώ_d)qټuwtyٮ|~.~U[+agC)иx*rTe?~ԇ YM?ˋHRt2 '<h^kupHh./˭$SqU~oAجV~6|^kg]Y(jl6,9J^SR>_ғn{cj3E7TZkAIȪp\uvuc_J{E߮+"G3@$\Vi3k7*S=u?7]\צnE|~zn%KeTyJaor6ּw`QQdn> o;O^LeV?N"Z8︷Cڜ)~V1!y&0w+[ٚeՇEF?ҽqSivGsNHچf1c9q%qd@[joaX]:n;)^߿9E8!uginOK8'0ޗkrT[9ai_?Sc]- NA3펇9wY+2,jQhbt|"Ty|<9ӋеuLMaB/zxSd"Uiɍv#?^kp!kۚlϯ/-;m/xglqTjU/>6l9͛WKӎSלSw{y=m Ymc%_*n:-uVN 7\O6^?`G{]~,v>wIjzu]w.jC6ydā˷KWmW< Wg#W|&ZPC߷;t؆ȏC6Sw+ofyxZ<UDQ=zmKv٬׻ˋG`bͮ(Z7+p�g˧*o˓v~p{}W,Ggv;c5(P&m)6 CGw} pP~*+Y.l^~IjUM'})f4=nvI繮oO޴f`MvK: HVf|<EIzl/L֛3-_ Ctf\ۅtW%~4J?^oC[rlHa8@i:oank2op"nOAyZy6$ivdZe(oDo3$%os]p@ D%##+ Ƽysq-]/̠ n 5D\H^ݵKYv ؄&RO'G׋ L5Լ4 </?OHj iݤv( KJ@շφOs@θWXvz1n@S3МhW!,*?/�g]UEy.F/. 9J(9QU%yhlϵveE\"_%󟵷i^(m7UWA/:o2 LEM/Gak; C(k^oo[ bZo(] o0A+˜6]HZaxlGkj>&,M}i:1tY8r#݆z72M nAn١3mwMX"ql<D~KzʏmIBs0KӘ9N!U_j#ӡo |Sl7H®6yN\aB$LʎہA@A{m<yBy&=aW>YABW>Vf$vh}E,iX<e{mZ#he[b'4Of `—cޛlZFqVn6ota!&ǒȳtݸ~laVL6yAW;o8z�&M7!` p/^ؘ(M0kkt&ʚ&KIDp Li:1(Zz/kCgz)ҸǓ;Ԍצ)}y]^<_냅М[S4 p} (7VFݷvL?h`#S�jY+ a}/DYUV^Ȥ-ANp1/X(2]rԸ<;5&*!Hw8Ⱦv1iLkM+x]pcE~T,v:z{ zEL/A+r)iزLC^NfYM5D\`M'J ]189b(?~/VuD4M"~:Witgo8ǴMYM͗fg0oPА/LC}&>|#-xo8 M^-AY~~&N7װ큁JSh@m|b k:D.̆`:_tln"b۰G-1 1|1" Ѳ%HiqA0t3’¢}۽d6 Hjp4G'qBoAr,~�Z(@=l/$UYRiL#,4 #"BTXDd!=/}a󋙬#zkZe^t hc_Xgh ]Dڪ)8 GxPg"!72m ;$e&?c,gPXi K�Ϻ nb0a/ˁN/3-giצ}Ͱ$ X50t_Qu$>u~~d8!J쿧Ǿ/7t+}/Bv� 'm>9 GA.ulP{vy!h9D0W+L!uYғt0Ti=˯U~txES7aq5u{bS g.`0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0cD0RbB5) R Cc L:3A:~XбKn"Ð0 Ȋt\7,-"Sn)$lzqXȫ侉h2HjԢ$m)ea< '.6t8&6v?XЩP8n yF'.!:_CIU!Dw+":?V,?Ctݘkudb]5FjS3:}h;&"N6$<\K00D4Bc=Rz# t( Cj`ijumZ0Q%h0 [55"XY,4sxy2xmkGǮyR罧] >hs ,$L}sh؎esMNWA{ZBv`d܆d02d^$a>Ǵ!lq¸z󋫫#w4 b~o#2=+>F$X[ǿkm?^7@%i#c\c9M:OPfuRVq҄~rwoN,ucI#; -}3&$NZ;q«e[B71w0ZɊ,ٔ~1W02A__<?vGy.}g\&^qሻ>ou:헛GSA{rLNkY=i*K\`yr"stWڞp )֙)-D4e�C7$moe:.O$Zo?y{yzG~Vvb:^U p2.ͦHmI 7|hE _K:)0 iy<|yxx?箸y^iy?Nf+<ۓ DaRV1{w'\9ARsS=*NfEUJ[=Z;b)cSEK7-{n._x=Hu",Fyfhsv:Q̨\g="AVdmn =f:DX2aZlUO"Vˇ>[Gٍ7t/)72m/ ,q}xٔ{k<=\줈mƠliK*\M p.7'+""]W\?ItE2�QԓW}# ~܉ӺuL/?r+ʼɝr%yBm`#pvx?w3,uP Rz|qԀ2W"K} ~r-22zz/0iߜ?,߹x�+' ARgpTAZ&gP/,qyAaۻ;LK]E:B hθW $<-Ufx4/O=MŽ?˳]5+3UmHKa{{</^C}OpϱĚw3Z۶ jNmi>ߜqϲ@4$~}xavuxa\|G>^B!<?:<˲$N~>kul6.&>]\Kkܳ5e)fIFzƓz}>9><<mU6Wg `n.b(a4`?誐惗\M!gc ϧG n\*|#=?m =庾kyppt|#AeYY:A؍u 6Etn'z~5?:::>yZ^H׺*p[]rMx v:2EUqŠxДxoKϧgW%$#(&^ju N![yI`kKA4q=Rms]ϳۇZcd/O1&00 hX\<zn! ݾƝB@cih:wW<vB" lKkr r=yeYyUmҮ_=/PeU=X*[kqmvp-$b깎3A�Zn6]9Ķ>.=,( X"XyHSkAϐe[EI&g{*2cgs#Յe r<=9Io-lv,ղ3w=UXx�-}KIb߶q\ME`~5]dc4m5 lj ;*^CxJ Cu]'d l}0yMV3x]Y !4~6^ *T B6}ǜ;l}\6$,#Tџ 0N4dfYb:d85ֶ4:BJyITg{hg줃ШO}UT`G*EaEJP`\ G> \G~0P Chz .b&O\7JT D(I$ttqպ;C8Z7L[~}lEj!l8eN[Kȡ&]\o5{sV2!RMӌ|zLq27=\Wo9]7 4df1Ͷ}b H}saf}~=艨똤*[V'x<S/jl[*lbcֳA:5-i DžQc|~N= /鍦t2z-mMˆ&Yvyr恖2xm6VݛlxUQeJ<9`.!9wUfXh`ܲDb:5+:tq,'PvCxK Ѕ]fu JDTUY$+-SW .wFB$'˶alĪIaȎBy@3 Xc~R zt:d͉ZL[Y g0LDt8q5btËNjE;o̶1,NjYmh`{kY78 OVyMC4Lg|-ǯ+Ya9,[Nc!z)\Vk:|?ʃU4rsOߛ4lM6^Q ߀a-,ޟ"hBy|}rFv- 5!z -bv_ 2[EZƆ_4I$h#7LXc-"q_8 6DsA <լXAyAnR( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( B|"aK'6˯{iǚ-8IUnb3ˏEY}`n+˧ ~ls_Cݾ*kXY;p:v=&wk"[^uldT%ke/Oȵ,sX, s&鶭Iu@*#FmM?#׹;PUp+Y[+=МeGet}47{=>T/JX#+rDC7-se,`:侭x<_+uS)[yXfnQ{P"3Ah$ܤ1×5u0bJ|ti7e =w#Zzb6VvH|ϱlS.BrUR.zj:ZdšAj_y"ET]UTI`7C^'TD^nsu[2> <,TZ4[Mϵ_N7**#z 1Ч׷s. w,1o9FrX*<{$*:xZ叭fGihLFX/ק߾};),4jEݟ_V@4 -\ eO46%3KٴmBtvnфIT;}l_J.{[(t5yq{VFe8Z,WBv/^4VG $MChvZFWzǧeܹm í[^b \[+t ,JGvGGR$WaqwZQC \ao[O[ۓŢz9iIϋaY̨?Y,FwUT(aO/oG溸\4} NӮkdw|%(//>-}?7G ^=(|weqVf2St8=v;[n> FyD>.> 0 ݍwmu%Ͱl/^L1W-U{+<ϳ, ݢ段p}e6Wd*3kݔ+U@g%_~/RRFQQ} 8]ch^~̜Ey<hߗoP#c-sLl(ZA.Y6}gC+ہ!xXb̺Xf 9O-YϯFGF><N|6Mpا{1U#|hBG\ttkr/0"83F툑YQ˵d "oחNg}yXjA\Z g,$8 [cFE}.ҧkFHuIVZ .OR{0qm$i9^.:ÜWvekybm' Kvyzm)[t.}unl>Y,&^g) g\A3%>Cd8= ,b|y,:xClIvߕQenyi'LY-lXmxmi9jo.aWv�+ &'I# ٧,C,xܚmY]߾70̈lUJw7(Av,jSxO]LVxEm0JOr<$&~QEf@B6m Gvx}=)k (~e^͇WaAoa ,\c 7TJLւª⪭~ 8J{мKʒcŁWD3Dh)mqTL=іCվ~[Dr}z!2ؖN/77WKՁ66{(PWU , �-Poǹj{a~0[ʆeLe`$o%,*`gaY7[-0'P Var�l*ɏoG,Ƴ4q粁Ml!;]= U ñ'7ߛn:#S F5E".4/ &+Y}]׷]M ic g^&q`[O-p V%Qۇi p-Q6z$宖؊`ފ, aalT}10d\klTlYyBr e Z~myAE IXcxVVeUcb:&,Cs0Hr|ߒ|r\qF҃!u9V<BUV} *"i\[''+WҎʰK,C^ʵ6Wg"qǷchyQ]>"t{y_mhINB^@-d!+s8Mc+lBDߵxљlXA5 | ~g8}%J4\,os抗dq;>)YÍ!څ�Hl:&&$ lM\ .XbzqYX-Tlٮ}PdE&q]Pg&i"qjB ]l&dc6 3QpPYvlIgȵZaxX^t>_n'*4iaZy<?!zv|nnݟoE[ךi`n/kF1CMFA ˭jI#Cr"S 'za }YO7 1tÄlJ}YnA]@҆WkJ^ uxod:}A3�&trQS d)B=˴ ^Stss?5 ^D0t]Qre#ʊB|r#SW!_TO]k umDUKH.7 Nj|iC{6akIDKhYIb�Hs$0=g<Ul(fu D7No'<t SK/l}sf/\a:JR!Aڝ@f(keCjƈuH5U3 >KQcc, V5g*4Sc(jۃ"\%QSĮA: Ϫoa H2L&'Δף*Ff(_=xv&fo3 XFAAAAAAAAAAAAAAAAAAAAAAAAaw`V�/Yʹ UyPs}iێc$ /S&H>LJk[& 1hFd`H4EZlFk&Ažk  'pJ C%Й񆟕kMsNT̡4dQ`?<rSyhir,=Y k:,5S|3 7?fTfF&ll7vn.ϾD}yQ{ ^TeYQ *PỽlwWsI4<6Uf4= >?<<x`d+2Wsilto?^8[+PNNDÍ,pL,Y29_eհxyM-肒M/ shNݴ4'#%HIZ5|2Oϯa&6N΂x^y&wΣ`8ADOq١łr|5ߙ!~㕨nd)\ v{D?'#w㴀ϏOj5}KhD;Y~feQmm9Nӭ% =iY[b�Ƙ4(u^G|Ի:$Wvdi ~K,?MZ2?4RO&ܰؼ@ИDl$i"t/.V%fp~@,ԝ(" 絯tюRXbٺTnZDu|bd -7s"ϒ 9Kכ"o(#*, sI2!$Պʗ^crq~GvfI ^}{8s7M5mK+R2+;\\I^^d[n˵&17*WNZUy[JTXpuEU#wQ똋▣۳S#İ&5kxm[I6/e_B̨ݡ:V5>[ <)o k{db wvj2<[}qi_3ߐ@(}w.[`<$K&@RFZx ,M\[ $ - MjX"=Osc GZT}|bٺ;LT/H4 TBbIϨE~)2d8JA3s+ARn4 UoFyYq`T?+0W(I]5nr&%]NH~Pȥ9 OSÚe.k[Csl _zRG:m=֠:xhDzܲ^`D<;{*zDo+t#AX7FaxɃ3n9}Wpmd!47qmA8CqBUC%d 64{<W<CUU@[0"uEUfjSR Lk()6YIWMѻãByQ"CÃe.U%A- ҬI2EVeEO:qM*4HYYP}^M$ Ay9R Q962°#Gde4PAEYOA1"ώ`8/,l|-,r +VrdM#,Vэ+Nsw0>7 {?*j B64ϛ2 'V?Cˋ'ֆ]D)"M+ bz1zrh6/dv=1exu:d'u|Xz- PQfIV];Ja^l2Y/#&Ds}?[E`h&K(1I6:=N!-lz[$sgòj:cu/l .=i53Kqݣ;~Z_^1dv:/8YUvj 91T+N[K߾uuiJS¸yO}1Y)2rM+YA^WnA\`ZqQ3 2 髳ŧtb6ZJ r:]Cs 1G<=PKVRuw,uT䉠;ϮKQ`Gkzqں{ϝ$@VhiQQB+ ?~xEz^-& ,ɧ vAt1&mCf$l[CX[ Z'ou䄂,ވ!glˬ9P8i/HNNIfQy bh] ( $IMuo./O#Et$[ ]3,`5U0[Ћt24M/6D] nDU㸮 ~k{A3&ŸgL~k Y߁0ɂÒYR ]\60 mgR *JTu*]ǐ/ (@n&P9G8<l(ٗo3g�Q k65kX=`Ij CSAdѱ $&XjL\F#'XV" !$@rѦ:1SsW 461KDk`mMfqNљk? чN` .m?s;p0)$lC^-%3h[c3о Y;ak(ں7KB@1y͠q`jAPDAAAAAAAAAAAAAAAAAAAAAAAAA;7`DEbt/52Qb+f ڰcY`~Bh@2߷mC[ȌUUy߸DˋꝻ-% +M4Yup޸y�~Έѯd0߂p?>ľJ ytݡ`|50v-!N1Ͱ̂^&%^0dyYD4qT=dyiۥz_*Cc!U µy 2yQd/gj9ayIljZSaY6N|@$kYw�Fqk.5K +)ϙ{KQvF$ '۫.\1Ul5+ t N%*z9T1Yt ,_o֑.&C-+k[l?&Ei^e qwS<mkQf[n)u+7SV60.uٺ955Cp,|?6ޙ,nfSfe"7o57t)@kb//矟$֗*xsWE(VzTgR]q)"?|wؼӪR_Ù.wSSH|[^mG´[f-.ޟO%'N"c}U J*=suI] !ó{J0ôȳ8Ņ̙>QI|ؖnHsn3K~ג#;sfܬĵWWN3OυO&+Oո 3;K߿;Aֹo ŬŻfahy񇥓 j])w;Z5un~x]yeī172@w?:5Y!o۾hz{KO( of80]ژyXRA5cdk]0 Pn#I0^fDJ(Pހ{o�{OMQCH3wq=qIUQŬ?3;[B�Gwmlk6l1D5H]ǡ9Ȳ2* =z8#Y8j^zʰa6E?.V"]KāFܵ=<lwpHXGl<C<4i|aCBLJ?Uu 涿=¤z*AY4Ʌt´8-<-9P󫝍| b~eݦ�,$ 3IPcQZs-jS&IXHtF m8_UCɫzL\jK ߏq=Oyp;!B 0 ][|cJdUH1šotdY?v[]4DYchxF F 8w-GyQ%ma ߊ]YPF)�up^r0+"ZiC |UK6e5ify;EuEx:Qgı@ 4)++6 E::Y4axAҖSvDO(Nyun='ʲ4 5@ =h3iʹːb(?Jcnxi'IRFaZ^sI uleᐱ�Vҷ?ldG H_/j?l�aZ%pigjX^ge6&jXԑZRtCn3)nqC.?*eFSOH^:묟*r6|4j4ZiZs<uMs\O^ fNXw,}lSj9Z~9$݂(w\ Vȵ#oyqؖxZO}r@6K(]XkmŽR1x:wVE 1eS0}?:'*e+Kմ{- 7A5[{'g'G1,ih iAys qFØU4EK*<?ė@+KӍK/˓ӫTP[ߊfmUE6d?<(:3*3p4V5]jJ%x^%I8rxmVz̊*MC6+/tt:'9$b<8?:8>9hzނmI޿Ȕ`v` ߑ4=V1Z4]mw{ŭfLT\pֆ +t p2� U=ؘ54Qwq2Nx )Q&Qh0u2#g4ߙ.@ Fm ?ǚC BS$21T/pԻZHj=$Pzs= #&�"a=?\3E~c LQsNwhmw:.snG                          +ڼRyv_)(UEo*B1-KΩ-iWc֗[zWtArJP`F<Hbt$jSfR,CN?dyq~8MTwv՟1-3_ǒa"0 / bx*Wwԩ 3Ns*X ǕЂ"R2xlj{h*"jc̪E!R1||8<_ ԡ2d8g5PVVX:9:s-刖t8KCO f4JNNE}?Vl 4/P37 [nQL'"˫*Ez663N.fYJh9a^EUbph218zҗ6|^T̷8Oc6$t%}.ULϋ:Rr<LM!`&2K|6b{k2.&ZXiZu\_HO9j]?|iw$v@v0[U9߹*3ߖz0[<VOϩ<aB0(\*Cuiu*#:+- ?Y=?)Rv/fqR{eO/mviRX@s_n()v2HN3T'}\fÇ#KUyz`??f&Y߲ftDKѭE%sHJquINRd hn;;^QևT`O _Eb4L'[Wndsgeǿ}2e9YV =8" H~= ;I)+H˪B`_E/M7Bt@*/4IZgNUxJԣO6v4?) XԈB.s{v=!yՀѐIl8[,,.17i\4c^] Fl5ԤQ_72c"GMzkW8M$ERgrK7>0.WE`p/;-qyN=-w5o|aVe v7@ҁRJCɫF Csy}wz7],:(c]g+f:G> ( mHaժH|$1Ƈ1x?~  Go=!~caQV@Oo1At67Rf~B,t)TYYkza14۩hyAQu<8E@J$e\"\[n8χMlɪ*�a[z$2 p C2hΡ.Kh钘6VqhM(^-wljUGPEXc &Wk3 خ!4y`xچjCiۦN?쑖bBznNmq-EYMPZ= Xq=-!G=w#e\lT$ C|)ŴзLy*vqf REj6jW7Xб l{2,/ ƶ]zdgyYB7 k%=0VkC D:d, 94ΐYj빖(;{_G`u)MD/j,hp\ײM9mvvn DUtд. q|ض E=:]gIѬ 2߁'rA)XqC\ؠRf긷;>9=>:: s5[W i/zuq98lj{x\^\^=iij;0LYeSY݌ KdA3hp)x^dEjru,7EQ#g)A1dwh:[r~6cI qؿʈWj͆"t?ak6t_0/+t~[pfJ†zneN�C1%uAziCsNEnW{zR'#1+,4dng(0VuKA&,݁X~9&ݍoLDƭiAAAAAAAAAAAAAAAAAAAAAAAAAAA"۶BTi[ſN5!k*u.?aYj%{פjJXFw\j) Bsηs^o {&X^twslDOu*#H\*rwN4ۭRnَ _-ߘsAnx&VX<eֹJgj~'Y*c@p։+[SXUqYof4%i|k~k:AyVUb𽻾ZSG ʣ .QDSN'W'#=}\C^40VKVRchiEE 7s6~WĖi$gi0KxM?0Sl7L*6秇S#"Yڅ͙N~D�Yy/#=^=G}%t.nw6>|܍ {ߣ8~\MGz7{w6%�\fa0}Hmݭu|m$Xz q=ׯ_˩w_JƏ_]CsR6O3?Cb4OyK'/_)>7:F +G4|;`TZ۟ sN)^ h<}Ljrzs^ZHLT5W ER0}ؼrJYL?KWgCFq,Zzˇ$U'H8\Zڀe|$"~ߦKqT6WwH&c^wۓk%zK^Y0p}Q+Nma먍V͞ayXF)VzDۯ="%sÓ˚>Gcf-F3ڌqE \=rdz?Y/l>j8Jq{*|7?kڵ$UbIet8ݫuȩ[?zP~2hCxr?Eqq:Q&wy^Y࿶ZG|6T9Y\2%1jwxy]L#?+DlGg^pqLǪװoe{!^n_F q̘]\*U4Nu 3&d/}O|EBDũ^\B<6Qd/ /W|\F(P xСyB"qGS,~$BMd~x}gBpOاTU3ݾ% Ipr}%\eGzTI';ṕѼ>\]=4 a٘qHX<% AY,{!F/J)�8)R&S:fh9=Xz'2 }(m[;0aRմZ6 2=Y`jFV#uv V i!fH[Yfot�3X?k>a\&lֲ>n^!t-= t|?쫎Җquʕ/m_-/@BonP$:Jlx;9lu1U2ekY ڷo_P>6ۺJwC1 Qʟgz*#08 orV^fno`Ycӏ·7My<EVo6*_FжzgC?=[9:~Vg`-W՞ږ"7wFf?g4[ ]mF+v3v[ԊJ[YI׿l�������������������������������������������������������������������Xw|"^s }[^Nj&>s Â-Mǒ ;aZ?t$P.Ӻ3 Bpow@R4'p12JQBHox>xVDt]{JMx<I2">闔\=yY<%!ٗPݼ>=oӜ<Eçb4GHt6MXg~:bKsg7ƓYB%Vb )V'<MJ=Iցq$¦޻Z 1#[=0~PeI&\9ʎҡ}>S޼:˗/OO,3ʿ Z NmLg w^i4=<~yYa=vKd"IwgeʓtSQ%ӧ>>NٰAp80ީfA".4NƂS=X2}Ǩyz5^:eƻ9q>x0bVKuc**!#p١,ࢰ~ e2 9GguUUXD"~Zth49 ܯo닳˦Cl&zcL*9[Byy]=6kţӪ$M#I2}9enDHxhvڥz C}~^@}nlaǨ||(v.*z{o wuc7'>|er#\eǠQ[tI%8N(G?$*&Ii`v EuإqEWUMdHNQvLu7Q3-/cuFL)p{Q=T=*5,G *cv,%g NǃFN+O[I}:;'U 1vl/lQ;ɾWQ'й>n*H )ë*Xh,rz+)%_>y< Iu-3}P!2N0M+68RN*<tk3Y֟e5 <Ŝ1F;yiQ(Q:}c(Dh<ķ\/\Go Ի(ll Bnfw*IQn;+MDTV!Œ\zo/7m,){XP"s_lA[͵սIA;@\;si j w{ݺv`q<:ްCj}!WCXAur8X܋9yAPqrxW\]MNjWuCDZAnbZ6B!oF?06Ϡmq*'9A_'rѷjc*?~}Nteu=Z9yEsvnŸVk?-=%w ���������������������������������������������������������������������~k-ֲ ſ04/;6-}g'QS˼. ^wbA؍G(BHNۑ+ӥXܥu!\(J4};tX1}>1n{TƱPa&o{Z11AdEF<h:Mih+k6~2/-SMG|KV8ULtLQ,KfA*V^si~m~ʎ$aPx:hec*eG9Y)!6'ieMt2>8yj@ÐɘΧw Ƃ G*st:{xzzO÷uZ>jceCe2j,RCQLO1ۈHQIYmV#5bt2xzHH{ّU676Rɐ Rl˦Oa$ƒ]"&YhmvcJUεEЫ/;6qbU놙,釜벰STvUn\JusѣRq}YB}]F +8<?1NF'(͞K1쯬鱪\_vI,Vg@tSuyzýn|bzN7V,ǒA猪MNb UW{8sqfZe~A{89޿He ק~su<mp4%Eѱk]$BE/ONIG"ώww{Y μ|T8΂VN-Ļۢ:QF*?ãsF}U.aHih}(|>)Vˎo^֢JNE]jU>*l`7UϤX[״ן UDŽ7[؝0[v_JMIkAs3$BJ rhPF 6uR ,Ql׏`[fk"1c$0γ~交iwmCoԇ͏g6P -C^? ˽+P˻,_J[﩮IH0Ziw>hwV~=ٗJsʎ\VmW+}*U ./O_o.aYU z{_LmVT_8sQ.?UUB(!hEرlu7Ń-]0wQ[eBB`zER/^6MCSSj#_^߅qR5,tPovɯwWgߞr-;_}Nߩenbi7J?/W,6-3͆m5odz}���������������������������)F-V R).3OAS>돦x:|\v;$r9S ( Q84>Mg83d2(&+;|:h:LbA}8N_nzR{Ϣh g|{|1󽧍ɫ8{xx~BxGɓ˓Y &w27K_=hg([3F8ܻ~A\FRprfտ81JOW$b4,+?_g8ݐ;( 7A:) ^K$8MyAs,ѽ_^;gh}q?xd~}2֒GqΕ<&S['^e/ݔ*uh}}OQOä4 /^xfȋJ0n]מ$Erk[;0ZLӥxX[a<M[oo=7d<]2T[^sO׶߼ԛ~v<3;W<6۷ww~o^Rr& sq=x9O&'F?vOOY,mX·wY^h:Ofz;'99xVx}2ZtjG_>>Y?/K:F]nxyF08(>:ݪ3bEd = UT~wSG硇I5RK ߇\oQMR>8h$=?epK^8 *-[}iVo˅/)(q;)7o?*a=_[wx֣ϯN } ݻGo(FJs.ݣ8΢0MWz:-f0ou{tvSq9P_TݍTG‹O۳hm?{A1ߛD0{O?v0Yn:4DE_F|A#�T 2܋~J)n����������������������������PZ~vKpiI|VUj+xMidRzv…gq|FTb}V{hػP?WI<Iif߫:0?t77N_,ga榺k xpJWI/lT {nmڊ"Ko/*h"4~s&~s7Ao:g^FH=ݺd ~w`</^|q6RyQ٩ߺgp2NySW/'ilz囝nIuvtgӳϟ/Ԛ`ڷ[wzQ7L \?^=qv.֒[v&LlyrrjƏWŰ}mAs8Rq5tp?׋Wu}v<9J5'5aӝu㇠>O/v%E{Ѷխ_7ǃBj>FQ49p=y]66q Ep6'K7׭do|[jwZkx9 3z}B~X̧i縔tXNޞgCht}Rrf۬gߝd:Vݘ+mTv<o)W݌A\.VɏR)_]%ܦ~P-Vr3>;8ʥrג^TgXiגI6b |x xVjF/=,yf> _x{6){Q{4fsEoB>K;7ެ{ɏFձGXw7Fވ������������������������������࿣Ѩ*^YN;%N;%5Fh2j ŏǪa4AvP.Ur1ušV<]Fa78_n$?k" Q9opow-NAWJ.|6fwcЅ|<>^q)T_?zAMEbGaC{sh6[gqᚾa&}Y݃d6ϢnB#wx> 3kotљ4Zغv=YSf6b߭L;ǥtVƝs\F7%wi`/mZBZ 6<b}}>Ϩn`beryBܶ?o3t=ɼӎ; +܆=Wܼ�������������������������������3j\^kVqYL;e'qv˩8oXYY<mVvϣIvKdݬp6mͫ^YRn66FLT[fJrv������������������������������������6':ʹ\^H;5703��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������q{l�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/voismooth.pas������������������������������������������������������0000755�0001750�0001750�00000042454�11545433540�016754� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit voismooth; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls, Buttons, Spin,define_types; type { Tvoismoothform } Tvoismoothform = class(TForm) CancelBtn: TSpeedButton; Label37: TLabel; Label38: TLabel; OKBtn: TSpeedButton; ScaleSides: TComboBox; HelpBtn: TSpeedButton; XROIfwhm: TSpinEdit; xROIoutput: TComboBox; XROIthresh: TFloatSpinEdit; procedure FormCreate(Sender: TObject); procedure SmoothOpenVOI(Sender: TObject); procedure BtnClick(Sender: TObject); procedure FormShow(Sender: TObject); procedure HelpBtnClick(Sender: TObject); procedure SmoothVOI_SPM5masks; private { private declarations } public { public declarations } end; var voismoothform: Tvoismoothform; implementation uses nifti_img_view,nifti_img; { Tvoismoothform } procedure Tvoismoothform.HelpBtnClick(Sender: TObject); begin Showmessage('The Full Width Half Maximum [FWHM] defines the width of the smoothing Gaussian. '+ 'The threshold defines a binary cutoff boundary - signals greater than the threshold will be included in the output. '+ 'A threshold of 0 will create an continuous 8-bit output (0..200 for signal 0..1)'); end; procedure Tvoismoothform.SmoothOpenVOI(Sender: TObject); var lScaleXY,lOK,lResliceNotMask: boolean; lYOutra,lROIrealRA: SingleP; lIncX,lMissing,lZPos,lYPos,lSliceSz,lXt,lYt,lZt,lX,lY,lZ,lXoffset,lYOffset,lZOffset,lI,lI2,lImgSz,lcutoffvoxx,lcutoffvoxy,lcutoffvoxz: integer; lScale,lThreshComp,lExpd,lThresh,lSig,lXmm,lYmm,lZmm,lcumgauss: single;//double; lxra,lyra,lzra,lzraScaled,lxCutra,lyCutra,lzCutra:SingleP0;//x0P; lStartTime,lEndTime: DWord; lXDim,lYDim,lZDim,lPlanes,lMinX,lMaxX,lMinY,lMaxY,lMinZ,lMaxZ: integer; begin lXDim := gBGImg.ScrnDim[1]; lYDim := gBGImg.ScrnDim[2]; lZDim := gBGImg.ScrnDim[3]; lXmm := gBGImg.ScrnMM[1]; lYmm := gBGImg.ScrnMM[2]; lZmm := gBGImg.ScrnMM[3]; lResliceNotMask := false; if not IsVOIOpen then begin ShowMessage('You have not created or opened a region of interest.'); exit; end; if (gBGImg.ScrnMM[1] = 0) or (lXmm = 0) or (lYmm = 0) or (lZmm =0) or (XROIfwhm.value=0) then begin ShowMessage('At least one of the images ''size [mm]'' settings or the ''FWHM [mm]'' is zero. Smoothing requires the image size to be specified.'); Exit; end; if ScaleSides.itemindex = 1 then lScaleXY := true else lScaleXY := false; lOK := true; if lScaleXY then begin lsig := (XROIfwhm.value / lXmm)/sqrt(8*ln(2)); // % FWHM -> sigma lcutoffvoxX := round(6*lsig); if (lcutoffvoxX *2) >= lXdim then lOK := false; lsig := (XROIfwhm.value / lYmm)/sqrt(8*ln(2)); // % FWHM -> sigma lcutoffvoxY := round(6*lsig); if (lcutoffvoxY *2) >= lYdim then lOK := false; end; {scaleXY} lsig := (XROIfwhm.value / lZmm)/sqrt(8*ln(2)); // % FWHM -> sigma lcutoffvoxZ := round(6*lsig); if (lcutoffvoxZ *2) >= lZdim then lOK := false; if not lOK then begin showmessage('Unable to smooth image: image dimensions are too small for such a broad smoothing. Reduce the FWHM'); exit; end; if xROIoutput.itemindex <> 1 then lResliceNotMask := true; lImgSz := gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems; if lImgSz < 1 then exit; CreateUndoVol;//create gBGImg.VOIUndoVol Move(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,gBGImg.VOIUndoVol^,gBGImg.VOIUndoVolItems); if lResliceNotMask then begin //reslice for lI := 1 to lImgSz do if gBGImg.VOIUndoVol^[lI] <> 0 then gBGImg.VOIUndoVol^[lI] := 1; end else begin //create mask: invert for lI := 1 to lImgSz do if gBGImg.VOIUndoVol^[lI] = 0 then gBGImg.VOIUndoVol^[lI] := 1 else gBGImg.VOIUndoVol^[lI] := 0; end; //create mask lSliceSz := lXdim * lYdim; //lZXi := lZdim*lXdim; //for swizzle lPlanes := 0; ImgForm.ProgressBar1.Position := 0; ImgForm.ProgressBar1.Min := 0; ImgForm.ProgressBar1.Max := lZdim * 3; ImgForm.StatusLabel.caption := 'Smoothing slice data: X-plane'; //lStartTime := GetTickCount; lThresh := XRoiThresh.value; lsig := (XROIfwhm.value / lXmm)/sqrt(8*ln(2)); // % FWHM -> sigma if lsig = 0 then begin Showmessage('Unable to compute gaussian with current FWHM'); exit; end; lcutoffvoxx := round(6*lsig); // % highest / lowest voxel to go out to getmem(lxra,(lcutoffvoxx+1)*sizeof(double {was extended})); getmem(lxCutra,(lcutoffvoxx+1)*sizeof(double {was extended})); lexpd := 2*lsig*lsig; lCumGauss := 0; for lI := 0 to lcutoffvoxx do begin lxra^[lI] := exp(-1*(lI*lI)/lexpd) ; lCumGauss := lCumGauss + lxra^[lI]; end; lCumGauss := 2*lCumGauss - lxra^[0]; if lCumGauss <> 0 then for lI := 0 to lcutoffvoxx do begin lxra^[lI] := lxra^[lI]/lCumGauss; end; for lI := 1 to lcutoffvoxX do begin lCumGauss := 0; for lI2 := (lcutoffvoxX - lI) downto -lcutoffvoxX do lCumGauss := lCumGauss + lXra^[abs(lI2)]; if lCumGauss <> 0 then lXCutra^[lI] := 1/lCumGauss; end; lXCutra^[0] := 1; lsig := (XROIfwhm.value / lYmm)/sqrt(8*ln(2)); // % FWHM -> sigma if lsig = 0 then begin Showmessage('Unable to compute gaussian with current FWHM'); exit; end; lcutoffvoxY := round(6*lsig); // % highest / lowest voxel to go out to getmem(lYra,(lcutoffvoxY+1)*sizeof(double {was extended})); getmem(lYCutra,(lcutoffvoxY+1)*sizeof(double {was extended})); lexpd := 2*lsig*lsig; lCumGauss := 0; for lI := 0 to lcutoffvoxY do begin lYra^[lI] := exp(-1*(lI*lI)/lexpd) ; lCumGauss := lCumGauss + lYra^[lI]; end; lCumGauss := 2*lCumGauss - lYra^[0]; if lCumGauss <> 0 then for lI := 0 to lcutoffvoxY do begin lYra^[lI] := lYra^[lI]/lCumGauss; end; for lI := 1 to lcutoffvoxY do begin lCumGauss := 0; for lI2 := (lcutoffvoxY - lI) downto -lcutoffvoxY do lCumGauss := lCumGauss + lYra^[abs(lI2)]; if lCumGauss <> 0 then lYCutra^[lI] := 1/lCumGauss; end; lYCutra^[0] := 1; lsig := (XROIfwhm.value / lZmm)/sqrt(8*ln(2)); // % FWHM -> sigma if lsig = 0 then begin Showmessage('Unable to compute gaussian with current FWHM'); exit; end; lcutoffvoxZ := round(6*lsig); // % highest / lowest voxel to go out to getmem(lZra,(lcutoffvoxZ+1)*sizeof(double {was extended})); getmem(lZraScaled,(lcutoffvoxZ+lcutoffvoxZ+1)*sizeof(double {was extended})); getmem(lZCutra,(lcutoffvoxZ+1)*sizeof(double {was extended})); lexpd := 2*lsig*lsig; lCumGauss := 0; for lI := 0 to lcutoffvoxZ do begin lZra^[lI] := exp(-1*(lI*lI)/lexpd ); lCumGauss := lCumGauss + lZra^[lI]; end; lCumGauss := 2*lCumGauss - lZra^[0]; if lCumGauss <> 0 then for lI := 0 to lcutoffvoxZ do begin lZra^[lI] := lZra^[lI]/lCumGauss; end; for lI := 1 to lcutoffvoxZ do begin lCumGauss := 0; for lI2 := (lcutoffvoxZ - lI) downto -lcutoffvoxZ do lCumGauss := lCumGauss + lZra^[abs(lI2)]; if lCumGauss <> 0 then lZCutra^[lI] := 1/lCumGauss; end; lZCutra^[0] := 1;(**) GetMem ( lROIrealRA , sizeof(single)*lImgSz); GetMem (lYOutRA, sizeof(single) * lYdim); if lResliceNotMask then for lI := 1 to lImgSz do lROIrealRA^[lI] := 0 else for lI := 1 to lImgSz do lROIrealRA^[lI] := 1; //X-direction for lZ := 1 to lZdim do begin lZPos := (lZ-1)*lSliceSz; for lY := 1 to lYdim do begin lyPos := (lY-1)*lXdim; for lX := 1 to lXdim do begin lMinX := lX - lCutoffVoxX; if lMinX < 1 then lMinX := 1; lMaxX := lX + lCutoffVoxX; if lMaxX > lXdim then lMaxX := lXdim; lMissing := (2*lCutOffVoxX)-(lMaxX-lMinX); if lScaleXY then lScale := lXCutRA^[lMissing] else lScale := lXCutRA^[0]; lCumGauss := 0; for lXt := lMinX to lMaxX do begin //SSE optimization? if (gBGImg.VOIUndoVol^[lXt+lYPos+lZpos] <> 0) then lCumGauss := lCumGauss + lScale*lXra^[abs(lX-lXt)] (*{kSmoothImg}*(gROIEXport[lXt+lYPos+lZpos]/255)*); end; {for each position} lROIrealRA^[lX+lYPos+lZpos] := lCumGauss; end; {lX} end; {lY} Application.ProcessMessages; inc(lPlanes); ImgForm.ProgressBar1.Position := lPLanes; end; {lZ loop for X-plane} ImgForm.StatusLabel.caption := 'Smoothing slice data: Y-plane'; for lZ := 1 to lZdim do begin {Z loop for Y plane} lZPos := (lZ-1)*lSliceSz; for lX := 1 to lXdim do begin for lY := 1 to lYdim do begin lMinY := lY - lCutoffVoxY; if lMinY < 1 then lMinY := 1; lMaxY := lY + lCutoffVoxY; if lMaxY > lYdim then lMaxY := lYdim; lMissing := (2*lCutOffVoxY)-(lMaxY-lMinY); if lScaleXY then lScale := lYCutRA^[lMissing] else lScale := lYCutRA^[0]; lCumGauss := 0; for lYt := lMinY to lMaxY do begin //SSE optimization? lCumGauss := lCumGauss+ lScale*(lROIrealRA^[lX+((lYt-1)*lXdim)+lZpos])*lYra^[abs(lY-lYt)]; end; {for each position} lYOutRA^[lY] := lCumGauss; end; {lY} for lY := 1 to lYdim do begin //SSE optimization lROIrealRA^[lX+((lY-1)*lXdim)+lZpos] := lYOutRA^[lY]; end; end; {lX} Application.ProcessMessages; inc(lPlanes); ImgForm.ProgressBar1.Position := lPlanes; end; {Z loop for Y plane} (*if (not lScaleXY) then begin //lOrigZPos := (lFirstEmptySlice-1)*lSliceSz; for lZ := lFirstEmptySlice to lZi do begin if (lROIonSliceRA[lZ]=0) then begin lZPos := (lZ-1)*lSliceSz; for lX := 1 to lSliceSz do //SSE optimization? lROIrealRA[lX+lZPos] := lROIrealRA[lX+lOrigZPos]; Application.ProcessMessages; end; {no ROI on this slice} end; {for n slices} end; {not scaled} *) lThreshComp := 1 - lThresh; ImgForm.StatusLabel.caption := 'Smoothing slice data: Z-plane'; lI := 0; for lZ := 1 to lZdim do begin lMinZ := lZ - lCutoffVoxZ; if lMinZ < 1 then lMinZ := 1; lMaxZ := lZ + lCutoffVoxZ; if lMaxZ > lZdim then lMaxZ := lZdim; lScale := 1; lMissing := (2*lCutOffVoxZ)-(lMaxZ-lMinZ); if (lMissing >= 0) and (lMissing <= lCutOffVoxZ) then lScale := lZCutRA^[lMissing]; if lThreshComp <> 1 then begin if lResliceNotMask then begin for lIncX := 1 to lcutoffvoxZ do lZraScaled^[lcutoffvoxZ-lIncX] := lZra^[lIncX]*lScale; for lIncX := 0 to lcutoffvoxZ do lZraScaled^[lcutoffvoxZ+lIncX] := lZra^[lIncX]*lScale; lZOffset := lcutoffvoxZ + lZ; for lY := 1 to lYdim do begin lyPos := (lY-1)*lXdim; for lX := 1 to lXdim do begin lCumGauss := 0; lIncX := ((lMinZ-1)*lSliceSz)+lX+lYPos; for lZt := lMinZ to lMaxZ do begin lCumGauss := lCumGauss + lROIrealRA^[lIncX]*lZraScaled^[(lZoffset-lZt)]; lIncX := lIncX+ lSliceSz //SSE optimization //lCumGauss := lCumGauss + lROIrealRA[lX+lYPos+(lZt-1)*lSliceSz]*lZra[abs(lZ-lZt)]*lScale; end; inc(lI); if (lCumGauss < (1-lThreshComp)) then gBGImg.VOIUndoVol^[lI] := 100 else gBGImg.VOIUndoVol^[lI] := 0; end; {lX} end; {lY} end else begin //this is a mask -> unrolled loop means faster processing for lY := 1 to lYdim do begin lyPos := (lY-1)*lXdim; for lX := 1 to lXdim do begin lCumGauss := 0; for lZt := lMinZ to lMaxZ do lCumGauss := lCumGauss + lROIrealRA^[lX+lYPos+(lZt-1)*lSliceSz]*lZra^[abs(lZ-lZt)]*lScale; inc(lI); if lCumGauss > lThreshComp then gBGImg.VOIUndoVol^[lI] := 0 else gBGImg.VOIUndoVol^[lI] := 100; end; {lX} end; {lY} end; end else begin //threshcomp = 1 analogua output for lY := 1 to lYdim do begin lyPos := (lY-1)*lXdim; for lX := 1 to lXdim do begin lCumGauss := 0; for lZt := lMinZ to lMaxZ do //SSE optimization? lCumGauss := lCumGauss + lROIrealRA^[lX+lYPos+(lZt-1)*lSliceSz]*lZra^[abs(lZ-lZt)]*lScale; inc(lI); gBGImg.VOIUndoVol^[lI] := round(200 * lCumGauss); end; {lX} end; {lY} end; //threshcomp=1 analogue output Application.ProcessMessages; inc(lPlanes); ImgForm.ProgressBar1.Position := lPlanes; end; {lZ loop} //lEndTime := GetTickCOunt; // ImgForm.StatusLabel.caption :=('Smoothing time(ms): '+inttostr(lEndTime-lStartTime)); FreeMem (lROIrealRA); FreeMem (lYOutRA); Freemem(lXra); Freemem(lYra); Freemem(lZra); Freemem(lZraScaled); Freemem(lXCutra); Freemem(lYCutra); Freemem(lZCutra); if (lThreshComp = 1) then begin //analogue output //gGlMaxUnscaledS := 200; //Scale.value := 0.0050000; for lI := 1 to lImgSz do gBGImg.VOIUndoVol^[lI] := 200 - gBGImg.VOIUndoVol^[lI]; end else begin //threshcomp <> 1 //gGlMaxUnscaledS := 100; //Scale.value := 0.0100000; for lI := 1 to lImgSz do if gBGImg.VOIUndoVol^[lI] = 0 then gBGImg.VOIUndoVol^[lI] := kVOI8bit else gBGImg.VOIUndoVol^[lI] := 0; end; //Threshcomp <> 1 so digital output lResliceNotMask := false; gBGImg.VOIchanged := true; ImgForm.ProgressBar1.Position := 0; ImgForm.Undo1Click(nil); //show smoothed buffer end; procedure Tvoismoothform.FormCreate(Sender: TObject); begin XROIthresh.value := 0.5; XROIfwhm.value := 8; ScaleSides.ItemIndex := 0; xROIoutput.ItemIndex := 0; end; procedure Tvoismoothform.BtnClick(Sender: TObject); begin if (Sender as TSpeedButton).tag = 1 then SmoothOpenVOI(Sender); voismoothform.Close; end; procedure Tvoismoothform.FormShow(Sender: TObject); begin // voismoothform.ModalResult := mrCancel; end; procedure VOIinvert; var lI,lImgSz: integer; begin lImgSz := gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems; if lImgSz < 1 then exit; CreateUndoVol; Move(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,gBGImg.VOIUndoVol^,gBGImg.VOIUndoVolItems); for lI := 1 to lImgSz do if gBGImg.VOIUndoVol^[lI] = 0 then gBGImg.VOIUndoVol^[lI] := 1 else gBGImg.VOIUndoVol^[lI] := 0; gBGImg.VOIchanged := true; ImgForm.Undo1Click(nil); //show smoothed buffer end; procedure Tvoismoothform.SmoothVOI_SPM5masks; var lBGname,lmaskname,llesionname: string; lorigFWHM , lorigThresh : single; lorigSS,lOrigOut: integer; begin if not IsVOIOpen then begin ShowMessage('You have not created or opened a region of interest.'); exit; end; lBGname := gMRIcroOverlay[kBGOverlayNum].HdrFileName; if not gMRIcroOverlay[kBGOverlayNum].NIfTItransform then begin //need to save BG as NIfTI lBGName := ChangeFilePrefix(lBGname,'x'); SaveAsVOIorNIFTIcore(lBGName,gMRIcroOverlay[kBGOverlayNum].ImgBuffer,gMRIcroOverlay[kBGOverlayNum].ImgBufferItems,gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr); end; lmaskname := ChangeFilePrefix(lBGname,'m'); lmaskname := changefileextx(lmaskname, '.nii'); llesionname := ChangeFilePrefix(lBGname,'l'); llesionname := changefileextx(llesionname, '.nii'); if (fileexists(lmaskname)) or (fileexists(llesionname)) then begin showmessage ('Files already exist named '+lmaskname+' '+llesionname); exit; end; //init lorigFWHM := XROIfwhm.value; lorigThresh := XROIthresh.value; lorigSS := voismoothform.ScaleSides.itemindex; lorigOut := xROIoutput.itemindex; //compute mask //XROIfwhm.value := 8; XROIfwhm.value := gBGImg.LesionDilate; XROIthresh.value := 0.001; ScaleSides.itemindex:=(1); xROIoutput.itemindex:=(1); if gBGImg.LesionDilate <= 0 then VOIinvert else SmoothOpenVOI(nil); if (gBGImg.VOIUndoSlice < 1) or (gBGImg.VOIUndoOrient <> 4) then begin //should be impossible - smoothVOI creates undovol showmessage('Serious error.'); exit; end; ImgForm.StatusLabel.caption := 'Smoothed :'+lMaskName; gMRIcroOverlay[kVOIOverlayNum].HdrFileName := lmaskname; ImgForm.SaveVOIcore(false);//12/2010 //unmirrors image //12/2010 SaveAsVOIorNIFTIcore (lmaskname, gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer,gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems, 1,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr); //compute lesion UndoVolVOI; XROIfwhm.value := gBGImg.LesionSmooth; XROIthresh.value := 0.5; //ScaleSides.setitemindex(0); xROIoutput.itemindex:=(0); SmoothOpenVOI(nil); gMRIcroOverlay[kVOIOverlayNum].HdrFileName := llesionname; ImgForm.SaveVOIcore(false);//12/2010 //unmirrors image gMRIcroOverlay[kVOIOverlayNum].HdrFileName := lmaskname; //SaveAsVOIorNIFTIcore (llesionname, gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer,gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems, 1,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr); //re-init UndoVolVOI; XROIfwhm.value := round(lorigFWHM); XROIthresh.value := lorigThresh; ScaleSides.itemindex:=(lOrigSS); xROIoutput.itemindex:=(lOrigOut); end; initialization {$I voismooth.lrs} end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/nifti_img_view.lfm�������������������������������������������������0000755�0001750�0001750�00000211636�12372022034�017706� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object ImgForm: TImgForm Left = 465 Height = 469 Top = 114 Width = 1025 ActiveControl = ControlPanel AllowDropFiles = True Caption = 'MRIcroN' ClientHeight = 469 ClientWidth = 1025 DockSite = True Font.Name = 'MS Sans Serif' Menu = MainMenu1 OnClose = FormClose OnCreate = FormCreate OnDestroy = FormDestroy OnDropFiles = FormDropFiles OnKeyDown = FormKeyDown OnKeyPress = FormKeyPress OnResize = FormResize OnShow = FormShow Position = poScreenCenter LCLVersion = '1.2.4.0' object ControlPanel: TPanel Left = 0 Height = 40 Top = 0 Width = 1025 Align = alTop BevelOuter = bvNone ClientHeight = 40 ClientWidth = 1025 ParentColor = False ParentShowHint = False ShowHint = True TabOrder = 0 OnDblClick = ControlPanelDblClick object LabelX: TLabel Left = 6 Height = 17 Top = 12 Width = 8 Caption = 'X' ParentColor = False end object LabelY: TLabel Left = 81 Height = 17 Top = 12 Width = 8 Caption = 'Y' ParentColor = False end object LabelZ: TLabel Left = 153 Height = 17 Top = 12 Width = 7 Caption = 'Z' ParentColor = False end object HideROIBtn: TSpeedButton Left = 808 Height = 30 Hint = 'Briefly hide VOIs and Overlays' Top = 4 Width = 30 Glyph.Data = { 36060000424D3606000000000000360000002800000010000000180000000100 2000000000000006000064000000640000000000000000000000FFFFFF00FFFF FF00FFFFFF00C61C1D25C000007F8C4545BCB70B0BCBBF0101E8C00000F6C000 00DBC00000BDC00000A0C0000082C0000063C0000024FFFFFF00FFFFFF00D65D 5F3CCF4142C4C82525FF8D4C4CFF47A0A0FF42A8A8FF983535FFC00000FFC000 00FFC00000FFC00000FF9A3333FFC00000FFC00000FFC00000C5DE828486D866 67FDD14A4BFFCA2D2EFFAB3030FF30BFBFFF30BFBFFF854F4FFFC00000FFC000 00FFBF0101FF7E5858FF3EADADFF519494FFAF1616FFC0000095E08A8DBBDA6E 70FFD35253FFCC3536FFAB393AFF8C4646FF7A5E5EFFBF0101FFC00000FFC000 00FFC00000FF854F4FFF30BFBFFF37B6B6FFA62222FFC000003EE2939557DB77 78FFD55A5CFFCE3E3FFFB63636FFC10505FFBB0707FFC00000FFC00000FFC000 00FFB21212FF973737FF6F6C6CFF933C3CFFBA0808E5C0000001E49B9E07DD7F 81ECD26768FFA26F70FF4BB0B0FF746F6FFFB80A0AFFC00000FFBB0606FFA327 27FF4E9797FF7E5757FFB80B0BFFBD0404FFC000008FFFFFFF00FFFFFF00DF87 8990D96B6CFF729FA0FF33CCCCFF49A9A9FFBD0404FFC00000FFC00000FF5F81 81FF30BFBFFF4C9A9AFFBF0101FFC00000FFC0000038FFFFFF00FFFFFF00E190 922CDB7375FF889394FF54AFAFFF85696AFFAF1818FFC00000FFC00000FF7268 68FF45A3A3FF776161FFAF1616FFC00000E0FFFFFF00FFFFFF00FFFFFF00FFFF FF00DD7B7DC9D65F61FFB95758FFC82828FFC20A0AFFC00000FFC00000FFC000 00FFA62222FFBF0101FFC00000FFC0000089FFFFFF00FFFFFF00FFFFFF00FFFF FF00DF848665AC8788FFD14B4DFFCB2F30FFC41313FFC00000FFC00000FFA820 20FFC00000FFC00000FFC00000FFC0000032FFFFFF00FFFFFF00FFFFFF00FFFF FF00E18C8E0D4CCDCEFB62AFB0FFC73C3DFFC61B1BFFC00000FF943A3AFF4E97 97FF637C7CFFA62222FFC00000DAFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF005AC8C8CC4DC4C5FFC44A4BFFC82324FFC10707FF8E4343FF30BF BFFF33BBBBFFAC1A1AFFC0000083FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF005ACCCD6BBB787AFFCB4D4EFFCA2C2CFFC30F0FFF904040FF637B 7BFF726767FFA91E1EFFC000002CFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF0000FFFF03D96C6ED6D25052FFC93738FFC51818FFC00000FFBD04 04FFB41010FFC00000D4FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00DB757772D4595AFF957273FF945959FFA62525FFC000 00FFC00000FFC000007DFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00DD7D7F159F898AFB37CDCEFF32C9C9FF9A3E3EFFC000 00FFC00000FFC0000026FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00B08587B642C7C7FF42BCBCFF836263FFC000 00FFC00000CEFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00CE7A7B4AD1585AFF9A6B6BFFC61D1DFFC000 00FFC0000077FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00DC7A7C02D65D5FE1CF4142FFB6393AFFC209 09FFC0000021FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00D8666780AA6B6CFF5AA1A2FF845E 5ED7FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00DA6E701F9F7C7DFD33CDCDFF6886 879AFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00948D8ECA689E9EFE8A67 6727FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00D7636455D04648C2FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00D96B6D06D24F5057FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnMouseDown = HideROIBtnMouseDown OnMouseUp = HideROIBtnMouseUp end object XBarBtn: TSpeedButton Left = 838 Height = 30 Hint = 'Toggle Crosshairs'#13#10'right-click to change gap size'#13#10'right+ctrl click to change color'#13#10'right+alt click to change thickness'#13#10'right+shift to reposition origin'#13#10'right+ctrl+alt to adjust font size' Top = 4 Width = 30 AllowAllUp = True Glyph.Data = { D6080000424DD608000000000000360000002800000017000000180000000100 200000000000A008000064000000640000000000000000000000FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00C0000039C0000034FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF000000FF140000FF500000FF0AFFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00C00000B8C00000A8FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF000000FF400000FFFF0000FF20FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00C00000B8C00000A8FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FF400000FFFF0000FF20FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00C00000B8C00000A8FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 FF400000FFFF0000FF20FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C000 00B8C00000A8FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF400000 FFFF0000FF20FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF000000FF190000FF500000FF500000FF500000FF50760063CE7100 68C30000FF500000FF500000FF500000FF500000FF500000FF7C0000FFFF0000 FF660000FF500000FF500000FF500000FF500000FF500000FF500000FF500000 FF190000FF500000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FF500000 FF050000FF100000FF100000FF100000FF10B00016BCAE0018AD0000FF100000 FF100000FF100000FF100000FF100000FF4C0000FFFF0000FF2E0000FF100000 FF100000FF100000FF100000FF100000FF100000FF100000FF05FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00C00000B8C00000A8FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF000000FF400000FFFF0000FF20FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00C00000B8C00000A8FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF000000FF400000FFFF0000FF20FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00C00000B8C00000A8FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FF400000FFFF0000FF20FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00C00000B8C00000A8FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 FF400000FFFF0000FF20FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C000 00B8C00000A8FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF400000 FFFF0000FF20FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C00000B8C000 00A8FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF400000FFFF0000 FF20FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C00000B8C00000A8FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF400000FFFF0000FF20FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C000 004DC00000F8C00000F8C00000F8C00000F8C00000FDC00000FDC00000F8C000 00F8C00000F8C00000F8C00000F88F0041FA0000FFFFA70021F9C00000F8C000 00F8C00000F8C00000F8C00000F8C00000F8C00000F8C000004DC0000020C000 0068C0000068C0000068C0000068C00000D5C00000CBC0000068C0000068C000 0068C0000068C00000686900738E0000FFFF8E00427BC0000068C0000068C000 0068C0000068C0000068C0000068C0000068C0000020FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00C00000B8C00000A8FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF000000FF400000FFFF0000FF20FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00C00000B8C00000A8FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FF400000FFFF0000FF20FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00C00000B8C00000A8FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 FF400000FFFF0000FF20FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C000 00B8C00000A8FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF400000 FFFF0000FF20FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C00000B8C000 00A8FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF400000FFFF0000 FF20FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C00000B8C00000A8FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF400000FFFF0000FF20FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C0000039C0000034FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF000000FF140000FF500000FF0AFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } GroupIndex = 321 OnClick = XBarBtnClick OnMouseDown = XBarBtnMouseDown ShowHint = True ParentShowHint = False end object LayerPanel: TPanel Left = 304 Height = 36 Top = 2 Width = 500 ClientHeight = 36 ClientWidth = 500 TabOrder = 5 object AutoContrastBtn: TSpeedButton Left = 121 Height = 28 Hint = 'Autocontrast' Top = 3 Width = 28 Glyph.Data = { D6080000424DD608000000000000360000002800000018000000170000000100 200000000000A008000064000000640000000000000000000000FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000022191919632E2E 2EA53F3F3FC2525252D74F4F4FD53C3C3CC02D2D2D9F1111115F0000001AFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF000000000C2E2E2EA8777777E8C6C6C6FEF4F4 F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0F0F0FF181818FF313030F22A28 289D00000005FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF0023232353454545DADCDCDCFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1B1616FF1A1010FF271A 1AFF322828EA231E1E3BFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF003030309E969696F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAFAFF2C2020FF2F1C1CFF3A23 23FF3E2525FF5A4545F840363685FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF0024242459909090F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFEFFFFF5F5FF3A2828FF422828FF5131 31FF573434FF4F2F2FFF594040F82B1F1F3DFFFFFF00FFFFFF00FFFFFF000000 00164A4A4ADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCFCFFFFF3F3FF422D2DFF4E2F2FFF643C 3CFF704343FF613A3AFF4B2D2DFF483636E8110A0A0AFFFFFF00FFFFFF003030 30C2E8E8E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFAFAFFFDFD FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCFCFFFFF2F2FF432D2DFF4F2F2FFF663D 3DFF754646FF633B3BFF4C2E2EFF422E2EFF3A3131AEFFFFFF000000002D8B8B 8BEEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F0EFFF826868FFF4F2 F2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFEFFFFF5F5FF3C2929FF452929FF5533 33FF5C3737FF533232FF422828FF2D1B1BFF3C3333F20000000921212172CFCF CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8DFDFFF835E5DFF633E3EFFF4F2 F2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F9FF2F2121FF331F1FFF3F26 26FF432828FF3D2525FF301D1DFF1F1313FF201C1CFE0303033C313131B1FBFB FBFFFFFFFFFFFFFFFFFFFFFFFFFFDECCCBFF8D5D5CFF7A4D4CFF6B4342FF7457 56FF685150FF5C4848FF4F4040FF433838FF363030FF150D0DFF1E1212FF2717 17FF291919FF261717FF1C1111FF0E0808FF020202FF2525258A454545CAFFFF FFFFFFFFFFFFFFFEFEFFD7B7B6FF9F6564FF905B5AFF815250FF734847FF643F 3EFF553535FF462C2BFF372322FF281919FF1A1010FF0B0707FF070404FF0E08 08FF100A0AFF0D0808FF050303FF000000FF000000FF272727C7545454DBFFFF FFFFFFFFFFFFE3C0BFFFB67371FFA76968FF98605EFF895655FF7A4D4CFF6B44 43FF5D3A39FF4E3130FF3F2827FF301E1EFF211515FF130C0BFF040202FF0000 00FF000000FF000000FF000000FF000000FF000000FF2B2B2BDB454545CAFFFF FFFFFFFFFFFFFEFCFBFFD4A6A6FFAF6E6DFFA06563FF915B5AFF825251FF7349 48FF643F3EFF563635FF472D2CFF382323FF291A19FF1A1010FF0C0707FF0000 00FF000000FF000000FF000000FF000000FF000000FF272727C7313131B1FBFB FBFFFFFFFFFFFFFFFFFFFFFEFEFFDAB8B7FFA76A68FF99605FFF8A5756FF7B4D 4CFF6C4443FF5D3B3AFF4F3231FF402828FF311F1EFF221515FF130C0CFF0403 03FF000000FF000000FF000000FF000000FF020202FF2525258921212172CFCF CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2CACAFFA26968FF925C5AFFE1D6 D5FFF6F4F4FFF5F3F3FFF4F2F2FFF4F2F2FFF3F1F1FF362727FF1B1111FF0C08 07FF000000FF000000FF000000FF000000FF161616FE0303033C0000002D8B8B 8BEEFFFFFFFFFFFEFEFFFFFEFEFFFFFEFEFFFFFFFFFFEADBDBFFA16D6BFFE9DF DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E2C2CFF231615FF140C 0CFF050303FF000000FF000000FF000000FF2A2A2AF100000009FFFFFF003A35 35C4EAE2E2FFFFF7F7FFFFF7F7FFFFF8F8FFFFF8F8FFFFF8F8FFF3E5E5FFF3ED EDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF453131FF2B1B1AFF1C11 11FF0D0808FF000000FF000000FF131313FF272727A9FFFFFF00FFFFFF002818 181A645656E3FFF1F1FFFFF1F1FFFFF1F1FFFFF2F2FFFFF2F2FFFFF2F2FFFFF3 F3FFFFF8F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4C3635FF32201FFF2516 16FF1C1111FF130C0CFF110A0AFF2B2626E500000009FFFFFF00FFFFFF00FFFF FF004F3B3B66A69292F3FFEBEBFFFFEBEBFFFFECECFFFFECECFFFFECECFFFFED EDFFFFEDEDFFFFF0F0FFFFFBFBFFFFFCFCFFFFFBFBFF604140FF503231FF4C2F 2FFF412828FF331F1FFF423434F718141439FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00594545ABB19797F4FFE5E5FFFFE6E6FFFFE6E6FFFFE6E6FFFFE7 E7FFFFE7E7FFFFE7E7FFFFE7E7FFFFE7E7FFFFE7E7FF805353FF6C4242FF603B 3BFF543433FF654D4DF83A323283FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF0063464668846161E5E6C8C8FFFFE0E0FFFFE0E0FFFFE0 E0FFFFE1E1FFFFE1E1FFFFE1E1FFFFE1E1FFFFE1E1FF8F5C5CFF7E4D4DFF764B 4AFF634545EC3328283FFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF009A5D5D1D715050BDAA8484F0DAB6B6FEF8D3 D3FFFFDBDBFFFFDBDBFFFFDBDBFFFFDBDBFFF5D2D2FFA06969FF906565F56146 46AA40272707FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF004429292C754D4D837C56 56BE8C6363D79D7171E7986E6EE5865F5FD4775353B75B3C3C720B07071BFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnClick = AutoContrastBtnClick end object LutFromZeroBtn: TSpeedButton Left = 439 Height = 28 Hint = 'Color range from zero' Top = 4 Width = 28 AllowAllUp = True Glyph.Data = { AE060000424DAE06000000000000360000002800000018000000170000000100 180000000000780600000000000000000000000000000000000000FF0000FF00 00FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF 0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000 FF0000FF0000000000000000000000FF0000FF0000FF0000FF0000FF0000FF00 00FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF 0000FF0000FF0000FF0000000000000000000000000000000000FF0000FF0000 FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00 00FF0000FF0000FF0000FF0000FF0000FF0000000000000000FF000000000000 0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000 FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00000000000000 00FF0000000000000000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF 0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000 FF0000000000000000FF0000000000000000FF0000FF00000000000000000000 00000000000000FF0000FF0000FF0000FF0000FF0000FF0000FF000000000000 0000000000000000000000000000000000FF0000000000000000FF0000FF0000 000000000000000000000000000000FF0000FF0000FF0000FF0000FF0000FF00 00FF000000000000000000000000000000000000000000000000000000000000 0000FF0000FF0000000000000000000000000000000000FF0000FF0000FF0000 FF0000FF0000FF0000FF0000000000000000000000000000000000FF00000000 00000000000000FF0000FF0000FF0000FF0000000000000000000000FF0000FF 0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000000000000000000000 FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00000000000000 00000000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF000000 0000000000000000FF0000FF0000FF000000FF00FF0000FF0000FF0000FF0000 FF0000FF0000000000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00 00FF0000FF0000FF0000000000FF0000FF0000FF0000FF000000FF00FF0000FF 0000FF0000FF0000FF0000FF0000000000FF0000FF0000FF0000FF0000FF0000 FF0000FF0000FF0000FF0000FF0000FF0000000000FF0000FF00808080808080 0000FF8080808080808080808080808080808080808080808080808080808080 8080808080808080808080808080808080808080808080808080808080808080 80808080800000000000000A08080E0808140C0C190F0F1E1212231414281717 2C1A1A311D1D3620203923233A25253A27273A29293A2B2B3A2D2D3A30300000 000000000000008080808080800000000000002C1A1A4428285935356F424284 4F4F9A5C5CB06969C57676DA8383F19090FE9B9BFFA4A4FFACACFFB5B5FFBEBE FFC6C6FFD7D7FFE0E0FFFFFF0000008080808080800000000000002E1B1B4428 285935356F4242844F4F9A5C5CB06969C57676DA8383F19090FE9B9BFFA4A4FF ACACFFB5B5FFBEBEFFC6C6FFD7D7FFE0E0FFFFFF000000808080808080000000 0000002E1B1B4428285935356F4242844F4F9A5C5CB06969C57676DA8383F190 90FE9B9BFFA4A4FFACACFFB5B5FFBEBEFFC6C6FFD7D7FFE0E0FFFFFF00000080 80808080800000000000002E1B1B4428285935356F4242844F4F9A5C5CB06969 C57676DA8383F19090FE9B9BFFA4A4FFACACFFB5B5FFBEBEFFC6C6FFD7D7FFE0 E0FFFFFF0000008080808080800000000000002E1B1B4428285935356F424284 4F4F9A5C5CB06969C57676DA8383F19090FE9B9BFFA4A4FFACACFFB5B5FFBEBE FFC6C6FFD7D7FFE0E0FFFFFF0000008080808080800000000000002E1B1B4428 285935356F4242844F4F9A5C5CB06969C57676DA8383F19090FE9B9BFFA4A4FF ACACFFB5B5FFBEBEFFC6C6FFD7D7FFE0E0FFFFFF000000808080808080000000 0000002E1B1B4428285935356F4242844F4F9A5C5CB06969C57676DA8383F190 90FE9B9BFFA4A4FFACACFFB5B5FFBEBEFFC6C6FFD7D7FFE0E0FFFFFF00000080 8080808080000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000080808080808080808080808080808080808080808080808080 8080808080808080808080808080808080808080808080808080808080808080 808080808080808080808080808080808080 } GroupIndex = 194 OnClick = LutFromZeroBtnClick end object ColorBarBtn: TSpeedButton Left = 467 Height = 28 Hint = 'Draw color range ' Top = 4 Width = 28 Glyph.Data = { 96030000424D96030000000000003600000028000000180000000C0000000100 180000000000600300006400000064000000000000000000000000FF0000FF00 00FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF 0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000 FF00808080808080808080808080808080808080808080808080808080808080 8080808080808080808080808080808080808080808080808080808080808080 808080808080808080808080800000000000000A08080E0808140C0C190F0F1E 12122314142817172C1A1A311D1D3620203923233A25253A27273A29293A2B2B 3A2D2D3A30300000000000000000008080808080800000000000002C1A1A4428 285935356F4242844F4F9A5C5CB06969C57676DA8383F19090FE9B9BFFA4A4FF ACACFFB5B5FFBEBEFFC6C6FFD7D7FFE0E0FFFFFF000000808080808080000000 0000002E1B1B4428285935356F4242844F4F9A5C5CB06969C57676DA8383F190 90FE9B9BFFA4A4FFACACFFB5B5FFBEBEFFC6C6FFD7D7FFE0E0FFFFFF00000080 80808080800000000000002E1B1B4428285935356F4242844F4F9A5C5CB06969 C57676DA8383F19090FE9B9BFFA4A4FFACACFFB5B5FFBEBEFFC6C6FFD7D7FFE0 E0FFFFFF0000008080808080800000000000002E1B1B4428285935356F424284 4F4F9A5C5CB06969C57676DA8383F19090FE9B9BFFA4A4FFACACFFB5B5FFBEBE FFC6C6FFD7D7FFE0E0FFFFFF0000008080808080800000000000002E1B1B4428 285935356F4242844F4F9A5C5CB06969C57676DA8383F19090FE9B9BFFA4A4FF ACACFFB5B5FFBEBEFFC6C6FFD7D7FFE0E0FFFFFF000000808080808080000000 0000002E1B1B4428285935356F4242844F4F9A5C5CB06969C57676DA8383F190 90FE9B9BFFA4A4FFACACFFB5B5FFBEBEFFC6C6FFD7D7FFE0E0FFFFFF00000080 80808080800000000000002E1B1B4428285935356F4242844F4F9A5C5CB06969 C57676DA8383F19090FE9B9BFFA4A4FFACACFFB5B5FFBEBEFFC6C6FFD7D7FFE0 E0FFFFFF00000080808080808000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000008080808080808080808080808080808080 8080808080808080808080808080808080808080808080808080808080808080 8080808080808080808080808080808080808080808080808080 } OnMouseDown = ColorBarBtnMouseDown end object LayerDrop: TComboBox Left = 4 Height = 20 Top = 4 Width = 116 ItemHeight = 0 ItemIndex = 0 Items.Strings = ( 'Background Layer' ) OnChange = LayerDropChange OnSelect = LayerDropSelect ParentShowHint = False ShowHint = True Style = csDropDownList TabOrder = 0 Text = 'Background Layer' end object MinWindowEdit: TFloatSpinEdit Left = 153 Height = 16 Top = 4 Width = 88 DecimalPlaces = 4 Increment = 1 MaxValue = 9999999 MinValue = -9999999 OnChange = MinContrastWindowEditChange TabOrder = 1 Value = 1 end object MaxWindowEdit: TFloatSpinEdit Left = 245 Height = 16 Top = 4 Width = 88 DecimalPlaces = 4 Increment = 1 MaxValue = 9999999 MinValue = -9999999 OnChange = MaxContrastWindowEditChange TabOrder = 2 Value = 1 end object LUTdrop: TComboBox Left = 340 Height = 20 Top = 5 Width = 100 DropDownCount = 66 ItemHeight = 0 OnChange = LUTdropChange OnSelect = LUTdropSelect ParentShowHint = False ShowHint = True Style = csDropDownList TabOrder = 3 end end object ZoomDrop: TComboBox Left = 225 Height = 20 Top = 8 Width = 79 DropDownCount = 12 ItemHeight = 0 Items.Strings = ( 'To Fit' 'To Int' 'x1' 'x2' 'x3' 'x4' 'x5' 'x6' 'x7' 'x8' 'x9' ) OnChange = ZoomDropChange OnSelect = ZoomDropSelect ParentShowHint = False ShowHint = True Style = csDropDownList TabOrder = 4 end object XViewEdit: TSpinEdit Left = 24 Height = 16 Top = 12 Width = 52 MinValue = 1 OnChange = XViewEditChange TabOrder = 0 Value = 100 end object YViewEdit: TSpinEdit Left = 97 Height = 16 Top = 12 Width = 52 MinValue = 1 OnChange = XViewEditChange TabOrder = 1 Value = 32 end object ZViewEdit: TSpinEdit Left = 169 Height = 16 Top = 12 Width = 52 MinValue = 1 OnChange = XViewEditChange TabOrder = 2 Value = 14 end object ToolPanel: TPanel Left = 872 Height = 32 Top = 4 Width = 165 BevelOuter = bvNone ClientHeight = 32 ClientWidth = 165 TabOrder = 3 Visible = False object PenBtn: TSpeedButton Left = 0 Height = 30 Hint = 'Pen Tool' Top = 0 Width = 30 AllowAllUp = True Glyph.Data = { F6060000424DF606000000000000360000002800000018000000180000000100 180000000000C00600000000000000000000000000000000000000FF0000FF00 00FF0000FF00C9C9CCBABAD0B1B1D2B0B0D2B4B4D1BCBCCFC6C6CD00FF0000FF 0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000 FF0000FF0000FF00CACACCA4A4D57B7BDF3434F13333F23333F23333F13535F1 3737F04343ED5656E96F6FE28B8BDBADADD3C8C8CC00FF0000FF0000FF0000FF 0000FF0000FF0000FF0000FF00A0A0D62F2FF31717F89797D83A3AF03333F233 33F23333F23333F23333F23333F23333F23333F23333F23333F14141EE7575E0 B8B8D000FF0000FF0000FF0000FF0000FF00ABABD36262FB4C4CFF1414F9C7C7 CCC2C2CEAFAFD3A1A1D69A9AD89494D98C8CDB8282DE7878E06D6DE35C5CE742 42EE3333F13333F23D3DEEBABACF00FF0000FF0000FF0000FF007F7FE3B3B3FF 3C3CFF0000FE9494D900FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF 0000FF0000FF00C9C9CC8E8EDA3333F23333F2A5A5D500FF0000FF0000FF0000 FF009F9FDB9898FF3535FF0000FF3F3FEE00FF0000FF0000FF0000FF0000FF00 00FF0000FF0000FF0000FF0000FF00CBCBCC6060E53333F25353E9C9C9CC00FF 0000FF0000FF0000FF00CACACC7676E41A1AFB2E2EF2A8A8D400FF0000FF0000 FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF009A9AD73333F13C3CEF B5B5D100FF0000FF0000FF0000FF0000FF00CCCCCCA9A9A93B3B435B5B5DB9B9 B900FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00CACACC4D 4DEA3434F19999D800FF0000FF0000FF0000FF0000FF0000FF00CCCCCC404040 0E0E0E0000001C1C1CB4B4B400FF0000FF0000FF0000FF0000FF0000FF0000FF 0000FF00B8B8D03434F15C5CE7CBCBCC00FF0000FF0000FF0000FF0000FF0000 FF00CBCBCB44444450505000000000000062626200FF0000FF0000FF0000FF00 00FF0000FF0000FF0000FF00C5C5CD4747EC4A4AEBBCBCCF00FF0000FF0000FF 0000FF0000FF0000FF00CBCBCB4646465F5F5F0000000000003F3F3F00FF0000 FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00B1B1D24949EB4141ED 9797D8CBCBCC00FF0000FF0000FF0000FF0000FF004949496565650000000000 0030303000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000 FF00C4C4CD7A7ADF3737F05D5DE7B5B5D100FF0000FF0000FF0000FF00505050 69696900000000000024242400FF0000FF0000FF0000FF0000FF0000FF0000FF 0000FF0000FF0000FF0000FF00CBCBCCB2B2D25B5BE73A3AEF8B8BDBCACACC00 FF0000FF006969695B5B5B0000000000001D1D1D00FF0000FF0000FF0000FF00 00FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00CACACC9797 D83E3EEE7B7BDFCBCBCC00FF009191915050500101010000001B1B1B00FF0000 FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00 00FF0000FF00CBCBCC7B7BDF3B3BEFC2C2CD00FF00BBBBBB3A3A3A0A0A0A0000 0018181800FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000 FF0000FF0000FF00CBCBCCB6B6D16C6CE35353E9A9A9D400FF0000FF00CACACA 323232171717000000101010CBCBCB00FF0000FF0000FF0000FF0000FF0000FF 0000FF0000FF0000FF00CBCBCCAEAED36969E46262E59F9FD6CACACC00FF0000 FF0000FF0000FF004B4B4B1515150000000B0B0BC6C6C600FF0000FF0000FF00 00FF0000FF0000FF0000FF00CACACCA0A0D66E6EE27A7ADFB5B5D1CBCBCC00FF 0000FF0000FF0000FF0000FF0000FF00858585020202000000050505BBBBBB00 FF0000FF0000FF0000FF0000FF0000FF00C4C4CD9595D8A5A5D5C8C8CC00FF00 00FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00BFBFBF0808080000 00000000A3A3A300FF0000FF0000FF0000FF0000FF0000FF00CBCBCC00FF0000 FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00 00FF004A4A4A00000000000084848400FF0000FF0000FF0000FF0000FF0000FF 0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000 FF0000FF0000FF0000FF00A6A6A603030300000065656500FF0000FF0000FF00 00FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF 0000FF0000FF0000FF0000FF0000FF0000FF0000FF0041414100000046464600 FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00 00FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00AAAA AA05050525252500FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000 FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00 } GroupIndex = 44 OnClick = PenBtnClick end object ClosedPenBtn: TSpeedButton Left = 30 Height = 30 Hint = 'Autoclose Pen' Top = 0 Width = 30 AllowAllUp = True Glyph.Data = { F6060000424DF606000000000000360000002800000018000000180000000100 180000000000C00600000000000000000000000000000000000000FF0000FF00 00FF0000FF00C9C9CCBABAD0B1B1D2B0B0D2B4B4D1BCBCCFC6C6CD00FF0000FF 0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000 FF0000FF0000FF00CACACCA4A4D57B7BDF3434F13333F23333F23333F13535F1 3737F04343ED5656E96F6FE28B8BDBADADD3C8C8CC00FF0000FF0000FF0000FF 0000FF0000FF0000FF0000FF00A0A0D62F2FF31717F89797D83A3AF03333F233 33F23333F23333F23333F23333F23333F23333F23333F23333F14141EE7575E0 B8B8D000FF0000FF0000FF0000FF0000FF00ABABD36262FB4C4CFF1414F9C7C7 CCC2C2CEAFAFD3A1A1D69A9AD89494D98C8CDB8282DE7878E06D6DE35C5CE742 42EE3333F13333F23D3DEEBABACF00FF0000FF0000FF0000FF007F7FE3B3B3FF 3C3CFF0000FE9494D900FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF 0000FF0000FF00C9C9CC8E8EDA3333F23333F2A5A5D500FF0000FF0000FF0000 FF009F9FDB9898FF3535FF0000FF3F3FEE00FF0000FF0000FF0000FF0000FF00 00FF0000FF0000FF0000FF0000FF00CBCBCC6060E53333F25353E9C9C9CC00FF 0000FF0000FF0000FF00CACACC7676E41A1AFB2E2EF2A8A8D400FF0000FF00FF 0000FF000000FF0000FF0000FF0000FF0000FF0000FF009A9AD73333F13C3CEF B5B5D100FF0000FF0000FF0000FF0000FF00CCCCCCA9A9A93B3B435B5B5DB9B9 B900FF00FF0000FF0000FF0000FF000000FF0000FF0000FF0000FF00CACACC4D 4DEA3434F19999D800FF0000FF0000FF0000FF0000FF0000FF00CCCCCC404040 0E0E0E0000001C1C1CB4B4B4FF0000FF0000FF0000FF000000FF0000FF0000FF 0000FF00B8B8D03434F15C5CE7CBCBCC00FF0000FF0000FF0000FF0000FF0000 FF00CBCBCB44444450505000000000000062626200FF00FF0000FF000000FF00 00FF0000FF0000FF0000FF00C5C5CD4747EC4A4AEBBCBCCF00FF0000FF0000FF 0000FF0000FF0000FF00CBCBCB4646465F5F5F0000000000003F3F3F00FF0000 FF0000FF0000FF00FF0000FF000000FF0000FF0000FF00B1B1D24949EB4141ED 9797D8CBCBCC00FF0000FF0000FF0000FF0000FF004949496565650000000000 0030303000FF0000FF0000FF00FF0000FF0000FF0000FF000000FF0000FF0000 FF00C4C4CD7A7ADF3737F05D5DE7B5B5D100FF0000FF0000FF0000FF00505050 69696900000000000024242400FF0000FF0000FF00FF0000FF0000FF0000FF00 0000FF0000FF0000FF0000FF00CBCBCCB2B2D25B5BE73A3AEF8B8BDBCACACC00 FF0000FF006969695B5B5B0000000000001D1D1D00FF0000FF0000FF0000FF00 FF0000FF000000FF0000FF0000FF0000FF0000FF0000FF0000FF00CACACC9797 D83E3EEE7B7BDFCBCBCC00FF009191915050500101010000001B1B1B00FF0000 FF0000FF0000FF0000FF0000FF0000FF00FF0000FF000000FF0000FF0000FF00 00FF0000FF00CBCBCC7B7BDF3B3BEFC2C2CD00FF00BBBBBB3A3A3A0A0A0A0000 0018181800FF0000FF0000FF0000FF0000FF0000FF00FF0000FF0000FF0000FF 000000FF0000FF00CBCBCCB6B6D16C6CE35353E9A9A9D400FF0000FF00CACACA 323232171717000000101010CBCBCB00FF0000FF0000FF0000FF0000FF00FF00 00FF0000FF0000FF0000CBCBCCAEAED36969E46262E59F9FD6CACACC00FF0000 FF0000FF0000FF004B4B4B1515150000000B0B0BC6C6C600FF0000FF0000FF00 00FF0000FF0000FF00FF0000FF0000A0A0D66E6EE27A7ADFB5B5D1CBCBCC00FF 0000FF0000FF0000FF0000FF0000FF00858585020202000000050505BBBBBB00 FF0000FF0000FF0000FF0000FF0000FF00C4C4CD9595D8A5A5D5C8C8CC00FF00 00FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00BFBFBF0808080000 00000000A3A3A300FF0000FF0000FF0000FF0000FF0000FF00CBCBCC00FF0000 FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00 00FF004A4A4A00000000000084848400FF0000FF0000FF0000FF0000FF0000FF 0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000 FF0000FF0000FF0000FF00A6A6A603030300000065656500FF0000FF0000FF00 00FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF 0000FF0000FF0000FF0000FF0000FF0000FF0000FF0041414100000046464600 FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00 00FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00AAAA AA05050525252500FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000 FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF0000FF00 } GroupIndex = 44 OnClick = PenBtnClick end object FillBtn: TSpeedButton Left = 60 Height = 30 Hint = 'Fill tool' Top = 0 Width = 30 AllowAllUp = True Glyph.Data = { D6080000424DD608000000000000360000002800000017000000180000000100 200000000000A008000064000000640000000000000000000000FFFFFF00FFFF FF00FFFFFF000000FF080000FF4F0000FF7A0000FF930000FFAB0000FFC40000 FFDD0000FFF50000FFEF0000FFD30000FFB80000FF9C0000FF810000FF540000 FF03FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF040000FF480000 FFA00000FFF10000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFDD0000 FF24FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF9C0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FF8EFFFF FF00FFFFFF00FFFFFF00FFFFFF000000FFD40000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFE0000FF40FFFFFF00FFFF FF00FFFFFF00FFFFFF000000FF410000FFF80000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFED0000FFB60000FF36FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF000000FF300000FFD60000FFFF0000FFFF0000FFFF0000 FFFC0000FFE30000FFD10000FFBF0000FFAD0000FF9B0000FF7D0000FF4E0000 FF1E540000195C09095D54000007FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF000000FF100000FFD70000FF4F0000FF290000FF06FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006512126A7625 25E4B46D6EF8722323E16818188C54000003FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF000000FF660000FFABFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF005400001C691717C6AC5F60F1FBBBBDFFFDC3 C5FFFDC9CBFFBE8283F5681919C35400000DFFFFFF00FFFFFF00FFFFFF00FFFF FF000000FFCF0000FF82FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF006612126F782525E5E49A9BFFFDBBBDFFFDC1C3FFFDC7C9FFFCCD CFFFFCD3D5FFD9ABADFC681B1BCB54000003FFFFFF00FFFFFF000000FF250000 FFFF0000FF59FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF005400001E6A15 16C9B05E5EF2FCB2B3FFFDB9BAFFFDBFC0FFFDC5C7FFFCCBCDFFFCD1D3FFFCD7 D9FFFCDDDFFFBD8E90F566191A8FFFFFFF00FFFFFF000000FF7A0000FFFF0000 FF39FFFFFF00FFFFFF00FFFFFF0054000001661111747A2525E5E79494FFFEB1 B2FFFDB7B8FFFDBDBEFFFDC3C4FFFDC9CBFFFCCFD1FFFCD4D7FFFCDADDFFFCE0 E3FFFBE6E9FF803E3FE854000023FFFFFF000000FFA70000FFFF0000FF50FFFF FF00FFFFFF00540000216A1414CBB45C5CF3FDA8A9FFFEAFB0FFFDB5B6FFFDBB BCFFFDC1C2FFFDC6C8FFFCCCCEFFFCD2D5FFFCD8DBFFFCDEE1FFFBE4E7FFFBEA EDFFD7BCBFFF681E1E9CFFFFFF000000FF990000FFFF0000FF82540000016711 11787C2424E6E98D8DFFFEA7A7FFFEADADFFFDB3B4FFFDB8BAFFFDBEC0FFFDC4 C6FFFCCACCFFFCD0D2FFFCD6D9FFFCDCDFFFFCE2E5FFFBE8EBFFFBEEF1FFFBF4 F7FF692020E4FFFFFF000000FF290000FFF40000FEF1471464E6722732FCDF82 82FFFEA5A5FFFEAAABFFFEB0B1FFFDB6B8FFFDBCBEFFFDC2C4FFFDC8CAFFFCCE D0FFFCD4D6FFFCDADDFFFCE0E3FFFBE6E9FFFBECEFFFFBF1F5FFAF8688F3661B 1B86FFFFFF00FFFFFF000000FF160D00D99B3525CDF9433FF3FF452BB9FF813A 48FFD78787FFFDB4B5FFFDBABBFFFDC0C2FFFDC6C8FFFCCCCEFFFCD2D4FFFCD8 DAFFFCDEE0FFFBE4E7FFFBE9EDFFFBEFF3FFD3BBBEFD671C1DBFFFFFFF00FFFF FF00FFFFFF00FFFFFF005400000C6D2524E0ADA7F3FF0000FFFF1615FDFF5B33 8EFFC37C7DFFFDBEBFFFFDC4C5FFFCCACCFFFCD0D2FFFCD6D8FFFCDBDEFFFCE1 E4FFFBE7EAFFFBEDF1FFEBDBDFFF6A2121DC5400000DFFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF005F10105CA57775EF413FFCFF0000FFFF0000FFFF5032 A9FFB77576FFFDC8C9FFFCCDD0FFFCD3D6FFFCD9DCFFFCDFE2FFFBE5E8FFFBEB EEFFF8ECF0FF773435E754000029FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00681D1DC9C5B7DBFF0606FFFF0000FFFF0000FFFF5037 B8FFA96A6AFFFCD1D4FFFCD7DAFFFCDDE0FFFBE3E6FFFBE9ECFFFBEFF2FF9660 62ED6316165CFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF0054000026763130E7A39CF1FF0404FFFF0000FFFF0000FFFF503B C5FFAB7071FFFCDBDEFFFCE1E4FFFBE7EAFFFBEDF0FFBF9B9DF7671C1D9CFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF005D0D0C3D753130E5A89FECFF0606FFFF0000FFFF0000FFFF5D33 88FFE3BEBFFFFBE5E8FFFBEBEEFFDEC7CAFF681E1FCB54000003FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF005705052D712B2AE1ACA2E6FF0909FFFF0000FFFF1312FCFF7C41 57FFFBE8ECFFF1E0E4FF6E2627E054000015FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00540000206F2726DBC0B2D9FF5D5BFBFF0404FFFF4532CAFFC29C 9EFF814142E95B0A0B38FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00540000166B2221BA8B4F4EE5C7B6D1FFDCD3EBFF773232FC671B 1C72FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00540000206A201FA56C2323E7691F1FBEFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } GroupIndex = 44 OnClick = PenBtnClick end object EllipseBtn: TSpeedButton Left = 90 Height = 30 Hint = 'Ellipse Tool' Top = 0 Width = 30 AllowAllUp = True Glyph.Data = { 76080000424D7608000000000000360000002800000018000000160000000100 2000000000004008000064000000640000000000000000000000FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF070000FF670000FFB3FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF1A0000FF2C0000FF03FFFF FF00FFFFFF00FFFFFF00FFFFFF000000FF053131FFBF3E3EFFFF0000FFCBFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF000000FF1F0000FFA70000FFE50000FFFF0000FFFF0000FFF50000 FFC30000FF52FFFFFF00FFFFFF000000FF38A6A6FFFF3535FFFF0000FFF90000 FF14FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FF640000FFF20000FFCB0000FF680000FF340000FF220000FF550000 FF9A0000FFFD0000FFA60000FF100707FF24A3A3FFFF2C2CFFFF0000FFFF0000 FF6CFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 FF4E0000FFFE0000FF7C0000FF04FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FF3D0000FFE10000FFADFFFFFF002C2CFF5D0F0FFFD80000FF9C0000 FF12FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF120000 FFE70000FF93FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF000000FF360000FFFC0000FF5954000027540000B95400008C5400 0008FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF7F0000 FFE00000FF0AFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF000000FF8A0000FFE05A09098B5F1010FF540000FF5400 00CF54000003FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FFB70000 FF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FF050000FF080000FF3C0000FFFF5A0F1AC0804141FF540000FF5400 00FF4D0015480000FF080000FF080000FF080000FF080000FF080000FFEB0000 FF68FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FFB00000FFFF0000FFFF0000FFFF380055FF834646FF540000FF5400 00FF250090FF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFEB0000 FF68FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FFB00000FF8D0000FF2E0000FFFB40003CBE824545FF540000FF5400 00FF480024910000FF280000FF280000FF280000FF490000FFFF0000FFB70000 FF98FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FFB00000FF780000FF350000FFFF4C001784824444FF540000FF5400 00FF54000088FFFFFF00FFFFFF00FFFFFF000000FF280000FFFF0000FF810000 FFDD0000FF08FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FFB00000FF780000FF860000FFE254000044824444FF540000FF5400 00FF54000091FFFFFF00FFFFFF00FFFFFF000000FF280000FFFF0000FF150000 FFEA0000FF8DFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FFB00000FF920000FFFB0000FF5F54000009814343FA550101FF5400 00FF54000099FFFFFF00FFFFFF00FFFFFF000000FF280000FFFFFFFFFF000000 FF530000FFFD0000FF740000FF02FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FFC10000FFEE0000FFB3FFFFFF00FFFFFF006D2525C6580606FF5400 00FF540000A1FFFFFF00FFFFFF00FFFFFF000000FF280000FFFFFFFFFF00FFFF FF000000FF6C0000FFF50000FFC40000FF600000FF2C0000FF1A0000FF4D0000 FF920000FFFE0000FFD40000FF13FFFFFF00FFFFFF005502027D590808FF5400 00FF540000A9FFFFFF00FFFFFF00FFFFFF000000FF280000FFFFFFFFFF00FFFF FF00FFFFFF000000FF240000FFAF0000FFEC0000FFFF0000FFFF0000FFF90000 FFCB0000FFCC0000FF78FFFFFF00FFFFFF00FFFFFF005400003A550101FF5400 00FF540000C7FFFFFF00FFFFFF00FFFFFF000000FF280000FFFFFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF220000FF340000FF07FFFF FF000000FFB00000FF78FFFFFF00FFFFFF00FFFFFF0054000004540000F35400 00FF540000FE5400001AFFFFFF00FFFFFF000000FF280000FFFFFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FFB00000FF78FFFFFF00FFFFFF00FFFFFF00FFFFFF00540000A05400 00FF540000FF5400006CFFFFFF00FFFFFF000000FF280000FFFFFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FFB00000FF78FFFFFF00FFFFFF00FFFFFF00FFFFFF00540000215400 00FA540000FF540000BEFFFFFF00FFFFFF000000FF280000FFFFFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FFB00000FF78FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF005400 0095540000FF540000FB5400000FFFFFFF000000FF280000FFFFFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FFB00000FFF30000FFE80000FFE80000FFE80000FFE80000FFE80900 E4EA510008FE540000FF0B00DDEB0000FFE80000FFEB0000FFFFFFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FF310000FF480000FF480000FF480000FF480000FF480000FF480000 FF4835005E844C0017D00300F54A0000FF480000FF480000FF48 } GroupIndex = 44 OnClick = PenBtnClick end object Fill3DBtn: TSpeedButton Left = 120 Height = 30 Hint = 'Create VOI based on background intensity' Top = 0 Width = 30 AllowAllUp = True Glyph.Data = { D6080000424DD608000000000000360000002800000018000000170000000100 200000000000A008000064000000640000000000000000000000FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FF1C0000FF510000 FF830000FFB50000FFE70000FFE70000FFB50000FF830000FF510204FF1CFFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF000000FF0B0000FF8D0000FFFC0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0102FFFF0A11FFFF121CFFFC1725 FF8D1A2AFF0BFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF000000FF460000FFDF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0305FFFF0E17FFFF1827FFFF2134FFFF273E FFFF2B44FFDF2B45FF46FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF000000FF870000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0D15FFFF1A29FFFF253CFFFF2F4BFFFF3757 FFFF3B5FFFFF3C60FFFF395BFF87FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF000000FF4A0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF080CFFFF1623FFFF2439FFFF314EFFFF3D60FFFF4670 FFFF4C79FFFF4D7AFFFF4974FFFF4167FF4AFFFFFF00FFFFFF00FFFFFF000000 FF160000FFE90000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0D16FFFF1D2EFFFF2C46FFFF3A5DFFFF4872FFFF5485 FFFF5C93FFFF5E95FFFF588CFFFF4D7BFFE94066FF16FFFFFF00FFFFFF000000 FFB40000FFFF0000FFFF0000DAFF0000B9FF0000A0FF0000B8FF0000DEFF0000 FDFF0000FFFF0102FFFF111BFDFF1927BFFF253ABFFF304CBFFF3C5FBFFF4670 BFFF5688CCFF649FE7FF649EFEFF5689FFFF4771FFB4FFFFFF000000FF2A0000 FFFF0000E0FF000045FF000000FF000000FF000000FF000000FF000000FF0000 39FF0000DEFF0203FFFF111CF5FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF0E1723FF345396FF4974FFFF395AFF2A0000FF600000 FEFF00003DFF000000FF000000FF00007BFF0000ECFF00008DFF000000FF0000 00FF000033FF0001FFFF0F19F5FF000000FF000000FF000000FF111C39FF1F32 56FF152133FF000000FF000000FF000000FF253C8AFF3656FF600000FF960000 FFFF0000FDFF0000E7FF0000CDFF0000FAFF0000FFFF0000DEFF000000FF0000 00FF000001FF0000F2FF0C13F5FF000000FF000000FF000000FF2A429AFF5180 FFFF588CFFFF253A68FF000000FF000000FF050713FF304CFF960000FFCB0000 FFFF0000FFFF0000FFFF0000FFFF0000BBFF00006BFF000027FF000000FF0000 00FF00006AFF0000FFFF060AF5FF000000FF000000FF000000FF22379AFF426A FFFF4872FFFF314EABFF000000FF000000FF000000FF2135D9D10000FFF20000 FFFF0000FFFF0000FFFF0000FFFF0000AAFF000003FF000000FF000000FF0000 7EFF0000FFFF0000FFFF0000F5FF000000FF000000FF000000FF1B2A9AFF3351 FFFF3758FFFF1F318BFF000000FF000000FF000000FF1927E2F30000FFC80000 FFFF0000F8FF0000D9FF0000B8FF0000F6FF0000ECFF00003EFF000000FF0000 00FF0000AEFF0000FFFF0000F5FF000000FF000000FF000000FF121C9AFF2338 FFFF2135D9FF080C32FF000000FF000000FF03051EFF0F19FFC80000FF920000 FFFF000085FF000000FF000000FF00005DFF0000ADFF00002FFF000000FF0000 00FF0000BCFF0000FFFF0000F5FF000000FF000000FF000000FF010218FF0203 16FF000000FF000000FF000000FF000002FF070BB4FF0203FF920000FF5C0000 FFFF0000FFFF00007BFF00000FFF000000FF000000FF000000FF00000FFF0000 7DFF0000FFFF0000FFFF0000F5FF000000FF000000FF000000FF000000FF0000 00FF000003FF01011FFF01024EFF0001CEFF0000FFFF0000FF5C0000FF250000 FFFF0007FFFF000FFFFF0010FAFF000EE1FF000BD5FF0005E6FF0000FBFF0000 FFFF0000FFFF0000FFFF0000FFFF0000EFFF0000EFFF0000EFFF0000EFFF0000 EFFF0000FBFF0000FFFF0000FFFF0000FFFF0000FFFF0000FF25FFFFFF00001C FFB5001DFFFF001DFFFF001CFFFF001CFFFF001BFFFF001BFFFF0017FFFF000A FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFA4FFFFFF00FFFFFF000032 FF170026FFE80023FFFF0023FFFF0022FFFF0021FFFF0020FFFF0020FFFF001F FFFF0017FFFF0004FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0001 FFFF0007FFFF000EFFFF0012FFFF0014FFE60021FF16FFFFFF00FFFFFF00FFFF FF000034FF55002BFFFD002AFFFF0029FFFF0028FFFF0027FFFF0026FFFF0025 FFFF0025FFFF0023FFFF0010FFFF0008FFFF000BFFFF000EFFFF0016FFFF001E FFFF001FFFFF001EFFFF001EFFFD0020FF4FFFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00002CFF880031FFFD0030FFFF002FFFFF002EFFFF002EFFFF002C FFFF002CFFFF002BFFFF002AFFFF002AFFFF0028FFFF0028FFFF0027FFFF0026 FFFF0025FFFF0025FFFD0022FF87FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF000041FF4A003DFFDE0037FFFF0036FFFF0035FFFF0035 FFFF0033FFFF0032FFFF0032FFFF0031FFFF0030FFFF002FFFFF002EFFFF002E FFFF0030FFDD0031FF47FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF000093FF110042FF93003EFFF9003DFFFF003C FFFF003BFFFF003BFFFF003AFFFF0038FFFF0038FFFF0037FFFF0035FFF9003A FF92007BFF0EFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000055FF12005BFF5B004F FF8E004AFFB90046FFDF0046FFDF0048FFBA004CFF8E0051FF590045FF10FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } GroupIndex = 44 OnClick = Fill3DBtnClick end end end object MagPanel: TPanel Left = 0 Height = 18 Top = 451 Width = 1025 Align = alBottom BevelOuter = bvNone ClientHeight = 18 ClientWidth = 1025 TabOrder = 1 object StatusLabel: TLabel Left = 2 Height = 17 Top = 2 Width = 133 Caption = ' No Images Loaded ' ParentColor = False end object ProgressBar1: TProgressBar Left = 875 Height = 18 Top = 0 Width = 150 Align = alRight Anchors = [akRight, akBottom] BorderWidth = 1 TabOrder = 0 end end object Panel1: TPanel Left = 0 Height = 411 Top = 40 Width = 1025 Align = alClient BevelOuter = bvNone ClientHeight = 411 ClientWidth = 1025 TabOrder = 2 object TriplePanel: TScrollBox Tag = 666 Left = 0 Height = 411 Top = 0 Width = 1025 HorzScrollBar.Page = 775 VertScrollBar.Page = 250 Align = alClient ClientHeight = 396 ClientWidth = 1010 Constraints.MinWidth = 5 Color = clBlack ParentColor = False TabOrder = 0 OnClick = ImgPanelClick object PGImageCor: TImage Tag = 2 Cursor = crCross Left = 1 Height = 12 Top = 1 Width = 12 AutoSize = True OnDblClick = PGImageCorDblClick OnMouseDown = PGImageMouseDown OnMouseMove = PGImageMouseMove OnMouseUp = PGImageMouseUp Stretch = True end object PGImageSag: TImage Tag = 3 Cursor = crCross Left = 323 Height = 12 Top = 110 Width = 12 AutoSize = True OnDblClick = PGImageCorDblClick OnMouseDown = PGImageMouseDown OnMouseMove = PGImageMouseMove OnMouseUp = PGImageMouseUp Stretch = True end object PGImageAx: TImage Tag = 1 Cursor = crCross Left = 763 Height = 12 Top = 238 Width = 12 AutoSize = True OnDblClick = PGImageCorDblClick OnMouseDown = PGImageMouseDown OnMouseMove = PGImageMouseMove OnMouseUp = PGImageMouseUp Stretch = True end end end object MainMenu1: TMainMenu left = 112 top = 212 object File1: TMenuItem Caption = '&File' object Open1: TMenuItem Caption = '&Open' ShortCut = 16463 OnClick = Open1Click end object Recent1: TMenuItem Caption = 'Open &recent' end object Templates1: TMenuItem Caption = 'Open &templates' end object CloseImages: TMenuItem Caption = '&Close images' OnClick = CloseImagesClick end object SaveasNIfTI1: TMenuItem Caption = 'Save as NIfTI...' ShortCut = 49235 OnClick = SaveasNIfTI1Click end object Saveaspicture1: TMenuItem Caption = '&Save as bitmap' ShortCut = 16467 OnClick = Saveaspicture1Click end object Exit1: TMenuItem Caption = 'E&xit' OnClick = Exit1Click end end object Edit1: TMenuItem Caption = '&Edit' object Copy1: TMenuItem Caption = 'Copy' ShortCut = 16451 OnClick = Copy1Click end object Paste1: TMenuItem Caption = 'Paste' ShortCut = 16470 OnClick = Paste1Click end object Undo1: TMenuItem Caption = 'Undo' ShortCut = 16474 OnClick = Undo1Click end end object OverlayMenu: TMenuItem Caption = '&Overlay' object OverlayOpen: TMenuItem Caption = 'Add' ShortCut = 16449 OnClick = OverlayOpenClick end object CloseOverlayImg: TMenuItem Caption = 'Close overlays' OnClick = CloseOverlayImgClick end object BGTransPctMenu: TMenuItem Caption = 'Transparency on background' object BGtrans0: TMenuItem Caption = '0% opaque' Checked = True GroupIndex = 251 RadioItem = True OnClick = BGtrans100Click end object BGtrans20: TMenuItem Tag = 20 Caption = '20%' GroupIndex = 251 RadioItem = True OnClick = BGtrans100Click end object BGtrans40: TMenuItem Tag = 40 Caption = '40%' GroupIndex = 251 RadioItem = True OnClick = BGtrans100Click end object BGtrans50: TMenuItem Tag = 50 Caption = '50%' GroupIndex = 251 RadioItem = True OnClick = BGtrans100Click end object BGtrans60: TMenuItem Tag = 60 Caption = '60%' GroupIndex = 251 RadioItem = True OnClick = BGtrans100Click end object BGtrans80: TMenuItem Tag = 80 Caption = '80%' GroupIndex = 251 RadioItem = True OnClick = BGtrans100Click end object BGtrans100: TMenuItem Tag = 100 Caption = '100% transparent' GroupIndex = 251 RadioItem = True OnClick = BGtrans100Click end object BGAdditive: TMenuItem Tag = -1 Caption = 'Additive' GroupIndex = 251 RadioItem = True OnClick = BGtrans100Click end end object OverlayTransPctMenu: TMenuItem Caption = 'Transparency on other overlays' object N0opaque1: TMenuItem Caption = '0% opaque' GroupIndex = 253 RadioItem = True OnClick = OverlayTransClick end object N201: TMenuItem Tag = 20 Caption = '20%' GroupIndex = 253 RadioItem = True OnClick = OverlayTransClick end object N401: TMenuItem Tag = 40 Caption = '40%' GroupIndex = 253 RadioItem = True OnClick = OverlayTransClick end object N501: TMenuItem Tag = 50 Caption = '50%' GroupIndex = 253 RadioItem = True OnClick = OverlayTransClick end object N601: TMenuItem Tag = 60 Caption = '60%' GroupIndex = 253 RadioItem = True OnClick = OverlayTransClick end object N801: TMenuItem Tag = 80 Caption = '80%' GroupIndex = 253 RadioItem = True OnClick = OverlayTransClick end object N100transparent1: TMenuItem Tag = 100 Caption = '100% transparent' GroupIndex = 253 RadioItem = True OnClick = OverlayTransClick end object OverlayAdditive: TMenuItem Tag = -1 Caption = 'Additive' Checked = True GroupIndex = 253 RadioItem = True OnClick = OverlayTransClick end end object LayerMenu: TMenuItem Caption = 'Layer color' Visible = False object Noneopen1: TMenuItem Caption = 'None open' end end object Layerrange1: TMenuItem Caption = 'Layer intensity' Visible = False object Noneopen2: TMenuItem Caption = 'None open' end end end object DrawMenu: TMenuItem Caption = '&Draw' object HideDrawMenuItem: TMenuItem Caption = 'Hide drawing tools' OnClick = ToggleDrawMenu end object OpenVOI: TMenuItem Caption = 'Open VOI...' OnClick = OpenVOIClick end object SaveVOI: TMenuItem Caption = 'Save VOI...' OnClick = SaveVOIClick end object CloseVOI: TMenuItem Caption = 'Close VOI...' OnClick = CloseVOIClick end object VOIColor: TMenuItem Caption = 'VOI color...' OnClick = VOIColorClick end object Applyintensityfiltertovolume1: TMenuItem Caption = 'Intensity filter...' ShortCut = 16454 OnClick = Applyintensityfiltertovolume1Click end object SmoothVOI1: TMenuItem Caption = 'Smooth VOI...' OnClick = SmoothVOI1Click end object MaskimagewithVOI1: TMenuItem Caption = 'Mask image with VOI' object VOImaskDelete: TMenuItem Caption = 'Delete regions with VOI' OnClick = VOImaskClick end object VOImaskPreserve: TMenuItem Tag = 1 Caption = 'Preserve regions with VOI' OnClick = VOImaskClick end end object Overlaycomparisons1: TMenuItem Caption = 'Overlay comparisons' object IntersectionmutualtoVOIandoverlays1: TMenuItem Caption = 'Intersection [VOI and overlays]' OnClick = ROIcomparisonClick end object UnionVOIoroverlays1: TMenuItem Tag = 1 Caption = 'Union [VOI or overlays]' OnClick = ROIcomparisonClick end object MaskVOIbutnotoverlays1: TMenuItem Tag = 2 Caption = 'Mask [VOI but not overlays]' OnClick = ROIcomparisonClick end end object Statistics1: TMenuItem Caption = 'Statistics' object Beta1: TMenuItem Caption = 'Create overlap images' OnClick = CreateOverlap end object Chisquare1: TMenuItem Caption = 'Subtraction Plots' OnClick = Chisquare1Click end object BatchROImean1: TMenuItem Caption = 'Batch descriptives' OnClick = BatchROImean1Click end object Batchprobmaps1: TMenuItem Caption = 'Batch prob maps' OnClick = Batchprobmaps1Click end object Batchclusterprobmaps1Batchclusterprobmaps1Click: TMenuItem Caption = 'Batch cluster prob maps' OnClick = Batchclusterprobmaps1Batchclusterprobmaps1ClickClick end end object Convert1: TMenuItem Caption = 'Convert' object ROIVOI1: TMenuItem Caption = 'ROI -> VOI' OnClick = ROIVOI1Click end object VOI2NII: TMenuItem Caption = 'VOI -> NII' OnClick = VOI2NIIClick end object NIIVOI: TMenuItem Caption = 'NII -> VOI' OnClick = NIIVOIClick end end object Nudge1: TMenuItem Caption = 'Nudge' object Up1: TMenuItem Caption = 'Left' OnClick = Up1Click end object Left1: TMenuItem Tag = 1 Caption = 'Right' OnClick = Up1Click end object LeftX1: TMenuItem Tag = 2 Caption = 'Posterior' OnClick = Up1Click end object RightX1: TMenuItem Tag = 3 Caption = 'Anterior' OnClick = Up1Click end object Posterior1: TMenuItem Tag = 4 Caption = 'Inferior' OnClick = Up1Click end object Posterior2: TMenuItem Tag = 5 Caption = 'Superior' OnClick = Up1Click end end object n5: TMenuItem Caption = 'Advanced' object RescaleMenu: TMenuItem Caption = 'Phase to rad/S' OnClick = RescaleMenuClick end object BrainExtraction1: TMenuItem Caption = 'Brain extraction' OnClick = BETmenuClick end object CropEdges1: TMenuItem Caption = 'Crop edges' OnClick = CropMenuClick end object Brainmask1: TMenuItem Caption = 'Brain mask ' OnClick = BrainMask1Click end object GenerateSPM5maskslesions1: TMenuItem Caption = 'Create SPM5 mask' OnClick = GenerateSPM5maskslesions1Click end object LRFlip1: TMenuItem Caption = 'LR Flip' OnClick = MirrorNII1Click end object ApplyClusterThreshold1: TMenuItem Caption = 'Apply cluster threshold' OnClick = ApplyClusterThreshold1Click end object ExportasRGBAnalyzeimage1: TMenuItem Caption = 'Export as RGB image' OnClick = ExportasRGBAnalyzeimage1Click end object Resliceimage1: TMenuItem Caption = 'Reslice images' OnClick = Resliceimage1Click end object AdjustimagessoVOIintensityiszero1: TMenuItem Caption = 'Adjust images so VOI intensity is zero' OnClick = AdjustimagessoVOIintensityiszero1Click end object Extract1: TMenuItem Caption = 'Extract objects' OnClick = Extract1Click end end object DescriptiveMenuItem: TMenuItem Caption = 'Descriptive' OnClick = DescriptiveMenuItemClick end object N1: TMenuItem Caption = '-' end object Pen1: TMenuItem Tag = 2 Caption = 'Pen' ShortCut = 112 OnClick = ToolSelectClick end object Penautoclose1: TMenuItem Tag = 3 Caption = 'Autoclose pen' ShortCut = 113 OnClick = ToolSelectClick end object CircleSquare1: TMenuItem Tag = 4 Caption = 'Fill' ShortCut = 114 OnClick = ToolSelectClick end object Circle2: TMenuItem Tag = 5 Caption = 'Circle' ShortCut = 115 OnClick = ToolSelectClick end object Circle1: TMenuItem Tag = 6 Caption = 'Deselect tools' ShortCut = 116 OnClick = ToolSelectClick end end object DrawHiddenMenu: TMenuItem Caption = 'Draw' Visible = False object MenuItem2: TMenuItem Caption = 'Show drawing tools' OnClick = ToggleDrawMenu end end object Controls1: TMenuItem Caption = '&View' object Display2: TMenuItem Tag = 2 Caption = 'Display' object Axial1: TMenuItem Tag = 1 AutoCheck = True Caption = 'Axial' GroupIndex = 234 RadioItem = True OnClick = Sagittal1Click end object Coronal1: TMenuItem Tag = 3 AutoCheck = True Caption = 'Coronal' GroupIndex = 234 RadioItem = True OnClick = Sagittal1Click end object Sagittal1: TMenuItem Tag = 2 AutoCheck = True Caption = 'Sagittal' GroupIndex = 234 RadioItem = True OnClick = Sagittal1Click end object Multiple1: TMenuItem AutoCheck = True Caption = 'Multiple' Checked = True GroupIndex = 234 RadioItem = True OnClick = Sagittal1Click end object Axial2: TMenuItem Tag = -1 AutoCheck = True Caption = 'Axial only' GroupIndex = 234 RadioItem = True OnClick = Sagittal1Click end object Coronal2: TMenuItem Tag = -3 AutoCheck = True Caption = 'Coronal only' GroupIndex = 234 RadioItem = True OnClick = Sagittal1Click end object Sagittal2: TMenuItem Tag = -2 AutoCheck = True Caption = 'Sagittal only' GroupIndex = 234 RadioItem = True OnClick = Sagittal1Click end end object N3: TMenuItem Caption = '-' end object Quicksmooth1: TMenuItem Caption = '3D Smooth background' OnClick = Quicksmooth1Click end object OverlaySmoothMenu: TMenuItem Caption = '3D Smooth overlays' OnClick = OverlaySmoothMenuClick end object Menu2DSmooth: TMenuItem Caption = '2D Smooth all' Checked = True OnClick = Menu2DSmoothClick end object N4: TMenuItem Caption = '-' end object FlipLRmenu: TMenuItem Caption = 'Flip L/R' OnClick = FlipLRmenuClick end object YokeMenu: TMenuItem Caption = 'Yoke' ShortCut = 16473 OnClick = YokeMenuClick end object N2: TMenuItem Caption = '-' end object MagnifyMenuItem: TMenuItem Caption = 'Magnify' OnClick = MagnifyMenuItemClick end object Crosshair1: TMenuItem Caption = 'Crosshair' OnClick = ToolSelectClick end object MenuItem1: TMenuItem Caption = '-' end object MNIMenu: TMenuItem Caption = 'MNI coordinates' OnClick = MNIMenuClick end object Landmarks1: TMenuItem Caption = 'Landmarks' OnClick = Landmarks1Click end end object Display1: TMenuItem Caption = 'Window' object ShowRender: TMenuItem Caption = 'Render' ShortCut = 16466 OnClick = ShowRenderClick end object ShowMultislice: TMenuItem Caption = 'Multislice' ShortCut = 16461 OnClick = ShowMultisliceClick end object HistoMenu: TMenuItem Caption = 'Histogram' ShortCut = 16456 OnClick = HistoMenuClick end object N4DTraces1: TMenuItem Caption = '4D Traces' ShortCut = 16452 OnClick = N4DTraces1Click end object Header1: TMenuItem Caption = 'Information' ShortCut = 16457 OnClick = Header1Click end end object Help1: TMenuItem Caption = '&Help' object Preferences1: TMenuItem Caption = 'Preferences...' OnClick = Preferences1Click end object About1: TMenuItem Caption = 'About' OnClick = About1Click end end end object SaveDialog1: TSaveDialog OnClose = SaveDialog1Close DefaultExt = '.bmp' Filter = 'Bitmap|.bmp' FilterIndex = 0 left = 18 top = 212 end object ColorDialog1: TColorDialog Color = clBlack CustomColors.Strings = ( 'ColorA=000000' 'ColorB=000080' 'ColorC=008000' 'ColorD=008080' 'ColorE=800000' 'ColorF=800080' 'ColorG=808000' 'ColorH=808080' 'ColorI=C0C0C0' 'ColorJ=0000FF' 'ColorK=00FF00' 'ColorL=00FFFF' 'ColorM=FF0000' 'ColorN=FF00FF' 'ColorO=FFFF00' 'ColorP=FFFFFF' 'ColorQ=C0DCC0' 'ColorR=F0CAA6' 'ColorS=F0FBFF' 'ColorT=A4A0A0' ) left = 50 top = 212 end object RefreshImagesTimer: TTimer Enabled = False Interval = 20 OnTimer = RefreshImagesTimerTimer left = 82 top = 212 end object RescaleImagesTimer: TTimer Enabled = False Interval = 50 OnTimer = RescaleImagesTimerTimer left = 178 top = 212 end object YokeTimer: TTimer Enabled = False Interval = 200 OnTimer = YokeTimerTimer left = 280 top = 264 end end ��������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_build.bat���������������������������������������������������������0000755�0001750�0001750�00000000447�10617723222�016140� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������C:\lazarus\pp\bin\i386-win32\strip --verbose --strip-all "C:\lazarus\mricron\mricron.exe" copy "C:\lazarus\mricron\mricron.exe" C:\mricron\mricron.exe copy "C:\lazarus\mricron\dcm2nii\dcm2nii.exe" C:\mricron\dcm2nii.exe "C:\Program Files\NSIS2\makensis" "C:\Program Files\NSIS2\mricron.nsi" �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/reslice_fsl.pas����������������������������������������������������0000755�0001750�0001750�00000017622�11425732636�017223� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit reslice_fsl; {$H+} interface uses nifti_hdr,define_types,metagraph,sysutils; function ResliceImg (lTargetImgName,lSrcImgName,lSrc2TargetMatName,lOutputName: string): boolean; procedure ResliceFSL; implementation uses nifti_img_view,dialogs,nifti_img,text,graphx,math,nifti_hdr_view,GraphicsMathLibrary,classes; procedure ResliceFSL; label 666; var lInc,lNumberofFiles: integer; lSrc2TargetMatName,lSrcImgName,lTargetImgName,lOutputName:string; lStrings : TStringList; begin ImgForm.CloseImagesClick(nil); if not OpenDialogExecute(kImgFilter,'Select source image[s]',true) then exit; lNumberofFiles:= HdrForm.OpenHdrDlg.Files.Count; if lNumberofFiles < 1 then exit; lStrings := TStringList.Create; lStrings.AddStrings(HdrForm.OpenHdrDlg.Files); if not OpenDialogExecute('FSL (*.mat)|*.mat','Select FSL source-to-target matrix',false) then goto 666; lSrc2TargetMatName := HdrForm.OpenHdrDlg.Filename; if not OpenDialogExecute(kImgFilter,'Select target image (source image will be warped to this)',false) then goto 666; lTargetImgName := HdrForm.OpenHdrDlg.Filename; TextForm.MemoT.Lines.Clear; for lInc:= 1 to lNumberofFiles do begin lSrcImgName := lStrings[lInc-1]; lOutputName := ChangeFilePrefix (lSrcImgName,'w'); TextForm.MemoT.Lines.Add(' Source->Matrix->Target '+lSrcImgName+'->'+ lSrc2TargetMatName+'->'+lTargetImgName); ResliceImg (lTargetImgName,lSrcImgName,lSrc2TargetMatName,lOutputName); end;//lLoop TextForm.Show; 666: lStrings.free; end; function ReadFSLMat (var lMat: TMatrix; lSrc2TargetMatName: string):boolean; var lF: TextFile; xx,xy,xz,xo ,yx,yy,yz,yo ,zx,zy,zz,zo: double; begin result := false; if not fileexists(lSrc2TargetMatName) then exit; Assign(lF,lSrc2TargetMatName); Filemode := 0; Reset(lF); readln(lF,xx,xy,xz,xo,yx,yy,yz,yo,zx,zy,zz,zo); //read all with one readln - // separate readlns only work for native eoln CloseFile(lF); lMat:= Matrix3D (xx,xy,xz,xo ,yx,yy,yz,yo ,zx,zy,zz,zo ,0,0,0,1); result := true; Filemode := 2; end; function Rx (var lDestHdr,lSrcHdr: TMRIcroHdr; var lInMat: TMatrix; var lOutputName: string):boolean; var lPos,lXYs,lXYZs,lXs,lYs,lZs,lXi,lYi,lZi,lX,lY,lZ, lXo,lYo,lZo,lMinY,lMinZ,lMaxY,lMaxZ: integer; lXrM1,lYrM1,lZrM1, lXreal,lYreal,lZreal: double; lOutImg: bytep; lScale,lMat: TMatrix; begin result := false; lXs := lSrcHdr.NIFTIhdr.Dim[1]; lYs := lSrcHdr.NIFTIhdr.Dim[2]; lZs := lSrcHdr.NIFTIhdr.Dim[3]; if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems <> lXs*lYs*lZs) then begin showmessage('Reslice error: background image not loaded.'); exit; end; lXYs:=lXs*lYs; //slicesz lXYZs := lXYs*lZs; lX := lDestHdr.NIFTIhdr.Dim[1]; lY := lDestHdr.NIFTIhdr.Dim[2]; lZ := lDestHdr.NIFTIhdr.Dim[3]; //TextForm.Memo1.Lines.Add(inttostr(lXs)+'x'+inttostr(lYs)+'x'+inttostr(lZs)+'->'+inttostr(lX)+'x'+inttostr(lY)+'x'+inttostr(lZ)); lDestHdr.NIFTIhdr.Dim[4] := 1; getmem(lOutImg, lX*lY*lZ*sizeof(byte)); lPos := 0; //http://eeg.sourceforge.net/MJenkinson_coordtransforms.pdf //FLIRT transforms are in world coordinates [mm] //to convert to a vxl-vxl transform, the matrix must be //PRE-multiplied by inv(Dest) and POST-multiplied by Src //where Dest and Src are the spatial dimensions in mm lScale:= Matrix3D (abs(lSrcHdr.NIFTIhdr.pixdim[1]),0,0,0 ,0,abs(lSrcHdr.NIFTIhdr.pixdim[2]),0,0 ,0,0,abs(lSrcHdr.NIFTIhdr.pixdim[3]),0 ,0,0,0,1); lScale := InvertMatrix3D(lScale); lMat := MultiplyMatrices(lScale,lInMat); lScale:= Matrix3D (abs(lDestHdr.NIFTIhdr.pixdim[1]),0,0,0 ,0,abs(lDestHdr.NIFTIhdr.pixdim[2]),0,0 ,0,0,abs(lDestHdr.NIFTIhdr.pixdim[3]),0 ,0,0,0,1); lMat := MultiplyMatrices(lMat,lScale); for lZi := 0 to (lZ-1) do begin for lYi := 0 to (lY-1) do begin for lXi := 0 to (lX-1) do begin inc(lPos); lOutImg^[lPos] := 0; lXreal := (lXi*lMat.matrix[1][1]+lYi*lMat.matrix[1][2]+lZi*lMat.matrix[1][3]+lMat.matrix[1][4]); lYreal := (lXi*lMat.matrix[2][1]+lYi*lMat.matrix[2][2]+lZi*lMat.matrix[2][3]+lMat.matrix[2][4]); lZreal := (lXi*lMat.matrix[3][1]+lYi*lMat.matrix[3][2]+lZi*lMat.matrix[3][3]+lMat.matrix[3][4]); //need to test Xreal as -0.01 truncates to zero if (lXreal >= 0) and (lYreal >= 1) and (lZreal >= 1) and (lXreal < (lXs -1)) and (lYreal < (lYs -1) ) and (lZreal < (lZs -1)) then begin lXo := trunc(lXreal); lYo := trunc(lYreal); lZo := trunc(lZreal); lXreal := lXreal-lXo; lYreal := lYreal-lYo; lZreal := lZreal-lZo; lXrM1 := 1-lXreal; lYrM1 := 1-lYreal; lZrM1 := 1-lZreal; lMinY := ((lYo)*lXs); lMinZ := ((lZo)*lXYs); lMaxY := ((lYo+1)*lXs); lMaxZ := ((lZo+1)*lXYs); inc(lXo);//images incremented from 1 not 0 {if lMax <(lXreal) then lMax := lXreal; if lMin >(lXreal) then lMin := lXreal; } lOutImg^[lPos] := round ( {all min} ( (lXrM1*lYrM1*lZrM1)*gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lXo+lMinY+lMinZ]) {x+1}+((lXreal*lYrM1*lZrM1)*gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lXo+1+lMinY+lMinZ]) {y+1}+((lXrM1*lYreal*lZrM1)*gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lXo+lMaxY+lMinZ]) {z+1}+((lXrM1*lYrM1*lZreal)*gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lXo+lMinY+lMaxZ]) {x+1,y+1}+((lXreal*lYreal*lZrM1)*gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lXo+1+lMaxY+lMinZ]) {x+1,z+1}+((lXreal*lYrM1*lZreal)*gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lXo+1+lMinY+lMaxZ]) {y+1,z+1}+((lXrM1*lYreal*lZreal)*gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lXo+lMaxY+lMaxZ]) {x+1,y+1,z+1}+((lXreal*lYreal*lZreal)*gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lXo+1+lMaxY+lMaxZ]) ); end; end;//z end;//y end;//z deletefile(lOutputName); SaveAsVOIorNIFTIcore (lOutputName,lOutImg, lX*lY*lZ, 1,1,lDestHdr.NIFTIhdr); lPos := 1; while (lPos <= (lX*lY*lZ)) and (lOutImg^[lPos] = 0) do inc(lPos); if lPos > (lX*lY*lZ) then result := false else result := true; freemem(lOutImg); end; function ResliceImg (lTargetImgName,lSrcImgName,lSrc2TargetMatName,lOutputName: string): boolean; label 666; var lReslice,lOrtho : boolean; lDestHdr,lSrcHdr: TMRIcroHdr; lMat: TMatrix; begin result := false; if not fileexists(lTargetImgName) then exit; if not fileexists(lSrcImgName) then exit; if not fileexists(lSrc2TargetMatName) then exit; if not ReadFSLMat(lMat,lSrc2TargetMatName) then exit; ImgForm.CloseImagesClick(nil); lReslice := gBGImg.ResliceOnLoad; lOrtho := gBGImg.OrthoReslice; gBGImg.OrthoReslice := false; gBGImg.ResliceOnLoad := false; //if not HdrForm.OpenAndDisplayHdr(lTargetImgName,lDestHdr) then goto 666; if not NIFTIhdr_LoadHdr(lTargetImgName, lDestHdr) then goto 666; if not NIFTIhdr_LoadHdr(lSrcImgName, lSrcHdr) then goto 666; ImgForm.OpenAndDisplayImg(lSrcImgName,True); if not Rx(lDestHdr,lSrcHdr,lMat,lOutputName) then goto 666; result := true; 666: if not result then showmessage('Error applying transform '+lSrcImgName+'->'+lTargetImgName+' using '+lSrc2TargetMatName); gBGImg.ResliceOnLoad := lReslice; gBGImg.OrthoReslice := lOrtho; end; end. ��������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/histoform.lfm������������������������������������������������������0000755�0001750�0001750�00000002460�12147215554�016725� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object HistogramForm: THistogramForm Left = 1007 Height = 336 Top = 272 Width = 465 Caption = 'Histogram' ClientHeight = 336 ClientWidth = 465 Font.Height = -11 Font.Name = 'MS Sans Serif' Menu = MainMenu1 OnCreate = FormCreate Position = poScreenCenter LCLVersion = '0.9.30.2' object HistoPanel: TScrollBox Left = 0 Height = 336 Top = 0 Width = 465 Align = alClient ClientHeight = 336 ClientWidth = 465 TabOrder = 0 object HistoImage: TImage Cursor = crCross Left = 0 Height = 336 Top = 0 Width = 465 Align = alClient AutoSize = True Center = True end end object MainMenu1: TMainMenu left = 113 top = 51 object File1: TMenuItem Caption = 'File' object Saveasbitmap1: TMenuItem Caption = 'Save as bitmap...' ShortCut = 16467 OnClick = Saveasbitmap1Click end object Closewindow1: TMenuItem Caption = 'Close window' ShortCut = 16471 OnClick = Closewindow1Click end end object Edit1: TMenuItem Caption = 'Edit' object Copy1: TMenuItem Caption = 'Copy' ShortCut = 16451 OnClick = Copy1Click end end end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/zconf.inc����������������������������������������������������������0000755�0001750�0001750�00000001274�10251433460�016017� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ -------------------------------------------------------------------- } {$DEFINE MAX_MATCH_IS_258} { Compile with -DMAXSEG_64K if the alloc function cannot allocate more than 64k bytes at a time (needed on systems with 16-bit int). } {- $DEFINE MAXSEG_64K} {$IFNDEF WIN32} {$DEFINE UNALIGNED_OK} { requires SizeOf(ush) = 2 ! } {$ENDIF} {$UNDEF DYNAMIC_CRC_TABLE} {$UNDEF FASTEST} {$define patch112} { apply patch from the zlib home page } { -------------------------------------------------------------------- } {$IFDEF FPC} {$DEFINE Use32} {$UNDEF DPMI} {$UNDEF MSDOS} {$UNDEF UNALIGNED_OK} { requires SizeOf(ush) = 2 ! } {$UNDEF MAXSEG_64K} {$ENDIF} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/nifti_img_view.pas�������������������������������������������������0000755�0001750�0001750�00000543515�12372022034�017717� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit nifti_img_view; {$mode delphi} interface {$IFDEF UNIX} {$IFNDEF ENDIAN_BIG}{$DEFINE COMPILEYOKE}{$ENDIF} //not supported on PPC {$ENDIF} uses {$H+} {$IFDEF Darwin}CarbonOpenDoc,{$ENDIF} {$IFDEF Unix} lclintf,LCLType,//gettickcount ,LMessages {$ELSE} Windows,ShellAPI, {$ENDIF} {$IFDEF COMPILEYOKE} yokesharemem, {$ENDIF} LResources, fx8, cpucount, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus, ComCtrls, ExtCtrls, StdCtrls, GraphicsMathLibrary, ClipBrd, define_types, Spin, Buttons, nifti_hdr, nifti_hdr_view, nifti_img, voismooth, IniFiles, ReadInt, stat, Distr, bet, mni, prefs, CropEdges,nifti_types, userdir, graphx, GraphType, IntfGraphics, landmarks,fastsmooth, nii_label;//registry type { TImgForm } TImgForm = class(TForm) AutoContrastBtn: TSpeedButton; ColorBarBtn: TSpeedButton; LayerDrop: TComboBox; LUTdrop: TComboBox; LutFromZeroBtn: TSpeedButton; MainMenu1: TMainMenu; File1: TMenuItem; MaxWindowEdit: TFloatSpinEdit; MenuItem1: TMenuItem; HistoMenu: TMenuItem; Header1: TMenuItem; ApplyClusterThreshold1: TMenuItem; LRFlip1: TMenuItem; ExportasRGBAnalyzeimage1: TMenuItem; BatchROImean1: TMenuItem; Batchprobmaps1: TMenuItem; Batchclusterprobmaps1Batchclusterprobmaps1Click: TMenuItem; Axial1: TMenuItem; Coronal1: TMenuItem; Axial2: TMenuItem; Coronal2: TMenuItem; Landmarks1: TMenuItem; Extract1: TMenuItem; HideDrawMenuItem: TMenuItem; DrawHiddenMenu: TMenuItem; MenuItem2: TMenuItem; Sagittal2: TMenuItem; Sagittal1: TMenuItem; Multiple1: TMenuItem; PGImageAx: TImage; PGImageSag: TImage; Resliceimage1: TMenuItem; AdjustimagessoVOIintensityiszero1: TMenuItem; Brainmask1: TMenuItem; GenerateSPM5maskslesions1: TMenuItem; RescaleMenu: TMenuItem; BrainExtraction1: TMenuItem; CropEdges1: TMenuItem; NIIVOI: TMenuItem; MinWindowEdit: TFloatSpinEdit; N4DTraces1: TMenuItem; LayerPanel: TPanel; n5: TMenuItem; Preferences1: TMenuItem; Display2: TMenuItem; MNIMenu: TMenuItem; Open1: TMenuItem; CloseImages: TMenuItem; Exit1: TMenuItem; Edit1: TMenuItem; Copy1: TMenuItem; Help1: TMenuItem; About1: TMenuItem; ControlPanel: TPanel; Crosshair1: TMenuItem; Pen1: TMenuItem; Penautoclose1: TMenuItem; CircleSquare1: TMenuItem; YokeTimer: TTimer; XViewEdit: TSpinEdit; YViewEdit: TSpinEdit; ZViewEdit: TSpinEdit; MagPanel: TPanel; ProgressBar1: TProgressBar; StatusLabel: TLabel; LabelX: TLabel; LabelY: TLabel; LabelZ: TLabel; Templates1: TMenuItem; Recent1: TMenuItem; Controls1: TMenuItem; ZoomDrop: TComboBox; Panel1: TPanel; Saveaspicture1: TMenuItem; SaveDialog1: TSaveDialog; ColorDialog1: TColorDialog; RefreshImagesTimer: TTimer; MagnifyMenuItem: TMenuItem; OverlayMenu: TMenuItem; OverlayOpen: TMenuItem; LayerMenu: TMenuItem; Noneopen1: TMenuItem; OverlaySmoothMenu: TMenuItem; CloseOverlayImg: TMenuItem; BGTransPctMenu: TMenuItem; OverlayTransPctMenu: TMenuItem; BGtrans0: TMenuItem; BGtrans20: TMenuItem; BGtrans40: TMenuItem; BGtrans50: TMenuItem; BGtrans60: TMenuItem; BGtrans80: TMenuItem; BGtrans100: TMenuItem; N0opaque1: TMenuItem; N201: TMenuItem; N401: TMenuItem; N501: TMenuItem; N601: TMenuItem; N801: TMenuItem; N100transparent1: TMenuItem; Layerrange1: TMenuItem; Noneopen2: TMenuItem; BGAdditive: TMenuItem; OverlayAdditive: TMenuItem; ShowRender: TMenuItem; DrawMenu: TMenuItem; OpenVOI: TMenuItem; SaveVOI: TMenuItem; CloseVOI: TMenuItem; VOIColor: TMenuItem; TriplePanel: TScrollBox; PGImageCor: TImage; Undo1: TMenuItem; Paste1: TMenuItem; Applyintensityfiltertovolume1: TMenuItem; Quicksmooth1: TMenuItem; MaskimagewithVOI1: TMenuItem; VOImaskDelete: TMenuItem; VOImaskPreserve: TMenuItem; SaveasNIfTI1: TMenuItem; Circle1: TMenuItem; Overlaycomparisons1: TMenuItem; IntersectionmutualtoVOIandoverlays1: TMenuItem; UnionVOIoroverlays1: TMenuItem; MaskVOIbutnotoverlays1: TMenuItem; RescaleImagesTimer: TTimer; SmoothVOI1: TMenuItem; Circle2: TMenuItem; Beta1: TMenuItem; Chisquare1: TMenuItem; Convert1: TMenuItem; ROIVOI1: TMenuItem; Statistics1: TMenuItem; ShowMultislice: TMenuItem; DescriptiveMenuItem: TMenuItem; N1: TMenuItem; HideROIBtn: TSpeedButton; XBarBtn: TSpeedButton; ToolPanel: TPanel; PenBtn: TSpeedButton; ClosedPenBtn: TSpeedButton; FillBtn: TSpeedButton; EllipseBtn: TSpeedButton; Fill3DBtn: TSpeedButton; N2: TMenuItem; Display1: TMenuItem; N3: TMenuItem; FlipLRmenu: TMenuItem; N4: TMenuItem; Menu2DSmooth: TMenuItem; VOI2NII: TMenuItem; Nudge1: TMenuItem; Up1: TMenuItem; Left1: TMenuItem; LeftX1: TMenuItem; RightX1: TMenuItem; Posterior1: TMenuItem; Posterior2: TMenuItem; YokeMenu: TMenuItem; procedure Extract1Click(Sender: TObject); procedure ToggleDrawMenu(Sender: TObject); procedure SaveVOIcore(lPromptFilename: boolean); procedure FormOpenFileMethod(const FileName : string); procedure Landmarks1Click(Sender: TObject); procedure SetIniMenus; procedure Batchclusterprobmaps1Batchclusterprobmaps1ClickClick(Sender: TObject); procedure Batchprobmaps1Click(Sender: TObject); procedure BatchROImean1Click(Sender: TObject); procedure BrainMask1Click(Sender: TObject); procedure ControlPanelDragDrop(Sender, Source: TObject; X, Y: Integer); procedure GenerateSPM5maskslesions1Click(Sender: TObject); procedure LoadOverlay (lFilename: string); procedure LoadOverlayIncludingRGB (lFilename: string); procedure ApplyClusterThreshold1Click(Sender: TObject); procedure BETmenuClick(Sender: TObject); procedure C(Sender: TObject); procedure CropMenuClick(Sender: TObject); procedure ExportasRGBAnalyzeimage1Click(Sender: TObject); procedure FormDropFiles(Sender: TObject; const FileNames: array of String); //procedure DropFilesOSX(Sender: TObject; const FileNames: array of String); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormKeyPress(Sender: TObject; var Key: char); procedure Header1Click(Sender: TObject); procedure HistoMenuClick(Sender: TObject); procedure LayerDropChange(Sender: TObject); procedure LUTdropChange(Sender: TObject); procedure AdjustimagessoVOIintensityiszero1Click(Sender: TObject); procedure MirrorNII1Click(Sender: TObject); procedure MNIMenuClick(Sender: TObject); procedure N4DTraces1Click(Sender: TObject); procedure NIIVOIClick(Sender: TObject); procedure PGImageCorDblClick(Sender: TObject); procedure Preferences1Click(Sender: TObject); procedure RescaleMenuClick(Sender: TObject); procedure Resliceimage1Click(Sender: TObject); procedure SaveasNIfTI1Click(Sender: TObject); procedure SaveDialog1Close(Sender: TObject); procedure UpdateColorSchemes; procedure UpdateTemplates; procedure UpdateMRU; procedure UpdateStatusLabel; procedure Exit1Click(Sender: TObject); procedure About1Click(Sender: TObject); procedure DisplayHdrClick(Sender: TObject); procedure Open1Click(Sender: TObject); procedure ToolSelectClick(Sender: TObject); procedure Copy1Click(Sender: TObject); procedure FormCreate(Sender: TObject); function OpenAndDisplayImg(var lFilename: string; lAdd2MRU: boolean): boolean; procedure OpenTemplateMRU(Sender: TObject); procedure XViewEditChange(Sender: TObject); procedure ReadIniFile; //read init file values procedure WriteIniFile; {$IFNDEF FPC} procedure FormClose(Sender: TObject; var Action: TCloseAction); {$ELSE} procedure FormClose(Sender: TObject); {$ENDIF} procedure MagnifyTimerTimer(Sender: TObject); procedure MagnifyPanelResize(Sender: TObject); procedure PGImageMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer); procedure FormMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); procedure FormMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); procedure PGImageMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure PGImageMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure LUTdropLoad(var lLayer: integer); procedure LUTdropSelect(Sender: TObject); procedure ZoomDropChange(Sender: TObject); procedure ZoomDropSelect(Sender: TObject); procedure ColorBarBtnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Saveaspicture1Click(Sender: TObject); procedure XBarBtnClick(Sender: TObject); procedure XBarBtnMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure XBarBtnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure AutoContrastBtnClick(Sender: TObject); procedure RefreshImagesTimerTimer(Sender: TObject); procedure MinContrastWindowEditChange(Sender: TObject); procedure ImgPanelClick(Sender: TObject); procedure MagnifyMenuItemClick(Sender: TObject); procedure CloseImagesClick(Sender: TObject); procedure UpdateLayerMenu; procedure OverlayOpenCore (var lFilename: string; lOverlayNum: integer); procedure OverlayOpenClick(Sender: TObject); procedure CloseOverlayImgClick(Sender: TObject); procedure BGtrans100Click(Sender: TObject); procedure OverlayTransClick(Sender: TObject); procedure LayerDropSelect(Sender: TObject); procedure OverlaySmoothMenuClick(Sender: TObject); procedure MaxContrastWindowEditChange(Sender: TObject); procedure ShowRenderClick(Sender: TObject); procedure PenBtnClick(Sender: TObject); procedure OpenVOIClick(Sender: TObject); procedure OpenVOICore(var lFilename : string); procedure SaveVOIClick(Sender: TObject); procedure VOIColorClick(Sender: TObject); procedure CloseVOIClick(Sender: TObject); procedure SetDimension8(lInPGHt,lInPGWid:integer; lBuff: ByteP; lUndoOnly: boolean); procedure Undo1Click(Sender: TObject); procedure Paste1Click(Sender: TObject); procedure HideROIBtnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure HideROIBtnMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure XBarColor; procedure Applyintensityfiltertovolume1Click(Sender: TObject); procedure Quicksmooth1Click(Sender: TObject); procedure VOImaskClick(Sender: TObject); procedure Sagittal1Click(Sender: TObject); procedure ROIcomparisonClick(Sender: TObject); procedure RescaleImagesTimerTimer(Sender: TObject); procedure Fill3DBtnClick(Sender: TObject); procedure SmoothVOI1Click(Sender: TObject); procedure CreateOverlap(Sender: TObject); procedure Chisquare1Click(Sender: TObject); procedure ROIVOI1Click(Sender: TObject); procedure LUTinvertBtnClick(Sender: TObject); procedure LutFromZeroBtnClick(Sender: TObject); procedure ShowMultisliceClick(Sender: TObject); procedure DescriptiveMenuItemClick(Sender: TObject); procedure FormResize(Sender: TObject); procedure FormShow(Sender: TObject); procedure OnLaunch; procedure FlipLRmenuClick(Sender: TObject); procedure Menu2DSmoothClick(Sender: TObject); procedure VALclick(Sender: TObject); procedure VOI2NIIClick(Sender: TObject); procedure TtoP1Click(Sender: TObject); procedure DesignVALClick(Sender: TObject); procedure Up1Click(Sender: TObject); procedure SetShareMem (lXmm,lYmm,lZmm: single); procedure CreateShareMem; procedure CloseShareMem; procedure YokeTimerTimer(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure YokeMenuClick(Sender: TObject); procedure DefaultControlPanel; procedure ControlPanelDblClick(Sender: TObject); procedure ResizeControlPanel (lRows: integer); procedure SaveOrCopyImages(lCopy: boolean); function ImgIntensityString(var lHdr: TMRIcroHdr; lVox: integer): string; overload; function ImgIntensityString(var lHdr: TMRIcroHdr; lX,lY,lZ: integer): string; overload; private { Private declarations } {$IFDEF FPC} function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;MousePos: TPoint): Boolean; override;{$ENDIF} public { Public declarations } public //procedure WMSysCommand (var Msg: TWMSysCommand) ; message WM_SYSCOMMAND; published property OnMouseWheel; end; const kYokeItems= 12; knMRU = 12;//max items in most recently used list knMaxOverlay = 20; kVOIOverlayNum = knMaxOverlay; kBGOverlayNum = 0; knAutoLUT = 7; kVOIFilter = 'Volume of interest (*.voi)|*.voi|MRIcro ROI (*.roi)|*.roi|'+kImgFilter; var gYoke: boolean = false; ImgForm: TImgForm; gBGImg: TBGImg; gMRIcroOverlay: array [0..knMaxOverlay] of TMRIcroHdr; gColorSchemeDir,gTemplateDir: String; gMRUstr: array [0..knMRU] of String; //most recently used files gMouseDownX,gMouseDownY: integer; gSelectOrigin: TPoint; gSelectRect: TRect; gOrigBGTransPct : integer= 50; //gMaxCPUThreads : integer = 8; gnCPUThreads : integer = 1; gUndoImg,gDrawImg: Tfx8; Type SingleArr = Array[1..kYokeItems] Of Single; SingleArrPtr = ^SingleArr; implementation uses statclustertable,batch,imgutil, reslice_fsl,render,ROIfilt,autoroi, MultiSlice, Text, histoform, about,clustering,ReadFloat; {$IFNDEF FPC} {$R *.DFM} {$ENDIF} procedure TImgForm.XBarColor; begin ColorDialog1.Color := gBGImg.XBarClr; if not ColorDialog1.Execute then exit; gBGImg.XBarClr := ColorDialog1.Color; RefreshImagesTimer.Enabled := true; exit; end; procedure DecViewEdit(var lEdit: TSpinEdit); begin if lEdit.Value > 1 then lEdit.value := lEdit.value -1 else lEdit.Value := lEdit.MaxValue; {$IFDEF FPC} ImgForm.XViewEditChange(nil); {$ENDIF} end; //DecViewEdit procedure IncViewEdit(var lEdit: TSpinEdit); begin if lEdit.Value < lEdit.MaxValue then lEdit.value := lEdit.value +1 else lEdit.Value := 1; {$IFDEF FPC} ImgForm.XViewEditChange(nil); {$ENDIF} end; //IncViewEdit function TImgForm.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; begin Result := inherited DoMouseWheel(Shift, WheelDelta, MousePos); //ImgForm.Caption := inttostr(random(888)); //... actions after a possible OnMouseWheel[Down|Up] //ImgForm.Caption := inttostr(WheelDelta)+' '+inttostr(random(888))+' '+inttostr(MousePos.X); if WheelDelta < 0 then begin Case SelectedImageNum of 3: DecViewEdit(YViewEdit); 2: DecViewEdit(XViewEdit); else DecViewEdit(ZViewEdit); end; end else begin Case SelectedImageNum of 3: IncViewEdit(YViewEdit); 2: IncViewEdit(XViewEdit); else IncViewEdit(ZViewEdit); end; end; end; procedure TImgForm.CloseShareMem; begin {$IFDEF COMPILEYOKE} YokeTimer.Enabled := false; CloseSharedMem; {$ENDIF} end; procedure TImgForm.SetShareMem (lXmm,lYmm,lZmm: single); begin {$IFDEF COMPILEYOKE} if not gYoke then exit; SetShareFloats(lXmm,lYmm,lZmm); {$ENDIF} end; procedure TImgForm.CreateShareMem; begin {$IFDEF COMPILEYOKE} CreateSharedMem(self); SetShareMem (0,0,0); YokeTimer.Enabled := gYoke; {$ENDIF} end; procedure TImgForm.YokeTimerTimer(Sender: TObject); var lX,lY,lZ: integer; lXmm,lYmm,lZmm: single; begin if not gYoke then YokeTimer.Enabled := false; {$IFDEF COMPILEYOKE} //labelx.caption := inttostr(random(888)); if not gYoke then exit; //LabelX.caption := inttostr(random(888)); if not GetShareFloats(lXmm,lYmm,lZmm) then exit; //LabelY.caption := inttostr(random(888)); MMToImgCoord(lX,lY,lZ,lXmm,lYmm,lZmm); if lX <> XViewEdit.value then XViewEdit.value := lX; if lY <> YViewEdit.value then YViewEdit.value := lY; if lZ <> ZViewEdit.value then ZViewEdit.value := lZ; XViewEditChange(nil); {$ENDIF} end; (*var lXmm,lYmm,lZmm: single; lX,lY,lZ: integer; begin if not gYoke then begin YokeTimer.Enabled := false; exit; end; if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems=0 then exit; {$IFDEF FPC} {$IFDEF COMPILEYOKE} lXmm:=gShareIntBuf^[1]; lYmm:=gShareIntBuf^[2]; lZmm:=gShareIntBuf^[3]; {$ELSE} YokeTimer.Enabled := false; exit; {$ENDIF} {$ELSE} EMemMap.EnterCriticalSection; Try lXmm:=SingleArrPtr(EMemMap.MemMap)^[1]; lYmm:=SingleArrPtr(EMemMap.MemMap)^[2]; lZmm:=SingleArrPtr(EMemMap.MemMap)^[3]; Finally EMemMap.LeaveCriticalSection; end; {$ENDIF} MMToImgCoord(lX,lY,lZ,lXmm,lYmm,lZmm); if lX <> XViewEdit.value then XViewEdit.value := lX; if lY <> YViewEdit.value then YViewEdit.value := lY; if lZ <> ZViewEdit.value then ZViewEdit.value := lZ; YokeTimer.Enabled := false; end; *) {$IFNDEF FPC} procedure TImgForm.WMSysCommand; begin if (Msg.CmdType = SC_MINIMIZE) then Application.Minimize else DefaultHandler(Msg) ; if (Msg.CmdType = SC_MAXIMIZE) then RefreshImagesTimer.enabled := true; end; {$ENDIF} function SelectedImagePanel: TScrollBox; begin case SelectedImageNum of 3: result := ImgForm.TriplePanel; 2: result := ImgForm.TriplePanel; else result := ImgForm.TriplePanel; end; end; function DrawToolSelected: boolean; begin if ( ImgForm.PenBtn.Down) or ( ImgForm.ClosedPenBtn.Down) or (ImgForm.FillBtn.Down) or (ImgForm.EllipseBtn.Down) then result := true else result := false; end; procedure TImgForm.WriteIniFile; var lInc: integer; lIni: string; lIniFile: TIniFile; begin lIni:= IniName; if (DiskFreeEx(lIni) < 1) or (not gBGIMg.SaveDefaultIni) then exit; //lIniFile := TIniFile.Create(changefileext(paramstr(0),'.ini')); lIniFile := TIniFile.Create(lIni);//DefaultsDir('')+ParseFileName(extractfilename(paramstr(0)))+'.ini'); //recent files lIniFile.WriteString('MRU', 'file0', gMRIcroOverlay[kBGOverlayNum].HdrFilename); for lInc := 1 to knMRU do lIniFile.WriteString('MRU', 'file'+inttostr(lInc), gMRUstr[lINc]); //STR //lIniFile.WriteString('STR', 'FSLDIR',gBGImg.FSLDIR); //lIniFile.WriteString('STR', 'FSLBETEXE',gBGImg.FSLBETEXE); lIniFile.WriteString('STR', 'FSLBASE',gBGImg.FSLBASE); lIniFile.WriteString('STR', 'FSLOUTPUTTYPE',gBGImg.FSLOUTPUTTYPE); //Booleans lIniFile.WriteString('BOOL', 'Reslice',Bool2Char(gBGImg.ResliceOnLoad)); lIniFile.WriteString('BOOL', 'ResliceOrtho',Bool2Char(gBGImg.OrthoReslice)); lIniFile.WriteString('BOOL', 'ShowDraw',Bool2Char(gBGImg.ShowDraw)); lIniFile.WriteString('BOOL', 'ThinPen',Bool2Char(gBGImg.ThinPen)); lIniFile.WriteString('BOOL', 'Smooth2D',Bool2Char(Menu2DSmooth.checked)); lIniFile.WriteString('BOOL', 'XBar',Bool2Char(XBarBtn.Down)); lIniFile.WriteString('BOOL', 'OverlaySmooth',Bool2Char(OverlaySmoothMenu.Checked)); lIniFile.WriteString('BOOL', 'LRmirror',Bool2Char(gBGImg.Mirror)); lIniFile.WriteString('BOOL', 'Yoke',Bool2Char(gYoke)); lIniFile.WriteString('BOOL', 'SingleRow',Bool2Char(gBGImg.SingleRow)); lIniFile.WriteString('BOOL', 'FlipAx',Bool2Char(gBGImg.FlipAx)); lIniFile.WriteString('BOOL', 'FlipSag',Bool2Char(gBGImg.FlipSag)); YokeTimer.Enabled := gYoke; //Integers //lIniFile.WriteString('INT', 'ResizeBeforeRescale',IntToStr(gBGImg.ResizeBeforeRescale)); lIniFile.WriteString('INT', 'FontSize',IntToStr(gBGImg.FontSize)); lIniFile.WriteString('INT', 'SaveImgFilter',IntToStr(gBGImg.SaveImgFilter)); lIniFile.WriteString('INT', 'SaveVoiFilter',IntToStr(gBGImg.SaveVoiFilter)); lIniFile.WriteString('INT', 'MaxDim',IntToStr(gBGImg.MaxDim)); lIniFile.WriteString('INT', 'LicenseID',IntToStr(gBGImg.LicenseID)); lIniFile.WriteString('INT', 'Zoom',IntToStr(ZoomDrop.ItemIndex)); lIniFile.WriteString('INT', 'LUT',IntToStr(gMRIcroOverlay[kBGOverlayNum].LUTindex)); lIniFile.WriteString('INT', 'XBarGap',IntToStr(gBGImg.XBarGap)); lIniFile.WriteString('INT', 'XBarThick',IntToStr(gBGImg.XBarThick)); lIniFile.WriteString('INT', 'XBarClr',IntToStr(gBGIMg.XBarClr)); lIniFile.WriteString('INT', 'VOIClr',IntToStr(gBGIMg.VOIClr)); if (gBGImg.BGTransPct < 0) or (gBGImg.BGTransPct > 90) then gBGImg.BGTransPct := 20; //additive or transparent values can confuse users if (gBGImg.OverlayTransPct < 0) or (gBGImg.OverlayTransPct > 90) then gBGImg.OverlayTransPct := 20; //additive or transparent values can confuse users lIniFile.WriteString('INT', 'BGTransPct',IntToStr(gBGImg.BGTransPct)); lIniFile.WriteString('INT', 'OverlayTransPct',IntToStr(gBGImg.OverlayTransPct)); lIniFile.WriteString('INT','MaxThreads',IntToStr(gnCPUThreads)); lIniFile.WriteString('INT', 'LesionDilate',IntToStr(gBGImg.LesionDilate)); lIniFile.WriteString('INT', 'LesionSmooth',IntToStr(gBGImg.LesionSmooth)); // {$ELSE} // lIniFile.WriteString('INT', 'MaxThreads',IntToStr(gMaxCPUThreads)); // {$ENDIF} lIniFile.WriteString('INT', 'SigDigits',IntToStr(gBGImg.SigDig)); lIniFile.WriteString('INT', 'ImageSeparation',IntToStr(gBGImg.ImageSeparation)); lIniFile.WriteString('INT', 'SPMDefaultsStatsFmriT',IntToStr(gBGImg.SPMDefaultsStatsFmriT)); lIniFile.WriteString('INT', 'SPMDefaultsStatsFmriT0',IntToStr(gBGImg.SPMDefaultsStatsFmriT0)); lIniFile.Free; end; (* function registerfiletype(inft,inkey,desc,icon:string): boolean; var myreg : treginifile; ct : integer; ft,key: string; begin result := true; ft := inft; key := inkey; ct := pos('.',ft); while ct > 0 do begin delete(ft,ct,1); ct := pos('.',ft); end; if (ft = '') or (Application.ExeName = '') then exit; //not a valid file-ext or ass. app ft := '.'+ft; myreg := treginifile.create(''); try myreg.rootkey := hkey_classes_root; // where all file-types are described if key = '' then key := copy(ft,2,maxint)+'_auto_file'; // if no key-name is given, create one myreg.writestring(ft,'',key); // set a pointer to the description-key myreg.writestring(key,'',desc); // write the description myreg.writestring(key+'\DefaultIcon','',icon); // write the def-icon if given myreg.writestring(key+'\shell\open\command','',Application.ExeName+' %1'); //association except result := false; showmessage('Only administrators can change file associations. You are currently logged in as a restricted user.'); end; myreg.free; end; *) procedure WriteIni2Form (lBGImg: TBGImg); begin ImgForm.ToolPanel.Visible := lBGImg.ShowDraw; ImgForm.DrawMenu.Visible := lBGImg.ShowDraw; ImgForm.DrawHiddenMenu.Visible := not lBGImg.ShowDraw; end; procedure TImgForm.SetIniMenus; begin XBarBtn.Down := gBGImg.XBarVisible; YokeMenu.Checked := gYoke; Menu2DSmooth.checked := gBGImg.StretchQuality = sqHigh; Menu2DSmoothClick(nil);//set quality end; procedure TImgForm.ReadIniFile; var lInc,lFilenum: integer; lFilename: string; lIniFile: TIniFile; begin //lFilename := changefileext(paramstr(0),'.ini'); lFilename := ininame;//DefaultsDir('')+ParseFileName(extractfilename(paramstr(0)))+'.ini'; if not FileexistsEx(lFilename) then begin //DrawMenu.Visible := ToolPanel.visible; WriteIni2Form(gBGImg); exit; end; lIniFile := TIniFile.Create(lFilename); gMRUstr[0] := lIniFile.ReadString('MRU', 'file0', '');//file0 - last file viewed lFileNum := 0; for lInc := 1 to knMRU do begin lFilename := lIniFile.ReadString('MRU', 'file'+inttostr(lInc), ''); if (length(lFilename) > 0) and (fileexistsex(lFilename)) then begin Inc(lFileNum); gMRUstr[lFileNum] := lFilename; end; end; gBGImg.FSLOUTPUTTYPE := lIniFile.ReadString('STR', 'FSLOUTPUTTYPE', gBGImg.FSLOUTPUTTYPE); //gBGImg.FSLDIR := lIniFile.ReadString('STR', 'FSLDIR', gBGImg.FSLDIR); //gBGImg.FSLBETEXE := lIniFile.ReadString('STR', 'FSLBETEXE', gBGImg.FSLBETEXE); gBGImg.FSLBASE := lIniFile.ReadString('STR', 'FSLDIR', gBGImg.FSLBASE); gBGImg.ResliceOnLoad := IniBool(lIniFile,'Reslice',gBGImg.ResliceOnLoad); gBGImg.OrthoReslice := IniBool(lIniFile,'ResliceOrtho',gBGImg.OrthoReslice); gBGImg.ThinPen := IniBool(lIniFile, 'ThinPen',True); gBGImg.ShowDraw := IniBool(lIniFile, 'ShowDraw',gBGImg.ShowDraw); WriteIni2Form(gBGImg); if IniBool(lIniFile,'Smooth2D',Menu2DSmooth.checked) then gBGImg.StretchQuality := sqHigh else gBGImg.StretchQuality := sqLow; //Menu2DSmooth.checked := IniBool(lIniFile,'Smooth2D',Menu2DSmooth.checked); Menu2DSmoothClick(nil);//set quality gBGImg.XBarVisible := IniBool(lIniFile,'XBar',XBarBtn.Down); gBGImg.OverlaySmooth := IniBool(lIniFile,'OverlaySmooth',gBGImg.OverlaySmooth); OverlaySmoothMenu.Checked := gBGImg.OverlaySmooth; gBGImg.Mirror := IniBool(lIniFile,'LRmirror',gBGImg.Mirror); FlipLRmenu.Checked := gBGImg.Mirror; gYoke := IniBool(lIniFile,'Yoke',gYoke); gBGImg.SingleRow := IniBool(lIniFile,'SingleRow',gBGImg.SingleRow); gBGImg.FlipAx := IniBool(lIniFile,'FlipAx',gBGImg.FlipAx); gBGImg.FlipSag := IniBool(lIniFile,'FlipSag',gBGImg.FlipSag); gBGImg.MaxDim := IniInt(lIniFile,'MaxDim',gBGImg.MaxDim); gBGImg.LicenseID := IniInt(lIniFile,'LicenseID',gBGImg.LicenseID); {$IFNDEF FPC} ZoomDrop.SetItemIndex(IniInt(lIniFile,'Zoom',ZoomDrop.ItemIndex)); LUTDrop.SetItemIndex(IniInt(lIniFile,'LUT',LUTDrop.ItemIndex)); {$ELSE} ZoomDrop.ItemIndex := (IniInt(lIniFile,'Zoom',ZoomDrop.ItemIndex)); LUTDrop.ItemIndex:= (IniInt(lIniFile,'LUT',LUTDrop.ItemIndex)); {$ENDIF} gBGImg.XBarGap := IniInt(lIniFile,'XBarGap',gBGImg.XBarGap); gBGImg.XBarThick := IniInt(lIniFile,'XBarThick',gBGImg.XBarThick); gBGImg.XBarClr := IniInt(lIniFile,'XBarClr',gBGImg.XBarClr); gBGImg.VOIClr := IniInt(lIniFile,'VOIClr',gBGImg.VOIClr); gBGImg.BGTransPct := IniInt(lIniFile,'BGTransPct',gBGImg.BGTransPct); gBGImg.OverlayTransPct := IniInt(lIniFile,'OverlayTransPct',gBGImg.OverlayTransPct); gnCPUThreads := IniInt(lIniFile,'MaxThreads',gnCPUThreads); gBGImg.SigDig := IniInt(lIniFile,'SigDigits',gBGImg.SigDig); gBGImg.ImageSeparation := IniInt(lIniFile,'ImageSeparation',gBGImg.ImageSeparation); gBGImg.FontSize := IniInt(lIniFile,'FontSize',gBGImg.FontSize); gBGImg.SaveImgFilter := IniInt(lIniFile,'SaveImgFilter',gBGImg.SaveImgFilter); gBGImg.SaveVoiFilter := IniInt(lIniFile,'SaveVoiFilter',gBGImg.SaveVoiFilter); gBGImg.SPMDefaultsStatsFmriT := IniInt(lIniFile,'SPMDefaultsStatsFmriT',gBGImg.SPMDefaultsStatsFmriT); gBGImg.SPMDefaultsStatsFmriT0 := IniInt(lIniFile,'SPMDefaultsStatsFmriT0',gBGImg.SPMDefaultsStatsFmriT0); gBGImg.LesionSmooth := IniInt(lIniFile,'LesionSmooth',gBGImg.LesionSmooth); gBGImg.LesionDilate := IniInt(lIniFile,'LesionDilate',gBGImg.LesionDilate); SetSubmenuWithTag(BGTransPctMenu, gBGImg.BGTransPct); SetSubmenuWithTag(OverlayTransPctMenu, gBGImg.OverlayTransPct); lIniFile.Free; end; //ReadIniFile //lStrings := TStringList.Create; procedure TImgForm.UpdateColorSchemes; var lSearchRec: TSearchRec; lStrings : TStringList; begin LUTdrop.Items.Clear; LUTdrop.Items.Add('Grayscale'); LUTdrop.Items.Add('Red'); LUTdrop.Items.Add('Blue'); LUTdrop.Items.Add('Green'); LUTdrop.Items.Add('Violet [r+b]'); LUTdrop.Items.Add('Yellow [r+g]'); LUTdrop.Items.Add('Cyan [g+b]'); lStrings := TStringList.Create; if FindFirst(gColorSchemeDir+pathdelim+'*.lut', faAnyFile, lSearchRec) = 0 then repeat lStrings.Add(ParseFileName(ExtractFileName(lSearchRec.Name))); //LUTdrop.Items.Add(ParseFileName(ExtractFileName(lSearchRec.Name))); until (FindNext(lSearchRec) <> 0); FindClose(lSearchRec); lStrings.Sort; LUTdrop.Items.AddStrings(lStrings); lStrings.Free; //LUTDrop.DropDownCount := 66;//LUTDrop.Items.Count; end;//UpdateColorSchemes (*procedure TImgForm.UpdateColorSchemes; var lSearchRec: TSearchRec; begin LUTdrop.Items.Clear; LUTdrop.Items.Add('Grayscale'); LUTdrop.Items.Add('Red'); LUTdrop.Items.Add('Blue'); LUTdrop.Items.Add('Green'); LUTdrop.Items.Add('Violet [r+b]'); LUTdrop.Items.Add('Yellow [r+g]'); LUTdrop.Items.Add('Cyan [g+b]'); if FindFirst(gColorSchemeDir+pathdelim+'*.lut', faAnyFile, lSearchRec) = 0 then repeat LUTdrop.Items.Add(ParseFileName(ExtractFileName(lSearchRec.Name))); until (FindNext(lSearchRec) <> 0); FindClose(lSearchRec); xxx //LUTDrop.DropDownCount := 66;//LUTDrop.Items.Count; end;//UpdateColorSchemes *) procedure TImgForm.BETmenuClick(Sender: TObject); begin BetForm.show; end; procedure TImgForm.ApplyClusterThreshold1Click(Sender: TObject); var lNumberofFiles,lC,lClusterSz: integer; lThresh: double; lFilename: string; begin CloseImagesClick(nil); if not OpenDialogExecute(kImgFilter,'Select NIfTI format images to convert',true) then exit; lNumberofFiles:= HdrForm.OpenHdrDlg.Files.Count; lClusterSz := ReadIntForm.GetInt('Minimum cluster size [in voxels]: ', 1,32,9999); lThresh := ReadFloatForm.GetFloat('Include voxels with an intensity above: ', 0,2,9999); ProgressBar1.Min := 0; ProgressBar1.Max :=lNumberofFiles; ProgressBar1.Position := 0; for lC:= 1 to lNumberofFiles do begin lFilename := HdrForm.OpenHdrDlg.Files[lC-1]; ImgForm.OpenAndDisplayImg(lFilename,True); //lFilename := changefileextX(lFilename,'I'+inttostr(round(lThresh))+'C'+inttostr(lClusterSz)+'.nii.gz'); lFilename := changefileprefix(lFilename,'I'+inttostr(round(lThresh))+'C'+inttostr(lClusterSz)); if ClusterFilterScrnImg (gMRIcroOverlay[kBGOverlayNum],lClusterSz,lThresh ) then if ImgVaries(gMRIcroOverlay[kBGOverlayNum]) then SaveAsVOIorNIFTIcore (lFilename, gMRIcroOverlay[kBGOverlayNum].ImgBuffer,gMRIcroOverlay[kBGOverlayNum].ImgBufferItems,gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr) else showmessage('No clusters survive filter '+ HdrForm.OpenHdrDlg.Files[lC-1]); ProgressBar1.Position := lC; end; if fileexistsEX(lFilename) then ImgForm.OpenAndDisplayImg(lFilename,True); ProgressBar1.Position := 0; end; procedure TImgForm.C(Sender: TObject); begin end; procedure TImgForm.CropMenuClick(Sender: TObject); begin CropEdgeForm.Show; end; procedure TImgForm.ExportasRGBAnalyzeimage1Click(Sender: TObject); var lFlip: boolean; begin lFlip := gBGImg.Mirror; gBGImg.Mirror := true; CreateAnaRGB; gBGImg.Mirror := lFlip; end; procedure TImgForm.FormDropFiles(Sender: TObject; const FileNames: array of String); var lFilename: string; begin if length(FileNames) < 1 then exit; lFilename := Filenames[0]; OpenAndDisplayImg(lFilename,true); end; procedure TImgForm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin //ImgForm.caption := inttostr(Key); if (XViewEdit.focused) or (YViewEdit.focused) or (ZViewEdit.focused) or (MinWindowEdit.focused) or (MaxWindowEdit.focused) then exit; Case Key of 36: DecViewEdit(YViewEdit); 35: IncViewEdit(YViewEdit); 37: DecViewEdit(XViewEdit); 38: IncViewEdit(ZViewEdit); 39: IncViewEdit(XViewEdit); 40: DecViewEdit(ZViewEdit); end; //case Key (* if WheelDelta < 0 then begin Case SelectedImageNum of 3: DecViewEdit(YViewEdit); 2: DecViewEdit(XViewEdit); else DecViewEdit(ZViewEdit); end; end else begin Case SelectedImageNum of 3: IncViewEdit(YViewEdit); 2: IncViewEdit(XViewEdit); else IncViewEdit(ZViewEdit); end; end;*) end; procedure TImgForm.FormKeyPress(Sender: TObject; var Key: char); begin //imgform.caption := 'zzz'; end; procedure TImgForm.Header1Click(Sender: TObject); begin DisplayHdrClick(nil); end; function ActiveLayer:integer; begin result := ImgForm.LayerDrop.ItemIndex; if result < 0 then result := 0; end; {$DEFINE noTEST} {$IFDEF TEST} procedure DrawBMP2( lx, ly: integer; var lBuff: RGBQuadp; var lImage: TImage); //uses GraphType, IntfGraphics var IntfImage: TLazIntfImage; ScanLineImage: TLazIntfImage; ImgFormatDescription: TRawImageDescription; lBitmap: TBitmap; begin lBitmap:=TBitmap.Create; ScanLineImage:=TLazIntfImage.Create(0,0); ImgFormatDescription.Init_BPP32_B8G8R8_BIO_TTB(lx,ly); ScanLineImage.DataDescription:=ImgFormatDescription; // call the pf24bit specific drawing function Move(lBuff^[1],PByte(ScanLineImage.GetDataLineStart(0))[1],lx*ly*sizeof(TRGBquad) ); lBitmap.Width:=ScanLineImage.Width; lBitmap.Height:=ScanLineImage.Height; IntfImage:=lBitmap.CreateIntfImage; // convert the content from the very specific to the current format IntfImage.CopyPixels(ScanLineImage); lBitmap.LoadFromIntfImage(IntfImage); ScanLineImage.Free; IntfImage.Free; lImage.Picture.Bitmap := lBitmap; lBitmap.Free; end; procedure FZ; var l2Time,lTime: DWord; y,x,lx, ly, lpos: integer; lBuff: RGBQuadp ; begin lx := 320; ly := 320; getmem(lBuff,(lx*ly)*sizeof( TRGBquad)); lpos := 0; for y := 1 to ly do begin for x := 1 to lx do begin inc(lpos); lBuff^[lpos].rgbblue := (y mod 255); lBuff^[lpos].rgbgreen :=(y mod 255); lBuff^[lpos].rgbred := (x mod 255) ; lBuff^[lpos].rgbreserved := 0; end; end; l2Time := GetTickCount; for y := 1 to 100 do DrawBMP2( lx, ly, lBuff,HistogramForm.HistoImage{lImage}); l2Time := GetTickCount - l2Time; lTime := GetTickCount; for y := 1 to 100 do DrawBMP( lx, ly, lBuff,HistogramForm.HistoImage{lImage}); lTime := GetTickCount - lTime; HistogramForm.Caption := inttostr(lTime)+' '+inttostr(l2Time); freemem(lBuff); end; {$ENDIF} procedure TImgForm.HistoMenuClick(Sender: TObject); VAR lLayer: integer; begin {$IFDEF TEST} FZ; {$ELSE} lLayer := ActiveLayer; DrawHistogram(gMRIcroOverlay[lLayer],HistogramForm.HistoImage{lImage}); HistogramForm.Caption := 'Histogram: '+extractfilename(gMRIcroOverlay[lLayer].HdrFileName); {$ENDIF} HistogramForm.show; //HistogramForm.BringToFront; end; procedure TImgForm.MNIMenuClick(Sender: TObject); begin MNIForm.show; //MNIForm.BringToFront; end; procedure TImgForm.N4DTraces1Click(Sender: TObject); begin Graph4DForm.show; //Graph4DForm.BringToFront; end; procedure TImgForm.NIIVOIClick(Sender: TObject); var lNumberofFiles,lC: integer; lFilename: string; begin CloseImagesClick(nil); if not OpenDialogExecute(kImgFilter {10/2007},'Select NIfTI format images to convert',true) then exit; lNumberofFiles:= HdrForm.OpenHdrDlg.Files.Count; ProgressBar1.Min := 0; ProgressBar1.Max :=lNumberofFiles; ProgressBar1.Position := 0; for lC:= 1 to lNumberofFiles do begin lFilename := HdrForm.OpenHdrDlg.Files[lC-1]; ImgForm.OpenAndDisplayImg(lFilename,True); lFilename := changefileextx(lFilename,'.voi'); ////Xversion 10/2007 - removes .nii.gz not just gz //SaveAsVOIorNIFTIcore (lFilename, lByteP, lVoxels, 1, gMRIcroOverlay[kBGOverlayNum].NiftiHdr); SaveAsVOIorNIFTIcore (lFilename, gMRIcroOverlay[kBGOverlayNum].ScrnBuffer,gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems, 1,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr); CloseVOIClick(nil); ProgressBar1.Position := lC; end; ProgressBar1.Position := 0; end; procedure TImgForm.PGImageCorDblClick(Sender: TObject); begin if Graph4DForm.visible then Graph4DForm.RefreshBtn.click; end; procedure TImgForm.Preferences1Click(Sender: TObject); begin PrefForm.ShowModal; end; function RescaleImg( lRescaleIntercept,lRescaleSlope: double): boolean; var //lRow,lNumberofFiles,lX,lY,lZ: integer; //lFilename: string; lHdr:TMRIcroHdr; lImgSamples,lInc,lBPP: integer; l32Buf,lo32Buf : SingleP; l16Buf : SmallIntP; begin //note ignores input slope/intercept scaling values result := false; if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1 then begin showmessage('Please load a background image for rescaling.'); exit; end; if ((gBGImg.ScrnDim[1] * gBGImg.ScrnDim[2] * gBGImg.ScrnDim[3]) <> gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems) then begin showmessage('Unable to rescale.'); exit; end; lBPP := gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP;//check if BitsPerPixel is supported if (lBPP <> 4) and (lBPP <> 2) and (lBPP <> 1) then begin showmessage('RescaleImg Error: Unsupported BPP: '+inttostr(lBPP)); exit; end; lImgSamples := gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems; MakeStatHdr (gMRIcroOverlay[kBGOverlayNum],lHdr,0{min}, 0{max},0{p1},0{p2},0{p3},kNIFTI_INTENT_NONE,floattostr(lRescaleSlope) ); GetMem(lHdr.ImgBufferUnaligned ,(lImgSamples*4)+16); //svn lHdr.ImgBuffer := ByteP($fffffff0 and (integer(lHdr.ImgBufferUnaligned)+15)); lHdr.ImgBuffer := align(lHdr.ImgBufferUnaligned, 16); lo32Buf := SingleP( lHdr.ImgBuffer ); if lBPP = 4 then begin l32Buf := SingleP( gMRIcroOverlay[kBGOverlayNum].ImgBuffer ); for lInc := 1 to lImgSamples do lo32Buf^[lInc] := (l32Buf^[lInc]+lRescaleIntercept) * lRescaleSlope; end else if lBPP = 2 then begin //lBPP=4 else l16Buf := SmallIntP( gMRIcroOverlay[kBGOverlayNum].ImgBuffer ); for lInc := 1 to lImgSamples do lo32Buf^[lInc] := (l16Buf^[lInc]+lRescaleIntercept) * lRescaleSlope; end else if lBPP = 1 then begin //lBPP=2 else for lInc := 1 to lImgSamples do lo32Buf^[lInc] := (gMRIcroOverlay[kBGOverlayNum].ImgBuffer^[lInc]+lRescaleIntercept) * lRescaleSlope; end;//lBPP = 1 SaveAsVOIorNIFTI(bytep(lo32Buf),lImgSamples,4,1,false,lHdr.NiftiHdr,'rscl'+extractfilename(gMRIcroOverlay[kBGOverlayNum].HdrFilename)); //SaveAsVOIorNIFTI(gMRIcroOverlay[lLayer].ImgBuffer,gMRIcroOverlay[lLayer].ImgBufferItems,gMRIcroOverlay[lLayer].ImgBufferBPP,1,false,gMRIcroOverlay[kBGOverlayNum].NiftiHdr,gMRIcroOverlay[lLayer].HdrFilename); FreeMem(lHdr.ImgBufferUnaligned); //lFilename := 'c:\striped2.hdr'; //SaveAsVOIorNIFTIcore (lFilename, gMRIcroOverlay[kBGOverlayNum].ScrnBuffer,gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems, 1,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr); result := true; end; procedure TImgForm.RescaleMenuClick(Sender: TObject); var ldTE,lScale,lTE1,lTE2: double; //lStr: string; begin if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1 then begin showmessage('Please load a background image for rescaling.'); exit; end; if gBGImg.Resliced then begin if not HdrForm.OpenAndDisplayHdr(gMRIcroOverlay[kBGOverlayNum].HdrFileName,gMRIcroOverlay[kBGOverlayNum]) then exit; if not OpenImg(gBGImg,gMRIcroOverlay[0],true,false,false,false,false) then exit; end; if (gMRIcroOverlay[kBGOverlayNum].GlMinUnscaledS < 0) or (gMRIcroOverlay[kBGOverlayNum].GlMaxUnscaledS > 4096) then begin showmessage('Error: you need to load a Siemens format Phase map with raw values in the range 0..4096'); exit; end; lTE1 := ReadFloatForm.GetFloat('Please enter the first TE (ms) used for phasemap. ', 0,5.19,9999); lTE2 := ReadFloatForm.GetFloat('Please enter the second TE (ms) used for phasemap. ', 0,7.65,9999); (*lStr := floattostr(5.19); //use floattostr for local decimal separator if not InputQuery('TEs used to create phasemap','Please enter the first TE in ms', lStr) then exit; try lTE1 := strtofloat(lStr); except showmessage('Unable to convert the string '+lStr+' to a number'); exit; end; lStr := floattostr(7.65); if not InputQuery('TEs used to create phasemap','Please enter the second TE in ms', lStr) then exit; try lTE2 := strtofloat(lStr); except showmessage('Unable to convert the string '+lStr+' to a number'); exit; end;*) if lTE1 = lTE2 then begin showmessage('In order to compute Rad/S the two TEs must be different.'); exit; end; //fx(lTE1,lTE2); //exit; //the fieldmap is simply a phase //difference image and is not scaled to any particular units. In Siemens //phase images the data goes from 0 to 4095 with 0 being -pi radians, 2048 //is 0 radians, and 4095 is just short of +pi radians. //So, to get units of radians/s you would need to know the difference in //echo times (dTE) in units of s (not ms). You would then take //(x-2048)(2pi/4096)/dTE //Note ignore original intercept and scale values //ldTE := abs(5.19 - 7.65)/1000; // div 1000 to scale ms to sec ldTE := abs(lTE1 - lTE2)/1000; // div 1000 to scale ms to sec lScale := (2*pi/4096)/ldTE; //showmessage(floattostr(lScale)); rescaleImg(-2048,lScale); end; procedure TImgForm.Resliceimage1Click(Sender: TObject); begin ResliceFSL; end; procedure TImgForm.SaveasNIfTI1Click(Sender: TObject); var lLayer: integer; begin lLayer := ActiveLayer; if gMRIcroOverlay[lLayer].ImgBufferItems=0 then begin Showmessage('You must load an image [File/Open] before you can save the image.'); exit; end; if (not IsNifTiMagic(gMRIcroOverlay[lLayer].niftiHdr)) then Showmessage('Warning: image will be saved with NIfTI spatial transform - ensure this image matches the orientation of the template images.'); SaveAsVOIorNIFTI(gMRIcroOverlay[lLayer].ImgBuffer,gMRIcroOverlay[lLayer].ImgBufferItems,gMRIcroOverlay[lLayer].ImgBufferBPP,1,false,gMRIcroOverlay[kBGOverlayNum].NiftiHdr,gMRIcroOverlay[lLayer].HdrFilename); end; procedure ApplySaveDlgFilter (lSaveDlg: TSaveDialog); var lLen,lPos,lPipes,lPipesReq: integer; lExt,lName: string; begin lPipesReq := (lSaveDlg.FilterIndex * 2)-1; if lPipesReq < 1 then exit; lLen := length(lSaveDlg.Filter); lPos := 1; lPipes := 0; while (lPos < lLen) and (lPipes < lPipesReq) do begin if lSaveDlg.Filter[lPos] = '|' then inc(lPipes); inc(lPos); end; if (lPos >= lLen) or (lPipes < lPipesReq) then exit; lExt := ''; while (lPos <= lLen) and (lSaveDlg.Filter[lPos] <> '|') do begin if lSaveDlg.Filter[lPos] <> '*' then lExt := lExt + lSaveDlg.Filter[lPos]; inc(lPos); end; lName := lSaveDlg.Filename; if lExt <> '' then lSaveDlg.Filename := ChangeFileExtX(lName,lExt); end; procedure TImgForm.SaveDialog1Close(Sender: TObject); begin ApplySaveDlgFilter(SaveDialog1); end; procedure Add2MRU (var lNewFilename: string); //add new file to most-recent list var lStr: string; lPos,lN : integer; begin //first, increase position of all old MRUs lN := 0; //Number of MRU files for lPos := 1 to (knMRU) do begin//first, eliminate duplicates lStr := gMRUstr[lPos]; if (lStr <> '') and (lStr <> lNewFileName) then begin inc(lN); gMRUstr[lN] := lStr; end; //keep in MRU list end; //for each MRU //next, increment positions if lN >= knMRU then lN := knMRU - 1; for lPos := lN downto 1 do gMRUstr[lPos+1] := gMRUstr[lPos]; if (lN+2) < (knMRU) then //+1 as we have added a file for lPos := (lN+2) to knMRU do gMRUstr[lPos] := ''; gMRUstr[1] := lNewFilename; ImgForm.UpdateMRU; ImgForm.SaveDialog1.FileName := lNewFilename; end;//Add2MRU procedure TImgForm.UpdateMRU;//most-recently-used menu var NewItem: TMenuItem; lPos: integer; begin While Recent1.Count < knMRU do begin NewItem := TMenuItem.Create(Self); Recent1.Add(NewItem); end; for lPos := 1 to knMRU do begin//for each MRU Recent1.Items[lPos-1].Visible:=gMRUstr[lPos] <> ''; Recent1.Items[lPos-1].Caption :=ExtractFileName(gMRUstr[lPos]); Recent1.Items[lPos-1].Tag := lPos; Recent1.Items[lPos-1].onclick := OpenTemplateMRU; {$IFDEF Darwin} Recent1.Items[lPos-1].ShortCut := ShortCut(Word('1')+ord(lPos-1), [ssMeta]); {$ELSE} Recent1.Items[lPos-1].ShortCut := ShortCut(Word('1')+ord(lPos-1), [ssCtrl]); {$ENDIF} end;//for each MRU end; //UpdateMRU procedure TImgForm.UpdateTemplates; var NewItem: TMenuItem; lN : integer; lFName : String; lSearchRec: TSearchRec; begin While Templates1.Count < knMRU do begin NewItem := TMenuItem.Create(Self); Templates1.Add(NewItem); end; lN := 0; if FindFirst(gTemplateDir+pathdelim+'*.*', faAnyFile, lSearchRec) = 0 then begin repeat lFName := lSearchRec.Name; if IsNIfTIHdrExt (lFName) then begin Templates1.Items[lN].Caption :=ExtractFileName(lFName);//(ParseFileName(ExtractFileName(lFName))); Templates1.Items[lN].Tag := 0; Templates1.Items[lN].visible := true; Templates1.Items[lN].onclick := OpenTemplateMRU; {$IFDEF Darwin} Templates1.Items[lN].ShortCut := ShortCut(Word('1')+ord(lN), [ssMeta, ssAlt]); {$ELSE} Templates1.Items[lN].ShortCut := ShortCut(Word('1')+ord(lN), [ssCtrl, ssShift]); {$ENDIF} inc(lN); end; until (FindNext(lSearchRec) <> 0) or (lN >= knMRU); end;// else ImgForm.Caption :=('Unable to find any files in the folder '+gTemplateDir+pathdelim); while lN < knMRU do begin Templates1.Items[lN].visible := false; inc(lN); end; FindClose(lSearchRec); end;//UpdateTemplates (*NOT OSX 10.7 friendly... procedure TImgForm.UpdateMRU;//most-recently-used menu var NewItem: TMenuItem; lPos,lN : integer; begin //Recent1.Clear; //While Recent1.Count > 1 do Recent1.Delete(0); // While Recent1.Count > 0 do Recent1.Items[0].Free; lN := 0; for lPos := 1 to knMRU do begin//for each MRU if gMRUstr[lPos] <> '' then begin inc(lN); NewItem := TMenuItem.Create(Self); NewItem.Caption :=ExtractFileName(gMRUstr[lPos]);//(ParseFileName(ExtractFileName(lFName))); NewItem.Tag := lN; {$IFDEF FPC} NewItem.onclick := OpenTemplateMRU; //Lazarus {$ELSE} NewItem.onclick := OpenTemplateMRU; {$ENDIF} NewItem.ShortCut := ShortCut(Word('1')+ord(lN-1), [ssCtrl]); Recent1.Add(NewItem); end;//if mru exists end;//for each MRU end; //UpdateMRU procedure TImgForm.UpdateTemplates; var NewItem: TMenuItem; lN : integer; lFName : String; lSearchRec: TSearchRec; begin While Templates1.Count > 0 do Templates1.Items[0].Free; lN := 0; if FindFirst(gTemplateDir+pathdelim+'*.*', faAnyFile, lSearchRec) = 0 then begin repeat lFName := lSearchRec.Name; if IsNIfTIHdrExt (lFName) then begin inc(lN); NewItem := TMenuItem.Create(Self); NewItem.Caption :=ExtractFileName(lFName);//(ParseFileName(ExtractFileName(lFName))); NewItem.Tag := 0; {$IFDEF FPC} NewItem.onclick := OpenTemplateMRU; //Lazarus {$ELSE} NewItem.onclick := OpenTemplateMRU; {$ENDIF} if (lN+knMRU) <= 9 then NewItem.ShortCut := ShortCut(Word('1')+knMRU+ord(lN-1), [ssCtrl]); Templates1.Add(NewItem); end; until (FindNext(lSearchRec) <> 0) end; FindClose(lSearchRec); end;//UpdateTemplates *) procedure TImgForm.OpenTemplateMRU(Sender: TObject);//open template or MRU //Templates have tag set to 0, Most-Recently-Used items have tag set to position in gMRUstr var lFilename: string; begin if sender = nil then begin //autolaunch with last image, or last template image in list lFilename := gMRUstr[0]; if (lFilename = '') or (not FileExistsEX(lFilename)) then begin if Templates1.Count > 0 then Templates1.Items[Templates1.Count-1].click; exit; end; OpenAndDisplayImg(lFilename,true); //open but do not add templates to MRU end else if (Sender as TMenuItem).tag = 0 then begin lFilename := gTemplateDir+pathdelim+(Sender as TMenuItem).caption ;//+ '.hdr'; OpenAndDisplayImg(lFilename,false); //open but do not add templates to MRU end else if (Sender as TMenuItem).tag <= knMRU then begin lFilename := gMRUstr[(Sender as TMenuItem).tag]; OpenAndDisplayImg(lFilename,true); end else Showmessage('OpenTemplateMRU error.'); end; function TImgForm.OpenAndDisplayImg(var lFilename: string; lAdd2MRU: boolean): boolean; var lVal: integer; begin Result := false; if (FSize(lFilename)) < 348 then exit; //to small to be a header or DICOM image if not HdrForm.OpenAndDisplayHdr(lFilename,gMRIcroOverlay[kBGOverlayNum]) then exit; //if (ssShift in KeyDataToShiftState(vk_Shift)) then begin // if not OpenImg(gBGImg,gMRIcroOverlay[0],true,false,false,not gBGImg.ResliceOnLoad,false) then exit //end else if (ssCtrl in KeyDataToShiftState(vk_Shift)) and (gBGIMg.OrthoReslice) then begin gBGIMg.OrthoReslice := false; OpenImg(gBGImg,gMRIcroOverlay[0],true,false,false,false,false); gBGIMg.OrthoReslice := true; end else if (ssShift in KeyDataToShiftState(vk_Shift)) then begin if not OpenImg(gBGImg,gMRIcroOverlay[0],true,false,false,not gBGImg.ResliceOnLoad,false) then exit end else if not OpenImg(gBGImg,gMRIcroOverlay[0],true,false,false,gBGImg.ResliceOnLoad,false) then exit; XViewEdit.MaxValue := gBGImg.ScrnDim[1];//gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[1]; YViewEdit.MaxValue := gBGImg.ScrnDim[2];//gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[2]; ZViewEdit.MaxValue :=gBGImg.ScrnDim[3];// gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[3]; (*XViewEdit.Value := round(gBGImg.ScrnOri[1]);//gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[1] div 2; YViewEdit.Value := round(gBGImg.ScrnOri[2]);//gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[2]div 2; lVal := round(gBGImg.ScrnOri[3]); if lVal < 1 then lVal := 1; ZViewEdit.Value := lVal;//gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[3] div 2;*) XViewEdit.Value := Bound ( round(gBGImg.ScrnOri[1]),1,round(XViewEdit.MaxValue)); YViewEdit.Value := Bound ( round(gBGImg.ScrnOri[2]),1,round(YViewEdit.MaxValue)); ZViewEdit.Value := Bound ( round(gBGImg.ScrnOri[3]),1,round(ZViewEdit.MaxValue)); ImgForm.Caption := extractfilename(paramstr(0))+' - '+lFilename; StatusLabel.caption := 'opened: '+lFilename; Result := true; //LayerDrop.ItemIndex := 0; //LayerDropSelect(nil); if lAdd2MRU then Add2MRU(lFilename); if gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.datatype = kDT_RGB then begin //RGB //we have loaded the first [red] plane - now load green and blue... OverlayOpenCore(lFilename,1); OverlayOpenCore(lFilename,2); //must use additive blending //gBGImg.BGTransPct := -1; //gBGImg.OverlayTransPct := -1; OverlayAdditive.Click; BGAdditive.Click; end; {$IFDEF FPC} XViewEditChange(nil); {$ENDIF} //showmessage(lFilename+' 666 '+ChangeFileext(lFilename,'.anat')); AnatForm.OpenAnat( ChangeFileextx(lFilename,'.anat')); end; //OpenAndDisplayImg {$IFNDEF FPC} procedure TImgForm.WMDropFiles(var Msg: TWMDropFiles); //implement drag and drop var CFileName: array[0..MAX_PATH] of Char; lFilename: string; begin try if DragQueryFile(Msg.Drop, 0, CFileName, MAX_PATH) > 0 then begin lFilename := CFilename; OpenAndDisplayImg(lFilename,true); Msg.Result := 0; end; finally DragFinish(Msg.Drop); end; end; {$ENDIF} procedure TImgForm.Exit1Click(Sender: TObject); begin ImgForm.Close; end; function XToStr(lR: extended; lDec: integer): string; begin result := FloatToStrF(lR, ffFixed,7,lDec); end; procedure TImgForm.DisplayHdrClick(Sender: TObject); var lLayer:integer; begin lLayer := ActiveLayer; HdrForm.SaveHdrDlg.Filename := gMRIcroOverlay[lLayer].HdrFilename; HdrForm.WriteHdrForm (gMRIcroOverlay[lLayer]); HdrForm.ShowModal; //HdrForm.BringToFront; end; procedure TImgForm.Open1Click(Sender: TObject); var lFilename: string; begin CloseImagesClick(nil); if not OpenDialogExecute(kImgFilterPlusAny,'Select background image',false) then exit; lFilename := HdrForm.OpenHdrDlg.Filename; OpenAndDisplayImg(lFilename,True); end; procedure TImgForm.ToolSelectClick(Sender: TObject); begin if (not ToolPanel.Visible) and ((Sender as TMenuItem).Tag > 0) then exit; //tools disabled case (Sender as TMenuItem).Tag of 0: begin XBarBtn.Down := not XBarBtn.Down; {$IFDEF Darwin} XBarbtnClick(nil); exit;{$ENDIF} end; 2: PenBtn.Down := true; 3: ClosedPenBtn.Down := true; 4: FillBtn.Down := true; 5: EllipseBtn.Down := true; 6: begin PenBtn.Down := false; ClosedPenBtn.Down := false; FillBtn.Down := false; EllipseBtn.Down := false; end; end; //case RefreshImagesTimer.Enabled := true; end; function SelectedImage: TImage; begin case SelectedImageNum of kSagView0: result := ImgForm.PGImageSag; kCoroView0: result := ImgForm.PGImageCor; else result := ImgForm.PGImageAx; end; end; procedure TImgForm.SetDimension8(lInPGHt,lInPGWid:integer; lBuff: ByteP; lUndoOnly: boolean); begin DefineBuffFX8(gDrawImg, lInPGWid,lInPGHt,lBuff); DefineBuffFX8(gUndoImg, lInPGWid,lInPGHt,lBuff); end; procedure WriteAxialVOI (lUndoOnly: boolean); var lX,lY,lSliceOffset,lSliceSz,lSlicePos: integer; lInBuff: ByteP; begin lX := gBGImg.ScrnDim[1]; lY := gBGImg.ScrnDim[2]; lSliceSz := lX*lY; if lSliceSz < 1 then exit; lSliceOffset := (ImgForm.ZViewEdit.Value-1)*lX*lY; gBGImg.VOIUndoSlice := ImgForm.ZViewEdit.Value; getmem(lInBuff,lSliceSz); for lSlicePos := 1 to lSliceSz do lInBuff^[lSlicePos] := gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lSliceOffset+lSlicePos]; ImgForm.SetDimension8(lY,lX, lInBuff,lUndoOnly); freemem(lInBuff); end; procedure WriteCorVOI (lUndoOnly: boolean); var lX,lY,lZ,lYOffset,lZOffset,lXYSliceSz,lPixel,lZPos,lXPos: integer; lInBuff: ByteP; begin lX := gBGImg.ScrnDim[1]; lY := gBGImg.ScrnDim[2]; lZ := gBGImg.ScrnDim[3]; lYOffset := (lX) * (round(ImgForm.YViewEdit.Value)-1); gBGImg.VOIUndoSlice := ImgForm.YViewEdit.Value; lXYSliceSz := (lX*lY); getmem(lInBuff,lZ*lX); lPixel := 0; for lZPos := 1 to lZ do begin lZOffset := (lZPos-1) * lXYSliceSz; for lXPos := 1 to lX do begin inc(lPixel); lInBuff^[lPixel] := gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lZOffset+lYOffset+lXPos]; end; //for each Y end; //for each Z ImgForm.SetDimension8(lZ,lX, lInBuff,lUndoOnly); freemem(lInBuff); end; procedure WriteSagVOI (lUndoOnly: boolean); var lX,lY,lZ,lXOffset,lYOffset,lZOffset,lXYSliceSz,lPixel,lZPos,lYPos: integer; lInBuff: ByteP; begin lX := gBGImg.ScrnDim[1]; lY := gBGImg.ScrnDim[2]; lZ := gBGImg.ScrnDim[3]; lXYSliceSz := lX*lY; lXOffset := round(ImgForm.XViewEdit.Value); //dec(lXOffset);//999+8 gBGImg.VOIUndoSlice := ImgForm.XViewEdit.Value; getmem(lInBuff,lZ*lY); lPixel := 0; for lZPos := 1 to lZ do begin lZOffset := (lZPos-1) * lXYSliceSz; lYOffset := 0; for lYPos := 1 to lY do begin inc(lPixel); lInBuff^[lPixel] := gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lZOffset+lYOffset+lXOffset]; lYOffset := lYOffset+ lX; end; //for each Y end; //for each Z ImgForm.SetDimension8(lZ,lY, lInBuff, lUndoOnly); freemem(lInBuff); end; procedure WriteUndoVOI(lPanel: integer;lUndoOnly: boolean); begin EnsureVOIOPen; case lPanel of 3: WriteCorVOI(lUndoOnly); 2: WriteSagVOI(lUndoOnly); else WriteAxialVOI(lUndoOnly); end; gBGImg.VOIchanged := true; if gBGImg.VOIUndoOrient = 4 then FreeUndoVol; //release 3D undo buffer when creating 2D buffer gBGImg.VOIUndoOrient := lPanel; end; procedure TImgForm.FormOpenFileMethod(const FileName : string); var lFilename: string; begin lFilename := Filename; OpenAndDisplayImg(lFilename,true); end; procedure TImgForm.Landmarks1Click(Sender: TObject); begin //Graph4DForm.show; AnatForm.show; end; procedure TImgForm.FormCreate(Sender: TObject); var lInc: longint; begin Application.ShowButtonGlyphs := sbgNever; KeyPreview := true; {$IFDEF Darwin} InitOpenDocHandler;//allows files to be associated... {$IFNDEF LCLgtk} //only for Carbon compile Open1.ShortCut := ShortCut(Word('O'), [ssMeta]); SaveasNIfTI1.ShortCut := ShortCut(Word('S'), [ssMeta,ssAlt]); Saveaspicture1.ShortCut := ShortCut(Word('S'), [ssMeta]); Copy1.ShortCut := ShortCut(Word('C'), [ssMeta]); Paste1.ShortCut := ShortCut(Word('V'), [ssMeta]); Undo1.ShortCut := ShortCut(Word('Z'), [ssMeta]); OverlayOpen.ShortCut := ShortCut(Word('A'), [ssMeta]); Applyintensityfiltertovolume1.ShortCut := ShortCut(Word('F'), [ssMeta]); HistoMenu.ShortCut := ShortCut(Word('H'), [ssMeta]); ShowRender.ShortCut := ShortCut(Word('R'), [ssMeta]); ShowMultislice.ShortCut := ShortCut(Word('M'), [ssMeta]); N4DTraces1.ShortCut := ShortCut(Word('D'), [ssMeta]); Header1.ShortCut := ShortCut(Word('I'), [ssMeta]); YokeMenu.ShortCut := ShortCut(Word('Y'), [ssMeta]); // OnDropFiles := OnDropFiles; {$ENDIF} {$ENDIF} {$IFDEF Darwin} {$IFNDEF LCLgtk} //only for Carbon compile Exit1.visible := false;//with OSX users quit from application menu {$ENDIF} {$ENDIF} CreateFX8(gUndoImg); CreateFX8(gDrawImg); TriplePanel.OnMouseWheelDown:= FormMouseWheelDown; TriplePanel.OnMouseWheelUp:= FormMouseWheelUp; TriplePanel.OnMouseWheelDown:= FormMouseWheelDown; TriplePanel.OnMouseWheelUp:= FormMouseWheelUp; TriplePanel.OnMouseWheelDown:= FormMouseWheelDown; TriplePanel.OnMouseWheelUp:= FormMouseWheelUp; randomize; gnCPUThreads := GetLogicalCpuCount; gMouseDownX := -1; ImgForm.Caption := extractfilename(paramstr(0)); ImgForm.DoubleBuffered := true; TriplePanel.DoubleBuffered := true; TriplePanel.DoubleBuffered := true; TriplePanel.DoubleBuffered := true; for lInc := 0 to knMaxOverlay do begin FreeImgMemory(gMRIcroOverlay[lInc]); NIFTIhdr_ClearHdr(gMRIcroOverlay[lInc]); gMRIcroOverlay[lInc].ScrnBufferItems := 0; gMRIcroOverlay[lInc].ImgBufferItems := 0; if lInc < knAutoLUT then gMRIcroOverlay[lInc].LUTindex := lInc else gMRIcroOverlay[lInc].LUTindex := lInc;//B&W LoadMonochromeLUT(gMRIcroOverlay[lInc].LUTindex,gBGImg,gMRIcroOverlay[lInc]); end; lInc:=maxint; LoadMonochromeLUT(lInc,gBGImg,gMRIcroOverlay[kVOIOverlayNum]); SetBGImgDefaults(gBGImg); CloseImagesClick(nil); gColorSchemeDir := extractfilepath(paramstr(0))+'lut'; {$IFNDEF Unix} DragAcceptFiles(Handle, True); //engage drag and drop {$ENDIF} UpdateColorSchemes; {$IFNDEF FPC} LUTdrop.SetItemIndex(0); Zoomdrop.SetItemIndex(0); LayerDrop.SetItemIndex(0); {$ELSE} LUTdrop.ItemIndex:=(0); Zoomdrop.ItemIndex:=(0); LayerDrop.ItemIndex:=(0); MagnifyMenuItem.visible := false; {$IFNDEF COMPILEYOKE} YokeMenu.visible := false; {$ENDIF} {$ENDIF} gTemplateDir := extractfilepath(paramstr(0))+'templates'; UpdateTemplates; for lInc := 1 to knMRU do gMRUstr[lInc] := ''; (*if (ssShift in KeyDataToShiftState(vk_Shift)) then begin case MessageDlg('Shift key down during launch: do you want to reset the default preferences?', mtConfirmation, [mbYes, mbNo], 0) of { produce the message dialog box } mrNo: ReadIniFile; end; //case end else*) if ResetDefaults then DrawMenu.Visible := ToolPanel.visible else ReadIniFile; SetIniMenus; UpdateMRU; DefaultControlPanel; OverlaySmoothMenuClick(nil); LUTDrop.OnSelect(nil); ZoomDrop.OnSelect(nil); CreateShareMem; if YokeMenu.checked then YokeTimer.enabled := true; //gBGIMg.SaveDefaultIni := true; end; function ImgIntensity(var lHdr: TMRIcroHdr; lPos: integer): single; overload; var l16Buf : SmallIntP; l32Buf : SingleP; begin result := 0; if (lPos > lHdr.ImgBufferItems) or (lPos < 1) then exit; if (lHdr.ImgBufferBPP = 4) then begin l32Buf := SingleP(lHdr.ImgBuffer ); result := l32Buf^[lPos]; end else if (lHdr.ImgBufferBPP = 2) then begin l16Buf := SmallIntP(lHdr.ImgBuffer ); result := l16Buf^[lPos]; end else if lHdr.ImgBufferBPP = 1 then result := lHdr.ImgBuffer^[lPos] else begin showmessage('Unknown Image Buffer Bytes Per Pixel: '+inttostr(lHdr.ImgBufferBPP)+' '+lHdr.HdrFileName); exit; end; result := Raw2ScaledIntensity (lHdr,result); end; function ImgIntensity(var lHdr: TMRIcroHdr; lX,lY,lZ: integer): single; overload; var lPos: integer; begin lPos := lX + ((lY-1)*gBGImg.ScrnDim[1])+((lZ-1)*gBGImg.ScrnDim[1]*gBGImg.ScrnDim[2]); result := ImgIntensity(lHdr,lPos); end; function TImgForm.ImgIntensityString(var lHdr: TMRIcroHdr; lVox: integer): string; overload; var lV: integer; begin if (lVox > lHdr.ImgBufferItems) or (lVox < 1) then exit; if lHdr.UsesLabels then begin lV := round(ImgIntensity(lHdr,lVox)); if lV <= High(gBGImg.LabelRA) then result := gBGImg.LabelRA[lV]; exit; end; if (not lHdr.UsesCustomPalette) or (lHdr.NIFTIhdr.datatype = kDT_RGB) then begin result := realtostr(ImgIntensity(lHdr,lVox),gBGImg.SigDig); exit; end; end; function TImgForm.ImgIntensityString(var lHdr: TMRIcroHdr; lX,lY,lZ: integer): string; overload; var lVox: integer; begin lVox := lX + ((lY-1)*gBGImg.ScrnDim[1])+((lZ-1)*gBGImg.ScrnDim[1]*gBGImg.ScrnDim[2]); result := ImgIntensityString(lHdr,lVox); end; procedure TImgForm.UpdateStatusLabel; var lX,lY,lZ,lOverlay,lLen: integer; lXmm,lYmm,lZmm: single; lIntenStr : string; begin lX := XviewEdit.value; lY := YviewEdit.value; lZ := ZviewEdit.value; ImgCoordToMM(lX,lY,lZ,lXmm,lYmm,lZmm); lIntenStr := ''; //StatusLabel.Caption := realtostr(lXmm,0)+'x'+realtostr(lYmm,0)+'x'+realtostr(lZmm,0); //lIntenStr := realtostr(lXmm,0)+'x'+realtostr(lYmm,0)+'x'+realtostr(lZmm,0)+'= '+lIntenStr;; //StatusLabel.Caption := lIntenStr; //StatusLabel.Caption := realtostr(lXmm,0)+'x'+realtostr(lYmm,0)+'x'+realtostr(lZmm,0)+'= '+lIntenStr; //crash! for lOverlay := kBGOverlayNum to (kVOIOverlayNum-1) do if gMRIcroOverlay[lOverlay].ImgBufferItems > 0 then lIntenStr := lIntenStr + ImgIntensityString(gMRIcroOverlay[lOverlay],lX,lY,lZ)+', '; lLen := length (lIntenstr); if lLen > 2 then lIntenStr[lLen-1] := ' '; //StatusLabel.Caption := realtostr(lXmm,0)+'x'+realtostr(lYmm,0)+'x'+realtostr(lZmm,0)+'= '+lIntenStr; Caption :=realtostr(lXmm,0)+'x'+realtostr(lYmm,0)+'x'+realtostr(lZmm,0)+'= '+lIntenStr; SetShareMem (lXmm,lYmm,lZmm); end; procedure TImgForm.XViewEditChange(Sender: TObject); begin gBGImg.XViewCenter := XviewEdit.value; gBGImg.YViewCenter := YviewEdit.value; gBGImg.ZViewCenter := ZviewEdit.value; RefreshImagesTimer.Enabled := true; //UpdateStatusLabel; //caused crash! - only with refreshimagestimes end; {$IFNDEF FPC} procedure TImgForm.FormClose(Sender: TObject; var Action: TCloseAction); {$ELSE} procedure TImgForm.FormClose(Sender: TObject); {$ENDIF} begin WriteIniFile; CloseImagesClick(nil); FreeFX8(gDrawImg); FreeFX8(gUndoImg); end; procedure TImgForm.MagnifyTimerTimer(Sender: TObject); {$IFDEF FPC} begin // MagnifyTimer.Enabled := false; end; {$ELSE} var Srect,Drect,PosForme,ImgForme:TRect; lZoomSlider,iWidth,iHeight,DmX,DmY:Integer; iTmpX,iTmpY:Real; C:TCanvas; hDesktop: Hwnd; Kursor:TPoint; begin MagnifyTimer.Enabled := false; lZoomSlider := 2; If not IsIconic(Application.Handle) then begin hDesktop:= GetDesktopWindow; GetCursorPos(Kursor); ImgForme := Rect(ImgForm.Left+ImgForm.TriplePanel.Left,ImgForm.Top+ImgForm.TriplePanel.Top,ImgForm.Left+ImgForm.Width,ImgForm.Top+ImgForm.Height); PosForme:=Rect(MagnifyPanel.Left,MagnifyPanel.Top,MagnifyPanel.Left+MagnifyPanel.Width,MagnifyPanel.Top+MagnifyPanel.Height); if true then begin iWidth:=MagnifyImage.Width; iHeight:=MagnifyImage.Height; if iHeight < 6 then exit; Drect:=Rect(0,0,iWidth,iHeight); iTmpX:=iWidth / (lZoomSlider*4);//(Slider.Position * 4); iTmpY:=iHeight / (lZoomSlider*4);//(Slider.Position * 4); Srect:=Rect(Kursor.x,Kursor.y,Kursor.x,Kursor.y); InflateRect(Srect,Round(iTmpX),Round(iTmpY)); If Srect.Left<0 then OffsetRect(Srect,-Srect.Left,0); If Srect.Top<0 then OffsetRect(Srect,0,-Srect.Top); If Srect.Right>Screen.Width then OffsetRect(Srect,-(Srect.Right-Screen.Width),0); If Srect.Bottom>Screen.Height then OffsetRect(Srect,0,-(Srect.Bottom-Screen.Height)); C:=TCanvas.Create; try C.Handle:=GetDC(GetDesktopWindow); SetStretchBltMode(C.Handle,COLORONCOLOR); //SetStretchBltMode(C.Handle, STRETCH_DELETESCANS); //SetStretchBltMode(C.Handle,{BILINEAR}TransparencyEdit.value); MagnifyImage.Canvas.CopyRect(Drect,C,Srect); finally ReleaseDC(hDesktop, C.Handle); C.Free; end; If True then begin // show crosshair MagnifyImage.Canvas.Pen.Color := gBGIMg.XBarClr; with MagnifyImage.Canvas do begin DmX:=lZoomSlider * 2 * (Kursor.X-Srect.Left); DmY:=lZoomSlider * 2 * (Kursor.Y-Srect.Top); MoveTo(1,DmY); // - LineTo(iWidth,DmY); // - MoveTo(DmX,1); // | LineTo(DmX,iHeight); // | end; // with MagnifyImage.Canvas end; // show crosshair Application.ProcessMessages; end // Cursor not inside form end; // IsIconic end; //magnify image {$ENDIF} procedure TImgForm.MagnifyPanelResize(Sender: TObject); begin (* MagnifyImage.Picture:=nil; if MagnifyPanel.Width < MagnifyPanel.Constraints.MinWidth then MagnifyPanel.Width := MagnifyPanel.Constraints.MinWidth; *) end; //Proc MagnifyPanelResize procedure SelectPanel (lPanelNumber: integer); begin gSelectedImageNum := lPanelNumber; end; //Proc SelectPanel procedure ShowFocusRect(lInRect: TRect); var LImage: TImage; begin lImage := SelectedImage; lImage.Canvas.DrawFocusRect(lInRect); end; //proc ShowFocusRect procedure XYscrn2Img (lImage: TIMage;lPanel,lXinRaw,lYinRaw: integer; var lXout,lYOut,lZOut: integer); var lYin,lXin,lZoom : integer; lOffset: single; begin //amx - must match XYscrn2Img and DrawXBar - e.g. +0.5 for middle of zoomed slice lZoom := ImageZoomPct(lImage); if lZoom = 0 then lZoom := 100; if lZoom > 100 then lOffset := 0.5 else lOffset := 0; lXIn := lXinRaw + 1; //index from 0 lYin := lImage.Height-lYinRaw; case lPanel of 2: begin if gBGImg.FlipSag then lXin := lImage.Width-lXinRaw; lXOut := ImgForm.XViewEdit.value; lYOut := round((lXin*100) / lZoom +lOffset); lZOut := round((lYin*100) / lZoom +lOffset); end; 3: begin lXOut := round((lXin*100) / lZoom +lOffset); lYOut := ImgForm.YViewEdit.value; lZOut := round((lYin*100) / lZoom +lOffset); end; else begin if gBGImg.FlipAx then lYin := lYinRaw; lXOut := round((lXin*100) / lZoom +lOffset); lYOut := round((lYin*100) / lZoom +lOffset); lZOut := ImgForm.ZViewEdit.value; end; //else end;//case lPanel //ImgForm.Caption := inttostr(lXOut)+' '+inttostr(lYOut)+' '+Inttostr(lZOut); end; //proc XYscrn2Img procedure AdjustContrastRectangle (lImage: TImage); var lXpos,lYPos,lXOut,lYOut,lZOut,lPanel,lLayer: integer; lMinInten,lMaxInten,lVal: single; begin lPanel := SelectedImageNum; lLayer := ActiveLayer; XYscrn2Img (lImage,lPanel,gSelectRect.Left,gSelectRect.Top, lXout,lYOut,lZOut); lMinInten := ImgIntensity(gMRIcroOverlay[lLayer],lXout,lYOut,lZOut); lMaxInten := lMinInten; for lYpos := gSelectRect.Top to gSelectRect.Bottom do begin for lXpos := gSelectRect.Left to gSelectRect.Right do begin XYscrn2Img (lImage,lPanel,lXpos,lYPos, lXout,lYOut,lZOut); // lVox := lXout + ((lYout-1)*gBGImg.ScrnDim[1])+((lZout-1)*gBGImg.ScrnDim[1]*gBGImg.ScrnDim[2]); // lVal := ImgIntensity(gMRIcroOverlay[lLayer],lVox); lVal:= ImgIntensity(gMRIcroOverlay[lLayer],lXout,lYOut,lZOut); if lVal < lMinInten then lMinInten := lVal; if lVal > lMaxInten then lMaxInten := lVal; end; //for PGX each column end; //for PGY2 - each row //ImgForm.StatusLabel.caption := (RealToStr(lMinInten,4))+'..'+({x} RealToStr(lMaxInten,4))+'bexx'+ inttostr(lXout)+'x'+inttostr(lYOut)+'x'+inttostr(lZOut)+' '+inttostr(ActiveLayer); // ImgForm.StatusLabel.caption := 'bexx'+ inttostr(gSelectRect.Top)+'..'+inttostr(gSelectRect.Bottom)+' -> '+inttostr(gSelectRect.Left)+'..'+inttostr(gSelectRect.Right); ImgForm.StatusLabel.caption := 'Intensity range '+(RealToStr(lMinInten,4))+'..'+({x} RealToStr(lMaxInten,4)); if lMinInten = lMaxInten then exit; //no range ImgForm.MinWindowEdit.value := lMinInten; ImgForm.MaxWindowEdit.value := lMaxInten; {$IFDEF FPC} ImgForm.MinContrastWindowEditChange(nil); {$ENDIF} end; procedure sortLTRB(var lXoutLow,lYOutLow,lXoutHi,lYOutHi: integer); //left<right, top<bottom var lXin1,lYin1,lXin2,lYin2: integer; begin lXin1 := lXoutLow; lYin1 := lYOutLow; lXin2 := lXoutHi; lYin2 := lYOutHi; if lXIn1 < lXin2 then begin lXoutLow := lXIn1; lXOutHi := lXIn2; end else begin lXoutLow := lXIn2; lXOutHi := lXIn1; end; if lYIn1 < lYin2 then begin lYoutLow := lYIn1; lYOutHi := lYIn2; end else begin lYoutLow := lYIn2; lYOutHi := lYIn1; end; end; //sortLTRB procedure DrawEllipse (lImage: TImage;lRect: TRect; lShift: TShiftState; lPanel: integer); var i: integer; begin ScaleBMP2Draw(gBGImg.VOIInvZoom, lRect.Left,lRect.Top,lPanel,Limage); ScaleBMP2Draw(gBGImg.VOIInvZoom, lRect.Right,lRect.Bottom,lPanel,lImage); if ssShift in lShift then i := 0 else i := kVOI8bit; if (ssCtrl in lShift) then FillRectFX8(gDrawImg,lRect.Left,lRect.Top,lRect.Right,lRect.Bottom,i) else FillEllipseFX8(gDrawImg,lRect.Left,lRect.Top,lRect.Right,lRect.Bottom,i); end; //DrawEllipse procedure TImgForm.PGImageMouseDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer); var lZoom,lPanel,lX, lY,lXout,lYOut,lZOut,lBasePenThick,lX2, lY2: integer; lImage: TImage; begin //ImgForm.GetFocus := true; gSelectOrigin.X := -1; lX := X; lY := Y; lImage := Sender as TImage; if lImage.Name = PGImageCor.Name {'PGImageCor'} then lPanel := kCoroView0 else if lImage.Name = PGImageSag.Name {'PGImageSag'} then lPanel := kSagView0 else lPanel := kAxView0; //lImage.Canvas.Pen.Width := 1; // lImage.Canvas.Pen.Color :=gBGImg.VOIClr; SelectPanel(lPanel); gBGImg.VOIInvZoom := ComputeInvZoomShl10(lPanel,lImage); if DrawToolSelected then begin //paint tool WriteUndoVOI(lPanel,false); if (ssShift in Shift) then begin //erase lImage.Canvas.Brush.Color:=clBlack; lImage.Canvas.Pen.Color := clBlack; end else begin lImage.Canvas.Brush.Color:=gBGImg.VOIClr; lImage.Canvas.Pen.Color := gBGImg.VOIClr; end; if gBGImg.ThinPen then lBasePenThick := 1 else begin //adjust pen thickness for zoom level if gBGImg.ZoomPct < 100 then begin lZoom := ComputeZoomPct(lPanel,lImage); if lZoom = 100 then lBasePenThick := 1 else lBasePenThick := round((ComputeZoomPct(lPanel,lImage)+50) / 100); end else if gBGImg.ZoomPct > 100 then lBasePenThick := gBGImg.ZoomPct div 100 else lBasePenThick := 1; end; //if not thinpen if (ssCtrl in Shift) then begin lImage.Canvas.Pen.Width := lBasePenThick*3; gDrawImg.PenThick := 3; end else begin lImage.Canvas.Pen.Width := lBasePenThick; gDrawImg.PenThick := 1; end; end; //paint tool selected //lImage.Canvas.Pen.Width := 1;//abba if (FillBtn.Down) and (ssCtrl in Shift) then begin //3D fill XYscrn2Img (lImage,lPanel,lX,lY, lXout,lYOut,lZOut); XViewEdit.value := lXOut; YViewEdit.value := lYOut; ZViewEdit.value := lZOut; if (ssShift in Shift) then //erase ROICluster(gBGImg.ScrnDim[1], gBGImg.ScrnDim[2], gBGImg.ScrnDim[3],XViewEdit.value,YViewEdit.value,ZViewEdit.value,true) else //draw ROICluster(gBGImg.ScrnDim[1], gBGImg.ScrnDim[2], gBGImg.ScrnDim[3],XViewEdit.value,YViewEdit.value,ZViewEdit.value,false); exit; end; //end 3D fill if (not PenBtn.Down) and (not ClosedPenBtn.Down) and (not FillBtn.Down) then begin if (EllipseBtn.Down) or (ssRight in Shift) then begin lImage.Canvas.Brush.Color:=gBGImg.VOIClr; //lImage.Canvas.Pen.Color :=gBGImg.VOIClr; ScaleScrn2BMP(lX,lY, lImage); gSelectRect.Left := lX; gSelectRect.Top := lY; gSelectRect.Right := lX; gSelectRect.Bottom := lY; ShowFocusRect(gSelectRect); gSelectOrigin.X := gSelectRect.Left; gSelectOrigin.Y := gSelectRect.Top; exit; end; //next no paint tools selected - show position where click occurred XYscrn2Img (lImage,lPanel,lX,lY, lXout,lYOut,lZOut); XViewEdit.value := lXOut; YViewEdit.value := lYOut; ZViewEdit.value := lZOut; //showmessage(floattostr(lXOut)+'x'+floattostr(lYOut)+'x'+floattostr(lZOut)); //ImgCoordToMM(lXOut,lYOut,lZOut,lXmm,lYmm,lZmm); //showmessage(floattostr(lXmm)+'x'+floattostr(lYmm)+'x'+floattostr(lZmm)); //showmessage(floattostr(gBGImg.ScrnOri[1])+'x'+floattostr(gBGImg.ScrnOri[2])+'x'+floattostr(gBGImg.ScrnOri[3])); //MMToImgCoord(lXOut,lYOut,lZOut,lXmm,lYmm,lZmm); //showmessage(floattostr(lXOut)+'x'+floattostr(lYOut)+'x'+floattostr(lZOut)); //SetShareMem (lXmm,lYmm,lZmm); {$IFDEF FPC} XViewEditChange(nil); {$ENDIF} exit; end; ScaleScrn2BMP(lX,lY, lImage); lImage.Canvas.MoveTo(lX,lY); lX2 := X; lY2 := Y; ScaleBMP2Draw(gBGImg.VOIInvZoom, lX2,lY2,lPanel,lImage); if (FillBtn.Down) or(ssRight in Shift) then begin if (ssShift in Shift) then FloodFillFX8 (gDrawImg, lX2,lY2,kVOI8bit,0,true) //FloodFillX(DrawImg2,lX2-1,lY2-1,gBGImg.VOIClr, fsSurface) else FloodFillFX8 (gDrawImg, lX2,lY2,kVOI8bit,kVOI8bit,false); //FloodFillX(DrawImg2,lX2-1,lY2-1,gBGImg.VOIClr, fsBorder); exit; end; //ImgForm.caption := inttostr(lX2); MoveToFX8(gDrawImg,lX2,lY2); if lImage.Canvas.Pen.Color = clBlack then //ensure single pixel is drawn if user clicks without dragging LineToFX8(gDrawImg,lX2,lY2,0) else LineToFX8(gDrawImg,lX2,lY2,kVOI8bit); gMouseDownX := lX; gMouseDownY := lY; end; //PGImageMouseDown var gDragX,gDragY,gDragZ : integer; //gDragRefresh : boolean = false; //only redraw one snapshot at a time procedure TImgForm.PGImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var lX, lY,lPanel,lXOut,lYOut,lZOut: integer; lImage: TImage; begin lImage := Sender as TImage; lX := X; lY := Y; ScaleScrn2BMP(lX,lY,lImage); //if MagnifyImage.Height > 10 then // MagnifyTimer.Enabled := true;//MagnifyBtn.Down; //StatusLabel.Caption := inttostr(lX)+','+inttostr(lY); if {(ssShift in Shift) and} (gSelectOrigin.X > 0) then begin ShowFocusRect(gSelectRect); gSelectRect.Left := gSelectOrigin.X; gSelectRect.Top := gSelectOrigin.Y; gSelectRect.Right := lX; gSelectRect.Bottom := lY; sortLTRB(gSelectRect.Left,gSelectRect.Top,gSelectRect.Right,gSelectRect.Bottom); ShowFocusRect(gSelectRect); exit; end; if (not DrawToolSelected) and ((ssLeft in Shift)) then begin //RefreshImagesTimer.Enabled := false; //gDragRefresh := true; if lImage.Name = PGImageCor.Name then lPanel := kCoroView0 else if lImage.Name = PGImageSag.Name then lPanel := kSagView0 else lPanel := kAxView0; XYscrn2Img (lImage,lPanel,lX,lY, lXout,lYOut,lZOut); if (lXout = gDragX) and (lYout = gDragY) and (lZOut = gDragZ) then exit;//no change XViewEdit.value := lXOut; YViewEdit.value := lYOut; ZViewEdit.value := lZOut; {$IFDEF FPC}XViewEditChange(nil);{$ENDIF} //can generate crash! //gDragRefresh := false; exit; end; if (not (ssLeft in Shift)) or (gMouseDownX < 0) then exit; if PenBtn.Down or ClosedPenBtn.Down then begin lImage.Canvas.LineTo(lX,lY); lX := X; lY := Y; ScaleBMP2Draw(gBGImg.VOIInvZoom, lX,lY,lPanel,lImage); //DrawImg2.Canvas.LineTo(lX,lY); if lImage.Canvas.Pen.Color = clBlack then LineToFX8(gDrawImg,lX,lY,0)//zzzxx else LineToFX8(gDrawImg,lX,lY,kVOI8bit);//zzzxx end; end; //PGImageMouseMove (*procedure Scrn2VOI (var lImage: TImage; lXvoi,lYvoi: integer; var lVOIBuffer: ByteP); const kSh = 10; //bits to shift var lInc,lXpos,lYPos,lVOISliceSz: integer; srcBmp : TBitmap; begin srcBmp := lImage.Picture.Bitmap; lVOISliceSz := lXvoi*lYvoi; GetMem (lVOIBuffer , lVOISliceSz); lInc := 0; for lYpos:=(lYvoi-1) downto 0 do begin for lXpos:=0 to lXvoi-1 do begin inc(lInc); //zax if srcBmp.Canvas.Pixels[lXpos,lYPos] = clBlack then lVOIBuffer^[lInc] := 0 else lVOIBuffer^[lInc] := 100; end; end; end; //Scrn2VOI *) procedure ReadCorVOI (var lImage: TFX8; lSlice: integer); var lX,lY,lZ,lYOffset,lZOffset,lXYSliceSz,lPixel,lZPos,lXPos: integer; begin lX := gBGImg.ScrnDim[1]; lY := gBGImg.ScrnDim[2]; lZ := gBGImg.ScrnDim[3]; lYOffset := (lX) * (round(lSlice)-1); lXYSliceSz := (lX*lY); //Scrn2VOI (lImage,lX,lZ, lInBuff); lPixel := 0; for lZPos := 1 to lZ do begin lZOffset := (lZPos-1) * lXYSliceSz; for lXPos := 1 to lX do begin inc(lPixel); gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lZOffset+lYOffset+lXPos] :=lImage.Img^[lPixel]; end; //for each Y end; //for each Z end; procedure ReadSagVOI (var lImage: TFX8;lSlice: integer); var lX,lY,lZ,lXOffset,lYOffset,lZOffset,lXYSliceSz,lPixel,lZPos,lYPos: integer; begin lX := gBGImg.ScrnDim[1]; lY := gBGImg.ScrnDim[2]; lZ := gBGImg.ScrnDim[3]; lXYSliceSz := lX*lY; lXOffset := round(lSlice); // dec(lXOffset);//999+8 lPixel := 0; for lZPos := 1 to lZ do begin lZOffset := (lZPos-1) * lXYSliceSz; lYOffset := 0; for lYPos := 1 to lY do begin inc(lPixel); gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lZOffset+lYOffset+lXOffset] := lImage.Img^[lPixel]; lYOffset := lYOffset+ lX; end; //for each Y end; //for each Z //freemem(lInBuff); end; procedure ReadAxialVOI (var lImage: TFX8;lSlice: integer); var lX,lY,lSliceOffset,lSliceSz: integer; begin lX := gBGImg.ScrnDim[1]; lY := gBGImg.ScrnDim[2]; lSliceSz := lX*lY; lSliceOffset := (lSlice-1)*lX*lY; //Scrn2VOI (lImage,lX,lY, lInBuff); for lX := 1 to lSliceSz do gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lSliceOffset+lX] := lImage.Img^[lX]; end; procedure ReadScrnVOI (lImage: TImage); var lView: integer; begin if (gBGImg.VOIUndoSlice < 1) or (gBGImg.VOIUndoOrient < 1) or (gBGImg.VOIUndoOrient > 3) then exit; if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1) or (lImage.Picture.Bitmap.Width < 1) or (lImage.Picture.Bitmap.Height < 1) then exit; EnsureVOIOpen; lView := SelectedImageNum; case lView of 3: ReadCorVOI(gDrawImg,ImgForm.YViewEdit.Value); 2: ReadSagVOI(gDrawImg,ImgForm.XViewEdit.Value); 1: ReadAxialVOI(gDrawImg,ImgForm.ZViewEdit.Value); end; ImgForm.RefreshImagesTimer.Enabled := true; end; procedure TImgForm.PGImageMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var lX, lY,lPanel: integer; lImage: TImage; begin lPanel := SelectedImageNum; lImage := Sender as TImage; lX := X; lY := Y; ScaleScrn2BMP(lX,lY,lImage); if (gSelectOrigin.X > 0) then begin sortLTRB(gSelectRect.Left,gSelectRect.Top,gSelectRect.Right,gSelectRect.Bottom); ShowFocusRect(gSelectRect); gSelectOrigin.X := -1; if (EllipseBtn.Down) then DrawEllipse(Limage,gSelectRect,Shift,lPanel) else begin AdjustContrastRectangle(lImage); exit; end; end; if ((PenBtn.Down) or (ClosedPenBtn.Down)) and (gMouseDownX > 0) then begin ScaleBMP2Draw(gBGImg.VOIInvZoom, gMouseDownX,gMouseDownY,lPanel,lImage); //next: draw single pxiel if user clicks on image without moving the mouse //DrawImg2.Canvas.Pixels[gMouseDownX,gMouseDownY] := DrawImg2.Canvas.Pen.Color; if (ClosedPenBtn.Down) then begin if lImage.Canvas.Pen.Color = clBlack then LineToFX8(gDrawImg,gMouseDownX,gMouseDownY,0) else LineToFX8(gDrawImg,gMouseDownX,gMouseDownY,kVOI8Bit); end; end; gMouseDownX := -1; //disable draws //if DrawToolSelected then if DrawToolSelected and (not (ssAlt in Shift)) then ReadScrnVOI (lImage); end; //PGImageMouseUp procedure TImgForm.FormMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); begin Case SelectedImageNum of 3: DecViewEdit(YViewEdit); 2: DecViewEdit(XViewEdit); else DecViewEdit(ZViewEdit); end; end; procedure TImgForm.FormMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean); begin Case SelectedImageNum of 3: IncViewEdit(YViewEdit); 2: IncViewEdit(XViewEdit); else IncViewEdit(ZViewEdit); end; end; procedure TImgForm.ZoomDropSelect(Sender: TObject); begin gBGImg.ZoomPct := (ZoomDrop.ItemIndex-1)*100; RefreshImagesTimer.Enabled := true; end; procedure TImgForm.ColorBarBtnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var lLTRB,lLayer: integer; lImage: TImage; begin if (ssAlt in Shift) then begin //lImage := SelectedImage; lLayer := ActiveLayer; DrawHistogram(gMRIcroOverlay[lLayer],HistogramForm.HistoImage{lImage}); HistogramForm.Caption := 'Histogram: '+extractfilename(gMRIcroOverlay[lLayer].HdrFileName); HistogramForm.show; if (ssCtrl in Shift) then TextReportHisto(gMRIcroOverlay[lLayer]); exit; end; lLTRB := 1; if (ssRight in Shift) then lLTRB := lLTRB + 1; if (ssCtrl in Shift) then lLTRB := lLTRB + 2; lImage := SelectedImage; intenBar(lImage,gMRIcroOverlay[ActiveLayer],lLTRB,0,0); end; procedure TImgForm.XBarBtnClick(Sender: TObject); begin gBGImg.XBarVisible := XBarBtn.Down; RefreshImagesTimer.Enabled := true; end; procedure RepositionOrigin; begin gBGImg.ScrnOri[1] := ImgForm.XviewEdit.value; gBGImg.ScrnOri[2] := ImgForm.YviewEdit.value; gBGImg.ScrnOri[3] := ImgForm.ZviewEdit.value; end; procedure TImgForm.XBarBtnMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin end; procedure TImgForm.XBarBtnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); label 555; begin if not (ssRight in shift) then exit; if (ssShift in Shift) then begin RepositionOrigin; goto 555; end; if (ssAlt in Shift) and (ssCtrl in Shift) then begin inc(gBGImg.FontSize,2); if gBGImg.FontSize > 24 then gBGImg.FontSize := 8; goto 555; end; if (ssAlt in Shift) then begin inc(gBGImg.XBarThick,2); if gBGImg.XBarThick > 10 then gBGImg.XBarThick := 1; goto 555; end; if (ssCtrl in Shift) then begin ColorDialog1.Color := gBGImg.XBarClr; if not ColorDialog1.Execute then exit; gBGImg.XBarClr := ColorDialog1.Color; goto 555; end; inc(gBGImg.XBarGap); if gBGImg.XBarGap > 10 then gBGImg.XBarGap := 0; 555: RefreshImagesTimer.Enabled := true; if MultiSliceForm.Visible then MultiSliceForm.CreateMultiSlice; end; //XBarBtnMouseDown procedure TImgForm.RefreshImagesTimerTimer(Sender: TObject); begin RefreshImagesTimer.Enabled := false; RefreshImages; UpdateStatusLabel; end; procedure TImgForm.ImgPanelClick(Sender: TObject); begin SelectPanel((Sender as TScrollBox).tag); end; procedure TImgForm.MagnifyMenuItemClick(Sender: TObject); begin (*if MagnifyPanel.Height < 20 then //Height constrained by Y MagnifyPanel.Height := 128 else MagnifyPanel.Height := MagnifyPanel.Constraints.MinHeight; *) end; procedure TImgForm.CloseImagesClick(Sender: TObject); var lC: integer; begin CloseVOIClick(nil); FreeUndoVol; for lC := 0 to knMaxOverlay do //background, all overlays, VOI FreeImgMemory(gMRIcroOverlay[lC]); gBGImg.VOIUndoSlice := 0; //next- set layers menu LayerDrop.Items.Clear; LayerDrop.Items.Add('Background'); {$IFNDEF FPC} LayerDrop.SetItemIndex(0); {$ELSE} LayerDrop.ItemIndex :=(0); {$ENDIF} LayerDropSelect(nil); end; procedure TImgForm.OverlayOpenCore (var lFilename: string; lOverlayNum: integer); begin if not HdrForm.OpenAndDisplayHdr(lFilename,gMRIcroOverlay[lOverlayNum]) then exit; //if not OpenImg(gBGImg,gMRIcroOverlay[lOverlayNum],false,false,false) then exit; //if (ssShift in KeyDataToShiftState(vk_Shift)) then begin // if not OpenImg(gBGImg,gMRIcroOverlay[lOverlayNum],false,false,false,not gBGImg.ResliceOnLoad,false) then exit; //end else if not OpenImg(gBGImg,gMRIcroOverlay[lOverlayNum],false,false,false,gBGImg.ResliceOnLoad,false) then exit; ImgForm.UpdateLayerMenu; ImgForm.RefreshImagesTimer.Enabled := true; end; procedure TImgForm.LoadOverlay (lFilename: string); var lOverlay,lC: integer; begin lOverlay := 0; for lC := 1 to (knMaxOverlay-1) do //-1: save final overlay for VOI if (lOverlay = 0) and (gMRIcroOverlay[lC].ImgBufferItems = 0) then lOverlay := lC; if lOverlay = 0 then begin showmessage('Unable to add an overlay. You have loaded the maximum number of overlays.'); exit; end; OverlayOpenCore ( lFilename, lOverlay); end; procedure TImgForm.LoadOverlayIncludingRGB (lFilename: string); var lOverlay,lC: integer; begin lOverlay := 0; for lC := 1 to (knMaxOverlay-1) do //-1: save final overlay for VOI if (lOverlay = 0) and (gMRIcroOverlay[lC].ImgBufferItems = 0) then lOverlay := lC; if lOverlay = 0 then begin showmessage('Unable to add an overlay. You have loaded the maximum number of overlays.'); exit; end; OverlayOpenCore ( lFilename, lOverlay); if (gMRIcroOverlay[lOverlay].NIFTIhdr.datatype = kDT_RGB) then begin OverlayOpenCore ( lFilename, lOverlay+1); OverlayOpenCore ( lFilename, lOverlay+2); OverlayAdditive.click; end; end; procedure TImgForm.BrainMask1Click(Sender: TObject); var lInc: integer; begin if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1 then begin showmessage('Please load a background image for rescaling.'); exit; end; //lImgSamples := gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems; for lInc := 1 to gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems do if gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lInc] <> 0 then gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lInc] := 1; SaveAsVOIorNIFTI(gMRIcroOverlay[kBGOverlayNum].ScrnBuffer,gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems,1,1,true,gMRIcroOverlay[kBGOverlayNum].NiftiHdr,gMRIcroOverlay[kVOIOverlayNum].HdrFileName); end; procedure TImgForm.ControlPanelDragDrop(Sender, Source: TObject; X, Y: Integer); begin end; (*procedure DescribeVOIonLabelsz (lOverlayNum: integer; lShowFilename: boolean); var lLocalMax,lLocalSum : HistoDoubleRA; l16Buf : SmallIntP; l32Buf : SingleP; l8Buf: byteP; lInten: double; lXmm,lYmm,lZmm: single; lHisto,lRegionVol,lLocalMaxPos: HistoRA; lInc,lRegion: Integer; lLabelStr: string; lVOI: boolean; lLabelStr20 : Array[0..kHistoBins] of kstr20; begin lInten := 0;//just to hide compiler hint... if (gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP = 2) and ('ratlas.nii.gz' = (extractfilename( gMRIcroOverlay[kBGOverlayNum].HdrFileName))) then begin // specific for PCDescribeVOIonLabelsRAT(lOverlayNum,lShowFilename); exit; end; if (gMRIcroOverlay[lOverlayNum].ScrnBufferItems <> gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems) or (gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP <> 1) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 2) then exit; TextForm.MemoT.Lines.add(' Custom Region Analysis'); TextForm.MemoT.Lines.add(' For Speculative Brodmann Map: 0=not cortical and 48=no Brodmann label'); lVOI := IsVOIROIExt(gMRIcroOverlay[lOverlayNum].HdrFileName); if (not lVOI) and (lOverlayNum = kVOIOverlayNum) then lVOI := true; //next describe format if lShowfilename then lLabelStr := ' Filename,' else lLabelStr := ' '; if lVOI then //intensity min/max position are not important TextForm.MemoT.Lines.add(lLabelStr+'Area'+kTextSep+'N>0'+kTextSep+'%N>0') else TextForm.MemoT.Lines.add(lLabelStr+'Area'+kTextSep+'N>0'+kTextSep+'%N>0'+kTextSep+'Sum>0'+kTextSep+'Mean>0'+kTextSep+'Max'+kTextSep+'MaxX'+kTextSep+'MaxY'+kTextSep+'MaxZ'); //next initialize if lShowFilename then lLabelStr := gMRIcroOverlay[lOverlayNum].HdrFileName+kTextSep else lLabelStr := ''; for lInc := 0 to kHistoBins do begin lHisto[lInc] := 0; lLocalMax[lInc] := 0; lLocalSum[lInc] := 0; lRegionVol[lInc] := 0; if (gMRIcroOverlay[kBGOverlayNum].UsesCustomPalette) then lLabelStr20[lInc] := gBGImg.LabelStr20[lInc] else lLabelStr20[lInc] := inttostr(lInc); end; for lInc := 1 to gMRIcroOverlay[lOverlayNum].ScrnBufferItems do if gMRIcroOverlay[lOverlayNum].ScrnBuffer^[lInc] > 0 then inc(lHisto[gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lInc]]); //local max start l32Buf := SingleP(gMRIcroOverlay[lOverlayNum].ImgBuffer ); l16Buf := SmallIntP(gMRIcroOverlay[lOverlayNum].ImgBuffer ); //NEXT if..else July07 - ROIs only use screen buffer, not imgbuffer... if gMRIcroOverlay[lOverlayNum].ScrnBufferItems = gMRIcroOverlay[lOverlayNum].ImgBufferItems then l8Buf := gMRIcroOverlay[lOverlayNum].ImgBuffer else l8Buf := gMRIcroOverlay[lOverlayNum].ScrnBuffer; for lInc := 1 to gMRIcroOverlay[lOverlayNum].ScrnBufferItems do begin if (gMRIcroOverlay[lOverlayNum].ImgBufferBPP = 4) then lInten := l32Buf^[lInc] else if (gMRIcroOverlay[lOverlayNum].ImgBufferBPP = 2) then lInten := l16Buf^[lInc] else if gMRIcroOverlay[lOverlayNum].ImgBufferBPP = 1 then lInten := l8Buf^[lInc];//July07 lRegion := gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lInc]; if lInten > 0 then lLocalSum[lRegion] := lLocalSum[lRegion]+lInten; if lInten > lLocalMax[lRegion] then begin lLocalMax[lRegion] := lInten;//intensity lLocalMaxPos[lRegion] := lInc;//location end; inc(lRegionVol[lRegion]); end; for lInc := 0 to kHistoBins do begin if (not lVOI) and (lLocalMax[lInc] > 0) then begin lLocalMax[lInc] := Raw2ScaledIntensity (gMRIcroOverlay[lOverlayNum],lLocalMax[lInc]); lLocalSum[lInc] := Raw2ScaledIntensity (gMRIcroOverlay[lOverlayNum],lLocalSum[lInc]); ImgPosToMM(lLocalMaxPos[lInc], lXmm,lYmm,lZmm); TextForm.MemoT.Lines.Add(lLabelStr+ lLabelStr20[lInc] + kTextSep + inttostr(lHisto[lInc])+kTextSep+floattostr( lHisto[lInc]/lRegionVol[lInc]) +kTextSep+floattostr( lLocalSum[lInc])+kTextSep+floattostr( lLocalSum[lInc]/lRegionVol[lInc]) //Sum>0, mean>0 +kTextSep + floattostr(lLocalMax[lInc])+kTextSep+floattostr(lXmm)+kTextSep+floattostr(lYmm)+kTextSep+floattostr(lZmm) ); end else if (lHisto[lInc] > 0) {necessarily also and (lRegionVol[lInc] > 0)} then TextForm.MemoT.Lines.Add(lLabelStr+ lLabelStr20[lInc] +kTextSep+ inttostr(lHisto[lInc])+kTextSep+floattostr( lHisto[lInc]/lRegionVol[lInc])) ; end; //for each row end; *) procedure DescribeVOIonLabels (lOverlayNum: integer; lShowFilename: boolean); const kT = kTextSep; PositiveInfinityBits : Int64 = $7FF0000000000000; NegativeInfinityBits : Int64 = $FFF0000000000000; VAR dPositiveInfinity : DOUBLE ABSOLUTE PositiveInfinityBits; dNegativeInfinity : DOUBLE ABSOLUTE NegativeInfinityBits; var l16Buf : SmallIntP; l32Buf : SingleP; l8Buf: byteP; type TVxStat = RECORD //peristimulus plot n, nNot0, minPos,maxPos: integer; sum,sumNot0,min,max: double; end; function clearVxStat: TVxStat; begin result.sum:=0; result.sumNot0:= 0; result.n:=0; result.nNot0 := 0; result.minPos:= 0; result.maxPos:=0; result.min := dPositiveInfinity; result.max := dNegativeInfinity; end; function roiIntensity(var lHdr: TMRIcroHdr; lPos: integer): integer; var l16Buf : SmallIntP; begin if (lHdr.ImgBufferBPP = 2) then begin l16Buf := SmallIntP(lHdr.ImgBuffer ); result := l16Buf^[lPos]; end else result := lHdr.ImgBuffer^[lPos]; end; function overlayIntensity(var lHdr: TMRIcroHdr; lPos: integer): single; begin if (lHdr.ImgBufferBPP = 4) then begin result := l32Buf^[lPos]; end else if (lHdr.ImgBufferBPP = 2) then begin result := l16Buf^[lPos]; end else result := l8Buf^[lPos]; end; procedure scaleIntensity(var valn: double); begin valn := (valn * gMRIcroOverlay[lOverlayNum].NIFTIhdr.scl_slope)+gMRIcroOverlay[lOverlayNum].NIFTIhdr.scl_inter end; var lROI,lVx: integer; lStat: array of TVxStat; lVal,loMax,hiMax: double; lStartTime: DWord; lBinaryOverlay: boolean; lLabelStr,lStr: string; begin if (not gMRIcroOverlay[kBGOverlayNum].UsesLabels) or (High(gBGImg.LabelRA) < 1) then exit; if (gMRIcroOverlay[lOverlayNum].ScrnBufferItems <> gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems) then exit; if (gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP > 2) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 2) then exit; //pointers to image data l32Buf := SingleP(gMRIcroOverlay[lOverlayNum].ImgBuffer ); l16Buf := SmallIntP(gMRIcroOverlay[lOverlayNum].ImgBuffer ); if gMRIcroOverlay[lOverlayNum].ScrnBufferItems = gMRIcroOverlay[lOverlayNum].ImgBufferItems then l8Buf := gMRIcroOverlay[lOverlayNum].ImgBuffer else l8Buf := gMRIcroOverlay[lOverlayNum].ScrnBuffer; lStartTime := GetTickCount; setlength(lStat, High(gBGImg.LabelRA)+1); for lROI := 0 to High(gBGImg.LabelRA) do lStat[lROI] := clearVxStat; for lVx := 1 to gMRIcroOverlay[lOverlayNum].ScrnBufferItems do begin lROI :=roiIntensity(gMRIcroOverlay[kBGOverlayNum], lVx); inc(lStat[lROI].n); lVal := overlayIntensity(gMRIcroOverlay[lOverlayNum],lVx); lStat[lROI].sum := lStat[lROI].sum+ lVal; if lVal <> 0 then begin lStat[lROI].sumNot0 := lStat[lROI].sumNot0+ lVal; inc(lStat[lROI].nNot0); end; if lVal > lStat[lROI].max then lStat[lROI].max := lVal; if lVal < lStat[lROI].min then lStat[lROI].min := lVal; end; //for each voxel //calibrate values with rescale slope/intercept, see if overlay has variablility loMax := dPositiveInfinity; hiMax := dNegativeInfinity; if gMRIcroOverlay[lOverlayNum].NIFTIhdr.scl_slope = 0 then gMRIcroOverlay[lOverlayNum].NIFTIhdr.scl_slope := 1; for lROI := 0 to High(gBGImg.LabelRA) do begin if (lStat[lROI].nNot0 > 0) and (lStat[lROI].max > hiMax) then hiMax := lStat[lROI].max; if (lStat[lROI].nNot0 > 0) and (lStat[lROI].min < loMax) then loMax := lStat[lROI].max; scaleIntensity (lStat[lROI].max); scaleIntensity (lStat[lROI].min); scaleIntensity (lStat[lROI].sum); scaleIntensity (lStat[lROI].sumNot0); end; lBinaryOverlay := (hiMax <= loMax); if lShowFilename then begin if gMRIcroOverlay[lOverlayNum].HdrFileName = '' then lLabelStr := 'VOI'+kT else lLabelStr := gMRIcroOverlay[lOverlayNum].HdrFileName+kT; end else lLabelStr := ''; TextForm.MemoT.Lines.add(lLabelStr+'Custom Region Analysis'); //add header lStr := 'Index'+kT+'Name'+kT+'numVox'+kT+'numVoxNotZero'+kT+'fracNotZero'; if not lBinaryOverlay then lStr := lStr+kT+'peak'+kT+'min'+kT+'mean'+kT+'meanNotZero'; TextForm.MemoT.Lines.Add(lLabelStr+lStr); //report values for lROI := 0 to High(gBGImg.LabelRA) do begin if (lStat[lROI].nNot0 > 0) then begin lStr := inttostr(lROI)+kT+gBGImg.LabelRA[lROI] +kT+inttostr(lStat[lROI].n)+kT+inttostr(lStat[lROI].nNot0)+kT+ realtoStr(lStat[lROI].nNot0/lStat[lROI].n,3); if not lBinaryOverlay then lStr := lStr+kT+floattostr(lStat[lROI].max)+kT+floattostr(lStat[lROI].min) +kT+floattostr(lStat[lROI].sum/lStat[lROI].n) +kT+floattostr(lStat[lROI].sumNot0/lStat[lROI].nNot0); TextForm.MemoT.Lines.Add(lLabelStr+lStr ); end; end; end; procedure ShowDescriptive (lOverlayNum: integer; lShowFilename: boolean); var lROIVol: array [1..3] of integer; lInc: integer; lCenterOfMass,lROISum,lROISumSqr,lROImin,lROImax:array [1..3] of double; lCC,lVal,lSD,lROImean: double; lLabelStr,lStr: string; procedure AddVal( lRA: integer); begin inc(lROIVol[lRA]); lROISum[lRA] := lROISum[lRA]+lVal; lROISumSqr[lRA] := lROISumSqr[lRA] + sqr(lVal); if lVal > lROImax[lRA] then lROImax[lRA] := lVal; if lVal < lROImin[lRA] then lROImin[lRA] := lVal; end; //proc AddVal begin //proc ShowDescript if gMRIcroOverlay[lOverlayNum].ScrnBufferItems <> gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems then exit; if lShowFilename then lLabelStr := gMRIcroOverlay[lOverlayNum].HdrFileName else lLabelStr := ''; for lInc := 1 to 3 do begin lROIVol[lInc] := 0; lROISum[lInc] := 0; lROISumSqr[lInc] := 0; lROImin[lInc] := maxint; lROImax[lInc] := -maxint; end; for lInc := 1 to gMRIcroOverlay[lOverlayNum].ScrnBufferItems do begin if gMRIcroOverlay[lOverlayNum].ScrnBuffer^[lInc] > 0 then begin //fx(lInc); lVal := RawBGIntensity(lInc); AddVal(1); if lVal <> 0 then AddVal(2); if lVal > 0 then AddVal(3); end; //if VOI voxel end; //for each voxel //next - compute StDev //compute descriptives for each set of values if lOverlayNum = kVOIOverlayNum then lStr := 'VOI notes ' else lStr := 'Overlay #'+inttostr(lOverlayNum); if not lShowFilename then begin TextForm.MemoT.Lines.Add(lStr+' '+gMRIcroOverlay[lOverlayNum].HdrFileName); end; //TextForm.Memo1.Lines.Add('CoM'); if CenterOfMass (lOverlayNum, lCenterOfMass[1],lCenterOfMass[2],lCenterOfMass[3]) > 0 then TextForm.MemoT.Lines.Add(' '+lLabelStr+' Center of mass XYZ '+RealToStr(lCenterOfMass[1],2)+'x'+RealToStr(lCenterOfMass[2],2)+'x'+RealToStr(lCenterOfMass[3],2)); for lInc := 1 to 3 do begin if lROIVol[lInc] > 1 then begin lSD := (lROISumSqr[lInc] - ((Sqr(lROISum[lInc]))/lROIVol[lInc])); if (lSD > 0) then lSD := Sqrt ( lSD/(lROIVol[lInc]-1)) else lSD := 0; end else lSD := 0; //next compute mean if lROIVol[lInc] > 0 then begin lROImean := lROISum[lInc]/lROIVol[lInc]; //next - calibrate values lROImin[lInc] := Raw2ScaledIntensity (gMRIcroOverlay[kBGOverlayNum],lROImin[lInc]); lROIMean := Raw2ScaledIntensity (gMRIcroOverlay[kBGOverlayNum],lROIMean); lROImax[lInc] := Raw2ScaledIntensity (gMRIcroOverlay[kBGOverlayNum],lROImax[lInc]); lSD := Raw2ScaledIntensity (gMRIcroOverlay[kBGOverlayNum],lSD); end else begin //2/2008 lROImin[lInc] := 0; lROImax[lInc] := 0; lROImean := 0; end; lcc := ((lROIVol[lInc]/1000)*gBGImg.ScrnMM[1]*gBGImg.ScrnMM[2]*gBGImg.ScrnMM[3]); case lInc of 3: lStr := 'VOI >0 '; 2: lStr := 'VOI <>0 '; else lStr := 'VOI '; end; lStr := lStr+' nvox(cc)=min/mean/max=SD: '+inttostr(round(lROIVol[lInc]))+kTextSep+RealToStr(lCC,2)+kTextSep+'='+kTextSep+RealToStr(lROIMin[lInc],4)+kTextSep+realToStr(lROIMean,4)+kTextSep+realToStr(lROIMax[lInc],4)+kTextSep+'='+kTextSep+realtostr(lSD,4); TextForm.MemoT.Lines.Add(lLabelStr+ lStr); end; //June07 if (gMRIcroOverlay[kBGOverlayNum].UsesCustomPalette) or (lShowFilename) then DescribeVOIonLabels(lOverlayNum,lShowfilename); TextForm.MemoT.Lines.Add(''); ImgForm.SaveDialog1.Filename := ExtractFileDirWithPathDelim(gMRIcroOverlay[lOverlayNum].HdrFileName)+'desc.csv'; end; procedure TImgForm.BatchROImean1Click(Sender: TObject); var lInc,lNumberofFiles: integer; lFilename:string; begin if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1 then begin showmessage('Please load a background image for rescaling.'); exit; end; for lInc := 1 to (knMaxOverlay-1) do FreeImgMemory(gMRIcroOverlay[lInc]); UpdateLayerMenu; if not OpenDialogExecute(kImgFilter,'Select images you wish to analyze',true) then exit; lNumberofFiles:= HdrForm.OpenHdrDlg.Files.Count; if lNumberofFiles < 1 then exit; TextForm.MemoT.Lines.Clear; for lInc:= 1 to lNumberofFiles do begin lFilename := HdrForm.OpenHdrDlg.Files[lInc-1]; OverlayOpenCore ( lFilename, 2); ShowDescriptive(2,true); //LayerDrop.SetItemIndex(LayerDrop.Items.Count-1); //LayerDropSelect(nil); end; FreeImgMemory(gMRIcroOverlay[2]); UpdateLayerMenu; //SaveDialog1.Filename := ExtractFileDirWithPathDelim(HdrForm.OpenHdrDlg.Files[0])+'desc.csv'; TextForm.Show; end; procedure TImgForm.Batchprobmaps1Click(Sender: TObject); begin BatchVOI; end; procedure TImgForm.Batchclusterprobmaps1Batchclusterprobmaps1ClickClick( Sender: TObject); begin BatchCluster; end; procedure TImgForm.GenerateSPM5maskslesions1Click(Sender: TObject); begin VOISmoothForm.SmoothVOI_SPM5masks; end; procedure TImgForm.OverlayOpenClick(Sender: TObject); var lFilename: string; lOverlay,lInc: integer; begin if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1 then begin showmessage('Please load a background image (''File''/''Open'') before adding an overlay.'); exit; end; if not OpenDialogExecute(kImgFilter,'Select overlay image[s]',true) then exit; if HdrForm.OpenHdrDlg.Files.Count < 1 then exit; for lInc := 1 to HdrForm.OpenHdrDlg.Files.Count do begin //vcx lFilename := HdrForm.OpenHdrDlg.Files[lInc-1]; LoadOverlayIncludingRGB{LoadOverlay}(lFilename); LayerDrop.ItemIndex := (LayerDrop.Items.Count-1); {$IFNDEF FPC} LayerDrop.SetItemIndex(LayerDrop.Items.Count-1); {$ELSE} LayerDrop.ItemIndex :=(LayerDrop.Items.Count-1); {$ENDIF} end; (* //HdrForm.OpenHdrDlg.Filter := kImgFilter; // if not HdrForm.OpenHdrDlg.Execute then exit; if not OpenDialogExecute(kImgFilter,'Select overlay image',false) then exit; lOverlay := 0; for lC := 1 to (knMaxOverlay-1) do //-1: save final overlay for VOI if (lOverlay = 0) and (gMRIcroOverlay[lC].ImgBufferItems = 0) then lOverlay := lC; if lOverlay = 0 then begin showmessage('Unable to add an overlay. You have loaded the maximum number of overlays.'); exit; end; lFilename := HdrForm.OpenHdrDlg.Filename; OverlayOpenCore ( lFilename, lOverlay); *) LayerDropSelect(nil); end; //OverlayOpenClick procedure TImgForm.BGtrans100Click(Sender: TObject); begin (sender as TMenuItem).checked := true; gBGImg.BGTransPct := (sender as TMenuItem).tag; RefreshImagesTimer.Enabled := true; end; procedure TImgForm.OverlayTransClick(Sender: TObject); begin (sender as TMenuItem).checked := true; gBGImg.OverlayTransPct := (sender as TMenuItem).tag; RefreshImagesTimer.Enabled := true; end; procedure TImgForm.LayerDropSelect(Sender: TObject); var lLayer: integer; begin lLayer := ActiveLayer; MaxWindowEdit.Value := gMRIcroOverlay[lLayer].WindowScaledMax; MinWindowEdit.Value := gMRIcroOverlay[lLayer].WindowScaledMin; if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems=0 then exit; {$IFNDEF FPC} LUTdrop.SetItemIndex(gMRIcroOverlay[lLayer].LUTindex); {$ELSE} LUTdrop.ItemIndex :=(gMRIcroOverlay[lLayer].LUTindex); {$ENDIF} //LUTinvertBtn.down := gMRIcroOverlay[lLayer].LUTinvert; LutFromZeroBtn.down := gMRIcroOverlay[lLayer].LutFromZero; end; procedure TImgForm.UpdateLayerMenu; var lStrings: TStringList; lPos,lLayer:integer; begin lStrings := TStringList.Create; lStrings.Add('Background'); lLayer := 0; for lPos := 1 to (knMaxOverlay-1) do //-1 as max overlay is VOI if (gMRIcroOverlay[lPos].ImgBufferItems > 0) then begin lStrings.Add(ParseFileName(ExtractFileName(gMRIcroOverlay[lPos].HdrFileName))); inc(lLayer); LUTdropLoad(lLayer); end; LayerDrop.Items := lStrings; {$IFNDEF FPC} if LayerDrop.ItemIndex >= LayerDrop.Items.Count then LayerDrop.SetItemIndex(LayerDrop.Items.Count-1); {$ELSE} if LayerDrop.ItemIndex >= LayerDrop.Items.Count then LayerDrop.ItemIndex :=(LayerDrop.Items.Count-1); {$ENDIF} LayerDropSelect(nil); lStrings.Free; end; procedure TImgForm.CloseOverlayImgClick(Sender: TObject); var lOverlay: integer; begin for lOverlay := 1 to (knMaxOverlay-1) do FreeImgMemory(gMRIcroOverlay[lOverlay]); UpdateLayerMenu; RefreshImagesTimer.Enabled := true; end; procedure TImgForm.LUTdropLoad(var lLayer: integer); var lStr: string; begin (*if gMRIcroOverlay[lLayer].NIFTIhdr.intent_code = kNIFTI_INTENT_LABEL then begin createLutLabel (gMRIcroOverlay[lLayer], 1.0); //RefreshImagesTimer.Enabled := true; exit; end; if gMRIcroOverlay[lLayer].UsesCustomPaletteRandomRainbow then exit; *) if gMRIcroOverlay[lLayer].UsesCustomPalette then begin exit; end; //gMRIcroOverlay[lLayer].LUTindex := LUTdrop.ItemIndex; if gMRIcroOverlay[lLayer].LUTindex < knAutoLUT then begin LoadMonochromeLUT(gMRIcroOverlay[lLayer].LUTindex,gBGImg,gMRIcroOverlay[lLayer]); RefreshImagesTimer.Enabled := true; exit; end; //if B&W lut lStr := gColorSchemeDir+pathdelim+LUTdrop.Items.Strings[gMRIcroOverlay[lLayer].LUTindex]+'.lut'; if not FileExistsEX(lStr) then showmessage('Can not find '+lStr); LoadColorScheme(lStr, gMRIcroOverlay[lLayer]); RefreshImagesTimer.Enabled := true; end; procedure TImgForm.LUTdropSelect(Sender: TObject); var lLayer: integer; begin lLayer := ActiveLayer; gMRIcroOverlay[lLayer].LUTindex := LUTdrop.ItemIndex; //gMRIcroOverlay[lLayer].LUTinvert := LUTinvertBtn.down; //gMRIcroOverlay[lLayer].LutFromZero := LutFromZeroBtn.down; LUTdropLoad(lLayer); //RescaleImagesTimer.Enabled := true; end; //proc LUTdropSelect procedure TImgForm.AutoContrastBtnClick(Sender: TObject); var lLayer: integer; begin lLayer := ActiveLayer; MinWindowEdit.Value := raw2ScaledIntensity(gMRIcroOverlay[lLayer], gMRIcroOverlay[lLayer].AutoBalMinUnscaled); MaxWindowEdit.Value := raw2ScaledIntensity(gMRIcroOverlay[lLayer],gMRIcroOverlay[lLayer].AutoBalMaxUnscaled);{} gMRIcroOverlay[lLayer].WindowScaledMin := MinWindowEdit.Value; gMRIcroOverlay[lLayer].WindowScaledMax := MaxWindowEdit.Value; RescaleImgIntensity(gBGImg,gMRIcroOverlay[lLayer],lLayer); RefreshImagesTimer.Enabled := true; end; procedure TImgForm.MinContrastWindowEditChange(Sender: TObject); var lLayer: integer; begin lLayer := ActiveLayer; //if gMRIcroOverlay[lLayer].WindowScaledMin = MinWindowEdit.Value then exit; gMRIcroOverlay[lLayer].WindowScaledMin := MinWindowEdit.Value; gMRIcroOverlay[lLayer].WindowScaledMax := MaxWindowEdit.Value; RescaleImagesTimer.Enabled := true; end; procedure TImgForm.MaxContrastWindowEditChange(Sender: TObject); var lLayer: integer; begin lLayer := ActiveLayer; if gMRIcroOverlay[lLayer].WindowScaledMax = MaxWindowEdit.Value then exit; gMRIcroOverlay[lLayer].WindowScaledMax := MaxWindowEdit.Value; RescaleImagesTimer.Enabled := true; end; procedure TImgForm.OverlaySmoothMenuClick(Sender: TObject); var lC: integer; begin if Sender = nil then begin gBGImg.OverlaySmooth := OverlaySmoothMenu.Checked; exit; end; OverlaySmoothMenu.Checked := not OverlaySmoothMenu.Checked; gBGImg.OverlaySmooth := OverlaySmoothMenu.Checked; for lC := 1 to knMaxOverlay do if gMRIcroOverlay[lC].ScrnBufferItems > 0 then RescaleImgIntensity(gBGImg,gMRIcroOverlay[lC],lC); RefreshImagesTimer.Enabled := true; end; procedure TImgForm.ShowRenderClick(Sender: TObject); begin RenderForm.Show; //RenderForm.BringToFront; end; procedure TImgForm.PenBtnClick(Sender: TObject); begin RefreshImagesTimer.Enabled := true; end; procedure OpenMRIcroROI (lFilename: string); const kMax12bit = 4095; kMax16bit = (256*256)-1; kMax15bit = kMax16bit shr 1; //kMax20bit = (16*256*256)-1; // k20v16bit = kMax20bit - kMax16bit; //kMaxRuns = 10000; //kMaxFile = 65536; //k16v12bit = kMax16bit - kMax12bit; var lFile32bitItems,lFileSz,lFilePos,lSliceSz,lZ,lRunsOnSlice, lRunLength,lRun,lRunOffset,lOutputSliceOffset,lRunPos: integer; lROIformatRA: LongIntp; lF: File; lBigFormat: boolean; begin lFileSz := FSize(lFilename); if (lFileSz < 1) or ((lFileSz mod 4) <> 0) then begin showmessage('Unable to open ROI: file size should be divisible by 4.'); exit; end; lFile32bitItems := lFileSz div 4; //how many 32-bit items? lSliceSz := gBGImg.ScrnDim[1]*gBGImg.ScrnDim[2]; lZ := gBGImg.ScrnDim[3]; if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems > 0 then freemem(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer); gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems := lSliceSz * lZ; getmem(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer,lSliceSz * lZ); fillchar(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems,0); if lSliceSz > 65535 then lBigFormat := true else lBigFormat := false; getmem(lROIformatRA,lFileSz); //file size must be divisible by 4 {$I-} AssignFile(lF, lFilename); FileMode := 0; { Set file access to read only } Reset(lF, 1); BlockRead(lF,lROIformatRA^,lFileSz); CloseFile(lF); FileMode := 2; {$I+} //next: check MSB of first byte to see if this is big format images if lBigFormat <> odd((lROIformatRA^[1] and kMax16bit) shr 15) then Showmessage('Warning: this ROI does not appear to be designed for the currently loaded background image.'); lFilePos := 1; if lBigFormat then begin //20-byte offset, 12-byte runlength while lFilePos < lFile32bitItems do begin lRunsOnSlice := (lROIformatRA^[lFilePos] shr 17) - 1; //shr 17: shift 16 bits, then div 2 (words instead of longints). Subtract 1 as the we have read slice number/ number of runs lZ := (lROIformatRA^[lFilePos] and kMax15bit); inc(lFilePos); lOutputSliceOffset := (lZ-1) * lSliceSz; for lRun := 1 to lRunsOnSlice do begin if (lFilePos <= lFileSz) then begin lRunLength := (lROIformatRA^[lFilePos] shr 16) and kMax12bit; lRunOffset := (lROIformatRA^[lFilePos] and kMax16bit)+ ((lROIformatRA^[lFilePos] shr 28) shl 16); if (lOutputSliceOffset+lRunLength+lRunOffset-1)> gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems then //showmessage('Overrun on slice '+inttostr(lZ)) else for lRunPos := lRunOffset to (lRunLength+lRunOffset-1) do gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lRunPos+lOutputSliceOffset] := kVOI8bit; end; inc(lFilePos); end;//for all runs end; //while lPos < lFSz end else begin //not big format format - 16-byte offset, 16-byte length while lFilePos < lFile32bitItems do begin //lRunsOnSlice := (lROIformatRA[lFilePos] shr 16) and kMax16bit; lRunsOnSlice := (lROIformatRA^[lFilePos] shr 17) - 1; //shr 17: shift 16 bits, then div 2 (words instead of longints). Subtract 1 as the we have read slice number/ number of runs lZ := (lROIformatRA^[lFilePos] and kMax15bit); inc(lFilePos); lOutputSliceOffset := (lZ-1) * lSliceSz; //showmessage(inttostr(lZ)+' '+inttostr(lRunsOnSlice)+' '+inttostr(lFilePos)+' '+inttostr(lFileSz)); for lRun := 1 to lRunsOnSlice do begin if (lFilePos <= lFileSz) then begin lRunLength := (lROIformatRA^[lFilePos] shr 16) and kMax16bit; lRunOffset := (lROIformatRA^[lFilePos] and kMax16bit); {if (lRunLength+lRunOffset-1)> gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems then showmessage('Overrun on slice '+inttostr(lZ)) else} for lRunPos := lRunOffset to (lRunLength+lRunOffset-1) do gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lRunPos+lOutputSliceOffset] := kVOI8bit; end; inc(lFilePos); end;//for all runs end; //while lPos < lFSz end; //if bigformat ... else little format freemem(lROIformatRA); lRun := maxint; LoadMonochromeLUT(lRun,gBGImg,gMRIcroOverlay[kVOIOverlayNum]); end; procedure TImgForm.OpenVOICore(var lFilename : string); var lExt: string; begin if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems > 0 then ImgForm.CloseVOIClick(nil); lExt := UpCaseExt(lFileName); gBGImg.VOIchanged := false; if (lExt='.ROI') then begin Showmessage('Warning: MRIcro ROI format does not save image dimensions. The background image must be in the same dimensions as the ROI.'); OpenMRIcroROI (lFileName); ImgForm.RefreshImagesTimer.Enabled := true; exit; end; if not HdrForm.OpenAndDisplayHdr(lFilename,gMRIcroOverlay[kVOIOverlayNum]) then exit; if not OpenImg(gBGImg,gMRIcroOverlay[kVOIOverlayNum],false,true,false,gBGImg.ResliceOnLoad,false) then exit; ImgForm.RefreshImagesTimer.Enabled := true; end;//OpenVOIClick procedure TImgForm.OpenVOIClick(Sender: TObject); var lFilename: string; begin if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1 then begin showmessage('Please load a background image (''File''/''Open'') before adding a VOI.'); exit; end; //HdrForm.OpenHdrDlg.Filter := '*.roi';//kVOIFilter; //if not HdrForm.OpenHdrDlg.Execute then exit; if not OpenDialogExecute(kVOIFilter,'Select Volume of Interest drawing',false) then exit; lFilename := HdrForm.OpenHdrDlg.Filename; OpenVOICore(lFilename); end;//OpenVOIClick (*procedure TImgForm.SaveVOIClick(Sender: TObject); var lHdr: TMRIcroHdr; begin if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems= 0 then begin Showmessage('You need to create a VOI before you can save it.'); exit; end; if gBGImg.Mirror then begin lHdr.ScrnBufferItems := gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems; Getmem(lHdr.ScrnBuffer,gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems); Move(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[1],lHdr.ScrnBuffer^[1],lHdr.ScrnBufferItems); MirrorScrnBuffer(gBGImg,lHdr); SaveAsVOIorNIFTI(lHdr.ScrnBuffer,lHdr.ScrnBufferItems,1,1,true,gMRIcroOverlay[kBGOverlayNum].NiftiHdr,gMRIcroOverlay[kVOIOverlayNum].HdrFileName); Freemem(lHdr.ScrnBuffer); exit; //sept2007 end; SaveAsVOIorNIFTI(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer,gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems,1,1,true,gMRIcroOverlay[kBGOverlayNum].NiftiHdr,gMRIcroOverlay[kVOIOverlayNum].HdrFileName); end;*) procedure TImgForm.SaveVOIcore(lPromptFilename: boolean); var lHdr: TMRIcroHdr; lNIFTIhdr: TNIFTIhdr; begin if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems= 0 then begin Showmessage('You need to create a VOI before you can save it.'); exit; end; //Start 10/2007: adjust scl_slope;? 10/2007 CopyNiftiHdr(gMRIcroOverlay[kBGOverlayNum].NiftiHdr,lNIFTIhdr); lNIFTIhdr.scl_slope := 1; lNIFTIhdr.scl_inter := 0; //end if gBGImg.Mirror then begin lHdr.ScrnBufferItems := gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems; Getmem(lHdr.ScrnBuffer,gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems); Move(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[1],lHdr.ScrnBuffer^[1],lHdr.ScrnBufferItems); MirrorScrnBuffer(gBGImg,lHdr); if lPromptFilename then SaveAsVOIorNIFTI(lHdr.ScrnBuffer,lHdr.ScrnBufferItems,1,1,true,lNIFTIhdr,gMRIcroOverlay[kVOIOverlayNum].HdrFileName) else SaveAsVOIorNIFTIcore(gMRIcroOverlay[kVOIOverlayNum].HdrFileName,lHdr.ScrnBuffer,lHdr.ScrnBufferItems,1,1,lNIFTIhdr); Freemem(lHdr.ScrnBuffer); exit; //12/2010 end; if lPromptFilename then SaveAsVOIorNIFTI(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer,gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems,1,1,true,lNiftiHdr,gMRIcroOverlay[kVOIOverlayNum].HdrFileName) else SaveAsVOIorNIFTIcore(gMRIcroOverlay[kVOIOverlayNum].HdrFileName,gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer,gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems,1,1,lNiftiHdr); end; procedure TImgForm.Extract1Click(Sender: TObject); var lMin : smallint; lOtsuLevels,lnVox,lVox,lDilate: integer; lOneContiguousObject : boolean; l16Buf : SmallIntP; l32Buf : SingleP; lMinS: single; begin lnVox := gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems; if lnVox < 9 then begin showmessage('Please load a background image.'); exit; end; lOtsuLevels := ReadIntForm.GetInt('Otsu levels: larger values for larger volumes',1,4,5); lDilate := ReadIntForm.GetInt('Edge dilation voxels: larger values for larger volumes',0,2,12); lOneContiguousObject := OKMsg('Only extract single largest object?'); //MaskBackground (var lImg: Bytep; lXi,lYi,lZi,lOtsuLevels: integer; lDilateVox: single; lOneContiguousObject: boolean ); MaskBackground(gMRIcroOverlay[kBGOverlayNum].ScrnBuffer, gBGImg.ScrnDim[1],gBGImg.ScrnDim[2],gBGImg.ScrnDim[3],lOtsuLevels,lDilate,lOneContiguousObject); if (gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP = 4) then begin l32Buf := SingleP(gMRIcroOverlay[kBGOverlayNum].ImgBuffer ); lMinS := l32Buf^[1]; for lVox := 1 to lnVox do if l32Buf^[lVox] < lMinS then lMinS := l32Buf^[lVox]; for lVox := 1 to lnVox do if gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lVox] = 0 then l32Buf^[lVox] := lMinS; end else if (gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP = 2) then begin l16Buf := SmallIntP(gMRIcroOverlay[kBGOverlayNum].ImgBuffer ); lMin := l16Buf^[1]; for lVox := 1 to lnVox do if l16Buf^[lVox] < lMin then lMin := l16Buf^[lVox]; for lVox := 1 to lnVox do if gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lVox] = 0 then l16Buf^[lVox] := lMin; end else if gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP = 1 then begin lMin := gMRIcroOverlay[kBGOverlayNum].ImgBuffer^[1]; for lVox := 1 to lnVox do if gMRIcroOverlay[kBGOverlayNum].ImgBuffer^[lVox] < lMin then lMin := gMRIcroOverlay[kBGOverlayNum].ImgBuffer^[lVox]; for lVox := 1 to lnVox do if gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lVox] = 0 then gMRIcroOverlay[kBGOverlayNum].ImgBuffer^[lVox] := lMin; end; end; procedure TImgForm.ToggleDrawMenu(Sender: TObject); begin gBGImg.ShowDraw := not DrawMenu.Visible; WriteIni2Form(gBGImg); end; procedure TImgForm.SaveVOIClick(Sender: TObject); var lHdr: TMRIcroHdr; lNIFTIhdr: TNIFTIhdr; begin if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems= 0 then begin Showmessage('You need to create a VOI before you can save it.'); exit; end; //Start 10/2007: adjust scl_slope;? 10/2007 CopyNiftiHdr(gMRIcroOverlay[kBGOverlayNum].NiftiHdr,lNIFTIhdr); lNIFTIhdr.scl_slope := 1; lNIFTIhdr.scl_inter := 0; //end if gBGImg.Mirror then begin lHdr.ScrnBufferItems := gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems; Getmem(lHdr.ScrnBuffer,gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems); Move(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[1],lHdr.ScrnBuffer^[1],lHdr.ScrnBufferItems); MirrorScrnBuffer(gBGImg,lHdr); SaveAsVOIorNIFTI(lHdr.ScrnBuffer,lHdr.ScrnBufferItems,1,1,true,lNIFTIhdr,gMRIcroOverlay[kVOIOverlayNum].HdrFileName); Freemem(lHdr.ScrnBuffer); exit; //sept2007 end; SaveAsVOIorNIFTI(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer,gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems,1,1,true,lNiftiHdr,gMRIcroOverlay[kVOIOverlayNum].HdrFileName); end; procedure TImgForm.VOIColorClick(Sender: TObject); var lMaxi: longint; begin ColorDialog1.Color := gBGImg.VOIClr; if not ColorDialog1.Execute then exit; gBGImg.VOIClr := ColorDialog1.Color; if gBGImg.VOIClr = clBlack then gBGImg.VOIClr := 1; //reserve 0 for deleting lMaxi:=maxint; LoadMonochromeLUT(lMaxi,gBGImg,gMRIcroOverlay[kVOIOverlayNum]); RefreshImagesTimer.Enabled := true; end; procedure TImgForm.CloseVOIClick(Sender: TObject); begin if (gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems>0) and (gBGImg.VOIChanged) then begin case MessageDlg('Do you wish to save the VOI drawing?', mtConfirmation, [mbYes, mbNo], 0) of { produce the message dialog box } {id_Yes}mrYes: SaveVOIClick(nil); end; //case end;//if changed FreeUndoVol; FreeImgMemory(gMRIcroOverlay[kVOIOverlayNum]); gBGImg.VOIUndoSlice := 0; gBGImg.VOIchanged := false; gBGImg.VOIUndoOrient := 0; RefreshImagesTimer.Enabled := true; end; procedure ImageRB (var lMaxR,lMaxB: integer; var lImage: TImage); var lPos: integer; begin if not lImage.Visible then exit; lPos := lImage.Left+lImage.Width; if lPos > lMaxR then lMaxR := lPos; lPos := lImage.Top+lImage.Height; if lPos > lMaxB then lMaxB := lPos; end; procedure CopyImg(var lSourceImg,lDestImg: TImage); var lPos: integer; begin if not lSourceImg.Visible then exit; lDestImg.Canvas.Draw(lSourceImg.Left,lSourceImg.Top,lSourceImg.Picture.Graphic); end; procedure TImgForm.SaveOrCopyImages(lCopy: boolean); var lMaxR,lMaxB: integer; lOutImg: TImage; begin lMaxR := 0; lMaxB := 0; ImageRB(lMaxR,lMaxB,ImgForm.PGImageAx); ImageRB(lMaxR,lMaxB,ImgForm.PGImageCor); ImageRB(lMaxR,lMaxB,ImgForm.PGImageSag); if (lMaxR < 1) or (lMaxB < 1) then exit; lOutImg := TImage.Create(ImgForm); try //use the object {$IFDEF FPC} lOutImg.Width := lMaxR; lOutImg.Height := lMaxB; {$ELSE} CreateImg(lMaxB,lMaxR,lOutImg); {$ENDIF} lOutImg.Canvas.Brush.color := ImgForm.TriplePanel.color; lOutImg.Canvas.Rectangle(0,0,lMaxR+1,lMaxB+1); CopyImg(ImgForm.PGImageAx,lOutImg); CopyImg(ImgForm.PGImageCor,lOutImg); CopyImg(ImgForm.PGImageSag,lOutImg); if lCopy then begin {$IFDEF FPC} lOutImg.Picture.Bitmap.SaveToClipboardFormat(2); //Clipboard.Assign(lOutImg.Picture.Bitmap); {$ENDIF} Clipboard.Assign(lOutImg.Picture.Graphic); end else SaveImgAsPNGBMP (lOutImg); finally FreeAndNil (lOutImg); end; end; procedure TImgForm.Saveaspicture1Click(Sender: TObject); begin SaveOrCopyImages(false); end; (*var lImage: TImage; begin lImage := SelectedImage; SaveImgAsPNGBMP (lImage); end; //Proc Saveaspicture1Click *) procedure TImgForm.Copy1Click(Sender: TObject); //Requires 'ClipBrd' in uses section begin SaveOrCopyImages(true); end; (*procedure TImgForm.Copy1Click(Sender: TObject); //Requires 'ClipBrd' in uses section var MyFormat : Word; lImage: TImage; AData: THandle; {$IFNDEF FPC}APalette : HPalette;{$ENDIF} begin lImage := SelectedImage; if (lImage.Picture.Graphic = nil) then begin //1420z Showmessage('You need to load an image before you can copy it to the clipboard.'); exit; end; {$IFNDEF FPC} lImage.Picture.Bitmap.SaveToClipBoardFormat(MyFormat,AData,APalette); ClipBoard.SetAsHandle(MyFormat,AData); {$ELSE} lImage.Picture.Bitmap.SaveToClipboardFormat(2); {$ENDIF} if (gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems>0) then WriteUndoVOI(SelectedImageNum,false); end; *) procedure TImgForm.Undo1Click(Sender: TObject); begin if gBGImg.VOIUndoSlice < 1 then exit; case gBGImg.VOIUndoOrient of 4: UndoVolVOI; 3: ReadCorVOI(gUndoImg,gBGImg.VOIUndoSlice); 2: ReadSagVOI(gUndoImg,gBGImg.VOIUndoSlice); 1: ReadAxialVOI(gUndoImg,gBGImg.VOIUndoSlice); end; ImgForm.RefreshImagesTimer.Enabled := true; end; procedure TImgForm.Paste1Click(Sender: TObject); begin if (gBGImg.VOIUndoSlice < 1) then exit; if gBGImg.VOIUndoOrient <> SelectedImageNum then //12/2007 exit; WriteUndoVOI(SelectedImageNum,true); case gBGImg.VOIUndoOrient of 3: ReadCorVOI(gDrawImg,ImgForm.YViewEdit.Value); 2: ReadSagVOI(gDrawImg,ImgForm.XViewEdit.Value); 1: ReadAxialVOI(gDrawImg,ImgForm.ZViewEdit.Value); else exit; end; ImgForm.RefreshImagesTimer.Enabled := true; end; procedure TImgForm.HideROIBtnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin gOrigBGTransPct := gBGImg.BGTransPct; gBGImg.BGTransPct := 100; refreshimagestimer.enabled := true; end; procedure TImgForm.HideROIBtnMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin gBGImg.BGTransPct := gOrigBGTransPct; Refreshimagestimer.enabled := true; end; procedure TImgForm.Applyintensityfiltertovolume1Click(Sender: TObject); begin if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems=0 then begin showmessage('You must have open a background image in order to apply an intensity filter (use File/Open).'); exit; end; FilterROIform.showmodal; end; procedure TImgForm.Quicksmooth1Click(Sender: TObject); var lHdr: TMRicroHdr; lXDim,lYDim,lZDim,lSum,lMinWt,lMaxWt,lMinInten,lMaxInten,lOutVolVox,lOutSliceSz,lX,lY,lZ,lXxi,l2,lZyi: integer; lSum32,lMinInten32,lMaxInten32: single; lTempBuff,lSrcBuff: Bytep; l16TempBuff,l16SrcBuff: SmallIntP; l32TempBuff,l32SrcBuff: SingleP; procedure AddPoint (lInten,lWeight:integer); begin lSum := lSum + (lInten*lWeight); if lInten <= lMinInten then begin lMinWt := lWeight; lMinInten := lInten; end else if lInten >= lMaxInten then begin lMaxWt := lWeight; lMaxInten := lInten; end; end; //nested AddPoint procedure AddPoint32 (lInten32: single; lWeight:integer); begin lSum32 := lSum32 + (lInten32*lWeight); if lInten32 <= lMinInten32 then begin lMinWt := lWeight; lMinInten32 := lInten32; end else if lInten32 >= lMaxInten32 then begin lMaxWt := lWeight; lMaxInten32 := lInten32; end; end; //nested AddPoint32 begin lHdr := gMRIcroOverlay[kBGOverlayNum]; lXDim := gBGImg.ScrnDim[1]; lYDim := gBGImg.ScrnDim[2]; lZDim := gBGImg.ScrnDim[3]; lOutSliceSz := gBGImg.ScrnDim[1] * gBGImg.ScrnDim[2]; lOutVolVox := lOutSliceSz * lZDim; if (lXDim < 3) or (lYDim < 3) or (lZDim < 3) or (lOutVolVox < 36) then begin showmessage('The 3D smoothing can only be applied to images with at least 3 slices in each dimension.'); exit; end; if (lHdr.ImgBufferItems < 1) then begin showmessage('Please first load the image you would like to smooth.'); exit; end; ProgressBar1.Min := 0; ProgressBar1.Max :=lZDim; StatusLabel.caption := 'Removing noise speckles and smoothing data [blur]'; if lHdr.ImgBufferBPP = 4 then begin //32-bit float data l32SrcBuff := SingleP(lHdr.ImgBuffer); GetMem(l32TempBuff,lOutVolVox*sizeof(single)); Move(l32SrcBuff^,l32TempBuff^,lOutVolVox*sizeof(single)); for lZ := 1 to lOutVolVox do l32SrcBuff^[lZ] := 0; for lZ := lZDim-1 downto 2 do begin ProgressBar1.Position := (lZDim-lZ); for lY := lYDim-1 downto 2 do begin lZyi := ((lZ-1)*lOutSliceSz) + ((lY-1) * lXDim); for lX := lXDim-1 downto 2 do begin lXxi := lZyi + lX; //next: gaussian mean after min/max values are excluded lSum32 := 0; lMinInten32 := l32TempBuff^[lXxi]; lMaxInten32 := l32TempBuff^[lXxi]; lMinWt := 12; lMaxWt := 12; AddPoint32(l32TempBuff^[lXxi],12);//quad-weight center AddPoint32(l32TempBuff^[lXxi-lOutSliceSz],2);//prev slice AddPoint32(l32TempBuff^[lXxi+lOutSliceSz],2);//next slices AddPoint32(l32TempBuff^[lXxi-1],2);//Left AddPoint32(l32TempBuff^[lXxi+1],2);//right AddPoint32(l32TempBuff^[lXxi-lXDim],2);//up AddPoint32(l32TempBuff^[lXxi+lXDim],2);//down AddPoint32(l32TempBuff^[lXxi-lOutSliceSz-1],1); AddPoint32(l32TempBuff^[lXxi-lOutSliceSz+1],1); AddPoint32(l32TempBuff^[lXxi-lOutSliceSz-lXDim],1); AddPoint32(l32TempBuff^[lXxi-lOutSliceSz+lXDim],1); AddPoint32(l32TempBuff^[lXxi+lOutSliceSz-1],1); AddPoint32(l32TempBuff^[lXxi+lOutSliceSz+1],1); AddPoint32(l32TempBuff^[lXxi+lOutSliceSz-lXDim],1); AddPoint32(l32TempBuff^[lXxi+lOutSliceSz+lXDim],1); AddPoint32(l32TempBuff^[lXxi-lXDim-1],1); AddPoint32(l32TempBuff^[lXxi+lXDim-1],1); AddPoint32(l32TempBuff^[lXxi-lXDim+1],1); AddPoint32(l32TempBuff^[lXxi+lXDim+1],1); if lMinInten32 = lMaxInten32 then l32SrcBuff^[lXxi] := lMaxInten32 //no variability in data else begin l2 := 36 - lMinWt -lMaxWt; //weight after we exceed brightest and darkest lSum32 := lSum32 -(lMinWt*lMinInten32) - (lMaxWt*lMaxInten32); //exclude brightest/darkest l32SrcBuff^[lXxi] := (lSum32/l2); end; end; //forX end; //forY end; //forZ Freemem(l32TempBuff); end else if (lHdr.ImgBufferBPP = 2) then begin //16-bit int data*) l16SrcBuff := SmallIntP(lHdr.ImgBuffer ); GetMem(l16TempBuff,lOutVolVox*sizeof(word)); Move(l16SrcBuff^,l16TempBuff^,lOutVolVox*sizeof(word)); for lZ := 1 to lOutVolVox do l16SrcBuff^[lZ] := 0; for lZ := lZDim-1 downto 2 do begin ProgressBar1.Position := (lZDim-lZ); for lY := lYDim-1 downto 2 do begin lZyi := ((lZ-1)*lOutSliceSz) + ((lY-1) * lXDim); for lX := lXDim-1 downto 2 do begin lXxi := lZyi + lX; //next: gaussian mean after min/max values are excluded lSum := 0; lMinInten := l16TempBuff^[lXxi]; lMaxInten := l16TempBuff^[lXxi]; lMinWt := 12; lMaxWt := 12; AddPoint(l16TempBuff^[lXxi],12);//quad-weight center AddPoint(l16TempBuff^[lXxi-lOutSliceSz],2);//prev slice AddPoint(l16TempBuff^[lXxi+lOutSliceSz],2);//next slices AddPoint(l16TempBuff^[lXxi-1],2);//Left AddPoint(l16TempBuff^[lXxi+1],2);//right AddPoint(l16TempBuff^[lXxi-lXDim],2);//up AddPoint(l16TempBuff^[lXxi+lXDim],2);//down AddPoint(l16TempBuff^[lXxi-lOutSliceSz-1],1); AddPoint(l16TempBuff^[lXxi-lOutSliceSz+1],1); AddPoint(l16TempBuff^[lXxi-lOutSliceSz-lXDim],1); AddPoint(l16TempBuff^[lXxi-lOutSliceSz+lXDim],1); AddPoint(l16TempBuff^[lXxi+lOutSliceSz-1],1); AddPoint(l16TempBuff^[lXxi+lOutSliceSz+1],1); AddPoint(l16TempBuff^[lXxi+lOutSliceSz-lXDim],1); AddPoint(l16TempBuff^[lXxi+lOutSliceSz+lXDim],1); AddPoint(l16TempBuff^[lXxi-lXDim-1],1); AddPoint(l16TempBuff^[lXxi+lXDim-1],1); AddPoint(l16TempBuff^[lXxi-lXDim+1],1); AddPoint(l16TempBuff^[lXxi+lXDim+1],1); if lMinInten = lMaxInten then l16SrcBuff^[lXxi] := lMaxInten //no variability in data else begin l2 := 36 - lMinWt -lMaxWt; //weight after we exceed brightest and darkest lSum := lSum -(lMinWt*lMinInten) - (lMaxWt*lMaxInten); //exclude brightest/darkest l16SrcBuff^[lXxi] := round(lSum/l2); end; end; //forX end; //forY end; //forZ Freemem(l16TempBuff); //OptimizeSingle(nil); end else if lHdr.ImgBufferBPP = 1 then begin //8-bit data lSrcBuff := lHdr.ImgBuffer; GetMem(lTempBuff,lOutVolVox); Move(lSrcBuff^,lTempBuff^,lOutVolVox); fillchar(lSrcBuff^,lOutVolVox,0); //set edges to 0, as outside voxel is not smoothed for lZ := lZDim-1 downto 2 do begin ProgressBar1.Position := (lZDim-lZ); for lY := lYDim-1 downto 2 do begin lZyi := ((lZ-1)*lOutSliceSz) + ((lY-1) * lXDim); for lX := lXDim-1 downto 2 do begin lXxi := lZyi + lX; //next: gaussian mean after min/max values are excluded lSum := 0; lMinInten := lTempBuff^[lXxi]; lMaxInten := lTempBuff^[lXxi]; lMinWt := 12; lMaxWt := 12; AddPoint(lTempBuff^[lXxi],12);//quad-weight center AddPoint(lTempBuff^[lXxi-lOutSliceSz],2);//prev slice AddPoint(lTempBuff^[lXxi+lOutSliceSz],2);//next slices AddPoint(lTempBuff^[lXxi-1],2);//Left AddPoint(lTempBuff^[lXxi+1],2);//right AddPoint(lTempBuff^[lXxi-lXDim],2);//up AddPoint(lTempBuff^[lXxi+lXDim],2);//down AddPoint(lTempBuff^[lXxi-lOutSliceSz-1],1); AddPoint(lTempBuff^[lXxi-lOutSliceSz+1],1); AddPoint(lTempBuff^[lXxi-lOutSliceSz-lXDim],1); AddPoint(lTempBuff^[lXxi-lOutSliceSz+lXDim],1); AddPoint(lTempBuff^[lXxi+lOutSliceSz-1],1); AddPoint(lTempBuff^[lXxi+lOutSliceSz+1],1); AddPoint(lTempBuff^[lXxi+lOutSliceSz-lXDim],1); AddPoint(lTempBuff^[lXxi+lOutSliceSz+lXDim],1); AddPoint(lTempBuff^[lXxi-lXDim-1],1); AddPoint(lTempBuff^[lXxi+lXDim-1],1); AddPoint(lTempBuff^[lXxi-lXDim+1],1); AddPoint(lTempBuff^[lXxi+lXDim+1],1); if lMinInten = lMaxInten then lSrcBuff^[lXxi] := lMaxInten //no variability in data else begin l2 := 36 - lMinWt -lMaxWt; //weight after we exceed brightest and darkest lSum := lSum -(lMinWt*lMinInten) - (lMaxWt*lMaxInten); //exclude brightest/darkest lSrcBuff^[lXxi] := round(lSum/l2); end; end; //forX end; //forY end; //forZ Freemem(lTempBuff); end else begin //8bit data showmessage('Unknown bits per pixel '+inttostr(lHdr.ImgBufferBPP) ); end; ProgressBar1.Position := 0; RescaleImgIntensity(gBGImg,gMRIcroOverlay[kBGOverlayNum],kBGOverlayNum); RefreshImagesTimer.Enabled := true; end; //quicksmooth procedure TImgForm.VOImaskClick(Sender: TObject); var lPreserve: integer; lHdr,lMaskHdr: TMRicroHdr; lXDim,lYDim,lZDim,lOutVolVox,lOutSliceSz,lZ: integer; lSrcBuff,lMaskBuff: Bytep; l16SrcBuff: SmallIntP; l32SrcBuff: SingleP; begin lPreserve := (sender as TMenuItem).tag; lHdr := gMRIcroOverlay[kBGOverlayNum]; lMaskHdr := gMRIcroOverlay[kVOIOverlayNum]; lXDim := gBGImg.ScrnDim[1]; lYDim := gBGImg.ScrnDim[2]; lZDim := gBGImg.ScrnDim[3]; lOutSliceSz := gBGImg.ScrnDim[1] * gBGImg.ScrnDim[2]; lOutVolVox := lOutSliceSz * lZDim; if (lXDim < 2) or (lYDim < 2) or (lZDim < 2) then begin showmessage('Masking can only be applied to images with multiple slices in 3 dimensions.'); exit; end; if (lHdr.ImgBufferItems <> lMaskHdr.ScrnBufferItems) or (lHdr.ImgBufferItems < 8) then begin showmessage('Please first load both an image (File/Open) and a masking VOI (Draw/Open).'); exit; end; if gBGImg.Mirror then MirrorScrnBuffer(gBGImg,lMaskHdr);//4/2008 lMaskBuff := (lMaskHdr.ScrnBuffer); ProgressBar1.Min := 0; ProgressBar1.Max :=lZDim; StatusLabel.caption := 'Masking data'; if lHdr.ImgBufferBPP = 4 then begin //32-bit float data l32SrcBuff := SingleP(lHdr.ImgBuffer); if lPreserve = 1 then begin for lZ := 1 to lOutVolVox do if lMaskBuff^[lZ] = 0 then l32SrcBuff^[lZ] := 0; end else begin for lZ := 1 to lOutVolVox do if lMaskBuff^[lZ] <> 0 then l32SrcBuff^[lZ] := 0; end; //if preserve end else if (lHdr.ImgBufferBPP = 2) then begin //16-bit int data*) l16SrcBuff := SmallIntP(lHdr.ImgBuffer ); if lPreserve = 1 then begin for lZ := 1 to lOutVolVox do if lMaskBuff^[lZ] = 0 then l16SrcBuff^[lZ] := 0; end else begin for lZ := 1 to lOutVolVox do if lMaskBuff^[lZ] <> 0 then l16SrcBuff^[lZ] := 0; end; end else if lHdr.ImgBufferBPP = 1 then begin //8-bit data lSrcBuff := lHdr.ImgBuffer; if lPreserve = 1 then begin for lZ := 1 to lOutVolVox do if lMaskBuff^[lZ] = 0 then lSrcBuff^[lZ] := 0 end else begin for lZ := 1 to lOutVolVox do if lMaskBuff^[lZ] <> 0 then lSrcBuff^[lZ] := 0; end; end else begin //8bit data showmessage('Unknown bits per pixel '+inttostr(lHdr.ImgBufferBPP) ); end; if gBGImg.Mirror then MirrorScrnBuffer(gBGImg,lMaskHdr);//4/2008 ProgressBar1.Position := 0; RescaleImgIntensity(gBGImg,gMRIcroOverlay[kBGOverlayNum],kBGOverlayNum); RefreshImagesTimer.Enabled := true; end; //VOImaskClick procedure TImgForm.Sagittal1Click(Sender: TObject); begin gBGImg.SliceView := (Sender as TMenuItem).Tag; RefreshImagesTimer.Enabled := true; end; procedure TImgForm.ROIcomparisonClick(Sender: TObject); var lComparison,lVolItems,lOverlay,lnOverlays,lPos: integer; begin lComparison := (Sender as TMenuItem).tag; //0=intersect AND,1=union OR ,2=mask lVolItems := gBGImg.ScrnDim[1]*gBGImg.ScrnDim[2]* gBGImg.ScrnDim[3]; if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems <> lVolItems) or (gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems <> lVolItems) then begin Showmessage('VOI comparisons require a VOI loaded onto a background image (Draw/Open).'); exit; end; lnOverlays := 0; for lOverlay := 1 to knMaxOverlay do if gMRIcroOverlay[lOverlay].ScrnBufferItems = lVolItems then inc(lnOverlays); if (lnOverlays = 0) then begin Showmessage('VOI comparisons require loaded overlays (Overlay/Add).'); exit; end; CreateUndoVol; if lComparison = 0 then begin //intersect AND for lOverlay := 1 to (knMaxOverlay-1) do begin if gMRIcroOverlay[lOverlay].ScrnBufferItems = lVolItems then begin for lPos := 1 to lVolItems do if gMRIcroOverlay[lOverlay].ScrnBuffer^[lPos] = 0 then gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lPos] := 0; end; //if overlay loaded end; //for each overlay end else if lComparison = 1 then begin //if intersect else UNION OR for lOverlay := 1 to (knMaxOverlay-1) do begin if gMRIcroOverlay[lOverlay].ScrnBufferItems = lVolItems then begin for lPos := 1 to lVolItems do if gMRIcroOverlay[lOverlay].ScrnBuffer^[lPos] > 0 then gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lPos] := kVOI8bit; end; //if overlay loaded end; //for each overlay end else if lComparison = 2 then begin //if union else MASK for lOverlay := 1 to (knMaxOverlay-1) do begin if gMRIcroOverlay[lOverlay].ScrnBufferItems = lVolItems then begin for lPos := 1 to lVolItems do if gMRIcroOverlay[lOverlay].ScrnBuffer^[lPos] > 0 then gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lPos] := 0; end; //if overlay loaded end; //for each overlay end; //if ..else MASK RefreshImagesTimer.Enabled := true; end; //ROIcomparisonClick procedure TImgForm.RescaleImagesTimerTimer(Sender: TObject); var lLayer: integer; begin lLayer := ActiveLayer; RescaleImagesTimer.Enabled := false; RescaleImgIntensity(gBGImg,gMRIcroOverlay[lLayer],lLayer); RefreshImages; end; procedure TImgForm.Fill3DBtnClick(Sender: TObject); begin AutoROIForm.Show; end; procedure TImgForm.SmoothVOI1Click(Sender: TObject); begin voismoothform.showmodal; //SmoothVOIForm.Showmodal end; procedure TImgForm.CreateOverlap(Sender: TObject); var lNumberofFiles,lC,lOverlay,lPos: integer; lFilename,lExt: string; lOverlapBuffer: ByteP; begin if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1 then begin showmessage('Please load a background image (''File''/''Open'') before adding an overlay.'); exit; end; lOverlay := 0; for lC := 1 to (knMaxOverlay-1) do //-1: save final overlay for VOI if (lOverlay = 0) and (gMRIcroOverlay[lC].ImgBufferItems = 0) then lOverlay := lC; if lOverlay = 0 then begin showmessage('Unable to add an overlay. You have loaded the maximum number of overlays.'); exit; end; if not OpenDialogExecute(kVOIFilter,'Select VOIs you wish to combine',true) then exit; lNumberofFiles:= HdrForm.OpenHdrDlg.Files.Count; if lNumberofFiles < 2 then begin Showmessage('Error: This function is designed to overlay MULTIPLE images. You selected less than two images.'); exit; end; ProgressBar1.Min := 0; ProgressBar1.Max :=lNumberofFiles; ProgressBar1.Position := 0; getmem(lOverlapBuffer,gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems); fillchar(lOverlapBuffer^,gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems,0); for lC:= 1 to lNumberofFiles do begin lFilename := HdrForm.OpenHdrDlg.Files[lC-1]; lExt := UpCaseExt(lFileName); gBGImg.VOIchanged := false; if not HdrForm.OpenAndDisplayHdr(lFilename,gMRIcroOverlay[lOverlay]) then exit; if not OpenImg(gBGImg,gMRIcroOverlay[lOverlay],false,false,false,gBGImg.ResliceOnLoad,false) then exit; ProgressBar1.Position := lC; for lPos := 1 to gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems do if gMRIcroOverlay[lOverlay].ScrnBuffer^[lPos] > 0 then lOverlapBuffer^[lPos] := lOverlapBuffer^[lPos]+1; FreeImgMemory(gMRIcroOverlay[lOverlay]); end; //for each image //July07 getmem for unaligned buffer getmem(gMRIcroOverlay[lOverlay].ImgBuffer,gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems); GetMem(gMRIcroOverlay[lOverlay].ImgBufferUnaligned ,gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems + 16); //July072007 //gMRIcroOverlay[lOverlay].ImgBuffer := ByteP($fffffff0 and (integer(gMRIcroOverlay[lOverlay].ImgBufferUnaligned)+15)); gMRIcroOverlay[lOverlay].ImgBuffer := system.align(gMRIcroOverlay[lOverlay].ImgBufferUnaligned, 16); gMRIcroOverlay[lOverlay].ImgBufferItems := gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems; for lPos := 1 to gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems do gMRIcroOverlay[lOverlay].ImgBuffer[lPos] := lOverlapBuffer[lPos]; freemem(lOverlapBuffer); MakeStatHdr (gMRIcroOverlay[kBGOverlayNum],gMRIcroOverlay[lOverlay],0, lNumberofFiles,1,0,0,kNIFTI_INTENT_ESTIMATE,'N'+inttostr(lNumberofFiles) ); UpdateLayerMenu; RescaleImgIntensity(gBGImg,gMRIcroOverlay[lOverlay],lOverlay); ProgressBar1.Position := 0; //SaveAsVOIorNIFTI(gMRIcroOverlay[lOverlay].ImgBuffer,gMRIcroOverlay[lOverlay].ScrnBufferItems,1,false,gMRIcroOverlay[lOverlay].niftiHdr,'sum'+inttostr(lNumberofFiles)); SaveAsVOIorNIFTI(gMRIcroOverlay[lOverlay].ImgBuffer,gMRIcroOverlay[lOverlay].ScrnBufferItems,1,1,false,gMRIcroOverlay[lOverlay].niftiHdr,'sum'+inttostr(lNumberofFiles)); RefreshImagesTimer.Enabled := true; end;//proc CreateOverlap procedure TImgForm.Chisquare1Click(Sender: TObject); var lNegativeNumbers: boolean; lVolVoxels,lPos,lnTotalThreshold,lLoop,lnVoxelsTested:integer; lMinExp,lChi,lChip,luChi, luChiP: double; lMaxChi,lMinChi: single; lBufferAligned,lBufferUnAligned,lBuffer: ByteP; l32Buf : SingleP; lFilename: string; lTotal,lYes,lNo: array [1..2] of integer; lMRIcroHdr: TMRIcroHdr; begin lVolVoxels := gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems; if lVolVoxels < 1 then begin showmessage('Please load a background image (''File''/''Open'') before adding an overlay.'); exit; end; CloseOverlayImgClick(nil); for lLoop := 1 to 2 do begin //open two images if lLoop = 1 then begin if not OpenDialogExecute(kImgFilter,'Select POSITIVE overlap image',false) then exit end else begin if not OpenDialogExecute(kImgFilter,'Select NEGATIVE overlap image',false) then exit; end; lFilename := HdrForm.OpenHdrDlg.Filename; if not HdrForm.OpenAndDisplayHdr(lFilename,gMRIcroOverlay[lLoop]) then exit; if not OpenImg(gBGImg,gMRIcroOverlay[lLoop],false,false,true,gBGImg.ResliceOnLoad,false) then exit; lTotal[lLoop] := round(gMRIcroOverlay[lLoop].NIFTIhdr.glmax); if (gMRIcroOverlay[lLoop].NIFTIhdr.intent_code <> kNIFTI_INTENT_ESTIMATE) then showmessage('Warning: header intent_code is not set to ESTIMATE. Compute Chi-squared only with cumulative maps created with this program.'); if (gMRIcroOverlay[lLoop].NIFTIhdr.intent_name[1] <> 'N') then showmessage('Warning: header intention not N. Compute Chi-squared only with cumulative maps created with this program.'); UpdateLayerMenu; RefreshImagesTimer.Enabled := true; end; if (lVolVoxels<> gMRIcroOverlay[1].ScrnBufferItems) or (lVolVoxels<> gMRIcroOverlay[2].ScrnBufferItems) then begin showmessage('Error loading images.'); exit; end; //next - chi squared lnTotalThreshold:= ReadIntForm.GetInt('Only test voxels damaged in at least N patients [A+B]', 1,1,(lTotal[1]+lTotal[2])); GetMem(lBufferUnaligned ,(lVolVoxels *sizeof(single) )+16); //lBufferAligned := ByteP($fffffff0 and (integer(lBufferUnaligned)+15)); lBufferAligned := system.align(lBufferUnaligned, 16); l32Buf := SingleP(lBufferAligned); lnVoxelsTested := 0; lNegativeNumbers := false; lMaxChi := 0; lMinChi := 0; for lPos := 1 to lVolVoxels do begin l32Buf^[lPos] := 0; lYes[1] := gMRIcroOverlay[1].ScrnBuffer^[lPos]; lNo[1] := lTotal[1]-lYes[1]; lYes[2] := gMRIcroOverlay[2].ScrnBuffer^[lPos]; lNo[2] := lTotal[2]-lYes[2]; if (lYes[1] < 0) or (lNo[1] < 0) or (lYes[2] < 0) or (lNo[2] < 0) then lNegativeNumbers := true else if (lYes[1]+lYes[2]) >= lnTotalThreshold then begin//e.g. at least 30% of all patients inc(lnVoxelsTested); //showmessage(inttostr(lYes[1])+'x'+inttostr(lNo[1])+'x'+ inttostr(lYes[2])+'x'+inttostr(lNo[2]) ); Chi2x2 (lYes[1], lNo[1], lYes[2], lNo[2],lMinExp,lChi,lChip,luChi, luChiP); if (luChi) > lMaxChi then lMaxChi := (luChi) else if (luChi < lMinChi) then lMinChi := luChi; if (lYes[1]/lTotal[1]) > (lYes[2]/lTotal[2]) then l32Buf^[lPos] := luChi//100-(100*luChip) //positives more likely than negative else l32Buf^[lPos] := -luChi;//-100+(100*luChip); //negatives more common end;//> threshold end; //for each voxel MakeStatHdr (gMRIcroOverlay[kBGOverlayNum],lMRIcroHdr,lMinChi, lMaxChi,1{df},0,lnVoxelsTested,kNIFTI_INTENT_CHISQ,inttostr(lnVoxelsTested) ); if lNegativeNumbers then Showmessage('Serious error: some group sizes were negative. This should be impossible with a Chi-Squared.'); //SaveAsVOIorNIFTI(lBufferAligned,lVolVoxels,4,false,lMRIcroHdr.NiftiHdr,'chi'+inttostr(lnTotalThreshold)); SaveAsVOIorNIFTI(lBufferAligned,lVolVoxels,4,1,false,lMRIcroHdr.NiftiHdr,'log10p'+inttostr(lnTotalThreshold)); //next - save log10 p values... MakeStatHdr (gMRIcroOverlay[kBGOverlayNum],lMRIcroHdr,lMinChi, lMaxChi,1{df},0,lnVoxelsTested,NIFTI_INTENT_LOG10PVAL,inttostr(lnVoxelsTested) ); for lPos := 1 to lVolVoxels do if l32Buf^[lPos] > 0 then l32Buf^[lPos] := -log(abs(gammq(0.5, 0.5 * l32Buf^[lPos])),10) else l32Buf^[lPos] :=0; SaveAsVOIorNIFTI(lBufferAligned,lVolVoxels,4,1,false,lMRIcroHdr.NiftiHdr,'log10p'+inttostr(lnTotalThreshold)); //next - free float buffer FreeMem(lBufferUnaligned); StatusLabel.Caption := 'Voxels tested: '+inttostr(lnVoxelsTested); //next - subtraction GetMem(lBuffer ,(lVolVoxels )); lNegativeNumbers := false; fillchar(lBuffer^,lVolVoxels,100); for lPos := 1 to lVolVoxels do begin lYes[1] := gMRIcroOverlay[1].ScrnBuffer^[lPos]; lNo[1] := lTotal[1]-lYes[1]; lYes[2] := gMRIcroOverlay[2].ScrnBuffer^[lPos]; lNo[2] := lTotal[2]-lYes[2]; if (lYes[1] < 0) or (lNo[1] < 0) or (lYes[2] < 0) or (lNo[2] < 0) then lNegativeNumbers := true else if (lYes[1] >0) or (lYes[2] > 0) then begin lBuffer^[lPos] := round((100* ((lYes[1]/lTotal[1])-(lYes[2]/lTotal[2])))+100); end;//> threshold end; //for each voxel MakeStatHdr (gMRIcroOverlay[kBGOverlayNum],lMRIcroHdr,-100, 100,1,0,0,kNIFTI_INTENT_ESTIMATE,'%'+inttostr(lTotal[1])+':'+inttostr(lTotal[2]) ); lMRIcroHdr.NIFTIhdr.scl_inter:= -100; if lNegativeNumbers then Showmessage('Serious error: some group sizes were negative. This should be impossible with a subtraction analysis.'); SaveAsVOIorNIFTI(lBuffer,lVolVoxels,1,1,false,lMRIcroHdr.NiftiHdr,'Sub'+inttostr(lTotal[1])+'_'+inttostr(lTotal[2])); FreeMem(lBuffer); end; //procedure Chisquare1Click procedure Paris(lFilename: string); begin ImgForm.CloseImagesClick(nil); ImgForm.OpenAndDisplayImg(lFilename,True); ImgForm.caption := 'x'; //if not HdrForm.OpenAndDisplayHdr(lFilename,gMRIcroOverlay[kBGOverlayNum]) then exit; ImgForm.Caption := 'y'; end; procedure Normandy; begin gBGImg.Prompt4DVolume := false; gBGImg.Resliced :=true; paris('/Users/rorden/downloads/fx/DBM8768/DBM8768_DIFFUSION AX PRE PERFUSION.nii.gz'); gBGImg.Prompt4DVolume := true; end; procedure TImgForm.ROIVOI1Click(Sender: TObject); var lNumberofFiles,lC: integer; lFilename: string; begin Normandy; exit; if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1 then begin showmessage('Please load a background image (''File''/''Open'') before adding an overlay.'); exit; end; if gBGImg.Resliced then begin if not HdrForm.OpenAndDisplayHdr(gMRIcroOverlay[kBGOverlayNum].HdrFileName,gMRIcroOverlay[kBGOverlayNum]) then exit; if not OpenImg(gBGImg,gMRIcroOverlay[0],true,false,false,false,false) then exit; end; showmessage('Warning: the currently open background image must have the dimensions (size, space between slices, etc) as the image used when creating the ROIs.'); if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems > 0 then CloseVOIClick(nil); if not OpenDialogExecute('MRIcro ROI (.roi)|*.roi','Select MRIcro format ROIs to convert',true) then exit; lNumberofFiles:= HdrForm.OpenHdrDlg.Files.Count; ProgressBar1.Min := 0; ProgressBar1.Max :=lNumberofFiles; ProgressBar1.Position := 0; for lC:= 1 to lNumberofFiles do begin lFilename := HdrForm.OpenHdrDlg.Files[lC-1]; OpenMRIcroROI (lFileName); lFilename := changefileextX(lFilename,'.voi'); SaveAsVOIorNIFTIcore (lFilename, gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer,gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems, 1,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr); CloseVOIClick(nil); ProgressBar1.Position := lC; end; ProgressBar1.Position := 0; end; procedure TImgForm.LUTinvertBtnClick(Sender: TObject); begin end; //proc LUTdropSelect procedure TImgForm.LutFromZeroBtnClick(Sender: TObject); var lLayer: integer; begin lLayer := ActiveLayer; gMRIcroOverlay[lLayer].LUTfromZero := LUTfromZeroBtn.down; LUTdropLoad(lLayer); RescaleImagesTimer.Enabled := true; end; procedure TImgForm.ShowMultisliceClick(Sender: TObject); begin (* if gBGImg.XBarClr = TColor(gMRIcroOverlay[kBGOverlayNum].LUTinvisible) then MultiSliceForm.MultiImage.canvas.font.Color := clBlack//clWhite;//gLUT[lClr].rgbRed+(gLUT[lClr].rgbGreen shl 8)+(gLUT[lClr].rgbBlue shl 16); else MultiSliceForm.MultiImage.canvas.font.Color := gBGImg.XBarClr;*) MultiSliceForm.Show; //MultiSliceForm.BringToFront; end; function RawBGIntensity(lPos: integer): single; var l16Buf : SmallIntP; l32Buf : SingleP; begin result := 0; if (lPos > gMRIcroOverlay[kBGOverlayNum].ImgBufferItems) or (lPos < 1) then exit; if (gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP = 4) then begin l32Buf := SingleP(gMRIcroOverlay[kBGOverlayNum].ImgBuffer ); result := l32Buf^[lPos]; end else if (gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP = 2) then begin l16Buf := SmallIntP(gMRIcroOverlay[kBGOverlayNum].ImgBuffer ); result := l16Buf^[lPos]; end else if gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP = 1 then result := gMRIcroOverlay[kBGOverlayNum].ImgBuffer^[lPos] else begin showmessage('Unknown Background Buffer Bytes Per Pixel'); exit; end; end; (*procedure DescribeVOIonLabelsX (lOverlayNum: integer); var lShowfilename: boolean = true; lLocalMax,lLocalSum : HistoDoubleRA; l16Buf : SmallIntP; l32Buf : SingleP; l8Buf: byteP; lInten: double; lXmm,lYmm,lZmm: single; lHisto,lRegionVol,lLocalMaxPos: HistoRA; lInc,lRegion: Integer; lLabelStr: string; lVOI: boolean; lLabelStr20 : Array[0..kHistoBins] of kstr20; begin lInten := 0;//just to hide compiler hint... if (gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP = 2) and ('ratlas.nii.gz' = (extractfilename( gMRIcroOverlay[kBGOverlayNum].HdrFileName))) then begin //DescribeVOIonLabelsRAT(lOverlayNum,lShowFilename); Showmessage('Please use Windows version.'); exit; end; if (gMRIcroOverlay[lOverlayNum].ScrnBufferItems <> gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems) or (gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP <> 1) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 2) then exit; TextForm.MemoT.Lines.add(' Custom Region Analysis'); TextForm.MemoT.Lines.add(' For Speculative Brodmann Map: 0=not cortical and 48=no Brodmann label'); lVOI := IsVOIROIExt(gMRIcroOverlay[lOverlayNum].HdrFileName); if (not lVOI) and (lOverlayNum = kVOIOverlayNum) then lVOI := true; //next describe format if lShowfilename then lLabelStr := ' Filename,' else lLabelStr := ' '; if lVOI then //intensity min/max position are not important TextForm.MemoT.Lines.add(lLabelStr+'Area'+kTextSep+'N>0'+kTextSep+'%N>0') else TextForm.MemoT.Lines.add(lLabelStr+'Area'+kTextSep+'N>0'+kTextSep+'%N>0'+kTextSep+'Sum>0'+kTextSep+'Mean>0'+kTextSep+'Max'+kTextSep+'MaxX'+kTextSep+'MaxY'+kTextSep+'MaxZ'); //next initialize if lShowFilename then lLabelStr := gMRIcroOverlay[lOverlayNum].HdrFileName+',' else lLabelStr := ''; for lInc := 0 to kHistoBins do begin lHisto[lInc] := 0; lLocalMax[lInc] := 0; lLocalSum[lInc] := 0; lRegionVol[lInc] := 0; if (gMRIcroOverlay[kBGOverlayNum].UsesLabels) then lLabelStr20[lInc] := gBGImg.LabelRA[lInc]// gBGImg.LabelStr20[lInc] else lLabelStr20[lInc] := inttostr(lInc); end; for lInc := 1 to gMRIcroOverlay[lOverlayNum].ScrnBufferItems do if gMRIcroOverlay[lOverlayNum].ScrnBuffer^[lInc] > 0 then inc(lHisto[gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lInc]]); //local max start l32Buf := SingleP(gMRIcroOverlay[lOverlayNum].ImgBuffer ); l16Buf := SmallIntP(gMRIcroOverlay[lOverlayNum].ImgBuffer ); //NEXT if..else July07 - ROIs only use screen buffer, not imgbuffer... if gMRIcroOverlay[lOverlayNum].ScrnBufferItems = gMRIcroOverlay[lOverlayNum].ImgBufferItems then l8Buf := gMRIcroOverlay[lOverlayNum].ImgBuffer else l8Buf := gMRIcroOverlay[lOverlayNum].ScrnBuffer; for lInc := 1 to gMRIcroOverlay[lOverlayNum].ScrnBufferItems do begin if (gMRIcroOverlay[lOverlayNum].ImgBufferBPP = 4) then lInten := l32Buf^[lInc] else if (gMRIcroOverlay[lOverlayNum].ImgBufferBPP = 2) then lInten := l16Buf^[lInc] else if gMRIcroOverlay[lOverlayNum].ImgBufferBPP = 1 then lInten := l8Buf^[lInc];//July07 lRegion := gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lInc]; if lInten > 0 then lLocalSum[lRegion] := lLocalSum[lRegion]+lInten; if lInten > lLocalMax[lRegion] then begin lLocalMax[lRegion] := lInten;//intensity lLocalMaxPos[lRegion] := lInc;//location end; inc(lRegionVol[lRegion]); end; for lInc := 0 to kHistoBins do begin if (not lVOI) and (lLocalMax[lInc] > 0) then begin lLocalMax[lInc] := Raw2ScaledIntensity (gMRIcroOverlay[lOverlayNum],lLocalMax[lInc]); lLocalSum[lInc] := Raw2ScaledIntensity (gMRIcroOverlay[lOverlayNum],lLocalSum[lInc]); ImgPosToMM(lLocalMaxPos[lInc], lXmm,lYmm,lZmm); TextForm.MemoT.Lines.Add(lLabelStr+ lLabelStr20[lInc] +kTextSep+ inttostr(lHisto[lInc])+kTextSep+floattostr( lHisto[lInc]/lRegionVol[lInc]) +kTextSep+floattostr( lLocalSum[lInc])+kTextSep+floattostr( lLocalSum[lInc]/lRegionVol[lInc]) //Sum>0, mean>0 +kTextSep + floattostr(lLocalMax[lInc])+kTextSep+floattostr(lXmm)+kTextSep+floattostr(lYmm)+kTextSep+floattostr(lZmm) ); end else if (lHisto[lInc] > 0) {necessarily also and (lRegionVol[lInc] > 0)} then TextForm.MemoT.Lines.Add(gBGImg.LabelRA[lInc] + kTextSep+ inttostr(lHisto[lInc])+kTextSep+floattostr( lHisto[lInc]/lRegionVol[lInc])) ; end; //for each row end; 2014: no longer used (16 bit LabelRA)*) function Mode (lOverlayNum: integer): double; const kBins = 4095; var lInc,lS,lMaxI: integer; lV,lMin,lMax,lScale: single; lRA: LongIntP0; begin result := nan; //error if (gMRIcroOverlay[lOverlayNum].ScrnBufferItems <> gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems ) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1)then exit; lMin := RawBGIntensity(1); lMax := lMin; for lInc := 1 to gMRIcroOverlay[lOverlayNum].ScrnBufferItems do begin if gMRIcroOverlay[lOverlayNum].ScrnBuffer^[lInc] > 0 then begin lV := RawBGIntensity(lInc); if lV < lMin then lMin := lV; if lV > lMax then lMax := lV; end; //if VOI voxel end; //for each voxel if lMin = lMax then begin //no variability result := Raw2ScaledIntensity(gMRIcroOverlay[kBGOverlayNum],lMin); exit; end; lScale := kBins/(lMax-lMin); getmem(lRA,(kBins+1) * sizeof(longint) ); //0..kBins for lInc := 0 to kBins do lRA^[lInc] := 0; for lInc := 1 to gMRIcroOverlay[lOverlayNum].ScrnBufferItems do begin if gMRIcroOverlay[lOverlayNum].ScrnBuffer^[lInc] > 0 then begin lV := RawBGIntensity(lInc); lS := round((lV-lMin)*lScale); inc(lRA^[lS]); end; //if VOI voxel end; //for each voxel lMaxI := 0; for lInc := 1 to kBins do if lRA^[lInc] > lRA^[lMaxI] then lMaxI := lInc; result := lMin+ (lMaxI/kBins * (lMax-lMin)); result := Raw2ScaledIntensity(gMRIcroOverlay[kBGOverlayNum],result); freemem(lRA); end; procedure TImgForm.DescriptiveMenuItemClick(Sender: TObject); var lROIVol: array [1..3] of integer; lInc,lOverlayNum,lImgSz: integer; lCenterOfMass,lROISum,lROISumSqr,lROImin,lROImax:array [1..3] of double; lMode,lCC,lVal,lSD,lROImean: double; lStr: string; procedure AddVal( lRA: integer); begin inc(lROIVol[lRA]); lROISum[lRA] := lROISum[lRA]+lVal; lROISumSqr[lRA] := lROISumSqr[lRA] + sqr(lVal); if lVal > lROImax[lRA] then lROImax[lRA] := lVal; if lVal < lROImin[lRA] then lROImin[lRA] := lVal; end; begin lImgSz := 0; for lOverlayNum := 1 to knMaxOverlay do if gMRIcroOverlay[lOverlayNum].ScrnBufferItems > lImgSz then lImgSz := gMRIcroOverlay[lOverlayNum].ScrnBufferItems; if (lImgSz < 1) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < lImgSz) then begin Showmessage('You need to create or load an overlay (Overlay/Open or Draw/OpenVOI) to get overlay statistics.'); exit; end; TextForm.MemoT.Lines.Clear; for lOverlayNum := 1 to knMaxOverlay do begin if gMRIcroOverlay[lOverlayNum].ScrnBufferItems = gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems then begin for lInc := 1 to 3 do begin lROIVol[lInc] := 0; lROISum[lInc] := 0; lROISumSqr[lInc] := 0; lROImin[lInc] := maxint; lROImax[lInc] := -maxint; end; for lInc := 1 to gMRIcroOverlay[lOverlayNum].ScrnBufferItems do begin if gMRIcroOverlay[lOverlayNum].ScrnBuffer^[lInc] > 0 then begin lVal := RawBGIntensity(lInc); AddVal(1); if lVal <> 0 then AddVal(2); if lVal > 0 then AddVal(3); end; //if VOI voxel end; //for each voxel //next - compute StDev //compute descriptives for each set of values TextForm.MemoT.Lines.Add('Overlay '+gMRIcroOverlay[lOverlayNum].HdrFileName); if CenterOfMass (lOverlayNum, lCenterOfMass[1],lCenterOfMass[2],lCenterOfMass[3]) > 0 then TextForm.MemoT.Lines.Add(' Center of mass XYZ '+RealToStr(lCenterOfMass[1],2)+'x'+RealToStr(lCenterOfMass[2],2)+'x'+RealToStr(lCenterOfMass[3],2)); for lInc := 1 to 3 do begin if lROIVol[lInc] > 1 then begin lSD := (lROISumSqr[lInc] - ((Sqr(lROISum[lInc]))/lROIVol[lInc])); if (lSD > 0) then lSD := Sqrt ( lSD/(lROIVol[lInc]-1)) else lSD := 0; end else lSD := 0; //next compute mean if lROIVol[lInc] > 0 then lROImean := lROISum[lInc]/lROIVol[lInc] else lROImean := 0; //next - calibrate values lROImin[lInc] := Raw2ScaledIntensity (gMRIcroOverlay[kBGOverlayNum],lROImin[lInc]); lROIMean := Raw2ScaledIntensity (gMRIcroOverlay[kBGOverlayNum],lROIMean); lROImax[lInc] := Raw2ScaledIntensity (gMRIcroOverlay[kBGOverlayNum],lROImax[lInc]); lSD := Raw2ScaledIntensity (gMRIcroOverlay[kBGOverlayNum],lSD); lcc := ((lROIVol[lInc]/1000)*gBGImg.ScrnMM[1]*gBGImg.ScrnMM[2]*gBGImg.ScrnMM[3]); case lInc of 3: lStr := 'VOI >0 '; 2: lStr := 'VOI <>0 '; else lStr := 'VOI '; end; lStr := lStr+' nvox(cc)=min/mean/max=SD: '+inttostr(round(lROIVol[lInc]))+kTextSep+RealToStr(lCC,2)+kTextSep+'='+RealToStr(lROIMin[lInc],4)+kTextSep+realToStr(lROIMean,4)+kTextSep+realToStr(lROIMax[lInc],4)+kTextSep+'='+kTextSep+realtostr(lSD,4); TextForm.MemoT.Lines.Add(lStr); end; lMode := Mode(lOverlayNum); if lMode <> NaN then TextForm.MemoT.Lines.Add('Mode:'+kTextSep+floattostr(lMode)); if gMRIcroOverlay[kBGOverlayNum].UsesLabels then DescribeVOIonLabels(lOverlayNum,false); TextForm.MemoT.Lines.Add(''); end; //overlaynum loaded end; //for each overlay TextForm.Show; end; procedure TImgForm.FormResize(Sender: TObject); begin if not ImgForm.visible then exit; RefreshImagesTimer.enabled := true; end; function ParamStrFilename (var lParamPos: integer): string; var I: integer; lStr: string; begin result := ''; if (ParamCount < lParamPos) then exit; I := lParamPos; repeat if I = lParamPos then lStr := ParamStr(I) else lStr := lStr +' '+ ParamStr(I); inc(I); until (I>ParamCount) or (fileexistsex(lStr)); lParamPos := I; if fileexistsex(lStr) then result := lStr; end; procedure TImgForm.OnLaunch; var lStr: String; lMaximize,lRender,lMultislice : boolean; lCommandChar: Char; I,lError,lOverlayNum,lInc,lLUT: integer; lSingle: single; procedure ReadCmdVal;//nested begin inc(I); lStr := ParamStr(I); {$IFNDEF FPC} lStr := string(StrUpper(PChar(lStr))) ; {$ELSE} {$IFNDEF UNIX} lStr := UpCase(lStr); //unix file names are case specific /EXAMPLE/ATTENTION.NII <> /Example/Attention {$ENDIF} {$ENDIF} end; //nested ReadCmdVal begin {$IFDEF Darwin} //Darwin starts passing a strange paramstr.... //with Darwin, opening a file can interfere with opening by association... exit; //ResliceImg ('/Users/crlab/Documents/example_func.nii.gz','/Users/crlab/Documents/v1x.voi','/Users/crlab/Documents/example_func2standard.mat','/Users/crlab/Documents/z1x.nii.gz'); {$ENDIF} if (ParamCount < 1) then begin ImgForm.OpenTemplateMRU(nil); RefreshImagesTimer.enabled := true; exit; end; lMaximize := false; lRender := false; lMultislice := false; lOverlayNum := 0; I := 1; lStr := ParamStrFilename(I); if lStr <> '' then OpenAndDisplayImg(lStr,True) else begin //no requested image OpenTemplateMRU(nil); I := 1;//exit; end; I := I-1; //ShowMultisliceClick(nil); if I >= ParamCount then exit; gBGIMg.SaveDefaultIni := false; //do not store changes loaded by script repeat lStr := ''; repeat inc(I); if I = 1 then lStr := ParamStr(I) else begin if lStr <> '' then lStr := lStr +' '+ ParamStr(I) else lStr := ParamStr(I); end; if (length(lStr)>1) and (lStr[1] = '-') then begin //special command lCommandChar := UpCase(lStr[2]); case lCommandChar of 'B': begin //background transparency ReadCmdVal; Val(lStr,lSingle,lError); if lError = 0 then gBGImg.BGTransPct := round(lSingle); SetSubmenuWithTag(BGTransPctMenu, gBGImg.BGTransPct); end; 'C': begin //color look up table ReadCmdVal; if (Length(lStr)>1) then begin if lStr[1] = '-' then begin //LUT index number Val(lStr,lSingle,lError); if lError = 0 then lLUT := abs(round(lSingle)) else lLUT := -1; end else begin lStr := ParseFileName(ExtractFileName(lStr)); {$IFDEF UNIX} lStr := UpCase(lStr); {$ENDIF} lLUT := -1; for lInc := 1 to (LUTdrop.Items.Count-1) do if lStr = string(StrUpper(PChar(LUTdrop.Items.Strings[lINc]))) then lLUT := lInc; end; //else text LUTname if lLUT >= 0 then begin gMRIcroOverlay[lOverlayNum].LUTindex := lLUT; LUTdropLoad(lOverlayNum); end; end; //str length > 1 end; 'D': gBGIMg.SaveDefaultIni := true; 'F': gBGImg.ResliceOnLoad := false; //turn off reslicing... loads files flat 'H': begin ReadCmdVal; Val(lStr,lSingle,lError); if lError = 0 then gMRIcroOverlay[lOverlayNum].WindowScaledMax := (lSingle); end; 'L': begin //Low intensity scale ReadCmdVal; Val(lStr,lSingle,lError); if lError = 0 then gMRIcroOverlay[lOverlayNum].WindowScaledMin := (lSingle); end; 'M': begin //multislice lMultislice := true; ReadCmdVal; if (lStr <> '') and (lStr <> '-')and (FileexistsEx(lStr)) and (lOverlayNum < (knMaxOverlay-1)) then gMultiSliceStartupFilename := (lStr); end; //if 'M' 'O': begin//Overlay ReadCmdVal; //Showmessage('o'+lStr); if (lStr <> '') and (FileexistsEx(lStr)) and (lOverlayNum < (knMaxOverlay-1)) then begin //Showmessage('oexists'+lStr); inc(lOverlayNum); OverlayOpenCore (lStr,lOverlayNum); end; end; //if 'O' 'R': begin//Overlay lRender := true;//Render ReadCmdVal; if (lStr <> '') and (lStr <> '-')and (FileexistsEx(lStr)) and (lOverlayNum < (knMaxOverlay-1)) then gRenderStartupFilename := (lStr); end; //if 'R' 'S': begin //smooth ReadCmdVal; Val(lStr,lSingle,lError); if lError = 0 then begin if odd(round(lSingle)) then begin gBGImg.StretchQuality := sqHigh; Menu2DSmooth.checked := true; end else begin gBGImg.StretchQuality := sqLow; Menu2DSmooth.checked := false; end; if lSingle > 1 then gBGIMg.OverlaySmooth := true else gBGIMg.OverlaySmooth := false; OverlaySmoothMenu.Checked := gBGIMg.OverlaySmooth; end;//error=0 end; 'T': begin //overlay transparency ReadCmdVal; Val(lStr,lSingle,lError); if lError = 0 then gBGImg.OverlayTransPct := round(lSingle); SetSubmenuWithTag(OverlayTransPctMenu, gBGImg.OverlayTransPct); end; 'V': begin //open voi ReadCmdVal; if (lStr <> '') and (FileexistsEx(lStr)) then OpenVOICore(lStr); end; 'X': lMaximize := true; //open maximized 'Z': gMRIcroOverlay[lOverlayNum].LUTfromZero := true; end; //case lStr[2] lStr := ''; end; //special command until (I=ParamCount) or (fileexists(lStr)) {or (gAbort)}; until I >= ParamCount; LayerDropSelect(nil); for lInc := 0 to lOverlayNum do RescaleImgIntensity(gBGImg,gMRIcroOverlay[lInc],lINc); RefreshImages; if lMultiSlice then ShowMultisliceClick(nil); if lRender then ShowRenderClick(nil); if lMaximize then begin ImgForm.WindowState := wsMaximized; RefreshImagesTimer.enabled := true; end; end; procedure TImgForm.FormShow(Sender: TObject); var lStr: String; lMaximize,lRender,lMultislice : boolean; lCommandChar: Char; I,lError,lOverlayNum,lInc,lLUT: integer; lSingle: single; procedure ReadCmdVal;//nested begin inc(I); lStr := ParamStr(I); {$IFNDEF FPC} lStr := string(StrUpper(PChar(lStr))) ; {$ELSE} {$IFNDEF UNIX} lStr := UpCase(lStr); //unix file names are case specific /EXAMPLE/ATTENTION.NII <> /Example/Attention {$ENDIF} {$ENDIF} end; //nested ReadCmdVal begin {$IFDEF Darwin} //Darwin starts passing a strange paramstr.... //with Darwin, opening a file can interfere with opening by association... (*lStr := '/Users/rorden/desktop/mricrox/templates/aal.nii.gz'; ImgForm.OpenAndDisplayImg(lStr,True); lStr := '/Users/rorden/desktop/mricrox/templates/crap.voi'; LoadOverlayIncludingRGB{LoadOverlay}(lStr); *) exit; //ResliceImg ('/Users/crlab/Documents/example_func.nii.gz','/Users/crlab/Documents/v1x.voi','/Users/crlab/Documents/example_func2standard.mat','/Users/crlab/Documents/z1x.nii.gz'); {$ENDIF} if (ParamCount < 1) then begin ImgForm.OpenTemplateMRU(nil); RefreshImagesTimer.enabled := true; exit; end; lMaximize := false; lRender := false; lMultislice := false; lOverlayNum := 0; I := 1; lStr := ParamStrFilename(I); if lStr <> '' then OpenAndDisplayImg(lStr,True) else begin //no requested image OpenTemplateMRU(nil); I := 1;//exit; end; I := I-1; //ShowMultisliceClick(nil); if I >= ParamCount then exit; gBGIMg.SaveDefaultIni := false; //do not store changes loaded by script repeat lStr := ''; repeat inc(I); if I = 1 then lStr := ParamStr(I) else begin if lStr <> '' then lStr := lStr +' '+ ParamStr(I) else lStr := ParamStr(I); end; if (length(lStr)>1) and (lStr[1] = '-') then begin //special command lCommandChar := UpCase(lStr[2]); case lCommandChar of 'B': begin //background transparency ReadCmdVal; Val(lStr,lSingle,lError); if lError = 0 then gBGImg.BGTransPct := round(lSingle); SetSubmenuWithTag(BGTransPctMenu, gBGImg.BGTransPct); end; 'C': begin //color look up table ReadCmdVal; if (Length(lStr)>1) then begin if lStr[1] = '-' then begin //LUT index number Val(lStr,lSingle,lError); if lError = 0 then lLUT := abs(round(lSingle)) else lLUT := -1; end else begin lStr := ParseFileName(ExtractFileName(lStr)); {$IFDEF UNIX} lStr := UpCase(lStr); {$ENDIF} lLUT := -1; for lInc := 1 to (LUTdrop.Items.Count-1) do if lStr = string(StrUpper(PChar(LUTdrop.Items.Strings[lINc]))) then lLUT := lInc; end; //else text LUTname if lLUT >= 0 then begin gMRIcroOverlay[lOverlayNum].LUTindex := lLUT; LUTdropLoad(lOverlayNum); end; end; //str length > 1 end; 'D': gBGIMg.SaveDefaultIni := true; 'F': gBGImg.ResliceOnLoad := false; //turn off reslicing... loads files flat 'H': begin ReadCmdVal; Val(lStr,lSingle,lError); if lError = 0 then gMRIcroOverlay[lOverlayNum].WindowScaledMax := (lSingle); end; 'L': begin //Low intensity scale ReadCmdVal; Val(lStr,lSingle,lError); if lError = 0 then gMRIcroOverlay[lOverlayNum].WindowScaledMin := (lSingle); end; 'M': begin //multislice lMultislice := true; ReadCmdVal; if (lStr <> '') and (lStr <> '-')and (FileexistsEx(lStr)) and (lOverlayNum < (knMaxOverlay-1)) then gMultiSliceStartupFilename := (lStr); end; //if 'M' 'O': begin//Overlay ReadCmdVal; //Showmessage('o'+lStr); if (lStr <> '') and (FileexistsEx(lStr)) and (lOverlayNum < (knMaxOverlay-1)) then begin //Showmessage('oexists'+lStr); inc(lOverlayNum); OverlayOpenCore (lStr,lOverlayNum); end; end; //if 'O' 'R': begin//Overlay lRender := true;//Render ReadCmdVal; if (lStr <> '') and (lStr <> '-')and (FileexistsEx(lStr)) and (lOverlayNum < (knMaxOverlay-1)) then gRenderStartupFilename := (lStr); end; //if 'R' 'S': begin //smooth ReadCmdVal; Val(lStr,lSingle,lError); if lError = 0 then begin if odd(round(lSingle)) then begin gBGImg.StretchQuality := sqHigh; Menu2DSmooth.checked := true; end else begin gBGImg.StretchQuality := sqLow; Menu2DSmooth.checked := false; end; if lSingle > 1 then gBGIMg.OverlaySmooth := true else gBGIMg.OverlaySmooth := false; OverlaySmoothMenu.Checked := gBGIMg.OverlaySmooth; end;//error=0 end; 'T': begin //overlay transparency ReadCmdVal; Val(lStr,lSingle,lError); if lError = 0 then gBGImg.OverlayTransPct := round(lSingle); SetSubmenuWithTag(OverlayTransPctMenu, gBGImg.OverlayTransPct); end; 'V': begin //open voi ReadCmdVal; if (lStr <> '') and (FileexistsEx(lStr)) then OpenVOICore(lStr); end; 'X': lMaximize := true; //open maximized 'Z': gMRIcroOverlay[lOverlayNum].LUTfromZero := true; end; //case lStr[2] lStr := ''; end; //special command until (I=ParamCount) or (fileexists(lStr)) {or (gAbort)}; until I >= ParamCount; LayerDropSelect(nil); for lInc := 0 to lOverlayNum do RescaleImgIntensity(gBGImg,gMRIcroOverlay[lInc],lINc); RefreshImages; if lMultiSlice then ShowMultisliceClick(nil); if lRender then ShowRenderClick(nil); if lMaximize then begin ImgForm.WindowState := wsMaximized; RefreshImagesTimer.enabled := true; end; end; procedure TImgForm.FlipLRmenuClick(Sender: TObject); var lC: integer; lStr: string; begin (sender as TMenuItem).checked := not (sender as TMenuItem).checked; gBGImg.Mirror := (sender as TMenuItem).checked ; gBGImg.VOImirrored := true; for lC := 0 to knMaxOverlay do if gMRIcroOverlay[lC].ScrnBufferItems > 0 then RescaleImgIntensity(gBGImg,gMRIcroOverlay[lC],lC); RefreshImagesTimer.Enabled := true; if gBGImg.Mirror then lStr := 'radiological [right on left side]' else lStr := 'neurological [left on left side]'; showmessage('Warning: left-right flips can be confusing. From now on, this software will attempt to show NIfTI images in '+lStr+' orientation.'); if MultiSliceForm.Visible then MultiSliceForm.CreateMultiSlice; end; procedure TImgForm.Menu2DSmoothClick(Sender: TObject); begin if Sender <> nil then (sender as TMenuItem).checked := not (sender as TMenuItem).checked; if Menu2DSmooth.checked then gBGImg.StretchQuality := sqHigh else gBGImg.StretchQuality := sqLow; RefreshImagesTimer.Enabled := true; end; procedure TImgForm.VALclick(Sender: TObject); begin //ComputeValFile( (sender as Tmenuitem).tag); end; procedure TImgForm.VOI2NIIClick(Sender: TObject); var lNumberofFiles,lC: integer; lFilename: string; begin CloseImagesClick(nil); if not OpenDialogExecute('VOI Drawings (.VOI)|*.VOI','Select VOI format images to convert',true) then exit; lNumberofFiles:= HdrForm.OpenHdrDlg.Files.Count; ProgressBar1.Min := 0; ProgressBar1.Max :=lNumberofFiles; ProgressBar1.Position := 0; for lC:= 1 to lNumberofFiles do begin lFilename := HdrForm.OpenHdrDlg.Files[lC-1]; OpenAndDisplayImg(lFilename,True); lFilename := changefileextx(lFilename,'.nii'); //SaveAsVOIorNIFTIcore (lFilename, lByteP, lVoxels, 1, gMRIcroOverlay[kBGOverlayNum].NiftiHdr); SaveAsVOIorNIFTIcore (lFilename, gMRIcroOverlay[kBGOverlayNum].ScrnBuffer,gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems, 1,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr); CloseVOIClick(nil); ProgressBar1.Position := lC; end; ProgressBar1.Position := 0; end;//VOI->NII procedure TImgForm.TtoP1Click(Sender: TObject); var lBufferAligned,lBufferUnAligned: ByteP; l32Buf,l32BufSrc : SingleP; l16BufSrc : SmallIntP; lSlope,lIntercept: single; lMRIcroHdr: TMRIcroHdr; lVolVoxels,lPos: integer; begin //alfa - currently open image lVolVoxels := gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems; if lVolVoxels < 1 then begin showmessage('Please load a background image (''File''/''Open'') before adding an overlay.'); exit; end; GetMem(lBufferUnaligned ,(lVolVoxels *sizeof(single) )+16); //lBufferAligned := ByteP($fffffff0 and (integer(lBufferUnaligned)+15)); lBufferAligned := system.align(lBufferUnaligned, 16); l32Buf := SingleP(lBufferAligned); //next load values case gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP of 4: begin l32BufSrc := SingleP(gMRIcroOverlay[kBGOverlayNum].ImgBuffer ); for lPos := 1 to lVolVoxels do l32Buf^[lPos] := l32BufSrc^[lPos]; end; 2: begin l16BufSrc := SmallIntP(gMRIcroOverlay[kBGOverlayNum].ImgBuffer ); for lPos := 1 to lVolVoxels do l32Buf^[lPos] := l16BufSrc^[lPos]; end; 1: begin for lPos := 1 to lVolVoxels do l32Buf^[lPos] := gMRIcroOverlay[kBGOverlayNum].ImgBuffer^[lPos]; end; else begin showmessage('unknown datatype'); end; end; //next calibrate values lSlope := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.scl_slope; lIntercept := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.scl_inter; if (lSlope=0) or ((lSlope=1) and (lIntercept=0)) then //no slope else begin for lPos := 1 to lVolVoxels do l32Buf^[lPos] := (l32Buf^[lPos] * lSlope)+lIntercept; end; //next - save log10 p values... MakeStatHdr (gMRIcroOverlay[kBGOverlayNum],lMRIcroHdr,0, 255,1{df},0,666,NIFTI_INTENT_LOG10PVAL,inttostr(666) ); for lPos := 1 to lVolVoxels do if l32Buf^[lPos] > 0 then l32Buf^[lPos] := -log(abs(pTdistr(42,l32Buf^[lPos])),10) else l32Buf^[lPos] :=0; SaveAsVOIorNIFTI(lBufferAligned,lVolVoxels,4,1,false,lMRIcroHdr.NiftiHdr,'log10p'+inttostr(666)); //next - free float buffer FreeMem(lBufferUnaligned); end; procedure TImgForm.DesignVALClick(Sender: TObject); begin //SpreadForm.Show; end; procedure TImgForm.Up1Click(Sender: TObject); var lVolVox,lPos,lShift: integer; begin if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems=0 then begin showmessage('You must have open a background image in order to apply an intensity filter (use File/Open).'); exit; end; if not IsVOIOpen then begin ShowMessage('You have not created or opened a region of interest.'); exit; end; CreateUndoVol;//create gBGImg.VOIUndoVol Move(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,gBGImg.VOIUndoVol^,gBGImg.VOIUndoVolItems); lVolVox := gBGImg.ScrnDim[1]* gBGImg.ScrnDim[2]*gBGImg.ScrnDim[3]; case (Sender as TMenuItem).tag of 0: lShift := 1; 1: lShift := -1; 2: lShift := gBGImg.ScrnDim[1]; 3: lShift := -gBGImg.ScrnDim[1]; 4: lShift := gBGImg.ScrnDim[1]*gBGImg.ScrnDim[2]; 5: lShift := -gBGImg.ScrnDim[1]*gBGImg.ScrnDim[2]; end; if lShift > 0 then begin for lPos := 1 to (lVolVox-lShift) do gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer[lPos] := gBGImg.VOIUndoVol[lPos+lShift]; end else begin for lPos := (1+abs(lShift)) to lVolVox do gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer[lPos] := gBGImg.VOIUndoVol[lPos+lShift]; end; gBGImg.VOIchanged := true; ImgForm.ProgressBar1.Position := 0; ImgForm.RefreshImagesTimer.Enabled := true; end; procedure TImgForm.FormDestroy(Sender: TObject); begin {$IFDEF Darwin} FormClose(nil); //OSX does not send a FormClose Event if you choose the Application/Quit option {$ENDIF} CloseShareMem; end; procedure TImgForm.YokeMenuClick(Sender: TObject); begin (sender as TMenuItem).checked := not (sender as TMenuItem).checked; gYoke := (sender as TMenuItem).checked ; if gYoke then CreateShareMem else CloseShareMem; end; procedure TImgForm.About1Click(Sender: TObject); begin AboutForm.ThreadLabel.Caption := ' '+inttostr(gnCPUThreads)+' threads'+' '+ininame; AboutForm.Showmodal; end; procedure TImgForm.LayerDropChange(Sender: TObject); begin {$IFDEF LCLgtk2} LayerDropSelect(nil); {$ENDIF} end; procedure TImgForm.LUTdropChange(Sender: TObject); begin {$IFDEF LCLgtk2} LutDropSelect(nil); {$ENDIF} end; procedure TImgForm.AdjustimagessoVOIintensityiszero1Click(Sender: TObject); begin BatchChangeInterceptSoVOIEqualsZero; end; procedure TImgForm.MirrorNII1Click(Sender: TObject); var lNumberofFiles,lC: integer; lFilename: string; begin Showmessage('WARNING: This will flip the images in the Left-Right dimension: this has serious consequences'); CloseImagesClick(nil); if not OpenDialogExecute(kImgFilter,'Select NIfTI format images to convert',true) then exit; lNumberofFiles:= HdrForm.OpenHdrDlg.Files.Count; ProgressBar1.Min := 0; ProgressBar1.Max :=lNumberofFiles; ProgressBar1.Position := 0; for lC:= 1 to lNumberofFiles do begin lFilename := HdrForm.OpenHdrDlg.Files[lC-1]; ImgForm.OpenAndDisplayImg(lFilename,True); lFilename := changefileextX(lFilename,'lr.nii.gz'); //zap //showmessage(lFilename); if MirrorImgBuffer (gMRIcroOverlay[kBGOverlayNum] ) then begin //showmessage(lFilename); SaveAsVOIorNIFTIcore (lFilename, gMRIcroOverlay[kBGOverlayNum].ImgBuffer,gMRIcroOverlay[kBGOverlayNum].ImgBufferItems,gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr); end; CloseVOIClick(nil); ProgressBar1.Position := lC; end; ProgressBar1.Position := 0; end; procedure TImgForm.ZoomDropChange(Sender: TObject); begin {$IFDEF LCLgtk2} ZoomDropSelect(nil); {$ENDIF} end; procedure TImgForm.ResizeControlPanel (lRows: integer); begin if lRows = 2 then begin ControlPanel.Tag := 2; LayerPanel.Top := 36; LayerPanel.Left := 1; ControlPanel.Height := 72; HideROIBtn.left := 307; XBarBtn.Left := 307+29; ToolPanel.Left := 307+61; end else begin ControlPanel.Tag := 1; LayerPanel.Top := 1; LayerPanel.Left := 307; HideROIBtn.left := 809; XBarBtn.Left := 809+29; ToolPanel.Left := 809+61; ControlPanel.Height := 40; end; end; procedure TImgForm.ControlPanelDblClick(Sender: TObject); begin if ControlPanel.Tag = 1 then ResizeControlPanel(2) else ResizeControlPanel(1); ImgForm.RefreshImagesTimer.enabled := true; end; procedure TImgForm.DefaultControlPanel; begin if gBGImg.SingleRow then begin ResizeControlPanel(1); ImgForm.Width := 1025; ImgForm.Height := 469; end else begin ResizeControlPanel(2); ImgForm.Width := 524; ImgForm.Height := 640; end; end; {$IFDEF FPC} initialization {$I nifti_img_view.lrs} {$ENDIF} for gMouseDownY := 0 to knMaxOverlay do gMRIcroOverlay[gMouseDownY].index := gMouseDownY; //RGB end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/yokesharemem.pas���������������������������������������������������0000755�0001750�0001750�00000007564�11450432724�017417� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit yokesharemem; {$mode objfpc}{$H+} interface //http://community.freepascal.org:10000/docs-html/rtl/ipc/shmctl // call CreateSharedMem when an application is created and CloseSharedMem when a program is closed // along with NInstances, these functions return the number of concurrent instances. // if a program crashes, the values may not be reset until the next reboot uses forms, classes, {$IFDEF UNIX} BaseUnix, SysUtils, ipc,dialogs; {$ELSE} winmemmap; {$ENDIF} function CreateSharedMem (lApp: TComponent): integer; //returns number of instances after including this one... function CloseSharedMem: integer; //returns number of instances after after this one closes function NInstances: integer; //returns number of instances function SetShareFloats(lXmm,lYmm,lZmm: single): boolean; function GetShareFloats(var lXmm,lYmm,lZmm: single): boolean; implementation type TShareMem = record Instances: integer; Xmm,Ymm,Zmm: single; end; PIntBuffer = ^TShareMem; var gShareIntBuf: PIntBuffer; gPrevShare : TShareMem; function NInstances: integer; begin result := gShareIntBuf^.Instances; end; function SetShareFloats(lXmm,lYmm,lZmm: single): boolean; begin gShareIntBuf^.Xmm := lXmm; gShareIntBuf^.Ymm := lYmm; gShareIntBuf^.Zmm := lZmm; gPrevShare := gShareIntBuf^; end; function GetShareFloats(var lXmm,lYmm,lZmm: single): boolean; begin lXmm := gShareIntBuf^.Xmm; lYmm := gShareIntBuf^.Ymm; lZmm := gShareIntBuf^.Zmm; if (lXmm = gPrevShare.Xmm) and (lYmm = gPrevShare.Ymm) and(lZmm = gPrevShare.Zmm) then result := false else result := true; gPrevShare := gShareIntBuf^; end; {$IFNDEF UNIX} //Windows implementation var EMemMap : TEMemMap; function CreateSharedMem (lApp: TComponent): integer; //returns number of instances after including this one... var I: integer; begin EMemMap:=TEMemMap.Create(lApp{Self}); EMemMap.CreateMutex('MRICROMUTEX3'); If NOT EMemMap.MapExisting('MRICROMAP3',SizeOf(TShareMem)) then begin gPrevShare.Xmm:=0; gPrevShare.Ymm:=0; gPrevShare.Zmm:=0; gPrevShare.Instances:=0; If NOT EMemMap.CreateMemMap('MRICROMAP2',SizeOf(TShareMem),gPrevShare) then EMemMap.RaiseMappingException; gShareIntBuf := PINtBuffer(EMemMap.MemMap); end else gShareIntBuf^.Instances := gShareIntBuf^.Instances + 1; end; function CloseSharedMem: integer; //returns number of instances after after this one closesb begin EMemMap.Free; end; {$ELSE} var fshmid: longint; segptr : Pointer; function CreateSharedMem (lApp: TComponent): integer; //returns number of instances after including this one... var key : Tkey; new: boolean; const ftokpath = '.'#0; begin key := ftok (pchar(@ftokpath[1]),ord('S')); fshmid := shmget(key,SizeOf(TShareMem) {segsize},IPC_CREAT or IPC_EXCL or 438); If fshmid=-1 then begin //showmessage('Loading existing memory.'); new := false; fshmid := shmget(key,SizeOf(TShareMem){segsize},0); If fshmid = -1 then begin showmessage ('Shared memory : Error !'+inttostr(fpgeterrno)); halt(1); end end else begin new := true; //showmessage ('Creating new shared memory segment.'); end; segptr:=shmat(fshmid,nil,0); gShareIntBuf := segptr; if new then gShareIntBuf^.Instances := 1 else gShareIntBuf^.Instances :=gShareIntBuf^.Instances + 1; result := gShareIntBuf^.Instances; end; function CloseSharedMem: integer; //returns number of instances after this application quits begin gShareIntBuf^.Instances := gShareIntBuf^.Instances -1; result := gShareIntBuf^.Instances; if Assigned (segptr) then shmdt (segptr); if result < 1 then begin //last running instance - close shared memory if shmctl (FShmId, IPC_RMID, nil) = -1 then Showmessage('unable to release shared memory'); end; end; {$ENDIF} end. ��������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/���������������������������������������������������������0000755�0001750�0001750�00000000000�12413465015�016160� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/ReadInt.lrs����������������������������������������������0000755�0001750�0001750�00000002317�11540170632�020234� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TReadIntForm','FORMDATA',[ 'TPF0'#12'TReadIntForm'#11'ReadIntForm'#4'Left'#3'2'#1#6'Height'#2'P'#3'Top'#3 +'*'#2#5'Width'#3#213#1#18'HorzScrollBar.Page'#3#212#1#18'VertScrollBar.Page' +#2'O'#13'ActiveControl'#7#11'ReadIntEdit'#11'BorderStyle'#7#8'bsDialog'#7'Ca' +'ption'#6#16'Integer required'#12'ClientHeight'#2'P'#11'ClientWidth'#3#213#1 +#21'Constraints.MaxHeight'#2'P'#20'Constraints.MaxWidth'#3#213#1#21'Constrai' +'nts.MinHeight'#2'P'#20'Constraints.MinWidth'#3#213#1#9'Font.Name'#6#13'MS S' +'ans Serif'#8'OnCreate'#7#10'FormCreate'#8'Position'#7#14'poScreenCenter'#10 +'LCLVersion'#6#8'0.9.28.2'#0#6'TLabel'#12'ReadIntLabel'#4'Left'#2#16#6'Heigh' +'t'#2#14#3'Top'#2#12#5'Width'#3'P'#1#9'Alignment'#7#14'taRightJustify'#8'Aut' +'oSize'#8#7'Caption'#6#14'Enter a number'#11'ParentColor'#8#0#0#9'TSpinEdit' +#11'ReadIntEdit'#4'Left'#3'h'#1#6'Height'#2#27#3'Top'#2#12#5'Width'#2']'#8'M' +'axValue'#2#0#8'TabOrder'#2#0#0#0#7'TButton'#5'OKBtn'#4'Left'#3'p'#1#6'Heigh' +'t'#2#25#3'Top'#2','#5'Width'#2'K'#25'BorderSpacing.InnerBorder'#2#4#7'Capti' +'on'#6#2'OK'#7'OnClick'#7#10'OKBtnClick'#8'TabOrder'#2#1#0#0#0 ]); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/spread.lrs�����������������������������������������������0000755�0001750�0001750�00000012021�12147213330�020152� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TSpreadForm','FORMDATA',[ 'TPF0'#11'TSpreadForm'#10'SpreadForm'#4'Left'#3#145#1#6'Height'#3#26#2#3'Top' +#3#183#0#5'Width'#3'F'#1#13'ActiveControl'#7#8'DataGrid'#7'Caption'#6#29'Vox' +'elwise Analysis of Lesions'#12'ClientHeight'#3#26#2#11'ClientWidth'#3'F'#1#9 +'Font.Name'#6#13'MS Sans Serif'#4'Menu'#7#9'MainMenu1'#7'OnClose'#7#9'FormCl' +'ose'#8'OnCreate'#7#10'FormCreate'#8'OnResize'#7#10'FormResize'#8'Position'#7 +#14'poScreenCenter'#10'LCLVersion'#6#8'0.9.30.2'#0#11'TStringGrid'#8'DataGri' +'d'#4'Left'#2#0#6'Height'#3#242#1#3'Top'#2#25#5'Width'#3'F'#1#5'Align'#7#8'a' +'lClient'#9'FixedRows'#2#2#7'Options'#11#15'goFixedVertLine'#10'goVertLine' +#10'goHorzLine'#13'goRangeSelect'#19'goDrawFocusSelected'#6'goTabs'#15'goThu' +'mbTracking'#0#8'RowCount'#2#12#8'TabOrder'#2#0#14'TitleFont.Name'#6#13'MS S' +'ans Serif'#10'OnDrawCell'#7#16'DataGridDrawCell'#10'OnKeyPress'#7#16'DataGr' +'idKeyPress'#11'OnMouseDown'#7#17'DataGridMouseDown'#11'OnMouseMove'#7#17'Da' +'taGridMouseMove'#12'OnSelectCell'#7#18'DataGridSelectCell'#0#0#8'TToolBar'#8 +'ToolBar1'#4'Left'#2#0#6'Height'#2#25#3'Top'#2#0#5'Width'#3'F'#1#11'EdgeBord' +'ers'#11#0#8'TabOrder'#2#1#0#12'TSpeedButton'#9'DesignBtn'#4'Left'#2#1#6'Hei' +'ght'#2#22#4'Hint'#6#5'ANOVA'#3'Top'#2#0#5'Width'#2'x'#7'Caption'#6#6'Design' +#10'Glyph.Data'#10'z'#1#0#0'v'#1#0#0'BMv'#1#0#0#0#0#0#0'v'#0#0#0'('#0#0#0' ' +#0#0#0#16#0#0#0#1#0#4#0#0#0#0#0#0#1#0#0#0#0#0#0#0#0#0#0#16#0#0#0#16#0#0#0#0#0 +#0#0#0#0#128#0#0#128#0#0#0#128#128#0#128#0#0#0#128#0#128#0#128#128#0#0#127 +#127#127#0#191#191#191#0#0#0#255#0#0#255#0#0#0#255#255#0#255#0#0#0#255#0#255 +#0#255#255#0#0#255#255#255#0'3s3s3s3s3'#127'?'#127'?'#127'?'#127'3sssssss?' +#127#127#127#127#127#127#127'w'#0#0#0#0#0#0#0'wwwwwwww3'#3'33<3333'#127#255 +'37'#243'3?7'#9#147'3<33'#153'7ws'#243'7'#243'3w3'#3'93<393?'#127#247#255#247 +#255#247#255'w'#7'w'#151'|w'#151'wwwwwwwww3'#3'3'#147'<3'#147'33'#127'3s'#247 +#243's37'#3'39<9337'#127'377'#247'333'#3'33'#153#147'33?'#127#255#255'w'#127 +#255#255'w'#7'ww|wwwwwwwwwww3'#3'33<3'#3'33'#127'337'#255#127#243'7'#3'33<'#0 +#0'<7'#127'337ww73'#3'33<3'#3'3?'#127#255#255#247#255#127#255'w'#7'wwwwwwwww' +'wwwww3333333333333333'#9'NumGlyphs'#2#2#7'OnClick'#7#14'DesignBtnClick'#8'S' +'howHint'#9#14'ParentShowHint'#8#0#0#0#10'TStatusBar'#10'StatusBar1'#4'Left' +#2#0#6'Height'#2#15#3'Top'#3#11#2#5'Width'#3'F'#1#6'Panels'#14#1#5'Width'#3 +#140#0#0#1#5'Width'#2'2'#0#0#11'SimplePanel'#8#0#0#9'TMainMenu'#9'MainMenu1' +#4'left'#2'l'#3'top'#2','#0#9'TMenuItem'#5'File1'#7'Caption'#6#5'&File'#0#9 +'TMenuItem'#4'New1'#7'Caption'#6#6'New...'#8'ShortCut'#3'N@'#7'OnClick'#7#11 +'NewBtnClick'#0#0#9'TMenuItem'#5'Open1'#7'Caption'#6#7'Open...'#8'ShortCut'#3 +'O@'#7'OnClick'#7#12'OpenBtnClick'#0#0#9'TMenuItem'#5'Save1'#7'Caption'#6#4 +'Save'#8'ShortCut'#3'S@'#7'OnClick'#7#12'SaveBtnClick'#0#0#9'TMenuItem'#5'Qu' +'it1'#7'Caption'#6#12'Close window'#8'ShortCut'#3'W@'#7'OnClick'#7#10'Quit1C' +'lick'#0#0#0#9'TMenuItem'#5'Edit1'#7'Caption'#6#4'Edit'#0#9'TMenuItem'#5'Cop' +'y1'#7'Caption'#6#4'Copy'#8'ShortCut'#3'C@'#7'OnClick'#7#10'Copy1Click'#0#0#9 +'TMenuItem'#6'Paste1'#7'Caption'#6#5'Paste'#8'ShortCut'#3'V@'#7'OnClick'#7#11 +'Paste1Click'#0#0#9'TMenuItem'#10'Selectall1'#7'Caption'#6#16'Select all cel' +'ls'#8'ShortCut'#3'A@'#7'OnClick'#7#15'Selectall1Click'#0#0#9'TMenuItem'#14 +'Clearallcells1'#7'Caption'#6#18'Clear all cells...'#7'OnClick'#7#19'Clearal' +'lcells1Click'#0#0#9'TMenuItem'#15'DescriptiveMenu'#7'Caption'#6#12'Descript' +'ives'#7'OnClick'#7#16'DescriptiveClick'#0#0#0#9'TMenuItem'#4'View'#7'Captio' +'n'#6#4'View'#0#9'TMenuItem'#5'Font1'#7'Caption'#6#4'Font'#0#9'TMenuItem'#3 +'N81'#3'Tag'#2#8#7'Caption'#6#1'8'#7'Checked'#9#10'GroupIndex'#2'o'#9'RadioI' +'tem'#9#7'OnClick'#7#14'FontSizeChange'#0#0#9'TMenuItem'#4'N101'#3'Tag'#2#10 +#7'Caption'#6#2'10'#10'GroupIndex'#2'o'#9'RadioItem'#9#7'OnClick'#7#14'FontS' +'izeChange'#0#0#9'TMenuItem'#4'N121'#3'Tag'#2#12#7'Caption'#6#2'12'#10'Group' +'Index'#2'o'#9'RadioItem'#9#7'OnClick'#7#14'FontSizeChange'#0#0#9'TMenuItem' +#4'N141'#3'Tag'#2#14#7'Caption'#6#2'14'#10'GroupIndex'#2'o'#9'RadioItem'#9#7 +'OnClick'#7#14'FontSizeChange'#0#0#0#9'TMenuItem'#7'Design1'#7'Caption'#6#6 +'Design'#8'ShortCut'#3'D@'#7'OnClick'#7#14'DesignBtnClick'#0#0#0#9'TMenuItem' +#5'Help1'#7'Caption'#6#5'&Help'#0#9'TMenuItem'#18'Aboutthissoftware1'#7'Capt' +'ion'#6#20'&About this software'#7'OnClick'#7#23'Aboutthissoftware1Click'#0#0 +#0#0#11'TOpenDialog'#11'OpenDialog1'#10'DefaultExt'#6#4'.val'#6'Filter'#6'<N' +'ative [val]|.val|Tab delimited text [txt]|.txt|All files|.*'#11'FilterIndex' +#2#0#4'left'#2'$'#3'top'#2','#0#0#11'TSaveDialog'#11'SaveDialog1'#10'Default' +'Ext'#6#4'.val'#6'Filter'#6'8Native format [val]|*.val|Tab delimited text [t' +'xt]|*.txt'#11'FilterIndex'#2#0#7'Options'#11#17'ofOverwritePrompt'#14'ofHid' +'eReadOnly'#0#4'left'#2'J'#3'top'#2','#0#0#0 ]); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/Copy of turbolesion.pas����������������������������������0000755�0001750�0001750�00000026274�11326425446�022536� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit turbolesion; interface {$H+} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes; Type TLDMPrefs = record NULP,BMtest,Ttest,Ltest: boolean; nCrit,nPermute,Run{0 except for montecarlo}: integer; NameAppend: string; end; implementation uses npmform; {$DEFINE NOTmedianfx} function TurboLDM (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lPrefs: TLDMPrefs ; var lSymptomRA: SingleP;var lFactname,lOutName: string): boolean; label 123,667; var lOutNameMod: string; lPlankImg: byteP; lOutImgSum,lOutImgBM,lOutImgT,lOutImgAUC, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP; lPos,lPlank,lThread: integer; lVolVox,lMinMask,lMaxMask,lTotalMemory,lnPlanks,lVoxPerPlank, lThreadStart,lThreadEnd,lThreadInc,lnLesion,//,lnPermute, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT,lBMz, lSum,lThresh,lThreshPermute,lThreshBonf,lThreshNULP :double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; lPlankAllocated: boolean; //lttest,lBM: boolean; {$IFDEF medianfx} lmedianFX,lmeanFX,lsummean,lsummedian: double; lmediancount: integer; {$ENDIF} begin //lttest:= ttestmenu.checked; //lBM := BMmenu.checked; lPlankAllocated := false; //lnPermute := MainForm.ReadPermute; MainForm.NPMmsg('Permutations = ' +IntToStr(lPrefs.nPermute)); MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; MainForm.NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); MainForm.NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) //assumes 1bpp else getmem(lPlankImg,kPlankSz); lPlankAllocated := true; lStartVox := lMinMask; lEndVox := lMinMask-1; {$IFDEF medianfx} lsummean := 0; lsummedian:= 0; lmediancount := 0; {$ENDIF} for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; createArray64(lObsp,lObs,lImages.Count); getmem(lOutImgSum,lVolVox* sizeof(single)); getmem(lOutImgBM,lVolVox* sizeof(single)); getmem(lOutImgT,lVolVox* sizeof(single)); getmem(lOutImgAUC,lVolVox* sizeof(single)); MainForm.InitPermute (lImages.Count, lPrefs.nPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; lOutImgAUC^[lPos] := 0; end; //next create permuted BM bounds if lPrefs.BMtest then begin MainForm.NPMmsg('Generating BM permutation thresholds'); MainForm.Refresh; for lPos := 1 to lImages.Count do lObs^[lPos-1] := lSymptomRA^[lPos]; genBMsim (lImages.Count, lObs); end; ClearThreadData(gnCPUThreads,lPrefs.nPermute) ; for lPlank := 1 to lnPlanks do begin MainForm.NPMmsg('Computing plank = ' +Inttostr(lPlank)); MainForm.Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TLesionContinuous.Create (MainForm.ProgressBar1,lPrefs.ttest,lPrefs.BMtest,lPrefs.nCrit, lPrefs.nPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,0,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA) do //with TLesionContinuous.Create (MainForm.ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,lSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; //freemem(lPlankImg); //lPlankAllocated := false; lThreshPermute := 0; lnVoxTested := SumThreadData(gnCPUThreads,lPrefs.nPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //next report findings if lnVoxTested < 1 then begin MainForm.NPMmsg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lPrefs.nCrit)+' patients**'); goto 123; end; MainForm.NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); {$IFDEF medianfx} MainForm.NPMmsg('Average MEAN effect size = ' +realtostr((lsummean/lmediancount),3)); MainForm.NPMmsg('Average MEDIAN effect size = ' +realtostr((lsummedian/lmediancount),3)); {$ENDIF} MainForm.NPMmsg('Only tested voxels with more than '+inttostr(lPrefs.nCrit)+' lesions'); //Next: save results from permutation thresholding.... lThreshBonf := MainForm.reportBonferroni('Std',lnVoxTested); //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); if lPrefs.Run < 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //save Area Under Curve lOutNameMod := ChangeFilePostfixExt(lOutName,'rocAUC'+lFactName,'.hdr'); if lPrefs.Run < 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgAUC,1); //create new header - subsequent images will use Z-scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lPrefs.Run < 1) and (Sum2PowerCont(lOutImgSum,lVolVox,lImages.Count)) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; if lPrefs.Run > 0 then //terrible place to do this - RAM problems, but need value to threshold maps lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap2 (lImages, lPrefs.nCrit,lnVoxTested,lPlankImg)); //MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if lPrefs.ttest then begin //save Ttest //next: convert t-scores to z scores for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lPrefs.nPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; lThresh := MainForm.reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); lThreshPermute := MainForm.reportPermute('ttest',lPrefs.nPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'ttest'+lFactName,'.hdr'); if lPrefs.Run > 0 then MainForm.NPMmsgAppend('threshtt,'+inttostr(lPrefs.Run)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgT))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if lPrefs.BMtest then begin //save Brunner Munzel lThresh := MainForm.reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); lThreshPermute := MainForm.reportPermute('BM',lPrefs.nPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'BM'+lFactName,'.hdr'); if lPrefs.Run > 0 then MainForm.NPMmsgAppend('threshbm,'+inttostr(lPrefs.Run)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgBM))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end; //next: free dynamic memory 123: MainForm.FreePermute (lPrefs.nPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgT); freemem(lOutImgAUC); freemem(lOutImgBM); freemem(lOutImgSum); freemem(lObsp); if lPlankAllocated then freemem(lPlankImg); //Next: NULPS - do this after closing all memory - this is a memory hog if lPrefs.NULP then lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap (lImages, lPrefs.nCrit,lnVoxTested)); MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); MainForm.MsgSave(lOutNameMod); MainForm.ProgressBar1.Position := 0; //if lRun > 0 then // AX(freeram,freeram,freeram,freeram,freeram,freeram); exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; //LesionNPMAnalyze end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/���������������������������������������������������0000755�0001750�0001750�00000000000�12360760644�017264� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/polynom.pas����������������������������������������0000755�0001750�0001750�00000015174�11326425446�021500� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit POLYNOM.PAS * * Version 1.3 * * (c) J. Debord, January 1998 * ********************************************************************** This unit implements routines for polynomials and rational fractions. ********************************************************************** Reference: 'Numerical Recipes' by Press et al. ********************************************************************** } unit Polynom; interface uses FMath, Matrices, Eigen, Stat; function Poly(X : Float; Coef : PVector; Deg : Integer) : Float; { ---------------------------------------------------------------------- Evaluates the polynomial : P(X) = Coef[0] + Coef[1] * X + Coef[2] * X^2 +...+ Coef[Deg] * X^Deg ---------------------------------------------------------------------- } function RRootPol(Coef : PVector; Deg : Integer; X : PVector) : Integer; { ---------------------------------------------------------------------- Real roots of a polynomial. The roots are computed analytically if Deg <= 3, otherwise they are computed numerically from the eigenvalues of the companion matrix (function RootPol in EIGEN.PAS). The roots are returned in X (in increasing order). The function returns the number of real roots found. ---------------------------------------------------------------------- } function CRootPol(Coef : PVector; Deg : Integer; X_Re, X_Im : PVector) : Integer; { ---------------------------------------------------------------------- Complex roots of a polynomial. The roots are computed numerically from the eigenvalues of the companion matrix (function RootPol in EIGEN.PAS). The real and imaginary parts of the roots are returned in X_Re and X_Im (in increasing order of the real parts). The function returns the number of roots found, which may be Deg or zero if the method did not converge. ---------------------------------------------------------------------- } function RFrac(X : Float; Coef : PVector; Deg1, Deg2 : Integer) : Float; { ---------------------------------------------------------------------- Evaluates the rational fraction : Coef[0] + Coef[1] * X + ... + Coef[Deg1] * X^Deg1 F(X) = ----------------------------------------------------- 1 + Coef[Deg1+1] * X + ... + Coef[Deg1+Deg2] * X^Deg2 ---------------------------------------------------------------------- } implementation const MAXDEG = 3; { Maximal degree for analytical solution of polynomial } function Poly(X : Float; Coef : PVector; Deg : Integer) : Float; var I : Integer; Y : Float; begin Y := Coef^[Deg]; for I := Pred(Deg) downto 0 do Y := Y * X + Coef^[I]; Poly := Y; end; function RFrac(X : Float; Coef : PVector; Deg1, Deg2 : Integer) : Float; var I : Integer; Sum : Float; { Denominator sum } begin Sum := 0.0; for I := (Deg1 + Deg2) downto Succ(Deg1) do Sum := (Sum + Coef^[I]) * X; RFrac := Poly(X, Coef, Deg1) / (1.0 + Sum); end; function RootPol3(Coef : PVector; Deg : Integer; X : PVector) : Integer; { Real roots of polynomial up to degree 3 (Analytical solution) } const PI2DIV3 = 2.0943951023931954923; { 2*pi/3 } var NR : Integer; { Number of roots } R, R2, Q, Q3, Delta, A0, A1, A2, A22, A3, AA, BB, Theta, Z : Float; begin if (Deg < 1) or (Deg > MAXDEG) then begin RootPol3 := 0; Exit; end; case Deg of 1 : begin NR := 1; X^[1] := - Coef^[0] / Coef^[1]; end; 2 : begin Delta := Sqr(Coef^[1]) - 4.0 * Coef^[0] * Coef^[2]; if Delta < 0 then NR := 0 else begin NR := 2; if Coef^[1] >= 0 then Q := - 0.5 * (Coef^[1] + Sqrt(Delta)) else Q := - 0.5 * (Coef^[1] - Sqrt(Delta)); X^[1] := Q / Coef^[2]; X^[2] := Coef^[0] / Q; end; end; 3 : begin A0 := Coef^[0] / Coef^[3]; A1 := Coef^[1] / Coef^[3]; A2 := Coef^[2] / Coef^[3]; A3 := A2 / 3.0; A22 := Sqr(A2); Q := (A22 - 3.0 * A1) / 9.0; R := (A2 * (2.0 * A22 - 9.0 * A1) + 27.0 * A0) / 54.0; R2 := R * R; Q3 := Q * Q * Q; Delta := Q3 - R2; if Delta < 0 then begin NR := 1; AA := Power(Abs(R) + Sqrt(- Delta), 0.333333333333333); if R >= 0 then AA := - AA; if AA <> 0 then BB := Q / AA else BB := 0.0; X^[1] := (AA + BB) - A3; end else begin NR := 3; Theta := ArcCos(R / Sqrt(Q3)) / 3.0; Z := - 2.0 * Sqrt(Q); X^[1] := Z * Cos(Theta) - A3; X^[2] := Z * Cos(Theta + PI2DIV3) - A3; X^[3] := Z * Cos(Theta - PI2DIV3) - A3; end; end; end; QSort(X, 1, Deg); RootPol3 := NR; end; function RRootPol(Coef : PVector; Deg : Integer; X : PVector) : Integer; var N : Integer; { Number of real roots } X_Re, X_Im : PVector; { Real and imaginary parts } ErrCode : Integer; { Error code } I : Integer; { Loop variable } begin DimVector(X_Re, Deg); DimVector(X_Im, Deg); if Deg <= MAXDEG then RRootPol := RootPol3(Coef, Deg, X) else begin ErrCode := RootPol(Coef, Deg, X_Re, X_Im); if ErrCode = MAT_OK then begin { Get real roots } N := 0; for I := 1 to Deg do if Abs(X_Im^[I]) <= MACHEP then begin Inc(N); X^[N] := X_Re^[I]; end; { Set other roots to zero } for I := Succ(N) to Deg do X^[I] := 0.0; RRootPol := N; end else RRootPol := 0; end; DelVector(X_Re, Deg); DelVector(X_Im, Deg); end; function CRootPol(Coef : PVector; Deg : Integer; X_Re, X_Im : PVector) : Integer; begin if RootPol(Coef, Deg, X_Re, X_Im) = MAT_OK then CRootPol := Deg else CRootPol := 0; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/fitmich.pas����������������������������������������0000755�0001750�0001750�00000011675�11326425446�021430� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITMICH.PAS * * Version 1.0 * * (c) J. Debord, April 1998 * ********************************************************************** This unit fits the Michaelis equation : Ymax . x y = -------- Km + x ********************************************************************** } unit FitMich; {$F+} interface uses FMath, Matrices, Stat, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X, Y : Float; B, D : PVector); function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; implementation function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } begin FuncName := 'y = Ymax . x / (Km + x)'; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 1; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'Ymax'; 1 : ParamName := 'Km '; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = Ymax B^[1] = Km -------------------------------------------------------------------- } begin RegFunc := B^[0] * X / (B^[1] + X); end; procedure DerivProc(X, Y : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point (X,Y) with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter -------------------------------------------------------------------- } begin D^[0] := Y / B^[0]; { dy/dYmax = x / (Km + x) } D^[1] := - Y / (B^[1] + X); { dy/dKm = - Ymax.x / (Km + x)^2 } end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of the Michaelis equation by linear regression: 1/y = 1/Ymax + (Km/Ymax) * (1/x) -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- } var X1, Y1 : PVector; { Transformed coordinates } W1 : PVector; { Weights } A : PVector; { Linear regression parameters } V : PMatrix; { Variance-covariance matrix } P : Integer; { Number of points for linear regression } K : Integer; { Loop variable } ErrCode : Integer; { Error code } begin DimVector(X1, N); DimVector(Y1, N); DimVector(W1, N); DimVector(A, 1); DimMatrix(V, 1, 1); P := 0; for K := 1 to N do if (X^[K] > 0.0) and (Y^[K] > 0.0) then begin Inc(P); X1^[P] := 1.0 / X^[K]; Y1^[P] := 1.0 / Y^[K]; W1^[P] := Sqr(Sqr(Y^[K])); if Method = 1 then W1^[P] := W1^[P] * W^[K]; end; ErrCode := WLinFit(X1, Y1, W1, P, A, V); if ErrCode = MAT_OK then begin B^[0] := 1.0 / A^[0]; B^[1] := A^[1] / A^[0]; end; FitModel := ErrCode; DelVector(X1, N); DelVector(Y1, N); DelVector(W1, N); DelVector(A, 1); DelMatrix(V, 1, 1); end; end. �������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/pastring.pas���������������������������������������0000755�0001750�0001750�00000020101�11326425446�021614� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit PASTRING.PAS * * Version 1.8 * * (c) J. Debord, December 2000 * ********************************************************************** Turbo Pascal string routines ********************************************************************** } unit PaString; interface uses FMath, FComp, Matrices; { *** Global variables controlling the appearance of a numeric string ** } const NumLength : Integer = 10; { Length of a numeric field } MaxDec : Integer = 4; { Max. number of decimal places } FloatPoint : Boolean = False; { Floating point notation } NSZero : Boolean = True; { Write non significant zero's } { ************************** String routines *************************** } function LTrim(S : String) : String; { ---------------------------------------------------------------------- Removes leading blanks ---------------------------------------------------------------------- } function RTrim(S : String) : String; { ---------------------------------------------------------------------- Removes trailing blanks ---------------------------------------------------------------------- } function Trim(S : String) : String; { ---------------------------------------------------------------------- Removes leading and trailing blanks ---------------------------------------------------------------------- } function StrChar(N : Byte; C : Char) : String; { ---------------------------------------------------------------------- Returns a string made of character C repeated N times ---------------------------------------------------------------------- } function RFill(S : String; L : Byte) : String; { ---------------------------------------------------------------------- Completes string S with trailing blanks for a total length L ---------------------------------------------------------------------- } function LFill(S : String; L : Byte) : String; { ---------------------------------------------------------------------- Completes string S with leading blanks for a total length L ---------------------------------------------------------------------- } function CFill(S : String; L : Byte) : String; { ---------------------------------------------------------------------- Completes string S with leading blanks to center the string on a total length L ---------------------------------------------------------------------- } function Replace(S : String; C1, C2 : Char) : String; { ---------------------------------------------------------------------- Replaces in string S all the occurences of character C1 by character C2 ---------------------------------------------------------------------- } function Extract(S : String; var Index : Byte; Delim : Char) : String; { ---------------------------------------------------------------------- Extracts a field from a string. Index is the position of the first character of the field. Delim is the character used to separate fields (e.g. blank, comma or tabulation). Blanks immediately following Delim are ignored. Index is updated to the position of the next field. ---------------------------------------------------------------------- } procedure Parse(S : String; Delim : Char; Field : PStrVector; var N : Byte); { ---------------------------------------------------------------------- Parses a string into its constitutive fields. Delim is the field separator. The number of fields is returned in N. The fields are returned in Field^[0]..Field^[N - 1]. Field must be dimensioned in the calling program. ---------------------------------------------------------------------- } function FloatToStr(X : Float) : String; { ---------------------------------------------------------------------- Converts a real to a string according to the values of the global variables NumLength, MaxDec, FloatPoint and NSZero ---------------------------------------------------------------------- } function IntToStr(N : LongInt) : String; { ---------------------------------------------------------------------- Converts an integer to a string according to the values of the global variables NumLength and MaxDec. ---------------------------------------------------------------------- } function CompToStr(Z : Complex) : String; { ---------------------------------------------------------------------- Converts a complex number to a string. ---------------------------------------------------------------------- } implementation function LTrim(S : String) : String; begin if S <> '' then repeat if S[1] = ' ' then Delete(S, 1, 1); until S[1] <> ' '; LTrim := S; end; function RTrim(S : String) : String; var L1 : Byte; begin if S <> '' then repeat L1 := Length(S); if S[L1] = ' ' then Delete(S, L1, 1); until S[L1] <> ' '; RTrim := S; end; function Trim(S : String) : String; begin Trim := LTrim(RTrim(S)); end; function StrChar(N : Byte; C : Char) : String; var I : Byte; S : String; begin S := ''; for I := 1 to N do S := S + C; StrChar := S; end; function RFill(S : String; L : Byte) : String; var L1 : Byte; begin L1 := Length(S); if L1 >= L then RFill := S else RFill := S + StrChar(L - L1, ' '); end; function LFill(S : String; L : Byte) : String; var L1 : Byte; begin L1 := Length(S); if L1 >= L then LFill := S else LFill := StrChar(L - L1, ' ') + S; end; function CFill(S : String; L : Byte) : String; var L1 : Byte; begin L1 := Length(S); if L1 >= L then CFill := S else CFill := StrChar((L - L1) div 2, ' ') + S; end; function Replace(S : String; C1, C2 : Char) : String; var S1 : String; K : Byte; begin S1 := S; K := Pos(C1, S1); while K > 0 do begin S1[K] := C2; K := Pos(C1, S1); end; Replace := S1; end; function Extract(S : String; var Index : Byte; Delim : Char) : String; var I, L : Byte; begin I := Index; L := Length(S); { Search for Delim } while (I <= L) and (S[I] <> Delim) do Inc(I); { Extract field } if I = Index then Extract := '' else Extract := Copy(S, Index, I - Index); { Skip blanks after Delim } repeat Inc(I); until (I > L) or (S[I] <> ' '); { Update Index } Index := I; end; procedure Parse(S : String; Delim : Char; Field : PStrVector; var N : Byte); var I, Index, L : Byte; begin I := 0; Index := 1; L := Length(S); repeat Field^[I] := Extract(S, Index, Delim); Inc(I); until Index > L; N := I; end; function FloatToStr(X : Float) : String; var S : String; C : Char; L : Byte; begin if FloatPoint then begin Str(X:Pred(NumLength), S); S := ' ' + S; end else begin Str(X:NumLength:MaxDec, S); if not NSZero then repeat L := Length(S); C := S[L]; if (C = '0') or (C = '.') then Delete(S, L, 1); until C <> '0'; end; FloatToStr := S; end; function IntToStr(N : LongInt) : String; var S : String; begin Str(N:(NumLength - MaxDec - 1), S); IntToStr := S; end; function CompToStr(Z : Complex) : String; var S : String; begin if Z.Form = Rec then begin if Z.Y >= 0.0 then S := ' + ' else S := ' - '; CompToStr := FloatToStr(Z.X) + S + FloatToStr(Abs(Z.Y)) + ' * i'; end else CompToStr := FloatToStr(Z.R) + ' * Exp(' + FloatToStr(Z.Theta) + ' * i)'; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/fithill.pas����������������������������������������0000755�0001750�0001750�00000013525�11326425446�021434� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITHILL.PAS * * Version 1.1 * * (c) J. Debord, August 2000 * ********************************************************************** This unit fits the Hill equation : Ymax . x^n y = ---------- K^n + x^n ********************************************************************** } unit FitHill; {$F+} interface uses FMath, Matrices, Stat, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X, Y : Float; B, D : PVector); function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; implementation function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } begin FuncName := 'y = Ymax . x^n / (K^n + x^n)'; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 2; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'Ymax'; 1 : ParamName := 'K '; 2 : ParamName := 'n '; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = Ymax B^[1] = K B^[2] = n -------------------------------------------------------------------- } begin if X = 0.0 then if B^[2] > 0.0 then RegFunc := 0.0 else RegFunc := B^[0] else { Compute function according to y = Ymax / [1 + (K/x)^n] } RegFunc := B^[0] / (1.0 + Power(B^[1] / X, B^[2])); end; procedure DerivProc(X, Y : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point (X,Y) with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter -------------------------------------------------------------------- } var Q, R, S : Float; begin if X = 0.0 then begin if B^[2] > 0.0 then D^[0] := 0.0 else D^[0] := 1.0; D^[1] := 0.0; D^[2] := 0.0; end else begin Q := Power(B^[1] / X, B^[2]); { (K/x)^n } R := 1.0 / (1.0 + Q); { 1 / [1 + (K/x)^n] } S := - Y * R * Q; { -Ymax.(K/x)^n / [1 + (K/x)^n]^2 } { dy/dYmax = 1 / [1 + (K/x)^n] } D^[0] := R; { dy/dK = -Ymax.(K/x)^n.(n/K)/[1 + (K/x)^n]^2 } D^[1] := S * B^[2] / B^[1]; { dy/dn = -Ymax.(K/x)^n.Ln(K/x)/[1 + (K/x)^n]^2 } D^[2] := S * Log(B^[1] / X); end; end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of the Hill equation by linear regression: Ln(Ymax/y - 1) = n.Ln(K) - n.Ln(x) -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- } var Ymax : Float; { Estimated value of Ymax } X1, Y1 : PVector; { Transformed coordinates } W1 : PVector; { Weights } A : PVector; { Linear regression parameters } V : PMatrix; { Variance-covariance matrix } P : Integer; { Number of points for linear regression } K : Integer; { Loop variable } ErrCode : Integer; { Error code } begin DimVector(X1, N); DimVector(Y1, N); DimVector(W1, N); DimVector(A, 1); DimMatrix(V, 1, 1); P := 0; Ymax := Max(Y, 1, N); for K := 1 to N do if (X^[K] > 0.0) and (Y^[K] > 0.0) and (Y^[K] < Ymax) then begin Inc(P); X1^[P] := Log(X^[K]); Y1^[P] := Log(Ymax / Y^[K] - 1.0); W1^[P] := Sqr(Y^[K] * (1.0 - Y^[K] / Ymax)); if Method = 1 then W1^[P] := W1^[P] * W^[K]; end; ErrCode := WLinFit(X1, Y1, W1, P, A, V); if ErrCode = MAT_OK then begin B^[0] := Ymax; B^[1] := Expo(- A^[0] / A^[1]); B^[2] := - A^[1]; end; FitModel := ErrCode; DelVector(X1, N); DelVector(Y1, N); DelVector(W1, N); DelVector(A, 1); DelMatrix(V, 1, 1); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/stat.pas�������������������������������������������0000755�0001750�0001750�00000025573�11326425446�020762� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit STAT.PAS * * Version 1.5 * * (c) J. Debord, June 2001 * ********************************************************************** Statistical routines ********************************************************************** } unit Stat; interface uses FMath, Matrices; { ---------------------------------------------------------------------- Common input parameters : X : Vector of statistical variable Lbound, Ubound : Indices of first and last elements of X W : Vector of weights ---------------------------------------------------------------------- } procedure QSort(X : PVector; Lbound, Ubound : Integer); { ---------------------------------------------------------------------- Sorts the elements of vector X in increasing order (quick sort) ---------------------------------------------------------------------- } procedure DQSort(X : PVector; Lbound, Ubound : Integer); { ---------------------------------------------------------------------- Sorts the elements of vector X in decreasing order (quick sort) ---------------------------------------------------------------------- } function Median(X : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Sorts vector X is ascending order and returns its median value ---------------------------------------------------------------------- } function Sum(X : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the sum of the elements of vector X ---------------------------------------------------------------------- } function SumSqr(X : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the sum of squared elements of vector X ---------------------------------------------------------------------- } function SumSqrDif(X : PVector; Lbound, Ubound : Integer; A : Float) : Float; { ---------------------------------------------------------------------- Returns the sum of squared differences between the elements of vector X and the constant A ---------------------------------------------------------------------- } function SumSqrDifVect(X, Y : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the sum of squared differences between two vectors ---------------------------------------------------------------------- } function SumWSqr(X, W : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the sum of weighted squared elements of vector X ---------------------------------------------------------------------- } function SumWSqrDif(X, W : PVector; Lbound, Ubound : Integer; A : Float) : Float; { ---------------------------------------------------------------------- Returns the sum of weighted squared differences between the elements of vector X and the constant A ---------------------------------------------------------------------- } function SumWSqrDifVect(X, Y, W : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the sum of weighted squared differences between two vectors ---------------------------------------------------------------------- } function Average(X : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the average value of vector X ---------------------------------------------------------------------- } function Variance(X : PVector; Lbound, Ubound : Integer; Avg : Float) : Float; { ---------------------------------------------------------------------- Returns the variance of vector X, with average Avg ---------------------------------------------------------------------- } function EstVar(X : PVector; Lbound, Ubound : Integer; Avg : Float) : Float; { ---------------------------------------------------------------------- Returns the estimated variance of the population to which vector X belongs ---------------------------------------------------------------------- } function Skewness(X : PVector; Lbound, Ubound : Integer; Avg, Sigma : Float) : Float; { ---------------------------------------------------------------------- Returns the skewness of vector X, with average Avg and standard deviation Sigma ---------------------------------------------------------------------- } function Kurtosis(X : PVector; Lbound, Ubound : Integer; Avg, Sigma : Float) : Float; { ---------------------------------------------------------------------- Returns the kurtosis of vector X, with average Avg and standard deviation Sigma ---------------------------------------------------------------------- } procedure RanMult(M : PVector; L : PMatrix; N : Integer; X : PVector); { ---------------------------------------------------------------------- Samples a vector X from the N-dimensioned multinormal distribution with mean vector M. L is the Cholesky factor of the variance-covariance matrix. ---------------------------------------------------------------------- } implementation procedure QSort(X : PVector; Lbound, Ubound : Integer); { Quick sort in ascending order - Adapted from Borland's BP7 demo } procedure Sort(L, R : Integer); var I, J : Integer; U, V : Float; begin I := L; J := R; U := X^[(L + R) div 2]; repeat while X^[I] < U do I := I + 1; while U < X^[J] do J := J - 1; if I <= J then begin V := X^[I]; X^[I] := X^[J]; X^[J] := V; I := I + 1; J := J - 1; end; until I > J; if L < J then Sort(L, J); if I < R then Sort(I, R); end; begin Sort(Lbound, Ubound); end; procedure DQSort(X : PVector; Lbound, Ubound : Integer); { Quick sort in descending order - Adapted from Borland's BP7 demo } procedure Sort(L, R : Integer); var I, J : Integer; U, V : Float; begin I := L; J := R; U := X^[(L + R) div 2]; repeat while X^[I] > U do I := I + 1; while U > X^[J] do J := J - 1; if I <= J then begin V := X^[I]; X^[I] := X^[J]; X^[J] := V; I := I + 1; J := J - 1; end; until I > J; if L < J then Sort(L, J); if I < R then Sort(I, R); end; begin Sort(Lbound, Ubound); end; function Median(X : PVector; Lbound, Ubound : Integer) : Float; var N, N2 : Integer; begin N := Ubound - Lbound + 1; N2 := N div 2 + Lbound - 1; QSort(X, Lbound, Ubound); if Odd(N) then Median := X^[N2 + 1] else Median := 0.5 * (X^[N2] + X^[N2 + 1]); end; function Sum(X : PVector; Lbound, Ubound : Integer) : Float; var S : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do S := S + X^[I]; Sum := S; end; function SumSqr(X : PVector; Lbound, Ubound : Integer) : Float; var S : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do S := S + Sqr(X^[I]); SumSqr := S; end; function SumSqrDif(X : PVector; Lbound, Ubound : Integer; A : Float) : Float; var S : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do S := S + Sqr(X^[I] - A); SumSqrDif := S; end; function SumSqrDifVect(X, Y : PVector; Lbound, Ubound : Integer) : Float; var S : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do S := S + Sqr(X^[I] - Y^[I]); SumSqrDifVect := S; end; function SumWSqr(X, W : PVector; Lbound, Ubound : Integer) : Float; var S : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do S := S + W^[I] * Sqr(X^[I]); SumWSqr := S; end; function SumWSqrDif(X, W : PVector; Lbound, Ubound : Integer; A : Float) : Float; var S : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do S := S + W^[I] * Sqr(X^[I] - A); SumWSqrDif := S; end; function SumWSqrDifVect(X, Y, W : PVector; Lbound, Ubound : Integer) : Float; var S : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do S := S + W^[I] * Sqr(X^[I] - Y^[I]); SumWSqrDifVect := S; end; function Average(X : PVector; Lbound, Ubound : Integer) : Float; begin Average := Sum(X, Lbound, Ubound) / (Ubound - Lbound + 1); end; function Variance(X : PVector; Lbound, Ubound : Integer; Avg : Float) : Float; begin Variance := SumSqrDif(X, Lbound, Ubound, Avg) / (Ubound - Lbound + 1); end; function EstVar(X : PVector; Lbound, Ubound : Integer; Avg : Float) : Float; begin EstVar := SumSqrDif(X, Lbound, Ubound, Avg) / (Ubound - Lbound); end; function Skewness(X : PVector; Lbound, Ubound : Integer; Avg, Sigma : Float) : Float; var S, T : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do begin T := (X^[I] - Avg) / Sigma; S := S + T * Sqr(T); end; Skewness := S / (Ubound - Lbound + 1); end; function Kurtosis(X : PVector; Lbound, Ubound : Integer; Avg, Sigma : Float) : Float; var S, T : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do begin T := (X^[I] - Avg) / Sigma; S := S + Sqr(Sqr(T)); end; Kurtosis := S / (Ubound - Lbound + 1) - 3.0; end; procedure RanMult(M : PVector; L : PMatrix; N : Integer; X : PVector); var U : PVector; I, J : Integer; begin { Form a vector of N independent standard normal variates } DimVector(U, N); for I := 1 to N do U^[I] := RanGaussStd; { Form X = M + L*U, which follows the multinormal distribution } for I := 1 to N do begin X^[I] := M^[I]; for J := 1 to I do X^[I] := X^[I] + L^[I]^[J] * U^[J]; end; DelVector(U, N); end; end. �������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/fitlin.pas�����������������������������������������0000755�0001750�0001750�00000006435�11326425446�021270� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITLIN.PAS * * Version 1.0 * * (c) J. Debord, April 1998 * ********************************************************************** This unit fits a linear function : y = a + b.x ********************************************************************** } unit FitLin; {$F+} interface uses FMath, Matrices, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; implementation function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } begin FuncName := 'y = a + b.x'; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 1; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'a'; 1 : ParamName := 'b'; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = a B^[1] = b -------------------------------------------------------------------- } begin RegFunc := B^[0] + B^[1] * X; end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; { -------------------------------------------------------------------- Fit the straight line -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters V = variance-covariance matrix of the parameters -------------------------------------------------------------------- } begin case Method of 0 : FitModel := LinFit(X, Y, N, B, V); 1 : FitModel := WLinFit(X, Y, W, N, B, V); end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/plotvar.inc����������������������������������������0000755�0001750�0001750�00000006737�07316774504�021473� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * PLOTVAR.INC * ********************************************************************** Constants, types and global variables common to PLOT.PAS and TEXPLOT.PAS ********************************************************************** } const MAXSYMBOL = 9; { Max. number of graphic symbols } EPS = 1.0E-10; { Lower limit for an axis label } type TScale = (LIN_SCALE, { Scale } LOG_SCALE); TGrid = (NO_GRID, { Grid } HORIZ_GRID, VERTIC_GRID, BOTH_GRID); TAxis = record { Coordinate axis } Scale : TScale; Min : Float; Max : Float; Step : Float; end; TTitle = record { Title for main graph or axis } Text : String[70]; Font : Integer; CharWidth : Integer; CharHeight : Integer; end; TLegend = record { Legends of plotted curves } Text : array[1..MAXSYMBOL] of String[40]; Font : Integer; CharWidth : Integer; CharHeight : Integer; SymbolSize : Integer; end; { ******** Global variables defining the appearance of the graph ******* } const Xwin1 : Integer = 15; { Window limits in % } Ywin1 : Integer = 15; Xwin2 : Integer = 85; Ywin2 : Integer = 85; GraphBorder : Boolean = True; { Plot graph border } XAxis : TAxis = (Scale : LIN_SCALE; { Horizontal axis } Min : 0.0; Max : 1.0; Step : 0.2); YAxis : TAxis = (Scale : LIN_SCALE; { Vertical axis } Min : 0.0; Max : 1.0; Step : 0.2); Grid : TGrid = NO_GRID; { Grid } GraphTitle : TTitle = (Text : ''; { Title of graph } Font : 2; CharWidth : 300; CharHeight : 350); XTitle : TTitle = (Text : 'X'; { Title of X axis } Font : 2; CharWidth : 200; CharHeight : 250); YTitle : TTitle = (Text : 'Y'; { Title of Y axis } Font : 2; CharWidth : 200; CharHeight : 250); Legend : TLegend = (Text : ('A', { Legends of curves } 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'); Font : 2; CharWidth : 50; CharHeight : 50; SymbolSize : 3); ���������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/regmultdelphi.pas����������������������������������0000755�0001750�0001750�00000050220�11326425446�022637� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Program REGMULT.PAS * * Version 1.1 * * (c) J. Debord, August 2000 * ********************************************************************** This program performs a weighted multiple linear least squares fit : y = b0 + b1 * x1 + b2 * x2 + ... The following parameters are passed on the command line : 1st parameter = name of input file (default extension = .DAT) 2nd parameter = 1 if the equation includes a constant term b0 Input files are ASCII files with the following structure : Line 1 : Title of study Line 2 : Number of variables (must be >= 2 here !) Next lines : Names of variables x1, x2, ..., y Next line : Number of observations (must be > number of variables !) The next lines contain the coordinates (x1, x2, ..., y) of the observations (1 observation by line). The coordinates must be separated by spaces or tabulations. The file INHIB.DAT is an example of data relating the inhibition of an enzyme to the physico-chemical properties of the inhibitors (J. DEBORD, P. N'DIAYE, J. C. BOLLINGER et al, J. Enzyme Inhib., 1997, 12, 13-26). The program parameters are : INHIB 1 The program may be executed from Turbo Pascal's integrated environment, in which case the parameters are entered through the "Parameters" option of the menu, or from DOS (after compilation into an executable file), in which case the parameters are entered on the command line (e.g. REGMULT INHIB 1). ********************************************************************** } unit RegMultDelphi; interface uses SysUtils,FMath, Matrices, Regress, Models, PaString,messages,dialogs,classes,define_types; const kMaxRA = 127; kCR = chr (13); kMaxObs = 100; kMaxFact = 64; //type // TIVra = array [1..kMaxFact,1..kMaxObs] of integer; {SpaceType = record mrix,mriy,mriz,fobx,foby,fobz: integer; end;} function MultipleRegression (lnObservations,lnFactors: integer; var X: PMatrix; var lImgIntensity: DoubleP0; var lOutT: DoubleP0): boolean; function MultipleRegressionVec (lnObservations,lnFactors: integer; var X: PMatrix; var Y: PVector; var lOutT,lOutSlope: DoubleP0): boolean; //var // gMRIFOBra: array [1..kMaxRA] of SpaceType; // gCoregRA: array[1..3,0..3] of double; {MRIx,y,z, Offset,FOBx,FOBy,FOBz} implementation (*var InFName : String; { Name of input file } Title : String; { Title of study } XName : PStrVector; { Names of independent variables } YName : String; { Name of dependent variable } N : Integer; { Number of observations } X : PMatrix; { Matrix of independent variables } Y : PVector; { Vector of dependent variable } Z : PVector; { Vector of independent variable (not used here) } Ycalc : PVector; { Expected Y values } S : PVector; { Standard deviations of Y values } CstPar : PVector; { Constant parameters } B : PVector; { Regression parameters } B_min, B_max : PVector; { Parameter bounds (not used, but must be declared in order to use the WLSFit routine ) } V : PMatrix; { Variance-covariance matrix of regression parameters } Theta : PVector; { Variance parameters } RegTest : TRegTest; { Regression tests } gErrCode : Integer; { Error code } *) (* procedure ReadCmdLine(var InFName : String; var CstPar : PVector); { ---------------------------------------------------------------------- Reads command line parameters. Stores constant parameters in CstPar, such that : CstPar^[0] = Number of independent variables (this one is set by ReadInputFile) CstPar^[1] = 1 to include a constant term (b0) The contents of CstPar are defined in the unit FITMULT.PAS, in the subdirectory REG of the TP Math units directory. ---------------------------------------------------------------------- } var I : Integer; begin DimVector(CstPar, 1); { Name of input file } InFName := ParamStr(1); if Pos('.', InFName) = 0 then InFName := InFName + '.dat'; { Presence of constant term } //I := 0; Val(ParamStr(2), I, gErrCode); CstPar^[1] := I; end; function ReadInputFile(InFName : String; var Title : String; var XName : PStrVector; var YName : String; var N : Integer; var X : PMatrix; var Y : PVector; CstPar : PVector) : Integer; var InF : Textfile; { Input file } Nvar : Integer; { Nb of independent variables } I, K : Integer; { Loop variables } begin Assign(InF, InFName); Reset(InF); ReadLn(InF, Title); ReadLn(InF, Nvar); { Total number of variables } if Nvar < 2 then begin showmessage('Data file must contain at least 2 variables !'); ReadInputFile := - 1; Exit; end; Nvar := Pred(Nvar); showmessage('trap3x'+inttostr(NVar)); DimStrVector(XName, Nvar);{crashes here} showmessage('trap4x'+inttostr(NVar)); for I := 1 to Nvar do begin ReadLn(InF, XName^[I]); showmessage(XName^[I]); end; ReadLn(InF, YName); ReadLn(InF, N); DimMatrix(X, Nvar, N); DimVector(Y, N); for K := 1 to N do begin for I := 1 to Nvar do Read(InF, X^[I]^[K]); Read(InF, Y^[K]); end; Close(InF); CstPar^[0] := Nvar; ReadInputFile := 0; end; procedure WriteOutputFile(InFName, Title : String; XName : PStrVector; YName : String; N : Integer; Y, CstPar, Ycalc, S, B : PVector; V : PMatrix; Test : TRegTest); var OutFName : String; { Name of output file } OutF : TextFile; { Output file } Line1, Line2 : String; { Separating lines } Nvar : Integer; { Nb of independent variables } Delta : Float; { Residual } Sr : Float; { Residual error } SB : PVector; { Standard deviations of parameters } T : PVector; { Student's t } Prob : PVector; { Probabilities } I, K : Integer; { Loop variables } begin Nvar := Round(CstPar^[0]); DimVector(SB, LastParam); DimVector(T, LastParam); DimVector(Prob, LastParam); K := Pos('.', InFName); OutFName := Copy(InFName, 1, Pred(K)) + '.out'; Assign(OutF, OutFName); Rewrite(OutF); Line1 := StrChar(73, '-'); Line2 := StrChar(73, '='); WriteLn(OutF, Line2); WriteLn(OutF, 'Data file : ', InFName); WriteLn(OutF, 'Study name : ', Title); for I := 1 to Nvar do WriteLn(OutF, 'x', I:1, ' : ', XName^[I]); WriteLn(OutF, 'y : ', YName); WriteLn(OutF, 'Function : ', FuncName); { Perform tests on parameters } ParamTest(B, V, N, FirstParam, LastParam, SB, T, Prob); WriteLn(OutF, Line1); WriteLn(OutF, 'Parameter Est.value Std.dev. t Student Prob(>|t|)'); WriteLn(OutF, Line1); showmessage(inttostr(nVar)+':'+inttostr(FirstParam)+':'+inttostr(LastParam)); for I := FirstParam to LastParam do if SB^[I] > 0.0 then WriteLn(OutF, ParamName(I):5, B^[I]:17:8, SB^[I]:17:8, T^[I]:17:2, Prob^[I]:17:4) else WriteLn(OutF, ParamName(I):5, B^[I]:17:8); WriteLn(OutF, Line1); WriteLn(OutF, 'Number of observations : n = ', N:5); with Test do begin Sr := Sqrt(Vr); WriteLn(OutF, 'Residual error : s = ', Sr:10:8); if (R2 >= 0.0) and (R2 <= 1.0) then WriteLn(OutF, 'Coefficient of determination : r2 = ', R2:10:8); if (R2a >= 0.0) and (R2a <= 1.0) then WriteLn(OutF, 'Adjusted coeff. of determination : r2a = ', R2a:10:8); Write(OutF, 'Variance ratio (explained/resid.) : F = ', F:10:4); WriteLn(OutF, ' Prob(>F) = ', Prob:6:4); end; WriteLn(OutF, Line1); WriteLn(OutF, ' i Y obs. Y calc. Residual Std.dev. Std.res.'); WriteLn(OutF, Line1); for K := 1 to N do begin Delta := Y^[K] - Ycalc^[K]; WriteLn(OutF, K:3, Y^[K]:14:4, Ycalc^[K]:14:4, Delta:14:4, S^[K]:14:4, (Delta / S^[K]):14:4); end; WriteLn(OutF, Line2); Close(OutF); Showmessage('Results written to file '+OutFName); DelVector(SB, LastParam); DelVector(T, LastParam); DelVector(Prob, LastParam); end; { *************************** Main program ***************************** } procedure RunReg; begin { Read command line parameters } //ReadCmdLine(InFName, CstPar); InFName := 'C:\inhib.dat'; DimVector(CstPar, 1); CstPar^[1] := 1; { Read input file } if ReadInputFile(InFName, Title, XName, YName, N, X, Y, CstPar) <> 0 then begin showmessage('Error reading file '+ InFName); exit; end; { Initialize regression and variance models. See MODELS.PAS in the REG subdirectory for a list of available models } InitModel(REG_MULT, VAR_CONST, { Here we use a constant variance } CstPar); { Set the regression algorithm which must be GAUSS_JORDAN or SVD. The default algorithm is SVD. Comment off the following line if you wish to change the algorithm. } { SetRegAlgo(GAUSS_JORDAN); } { Dimension arrays. Note: the variance parameters Theta^[1]..Theta^[LastVarParam] must be supplied if we use a non-constant variance model } DimVector(Theta, LastVarParam); DimVector(B, LastParam); DimMatrix(V, LastParam, LastParam); DimVector(Ycalc, N); DimVector(S, N); { Perform regression. The numbers 1 and 0.1 denote the maximal number of iterations and the tolerance on the parameters. They are purely formal values here since the multiple linear regression does not use an iterative minimization algorithm. } gErrCode := WLSFit(Z, X, Y, N, True, 1, 0.1, Theta, B, B_min, B_max, V, Ycalc, S, RegTest); { Write results } case gErrCode of MAT_OK : WriteOutputFile(InFName, Title, XName, YName, N, Y, CstPar, Ycalc, S, B, V, RegTest); MAT_SINGUL : WriteLn('Singular matrix !'); MAT_NON_CONV : WriteLn('Non-convergence of SVD algorithm !'); end; end; *) //ComputeRegress(lnObservations,lnFactors, Y, CstPar, Ycalc, S, B, V, lRegTest); procedure ComputeRegress (N,lnFactors : Integer; var Y, CstPar, Ycalc, S, B : PVector; var V : PMatrix; var Test : TRegTest; var lOutT: DoubleP0); var I: integer; SB : PVector; { Standard deviations of parameters } T : PVector; { Student's t } Prob : PVector; { Probabilities } begin DimVector(SB, LastParam); DimVector(T, LastParam); DimVector(Prob, LastParam); { Perform tests on parameters } ParamTest(B, V, N, FirstParam, LastParam, SB, T, Prob); for I := 0 to (lnFactors-1) do lOutT[I] := T^[FirstParam+I+1];//first parameter is global fit lOutT[lnFactors] := T^[FirstParam];//global fit //for I := FirstParam to LastParam do // Showmessage(floattostr(T^[I]) ); DelVector(SB, LastParam); DelVector(T, LastParam); DelVector(Prob, LastParam); end; (* procedure ScreenOutputFile( var YName : String; N,ldimension : Integer; var Y, CstPar, Ycalc, S, B : PVector; var V : PMatrix; var Test : TRegTest; var lDynStr: String); var lA,lB,lC,lD : String; { Name of output file } Nvar : Integer; { Nb of independent variables } Delta : Float; { Residual } Sr : Float; { Residual error } SB : PVector; { Standard deviations of parameters } T : PVector; { Student's t } Prob : PVector; { Probabilities } I, K : Integer; { Loop variables } begin Nvar := Round(CstPar^[0]); DimVector(SB, LastParam); DimVector(T, LastParam); DimVector(Prob, LastParam); { Perform tests on parameters } ParamTest(B, V, N, FirstParam, LastParam, SB, T, Prob); lDynStr:=lDynStr+'|'+( 'Parameter Est.value Std.dev. t Student Prob(>|t|)'); //showmessage(inttostr(nVar)+':'+inttostr(FirstParam)+':'+inttostr(LastParam)); for I := FirstParam to LastParam do begin if SB^[I] > 0.0 then begin Str(B^[I]:17:8,lA); Str(SB^[I]:17:8,lB); Str(T^[I]:17:2,lC); Str(Prob^[I]:17:4,lD); lDynStr:=lDynStr+'|'+(ParamName(I)+lA+lB+'T='+lC+lD); end else begin B^[I]:= 0; Str(B^[I]:17:8,lA); lDynStr:=lDynStr+'|'+(ParamName(I)+lA); end; //gCoregRA[lDImension,I]:= B^[I]; end; DelVector(SB, LastParam); DelVector(T, LastParam); DelVector(Prob, LastParam); end; *) //function PredictData(lnObservations: integer; var lStr: tstringlist): boolean; function MultipleRegression (lnObservations,lnFactors: integer; var X: PMatrix; var lImgIntensity: DoubleP0; var lOutT: DoubleP0): boolean; var K : Integer; { Nb of independent variables } //X : PMatrix; { Matrix of independent variables } Y : PVector; { Vector of dependent variable } Z : PVector; { Vector of independent variable (not used here) } Ycalc : PVector; { Expected Y values } S : PVector; { Standard deviations of Y values } CstPar : PVector; { Constant parameters } B : PVector; { Regression parameters } B_min, B_max : PVector; { Parameter bounds (not used, but must be declared in order to use the WLSFit routine ) } V : PMatrix; { Variance-covariance matrix of regression parameters } Theta : PVector; { Variance parameters } lRegTest : TRegTest; { Regression tests } gErrCode : Integer; { Error code } begin result := false; if lnObservations < 5 then begin showmessage('At least 5 samples required for 3D registration.'); exit; end; DimVector(CstPar, 1); DimVector(Y, lnObservations); CstPar^[1] := 1; CstPar^[0] := lnFactors; for K := 1 to lnObservations do Y^[K] := lImgIntensity[K-1]; { Initialize regression and variance models.} InitModel(REG_MULT,VAR_CONST,{ Here we use a constant variance }CstPar); { Set the regression algorithm which must be GAUSS_JORDAN or SVD. The default algorithm is SVD. Comment off the following line if you wish to change the algorithm. } { SetRegAlgo(GAUSS_JORDAN); } DimVector(Theta, LastVarParam); DimVector(B, LastParam); DimMatrix(V, LastParam, LastParam); DimVector(Ycalc, lnObservations); DimVector(S, lnObservations); { Perform regression. The numbers 1 and 0.1 denote the maximal number of iterations and the tolerance on the parameters. They are purely formal values here since the multiple linear regression does not use an iterative minimization algorithm. } gErrCode := WLSFit(Z, X, Y, lnObservations, True, 1, 0.1, Theta, B,B_min, B_max, V, Ycalc, S, lRegTest); { Write results } //showmessage(inttostr(xx)); case gErrCode of MAT_OK : begin //ScreenOutputFile({XName,}YName,lnObservations,lDim, Y, CstPar, Ycalc, S, B, V, lRegTest,lStr); //Showmessage(lStr); ComputeRegress(lnObservations,lnFactors, Y, CstPar, Ycalc, S, B, V, lRegTest,lOutT); end; { MAT_OK : WriteOutputFile(InFName, Title, XName, YName, N, Y, CstPar, Ycalc, S, B, V, RegTest); } MAT_SINGUL : Showmessage('Singular matrix !'); MAT_NON_CONV : Showmessage('Non-convergence of SVD algorithm !'); end; DelVector(CstPar, 1); DelVector(Y, lnObservations); //DelStrVector(XName,lnXFactors); DelVector(Theta, LastVarParam); DelVector(B, LastParam); DelMatrix(V, LastParam, LastParam); DelVector(Ycalc, lnObservations); DelVector(S, lnObservations); result := true; end; function MultipleRegressionVec (lnObservations,lnFactors: integer; var X: PMatrix; var Y: PVector; var lOutT,lOutSlope: DoubleP0): boolean; var K : Integer; { Nb of independent variables } Z : PVector; { Vector of independent variable (not used here) } Ycalc : PVector; { Expected Y values } S : PVector; { Standard deviations of Y values } CstPar : PVector; { Constant parameters } B : PVector; { Regression parameters } B_min, B_max : PVector; { Parameter bounds (not used, but must be declared in order to use the WLSFit routine ) } V : PMatrix; { Variance-covariance matrix of regression parameters } Theta : PVector; { Variance parameters } lRegTest : TRegTest; { Regression tests } gErrCode : Integer; { Error code } begin result := false; if lnObservations < 5 then begin showmessage('At least 5 samples required for 3D registration.'); exit; end; DimVector(CstPar, 1); CstPar^[1] := 1; CstPar^[0] := lnFactors; { Initialize regression and variance models.} InitModel(REG_MULT,VAR_CONST,{ Here we use a constant variance }CstPar); { Set the regression algorithm which must be GAUSS_JORDAN or SVD. The default algorithm is SVD. Comment off the following line if you wish to change the algorithm. } { SetRegAlgo(GAUSS_JORDAN); } DimVector(Theta, LastVarParam); DimVector(B, LastParam); DimMatrix(V, LastParam, LastParam); DimVector(Ycalc, lnObservations); DimVector(S, lnObservations); { Perform regression. The numbers 1 and 0.1 denote the maximal number of iterations and the tolerance on the parameters. They are purely formal values here since the multiple linear regression does not use an iterative minimization algorithm. } gErrCode := WLSFit(Z, X, Y, lnObservations, True, 1, 0.1, Theta, B,B_min, B_max, V, Ycalc, S, lRegTest); { Write results } //showmessage(inttostr(xx)); case gErrCode of MAT_OK : begin //ScreenOutputFile({XName,}YName,lnObservations,lDim, Y, CstPar, Ycalc, S, B, V, lRegTest,lStr); //Showmessage(lStr); ComputeRegress(lnObservations,lnFactors, Y, CstPar, Ycalc, S, B, V, lRegTest,lOutT); end; { MAT_OK : WriteOutputFile(InFName, Title, XName, YName, N, Y, CstPar, Ycalc, S, B, V, RegTest); } MAT_SINGUL : Showmessage('Singular matrix !'); MAT_NON_CONV : Showmessage('Non-convergence of SVD algorithm !'); end; for K := 0 to (lnFactors-1) do lOutSlope^[K] := B^[FirstParam+K+1];//first parameter is global fit lOutSlope^[lnFactors] := B^[FirstParam];//global fit DelVector(CstPar, 1); //DelVector(Y, lnObservations); //DelStrVector(XName,lnXFactors); DelVector(Theta, LastVarParam); DelVector(B, LastParam); DelMatrix(V, LastParam, LastParam); DelVector(Ycalc, lnObservations); DelVector(S, lnObservations); result := true; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/fcomp.pas������������������������������������������0000755�0001750�0001750�00000043407�11326425446�021107� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FCOMP.PAS * * Version 1.1 * * (c) J. Debord, July 2000 * ********************************************************************** Complex functions for TPMATH (Based on CMPLX.ZIP by E.F. Glynn) ********************************************************************** } unit FComp; interface uses FMath; { ********************************************************************** Complex type ********************************************************************** } type ComplexForm = (Rec, Pol); { Rectangular or Polar form } Complex = record case Form : ComplexForm of Rec : (X, Y : Float); Pol : (R, Theta : Float); end; const C_infinity : Complex = (Form : Rec; X : MAXNUM; Y : 0.0); C_zero : Complex = (Form : Rec; X : 0.0; Y : 0.0); C_one : Complex = (Form : Rec; X : 1.0; Y : 0.0); C_i : Complex = (Form : Rec; X : 0.0; Y : 1.0); C_pi : Complex = (Form : Rec; X : PI; Y : 0.0); C_pi_div_2 : Complex = (Form : Rec; X : PIDIV2; Y : 0.0); { ********************************************************************** Complex number initialization and conversion ********************************************************************** } procedure CSet(var Z : Complex; A, B : Float; F : ComplexForm); { ---------------------------------------------------------------------- Initializes a complex number according to the form specified by F F = Rec ==> Z = A + i * B F = Pol ==> Z = A * Exp(i * B) ---------------------------------------------------------------------- } procedure CConvert(var Z : Complex; F : ComplexForm); { Converts the complex number Z to the form specified by F } procedure CSwap(var X, Y : Complex); { Exchanges two complex numbers } { ********************************************************************** Complex functions ********************************************************************** } function CReal(Z : Complex) : Float; { Re(Z) } function CImag(Z : Complex) : Float; { Im(Z) } function CAbs(Z : Complex) : Float; { |Z| } function CArg(Z : Complex) : Float; { Arg(Z) } function CSgn(Z : Complex) : Integer; { Complex sign } procedure CNeg(A : Complex; var Z : Complex); { Z = -A } procedure CConj(A : Complex; var Z : Complex); { Z = A* } procedure CAdd(A, B : Complex; var Z : Complex); { Z = A + B } procedure CSub(A, B : Complex; var Z : Complex); { Z = A - B } procedure CDiv(A, B : Complex; var Z : Complex); { Z = A / B } procedure CMult(A, B : Complex; var Z : Complex); { Z = A * B } procedure CLn(A : Complex; var Z : Complex); { Z = Ln(A) } procedure CExp(A : Complex; var Z : Complex); { Z = Exp(A) } procedure CPower(A, B : Complex; var Z : Complex); { Z = A^B } procedure CIntPower(A : Complex; N : Integer; var Z : Complex); { Z = A^N } procedure CRealPower(A : Complex; X : Float; var Z : Complex); { Z = A^X } procedure CSqrt(A : Complex; var Z : Complex); { Z = Sqrt(A) } procedure CRoot(A : Complex; K, N : Integer; var Z : Complex); { Z = A^(1/N) } procedure CSin(A : Complex; var Z : Complex); { Z = Sin(A) } procedure CCos(A : Complex; var Z : Complex); { Z = Cos(A) } procedure CTan(A : Complex; var Z : Complex); { Z = Tan(A) } procedure CArcSin(A : Complex; var Z : Complex); { Z = ArcSin(A) } procedure CArcCos(A : Complex; var Z : Complex); { Z = ArcCos(A) } procedure CArcTan(A : Complex; var Z : Complex); { Z = ArcTan(A) } procedure CSinh(A : Complex; var Z : Complex); { Z = Sinh(A) } procedure CCosh(A : Complex; var Z : Complex); { Z = Cosh(A) } procedure CTanh(A : Complex; var Z : Complex); { Z = Tanh(A) } procedure CArcSinh(A : Complex; var Z : Complex); { Z = ArcSinh(A) } procedure CArcCosh(A : Complex; var Z : Complex); { Z = ArcCosh(A) } procedure CArcTanh(A : Complex; var Z : Complex); { Z = ArcTanh(A) } procedure CLnGamma(A : Complex; var Z : Complex); { Z = Ln(Gamma(A)) } implementation {$IFDEF CPU387} {$DEFINE USE_ASM} {$ENDIF} {$IFDEF CPUP2} {$DEFINE USE_ASM} {$ENDIF} procedure CSet(var Z : Complex; A, B : Float; F : ComplexForm); begin Z.Form := F; if F = Pol then begin Z.R := A; Z.Theta := B; end else begin Z.X := A; Z.Y := B; end; end; function CAbs(Z : Complex) : Float; begin if Z.Form = Rec then CAbs := Pythag(Z.X, Z.Y) else CAbs := Z.R; end; function CArg(Z : Complex) : Float; begin if Z.Form = Rec then CArg := ArcTan2(Z.Y, Z.X) else CArg := Z.Theta; end; function CReal(Z : Complex) : Float; begin if Z.Form = Rec then CReal := Z.X else CReal := Z.R * {$IFDEF USE_ASM}fCos{$ELSE}Cos{$ENDIF}(Z.Theta); end; function CImag(Z : Complex) : Float; begin if Z.Form = Rec then CImag := Z.Y else CImag := Z.R * {$IFDEF USE_ASM}fSin{$ELSE}Sin{$ENDIF}(Z.Theta); end; function CSgn(Z : Complex) : Integer; var Re, Im : Float; begin Re := CReal(Z); if Re > 0.0 then CSgn := 1 else if Re < 0.0 then CSgn := - 1 else begin Im := CImag(Z); if Im > 0.0 then CSgn := 1 else if Im < 0.0 then CSgn := - 1 else CSgn := 0; end; end; procedure CConvert(var Z : Complex; F : ComplexForm); var A : Complex; begin if Z.Form = F then Exit; if Z.Form = Pol then begin { Polar-to-rectangular conversion } A.Form := Rec; A.X := Z.R * {$IFDEF USE_ASM}fCos{$ELSE}Cos{$ENDIF}(Z.Theta); A.Y := Z.R * {$IFDEF USE_ASM}fSin{$ELSE}Sin{$ENDIF}(Z.Theta); end else begin { Rectangular-to-polar conversion } A.Form := Pol; if Z.X = 0.0 then if Z.Y = 0.0 then A.R := 0.0 else if Z.Y > 0.0 then A.R := Z.Y else A.R := - Z.Y else A.R := CAbs(Z); A.Theta := ArcTan2(Z.Y, Z.X); end; Z := A; end; procedure CSwap(var X, Y : Complex); var Temp : Complex; begin Temp := X; X := Y; Y := Temp; end; procedure CNeg(A : Complex; var Z : Complex); begin Z.Form := A.Form; if A.Form = Pol then begin Z.R := A.R; Z.Theta := FixAngle(A.Theta + PI) end else begin Z.X := - A.X; Z.Y := - A.Y end; end; procedure CConj(A : Complex; var Z : Complex); begin Z.Form := A.Form; if A.Form = Pol then begin Z.R := A.R; Z.Theta := FixAngle(- A.Theta) end else begin Z.X := A.X; Z.Y := - A.Y end end; procedure CAdd(A, B : Complex; var Z : Complex); begin CConvert(A, Rec); CConvert(B, Rec); Z.Form := Rec; Z.X := A.X + B.X; Z.Y := A.Y + B.Y; end; procedure CSub(A, B : Complex; var Z : Complex); begin CConvert(A, Rec); CConvert(B, Rec); Z.Form := Rec; Z.X := A.X - B.X; Z.Y := A.Y - B.Y; end; procedure CMult(A, B : Complex; var Z : Complex); begin CConvert(B, A.Form); { arbitrarily convert one to type of other } Z.Form := A.Form; if A.Form = Pol then begin Z.R := A.R * B.R; Z.Theta := FixAngle(A.Theta + B.Theta) end else begin Z.X := A.X * B.X - A.Y * B.Y; Z.Y := A.X * B.Y + A.Y * B.X end; end; procedure CDiv(A, B : Complex; var Z : Complex); var Temp : Float; begin if ((B.Form = Rec) and (B.X = 0.0) and (B.Y = 0.0)) or ((B.Form = Pol) and (B.R = 0.0)) then begin MathErr := FN_OVERFLOW; Z := C_infinity; Exit; end; CConvert(B, A.Form); { arbitrarily convert one to type of other } Z.Form := A.Form; if A.Form = Pol then begin Z.R := A.R / B.R; Z.Theta := FixAngle(A.Theta - B.Theta); end else begin Temp := Sqr(B.X) + Sqr(B.Y); Z.X := (A.X * B.X + A.Y * B.Y) / Temp; Z.Y := (A.Y * B.X - A.X * B.Y) / Temp; end; end; procedure CLn(A : Complex; var Z : Complex); var LnR : Float; begin CConvert(A, Pol); LnR := Log(A.R); if MathErr = FN_OK then CSet(Z, LnR, FixAngle(A.Theta), Rec) else CSet(Z, - MAXNUM, 0.0, Rec); end; procedure CExp(A : Complex; var Z : Complex); var ExpX, SinY, CosY : Float; begin CConvert(A, Rec); ExpX := Expo(A.X); if MathErr = FN_OK then begin SinY := {$IFDEF USE_ASM}fSin{$ELSE}Sin{$ENDIF}(A.Y); CosY := {$IFDEF USE_ASM}fCos{$ELSE}Cos{$ENDIF}(A.Y); CSet(Z, ExpX * CosY, ExpX * SinY, Rec); end else CSet(Z, ExpX, 0.0, Rec); end; procedure CPower(A, B : Complex; var Z : Complex); var BLnA, LnA : Complex; begin CConvert(A, Rec); CConvert(B, Rec); if (A.X = 0.0) and (A.Y = 0.0) then if (B.X = 0.0) and (B.Y = 0.0) then Z := C_one { lim a^a = 1 as a -> 0 } else Z := C_zero { 0^b = 0, b > 0 } else begin CLn(A, LnA); CMult(B, LnA, BLnA); CExp(BLnA, Z); end; end; procedure CIntPower(A : Complex; N : Integer; var Z : Complex); { CIntPower directly applies DeMoivre's theorem to calculate an integer power of a complex number. The formula holds for both positive and negative values of N } begin CConvert(A, Pol); if A.R = 0.0 then if N = 0 then Z := C_one else if N > 0 then Z := C_zero else begin MathErr := FN_SING; Z := C_infinity; end else CSet(Z, IntPower(A.R, N), FixAngle(N * A.Theta), Pol); end; procedure CRealPower(A : Complex; X : Float; var Z : Complex); begin CConvert(A, Pol); if A.R = 0.0 then if X = 0.0 then Z := C_one else if X > 0.0 then Z := C_zero else begin MathErr := FN_SING; Z := C_infinity; end else CSet(Z, Power(A.R, X), FixAngle(X * A.Theta), Pol); end; procedure CRoot(A : Complex; K, N : Integer; var Z : Complex); { CRoot can calculate all 'N' roots of 'A' by varying 'K' from 0..N-1 } { This is another application of DeMoivre's theorem. See CIntPower. } begin if (N <= 0) or (K < 0) or (K >= N) then begin MathErr := FN_DOMAIN; Z := C_zero; Exit; end; CConvert(A, Pol); if A.R = 0.0 then Z := C_zero else CSet(Z, Power(A.R, 1.0 / N), FixAngle((A.Theta + K * TWOPI) / N), Pol); end; procedure CSqrt(A : Complex; var Z : Complex); begin CConvert(A, Pol); if A.R = 0.0 then Z := C_zero else CSet(Z, Sqrt(A.R), FixAngle(0.5 * A.Theta), Pol); end; procedure CCos(A : Complex; var Z : Complex); var SinX, CosX, SinhY, CoshY : Float; begin CConvert(A, Rec); SinCos(A.X, SinX, CosX); SinhCosh(A.Y, SinhY, CoshY); { Called here to set MathErr } CSet(Z, CosX * CoshY, - SinX * SinhY, Rec) end; procedure CSin(A : Complex; var Z : Complex); var SinX, CosX, SinhY, CoshY : Float; begin CConvert(A, Rec); SinCos(A.X, SinX, CosX); SinhCosh(A.Y, SinhY, CoshY); { Called here to set MathErr } CSet(Z, SinX * CoshY, CosX * SinhY, Rec) end; procedure CTan(A : Complex; var Z : Complex); var X2, Y2, SinX2, CosX2, SinhY2, CoshY2, Temp : Float; begin CConvert(A, Rec); X2 := 2.0 * A.X; Y2 := 2.0 * A.Y; SinCos(X2, SinX2, CosX2); SinhCosh(Y2, SinhY2, CoshY2); if MathErr = FN_OK then Temp := CosX2 + CoshY2 else Temp := CoshY2; if Temp <> 0.0 then CSet(Z, SinX2 / Temp, SinhY2 / Temp, Rec) else begin { A = Pi/2 + k*Pi } MathErr := FN_SING; CSet(Z, MAXNUM, 0.0, Rec); end; end; procedure CCosh(A : Complex; var Z : Complex); var SinhX, CoshX, SinY, CosY : Float; begin CConvert(A, Rec); SinCos(A.Y, SinY, CosY); SinhCosh(A.X, SinhX, CoshX); CSet(Z, CoshX * CosY, SinhX * SinY, Rec) end; procedure CSinh(A : Complex; var Z : Complex); var SinhX, CoshX, SinY, CosY : Float; begin CConvert(A, Rec); SinCos(A.Y, SinY, CosY); SinhCosh(A.X, SinhX, CoshX); CSet(Z, SinhX * CosY, CoshX * SinY, Rec) end; procedure CTanh(A : Complex; var Z : Complex); var X2, Y2, SinY2, CosY2, SinhX2, CoshX2, Temp : Float; begin CConvert(A, Rec); X2 := 2.0 * A.X; Y2 := 2.0 * A.Y; SinCos(Y2, SinY2, CosY2); SinhCosh(X2, SinhX2, CoshX2); if MathErr = FN_OK then Temp := CoshX2 + CosY2 else Temp := CoshX2; if Temp <> 0.0 then CSet(Z, SinhX2 / Temp, SinY2 / Temp, Rec) else begin { A = i * (Pi/2 + k*Pi) } MathErr := FN_SING; CSet(Z, 0.0, MAXNUM, Rec); end; end; procedure CArcSin(A : Complex; var Z : Complex); var Rp, Rm, S, T, X2, XX, YY : Float; B : Complex; begin CConvert(A, Rec); CSet(B, A.Y, - A.X, Rec); { Y - i*X } X2 := 2.0 * A.X; XX := Sqr(A.X); YY := Sqr(A.Y); S := XX + YY + 1.0; Rp := 0.5 * Sqrt(S + X2); Rm := 0.5 * Sqrt(S - X2); T := Rp + Rm; Z.Form := Rec; Z.X := ArcSin(Rp - Rm); Z.Y := CSgn(B) * Log(T + Sqrt(Sqr(T) - 1.0)); end; procedure CArcCos(A : Complex; var Z : Complex); begin CArcSin(A, Z); CSub(C_pi_div_2, Z, Z); { Pi/2 - ArcSin(Z) } end; procedure CArcTan(A : Complex; var Z : Complex); var XX, Yp1, Ym1 : Float; begin CConvert(A, Rec); if (A.X = 0.0) and (Abs(A.Y) = 1.0) then { A = +/- i } begin MathErr := FN_SING; CSet(Z, 0.0, Sgn(A.Y) * MAXNUM, Rec); Exit; end; XX := Sqr(A.X); Yp1 := A.Y + 1.0; Ym1 := A.Y - 1.0; Z.Form := Rec; Z.X := 0.5 * (ArcTan2(A.X, - Ym1) - ArcTan2(- A.X, Yp1)); Z.Y := 0.25 * Log((XX + Sqr(Yp1)) / (XX + Sqr(Ym1))); end; procedure CArcSinh(A : Complex; var Z : Complex); { ArcSinH(A) = -i*ArcSin(i*A) } begin CMult(C_i, A, Z); CArcSin(Z, Z); CMult(C_i, Z, Z); CNeg(Z, Z); end; procedure CArcCosh(A : Complex; var Z : Complex); { ArcCosH(A) = CSgn(Y + i(1-X))*i*ArcCos(A) where A = X+iY } var B : Complex; begin CArcCos(A, Z); CMult(C_i, Z, Z); CSet(B, A.Y, 1.0 - A.X, Rec); { Y + i*(1-X) } if CSgn(B) = -1 then CNeg(Z, Z); end; procedure CArcTanh(A : Complex; var Z : Complex); { ArcTanH(A) = -i*ArcTan(i*A) } begin CConvert(A, Rec); if (Abs(A.X) = 1.0) and (A.Y = 0.0) then { A = +/- 1 } begin MathErr := FN_SING; CSet(Z, Sgn(A.X) * MAXNUM, 0.0, Rec); Exit; end; CMult(C_i, A, Z); CArcTan(Z, Z); CMult(C_i, Z, Z); CNeg(Z, Z); end; procedure CApproxLnGamma(Z : Complex; var Sum : Complex); { This is the approximation used in the National Bureau of Standards "Table of the Gamma Function for Complex Arguments," Applied Mathematics Series 34, 1954. The NBS table was created using this approximation over the area 9 < Re(z) < 10 and 0 < Im(z) < 10. Other table values were computed using the relationship: _ _ ln | (z+1) = ln z + ln | (z) } const C : array[1..8] of Float = (8.33333333333333E-02, - 2.77777777777778E-03, 7.93650793650794E-04, - 5.95238095238095E-04, 8.41750841750842E-04, - 1.91752691752692E-03, 6.41025641025641E-03, - 2.95506535947712E-02); var I : Integer; Powers : array[1..8] of Complex; Temp1, Temp2 : Complex; begin CConvert(Z, Rec); CLn(Z, Temp1); { Ln(Z) } CSet(Temp2, Z.X - 0.5, Z.Y, Rec); { Z - 0.5 } CMult(Temp1, Temp2, Sum); { (Z - 0.5)*Ln(Z) } CSub(Sum, Z, Sum); { (Z - 0.5)*ln(Z) - Z } Sum.X := Sum.X + LN2PIDIV2; Temp1 := C_one; CDiv(Temp1, Z, Powers[1]); { Z^(-1) } CMult(Powers[1], Powers[1], Temp2); { Z^(-2) } for I := 2 to 8 do CMult(Powers[I - 1], Temp2, Powers[I]); for I := 8 downto 1 do begin CSet(Temp1, C[I] * Powers[I].X, C[I] * Powers[I].Y, Rec); CAdd(Sum, Temp1, Sum); end end; procedure CLnGamma(A : Complex; var Z : Complex); var LnA, Temp : Complex; begin CConvert(A, Rec); if (A.X <= 0.0) and (A.Y = 0.0) then if (Int(A.X - 1E-8) - A.X) = 0.0 then { Negative integer? } begin MathErr := FN_SING; Z := C_infinity; Exit end; if A.Y < 0.0 then { 3rd or 4th quadrant? } begin CConj(A, A); CLnGamma(A, Z); { Try again in 1st or 2nd quadrant } CConj(Z, Z) { Left this out! 1/3/91 } end else begin if A.X < 9.0 then { "left" of NBS table range } begin CLn(A, LnA); CSet(A, A.X + 1.0, A.Y, Rec); CLnGamma(A, Temp); CSub(Temp, LnA, Z) end else CApproxLnGamma(A, Z) { NBS table range: 9 < Re(z) < 10 } end end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/winplot.pas����������������������������������������0000755�0001750�0001750�00000071142�11326425446�021474� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit WINPLOT.PAS * * Version 1.1 * * (c) J. Debord, October 1999 * ********************************************************************** Plotting routines for DELPHI ********************************************************************** } unit WinPlot; interface uses { DELPHI units } WinTypes, Graphics, { TPMath units } FMath, Matrices, Stat, PaString; { ************************* Constants and types ************************ } const MAXCURV = 255; { Max. number of curves which may be plotted } MAXSYMBOL = 9; { Max. number of symbols for plotting curves } EPS = 1.0E-10; { Lower limit for an axis label } type TScale = (LIN_SCALE, { Scale } LOG_SCALE); TGrid = (NO_GRID, { Grid } HORIZ_GRID, VERTIC_GRID, BOTH_GRID); TAxis = record { Coordinate axis } Scale : TScale; Min, Max, Step : Float; Title : String; end; TPointParam = record { Point parameters } Symbol : Integer; { Symbol index } Size : Integer; { Symbol size in 1/250 of graphic width } Color : TColor; end; TLineParam = record { Line parameters } Width : Integer; Style : TPenStyle; Color : TColor; end; TCurvParam = record { Curve parameters } PointParam : TPointParam; LineParam : TLineParam; Legend : String[30]; { Legend of curve } Step : Integer; { Plot 1 point every Step points } Connect : Boolean; { Connect points with line? } end; TCurvParamArray = array[1..MAXCURV] of TCurvParam; PCurvParamArray = ^TCurvParamArray; { ******** Global variables defining the appearance of the graph ******* } const Xwin1 : Integer = 15; { Window coordinates in percent of maximum } Ywin1 : Integer = 15; Xwin2 : Integer = 75; Ywin2 : Integer = 75; GraphBorder : Boolean = True; { For plotting a rectangle around the graph } XAxis : TAxis = (Scale : LIN_SCALE; { Horizontal axis } Min : 0.0; Max : 1.0; Step : 0.2; Title : 'X'); YAxis : TAxis = (Scale : LIN_SCALE; { Vertical axis } Min : 0.0; Max : 1.0; Step : 0.2; Title : 'Y'); Grid : TGrid = BOTH_GRID; { Grid } GraphTitle : String = ''; { Title of graph } { ************************** Graphic routines ************************** } procedure InitGraph(Canvas : TCanvas; Width, Height : Integer); { ---------------------------------------------------------------------- Initializes the graphic ---------------------------------------------------------------------- The parameters refer to the object on which the graphic is plotted. Examples: To draw on a TImage object: InitGraph(Image1.Canvas, Image1.Width, Image1.Height); To print the graphic: InitGraph(Printer.Canvas, Printer.PageWidth, Printer.PageHeight); ---------------------------------------------------------------------- } procedure PlotXAxis(Canvas : TCanvas); { ---------------------------------------------------------------------- Plots the X axis ---------------------------------------------------------------------- } procedure PlotYAxis(Canvas : TCanvas); { ---------------------------------------------------------------------- Plots the Y axis ---------------------------------------------------------------------- } procedure WriteTitle(Canvas : TCanvas); { ---------------------------------------------------------------------- Writes the title of the graph ---------------------------------------------------------------------- } procedure PlotGrid(Canvas : TCanvas); { ---------------------------------------------------------------------- Plots a grid on the graph ---------------------------------------------------------------------- } procedure PlotPoint(Canvas : TCanvas; X, Y : Float; PointParam : TPointParam); { ---------------------------------------------------------------------- Plots a point ---------------------------------------------------------------------- X, Y : point coordinates PointParam : point parameters ---------------------------------------------------------------------- } procedure PlotCurve(Canvas : TCanvas; X, Y : PVector; Lbound, Ubound : Integer; CurvParam : TCurvParam); { ---------------------------------------------------------------------- Plots a curve ---------------------------------------------------------------------- X, Y : point coordinates Lbound, Ubound : indices of first and last points CurvParam : curve parameters ---------------------------------------------------------------------- } procedure PlotCurveWithErrorBars(Canvas : TCanvas; X, Y, S : PVector; Ns : Integer; Lbound, Ubound : Integer; CurvParam : TCurvParam); { ---------------------------------------------------------------------- Plots a curve with error bars ---------------------------------------------------------------------- X, Y : point coordinates S : errors (e.g. standard deviations) Ns : error multiplier (e.g. 2 for plotting 2 SD's) Lbound, Ubound : indices of first and last points CurvParam : curve parameters ---------------------------------------------------------------------- } procedure PlotFunc(Canvas : TCanvas; Func : TFunc; Xmin, Xmax : Float; Npt : Integer; LineParam : TLineParam); { ---------------------------------------------------------------------- Plots a function ---------------------------------------------------------------------- Func : function to be plotted must be programmed as: function Func(X : Float) : Float; Xmin, Xmax : abscissae of 1st and last point to plot Npt : number of points LineParam : line parameters ---------------------------------------------------------------------- } procedure WriteLegend(Canvas : TCanvas; NCurv : Integer; CurvParam : PCurvParamArray; ShowPoints, ShowLines : Boolean); { ---------------------------------------------------------------------- Writes the legends for the plotted curves ---------------------------------------------------------------------- NCurv : number of curves (1 to MAXCURV) CurvParam : curve parameters ShowPoints : for displaying points ShowLines : for displaying lines ---------------------------------------------------------------------- } { *********** The following routines are defined in PLOT.INC *********** } procedure Interval(X1, X2 : Float; MinDiv, MaxDiv : Integer; var Min, Max, Step : Float); { ---------------------------------------------------------------------- Determines an interval [Min, Max] including the values from X1 to X2, and a subdivision Step of this interval ---------------------------------------------------------------------- Input parameters : X1, X2 = min. & max. values to be included MinDiv = minimum nb of subdivisions MaxDiv = maximum nb of subdivisions ---------------------------------------------------------------------- Output parameters : Min, Max, Step ---------------------------------------------------------------------- } procedure AutoScale(Z : PVector; Lbound, Ubound : Integer; var Axis : TAxis); { ---------------------------------------------------------------------- Determines the scale of an axis ---------------------------------------------------------------------- Input parameters : Z = array of values to be plotted Lbound, Ubound = indices of first and last elements of Z ---------------------------------------------------------------------- Output parameters : Axis ---------------------------------------------------------------------- } function Xpixel(X : Float) : Integer; { ---------------------------------------------------------------------- Converts user abscissa X to screen coordinate ---------------------------------------------------------------------- } function Ypixel(Y : Float) : Integer; { ---------------------------------------------------------------------- Converts user ordinate Y to screen coordinate ---------------------------------------------------------------------- } function Xuser(X : Integer) : Float; { ---------------------------------------------------------------------- Converts screen coordinate X to user abscissa ---------------------------------------------------------------------- } function Yuser(Y : Integer) : Float; { ---------------------------------------------------------------------- Converts screen coordinate Y to user ordinate ---------------------------------------------------------------------- } implementation uses Classes; var GraphWidth, GraphHeight, SymbolSizeUnit : Integer; { ---------------------------------------------------------------------- Include the variables and routines common to PLOT.PAS and WINPLOT.PAS ---------------------------------------------------------------------- } {$I PLOT.INC} { ---------------------------------------------------------------------- } procedure PlotXAxis(Canvas : TCanvas); var W, X, Z : Float; N, I, J, TickLength, MinorTickLength, Wp, Xp : Integer; XLabel : String; NSZ : Boolean; begin TickLength := Canvas.TextHeight('M') div 2; MinorTickLength := Round(0.67 * TickLength); { For log scale } { Draw axis } Canvas.MoveTo(XminPixel, YmaxPixel); Canvas.LineTo(XmaxPixel, YmaxPixel); NSZ := NSZero; NSZero := False; { Don't write non significant zero's } N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); { Nb of intervals } X := XAxis.Min; { Tick mark position } for I := 0 to N do { Label axis } begin if (XAxis.Scale = LIN_SCALE) and (Abs(X) < EPS) then X := 0.0; Xp := Xpixel(X); { Draw tick mark } Canvas.MoveTo(Xp, YmaxPixel); Canvas.LineTo(Xp, YmaxPixel + TickLength); { Write label } if XAxis.Scale = LIN_SCALE then Z := X else Z := Exp10(X); XLabel := Trim(PaString.FloatToStr(Z)); Canvas.TextOut(Xp - Canvas.TextWidth(XLabel) div 2, YmaxPixel + TickLength, XLabel); { Plot minor divisions on logarithmic scale } if (XAxis.Scale = LOG_SCALE) and (I < N) then for J := 2 to 9 do begin W := X + Log10(J); Wp := Xpixel(W); Canvas.MoveTo(Wp, YmaxPixel); Canvas.LineTo(Wp, YmaxPixel + MinorTickLength); end; X := X + XAxis.Step; end; NSZero := NSZ; { Write axis title } if XAxis.Title <> '' then Canvas.TextOut(XminPixel + (XmaxPixel - XminPixel - Canvas.TextWidth(XAxis.Title)) div 2, YmaxPixel + 2 * Canvas.TextHeight('M'), XAxis.Title); end; procedure PlotYAxis(Canvas : TCanvas); var W, Y, Z : Float; N, I, J, Wp, Yp : Integer; TickLength, MinorTickLength, Yoffset : Integer; YLabel : String; NSZ : Boolean; begin TickLength := Canvas.TextWidth('M') div 2; MinorTickLength := Round(0.67 * TickLength); { For log scale } Yoffset := Canvas.TextHeight('M') div 2; { Draw axis } Canvas.MoveTo(XminPixel, YminPixel); Canvas.LineTo(XminPixel, YmaxPixel); NSZ := NSZero; NSZero := False; { Don't write non significant zero's } N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); { Nb of intervals } Y := YAxis.Min; { Tick mark position } for I := 0 to N do { Label axis } begin if (YAxis.Scale = LIN_SCALE) and (Abs(Y) < EPS) then Y := 0.0; Yp := Ypixel(Y); { Draw tick mark } Canvas.MoveTo(XminPixel, Yp); Canvas.LineTo(XminPixel - TickLength, Yp); { Write label } if YAxis.Scale = LIN_SCALE then Z := Y else Z := Exp10(Y); YLabel := Trim(PaString.FloatToStr(Z)); Canvas.TextOut(XminPixel - TickLength - Canvas.TextWidth(YLabel), Yp - Yoffset, YLabel); { Plot minor divisions on logarithmic scale } if (YAxis.Scale = LOG_SCALE) and (I < N) then for J := 2 to 9 do begin W := Y + Log10(J); Wp := Ypixel(W); Canvas.MoveTo(XminPixel, Wp); Canvas.LineTo(XminPixel - MinorTickLength, Wp); end; Y := Y + YAxis.Step; end; NSZero := NSZ; { Write axis title } if YAxis.Title <> '' then Canvas.TextOut(XminPixel, YminPixel - 3 * Yoffset, YAxis.Title); end; procedure InitGraph(Canvas : TCanvas; Width, Height : Integer); begin GraphWidth := Width; GraphHeight := Height; SymbolSizeUnit := GraphWidth div 250; XminPixel := Round(Xwin1 / 100 * Width); YminPixel := Round(Ywin1 / 100 * Height); XmaxPixel := Round(Xwin2 / 100 * Width); YmaxPixel := Round(Ywin2 / 100 * Height); FactX := (XmaxPixel - XminPixel) / (XAxis.Max - XAxis.Min); FactY := (YmaxPixel - YminPixel) / (YAxis.Max - YAxis.Min); if GraphBorder then Canvas.Rectangle(XminPixel, YminPixel, Succ(XmaxPixel), Succ(YmaxPixel)); end; procedure WriteTitle(Canvas : TCanvas); begin if GraphTitle <> '' then with Canvas do TextOut((XminPixel + XmaxPixel - TextWidth(GraphTitle)) div 2, YminPixel - 2 * TextHeight(GraphTitle), GraphTitle); end; procedure PlotGrid(Canvas : TCanvas); var X, Y : Float; I, N, Xp, Yp : Integer; PenStyle : TpenStyle; begin { Save current settings } PenStyle := Canvas.Pen.Style; Canvas.Pen.Style := psDot; if Grid in [HORIZ_GRID, BOTH_GRID] then { Horizontal lines } begin N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); { Nb of intervals } for I := 1 to Pred(N) do begin Y := YAxis.Min + I * YAxis.Step; { Origin of line } Yp := Ypixel(Y); Canvas.MoveTo(XminPixel, Yp); Canvas.LineTo(XmaxPixel, Yp); end; end; if Grid in [VERTIC_GRID, BOTH_GRID] then { Vertical lines } begin N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); for I := 1 to Pred(N) do begin X := XAxis.Min + I * XAxis.Step; Xp := Xpixel(X); Canvas.MoveTo(Xp, YminPixel); Canvas.LineTo(Xp, YmaxPixel); end; end; { Restore settings } Canvas.Pen.Style := PenStyle; end; function XOutOfBounds(X : Integer) : Boolean; { Checks if an absissa is outside the graphic bounds } begin XOutOfBounds := (X < XminPixel) or (X > XmaxPixel); end; function YOutOfBounds(Y : Integer) : Boolean; { Checks if an ordinate is outside the graphic bounds } begin YOutOfBounds := (Y < YminPixel) or (Y > YmaxPixel); end; function CheckPoint(X, Y : Float; var Xp, Yp : Integer) : Boolean; { Computes the pixel coordinates of a point and checks if it is enclosed within the graph limits } begin Xp := Xpixel(X); Yp := Ypixel(Y); CheckPoint := not(XOutOfBounds(Xp) or YOutOfBounds(Yp)); end; procedure PlotSymbol(Canvas : TCanvas; Xp, Yp : Integer; Symbol, Size : Integer); { Plots a symbol at pixel coordinates (Xp, Yp) with the current canvas settings } var Xp1, Xp2, Yp1, Yp2 : Integer; begin if Symbol > 0 then begin Size := Size * SymbolSizeUnit; Xp1 := Xp - Size; Yp1 := Yp - Size; Xp2 := Xp + Size + 1; Yp2 := Yp + Size + 1; end; with Canvas do case Symbol of 0 : Pixels[Xp, Yp] := Brush.Color; 1, 2 : Ellipse(Xp1, Yp1, Xp2, Yp2); { Circle } 3, 4 : Rectangle(Xp1, Yp1, Xp2, Yp2); { Square } 5, 6 : Polygon([Point(Xp1, Yp2 - 1), Point(Xp2, Yp2 - 1), Point(Xp, Yp1 - 1)]); { Triangle } 7 : begin { + } MoveTo(Xp, Yp1); LineTo(Xp, Yp2); MoveTo(Xp1, Yp); LineTo(Xp2, Yp); end; 8 : begin { x } MoveTo(Xp1, Yp1); LineTo(Xp2, Yp2); MoveTo(Xp1, Yp2 - 1); LineTo(Xp2, Yp1 - 1); end; 9 : begin { * } MoveTo(Xp, Yp1); LineTo(Xp, Yp2); MoveTo(Xp1, Yp); LineTo(Xp2, Yp); MoveTo(Xp1, Yp1); LineTo(Xp2, Yp2); MoveTo(Xp1, Yp2 - 1); LineTo(Xp2, Yp1 - 1); end; end; end; procedure PlotLine(Canvas : TCanvas; Xp1, Yp1, Xp2, Yp2 : Integer); { Plots a line with the current canvas settings } begin Canvas.MoveTo(Xp1, Yp1); Canvas.LineTo(Xp2, Yp2); end; procedure PlotPoint(Canvas : TCanvas; X, Y : Float; PointParam : TPointParam); var Xp, Yp : Integer; BrushStyle : TBrushStyle; PenColor, BrushColor : TColor; begin if XAxis.Scale = LOG_SCALE then X := Log10(X); if YAxis.Scale = LOG_SCALE then Y := Log10(Y); if not CheckPoint(X, Y, Xp, Yp) then Exit; with Canvas do begin { Save current settings } PenColor := Pen.Color; BrushColor := Brush.Color; BrushStyle := Brush.Style; Pen.Color := PointParam.Color; Brush.Color := PointParam.Color; if PointParam.Symbol in [0, 1, 3, 5] then Brush.Style := bsSolid else Brush.Style := bsClear; PlotSymbol(Canvas, Xp, Yp, PointParam.Symbol, PointParam.Size); { Restore settings } Pen.Color := PenColor; Brush.Color := BrushColor; Brush.Style := BrushStyle; end; end; procedure PlotErrorBar(Canvas : TCanvas; Y, S : Float; Ns : Integer; Xp, Yp, Size : Integer); { Plots an error bar with the current canvas settings } var Delta, Y1 : Float; Yp1 : Integer; begin Size := Size * SymbolSizeUnit; Delta := Ns * S; Y1 := Y - Delta; if YAxis.Scale = LOG_SCALE then Y1 := Log10(Y1); Yp1 := Ypixel(Y1); if Yp1 <= YmaxPixel then begin PlotLine(Canvas, Xp - Size, Yp1, Xp + Size + 1, Yp1); PlotLine(Canvas, Xp, Yp, Xp, Yp1); end else PlotLine(Canvas, Xp, Yp, Xp, YmaxPixel); Y1 := Y + Delta; if YAxis.Scale = LOG_SCALE then Y1 := Log10(Y1); Yp1 := Ypixel(Y1); if Yp1 >= YminPixel then begin PlotLine(Canvas, Xp - Size, Yp1, Xp + Size + 1, Yp1); PlotLine(Canvas, Xp, Yp, Xp, Yp1); end else PlotLine(Canvas, Xp, Yp, Xp, YminPixel); end; procedure GenPlotCurve(Canvas : TCanvas; X, Y, S : PVector; Ns : Integer; Lbound, Ubound : Integer; CurvParam : TCurvParam; ErrorBars : Boolean); { General curve plotting routine } var X1, Y1, X2, Y2 : Float; Xp1, Yp1, Xp2, Yp2 : Integer; I : Integer; Flag1, Flag2 : Boolean; PenWidth : Integer; PenStyle : TpenStyle; PenColor, BrushColor : TColor; BrushStyle : TBrushStyle; begin with Canvas do begin { Save current settings } PenColor := Pen.Color; PenStyle := Pen.Style; PenWidth := Pen.Width; BrushColor := Brush.Color; BrushStyle := Brush.Style; Pen.Color := CurvParam.LineParam.Color; Pen.Style := CurvParam.LineParam.Style; Pen.Width := CurvParam.LineParam.Width; Brush.Color := CurvParam.PointParam.Color; if CurvParam.PointParam.Symbol in [0, 1, 3, 5] then Brush.Style := bsSolid else Brush.Style := bsClear; { Plot first point } X1 := X^[Lbound]; if XAxis.Scale = LOG_SCALE then X1 := Log10(X1); Y1 := Y^[Lbound]; if YAxis.Scale = LOG_SCALE then Y1 := Log10(Y1); Flag1 := CheckPoint(X1, Y1, Xp1, Yp1); if Flag1 then begin PlotSymbol(Canvas, Xp1, Yp1, CurvParam.PointParam.Symbol, CurvParam.PointParam.Size); if ErrorBars and (S^[Lbound] > 0.0) then PlotErrorBar(Canvas, Y^[Lbound], S^[Lbound], Ns, Xp1, Yp1, CurvParam.PointParam.Size); end; { Plot other points and connect them by lines if necessary } I := Lbound + CurvParam.Step; while I <= Ubound do begin X2 := X^[I]; if XAxis.Scale = LOG_SCALE then X2 := Log10(X2); Y2 := Y^[I]; if YAxis.Scale = LOG_SCALE then Y2 := Log10(Y2); Flag2 := CheckPoint(X2, Y2, Xp2, Yp2); if Flag2 then begin PlotSymbol(Canvas, Xp2, Yp2, CurvParam.PointParam.Symbol, CurvParam.PointParam.Size); if ErrorBars and (S^[I] > 0.0) then PlotErrorBar(Canvas, Y^[I], S^[I], Ns, Xp2, Yp2, CurvParam.PointParam.Size); if CurvParam.Connect and Flag1 then PlotLine(Canvas, Xp1, Yp1, Xp2, Yp2); end; Xp1 := Xp2; Yp1 := Yp2; Flag1 := Flag2; Inc(I, CurvParam.Step); end; { Restore settings } Pen.Color := PenColor; Pen.Style := PenStyle; Pen.Width := PenWidth; Brush.Color := BrushColor; Brush.Style := BrushStyle; end; end; procedure PlotCurve(Canvas : TCanvas; X, Y : PVector; Lbound, Ubound : Integer; CurvParam : TCurvParam); var Ns : Integer; { Dummy variables } S : PVector; begin GenPlotCurve(Canvas, X, Y, S, Ns, Lbound, Ubound, CurvParam, False); end; procedure PlotCurveWithErrorBars(Canvas : TCanvas; X, Y, S : PVector; Ns : Integer; Lbound, Ubound : Integer; CurvParam : TCurvParam); begin GenPlotCurve(Canvas, X, Y, S, Ns, Lbound, Ubound, CurvParam, True); end; procedure PlotFunc(Canvas : TCanvas; Func : TFunc; Xmin, Xmax : Float; Npt : Integer; LineParam : TLineParam); var PenColor : TColor; PenStyle : TpenStyle; PenWidth : Integer; X1, Y1, X2, Y2, H : Float; Xp1, Yp1, Xp2, Yp2 : Integer; Flag1, Flag2 : Boolean; I : Integer; begin if (Npt < 2) or (LineParam.Style = psClear) then Exit; if Xmin >= Xmax then begin Xmin := XAxis.Min; Xmax := XAxis.Max; end; H := (Xmax - Xmin) / Npt; with Canvas do begin { Save current settings } PenColor := Pen.Color; PenStyle := Pen.Style; PenWidth := Pen.Width; Pen.Color := LineParam.Color; Pen.Style := LineParam.Style; Pen.Width := LineParam.Width; { Check first point } X1 := Xmin; if XAxis.Scale = LIN_SCALE then Y1 := Func(X1) else Y1 := Func(Exp10(X1)); if YAxis.Scale = LOG_SCALE then Y1 := Log10(Y1); Flag1 := CheckPoint(X1, Y1, Xp1, Yp1); { Check other points and plot lines if possible } for I := 1 to Npt do begin X2 := X1 + H; if XAxis.Scale = LIN_SCALE then Y2 := Func(X2) else Y2 := Func(Exp10(X2)); if YAxis.Scale = LOG_SCALE then Y2 := Log10(Y2); Flag2 := CheckPoint(X2, Y2, Xp2, Yp2); if Flag1 and Flag2 then PlotLine(Canvas, Xp1, Yp1, Xp2, Yp2); X1 := X2; Xp1 := Xp2; Yp1 := Yp2; Flag1 := Flag2; end; { Restore settings } Pen.Color := PenColor; Pen.Style := PenStyle; Pen.Width := PenWidth; end; end; procedure WriteLegend(Canvas : TCanvas; NCurv : Integer; CurvParam : PCurvParamArray; ShowPoints, ShowLines : Boolean); var CharHeight, I, L, Lmax, N, Nmax, Xp, Xl, Y : Integer; PenWidth : Integer; PenStyle : TpenStyle; PenColor, BrushColor : TColor; BrushStyle : TBrushStyle; begin N := 0; { Nb of legends to be plotted } Lmax := 0; { Length of the longest legend } for I := 1 to NCurv do if CurvParam^[I].Legend <> '' then begin Inc(N); L := Canvas.TextWidth(CurvParam^[I].Legend); if L > Lmax then Lmax := L; end; if (N = 0) or (Lmax = 0) then Exit; { Character height } CharHeight := Canvas.TextHeight('M'); { Max. number of legends which may be plotted } Nmax := Round((YmaxPixel - YminPixel) / CharHeight) - 1; if N > Nmax then N := Nmax; { Draw rectangle around the legends } Canvas.Rectangle(XmaxPixel + Round(0.02 * GraphWidth), YminPixel, XmaxPixel + Round(0.12 * GraphWidth) + Lmax, YminPixel + (N + 1) * CharHeight); L := Round(0.02 * GraphWidth); { Half-length of line } Xp := XmaxPixel + 3 * L; { Position of symbol } Xl := XmaxPixel + 5 * L; { Position of legend } { Save current settings } with Canvas do begin PenColor := Pen.Color; PenStyle := Pen.Style; PenWidth := Pen.Width; BrushColor := Brush.Color; BrushStyle := Brush.Style; end; for I := 1 to IMin(NCurv, Nmax) do with Canvas do begin Pen.Color := CurvParam^[I].LineParam.Color; Pen.Style := CurvParam^[I].LineParam.Style; Pen.Width := CurvParam^[I].LineParam.Width; Brush.Color := CurvParam^[I].PointParam.Color; if CurvParam^[I].PointParam.Symbol in [0, 1, 3, 5] then Brush.Style := bsSolid else Brush.Style := bsClear; { Plot point and line } Y := YminPixel + I * CharHeight; if ShowPoints then PlotSymbol(Canvas, Xp, Y, CurvParam^[I].PointParam.Symbol, CurvParam^[I].PointParam.Size); if ShowLines then PlotLine(Canvas, Xp - L, Y, Xp + L, Y); { Write legend } Brush.Style := bsClear; Canvas.TextOut(Xl, Y - CharHeight div 2, CurvParam^[I].Legend); end; { Restore settings } with Canvas do begin Pen.Color := PenColor; Pen.Style := PenStyle; Pen.Width := PenWidth; Brush.Color := BrushColor; Brush.Style := BrushStyle; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/fitmult.pas����������������������������������������0000755�0001750�0001750�00000010761�11326425446�021464� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITMULT.PAS * * Version 1.1 * * (c) J. Debord, October 1998 * ********************************************************************** This unit fits the multiple linear equation: y = b0 + b1.x1 + b2.x2 + ... ********************************************************************** } unit FitMult; {$F+} interface uses FMath, Matrices, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X, B : PVector) : Float; function FitModel(Method : Integer; X : PMatrix; Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; procedure InitModel(CstPar : PVector); implementation const Nvar : Integer = 2; { Number of independent variables } ConsTerm : Boolean = True; { Flags the presence of a constant term b0 } function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } var Name, S : String; I : Integer; begin Name := 'y = '; if ConsTerm then Name := Name + 'b0 + '; Name := Name + 'b1.x1'; for I := 2 to Nvar do begin Str(I, S); Name := Name + ' + b' + S + '.x' + S; end; FuncName := Name; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted -------------------------------------------------------------------- } begin if ConsTerm then FirstParam := 0 else FirstParam := 1; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := Nvar; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } var S : String; begin Str(I, S); ParamName := 'b' + S; end; function RegFunc(X, B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at observation X B is the vector of parameters. -------------------------------------------------------------------- } var I : Integer; Y : Float; begin if ConsTerm then Y := B^[0] else Y := 0.0; for I := 1 to Nvar do Y := Y + B^[I] * X^[I]; RegFunc := Y; end; function FitModel(Method : Integer; X : PMatrix; Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; { -------------------------------------------------------------------- Multiple linear regression -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X = matrix of independent variables Y = vector of dependent variable W = vector of weights N = number of observations Output : B = estimated regression parameters V = variance-covariance matrix of parameters -------------------------------------------------------------------- } begin case Method of 0 : FitModel := MulFit(X, Y, N, Nvar, ConsTerm, B, V); 1 : FitModel := WMulFit(X, Y, W, N, Nvar, ConsTerm, B, V); end; end; procedure InitModel(CstPar : PVector); { -------------------------------------------------------------------- Initializes the global variables of the unit -------------------------------------------------------------------- CstPar^[0] = number of independent variables CstPar^[1] = 1 to include a constant term (b0) -------------------------------------------------------------------- } begin Nvar := Round(CstPar^[0]); ConsTerm := (CstPar^[1] = 1); end; end. ���������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/eigen.pas������������������������������������������0000755�0001750�0001750�00000060372�11326425446�021072� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit EIGEN.PAS * * Version 1.8 * * (c) J. Debord, May 2001 * ********************************************************************** Procedures for computing eigenvalues and eigenvectors ********************************************************************** References: 1) Borland's Numerical Methods Toolbox : Jacobi 2) 'Numerical Recipes' by Press et al. : EigenVals, RootPol ********************************************************************** } unit Eigen; interface uses FMath, Matrices; function Jacobi(A : PMatrix; Lbound, Ubound, MaxIter : Integer; Tol : Float; V : PMatrix; Lambda : PVector) : Integer; { ---------------------------------------------------------------------- Eigenvalues and eigenvectors of a symmetric matrix by the iterative method of Jacobi ---------------------------------------------------------------------- Input parameters : A = matrix Lbound = index of first matrix element Ubound = index of last matrix element MaxIter = maximum number of iterations Tol = required precision ---------------------------------------------------------------------- Output parameters : V = matrix of eigenvectors (stored by lines) Lambda = eigenvalues in decreasing order ---------------------------------------------------------------------- Possible results : MAT_OK MAT_NON_CONV ---------------------------------------------------------------------- NB : 1. The eigenvectors are normalized, with their first component > 0 2. This procedure destroys the original matrix A ---------------------------------------------------------------------- } function EigenVals(A : PMatrix; Lbound, Ubound : Integer; Lambda_Re, Lambda_Im : PVector) : Integer; { ---------------------------------------------------------------------- Eigenvalues of a general square matrix ---------------------------------------------------------------------- Input parameters : A = matrix Lbound = index of first matrix element Ubound = index of last matrix element ---------------------------------------------------------------------- Output parameters : Lambda_Re = real part of eigenvalues Lambda_Im = imaginary part of eigenvalues ---------------------------------------------------------------------- Possible results : MAT_OK MAT_NON_CONV ---------------------------------------------------------------------- NB : This procedure destroys the original matrix A ---------------------------------------------------------------------- } function EigenVect(A : PMatrix; Lbound, Ubound : Integer; Lambda, Tol : Float; V : PVector) : Integer; { ---------------------------------------------------------------------- Computes the eigenvector associated to a real eigenvalue ---------------------------------------------------------------------- Input parameters : A = matrix Lbound = index of first matrix element Ubound = index of last matrix element Lambda = eigenvalue Tol = required precision ---------------------------------------------------------------------- Output parameters : V = eigenvector ---------------------------------------------------------------------- Possible results : MAT_OK MAT_NON_CONV ---------------------------------------------------------------------- NB : 1. The eigenvector is normalized, with its first component > 0 2. The function returns only one eigenvector, even if the eigenvalue has a multiplicity greater than 1. ---------------------------------------------------------------------- } procedure DivLargest(V : PVector; Lbound, Ubound : Integer; var Largest : Float); { ---------------------------------------------------------------------- Normalizes an eigenvector V by dividing by the element with the largest absolute value ---------------------------------------------------------------------- } function RootPol(Coef : PVector; Deg : Integer; X_Re, X_Im : PVector) : Integer; { ---------------------------------------------------------------------- Real and complex roots of a real polynomial by the method of the companion matrix ---------------------------------------------------------------------- Input parameters : Coef = coefficients of polynomial Deg = degree of polynomial ---------------------------------------------------------------------- Output parameters : X_Re = real parts of root (in increasing order) X_Im = imaginary parts of root ---------------------------------------------------------------------- Possible results : MAT_OK MAT_NON_CONV ---------------------------------------------------------------------- } implementation function Jacobi(A : PMatrix; Lbound, Ubound, MaxIter : Integer; Tol : Float; V : PMatrix; Lambda : PVector) : Integer; var SinTheta, CosTheta, TanTheta, Tan2Theta : Float; CosSqr, SinSqr, SinCos, SumSqrDiag : Float; AII, AJJ, AIJ, AIK, AJK, VIK, VJK, D : Float; I, J, K, Iter : Integer; Done : Boolean; begin Iter := 0; for I := Lbound to Ubound do for J := Lbound to Ubound do if I = J then V^[I]^[J] := 1.0 else V^[I]^[J] := 0.0; repeat Iter := Succ(Iter); SumSqrDiag := 0.0; for I := Lbound to Ubound do SumSqrDiag := SumSqrDiag + Sqr(A^[I]^[I]); Done := True; for I := Lbound to Pred(Ubound) do for J := Succ(I) to Ubound do if Abs(A^[I]^[J]) > Tol * SumSqrDiag then begin Done := False; { Calculate rotation } D := A^[I]^[I] - A^[J]^[J]; if Abs(D) > MACHEP then begin Tan2Theta := D / (2.0 * A^[I]^[J]); TanTheta := - Tan2Theta + Sgn(Tan2Theta) * Sqrt(1.0 + Sqr(Tan2Theta)); CosTheta := 1.0 / Sqrt(1.0 + Sqr(TanTheta)); SinTheta := CosTheta * TanTheta; end else begin CosTheta := SQRT2DIV2; { Sqrt(2)/2 } SinTheta := Sgn(A^[I]^[J]) * SQRT2DIV2; end; { Rotate matrix } CosSqr := Sqr(CosTheta); SinSqr := Sqr(SinTheta); SinCos := SinTheta * CosTheta; AII := A^[I]^[I] * CosSqr + 2.0 * A^[I]^[J] * SinCos + A^[J]^[J] * SinSqr; AJJ := A^[I]^[I] * SinSqr - 2.0 * A^[I]^[J] * SinCos + A^[J]^[J] * CosSqr; AIJ := (A^[J]^[J] - A^[I]^[I]) * SinCos + A^[I]^[J] * (CosSqr - SinSqr); for K := Lbound to Ubound do if not(K in [I, J]) then begin AIK := A^[I]^[K] * CosTheta + A^[J]^[K] * SinTheta; AJK := - A^[I]^[K] * SinTheta + A^[J]^[K] * CosTheta; A^[I]^[K] := AIK; A^[K]^[I] := AIK; A^[J]^[K] := AJK; A^[K]^[J] := AJK; end; A^[I]^[I] := AII; A^[J]^[J] := AJJ; A^[I]^[J] := AIJ; A^[J]^[I] := AIJ; { Rotate eigenvectors } for K := Lbound to Ubound do begin VIK := CosTheta * V^[I]^[K] + SinTheta * V^[J]^[K]; VJK := - SinTheta * V^[I]^[K] + CosTheta * V^[J]^[K]; V^[I]^[K] := VIK; V^[J]^[K] := VJK; end; end; until Done or (Iter > MaxIter); { The diagonal terms of the transformed matrix are the eigenvalues } for I := Lbound to Ubound do Lambda^[I] := A^[I]^[I]; if Iter > MaxIter then begin Jacobi := MAT_NON_CONV; Exit; end; { Sort eigenvalues and eigenvectors } for I := Lbound to Pred(Ubound) do begin K := I; D := Lambda^[I]; for J := Succ(I) to Ubound do if Lambda^[J] > D then begin K := J; D := Lambda^[J]; end; FSwap(Lambda^[I], Lambda^[K]); SwapRows(I, K, V, Lbound, Ubound); end; { Make sure that the first component of each eigenvector is > 0 } for I := Lbound to Ubound do if V^[I]^[Lbound] < 0.0 then for J := Lbound to Ubound do V^[I]^[J] := - V^[I]^[J]; Jacobi := MAT_OK; end; procedure Balance(A : PMatrix; Lbound, Ubound : Integer); { Balances the matrix, i.e. reduces norm without affecting eigenvalues } const RADIX = 2; { Base used for machine computations } var I, J, Last : Integer; C, F, G, R, S, Sqrdx : Float; begin Sqrdx := Sqr(RADIX); repeat Last := 1; for I := Lbound to Ubound do begin C := 0.0; R := 0.0; for J := Lbound to Ubound do if J <> I then begin C := C + Abs(A^[J]^[I]); R := R + Abs(A^[I]^[J]); end; if (C <> 0.0) and (R <> 0.0) then begin G := R / RADIX; F := 1.0; S := C + R; while C < G do begin F := F * RADIX; C := C * Sqrdx; end; G := R * RADIX; while C > G do begin F := F / RADIX; C := C / Sqrdx; end; if (C + R) / F < 0.95 * S then begin Last := 0; G := 1.0 / F; for J := Lbound to Ubound do A^[I]^[J] := A^[I]^[J] * G; for J := Lbound to Ubound do A^[J]^[I] := A^[J]^[I] * F; end; end; end; until Last <> 0; end; procedure ElmHes(A : PMatrix; Lbound, Ubound : Integer); { Reduces the matrix to upper Hessenberg form by elimination } var I, J, M : Integer; X, Y : Float; begin for M := Succ(Lbound) to Pred(Ubound) do begin X := 0.0; I := M; for J := M to Ubound do if Abs(A^[J]^[M - 1]) > Abs(X) then begin X := A^[J]^[M - 1]; I := J; end; if I <> M then begin for J := Pred(M) to Ubound do FSwap(A^[I]^[J], A^[M]^[J]); for J := Lbound to Ubound do FSwap(A^[J]^[I], A^[J]^[M]); end; if X <> 0.0 then for I := Succ(M) to Ubound do begin Y := A^[I]^[M - 1]; if Y <> 0.0 then begin Y := Y / X; A^[I]^[M - 1] := Y; for J := M to Ubound do A^[I]^[J] := A^[I]^[J] - Y * A^[M]^[J]; for J := Lbound to Ubound do A^[J]^[M] := A^[J]^[M] + Y * A^[J]^[I]; end; end; end; for I := (Lbound + 2) to Ubound do for J := Lbound to (I - 2) do A^[I]^[J] := 0.0; end; function Hqr(A : PMatrix; Lbound, Ubound : Integer; Lambda_Re, Lambda_Im : PVector) : Integer; { Finds the eigenvalues of an upper Hessenberg matrix } label 2, 3, 4; var I, Its, J, K, L, M, N : Integer; Anorm, P, Q, R, S, T, U, V, W, X, Y, Z : Float; function Sign(A, B : Float) : Float; begin if B < 0.0 then Sign := - Abs(A) else Sign := Abs(A) end; begin Anorm := Abs(A^[1]^[1]); for I := Succ(Lbound) to Ubound do for J := I - 1 to Ubound do Anorm := Anorm + Abs(A^[I]^[J]); N := Ubound; T := 0.0; while N >= Lbound do begin Its := 0; 2: for L := N downto Succ(Lbound) do begin S := Abs(A^[L - 1]^[L - 1]) + Abs(A^[L]^[L]); if S = 0.0 then S := Anorm; if Abs(A^[L]^[L - 1]) <= MACHEP * S then goto 3 end; L := Lbound; 3: X := A^[N]^[N]; if L = N then begin Lambda_Re^[N] := X + T; Lambda_Im^[N] := 0.0; N := N - 1 end else begin Y := A^[N - 1]^[N - 1]; W := A^[N]^[N - 1] * A^[N - 1]^[N]; if L = N - 1 then begin P := 0.5 * (Y - X); Q := Sqr(P) + W; Z := Sqrt(Abs(Q)); X := X + T; if Q >= 0.0 then begin Z := P + Sign(Z, P); Lambda_Re^[N] := X + Z; Lambda_Re^[N - 1] := Lambda_Re^[N]; if Z <> 0.0 then Lambda_Re^[N] := X - W / Z; Lambda_Im^[N] := 0.0; Lambda_Im^[N - 1] := 0.0 end else begin Lambda_Re^[N] := X + P; Lambda_Re^[N - 1] := Lambda_Re^[N]; Lambda_Im^[N] := Z; Lambda_Im^[N - 1] := - Z end; N := N - 2 end else begin if Its = 30 then begin Hqr := MAT_NON_CONV; Exit; end; if (Its = 10) or (Its = 20) then begin T := T + X; for I := Lbound to N do A^[I]^[I] := A^[I]^[I] - X; S := Abs(A^[N]^[N - 1]) + Abs(A^[N - 1]^[N - 2]); X := 0.75 * S; Y := X; W := - 0.4375 * Sqr(S) end; Its := Its + 1; for M := N - 2 downto L do begin Z := A^[M]^[M]; R := X - Z; S := Y - Z; P := (R * S - W) / A^[M + 1]^[M] + A^[M]^[M + 1]; Q := A^[M + 1]^[M + 1] - Z - R - S; R := A^[M + 2]^[M + 1]; S := Abs(P) + Abs(Q) + Abs(R); P := P / S; Q := Q / S; R := R / S; if M = L then goto 4; U := Abs(A^[M]^[M - 1]) * (Abs(Q) + Abs(R)); V := Abs(P) * (Abs(A^[M - 1]^[M - 1]) + Abs(Z) + Abs(A^[M + 1]^[M + 1])); if U <= MACHEP * V then goto 4 end; 4: for I := M + 2 to N do begin A^[I]^[I - 2] := 0.0; if I <> (M + 2) then A^[I]^[I - 3] := 0.0 end; for K := M to N - 1 do begin if K <> M then begin P := A^[K]^[K - 1]; Q := A^[K + 1]^[K - 1]; R := 0.0; if K <> (N - 1) then R := A^[K + 2]^[K - 1]; X := Abs(P) + Abs(Q) + Abs(R); if X <> 0.0 then begin P := P / X; Q := Q / X; R := R / X end end; S := Sign(Sqrt(Sqr(P) + Sqr(Q) + Sqr(R)), P); if S <> 0.0 then begin if K = M then begin if L <> M then A^[K]^[K - 1] := - A^[K]^[K - 1]; end else begin A^[K]^[K - 1] := - S * X end; P := P + S; X := P / S; Y := Q / S; Z := R / S; Q := Q / P; R := R / P; for J := K to N do begin P := A^[K]^[J] + Q * A^[K + 1]^[J]; if K <> (N - 1) then begin P := P + R * A^[K + 2]^[J]; A^[K + 2]^[J] := A^[K + 2]^[J] - P * Z end; A^[K + 1]^[J] := A^[K + 1]^[J] - P * Y; A^[K]^[J] := A^[K]^[J] - P * X end; for I := L to IMin(N, K + 3) do begin P := X * A^[I]^[K] + Y * A^[I]^[K + 1]; if K <> (N - 1) then begin P := P + Z * A^[I]^[K + 2]; A^[I]^[K + 2] := A^[I]^[K + 2] - P * R end; A^[I]^[K + 1] := A^[I]^[K + 1] - P * Q; A^[I]^[K] := A^[I]^[K] - P end end end; goto 2 end end end; Hqr := MAT_OK; end; function EigenVals(A : PMatrix; Lbound, Ubound : Integer; Lambda_Re, Lambda_Im : PVector) : Integer; begin Balance(A, Lbound, Ubound); ElmHes(A, Lbound, Ubound); EigenVals := Hqr(A, Lbound, Ubound, Lambda_Re, Lambda_Im); end; procedure DivLargest(V : PVector; Lbound, Ubound : Integer; var Largest : Float); var I : Integer; begin Largest := V^[Lbound]; for I := Succ(Lbound) to Ubound do if Abs(V^[I]) > Abs(Largest) then Largest := V^[I]; for I := Lbound to Ubound do V^[I] := V^[I] / Largest; end; function EigenVect(A : PMatrix; Lbound, Ubound : Integer; Lambda, Tol : Float; V : PVector) : Integer; procedure SetMatrix(A, A1 : PMatrix; Lbound, Ubound : Integer; Lambda : Float); { Form A1 = A - Lambda * I } var I : Integer; begin CopyMatrix(A1, A, Lbound, Lbound, Ubound, Ubound); for I := Lbound to Ubound do A1^[I]^[I] := A^[I]^[I] - Lambda; end; function Solve(A : PMatrix; Lbound, Ubound, N : Integer; Tol : Float; V : PVector) : Integer; { Solve the system A*X = 0 after fixing the N-th unknown to 1 } var A1, W : PMatrix; B, S, X : PVector; ErrCode, I, I1, J, J1, Ubound1 : Integer; begin Ubound1 := Pred(Ubound); DimMatrix(A1, Ubound1, Ubound1); DimMatrix(W, Ubound1, Ubound1); DimVector(B, Ubound1); DimVector(S, Ubound1); DimVector(X, Ubound1); I1 := Pred(Lbound); for I := Lbound to Ubound do if I <> N then begin Inc(I1); J1 := 0; for J := Lbound to Ubound do if J <> N then begin Inc(J1); A1^[I1]^[J1] := A^[I]^[J]; end else B^[I1] := - A^[I]^[J]; end; ErrCode := SV_Decomp(A1, Lbound, Ubound1, Ubound1, S, W); if ErrCode = 0 then begin SV_SetZero(S, Lbound, Ubound1, Tol); SV_Solve(A1, S, W, B, Lbound, Ubound1, Ubound1, X); { Update eigenvector } I1 := 0; for I := Lbound to Ubound do if I = N then V^[I] := 1.0 else begin Inc(I1); V^[I] := X^[I1]; end; end; DelMatrix(A1, Ubound1, Ubound1); DelMatrix(W, Ubound1, Ubound1); DelVector(B, Ubound1); DelVector(S, Ubound1); DelVector(X, Ubound1); Solve := ErrCode; end; function ZeroVector(B : PVector; Lbound, Ubound : Integer; Tol : Float) : Boolean; { Check if vector B is zero } var I : Integer; Z : Boolean; begin Z := True; for I := Lbound to Ubound do Z := Z and (Abs(B^[I]) < Tol); ZeroVector := Z; end; function CheckEigenVector(A1 : PMatrix; V : PVector; Lbound, Ubound : Integer; Tol : Float) : Boolean; { Check if the equation A1 * V = 0 holds } var I, K : Integer; B : PVector; begin DimVector(B, Ubound); { Form B = A1 * V } for I := Lbound to Ubound do for K := Lbound to Ubound do B^[I] := B^[I] + A1^[I]^[K] * V^[K]; { Check if B is zero } CheckEigenVector := ZeroVector(B, Lbound, Ubound, Tol); DelVector(B, Ubound); end; procedure Normalize(V : PVector; Lbound, Ubound : Integer); { Normalize eigenvector and make sure that the first component is >= 0 } var Sum, Norm : Float; I : Integer; begin Sum := 0.0; for I := Lbound to Ubound do Sum := Sum + Sqr(V^[I]); Norm := Sqrt(Sum); for I := Lbound to Ubound do if V^[I] <> 0.0 then V^[I] := V^[I] / Norm; if V^[Lbound] < 0.0 then for I := Lbound to Ubound do if V^[I] <> 0.0 then V^[I] := - V^[I]; end; var ErrCode, I : Integer; A1 : PMatrix; begin DimMatrix(A1, Ubound, Ubound); { Form A1 = A - Lambda * I } SetMatrix(A, A1, Lbound, Ubound, Lambda); { Try to solve the system A1*V=0 by eliminating 1 equation } I := Lbound; repeat if (Solve(A1, Lbound, Ubound, I, Tol, V) = 0) and CheckEigenVector(A1, V, Lbound, Ubound, Tol) then ErrCode := 0 else ErrCode := - 1; Inc(I); until (ErrCode = 0) or (I > Ubound); if ErrCode = 0 then begin Normalize(V, Lbound, Ubound); EigenVect := MAT_OK; end else EigenVect := MAT_NON_CONV; DelMatrix(A1, Ubound, Ubound); end; function RootPol(Coef : PVector; Deg : Integer; X_Re, X_Im : PVector) : Integer; var A : PMatrix; { Companion matrix } N : Integer; { Size of matrix } I, J, K : Integer; { Loop variables } ErrCode : Integer; { Error code } Temp : Float; begin N := Pred(Deg); DimMatrix(A, N, N); { Set up the companion matrix (to save space, begin at index 0) } for J := 0 to N do A^[0]^[J] := - Coef^[Deg - J - 1] / Coef^[Deg]; for J := 0 to Pred(N) do A^[J + 1]^[J] := 1.0; { The roots of the polynomial are the eigenvalues of the companion matrix } Balance(A, 0, N); ErrCode := Hqr(A, 0, N, X_Re, X_Im); if ErrCode = MAT_OK then begin { Sort roots in increasing order of real parts } for I := 0 to N - 1 do begin K := I; Temp := X_Re^[I]; for J := Succ(I) to N do if X_Re^[J] < Temp then begin K := J; Temp := X_Re^[J]; end; FSwap(X_Re^[I], X_Re^[K]); FSwap(X_Im^[I], X_Im^[K]); end; { Transfer roots from 0..(Deg - 1) to 1..Deg } for J := N downto 0 do begin X_Re^[J + 1] := X_Re^[J]; X_Im^[J + 1] := X_Im^[J]; end; end; DelMatrix(A, N, N); RootPol := ErrCode; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/math387.inc����������������������������������������0000755�0001750�0001750�00000027663�07140500074�021160� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * MATH387.INC * ********************************************************************** Mathematical functions for TPMATH (Assembler version for 387/486/Pentium with BP7 and Delphi1) ********************************************************************** } (* Bibliotheque mathematique pour utilisation du coprocesseur flottant JD GAYRARD Sept. 95 ---------------------------------------------------------------------- Unite d'origine : MATH387.PAS, disponible dans MATHLIB2.ZIP (http://wcarchive.cdrom.com/pub/delphi_www/) Convertie en fichier Include par J. DEBORD, Juin 97 avec ajout des fonctions fexp2 et flog2 ---------------------------------------------------------------------- la bibliotheque est batie partir des fonctions du coprocesseur du type 386, elle fournit les fonctions suivantes: fsin, fcos, ftan, farctan, farctan2, farcsin, farccos, fmod, mod_2PI, ften_to, fy_to_x, fexp, fexp2, fln, flog, flog2... Aucune verification du domaine de definition des fonctions n'est faite, pas plus qu'un controle de la validite des operandes. Il est conseille d'utiliser cette bibliotheque pour les types single et double exclusivement *) { table opcode du 387 non comprise par turbo pascal V7 } { FSIN : D9 FE FCOS : D9 FF FSINCOS : D9 FB FPREM1 : D9 F5 } (* use only with 80387, 80486 or pentium for type single, double and extended, no check of definition domain of the function or range (FPU limitation). The f prefix avoids function redefinition of system runtime library *) function fsin(x : Float): Float; assembler; {if x < pi.2^62, then C2 is set to 0 and ST = sin(x) else C2 is set to 1 and ST = x } {no check range validity is performed in this function} asm FLD x { load x } DB $D9, $FE { opcode for FSIN } end; function fcos(x : Float): Float; assembler; { if x < pi.2^62, then C2 is set to 0 and ST = sin(x) else C2 is set to 1 and ST = x } {no range validity check is performed in this function} asm FLD x { load angle } DB $D9, $FF { opcode for FCOS } end; (* procedure dsincos(x : Float; var sinus, cosinus : double); assembler; { retourne sinus et cosinus(x), utilisable uniquement avec 80387, 80468 et pentium et type double } asm { ST(0) ST(1) } FLD x { x - } DB $D9, $FB { cos(x) sin(x) } LES DI,cosinus { } FSTP ES:QWORD PTR [DI] { sin(x) - } LES DI,sinus { } FSTP ES:QWORD PTR [DI] { - - } end; procedure ssincos(x : Float; var sinus, cosinus : single); assembler; { retourne sinus et cosinus(x), utilisable uniquement avec 80387, 80468 et pentium et type single } asm { ST(0) ST(1) } FLD x { x - } DB $D9, $FB { cos(x) sin(x) } LES DI,cosinus { } FSTP ES:DWORD PTR [DI] { sin(x) - } LES DI,sinus { } FSTP ES:DWORD PTR [DI] { - - } end; procedure fsincos(x : Float; var sinus, cosinus : Float); { retourne sinus et cosinus(x), utilisable uniquement avec 80387, 80486 et pentium } var lcos, lsin : Float; begin asm { ST(0) ST(1) } FLD x { x - } DB $D9, $FB { cos(x) sin(x) } FSTP lcos { sin(x) - } FSTP lsin { - - } end; cosinus := lcos; sinus := lsin end; *) function ftan(x : Float): Float; assembler; { if x < pi.2^62, then C2 is set to 0 and ST = 1 and ST(1) = tan(x) else C2 is set to 1 and ST = x } {no range validity check is performed in this function} asm { ST(0) ST(1) } FLD x { x - } FPTAN { 1 tan(x) } FSTP ST(0) { tan(x) - } end; function farcsin(x : Float): Float; assembler; (* retourne l'arcsin de x *) { methode : ________ arcsin(x) = arctan( x / V 1 - x.x ) } {no range validity check is performed in this function |x| > 1 } asm { ST(0) ST(1) ST(2) } FLD X { x - - } FLD ST(0) { x x - } FMUL ST(0), ST { x.x x - } FLD1 { 1 x.x x } FSUBRP ST(1), ST { 1 - x x - } FSQRT { sqrt(1-x) x - } FPATAN { arcsin(x) - - } end; function farccos(x : Float): Float; assembler; { retourne arccos(x) methode : ________ arcsin(x) = arctan( V 1 - x.x / x ) } { pas de controle de domaine de definition |x| > 1 } asm { ST(0) ST(1) ST(2) } FLD X { x - - } FLD ST(0) { x x - } FMUL ST(0), ST { x.x x - } FLD1 { 1 x.x x } FSUBRP ST(1), ST { 1 - x x - } FSQRT { sqrt(1-x) x - } FXCH { x z - } FPATAN { arccos(x) - - } end; function farctan(x : Float): Float; assembler; asm { ST(0) ST(1) } FLD x { x - } FLD1 { 1 x } FPATAN { atan(x/1) - } end; function farctan2(y, x : Float): Float; assembler; { retourne arctan (y / x) } asm { ST(0) ST(1) } FLD y { y - } FLD x { x y } FPATAN { atan(y/x) - } end; (* function fmod(x, y : Float): Float; assembler; { retourne x mod y } asm { ST(0) ST(1) } FLD Y { y - } FLD X { x y } @repeat_mod: FPREM { x mod y y } FSTSW AX SAHF JP @repeat_mod FSTP ST(1) { x mod y - } end; function fmod_2PI( x : Float): Float; assembler; { retourne x mod 2.pi } asm { ST(0) ST(1) } FLDPI { pi - } FADD ST, ST { 2.pi - } FLD x { x 2.pi } @unit_circle: FPREM { x mod 2pi 2pi } FSTSW AX SAHF JP @unit_circle FSTP ST(1) { x mod 2pi - } end; *) function fln(x : Float): Float; assembler; { retourne le logarithme naturel de x, utilise la methode loge(x) = loge(2).log2(x) } { pas de verification du domaine de definition (x < 0) } asm { ST(0) ST(1) } FLDLN2 { ln(2) - } FLD X { x ln(2) } FYL2X { ln(2).log2(x) - } end; function flog2(x : Float): Float; assembler; { retourne le logarithme de base 2 de x } { pas de verification du domaine de definition (x < 0) } asm { ST(0) ST(1) } FLD1 { 1 - } FLD X { x 1 } FYL2X { log2(x) - } end; function flog10(x : Float): Float; assembler; { retourne le logarithme base 10 de x, utilise la methode log10(x) = log10(2).log2(x) } { pas de verification du domaine de definition (x < 0) } asm { ST(0) ST(1) } FLDLG2 { log10(2) - } FLD X { x log10(2) } FYL2X {log2(x).log10(2) - } end; function fexp(x : Float): Float; assembler; { retourne e^x, par la methode e^x = 2^(x.log2(e)) } { 2^z = 2^f.2^i with f = frac(z) and i = int(z) } { 2^f is computed with F2XM1, 2^i with FSCALE } const round_down : word = $177F; var control_ww : word; asm { ST(0) ST(1) ST(2) } FLD X { x - - } FLDL2E { log2(e) x - } FMULP ST(1), ST { x.log2(e) - - } FSTCW control_ww FLDCW round_down FLD ST(0) { z z - } FRNDINT { int(z) z - } FLDCW control_ww FXCH { z i - } FSUB ST, ST(1) { f i - } F2XM1 { 2^f-1 i - } FLD1 { 1 2^f-1 i } FADDP ST(1), ST { 2^f i - } FSCALE { 2^f.2^i i - } FSTP ST(1) { e^x - - } end; function fexp2(x : Float): Float; assembler; { retourne 2^x par la methode 2^z = 2^f.2^i } { with f = frac(z) and i = int(z) } { 2^f is computed with F2XM1, 2^i with FSCALE } const round_down : word = $177F; var control_ww : word; asm { ST(0) ST(1) ST(2) } FLD X { x - - } FSTCW control_ww FLDCW round_down FLD ST(0) { x x - } FRNDINT { int(x) x - } FLDCW control_ww FXCH { x i - } FSUB ST, ST(1) { f i - } F2XM1 { 2^f-1 i - } FLD1 { 1 2^f-1 i } FADDP ST(1), ST { 2^f i - } FSCALE { 2^f.2^i i - } FSTP ST(1) { 2^x - - } end; function fexp10(x : Float): Float; assembler; { retourne 10^x, par la methode 10^x = 2^(x.log2(10)) { 2^z = 2^f.2^i with f = frac(z) and i = int(z) { 2^f is computed with F2XM1, 2^i with FSCALE } const round_down : word = $177F; var control_ww : word; asm { ST(0) ST(1) ST(2) } FLD X { x - - } FLDL2T { log2(10) x - } FMULP ST(1), ST { x.log2(10) - - } FSTCW control_ww FLDCW round_down FLD ST(0) { z z - } FRNDINT { int(z) z - } FLDCW control_ww FXCH { z i - } FSUB ST, ST(1) { f i - } F2XM1 { 2^f-1 i - } FLD1 { 1 2^f-1 i } FADDP ST(1), ST { 2^f i - } FSCALE { 2^f.2^i i - } FSTP ST(1) { 10^x - - } end; (* function fpower(y, x : Float): Float; assembler; { retourne y^x, par la methode y^x = 2^(y.log2(y)) {no range validity check is performed in this function (y > 0) } { 2^z = 2^f.2^i with f = frac(z) and i = int(z) { 2^f is computed with F2XM1, 2^i with FSCALE } const round_down : word = $177F; var control_ww : word; asm { ST(0) ST(1) ST(2) } FLD Y { y - - } FLD X { x y - } FYL2X { x.log2(y) - - } FSTCW control_ww FLDCW round_down FLD ST(0) { z z - } FRNDINT { int(z) z - } FLDCW control_ww FXCH { z i - } FSUB ST, ST(1) { f i - } F2XM1 { 2^f-1 i - } FLD1 { 1 2^f-1 i } FADDP ST(1), ST { 2^f i - } FSCALE { 2^f.2^i i - } FSTP ST(1) { y^x - - } end; function module(x, y : Float): Float; assembler; { retourne le module du complexe (x,y) } asm { ST(0) ST(1) } FLD Y { y - } FMUL ST(0), ST { y.y - } FLD X { x y.y } FMUL ST(0), ST { x.x y.y } FADDP ST(1), ST { d.d - } FSQRT { d - } end; *) �����������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/plot.inc�������������������������������������������0000755�0001750�0001750�00000005236�07275617620�020752� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * PLOT.INC * ********************************************************************** Variables and routines common to PLOT.PAS and WINPLOT.PAS ********************************************************************** } var XminPixel, YminPixel : Integer; { Pixel coord. of upper left corner } XmaxPixel, YmaxPixel : Integer; { Pixel coord. of lower right corner } FactX, FactY : Float; { Scaling factors } function Xpixel(X : Float) : Integer; var P : Float; begin P := FactX * (X - XAxis.Min); if Abs(P) > 30000 then Xpixel := 30000 else Xpixel := Round(P) + XminPixel; end; function Ypixel(Y : Float) : Integer; var P : Float; begin P := FactY * (YAxis.Max - Y); if Abs(P) > 30000 then Ypixel := 30000 else Ypixel := Round(P) + YminPixel; end; function Xuser(X : Integer) : Float; begin Xuser := XAxis.Min + (X - XminPixel) / FactX; end; function Yuser(Y : Integer) : Float; begin Yuser := YAxis.Max - (Y - YminPixel) / FactY; end; procedure Interval(X1, X2 : Float; MinDiv, MaxDiv : Integer; var Min, Max, Step : Float); var H, R, K : Float; begin if X1 >= X2 then Exit; H := X2 - X1; R := Int(Log10(H)); if H < 1.0 then R := R - 1.0; Step := Exp10(R); repeat K := Int(H / Step); if K < MinDiv then Step := 0.5 * Step; if K > MaxDiv then Step := 2.0 * Step; until (K >= MinDiv) and (K <= MaxDiv); Min := Step * Int(X1 / Step); Max := Step * Int(X2 / Step); while Min > X1 do Min := Min - Step; while Max < X2 do Max := Max + Step; end; procedure AutoScale(Z : PVector; Lbound, Ubound : Integer; var Axis : TAxis); var I : Integer; Zmin, Zmax, Z1, Z2 : Float; begin if Axis.Scale = LIN_SCALE then Interval(Min(Z, Lbound, Ubound), Max(Z, Lbound, Ubound), 2, 6, Axis.Min, Axis.Max, Axis.Step) else begin Zmin := MAXNUM; Zmax := 0.0; for I := Lbound to Ubound do if Z^[I] > 0.0 then if Z^[I] < Zmin then Zmin := Z^[I] else if Z^[I] > Zmax then Zmax := Z^[I]; Z1 := Int(Log10(Zmin)); Z2 := Int(Log10(Zmax)); if Zmin < 1.0 then Z1 := Z1 - 1.0; if Zmax > 1.0 then Z2 := Z2 + 1.0; Axis.Min := Z1; Axis.Max := Z2; Axis.Step := 1.0; end; end; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/fitiexpo.pas���������������������������������������0000755�0001750�0001750�00000011251�11326425446�021622� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITIEXPO.PAS * * Version 1.2 * * (c) J. Debord, August 2000 * ********************************************************************** This unit fits the increasing exponential : y = A.[1 - exp(-k.x)] ********************************************************************** } unit FitIExpo; {$F+} interface uses FMath, Matrices, Stat, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X : Float; B, D : PVector); function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; implementation function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } begin FuncName := 'y = A[1 - exp(-k.x)]'; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 1; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'A'; 1 : ParamName := 'k'; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = A B^[1] = k -------------------------------------------------------------------- } begin RegFunc := B^[0] * (1.0 - Expo(- B^[1] * X)); end; procedure DerivProc(X : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point X with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter. -------------------------------------------------------------------- } var E : Float; begin E := Expo(- B^[1] * X); { exp(-k.x) } D^[0] := 1.0 - E; { dy/dA = 1 - exp(-k.x) } D^[1] := B^[0] * X * E; { dy/dk = A.x.exp(-k.x) } end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of the increasing exponential by linear regression: Ln(1 - y/A) = -k.x -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- } var Y1 : PVector; { Transformed ordinates } W1 : PVector; { Weights } A : PVector; { Linear regression parameters } V : PMatrix; { Variance-covariance matrix } K : Integer; { Loop variable } ErrCode : Integer; { Error code } begin DimVector(Y1, N); DimVector(W1, N); DimVector(A, 1); DimMatrix(V, 1, 1); { Estimation of A } B^[0] := 1.1 * Max(Y, 1, N); for K := 1 to N do begin Y1^[K] := Log(1.0 - Y^[K] / B^[0]); W1^[K] := Sqr(Y^[K] - B^[0]); if Method = 1 then W1^[K] := W1^[K] * W^[K]; end; ErrCode := WLinFit(X, Y1, W1, N, A, V); if ErrCode = MAT_OK then B^[1] := - A^[1]; FitModel := ErrCode; DelVector(Y1, N); DelVector(W1, N); DelVector(A, 1); DelMatrix(V, 1, 1); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/optim.pas������������������������������������������0000755�0001750�0001750�00000100642�11326425446�021126� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit OPTIM.PAS * * Version 2.1 * * (c) J. Debord, June 2001 * ********************************************************************** This unit implements the following methods for function minimization: * Golden search for a function of one variable * Simplex, Marquardt, BFGS for a function of several variables ********************************************************************** References: 1) 'Numerical Recipes' by Press et al. 2) D. W. MARQUARDT, J. Soc. Indust. Appl. Math., 1963, 11, 431-441 3) J. A. NELDER & R. MEAD, Comput. J., 1964, 7, 308-313 4) R. O'NEILL, Appl. Statist., 1971, 20, 338-345 ********************************************************************** } unit Optim; interface uses FMath, Matrices; { ********************************************************************** Error codes ********************************************************************** } const OPT_OK = 0; { No error } OPT_SING = - 1; { Singular hessian matrix } OPT_BIG_LAMBDA = - 2; { Too high Marquardt's parameter } OPT_NON_CONV = - 3; { Non-convergence } { ********************************************************************** Functional types ********************************************************************** } type { Function of several variables } TFuncNVar = function(X : PVector) : Float; { Procedure to compute gradient vector } TGradient = procedure(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; G : PVector); { Procedure to compute gradient vector and hessian matrix } THessGrad = procedure(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; G : PVector; H : PMatrix); { ********************************************************************** Log file ********************************************************************** } const WriteLogFile : Boolean = False; { Write iteration info to log file } LogFileName : String = 'optim.log'; { Name of log file } { ********************************************************************** Minimization routines ********************************************************************** } function GoldSearch(Func : TFunc; A, B : Float; MaxIter : Integer; Tol : Float; var Xmin, Ymin : Float) : Integer; { ---------------------------------------------------------------------- Performs a golden search for the minimum of function Func ---------------------------------------------------------------------- Input parameters : Func = objective function A, B = two points near the minimum MaxIter = maximum number of iterations Tol = required precision (should not be less than the square root of the machine precision) ---------------------------------------------------------------------- Output parameters : Xmin, Ymin = coordinates of minimum ---------------------------------------------------------------------- Possible results : OPT_OK OPT_NON_CONV ---------------------------------------------------------------------- } function LinMin(Func : TFuncNVar; X, DeltaX : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float) : Integer; { ---------------------------------------------------------------------- Minimizes function Func from point X in the direction specified by DeltaX ---------------------------------------------------------------------- Input parameters : Func = objective function X = initial minimum coordinates DeltaX = direction in which minimum is searched Lbound, Ubound = indices of first and last variables MaxIter = maximum number of iterations Tol = required precision ---------------------------------------------------------------------- Output parameters : X = refined minimum coordinates F_min = function value at minimum ---------------------------------------------------------------------- Possible results : OPT_OK OPT_NON_CONV ---------------------------------------------------------------------- } function Simplex(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float) : Integer; { ---------------------------------------------------------------------- Minimization of a function of several variables by the simplex method of Nelder and Mead ---------------------------------------------------------------------- Input parameters : Func = objective function X = initial minimum coordinates Lbound, Ubound = indices of first and last variables MaxIter = maximum number of iterations Tol = required precision ---------------------------------------------------------------------- Output parameters : X = refined minimum coordinates F_min = function value at minimum ---------------------------------------------------------------------- Possible results : OPT_OK OPT_NON_CONV ---------------------------------------------------------------------- } procedure NumGradient(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; G : PVector); { ---------------------------------------------------------------------- Computes the gradient vector of a function of several variables by numerical differentiation ---------------------------------------------------------------------- Input parameters : Func = function of several variables X = vector of variables Lbound, Ubound = indices of first and last variables ---------------------------------------------------------------------- Output parameter : G = gradient vector ---------------------------------------------------------------------- } procedure NumHessGrad(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; G : PVector; H : PMatrix); { ---------------------------------------------------------------------- Computes gradient vector & hessian matrix by numerical differentiation ---------------------------------------------------------------------- Input parameters : as in NumGradient ---------------------------------------------------------------------- Output parameters : G = gradient vector H = hessian matrix ---------------------------------------------------------------------- } function Marquardt(Func : TFuncNVar; HessGrad : THessGrad; X : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; H_inv : PMatrix) : Integer; { ---------------------------------------------------------------------- Minimization of a function of several variables by Marquardt's method ---------------------------------------------------------------------- Input parameters : Func = objective function HessGrad = procedure to compute gradient & hessian X = initial minimum coordinates Lbound, Ubound = indices of first and last variables MaxIter = maximum number of iterations Tol = required precision ---------------------------------------------------------------------- Output parameters : X = refined minimum coordinates F_min = function value at minimum H_inv = inverse hessian matrix ---------------------------------------------------------------------- Possible results : OPT_OK OPT_SING OPT_BIG_LAMBDA OPT_NON_CONV ---------------------------------------------------------------------- } function BFGS(Func : TFuncNVar; Gradient : TGradient; X : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; H_inv : PMatrix) : Integer; { ---------------------------------------------------------------------- Minimization of a function of several variables by the Broyden-Fletcher-Goldfarb-Shanno method ---------------------------------------------------------------------- Parameters : Gradient = procedure to compute gradient vector Other parameters as in Marquardt ---------------------------------------------------------------------- Possible results : OPT_OK OPT_NON_CONV ---------------------------------------------------------------------- } implementation var Eps : Float; { Fractional increment for numer. derivation } X1 : PVector; { Initial point for line minimization } DeltaX1 : PVector; { Direction for line minimization } Lbound1, Ubound1 : Integer; { Bounds of X1 and DeltaX1 } LinObjFunc : TFuncNVar; { Objective function for line minimization } LogFile : Text; { Stores the result of each minimization step } procedure MinBrack(Func : TFunc; var A, B, C, Fa, Fb, Fc : Float); { ---------------------------------------------------------------------- Given two points (A, B) this procedure finds a triplet (A, B, C) such that: 1) A < B < C 2) A, B, C are within the golden ratio 3) Func(B) < Func(A) and Func(B) < Func(C). The corresponding function values are returned in Fa, Fb, Fc ---------------------------------------------------------------------- } begin if A > B then FSwap(A, B); Fa := Func(A); Fb := Func(B); if Fb > Fa then begin FSwap(A, B); FSwap(Fa, Fb); end; C := B + GOLD * (B - A); Fc := Func(C); while Fc < Fb do begin A := B; B := C; Fa := Fb; Fb := Fc; C := B + GOLD * (B - A); Fc := Func(C); end; if A > C then begin FSwap(A, C); FSwap(Fa, Fc); end; end; function GoldSearch(Func : TFunc; A, B : Float; MaxIter : Integer; Tol : Float; var Xmin, Ymin : Float) : Integer; var C, Fa, Fb, Fc, F1, F2, MinTol, X0, X1, X2, X3 : Float; Iter : Integer; begin MinTol := Sqrt(MACHEP); if Tol < MinTol then Tol := MinTol; MinBrack(Func, A, B, C, Fa, Fb, Fc); X0 := A; X3 := C; if (C - B) > (B - A) then begin X1 := B; X2 := B + CGOLD * (C - B); F1 := Fb; F2 := Func(X2); end else begin X1 := B - CGOLD * (B - A); X2 := B; F1 := Func(X1); F2 := Fb; end; Iter := 0; while (Iter <= MaxIter) and (Abs(X3 - X0) > Tol * (Abs(X1) + Abs(X2))) do if F2 < F1 then begin X0 := X1; X1 := X2; F1 := F2; X2 := X1 + CGOLD * (X3 - X1); F2 := Func(X2); Inc(Iter); end else begin X3 := X2; X2 := X1; F2 := F1; X1 := X2 - CGOLD * (X2 - X0); F1 := Func(X1); Inc(Iter); end; if F1 < F2 then begin Xmin := X1; Ymin := F1; end else begin Xmin := X2; Ymin := F2; end; if Iter > MaxIter then GoldSearch := OPT_NON_CONV else GoldSearch := OPT_OK; end; procedure CreateLogFile; begin Assign(LogFile, LogFileName); Rewrite(LogFile); end; function Simplex(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float) : Integer; const STEP = 1.50; { Step used to construct the initial simplex } var P : PMatrix; { Simplex coordinates } F : PVector; { Function values } Pbar : PVector; { Centroid coordinates } Pstar, P2star : PVector; { New vertices } Ystar, Y2star : Float; { New function values } F0 : Float; { Function value at minimum } N : Integer; { Number of parameters } M : Integer; { Index of last vertex } L, H : Integer; { Vertices with lowest & highest F values } I, J : Integer; { Loop variables } Iter : Integer; { Iteration count } Corr, MaxCorr : Float; { Corrections } Sum : Float; Flag : Boolean; procedure UpdateSimplex(Y : Float; Q : PVector); { Update "worst" vertex and function value } begin F^[H] := Y; CopyVector(P^[H], Q, Lbound, Ubound); end; begin if WriteLogFile then begin CreateLogFile; WriteLn(LogFile, 'Simplex'); WriteLn(LogFile, 'Iter F'); end; N := Ubound - Lbound + 1; M := Succ(Ubound); DimMatrix(P, M, Ubound); DimVector(F, M); DimVector(Pbar, Ubound); DimVector(Pstar, Ubound); DimVector(P2star, Ubound); Iter := 1; F0 := MAXNUM; { Construct initial simplex } for I := Lbound to M do CopyVector(P^[I], X, Lbound, Ubound); for I := Lbound to Ubound do P^[I]^[I] := P^[I]^[I] * STEP; { Evaluate function at each vertex } for I := Lbound to M do F^[I] := Func(P^[I]); repeat { Find vertices (L,H) having the lowest and highest function values, i.e. "best" and "worst" vertices } L := Lbound; H := Lbound; for I := Succ(Lbound) to M do if F^[I] < F^[L] then L := I else if F^[I] > F^[H] then H := I; if F^[L] < F0 then F0 := F^[L]; if WriteLogFile then WriteLn(LogFile, Iter:4, ' ', F0:12); { Find centroid of points other than P(H) } for J := Lbound to Ubound do begin Sum := 0.0; for I := Lbound to M do if I <> H then Sum := Sum + P^[I]^[J]; Pbar^[J] := Sum / N; end; { Reflect worst vertex through centroid } for J := Lbound to Ubound do Pstar^[J] := 2.0 * Pbar^[J] - P^[H]^[J]; Ystar := Func(Pstar); { If reflection successful, try extension } if Ystar < F^[L] then begin for J := Lbound to Ubound do P2star^[J] := 3.0 * Pstar^[J] - 2.0 * Pbar^[J]; Y2star := Func(P2star); { Retain extension or contraction } if Y2star < F^[L] then UpdateSimplex(Y2star, P2star) else UpdateSimplex(Ystar, Pstar); end else begin I := Lbound; Flag := False; repeat if (I <> H) and (F^[I] > Ystar) then Flag := True; Inc(I); until Flag or (I > M); if Flag then UpdateSimplex(Ystar, Pstar) else begin { Contraction on the reflection side of the centroid } if Ystar <= F^[H] then UpdateSimplex(Ystar, Pstar); { Contraction on the opposite side of the centroid } for J := Lbound to Ubound do P2star^[J] := 0.5 * (P^[H]^[J] + Pbar^[J]); Y2star := Func(P2star); if Y2star <= F^[H] then UpdateSimplex(Y2star, P2star) else { Contract whole simplex } for I := Lbound to M do for J := Lbound to Ubound do P^[I]^[J] := 0.5 * (P^[I]^[J] + P^[L]^[J]); end; end; { Test convergence } MaxCorr := 0.0; for J := Lbound to Ubound do begin Corr := Abs(P^[H]^[J] - P^[L]^[J]); if Corr > MaxCorr then MaxCorr := Corr; end; Inc(Iter); until (MaxCorr < Tol) or (Iter > MaxIter); CopyVector(X, P^[L], Lbound, Ubound); F_min := F^[L]; DelMatrix(P, M, Ubound); DelVector(F, M); DelVector(Pbar, Ubound); DelVector(Pstar, Ubound); DelVector(P2star, Ubound); if WriteLogFile then Close(LogFile); if Iter > MaxIter then Simplex := OPT_NON_CONV else Simplex := OPT_OK; end; {$F+} function F1dim(R : Float) : Float; { ---------------------------------------------------------------------- Function used by LinMin to find the minimum of the objective function LinObjFunc in the direction specified by the global variables X1 and DeltaX1. R is the step in this direction. ---------------------------------------------------------------------- } const Xt : PVector = nil; var I : Integer; begin if Xt = nil then DimVector(Xt, Ubound1); for I := Lbound1 to Ubound1 do Xt^[I] := X1^[I] + R * DeltaX1^[I]; F1dim := LinObjFunc(Xt); end; {$F-} function LinMin(Func : TFuncNVar; X, DeltaX : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float) : Integer; var I, ErrCode : Integer; R : Float; begin { Redimension global vectors } DelVector(X1, Ubound1); DelVector(DeltaX1, Ubound1); DimVector(X1, Ubound); DimVector(DeltaX1, Ubound); Lbound1 := Lbound; Ubound1 := Ubound; { Initialize global variables } LinObjFunc := Func; for I := Lbound to Ubound do begin X1^[I] := X^[I]; DeltaX1^[I] := DeltaX^[I] end; { Perform golden search } ErrCode := GoldSearch({$IFDEF FPK}@{$ENDIF}F1dim, 0.0, 1.0, MaxIter, Tol, R, F_min); { Update variables } if ErrCode = OPT_OK then for I := Lbound to Ubound do X^[I] := X^[I] + R * DeltaX^[I]; LinMin := ErrCode; end; {$F+} procedure NumGradient(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; G : PVector); var Temp, Delta, Fplus, Fminus : Float; I : Integer; begin for I := Lbound to Ubound do begin Temp := X^[I]; if Temp <> 0.0 then Delta := Eps * Abs(Temp) else Delta := Eps; X^[I] := Temp - Delta; Fminus := Func(X); X^[I] := Temp + Delta; Fplus := Func(X); G^[I] := (Fplus - Fminus) / (2.0 * Delta); X^[I] := Temp; end; end; {$F-} {$F+} procedure NumHessGrad(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; G : PVector; H : PMatrix); var Delta, Xminus, Xplus, Fminus, Fplus : PVector; Temp1, Temp2, F, F2plus : Float; I, J : Integer; begin DimVector(Delta, Ubound); { Increments } DimVector(Xminus, Ubound); { X - Delta } DimVector(Xplus, Ubound); { X + Delta } DimVector(Fminus, Ubound); { F(X - Delta) } DimVector(Fplus, Ubound); { F(X + Delta) } F := Func(X); for I := Lbound to Ubound do begin if X^[I] <> 0.0 then Delta^[I] := Eps * Abs(X^[I]) else Delta^[I] := Eps; Xplus^[I] := X^[I] + Delta^[I]; Xminus^[I] := X^[I] - Delta^[I]; end; for I := Lbound to Ubound do begin Temp1 := X^[I]; X^[I] := Xminus^[I]; Fminus^[I] := Func(X); X^[I] := Xplus^[I]; Fplus^[I] := Func(X); X^[I] := Temp1; end; for I := Lbound to Ubound do begin G^[I] := (Fplus^[I] - Fminus^[I]) / (2.0 * Delta^[I]); H^[I]^[I] := (Fplus^[I] + Fminus^[I] - 2.0 * F) / Sqr(Delta^[I]); end; for I := Lbound to Pred(Ubound) do begin Temp1 := X^[I]; X^[I] := Xplus^[I]; for J := Succ(I) to Ubound do begin Temp2 := X^[J]; X^[J] := Xplus^[J]; F2plus := Func(X); H^[I]^[J] := (F2plus - Fplus^[I] - Fplus^[J] + F) / (Delta^[I] * Delta^[J]); H^[J]^[I] := H^[I]^[J]; X^[J] := Temp2; end; X^[I] := Temp1; end; DelVector(Delta, Ubound); DelVector(Xminus, Ubound); DelVector(Xplus, Ubound); DelVector(Fminus, Ubound); DelVector(Fplus, Ubound); end; {$F-} function ParamConv(OldX, X : PVector; Lbound, Ubound : Integer; Tol : Float) : Boolean; { ---------------------------------------------------------------------- Check for convergence on parameters ---------------------------------------------------------------------- } var I : Integer; Conv : Boolean; begin I := Lbound; Conv := True; repeat Conv := Conv and (Abs(X^[I] - OldX^[I]) < FMax(Tol, Tol * Abs(OldX^[I]))); Inc(I); until (Conv = False) or (I > Ubound); ParamConv := Conv; end; function Marquardt(Func : TFuncNVar; HessGrad : THessGrad; X : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; H_inv : PMatrix) : Integer; const LAMBDA0 = 1.0E-2; { Initial lambda value } LAMBDAMAX = 1.0E+3; { Highest lambda value } FTOL = 1.0E-10; { Tolerance on function decrease } var Lambda, Lambda1 : Float; { Marquardt's lambda } I : Integer; { Loop variable } OldX : PVector; { Old parameters } G : PVector; { Gradient vector } H : PMatrix; { Hessian matrix } A : PMatrix; { Modified Hessian matrix } DeltaX : PVector; { New search direction } F1 : Float; { New minimum } Lambda_Ok : Boolean; { Successful Lambda decrease } Conv : Boolean; { Convergence reached } Done : Boolean; { Iterations done } Iter : Integer; { Iteration count } ErrCode : Integer; { Error code } begin if WriteLogFile then begin CreateLogFile; WriteLn(LogFile, 'Marquardt'); WriteLn(LogFile, 'Iter F Lambda'); end; Lambda := LAMBDA0; ErrCode := OPT_OK; DimVector(OldX, Ubound); DimVector(G, Ubound); DimMatrix(H, Ubound, Ubound); DimMatrix(A, Ubound, Ubound); DimVector(DeltaX, Ubound); F_min := Func(X); { Initial function value } LinObjFunc := Func; { Function for line minimization } Iter := 1; Conv := False; Done := False; repeat if WriteLogFile then WriteLn(LogFile, Iter:4, ' ', F_min:12, ' ', Lambda:12); { Save current parameters } CopyVector(OldX, X, Lbound, Ubound); { Compute Gradient and Hessian } HessGrad(Func, X, Lbound, Ubound, G, H); CopyMatrix(A, H, Lbound, Lbound, Ubound, Ubound); { Change sign of gradient } for I := Lbound to Ubound do G^[I] := - G^[I]; if Conv then { Newton-Raphson iteration } begin ErrCode := GaussJordan(A, G, Lbound, Ubound, H_inv, DeltaX); if ErrCode = MAT_OK then for I := Lbound to Ubound do X^[I] := OldX^[I] + DeltaX^[I]; Done := True; end else { Marquardt iteration } begin repeat { Multiply each diagonal term of H by (1 + Lambda) } Lambda1 := 1.0 + Lambda; for I := Lbound to Ubound do A^[I]^[I] := Lambda1 * H^[I]^[I]; ErrCode := GaussJordan(A, G, Lbound, Ubound, H_inv, DeltaX); if ErrCode = MAT_OK then begin { Initialize parameters } CopyVector(X, OldX, Lbound, Ubound); { Minimize in the direction specified by DeltaX } ErrCode := LinMin(Func, X, DeltaX, Lbound, Ubound, 100, 0.01, F1); { Check that the function has decreased. Otherwise increase Lambda, without exceeding LAMBDAMAX } Lambda_Ok := (F1 - F_min) < F_min * FTOL; if not Lambda_Ok then Lambda := 10.0 * Lambda; if Lambda > LAMBDAMAX then ErrCode := OPT_BIG_LAMBDA; end; until Lambda_Ok or (ErrCode <> MAT_OK); { Check for convergence } Conv := ParamConv(OldX, X, Lbound, Ubound, Tol); { Prepare next iteration } Lambda := 0.1 * Lambda; F_min := F1; end; Inc(Iter); if Iter > MaxIter then ErrCode := OPT_NON_CONV; until Done or (ErrCode <> OPT_OK); DelVector(OldX, Ubound); DelVector(G, Ubound); DelMatrix(H, Ubound, Ubound); DelMatrix(A, Ubound, Ubound); DelVector(DeltaX, Ubound); if WriteLogFile then Close(LogFile); if ErrCode = MAT_SINGUL then ErrCode := OPT_SING; Marquardt := ErrCode; end; function BFGS(Func : TFuncNVar; Gradient : TGradient; X : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; H_inv : PMatrix) : Integer; var I, J, Iter, ErrCode : Integer; DeltaXmax, Gmax, P1, P2, R1, R2 : Float; OldX, DeltaX, dX, G, OldG, dG, HdG, R1dX, R2HdG, U, P2U : PVector; Conv : Boolean; function AbsMax(V : PVector; Lbound, Ubound : Integer) : Float; { Returns the component with maximum absolute value } var I : Integer; AbsV : PVector; begin DimVector(AbsV, Ubound); for I := Lbound to Ubound do AbsV^[I] := Abs(V^[I]); AbsMax := Max(AbsV, Lbound, Ubound); DelVector(AbsV, Ubound); end; begin if WriteLogFile then begin CreateLogFile; WriteLn(LogFile, 'BFGS'); WriteLn(LogFile, 'Iter F'); end; DimVector(OldX, Ubound); DimVector(DeltaX, Ubound); DimVector(dX, Ubound); DimVector(G, Ubound); DimVector(OldG, Ubound); DimVector(dG, Ubound); DimVector(HdG, Ubound); DimVector(R1dX, Ubound); DimVector(R2HdG, Ubound); DimVector(U, Ubound); DimVector(P2U, Ubound); Iter := 0; Conv := False; LinObjFunc := Func; { Function for line minimization } { Initialize function } F_min := Func(X); { Initialize inverse hessian to unit matrix } for I := Lbound to Ubound do for J := Lbound to Ubound do if I = J then H_inv^[I]^[J] := 1.0 else H_inv^[I]^[J] := 0.0; { Initialize gradient } Gradient(Func, X, Lbound, Ubound, G); Gmax := AbsMax(G, Lbound, Ubound); { Initialize search direction } if Gmax > MACHEP then for I := Lbound to Ubound do DeltaX^[I] := - G^[I] else Conv := True; { Quit if gradient is already small } while (not Conv) and (Iter < MaxIter) do begin if WriteLogFile then WriteLn(LogFile, Iter:4, ' ', F_min:12); { Normalize search direction to avoid excessive displacements } DeltaXmax := AbsMax(DeltaX, Lbound, Ubound); if DeltaXmax > 1.0 then for I := Lbound to Ubound do DeltaX^[I] := DeltaX^[I] / DeltaXmax; { Save old parameters and gradient } CopyVector(OldX, X, Lbound, Ubound); CopyVector(OldG, G, Lbound, Ubound); { Minimize along the direction specified by DeltaX } ErrCode := LinMin(Func, X, DeltaX, Lbound, Ubound, 100, 0.01, F_min); { Compute new gradient } Gradient(Func, X, Lbound, Ubound, G); { Compute differences between two successive estimations of parameter vector and gradient vector } for I := Lbound to Ubound do begin dX^[I] := X^[I] - OldX^[I]; dG^[I] := G^[I] - OldG^[I]; end; { Multiply by inverse hessian } for I := Lbound to Ubound do begin HdG^[I] := 0.0; for J := Lbound to Ubound do HdG^[I] := HdG^[I] + H_inv^[I]^[J] * dG^[J]; end; { Scalar products in denominator of BFGS formula } P1 := 0.0; P2 := 0.0; for I := Lbound to Ubound do begin P1 := P1 + dX^[I] * dG^[I]; P2 := P2 + dG^[I] * HdG^[I]; end; if (P1 = 0.0) or (P2 = 0.0) then Conv := True else begin { Inverses of scalar products } R1 := 1.0 / P1; R2 := 1.0 / P2; { Compute BFGS correction terms } for I := Lbound to Ubound do begin R1dX^[I] := R1 * dX^[I]; R2HdG^[I] := R2 * HdG^[I]; U^[I] := R1dX^[I] - R2HdG^[I]; P2U^[I] := P2 * U^[I]; end; { Update inverse hessian } for I := Lbound to Ubound do for J := Lbound to Ubound do H_inv^[I]^[J] := H_inv^[I]^[J] + R1dX^[I] * dX^[J] - R2HdG^[I] * HdG^[J] + P2U^[I] * U^[J]; { Update search direction } for I := Lbound to Ubound do begin DeltaX^[I] := 0.0; for J := Lbound to Ubound do DeltaX^[I] := DeltaX^[I] - H_inv^[I]^[J] * G^[J]; end; { Test convergence and update iteration count } Conv := ParamConv(OldX, X, Lbound, Ubound, Tol); Inc(Iter); end; end; DelVector(OldX, Ubound); DelVector(DeltaX, Ubound); DelVector(dX, Ubound); DelVector(G, Ubound); DelVector(OldG, Ubound); DelVector(dG, Ubound); DelVector(HdG, Ubound); DelVector(R1dX, Ubound); DelVector(R2HdG, Ubound); DelVector(U, Ubound); DelVector(P2U, Ubound); if WriteLogFile then Close(LogFile); if Iter > MaxIter then BFGS := OPT_NON_CONV else BFGS := OPT_OK; end; begin X1 := nil; DeltaX1 := nil; Ubound1 := 1; Eps := Power(MACHEP, 0.333); end. ����������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/fitlogis.pas���������������������������������������0000755�0001750�0001750�00000016076�11326425446�021625� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITLOGIS.PAS * * Version 1.4 * * (c) J. Debord, August 2000 * ********************************************************************** This unit fits the logistic function : B - A y = A + ----------------- 1 + exp(-a.x + b) ********************************************************************** } unit FitLogis; {$F+} interface uses FMath, Matrices, Stat, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X : Float; B, D : PVector); function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; procedure InitModel(CstPar : PVector); implementation const ConsTerm : Boolean = True; { Flags the presence of a constant term A } function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function. -------------------------------------------------------------------- } begin if ConsTerm then FuncName := 'y = A + (B - A) / [1 + exp(-a.x + b)]' else FuncName := 'y = B / [1 + exp(-a.x + b)]'; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted (0 if there is a constant term A, 1 otherwise) -------------------------------------------------------------------- } begin if ConsTerm then FirstParam := 0 else FirstParam := 1; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 3; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter. -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'A'; 1 : ParamName := 'B'; 2 : ParamName := 'a'; 3 : ParamName := 'b'; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X. B is the vector of parameters, such that : B^[0] = A B^[1] = B B^[2] = a B^[3] = b -------------------------------------------------------------------- } begin if ConsTerm then RegFunc := B^[0] + (B^[1] - B^[0]) / (1.0 + Expo(- B^[2] * X + B^[3])) else RegFunc := B^[1] / (1.0 + Expo(- B^[2] * X + B^[3])); end; procedure DerivProc(X : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point X with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter -------------------------------------------------------------------- } var Q, R : Float; begin Q := Expo(- B^[2] * X + B^[3]); { exp(-ax+b) } R := 1.0 / (1.0 + Q); { 1 / [1 + exp(-ax+b)] } D^[0] := 1.0 - R; { dy/dA = 1 - 1 / [1 + exp(-ax+b)] } D^[1] := R; { dy/dB = 1 / [1 + exp(-ax+b)] } { dy/db = (A-B).exp(-ax+b) / [1 + exp(-ax+b)]^2 } D^[3] := (B^[0] - B^[1]) * Q * Sqr(R); { dy/da = (B-A).x.exp(-ax+b) / [1 + exp(-ax+b)]^2 } D^[2] := - D^[3] * X; end; procedure SortPoints(X, Y : PVector; N : Integer); { ---------------------------------------------------------------------- Sort points by increasing X values ---------------------------------------------------------------------- } var I, J, K : Integer; A : Float; begin for I := 1 to Pred(N) do begin K := I; A := X^[I]; for J := Succ(I) to N do if X^[J] < A then begin K := J; A := X^[J]; end; FSwap(X^[I], X^[K]); FSwap(Y^[I], Y^[K]); end; end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of a logistic function by linear regression: Ln[(B - A)/(y - A) - 1] = -ax + b -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- } var XX : PVector; { Transformed X coordinates } YY : PVector; { Transformed Y coordinates } WW : PVector; { Weights } A : PVector; { Linear regression parameters } V : PMatrix; { Variance-covariance matrix } P : Integer; { Number of points for linear regression } K : Integer; { Loop variable } ErrCode : Integer; { Error code } D : Float; { B - A } begin DimVector(XX, N); DimVector(YY, N); DimVector(WW, N); DimVector(A, 1); DimMatrix(V, 1, 1); SortPoints(X, Y, N); if ConsTerm then B^[0] := Y^[1] else B^[0] := 0.0; B^[1] := Y^[N]; P := 0; D := B^[1] - B^[0]; for K := 1 to N do if (X^[K] > X^[1]) and (X^[K] < X^[N]) then begin Inc(P); XX^[P] := X^[K]; YY^[P] := Log(D / (Y^[K] - B^[0]) - 1.0); WW^[P] := Sqr((Y^[K] - B^[0]) * (Y^[K] - B^[1]) / D); if Method = 1 then WW^[P] := WW^[P] * W^[K]; end; ErrCode := WLinFit(XX, YY, WW, P, A, V); if ErrCode = MAT_OK then begin B^[2] := - A^[1]; B^[3] := A^[0]; end; FitModel := ErrCode; DelVector(XX, N); DelVector(YY, N); DelVector(WW, N); DelVector(A, 1); DelMatrix(V, 1, 1); end; procedure InitModel(CstPar : PVector); { -------------------------------------------------------------------- Initializes the global variables of the unit. -------------------------------------------------------------------- CstPar^[0] = 1 to include a constant term (A) -------------------------------------------------------------------- } begin ConsTerm := (CstPar^[0] = 1); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/mcmc.pas�������������������������������������������0000755�0001750�0001750�00000024075�11326425446�020722� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit MCMC.PAS * * Version 1.2 * * (c) J. Debord, June 2001 * ********************************************************************** Simulation by Markov Chain Monte Carlo (MCMC) with the Metropolis-Hastings algorithm. This algorithm simulates the probability density function (pdf) of a vector X. The pdf P(X) is written as: P(X) = C * Exp(- F(X) / T) Simulating P by the Metropolis-Hastings algorithm is equivalent to minimizing F by simulated annealing at the constant temperature T. The constant C is not used in the simulation. The series of random vectors generated during the annealing step constitutes a Markov chain which tends towards the pdf to be simulated. It is possible to run several cycles of the algorithm. The variance-covariance matrix of the simulated distribution is re-evaluated at the end of each cycle and used for the next cycle. ********************************************************************** } unit MCMC; interface uses FMath, Matrices, Optim, Regress; { ********************************************************************** Metropolis-Hastings parameters ********************************************************************** } const MH_NCycles : Integer = 1; { Number of cycles } MH_MaxSim : Integer = 1000; { Max nb of simulations at each cycle } MH_SavedSim : Integer = 200; { Nb of simulations to be saved } { ********************************************************************** Simulation routine ********************************************************************** } function Hastings(Func : TFuncNVar; T : Float; X : PVector; V : PMatrix; Lbound, Ubound : Integer; Xmat : PMatrix; X_min : PVector; var F_min : Float) : Integer; { ---------------------------------------------------------------------- Simulation of a probability density function by the Metropolis-Hastings algorithm ---------------------------------------------------------------------- Input parameters : Func = Function such that the pdf is P(X) = C * Exp(- Func(X) / T) T = Temperature X = Initial mean vector V = Initial variance-covariance matrix Lbound, Ubound = Indices of first and last variables ---------------------------------------------------------------------- Output parameters : Xmat = Matrix of simulated vectors, stored columnwise, i.e. Xmat[Lbound..Ubound, 1..MH_SavedSim] X = Mean of distribution V = Variance-covariance matrix of distribution X_min = Coordinates of minimum of F(X) (mode of the distribution) F_min = Value of F(X) at minimum ---------------------------------------------------------------------- Possible results : MAT_OK : No error MAT_NOT_PD : The variance-covariance matrix is not positive definite ---------------------------------------------------------------------- } implementation function CalcSD(V : PMatrix; Lbound, Ubound : Integer; L : PMatrix) : Integer; { ---------------------------------------------------------------------- Computes the standard deviations for independent random numbers from the variance-covariance matrix. ---------------------------------------------------------------------- } var I, ErrCode : Integer; begin I := LBound; ErrCode := 0; repeat if V^[I]^[I] > 0.0 then L^[I]^[I] := Sqrt(V^[I]^[I]) else ErrCode := MAT_NOT_PD; Inc(I); until (ErrCode <> 0) or (I > Ubound); CalcSD := ErrCode; end; procedure GenIndepRandomVector(X : PVector; L : PMatrix; Lbound, Ubound : Integer; X1 : PVector); { ---------------------------------------------------------------------- Generates a random vector X1 from X, using independent gaussian random increments. L is the diagonal matrix of the standard deviations. ---------------------------------------------------------------------- } var I : Integer; begin for I := Lbound to Ubound do X1^[I] := RanGauss(X^[I], L^[I]^[I]); end; procedure GenRandomVector(X : PVector; L : PMatrix; Lbound, Ubound : Integer; X1 : PVector); { ---------------------------------------------------------------------- Generates a random vector X1 from X, using correlated gaussian random increments. L is the Cholesky factor of the variance-covariance matrix ---------------------------------------------------------------------- } var U : PVector; I, J : Integer; begin { Form a vector U of independent standard normal variates } DimVector(U, Ubound); for I := Lbound to Ubound do U^[I] := RanGaussStd; { Form X1 = X + L*U, which follows the multinormal distribution } for I := Lbound to Ubound do begin X1^[I] := X^[I]; for J := Lbound to I do X1^[I] := X1^[I] + L^[I]^[J] * U^[J]; end; DelVector(U, Ubound); end; function Accept(DeltaF, T : Float) : Boolean; { ---------------------------------------------------------------------- Checks if a variation DeltaF of the function at temperature T is acceptable. ---------------------------------------------------------------------- } begin Accept := (DeltaF < 0.0) or (Expo(- DeltaF / T) > RanMar); end; function HastingsCycle(Func : TFuncNVar; T : Float; X : PVector; V : PMatrix; Lbound, Ubound : Integer; Indep : Boolean; Xmat : PMatrix; X_min : PVector; var F_min : Float) : Integer; { ---------------------------------------------------------------------- Performs one cycle of the Metropolis-Hastings algorithm ---------------------------------------------------------------------- } var F, F1 : Float; { Function values } DeltaF : Float; { Variation of function } X1 : PVector; { New coordinates } L : PMatrix; { Standard dev. or Cholesky factor } I, K : Integer; { Loop variable } Iter : Integer; { Iteration count } FirstSavedSim : Integer; { Index of first simulation to be saved } ErrCode : Integer; { Error code } begin { Dimension arrays } DimVector(X1, Ubound); DimMatrix(L, Ubound, Ubound); { Compute SD's or Cholesky factor } if Indep then ErrCode := CalcSD(V, Lbound, Ubound, L) else ErrCode := Cholesky(V, Lbound, Ubound, L); HastingsCycle := ErrCode; if ErrCode = MAT_NOT_PD then Exit; { Compute initial function value } F := Func(X); { Perform MH_MaxSim simulations at constant temperature } FirstSavedSim := MH_MaxSim - MH_SavedSim + 1; Iter := 1; K := 1; repeat { Generate new vector } if Indep then GenIndepRandomVector(X, L, Lbound, Ubound, X1) else GenRandomVector(X, L, Lbound, Ubound, X1); { Compute new function value } F1 := Func(X1); DeltaF := F1 - F; { Check for acceptance } if Accept(DeltaF, T) then begin CopyVector(X, X1, Lbound, Ubound); if Iter >= FirstSavedSim then begin { Save simulated vector into column K of matrix Xmat } CopyColFromVector(Xmat, X1, Lbound, Ubound, K); Inc(K); end; if F1 < F_min then begin { Update minimum } CopyVector(X_min, X1, Lbound, Ubound); F_min := F1; end; F := F1; Inc(Iter); end; until Iter > MH_MaxSim; { Update mean vector and variance-covariance matrix } VecMean(Xmat, MH_SavedSim, Lbound, Ubound, X); MatVarCov(Xmat, MH_SavedSim, Lbound, Ubound, X, V); DelVector(X1, Ubound); DelMatrix(L, Ubound, Ubound); end; function Hastings(Func : TFuncNVar; T : Float; X : PVector; V : PMatrix; Lbound, Ubound : Integer; Xmat : PMatrix; X_min : PVector; var F_min : Float) : Integer; var K, ErrCode : Integer; Indep : Boolean; begin { Initialize the Marsaglia random number generator using the standard Pascal generator } Randomize; RMarIn(System.Random(10000), System.Random(10000)); K := 1; Indep := True; F_min := MAXNUM; repeat ErrCode := HastingsCycle(Func, T, X, V, Lbound, Ubound, Indep, Xmat, X_min, F_min); Indep := False; Inc(K); until (ErrCode <> 0) or (K > MH_NCycles); Hastings := ErrCode; end; end.�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/simopt.pas�����������������������������������������0000755�0001750�0001750�00000024425�11326425446�021315� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit SIMOPT.PAS * * Version 1.0 * * (c) J. Debord, August 2000 * ********************************************************************** This unit implements simulated annealing for function minimization ********************************************************************** Reference: Program SIMANN.FOR by Bill Goffe (http://www.netlib.org/simann) ********************************************************************** } unit SimOpt; interface uses FMath, Matrices, Optim, Stat; const SA_Nt : Integer = 5; { Number of loops at constant temperature } SA_Ns : Integer = 15; { Number of loops before step adjustment } SA_Rt : Float = 0.9; { Temperature reduction factor } SA_NCycles : Integer = 1; { Number of cycles } function SimAnn(Func : TFuncNVar; X, Xmin, Xmax : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float) : Integer; { ---------------------------------------------------------------------- Minimization of a function of several variables by simulated annealing ---------------------------------------------------------------------- Input parameters : Func = objective function to be minimized X = initial minimum coordinates Xmin = minimum value of X Xmax = maximum value of X Lbound, Ubound = indices of first and last variables MaxIter = max number of annealing steps Tol = required precision ---------------------------------------------------------------------- Output parameter : X = refined minimum coordinates F_min = function value at minimum ---------------------------------------------------------------------- Possible results : OPT_OK OPT_NON_CONV ---------------------------------------------------------------------- } implementation var LogFile : Text; { Stores the result of each minimization step } procedure CreateLogFile; begin Assign(LogFile, LogFileName); Rewrite(LogFile); end; function InitTemp(Func : TFuncNVar; X, Xmin, Range : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Computes the initial temperature so that the probability of accepting an increase of the function is about 0.5 ---------------------------------------------------------------------- } const N_EVAL = 50; { Number of function evaluations } var T : Float; { Temperature } F, F1 : Float; { Function values } DeltaF : PVector; { Function increases } N_inc : Integer; { Number of function increases } I : Integer; { Index of function evaluation } K : Integer; { Index of parameter } begin DimVector(DeltaF, N_EVAL); T := 0.0; N_inc := 0; F := Func(X); { Compute N_EVAL function values, changing each parameter in turn } K := Lbound; for I := 1 to N_EVAL do begin X^[K] := Xmin^[K] + RanMar * Range^[K]; F1 := Func(X); if F1 > F then begin Inc(N_inc); DeltaF^[N_inc] := F1 - F; end; F := F1; Inc(K); if K > Ubound then K := Lbound; end; { The median M of these N_eval values has a probability of 1/2. From Boltzmann's formula: Exp(-M/T) = 1/2 ==> T = M / Ln(2) } T := Median(DeltaF, 1, N_inc) / LN2; if T = 0.0 then T := 1.0; InitTemp := T; DelVector(DeltaF, N_EVAL); end; function ParamConv(X, Step : PVector; Lbound, Ubound : Integer; Tol : Float) : Boolean; { ---------------------------------------------------------------------- Checks for convergence on parameters ---------------------------------------------------------------------- } var I : Integer; Conv : Boolean; begin I := Lbound; Conv := True; repeat Conv := Conv and (Step^[I] < FMax(Tol, Tol * Abs(X^[I]))); Inc(I); until (Conv = False) or (I > Ubound); ParamConv := Conv; end; function Accept(DeltaF, T : Float; var N_inc, N_acc : Integer) : Boolean; { ---------------------------------------------------------------------- Checks if a variation DeltaF of the function at temperature T is acceptable. Updates the counters N_inc (number of increases of the function) and N_acc (number of accepted increases). ---------------------------------------------------------------------- } begin if DeltaF < 0.0 then Accept := True else begin Inc(N_inc); if Expo(- DeltaF / T) > RanMar then begin Accept := True; Inc(N_acc); end else Accept := False; end; end; function SimAnnCycle(Func : TFuncNVar; X, Xmin, Xmax : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var LogFile : Text; var F_min : Float) : Integer; { ---------------------------------------------------------------------- Performs one cycle of simulated annealing ---------------------------------------------------------------------- } const N_FACT = 2.0; { Factor for step reduction } var I, Iter, J, K, N_inc, N_acc : Integer; F, F1, DeltaF, Ratio, T, OldX : Float; Range, Step, Xopt : PVector; Nacc : PIntVector; begin DimVector(Step, Ubound); DimVector(Xopt, Ubound); DimVector(Range, Ubound); DimIntVector(Nacc, Ubound); { Determine parameter range, step and optimum } for K := Lbound to Ubound do begin Range^[K] := Xmax^[K] - Xmin^[K]; Step^[K] := 0.5 * Range^[K]; Xopt^[K] := X^[K]; end; { Initialize function values } F := Func(X); F_min := F; { Initialize temperature and iteration count } T := InitTemp(Func, X, Xmin, Range, Lbound, Ubound); Iter := 0; repeat { Perform SA_Nt evaluations at constant temperature } N_inc := 0; N_acc := 0; for I := 1 to SA_Nt do begin for J := 1 to SA_Ns do for K := Lbound to Ubound do begin { Save current parameter value } OldX := X^[K]; { Pick new value, keeping it within Range } X^[K] := X^[K] + (2.0 * RanMar - 1.0) * Step^[K]; if (X^[K] < Xmin^[K]) or (X^[K] > Xmax^[K]) then X^[K] := Xmin^[K] + RanMar * Range^[K]; { Compute new function value } F1 := Func(X); DeltaF := F1 - F; { Check for acceptance } if Accept(DeltaF, T, N_inc, N_acc) then begin Inc(Nacc^[K]); F := F1; end else { Restore parameter value } X^[K] := OldX; { Update minimum if necessary } if F < F_min then begin Xopt^[K] := X^[K]; F_min := F; end; end; { Ajust step length to maintain an acceptance ratio of about 50% for each parameter } for K := Lbound to Ubound do begin Ratio := Int(Nacc^[K]) / Int(SA_Ns); if Ratio > 0.6 then begin { Increase step length, keeping it within Range } Step^[K] := Step^[K] * (1.0 + ((Ratio - 0.6) / 0.4) * N_FACT); if Step^[K] > Range^[K] then Step^[K] := Range^[K]; end else if Ratio < 0.4 then { Reduce step length } Step^[K] := Step^[K] / (1.0 + ((0.4 - Ratio) / 0.4) * N_FACT); { Restore counter } Nacc^[K] := 0; end; end; if WriteLogFile then WriteLn(LogFile, Iter:4, ' ', T:12, ' ', F:12, N_inc:6, N_acc:6); { Update temperature and iteration count } T := T * SA_Rt; Inc(Iter); until ParamConv(Xopt, Step, Lbound, Ubound, Tol) or (Iter > MaxIter); for K := Lbound to Ubound do X^[K] := Xopt^[K]; DelVector(Step, Ubound); DelVector(Xopt, Ubound); DelVector(Range, Ubound); DelIntVector(Nacc, Ubound); if Iter > MaxIter then SimAnnCycle := OPT_NON_CONV else SimAnnCycle := OPT_OK; end; function SimAnn(Func : TFuncNVar; X, Xmin, Xmax : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float) : Integer; var Cycle, ErrCode : Integer; begin if WriteLogFile then CreateLogFile; { Initialize the Marsaglia random number generator using the standard Pascal generator } Randomize; RMarIn(System.Random(10000), System.Random(10000)); Cycle := 1; repeat if WriteLogFile then begin WriteLn(LogFile, 'Simulated annealing: Cycle ', Cycle); WriteLn(LogFile); WriteLn(LogFile, 'Iter T F Inc Acc'); end; ErrCode := SimAnnCycle(Func, X, Xmin, Xmax, Lbound, Ubound, MaxIter, Tol, LogFile, F_min); Inc(Cycle); until (Cycle > SA_NCycles) or (ErrCode <> OPT_OK); if WriteLogFile then Close(LogFile); SimAnn := ErrCode; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/plot.pas�������������������������������������������0000755�0001750�0001750�00000043115�11326425446�020755� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit PLOT.PAS * * Version 1.7 * * (c) J. Debord, June 2001 * ********************************************************************** Plotting routines for Turbo Pascal ********************************************************************** } unit Plot; interface uses Graph, FMath, Matrices, PaString; const BGIPath : String = 'C:\BP\BGI'; { Access path for graphic drivers } DefSymbSize : Integer = 3; { Default symbol size } { ********************** Include global variables ********************** } {$I PLOTVAR.INC} { ************************** Graphic routines ************************** } function GraphOk : Boolean; { ---------------------------------------------------------------------- Initializes high resolution graphics and plots the axes ---------------------------------------------------------------------- } procedure PlotGrid; { ---------------------------------------------------------------------- Plots a grid on the graph ---------------------------------------------------------------------- } procedure WriteLegend(NCurv : Integer); { ---------------------------------------------------------------------- Writes the graph title and the legends for the plotted curves Input parameter : NCurv = number of curves (1 to MAXCURV) ---------------------------------------------------------------------- } procedure SetClipping(Clip : Boolean); { ---------------------------------------------------------------------- Determines whether drawings are clipped at the current viewport boundaries, according to the value of the Boolean parameter Clip ---------------------------------------------------------------------- } procedure PlotPoint(Xp, Yp, Symbol, Size, Trace : Integer); { ---------------------------------------------------------------------- Plots a point on the screen ---------------------------------------------------------------------- Input parameters : Xp, Yp : point coordinates in pixels Symbol : 0 = point (.) 1 = solid circle 2 = open circle 3 = solid square 4 = open square 5 = solid triangle 6 = open triangle 7 = plus (+) 8 = multiply (x) 9 = star (*) Size : symbol size Trace : type of line between points 0 = none 1 = solid 2 = dotted 3 = centered 4 = dashed ---------------------------------------------------------------------- } procedure PlotCurve(X, Y : PVector; Lbound, Ubound, Symbol, Trace : Integer); { ---------------------------------------------------------------------- Plots a curve ---------------------------------------------------------------------- Input parameters : X, Y = point coordinates Lbound, Ubound = indices of first and last points Symbol, Trace = as in PlotPoint ---------------------------------------------------------------------- } procedure PlotCurveWithErrorBars(X, Y, S : PVector; Lbound, Ubound, Symbol, Trace : Integer); { ---------------------------------------------------------------------- Plots a curve with error bars ---------------------------------------------------------------------- Input parameters : X, Y = point coordinates S = errors (standard deviations) Lbound, Ubound = indices of first and last points Symbol, Trace = as in PlotPoint ---------------------------------------------------------------------- } procedure PlotFunc(Func : TFunc; X1, X2 : Float; Trace : Integer); { ---------------------------------------------------------------------- Plots a function ---------------------------------------------------------------------- Input parameters : Func = function to be plotted X1, X2 = abscissae of 1st and last point to plot Trace = as in PlotPoint ---------------------------------------------------------------------- The function must be programmed as : function Func(X : Float) : Float; ---------------------------------------------------------------------- } { *********** The following routines are defined in PLOT.INC *********** } procedure Interval(X1, X2 : Float; MinDiv, MaxDiv : Integer; var Min, Max, Step : Float); { ---------------------------------------------------------------------- Determines an interval [Min, Max] including the values from X1 to X2, and a subdivision Step of this interval ---------------------------------------------------------------------- Input parameters : X1, X2 = min. & max. values to be included MinDiv = minimum nb of subdivisions MaxDiv = maximum nb of subdivisions ---------------------------------------------------------------------- Output parameters : Min, Max, Step ---------------------------------------------------------------------- } procedure AutoScale(Z : PVector; Lbound, Ubound : Integer; var Axis : TAxis); { ---------------------------------------------------------------------- Determines the scale of an axis ---------------------------------------------------------------------- Input parameters : Z = array of values to be plotted Lbound, Ubound = indices of first and last elements of Z ---------------------------------------------------------------------- Output parameters : Axis ---------------------------------------------------------------------- } function Xpixel(X : Float) : Integer; { ---------------------------------------------------------------------- Converts user abscissa X to screen coordinate ---------------------------------------------------------------------- } function Ypixel(Y : Float) : Integer; { ---------------------------------------------------------------------- Converts user ordinate Y to screen coordinate ---------------------------------------------------------------------- } function Xuser(X : Integer) : Float; { ---------------------------------------------------------------------- Converts screen coordinate X to user abscissa ---------------------------------------------------------------------- } function Yuser(Y : Integer) : Float; { ---------------------------------------------------------------------- Converts screen coordinate Y to user ordinate ---------------------------------------------------------------------- } implementation { ---------------------------------------------------------------------- Include the variables and routines common to PLOT.PAS and WINPLOT.PAS ---------------------------------------------------------------------- } {$I PLOT.INC} { ---------------------------------------------------------------------- } procedure PlotXAxis; var W, X, Z : Float; N, I, J : Integer; NSZ : Boolean; begin Line(XminPixel, YmaxPixel, XmaxPixel, YmaxPixel); SetTextStyle(XTitle.Font, HorizDir, 1); SetUserCharSize(XTitle.CharWidth, 100, XTitle.CharHeight, 100); SetTextJustify(CenterText, TopText); N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); { Nb of intervals } X := XAxis.Min; { Tick mark position } NSZ := NSZero; NSZero := False; { Don't write non significant zero's } for I := 0 to N do { Label axis } begin if (XAxis.Scale = LIN_SCALE) and (Abs(X) < EPS) then X := 0.0; MoveTo(Xpixel(X), YmaxPixel); LineRel(0, 5); { Plot tick mark } if XAxis.Scale = LIN_SCALE then Z := X else Z := Exp10(X); OutText(Trim(FloatToStr(Z))); if (XAxis.Scale = LOG_SCALE) and (I < N) then for J := 2 to 9 do { Plot minor divisions } begin { on logarithmic scale } W := X + Log10(J); MoveTo(Xpixel(W), YmaxPixel); LineRel(0, 3); end; X := X + XAxis.Step; end; if XTitle.Text <> '' then { Plot axis title } OutTextXY((XminPixel + XmaxPixel) div 2, YmaxPixel + GetMaxY div 12, XTitle.Text); NSZero := NSZ; end; procedure PlotYAxis; var W, Y, Z : Float; N, I, J : Integer; NSZ : Boolean; begin Line(XminPixel, YminPixel, XminPixel, YmaxPixel); SetTextStyle(YTitle.Font, HorizDir, 1); SetUserCharSize(YTitle.CharWidth, 100, YTitle.CharHeight, 100); SetTextJustify(RightText, CenterText); N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); Y := YAxis.Min; NSZ := NSZero; NSZero := False; for I := 0 to N do begin if (YAxis.Scale = LIN_SCALE) and (Abs(Y) < EPS) then Y := 0.0; MoveTo(XminPixel, Ypixel(Y)); LineRel(- 5, 0); MoveRel(- 2, - 2); if YAxis.Scale = LIN_SCALE then Z := Y else Z := Exp10(Y); OutText(Trim(FloatToStr(Z))); if (YAxis.Scale = LOG_SCALE) and (I < N) then for J := 2 to 9 do begin W := Y + Log10(J); MoveTo(XminPixel, Ypixel(W)); LineRel(- 3, 0); end; Y := Y + YAxis.Step; end; if YTitle.Text <> '' then begin SetTextStyle(YTitle.Font, VertDir, 1); SetUserCharSize(YTitle.CharWidth, 100, YTitle.CharHeight, 100); OutTextXY(XminPixel - GetMaxX div 8, (YminPixel + YmaxPixel) div 2, YTitle.Text); end; NSZero := NSZ; end; function GraphOk : Boolean; var Pilot, Mode : Integer; begin Pilot := Detect; InitGraph(Pilot, Mode, BGIPath); if GraphResult <> 0 then begin GraphOk := False; Exit; end; GraphOk := True; XminPixel := Round(Xwin1 / 100 * GetMaxX); YminPixel := Round(Ywin1 / 100 * GetMaxY); XmaxPixel := Round(Xwin2 / 100 * GetMaxX); YmaxPixel := Round(Ywin2 / 100 * GetMaxY); FactX := (XmaxPixel - XminPixel) / (XAxis.Max - XAxis.Min); FactY := (YmaxPixel - YminPixel) / (YAxis.Max - YAxis.Min); if GraphBorder then Rectangle(XminPixel, YminPixel, XmaxPixel, YmaxPixel); PlotXAxis; PlotYAxis; end; procedure PlotGrid; var X, Y : Float; I, N, Xp, Yp : Integer; begin SetLineStyle(DottedLn, 0, NormWidth); if Grid in [HORIZ_GRID, BOTH_GRID] then { Horizontal lines } begin N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); { Nb of intervals } for I := 1 to Pred(N) do begin Y := YAxis.Min + I * YAxis.Step; { Origin of line } Yp := Ypixel(Y); Line(XminPixel, Yp, XmaxPixel, Yp); end; end; if Grid in [VERTIC_GRID, BOTH_GRID] then { Vertical lines } begin N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); for I := 1 to Pred(N) do begin X := XAxis.Min + I * XAxis.Step; Xp := Xpixel(X); Line(Xp, YminPixel, Xp, YmaxPixel); end; end; SetLineStyle(SolidLn, 0, NormWidth); end; procedure PlotPoint(Xp, Yp, Symbol, Size, Trace : Integer); var Xasp, Yasp, Xp1, Xp2, Yp1, Yp2, Dx, Dy : Word; R : Float; Triangle : array[1..4] of PointType; Square : array[1..5] of PointType; begin if Trace = 0 then MoveTo(Xp, Yp) else begin SetLineStyle(Pred(Trace), 0, NormWidth); LineTo(Xp, Yp); SetLineStyle(0, 0, 1); end; GetAspectRatio(Xasp, Yasp); R := 0.0001 * Size; Dx := Round(R * Yasp); Dy := Round(R * Xasp); Xp1 := Xp - Size; Xp2 := Xp + Size; Yp1 := Yp - Size; Yp2 := Yp + Size; if Symbol in [3, 4] then begin Square[1].X := Xp1; Square[1].Y := Yp1; Square[2].X := Xp1; Square[2].Y := Yp2; Square[3].X := Xp2; Square[3].Y := Yp2; Square[4].X := Xp2; Square[4].Y := Yp1; Square[5].X := Xp1; Square[5].Y := Yp1; end; if Symbol in [5, 6] then begin Triangle[1].X := Xp; Triangle[1].Y := Yp1; Triangle[2].X := Xp2; Triangle[2].Y := Yp2; Triangle[3].X := Xp1; Triangle[3].Y := Yp2; Triangle[4].X := Xp; Triangle[4].Y := Yp1; end; case Symbol of 0 : PutPixel(Xp, Yp, GetColor); { } 1 : PieSlice(Xp, Yp, 0, 360, Dx); { Solid circle } 2 : Ellipse(Xp, Yp, 0, 360, Dx, Dy); { Open circle } 3 : FillPoly(5, Square); { Solid square } 4 : DrawPoly(5, Square); { Open square } 5 : FillPoly(4, Triangle); { Solid triangle } 6 : DrawPoly(4, Triangle); { Open triangle } 7 : begin { + } Line(Xp, Yp1, Xp, Yp2); Line(Xp1, Yp, Xp2, Yp); end; 8 : begin { x } Line(Xp1, Yp1, Xp2, Yp2); Line(Xp1, Yp2, Xp2, Yp1); end; 9 : begin Line(Xp, Yp1, Xp, Yp2); { * } Line(Xp1, Yp, Xp2, Yp); Line(Xp1, Yp1, Xp2, Yp2); Line(Xp1, Yp2, Xp2, Yp1); end; end; end; procedure WriteLegend(NCurv : Integer); var I, Xp, Yp, Dy : Integer; begin with GraphTitle do if Text <> '' then begin SetTextStyle(Font, HorizDir, 1); SetUserCharSize(CharWidth, 100, CharHeight, 100); SetTextJustify(CenterText, TopText); OutTextXY((XminPixel + XmaxPixel) div 2, YminPixel - GetMaxY div 10, Text); end; with Legend do begin SetTextStyle(Font, HorizDir, 1); SetUserCharSize(CharWidth, 100, CharHeight, 100); SetTextJustify(LeftText, CenterText); Dy := (YmaxPixel - YminPixel) div 10; Xp := XmaxPixel + 30; Yp := YminPixel + Dy; for I := 1 to NCurv do if Text[I] <> '' then begin PlotPoint(Xp, Yp, I, SymbolSize, 0); OutTextXY(Xp + 20, Yp, Text[I]); Yp := Yp + Dy; end; end; end; procedure SetClipping(Clip : Boolean); begin if XminPixel = 0 then begin XminPixel := Round(Xwin1 / 100 * GetMaxX); YminPixel := Round(Ywin1 / 100 * GetMaxY); XmaxPixel := Round(Xwin2 / 100 * GetMaxX); YmaxPixel := Round(Ywin2 / 100 * GetMaxY); end; SetViewPort(XminPixel, YminPixel, XmaxPixel, YmaxPixel, Clip); XmaxPixel := XmaxPixel - XminPixel; XminPixel := 0; YmaxPixel := YmaxPixel - YminPixel; YminPixel := 0; end; procedure PlotCurve(X, Y : PVector; Lbound, Ubound, Symbol, Trace : Integer); var XI, YI : Float; I, NL : Integer; begin NL := 0; for I := Lbound to Ubound do begin XI := X^[I]; if XAxis.Scale = LOG_SCALE then XI := Log10(XI); YI := Y^[I]; if YAxis.Scale = LOG_SCALE then YI := Log10(YI); PlotPoint(Xpixel(XI), Ypixel(YI), Symbol, DefSymbSize, NL); NL := Trace; end; end; procedure PlotCurveWithErrorBars(X, Y, S : PVector; Lbound, Ubound, Symbol, Trace : Integer); var XI, YI, Y1, Y2 : Float; I, NL, Xp, Yp, Yp1, Yp2 : Integer; begin NL := 0; for I := Lbound to Ubound do begin XI := X^[I]; if XAxis.Scale = LOG_SCALE then XI := Log10(XI); YI := Y^[I]; if YAxis.Scale = LOG_SCALE then YI := Log10(YI); Xp := Xpixel(XI); Yp := Ypixel(YI); PlotPoint(Xp, Yp, Symbol, DefSymbSize, NL); if S^[I] > 0 then begin Y1 := Y^[I] - S^[I]; if YAxis.Scale = LOG_SCALE then Y1 := Log10(Y1); Y2 := Y^[I] + S^[I]; if YAxis.Scale = LOG_SCALE then Y2 := Log10(Y2); Yp1 := Ypixel(Y1); Yp2 := Ypixel(Y2); Line(Xp - 5, Yp1, Xp + 5, Yp1); Line(Xp - 5, Yp2, Xp + 5, Yp2); Line(Xp, Yp1, Xp, Yp2); end; NL := Trace; end; end; procedure PlotFunc(Func : TFunc; X1, X2 : Float; Trace : Integer); var X, Y, H : Float; I, Npt, NL, Xp, Yp : Integer; begin NL := 0; { Indicates if a line must be drawn from the previous point } X := X1; { Nb of points to be plotted = number of pixels between X1 and X2 } Npt := Xpixel(X2) - Xpixel(X1); H := (X2 - X1) / Npt; for I := 0 to Npt do begin X := X1 + I * H; if XAxis.Scale = LIN_SCALE then Y := Func(X) else Y := Func(Exp10(X)); if MathError <> FN_OK then NL := 0 else begin if YAxis.Scale = LOG_SCALE then Y := Log10(Y); Xp := Xpixel(X); Yp := Ypixel(Y); PlotPoint(Xp, Yp, 0, 0, NL); NL := Trace; end; end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/matcomp.pas����������������������������������������0000755�0001750�0001750�00000022156�11326425446�021441� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit MATCOMP.PAS * * Version 1.3 * * (c) J. Debord, August 2000 * ********************************************************************** Matrices with complex elements. See MATRICES.PAS for details concerning the dynamic allocation and use of matrices. ********************************************************************** References: 1) 'Basic Programs for Scientists and Engineers' by A.R. Miller 2) 'Numerical Recipes' by Press et al. ********************************************************************** } unit MatComp; interface uses FMath, FComp, Matrices; { ********************************************************************** This section defines the vector and matrix types. Maximal sizes are given for a 16-bit compiler (TP/BP). Higher values may be used with a 32-bit compiler such as FPC. ********************************************************************** } const {$IFDEF DOUBLEREAL} MAX_COMP = 3854; { Max size of complex vector } {$ELSE} {$IFDEF SINGLEREAL} MAX_COMP = 7280; {$ELSE} {$IFDEF PASCALREAL} MAX_COMP = 5040; {$ELSE} {$DEFINE EXTENDEDREAL} MAX_COMP = 3119; {$ENDIF} {$ENDIF} {$ENDIF} type TCompVector = array[0..MAX_COMP] of Complex; PCompVector = ^TCompVector; TCompMatrix = array[0..MAX_VEC] of PCompVector; PCompMatrix = ^TCompMatrix; { ********************************************************************** Memory allocation routines ********************************************************************** } procedure DimCompVector(var V : PCompVector; Ubound : Integer); { ---------------------------------------------------------------------- Creates complex vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DimCompMatrix(var A : PCompMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Creates complex matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } { ********************************************************************** Memory deallocation routines ********************************************************************** } procedure DelCompVector(V : PCompVector; Ubound : Integer); { ---------------------------------------------------------------------- Deletes complex vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DelCompMatrix(A : PCompMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Deletes complex matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } { ********************************************************************** Complex matrix functions ********************************************************************** } function C_LU_Decomp(A : PCompMatrix; Lbound, Ubound : Integer) : Integer; { ---------------------------------------------------------------------- LU decomposition ---------------------------------------------------------------------- } procedure C_LU_Solve(A : PCompMatrix; B : PCompVector; Lbound, Ubound : Integer; X : PCompVector); { ---------------------------------------------------------------------- Solves a system of equations whose matrix has been transformed by C_LU_Decomp ---------------------------------------------------------------------- } implementation const { Used by LU procedures } LastDim : Integer = 1; { Dimension of the last system solved } Index : PIntVector = nil; { Records the row permutations } procedure DimCompVector(var V : PCompVector; Ubound : Integer); var I : Integer; begin { Check bounds } if (Ubound < 0) or (Ubound > MAX_COMP) then begin V := nil; Exit; end; { Allocate vector } GetMem(V, Succ(Ubound) * SizeOf(Complex)); if V = nil then Exit; { Initialize vector } for I := 0 to Ubound do V^[I] := C_zero; end; procedure DimCompMatrix(var A : PCompMatrix; Ubound1, Ubound2 : Integer); var I, J : Integer; RowSize : Word; begin { Check bounds } if (Ubound1 < 0) or (Ubound1 > MAX_VEC) or (Ubound2 < 0) or (Ubound2 > MAX_COMP) then begin A := nil; Exit; end; { Size of a row } GetMem(A, Succ(Ubound1) * SizeOf(PCompVector)); if A = nil then Exit; { Allocate each row } for I := 0 to Ubound1 do begin GetMem(A^[I], RowSize); if A^[I] = nil then begin A := nil; Exit; end; end; { Initialize matrix } for I := 0 to Ubound1 do for J := 0 to Ubound2 do A^[I]^[J] := C_zero; end; procedure DelCompVector(V : PCompVector; Ubound : Integer); begin if V <> nil then begin FreeMem(V, Succ(Ubound) * SizeOf(Complex)); V := nil; end; end; procedure DelCompMatrix(A : PCompMatrix; Ubound1, Ubound2 : Integer); var I : Integer; RowSize : Word; begin if A <> nil then begin RowSize := Succ(Ubound2) * SizeOf(Complex); for I := Ubound1 downto 0 do FreeMem(A^[I], RowSize); FreeMem(A, Succ(Ubound1) * SizeOf(PCompVector)); A := nil; end; end; function C_LU_Decomp(A : PCompMatrix; Lbound, Ubound : Integer) : Integer; const TINY = 1.0E-20; var I, Imax, J, K : Integer; C, Pvt, T : Float; Sum, Z : Complex; V : PVector; begin DimVector(V, Ubound); { Reallocate Index } if Index <> nil then DelIntVector(Index, LastDim); DimIntVector(Index, Ubound); LastDim := Ubound; for I := Lbound to Ubound do begin Pvt := 0.0; for J := Lbound to Ubound do begin C := CAbs(A^[I]^[J]); if C > Pvt then Pvt := C; end; if Pvt < MACHEP then begin DelVector(V, Ubound); C_LU_Decomp := MAT_SINGUL; Exit; end; V^[I] := 1.0 / Pvt; end; for J := Lbound to Ubound do begin for I := Lbound to Pred(J) do begin Sum := A^[I]^[J]; for K := Lbound to Pred(I) do begin { Sum := Sum - A^[I]^[K] * A^[K]^[J]; } CMult(A^[I]^[K], A^[K]^[J], Z); CSub(Sum, Z, Sum); end; A^[I]^[J] := Sum; end; Pvt := 0.0; for I := J to Ubound do begin Sum := A^[I]^[J]; for K := Lbound to Pred(J) do begin { Sum := Sum - A^[I]^[K] * A^[K]^[J]; } CMult(A^[I]^[K], A^[K]^[J], Z); CSub(Sum, Z, Sum); end; A^[I]^[J] := Sum; T := V^[I] * CAbs(Sum); if T > Pvt then begin Pvt := T; Imax := I; end; end; if J <> Imax then begin { SwapRows(Imax, J, A, Lbound, Ubound); } for K := Lbound to Ubound do CSwap(A^[Imax]^[K], A^[J]^[K]); V^[Imax] := V^[J]; end; Index^[J] := Imax; if CAbs(A^[J]^[J]) = 0.0 then CSet(A^[J]^[J], TINY, TINY, Rec); if J <> Ubound then for I := Succ(J) to Ubound do { A^[I]^[J] := A^[I]^[J] / A^[J]^[J]; } CDiv(A^[I]^[J], A^[J]^[J], A^[I]^[J]); end; DelVector(V, Ubound); C_LU_Decomp := MAT_OK; end; procedure C_LU_Solve(A : PCompMatrix; B : PCompVector; Lbound, Ubound : Integer; X : PCompVector); var I, Ip, J, K : Integer; Sum, Z : Complex; begin K := Pred(Lbound); { CopyVector(X, B, Lbound, Ubound); } for I := Lbound to Ubound do X^[I] := B^[I]; for I := Lbound to Ubound do begin Ip := Index^[I]; Sum := X^[Ip]; X^[Ip] := X^[I]; if K >= Lbound then for J := K to Pred(I) do begin { Sum := Sum - A^[I]^[J] * X^[J] } CMult(A^[I]^[J], X^[J], Z); CSub(Sum, Z, Sum); end else if CAbs(Sum) <> 0.0 then K := I; X^[I] := Sum; end; for I := Ubound downto Lbound do begin Sum := X^[I]; if I < Ubound then for J := Succ(I) to Ubound do begin { Sum := Sum - A^[I]^[J] * X^[J]; } CMult(A^[I]^[J], X^[J], Z); CSub(Sum, Z, Sum); end; { X^[I] := Sum / A^[I]^[I]; } CDiv(Sum, A^[I]^[I], X^[I]); end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/fitfrac.pas����������������������������������������0000755�0001750�0001750�00000015540�11326425446�021416� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITFRAC.PAS * * Version 1.2 * * (c) J. Debord, April 1999 * ********************************************************************** This unit fits a rational fraction : p0 + p1.x + p2.x^2 + ... y = ------------------------ 1 + q1.x + q2.x^2 + ... ********************************************************************** } unit FitFrac; {$F+} interface uses FMath, Matrices, Polynom, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X, Y : Float; B, D : PVector); function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; procedure InitModel(CstPar : PVector); implementation const Deg1 : Integer = 1; { Degree of numerator } Deg2 : Integer = 1; { Degree of denominator } ConsTerm : Boolean = True; { Flags the presence of a constant term p0 } function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } var Name, S : String; I : Integer; begin Name := 'y = ('; if ConsTerm then Name := Name + 'p0 + '; Name := Name + 'p1.x'; for I := 2 to Deg1 do begin Str(I, S); Name := Name + ' + p' + S + '.x^' + S; end; Name := Name + ') / (1 + q1.x'; for I := (Deg1 + 2) to (Deg1 + Deg2) do begin Str(I - Deg1, S); Name := Name + ' + q' + S + '.x^' + S; end; Name := Name + ')'; FuncName := Name; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted (0 if there is a constant term p0, 1 otherwise) -------------------------------------------------------------------- } begin if ConsTerm then FirstParam := 0 else FirstParam := 1; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := Deg1 + Deg2; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } var S : String; begin if I <= Deg1 then begin Str(I, S); ParamName := 'p' + S; end else begin Str(I - Deg1, S); ParamName := 'q' + S; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = p0 B^[1] = p1 B^[2] = p2 ... B^[Deg1 + 1] = q1 B^[Deg1 + 2] = q2 ... -------------------------------------------------------------------- } begin RegFunc := RFrac(X, B, Deg1, Deg2); end; procedure DerivProc(X, Y : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point (X,Y) with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter -------------------------------------------------------------------- } var I : Integer; Den : Float; begin { Compute denominator (1 + q1.x + q2.x^2 + ...) } Den := 0.0; for I := (Deg1 + Deg2) downto Succ(Deg1) do Den := (Den + B^[I]) * X; Den := 1.0 + Den; { dy/dp0 = 1 / (1 + q1.x + q2.x^2 + ...) } D^[0] := 1.0 / Den; { dy/dpi = x^i / (1 + q1.x + q2.x^2 + ...) } for I := 1 to Deg1 do D^[I] := D^[I - 1] * X; { dy/dq1 = -x.y / (1 + q1.x + q2.x^2 + ...) } D^[Deg1 + 1] := - X * Y / Den; { dy/dqi = -x^i.y / (1 + q1.x + q2.x^2 + ...) } for I := (Deg1 + 2) to (Deg1 + Deg2) do D^[I] := D^[I - 1] * X; end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of a rational fraction by linear regression: y = p0 + p1.x + p2.x^2 + ... - q1.(x.y) - q2.(x^2.y) - ... -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- } var I, J : Integer; { Loop variables } M : Integer; { Index of last fitted parameter } U : PMatrix; { Matrix of independent variables } V : PMatrix; { Variance-covariance matrix } begin M := LastParam; DimMatrix(U, M, N); DimMatrix(V, M, M); for J := 1 to N do begin U^[1]^[J] := X^[J]; for I := 2 to Deg1 do U^[I]^[J] := U^[I - 1]^[J] * X^[J]; U^[Deg1 + 1]^[J] := - X^[J] * Y^[J]; for I := (Deg1 + 2) to M do U^[I]^[J] := U^[I - 1]^[J] * X^[J]; end; case Method of 0 : FitModel := MulFit(U, Y, N, M, ConsTerm, B, V); 1 : FitModel := WMulFit(U, Y, W, N, M, ConsTerm, B, V); end; if not ConsTerm then B^[0] := 0.0; DelMatrix(U, M, N); DelMatrix(V, M, M); end; procedure InitModel(CstPar : PVector); { -------------------------------------------------------------------- Initializes the global variables of the unit -------------------------------------------------------------------- CstPar^[0] = Degree of numerator CstPar^[1] = Degree of denominator CstPar^[2] = 1 to include a constant term (p0) -------------------------------------------------------------------- } var D1, D2 : Integer; begin D1 := Round(CstPar^[0]); D2 := Round(CstPar^[1]); if D1 > 0 then Deg1 := D1; if D2 > 0 then Deg2 := D2; ConsTerm := (CstPar^[2] = 1); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/fmath.pas������������������������������������������0000755�0001750�0001750�00000171614�11326425446�021104� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FMATH.PAS * * Version 2.4 * * (c) J. Debord, June 2001 * ********************************************************************** This unit implements some mathematical functions in Pascal ********************************************************************** Notes: 1) The default real type is DOUBLE (8-byte real). Depending on the compiler, other types may be selected by defining the symbols: ------------------------------------------------------- Symbol Type TP-BP-Delphi FPC GPC ------------------------------------------------------- SINGLEREAL Single X X X PASCALREAL Real X EXTENDEDREAL Extended X X X ------------------------------------------------------- Note: "Real" is equivalent to "Double" in FPC and GPC 2) Error handling: The function MathError returns the error code from the last function evaluation. It must be checked immediately after a function call: Y := f(X); (* f is one of the functions of the library *) if MathError = FN_OK then ... The possible error codes, and the default values attributed to the function, are the following: ------------------------------------------------------------------ Error code Value Significance Function default value ------------------------------------------------------------------ FN_OK 0 No error FN_DOMAIN -1 Argument domain error 0 FN_SING -2 Function singularity +/- MAXNUM FN_OVERFLOW -3 Overflow range error MAXNUM FN_UNDERFLOW -4 Underflow range error 0 ------------------------------------------------------------------ where MAXNUM is a constant defining the highest number which may be represented within the chosen floating point type. The standard functions Exp and Ln have been redefined according to the above conventions as Expo and Log. 3) Assembler functions: some functions are written in assembler. There are two versions: * One for BP 7 or Delphi 1 with a 387, 486 or Pentium processor. This version may be selected by defining the symbol CPU387 * The other for FPC with a Pentium II or Pentium III processor. This version may be selected by defining the symbol CPUP2 Units and programs must be compiled with the options -Si and -Rintel (e.g. ppc386 -Si -Rintel -dCPUP2 fmath) Once you have selected a version you have two possibilities: * Call the Pascal functions (e.g. Expo, ArcSin...). This will provide some acceleration while keeping the error handling. * Call the assembler functions directly (e.g. fExp, fArcSin...) This will provide further acceleration but without error handling. Thus it is the responsibility of the calling program to check the arguments passed to the function. See the interface files MATH387.INT and MATHP2.INT for a list of available functions. ********************************************************************** } unit FMath; interface { ---------------------------------------------------------------------- Floating point type (Default = Double) ---------------------------------------------------------------------- } {$IFDEF __GPC__} {$UNDEF PASCALREAL} {$ENDIF} {$IFDEF FPK} {$UNDEF PASCALREAL} {$ENDIF} {$IFDEF PASCALREAL} {$IFDEF VER120} type Float = Real48; { Delphi 4 } {$ELSE} type Float = Real; {$ENDIF} {$ELSE} {$IFDEF SINGLEREAL} type Float = Single; {$ELSE} {$IFDEF EXTENDEDREAL} type Float = Extended; {$ELSE} {$DEFINE DOUBLEREAL} type Float = Double; {$ENDIF} {$ENDIF} {$ENDIF} { ---------------------------------------------------------------------- Mathematical constants ---------------------------------------------------------------------- } const PI = 3.14159265358979323846; { Pi } LN2 = 0.69314718055994530942; { Ln(2) } LN10 = 2.30258509299404568402; { Ln(10) } LNPI = 1.14472988584940017414; { Ln(Pi) } INVLN2 = 1.44269504088896340736; { 1/Ln(2) } INVLN10 = 0.43429448190325182765; { 1/Ln(10) } TWOPI = 6.28318530717958647693; { 2*Pi } PIDIV2 = 1.57079632679489661923; { Pi/2 } SQRTPI = 1.77245385090551602730; { Sqrt(Pi) } SQRT2PI = 2.50662827463100050242; { Sqrt(2*Pi) } INVSQRT2PI = 0.39894228040143267794; { 1/Sqrt(2*Pi) } LNSQRT2PI = 0.91893853320467274178; { Ln(Sqrt(2*Pi)) } LN2PIDIV2 = 0.91893853320467274178; { Ln(2*Pi)/2 } SQRT2 = 1.41421356237309504880; { Sqrt(2) } SQRT2DIV2 = 0.70710678118654752440; { Sqrt(2)/2 } GOLD = 1.61803398874989484821; { Golden Mean = (1 + Sqrt(5))/2 } CGOLD = 0.38196601125010515179; { 2 - GOLD } { ---------------------------------------------------------------------- Machine-dependent constants ---------------------------------------------------------------------- } {$IFDEF SINGLEREAL} const MACHEP = 1.192093E-7; { Floating point precision: 2^(-23) } MAXNUM = 3.402823E+38; { Max. floating point number: 2^128 } MINNUM = 1.175495E-38; { Min. floating point number: 2^(-126) } MAXLOG = 88.72283; { Max. argument for Exp = Ln(MAXNUM) } MINLOG = -87.33655; { Min. argument for Exp = Ln(MINNUM) } MAXFAC = 33; { Max. argument for Factorial } MAXGAM = 34.648; { Max. argument for Gamma } MAXLGM = 1.0383E+36; { Max. argument for LnGamma } {$ELSE} {$IFDEF DOUBLEREAL} const MACHEP = 2.220446049250313E-16; { 2^(-52) } MAXNUM = 1.797693134862315E+308; { 2^1024 } MINNUM = 2.225073858507202E-308; { 2^(-1022) } MAXLOG = 709.7827128933840; MINLOG = -708.3964185322641; MAXFAC = 170; MAXGAM = 171.624376956302; MAXLGM = 2.556348E+305; {$ELSE} {$IFDEF EXTENDEDREAL} const MACHEP = 1.08420217248550444E-19; { 2^(-63) } MAXNUM = 1.18973149535723103E+4932; { 2^16384 } MINNUM = 3.36210314311209558E-4932; { 2^(-16382) } MAXLOG = 11356.5234062941439; MINLOG = - 11355.137111933024; MAXFAC = 1754; MAXGAM = 1755.455; MAXLGM = 1.04848146839019521E+4928; {$ELSE} {$IFDEF PASCALREAL} const MACHEP = 1.818989404E-12; { 2^(-39) } MAXNUM = 4.253529586E+37; { 2^126 } MINNUM = 2.350988703E-38; { 2^(-125) } MAXLOG = 8.664339757E+01; MINLOG = - 4.253529586E+01; MAXFAC = 33; MAXGAM = 34.64809785; MAXLGM = 1.038324114E+36; {$ENDIF} {$ENDIF} {$ENDIF} {$ENDIF} { ---------------------------------------------------------------------- Error codes for mathematical functions ---------------------------------------------------------------------- } const FN_OK = 0; { No error } FN_DOMAIN = - 1; { Argument domain error } FN_SING = - 2; { Function singularity } FN_OVERFLOW = - 3; { Overflow range error } FN_UNDERFLOW = - 4; { Underflow range error } FN_TLOSS = - 5; { Total loss of precision } FN_PLOSS = - 6; { Partial loss of precision } { ---------------------------------------------------------------------- Global variables and constants ---------------------------------------------------------------------- } const NFACT = 33; { The factorials of the first NFACT integers are stored in a table } var MathErr : Integer; { Error code from the latest function evaluation } FactArray : array[0..NFACT] of Float; { Table of factorials } { ---------------------------------------------------------------------- Functional type ---------------------------------------------------------------------- } type TFunc = function(X : Float) : Float; { ---------------------------------------------------------------------- Error handling function ---------------------------------------------------------------------- } function MathError : Integer; { Error code from the last function call } { ---------------------------------------------------------------------- Minimum, maximum, sign and exchange ---------------------------------------------------------------------- } function FMin(X, Y : Float) : Float; { Minimum of 2 reals } function FMax(X, Y : Float) : Float; { Maximum of 2 reals } function IMin(X, Y : Integer) : Integer; { Minimum of 2 integers } function IMax(X, Y : Integer) : Integer; { Maximum of 2 integers } function Sgn(X : Float) : Integer; { Sign (returns 1 if X = 0) } function Sgn0(X : Float) : Integer; { Sign (returns 0 if X = 0) } procedure FSwap(var X, Y : Float); { Exchange 2 reals } procedure ISwap(var X, Y : Integer); { Exchange 2 integers } { ---------------------------------------------------------------------- Assembler functions ---------------------------------------------------------------------- } {$IFDEF CPU387} {$UNDEF CPUP2} {$I MATH387.INT} {$ENDIF} {$IFDEF CPUP2} {$UNDEF CPU387} {$I MATHP2.INT} {$ENDIF} { ---------------------------------------------------------------------- Sign, logarithms, exponentials and power ---------------------------------------------------------------------- } function Expo(X : Float) : Float; { Exponential } function Exp2(X : Float) : Float; { 2^X } function Exp10(X : Float) : Float; { 10^X } function Log(X : Float) : Float; { Natural log } function Log2(X : Float) : Float; { Log, base 2 } function Log10(X : Float) : Float; { Decimal log } function LogA(X, A : Float) : Float; { Log, base A } function IntPower(X : Float; N : Integer) : Float; { X^N } function Power(X, Y : Float) : Float; { X^Y, X >= 0 } function Pythag(X, Y : Float) : Float; { Sqrt(X^2 + Y^2) } { ---------------------------------------------------------------------- Trigonometric and inverse trigonometric functions ---------------------------------------------------------------------- } function FixAngle(Theta : Float) : Float; { Set Theta in -Pi..Pi } function Tan(X : Float) : Float; { Tangent } function ArcSin(X : Float) : Float; { Arc sinus } function ArcCos(X : Float) : Float; { Arc cosinus } function ArcTan2(Y, X : Float) : Float; { Angle (Ox, OM) with M(X,Y) } procedure SinCos(X : Float; var SinX, CosX : Float); { Sin & Cos } { ---------------------------------------------------------------------- Hyperbolic and inverse hyperbolic functions ---------------------------------------------------------------------- } function Sinh(X : Float) : Float; { Hyperbolic sine } function Cosh(X : Float) : Float; { Hyperbolic cosine } function Tanh(X : Float) : Float; { Hyperbolic tangent } function ArcSinh(X : Float) : Float; { Inverse hyperbolic sine } function ArcCosh(X : Float) : Float; { Inverse hyperbolic cosine } function ArcTanh(X : Float) : Float; { Inverse hyperbolic tangent } procedure SinhCosh(X : Float; var SinhX, CoshX : Float); { Sinh & Cosh } { ---------------------------------------------------------------------- Special functions ---------------------------------------------------------------------- } function Fact(N : Integer) : Float; { Factorial } function Binomial(N, K : Integer) : Float; { Binomial coef. C(N,K) } function Gamma(X : Float) : Float; { Gamma function } function SgnGamma(X : Float) : Integer; { Sign of Gamma function } function LnGamma(X : Float) : Float; { Log(|Gamma(X)|) } function IGamma(A, X : Float) : Float; { Incomplete Gamma function } function JGamma(A, X : Float) : Float; { Complement of IGamma } function Beta(X, Y : Float) : Float; { Beta function } function IBeta(A, B, X : Float) : Float; { Incomplete Beta function } function Erf(X : Float) : Float; { Error function } function Erfc(X : Float) : Float; { Complement of Erf } { ---------------------------------------------------------------------- Binomial distribution with probability P and number of repetitions N ---------------------------------------------------------------------- } function PBinom(N : Integer; P : Float; K : Integer) : Float; { Prob(X = K) } function FBinom(N : Integer; P : Float; K : Integer) : Float; { Prob(X <= K) } { ---------------------------------------------------------------------- Poisson distribution with mean Mu ---------------------------------------------------------------------- } function PPoisson(Mu : Float; K : Integer) : Float; { Prob(X = K) } function FPoisson(Mu : Float; K : Integer) : Float; { Prob(X <= K) } { ---------------------------------------------------------------------- Standard normal distribution ---------------------------------------------------------------------- } function DNorm(X : Float) : Float; { Density of standard normal } function FNorm(X : Float) : Float; { Prob(U <= X) } function PNorm(X : Float) : Float; { Prob(|U| >= |X|) } function InvNorm(P : Float) : Float; { Inverse of FNorm : returns X such that Prob(U <= X) = P} { ---------------------------------------------------------------------- Student distribution with Nu d.o.f. ---------------------------------------------------------------------- } function DStudent(Nu : Integer; X : Float) : Float; { Density of t } function FStudent(Nu : Integer; X : Float) : Float; { Prob(t <= X) } function PStudent(Nu : Integer; X : Float) : Float; { Prob(|t| >= |X|) } { ---------------------------------------------------------------------- Khi-2 distribution with Nu d.o.f. ---------------------------------------------------------------------- } function DKhi2(Nu : Integer; X : Float) : Float; { Density of Khi2 } function FKhi2(Nu : Integer; X : Float) : Float; { Prob(Khi2 <= X) } function PKhi2(Nu : Integer; X : Float) : Float; { Prob(Khi2 >= X) } { ---------------------------------------------------------------------- Fisher-Snedecor distribution with Nu1 and Nu2 d.o.f. ---------------------------------------------------------------------- } function DSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; { Density of F } function FSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; { Prob(F <= X) } function PSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; { Prob(F >= X) } { ---------------------------------------------------------------------- Exponential distribution ---------------------------------------------------------------------- } function DExpo(A, X : Float) : Float; { Density of exponential distrib. } function FExpo(A, X : Float) : Float; { Prob( <= X) } { ---------------------------------------------------------------------- Beta distribution ---------------------------------------------------------------------- } function DBeta(A, B, X : Float) : Float; { Density of Beta distribution } function FBeta(A, B, X : Float) : Float; { Prob( <= X) } { ---------------------------------------------------------------------- Gamma distribution ---------------------------------------------------------------------- } function DGamma(A, B, X : Float) : Float; { Density of Gamma distribution } function FGamma(A, B, X : Float) : Float; { Prob( <= X) } { ---------------------------------------------------------------------- Random numbers ---------------------------------------------------------------------- } procedure RMarIn(Seed1, Seed2 : Integer); { Initializes the random number generator. The default initialization corresponds to RMarIn(1802, 9373) } function IRanMar : LongInt; { Returns a 32 bit random number in [ -2,147,483,648 ; 2,147,483,647 ] } function RanMar : Float; { Returns a random number in [0, 1[ } function RanGaussStd : Float; { Returns a random number from the standard normal distribution (i.e. the Gaussian distribution with zero mean and unit variance) } function RanGauss(Mu, Sigma : Float) : Float; { Returns a random number from a Gaussian distribution with mean Mu and standard deviation Sigma } { ********************************************************************** } implementation { ---------------------------------------------------------------------- Error handling functions ---------------------------------------------------------------------- } function DefaultVal(ErrCode : Integer) : Float; { Sets the global variable MathErr and the function default value according to the error code } begin MathErr := ErrCode; case ErrCode of FN_DOMAIN : DefaultVal := 0.0; FN_SING : DefaultVal := MAXNUM; FN_OVERFLOW : DefaultVal := MAXNUM; FN_UNDERFLOW : DefaultVal := 0.0; else DefaultVal := 0.0; end; end; function MathError : Integer; begin MathError := MathErr; end; { ---------------------------------------------------------------------- Minimum, maximum and sign ---------------------------------------------------------------------- } function FMin(X, Y : Float) : Float; begin if X <= Y then FMin := X else FMin := Y; end; function FMax(X, Y : Float) : Float; begin if X >= Y then FMax := X else FMax := Y; end; function IMin(X, Y : Integer) : Integer; begin if X <= Y then IMin := X else IMin := Y; end; function IMax(X, Y : Integer) : Integer; begin if X >= Y then IMax := X else IMax := Y; end; procedure FSwap(var X, Y : Float); var Temp : Float; begin Temp := X; X := Y; Y := Temp; end; procedure ISwap(var X, Y : Integer); var Temp : Integer; begin Temp := X; X := Y; Y := Temp; end; function Sgn(X : Float) : Integer; begin if X >= 0.0 then Sgn := 1 else Sgn := - 1; end; function Sgn0(X : Float) : Integer; begin if X > 0.0 then Sgn0 := 1 else if X = 0.0 then Sgn0 := 0 else Sgn0 := - 1; end; { ---------------------------------------------------------------------- Assembler functions ---------------------------------------------------------------------- } {$IFDEF CPU387} {$I MATH387.INC} {$DEFINE USE_ASM} {$ENDIF} {$IFDEF CPUP2} {$I MATHP2.INC} {$DEFINE USE_ASM} {$ENDIF} { ---------------------------------------------------------------------- Elementary functions ---------------------------------------------------------------------- } function Expo(X : Float) : Float; begin MathErr := FN_OK; if X < MINLOG then Expo := DefaultVal(FN_UNDERFLOW) else if X > MAXLOG then Expo := DefaultVal(FN_OVERFLOW) else Expo := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(X); end; function Exp2(X : Float) : Float; var XLn2 : Float; begin MathErr := FN_OK; XLn2 := X * LN2; if XLn2 < MINLOG then Exp2 := DefaultVal(FN_UNDERFLOW) else if XLn2 > MAXLOG then Exp2 := DefaultVal(FN_OVERFLOW) else Exp2 := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(XLn2); end; function Exp10(X : Float) : Float; var XLn10 : Float; begin MathErr := FN_OK; XLn10 := X * LN10; if XLn10 < MINLOG then Exp10 := DefaultVal(FN_UNDERFLOW) else if XLn10 > MAXLOG then Exp10 := DefaultVal(FN_OVERFLOW) else Exp10 := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(XLn10); end; function Log(X : Float) : Float; begin MathErr := FN_OK; if X < 0.0 then Log := DefaultVal(FN_DOMAIN) else if X = 0.0 then Log := DefaultVal(FN_SING) else Log := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X); end; function Log10(X : Float) : Float; begin MathErr := FN_OK; if X < 0.0 then Log10 := DefaultVal(FN_DOMAIN) else if X = 0.0 then Log10 := DefaultVal(FN_SING) else Log10 := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) * INVLN10; end; function Log2(X : Float) : Float; begin MathErr := FN_OK; if X < 0.0 then Log2 := DefaultVal(FN_DOMAIN) else if X = 0.0 then Log2 := DefaultVal(FN_SING) else Log2 := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) * INVLN2; end; function LogA(X, A : Float) : Float; begin MathErr := FN_OK; if (X < 0.0) or (A <= 0.0) or (A = 1.0) then LogA := DefaultVal(FN_DOMAIN) else if X = 0.0 then LogA := Sgn(1.0 - A) * DefaultVal(FN_SING) else {$IFDEF USE_ASM} LogA := fLn(X) / fLn(A); {$ELSE} LogA := Ln(X) / Ln(A); {$ENDIF} end; function IntPower(X : Float; N : Integer) : Float; { Computes X^N by repeated multiplications } var M : Integer; T : Float; begin MathErr := FN_OK; if X = 0.0 then begin if N = 0 then { 0^0 = lim x^x = 1 } IntPower := 1.0 { x->0 } else if N > 0 then IntPower := 0.0 { 0^N = 0 } else IntPower := DefaultVal(FN_SING); Exit; end; if N = 0 then begin IntPower := 1.0; Exit; end; { Legendre's algorithm for minimizing the number of multiplications } T := 1.0; M := Abs(N); repeat if Odd(M) then begin Dec(M); T := T * X; end else begin M := M div 2; X := Sqr(X); end; until M = 0; if N > 0 then IntPower := T else IntPower := 1.0 / T; end; function Power(X, Y : Float) : Float; { Computes X^Y = Exp(Y * Ln(X)), for X >= 0 } var YLnX : Float; begin MathErr := FN_OK; if X < 0.0 then begin Power := DefaultVal(FN_DOMAIN); Exit; end; if X = 0.0 then begin if Y = 0.0 then { 0^0 = lim x^x = 1 } Power := 1.0 { x->0 } else if Y > 0.0 then Power := 0.0 { 0^Y = 0 } else Power := DefaultVal(FN_SING); Exit; end; if Y = 0.0 then begin Power := 1.0; Exit; end; YLnX := Y * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X); if YLnX < MINLOG then Power := DefaultVal(FN_UNDERFLOW) else if YLnX > MAXLOG then Power := DefaultVal(FN_OVERFLOW) else Power := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(YLnX); end; function Pythag(X, Y : Float) : Float; { Computes Sqrt(X^2 + Y^2) without destructive underflow or overflow } var AbsX, AbsY : Float; begin MathErr := FN_OK; AbsX := Abs(X); AbsY := Abs(Y); if AbsX > AbsY then Pythag := AbsX * Sqrt(1.0 + Sqr(AbsY / AbsX)) else if AbsY = 0.0 then Pythag := 0.0 else Pythag := AbsY * Sqrt(1.0 + Sqr(AbsX / AbsY)); end; procedure SinCos(X : Float; var SinX, CosX : Float); begin MathErr := FN_OK; SinX := {$IFDEF USE_ASM}fSin{$ELSE}Sin{$ENDIF}(X); CosX := {$IFDEF USE_ASM}fCos{$ELSE}Cos{$ENDIF}(X); end; function FixAngle(Theta : Float) : Float; begin MathErr := FN_OK; while Theta > PI do Theta := Theta - TWOPI; while Theta <= - PI do Theta := Theta + TWOPI; FixAngle := Theta; end; function Tan(X : Float) : Float; var SinX, CosX : Float; begin MathErr := FN_OK; SinX := {$IFDEF USE_ASM}fSin{$ELSE}Sin{$ENDIF}(X); CosX := {$IFDEF USE_ASM}fCos{$ELSE}Cos{$ENDIF}(X); if CosX = 0.0 then Tan := Sgn(SinX) * DefaultVal(FN_SING) else Tan := SinX / CosX; end; function ArcSin(X : Float) : Float; begin MathErr := FN_OK; if (X < - 1.0) or (X > 1.0) then ArcSin := DefaultVal(FN_DOMAIN) else if X = 1.0 then ArcSin := PIDIV2 else if X = - 1.0 then ArcSin := - PIDIV2 else ArcSin := {$IFDEF USE_ASM}fArcTan{$ELSE}ArcTan{$ENDIF}(X / Sqrt(1.0 - Sqr(X))); end; function ArcCos(X : Float) : Float; begin MathErr := FN_OK; if (X < - 1.0) or (X > 1.0) then ArcCos := DefaultVal(FN_DOMAIN) else if X = 1.0 then ArcCos := 0.0 else if X = - 1.0 then ArcCos := PI else ArcCos := PIDIV2 - {$IFDEF USE_ASM}fArcTan{$ELSE}ArcTan{$ENDIF}(X / Sqrt(1.0 - Sqr(X))); end; function ArcTan2(Y, X : Float) : Float; var Theta : Float; begin MathErr := FN_OK; if X = 0.0 then if Y = 0.0 then ArcTan2 := 0.0 else if Y > 0.0 then ArcTan2 := PIDIV2 else ArcTan2 := - PIDIV2 else begin { 4th/1st quadrant -PI/2..PI/2 } Theta := {$IFDEF USE_ASM}fArcTan{$ELSE}ArcTan{$ENDIF}(Y / X); { 2nd/3rd quadrants } if X < 0.0 then if Y >= 0.0 then Theta := Theta + PI { 2nd quadrant: PI/2..PI } else Theta := Theta - PI; { 3rd quadrant: -PI..-PI/2 } ArcTan2 := Theta; end; end; { ---------------------------------------------------------------------- Hyperbolic functions ---------------------------------------------------------------------- } function Sinh(X : Float) : Float; var ExpX : Float; begin MathErr := FN_OK; if (X < MINLOG) or (X > MAXLOG) then Sinh := Sgn(X) * DefaultVal(FN_OVERFLOW) else begin ExpX := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(X); Sinh := 0.5 * (ExpX - 1.0 / ExpX); end; end; function Cosh(X : Float) : Float; var ExpX : Float; begin MathErr := FN_OK; if (X < MINLOG) or (X > MAXLOG) then Cosh := DefaultVal(FN_OVERFLOW) else begin ExpX := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(X); Cosh := 0.5 * (ExpX + 1.0 / ExpX); end; end; procedure SinhCosh(X : Float; var SinhX, CoshX : Float); var ExpX, ExpMinusX : Float; begin MathErr := FN_OK; if (X < MINLOG) or (X > MAXLOG) then begin CoshX := DefaultVal(FN_OVERFLOW); SinhX := Sgn(X) * CoshX; end else begin ExpX := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(X); ExpMinusX := 1.0 / ExpX; SinhX := 0.5 * (ExpX - ExpMinusX); CoshX := 0.5 * (ExpX + ExpMinusX); end; end; function Tanh(X : Float) : Float; var SinhX, CoshX : Float; begin SinhCosh(X, SinhX, CoshX); Tanh := SinhX / CoshX; end; function ArcSinh(X : Float) : Float; begin MathErr := FN_OK; ArcSinh := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X + Sqrt(Sqr(X) + 1.0)); end; function ArcCosh(X : Float) : Float; begin MathErr := FN_OK; if X < 1.0 then ArcCosh := DefaultVal(FN_DOMAIN) else ArcCosh := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X + Sqrt(Sqr(X) - 1.0)); end; function ArcTanh(X : Float) : Float; begin MathErr := FN_OK; if (X < - 1.0) or (X > 1.0) then ArcTanh := DefaultVal(FN_DOMAIN) else if (X = - 1.0) or (X = 1.0) then ArcTanh := Sgn(X) * DefaultVal(FN_SING) else ArcTanh := 0.5 * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}((1.0 + X) / (1.0 - X)); end; { ---------------------------------------------------------------------- Special functions (translated from Cephes math library by S. Moshier: http://www.netlib.org/cephes) ---------------------------------------------------------------------- } const { Used by IGamma and IBeta } BIG = 9.223372036854775808E18; BIGINV = 1.084202172485504434007E-19; type TabCoef = array[0..9] of Float; function PolEvl(var X : Float; var Coef : TabCoef; N : Integer) : Float; { ---------------------------------------------------------------------- Evaluates polynomial of degree N: 2 N y = C + C x + C x +...+ C x 0 1 2 N Coefficients are stored in reverse order: Coef[0] = C , ..., Coef[N] = C N 0 The function P1Evl() assumes that Coef[N] = 1.0 and is omitted from the array. Its calling arguments are otherwise the same as PolEvl(). ---------------------------------------------------------------------- } var Ans : Float; I : Integer; begin Ans := Coef[0]; for I := 1 to N do Ans := Ans * X + Coef[I]; PolEvl := Ans; end; function P1Evl(var X : Float; var Coef : TabCoef; N : Integer) : Float; { ---------------------------------------------------------------------- Evaluate polynomial when coefficient of X is 1.0. Otherwise same as PolEvl. ---------------------------------------------------------------------- } var Ans : Float; I : Integer; begin Ans := X + Coef[0]; for I := 1 to N - 1 do Ans := Ans * X + Coef[I]; P1Evl := Ans; end; function SgnGamma(X : Float) : Integer; begin if X > 0.0 then SgnGamma := 1 else if Odd(Trunc(Abs(X))) then SgnGamma := 1 else SgnGamma := - 1; end; function Stirf(X : Float) : Float; { Stirling's formula for the gamma function Gamma(x) = Sqrt(2*Pi) x^(x-.5) exp(-x) (1 + 1/x P(1/x)) where P(x) is a polynomial } const STIR : TabCoef = ( 7.147391378143610789273E-4, - 2.363848809501759061727E-5, - 5.950237554056330156018E-4, 6.989332260623193171870E-5, 7.840334842744753003862E-4, - 2.294719747873185405699E-4, - 2.681327161876304418288E-3, 3.472222222230075327854E-3, 8.333333333333331800504E-2, 0); var W, P : Float; begin W := 1.0 / X; if X > 1024.0 then begin P := 6.97281375836585777429E-5 * W + 7.84039221720066627474E-4; P := P * W - 2.29472093621399176955E-4; P := P * W - 2.68132716049382716049E-3; P := P * W + 3.47222222222222222222E-3; P := P * W + 8.33333333333333333333E-2; end else P := PolEvl(W, STIR, 8); {$IFDEF USE_ASM} Stirf := SQRT2PI * fExp((X - 0.5) * fLn(X) - X) * (1.0 + W * P); {$ELSE} Stirf := SQRT2PI * Exp((X - 0.5) * Ln(X) - X) * (1.0 + W * P); {$ENDIF} end; function GamSmall(X1, Z : Float) : Float; { Gamma function for small values of the argument } const S : TabCoef = ( - 1.193945051381510095614E-3, 7.220599478036909672331E-3, - 9.622023360406271645744E-3, - 4.219773360705915470089E-2, 1.665386113720805206758E-1, - 4.200263503403344054473E-2, - 6.558780715202540684668E-1, 5.772156649015328608253E-1, 1.000000000000000000000E0, 0); SN : TabCoef = ( 1.133374167243894382010E-3, 7.220837261893170325704E-3, 9.621911155035976733706E-3, - 4.219773343731191721664E-2, - 1.665386113944413519335E-1, - 4.200263503402112910504E-2, 6.558780715202536547116E-1, 5.772156649015328608727E-1, - 1.000000000000000000000E0, 0); var P : Float; begin if X1 = 0.0 then begin GamSmall := DefaultVal(FN_SING); Exit; end; if X1 < 0.0 then begin X1 := - X1; P := PolEvl(X1, SN, 8); end else P := PolEvl(X1, S, 8); GamSmall := Z / (X1 * P); end; function StirfL(X : Float) : Float; { Approximate Ln(Gamma) by Stirling's formula, for X >= 13 } const P : TabCoef = ( 4.885026142432270781165E-3, - 1.880801938119376907179E-3, 8.412723297322498080632E-4, - 5.952345851765688514613E-4, 7.936507795855070755671E-4, - 2.777777777750349603440E-3, 8.333333333333331447505E-2, 0, 0, 0); var Q, W : Float; begin Q := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) * (X - 0.5) - X; Q := Q + LNSQRT2PI; if X > 1.0E+10 then StirfL := Q else begin W := 1.0 / Sqr(X); StirfL := Q + PolEvl(W, P, 6) / X; end; end; function Gamma(X : Float) : Float; const P : TabCoef = ( 4.212760487471622013093E-5, 4.542931960608009155600E-4, 4.092666828394035500949E-3, 2.385363243461108252554E-2, 1.113062816019361559013E-1, 3.629515436640239168939E-1, 8.378004301573126728826E-1, 1.000000000000000000009E0, 0, 0); Q : TabCoef = ( - 1.397148517476170440917E-5, 2.346584059160635244282E-4, - 1.237799246653152231188E-3, - 7.955933682494738320586E-4, 2.773706565840072979165E-2, - 4.633887671244534213831E-2, - 2.243510905670329164562E-1, 4.150160950588455434583E-1, 9.999999999999999999908E-1, 0); var SgnGam, N : Integer; A, X1, Z : Float; begin MathErr := FN_OK; SgnGam := SgnGamma(X); if (X = 0.0) or ((X < 0.0) and (Frac(X) = 0.0)) then begin Gamma := SgnGam * DefaultVal(FN_SING); Exit; end; if X > MAXGAM then begin Gamma := DefaultVal(FN_OVERFLOW); Exit; end; A := Abs(X); if A > 13.0 then begin if X < 0.0 then begin N := Trunc(A); Z := A - N; if Z > 0.5 then begin N := N + 1; Z := A - N; end; Z := Abs(A * {$IFDEF USE_ASM}fSin{$ELSE}Sin{$ENDIF}(PI * Z)) * Stirf(A); if Z <= PI / MAXNUM then begin Gamma := SgnGam * DefaultVal(FN_OVERFLOW); Exit; end; Z := PI / Z; end else Z := Stirf(X); Gamma := SgnGam * Z; end else begin Z := 1.0; X1 := X; while X1 >= 3.0 do begin X1 := X1 - 1.0; Z := Z * X1; end; while X1 < - 0.03125 do begin Z := Z / X1; X1 := X1 + 1.0; end; if X1 <= 0.03125 then Gamma := GamSmall(X1, Z) else begin while X1 < 2.0 do begin Z := Z / X1; X1 := X1 + 1.0; end; if (X1 = 2.0) or (X1 = 3.0) then Gamma := Z else begin X1 := X1 - 2.0; Gamma := Z * PolEvl(X1, P, 7) / PolEvl(X1, Q, 8); end; end; end; end; function LnGamma(X : Float) : Float; const P : TabCoef = ( - 2.163690827643812857640E3, - 8.723871522843511459790E4, - 1.104326814691464261197E6, - 6.111225012005214299996E6, - 1.625568062543700591014E7, - 2.003937418103815175475E7, - 8.875666783650703802159E6, 0, 0, 0); Q : TabCoef = ( - 5.139481484435370143617E2, - 3.403570840534304670537E4, - 6.227441164066219501697E5, - 4.814940379411882186630E6, - 1.785433287045078156959E7, - 3.138646407656182662088E7, - 2.099336717757895876142E7, 0, 0, 0); var N : Integer; A, X1, Z : Float; begin MathErr := FN_OK; if (X = 0.0) or ((X < 0.0) and (Frac(X) = 0.0)) then begin LnGamma := DefaultVal(FN_SING); Exit; end; if X > MAXLGM then begin LnGamma := DefaultVal(FN_OVERFLOW); Exit; end; A := Abs(X); if A > 34.0 then begin if X < 0.0 then begin N := Trunc(A); Z := A - N; if Z > 0.5 then begin N := N + 1; Z := N - A; end; Z := A * {$IFDEF USE_ASM}fSin{$ELSE}Sin{$ENDIF}(PI * Z); if Z = 0.0 then begin LnGamma := DefaultVal(FN_OVERFLOW); Exit; end; Z := LNPI - {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(Z) - StirfL(A); end else Z := StirfL(X); LnGamma := Z; end else if X < 13.0 then begin Z := 1.0; X1 := X; while X1 >= 3 do begin X1 := X1 - 1.0; Z := Z * X1; end; while X1 < 2.0 do begin if Abs(X1) <= 0.03125 then begin LnGamma := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(Abs(GamSmall(X1, Z))); Exit; end; Z := Z / X1; X1 := X1 + 1.0; end; if Z < 0.0 then Z := - Z; if X1 = 2.0 then LnGamma := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(Z) else begin X1 := X1 - 2.0; LnGamma := X1 * PolEvl(X1, P, 6) / P1Evl(X1, Q, 7) + {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(Z); end; end else LnGamma := StirfL(X); end; function IGamma(A, X : Float) : Float; var Ans, Ax, C, R : Float; begin MathErr := FN_OK; if (X <= 0.0) or (A <= 0.0) then begin IGamma := 0.0; Exit; end; if (X > 1.0) and (X > A) then begin IGamma := 1.0 - JGamma(A, X); Exit; end; Ax := A * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) - X - LnGamma(A); if Ax < MINLOG then begin IGamma := DefaultVal(FN_UNDERFLOW); Exit; end; Ax := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(Ax); { power series } R := A; C := 1.0; Ans := 1.0; repeat R := R + 1.0; C := C * X / R; Ans := Ans + C; until C / Ans <= MACHEP; IGamma := Ans * Ax / A; end; function JGamma(A, X : Float) : Float; var Ans, C, Yc, Ax, Y, Z, R, T, Pk, Pkm1, Pkm2, Qk, Qkm1, Qkm2 : Float; begin MathErr := FN_OK; if (X <= 0.0) or (A <= 0.0) then begin JGamma := 1.0; Exit; end; if (X < 1.0) or (X < A) then begin JGamma := 1.0 - IGamma(A, X); Exit; end; Ax := A * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) - X - LnGamma(A); if Ax < MINLOG then begin JGamma := DefaultVal(FN_UNDERFLOW); Exit; end; Ax := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(Ax); { continued fraction } Y := 1.0 - A; Z := X + Y + 1.0; C := 0.0; Pkm2 := 1.0; Qkm2 := X; Pkm1 := X + 1.0; Qkm1 := Z * X; Ans := Pkm1 / Qkm1; repeat C := C + 1.0; Y := Y + 1.0; Z := Z + 2.0; Yc := Y * C; Pk := Pkm1 * Z - Pkm2 * Yc; Qk := Qkm1 * Z - Qkm2 * Yc; if Qk <> 0.0 then begin R := Pk / Qk; T := Abs((Ans - R) / R); Ans := R; end else T := 1.0; Pkm2 := Pkm1; Pkm1 := Pk; Qkm2 := Qkm1; Qkm1 := Qk; if Abs(Pk) > BIG then begin Pkm2 := Pkm2 / BIG; Pkm1 := Pkm1 / BIG; Qkm2 := Qkm2 / BIG; Qkm1 := Qkm1 / BIG; end; until T <= MACHEP; JGamma := Ans * Ax; end; function Fact(N : Integer) : Float; begin MathErr := FN_OK; if N < 0 then Fact := DefaultVal(FN_DOMAIN) else if N > MAXFAC then Fact := DefaultVal(FN_OVERFLOW) else if N <= NFACT then Fact := FactArray[N] else Fact := Gamma(N + 1); end; function Binomial(N, K : Integer) : Float; var I, N1 : Integer; Prod : Float; begin MathErr := FN_OK; if K < 0 then Binomial := 0.0 else if (K = 0) or (K = N) then Binomial := 1.0 else if (K = 1) or (K = N - 1) then Binomial := N else begin if K > N - K then K := N - K; N1 := Succ(N); Prod := N; for I := 2 to K do Prod := Prod * (Int(N1 - I) / Int(I)); Binomial := Int(0.5 + Prod); end; end; function Beta(X, Y : Float) : Float; { Computes Beta(X, Y) = Gamma(X) * Gamma(Y) / Gamma(X + Y) } var Lx, Ly, Lxy : Float; SgnBeta : Integer; begin MathErr := FN_OK; SgnBeta := SgnGamma(X) * SgnGamma(Y) * SgnGamma(X + Y); Lxy := LnGamma(X + Y); if MathErr <> FN_OK then begin Beta := 0.0; Exit; end; Lx := LnGamma(X); if MathErr <> FN_OK then begin Beta := SgnBeta * MAXNUM; Exit; end; Ly := LnGamma(Y); if MathErr <> FN_OK then begin Beta := SgnBeta * MAXNUM; Exit; end; Beta := SgnBeta * {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(Lx + Ly - Lxy); end; function PSeries(A, B, X : Float) : Float; { Power series for incomplete beta integral. Use when B*X is small } var S, T, U, V, T1, Z, Ai : Float; N : Integer; begin Ai := 1.0 / A; U := (1.0 - B) * X; V := U / (A + 1.0); T1 := V; T := U; N := 2; S := 0.0; Z := MACHEP * Ai; while Abs(V) > Z do begin U := (N - B) * X / N; T := T * U; V := T / (A + N); S := S + V; N := N + 1; end; S := S + T1; S := S + Ai; U := A * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X); if (A + B < MAXGAM) and (Abs(U) < MAXLOG) then begin T := Gamma(A + B) / (Gamma(A) * Gamma(B)); S := S * T * Power(X, A); end else begin T := LnGamma(A + B) - LnGamma(A) - LnGamma(B) + U + {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(S); if T < MINLOG then S := 0.0 else S := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(T); end; PSeries := S; end; function CFrac1(A, B, X : Float) : Float; { Continued fraction expansion #1 for incomplete beta integral } var Xk, Pk, Pkm1, Pkm2, Qk, Qkm1, Qkm2, K1, K2, K3, K4, K5, K6, K7, K8, R, T, Ans, Thresh : Float; N : Integer; label CDone; begin K1 := A; K2 := A + B; K3 := A; K4 := A + 1.0; K5 := 1.0; K6 := B - 1.0; K7 := K4; K8 := A + 2.0; Pkm2 := 0.0; Qkm2 := 1.0; Pkm1 := 1.0; Qkm1 := 1.0; Ans := 1.0; R := 1.0; N := 0; Thresh := 3.0 * MACHEP; repeat Xk := - (X * K1 * K2) / (K3 * K4); Pk := Pkm1 + Pkm2 * Xk; Qk := Qkm1 + Qkm2 * Xk; Pkm2 := Pkm1; Pkm1 := Pk; Qkm2 := Qkm1; Qkm1 := Qk; Xk := (X * K5 * K6) / (K7 * K8); Pk := Pkm1 + Pkm2 * Xk; Qk := Qkm1 + Qkm2 * Xk; Pkm2 := Pkm1; Pkm1 := Pk; Qkm2 := Qkm1; Qkm1 := Qk; if Qk <> 0.0 then R := Pk / Qk; if R <> 0.0 then begin T := Abs((Ans - R) / R); Ans := R; end else T := 1.0; if T < Thresh then goto CDone; K1 := K1 + 1.0; K2 := K2 + 1.0; K3 := K3 + 2.0; K4 := K4 + 2.0; K5 := K5 + 1.0; K6 := K6 - 1.0; K7 := K7 + 2.0; K8 := K8 + 2.0; if Abs(Qk) + Abs(Pk) > BIG then begin Pkm2 := Pkm2 * BIGINV; Pkm1 := Pkm1 * BIGINV; Qkm2 := Qkm2 * BIGINV; Qkm1 := Qkm1 * BIGINV; end; if (Abs(Qk) < BIGINV) or (Abs(Pk) < BIGINV) then begin Pkm2 := Pkm2 * BIG; Pkm1 := Pkm1 * BIG; Qkm2 := Qkm2 * BIG; Qkm1 := Qkm1 * BIG; end; N := N + 1; until N > 400; MathErr := FN_PLOSS; CDone: CFrac1 := Ans; end; function CFrac2(A, B, X : Float) : Float; { Continued fraction expansion #2 for incomplete beta integral } var Xk, Pk, Pkm1, Pkm2, Qk, Qkm1, Qkm2, K1, K2, K3, K4, K5, K6, K7, K8, R, T, Z, Ans, Thresh : Float; N : Integer; label CDone; begin K1 := A; K2 := B - 1.0; K3 := A; K4 := A + 1.0; K5 := 1.0; K6 := A + B; K7 := A + 1.0; K8 := A + 2.0; Pkm2 := 0.0; Qkm2 := 1.0; Pkm1 := 1.0; Qkm1 := 1.0; Z := X / (1.0 - X); Ans := 1.0; R := 1.0; N := 0; Thresh := 3.0 * MACHEP; repeat Xk := - (Z * K1 * K2) / (K3 * K4); Pk := Pkm1 + Pkm2 * Xk; Qk := Qkm1 + Qkm2 * Xk; Pkm2 := Pkm1; Pkm1 := Pk; Qkm2 := Qkm1; Qkm1 := Qk; Xk := (Z * K5 * K6) / (K7 * K8); Pk := Pkm1 + Pkm2 * Xk; Qk := Qkm1 + Qkm2 * Xk; Pkm2 := Pkm1; Pkm1 := Pk; Qkm2 := Qkm1; Qkm1 := Qk; if Qk <> 0.0 then R := Pk / Qk; if R <> 0.0 then begin T := Abs((Ans - R) / R); Ans := R; end else T := 1.0; if T < Thresh then goto CDone; K1 := K1 + 1.0; K2 := K2 - 1.0; K3 := K3 + 2.0; K4 := K4 + 2.0; K5 := K5 + 1.0; K6 := K6 + 1.0; K7 := K7 + 2.0; K8 := K8 + 2.0; if Abs(Qk) + Abs(Pk) > BIG then begin Pkm2 := Pkm2 * BIGINV; Pkm1 := Pkm1 * BIGINV; Qkm2 := Qkm2 * BIGINV; Qkm1 := Qkm1 * BIGINV; end; if (Abs(Qk) < BIGINV) or (Abs(Pk) < BIGINV) then begin Pkm2 := Pkm2 * BIG; Pkm1 := Pkm1 * BIG; Qkm2 := Qkm2 * BIG; Qkm1 := Qkm1 * BIG; end; N := N + 1; until N > 400; MathErr := FN_PLOSS; CDone: CFrac2 := Ans; end; function IBeta(A, B, X : Float) : Float; var A1, B1, X1, T, W, Xc, Y : Float; Flag : Boolean; label Done; begin MathErr := FN_OK; if (A <= 0.0) or (B <= 0.0) or (X < 0.0) or (X > 1.0) then begin IBeta := DefaultVal(FN_DOMAIN); Exit; end; if (X = 0.0) or (X = 1.0) then begin IBeta := X; Exit; end; Flag := False; if (B * X <= 1.0) and (X <= 0.95) then begin T := PSeries(A, B, X); goto Done; end; W := 1.0 - X; { Reverse a and b if x is greater than the mean. } if X > A / (A + B) then begin Flag := True; A1 := B; B1 := A; Xc := X; X1 := W; end else begin A1 := A; B1 := B; Xc := W; X1 := X; end; if Flag and (B1 * X1 <= 1.0) and (X1 <= 0.95) then begin T := PSeries(A1, B1, X1); goto Done; end; { Choose expansion for optimal convergence } Y := X1 * (A1 + B1 - 2.0) - (A1 - 1.0); if Y < 0.0 then W := CFrac1(A1, B1, X1) else W := CFrac2(A1, B1, X1) / Xc; { Multiply w by the factor a b _ _ _ x (1-x) | (a+b) / ( a | (a) | (b) ) } Y := A1 * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X1); T := B1 * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(Xc); if (A1 + B1 < MAXGAM) and (Abs(Y) < MAXLOG) and (Abs(T) < MAXLOG) then begin T := Power(Xc, B1) ; T := T * Power(X1, A1); T := T / A1; T := T * W; T := T * Gamma(A1 + B1) / (Gamma(A1) * Gamma(B1)); end else begin { Resort to logarithms } Y := Y + T + LnGamma(A1 + B1) - LnGamma(A1) - LnGamma(B1) + {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(W / A1); if Y < MINLOG then T := 0.0 else T := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(Y); end; Done: if Flag then if T <= MACHEP then T := 1.0 - MACHEP else T := 1.0 - T; IBeta := T; end; function Erf(X : Float) : Float; begin if X < 0.0 then Erf := - IGamma(0.5, Sqr(X)) else Erf := IGamma(0.5, Sqr(X)); end; function Erfc(X : Float) : Float; begin if X < 0.0 then Erfc := 1.0 + IGamma(0.5, Sqr(X)) else Erfc := JGamma(0.5, Sqr(X)); end; { ---------------------------------------------------------------------- Probability functions ---------------------------------------------------------------------- } function PBinom(N : Integer; P : Float; K : Integer) : Float; begin MathErr := FN_OK; if (P < 0.0) or (P > 1.0) or (N <= 0) or (N < K) then PBinom := DefaultVal(FN_DOMAIN) else if K = 0 then PBinom := IntPower(1.0 - P, N) else if K = N then PBinom := IntPower(P, N) else PBinom := Binomial(N, K) * IntPower(P, K) * IntPower(1.0 - P, N - K); end; function FBinom(N : Integer; P : Float; K : Integer) : Float; begin MathErr := FN_OK; if (P < 0.0) or (P > 1.0) or (N <= 0) or (N < K) then FBinom := DefaultVal(FN_DOMAIN) else if K = 0 then FBinom := IntPower(1.0 - P, N) else if K = N then FBinom := 1.0 else FBinom := 1.0 - IBeta(K + 1, N - K, P); end; function PPoisson(Mu : Float; K : Integer) : Float; var P : Float; I : Integer; begin MathErr := FN_OK; if (Mu <= 0.0) or (K < 0) then PPoisson := DefaultVal(FN_DOMAIN) else if K = 0 then PPoisson := Expo(- Mu) else begin P := Mu; for I := 2 to K do P := P * Mu / I; PPoisson := Expo(- Mu) * P; end; end; function FPoisson(Mu : Float; K : Integer) : Float; begin MathErr := FN_OK; if (Mu <= 0.0) or (K < 0) then FPoisson := DefaultVal(FN_DOMAIN) else if K = 0 then FPoisson := Expo(- Mu) else FPoisson := JGamma(K + 1, Mu); end; function DNorm(X : Float) : Float; begin DNorm := INVSQRT2PI * Expo(- 0.5 * Sqr(X)); end; function FNorm(X : Float) : Float; begin FNorm := 0.5 * (1.0 + Erf(X * SQRT2DIV2)); end; function InvNorm(P : Float) : Float; { ---------------------------------------------------------------------- Inverse of Normal distribution function Returns the argument, X, for which the area under the Gaussian probability density function (integrated from minus infinity to X) is equal to P. Translated from Cephes library. ---------------------------------------------------------------------- } const P0 : TabCoef = ( 8.779679420055069160496E-3, - 7.649544967784380691785E-1, 2.971493676711545292135E0, - 4.144980036933753828858E0, 2.765359913000830285937E0, - 9.570456817794268907847E-1, 1.659219375097958322098E-1, - 1.140013969885358273307E-2, 0, 0); Q0 : TabCoef = ( - 5.303846964603721860329E0, 9.908875375256718220854E0, - 9.031318655459381388888E0, 4.496118508523213950686E0, - 1.250016921424819972516E0, 1.823840725000038842075E-1, - 1.088633151006419263153E-2, 0, 0, 0); P1 : TabCoef = ( 4.302849750435552180717E0, 4.360209451837096682600E1, 9.454613328844768318162E1, 9.336735653151873871756E1, 5.305046472191852391737E1, 1.775851836288460008093E1, 3.640308340137013109859E0, 3.691354900171224122390E-1, 1.403530274998072987187E-2, 1.377145111380960566197E-4); Q1 : TabCoef = ( 2.001425109170530136741E1, 7.079893963891488254284E1, 8.033277265194672063478E1, 5.034715121553662712917E1, 1.779820137342627204153E1, 3.845554944954699547539E0, 3.993627390181238962857E-1, 1.526870689522191191380E-2, 1.498700676286675466900E-4, 0); P2 : TabCoef = ( 3.244525725312906932464E0, 6.856256488128415760904E0, 3.765479340423144482796E0, 1.240893301734538935324E0, 1.740282292791367834724E-1, 9.082834200993107441750E-3, 1.617870121822776093899E-4, 7.377405643054504178605E-7, 0, 0); Q2 : TabCoef = ( 6.021509481727510630722E0, 3.528463857156936773982E0, 1.289185315656302878699E0, 1.874290142615703609510E-1, 9.867655920899636109122E-3, 1.760452434084258930442E-4, 8.028288500688538331773E-7, 0, 0, 0); P3 : TabCoef = ( 2.020331091302772535752E0, 2.133020661587413053144E0, 2.114822217898707063183E-1, - 6.500909615246067985872E-3, - 7.279315200737344309241E-4, - 1.275404675610280787619E-5, - 6.433966387613344714022E-8, - 7.772828380948163386917E-11, 0, 0); Q3 : TabCoef = ( 2.278210997153449199574E0, 2.345321838870438196534E-1, - 6.916708899719964982855E-3, - 7.908542088737858288849E-4, - 1.387652389480217178984E-5, - 7.001476867559193780666E-8, - 8.458494263787680376729E-11, 0, 0, 0); var X, Y, Z, Y2, X0, X1 : Float; Code : Integer; begin if (P <= 0.0) or (P >= 1.0) then begin InvNorm := DefaultVal(FN_DOMAIN); Exit; end; Code := 1; Y := P; if Y > (1.0 - 0.13533528323661269189) then { 0.135... = exp(-2) } begin Y := 1.0 - Y; Code := 0; end; if Y > 0.13533528323661269189 then begin Y := Y - 0.5; Y2 := Y * Y; X := Y + Y * (Y2 * PolEvl(Y2, P0, 7) / P1Evl(Y2, Q0, 7)); X := X * SQRT2PI; InvNorm := X; Exit; end; X := Sqrt(- 2.0 * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(Y)); X0 := X - {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) / X; Z := 1.0 / X; if X < 8.0 then X1 := Z * PolEvl(Z, P1, 9) / P1Evl(Z, Q1, 9) else if X < 32.0 then X1 := Z * PolEvl(Z, P2, 7) / P1Evl(Z, Q2, 7) else X1 := Z * PolEvl(Z, P3, 7) / P1Evl(Z, Q3, 7); X := X0 - X1; if Code <> 0 then X := - X; InvNorm := X; end; function PNorm(X : Float) : Float; var A : Float; begin A := Abs(X); MathErr := FN_OK; if A = 0.0 then PNorm := 1.0 else if A < 1.0 then PNorm := 1.0 - Erf(A * SQRT2DIV2) else PNorm := Erfc(A * SQRT2DIV2); end; function DStudent(Nu : Integer; X : Float) : Float; var L, P, Q : Float; begin MathErr := FN_OK; if Nu < 1 then DStudent := DefaultVal(FN_DOMAIN) else begin P := 0.5 * (Nu + 1); Q := 0.5 * Nu; L := LnGamma(P) - LnGamma(Q) - 0.5 * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(Nu * PI) - P * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(1.0 + Sqr(X) / Nu); DStudent := Expo(L); end; end; function FStudent(Nu : Integer; X : Float) : Float; begin MathErr := FN_OK; if Nu < 1 then FStudent := DefaultVal(FN_DOMAIN) else FStudent := 1.0 - IBeta(0.5 * Nu, 0.5, Nu / (Nu + Sqr(X))); end; function PStudent(Nu : Integer; X : Float) : Float; begin MathErr := FN_OK; if Nu < 1 then PStudent := DefaultVal(FN_DOMAIN) else PStudent := IBeta(0.5 * Nu, 0.5, Nu / (Nu + Sqr(X))); end; function DKhi2(Nu : Integer; X : Float) : Float; begin MathErr := FN_OK; DKhi2 := DGamma(0.5 * Nu, 0.5, X); end; function FKhi2(Nu : Integer; X : Float) : Float; begin MathErr := FN_OK; if (Nu < 1) or (X <= 0.0) then FKhi2 := DefaultVal(FN_DOMAIN) else FKhi2 := IGamma(0.5 * Nu, 0.5 * X); end; function PKhi2(Nu : Integer; X : Float) : Float; begin MathErr := FN_OK; if (Nu < 1) or (X <= 0.0) then PKhi2 := DefaultVal(FN_DOMAIN) else PKhi2 := JGamma(0.5 * Nu, 0.5 * X); end; function DSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; var P1, P2, R, S, L : Float; begin MathErr := FN_OK; if (Nu1 < 1) or (Nu2 < 1) or (X <= 0.0) then DSnedecor := DefaultVal(FN_DOMAIN) else begin R := Int(Nu1) / Int(Nu2); P1 := 0.5 * Nu1; P2 := 0.5 * Nu2; S := P1 + P2; L := LnGamma(S) - LnGamma(P1) - LnGamma(P2) + P1 * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(R); L := L + (P1 - 1.0) * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) - S * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(1.0 + R * X); DSnedecor := Expo(L); end; end; function FSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; begin MathErr := FN_OK; if (Nu1 < 1) or (Nu2 < 1) or (X <= 0.0) then FSnedecor := DefaultVal(FN_DOMAIN) else FSnedecor := 1.0 - IBeta(0.5 * Nu2, 0.5 * Nu1, Nu2 / (Nu2 + Nu1 * X)); end; function PSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; begin MathErr := FN_OK; if (Nu1 < 1) or (Nu2 < 1) or (X <= 0.0) then PSnedecor := DefaultVal(FN_DOMAIN) else PSnedecor := IBeta(0.5 * Nu2, 0.5 * Nu1, Nu2 / (Nu2 + Nu1 * X)); end; function DExpo(A, X : Float) : Float; begin if (A <= 0.0) or (X < 0.0) then DExpo := DefaultVal(FN_DOMAIN) else DExpo := A * Expo(- A * X); end; function FExpo(A, X : Float) : Float; begin if (A <= 0.0) or (X < 0.0) then FExpo := DefaultVal(FN_DOMAIN) else FExpo := 1.0 - Expo(- A * X); end; function DBeta(A, B, X : Float) : Float; var L : Float; begin MathErr := FN_OK; if (A <= 0.0) or (B <= 0.0) or (X < 0.0) or (X > 1.0) then DBeta := DefaultVal(FN_DOMAIN) else if X = 0.0 then if A < 1.0 then DBeta := DefaultVal(FN_SING) else DBeta := 0.0 else if X = 1.0 then if B < 1.0 then DBeta := DefaultVal(FN_SING) else DBeta := 0.0 else begin L := LnGamma(A + B) - LnGamma(A) - LnGamma(B); L := L + (A - 1.0) * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) + (B - 1.0) * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(1.0 - X); DBeta := Expo(L); end; end; function FBeta(A, B, X : Float) : Float; begin FBeta := IBeta(A, B, X); end; function DGamma(A, B, X : Float) : Float; var L : Float; begin MathErr := FN_OK; if (A <= 0.0) or (B <= 0.0) or (X < 0.0) then DGamma := DefaultVal(FN_DOMAIN) else if X = 0.0 then if A < 1.0 then DGamma := DefaultVal(FN_SING) else if A = 1.0 then DGamma := B else DGamma := 0.0 else begin L := A * Ln(B) - LnGamma(A) + (A - 1.0) * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) - B * X; DGamma := Expo(L); end; end; function FGamma(A, B, X : Float) : Float; begin FGamma := IGamma(A, B * X); end; { ---------------------------------------------------------------------- Random numbers ---------------------------------------------------------------------- } var X1, X2, C1, C2 : LongInt; procedure RMarIn(Seed1, Seed2 : Integer); begin X1 := Seed1; X2 := Seed2; C1 := 0; C2 := 0; end; function IRanMar : LongInt; var Y1, Y2 : LongInt; begin Y1 := 18000 * X1 + C1; X1 := Y1 and 65535; C1 := Y1 shr 16; Y2 := 30903 * X2 + C2; X2 := Y2 and 65535; C2 := Y2 shr 16; IRanMar := (X1 shl 16) + (X2 and 65535); end; function RanMar : Float; begin RanMar := (IRanMar + 2147483648.0) / 4294967296.0; end; function RanGaussStd : Float; { Computes 2 random numbers from the standard normal distribution, returns one and saves the other for the next call } const Gauss_Save : Float = 0.0; { Saves a random number } Gauss_Set : Boolean = False; { Flags if a number has been saved } var R, Theta, SinTheta, CosTheta : Float; begin if not Gauss_Set then begin R := Sqrt(- 2.0 * Log(RanMar)); Theta := TWOPI * RanMar; SinCos(Theta, SinTheta, CosTheta); RanGaussStd := R * CosTheta; { Return 1st number } Gauss_Save := R * SinTheta; { Save 2nd number } end else RanGaussStd := Gauss_Save; { Return saved number } Gauss_Set := not Gauss_Set; end; function RanGauss(Mu, Sigma : Float) : Float; { Returns a random number from the normal distribution with mean Mu and standard deviation Sigma } begin RanGauss := Mu + Sigma * RanGaussStd; end; { ---------------------------------------------------------------------- Initialization code ---------------------------------------------------------------------- } var I : Integer; begin { Initialize MathErr } MathErr := FN_OK; { Store the factorials of the first NFACT integers in a table } FactArray[0] := 1.0; FactArray[1] := 1.0; FactArray[2] := 2.0; for I := 3 to NFACT do FactArray[I] := FactArray[I - 1] * I; { Initialize random number generator } RMarIn(1802, 9373); end. ��������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/fitpka.pas�����������������������������������������0000755�0001750�0001750�00000012532�11326425446�021254� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITPKA.PAS * * Version 1.1 * * (c) J. Debord, July 1999 * ********************************************************************** This unit fits the acid/base titration function : B - A y = A + ---------------- 1 + 10^(pKa - x) where x is pH y is some property (e.g. absorbance) which depends on the ratio of the acidic and basic forms of the compound A is the property for the pure acidic form B is the property for the pure basic form pKa is the acidity constant ********************************************************************** } unit FitPKa; {$F+} interface uses FMath, Matrices, Stat, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X : Float; B, D : PVector); function FitModel(X, Y : PVector; N : Integer; B : PVector) : Integer; implementation function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } begin FuncName := 'y = A + (B - A) / [1 + 10^(pKa - x)]' end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted (0 if there is a constant term A, 1 otherwise) -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 2; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'A'; 1 : ParamName := 'B'; 2 : ParamName := 'pKa'; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = A B^[1] = B B^[2] = pKa -------------------------------------------------------------------- } begin RegFunc := B^[0] + (B^[1] - B^[0]) / (1.0 + Exp10(B^[2] - X)); end; procedure DerivProc(X : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point X with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter. -------------------------------------------------------------------- } var Q, R : Float; begin Q := Exp10(B^[2] - X); { 10^(pKa - x) } R := 1.0 / (1.0 + Q); { 1/[1 + 10^(pKa - x)] } D^[0] := 1.0 - R; { dy/dA = 1 - 1/[1 + 10^(pKa - x)] } D^[1] := R; { dy/dB = 1/[1 + 10^(pKa - x)] } { dy/dpKa = (A-B).10^(pKa - x).Ln(10) / [1 + 10^(pKa - x)]^2 } D^[2] := (B^[0] - B^[1]) * Q * LN10 * Sqr(R); end; procedure SortPoints(X, Y : PVector; N : Integer); { ---------------------------------------------------------------------- Sort points by increasing X values ---------------------------------------------------------------------- } var I, J, K : Integer; A : Float; begin for I := 1 to Pred(N) do begin K := I; A := X^[I]; for J := Succ(I) to N do if X^[J] < A then begin K := J; A := X^[J]; end; FSwap(X^[I], X^[K]); FSwap(Y^[I], Y^[K]); end; end; function FitModel(X, Y : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of the acid/base titration function -------------------------------------------------------------------- Input : X, Y = point coordinates N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- } var K : Integer; { Loop variable } Z : Float; { (A + B) / 2 } begin SortPoints(X, Y, N); B^[0] := Y^[1]; B^[1] := Y^[N]; Z := 0.5 * (B^[0] + B^[1]); for K := 2 to N - 1 do if Y^[K] = Z then B^[2] := X^[K] else if ((Y^[K] < Z) and (Y^[K + 1] > Z)) or ((Y^[K] > Z) and (Y^[K + 1] < Z)) then B^[2] := 0.5 * (X^[K] + X^[K + 1]); FitModel := 0; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/Regress.pas����������������������������������������0000755�0001750�0001750�00000132600�11326425446�021407� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit REGRESS.PAS * * Version 2.2 * * (c) J. Debord, August 2000 * ********************************************************************** Regression routines ********************************************************************** } unit Regress; interface uses FMath, Matrices, Eigen, Optim, SimOpt, Stat,dialogs; { ********************************************************************** Type definitions ********************************************************************** } { Algorithm for linear regression } type TRegAlgo = ( GAUSS_JORDAN, { Gauss-Jordan solution of normal equations } SVD); { Singular value decomposition } { Optimization algorithm for nonlinear regression } type TOptAlgo = ( NL_MARQ, { Marquardt algorithm } NL_SIMP, { Simplex algorithm } NL_BFGS, { BFGS algorithm } NL_SA); { Simulated annealing } { Regression modes } type TRegMode = (UNWEIGHTED, WEIGHTED); { Regression function } type TRegFunc = function(X : Float; B : PVector) : Float; { Procedure to compute the derivatives of the regression function with respect to the regression parameters } type TDerivProc = procedure(RegFunc : TRegFunc; X, Y : Float; B, D : PVector); { Test of regression } type TRegTest = record Vr, { Residual variance } R2, { Coefficient of determination } R2a, { Adjusted coeff. of determination } F, { Variance ratio (explained/residual) } Prob : Float; { Probability of F } end; { ********************************************************************** Procedures to modify the regression settings ********************************************************************** } procedure SetRegAlgo(Algo : TRegAlgo); { ---------------------------------------------------------------------- Sets the linear regression algorithm according to Algo, which must be GAUSS_JORDAN or SVD. The default algorithm is SVD. ---------------------------------------------------------------------- } procedure SetOptAlgo(Algo : TOptAlgo); { ---------------------------------------------------------------------- Sets the optimization algorithm according to Algo, which must be NL_MARQ, NL_SIMP, NL_BFGS or NL_SA. The default algorithm is NL_MARQ. ---------------------------------------------------------------------- } procedure SetFirstPoint(Index : Integer); { ---------------------------------------------------------------------- Sets the index of the first data point (usually 0 or 1). The default value is 1. ---------------------------------------------------------------------- } function GetRegAlgo : TRegAlgo; { ---------------------------------------------------------------------- Returns the linear regression algorithm ---------------------------------------------------------------------- } function GetOptAlgo : TOptAlgo; { ---------------------------------------------------------------------- Returns the optimization algorithm ---------------------------------------------------------------------- } function GetFirstPoint : Integer; { ---------------------------------------------------------------------- Returns the index of the first data point ---------------------------------------------------------------------- } { ********************************************************************** Unweighted regression routines ********************************************************************** These routines fit equations to data by minimizing the sum of squared residuals : SS = Sum [y(k) - ycalc(k)]^2 where y(k) and ycalc(k) are respectively the observed and calculated value of the dependent variable for observation k. ycalc(k) is a function of the regression parameters b(0), b(1) ... The following regression types are implemented : * Simple linear regression : y(k) = b(0) + b(1) * x(k) * Multiple linear regression : y(k) = b(0) + b(1) * x(1,k) + b(2) * x(2,k) + ... + b(Nvar) * x(Nvar,k) * Polynomial regression : y(k) = b(0) + b(1) * x(k) + b(2) * x(k)^2 + ... + b(Deg) * x(k)^Deg * Nonlinear regression : y(k) = f[x(k), b(0), b(1), ... ] where f is a user-specified function. The following parameters are common to all routines : Input : X = Vector or matrix of independent variables Y = Vector of dependent variable N = Index of the last observation Output : B = Regression parameters V = Inverse matrix of normal equations ********************************************************************** } function LinFit(X, Y : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- Simple linear regression ---------------------------------------------------------------------- } function MulFit(X : PMatrix; Y : PVector; N, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- Multiple linear regression ---------------------------------------------------------------------- Additional input parameters : Nvar = Index of the last independent variable ConsTerm = Flags the presence of a constant term b(0) ---------------------------------------------------------------------- } function PolFit(X, Y : PVector; N, Deg : Integer; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- Polynomial regression ---------------------------------------------------------------------- Additional input parameter : Deg = Degree of polynomial ---------------------------------------------------------------------- } function NLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y : PVector; N, Lbound, Ubound, MaxIter : Integer; Tol : Float; B, B_min, B_max : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- Nonlinear regression ---------------------------------------------------------------------- Additional input parameters : RegFunc = Regression function DerivProc = Procedure to compute the derivatives of RegFunc Lbound, Ubound = Indices of first and last function parameters MaxIter = Maximum number of iterations Tol = Required parameter precision B = Initial parameter values B_min, B_max = Lower and upper parameter bounds ---------------------------------------------------------------------- } { ********************************************************************** Weighted regression routines ********************************************************************** These routines fit equations to data by minimizing the sum of weighted squared residuals : SWS = Sum w(k)*[y(k) - ycalc(k)]^2 where the "weight" w(k) is inversely proportional to the variance v(k) of the observation y(k). v(k) is usually computed as : v(k) = Vr * g[y(k)] = Vr / w(k) where Vr is the residual variance and g is a user-specified function (e.g. g[y(k)] = y(k)^2 for a constant coefficient of variation). Function syntax and results are the same than for unweighted regression except that the vector of weights (W) is passed as an additional input parameter. ********************************************************************** } function WLinFit(X, Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; function WMulFit(X : PMatrix; Y, W : PVector; N, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix) : Integer; function WPolFit(X, Y, W : PVector; N, Deg : Integer; B : PVector; V : PMatrix) : Integer; function WNLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y, W : PVector; N, Lbound, Ubound, MaxIter : Integer; Tol : Float; B, B_min, B_max : PVector; V : PMatrix) : Integer; { ********************************************************************** Procedure to compute the derivatives of the regression function by numerical differentiation. ********************************************************************** } procedure NumDeriv(RegFunc : TRegFunc; X, Y : Float; B, D : PVector); { ---------------------------------------------------------------------- Input parameters : RegFunc = Regression function X, Y = Coordinates of point B = Regression parameters Output parameter : D = Derivatives (D^[I] contains the derivative w.r.t. parameter B^[I]) ---------------------------------------------------------------------- } { ********************************************************************** Routines to test the quality of the regression ********************************************************************** These routines compute the variance-covariance matrix of the fitted parameters and the different statistics used to test the quality of the fit. Input parameters : Y = Vector of dependent variable Ycalc = Computed Y values W = Vector of weights (if any) N = Index of the last observation Lbound, Ubound = Indices of first & last fitted parameters V = Inverse normal equations matrix Output parameters : V = Variance-covariance matrix Test = Test statistics (Vr, R2, R2a, F, Prob) ********************************************************************** } procedure RegTest(Y, Ycalc : PVector; N, Lbound, Ubound : Integer; V : PMatrix; var Test : TRegTest); { ---------------------------------------------------------------------- Test of unweighted regression ---------------------------------------------------------------------- } procedure WRegTest(Y, Ycalc, W : PVector; N, Lbound, Ubound : Integer; V : PMatrix; var Test : TRegTest); { ---------------------------------------------------------------------- Test of weighted regression ---------------------------------------------------------------------- } { ********************************************************************** Test of regression parameters ********************************************************************** } procedure ParamTest(B : PVector; V : PMatrix; N, Lbound, Ubound : Integer; S, T, Prob : PVector); { ---------------------------------------------------------------------- This routine tests the significance of the parameters. It must be called AFTER RegTest or WRegTest since it uses the variance-covariance matrix. ---------------------------------------------------------------------- Input parameters : B = Regression parameters V = Variance-covariance matrix N = Index of the last observation Lbound, Ubound = Indices of first & last fitted parameters ---------------------------------------------------------------------- Output parameters : S = Standard deviations of parameters T = Student's t Prob = Probabilities ---------------------------------------------------------------------- } { ********************************************************************** Correlation and principal component analysis Common parameters: X = matrix of variables (X^[I] contains the I-th variable) N = Index of the last observation Lbound, Ubound = Indices of first & last variables M = Mean vector (M^[I] = mean of X^[I]) S = Vector of standard deviations V = Variance-covariance matrix R = Correlation matrix ********************************************************************** } procedure VecMean(X : PMatrix; N, Lbound, Ubound : Integer; M : PVector); { ---------------------------------------------------------------------- Computes the mean vector (M) from matrix X Input : X, Lbound, Ubound Output : M ---------------------------------------------------------------------- } procedure VecSD(X : PMatrix; N, Lbound, Ubound : Integer; M, S : PVector); { ---------------------------------------------------------------------- Computes the vector of standard deviations (S) from matrix X Input : X, Lbound, Ubound, M Output : S ---------------------------------------------------------------------- } procedure MatVarCov(X : PMatrix; N, Lbound, Ubound : Integer; M : PVector; V : PMatrix); { ---------------------------------------------------------------------- Computes the variance-covariance matrix (V) from matrix X Input : X, Lbound, Ubound, M Output : V ---------------------------------------------------------------------- } procedure MatCorrel(V : PMatrix; Lbound, Ubound : Integer; R : PMatrix); { ---------------------------------------------------------------------- Computes the correlation matrix (R) from the variance-covariance matrix (V) Input : V, Lbound, Ubound Output : R ---------------------------------------------------------------------- } function PCA(R : PMatrix; Lbound, Ubound : Integer; Lambda : PVector; C, Rc : PMatrix) : Integer; { ---------------------------------------------------------------------- Performs a principal component analysis of the correlation matrix R ---------------------------------------------------------------------- Input : R, Lbound, Ubound Output : Lambda = Eigenvalues of the correlation matrix (in descending order) C = Eigenvectors of the correlation matrix (C^[I] is the I-th eigenvector) Rc = Correlations between principal factors and variables (R^[I]^[J] is the correlation coefficient between factor I and variable J) ---------------------------------------------------------------------- Possible results : MAT_OK : No error MAT_NON_CONV : Non-convergence of eigenvalue determination ---------------------------------------------------------------------- NB : This procedure destroys the original matrix R ---------------------------------------------------------------------- } procedure ScaleVar(X : PMatrix; N, Lbound, Ubound : Integer; M, S : PVector; Z : PMatrix); { ---------------------------------------------------------------------- Scales a set of variables by subtracting means and dividing by SD's ---------------------------------------------------------------------- Input : X, N, Lbound, Ubound, M, S Output : Z = matrix of scaled variables (Z^[I] contains the I-th var.) ---------------------------------------------------------------------- } procedure PrinFac(Z : PMatrix; N, Lbound, Ubound : Integer; C, F : PMatrix); { ---------------------------------------------------------------------- Computes principal factors ---------------------------------------------------------------------- Input : Z, N, Lbound, Ubound C = matrix of eigenvectors from PCA Output : F = matrix of principal factors (F^[I] contains the I-th factor) ---------------------------------------------------------------------- } implementation { Constants for eigenvalue determination in PCA } const PCA_MAXITER = 100; { Max number of iterations } PCA_TOL = 1.0E-6; { Required precision } MAX_FUNC = 1.0E+30; { Max. value for objective function (used to prevent overflow) } { Default settings } const RegAlgo : TRegAlgo = SVD; { Linear regression algorithm } OptAlgo : TOptAlgo = NL_MARQ; { Optimization algorithms } FirstPoint : Integer = 1; { Index of first data point } { Global variables used by the nonlinear regression routines } const NN : Integer = 1; { Number of observations } XX : PVector = nil; { X coordinates } YY : PVector = nil; { Y coordinates } WW : PVector = nil; { Weights } YYcalc : PVector = nil; { Estimated Y values } FirstParam : Integer = 0; { Index of first fitted parameter } LastParam : Integer = 1; { Index of last fitted parameter } ParamMin : PVector = nil; { Lower bounds on parameters } ParamMax : PVector = nil; { Higher bounds on parameters } var RegFunc1 : TRegFunc; { Regression function } DerivProc1 : TDerivProc; { Derivation procedure } function TolSVD(N : Integer) : Float; { This function sets the relative threshold below which a singular value is considered zero. N is the number of observations. } begin TolSVD := N * MACHEP; end; procedure SetRegAlgo(Algo : TRegAlgo); begin RegAlgo := Algo; end; procedure SetOptAlgo(Algo : TOptAlgo); begin OptAlgo := Algo; end; procedure SetFirstPoint(Index : Integer); begin if Index >= 0 then FirstPoint := Index; end; function GetRegAlgo : TRegAlgo; begin GetRegAlgo := RegAlgo; end; function GetOptAlgo : TOptAlgo; begin GetOptAlgo := OptAlgo; end; function GetFirstPoint : Integer; begin GetFirstPoint := FirstPoint; end; function GenLinFit(Mode : TRegMode; X, Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- General linear regression routine ---------------------------------------------------------------------- } var WX, S, SX, SY, SX2, SXY, D : Float; K : Integer; begin S := 0.0; SX := 0.0; SY := 0.0; SX2 := 0.0; SXY := 0.0; if Mode = UNWEIGHTED then begin S := N - FirstPoint + 1; for K := FirstPoint to N do begin SX := SX + X^[K]; SY := SY + Y^[K]; SX2 := SX2 + Sqr(X^[K]); SXY := SXY + X^[K] * Y^[K]; end; end else begin for K := FirstPoint to N do begin WX := W^[K] * X^[K]; S := S + W^[K]; SX := SX + WX; SY := SY + W^[K] * Y^[K]; SX2 := SX2 + WX * X^[K]; SXY := SXY + WX * Y^[K]; end; end; D := S * SX2 - Sqr(SX); if D <= 0.0 then GenLinFit := MAT_SINGUL else begin V^[0]^[0] := SX2 / D; V^[0]^[1] := - SX / D; V^[1]^[0] := V^[0]^[1]; V^[1]^[1] := S / D; B^[0] := V^[0]^[0] * SY + V^[0]^[1] * SXY; B^[1] := V^[1]^[0] * SY + V^[1]^[1] * SXY; GenLinFit := MAT_OK; end; end; function LinFit(X, Y : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; var W : PVector; begin LinFit := GenLinFit(UNWEIGHTED, X, Y, W, N, B, V); end; function WLinFit(X, Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; begin WLinFit := GenLinFit(WEIGHTED, X, Y, W, N, B, V); end; function Gauss_GenMulFit(Mode : TRegMode; X : PMatrix; Y, W : PVector; N, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- General multiple linear regression routine (Gauss-Jordan algorithm) ---------------------------------------------------------------------- } var A : PMatrix; { Matrix of normal equations } G : PVector; { Constant vector } I, J, K : Integer; { Loop variables } WX : Float; begin DimMatrix(A, Nvar, Nvar); DimVector(G, Nvar); { If constant term, set line 0 and column 0 of matrix A, and element 0 of vecteur G } if ConsTerm then begin if Mode = UNWEIGHTED then begin A^[0]^[0] := Int(N - FirstPoint + 1); for K := FirstPoint to N do begin for J := 1 to Nvar do A^[0]^[J] := A^[0]^[J] + X^[J]^[K]; G^[0] := G^[0] + Y^[K]; end; end else begin for K := FirstPoint to N do begin A^[0]^[0] := A^[0]^[0] + W^[K]; for J := 1 to Nvar do A^[0]^[J] := A^[0]^[J] + W^[K] * X^[J]^[K]; G^[0] := G^[0] + W^[K] * Y^[K]; end; end; for J := 1 to Nvar do A^[J]^[0] := A^[0]^[J]; end; { Set other elements of A and G } if Mode = UNWEIGHTED then for K := FirstPoint to N do for I := 1 to Nvar do begin for J := I to Nvar do A^[I]^[J] := A^[I]^[J] + X^[I]^[K] * X^[J]^[K]; G^[I] := G^[I] + X^[I]^[K] * Y^[K]; end else for K := FirstPoint to N do for I := 1 to Nvar do begin WX := W^[K] * X^[I]^[K]; for J := I to Nvar do A^[I]^[J] := A^[I]^[J] + WX * X^[J]^[K]; G^[I] := G^[I] + WX * Y^[K]; end; { Fill in symmetric matrix } for I := 2 to Nvar do for J := 1 to Pred(I) do A^[I]^[J] := A^[J]^[I]; { Solve normal equations } if ConsTerm then Gauss_GenMulFit := GaussJordan(A, G, 0, Nvar, V, B) else Gauss_GenMulFit := GaussJordan(A, G, 1, Nvar, V, B); DelMatrix(A, Nvar, Nvar); DelVector(G, Nvar); end; function SVD_GenMulFit(Mode : TRegMode; X : PMatrix; Y, W : PVector; N, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- General multiple linear regression routine (SVD algorithm) ---------------------------------------------------------------------- } var U : PMatrix; { Matrix of independent variables for SVD } Z : PVector; { Vector of dependent variables for SVD } S : PVector; { Singular values } S2inv : PVector; { Inverses of squared singular values } V1 : PMatrix; { Orthogonal matrix from SVD } Lbound : Integer; { Lower bound of U matrix in both dims. } Ubound : Integer; { Upper bound of U matrix in 1st dim. } I, J, K : Integer; { Loop variables } Sigma : Float; { Square root of weight } Sum : Float; { Element of variance-covariance matrix } ErrCode : Integer; { Error code } begin if ConsTerm then begin Lbound := 0; Ubound := N - FirstPoint; end else begin Lbound := 1; Ubound := N - FirstPoint + 1; end; { Dimension arrays } DimMatrix(U, Ubound, Nvar); DimVector(Z, Ubound); DimVector(S, Nvar); DimVector(S2inv, Nvar); DimMatrix(V1, Nvar, Nvar); { ---------------------------------------------------------- Prepare arrays for SVD : If constant term, use U[0..(N - FirstPoint), 0..Nvar] and Z[0..(N - FirstPoint)] Else use U[1..(N - FirstPoint + 1), 1..Nvar] and Z[1..(N - FirstPoint + 1)] ---------------------------------------------------------- } if Mode = UNWEIGHTED then for I := Lbound to Ubound do begin K := I - Lbound + FirstPoint; Z^[I] := Y^[K]; if ConsTerm then U^[I]^[0] := 1.0; for J := 1 to Nvar do U^[I]^[J] := X^[J]^[K]; end else for I := Lbound to Ubound do begin K := I - Lbound + FirstPoint; Sigma := Sqrt(W^[K]); Z^[I] := Y^[K] * Sigma; if ConsTerm then U^[I]^[0] := Sigma; for J := 1 to Nvar do U^[I]^[J] := X^[J]^[K] * Sigma; end; { Perform singular value decomposition } ErrCode := SV_Decomp(U, Lbound, Ubound, Nvar, S, V1); if ErrCode = MAT_OK then begin { Set the lowest singular values to zero } SV_SetZero(S, Lbound, Nvar, TolSVD(N - FirstPoint + 1)); { Solve the system } SV_Solve(U, S, V1, Z, Lbound, Ubound, Nvar, B); { Compute variance-covariance matrix } for I := Lbound to Nvar do if S^[I] > 0.0 then S2inv^[I] := 1.0 / Sqr(S^[I]) else S2inv^[I] := 0.0; for I := Lbound to Nvar do for J := Lbound to I do begin Sum := 0.0; for K := Lbound to Nvar do Sum := Sum + V1^[I]^[K] * V1^[J]^[K] * S2inv^[K]; V^[I]^[J] := Sum; V^[J]^[I] := Sum; end; end; SVD_GenMulFit := ErrCode; DelMatrix(U, Ubound, Nvar); DelVector(Z, Ubound); DelVector(S, Nvar); DelVector(S2inv, Nvar); DelMatrix(V1, Nvar, Nvar); end; function GenMulFit(Mode : TRegMode; X : PMatrix; Y, W : PVector; N, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- General multiple linear regression routine ---------------------------------------------------------------------- } begin case RegAlgo of GAUSS_JORDAN : GenMulFit := Gauss_GenMulFit(Mode, X, Y, W, N, Nvar, ConsTerm, B, V); SVD : GenMulFit := SVD_GenMulFit(Mode, X, Y, W, N, Nvar, ConsTerm, B, V); end; end; function MulFit(X : PMatrix; Y : PVector; N, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix) : Integer; var W : PVector; begin MulFit := GenMulFit(UNWEIGHTED, X, Y, W, N, Nvar, ConsTerm, B, V); end; function WMulFit(X : PMatrix; Y, W : PVector; N, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix) : Integer; begin WMulFit := GenMulFit(WEIGHTED, X, Y, W, N, Nvar, ConsTerm, B, V); end; procedure PowMat(X : PVector; N, Deg : Integer; U : PMatrix); { ---------------------------------------------------------------------- Computes matrix of increasing powers of X for polynomial regression ---------------------------------------------------------------------- } var I, K : Integer; begin for K := FirstPoint to N do begin U^[1]^[K] := X^[K]; for I := 2 to Deg do U^[I]^[K] := U^[I - 1]^[K] * X^[K]; end; end; function GenPolFit(Mode : TRegMode; X, Y, W : PVector; N, Deg : Integer; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- General polynomial regression routine ---------------------------------------------------------------------- } var U : PMatrix; begin DimMatrix(U, Deg, N); PowMat(X, N, Deg, U); GenPolFit := GenMulFit(Mode, U, Y, W, N, Deg, True, B, V); DelMatrix(U, Deg, N); end; function PolFit(X, Y : PVector; N, Deg : Integer; B : PVector; V : PMatrix) : Integer; var W : PVector; begin PolFit := GenPolFit(UNWEIGHTED, X, Y, W, N, Deg, B, V); end; function WPolFit(X, Y, W : PVector; N, Deg : Integer; B : PVector; V : PMatrix) : Integer; begin WPolFit := GenPolFit(WEIGHTED, X, Y, W, N, Deg, B, V); end; procedure SetGlobalVar(RegFunc : TRegFunc; DerivProc : TDerivProc; Mode : TRegMode; X, Y, W : PVector; N, Lbound, Ubound : Integer; B_min, B_max : PVector); { Sets the global variables used by the nonlinear regression routines } begin DelVector(XX, NN); DelVector(YY, NN); DelVector(YYcalc, NN); DimVector(XX, N); DimVector(YY, N); DimVector(YYcalc, N); CopyVector(XX, X, FirstPoint, N); CopyVector(YY, Y, FirstPoint, N); if Mode = WEIGHTED then begin DelVector(WW, NN); DimVector(WW, N); CopyVector(WW, W, FirstPoint, N); end; NN := N; DelVector(ParamMin, LastParam); DelVector(ParamMax, LastParam); DimVector(ParamMin, Ubound); DimVector(ParamMax, Ubound); CopyVector(ParamMin, B_min, Lbound, Ubound); CopyVector(ParamMax, B_max, Lbound, Ubound); FirstParam := Lbound; LastParam := Ubound; RegFunc1 := RegFunc; DerivProc1 := DerivProc; end; {$F+} procedure NumDeriv(RegFunc : TRegFunc; X, Y : Float; B, D : PVector); var I : Integer; Eps, Temp, Y1 : Float; begin Eps := Sqrt(MACHEP); for I := FirstParam to LastParam do begin Temp := B^[I]; { Save parameter } B^[I] := B^[I] + Eps * Abs(B^[I]); { Modified parameter } Y1 := RegFunc(X, B); D^[I] := (Y1 - Y) / (B^[I] - Temp); { Derivative } B^[I] := Temp; { Restore parameter } end; end; function OutOfBounds(B, B_min, B_max : PVector) : Boolean; { Check if the parameters are inside the bounds } var I : Integer; OoB : Boolean; begin I := FirstParam; OoB := False; repeat OoB := (B^[I] < B_min^[I]) or (B^[I] > B_max^[I]); Inc(I); until OoB or (I > LastParam); OutOfBounds := OoB; end; function OLS_ObjFunc(B : PVector) : Float; { Objective function for unweighted nonlinear regression } var K : Integer; S : Float; begin if OutOfBounds(B, ParamMin, ParamMax) then begin OLS_ObjFunc := MAX_FUNC; Exit; end; S := 0.0; K := FirstPoint; repeat YYcalc^[K] := RegFunc1(XX^[K], B); S := S + Sqr(YY^[K] - YYcalc^[K]); Inc(K); until (K > NN) or (S > MAX_FUNC); if S > MAX_FUNC then S := MAX_FUNC; OLS_ObjFunc := S; end; procedure OLS_Gradient(Func : TFuncNVar; B : PVector; Lbound, Ubound : Integer; G : PVector); { Gradient for unweighted nonlinear regression. Func is a dummy parameter here. } var I, K : Integer; { Loop variables } R : Float; { Residual } D : PVector; { Derivatives of the regression function } begin DimVector(D, Ubound); { Initialization } for I := Lbound to Ubound do G^[I] := 0.0; { Compute Gradient } for K := FirstPoint to NN do begin R := YY^[K] - YYcalc^[K]; DerivProc1(RegFunc1, XX^[K], YYcalc^[K], B, D); for I := Lbound to Ubound do G^[I] := G^[I] - D^[I] * R; end; for I := Lbound to Ubound do G^[I] := 2.0 * G^[I]; DelVector(D, Ubound); end; procedure OLS_HessGrad(Func : TFuncNVar; B : PVector; Lbound, Ubound : Integer; G : PVector; H : PMatrix); { Gradient and Hessian for unweighted nonlinear regression. Func is a dummy parameter here. } var I, J, K : Integer; { Loop variables } R : Float; { Residual } D : PVector; { Derivatives of the regression function } begin DimVector(D, Ubound); { Initializations } for I := Lbound to Ubound do begin G^[I] := 0.0; for J := I to Ubound do H^[I]^[J] := 0.0; end; { Compute Gradient & Hessian } for K := FirstPoint to NN do begin R := YY^[K] - YYcalc^[K]; DerivProc1(RegFunc1, XX^[K], YYcalc^[K], B, D); for I := Lbound to Ubound do begin G^[I] := G^[I] - D^[I] * R; for J := I to Ubound do H^[I]^[J] := H^[I]^[J] + D^[I] * D^[J]; end; end; { Fill in symmetric matrix } for I := Succ(Lbound) to Ubound do for J := Lbound to Pred(I) do H^[I]^[J] := H^[J]^[I]; DelVector(D, Ubound); end; function WLS_ObjFunc(B : PVector) : Float; { Objective function for weighted nonlinear regression } var K : Integer; S : Float; begin if OutOfBounds(B, ParamMin, ParamMax) then begin WLS_ObjFunc := MAX_FUNC; Exit; end; S := 0.0; K := FirstPoint; repeat YYcalc^[K] := RegFunc1(XX^[K], B); S := S + WW^[K] * Sqr(YY^[K] - YYcalc^[K]); Inc(K); until (K > NN) or (S > MAX_FUNC); if S > MAX_FUNC then S := MAX_FUNC; WLS_ObjFunc := S; end; procedure WLS_Gradient(Func : TFuncNVar; B : PVector; Lbound, Ubound : Integer; G : PVector); { Gradient for weighted nonlinear regression. Func is a dummy parameter here. } var I, K : Integer; { Loop variables } R : Float; { Residual } D : PVector; { Derivatives of the regression function } WD : Float; { Weighted derivative } begin DimVector(D, Ubound); { Initialization } for I := Lbound to Ubound do G^[I] := 0.0; { Compute Gradient } for K := FirstPoint to NN do begin R := YY^[K] - YYcalc^[K]; DerivProc1(RegFunc1, XX^[K], YYcalc^[K], B, D); for I := Lbound to Ubound do begin WD := WW^[K] * D^[I]; G^[I] := G^[I] - WD * R; end; end; for I := Lbound to Ubound do G^[I] := 2.0 * G^[I]; DelVector(D, Ubound); end; procedure WLS_HessGrad(Func: TFuncNVar; B : PVector; Lbound, Ubound : Integer; G : PVector; H : PMatrix); { Gradient and Hessian for weighted nonlinear regression. Func is a dummy parameter here. } var I, J, K : Integer; { Loop variables } R : Float; { Residual } D : PVector; { Derivatives of the regression function } WD : Float; { Weighted derivative } begin DimVector(D, Ubound); { Initialization } for I := Lbound to Ubound do begin G^[I] := 0.0; for J := I to Ubound do H^[I]^[J] := 0.0; end; { Compute Gradient & Hessian } for K := FirstPoint to NN do begin R := YY^[K] - YYcalc^[K]; DerivProc1(RegFunc1, XX^[K], YYcalc^[K], B, D); for I := Lbound to Ubound do begin WD := WW^[K] * D^[I]; G^[I] := G^[I] - WD * R; for J := I to Ubound do H^[I]^[J] := H^[I]^[J] + WD * D^[J]; end; end; { Fill in symmetric matrix } for I := Succ(Lbound) to Ubound do for J := Lbound to Pred(I) do H^[I]^[J] := H^[J]^[I]; DelVector(D, Ubound); end; {$F-} function GenNLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; Mode : TRegMode; X, Y, W : PVector; N, Lbound, Ubound, MaxIter : Integer; Tol : Float; B, B_min, B_max : PVector; V : PMatrix) : Integer; { -------------------------------------------------------------------- General nonlinear regression routine -------------------------------------------------------------------- } var F_min : Float; { Value of objective function at minimum } ErrCode : Integer; { Error code } G : PVector; { Gradient vector } H : PMatrix; { Hessian matrix } ObjFunc : TFuncNVar; { Objective function } GradProc : TGradient; { Procedure to compute gradient } HessProc : THessGrad; { Procedure to compute gradient and hessian } begin SetGlobalVar(RegFunc, DerivProc, Mode, X, Y, W, N, Lbound, Ubound, B_min, B_max); case Mode of UNWEIGHTED : begin ObjFunc := {$IFDEF FPK}@{$ENDIF}OLS_ObjFunc; GradProc := {$IFDEF FPK}@{$ENDIF}OLS_Gradient; HessProc := {$IFDEF FPK}@{$ENDIF}OLS_HessGrad; end; WEIGHTED : begin ObjFunc := {$IFDEF FPK}@{$ENDIF}WLS_ObjFunc; GradProc := {$IFDEF FPK}@{$ENDIF}WLS_Gradient; HessProc := {$IFDEF FPK}@{$ENDIF}WLS_HessGrad; end; end; case OptAlgo of NL_MARQ : ErrCode := Marquardt(ObjFunc, HessProc, B, Lbound, Ubound, MaxIter, Tol, F_min, V); NL_SIMP : ErrCode := Simplex(ObjFunc, B, Lbound, Ubound, MaxIter, Tol, F_min); NL_BFGS : ErrCode := BFGS(ObjFunc, GradProc, B, Lbound, Ubound, MaxIter, Tol, F_min, V); NL_SA : ErrCode := SimAnn(ObjFunc, B, B_min, B_max, Lbound, Ubound, MaxIter, Tol, F_min); end; if (OptAlgo <> NL_MARQ) and (OptAlgo <> NL_BFGS) and (ErrCode = OPT_OK) then begin { Compute the Hessian matrix and its inverse } DimVector(G, Ubound); DimMatrix(H, Ubound, Ubound); case Mode of UNWEIGHTED : OLS_HessGrad(ObjFunc, B, Lbound, Ubound, G, H); WEIGHTED : WLS_HessGrad(ObjFunc, B, Lbound, Ubound, G, H); end; if InvMat(H, Lbound, Ubound, V) = 0 then ErrCode := OPT_OK else ErrCode := OPT_SING; DelVector(G, Ubound); DelMatrix(H, Ubound, Ubound); end; GenNLFit := ErrCode; end; function NLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y : PVector; N, Lbound, Ubound, MaxIter : Integer; Tol : Float; B, B_min, B_max : PVector; V : PMatrix) : Integer; var W : PVector; begin NLFit := GenNLFit(RegFunc, DerivProc, UNWEIGHTED, X, Y, W, N, Lbound, Ubound, MaxIter, Tol, B, B_min, B_max, V); end; function WNLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y, W : PVector; N, Lbound, Ubound, MaxIter : Integer; Tol : Float; B, B_min, B_max : PVector; V : PMatrix) : Integer; begin WNLFit := GenNLFit(RegFunc, DerivProc, WEIGHTED, X, Y, W, N, Lbound, Ubound, MaxIter, Tol, B, B_min, B_max, V); end; procedure GenRegTest(Mode : TRegMode; Y, Ycalc, W : PVector; N, Lbound, Ubound : Integer; V : PMatrix; var Test : TRegTest); var Ybar : Float; { Average Y value } SSt : Float; { Total sum of squares } SSe : Float; { Explained sum of squares } SSr : Float; { Residual sum of squares } Nobs : Integer; { Number of observations } Npar : Integer; { Number of fitted parameters } Nu1, Nu2 : Integer; { Degrees of freedom } I, J : Integer; { Loop variables } begin Nobs := N - FirstPoint + 1; Npar := Ubound - Lbound + 1; with Test do if Nobs > Npar then begin Ybar := Average(Y, FirstPoint, N); if Mode = UNWEIGHTED then begin SSt := SumSqrDif(Y, FirstPoint, N, Ybar); SSe := SumSqrDif(Ycalc, FirstPoint, N, Ybar); SSr := SumSqrDifVect(Y, Ycalc, FirstPoint, N); end else begin SSt := SumWSqrDif(Y, W, FirstPoint, N, Ybar); SSe := SumWSqrDif(Ycalc, W, FirstPoint, N, Ybar); SSr := SumWSqrDifVect(Y, Ycalc, W, FirstPoint, N); end; Nu1 := Npar - 1; Nu2 := Nobs - Npar; if (SSt = 0) or (Nu2=0) then begin //showmessage('Error: are all you data points in the same plane?'); exit; end; R2 := SSe / SSt; R2a := 1.0 - (1.0 - R2) * (Nobs - 1) / Nu2; Vr := SSr / Nu2; if (Vr > 0.0) and (Nu1 > 0.0) then begin F := (SSe / Nu1) / Vr; Prob := PSnedecor(Nu1, Nu2, F); end else begin F := MAXNUM; Prob := 0.0; end; end else begin Vr := 0.0; R2 := 1.0; R2a := 0.0; F := 0.0; Prob := 1.0; end; { Compute variance-covariance matrix } for I := Lbound to Ubound do for J := I to Ubound do V^[I]^[J] := V^[I]^[J] * Test.Vr; for I := Succ(Lbound) to Ubound do for J := Lbound to Pred(I) do V^[I]^[J] := V^[J]^[I]; end; procedure RegTest(Y, Ycalc : PVector; N, Lbound, Ubound : Integer; V : PMatrix; var Test : TRegTest); var W : PVector; begin GenRegTest(UNWEIGHTED, Y, Ycalc, W, N, Lbound, Ubound, V, Test); end; procedure WRegTest(Y, Ycalc, W : PVector; N, Lbound, Ubound : Integer; V : PMatrix; var Test : TRegTest); begin GenRegTest(WEIGHTED, Y, Ycalc, W, N, Lbound, Ubound, V, Test); end; procedure ParamTest(B : PVector; V : PMatrix; N, Lbound, Ubound : Integer; S, T, Prob : PVector); var I : Integer; Nu : Integer; { Degrees of freedom } Nobs : Integer; { Number of observations } Nvar : Integer; { Number of indep. variables } begin Nobs := N - FirstPoint + 1; Nvar := Ubound - Lbound + 1; Nu := Nobs - Nvar; { DoF = Nb points - Nb parameters } for I := Lbound to Ubound do if V^[I]^[I] > 0.0 then begin S^[I] := Sqrt(V^[I]^[I]); T^[I] := B^[I] / S^[I]; Prob^[I] := PStudent(Nu, T^[I]); end else begin S^[I] := 0.0; T^[I] := 0.0; Prob^[I] := 1.0; end; end; procedure VecMean(X : PMatrix; N, Lbound, Ubound : Integer; M : PVector); var I, K, Nobs : Integer; Sum : Float; begin Nobs := N - FirstPoint + 1; for I := Lbound to Ubound do begin Sum := 0.0; for K := FirstPoint to N do Sum := Sum + X^[I]^[K]; M^[I] := Sum / Nobs; end; end; procedure VecSD(X : PMatrix; N, Lbound, Ubound : Integer; M, S : PVector); var I, K, Nobs : Integer; Sum : Float; begin Nobs := N - FirstPoint + 1; for I := Lbound to Ubound do begin Sum := 0.0; for K := FirstPoint to N do Sum := Sum + Sqr(X^[I]^[K] - M^[I]); S^[I] := Sqrt(Sum / Nobs); end; end; procedure MatVarCov(X : PMatrix; N, Lbound, Ubound : Integer; M : PVector; V : PMatrix); var I, J, K, Nobs : Integer; Sum : Float; begin Nobs := N - FirstPoint + 1; for I := Lbound to Ubound do for J := I to Ubound do begin Sum := 0.0; for K := FirstPoint to N do Sum := Sum + (X^[I]^[K] - M^[I]) * (X^[J]^[K] - M^[J]); V^[I]^[J] := Sum / Nobs; end; for I := Succ(Lbound) to Ubound do for J := Lbound to Pred(I) do V^[I]^[J] := V^[J]^[I]; end; procedure MatCorrel(V : PMatrix; Lbound, Ubound : Integer; R : PMatrix); var I, J : Integer; begin for I := Lbound to Ubound do begin R^[I]^[I] := 1.0; for J := Succ(I) to Ubound do begin R^[I]^[J] := V^[I]^[J] / Sqrt(V^[I]^[I] * V^[J]^[J]); R^[J]^[I] := R^[I]^[J]; end; end; end; function PCA(R : PMatrix; Lbound, Ubound : Integer; Lambda : PVector; C, Rc : PMatrix) : Integer; var I, J, ErrCode : Integer; Rac : Float; begin { Compute eigenvalues and eigenvectors of correlation matrix } ErrCode := Jacobi(R, Lbound, Ubound, PCA_MAXITER, PCA_TOL, C, Lambda); if ErrCode <> 0 then begin PCA := ErrCode; Exit; end; { Compute correlations between principal factors and reduced variables } for I := Lbound to Ubound do begin Rac := Sqrt(Lambda^[I]); for J := Lbound to Ubound do Rc^[I]^[J] := C^[I]^[J] * Rac; end; PCA := ErrCode; end; procedure ScaleVar(X : PMatrix; N, Lbound, Ubound : Integer; M, S : PVector; Z : PMatrix); var I, K : Integer; begin for I := Lbound to Ubound do for K := FirstPoint to N do Z^[I]^[K] := (X^[I]^[K] - M^[I]) / S^[I]; end; procedure PrinFac(Z : PMatrix; N, Lbound, Ubound : Integer; C, F : PMatrix); var I, J, K : Integer; begin for I := Lbound to Ubound do for K := FirstPoint to N do begin F^[I]^[K] := 0.0; for J := Lbound to Ubound do F^[I]^[K] := F^[I]^[K] + C^[I]^[J] * Z^[J]^[K]; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/mathp2.inc�����������������������������������������0000755�0001750�0001750�00000070025�07140473620�021154� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * MATHP2.INC * ********************************************************************** Mathematical functions for TPMATH (Assembler version for Pentium II/III with FPC) ********************************************************************** } { Bibliotheque mathematique pour utilisation du coprocesseur flottant JD GAYRARD Sept. 95 ---------------------------------------------------------------------- Unite d'origine : MATH387.PAS, disponible dans MATHLIB2.ZIP (http://wcarchive.cdrom.com/pub/delphi_www/) Adapte aux pentiums II/III et complete par P. NOGARET (2000) ---------------------------------------------------------------------- } {***********************************************************************} {* function fexp(x : Float): Float;assembler; *} {***********************************************************************} {* Fonction dveloppe partir du document de Agner Fog *} {* www.agner.org/assem *} {***********************************************************************} {* retourne e^x, par la methode e^x = 2^(x.log2(e)) *} {* 2^z = 2^f.2^i avec f = frac(z) and i = int(z) *} {* 2^f is computed with F2XM1, *} {* 2^i pourrait tre calcul avec FSCALE mais cette instruction *} {* est trs lente 56 micro-ops sur un pentium II *} {* pour la mthode utilis pour calculer 2^i voir Agner Fog *} {***********************************************************************} {* st(0) st(1) *} {* log2(e) - *} {* x log2(e) *} {* z:=x.log2(e) - *} {* z - *} {* z - round(z) - *} {* 2^(z - round(z)) - 1 - *} {* 1 2^(z - round(z)) - 1 *} {* 2^(z - round(z)) - *} {* temp:=2^i 2^f:=2^(z - round(z)) *} {* e^x - *} {***********************************************************************} function fexp(x : Float): Float;assembler; var round_z : dword; temp : extended; asm FLDL2E FLD x FMULP FIST round_z MOV DWORD PTR [temp], 00000000H MOV DWORD PTR [temp+4],80000000H FISUB round_z MOV EAX, round_z ADD EAX, 00003FFFH MOV DWORD PTR [temp+8],EAX F2XM1 FLD1 FADDP FLD TBYTE PTR [temp] FMULP end ['eax']; {***********************************************************************} {* function fexp2(x : Float): Float; assembler; *} {***********************************************************************} {* Fonction dveloppe partir du document de Agner Fog *} {* www.agner.org/assem *} {***********************************************************************} {* retourne 2^x par la methode 2^z = 2^f.2^i *} {* avec f = frac(z) and i = int(z) *} {* 2^f is computed with F2XM1, *} {* 2^i pourrait tre calcul avec FSCALE mais cette instruction *} {* est trs lente 56 micro-ops sur un pentium II *} {* pour la mthode utilis pour calculer 2^i voir Agner Fog *} {***********************************************************************} {* st(0) st(1) *} {* x - *} {* z:=x - *} {* z - *} {* z - round(z) - *} {* 2^(z - round(z)) - 1 - *} {* 1 2^(z - round(z)) - 1 *} {* 2^(z - round(z)) - *} {* temp:=2^i 2^f:=2^(z - round(z)) *} {* e^x - *} {***********************************************************************} function fexp2(x : Float): Float; assembler; var round_z : dword; temp : extended; asm FLD x FIST round_z MOV DWORD PTR [temp], 00000000H MOV DWORD PTR [temp+4],80000000H FISUB round_z MOV EAX, round_z { round_zmax := 16384 } ADD EAX, 00003FFFH MOV DWORD PTR [temp+8],EAX F2XM1 FLD1 FADDP FLD TBYTE PTR [temp] FMULP end ['EAX']; {***********************************************************************} {* function fexp10(x : Float): Float; assembler; *} {***********************************************************************} {* Fonction dveloppe partir du document de Agner Fog *} {* www.agner.org/assem *} {***********************************************************************} {* retourne 10^x, par la methode 10^x = 2^(x.log2(10)) *} {* 2^z = 2^f.2^i with f = frac(z) and i = int(z) *} {* 2^f is computed with F2XM1 *} {* 2^i pourrait tre calcul avec FSCALE mais cette instruction *} {* est trs lente 56 micro-ops sur un pentium II *} {* pour la mthode utilis pour calculer 2^i voir Agner Fog *} {***********************************************************************} {* st(0) st(1) *} {* log2(10) - *} {* x log2(10) *} {* z:=x.log2(10) - *} {* z - *} {* z - round(z) - *} {* 2^(z - round(z)) - 1 - *} {* 1 2^(z - round(z)) - 1 *} {* 2^(z - round(z)) - *} {* temp:=2^i 2^f:=2^(z - round(z)) *} {* 10^x - *} {***********************************************************************} function fexp10(x : Float): Float; assembler; var round_z : dword; temp : extended; asm FLDL2T FLD X FMULP FIST round_z MOV DWORD PTR [temp], 00000000H MOV DWORD PTR [temp+4],80000000H FISUB round_z MOV EAX, round_z ADD EAX, 00003FFFH MOV DWORD PTR [temp+8],EAX F2XM1 FLD1 FADDP FLD TBYTE PTR [temp] FMULP end ['EAX']; function fln(x : Float): Float; assembler; { retourne le logarithme naturel de x, utilise la methode loge(x) = loge(2).log2(x) } { pas de verification du domaine de definition (x < 0) } asm { ST(0) ST(1) } FLDLN2 { ln(2) - } FLD X { x ln(2) } FYL2X { ln(2).log2(x) - } end; function flog2(x : Float): Float; assembler; { retourne le logarithme de base 2 de x } { pas de verification du domaine de definition (x < 0) } asm { ST(0) ST(1) } FLD1 { 1 - } FLD X { x 1 } FYL2X { log2(x) - } end; {***********************************************************************} {* function flog10(X : Float) : Float; *} {***********************************************************************} {* Compute a common (base 10) logarithm. If X is near 1.0, then we *} {* use the FYL2XP1 instruction instead of FYL2X. "Near" means between *} {* 1.0 and 1+Sqrt(2)/2. We use an approximation for Sqrt(2)/2, so we *} {* don't have to compute it. The exact value isn't important, since *} {* FYL2X works fine for values near the transition. *} {***********************************************************************} function flog10(x : Float): Float; assembler; const HalfSqrt2p1: Extended = 1.7071; asm fldlg2 { push Log2 } fld X { push X } fld1 { push 1.0 } fcomp ST(1) { if (X < 1.0) } jl @@1 { goto @@1 } fld HalfSqrt2p1 { push 1.707 } fcomp ST(1) { if (X > 1.707) } jg @@1 { goto @@1 } fld1 { X is small, so subtract 1.0 } fsubrp { X := X - 1.0 } fyl2xp1 { Log10(2) * Log2(X+1) } jmp @@2 @@1: { X is not near 1.0 } fyl2x { Log10(2) * Log2(X) } @@2: end; {***********************************************************************} {* function fsin(X : Float) : Float; *} {***********************************************************************} {* if x < pi.2^62, then C2 is set to 0 and ST = sin(x) *} {* else C2 is set to 1 and ST = x *} {* no check range validity is performed in this function *} {***********************************************************************} function fsin(X : Float) : Float; assembler; asm FLD x fsin end; {***********************************************************************} {* function fcos(X : Float) : Float; *} {***********************************************************************} function fcos(X : Float) : Float; assembler; asm FLD x fcos end; {***********************************************************************} {* function ftan(X : Float) : Float;assembler; *} {***********************************************************************} function ftan(X : Float) : Float; assembler; asm { ST(0) ST(1) } FLD x { x - } FPTAN { 1 tan(x) } FSTP ST(0) { tan(x) - } end; {***********************************************************************} {* function farctan(X : Float) : Float; *} {***********************************************************************} function farctan(x : Float): Float; assembler; asm { ST(0) ST(1) } FLD x { x - } FLD1 { 1 x } FPATAN { atan(x/1) - } end; {***********************************************************************} {* function farctan2(Y, X : Float) : Float; *} {***********************************************************************} function farctan2(y, x : Float): Float; assembler; { retourne arctan (y / x) } asm { ST(0) ST(1) } FLD y { y - } FLD x { x y } FPATAN { atan(y/x) - } end; {***********************************************************************} {* function farcsin(X : Float) : Float; *} {***********************************************************************} {* retourne l'arcsin de x *} {* methode : ________ *} {* arcsin(x) = arctan( x / V 1 - x.x ) *} {* no range validity check is performed in this function |x| > 1 *} {***********************************************************************} {* ST(0) ST(1) ST(2) *} {* x - - *} {* x x - *} {* x.x x - *} {* 1 x.x x *} {* 1 - x x - *} {* sqrt(1-x) x - *} {* arcsin(x) - - *} {***********************************************************************} function farcsin(x : Float): Float; assembler; asm FLD X FLD ST(0) FMUL ST(0), ST FLD1 FSUBRP ST(1), ST FSQRT FPATAN end; {***********************************************************************} {* function farccos(x : Float): Float; assembler; *} {***********************************************************************} {* retourne l'arccos de x *} {* methode : ________ *} {* arccos(x) = arctan( V 1 - x.x / x) *} {* pas de controle de domaine de definition |x| > 1 *} {***********************************************************************} {* ST(0) ST(1) ST(2) *} {* x - - *} {* x x - *} {* x.x x - *} {* 1 x.x x *} {* 1 - x x - *} {* sqrt(1-x) x - *} {* x z - *} {* arccos(x) - - *} {***********************************************************************} function farccos(x : Float): Float; assembler; asm FLD X FLD ST(0) FMUL ST(0), ST FLD1 FSUBRP ST(1), ST FSQRT FXCH FPATAN end; {***********************************************************************} {* function fsinh(X : Float) : Float; *} {***********************************************************************} {* retourne le sinus hyperbolique de l'argument *} {* sh(x) = [exp(x) - exp(-x)] / 2 *} {* methode : z = exp(x), ch(x) = 1/2 (z - 1/z) *} {* z = 2^y, y = x.log2(e), *} {* z = 2^f.2^i, f = frac(y), i = int(y) *} {* 2^f est calcul avec F2XM1, 2^i sans FSCALE *} {***********************************************************************} {* ST(0) ST(1) ST(2) *} {* log2(e) - - *} {* x log2(e) - *} {* z:=x.log2(e) - - *} {* z - - *} {* z - round(z) - - *} {* 2^(z - round(z)) - 1 - - *} {* 1 2^(z - round(z)) - 1 - *} {* 2^(z - round(z)) - - *} {* temp:=2^i 2^f:=2^(z - round(z)) - *} {* e^x - - *} {* e^x e^x - *} {* 1 z z *} {* 1/z z - *} {* z-1/z - - *} {* 0.5 z-1/z - *} {* sh(x) - - *} {***********************************************************************} function fsinh(x : float): float; assembler; const one_half : float = 0.5; var round_z : dword; temp : extended; asm FLDL2E FLD x FMULP FIST round_z MOV DWORD PTR [temp], 00000000H MOV DWORD PTR [temp+4],80000000H FISUB round_z MOV EAX, round_z ADD EAX, 00003FFFH MOV DWORD PTR [temp+8],EAX F2XM1 FLD1 FADDP FLD TBYTE PTR [temp] FMULP FST ST(1) FLD1 FDIVRP ST(1), ST FSUBP ST(1), ST FLD one_half FMULP ST(1), ST end; {***********************************************************************} {* function fcosh(X : Float) : Float; *} {***********************************************************************} {* retourne le cosinus hyperbolique de l'argument *} {* ch(x) = [exp(x) + exp(-x)] / 2 *} {* methode : z = exp(x), ch(x) = 1/2 (z + 1/z) *} {* z = 2^y, y = x.log2(e), *} {* z = 2^f.2^i, f = frac(y), i = int(y) *} {* 2^f est calcul avec F2XM1, 2^i sans FSCALE *} {***********************************************************************} {* st(0) st(1) st(2) *} {* log2(e) - *} {* x log2(e) *} {* z:=x.log2(e) - *} {* z - *} {* z - round(z) - *} {* 2^(z - round(z)) - 1 - *} {* 1 2^(z - round(z)) - 1 *} {* 2^(z - round(z)) - *} {* temp:=2^i 2^f:=2^(z - round(z)) *} {* e^x - *} {* e^x e^x - *} {* 1 z z *} {* 1/z z - *} {* z+1/z - - *} {* 0.5 z+1/z - *} {* ch(x) - - *} {***********************************************************************} function fcosh(x : float): float; assembler; const one_half : float = 0.5; var round_z : dword; temp : extended; asm FLDL2E FLD x FMULP FIST round_z MOV DWORD PTR [temp], 00000000H MOV DWORD PTR [temp+4],80000000H FISUB round_z MOV EAX, round_z ADD EAX, 00003FFFH MOV DWORD PTR [temp+8],EAX F2XM1 FLD1 FADDP FLD TBYTE PTR [temp] FMULP FST ST(1) FLD1 FDIVRP ST(1), ST FADDP ST(1), ST FLD one_half FMULP ST(1), ST end; {***********************************************************************} {* function ftanh(X : Float) : Float; *} {***********************************************************************} {* retourne la tangente hyperbolique de l'argument *} {* th(x) = sh(x) / ch(x) *) *} {* th(x) = [exp(x) - exp(-x)] / [exp(x) + exp(-x)] *} {* methode : z = exp(x), ch(x) = (z - 1/z) / (z + 1/z) *} {* z = 2^y, y = x.log2(e), *} {* z = 2^f.2^i, f = frac(y), i = int(y) *} {* 2^f est calcul avec F2XM1, 2^i sans FSCALE *} {***********************************************************************} {* st(0) st(1) st(2) *} {* log2(e) - *} {* x log2(e) *} {* z:=x.log2(e) - *} {* z - *} {* z - round(z) - *} {* 2^(z - round(z)) - 1 - *} {* 1 2^(z - round(z)) - 1 *} {* 2^(z - round(z)) - *} {* temp:=2^i 2^f:=2^(z - round(z)) *} {* e^x - *} {* e^x e^x - *} {* 1 z z *} {* 1/z z z *} {* 1/z z z-1/z *} {* z+1/z z-1/z - *} {* th(x) - - *} {***********************************************************************} function ftanh(x : float): float; assembler; const one_half : float = 0.5; var round_z : dword; temp : extended; asm FLDL2E FLD x FMULP FIST round_z MOV DWORD PTR [temp], 00000000H MOV DWORD PTR [temp+4],80000000H FISUB round_z MOV EAX, round_z ADD EAX, 00003FFFH MOV DWORD PTR [temp+8],EAX F2XM1 FLD1 FADDP FLD TBYTE PTR [temp] FMULP FST ST(1) FLD1 FDIV ST, ST(1) FSUB ST(2), ST FADDP ST(1), ST FDIVP ST(1), ST end; {***********************************************************************} {* function farcsinh(X : Float) : Float; *} {***********************************************************************} {* retourne l'arc sinus hyperbolique de l'argument *} {* _________ *} {* arg sh(x) = ln ( x + V x.x + 1 ) *} {***********************************************************************} {* ST(0) ST(1) ST(2) ST(3) *} {* ln(2) - - - *} {* x ln(2) - - *} {* x x ln(2) - *} {* x.x x ln(2) - *} {* 1 x.x x ln(2) *} {* x.x + 1 x ln(2) - *} {* sqrt(x.x+1) x ln(2) - *} {* x + z ln(2) - - *} {* arg_sh(x) - - - *} {***********************************************************************} function farcsinh(x : float): float; assembler; asm FLDLN2 FLD X FLD ST(0) FMUL ST(0), ST FLD1 FADDP ST(1), ST FSQRT FADDP ST(1), ST FYL2X end; {***********************************************************************} {* function farccosh(X : Float) : Float; *} {***********************************************************************} {* retourne l'arc cosinus hyperbolique de l'argument *} {* ________ *} {* arg ch(x) = ln ( x + V x.x - 1 ) x >=1 *} {***********************************************************************} {* ST(0) ST(1) ST(2) ST(3) *} {* ln(2) - - - *} {* x ln(2) - - *} {* x x ln(2) - *} {* x.x x ln(2) - *} {* 1 x.x x ln(2) *} {* x.x - 1 x ln(2) - *} {* sqrt(x2-1) x ln(2) - *} {* x + z ln(2) - - *} {* arg_ch(x) - - - *} {***********************************************************************} function farccosh(x : float): float; assembler; asm FLDLN2 FLD X FLD ST(0) FMUL ST(0), ST FLD1 FSUBP ST(1), ST FSQRT FADDP ST(1), ST FYL2X end; {***********************************************************************} {* function farctanh(X : Float) : Float; *} {***********************************************************************} {* retourne l'arc tangente hyperbolique de l'argument *} {* arg th(x) = 1/2 ln [ (1 + x) / (1 - x) ] *} {***********************************************************************} {* ST(0) ST(1) ST(2) ST(3) *} {* ln(2) - - - *} {* x ln(2) - - *} {* x x ln(2) - *} {* 1 x x ln(2) *} {* 1 x 1 + x ln(2) *} {* 1 - x 1 + x ln(2) - *} {* 1+x/1-x ln(2) - - *} {* ln(z) - - - *} {***********************************************************************} function farctanh(x : float): float; assembler; asm FLDLN2 FLD X FLD ST(0) FLD1 FADD ST(2),ST FSUBRP ST(1),ST FDIVP ST(1),ST FYL2X end; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/fourier.pas����������������������������������������0000755�0001750�0001750�00000025437�11326425446�021461� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(*========================================================================== fourier.pas - Don Cross <dcross@intersrv.com> Modified by Jean Debord <JDebord@compuserve.com> for use with TP Math. This is a Turbo Pascal Unit for calculating the Fast Fourier Transform (FFT) and the Inverse Fast Fourier Transform (IFFT). Visit the following URL for the latest version of this code. This page also has a C/C++ version, and a brief discussion of the theory behind the FFT algorithm. http://www.intersrv.com/~dcross/fft.html#pascal Revision history [most recent first]: 1998 November 27 [Jean Debord] Replaced the constant MAXPOWER by a variable which is initialized according to the value of MAX_FLT defined in MATRICES.PAS 1997 March 1 [Jean Debord] Modifications for use with the TP Math library: 1. Added a USES clause for the TP Math units. 2. Set real type to Float (defined in FMATH.PAS) 3. Added a constant MAXPOWER to define the maximum number of points. Modified functions IsPowerOfTwo and NumberOfBitsNeeded accordingly. 4. Changed array types to those defined in TP Math. Modified array allocation, deallocation and reference accordingly. 5. Removed compiler directives, which were no longer necessary. 6. Modified some typographical and formatting options so that the code looks like the other TP Math units. No modification was made to the original algorithm. 1996 December 11 [Don Cross] Improved documentation of the procedure CalcFrequency. Fixed some messed up comments in procedure IFFT. 1996 December 6 [Don Cross] Made procedure 'fft_integer' more efficient when buffer size changes in successive calls: the buffer is now only resized when the input has more samples, not a differing number of samples. Also changed the way 'fft_integer_cleanup' works so that it is more "bullet-proof". 1996 December 4 [Don Cross] Adding the procedure 'CalcFrequency', which calculates the FFT at a specific frequency index p=0..n-1, instead of the whole FFT. This is O(n^2) instead of O(n*log(n)). 1996 November 30 [Don Cross] Adding a routine to allow FFT of an input array of integers. It is called 'fft_integer'. 1996 November 18 [Don Cross] Added some comments. 1996 November 17 [Don Cross] Wrote and debugged first version. ==========================================================================*) unit Fourier; interface uses FMath, Matrices; (*--------------------------------------------------------------------------- procedure FFT Calculates the Fast Fourier Transform of the array of complex numbers represented by 'RealIn' and 'ImagIn' to produce the output complex numbers in 'RealOut' and 'ImagOut'. ---------------------------------------------------------------------------*) procedure FFT(NumSamples : Integer; RealIn, ImagIn, RealOut, ImagOut : PVector); (*--------------------------------------------------------------------------- procedure IFFT Calculates the Inverse Fast Fourier Transform of the array of complex numbers represented by 'RealIn' and 'ImagIn' to produce the output complex numbers in 'RealOut' and 'ImagOut'. ---------------------------------------------------------------------------*) procedure IFFT(NumSamples : Integer; RealIn, ImagIn, RealOut, ImagOut : PVector); (*--------------------------------------------------------------------------- procedure FFT_Integer Same as procedure FFT, but uses Integer input arrays instead of double. Make sure you call FFT_Integer_Cleanup after the last time you call FFT_Integer to free up memory it allocates. ---------------------------------------------------------------------------*) procedure FFT_Integer(NumSamples : Integer; RealIn, ImagIn : PIntVector; RealOut, ImagOut : PVector); (*-------------------------------------------------------------------------- procedure FFT_Integer_Cleanup If you call the procedure 'FFT_Integer', you must call 'FFT_Integer_Cleanup' after the last time you call 'FFT_Integer' in order to free up dynamic memory. --------------------------------------------------------------------------*) procedure FFT_Integer_Cleanup; (*-------------------------------------------------------------------------- procedure CalcFrequency This procedure calculates the complex frequency sample at a given index directly. Use this instead of 'FFT' when you only need one or two frequency samples, not the whole spectrum. It is also useful for calculating the Discrete Fourier Transform (DFT) of a number of data which is not an integer power of 2. For example, you could calculate the DFT of 100 points instead of rounding up to 128 and padding the extra 28 array slots with zeroes. --------------------------------------------------------------------------*) procedure CalcFrequency(NumSamples, FrequencyIndex : Integer; RealIn, ImagIn : PVector; var RealOut, ImagOut : Float); implementation var MaxPower : Integer; function IsPowerOfTwo(X : Integer) : Boolean; var I, Y : Integer; begin Y := 2; for I := 1 to Pred(MaxPower) do begin if X = Y then begin IsPowerOfTwo := True; Exit; end; Y := Y shl 1; end; IsPowerOfTwo := False; end; function NumberOfBitsNeeded(PowerOfTwo : Integer) : Integer; var I : Integer; begin for I := 0 to MaxPower do begin if (PowerOfTwo and (1 shl I)) <> 0 then begin NumberOfBitsNeeded := I; Exit; end; end; end; function ReverseBits(Index, NumBits : Integer) : Integer; var I, Rev : Integer; begin Rev := 0; for I := 0 to NumBits - 1 do begin Rev := (Rev shl 1) or (Index and 1); Index := Index shr 1; end; ReverseBits := Rev; end; procedure FourierTransform(AngleNumerator : Float; NumSamples : Integer; RealIn, ImagIn, RealOut, ImagOut : PVector); var NumBits, I, J, K, N, BlockSize, BlockEnd : Integer; Delta_angle, Delta_ar : Float; Alpha, Beta : Float; Tr, Ti, Ar, Ai : Float; begin if not IsPowerOfTwo(NumSamples) or (NumSamples < 2) then begin Write('Error in procedure Fourier: NumSamples=', NumSamples); WriteLn(' is not a positive integer power of 2.'); Halt; end; NumBits := NumberOfBitsNeeded(NumSamples); for I := 0 to NumSamples - 1 do begin J := ReverseBits(I, NumBits); RealOut^[J] := RealIn^[I]; ImagOut^[J] := ImagIn^[I]; end; BlockEnd := 1; BlockSize := 2; while BlockSize <= NumSamples do begin Delta_angle := AngleNumerator / BlockSize; Alpha := Sin(0.5 * Delta_angle); Alpha := 2.0 * Alpha * Alpha; Beta := Sin(Delta_angle); I := 0; while I < NumSamples do begin Ar := 1.0; (* cos(0) *) Ai := 0.0; (* sin(0) *) J := I; for N := 0 to BlockEnd - 1 do begin K := J + BlockEnd; Tr := Ar * RealOut^[K] - Ai * ImagOut^[K]; Ti := Ar * ImagOut^[K] + Ai * RealOut^[K]; RealOut^[K] := RealOut^[J] - Tr; ImagOut^[K] := ImagOut^[J] - Ti; RealOut^[J] := RealOut^[J] + Tr; ImagOut^[J] := ImagOut^[J] + Ti; Delta_ar := Alpha * Ar + Beta * Ai; Ai := Ai - (Alpha * Ai - Beta * Ar); Ar := Ar - Delta_ar; Inc(J); end; I := I + BlockSize; end; BlockEnd := BlockSize; BlockSize := BlockSize shl 1; end; end; procedure FFT(NumSamples : Integer; RealIn, ImagIn, RealOut, ImagOut : PVector); begin FourierTransform(2 * PI, NumSamples, RealIn, ImagIn, RealOut, ImagOut); end; procedure IFFT(NumSamples : Integer; RealIn, ImagIn, RealOut, ImagOut : PVector); var I : Integer; begin FourierTransform(- 2 * PI, NumSamples, RealIn, ImagIn, RealOut, ImagOut); { Normalize the resulting time samples } for I := 0 to NumSamples - 1 do begin RealOut^[I] := RealOut^[I] / NumSamples; ImagOut^[I] := ImagOut^[I] / NumSamples; end; end; var RealTemp, ImagTemp : PVector; TempArraySize : Integer; procedure FFT_Integer(NumSamples : Integer; RealIn, ImagIn : PIntVector; RealOut, ImagOut : PVector); var I : Integer; begin if NumSamples > TempArraySize then begin FFT_Integer_Cleanup; { free up memory in case we already have some } DimVector(RealTemp, NumSamples); DimVector(ImagTemp, NumSamples); TempArraySize := NumSamples; end; for I := 0 to NumSamples - 1 do begin RealTemp^[I] := RealIn^[I]; ImagTemp^[I] := ImagIn^[I]; end; FourierTransform(2 * PI, NumSamples, RealTemp, ImagTemp, RealOut, ImagOut); end; procedure FFT_Integer_Cleanup; begin if TempArraySize > 0 then begin if RealTemp <> nil then DelVector(RealTemp, TempArraySize); if ImagTemp <> nil then DelVector(ImagTemp, TempArraySize); TempArraySize := 0; end; end; procedure CalcFrequency(NumSamples, FrequencyIndex : Integer; RealIn, ImagIn : PVector; var RealOut, ImagOut : Float); var K : Integer; Cos1, Cos2, Cos3, Theta, Beta : Float; Sin1, Sin2, Sin3 : Float; begin RealOut := 0.0; ImagOut := 0.0; Theta := 2 * PI * FrequencyIndex / NumSamples; Sin1 := Sin(- 2 * Theta); Sin2 := Sin(- Theta); Cos1 := Cos(- 2 * Theta); Cos2 := Cos(- Theta); Beta := 2 * Cos2; for K := 0 to NumSamples - 1 do begin { Update trig values } Sin3 := Beta * Sin2 - Sin1; Sin1 := Sin2; Sin2 := Sin3; Cos3 := Beta * Cos2 - Cos1; Cos1 := Cos2; Cos2 := Cos3; RealOut := RealOut + RealIn^[K] * Cos3 - ImagIn^[K] * Sin3; ImagOut := ImagOut + ImagIn^[K] * Cos3 + RealIn^[K] * Sin3; end; end; begin { Unit initialization code } MaxPower := Trunc(Log2(MAX_FLT)); { Max power of two } TempArraySize := 0; { flag that buffers RealTemp, RealImag not allocated } RealTemp := nil; ImagTemp := nil; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/_clean.bat�����������������������������������������0000755�0001750�0001750�00000000213�10722107550�021163� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������del /S *.~* del /S *.dcu del /S *.dsk del /S *.cfg del /S *.dof del /S *.obj del /S *.hpp del /S *.ddp del /S *.mps del /S *.mpt �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/fitexpo.pas����������������������������������������0000755�0001750�0001750�00000024271�11326425446�021457� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITEXPO.PAS * * Version 1.4 * * (c) J. Debord, August 2000 * ********************************************************************** This unit fits a sum of decreasing exponentials : y = Ymin + A1.exp(-a1.x) + A2.exp(-a2.x) + A3.exp(-a3.x) + ... ********************************************************************** } unit FitExpo; {$F+} interface uses FMath, Matrices, Polynom, Stat, Regress; const NO_REAL_ROOT = - 2; { No real exponent } function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X : Float; B, D : PVector); function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; procedure InitModel(CstPar : PVector); implementation const N_exp : Integer = 1; { Number of exponentials } ConsTerm : Boolean = True; { Flags the presence of a constant term Ymin } function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } var I : Integer; Name, S : String; begin Name := 'y = '; if ConsTerm then Name := Name + 'Ymin + '; Name := Name + 'A1.exp(-a1.x)'; for I := 2 to N_exp do begin Str(I, S); Name := Name + ' + A' + S + '.exp(-a' + S + '.x)'; end; FuncName := Name; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted (0 if there is a constant term Ymin, 1 otherwise) -------------------------------------------------------------------- } begin if ConsTerm then FirstParam := 0 else FirstParam := 1; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 2 * N_exp; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } var S : String; begin if I = 0 then ParamName := 'Ymin' else if Odd(I) then begin Str(Succ(I) div 2, S); ParamName := 'A' + S; end else begin Str(I div 2, S); ParamName := 'a' + S; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = Ymin B^[1] = A1 B^[2] = a1 ............................... B^[2*i-1] = Ai B^[2*i] = ai i = 1..N_exp -------------------------------------------------------------------- } var I : Integer; S : Float; begin if ConsTerm then S := B^[0] else S := 0.0; for I := 1 to N_exp do S := S + B^[2 * I - 1] * Expo(- B^[2 * I] * X); RegFunc := S; end; procedure DerivProc(X : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point X with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter. -------------------------------------------------------------------- } var I, P, Q : Integer; E : Float; begin D^[0] := 1.0; { dy/dYmin = 1 } for I := 1 to N_exp do begin Q := 2 * I; P := Pred(Q); E := Expo(- B^[Q] * X); D^[P] := E; { dy/dAi = exp(-ai.x) } D^[Q] := - X * B^[P] * E; { dy/dai = -x.Ai.exp(-ai.x) } end; end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of a sum of exponentials by linear regression -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- Ref. : R. GOMENI & C. GOMENI, Automod : A polyalgorithm for an integrated analysis of linear pharmacokinetic models Comput. Biol. Med., 1979, 9, 39-48 -------------------------------------------------------------------- } var I, K, M : Integer; X1, Y1 : PVector; { Modified coordinates } U : PMatrix; { Variables for linear regression } P : PVector; { Linear regression parameters } C, Z : PVector; { Coefficients and roots of polynomial } V : PMatrix; { Variance-covariance matrix } H : Float; { Integration step } ErrCode : Integer; { Error code } begin M := Pred(2 * N_exp); DimVector(X1, N); DimVector(Y1, N); DimMatrix(U, M, N); DimMatrix(V, M, M); DimVector(P, M); DimVector(C, N_exp); DimVector(Z, N_exp); CopyVector(X1, X, 1, N); CopyVector(Y1, Y, 1, N); { Change scale so that the X's begin at zero } if X^[1] <> 0.0 then for K := 1 to N do X1^[K] := X1^[K] - X^[1]; { Estimate the constant term at 90% of the lowest observed value, then subtract it from each Y value } if ConsTerm then begin B^[0] := 0.9 * Min(Y1, 1, N); for K := 1 to N do Y1^[K] := Y1^[K] - B^[0]; end; { ------------------------------------------------------------------ Fit the linearized form of the function : y = p(0) + p(1) * x + p(2) * x^2 + ... + p(N_exp-1) * x^(N_exp-1) (x (x (x + p(N_exp) | y dx + ... + p(2*N_exp-1) | ....| y dx )0 )0 )0 ------------------------------------------------------------------ } { Compute increasing powers of X } if N_exp > 1 then for K := 2 to N do begin U^[1]^[K] := X1^[K]; for I := 2 to Pred(N_exp) do U^[I]^[K] := U^[I - 1]^[K] * X1^[K]; end; { Compute integrals by the trapezoidal rule } for K := 2 to N do begin H := 0.5 * (X1^[K] - X1^[K - 1]); U^[N_exp]^[K] := U^[N_exp]^[K - 1] + (Y1^[K] + Y1^[K - 1]) * H; for I := Succ(N_exp) to M do U^[I]^[K] := U^[I]^[K - 1] + (U^[I - 1]^[K] + U^[I - 1]^[K - 1]) * H; end; { Fit the equation } case Method of 0 : ErrCode := MulFit(U, Y1, N, M, True, P, V); 1 : ErrCode := WMulFit(U, Y1, W, N, M, True, P, V); end; if ErrCode = MAT_SINGUL then FitModel := ErrCode else begin { ---------------------------------------------------------------- The exponents are the roots of the polynomial : x^N_exp + p(N_exp) * x^(N_exp-1) - p(N_exp+1) * x^(N_exp-2) +... ---------------------------------------------------------------- } { Compute polynomial coefficients } C^[N_exp] := 1.0; for I := 1 to N_exp do if Odd(I) then C^[N_exp - I] := P^[N_exp + I - 1] else C^[N_exp - I] := - P^[N_exp + I - 1]; { Solve polynomial } if RRootPol(C, N_exp, Z) <> N_exp then FitModel := NO_REAL_ROOT else begin { Sort exponents in decreasing order } DQSort(Z, 1, N_exp); { Compute the coefficients of the exponentials by linear regression on the exponential terms } for I := 1 to N_exp do for K := 1 to N do U^[I]^[K] := Expo(- Z^[I] * X1^[K]); case Method of 0 : ErrCode := MulFit(U, Y1, N, N_exp, False, P, V); 1 : ErrCode := WMulFit(U, Y1, W, N, N_exp, False, P, V); end; if ErrCode = MAT_SINGUL then FitModel := ErrCode else begin { Extract model parameters } for I := 1 to N_exp do begin { Correct for scale change if necessary } if X^[1] <> 0.0 then P^[I] := P^[I] * Expo(Z^[I] * X^[1]); { Extract coefficients and exponents } B^[2 * I - 1] := P^[I]; { Coefficients } B^[2 * I] := Z^[I]; { Exponents } end; FitModel := MAT_OK; end; end; end; DelVector(X1, N); DelVector(Y1, N); DelMatrix(U, M, N); DelMatrix(V, M, M); DelVector(P, M); DelVector(C, N_exp); DelVector(Z, N_exp); end; procedure InitModel(CstPar : PVector); { -------------------------------------------------------------------- Initializes the global variables of the unit -------------------------------------------------------------------- CstPar^[0] = number of exponentials CstPar^[1] = 1 to include a constant term (Ymin) -------------------------------------------------------------------- } var N : Integer; begin N := Round(CstPar^[0]); if N > 0 then N_exp := N; ConsTerm := (CstPar^[1] = 1); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/models.pas�����������������������������������������0000755�0001750�0001750�00000047411�11326425446�021265� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit MODELS.PAS * * Version 1.4 * * (c) J. Debord, August 2000 * ********************************************************************** Library of regression and variance models ********************************************************************** } unit Models; {$F+} interface uses FMath, Matrices, Regress, FitLin, FitMult, FitPoly, FitFrac, FitExpo, FitIExpo, FitExLin, FitPower, FitMich, FitHill, FitLogis, FitPKa; { --------------------------------------------------------------------- Highest index of regression models --------------------------------------------------------------------- } const MAXMODEL = 11; { --------------------------------------------------------------------- Highest index of variance models --------------------------------------------------------------------- } const MAXVARMODEL = 5; { --------------------------------------------------------------------- Definition of regression models --------------------------------------------------------------------- } const REG_LIN = 0; { Linear } REG_MULT = 1; { Multiple linear } REG_POL = 2; { Polynomial } REG_FRAC = 3; { Rational fraction } REG_EXPO = 4; { Sum of exponentials } REG_IEXPO = 5; { Increasing exponential } REG_EXLIN = 6; { Exponential + linear } REG_POWER = 7; { Power } REG_MICH = 8; { Michaelis } REG_HILL = 9; { Hill } REG_LOGIS = 10; { Logistic } REG_PKA = 11; { Acid/Base titration curve } { --------------------------------------------------------------------- Definition of variance models --------------------------------------------------------------------- } const VAR_CONST = 0; { Constant } VAR_LIN = 1; { Linear } VAR_POL2 = 2; { 2nd degree polynomial } VAR_POL3 = 3; { 3rd degree polynomial } VAR_EXPO = 4; { Exponential } VAR_POWER = 5; { Power } { --------------------------------------------------------------------- Names of regression models --------------------------------------------------------------------- } const MODELNAME : array[0..MAXMODEL] of String = {$IFDEF FRENCH} ('Lineaire', 'Lineaire multiple', 'Polynomial', 'Fraction rationnelle', 'Somme d''exponentielles', 'Exponentielle croissante', 'Exponentielle + lineaire', 'Puissance', 'Michaelis', 'Hill', 'Logistique', 'Titrage acide/base'); {$ELSE} ('Linear', 'Multiple linear', 'Polynomial', 'Rational fraction', 'Sum of exponentials', 'Increasing exponential', 'Exponential + linear', 'Power', 'Michaelis', 'Hill', 'Logistic', 'Acid/Base titration curve'); {$ENDIF} { --------------------------------------------------------------------- Names of variance models --------------------------------------------------------------------- } const VARMODELNAME : array[0..MAXVARMODEL] of String = {$IFDEF FRENCH} ('Constante', 'Lineaire', 'Polynome de degre 2', 'Polynome de degre 3', 'Exponentielle', 'Puissance'); {$ELSE} ('Constant', 'Linear', '2nd degree polynomial', '3rd degree polynomial', 'Exponential', 'Power'); {$ENDIF} function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first fitted parameter -------------------------------------------------------------------- } function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last fitted parameter -------------------------------------------------------------------- } function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th fitted parameter -------------------------------------------------------------------- } function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function for one independent variable B is the vector of parameters -------------------------------------------------------------------- } function RegFuncNVar(X, B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function for several independent variables B is the vector of parameters -------------------------------------------------------------------- } procedure DerivProc(RegFunc : TRegFunc; X, Y : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point (X,Y) with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter. -------------------------------------------------------------------- } procedure InitModel(Reg_Model, Var_Model : Integer; CstPar : PVector); { -------------------------------------------------------------------- Initializes the regression and variance models. Constant parameters (e.g. degree of polynomial) are passed in vector CstPar. -------------------------------------------------------------------- } function WLSFit(X : PVector; U : PMatrix; Y : PVector; N : Integer; Init : Boolean; MaxIter : Integer; Tol : Float; Theta, B : PVector; B_min, B_max : PVector; V : PMatrix; Ycalc, S : PVector; var Test : TRegTest) : Integer; { ---------------------------------------------------------------------- Fits the regression function and computes the regression tests ---------------------------------------------------------------------- Input : X, U = vector or matrix of independent variable(s) Y = vector of dependent variable N = number of observations Init = TRUE to compute initial parameter estimates FALSE to use the current values MaxIter = maximum number of iterations (if 0 the parameters will not be refined) Tol = required parameter precision Theta = variance parameters B = initial parameters values B_min, B_max = parameter bounds -------------------------------------------------------------------- Output : Theta = updated variance parameters (residual variance stored in Theta^[0]) B = regression parameters V = variance-covariance matrix Ycalc = estimated Y values S = standard deviations of Y Test = regression tests -------------------------------------------------------------------- Possible results = OPT_OK : no error OPT_SING : singular matrix OPT_BIG_LAMBDA : too high Marquardt's parameter OPT_NON_CONV : non-convergence -------------------------------------------------------------------- } function VarFuncName : String; { -------------------------------------------------------------------- Returns the name of the variance function -------------------------------------------------------------------- } function LastVarParam : Integer; { ---------------------------------------------------------------------- Returns the index of the last variance parameter (upper bound of Theta) ---------------------------------------------------------------------- } function VarFunc(Y : Float; Theta : PVector) : Float; { -------------------------------------------------------------------- Computes the variance of an observation Y. The parameters are Theta^[1], Theta^[2],... The true variance is Theta^[0] * VarFunc, where Theta^[0] (equal to the residual variance Vr) is estimated by the regression program. -------------------------------------------------------------------- } implementation const RegModel : Integer = 0; { Index of regression model } VarModel : Integer = 0; { Index of variance model } function FuncName : String; begin case RegModel of REG_LIN : FuncName := FitLin.FuncName; REG_MULT : FuncName := FitMult.FuncName; REG_POL : FuncName := FitPoly.FuncName; REG_FRAC : FuncName := FitFrac.FuncName; REG_EXPO : FuncName := FitExpo.FuncName; REG_IEXPO : FuncName := FitIExpo.FuncName; REG_EXLIN : FuncName := FitExLin.FuncName; REG_POWER : FuncName := FitPower.FuncName; REG_MICH : FuncName := FitMich.FuncName; REG_HILL : FuncName := FitHill.FuncName; REG_LOGIS : FuncName := FitLogis.FuncName; REG_PKA : FuncName := FitPKa.FuncName; end; end; function FirstParam : Integer; begin case RegModel of REG_LIN : FirstParam := FitLin.FirstParam; REG_MULT : FirstParam := FitMult.FirstParam; REG_POL : FirstParam := FitPoly.FirstParam; REG_FRAC : FirstParam := FitFrac.FirstParam; REG_EXPO : FirstParam := FitExpo.FirstParam; REG_IEXPO : FirstParam := FitIExpo.FirstParam; REG_EXLIN : FirstParam := FitExLin.FirstParam; REG_POWER : FirstParam := FitPower.FirstParam; REG_MICH : FirstParam := FitMich.FirstParam; REG_HILL : FirstParam := FitHill.FirstParam; REG_LOGIS : FirstParam := FitLogis.FirstParam; REG_PKA : FirstParam := FitPKa.FirstParam; end; end; function LastParam : Integer; begin case RegModel of REG_LIN : LastParam := FitLin.LastParam; REG_MULT : LastParam := FitMult.LastParam; REG_POL : LastParam := FitPoly.LastParam; REG_FRAC : LastParam := FitFrac.LastParam; REG_EXPO : LastParam := FitExpo.LastParam; REG_IEXPO : LastParam := FitIExpo.LastParam; REG_EXLIN : LastParam := FitExLin.LastParam; REG_POWER : LastParam := FitPower.LastParam; REG_MICH : LastParam := FitMich.LastParam; REG_HILL : LastParam := FitHill.LastParam; REG_LOGIS : LastParam := FitLogis.LastParam; REG_PKA : LastParam := FitPKa.LastParam; end; end; function ParamName(I : Integer) : String; begin case RegModel of REG_LIN : ParamName := FitLin.ParamName(I); REG_MULT : ParamName := FitMult.ParamName(I); REG_POL : ParamName := FitPoly.ParamName(I); REG_FRAC : ParamName := FitFrac.ParamName(I); REG_EXPO : ParamName := FitExpo.ParamName(I); REG_IEXPO : ParamName := FitIExpo.ParamName(I); REG_EXLIN : ParamName := FitExLin.ParamName(I); REG_POWER : ParamName := FitPower.ParamName(I); REG_MICH : ParamName := FitMich.ParamName(I); REG_HILL : ParamName := FitHill.ParamName(I); REG_LOGIS : ParamName := FitLogis.ParamName(I); REG_PKA : ParamName := FitPKa.ParamName(I); end; end; function RegFunc(X : Float; B : PVector) : Float; begin case RegModel of REG_LIN : RegFunc := FitLin.RegFunc(X, B); REG_POL : RegFunc := FitPoly.RegFunc(X, B); REG_FRAC : RegFunc := FitFrac.RegFunc(X, B); REG_EXPO : RegFunc := FitExpo.RegFunc(X, B); REG_IEXPO : RegFunc := FitIExpo.RegFunc(X, B); REG_EXLIN : RegFunc := FitExLin.RegFunc(X, B); REG_POWER : RegFunc := FitPower.RegFunc(X, B); REG_MICH : RegFunc := FitMich.RegFunc(X, B); REG_HILL : RegFunc := FitHill.RegFunc(X, B); REG_LOGIS : RegFunc := FitLogis.RegFunc(X, B); REG_PKA : RegFunc := FitPKa.RegFunc(X, B); end; end; function RegFuncNVar(X, B : PVector) : Float; begin case RegModel of REG_MULT : RegFuncNVar := FitMult.RegFunc(X, B); end; end; procedure DerivProc(RegFunc : TRegFunc; X, Y : Float; B, D : PVector); begin case RegModel of REG_FRAC : FitFrac.DerivProc(X, Y, B, D); REG_EXPO : FitExpo.DerivProc(X, B, D); REG_IEXPO : FitIExpo.DerivProc(X, B, D); REG_EXLIN : FitExLin.DerivProc(X, B, D); REG_POWER : FitPower.DerivProc(X, Y, B, D); REG_MICH : FitMich.DerivProc(X, Y, B, D); REG_HILL : FitHill.DerivProc(X, Y, B, D); REG_LOGIS : FitLogis.DerivProc(X, B, D); REG_PKA : FitPKa.DerivProc(X, B, D); else NumDeriv(RegFunc, X, Y, B, D); end; end; procedure InitModel(Reg_Model, Var_Model : Integer; CstPar : PVector); begin RegModel := Reg_Model; VarModel := Var_Model; case RegModel of REG_MULT : FitMult.InitModel(CstPar); REG_POL : FitPoly.InitModel(CstPar); REG_FRAC : FitFrac.InitModel(CstPar); REG_EXPO : FitExpo.InitModel(CstPar); REG_LOGIS : FitLogis.InitModel(CstPar); end; end; function FitModel(Method : Integer; X : PVector; U : PMatrix; Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; { -------------------------------------------------------------------- Fits the regression model by unweighted linear least squares. For nonlinear models, this is only an approximate fit, to be refined by the nonlinear regression procedure WLSFit -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, U = vector or matrix of independent variable(s) Y = vector of dependent variable W = weights N = number of observations -------------------------------------------------------------------- Output : B = estimated regression parameters V = unscaled variance-covariance matrix (for linear and polynomial models only). The true matrix will be Vr * V, where Vr is the residual variance. -------------------------------------------------------------------- The function returns 0 if no error occurred -------------------------------------------------------------------- } begin case RegModel of REG_LIN : FitModel := FitLin.FitModel(Method, X, Y, W, N, B, V); REG_MULT : FitModel := FitMult.FitModel(Method, U, Y, W, N, B, V); REG_POL : FitModel := FitPoly.FitModel(Method, X, Y, W, N, B, V); REG_FRAC : FitModel := FitFrac.FitModel(Method, X, Y, W, N, B); REG_EXPO : FitModel := FitExpo.FitModel(Method, X, Y, W, N, B); REG_IEXPO : FitModel := FitIExpo.FitModel(Method, X, Y, W, N, B); REG_EXLIN : FitModel := FitExLin.FitModel(X, Y, N, B); REG_POWER : FitModel := FitPower.FitModel(Method, X, Y, W, N, B); REG_MICH : FitModel := FitMich.FitModel(Method, X, Y, W, N, B); REG_HILL : FitModel := FitHill.FitModel(Method, X, Y, W, N, B); REG_LOGIS : FitModel := FitLogis.FitModel(Method, X, Y, W, N, B); REG_PKA : FitModel := FitPKa.FitModel(X, Y, N, B); end; end; function WLSFit(X : PVector; U : PMatrix; Y : PVector; N : Integer; Init : Boolean; MaxIter : Integer; Tol : Float; Theta, B : PVector; B_min, B_max : PVector; V : PMatrix; Ycalc, S : PVector; var Test : TRegTest) : Integer; var Method : Integer; { Regression method } W : PVector; { Weights } Xk : PVector; { Vector of variables for observation k } Sr : Float; { Residual standard deviation } ErrCode : Integer; { Error code } K : Integer; { Loop variable } begin DimVector(W, N); DimVector(Xk, LastParam); { Determine regression method } if VarModel = VAR_CONST then Method := 0 else Method := 1; { Compute weights if necessary } if Method = 1 then for K := 1 to N do W^[K] := 1.0 / VarFunc(Y^[K], Theta); { Compute initial parameter estimates if necessary } if Init then ErrCode := FitModel(Method, X, U, Y, W, N, B, V) else ErrCode := 0; { Refine parameters if necessary } if not(RegModel in [REG_LIN, REG_MULT, REG_POL]) and (MaxIter > 0) and (ErrCode = 0) then if VarModel = VAR_CONST then ErrCode := NLFit({$IFDEF FPK}@{$ENDIF}RegFunc, {$IFDEF FPK}@{$ENDIF}DerivProc, X, Y, N, FirstParam, LastParam, MaxIter, Tol, B, B_min, B_max, V) else ErrCode := WNLFit({$IFDEF FPK}@{$ENDIF}RegFunc, {$IFDEF FPK}@{$ENDIF}DerivProc, X, Y, W, N, FirstParam, LastParam, MaxIter, Tol, B, B_min, B_max, V); if ErrCode = 0 then begin { Estimate Y values } if RegModel = REG_MULT then for K := 1 to N do begin CopyVectorFromCol(Xk, U, FirstParam, LastParam, K); Ycalc^[K] := RegFuncNVar(Xk, B); end else for K := 1 to N do Ycalc^[K] := RegFunc(X^[K], B); { Compute regression tests and update variance-covariance matrix } if VarModel = VAR_CONST then RegTest(Y, Ycalc, N, FirstParam, LastParam, V, Test) else WRegTest(Y, Ycalc, W, N, FirstParam, LastParam, V, Test); { Store residual variance in Theta^[0] } Theta^[0] := Test.Vr; { Compute standard deviations } Sr := Sqrt(Test.Vr); for K := 1 to N do S^[K] := Sr; if VarModel <> VAR_CONST then for K := 1 to N do S^[K] := S^[K] / Sqrt(W^[K]); end; DelVector(W, N); DelVector(Xk, LastParam); WLSFit := ErrCode; end; function VarFuncName : String; begin case VarModel of VAR_CONST : VarFuncName := 'v = e0'; VAR_LIN : VarFuncName := 'v = e0.(1 + e1.y)'; VAR_POL2 : VarFuncName := 'v = e0.(1 + e1.y + e2.y^2)'; VAR_POL3 : VarFuncName := 'v = e0.(1 + e1.y + e2.y^2 + e3.y^3)'; VAR_EXPO : VarFuncName := 'v = e0.exp(e1.y)'; VAR_POWER : VarFuncName := 'v = e0.y^e1'; end; end; function VarFunc(Y : Float; Theta : PVector) : Float; begin case VarModel of VAR_CONST : VarFunc := 1.0; VAR_LIN : VarFunc := 1.0 + Theta^[1] * Y; VAR_POL2 : VarFunc := 1.0 + Y * (Theta^[1] + Theta^[2] * Y); VAR_POL3 : VarFunc := 1.0 + Y * (Theta^[1] + Y * (Theta^[2] + Theta^[3] * Y)); VAR_EXPO : VarFunc := Exp(Theta^[1] * Y); VAR_POWER : VarFunc := Power(Y, Theta^[1]); end; end; function LastVarParam : Integer; begin case VarModel of VAR_CONST : LastVarParam := 0; VAR_LIN : LastVarParam := 1; VAR_POL2 : LastVarParam := 2; VAR_POL3 : LastVarParam := 3; VAR_EXPO : LastVarParam := 1; VAR_POWER : LastVarParam := 1; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/fitpoly.pas����������������������������������������0000755�0001750�0001750�00000007775�11326425446�021501� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITPOLY.PAS * * Version 1.2 * * (c) J. Debord, March 1999 * ********************************************************************** This unit fits a polynomial : y = b0 + b1.x + b2.x^2 + ... ********************************************************************** } unit FitPoly; {$F+} interface uses FMath, Matrices, Polynom, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; procedure InitModel(CstPar : PVector); implementation const Deg : Integer = 2; { Degree of polynomial } function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function. -------------------------------------------------------------------- } var Name, S : String; I : Integer; begin Name := 'y = b0 + b1.x'; for I := 2 to Deg do begin Str(I, S); Name := Name + ' + b' + S + '.x^' + S; end; FuncName := Name; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted. -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted. -------------------------------------------------------------------- } begin LastParam := Deg; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter. -------------------------------------------------------------------- } var S : String; begin Str(I, S); ParamName := 'b' + S; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X. B is the vector of parameters (coefficients of polynomial). -------------------------------------------------------------------- } begin RegFunc := Poly(X, B, Deg); end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; { -------------------------------------------------------------------- Fit of polynomial. -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters V = variance-covariance matrix of parameters -------------------------------------------------------------------- } begin case Method of 0 : FitModel := PolFit(X, Y, N, Deg, B, V); 1 : FitModel := WPolFit(X, Y, W, N, Deg, B, V); end; end; procedure InitModel(CstPar : PVector); { -------------------------------------------------------------------- Initializes the global variables of the unit. -------------------------------------------------------------------- CstPar^[0] = Degree of polynomial -------------------------------------------------------------------- } var D : Integer; begin D := Round(CstPar^[0]); if D > 1 then Deg := D; end; end. ���mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/texplot.pas����������������������������������������0000755�0001750�0001750�00000036214�11326425446�021500� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit TEXPLOT.PAS * * Version 1.1 * * (c) J. Debord, June 2001 * ********************************************************************** Plotting routines for TeX/PSTricks ********************************************************************** } unit TexPlot; interface uses FMath, Matrices, PaString; { ********************** Include global variables ********************** } {$I PLOTVAR.INC} { ************************** Graphic routines ************************** } procedure InitTexGraph(var F : Text; FileName : String); { ---------------------------------------------------------------------- Initializes TeX graphics. Writes a border around the graph according to the value of the global variable GraphBorder (defined in PLOTVAR.INC) ---------------------------------------------------------------------- F : file to be written FileName : name of TeX file (e.g. 'figure.tex') ---------------------------------------------------------------------- } function Xcm(X : Float) : Float; { ---------------------------------------------------------------------- Converts user coordinate X to cm ---------------------------------------------------------------------- } function Ycm(Y : Float) : Float; { ---------------------------------------------------------------------- Converts user coordinate Y to cm ---------------------------------------------------------------------- } procedure WriteXAxis(var F : Text); { ---------------------------------------------------------------------- Writes horizontal axis (global variable XAxis in PLOTVAR.INC) ---------------------------------------------------------------------- } procedure WriteYAxis(var F : Text); { ---------------------------------------------------------------------- Writes vertical axis (global variable YAxis in PLOTVAR.INC) ---------------------------------------------------------------------- } procedure WriteGrid(var F : Text); { ---------------------------------------------------------------------- Writes a grid (global variable Grid in PLOTVAR.INC) ---------------------------------------------------------------------- } procedure WriteLine(var F : Text; X1, Y1, X2, Y2 : Float; Style : String); { ---------------------------------------------------------------------- Writes a line between two points ---------------------------------------------------------------------- F : output file X1, Y1 : coordinates of first point X2, Y2 : coordinates of second point Style : line style (must be 'solid', 'dotted' or 'dashed') ---------------------------------------------------------------------- } procedure WritePoints(var F : Text; X, Y : PVector; Lbound, Ubound, Symbol, Size : Integer); { ---------------------------------------------------------------------- Writes a set of points ---------------------------------------------------------------------- F : output file X, Y : point coordinates Lbound, Ubound : indices of first and last point Symbol : 1 = solid circle 2 = open circle 3 = solid square 4 = open square 5 = solid triangle 6 = open triangle 7 = plus (+) 8 = multiply (x) 9 = star (*) Size : size of points ---------------------------------------------------------------------- } procedure WriteText(var F : Text; Place : String; X, Y : Float; S : String); { ---------------------------------------------------------------------- Writes a text ---------------------------------------------------------------------- F : output file Place : defines the position of point (X,Y) with respect to the box enclosing the text the possible values are 'tl', 't', 'tr', 'l', 'r', 'Bl', 'B', 'Br', 'bl', 'b', 'br' according to the following scheme: t tl +---------------------+ tr | | | | l | | r | | Bl |----------B----------| Br bl +---------------------+ br b X, Y : position of text S : text to be written ---------------------------------------------------------------------- } procedure WriteNumber(var F : Text; Place : String; X, Y, Z : Float); { ---------------------------------------------------------------------- Writes a number ---------------------------------------------------------------------- Z is the number to be written Other parameters as in WriteText ---------------------------------------------------------------------- } procedure WriteCurve(var F : Text; X, Y : PVector; Lbound, Ubound, Width : Integer; Style : String; Smooth : Boolean); { ---------------------------------------------------------------------- Writes a curve ---------------------------------------------------------------------- F : output file X, Y : point coordinates Lbound, Ubound : indices of first and last point Width : curve width in units of 0.01 cm Style : curve style (must be 'solid', 'dotted' or 'dashed') Smooth : indicates if the curve must be smoothed ---------------------------------------------------------------------- } procedure WriteFunc(var F : Text; Func : TFunc; X1, X2 : Float; Npt, Width : Integer; Style : String); { ---------------------------------------------------------------------- Writes the curve representing a function ---------------------------------------------------------------------- F : output file Func : function to be plotted X1, X2 : abscissae of 1st and last point to plot Npt : number of points Width, Style : width of curve (as in WriteCurve) ---------------------------------------------------------------------- The function must be programmed as: function Func(X : Float) : Float; ---------------------------------------------------------------------- } procedure CloseTexGraph(var F : Text); { ---------------------------------------------------------------------- Close graphics ---------------------------------------------------------------------- } implementation const PAGEWIDTH = 13; { Graph width in cm } PAGEHEIGHT = 10; { Graph height in cm } var XminCm, YminCm : Float; { Coord. of lower left corner in cm } XmaxCm, YmaxCm : Float; { Coord. of upper right corner in cm } FactX, FactY : Float; { Scaling factors } function Xcm(X : Float) : Float; { Converts user coordinate X to cm } begin Xcm := XminCm + FactX * (X - XAxis.Min); end; function Ycm(Y : Float) : Float; { Converts user coordinate Y to cm } begin Ycm := YminCm + FactY * (Y - YAxis.Min); end; procedure WriteHeader(var F : Text); begin WriteLn(F, '\documentclass[12pt,a4paper]{article}'); WriteLn(F, '\usepackage{t1enc}'); WriteLn(F, '\usepackage{pst-plot}'); WriteLn(F, '\begin{document}'); WriteLn(F); WriteLn(F, '\begin{pspicture}(', PAGEWIDTH, ',', PAGEHEIGHT, ')'); end; procedure WriteCoord(var F : Text; X, Y : Float); { Writes the coordinates (in cm) of a point } var NSZ : Boolean; begin NSZ := NSZEro; NSZero := False; Write(F, '(', Trim(FloatToStr(X)), ',', Trim(FloatToStr(Y)), ')'); NSZEro := NSZ; end; procedure WriteLine(var F : Text; X1, Y1, X2, Y2 : Float; Style : String); begin Write(F, '\psline'); if Style <> '' then Write(F, '[linestyle=', Style, ']'); WriteCoord(F, X1, Y1); WriteCoord(F, X2, Y2); WriteLn(F); end; procedure WriteText(var F : Text; Place : String; X, Y : Float; S : String); begin Write(F, '\rput[', Place, ']'); WriteCoord(F, X, Y); WriteLn(F, '{', S, '}'); end; procedure WriteNumber(var F : Text; Place : String; X, Y, Z : Float); begin Write(F, '\rput[', Place, ']'); WriteCoord(F, X, Y); WriteLn(F, '{', Trim(FloatToStr(Z)), '}'); end; procedure WriteXAxis(var F: Text); var W, X, Xc, Z : Float; N, I, J : Integer; NSZ : Boolean; begin WriteLine(F, XminCm, YminCm, XmaxCm, YminCm, ''); N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); { Nb of intervals } X := XAxis.Min; { Tick mark position } NSZ := NSZero; NSZero := False; { Don't write non significant zero's } for I := 0 to N do { Label axis } begin if (XAxis.Scale = LIN_SCALE) and (Abs(X) < EPS) then X := 0.0; Xc := Xcm(X); WriteLine(F, Xc, YminCm, Xc, YminCm - 0.25, ''); { Tick mark } if XAxis.Scale = LIN_SCALE then Z := X else Z := Exp10(X); WriteNumber(F, 't', Xc, YminCm - 0.35, Z); { Label } if (XAxis.Scale = LOG_SCALE) and (I < N) then for J := 2 to 9 do { Plot minor divisions } begin { on logarithmic scale } W := X + Log10(J); Xc := Xcm(W); WriteLine(F, Xc, YminCm, Xc, YminCm - 0.15, ''); end; X := X + XAxis.Step; end; { Write axis title } if XTitle.Text <> '' then WriteText(F, 't', 0.5 * (XminCm + XmaxCm), YminCm - 1.0, XTitle.Text); NSZero := NSZ; end; procedure WriteYAxis(var F : Text); var W, Y, Yc, Z : Float; N, I, J : Integer; NSZ : Boolean; begin WriteLine(F, XminCm, YminCm, XminCm, YmaxCm, ''); N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); Y := YAxis.Min; NSZ := NSZero; NSZero := False; for I := 0 to N do begin if (YAxis.Scale = LIN_SCALE) and (Abs(Y) < EPS) then Y := 0.0; Yc := Ycm(Y); WriteLine(F, XminCm, Yc, XminCm - 0.25, Yc, ''); if YAxis.Scale = LIN_SCALE then Z := Y else Z := Exp10(Y); WriteNumber(F, 'r', XminCm - 0.35, Yc, Z); if (YAxis.Scale = LOG_SCALE) and (I < N) then for J := 2 to 9 do begin W := Y + Log10(J); Yc := Ycm(W); WriteLine(F, XminCm, Yc, XminCm - 0.15, Yc, ''); end; Y := Y + YAxis.Step; end; { Write axis title } if YTitle.Text <> '' then WriteText(F, 'l', XminCm, YmaxCm + 0.5, YTitle.Text); NSZero := NSZ; end; procedure WriteGrid(var F : Text); var X, Y, Xc, Yc : Float; I, N : Integer; begin { Horizontal lines } if Grid in [HORIZ_GRID, BOTH_GRID] then begin N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); { Nb of intervals } for I := 1 to Pred(N) do begin Y := YAxis.Min + I * YAxis.Step; { Origin of line } Yc := Ycm(Y); WriteLine(F, XminCm, Yc, XmaxCm, Yc, 'dotted'); end; end; { Vertical lines } if Grid in [VERTIC_GRID, BOTH_GRID] then begin N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); for I := 1 to Pred(N) do begin X := XAxis.Min + I * XAxis.Step; Xc := Xcm(X); WriteLine(F, Xc, YminCm, Xc, YmaxCm, 'dotted'); end; end; end; procedure InitTexGraph(var F : Text; Filename : String); begin XminCm := 0.01 * Xwin1 * PAGEWIDTH; XmaxCm := 0.01 * Xwin2 * PAGEWIDTH; YminCm := 0.01 * Ywin1 * PAGEHEIGHT; YmaxCm := 0.01 * Ywin2 * PAGEHEIGHT; FactX := (XmaxCm - XminCm) / (XAxis.Max - XAxis.Min); FactY := (YmaxCm - YminCm) / (YAxis.Max - YAxis.Min); Assign(F, FileName); Rewrite(F); WriteHeader(F); if GraphBorder then begin Write(F, '\pspolygon'); WriteCoord(F, XminCm, YminCm); WriteCoord(F, XmaxCm, YminCm); WriteCoord(F, XmaxCm, YmaxCm); WriteCoord(F, XminCm, YmaxCm); WriteLn(F); end; end; procedure WritePoint(var F : Text; X, Y : Float); var Xc, Yc : Float; begin if XAxis.Scale = LOG_SCALE then X := Log10(X); if YAxis.Scale = LOG_SCALE then Y := Log10(Y); Xc := Xcm(X); Yc := Ycm(Y); if (Xc >= XminCm) and (Xc <= XmaxCm) and (Yc >= YminCm) and (Yc <= YmaxCm) then WriteCoord(F, Xc, Yc); end; procedure WritePoints(var F : Text; X, Y : PVector; Lbound, Ubound, Symbol, Size : Integer); var I, N : Integer; begin Write(F, '\psdots[dotscale=', Size, ' ', Size, ', dotstyle='); case Symbol of 1 : Write(F, '*'); 2 : Write(F, 'o'); 3 : Write(F, 'square*'); 4 : Write(F, 'square'); 5 : Write(F, 'triangle*'); 6 : Write(F, 'triangle'); 7 : Write(F, '+'); 8 : Write(F, 'x'); 9 : Write(F, 'asterisk'); end; WriteLn(F, ']%'); I := Lbound; repeat WritePoint(F, X^[I], Y^[I]); if (I > 0) and (I < Ubound) and (I mod 5 = 0) then WriteLn(F, '%'); Inc(I); until I > Ubound; WriteLn(F); end; procedure WriteCurve(var F : Text; X, Y : PVector; Lbound, Ubound, Width : Integer; Style : String; Smooth : Boolean); var I, N : Integer; W : Float; Ws : String; begin W := 0.01 * Width; Str(W:5:2, Ws); Ws := Trim(Ws); if Smooth then Write(F, '\pscurve') else Write(F, '\psline'); WriteLn(F, '[linewidth=', Ws, ', linestyle=', Style, ']%'); I := Lbound; repeat WritePoint(F, X^[I], Y^[I]); if (I > 0) and (I < Ubound) and (I mod 5 = 0) then WriteLn(F, '%'); Inc(I); until I > Ubound; WriteLn(F); end; procedure WriteFunc(var F : Text; Func : TFunc; X1, X2 : Float; Npt, Width : Integer; Style : String); const X : PVector = nil; Y : PVector = nil; N : Integer = 0; var H : Float; I : Integer; begin if Npt <> N then begin DelVector(X, N); DelVector(Y, N); DimVector(X, Npt); DimVector(Y, Npt); N := Npt; end; H := (X2 - X1) / N; for I := 0 to N do begin X^[I] := X1 + I * H; if XAxis.Scale = LIN_SCALE then Y^[I] := Func(X^[I]) else Y^[I] := Func(Exp10(X^[I])); end; WriteCurve(F, X, Y, 0, N, Width, Style, True); end; procedure CloseTexGraph(var F: Text); begin WriteLn(F, '\end{pspicture}'); WriteLn(F); WriteLn(F, '\end{document}'); Close(F); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/GraphicsMathLibrary.pas����������������������������0000755�0001750�0001750�00000061473�11326425446�023705� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// Graphics Math Library // // Copyright (C) 1982, 1985, 1992, 1995-1998 Earl F. Glynn, Overland Park, KS. // All Rights Reserved. E-Mail Address: EarlGlynn@att.net UNIT GraphicsMathLibrary; // Matrix/Vector Operations for 2D/3D Graphics} INTERFACE USES SysUtils,dialogs; {Exception} CONST sizeUndefined = 1; size2D = 3; // 'size' of 2D homogeneous vector or transform matrix size3D = 4; // 'size' of 3D homogeneous vector or transform matrix TYPE EVectorError = CLASS(Exception); EMatrixError = CLASS(Exception); TAxis = (axisX, axisY, axisZ); TCoordinate = (coordCartesian, coordSpherical, coordCylindrical); TDimension = (dimen2D, dimen3D); // two- or three-dimensional TYPE TIndex = 1..4; // index of 'TMatrix' and 'TVector' TYPEs TMatrix = // transformation 'matrix' RECORD size: TIndex; matrix: ARRAY[TIndex,TIndex] OF single //azx DOUBLE END; Trotation = (rotateClockwise, rotateCounterClockwise); // Normally the TVector TYPE is used to define 2D/3D homogenous // cartesian coordinates for graphics, i.e., (x,y,1) for 2D and // (x,y,z,1) for 3D. // // Cartesian coordinates can be converted to spherical (r, theta, phi), // or cylindrical coordinates (r,theta, z). Spherical or cylindrical // coordinates can be converted back to cartesian coordinates. TVector = RECORD size: TIndex; CASE INTEGER OF 0: (vector: ARRAY[TIndex] OF single); 1: (x: single; y: single; z: single; // contains 'h' for 2D cartesian vector h: single) END; TIntVector = RECORD size: TIndex; CASE INTEGER OF 0: (vector: ARRAY[TIndex] OF integer); 1: (x: integer; y: integer; z: integer; // contains 'h' for 2D cartesian vector h: integer) END; // Vector Operations // FUNCTION Vector2D (CONST xValue, yValue: DOUBLE): TVector; FUNCTION Vector3D (CONST xValue, yValue, zValue: DOUBLE): TVector; (* FUNCTION AddVectors (CONST u,v: TVector): TVector; // FUNCTION Transform (CONST u: TVector; CONST a: TMatrix): TVector; FUNCTION DotProduct (CONST u,v: TVector): DOUBLE; FUNCTION CrossProduct(CONST u,v: TVector): TVector; *) // Basic Matrix Operations FUNCTION Matrix2D (CONST m11,m12,m13, // 2D "graphics" matrix m21,m22,m23, m31,m32,m33: DOUBLE): TMatrix; FUNCTION Matrix3D (CONST m11,m12,m13,m14, // 3D "graphics" matrix m21,m22,m23,m24, m31,m32,m33,m34, m41,m42,m43,m44: DOUBLE): TMatrix; FUNCTION MultiplyMatrices (CONST a,b: TMatrix): TMatrix; FUNCTION InvertMatrix3D (CONST Input:TMatrix): TMatrix; FUNCTION InvertMatrix (CONST a,b: TMatrix; VAR determinant: DOUBLE): TMatrix; // Transformation Matrices FUNCTION RotateMatrix (CONST dimension: TDimension; CONST xyz : TAxis; CONST angle : DOUBLE; CONST rotation : Trotation): TMatrix; // FUNCTION ScaleMatrix (CONST s: TVector): TMatrix; // FUNCTION TranslateMatrix (CONST t: TVector): TMatrix; FUNCTION ViewTransformMatrix (CONST coordinate: TCoordinate; CONST azimuth {or x}, elevation {or y}, distance {or z}: DOUBLE; CONST ScreenX, ScreenY, ScreenDistance: DOUBLE): TMatrix; // conversions // FUNCTION FromCartesian (CONST ToCoordinate: TCoordinate; CONST u: TVector): TVector; // FUNCTION ToCartesian (CONST FromCoordinate: TCoordinate; CONST u: TVector): TVector; //FUNCTION ToDegrees(CONST angle {radians}: DOUBLE): DOUBLE {degrees}; FUNCTION ToRadians(CONST angle {degrees}: DOUBLE): DOUBLE {radians}; // miscellaneous FUNCTION Defuzz(CONST x: DOUBLE): DOUBLE; { FUNCTION GetFuzz: DOUBLE; PROCEDURE SetFuzz(CONST x: DOUBLE); } IMPLEMENTATION VAR fuzz : DOUBLE; // ************************* Vector Operations ************************* // This procedure defines two-dimensional homogeneous coordinates (x,y,1) // as a single 'vector' data element 'u'. The 'size' of a two-dimensional // homogenous vector is 3. // This procedure defines three-dimensional homogeneous coordinates // (x,y,z,1) as a single 'vector' data element 'u'. The 'size' of a // three-dimensional homogenous vector is 4. FUNCTION Vector3D (CONST xValue, yValue, zValue: DOUBLE): TVector; BEGIN WITH RESULT DO BEGIN x := xValue; y := yValue; z := zValue; h := 1.0; // homogeneous coordinate size := size3D END END {Vector3D}; // AddVectors adds two vectors defined with homogeneous coordinates. FUNCTION AddVectors (CONST u,v: TVector): TVector; VAR i: TIndex; BEGIN IF (u.size IN [size2D..size3D]) AND (v.size IN [size2D..size3D]) AND (u.size = v.size) THEN BEGIN RESULT.size := u.size; FOR i := 1 TO u.size-1 DO {2D + 2D = 2D or 3D + 3D = 3D} BEGIN RESULT.vector[i] := u.vector[i] + v.vector[i] END; RESULT.vector[u.size] := 1.0 {homogeneous coordinate} END ELSE raise EVectorError.Create('Vector Addition Mismatch') END {AddVectors}; // *********************** Basic Matrix Operations ********************** FUNCTION Matrix2D (CONST m11,m12,m13, m21,m22,m23, m31,m32,m33: DOUBLE): TMatrix; BEGIN WITH RESULT DO BEGIN matrix[1,1] := m11; matrix[1,2] := m12; matrix[1,3] := m13; matrix[2,1] := m21; matrix[2,2] := m22; matrix[2,3] := m23; matrix[3,1] := m31; matrix[3,2] := m32; matrix[3,3] := m33; size := size2D END END {Matrix2D}; FUNCTION Matrix3D (CONST m11,m12,m13,m14, m21,m22,m23,m24, m31,m32,m33,m34, m41,m42,m43,m44: DOUBLE): TMatrix; BEGIN WITH RESULT DO BEGIN matrix[1,1] := m11; matrix[1,2] := m12; matrix[1,3] := m13; matrix[1,4] := m14; matrix[2,1] := m21; matrix[2,2] := m22; matrix[2,3] := m23; matrix[2,4] := m24; matrix[3,1] := m31; matrix[3,2] := m32; matrix[3,3] := m33; matrix[3,4] := m34; matrix[4,1] := m41; matrix[4,2] := m42; matrix[4,3] := m43; matrix[4,4] := m44; size := size3D END END {Matrix3D}; // Compound geometric transformation matrices can be formed by multiplying // simple transformation matrices. This procedure only multiplies together // matrices for two- or three-dimensional transformations, i.e., 3x3 or 4x4 // matrices. The multiplier and multiplicand must be of the same dimension. FUNCTION MultiplyMatrices (CONST a,b: TMatrix): TMatrix; VAR i,j,k: TIndex; temp : DOUBLE; BEGIN RESULT.size := a.size; IF a.size = b.size THEN FOR i := 1 TO a.size DO BEGIN FOR j := 1 TO a.size DO BEGIN temp := 0.0; FOR k := 1 TO a.size DO BEGIN temp := temp + a.matrix[i,k]*b.matrix[k,j]; END; RESULT.matrix[i,j] := Defuzz(temp) END END ELSE Showmessage('shit'+inttostr(a.size)+'x'+inttostr(b.size)); //ELSE EMatrixError.Create('MultiplyMatrices error') END {MultiplyMatrices}; PROCEDURE lubksb(a: {glnpbynp}TMatrix; n: integer; indx: TIntVector; VAR b: TVector); VAR j,ip,ii,i: integer; sum: double; BEGIN ii := 0; FOR i := 1 TO n DO BEGIN ip := indx.vector[i]; sum := b.vector[ip]; b.vector[ip] := b.vector[i]; IF (ii <> 0) THEN BEGIN FOR j := ii TO i-1 DO BEGIN sum := sum-a.matrix[i,j]*b.vector[j] END END ELSE IF (sum <> 0.0) THEN BEGIN ii := i END; b.vector[i] := sum END; FOR i := n DOWNTO 1 DO BEGIN sum := b.vector[i]; IF (i < n) THEN BEGIN FOR j := i+1 TO n DO BEGIN sum := sum-a.matrix[i,j]*b.vector[j] END END; b.vector[i] := sum/a.matrix[i,i] END end; PROCEDURE ludcmp(VAR a: TMatrix; n: integer; VAR indx: TIntVector; VAR d: double); CONST tiny=1.0e-20; VAR k,j,imax,i: integer; sum,dum,big: real; vv: TVector; BEGIN d := 1.0; FOR i := 1 TO n DO BEGIN big := 0.0; FOR j := 1 TO n DO IF (abs(a.matrix[i,j]) > big) THEN big := abs(a.matrix[i,j]); IF (big = 0.0) THEN BEGIN writeln('pause in LUDCMP - singular matrix'); readln END; vv.vector[i] := 1.0/big END; FOR j := 1 TO n DO BEGIN FOR i := 1 TO j-1 DO BEGIN sum := a.matrix[i,j]; FOR k := 1 TO i-1 DO BEGIN sum := sum-a.matrix[i,k]*a.matrix[k,j] END; a.matrix[i,j] := sum END; big := 0.0; FOR i := j TO n DO BEGIN sum := a.matrix[i,j]; FOR k := 1 TO j-1 DO BEGIN sum := sum-a.matrix[i,k]*a.matrix[k,j] END; a.matrix[i,j] := sum; dum := vv.vector[i]*abs(sum); IF (dum > big) THEN BEGIN big := dum; imax := i END END; IF (j <> imax) THEN BEGIN FOR k := 1 TO n DO BEGIN dum := a.matrix[imax,k]; a.matrix[imax,k] := a.matrix[j,k]; a.matrix[j,k] := dum END; d := -d; vv.vector[imax] := vv.vector[j] END; indx.vector[j] := imax; IF (a.matrix[j,j] = 0.0) THEN a.matrix[j,j] := tiny; IF (j <> n) THEN BEGIN dum := 1.0/a.matrix[j,j]; FOR i := j+1 TO n DO BEGIN a.matrix[i,j] := a.matrix[i,j]*dum END END END; END; FUNCTION InvertMatrix3D (CONST Input:TMatrix): TMatrix; var n,i,j: integer; d: double; indx: tIntVector; col: tvector; a,y: TMatrix; begin a:= Input; n := 3; ludcmp(a,n,indx,d); for j := 1 to n do begin for i := 1 to n do col.vector[i] := 0; col.vector[j] := 1.0; lubksb(a,n,indx,col); for i := 1 to n do y.matrix[i,j] := col.vector[i]; end; result := y; end; // This procedure inverts a general transformation matrix. The user need // not form an inverse geometric transformation by keeping a product of // the inverses of simple geometric transformations: translations, rotations // and scaling. A determinant of zero indicates no inverse is possible for // a singular matrix. FUNCTION InvertMatrix (CONST a,b: TMatrix; VAR determinant: DOUBLE): TMatrix; VAR c : TMatrix; i,i_pivot: TIndex; i_flag : ARRAY[TIndex] OF BOOLEAN; j,j_pivot: TIndex; j_flag : ARRAY[TIndex] OF BOOLEAN; modulus : DOUBLE; n : TIndex; pivot : DOUBLE; pivot_col: ARRAY[TIndex] OF TIndex; pivot_row: ARRAY[TIndex] OF TIndex; temporary: DOUBLE; BEGIN c := a; // The matrix inversion algorithm used here WITH c DO // is similar to the "maximum pivot strategy" BEGIN // described in "Applied Numerical Methods" FOR i := 1 TO size DO // by Carnahan, Luther and Wilkes, BEGIN // pp. 282-284. i_flag[i] := TRUE; j_flag[i] := TRUE END; modulus := 1.0; i_pivot := 1; // avoid initialization warning j_pivot := 1; // avoid initialization warning FOR n := 1 TO size DO BEGIN pivot := 0.0; IF ABS(modulus) > 0.0 THEN BEGIN FOR i := 1 TO size DO IF i_flag[i] THEN FOR j := 1 TO size DO IF j_flag[j] THEN IF ABS(matrix[i,j]) > ABS(pivot) THEN BEGIN pivot := matrix[i,j]; // largest value on which to pivot i_pivot := i; // indices of pivot element j_pivot := j END; IF Defuzz(pivot) = 0 // If pivot is too small, consider THEN modulus := 0 // the matrix to be singular ELSE BEGIN pivot_row[n] := i_pivot; pivot_col[n] := j_pivot; i_flag[i_pivot] := FALSE; j_flag[j_pivot] := FALSE; FOR i := 1 TO size DO IF i <> i_pivot THEN FOR j := 1 TO size DO // pivot column unchanged for elements IF j <> j_pivot // not in pivot row or column ... THEN matrix[i,j] := (matrix[i,j]*matrix[i_pivot,j_pivot] - matrix[i_pivot,j]*matrix[i,j_pivot]) / modulus; // 2x2 minor / modulus FOR j := 1 TO size DO IF j <> j_pivot // change signs of elements in pivot row THEN matrix[i_pivot,j] := -matrix[i_pivot,j]; temporary := modulus; // exchange pivot element and modulus modulus := matrix[i_pivot,j_pivot]; matrix[i_pivot,j_pivot] := temporary END END END {FOR n} END {WITH}; determinant := Defuzz(modulus); IF determinant <> 0 THEN BEGIN RESULT.size := c.size; // The matrix inverse must be unscrambled FOR i := 1 TO c.size DO // if pivoting was not along main diagonal. FOR j := 1 TO c.size DO RESULT.matrix[pivot_row[i],pivot_col[j]] := Defuzz(c.matrix[i,j]/determinant) END ELSE EMatrixError.Create('InvertMatrix error') END {InvertMatrix}; // *********************** Transformation Matrices ******************** // This procedure defines a matrix for a two- or three-dimensional rotation. // To avoid possible confusion in the sense of the rotation, 'rotateClockwise' // or 'roCounterlcockwise' must always be specified along with the axis // of rotation. Two-dimensional rotations are assumed to be about the z-axis // in the x-y plane. // // A rotation about an arbitrary axis can be performed with the following // steps: // (1) Translate the object into a new coordinate system where (x,y,z) // maps into the origin (0,0,0). // (2) Perform appropriate rotations about the x and y axes of the // coordinate system so that the unit vector (a,b,c) is mapped into // the unit vector along the z axis. // (3) Perform the desired rotation about the z-axis of the new // coordinate system. // (4) Apply the inverse of step (2). // (5) Apply the inverse of step (1). FUNCTION RotateMatrix (CONST dimension: TDimension; CONST xyz : TAxis; CONST angle : DOUBLE; CONST rotation : Trotation): TMatrix; VAR cosx : DOUBLE; sinx : DOUBLE; TempAngle: DOUBLE; BEGIN TempAngle := angle; // Use TempAngle since "angle" is CONST parameter IF rotation = rotateCounterClockwise THEN TempAngle := -TempAngle; cosx := Defuzz( COS(TempAngle) ); sinx := Defuzz( SIN(TempAngle) ); CASE dimension OF dimen2D: CASE xyz OF axisX,axisY: EMatrixError.Create('Invalid 2D rotation matrix. Specify axisZ'); axisZ: RESULT := Matrix2D ( cosx, -sinx, 0, sinx, cosx, 0, 0, 0, 1) END; dimen3D: CASE xyz OF axisX: RESULT := Matrix3D ( 1, 0, 0, 0, 0, cosx, -sinx, 0, 0, sinx, cosx, 0, 0, 0, 0, 1); axisY: RESULT := Matrix3D ( cosx, 0, sinx, 0, 0, 1, 0, 0, -sinx, 0, cosx, 0, 0, 0, 0, 1); axisZ: RESULT := Matrix3D ( cosx, -sinx, 0, 0, sinx, cosx, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); END END END {RotateMatrix}; // 'ScaleMatrix' accepts a 'vector' containing the scaling factors for // each of the dimensions and creates a scaling matrix. The size // of the vector dictates the size of the resulting matrix. FUNCTION ScaleMatrix (CONST s: TVector): TMatrix; BEGIN CASE s.size OF size2D: RESULT := Matrix2D (s.x, 0, 0, 0, s.y, 0, 0, 0, 1); size3D: RESULT := Matrix3D (s.x, 0, 0, 0, 0, s.y, 0, 0, 0, 0, s.z, 0, 0, 0, 0, 1) END END {ScaleMatrix}; // 'TranslateMatrix' defines a translation transformation matrix. The // components of the vector 't' determine the translation components. // (Note: 'Translate' here is from kinematics in physics.) FUNCTION TranslateMatrix (CONST t: TVector): TMatrix; BEGIN CASE t.size OF size2D: RESULT := Matrix2D ( 1, 0, 0, 0, 1, 0, t.x, t.y, 1); size3D: RESULT := Matrix3D ( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, t.x, t.y, t.z, 1) END END {TranslateMatrix}; // 'ViewTransformMatrix' creates a transformation matrix for changing // from world coordinates to eye coordinates. The location of the 'eye' // from the 'object' is given in spherical (azimuth,elevation,distance) // coordinates or Cartesian (x,y,z) coordinates. The size of the screen // is 'ScreenX' units horizontally and 'ScreenY' units vertically. The // eye is 'ScreenDistance' units from the viewing screen. A large ratio // 'ScreenDistance/ScreenX (or ScreenY)' specifies a narrow aperature // -- a telephoto view. Conversely, a small ratio specifies a large // aperature -- a wide-angle view. This view transform matrix is very // useful as the default three-dimensional transformation matrix. Once // set, all points are automatically transformed. FUNCTION ViewTransformMatrix (CONST coordinate: TCoordinate; CONST azimuth {or x}, elevation {or y}, distance {or z}: DOUBLE; CONST ScreenX, ScreenY, ScreenDistance: DOUBLE): TMatrix; CONST HalfPI = PI / 2.0; VAR a : TMatrix; b : TMatrix; cosm : DOUBLE; // COS(-angle) hypotenuse: DOUBLE; sinm : DOUBLE; // SIN(-angle) temporary : DOUBLE; u : TVector; x : DOUBLE ABSOLUTE azimuth; // x and azimuth are synonyms y : DOUBLE ABSOLUTE elevation; // synonyms z : DOUBLE ABSOLUTE distance; // synonyms BEGIN CASE coordinate OF coordCartesian: u := Vector3D (-x, -y, -z); coordSpherical: BEGIN temporary := -distance * COS(elevation); u := Vector3D (temporary * COS(azimuth - HalfPI), temporary * SIN(azimuth - HalfPI), -distance * SIN(elevation)); END END; a := TranslateMatrix(u); // translate origin to 'eye' b := RotateMatrix (dimen3D, axisX, HalfPI, rotateClockwise); a := MultiplyMatrices(a,b); CASE coordinate OF coordCartesian: BEGIN temporary := SQR(x) + SQR(y); hypotenuse := SQRT(temporary); if hypotenuse <> 0 then begin cosm := -y/hypotenuse; sinm := x/hypotenuse; end else begin cosm := 1;//abba sinm := 0; end; b := Matrix3D ( cosm, 0, sinm, 0, 0, 1, 0, 0, -sinm, 0, cosm, 0, 0, 0, 0, 1); a := MultiplyMatrices (a,b); cosm := hypotenuse; hypotenuse := SQRT(temporary + SQR(z)); cosm := cosm/hypotenuse; sinm := -z/hypotenuse; b := Matrix3D ( 1, 0, 0, 0, 0, cosm, -sinm, 0, 0, sinm, cosm, 0, 0, 0, 0, 1) END; coordSpherical: BEGIN b := RotateMatrix (dimen3D,axisY,-azimuth,rotateCounterClockwise); a := MultiplyMatrices(a,b); b := RotateMatrix (dimen3D,axisX,elevation,rotateCounterClockwise); END END {CASE}; a := MultiplyMatrices (a,b); u := Vector3D (ScreenDistance/(0.5*ScreenX), ScreenDistance/(0.5*ScreenY),-1.0); b := ScaleMatrix (u); // reverse sense of z-axis; screen transformation RESULT := MultiplyMatrices (a,b); END {ViewTransformMatrix}; // *************************** Conversions ************************** // This function converts the vector parameter from Cartesian // coordinates to the specified type of coordinates. FUNCTION FromCartesian (CONST ToCoordinate: TCoordinate; CONST u: TVector): TVector; VAR phi : DOUBLE; r : DOUBLE; temp : DOUBLE; theta: DOUBLE; BEGIN IF ToCoordinate = coordCartesian THEN RESULT := u ELSE BEGIN RESULT.size := u.size; IF (u.size = size3D) AND (ToCoordinate = coordSpherical) THEN BEGIN // spherical 3D temp := SQR(u.x)+SQR(u.y); // (x,y,z) -> (r,theta,phi) r := SQRT(temp+SQR(u.z)); IF Defuzz(u.x) = 0.0 THEN theta := PI/4 ELSE theta := ARCTAN(u.y/u.x); IF Defuzz(u.z) = 0.0 THEN phi := PI/4 ELSE phi := ARCTAN(SQRT(temp)/u.z); RESULT.x := r; RESULT.y := theta; RESULT.z := phi END ELSE BEGIN // cylindrical 2D/3D or spherical 2D // (x,y) -> (r,theta) or (x,y,z) -> (r,theta,z) r := SQRT( SQR(u.x) + SQR(u.y) ); IF Defuzz(u.x) = 0.0 THEN theta := PI/4 ELSE theta := ARCTAN(u.y/u.x); RESULT.x := r; RESULT.y := theta END END END {FromCartesian}; // This function converts the vector parameter from specified coordinates // into Cartesian coordinates. FUNCTION ToCartesian (CONST FromCoordinate: TCoordinate; CONST u: TVector): TVector; VAR phi : DOUBLE; r : DOUBLE; sinphi: DOUBLE; theta : DOUBLE; BEGIN RESULT := u; IF FromCoordinate = coordCartesian THEN RESULT := u ELSE BEGIN RESULT.size := u.size; IF (u.size = size3D) AND (FromCoordinate = coordSpherical) THEN BEGIN // spherical 3D r := u.x; // (r,theta,phi) -> (x,y,z) theta := u.y; phi := u.z; sinphi := SIN(phi); RESULT.x := r * COS(theta) * sinphi; RESULT.y := r * SIN(theta) * sinphi; RESULT.z := r * COS(phi) END ELSE BEGIN // cylindrical 2D/3D or spherical 2D r := u.x; // (r,theta) -> (x,y) or (r,theta,z) -> (x,y,z) theta := u.y; RESULT.x := r * COS(theta); RESULT.y := r * SIN(theta) END END END {ToCartesian}; // Convert angle in degrees to radians. FUNCTION ToRadians (CONST angle: DOUBLE): DOUBLE; BEGIN RESULT := PI/180.0 * angle END; {ToRadians} // *************************** Miscellaneous ************************** // 'Defuzz' is used for comparisons and to avoid propagation of 'fuzzy', // nearly-zero values. DOUBLE calculations often result in 'fuzzy' values. // The term 'fuzz' was adapted from the APL language. FUNCTION Defuzz(CONST x: DOUBLE): DOUBLE; BEGIN IF ABS(x) < fuzz THEN RESULT := 0.0 ELSE RESULT := x END {Defuzz}; INITIALIZATION fuzz := 1.0E-6; END. {GraphicsMath UNIT} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/Matrices.pas���������������������������������������0000755�0001750�0001750�00000162023�11326425446�021546� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit MATRICES.PAS * * Version 2.0 * * (c) J. Debord, May 2001 * ********************************************************************** This unit implements dynamic allocation of vectors and matrices in Pascal, together with various matrix operations. Dynamic allocation is allowed by declaring arrays as pointers. There are 8 types available : PVector, PMatrix for floating point arrays PIntVector, PIntMatrix for integer arrays PBoolVector, PBoolMatrix for boolean arrays PStrVector, PStrMatrix for string arrays (255 char.) To use these arrays in your programs, you must : (1) Declare variables of the appropriate type, e.g. var V : PVector; A : PMatrix; (2) Allocate each array BEFORE using it : DimVector(V, N); creates vector V[0..N] DimMatrix(A, N, M); creates matrix A[0..N, 0..M] where N, M are two integer variables If the allocation succeeds, all array elements are initialized to zero (for numeric arrays), False (for boolean arrays), or the null string (for string arrays). Otherwise, the pointer is initialized to NIL. (3) Use arrays as in standard Turbo Pascal, with the following exceptions : (a) You must use the indirection operator (^) to reference any array element, i.e. write V^[I] and A^[I]^[J] instead of V[I] and A[I,J]. (b) You cannot use the assignment operator (:=) to copy the contents of an array into another array. Writing B := A simply makes B point to the same memory block than A. You must use one of the provided Copy... procedures (see their documentation in the interface part of the unit). In addition, note that : (a) All arrays begin at index 0, so that the 0-indexed element is always present, even if you don't use it. (b) A matrix is declared as an array of vectors, so that A^[I] denotes the I-th vector of matrix A and may be used as any vector. (4) Deallocate arrays when you no longer need them. This will free the corresponding memory : DelVector(V, N); DelMatrix(A, N, M); For more information, read the comments of each routine in the interface part of the unit, and check the demo programs. ********************************************************************** References : 1) 'Basic Programs for Scientists and Engineers' by A.R. Miller : GaussJordan, InvMat 2) Borland's Numerical Methods Toolbox : Det 3) 'Numerical Recipes' by Press et al. : Cholesky, LU, SVD 4) 'Matrix Computations' by Golub & Van Loan : QR_Decomp & QR_Solve (Pascal implementation contributed by Mark Vaughan) ********************************************************************** } unit Matrices; interface uses FMath,dialogs,sysutils; { ********************************************************************** This section defines some error codes. ********************************************************************** } const MAT_OK = 0; { No error } MAT_SINGUL = - 1; { Singular matrix } MAT_NON_CONV = - 2; { Non convergence of iterative procedure } MAT_NOT_PD = - 3; { Matrix not positive definite } { ********************************************************************** This section defines the vector and matrix types. Maximal sizes are given for a 16-bit compiler (TP / BP / Delphi 1). Higher values may be used with the 32-bit compilers (Delphi 2-4, FPK, GPC). ********************************************************************** } const {$IFDEF EXTENDEDREAL} MAX_FLT = 6552; { Max size of real vector } {$ELSE} {$IFDEF SINGLEREAL} MAX_FLT = 16382; {$ELSE} {$IFDEF PASCALREAL} MAX_FLT = 10921; {$ELSE} {$DEFINE DOUBLEREAL} MAX_FLT = 8190; {$ENDIF} {$ENDIF} {$ENDIF} MAX_INT = 16382; { Max size of integer vector } MAX_BOOL = 32766; { Max size of boolean vector } MAX_STR = 254; { Max size of string vector } MAX_VEC = 16382; { Max number of vectors in a matrix } type Str255= string[255]; TVector = array[0..MAX_FLT] of Float; TIntVector = array[0..MAX_INT] of Integer; TBoolVector = array[0..MAX_BOOL] of Boolean; TStrVector = array[0..MAX_STR] of Str255; PVector = ^TVector; PIntVector = ^TIntVector; PBoolVector = ^TBoolVector; PStrVector = ^TStrVector; TMatrix = array[0..MAX_VEC] of PVector; TIntMatrix = array[0..MAX_VEC] of PIntVector; TBoolMatrix = array[0..MAX_VEC] of PBoolVector; TStrMatrix = array[0..MAX_VEC] of PStrVector; PMatrix = ^TMatrix; PIntMatrix = ^TIntMatrix; PBoolMatrix = ^TBoolMatrix; PStrMatrix = ^TStrMatrix; { ********************************************************************** Memory allocation routines ********************************************************************** } procedure DimVector(var V : PVector; Ubound : Integer); { ---------------------------------------------------------------------- Creates floating point vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DimIntVector(var V : PIntVector; Ubound : Integer); { ---------------------------------------------------------------------- Creates integer vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DimBoolVector(var V : PBoolVector; Ubound : Integer); { ---------------------------------------------------------------------- Creates boolean vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DimStrVector(var V : PStrVector; Ubound : Integer); { ---------------------------------------------------------------------- Creates string vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DimMatrix(var A : PMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Creates floating point matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } procedure DimIntMatrix(var A : PIntMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Creates integer matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } procedure DimBoolMatrix(var A : PBoolMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Creates boolean matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } procedure DimStrMatrix(var A : PStrMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Creates string matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } { ********************************************************************** Memory deallocation routines ********************************************************************** } procedure DelVector(var V : PVector; Ubound : Integer); { ---------------------------------------------------------------------- Deletes floating point vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DelIntVector(var V : PIntVector; Ubound : Integer); { ---------------------------------------------------------------------- Deletes integer vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DelBoolVector(var V : PBoolVector; Ubound : Integer); { ---------------------------------------------------------------------- Deletes boolean vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DelStrVector(var V : PStrVector; Ubound : Integer); { ---------------------------------------------------------------------- Deletes string vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DelMatrix(var A : PMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Deletes floating point matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } procedure DelIntMatrix(var A : PIntMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Deletes integer matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } procedure DelBoolMatrix(var A : PBoolMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Deletes boolean matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } procedure DelStrMatrix(var A : PStrMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Deletes string matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } { ********************************************************************** Routines for copying vectors and matrices ---------------------------------------------------------------------- Lbound, Ubound : indices of first and last vector elements Lbound1, Lbound2 : indices of first matrix element in each dimension Ubound1, Ubound2 : indices of last matrix element in each dimension ********************************************************************** } procedure SwapRows(I, K : Integer; A : PMatrix; Lbound, Ubound : Integer); { ---------------------------------------------------------------------- Exchanges rows I and K of matrix A ---------------------------------------------------------------------- } procedure SwapCols(J, K : Integer; A : PMatrix; Lbound, Ubound : Integer); { ---------------------------------------------------------------------- Exchanges columns J and K of matrix A ---------------------------------------------------------------------- } procedure CopyVector(Dest, Source : PVector; Lbound, Ubound : Integer); { ---------------------------------------------------------------------- Copies vector Source into vector Dest ---------------------------------------------------------------------- } procedure CopyMatrix(Dest, Source : PMatrix; Lbound1, Lbound2, Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Copies matrix Source into matrix Dest ---------------------------------------------------------------------- } procedure CopyRowFromVector(Dest : PMatrix; Source : PVector; Lbound, Ubound, Row : Integer); { ---------------------------------------------------------------------- Copies vector Source into line Row of matrix Dest ---------------------------------------------------------------------- } procedure CopyColFromVector(Dest : PMatrix; Source : PVector; Lbound, Ubound, Col : Integer); { ---------------------------------------------------------------------- Copies vector Source into column Col of matrix Dest ---------------------------------------------------------------------- } procedure CopyVectorFromRow(Dest : PVector; Source : PMatrix; Lbound, Ubound, Row : Integer); { ---------------------------------------------------------------------- Copies line Row of matrix Source into vector Dest ---------------------------------------------------------------------- } procedure CopyVectorFromCol(Dest : PVector; Source : PMatrix; Lbound, Ubound, Col : Integer); { ---------------------------------------------------------------------- Copies column Col of matrix Source into vector Dest ---------------------------------------------------------------------- } { ********************************************************************** Vector and matrix functions ********************************************************************** } function Min(X : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the lowest value of vector X ---------------------------------------------------------------------- } function Max(X : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the highest value of vector X ---------------------------------------------------------------------- } function IntMin(X : PIntVector; Lbound, Ubound : Integer) : Integer; { ---------------------------------------------------------------------- Returns the lowest value of integer vector X ---------------------------------------------------------------------- } function IntMax(X : PIntVector; Lbound, Ubound : Integer) : Integer; { ---------------------------------------------------------------------- Returns the highest value of integer vector X ---------------------------------------------------------------------- } procedure Transpose(A : PMatrix; Lbound1, Lbound2, Ubound1, Ubound2 : Integer; A_t : PMatrix); { ---------------------------------------------------------------------- Transposes a matrix ---------------------------------------------------------------------- Input parameters : A = original matrix Lbound1, Lbound2 = indices of 1st matrix elem. in each dim. Ubound1, Ubound2 = indices of last matrix elem. in each dim. ---------------------------------------------------------------------- Output parameter : A_t = transposed matrix ---------------------------------------------------------------------- } function GaussJordan(A : PMatrix; B : PVector; Lbound, Ubound : Integer; A_inv : PMatrix; X : PVector) : Integer; { ---------------------------------------------------------------------- Solves a system of linear equations by the Gauss-Jordan method ---------------------------------------------------------------------- Input parameters : A = system matrix B = constant vector Lbound = index of first matrix element Ubound = index of last matrix element ---------------------------------------------------------------------- Output parameters : A_inv = inverse matrix X = solution vector ---------------------------------------------------------------------- Possible results : MAT_OK MAT_SINGUL ---------------------------------------------------------------------- } function InvMat(A : PMatrix; Lbound, Ubound : Integer; A_inv : PMatrix) : Integer; { ---------------------------------------------------------------------- Computes the inverse of a square matrix by the Gauss-Jordan method ---------------------------------------------------------------------- Parameters : as in Gauss-Jordan ---------------------------------------------------------------------- Possible results : MAT_OK MAT_SINGUL ---------------------------------------------------------------------- } function Det(A : PMatrix; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Computes the determinant of a square matrix ---------------------------------------------------------------------- Parameters : as in Gauss-Jordan ---------------------------------------------------------------------- NB : This procedure destroys the original matrix A ---------------------------------------------------------------------- } function Cholesky(A : PMatrix; Lbound, Ubound : Integer; L : PMatrix) : Integer; { ---------------------------------------------------------------------- Cholesky decomposition. Factors the symmetric positive definite matrix A as a product L * L', where L is a lower triangular matrix. This procedure may be used as a test of positive definiteness. ---------------------------------------------------------------------- Input parameters : A = matrix Lbound = index of first matrix element Ubound = index of last matrix element ---------------------------------------------------------------------- Output parameter : L = Cholesky factor of matrix A ---------------------------------------------------------------------- Possible results : MAT_OK MAT_NOT_PD ---------------------------------------------------------------------- } function LU_Decomp(A : PMatrix; Lbound, Ubound : Integer) : Integer; { ---------------------------------------------------------------------- LU decomposition. Factors the square matrix A as a product L * U, where L is a lower triangular matrix (with unit diagonal terms) and U is an upper triangular matrix. This routine is used in conjunction with LU_Solve to solve a system of equations. ---------------------------------------------------------------------- Input parameters : A = matrix Lbound = index of first matrix element Ubound = index of last matrix element ---------------------------------------------------------------------- Output parameter : A = contains the elements of L and U ---------------------------------------------------------------------- Possible results : MAT_OK MAT_SINGUL ---------------------------------------------------------------------- NB : This procedure destroys the original matrix A ---------------------------------------------------------------------- } procedure LU_Solve(A : PMatrix; B : PVector; Lbound, Ubound : Integer; X : PVector); { ---------------------------------------------------------------------- Solves a system of equations whose matrix has been transformed by LU_Decomp ---------------------------------------------------------------------- Input parameters : A = result from LU_Decomp B = constant vector Lbound, Ubound = as in LU_Decomp ---------------------------------------------------------------------- Output parameter : X = solution vector ---------------------------------------------------------------------- } function SV_Decomp(A : PMatrix; Lbound, Ubound1, Ubound2 : Integer; S : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- Singular value decomposition. Factors the matrix A (n x m, with n >= m) as a product U * S * V' where U is a (n x m) column-orthogonal matrix, S a (m x m) diagonal matrix with elements >= 0 (the singular values) and V a (m x m) orthogonal matrix. This routine is used in conjunction with SV_Solve to solve a system of equations. ---------------------------------------------------------------------- Input parameters : A = matrix Lbound = index of first matrix element Ubound1 = index of last matrix element in 1st dim. Ubound2 = index of last matrix element in 2nd dim. ---------------------------------------------------------------------- Output parameter : A = contains the elements of U S = vector of singular values V = orthogonal matrix ---------------------------------------------------------------------- Possible results : MAT_OK MAT_NON_CONV ---------------------------------------------------------------------- NB : This procedure destroys the original matrix A ---------------------------------------------------------------------- } procedure SV_SetZero(S : PVector; Lbound, Ubound : Integer; Tol : Float); { ---------------------------------------------------------------------- Sets the singular values to zero if they are lower than a specified threshold. ---------------------------------------------------------------------- Input parameters : S = vector of singular values Tol = relative tolerance Threshold value will be Tol * Max(S) Lbound = index of first vector element Ubound = index of last vector element ---------------------------------------------------------------------- Output parameter : S = modified singular values ---------------------------------------------------------------------- } procedure SV_Solve(U : PMatrix; S : PVector; V : PMatrix; B : PVector; Lbound, Ubound1, Ubound2 : Integer; X : PVector); { ---------------------------------------------------------------------- Solves a system of equations by singular value decomposition, after the matrix has been transformed by SV_Decomp, and the lowest singular values have been set to zero by SV_SetZero. ---------------------------------------------------------------------- Input parameters : U, S, V = vector and matrices from SV_Decomp B = constant vector Lbound, Ubound1, Ubound2 = as in SV_Decomp ---------------------------------------------------------------------- Output parameter : X = solution vector = V * Diag(1/s(i)) * U' * B, for s(i) <> 0 ---------------------------------------------------------------------- } procedure SV_Approx(U : PMatrix; S : PVector; V : PMatrix; Lbound, Ubound1, Ubound2 : Integer; A : PMatrix); { ---------------------------------------------------------------------- Approximates a matrix A by the product USV', after the lowest singular values have been set to zero by SV_SetZero. ---------------------------------------------------------------------- Input parameters : U, S, V = vector and matrices from SV_Decomp Lbound, Ubound1, Ubound2 = as in SV_Decomp ---------------------------------------------------------------------- Output parameter : A = approximated matrix ---------------------------------------------------------------------- } function QR_Decomp(A : PMatrix; Lbound, Ubound1, Ubound2 : Integer; R : PMatrix) : Integer; { ---------------------------------------------------------------------- QR decomposition. Factors the matrix A (n x m, with n >= m) as a product Q * R where Q is a (n x m) column-orthogonal matrix, and R a (m x m) upper triangular matrix. This routine is used in conjunction with QR_Solve to solve a system of equations. ---------------------------------------------------------------------- Input parameters : A = matrix Lbound = index of first matrix element Ubound1 = index of last matrix element in 1st dim. Ubound2 = index of last matrix element in 2nd dim. ---------------------------------------------------------------------- Output parameter : A = contains the elements of Q R = upper triangular matrix ---------------------------------------------------------------------- Possible results : MAT_OK MAT_SING ---------------------------------------------------------------------- NB : This procedure destroys the original matrix A ---------------------------------------------------------------------- } procedure QR_Solve(Q, R : PMatrix; B : PVector; Lbound, Ubound1, Ubound2 : Integer; X : PVector); { ---------------------------------------------------------------------- Solves a system of equations by the QR decomposition, after the matrix has been transformed by QR_Decomp. ---------------------------------------------------------------------- Input parameters : Q, R = matrices from QR_Decomp B = constant vector Lbound, Ubound1, Ubound2 = as in QR_Decomp ---------------------------------------------------------------------- Output parameter : X = solution vector ---------------------------------------------------------------------- } implementation const { Used by LU procedures } LastDim : Integer = 1; { Dimension of the last system solved } Index : PIntVector = nil; { Records the row permutations } procedure DimVector(var V : PVector; Ubound : Integer); var I : Integer; begin { Check bounds } if (Ubound < 0) or (Ubound > MAX_FLT) then begin V := nil; Exit; end; { Allocate vector } GetMem(V, Succ(Ubound) * SizeOf(Float)); if V = nil then Exit; { Initialize vector } for I := 0 to Ubound do V^[I] := 0.0; end; procedure DimIntVector(var V : PIntVector; Ubound : Integer); var I : Integer; begin { Check bounds } if (Ubound < 0) or (Ubound > MAX_INT) then begin V := nil; Exit; end; { Allocate vector } GetMem(V, Succ(Ubound) * SizeOf(Integer)); if V = nil then Exit; { Initialize vector } for I := 0 to Ubound do V^[I] := 0; end; procedure DimBoolVector(var V : PBoolVector; Ubound : Integer); var I : Integer; begin { Check bounds } if (Ubound < 0) or (Ubound > MAX_BOOL) then begin V := nil; Exit; end; { Allocate vector } GetMem(V, Succ(Ubound) * SizeOf(Boolean)); if V = nil then Exit; { Initialize vector } for I := 0 to Ubound do V^[I] := False; end; procedure DimStrVector(var V : PStrVector; Ubound : Integer); var I : Integer; begin { Check bounds } if (Ubound < 0) or (Ubound > MAX_STR) then begin showmessage('DIMstr error'); V := nil; Exit; end; { Allocate vector } GetMem(V, Succ(Ubound) * sizeof(TStrVector) {256}); if V = nil then Exit; { Initialize vector } for I := 0 to Ubound do V^[I] := ''; //showmessage(inttostr(Ubound)+'b'+inttostr(MAX_STR)); end; procedure DimMatrix(var A : PMatrix; Ubound1, Ubound2 : Integer); var I, J : Integer; RowSize : Word; begin if (Ubound1 < 0) or (Ubound1 > MAX_VEC) or (Ubound2 < 0) or (Ubound2 > MAX_FLT) then begin A := nil; Exit; end; { Allocate matrix } GetMem(A, Succ(Ubound1) * SizeOf(PVector)); if A = nil then Exit; { Size of a row } RowSize := Succ(Ubound2) * SizeOf(Float); { Allocate each row } for I := 0 to Ubound1 do begin GetMem(A^[I], RowSize); if A^[I] = nil then begin A := nil; Exit; end; end; { Initialize matrix } for I := 0 to Ubound1 do for J := 0 to Ubound2 do A^[I]^[J] := 0.0; end; procedure DimIntMatrix(var A : PIntMatrix; Ubound1, Ubound2 : Integer); var I, J : Integer; RowSize : Word; begin { Check bounds } if (Ubound1 < 0) or (Ubound1 > MAX_VEC) or (Ubound2 < 0) or (Ubound2 > MAX_INT) then begin A := nil; Exit; end; { Allocate matrix } GetMem(A, Succ(Ubound1) * SizeOf(PIntVector)); if A = nil then Exit; { Size of a row } RowSize := Succ(Ubound2) * SizeOf(Integer); { Allocate each row } for I := 0 to Ubound1 do begin GetMem(A^[I], RowSize); if A^[I] = nil then begin A := nil; Exit; end; end; { Initialize matrix } for I := 0 to Ubound1 do for J := 0 to Ubound2 do A^[I]^[J] := 0; end; procedure DimBoolMatrix(var A : PBoolMatrix; Ubound1, Ubound2 : Integer); var I, J : Integer; RowSize : Word; begin { Check bounds } if (Ubound1 < 0) or (Ubound1 > MAX_VEC) or (Ubound2 < 0) or (Ubound2 > MAX_BOOL) then begin A := nil; Exit; end; { Allocate matrix } GetMem(A, Succ(Ubound1) * SizeOf(PBoolVector)); if A = nil then Exit; { Size of a row } RowSize := Succ(Ubound2) * SizeOf(Boolean); { Allocate each row } for I := 0 to Ubound1 do begin GetMem(A^[I], RowSize); if A^[I] = nil then begin A := nil; Exit; end; end; { Initialize matrix } for I := 0 to Ubound1 do for J := 0 to Ubound2 do A^[I]^[J] := False; end; procedure DimStrMatrix(var A : PStrMatrix; Ubound1, Ubound2 : Integer); var I, J : Integer; RowSize : Word; begin { Check bounds } if (Ubound1 < 0) or (Ubound1 > MAX_VEC) or (Ubound2 < 0) or (Ubound2 > MAX_STR) then begin A := nil; Exit; end; { Allocate matrix } GetMem(A, Succ(Ubound1) * SizeOf(PStrVector)); if A = nil then Exit; { Size of a row } RowSize := Succ(Ubound2) * 256; { Allocate each row } for I := 0 to Ubound1 do begin GetMem(A^[I], RowSize); if A^[I] = nil then begin A := nil; Exit; end; end; { Initialize matrix } for I := 0 to Ubound1 do for J := 0 to Ubound2 do A^[I]^[J] := ''; end; procedure DelVector(var V : PVector; Ubound : Integer); begin if V <> nil then begin FreeMem(V, Succ(Ubound) * SizeOf(Float)); V := nil; end; end; procedure DelIntVector(var V : PIntVector; Ubound : Integer); begin if V <> nil then begin FreeMem(V, Succ(Ubound) * SizeOf(Integer)); V := nil; end; end; procedure DelBoolVector(var V : PBoolVector; Ubound : Integer); begin if V <> nil then begin FreeMem(V, Succ(Ubound) * SizeOf(Boolean)); V := nil; end; end; procedure DelStrVector(var V : PStrVector; Ubound : Integer); begin if V <> nil then begin FreeMem(V{, Succ(Ubound) * 256}); V := nil; end; end; procedure DelMatrix(var A : PMatrix; Ubound1, Ubound2 : Integer); var I : Integer; RowSize : Word; begin if A <> nil then begin RowSize := Succ(Ubound2) * SizeOf(Float); for I := Ubound1 downto 0 do FreeMem(A^[I], RowSize); FreeMem(A, Succ(Ubound1) * SizeOf(PVector)); A := nil; end; end; procedure DelIntMatrix(var A : PIntMatrix; Ubound1, Ubound2 : Integer); var I : Integer; RowSize : Word; begin if A <> nil then begin RowSize := Succ(Ubound2) * SizeOf(Integer); for I := Ubound1 downto 0 do FreeMem(A^[I], RowSize); FreeMem(A, Succ(Ubound1) * SizeOf(PIntVector)); A := nil; end; end; procedure DelBoolMatrix(var A : PBoolMatrix; Ubound1, Ubound2 : Integer); var I : Integer; RowSize : Word; begin if A <> nil then begin RowSize := Succ(Ubound2) * SizeOf(Boolean); for I := Ubound1 downto 0 do FreeMem(A^[I], RowSize); FreeMem(A, Succ(Ubound1) * SizeOf(PBoolVector)); A := nil; end; end; procedure DelStrMatrix(var A : PStrMatrix; Ubound1, Ubound2 : Integer); var I : Integer; RowSize : Word; begin if A <> nil then begin RowSize := Succ(Ubound2) * 256; for I := Ubound1 downto 0 do FreeMem(A^[I], RowSize); FreeMem(A, Succ(Ubound1) * SizeOf(PStrVector)); A := nil; end; end; procedure SwapRows(I, K : Integer; A : PMatrix; Lbound, Ubound : Integer); var J : Integer; begin for J := Lbound to Ubound do FSwap(A^[I]^[J], A^[K]^[J]); end; procedure SwapCols(J, K : Integer; A : PMatrix; Lbound, Ubound : Integer); var I : Integer; begin for I := Lbound to Ubound do FSwap(A^[I]^[J], A^[I]^[K]); end; procedure CopyVector(Dest, Source : PVector; Lbound, Ubound : Integer); var I : Integer; begin for I := Lbound to Ubound do Dest^[I] := Source^[I]; end; procedure CopyMatrix(Dest, Source : PMatrix; Lbound1, Lbound2, Ubound1, Ubound2 : Integer); var I, J : Integer; begin for I := Lbound1 to Ubound1 do for J := Lbound2 to Ubound2 do Dest^[I]^[J] := Source^[I]^[J]; end; procedure CopyRowFromVector(Dest : PMatrix; Source : PVector; Lbound, Ubound, Row : Integer); var J : Integer; begin for J := Lbound to Ubound do Dest^[Row]^[J] := Source^[J]; end; procedure CopyColFromVector(Dest : PMatrix; Source : PVector; Lbound, Ubound, Col : Integer); var I : Integer; begin for I := Lbound to Ubound do Dest^[I]^[Col] := Source^[I]; end; procedure CopyVectorFromRow(Dest : PVector; Source : PMatrix; Lbound, Ubound, Row : Integer); var J : Integer; begin for J := Lbound to Ubound do Dest^[J] := Source^[Row]^[J]; end; procedure CopyVectorFromCol(Dest : PVector; Source : PMatrix; Lbound, Ubound, Col : Integer); var I : Integer; begin for I := Lbound to Ubound do Dest^[I] := Source^[I]^[Col]; end; function Min(X : PVector; Lbound, Ubound : Integer) : Float; var Xmin : Float; I : Integer; begin Xmin := X^[Lbound]; for I := Succ(Lbound) to Ubound do if X^[I] < Xmin then Xmin := X^[I]; Min := Xmin; end; function Max(X : PVector; Lbound, Ubound : Integer) : Float; var Xmax : Float; I : Integer; begin Xmax := X^[Lbound]; for I := Succ(Lbound) to Ubound do if X^[I] > Xmax then Xmax := X^[I]; Max := Xmax; end; function IntMin(X : PIntVector; Lbound, Ubound : Integer) : Integer; var I, Xmin : Integer; begin Xmin := X^[Lbound]; for I := Succ(Lbound) to Ubound do if X^[I] < Xmin then Xmin := X^[I]; IntMin := Xmin; end; function IntMax(X : PIntVector; Lbound, Ubound : Integer) : Integer; var I, Xmax : Integer; begin Xmax := X^[Lbound]; for I := Succ(Lbound) to Ubound do if X^[I] > Xmax then Xmax := X^[I]; IntMax := Xmax; end; procedure Transpose(A : PMatrix; Lbound1, Lbound2, Ubound1, Ubound2 : Integer; A_t : PMatrix); var I, J : Integer; begin for I := Lbound1 to Ubound1 do for J := Lbound2 to Ubound2 do A_t^[J]^[I] := A^[I]^[J]; end; function GaussJordan(A : PMatrix; B : PVector; Lbound, Ubound : Integer; A_inv : PMatrix; X : PVector) : Integer; var I, J, K : Integer; Pvt, T : Float; PRow, PCol : PIntVector; { Store line and column of pivot } begin DimIntVector(PRow, Ubound); DimIntVector(PCol, Ubound); { Copy A into A_inv and B into X } CopyMatrix(A_inv, A, Lbound, Lbound, Ubound, Ubound); CopyVector(X, B, Lbound, Ubound); K := Lbound; while K <= Ubound do begin { Search for largest pivot in submatrix A_inv[K..Ubound, K..Ubound] } Pvt := A_inv^[K]^[K]; PRow^[K] := K; PCol^[K] := K; for I := K to Ubound do for J := K to Ubound do if Abs(A_inv^[I]^[J]) > Abs(Pvt) then begin Pvt := A_inv^[I]^[J]; PRow^[K] := I; PCol^[K] := J; end; { Pivot too weak ==> quasi-singular matrix } if Abs(Pvt) < MACHEP then begin DelIntVector(PRow, Ubound); DelIntVector(PCol, Ubound); GaussJordan := MAT_SINGUL; Exit; end; { Exchange current row (K) with pivot row } if PRow^[K] <> K then begin SwapRows(PRow^[K], K, A_inv, Lbound, Ubound); FSwap(X^[PRow^[K]], X^[K]); end; { Exchange current column (K) with pivot column } if PCol^[K] <> K then SwapCols(PCol^[K], K, A_inv, Lbound, Ubound); { Transform pivot row } A_inv^[K]^[K] := 1.0; for J := Lbound to Ubound do A_inv^[K]^[J] := A_inv^[K]^[J] / Pvt; X^[K] := X^[K] / Pvt; { Transform other rows } for I := Lbound to Ubound do if I <> K then begin T := A_inv^[I]^[K]; A_inv^[I]^[K] := 0.0; for J := Lbound to Ubound do A_inv^[I]^[J] := A_inv^[I]^[J] - T * A_inv^[K]^[J]; X^[I] := X^[I] - T * X^[K]; end; Inc(K); end; { Rearrange inverse matrix } for I := Ubound downto Lbound do if PCol^[I] <> I then begin SwapRows(PCol^[I], I, A_inv, Lbound, Ubound); FSwap(X^[PCol^[I]], X^[I]); end; for J := Ubound downto Lbound do if PRow^[J] <> J then SwapCols(PRow^[J], J, A_inv, Lbound, Ubound); DelIntVector(PRow, Ubound); DelIntVector(PCol, Ubound); GaussJordan := MAT_OK; end; function InvMat(A : PMatrix; Lbound, Ubound : Integer; A_inv : PMatrix) : Integer; var I, J, K : Integer; Pvt, T : Float; PRow, PCol : PIntVector; { Store line and column of pivot } begin DimIntVector(PRow, Ubound); DimIntVector(PCol, Ubound); { Copy A into A_inv } CopyMatrix(A_inv, A, Lbound, Lbound, Ubound, Ubound); K := Lbound; while K <= Ubound do begin { Search for largest pivot in submatrix A_inv[K..Ubound, K..Ubound] } Pvt := A_inv^[K]^[K]; PRow^[K] := K; PCol^[K] := K; for I := K to Ubound do for J := K to Ubound do if Abs(A_inv^[I]^[J]) > Abs(Pvt) then begin Pvt := A_inv^[I]^[J]; PRow^[K] := I; PCol^[K] := J; end; { Pivot too weak ==> quasi-singular matrix } if Abs(Pvt) < MACHEP then begin DelIntVector(PRow, Ubound); DelIntVector(PCol, Ubound); InvMat := MAT_SINGUL; Exit; end; { Exchange current row (K) with pivot row } if PRow^[K] <> K then SwapRows(PRow^[K], K, A_inv, Lbound, Ubound); { Exchange current column (K) with pivot column } if PCol^[K] <> K then SwapCols(PCol^[K], K, A_inv, Lbound, Ubound); { Transform pivot row } A_inv^[K]^[K] := 1.0; for J := Lbound to Ubound do A_inv^[K]^[J] := A_inv^[K]^[J] / Pvt; { Transform other rows } for I := Lbound to Ubound do if I <> K then begin T := A_inv^[I]^[K]; A_inv^[I]^[K] := 0.0; for J := Lbound to Ubound do A_inv^[I]^[J] := A_inv^[I]^[J] - T * A_inv^[K]^[J]; end; Inc(K); end; { Rearrange inverse matrix } for I := Ubound downto Lbound do if PCol^[I] <> I then SwapRows(PCol^[I], I, A_inv, Lbound, Ubound); for J := Ubound downto Lbound do if PRow^[J] <> J then SwapCols(PRow^[J], J, A_inv, Lbound, Ubound); DelIntVector(PRow, Ubound); DelIntVector(PCol, Ubound); InvMat := MAT_OK; end; function Det(A : PMatrix; Lbound, Ubound : Integer) : Float; var D, T : Float; { Partial determinant & multiplier } I, J, K : Integer; { Loop variables } ZeroDet : Boolean; { Flags a null determinant } begin ZeroDet := False; D := 1.0; K := Lbound; { Make the matrix upper triangular } while not(ZeroDet) and (K < Ubound) do begin { If diagonal element is zero then switch rows } if Abs(A^[K]^[K]) < MACHEP then begin ZeroDet := True; I := K; { Try to find a row with a non-zero element in this column } while ZeroDet and (I < Ubound) do begin I := Succ(I); if Abs(A^[I]^[K]) > MACHEP then begin { Switch these two rows } SwapRows(I, K, A, Lbound, Ubound); ZeroDet := False; { Switching rows changes the sign of the determinant } D := - D; end; end; end; if not(ZeroDet) then for I := Succ(K) to Ubound do if Abs(A^[I]^[K]) > MACHEP then begin { Make the K element of this row zero } T := - A^[I]^[K] / A^[K]^[K]; for J := 1 to Ubound do A^[I]^[J] := A^[I]^[J] + T * A^[K]^[J]; end; D := D * A^[K]^[K]; { Multiply the diagonal term into D } Inc(K); end; if ZeroDet then Det := 0.0 else Det := D * A^[Ubound]^[Ubound]; end; function Cholesky(A : PMatrix; Lbound, Ubound : Integer; L : PMatrix) : Integer; var I, J, K : Integer; Sum : Float; begin for K := Lbound to Ubound do begin Sum := A^[K]^[K]; for J := Lbound to K - 1 do Sum := Sum - Sqr(L^[K]^[J]); if Sum <= 0.0 then begin Cholesky := MAT_NOT_PD; Exit; end; L^[K]^[K] := Sqrt(Sum); for I := K + 1 to Ubound do begin Sum := A^[I]^[K]; for J := Lbound to K - 1 do Sum := Sum - L^[I]^[J] * L^[K]^[J]; L^[I]^[K] := Sum / L^[K]^[K]; end; end; Cholesky := MAT_OK; end; function LU_Decomp(A : PMatrix; Lbound, Ubound : Integer) : Integer; const TINY = 1.0E-20; var I, Imax, J, K : Integer; Pvt, T, Sum : Float; V : PVector; begin DimVector(V, Ubound); { Reallocate Index } if Index <> nil then DelIntVector(Index, LastDim); DimIntVector(Index, Ubound); LastDim := Ubound; for I := Lbound to Ubound do begin Pvt := 0.0; for J := Lbound to Ubound do if Abs(A^[I]^[J]) > Pvt then Pvt := Abs(A^[I]^[J]); if Pvt < MACHEP then begin DelVector(V, Ubound); LU_Decomp := MAT_SINGUL; Exit; end; V^[I] := 1.0 / Pvt; end; for J := Lbound to Ubound do begin for I := Lbound to Pred(J) do begin Sum := A^[I]^[J]; for K := Lbound to Pred(I) do Sum := Sum - A^[I]^[K] * A^[K]^[J]; A^[I]^[J] := Sum; end; Pvt := 0.0; for I := J to Ubound do begin Sum := A^[I]^[J]; for K := Lbound to Pred(J) do Sum := Sum - A^[I]^[K] * A^[K]^[J]; A^[I]^[J] := Sum; T := V^[I] * Abs(Sum); if T > Pvt then begin Pvt := T; Imax := I; end; end; if J <> Imax then begin SwapRows(Imax, J, A, Lbound, Ubound); V^[Imax] := V^[J]; end; Index^[J] := Imax; if A^[J]^[J] = 0.0 then A^[J]^[J] := TINY; if J <> Ubound then begin T := 1.0 / A^[J]^[J]; for I := Succ(J) to Ubound do A^[I]^[J] := A^[I]^[J] * T; end; end; DelVector(V, Ubound); LU_Decomp := MAT_OK; end; procedure LU_Solve(A : PMatrix; B : PVector; Lbound, Ubound : Integer; X : PVector); var I, Ip, J, K : Integer; Sum : Float; begin K := Pred(Lbound); CopyVector(X, B, Lbound, Ubound); for I := Lbound to Ubound do begin Ip := Index^[I]; Sum := X^[Ip]; X^[Ip] := X^[I]; if K >= Lbound then for J := K to Pred(I) do Sum := Sum - A^[I]^[J] * X^[J] else if Sum <> 0.0 then K := I; X^[I] := Sum; end; for I := Ubound downto Lbound do begin Sum := X^[I]; if I < Ubound then for J := Succ(I) to Ubound do Sum := Sum - A^[I]^[J] * X^[J]; X^[I] := Sum / A^[I]^[I]; end; end; function SV_Decomp(A : PMatrix; Lbound, Ubound1, Ubound2 : Integer; S : PVector; V : PMatrix) : Integer; label 1, 2, 3; var I, Its, J, JJ, K, L, N : Integer; Anorm, C, F, G, H, Sum, Scale, T, X, Y, Z : Float; R : PVector; begin G := 0.0; Scale := 0.0; Anorm := 0.0; DimVector(R, Ubound2); for I := Lbound to Ubound2 do begin L := I + 1; R^[I] := Scale * G; G := 0.0; Sum := 0.0; Scale := 0.0; if I <= Ubound1 then begin for K := I to Ubound1 do Scale := Scale + Abs(A^[K]^[I]); if Scale <> 0.0 then begin for K := I to Ubound1 do begin A^[K]^[I] := A^[K]^[I] / Scale; Sum := Sum + A^[K]^[I] * A^[K]^[I]; end; F := A^[I]^[I]; G := - Sgn(F) * Sqrt(Sum); H := F * G - Sum; A^[I]^[I] := F - G; if I <> Ubound2 then begin for J := L to Ubound2 do begin Sum := 0.0; for K := I to Ubound1 do Sum := Sum + A^[K]^[I] * A^[K]^[J]; F := Sum / H; for K := I to Ubound1 do A^[K]^[J] := A^[K]^[J] + F * A^[K]^[I]; end; end; for K := I to Ubound1 do A^[K]^[I] := Scale * A^[K]^[I]; end; end; S^[I] := Scale * G; G := 0.0; Sum := 0.0; Scale := 0.0; if (I <= Ubound1) and (I <> Ubound2) then begin for K := L to Ubound2 do Scale := Scale + Abs(A^[I]^[K]); if Scale <> 0.0 then begin for K := L to Ubound2 do begin A^[I]^[K] := A^[I]^[K] / Scale; Sum := Sum + A^[I]^[K] * A^[I]^[K]; end; F := A^[I]^[L]; G := - Sgn(F) * Sqrt(Sum); H := F * G - Sum; A^[I]^[L] := F - G; for K := L to Ubound2 do R^[K] := A^[I]^[K] / H; if I <> Ubound1 then for J := L to Ubound1 do begin Sum := 0.0; for K := L to Ubound2 do Sum := Sum + A^[J]^[K] * A^[I]^[K]; for K := L to Ubound2 do A^[J]^[K] := A^[J]^[K] + Sum * R^[K]; end; for K := L to Ubound2 do A^[I]^[K] := Scale * A^[I]^[K]; end; end; Anorm := FMax(Anorm, Abs(S^[I]) + Abs(R^[I])); end; for I := Ubound2 downto Lbound do begin if I < Ubound2 then begin if G <> 0.0 then begin for J := L to Ubound2 do V^[J]^[I] := (A^[I]^[J] / A^[I]^[L]) / G; for J := L to Ubound2 do begin Sum := 0.0; for K := L to Ubound2 do Sum := Sum + A^[I]^[K] * V^[K]^[J]; for K := L to Ubound2 do V^[K]^[J] := V^[K]^[J] + Sum * V^[K]^[I]; end; end; for J := L to Ubound2 do begin V^[I]^[J] := 0.0; V^[J]^[I] := 0.0; end; end; V^[I]^[I] := 1.0; G := R^[I]; L := I; end; for I := Ubound2 downto Lbound do begin L := I + 1; G := S^[I]; if I < Ubound2 then for J := L to Ubound2 do A^[I]^[J] := 0.0; if G <> 0.0 then begin G := 1.0 / G; if I <> Ubound2 then for J := L to Ubound2 do begin Sum := 0.0; for K := L to Ubound1 do Sum := Sum + A^[K]^[I] * A^[K]^[J]; F := (Sum / A^[I]^[I]) * G; for K := I to Ubound1 do A^[K]^[J] := A^[K]^[J] + F * A^[K]^[I]; end; for J := I to Ubound1 do A^[J]^[I] := A^[J]^[I] * G; end else for J := I to Ubound1 do A^[J]^[I] := 0.0; A^[I]^[I] := A^[I]^[I] + 1.0; end; for K := Ubound2 downto Lbound do begin for Its := 1 to 30 do begin for L := K downto Lbound do begin N := L - 1; if (Abs(R^[L]) + Anorm) = Anorm then goto 2; if (Abs(S^[N]) + Anorm) = Anorm then goto 1; end; 1: T := 1.0; for I := L to K do begin F := T * R^[I]; if (Abs(F) + Anorm) <> Anorm then begin G := S^[I]; H := Pythag(F, G); S^[I] := H; H := 1.0 / H; C := G * H; T := - (F * H); for J := Lbound to Ubound1 do begin Y := A^[J]^[N]; Z := A^[J]^[I]; A^[J]^[N] := (Y * C) + (Z * T); A^[J]^[I] := - (Y * T) + (Z * C); end; end; end; 2: Z := S^[K]; if L = K then begin if Z < 0.0 then begin S^[K] := - Z; for J := Lbound to Ubound2 do V^[J]^[K] := - V^[J]^[K]; end; goto 3 end; if Its = 30 then begin DelVector(R, Ubound2); SV_Decomp := MAT_NON_CONV; Exit; end; X := S^[L]; N := K - 1; Y := S^[N]; G := R^[N]; H := R^[K]; F := ((Y - Z) * (Y + Z) + (G - H) * (G + H)) / (2.0 * H * Y); G := Pythag(F, 1.0); F := ((X - Z) * (X + Z) + H * ((Y / (F + Sgn(F) * Abs(G))) - H)) / X; C := 1.0; T := 1.0; for J := L to N do begin I := J + 1; G := R^[I]; Y := S^[I]; H := T * G; G := C * G; Z := Pythag(F, H); R^[J] := Z; C := F / Z; T := H / Z; F := (X * C) + (G * T); G := - (X * T) + (G * C); H := Y * T; Y := Y * C; for JJ := Lbound to Ubound2 do begin X := V^[JJ]^[J]; Z := V^[JJ]^[I]; V^[JJ]^[J] := (X * C) + (Z * T); V^[JJ]^[I] := - (X * T) + (Z * C); end; Z := Pythag(F, H); S^[J] := Z; if Z <> 0.0 then begin Z := 1.0 / Z; C := F * Z; T := H * Z; end; F := (C * G) + (T * Y); X := - (T * G) + (C * Y); for JJ := Lbound to Ubound1 do begin Y := A^[JJ]^[J]; Z := A^[JJ]^[I]; A^[JJ]^[J] := (Y * C) + (Z * T); A^[JJ]^[I] := - (Y * T) + (Z * C); end end; R^[L] := 0.0; R^[K] := F; S^[K] := X; end; 3: end; DelVector(R, Ubound2); SV_Decomp := MAT_OK; end; procedure SV_SetZero(S : PVector; Lbound, Ubound : Integer; Tol : Float); var Threshold : Float; I : Integer; begin Threshold := Tol * Max(S, Lbound, Ubound); for I := Lbound to Ubound do if S^[I] < Threshold then S^[I] := 0.0; end; procedure SV_Solve(U : PMatrix; S : PVector; V : PMatrix; B : PVector; Lbound, Ubound1, Ubound2 : Integer; X : PVector); var I, J, JJ : Integer; Sum : Float; Tmp : PVector; begin DimVector(Tmp, Ubound2); for J := Lbound to Ubound2 do begin Sum := 0.0; if S^[J] > 0.0 then begin for I := Lbound to Ubound1 do Sum := Sum + U^[I]^[J] * B^[I]; Sum := Sum / S^[J]; end; Tmp^[J] := Sum; end; for J := Lbound to Ubound2 do begin Sum := 0.0; for JJ := Lbound to Ubound2 do Sum := Sum + V^[J]^[JJ] * Tmp^[JJ]; X^[J] := Sum; end; DelVector(Tmp, Ubound2); end; procedure SV_Approx(U : PMatrix; S : PVector; V : PMatrix; Lbound, Ubound1, Ubound2 : Integer; A : PMatrix); var I, J, K : Integer; begin for I := Lbound to Ubound1 do for J := Lbound to Ubound2 do begin A^[I]^[J] := 0.0; for K := Lbound to Ubound2 do if S^[K] > 0.0 then A^[I]^[J] := A^[I]^[J] + U^[I]^[K] * V^[J]^[K]; end; end; function QR_Decomp(A : PMatrix; Lbound, Ubound1, Ubound2 : Integer; R : PMatrix) : Integer; var I, J, K : Integer; Sum : Float; begin for K := Lbound to Ubound2 do begin { Compute the "k"th diagonal entry in R } Sum := 0.0; for I := Lbound to Ubound1 do Sum := Sum + Sqr(A^[I]^[K]); if Sum = 0.0 then begin QR_Decomp := MAT_SINGUL; Exit; end; R^[K]^[K] := Sqrt(Sum); { Divide the entries in the "k"th column of A by the computed "k"th } { diagonal element of R. this begins the process of overwriting A } { with Q . . . } for I := Lbound to Ubound1 do A^[I]^[K] := A^[I]^[K] / R^[K]^[K]; for J := (K + 1) to Ubound2 do begin { Complete the remainder of the row entries in R } Sum := 0.0; for I := Lbound to Ubound1 do Sum := Sum + A^[I]^[K] * A^[I]^[J]; R^[K]^[J] := Sum; { Update the column entries of the Q/A matrix } for I := Lbound to Ubound1 do A^[I]^[J] := A^[I]^[J] - A^[I]^[K] * R^[K]^[J]; end; end; QR_Decomp := MAT_OK; end; procedure QR_Solve(Q, R : PMatrix; B : PVector; Lbound, Ubound1, Ubound2 : Integer; X : PVector); var I, J : Integer; Sum : Float; begin { Form Q'B and store the result in X } for J := Lbound to Ubound2 do begin X^[J] := 0.0; for I := Lbound to Ubound1 do X^[J] := X^[J] + Q^[I]^[J] * B^[I]; end; { Update X with the solution vector } X^[Ubound2] := X^[Ubound2] / R^[Ubound2]^[Ubound2]; for I := (Ubound2 - 1) downto Lbound do begin Sum := 0.0; for J := (I + 1) to Ubound2 do Sum := Sum + R^[I]^[J] * X^[J]; X^[I] := (X^[I] - Sum) / R^[I]^[I]; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/fitexlin.pas���������������������������������������0000755�0001750�0001750�00000010330�11326425446�021612� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITEXLIN.PAS * * Version 1.1 * * (c) J. Debord, August 2000 * ********************************************************************** This unit fits the "exponential + linear" model: y = A.[1 - exp(-k.x)] + B.x ********************************************************************** } unit FitExLin; {$F+} interface uses FMath, Matrices, Stat, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X : Float; B, D : PVector); function FitModel(X, Y : PVector; N : Integer; B : PVector) : Integer; implementation function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } begin FuncName := 'y = A[1 - exp(-k.x)] + B.x'; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 2; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'A'; 1 : ParamName := 'k'; 2 : ParamName := 'B'; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = A B^[1] = k B^[2] = B -------------------------------------------------------------------- } begin RegFunc := B^[0] * (1.0 - Expo(- B^[1] * X)) + B^[2] * X; end; procedure DerivProc(X : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point X with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter. -------------------------------------------------------------------- } var E : Float; begin E := Expo(- B^[1] * X); { exp(-k.x) } D^[0] := 1.0 - E; { dy/dA = 1 - exp(-k.x) } D^[1] := B^[0] * X * E; { dy/dk = A.x.exp(-k.x) } D^[2] := X; { dy/dB = x } end; function FitModel(X, Y : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Computes initial estimates of the regression parameters -------------------------------------------------------------------- Input : N = number of points X, Y = point coordinates Output : B = estimated regression parameters -------------------------------------------------------------------- } var K : Integer; D : Float; begin { B is the slope of the last (linear) part of the curve } K := Round(0.9 * N); if K = N then K := Pred(N); B^[2] := (Y^[N] - Y^[K]) / (X^[N] - X^[K]); { A is the intercept of the linear part } B^[0] := Y^[N] - B^[2] * X^[N]; { Slope of the tangent at origin = B + k.A } K := Round(0.1 * N); if K = 1 then K := 2; D := (Y^[K] - Y^[1]) / (X^[K] - X^[1]); B^[1] := (D - B^[1]) / B^[0]; FitModel := 0; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dmath/fitpower.pas���������������������������������������0000755�0001750�0001750�00000011415�11326425446�021634� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITPOWER.PAS * * Version 1.1 * * (c) J. Debord, August 2000 * ********************************************************************** This unit fits a power function : y = A.x^n ********************************************************************** } unit FitPower; {$F+} interface uses FMath, Matrices, Stat, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X, Y : Float; B, D : PVector); function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; implementation function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function. -------------------------------------------------------------------- } begin FuncName := 'y = A.x^n'; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted. -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted. -------------------------------------------------------------------- } begin LastParam := 1; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter. -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'A'; 1 : ParamName := 'n'; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X. B is the vector of parameters, such that : B^[0] = A B^[1] = n -------------------------------------------------------------------- } begin RegFunc := B^[0] * Power(X, B^[1]); end; procedure DerivProc(X, Y : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point (X,Y) with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter. -------------------------------------------------------------------- } begin D^[0] := Y / B^[0]; { dy/dA = x^n } D^[1] := Y * Log(X); { dy/dk = A.x^n.Ln(x) } end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of a power function by linear regression: Ln(y) = Ln(A) + n.Ln(x) -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- } var X1, Y1 : PVector; { Transformed coordinates } W1 : PVector; { Weights } A : PVector; { Linear regression parameters } V : PMatrix; { Variance-covariance matrix } P : Integer; { Number of points for linear regression } K : Integer; { Loop variable } ErrCode : Integer; { Error code } begin DimVector(X1, N); DimVector(Y1, N); DimVector(W1, N); DimVector(A, 1); DimMatrix(V, 1, 1); P := 0; for K := 1 to N do if (X^[K] > 0.0) and (Y^[K] > 0.0) then begin Inc(P); X1^[P] := Log(X^[K]); Y1^[P] := Log(Y^[K]); W1^[P] := Sqr(Y^[K]); if Method = 1 then W1^[P] := W1^[P] * W^[K]; end; ErrCode := WLinFit(X1, Y1, W1, P, A, V); if ErrCode = MAT_OK then begin B^[0] := Expo(A^[0]); B^[1] := A^[1]; end; FitModel := ErrCode; DelVector(X1, N); DelVector(Y1, N); DelVector(W1, N); DelVector(A, 1); DelMatrix(V, 1, 1); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/old/�����������������������������������������������������0000755�0001750�0001750�00000000000�12360760644�016745� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/old/montecarlo.pas���������������������������������������0000755�0001750�0001750�00000017307�11326425450�021622� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit montecarlo; interface {$H+} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes; procedure LesionMonteCarlo (lBinomial,lTTest,lBM: boolean); implementation uses npmform,filename,turbolesion; procedure RandomGroup(kSamplesPerTest: integer;lImageNames: TStrings;lSymptomRA: SingleP;var lPartImageNames: TStrings; var lPartSymptomRA: SingleP); var lTotal,lInc,lRand,lSwap: integer; lRanOrder: longintP; begin lPartImageNames.Clear; lTotal := lImageNames.Count; if kSamplesPerTest > lTotal then begin showmessage('Monte carlo error: population must be larger than sample size.'); exit; end; //fx(lTOtal); Getmem(lRanOrder,lTotal*sizeof(longint)); for lInc := 1 to lTotal do lRanOrder^[lInc] := lInc; for lInc := lTotal downto 2 do begin lRand := Random(lInc)+1; lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc]; lRanOrder^[lInc] := lSwap; end; for lInc := 1 to kSamplesPerTest do begin lPartImageNames.Add(lImageNames.Strings[lRanOrder^[lInc]-1]);//indexed from 0 lPartSymptomRA^[lInc] := lSymptomRA^[lRanOrder^[lInc]]; end; Freemem(lRanOrder); end; {$DEFINE notanacom} procedure LesionMonteCarlo (lBinomial,lTTest,lBM: boolean); label 666; const kSimSampleSize = 64; knSim = 5; kCrit = 3; {$IFDEF anacom} knControls = 64; {$ENDIF} var lPrefs: TLDMPrefs ; lSim,lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCrit: integer; lPartImageNames,lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lOutName,lFactname,lOutNameSim: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA,lPartSymptomRA: singleP; {$IFDEF anacom} lnControlObservations: integer; lControlSymptomRA: singleP; {$ENDIF} begin //lBinomial := not odd( (Sender as tMenuItem).tag); lPrefs.NULP := true{gNULP false}; if not lBinomial then begin lPrefs.BMtest := lbm;//BMmenu.checked; lPrefs.Ttest := lttest;//ttestmenu.checked; if (not lPrefs.BMtest) and (not lPrefs.ttest) then lPrefs.ttest := true; lPrefs.Ltest:= false; end else begin lPrefs.BMtest := false; lPrefs.Ttest := false; lPrefs.Ltest:= true; end; lPrefs.nCrit := kCrit; lPrefs.nPermute := MainForm.ReadPermute;; lPrefs.Run := 0;{0 except for montecarlo} if (not lBinomial) and (not lTTest) and (not lBM) then begin Showmessage('Error: you need to compute at least on test [options/test menu]'); exit; end; lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? lPartImageNames := TStringList.Create; getmem(lPartSymptomRA,kSimSampleSize*sizeof(single)); {$IFDEF anacom} lnControlObservations := knControls; getmem(lControlSymptomRA,lnControlObservations*sizeof(single)); for lSim := 1 to lnControlObservations do lControlSymptomRA^[lSim] := 5; {$ENDIF} //next, get 1st group if not MainForm.GetVal(lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCrit{,binom},lPredictorList) then begin showmessage('Error with VAL file'); goto 666; end; lTemp4D := CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) or (lnSubjAll < kSimSampleSize) then begin Showmessage('Not enough subjects ('+inttostr(lnSubjAll)+') [sample size is '+inttostr(kSimSampleSize)+']or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; MainForm.SaveHdrDlg.Filename := loutname; lOutName := lOutName+'.nii.gz'; if not MainForm.SaveHdrName ('Base Statistical Map', lOutName) then goto 666; for lFact := 1 to lnFactors do begin lImageNames.clear; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); lnSubj := lImageNames.Count; if lnSubj > 1 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; //randomization loop.... for lSim := 1 to knSim do begin RandomGroup(kSimSampleSize, lImageNames,lSymptomRA, lPartImageNames, lPartSymptomRA); lOutNameSim := AddIndexToFilename(lOutName,lSim); lnCrit := kCrit; MainForm.NPMMsgClear; //Msg(GetKVers); MainForm.NPMMsg('Threads: '+inttostr(gnCPUThreads)); lFactName := lPredictorList.Strings[lFact-1]; lFactName := LegitFilename(lFactName,lFact); MainForm.NPMMsg('Factor = '+lFactname); For lSubj := 1 to kSimSampleSize do MainForm.NPMMsg (lPartImageNames.Strings[lSubj-1] + ' = '+realtostr(lPartSymptomRA^[lSubj],2) ); MainForm.NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); MainForm.NPMMsg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); MainForm.NPMMsg('Number of Lesion maps = '+inttostr(kSimSampleSize)); if not CheckVoxelsGroup(lPartImageNames,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; lPrefs.Run := lSim; if lBinomial then TurboLDM (lPartImageNames, lMaskHdr, lPrefs, lPartSymptomRA, lFactname,lOutNameSim) else begin MainForm.ReportDescriptives(lPartSymptomRA,lnSubj); //TurboLDM (lPartImageNames, lMaskHdr, lPrefs, lPartSymptomRA, lFactname,lOutNameSim); {$IFDEF anacom} AnacomLesionNPMAnalyze (lPartImageNames, lMaskHdr, lnCrit,lSim,lnControlObservations, lPartSymptomRA,lControlSymptomRA, lFactname,lOutNameSim,lPrefs.Ttest,lPrefs.BMtest {lttest,lBM}); {$ENDIF} end; end; //for each simulation... Freemem(lSymptomRA); end; //lnsubj > 1 end; //for each factor if lnSubjAll > 0 then begin Freemem(lMultiSymptomRA); end; 666: lPartImageNames.free; lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; freemem(lPartSymptomRA); {$IFDEF anacom} freemem(lControlSymptomRA); {$ENDIF} DeleteDecompressed4D(lTemp4D); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/old/anacom.pas�������������������������������������������0000755�0001750�0001750�00000061664�11326425450�020722� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit anacom; interface {$H+} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr,filename, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes; //procedure DoAnaCOM; function AnacomLesionNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttestIn,lBMIn: boolean): boolean; implementation uses npmform; {$DEFINE NOTmedianfx} function AnacomLesionNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttestIn,lBMIn: boolean): boolean; label 123,667; var lOutNameMod: string; lPlankImg: byteP; lOutImgSum,lOutImgBM,lOutImgT, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM,lCombinedSymptomRA: singleP; lPos,lPlank,lThread,lnControlsPlusPatients: integer; lVolVox,lMinMask,lMaxMask,lTotalMemory,lnPlanks,lVoxPerPlank, lThreadStart,lThreadEnd,lThreadInc,lnLesion,lnPermute, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT,lBMz, lSum,lThresh,lThreshBonf,lThreshPermute,lThreshNULP :double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; lBM,lttest,lLtest: boolean; lnControlNeg: integer; {$IFDEF medianfx} lmedianFX,lmeanFX,lsummean,lsummedian: double; lmediancount: integer; {$ENDIF} begin lnControlNeg := lnControl; //negative for binomial test lttest := lttestin; lbm := lbmin; if (not (lttest)) and (not (lbm)) then begin lLtest := true; lBM := true; lnControlNeg := -lnControl; end; //lttest:= ttestmenu.checked; //lBM := BMmenu.checked; if lnControl < 1 then begin MainForm.NPMmsg('AnaCom aborted - need data from at least 1 control individual'); exit; end; lnPermute := 0;//MainForm.ReadPermute; MainForm.NPMmsg('Permutations = ' +IntToStr(lnPermute)); MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; MainForm.NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); MainForm.NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) //assumes 1bpp else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; {$IFDEF medianfx} lsummean := 0; lsummedian:= 0; lmediancount := 0; {$ENDIF} for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; lnControlsPlusPatients := lImages.Count+lnControl; createArray64(lObsp,lObs,lnControlsPlusPatients); getmem(lOutImgSum,lVolVox* sizeof(single)); getmem(lOutImgBM,lVolVox* sizeof(single)); getmem(lOutImgT,lVolVox* sizeof(single)); MainForm.InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; end; //sumptom array for lesions AND controls for lPos := 1 to lImages.Count do lObs^[lPos-1] := lSymptomRA^[lPos]; for lPos := 1 to lnControl do lObs^[lPos-1+lImages.Count] := lControlSymptomRA^[lPos]; getmem(lCombinedSymptomRA,lnControlsPlusPatients* sizeof(single)); for lPos := 1 to lnControlsPlusPatients do lCombinedSymptomRA^[lPos] := lObs^[lPos-1]; //next create permuted BM bounds if lBM then begin MainForm.NPMmsg('Generating BM permutation thresholds'); MainForm.Refresh; //for lPos := 1 to lImages.Count do // lObs^[lPos-1] := lSymptomRA^[lPos]; genBMsim (lnControlsPlusPatients, lObs); end; ClearThreadData(gnCPUThreads,lnPermute) ; for lPlank := 1 to lnPlanks do begin MainForm.NPMmsg('Computing plank = ' +Inttostr(lPlank)); MainForm.Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TLesionContinuous.Create (MainForm.ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lnControlNeg,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,nil,lCombinedSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; lThreshPermute := 0; lnVoxTested := SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //next report findings if lnVoxTested < 1 then begin MainForm.NPMmsg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lnCrit)+' patients**'); goto 123; end; MainForm.NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); {$IFDEF medianfx} MainForm.NPMmsg('Average MEAN effect size = ' +realtostr((lsummean/lmediancount),3)); MainForm.NPMmsg('Average MEDIAN effect size = ' +realtostr((lsummedian/lmediancount),3)); {$ENDIF} MainForm.NPMmsg('Only tested voxels with more than '+inttostr(lnCrit)+' lesions'); //Next: save results from permutation thresholding.... //Next: save results from permutation thresholding.... lThreshBonf := MainForm.reportBonferroni('Std',lnVoxTested); //Next: NULPS if lRun > 0 then //terrible place to do this - RAM problems, but need value to threshold maps lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap2 (lImages, lnCrit,lnVoxTested,lPlankImg)); //lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap (lImages, lnCrit)); //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); if (lRun < 1) then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //create new header - subsequent images will use Z-scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lRun < 1) and (Sum2PowerCont(lOutImgSum,lVolVox,lImages.Count)) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; //MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if lttest then begin //save Ttest //next: convert t-scores to z scores if lnControl < 1 then for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lnPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; lThresh := MainForm.reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); lThreshPermute := MainForm.reportPermute('attest',lnPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'attest'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('AnaComthreshtt,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgT))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if lBM then begin //save Mann Whitney lThresh := MainForm.reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); lThreshPermute := MainForm.reportPermute('aBM',lnPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'aBM'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('AnaCOMthreshbm,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgBM))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end; //next: free dynamic memory 123: MainForm.FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgT); freemem(lOutImgBM); freemem(lOutImgSum); freemem(lObsp); freemem(lPlankImg); MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); MainForm.MsgSave(lOutNameMod); MainForm.ProgressBar1.Position := 0; exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; //LesionNPMAnalyze (*function readCSV2 (lFilename: string; lCol1,lCol2: integer; var lnObservations : integer; var ldataRA1,ldataRA2: singlep): boolean; const kHdrRow = 0;//1; kHdrCol = 0;//1; var lNumStr: string; F: TextFile; lTempFloat: double; lCh: char; lnFactors,MaxC,R,C:integer; lError: boolean; begin lError := false; result := false; if not fileexists(lFilename) then begin showmessage('Can not find '+lFilename); exit; end; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); if (R <= (kHdrRow+1)) or (MaxC < (kHdrCol+lCol1)) or (MaxC < (kHdrCol+lCol2)) then begin showmessage('problems reading CSV - not enough columns/rows '+inttostr(lCol1)+' '+inttostr(lCol2)); exit; end; lnObservations := R -kHdrRow ; //-1: first row is header.... lnFactors := MaxC-1;// -1: first column is Y values //fx(lnObservations,lnFactors); //exit; getmem(ldataRA1,lnObservations*sizeof(single)); getmem(ldataRA2,lnObservations*sizeof(single)); //second pass Reset(F); C := 1; MaxC := 0; R := 1; lNumStr := ''; lTempfloat := 0; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin if (R > kHdrRow) and (C > kHdrCol) then begin if ((C-kHdrCol) = lCol1) or ((C-kHdrCol) = lCol2) then begin if lNumStr = '-' then begin lTempFloat := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(lNumStr); if (C-kHdrCol) = lCol1 then ldataRA1^[R-kHdrRow] := lTempFloat else if (C-kHdrCol) = lCol2 then ldataRA2^[R-kHdrRow] := lTempFloat; end; //number end; //col1 or col2 end;// else //R > 1 lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 1; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if (lNumStr <> '') and (C = lnFactors) then begin //unterminated string try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except ldataRA2^[R-1] := lTempFloat; end;//unterminated string //read finel item CloseFile(F); FileMode := 2; //Set file access to read/write result := true; end; *) function readTxt (lFilename: string; var lnObservations : integer; var ldataRA1: singlep): boolean; const kHdrRow = 0;//1; kHdrCol = 0;//1; var lCol1: integer; lNumStr: string; F: TextFile; lTempFloat: double; lCh: char; lnFactors,MaxC,R,C:integer; lError: boolean; begin lCol1:= 1; lError := false; result := false; if not fileexists(lFilename) then begin showmessage('Can not find '+lFilename); exit; end; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); if (R <= (kHdrRow+1)) or (MaxC < (kHdrCol+lCol1)) then begin showmessage('problems reading CSV - not enough columns/rows '); exit; end; lnObservations := R -kHdrRow ; //-1: first row is header.... lnFactors := kHdrCol+lCol1;// -1: first column is Y values //fx(lnObservations,lnFactors); //exit; getmem(ldataRA1,lnObservations*sizeof(single)); //second pass Reset(F); C := 1; MaxC := 0; R := 1; lNumStr := ''; lTempfloat := 0; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin if (R > kHdrRow) and (C > kHdrCol) then begin if ((C-kHdrCol) = lCol1) {or ((C-kHdrCol) = lCol2)} then begin if lNumStr = '-' then begin lTempFloat := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(lNumStr); if (C-kHdrCol) = lCol1 then begin //showmessage(lNumStr); ldataRA1^[R-kHdrRow] := lTempFloat; end; {else if (C-kHdrCol) = lCol2 then ldataRA2^[R-kHdrRow] := lTempFloat;} end; //number end; //col1 or col2 end;// else //R > 1 lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 1; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; //showmessage(lNumStr+' '+inttostr(lnFactors)+' '+inttostr(C)); if (lNumStr <> '') and (C = lnFactors) then begin //unterminated string try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(inttostr(R)+' '+floattostr(lTempFLoat)); ldataRA1^[R] := lTempFloat; end;//unterminated string //read finel item CloseFile(F); FileMode := 2; //Set file access to read/write result := true; end; (*procedure DoAnaCOM; label 666; var lControlFilename: string; lI, lnControlObservations : integer; lControldata: singlep; lBinomial: boolean; lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCrit: integer; lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lOutName,lFactname: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA: singleP; begin npmform.MainForm.memo1.lines.clear; npmform.MainForm.memo1.lines.add('AnaCOM analysis requires TXT/CSV format text file.'); npmform.MainForm.memo1.lines.add('One row per control participant.'); npmform.MainForm.memo1.lines.add('First column is performance of that participant.'); npmform.MainForm.memo1.lines.add('Example file:'); //npmform.MainForm.memo1.lines.add('deficit, voxels'); npmform.MainForm.memo1.lines.add('11'); npmform.MainForm.memo1.lines.add('19'); npmform.MainForm.memo1.lines.add('2'); npmform.MainForm.memo1.lines.add('22'); npmform.MainForm.memo1.lines.add('19'); npmform.MainForm.memo1.lines.add('6'); lControlFilename := 'c:\fx.txt'; if (not readTxt (lControlFilename, lnControlObservations,lControldata)) or (lnControlObservations < 1) then begin showmessage('Error reading file '+lControlFilename); exit; end; npmform.MainForm.memo1.lines.add('Control (n='+inttostr(lnControlObservations)+')performance: '); for lI := 1 to lnControlObservations do begin npmform.MainForm.memo1.lines.add(inttostr(lI)+' '+floattostr(lControldata^[lI])); end; //begin - copy lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? //next, get 1st group if not MainForm.GetVal(lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCrit,{,binom}lPredictorList) then begin showmessage('Error with VAL file'); goto 666; end; lTemp4D := CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) then begin Showmessage('Not enough subjects ('+inttostr(lnSubjAll)+') or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; MainForm.SaveHdrDlg.Filename := loutname; lOutName := lOutName+'.nii.gz'; if not MainForm.SaveHdrName ('Base Statistical Map', lOutName) then exit; for lFact := 1 to lnFactors do begin lImageNames.clear; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); lnSubj := lImageNames.Count; if lnSubj > 1 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; MainForm.NPMmsgClear; MainForm.NPMMsg(MainForm.GetKVers); MainForm.NPMMsg('Threads: '+inttostr(gnCPUThreads)); lFactName := lPredictorList.Strings[lFact-1]; lFactName := LegitFilename(lFactName,lFact); MainForm.NPMMsg('Factor = '+lFactname); For lSubj := 1 to lnSubj do MainForm.NPMMsg (lImageNames.Strings[lSubj-1] + ' = '+realtostr(lSymptomRA^[lSubj],2) ); MainForm.NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); MainForm.NPMMsg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); MainForm.NPMMsg('Number of Lesion maps = '+inttostr(lnSubj)); if not CheckVoxelsGroup(lImageNames,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; MainForm.ReportDescriptives(lSymptomRA,lnSubj); AnacomLesionNPMAnalyze(lImageNames,lMaskHdr,lnCrit,-1,lnControlObservations,lSymptomRA,lControldata,lFactName,lOutname,true {ttest},false{BM}); Freemem(lSymptomRA); end; //lnsubj > 1 end; //for each factor if lnSubjAll > 0 then begin Freemem(lMultiSymptomRA); end; 666: lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); ///end //AnacomLesionNPMAnalyze ( lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttest,lBM: boolean): boolean; freemem(lControldata); end;*) end. ����������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/old/lesion.pas�������������������������������������������0000755�0001750�0001750�00000047300�11326425450�020744� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit lesion; interface {$H+} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes; function LesionNPMAnalyze2 (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnPermute: integer; var lSymptomRA: SingleP;var lFactname,lOutName: string; lttest,lBM: boolean): boolean; function LesionNPMAnalyzeBinomial2 (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lnPermute: integer; var lSymptomRA: SingleP; var lFactname,lOutName: string): boolean; var gNULP,gROI: boolean; implementation uses npmform; {$DEFINE NOTmedianfx} function LesionNPMAnalyze2 (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnPermute: integer; var lSymptomRA: SingleP;var lFactname,lOutName: string; lttest,lBM: boolean): boolean; label 123,667; var lOutNameMod: string; lPlankImg: byteP; lOutImgSum,lOutImgBM,lOutImgT,lOutImgAUC, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP; lPos,lPlank,lThread: integer; lVolVox,lMinMask,lMaxMask,lTotalMemory,lnPlanks,lVoxPerPlank, lThreadStart,lThreadEnd,lThreadInc,lnLesion,//,lnPermute, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT,lBMz, lSum,lThresh,lThreshPermute,lThreshBonf,lThreshNULP :double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; lPlankAllocated: boolean; //lttest,lBM: boolean; {$IFDEF medianfx} lmedianFX,lmeanFX,lsummean,lsummedian: double; lmediancount: integer; {$ENDIF} begin //lttest:= ttestmenu.checked; //lBM := BMmenu.checked; lPlankAllocated := false; //lnPermute := MainForm.ReadPermute; MainForm.NPMmsg('Permutations = ' +IntToStr(lnPermute)); MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; MainForm.NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); MainForm.NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) //assumes 1bpp else getmem(lPlankImg,kPlankSz); lPlankAllocated := true; lStartVox := lMinMask; lEndVox := lMinMask-1; {$IFDEF medianfx} lsummean := 0; lsummedian:= 0; lmediancount := 0; {$ENDIF} for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; createArray64(lObsp,lObs,lImages.Count); getmem(lOutImgSum,lVolVox* sizeof(single)); getmem(lOutImgBM,lVolVox* sizeof(single)); getmem(lOutImgT,lVolVox* sizeof(single)); getmem(lOutImgAUC,lVolVox* sizeof(single)); MainForm.InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; lOutImgAUC^[lPos] := 0; end; //next create permuted BM bounds if lBM then begin MainForm.NPMmsg('Generating BM permutation thresholds'); MainForm.Refresh; for lPos := 1 to lImages.Count do lObs^[lPos-1] := lSymptomRA^[lPos]; genBMsim (lImages.Count, lObs); end; ClearThreadData(gnCPUThreads,lnPermute) ; for lPlank := 1 to lnPlanks do begin MainForm.NPMmsg('Computing plank = ' +Inttostr(lPlank)); MainForm.Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TLesionContinuous.Create (MainForm.ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,0,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA) do //with TLesionContinuous.Create (MainForm.ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,lSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; //freemem(lPlankImg); //lPlankAllocated := false; lThreshPermute := 0; lnVoxTested := SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //next report findings if lnVoxTested < 1 then begin MainForm.NPMmsg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lnCrit)+' patients**'); goto 123; end; MainForm.NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); {$IFDEF medianfx} MainForm.NPMmsg('Average MEAN effect size = ' +realtostr((lsummean/lmediancount),3)); MainForm.NPMmsg('Average MEDIAN effect size = ' +realtostr((lsummedian/lmediancount),3)); {$ENDIF} MainForm.NPMmsg('Only tested voxels with more than '+inttostr(lnCrit)+' lesions'); //Next: save results from permutation thresholding.... lThreshBonf := MainForm.reportBonferroni('Std',lnVoxTested); //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); if lRun < 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //save Area Under Curve lOutNameMod := ChangeFilePostfixExt(lOutName,'rocAUC'+lFactName,'.hdr'); if lRun < 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgAUC,1); //create new header - subsequent images will use Z-scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lRun < 1) and (Sum2PowerCont(lOutImgSum,lVolVox,lImages.Count)) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; if lRun > 0 then //terrible place to do this - RAM problems, but need value to threshold maps lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap2 (lImages, lnCrit,lnVoxTested,lPlankImg)); //MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if lttest then begin //save Ttest //next: convert t-scores to z scores for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lnPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; lThresh := MainForm.reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); lThreshPermute := MainForm.reportPermute('ttest',lnPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'ttest'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('threshtt,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgT))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if lBM then begin //save Brunner Munzel lThresh := MainForm.reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); lThreshPermute := MainForm.reportPermute('BM',lnPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'BM'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('threshbm,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgBM))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end; //next: free dynamic memory 123: MainForm.FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgT); freemem(lOutImgAUC); freemem(lOutImgBM); freemem(lOutImgSum); freemem(lObsp); if lPlankAllocated then freemem(lPlankImg); //Next: NULPS - do this after closing all memory - this is a memory hog if gNULP then lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap (lImages, lnCrit,lnVoxTested)); MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); MainForm.MsgSave(lOutNameMod); MainForm.ProgressBar1.Position := 0; //if lRun > 0 then // AX(freeram,freeram,freeram,freeram,freeram,freeram); exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; //LesionNPMAnalyze function LesionNPMAnalyzeBinomial2 (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lnPermute: integer; var lSymptomRA: SingleP; var lFactname,lOutName: string): boolean; label 123,667; var lVal: single; lOutNameMod: string; lPlankImg: byteP; lOutImgSum,lOutImgL,lOutImgAUC,lDummyImg, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP; lPos,lPlank,lThread,lnDeficit: integer; lTotalMemory,lVolVox,lMinMask,lMaxMask,lnPlanks,lVoxPerPlank, lThreadStart,lThreadInc,lThreadEnd, lnLesion, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT, lSum: double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; begin MainForm.NPMmsg('Permutations = ' +IntToStr(lnPermute)); //lOutName := lMaskHdr.ImgFileName; //if not SaveHdrName ('Statistical Map', lOutName) then exit; MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; MainForm.NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); MainForm.NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) //assumes 1bp else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; createArray64(lObsp,lObs,lImages.Count); getmem(lOutImgSum,lVolVox* sizeof(single)); getmem(lOutImgL,lVolVox* sizeof(single)); getmem(lOutImgAUC,lVolVox* sizeof(single)); MainForm.InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgL^[lPos] := 0; lOutImgAUC^[lPos] := 0; end; ClearThreadDataPvals(gnCPUThreads,lnPermute) ; for lPlank := 1 to lnPlanks do begin MainForm.ProgressBar1.Position := 1; MainForm.NPMmsg('Computing plank = ' +Inttostr(lPlank)); MainForm.Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error //with TLesionBinomial.Create (ProgressBar1,false,true,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,666, lDummyImg,lPlankImg,lOutImgSum,lOutImgL,lDummyImg,lSymptomRA) do with TLesionBinom.Create (MainForm.ProgressBar1,false,true,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,0,lPlankImg,lOutImgSum,lOutImgL,lDummyImg,lOutImgAUC,lSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} inc(gThreadsRunning); MainForm.NPMmsg('Thread ' +Inttostr(gThreadsRunning)+' = '+inttostr(lThreadStart)+'..'+inttostr(lThreadEnd)); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; lnVoxTested := SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); for lPos := 1 to lnPermute do begin if (lPermuteMinT^[lPos] > 1.1) or (lPermuteMinT^[lPos] < -1.1) then lPermuteMinT^[lPos] := 0.5; if (lPermuteMaxT^[lPos] > 1.1) or (lPermuteMaxT^[lPos] < -1.1) then lPermuteMaxT^[lPos] := 0.5; lVal := lPermuteMaxT^[lPos]; lPermuteMaxT^[lPos] := lPermuteMinT^[lPos]; lPermuteMinT^[lPos] := lVal; if lPermuteMaxT^[lPos] < 0 then lPermuteMaxT^[lPos] := -pNormalInv(abs(lPermuteMaxT^[lPos])) else lPermuteMaxT^[lPos] := pNormalInv(lPermuteMaxT^[lPos]); if lPermuteMinT^[lPos] < 0 then lPermuteMinT^[lPos] := -pNormalInv(abs(lPermuteMinT^[lPos])) else lPermuteMinT^[lPos] := pNormalInv(lPermuteMinT^[lPos]); end; if lnVoxTested < 1 then begin MainForm.NPMmsg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lnCrit)+' patients**'); goto 123; end; //next report findings MainForm.NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); MainForm.NPMmsg('Only tested voxels with more than '+inttostr(lnCrit)+' lesions'); //Next: save results from permutation thresholding.... MainForm.reportBonferroni('Std',lnVoxTested); //next: save data //savedata MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //save Area Under Curve lOutNameMod := ChangeFilePostfixExt(lOutName,'rocAUC'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgAUC,1); //future images will store Z-scores... MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); //save power map lnDeficit := 0; for lPos := 1 to lImages.Count do if lSymptomRA^[lPos] = 0 then inc(lnDeficit); if Sum2PowerBinom(lOutImgSum,lVolVox,lImages.Count,lnDeficit) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; //save Liebermeister lOutNameMod := ChangeFilePostfixExt(lOutName,'L'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgL,1); //save end MainForm.reportFDR ('L', lVolVox, lnVoxTested, lOutImgL); MainForm.reportPermute('L',lnPermute,lPermuteMaxT, lPermuteMinT); 123: //next: free dynamic memory MainForm.FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgL); freemem(lOutImgAUC); freemem(lOutImgSum); freemem(lObsp); freemem(lPlankImg); //Next: NULPS - do this at the end, it is a memory hog! if gNULP then MainForm.reportBonferroni('Unique overlap',CountOverlap (lImages, lnCrit,lnVoxTested)); MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); MainForm.MsgSave(lOutNameMod); MainForm.ProgressBar1.Position := 0; exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/lesion_pattern.pas���������������������������������������0000755�0001750�0001750�00000004777�11326425446�021743� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit lesion_pattern; interface uses define_types; Type TLesionPattern = RECORD lowest, lo,hi,highest : int64; end; function SetOrderX (var lObs: Bytep; var lObsCount: integer): TLesionPattern ; function SameOrder(lO1,lO2: TLesionPattern; lObsCount: integer): boolean; function EmptyOrder: TLesionPattern; procedure SetBit(lPos: integer; var lVal: TLesionPattern); const kMaxBit = 63; kMaxBitx2 = 2*kMaxBit; kMaxBitx3 = 3*kMaxBit; kMaxObs = {126}kMaxBit*4; implementation var lPowerRA: array [1..kMaxBit] of int64; procedure SetBit(lPos: integer; var lVal: TLesionPattern); begin if (lPos <= kMaxBit) then lVal.Lowest := lVal.Lowest + lPowerRA[lPos] else if (lPos <= kMaxBitx2) then lVal.Lo := lVal.Lo + lPowerRA[lPos-kMaxBit] else if (lPos <= kMaxBitx3) then lVal.Hi := lVal.Hi + lPowerRA[lPos-kMaxBitx2] else lVal.Highest := lVal.Highest + lPowerRA[lPos-kMaxBitx3]; end; function EmptyOrder: TLesionPattern; begin result.lowest := 0; result.lo := 0; result.hi := 0; result.highest := 0; end; function SameOrder(lO1,lO2: TLesionPattern; lObsCount: integer): boolean; begin result := false; if lObsCount > kMaxObs then exit; if (lO1.lowest = lo2.lowest) and (lO1.highest = lO2.highest) and (lO1.lo = lo2.lo) and (lO1.hi = lO2.hi) then result := true else result := false; end; (*function SetOrder (var lObs: Singlep; var lObsCount: integer): TLesionPattern ; var lPos: integer; begin result := EmptyOrder; if ( lObsCount > kMaxObs) or (lObsCount < 1) then exit; for lPos := 1 to lObsCount do if lObs[lPos] <> 0 then SetBit(lPos,result); end; function SetOrderI (var lObs: LongIntp; var lObsCount: integer): TLesionPattern ; var lPos: integer; begin result := EmptyOrder; if ( lObsCount > kMaxObs) or (lObsCount < 1) then exit; for lPos := 1 to lObsCount do if lObs[lPos] <> 0 then SetBit(lPos,result); end;*) function SetOrderX (var lObs: Bytep; var lObsCount: integer): TLesionPattern ; var lPos: integer; begin result := EmptyOrder; if ( lObsCount > kMaxObs) or (lObsCount < 1) then exit; for lPos := 1 to (lObsCount) do if lObs^[lPos] <> 0 then SetBit(lPos,result); end; var lPowerPos: integer; initialization lPowerRA[1] := 1; for lPowerPos := 2 to kMaxBit do lPowerRA[lPowerPos] := lPowerRA[lPowerPos-1]*2; end. �mricron-0.20140804.1~dfsg.1.orig/npm_precl/xanacom.pas����������������������������������������������0000755�0001750�0001750�00000063310�11326425450�020322� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit anacom; interface {$H+} uses define_types,SysUtils,part,StatThds,statcr,StatThdsUtil,Brunner, DISTR,nifti_img, hdr,filename,Messages, Classes, Graphics, Controls, Forms, Dialogs,StdCtrls,ComCtrls,ExtCtrls,Menus, overlap, ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, upower,firthThds,firth,IniFiles,cpucount,userdir,math, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} regmult,utypes; function AnacomLesionNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttestIn,lBMIn: boolean): boolean; procedure DoAnaCOM; function readTxt (lFilename: string; var lnObservations : integer; var ldataRA1: singlep): boolean; implementation uses npmform; {$DEFINE NOTmedianfx} function AnacomLesionNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttestIn,lBMIn: boolean): boolean; label 123,667; var lOutNameMod: string; lPlankImg: byteP; lOutImgSum,lOutImgBM,lOutImgT, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM,lCombinedSymptomRA: singleP; lPos,lPlank,lThread,lnControlsPlusPatients: integer; lVolVox,lMinMask,lMaxMask,lTotalMemory,lnPlanks,lVoxPerPlank, lThreadStart,lThreadEnd,lThreadInc,lnLesion,lnPermute, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT,lBMz, lSum,lThresh,lThreshBonf,lThreshPermute,lThreshNULP :double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; lSave,lBM,lttest,lLtest: boolean; lnControlNeg: integer; {$IFDEF medianfx} lmedianFX,lmeanFX,lsummean,lsummedian: double; lmediancount: integer; {$ENDIF} begin lSave := true; lnControlNeg := lnControl; //negative for binomial test lttest := lttestin; lbm := lbmin; if (not (lttest)) and (not (lbm)) then begin lLtest := true; lBM := true; lnControlNeg := -lnControl; end; //lttest:= ttestmenu.checked; //lBM := BMmenu.checked; if lnControl < 1 then begin MainForm.NPMmsg('AnaCOM aborted - need data from at least 1 control individual'); exit; end; lnPermute := 0;//MainForm.ReadPermute; MainForm.NPMmsg('Permutations = ' +IntToStr(lnPermute)); MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; MainForm.NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); MainForm.NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) //assumes 1bpp else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; {$IFDEF medianfx} lsummean := 0; lsummedian:= 0; lmediancount := 0; {$ENDIF} for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; lnControlsPlusPatients := lImages.Count+lnControl; createArray64(lObsp,lObs,lnControlsPlusPatients); getmem(lOutImgSum,lVolVox* sizeof(single)); getmem(lOutImgBM,lVolVox* sizeof(single)); getmem(lOutImgT,lVolVox* sizeof(single)); MainForm.InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; end; //sumptom array for lesions AND controls for lPos := 1 to lImages.Count do lObs^[lPos-1] := lSymptomRA^[lPos]; for lPos := 1 to lnControl do lObs^[lPos-1+lImages.Count] := lControlSymptomRA^[lPos]; getmem(lCombinedSymptomRA,lnControlsPlusPatients* sizeof(single)); for lPos := 1 to lnControlsPlusPatients do lCombinedSymptomRA^[lPos] := lObs^[lPos-1]; //next create permuted BM bounds if lBM then begin MainForm.NPMmsg('Generating BM permutation thresholds'); MainForm.Refresh; //for lPos := 1 to lImages.Count do // lObs^[lPos-1] := lSymptomRA^[lPos]; genBMsim (lnControlsPlusPatients, lObs); end; ClearThreadData(gnCPUThreads,lnPermute) ; for lPlank := 1 to lnPlanks do begin MainForm.NPMmsg('Computing plank = ' +Inttostr(lPlank)); MainForm.Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TLesionContinuous.Create (MainForm.ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lnControlNeg,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,nil,lCombinedSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; lThreshPermute := 0; lnVoxTested := SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //next report findings if lnVoxTested < 1 then begin MainForm.NPMmsg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lnCrit)+' patients**'); goto 123; end; MainForm.NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); {$IFDEF medianfx} MainForm.NPMmsg('Average MEAN effect size = ' +realtostr((lsummean/lmediancount),3)); MainForm.NPMmsg('Average MEDIAN effect size = ' +realtostr((lsummedian/lmediancount),3)); {$ENDIF} MainForm.NPMmsg('Only tested voxels with more than '+inttostr(lnCrit)+' lesions'); //Next: save results from permutation thresholding.... //Next: save results from permutation thresholding.... lThreshBonf := MainForm.reportBonferroni('Std',lnVoxTested); //Next: NULPS if lRun > 0 then //terrible place to do this - RAM problems, but need value to threshold maps lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap2 (lImages, lnCrit,lnVoxTested,lPlankImg)); //lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap (lImages, lnCrit)); //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); if (lSave) and (lRun < 1) then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //create new header - subsequent images will use Z-scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lSave) and (lRun < 1) and (Sum2PowerCont(lOutImgSum,lVolVox,lImages.Count)) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; //MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if lttest then begin //save Ttest //next: convert t-scores to z scores if lnControl < 1 then //do not convert t-scores for anaCOM - numbers vary from voxel to voxel... for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lnPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; lThresh := MainForm.reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); lThreshPermute := MainForm.reportPermute('attest',lnPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'attest'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('AnaComthreshtt,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgT))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); if lSave then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if lBM then begin //save Mann Whitney lThresh := MainForm.reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); lThreshPermute := MainForm.reportPermute('aBM',lnPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'aBM'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('AnaCOMthreshbm,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgBM))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); if lSave then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end; //next: free dynamic memory 123: MainForm.FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgT); freemem(lOutImgBM); freemem(lOutImgSum); freemem(lObsp); freemem(lPlankImg); freemem(lCombinedSymptomRA); MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); if lSave then MainForm.MsgSave(lOutNameMod); MainForm.ProgressBar1.Position := 0; exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; //LesionNPMAnalyze (*function readCSV2 (lFilename: string; lCol1,lCol2: integer; var lnObservations : integer; var ldataRA1,ldataRA2: singlep): boolean; const kHdrRow = 0;//1; kHdrCol = 0;//1; var lNumStr: string; F: TextFile; lTempFloat: double; lCh: char; lnFactors,MaxC,R,C:integer; lError: boolean; begin lError := false; result := false; if not fileexists(lFilename) then begin showmessage('Can not find '+lFilename); exit; end; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); if (R <= (kHdrRow+1)) or (MaxC < (kHdrCol+lCol1)) or (MaxC < (kHdrCol+lCol2)) then begin showmessage('problems reading CSV - not enough columns/rows '+inttostr(lCol1)+' '+inttostr(lCol2)); exit; end; lnObservations := R -kHdrRow ; //-1: first row is header.... lnFactors := MaxC-1;// -1: first column is Y values //fx(lnObservations,lnFactors); //exit; getmem(ldataRA1,lnObservations*sizeof(single)); getmem(ldataRA2,lnObservations*sizeof(single)); //second pass Reset(F); C := 1; MaxC := 0; R := 1; lNumStr := ''; lTempfloat := 0; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin if (R > kHdrRow) and (C > kHdrCol) then begin if ((C-kHdrCol) = lCol1) or ((C-kHdrCol) = lCol2) then begin if lNumStr = '-' then begin lTempFloat := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(lNumStr); if (C-kHdrCol) = lCol1 then ldataRA1^[R-kHdrRow] := lTempFloat else if (C-kHdrCol) = lCol2 then ldataRA2^[R-kHdrRow] := lTempFloat; end; //number end; //col1 or col2 end;// else //R > 1 lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 1; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if (lNumStr <> '') and (C = lnFactors) then begin //unterminated string try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except ldataRA2^[R-1] := lTempFloat; end;//unterminated string //read finel item CloseFile(F); FileMode := 2; //Set file access to read/write result := true; end; *) function readTxt (lFilename: string; var lnObservations : integer; var ldataRA1: singlep): boolean; const kHdrRow = 0;//1; kHdrCol = 0;//1; var lCol1: integer; lNumStr: string; F: TextFile; lTempFloat: double; lCh: char; lnFactors,MaxC,R,C:integer; lError: boolean; begin lCol1:= 1; lError := false; result := false; if not fileexists(lFilename) then begin showmessage('Can not find '+lFilename); exit; end; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); if (R <= (kHdrRow+1)) or (MaxC < (kHdrCol+lCol1)) then begin showmessage('problems reading CSV - not enough columns/rows '); exit; end; lnObservations := R -kHdrRow ; //-1: first row is header.... lnFactors := kHdrCol+lCol1;// -1: first column is Y values //fx(lnObservations,lnFactors); //exit; getmem(ldataRA1,lnObservations*sizeof(single)); //second pass Reset(F); C := 1; MaxC := 0; R := 1; lNumStr := ''; lTempfloat := 0; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin if (R > kHdrRow) and (C > kHdrCol) then begin if ((C-kHdrCol) = lCol1) {or ((C-kHdrCol) = lCol2)} then begin if lNumStr = '-' then begin lTempFloat := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(lNumStr); if (C-kHdrCol) = lCol1 then begin //showmessage(lNumStr); ldataRA1^[R-kHdrRow] := lTempFloat; end; {else if (C-kHdrCol) = lCol2 then ldataRA2^[R-kHdrRow] := lTempFloat;} end; //number end; //col1 or col2 end;// else //R > 1 lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 1; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; //showmessage(lNumStr+' '+inttostr(lnFactors)+' '+inttostr(C)); if (lNumStr <> '') and (C = lnFactors) then begin //unterminated string try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(inttostr(R)+' '+floattostr(lTempFLoat)); ldataRA1^[R] := lTempFloat; end;//unterminated string //read finel item CloseFile(F); FileMode := 2; //Set file access to read/write result := not lError; end; procedure DoAnaCOM; label 666; var lControlFilename: string; lI, lnControlObservations : integer; lControldata: singlep; //lBinomial: boolean; lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCrit: integer; lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lOutName,lFactname: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA: singleP; begin npmform.MainForm.memo1.lines.clear; npmform.MainForm.memo1.lines.add('AnaCOM analysis requires TXT/CSV format text file.'); npmform.MainForm.memo1.lines.add('One row per control participant.'); npmform.MainForm.memo1.lines.add('First column is performance of that participant.'); npmform.MainForm.memo1.lines.add('Example file:'); npmform.MainForm.memo1.lines.add('11'); npmform.MainForm.memo1.lines.add('19'); npmform.MainForm.memo1.lines.add('2'); npmform.MainForm.memo1.lines.add('22'); npmform.MainForm.memo1.lines.add('19'); npmform.MainForm.memo1.lines.add('6'); if not MainForm.OpenDialogExecute('Select text file',false,false,'Text file (*.txt)|*.txt;*.csv') then begin showmessage('AnaCOM aborted: Control data file selection failed.'); exit; end; //if not selected lControlFilename := MainForm.OpenHdrDlg.Filename; if (not readTxt (lControlFilename, lnControlObservations,lControldata)) or (lnControlObservations < 1) then begin showmessage('Error reading file '+lControlFilename); exit; end; npmform.MainForm.memo1.lines.add('Control (n='+inttostr(lnControlObservations)+')performance ['+lControlFilename+']'); for lI := 1 to lnControlObservations do npmform.MainForm.memo1.lines.add(inttostr(lI)+' '+floattostr(lControldata^[lI])); //begin - copy lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? //next, get 1st group if not MainForm.GetValX(lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCrit,{,binom}lPredictorList) then begin showmessage('Error with VAL file'); goto 666; end; lTemp4D := CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) then begin Showmessage('AnaCOM error: not enough patients ('+inttostr(lnSubjAll)+') or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st file: '+lMaskName); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; MainForm.SaveHdrDlg.Filename := loutname; lOutName := lOutName+'.nii.gz'; if not MainForm.SaveHdrName ('Base Statistical Map', lOutName) then exit; for lFact := 1 to lnFactors do begin lImageNames.clear; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); lnSubj := lImageNames.Count; if lnSubj > 1 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; MainForm.NPMmsgClear; MainForm.NPMMsg(MainForm.GetKVers); MainForm.NPMMsg('Threads: '+inttostr(gnCPUThreads)); npmform.MainForm.memo1.lines.add('Control (n='+inttostr(lnControlObservations)+')performance ['+lControlFilename+']'); for lI := 1 to lnControlObservations do npmform.MainForm.memo1.lines.add(inttostr(lI)+' '+floattostr(lControldata^[lI])); lFactName := lPredictorList.Strings[lFact-1]; lFactName := LegitFilename(lFactName,lFact); MainForm.NPMMsg('Patient performance, (n= '+inttostr(lnSubj)+') Factor = '+lFactname); For lSubj := 1 to lnSubj do MainForm.NPMMsg (lImageNames.Strings[lSubj-1] + ' = '+realtostr(lSymptomRA^[lSubj],2) ); MainForm.NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); MainForm.NPMMsg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); MainForm.NPMMsg('Number of Lesion maps = '+inttostr(lnSubj)); if not CheckVoxelsGroup(lImageNames,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; MainForm.ReportDescriptives(lSymptomRA,lnSubj); AnacomLesionNPMAnalyze(lImageNames,lMaskHdr,lnCrit,-1,lnControlObservations,lSymptomRA,lControldata,lFactName,lOutname,true {ttest},false{BM}); Freemem(lSymptomRA); end; //lnsubj > 1 end; //for each factor if lnSubjAll > 0 then Freemem(lMultiSymptomRA); 666: lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); freemem(lControldata); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/montecarlo.pas�������������������������������������������0000755�0001750�0001750�00000017273�11326425450�021046� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit montecarlo; interface {$H+} {$DEFINE anacom} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes{$IFDEF anacom} ,anacom{$ENDIF}; procedure LesionMonteCarlo (lBinomial,lTTest,lBM: boolean); implementation uses npmform,filename,turbolesion; procedure RandomGroup(kSamplesPerTest: integer;lImageNames: TStrings;lSymptomRA: SingleP;var lPartImageNames: TStrings; var lPartSymptomRA: SingleP); var lTotal,lInc,lRand,lSwap: integer; lRanOrder: longintP; begin lPartImageNames.Clear; lTotal := lImageNames.Count; if kSamplesPerTest > lTotal then begin showmessage('Monte carlo error: population must be larger than sample size.'); exit; end; Getmem(lRanOrder,lTotal*sizeof(longint)); for lInc := 1 to lTotal do lRanOrder^[lInc] := lInc; for lInc := lTotal downto 2 do begin lRand := Random(lInc)+1; lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc]; lRanOrder^[lInc] := lSwap; end; for lInc := 1 to kSamplesPerTest do begin lPartImageNames.Add(lImageNames.Strings[lRanOrder^[lInc]-1]);//indexed from 0 lPartSymptomRA^[lInc] := lSymptomRA^[lRanOrder^[lInc]]; end; Freemem(lRanOrder); end; procedure LesionMonteCarlo (lBinomial,lTTest,lBM: boolean); label 666; const kSimSampleSize = 64; knSim = 2; kCrit = 3; {$IFDEF anacom} knControls = 64; {$ENDIF} var lPrefs: TLDMPrefs ; lSim,lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCrit: integer; lPartImageNames,lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lOutName,lFactname,lOutNameSim: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA,lPartSymptomRA: singleP; {$IFDEF anacom} lnControlObservations: integer; lControlSymptomRA: singleP; {$ENDIF} begin //lBinomial := not odd( (Sender as tMenuItem).tag); lPrefs.NULP := true{gNULP false}; if not lBinomial then begin lPrefs.BMtest := lbm;//BMmenu.checked; lPrefs.Ttest := lttest;//ttestmenu.checked; if (not lPrefs.BMtest) and (not lPrefs.ttest) then lPrefs.ttest := true; lPrefs.Ltest:= false; end else begin lPrefs.BMtest := false; lPrefs.Ttest := false; lPrefs.Ltest:= true; end; lPrefs.nCrit := kCrit; lPrefs.nPermute := 0;//MainForm.ReadPermute;; lPrefs.Run := 0;{0 except for montecarlo} if (not lBinomial) and (not lTTest) and (not lBM) then begin Showmessage('Error: you need to compute at least on test [options/test menu]'); exit; end; lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? lPartImageNames := TStringList.Create; getmem(lPartSymptomRA,kSimSampleSize*sizeof(single)); {$IFDEF anacom} lnControlObservations := knControls; getmem(lControlSymptomRA,lnControlObservations*sizeof(single)); for lSim := 1 to lnControlObservations do lControlSymptomRA^[lSim] := 1000; {$ENDIF} //next, get 1st group if not MainForm.GetValX(lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCrit{,binom},lPredictorList) then begin showmessage('Error with VAL file'); goto 666; end; lTemp4D := CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) or (lnSubjAll < kSimSampleSize) then begin Showmessage('Not enough subjects ('+inttostr(lnSubjAll)+') [sample size is '+inttostr(kSimSampleSize)+']or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; MainForm.SaveHdrDlg.Filename := loutname; lOutName := lOutName+'.nii.gz'; if not MainForm.SaveHdrName ('Base Statistical Map', lOutName) then goto 666; for lFact := 1 to lnFactors do begin lImageNames.clear; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); lnSubj := lImageNames.Count; if lnSubj > 1 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; //randomization loop.... for lSim := 1 to knSim do begin RandomGroup(kSimSampleSize, lImageNames,lSymptomRA, lPartImageNames, lPartSymptomRA); lOutNameSim := AddIndexToFilename(lOutName,lSim); lnCrit := kCrit; MainForm.NPMMsgClear; //Msg(GetKVers); MainForm.NPMMsg('Threads: '+inttostr(gnCPUThreads)); lFactName := lPredictorList.Strings[lFact-1]; lFactName := LegitFilename(lFactName,lFact); MainForm.NPMMsg('Factor = '+lFactname); For lSubj := 1 to kSimSampleSize do MainForm.NPMMsg (lPartImageNames.Strings[lSubj-1] + ' = '+realtostr(lPartSymptomRA^[lSubj],2) ); MainForm.NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); MainForm.NPMMsg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); MainForm.NPMMsg('Number of Lesion maps = '+inttostr(kSimSampleSize)); if not CheckVoxelsGroup(lPartImageNames,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; lPrefs.Run := lSim; if lBinomial then TurboLDM (lPartImageNames, lMaskHdr, lPrefs, lPartSymptomRA, lFactname,lOutNameSim) else begin MainForm.ReportDescriptives(lPartSymptomRA,lnSubj); TurboLDM (lPartImageNames, lMaskHdr, lPrefs, lPartSymptomRA, lFactname,lOutNameSim); {$IFDEF anacom} AnacomLesionNPMAnalyze (lPartImageNames, lMaskHdr, lnCrit,lSim,lnControlObservations, lPartSymptomRA,lControlSymptomRA, lFactname,lOutNameSim,true,false); {$ENDIF} end; end; //for each simulation... Freemem(lSymptomRA); end; //lnsubj > 1 end; //for each factor if lnSubjAll > 0 then begin Freemem(lMultiSymptomRA); end; 666: lPartImageNames.free; lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; freemem(lPartSymptomRA); {$IFDEF anacom} freemem(lControlSymptomRA); {$ENDIF} DeleteDecompressed4D(lTemp4D); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/xLesionStatThds.pas��������������������������������������0000755�0001750�0001750�00000044527�11354667732�022021� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit LesionStatThds; interface uses SysUtils, ComCtrls,Classes, Graphics, ExtCtrls, define_types,stats,StatThdsUtil,Brunner,lesion_pattern; type TLesionStatThread = class(TThread) private lBarX: TProgressBar; lttestx,lBMx: boolean; lnCritx,lBarPosX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx, lImagesCountx,lControlsx : integer; lPlankImgx:ByteP; lOutImgMnx,lOutImgBMx,lOutImgTx,lOutImgAUCX,lSymptomRAx: SingleP; //lBarX: TProgressBar; procedure DoVisualSwap; protected procedure Execute; override; procedure VisualProg(lPos: Integer); procedure Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg:bytep;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); virtual; abstract; public constructor Create(lBar: TProgressBar;lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg:ByteP;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); end; { Lesion - image reveals value } TLesionContinuous = class(TLesionStatThread ) protected procedure Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: byteP;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); override; end; TLesionBinom = class(TLesionStatThread ) protected procedure Analyze(lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: byteP;lOutImgMn,lOutImgL,lOutImgX,lOutImgAUC,lSymptomRA: SingleP); override; end; implementation (*procedure OutStr(lStr: string); var lOutname: string; f: TextFile; begin lOutname:='c:\fx.txt'; if fileexists(lOutname) then begin { open a text file } AssignFile(f, lOutname); Append(f); Writeln(f, lStr); Flush(f); { ensures that the text was actually written to file } { insert code here that would require a Flush before closing the file } CloseFile(f); end; end; *) Const Two32 = 4294967296.0 ; function GenRandThreaded(lRange: integer; var lRandSeed:comp): integer; //normal random function does not work well when threaded - randseed is changed by each thread const lFactor = $08088405 ; lTerm = 1 ; type lT = array [0..1] of longint ; var lX: extended; begin lRandSeed := lRandSeed*lFactor + lTerm; lT(lRandSeed)[1] := 0 ; // < May'04 was: RS := RS - Trunc(RS/Two32)*Two32 ; lX := lRandSeed/Two32 ; result := trunc((lRange)*lX); end; procedure GenPermuteThreaded (lnSubj: integer; var lOrigOrder,lRanOrder: DoubleP0; var lRandSeed:comp); var lInc,lRand: integer; lSwap: double; begin Move(lOrigOrder^,lRanOrder^,lnSubj*sizeof(double)); for lInc := lnSubj downto 2 do begin lRand := GenRandThreaded(lInc,lRandSeed); lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc-1]; lRanOrder^[lInc-1] := lSwap; end; end; procedure StatPermuteThreaded (lttest,lBM: boolean; lnSubj, lnGroup0,lnPermute,lThread: integer;var lOrigOrder: DoubleP0); var lInc: integer; lOutT,lDF,lBMz: double; lRS: Comp; lRanOrderp: pointer; lRanOrder: Doublep0; begin if (lnSubj < 1) or (lnPermute < 1) then exit; createArray64(lRanOrderp,lRanOrder,lnSubj); lRS := 128; for lInc := 1 to lnPermute do begin GenPermuteThreaded(lnSubj, lOrigOrder,lRanOrder,lRS); //generate random order of participants if lttest then begin TStat2 (lnSubj, lnGroup0, lRanOrder, lOutT); if lOutT > gPermuteMaxT[lThread,lInc] then gPermuteMaxT[lThread,lInc] := lOutT; if lOutT < gPermuteMinT[lThread,lInc] then gPermuteMinT[lThread,lInc] := lOutT; end; //compute ttest if lBM then begin //BMTest (lnSubj, lnGroup0, lRanOrder,lOutT); tBM (lnSubj, lnGroup0, lRanOrder,lBMz,lDF); lBMz := BMzVal (lnSubj, lnGroup0,lBMz,lDF); if lBMz > gPermuteMaxBM[lThread,lInc] then gPermuteMaxBM[lThread,lInc] := lBMz; if lBMz < gPermuteMinBM[lThread,lInc] then gPermuteMinBM[lThread,lInc] := lBMz; end; //compute BM end; freemem(lRanOrderp); end; procedure GenPermuteThreadedBinom (lnSubj: integer; var lOrigOrder,lRanOrder: ByteP0; var lRandSeed:comp); var lInc,lRand: integer; lSwap: byte; begin Move(lOrigOrder^,lRanOrder^,lnSubj); for lInc := lnSubj downto 2 do begin lRand := GenRandThreaded(lInc,lRandSeed); lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc-1]; lRanOrder^[lInc-1] := lSwap; end; end; procedure StatPermuteBinomialThreaded (lnSubj, lnGroup0,lnPermute,lThread: integer;var lOrigOrder: ByteP0); var lInc: integer; lOutP: double; lRS: Comp; lRanOrder: byteP0; begin if (lnSubj < 1) or (lnPermute < 1) then exit; //createArray64(lRanOrderp,lRanOrder,lnSubj); getmem(lRanOrder,lnSubj); lRS := 128; for lInc := 1 to lnPermute do begin GenPermuteThreadedBinom(lnSubj, lOrigOrder,lRanOrder,lRS); //generate random order of participants (*if lChi2 then begin Chi2 (lnSubj, lnGroup0, lRanOrder, lOutT); if lOutT > gPermuteMaxT[lThread,lInc] then gPermuteMaxT[lThread,lInc] := lOutT; if lOutT < gPermuteMinT[lThread,lInc] then gPermuteMinT[lThread,lInc] := lOutT; end; //compute ttest if lLieber then begin*) //Liebermeister2bP (lnSubj, lnGroup0, lRanOrder,lOutP); Liebermeister2bP (lnSubj, lnGroup0, lRanOrder,lOutP); if (lOutP > 0) and (lOutP < gPermuteMinT[lThread,lInc]) then begin //negative correlation //fx(lOutP, gPermuteMinBM[lThread,lInc]); gPermuteMinT[lThread,lInc] := lOutP; end; if (lOutP < 0) and ( lOutP > gPermuteMaxT[lThread,lInc]) then //negative correlation gPermuteMaxT[lThread,lInc] := lOutP; //end; //compute BM end; freemem(lRanOrder); end; procedure TLesionStatThread .DoVisualSwap; begin lBarX.Position := lBarPosX; end; procedure TLesionStatThread .VisualProg(lPos: Integer); begin lBarPosX := lPos; {$IFDEF FPC}Synchronize(@DoVisualSwap); {$ELSE} Synchronize(DoVisualSwap);{$ENDIF} end; constructor TLesionStatThread.Create(lBar: TProgressBar; lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: byteP;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); begin lBarX := lBar; lttestx := lttest; lBMx:= lBM; lThreadX := lThread; lThreadStartX := lThreadStart; lThreadEndX := lThreadEnd; lStartVoxx := lStartVox; lVoxPerPlankx := lVoxPerPlank; lImagesCountX := lImagesCount; lControlsX := lControlsIn; lPlankImgx := lPlankImg; lOutImgMnx := lOutImgMn; lOutImgBMx := lOutImgBM; lOutImgTx := lOutImgT; lOutImgAUCx := lOutImgAUC; lSymptomRAx := lSymptomRA; lnPermuteX := lnPermute; lnCritX := lnCrit; FreeOnTerminate := True; inherited Create(False); end; { The Execute method is called when the thread starts } procedure TLesionStatThread .Execute; begin Analyze(lttestx,lBMx, lnCritX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx,lImagesCountx,lControlsx,lPlankImgX,lOutImgMnx,lOutImgBMx,lOutImgTx,lOutImgAUCx,lSymptomRAx); end; procedure TLesionContinuous.Analyze (lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIN : integer; lPlankImg:bytep;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); //pattern variables const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lPrevZValsT,lPrevZValsBM,lPrevAUCVals: array [1..knPrevPattern] of Single; lPatternPos: integer; lLesionOrderp: bytep; //standard variables var lStr: string; lObstp,lObsp: pointer; lObst,lObs: Doublep0; lT,lBMz,lDF: Double; lObsB: bytep0; lnLesion,lnNoLesion,lPosPct,lPos,lPos2,lPos2Offset,lnControl, lnControlsPlusLesion,lnControlsPlusPatients : integer; begin //statthread //init patterns lnControl := abs(lControlsIn); if lControlsIn < 0 then begin //binomial getmem(lObsB, lImagesCount+lnControl); end; lnControlsPlusPatients := lImagesCount+lnControl; for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; //lMaxLesion := lImagesCount-lnCrit; getmem(lLesionOrderp, lImagesCount *sizeof(byte)); //now init standard variables createArray64(lObsp,lObs,lnControlsPlusPatients); lPosPct := (lThreadEnd-lThreadStart) div 100; //if lThread = 1 then // OutStr( inttostr(lThreadStart)+':'+inttostr(lThreadEnd)); //xxxxx for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; lnNoLesion := 0; for lPos := 1 to lImagesCount do begin if lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2] = 0 then begin //no lesion inc(lnNoLesion); lLesionOrderp^[lPos] := 0; lObs^[lnNoLesion-1] := lSymptomRA^[lPos]; end else begin //lesion inc(lnLesion); lLesionOrderp^[lPos] := 1; //lObs^[lImagesCount-lnLesion] := lSymptomRA^[lPos]; //note: lObs indexed from zero! lObs^[lImagesCount-lPos+lnNoLesion] := lSymptomRA^[lPos]; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) {and (lnLesion <= lMaxLesion)} then begin inc(gnVoxTestedRA[lThread]); //now check if we have seen this precise lesion order recently... lPattern := SetOrderX (lLesionOrderp,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin //lesion pattern is not novel if lttest then lOutImgT^[lPos2Offset] := lPrevZvalsT[lPos]; if lBM then lOutImgBM^[lPos2Offset] := lPrevZvalsBM[lPos]; if lOutImgAUC <> nil then lOutImgAUC^[lPos2Offset] := lPrevAUCvals[lPos]; end else begin //lesion pattern is novel //record novel pattern inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; lPrevPatternRA[lPatternPos] := lPattern; lnControlsPlusLesion := lnControlsPlusPatients; if (lControlsIn > 0) {and (lnLesion > 0)} then begin //anaCOm createArray64(lObstp,lObst,lImagesCount); for lPos := 1 to lImagesCount do lObst^[lPos-1] := lObs^[lPos-1]; for lPos := 1 to lnLesion do lObs^[lPos-1+lnControl] := lObst^[lPos-1+lnNoLesion]; freemem(lObstP); for lPos := 1 to lnControl do lObs^[lPos-1] := lSymptomRA^[lPos+lImagesCount]; lnControlsPlusLesion := lnControl+lnLesion; lnNoLesion := {lnNoLesion +} lnControl; end;//controls (*if lPos2 = 2570879 then begin //xxxx for lPos := 1 to lImagesCount do begin outstr(inttostr(lPos)+'>'+floattostr(lObs^[lPos-1]) ); end; end;*) if lttest then begin if lControlsIn > 0 then begin//anacom TStat2Z (lnControlsPlusLesion, lnControl {lnNoLesion},lObs,lT); (* if lPos2 = 2570879 then begin outstr( floattostr(lT)+ ' '+inttostr(lnControl)); //xxxx for lPos := 1 to lnControlsPlusLesion do begin outstr(inttostr(lPos)+', '+floattostr(lObs^[lPos-1]) ); end; end; *) end else TStat2 (lnControlsPlusLesion, lnNoLesion, lObs,lT); lOutImgT^[lPos2Offset] := lT; lPrevZValsT[lPatternPos] := lT; end; if lBM then begin tBM (lnControlsPlusLesion, lnNoLesion, lObs,lBMz,lDF); lBMz := BMzVal (lnControlsPlusPatients, lnNoLesion,lBMz,lDF); lOutImgBM^[lPos2Offset] := lBMz; lPrevZValsBM[lPatternPos] := lBMz; end; if lOutImgAUC <> nil then begin lOutImgAUC^[lPos2Offset] := continROC (lnControlsPlusLesion, lnNoLesion, lObs); lPrevAUCVals[lPatternPos] := lOutImgAUC^[lPos2Offset]; end; StatPermuteThreaded (lttest,lBM,lImagesCount, lnNoLesion,lnPermute,lThread, lObs); end; //novel lesion pattern end; //in brain mask - compute end; //for each voxel freemem(lObsP); freemem(lLesionOrderp); if lControlsIn < 0 then //binomial freemem(lObsB); end; procedure TLesionBinom.Analyze (lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: bytep;lOutImgMn,lOutImgL,lOutImgX,lOutImgAUC,lSymptomRA: SingleP); //procedure TLesionBinomial.Analyze (lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgL,lOutImgX,lSymptomRA: SingleP); //pattern variables const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lPrevZValsL ,lPrevAUCVals: array [1..knPrevPattern] of Single; lPatternPos: integer; lLesionOrderp: bytep; //standard variables var //lObsp: pointer; //lObs: Doublep0; lPrevZVals lObs: ByteP0; lAUC,lZ: Double; lnLesion,lPosPct,lPos,lPos2,lPos2Offset,lnVoxTested: integer; begin //Binomial StatThread //init patterns for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; getmem(lLesionOrderp, lImagesCount *sizeof(byte)); //now init standard variables //createArray64(lObsp,lObs,lImagesCount); getmem(lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; for lPos := 1 to lImagesCount do begin if ((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]) = 0 then begin //no lesion lObs^[lImagesCount-lPos+lnLesion] := round(lSymptomRA^[lPos]); lLesionOrderp^[lPos] := 0; end else begin //lesion inc(lnLesion); lLesionOrderp^[lPos] := 1; lObs^[lnLesion-1] := round(lSymptomRA^[lPos]); //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) then begin inc(gnVoxTestedRA[lThread]); //next check patterns //x lPattern := SetOrderX (lLesionOrderp,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin //lesion pattern is not novel //if lChi2 then // lOutImgX^[lPos2Offset] := lPrevZvalsX[lPos]; //if lLieber then lOutImgL^[lPos2Offset] := lPrevZvalsL[lPos]; if lOutImgAUC <> nil then lOutImgAUC^[lPos2Offset] := lPrevAUCvals[lPos]; end else begin //lesion pattern is novel //record novel pattern inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; lPrevPatternRA[lPatternPos] := lPattern; {if lChi2 then begin Chi2 (lImagesCount, lnLesion, lObs,lT); lOutImgX^[lPos2Offset] := lT;//lT; lPrevZValsX[lPatternPos] := lT; end; if lLieber then begin} Liebermeister2b(lImagesCount, lnLesion, lObs,lAUC,lZ); if lOutImgAUC <> nil then lOutImgAUC^[lPos2Offset] := lAUC; lPrevAUCVals[lPatternPos] := lAUC; lOutImgL^[lPos2Offset] := lZ; lPrevZValsL[lPatternPos] := lZ; //end; StatPermuteBinomialThreaded (lImagesCount, lnLesion,lnPermute,lThread, lObs); end; end; //in brain mask - compute end; //for each voxel freemem(lObs); freemem(lLesionOrderp) end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npmform.lrs����������������������������������������������0000755�0001750�0001750�00000015171�12147221422�020364� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TMainForm','FORMDATA',[ 'TPF0'#9'TMainForm'#8'MainForm'#4'Left'#3#5#2#6'Height'#3#162#1#3'Top'#3'A'#1 +#5'Width'#3#30#2#13'ActiveControl'#7#5'Memo1'#7'Caption'#6#22'Non-Parametric' +' Mapping'#12'ClientHeight'#3#162#1#11'ClientWidth'#3#30#2#4'Menu'#7#9'MainM' +'enu1'#7'OnClose'#7#9'FormClose'#8'OnCreate'#7#10'FormCreate'#6'OnShow'#7#8 +'FormShow'#8'Position'#7#14'poScreenCenter'#10'LCLVersion'#6#8'0.9.30.2'#0#5 +'TMemo'#5'Memo1'#4'Left'#2#0#6'Height'#3#137#1#3'Top'#2#0#5'Width'#3#30#2#5 +'Align'#7#8'alClient'#10'ScrollBars'#7#10'ssAutoBoth'#8'TabOrder'#2#0#0#0#6 +'TPanel'#6'Panel1'#4'Left'#2#0#6'Height'#2#25#3'Top'#3#137#1#5'Width'#3#30#2 +#5'Align'#7#8'alBottom'#12'ClientHeight'#2#25#11'ClientWidth'#3#30#2#8'TabOr' +'der'#2#1#0#12'TProgressBar'#12'ProgressBar1'#4'Left'#2#1#6'Height'#2#23#3'T' +'op'#2#1#5'Width'#3#28#2#5'Align'#7#8'alClient'#8'TabOrder'#2#0#0#0#0#9'TMai' +'nMenu'#9'MainMenu1'#4'left'#2#8#3'top'#2#8#0#9'TMenuItem'#5'File1'#7'Captio' +'n'#6#4'File'#0#9'TMenuItem'#9'SaveText1'#7'Caption'#6#12'Save text...'#7'On' +'Click'#7#14'Savetext1Click'#0#0#9'TMenuItem'#5'Exit1'#7'Caption'#6#4'Exit'#7 +'OnClick'#7#10'Exit1Click'#0#0#0#9'TMenuItem'#5'Edit1'#7'Caption'#6#4'Edit'#0 +#9'TMenuItem'#5'Copy1'#7'Caption'#6#4'Copy'#7'OnClick'#7#10'Copy1Click'#0#0#0 +#9'TMenuItem'#5'VLSM1'#7'Caption'#6#4'VLSM'#0#9'TMenuItem'#24'BinomialAnalys' +'islesions1'#7'Caption'#6'''Binary images, binary groups (lesions) '#8'Short' +'Cut'#3'B@'#7'OnClick'#7#14'LesionBtnClick'#0#0#9'TMenuItem!Binaryimagescont' +'inuousgroupsfast1'#3'Tag'#2#1#7'Caption'#6'(Binary images, continuous groou' +'ps (vlsm)'#8'ShortCut'#3'L@'#7'OnClick'#7#14'LesionBtnClick'#0#0#9'TMenuIte' +'m'#28'PenalizedLogisticRegerssion1'#7'Caption'#6#31'Binary images, multiple' +' factors'#7'OnClick'#7'!PenalizedLogisticRegerssion1Click'#0#0#9'TMenuItem' +#12'ROIanalysis1'#7'Caption'#6#12'ROI analysis'#7'OnClick'#7#17'ROIanalysis1' +'Click'#0#0#9'TMenuItem'#7'Design1'#7'Caption'#6#9'Design...'#8'ShortCut'#3 +'D@'#7'OnClick'#7#12'Design1Click'#0#0#0#9'TMenuItem'#4'VBM1'#7'Caption'#6#3 +'VBM'#0#9'TMenuItem'#22'ContinuousanalysisVBM1'#7'Caption'#6'&Continuous ima' +'ges, binary groups (VBM)'#8'ShortCut'#3'V@'#7'OnClick'#7#8'NPMclick'#0#0#9 +'TMenuItem'#11'PairedTMenu'#7'Caption'#6#22'Paired Measures T-test'#7'OnClic' +'k'#7#16'PairedTMenuClick'#0#0#9'TMenuItem'#15'MultipleRegress'#7'Caption'#6 +#23'Multiple WLS Regression'#7'OnClick'#7#20'MultipleRegressClick'#0#0#9'TMe' +'nuItem'#13'SingleRegress'#7'Caption'#6#21'Single WLS Regression'#7'OnClick' +#7#18'SingleRegressClick'#0#0#9'TMenuItem'#9'MenuItem3'#7'Caption'#6#22'Dual' +' image correlation'#7'OnClick'#7#26'DualImageCorrelation1Click'#0#0#0#9'TMe' +'nuItem'#8'Options1'#7'Caption'#6#7'Options'#0#9'TMenuItem'#13'Permutations1' +#7'Caption'#6#12'Permutations'#0#9'TMenuItem'#2'N0'#9'AutoCheck'#9#7'Caption' +#6#4'None'#7'Checked'#9#10'GroupIndex'#2'{'#9'RadioItem'#9#7'OnClick'#7#14'r' +'adiomenuclick'#0#0#9'TMenuItem'#5'N1000'#3'Tag'#3#232#3#9'AutoCheck'#9#7'Ca' +'ption'#6#4'1000'#10'GroupIndex'#2'{'#9'RadioItem'#9#7'OnClick'#7#14'radiome' +'nuclick'#0#0#9'TMenuItem'#5'N2000'#3'Tag'#3#208#7#9'AutoCheck'#9#7'Caption' +#6#4'2000'#10'GroupIndex'#2'{'#9'RadioItem'#9#7'OnClick'#7#14'radiomenuclick' +#0#0#9'TMenuItem'#5'N3000'#3'Tag'#3#184#11#9'AutoCheck'#9#7'Caption'#6#4'300' +'0'#10'GroupIndex'#2'{'#9'RadioItem'#9#7'OnClick'#7#14'radiomenuclick'#0#0#9 +'TMenuItem'#5'N4000'#3'Tag'#3#160#15#9'AutoCheck'#9#7'Caption'#6#4'4000'#10 +'GroupIndex'#2'{'#9'RadioItem'#9#7'OnClick'#7#14'radiomenuclick'#0#0#0#9'TMe' +'nuItem'#6'Tests1'#7'Caption'#6#5'Tests'#0#9'TMenuItem'#9'ttestmenu'#7'Capti' +'on'#6#6't-test'#7'OnClick'#7#13'testmenuclick'#0#0#9'TMenuItem'#6'BMmenu'#7 +'Caption'#6#14'Brunner Munzel'#7'Checked'#9#7'OnClick'#7#13'testmenuclick'#0 +#0#0#9'TMenuItem'#8'Threads1'#7'Caption'#6#7'Threads'#0#9'TMenuItem'#2'T1'#9 +'AutoCheck'#9#7'Caption'#6#1'1'#7'Checked'#9#10'GroupIndex'#3#131#0#9'RadioI' +'tem'#9#7'OnClick'#7#12'threadChange'#0#0#9'TMenuItem'#2'T2'#9'AutoCheck'#9#7 +'Caption'#6#1'2'#10'GroupIndex'#3#131#0#9'RadioItem'#9#7'OnClick'#7#12'threa' +'dChange'#0#0#9'TMenuItem'#2'T3'#9'AutoCheck'#9#7'Caption'#6#1'3'#10'GroupIn' +'dex'#3#131#0#9'RadioItem'#9#7'OnClick'#7#12'threadChange'#0#0#9'TMenuItem'#2 +'T4'#9'AutoCheck'#9#7'Caption'#6#1'4'#10'GroupIndex'#3#131#0#9'RadioItem'#9#7 +'OnClick'#7#12'threadChange'#0#0#9'TMenuItem'#2'T7'#9'AutoCheck'#9#7'Caption' +#6#1'7'#10'GroupIndex'#3#131#0#9'RadioItem'#9#7'OnClick'#7#12'threadChange'#0 +#0#9'TMenuItem'#2'T8'#9'AutoCheck'#9#7'Caption'#6#1'8'#10'GroupIndex'#3#131#0 +#9'RadioItem'#9#7'OnClick'#7#12'threadChange'#0#0#9'TMenuItem'#3'T15'#9'Auto' +'Check'#9#7'Caption'#6#2'15'#10'GroupIndex'#3#131#0#9'RadioItem'#9#7'OnClick' +#7#12'threadChange'#0#0#9'TMenuItem'#3'T16'#9'AutoCheck'#9#7'Caption'#6#2'16' +#10'GroupIndex'#3#131#0#9'RadioItem'#9#7'OnClick'#7#12'threadChange'#0#0#0#0 +#9'TMenuItem'#10'Utilities1'#7'Caption'#6#9'Utilities'#0#9'TMenuItem'#9'niin' +'iigz1'#7'Caption'#6#14'nii -> .nii.gz'#7'OnClick'#7#14'niiniigz1Click'#0#0#9 ,'TMenuItem'#9'Variance1'#7'Caption'#6#14'Variance image'#7'OnClick'#7#14'Var' +'iance1Click'#0#0#9'TMenuItem'#14'Makemeanimage2'#3'Tag'#2#1#7'Caption'#6#19 +'Make binarized mean'#7'OnClick'#7#19'Makemeanimage1Click'#0#0#9'TMenuItem' +#14'Makemeanimage1'#7'Caption'#6#21'Make mean/StDev image'#7'OnClick'#7#19'M' +'akemeanimage1Click'#0#0#9'TMenuItem'#21'SingleSubjectZScores1'#7'Caption'#6 +#22'Single Subject Z-Score'#7'OnClick'#7#26'SingleSubjectZScores1Click'#0#0#9 +'TMenuItem'#24'IntensitynormalizationA1'#3'Tag'#2#1#7'Caption'#6#25'Intensit' +'y normalization A'#7'OnClick'#7#13'Balance1Click'#0#0#9'TMenuItem'#8'Balanc' +'e1'#7'Caption'#6#25'Intensity normalization B'#7'OnClick'#7#13'Balance1Clic' +'k'#0#0#9'TMenuItem PhysiologicalArtifactCorrection1'#7'Caption'#6#24'Physio' +'logical Correction'#7'OnClick'#7'%PhysiologicalArtifactCorrection1Click'#0#0 +#9'TMenuItem'#20'Countlesionoverlaps1'#7'Caption'#6#21'Count lesion overlaps' +#7'OnClick'#7#25'Countlesionoverlaps1Click'#0#0#9'TMenuItem'#4'FCE1'#7'Capti' +'on'#6#4'TFCE'#7'OnClick'#7#9'FCE1Click'#0#0#0#9'TMenuItem'#5'Help1'#7'Capti' +'on'#6#4'Help'#7'Visible'#8#0#9'TMenuItem'#6'About1'#7'Caption'#6#5'About'#7 +'OnClick'#7#11'About1Click'#0#0#0#0#11'TSaveDialog'#10'SaveHdrDlg'#11'Filter' +'Index'#2#0#4'left'#2#8#3'top'#2'('#0#0#11'TOpenDialog'#10'OpenHdrDlg'#11'Fi' +'lterIndex'#2#0#4'left'#2#8#3'top'#2'H'#0#0#0 ]); �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/valformat.pas��������������������������������������������0000755�0001750�0001750�00000023646�11326425450�020677� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit valformat; {$H+} interface uses {$IFNDEF UNIX} Windows,{Registry,ShlObj,}{$ENDIF} Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Grids, Menus, ToolWin, ComCtrls, Buttons,Clipbrd, StdCtrls, Spin,define_types,npmform; const {$IFDEF FPC} kNaN = -maxint; {$ELSE} kNaN : double = 1/0; {$ENDIF} kVALNativeSignatureBase = '#Version:'; kValMaxVers = 1; //version 0 = 3D, version 1 = 4D, version 2 not yet supported kTxtExt = '.txt'; kVALNativeExt = '.val'; kValFilter = 'Text description (*.val)|*.val'; function RowColPos (lRow,lCol,lnCol: integer): integer; function OpenValFile (var lFilename,lTemplateName:string; var lnRow,lnCol,lnColWObs,lnCritPct: integer; var lDesignUnspecified : boolean; var lPredictorList,lFileList:TStringList; var lDoublePtr: Pointer): boolean; function GetValCore (var lVALFilename:string; var lnSubj, lnFactors: integer; var lSymptomRA: singleP; var lImageNames: TStrings; var lCrit,lCritPct: integer; {lBinomial : boolean;} var lPredictorList: TStringList):boolean; implementation procedure MsgX (lStr: string); begin //output something here showmessage(lStr); end; function VALNativeSignature (lStr: string): boolean; var lP,lLen: integer; lVers: string; begin result := false; lLen := length(lStr); if lLen < (length(kVALNativeSignatureBase)+1) then exit; for lP := 1 to length(kVALNativeSignatureBase) do if lStr[lP] <> kVALNativeSignatureBase[lP] then exit; //VAL format, but can we read this version? for lP := (length(kVALNativeSignatureBase)+1) to lLen do lVers := lVers + lStr[lP]; if strtoint(lVers) <= kValMaxVers then result := true; end; function ReadTabStr (var lStr: string; var lPos: integer): string; var lLen: integer; begin result := ''; if lPos < 1 then lPos := 1; lLen := length(lStr); while (lPos <= lLen) and (lStr[lPos] <> kTab) do begin result := result + lStr[lPos]; inc(lPos); end; inc(lPos); end; function RowColPos (lRow,lCol,lnCol: integer): integer; begin result := ((lRow-1{alfa})*lnCol)+lCol; end; //Replicates Readln, but works for Unix files... Delphi 4's readln fails for non-MSDOS EOLs procedure ReadlnX (var F: TextFile; var lResult: string); var lCh: char; begin lResult := ''; while not Eof(F) do begin Read(F, lCh); if (lCh in [#10,#13]) then begin if lResult <> '' then begin //Showmessage(lResult); exit; end; end else lResult := lResult + lCh; end; end; //ReadlnX function OpenValFile (var lFilename,lTemplateName:string; var lnRow,lnCol,lnColwObs,lnCritPct: integer; var lDesignUnspecified : boolean; var lPredictorList,lFileList:TStringList; var lDoublePtr: Pointer): boolean; var lNumStr,lStr,lExt,lPrevNumStr,lCmdStr: string; F: TextFile; lTempFloat: double; lCh: char; lPos,MaxC,R,C:integer; lDoubleBuf: DoubleP; lError: boolean; lDecimalSep: char; begin lnRow := 0; lnCol := 0; result := false; if not fileexists(lFilename) then exit; lError:= false; lnCritPct := 0; lExt := StrLower(PChar(extractfileext(lFilename))); if (lExt = kTxtExt) or (lExt = kVALNativeExt) then else begin Showmessage('This version is unable to recognize the extension of the file: '+lFilename); exit; end; lDecimalSep := DecimalSeparator; DecimalSeparator := '.'; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; if lExt = kVALNativeExt then begin ReadlnX(F,lStr);//Version if not VALNativeSignature(lStr) then begin showmessage('This software can not read this file. Perhaps you need to upgrade your software. The first line should read "'+kVALNativeSignatureBase+'x" where "x" is <'+inttostr(kValMaxVers+1)); CloseFile(F); FileMode := 2; //Set file access to read/write exit; end; lDesignUnspecified := false; lStr := '#'; while (length(lStr)> 0) and (lStr[1] = '#') and (not Eof(F)) do begin ReadlnX(F,lStr); lPos := 0; //start at beginning of line lCmdStr := ReadTabStr(lStr,lPos); if lCmdStr = '#Template' then lTemplateName := ReadTabStr(lStr,lPos); if lCmdStr = '#CritPct' then lnCritPct := StrToInt(ReadTabStr(lStr,lPos)); end; if (length(lStr)> 0) and (lStr[1] = '#') then showmessage(lCmdStr); end else begin lnCritPct := 0; lDesignUnspecified := true; lTemplateName := '-'; end;//Ext=native version Reset(F); while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9]) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); lnRow:= R; lnCol := MaxC-1; lnColWObs := lnCol+1; getmem(lDoublePtr,(lnRow*lnColWObs* sizeof(double))+16); {$IFDEF FPC} lDoubleBuf := align(lDoublePtr,16); {$ELSE} //lDoubleBuf := DoubleP((integer(lDoublePtr) and $FFFFFFF0)+16); lDoubleBuf := DoubleP($fffffff0 and (integer(lDoublePtr)+15)); {$ENDIF} for C := 1 to (lnRow*lnColWObs) do lDoubleBuf^[C] := 0; //Second pass: fill values Reset(F); C := 0; MaxC := 0; R := 1; lNumStr := ''; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9]) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin //read current entry if R = 1 then begin //1st Row if C > 0 then lPredictorList.Add( lNumStr) end else if C = 0 then begin //1st Row //showmessage(lNumStr); lFileList.Add( lNumStr) end else begin //note: below -1 as we strip first header row for predictor names if lNumStr = '-' then begin lDoubleBuf^[RowColPos (R-1{ july 06 alfa},C,lnColWObs)] := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading VAL file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := knan; end; end; lDoubleBuf^[RowColPos (R-1{ july 06 alfa},C,lnColWObs)] := lTempFloat;//DataGrid.Cells[ C, kMaxFactors+R-1 ] := (lNumStr) ; end; end; lPrevNumStr := lNumStr; lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if (lNumStr <> '') and (C>0) then //alfa read data immediately prior to EOF lDoubleBuf^[RowColPos (R-1{alfa},C,lnColWObs)] := strtofloat(lNumStr); CloseFile(F); FileMode := 2; //Set file access to read/write result := true; DecimalSeparator := lDecimalSep; //fx(lPredictorList.Count,lnCol); if lPredictorList.Count < lnCol then begin for C := (lPredictorList.Count+1) to lnCol do lPredictorList.Add('Predictor'+inttostr(C)); end; end; function GetValCore (var lVALFilename:string; var lnSubj, lnFactors: integer; var lSymptomRA: singleP; var lImageNames: TStrings; var lCrit,lCritPct: integer; {lBinomial : boolean;} var lPredictorList: TStringList):boolean; //warning: you MUST free lPredictorList var lTemplateName: string; lnRow,lCol,lnColWObs,lInc,lRow: integer; lDesignUnspecified : boolean; lFileList:TStringList; lInRA: DoubleP0; lInP: Pointer; begin lPredictorList := TStringList.Create; result := false; lnSubj := 0; if not Fileexists(lVALFilename) then begin MsgX('NPM aborted: VAL file selection failed:' +lValFilename); exit; end; //if not selected lFileList := TStringList.Create; //MsgX( 'VAL filename: '+lVALFilename); if not OpenValFile (lVALFilename,lTemplateName, lnRow,lnFactors,lnColWObs,lCritPct, lDesignUnspecified,lPredictorList,lFileList, lInP) then exit; if lnRow > 1 then begin lnSubj := lnRow -1; //top row is predictor {$IFDEF FPC} lInRA := align(lInP,16); {$ELSE} lInRA := DoubleP0($fffffff0 and (integer(lInP)+15)); {$ENDIF} getmem(lSymptomRA,lnSubj*lnFactors* sizeof(single)); for lCol := 1 to lnFactors do begin for lRow := 1 to lnSubj do begin lSymptomRA^[lRow+ ((lCol-1)*lnSubj)] := lInRA^[(lRow*lnColWObs)-lnColWObs-1+lCol]; end; end; for lInc := 1 to lnSubj do lImageNames.add(ExtractFileDirWithPathDelim(lVALFilename)+lFileList.Strings[lInc-1]); //end reverse end; //for lRow = each subject lFileList.free; Freemem(lInP); lCrit := round( (lnSubj*lCritPct)/100); result := true; end; end. ������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npm.dpr��������������������������������������������������0000755�0001750�0001750�00000001254�10772470554�017500� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������program npm; uses Forms, npmform in 'npmform.pas' {MainForm}, stats in 'stats.pas', spread in 'spread.pas' {SpreadForm}, design in 'design.pas' {DesignForm}, valformat in 'valformat.pas', ReadInt in 'ReadInt.pas' {ReadIntForm}, firth in 'firth.pas', roc in 'roc.pas', prefs in 'prefs.pas'; {$R *.RES} {$IFNDEF FPC} {$R windowsxp.res} {$ENDIF} begin Application.Initialize; Application.Title := 'NPM'; Application.CreateForm(TMainForm, MainForm); Application.CreateForm(TSpreadForm, SpreadForm); Application.CreateForm(TDesignForm, DesignForm); Application.CreateForm(TReadIntForm, ReadIntForm); Application.Run; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/tfce_clustering.pas��������������������������������������0000755�0001750�0001750�00000017743�12111137054�022056� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit tfce_clustering; //USED by stats to select only regions with a given number of connected/contiguous voxels {$IFDEF FPC} {$mode delphi}{$H+} {$ENDIF} interface uses {$IFNDEF UNIX} Windows, {$ELSE} LCLType, LCLintf, {$ENDIF} define_types,dialogs,SysUtils,nifti_hdr,nifti_img, math; //procedure FindClusters (lMultiBuf: SingleP; lXdim, lYDim, lZDim, lThreshClusterSz: integer; lMinNeg, lMinPos: single); //function ClusterTFCE (var lHdr: TMRIcroHdr; lThreshClusterSz: integer; lThresh: double ): boolean; function doTFCE (var lHdr: TNIFTIhdr; lImg: SingleP; NumConn: integer; H, E, minT, deltaT: single ): boolean; //mimics FSL's function "TFCE" in newimagefns.h function doTFCEbothPolarities (var lHdr: TNIFTIhdr; lImg: SingleP; NumConn: integer; H, E, minT, deltaT, minNegT, NegdeltaT: single; var maxTFCE, maxNegTFCE: single): boolean; //both polarities computes TFCE for both positive and negative values implementation uses npmform; procedure countClusterSize (lX,lY,lZ, lnumConnIn: integer; var lClusterBuff: LongIntP); //input CountImg is volume X*Y*Z where voxels are either 0 or 1 // output: CountImg voxels report number of connected neighbors const lClusterSign = 1; //input CountImg has this value set to 1 lClusterFillValue = -1; //impossible cluster size - used to denote actively growing cluster var lQHead,lV,lXY, lXYZ,lClusterSz, lQTail,lnumConn,lI,lNeighbor: integer; lQra: LongIntP; ConnOffset : ARRAY [1..26] of integer; procedure InitConn; begin //first 6 share face ConnOffset[1] := -1;//L ConnOffset[2] := 1; //R ConnOffset[3] := -lX; //A ConnOffset[4] := lX; //P ConnOffset[5] := -lXY;//I ConnOffset[6] := lXY;//S if lnumConnIn < 7 then begin lnumConn := 6; exit; end; //share edge //..check plane above ConnOffset[7] := (lXY-1); //left ConnOffset[8] := (lXY+1); //right ConnOffset[9] := (lXY-lX); //up ConnOffset[10] := (lXY+lX); //down //..check plane below ConnOffset[11] := (-lXY-1); //left ConnOffset[12] := (-lXY+1); //right ConnOffset[13] := (-lXY-lX); //up ConnOffset[14] := (-lXY+lX); //down //..check diagonals of current plane ConnOffset[15] := (-lX-1); //up, left ConnOffset[16] := (-lX+1); //up, right ConnOffset[17] := (+lX-1); //down, left ConnOffset[18] := (+lX+1); //down, right if lnumConnIn < 19 then begin lnumConn := 18; exit; end; //share corner //..check plane above ConnOffset[19] := (lXY-1-lX); //left ConnOffset[20] := (lXY-1+lX); //right ConnOffset[21] := (lXY+1-lX); //up ConnOffset[22] := (lXY+1+lX); //down //..check plane BELOW ConnOffset[23] := (-lXY-1-lX); //left ConnOffset[24] := (-lXY-1+lX); //right ConnOffset[25] := (-lXY+1-lX); //up ConnOffset[26] := (-lXY+1+lX); //down lnumConn := 26; end; //InitConn begin lXY := lX * lY; lXYZ := lX*lY*lZ; InitConn; if lXYZ < 1 then exit; GetMem(lQra,lXYZ * sizeof(longint) ); //check every voxel to see if it is isolated for lV := 1 to lXYZ do begin if (lClusterBuff^[lV]=lClusterSign) then begin //new cluster detected lClusterSz := 1; lQHead := 1; lQTail := 1; lQra^[lQTail] := lV; lClusterBuff^[lV] := lClusterFillValue; while (lQHead >= lQTail) do begin //RetirePixel: lQTail incremented once, lQHead is incremented 0..nummConn for lI := 1 to lnumConn do begin lNeighbor := lQra^[lQTail]+ConnOffset[lI]; if (lClusterBuff^[lNeighbor]=lClusterSign) then begin//add item inc(lQHead); inc(lClusterSz); lClusterBuff^[lNeighbor] := lClusterFillValue; lQra^[lQHead] := lNeighbor; end; //if new item detected end; //for each connector inc(lQTail); //done with this pixel end; //while items in Queue for lI := lV to lXYZ do if (lClusterBuff^[lI]=lClusterFillValue) then lClusterBuff^[lI] := lClusterSz; end; //new item found end; //for each voxel freemem(lQra); end; procedure ZeroFaces (var lHdr: TNIFTIhdr; lImg: SingleP ); var lV,lX,lY,lZ,lZi,lYi,lXi: integer; begin lX := lHdr.Dim[1]; lY := lHdr.Dim[2]; lZ := lHdr.Dim[3]; if (lX < 3) or (lY < 3) or (lZ < 3) then exit; for lV := 1 to (lX*lY) do lImg[lV] := 0; //bottom slice for lV := ((lX*lY*lZ)-(lX*lY)) to (lX*lY*lZ) do lImg[lV] := 0; //top slice //left side lV := 1; for lZi := 1 to lZ do begin for lYi := 1 to lY do begin lImg[lV] := 0; lV := lV+lX; end; end; //right side lV := lX; for lZi := 1 to lZ do begin for lYi := 1 to lY do begin lImg[lV] := 0; lV := lV+lX; end; end; //anterior for lZi := 1 to lZ do begin lV := (lZi-1) * lX*lY; for lXi := 1 to lX do begin lV := lV+1; lImg[lV] := 0; end; end; //posterior for lZi := 1 to lZ do begin lV := (lZi-1) * lX*lY; lV := lV + ((lY-1) *lX); for lXi := 1 to lX do begin lV := lV+1; lImg[lV] := 0; end; end; end; function doTFCEbothPolarities (var lHdr: TNIFTIhdr; lImg: SingleP; NumConn: integer; H, E, minT, deltaT, minNegT, NegdeltaT: single; var maxTFCE, maxNegTFCE: single): boolean; var lV,lXYZ,lX,lY,lZ: integer; lNegImg: SingleP; begin result := false; lX := lHdr.Dim[1]; lY := lHdr.Dim[2]; lZ := lHdr.Dim[3]; lXYZ := lX*lY*lZ; if lXYZ < 1 then exit; getmem(lNegImg,lXYZ*sizeof(single)); for lV := 1 to lXYZ do lNegImg[lV] := -lImg[lV]; doTFCE (lHdr, lImg, NumConn, H, E, minT, deltaT); maxTFCE :=lImg[lV]; for lV := 1 to lXYZ do if (maxTFCE < lImg[lV]) then maxTFCE:= lImg[lV]; doTFCE (lHdr, lNegImg, NumConn, H, E, abs(minNegT), abs(NegdeltaT)); maxNegTFCE :=lImg[lV]; for lV := 1 to lXYZ do if (maxNegTFCE < lNegImg[lV]) then maxNegTFCE:= lNegImg[lV]; maxNegTFCE := -maxNegTFCE; for lV := 1 to lXYZ do begin if (lNegImg[lV] > 0) then lImg[lV] := -lNegImg[lV]; end; freemem(lNegImg); end; function doTFCE (var lHdr: TNIFTIhdr; lImg: SingleP; NumConn: integer; H, E, minT, deltaT: single ): boolean; const kSteps = 100; label 777; var lV,lXYZ,lX,lY,lZ: integer; maxval, lThresh, ThreshPowerHxdh, dh: single; lThreshImg: SingleP; lCountImg: LongIntP; lStartTime: DWord; begin lX := lHdr.Dim[1]; lY := lHdr.Dim[2]; lZ := lHdr.Dim[3]; lStartTime := GetTickCount; result := false;//assume failure lXYZ := lX*lY*lZ; if lXYZ < 1 then exit; //E := 0.5; //0.5 //H := 2;//2 getmem(lThreshImg,lXYZ*sizeof(single)); getmem(lCountImg,lXYZ*sizeof(longint)); ZeroFaces (lHdr, lImg ); maxval := lImg[1]; for lV := 1 to lXYZ do begin lThreshImg[lV] := lImg[lV]; if lImg[lV] > maxval then maxval := lImg[lV]; lImg[lV] := 0; //initialize sum map to zero end; if (maxval <= 0) then goto 777; if (maxval < minT) then goto 777; if (deltaT = 0) then dh := (maxval-minT) / kSteps else dh := deltaT; MainForm.NPMmsg('max = '+floattostr(maxval)+' deltaT = '+floattostr(dh)); lThresh := minT+dh; while lThresh < maxval do begin for lV := 1 to lXYZ do begin if (lThreshImg[lV] <= lThresh) then lCountImg[lV] := 0 else lCountImg[lV] := 1; end; countClusterSize (lX,lY,lZ,NumConn, lCountImg); ThreshPowerHxdh := power(lThresh,H)*dh; for lV := 1 to lXYZ do if (lCountImg[lV] > 0) then lImg[lV] := lImg[lV] + (exp(E*ln(lCountImg[lV])) * ThreshPowerHxdh); //faster than power (*for lV := 1 to lXYZ do if (lCountImg[lV] > 0) then lImg[lV] := lImg[lV] + (power(lCountImg[lV],E) * ThreshPowerHxdh); *) lThresh := lThresh + dh; end; 777: MainForm.NPMmsg('Time = '+inttostr(GetTickCount - lStartTime)); freemem(lCountImg); freemem(lThreshImg); result := true; //report success! end; end. �����������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/ReadFloat.dfm��������������������������������������������0000755�0001750�0001750�00000001252�10737134244�020520� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �TREADFLOATFORM�0��TPF0TReadFloatForm ReadFloatFormLeftTop BorderStylebsDialogCaptionReal number required ClientHeightG ClientWidthColor clBtnFace Font.CharsetDEFAULT_CHARSET Font.Color clWindowText Font.Height Font.Name MS Sans Serif Font.Style �OldCreateOrderPositionpoScreenCenter PixelsPerInch` TextHeight �TLabelReadFloatLabelLeft�TopWidthKHeight AlignmenttaRightJustifyCaptionEnter a number ��TButtonOKBtnLeftXTop(WidthKHeightCaptionOK ModalResultTabOrder�OnClick OKBtnClick�� TRxSpinEdit ReadFloatEditLeft0Top WidthyHeight ButtonKind bkStandardDecimal ValueTypevtFloatTabOrder���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/prefs.pas������������������������������������������������0000755�0001750�0001750�00000022734�11477144230�020021� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit prefs; {$H+} interface uses inifiles, define_types,SysUtils,classes,turbolesion; function DoLesion (var lPrefs: TLDMPrefs): boolean; procedure SetDefaultPrefs (var lPrefs: TLDMPrefs); procedure ReadParamStr; implementation uses nifti_img, hdr,nifti_hdr, valformat,StatThdsUtil,filename,npmform; procedure MsgX(lStr: string); begin MainForm.NPMmsg(lStr); end; procedure ClearMsgX; begin MainForm.NPMmsgClear end; procedure SetDefaultPrefs (var lPrefs: TLDMPrefs); begin //lPrefs.unusedbool := true; lPrefs.tTest := true; lPrefs.BMtest := false; lPrefs.Ltest := false; lPrefs.nPermute := 0; lPrefs.CritPct := -1;//use default in val file lPrefs.ExplicitMaskName := ''; lPrefs.ValFilename := ''; lPrefs.Outname := ''; end; (*function CheckBool (lPref, lFlag: integer): boolean; //check if Flag is in lPref. For example, if Flag is 1 then returns true for all odd lPrefs begin result := (lPref and lFlag) = lFlag; end; *) function noVariance (lRA: singlep; lnSubj: integer): boolean; var lI : integer; begin result := false; if lnSubj < 2 then exit; for lI := 2 to lnSubj do if lRA^[1] <> lRA^[lI] then exit; result := true; end; function DoLesion (var lPrefs: TLDMPrefs): boolean; label 666; var lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCritV,lCritPctV: integer; lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lFactname: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA: singleP; begin if (not lPrefs.BMtest) and (not lPrefs.ttest) and (not lPrefs.LTest) then begin MsgX('Error: you need to compute at least on test [options/test menu]'); exit; end; lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? if not GetValCore(lPrefs.ValFilename, lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCritV,lCritPctV,lPredictorList) then begin MsgX('Error with VAL file'); goto 666; end; if lPrefs.critPct < 0 then //-1 denotes using the values specified in the VAL file lPrefs.critPct := lCritPctV; lTemp4D := CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) then begin MsgX('Not enough subjects ('+inttostr(lnSubjAll)+') or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin MsgX('Error reading 1st mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin MsgX('Mask file size too small.'); goto 666; end; if (lPrefs.OutName = '') or (not DirExists(extractfiledir(lPrefs.Outname))) then begin lPrefs.Outname := extractfiledir(lPrefs.ValFilename)+pathdelim+'results.nii.gz'; MsgX('Output stored as '+lPrefs.Outname); end; for lFact := 1 to lnFactors do begin ClearMsgX; MsgX(MainForm.GetKVers); lImageNames.clear; for lSubj := 1 to lnSubjAll do if (not lPrefs.LTest) or (lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] = 0) OR (lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] = 1) THEN begin {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); end else begin MsgX('Data rejected: behavior must be zero or one for binomial test '+lImageNamesAll.Strings[lSubj-1]); end; lnSubj := lImageNames.Count; if lnSubj > 2 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do begin if (not lPrefs.LTest) or (lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] = 0) OR (lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] = 1) THEN begin {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; //valid value end; //not binomial, or 1/0 end; //for each subject MsgX('Threads: '+inttostr(gnCPUThreads)); lFactName := lPredictorList.Strings[lFact-1]; lFactName := LegitFilename(lFactName,lFact); MsgX('Factor = '+lFactname); For lSubj := 1 to lnSubj do MsgX (lImageNames.Strings[lSubj-1] + ' = '+realtostr(lSymptomRA^[lSubj],2) ); MsgX('Total voxels = '+inttostr(lMaskVoxels)); lPrefs.nCrit := round( (lnSubj*lPrefs.CritPct)/100); MsgX('Only testing voxels damaged in at least '+inttostr(lPrefs.nCrit)+' individual[s]'); MsgX('Number of Lesion maps = '+inttostr(lnSubj)); if not CheckVoxelsGroupX(lImageNames,lMaskHdr {lMaskVoxels}) then begin MsgX('Error: File dimensions differ from mask.'); goto 666; end; if noVariance (lSymptomRA,lnSubj) then MsgX('Error no variability in behavioral data ') else TurboLDM (lImageNames, lMaskHdr, lPrefs, lSymptomRA, lFactname,lPrefs.OutName); Freemem(lSymptomRA); end else begin MsgX('At least 2 individuals required to compute statistics for '+lPredictorList.Strings[lFact-1]); end; //lnsubj > 2 end; //for each factor if lnSubjAll > 0 then begin Freemem(lMultiSymptomRA); end; 666: lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); end; procedure ShowHelp; begin MsgX('usage ''npm [options] -o resultsfilname valfilename'' '); MsgX(' Options '); MsgX(' -c: critical percent 0..100 '); MsgX(' -p: permutations 0..4000 '); MsgX(' -t: Test [1=Liebermeister, 2=TTest, 4=BMtest, 6=t&BMtests'); MsgX(' -o: Output filename'); MsgX('examples:'); MsgX(' npm -c 25 -p 1000 -o c:\results.nii.gz c:\mri\data.val'); MsgX(' npm -c 25 -o "c:\program files\results.hdr" c:\mri\data.val'); end; procedure ReadParamStr; var lStr: String; I,lError: integer; lCommandChar: Char; lSingle: single; lHelpShown: boolean; lPrefs: TLDMPrefs; begin if (ParamCount < 1) then exit; SetDefaultPrefs(lPrefs); lHelpShown := false; lStr := paramstr(0); lStr := extractfilename(lStr); lStr := string(StrUpper(PChar(lStr))) ; if (ParamCount > 0) then begin I := 0; repeat lStr := ''; repeat inc(I); if I = 1 then lStr := ParamStr(I) else begin if lStr <> '' then lStr := lStr +' '+ ParamStr(I) else lStr := ParamStr(I); end; if (length(lStr)>1) and (lStr[1] = '-') and (ParamCount > I) then begin //special command //-z= zoom, -f= format [png,jpeg,bmp], -o= output directory lCommandChar := UpCase(lStr[2]); inc(I); lStr := ParamStr(I); lStr := string(StrUpper(PChar(lStr))) ; case lCommandChar of 'C','P','T': begin //CritPct Val(lStr,lSingle,lError); if lError = 0 then begin if lCommandChar = 'C' then lPrefs.CritPct := round(lSingle) else if lCOmmandChar = 'P' then lPrefs.nPermute := round(lSingle) else if lCOmmandChar = 'T' then begin case round(lSingle) of 1: begin lPrefs.LTest := true; lPrefs.Ttest := false; lPrefs.BMtest := false; end; 2: begin lPrefs.LTest := false; lPrefs.Ttest := true; lPrefs.BMtest := false; end; 4: begin lPrefs.LTest := false; lPrefs.Ttest := false; lPrefs.BMtest := true; end; 6: begin lPrefs.LTest := false; lPrefs.Ttest := true; lPrefs.BMtest := true; end; //1=Liebermeister, 2=TTest, 4=BMtest, 6=t&BMtests end;//xxx end; end; //not lError end; //C= CritPct,P=permutations,T=test 'O': begin //output filename lPrefs.OutName :=lStr; end; end; //case lStr[2] lStr := ''; end; //special command until (I=ParamCount) or (fileexists(lStr)) {or (gAbort)}; if fileexists(lStr) then begin //lStr := GetLongFileName(lStr); lPrefs.ValFilename := lStr; //if lPrefs.OutName = '' then // lPrefs.Outname := extractfiledir(paramstr(0))+pathdelim+'results.nii.gz'; MsgX ('output ' + lPrefs.Outname); MsgX ('val file: '+lPrefs.ValFilename); DoLesion(lPrefs); MainForm.close; end else begin MsgX('Error: unable to find '+lStr); if not lHelpShown then Showhelp; lHelpShown := true; end; until I >= ParamCount; end else begin ShowHelp; end;{param count > 0} end; end. ������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/ReadInt.dfm����������������������������������������������0000755�0001750�0001750�00000001204�10621133136�020171� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �TREADINTFORM�0n��TPF0 TReadIntForm ReadIntFormLeft9Top� BorderStylebsDialogCaptionInteger required ClientHeightI ClientWidthColor clBtnFace Font.CharsetDEFAULT_CHARSET Font.Color clWindowText Font.Height Font.Name MS Sans Serif Font.Style �OldCreateOrderPositionpoScreenCenter PixelsPerInch` TextHeight �TLabel ReadIntLabelLeftTopWidthKHeight AlignmenttaRightJustifyCaptionEnter a number �� TSpinEdit ReadIntEditLefthTop WidthYHeightMaxValue�MinValue�TabOrderValue���TButtonOKBtnLeftXTop(WidthKHeightCaptionOK ModalResultTabOrder�OnClick OKBtnClick�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/ReadFloat.pas��������������������������������������������0000755�0001750�0001750�00000002031�11326425450�020526� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit ReadFloat; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, RXSpin; type TReadFloatForm = class(TForm) OKBtn: TButton; ReadFloatLabel: TLabel; ReadFloatEdit: TRxSpinEdit; function GetFloat(lStr: string; lMin,lDefault,lMax: double): double; procedure OKBtnClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var ReadFloatForm: TReadFloatForm; implementation {$R *.DFM} function TReadFloatForm.GetFloat(lStr: string; lMin,lDefault,lMax: double): double; begin //result := lDefault; ReadFloatLabel.caption := lStr+' ['+floattostr(lMin)+'..'+floattostr(lMax)+']'; ReadFloatEdit.MinValue := lMin; ReadFloatEdit.MaxValue := lMax; ReadFloatEdit.Value := lDefault; ReadFloatForm.ShowModal; result := ReadFloatEdit.Value; end; procedure TReadFloatForm.OKBtnClick(Sender: TObject); begin ReadFloatForm.ModalResult := mrOK; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/design.lrs�����������������������������������������������0000755�0001750�0001750�00000005733�11540170650�020164� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TDesignForm','FORMDATA',[ 'TPF0'#11'TDesignForm'#10'DesignForm'#4'Left'#3#225#1#6'Height'#3#207#0#3'Top' +#3#179#0#5'Width'#3'|'#2#18'HorzScrollBar.Page'#3'{'#2#18'VertScrollBar.Page' +#3#206#0#13'ActiveControl'#7#4'AVal'#11'BorderStyle'#7#8'bsDialog'#7'Caption' +#6#6'Design'#12'ClientHeight'#3#207#0#11'ClientWidth'#3'|'#2#21'Constraints.' +'MaxHeight'#3#207#0#20'Constraints.MaxWidth'#3'|'#2#21'Constraints.MinHeight' +#3#207#0#20'Constraints.MinWidth'#3'|'#2#9'Font.Name'#6#13'MS Sans Serif'#8 +'OnCreate'#7#10'FormCreate'#8'Position'#7#14'poScreenCenter'#10'LCLVersion'#6 +#8'0.9.28.2'#0#6'TLabel'#6'Label4'#4'Left'#2#4#6'Height'#2#18#3'Top'#2#8#5'W' +'idth'#2'F'#7'Caption'#6#10'Predictors'#11'ParentColor'#8#0#0#6'TLabel'#6'La' +'bel5'#4'Left'#2'L'#6'Height'#2#18#3'Top'#2#8#5'Width'#2'r'#7'Caption'#6#15 +'Predictor Names'#11'ParentColor'#8#0#0#6'TLabel'#6'Label1'#4'Left'#2#12#6'H' +'eight'#2#18#3'Top'#2'{'#5'Width'#2'Q'#7'Caption'#6#12'Participants'#11'Pare' +'ntColor'#8#0#0#6'TLabel'#13'TemplateLabel'#4'Left'#3#148#0#6'Height'#2#18#3 +'Top'#2'_'#5'Width'#2'p'#7'Caption'#6#15'C:\template.img'#11'ParentColor'#8#0 +#0#6'TLabel'#6'Label2'#4'Left'#2#12#6'Height'#2#18#3'Top'#3#168#0#5'Width'#3 +#7#1#7'Caption'#6'%Ignore voxels damaged in less than N%'#11'ParentColor'#8#0 +#0#7'TButton'#5'OKBtn'#4'Left'#3#15#2#6'Height'#2#25#3'Top'#3#168#0#5'Width' +#2'K'#25'BorderSpacing.InnerBorder'#2#4#7'Caption'#6#2'OK'#11'ModalResult'#2 +#1#8'TabOrder'#2#0#0#0#9'TSpinEdit'#4'AVal'#4'Left'#2#12#6'Height'#2#27#3'To' +'p'#2'%'#5'Width'#2'F'#8'MaxValue'#2'c'#8'MinValue'#2#1#8'OnChange'#7#10'AVa' +'lChange'#8'TabOrder'#2#1#5'Value'#2#2#0#0#11'TStringGrid'#11'ALevelNames'#4 +'Left'#2'b'#6'Height'#2'*'#3'Top'#2#30#5'Width'#3#15#2#8'ColCount'#2#2#9'Fix' +'edCols'#2#0#9'FixedRows'#2#0#7'Options'#11#15'goFixedVertLine'#15'goFixedHo' +'rzLine'#10'goVertLine'#19'goDrawFocusSelected'#9'goEditing'#0#8'RowCount'#2 +#1#10'ScrollBars'#7#12'ssHorizontal'#8'TabOrder'#2#2#16'TitleFont.Height'#2 +#245#14'TitleFont.Name'#6#13'MS Sans Serif'#7'OnEnter'#7#16'ALevelNamesEnter' +#6'OnExit'#7#15'ALevelNamesExit'#0#0#9'TCheckBox'#17'LesionCovaryCheck'#4'Le' +'ft'#3#255#0#6'Height'#2#21#3'Top'#2'{'#5'Width'#3#11#1#7'Caption'#6'"Automa' +'tically Covary Lesion Volume'#8'TabOrder'#2#5#7'Visible'#8#0#0#7'TButton'#9 +'AddMRIBtn'#4'Left'#2']'#6'Height'#2#25#3'Top'#2'v'#5'Width'#3#129#0#25'Bord' +'erSpacing.InnerBorder'#2#4#7'Caption'#6#13'Select Images'#7'OnClick'#7#14'A' +'ddMRIBtnClick'#8'TabOrder'#2#4#0#0#7'TButton'#11'TemplateBtn'#4'Left'#2#12#6 +'Height'#2#25#3'Top'#2'Y'#5'Width'#3#129#0#25'BorderSpacing.InnerBorder'#2#4 +#7'Caption'#6#15'Select Template'#7'OnClick'#7#16'TemplateBtnClick'#8'TabOrd' +'er'#2#3#0#0#9'TSpinEdit'#11'CritPctEdit'#4'Left'#3'0'#1#6'Height'#2#27#3'To' +'p'#3#162#0#5'Width'#2'L'#8'OnChange'#7#10'AValChange'#8'TabOrder'#2#6#5'Val' +'ue'#2#1#0#0#0 ]); �������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/design.pas�����������������������������������������������0000755�0001750�0001750�00000013005�11540170650�020136� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit design; interface uses {$IFNDEF FPC} //Utils, {$ELSE} LResources, {$ENDIF} //{$IFNDEF Unix} Windows,{$ENDIF} Buttons, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Spin, Grids,nifti_hdr; type String10= String[10]; { TDesignForm } TDesignForm = class(TForm) OKBtn: TButton; AVal: TSpinEdit; Label4: TLabel; Label5: TLabel; ALevelNames: TStringGrid; LesionCovaryCheck: TCheckBox; AddMRIBtn: TButton; Label1: TLabel; TemplateBtn: TButton; TemplateLabel: TLabel; CritPctEdit: TSpinEdit; Label2: TLabel; //procedure LRsetup (var NumColumns,Vars,L1,L2,L3: integer; var OK: boolean); procedure AValChange(Sender: TObject); procedure FormCreate(Sender: TObject); procedure ALevelNamesEnter(Sender: TObject); procedure ALevelNamesExit(Sender: TObject); procedure AddMRIBtnClick(Sender: TObject); procedure TemplateBtnClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var DesignForm: TDesignForm; implementation uses npmform,spread,hdr; {$IFNDEF FPC} {$R *.DFM} {$ENDIF} const kMaxColumns = 16; {for ANOVA} //maxElements = kMaxColumns; {ANOVA} MaxLen = 12; //kCR = chr (13); //kTab = chr(9); kVALImgFilter = 'Image (*.hdr;*.nii;*.voi)|*.hdr;*.nii;*.nii.gz;*.voi'; procedure TDesignForm.AValChange(Sender: TObject); {$IFDEF FPC} var lOrig,lP: integer; begin lOrig := ALevelNames.ColCount; DesignForm.Caption := inttostr(AVal.Value); ALevelNames.ColCount := AVal.Value; if AVal.value > lOrig then for lP := lOrig to (AVal.value-1) do AlevelNames.Cells[lP,0] := 'Pred'+inttostr(lP+1); end; {$ELSE} begin ALevelNames.ColCount := AVal.Value; end; {$ENDIF} procedure TDesignForm.FormCreate(Sender: TObject); var lC: integer; begin ALevelNames.ColCount := 16 ; AlevelNames.Selection:=TGridRect(Rect(-1,-1,-1,-1)); //AlevelNames.Cells[8,0] := 'Pred'; for lC := 0 to 15 do begin AlevelNames.Cells[lC,0] := 'Pred'+inttostr(lC+1); end; SpreadForm.UpdateLabels; AValChange(nil); end; procedure TDesignForm.ALevelNamesEnter(Sender: TObject); begin AlevelNames.Selection:=TGridRect(Rect(0,0,0,0)); end; procedure TDesignForm.ALevelNamesExit(Sender: TObject); begin AlevelNames.Selection:=TGridRect(Rect(-1,-1,-1,-1)); end; function LeadingZeroFilename (lInX: string): string; var lIn: string; lC,lnPad,lPos,lnDec,lExtPos,lLen: integer; begin {$IFDEF Unix} lIn := lInX; {$ELSE} lIn := Lowercase(lInX); {$ENDIF} lnPad := 8; lLen := length(lIn); result := lIn; if lLen < 1 then exit; lExtPos := 1; while (lExtPos <= lLen) and (lIn[lExtPos] <> '.') do inc(lExtPos); if lExtPos <= 1 then exit; lnDec := 0; lPos := lExtPos -1; while (lPos > 0) and ( lIn[lPos] in ['0'..'9']) do dec(lPos); lnDec := (lExtPos-lPos)-1; if (lnDec = 0) or (lnDec >= lnPad) then exit; result := ''; if lPos > 0 then for lC := 1 to lPos do result := result + lIn[lC]; for lC := 1 to (lnPad-lnDec) do result := result + '0'; for lC := (lPos+1) to lLen do result := result+lIn[lC]; end; procedure SortStrPadded (var lStr: TStringList); {file1,file2...file10 not file1,file10..file2} var counter, look:integer; temp:Tstrings; begin if lStr.Count < 2 then exit; temp := TStringList.Create; for counter:=0 to lStr.Count-1 do temp.Append(LeadingZeroFilename{LowerCase}(lStr[counter])); for counter:=0 to temp.Count-1 do for look:=counter+1 to temp.Count-1 do if temp[look]<temp[counter] then begin lStr.Exchange(look, counter); temp.Exchange(look,counter); end; temp.Free; end; procedure TDesignForm.AddMRIBtnClick(Sender: TObject); var lNumberofFiles,lC: integer; lFileStrs: TStringList; begin if not MainForm.OpenDialogExecute('Select VOIs you wish to analyze',true,false,kVALImgFilter) then exit; lNumberofFiles:= MainForm.OpenHdrDlg.Files.Count; if lNumberofFiles < 2 then begin lNumberofFiles := NIFTIhdr_HdrVolumes(MainForm.OpenHdrDlg.Filename); if lNumberofFiles < 2 then begin Showmessage('Error: This function is designed to overlay MULTIPLE images. You selected less than two images.'); exit; end; lFileStrs := TStringList.Create; for lC:= 1 to lNumberofFiles do lFileStrs.Add(extractfilename(MainForm.OpenHdrDlg.Filename)+':'+inttostr(lC)); end else begin lFileStrs := TStringList.Create; for lC:= 1 to lNumberofFiles do lFileStrs.Add(extractfilename(MainForm.OpenHdrDlg.Files[lC-1])); SortStrPadded (lFileStrs); end; SpreadForm.DataGrid.RowCount := lNumberofFiles+1+kMaxFactors; //10/10/2006 -must resize BEFORE to populating cells for lC:= 1 to lNumberofFiles do SpreadForm.DataGrid.Cells[0,kMaxFactors+lC] := lFileStrs[lC-1]; lFileStrs.free; end; procedure TDesignForm.TemplateBtnClick(Sender: TObject); begin if not MainForm.OpenDialogExecute('Select Template image [determines bounding box and dimensions]',false,false,kVALImgFilter) then exit; TemplateLabel.Caption := (MainForm.OpenHdrDlg.Filename); end; {$IFDEF FPC} initialization {$I design.lrs} {$ENDIF} end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/windowsxp.res��������������������������������������������0000755�0001750�0001750�00000001340�07374553744�020757� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ������������������������� ���������0� ��������<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity name="CiaoSoftware.Ciao.Shell.Contacts" processorArchitecture="x86" version="5.1.0.0" type="win32"/> <description>Windows Shell</description> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*" /> </dependentAssembly> </dependency> </assembly> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/spread.lfm�����������������������������������������������0000755�0001750�0001750�00000012232�12147213330�020134� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object SpreadForm: TSpreadForm Left = 401 Height = 538 Top = 183 Width = 326 ActiveControl = DataGrid Caption = 'Voxelwise Analysis of Lesions' ClientHeight = 538 ClientWidth = 326 Font.Name = 'MS Sans Serif' Menu = MainMenu1 OnClose = FormClose OnCreate = FormCreate OnResize = FormResize Position = poScreenCenter LCLVersion = '0.9.30.2' object DataGrid: TStringGrid Left = 0 Height = 498 Top = 25 Width = 326 Align = alClient FixedRows = 2 Options = [goFixedVertLine, goVertLine, goHorzLine, goRangeSelect, goDrawFocusSelected, goTabs, goThumbTracking] RowCount = 12 TabOrder = 0 TitleFont.Name = 'MS Sans Serif' OnDrawCell = DataGridDrawCell OnKeyPress = DataGridKeyPress OnMouseDown = DataGridMouseDown OnMouseMove = DataGridMouseMove OnSelectCell = DataGridSelectCell end object ToolBar1: TToolBar Left = 0 Height = 25 Top = 0 Width = 326 EdgeBorders = [] TabOrder = 1 object DesignBtn: TSpeedButton Left = 1 Height = 22 Hint = 'ANOVA' Top = 0 Width = 120 Caption = 'Design' Glyph.Data = { 76010000424D7601000000000000760000002800000020000000100000000100 0400000000000001000000000000000000001000000010000000000000000000 800000800000008080008000000080008000808000007F7F7F00BFBFBF000000 FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00337333733373 3373337F3F7F3F7F3F7F33737373737373733F7F7F7F7F7F7F7F770000000000 00007777777777777777330333333C333333337FFF3337F3333F370993333C33 3399377773F337F33377330339333C3339333F7FF7FFF7FFF7FF770777977C77 97777777777777777777330333933C339333337F3373F7F37333370333393C39 3333377F333737F7333333033333999333333F7FFFFF777FFFFF770777777C77 77777777777777777777330333333C330333337F333337FF7FF3370333333C00 003C377F333337777737330333333C3303333F7FFFFFF7FF7FFF770777777777 7777777777777777777733333333333333333333333333333333 } NumGlyphs = 2 OnClick = DesignBtnClick ShowHint = True ParentShowHint = False end end object StatusBar1: TStatusBar Left = 0 Height = 15 Top = 523 Width = 326 Panels = < item Width = 140 end item Width = 50 end> SimplePanel = False end object MainMenu1: TMainMenu left = 108 top = 44 object File1: TMenuItem Caption = '&File' object New1: TMenuItem Caption = 'New...' ShortCut = 16462 OnClick = NewBtnClick end object Open1: TMenuItem Caption = 'Open...' ShortCut = 16463 OnClick = OpenBtnClick end object Save1: TMenuItem Caption = 'Save' ShortCut = 16467 OnClick = SaveBtnClick end object Quit1: TMenuItem Caption = 'Close window' ShortCut = 16471 OnClick = Quit1Click end end object Edit1: TMenuItem Caption = 'Edit' object Copy1: TMenuItem Caption = 'Copy' ShortCut = 16451 OnClick = Copy1Click end object Paste1: TMenuItem Caption = 'Paste' ShortCut = 16470 OnClick = Paste1Click end object Selectall1: TMenuItem Caption = 'Select all cells' ShortCut = 16449 OnClick = Selectall1Click end object Clearallcells1: TMenuItem Caption = 'Clear all cells...' OnClick = Clearallcells1Click end object DescriptiveMenu: TMenuItem Caption = 'Descriptives' OnClick = DescriptiveClick end end object View: TMenuItem Caption = 'View' object Font1: TMenuItem Caption = 'Font' object N81: TMenuItem Tag = 8 Caption = '8' Checked = True GroupIndex = 111 RadioItem = True OnClick = FontSizeChange end object N101: TMenuItem Tag = 10 Caption = '10' GroupIndex = 111 RadioItem = True OnClick = FontSizeChange end object N121: TMenuItem Tag = 12 Caption = '12' GroupIndex = 111 RadioItem = True OnClick = FontSizeChange end object N141: TMenuItem Tag = 14 Caption = '14' GroupIndex = 111 RadioItem = True OnClick = FontSizeChange end end object Design1: TMenuItem Caption = 'Design' ShortCut = 16452 OnClick = DesignBtnClick end end object Help1: TMenuItem Caption = '&Help' object Aboutthissoftware1: TMenuItem Caption = '&About this software' OnClick = Aboutthissoftware1Click end end end object OpenDialog1: TOpenDialog DefaultExt = '.val' Filter = 'Native [val]|.val|Tab delimited text [txt]|.txt|All files|.*' FilterIndex = 0 left = 36 top = 44 end object SaveDialog1: TSaveDialog DefaultExt = '.val' Filter = 'Native format [val]|*.val|Tab delimited text [txt]|*.txt' FilterIndex = 0 Options = [ofOverwritePrompt, ofHideReadOnly] left = 74 top = 44 end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npmform.lfm����������������������������������������������0000755�0001750�0001750�00000017400�12147221422�020337� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object MainForm: TMainForm Left = 517 Height = 418 Top = 321 Width = 542 ActiveControl = Memo1 Caption = 'Non-Parametric Mapping' ClientHeight = 418 ClientWidth = 542 Menu = MainMenu1 OnClose = FormClose OnCreate = FormCreate OnShow = FormShow Position = poScreenCenter LCLVersion = '0.9.30.2' object Memo1: TMemo Left = 0 Height = 393 Top = 0 Width = 542 Align = alClient ScrollBars = ssAutoBoth TabOrder = 0 end object Panel1: TPanel Left = 0 Height = 25 Top = 393 Width = 542 Align = alBottom ClientHeight = 25 ClientWidth = 542 TabOrder = 1 object ProgressBar1: TProgressBar Left = 1 Height = 23 Top = 1 Width = 540 Align = alClient TabOrder = 0 end end object MainMenu1: TMainMenu left = 8 top = 8 object File1: TMenuItem Caption = 'File' object SaveText1: TMenuItem Caption = 'Save text...' OnClick = Savetext1Click end object Exit1: TMenuItem Caption = 'Exit' OnClick = Exit1Click end end object Edit1: TMenuItem Caption = 'Edit' object Copy1: TMenuItem Caption = 'Copy' OnClick = Copy1Click end end object VLSM1: TMenuItem Caption = 'VLSM' object BinomialAnalysislesions1: TMenuItem Caption = 'Binary images, binary groups (lesions) ' ShortCut = 16450 OnClick = LesionBtnClick end object Binaryimagescontinuousgroupsfast1: TMenuItem Tag = 1 Caption = 'Binary images, continuous grooups (vlsm)' ShortCut = 16460 OnClick = LesionBtnClick end object PenalizedLogisticRegerssion1: TMenuItem Caption = 'Binary images, multiple factors' OnClick = PenalizedLogisticRegerssion1Click end object ROIanalysis1: TMenuItem Caption = 'ROI analysis' OnClick = ROIanalysis1Click end object Design1: TMenuItem Caption = 'Design...' ShortCut = 16452 OnClick = Design1Click end end object VBM1: TMenuItem Caption = 'VBM' object ContinuousanalysisVBM1: TMenuItem Caption = 'Continuous images, binary groups (VBM)' ShortCut = 16470 OnClick = NPMclick end object PairedTMenu: TMenuItem Caption = 'Paired Measures T-test' OnClick = PairedTMenuClick end object MultipleRegress: TMenuItem Caption = 'Multiple WLS Regression' OnClick = MultipleRegressClick end object SingleRegress: TMenuItem Caption = 'Single WLS Regression' OnClick = SingleRegressClick end object MenuItem3: TMenuItem Caption = 'Dual image correlation' OnClick = DualImageCorrelation1Click end end object Options1: TMenuItem Caption = 'Options' object Permutations1: TMenuItem Caption = 'Permutations' object N0: TMenuItem AutoCheck = True Caption = 'None' Checked = True GroupIndex = 123 RadioItem = True OnClick = radiomenuclick end object N1000: TMenuItem Tag = 1000 AutoCheck = True Caption = '1000' GroupIndex = 123 RadioItem = True OnClick = radiomenuclick end object N2000: TMenuItem Tag = 2000 AutoCheck = True Caption = '2000' GroupIndex = 123 RadioItem = True OnClick = radiomenuclick end object N3000: TMenuItem Tag = 3000 AutoCheck = True Caption = '3000' GroupIndex = 123 RadioItem = True OnClick = radiomenuclick end object N4000: TMenuItem Tag = 4000 AutoCheck = True Caption = '4000' GroupIndex = 123 RadioItem = True OnClick = radiomenuclick end end object Tests1: TMenuItem Caption = 'Tests' object ttestmenu: TMenuItem Caption = 't-test' OnClick = testmenuclick end object BMmenu: TMenuItem Caption = 'Brunner Munzel' Checked = True OnClick = testmenuclick end end object Threads1: TMenuItem Caption = 'Threads' object T1: TMenuItem AutoCheck = True Caption = '1' Checked = True GroupIndex = 131 RadioItem = True OnClick = threadChange end object T2: TMenuItem AutoCheck = True Caption = '2' GroupIndex = 131 RadioItem = True OnClick = threadChange end object T3: TMenuItem AutoCheck = True Caption = '3' GroupIndex = 131 RadioItem = True OnClick = threadChange end object T4: TMenuItem AutoCheck = True Caption = '4' GroupIndex = 131 RadioItem = True OnClick = threadChange end object T7: TMenuItem AutoCheck = True Caption = '7' GroupIndex = 131 RadioItem = True OnClick = threadChange end object T8: TMenuItem AutoCheck = True Caption = '8' GroupIndex = 131 RadioItem = True OnClick = threadChange end object T15: TMenuItem AutoCheck = True Caption = '15' GroupIndex = 131 RadioItem = True OnClick = threadChange end object T16: TMenuItem AutoCheck = True Caption = '16' GroupIndex = 131 RadioItem = True OnClick = threadChange end end end object Utilities1: TMenuItem Caption = 'Utilities' object niiniigz1: TMenuItem Caption = 'nii -> .nii.gz' OnClick = niiniigz1Click end object Variance1: TMenuItem Caption = 'Variance image' OnClick = Variance1Click end object Makemeanimage2: TMenuItem Tag = 1 Caption = 'Make binarized mean' OnClick = Makemeanimage1Click end object Makemeanimage1: TMenuItem Caption = 'Make mean/StDev image' OnClick = Makemeanimage1Click end object SingleSubjectZScores1: TMenuItem Caption = 'Single Subject Z-Score' OnClick = SingleSubjectZScores1Click end object IntensitynormalizationA1: TMenuItem Tag = 1 Caption = 'Intensity normalization A' OnClick = Balance1Click end object Balance1: TMenuItem Caption = 'Intensity normalization B' OnClick = Balance1Click end object PhysiologicalArtifactCorrection1: TMenuItem Caption = 'Physiological Correction' OnClick = PhysiologicalArtifactCorrection1Click end object Countlesionoverlaps1: TMenuItem Caption = 'Count lesion overlaps' OnClick = Countlesionoverlaps1Click end object FCE1: TMenuItem Caption = 'TFCE' OnClick = FCE1Click end end object Help1: TMenuItem Caption = 'Help' Visible = False object About1: TMenuItem Caption = 'About' OnClick = About1Click end end end object SaveHdrDlg: TSaveDialog FilterIndex = 0 left = 8 top = 40 end object OpenHdrDlg: TOpenDialog FilterIndex = 0 left = 8 top = 72 end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/part.pas�������������������������������������������������0000755�0001750�0001750�00000052667�11326425450�017657� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit part; //Physiological Artifact Removal Tool {$H+} interface uses define_types,dialogs,SysUtils; function ApplyPart( lFilename: string;lImgData: singleP; lBins,lVolVox,lSlices, lImgVol : integer; lTRsec: single): string; implementation type TPhysioT = RECORD Triggers,InterpolatedTriggers: integer; TriggerMedian,TriggerQ1,TriggerQ3: Double; TriggerRA: singleP; END; function SaveTriggersAs3ColumnFSL(lPhysioIn: TPhysioT; lOutName: string): boolean; var lF: textfile; lPos: integer; begin result := false; if (lPhysioIn.Triggers < 1) then exit; assignfile(lF,lOutName+'.txt'); Filemode := 0; rewrite(lF); for lPos := 1 to lPhysioIn.Triggers do Writeln(lf,realtostr(lPhysioIn.TriggerRA^[lPos],3)+' 1 1'); closefile(lF); Filemode := 2; result := true; end; procedure qsort(lower, upper : integer; var Data:SingleP); //40ms - fast but very recursive... var left, right : integer; pivot,lswap: single; begin pivot:=Data^[(lower+upper) div 2]; left:=lower; right:=upper; while left<=right do begin while Data^[left] < pivot do left:=left+1; { Parting for left } while Data^[right] > pivot do right:=right-1;{ Parting for right} if left<=right then begin { Validate the change } lswap := Data^[left]; Data^[left] := Data^[right]; Data^[right] := lswap; left:=left+1; right:=right-1; end; //validate end;//while left <=right if right>lower then qsort(lower,right,Data); { Sort the LEFT part } if upper>left then qsort(left ,upper,data); { Sort the RIGHT part } end; procedure QuartileTriggerSpacing(var lPhysio: TPhysioT); var lTriggerDelayRA: singleP; lPos: integer; begin lPhysio.TriggerQ1 := 0; lPhysio.TriggerMedian := 0; lPhysio.TriggerQ3 := 0; if lPhysio.Triggers < 4 then exit; getmem(lTriggerDelayRA,(lPhysio.Triggers-1)*sizeof(single)); for lPos := 1 to (lPhysio.Triggers-1) do lTriggerDelayRA^[lPos] := abs(lPhysio.TriggerRA^[lPos]-lPhysio.TriggerRA^[lPos+1]); qsort(1,lPhysio.Triggers-1,lTriggerDelayRA);//-1 : fence post vs wire lPos := lPhysio.Triggers div 2; lPhysio.TriggerMedian := lTriggerDelayRA^[lPos]; lPos := lPhysio.Triggers div 4; lPhysio.TriggerQ1 := lTriggerDelayRA^[lPos]; lPos := round(0.75*lPhysio.Triggers ); lPhysio.TriggerQ3 := lTriggerDelayRA^[lPos]; freemem(lTriggerDelayRA); end; function PARTool (var lPhysio: TPhysioT; lImgData: singleP; lTRsec: single; lnVolVox,lnSlices, lImgVol, lBinIn : integer): string; const kMinSamplesPerBin = 4; var lV,lSliceTime,lMeanSignal,lOnsetTime,lBinWidth,lBinMin,lBinMax,lTimeSinceTrigger,lPrevTriggerTime: double; lSlice,lSlicePos,lnSliceVox,lnSlicePos,lVoxel,lBin,lSample,lnBin,lnBinDiv2,lNextTrigger,lSamplesWithVariance,lCorrectedSamples,lVolOffset: integer; lBinCountRA,lVolBinRA: longintp; lVariance : boolean; lBinEstimateRA: doublep; begin result := ''; if (lPhysio.Triggers < 4) or (lnVolVox < 4) or (lImgVol < 4) then begin showmessage('PART requires at least 4 triggers and at least 4 volumes each with at least 4 voxels'); exit; end; if (lBinIn < 4) then begin showmessage('PART requires at least 4 data bins'); exit; end; lnSliceVox := lnVolVox div lnSlices; if (lnVolVox mod lnSlices) <> 0 then begin showmessage('PART requires volvox to be evenly divisible by number of slices.'); exit; end; lSamplesWithVariance := 0; lCorrectedSamples := 0; QuartileTriggerSpacing(lPhysio); //find number bin range - this is median-1.5IQR..median+1.5IQR lBinMin := -lPhysio.TriggerMedian/2-(abs(lPhysio.TriggerQ1-lPhysio.TriggerQ3)*0.75); lBinMax := +lPhysio.TriggerMedian/2+abs(lPhysio.TriggerQ1-lPhysio.TriggerQ3)*0.75; //next - create bins lnBin := lBinIn; //could adjust number of bins and return here wth a label lBinWidth := abs((lBinMax-lBinMin)/(lnBin-1));//lnBin-1: fenceposts vs wire lnBinDiv2 := (lnBin div 2)+1; getmem(lBinCountRA,lnBin*sizeof(integer)); getmem(lBinEstimateRA,lnBin*sizeof(double)); getmem(lVolBinRA,lImgVol*sizeof(integer)); lVoxel := 0; for lSlice := 1 to lnSlices do begin //adjust slices so slice 1 occurs at 0, slice 2 at 1/nslices... lSliceTime := ((lSlice-1)/lnSlices)-1; //-1 as 1st volume starts at zero, not 1 //do next step for each slice - different slices have different bin distributions due to different slicetime //next count number of samples in each bin for lBin := 1 to lnBin do lBinCountRA^[lBin] := 0; lPrevTriggerTime := -MaxInt; lNextTrigger := 1; for lSample := 1 to lImgVol do begin //for each sample, find nearest trigger lOnsetTime := lSample+lSliceTime; if lOnsetTime > lPhysio.TriggerRA^[lNextTrigger] then begin while (lNextTrigger <= lPhysio.Triggers ) and (lOnsetTime > lPhysio.TriggerRA^[lNextTrigger]) do begin lPrevTriggerTime := lPhysio.TriggerRA^[lNextTrigger]; inc(lNextTrigger); end; //while end;//if onset > lTimeSinceTrigger := lOnsetTime-lPrevTriggerTime; if lTimeSinceTrigger > abs(lPhysio.TriggerRA^[lNextTrigger]-lOnsetTime) then lTimeSinceTrigger := -abs(lPhysio.TriggerRA^[lNextTrigger]-lOnsetTime);//use abs in case we are past final trigger //now compute bin... //inc(lCorrectedSamples); if (lTimeSinceTrigger > lBinMin) and (lTimeSinceTrigger < lBinMax) then begin lBin := round( (lTimeSinceTrigger)/ lBinWidth)+lnBinDiv2; lVolBinRA^[lSample] := lBin; if (lBin < 1) or (lBin > lnBin) then fx(-661,lBin,lTimeSinceTrigger) else inc(lBinCountRA^[lBin]); end else lVolBinRA^[lSample] := 0; end; //for each volume for lSlicePos := 1 to lnSliceVox do begin inc(lVoxel); //first - only correct voxels with variability - do not waste time outside brain lVolOffset := lVoxel; lVariance := false; lSample := 1; lV := lImgData^[lVolOffset]; while (not lVariance) and (lSample <= lImgVol) do begin if lV <> lImgData^[lVolOffset] then lVariance := true; inc(lSample); lVolOffset := lVolOffset+lnVolVox; end; //while no variance if lVariance then begin //voxel intensity varies accross time - attempt to remove artifact lSamplesWithVariance := lSamplesWithVariance +lImgVol; //1st - sum effects for lBin := 1 to lnBin do lBinEstimateRA^[lBin] := 0; lMeanSignal := 0; lVolOffset := lVoxel; for lSample := 1 to lImgVol do begin lMeanSignal := lImgData^[lVolOffset] + lMeanSignal; lBin := lVolBinRA^[lSample]; if (lBin > 0) and (lBinCountRA^[lBin] > kMinSamplesPerBin) then lBinEstimateRA^[lBin] := lBinEstimateRA^[lBin]+ lImgData^[lVolOffset]; lVolOffset := lVolOffset+lnVolVox; end; //for each volume lMeanSignal := lMeanSignal /lImgVol; //next compute correction... average signal in bin - average voxel intensity irrelevant of bin for lBin := 1 to lnBin do if lBinCountRA^[lBin] > kMinSamplesPerBin then lBinEstimateRA^[lBin] := (lBinEstimateRA^[lBin]/lBinCountRA^[lBin])-lMeanSignal; //lBinEstimateRA[lBin] := lBinEstimateRA[lBin]-lBinMeanCount; //next apply correction - inner loop complete for each voxel! lVolOffset := lVoxel; for lSample := 1 to lImgVol do begin //for each sample, find nearest trigger lBin := lVolBinRA^[lSample]; if (lBin > 0) and (lBinCountRA^[lBin] > kMinSamplesPerBin) then begin lImgData^[lVolOffset] := (lImgData^[lVolOffset]-lBinEstimateRA^[lBin]); inc(lCorrectedSamples) end; lVolOffset := lVolOffset+lnVolVox; end; //for each volume end; //if variance end;//for each voxel in slice end; //for slice //**INNER LOOP end - //next - report results result :=' Time per vol (TR) [sec] '+realtostr(lTRsec,4)+kCR; result :=result +' fMRI Volumes '+inttostr(lImgVol)+kCR; result :=result +' Triggers n/First...Last [vol] '+realtostr(lPhysio.Triggers,0)+'/'+realtostr(lPhysio.TriggerRA^[1],2)+'...'+realtostr(lPhysio.TriggerRA^[lPhysio.Triggers],2)+kCR; if abs(lImgVol-lPhysio.TriggerRA^[lPhysio.Triggers]) > 10 then begin result :=result +'******* WARNING: Duration of fMRI session and duration of triggers is very different *******'; result :=result +'******* Please ensure specified TR is correct, files are correct and onset of fMRI was synchronized with physio data *******'; end; result := result + ' Q1/Median/Q2 [sec] '+realtostr(lTRsec*lPhysio.TriggerQ1,2)+'/'+realtostr(lTRsec*lPhysio.TriggerMedian,2)+'/'+realtostr(lTRsec*lPhysio.TriggerQ3,2)+kCR; result := result + ' Bin n/Range [sec] '+inttostr(lnBin)+'/'+realtostr(lTRsec*lBinMin,2)+ '...'+realtostr(lTRsec*lBinMax,2)+kCR; result := result+ ' voxels without variance (outside brain) %: '+realtostr(100*( (lnVolVox-(lSamplesWithVariance/lImgVol))/lnVolVox),2)+kCR; if lSamplesWithVariance > 0 then result := result+ ' voxels with variance which were corrected %: '+realtostr(100*(lCorrectedSamples/lSamplesWithVariance),2)+kCR; for lBin := 1 to lnBin do result := result+(' Bin '+inttostr(lBin)+ ' '+realtostr(lBin*lBinWidth+lBinMin ,2) +' '+inttostr(lBinCountRA^[lBin]) )+kCR; freemem(lBinCountRA); freemem(lBinEstimateRA); freemem(lVolBinRA); end; function StrVal (var lNumStr: string): integer; begin try result := strtoint(lNumStr); except on EConvertError do begin showmessage('StrVal Error - Unable to convert the string '+lNumStr+' to a number'); result := MaxInt; end; end; end; procedure AddSample(var lNumStr: string; var lnTotal,lnSample, lnTrigger: integer; var lPhysio: TPhysioT); var lVal: integer; begin lVal := StrVal(lNumStr); if lVal = 5003 then exit; lNumStr := ''; inc(lnTotal); if lnTotal < 5 then exit; if lVal > 4096 then begin if lVal <> 5000 then begin showmessage('Potentially serious error: unknown trigger type : '+inttostr(lVal)); end; inc(lnTrigger); if (lPhysio.Triggers <> 0) then lPhysio.TriggerRA^[lnTrigger] := lnSample; end else begin inc(lnSample); end; end; function AdjustStartPos (var lStr: string; var lStartPos: integer): boolean; //Some Siemens physio files appear to have nonsense characters befor real data<bh:ef><bh:bb><bh:bf>1 var lLen: integer; begin lLen := length(lStr); result := false; if (lLen-lStartPos)<2 then exit; result := true; repeat if lStr[lStartPos] in [ '0'..'9'] then exit; inc(lStartPos); until (lStartPos = lLen); result := false; end; procedure CountValidItems(var lStr: string; var lStartPos,lnSample, lnTrigger: integer; var lPhysio: TPhysioT); label 123; var lPos,lnTotal: integer; lNumStr: string; begin lnTotal:= 0; lnSample := 0; lnTrigger := 0; lNumStr := ''; if length(lStr)<2 then exit; if not AdjustStartPos ( lStr, lStartPos) then exit; //Oct 2009 for lPos := lStartPos to length(lStr) do begin if (lStr[lPos] = ' ') and (lNumStr <> '') then begin if lNumStr = '5003' then begin lNumStr := ''; goto 123; //end of recording end else AddSample(lNumStr, lnTotal,lnSample, lnTrigger, lPhysio); end else begin if lStr[lPos] in [ '0'..'9'] then lNumStr := lNumStr + lStr[lPos] else if lStr[lPos] in [' '] then else begin //Showmessage(lStr[lPos]); goto 123; end; end; end; //for length 123: if (lNumStr <> '') then AddSample(lNumStr, lnTotal,lnSample, lnTrigger, lPhysio); lStartPos := lPos; while (lStartPos < length(lStr)) and ( lStr[lStartPos] <> ' ') do begin inc(lStartPos); end; end; procedure CreatePhysio (var lPhysio: TPhysioT); begin lPhysio.Triggers := 0; end; procedure ClosePhysio (var lPhysio: TPhysioT); begin with lPhysio do begin if Triggers > 0 then freemem(TriggerRA); Triggers := 0; end; end; procedure InitPhysio(lnTrigger: integer; var lPhysio: TPhysioT); begin ClosePhysio (lPhysio); with lPhysio do begin Triggers := lnTrigger; InterpolatedTriggers := 0; if Triggers > 0 then getmem(TriggerRA,Triggers*sizeof(single)); end; end; function load3ColTxtPhysio (lFilename: string; var lPhysio: TPhysioT): boolean; var F: TextFile; lnTrigger: integer; lFloat,lFloat2,lFloat3: single; begin result := false; if not fileexists(lFilename) then exit; ClosePhysio(lPhysio); AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //pass 1 - count number of triggers lnTrigger := 0; Reset(F); while not EOF(F) do begin {$I-} read(F,lFloat,lFloat2,lFloat3); //read triplets instead of readln: this should load UNIX files {$I+} if (ioresult = 0) and (lFloat > 0) then inc(lnTrigger); end; //pass 2 - load array InitPhysio(lnTrigger, lPhysio); lnTrigger := 0; Reset(F); while not EOF(F) do begin {$I-} read(F,lFloat,lFloat2,lFloat3); //read triplets instead of readln: this should load UNIX files {$I+} if (ioresult = 0) and (lFloat > 0) then begin inc(lnTrigger); lPhysio.TriggerRA^[lnTrigger] := lFloat; end; end; FileMode := 2; //Set file access to read/write CloseFile(F); result := true; end; procedure ReadlnX (var F: TextFile; var lResult: string); var lCh: char; begin lResult := ''; while not Eof(F) do begin Read(F, lCh); if (lCh in [#10,#13]) then begin if lResult <> '' then begin //Showmessage(lResult); exit; end; end else lResult := lResult + lCh; end; end; //ReadlnX function loadSiemensPhysio (lFilename: string; var lPhysio: TPhysioT): boolean; var F: TextFile; lStr: string; lPos,lnSample,lnTrigger: integer; begin result := false; if not fileexists(lFilename) then exit; ClosePhysio(lPhysio); AssignFile(F, lFilename); FileMode := 0; //Set file access to read only Reset(F); ReadlnX(F,lStr);//ColNames if length(lStr) < 1 then begin CloseFile(F); exit; end; //first pass - count items lPos := 1; CountValidItems(lStr,lPos,lnSample,lnTrigger,lPhysio); //second pass - load array if (lnSample < 1) and (lnTrigger < 1) then begin CloseFile(F); exit; end; //2nd pass... InitPhysio(lnTrigger, lPhysio); lPos := 1; CountValidItems(lStr,lPos,lnSample,lnTrigger,lPhysio); FileMode := 2; //Set file access to read/write CloseFile(F); result := true; end; function InterpolateGaps (var lPhysioIn: TPhysioT): boolean; //attempts to fill missing trigger pulses //you must call QuartileTriggerSpacing before this function! // it assumes q1/median/q3 are filled var lGap,l2Min,l2Max,l3Min,l3Max: double; lnReplace,lTrigger,lTrigger2: integer; lTempPhysio: TPhysioT; begin result := false; if (lPhysioIn.Triggers < 4) then begin showmessage('InterpolateGaps requires at least 4 triggers.'); exit; end; l2Min := 2*lPhysioIn.TriggerMedian-(abs(lPhysioIn.TriggerQ1-lPhysioIn.TriggerQ3)*1.5); l2Max := 2*lPhysioIn.TriggerMedian+(abs(lPhysioIn.TriggerQ1-lPhysioIn.TriggerQ3)*1.5); l3Min := 3*lPhysioIn.TriggerMedian-(abs(lPhysioIn.TriggerQ1-lPhysioIn.TriggerQ3)*1.5); l3Max := 3*lPhysioIn.TriggerMedian+(abs(lPhysioIn.TriggerQ1-lPhysioIn.TriggerQ3)*1.5); if l2Max > l3Min then exit; //variability too high to determine gaps lnReplace := 0; for lTrigger := 2 to lPhysioIn.Triggers do begin lGap := lPhysioIn.TriggerRA^[lTrigger] - lPhysioIn.TriggerRA^[lTrigger-1]; if (lGap > l2Min) and (lGap < l2Max) then inc(lnReplace); if (lGap > l3Min) and (lGap < l3Max) then inc(lnReplace,2); end; if lnReplace = 0 then begin result := true; exit; end; //create temp backup CreatePhysio(lTempPhysio); InitPhysio(lPhysioIn.Triggers, lTempPhysio); for lTrigger := 1 to lPhysioIn.Triggers do lTempPhysio.TriggerRA[lTrigger] := lPhysioIn.TriggerRA[lTrigger]; //create resized array InitPhysio(lTempPhysio.Triggers+lnReplace, lPhysioIn); //fill gaps lPhysioIn.TriggerRA[1] := lTempPhysio.TriggerRA[1]; lTrigger2 := 1; for lTrigger := 2 to lTempPhysio.Triggers do begin inc(lTrigger2); lGap := lTempPhysio.TriggerRA^[lTrigger] - lTempPhysio.TriggerRA^[lTrigger-1]; if ((lGap > l2Min) and (lGap < l2Max)) then begin //1 beat lPhysioIn.TriggerRA^[lTrigger2] := lTempPhysio.TriggerRA^[lTrigger-1]+(lgap / 2); inc(lTrigger2); end; if ((lGap > l3Min) and (lGap < l3Max)) then begin //2 beats lPhysioIn.TriggerRA^[lTrigger2] := lTempPhysio.TriggerRA^[lTrigger-1]+(lgap / 3); inc(lTrigger2); lPhysioIn.TriggerRA^[lTrigger2] := lTempPhysio.TriggerRA^[lTrigger-1]+(2*lgap / 3); inc(lTrigger2); end; lPhysioIn.TriggerRA^[lTrigger2] := lTempPhysio.TriggerRA^[lTrigger]; end; ClosePhysio (lTempPhysio); lPhysioIn.InterpolatedTriggers := lnReplace; result := true; end; function ScalePhysioToTime(lPhysio: TPhysioT; lSamplesPerUnit: single): boolean; var lScale: single; lTrigger: integer; begin result := false; if (lPhysio.Triggers < 4) then begin showmessage('ScalePhysioToTR requires at least 4 triggers.'); exit; end; if (lSamplesPerUnit <= 0) then begin showmessage('ScalePhysioToTime requires TR(sec) and samples/sec >0.'); exit; end; lScale := 1/(lSamplesPerUnit); //use reciprocal: mults faster than divides for lTrigger := 1 to lPhysio.Triggers do lPhysio.TriggerRA^[lTrigger] := lPhysio.TriggerRA^[lTrigger] * lScale; result := true; end; procedure EnsureAscending(lPhysio: TPhysioT); //check if order is correct - if not the sort... //an alternative is to always sort, but this method is faster and less resource intensive for sorted data var lPos: integer; begin if lPhysio.Triggers < 2 then exit; for lPos := 2 to lPhysio.Triggers do begin if lPhysio.TriggerRA^[lPos] < lPhysio.TriggerRA^[lPos-1] then begin showmessage('Warning: input times are not in ascending order - data will be sorted.'); qsort(1,lPhysio.Triggers,lPhysio.TriggerRA); //ensure trigger timings are in order... exit; end; end; end; function ApplyPart( lFilename: string;lImgData: singleP; lBins,lVolVox,lSlices, lImgVol : integer; lTRsec: single): string; var lPhysio: TPhysioT; begin result := ''; if not fileexists (lFilename) then exit; CreatePhysio(lPhysio); if UpCaseExt(lFilename) = '.TXT' then begin if not load3ColTxtPhysio(lFilename,lPhysio) then exit; end else if not loadSiemensPhysio(lFilename,lPhysio) then exit; EnsureAscending(lPhysio); QuartileTriggerSpacing(lPhysio); if not InterpolateGaps (lPhysio) then exit; if UpCaseExt(lFilename) <> '.TXT' then begin//export Siemens file as 3-column text ScalePhysioToTime(lPhysio,50); //50: siemens files use 50 Hz sampling -> convert to sec SaveTriggersAs3ColumnFSL(lPhysio,lFilename); //do this before TR conversion... end; ScalePhysioToTime(lPhysio,lTRsec); //Convert sec to volumes result := PARTool (lPhysio,lImgData,lTRsec,lVolVox,lSlices, lImgVol, lBins); ClosePhysio(lPhysio); end; end. �������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/tfce_clustering.7z���������������������������������������0000755�0001750�0001750�00000004071�12110676124�021626� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������7z'�Ip������h�������z0�:bA.٘ '&E񚯬mK**s1dfF lX꿖KQ9&{J:`Ac$Q!Wfi`#*ELL꘎ eTR4>Wc17(׸նR~}e^k+PqݎNYC\7*s^!i?rA>NE7X tie #hsLv1M+}P_5)wtqYEzPuK6zi>l= 95\tB\pSSÞt�j}ފd}Ş|2^-G団V@kVt+3(Rk+/6ėlgFB{GˊaQx8tT*zL2?> Cb`~O͙58bɿf2Ib'F,X.Ĺ *|H9c<<($ޮp$*Pt )]}F,$QJNJу߿`tH ;z1.~_rˏO=`hǟKcjgy:*.G}e^ n!W/\UDIBE ~jV|.Ma+*v94J;Qr(ʲU'Fý=vgKd/D; (-e4>m&]E'%[^1z * ;RZZMȪ |nG�56:\YT#W W,X2s @W0bQg;JH7iM$@i2PoUfd=VG XBrއwYDS4r[Bw r$Â0^, Cڼ`*ff :_+V0̩7ud(9ſSy=�̩U/"(5/R<a8yyڔ VDQo@^H*튔/kvz(NYK1s+iByٟd/7.l[}j7gWdB78kIvkr9Cѐ8u)~$EȚ\44ЋlXE)EW/žF_3dQE,;WE3Cf9㙼ʖ J><¤$߳1Fiq6~D!ƛ蝃Cɭb #nZo!2wAv{vtңUIH) D H+�uOGaVdž$ʨGԥݹU"+(quMd*'oΊ^.6=i6lNhvıdHw_@bO/ޜ[S<g~P4q5"6g@!+z0O<'H;o[,Wotô(giKK; -1#ෛ)r1V :!8z]Ϋk'肽U/F*^ mۉ T�SRWg 8H !)Y[H` Ԟ q0L]�Q؃~ y捐�TC(0Wi^D)@sKOG9r/&/_*3RϱWg9QՎS3z=sť٣|S2S6?@QhCr?-\ܣZD[qpJ.ЗڞBVd Yl 0[+f܁^˛bͿ ^_ïS/kR힍'j}XA;"?, QSN.na9C$}5ZLpuK4:E->^(ZZa~\ab�%b7yK{O"8Fϰ_UyF GFPkH{хmT0I&X9�|h z R^�� � �#]��� � SC��)�t�f�c�e�_�c�l�u�s�t�e�r�i�n�g�.�p�a�s��� ��2Y7� ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/ReadInt.pas����������������������������������������������0000755�0001750�0001750�00000002363�11540170630�020216� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit ReadInt; interface uses {$IFDEF FPC} LResources,{$ENDIF} Buttons{only Lazarus?},SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Spin; type TReadIntForm = class(TForm) ReadIntEdit: TSpinEdit; ReadIntLabel: TLabel; OKBtn: TButton; function GetInt(lStr: string; lMin,lDefault,lMax: integer): integer; procedure OKBtnClick(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var ReadIntForm: TReadIntForm; implementation {$IFNDEF FPC} {$R *.DFM} {$ENDIF} function TReadIntForm.GetInt(lStr: string; lMin,lDefault,lMax: integer): integer; begin //result := lDefault; ReadIntLabel.caption := lStr+' ['+inttostr(lMin)+'..'+inttostr(lMax)+']'; ReadIntEdit.MinValue := lMin; ReadIntEdit.MaxValue := lMax; ReadIntEdit.Value := lDefault; ReadIntForm.ShowModal; result := ReadIntEdit.Value; end; procedure TReadIntForm.OKBtnClick(Sender: TObject); begin ReadIntForm.ModalResult := mrOK; end; procedure TReadIntForm.FormCreate(Sender: TObject); begin end; {$IFDEF FPC} initialization {$I ReadInt.lrs} {$ENDIF} end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/Copy of prefs.pas����������������������������������������0000755�0001750�0001750�00000021432�11326425446�021277� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit prefs; {$H+} interface uses inifiles, define_types,SysUtils,classes; type TPrefs = record UnusedBool: boolean; Test, Permutations,CritPct: integer; end; const knotest = 0; //no test specified kltest = 1;//binomial Liebermeister test kttest = 2; //t-test kbmtest = 4;//Bruneer-Mnuzel test klrtest = 8; //logisitic regression test //procedure ReadIni(var lIniName: string; var lPrefs: TPrefs); procedure SetDefaultPrefs (var lPrefs: TPrefs); //procedure SaveIni (var lIniName: string; var lPrefs: TPrefs); //procedure CorrectPrefs (var lPrefs: TPrefs); //ensures only usable file types are created procedure ReadParamStr; implementation uses nifti_img, hdr,nifti_hdr; procedure Msg(lStr: string); begin // end; procedure SetDefaultPrefs (var lPrefs: TPrefs); begin lPrefs.unusedbool := true; lPrefs.Test := knotest; lPrefs.Permutations := 0; lPrefs.CritPct := 0; end; function CheckBool (lPref, lFlag: integer): boolean; //check if Flag is ni lPref. For example, if Flag is 1 then returns true for all odd lPrefs begin result := (lPref and lFlag) = lFlag; end; function DoLesion (lPrefs: TPrefs): boolean; label 666; const kSimSampleSize = 64; knSim = 100; kCrit = 3; var //lBinomial: boolean; lSim,lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCrit,lnControlObservations: integer; lPartImageNames,lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lOutName,lFactname,lOutNameSim: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA,lPartSymptomRA,lControlSymptomRA: singleP; begin result := false; //lBinomial := not odd( (Sender as tMenuItem).tag); if (not CheckBool(lPrefs.test ,kltest)) and (not CheckBool(lPrefs.test, kttest)) and (not CheckBool(lPrefs.test, kbmtest)) then begin Msg('Error: you need to compute at least on test [options/test menu]'); exit; end; lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? lPartImageNames := TStringList.Create; getmem(lPartSymptomRA,kSimSampleSize*sizeof(single)); lnControlObservations := 20; getmem(lControlSymptomRA,lnControlObservations*sizeof(single)); for lSim := 1 to lnControlObservations do lControlSymptomRA[lSim] := 5; //next, get 1st group if not MainForm.GetVal(lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCrit,lBinomial,lPredictorList) then begin showmessage('Error with VAL file'); goto 666; end; lTemp4D := MainForm.CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) then begin Showmessage('Not enough subjects ('+inttostr(lnSubjAll)+') or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not MainForm.CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; MainForm.SaveHdrDlg.Filename := loutname; lOutName := lOutName+'.nii.gz'; if not MainForm.SaveHdrName ('Base Statistical Map', lOutName) then goto 666; for lFact := 1 to lnFactors do begin lImageNames.clear; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); lnSubj := lImageNames.Count; if lnSubj > 1 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; //randomization loop.... for lSim := 1 to knSim do begin RandomGroup(kSimSampleSize, lImageNames,lSymptomRA, lPartImageNames, lPartSymptomRA); lOutNameSim := AddIndexToFilename(lOutName,lSim); lnCrit := kCrit; MainForm.NPMMsgClear; //Msg(GetKVers); MainForm.NPMMsg('Threads: '+inttostr(gnCPUThreads)); lFactName := lPredictorList.Strings[lFact-1]; lFactName := MainForm.LegitFilename(lFactName,lFact); MainForm.NPMMsg('Factor = '+lFactname); For lSubj := 1 to kSimSampleSize do MainForm.NPMMsg (lPartImageNames.Strings[lSubj-1] + ' = '+realtostr(lPartSymptomRA^[lSubj],2) ); MainForm.NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); MainForm.NPMMsg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); MainForm.NPMMsg('Number of Lesion maps = '+inttostr(kSimSampleSize)); if not MainForm.CheckVoxelsGroup(lPartImageNames,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; if lBinomial then MainForm.LesionNPMAnalyzeBinomial(lPartImageNames,lMaskHdr,lnCrit,lPartSymptomRA,lFactname,lOutNameSim) else begin MainForm.ReportDescriptives(lPartSymptomRA,lnSubj); //LesionNPMAnalyze2(lImageNames,lMaskHdr,lnCrit,-1,lSymptomRA,lFactName,lOutname); LesionNPMAnalyze2(lPartImageNames,lMaskHdr,lnCrit,lSim{-1},MainForm.ReadPermute,lPartSymptomRA,lFactName,lOutNameSim,lTTest,lBM); end; end; //for each simulation... Freemem(lSymptomRA); end; //lnsubj > 1 end; //for each factor if lnSubjAll > 0 then begin Freemem(lMultiSymptomRA); end; result := true; 666: lPartImageNames.free; lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; freemem(lPartSymptomRA); MainForm.DeleteDecompressed4D(lTemp4D); end; procedure ReadParamStr; var lStr: String; I,lError: integer; //lResult,lHelpShown : boolean; lCommandChar: Char; //I,lError: integer; lSingle: single; //lOrigWinWid,lOrigWinCen: Integer;*) lPrefs: TPrefs; begin SetDefaultPrefs(lPrefs); lStr := paramstr(0); lStr := extractfilename(lStr); lStr := string(StrUpper(PChar(lStr))) ; {$IFDEF PNG} if (lStr = 'DCM2PNG.EXE') then gOutputFormat := kPNG; {$ENDIF} if (ParamCount > 0) then begin I := 0; repeat lStr := ''; repeat inc(I); if I = 1 then lStr := ParamStr(I) else begin if lStr <> '' then lStr := lStr +' '+ ParamStr(I) else lStr := ParamStr(I); end; if (length(lStr)>1) and (lStr[1] = '-') and (ParamCount > I) then begin //special command //-z= zoom, -f= format [png,jpeg,bmp], -o= output directory lCommandChar := UpCase(lStr[2]); inc(I); lStr := ParamStr(I); lStr := string(StrUpper(PChar(lStr))) ; case lCommandChar of 'C','P','T': begin //CritPct Val(lStr,lSingle,lError); if lError = 0 then begin if lCommandChar = 'C' then lPrefs.CritPct := round(lSingle) else if lCOmmandChar = 'P' then lPrefs.Permutations := round(lSingle) else if lCOmmandChar = 'T' then lPrefs.Test := round(lSingle); end; //not lError end; //C= CritPct end; //case lStr[2] lStr := ''; end; //special command until (I=ParamCount) or (fileexists(lStr)) {or (gAbort)}; if fileexists(lStr) then begin //lStr := GetLongFileName(lStr); xxx end else if not (gSilent) then begin MyWriteln('0 dcm2jpg ERROR: unable to find '+lStr); if lHelpShown then MyReadln else Showhelp; lHelpShown := true; end; until I >= ParamCount; end else begin //begin test routines.... (* lStr := 'D:\yuv2.dcm'; ResetDCMvalues; lOrigWinWid := gWinWid; lOrigWinCen := gWinCen; LoadData(lStr); gWinWid := lOrigWinWid; gWinCen := lOrigWinCen; //...end test routines(**) ShowHelp; end;{param count > 0} end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/firth.pas������������������������������������������������0000755�0001750�0001750�00000035056�11326425446�020023� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit firth; interface uses ComCtrls,Classes, Graphics, ExtCtrls, define_types,{stats,}StatThdsUtil,lesion_pattern,Mat,Math,Distr,Vector; procedure FirthAnalyzeNoThread(lnCond, lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: bytep;lOutImgMn,lSymptomRA: SingleP;lOutImg: SingleRAp); implementation uses npmform, dialogs; procedure VisualProg(lPos: Integer); begin MainForm.ProgressBar1.Position := lPos; MainForm.Refresh; end; var finalloglik: SingleP0; KxKA1,KxKB1,KxKA,KxKB :TMatrix; Kvec,Kvec1 : TVector; Kveci,kVeci1 : TVectori; betak,xbeta,y,pi,ustar, XXx,XXXW2,XXFisher,XXcovs,XXXWPrime, deltahalfs,deltat,delta,covs,x,Fisher,XW2,W,XWprime,Hprime,H,ustarmat,negx: TMatrix; lBarX: TProgressBar; lnCondx,lnCritx,lBarPosX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx,lImagesCountx : integer; lPlankImgx: byteP;lOutImgMnx,lSymptomRAx: SingleP; lOutImgX: SingleRAp; procedure logistfx (xin: SingleP; var lZvals: SingleP0; numSubj,numCond: integer; lComputeIntercept: boolean); //todo zero output incase exit //yin = 1..numSubj binary 0/1 values //xin = numSubj*numCond predictors //Chivals = 0..numCond p-values - the 0th Khi-value is the intercept // [0th value will not be computed if ; lComputeIntercept= false] label 123,666; const maxit = 25; maxhs = 5; epsilon = 0.0001; maxstep = 10; var SumY0,SumY1,mx, beta0,loglik,loglikold: double; sumy, n, i,j, k, iter,halfs,lCond,dropCond: integer; variability,firth: boolean; procedure crossprodustar; var inc,row: integer; begin for row := 1 to k do begin ustarmat[row,1] := 0; for inc := 1 to ustar.r do ustarmat[row,1] := ustarmat[row,1] + (x[row,inc]*ustar[inc,1]); end; end; procedure Diag2Vec; var inc: integer; begin for inc := 1 to pi.r do ustar[inc,1] := ustar[inc,1]+ H[inc,inc]*(0.5-pi[inc,1]); end; //nested DiagP2 procedure DiagP2 (var W, P: TMatrix); var inc: integer; begin W.Zero; for inc := 1 to P.r do W[inc,inc] := Power((P[inc,1] * (1-P[inc,1])),0.5) ; end; //nested DiagP2 procedure ComputeFisher; begin DiagP2(W,pi); XW2.mult(x,W); //XWPrime.copy( XW2); //XWPrime.transpose; XWPrime.transpose(XW2); Fisher.mult(XW2,XWPrime); covs.copy( Fisher); covs.Invert2(KxKA,KxKB,Kvec,Kveci) end; //nested computeFisher procedure computedropdelta; var jinc,iinc,ii,jj: integer; begin DiagP2(W,pi); XXXW2.mult(XXx,W); //XXXWPrime.copy( XXXW2); //XXXWPrime.transpose; XXXWPrime.transpose(XXXW2); XXFisher.mult(XXXW2,XXXWPrime); XXcovs.copy( XXFisher); //XXcovs.Invert; XXcovs.Invert2(KxKA1,KxKB1,Kvec1,Kveci1); covs.Zero; ii := 0; for iinc := 1 to (k) do begin if iinc <> (dropCond+1) then begin //leave the specified column zeros... inc(ii); jj := 0; for jinc := 1 to (k) do begin if jinc <> (dropCond+1) then begin inc(jj); covs[iinc,jinc] := xxCovs[ii,jj]; end; end; end; end; end; function firthpenalty: double; begin ComputeFisher; //result := 0.5 * ln(abs(Fisher.det)); result := 0.5 * ln(abs(Fisher.Det2(KxKA,kVeci,kVec))); end; //nested firthpenalty function ComputeLogLik: double; var inc: integer; lDenom: double; begin xbeta.mult(betak,negx); for inc := 1 to n do begin lDenom := (1 + exp( xbeta[inc,1])); if lDenom = 0 then showmessage('yikes') else pi[inc,1] := 1/lDenom; end; result := 0; for inc := 1 to n do if y[inc,1] = 1 then //if pi[inc,1] <> 1 then result := result+ln(pi[inc,1]); for inc := 1 to n do if y[inc,1] = 0 then //if pi[inc,1] <> 1 then result := result+ln(1-pi[inc,1]); if firth then result := result + firthpenalty; end;//nested ComputeLogLik begin for i := 0 to (numCond) do lZVals^[i] := 0; // if (numSubj < 2) or (numCond < 1) then exit; //ensure there is some variability in the input data... variability := false; i := 1; repeat inc(i); if xin^[i] <> xin^[1] then variability := true; until (i= (numSubj*numCond)) or (variability); if not variability then exit; //no variance in the regressors... variability := false; i := 1; repeat inc(i); if y[i,1] <> y[1,1] then variability := true; until (i= (numSubj)) or (variability); if not variability then exit; //no variance in the dependent variable... dropCond := -1; //initially compute full model, then compute effect of removing individual conditions firth := true; n := numSubj; k := numCond + 1; //get memory //beta := TMatrix.Create(n,1); //design our model //first row = 1: ell samples have equal weight for i := 1 to n do x.M[1,i] := 1; //next load model into x iter := 0; for j := 2 to k do for i := 1 to n do begin inc(iter); x.M[j,i] := xin^[iter]; end; //WriteMatrix('Observations',y); //WriteMatrix('Model',x); //negx is just sing-swapped - we will generate this as we use it a lot... for j := 1 to k do for i := 1 to n do begin negx.M[j,i] := -x.M[j,i]; end; //now start computations sumy := 0; for i := 1 to n do sumy := sumy + round(y[i,1]); if (sumy <= 0) or (sumy >= n) then begin //serious error: no variability. This should have been detected earlier in the procedure when yin was tested for variability goto 666; end; beta0 := ln((sumy/n)/(1 - sumy/n));//initial estimate 123: //go here for each dropcond if DropCond >= 0 then begin betak.Ones; betak.mult( 0) //start with a null model... does not really make sense end else begin betak.zero; betak[1,1] := (beta0); end; iter := 0; if DropCond >= 0 then begin //drop one of the factors... if dropCond <> 0 then begin//include intercept for i := 1 to n do XXx.M[1,i] := 1; lCond := 1; end else lCond := 0; for j := 1 to NumCond do begin if j <> DropCond then begin inc(lCond); for i := 1 to n do XXx.M[lCond,i] := x.M[j+1,i]; end; //if j <> dropCond end; end;//if lDropCond >= 0 loglik := ComputeLogLik; repeat inc(iter); ComputeFisher; HPrime.mult(XWPrime,covs); H.mult(HPrime,XW2); //WriteMatrix(covs); ustar.Sub(y,pi); if firth then Diag2Vec; crossprodustar; if dropCond >= 0 then // model with dropped factor computedropdelta; deltat.mult(covs,ustarmat); delta.transpose(deltat); mx := delta.MatAbsMax/MaxStep; if mx > 1 then delta.mult(mx);//scale delta betak.add(delta); loglikold := loglik; halfs := 1; while halfs <= maxhs do begin // Half-Steps //fx(iter,halfs,loglik); loglik := ComputeLogLik; deltahalfs.mult(delta,power(2,-halfs)); betak.sub(deltahalfs); if (loglik > loglikold) then break; inc(halfs); end; if delta.MatAbsMax <= epsilon then break; until (iter >= maxit); //fx(DropCond,loglik); //done with this model - record model fit if DropCond < 0 then finalloglik^[k] := loglik //full model else begin finalloglik^[DropCond] := loglik; //model with a factor removed end; if DropCond < numCond then begin inc(DropCond); if (DropCond = 0) and (not lComputeIntercept) then //only compute intercept model if requested inc(DropCond); goto 123; end; //finally - results //ResultsForm.Memo1.lines.add (inttostr(j)+' cases have Y=0, '+inttostr(n-j)+' cases have Y=1'); if lComputeIntercept then J := 0 else J := 1; for i := J to (k-1) do begin lZVals^[i] := abs(2*(finalloglik^[i]-finalloglik^[k])); //find direction of effect - does a larger value of the IV predict more zeros or ones lZVals^[i] := pNormalInv(ChiSq(lZVals^[i],1)); //we have now computed a Z scores - but Chi is one tailed, so all Z > 0... lets check direction Sumy0 := 0; Sumy1 := 0; for iter := 1 to n do begin if y[iter,1] = 0 then Sumy0 := Sumy0 + x.M[i+1,iter] //+1: M indexed from 1, ZVal indexed from 0 else Sumy1 := Sumy1 + x.M[i+1,iter]; //+1 M indexed from 1 end; //compute means Sumy1 := Sumy1/sumy; Sumy0 := Sumy0/(n-sumy); if Sumy0 < Sumy1 then //negative z-scores: damage here predicts performance is BETTER lZVals^[i] := -lZVals^[i]; end; (*if lComputeIntercept then //intercept is the 0th value lChiVals[0] := abs(2*(finalloglik[0]-finalloglik[k])); for i := 1 to (k-1) do //k-1 as this is indexed from 0 lChiVals[i] := abs(2*(finalloglik[i]-finalloglik[k])); *) 666: end; //FirthAnalyzeNoThread (lnCond,lnCrit, lnPermute,1,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lPlankImg,lOutImgSum,lSymptomRA,lOutImg); procedure FirthAnalyzeNoThread(lnCond, lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: bytep;lOutImgMn,lSymptomRA: SingleP;lOutImg: SingleRAp); //calls logistf (yin,xin: SingleP; var lChivals: SingleP0; numSubj,numCond: integer); label 666; const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lObs: Bytep; lPrevZVals: array [1..knPrevPattern] of SingleP0; lZVals: SingleP0; lPatternPos,lC,lnLesion,lPosPct,lPos,lPos2,lPos2Offset,lnCritLocal,n,k: integer; begin //statthread lnCritLocal := lnCrit; if lnCritLocal < 1 then lnCritLocal := 1; Getmem(lObs,lImagesCount*sizeof(byte)); Getmem(lZVals,(lnCond+1)*sizeof(single)); for lPos := 1 to knPrevPattern do Getmem(lPrevZVals[lPos],(lnCond+1)*sizeof(single)); n := lImagesCount; k := lnCond + 1; y := TMatrix.Create(n,1); GetMem(finalloglik,(k+1)*sizeof(single));//finalloglik := TVector.Create(k+1); x := TMatrix.Create (k, n); betak:=TMatrix.Create(1,k); covs:=TMatrix.Create(k,k); delta:=TMatrix.Create(1,k); deltahalfs:=TMatrix.Create(1,k); deltat:=TMatrix.Create(k,1); Fisher:=TMatrix.Create(k,k); H:=TMatrix.Create(n,n); HPrime:=TMatrix.Create(n,k); negx:=TMatrix.Create(k,n); pi:=TMatrix.Create(n,1); ustar:=TMatrix.Create(n,1); ustarmat:=TMatrix.create(k,1); W:=TMatrix.Create(n,n); xbeta:=TMatrix.Create(1,n); XW2:=TMatrix.Create(k,n); //XWPrime:=TMatrix.Create(k,n); XWPrime:=TMatrix.Create(n,k); XXcovs:=TMatrix.Create(k-1,k-1); XXFisher:=TMatrix.Create(k-1,k-1); XXx:=TMatrix.Create(k-1,n); XXXW2:=TMatrix.Create(k-1,n); //XXXWPrime:=TMatrix.Create(k-1,n); XXXWPrime := TMatrix.Create ( n, k-1); KxKA := TMatrix.Create(k,k); KxKB := TMatrix.Create(k,k); Kvec := TVector.Create(k); Kveci := TVectori.Create(k); KxKA1 := TMatrix.Create(k-1,k-1); KxKB1 := TMatrix.Create(k-1,k-1); Kvec1 := TVector.Create(k-1); Kveci1 := TVectori.Create(k-1); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; for lPos := 1 to lImagesCount do begin if lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2] = 0 then begin //no lesion y[lPos,1] := 0; lObs^[lPos] := 0; end else begin //lesion inc(lnLesion); lObs^[lPos] := 1; y[lPos,1] := 1; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCritLocal) and (lnLesion < lImagesCount) then begin lPattern := SetOrderX (lObs,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin inc(gnVoxTestedRA[lThread]); //logistfx(lObs,lSymptomRA, lZvals, lImagesCount,lnCond,false); for lC := 1 to lnCond do lOutImg^[lC]^[lPos2Offset] := lPrevZvals[lPos]^[lC]; end else begin //new pattern - need to compute inc(gnVoxTestedRA[lThread]); logistfx(lSymptomRA, lZvals, lImagesCount,lnCond,false); for lC := 1 to lnCond do lOutImg^[lC]^[lPos2Offset] := lZvals^[lC]; lPrevPatternRA[lPatternPos] := lPattern; for lC := 1 to lnCond do lPrevZVals[lPatternPos]^[lC] := lZvals^[lC]; inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; end; //new pattern end; //nlesion > nCritical end; //for each voxel //gMat := false; 666: freemem(lObs); for lPos := 1 to knPrevPattern do freemem(lPrevZVals[lPos]); freemem(lZVals); y.free; x.free; betak.free; covs.free; delta.free; deltahalfs.free; deltat.free; Fisher.free; H.free; HPrime.free; negx.free; pi.free; ustar.free; ustarmat.Free; W.free; xbeta.free; XW2.free; XWPrime.free; XXcovs.free; XXFisher.free; XXx.free; XXXW2.free; XXXWPrime.free; KxKA.free; KxKB.free; Kvec.free; Kveci.free; KxKA1.free; KxKB1.free; Kvec1.free; Kveci1.free; freemem(finalloglik); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/LesionStatThds.pas���������������������������������������0000755�0001750�0001750�00000045077�11354673540�021624� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit LesionStatThds; interface uses SysUtils, ComCtrls,Classes, Graphics, ExtCtrls, define_types,stats,StatThdsUtil,Brunner,lesion_pattern; type TLesionStatThread = class(TThread) private lBarX: TProgressBar; lttestx,lBMx: boolean; lnCritx,lBarPosX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx, lImagesCountx,lControlsx : integer; lPlankImgx:ByteP; lOutImgMnx,lOutImgBMx,lOutImgTx,lOutImgAUCX,lSymptomRAx: SingleP; //lBarX: TProgressBar; procedure DoVisualSwap; protected procedure Execute; override; procedure VisualProg(lPos: Integer); procedure Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg:bytep;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); virtual; abstract; public constructor Create(lBar: TProgressBar;lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg:ByteP;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); end; { Lesion - image reveals value } TLesionContinuous = class(TLesionStatThread ) protected procedure Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: byteP;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); override; end; TLesionBinom = class(TLesionStatThread ) protected procedure Analyze(lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: byteP;lOutImgMn,lOutImgL,lOutImgX,lOutImgAUC,lSymptomRA: SingleP); override; end; implementation (*procedure OutStr(lStr: string); var lOutname: string; f: TextFile; begin lOutname:='c:\fx.txt'; if fileexists(lOutname) then begin { open a text file } AssignFile(f, lOutname); Append(f); Writeln(f, lStr); Flush(f); { ensures that the text was actually written to file } { insert code here that would require a Flush before closing the file } CloseFile(f); end; end; *) Const Two32 = 4294967296.0 ; function GenRandThreaded(lRange: integer; var lRandSeed:comp): integer; //normal random function does not work well when threaded - randseed is changed by each thread const lFactor = $08088405 ; lTerm = 1 ; type lT = array [0..1] of longint ; var lX: extended; begin lRandSeed := lRandSeed*lFactor + lTerm; lT(lRandSeed)[1] := 0 ; // < May'04 was: RS := RS - Trunc(RS/Two32)*Two32 ; lX := lRandSeed/Two32 ; result := trunc((lRange)*lX); end; procedure GenPermuteThreaded (lnSubj: integer; var lOrigOrder,lRanOrder: DoubleP0; var lRandSeed:comp); var lInc,lRand: integer; lSwap: double; begin Move(lOrigOrder^,lRanOrder^,lnSubj*sizeof(double)); for lInc := lnSubj downto 2 do begin lRand := GenRandThreaded(lInc,lRandSeed); lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc-1]; lRanOrder^[lInc-1] := lSwap; end; end; procedure StatPermuteThreaded (lttest,lBM: boolean; lnSubj, lnGroup0,lnPermute,lThread: integer;var lOrigOrder: DoubleP0); var lInc: integer; lOutT,lDF,lBMz: double; lRS: Comp; lRanOrderp: pointer; lRanOrder: Doublep0; begin if (lnSubj < 1) or (lnPermute < 1) then exit; createArray64(lRanOrderp,lRanOrder,lnSubj); lRS := 128; for lInc := 1 to lnPermute do begin GenPermuteThreaded(lnSubj, lOrigOrder,lRanOrder,lRS); //generate random order of participants if lttest then begin TStat2 (lnSubj, lnGroup0, lRanOrder, lOutT); if lOutT > gPermuteMaxT[lThread,lInc] then gPermuteMaxT[lThread,lInc] := lOutT; if lOutT < gPermuteMinT[lThread,lInc] then gPermuteMinT[lThread,lInc] := lOutT; end; //compute ttest if lBM then begin //BMTest (lnSubj, lnGroup0, lRanOrder,lOutT); tBM (lnSubj, lnGroup0, lRanOrder,lBMz,lDF); lBMz := BMzVal (lnSubj, lnGroup0,lBMz,lDF); if lBMz > gPermuteMaxBM[lThread,lInc] then gPermuteMaxBM[lThread,lInc] := lBMz; if lBMz < gPermuteMinBM[lThread,lInc] then gPermuteMinBM[lThread,lInc] := lBMz; end; //compute BM end; freemem(lRanOrderp); end; procedure GenPermuteThreadedBinom (lnSubj: integer; var lOrigOrder,lRanOrder: ByteP0; var lRandSeed:comp); var lInc,lRand: integer; lSwap: byte; begin Move(lOrigOrder^,lRanOrder^,lnSubj); for lInc := lnSubj downto 2 do begin lRand := GenRandThreaded(lInc,lRandSeed); lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc-1]; lRanOrder^[lInc-1] := lSwap; end; end; procedure StatPermuteBinomialThreaded (lnSubj, lnGroup0,lnPermute,lThread: integer;var lOrigOrder: ByteP0); var lInc: integer; lOutP: double; lRS: Comp; lRanOrder: byteP0; //lRanOrderp: pointer; //lRanOrder: Doublep0; begin if (lnSubj < 1) or (lnPermute < 1) then exit; //createArray64(lRanOrderp,lRanOrder,lnSubj); getmem(lRanOrder,lnSubj); lRS := 128; for lInc := 1 to lnPermute do begin GenPermuteThreadedBinom(lnSubj, lOrigOrder,lRanOrder,lRS); //generate random order of participants (*if lChi2 then begin Chi2 (lnSubj, lnGroup0, lRanOrder, lOutT); if lOutT > gPermuteMaxT[lThread,lInc] then gPermuteMaxT[lThread,lInc] := lOutT; if lOutT < gPermuteMinT[lThread,lInc] then gPermuteMinT[lThread,lInc] := lOutT; end; //compute ttest if lLieber then begin*) //Liebermeister2bP (lnSubj, lnGroup0, lRanOrder,lOutP); Liebermeister2bP (lnSubj, lnGroup0, lRanOrder,lOutP); if (lOutP > 0) and (lOutP < gPermuteMinT[lThread,lInc]) then begin //negative correlation //fx(lOutP, gPermuteMinBM[lThread,lInc]); gPermuteMinT[lThread,lInc] := lOutP; end; if (lOutP < 0) and ( lOutP > gPermuteMaxT[lThread,lInc]) then //negative correlation gPermuteMaxT[lThread,lInc] := lOutP; //end; //compute BM end; freemem(lRanOrder); end; procedure TLesionStatThread .DoVisualSwap; begin lBarX.Position := lBarPosX; end; procedure TLesionStatThread .VisualProg(lPos: Integer); begin lBarPosX := lPos; {$IFDEF FPC}Synchronize(@DoVisualSwap); {$ELSE} Synchronize(DoVisualSwap);{$ENDIF} end; constructor TLesionStatThread .Create(lBar: TProgressBar; lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: byteP;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); begin lBarX := lBar; lttestx := lttest; lBMx:= lBM; lThreadX := lThread; lThreadStartX := lThreadStart; lThreadEndX := lThreadEnd; lStartVoxx := lStartVox; lVoxPerPlankx := lVoxPerPlank; lImagesCountX := lImagesCount; lControlsX := lControlsIn; lPlankImgx := lPlankImg; lOutImgMnx := lOutImgMn; lOutImgBMx := lOutImgBM; lOutImgTx := lOutImgT; lOutImgAUCx := lOutImgAUC; lSymptomRAx := lSymptomRA; lnPermuteX := lnPermute; lnCritX := lnCrit; FreeOnTerminate := True; inherited Create(False); end; { The Execute method is called when the thread starts } procedure TLesionStatThread .Execute; begin Analyze(lttestx,lBMx, lnCritX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx,lImagesCountx,lControlsx,lPlankImgX,lOutImgMnx,lOutImgBMx,lOutImgTx,lOutImgAUCx,lSymptomRAx); end; procedure TLesionContinuous.Analyze (lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIN : integer; lPlankImg:bytep;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); //pattern variables const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lPrevZValsT,lPrevZValsBM,lPrevAUCVals: array [1..knPrevPattern] of Single; lPatternPos: integer; lLesionOrderp: bytep; //standard variables var lStr: string; lObstp,lObsp: pointer; lObst,lObs: Doublep0; lT,lBMz,lDF: Double; lObsB: bytep0; lnLesion,lnNoLesion,lPosPct,lPos,lPos2,lPos2Offset,lnControl, lnControlsPlusLesion,lnControlsPlusPatients : integer; begin //statthread //init patterns lnControl := abs(lControlsIn); if lControlsIn < 0 then begin //binomial getmem(lObsB, lImagesCount+lnControl); end; lnControlsPlusPatients := lImagesCount+lnControl; for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; //lMaxLesion := lImagesCount-lnCrit; getmem(lLesionOrderp, lImagesCount *sizeof(byte)); //now init standard variables createArray64(lObsp,lObs,lnControlsPlusPatients); lPosPct := (lThreadEnd-lThreadStart) div 100; //if lThread = 1 then // OutStr( inttostr(lThreadStart)+':'+inttostr(lThreadEnd)); //xxxxx for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; lnNoLesion := 0; for lPos := 1 to lImagesCount do begin if lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2] = 0 then begin //no lesion inc(lnNoLesion); lLesionOrderp^[lPos] := 0; lObs^[lnNoLesion-1] := lSymptomRA^[lPos]; end else begin //lesion inc(lnLesion); lLesionOrderp^[lPos] := 1; //lObs^[lImagesCount-lnLesion] := lSymptomRA^[lPos]; //note: lObs indexed from zero! lObs^[lImagesCount-lPos+lnNoLesion] := lSymptomRA^[lPos]; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) and (lnLesion < lImagesCount) then begin //when there are 0 lesions or all lesions there is no variability! inc(gnVoxTestedRA[lThread]); //now check if we have seen this precise lesion order recently... lPattern := SetOrderX (lLesionOrderp,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin //lesion pattern is not novel if lttest then lOutImgT^[lPos2Offset] := lPrevZvalsT[lPos]; if lBM then lOutImgBM^[lPos2Offset] := lPrevZvalsBM[lPos]; if lOutImgAUC <> nil then lOutImgAUC^[lPos2Offset] := lPrevAUCvals[lPos]; end else begin //lesion pattern is novel //record novel pattern inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; lPrevPatternRA[lPatternPos] := lPattern; lnControlsPlusLesion := lnControlsPlusPatients; if (lControlsIn > 0) {and (lnLesion > 0)} then begin //anaCOm createArray64(lObstp,lObst,lImagesCount); for lPos := 1 to lImagesCount do lObst^[lPos-1] := lObs^[lPos-1]; for lPos := 1 to lnLesion do lObs^[lPos-1+lnControl] := lObst^[lPos-1+lnNoLesion]; freemem(lObstP); for lPos := 1 to lnControl do lObs^[lPos-1] := lSymptomRA^[lPos+lImagesCount]; lnControlsPlusLesion := lnControl+lnLesion; lnNoLesion := {lnNoLesion +} lnControl; end;//controls (*if lPos2 = 2570879 then begin //xxxx for lPos := 1 to lImagesCount do begin outstr(inttostr(lPos)+'>'+floattostr(lObs^[lPos-1]) ); end; end;*) if lttest then begin if lControlsIn > 0 then begin//anacom TStat2Z (lnControlsPlusLesion, lnControl {lnNoLesion},lObs,lT); (* if lPos2 = 2570879 then begin outstr( floattostr(lT)+ ' '+inttostr(lnControl)); //xxxx for lPos := 1 to lnControlsPlusLesion do begin outstr(inttostr(lPos)+', '+floattostr(lObs^[lPos-1]) ); end; end; *) end else TStat2 (lnControlsPlusLesion, lnNoLesion, lObs,lT); lOutImgT^[lPos2Offset] := lT; lPrevZValsT[lPatternPos] := lT; end; if lBM then begin tBM (lnControlsPlusLesion, lnNoLesion, lObs,lBMz,lDF); lBMz := BMzVal (lnControlsPlusPatients, lnNoLesion,lBMz,lDF); lOutImgBM^[lPos2Offset] := lBMz; lPrevZValsBM[lPatternPos] := lBMz; end; if lOutImgAUC <> nil then begin lOutImgAUC^[lPos2Offset] := continROC (lnControlsPlusLesion, lnNoLesion, lObs); lPrevAUCVals[lPatternPos] := lOutImgAUC^[lPos2Offset]; end; StatPermuteThreaded (lttest,lBM,lImagesCount, lnNoLesion,lnPermute,lThread, lObs); end; //novel lesion pattern end; //in brain mask - compute end; //for each voxel freemem(lObsP); freemem(lLesionOrderp); if lControlsIn < 0 then //binomial freemem(lObsB); end; procedure TLesionBinom.Analyze (lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: bytep;lOutImgMn,lOutImgL,lOutImgX,lOutImgAUC,lSymptomRA: SingleP); //procedure TLesionBinomial.Analyze (lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgL,lOutImgX,lSymptomRA: SingleP); //pattern variables const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lPrevZValsL ,lPrevAUCVals: array [1..knPrevPattern] of Single; lPatternPos: integer; lLesionOrderp: bytep; //standard variables var //lObsp: pointer; //lObs: Doublep0; lPrevZVals lObs: ByteP0; lAUC,lZ: Double; lnLesion,lPosPct,lPos,lPos2,lPos2Offset,lnVoxTested: integer; begin //Binomial StatThread //init patterns for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; getmem(lLesionOrderp, lImagesCount *sizeof(byte)); //now init standard variables //createArray64(lObsp,lObs,lImagesCount); getmem(lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; for lPos := 1 to lImagesCount do begin if ((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]) = 0 then begin //no lesion lObs^[lImagesCount-lPos+lnLesion] := round(lSymptomRA^[lPos]); lLesionOrderp^[lPos] := 0; end else begin //lesion inc(lnLesion); lLesionOrderp^[lPos] := 1; lObs^[lnLesion-1] := round(lSymptomRA^[lPos]); //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) and (lnLesion < lImagesCount) then begin //when there are 0 lesions or all lesions there is no variability! inc(gnVoxTestedRA[lThread]); //next check patterns lPattern := SetOrderX (lLesionOrderp,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin //lesion pattern is not novel //if lChi2 then // lOutImgX^[lPos2Offset] := lPrevZvalsX[lPos]; //if lLieber then lOutImgL^[lPos2Offset] := lPrevZvalsL[lPos]; if lOutImgAUC <> nil then lOutImgAUC^[lPos2Offset] := lPrevAUCvals[lPos]; end else begin //lesion pattern is novel //record novel pattern inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; lPrevPatternRA[lPatternPos] := lPattern; {if lChi2 then begin Chi2 (lImagesCount, lnLesion, lObs,lT); lOutImgX^[lPos2Offset] := lT;//lT; lPrevZValsX[lPatternPos] := lT; end; if lLieber then begin} Liebermeister2b(lImagesCount, lnLesion, lObs,lAUC,lZ); if lOutImgAUC <> nil then lOutImgAUC^[lPos2Offset] := lAUC; lPrevAUCVals[lPatternPos] := lAUC; lOutImgL^[lPos2Offset] := lZ; lPrevZValsL[lPatternPos] := lZ; //end; StatPermuteBinomialThreaded (lImagesCount, lnLesion,lnPermute,lThread, lObs); end; end; //in brain mask - compute end; //for each voxel freemem(lObs); freemem(lLesionOrderp) end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npm.lpr��������������������������������������������������0000755�0001750�0001750�00000001275�11421113036�017470� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������program npm; {$mode objfpc}{$H+} {$I options.inc} uses {$IFDEF UNIX}cthreads,{$ENDIF} Interfaces, // this includes the LCL widgetset Forms, npmform,stats ,nifti_hdr,valformat, part, gzio2, StatThds, StatThdsUtil, brunner, statcr, distr, GraphicsMathLibrary, define_types, ReadInt {$IFDEF SPREADSHEET} ,design,spread{$ENDIF}; {$IFNDEF FPC} {$R npm.res} {$ENDIF} begin Application.Initialize; Application.CreateForm(TMainForm, MainForm); {$IFDEF SPREADSHEET} Application.CreateForm(TSpreadForm, SpreadForm); Application.CreateForm(TDesignForm, DesignForm); {$ENDIF} Application.CreateForm(TReadIntForm, ReadIntForm); Application.Run; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/ReadInt.lfm����������������������������������������������0000755�0001750�0001750�00000001762�11540170632�020215� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object ReadIntForm: TReadIntForm Left = 306 Height = 80 Top = 554 Width = 469 HorzScrollBar.Page = 468 VertScrollBar.Page = 79 ActiveControl = ReadIntEdit BorderStyle = bsDialog Caption = 'Integer required' ClientHeight = 80 ClientWidth = 469 Constraints.MaxHeight = 80 Constraints.MaxWidth = 469 Constraints.MinHeight = 80 Constraints.MinWidth = 469 Font.Name = 'MS Sans Serif' OnCreate = FormCreate Position = poScreenCenter LCLVersion = '0.9.28.2' object ReadIntLabel: TLabel Left = 16 Height = 14 Top = 12 Width = 336 Alignment = taRightJustify AutoSize = False Caption = 'Enter a number' ParentColor = False end object ReadIntEdit: TSpinEdit Left = 360 Height = 27 Top = 12 Width = 93 MaxValue = 0 TabOrder = 0 end object OKBtn: TButton Left = 368 Height = 25 Top = 44 Width = 75 BorderSpacing.InnerBorder = 4 Caption = 'OK' OnClick = OKBtnClick TabOrder = 1 end end ��������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/Copy of npm.cfg������������������������������������������0000755�0001750�0001750�00000001011�11031052252�020675� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-$A+ -$B- -$C+ -$D+ -$E- -$F- -$G+ -$H+ -$I+ -$J+ -$K- -$L+ -$M- -$N+ -$O+ -$P+ -$Q- -$R- -$S- -$T- -$U- -$V+ -$W- -$X+ -$YD -$Z1 -cg -AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; -H+ -W+ -M -$M16384,1048576 -K$00400000 -LN"c:\program files\borland\delphi4\Lib" -U"C:\pas\mricron\common;C:\pas\mricron\fpmath" -O"C:\pas\mricron\common;C:\pas\mricron\fpmath" -I"C:\pas\mricron\common;C:\pas\mricron\fpmath" -R"C:\pas\mricron\common;C:\pas\mricron\fpmath" �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/turbolesion.pas������������������������������������������0000755�0001750�0001750�00000052347�11477144752�021263� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit turbolesion; interface {$H+} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes; Type TLDMPrefs = record NULP,BMtest,Ttest,Ltest: boolean; CritPct,nCrit,nPermute,Run: integer; ValFilename, OutName, ExplicitMaskName: string; end; function TurboLDM (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; var lPrefs: TLDMPrefs ; var lSymptomRA: SingleP;var lFactname,lOutName: string): boolean; implementation uses npmform; (*procedure Debog (var lSumImg: Smallintp; lVox: integer); var lInName : string; lFData: file; begin lInName := 'c:\16.img'; assignfile(lFdata,lInName); filemode := 2; Rewrite(lFdata,lVox*sizeof(smallint)); BlockWrite(lFdata,lSumImg^, 1 {, NumWritten}); closefile(lFdata); end;*) function MakeSum (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; var lSumImg: Smallintp): boolean; //if successful, you MUST freemem(lSumImg)... label 667; var lVolVox,lVox,lImg,lPosPct: integer; lVolImg: byteP; begin result := false; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then exit; getmem(lVolImg,lVolVox* sizeof(byte)); getmem(lSumImg,lVolVox* sizeof(smallint)); for lVox := 1 to lVolVox do //June 2009 init array lSumImg^[lVox] := 0; (* for lVox := 1 to lVolVox do if lVolImg^[lVox] <> 0 then lSumImg^[lVox] := lSumImg^[lVox]+1;*) for lImg := 1 to lImages.Count do begin lPosPct := round(100*(lImg / lImages.Count)); MainForm.ProgressBar1.Position := lPosPct; Application.Processmessages; if not LoadImg8(lImages[lImg-1], lVolImg, 1, lVolVox,round(gOffsetRA[lImg]),1,gDataTypeRA[lImg],lVolVox) then goto 667; for lVox := 1 to lVolVox do if lVolImg^[lVox] <> 0 then lSumImg^[lVox] := lSumImg^[lVox]+1; end;//for each image MainForm.NPMmsg('Sum image finished = ' +TimeToStr(Now)); MainForm.ProgressBar1.Position := 0; //Debog(lSumImg, lVolVox); freemem(lVolImg); result := true; exit; 667: //you only get here if you aborted ... free memory and report error freemem(lVolImg); freemem(lSumImg); MainForm.NPMMsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; function ThreshSumImg (var lSumImg: Smallintp; lVolVox,lThresh: integer): integer; //sets all voxels with values < lThresh to zero, returns number of voxels to survive threshold. var lPos: integer; begin result := 0; if lVolVox < 1 then exit; for lPos := 1 to lVolVox do if lSumImg^[lPos] < lThresh then lSumImg^[lPos] := 0 else inc(result); end; function ExplicitMaskSumImg (lMaskName: string; var lSumImg: Smallintp; lVolVox: integer): integer; //Any voxels in MaskImg that are 0 are zeroed in the SumImg var lOK: boolean; lPos: integer; lMaskHdr: TMRIcroHdr; lMaskData: bytep; label 666; begin result := 0; if (lVolVox < 1) or (not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr)) then begin MainForm.NPMmsg('Error: unable to load explicit mask named '+lMaskName); exit; end; if lVolVox <> (lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]) then begin MainForm.NPMmsg('Error: data and explicit mask have different sizes '+lMaskName); exit; end; getmem(lMaskData,lVolVox* sizeof(byte)); lOK := LoadImg8(lMaskName, lMaskData, 1, lVolVox,round(lMaskHdr.NIFTIhdr.vox_offset),1,lMaskHdr.NIFTIhdr.DataType,lVolVox); if not lOK then goto 666; if lVolVox < 1 then exit; for lPos := 1 to lVolVox do if lMaskData^[lPos] < 1 then lSumImg^[lPos] := 0 else inc(result); 666: freemem(lMaskData); end; function LoadImg8Masked(lInName: string; lImgData: bytep; lMaskData: SmallIntP; lStartMaskPos, lEndMaskPos,linvox_offset,lRApos,lDataType,lVolVox: integer): boolean; label 111; var lFullImgData: bytep; lMaskPos,lPos: integer; begin result := false; if (lVolVox < 1) or (lEndMaskPos < lStartMaskPos) then exit; getmem(lFullImgData,lVolVox* sizeof(byte)); result := LoadImg8(lInName, lFullImgData, 1, lVolVox,linvox_offset,1,lDataType,lVolVox); if result then begin lMaskPos := 0; for lPos := 1 to lVolVox do begin if lMaskData^[lPos] <> 0 then begin inc(lMaskPos); if (lMaskPos >=lStartMaskPos) then lImgData^[lRApos+lMaskPos-1] := lFullImgData^[lPos]; if lMaskPos = lEndMaskPos then goto 111; end;//voxel in mask end; //for each voxel in image end;//if LoadImg8 success 111: freemem(lFullImgData); end; function reformat(var lStatImg: singlep; lMaskImg: smallintp; lVolVox: integer): boolean; var lPos,lStatPos,lMaskItems: integer; begin result := false; if lVolVox < 1 then exit; lMaskItems := 0; for lPos := 1 to lVolVox do if lMaskImg^[lPos] <> 0 then inc(lMaskItems); result := true; if (lMaskItems < 1) or (lMaskItems >= lVolVox) then exit;//no need to reformat //note that we do this in descending order, so we do not overwrite... lStatPos := lMaskItems; for lPos := lVolVox downto 1 do if lMaskImg^[lPos] <> 0 then begin lStatImg^[lPos] := lStatImg^[lStatPos]; dec(lStatPos); end else lStatImg^[lPos] := 0; end;//reformat function NULPcount (lPlankImg: bytep; lVoxPerPlank,lImagesCount: integer; var lUniqueOrders: integer; var lOverlapRA: Overlapp): boolean; procedure CheckOrder(var lObservedOrder: TLesionPattern); var lInc: integer; begin if lUniqueOrders > 0 then begin //see if this is unique for lInc := 1 to lUniqueOrders do if SameOrder(lObservedOrder,lOverlapRA^[lInc],lImagesCount) then exit; //not unique end; //UniqueOrders > 0 //if we have not exited yet, we have found a new ordering! lUniqueOrders := lUniqueOrders + 1; lOverlapRA^[lUniqueOrders] := lObservedOrder; end; var lVox,lPlankImgPos,lPos: integer; lOrder,lPrevOrder: TLesionPattern; begin result := false; lPrevOrder := EmptyOrder;//impossible: forces first voxel of each order to be checked for lVox := 1 to lVoxPerPlank do begin (*if (lVox mod lVoxPerPlankDiv10) = 0 then begin MainForm.ProgressBar1.Position := (lVox div lVoxPerPlankDiv10)*10; MainForm.Refresh; Application.processmessages; end;*) lOrder := EmptyOrder; lPlankImgPos := 0; //lnDeficits := 0; for lPos := 1 to lImagesCount do begin if (lPlankImg^[lPlankImgPos + lVox] > 0) then begin //inc(lnDeficits); SetBit(lPos,lOrder); end; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end; //if (lnDeficits >= lminDeficits) then begin //this is different from the last voxel: perhaps this is a new ordering if (not SameOrder(lOrder,lPrevOrder,lImagesCount)) then CheckOrder(lOrder); //inc(lnVoxels); //end;//nDeficies lPrevOrder := lOrder; end;//for lVox result := true; end; procedure PtoZpermute (lnPermute: integer; lPermuteMaxT, lPermuteMinT: singlep); var lPos: integer; lVal : single; begin if lPos < 1 then exit; for lPos := 1 to lnPermute do begin if (lPermuteMinT^[lPos] > 1.1) or (lPermuteMinT^[lPos] < -1.1) then lPermuteMinT^[lPos] := 0.5; if (lPermuteMaxT^[lPos] > 1.1) or (lPermuteMaxT^[lPos] < -1.1) then lPermuteMaxT^[lPos] := 0.5; lVal := lPermuteMaxT^[lPos]; lPermuteMaxT^[lPos] := lPermuteMinT^[lPos]; lPermuteMinT^[lPos] := lVal; if lPermuteMaxT^[lPos] < 0 then lPermuteMaxT^[lPos] := -pNormalInv(abs(lPermuteMaxT^[lPos])) else lPermuteMaxT^[lPos] := pNormalInv(lPermuteMaxT^[lPos]); if lPermuteMinT^[lPos] < 0 then lPermuteMinT^[lPos] := -pNormalInv(abs(lPermuteMinT^[lPos])) else lPermuteMinT^[lPos] := pNormalInv(lPermuteMinT^[lPos]); end; end; function TurboLDM (var lImages: TStrings; var lMaskHdr: TMRIcroHdr;var lPrefs: TLDMPrefs ; var lSymptomRA: SingleP;var lFactname,lOutName: string): boolean; label 123,667; var lOutNameMod: string; lStatHdr: TNIfTIhdr; lThreshFDR,lThreshPermute,lThreshBonf,lThreshNULP :double; lObsp: pointer; lObs: Doublep0; lRanOrderp: pointer; lRanOrder: Doublep0; lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM,lOutImgSum,lOutImgBM,lOutImgT,lOutImgAUC: singlep; lSumImg: Smallintp; lPlankImg: byteP; lVoxPerPlank,lnPlanks,lTotalMemory,lnVoxTested,lVolVox: int64; lUniqueOrders,lThread,lThreadStart,lThreadInc,lThreadEnd, lPos2,lPosPct,lPos,lPlankImgPos,lPlank,lStartVox,lEndVox: integer; lOverlapRA: Overlapp; {$IFNDEF FPC} lStartTime :DWord;{$ENDIF} begin {$IFNDEF FPC} lStartTime := GetTickCount;{$ENDIF} result := false; lSumImg := nil; lPlankImg := nil; lOutImgSum := nil; lOutImgBM := nil; lOutImgT := nil; lOutImgAUC := nil; lOverlapRA := nil; lUniqueOrders := 0; if lPrefs.Ltest then begin lPrefs.Ttest := false; lPrefs.BMtest := false; end else if (not lPrefs.Ttest) and (not lPrefs.BMtest) then begin//not binomial MainForm.NPMmsg('Error no tests specified'); exit; end; MainForm.NPMmsg('Permutations = ' +IntToStr(lPrefs.nPermute)); MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; if not MakeSum( lImages, lMaskHdr, lSumImg) then goto 667; lnVoxTested := ThreshSumImg(lSumImg,lVolVox,lPrefs.nCrit); MainForm.NPMmsg('Voxels damaged in at least '+inttostr(lPrefs.nCrit)+' individuals = ' +Floattostr(lnVoxTested)); if lnVoxTested < 1 then begin MainForm.NPMmsg('Error: no voxels damaged in at least '+inttostr(lPrefs.nCrit)+' individuals.'); goto 667; end; if (lPrefs.ExplicitMaskName <> '') then begin lnVoxTested := ExplicitMaskSumImg (lPrefs.ExplicitMaskName, lSumImg, lVolVox); MainForm.NPMmsg('Voxels also non-zero in mask '+lPrefs.ExplicitMaskName+' = ' +Floattostr(lnVoxTested)); if lnVoxTested < 1 then begin MainForm.NPMmsg('Error: no remaing voxels also non-zero in mask '+lPrefs.ExplicitMaskName); goto 667; end; end; //compute planks and acquire memory lTotalMemory := lnVoxTested * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/kPlankSz ) + 1; MainForm.NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/kPlankSz)); if (lnPlanks = 1) then begin lVoxPerPlank := lnVoxTested; //we can do this in a single pass getmem(lPlankImg,lTotalMemory) end else begin getmem(lPlankImg,kPlankSz); lVoxPerPlank := kPlankSz div lImages.Count; end; //spatial maps for results getmem(lOutImgSum,lVolVox*sizeof(single)); getmem(lOutImgBM,lVolVox*sizeof(single)); getmem(lOutImgT,lVolVox*sizeof(single)); getmem(lOutImgAUC,lVolVox*sizeof(single)); //initialize memory MainForm.InitPermute (lImages.Count, lPrefs.nPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; lOutImgAUC^[lPos] := 0; end; //next create permuted BM bounds if lPrefs.BMtest then begin MainForm.NPMmsg('Generating BM permutation thresholds'); MainForm.Refresh; createArray64(lObsp,lObs,lImages.Count); for lPos := 1 to lImages.Count do lObs^[lPos-1] := lSymptomRA^[lPos]; genBMsim (lImages.Count, lObs); freemem(lObsp); end; if lPrefs.NULP then getmem(lOverlapRA,lnVoxTested* sizeof(TLesionPattern)); if lPrefs.Ltest then ClearThreadDataPvals(gnCPUThreads,lPrefs.nPermute) else ClearThreadData(gnCPUThreads,lPrefs.nPermute) ; //load and process data lStartVox := 1; lEndVox := 0; for lPlank := 1 to lnPlanks do begin MainForm.NPMmsg('Computing plank = ' +Inttostr(lPlank)+' of '+inttostr(lnPlanks)); lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lnVoxTested then begin lVoxPerPlank := lnVoxTested-lStartVox+1{lVoxPerPlank - (lEndVox-lVolVox)}; lEndVox := lnVoxTested; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8Masked(lImages[lPos-1], lPlankImg,lSumImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error if lPrefs.Ltest then begin with TLesionBinom.Create (MainForm.ProgressBar1,false,true,lPrefs.nCrit, lPrefs.nPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,0,lPlankImg,lOutImgSum,lOutImgBM,lOutIMgT{not used},lOutImgAUC,lSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} end else begin with TLesionContinuous.Create (MainForm.ProgressBar1,lPrefs.ttest,lPrefs.BMtest,lPrefs.nCrit, lPrefs.nPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,0,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA) do //with TLesionContinuous.Create (MainForm.ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,lSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} end; inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //end of threading if lPrefs.NULP then NULPcount (lPlankImg, lVoxPerPlank,lImages.Count, lUniqueOrders, lOverlapRA); lStartVox := lEndVox + 1; end; //calculate max per thread SumThreadData(gnCPUThreads,lPrefs.nPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //data in maps is stored in voxels 1..lnVoxTested - put in spatial order reformat(lOutImgSum,lSumImg,lVolVox); reformat(lOutImgBM,lSumImg,lVolVox); reformat(lOutImgT,lSumImg,lVolVox); reformat(lOutImgAUC,lSumImg,lVolVox); lThreshBonf := MainForm.reportBonferroni('Std',lnVoxTested); if lPrefs.NULP then lThreshBonf := MainForm.reportBonferroni('Number of Unique Lesion Patterns',lUniqueOrders); //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); if lPrefs.Run < 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //save Area Under Curve lOutNameMod := ChangeFilePostfixExt(lOutName,'rocAUC'+lFactName,'.hdr'); if lPrefs.Run < 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgAUC,1); //create new header - subsequent images will use Z-scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lPrefs.Run < 1) and (Sum2Power(lOutImgSum,lVolVox,lImages.Count,lPrefs.nCrit, lPrefs.LTest)) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; //if lPrefs.Run > 0 then //terrible place to do this - RAM problems, but need value to threshold maps // lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap2 (lImages, lPrefs.nCrit,lnVoxTested,lPlankImg)); if lPrefs.ttest then begin //save Ttest //next: convert t-scores to z scores for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lPrefs.nPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; lThreshFDR := MainForm.reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); lThreshPermute := MainForm.reportPermute('ttest',lPrefs.nPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'ttest'+lFactName,'.hdr'); {$IFNDEF FPC} if lPrefs.Run > 0 then begin MainForm.NPMmsgAppend('threshtt,'+inttostr(lPrefs.Run)+','+inttostr(MainForm.ThreshMap(lThreshBonf,lVolVox,lOutImgT))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)+','+inttostr(round((GetTickCount - lStartTime)/1000))); end; {$ENDIF} NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if lPrefs.LTest then begin PtoZpermute (lPrefs.nPermute, lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'L'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); MainForm.reportFDR ('L', lVolVox, lnVoxTested, lOutImgBM); MainForm.reportPermute('L',lPrefs.nPermute,lPermuteMaxT, lPermuteMinT); end;//Liebermeister if lPrefs.BMtest then begin //save Brunner Munzel lThreshFDR := MainForm.reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); lThreshPermute := MainForm.reportPermute('BM',lPrefs.nPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'BM'+lFactName,'.hdr'); if lPrefs.Run > 0 then MainForm.NPMmsgAppend('threshbm,'+inttostr(lPrefs.Run)+','+inttostr(MainForm.ThreshMap(lThreshBonf,lVolVox,lOutImgBM))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end; MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); {$IFNDEF FPC} MainForm.NPMmsg('Processing Time = ' +inttostr(round((GetTickCount - lStartTime)/1000)));{$ENDIF} lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); MainForm.MsgSave(lOutNameMod); //all done result := true;//all done without aborting 667: // free memory and report error if lPlankImg <> nil then freemem(lPlankImg); if lSumImg <> nil then freemem(lSumImg); if lOutImgSum <> nil then freemem(lOutImgSum); if lOutImgBM <> nil then freemem(lOutImgBM); if lOutImgT <> nil then freemem(lOutImgT); if lOutImgAUC <> nil then freemem(lOutImgAUC); if lOverlapRA <> nil then freemem(lOverlapRA); if not result then MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; //TurboLDM end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/anacom.pas�����������������������������������������������0000755�0001750�0001750�00000061664�11326425446�020151� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit anacom; interface {$H+} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr,filename, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes; //procedure DoAnaCOM; function AnacomLesionNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttestIn,lBMIn: boolean): boolean; implementation uses npmform; {$DEFINE NOTmedianfx} function AnacomLesionNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttestIn,lBMIn: boolean): boolean; label 123,667; var lOutNameMod: string; lPlankImg: byteP; lOutImgSum,lOutImgBM,lOutImgT, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM,lCombinedSymptomRA: singleP; lPos,lPlank,lThread,lnControlsPlusPatients: integer; lVolVox,lMinMask,lMaxMask,lTotalMemory,lnPlanks,lVoxPerPlank, lThreadStart,lThreadEnd,lThreadInc,lnLesion,lnPermute, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT,lBMz, lSum,lThresh,lThreshBonf,lThreshPermute,lThreshNULP :double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; lBM,lttest,lLtest: boolean; lnControlNeg: integer; {$IFDEF medianfx} lmedianFX,lmeanFX,lsummean,lsummedian: double; lmediancount: integer; {$ENDIF} begin lnControlNeg := lnControl; //negative for binomial test lttest := lttestin; lbm := lbmin; if (not (lttest)) and (not (lbm)) then begin lLtest := true; lBM := true; lnControlNeg := -lnControl; end; //lttest:= ttestmenu.checked; //lBM := BMmenu.checked; if lnControl < 1 then begin MainForm.NPMmsg('AnaCom aborted - need data from at least 1 control individual'); exit; end; lnPermute := 0;//MainForm.ReadPermute; MainForm.NPMmsg('Permutations = ' +IntToStr(lnPermute)); MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; MainForm.NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); MainForm.NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) //assumes 1bpp else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; {$IFDEF medianfx} lsummean := 0; lsummedian:= 0; lmediancount := 0; {$ENDIF} for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; lnControlsPlusPatients := lImages.Count+lnControl; createArray64(lObsp,lObs,lnControlsPlusPatients); getmem(lOutImgSum,lVolVox* sizeof(single)); getmem(lOutImgBM,lVolVox* sizeof(single)); getmem(lOutImgT,lVolVox* sizeof(single)); MainForm.InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; end; //sumptom array for lesions AND controls for lPos := 1 to lImages.Count do lObs^[lPos-1] := lSymptomRA^[lPos]; for lPos := 1 to lnControl do lObs^[lPos-1+lImages.Count] := lControlSymptomRA^[lPos]; getmem(lCombinedSymptomRA,lnControlsPlusPatients* sizeof(single)); for lPos := 1 to lnControlsPlusPatients do lCombinedSymptomRA^[lPos] := lObs^[lPos-1]; //next create permuted BM bounds if lBM then begin MainForm.NPMmsg('Generating BM permutation thresholds'); MainForm.Refresh; //for lPos := 1 to lImages.Count do // lObs^[lPos-1] := lSymptomRA^[lPos]; genBMsim (lnControlsPlusPatients, lObs); end; ClearThreadData(gnCPUThreads,lnPermute) ; for lPlank := 1 to lnPlanks do begin MainForm.NPMmsg('Computing plank = ' +Inttostr(lPlank)); MainForm.Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TLesionContinuous.Create (MainForm.ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lnControlNeg,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,nil,lCombinedSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; lThreshPermute := 0; lnVoxTested := SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //next report findings if lnVoxTested < 1 then begin MainForm.NPMmsg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lnCrit)+' patients**'); goto 123; end; MainForm.NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); {$IFDEF medianfx} MainForm.NPMmsg('Average MEAN effect size = ' +realtostr((lsummean/lmediancount),3)); MainForm.NPMmsg('Average MEDIAN effect size = ' +realtostr((lsummedian/lmediancount),3)); {$ENDIF} MainForm.NPMmsg('Only tested voxels with more than '+inttostr(lnCrit)+' lesions'); //Next: save results from permutation thresholding.... //Next: save results from permutation thresholding.... lThreshBonf := MainForm.reportBonferroni('Std',lnVoxTested); //Next: NULPS if lRun > 0 then //terrible place to do this - RAM problems, but need value to threshold maps lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap2 (lImages, lnCrit,lnVoxTested,lPlankImg)); //lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap (lImages, lnCrit)); //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); if (lRun < 1) then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //create new header - subsequent images will use Z-scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lRun < 1) and (Sum2PowerCont(lOutImgSum,lVolVox,lImages.Count)) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; //MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if lttest then begin //save Ttest //next: convert t-scores to z scores if lnControl < 1 then for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lnPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; lThresh := MainForm.reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); lThreshPermute := MainForm.reportPermute('attest',lnPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'attest'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('AnaComthreshtt,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgT))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if lBM then begin //save Mann Whitney lThresh := MainForm.reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); lThreshPermute := MainForm.reportPermute('aBM',lnPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'aBM'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('AnaCOMthreshbm,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgBM))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end; //next: free dynamic memory 123: MainForm.FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgT); freemem(lOutImgBM); freemem(lOutImgSum); freemem(lObsp); freemem(lPlankImg); MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); MainForm.MsgSave(lOutNameMod); MainForm.ProgressBar1.Position := 0; exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; //LesionNPMAnalyze (*function readCSV2 (lFilename: string; lCol1,lCol2: integer; var lnObservations : integer; var ldataRA1,ldataRA2: singlep): boolean; const kHdrRow = 0;//1; kHdrCol = 0;//1; var lNumStr: string; F: TextFile; lTempFloat: double; lCh: char; lnFactors,MaxC,R,C:integer; lError: boolean; begin lError := false; result := false; if not fileexists(lFilename) then begin showmessage('Can not find '+lFilename); exit; end; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); if (R <= (kHdrRow+1)) or (MaxC < (kHdrCol+lCol1)) or (MaxC < (kHdrCol+lCol2)) then begin showmessage('problems reading CSV - not enough columns/rows '+inttostr(lCol1)+' '+inttostr(lCol2)); exit; end; lnObservations := R -kHdrRow ; //-1: first row is header.... lnFactors := MaxC-1;// -1: first column is Y values //fx(lnObservations,lnFactors); //exit; getmem(ldataRA1,lnObservations*sizeof(single)); getmem(ldataRA2,lnObservations*sizeof(single)); //second pass Reset(F); C := 1; MaxC := 0; R := 1; lNumStr := ''; lTempfloat := 0; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin if (R > kHdrRow) and (C > kHdrCol) then begin if ((C-kHdrCol) = lCol1) or ((C-kHdrCol) = lCol2) then begin if lNumStr = '-' then begin lTempFloat := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(lNumStr); if (C-kHdrCol) = lCol1 then ldataRA1^[R-kHdrRow] := lTempFloat else if (C-kHdrCol) = lCol2 then ldataRA2^[R-kHdrRow] := lTempFloat; end; //number end; //col1 or col2 end;// else //R > 1 lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 1; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if (lNumStr <> '') and (C = lnFactors) then begin //unterminated string try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except ldataRA2^[R-1] := lTempFloat; end;//unterminated string //read finel item CloseFile(F); FileMode := 2; //Set file access to read/write result := true; end; *) function readTxt (lFilename: string; var lnObservations : integer; var ldataRA1: singlep): boolean; const kHdrRow = 0;//1; kHdrCol = 0;//1; var lCol1: integer; lNumStr: string; F: TextFile; lTempFloat: double; lCh: char; lnFactors,MaxC,R,C:integer; lError: boolean; begin lCol1:= 1; lError := false; result := false; if not fileexists(lFilename) then begin showmessage('Can not find '+lFilename); exit; end; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); if (R <= (kHdrRow+1)) or (MaxC < (kHdrCol+lCol1)) then begin showmessage('problems reading CSV - not enough columns/rows '); exit; end; lnObservations := R -kHdrRow ; //-1: first row is header.... lnFactors := kHdrCol+lCol1;// -1: first column is Y values //fx(lnObservations,lnFactors); //exit; getmem(ldataRA1,lnObservations*sizeof(single)); //second pass Reset(F); C := 1; MaxC := 0; R := 1; lNumStr := ''; lTempfloat := 0; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin if (R > kHdrRow) and (C > kHdrCol) then begin if ((C-kHdrCol) = lCol1) {or ((C-kHdrCol) = lCol2)} then begin if lNumStr = '-' then begin lTempFloat := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(lNumStr); if (C-kHdrCol) = lCol1 then begin //showmessage(lNumStr); ldataRA1^[R-kHdrRow] := lTempFloat; end; {else if (C-kHdrCol) = lCol2 then ldataRA2^[R-kHdrRow] := lTempFloat;} end; //number end; //col1 or col2 end;// else //R > 1 lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 1; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; //showmessage(lNumStr+' '+inttostr(lnFactors)+' '+inttostr(C)); if (lNumStr <> '') and (C = lnFactors) then begin //unterminated string try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(inttostr(R)+' '+floattostr(lTempFLoat)); ldataRA1^[R] := lTempFloat; end;//unterminated string //read finel item CloseFile(F); FileMode := 2; //Set file access to read/write result := true; end; (*procedure DoAnaCOM; label 666; var lControlFilename: string; lI, lnControlObservations : integer; lControldata: singlep; lBinomial: boolean; lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCrit: integer; lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lOutName,lFactname: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA: singleP; begin npmform.MainForm.memo1.lines.clear; npmform.MainForm.memo1.lines.add('AnaCOM analysis requires TXT/CSV format text file.'); npmform.MainForm.memo1.lines.add('One row per control participant.'); npmform.MainForm.memo1.lines.add('First column is performance of that participant.'); npmform.MainForm.memo1.lines.add('Example file:'); //npmform.MainForm.memo1.lines.add('deficit, voxels'); npmform.MainForm.memo1.lines.add('11'); npmform.MainForm.memo1.lines.add('19'); npmform.MainForm.memo1.lines.add('2'); npmform.MainForm.memo1.lines.add('22'); npmform.MainForm.memo1.lines.add('19'); npmform.MainForm.memo1.lines.add('6'); lControlFilename := 'c:\fx.txt'; if (not readTxt (lControlFilename, lnControlObservations,lControldata)) or (lnControlObservations < 1) then begin showmessage('Error reading file '+lControlFilename); exit; end; npmform.MainForm.memo1.lines.add('Control (n='+inttostr(lnControlObservations)+')performance: '); for lI := 1 to lnControlObservations do begin npmform.MainForm.memo1.lines.add(inttostr(lI)+' '+floattostr(lControldata^[lI])); end; //begin - copy lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? //next, get 1st group if not MainForm.GetVal(lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCrit,{,binom}lPredictorList) then begin showmessage('Error with VAL file'); goto 666; end; lTemp4D := CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) then begin Showmessage('Not enough subjects ('+inttostr(lnSubjAll)+') or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; MainForm.SaveHdrDlg.Filename := loutname; lOutName := lOutName+'.nii.gz'; if not MainForm.SaveHdrName ('Base Statistical Map', lOutName) then exit; for lFact := 1 to lnFactors do begin lImageNames.clear; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); lnSubj := lImageNames.Count; if lnSubj > 1 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; MainForm.NPMmsgClear; MainForm.NPMMsg(MainForm.GetKVers); MainForm.NPMMsg('Threads: '+inttostr(gnCPUThreads)); lFactName := lPredictorList.Strings[lFact-1]; lFactName := LegitFilename(lFactName,lFact); MainForm.NPMMsg('Factor = '+lFactname); For lSubj := 1 to lnSubj do MainForm.NPMMsg (lImageNames.Strings[lSubj-1] + ' = '+realtostr(lSymptomRA^[lSubj],2) ); MainForm.NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); MainForm.NPMMsg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); MainForm.NPMMsg('Number of Lesion maps = '+inttostr(lnSubj)); if not CheckVoxelsGroup(lImageNames,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; MainForm.ReportDescriptives(lSymptomRA,lnSubj); AnacomLesionNPMAnalyze(lImageNames,lMaskHdr,lnCrit,-1,lnControlObservations,lSymptomRA,lControldata,lFactName,lOutname,true {ttest},false{BM}); Freemem(lSymptomRA); end; //lnsubj > 1 end; //for each factor if lnSubjAll > 0 then begin Freemem(lMultiSymptomRA); end; 666: lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); ///end //AnacomLesionNPMAnalyze ( lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttest,lBM: boolean): boolean; freemem(lControldata); end;*) end. ����������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/StatThdsUtil.pas�����������������������������������������0000755�0001750�0001750�00000007261�11477106440�021275� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit StatThdsUtil; interface uses ComCtrls,Classes, Graphics, ExtCtrls, define_types,stats,dialogs; const kMaxThreads = 16; kSh = 10; //bits to shift kMaxImages = 1024; kMaxPermute = 4000; kPlankMB : integer = 512; var gnCPUThreads, gThreadsRunning: Integer; kPlankSz : integer;// =1024 {bytes/kb} * 1024 {bytes/mb} * kPlankMB; //e.g. 512 MB gDataTypeRA: array [0..kMaxImages] of integer; gOffsetRA,gScaleRA,gInterceptRA: array [0..kMaxImages] of single; gnVoxTestedRA : array [0..kMaxThreads] of integer; gPermuteMinT,gPermuteMaxT,gPermuteMinBM,gPermuteMaxBM : array [0..kMaxThreads,0..kMaxPermute ] of double; procedure ClearThreadData(lnThreads,lnPermute: integer); function SumThreadDataLite (lnThreads: integer): integer; function SumThreadData (lnThreads,lnPermute: integer;lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP): integer; procedure ClearThreadDataPvals (lnThreads,lnPermute: integer); implementation procedure ClearThreadDataPvals (lnThreads,lnPermute: integer); var lT,lP: integer; begin if lnThreads < 1 then exit; if lnPermute > kMaxPermute then showmessage('Error: recompile with larger kMaxPermute'); for lT := 1 to lnThreads do gnVoxTestedRA[lT] := 0; if lnPermute < 1 then exit; for lT := 1 to lnThreads do begin for lP := 1 to lnPermute do begin gPermuteMinT[lT,lP] := 10; gPermuteMaxT[lT,lP] := -10; gPermuteMinBM[lT,lP] := 10; gPermuteMaxBM[lT,lP] := -10; end; end; end; procedure ClearThreadData (lnThreads,lnPermute: integer); var lT,lP: integer; begin if lnThreads < 1 then exit; if lnPermute > kMaxPermute then showmessage('Error: recompile with larger kMaxPermute'); for lT := 1 to lnThreads do gnVoxTestedRA[lT] := 0; if lnPermute < 1 then exit; for lT := 1 to lnThreads do begin for lP := 1 to lnPermute do begin gPermuteMinT[lT,lP] := 0; gPermuteMaxT[lT,lP] := 0; gPermuteMinBM[lT,lP] := 0; gPermuteMaxBM[lT,lP] := 0; end; end; end; function SumThreadDataLite (lnThreads: integer): integer; var lT: integer; begin result := 0; if lnThreads < 1 then exit; for lT := 1 to lnThreads do result := result + gnVoxTestedRA[lT]; end; function SumThreadData (lnThreads,lnPermute: integer;lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP): integer; var lT,lP: integer; begin result := 0; if lnThreads < 1 then exit; for lT := 1 to lnThreads do result := result + gnVoxTestedRA[lT]; if lnPermute < 1 then exit; for lP := 1 to lnPermute do begin lPermuteMinT^[lP] := gPermuteMinT[1,lP]; lPermuteMaxT^[lP] := gPermuteMaxT[1,lP]; lPermuteMinBM^[lP] := gPermuteMinBM[1,lP]; lPermuteMaxBM^[lP] := gPermuteMaxBM[1,lP]; end; if lnThreads < 2 then exit; for lT := 2 to lnThreads do begin for lP := 1 to lnPermute do begin if lPermuteMinT^[lP] > gPermuteMinT[lT,lP] then lPermuteMinT^[lP] := gPermuteMinT[lT,lP]; if lPermuteMinBM^[lP] > gPermuteMinBM[lT,lP] then lPermuteMinBM^[lP] := gPermuteMinBM[lT,lP]; if lPermuteMaxT^[lP] < gPermuteMaxT[lT,lP] then lPermuteMaxT^[lP] := gPermuteMaxT[lT,lP]; if lPermuteMaxBM^[lP] < gPermuteMaxBM[lT,lP] then lPermuteMaxBM^[lP] := gPermuteMaxBM[lT,lP]; end; end; end; //SumThreadData end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/zconf.inc������������������������������������������������0000755�0001750�0001750�00000001274�10251433460�017776� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ -------------------------------------------------------------------- } {$DEFINE MAX_MATCH_IS_258} { Compile with -DMAXSEG_64K if the alloc function cannot allocate more than 64k bytes at a time (needed on systems with 16-bit int). } {- $DEFINE MAXSEG_64K} {$IFNDEF WIN32} {$DEFINE UNALIGNED_OK} { requires SizeOf(ush) = 2 ! } {$ENDIF} {$UNDEF DYNAMIC_CRC_TABLE} {$UNDEF FASTEST} {$define patch112} { apply patch from the zlib home page } { -------------------------------------------------------------------- } {$IFDEF FPC} {$DEFINE Use32} {$UNDEF DPMI} {$UNDEF MSDOS} {$UNDEF UNALIGNED_OK} { requires SizeOf(ush) = 2 ! } {$UNDEF MAXSEG_64K} {$ENDIF} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npm.dof��������������������������������������������������0000755�0001750�0001750�00000004442�12147207562�017460� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[FileVersion] Version=7.0 [Compiler] A=8 B=0 C=1 D=1 E=0 F=0 G=1 H=1 I=1 J=1 K=0 L=1 M=0 N=1 O=1 P=1 Q=0 R=0 S=0 T=0 U=0 V=1 W=0 X=1 Y=1 Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; NamespacePrefix= SymbolDeprecated=1 SymbolLibrary=1 SymbolPlatform=1 UnitLibrary=1 UnitPlatform=1 UnitDeprecated=1 HResultCompat=1 HidingMember=1 HiddenVirtual=1 Garbage=1 BoundsError=1 ZeroNilCompat=1 StringConstTruncated=1 ForLoopVarVarPar=1 TypedConstVarPar=1 AsgToTypedConst=1 CaseLabelRange=1 ForVariable=1 ConstructingAbstract=1 ComparisonFalse=1 ComparisonTrue=1 ComparingSignedUnsigned=1 CombiningSignedUnsigned=1 UnsupportedConstruct=1 FileOpen=1 FileOpenUnitSrc=1 BadGlobalSymbol=1 DuplicateConstructorDestructor=1 InvalidDirective=1 PackageNoLink=1 PackageThreadVar=1 ImplicitImport=1 HPPEMITIgnored=1 NoRetVal=1 UseBeforeDef=1 ForLoopVarUndef=1 UnitNameMismatch=1 NoCFGFileFound=1 MessageDirective=1 ImplicitVariants=1 UnicodeToLocale=1 LocaleToUnicode=1 ImagebaseMultiple=1 SuspiciousTypecast=1 PrivatePropAccessor=1 UnsafeType=1 UnsafeCode=1 UnsafeCast=1 [Linker] MapFile=0 OutputObjs=0 ConsoleApp=1 DebugInfo=0 RemoteSymbols=0 MinStackSize=16384 MaxStackSize=1048576 ImageBase=4194304 ExeDescription= [Directories] OutputDir= UnitOutputDir= PackageDLLOutputDir= PackageDCPOutputDir= SearchPath=C:\pas\mricron\common;C:\pas\mricron\fpmath Packages=Vcl40;Vclx40;VclSmp40;Qrpt40;Vcldb40;RxCtl4 Conditionals= DebugSourceDirs= UsePackages=0 [Parameters] RunParams= HostApplication= Launcher= UseLauncher=0 DebugCWD= [Language] ActiveLang= ProjectLang= RootDir= [Version Info] IncludeVerInfo=0 AutoIncBuild=0 MajorVer=1 MinorVer=0 Release=0 Build=0 Debug=0 PreRelease=0 Special=0 Private=0 DLL=0 Locale=1033 CodePage=1252 [Version Info Keys] CompanyName= FileDescription= FileVersion=1.0.0.0 InternalName= LegalCopyright= LegalTrademarks= OriginalFilename= ProductName= ProductVersion=1.0.0.0 Comments= [HistoryLists\hlUnitAliases] Count=1 Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; [HistoryLists\hlSearchPath] Count=2 Item0=C:\pas\mricron\common;C:\pas\mricron\fpmath Item1=C:\pas\mricron\common ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/StatThds.pas���������������������������������������������0000755�0001750�0001750�00000056072�11326425450�020441� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit StatThds; interface uses ComCtrls,Classes, Graphics, ExtCtrls, define_types,stats,StatThdsUtil,Brunner,lesion_pattern; type TStatThread = class(TThread) private lBarX: TProgressBar; lttestx,lBMx: boolean; lnCritx,lBarPosX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx,lImagesCountx,lnGroup1x : integer; lMaskImgx,lPlankImgx,lOutImgMnx,lOutImgBMx,lOutImgTx,lSymptomRAx: SingleP; //lBarX: TProgressBar; procedure DoVisualSwap; protected procedure Execute; override; procedure VisualProg(lPos: Integer); procedure Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); virtual; abstract; public constructor Create(lBar: TProgressBar;lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); end; { VBM - two groups } TNNStat = class(TStatThread) protected procedure Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); override; end; TPairedTStat = class(TStatThread) protected procedure Analyze(lunused1,lunused2: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); override; end; { Lesion - image reveals value } TLesionStat = class(TStatThread) protected procedure Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); override; end; TLesionBinomial = class(TStatThread) protected procedure Analyze(lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgL,lOutImgX,lSymptomRA: SingleP); override; end; implementation //uses Stat; { TSortThread } (*tpIdle The thread executes only when the system is idle. The system will not interrupt other threads to execute a thread with tpIdle priority. tpLowest The thread's priority is two points below normal. tpLower The thread's priority is one point below normal. tpNormal The thread has normal priority. tpHigher The thread's priority is one point above normal. tpHighest The thread's priority is two points above normal. tpTimeCritical*) Const Two32 = 4294967296.0 ; function GenRandThreaded(lRange: integer; var lRandSeed:comp): integer; //normal random function does not work well when threaded - randseed is changed by each thread const lFactor = $08088405 ; lTerm = 1 ; type lT = array [0..1] of longint ; var lX: extended; begin lRandSeed := lRandSeed*lFactor + lTerm; lT(lRandSeed)[1] := 0 ; // < May'04 was: RS := RS - Trunc(RS/Two32)*Two32 ; lX := lRandSeed/Two32 ; result := trunc((lRange)*lX); end; procedure GenPermuteThreaded (lnSubj: integer; var lOrigOrder,lRanOrder: DoubleP0; var lRandSeed:comp); var lInc,lRand: integer; lSwap: double; begin Move(lOrigOrder^,lRanOrder^,lnSubj*sizeof(double)); for lInc := lnSubj downto 2 do begin lRand := GenRandThreaded(lInc,lRandSeed); lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc-1]; lRanOrder^[lInc-1] := lSwap; end; end; procedure StatPermuteThreaded (lttest,lBM: boolean; lnSubj, lnGroup0,lnPermute,lThread: integer;var lOrigOrder: DoubleP0); var lInc: integer; lOutT: double; lRS: Comp; lRanOrderp: pointer; lRanOrder: Doublep0; begin if (lnSubj < 1) or (lnPermute < 1) then exit; createArray64(lRanOrderp,lRanOrder,lnSubj); lRS := 128; for lInc := 1 to lnPermute do begin GenPermuteThreaded(lnSubj, lOrigOrder,lRanOrder,lRS); //generate random order of participants if lttest then begin TStat2 (lnSubj, lnGroup0, lRanOrder, lOutT); if lOutT > gPermuteMaxT[lThread,lInc] then gPermuteMaxT[lThread,lInc] := lOutT; if lOutT < gPermuteMinT[lThread,lInc] then gPermuteMinT[lThread,lInc] := lOutT; end; //compute ttest if lBM then begin BMTest (lnSubj, lnGroup0, lRanOrder,lOutT); if lOutT > gPermuteMaxBM[lThread,lInc] then gPermuteMaxBM[lThread,lInc] := lOutT; if lOutT < gPermuteMinBM[lThread,lInc] then gPermuteMinBM[lThread,lInc] := lOutT; end; //compute BM end; freemem(lRanOrderp); end; procedure StatPermuteBinomialThreaded (lChi2,lLieber: boolean; lnSubj, lnGroup0,lnPermute,lThread: integer;var lOrigOrder: DoubleP0); var lInc: integer; lOutT: double; lRS: Comp; lRanOrderp: pointer; lRanOrder: Doublep0; begin if (lnSubj < 1) or (lnPermute < 1) then exit; createArray64(lRanOrderp,lRanOrder,lnSubj); lRS := 128; for lInc := 1 to lnPermute do begin GenPermuteThreaded(lnSubj, lOrigOrder,lRanOrder,lRS); //generate random order of participants if lChi2 then begin Chi2 (lnSubj, lnGroup0, lRanOrder, lOutT); if lOutT > gPermuteMaxT[lThread,lInc] then gPermuteMaxT[lThread,lInc] := lOutT; if lOutT < gPermuteMinT[lThread,lInc] then gPermuteMinT[lThread,lInc] := lOutT; end; //compute ttest if lLieber then begin Liebermeister2 (lnSubj, lnGroup0, lRanOrder,lOutT); if lOutT > gPermuteMaxBM[lThread,lInc] then gPermuteMaxBM[lThread,lInc] := lOutT; if lOutT < gPermuteMinBM[lThread,lInc] then gPermuteMinBM[lThread,lInc] := lOutT; end; //compute BM end; freemem(lRanOrderp); end; procedure TStatThread.DoVisualSwap; begin lBarX.Position := lBarPosX; end; procedure TStatThread.VisualProg(lPos: Integer); begin lBarPosX := lPos; {$IFDEF FPC}Synchronize(@DoVisualSwap); {$ELSE} Synchronize(DoVisualSwap);{$ENDIF} end; constructor TStatThread.Create(lBar: TProgressBar; lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); begin lBarX := lBar; lttestx := lttest; lBMx:= lBM; lThreadX := lThread; lThreadStartX := lThreadStart; lThreadEndX := lThreadEnd; lStartVoxx := lStartVox; lVoxPerPlankx := lVoxPerPlank; lImagesCountX := lImagesCount; lnGroup1x := lnGroup1; lMaskImgx := lMaskImg; lPlankImgx := lPlankImg; lOutImgMnx := lOutImgMn; lOutImgBMx := lOutImgBM; lOutImgTx := lOutImgT; lSymptomRAx := lSymptomRA; lnPermuteX := lnPermute; lnCritX := lnCrit; FreeOnTerminate := True; inherited Create(False); end; { The Execute method is called when the thread starts } procedure TStatThread.Execute; begin Analyze(lttestx,lBMx, lnCritX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx,lImagesCountx,lnGroup1x,lMaskImgx,lPlankImgX,lOutImgMnx,lOutImgBMx,lOutImgTx,lSymptomRAx); end; { Nearest Nighbor } procedure TNNStat.Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); var lObsp: pointer; lObs: Doublep0; lT: Double; lPosPct,lPos,lPos2,lPos2Offset: integer; lSum: single; begin //statthread createArray64(lObsp,lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; if lMaskImg^[lPos2Offset] <> 0 then begin inc(gnVoxTestedRA[lThread]); lSum := 0; for lPos := 1 to lImagesCount do begin lObs^[lPos-1] := (gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; lSum := lSum + lObs^[lPos-1]; end; lOutImgMn^[lPos2Offset] := lSum/lImagesCount; if lttest then begin TStat2 (lImagesCount, lnGroup1, lObs,lT); lOutImgT^[lPos2Offset] := lT; end; if lBM then begin BMTest(lImagesCount, lnGroup1, lObs,lT); lOutImgBM^[lPos2Offset] := lT; //TStatAbs (lImagesCount, lnGroup1, lObs,lT); //lOutImgBM[lPos2Offset] := lT; end; StatPermuteThreaded (lttest,lBM,lImagesCount, lnGroup1,lnPermute,lThread, lObs); end; //in brain mask - compute end; //for each voxel freemem(lObsP); end; { Paired T-Test} (*procedure PairedTTest (N, SumOfDifSqrs, SumDif: double;var t, p,DF: double); var meanDif, SumDifSqr, temp: double; begin df := n - 1; t := 0; p := 1; if (SumOfDifSqrs <> 0)and (SumDif <> 0)and (df <> 0) and (N <> 0) then begin meanDif := SumDif / N; SumDifSqr := sqr(SumDif); temp := SumOfDifSqrs - (SumDifSqr / n); temp := temp / (n * df); temp := sqrt(temp); if temp <> 0 then begin t := meanDif / temp; p := betai(0.5 * df, 0.5, df / (df + sqr(t))) end else {t is infinitely big} p := -1.0; end; end; {paired ttest} *) procedure TPairedTStat.Analyze(lUnused1,lUnused2: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); var lObsp: pointer; lObs: Doublep0; lT: Double; lPosPct,lPos,lPos2,lPos2Offset: integer; lSum: single; begin //statthread createArray64(lObsp,lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; if lMaskImg^[lPos2Offset] <> 0 then begin inc(gnVoxTestedRA[lThread]); lSum := 0; for lPos := 1 to lImagesCount do begin lObs^[lPos-1] := (gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; lSum := lSum + lObs^[lPos-1]; end; lOutImgMn^[lPos2Offset] := lSum/lImagesCount; PairedTStat (lImagesCount, lObs,lT); lOutImgT^[lPos2Offset] := lT; //StatPermuteThreaded (lttest,lBM,lImagesCount, lnGroup1,lnPermute,lThread, lObs); end; //in brain mask - compute end; //for each voxel freemem(lObsP); end; (*procedure TLesionStat.Analyze (lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); var lObsp: pointer; lObs: Doublep0; lT,lBMz,lDF: Double; lnLesion,lnNoLesion,lPosPct,lPos,lPos2,lPos2Offset,lnVoxTested: integer; begin //statthread createArray64(lObsp,lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; lnNoLesion := 0; for lPos := 1 to lImagesCount do begin if ((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]) = 0 then begin //no lesion inc(lnNoLesion); lObs^[lnNoLesion-1] := lSymptomRA^[lPos]; end else begin //lesion inc(lnLesion); lObs^[lImagesCount-lPos+lnNoLesion] := lSymptomRA^[lPos]; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) then begin inc(gnVoxTestedRA[lThread]); if lttest then begin TStat2 (lImagesCount, lnNoLesion, lObs,lT); lOutImgT^[lPos2Offset] := lT; end; if lBM then begin tBM (lImagesCount, lnNoLesion, lObs,lBMz,lDF); BMzVal (lImagesCount, lnNoLesion,lBMz,lDF); lOutImgBM^[lPos2Offset] := lBMz; end; StatPermuteThreaded (lttest,lBM,lImagesCount, lnNoLesion,lnPermute,lThread, lObs); end; //in brain mask - compute end; //for each voxel freemem(lObsP); end;*) procedure TLesionStat.Analyze (lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); //pattern variables const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lPrevZValsT,lPrevZValsBM: array [1..knPrevPattern] of Single; lPatternPos: integer; lLesionOrderp: bytep; //standard variables var lObsp: pointer; lObs: Doublep0; lT,lBMz,lDF: Double; lnLesion,lnNoLesion,lPosPct,lPos,lPos2,lPos2Offset,lnVoxTested: integer; begin //statthread //init patterns for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; getmem(lLesionOrderp, lImagesCount *sizeof(byte)); //now init standard variables createArray64(lObsp,lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; lnNoLesion := 0; for lPos := 1 to lImagesCount do begin if ((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]) = 0 then begin //no lesion inc(lnNoLesion); lLesionOrderp^[lPos] := 0; lObs^[lnNoLesion-1] := lSymptomRA^[lPos]; end else begin //lesion inc(lnLesion); lLesionOrderp^[lPos] := 1; lObs^[lImagesCount-lPos+lnNoLesion] := lSymptomRA^[lPos]; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) then begin inc(gnVoxTestedRA[lThread]); //now check if we have seen this precise lesion order recently... lPattern := SetOrderX (lLesionOrderp,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin //lesion pattern is not novel if lttest then lOutImgT^[lPos2Offset] := lPrevZvalsT[lPos]; if lBM then lOutImgBM^[lPos2Offset] := lPrevZvalsBM[lPos]; end else begin //lesion pattern is novel //record novel pattern inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; lPrevPatternRA[lPatternPos] := lPattern; if lttest then begin TStat2 (lImagesCount, lnNoLesion, lObs,lT); lOutImgT^[lPos2Offset] := lT; lPrevZValsT[lPatternPos] := lT; end; if lBM then begin tBM (lImagesCount, lnNoLesion, lObs,lBMz,lDF); BMzVal (lImagesCount, lnNoLesion,lBMz,lDF); lOutImgBM^[lPos2Offset] := lBMz; lPrevZValsBM[lPatternPos] := lBMz; end; StatPermuteThreaded (lttest,lBM,lImagesCount, lnNoLesion,lnPermute,lThread, lObs); end; //novel lesion pattern end; //in brain mask - compute end; //for each voxel freemem(lObsP); freemem(lLesionOrderp) end; procedure TLesionBinomial.Analyze (lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgL,lOutImgX,lSymptomRA: SingleP); //pattern variables const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lPrevZValsL,lPrevZValsX: array [1..knPrevPattern] of Single; lPatternPos: integer; lLesionOrderp: bytep; //standard variables var lObsp: pointer; lObs: Doublep0; lT: Double; lnLesion,lPosPct,lPos,lPos2,lPos2Offset,lnVoxTested: integer; begin //Binomial StatThread //init patterns for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; getmem(lLesionOrderp, lImagesCount *sizeof(byte)); //now init standard variables createArray64(lObsp,lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; for lPos := 1 to lImagesCount do begin if ((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]) = 0 then begin //no lesion lObs^[lImagesCount-lPos+lnLesion] := lSymptomRA^[lPos]; lLesionOrderp^[lPos] := 0; end else begin //lesion inc(lnLesion); lLesionOrderp^[lPos] := 1; lObs^[lnLesion-1] := lSymptomRA^[lPos]; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) then begin inc(gnVoxTestedRA[lThread]); //next check patterns lPattern := SetOrderX (lLesionOrderp,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin //lesion pattern is not novel //if lChi2 then // lOutImgX^[lPos2Offset] := lPrevZvalsX[lPos]; //if lLieber then lOutImgL^[lPos2Offset] := lPrevZvalsL[lPos]; end else begin //lesion pattern is novel //record novel pattern inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; lPrevPatternRA[lPatternPos] := lPattern; {if lChi2 then begin Chi2 (lImagesCount, lnLesion, lObs,lT); lOutImgX^[lPos2Offset] := lT;//lT; lPrevZValsX[lPatternPos] := lT; end; if lLieber then begin} Liebermeister2(lImagesCount, lnLesion, lObs,lT); lOutImgL^[lPos2Offset] := lT; lPrevZValsL[lPatternPos] := lT; //end; StatPermuteBinomialThreaded ({lChi2}false,lLieber,lImagesCount, lnLesion,lnPermute,lThread, lObs); end; end; //in brain mask - compute end; //for each voxel freemem(lObsP); freemem(lLesionOrderp) end; (*procedure TLesionBinomial.Analyze (lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgL,lOutImgX,lSymptomRA: SingleP); var lObsp: pointer; lObs: Doublep0; lT: Double; lnLesion,lPosPct,lPos,lPos2,lPos2Offset,lnVoxTested: integer; begin //statthread createArray64(lObsp,lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; for lPos := 1 to lImagesCount do begin if ((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]) = 0 then begin //no lesion lObs^[lImagesCount-lPos+lnLesion] := lSymptomRA^[lPos]; end else begin //lesion inc(lnLesion); lObs^[lnLesion-1] := lSymptomRA^[lPos]; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) then begin inc(gnVoxTestedRA[lThread]); if lChi2 then begin Chi2 (lImagesCount, lnLesion, lObs,lT); lOutImgX^[lPos2Offset] := lT;//lT; end; if lLieber then begin Liebermeister2(lImagesCount, lnLesion, lObs,lT); lOutImgL^[lPos2Offset] := lT; end; StatPermuteBinomialThreaded (lChi2,lLieber,lImagesCount, lnLesion,lnPermute,lThread, lObs); end; //in brain mask - compute end; //for each voxel freemem(lObsP); end;*) end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/roc.pas��������������������������������������������������0000755�0001750�0001750�00000027255�11454157032�017467� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit roc; interface //demonstrates the ROC tests that are in the Brunner.pas file uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,//Brunner,nifti_img, DISTR Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,Menus, //overlap,ReadInt,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,IniFiles,cpucount,userdir,math, regmult,utypes; procedure testROC; procedure testROC2; function AUCbinomcont (lBinomdataRA,lContdataRA: singlep; lnSubj :integer): double; function AUCcontcont (ldatara1,ldatara2: singlep; lnSubj :integer): double; implementation uses npmform; function readCSV2 (lFilename: string; lCol1,lCol2: integer; var lnObservations : integer; var ldataRA1,ldataRA2: singlep): boolean; const kHdrRow = 0;//1; kHdrCol = 0;//1; var lNumStr: string; F: TextFile; lTempFloat: double; lCh: char; lnFactors,MaxC,R,C:integer; lError: boolean; begin lError := false; result := false; if not fileexists(lFilename) then begin showmessage('Can not find '+lFilename); exit; end; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); if (R <= (kHdrRow+1)) or (MaxC < (kHdrCol+lCol1)) or (MaxC < (kHdrCol+lCol2)) then begin showmessage('problems reading CSV - not enough columns/rows '+inttostr(lCol1)+' '+inttostr(lCol2)); exit; end; lnObservations := R -kHdrRow ; //-1: first row is header.... lnFactors := MaxC-1;// -1: first column is Y values //fx(lnObservations,lnFactors); //exit; getmem(ldataRA1,lnObservations*sizeof(single)); getmem(ldataRA2,lnObservations*sizeof(single)); //second pass Reset(F); C := 1; MaxC := 0; R := 1; lNumStr := ''; lTempfloat := 0; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin if (R > kHdrRow) and (C > kHdrCol) then begin if ((C-kHdrCol) = lCol1) or ((C-kHdrCol) = lCol2) then begin if lNumStr = '-' then begin lTempFloat := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(lNumStr); if (C-kHdrCol) = lCol1 then ldataRA1^[R-kHdrRow] := lTempFloat else if (C-kHdrCol) = lCol2 then ldataRA2^[R-kHdrRow] := lTempFloat; end; //number end; //col1 or col2 end;// else //R > 1 lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 1; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if (lNumStr <> '') and (C = lnFactors) then begin //unterminated string try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except ldataRA2^[R-1] := lTempFloat; end;//unterminated string //read finel item CloseFile(F); FileMode := 2; //Set file access to read/write result := true; end; function AUCcontcont (ldatara1,ldatara2: singlep; lnSubj :integer): double; var lIn,lInDX : DoubleP0; lnGroup0,lnGroup1,lI: integer; begin result := 0.5; if lnSubj < 1 then exit; Getmem(lIn,lnSubj*sizeof(double)); Getmem(lInDX,lnSubj*sizeof(double)); for lI := 1 to lnSubj do begin lIn^[lI-1] := ldatara2^[lI]; lInDX^[lI-1] := ldatara1^[lI]; end; result := continROC2 (lnSubj, lIn, lInDX); freemem(lIn); freemem(lInDX); end; function AUCbinomcont (lBinomdataRA,lContdataRA: singlep; lnSubj :integer): double; var lIn : DoubleP0; lnGroup0,lnGroup1,lI: integer; begin result := 0.5; if lnSubj < 1 then exit; Getmem(lIn,lnSubj*sizeof(double)); lnGroup0 := 0; lnGroup1 := 0; for lI := 1 to lnSubj do begin if lBinomdataRA^[lI] = 0 then begin lIn^[lnGroup0] := lContdataRA^[lI]; inc (lnGroup0); end else begin inc (lnGroup1); lIn^[lnSubj-lnGroup1] := lContdataRA^[lI]; end; end; result := continROC (lnSubj, lnGroup0, lIn); freemem(lIn); end; procedure testROC; var lROC : single; lI,lnSubj,lnGroup0: integer; //lIn : DoubleP0; //csv lnGroup1,lCol1,lCol2: integer; var lnObservations : integer; var ldataRA1,ldataRA2: singlep ; begin npmform.MainForm.memo1.lines.clear; npmform.MainForm.memo1.lines.add('ROC analysis requires CSV format text file.'); npmform.MainForm.memo1.lines.add('First column is the filename (ignored).'); npmform.MainForm.memo1.lines.add('Second column is 0 [deficit present] or 1 [no deficit].'); npmform.MainForm.memo1.lines.add('Third column is number of voxels injured in ROI [0 or greater]:'); npmform.MainForm.memo1.lines.add('Example file:'); //npmform.MainForm.memo1.lines.add('deficit, voxels'); npmform.MainForm.memo1.lines.add('c:\c01.voi,0, 121'); npmform.MainForm.memo1.lines.add('c:\c02.voi,1, 33'); npmform.MainForm.memo1.lines.add('c:\c03.voi,0, 222'); npmform.MainForm.memo1.lines.add('c:\c04.voi,1, 56'); npmform.MainForm.memo1.lines.add('c:\c05.voi,1, 96'); npmform.MainForm.memo1.lines.add('c:\c06.voi,0, 100'); //get csv npmform.MainForm.memo1.lines.add(' ...requesting CSV file'); if not MainForm.OpenDialogExecute('Select comma separated filenames ',false,false,kTxtFilter) then exit; npmform.MainForm.memo1.lines.add(' ...reading CSV file'); if not readCSV2 (MainForm.OpenHdrDlg.Filename, 2,3, lnObservations, ldataRA1,ldataRA2) then exit; npmform.MainForm.memo1.lines.add(' ...observations: '+inttostr(lnObservations)); if lnObservations < 3 then begin showmessage('At least 3 subjects required.'); exit; end; lnSubj := lnObservations; lnGroup0 := 0; for lI := 1 to lnSubj do if ldatara1^[lI] = 0 then inc (lnGroup0); npmform.MainForm.memo1.lines.add(' ...observations with deficit [0]: '+inttostr(lnGroup0)); if (lnGroup0 = lnSubj) or (lnGroup0 = 0) then begin showmessage('Some values in the first column must be zero, some must be non-zero.'); exit; end; lROC := AUCbinomcont (ldatara1,ldatara2, lnSubj); (*Getmem(lIn,lnSubj*sizeof(double)); lnGroup0 := 0; lnGroup1 := 0; for lI := 1 to lnSubj do begin if ldatara1[lI] = 0 then begin lIn[lnGroup0] := ldatara2[lI]; inc (lnGroup0); end else begin inc (lnGroup1); lIn[lnSubj-lnGroup1] := ldatara2[lI]; end; end; lROC := continROC (lnSubj, lnGroup0, lIn); freemem(lIn); *) freemem(ldataRA1); freemem(ldataRA2); //now analyze npmform.MainForm.memo1.lines.add('ROC = '+floattostr(lROC)); //fx(lROC); end; procedure testROC2; var //lDouble: double; lVariable: boolean; lF,lROC : single; lI,lnSubj: integer; lIn,lInDX : DoubleP0; //csv lnGroup1,lCol1,lCol2: integer; var lnObservations : integer; var ldataRA1,ldataRA2: singlep ; begin npmform.MainForm.memo1.lines.clear; npmform.MainForm.memo1.lines.add('ROC analysis requires CSV format text file.'); npmform.MainForm.memo1.lines.add('First column is the filename (ignored).'); npmform.MainForm.memo1.lines.add('Second column is degree of deficit [lower value = more impaired].'); npmform.MainForm.memo1.lines.add('Third column is number of voxels injured in ROI [0 or greater]:'); npmform.MainForm.memo1.lines.add('Example file:'); //npmform.MainForm.memo1.lines.add('deficit, voxels'); npmform.MainForm.memo1.lines.add('c:\c01.voi,0.3, 121'); npmform.MainForm.memo1.lines.add('c:\c02.voi,0.1, 33'); npmform.MainForm.memo1.lines.add('c:\c03.voi,0.2, 222'); npmform.MainForm.memo1.lines.add('c:\c04.voi,1.3, 56'); npmform.MainForm.memo1.lines.add('c:\c05.voi,1.7, 96'); npmform.MainForm.memo1.lines.add('c:\c06.voi,1.5, 100'); //get csv npmform.MainForm.memo1.lines.add(' ...requesting CSV file'); if not MainForm.OpenDialogExecute('Select comma separated filenames ',false,false,kTxtFilter) then exit; npmform.MainForm.memo1.lines.add(' ...reading CSV file'); if not readCSV2 (MainForm.OpenHdrDlg.Filename, 2,3, lnObservations, ldataRA1,ldataRA2) then exit; npmform.MainForm.memo1.lines.add(' ...observations: '+inttostr(lnObservations)); if lnObservations < 3 then begin showmessage('At least 3 subjects required.'); exit; end; lnSubj := lnObservations; lF := ldatara1^[1]; lVariable := false; for lI := 1 to lnSubj do if ldatara1^[lI] <> lF then lVariable := true; if (not lVariable) then begin showmessage('The columns must have some variability.'); exit; end; Getmem(lIn,lnSubj*sizeof(double)); Getmem(lInDX,lnSubj*sizeof(double)); for lI := 1 to lnSubj do begin lIn^[lI-1] := ldatara2^[lI]; lInDX^[lI-1] := ldatara1^[lI]; end; freemem(ldataRA1); freemem(ldataRA2); //now analyze (*lnSubj := 10; lnGroup0 := 5; Getmem(lIn,lnSubj*sizeof(double)); for lI := 0 to (lnSubj-1) do lIn[lI] := -lI;//random(99); *) lROC := continROC2 (lnSubj, lIn, lInDX); npmform.MainForm.memo1.lines.add('ROC = '+floattostr(lROC)); freemem(lIn); freemem(lInDX); end; (*procedure testROC; var lROC : single; lI,lnSubj,lnGroup0: integer; lIn : DoubleP0; begin lnSubj := 10; lnGroup0 := 5; Getmem(lIn,lnSubj*sizeof(double)); for lI := 0 to (lnSubj-1) do lIn[lI] := -lI;//random(99); lROC := continROC (lnSubj, lnGroup0, lIn); npmform.MainForm.memo1.lines.add('ROC = '+floattostr(lROC)); //fx(lROC); freemem(lIn); end; *) end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/brunner.pas����������������������������������������������0000755�0001750�0001750�00000040071�11326425446�020353� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit brunner; interface uses define_types,math,Distr; procedure tBM (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var ltBM,lDF: double); procedure genBMsim (lnSubj: integer; var lOrigOrder: DoubleP0); function BMzVal(lnSubj, lnGroup0: integer; ltBM,lDF: double): double; function continROC (lnSubj, lnGroup0: integer; var lIn: DoubleP0): single; function continROC2 (lnSubj: integer; var lInIV, lInDV: DoubleP0): single; const knPermute= 20000; knSim = 15; var gSimRA: array [1..knSim] of DoubleP; gSimRAp: array [1..knSim] of pointer; implementation function BMzVal(lnSubj,lnGroup0 : integer; ltBM,lDF: double): double; //can be approximated by result := TtoZ(ltBM,lDF); var lnSmallGroup,lJump,lEstimate,i,tie: integer; ltBMs : double; lSwap: boolean; begin //result := TtoZ(ltBM,lDF); exit; lSwap := false; ltBMs := ltBM; result := 0; tie := 0; if (lnSubj div 2) > lnGroup0 then lnSmallGroup := lnGroup0 else lnSmallGroup := lnSubj-lnGroup0; if lnSmallGroup < 1 then exit; if lnSmallGroup > knSim then begin result := TtoZ(ltBMs,lDF); exit; end; if (lnSubj div 2) < lnGroup0 then begin ltBMs := -ltBMs; lSwap := not lSwap; //distributions are not symetrical end; lEstimate := knPermute div 2; //start half way through data lJump := lEstimate div 2; for i := 1 to 9 do begin if gSimRA[lnSmallGroup]^[lEstimate] > ltBMs then lEstimate := lEstimate - lJump else lEstimate := lEstimate + lJump; lJump := (lJump+1) div 2; end; if lEstimate < (knPermute div 2) then begin //p < 0.5 count up for less extreme i := lEstimate-lJump-lJump; if i < 1 then i := 1; while ltBMs > gSimRA[lnSmallGroup]^[i] do begin inc(i); end; if ltBMs = gSimRA[lnSmallGroup]^[i] then begin while ltBMs = gSimRA[lnSmallGroup]^[i] do begin inc(i); dec(tie); end; dec(tie); end; end else begin //p < 0.5 count down for less extreme i := lEstimate+lJump+lJump; if i >= knPermute then i := knPermute; while ltBMs < gSimRA[lnSmallGroup]^[i] do dec(i); if ltBMs = gSimRA[lnSmallGroup]^[i] then begin while ltBMs = gSimRA[lnSmallGroup]^[i] do begin dec(i); inc(tie); end; inc(tie); end; i := i - 1; //indexed from 1 not 0 end; //result := (i+(tie/2)); //result := (1-( (i+(tie/2))/knPermute)); result := pNormalInv(1-( (i+(tie/2))/knPermute)); if lSwap then result := -result; end; procedure Sort (lo, up: integer; var r:DoubleP); //62ms Shell Sort http://www.dcc.uchile.cl/~rbaeza/handbook/algs/4/414.sort.p.html label 999; var d, i, j : integer; tempr : single; begin d := up-lo+1; while d>1 do begin if d<5 then d := 1 else d := trunc( 0.45454*d ); // Do linear insertion sort in steps size d for i:=up-d downto lo do begin tempr := r^[i]; j := i+d; while j <= up do if tempr > r^[j] then begin r^[j-d] := r^[j]; j := j+d end else goto 999; {*** break ***} 999: r^[j-d] := tempr end end end; //sort procedure GenPermute (lnSubj: integer; var lOrigOrder,lRanOrder: DoubleP0); var lInc,lRand: integer; lSwap: double; begin //next lines commented out - this check should be done before inner loop //if lnSubj < 2 then //can not randomize order of single value // exit; //Move(src,dest,count); Move(lOrigOrder^,lRanOrder^,lnSubj*sizeof(double)); //for lInc := 1 to lnSubj do // lRanOrder[lInc-1] := lOrigOrder[lInc-1]; for lInc := lnSubj downto 2 do begin lRand := Random(lInc); lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc-1]; lRanOrder^[lInc-1] := lSwap; end; end; procedure genBMsim (lnSubj: integer; var lOrigOrder: DoubleP0); //1.) creates kSim random permutations of the data //2.) sorts permutations var lRanOrderp: pointer; lRanOrder: DoubleP0; lInc,lnSmallGroup: integer; lOutT,lDF: double; begin if (lnSubj < 1) or (knPermute < 1) then exit; createArray64(lRanOrderp,lRanOrder,lnSubj); //lnSmallGroup := lnGroup0; //if lnSmallGroup > knSim then exit; for lnSmallGroup := 1 to knSim do begin //RandSeed := 128; //same order for all voxels for lInc := 1 to knPermute do begin GenPermute(lnSubj, lOrigOrder,lRanOrder); //generate random order of participants tBM (lnSubj, lnSmallGroup, lRanOrder,lOutT,lDF); gSimRA[lnSmallGroup]^[lInc] := lOutT; end; //next sort permutes... Sort(1,knPermute,gSimRA[lnSmallGroup]); end; freemem(lRanOrderp); end; procedure SortDouble (first, last: integer; var DynDataRA:DoubleP0; var lGroupRA: Bytep0); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} {less memory intensive than recursive quicksort} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n, nn, m, lognb2, l, k, j, i: INTEGER; swap: Single; swapbyte: byte; begin n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 0 to k do begin i := j; 555: {<- LABEL} l := i + m; if (DynDataRA^[l] < DynDataRA^[i]) then begin swap := DynDataRA^[i]; DynDataRA^[i] := DynDataRA^[l]; DynDataRA^[l] := swap; swapbyte := lGroupRA^[i]; lGroupRA^[i] := lGroupRA^[l]; lGroupRA^[l] := swapbyte; i := i - m; if (i >= 0) then goto 555; end end end end;//sort procedure RankArray (first, last: integer; var DynDataRA:DoubleP0; var lGSum: double); var lnTies,lPos,lStartPos,lRankPos: integer; lScore,lTie : double; begin lGSum := 0; lPos := first; while lPos <= last do begin lStartPos := lPos; lScore := DynDataRA^[lPos]; while (lPos < last) and (lScore = DynDataRA^[lPos+1]) do inc(lPos); //count ties lnTies := lPos - lStartPos; lTie := (lnTies) *0.5; if lnTies > 0 then begin lnTies := lnTies+1;//tj on page 135 of Siegel lGSum := lGSum + (( (lnTies*lnTies*lnTies) - lnTies)/12); //showmessage(inttostr(lnTies)+' '+realtostr(lGSum,4)); end; for lRankPos := lStartPos to lPos do DynDataRA^[lRankPos] := lStartPos+1+lTie; inc(lPos);//start with next value end; end; procedure LocalRank (first, last: integer; var DynDataRA,DynDataRAX:DoubleP0; var lGroupRA: Bytep0); var lGroup,lnTies,lPos,lStartPos,lRankPos,lLocalRank: integer; lScore,lTie : double; begin for lGroup := 0 to 1 do begin lPos := first; lLocalRank := 0; while lPos <= last do begin if lGroupRA^[lPos] = lGroup then begin// inc(lLocalRank); lStartPos := lPos; lScore := DynDataRA^[lPos]; lnTies := 0; while (lPos < last) and (0.001 > abs (lScore - DynDataRA^[lPos+1]) ) do begin inc(lPos); //count ties if lGroupRA^[lPos] = lGroup then inc(lnTies); end; lTie := (lnTies) *0.5; for lRankPos := lStartPos to lPos do begin if lGroupRA^[lRankPos] = lGroup then DynDataRAX^[lRankPos] := (lLocalRank+lTie); end; lLocalRank := lLocalRank + lnTies; end; //if in group inc(lPos);//start with next value end; //while... for each observation end; //for each group end; (*procedure tBM (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var ltBM,lDF: double); //this is a t-test - only use to test BM!!! var i,lnGroupY,lnGroupX: integer; lSumX,lSumY,lSumSqrx,lSumSqry,lVarx,lVary,lS: double; begin lnGroupX := lnGroup0; lnGroupY := lnSubj - lnGroupX; lDF := lnSubj -1; if (lnGroupX < 1) or (lnGroupY < 1) then begin //need at least 1 subj in each group ltBM := 0; exit; end; lSumx := 0; lSumSqrX := 0; for i := 0 to (lnGroupX-1) do begin //for each subject //lVal := lIn[i]; lsumx := lsumx + lIn[i]; lSumSqrX := lSumSqrX + sqr(lIn[i]); end; //lMnX := lsumx/lnGroupX; lVarx := (lnGroupX*lSumSqrX) - Sqr(lsumx); if lnGroupX > 1 then lVarX := lVarX / (lnGroupX*(lnGroupX-1)) else lVarx := 0; lSumy := 0; lSumSqry := 0; for i := lnGroupX to (lnSubj-1) do begin //for each subject //lVal := lIn[i]; lsumy := lsumy + lIn[i]; lSumSqry := lSumSqry + sqr(lIn[i]); end; //for each sub //lMnY := lsumy/lnGroupY; lVary := (lnGroupY*lSumSqrY) - Sqr(lsumy); if lnGroupY > 1 then lVary := lVary / (lnGroupY*(lnGroupY-1)) else lVary := 0; //lm := (lsumx/lnGroupX)-(lsumy/lnGroupY); //mean effect size lmnx - lmny; //ldf := lnSubj - 2; ls := sqrt( ( ((lnGroupX - 1) * lvarx + (lnGroupY - 1) * lvary) / (lnSubj - 2){ldf}) ) ; ls := ls * sqrt(1 / lnGroupX + 1 / lnGroupY); //note - to get here both lnx and lny > 0 if ls = 0 then ltBM := 0 else ltBM := ( ((lsumx/lnGroupX)-(lsumy/lnGroupY))/ls);//t = lm / ls; end; *) procedure tBM (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var ltBM,lDF: double); var lObspX,lObsp: pointer; lObsX,lObs: Doublep0; lGroupRA: Bytep0; i,ln0,ln1: integer; lZ,lGSum: double; lSum0,lSum1,lMean0,lMean1,lSqr0,lSqr1,lk0,lk1: double; begin createArray64(lObsp,lObs,lnSubj); getmem(lGroupRA,lnSubj*sizeof(Byte)); createArray64(lObspX,lObsX,lnSubj); ln0 := 0; ln1 := 0; for i := 0 to (lnSubj-1) do begin //for each subject //lVal := lIn[i]; lObs[i] := lIn[i]; if i < lnGroup0 then //group0 lGroupRA^[i] := 0 else lGroupRA^[i] := 1; end; //for each sub for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then inc(ln0) //number of observations in group zero else inc(ln1); //number of observations in group one if (ln0 > 1) and (ln1 > 1) then begin SortDouble(0,lnSubj-1,lObs,lGroupRA); RankArray(0,lnSubj-1,lObs,lGSum); lSum0 := 0; lSum1 := 0; for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then lSum0 := lSum0 + lObs^[i] else lSum1 := lSum1 + lObs^[i]; lMean0 := lSum0 / ln0; lMean1 := lSum1 / ln1; //fx(lmean0,lMean1); lSqr0 := 0; lSqr1 := 1; lk0 := (ln0+1)/2; lk1 := (ln1+1)/2; LocalRank(0,lnSubj-1,lObs,lObsX,lGroupRA); for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then lSqr0 := lSqr0 + Sqr(lObs^[i]-lObsX^[i]-lMean0+lk0) else lSqr1 := lSqr1 + Sqr(lObs^[i]-lObsX^[i]-lMean1+lk1); lSqr0 := (1/(ln0-1))*lSqr0; lSqr1 := (1/(ln1-1))*lSqr1; lZ := -(ln0*ln1*(lMean1-lMean0))/((ln0+ln1)*sqrt((ln0*lSqr0)+(ln1*lSqr1) ) ); lDF := sqr(ln0*lSqr0+ln1*lSqr1) / ( (sqr(ln0*lSqr0)/(ln0-1)) + (sqr(ln1*lSqr1)/(ln1-1)) ) ; //lZ := TtoZ(lZ,lDF); ltBM := lZ; //fx(lZ,lDF); end else //>1 ltBM := 0; freemem(lObsp); freemem(lObspX); freemem(lGroupRA); end; //tBM (**) procedure SortDoubleP0 (first, last: integer; var DynDataRA:DoubleP0); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} {less memory intensive than recursive quicksort} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n, nn, m, lognb2, l, k, j, i: INTEGER; swap: Single; //swapbyte: byte; begin n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 0 to k do begin i := j; 555: {<- LABEL} l := i + m; if (DynDataRA^[l] < DynDataRA^[i]) then begin swap := DynDataRA^[i]; DynDataRA^[i] := DynDataRA^[l]; DynDataRA^[l] := swap; i := i - m; if (i >= 0) then goto 555; end end end end;//sort function continROC (lnSubj, lnGroup0: integer; var lIn: DoubleP0): single; //see equation 1 of Obuchiwski, Statistics in Medicine, 25: 481-493 var lSum,lV: double; linc0,linc1,lnGroup1,i: integer; lObsp0,lObsp1: pointer; lObs0,lObs1: Doublep0; begin result := -1; lnGroup1 := lnSubj - lnGroup0; if (lnGroup1 < 1) or (lnGroup0 < 1) then exit; createArray64(lObsp1,lObs1,lnSubj); createArray64(lObsp0,lObs0,lnSubj); for i := 0 to (lnGroup0-1) do //for each subject without disease lObs0[i] := lIn[i]; SortDoubleP0(0,lnGroup0-1,lObs0); for i := lnGroup0 to (lnSubj-1) do //for each subject with disease lObs1[i-lnGroup0] := lIn[i]; SortDoubleP0(0,lnGroup1-1,lObs1); lSum := 0; for linc0 := 0 to (lnGroup0-1) do begin for linc1 := 0 to (lnGroup1-1) do begin if (lObs0^[linc0]) > (lObs1^[linc1]) then lV := 1 else if (lObs0^[linc0]) = (lObs1^[linc1]) then //tie lV := 0.5 else lV := 0; lSum := lV + lSum; end;//for group1 end;//for group0 lSum := lSum * (1/ (lnGroup0*lnGroup1 ) ); result := lSum; freemem(lObsp1); freemem(lObsp0); end; //continROC procedure SortDoubleDouble (first, last: integer; var DynDataRA, lGroupRA: DoubleP0); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} {less memory intensive than recursive quicksort} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n, nn, m, lognb2, l, k, j, i: INTEGER; swap,swapbyte: double; begin n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 0 to k do begin i := j; 555: {<- LABEL} l := i + m; if (DynDataRA^[l] < DynDataRA^[i]) then begin swap := DynDataRA^[i]; DynDataRA^[i] := DynDataRA^[l]; DynDataRA^[l] := swap; swapbyte := lGroupRA^[i]; lGroupRA^[i] := lGroupRA^[l]; lGroupRA^[l] := swapbyte; i := i - m; if (i >= 0) then goto 555; end end end end;//sort function continROC2 (lnSubj: integer; var lInIV, lInDV: DoubleP0): single; //see equation 9 of Obuchiwski, Statistics in Medicine, 25: 481-493 var lSum,lV: double; linci,lincj,i: integer; lObspIV,lObspDV: pointer; lObsIV,lObsDV: Doublep0; begin result := -1; if (lnSubj < 1) then exit; createArray64(lObspIV,lObsIV,lnSubj); createArray64(lObspDV,lObsDV,lnSubj); for i := 0 to (lnSubj-1) do //for each subject without disease lObsIV[i] := lInIV[i]; for i := 0 to (lnSubj-1) do //for each subject without disease lObsDV[i] := lInDV[i]; SortDoubleDouble(0,lnSubj-1,lObsIV,lObsDV); lSum := 0; for linci := 0 to (lnSubj-1) do begin for lincj := 0 to (lnSubj-1) do begin if lincj <> linci then begin if ((lObsDV^[linci] > lObsDV^[lincj]) and (lObsIV^[linci] > lObsIV^[lincj])) or ((lObsDV^[linci] < lObsDV^[lincj]) and (lObsIV^[linci] < lObsIV^[lincj])) then lV := 1 else if (lObsDV^[linci] = lObsDV^[lincj]) or (lObsIV^[linci] = lObsIV^[lincj]) then //tie lV := 0.5 else lV := 0; lSum := lV + lSum; end; end;//for group1 end;//for group0 lSum := lSum * (1/ (lnSubj* (lnSubj-1) ) ); result := lSum; freemem(lObspDV); freemem(lObspIV); end; //continROC2 var i: integer; initialization begin for i := 1 to knSim do createArray64(gSimRAp[i],gSimRA[i],knPermute); end; finalization begin for i := 1 to knSim do freemem(gSimRAp[i]); end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/associate.pas��������������������������������������������0000755�0001750�0001750�00000002643�11326425446�020656� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit associate; interface uses Windows,registry,Forms,dialogs,SysUtils; function registerfiletype(inft,inkey,desc,icon:string): boolean; implementation function registerfiletype(inft,inkey,desc,icon:string): boolean; var myreg : treginifile; ct : integer; ft,key: string; begin result := true; ft := inft; key := inkey; ct := pos('.',ft); while ct > 0 do begin delete(ft,ct,1); ct := pos('.',ft); end; if (ft = '') or (Application.ExeName = '') then exit; //not a valid file-ext or ass. app ft := '.'+ft; myreg := treginifile.create(''); try myreg.rootkey := hkey_classes_root; // where all file-types are described if key = '' then key := copy(ft,2,maxint)+'_auto_file'; // if no key-name is given, create one myreg.writestring(ft,'',key); // set a pointer to the description-key myreg.writestring(key,'',desc); // write the description myreg.writestring(key+'\DefaultIcon','',icon); // write the def-icon if given //showmessage(key); myreg.writestring(key+'\shell\open\command','',Application.ExeName+' %1'); //association except result := false; showmessage('Only administrators can change file associations. You are currently logged in as a restricted user.'); end; //finally myreg.free; //end; end; end.���������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npm.res��������������������������������������������������0000755�0001750�0001750�00000001554�11477146210�017477� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ������������������������� ��������� ��������(��� ���@�����������������������������������������������������������������������3wywwywwwwww������������������������wwww���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������0����M�A�I�N�I�C�O�N��������� ������������ ����������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/stats.pas������������������������������������������������0000755�0001750�0001750�00000102022�11477147256�020040� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit stats; interface uses define_types,statcr,DISTR ,SysUtils,Dialogs,ClipBrd; procedure TStat2 (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutT: double); //procedure TStatAbs (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutT: double); procedure PairedTStat (lnSubj: integer; var lIn: DoubleP0; var lOutT: double); procedure TStatWelch (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var lOutT: double); procedure WilcoxonMW2 (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var lOutT: double); procedure MeanMedian(lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lMeanFX,lMedianFX: double); procedure TStat2Z (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutT: double); procedure BMTest (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var lOutT: double); procedure Liebermeister2 (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutZ: double); procedure Liebermeister2b (lnSubj, lnGroupX: integer; var lIn: ByteP0; var lAUC,lOutZ: double); procedure Liebermeister2bP (lnSubj, lnGroupX: integer; var lIn: ByteP0; var lOutP: double); //procedure Liebermeister2bPlus (lnSubj, lnGroupX: integer; var lIn: ByteP0; var lAUC, lOutP: double); //function Aprime (lHit,lFA: double): double; //function AUC (lHit,lFA: double): double; //function rocAUC (lHit,lFA: double): double; function rocAUC (lnYesDeficitYesLesion,lnNoDeficitYesLesion,lnYesDeficitNoLesion,lnNoDeficitNoLesion: integer): double; procedure Chi2 (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutZ: double); implementation procedure Chi2 (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutZ: double); var lVal: double; // luChiP: double; i,lnYesDeficit1,lnYesDeficit0,lnNoDeficit1,lnNoDeficit0, lnYesDeficit,lnNoDeficit: integer; begin lnYesDeficit0 := 0; lnYesDeficit1 := 0; lnNoDeficit0 := 0; lnNoDeficit1 := 0; for i := 0 to (lnGroupX-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit0) else inc(lnNoDeficit0); end; for i := lnGroupX to (lnSubj-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit1) else inc(lnNoDeficit1); end; //for each sub lnYesDeficit :=lnYesDeficit0+lnYesDeficit1; lnNoDeficit := lnNoDeficit0+lnNoDeficit1; if (lnYesDeficit<1) or (lnNoDeficit<1) then lOutZ := 0 else begin lVal := Fisher(lnYesDeficit0, lnYesDeficit1, lnNoDeficit0, lnNoDeficit1); if lVal < 0 then lOutZ := -pNormalInv(abs(lVal)) else lOutZ := pNormalInv(lVal) (*Chi2x2 (lnYesDeficit0, lnYesDeficit1, lnNoDeficit0, lnNoDeficit1,lMinExp,lChi,lChip,luChi, luChiP); if (lnYesDeficit1/lnYesDeficit) > (lnNoDeficit1/lnNoDeficit) then lOutZ := -luChi//t = m / d; else lOutZ := luChi;//t = m / d; *) end; //compute chi end; function rocAz (lHit,lFA: double): double; //see Zhang and Mueller, 2005, Psychometrika 70, 145-154 var lH,lF: double; begin if (lHit = 1) and (lFA = 0) then begin result := 1; exit; end; if (lHit = 0) and (lFA = 1) then begin result := 0; exit; end; if lHit >= lFA then begin//normal: better than chance lH := lHit; lF := lFA; end else begin //..else worse than chance lF := lHit; lH := lFA; end; if (lF <= 0.5) and (0.5 <= lH) then result := 0.75+ ((lH-lF)*0.25)- lF*(1-lH) else if (lF <= lH) and (lH < 0.5) then begin if (4*lH) = 0 then result := 0.5 else result := 0.75+ ((lH-lF)*0.25)- (lF/(4*lH)) end else if (0.5 < lF) and (lF <= lH) then begin if (4*(1-lF)) = 0 then result := 0.5 else result := 0.75 + ((lH-lF)*0.25) - ((1-lH)/(4*(1-lF))) end else showmessage('error in Zhang and Mueller, 2005 (func rocA)'); if lHit < lFA then //worse than chance result := 1 - result; end; function rocAUC (lnYesDeficitYesLesion,lnNoDeficitYesLesion,lnYesDeficitNoLesion,lnNoDeficitNoLesion: integer): double; var lHitRate,lFalseAlarmRate: double; begin result := 0.5; if ((lnYesDeficitYesLesion+lnNoDeficitYesLesion)=0) or ((lnYesDeficitNoLesion+lnNoDeficitNoLesion)=0) then exit; lHitRate := lnYesDeficitYesLesion/(lnYesDeficitYesLesion+lnNoDeficitYesLesion); lFalseAlarmRate := lnYesDeficitNoLesion/(lnYesDeficitNoLesion+lnNoDeficitNoLesion); result := rocAz(lHitRate,lFalseAlarmRate); end; (*function Aprime (lHit,lFA: double): double; //see Wickens Elementary Signal Detection, equation 4.11, page 71 //problem - not symetrical: values less than 0.5 extreme - // does not deal with lFA > lHit begin if (lFA=1) or (lHit = 0) then result := 0.5 //avoid divide by zero else result := 1 - 0.25*( ((1-lHit)/(1-lFA)) + lFA/lHit); end;*) (*function AUC (lHit,lFA: double): double; var lNum,lDenom: double; begin if (lHit> lFA) then begin lNum := (lHit-lFA)*(1+lHit-lFA); lDenom := 4 * lHit * (1 - lFA); if lDenom = 0 then result := 0 else result := 0.5+ (lNum/lDenom); end else begin lNum := (lFA-lHit)*(1+lFA-lHit); lDenom := 4 * lFA * (1 - lHit); if lDenom = 0 then result := 0 else result := 0.5- (lNum/lDenom); end; end; *) procedure ROCbinomialAUC (lnSubj, lnGroupX: integer; var lIn: ByteP0; var lAUC: double); //Receiver operating characteristic area under curve for binimial data //Liebermeister QuasiExact - excellent power var i,lnYesDeficit1,lnYesDeficit0,lnNoDeficit1,lnNoDeficit0, lnYesDeficit,lnNoDeficit: integer; //lHitRate,lFalseAlarmRate: double; begin lnYesDeficit0 := 0; lnYesDeficit1 := 0; lnNoDeficit0 := 0; lnNoDeficit1 := 0; for i := 0 to (lnGroupX-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit0) else inc(lnNoDeficit0); end; for i := lnGroupX to (lnSubj-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit1) else inc(lnNoDeficit1); end; //for each sub lAUC := rocAUC (lnYesDeficit1,lnNoDeficit1,lnYesDeficit0,lnNoDeficit0); (*lHitRate := lnYesDeficit1/(lnYesDeficit1+lnNoDeficit1); lFalseAlarmRate := lnYesDeficit0/(lnYesDeficit0+lnNoDeficit0); lAUC := rocA {AUC} (lHitRate,lFalseAlarmRate); *) end; procedure Liebermeister2bP (lnSubj, lnGroupX: integer; var lIn: ByteP0; var lOutP: double); //Liebermeister QuasiExact - excellent power var i,lnYesDeficit1,lnYesDeficit0,lnNoDeficit1,lnNoDeficit0, lnYesDeficit,lnNoDeficit: integer; //lMaxChi,lMinChi: single; begin lnYesDeficit0 := 0; lnYesDeficit1 := 0; lnNoDeficit0 := 0; lnNoDeficit1 := 0; for i := 0 to (lnGroupX-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit0) else inc(lnNoDeficit0); end; for i := lnGroupX to (lnSubj-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit1) else inc(lnNoDeficit1); end; //for each sub lnYesDeficit :=lnYesDeficit0+lnYesDeficit1; lnNoDeficit := lnNoDeficit0+lnNoDeficit1; if (lnYesDeficit<1) or (lnNoDeficit<1) then lOutP := 0 else begin lOutP := Liebermeister(lnYesDeficit0, lnYesDeficit1, lnNoDeficit0, lnNoDeficit1); end; //compute chi end; procedure Liebermeister2b (lnSubj, lnGroupX: integer; var lIn: ByteP0; var lAUC,lOutZ: double); //(lnRow,lnCol: integer; var lIn,lOutZ: DoubleP0); //Liebermeister QuasiExact - excellent power var lVal: double; i,lnYesDeficitNoLesion,lnYesDeficitYesLesion,lnNoDeficitNoLesion,lnNoDeficitYesLesion, lnYesDeficit,lnNoDeficit: integer; //lHitRate,lFalseAlarmRate: double; //lMaxChi,lMinChi: single; begin lnYesDeficitYesLesion := 0; lnYesDeficitNoLesion := 0; lnNoDeficitYesLesion := 0; lnNoDeficitNoLesion := 0; for i := 0 to (lnGroupX-1) do begin //for each lesioned subject if lIn^[i] = 0 then inc(lnYesDeficitYesLesion) else inc(lnNoDeficitYesLesion); end; for i := lnGroupX to (lnSubj-1) do begin //for each unlesioned subject if lIn^[i] = 0 then inc(lnYesDeficitNoLesion) else inc(lnNoDeficitNoLesion); end; //for each sub lnYesDeficit :=lnYesDeficitYesLesion+lnYesDeficitNoLesion; lnNoDeficit := lnNoDeficitYesLesion+lnNoDeficitNoLesion; if (lnYesDeficit<1) or (lnNoDeficit<1) then lOutZ := 0 else begin lVal := Liebermeister(lnYesDeficitYesLesion, lnYesDeficitNoLesion, lnNoDeficitYesLesion, lnNoDeficitNoLesion); if lVal < 0 then lOutZ := -pNormalInv(abs(lVal)) else lOutZ := pNormalInv(lVal) end; //compute chi lAUC := rocAUC (lnYesDeficitYesLesion,lnNoDeficitYesLesion,lnYesDeficitNoLesion,lnNoDeficitNoLesion); {lFalseAlarmRate := lnYesDeficitNoLesion/(lnYesDeficitNoLesion+lnNoDeficitNoLesion); lHitRate := lnYesDeficitYesLesion/(lnYesDeficitYesLesion+lnNoDeficitYesLesion); lAUC := rocAz (lHitRate,lFalseAlarmRate); } //if lOutZ > 4 then ax(lnYesDeficitYesLesion,lnNoDeficitYesLesion,lnYesDeficitNoLesion,lnNoDeficitNoLesion,lauc,lOutZ); end; procedure Liebermeister2 (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutZ: double); //(lnRow,lnCol: integer; var lIn,lOutZ: DoubleP0); //Liebermeister QuasiExact - excellent power var lVal: double; i,lnYesDeficit1,lnYesDeficit0,lnNoDeficit1,lnNoDeficit0, lnYesDeficit,lnNoDeficit: integer; //lMaxChi,lMinChi: single; begin lnYesDeficit0 := 0; lnYesDeficit1 := 0; lnNoDeficit0 := 0; lnNoDeficit1 := 0; for i := 0 to (lnGroupX-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit0) else inc(lnNoDeficit0); end; for i := lnGroupX to (lnSubj-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit1) else inc(lnNoDeficit1); end; //for each sub lnYesDeficit :=lnYesDeficit0+lnYesDeficit1; lnNoDeficit := lnNoDeficit0+lnNoDeficit1; if (lnYesDeficit<1) or (lnNoDeficit<1) then lOutZ := 0 else begin lVal := Liebermeister(lnYesDeficit0, lnYesDeficit1, lnNoDeficit0, lnNoDeficit1); if lVal < 0 then lOutZ := -pNormalInv(abs(lVal)) else lOutZ := pNormalInv(lVal) end; //compute chi end; procedure SortDouble (first, last: integer; var DynDataRA:DoubleP0; var lGroupRA: Bytep0); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} {less memory intensive than recursive quicksort} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n, nn, m, lognb2, l, k, j, i: INTEGER; swap: Single; swapbyte: byte; begin n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 0 to k do begin i := j; 555: {<- LABEL} l := i + m; if (DynDataRA^[l] < DynDataRA^[i]) then begin swap := DynDataRA^[i]; DynDataRA^[i] := DynDataRA^[l]; DynDataRA^[l] := swap; swapbyte := lGroupRA^[i]; lGroupRA^[i] := lGroupRA^[l]; lGroupRA^[l] := swapbyte; i := i - m; if (i >= 0) then goto 555; end end end end;//sort procedure RankArray (first, last: integer; var DynDataRA:DoubleP0; var lGSum: double); var lnTies,lPos,lStartPos,lRankPos: integer; lScore,lTie : double; begin lGSum := 0; lPos := first; while lPos <= last do begin lStartPos := lPos; lScore := DynDataRA^[lPos]; while (lPos < last) and (lScore = DynDataRA^[lPos+1]) do inc(lPos); //count ties lnTies := lPos - lStartPos; lTie := (lnTies) *0.5; if lnTies > 0 then begin lnTies := lnTies+1;//tj on page 135 of Siegel lGSum := lGSum + (( (lnTies*lnTies*lnTies) - lnTies)/12); //showmessage(inttostr(lnTies)+' '+realtostr(lGSum,4)); end; for lRankPos := lStartPos to lPos do DynDataRA^[lRankPos] := lStartPos+1+lTie; inc(lPos);//start with next value end; end; function k_out_n (k,n: integer): double; //total possible permutations //k= smaller group, n=sum of both groups var lVal: double; begin if not gFactRAready then InitFact; if (k < 1) or (n <0) then begin result := 20000001; showmessage('error k_out_n: k and n must be positive '+inttostr(n)+':'+inttostr(k)) end else if (n > kMaxFact) or (k > kMaxFact) then result := 20000001 else begin lVal := gFactRA[n] / (gFactRA[k]*gFactRA[n-k] ); if lVal > 20000001 then result := 20000001 else result := round(lVal); //result := round(gFactRA[n] / (gFactRA[k]*gFactRA[n-k] ) ); end; // k out n = n!/(k!*(n-k)! which is equal to the PROD(i=k; 1){(n-i+1)/i} end; //k_out_n //http://www.fon.hum.uva.nl/rob/ //# samples for which the sum of the ranks in the smaller sample is smaller than or //# equal to a given upper bound W. //# $W = the bound, $Sum = the sum of ranks upto now, $m-1 = one less than the //# number of elements in the smaller sample that still have to be done, //# $Start = the current position in the ranks list, *RankList = the array //# with all the ranks (this is NOT just the numbers from 1 - N because of ties). //# The list with ranks MUST be sorted in INCREASING order. function CountSmallerRanks(var W,Sum: double; lm, Start,N: integer; var RankList: DoubleP0): integer; var Temp: double; i, mminus1: integer; begin Temp:= 0; result := 0; if(Sum > W) then exit; //Check all subsets of the remaining of RankList mminus1 := lm-1; if(mminus1 > 0) then begin for i := Start to (N-mminus1) do begin Temp := Sum + RankList^[i]; if(Temp > W) then exit;// No smaller values expected anymore result := result +CountSmallerRanks(W,Temp, mminus1, i+1, N, RankList); end; end else begin //If even adding the highest rank doesn't reach $W, //return the remaining number of items if( (Sum + N + 1) <= W) then begin result := N - Start + 1; exit; end; for i := Start to N do begin Temp := Sum + RankList^[i]; if(Temp <= W) then inc(result) else // No smaller values expected anymore exit; end; //for end; //m = 0 end; procedure SortD (first, last: integer; var DynDataRA:DoubleP0); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} {less memory intensive than recursive quicksort} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n, nn, m, lognb2, l, k, j, i: INTEGER; swap: Single; begin n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 1 to k do begin i := j; 555: {<- LABEL} l := i + m; if (DynDataRA^[l] < DynDataRA^[i]) then begin swap := DynDataRA^[i]; DynDataRA^[i] := DynDataRA^[l]; DynDataRA^[l] := swap; i := i - m; if (i >= 0) then goto 555; end end end end;//sort function Median (var lObs: DoubleP0; lnSubj: integer): double; begin SortD(0,lnSubj-1,lObs); if odd(lnSubj) then result := lObs^[lnSubj div 2] else result := 0.5* (lObs^[(lnSubj div 2)-1]+lObs^[lnSubj div 2]); end; (* getmem(lGroupRA,lnSubj*sizeof(Byte)); createArray64(lObspX,lObsX,lnSubj); ln0 := 0; ln1 := 0; for i := 0 to (lnSubj-1) do begin //for each subject //lVal := lIn[i]; lObs[i] := lIn[i]; if i < lnGroup0 then //group0 lGroupRA[i] := 0 else lGroupRA[i] := 1; end; //for each sub for i := 0 to (lnSubj-1) do if lGroupRA[i] = 0 then inc(ln0) //number of observations in group zero else inc(ln1); //number of observations in group one if (ln0 > 1) and (ln1 > 1) then begin SortDouble(0,lnSubj-1,lObs,lGroupRA); *) procedure MeanMedian(lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lMeanFX,lMedianFX: double); //compute mean and median effect size var i: integer; lMeanY,lMeanX,lMedianY,lMedianX: double; lObsp: pointer; lObs: Doublep0; begin lMeanFX := 0; lMedianFX := 0; if (lnSubj=lnGroupX) or (lnSubj < 2) or (lnGroupX = 0) then exit; //at least one empty group - no effect size //next compute mean/median for groupX lMeanX := 0; createArray64(lObsp,lObs,lnSubj); for i := 0 to (lnGroupX-1) do begin //for each subject lMeanX := lMeanX + lIn^[i]; lObs[i] := lIn[i]; end; lMeanX := lMeanX/lnGroupX; lMedianX := Median (lObs,lnGroupX); freemem(lObsp); //next compute mean/median for groupY lMeanY := 0; createArray64(lObsp,lObs,(lnSubj-lnGroupX)); for i := lnGroupX to (lnSubj-1) do begin //for each subject lMeanY := lMeany + lIn^[i]; lObs^[i-lnGroupX] := lIn^[i]; end; lMeanY := lMeanY/ (lnSubj-lnGroupX); lMedianY := Median (lObs,(lnSubj-lnGroupX)); freemem(lObsp); //finally, compute effect sizes lMeanFX := lMeanX-lMeanY; lMedianFX := lMedianX-lMedianY; end; procedure PairedTStat (lnSubj: integer; var lIn: DoubleP0; var lOutT: double); //lIn has data for controls 1...n followed by 1..n paired measures. //e.g. if three observations, 1x,2x,3x,1c,2c,3c var i,lnObs: integer; lSqrSumDif,lSumDif,lSumDifSqr,lDF,lDif,lmeanDif,lVar: double; begin lOutT := 0; if (odd(lnSubj)) or (lnSubj < 4) then exit; //must have even number lnObs := lnSubj shr 1; lSumDif := 0; lSumDifSqr := 0; for i := 0 to (lnObs-1) do begin //for each subject lDif := lIn^[i]-(lIn^[lnObs+i]) ; lSumDif := lSumDif + lDif; lSumDifSqr := lSumDifSqr + sqr(lDif); end; lDF := lnObs - 1; if (lSumDifSqr <> 0)and (lSumDif <> 0){and (lDF <> 0) and (lnObs <> 0)} then begin lmeanDif := lSumDif / lnObs; lSqrSumDif := sqr(lSumDif); lVar := lSumDifSqr - (lSqrSumDif / lnObs); lVar := lVar / (lnObs * lDF); lVar := sqrt(lVar); if lVar <> 0 then lOutT := lmeanDif / lVar; end; end; (*procedure ReportError (lnSubj, lnGroupX: integer; var lIn: DoubleP0; lS: double); var myFile : TextFile; text : string; i: integer; begin AssignFile(myFile, 'c:\Test666.txt'); ReWrite(myFile); WriteLn(myFile,'Subj = '+INTTOSTR(lnSubj)); WriteLn(myFile,'Group1 = '+INTTOSTR(lnGroupX)); WriteLn(myFile,'Var = '+FLOATTOSTR(lS)); for i := 0 to (lnSubj-1) do WriteLn(myFile,floattostr(lIn^[i])); CloseFile(myFile); end;*) procedure TStat2 (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutT: double); //pooled variance t-test http://www.okstate.edu/ag/agedcm4h/academic/aged5980a/5980/newpage26.htm const tiny = 1.0e-5; var i,lnGroupY: integer; lSumX,lSumY,lSumSqrx,lSumSqry,lVarx,lVary,lS: double; begin lnGroupY := lnSubj - lnGroupX; lOutT := 0; if (lnGroupX < 1) or (lnGroupY < 1) or (lnSubj < 3) then //need at least 1 subj in each group exit; lSumx := 0; lSumSqrX := 0; for i := 0 to (lnGroupX-1) do begin //for each subject //lVal := lIn[i]; lsumx := lsumx + lIn^[i]; lSumSqrX := lSumSqrX + sqr(lIn^[i]); end; lVarx := (lnGroupX*lSumSqrX) - Sqr(lsumx); if lnGroupX > 1 then lVarX := lVarX / (lnGroupX*(lnGroupX-1)) else lVarx := 0; lSumy := 0; lSumSqry := 0; for i := lnGroupX to (lnSubj-1) do begin //for each subject lsumy := lsumy + lIn^[i]; lSumSqry := lSumSqry + sqr(lIn^[i]); end; //for each sub //lMnY := lsumy/lnGroupY; lVary := (lnGroupY*lSumSqrY) - Sqr(lsumy); if lnGroupY > 1 then lVary := lVary / (lnGroupY*(lnGroupY-1)) else lVary := 0; //lm := (lsumx/lnGroupX)-(lsumy/lnGroupY); //mean effect size lmnx - lmny; //ldf := lnSubj - 2; ls := ( ((lnGroupX - 1) * lvarx + (lnGroupY - 1) * lvary) / (lnSubj - 2){ldf}) ; if abs(ls) < tiny then exit; if ls < 0 then showmessage('Error: t-test variance should not be zero.'); //deepshit (lnSubj, lnGroupX, lIn,lS); //if ls <= 0 then // exit; xxx ls := sqrt( ls) ; ls := ls * sqrt(1 / lnGroupX + 1 / lnGroupY); //note - to get here both lnx and lny > 0 if ls = 0 then lOutT := 0 else lOutT := ( ((lsumx/lnGroupX)-(lsumy/lnGroupY))/ls);//t = lm / ls; end; (*procedure TStatAbs (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutT: double); var i,lnGroupY: integer; lSumX,lSumY,lSumSqrx,lSumSqry,lVarx,lVary,lS: double; begin lnGroupY := lnSubj - lnGroupX; if (lnGroupX < 1) or (lnGroupY < 1) then begin //need at least 1 subj in each group lOutT := 0; exit; end; lSumx := 0; lSumSqrX := 0; for i := 0 to (lnGroupX-1) do begin //for each subject lsumx := lsumx + lIn[i]; lSumSqrX := lSumSqrX + sqr(lIn[i]); end; lVarx := (lnGroupX*lSumSqrX) - Sqr(lsumx); if lnGroupX > 1 then lVarX := lVarX / (lnGroupX*(lnGroupX-1)) else lVarx := 0; lSumy := 0; lSumSqry := 0; for i := lnGroupX to (lnSubj-1) do begin //for each subject //lVal := lIn[i]; lsumy := lsumy + lIn[i]; lSumSqry := lSumSqry + sqr(lIn[i]); end; //for each sub lVary := (lnGroupY*lSumSqrY) - Sqr(lsumy); if lnGroupY > 1 then lVary := lVary / (lnGroupY*(lnGroupY-1)) else lVary := 0; ls := sqrt( ( ((lnGroupX - 1) * lvarx + (lnGroupY - 1) * lvary) / (lnSubj - 2)) ) ; ls := ls * sqrt(1 / lnGroupX + 1 / lnGroupY); //note - to get here both lnx and lny > 0 if ls = 0 then lOutT := 0 else lOutT := ( ((lsumx/lnGroupX)-(lsumy/lnGroupY))/ls);//t = lm / ls; //next - create direction map if (abs(lOutT) >= 1.96) then begin if abs (lsumx/lnGroupX) > abs(lsumy/lnGroupY) then lOutT := 4 else lOutT := -4 end else lOutT := 0; end;*) procedure TStat2Z (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutT: double); var i,lnGroupY: integer; lSumX,lSumY,lSumSqrx,lSumSqry,lVarx,lVary,lS: double; begin lnGroupY := lnSubj - lnGroupX; if (lnGroupX < 1) or (lnGroupY < 1) then begin //need at least 1 subj in each group lOutT := 0; exit; end; lSumx := 0; lSumSqrX := 0; for i := 0 to (lnGroupX-1) do begin //for each subject //lVal := lIn[i]; lsumx := lsumx + lIn^[i]; lSumSqrX := lSumSqrX + sqr(lIn^[i]); end; lVarx := (lnGroupX*lSumSqrX) - Sqr(lsumx); if lnGroupX > 1 then lVarX := lVarX / (lnGroupX*(lnGroupX-1)) else lVarx := 0; lSumy := 0; lSumSqry := 0; for i := lnGroupX to (lnSubj-1) do begin //for each subject //lVal := lIn[i]; lsumy := lsumy + lIn^[i]; lSumSqry := lSumSqry + sqr(lIn^[i]); end; //for each sub //lMnY := lsumy/lnGroupY; lVary := (lnGroupY*lSumSqrY) - Sqr(lsumy); if lnGroupY > 1 then lVary := lVary / (lnGroupY*(lnGroupY-1)) else lVary := 0; //lm := (lsumx/lnGroupX)-(lsumy/lnGroupY); //mean effect size lmnx - lmny; //ldf := lnSubj - 2; ls := sqrt( ( ((lnGroupX - 1) * lvarx + (lnGroupY - 1) * lvary) / (lnSubj - 2){ldf}) ) ; ls := ls * sqrt(1 / lnGroupX + 1 / lnGroupY); //note - to get here both lnx and lny > 0 if ls = 0 then lOutT := 0 else begin lOutT := ( ((lsumx/lnGroupX)-(lsumy/lnGroupY))/ls);//t = lm / ls; lOutT := TtoZ (lOutT,lnSubj-2); //fx((lsumx/lnGroupX),(lsumy/lnGroupY)); end; end; procedure TStatWelch (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var lOutT: double); //see R. D. DeVeaux 'The t -test: Some details' for details //uses Welch's Test to protect against unequal variances //uses true [often fractional] Degrees of Freedom label 129; var i,lNx,lNy: integer; lVal,lSumX,lSumY,lSumSqrx,lSumSqry,lVarx,lVary,lMnX,lMnY,lM,lDF,lDenom,lZ,lT: double; begin lZ := 0; lNx := 0; lSumx := 0; lSumSqrX := 0; lNy := 0; lSumy := 0; lSumSqry := 0; for i := 0 to (lnSubj-1) do begin //for each subject lVal := lIn^[i]; if i < lnGroup0 then begin //group0 inc(lNx); lsumx := lsumx + lVal; lSumSqrX := lSumSqrX + sqr(lVal); end else begin //else group1 inc(lNy); lsumy := lsumy + lVal; lSumSqry := lSumSqry + sqr(lVal); end;//group1 end; //for each sub if (lNy < 2) or (lNx < 2) then goto 129; //unable to calculate lVarX := (lNx*lSumSqrX) - Sqr(lSumX); lVarX := lVarX / (lNx*(lNx-1)); lMnX := lSumX/lNx; lVary := (lNy*lSumSqrY) - Sqr(lsumy); lVary := lVary / (lNy*(lNy-1)); lMnY := lSumY/lNy; lm := lMnX - lMnY; //difference between means = t-Numerator if (lm = 0) {or (lVarY=0) or (lVarX = 0)} then goto 129; //no difference in proportions - do not waste time computing DF //next compute true Degrees of Freedom lDF := sqr( (lVarX/lNx)+(lVarY/lNy)); //lDF := lDF /( ((Sqr(lVarX/lNx)) / (lnx-1) ) + ((Sqr(lVarY/lNy)) / (lny-1) ) ); if (lVarX=0) or (lVarY=0) then begin //forced to estimate based on pooled variance lDF := lnx+lny -2; lDenom:= ( ((lnx - 1) * lvarx + (lny - 1) * lvary) / (lNx+lNy-2)); lDenom := sqrt(lDenom / lnx + lDenom / lny); end else begin lDF := lDF /( ((Sqr(lVarX/lNx)) / (lnx-1) ) + ((Sqr(lVarY/lNy)) / (lny-1) ) ); lDenom := sqrt(lVarX/lNx + lVary/lNy);//assume Unequal variances "Welch's Test" end; if lDenom = 0 then goto 129; lT := ( lm/lDenom);//t = m / d; lZ := TtoZ(lT,lDF); //az //lP := pNormal(TtoZ(lT,lDF)); 129: lOutT := lZ; //vlsm compatible = lOutT[lColX] := ( lm/lD);//t = m / d; end; FUNCTION specialdouble (d:double): boolean; //returns true if s is Infinity, NAN or Indeterminate //8byte IEEE: msb[63] = signbit, bits[52-62] exponent, bits[0..51] mantissa //exponent of all 1s = Infinity, NAN or Indeterminate CONST kSpecialExponent = 2047 shl 20; VAR Overlay: ARRAY[1..2] OF LongInt ABSOLUTE d; BEGIN IF ((Overlay[2] AND kSpecialExponent) = kSpecialExponent) THEN RESULT := true ELSE RESULT := false; END; procedure LocalRank (first, last: integer; var DynDataRA,DynDataRAX:DoubleP0; var lGroupRA: Bytep0); var lGroup,lnTies,lPos,lStartPos,lRankPos,lLocalRank: integer; lScore,lTie : double; begin for lGroup := 0 to 1 do begin lPos := first; lLocalRank := 0; while lPos <= last do begin if lGroupRA^[lPos] = lGroup then begin// inc(lLocalRank); lStartPos := lPos; lScore := DynDataRA^[lPos]; lnTies := 0; while (lPos < last) and (0.001 > abs (lScore - DynDataRA^[lPos+1]) ) do begin inc(lPos); //count ties if lGroupRA^[lPos] = lGroup then inc(lnTies); end; lTie := (lnTies) *0.5; for lRankPos := lStartPos to lPos do begin if lGroupRA^[lRankPos] = lGroup then DynDataRAX^[lRankPos] := (lLocalRank+lTie); end; lLocalRank := lLocalRank + lnTies; end; //if in group inc(lPos);//start with next value end; //while... for each observation end; //for each group end; procedure BMTest (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var lOutT: double); //procedure BMtest (lnRow,lnCol: integer; var lIn,lOutT: DoubleP0); var lObspX,lObsp: pointer; lObsX,lObs: Doublep0; lGroupRA: Bytep0; i,ln0,ln1,lColX: integer; lDF,lZ,lGSum: double; lSum0,lSum1,lMean0,lMean1,lSqr0,lSqr1,lk0,lk1: double; begin createArray64(lObsp,lObs,lnSubj); getmem(lGroupRA,lnSubj*sizeof(Byte)); createArray64(lObspX,lObsX,lnSubj); ln0 := 0; ln1 := 0; for i := 0 to (lnSubj-1) do begin //for each subject //lVal := lIn[i]; lObs^[i] := lIn^[i]; if i < lnGroup0 then //group0 lGroupRA^[i] := 0 else lGroupRA^[i] := 1; end; //for each sub for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then inc(ln0) //number of observations in group zero else inc(ln1); //number of observations in group one if (ln0 > 1) and (ln1 > 1) then begin SortDouble(0,lnSubj-1,lObs,lGroupRA); RankArray(0,lnSubj-1,lObs,lGSum); lSum0 := 0; lSum1 := 0; for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then lSum0 := lSum0 + lObs^[i] else lSum1 := lSum1 + lObs^[i]; lMean0 := lSum0 / ln0; lMean1 := lSum1 / ln1; //fx(lmean0,lMean1); lSqr0 := 0; lSqr1 := 1; lk0 := (ln0+1)/2; lk1 := (ln1+1)/2; LocalRank(0,lnSubj-1,lObs,lObsX,lGroupRA); for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then lSqr0 := lSqr0 + Sqr(lObs^[i]-lObsX^[i]-lMean0+lk0) else lSqr1 := lSqr1 + Sqr(lObs^[i]-lObsX^[i]-lMean1+lk1); lSqr0 := (1/(ln0-1))*lSqr0; lSqr1 := (1/(ln1-1))*lSqr1; lZ := -(ln0*ln1*(lMean1-lMean0))/((ln0+ln1)*sqrt((ln0*lSqr0)+(ln1*lSqr1) ) ); lDF := sqr(ln0*lSqr0+ln1*lSqr1) / ( (sqr(ln0*lSqr0)/(ln0-1)) + (sqr(ln1*lSqr1)/(ln1-1)) ) ; lZ := TtoZ(lZ,lDF); //az lOutT := lZ; //fx(lZ,lDF); end else //>1 lOutT := 0; freemem(lObsp); freemem(lObspX); freemem(lGroupRA); end; //bmtest procedure WilcoxonMW2 (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var lOutT: double); var lObsp: pointer; lObs: Doublep0; lGroupRA: Bytep0; m,n,i,ln0,ln1,mplusn: integer; lPermutations,lVal,lWsmalln,lZ,lZi,lTail,lGSum,lWTotal,lH0,lSum: double; begin createArray64(lObsp,lObs,lnSubj); getmem(lGroupRA,lnSubj*sizeof(Byte)); ln0 := 0; ln1 := 0; for i := 0 to (lnSubj-1) do begin //for each subject //lVal := lIn[i]; lObs[i] := lIn[i]; if i < lnGroup0 then //group0 lGroupRA^[i] := 0 else lGroupRA^[i] := 1; end; //for each sub for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then inc(ln0) //number of observations in group zero else inc(ln1); //number of observations in group one SortDouble(0,lnSubj-1,lObs,lGroupRA); RankArray(0,lnSubj-1,lObs,lGSum); lWsmalln := 0; if ln1 < ln0 then begin //Group1 smaller than Group0 m := ln1; n := ln0; for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 1 then lWsmalln := lWsmalln + lObs^[i]; end else begin//Group0 smaller than Group1 m := ln0; n := ln1; for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then lWsmalln := lWsmalln + lObs^[i]; end; mplusn := m + n; lZ := 0; if lWsmalln > (mplusn*(mplusn+1)/4) then lTail := -0.5 else lTail := 0.5; if m < 1 then lZ := 0 else if lGSum = 0 then begin //no ties lZ := ( lWsmalln + lTail - m * ( m + n + 1 ) / 2 ) / sqrt( m * n * ( m + n + 1 ) / 12 ); end else begin //correct for ties, see Siegel page 135 if ((12-lGSum)<>0) and (((lnSubj*(lnSubj-1)) * (((lnSubj*lnSubj*lnSubj) -lnSubj) /12-lGSum))<> 0) then begin lZ := lWsmalln + lTail - (m * ( lnSubj + 1 ) / 2 ); lZ := lZ/sqrt ( (m*n)/ (lnSubj*(lnSubj-1)) * (((lnSubj*lnSubj*lnSubj) -lnSubj) /12-lGSum)); end else begin lZ := ( lWsmalln + lTail - m * ( m + n + 1 ) / 2 ) / sqrt( m * n * ( m + n + 1 ) / 12 ); end; end; {if lStr = '' then begin for i := 0 to (lnSubj-1) do lStr := lStr+inttostr(lGroupRA[i])+', '+floattostr( lObs[i])+';'; lStr := ('w'+floattostr(lWsmalln)+'Z'+floattostr(lZ)+'ties'+floattostr(lgSum)+'m'+inttostr(m)+'n'+inttostr(n)+':'+lStr); end; } if m < 10 then lPermutations := k_out_n(m,mplusn); if (m < 10) and (lPermutations < 20000000) and (abs(lZ) > 1) {}then begin lWTotal :=mplusn*(mplusn+1)/2; //sum ranks for both groups m and n lH0 := lWTotal * (m/mplusn); //null hypothesis lSum := 0; //next - use smallest value of W if lWSmallN > lH0 then begin lWSmallN := lH0 - (lWSmallN-lH0); //Due to ties, we need to flip the order as well, as we are searching smaller for i := 0 to (lnSubj-1) do lObs^[i] := (lnSubj+1)-lObs^[i]; for i := 0 to ((lnSubj-2) div 2) do begin //swap lVal := lObs^[i]; lObs^[i] := lObs^[lnSubj-1-i]; lObs^[lnSubj-1-i] := lVal; end; end; lVal := CountSmallerRanks(lWSmallN, lSum, m, 0,(mplusn-1), lObs); lZi := lZ; lZ :=pNormalInvQuickApprox(lVal/lPermutations); if ((lZ > 0) and (lZi < -1)) or ((lZ < 0) and (lZi > 1)) then lZ := -lZ; end; if ln1 < ln0 then //we computed unexpected tail lOutT := -lZ else lOutT := lZ;//t = m / d; freemem(lObsp); freemem(lGroupRA); end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/hdr.pas��������������������������������������������������0000755�0001750�0001750�00000050513�12064634164�017456� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit hdr; interface {$H+} uses nifti_hdr,define_types,classes; procedure MakeStatHdr (var lBGHdr,lStatHdr: TniftiHdr; lMinIntensity,lMaxIntensity,lIntent_p1,lIntent_p2,lIntent_p3: single; lIntent_code: smallint;lIntentName: string); procedure MakeHdr (var lBGHdr,lStatHdr: TniftiHdr); function NIFTIhdr_SaveHdrImg (var lFilename: string; var lHdr: TNIFTIHdr; lAllowOverwrite,lSPM2,lSingleFile: boolean;var lImg: SingleP; lnVol: integer): boolean; function NIFTIhdr_SaveHdrImg8 (var lFilename: string; var lHdr: TNIFTIHdr; lAllowOverwrite,lSPM2,lSingleFile: boolean;var lImg: ByteP; lnVol: integer): boolean; function Files4D (lFilename: string): boolean; function Vol4D (lFilename: string): integer; function FileExists4D (lFilename: string): boolean; function Filename4D(lFilename: string): string; function FilenameVol4D (lFilename: string; var lBaseName: string; var lVol: integer): boolean; function NIFTIhdr_HdrVolumes (lFilenameIn: string): integer; function BPP (lDataType: integer): integer; function CreateDecompressed4D(var lImageNames: TStrings): string; function CheckVoxels(var lHdrNameIn : string; lMaskVoxels, lImageNumber: integer):boolean; //function CheckVoxelsGroupX(var lG: TStrings; lMaskVoxels: integer):boolean; function CheckVoxelsGroupX(var lG: TStrings; lMaskHdr: TMRIcroHdr): boolean; //function CheckVoxelsGroupY(var lG: TStrings):boolean; procedure DeleteDecompressed4D(lDecomName: string); implementation uses {$IFDEF FPC} gzio2,Controls, {$ELSE} {gzio,ZLib,}DiskSpaceKludge,gziod,{$ENDIF} {$IFNDEF UNIX}Windows, {$ENDIF} Dialogs ,SysUtils,StatThdsUtil,npmform; //define_types,GraphicsMathLibrary; {$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF} procedure MsgX (lStr: string); begin //msgx end; procedure DeleteDecompressed4D(lDecomName: string); begin if lDecomName = '' then exit; if not fileexists(lDecomName) then exit; sysutils.deletefile(lDecomName); end; function CheckVoxels(var lHdrNameIn : string; lMaskVoxels, lImageNumber: integer):boolean; var lHdr: TMRIcroHdr; lHdrName: string; lVox: integer; begin result := false; lHdrName := Filename4D(lHdrNameIn); if not NIFTIhdr_LoadHdr(lHdrName,lHdr) then begin MainForm.NPMmsg('Unable to load image '+lHdrName); exit; end; lVox := ComputeImageDataBytes8bpp(lHdr); if lVox <> lMaskVoxels then begin MainForm.NPMmsg('Voxels differ for '+lHdrName+' expected '+inttostr(lMaskVoxels)+' described '+inttostr(lVox)); exit; end; (*if (lHdr.NIFTIhdr.bitpix <> 8) and (lHdr.NIFTIhdr.datatype <> kDT_FLOAT) and (lHdr.NIFTIhdr.datatype <> kDT_SIGNED_INT) then begin showmessage('Error: This software can only read uncompressed images that are either 8-bit integer or 32-bit real precision.'); exit; end; //beta *) if UpCaseExt(lHdrName) = '.HDR' then lHdrName := changefileext(lHdrName,'.img'); if (not GzExt(lHdrName) ) and (FSize(lHdrName) < lMaskVoxels) then begin showmessage('The uncompressed image data should be at least '+inttostr(lMaskVoxels)+' bytes. '+lHdrName); exit; end; result := true; //gBitPixRA[lImageNumber] := lHdr.NIFTIhdr.bitpix; gDataTypeRA[lImageNumber] := lHdr.NIFTIhdr.datatype; gOffsetRA[lImageNumber] := lHdr.NIFTIhdr.vox_offset; gScaleRA[lImageNumber] := lHdr.NIFTIhdr.scl_slope; gInterceptRA[lImageNumber] := lHdr.NIFTIhdr.scl_inter; end; (*function CheckVoxelsGroup(var lG: TStrings; lMaskVoxels: integer):boolean; var lC: integer; lHdrName : string; begin result := false; if lG.count < 1 then exit; for lC := 1 to lG.count do begin lHdrName:= lG[lC-1]; result := CheckVoxels(lHdrName, lMaskVoxels,lC); end; end;*) (*function CheckVoxelsGroup(var lG: TStrings; lMaskVoxels: integer):boolean; var lC: integer; lHdrName : string; begin result := false; if lG.count < 1 then exit; for lC := 1 to lG.count do begin lHdrName:= lG[lC-1]; if not CheckVoxels(lHdrName, lMaskVoxels,lC) then begin if not fileexists (lHdrName) then MainForm.NPMmsg('File not found "'+lHdrName+'"') else MainForm.NPMmsg('Problem with "'+lHdrName+'" expected '+inttostr(lMaskVoxels)); exit; end; end; result := true; end;*) function SameTransform (A,B:TNIFTIhdr): boolean; var lDim: integer; begin result := false; for lDim := 0 to 3 do begin if A.srow_x[lDim] <> B.srow_x[lDim] then exit; if A.srow_y[lDim] <> B.srow_y[lDim] then exit; if A.srow_z[lDim] <> B.srow_z[lDim] then exit; end; result := true; end; function TransformTxt (A:TNIFTIhdr): string; var lDim: integer; begin result := '['; for lDim := 0 to 3 do result := result + ' '+floattostr(A.srow_x[lDim]); result := result + ';'; for lDim := 0 to 3 do result := result + ' '+floattostr(A.srow_y[lDim]); result := result + ';'; for lDim := 0 to 3 do result := result + ' '+floattostr(A.srow_z[lDim]); result := result + ']'; end; function CheckVoxelsX(var lHdrNameIn : string; lMaskHdr: TMRIcroHdr; lImageNumber: integer):boolean; var lHdr: TMRIcroHdr; lHdrName: string; lDim: integer; begin result := false; lHdrName := Filename4D(lHdrNameIn); if not NIFTIhdr_LoadHdr(lHdrName,lHdr) then begin MainForm.NPMmsg('Unable to load image '+lHdrName+' Possible solution: make sure VAL file and images are in the same folder'); exit; end; (*lVox := ComputeImageDataBytes8bpp(lHdr); lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if lVox <> lMaskVoxels then begin MainForm.NPMmsg('Voxels differ for '+lHdrName+' expected '+inttostr(lMaskVoxels)+' described '+inttostr(lVox)); exit; end; *) for lDim := 1 to 3 do begin if (lHdr.NIFTIhdr.dim[lDim] <> lMaskHdr.NIFTIhdr.dim[lDim]) then begin MainForm.NPMmsg('Dimension '+inttostr(lDim)+' of '+lHdrName+' does not match '+lMaskHdr.HdrFileName); exit; end; end; if (not lHdr.NIfTItransform) then MainForm.NPMmsg('Warning: no spatial transform for '+lHdrName+' (Analyze not NIfTI). Please ensure images are coregistered.') else if (not lMaskHdr.NIfTItransform) then MainForm.NPMmsg('Warning: no spatial transform for '+lMaskHdr.HdrFileName+' (Analyze not NIfTI). Please ensure images are coregistered.') else begin if not SameTransform (lHdr.NIFTIhdr, lMaskHdr.NIFTIhdr) then begin MainForm.NPMmsg('Warning: spatial transforms differ for '+lHdrName+' and '+lMaskHdr.HdrFileName); MainForm.NPMmsg(TransformTxt(lHdr.NIFTIhdr)+' <> '+ TransformTxt(lMaskHdr.NIFTIhdr)); end; end; (*if (lHdr.NIFTIhdr.bitpix <> 8) and (lHdr.NIFTIhdr.datatype <> kDT_FLOAT) and (lHdr.NIFTIhdr.datatype <> kDT_SIGNED_INT) then begin showmessage('Error: This software can only read uncompressed images that are either 8-bit integer or 32-bit real precision.'); exit; end; //beta *) if UpCaseExt(lHdrName) = '.HDR' then lHdrName := changefileext(lHdrName,'.img'); if (not GzExt(lHdrName) ) and (FSize(lHdrName) < (lHdr.NIFTIhdr.dim[1]*lHdr.NIFTIhdr.dim[2]*lHdr.NIFTIhdr.dim[3])) then begin showmessage('The file size appears too small '+lHdrName); exit; end; result := true; //gBitPixRA[lImageNumber] := lHdr.NIFTIhdr.bitpix; gDataTypeRA[lImageNumber] := lHdr.NIFTIhdr.datatype; gOffsetRA[lImageNumber] := lHdr.NIFTIhdr.vox_offset; gScaleRA[lImageNumber] := lHdr.NIFTIhdr.scl_slope; gInterceptRA[lImageNumber] := lHdr.NIFTIhdr.scl_inter; end; function CheckVoxelsGroupX(var lG: TStrings; lMaskHdr: TMRIcroHdr):boolean; var lC: integer; lHdrName : string; begin result := false; if lG.count < 1 then exit; for lC := 1 to lG.count do begin lHdrName:= lG[lC-1]; if not CheckVoxelsX(lHdrName, lMaskHdr,lC) then begin if not fileexists (lHdrName) then MainForm.NPMmsg('File not found "'+lHdrName+'". Possible solution: make sure VAL file and images are in the same folder') else MainForm.NPMmsg('Problem with "'+lHdrName); exit; end; end; result := true; end; (*function CheckVoxelsGroupY(var lG: TStrings):boolean; var lMaskHdr: TMRIcroHdr; lS: string; begin result := false; if lG.count < 1 then exit; lS := lG[0]; if not NIFTIhdr_LoadHdr(lS,lMaskHdr) then begin MainForm.NPMmsg('Unable to load image '+lS); exit; end; result := CheckVoxelsGroupX(lG,lMaskHdr); end; *) function BPP (lDataType: integer): integer; begin result := 0; case lDataType of kDT_UNSIGNED_CHAR: result := 1; kDT_SIGNED_SHORT: result := 2; // signed short (16 bits/voxel) kDT_SIGNED_INT : result := 4; // signed int (32 bits/voxel) kDT_FLOAT : result := 4; // float (32 bits/voxel) kDT_COMPLEX : result := 8; // complex (64 bits/voxel) end; end; function NIFTIhdr_HdrVolumes (lFilenameIn: string): integer; var lFilename: string; lHdr: TMRIcroHdr; begin result := 0; lFilename := lFilenameIn; if not NIFTIhdr_LoadHdr (lFilename, lHdr)then exit; result := lHdr.niftiHdr.dim[4]; end; function FileExists4D (lFilename: string): boolean; var lBaseName: string; var lVol: integer; begin FilenameVol4D (lFilename, lBasename,lVol); result := fileexists(lBasename); end; function FilenameVol4D (lFilename: string; var lBaseName: string; var lVol: integer): boolean; //4D files end with the image index number c:\dir\filename:1 //returns true if 4D file (with lVol = volume), otherwise returns false with lvol = 1 var lLen,lP: integer; lNumStr: string; begin lVol := 1; lBasename := lFilename; result := false; lLen := length(lFilename); if lLen < 1 then exit; lP := lLen; lNumStr := ''; while (lP > 0) and (lFilename[lP] in ['0'..'9']) do begin lNumStr := lFilename[lP]+lNumStr; dec(lP); end; //showmessage(lNumStr + '*'+lFilename[lP]); if (lNumStr = '') or (lP < 2) or (lFilename[lP] <> ':') then exit; lVol := strtoint(lNumStr); lLen := lP -1; lBasename := ''; for lP := 1 to lLen do lBasename := lBasename + lFilename[lP]; result := true; end; function Filename4D(lFilename: string): string; var lVol: integer; begin FilenameVol4D (lFilename, result,lVol); end; function Vol4D (lFilename: string): integer; var lBaseName: string; begin FilenameVol4D (lFilename, lBasename,result); end; function Files4D (lFilename: string): boolean; var lBaseName: string; var lVol: integer; begin result := FilenameVol4D (lFilename, lBasename,lVol); end; function CreateDecompressed4D(var lImageNames: TStrings): string; //returns temp filename if all imagenames are a single compressed 4D datafile //this means that a nii.gz file is only decompressed once, instead of once per volume*plank var lP: integer; lFilename : string; begin result := ''; if lImageNames.Count < 2 then exit; if not Files4D(lImageNames.Strings[0]) then exit; lFilename := Filename4D(lImageNames.Strings[0]); if not Fileexists(lFilename) then exit; if not GzExt(lFilename) then exit; //not a decompressed file //see if single 4D image for lP := 2 to lImageNames.Count do if not Files4D(lImageNames.Strings[lP-1]) then exit; for lP := 2 to lImageNames.Count do if lFilename <> Filename4D(lImageNames.Strings[lP-1]) then exit; //find unique filename for extracted file result := lFilename +'.nii'; while fileexists(result) do //make sure we do not overwrite anything result := lFilename +inttostr(random(9999))+'.nii'; //unzip Msgx('Decompressing 4D image '+lFilename+ ' -> '+result); Gunzip(lFilename,result); //set image names to point to uncompressed volume for lP := 1 to lImageNames.Count do lImageNames.Strings[lP-1] := result +':'+inttostr(Vol4D(lImageNames.Strings[lP-1]) ); end; procedure MakeStatHdr (var lBGHdr,lStatHdr: TniftiHdr; lMinIntensity,lMaxIntensity,lIntent_p1,lIntent_p2,lIntent_p3: single; lIntent_code: smallint;lIntentName: string); var lIntentNameLen,lPos: integer; lStr: string; begin move(lBGHdr,lStatHdr,sizeof(TniftiHdr)); with lStatHdr do begin magic :=kNIFTI_MAGIC_SEPARATE_HDR; bitpix := 32; //32-bit real data datatype := kDT_FLOAT; scl_slope:= 1; scl_inter:= 0; glmin := round(lMinIntensity); glmax := round(lMaxIntensity); intent_code := lIntent_Code;// kNIFTI_INTENT_ESTIMATE; intent_p1 := lIntent_p1; intent_p2 := lIntent_p2; intent_p3 := lIntent_p3; lIntentNameLen := length(lIntentName); descrip[1] := 'N'; descrip[2] := 'P'; descrip[3] := 'M'; if lIntent_code=kNIFTI_INTENT_TTEST then begin descrip[4] := 't' ; lStr := inttostr(trunc(lIntent_p1)); for lPos := 1 to length (lStr) do descrip[4+lPos] := lStr[lPos] ; end else descrip[4] := 'z'; if lIntentNameLen > sizeof(intent_name) then lIntentNameLen := sizeof(intent_name); if lIntentNameLen > 0 then for lPos := 1 to lIntentNameLen do intent_name[lPos] := lIntentName[lPos]; end; end; procedure SaveAsVOIorNIFTIcore (var lFilename: string; var lNiftiHdr: TNIFTIHdr; var lImg: SingleP; lnVolIn,lImgBufferBPP: integer); const kImgOffset = 352; //header is 348 bytes, but 352 is divisible by 8... var lHdr: TNIFTIhdr; lBuff: ByteP; lF: File; lCompressedFilename,lExt: string; lnVol,lC,lFSize: integer; lImgBuffer: ByteP; lImgBufferItems{, lImgBufferBPP}: integer; begin lnVol := lnVolIn; move(lNiftiHdr,lHdr,sizeof(lHdr)); lImgBufferItems := lHdr.dim[1]*lHdr.dim[2]*lHdr.dim[3]; //lImgBufferBPP:= 4; lImgBuffer := ByteP(lImg); lExt := UpCaseExt(lFileName); if DiskFreeEx(lFilename) < (kImgOffset+(lImgBufferItems*lImgBufferBPP*lnVol)) then begin case MessageDlg('Very little space on the selected drive. Attempt to save to this disk?', mtConfirmation, [mbYes, mbCancel], 0) of {$IFDEF FPC}mrCancel: exit; {$ELSE} id_Cancel: exit;{$ENDIF} end; //case end; if FileExistsEX(lFileName) then begin case MessageDlg('Overwrite the file named '+lFileName+'?', mtConfirmation, [mbYes, mbCancel], 0) of {$IFDEF FPC}mrCancel: exit; {$ELSE} id_Cancel: exit;{$ENDIF} //requires Uses Controls end; //case end; //file exists if (lExt='.VOI') then begin lHdr.intent_name[1] := 'B';//Binary lHdr.scl_slope := 1/kVOI8bit; lHdr.scl_inter := 0; end; if lnVol < 2 then begin lHdr.dim[0] := 3;//3D july2006 lHdr.dim[4] := 1;//3D Aug 2007 lnVol := 1; end else begin lHdr.dim[0] := 4;//3D july2006 lHdr.dim[4] := lnVol;//3D july2006 end; (*if not (lImgBufferItems = (lHdr.dim[1]*lHdr.dim[2]*lHdr.dim[3])) then begin //july2006 lHdr.sform_code := 1; WriteNiftiMatrix ( lHdr, //must match MAGMA in nifti_hdr gBGImg.ScrnMM[1],0,0,(gBGImg.ScrnOri[1]-1)*-gBGImg.ScrnMM[1], 0,gBGImg.ScrnMM[2],0,(gBGImg.ScrnOri[2]-1)*-gBGImg.ScrnMM[2], 0,0,gBGImg.ScrnMM[3],(gBGImg.ScrnOri[3]-1)*-gBGImg.ScrnMM[3]); end;*) if not IsNifTiMagic(lHdr) then begin {lHdr.sform_code := 1; WriteNiftiMatrix ( lHdr, //must match MAGMA in nifti_hdr gBGImg.ScrnMM[1],0,0,(gBGImg.ScrnOri[1]-1)*-gBGImg.ScrnMM[1], 0,gBGImg.ScrnMM[2],0,(gBGImg.ScrnOri[2]-1)*-gBGImg.ScrnMM[2], 0,0,gBGImg.ScrnMM[3],(gBGImg.ScrnOri[3]-1)*-gBGImg.ScrnMM[3]); } end; case lImgBufferBPP of 4: begin lHdr.bitpix := 32; lHdr.datatype := kDT_FLOAT;//note 32-bit integers saved internally as 32-bit float end; 2: begin lHdr.bitpix := 16; lHdr.datatype := kDT_SIGNED_SHORT; end; 1: begin lHdr.bitpix := 8; lHdr.datatype := kDT_UNSIGNED_CHAR; //lHdr.scl_inter := lHdr.WindowScaledMin; //lHdr.scl_slope := (lHdr.WindowScaledMax-lHdr.WindowScaledMin) /255; end; else begin showmessage('Error: Unsupported bytes per voxel: '+inttostr(lImgBufferBPP)); exit; end; end; if (lExt='.IMG') or (lExt ='.HDR') then begin //done previously lHdr.magic := kNIFTI_MAGIC_SEPARATE_HDR; lHdr.vox_offset := 0; Filemode := 1; //next write header data as .hdr lFilename := changeFileExt(lFilename,'.hdr'); AssignFile(lF, lFileName); Rewrite(lF,sizeof(TNIFTIhdr)); BlockWrite(lF,lHdr, 1); CloseFile(lF); //next write image data as .img lFilename := changeFileExt(lFilename,'.img'); AssignFile(lF, lFileName); {WIN} Rewrite(lF,lImgBufferItems*lImgBufferBPP*lnVol); BlockWrite(lF,lImgBuffer^,1); CloseFile(lF); Filemode := 2; exit; end; //separate header lHdr.magic := kNIFTI_MAGIC_EMBEDDED_HDR; lHdr.vox_offset := kImgOffset;//352 bytes lFSize := kImgOffset+(lImgBufferItems*lImgBufferBPP*lnVol); getmem(lBuff,lFSize); move(lHdr,lBuff^,sizeof(lHdr)); //Next: NIfTI 1.1 requires bytes 349..352 set to zero when no XML information lC := kImgOffset; lBuff^[lC-3] := 0; lBuff^[lC-2] := 0; lBuff^[lC-1] := 0; lBuff^[lC] := 0; lC := kImgOffset+1; move(lImgBuffer^[1],lBuff^[lC],lImgBufferItems*lImgBufferBPP*lnVol); if (lExt='.NII') then begin Filemode := 1; AssignFile(lF, lFileName); Rewrite(lF,lFSize); BlockWrite(lF,lBuff^,1); CloseFile(lF); Filemode := 2; exit; end; //uncompressed if (lExt<>'.VOI') then lCompressedFilename := changefileextX(lFilename,'.nii.gz') else lCompressedFilename := lFilename; //FX(lFSize); GZipBuffer(lCompressedFilename,lBuff,lFSize,false); freemem(lBuff); end; procedure MakeHdr (var lBGHdr,lStatHdr: TniftiHdr); //lIntent kNIFTI_INTENT_CHISQ lIntent_p1 = DOF //lIntent kNIFTI_INTENT_ZSCORE no params //lIntent kNIFTI_INTENT_TTEST lIntent_p1 = DOF begin move(lBGHdr,lStatHdr,sizeof(TniftiHdr)); with lStatHdr do begin magic :=kNIFTI_MAGIC_SEPARATE_HDR; bitpix := 32; //32-bit real data datatype := kDT_FLOAT; scl_slope:= 1; scl_inter:= 0; descrip[1] := 'X';//can not be npm end; end; function NIFTIhdr_SaveHdrImg (var lFilename: string; var lHdr: TNIFTIHdr; lAllowOverwrite,lSPM2,lSingleFile: boolean;var lImg: SingleP; lnVol: integer): boolean; var lOutNameMod: string; lSPM2output: boolean; begin lOutNameMod := lFilename; lOutNameMod := changefileextX(lOutNameMod,'.hdr'); lSPM2output := lSPM2; //fx(lHdr.srow_x[3],lHdr.srow_y[3],lHdr.srow_z[3]); (*if not IsNifTiMagic(lHdr) then lSPM2output := true;*) if (lSingleFile) and (not lSPM2output) then begin lHdr.magic := kNIFTI_MAGIC_EMBEDDED_HDR; lOutNameMod := changefileextX(lOutNameMod,'.nii.gz'); end else if (not lSPM2output) then lHdr.magic := kNIFTI_MAGIC_SEPARATE_HDR else //the nifti_hdr reader converts the Analyze to NIfTI, so we need to save as NIfTI with NPM lHdr.magic := kNIFTI_MAGIC_SEPARATE_HDR; //lHdr.magic := 1984; SaveAsVOIorNIFTIcore (lOutNameMod, lHdr, lImg,lnVol,4); end; function NIFTIhdr_SaveHdrImg8 (var lFilename: string; var lHdr: TNIFTIHdr; lAllowOverwrite,lSPM2,lSingleFile: boolean;var lImg: ByteP; lnVol: integer): boolean; var lOutNameMod: string; begin lOutNameMod := lFilename; if IsVOIExt (lOutNameMod) then begin lHdr.magic := kNIFTI_MAGIC_EMBEDDED_HDR; end else begin lOutNameMod := changefileextX(lOutNameMod,'.hdr'); if (lSingleFile) and (not lSPM2) then begin lHdr.magic := kNIFTI_MAGIC_EMBEDDED_HDR; lOutNameMod := changefileextX(lOutNameMod,'.nii.gz'); end else if (not lSPM2) then lHdr.magic := kNIFTI_MAGIC_SEPARATE_HDR else lHdr.magic := 1984; end; SaveAsVOIorNIFTIcore (lOutNameMod, lHdr, SingleP(lImg),lnVol,1); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/options.inc����������������������������������������������0000755�0001750�0001750�00000000336�10673315046�020357� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ -------------------------------------------------------------------- } {$DEFINE SPREADSHEET} {If "DEFINE SPREADSHEET" then the VAL file design for will be created.} {This uses the spread.* and design.* files} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/spread.dfm�����������������������������������������������0000755�0001750�0001750�00000006425�12147211710�020133� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �TSPREADFORM�0� ��TPF0 TSpreadForm SpreadFormLeft�Top�WidthlHeightCaptionVoxelwise Analysis of LesionsColor clBtnFace Font.CharsetDEFAULT_CHARSET Font.Color clWindowText Font.Height Font.Name MS Sans Serif Font.Style �Menu MainMenu1OldCreateOrder PositionpoScreenCenterOnClose FormCloseOnCreate FormCreateOnResize FormResize PixelsPerInch` TextHeight � TStringGridDataGridLeft�TopWidthdHeightAlignalClientDefaultRowHeightRowCount FixedRowsOptions goFixedVertLine goVertLine goHorzLine goRangeSelectgoDrawFocusSelectedgoTabsgoThumbTracking�TabOrder� OnDrawCellDataGridDrawCell OnKeyPressDataGridKeyPress OnMouseDownDataGridMouseDown OnMouseMoveDataGridMouseMove OnSelectCellDataGridSelectCell ColWidths@@@@@� RowHeights���TToolBarToolBar1Left�Top�WidthdHeight EdgeBorders �TabOrder� TSpeedButton SpeedButton1Left�TopWidthHeightEnabledFlat �� TSpeedButton DesignBtnLeftTopWidth�HeightHintANOVACaptionDesign Glyph.Data z��v��BMv������v���(��� ������������������������������������������������������������������3s3s3s3s3???3sssssss?w�������wwwwwwww333<3333373?7 3<337ws73w393<393?ww|wwwwwwwwww33<3333ss3739<93373773333333?wwww|wwwwwwwwwww333<333337733<��<7337ww7333<33?wwwwwwwwwwwwwww3333333333333333 NumGlyphsParentShowHintShowHint OnClickDesignBtnClick��� TStatusBar StatusBar1Left�TopWidthdHeightPanelsWidth��Width2���� TMainMenu MainMenu1LeftlTop,� TMenuItemFile1Caption&File� TMenuItemNew1CaptionNew...ShortCutN@OnClick NewBtnClick�� TMenuItemOpen1CaptionOpen...ShortCutO@OnClick OpenBtnClick�� TMenuItemSave1CaptionSaveShortCutS@OnClick SaveBtnClick�� TMenuItem Descriptives1Caption DescriptivesOnClickDescriptiveClick�� TMenuItemQuit1Caption Close windowShortCutW@OnClick Quit1Click��� TMenuItemEdit1CaptionEdit� TMenuItemCopy1CaptionCopyShortCutC@OnClick Copy1Click�� TMenuItemPaste1CaptionPasteShortCutV@OnClick Paste1Click�� TMenuItem Selectall1CaptionSelect all cellsShortCutA@OnClickSelectall1Click�� TMenuItemClearallcells1CaptionClear all cells...OnClickClearallcells1Click�� TMenuItemDescriptiveMenuCaption DescriiptiveShortCutD@OnClickDescriptiveClick��� TMenuItemViewCaptionView� TMenuItemFont1CaptionFont� TMenuItemN81TagCaption8Checked GroupIndexo RadioItem OnClickFontSizeChange�� TMenuItemN101Tag Caption10 GroupIndexo RadioItem OnClickFontSizeChange�� TMenuItemN121Tag Caption12 GroupIndexo RadioItem OnClickFontSizeChange�� TMenuItemN141TagCaption14 GroupIndexo RadioItem OnClickFontSizeChange��� TMenuItemDesign1CaptionDesignShortCutD@OnClickDesignBtnClick��� TMenuItemHelp1Caption&HelpVisible� TMenuItemAboutthissoftware1Caption&About this softwareOnClickAboutthissoftware1Click���� TOpenDialog OpenDialog1 DefaultExt*.valFilter?Native [val]|*.val|Tab delimited text [txt]|*.txt|All files|*.*Left$Top,�� TSaveDialog SaveDialog1 DefaultExt.valFilter8Native format [val]|*.val|Tab delimited text [txt]|*.txtOptions ofOverwritePromptofHideReadOnly�LeftJTop,����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/design.lfm�����������������������������������������������0000755�0001750�0001750�00000005332�11540170650�020135� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object DesignForm: TDesignForm Left = 481 Height = 207 Top = 179 Width = 636 HorzScrollBar.Page = 635 VertScrollBar.Page = 206 ActiveControl = AVal BorderStyle = bsDialog Caption = 'Design' ClientHeight = 207 ClientWidth = 636 Constraints.MaxHeight = 207 Constraints.MaxWidth = 636 Constraints.MinHeight = 207 Constraints.MinWidth = 636 Font.Name = 'MS Sans Serif' OnCreate = FormCreate Position = poScreenCenter LCLVersion = '0.9.28.2' object Label4: TLabel Left = 4 Height = 18 Top = 8 Width = 70 Caption = 'Predictors' ParentColor = False end object Label5: TLabel Left = 76 Height = 18 Top = 8 Width = 114 Caption = 'Predictor Names' ParentColor = False end object Label1: TLabel Left = 12 Height = 18 Top = 123 Width = 81 Caption = 'Participants' ParentColor = False end object TemplateLabel: TLabel Left = 148 Height = 18 Top = 95 Width = 112 Caption = 'C:\template.img' ParentColor = False end object Label2: TLabel Left = 12 Height = 18 Top = 168 Width = 263 Caption = 'Ignore voxels damaged in less than N%' ParentColor = False end object OKBtn: TButton Left = 527 Height = 25 Top = 168 Width = 75 BorderSpacing.InnerBorder = 4 Caption = 'OK' ModalResult = 1 TabOrder = 0 end object AVal: TSpinEdit Left = 12 Height = 27 Top = 37 Width = 70 MaxValue = 99 MinValue = 1 OnChange = AValChange TabOrder = 1 Value = 2 end object ALevelNames: TStringGrid Left = 98 Height = 42 Top = 30 Width = 527 ColCount = 2 FixedCols = 0 FixedRows = 0 Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goDrawFocusSelected, goEditing] RowCount = 1 ScrollBars = ssHorizontal TabOrder = 2 TitleFont.Height = -11 TitleFont.Name = 'MS Sans Serif' OnEnter = ALevelNamesEnter OnExit = ALevelNamesExit end object LesionCovaryCheck: TCheckBox Left = 255 Height = 21 Top = 123 Width = 267 Caption = 'Automatically Covary Lesion Volume' TabOrder = 5 Visible = False end object AddMRIBtn: TButton Left = 93 Height = 25 Top = 118 Width = 129 BorderSpacing.InnerBorder = 4 Caption = 'Select Images' OnClick = AddMRIBtnClick TabOrder = 4 end object TemplateBtn: TButton Left = 12 Height = 25 Top = 89 Width = 129 BorderSpacing.InnerBorder = 4 Caption = 'Select Template' OnClick = TemplateBtnClick TabOrder = 3 end object CritPctEdit: TSpinEdit Left = 304 Height = 27 Top = 162 Width = 76 OnChange = AValChange TabOrder = 6 Value = 1 end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/filename.pas���������������������������������������������0000755�0001750�0001750�00000001117�11326425446�020456� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit filename; interface {$H+} function LegitFilename(var lInName: string; lIndex: integer): string; implementation uses SysUtils; function LegitFilename(var lInName: string; lIndex: integer): string; var I: integer; begin if length(lInName) < 1 then begin result := inttostr(lIndex); exit; end; result := ''; for I := 1 to length(lInName) do if lInName[I] in [ '0'..'9','a'..'z','A'..'Z'] then result := result + lInName[I]; if length(result) < 1 then result := inttostr(lIndex); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npm.lpi��������������������������������������������������0000755�0001750�0001750�00000050473�12147221422�017470� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <CONFIG> <ProjectOptions> <Version Value="9"/> <PathDelim Value="\"/> <General> <Flags> <LRSInOutputDirectory Value="False"/> </Flags> <MainUnit Value="0"/> <ActiveWindowIndexAtStart Value="0"/> </General> <VersionInfo> <StringTable ProductVersion=""/> </VersionInfo> <BuildModes Count="1"> <Item1 Name="default" Default="True"/> </BuildModes> <PublishOptions> <Version Value="2"/> <IgnoreBinaries Value="False"/> <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/> </PublishOptions> <RunParams> <local> <FormatVersion Value="1"/> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> </RunParams> <RequiredPackages Count="1"> <Item1> <PackageName Value="LCL"/> </Item1> </RequiredPackages> <Units Count="57"> <Unit0> <Filename Value="npm.lpr"/> <IsPartOfProject Value="True"/> <UnitName Value="npm"/> <EditorIndex Value="0"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="8" Y="13"/> <UsageCount Value="45"/> <Loaded Value="True"/> <LoadedDesigner Value="True"/> </Unit0> <Unit1> <Filename Value="npmform.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="MainForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="npmform"/> <IsVisibleTab Value="True"/> <EditorIndex Value="4"/> <WindowIndex Value="0"/> <TopLine Value="224"/> <CursorPos X="7" Y="250"/> <UsageCount Value="45"/> <Loaded Value="True"/> <LoadedDesigner Value="True"/> </Unit1> <Unit2> <Filename Value="nifti_hdr.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="nifti_hdr"/> <TopLine Value="358"/> <CursorPos X="49" Y="368"/> <UsageCount Value="41"/> </Unit2> <Unit3> <Filename Value="define_types.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="define_types"/> <TopLine Value="945"/> <CursorPos X="38" Y="959"/> <UsageCount Value="41"/> </Unit3> <Unit4> <Filename Value="GraphicsMathLibrary.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="GraphicsMathLibrary"/> <TopLine Value="681"/> <CursorPos X="1" Y="738"/> <UsageCount Value="41"/> </Unit4> <Unit5> <Filename Value="distr.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="distr"/> <TopLine Value="99"/> <CursorPos X="1" Y="107"/> <UsageCount Value="41"/> </Unit5> <Unit6> <Filename Value="statcr.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="statcr"/> <TopLine Value="1"/> <CursorPos X="34" Y="6"/> <UsageCount Value="41"/> </Unit6> <Unit7> <Filename Value="stats.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="stats"/> <TopLine Value="369"/> <CursorPos X="41" Y="370"/> <UsageCount Value="41"/> </Unit7> <Unit8> <Filename Value="brunner.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="brunner"/> <TopLine Value="500"/> <CursorPos X="29" Y="517"/> <UsageCount Value="41"/> </Unit8> <Unit9> <Filename Value="StatThdsUtil.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="StatThdsUtil"/> <TopLine Value="1"/> <CursorPos X="69" Y="6"/> <UsageCount Value="41"/> </Unit9> <Unit10> <Filename Value="StatThds.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="StatThds"/> <EditorIndex Value="9"/> <WindowIndex Value="0"/> <TopLine Value="17"/> <CursorPos X="11" Y="127"/> <UsageCount Value="41"/> <Loaded Value="True"/> </Unit10> <Unit11> <Filename Value="valformat.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="valformat"/> <TopLine Value="64"/> <CursorPos X="1" Y="91"/> <UsageCount Value="41"/> </Unit11> <Unit12> <Filename Value="design.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="DesignForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="design"/> <EditorIndex Value="3"/> <WindowIndex Value="0"/> <TopLine Value="37"/> <CursorPos X="24" Y="52"/> <UsageCount Value="40"/> <Loaded Value="True"/> <LoadedDesigner Value="True"/> </Unit12> <Unit13> <Filename Value="spread.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="SpreadForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="spread"/> <EditorIndex Value="2"/> <WindowIndex Value="0"/> <TopLine Value="557"/> <CursorPos X="1" Y="584"/> <UsageCount Value="40"/> <Loaded Value="True"/> <LoadedDesigner Value="True"/> </Unit13> <Unit14> <Filename Value="gzio2.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="gzio2"/> <TopLine Value="774"/> <CursorPos X="22" Y="793"/> <UsageCount Value="41"/> </Unit14> <Unit15> <Filename Value="part.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="part"/> <TopLine Value="91"/> <CursorPos X="38" Y="108"/> <UsageCount Value="41"/> </Unit15> <Unit16> <Filename Value="markorder.pas"/> <UnitName Value="markorder"/> <TopLine Value="8"/> <CursorPos X="44" Y="23"/> <UsageCount Value="10"/> </Unit16> <Unit17> <Filename Value="ztopform.pas"/> <ComponentName Value="ZForm"/> <UnitName Value="ztopform"/> <TopLine Value="9"/> <CursorPos X="18" Y="23"/> <UsageCount Value="22"/> </Unit17> <Unit18> <Filename Value="..\examples\opendialogcrash\unit1.pas"/> <ComponentName Value="Form1"/> <HasResources Value="True"/> <UnitName Value="Unit1"/> <TopLine Value="19"/> <CursorPos X="40" Y="14"/> <UsageCount Value="10"/> </Unit18> <Unit19> <Filename Value="nifti_img.pas"/> <UnitName Value="nifti_img"/> <TopLine Value="52"/> <CursorPos X="28" Y="54"/> <UsageCount Value="11"/> </Unit19> <Unit20> <Filename Value="lesion_pattern.pas"/> <UnitName Value="lesion_pattern"/> <TopLine Value="76"/> <CursorPos X="25" Y="86"/> <UsageCount Value="10"/> </Unit20> <Unit21> <Filename Value="ReadInt.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="ReadIntForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="ReadInt"/> <EditorIndex Value="1"/> <WindowIndex Value="0"/> <TopLine Value="33"/> <CursorPos X="9" Y="50"/> <UsageCount Value="39"/> <Loaded Value="True"/> <LoadedDesigner Value="True"/> </Unit21> <Unit22> <Filename Value="ReadInt.lrs"/> <IsPartOfProject Value="True"/> <TopLine Value="1"/> <CursorPos X="1" Y="3"/> <UsageCount Value="37"/> </Unit22> <Unit23> <Filename Value="LesionStatThds.pas"/> <UnitName Value="LesionStatThds"/> <EditorIndex Value="8"/> <WindowIndex Value="0"/> <TopLine Value="414"/> <CursorPos X="77" Y="439"/> <UsageCount Value="12"/> <Loaded Value="True"/> </Unit23> <Unit24> <Filename Value="power.pas"/> <UnitName Value="power"/> <TopLine Value="1"/> <CursorPos X="1" Y="1"/> <UsageCount Value="11"/> </Unit24> <Unit25> <Filename Value="Mat.pas"/> <UnitName Value="Mat"/> <TopLine Value="225"/> <CursorPos X="18" Y="239"/> <UsageCount Value="11"/> </Unit25> <Unit26> <Filename Value="Vector.pas"/> <UnitName Value="Vector"/> <TopLine Value="1"/> <CursorPos X="1" Y="1"/> <UsageCount Value="10"/> </Unit26> <Unit27> <Filename Value="firth.pas"/> <UnitName Value="firth"/> <TopLine Value="382"/> <CursorPos X="19" Y="383"/> <UsageCount Value="10"/> </Unit27> <Unit28> <Filename Value="overlap.pas"/> <UnitName Value="overlap"/> <TopLine Value="1"/> <CursorPos X="1" Y="6"/> <UsageCount Value="10"/> </Unit28> <Unit29> <Filename Value="firthThds.pas"/> <UnitName Value="firthThds"/> <TopLine Value="312"/> <CursorPos X="123" Y="315"/> <UsageCount Value="10"/> </Unit29> <Unit30> <Filename Value="design.lfm"/> <TopLine Value="1"/> <CursorPos X="1" Y="1"/> <UsageCount Value="10"/> <DefaultSyntaxHighlighter Value="LFM"/> </Unit30> <Unit31> <Filename Value="options.inc"/> <TopLine Value="1"/> <CursorPos X="21" Y="3"/> <UsageCount Value="11"/> </Unit31> <Unit32> <Filename Value="userdir.pas"/> <UnitName Value="userdir"/> <TopLine Value="1"/> <CursorPos X="64" Y="45"/> <UsageCount Value="11"/> </Unit32> <Unit33> <Filename Value="..\..\lcl\forms.pp"/> <UnitName Value="Forms"/> <TopLine Value="642"/> <CursorPos X="14" Y="661"/> <UsageCount Value="11"/> </Unit33> <Unit34> <Filename Value="..\gzio2.pas"/> <UnitName Value="gzio2"/> <TopLine Value="627"/> <CursorPos X="22" Y="635"/> <UsageCount Value="10"/> </Unit34> <Unit35> <Filename Value="..\..\fpc\2.0.4\source\rtl\objpas\sysutils\finah.inc"/> <TopLine Value="17"/> <CursorPos X="22" Y="27"/> <UsageCount Value="10"/> </Unit35> <Unit36> <Filename Value="..\define_types.pas"/> <UnitName Value="define_types"/> <TopLine Value="1"/> <CursorPos X="31" Y="5"/> <UsageCount Value="10"/> </Unit36> <Unit37> <Filename Value="..\..\fpc\2.0.4\source\rtl\win32\wininc\messages.inc"/> <TopLine Value="1191"/> <CursorPos X="6" Y="1201"/> <UsageCount Value="10"/> </Unit37> <Unit38> <Filename Value="regression.pas"/> <UnitName Value="regression"/> <EditorIndex Value="10"/> <WindowIndex Value="0"/> <TopLine Value="725"/> <CursorPos X="37" Y="731"/> <UsageCount Value="14"/> <Loaded Value="True"/> </Unit38> <Unit39> <Filename Value="Regmult.pas"/> <UnitName Value="RegMult"/> <TopLine Value="30"/> <CursorPos X="27" Y="43"/> <UsageCount Value="10"/> </Unit39> <Unit40> <Filename Value="..\fpmath\regmult.pas"/> <UnitName Value="regmult"/> <TopLine Value="39"/> <CursorPos X="69" Y="45"/> <UsageCount Value="10"/> </Unit40> <Unit41> <Filename Value="..\common\distr.pas"/> <UnitName Value="distr"/> <TopLine Value="296"/> <CursorPos X="1" Y="308"/> <UsageCount Value="11"/> </Unit41> <Unit42> <Filename Value="..\common\define_types.pas"/> <UnitName Value="define_types"/> <EditorIndex Value="11"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="24" Y="21"/> <UsageCount Value="12"/> <Loaded Value="True"/> </Unit42> <Unit43> <Filename Value="hdr.pas"/> <UnitName Value="hdr"/> <TopLine Value="1"/> <CursorPos X="1" Y="3"/> <UsageCount Value="10"/> </Unit43> <Unit44> <Filename Value="..\common\gzio2.pas"/> <UnitName Value="gzio2"/> <TopLine Value="223"/> <CursorPos X="16" Y="236"/> <UsageCount Value="10"/> </Unit44> <Unit45> <Filename Value="..\common\nifti_hdr.pas"/> <UnitName Value="nifti_hdr"/> <TopLine Value="119"/> <CursorPos X="1" Y="121"/> <UsageCount Value="11"/> </Unit45> <Unit46> <Filename Value="..\common\GraphicsMathLibrary.pas"/> <UnitName Value="GraphicsMathLibrary"/> <TopLine Value="1"/> <CursorPos X="17" Y="8"/> <UsageCount Value="10"/> </Unit46> <Unit47> <Filename Value="..\fpmath\utypes.pas"/> <UnitName Value="utypes"/> <TopLine Value="470"/> <CursorPos X="41" Y="482"/> <UsageCount Value="12"/> </Unit47> <Unit48> <Filename Value="lesion.pas"/> <UnitName Value="lesion"/> <TopLine Value="299"/> <CursorPos X="64" Y="313"/> <UsageCount Value="10"/> </Unit48> <Unit49> <Filename Value="anacom.pas"/> <UnitName Value="anacom"/> <TopLine Value="579"/> <CursorPos X="32" Y="593"/> <UsageCount Value="10"/> </Unit49> <Unit50> <Filename Value="filename.pas"/> <UnitName Value="filename"/> <TopLine Value="1"/> <CursorPos X="6" Y="4"/> <UsageCount Value="10"/> </Unit50> <Unit51> <Filename Value="montecarlo.pas"/> <UnitName Value="montecarlo"/> <EditorIndex Value="7"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="6" Y="3"/> <UsageCount Value="11"/> <Loaded Value="True"/> </Unit51> <Unit52> <Filename Value="roc.pas"/> <UnitName Value="roc"/> <TopLine Value="317"/> <CursorPos X="33" Y="344"/> <UsageCount Value="10"/> </Unit52> <Unit53> <Filename Value="..\fpmath\types.inc"/> <EditorIndex Value="12"/> <WindowIndex Value="0"/> <TopLine Value="112"/> <CursorPos X="3" Y="174"/> <UsageCount Value="13"/> <Loaded Value="True"/> </Unit53> <Unit54> <Filename Value="C:\Developer\lazarus\lcl\interfaces\carbon\carbonprivatecommon.inc"/> <TopLine Value="170"/> <CursorPos X="1" Y="184"/> <UsageCount Value="10"/> </Unit54> <Unit55> <Filename Value="tfce_clustering.pas"/> <UnitName Value="tfce_clustering"/> <EditorIndex Value="6"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="27" Y="3"/> <UsageCount Value="10"/> <Loaded Value="True"/> </Unit55> <Unit56> <Filename Value="..\..\..\..\..\..\Developer\lazarus\lcl\include\menuitem.inc"/> <EditorIndex Value="5"/> <WindowIndex Value="0"/> <TopLine Value="1288"/> <CursorPos X="1" Y="1317"/> <UsageCount Value="10"/> <Loaded Value="True"/> </Unit56> </Units> <JumpHistory Count="30" HistoryIndex="29"> <Position1> <Filename Value="regression.pas"/> <Caret Line="714" Column="16" TopLine="696"/> </Position1> <Position2> <Filename Value="regression.pas"/> <Caret Line="454" Column="25" TopLine="428"/> </Position2> <Position3> <Filename Value="regression.pas"/> <Caret Line="663" Column="24" TopLine="470"/> </Position3> <Position4> <Filename Value="npmform.pas"/> <Caret Line="94" Column="7" TopLine="75"/> </Position4> <Position5> <Filename Value="npmform.pas"/> <Caret Line="99" Column="11" TopLine="80"/> </Position5> <Position6> <Filename Value="tfce_clustering.pas"/> <Caret Line="1" Column="1" TopLine="1"/> </Position6> <Position7> <Filename Value="spread.pas"/> <Caret Line="591" Column="34" TopLine="587"/> </Position7> <Position8> <Filename Value="npmform.pas"/> <Caret Line="2" Column="1" TopLine="1"/> </Position8> <Position9> <Filename Value="npmform.pas"/> <Caret Line="1521" Column="28" TopLine="1502"/> </Position9> <Position10> <Filename Value="spread.pas"/> <Caret Line="584" Column="3" TopLine="557"/> </Position10> <Position11> <Filename Value="npmform.pas"/> <Caret Line="1516" Column="14" TopLine="1502"/> </Position11> <Position12> <Filename Value="npmform.pas"/> <Caret Line="1521" Column="17" TopLine="1502"/> </Position12> <Position13> <Filename Value="npmform.pas"/> <Caret Line="1518" Column="20" TopLine="1502"/> </Position13> <Position14> <Filename Value="npmform.pas"/> <Caret Line="37" Column="40" TopLine="13"/> </Position14> <Position15> <Filename Value="npmform.pas"/> <Caret Line="25" Column="22" TopLine="1"/> </Position15> <Position16> <Filename Value="npmform.pas"/> <Caret Line="30" Column="28" TopLine="1"/> </Position16> <Position17> <Filename Value="npmform.pas"/> <Caret Line="89" Column="30" TopLine="43"/> </Position17> <Position18> <Filename Value="npmform.pas"/> <Caret Line="18" Column="79" TopLine="1"/> </Position18> <Position19> <Filename Value="npmform.pas"/> <Caret Line="183" Column="43" TopLine="156"/> </Position19> <Position20> <Filename Value="npmform.pas"/> <Caret Line="1434" Column="1" TopLine="1429"/> </Position20> <Position21> <Filename Value="npmform.pas"/> <Caret Line="1511" Column="8" TopLine="1476"/> </Position21> <Position22> <Filename Value="npmform.pas"/> <Caret Line="5" Column="152" TopLine="1"/> </Position22> <Position23> <Filename Value="npmform.pas"/> <Caret Line="144" Column="23" TopLine="98"/> </Position23> <Position24> <Filename Value="npmform.pas"/> <Caret Line="32" Column="5" TopLine="18"/> </Position24> <Position25> <Filename Value="regression.pas"/> <Caret Line="671" Column="129" TopLine="661"/> </Position25> <Position26> <Filename Value="npmform.pas"/> <Caret Line="3" Column="170" TopLine="1"/> </Position26> <Position27> <Filename Value="npmform.pas"/> <Caret Line="145" Column="22" TopLine="99"/> </Position27> <Position28> <Filename Value="npmform.pas"/> <Caret Line="147" Column="26" TopLine="121"/> </Position28> <Position29> <Filename Value="npmform.pas"/> <Caret Line="239" Column="40" TopLine="205"/> </Position29> <Position30> <Filename Value="npmform.pas"/> <Caret Line="241" Column="29" TopLine="214"/> </Position30> </JumpHistory> </ProjectOptions> <CompilerOptions> <Version Value="9"/> <PathDelim Value="\"/> <SearchPaths> <OtherUnitFiles Value="..\fpmath;..\common"/> </SearchPaths> <Parsing> <SyntaxOptions> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <Linking> <Debugging> <UseLineInfoUnit Value="False"/> <StripSymbols Value="True"/> </Debugging> <LinkSmart Value="True"/> <Options> <LinkerOptions Value=" -macosx_version_min 10.4 "/> <Win32> <GraphicApplication Value="True"/> </Win32> </Options> </Linking> <Other> <CompilerMessages> <UseMsgFile Value="True"/> </CompilerMessages> <CompilerPath Value="$(CompPath)"/> </Other> </CompilerOptions> <Debugging> <Exceptions Count="2"> <Item1> <Name Value="ECodetoolError"/> </Item1> <Item2> <Name Value="EFOpenError"/> </Item2> </Exceptions> </Debugging> </CONFIG> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/tfce_clustering.zip��������������������������������������0000755�0001750�0001750�00000004375�12110670532�022074� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PK����BdSBy!Q�������tfce_clustering.pasio0'.krA%ch�eZ8vqCwm6 G=p^sN$"#gHn!L*% #D gA9<Sœ<O@$8G\wq<y'a% #g$$d~LC&9{(|NE/bV4j#s .HK{*ALy2#ԍ!ILSٯ I;ye�Z9OS@d )Nr)4/uJ`c9H \ >h�ȏo�B0rè`9y:.I W&e}ŗi"dj0*KF"~!h͉Ϧ>54"|Ձg"e!=mtAqI00z $�\!AId) /Dq3S[J@0nG{ l�d"˨Kȴ5v܈ @9!s)NII&Sc|"=#ʔfKYdD�ޛ›_jW} ч;H419~@wo쁷w�n7c£UV !9N/!kD6l =g1qai[>{0zpDQI xD:G%\ z@л]eimowhkY|[+.?z4~ZTNLܷVjXI'vYiB;з�M O>n.`i`,81 :FO8HX;0)T-# ͅD2�>B~W)0q$6ۺ7\}w'>UYRVeDy+LU.%.N|C;]PAq< Hc|`muiz %FiP!V{y[lBsǒFki5CplS1ciцeִ'mP)B-}Z*״nIGC {M4^|Հ-V"q|݀-jA9)v:S`BLX4aHn!j`,v,DU/_6Mګ9,BL&=G<C;Gv ,5w\JP䵒nY%N_w4RY"TȎjxEBr"&[C~~P 3Ώ'^7q�U{C W2@ߒnkflf3YUJ,mf 'iK)ߠZ$-Zx_Y3"?۽}$:UdDʦTf˨;ޟkI" I,?#Ra .~UoF=xKWBjgݰ</p/.ͧ}m_`1'+BzZ[s%2as,)dFdhU(xZ˒K X?2U2ʫ3WnaZC_ט]?13ܞ ۥ\lr=B8G!uh֤ۜO yY7$oSP4 "dXJEJ*jYfz$O}qJO1E1G <vʬ*l~AS2Z8kG#8ԠoXd9ez 6MM>72ӹ~ziNn> sڮ7KնiQK÷A^blvmsVQd%`P@&fDo{71'K-Ԥ^2Cp.yzf߁; RXNdKsn#u BץK=lp}Y3Pu\ aq!lH Һ"Zv)o9 xZSehK|(u{xqu-*z M7nqb]@oxf:bG]nxw겹jjJWk9yFYa~gjt.~"z+VݦoZ,XNzͲPK?�����BdSBy!Q�����$������� �������tfce_clustering.pas � ��������NO QnTJ^ PK������e��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/dice.ico�������������������������������������������������0000755�0001750�0001750�00000001376�07522725654�017607� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ��������(��� ���@�����������������������������������������������������������������������3wywwywwwwww������������������������wwww������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npm.ini��������������������������������������������������0000755�0001750�0001750�00000000173�12156142626�017463� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[BOOL] computettest=1 computebm=0 countlesionpatterns=1 ROI=1 [INT] CacheMB=512 nPermute=4000 nThread=2 TFCE=0 �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/spread.pas�����������������������������������������������0000755�0001750�0001750�00000102320�12147213330�020137� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit spread; interface {$H+} uses {$IFNDEF FPC} //Utils, Toolwin,shlobj,Spin,ShellApi,windows,messages, {$ELSE} LResources, {$ENDIF} SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Grids, Menus, ComCtrls, Buttons,Clipbrd,design, StdCtrls,Registry, define_types,valformat; type { TSpreadForm } TSpreadForm = class(TForm) DataGrid: TStringGrid; MainMenu1: TMainMenu; File1: TMenuItem; //DescriptiveMenu: TMenuItem; New1: TMenuItem; Open1: TMenuItem; Design1:TMenuItem; Quit1: TMenuItem; ToolBar1: TToolBar; Help1: TMenuItem; Aboutthissoftware1: TMenuItem; StatusBar1: TStatusBar; Save1: TMenuItem; Edit1: TMenuItem; Copy1: TMenuItem; Paste1: TMenuItem; OpenDialog1: TOpenDialog; SaveDialog1: TSaveDialog; Selectall1: TMenuItem; View: TMenuItem; Font1: TMenuItem; N81: TMenuItem; N101: TMenuItem; N121: TMenuItem; N141: TMenuItem; DesignBtn: TSpeedButton; Clearallcells1: TMenuItem; DescriptiveMenu: TMenuItem; procedure UpdateLabels; function GetVal (lC,lR: integer; var lVal: double): boolean; procedure Quit1Click(Sender: TObject); procedure FormResize(Sender: TObject); procedure Aboutthissoftware1Click(Sender: TObject); procedure OpenBtnClick(Sender: TObject); procedure DataGridSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); procedure NewBtnClick(Sender: TObject); procedure Save1Click(var NoCancel: boolean); procedure FormCreate(Sender: TObject); procedure DataGridMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure OpenTextFile (var lFilename:string); function CheckSave2Close (lAllowCancel: boolean): boolean; procedure DataGridKeyPress(Sender: TObject; var Key: Char); procedure Copy1Click(Sender: TObject); procedure Paste1Click(Sender: TObject); procedure SaveBtnClick(Sender: TObject); procedure ShowStatus; procedure ReadCells2Buffer; procedure Selectall1Click(Sender: TObject); procedure FontSizeChange(Sender: TObject); procedure DataGridMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure DataGridDrawCell(Sender: TObject; Col, Row: Integer; Rect: TRect; State: TGridDrawState); procedure Clearallcells1Click(Sender: TObject); procedure DesignBtnClick(Sender: TObject); procedure AddMRIScansClick(Sender: TObject); procedure DescriptiveClick(Sender: TObject); function SOpenDialogExecute (lCaption: string;lAllowMultiSelect,lForceMultiSelect: boolean; lFilter: string): boolean; {$IFNDEF FPC} procedure FormClose(Sender: TObject; var Action: TCloseAction); {$ELSE} procedure FormClose(Sender: TObject); //procedure SpeedButton3Click(Sender: TObject); {$ENDIF} private //procedure WMDropFiles(var Msg: TWMDropFiles); message WM_DROPFILES; { Private declarations } public { Public declarations } end; var SpreadForm: TSpreadForm; const kRegressSWName = 'VAL'; kRegressSWVers = kRegressSWName+' v1.0'; kMaxFactors = 1; gVALChanges: boolean = false; gDesignUnspecified : boolean = true; gEnterCell : boolean= false; gVALFontSize: integer = 8; kMagicDouble : double = -111666222; //kVALNativeSignature = 'abba'; //kTxtExt = '.txt'; //kVALNativeExt = '.val'; implementation uses statcr,hdr; {$IFNDEF FPC} {$R *.DFM} {$ENDIF} function TSpreadForm.SOpenDialogExecute (lCaption: string;lAllowMultiSelect,lForceMultiSelect: boolean; lFilter: string): boolean;//; lAllowMultiSelect: boolean): boolean; var lNumberofFiles: integer; begin OpenDialog1.Filter := lFilter;//kAnaHdrFilter;//lFilter; OpenDialog1.FilterIndex := 1; OpenDialog1.Title := lCaption; if lAllowMultiSelect then OpenDialog1.Options := [ofAllowMultiSelect,ofFileMustExist] else OpenDialog1.Options := [ofFileMustExist]; result := OpenDialog1.Execute; if not result then exit; if lForceMultiSelect then begin lNumberofFiles:= OpenDialog1.Files.Count; if lNumberofFiles < 2 then begin Showmessage('Error: This function is designed to overlay MULTIPLE images. You selected less than two images.'); result := false; end; end; end; (*procedure TSpreadForm.WMDropFiles(var Msg: TWMDropFiles); var lStr: string; CFileName: array[0..MAX_PATH] of Char; begin try if DragQueryFile(Msg.Drop, 0, CFileName, MAX_PATH) > 0 then //requires ShellAPI in 'uses' clause begin if gChanges then begin if not CheckSave2Close(true) then exit; end; lStr := CFilename; OpenTextFile(lStr); OpenDialog1.FileName := lStr; Msg.Result := 0; end; finally DragFinish(Msg.Drop); end; end; *) procedure TSpreadForm.Quit1Click(Sender: TObject); begin if not CheckSave2Close(true) then exit; gVALChanges := false; SpreadForm.Close; end; procedure TSpreadForm.FormResize(Sender: TObject); var lClient,lWid,lCount: integer; begin lCount := DataGrid.ColCount; lClient := DataGrid.ClientWidth; if lCount < 1 then begin DataGrid.ColWidths[0] := lClient; exit; end; lWid := ((lClient) div lCount); DataGrid.DefaultColWidth := lWid-1; (*if lWid <> lCol1Wid then begin lCol1Wid := (lClient-((lCount) * lWid))-lCount{-14}; lGrid.ColWidths[0] := lCol1Wid; end;*) end; function ColLabel (lCol: integer): string; //first column= A, 26th=Z,27th AA, etc... var lColDiv,lColMod: integer; begin result := ''; lColDiv := lCol; repeat lColMod := lColDiv mod 26; if lColMod = 0 then lColMod := 26; result := chr(ord('A')+lColMod-1)+result; {if lColDiv = 26 then lColDiv := 0 else} lColDiv := (lColDiv-1) div 26; until lColDiv <= 0; end; procedure UpdateGridLabels(lGrid: TStringGrid); var lA,lInc,lInc2: integer; begin if lGrid.RowCount < 2 then exit; //for lInc := (lGrid.RowCount -1) downto 1 do // lGrid.Cells[0,kMaxFactors+lInc] := inttostr(lInc); if (lGrid.ColCount) < 1 then exit; //Next enter ANOVA labels for each row for lInc := (lGrid.ColCount-1 {-1 for Lazarus 999}) downto 0 do for lInc2 := 0 to kMaxFactors do lGrid.Cells[lInc,lInc2] := ''; lA := DesignForm.AVal.value; //999 showmessage(inttostr(lGrid.RowCount)+'x'+inttostr(lGrid.ColCount)+'alpha'+inttostr(lA)); //lGrid.Cells[0,0] := ''; for lInc := 1 to lA do lGrid.Cells[lInc,0] := DesignForm.ALevelNames.Cells[lInc-1,0]; {$IFDEF FPC} for lInc := (lGrid.ColCount -2) downto 0 do lGrid.Cells[lInc +1 ,kMaxFactors] := ColLabel(lInc+1); {$ELSE} for lInc := (lGrid.ColCount -1) downto 0 do lGrid.Cells[lInc+1,kMaxFactors] := ColLabel(lInc+1);//chr(ord('A')+lInc); {$ENDIF} end; procedure TSpreadForm.UpdateLabels; begin DataGrid.ColCount := DesignForm.AVal.value+1; //2007 For FPC UpdateGridLabels(DataGrid); DataGrid.ColCount := DesignForm.AVal.value+1; end; procedure TSpreadForm.Aboutthissoftware1Click(Sender: TObject); begin Showmessage(kRegressSWVers); // AboutForm.Showmodal; end; procedure ClearDesignMatrix; begin gDesignUnspecified := true; SpreadForm.DesignBtn.Caption := 'Design: not specified'; end; procedure DesignBtnLabelUpdate; begin SpreadForm.DesignBtn.Caption := 'Design IVs: '+inttostr(DesignForm.AVal.Value) ; SpreadForm.UpdateLabels; SpreadForm.FormResize(nil); end; {$ifdef fpc} function alignx(addr : Pointer;alignment : PtrUInt) : Pointer; begin result:=align(addr,alignment); end; {$endif} procedure TSpreadForm.OpenTextFile (var lFilename:string); var lTemplateName:string; lnCritPct,lnRow,lnCol,lnColWObs,lCol,lRow: integer; //lLesionCovary : boolean; lPredictorList,lFileList:TStringList; lDoublePtr: Pointer; lDoubleBuf : DoubleP; begin Self.Caption := kRegressSWVers+': '+extractfilename(lFilename); ClearDesignMatrix; lPredictorList := TStringList.Create; lFileList := TStringList.Create; gVALChanges := false; OpenValFile (lFilename,lTemplateName, lnRow,lnCol,lnColWObs,lnCritPct,gDesignUnspecified,lPredictorList,lFileList,lDoublePtr); {$IFDEF FPC} DataGrid.RowCount := kMaxFactors+lnRow{-1}; {$ELSE} DataGrid.RowCount := kMaxFactors+lnRow; {$ENDIF} DataGrid.ColCount := lnCol+1; DataGrid.refresh; {$IFDEF FPC} lDoubleBuf := alignx(lDoublePtr, 16); // note: lDoubleBuf > lDoublePtr always (VSDS); {$ELSE} lDoubleBuf := DoubleP($fffffff0 and (integer(lDoublePtr)+15)); {$ENDIF} if lFileList.Count < lnRow then lnRow := lFileList.Count; for lRow := 1 to lnRow do begin DataGrid.Cells[ 0, kMaxFactors+lRow ] := lFileList.Strings[lRow-1]; for lCol := 1 to lnCol do begin if lDoubleBuf^[RowColPos (lRow,lCol,lnColWObs)] = kMagicDouble then DataGrid.Cells[ lCol, kMaxFactors+lRow ] := '' else DataGrid.Cells[ lCol, kMaxFactors+lRow ] := floattostr((lDoubleBuf^[RowColPos (lRow,lCol,lnColWObs)])); end; end; if lPredictorList.Count < lnRow then for lCol := (lPredictorList.Count+1) to lnRow do lPredictorList.Add( 'Pred'+inttostr(lCol) ); DesignForm.ALevelNames.ColCount := lnCol; for lCol := 1 to lnCol do DesignForm.ALevelNames.Cells[lCol-1,0] := lPredictorList.Strings[lCol-1]; Freemem(lDoublePtr); lPredictorList.Free; lFileList.free; //DesignForm.LesionCovaryCheck.Checked := lLesionCovary; DesignForm.CritPctEdit.value := lnCritPct; DesignForm.TemplateLabel.Caption := lTemplateName; //Tidy Up... DesignForm.AVal.Value := lnCol; UpdateLabels; DesignBtnLabelUpdate; FormResize(nil); if gDesignUnspecified then Showmessage('You need to define the experiment design [press the ''Design'' button]'); end; procedure TSpreadForm.OpenBtnClick(Sender: TObject); var lFileName: string; begin if gVALChanges then begin if not CheckSave2Close(true) then exit; end; if not SOpenDialogExecute('Select VAL design file',false,false, kValFilter) then exit; lFilename := OpenDialog1.filename; if not fileexists(lFilename) then exit; OpenTextFile(lFilename); end; procedure GridToStatusBar(lGrid: TStringGrid; lStatus: TStatusBar); begin {$IFDEF FPC} //SpreadForm.StatusBar1.Panels[1].Text := inttostr(random(888)); if (lGrid.Selection.Top <= kMaxFactors) or (lGrid.Selection.Left <= 0) then begin lGrid.Selection:=TGridRect(Rect(-1,-1,-1,-1)); SpreadForm.Caption := ''; exit; end; if lGrid.Selection.Top < 0 then exit; if((lGrid.Selection.Top = lGrid.Selection.Bottom ) and ( lGrid.Selection.Left = lGrid.Selection.Right )) then begin SpreadForm.Caption := lGrid.Cells[0,lGrid.Selection.Top]+' = '+lGrid.Cells[lGrid.Selection.Left,lGrid.Selection.Top]+' '+ lGrid.Cells[lGrid.Selection.Left,0]+' '+ lGrid.Cells[lGrid.Selection.Left,1]+inttostr(lGrid.Selection.Top-kMaxFactors); end else begin SpreadForm.Caption := inttostr(lGrid.Selection.Bottom-lGrid.Selection.Top + 1)+'R x '+ inttostr(lGrid.Selection.Right-lGrid.Selection.Left + 1)+'C'; end; (*if((lGrid.Selection.Top <> lGrid.Selection.Bottom ) or ( lGrid.Selection.Left <> lGrid.Selection.Right )) then exit; if (lGrid.Selection.Top <= kMaxFactors) or (lGrid.Selection.Left <= 0) then begin lGrid.Selection:=TGridRect(Rect(-1,-1,-1,-1)); lStatus.Panels[0].Text := ''; exit; end; if (lGrid.Selection.Top < 0) then exit; //lStatus.Panels[1].Text := inttostr(lGrid.Selection.Bottom-lGrid.Selection.Top + 1)+'R x '+ inttostr(lGrid.Selection.Right-lGrid.Selection.Left + 1)+'C'; //lStatus.Panels[1].Text := inttostr(lGrid.Selection.Top)+'R x '+ inttostr(lGrid.Selection.Bottom)+'C'; SpreadForm.Caption := inttostr(lGrid.Selection.Top)+'R x '+ inttostr(lGrid.Selection.Left)+'C'; exit; if((lGrid.Selection.Top = lGrid.Selection.Bottom ) and ( lGrid.Selection.Left = lGrid.Selection.Right )) then begin lStatus.Panels[1].Text := {ColLabel(lGrid.Selection.Left)+}lGrid.Cells[0,lGrid.Selection.Top]{inttostr(lGrid.Selection.Top-kMaxFactors)}+' = '+lGrid.Cells[lGrid.Selection.Left,lGrid.Selection.Top]; // lStatus.Panels[0].Text := lGrid.Cells[lGrid.Selection.Left,0]+' '+ lGrid.Cells[lGrid.Selection.Left,1]+' '+lGrid.Cells[lGrid.Selection.Left,2]; // lStatus.Panels[0].Text := lGrid.Cells[lGrid.Selection.Left,0]+' '+ lGrid.Cells[lGrid.Selection.Left,1]+inttostr(lGrid.Selection.Top-kMaxFactors); //lStatus.Panels[0].Text := lGrid.Cells[lGrid.Selection.Left,0]+' '+ lGrid.Cells[lGrid.Selection.Left,1]+inttostr(lGrid.Selection.Top-kMaxFactors); end else begin lStatus.Panels[0].Text := inttostr(lGrid.Selection.Bottom-lGrid.Selection.Top + 1)+'R x '+ inttostr(lGrid.Selection.Right-lGrid.Selection.Left + 1)+'C'; lStatus.Panels[1].Text := ''; end; *) {$ELSE} //Delphi if (lGrid.Selection.Top <= kMaxFactors) or (lGrid.Selection.Left <= 0) then begin lGrid.Selection:=TGridRect(Rect(-1,-1,-1,-1)); lStatus.Panels[0].Text := ''; exit; end; if lGrid.Selection.Top < 0 then exit; if((lGrid.Selection.Top = lGrid.Selection.Bottom ) and ( lGrid.Selection.Left = lGrid.Selection.Right )) then begin lStatus.Panels[1].Text := lGrid.Cells[0,lGrid.Selection.Top]+' = '+lGrid.Cells[lGrid.Selection.Left,lGrid.Selection.Top]; lStatus.Panels[0].Text := lGrid.Cells[lGrid.Selection.Left,0]+' '+ lGrid.Cells[lGrid.Selection.Left,1]+inttostr(lGrid.Selection.Top-kMaxFactors); end else begin lStatus.Panels[0].Text := inttostr(lGrid.Selection.Bottom-lGrid.Selection.Top + 1)+'R x '+ inttostr(lGrid.Selection.Right-lGrid.Selection.Left + 1)+'C'; lStatus.Panels[1].Text := ''; end; {$ENDIF} end; procedure TSpreadForm.ShowStatus; begin //SpreadForm.Caption := inttostr(random(888)); GridToStatusBar(DataGrid,StatusBar1); end; procedure TSpreadForm.DataGridSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); begin //ShowStatus; //bxxx gEnterCell := true; end; procedure TSpreadForm.NewBtnClick(Sender: TObject); begin DesignForm.Showmodal; gDesignUnspecified := false; DesignBtnLabelUpdate; end; function RemoveColons( lStr: string): string; var lLen,lPos: integer; begin result := lStr; lLen := length(lStr); if lLen < 1 then exit; for lPos := 1 to lLen do if result[lPos] = ':' then result[lPos] := ';'; end; function Str2Float (var lStr: string; var lError: boolean): single; begin lError := false; try result := Strtofloat(lStr); except on EConvertError do lError := true; end; //except end; procedure TSpreadForm.Save1Click(var NoCancel: boolean); const kNative = 1; kTxt = 2; var f: TextFile; lFormat,C, R,lLen,lPos,ColStart,ColEnd,RowStart,RowEnd : integer ; lLevelStr,lFilename,S,lCell,lExt : string ; kSpacer,lDecimalSep : char; lError: boolean; begin NoCancel := false; if not SaveDialog1.Execute then exit; lFormat := SaveDialog1.FilterIndex; if (lFormat < kNative) or (lFormat > kTxt) then lFormat := kNative; case lFormat of kTxt: lExt := kTXText; else lExt := kValNativeExt; end; if lFormat <> kNative then begin case MessageDlg( 'Export file as a text format? Note you will lose information about the experiment design [save to Native format to preserve condition information]', mtWarning, [mbYes, mbCancel], 0 ) of mrCancel : exit ; end ; end; //not native if (lFormat = kNative) and (gDesignUnspecified) then begin showmessage('Unable to save this data as '+kRegressSWVers+' format file until you have specified the conditions [press the ''Design'' button]'); exit; end; //lExt := StrUpper(PChar(extractfileext(SaveDialog1.Filename))); lFilename := SaveDialog1.Filename; lDecimalSep := DecimalSeparator; DecimalSeparator := '.'; ChangeFileExt(lFilename,lExt); // Setup... kSpacer := #9; //tab S := '' ; RowStart := kMaxFactors+1 ; RowEnd := DataGrid.RowCount - 1; ColStart := 0 ; ColEnd := DataGrid.ColCount - 1; if (ColEnd < ColStart) or (RowEnd < RowStart) then exit; // Copy to string for R := RowStart to RowEnd do begin for C := ColStart to ColEnd do begin lCell := DataGrid.Cells[ C, R ]; if C <> ColStart then begin if lCell = '' then //this simply prevents error reports when run from debugger lError := true else Str2Float (lCell, lError); if (lError) then lCell := '-'; end; S := S + lCell; if( C < DataGrid.ColCount - 1 ) then S := S + kSpacer{#9} ; // Tab end ; if R <> (DataGrid.RowCount - 1) then //all except last line S := S + #13#10 ; // End line end ; AssignFile(f, lFileName); rewrite(f); if lFormat = kNative then begin Self.Caption := kRegressSWVers+': '+extractfilename(SaveDialog1.Filename);//remove any previous filename if Files4D(DataGrid.Cells[ ColStart, RowStart ]) then writeln(f,kVALNativeSignatureBase + '1')//version 1 supports 4D images else writeln(f,kVALNativeSignatureBase + '0');//version 0 supports 3D images only //Details for 1st factor //writeln(f,'#Predictors:'+inttostr(lLen)+lLevelStr+lWithinSubjStr); writeln(f,'#Covary Volume'+kSpacer+bool2char(DesignForm.LesionCovaryCheck.Checked)); writeln(f,'#Template'+kSpacer+DesignForm.TemplateLabel.Caption); writeln(f,'#CritPct'+kSpacer+inttostr(DesignForm.CritPctEdit.value)); lLevelStr := 'ImageName'; lLen := DesignForm.AVal.value; if lLen >= 1 then for lPos := 1 to lLen do lLevelStr := lLevelStr+kTab+(DesignForm.ALevelNames.Cells[lPos-1,0]); writeln(f,lLevelStr); gVALChanges := false; end; Writeln(f, S); Flush(f); { ensures that the text was actually written to file } CloseFile(f); NoCancel := true; DecimalSeparator :=lDecimalSep; end; procedure registerfiletype(inft,inkey,desc,icon:string); var myreg : treginifile; ct : integer; ft,key: string; begin ft := inft; key := inkey; ct := pos('.',ft); while ct > 0 do begin delete(ft,ct,1); ct := pos('.',ft); end; if (ft = '') or (Application.ExeName = '') then exit; //not a valid file-ext or ass. app ft := '.'+ft; myreg := treginifile.create(''); try myreg.rootkey := hkey_classes_root; // where all file-types are described if key = '' then key := copy(ft,2,maxint)+'_auto_file'; // if no key-name is given, create one myreg.writestring(ft,'',key); // set a pointer to the description-key myreg.writestring(key,'',desc); // write the description myreg.writestring(key+'\DefaultIcon','',icon); // write the def-icon if given myreg.writestring(key+'\shell\open\command','',Application.ExeName+' %1'); //association finally myreg.free; end; end; procedure TSpreadForm.FormCreate(Sender: TObject); begin SpreadForm.Caption := kRegressSWName; (* registerfiletype(kNativeExt,kRegressSWName{key},kRegressSWName,Application.ExeName+',1'); DragAcceptFiles(Handle, True); *) DataGrid.Selection:=TGridRect(Rect(-1,-1,-1,-1)); gVALFontSize := 8; //DecSeparator := DecimalSeparator; //l64rBufP := nil; gEnterCell := false; gVALChanges := false; DataGrid.ColCount := 9; DataGrid.RowCount := 15; FormResize(nil); {$IFDEF Darwin} {$IFNDEF LCLgtk} //only for Carbon compile New1.ShortCut := ShortCut(Word('N'), [ssMeta]); Open1.ShortCut := ShortCut(Word('O'), [ssMeta]); Save1.ShortCut := ShortCut(Word('S'), [ssMeta]); Quit1.ShortCut := ShortCut(Word('W'), [ssMeta]); Copy1.ShortCut := ShortCut(Word('C'), [ssMeta]); Paste1.ShortCut := ShortCut(Word('V'), [ssMeta]); Selectall1.ShortCut := ShortCut(Word('A'), [ssMeta]); DescriptiveMenu.ShortCut := ShortCut(Word('L'), [ssMeta]); {$ENDIF}//Carbon {$ENDIF}//Darwin end; procedure TSpreadForm.DataGridMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var C, R : integer ; Rect : TGridRect ; begin DataGrid.MouseToCell( X, Y, C, R ) ; Rect.Left := C ; Rect.Right := C ; Rect.Top := R ; Rect.Bottom := R ; DataGrid.Selection := Rect ; end; procedure TSpreadForm.DataGridKeyPress(Sender: TObject; var Key: Char); var S : string ; begin if (Key in ['0'..'9','.',kBS,kDel,kCR]) or ((Key='-') and (gEnterCell)) then else exit; if(( DataGrid.Selection.Top = DataGrid.Selection.Bottom ) and ( DataGrid.Selection.Left = DataGrid.Selection.Right )) then begin gVALChanges := true; if gEnterCell then begin S := '' end else S := DataGrid.Cells[ DataGrid.Selection.Left,DataGrid.Selection.Top ] ; gEnterCell := false; if ( ( Key = kDEL ) or ( Key = kBS ) )then begin if( length( S ) > 0 ) then begin setlength( S, length( S ) - 1 ) ; end ; end else if ( Key = kCR ) then begin //Edit_Box.Text := S ; exit ; end else begin S := S + Key ; end ; DataGrid.Cells[ DataGrid.Selection.Left, DataGrid.Selection.Top ] := S ; //Format_Grid.Cells[ DataGrid.Selection.Left, DataGrid.Selection.Top ] := '' ; end ; end; procedure TSpreadForm.Copy1Click(Sender: TObject); var C, R : integer ; P: PChar; S : string ; RStart,CStart,REnd,CEnd : integer ; begin // Setup... S := '' ; if (DataGrid.Selection.Left < 0) or (DataGrid.Selection.Top < 0) then begin DataGrid.Selection:= TGridRect(Rect(1,1+kMaxFactors,DataGrid.ColCount-1,DataGrid.RowCount-1)); end; CStart := DataGrid.Selection.Left; CEnd := DataGrid.Selection.Right; RStart := DataGrid.Selection.Top; REnd := DataGrid.Selection.Bottom; // Copy to string for R := RStart to REnd do begin for C := CStart to CEnd do begin S := S + DataGrid.Cells[ C, R ] ; if( C < CEnd ) then begin S := S + #9 ; // Tab end ; end ; S := S + #13#10 ; // End line end ; // Set clipboard {$IFNDEF FPC} Clipboard.SetTextBuf( PChar( S ) ) ; {$ELSE} p:=StrAlloc (length(S)+1); if StrPCopy (P,S)=P then Clipboard.SetTextBuf(P); {$ENDIF} end; procedure TSpreadForm.Paste1Click(Sender: TObject); const BS = #8 ; { Backspace } CR = #13 ; { Carriage return } DEL = #127 ; { Delete } //HT = #9 ; { Horizontal Tab } //LF = #10 ; { Line Feed } //VT = #11 ; { Vertical Tab } var StartC,C, R,I : integer ; Dummy : integer ; lSciNotation,EOF: boolean; lValue: double; DecSeparator : char; Line, S, Work,WorkFilter : string ; begin // Setup... DecSeparator := DecimalSeparator; S := Clipboard.AsText ; EOF:= false; if (DataGrid.Selection.Left < 0) or (DataGrid.Selection.Top < 0) then begin Selectall1Click(nil); end; //gChanges := true; StartC := DataGrid.Selection.Left; R := DataGrid.Selection.Top; C := StartC; while( length( S ) > 0 ) do begin // Extract next line... {$IFDEF UNIX} Dummy := pos( #13, S + #13 ) ; {$ELSE} Dummy := pos( #13#10, S + #13#10 ) ; {$ENDIF} Line := copy( S, 1, Dummy - 1 ) ; if (Dummy+1) < length(S) then //last line may not have eol S := copy( S, Dummy + 1, length( S ) ) else EOF := true; while( length( Line ) > 0 ) do begin // Extract next cell... lSciNotation := false; Dummy := pos( #9, Line + #9 ) ; Work := copy( Line, 1, Dummy - 1 ) ; Line := copy( Line, Dummy + 1, length( S ) ) ; WorkFilter := ''; if length(Work) > 0 then begin for I := length(Work) downto 1 do begin if (Work[i] in ['-','0'..'9','E','e',DecSeparator,BS,DEL,CR]) then WorkFilter := Work[i]+WorkFilter; if (Work[i] in ['E','e']) then lSciNotation := true; end; end; if lSciNotation then begin try lValue := strtofloat(Workfilter); except on EConvertError do lValue := NaN else lValue := NaN; end; //try..except if lValue <> NaN then DataGrid.Cells[ C, R ] :=(floattostr(lValue)); end else if(length(WorkFilter) > 0) and ( C < DataGrid.ColCount ) then begin DataGrid.Cells[ C, R ] := WorkFilter ; //Format_Grid.Cells[ C, R ] := '' ; end ; inc( C ) ; end ; inc( R ) ; // Move to next row if( R >= DataGrid.RowCount ) or (EOF) then begin break ; // All done with paste end ; C := StartC; end ; // While length(S) > 0 end; //proc Paste1Click (*var StartC,C, R,I : integer ; Dummy : integer ; lSciNotation,EOF,lData: boolean; lValue: double; Line, S, Work,WorkFilter : string ; begin // Setup... lValue := 0; //only to prevent compiler warning... S := Clipboard.AsText ; EOF:= false; if (DataGrid.Selection.Left < 0) or (DataGrid.Selection.Top < 0) then begin Selectall1Click(nil); end; //R := 1 ; //StartC := 1 ; StartC := DataGrid.Selection.Left; //CEnd := DataGrid.Selection.Right; R := DataGrid.Selection.Top; //REnd := DataGrid.Selection.Bottom; // Do the paste C := StartC; while( length( S ) > 0 ) do begin // Extract next line... Dummy := pos( #13#10, S + #13#10 ) ; Line := copy( S, 1, Dummy - 1 ) ; if (Dummy+1) < length(S) then //last line may not have eol S := copy( S, Dummy + 1, length( S ) ) else EOF := true; //showmessage(inttostr(C)+'x'+Line); while( length( Line ) > 0 ) do begin // Extract next cell... lSciNotation := false; //old //Dummy := pos( #9, Line + #9 ) ; //new - comma separated, etc lData := false; Dummy := length(line)+1; I := 1; repeat if (Line[i] in ['-','0'..'9','E','e']) then lData := true else begin if lData then Dummy := I; end; inc(I); until (I > length(Line)) or (Dummy = (I-1)); //end new Work := copy( Line, 1, Dummy - 1 ); //showmessage(inttostr(Dummy)+'x'+Work); Line := copy( Line, Dummy + 1, length( S ) ) ; //showmessage(Line); WorkFilter := ''; if length(Work) > 0 then begin for I := length(Work) downto 1 do begin if (Work[i] in ['-','0'..'9','E','e','.',kBS,kDEL,kCR]) then WorkFilter := Work[i]+WorkFilter; if (Work[i] in ['E','e']) then lSciNotation := true; end; end; if lSciNotation then begin try lValue := strtofloat(Workfilter); except on EConvertError do lValue := NaN; end; //try..except if lValue <> NaN then DataGrid.Cells[ C, R ] :=(floattostr(lValue)); end else if(length(WorkFilter) > 0) and ( C < DataGrid.ColCount ) then begin DataGrid.Cells[ C, R ] := WorkFilter ; //Format_Grid.Cells[ C, R ] := '' ; end ; inc( C ) ; end ; inc( R ) ; // Move to next row if( R >= DataGrid.RowCount ) or (EOF) then begin break ; // All done with paste end ; //Showmessage(inttostr(StartC)); C := StartC; end ; // TMainForm.Paste1Click end; *) procedure TSpreadForm.SaveBtnClick(Sender: TObject); var b: boolean; begin Save1Click(b); end; function TSpreadForm.CheckSave2Close (lAllowCancel: boolean): boolean; begin result := true; if not gVALChanges then exit; result := false; if lAllowCancel then begin case MessageDlg( 'Save changes?', mtWarning, [mbYes, mbNo, mbCancel], 0 ) of mrYes : begin Save1Click( result ) ; end ; mrCancel : exit ; end ; end else case MessageDlg( 'Save changes?', mtWarning, [mbYes, mbNo], 0 ) of mrYes : begin Save1Click( result ) ; end ; end; result := true; end; procedure TSpreadForm.ReadCells2Buffer; var lDbl: double; lRend,lRStart,lCStart,lCEnd,lC,lR,lPos: integer; lStr: string; l64rBufP: pointer; l64rBuf: DoubleP; begin //if l64rBufP <> nil then // freemem(l64rBufP); GetMem(l64rBufP,(DataGrid.ColCount*DataGrid.RowCount*sizeof(double))+16); {$IFDEF FPC} l64rBuf := alignx(l64rBufP, 16); {$ELSE} l64rBuf := DoubleP((integer(l64rBufP) and $FFFFFFF0)+16); {$ENDIF} lRStart := {1}kMaxFactors+1; lREnd := DataGrid.RowCount - 1; lCstart := 1; lCend := DataGrid.ColCount - 1; //gnCol := lCEnd; //gnRow := lREnd-lRStart+1; // Copy to string lPos := 0; for lR := lRStart to lREnd do begin for lC := lCStart to lCEnd do begin inc(lPos); lStr := (DataGrid.Cells[ lC, lR ]); lDbl := NaN; if length(lStr) > 0 then begin try lDbl := Strtofloat(lStr); except on EConvertError do begin showmessage('Cell '+ColLabel(lC)+inttostr(lR-kMaxFactors)+ ': Unable to convert the string '+lStr+' to a number'); DataGrid.Cells[ lC, lR ] := ''; lDbl := NaN; //NAN? Not-A-Number end; //Error end; //except end; //length > 0 l64rBuf^[lPos] :=lDbl; end ; //for each col end ; //for each row freemem(l64rBufP); end; procedure TSpreadForm.Selectall1Click(Sender: TObject); begin DataGrid.Selection:= TGridRect(Rect(1,1+kMaxFactors,DataGrid.ColCount-1,DataGrid.RowCount-1)); end; procedure TSpreadForm.FontSizeChange(Sender: TObject); begin (sender as TMenuItem).Checked := true; gVALFontSize := (sender as TMenuItem).tag; DataGrid.Font.Size := (sender as TMenuItem).tag; DataGrid.DefaultRowHeight := (sender as TMenuItem).tag+12; FormResize(nil); end; procedure TSpreadForm.DataGridMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin ShowStatus; end; procedure TSpreadForm.DataGridDrawCell(Sender: TObject; Col, Row: Integer; Rect: TRect; State: TGridDrawState); begin ShowStatus; end; procedure TSpreadForm.Clearallcells1Click(Sender: TObject); var lR,lC,lRi,lCi: integer; begin lR := DataGrid.RowCount-1; lC := DataGrid.ColCount-1; for lRi := 1 to lR do begin for lCi := 1 to lC do begin DataGrid.Cells[lCi,kMaxFactors+lRi] := ''; end;//for cols end;//for rows end; procedure TSpreadForm.DesignBtnClick(Sender: TObject); begin DesignForm.Showmodal; gDesignUnspecified := false; DesignBtnLabelUpdate; end; procedure TSpreadForm.AddMRIScansClick(Sender: TObject); begin DesignForm.AddMRIBtnClick(nil); end; function TSpreadForm.GetVal (lC,lR: integer; var lVal: double): boolean; var lStr: string; lDbl: double; begin result := false; lVal := 0; lStr := (DataGrid.Cells[ lC, lR ]); if lStr = '' then exit; try lDbl := Strtofloat(lStr); except on EConvertError do begin showmessage('Cell '+ColLabel(lC)+inttostr(lR-kMaxFactors)+ ': Unable to convert the string '+lStr+' to a number'); exit; end; end; //try..except lVal := lDbl; result := true; end;//GetVal procedure TSpreadForm.DescriptiveClick(Sender: TObject); var lMn,lSD,lSE,lSkew,lZSkew: double; n,lR,lC,lRi,lCi: integer; lVal: double; RA: SingleP; begin lR := DataGrid.RowCount-1; if (lR <= kMaxFactors+1) then exit; lC := DataGrid.ColCount-1; Getmem(RA,lR * sizeof(single)); for lCi := 1 to lC do begin n := 0; for lRi := (kMaxFactors+1) to lR do begin if GetVal (lCi,lRi,lVal) then begin inc(n); RA^[n] := lVal; end; end;//for rows if n > 0 then begin SuperDescriptive (RA, n, lMn,lSD,lSE,lSkew,lZSkew); Showmessage('"'+DataGrid.Cells[ lC, 0]+'" mean='+floattostr(lMn)+',StDev='+floattostr(lSD)+',StEr='+floattostr(lSE)+',Skew='+floattostr(lSkew)+',ZSkew='+floattostr(lZSkew)); end; //n > 0 end;//for cols Freemem(RA); end; {$IFNDEF FPC} procedure TSpreadForm.FormClose(Sender: TObject; var Action: TCloseAction); {$ELSE} procedure TSpreadForm.FormClose(Sender: TObject); {$ENDIF} begin CheckSave2Close(false); end; {$IFDEF FPC} initialization {$I spread.lrs} {$ENDIF} end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/fpc-res.res����������������������������������������������0000755�0001750�0001750�00000001764�11316122230�020233� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ �����������������������<���L����L�A�Z�_�P�I�C�_�D�I�A�L�O�G�_�T�E�M�P�L�A�T�E�������0�����������T���������,���������P����������_S�T�A�T�I�C��������� ��������� ��������(��� ���@�����������������������������������������������������������������������3wywwywwwwww������������������������wwww���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������0����M�A�I�N�I�C�O�N��������� ������������ ������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/nifti_img.pas��������������������������������������������0000755�0001750�0001750�00000045332�11477113344�020650� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit nifti_img; //only for Delphi - not Freepascal //Unit for running multiple regression interface uses define_types,Classes,nifti_hdr,sysutils,dialogs {$IFDEF FPC},gzio2 {$ELSE} ,gziod {$ENDIF} ; {$H+} function LoadImg(lInName: string; lImgData: SingleP; lStart, lEnd,linvox_offset,lRApos,lDataType,lVolVox: integer): boolean; function LoadImg8(lInName: string; lImgData: ByteP; lStart, lEnd,linvox_offset,lRApos,lDataType,lVolVox: integer): boolean; implementation uses npmform,hdr; function LoadImg(lInName: string; lImgData: SingleP; lStart, lEnd,linvox_offset,lRApos,lDataType,lVolVox: integer): boolean; var lvox_offset,lInc,lFSize,lP2: integer; lFData: file; lImgName: string; lByteP: ByteP; lSmallIntP: SmallIntP; lV,lMin,lMax: single; begin result := false; if (lStart >= lEnd) or (lStart < 1) or (lEnd < 1) then begin MainForm.NPMmsg('Error: LoadImg '+inttostr(lStart)+'>='+inttostr(lEnd)+' or zero'); exit; end; if Files4D(lInName) then begin lImgName := Filename4D(lInName); lP2 := BPP (lDataType); if lP2 = 0 then begin Showmessage(lImgName +' is an unsupported file type'); exit; end; lvox_offset := linvox_offset+ ((Vol4D(lInName)-1)* (lP2 * lVolVox)); end else begin lImgName := lInName; lvox_offset := linvox_offset; end; if UpCaseExt(lImgName) = '.HDR' then lImgName := changefileext(lImgName,'.img'); lFSize := FSize(lImgName); if (not GzExt(lImgName)) and (lFSize < (lEnd+ lvox_offset)) then begin MainForm.NPMmsg('Error: LoadImg '+lImgName+' FSize = '+inttostr(lFSize)+' Expected '+inttostr(lEnd+ lvox_offset)); exit; end; filemode := 0; if GzExt(lImgName) then begin if lDataType = kDT_UNSIGNED_CHAR then begin getmem(lByteP, (lEnd+1)-lStart); UnGZip(lImgName,lByteP,lvox_offset+lStart-1,(lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lByteP^[lInc]; freemem(lByteP); end else if (lDataType = kDT_SIGNED_SHORT) then begin //getmem(lSmallIntP, sizeof(smallint)* ((lEnd+1)-lStart)); getmem(lByteP, ((lEnd+1)-lStart)*sizeof(smallint)); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(smallint)),((lEnd+1)-lStart)*sizeof(smallint)); for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*2)+1 ; lImgData^[lRApos+lInc-1] := makesmallint(lByteP^[lP2],lByteP^[lP2+1]); end; freemem(lByteP); end else if (lDataType = kDT_SIGNED_INT) or (lDataType = kDT_FLOAT) then begin lByteP := ByteP(@lImgData^[lRApos]); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(single)),((lEnd+1)-lStart)*sizeof(single)); (*getmem(lByteP, ((lEnd+1)-lStart)*sizeof(single)); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(single)),((lEnd+1)-lStart)*sizeof(single)); for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*4)+1 ; lImgData^[lRApos+lInc-1] := makesingle(lByteP^[lP2],lByteP^[lP2+1],lByteP^[lP2+2],lByteP^[lP2+3]); //lImgData^[lRApos+lInc-1] := makesingle(lByteP^[lP2+3],lByteP^[lP2+2],lByteP^[lP2+1],lByteP^[lP2]); end; freemem(lByteP); *) //test range (*lINc := 1; lMin := lImgData^[lRApos+lInc-1]; lMax := lMin; for lInc := 1 to ((lEnd+1)-lStart) do begin lV := lImgData^[lRApos+lInc-1]; if lV > lMax then lMax := lV; if lV < lMin then lMin := lMax; end; MainForm.NPMmsg(inttostr(lvox_offset)+' '+realtostr(lMin,8)+' '+realtostr(lMax,8)); *) //end if lDataType = kDT_SIGNED_INT then begin for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := conv4r4i (lImgData^[lRApos+lInc-1]); end else begin for lInc := 1 to ((lEnd+1)-lStart) do if specialsingle(lImgData^[lRApos+lInc-1])then lImgData^[lRApos+lInc-1] := 0; end; end else begin showmessage(lImgName + ' is an unsupported compressed data type '+inttostr(lDataType)); exit; end; end else begin assignfile(lFdata,lImgName); if lDataType = kDT_UNSIGNED_CHAR then begin getmem(lByteP, (lEnd+1)-lStart); reset(lFdata,1); //12/2010 seek(lFdata,lvox_offset+lStart-1); BlockRead(lFdata, lByteP^, (lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lByteP^[lInc]; freemem(lByteP); end else if (lDataType = kDT_SIGNED_SHORT) then begin getmem(lSmallIntP, sizeof(smallint)* ((lEnd+1)-lStart)); reset(lFdata,2); if (lvox_offset mod 2) <> 0 then begin showmessage('Error: this software can only read headers with dataoffsets that are divisible by 4.'); end; seek(lFdata,(lvox_offset div 2)+ (lStart-1)); BlockRead(lFdata, lSmallIntP^, (lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lSmallIntP^[lInc]; freemem(lSmallIntP); end else if (lDataType = kDT_SIGNED_INT) or (lDataType = kDT_FLOAT) then begin //next: 4 byte data reset(lFdata,4); if (lvox_offset mod 4) <> 0 then begin showmessage('Error: this software can only read headers with dataoffsets that are divisible by 4.'); end; seek(lFdata,(lvox_offset div 4)+ (lStart-1) ); BlockRead(lFdata, lImgData[lRApos], (lEnd+1)-lStart); if lDataType = kDT_SIGNED_INT then begin for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := conv4r4i (lImgData^[lRApos+lInc-1]); end else begin for lInc := 1 to ((lEnd+1)-lStart) do if specialsingle(lImgData^[lRApos+lInc-1]) then lImgData^[lRApos+lInc-1] := 0; end; end else showmessage('Unsupported COMPRESSED data type '+inttostr(lDataType)); closefile(lFdata); end; //not gz result := true; end; (*function LoadImgx(lInName: string; lImgData: SingleP; lStart, lEnd,linvox_offset,lRApos,lDataType,lVolVox: integer): boolean; var lvox_offset,lInc,lFSize,lP2: integer; lFData: file; lImgName: string; lByteP: ByteP; lSmallIntP: SmallIntP; lV,lMin,lMax: single; begin result := false; if (lStart >= lEnd) or (lStart < 1) or (lEnd < 1) then begin MainForm.NPMmsg('Error: LoadImg '+inttostr(lStart)+'>='+inttostr(lEnd)+' or zero'); exit; end; if Files4D(lInName) then begin lImgName := Filename4D(lInName); lP2 := BPP (lDataType); if lP2 = 0 then begin Showmessage(lImgName +' is an unsupported file type'); exit; end; lvox_offset := linvox_offset+ ((Vol4D(lInName)-1)* (lP2 * lVolVox)); end else begin lImgName := lInName; lvox_offset := linvox_offset; end; if UpCaseExt(lImgName) = '.HDR' then lImgName := changefileext(lImgName,'.img'); lFSize := FSize(lImgName); if (not GzExt(lImgName)) and (lFSize < (lEnd+ lvox_offset)) then begin MainForm.NPMmsg('Error: LoadImg '+lImgName+' FSize = '+inttostr(lFSize)+' Expected '+inttostr(lEnd+ lvox_offset)); exit; end; filemode := 0; if GzExt(lImgName) then begin if lDataType = kDT_UNSIGNED_CHAR then begin getmem(lByteP, (lEnd+1)-lStart); UnGZip(lImgName,lByteP,lvox_offset+lStart-1,(lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lByteP^[lInc]; freemem(lByteP); end else if (lDataType = kDT_SIGNED_SHORT) then begin //getmem(lSmallIntP, sizeof(smallint)* ((lEnd+1)-lStart)); getmem(lByteP, ((lEnd+1)-lStart)*sizeof(smallint)); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(smallint)),((lEnd+1)-lStart)*sizeof(smallint)); for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*2)+1 ; lImgData^[lRApos+lInc-1] := makesmallint(lByteP^[lP2],lByteP^[lP2+1]); end; freemem(lByteP); end else if (lDataType = kDT_SIGNED_INT) or (lDataType = kDT_FLOAT) then begin lByteP := ByteP(@lImgData^[lRApos]); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(single)),((lEnd+1)-lStart)*sizeof(single)); {getmem(lByteP, ((lEnd+1)-lStart)*sizeof(single)); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(single)),((lEnd+1)-lStart)*sizeof(single)); for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*4)+1 ; lImgData^[lRApos+lInc-1] := makesingle(lByteP^[lP2],lByteP^[lP2+1],lByteP^[lP2+2],lByteP^[lP2+3]); //lImgData^[lRApos+lInc-1] := makesingle(lByteP^[lP2+3],lByteP^[lP2+2],lByteP^[lP2+1],lByteP^[lP2]); end; freemem(lByteP);} //test range {lINc := 1; lMin := lImgData^[lRApos+lInc-1]; lMax := lMin; for lInc := 1 to ((lEnd+1)-lStart) do begin lV := lImgData^[lRApos+lInc-1]; if lV > lMax then lMax := lV; if lV < lMin then lMin := lMax; end; MainForm.NPMmsg(inttostr(lvox_offset)+' '+realtostr(lMin,8)+' '+realtostr(lMax,8)); } //end if lDataType = kDT_SIGNED_INT then begin for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := conv4r4i (lImgData^[lRApos+lInc-1]); end else begin for lInc := 1 to ((lEnd+1)-lStart) do if specialsingle(lImgData^[lRApos+lInc-1])then lImgData^[lRApos+lInc-1] := 0; end; end else begin showmessage(lImgName + ' is an unsupported compressed data type '+inttostr(lDataType)); exit; end; end else begin assignfile(lFdata,lImgName); if lDataType = kDT_UNSIGNED_CHAR then begin getmem(lByteP, (lEnd+1)-lStart); reset(lFdata,1); seek(lFdata,lvox_offset+lStart-1); BlockRead(lFdata, lByteP^, (lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lByteP^[lInc]; freemem(lByteP); end else if (lDataType = kDT_SIGNED_SHORT) then begin getmem(lSmallIntP, sizeof(smallint)* ((lEnd+1)-lStart)); reset(lFdata,2); if (lvox_offset mod 2) <> 0 then begin showmessage('Error: this software can only read headers with dataoffsets that are divisible by 4.'); end; seek(lFdata,(lvox_offset div 2)+ (lStart-1)); BlockRead(lFdata, lSmallIntP^, (lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lSmallIntP^[lInc]; freemem(lSmallIntP); end else if (lDataType = kDT_SIGNED_INT) or (lDataType = kDT_FLOAT) then begin //next: 4 byte data reset(lFdata,4); if (lvox_offset mod 4) <> 0 then begin showmessage('Error: this software can only read headers with dataoffsets that are divisible by 4.'); end; seek(lFdata,(lvox_offset div 4)+ (lStart-1) ); BlockRead(lFdata, lImgData[lRApos], (lEnd+1)-lStart); if lDataType = kDT_SIGNED_INT then begin for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := conv4r4i (lImgData^[lRApos+lInc-1]); end else begin for lInc := 1 to ((lEnd+1)-lStart) do if specialsingle(lImgData^[lRApos+lInc-1]) then lImgData^[lRApos+lInc-1] := 0; end; end else showmessage('Unsupported COMPRESSED data type '+inttostr(lDataType)); closefile(lFdata); end; //not gz result := true; end; *) function LoadImg8(lInName: string; lImgData: ByteP; lStart, lEnd,linvox_offset,lRApos,lDataType,lVolVox: integer): boolean; //loads BINARY data - ignore scaling: zero or not zero var lvox_offset,lInc,lFSize,lP2: integer; lFData: file; lImgName: string; lByteP: ByteP; lSmallIntP: SmallIntP; lSingle: single; begin result := false; if (lStart >= lEnd) or (lStart < 1) or (lEnd < 1) then begin MainForm.NPMmsg('Error: LoadImg '+inttostr(lStart)+'>='+inttostr(lEnd)+' or zero'); exit; end; if Files4D(lInName) then begin lImgName := Filename4D(lInName); lP2 := BPP (lDataType); if lP2 = 0 then begin Showmessage(lImgName +' is an unsupported file type'); exit; end; lvox_offset := linvox_offset+ ((Vol4D(lInName)-1)* (lP2 * lVolVox)); end else begin lImgName := lInName; lvox_offset := linvox_offset; end; if UpCaseExt(lImgName) = '.HDR' then lImgName := changefileext(lImgName,'.img'); lFSize := FSize(lImgName); if (not GzExt(lImgName)) and (lFSize < (lEnd+ lvox_offset)) then begin MainForm.NPMmsg('Error: LoadImg '+lImgName+' FSize = '+inttostr(lFSize)+' Expected '+inttostr(lEnd+ lvox_offset)); exit; end; filemode := 0; //zero array for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := 0;//makesingle(lByteP^[lP2],lByteP^[lP2+1],lByteP^[lP2+2],lByteP^[lP2+3]); if GzExt(lImgName) then begin if lDataType = kDT_UNSIGNED_CHAR then begin getmem(lByteP, (lEnd+1)-lStart); UnGZip(lImgName,lByteP,lvox_offset+lStart-1,(lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lByteP^[lInc]; freemem(lByteP); end else if (lDataType = kDT_SIGNED_SHORT) then begin //getmem(lSmallIntP, sizeof(smallint)* ((lEnd+1)-lStart)); getmem(lByteP, ((lEnd+1)-lStart)*sizeof(smallint)); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(smallint)),((lEnd+1)-lStart)*sizeof(smallint)); for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*2)+1 ; lImgData^[lRApos+lInc-1] := makesmallint(lByteP^[lP2],lByteP^[lP2+1]); end; freemem(lByteP); end else if (lDataType = kDT_SIGNED_INT) or (lDataType = kDT_FLOAT) then begin getmem(lByteP, ((lEnd+1)-lStart)*sizeof(single)); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(single)),((lEnd+1)-lStart)*sizeof(single)); if lDataType = kDT_SIGNED_INT then begin for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*4)+1 ; lSingle := conv4r4i (makesingle(lByteP^[lP2],lByteP^[lP2+1],lByteP^[lP2+2],lByteP^[lP2+3])); if lSingle <> 0 then lImgData^[lRApos+lInc-1] := 1; end; end else begin //32 bit float for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*4)+1 ; lSingle := makesingle(lByteP^[lP2],lByteP^[lP2+1],lByteP^[lP2+2],lByteP^[lP2+3]); if (not specialsingle(lSingle)) and (lSingle <> 0) then lImgData^[lRApos+lInc-1] := 1; end; end; freemem(lByteP); end else begin showmessage(lImgName + ' is an unsupported compressed data type '+inttostr(lDataType)); exit; end; end else begin assignfile(lFdata,lImgName); if lDataType = kDT_UNSIGNED_CHAR then begin getmem(lByteP, (lEnd+1)-lStart); reset(lFdata,1); seek(lFdata,lvox_offset+lStart-1); BlockRead(lFdata, lByteP^, (lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lByteP^[lInc]; freemem(lByteP); end else if (lDataType = kDT_SIGNED_SHORT) then begin getmem(lSmallIntP, sizeof(smallint)* ((lEnd+1)-lStart)); reset(lFdata,2); if (lvox_offset mod 2) <> 0 then begin showmessage('Error: this software can only read headers with dataoffsets that are divisible by 4.'); end; seek(lFdata,(lvox_offset div 2)+ (lStart-1)); BlockRead(lFdata, lSmallIntP^, (lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lSmallIntP^[lInc]; freemem(lSmallIntP); end else if (lDataType = kDT_SIGNED_INT) or (lDataType = kDT_FLOAT) then begin //next: 4 byte data reset(lFdata,4); if (lvox_offset mod 4) <> 0 then begin showmessage('Error: this software can only read headers with dataoffsets that are divisible by 4.'); end; seek(lFdata,(lvox_offset div 4)+ (lStart-1) ); getmem(lByteP, ((lEnd+1)-lStart)*sizeof(single)); //fx(((lEnd+1)-lStart)*sizeof(single)); BlockRead(lFdata, lByteP^, ((lEnd+1)-lStart)); //April 2009 //UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(single)),((lEnd+1)-lStart)*sizeof(single)); if lDataType = kDT_SIGNED_INT then begin for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*4)+1 ; lSingle := conv4r4i (makesingle(lByteP^[lP2],lByteP^[lP2+1],lByteP^[lP2+2],lByteP^[lP2+3])); if lSingle <> 0 then lImgData^[lRApos+lInc-1] := 1; end; end else begin for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*4)+1 ; lSingle := makesingle(lByteP^[lP2],lByteP^[lP2+1],lByteP^[lP2+2],lByteP^[lP2+3]); if (not specialsingle(lSingle)) and (lSingle <> 0) then lImgData^[lRApos+lInc-1] := 1; end; end; freemem(lByteP); end else showmessage('Unsupported COMPRESSED data type '+inttostr(lDataType)); closefile(lFdata); end; //not gz result := true; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/firthThds.pas��������������������������������������������0000755�0001750�0001750�00000050757�11326425446�020653� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit firthThds; //Unit for running penalized multiple logistic regression //creates multiple threads //Requires firth interface uses ComCtrls,Classes, Graphics, ExtCtrls, define_types,{stats,}StatThdsUtil,lesion_pattern,Mat,Math,Distr,Vector; type TMultiRegThread = class(TThread) private finalloglik: SingleP0; KxKA1,KxKB1,KxKA,KxKB :TMatrix; Kvec,Kvec1 : TVector; Kveci,kVeci1 : TVectori; betak,xbeta,y,pi,ustar, XXx,XXXW2,XXFisher,XXcovs,XXXWPrime, deltahalfs,deltat,delta,covs,x,Fisher,XW2,W,XWprime,Hprime,H,ustarmat,negx: TMatrix; lBarX: TProgressBar; lnCondx,lnCritx,lBarPosX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx,lImagesCountx : integer; lPlankImgx: byteP;lOutImgMnx,lSymptomRAx: SingleP; lOutImgX: SingleRAp; //lBarX: TProgressBar; procedure DoVisualSwap; protected procedure Execute; override; procedure VisualProg(lPos: Integer); procedure Analyze(lnCond,lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: bytep;lOutImgMn,lSymptomRA: SingleP; lOutImg: SingleRAp); virtual; abstract; public constructor Create(lBar: TProgressBar; lnCond,lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: byteP;lOutImgMn,lSymptomRA: SingleP; lOutImg: SingleRAp); end; TFirthThreadStat = class(TMultiRegThread ) protected procedure Analyze(lnCond,lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: bytep;lOutImgMn,lSymptomRA: SingleP; lOutImg: SingleRAp); override; procedure logistfx (xin: SingleP; var lZvals: SingleP0; numSubj,numCond: integer; lComputeIntercept: boolean); end; implementation procedure TMultiRegThread .DoVisualSwap; begin lBarX.Position := lBarPosX; end; procedure TMultiRegThread.VisualProg(lPos: Integer); begin lBarPosX := lPos; {$IFDEF FPC}Synchronize(@DoVisualSwap); {$ELSE} Synchronize(DoVisualSwap);{$ENDIF} end; constructor TMultiRegThread.Create(lBar: TProgressBar; lnCond,lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: bytep;lOutImgMn,lSymptomRA: SingleP;lOutImg: SingleRAp); begin lBarX := lBar; lThreadX := lThread; lThreadStartX := lThreadStart; lThreadEndX := lThreadEnd; lStartVoxx := lStartVox; lVoxPerPlankx := lVoxPerPlank; lImagesCountX := lImagesCount; lPlankImgx := lPlankImg; lOutImgMnx := lOutImgMn; lOutImgX := lOutImg; lSymptomRAx := lSymptomRA; lnPermuteX := lnPermute; lnCritX := lnCrit; lnCondX := lnCond; FreeOnTerminate := True; inherited Create(False); end; { The Execute method is called when the thread starts } procedure TMultiRegThread .Execute; begin Analyze(lnCondX,lnCritX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx,lImagesCountx,lPlankImgX,lOutImgMnx,lSymptomRAx,lOutImgX); end; procedure TFirthThreadStat.logistfx (xin: SingleP; var lZvals: SingleP0; numSubj,numCond: integer; lComputeIntercept: boolean); //todo zero output incase exit //yin = 1..numSubj binary 0/1 values //xin = numSubj*numCond predictors //Chivals = 0..numCond p-values - the 0th Khi-value is the intercept // [0th value will not be computed if ; lComputeIntercept= false] label 123,666; const maxit = 25; maxhs = 5; epsilon = 0.0001; maxstep = 10; var SumY0,SumY1,mx, beta0,loglik,loglikold: double; sumy, n, i,j, k, iter,halfs,lCond,dropCond: integer; variability,firth: boolean; procedure crossprodustar; var inc,row: integer; begin for row := 1 to k do begin ustarmat[row,1] := 0; for inc := 1 to ustar.r do ustarmat[row,1] := ustarmat[row,1] + (x[row,inc]*ustar[inc,1]); end; end; procedure Diag2Vec; var inc: integer; begin for inc := 1 to pi.r do ustar[inc,1] := ustar[inc,1]+ H[inc,inc]*(0.5-pi[inc,1]); end; //nested DiagP2 procedure DiagP2 (var W, P: TMatrix); var inc: integer; begin W.Zero; for inc := 1 to P.r do W[inc,inc] := Power((P[inc,1] * (1-P[inc,1])),0.5) ; end; //nested DiagP2 procedure ComputeFisher; begin DiagP2(W,pi); XW2.mult(x,W); //XWPrime.copy( XW2); //XWPrime.transpose; XWPrime.transpose(XW2); Fisher.mult(XW2,XWPrime); covs.copy( Fisher); covs.Invert2(KxKA,KxKB,Kvec,Kveci) end; //nested computeFisher procedure computedropdelta; var jinc,iinc,ii,jj: integer; begin DiagP2(W,pi); XXXW2.mult(XXx,W); //XXXWPrime.copy( XXXW2); //XXXWPrime.transpose; XXXWPrime.transpose(XXXW2); XXFisher.mult(XXXW2,XXXWPrime); XXcovs.copy( XXFisher); //XXcovs.Invert; XXcovs.Invert2(KxKA1,KxKB1,Kvec1,Kveci1); covs.Zero; ii := 0; for iinc := 1 to (k) do begin if iinc <> (dropCond+1) then begin //leave the specified column zeros... inc(ii); jj := 0; for jinc := 1 to (k) do begin if jinc <> (dropCond+1) then begin inc(jj); covs[iinc,jinc] := xxCovs[ii,jj]; end; end; end; end; end; function firthpenalty: double; begin ComputeFisher; //result := 0.5 * ln(abs(Fisher.det)); result := 0.5 * ln(abs(Fisher.Det2(KxKA,kVeci,kVec))); end; //nested firthpenalty function ComputeLogLik: double; var inc: integer; begin xbeta.mult(betak,negx); for inc := 1 to n do pi[inc,1] := (1/(1 + exp( xbeta[inc,1]))); result := 0; for inc := 1 to n do if y[inc,1] = 1 then result := result+ln(pi[inc,1]); for inc := 1 to n do if y[inc,1] = 0 then result := result+ln(1-pi[inc,1]); if firth then result := result + firthpenalty; end;//nested ComputeLogLik begin for i := 0 to (numCond) do lZVals^[i] := 0; // if (numSubj < 2) or (numCond < 1) then exit; //ensure there is some variability in the input data... variability := false; i := 1; repeat inc(i); if xin^[i] <> xin^[1] then variability := true; until (i= (numSubj*numCond)) or (variability); if not variability then exit; //no variance in the regressors... variability := false; i := 1; repeat inc(i); if y[i,1] <> y[1,1] then variability := true; until (i= (numSubj)) or (variability); if not variability then exit; //no variance in the dependent variable... dropCond := -1; //initially compute full model, then compute effect of removing individual conditions firth := true; n := numSubj; k := numCond + 1; //get memory //beta := TMatrix.Create(n,1); //design our model //first row = 1: ell samples have equal weight for i := 1 to n do x.M[1,i] := 1; //next load model into x iter := 0; for j := 2 to k do for i := 1 to n do begin inc(iter); x.M[j,i] := xin^[iter]; end; //WriteMatrix('Observations',y); //WriteMatrix('Model',x); //negx is just sing-swapped - we will generate this as we use it a lot... for j := 1 to k do for i := 1 to n do begin negx.M[j,i] := -x.M[j,i]; end; //now start computations sumy := 0; for i := 1 to n do sumy := sumy + round(y[i,1]); if (sumy <= 0) or (sumy >= n) then begin //serious error: no variability. This should have been detected earlier in the procedure when yin was tested for variability goto 666; end; beta0 := ln((sumy/n)/(1 - sumy/n));//initial estimate 123: //go here for each dropcond if DropCond >= 0 then begin betak.Ones; betak.mult( 0) //start with a null model... does not really make sense end else begin betak.zero; betak[1,1] := (beta0); end; iter := 0; if DropCond >= 0 then begin //drop one of the factors... if dropCond <> 0 then begin//include intercept for i := 1 to n do XXx.M[1,i] := 1; lCond := 1; end else lCond := 0; for j := 1 to NumCond do begin if j <> DropCond then begin inc(lCond); for i := 1 to n do XXx.M[lCond,i] := x.M[j+1,i]; end; //if j <> dropCond end; end;//if lDropCond >= 0 loglik := ComputeLogLik; repeat inc(iter); ComputeFisher; HPrime.mult(XWPrime,covs); H.mult(HPrime,XW2); //WriteMatrix(covs); ustar.Sub(y,pi); if firth then Diag2Vec; crossprodustar; if dropCond >= 0 then // model with dropped factor computedropdelta; deltat.mult(covs,ustarmat); delta.transpose(deltat); mx := delta.MatAbsMax/MaxStep; if mx > 1 then delta.mult(mx);//scale delta betak.add(delta); loglikold := loglik; halfs := 1; while halfs <= maxhs do begin // Half-Steps //fx(iter,halfs,loglik); loglik := ComputeLogLik; deltahalfs.mult(delta,power(2,-halfs)); betak.sub(deltahalfs); if (loglik > loglikold) then break; inc(halfs); end; if delta.MatAbsMax <= epsilon then break; until (iter >= maxit); //fx(DropCond,loglik); //done with this model - record model fit if DropCond < 0 then finalloglik^[k] := loglik //full model else begin finalloglik^[DropCond] := loglik; //model with a factor removed end; if DropCond < numCond then begin inc(DropCond); if (DropCond = 0) and (not lComputeIntercept) then //only compute intercept model if requested inc(DropCond); goto 123; end; //finally - results //ResultsForm.Memo1.lines.add (inttostr(j)+' cases have Y=0, '+inttostr(n-j)+' cases have Y=1'); if lComputeIntercept then J := 0 else J := 1; for i := J to (k-1) do begin lZVals^[i] := abs(2*(finalloglik^[i]-finalloglik^[k])); //find direction of effect - does a larger value of the IV predict more zeros or ones lZVals^[i] := pNormalInv(ChiSq(lZVals^[i],1)); //we have now computed a Z scores - but Chi is one tailed, so all Z > 0... lets check direction Sumy0 := 0; Sumy1 := 0; for iter := 1 to n do begin if y[iter,1] = 0 then Sumy0 := Sumy0 + x.M[i+1,iter] //+1: M indexed from 1, ZVal indexed from 0 else Sumy1 := Sumy1 + x.M[i+1,iter]; //+1 M indexed from 1 end; //compute means Sumy1 := Sumy1/sumy; Sumy0 := Sumy0/(n-sumy); if Sumy0 < Sumy1 then //negative z-scores: damage here predicts performance is BETTER lZVals^[i] := -lZVals^[i]; end; (*if lComputeIntercept then //intercept is the 0th value lChiVals[0] := abs(2*(finalloglik[0]-finalloglik[k])); for i := 1 to (k-1) do //k-1 as this is indexed from 0 lChiVals[i] := abs(2*(finalloglik[i]-finalloglik[k])); *) 666: end; {Firth penalized logisitic regression} procedure TFirthThreadStat.Analyze(lnCond, lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: bytep;lOutImgMn,lSymptomRA: SingleP;lOutImg: SingleRAp); //calls logistf (yin,xin: SingleP; var lChivals: SingleP0; numSubj,numCond: integer); label 666; const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lObs: Bytep; lPrevZVals: array [1..knPrevPattern] of SingleP0; lZVals: SingleP0; lPatternPos,lC,lnLesion,lPosPct,lPos,lPos2,lPos2Offset,lnCritLocal,n,k: integer; begin //statthread lnCritLocal := lnCrit; if lnCritLocal < 1 then lnCritLocal := 1; Getmem(lObs,lImagesCount*sizeof(byte)); Getmem(lZVals,(lnCond+1)*sizeof(single)); for lPos := 1 to knPrevPattern do Getmem(lPrevZVals[lPos],(lnCond+1)*sizeof(single)); n := lImagesCount; k := lnCond + 1; y := TMatrix.Create(n,1); GetMem(finalloglik,(k+1)*sizeof(single));//finalloglik := TVector.Create(k+1); x := TMatrix.Create (k, n); betak:=TMatrix.Create(1,k); covs:=TMatrix.Create(k,k); delta:=TMatrix.Create(1,k); deltahalfs:=TMatrix.Create(1,k); deltat:=TMatrix.Create(k,1); Fisher:=TMatrix.Create(k,k); H:=TMatrix.Create(n,n); HPrime:=TMatrix.Create(n,k); negx:=TMatrix.Create(k,n); pi:=TMatrix.Create(n,1); ustar:=TMatrix.Create(n,1); ustarmat:=TMatrix.create(k,1); W:=TMatrix.Create(n,n); xbeta:=TMatrix.Create(1,n); XW2:=TMatrix.Create(k,n); //XWPrime:=TMatrix.Create(k,n); XWPrime:=TMatrix.Create(n,k); XXcovs:=TMatrix.Create(k-1,k-1); XXFisher:=TMatrix.Create(k-1,k-1); XXx:=TMatrix.Create(k-1,n); XXXW2:=TMatrix.Create(k-1,n); //XXXWPrime:=TMatrix.Create(k-1,n); XXXWPrime := TMatrix.Create ( n, k-1); KxKA := TMatrix.Create(k,k); KxKB := TMatrix.Create(k,k); Kvec := TVector.Create(k); Kveci := TVectori.Create(k); KxKA1 := TMatrix.Create(k-1,k-1); KxKB1 := TMatrix.Create(k-1,k-1); Kvec1 := TVector.Create(k-1); Kveci1 := TVectori.Create(k-1); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; for lPos := 1 to lImagesCount do begin if lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2] = 0 then begin //no lesion y[lPos,1] := 0; lObs^[lPos] := 0; end else begin //lesion inc(lnLesion); lObs^[lPos] := 1; y[lPos,1] := 1; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCritLocal) and (lnLesion < lImagesCount) then begin lPattern := SetOrderX (lObs,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin inc(gnVoxTestedRA[lThread]); //logistf(lObs,lSymptomRA, lZvals, lImagesCount,lnCond,false); for lC := 1 to lnCond do lOutImg^[lC]^[lPos2Offset] := lPrevZvals[lPos]^[lC]; end else begin //new pattern - need to compute inc(gnVoxTestedRA[lThread]); logistfx(lSymptomRA, lZvals, lImagesCount,lnCond,false); for lC := 1 to lnCond do lOutImg^[lC]^[lPos2Offset] := lZvals^[lC]; lPrevPatternRA[lPatternPos] := lPattern; for lC := 1 to lnCond do lPrevZVals[lPatternPos]^[lC] := lZvals^[lC]; inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; end; //new pattern end; //nlesion > nCritical end; //for each voxel //gMat := false; 666: freemem(lObs); for lPos := 1 to knPrevPattern do freemem(lPrevZVals[lPos]); freemem(lZVals); y.free; x.free; betak.free; covs.free; delta.free; deltahalfs.free; deltat.free; Fisher.free; H.free; HPrime.free; negx.free; pi.free; ustar.free; ustarmat.Free; W.free; xbeta.free; XW2.free; XWPrime.free; XXcovs.free; XXFisher.free; XXx.free; XXXW2.free; XXXWPrime.free; KxKA.free; KxKB.free; Kvec.free; Kveci.free; KxKA1.free; KxKB1.free; Kvec1.free; Kveci1.free; freemem(finalloglik); end; (* {Firth penalized logisitic regression} procedure TFirthThreadStat .Analyze(lnCond, lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg,lOutImgMn,lSymptomRA: SingleP;lOutImg: SingleRAp); //calls logistf (yin,xin: SingleP; var lChivals: SingleP0; numSubj,numCond: integer); var lPattern,lPrevPattern: TLesionPattern; lObs: Singlep; lZVals,lPrevZVals: SingleP0; lC,lnLesion,lPosPct,lPos,lPos2,lPos2Offset,lnCritLocal,n,k: integer; begin //statthread lnCritLocal := lnCrit; if lnCritLocal < 1 then lnCritLocal := 1; Getmem(lObs,lImagesCount*sizeof(single)); Getmem(lZVals,(lnCond+1)*sizeof(single)); Getmem(lPrevZVals,(lnCond+1)*sizeof(single)); n := lImagesCount; k := lnCond + 1; y := TMatrix.Create(n,1); GetMem(finalloglik,(k+1)*sizeof(single));//finalloglik := TVector.Create(k+1); x := TMatrix.Create (k, n); betak:=TMatrix.Create(1,k); covs:=TMatrix.Create(k,k); delta:=TMatrix.Create(1,k); deltahalfs:=TMatrix.Create(1,k); deltat:=TMatrix.Create(k,1); Fisher:=TMatrix.Create(k,k); H:=TMatrix.Create(n,n); HPrime:=TMatrix.Create(n,k); negx:=TMatrix.Create(k,n); pi:=TMatrix.Create(n,1); ustar:=TMatrix.Create(n,1); ustarmat:=TMatrix.create(k,1); W:=TMatrix.Create(n,n); xbeta:=TMatrix.Create(1,n); XW2:=TMatrix.Create(k,n); //XWPrime:=TMatrix.Create(k,n); XWPrime:=TMatrix.Create(n,k); XXcovs:=TMatrix.Create(k-1,k-1); XXFisher:=TMatrix.Create(k-1,k-1); XXx:=TMatrix.Create(k-1,n); XXXW2:=TMatrix.Create(k-1,n); //XXXWPrime:=TMatrix.Create(k-1,n); XXXWPrime := TMatrix.Create ( n, k-1); KxKA := TMatrix.Create(k,k); KxKB := TMatrix.Create(k,k); Kvec := TVector.Create(k); Kveci := TVectori.Create(k); KxKA1 := TMatrix.Create(k-1,k-1); KxKB1 := TMatrix.Create(k-1,k-1); Kvec1 := TVector.Create(k-1); Kveci1 := TVectori.Create(k-1); //gMat := true; lPosPct := (lThreadEnd-lThreadStart) div 100; lPrevPattern := EmptyOrder; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; for lPos := 1 to lImagesCount do begin if ((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]) = 0 then begin //no lesion y[lPos,1] := 0; lObs[lPos] := 0; end else begin //lesion inc(lnLesion); lObs[lPos] := 1; y[lPos,1] := 1; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCritLocal) and (lnLesion < lImagesCount) then begin lPattern := SetOrder (lObs,lImagesCount); if SameOrder(lPattern,lPrevPattern,lImagesCount) then begin inc(gnVoxTestedRA[lThread]); //logistf(lObs,lSymptomRA, lZvals, lImagesCount,lnCond,false); for lC := 1 to lnCond do lOutImg^[lC]^[lPos2Offset] := lPrevZvals[lC]; end else begin //new pattern - need to compute inc(gnVoxTestedRA[lThread]); logistfx(lSymptomRA, lZvals, lImagesCount,lnCond,false); for lC := 1 to lnCond do lOutImg^[lC]^[lPos2Offset] := lZvals[lC]; end; lPrevPattern := lPattern; for lC := 1 to lnCond do lPrevZVals[lC] := lZvals[lC]; end; end; //for each voxel //gMat := false; freemem(lObs); freemem(lPrevZVals); freemem(lZVals); y.free; x.free; betak.free; covs.free; delta.free; deltahalfs.free; deltat.free; Fisher.free; H.free; HPrime.free; negx.free; pi.free; ustar.free; ustarmat.Free; W.free; xbeta.free; XW2.free; XWPrime.free; XXcovs.free; XXFisher.free; XXx.free; XXXW2.free; XXXWPrime.free; KxKA.free; KxKB.free; Kvec.free; Kveci.free; KxKA1.free; KxKB1.free; Kvec1.free; Kveci1.free; freemem(finalloglik); end; (**) end. �����������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npm.cfg��������������������������������������������������0000755�0001750�0001750�00000001122�12147207562�017437� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-$A8 -$B- -$C+ -$D+ -$E- -$F- -$G+ -$H+ -$I+ -$J+ -$K- -$L+ -$M- -$N+ -$O+ -$P+ -$Q- -$R- -$S- -$T- -$U- -$V+ -$W- -$X+ -$YD -$Z1 -cg -AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; -H+ -W+ -M -$M16384,1048576 -K$00400000 -LE"c:\program files (x86)\borland\delphi7\Projects\Bpl" -LN"c:\program files (x86)\borland\delphi7\Projects\Bpl" -U"C:\pas\mricron\common;C:\pas\mricron\fpmath" -O"C:\pas\mricron\common;C:\pas\mricron\fpmath" -I"C:\pas\mricron\common;C:\pas\mricron\fpmath" -R"C:\pas\mricron\common;C:\pas\mricron\fpmath" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/design.dfm�����������������������������������������������0000755�0001750�0001750�00000003262�10653724326�020136� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �TDESIGNFORM�0��TPF0 TDesignForm DesignFormLeft Topf BorderStylebsDialogCaptionDesign ClientHeight� ClientWidthdColor clBtnFace Font.CharsetDEFAULT_CHARSET Font.Color clWindowText Font.Height Font.Name MS Sans Serif Font.Style �OldCreateOrder PositionpoScreenCenterOnCreate FormCreate PixelsPerInch` TextHeight �TLabelLabel4LeftTopWidth/Height Caption Predictors��TLabelLabel5LeftLTopWidthNHeight CaptionPredictor Names��TLabelLabel1LeftTop6Width7Height Caption Participants��TLabel TemplateLabelLeft�ToprWidthJHeight CaptionC:\template.imgVisible��TLabelLabel2Left TopTWidth�Height Caption%Ignore voxels damaged in less than N%��TButtonOKBtnLeftToppWidthKHeightCaptionOK ModalResultTabOrder��� TSpinEditAValLeftTopWidth@Height MaxLengthMaxValuecMinValueTabOrderValueOnChange AValChange�� TStringGrid ALevelNamesLeftJTopWidthHeightColCountDefaultRowHeight FixedCols�RowCount FixedRows�Options goFixedVertLinegoFixedHorzLine goVertLinegoDrawFocusSelected goEditing� ScrollBarsssNoneTabOrderOnEnterALevelNamesEnterOnExitALevelNamesExit�� TCheckBoxLesionCovaryCheckLeft�Top6Width�HeightCaption"Automatically Covary Lesion VolumeTabOrderVisible��TButton AddMRIBtnLeftHTop0Width�HeightCaption Select ImagesTabOrderOnClickAddMRIBtnClick��TButton TemplateBtnLeftToplWidth�HeightCaptionSelect TemplateTabOrderVisibleOnClickTemplateBtnClick�� TSpinEdit CritPctEditLeft�TopNWidth@Height MaxLengthMaxValuedMinValue�TabOrderValue�OnChange AValChange�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/overlap.pas����������������������������������������������0000755�0001750�0001750�00000041657�11326425450�020356� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit overlap; {$H+} interface uses nifti_hdr,define_types,SysUtils, StatThdsUtil,Brunner,nifti_img, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,lesion_pattern; Type OverlapRA = array [1..1] of TLesionPattern;//Toverlap; Overlapp = ^OverlapRA; //function CountOverlap2(var lImages: TStrings; lMinDeficits: integer; lPlankImg: bytep): integer; function CountOverlap (var lImages: TStrings; lMinDeficits,lnVoxTested: integer): integer; procedure EvaluatePower(var lFilenames: TStrings; lOverlapInc,lOverlapMax,lReps,lPct: integer); function CountOverlap2(var lImages: TStrings; lMinDeficits, lnVoxTested: integer; lPlankImg: bytep): integer; //procedure EvaluatePower; implementation uses npmform; function SelectFiles (var lIn,lOut: TStrings; lN: integer): boolean; //select (without replacement) lN filenames from the population lIn var lnFound,lTrial,lRan,lSwap: integer; lRandRA: longintP; begin result := false; lnFound := lIn.count; if (lnFound < lN) then exit; //not enough items found getmem(lRandRA,lnFound*sizeof(longint)); for lTrial := 1 to lnFound do lRandRA^[lTrial] := lTrial-1; //index to each strong for lTrial := lnFound downto 2 do begin //jumble order lRan := random(lTrial)+1; lSwap := lRandRA^[lTrial]; lRandRA^[lTrial] := lRandRA^[lRan]; lRandRA^[lRan] := lSwap; end; for lTrial := 1 to lN do lOut.Add(lIn[lRandRA^[lTrial]]); freemem(lRandRA); result := true; end; procedure EvaluatePower(var lFilenames: TStrings; lOverlapInc,lOverlapMax,lReps,lPct: integer); label 666; var lG: TStrings; lSize,lRep: integer; begin if (lReps < 1) or (lOverlapMax < 1) or (lOverlapInc < 1) or (lOverlapMax > lFilenames.count) or (lOverlapInc > lOverlapMax) then begin showmessage('Error with EvaluatePower inputs...'); exit; end; MainForm.NPMMsgClear; //MainForm.NPMmsg(kVers); randomize; MainForm.NPMmsg('Power Analysis began = ' +TimeToStr(Now)); lSize := lOverlapInc; while lSize <= lOverlapMax do begin for lRep := 1 to lReps do begin lG:= TStringList.Create; if not SelectFiles(lFilenames,lG,lSize) then begin showmessage('Error selecting '+inttostr(lSize)+'files!'); goto 666; end; CountOverlap(lG, round((lPct/100)*lSize),-1 ); lG.Free; end; //for lLoop lSize := lSize + lOverlapInc; end; //for lRep MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); exit; 666: //there has been a critical failure! lG.Free; end; (*function SelectFiles (lN: integer; var lOut: TStrings): boolean; var lnFound,lTrial,lRan,lSwap: integer; lMaskExt,lFilePath: string; lSearchRec: TSearchRec; lF: TStrings; lRandRA: longintP; begin result := false; lF:= TStringList.Create; lFilepath := 'C:\140\'; lMaskExt := '*.voi'; if FindFirst(lFilePath{+PathDelim}+lMaskExt, faAnyFile-faSysFile-faDirectory, lSearchRec) = 0 then begin repeat lF.add(lFilePath+lSearchRec.Name); until (FindNext(lSearchRec) <> 0); end; lnFound := lF.count; if (lnFound < lN) then begin lF.free; exit; end; //not enough items found getmem(lRandRA,lnFound*sizeof(longint)); for lTrial := 1 to lnFound do lRandRA[lTrial] := lTrial-1; //index to each strong for lTrial := lnFound downto 2 do begin //jumble order lRan := random(lTrial)+1; lSwap := lRandRA[lTrial]; lRandRA[lTrial] := lRandRA[lRan]; lRandRA[lRan] := lSwap; end; for lTrial := 1 to lN do lOut.Add(lF[lRandRA[lTrial]]); freemem(lRandRA); lF.Free; result := true; end; procedure EvaluatePower; label 666; var lG: TStrings; lMaskname: string; lMaskHdr: TMRIcroHdr; lMaskVoxels,lN,lLoop,lRep: integer; begin MainForm.NPMMsgClear; //MainForm.NPMmsg(kVers); randomize; MainForm.NPMmsg('Power Analysis began = ' +TimeToStr(Now)); for lRep := 7 to 10 do begin for lLoop := 1 to 10 do begin lN := lRep * 10; lG:= TStringList.Create; if not SelectFiles(lN,lG) then begin showmessage('Error selecting '+inttostr(lN)+'files!'); goto 666; end; {if not OpenDialogExecute('Select images to average',true,true,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected lG:= TStringList.Create; lG.addstrings(OpenHdrDlg.Files);} {$IFDEF FORMATVARIES} //this next bit allows different types of scans to be read, but it is slow.... lMaskname := lG[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if not MainForm.CheckVoxelsGroup(lG,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; {$ENDIF} CountOverlap(lG, {round(0.1*lN)} 0); lG.Free; end; //for lLoop end; //for lRep MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); exit; 666: //there has been a critical failure! lG.Free; end; *) function CountOverlap2(var lImages: TStrings; lMinDeficits, lnVoxTested: integer; lPlankImg: bytep): integer; label 123,667; const kMaxBit = 63; var lMaskName: string; //lPlankImg: byteP; lDouble,lTotalMemory: double; lVoxPerPlankDiv10,lOffset,lnDeficits,lUniqueOrders, lVolVox,lPos,lPlank,lVox,lDataType,lnVoxels,lImagesCount: integer; lnPlanks,lVoxPerPlank,lStartVox,lEndVox,lPlankImgPos: int64; lOverlapRA: Overlapp; lOrder,lPrevOrder: TLesionPattern;//x TOverlap; lMaskHdr: TMRIcroHdr; //lPowerRA: array [1..kMaxBit] of int64; procedure CheckOrder(var lObservedOrder: TLesionPattern); var lInc: integer; begin if lUniqueOrders > 0 then begin //see if this is unique for lInc := 1 to lUniqueOrders do if SameOrder(lObservedOrder,lOverlapRA^[lInc],lImagesCount) then exit; //not unique end; //UniqueOrders > 0 //if we have not exited yet, we have found a new ordering! lUniqueOrders := lUniqueOrders + 1; lOverlapRA^[lUniqueOrders] := lObservedOrder; end; begin result := -1; //MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); //lMinDeficits := 0; lUniqueOrders := 0; lTotalMemory := 0; lMaskName := lImages[0]; lImagesCount := lImages.Count; if lImagesCount < 1 then goto 667; if lImages.Count > (kMaxObs) then begin MainForm.NPMmsg('Only able to compute tests for <= '+inttostr(kMaxObs)+' overlays.'); goto 667; end; if not NIFTIhdr_LoadHdr(lMaskName,lMaskHdr) then begin MainForm.NPMmsg('Error reading 1st image.'); goto 667; end; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; lDataType := lMaskHdr.NIFTIhdr.datatype; lOffset := round(lMaskHdr.NIFTIhdr.vox_offset); //showmessage(inttostr(lVolVox)); if (lVolVox < 1) then goto 667; lVoxPerPlank := kPlankSz div lImages.Count {div sizeof(single)} ; if (lVoxPerPlank = 0) then goto 667; //no data lDouble := lVolVox;//force floating point multiplication in next step... lTotalMemory := lDouble * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; lnVoxels := 0; lStartVox := 1; lEndVox := 0; if lnVoxTested <= 0 then getmem(lOverlapRA,lVolVox* sizeof(TLesionPattern)) else getmem(lOverlapRA,lnVoxTested* sizeof(TLesionPattern)); for lPlank := 1 to lnPlanks do begin MainForm.ProgressBar1.Position := 1; MainForm.Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lVolVox then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lVolVox); lEndVox := lVolVox; end; lVoxPerPlankDiv10 := lVoxPerPlank div 10; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin {$IFDEF FORMATVARIES} if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then {$ELSE} if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,lOffset,lPlankImgPos,lDataType,lVolVox) then {$ENDIF} goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image lPrevOrder := EmptyOrder;//impossible: forces first voxel of each order to be checked for lVox := 1 to lVoxPerPlank do begin if (lVox mod lVoxPerPlankDiv10) = 0 then begin MainForm.ProgressBar1.Position := (lVox div lVoxPerPlankDiv10)*10; MainForm.Refresh; Application.processmessages; end; lOrder := EmptyOrder; lPlankImgPos := 0; lnDeficits := 0; for lPos := 1 to lImages.Count do begin if (lPlankImg^[lPlankImgPos + lVox] > 0) then begin inc(lnDeficits); SetBit(lPos,lOrder); end; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end; if (lnDeficits >= lminDeficits) then begin //this is different from the last voxel: perhaps this is a new ordering if (not SameOrder(lOrder,lPrevOrder,lImagesCount)) then CheckOrder(lOrder); inc(lnVoxels); end; lPrevOrder := lOrder; end; lStartVox := lEndVox + 1; end; MainForm.NPMmsg('n=,'+inttostr( lImages.Count)+',minN=,'+inttostr(lMinDeficits) +',unique overlap patterns,' +Inttostr(lUniqueOrders) +',voxels tested,' +Inttostr(lnVoxels)); 123: //next: free dynamic memory freemem(lOverlapRA); //MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); MainForm.ProgressBar1.Position := 0; result := lUniqueOrders; exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 0 then begin freemem(lPlankImg); freemem(lOverlapRA); end; MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; function CountOverlap(var lImages: TStrings; lMinDeficits,lnVoxTested: integer): integer; var lPlankImg: byteP; begin getmem(lPlankImg,kPlankSz); result := CountOverlap2( lImages, lMinDeficits,lnVoxTested,lPlankImg); freemem(lPlankImg); end; (*function CountOverlap2(var lImages: TStrings; lMinDeficits: integer; lPlankImg: bytep): integer; label 123,667; var lMaskName: string; lVoxPerPlankDiv10,lOffset,lnDeficits,lUniqueOrders,lTotalMemory, lImagesCount,lVolVox,lPos,lPlank,lVox,lDataType,lnVoxels: integer; lnPlanks,lVoxPerPlank,lStartVox,lEndVox,lPlankImgPos: int64; lOverlapRA: Overlapp; lOrder,lPrevOrder: TLesionPattern; lMaskHdr: TMRIcroHdr; //lPowerRA: array [1..kMaxBit] of int64; procedure CheckOrder(var lObservedOrder: TLesionPattern); var lInc: integer; begin if lUniqueOrders > 0 then begin //see if this is unique for lInc := 1 to lUniqueOrders do if SameOrder(lObservedOrder,lOverlapRA^[lInc],lImagesCount) then exit; //not unique end; //UniqueOrders > 0 //if we have not exited yet, we have found a new ordering! lUniqueOrders := lUniqueOrders + 1; lOverlapRA^[lUniqueOrders] := lObservedOrder; end; begin result := -1; //MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); //lMinDeficits := 0; lUniqueOrders := 0; lTotalMemory := 0; lImagesCount := lImages.Count; lMaskName := lImages[0]; if lImages.Count < 1 then goto 667; if lImages.Count > (kMaxObs) then begin MainForm.NPMmsg('Only able to compute tests for <= '+inttostr(kMaxObs)+' overlays.'); goto 667; end; if not NIFTIhdr_LoadHdr(lMaskName,lMaskHdr) then begin MainForm.NPMmsg('Error reading 1st image.'); goto 667; end; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; lDataType := lMaskHdr.NIFTIhdr.datatype; lOffset := round(lMaskHdr.NIFTIhdr.vox_offset); //showmessage(inttostr(lVolVox)); if (lVolVox < 1) then goto 667; lVoxPerPlank := kPlankSz div lImages.Count ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := lVolVox * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data //showmessage('xx'); lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; //MainForm.NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); //MainForm.NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); //if lTotalMemory > kPLankSz then // getmem(lPlankImg,kPlankSz); //else // getmem(lPlankImg,lTotalMemory); lnVoxels := 0; lStartVox := 1; lEndVox := 0; getmem(lOverlapRA,lVolVox* sizeof(TLesionPattern)); for lPlank := 1 to lnPlanks do begin MainForm.ProgressBar1.Position := 1; MainForm.Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lVolVox then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lVolVox); lEndVox := lVolVox; end; lVoxPerPlankDiv10 := lVoxPerPlank div 10; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin {$IFDEF FORMATVARIES} if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then {$ELSE} if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,lOffset,lPlankImgPos,lDataType,lVolVox) then {$ENDIF} goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image lPrevOrder := EmptyOrder;//impossible: forces first voxel of each order to be checked for lVox := 1 to lVoxPerPlank do begin if (lVox mod lVoxPerPlankDiv10) = 0 then begin MainForm.ProgressBar1.Position := (lVox div lVoxPerPlankDiv10)*10; MainForm.Refresh; Application.processmessages; end; lOrder := EmptyOrder; lPlankImgPos := 0; lnDeficits := 0; for lPos := 1 to lImages.Count do begin if (lPlankImg^[lPlankImgPos + lVox] > 0) then begin inc(lnDeficits); SetBit(lPos,lOrder); end; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end; if (lnDeficits >= lminDeficits) then begin //this is different from the last voxel: perhaps this is a new ordering if (not SameOrder(lOrder,lPrevOrder,lImagesCount)) then CheckOrder(lOrder); inc(lnVoxels); end; lPrevOrder := lOrder; end; lStartVox := lEndVox + 1; end; MainForm.NPMmsg('n=,'+inttostr( lImagesCount)+',minN=,'+inttostr(lMinDeficits) +',unique overlap patterns,' +Inttostr(lUniqueOrders) +',voxels tested,' +Inttostr(lnVoxels)); 123: //next: free dynamic memory //freemem(lPlankImg); freemem(lOverlapRA); //MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); MainForm.ProgressBar1.Position := 0; result := lUniqueOrders; exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 0 then begin freemem(lPlankImg); freemem(lOverlapRA); end; MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; *) end. ���������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npm.app/�������������������������������������������������0000755�0001750�0001750�00000000000�12360760644�017540� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npm.app/Contents/����������������������������������������0000755�0001750�0001750�00000000000�12360760644�021335� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npm.app/Contents/Resources/������������������������������0000755�0001750�0001750�00000000000�12147212634�023301� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npm.app/Contents/PkgInfo���������������������������������0000755�0001750�0001750�00000000011�12147212634�022602� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������APPL???? �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npm.app/Contents/Info.plist������������������������������0000755�0001750�0001750�00000002215�12147212634�023302� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleExecutable</key> <string>npm</string> <key>CFBundleName</key> <string>npm</string> <key>CFBundleIdentifier</key> <string>com.company.npm</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleSignature</key> <string>npm?</string> <key>CFBundleShortVersionString</key> <string>0.1</string> <key>CFBundleVersion</key> <string>1</string> <key>CSResourcesFileMapped</key> <true/> <key>CFBundleDocumentTypes</key> <array> <dict> <key>CFBundleTypeRole</key> <string>Viewer</string> <key>CFBundleTypeExtensions</key> <array> <string>*</string> </array> <key>CFBundleTypeOSTypes</key> <array> <string>fold</string> <string>disk</string> <string>****</string> </array> </dict> </array> </dict> </plist> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npm.app/Contents/MacOS/����������������������������������0000755�0001750�0001750�00000000000�12360760644�022277� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npm.app/Contents/MacOS/npm�������������������������������0000755�0001750�0001750�00000000014�12147212634�023004� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������../../../npm��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/xmontecarlo.pas������������������������������������������0000755�0001750�0001750�00000021004�11326425450�021221� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit montecarlo; interface {$H+} {$DEFINE anacom} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes{$IFDEF anacom} ,anacom{$ENDIF}; procedure LesionMonteCarlo (lBinomial,lTTest,lBM: boolean); implementation uses npmform,filename,turbolesion; procedure RandomGroup(kSamplesPerTest: integer;lImageNames: TStrings;lSymptomRA: SingleP;var lPartImageNames: TStrings; var lPartSymptomRA: SingleP); var lTotal,lInc,lRand,lSwap: integer; lRanOrder: longintP; begin lPartImageNames.Clear; lTotal := lImageNames.Count; if kSamplesPerTest > lTotal then begin showmessage('Monte carlo error: population must be larger than sample size.'); exit; end; Getmem(lRanOrder,lTotal*sizeof(longint)); for lInc := 1 to lTotal do lRanOrder^[lInc] := lInc; for lInc := lTotal downto 2 do begin lRand := Random(lInc)+1; lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc]; lRanOrder^[lInc] := lSwap; end; for lInc := 1 to kSamplesPerTest do begin lPartImageNames.Add(lImageNames.Strings[lRanOrder^[lInc]-1]);//indexed from 0 lPartSymptomRA^[lInc] := lSymptomRA^[lRanOrder^[lInc]]; end; Freemem(lRanOrder); end; procedure LesionMonteCarlo (lBinomial,lTTest,lBM: boolean); label 666; //const //kSimSampleSize = 64; //knSim = 2; //kCrit = 3; {$IFDEF anacom} //knControls = 64; {$ENDIF} var lPrefs: TLDMPrefs ; lCrit,lnSim, lSimSampleSize,lSim,lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCrit: integer; lPartImageNames,lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lControlFilename,lTemp4D,lMaskname,lOutName,lFactname,lOutNameSim: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA,lPartSymptomRA: singleP; {$IFDEF anacom} lnControlObservations: integer; lControlSymptomRA: singleP; {$ENDIF} begin lnSim := ReadIntForm.GetInt('Enter total numbers of simulations ', 10,25,1000); lSimSampleSize := ReadIntForm.GetInt('Number of patients per simulation? ', 2,10,1000); lCrit := ReadIntForm.GetInt('Only analyze voxels damaged in at least N patients ', 2,10,1000); //lBinomial := not odd( (Sender as tMenuItem).tag); lPrefs.NULP := true{gNULP false}; if not lBinomial then begin lPrefs.BMtest := lbm;//BMmenu.checked; lPrefs.Ttest := lttest;//ttestmenu.checked; if (not lPrefs.BMtest) and (not lPrefs.ttest) then lPrefs.ttest := true; lPrefs.Ltest:= false; end else begin lPrefs.BMtest := false; lPrefs.Ttest := false; lPrefs.Ltest:= true; end; lPrefs.nCrit := lCrit; lPrefs.nPermute := 0;//MainForm.ReadPermute;; lPrefs.Run := 0;{0 except for montecarlo} if (not lBinomial) and (not lTTest) and (not lBM) then begin Showmessage('Error: you need to compute at least on test [options/test menu]'); exit; end; lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? lPartImageNames := TStringList.Create; getmem(lPartSymptomRA,lSimSampleSize*sizeof(single)); {$IFDEF anacom} if not MainForm.OpenDialogExecute('Select text file',false,false,'Text file (*.txt)|*.txt;*.csv') then begin showmessage('AnaCOM aborted: Control data file selection failed.'); exit; end; //if not selected lControlFilename := MainForm.OpenHdrDlg.Filename; if (not readTxt (lControlFilename, lnControlObservations,lControlSymptomRA)) or (lnControlObservations < 1) then begin showmessage('Error reading file '+lControlFilename); exit; end; //lnControlObservations := knControls; //getmem(lControlSymptomRA,lnControlObservations*sizeof(single)); //for lSim := 1 to lnControlObservations do // lControlSymptomRA^[lSim] := 1000; {$ENDIF} //next, get 1st group if not MainForm.GetValX(lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCrit{,binom},lPredictorList) then begin showmessage('Error with VAL file'); goto 666; end; lTemp4D := CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) or (lnSubjAll < lSimSampleSize) then begin Showmessage('Not enough subjects ('+inttostr(lnSubjAll)+') [sample size is '+inttostr(lSimSampleSize)+']or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; MainForm.SaveHdrDlg.Filename := loutname; lOutName := lOutName+'.nii.gz'; if not MainForm.SaveHdrName ('Base Statistical Map', lOutName) then goto 666; for lFact := 1 to lnFactors do begin lImageNames.clear; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); lnSubj := lImageNames.Count; if lnSubj > 1 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; //randomization loop.... for lSim := 1 to lnSim do begin RandomGroup(lSimSampleSize, lImageNames,lSymptomRA, lPartImageNames, lPartSymptomRA); lOutNameSim := AddIndexToFilename(lOutName,lSim); lnCrit := lCrit; MainForm.NPMMsgClear; //Msg(GetKVers); MainForm.NPMMsg('Threads: '+inttostr(gnCPUThreads)); lFactName := lPredictorList.Strings[lFact-1]; lFactName := LegitFilename(lFactName,lFact); MainForm.NPMMsg('Factor = '+lFactname); For lSubj := 1 to lSimSampleSize do MainForm.NPMMsg (lPartImageNames.Strings[lSubj-1] + ' = '+realtostr(lPartSymptomRA^[lSubj],2) ); MainForm.NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); MainForm.NPMMsg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); MainForm.NPMMsg('Number of Lesion maps = '+inttostr(lSimSampleSize)); if not CheckVoxelsGroup(lPartImageNames,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; lPrefs.Run := lSim; if lBinomial then TurboLDM (lPartImageNames, lMaskHdr, lPrefs, lPartSymptomRA, lFactname,lOutNameSim) else begin MainForm.ReportDescriptives(lPartSymptomRA,lnSubj); TurboLDM (lPartImageNames, lMaskHdr, lPrefs, lPartSymptomRA, lFactname,lOutNameSim); {$IFDEF anacom} AnacomLesionNPMAnalyze (lPartImageNames, lMaskHdr, lnCrit,lSim,lnControlObservations, lPartSymptomRA,lControlSymptomRA, lFactname,lOutNameSim,true,false); {$ENDIF} end; end; //for each simulation... Freemem(lSymptomRA); end; //lnsubj > 1 end; //for each factor if lnSubjAll > 0 then begin Freemem(lMultiSymptomRA); end; 666: lPartImageNames.free; lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; freemem(lPartSymptomRA); {$IFDEF anacom} freemem(lControlSymptomRA); {$ENDIF} DeleteDecompressed4D(lTemp4D); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/Mat.pas��������������������������������������������������0000755�0001750�0001750�00000244524�11326425446�017432� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit Mat; { Basic Matrix Unit for Delphi, May 1996. Implemented using original iMAP C matrix library } { Use this instead of matrix } interface Uses SysUtils, Classes, Vector,dialogs; //var gMat: boolean = false; type EMatrixError = class (Exception); EMatrixSizeError = class (EMatrixError); ESingularMatrix = class (EMatrixError); ENonSquareMatrix = class (EMatrixError); TMatError = (Singular, NonSingular, NonSquare); { A Matrix is made up of a set of rows of type TRow, pTRow is a pointer to a single row and a matrix is a row of pTRows, this allows arrays larger then 65K to be built, the max size of a matrix is roughly 4096 MBytes } MatRA = array [1..1] of Double; Matp = ^MatRA; { forward declare the Matrix class } TMatrix = class; { Used by svdfit, supplies basis functions at x } BasisProc = procedure (x : TMatElement; var BasisFunc : TVector); { Define a dynamic matrix type for holding doubles } TMatrix = class (TObject) private nr, nc : integer; mx :matp;//: pTRowList; { pointer to a list of rows } procedure SetSize (ri, ci : integer); procedure FreeSpace; public constructor create (r, c : integer); overload; virtual; constructor create (n : integer); overload; virtual; constructor create (c : integer; d : array of TMatElement); overload; virtual; destructor destroy; override; procedure Setval (ri, ci : integer; v : TMatElement); function Getval (ri, ci : integer) : TMatElement; property M[x, y : Integer] : TMatElement read GetVal write SetVal; default; property r : integer read nr; property c : integer read nc; function IsSquare : boolean; function SameDimensions (m1, m2 : TMatrix) : boolean; function Identity : TMatrix; function Diagonal (k : TMatElement) : TMatrix; overload; function Diagonal (v : TVector) : TMatrix; overload; function Zero : TMatrix; function Ones : TMatrix; function L (ci :integer; d : array of TMatElement) : TMatrix; function transpose : TMatrix; overload; function transpose (m1 : TMatrix) : TMatrix; overload; function add (m1, m2 : TMatrix) : TMatrix; overload; function add (m1 : TMatrix) : TMatrix; overload; function sub (m1, m2 : TMatrix) : TMatrix; overload; function sub (m1 : TMatrix) : TMatrix; overload; function mult (m1 : TMatrix; k : TMatElement) : TMatrix; overload; function mult (k : TMatElement) : TMatrix; overload; function mult (m1, m2 : TMatrix) : TMatrix; overload; function copy (m1 : TMatrix) : TMatrix; procedure ExtractColumn (var v : TVector; cc : integer); procedure ExtractRow (var v : TVector; rr : integer); function ExchangeRows (r1, r2 : integer) : TMatrix; function ExchangeCols (c1, c2 : integer) : TMatrix; function Rank (echelon : TMatrix; eps : double) : integer; procedure Invert (inv : TMatrix); overload; procedure Invert; overload; procedure Invert2 (var dest, src : TMatrix; var col: TVector; var index : TVectori); function Det2 (m1 : TMatrix; var index : TVectori; var v : TVector): double; procedure SolveLinear (v, b : TVector; SelfToInv : boolean); procedure LUSolve (index : TVectori; b : TVector); procedure LUDecomp (m1 : TMatrix; index : TVectori); procedure LUDecomp2 (var m1 : TMatrix; var index : TVectori; var v : TVector); function MatMax: double; function MatAbsMax: double; function Det : double; procedure NullSpace (var NullVectors : TMatrix; var BasisSize : integer; var Echelon : TMatrix; var TheRank : integer); procedure svd (var u : TMatrix; var w : TVector; var v : TMatrix); procedure svd2 (var u : TMatrix; var w : TVector; var v : TMatrix); procedure svdSolve (var u : TMatrix; var w : TVector; var v : TMatrix; b : TVector; var x : TVector); function svdfit (x, y, yerr : TVector; var fit : TVector; var u, v : TMatrix; var w : TVector; funcs : BasisProc): TMatElement; procedure svdCovar (v : TMatrix; w : TVector; alpha : TMatrix); procedure eliminate_cms (S, Tk1 : TMatrix; var cr, N : integer); procedure ElementaryModes (D : TVectori; var mf, mb, C1, k : integer; Tk : TMatrix); class procedure Tableau (N, R1 : integer; var mf, mb, C1, k : integer; Tk, Tk1 : TMatrix); class function grecodiv_of_vector (N, R1 : integer; vec : TVector) : integer; class function grecodiv(P, Rest: integer) : integer; procedure Conserve(st : TMatrix); end; { ------------------------------------------------------------------------- } implementation const MATERROR = 'Matrix Operation Error:'; { ------------------------------------------------------------------------- } { START OF MATRIX IMPLEMETATION } { ------------------------------------------------------------------------- } { ------------------------- Constructors first ---------------------------- } { ******************************************************************** } { Usage: A := TMatrix.create (3, 2); } { ******************************************************************** } constructor TMatrix.create (r, c : integer); begin Inherited Create; nr := 0; nc := 0; mx := Nil; Self.SetSize (r, c); end; { ******************************************************************** } { Create an identity matrix } { } { Usage: A := TMatrix.createI (3); } { ******************************************************************** } constructor TMatrix.create (n : integer); var i : integer; begin Inherited Create; nr := 0; nc := 0; mx := Nil; Self.SetSize (n, n); for i := 1 to n do Self[i,i] := 1.0; end; { ******************************************************************** } { Create a matrix filled with values from array d given that the } { number of columns equals c. } { } { Usage: A := TMatrix.createLit (2, [1, 2, 3, 4]); } { Creates a 2 by 2 array } { ******************************************************************** } constructor TMatrix.create (c : integer; d : array of TMatElement); var i, j, ri, count : integer; begin Inherited Create; nr := 0; nc := 0; mx := Nil; ri := (High(d)+1) div c; Self.SetSize (ri, c); count := 0; for i := 1 to ri do for j := 1 to c do begin Self[i,j] := d[count]; inc (count); end; end; { ******************************************************************** } { Usage: A.destroy, use a.free in a program } { ******************************************************************** } destructor TMatrix.destroy; begin FreeSpace; Inherited Destroy; end; { Free the data space but not the object } procedure TMatrix.FreeSpace; //var i : integer; begin if mx <> Nil then begin FreeMem (mx); mx := Nil; end; end; { Internal routine used set size of matrix and allocate space } procedure TMatrix.SetSize (ri, ci : integer); //var i : integer; begin if (mx <> Nil) and ((ri*ci)= (nr*nc) ) then begin nr := ri; nc := ci; exit; end; //if gMat then beep; FreeSpace; nr := ri; nc := ci; //if gMat then beep; Getmem(mx,ri*ci*sizeof(TMatElement));//AllocMem (sizeof (pTRowList) * (nr+1)); { r+1 so that I can index from 1 } end; { ---------------------------------------------------------------------------- } { BASIC ROUTINES } { ---------------------------------------------------------------------------- } { ******************************************************************** } { Used internally but is also accessible from the outside } { } { Normal Usage: A[2, 3] := 1.2; } { } { ******************************************************************** } procedure TMatrix.Setval (ri, ci : integer; v : TMatElement); begin if ri > r then raise EMatrixSizeError.Create ('ri index out of range: ' + inttostr (ri)); if ci > c then raise EMatrixSizeError.Create ('ci index out of range: ' + inttostr (ci)); mx^[ri + ((ci-1)* r )] := v; end; { ******************************************************************** } { Used internally but is also accessible from the outside } { } { Normal Usage: d := A[2, 3]; } { } { ******************************************************************** } function TMatrix.Getval (ri, ci : integer) : TMatElement; begin result := mx^[ri + ((ci-1)* r )]; end; { ******************************************************************** } { Fill an existing matrix with the array d of numbers. ci equals } { the number of columns. } { } { Usage: A.L(3, [1, 2, 3, 4, 5, 6, 7, 8, 9]); } { } { ******************************************************************** } function TMatrix.L (ci :integer; d : array of TMatElement) : TMatrix; var i, j, ri, count : integer; begin ri := (High(d)+1) div ci; FreeMem (mx, sizeof (TMatElement) * nr * nc); Self.SetSize (ri, ci); count := 0; for i := 1 to ri do for j := 1 to ci do begin Self[i,j] := d[count]; inc (count); end; result := Self; end; { ******************************************************************** } { Set all elements to one } { } { Usage: A.Ones; } { } { ******************************************************************** } function TMatrix.Ones : TMatrix; var i, j : integer; begin for i := 1 to r do for j := 1 to c do Self[i,j] := 1.0; result := Self; end; { ******************************************************************** } { Zero the Self matrix } { } { Usage: A.Zero; } { } { ******************************************************************** } function TMatrix.Zero : TMatrix; var i, j : integer; begin for i := 1 to r do for j := 1 to c do Self[i,j] := 0.0; result := Self; end; { ******************************************************************** } { Returns true if matrices m1 and m2 have the same dimensions } { } { Usage: if SameDimensions (A, B) then } { } { ******************************************************************** } function TMatrix.SameDimensions (m1, m2 : TMatrix) : boolean; begin result := (m1.nr = m2.nr) and (m1.nc = m2.nc); { use nr, nc for direct access } end; { ******************************************************************** } { Returns true if matrix m is square } { } { Usage: if IsSquare then } { } { ******************************************************************** } function TMatrix.IsSquare : boolean; begin result := Self.nr = Self.nc; end; { ******************************************************************** } { Turn the matrix Self into an identify matrix } { } { Usage: A.Identity } { } { ******************************************************************** } function TMatrix.Identity : TMatrix; var i : integer; begin if Self.IsSquare then begin Self.Zero; for i := 1 to r do Self[i,i] := 1.0; result := Self; end else raise EMatrixSizeError.Create ('An identity matrix can only be formed from a square matrix'); end; { ******************************************************************** } { Make the matrix object a diagonal matrix with the value, k } { } { Usage: A.Diagonal (3.1415); } { } { ******************************************************************** } function TMatrix.Diagonal (k : TMatElement) : TMatrix; var i : integer; begin if Self.IsSquare then begin Self.Zero; for i := 1 to r do Self[i,i] := k; result := Self; end else raise EMatrixSizeError.Create ('Can only form a diagonal matrix from a square matrix'); end; { ******************************************************************** } { This forms a diagonal matrix from the elements of vector v. } { } { Usage: A.Diagonal (v) } { } { ******************************************************************** } function TMatrix.Diagonal (v : TVector) : TMatrix; var i : integer; begin if Self.IsSquare then begin if v.size = Self.nr then begin Self.zero; for i := 1 to r do Self[i,i] := v[i]; result := Self; end else raise EMatrixSizeError.Create ('Vector must be same size as matrix in DiagonalV'); end else raise EMatrixSizeError.Create ('Can only form a diagonal matrix from a square matrix'); end; { ******************************************************************** } { Transpose matrix 'Self', Self is thus destroyed and replaced } { } { Usage: A.transpose } { } { ******************************************************************** } function TMatrix.Transpose : TMatrix; var i, j : integer; tmp : TMatrix; begin if (r=1) or (c=1) then begin i := nr; nr := nc; nc := i; exit; end; tmp := TMatrix.create (c, r); try for i := 1 to r do for j := 1 to c do tmp [j,i] := Self[i,j]; Self.FreeSpace; Self.SetSize (tmp.nr, tmp.nc); { move data from transpose to Self } Self.Copy (tmp); finally tmp.Destroy; end; result := Self; end; { ******************************************************************** } { Transpose the matrix 'm' into Self } { } { Usage: T.transpose (A); Tranposes A and puts result into T } { Will also accept T.transpose (T) } { ******************************************************************** } function TMatrix.Transpose (m1 : TMatrix) : TMatrix; var i, j : integer; t : TMatrix; begin if (m1.r <> Self.c) and (m1.c <> Self.r) then raise EMatrixSizeError.Create ('Destination matrix has incorrect dimensions for transpose'); { If the user is trying to transpose itself.... } if Self = m1 then begin t := TMatrix.Create (r, c); try t.Copy (m1); for i := 1 to m1.r do for j := 1 to m1.c do Self[j,i] := t[i,j]; finally t.free; result := Self; end; exit; end; for i := 1 to m1.r do for j := 1 to m1.c do Self[j,i] := m1[i,j]; result := Self; end; { ******************************************************************** } { Copy matrix 'm' to Self, Self must exist and is overwritten } { in the process. This procedure does a fast deep copy of the matrix. } { } { Usage: B.Copy (A); performs the operation: B = A with deep copy } { } { ******************************************************************** } function TMatrix.Copy (m1 : TMatrix) : TMatrix; begin if ( r<> m1.r) or (c <> m1.c) then begin (*if r <> m.r then raise EMatrixSizeError.Create (MATERROR + #13#10'Cannot copy matrices with different sized rows: dest<' + inttostr (r) + '> src<' + inttostr (m.r) + '>') else raise EMatrixSizeError.Create (MATERROR + #13#10'Cannot copy matrices with different sized columns: dest<' + inttostr (c) + '> src<' + inttostr (m.c) + '>'); *) SetSize (self.r, self.c); end; { Copy a whole row at a time using move } //for i := 1 to r do move (m.mx^[i]^, Self.mx^[i]^, sizeof(TMatElement) * (c+1)); move(m1.mx^,self.mx^,r*c*sizeof(double)); // Copy over column and row names, clear destination first then copy result := Self; end; { ******************************************************************** } { Extract column cc from the Self matrix and return it as a TVector } { } { Usage: m.ExtractColumn (v, 1) extract column 1 from m and place in v} { } { ******************************************************************** } procedure TMatrix.ExtractColumn (var v : TVector; cc : integer); var i : integer; begin v.freeSpace; v.SetSize (Self.r); { Create result vector of appropriate size } for i := 1 to Self.r do v[i] := Self[i, cc]; end; { ******************************************************************** } { Extract rwo rr from the Self matrix and return it as a TVector } { } { Usage: m.ExtractRow (v, 1) extract row 1 from m and place in v } { } { ******************************************************************** } procedure TMatrix.ExtractRow (var v : TVector; rr : integer); var i : integer; begin v.freespace; v.SetSize (Self.c); for i := 1 to Self.c do v[i] := Self[rr, i]; end; { ******************************************************************** } { Add matrix 'm' to Self, giving a new Self } { } { Usage: A.addU (B); add B to A, giving A } { } { ******************************************************************** } function TMatrix.add (m1 : TMatrix) : TMatrix; var i, j : integer; begin if Not SameDimensions (m1, Self) then raise EMatrixSizeError.Create ('Incorrectly sized result matrix for matrix addition'); for i := 1 to r do for j := 1 to c do Self[i,j] := Self[i,j] + m1[i,j]; result := Self; end; { ******************************************************************** } { Add matrix 'm1' and 'm2' and assign to Self } { } { Usage: A.add (A1, A2); add A1 to A2 giving A } { } { ******************************************************************** } function TMatrix.add (m1, m2 : TMatrix) : TMatrix; var i, j : integer; begin if Not SameDimensions (m1, m2) then raise EMatrixSizeError.Create ('Incompatible matrix operands to add'); if Not SameDimensions (m1, Self) then raise EMatrixSizeError.Create ('Incorrectly sized result matrix for matrix addition'); for i := 1 to r do for j := 1 to c do Self[i,j] := m1[i,j] + m2[i,j]; result := Self; end; { ******************************************************************** } { Subtract matrix m from Self giving a new Self } { } { Usage: A.subU (B); subtract B from A giving A } { } { ******************************************************************** } function TMatrix.sub (m1 : TMatrix) : TMatrix; var i, j : integer; begin if Not SameDimensions (m1, Self) then raise EMatrixSizeError.Create ('Incorrecly sized result matrix for matrix subtraction'); for i := 1 to r do for j := 1 to c do Self[i,j] := Self[i,j] - m1[i,j]; result := Self; end; { ******************************************************************** } { Subtract m2 from m1 giving Self } { } { Usage: A.sub (A1, A2); subtract A2 from A1 giving A (A = A2 - A1) } { } { ******************************************************************** } function TMatrix.sub (m1, m2 : TMatrix) : TMatrix; var i, j : integer; begin if Not SameDimensions (m1, m2) then raise EMatrixSizeError.Create ('Incompatible matrix operands to subtract'); if Not SameDimensions (m1, Self) then raise EMatrixSizeError.Create ('Incorrectly sized result matrix for matrix subtraction'); for i := 1 to r do for j := 1 to c do Self[i,j] := m1[i,j] - m2[i,j]; result := Self; end; { ******************************************************************** } { Multiply a matrix 'm' by scalar constant k and assign result to Self } { } { Usage: A.multk (B, 0.5); multiply scalar, 0.5 by B giving A } { } { ******************************************************************** } function TMatrix.mult (m1 : TMatrix; k : TMatElement) : TMatrix; var i, j : integer; begin for i := 1 to m1.r do for j := 1 to m1.c do Self[i, j] := m1[i,j] * k; result := Self; end; { ******************************************************************** } { Multiply the Self matrix by the scalar constant k } { } { Usage: A.multKU (0.5); multiply scalar 0.5 by A giving A } { } { ******************************************************************** } function TMatrix.mult (k : TMatElement) : TMatrix; var i, j : integer; begin for i := 1 to r do for j := 1 to c do Self[i, j] := Self[i,j] * k; result := Self; end; { ******************************************************************** } { Multiply matrix 'm1' by 'm2' to give result in Self } { } { Usage: A.mult (A1, A2); multiply A1 by A2 giving A } { } { ******************************************************************** } function TMatrix.mult (m1, m2 : Tmatrix) : TMatrix; var i, j, k, m1_Col : integer; sum : TMatElement; begin if m1.c = m2.r then begin m1_col := m1.c; for i := 1 to Self.r do for j := 1 to Self.c do begin sum := 0.0; for k := 1 to m1_Col do sum := sum + m1[i, k]* m2[k, j]; Self[i,j] := sum; end; result := Self; end else raise EMatrixSizeError.Create ('Incompatible matrix operands to multiply'); end; { ******************************************************************** } { LU Solve. Solve the linear system represented by m and right-hand } { side b m is assumed have have been decomposed by LUDecomp } { } { Usage: m.LUSolve (index, b) } { } { ******************************************************************** } procedure TMatrix.LUSolve (index : TVectori; b : TVector); var i, j, ii, ip, nRows : integer; sum : TMatElement; begin ii := 0; nRows := r; for i := 1 to nRows do begin ip := index[i]; sum := b[ip]; b[ip] := b[i]; if ii <> 0 then for j := ii TO i-1 do sum := sum - Self[i,j]*b[j] else if sum <> 0.0 then ii := i; b[i] := sum; end; for i := nRows downto 1 do begin sum := b[i]; if i < nRows then for j := i+1 to nRows do sum := sum - Self[i,j]*b[j]; b[i] := sum/Self[i,i]; end end; { ******************************************************************** } { Form LU decomposition of Self matrix. Result goes into m } { } { Usage: m.LUDecomp(result, index); } { } { ******************************************************************** } procedure TMatrix.LUDecomp (m1 : TMatrix; index : TVectori); var v : TVector; i, k, j, imax, nRows : integer; sum, big, tmp : TMatElement; begin if Self.r = m1.c then begin m1.Copy (Self); v := TVector.Create (m1.r); try { Find the largest element in every row, and store its reciprocal in v[i] } nRows := m1.r; for i := 1 to nRows do begin big := 0.0; { needed to test for singularity } { Although we're working across columns we can use nRows since m1 is square } for j := 1 to nRows do if (abs(m[i,j]) > big) then big := abs(m[i,j]); if big = 0.0 then raise ESingularMatrix.Create ('LUDecomp: Singular matrix in LUDecomp, found row of zeros'); v[i] := 1.0/big end; for j := 1 TO nRows do begin { Form beta = aij - sum_k=1^i-1 aik * bkj } for i := 1 TO j-1 do begin sum := m[i,j]; for k := 1 to i-1 do sum := sum - m[i,k]*m[k,j]; m[i,j] := sum end; big := 0.0; for i := j to nRows do begin sum := m[i,j]; for k := 1 to j-1 do sum := sum - m[i,k]*m[k,j]; m[i,j] := sum; if v[i]*abs(sum) >= big then begin big := v[i]*abs(sum); imax := i end end; { Interchange rows if necessary } if j <> imax then begin { Swap row names aswell } for k := 1 to nRows do begin tmp := m[imax,k]; m[imax,k] := m[j,k]; m[j,k] := tmp end; v[imax] := v[j] end; index[j] := imax; { Get ready to divide by pivot element } if m[j,j] = 0.0 then raise ESingularMatrix.Create ('LUDecomp: Singular Matrix, pivot value is zero'); if j <> nRows then begin tmp := 1.0/m[j,j]; for i := j+1 to nRows do m[i,j] := m[i,j]*tmp end end; finally v.destroy; end; end else raise ENonSquareMatrix.Create ('LUDecomp: Matrix must be square'); end; //return max value in a matrix function TMatrix.MatMax : double; var i,j : integer; begin if (r < 1) or (c<1) then begin result := 0; exit; end; result := m[1,1]; for i := 1 to r do for j := 1 to c do if m[i, j] > result then result := m[i,j]; end; //return max value in a matrix function TMatrix.MatAbsMax : double; var i,j : integer; begin if (r < 1) or (c<1) then begin result := 0; exit; end; result := abs(m[1,1]); for i := 1 to r do for j := 1 to c do if abs(m[i, j]) > result then result := abs(m[i,j]); end; { ******************************************************************** } { Find determinant of matrix } { } { Usage: d := m.det } { } { ******************************************************************** } function TMatrix.Det : double; var m1 : TMatrix; index : TVectori; i : integer; begin result := 1; if r = c then begin index := TVectori.Create (r); m1 := TMatrix.Create (r,r); try m1.copy (Self); Self.LUDecomp (m1, index); for i := 1 to r do result := result * m1[i,i]; finally m1.free; index.free; end; end else raise ENonSquareMatrix.Create ('Determinant: Matrix must be square'); end; (*procedure wMatrix( lTitle: string; A : TMatrix); var lR,lC: integer; lStr: string; begin if (A.r < 1) or (A.c < 1) then exit; lStr := (lTitle)+chr($0D)+chr($0A); for lR := 1 to (A.r) do begin for lC := 1 to (A.c) do lStr := lStr + floattostr(A.Getval(lr, lc))+' '; lStr := lStr + chr($0D)+chr($0A); end; //each row showmessage(lStr); end;*) procedure TMatrix.LUDecomp2 (var m1 : TMatrix; var index : TVectori; var v : TVector); var i, k, j, imax, nRows : integer; sum, big, tmp : TMatElement; begin if Self.r = m1.c then begin m1.Copy (Self); //wmatrix('m1',m1); //v := TVector.Create (m.r); try { Find the largest element in every row, and store its reciprocal in v[i] } nRows := m1.r; for i := 1 to nRows do begin big := 0.0; { needed to test for singularity } { Although we're working across columns we can use nRows since m1 is square } for j := 1 to nRows do if (abs(m1[i,j]) > big) then big := abs(m1[i,j]); if big = 0.0 then raise ESingularMatrix.Create ('LUDecomp: Singular matrix in LUDecomp, found row of zeros'); v[i] := 1.0/big end; for j := 1 TO nRows do begin { Form beta = aij - sum_k=1^i-1 aik * bkj } for i := 1 TO j-1 do begin sum := m1[i,j]; for k := 1 to i-1 do sum := sum - m1[i,k]*m1[k,j]; m1[i,j] := sum end; big := 0.0; for i := j to nRows do begin sum := m1[i,j]; for k := 1 to j-1 do sum := sum - m1[i,k]*m1[k,j]; m1[i,j] := sum; if v[i]*abs(sum) >= big then begin big := v[i]*abs(sum); imax := i end end; { Interchange rows if necessary } if j <> imax then begin { Swap row names aswell } for k := 1 to nRows do begin tmp := m1[imax,k]; m1[imax,k] := m1[j,k]; m1[j,k] := tmp end; v[imax] := v[j] end; index[j] := imax; { Get ready to divide by pivot element } if m1[j,j] = 0.0 then raise ESingularMatrix.Create ('LUDecomp: Singular Matrix, pivot value is zero'); if j <> nRows then begin tmp := 1.0/m1[j,j]; for i := j+1 to nRows do m1[i,j] := m1[i,j]*tmp end end; finally //v.destroy; end; end else raise ENonSquareMatrix.Create ('LUDecomp: Matrix must be square'); end; function TMatrix.Det2 (m1 : TMatrix; var index : TVectori; var v : TVector): double; var i : integer; begin result := 1; if r = c then begin //index := TVectori.Create (r); //m := TMatrix.Create (r,r); try m1.copy (Self); Self.LUDecomp2 (m1, index,v); for i := 1 to r do result := result * m1[i,i]; finally //m.free; index.free; end; end else raise ENonSquareMatrix.Create ('Determinant: Matrix must be square'); end; { ******************************************************************** } { Solve a linear system of equations: Self.v = b, i.e solve for v } { } { Usage: A.SolveLinear (v, b, t); } { Solution in v } { If the boolean t is true then self is replaced by the inverse } { ******************************************************************** } procedure TMatrix.SolveLinear (v, b : TVector; SelfToInv : boolean); var n, i, j : integer; indx : TVectori; col : TVector; dest, src : TMatrix; begin if Self.r = Self.c then begin n := Self.r; { Make a copy and work on the copy } dest := TMatrix.Create (n, n); src := TMatrix.Create (n, n); indx := TVectori.Create (n); try src.Copy (Self); for i := 1 to n do v[i] := b[i]; src.LUDecomp (dest, indx); dest.LUSolve (indx, v); if SelfToInv then begin col := TVector.Create (n); try for j := 1 to n do begin for i := 1 to n do col[i] := 0.0; col[j] := 1.0; dest.LUSolve (indx, col); for i := 1 to n do Self[i,j] := col[i]; end; finally col.free; end; end; finally indx.destroy; dest.destroy; src.destroy; end; end else raise ENonSquareMatrix.Create ('SolveLinear: Matrix must be square'); end; { ******************************************************************** } { Fast method for inverting a matrix (Self) } { Result in inv } { } { Usage: A.Invert (inv); } { ******************************************************************** } procedure TMatrix.Invert2 (var dest, src : TMatrix; var col: TVector; var index : TVectori); var n, i, j : integer; begin n := Self.r; try src.Copy (Self); try //wmatrix('w1',src); src.LUDecomp2 (dest, index,col); //wmatrix('w2',src); except on ESingularMatrix do raise ESingularMatrix.Create ('Invert: Singular Matrix'); end; for j := 1 to n do begin for i := 1 to n do col[i] := 0.0; col[j] := 1.0; dest.LUSolve (index, col); for i := 1 to n do Self[i,j] := col[i]; end; finally //col.destroy; dest.destroy; src.destroy; index.destroy; end; end; procedure TMatrix.Invert (inv : TMatrix); var col : TVector; n, i, j : integer; dest, src : TMatrix; indx : TVectori; begin n := Self.r; col := TVector.Create (n); dest := TMatrix.Create (n, n); src := TMatrix.Create (n, n); indx := TVectori.Create (n); try src.Copy (Self); try src.LUDecomp (dest, indx); except on ESingularMatrix do raise ESingularMatrix.Create ('Invert: Singular Matrix'); end; for j := 1 to n do begin for i := 1 to n do col[i] := 0.0; col[j] := 1.0; dest.LUSolve (indx, col); for i := 1 to n do inv[i,j] := col[i]; end; finally col.destroy; dest.destroy; src.destroy; indx.destroy; end; end; { ******************************************************************** } { Fast method for inverting a matrix (Self) } { Result in Self } { } { Usage: A.Invert } { ******************************************************************** } procedure TMatrix.Invert; var col : TVector; n, i, j : integer; dest, src : TMatrix; index : TVectori; begin n := Self.r; col := TVector.Create (n); dest := TMatrix.Create (n, n); src := TMatrix.Create (n, n); index := TVectori.Create (n); try src.Copy (Self); try src.LUDecomp (dest, index); except on ESingularMatrix do raise ESingularMatrix.Create ('Invert: Singular Matrix'); end; for j := 1 to n do begin for i := 1 to n do col[i] := 0.0; col[j] := 1.0; dest.LUSolve (index, col); for i := 1 to n do Self[i,j] := col[i]; end; finally col.destroy; dest.destroy; src.destroy; index.destroy; end; end; { Internal routine that sets any values less than eps to 0.0 } procedure CleanUpMatrix (m : TMatrix; eps : double); var i, j, ri, ci : integer; begin { Removes all numbers close to zero, i.e between -eps and +eps } ri := m.r; ci := m.c; for i := 1 to ri do for j := 1 to ci do if abs (m [i, j]) < eps then m [i, j] := 0.0; end; { Internal routine to work out the rank of a matrix given the reduced row-echelon } function ComputeRank (m : TMatrix; eps : double) : integer; var i, j, ri, ci, rank : integer; begin ri := m.r; ci := m.c; { find the rank - brute force algorithm } rank := 0; { search row by row for zero rows } for i := 1 to ri do begin { search along the row looking for nonzero entry } for j := 1 to ci do if abs (m [i, j]) > eps then begin inc (rank); break; end; end; result := rank; end; { ******************************************************************** } { Routine to exchange two rows, r1 and r2 in matrix Self } { } { Usage: A.exchangeRows (1, 2); } { } { ******************************************************************** } function TMatrix.ExchangeRows (r1, r2 : integer) : TMatrix; var ci, i : integer; t : double; begin if (r1 > 0) and (r1 <= Self.r) and (r2 > 0) and (r2 <= Self.r) then begin ci := Self.c; for i := 1 to ci do begin t := Self[r1, i]; Self[r1, i] := Self[r2, i]; Self[r2, i] := t; end; result := Self; end else raise EMatrixSizeError.Create ('Rows not in range for exchange'); end; { ******************************************************************** } { Routine to exchange two columns, c1 and c2 in matrix Self } { } { Usage: A.exchangeCols (1, 2); } { } { ******************************************************************** } function TMatrix.ExchangeCols (c1, c2 : integer) : TMatrix; var ri, i : integer; t : double; begin if (c1 > 0) and (c1 <= Self.c) and (c2 > 0) and (c2 <= Self.c) then begin ri := Self.r; for i := 1 to ri do begin t := Self[c1, i]; Self[c1, i] := Self[c2, i]; Self[c2, i] := t; end; result := Self; end else raise EMatrixSizeError.Create ('Columns not in range for exchange'); end; { ******************************************************************** } { Find the rank r, of the matrix Self, The reduced Row } { echelon is returned in mat. eps is the magnitude of } { the largest number before it is assumed to be zero. } { } { Usage: r := A.Rank (echelon, 1e-8) } { Find the rank of A, place echelon in echelon } { } { ******************************************************************** } function TMatrix.Rank (echelon : TMatrix; eps : double) : integer; var Arow, Acol, i, j, n, m1, RowScan : integer; factor : double; begin echelon.copy (Self); { we work on mat, not Self } if (eps = 0.0) then eps := 1.0E-14; n := echelon.r; m1 := echelon.c; Arow := 1; Acol := 1; repeat { locate a nonzero column } if abs(echelon [Arow, Acol]) <= eps then { i.e equals zero } begin { First entry was zero, therefore work our way down the matrix looking for a nonzero entry, when found, swap it for Arow } RowScan := Arow; repeat { next row } inc (RowScan); { have we reached the end of the rows but we've still got columns left to scan } if (RowScan > n) and (Acol < m1) then begin { reset row counter back to where it was and try next column } RowScan := Arow; inc (Acol); end; { If we've scanned the whole matrix, so lets get out... } if (RowScan > n) then begin CleanUpMatrix (echelon, eps); result := ComputeRank (echelon, eps); exit; end; until abs (echelon [RowScan, Acol]) > eps; { keep searching until non-zero entry found } { We've found a nonzero row entry so swap it with 'Arow' which did have a zero as its entry } echelon.exchangeRows (Arow, RowScan); end; { Arow now holds the row of interest } factor := 1.0/echelon [Arow, Acol]; { reduce all the entries along the column by the factor } for i := Acol to m1 do echelon[Arow,i] := echelon[Arow, i] * factor; { now eliminate all entries above and below Arow, this generates the reduced form } for i := 1 to n do { miss out Arow itself } if (i <> Arow) and (abs (echelon [i, Acol]) > eps) then begin factor := echelon [i, Acol]; { work your way along the column doing the same operation } for j := Acol to m1 do echelon[i,j] := echelon [i, j] - factor * echelon [Arow, j]; end; inc (Arow); inc (Acol); until (Arow > n) or (Acol > m1); CleanUpMatrix (echelon, eps); result := ComputeRank (echelon, eps); { This is just a patch for the moment } end; (* Algorithm 1. Reduce matrix to reduced echelon form 2. There will be as many null space vectors as there are non-leading columns. Select one of these non-leading columns. 3. Select the ith non-leading column and place a 1 at the ith position in the growing null space vector 4. Consider the remaining non-leading columns, say j,k,l... and place zero's at positions j,k,l... in the growing null vector. 5. Consider now the column positions of the leading columns, say l,m,n... The equivalent entries in the growing null space are what remains to be filled in. Select each of these leading columns in turn, say the lth first. Record which row the leading one is in, say r. Then place at position l in the growing null space vector, the element -1 * element (r, i) where i is the original ith non-leading column selected in step 3. Continue for leading columns m,n... until the growing null space vector is complete. 6. Go back to step 2 and pick another non-leading column to compute the next null space vector. Does not disturb the matrix Self. Null space to be found in NullVectors, size of the basis in BasisSize, the reduced row-echelon in Echelon and the rank in TheRank } Usage: A.NullSpace (N, b, Echelon, r); *) procedure TMatrix.NullSpace (var NullVectors : TMatrix; var BasisSize : integer; var Echelon : TMatrix; var TheRank : integer); var eps, x: double; i, j, k : integer; mask : TVectori; tmpNullVectors : TMatrix; VectorCounter, maskcount : integer; minus999, minus888, EchelonCols : integer; begin try eps := 0.000000001; minus999 := -999; { leading column } minus888 := -888; { non-leading column } if NullVectors <> Nil then NullVectors.free; if Echelon <> Nil then Echelon.free; tmpNullVectors := TMatrix.Create (Self.c, Self.c); Echelon := TMatrix.Create (Self.r, Self.c); EchelonCols := Echelon.c; mask := TVectori.create (EchelonCols); // STEP 1 k := Self.Rank (Echelon, eps); TheRank := k; k := Self.c - TheRank; BasisSize := k; if BasisSize > 0 then begin for i := 1 to EchelonCols do mask [i] := minus888; for i := 1 to Echelon.r do begin { scan along columns looking for a leading one } j := 1; repeat x := Echelon[i, j]; if (x > -eps) and (x < eps) then { check if its practically zero } Echelon [i, j] := 0.0; if (x > 1.0-eps) and (x < 1.0+eps) then { x is then = 1.0 } begin mask [j] := minus999; { tag as leading column } j := 0; { exit signal } end else j := j + 1; until (j = 0) or (j > EchelonCols); end; { end row scan } { Find non-leading columns } VectorCounter := 1; i := 1; { i = column counter, check all columns } repeat for j := 1 to EchelonCols do tmpNullVectors[j, VectorCounter] := minus888; { STEP 5 } { remember, all minus888's in mask = non-leading columns } if mask [i] = minus888 then { found a non-leading column } begin j := 1; { move down mask } for maskcount := 1 to EchelonCols do if (mask [maskcount] = minus999) then begin tmpNullVectors[maskcount, VectorCounter] := -Echelon[j, i]; inc (j); end; { STEP 4 } { zero all -888 (free) entries } for j := 1 to EchelonCols do if tmpNullVectors[j, VectorCounter] = minus888 then tmpNullVectors[j, VectorCounter] := 0.0; { STEP 2 AND 3 } { mark free variable } tmpNullVectors[i, VectorCounter] := 1.0; VectorCounter := VectorCounter + 1; end; inc (i); until i > EchelonCols; end else begin BasisSize := 0; NullVectors := Nil; end; finally if BasisSize > 0 then begin NullVectors := TMatrix.Create (Self.c, BasisSize); for i := 1 to Self.c do for j := 1 to BasisSize do NullVectors[i,j] := tmpNullVectors[i,j]; end; mask.free; tmpNullVectors.free; end; end; function sign (a, b : TMatElement) : TMatElement; begin if b >= 0.0 then result := abs (a) else result := -abs(a); end; function max (a, b : TMatElement) : TMatElement; begin if a > b then result := a else result := b; end; { Compute sqrt (a^2 + b^2) using numerically more stable method. If x = sqrt(a^2 + b^2), then, x/a^2 = 1/a^2 sqrt (a^2 + b^2), mult both sides by sqrt(..), so x/a^2 * sqrt (a^2 + b^2) = 1/a^2 (a^2 + b^2) or x/a^2 * sqrt (a^2 + b^2) = 1 + (b/a)^2 but on left side 1/a^2 sqrt(a^2 + b^2) equals x/a^2, therefore x * x/a^2 = 1 + (b/a) ^2, take square roots on both side yields: x/a := sqrt (1+(b/a)^2), or FINALLY: x := a sqrt (1 + (b/a)^2) } function pythag (a, b : TMatElement) : TMatElement; var at, bt, ct : TMatElement; begin result := sqrt (a*a + b*b); exit; at := abs (a); bt := abs (b); if at > bt then begin ct := bt/at; result := at*sqrt (1 + ct*ct); end else begin if bt > 0 then begin ct := at/bt; result := bt*sqrt (1 + ct*ct); end else result := 0.0; end; end; function MyAbs (x : TMatElement) : TMatElement; begin if x < 0.0 then x := -x; result := x; end; {procedure TMatrix.svd2 (var u : TMatrix; var w : TVector; var v : TMatrix);} procedure TMatrix.svd2 (var u : TMatrix; var w : TVector; var v : TMatrix); LABEL 1,2,3; CONST nmax=100; VAR n, m1, nm, l1, k, j, jj, its, i : integer; z, y, x, scale, s, h, g, f, cc, anorm : real; rv1 : TVector; //Aug : TMatrix; AugMatrix : boolean; function sign(a,b: TMatElement): TMatElement; begin if (b >= 0.0) then sign := abs(a) else sign := -abs(a) end; function max(a,b: TMatElement): TMatElement; begin if (a > b) then max := a else max := b end; begin m1 := r; n := c; AugMatrix := false; (*if m < n then begin { More parameters than data ! Change structure of Self by augmenting Self with additional rows (entries set to zero) so that m = n, don't change m or n though } {Aug := TMatrix.Create (n, n); Aug.zero; try for i := 1 to m do for j := 1 to n do Aug[i,j] := Self[i,j]; u.FreeSpace; u.SetSize (n, n); u.Copy (Aug); AugMatrix := true; finally Aug.free; end; end else*) u.Copy(Self); { Work on U, don't destroy Self } if AugMatrix then rv1 := TVector.Create (n) { Make enough room } else rv1 := TVector.Create (m1); { Save some space } g := 0.0; scale := 0.0; anorm := 0.0; FOR i := 1 TO n DO BEGIN l1 := i+1; rv1[i] := scale*g; g := 0.0; s := 0.0; scale := 0.0; IF (i <= m1) THEN BEGIN FOR k := i TO m1 DO scale := scale + Myabs(u[k,i]); IF (Myabs(scale) > 1e-12) THEN BEGIN {IF (scale <> 0.0) THEN BEGIN} for k := i to m1 do begin u[k,i] := u[k,i]/scale; s := s + u[k,i]*u[k,i] end; f := u[i,i]; g := -sign(sqrt(s),f); h := f*g-s; u[i,i] := f-g; if (i <> n) then begin for j := l1 to n do begin s := 0.0; for k := i to m1 do s := s + u[k,i]*u[k,j]; f := s/h; for k := i to m1 do u[k,j] := u[k,j] + f*u[k,i]; end end; for k := i to m1 do u[k,i] := scale*u[k,i] END END; w[i] := scale*g; g := 0.0; s := 0.0; scale := 0.0; IF ((i <= m1) AND (i <> n)) THEN BEGIN for k := l1 to n do scale := scale + Myabs(u[i,k]); if (Myabs(scale) > 1e-12) then begin {if (scale <> 0.0) then begin} for k := l1 to n do begin u[i,k] := u[i,k]/scale; s := s + u[i,k]*u[i,k] end; f := u[i,l1]; g := -sign(sqrt(s),f); h := f*g-s; u[i,l1] := f-g; for k := l1 to n do rv1[k] := u[i,k]/h; if (i <> m1) then begin for j := l1 to m1 do begin s := 0.0; for k := l1 to n do s := s + u[j,k]*u[i,k]; for k := l1 to n do u[j,k] := u[j,k] + s*rv1[k]; end end; for k := l1 to n do u[i,k] := scale*u[i,k]; END END; anorm := max(anorm,(Myabs(w[i]) + Myabs(rv1[i]))) END; FOR i := n DOWNTO 1 DO BEGIN IF (i < n) THEN BEGIN if (Myabs(g) > 1e-12) then {IF (g <> 0.0) THEN} begin for j := l1 to n do v[j,i] := (u[i,j]/u[i,l1])/g; for j := l1 to n do begin s := 0.0; for k := l1 to n do s := s + u[i,k]*v[k,j]; for k := l1 to n do v[k,j] := v[k,j] + s*v[k,i] end end; for j := l1 to n do begin v[i,j] := 0.0; v[j,i] := 0.0; end END; v[i,i] := 1.0; g := rv1[i]; l1 := i end; FOR i := n DOWNTO 1 DO BEGIN l1 := i+1; g := w[i]; if (i < n) then for j := l1 to n do u[i,j] := 0.0; if (Myabs(g) > 1e-12) then {IF (g <> 0.0) THEN} begin g := 1.0/g; IF (i <> n) THEN begin for j := l1 to n do begin s := 0.0; for k := l1 to m1 do s := s + u[k,i]*u[k,j]; f := (s/u[i,i])*g; for k := i to m1 do u[k,j] := u[k,j] + f*u[k,i]; end end; for j := i to m1 do u[j,i] := u[j,i]*g; end else begin for j := i to m1 do u[j,i] := 0.0; end; u[i,i] := u[i,i]+1.0 END; FOR k := n DOWNTO 1 DO BEGIN FOR its := 1 TO 30 DO BEGIN for l1 := k downto 1 do begin nm := l1-1; if ((Myabs(rv1[l1]) + anorm) - anorm < 1e-12) then goto 2; {if ((Myabs(rv1[l]) + anorm) = anorm) then goto 2;} if ((Myabs(w[nm]) + anorm) - anorm < 1e-12) then goto 1 {if ((Myabs(w[nm]) + anorm) = anorm) then goto 1} end; 1: cc := 0.0; s := 1.0; for i := l1 to k do begin f := s*rv1[i]; if ((Myabs(f) + anorm) - anorm > 1e-12) then {if ((Myabs(f)+anorm) <> anorm) then} begin g := w[i]; h := sqrt(f*f+g*g); w[i] := h; h := 1.0/h; cc := (g*h); s := -(f*h); for j := 1 to m1 do begin y := u[j,nm]; z := u[j,i]; u[j,nm] := (y*cc)+(z*s); u[j,i] := -(y*s)+(z*cc) end end end; 2: z := w[k]; if (l1 = k) then begin if (z < 0.0) then begin w[k] := -z; for j := 1 to n do v[j,k] := -v[j,k]; end; GOTO 3 end; if (its = 30) then writeln ('no convergence in 30 SVDCMP iterations'); x := w[l1]; nm := k-1; y := w[nm]; g := rv1[nm]; h := rv1[k]; f := ((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y); g := sqrt(f*f+1.0); f := ((x-z)*(x+z)+h*((y/(f+sign(g,f)))-h))/x; cc := 1.0; s := 1.0; for j := l1 to nm do begin i := j+1; g := rv1[i]; y := w[i]; h := s*g; g := cc*g; z := sqrt(f*f+h*h); rv1[j] := z; cc := f/z; s := h/z; f := (x*cc)+(g*s); g := -(x*s)+(g*cc); h := y*s; y := y*cc; for jj := 1 to n do begin x := v[jj,j]; z := v[jj,i]; v[jj,j] := (x*cc)+(z*s); v[jj,i] := -(x*s)+(z*cc) end; z := sqrt(f*f+h*h); w[j] := z; if (Myabs(z) > 1e-12) then {if (z <> 0.0) then} begin z := 1.0/z; cc := f*z; s := h*z end; f := (cc*g)+(s*y); x := -(s*g)+(cc*y); for jj := 1 to m1 do begin y := u[jj,j]; z := u[jj,i]; u[jj,j] := (y*cc)+(z*s); u[jj,i] := -(y*s)+(z*cc) end end; rv1[l1] := 0.0; rv1[k] := f; w[k] := x END; 3: END END; { Perform a Singular Value Decompostion on self, returning u, w, and v, modified from Numerical Recipes and Forsythe et al 1977, Computer methods for Math Calc } procedure TMatrix.svd (var u : TMatrix; var w : TVector; var v : TMatrix); label 3; var i, j, k, l1, n, m1, its, flag, nm, jj : integer; rv1 : TVector; scale, g, h, f, anorm, s, cc, x, y, z : TMatElement; Aug : TMatrix; AugMatrix : boolean; begin m1:= r; n := c; AugMatrix := false; if m1 < n then begin { More parameters than data ! Change structure of Self by augmenting Self with additional rows (entries set to zero) so that m = n, don't change m or n though } Aug := TMatrix.Create (n, n); Aug.zero; try for i := 1 to m1 do for j := 1 to n do Aug[i,j] := Self[i,j]; u.FreeSpace; u.SetSize (n, n); u.Copy (Aug); AugMatrix := true; finally Aug.free; end; end else u.Copy(Self); { Work on U, don't destroy Self } scale := 0.0; g := 0.0; anorm := 0.0; if AugMatrix then rv1 := TVector.Create (n) { Make enough room } else rv1 := TVector.Create (m1); { Save some space } try for i := 1 to n do begin l1 := i + 1; rv1[i] := scale * g; g := 0.0; s := 0.0; scale := 0.0; if i <= m1 then begin for k := i to m1 do scale := scale + abs (u[k,i]); if scale <> 0.0 then begin for k := i to m1 do begin u[k, i] := u[k, i] / scale; s := s + u[k,i]*u[k,i]; end; f := u[i,i]; g := -sign (sqrt (s), f); h := f*g - s; u[i,i] := f - g; if i <> n then begin for j := l1 to n do begin s := 0.0; for k := i to m1 do s := s + u[k,i]*u[k,j]; f := s/h; for k := i to m1 do u[k,j] := u[k,j] + f*u[k,i]; end; end; for k := i to m1 do u[k,i] := u[k,i] * scale; end; end; w[i] := scale * g; g := 0.0; s := 0.0; scale := 0.0; if (i <= m1) and (i <> n) then begin for k := l1 to n do scale := scale + abs (u[i,k]); if scale <> 0.0 then begin for k := l1 to n do begin u[i,k] := u[i,k] / scale; s := s + u[i,k]*u[i,k]; end; f := u[i,l1]; g := -sign(sqrt (s), f); h := f*g - s; u[i,l1] := f - g; for k := l1 to n do rv1[k] := u[i,k]/h; if i <> m1 then begin for j := l1 to m1 do begin s := 0.0; for k := l1 to n do s := s + u[j,k]*u[i,k]; for k := l1 to n do u[j,k] := u[j,k] + s*rv1[k]; end; end; for k := l1 to n do u[i,k] := u[i,k] * scale; end; end; anorm := max (anorm, abs(w[i]) + abs(rv1[i])); end; { ------------------------------------------ } { Accumulation of right-hand transformations } for i := n downto 1 do begin if i < n then begin if g <> 0.0 then begin for j := l1 to n do v[j,i] := (u[i,j]/u[i,l1])/g; for j := l1 to n do begin s := 0.0; for k := l1 to n do s := s + u[i,k]*v[k,j]; for k := l1 to n do v[k,j] := v[k,j] + s*v[k,i]; end; end; for j := l1 to n do begin v[i,j] := 0.0; v[j,i] := 0.0; end; end; v[i,i] := 1.0; g := rv1[i]; l1 := i; end; { ------------------------------------------ } { Accumulation of left-hand transformations } for i := n downto 1 do begin l1 := i + 1; g := w[i]; if i < n then for j := l1 to n do u[i,j] := 0.0; if g <> 0.0 then begin g := 1.0/g; if i <> n then begin for j := l1 to n do begin s := 0.0; for k := l1 to m1 do s := s + u[k,i]*u[k,j]; f := (s/u[i,i])*g; for k := i to m1 do u[k,j] := u[k,j] + f*u[k,i]; end; end; for j := i to m1 do u[j,i] := u[j,i] * g; end else begin for j := i to m1 do u[j,i] := 0.0; end; u[i,i] := u[i,i] + 1.0; end; { --------------------------------------------- } { Diagonalization of the bidiagonal form } for k := n downto 1 do begin for its := 1 to 30 do begin flag := 1; for l1 := k downto 1 do begin nm := l1 - 1; if abs (rv1[l1] + anorm) = anorm then begin flag := 0; break; end; if abs (w[nm] + anorm) = anorm then break; end; if flag <> 0 then begin cc := 0.0; s := 1.0; for i := l1 to k do begin f := s * rv1[i]; if (abs (f) + anorm) <> anorm then begin g := w[i]; h := pythag (f, g); w[i] := h; h := 1.0/h; cc := g*h; s := -f*h; for j := 1 to m1 do begin y := u[j,nm]; z := u[j, i]; u[j,nm] := y*cc + z*s; u[j,i] := z*cc - y*s; end; end; end; end; z := w[k]; if l1 = k then begin if z < 0.0 then begin w[k] := -z; for j := 1 to n do v[j,k] := -v[j,k]; end; {break;} goto 3; end; if (its = 30) then raise Exception.Create ('Exceeded iterations in SVD routine'); x := w[l1]; nm := k - 1; y := w[nm]; g := rv1[nm]; h := rv1[k]; f := ((y - z)*(y + z) + (g - h)*(g + h))/(2.0*h*y); g := pythag (f, 1.0); f := ((x - z) * (x + z) + h*((y/(f + sign(g, f))) - h))/x; cc := 1.0; s := 1.0; for j := l1 to nm do begin i := j + 1; g := rv1[i]; y := w[i]; h := s*g; g := cc*g; z := pythag (f, h); rv1[j] := z; cc := f/z; s := h/z; f := x*cc + g*s; g := g*cc - x*s; h := y*s; y := y*cc; for jj := 1 to n do begin x := v[jj,j]; z := v[jj,i]; v[jj,j] := x*cc + z*s; v[jj,i] := z*cc - x*s; end; z := pythag (f, h); w[j] := z; if z <> 0 then begin z := 1.0/z; cc := f*z; s := h*z; end; f := (cc*g) + (s*y); x := (cc*y) - (s*g); for jj := 1 to m1 do begin y := u[jj,j]; z := u[jj,i]; u[jj,j] := y*cc + z*s; u[jj,i] := z*cc - y*s; end; end; rv1[l1] := 0.0; rv1[k] := f; w[k] := x; 3: end; end; finally rv1.free; end; if AugMatrix then begin { This means that originally m < n, therefore u has some junk rows, remove them here } Aug := TMatrix.Create (m1, n); try for i := 1 to m1 do for j := 1 to n do Aug[i,j] := u[i,j]; u.FreeSpace; u.SetSize (m1, n); u.Copy (Aug); finally Aug.free; end; end; end; { Call this after having called svd, computes x = V [diag (1/wj)]. U^t.b } procedure TMatrix.svdSolve (var u : TMatrix; var w : TVector; var v : TMatrix; b : TVector; var x : TVector); var j, i, n, m1 : integer; s: TMatElement; tmp: TVector; begin m1 := u.r; n := u.c; tmp := TVector.Create (u.c); try { Compute diag (1/wj) . U^t . b } for j := 1 to n do begin s := 0.0; if (w[j] <> 0.0) then begin for i := 1 to m1 do s := s + u[i,j]*b[i]; s := s/w[j] end; tmp[j] := s end; { ...mult by V to get solution vector x } for i := 1 to n do begin s := 0.0; for j := 1 to w.size do s := s + v[i,j]*tmp[j]; x[i] := s end; finally tmp.free; end; end; { Solves the equation: (A.a - b)^2 = 0 for a. Where, A is the 'design matrix', Aij = Xj(xi)/sigi, where Xj is the value of the jth basis function; b is the set of weighted observed y values, b = yi/sigi; and a is the set of fitting coefficients for the basis functions. Thus A.a - b expresses predicted - observed } { BasisProc is a procedure which must return in an array the values for the basis functions at a particular value of xi, i.e it computes, Xj(xi) } function TMatrix.svdfit (x, y, yerr : TVector; var fit : TVector; var u, v : TMatrix; var w : TVector; funcs : BasisProc): TMatElement; const tol=1.0e-5; var i, j : integer; wmax, weight, thresh, sum: TMatElement; BasisVal, b : TVector; A : TMatrix; begin BasisVal := TVector.Create (fit.size); b := TVector.Create (x.size); A := TMatrix.Create (x.size, fit.size); try { Form the A matrix } for i := 1 to x.size do begin funcs(x[i], BasisVal); weight := 1.0/yerr[i]; for j := 1 to fit.size do A[i,j] := BasisVal[j]*weight; b[i] := y[i]*weight end; A.svd (u, w, v); wmax := 0.0; for j := 1 to fit.size do if (w[j] > wmax) then wmax := w[j]; thresh := tol*wmax; for j := 1 to fit.size do if (w[j] < thresh) then w[j] := 0.0; svdSolve (u, w, v, b, fit); result := 0.0; { chisqr set to zero ready to accumulate } for i := 1 to x.size do begin funcs(x[i], BasisVal); sum := 0.0; for j := 1 to fit.size do sum := sum + fit[j]*BasisVal[j]; result := result + sqr((y[i]-sum)/yerr[i]); { Accumulate chisqr } end; finally BasisVal.free; A.free; b.free; end; end; procedure TMatrix.svdCovar (v : TMatrix; w : TVector; alpha : TMatrix); var i, j, k : integer; wti : TVector; sum : TMatElement; begin wti := TVector.Create (w.size); try for i := 1 to w.size do begin wti[i] := 0.0; if w[i] > 0.0 then wti[i] := 1.0/(w[i]*w[i]); end; for i := 1 to w.size do begin for j := 1 to i do begin sum := 0.0; for k := 1 to w.size do sum := sum + v[i,k]*v[j,k]*wti[k]; alpha[j,i] := sum; alpha[i,j] := alpha[j,i]; end; end; finally wti.free; end; end; procedure TMatrix.eliminate_cms (S, Tk1 : TMatrix; var cr, N : integer); (* eliminating conserved moieties *) var i,j,x,y,crc,old_cr : byte; begin x := 0; cr := 0; (* cr - conservation relations *) for i := 1 to N do begin old_cr := cr; for j := i+1 to N do begin crc := 0; (* crc - cr counter *) // S.c = number of reactions for y := 1 to S.c do crc := crc + trunc (abs(S[i,y]+S[j,y])); if crc = 0 then cr := cr+1; end; if cr = old_cr then begin x := x+1; for y := 1 to S.c do Tk1[x,y] := S[i,y]; end; end; end; procedure TMatrix.ElementaryModes (D : TVectori; var mf, mb, C1, k : integer; Tk : TMatrix); var i, j, cr, N, k1 : integer; Tk1 : TMatrix; hlpRow : TVector; begin N := Self.r; Tk1 := TMatrix.Create (Self.r, Self.c); hlpRow := TVector.Create (Self.c); try {eliminate_cms; (* also transscribing S into Tk1 *) N := N-cr; for i := 1 to R do begin for j := 1 to N do Tk[i,j] := Tk1[j,i]; (* transposing matrix *) for j:=N+1 to N+R do if i=j-N then Tk[i,j]:=1 (* appending.. *) else Tk[i,j]:=0; (*..unity matrix*) end; (* (preliminary) fund. rows to the top *) i := 0; (* splitting indices into F/B *) for j := 1 TO R DO begin if (D[j] <> 0) then begin i := i+1; hlprow := Tk[i]; Tk[i] := Tk[j]; Tk[j] := hlprow; end; end; mf := i; (* no. of fundamental rows *) mb := R-mf;} eliminate_cms (Self, Tk1, cr, N); (* also transscribing S into Tk1 *) N := N-cr; for i := 1 to Self.c do begin for j := 1 to N do Tk[i,j] := Tk1[j,i]; (* transposing matrix *) for j := N+1 to N+Self.c do if i=j-N then Tk[i,j] := 1 (* appending.. *) else Tk[i,j] := 0; (*..unity matrix*) end; (* (preliminary) fund. rows to the top *) i := 0; (* splitting indices into F/B *) for j := 1 TO Self.c DO begin if (D[j] <> 0) then begin i := i+1; for k1 := 1 to Self.c do hlprow[k1] := Tk[i,k1]; for k1 := 1 to Self.c do Tk[i,k1] := Tk[j,k1]; for k1 := 1 to Self.c do Tk[j,k1] := hlprow[k1]; //hlprow := Tk[i]; //Tk[i] := Tk[j]; //Tk[j] := hlprow; end; end; mf := i; (* no. of fundamental rows *) mb := Self.c-mf; (* no. of basis rows *) Tableau (N, Self.c, mf, mb, C1, k, Tk, Tk1); finally hlpRow.Free; Tk1.Free; end; end; class function TMatrix.grecodiv(P, Rest: integer) : integer; var old_Rest : integer; begin grecodiv := 1; if (Rest*P <> 0) then begin if ABS(P) < ABS(Rest) then begin old_Rest := Rest; Rest := P; P := old_Rest; (* swap P 'n' R *) end; repeat (* Euclidean Algorithm: *) old_Rest := Rest; Rest := P mod old_Rest; P := old_Rest; until (Rest = 0); grecodiv := P; end else if (P = 0) then begin if (Rest = 0) then grecodiv := 1 else grecodiv := Rest; end else grecodiv := P; end; class function TMatrix.grecodiv_of_vector (N, R1 : integer; vec : TVector) : integer; var x : byte; coeff : integer; begin coeff := trunc (vec[1]); for x := 2 to (N+R1) do begin if (vec[x] <> 0) then coeff := grecodiv(trunc (vec[x]), coeff); end; grecodiv_of_vector := coeff; end; class procedure TMatrix.Tableau (N, R1 : integer; var mf, mb, C1, k : integer; Tk, Tk1 : TMatrix); var i,j,k1,x,xa,y,m1 : integer; cf,dir,ifrom,iend : integer; index,bool,allow_comb : boolean; l1 : integer; vec : TVector; begin C1 := R1; (* C: number of rows of the tableau *) k := 0; (* k: tableau index *) vec := TVector.Create (Tk1.c); repeat //output; (* HELPFUL MONITORING*) //write(' k = ');writeln(k);writeln('cf=',cf); (* OF TABLEAU STEPS *) {write(' Press <ENTER> to continue.'); readln;} l1 := 1; (* l: row index in the tableau k+1 *) cf := 0; (* counter for f-rows in the tableau k+1*) for dir :=1 to 2 do BEGIN IF dir=1 THEN BEGIN ifrom:=1; iend:=mf; END ELSE BEGIN ifrom:=mf+1; iend:=c1 END; FOR i := ifrom TO iend DO BEGIN IF Tk[i,k+1] = 0 THEN (* copying rows that *) BEGIN (* have a zero element *) for k1 := 1 to Tk1.c do Tk1[l1, k1] := Tk[i, k1]; (* already *) //Tk1[l] := Tk[i]; (* already *) l1 := l1+1; IF i <= mf THEN cf := cf+1; END END; FOR i:=ifrom TO iend DO BEGIN IF Tk[i,k+1]<>0 THEN BEGIN FOR j := i+1 TO C1 DO BEGIN IF Tk[j,k+1] <> 0 THEN BEGIN IF Tk[i,k+1]*Tk[j,k+1] > 0 THEN BEGIN (* not for f-rows with *) IF j <= mf THEN allow_comb := false (* same signum *) ELSE BEGIN FOR y := 1 TO N+R1 DO Tk[j,y] := -1 * Tk[j,y]; (* invert b-row *) allow_comb := true; END; END ELSE allow_comb := true; IF allow_comb THEN BEGIN index:=true; (* first simplicity (S) test: *) IF (l1>1) THEN BEGIN IF dir=1 THEN x:=0 ELSE x:=cf; WHILE (x<l1-1) AND (INDEX) DO BEGIN x:=x+1; y:=n; bool:=true; REPEAT y:=y+1; IF ((Tk[i,y] = 0) and (Tk[j,y] = 0)) THEN IF Tk1[x,y] <> Tk[i,y] THEN bool:=false; UNTIL (y=n+r1)or NOT bool; IF (y=n+r1)and bool THEN index:=false; END; END; IF index THEN BEGIN (* combine rows *) FOR y:=1 TO R1+N DO Tk1[l1,y]:=abs(Tk[i,k+1])*Tk[j,y]+abs(Tk[j,k+1])*Tk[i,y]; for k1 := 1 to Tk1.c do vec[i] := Tk1[l1,k1]; m1:= Grecodiv_of_vector(N, R1, vec) ; //m:= Grecodiv_of_vector(Tk1[l]) ; IF (ABS(m1)<>1) AND (m1<>0) THEN FOR y:=1 to R1+N DO Tk1[l1,y]:= trunc (Tk1[l1,y]) DIV ABS(m1); l1:= l1+1; IF i <= mf THEN cf := cf+1; (* second simplicity (S) test: *) IF dir=1 THEN x:=0 ELSE x:=cf; bool:=true; WHILE (X<L1-2) AND (bool=true) DO BEGIN x:=x+1; y:=n; bool:=false; REPEAT y:=y+1; IF Tk1[x,y]=0 THEN IF (Tk1[x,y]<>Tk[i,y]) OR (Tk1[x,y]<>Tk[j,y]) THEN bool:=true; UNTIL (y=n+r1)or bool; IF (y=n+r1)and NOT(bool) THEN BEGIN {writeln('Jetzt hat folgende Zeile:'); FOR Y:=n+1 to n+r DO write(Tk1[x,y]:3); writeln; writeln('x=',x); writeln; writeln('l-1=',l-1); writeln('verloren gegen folgende Zeilen:'); FOR Y:=n+1 to n+r DO write(Tk[i,y]:3); writeln; writeln('i=',i); FOR Y:=n+1 to n+r DO write(Tk[j,y]:3); writeln; writeln('j=',j); writeln; writeln(x,'+1te Zeile:'); FOR Y:=n+1 to n+r DO write(Tk1[x+1,y]:3); writeln;} FOR xa:=x TO l1-2 DO BEGIN FOR y:=1 TO n+r1 DO Tk1[xa,y]:=Tk1[xa+1,y]; END; l1:=l1-1; IF x<=cf THEN cf:=cf-1; END; END; END; END; END; END; END; END; END; C1 := l1-1; (* new no. of rows *) mf := cf; mb := C1-mf; k := k+1; (* next tableau *) for i := 1 to C1 do begin for k1 := 1 to Tk.c do Tk[i, k1] := Tk1[i, k1]; (* restarting with Tk1 *) end; //for i := 1 to C do Tk[i] := Tk1[i]; (* restarting with Tk1 *) until (k = N) or ((mb = 0) and (mf = 0)); //if ((mb = 0) and (mf = 0)) then // writeln(' There exist neither irreversible nor reversible flux modes.') //else // output; vec.Free; end; // Evaluate conservation relations, uses the algorthim: tr(ns(tr(m))) procedure TMatrix.Conserve(st : TMatrix); var tmp, ns, echelon : TMatrix; b, r1 : integer; begin tmp := TMatrix.Create (st.c, st.r); ns := TMatrix.Create (1,1); echelon := TMatrix.Create (1,1); try tmp.Transpose (st); tmp.NullSpace (ns, b, Echelon, r1); Self.SetSize (ns.c, ns.r); Self.Transpose (ns); finally ns.free; echelon.free; tmp.free; end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/upower.pas�����������������������������������������������0000755�0001750�0001750�00000011732�11326425450�020216� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit upower; interface uses define_types, statcr, distr, dialogs; function Sum2Power(lOutImgSum: SingleP; lVolVox,lnTotal,lnDeficit: integer; lBinomial: boolean): boolean; function Sum2PowerCont(lOutImgSum: SingleP; lVolVox,lnTotal: integer): boolean; function Sum2PowerBinom(lOutImgSum: SingleP; lVolVox,lnTotal,lnDeficit: integer): boolean; function k_out_n (k,n: integer): double; //total possible permutations implementation function k_out_n (k,n: integer): double; //total possible permutations //k= smaller group, n=sum of both groups begin if not gFactRAready then InitFact; result := round(gFactRA[n] / (gFactRA[k]*gFactRA[n-k] ) ); // k out n = n!/(k!*(n-k)! which is equal to the PROD(i=k; 1){(n-i+1)/i} end; //k_out_n function Sum2Power(lOutImgSum: SingleP; lVolVox,lnTotal,lnDeficit: integer; lBinomial: boolean): boolean; begin if lBinomial then result := Sum2PowerBinom(lOutImgSum, lVolVox,lnTotal,lnDeficit) else result := Sum2PowerCont(lOutImgSum, lVolVox,lnTotal) end; function Sum2PowerCont(lOutImgSum: SingleP; lVolVox,lnTotal: integer): boolean; //convert Sum image to power map showing maximum possible effect size //'Cont' version is for continuous data var lDensity,lN,lRank: integer; lDensityPowerRA: singleP; begin result := false; if (lnTotal < 2) or (lVolVox < 1) then exit; getmem(lDensityPowerRA,lnTotal* sizeof(single)); //no need to compute power for [lnTotal] and [0] - no variability when everyone or no one has a lesion //lDensityPowerRA[lnTotal] := 0; //everyone has a lesion = no variability lRank := 0; for lN := 1 to (lnTotal -1) do begin //most power when all participants with a lesion have most extreme behavioural data //therefore, they will have the lowest ranks: rank 1,2,3,4 lRank := lRank + lN; if (lnTotal > 360) then //cannot calculate values this large... lDensityPowerRA^[lN] := 0 else if (lN > 10) and (lnTotal > 64) then //avoid overflow... lDensityPowerRA^[lN] := pNormalInv ( 1/(k_out_n(10,lnTotal)) ) else begin lDensityPowerRA^[lN] := 1/(k_out_n(lN,lnTotal)); //compute Wilcoxon probability lDensityPowerRA^[lN] := pNormalInv (lDensityPowerRA^[lN]);//convert p to z-score end; //max power when every possible person with a lesion has a defict, and everyone w/o lesion does not... //lDensityPowerRA[lN] := Liebermeister (lLD,lnoLD,lLnoD,lnoLnoD); //probability of this observation //lDensityPowerRA[lN] := pNormalInv (lDensityPowerRA[lN]);//convert p to z-score //fx(lDensityPowerRA[lN]); end; //now use lookup table to convert overlay density to effective power for lN := 1 to lVolVox do begin lDensity := round( lOutImgSum^[lN]); if (lDensity > 0) and (lDensity < lnTotal) then lOutImgSum^[lN] := lDensityPowerRA^[lDensity] else lOutImgSum^[lN] := 0; end; //for each voxel freemem(lDensityPowerRA); result := true; end; function Sum2PowerBinom(lOutImgSum: SingleP; lVolVox,lnTotal,lnDeficit: integer): boolean; //convert Sum image to power map showing maximum possible effect size var lDensity,lN,lLD,lLnoD,lnoLD,lnoLnoD: integer; lDensityPowerRA: singleP; begin result := false; if (lnTotal < 2) or (lnDeficit < 1) or (lVolVox < 1) then exit; if(lnDeficit >= lnTotal) then begin showmessage('Sum2Power error: people with deficit must be less than sample size'); exit; end; getmem(lDensityPowerRA,lnTotal* sizeof(single)); //no need to compute power for lnTotal and 0 - no variability when everyone or no one has a lesion //lDensityPowerRA[lnTotal] := 0; //everyone has a lesion = no variability for lN := 1 to (lnTotal -1) do begin //max power when every possible person with a lesion has a defict, and everyone w/o lesion does not... if lN > lnDeficit then begin lLD := lnDeficit; lLnoD := lN - lnDeficit; end else begin lLD := lN; lLnoD := 0; end; lnoLD := lnDeficit-lLD; //number of people with deficit who do not have a lesion - as close to zero as possible lnoLnoD := lnTotal-lnoLD-lLnoD-lLD; lDensityPowerRA^[lN] := Liebermeister (lLD,lnoLD,lLnoD,lnoLnoD); //probability of this observation lDensityPowerRA^[lN] := pNormalInv (lDensityPowerRA^[lN]);//convert p to z-score //fx(lLD,lnoLD,lLnoD,lnoLnoD,lDensityPowerRA[lN]); end; //now use lookup table to convert overlay density to effective power for lN := 1 to lVolVox do begin lDensity := round( lOutImgSum^[lN]); if (lDensity > 0) and (lDensity < lnTotal) then lOutImgSum^[lN] := lDensityPowerRA^[lDensity] else lOutImgSum^[lN] := 0; end; //for each voxel freemem(lDensityPowerRA); result := true; end; end. ��������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/extrafpc.cfg���������������������������������������������0000755�0001750�0001750�00000000130�11316122054�020444� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#IFDEF Darwin -k-macosx_version_min -k10.4 -XR/Developer/SDKs/MacOSX10.4u.sdk/ #ENDIF����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/regression.pas�������������������������������������������0000755�0001750�0001750�00000102503�12147220370�021046� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit regression; //only for Delphi - not Freepascal //Unit for running multiple regression interface uses {$H+} {$IFNDEF UNIX} Windows, {$ENDIF} {$IFDEF FPC} utypes,regmult,{$ELSE} utypes,regmult, {$ENDIF}define_types,Classes,nifti_hdr,sysutils,nifti_img, StatThdsUtil,Forms,Distr,Dialogs,npmform, tfce_clustering; function GetValReg (var lnSubj,lnFactors: integer; var X : PMatrix; var lImageNames: TStrings; var lPredictorList: TStringList): boolean; function ARegressNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; var X: PMatrix; lnFactors: integer; var lPredictorList: TStringList; lOutname: string; lnPermute, TFCEconn: integer): boolean; function Regress2NPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lOutname: string; var lXadditional: PMatrix; lnAdditionalFactors: integer ): boolean; function TtoR(t,df: double): double; implementation uses valformat,hdr,math; (*function readCSV (lFilename: string; var lnObservations,lnFactors : integer; var X : PMatrix; var Y: PVector): boolean; var lNumStr: string; F: TextFile; lTempFloat: double; lCh: char; lPos,MaxC,R,C:integer; lError: boolean; begin result := false; if not fileexists(lFilename) then exit; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); if (R < 2) or (MaxC < 5) then begin showmessage('problems reading CSV'); exit; end; lnObservations := MaxC; lnFactors := R -1; DimVector(Y, lnObservations); DimMatrix(X, lnFactors, lnObservations); //second pass Reset(F); C := 0; MaxC := 0; R := 1; lNumStr := ''; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin if lNumStr = '-' then begin lTempFloat := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading VAL file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end; if R = 1 then Y^[C+1] := lTempFloat else X^[R-1]^[C+1] := lTempFloat; //xxx := lTempFloat;//DataGrid.Cells[ C, kMaxFactors+R-1 ] := (lNumStr) ; end; lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; CloseFile(F); FileMode := 2; //Set file access to read/write result := true; end; function TestMultReg: boolean; var i,lnFactors, lnObservations: integer; X : PMatrix; Y: PVector; lOutT,lOutSlope: DoubleP0; lStart: dword; begin if not readCSV('C:\xio.csv',lnObservations,lnFactors,X,Y ) then exit; //showmessage('alpha'); getmem(lOutT, (lnFactors+1)* sizeof(double)); getmem(lOutSlope, (lnFactors+1)* sizeof(double)); lStart := gettickcount; for i := 1 to 10000 do MultipleRegressionVec (lnObservations,lnFactors, X, Y, lOutT,lOutSlope); fx(gettickcount-lstart); if MultipleRegressionVec (lnObservations,lnFactors, X, Y, lOutT,lOutSlope) then begin for i := 0 to lnFactors do fx(lOutT^[i],lOutSlope^[i]); end; freemem(lOutT); freemem(lOutSlope); DelMatrix(X, lnFactors, lnObservations); DelVector(Y, lnObservations); end; *) (*procedure rx(lnObs,lnFactors: integer; X: PMatrix; lObs: Doublep0); var n,f: integer; str: string; begin for n := 1 to lnObs do begin str := floattostr(lObs^[n-1]); for f := 1 to lnFactors do str := str+','+floattostr(X^[f]^[n]); MainForm.NPMmsg(str); end;//each obs str := '----------'; end;//proc RX*) function Sign(value: double): double; begin if value > 0 then result := 1 else if value < 0 then result := -1 else result := 0; end; function TtoR(t,df: double): double; CONST eps=3.0e-7; begin result := 0; if (t = 0) or (df = 0) then exit; result := sign(t)/ sqrt( (df/(t*t+eps)) +1 ); end; {$DEFINE SaveT} //if SaveT then t-score map will be saved {$DEFINE SaveRnotZ} //if SaveRnotZ then r-value map will be saved, but not Z-score map function Regress2NPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lOutname: string; var lXadditional: PMatrix; lnAdditionalFactors: integer ): boolean; //lImages is list 1..N of 1st images followed by 1..N of corresponding control images //example c1.img, c2.img,c3.img,e1.img,e2.img,e3.img //lImages.Count must be even label 667; const kMaxFact = 80; var lOutNameMod,lFactName,lRunName: string; lMaskImg,lPlankImg,lOutImgMn: SingleP; lOutImgR: array [1..kMaxFact] of SingleP; lTotalMemory: int64; lnFactors,lnObservations,lnObservationsDiv2,lPlank,lVolVox,lPos,lMinMask,lMaxMask,lnPlanks,lVoxPerPlank, lDF,lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct,lFact,lnStatFact: integer; l1st, lSum, lMn: double; lVar: boolean; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lnPermute: integer; lRanOrderp: pointer; lRanOrder: Doublep0; lZP: Pointer; lZra : DoubleP0; X : PMatrix; begin lnFactors := 1+lnAdditionalFactors; lnPermute := MainForm.ReadPermute; if odd(lImages.Count) then begin showmessage('Regress2NPMAnalyze must be passed an even number of images: the first half of the list is the experimental images, followed by corresponding control images.'); exit; end; lnObservations := lImages.Count; lnObservationsDiv2 := lImages.Count div 2; lDF := lnObservationsDiv2-lnFactors-1; if lDF < 1 then begin showmessage('Regress2NPMAnalyze: DF must be >0 (DF=[Num-Factors-1]) Num='+inttostr(lnObservationsDiv2)+' Factors='+inttostr(lnFactors) ); exit; end; DimMatrix(X, lnFactors, lnObservationsDiv2); //fx(lnAdditionalFactors); if lnAdditionalFactors > 0 then begin for lPos2 := 1 to lnAdditionalFactors do begin for lPos := 1 to lnObservationsDiv2 do begin X^[lPos2+1]^[lPos] := lXadditional^[lPos2]^[lPos]; //fx(lPos2+1,lPos, X^[lPos2+1]^[lPos]); end; end; //pos 2 end; //additional factros //Memo1.Lines.Add('Permutations = ' +IntToStr(lnPermute)); MainForm.Memo1.Lines.Add('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lnStatFact := lnFactors + 1; //factors + overall model if lnStatFact > (kMaxFact-1) then begin //-1 because factors + model MainForm.Memo1.Lines.Add('ERROR: Can not analyze more than = ' +inttostr(kMaxFact-1)+' factors'); goto 667; end; //load mask getmem(lMaskImg,lVolVox*sizeof(single)); if not LoadImg(lMaskHdr.ImgFileName, lMaskImg, 1, lVolVox,round(gOffsetRA[0]),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin MainForm.Memo1.Lines.Add('Unable to load mask ' +lMaskHdr.ImgFileName); goto 667; end; //next find start and end of mask lPos := 0; repeat inc(lPos); until (lMaskImg^[lPos] > 0) or (lPos = lVolVox); lMinMask := lPos; lPos := lVolVox+1; repeat dec(lPos); until (lMaskImg^[lPos] > 0) or (lPos = 1); lMaxMask := lPos; if lMaxMask = 1 then begin MainForm.Memo1.Lines.Add('Mask appears empty' +lMaskHdr.ImgFileName); goto 667; end; MainForm.Memo1.Lines.Add('Mask has voxels from '+inttostr(lMinMask)+'..'+inttostr(lMaxMask)); lVoxPerPlank := kPlankSz div lnObservations div sizeof(single) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lnObservations; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lnObservations) ) + 1; MainForm.Memo1.Lines.Add('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lnObservations))); MainForm.Memo1.Lines.Add('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory*sizeof(single)) //assumes 4bpp else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; lnVoxTested := 0; for lPos := 1 to lnObservations do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; createArray64(lObsp,lObs,lnObservations); getmem(lOutImgMn,lVolVox* sizeof(single)); for lPos := 1 to lVolVox do lOutImgMn^[lPos] := 0; for lFact := 1 to (lnStatFact) do begin //+1 as we include full model getmem(lOutImgR[lFact],lVolVox* sizeof(single)); for lPos := 1 to lVolVox do lOutImgR[lFact]^[lPos] := 0; end; createArray64(lZp,lZra,lnFactors+1); //+1 as we include full model //InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxTW, lPermuteMinTW,lPermuteMaxWMW, lPermuteMinWMW, lRanOrderp, lRanOrder); for lPlank := 1 to lnPlanks do begin MainForm.Memo1.Lines.Add('Computing plank = ' +Inttostr(lPlank)); MainForm.Refresh; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lnObservations do begin if not LoadImg(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image lPosPct := lVoxPerPlank div 100; for lPos2 := 1 to lVoxPerPlank do begin if (lPos2 mod lPosPct) = 0 then begin MainForm.ProgressBar1.Position := round((lPos2/lVoxPerPlank)*100); Application.Processmessages; end; lPos2Offset := lPos2+lStartVox-1; if lMaskImg^[lPos2Offset] <> 0 then begin inc(lnVoxTested); lSum := 0; //check for variance lVar := false; lPos := 1; l1st := (gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; for lPos := 1 to lnObservations do lObs^[lPos-1] := (gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; for lPos := 1 to lnObservationsDiv2 do begin lSum := lSum + lObs^[lPos-1]; if (not lVar) and (lObs^[lPos-1]<>l1st) then lVar := true; //lSumOfSqrs := lSumOfSqrs + sqr(lObs[lPos-1]); X^[1]^[lPos] := lObs^[lnObservationsDiv2+lPos-1]; end; lOutImgMn^[lPos2Offset] := lSum/lnObservationsDiv2; if lVar then begin MultipleRegression (lnObservationsDiv2,lnFactors, X, lObs, lZra); //if lPos2Offset = 359948 then rx(lnObservationsDiv2,lnFactors,X,lObs); for lFact := 1 to lnStatFact do lOutImgR[lFact]^[lPos2Offset] := lZra^[lFact-1]; end; //StatPermute (lttest,lwelch,lWMW,lImages.Count, lnGroup1,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxTW, lPermuteMinTW,lPermuteMaxWMW, lPermuteMinWMW, lObs,lRanOrder); end; //in brain mask - compute end; lStartVox := lEndVox + 1; end; //next report findings MainForm.Memo1.Lines.Add('Voxels tested = ' +Inttostr(lnVoxTested)); MainForm.reportBonferroni('Std',lnVoxTested); //next: save data if lnFactors = 1 then lRunName := 'reg' else lRunName := ''; //savedata MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save mean lOutNameMod := ChangeFilePostfixExt(lOutName,'Mn'+lRunName,'.hdr'); if not FileExistsEX(lOutNameMod) then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgMn,1); //save regression for lFact := 1 to (lnStatFact) do begin if (lFact > lnFactors) and (lnFactors = 1) then lFactName := 'intercept'+'reg' //for analysis of multiple single regressions else if (lFact > lnFactors) then lFactName := 'intercept' else lFactName := 'reg'+inttostr(lFact); MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); {$IFDEF SaveT} //if SaveTRnotZ then t-score and r-score maps will be created, but no Z-score maps //the next bit is optional - save data as T-values instead of Z-scores // this allows direct comparison with SPM... MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,lDF,0,lnVoxTested,kNIFTI_INTENT_TTEST,inttostr(lnVoxTested) ); lOutNameMod := ChangeFilePostfixExt(lOutName, 'wlsT'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgR[lFact],1); {$ENDIF} {$IFDEF SaveRnotZ} MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,lDF,0,lnVoxTested,kNIFTI_INTENT_CORREL,inttostr(lnVoxTested) ); for lPos := 1 to lVolVox do lOutImgR[lFact]^[lPos] := TtoR (lOutImgR[lFact]^[lPos],lDF); lOutNameMod := ChangeFilePostfixExt(lOutName, 'wlsR'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgR[lFact],1); {$ELSE} //next - save Zscores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,lDF,0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); //{ DoF = Nb points - Nb parameters } for lPos := 1 to lVolVox do lOutImgR[lFact]^[lPos] := TtoZ (lOutImgR[lFact]^[lPos],lDF); MainForm.reportFDR ('wls'+lFactName, lVolVox, lnVoxTested, lOutImgR[lFact]); lOutNameMod := ChangeFilePostfixExt(lOutName, 'wls'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgR[lFact],1); {$ENDIF} freemem(lOutImgR[lFact]); end; //next: close images Freemem(lZp); freemem(lOutImgMn); freemem(lObsp); freemem(lMaskImg); freemem(lPlankImg); MainForm.Memo1.Lines.Add('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lRunName,'.txt'); MainForm.Memo1.Lines.SaveToFile(lOutNameMod); MainForm.ProgressBar1.Position := 0; DelMatrix(X, lnFactors, lnObservationsDiv2); exit; 667: //you only get here if you aborted ... free memory and report error DelMatrix(X, 1, lnObservationsDiv2); if lVolVox > 1 then freemem(lMaskImg); if lTotalMemory > 1 then freemem(lPlankImg); MainForm.Memo1.Lines.Add('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; {$DEFINE NoThread} function InnerARegressNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; var X: PMatrix; lnFactors: integer; var lPredictorList: TStringList; lOutname: string; lSaveData: boolean; var lMinZ,lMaxZ: double; var lMaxNegTFCEZ, lMaxTFCEZ:single; TFCEconn: integer): boolean; //TFCEmode 0 = no TFCE, 1 = only report min/maxTFCE, 2 = save TFCE map to disk {$IFNDEF Thread} const kMaxFact = 80; {$ENDIF} label 667; var lOutNameMod,lFactName,lRunName: string; lMaskImg,lPlankImg,lOutImgMn: SingleP; {$IFDEF Thread} lOutImgR: TRegRA; {$ELSE} lOutImgR: array [1..kMaxFact] of SingleP; {$ENDIF} lTotalMemory: int64; lnObservations,lPlank,lVolVox,lPos,lMinMask,lMaxMask,lnPlanks,lVoxPerPlank, //lPos2,lPos2Offset, lDF,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lFact,lnStatFact: integer; //l1st, lSum, lMn: double; //lVar: boolean; //lObsp: pointer;lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; {$IFDEF Thread} lThread,lThreadStart,lThreadEnd,lThreadInc: integer; {$ELSE} lObsP,lZP: Pointer; lObs,lZra : DoubleP0; lSum,l1st: double; lVar: boolean; lPos2,lPosPct,lPos2Offset: integer; {$ENDIF} begin lnObservations := lImages.Count; lDF := lnObservations-lnFactors-1; if lDF < 1 then begin showmessage('Regress2NPMAnalyze: DF must be >0 (DF=[Num-Factors-1]) Num='+inttostr(lnObservations)+' Factors='+inttostr(lnFactors) ); exit; end; if (lSaveData) then MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lnStatFact := lnFactors + 1; //factors + overall model if lnStatFact > (kMaxFact-1) then begin //-1 because factors + model MainForm.NPMmsg('ERROR: Can not analyze more than = ' +inttostr(kMaxFact-1)+' factors'); goto 667; end; //load mask getmem(lMaskImg,lVolVox*sizeof(single)); if not LoadImg(lMaskHdr.ImgFileName, lMaskImg, 1, lVolVox,round(gOffsetRA[0]),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin MainForm.NPMmsg('Unable to load mask ' +lMaskHdr.ImgFileName); goto 667; end; //next find start and end of mask lPos := 0; repeat inc(lPos); until (lMaskImg^[lPos] > 0) or (lPos = lVolVox); lMinMask := lPos; lPos := lVolVox+1; repeat dec(lPos); until (lMaskImg^[lPos] > 0) or (lPos = 1); lMaxMask := lPos; if lMaxMask = 1 then begin MainForm.NPMmsg('Mask appears empty' +lMaskHdr.ImgFileName); goto 667; end; if (lSaveData) then MainForm.NPMmsg('Mask has voxels from '+inttostr(lMinMask)+'..'+inttostr(lMaxMask)); lVoxPerPlank := kPlankSz div lnObservations div sizeof(single) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lnObservations; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lnObservations) ) + 1; if (lSaveData) then MainForm.NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lnObservations))); if (lSaveData) then MainForm.NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory* sizeof(single)) //assumes 4bpp else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; //lnVoxTested := 0; for lPos := 1 to lnObservations do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; //createArray64(lObsp,lObs,lnObservations); getmem(lOutImgMn,lVolVox* sizeof(single)); for lPos := 1 to lVolVox do lOutImgMn^[lPos] := 0; for lFact := 1 to (lnStatFact) do begin //+1 as we include full model getmem(lOutImgR[lFact],lVolVox* sizeof(single)); for lPos := 1 to lVolVox do lOutImgR[lFact]^[lPos] := 0; end; //createArray64(lZp,lZra,lnFactors+1); //+1 as we include full model {$IFDEF Thread} ClearThreadDataPvals(gnCPUThreads,0) ; {$ELSE} lnVoxTested := 0; {$ENDIF} for lPlank := 1 to lnPlanks do begin if (lSaveData) then MainForm.NPMmsg('Computing plank = ' +Inttostr(lPlank)); MainForm.Refresh; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lnObservations do begin if not LoadImg(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image {$IFDEF Thread} lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TLinThreadStat.Create (X,ProgressBar1, lnFactors,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lnObservations, lMaskImg,lPlankImg,lOutImgMn,lOutImgR) do {$IFDEF FPC} OnTerminate := @ThreadDone; {$ELSE}OnTerminate := ThreadDone;{$ENDIF} inc(gThreadsRunning); Msg('Thread ' +Inttostr(gThreadsRunning)+' = '+inttostr(lThreadStart)+'..'+inttostr(lThreadEnd)); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; {$ELSE} //not threaded createArray64(lZp,lZra,lnFactors+1); //+1 as we include full model createArray64(lObsp,lObs,lnObservations); lPosPct := lVoxPerPlank div 100; for lPos2 := 1 to lVoxPerPlank do begin if (lPos2 mod lPosPct) = 0 then begin MainForm.ProgressBar1.Position := round((lPos2/lVoxPerPlank)*100); Application.Processmessages; end; lPos2Offset := lPos2+lStartVox-1; if lMaskImg^[lPos2Offset] <> 0 then begin inc(lnVoxTested); lSum := 0; //check for variance lVar := false; lPos := 1; l1st := (gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; for lPos := 1 to lnObservations do begin lObs^[lPos-1] := (gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; lSum := lSum + lObs^[lPos-1]; if (not lVar) and (lObs^[lPos-1]<>l1st) then lVar := true; end; lOutImgMn^[lPos2Offset] := lSum/lnObservations; if lVar then begin MultipleRegression (lnObservations,lnFactors, X, lObs, lZra); //if {lZra^[0] < -5.548} lPos2Offset = 762287 then // ReportRegression (lPos2Offset,lnObservations,lnFactors, X, lObs, lZra ); for lFact := 1 to lnStatFact do lOutImgR[lFact]^[lPos2Offset] := lZra^[lFact-1]; end; end; //in brain mask - compute end; //for each voxel Freemem(lZp); Freemem(lObsp); {$ENDIF} //if threaded else not threaded lStartVox := lEndVox + 1; end; //for each plank {$IFDEF Thread} lnVoxTested := SumThreadDataLite(gnCPUThreads); {$ENDIF} //FACTOR 1 MinMax lFact := 1; lMinZ := lOutImgR[lFact]^[1]; for lPos := 1 to lVolVox do if (lOutImgR[lFact]^[lPos] < lMinZ) then lMinZ :=lOutImgR[lFact]^[lPos]; lMinZ := TtoZ (lMinZ,lDF); lMaxZ := lOutImgR[lFact]^[1]; for lPos := 1 to lVolVox do if (lOutImgR[lFact]^[lPos] > lMaxZ) then lMaxZ :=lOutImgR[lFact]^[lPos]; lMaxZ := TtoZ (lMaxZ,lDF); //MainForm.NPMmsg('Factor1MinMax ' +floattostr(lMinZ)+' '+floattostr(lMaxZ)); if (lSaveData) then begin //next report findings MainForm.NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); MainForm.reportBonferroni('Std',lnVoxTested); //next: save data if lnFactors = 1 then lRunName := lPredictorList[0] else lRunName := ''; //savedata MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save mean lOutNameMod := ChangeFilePostfixExt(lOutName,'Mean'+lRunName,'.hdr'); if not FileExistsEX(lOutNameMod) then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgMn,1); //save regression for lFact := 1 to (lnStatFact) do begin if (lFact > lnFactors) and (lnFactors = 1) then begin //nothing end else begin if (lFact > lnFactors) and (lnFactors = 1) then lFactName := 'intercept'+lPredictorList[0] //for analysis of multiple single regressions else if (lFact > lnFactors) then lFactName := 'model' else lFactName := lPredictorList[lFact-1]; MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //NEXT : optional save t-maps //MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,lDF,0,lnVoxTested,kNIFTI_INTENT_TTEST,inttostr(lnVoxTested) ); //lOutNameMod := ChangeFilePostfixExt(lOutName, 'wlsT'+lFactName,'.hdr'); //NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgR[lFact],1); //END: t-maps //next - Z scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,lDF,0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); //{ DoF = Nb points - Nb parameters } for lPos := 1 to lVolVox do lOutImgR[lFact]^[lPos] := TtoZ (lOutImgR[lFact]^[lPos],lDF); MainForm.reportFDR ('wls'+lFactName, lVolVox, lnVoxTested, lOutImgR[lFact]); lOutNameMod := ChangeFilePostfixExt(lOutName, 'wls'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgR[lFact],1); if (lFact = 1) and (TFCEconn > 0) then begin //TFCE //lMinZ := lOutImgR[lFact]^[1]; MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,lDF,0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); doTFCEbothPolarities (lStatHdr, lOutImgR[lFact], TFCEconn {NumConn}, 2.0{H}, 0.5 {E}, 0, lMaxZ/100, 0, lMinZ/100, lMaxTFCEZ, lMaxNegTFCEZ); lOutNameMod := ChangeFilePostfixExt(lOutName, 'tfce'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgR[lFact],1); end; //TFCE end;//if..else intercept and lnFactors = 1 end;//for each statfactor end; //if lSaveData if (not (lSaveData)) and (TFCEconn > 0) and ((lMaxTFCEZ <> 0) or (lMaxNegTFCEZ <> 0)) then begin //lMinZ := lOutImgR[lFact]^[1]; lFact := 1; MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,lDF,0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); doTFCEbothPolarities (lStatHdr, lOutImgR[lFact], TFCEconn {NumConn}, 2.0{H}, 0.5 {E}, 0, lMaxTFCEZ, 0, lMaxNegTFCEZ, lMaxTFCEZ, lMaxNegTFCEZ) end; //xxx //next: close images for lFact := 1 to (lnStatFact) do freemem(lOutImgR[lFact]); //Freemem(lZp); freemem(lOutImgMn); //freemem(lObsp); freemem(lMaskImg); freemem(lPlankImg); //lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lRunName,'.txt'); //MainForm.MsgSave(lOutNameMod); MainForm.ProgressBar1.Position := 0; exit; 667: //you only get here if you aborted ... free memory and report error if lVolVox > 1 then freemem(lMaskImg); if lTotalMemory > 1 then freemem(lPlankImg); MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; procedure PermuteMatrix(var Src, Dest: PMatrix; lnSubj: integer); //assumes only one column/factor!!! var lRow,lPos: integer; lSwap: double; begin for lRow := 1 to lnSubj do Dest^[1]^[lRow] := Src^[1]^[lRow]; for lRow := lnSubj downto 1 do begin lPos := random(lRow)+1; lSwap := Dest^[1]^[lRow]; Dest^[1]^[lRow] := Dest^[1]^[lPos]; Dest^[1]^[lPos] := lSwap; end; end; function ARegressNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; var X: PMatrix; lnFactors: integer; var lPredictorList: TStringList; lOutname: string; lnPermute, TFCEconn: integer ): boolean; label 777; var //SaveData: boolean; var lMaxTFCEZ, lMaxNegTFCEZ: single; lMinZ,lMaxZ,lTFCEdh,lNegTFCEdh:double; Xp : PMatrix; lp,lnSubj,lRow : integer; lPermuteMaxZ, lPermuteMinZ,lPermuteMaxTFCEZ, lPermuteMinTFCEZ: singleP; begin InnerARegressNPMAnalyze (lImages, lMaskHdr, X, lnFactors, lPredictorList, lOutname, TRUE,lMinZ,lMaxZ, lMaxNegTFCEZ, lMaxTFCEZ, TFCEconn ); if lnFactors > 1 then goto 777; if (lnPermute < 1) then goto 777; //MainForm.NPMmsg('0 ObservedzMinMax ' +floattostr(lMinZ)+' '+floattostr(lMaxZ)); MainForm.NPMmsg('OBSERVED Factor1 zMin zMax zMinTFCE zMaxTFCE ' +floattostr(lMinZ)+' '+floattostr(lMaxZ) +' ' +floattostr(lMaxNegTFCEZ)+' '+floattostr(lMaxTFCEZ)); lnSubj := lImages.Count; DimMatrix(Xp, lnFactors, lnSubj); randomize; getmem(lPermuteMaxZ,lnPermute* sizeof(single)); getmem(lPermuteMinZ,lnPermute* sizeof(single)); getmem(lPermuteMaxTFCEZ,lnPermute* sizeof(single)); getmem(lPermuteMinTFCEZ,lnPermute* sizeof(single)); lTFCEdh := lMaxZ / 100; lNegTFCEdh := abs(lMinZ) / 100; for lp := 1 to lnPermute do begin //for lRow := 1 to lnSubj do // Xp^[1]^[lRow] := X^[1]^[lRow]; lMaxNegTFCEZ := lNegTFCEdh; lMaxTFCEZ := lTFCEdh; PermuteMatrix(X,Xp,lnSubj); InnerARegressNPMAnalyze (lImages, lMaskHdr, Xp, lnFactors, lPredictorList, lOutname, FALSE,lMinZ,lMaxZ,lMaxNegTFCEZ, lMaxTFCEZ, TFCEconn); MainForm.NPMmsg(inttostr(lp)+' Factor1 zMin zMax zMinTFCE zMaxTFCE ' +floattostr(lMinZ)+' '+floattostr(lMaxZ) +' ' +floattostr(lMaxNegTFCEZ)+' '+floattostr(lMaxTFCEZ)); lPermuteMaxZ^[lp] := lMaxZ; lPermuteMinZ^[lp] := lMinZ; lPermuteMaxTFCEZ^[lp] := lMaxTFCEZ; lPermuteMinTFCEZ^[lp] := lMaxNegTFCEZ; end; DelMatrix(Xp, lnFactors, lnSubj); MainForm.reportPermute ('Permutation', lnPermute, lPermuteMaxZ, lPermuteMinZ); MainForm.reportPermute ('TFCEPermutation', lnPermute, lPermuteMaxTFCEZ, lPermuteMinTFCEZ); Freemem(lPermuteMaxZ); Freemem(lPermuteMinZ); Freemem(lPermuteMaxTFCEZ); Freemem(lPermuteMinTFCEZ); 777: MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); MainForm.MsgSave( ChangeFilePostfixExt(lOutName,'Notes','.txt')); end; function GetValReg (var lnSubj,lnFactors: integer; var X : PMatrix; var lImageNames: TStrings; var lPredictorList: TStringList): boolean; var lVALFilename,lTemplateName: string; lnRow,lnColWObs,lnCritPct,lInc,lRow,lCol: integer; lDesignUnspecified : boolean; lFileList:TStringList; lInRA: DoubleP0; lInP: Pointer; begin result := false; lnSubj := 0; if not MainForm.OpenDialogExecute('Select MRIcron VAL file',false,false,'MRIcron VAL (*.val)|*.val') then begin showmessage('NPM aborted: VAL file selection failed.'); exit; end; //if not selected lVALFilename := MainForm.OpenHdrDlg.Filename; MainForm.Memo1.Lines.Add( 'VAL filename: '+lVALFilename); lFileList := TStringList.Create; if not OpenValFile (lVALFilename,lTemplateName, lnRow,lnFactors,lnColWObs,lnCritPct, lDesignUnspecified,lPredictorList,lFileList, lInP) then exit; if lnRow > 1 then begin lnSubj := lnRow -1; //top row is predictor {$IFDEF FPC} lInRA := align(lInP,16); {$ELSE} lInRA := DoubleP0($fffffff0 and (integer(lInP)+15)); //lInRA := DoubleP0((integer(lInP) and $FFFFFFF0)+16); {$ENDIF} DimMatrix(X, lnFactors, lnSubj); for lCol := 1 to lnFactors do begin for lRow := 1 to lnSubj do begin //MainForm.Memo1.Lines.Add(inttostr( (lRow*lnColWObsAndCovary)-4+lCol )); X^[lCol]^[lRow] := lInRA^[(lRow*lnColWObs)-lnColWObs-1+lCol]; end; end; MainForm.Memo1.Lines.Add(inttostr(lnFactors)+' '+inttostr(lnSubj)); for lInc := 1 to lnSubj do lImageNames.add(ExtractFileDirWithPathDelim(lVALFilename)+lFileList.Strings[lInc-1]); result := true; end else result := false; lFileList.free; Freemem(lInP); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/Vector.pas�����������������������������������������������0000755�0001750�0001750�00000043317�11326425450�020143� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit Vector; interface uses SysUtils; //var gMat: boolean = false; type EVectorSizeError = class (Exception); TMatElement = double; //extended; { The 1000 in the array types below does not impose a limit at runtime! If you compile with range checking on then the compiled code will impose an effective limit of 1000, but with range checking off the size of vector is limited to 64K under 16bit OS or *much* greater under 32bit OS } TArrayd = array[1..1000] of TMatElement; pTArrayd = ^TArrayd; TArrayi = array[1..1000] of integer; pTArrayi = ^TArrayi; { Define a dynamic array type for holding integers } TVectori = class (TObject) private s : integer; { size of vector } vx : pTArrayi; { pointer to the data } private procedure SetSize (NewSize : integer); public constructor create (i : integer); virtual; destructor destroy; override; procedure EnlargeBy (n : integer); procedure ReduceBy (n : integer); procedure Enlarge; procedure Reduce; procedure Zero; procedure Clear; procedure Assign (v : TVectori); procedure Setval (i : integer; v : integer); function Getval (i : integer) : integer; function GetSize : integer; property Elem[x : Integer] : integer read GetVal write SetVal; default; property Size : integer read s; end; { Define a dynamic array type for holding Extendeds } TVector = class (TObject) private s : integer; { size of vector } vx : pTArrayd; { pointer to the data } Tmp : boolean; { set to true if temporary } public { Declare as a class method, saves having a self variable } class function Dot (u, v : TVector) : TMatElement; constructor create (i : integer); virtual; constructor createTmp (i : integer); destructor destroy; override; procedure FreeSpace; procedure SetSize (i : integer); procedure EnlargeBy (n : integer); procedure ReduceBy (n : integer); procedure Enlarge; procedure Reduce; procedure Zero; procedure Clear; procedure Setval (i : integer; v : TMatElement); function Getval (i : integer) : TMatElement; property Elem[x : Integer] : TMatElement read GetVal write SetVal; default; property Size : integer read s; procedure Assign (v : TVector); function Add (v, u : TVector) : TVector; function Sub (v, u : TVector) : TVector; class function xAdd (v, u : TVector) : TVector; class function xSub (v, u : TVector) : TVector; function DotU (v : TVector) : TMatElement; function CrossU (v : TVector) : TVector; function Cross (v1, v2 : TVector) : TVector; function Sum : TMatElement; function Mean : TMatElement; function SumofSquares : TMatElement; function Norm : TMatElement; function StdDev : TMatElement; procedure Scale (factor : TMatElement); end; implementation // ------------------------------------------------------------------------- // START OF VECTOR TYPE IMPLEMETATION // ------------------------------------------------------------------------- { The data space which holds the data for a vector is typed as [1..x] so that indexing autmatically starts at one, therefore there is no need in the following code to add 1 to the size of the vector when creating or destroying it } { Create a vector of size i } constructor TVector.create(i : integer); begin Inherited Create; s := 0; vx := Nil; { vx set to Nil to indicate empty vector, used by SetSize } if i > 0 then Self.SetSize (i); end; constructor TVector.createTmp (i : integer); begin Inherited Create; s := 0; vx := Nil; { vx set to Nil to indicate empty vector, used by SetSize } if i > 0 then Self.SetSize (i); Tmp := true; end; destructor TVector.destroy; begin FreeSpace; Inherited Destroy; end; { Private internal procedure } procedure TVector.FreeSpace; begin if vx <> Nil then FreeMem (vx, sizeof (TMatElement) * s); vx := Nil; s := 0; end; { Internal routine to allocate space. If space already exists then it frees it first } procedure TVector.SetSize (i : integer); begin if vx <> Nil then FreeMem (vx, sizeof (TMatElement) * s); s := i; vx := AllocMem (sizeof (TMatElement) * s); //if gMat then beep; end; { Increase the size of the vector without destroying and existing data } procedure TVector.EnLargeBy (n : integer); begin if n < 0 then raise EVectorSizeError.Create ('Argument to EnLargeBy must be positive'); ReAllocMem (vx, sizeof (TMatElement)*(s+n)); inc (s,n); { Modified for D2 } end; { Reduce the size of the vector } procedure TVector.ReduceBy (n : integer); begin if n >= s then raise EVectorSizeError.Create ('Can''t reduce size of vector to below zero elements'); ReAllocMem (vx, sizeof (TMatElement)*(s-n)); dec (s,n); { modified for D2 } end; { Enlarge the vector by one element without destroying any existing data } procedure TVector.Enlarge; begin ReAllocMem (vx, sizeof (TMatElement)*(s+1)); inc (s); { Modified for D2 } end; { Reduce the vector by one element, the top most element is destroyed } procedure TVector.Reduce; begin ReAllocMem (vx, sizeof (TMatElement)*(s-1)); dec (s); { Modified for D2 } end; { Clears the vector, sets all elements to zero } procedure TVector.Zero; var i : integer; begin for i := 1 to s do vx^[i] := 0.0; end; { Clears the vector, sets all elements to zero } procedure TVector.Clear; begin Zero; end; { used internally but is also accessible from the outside } procedure TVector.Setval (i : integer; v : TMatElement); begin vx^[i] := v; end; { used internally but is also accessible from the outside } function TVector.Getval (i : integer) : TMatElement; begin result := vx^[i]; end; // ------------------------------------------------------------------------- // Copies vector v, including contects to self. If self is not the same // size as v then self is resized // Copy v to u: // Usage: u.Assign (v) // ------------------------------------------------------------------------- procedure TVector.Assign (v : TVector); begin v.Tmp := False; { just in case its a temporary variable } if v.s <> Self.s then Self.SetSize (v.s); move (v.vx^, Self.vx^, sizeof(TMatElement) * s) end; // ------------------------------------------------------------------------- // Add the vectors, 'v' and 'u' together to produce Self. Error if v and u are // the the same size. If Self is not sized correctly, then Add will resize Self // Usage: w.Add (u, v) // Add u to v giving result w // ------------------------------------------------------------------------- function TVector.Add (v, u : TVector) : TVector; var i : integer; begin if v.s <> u.s then raise EVectorSizeError.Create ('Vectors must be the same size to sum them'); if Self.s <> v.s then Self.SetSize (v.s); for i := 1 to v.s do Self[i] := v[i] + u[i]; if v.tmp then v.free; if u.tmp then u.free; result := Self; end; // ------------------------------------------------------------------------- // Add the vectors, 'v' and 'u' together and RETURN the result. An Error // occurs if v and u are the the same size. xAdd returns the result to the // caller therefore it is the responsibility of the caller to dispose of the // memory allocated by xSub. Note, the variable which is used to store the // returned result must not have been previously allocated, otherwise you'll // get memory leak! // w must be unallocated // Usage: w := Add (u, v) // Add u to v giving result w // ------------------------------------------------------------------------- class function TVector.xAdd (v, u : TVector) : TVector; var i : integer; t : TVector; begin if v.s <> u.s then raise EVectorSizeError.Create ('Vectors must be the same size to sum them'); t := TVector.CreateTmp (v.s); for i := 1 to v.s do t[i] := v[i] + u[i]; result := t; end; // ------------------------------------------------------------------------- // Subtract the vectors, 'v' and 'u' together to produce Self. Error if v and u are // the the same size. If Self is not sized correctly, then Add will resize Self // Usage: w.Sub (u, v) // Add u to v giving result w // ------------------------------------------------------------------------- function TVector.Sub (v, u : TVector) : TVector; var i : integer; begin if v.s <> u.s then raise EVectorSizeError.Create ('Vectors must be the same size to subtract them'); if Self.s <> v.s then Self.SetSize (v.s); for i := 1 to v.s do Self[i] := v[i] - u[i]; if v.tmp then v.free; if u.tmp then u.free; result := Self; end; // ------------------------------------------------------------------------- // Subtract the vectors, 'v' and 'u' together and RETURN the result. An Error // occurs if v and u are the the same size. xSub returns the result to the // caller therefore it is the responsibility of the caller to dispose of the // memory allocated by xSub. Note, the variable which is used to store the // returned result must not have been previously allocated, otherwise you'll // get memory leak! // w must be unallocated // Usage: w := Sub (u, v) // Add u to v giving result w // ------------------------------------------------------------------------- class function TVector.xSub (v, u : TVector) : TVector; var i : integer; t : TVector; begin if v.s <> u.s then raise EVectorSizeError.Create ('Vectors must be the same size to subtract them'); t := TVector.CreateTmp (v.s); for i := 1 to v.s do t[i] := v[i] - u[i]; result := t; end; // ------------------------------------------------------------------------- // Compute the dot product of vectors 'u' and 'v' // Usage: d := dot (u, v); // ------------------------------------------------------------------------- class function TVector.Dot (u, v : TVector) : TMatElement; var i : integer; begin if u.Size <> v.Size then raise EVectorSizeError.Create ('Vectors must be of the same size to compute dot product'); result := 0.0; for i := 1 to u.Size do result := result + u[i]*v[i]; end; // ------------------------------------------------------------------------- // Apply a dot product to Self and argument, 'v' // Usage: d := u.dotU (v); // ------------------------------------------------------------------------- function TVector.DotU (v : TVector) : TMatElement; var i : integer; begin if Self.Size <> v.Size then raise EVectorSizeError.Create ('Vectors must be of the same size to compute dot product'); result := 0.0; for i := 1 to Self.Size do result := result + Self[i]*v[i]; end; // ------------------------------------------------------------------------- // Compute the cross product of Self and vector 'v', replacing Self // Usage: v.CrossU (u) // ------------------------------------------------------------------------- function TVector.CrossU (v : TVector) : TVector; begin if (v.Size = 3) and (Self.Size = 3) then begin Self[1] := Self[2]*v[3] - Self[3]*v[2]; Self[2] := Self[3]*v[1] - Self[1]*v[3]; Self[3] := Self[1]*v[2] - Self[2]*v[1]; result := Self; end else raise EVectorSizeError.Create ('Cross product can only be calculated for vectors in 3D'); end; // ------------------------------------------------------------------------- // Compute the cross product of 'v1' and vector 'v2' giving Self // Usage: v.Cross (v1, v2) // ------------------------------------------------------------------------- function TVector.Cross (v1, v2 : TVector) : TVector; begin if (v1.Size = 3) and (v2.Size = 3) and (Self.Size = 3) then begin Self[1] := v1[2]*v2[3] - v1[3]*v2[2]; Self[2] := v1[3]*v2[1] - v1[1]*v2[3]; Self[3] := v1[1]*v2[2] - v1[2]*v2[1]; result := Self; end else raise EVectorSizeError.Create ('Cross product can only be calculated for vectors in 3D'); end; // ------------------------------------------------------------------------- // Returns the sum of values in the vector // Usage: total := v.sum // ------------------------------------------------------------------------- function TVector.Sum : TMatElement; var i : integer; begin result := 0.0; for i := 1 to s do result := result + vx^[i]; end; // ------------------------------------------------------------------------- // Returns the mean of the elements of the vector // Usage: average := v.mean; // ------------------------------------------------------------------------- function TVector.Mean : TMatElement; begin if s > 0 then result := sum / s else raise Exception.Create ('Vector must have at least one element to compute mean'); end; // ------------------------------------------------------------------------- // Returns the sum of the squares of values in Data // Usage: s := v.SumOfSquares; // ------------------------------------------------------------------------- function TVector.SumOfSquares : TMatElement; var i : integer; begin result := 0.0; for i := 1 to s do result := result + sqr(vx^[i]); end; // ------------------------------------------------------------------------- // Returns the Euclidean norm of the Self vector // ------------------------------------------------------------------------- function TVector.Norm : TMatElement; begin result := sqrt (Self.SumOfSquares); end; // ------------------------------------------------------------------------- // Returns the sample standard deviation // Usage: sd := v.StdDev; // ------------------------------------------------------------------------- function TVector.StdDev : TMatElement; var sq, total : TMatElement; i : integer; begin sq := 0; total := 0; if s > 1 then begin for i := 1 to s do begin sq := sq + sqr(vx^[i]); total := total + vx^[i]; end; result := sqrt ((sq - sqr(total)/s)/(s-1)); // The following code is easier to read but slightly slower in execution: // result := sqrt ((SumOfSquares - sqr (sum)/s)/(s-1));} end else raise Exception.Create ('Can''t calculate stddev for vector with one or no elements'); end; // ------------------------------------------------------------------------- // Scale the vector by factor // Usage: v.Scale (2) Multiplies all elements by 2 // ------------------------------------------------------------------------- procedure TVector.Scale (factor : TMatElement); var i : integer; begin for i := 1 to s do vx^[i] := vx^[i]*factor; end; { ------------------------------------------------------------------------- } { START OF INTEGER VECTOR IMPLEMETATION } { ------------------------------------------------------------------------- } { Create a vector of size i } constructor TVectori.create(i : integer); begin Inherited Create; vx := Nil; Self.SetSize (i); end; destructor TVectori.destroy; begin if vx <> Nil then FreeMem (vx, sizeof (integer) * s); Inherited Destroy; end; { Internal routine used by define } procedure TVectori.SetSize (NewSize : integer); begin if vx <> Nil then FreeMem (vx, sizeof (integer) * s); s := NewSize; vx := AllocMem (sizeof (integer) * NewSize); end; procedure TVectori.EnLargeBy (n : integer); begin ReAllocMem (vx, sizeof (integer)*(s+n)); inc (s,n); { Modified for D2 } end; procedure TVectori.ReduceBy (n : integer); begin if n >= s then raise EVectorSizeError.Create ('Can''t reduce size of vector to below zero elements'); ReAllocMem (vx, sizeof (integer)*(s-n)); dec (s,n); { Modified for D2 } end; { Enlarge the vector by one element without destroying any existing data } procedure TVectori.Enlarge; begin ReAllocMem (vx, sizeof (integer)*(s+1)); inc (s); { Modified for D2 } end; { Reduce the vector by one element, the top most element is destroyed } procedure TVectori.Reduce; begin ReAllocMem (vx, sizeof (integer)*(s-1)); dec (s); { Modified for D2 } end; { Clear the vector, sets all elements to zero } procedure TVectori.Zero; var i : integer; begin for i := 1 to s do vx^[i] := 0; end; { Clear the vector, sets all elements to zero } procedure TVectori.Clear; begin Zero; end; procedure TVectori.Assign (v : TVectori); begin if v.s <> Self.s then Self.SetSize (v.s); move (v.vx^, Self.vx^, sizeof(integer) * s) end; { used internally but is also accessible from the outside } procedure TVectori.Setval (i : integer; v : integer); begin vx^[i] := v; end; { used internally but is also accessible from the outside } function TVectori.Getval (i : integer) : integer; begin result := vx^[i]; end; function TVectori.GetSize : integer; begin result := s; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npmform.pas����������������������������������������������0000755�0001750�0001750�00000474260�12147221422�020357� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit npmform; {$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF} interface {$I options.inc} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, Messages, Classes, Graphics, Controls, Forms, Dialogs, Menus, ComCtrls, ExtCtrls, StdCtrls, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr,tfce_clustering, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ELSE} LCLType, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes,turbolesion {$IFDEF compileANACOM}, anacom{$ENDIF} {$IFDEF benchmark}, montecarlo{$ENDIF} ; //regmultdelphi,matrices; type { TMainForm } TMainForm = class(TForm) Binaryimagescontinuousgroupsfast1: TMenuItem; Memo1: TMemo; Design1: TMenuItem; FCE1: TMenuItem; MultipleRegress: TMenuItem; SaveText1: TMenuItem; ROIanalysis1: TMenuItem; OpenHdrDlg: TOpenDialog; SaveHdrDlg: TSaveDialog; Panel1: TPanel; ProgressBar1: TProgressBar; MainMenu1: TMainMenu; About1: TMenuItem; AssociatevalfileswithNPM1: TMenuItem; Balance1: TMenuItem; BinomialAnalysislesions1: TMenuItem; BMmenu: TMenuItem; ContinuousanalysisVBM1: TMenuItem; Copy1: TMenuItem; Countlesionoverlaps1: TMenuItem; Edit1: TMenuItem; Exit1: TMenuItem; File1: TMenuItem; Help1: TMenuItem; IntensitynormalizationA1: TMenuItem; Makemeanimage1: TMenuItem; Makemeanimage2: TMenuItem; N0: TMenuItem; N1000: TMenuItem; N2000: TMenuItem; N3000: TMenuItem; N4000: TMenuItem; niiniigz1: TMenuItem; Options1: TMenuItem; PairedTMenu: TMenuItem; PenalizedLogisticRegerssion1: TMenuItem; Permutations1: TMenuItem; PhysiologicalArtifactCorrection1: TMenuItem; SingleRegress: TMenuItem; SingleSubjectZScores1: TMenuItem; T1: TMenuItem; T15: TMenuItem; T16: TMenuItem; T2: TMenuItem; T3: TMenuItem; T4: TMenuItem; T7: TMenuItem; T8: TMenuItem; Tests1: TMenuItem; Threads1: TMenuItem; ttestmenu: TMenuItem; Utilities1: TMenuItem; Variance1: TMenuItem; VBM1: TMenuItem; VLSM1: TMenuItem; ComputeIntersectionandUnion1: TMenuItem; Intensitynormalization1: TMenuItem; Masked1: TMenuItem; MaskedintensitynormalizationA1: TMenuItem; MaskedintensitynormalizationB1: TMenuItem; //Binaryimagescontinuousgroupsfast1: TMenuItem; Binarizeimages1: TMenuItem; Resliceimagetoneworientationandboundingbox1: TMenuItem; Setnonseroto1001: TMenuItem; AnaCOMmenu: TMenuItem; MonteCarloSimulation1: TMenuItem; Subtract1: TMenuItem; LogPtoZ1: TMenuItem; //FCE1: TMenuItem; function GetKVers: string; function GetValX (var lnSubj, lnFactors: integer; var lSymptomRA: singleP; var lImageNames: TStrings; var lCrit: integer; {lBinomial : boolean;} var lPredictorList: TStringList):boolean; function ThreshMap(lThresh: single; lVolVox: integer;lOutImg: singleP): integer; function FirthNPMAnalyze (var lImages: TStrings; var lPredictorList: TStringList; var lMaskHdr: TMRIcroHdr; lnCond,lnCrit: integer; var lSymptomRA: SingleP; var lOutName: string): boolean; procedure InitPermute (lnSubj, lnPermute: integer; var lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP; var lRanOrderp: pointer; var lRanOrder: Doublep0); function reportPermute (lLabel:string; lnPermute: integer; var lPermuteMaxZ, lPermuteMinZ: singleP): double; procedure FreePermute (lnPermute: integer; var lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP;var lRanOrderp: pointer); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); function SaveHdrName (lCaption: string; var lFilename: string): boolean; procedure StrToMemo (lStr: string); procedure NPMclick(Sender: TObject); function OpenDialogExecute (lCaption: string;lAllowMultiSelect,lForceMultiSelect: boolean; lFilter: string): boolean;//; lAllowMultiSelect: boolean): boolean; function NPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lMaskVoxels,lnGroup1: integer): boolean; function NPMAnalyzePaired (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lMaskVoxels: integer): boolean; function NPMzscore (var lImages: TStrings; var lMnHdr,lStDevHdr: TMRIcroHdr): boolean; procedure FormCreate(Sender: TObject); function ReportDescriptives (var RA: SingleP; n: integer): boolean; function MakeSubtract (lPosName,lNegName: string): boolean; function MakeMean (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lBinarize,lVariance: boolean): boolean; function Balance (var lImageName,lMaskName: String; lMethod: integer{lInflection: boolean}): boolean; procedure LesionBtnClick(Sender: TObject); procedure Copy1Click(Sender: TObject); procedure testmenuclick(Sender: TObject); procedure radiomenuclick(Sender: TObject); procedure ReadIniFile; procedure WriteIniFile; function reportBonferroni(lLabel: string; lnTests: integer): double; function reportFDR (lLabel:string; lnVox, lnTests: integer; var lData: SingleP): double; procedure Makemeanimage1Click(Sender: TObject); procedure Exit1Click(Sender: TObject); procedure Balance1Click(Sender: TObject); procedure niiniigz1Click(Sender: TObject); procedure Variance1Click(Sender: TObject); procedure ZtoP1Click(Sender: TObject); procedure About1Click(Sender: TObject); procedure Design1Click(Sender: TObject); procedure PhysiologicalArtifactCorrection1Click(Sender: TObject); procedure DualImageCorrelation1Click(Sender: TObject); procedure FormShow(Sender: TObject); procedure PairedTMenuClick(Sender: TObject); procedure SingleSubjectZScores1Click(Sender: TObject); procedure MultipleRegressClick(Sender: TObject); function ReadPermute: integer; procedure NPMmsg( lStr: string); procedure NPMmsgClear; procedure MsgSave(lFilename: string); procedure SingleRegressClick(Sender: TObject); procedure AssociatevalfileswithNPM1Click(Sender: TObject); procedure threadChange(Sender: TObject); procedure Countlesionoverlaps1Click(Sender: TObject); procedure PenalizedLogisticRegerssion1Click(Sender: TObject); procedure ComputeIntersectionandUnion1Click(Sender: TObject); procedure ROCbinomialdeficit1Click(Sender: TObject); procedure ROCcontinuousdeficit1Click(Sender: TObject); procedure ThreadDone(Sender: TObject); procedure NPMmsgAppend( lStr: string); procedure ROIanalysis1Click(Sender: TObject); procedure Masked1Click(Sender: TObject); procedure Binarizeimages1Click(Sender: TObject); procedure Resliceimagetoneworientationandboundingbox1Click( Sender: TObject); procedure Setnonseroto1001Click(Sender: TObject); procedure Savetext1Click(Sender: TObject); procedure AnaCOMmenuClick(Sender: TObject); procedure MonteCarloSimulation1Click(Sender: TObject); procedure Subtract1Click(Sender: TObject); procedure LogPtoZ1Click(Sender: TObject); procedure FCE1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var MainForm: TMainForm; implementation uses filename,prefs,roc,hdr,regression,valformat {$IFDEF SPREADSHEET} ,design,spread{$ENDIF} {$IFNDEF UNIX},ActiveX {$ENDIF}; {$IFNDEF FPC} {$R *.DFM} {$ENDIF} const kVers : string = 'Chris Rorden''s NPM :: '+kMRIcronVers; var gNULP: boolean = true; gROI : boolean = false; gTFCE: integer; function TMainForm.GetKVers: string; begin result := kVers +'; Threads used = '+inttostr(gnCPUThreads ); end; procedure TMainForm.NPMmsgAppend( lStr: string); var lOutname: string; f: TextFile; begin MainForm.Memo1.Lines.add(lStr); lOutname:='c:\dx.txt'; if fileexists(lOutname) then begin { open a text file } AssignFile(f, lOutname); Append(f); Writeln(f, lStr); Flush(f); { ensures that the text was actually written to file } { insert code here that would require a Flush before closing the file } CloseFile(f); end; end; procedure TMainForm.NPMmsg( lStr: string); begin MainForm.Memo1.Lines.add(lStr); end; procedure Msg(lStr: string); begin MainForm.NPMmsg(lStr); end; procedure MsgClear; begin MainForm.Memo1.Lines.Clear; end; procedure TMainForm.NPMmsgClear; begin MsgClear; end; procedure TMainForm.MsgSave(lFilename: string); var i: integer; f: textfile; begin if (Memo1.Lines.Count < 1) then exit; if fileexists(lFilename) then begin AssignFile(f, lFilename); {$I-} append(f); {$I+} if IOResult= 0 then for i:= 0 to Memo1.Lines.Count- 1 do WriteLn(f, Memo1.Lines[i]); CloseFile(f); end else MainForm.Memo1.Lines.SaveToFile(lFilename); end; procedure TMainForm.ThreadDone(Sender: TObject); begin Dec(gThreadsRunning); end; procedure InitRA (lnPermute: integer; var lRA: singleP); var lInc: integer; begin getmem(lRA,lnPermute* sizeof(single)); for lInc := 1 to lnPermute do lRA^[lInc] := 0; end; procedure TMainForm.InitPermute (lnSubj, lnPermute: integer; var lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP; var lRanOrderp: pointer; var lRanOrder: Doublep0); begin if (lnPermute < 2) then exit; InitRA(lnPermute,lPermuteMaxT); InitRA(lnPermute,lPermuteMinT); InitRA(lnPermute,lPermuteMaxBM); InitRA(lnPermute,lPermuteMinBM); createArray64(lRanOrderp,lRanOrder,lnSubj); end; //init permute procedure sort (lo, up: integer; var r:SingleP); //62ms Shell Sort http://www.dcc.uchile.cl/~rbaeza/handbook/algs/4/414.sort.p.html label 999; var d, i, j : integer; tempr : single; begin d := up-lo+1; while d>1 do begin if d<5 then d := 1 else d := trunc( 0.45454*d ); //Do linear insertion sort in steps size d for i:=up-d downto lo do begin tempr := r^[i]; j := i+d; while j <= up do if tempr > r^[j] then begin r^[j-d] := r^[j]; j := j+d end else goto 999; //break 999: r^[j-d] := tempr end //for end //while end; //proc Sort function IndexPct(lnPermute: integer; lPct: single; lTop: boolean): integer; begin result := round(lnPermute * lPct); if lTop then result := (lnPermute - result)+1; if (result < 1) then result := 1; if (result > lnPermute) then result := lnPermute; end; function TMainForm.reportBonferroni(lLabel: string; lnTests: integer): double; //returns 5% Z score begin if lnTests < 1 then exit; result := pNormalInv(0.05/lnTests); msg(inttostr(lnTests)+' test '+lLabel+' Bonferroni FWE Z '+ '0.050='+realtostr(result,3)+ ', 0.025='+realtostr(pNormalInv(0.025/lnTests),3)+ ', 0.01='+realtostr(pNormalInv(0.01/lnTests),3)); end; function TMainForm.reportFDR (lLabel:string; lnVox, lnTests: integer; var lData: SingleP): double; var lC,lN: integer; lPs: SingleP; lFDR05r, lFDR01r,lFDR05p, lFDR01p,lMin,lMax : double; begin result := 10000; if (lnTests < 1) or (lnVox < 1) then exit; GetMem(lPs,lnTests*sizeof(single)); for lC := 1 to lnTests do lPs^[lC] := 0; lN := 0; lMin := 0; lMax := 0; for lC := 1 to lnVox do begin if lData^[lC] <> 0 then begin inc(lN); if lData^[lC] > lMax then lMax := lData^[lC] else if lData^[lC] < lMin then lMin := lData^[lC]; if lN <= lnTests then lPs^[lN] := pNormal(lData^[lC]); end; end; EstimateFDR2(lnTests, lPs, lFDR05p, lFDR01p,lFDR05r, lFDR01r); msg(lLabel+' Range ' +realtostr(lMin,3)+ '...'+realtostr(lMax,3)); {Msg(lLabel+' Range ' +realtostr(pNormalInv(lPs[lnTests]),3)+ '...'+realtostr(pNormalInv(lPs[1]),3)+ ' '); } //we could use this and save time computing lmin/lmax, but loss in precision msg(lLabel+' +FDR Z '+ '0.050='+realtostr(pNormalInv(lFDR05p),8)+ ', 0.01='+realtostr(pNormalInv(lFDR01p),8)+ ' '); msg(lLabel+' -FDR Z '+ '0.050='+realtostr(pNormalInv(1-lFDR05r),8)+ ', 0.01='+realtostr(pNormalInv(1-lFDR01r),8)+ ' '); result := pNormalInv(lFDR01p); end; function ReportThresh (lLabel: string; lnPermute: integer; var lRankedData: singleP;lTop:boolean): double; begin result := lRankedData^[IndexPct(lnPermute,0.050,lTop)]; msg(lLabel+': permutationFWE '+ //'0.500='+realtostr(lRankedData[IndexPct(lnPermute,0.500,lTop)],3)+ ', 0.050='+realtostr({lRankedData^[IndexPct(lnPermute,0.050,lTop)]} result,8)+ ', 0.025='+realtostr(lRankedData^[IndexPct(lnPermute,0.025,lTop)],8)+ ', 0.01='+realtostr(lRankedData^[IndexPct(lnPermute,0.010,lTop)],8)+ ' '); end; function TMainForm.reportPermute (lLabel:string; lnPermute: integer; var lPermuteMaxZ, lPermuteMinZ: singleP): double; begin result := 0; if (lnPermute < 2) then exit; sort (1, lnPermute,lPermuteMaxZ); result := ReportThresh(lLabel+'+',lnPermute,lPermuteMaxZ,true); sort (1, lnPermute,lPermuteMinZ); ReportThresh(lLabel+'-',lnPermute,lPermuteMinZ,false); //for lPos := 1 to lnPermute do // msg(inttostr(lPos)+', '+realtostr(lPermuteMinZ[lPos],4)); end; procedure TMainForm.FreePermute (lnPermute: integer; var lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP;var lRanOrderp: pointer); begin if (lnPermute < 2) then exit; Freemem(lRanOrderp); Freemem(lPermuteMaxT); Freemem(lPermuteMinT); Freemem(lPermuteMaxBM); Freemem(lPermuteMinBM); end; function TMainForm.SaveHdrName (lCaption: string; var lFilename: string): boolean; begin result := false; SaveHdrDlg.InitialDir := lFilename; SaveHdrDlg.Title := lCaption; SaveHdrDlg.Filter := kAnaHdrFilter; if not SaveHdrDlg.Execute then exit; lFilename := SaveHdrDlg.Filename; result := true; end; procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin //showmessage('zz'); WriteIniFile; end; procedure MakeStatHdr (var lBGHdr,lStatHdr: TniftiHdr; lMinIntensity,lMaxIntensity,lIntent_p1,lIntent_p2,lIntent_p3: single; lIntent_code: smallint;lIntentName: string); var lIntentNameLen,lPos: integer; lStr: string; begin move(lBGHdr,lStatHdr,sizeof(TniftiHdr)); with lStatHdr do begin magic :=kNIFTI_MAGIC_SEPARATE_HDR; bitpix := 32; //32-bit real data datatype := kDT_FLOAT; scl_slope:= 1; scl_inter:= 0; glmin := round(lMinIntensity); glmax := round(lMaxIntensity); intent_code := lIntent_Code;// kNIFTI_INTENT_ESTIMATE; intent_p1 := lIntent_p1; intent_p2 := lIntent_p2; intent_p3 := lIntent_p3; lIntentNameLen := length(lIntentName); descrip[1] := 'N'; descrip[2] := 'P'; descrip[3] := 'M'; if lIntent_code=kNIFTI_INTENT_TTEST then begin descrip[4] := 't' ; lStr := inttostr(trunc(lIntent_p1)); for lPos := 1 to length (lStr) do descrip[4+lPos] := lStr[lPos] ; end else descrip[4] := 'z'; if lIntentNameLen > sizeof(intent_name) then lIntentNameLen := sizeof(intent_name); if lIntentNameLen > 0 then for lPos := 1 to lIntentNameLen do intent_name[lPos] := lIntentName[lPos]; end; end; procedure WriteThread( lnThread: integer); begin case lnThread of 2: MainForm.T2.checked := true; 3: MainForm.T3.checked := true; 4: MainForm.T4.checked := true; 7: MainForm.T7.checked := true; 8: MainForm.T8.checked := true; 15: MainForm.T15.checked := true; 16: MainForm.T16.checked := true; else MainForm.T1.checked := true; end; gnCPUThreads := lnThread; end; function ReadThread: integer; begin if MainForm.T16.checked then result := 16 else if MainForm.T15.checked then result := 15 else if MainForm.T8.checked then result := 8 else if MainForm.T7.checked then result := 7 else if MainForm.T4.checked then result := 4 else if MainForm.T3.checked then result := 3 else if MainForm.T2.checked then result := 2 else result := 1; gnCPUThreads := result; end; procedure WritePermute( lnPermute: integer); begin case lnPermute of 4000: MainForm.N4000.checked := true; 3000: MainForm.N3000.checked := true; 2000: MainForm.N2000.checked := true; 1000: MainForm.N1000.checked := true; else MainForm.N0.checked := true; end; end; function TMainForm.ReadPermute: integer; begin if MainForm.N4000.checked then result := 4000 else if MainForm.N3000.checked then result := 3000 else if MainForm.N2000.checked then result := 2000 else if MainForm.N1000.checked then result := 1000 else result := 0; end; (*function LoadImgX(lInName: string; lImgData: SingleP; lStart, lEnd,linvox_offset,lRApos,lDataType,lVolVox: integer): boolean; var lInc: integer; begin //LoadImgX(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox); for lInc := 1 to ((lEnd{+1})-lStart) do lImgData^[lRApos+lInc-1] := 123; msg(inttostr(lRApos+1-1)+' '+inttostr(lRApos+((lEnd+1)-lStart)-1) ); end;*) function TMainForm.NPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lMaskVoxels,lnGroup1: integer): boolean; label 667; var lOutName,lOutNameMod: string; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lDummy: SingleP; lTotalMemory: double; //not integer - limit for 32bit int is 2Gb lPlank,lVolVox,lPos,lMinMask,lMaxMask,lnPlanks,lVoxPerPlank, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lThreadStart,lThreadEnd,lThreadInc: integer; lT, lSum, lMn: double; lStatHdr: TNIfTIhdr; lFdata: file; lThread,lnPermute: integer; lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP; lRanOrderp: pointer; lRanOrder: Doublep0; lttest,lBM: boolean; begin result := false; lttest:= ttestmenu.checked; lBM := BMmenu.checked; lnPermute := ReadPermute; //lnPermute := 100; msg('Permutations = ' +IntToStr(lnPermute)); lOutName := lMaskHdr.ImgFileName; if not SaveHdrName ('Statistical Map', lOutName) then exit; msg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; //load mask getmem(lMaskImg,lVolVox*sizeof(single)); if not LoadImg(lMaskHdr.ImgFileName, lMaskImg, 1, lVolVox,round(gOffsetRA[0]),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin msg('Unable to load mask ' +lMaskHdr.ImgFileName); goto 667; end; //next find start and end of mask lPos := 0; repeat inc(lPos); until (lMaskImg^[lPos] > 0) or (lPos = lVolVox); lMinMask := lPos; lPos := lVolVox+1; repeat dec(lPos); until (lMaskImg^[lPos] > 0) or (lPos = 1); lMaxMask := lPos; if lMaxMask = 1 then begin msg('Mask appears empty' +lMaskHdr.ImgFileName); goto 667; end; msg('Mask has voxels from '+inttostr(lMinMask)+'..'+inttostr(lMaxMask)); lVoxPerPlank := kPlankSz div lImages.Count div sizeof(single) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; msg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); msg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; getmem(lOutImgMn,lVolVox* sizeof(single)); getmem(lOutImgBM,lVolVox* sizeof(single)); getmem(lOutImgT,lVolVox* sizeof(single)); InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgMn^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; end; ClearThreadData(gnCPUThreads,lnPermute); for lPlank := 1 to lnPlanks do begin msg('Computing plank = ' +Inttostr(lPlank)); Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //showmessage('stop'); //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TNNStat.Create (ProgressBar1,lttest,lBM,0, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lnGroup1, lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lDummy) do {$IFDEF FPC} OnTerminate := @ThreadDone; {$ELSE}OnTerminate := ThreadDone;{$ENDIF} inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; lnVoxTested := SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //next report findings msg('Voxels tested = ' +Inttostr(lnVoxTested)); reportBonferroni('Std',lnVoxTested); //next: save data (*savedata*) MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save mean lOutNameMod := ChangeFilePostfixExt(lOutName,'Mean','.hdr'); if lnVoxTested > 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgMn,1); MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lttest) and (lnVoxTestED > 1 ) then begin //save Ttest //reportRange ('ttest', lVolVox, lnVoxTested, lOutImgT); //next: convert t-scores to z scores for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lnPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); reportPermute('ttest',lnPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'ttest','.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if (lBM) and (lnVoxTested > 1 ) then begin //save Brunner Munzel reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); reportPermute('BM',lnPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'BM','.hdr'); {reportFDR ('absT', lVolVox, lnVoxTested, lOutImgBM); reportPermute('absT',lnPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'absT','.hdr'); } //NIFTIhdr_SaveHdr(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr)); lOutNameMod := changefileext(lOutNameMod,'.img'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end;(**) //next: close images FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgT); freemem(lOutImgBM); freemem(lOutImgMn); //freemem(lObsp); freemem(lMaskImg); freemem(lPlankImg); msg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes','.txt'); MsgSave(lOutNameMod); ProgressBar1.Position := 0; result := true; exit; 667: //you only get here if you aborted ... free memory and report error if lVolVox > 1 then freemem(lMaskImg); if lTotalMemory > 1 then freemem(lPlankImg); msg('Unable to complete analysis.'); ProgressBar1.Position := 0; end; function TMainForm.NPMAnalyzePaired (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lMaskVoxels: integer): boolean; label 667; var lOutName,lOutNameMod: string; lMaskImg,lPlankImg,lOutImgMn,lOutImgT,lDummy,lDummy2: SingleP; lTotalMemory: double; //not integer - limit for 32bit int is 2Gb lPlank,lVolVox,lPos,lMinMask,lMaxMask,lnPlanks,lVoxPerPlank, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lThreadStart,lThreadEnd,lThreadInc: integer; lT, lSum, lMn: double; lStatHdr: TNIfTIhdr; lFdata: file; lThread,lnPermute: integer; lPermuteMaxT, lPermuteMinT: singleP; lRanOrderp: pointer; lRanOrder: Doublep0; begin //lnPermute := ReadPermute; lnPermute := 0;//not yet msg('Permutations = ' +IntToStr(lnPermute)); lOutName := lMaskHdr.ImgFileName; if not SaveHdrName ('Statistical Map', lOutName) then exit; msg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; //load mask getmem(lMaskImg,lVolVox*sizeof(single)); if not LoadImg(lMaskHdr.ImgFileName, lMaskImg, 1, lVolVox,round(gOffsetRA[0]),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin msg('Unable to load mask ' +lMaskHdr.ImgFileName); goto 667; end; //next find start and end of mask lPos := 0; repeat inc(lPos); until (lMaskImg^[lPos] > 0) or (lPos = lVolVox); lMinMask := lPos; lPos := lVolVox+1; repeat dec(lPos); until (lMaskImg^[lPos] > 0) or (lPos = 1); lMaxMask := lPos; if lMaxMask = 1 then begin Msg('Mask appears empty' +lMaskHdr.ImgFileName); goto 667; end; Msg('Mask has voxels from '+inttostr(lMinMask)+'..'+inttostr(lMaxMask)); lVoxPerPlank := kPlankSz div lImages.Count div sizeof(single) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; Msg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); Msg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; getmem(lOutImgMn,lVolVox* sizeof(single)); getmem(lOutImgT,lVolVox* sizeof(single)); //not yet InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgMn^[lPos] := 0; lOutImgT^[lPos] := 0; end; ClearThreadData(gnCPUThreads,lnPermute); for lPlank := 1 to lnPlanks do begin Msg('Computing plank = ' +Inttostr(lPlank)); Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TPairedTStat.Create (ProgressBar1,false,false,0, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,666, lMaskImg,lPlankImg,lOutImgMn,lDummy2,lOutImgT,lDummy) do {$IFDEF FPC} OnTerminate := @ThreadDone; {$ELSE}OnTerminate := ThreadDone;{$ENDIF} inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; lnVoxTested := SumThreadDataLite(gnCPUThreads);//not yet SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //next report findings Msg('Voxels tested = ' +Inttostr(lnVoxTested)); reportBonferroni('Std',lnVoxTested); //next: save data (*savedata *) MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save mean lOutNameMod := ChangeFilePostfixExt(lOutName,'Mean','.hdr'); if lnVoxTested > 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgMn,1); MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lnVoxTestED > 1 ) then begin //save Ttest //next: convert t-scores to z scores for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],(lImages.Count div 2)-1); for lPos := 1 to lnPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); reportPermute('ttest',lnPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'ttest','.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; //next: close images //not yet FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgT); freemem(lOutImgMn); //freemem(lObsp); freemem(lMaskImg); freemem(lPlankImg); Msg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes','.txt'); MsgSave(lOutNameMod); ProgressBar1.Position := 0; exit; 667: //you only get here if you aborted ... free memory and report error if lVolVox > 1 then freemem(lMaskImg); if lTotalMemory > 1 then freemem(lPlankImg); Msg('Unable to complete analysis.'); ProgressBar1.Position := 0; end; function TMainForm.OpenDialogExecute (lCaption: string;lAllowMultiSelect,lForceMultiSelect: boolean; lFilter: string): boolean;//; lAllowMultiSelect: boolean): boolean; var lNumberofFiles: integer; begin OpenHdrDlg.Filter := lFilter;//kAnaHdrFilter;//lFilter; OpenHdrDlg.FilterIndex := 1; OpenHdrDlg.Title := lCaption; if lAllowMultiSelect then OpenHdrDlg.Options := [ofAllowMultiSelect,ofFileMustExist] else OpenHdrDlg.Options := [ofFileMustExist]; result := OpenHdrDlg.Execute; if not result then exit; if lForceMultiSelect then begin lNumberofFiles:= OpenHdrDlg.Files.Count; if lNumberofFiles < 2 then begin Showmessage('Error: This function is designed to overlay MULTIPLE images. You selected less than two images.'); result := false; end; end; end; procedure TMainForm.NPMclick(Sender: TObject); label 666; var lnGroup1,lMaskVoxels: integer; lG: TStrings; lMaskname: string; lMaskHdr: TMRIcroHdr; begin if (not ttestmenu.checked) and (not BMmenu.checked) then begin Showmessage('Error: you need to compute at least on test [options/test menu]'); exit; end; MsgClear; Msg(GetKVers); Msg('Threads: '+inttostr(gnCPUThreads)); if not OpenDialogExecute('Select brain mask ',false,false,kImgFilter) then begin showmessage('NPM aborted: mask selection failed.'); exit; end; //if not selected lMaskname := OpenHdrDlg.Filename; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading mask.'); exit; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); exit; end; Msg('Mask name = '+ lMaskname); Msg('Total voxels = '+inttostr(lMaskVoxels)); //next, get 1st group if not OpenDialogExecute('Select postive group (Z scores positive if this group is brighter)',true,true,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected lG:= TStringList.Create; //not sure why TStrings.Create does not work??? lG.addstrings(OpenHdrDlg.Files); lnGroup1 :=OpenHdrDlg.Files.Count; Msg('Scans in Group 1 = '+inttostr(lnGroup1)); //next, get 2nd group if not OpenDialogExecute('Select negative group (Z scores negative if this group is brighter)',true,true,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); goto 666; end; //if not selected lG.addstrings(OpenHdrDlg.Files); if not CheckVoxelsGroupX(lG,lMaskHdr {lMaskVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; Msg('Scans in Group 2 = '+inttostr(lG.count-lnGroup1)); NPMAnalyze(lG,lMaskHdr,lMaskVoxels,lnGroup1); 666: lG.Free; end; function TMainForm.ThreshMap(lThresh: single; lVolVox: integer;lOutImg: singleP): integer; var lVox: integer; begin result := 0; for lVox := 1 to lVolVox do if lOutImg^[lVox] >= lThresh then inc(result); for lVox := 1 to lVolVox do if lOutImg^[lVox] >= lThresh then lOutImg^[lVox] := 1 else lOutImg^[lVox] := 0; end; {x$DEFINE NOTmedianfx} (*function TMainForm.LesionNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun: integer; var lSymptomRA: SingleP;var lFactname,lOutName: string): boolean; label 123,667; var lOutNameMod: string; lPlankImg: byteP; lOutImgSum,lOutImgBM,lOutImgT, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP; lPos,lPlank,lThread: integer; lVolVox,lMinMask,lMaxMask,lTotalMemory,lnPlanks,lVoxPerPlank, lThreadStart,lThreadEnd,lThreadInc,lnLesion,lnPermute, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT,lBMz, lSum,lThresh :double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; lttest,lBM: boolean; {$IFDEF medianfx} lmedianFX,lmeanFX,lsummean,lsummedian: double; lmediancount: integer; {$ENDIF} begin lttest:= ttestmenu.checked; lBM := BMmenu.checked; lnPermute := ReadPermute; Msg('Permutations = ' +IntToStr(lnPermute)); Msg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; Msg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); Msg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) //assumes 1bpp else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; {$IFDEF medianfx} lsummean := 0; lsummedian:= 0; lmediancount := 0; {$ENDIF} for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; createArray64(lObsp,lObs,lImages.Count); getmem(lOutImgSum,lVolVox* sizeof(single)); getmem(lOutImgBM,lVolVox* sizeof(single)); getmem(lOutImgT,lVolVox* sizeof(single)); InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; end; //next create permuted BM bounds if lBM then begin Msg('Generating BM permutation thresholds'); Refresh; for lPos := 1 to lImages.Count do lObs^[lPos-1] := lSymptomRA^[lPos]; genBMsim (lImages.Count, lObs); end; ClearThreadData(gnCPUThreads,lnPermute) ; for lPlank := 1 to lnPlanks do begin Msg('Computing plank = ' +Inttostr(lPlank)); Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TLesionContinuous.Create (ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,0,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,nil,lSymptomRA) do {$IFDEF FPC} OnTerminate := @ThreadDone; {$ELSE}OnTerminate := ThreadDone;{$ENDIF} inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; lnVoxTested := SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //next report findings if lnVoxTested < 1 then begin Msg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lnCrit)+' patients**'); goto 123; end; Msg('Voxels tested = ' +Inttostr(lnVoxTested)); {$IFDEF medianfx} Msg('Average MEAN effect size = ' +realtostr((lsummean/lmediancount),3)); Msg('Average MEDIAN effect size = ' +realtostr((lsummedian/lmediancount),3)); {$ENDIF} Msg('Only tested voxels with more than '+inttostr(lnCrit)+' lesions'); //Next: save results from permutation thresholding.... reportBonferroni('Std',lnVoxTested); //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //create new header - subsequent images will use Z-scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if Sum2PowerCont(lOutImgSum,lVolVox,lImages.Count) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; //MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if lttest then begin //save Ttest //next: convert t-scores to z scores for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lnPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; lThresh := reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); reportPermute('ttest',lnPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'ttest'+lFactName,'.hdr'); if lRun > 0 then Msg('threshtt,'+inttostr(lRun)+','+inttostr(ThreshMap(lThresh,lVolVox,lOutImgT))+','+realtostr(lThresh,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if lBM then begin //save Mann Whitney lThresh := reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); reportPermute('BM',lnPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'BM'+lFactName,'.hdr'); if lRun > 0 then Msg('threshbm,'+inttostr(lRun)+','+inttostr(ThreshMap(lThresh,lVolVox,lOutImgBM))+','+realtostr(lThresh,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end; //next: free dynamic memory 123: FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgT); freemem(lOutImgBM); freemem(lOutImgSum); freemem(lObsp); freemem(lPlankImg); Msg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); MsgSave(lOutNameMod); ProgressBar1.Position := 0; exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); Msg('Unable to complete analysis.'); ProgressBar1.Position := 0; end; //LesionNPMAnalyze *) (*function TMainForm.LesionNPMAnalyzeBinomial (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit: integer; var lSymptomRA: SingleP; var lFactname,lOutName: string): boolean; label 123,667; var lVal: single; lOutNameMod: string; lPlankImg: byteP; lOutImgSum,lOutImgL,lDummyImg, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP; lPos,lPlank,lThread,lnDeficit: integer; lTotalMemory,lVolVox,lMinMask,lMaxMask,lnPlanks,lVoxPerPlank, lThreadStart,lThreadInc,lThreadEnd, lnLesion,lnPermute, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT, lSum: double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; begin lnPermute := ReadPermute; Msg('Permutations = ' +IntToStr(lnPermute)); //lOutName := lMaskHdr.ImgFileName; //if not SaveHdrName ('Statistical Map', lOutName) then exit; Msg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; Msg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); Msg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) //assumes 1bp else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; createArray64(lObsp,lObs,lImages.Count); getmem(lOutImgSum,lVolVox* sizeof(single)); getmem(lOutImgL,lVolVox* sizeof(single)); InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgL^[lPos] := 0; end; ClearThreadDataPvals(gnCPUThreads,lnPermute) ; for lPlank := 1 to lnPlanks do begin ProgressBar1.Position := 1; Msg('Computing plank = ' +Inttostr(lPlank)); Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error //with TLesionBinomial.Create (ProgressBar1,false,true,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,666, lDummyImg,lPlankImg,lOutImgSum,lOutImgL,lDummyImg,lSymptomRA) do with TLesionBinom.Create (ProgressBar1,false,true,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,0,lPlankImg,lOutImgSum,lOutImgL,lDummyImg,nil,lSymptomRA) do {$IFDEF FPC} OnTerminate := @ThreadDone; {$ELSE}OnTerminate := ThreadDone;{$ENDIF} inc(gThreadsRunning); Msg('Thread ' +Inttostr(gThreadsRunning)+' = '+inttostr(lThreadStart)+'..'+inttostr(lThreadEnd)); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; lnVoxTested := SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); for lPos := 1 to lnPermute do begin if (lPermuteMinT^[lPos] > 1.1) or (lPermuteMinT^[lPos] < -1.1) then lPermuteMinT^[lPos] := 0.5; if (lPermuteMaxT^[lPos] > 1.1) or (lPermuteMaxT^[lPos] < -1.1) then lPermuteMaxT^[lPos] := 0.5; lVal := lPermuteMaxT^[lPos]; lPermuteMaxT^[lPos] := lPermuteMinT^[lPos]; lPermuteMinT^[lPos] := lVal; if lPermuteMaxT^[lPos] < 0 then lPermuteMaxT^[lPos] := -pNormalInv(abs(lPermuteMaxT^[lPos])) else lPermuteMaxT^[lPos] := pNormalInv(lPermuteMaxT^[lPos]); if lPermuteMinT^[lPos] < 0 then lPermuteMinT^[lPos] := -pNormalInv(abs(lPermuteMinT^[lPos])) else lPermuteMinT^[lPos] := pNormalInv(lPermuteMinT^[lPos]); end; if lnVoxTested < 1 then begin Msg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lnCrit)+' patients**'); goto 123; end; //next report findings Msg('Voxels tested = ' +Inttostr(lnVoxTested)); Msg('Only tested voxels with more than '+inttostr(lnCrit)+' lesions'); //Next: save results from permutation thresholding.... reportBonferroni('Std',lnVoxTested); //next: save data //savedata MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //future images will store Z-scores... MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); //save power map lnDeficit := 0; for lPos := 1 to lImages.Count do if lSymptomRA^[lPos] = 0 then inc(lnDeficit); if Sum2Power(lOutImgSum,lVolVox,lImages.Count,lnDeficit) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; // MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); //save Liebermeister lOutNameMod := ChangeFilePostfixExt(lOutName,'L'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgL,1); //save end reportFDR ('L', lVolVox, lnVoxTested, lOutImgL); reportPermute('L',lnPermute,lPermuteMaxT, lPermuteMinT); 123: //next: free dynamic memory FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgL); freemem(lOutImgSum); freemem(lObsp); freemem(lPlankImg); Msg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); MsgSave(lOutNameMod); ProgressBar1.Position := 0; exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); Msg('Unable to complete analysis.'); ProgressBar1.Position := 0; end; *) function TMainForm.GetValX (var lnSubj, lnFactors: integer; var lSymptomRA: singleP; var lImageNames: TStrings; var lCrit: integer; {lBinomial : boolean;} var lPredictorList: TStringList):boolean; //warning: you MUST free lPredictorList var lVALFilename {,lTemplateName}: string; lCritPct: integer; begin lPredictorList := TStringList.Create; result := false; lnSubj := 0; if not MainForm.OpenDialogExecute('Select MRIcron VAL file',false,false,'MRIcron VAL (*.val)|*.val') then begin showmessage('NPM aborted: VAL file selection failed.'); exit; end; //if not selected lVALFilename := MainForm.OpenHdrDlg.Filename; result := GetValCore ( lVALFilename, lnSubj, lnFactors, lSymptomRA, lImageNames, lCrit,lCritPct{,binom},lPredictorList); end; function TMainForm.ReportDescriptives (var RA: SingleP; n: integer): boolean; var lMn,lSD,lSE,lSkew,lZSkew: double; begin SuperDescriptive (RA, n, lMn,lSD,lSE,lSkew,lZSkew); Msg('mean='+floattostr(lMn)+',StDev='+floattostr(lSD)+',StEr='+floattostr(lSE)+',Skew='+floattostr(lSkew)+',ZSkew='+floattostr(lZSkew)); end; (*function noVariance (lRA: singlep; lnSubj: integer): boolean; var lI : integer; begin result := false; if lnSubj < 2 then exit; for lI := 2 to lnSubj do if lRA^[1] <> lRA^[lI] then exit; result := true; end; *) (*procedure TMainForm.LesionBtnClick(Sender: TObject); label 666; var lBinomial: boolean; lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCrit: integer; lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lOutName,lFactname: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA: singleP; begin lBinomial := not odd( (Sender as tMenuItem).tag); if (not lBinomial) and (not ttestmenu.checked) and (not BMmenu.checked) then begin Showmessage('Error: you need to compute at least on test [options/test menu]'); exit; end; lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? //next, get 1st group if not GetVal(lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCrit{,binom},lPredictorList) then begin showmessage('Error with VAL file'); goto 666; end; lTemp4D := CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) then begin Showmessage('Not enough subjects ('+inttostr(lnSubjAll)+') or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; if not CheckVoxelsGroup(lImageNamesAll,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; SaveHdrDlg.Filename := loutname; lOutName := lOutName+'.nii.gz'; if not SaveHdrName ('Base Statistical Map', lOutName) then goto 666; for lFact := 1 to lnFactors do begin MsgClear; Msg(GetKVers); lImageNames.clear; for lSubj := 1 to lnSubjAll do if (not lBinomial) or (lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] = 0) OR (lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] = 1) THEN begin {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); end else begin Msg('Data rejected: behavior must be zero or one for binomial test '+lImageNamesAll.Strings[lSubj-1]); end; lnSubj := lImageNames.Count; if lnSubj > 1 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do if (not lBinomial) or (lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] = 0) OR (lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] = 1) THEN {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; Msg('Threads: '+inttostr(gnCPUThreads)); lFactName := lPredictorList.Strings[lFact-1]; lFactName := LegitFilename(lFactName,lFact); Msg('Factor = '+lFactname); For lSubj := 1 to lnSubj do Msg (lImageNames.Strings[lSubj-1] + ' = '+realtostr(lSymptomRA^[lSubj],2) ); Msg('Total voxels = '+inttostr(lMaskVoxels)); Msg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); Msg('Number of Lesion maps = '+inttostr(lnSubj)); if not CheckVoxelsGroup(lImageNames,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; if noVariance (lSymptomRA,lnSubj) then Msg('Error no variability in behavioral data ') else if lBinomial then LesionNPMAnalyzeBinomial2(lImageNames,lMaskHdr,lnCrit,MainForm.ReadPermute,lSymptomRA,lFactname,lOutName) else begin ReportDescriptives(lSymptomRA,lnSubj); LesionNPMAnalyze2(lImageNames,lMaskHdr,lnCrit,-1,MainForm.ReadPermute,lSymptomRA,lFactName,lOutname,ttestmenu.checked,BMmenu.checked); end; Freemem(lSymptomRA); end; //lnsubj > 1 end; //for each factor if lnSubjAll > 0 then begin Freemem(lMultiSymptomRA); end; 666: lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); end; *) procedure TMainForm.Copy1Click(Sender: TObject); begin Memo1.SelectAll; Memo1.CopyToClipboard; end; procedure TMainForm.testmenuclick(Sender: TObject); begin (sender as TMenuItem).checked := not (sender as TMenuItem).checked; end; procedure TMainForm.radiomenuclick(Sender: TObject); begin (sender as tmenuitem).checked := true; end; procedure ComputePlankSize; begin if kPlankMB < 128 then kPlankMB := 128; if kPlankMB > 2000 then kPlankMB := 2000; //we use signed 32-bit pointers, so we can not exceed 2Gb kPlankSz :=1024 {bytes/kb} * 1024 {bytes/mb} * kPlankMB; kVers := kVers + ' CacheMB = '+inttostr(kPlankMB); end; procedure TMainForm.ReadIniFile; var lFilename: string; lThreads: integer; lIniFile: TIniFile; begin lFilename := IniName; if not FileexistsEx(lFilename) then exit; lIniFile := TIniFile.Create(lFilename); ttestmenu.checked := IniBool(lIniFile,'computettest',true); //welchmenu.checked := IniBool(lIniFile,'computewelch',true); BMmenu.checked := IniBool(lIniFile,'computebm',false); gNULP := IniBool(lIniFile,'countlesionpatterns',false); gROI := IniBool(lIniFile,'ROI',false); gTFCE := IniInt(lIniFile,'TFCE',0); kPlankMB := IniInt(lIniFile,'CacheMB',512); WritePermute(IniInt(lIniFile,'nPermute',0)); lThreads := IniInt(lIniFile,'nThread', gnCPUThreads ); if lThreads > gnCPUThreads then lThreads := gnCPUThreads; gnCPUThreads := lThreads; lIniFile.Free; end; //ReadIniFile procedure TMainForm.WriteIniFile; var lIniName: string; lIniFile: TIniFile; begin //showmessage('aaa'); lIniName := IniName; if (DiskFreeEx(lIniName) < 1) then exit; lIniFile := TIniFile.Create(lIniName); lIniFile.WriteString('BOOL', 'computettest',Bool2Char(ttestmenu.checked)); lIniFile.WriteString('BOOL', 'countlesionpatterns',Bool2Char(gNULP)); lIniFile.WriteString('BOOL', 'ROI',Bool2Char(gROI)); //lIniFile.WriteString('BOOL', 'computewelch',Bool2Char(welchmenu.checked)); lIniFile.WriteString('BOOL', 'computebm',Bool2Char(BMmenu.checked)); lIniFile.WriteString('INT', 'TFCE',inttostr(gTFCE)); lIniFile.WriteString('INT', 'CacheMB',inttostr(kPlankMB)); lIniFile.WriteString('INT', 'nPermute',inttostr(ReadPermute)); lIniFile.WriteString('INT', 'nThread',inttostr(ReadThread)); lIniFile.Free; end; procedure TMainForm.FormCreate(Sender: TObject); begin {$IFDEF Darwin} File1.visible := false;//for OSX, exit is in the application's menu //Edit1.visible := false;//clipboard note yet working for OSX {$ENDIF} {$IFDEF FPC} Application.ShowButtonGlyphs := sbgNever; {$ENDIF} {$IFDEF Darwin} {$IFNDEF LCLgtk} //only for Carbon compile Copy1.ShortCut := ShortCut(Word('C'), [ssMeta]); BinomialAnalysislesions1.ShortCut := ShortCut(Word('B'), [ssMeta]); Binaryimagescontinuousgroupsfast1.ShortCut := ShortCut(Word('L'), [ssMeta]); Design1.ShortCut := ShortCut(Word('D'), [ssMeta]); ContinuousanalysisVBM1.ShortCut := ShortCut(Word('V'), [ssMeta]); MultipleRegress.ShortCut := ShortCut(Word('R'), [ssMeta]); Makemeanimage1.ShortCut := ShortCut(Word('M'), [ssMeta]); About1.ShortCut := ShortCut(Word('A'), [ssMeta]); {$ENDIF}//Carbon {$ENDIF}//Darwin gnCPUThreads := GetLogicalCpuCount; (*if (ssShift in KeyDataToShiftState(vk_Shift)) then begin case MessageDlg('Shift key down during launch: do you want to reset the default preferences?', mtConfirmation, [mbYes, mbNo], 0) of { produce the message dialog box } mrNo: ReadIniFile; end; //case end else *) if not ResetDefaults then ReadIniFile; WriteThread(gnCPUThreads); ComputePlankSize; // ROIanalysis1.visible := gROI; {$IFDEF compileANACOM} AnaCOMmenu.visible := gROI; {$ENDIF} end; function TMainForm.MakeMean (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lBinarize,lVariance : boolean): boolean; label 667; var lOutName,lOutNameMod: string; lCountRA,lOutImgMn,lOutStDev,lPlankImg: SingleP; lTotalMemory: double; lPlank,lVolVox,lPos,lMinMask,lMaxMask,lnPlanks,lVoxPerPlank, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: integer; lStDev: boolean; lT, lSum,lSumSqr,lSD, lMn,lTotalSum,lTotalN: double; lStatHdr: TNIfTIhdr; lFdata: file; begin result := false; if not SaveHdrName ('Output image', lOutName) then exit; if (not lVariance) and (not lBinarize) then lStDev := true else lStDev := false; if lStDev then lStDev := OKMsg('Create a standard deviation image as well as a mean image?'); Msg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(single) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; Msg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); Msg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); // fx(kPlankSz,8888); getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; Msg('Number of scans = '+inttostr(lImages.count)); Msg(' Index,Filename,Intercept,Slope'); if lBinarize then begin getmem(lCountRA,lImages.Count*sizeof(single)); for lPos := 1 to lImages.Count do begin gInterceptRA[lPos] := 0; gScaleRA[lPos] := 1; lCountRA^[lPos] := 0; end; end else begin for lPos := 1 to lImages.Count do begin Msg(' '+inttostr(lPos)+','+lImages[lPos-1]+','+realtostr(gInterceptRA[lPos],4)+','+realtostr(gScaleRA[lPos],4)); if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; end; end; lTotalSum := 0; lTotalN := 0; //createArray64(lObsp,lObs,lImages.Count); getmem(lOutImgMn,lVolVox* sizeof(single)); if lStDev then getmem(lOutStDev,lVolVox* sizeof(single)); for lPlank := 1 to lnPlanks do begin Msg('Computing plank = ' +Inttostr(lPlank)); Refresh; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image lPosPct := lVoxPerPlank div 100; for lPos2 := 1 to lVoxPerPlank do begin if (lPos2 mod lPosPct) = 0 then begin ProgressBar1.Position := round((lPos2/lVoxPerPlank)*100); Application.Processmessages; end; lPos2Offset := lPos2+lStartVox-1; lSum := 0; if lVariance then begin lSum := sqr(lPlankImg^[lPos2]-lPlankImg^[lVoxPerPlank+lPos2]);//actually variance... //% signal //if lPlankImg[lVoxPerPlank+lPos2] <> 0 then // lSum := lPlankImg[lPos2]/lPlankImg[lVoxPerPlank+lPos2] //else // lSum := 0;//pct signal... //end % signal lOutImgMn^[lPos2Offset] := lSum; lTotalSum := lTotalSum + lOutImgMn^[lPos2Offset]; lTotalN := lTotalN + 1; end else begin //not variance if lBinarize then begin for lPos := 1 to lImages.Count do if lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2] <> 0 then begin lSum := lSum+1; lCountRA^[lPos] := lCountRA^[lPos] + 1; end; end else for lPos := 1 to lImages.Count do lSum := lSum +(gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; // fx(lPos, gScaleRA[lPos],gInterceptRA[lPos]); lOutImgMn^[lPos2Offset] := lSum/lImages.Count; if lStDev then begin //lSum := 0; //for lPos := 1 to lImages.Count do // lSum := lSum + (gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; lSumSqr := 0; for lPos := 1 to lImages.Count do lSumSqr := lSumSqr + Sqr((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]); lSD := (lSumSqr - ((Sqr(lSum))/lImages.Count)); if (lSD > 0) then lSD := Sqrt ( lSD/(lImages.Count-1)) else begin lSD := 0; (*if l1stError then begin for lPos := 1 to lImages.Count do Msg(floattostr( (gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos])); msg('---'); msg(floattostr(lSum)); msg(floattostr(lSumSqr)); l1stError := false; end;*) end; lOutStDev^[lPos2Offset] := lSD; end; end; //not variance if lSum > 0 then begin lTotalSum := lTotalSum + lOutImgMn^[lPos2Offset]; lTotalN := lTotalN + 1; end; end; lStartVox := lEndVox + 1; end; if lBinarize then begin for lPos := 1 to lImages.Count do begin Msg(' '+inttostr(lPos)+','+lImages[lPos-1]+','+inttostr(round(lCountRA^[lPos])) ); lCountRA^[lPos] := 0; end; freemem(lCountRA); end; //if binar //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save mean if lVariance then lOutNameMod := ChangeFilePostfixExt(lOutName,'var','.hdr') else lOutNameMod := ChangeFilePostfixExt(lOutName,'Mean','.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgMn,1); freemem(lOutImgMn); if lStDev then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'StDev','.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutStDev,1); freemem(lOutStDev); end; //freemem(lObsp); freemem(lPlankImg); Msg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes','.txt'); MsgSave(lOutNameMod); if (lTotalN > 0) then Msg('num voxels >0 = ' +inttostr(round(lTotalN))+' mean value for voxels >0: '+floattostr(lTotalSum/lTotalN)); ProgressBar1.Position := 0; exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); Msg('Unable to complete analysis.'); ProgressBar1.Position := 0; end; function ApplyTFCE (lImageName: string): boolean; var lImg: SingleP; lHdr: TMRIcroHdr; lVolVox: integer; maxTFCE, maxNegTFCE: single; lOutNameMod: string; begin result := false; if not NIFTIhdr_LoadHdr(lImageName,lHdr) then begin showmessage('Error reading '+lImageName); exit; end; lVolVox := lHdr.NIFTIhdr.dim[1]*lHdr.NIFTIhdr.dim[2]* lHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then exit; getmem(lImg,lVolVox*sizeof(single)); if not LoadImg(lHdr.ImgFileName, lImg, 1, lVolVox,round(lHdr.NIFTIhdr.vox_offset),1,lHdr.NIFTIhdr.datatype,lVolVox) then begin Msg('Unable to load ' +lHdr.ImgFileName); exit; end; //lHdr.NIFTIhdr.scl_slope := 1; lHdr.NIFTIhdr.scl_inter := 0; doTFCEbothPolarities (lHdr.NIFTIhdr, lImg, 6 {NumConn}, 2.0 {H}, 0.5 { E}, 0, 0,0,0 ,maxTFCE, maxNegTFCE); lOutNameMod := ChangeFilePrefixExt(lImageName,'i','.hdr'); Msg('Creating ' +lOutNameMod); NIFTIhdr_SaveHdrImg(lOutNameMod,lHdr.NIFTIhdr,true,not IsNifTiMagic(lHdr.NIFTIhdr),true,lImg,1); freemem(lImg); end; procedure TMainForm.FCE1Click(Sender: TObject); var lFilename: string; lPos: Integer; lHdr: TMRIcroHdr; begin MsgClear; Msg(GetKVers); if not OpenDialogExecute('Select images for TFCE',true,false,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected if OpenHdrDlg.Files.Count < 1 then exit; for lPos := 1 to OpenHdrDlg.Files.Count do begin lFilename := OpenHdrDlg.Files[lPos-1]; //TFCE(lFilename,1,false); //ClusterTFCE (lHdr, 666, 2); ApplyTFCE(lFilename); //Binarize (var lImageName:String; lNonZeroVal: integer; lZeroThresh: boolean): boolean; end; Msg('Done'); end; procedure TMainForm.Makemeanimage1Click(Sender: TObject); label 666; var lMaskVoxels: integer; lG: TStrings; lMaskname: string; lMaskHdr: TMRIcroHdr; begin MsgClear; Msg(GetKVers); if not OpenDialogExecute('Select images to average',true,true,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected lG:= TStringList.Create; lG.addstrings(OpenHdrDlg.Files); lMaskname := lG[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading '+lMaskName); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if not CheckVoxelsGroupX(lG,lMaskHdr {lMaskVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; Msg('Voxels = '+inttostr(lMaskVoxels)); MakeMean(lG,lMaskHdr, odd((Sender as TMenuItem).tag),false); 666: lG.Free; end; procedure TMainForm.Exit1Click(Sender: TObject); begin Close; end; function MinMax (var lImg: SingleP; var lVolVox: integer; var lMin, lMax: single): boolean; var lC: integer; begin result := false; if lVolVox < 1 then exit; lMax := lImg^[1]; for lC := 1 to lVolVox do if lImg^[lC] > lMax then lMax := lImg^[lC]; //lCx := lC; lMin := lImg^[1]; for lC := 1 to lVolVox do if lImg^[lC] < lMin then lMin := lImg^[lC]; result := true; end; function DetectMode (var lImg: SingleP; var lVolVox: integer; var lMin, lMax, lModeLo,lModeHi: single; lInflection: boolean): boolean; const kHistoBins = 255;//numbers of bins for histogram/image balance var lSmooth,lPrevSmooth,lModeWid,lC,lMinPos,lMode,lModePos,lMaxModePos,lMode2NotInflection: integer; lMod,lRng: single; lHisto : array [0..kHistoBins] of longint; begin result := false; if (lVolVox < 1) or (lMax < lMin) then exit; //zero array for lC := 1 to kHistoBins do lHisto[lC] := 0; //find scaling lRng := abs(lMax-lMin); if lRng > 0 then lMod := (kHistoBins)/lRng else lMod := 0; //fill histogram for lC := 1 to lVolVox do if lImg^[lC] <> 0 then inc(lHisto[round((lImg^[lC]-lMin)*lMod)]); {for lC := 1 to lVolVox do inc(lHisto[round((lImg^[lC]-lMin)*lMod)]); } //smooth histogram lPrevSmooth := lHisto[1]; for lC := 2 to (kHistoBins-1) do begin lSmooth := round( (lHisto[lC-1]+lHisto[lC]+lHisto[lC]+lHisto[lC+1])/4); lHisto[lC-1] := lPrevSmooth; lPrevSmooth := lSmooth; end; lHisto[kHistoBins-1] := lPrevSmooth; //find mode lMode := 0; lMinPos := 1;//indexed from zero //find highest peak for lC := lMinPos to kHistoBins do begin if lHisto[lC] > lMode then begin lModePos := lC; lMode := lHisto[lC]; end;//if new mode end; //for each bin if lMode > 0 then lMaxModePos := lModePos else exit; //find 2nd highest peak //find 2nd highest peak lModeWid := 25; lModePos := lMinPos; lMode := lHisto[lMinPos]; if (lMaxModePos - lModeWid) > lMinPos then begin for lC := lMinPos to (lMaxModePos - lModeWid) do begin if lHisto[lC] > lMode then begin lModePos := lC; lMode := lHisto[lC]; end;//if new mode end; //for each bin end; //check below highest peak if (lMaxModePos + lModeWid) < kHistoBins then begin for lC := (lMaxModePos + lModeWid) to kHistoBins do begin if lHisto[lC] > lMode then begin lModePos := lC; lMode := lHisto[lC]; end;//if new mode end; //for each bin end; //check above highest peak //fx(lModePos); //an alternative method to find mode is to look for inflection - less assumptions, more sensitive to noise if lInflection then begin lMode2NotInflection := lModePos; lModePos := lMinPos; lMode := 0; lC := lMaxModePos; while ((lC-1) > lMinPos) and (lHisto[lC] > lHisto[lC-1]) do dec(lC); //find inflection while ((lC-1) > lMinPos) do begin dec(lC); if lHisto[lC] > lMode then begin lModePos := lC; lMode := lHisto[lC]; end;//if new mode end; //look for mode lC := lMaxModePos; while ((lC+1) <= kHistoBins) and (lHisto[lC] > lHisto[lC+1]) do inc(lC); //find inflection while ((lC+1) <= kHistoBins) do begin inc(lC); if lHisto[lC] > lMode then begin lModePos := lC; lMode := lHisto[lC]; end;//if new mode end; //look for mode if abs(lMode2NotInflection-lModePos) > 3 then Showmessage('Warning: inflection and windowed algorithms find different 2nd modes. Using inflection 2nd mode. inflection ='+inttostr(lModePos)+' windowed: '+inttostr(lMode2NotInflection)); end; //now, return scaled values... if lMod = 0 then exit; lModeLo := (lModePos/lMod)+lMin; lModeHi := (lMaxModePos/lMod)+lMin; if lModeLo > lModeHi then begin lMod := lModeLo; lModeLo := lModeHi; lModeHi := lMod; end; result := true; end; procedure CopyFileEXoverwrite (lInName,lOutName: string); var lFSize: Integer; lBuff: bytep0; lFData: file; begin lFSize := FSize(lInName); if (lFSize < 1) then exit; assignfile(lFdata,lInName); filemode := 0; reset(lFdata,lFSize{1}); GetMem( lBuff, lFSize); BlockRead(lFdata, lBuff^, 1{lFSize}); closefile(lFdata); assignfile(lFdata,lOutName); filemode := 2; Rewrite(lFdata,lFSize); BlockWrite(lFdata,lBuff^, 1 {, NumWritten}); closefile(lFdata); freemem(lBuff); end; procedure CopyFileEX (lInName,lOutName: string); var lFSize: Integer; begin lFSize := FSize(lInName); if (lFSize < 1) or (fileexistsEX(lOutName)) then exit; CopyFileEXoverwrite (lInName,lOutName); end; function DetectMeanStDev (var lImg: SingleP; var lVolVox: integer; var lMean,lStDev: double): boolean; var lIncVox,lVox: integer; lSum,lSumSqr,lSE: double; begin lMean := 0; lStDev := 0; result := false; if (lVolVox < 1) then exit; lSum := 0; lSumSqr := 0; lIncVox := 0; //voxels included - e.g. not masked for lVox := 1 to lVolVox do begin if lImg^[lVox] <> 0 then begin //not in mask inc(lIncVox); lSum := lSum + lImg^[lVox]; lSumSqr := lSumSqr + sqr(lImg^[lVox]); end; end; if lincVox < 3 then exit; Descriptive (lincVox, lSumSqr, lSum,lMean,lStDev,lSE); result := true; end; //DetectMeanStDev //zero array function TMainForm.Balance (var lImageName,lMaskName: String; {lInflection: boolean}lMethod: integer): boolean; //0 = masked peak //1 = inflection //2 = mean =1, stdev=1 var lImg,lMaskImg: SingleP; lHdr,lMaskHdr: TMRIcroHdr; lVolVox,lVox,lMasked: integer; lMaskedInten,lMean,lStDev: double; lMin,lMax: single; lModeLo,lModeHi,lIntercept,lSlope: single; lOutNameMod: string; begin //lOutName := lMaskHdr.ImgFileName; result := false; //if not SaveHdrName ('Statistical Map', lOutName) then exit; if not NIFTIhdr_LoadHdr(lImageName,lHdr) then begin showmessage('Error reading '+lImageName); exit; end; lVolVox := lHdr.NIFTIhdr.dim[1]*lHdr.NIFTIhdr.dim[2]* lHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then exit; getmem(lImg,lVolVox*sizeof(single)); if not LoadImg(lHdr.ImgFileName, lImg, 1, lVolVox,round(lHdr.NIFTIhdr.vox_offset),1,lHdr.NIFTIhdr.datatype,lVolVox) then begin Msg('Unable to load ' +lHdr.ImgFileName); exit; end; if lMaskName <> '' then begin if not NIFTIhdr_LoadHdr(lMaskName,lMaskHdr) then begin showmessage('Error reading '+lMaskName); exit; end; if lVolVox <> (lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]) then begin showmessage('Mask and header must have identical dimensions '+lMaskName+ ' ' + lImageName); exit; end; getmem(lMaskImg,lVolVox*sizeof(single)); if not LoadImg(lMaskHdr.ImgFileName, lMaskImg, 1, lVolVox,round(lMaskHdr.NIFTIhdr.vox_offset),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin Msg('Unable to load mask ' +lMaskHdr.ImgFileName); exit; end; lMasked := 0; lMaskedInten := 0; for lVox := 1 to lVolVox do if lMaskImg^[lVox] = 0 then begin lMaskedInten := lMaskedInten + lImg^[lVox]; lImg^[lVox] := 0; inc(lMasked); end; if lMasked < 1 then Msg('Warning: no voxels masked with image '+lMaskName) else Msg('Mask='+ lMaskName+' Number of voxels masked= '+inttostr(lMasked)+' Mean unscaled intensity of masked voxels= '+floattostr(lMaskedInten/lMasked)); freemem(lMaskImg); end;//mask if not MinMax(lImg,lVolVox,lMin,lMax) then exit; Msg(lImageName+' -> '+lHdr.ImgFileName); Msg('min..max ' +floattostr(lMin)+'..'+floattostr(lMax)); if (lMethod = 0) or (lMethod = 1) then begin if not DetectMode(lImg,lVolVox,lMin,lMax,lModeLo,lModeHi, odd(lMethod)) then exit; if odd(lMethod) then Msg('method for finding second mode: inflection') else Msg('method for finding second mode: masked peak'); Msg('modes Lo Hi ' +floattostr(lModeLo)+'..'+floattostr(lModeHi)); if lModeLo >= lModeHi then exit; lSlope := 1/abs(lModeHi-lModeLo); lIntercept := (abs(lModeHi-lModeLo)-(lModeLo))*lSlope ; //make mode lo = 1; end else begin DetectMeanStDev (lImg, lVolVox, lMean,lStDev); if lStDev <>0 then lSlope := 1/lStDev else begin Msg('Warning: StDev = 0!!!!'); lSlope := 1; end; lIntercept := (-lMean*lSlope)+2; //mean voxel has intensity of zero Msg('method for intensity normalization: Mean = 2, StDev = 1'); Msg('raw_Mean = '+floattostr(lMean)+' '+' raw_StDev = '+floattostr(lStDev)); end; Msg('Slope/Intercept ' +floattostr(lSlope)+'..'+floattostr(lIntercept)); lHdr.NIFTIhdr.scl_slope := lSlope; lHdr.NIFTIhdr.scl_inter := lIntercept; //CopyFileEX(lHdr.HdrFilename,changefileext( lHdr.HdrFilename,'.hdx')); RenameFile(lHdr.HdrFilename,changefileext( lHdr.HdrFilename,'.hdx')); //optional - save input lOutNameMod := ChangeFilePrefixExt(lImageName,'i','.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lHdr.NIFTIhdr,true,not IsNifTiMagic(lHdr.NIFTIhdr),true,lImg,1); //end optional NIFTIhdr_SaveHdr(lHdr.HdrFilename,lHdr.NIFTIhdr,true,not IsNifTiMagic(lHdr.NIFTIhdr)); freemem(lImg); end; procedure TMainForm.Balance1Click(Sender: TObject); var lFilename,lMaskName: string; lPos: Integer; begin MsgClear; Msg(GetKVers); if not OpenDialogExecute('Select images for intensity normalization',true,false,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected if OpenHdrDlg.Files.Count < 1 then exit; lMaskName := ''; for lPos := 1 to OpenHdrDlg.Files.Count do begin lFilename := OpenHdrDlg.Files[lPos-1]; balance(lFilename,lMaskname,(Sender as TMenuItem).tag); end; end; procedure TMainForm.niiniigz1Click(Sender: TObject); var lFilename,lOutname,lPath,lName,lExt: string; lPos: Integer; begin MsgClear; Msg(GetKVers); if not OpenDialogExecute('Select images',true,false,kNIIFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected if OpenHdrDlg.Files.Count < 1 then exit; for lPos := 1 to OpenHdrDlg.Files.Count do begin lFilename := OpenHdrDlg.Files[lPos-1]; FilenameParts(lFilename,lPath,lName,lExt); lOutname := lPath+lName+'.nii.gz'; msg('Compressing '+ lFilename+' -> '+lOutname); GZipFile(lFilename, lOutname,false); end; msg('Compression completed'); end; procedure TMainForm.Variance1Click(Sender: TObject); label 666; var lMaskVoxels: integer; lG: TStrings; lMaskname: string; lMaskHdr: TMRIcroHdr; begin MsgClear; Msg(GetKVers); if not OpenDialogExecute('Select 2 images)',true,true,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected lG:= TStringList.Create; lG.addstrings(OpenHdrDlg.Files); if lG.count <> 2 then begin showmessage('You must select exactly two image.'); goto 666; end; lMaskname := lG[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if not CheckVoxelsGroupX(lG,lMaskHdr{lMaskVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; Msg('Voxels = '+inttostr(lMaskVoxels)); MakeMean(lG,lMaskHdr, odd((Sender as TMenuItem).tag),true); 666: lG.Free; end; procedure BMX; const kN = 53; knNoLesion = 48; kSymptomRA: array[1..kn] of single = (4,4.5,2.5,5,4,3.25,0.75,4.5,4.5,0.5,1.625,0,3.5,3,4,2,4.5,5,1.5,5,2.5,5,4,0,2, 1.5,1.75,2.5,5,0,3.25,4.375,0,3.75,0.25,0,2,5,0,0.5,0,2.25,0,2.25,2,0,0.25,0,0,0,0,0,0); var lObs: doublep0; lI: integer; lBMz,lBMzs,lDF: double; begin getmem(lObs,kN * sizeof(double)); for lI := 1 to kN do lObs^[lI-1] := kSymptomRA[lI]; tBM (kN, knNoLesion, lObs,lBMz,lDF); //simulate MainForm.NPMmsg('Generating BM permutation thresholds'); MainForm.Refresh; genBMsim (kN, lObs); lBMzs := BMzVal (kN, knNoLesion,lBMz,lDF); //end simulate MainForm.NPMmsg('BMsim= '+floattostr(lBMzs)+' '+'BM= '+floattostr(lBMz)+' '+floattostr(lDF) ); freemem(lObs); end; (*procedure SX; var lVALFilename {,lTemplateName}: string; lCritPct,lnSubj, lnFactors: integer; var lSymptomRA: singleP; var lImageNames: TStrings; var lCrit: integer; {lBinomial : boolean;} var lPredictorList: TStringList; begin lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? lVALFilename := 'c:\RT_norm.val';//MainForm.OpenHdrDlg.Filename; lPredictorList := TStringList.Create; GetValCore ( lVALFilename, lnSubj, lnFactors, lSymptomRA, lImageNames, lCrit,lCritPct{,binom},lPredictorList); lImageNames.Free; lPredictorList.Free; end;*) (*procedure ComputeR; var lStr: string; lT,lDF: double; begin inputquery('Enter value','Enter T score',lStr); lT := strtofloat(lStr); inputquery('Enter value','Enter DF',lStr); lDF := strtofloat(lStr); showmessage('The coresponding correlation Z score for t('+floattostr(lDF)+')='+floattostr(lT) +' is '+floattostr(TtoZ(lT,lDF) ) ); //showmessage('The coresponding correlation R score for t('+floattostr(lDF)+')='+floattostr(lT) +' is '+floattostr(TtoR(lT,lDF) ) ); end; function Log10x (lLogP: double): double; begin result := -Log10(lLogP); fx(result); end; procedure LogPtoZ (lLogP: double); var lD,lZ: double; begin ///lD := Log10(lLogp); lD := Power(10,-lLogP); lZ := pNormalInv(lD); fx(lD,lZ); end; *) procedure TMainForm.About1Click(Sender: TObject); begin //Masked1Click(nil); exit; //LogPtoZ (Log10x(0.02)); //LogPtoZ(1.699); //ComputeR; showmessage(GetkVers ); end; procedure TMainForm.Design1Click(Sender: TObject); begin {$IFDEF SPREADSHEET} SpreadForm.Show; {$ELSE} Showmessage('Spreadsheet not yet supported on the Operating System');{$ENDIF} end; procedure TMainForm.StrToMemo(lStr: String); var lLen,lPos: integer; lOutStr: string; begin lLen := length(lStr); if lLen < 1 then exit; lOutStr := ''; for lPos := 1 to lLen do begin if lStr[lPos] = kCR then begin Msg(lOutStr); lOutStr := ''; end else lOutStr := lOutStr + lStr[lPos]; end; if lOutStr <> '' then Msg(lOutStr); end; procedure TMainForm.PhysiologicalArtifactCorrection1Click(Sender: TObject); var lInImgName,lPulsFile,lRespFile,lOutImgName,lStr: string; l4Ddata: singlep; lHdr: TMRIcroHdr; lDim,lImgVox: integer; lOutHdr: TniftiHdr; begin if not OpenDialogExecute('Select file with pulse onsets',false,false,'Siemens physio |*.puls|3-column text |*.txt') then exit; lPulsFile := OpenHdrDlg.Filename; if UpCaseExt(lPulsFile) = '.PULS' then lRespFile := changefileext(lPulsFile,'.resp') else begin //text input if not OpenDialogExecute('Select file with respiration onsets',false,false,'3-column text |*.txt') then lRespFile := '' else lRespFile := OpenHdrDlg.Filename; end; if not OpenDialogExecute('Select 4D motion corrected data ',false,false,kImgFilter) then exit; lInImgName := OpenHdrDlg.Filename; if not NIFTIhdr_LoadHdr(lInImgName,lHdr) then begin showmessage('Error reading image header.'); exit; end; for lDim := 1 to 4 do if lHdr.NIFTIhdr.Dim[lDim] < 4 then begin Showmessage('You need to select a 4D image with at least 4 voxels/images in each dimension.'); exit; end; lImgVox := lHdr.NIFTIhdr.Dim[1]*lHdr.NIFTIhdr.Dim[2]*lHdr.NIFTIhdr.Dim[3]; lDim := lImgVox*lHdr.NIFTIhdr.Dim[4]; MsgClear; Msg(kVers); Msg('Physiological Artifact Removal Tool started = ' +TimeToStr(Now)); Msg('Assuming continuous fMRI ascending acquisition with TR = '+realtostr(lHdr.NIFTIhdr.PixDim[4],4)+'sec'); MainForm.refresh; getmem(l4Ddata,lDim*sizeof(single)); if not LoadImg(lHdr.ImgFileName, l4Ddata, 1, lDim,round(lHdr.NIFTIhdr.vox_offset),1,lHdr.NIFTIhdr.datatype,lImgVox) then begin Showmessage('Unable to load data'); freemem(l4Ddata); exit; end; lStr := ApplyPART( lPulsFile,l4Ddata,40, lImgVox,lHdr.NIFTIhdr.Dim[3], lHdr.NIFTIhdr.Dim[4], lHdr.NIFTIhdr.PixDim[4]); if lStr = '' then begin Showmessage('Unable to apply physio file. Physiological correction is being aborted.'); exit; end; StrToMemo (lStr); if (lRespFile <> '') and (fileexists(lRespFile)) then begin lStr := ApplyPART( lRespFile,l4Ddata,20, lImgVox,lHdr.NIFTIhdr.Dim[3], lHdr.NIFTIhdr.Dim[4], lHdr.NIFTIhdr.PixDim[4]); StrToMemo (lStr); if lStr = '' then begin Showmessage('Unable to read Respiration file. Hysiological correction is being aborted.'); exit; end; end; MakeHdr (lHdr.NIFTIhdr,lOutHdr); Msg('Input = ' +lInImgName); lOutImgName := ChangeFilePrefixExt(lInImgName,'i','.hdr'); NIFTIhdr_SaveHdrImg(lOutImgName,lOutHdr,true,not IsNifTiMagic(lHdr.NIFTIhdr),true,l4Ddata,lHdr.NIFTIhdr.Dim[4]); Msg('Output = ' +lOutImgName); Msg('Physiological Artifact Removal Tool finished = ' +TimeToStr(Now)); lOutImgName := ChangeFilePostfixExt(lOutImgName,'Notes','.txt'); MsgSave(lOutImgName); freemem(l4Ddata); end; function ChangeName (lInName: string): string; var lPath,lName,lExt: string; begin //lInName:= 'c:\vbm\ds\123'; FilenameParts (lInName, lPath,lName,lExt); //showmessage(lPath+'*'+lName+'*'+lExt); if length(lName) > 0 then lName[1] := 'e' else lName := 'Unable to convert '+lInName; result := lPath+lName+lExt; end; function Add2ndScans(var lImageNames: TStrings): boolean; var lnSubj,lSubj: integer; lFilename: string; begin result := false; lnSubj :=lImageNames.Count; if lnSubj < 1 then exit; for lSubj := 1 to lnSubj do begin lFilename := ChangeName(lImageNames[lSubj-1]); if not (fileexists4D(lFilename)) then begin showmessage('Unable to find a file named '+ lFilename); exit; end; lImageNames.add(lFilename); end; result := true; end; function ReadPairedFilenames(var lImageNames: TStrings): boolean; var lLen,lPos: integer; lFilenames,lF1,lF2: string; lImageNames2: TStrings; lF: TextFile; begin result := false; Showmessage('Please select a text file with the image names. '+kCR+ 'Each line of the file should specify the control and experimental filenames, separated by an *'+kCR+ 'C:\vbmdata\c1.nii.gz*C:\vbmdata\e1.nii.gz'+kCR + 'C:\vbmdata\c2.nii.gz*C:\vbmdata\e2.nii.gz'+kCR+ 'C:\vbmdata\c3.nii.gz*C:\vbmdata\e3.nii.gz'+kCR+ '...' ); if not MainForm.OpenDialogExecute('Select asterix separated filenames ',false,false,kTxtFilter) then exit; lImageNames2:= TStringList.Create; //not sure why TStrings.Create does not work??? //xxx assignfile(lF,MainForm.OpenHdrDlg.FileName ); FileMode := 0; //read only reset(lF); while not EOF(lF) do begin readln(lF,lFilenames); lLen := length(lFilenames); if lLen > 0 then begin lF1:= ''; lF2 := ''; lPos := 1; while (lPos <= lLen) and (lFilenames[lPos] <> '*') do begin lF1 := lF1 + lFilenames[lPos]; inc(lPos); end; inc(lPos); while (lPos <= lLen) do begin lF2 := lF2 + lFilenames[lPos]; inc(lPos); end; if (length(lF1) > 0) and (length(lF2)>0) then begin if Fileexists4D(lF1) then begin if Fileexists4D(lF2) then begin lImageNames.add(lF1); lImageNames2.add(lF2); end else //F2exists showmessage('Can not find image '+lF2); end else //F1 exists showmessage('Can not find image '+lF1); end; end;//len>0 end; //while not EOF closefile(lF); FileMode := 2; //read/write if (lImageNames.count > 0) and (lImageNames2.count = lImageNames.count) then begin lImageNames.AddStrings(lImageNames2); result := true; end; lImageNames2.Free; end; function AddNumStr(var X : PMatrix; var lNumStr: string; lRow,lCol: integer):boolean; var lTempFloat: double; begin result := false; if (lNumStr = '') or (lRow < 1) or (lCol < 1) then exit; try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin showmessage('Empty cells? Error reading TXT file row:'+inttostr(lRow)+' col:'+inttostr(lCol)+' - Unable to convert the string '+lNumStr+' to a number'); exit; end; end; //fx(lRow,lCol,lTempFloat); X^[lCol]^[lRow] := lTempFloat; lNumStr := ''; result := true; end; {$DEFINE notRTEST} function ReadPairedFilenamesReg(var lImageNames: TStrings; var X : PMatrix; var lnAdditionalFactors: integer): boolean; var lLen,lPos,lSep,lMaxSep,lLine: integer; lFilenames,lF1,lF2,lNumStr: string; lImageNames2: TStrings; lF: TextFile; begin result := false; {$IFDEF RTEST} MainForm.OpenHdrDlg.FileName := 'c:\twins\dataplus.txt'; {$ELSE} Showmessage('Please select a text file with the image names. '+kCR+ 'Each line of the file should specify the control and experimental filenames, separated by an *'+kCR+ 'C:\vbmdata\c1.nii.gz*C:\vbmdata\e1.nii.gz'+kCR + 'C:\vbmdata\c2.nii.gz*C:\vbmdata\e2.nii.gz'+kCR+ 'C:\vbmdata\c3.nii.gz*C:\vbmdata\e3.nii.gz'+kCR+ '...' ); if not MainForm.OpenDialogExecute('Select asterix separated filenames ',false,false,kTxtFilter) then exit; {$ENDIF} lImageNames2:= TStringList.Create; //not sure why TStrings.Create does not work??? //xxx assignfile(lF,MainForm.OpenHdrDlg.FileName ); FileMode := 0; //read only reset(lF); while not EOF(lF) do begin readln(lF,lFilenames); lLen := length(lFilenames); if lLen > 0 then begin lF1:= ''; lF2 := ''; lPos := 1; while (lPos <= lLen) and (lFilenames[lPos] <> '*') do begin lF1 := lF1 + lFilenames[lPos]; inc(lPos); end; inc(lPos); while (lPos <= lLen) and (lFilenames[lPos] <> '*') do begin lF2 := lF2 + lFilenames[lPos]; inc(lPos); end; if (length(lF1) > 0) and (length(lF2)>0) then begin if Fileexists4D(lF1) then begin if Fileexists4D(lF2) then begin lImageNames.add(lF1); lImageNames2.add(lF2); end else //F2exists showmessage('Can not find image '+lF2); end else //F1 exists showmessage('Can not find image '+lF1); end; end;//len>0 end; //while not EOF //fx(lImageNames.count); //next - count additional factors lnAdditionalFactors := 0; reset(lF); lMaxSep := 0; while not EOF(lF) do begin readln(lF,lFilenames); lLen := length(lFilenames); lSep := 0; if lLen > 0 then begin for lPos := 1 to lLen do if lFilenames[lPos] = '*' then inc(lSep) end;//len>0 if lSep > lMaxSep then lMaxSep := lSep; end; //while not EOF if (lMaxSep > 1) and (lImageNames2.count > 1) then begin //additional factors present //final pas - load additional factors lnAdditionalFactors := lMaxSep - 1; DimMatrix(X, lnAdditionalFactors, lImageNames2.count); reset(lF); lLine := 0; while not EOF(lF) do begin readln(lF,lFilenames); lLen := length(lFilenames); lSep := 0; if lLen > 0 then begin inc(lLine); lPos := 1; lNumStr := ''; while lPos <= lLen do begin if (lFilenames[lPos] = '*') then begin AddNumStr(X,lNumStr,lLine,lSep-1); inc(lSep); end else if (lSep >= 2) and (not (lFilenames[lPos] in [#10,#13,#9]) ) then begin lNumStr := lNumStr+lFilenames[lPos]; //showmessage(lNumStr); end; inc(lPos); end; //while not EOLN AddNumStr(X,lNumStr,lLine,lSep-1); end;//len>0 end; //while not EOF //next - read final line of unterminated string... end;//maxsepa > 1 //2nd pass vals closefile(lF); FileMode := 2; //read/write if (lImageNames.count > 0) and (lImageNames2.count = lImageNames.count) then begin lImageNames.AddStrings(lImageNames2); result := true; end; lImageNames2.Free; result := true; end; procedure TMainForm.DualImageCorrelation1Click(Sender: TObject); label 666; var lnSubj,lSubj,lMaskVoxels,lnAdditionalFactors,lI: integer; lImageNames: TStrings; X: PMatrix; lMaskname,lStr,lOutName: string; lMaskHdr: TMRIcroHdr; begin lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? MsgClear; Msg(kVers); {$IFDEF RTEST} OpenHdrDlg.FileName := 'c:\twins\aameanMean.hdr'; {$ELSE} Msg('Dual-image Linear Regression [Weighted Least Squares]'); if not OpenDialogExecute('Select brain mask ',false,false,kImgFilter) then begin showmessage('NPM aborted: mask selection failed.'); goto 666; end; //if not selected {$ENDIF} lMaskname := OpenHdrDlg.Filename; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading Mask image.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; if not ReadPairedFilenamesReg(lImageNames,X,lnAdditionalFactors) then exit; lnSubj :=lImageNames.Count div 2; //fx(lnAdditionalFactors); //show matrix //MsgStrings (lImageNames); Msg ('n Subjects = '+inttostr(lnSubj)); for lSubj := 0 to (lnSubj-1) do begin lStr := lImageNames[lSubj]+' <-> '+lImageNames[lSubj+lnSubj]; if lnAdditionalFactors > 0 then for lI := 1 to lnAdditionalFactors do lStr := lStr+','+floattostr(X^[lI]^[lSubj+1]); Msg(lStr); end; if not CheckVoxelsGroupX(lImageNames,lMaskHdr{lMaskVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; Msg('Mask = '+lMaskname); Msg('Total voxels = '+inttostr(lMaskVoxels)); Msg('Number of observations = '+inttostr(lnSubj)); (*if not CheckVoxelsGroupX(lImageNames,lMaskHdr{lMaskVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end;*) if lnSubj < 5 then begin showmessage('Paired regression error: Requires at least 5 images per group.'); goto 666; end; lOutName := lMaskName; if not SaveHdrName ('Base Statistical Map', lOutName) then exit; //showmessage('Unimplemented Regress');// Regress2NPMAnalyze (lImageNames, lMaskHdr, lOutname,X,lnAdditionalFactors); if lnAdditionalFactors > 1 then DelMatrix(X, lnAdditionalFactors, lnSubj); 666: lImageNames.Free; end; procedure TMainForm.LesionBtnClick(Sender: TObject); label 666; var lPrefs: TLDMPrefs ; begin lPrefs.NULP := gNULP; if (1= (Sender as tMenuItem).tag) then begin //continuous lPrefs.BMtest := BMmenu.checked; lPrefs.Ttest := ttestmenu.checked; if (not lPrefs.BMtest) and (not lPrefs.ttest) then lPrefs.ttest := true; lPrefs.Ltest:= false; end else begin //binomial lPrefs.BMtest := false; lPrefs.Ttest := false; lPrefs.Ltest:= true; end; lPrefs.CritPct := -1; lPrefs.nPermute := ReadPermute; lPrefs.Run := 0;{0 except for montecarlo} {if (not lPrefs.Ltest) and (not lPrefs.Ttest) and (not lPrefs.BMtest) then begin Showmessage('Error: you need to compute at least on test [options/test menu]'); exit; end; code above defaults to t-test} if not MainForm.OpenDialogExecute('Select MRIcron VAL file',false,false,'MRIcron VAL (*.val)|*.val') then begin showmessage('NPM aborted: VAL file selection failed.'); exit; end; //if not selected lPrefs.VALFilename := MainForm.OpenHdrDlg.Filename; lPrefs.OutName := ExtractFileDirWithPathDelim(lPrefs.VALFilename)+'results'; lPrefs.OutName := lPrefs.OutName+'.nii.gz'; SaveHdrDlg.Filename := lPrefs.Outname; if not SaveHdrName ('Base Statistical Map', lPrefs.OutName) then exit; //Explicit mask if not OpenDialogExecute('Select explicit mask [optional]',false,false,kImgPlusVOIFilter) then lPrefs.ExplicitMaskName := '' else lPrefs.ExplicitMaskName := OpenHdrDlg.FileName; DoLesion (lPrefs); //Prefs.pas end; procedure TMainForm.FormShow(Sender: TObject); begin MsgClear; Msg(GetkVers); {$IFNDEF UNIX} {GUILaunch;}{$ENDIF} LongTimeFormat := 'YYYY-MMM-DD hh:nn:ss'; //delphi TimeToStr ShortTimeFormat := 'YYYY-MMM-DD hh:nn:ss'; //freepascal TimeToStr //stax; //MakeGZ; //{x$IFNDEF UNIX} Threads1.visible := false;{x$ENDIF}//Windows can read actual CPU count //TestMultReg; //SingleRegressClick(nil); //DualImageCorrelation1Click(nil); //AnaCOM1Click(nil); //msg(floattostr(pNormalInv(1/20000))); //msg(floattostr(pNormalInv(0.01667))); //msg(floattostr(pNormalInv(0.05/51700))); //msg(floattostr(0.05/pNormal(4.76 ))); {$IFNDEF UNIX} ReadParamStr; {$ENDIF} //FX(rocA(0.2,0.4),AUC(0.7,0.4),rocA(0.4,0.7),AUC(0.4,0.7) ); //LesionX; {$IFDEF benchmark} MonteCarloSimulation1.visible := true; // LesionMonteCarlo (false,true,true); {$ENDIF} end; procedure TMainForm.PairedTMenuClick(Sender: TObject); label 666; var lnSubj,lSubj,lMaskVoxels: integer; lImageNames: TStrings; lMaskname,lStr,lOutName: string; lMaskHdr: TMRIcroHdr; begin lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? MsgClear; Msg(kVers); Msg('Paired T-test [Repeated Measures]'); if not OpenDialogExecute('Select brain mask ',false,false,kImgFilter) then begin showmessage('NPM aborted: mask selection failed.'); goto 666; end; //if not selected //OpenHdrDlg.FileName := 'c:\vbmdata\mask50.nii.gz'; lMaskname := OpenHdrDlg.Filename; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading Mask image.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; if not ReadPairedFilenames(lImageNames) then exit; lnSubj :=lImageNames.Count div 2; if not CheckVoxelsGroupX(lImageNames,lMaskHdr{lMaskVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; Msg('Mask = '+lMaskname); Msg('Total voxels = '+inttostr(lMaskVoxels)); Msg('Number of observations = '+inttostr(lnSubj)); Msg('Degrees of Freedom = '+inttostr(lnSubj-1)); if not CheckVoxelsGroupX(lImageNames,lMaskHdr{lMaskVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; //show matrix //MsgStrings (lImageNames); Msg ('n Subjects = '+inttostr(lnSubj)); lStr := 'Image,'; for lSubj := 0 to (lnSubj-1) do Msg(lImageNames[lSubj]+' <-> '+lImageNames[lSubj+lnSubj]); if lnSubj < 4 then begin showmessage('Paired t-test error: Requires at least 4 images per group.'); goto 666; end; lOutName := lMaskName; //if not SaveHdrName ('Base Statistical Map', lOutName) then exit; NPMAnalyzePaired (lImageNames, lMaskHdr, lMaskVoxels); //Regress2NPMAnalyze (lImageNames, lMaskHdr, lOutname); 666: lImageNames.Free; end; function TMainForm.NPMzscore (var lImages: TStrings; var lMnHdr,lStDevHdr: TMRIcroHdr): boolean; label 667; var lOutNameMod: string; lMnImg,lStDevImg,lSubjImg,lOutImg: SingleP; lVal: single; lSubj,lPos,lVolVox: integer; lStatHdr: TNIfTIhdr; begin result := false; //lOutName := lMnHdr.ImgFileName; //if not SaveHdrName ('Statistical Map', lOutName) then exit; Msg('Analysis began = ' +TimeToStr(Now)); lVolVox := lMnHdr.NIFTIhdr.dim[1]*lMnHdr.NIFTIhdr.dim[2]* lMnHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; //load mask for lPos := 0 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; if gScaleRA[kMaxImages] = 0 then gScaleRA[kMaxImages] := 1; getmem(lMnImg,lVolVox*sizeof(single)); if not LoadImg(lMnHdr.ImgFileName, lMnImg, 1, lVolVox,round(gOffsetRA[0]),1,lMnHdr.NIFTIhdr.datatype,lVolVox) then begin Msg('Unable to load mean ' +lMnHdr.ImgFileName); goto 667; end; //load StDev getmem(lStDevImg,lVolVox*sizeof(single)); if not LoadImg(lStDevHdr.ImgFileName, lStDevImg, 1, lVolVox,round(gOffsetRA[kMaxImages]),1,lStDevHdr.NIFTIhdr.datatype,lVolVox) then begin Msg('Unable to load StDev ' +lStDevHdr.ImgFileName); goto 667; end; getmem(lOutImg,lVolVox* sizeof(single)); for lPos := 1 to lVolVox do begin lMnImg^[lPos] := (gScaleRA[0]*lMnImg^[lPos])+gInterceptRA[0]; lStDevImg^[lPos] := (gScaleRA[kMaxImages]*lStDevImg^[lPos])+gInterceptRA[kMaxImages]; if lStDevImg^[lPos] = 0 then lOutImg^[lPos] := 0; end; getmem(lSubjImg,lVolVox* sizeof(single)); for lSubj := 1 to lImages.Count do begin ProgressBar1.Position := round((lSubj/lImages.Count)*100); Msg( lImages.Strings[lSubj-1]); showmessage(inttostr(round(gOffsetRA[lSubj]))); LoadImg(lImages.Strings[lSubj-1], lSubjImg, 1, lVolVox,round(gOffsetRA[lSubj]),1,gDataTypeRA[lSubj],lVolVox); for lPos := 1 to lVolVox do begin if lStDevImg^[lPos] <> 0 then begin lVal := (gScaleRA[lSubj]*lSubjImg^[lPos])+gInterceptRA[lSubj]; lOutImg^[lPos] := (lVal-lMnImg^[lPos])/lStDevImg^[lPos]; end; //for each voxel with variance end; //for each voxel lOutNameMod := ChangeFilePostfixExt(lImages.Strings[lSubj-1],'Z','.hdr'); MakeStatHdr (lMnHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lVolVox,kNIFTI_INTENT_ZSCORE,inttostr(lVolVox) ); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMnHdr.NIFTIhdr),true,lOutImg,1); end; //for each subj freemem(lSubjImg); freemem(lOutImg); freemem(lMnImg); freemem(lStDevImg); Msg('Analysis finished = ' +TimeToStr(Now)); ProgressBar1.Position := 0; result := true; exit; 667: //you only get here if you aborted ... free memory and report error if lVolVox > 1 then freemem(lMnImg); Msg('Unable to complete analysis.'); ProgressBar1.Position := 0; end; procedure TMainForm.SingleSubjectZScores1Click(Sender: TObject); label 666; var lnSubj,lMnVoxels: integer; lG: TStrings; lMn,lStDev: string; lMnHdr,lStDevHdr: TMRIcroHdr; begin if (not ttestmenu.checked) and (not BMmenu.checked) then begin Showmessage('Error: you need to compute at least on test [options/test menu]'); exit; end; MsgClear; Msg(kVers); Msg('Threads: '+inttostr(gnCPUThreads)); if not OpenDialogExecute('Select mean image ',false,false,kImgFilter) then begin showmessage('NPM aborted: mean selection failed.'); exit; end; //if not selected lMn := OpenHdrDlg.Filename; if not NIFTIhdr_LoadHdr(lMn,lMnHdr) then begin showmessage('Error reading mask.'); exit; end; lMnVoxels := ComputeImageDataBytes8bpp(lMnHdr); if (lMnVoxels < 2) or (not CheckVoxels(lMn,lMnVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mean file size too small.'); exit; end; if not OpenDialogExecute('Select StDev image ',false,false,kImgFilter) then begin showmessage('NPM aborted: StDev selection failed.'); exit; end; //if not selected lStDev := OpenHdrDlg.Filename; if not NIFTIhdr_LoadHdr(lStDev,lStDevHdr) then begin showmessage('Error reading StDev.'); exit; end; if not CheckVoxels(lStDev, lMnVoxels,kMaxImages) then begin showmessage('Error Mean and StDev must have same size.'); exit; end; Msg('Mean name = '+ lMn); Msg('Total voxels = '+inttostr(lMnVoxels)); //next, get 1st group if not OpenDialogExecute('Select postive group (Z scores positive if this group is brighter)',true,false,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected lG:= TStringList.Create; //not sure why TStrings.Create does not work??? lG.addstrings(OpenHdrDlg.Files); lnSubj :=OpenHdrDlg.Files.Count; Msg('Subjects= '+inttostr(lnSubj)); if not CheckVoxelsGroupX(lG,lMnHdr {lMnVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; NPMzscore (lG, lMnHdr,lStDevHdr); //NPMAnalyze(lG,lMnHdr,lMnVoxels,lnSubj); 666: lG.Free; end; procedure TMainForm.MultipleRegressClick(Sender: TObject); label 666; var lnFactors,lnSubj,lMaskVoxels,lRow,lCol: integer; lImageNames: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lStr,lOutName: string; lMaskHdr: TMRIcroHdr; X : PMatrix; begin {$IFDEF FPC} showmessage('Regression routines not extensively tested: you may want to use the Windows compilation.'); {$ENDIF} lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? lPredictorList := TStringList.Create; Memo1.Lines.Clear; Memo1.Lines.Add(kVers); Memo1.Lines.Add('Multiple Linear Regression [Weighted Least Squares]'); if not GetValReg(lnSubj,lnFactors,X,lImageNames,lPredictorList) then goto 666; lTemp4D := CreateDecompressed4D(lImageNames); if not OpenDialogExecute('Select brain mask ',false,false,kImgFilter) then begin showmessage('NPM aborted: mask selection failed.'); goto 666; end; //if not selected lMaskname := OpenHdrDlg.Filename; //lMaskname := lImageNames[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st image.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; Memo1.Lines.Add('Mask = '+lMaskname); Memo1.Lines.Add('Total voxels = '+inttostr(lMaskVoxels)); Memo1.Lines.Add('Number of observations = '+inttostr(lnSubj)); if not CheckVoxelsGroupX(lImageNames,lMaskHdr {lMaskVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; //show matrix lStr := 'Image,'; for lCol := 1 to lnFactors do lStr := lStr + lPredictorList.Strings[lCol-1]+', '; MainForm.Memo1.Lines.Add(lStr); for lRow := 1 to lnSubj do begin lStr := lImageNames[lRow-1]+','; for lCol := 1 to lnFactors do lStr := lStr + floattostr(X^[lCol]^[lRow])+', '; MainForm.Memo1.Lines.Add(lStr); end; lOutName := lMaskName; if not SaveHdrName ('Base Statistical Map', lOutName) then exit; ARegressNPMAnalyze(lImageNames,lMaskHdr,X,lnFactors,lPredictorList,lOutName,0,0); DelMatrix(X, lnFactors, lnSubj); 666: lImageNames.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); end; {$DEFINE notRegTest} procedure TMainForm.SingleRegressClick(Sender: TObject); label 666; var lnSubj1,lnFactors,lnSubj,lMaskVoxels,lRow,lCol: integer; lImageNames,lImageNames1: TStrings; lPredictorList,lPredictorList1: TStringList; lTemp4D,lMaskname,lOutName: string; lMaskHdr: TMRIcroHdr; X,X1 : PMatrix; begin {$IFDEF FPC} showmessage('Regression routines not extensively tested: you may want to use the Windows compilation.'); {$ENDIF} lTemp4D := ''; lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? lPredictorList := TStringList.Create; lPredictorList1 := TStringList.Create; if not GetValReg(lnSubj,lnFactors,X,lImageNames,lPredictorList) then goto 666; {$IFDEF regtest} lMaskname := 'C:\Documents and Settings\Chris Rorden\Desktop\npmdata\npmdata\amask50.nii.gz'; {$ELSE} if not OpenDialogExecute('Select brain mask ',false,false,kImgFilter) then begin showmessage('NPM aborted: mask selection failed.'); goto 666; end; //if not selected lMaskname := OpenHdrDlg.Filename; {$ENDIF} if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st image.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; if not CheckVoxelsGroupX(lImageNames,lMaskHdr{lMaskVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; lOutName := lMaskName; {$IFNDEF regtest} if not SaveHdrName ('Base Statistical Map', lOutName) then goto 666; {$ENDIF} lTemp4D := CreateDecompressed4D(lImageNames); lImageNames1:= TStringList.Create; for lCol := 1 to lnFactors do begin lPredictorList1.Clear; lPredictorList1.Add(lPredictorList[lCol-1]); lImageNames1.clear; for lRow := 1 to lnSubj do if X^[lCol]^[lRow] <> kNaN then lImageNames1.Add(lImageNames[lRow-1]); DimMatrix(X1, 1, lImageNames1.Count); lnSubj1 := 0; for lRow := 1 to lnSubj do if X^[lCol]^[lRow] <> kNaN then begin inc(lnSubj1); X1^[1]^[lnSubj1] := X^[lCol]^[lRow]; end; if lnSubj1 <> lImageNames1.Count then //should be impossible showmessage('serious error'); Memo1.Lines.Clear; Memo1.Lines.Add(kVers); Memo1.Lines.Add('Single Linear Regression [Weighted Least Squares]'); Memo1.Lines.Add('Mask = '+lMaskname); Memo1.Lines.Add('Total voxels = '+inttostr(lMaskVoxels)); Memo1.Lines.Add('Number of observations = '+inttostr(lnSubj1)); MainForm.Memo1.Lines.Add('Image,'+ lPredictorList1.Strings[0]); for lRow := 1 to lnSubj1 do MainForm.Memo1.Lines.Add(lImageNames1[lRow-1]+','+floattostr(X1^[1]^[lRow]) ) ; ARegressNPMAnalyze(lImageNames1,lMaskHdr,X1,1,lPredictorList1,lOutName, ReadPermute,gTFCE); //PermuteRegressNPMAnalyze (lImageNames1,lMaskHdr,X1,1,lPredictorList1,lOutName); DelMatrix(X1, 1, lnSubj1); end; lImageNames1.Free; DelMatrix(X, lnFactors, lnSubj); 666: DeleteDecompressed4D(lTemp4D); lImageNames.Free; lPredictorList.Free; lPredictorList1.Free; end; procedure TMainForm.AssociatevalfileswithNPM1Click(Sender: TObject); begin {$IFDEF FPC} //unsupported by FreePascal {$ELSE} case MessageDlg('NPM installation:'+kCR+'Do you want .val fiels to automatically open NPM when you double click on their icons?', mtConfirmation, [mbYes, mbNo], 0) of { produce the message dialog box } id_No: exit; end; registerfiletype(kVALNativeExt,'NPM'{key},'NPM',Application.ExeName+',1'); {$ENDIF} end; procedure TMainForm.threadChange(Sender: TObject); begin (sender as tmenuitem).checked := true; ReadThread; end; procedure TMainForm.Countlesionoverlaps1Click(Sender: TObject); label 666; var lReps,lMax,lInc,lMaskVoxels,lDefault,lTotal,lPct: integer; lG: TStrings; lMaskname: string; lMaskHdr: TMRIcroHdr; begin MsgClear; Msg(kVers); if not OpenDialogExecute('Select images to overlap',true,false,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected if MainForm.OpenHdrDlg.Files.Count < 2 then begin lTotal := NIFTIhdr_HdrVolumes(MainForm.OpenHdrDlg.Filename); if lTotal < 2 then begin Showmessage('Error: This function is designed to overlay MULTIPLE volumes. You selected less than two images.'); exit; end; lG:= TStringList.Create; for lReps := 1 to lTotal do lG.Add(MainForm.OpenHdrDlg.Filename+':'+inttostr(lReps) ); end else begin lG:= TStringList.Create; lG.addstrings(OpenHdrDlg.Files); end; lMaskname := lG[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if not CheckVoxelsGroupX(lG,lMaskHdr{lMaskVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; lTotal := lG.Count; if lTotal > kMaxObs then lTotal := kMaxObs; //this implemmentation uses 126 bits per voxel - we can not test more than this! if lTotal > 100 then lDefault := 100 else lDefault := lTotal; lMax := ReadIntForm.GetInt('Enter maximum number of overlaps to test ', 3,lDefault,lTotal); lDefault := lMax div 10; if lDefault < 1 then lDefault := 1; lInc := ReadIntForm.GetInt('Enter overlap increment (e.g. if 5; then 5, 10, 15...) ', 1,lDefault,lMax); lReps := ReadIntForm.GetInt('Enter number of times each increment is tested ', 1,10,100); lPct := ReadIntForm.GetInt('Only include voxels damaged in N% of patients ', 0,5,100); Msg('Voxels = '+inttostr(lMaskVoxels)); Msg('Scans to permute = '+inttostr(lG.count)); EvaluatePower (lG,lInc,lMax,lReps,lPct); //MakeMean(lG,lMaskHdr, odd((Sender as TMenuItem).tag),false); 666: lG.Free; end; {$DEFINE SINGLETHREAD} {$DEFINE NOTHREAD} function TMainForm.FirthNPMAnalyze (var lImages: TStrings; var lPredictorList: TStringList; var lMaskHdr: TMRIcroHdr; lnCond,lnCrit: integer; var lSymptomRA: SingleP; var lOutName: string): boolean; label 123,667; var lOutNameMod: string; lPlankImg: bytep; lOutImgSum : singleP; lOutImg: SingleRAp; {$IFDEF SINGLETHREAD}lnCPUThreads,{$ENDIF} lCond,lPos,lPlank,lThread,lnDeficit: integer; lTotalMemory,lVolVox,lMinMask,lMaxMask,lnPlanks,lVoxPerPlank, lThreadStart,lThreadInc,lThreadEnd, lnLesion,lnPermute, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT, lSum: double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; begin if lnCond < 1 then exit; lnPermute := ReadPermute; if lnPermute > 1 then begin Msg('NPM does not (yet) support permutation thresholding with Logisitic Regression.'); lnPermute := 0; end; {$IFDEF SINGLETHREAD} lnCPUThreads := gnCPUThreads; if gnCPUThreads > 1 then Msg('July 2007 logistic regression will only use 1 thread. You may want to check for a software update'); gnCPUThreads := 1; {$ENDIF} Msg('Permutations = ' +IntToStr(lnPermute)); Msg('Logisitic Regression began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; Msg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); Msg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; createArray64(lObsp,lObs,lImages.Count); getmem(lOutImgSum,lVolVox* sizeof(single)); //getmem(lOutImgL,lVolVox* sizeof(single)); getmem(lOutImg,lnCond*sizeof(Singlep)); for lCond := 1 to lnCond do begin getmem(lOutImg^[lCond],lVolVox* sizeof(single)); for lPos := 1 to lVolVox do lOutImg^[lCond]^[lPos] := 0; end; //InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do lOutImgSum^[lPos] := 0; ClearThreadData(gnCPUThreads,lnPermute) ; for lPlank := 1 to lnPlanks do begin ProgressBar1.Position := 1; Msg('Computing plank = ' +Inttostr(lPlank)); Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; {$IFDEF NOTHREAD} FirthAnalyzeNoThread (lnCond, lnCrit,lnPermute,1,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lPlankImg,lOutImgSum,lSymptomRA,lOutImg); //FirthAnalyzeNoThread (lnCond,lnCrit, lnPermute,1,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lPlankImg,lOutImgSum,lSymptomRA,lOutImg); {$ELSE} for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TFirthThreadStat.Create (ProgressBar1,lnCond,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lPlankImg,lOutImgSum,lSymptomRA,lOutImg) do {$IFDEF FPC} OnTerminate := @ThreadDone; {$ELSE}OnTerminate := ThreadDone;{$ENDIF} inc(gThreadsRunning); Msg('Thread ' +Inttostr(gThreadsRunning)+' = '+inttostr(lThreadStart)+'..'+inttostr(lThreadEnd)); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; {$ENDIF} //THREADED Application.processmessages; //showmessage('Threads done'); //threading end lStartVox := lEndVox + 1; end; lnVoxTested := SumThreadDataLite(gnCPUThreads); //not yet lnVoxTested := SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); if lnVoxTested < 1 then begin Msg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lnCrit)+' patients**'); goto 123; end; //next report findings Msg('Voxels tested = ' +Inttostr(lnVoxTested)); Msg('Only tested voxels with more than '+inttostr(lnCrit)+' lesions'); //Next: save results from permutation thresholding.... reportBonferroni('Std',lnVoxTested); //next: save data (*savedata *) MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum','.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); for lCond := 1 to lnCond do begin reportFDR (lPredictorList[lCond-1]+inttostr(lCond), lVolVox, lnVoxTested, lOutImg^[lCond]); //reportPermute('L',lnPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,lPredictorList[lCond-1]+inttostr(lCond),'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImg^[lCond],1); end; 123: //next: free dynamic memory //FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); for lCond := 1 to lnCond do freemem(lOutImg^[lCond]); freemem(lOutImg); freemem(lOutImgSum); freemem(lObsp); freemem(lPlankImg); Msg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes','.txt'); MsgSave(lOutNameMod); ProgressBar1.Position := 0; {$IFDEF SINGLETHREAD} gnCPUThreads := lnCPUThreads; {$ENDIF} exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); Msg('Unable to complete analysis.'); ProgressBar1.Position := 0; {$IFDEF SINGLETHREAD} gnCPUThreads := lnCPUThreads; {$ENDIF} end; function ComputeLesionVolume (lImgName: string): integer; var lHdr: TMRIcroHdr; lImg: byteP; lVolVox,lVox:integer; begin result := -1; //error NIFTIhdr_LoadHdr(lImgName,lHdr); lVolVox := lHdr.NIFTIhdr.dim[1]*lHdr.NIFTIhdr.dim[2]* lHdr.NIFTIhdr.dim[3]; getmem(lImg,lVolVox*sizeof(byte)); if not LoadImg8(lImgName, lImg, 1, lVolVox,round(lHdr.NIFTIhdr.vox_offset),1,lHdr.NIFTIhdr.datatype,lVolVox) then begin Msg('Unable to load ' +lHdr.ImgFileName); freemem(lImg); exit; end; result := 0; for lVox := 1 to lVolVox do if (lImg^[lVox] <> 0) then inc(result); freemem(lImg); end; procedure TMainForm.PenalizedLogisticRegerssion1Click(Sender: TObject); label 666; var lVol,lMin,lMax,lI,lFact,lnFactors,lSubj,lnSubj,lMaskVoxels,lnCrit: integer; lImageNames: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lOutName,lStr: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lTempRA: singleP; //lBinomial: boolean; begin // lBinomial := false; lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? //next, get 1st group if not GetValX(lnSubj,lnFactors,lMultiSymptomRA,lImageNames,lnCrit{,binom},lPredictorList) then goto 666; lTemp4D := CreateDecompressed4D(lImageNames); if (lnSubj < 2) or (lnFactors < 1) then begin showmessage('This analysis requires at least 2 participants and one factor'); goto 666; end; lMaskname := lImageNames[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st image: '+lMaskname); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if not CheckVoxelsGroupX(lImageNames,lMaskHdr{lMaskVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; case MessageDlg('Do you want to add lesion volume as a regressor?', mtConfirmation, [mbYes, mbNo], 0) of { produce the message dialog box } mrYes: begin //add a new condition called lesionvolume - create a new larger array for data Msg('Computing lesion volumes...'); lPredictorList.Add('LesionVolume'); GetMem(lTempRA,lnSubj*lnFactors*sizeof(single)); for lI := 1 to (lnSubj*lnFactors) do lTempRA^[lI] := lMultiSymptomRA^[lI]; Freemem(lMultiSymptomRA); GetMem(lMultiSymptomRA,lnSubj*(lnFactors+1)*sizeof(single)); for lI := 1 to (lnSubj*lnFactors) do lMultiSymptomRA^[lI] := lTempRA^[lI]; Freemem(lTempRA); //now create the new factor lI := lnSubj*lnFactors; for lSubj := 1 to lnSubj do lMultiSymptomRA^[lI+lSubj] := ComputeLesionVolume(lImageNames[lSubj-1]); //ensure there is variability in this regressor lMin := round(lMultiSymptomRA^[lI+1]); lMax := round(lMultiSymptomRA^[lI+1]); for lSubj := 1 to lnSubj do begin lVol := round(lMultiSymptomRA^[lI+lSubj]); if lVol < lMin then lMin := lVol; if lVol > lMax then lMax := lVol; end; if (lMin < 0) then begin showmessage('Regression aborted: Error computing lesion volumes.'); goto 666; end; if (lMin = lMax) then begin showmessage('Regression aborted: no variability in lesion volume.'); goto 666; end; inc(lnFactors); end; //if user decides to include lesion volume end; //case lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; SaveHdrDlg.Filename := loutname; MsgClear; Msg(kVers); Msg('Firth Penalized regression is still beta software...'); Msg('Number of participants: '+inttostr(lnSubj)); Msg('Number of factors: '+inttostr(lnFactors)); Msg('Threads: '+inttostr(gnCPUThreads)); //next - header shows factor names lStr :='imagename'; for lFact := 1 to lnFactors do lStr := lStr+','+lPredictorList[lFact-1]; Msg(lStr); For lSubj := 1 to lnSubj do begin lStr :=''; for lFact := 1 to lnFactors do begin lStr := lStr+','+realtostr(lMultiSymptomRA^[lSubj+ ((lFact-1)*lnSubj)],2); end; Msg (lImageNames.Strings[lSubj-1] + ' = '+lStr ); end; Msg('Total voxels = '+inttostr(lMaskVoxels)); Msg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); Msg('Number of Lesion maps = '+inttostr(lnSubj)); lOutName := lOutName+'.nii.gz'; if not SaveHdrName ('Base Statistical Map', lOutName) then goto 666; if not CheckVoxelsGroupX(lImageNames,lMaskHdr{lMaskVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; FirthNPMAnalyze (lImageNames,lPredictorList,lMaskHdr,lnFactors,lnCrit, lMultiSymptomRA, lOutName); 666: lImageNames.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); end; function ComputeIntersection ( lAname,lBname: string; var lUnion,lIntersection,lAnotB,lBnotA: integer): boolean; label 667; var lOutName,lOutNameMod: string; lVolVox,lVolVoxA,lVox: integer; lImgA,lImgB: SingleP; lMaskHdr: TMRIcroHdr; lA,lB: boolean; begin lUnion:= 0; lIntersection := 0; lAnotB := 0; lBnotA := 0; result := false; //read A if not NIFTIhdr_LoadHdr(lAname,lMaskHdr) then begin showmessage('Error reading image A - '+lAname); exit; end; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; getmem(lImgA,lVolVox*sizeof(single)); if not LoadImg(lAname, lImgA, 1, lVolVox,round(lMaskHdr.NIFTIhdr.vox_offset),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin msg('Unable to load mask ' +lMaskHdr.ImgFileName); goto 667; end; lVolVoxA := lVolVox; //read B if not NIFTIhdr_LoadHdr(lBname,lMaskHdr) then begin showmessage('Error reading image B - '+lBname); exit; end; //fx(666,round(gOffsetRA[0])); lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVoxA <> lVolVox) or (lVolVox < 1) then goto 667; getmem(lImgB,lVolVox*sizeof(single)); if not LoadImg(lBname, lImgB, 1, lVolVox,round(lMaskHdr.NIFTIhdr.vox_offset),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin msg('Unable to load mask ' +lMaskHdr.ImgFileName); goto 667; end; for lVox := 1 to lVolVox do begin lA := (lImgA^[lVox] <> 0); lB := (lImgB^[lVox] <> 0); if lA and lB then begin //fx(lVox,lImgA^[lVox],lImgB^[lVox]); inc(lIntersection); end; if lA or lB then inc(lUnion); if lA and not lB then inc(lAnotB); if lB and not lA then inc(lBnotA); end; freemem(lImgA); freemem(lImgB); result := true; 667: end; procedure TMainForm.ZtoP1Click(Sender: TObject); var lAname,lBname: string; var lUnion,lIntersection,lAnotB,lBnotA: integer; begin //removed lAName := 'C:\mri\roc\p2.nii.gz'; lBName := 'C:\mri\roc\RBD35.voi'; if not ComputeIntersection ( lAName,lBName,lUnion,lIntersection,lAnotB,lBnotA) then Msg('Error'); Msg( lAName+' '+lBName+' I'+inttostr(lIntersection)+' U'+inttostr(lUnion)+' AnotB'+inttostr(lAnotB)+' BnotA'+inttostr(lBnotA)); end; procedure TMainForm.ComputeIntersectionandUnion1Click(Sender: TObject); label 666; var lUnion,lIntersection,lAnotB,lBnotA, lnSubj,lSubj,lMaskVoxels,lnAdditionalFactors: integer; lImageNames: TStrings; lMaskname, lStr,lOutName: string; lMaskHdr: TMRIcroHdr; X: PMatrix; begin lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? MsgClear; Msg(kVers); Msg('Compute intersection [A and B] and union [A or B] for a series of images'); if not ReadPairedFilenamesReg(lImageNames,X,lnAdditionalFactors) then exit; lnSubj :=lImageNames.Count div 2; if lnAdditionalFactors > 1 then DelMatrix(X, lnAdditionalFactors, lnSubj); lMaskname :=lImageNames[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading first image.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Image file size too small.'); goto 666; end; if not CheckVoxelsGroupX(lImageNames,lMaskHdr{lMaskVoxels}) then begin showmessage('File dimensions differ from first image.'); goto 666; end; Msg ('n Subjects = '+inttostr(lnSubj)); for lSubj := 0 to (lnSubj-1) do begin lStr := 'A=,'+lImageNames[lSubj]+',B=,'+lImageNames[lSubj+lnSubj]; ComputeIntersection ( lImageNames[lSubj],lImageNames[lSubj+lnSubj],lUnion,lIntersection,lAnotB,lBnotA); lStr := lStr + ',A and B=,'+inttostr(lIntersection); lStr := lStr + ',A or B=,'+inttostr(lUnion); lStr := lStr + ',A not B=,'+inttostr(lAnotB); lStr := lStr + ',B not A=,'+inttostr(lBnotA); Msg(lStr); end; //Msg('Mask = '+lMaskname); //Msg('Total voxels = '+inttostr(lMaskVoxels)); Msg('Number of observations = '+inttostr(lnSubj)); 666: lImageNames.Free; end; //compute intersection and union procedure TMainForm.ROCbinomialdeficit1Click(Sender: TObject); begin testROC; end; procedure TMainForm.ROCcontinuousdeficit1Click(Sender: TObject); begin testROC2; end; function isBinom ( lRA: singleP; lnObs: integer): boolean; var lI: integer; begin result := false; if lnObs < 1 then exit; for lI := 1 to lnObs do if (lRA^[lI] <> 0) and (lRA^[lI] <> 1) then exit; result := true; end; procedure Means ( lBinomRA,lContRA: singleP; lnObs: integer); var lI,ln0: integer; lMeans0, lMeans1: double; begin lMeans0 := 0; lMeans1 := 0; ln0 := 0; if lnObs < 1 then exit; for lI := 1 to lnObs do begin if (lBinomRA^[lI] = 0) then begin inc(ln0); lMeans0 := lMeans0 + lContRA^[lI]; end else lMeans1 := lMeans1 + lContRA^[lI]; end; if ln0 > 0 then lMeans0 := lMeans0 / ln0; if ln0 < lnObs then lMeans1 := lMeans1 / (lnObs-ln0); npmform.MainForm.memo1.lines.add('mean volume for '+inttostr(ln0)+' people who scored 0 is = '+floattostr(lmeans0)); npmform.MainForm.memo1.lines.add('mean volume for '+inttostr(lnObs-ln0)+' people who scored 1 is = '+floattostr(lmeans1)); end; function AUCbinomcontT (lBinomdataRA,lContdataRA: singlep; lnSubj :integer; var lT: double): double; var lIn : DoubleP0; lnGroup0,lnGroup1,lI: integer; begin result := 0.5; if lnSubj < 1 then exit; Getmem(lIn,lnSubj*sizeof(double)); lnGroup0 := 0; lnGroup1 := 0; for lI := 1 to lnSubj do begin if lBinomdataRA^[lI] = 0 then begin lIn^[lnGroup0] := lContdataRA^[lI]; inc (lnGroup0); end else begin inc (lnGroup1); lIn^[lnSubj-lnGroup1] := lContdataRA^[lI]; end; end; result := continROC (lnSubj, lnGroup0, lIn); TStat2 (lnSubj, lnGroup0, lIn,lT); freemem(lIn); end; procedure Contrast(lBehavName,lROIname: string; lBehavRA,lLesionVolRA: singleP; lnSubj: integer); var lDF: integer; lROC,lT,lP: double; begin if isBinom (lBehavRA,lnSubj) then begin lROC := AUCbinomcontT (lBehavRA,lLesionVolRA, lnSubj,lT); lDF := lnSubj-2; lP := pTdistr(lDF,lT); Means ( lBehavRA,lLesionVolRA, lnSubj); npmform.MainForm.memo1.lines.add('ROI=,'+lROIname+',Behav=,'+lBehavName+', Area Under Curve=,'+floattostr(lROC)+', T('+inttostr(lDF)+')=,'+floattostr(lT)+',p<,'+floattostr(lp)); end else begin lROC := AUCcontcont (lBehavRA,lLesionVolRA, lnSubj); npmform.MainForm.memo1.lines.add('ROI=,'+lROIname+',Behav=,'+lBehavName+', Area Under Curve = '+floattostr(lROC)); end; //xxx end; function ComputeOverlap ( lROIname: string; var lLesionNames: TStrings; var lROIvol: double; lFracROIinjured: singlep): boolean; label 667; var lName: string; lSum: double; lLesion,lnLesions,lVolVox,lVolVoxA,lVox: integer; lROIImg,lImgB: SingleP; lMaskHdr: TMRIcroHdr; begin lROIvol := 0; result := false; lnLesions := lLesionNames.count; if lnLesions < 1 then begin showmessage('Error: no lesion names'); exit; end; for lLesion := 1 to lnLesions do lFracROIinjured^[lLesion] := 0; //read A if not NIFTIhdr_LoadHdr(lROIname,lMaskHdr) then begin showmessage('Error reading ROI - '+lROIname); exit; end; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then begin showmessage('Error with Mask voxels ' + inttostr(lVolVox)); exit; end; if not CheckVoxelsGroupX(lLesionNames, lMaskHdr) then begin showmessage('Error image dimensions vary.'); exit; end; getmem(lROIImg,lVolVox*sizeof(single)); getmem(lImgB,lVolVox*sizeof(single)); if not LoadImg(lROIname, lROIImg, 1, lVolVox,round(lMaskHdr.NIFTIhdr.vox_offset),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin MainForm.NPMmsg('Unable to load lesion ' +lMaskHdr.ImgFileName); goto 667; end; lVolVoxA := lVolVox; for lVox := 1 to lVolVox do if (lROIImg^[lVox] > 0) then lROIvol := lROIvol +lROIImg^[lVox]; //read Lesion if lROIvol < 1 then begin MainForm.NPMmsg('ROI volume < 1'); goto 667; end; //for each lesion //MainForm.NPMmsg('Compute overlap started '+inttostr(lnLesions)+' '+floattostr(lROIvol)+' '+inttostr(lVolVoxA)); MainForm.ProgressBar1.Position := 0; for lLesion := 1 to lnLesions do begin MainForm.ProgressBar1.Position := round((lLesion/lnLesions)*100) ; lSum := 0; lName := lLesionNames.Strings[lLesion-1]; if not NIFTIhdr_LoadHdr(lName,lMaskHdr) then begin showmessage('Error reading lesion - '+lName); exit; end; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVoxA <> lVolVox) or (lVolVox < 1) then begin MainForm.NPMmsg('Volume does not have expected number of voxels ' +lMaskHdr.ImgFileName +'<>'+lROIname+ ' found ' +inttostr(lVolVox)+' expected '+inttostr(lVolVoxA)); goto 667; end; if not LoadImg(lName, lImgB, 1, lVolVox,round(lMaskHdr.NIFTIhdr.vox_offset),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin MainForm.NPMmsg('Unable to load mask ' +lMaskHdr.ImgFileName); goto 667; end; for lVox := 1 to lVolVox do begin //if {(lImgB^[lVox] <> 0) and} (lROIImg^[lVox] <> 0) then fx(lROIImg^[lVox]); if (lROIImg^[lVox] > 0) and (lImgB^[lVox] <> 0) then lSum := lSum + lROIImg^[lVox]; end; lFracROIinjured^[lLesion] := lSum/lROIvol; end;//for each lesion result := true; MainForm.ProgressBar1.Position := 0; (*for lLesion := 1 to lnLesions do begin if lFracROIinjured^[lLesion] > 0 then fx( lFracROIinjured^[lLesion], lLesion); end; *) 667: freemem(lImgB); freemem(lROIImg); end; procedure TMainForm.ROIanalysis1Click(Sender: TObject); label 666; var lROI,lnROI,lVol,lMin,lMax,lI,lFact,lnFactors,lSubj,lnSubj,lMaskVoxels,lnCrit: integer; lROInames,lImageNames: TStrings; lPredictorList: TStringList; lVolStr,lTemp4D,lOutName,lStr: string; lBehav: single; lROIvolRA: doubleP; lMultiSymptomRA,lLesionVolRA,lBehavRA: singleP; lError: boolean; begin if not OpenDialogExecute('Select regions of interest',true,false,kImgPlusVOIFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected lROInames:= TStringList.Create; lROInames.addstrings(OpenHdrDlg.Files); lnROI := lROINames.Count; if lnROI < 1 then begin showmessage('You need to select at least one ROI.'); exit; end; lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? if not GetValX(lnSubj,lnFactors,lMultiSymptomRA,lImageNames,lnCrit,lPredictorList) then goto 666; lTemp4D := CreateDecompressed4D(lImageNames); if (lnSubj < 1) or (lnFactors < 1) then begin showmessage('This analysis requires at least 1 participant and one factor'); goto 666; end; MsgClear; Msg(kVers); MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); Msg('VAL file name: '+MainForm.OpenHdrDlg.Filename); Msg('Number of participants: '+inttostr(lnSubj)); Msg('Number of factors: '+inttostr(lnFactors)); Msg('Number of Lesion maps = '+inttostr(lnSubj)); //next - header shows factor names lStr :='imagename'; for lFact := 1 to lnFactors do lStr := lStr+','+lPredictorList[lFact-1]; for lROI := 1 to lnROI do lStr := lStr+','+lROInames[lROI-1]; Msg(lStr+',LesionVolume'); lError := false; Getmem(lROIVolRA, lnSubj*lnROI*sizeof(double)); Getmem(lLesionVolRA, lnSubj*lnROI*sizeof(single)); Getmem(lBehavRA, lnSubj*lnFactors*sizeof(single)); for lROI := 1 to lnROI do begin //if not ComputeIntersection ( lImageNames.Strings[lSubj-1],lROInames[lROI-1],lUnion,lIntersection,lAnotB,lBnotA) then if not ComputeOverlap (lROInames[lROI-1],lImageNames, lROIvolRA^[lROI], singlep(@lLesionVolRA^[((lROI-1)*lnSubj)+1])) then begin MainForm.NPMmsg('Error computing overlap'); goto 666; end; end; For lSubj := 1 to lnSubj do begin lStr :=''; for lFact := 1 to lnFactors do begin lBehav := lMultiSymptomRA^[lSubj+ ((lFact-1)*lnSubj)]; lStr := lStr+','+realtostr(lBehav,2); lBehavRA^[((lFact-1)*lnSubj) +lSubj] := lBehav; end; for lROI := 1 to lnROI do lStr := lStr+','+floattostr(lLesionVolRA^[((lROI-1)*lnSubj) +lSubj]); lVolStr := floattostr(ComputeLesionVolume(lImageNames.Strings[lSubj-1])); Msg (lImageNames.Strings[lSubj-1] + ' = '+lStr +','+lVolStr ); end; (* For lSubj := 1 to lnSubj do begin lStr :=''; for lFact := 1 to lnFactors do begin lBehav := lMultiSymptomRA^[lSubj+ ((lFact-1)*lnSubj)]; lStr := lStr+','+realtostr(lBehav,2); lBehavRA^[((lFact-1)*lnSubj) +lSubj] := lBehav; end; for lROI := 1 to lnROI do begin if ComputeIntersection ( lImageNames.Strings[lSubj-1],lROInames[lROI-1],lUnion,lIntersection,lAnotB,lBnotA) then begin lStr := lStr+','+inttostr(lIntersection); lLesionVolRA^[((lROI-1)*lnSubj) +lSubj] := lIntersection; end else begin lError:= true; lStr := lStr+',error'; end; //Msg( lImageNames.Strings[lSubj-1]+' '+lROInames[lROI-1]+' I'+inttostr(lIntersection)+' U'+inttostr(lUnion)+' AnotB'+inttostr(lAnotB)+' BnotA'+inttostr(lBnotA)); end; Msg (lImageNames.Strings[lSubj-1] + ' = '+lStr ); end;*) for lROI := 1 to lnROI do begin for lFact := 1 to lnFactors do begin Contrast(lPredictorList[lFact-1],lROInames[lROI-1],singlep(@lBehavRA^[((lFact-1)*lnSubj)+1]),singlep(@lLesionVolRA^[((lROI-1)*lnSubj)+1]),lnSubj);//,((lFact-1)*lnSubj),((lROI-1)*lnSubj)); end; //for each factor end; //for each ROI for lROI := 1 to lnROI do begin Msg( lROInames[lROI-1] +' volume = '+floattostr(lROIvolRA^[lROI]) ) end; //for each ROI Freemem(lLesionVolRA); Freemem(lBehavRA); Freemem(lROIvolRA); 666: lROInames.free; lImageNames.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); end; procedure TMainForm.Masked1Click(Sender: TObject); var lFilename,lMaskname: string; lPos: Integer; begin MsgClear; Msg(GetKVers); if not OpenDialogExecute('Select brain mask ',false,false,kImgFilter) then begin showmessage('NPM aborted: mask selection failed.'); exit; end; //if not selected lMaskname := OpenHdrDlg.Filename; if not OpenDialogExecute('Select images for intensity normalization',true,false,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected if OpenHdrDlg.Files.Count < 1 then exit; for lPos := 1 to OpenHdrDlg.Files.Count do begin lFilename := OpenHdrDlg.Files[lPos-1]; balance(lFilename,lMaskname,(Sender as TMenuItem).tag); end; end; function Binarize (var lImageName:String; lNonZeroVal: integer; lZeroThresh: boolean): boolean; var lImg8: ByteP; lImg: SingleP; lHdr: TMRIcroHdr; lVolVox,lVox: integer; lMin,lMax: single; lModeLo,lModeHi,lIntercept,lSlope: single; lOutNameMod: string; begin //lOutName := lMaskHdr.ImgFileName; result := false; //if not SaveHdrName ('Statistical Map', lOutName) then exit; if not NIFTIhdr_LoadHdr(lImageName,lHdr) then begin showmessage('Error reading '+lImageName); exit; end; lVolVox := lHdr.NIFTIhdr.dim[1]*lHdr.NIFTIhdr.dim[2]* lHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then exit; getmem(lImg,lVolVox*sizeof(single)); getmem(lImg8,lVolVox*sizeof(byte)); if not LoadImg(lHdr.ImgFileName, lImg, 1, lVolVox,round(lHdr.NIFTIhdr.vox_offset),1,lHdr.NIFTIhdr.datatype,lVolVox) then begin Msg('Unable to load ' +lHdr.ImgFileName); exit; end; lHdr.NIFTIhdr.scl_slope := 1; lHdr.NIFTIhdr.scl_inter := 0; if lZeroThresh then begin lOutNameMod := ChangeFilePrefixExt(lImageName,'i','.nii'); lMin := 0; lMax := 0 end else begin lOutNameMod := ChangeFilePrefixExt(lImageName,'i','.voi'); lMin := lIMg^[1]; for lVox := 1 to lVolVox do if lImg^[lVox] < lMin then lMin := lIMg^[lVox]; lMax := lIMg^[1]; for lVox := 1 to lVolVox do if lImg^[lVox] > lMax then lMax := lIMg^[lVox]; for lVox := 1 to lVolVox do lImg8^[lVox] := 0; lMax := ((lMax-lMin) / 2)+lMin; end; for lVox := 1 to lVolVox do if lImg^[lVox] > lMax then lImg8^[lVox] := lNonZeroVal; Msg('Creating ' +lOutNameMod+' Threshold = '+floattostr(lMax)); NIFTIhdr_SaveHdrImg8(lOutNameMod,lHdr.NIFTIhdr,true,not IsNifTiMagic(lHdr.NIFTIhdr),true,lImg8,1); freemem(lIMg8); freemem(lImg); end; procedure TMainForm.Binarizeimages1Click(Sender: TObject); var lFilename: string; lPos: Integer; begin MsgClear; Msg(GetKVers); if not OpenDialogExecute('Select images for intensity normalization',true,false,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected if OpenHdrDlg.Files.Count < 1 then exit; for lPos := 1 to OpenHdrDlg.Files.Count do begin lFilename := OpenHdrDlg.Files[lPos-1]; Binarize(lFilename,1,false); //Binarize (var lImageName:String; lNonZeroVal: integer; lZeroThresh: boolean): boolean; end; Msg('Done'); end; procedure TMainForm.Resliceimagetoneworientationandboundingbox1Click( Sender: TObject); begin (* var lSourcename,lTargetName: string; lPos: integer; begin MsgClear; Msg(GetKVers); Msg('This function will transform a source image to match a target image.'); Msg(' The resliced image will have the voxel size, orientation and bounding box of the target.'); Msg('You will be prompted to select a target image as well as source images.'); Msg(' The resliced image will have the prefix ''r'', e.g. c:\source.nii -> c:\rsource.nii.'); if not OpenDialogExecute('Select target image (source images will be resliced to match target)',false,false,kImgFilter) then begin showmessage('reslice aborted: target selection failed.'); exit; end; //if not selected lTargetName := OpenHdrDlg.Filename; if not OpenDialogExecute('Select source images for reslicing',true,false,kImgFilter) then begin showmessage('reslice aborted: source selection failed.'); exit; end; //if not selected if OpenHdrDlg.Files.Count < 1 then exit; for lPos := 1 to OpenHdrDlg.Files.Count do begin lSourcename := OpenHdrDlg.Files[lPos-1]; xxBinarize(lFilename); end; Msg('Done'); *) end; procedure TMainForm.Setnonseroto1001Click(Sender: TObject); var lFilename: string; lPos: Integer; begin MsgClear; Msg(GetKVers); if not OpenDialogExecute('Select images for intensity normalization',true,false,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected if OpenHdrDlg.Files.Count < 1 then exit; for lPos := 1 to OpenHdrDlg.Files.Count do begin lFilename := OpenHdrDlg.Files[lPos-1]; Binarize(lFilename,100,true); //Binarize (var lImageName:String; lNonZeroVal: integer; lZeroThresh: boolean): boolean; end; end; procedure TMainForm.Savetext1Click(Sender: TObject); begin SaveHdrDlg.Title := 'Save file as comma separated values (to open with Excel)'; SaveHdrDlg.Filter := 'Comma Separated (*.csv)|*.csv|Text (*.txt)|*.txt'; SaveHdrDlg.DefaultExt := '*.csv'; if not SaveHdrDlg.Execute then exit; Memo1.Lines.SaveToFile(SaveHdrDlg.Filename); end; procedure TMainForm.AnaCOMmenuClick(Sender: TObject); begin {$IFDEF compileANACOM} DoAnaCOM; {$ENDIF} end; procedure TMainForm.MonteCarloSimulation1Click(Sender: TObject); begin {$IFDEF benchmark} LesionMonteCarlo (false,true,true); {$ENDIF} end; function TMainForm.MakeSubtract (lPosName,lNegName: string): boolean; var lNegImg,lImg,lOutImg: SingleP; lHdr,lNegHdr: TMRIcroHdr; lVolVox,lVox: integer; lOutNameMod: string; begin result := false; if not NIFTIhdr_LoadHdr(lPosName,lHdr) then begin showmessage('Error reading '+lPosName); exit; end; lVolVox := lHdr.NIFTIhdr.dim[1]*lHdr.NIFTIhdr.dim[2]* lHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then exit; getmem(lImg,lVolVox*sizeof(single)); if not LoadImg(lHdr.ImgFileName, lImg, 1, lVolVox,round(lHdr.NIFTIhdr.vox_offset),1,lHdr.NIFTIhdr.datatype,lVolVox) then begin Msg('Unable to load ' +lHdr.ImgFileName); exit; end; if not NIFTIhdr_LoadHdr(lNegName,lNegHdr) then begin showmessage('Error reading '+lNegName); exit; end; if lVolVox <> (lNegHdr.NIFTIhdr.dim[1]*lNegHdr.NIFTIhdr.dim[2]* lNegHdr.NIFTIhdr.dim[3]) then begin showmessage('Volumes differ'); exit; end; getmem(lImg,lVolVox*sizeof(single)); if not LoadImg(lHdr.ImgFileName, lImg, 1, lVolVox,round(lHdr.NIFTIhdr.vox_offset),1,lHdr.NIFTIhdr.datatype,lVolVox) then begin Msg('Unable to load ' +lHdr.ImgFileName); exit; end; getmem(lNegImg,lVolVox*sizeof(single)); if not LoadImg(lNegHdr.ImgFileName, lNegImg, 1, lVolVox,round(lNegHdr.NIFTIhdr.vox_offset),1,lNegHdr.NIFTIhdr.datatype,lVolVox) then begin Msg('Unable to load ' +lNegHdr.ImgFileName); exit; end; getmem(lOutImg,lVolVox*sizeof(single)); for lVox := 1 to lVolVox do lOutImg^[lVox] := lImg^[lVox] - lNegImg^[lVox]; lHdr.NIFTIhdr.scl_slope := 1; lHdr.NIFTIhdr.scl_inter := 0; lOutNameMod := ChangeFilePrefixExt(lPosName,'subtract_','.hdr'); Msg(lPosName+' - ' + lNegName+ ' = '+lOutNameMod); NIFTIhdr_SaveHdrImg(lOutNameMod,lHdr.NIFTIhdr,true,not IsNifTiMagic(lHdr.NIFTIhdr),true,lOutImg,1); //end optional //NIFTIhdr_SaveHdr(lHdr.HdrFilename,lHdr.NIFTIhdr,true,not IsNifTiMagic(lHdr.NIFTIhdr)); freemem(lImg); freemem(lOutImg); freemem(lNegImg); end;//makesubtract procedure TMainForm.Subtract1Click(Sender: TObject); var lPosName,lNegName: string; begin if not OpenDialogExecute('Select positive',false,false,kImgPlusVOIFilter) then exit; lPosName := OpenHdrDlg.FileName; if not OpenDialogExecute('Select negative',false,false,kImgPlusVOIFilter) then exit; lNegName := OpenHdrDlg.FileName; MakeSubtract (lPosName,lNegName); end; procedure TMainForm.LogPtoZ1Click(Sender: TObject); var lFilename: string; lPos: Integer; begin MsgClear; Msg(GetKVers); if not OpenDialogExecute('Select images for intensity normalization',true,false,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected if OpenHdrDlg.Files.Count < 1 then exit; for lPos := 1 to OpenHdrDlg.Files.Count do begin lFilename := OpenHdrDlg.Files[lPos-1]; //LogPToZ(lFilename,1,false); end; Msg('Done'); end; {$IFDEF UNIX} initialization {$I npmform.lrs} {$ELSE} //not unix: windows initialization {$IFDEF FPC} {$I npmform.lrs} {$ENDIF}//FPC OleInitialize(nil); finalization OleUninitialize {$ENDIF} //Windows end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/npmform.dfm����������������������������������������������0000755�0001750�0001750�00000013157�12107136224�020335� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �TMAINFORM�0\��TPF0 TMainFormMainFormLeft@TopCWidthHeightCaptionNon-Parametric MappingColor clBtnFace Font.CharsetDEFAULT_CHARSET Font.Color clWindowText Font.Height Font.Name MS Sans Serif Font.Style �Menu MainMenu1OldCreateOrder PositionpoScreenCenterOnClose FormCloseOnCreate FormCreateOnShowFormShow PixelsPerInch` TextHeight �TMemoMemo1Left�Top�WidthHeightAlignalClient ScrollBars ssVerticalTabOrder�WordWrap��TPanelPanel1Left�TopWidthHeightAlignalBottom BevelOuterbvNoneCaptionPanel1TabOrder� TProgressBar ProgressBar1Left�Top�WidthHeightAlignalClientTabOrder���� TOpenDialog OpenHdrDlgLeftTop<�� TSaveDialog SaveHdrDlgLeftTop$�� TMainMenu MainMenu1LeftTop� TMenuItemFile1CaptionFile� TMenuItem Savetext1Caption Save text....OnClickSavetext1Click�� TMenuItemExit1CaptionExitOnClick Exit1Click��� TMenuItemEdit1CaptionEdit� TMenuItemCopy1CaptionCopyShortCutC@OnClick Copy1Click��� TMenuItemVLSM1CaptionVLSM� TMenuItemBinomialAnalysislesions1CaptionBinary images, binary behaviorShortCutB@OnClickLesionBtnClick�� TMenuItem!Binaryimagescontinuousgroupsfast1TagCaption"Binary images, continuous behaviorShortCutL@OnClickLesionBtnClick�� TMenuItemPenalizedLogisticRegerssion1Caption"Binary Images, Multiple RegressorsOnClick!PenalizedLogisticRegerssion1Click�� TMenuItem AnaCOMmenuCaptionAnaCOMVisibleOnClickAnaCOMmenuClick�� TMenuItemMonteCarloSimulation1CaptionMonteCarloSimulationOnClickMonteCarloSimulation1Click�� TMenuItem ROIanalysis1Caption ROI analysisOnClickROIanalysis1Click�� TMenuItemDesign1Caption Design...ShortCutD@OnClick Design1Click��� TMenuItemVBM1CaptionVBM� TMenuItemContinuousanalysisVBM1Caption&Continuous images, binary groups (VBM)ShortCutV@OnClickNPMclick�� TMenuItemMultipleRegressCaptionMultiple WLS RegressionShortCutR@OnClickMultipleRegressClick�� TMenuItem SingleRegressTagCaptionSingle WLS RegressionOnClickSingleRegressClick�� TMenuItemDualImageCorrelation1CaptionDual Image CorrelationOnClickDualImageCorrelation1Click�� TMenuItem PairedTMenuCaptionPaired Measures T-testOnClickPairedTMenuClick��� TMenuItemOptions1CaptionOptions� TMenuItem Permutations1Caption Permutations� TMenuItemN0CaptionNoneChecked GroupIndex{ RadioItem OnClickradiomenuclick�� TMenuItemN1000TagCaption1000 GroupIndex{ RadioItem OnClickradiomenuclick�� TMenuItemN2000TagCaption2000 GroupIndex{ RadioItem OnClickradiomenuclick�� TMenuItemN3000Tag Caption3000 GroupIndex{ RadioItem OnClickradiomenuclick�� TMenuItemN4000TagCaption4000 GroupIndex{ RadioItem OnClickradiomenuclick��� TMenuItemTests1CaptionTests� TMenuItem ttestmenuCaptionttestChecked OnClick testmenuclick�� TMenuItemBMmenuCaptionBrunner MunzelChecked GroupIndexOnClick testmenuclick��� TMenuItemThreads1CaptionThreads� TMenuItemT1Caption1Checked GroupIndex� RadioItem OnClick threadChange�� TMenuItemT2Caption2 GroupIndex� RadioItem OnClick threadChange�� TMenuItemT3Caption3 GroupIndex� RadioItem OnClick threadChange�� TMenuItemT4Caption4 GroupIndex� RadioItem OnClick threadChange�� TMenuItemT7Caption7 GroupIndex� RadioItem OnClick threadChange�� TMenuItemT8Caption8 GroupIndex� RadioItem OnClick threadChange�� TMenuItemT15Caption15 GroupIndex� RadioItem OnClick threadChange�� TMenuItemT16Caption16 GroupIndex� RadioItem OnClick threadChange���� TMenuItem Utilities1Caption Utilities� TMenuItem niiniigz1Caption nii->.nii.gzOnClickniiniigz1Click�� TMenuItem Variance1CaptionVariance imageOnClickVariance1Click�� TMenuItemMakemeanimage2TagCaptionMake binarized mean OnClickMakemeanimage1Click�� TMenuItemBinarizeimages1CaptionBinarize imagesOnClickBinarizeimages1Click�� TMenuItemMakemeanimage1CaptionMake mean/StDev imageShortCutM@OnClickMakemeanimage1Click�� TMenuItemSingleSubjectZScores1CaptionSingle Subject Z-ScoresOnClickSingleSubjectZScores1Click�� TMenuItem PhysiologicalArtifactCorrection1CaptionPhysiological CorrectionOnClick%PhysiologicalArtifactCorrection1Click�� TMenuItemCountlesionoverlaps1CaptionCount lesion overlapsOnClickCountlesionoverlaps1Click�� TMenuItemComputeIntersectionandUnion1CaptionCompute Intersection and UnionOnClick!ComputeIntersectionandUnion1Click�� TMenuItemIntensitynormalization1CaptionIntensity normalization� TMenuItemMaskedintensitynormalizationA1TagCaption Masked intensity normalization AShortCutI@OnClick Masked1Click�� TMenuItemMasked1Caption Masked intensity normalization BOnClick Masked1Click�� TMenuItemMaskedintensitynormalizationB1TagCaption Masked intensity normalization COnClick Masked1Click�� TMenuItemIntensitynormalizationA1TagCaptionIntensity normalization AOnClick Balance1Click�� TMenuItemBalance1CaptionIntensity normalization BOnClick Balance1Click�� TMenuItemSetnonseroto1001CaptionSet non-zero to 100OnClickSetnonseroto1001Click��� TMenuItem+Resliceimagetoneworientationandboundingbox1CaptionReslice imagesVisibleOnClick0Resliceimagetoneworientationandboundingbox1Click�� TMenuItem Subtract1CaptionSubtract imagesOnClickSubtract1Click�� TMenuItemLogPtoZ1Caption LogP to ZOnClick LogPtoZ1Click�� TMenuItemFCE1CaptionTFCEOnClick FCE1Click��� TMenuItemHelp1CaptionHelp� TMenuItemAbout1CaptionAboutShortCutA@OnClick About1Click�� TMenuItemAssociatevalfileswithNPM1CaptionAssociate .val files with NPMOnClickAssociatevalfileswithNPM1Click����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/results.niiNotesseverity.txt�����������������������������0000755�0001750�0001750�00000004403�11326425450�024011� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Threads: 2 Factor = severity c:\mri\anacom\n01.voi = 4.00 c:\mri\anacom\n02.voi = 4.50 c:\mri\anacom\n03.voi = 0.00 c:\mri\anacom\n04.voi = 2.50 c:\mri\anacom\n05.voi = 5.00 c:\mri\anacom\n06.voi = 4.00 c:\mri\anacom\n07.voi = 3.25 c:\mri\anacom\n08.voi = 0.75 c:\mri\anacom\n09.voi = 4.50 c:\mri\anacom\n10.voi = 4.50 c:\mri\anacom\n11.voi = 0.50 c:\mri\anacom\n12.voi = 1.63 c:\mri\anacom\n13.voi = 0.00 c:\mri\anacom\n14.voi = 3.50 c:\mri\anacom\n15.voi = 3.00 c:\mri\anacom\n17.voi = 4.00 c:\mri\anacom\n18.voi = 2.00 c:\mri\anacom\n19.voi = 4.50 c:\mri\anacom\n20.voi = 5.00 c:\mri\anacom\n21.voi = 0.00 c:\mri\anacom\n22.voi = 1.50 c:\mri\anacom\n23.voi = 5.00 c:\mri\anacom\n24.voi = 2.50 c:\mri\anacom\n25.voi = 5.00 c:\mri\anacom\n26.voi = 4.00 c:\mri\anacom\n27.voi = 0.00 c:\mri\anacom\n28.voi = 0.00 c:\mri\anacom\n29.voi = 2.00 c:\mri\anacom\n30.voi = 1.50 c:\mri\anacom\n31.voi = 1.75 c:\mri\anacom\n32.voi = 0.00 c:\mri\anacom\n33.voi = 2.50 c:\mri\anacom\n34.voi = 5.00 c:\mri\anacom\n35.voi = 0.00 c:\mri\anacom\n37.voi = 0.00 c:\mri\anacom\n38.voi = 3.25 c:\mri\anacom\n39.voi = 4.38 c:\mri\anacom\n40.voi = 0.00 c:\mri\anacom\n41.voi = 3.75 c:\mri\anacom\n42.voi = 0.25 c:\mri\anacom\n43.voi = 0.00 c:\mri\anacom\n44.voi = 2.00 c:\mri\anacom\n45.voi = 5.00 c:\mri\anacom\n46.voi = 0.00 c:\mri\anacom\n47.voi = 0.50 c:\mri\anacom\n48.voi = 0.00 c:\mri\anacom\n49.voi = 2.25 c:\mri\anacom\n50.voi = 0.00 c:\mri\anacom\n51.voi = 2.25 c:\mri\anacom\n52.voi = 2.00 c:\mri\anacom\n53.voi = 0.00 c:\mri\anacom\n54.voi = 0.25 c:\mri\anacom\n55.voi = 0.00 Total voxels = 7109137 Only testing voxels damaged in at least 5 individual[s] Number of Lesion maps = 53 Permutations = 0 Analysis began = 2008-Mar-24 14:41:02 Memory planks = 0.701815434883711 Max voxels per Plank = 10129639 Computing plank = 1 Voxels tested = 40826 Only tested voxels with more than 5 lesions 40826 test Std Bonferroni FWE Z 0.050=4.712, 0.025=4.852, 0.01=5.030 n=,53,minN=,5,unique overlap patterns,9785,voxels tested,20016 9785 test Unique overlap Bonferroni FWE Z 0.050=4.412, 0.025=4.560, 0.01=4.749 ttest Range -3.936...5.118 ttest +FDR Z 0.050=2.085, 0.01=3.152 ttest -FDR Z 0.050=-3.440, 0.01=9.200 Analysis finished = 2008-Mar-24 14:41:50 �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm_precl/statcr.pas�����������������������������������������������0000755�0001750�0001750�00000037420�11326425450�020177� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Unit statcr; interface uses Dialogs,define_types; const ITMAX = 300; EPS = 3.0e-7; kMaxFact = 1700; {<= 1754} gFactRAready : boolean = false; type FactRA = array[0..kMaxFact] of extended; var gFactRA : FactRA; FUNCTION betai(a,b,x: double): double; procedure AlertMsg (pWarningStr: String); function gammq( a,x: real): real; function Fisher (A,B,C,D: integer): double; procedure Chi2x2 (A, B, C, D: integer; var pMinExp, pChi, p, puChi, pup: double); function Liebermeister (A,B,C,D: integer): extended; procedure EstimateFDR(lnTests: integer; Ps: SingleP; var lFDR05, lFDR01: double); function Fisher1TailMidP (A,B,C,D: integer): double; { use instead of chi2x2: returns p-value} procedure InitFact; procedure EstimateFDR2(lnTests: integer; var Ps: SingleP; var lFDR05, lFDR01,lnegFDR05, lnegFDR01: double); procedure Descriptive (nV, SumOfSqrs, Sum: double; var lMn,lSD,lSE: double); procedure SuperDescriptive (var RA: SingleP; n: integer; var lMn,lSD,lSE,lSkew,lZSkew: double); implementation uses Math{power}; procedure Descriptive (nV, SumOfSqrs, Sum: double; var lMn,lSD,lSE: double); //given nV,SumOfSqrs,and Sum, returns Mean, StandardDeviation,StandardError and Skew begin //first: initialize values lSD := 0; lSE := 0; lMn := 0; if nV < 1 then exit; //next: compute mean lMn := Sum / nV; if (nV < 2) then exit; lSD := SumOfSqrs-(Sum*Sum/nV); lSD := sqrt((lSD)/(nV-1) ); lSE := lSD/ sqrt(nV); end; procedure SuperDescriptive (var RA: SingleP; n: integer; var lMn,lSD,lSE,lSkew,lZSkew: double); var i: integer; SumOfSqrs,Sum,Sigma: double; begin lMn:= 0; lSD := 0; lSE := 0; lSkew := 0; lZSkew := 0; if n < 1 then exit; Sum := 0; SumOfSqrs := 0; for i := 1 to n do begin Sum := Sum + RA^[i]; SumOfSqrs := SumOfSqrs + sqr(RA^[i]); end; Descriptive (n, SumOfSqrs, Sum,lMn,lSD,lSE); if (n < 3) or (lSD = 0) then lSkew := 0 else begin Sigma := 0; for i := 1 to n do Sigma := Sigma + Power( ((RA^[i]-lMn) / lSD) ,3); lSkew := (n/ ( (n-1)*(n-2) ) ) * Sigma; end; lZSkew := lSkew/(sqrt(6/N)); end; procedure InitFact; var lX: word; begin gFactRA[0]:= 1; gFactRA[1] := 1; for lx := 2 to kMaxFact do gFactRA[lx] := lx * gFactRA[lx-1]; gFactRAready := true; end; function FisherX (A,B,C,D: integer): double; {FisherExactTest, use instead of chi} {FisherX computes odds for this specific config only, not more extreme cases} {alternate to Chi Square, see Siegel & Castellan, Nonparametric Statistics} {use instead of Chi when n <= 20} {A= X hits, B= control hits, C = X misses, D = control misses} var N: word; begin N := A+B+C+D; if (N <= kMaxFact) and (A>=0) and (B>=0) and (C>=0) and (D>=0) and (N > 0) then begin FisherX := ( (gFactRA[A+B]/gFactRA[A])* (gFactRA[B+D]/gFactRA[B])* (gFactRA[A+C]/gFactRA[C])* (gFactRA[C+D]/gFactRA[D]) )/ gFactRA[N]; end else FisherX := 0; end; function MidPKingFisher (lSmal,lCross1,lCross2,lSmalDiag: integer): extended; var lProb1, lProb2: extended; lA,lB,lC,lD,lCnt: integer; l1st : boolean; begin lA :=lSmal; lB:=lCross1; lC:=lCross2; lD:=lSmalDiag; lProb1:=0; l1st := true; //set to true for midP for lCnt := lA downto 0 do begin if l1st then lProb1 := 0.5* FisherX(lA,lB,lC,lD) else lProb1 := lProb1 + FisherX(lA,lB,lC,lD); l1st := false; dec(lA); dec(lD); inc(lB); inc(lC); end; lA :=lSmal; lB:=lCross1; lC:=lCross2; lD:=lSmalDiag; lProb2:=0; l1st := true; //alfa -set to true for MidP while (lB >= 0) and (lC >= 0) do begin if l1st then lProb2 := 0.5* FisherX(lA,lB,lC,lD) else lProb2 := lProb2 + FisherX(lA,lB,lC,lD); l1st := false; inc(lA); inc(lD); dec(lB); dec(lC); end; if lProb1 < lProb2 then result := lProb1 else result := lProb2; //result := lprob1; end; function KingFisher (lSmal,lCross1,lCross2,lSmalDiag: integer): double; var lProb1, lProb2: double; lA,lB,lC,lD,lCnt: integer; begin lA :=lSmal; lB:=lCross1; lC:=lCross2; lD:=lSmalDiag; lProb1:=0; for lCnt := lA downto 0 do begin lProb1 := lProb1 + FisherX(lA,lB,lC,lD); dec(lA); dec(lD); inc(lB); inc(lC); end; lA :=lSmal; lB:=lCross1; lC:=lCross2; lD:=lSmalDiag; lProb2:=0; while (lB >= 0) and (lC >= 0) do begin lProb2 := lProb2 + FisherX(lA,lB,lC,lD); inc(lA); inc(lD); dec(lB); dec(lC); end; if lProb1 < lProb2 then result := lProb1 else result := lProb2; end; function Lieber (lSmal,lCross1,lCross2,lSmalDiag: integer): extended; var lA,lB,lC,lD,lCnt: integer; begin lA :=lSmal; lB:=lCross1+1; lC:=lCross2+1; lD:=lSmalDiag; result :=0; for lCnt := lA downto 0 do begin result := result + FisherX(lA,lB,lC,lD); dec(lA); dec(lD); inc(lB); inc(lC); end; //TabbedNotebookDlg.caption := realtostr(result,6) ; //TabbedNotebookDlg.caption := realtostr(result,6) ; if result <= 0.5 then exit; lA :=lSmal+1; lB:=lCross1; lC:=lCross2; lD:=lSmalDiag+1; result:=0; while (lB >= 0) and (lC >= 0) do begin result := result + FisherX(lA,lB,lC,lD); inc(lA); inc(lD); dec(lB); dec(lC); end; end; function Liebermeister (A,B,C,D: integer): extended; {A= X hits, B= control hits, C = X misses, D = control misses} begin result := 1; if (A+B+C+D)<1 then exit; if not gFactRAready then InitFact; if (A<=B) and (A<=C) and (A<=D) then {lA smallest} result :=Lieber(A,B,C,D) else if (B<=C) and (B<=D) then {lB smallest} result :=Lieber(B,A,D,C) else if (C<=D) then {lC smallest} result :=Lieber(C,D,A,B) else {d smallest} result :=Lieber(D,C,B,A); if ((A+C)>0) and ((B+D)>0) then begin if (A/(A+C)) < (B/(B+D)) then result := -result; end; end; (*function Liebermeister (Ain,Bin,Cin,Din: integer): extended; var A,B,C,D: integer; {A= X hits, B= control hits, C = X misses, D = control misses} begin A := Ain; B := Bin; C := Cin; D := Din; if (A+B+C+D)<1 then begin result := 1; exit; end; //easy way to calculate Lieberman - make more extreme, then calculate Fisher if abs(A-D) > abs(B-C) then begin inc(A); inc(D); end else begin inc(B); inc(C); end; if not gFactRAready then InitFact; if (A<=B) and (A<=C) and (A<=D) then {lA smallest} result :=KingFisher(A,B,C,D) else if (B<=C) and (B<=D) then {lB smallest} result :=KingFisher(B,A,D,C) else if (C<=D) then {lC smallest} result :=KingFisher(C,D,A,B) else {d smallest} result :=KingFisher(D,C,B,A); if ((A+C)>0) and ((B+D)>0) then begin if (A/(A+C)) < (B/(B+D)) then result := -result; end; end;*) function Fisher (A,B,C,D: integer): double; {A= X hits, B= control hits, C = X misses, D = control misses} begin if (A+B+C+D)<1 then begin result := 1; exit end; if not gFactRAready then InitFact; if (A<=B) and (A<=C) and (A<=D) then {lA smallest} result :=KingFisher(A,B,C,D) else if (B<=C) and (B<=D) then {lB smallest} result :=KingFisher(B,A,D,C) else if (C<=D) then {lC smallest} result :=KingFisher(C,D,A,B) else {d smallest} result :=KingFisher(D,C,B,A); if ((A+C)>0) and ((B+D)>0) then begin if (A/(A+C)) < (B/(B+D)) then result := -result; end; end; function Fisher1TailMidP (A,B,C,D: integer): double; {A= X hits, B= control hits, C = X misses, D = control misses} begin if (A+B+C+D)<1 then begin result := 1; exit end; if not gFactRAready then InitFact; if (A<=B) and (A<=C) and (A<=D) then {lA smallest} result :=MidPKingFisher(A,B,C,D) else if (B<=C) and (B<=D) then {lB smallest} result :=MidPKingFisher(B,A,D,C) else if (C<=D) then {lC smallest} result :=MidPKingFisher(C,D,A,B) else {d smallest} result :=MidPKingFisher(D,C,B,A); if ((A+C)>0) and ((B+D)>0) then begin if (A/(A+C)) < (B/(B+D)) then result := -result; end; end; procedure Sort (first, last: integer; var DynDataRA:SingleP); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} {less memory intensive than recursive quicksort} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n, nn, m, lognb2, l, k, j, i: INTEGER; swap: Single; begin n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 1 to k do begin i := j; 555: {<- LABEL} l := i + m; if (DynDataRA^[l] < DynDataRA^[i]) then begin swap := DynDataRA^[i]; DynDataRA^[i] := DynDataRA^[l]; DynDataRA^[l] := swap; i := i - m; if (i >= 1) then goto 555; end end end end;//sort procedure EstimateFDR(lnTests: integer; Ps: SingleP; var lFDR05, lFDR01: double); var lInc: integer; Qs: SingleP; begin //rank Pvalues Sort(1,lnTests,Ps); {lStr := 'sort='; for lInc := 1 to knTests do lStr := lStr+realtostr(Ps[lInc],4)+','; Memo1.Lines.Add(lStr); } GetMem(Qs,lnTests*sizeof(single)); //next findcrit FDR05 for lInc := 1 to lnTests do Qs^[lInc] := (0.05*lInc)/lnTests; lFDR05 := 0; for lInc := 1 to lnTests do if Ps^[lInc] <= Qs^[lInc] then lFDR05 := Ps^[lInc]; //next findcrit FDR01 for lInc := 1 to lnTests do Qs^[lInc] := (0.01*lInc)/lnTests; lFDR01 := 0; for lInc := 1 to lnTests do if Ps^[lInc] <= Qs^[lInc] then lFDR01 := Ps^[lInc]; Freemem(Qs); end; procedure EstimateFDR2(lnTests: integer; var Ps: SingleP; var lFDR05, lFDR01,lnegFDR05, lnegFDR01: double); var lInc: integer; lrPs,Qs: SingleP; begin //rank Pvalues Sort(1,lnTests,Ps); {lStr := 'sort='; for lInc := 1 to knTests do lStr := lStr+realtostr(Ps[lInc],4)+','; Memo1.Lines.Add(lStr); } GetMem(Qs,lnTests*sizeof(single)); //next findcrit FDR05 for lInc := 1 to lnTests do Qs^[lInc] := (0.05*lInc)/lnTests; lFDR05 := 0; for lInc := 1 to lnTests do if Ps^[lInc] <= Qs^[lInc] then lFDR05 := Ps^[lInc]; //next findcrit FDR01 for lInc := 1 to lnTests do Qs^[lInc] := (0.01*lInc)/lnTests; lFDR01 := 0; for lInc := 1 to lnTests do if Ps^[lInc] <= Qs^[lInc] then lFDR01 := Ps^[lInc]; //reverse GetMem(lrPs,lnTests*sizeof(single)); for lInc := 1 to lnTests do lrPs^[lInc] := 1- Ps^[lnTests-lInc+1]; //for lInc := 1 to lnTests do // Ps[lInc] := lR[lnTests-lInc+1]; for lInc := 1 to lnTests do Qs^[lInc] := (0.05*lInc)/lnTests; lnegFDR05 := 0; for lInc := 1 to lnTests do if lrPs^[lInc] <= Qs^[lInc] then lnegFDR05 := lrPs^[lInc]; //next findcrit FDR01 for lInc := 1 to lnTests do Qs^[lInc] := (0.01*lInc)/lnTests; lnegFDR01 := 0; for lInc := 1 to lnTests do if lrPs^[lInc] <= Qs^[lInc] then lnegFDR01 := lrPs^[lInc]; FreeMem(lrPs); Freemem(Qs); end; procedure AlertMsg (pWarningStr: String); begin MessageDLG(pWarningStr, mtWarning,[mbOK],0); end; function gammln (xx: double): double; {Numerical Recipes for Pascal, p 177} const stp = 2.50662827465; var x, tmp, ser: double; begin x := xx - 1.0; tmp := x + 5.5; tmp := (x + 0.5) * ln(tmp) - tmp; ser := 1.0 + 76.18009173 / (x + 1.0) - 86.50532033 / (x + 2.0) + 24.01409822 / (x + 3.0) - 1.231739516 / (x + 4.0) + 0.120858003e-2 / (x + 5.0) - 0.536382e-5 / (x + 6.0); gammln := tmp + ln(stp * ser) end; {procedure gammln} FUNCTION betacf(a,b,x: double): double; LABEL 1; CONST itmax=100; eps=3.0e-7; VAR tem,qap,qam,qab,em,d: double; bz,bpp,bp,bm,az,app: double; am,aold,ap: double; m: integer; BEGIN am := 1.0; bm := 1.0; az := 1.0; qab := a+b; qap := a+1.0; qam := a-1.0; bz := 1.0-qab*x/qap; FOR m := 1 TO itmax DO BEGIN em := m; tem := em+em; d := em*(b-m)*x/((qam+tem)*(a+tem)); ap := az+d*am; bp := bz+d*bm; d := -(a+em)*(qab+em)*x/((a+tem)*(qap+tem)); app := ap+d*az; bpp := bp+d*bz; aold := az; am := ap/bpp; bm := bp/bpp; az := app/bpp; bz := 1.0; IF ((abs(az-aold)) < (eps*abs(az))) THEN GOTO 1 END; writeln('pause in BETACF'); writeln('a or b too big, or itmax too small'); readln; 1: betacf := az END; FUNCTION betai(a,b,x: double): double; VAR bt: double; BEGIN IF ((x < 0.0) OR (x > 1.0)) THEN BEGIN writeln('pause in routine BETAI'); readln END; IF ((x = 0.0) OR (x = 1.0)) THEN bt := 0.0 ELSE bt := exp(gammln(a+b)-gammln(a)-gammln(b) +a*ln(x)+b*ln(1.0-x)); IF (x < ((a+1.0)/(a+b+2.0))) THEN betai := bt*betacf(a,b,x)/a ELSE betai := 1.0-bt*betacf(b,a,1.0-x)/b END; procedure gser(var gamser, a,x, gln: real); var n: integer; sum, del, ap: real; begin gln := gammln(a); if x <= 0.0 then begin if x < 0.0 then AlertMsg('x less then 0 in routine GSER'); gamser:= 0.0; end else begin ap := a; sum := 1.0/a; del := sum; for n := 1 to ITMAX do begin ap := ap + 1; del := del * (x/ap); sum := sum + del; if (abs(del) < abs((sum)*EPS) )then begin gamser := sum * exp(-x+a*ln(x)-gln); exit; end; end; Alertmsg('GSER error: ITMAX too small for requested a-value'); end; end; procedure gcf(var gammcf: real; a,x, gln: real); var n: integer; gold,fac,b1,b0,a0,g,ana,anf,an,a1: real; begin fac := 1.0; b1 := 1.0; b0 := 0.0; a0 := 1.0; gold := 0.0; gln := gammln(a); a1 := x; for n := 1 to ITMAX do begin an :=(n); ana := an - a; a0 := (a1 + a0*ana)*fac; b0 := (b1 + b0*ana)*fac; anf := an * fac; a1 := x*a0+anf*a1; b1 := x*b0+anf*b1; if a1 <> 0 then begin fac := 1.0/a1; g := b1*fac; if (abs((g-gold)/g)<EPS) then begin gammcf := exp(-x+a*ln(x)-gln)*g; exit; end; gold := g; end; end; Alertmsg('GCF error: ITMAX too small for requested a-value'); end; function gammq( a,x: real): real; var gamser, gammcf, gln: real; begin gammq := 0; if (x < 0) or (a <= 0.0) then alertmsg('Invalid arguments in routine GAMMQ') else begin if (x < (a+1.0)) then begin gser(gamser,a,x,gln); gammq := 1.0 - gamser; end else begin gcf(gammcf,a,x,gln); gammq := gammcf; end; end; end; procedure Chi2x2 (A, B, C, D: integer; var pMinExp, pChi, p, puChi, pup: double); {A= X hits, B= control hits, C = X misses, D = control misses} var lA, lB, lC, lD, lN: extended; {AEXp, BExp, CExp, Dexp, } lSameOdds: boolean; begin lA := A; {convert to extended} lB := B; lC := C; lD := D; ln := lA + lB + lC + lD; if lN > 0 then begin {avoid divide by 0} pMinExp := ((lA + lB) * (lA + lC)) / lN; if (((lA + lB) * (lB + lD)) / lN) < pMinExp then pMinExp := ((lA + lB) * (lB + lD)) / lN; if (((lC + lD) * (lA + lC)) / lN) < pMinExp then pMinExp := ((lC + lD) * (lA + lC)) / lN; if (((lC + lD) * (lB + lD)) / lN) < pMinExp then pMinExp := ((lC + lD) * (lB + lD)) / lN; end else pMinExp := 0; lSameOdds := false; if (lC > 0) and (lD > 0) then begin if (lA / lC) = (lB / lD) then lSameOdds := true; end; if (lC = 0) and (lD = 0) then lSameOdds := true; if ((lA+lC) = 0) or ((lB+lD) = 0) then lSameOdds := true; if (lSameOdds = true) then begin pChi := 0; {same odds} p := 1.0; puChi := 0; pup := 1.0; end else begin puChi := ((sqr((lA * lD) - (lB * lC))) * lN) / ((la + lb) * (lc + ld) * (lb + ld) * (la + lc)); pup := gammq(0.5, 0.5 * puChi); {half df} pChi := ((sqr(abs((lA * lD) - (lB * lC)) - (0.5 * lN))) * lN) / ((la + lb) * (lc + ld) * (lb + ld) * (la + lc)); p := gammq(0.5, 0.5 * pChi); end; end; END. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/cutout.lrs���������������������������������������������������������0000755�0001750�0001750�00000007613�11450447356�016270� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TCutoutForm','FORMDATA',[ 'TPF0'#11'TCutoutForm'#10'CutoutForm'#4'Left'#3#128#1#6'Height'#3'N'#1#3'Top' +#3#175#0#5'Width'#3'N'#1#18'HorzScrollBar.Page'#3'O'#1#18'VertScrollBar.Page' +#3'<'#1#13'ActiveControl'#7#17'RenderCutoutCheck'#11'BorderIcons'#11#12'biSy' +'stemMenu'#10'biMinimize'#0#11'BorderStyle'#7#8'bsSingle'#7'Caption'#6#7'Cut' +'outs'#12'ClientHeight'#3'N'#1#11'ClientWidth'#3'N'#1#21'Constraints.MaxHeig' +'ht'#3'N'#1#20'Constraints.MaxWidth'#3'N'#1#21'Constraints.MinHeight'#3'N'#1 +#20'Constraints.MinWidth'#3'N'#1#7'OnClose'#7#9'FormClose'#6'OnShow'#7#8'For' +'mShow'#8'Position'#7#14'poScreenCenter'#10'LCLVersion'#6#6'0.9.29'#0#9'TChe' +'ckBox'#17'RenderCutoutCheck'#4'Left'#2#16#6'Height'#2#17#3'Top'#2#8#5'Width' +#2'P'#7'Caption'#6#11'Show cutout'#7'OnClick'#7#22'RenderCutoutCheckClick'#8 +'TabOrder'#2#0#0#0#9'TGroupBox'#9'CutoutBox'#4'Left'#2#16#6'Height'#3#224#0#3 +'Top'#2' '#5'Width'#3'0'#1#12'ClientHeight'#3#206#0#11'ClientWidth'#3','#1#8 +'TabOrder'#2#5#0#6'TLabel'#6'Label1'#4'Left'#2#14#6'Height'#2#14#3'Top'#2#8#5 +'Width'#2':'#7'Caption'#6#12'X [low=left]'#11'ParentColor'#8#0#0#6'TLabel'#6 +'Label2'#4'Left'#2#14#6'Height'#2#14#3'Top'#2'0'#5'Width'#2'U'#7'Caption'#6 +#17'Y [low=posterior]'#11'ParentColor'#8#0#0#6'TLabel'#6'Label3'#4'Left'#2#14 +#6'Height'#2#14#3'Top'#2'X'#5'Width'#2'L'#7'Caption'#6#15'Z [low=ventral]'#11 +'ParentColor'#8#0#0#6'TLabel'#6'Label4'#4'Left'#2#14#6'Height'#2#14#3'Top'#3 +#135#0#5'Width'#2'7'#7'Caption'#6#11'Cutout Tint'#11'ParentColor'#8#0#0#6'TL' +'abel'#6'Label5'#4'Left'#2#14#6'Height'#2#14#3'Top'#3#175#0#5'Width'#2'>'#7 +'Caption'#6#12'Cutout Color'#11'ParentColor'#8#0#0#9'TSpinEdit'#3'XLo'#4'Lef' +'t'#2'v'#6'Height'#2#21#3'Top'#2#0#5'Width'#2'R'#8'MaxValue'#3#232#3#8'OnCha' +'nge'#7#12'PreviewClick'#8'TabOrder'#2#0#0#0#9'TSpinEdit'#3'XHi'#4'Left'#3 +#206#0#6'Height'#2#21#3'Top'#2#0#5'Width'#2'R'#8'MaxValue'#3#232#3#8'OnChang' +'e'#7#12'PreviewClick'#8'TabOrder'#2#1#0#0#9'TSpinEdit'#3'YLo'#4'Left'#2'v'#6 +'Height'#2#21#3'Top'#2'('#5'Width'#2'R'#8'MaxValue'#3#232#3#8'OnChange'#7#12 +'PreviewClick'#8'TabOrder'#2#2#0#0#9'TSpinEdit'#3'YHi'#4'Left'#3#206#0#6'Hei' +'ght'#2#21#3'Top'#2'('#5'Width'#2'R'#8'MaxValue'#3#232#3#8'OnChange'#7#12'Pr' +'eviewClick'#8'TabOrder'#2#3#0#0#9'TSpinEdit'#3'ZLo'#4'Left'#2'v'#6'Height'#2 +#21#3'Top'#2'X'#5'Width'#2'R'#8'MaxValue'#3#232#3#8'OnChange'#7#12'PreviewCl' +'ick'#8'TabOrder'#2#4#0#0#9'TSpinEdit'#3'ZHi'#4'Left'#3#206#0#6'Height'#2#21 +#3'Top'#2'X'#5'Width'#2'R'#8'MaxValue'#3#232#3#8'OnChange'#7#12'PreviewClick' +#8'TabOrder'#2#5#0#0#9'TComboBox'#14'CutoutBiasDrop'#4'Left'#2'v'#6'Height'#2 +#19#3'Top'#3#128#0#5'Width'#3#170#0#10'ItemHeight'#2#13#13'Items.Strings'#1#6 +#8'0.1 Dark'#6#3'0.2'#6#3'0.3'#6#3'0.4'#6#3'0.5'#6#3'0.6'#6#3'0.7'#6#3'0.8'#6 +#9'0.9 Light'#0#8'OnChange'#7#12'PreviewClick'#5'Style'#7#16'csOwnerDrawFixe' +'d'#8'TabOrder'#2#6#0#0#9'TComboBox'#13'CutoutLUTDrop'#4'Left'#2'v'#6'Height' +#2#19#3'Top'#3#168#0#5'Width'#3#170#0#10'ItemHeight'#2#13#8'OnChange'#7#12'P' +'reviewClick'#5'Style'#7#16'csOwnerDrawFixed'#8'TabOrder'#2#7#0#0#0#7'TButto' +'n'#10'PreviewBtn'#4'Left'#3#128#0#6'Height'#2#25#3'Top'#3'0'#1#5'Width'#2'K' +#7'Caption'#6#7'Preview'#7'OnClick'#7#12'PreviewClick'#8'TabOrder'#2#2#7'Vis' +'ible'#8#0#0#7'TButton'#6'DefBtn'#4'Left'#3#128#0#6'Height'#2#25#3'Top'#3#16 +#1#5'Width'#2'K'#7'Caption'#6#8'Defaults'#7'OnClick'#7#11'DefBtnClick'#8'Tab' +'Order'#2#3#0#0#7'TButton'#5'OKBtn'#4'Left'#3#237#0#6'Height'#2#25#3'Top'#3 +#16#1#5'Width'#2'K'#7'Caption'#6#2'OK'#7'OnClick'#7#10'OKBtnClick'#8'TabOrde' +'r'#2#4#0#0#7'TButton'#11'PreviewBtn1'#4'Left'#2#16#6'Height'#2#25#3'Top'#3 +#16#1#5'Width'#2'K'#7'Caption'#6#7'Preview'#7'OnClick'#7#16'PreviewBtn1Click' +#8'TabOrder'#2#1#0#0#0 ]); ���������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/batch.pas����������������������������������������������������������0000755�0001750�0001750�00000014372�11433537230�016001� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit batch; {$H+} interface uses {$IFNDEF UNIX} Windows, {$ELSE} lclintf,LCLType,LResources,BaseUnix, {$ENDIF} define_types; procedure BatchVOI; implementation uses Forms, //lclintf,LResources,{$IFNDEF Unix} Controls, {$ELSE}BaseUnix, LCLType,{$ENDIF} nifti_img, nifti_img_view, dialogs, nifti_hdr_view, text,sysutils,classes, fdr,batchstatselect; (*function LesionFrac (lOverlayNum: integer): double; var lLesionSum,lInten: double; lInc: integer; begin result := 0; if gMRIcroOverlay[lOverlayNum].ScrnBufferItems < 1 then exit; if gMRIcroOverlay[lOverlayNum].ScrnBufferItems <> gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems then exit; lLesionSum := 0; for lInc := 1 to gMRIcroOverlay[lOverlayNum].ScrnBufferItems do begin lInten := RawBGIntensity(lInc); if gMRIcroOverlay[lOverlayNum].ScrnBuffer[lInc] > 0 then lLesionSum := lLesionSum + lInten; end; //for each voxel result := lLesionSum; end;*) function VOIVol (lOverlayNum: integer): integer; var lInc,lVox: integer; begin result := 0; if gMRIcroOverlay[lOverlayNum].ScrnBufferItems < 1 then exit; if gMRIcroOverlay[lOverlayNum].ScrnBufferItems <> gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems then exit; lVox := 0; for lInc := 1 to gMRIcroOverlay[lOverlayNum].ScrnBufferItems do begin if gMRIcroOverlay[lOverlayNum].ScrnBuffer^[lInc] > 0 then inc(lVox); end; //for each voxel result := lVox; end; //VOIVol function VOIMean (lOverlayNum: integer): double; var lSum,lInten,lVol: double; lInc: integer; begin result := 0; lVol := VOIVol(lOverlayNum); if lVol < 1 then exit; lSum := 0; for lInc := 1 to gMRIcroOverlay[lOverlayNum].ScrnBufferItems do begin lInten := RawBGIntensity(lInc); //Next line - only voxels that are part of VOI if gMRIcroOverlay[lOverlayNum].ScrnBuffer^[lInc] > 0 then lSum := lSum + lInten; end; //for each voxel result := lSum/lVol; end; //VOIMean function VOIMeanFrac10pct (lOverlayNum: integer; lMax: boolean): double; //if lMax is true, return top 10pct, if false return bottom var lSum: double; lVox,lInc,l10pct: integer; lRA: singlep; begin //proc ShowDescript result := 0; if gMRIcroOverlay[lOverlayNum].ScrnBufferItems < 1 then exit; if gMRIcroOverlay[lOverlayNum].ScrnBufferItems <> gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems then exit; //first - count number of voxels in ROI lVox := 0; for lInc := 1 to gMRIcroOverlay[lOverlayNum].ScrnBufferItems do if gMRIcroOverlay[lOverlayNum].ScrnBuffer^[lInc] > 0 then inc(lVox); //next - get memory if lVox < 1 then exit; getmem(lRA,lVox * sizeof(single)); lVox := 0; for lInc := 1 to gMRIcroOverlay[lOverlayNum].ScrnBufferItems do if gMRIcroOverlay[lOverlayNum].ScrnBuffer^[lInc] > 0 then begin inc(lVox); lRA^[lVox] := RawBGIntensity(lInc); end; qsort(1, lVox,lRA); l10pct := round(lVox / 10); if l10pct < 1 then l10pct := 1; lSum := 0; if not lMax then begin //lower 10pct for lInc := 1 to l10pct do lSum := lSum + lRA^[lInc] end else begin //top 10pct for lInc := (lVox-l10pct+1) to lVox do lSum := lSum + lRA^[lInc]; end; result := lSum / l10pct; freemem(lRA); end; procedure BatchVOI; var lNumberofP,lP,lInc,lNumberofFiles,lLoop: integer; lFilename,lStr:string; lBGStrings : TStrings; begin for lInc := 1 to (knMaxOverlay-1) do FreeImgMemory(gMRIcroOverlay[lInc]); ImgForm.UpdateLayerMenu; lBGStrings := TStringList.Create; if (ssShift in KeyDataToShiftState(vk_Shift)) then begin GetFilesInDir(ExtractFileDir(HdrForm.OpenHdrDlg.Filename),lBGStrings) end else begin if not OpenDialogExecute(kImgFilter,'Select background images (stat maps)',true) then exit; lBGStrings.AddStrings(HdrForm.OpenHdrDlg.Files); end; lNumberofP:= lBGStrings.Count; if lNumberofP < 1 then begin lBGStrings.free; exit; end; if not OpenDialogExecute(kImgFilter,'Select overlay images (ROIs)',true) then exit; lNumberofFiles:= HdrForm.OpenHdrDlg.Files.Count; if lNumberofFiles < 1 then exit; TextForm.MemoT.Lines.Clear; lStr := 'Function'+kTextSep+'VOIname'+kTextSep+'VOIvol'; for lP := 1 to lNumberofP do lStr := lStr + kTextSep+(lBGStrings.Strings[lP-1]); TextForm.MemoT.lines.add(lStr); for lLoop := 1 to 3 do begin {if lLoop=3 then lStr := 'min10pct'+kSep+'Filename+'kSep+'Vol' else if lLoop=2 then lStr := 'max10pct'+Filename+'kSep+'Vol' else lStr := 'mean'+Filename+kSep'Vol';} for lInc:= 1 to lNumberofFiles do begin ImgForm.StatusLabel.Caption := inttostr(lInc)+'/'+inttostr(lNumberofFiles); IMgForm.refresh; if lLoop=3 then lStr := 'min10pct' else if lLoop=2 then lStr := 'max10pct' else lStr := 'mean'; lStr := lStr +kTextSep+ (HdrForm.OpenHdrDlg.Files[lInc-1]); for lP := 1 to lNumberofP do begin lFilename := lBGStrings.Strings[lP-1]; ImgForm.OpenAndDisplayImg(lFilename,True); lFilename := HdrForm.OpenHdrDlg.Files[lInc-1]; ImgForm.OverlayOpenCore ( lFilename, 2); if lP = 1 then lStr := lStr + kTextSep+ inttostr(VOIVol(2) ); if lLoop = 3 then lStr := lStr + kTextSep+ floattostr(VOIMeanFrac10Pct(2,false)) else if lLoop = 2 then lStr := lStr + kTextSep+ floattostr(VOIMeanFrac10Pct(2,true)) else lStr := lStr + kTextSep+ floattostr(VOIMean(2)); end; TextForm.MemoT.lines.add(lStr ); end; end;//lLoop FreeImgMemory(gMRIcroOverlay[2]); ImgForm.UpdateLayerMenu; //SaveDialog1.Filename := ExtractFileDirWithPathDelim(HdrForm.OpenHdrDlg.Files[0])+'desc.csv'; lBGStrings.Free; //ImgForm.SaveDialog1.Filename := ExtractFileDirWithPathDelim(gMRIcroOverlay[lOverlayNum].HdrFileName)+'desc.csv'; TextForm.Show; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/ReadFloat.lfm������������������������������������������������������0000755�0001750�0001750�00000002130�11450447710�016543� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object ReadFloatForm: TReadFloatForm Left = 335 Height = 95 Top = 308 Width = 465 HorzScrollBar.Page = 464 VertScrollBar.Page = 94 BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Real number required' ClientHeight = 95 ClientWidth = 465 Constraints.MaxHeight = 95 Constraints.MaxWidth = 465 Constraints.MinHeight = 95 Constraints.MinWidth = 465 Position = poScreenCenter LCLVersion = '0.9.29' object ReadFloatLabel: TLabel Left = 16 Height = 14 Top = 15 Width = 312 Alignment = taRightJustify AutoSize = False Caption = 'Enter a number' ParentColor = False end object OKBtn: TButton Left = 368 Height = 25 Top = 55 Width = 75 BorderSpacing.InnerBorder = 4 Caption = 'OK' OnClick = OKBtnClick TabOrder = 0 end object ReadFloatEdit: TFloatSpinEdit Left = 336 Height = 21 Top = 12 Width = 119 DecimalPlaces = 4 Increment = 1 MaxValue = 100000000 MinValue = -100000000 TabOrder = 1 Value = 0 end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/landmarks.lrs������������������������������������������������������0000755�0001750�0001750�00000003755�11450447434�016721� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TAnatForm','FORMDATA',[ 'TPF0'#9'TAnatForm'#8'AnatForm'#4'Left'#3#144#1#6'Height'#2#27#3'Top'#3'^'#2#5 +'Width'#3#182#1#11'BorderStyle'#7#8'bsDialog'#7'Caption'#6#9'Landmarks'#12'C' +'lientHeight'#2#27#11'ClientWidth'#3#182#1#21'Constraints.MaxHeight'#2#27#20 +'Constraints.MaxWidth'#3#182#1#21'Constraints.MinHeight'#2#27#20'Constraints' +'.MinWidth'#3#182#1#11'Font.Height'#2#245#9'Font.Name'#6#13'MS Sans Serif'#9 +'FormStyle'#7#11'fsStayOnTop'#8'Position'#7#14'poScreenCenter'#10'LCLVersion' +#6#6'0.9.29'#0#8'TToolBar'#8'ToolBar1'#4'Left'#2#0#6'Height'#2#29#3'Top'#2#0 +#5'Width'#3#182#1#12'ButtonHeight'#2#21#7'Caption'#6#8'ToolBar1'#9'Font.Name' +#6#13'MS Sans Serif'#10'ParentFont'#8#8'TabOrder'#2#0#0#12'TSpeedButton'#7'O' +'penBtn'#4'Left'#2#1#6'Height'#2#21#3'Top'#2#2#5'Width'#2'8'#7'Caption'#6#4 +'Open'#5'Color'#7#9'clBtnFace'#9'NumGlyphs'#2#0#7'OnClick'#7#12'OpenBtnClick' +#0#0#12'TSpeedButton'#7'SaveBtn'#4'Left'#2'9'#6'Height'#2#21#3'Top'#2#2#5'Wi' +'dth'#2'8'#7'Caption'#6#4'Save'#5'Color'#7#9'clBtnFace'#9'NumGlyphs'#2#0#7'O' +'nClick'#7#12'SaveBtnClick'#0#0#9'TComboBox'#9'ComboBox1'#4'Left'#2'q'#6'Hei' +'ght'#2#24#3'Top'#2#2#5'Width'#3#145#0#13'DropDownCount'#2#24#10'ItemHeight' +#2#16#8'OnChange'#7#15'ComboBox1Change'#5'Style'#7#14'csDropDownList'#8'TabO' +'rder'#2#0#0#0#12'TSpeedButton'#6'AddBtn'#4'Left'#3#2#1#6'Height'#2#21#3'Top' +#2#2#5'Width'#2'8'#7'Caption'#6#3'Add'#5'Color'#7#9'clBtnFace'#9'NumGlyphs'#2 +#0#7'OnClick'#7#11'AddBtnClick'#0#0#12'TSpeedButton'#9'UpdateBtn'#4'Left'#3 +':'#1#6'Height'#2#21#3'Top'#2#2#5'Width'#2'8'#7'Caption'#6#6'Update'#5'Color' +#7#9'clBtnFace'#9'NumGlyphs'#2#0#7'OnClick'#7#14'UpdateBtnClick'#0#0#12'TSpe' +'edButton'#9'DeleteBtn'#4'Left'#3'r'#1#6'Height'#2#21#3'Top'#2#2#5'Width'#2 +'8'#7'Caption'#6#6'Delete'#5'Color'#7#9'clBtnFace'#9'NumGlyphs'#2#0#7'OnClic' +'k'#7#14'DeleteBtnClick'#0#0#0#0 ]); �������������������mricron-0.20140804.1~dfsg.1.orig/prefs.lrs����������������������������������������������������������0000755�0001750�0001750�00000006311�12332435212�016042� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TPrefForm','FORMDATA',[ 'TPF0'#9'TPrefForm'#8'PrefForm'#4'Left'#3#164#3#6'Height'#3#200#1#3'Top'#3#200 +#0#5'Width'#3#137#1#13'ActiveControl'#7#12'ResliceCheck'#11'BorderIcons'#11 +#12'biSystemMenu'#0#11'BorderStyle'#7#8'bsDialog'#7'Caption'#6#11'Preference' +'s'#12'ClientHeight'#3#200#1#11'ClientWidth'#3#137#1#21'Constraints.MaxHeigh' +'t'#3#200#1#20'Constraints.MaxWidth'#3#137#1#21'Constraints.MinHeight'#3#200 +#1#20'Constraints.MinWidth'#3#137#1#8'OnCreate'#7#10'FormCreate'#6'OnShow'#7 +#8'FormShow'#8'Position'#7#14'poScreenCenter'#10'LCLVersion'#6#8'1.0.12.0'#0 +#9'TGroupBox'#9'GroupBox1'#4'Left'#2#8#6'Height'#3#24#1#3'Top'#2#8#5'Width'#3 +'p'#1#7'Caption'#6#13'Image Display'#12'ClientHeight'#3#2#1#11'ClientWidth'#3 +'h'#1#8'TabOrder'#2#0#0#6'TLabel'#6'Label1'#4'Left'#2'x'#6'Height'#2#17#3'To' +'p'#2'G'#5'Width'#3#190#0#7'Caption'#6#26'Maximum Dimension [Voxels]'#11'Par' +'entColor'#8#0#0#6'TLabel'#6'Label2'#4'Left'#2'x'#6'Height'#2#17#3'Top'#2'q' +#5'Width'#2'x'#7'Caption'#6#17'Rendering Threads'#11'ParentColor'#8#0#0#6'TL' +'abel'#6'Label3'#4'Left'#2'x'#6'Height'#2#17#3'Top'#3#145#0#5'Width'#3#161#0 +#7'Caption'#6#24'Decimal places Displayed'#11'ParentColor'#8#0#0#9'TCheckBox' +#12'ResliceCheck'#4'Left'#2#15#6'Height'#2#18#3'Top'#2#9#5'Width'#3#210#0#7 +'Caption'#6#28'Reorient images when loading'#7'OnClick'#7#17'ResliceCheckCli' +'ck'#8'TabOrder'#2#0#0#0#9'TSpinEdit'#10'MaxDimEdit'#4'Left'#2#14#6'Height'#2 +#16#3'Top'#2'@'#5'Width'#2'd'#8'MaxValue'#3#0#16#8'MinValue'#3#0#1#8'TabOrde' +'r'#2#1#5'Value'#3#0#1#0#0#9'TSpinEdit'#10'ThreadEdit'#4'Left'#2#14#6'Height' +#2#16#3'Top'#2'e'#5'Width'#2'd'#8'MaxValue'#3#0#16#8'MinValue'#2#1#8'TabOrde' +'r'#2#2#5'Value'#2#1#0#0#9'TSpinEdit'#10'SigDigEdit'#4'Left'#2#14#6'Height'#2 +#16#3'Top'#3#138#0#5'Width'#2'd'#8'MaxValue'#2' '#8'TabOrder'#2#3#0#0#9'TChe' +'ckBox'#10'OrthoCheck'#4'Left'#2'+'#6'Height'#2#18#3'Top'#2'%'#5'Width'#3#240 +#0#7'Caption'#6'"Rotate to nearest orthogonal angle'#8'TabOrder'#2#4#0#0#9'T' +'CheckBox'#14'SingleRowCheck'#4'Left'#2#15#6'Height'#2#18#3'Top'#3#208#0#5'W' +'idth'#3#174#0#7'Caption'#6#26'All slices on a single row'#8'TabOrder'#2#5#0 +#0#0#9'TGroupBox'#9'GroupBox2'#4'Left'#2#8#6'Height'#2'@'#3'Top'#3'('#1#5'Wi' +'dth'#3'p'#1#7'Caption'#6#7'Drawing'#12'ClientHeight'#2'*'#11'ClientWidth'#3 +'h'#1#8'TabOrder'#2#1#0#9'TCheckBox'#12'ThinPenCheck'#4'Left'#2#15#6'Height' +#2#18#3'Top'#2#16#5'Width'#2'K'#7'Caption'#6#8'Thin Pen'#8'TabOrder'#2#0#0#0 +#0#7'TButton'#5'OKBtn'#4'Left'#3'('#1#6'Height'#2#25#3'Top'#3#160#1#5'Width' +#2'K'#25'BorderSpacing.InnerBorder'#2#4#7'Caption'#6#2'OK'#7'OnClick'#7#10'O' +'KBtnClick'#8'TabOrder'#2#2#0#0#7'TButton'#9'CancelBtn'#4'Left'#3#192#0#6'He' +'ight'#2#25#3'Top'#3#160#1#5'Width'#2'K'#25'BorderSpacing.InnerBorder'#2#4#7 +'Caption'#6#6'Cancel'#7'OnClick'#7#14'CancelBtnClick'#8'TabOrder'#2#3#0#0#7 +'TButton'#7'XBarClr'#4'Left'#2#26#6'Height'#2#25#3'Top'#3#197#0#5'Width'#3 +#178#0#25'BorderSpacing.InnerBorder'#2#4#7'Caption'#6#22'Choose Cross-Bar Co' +'lor'#7'OnClick'#7#12'XBarClrClick'#8'TabOrder'#2#4#0#0#0 ]); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_lxall.bat���������������������������������������������������������0000755�0001750�0001750�00000000341�11070477134�016150� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� cd ~/mricron chmod 777 ./_qtscript.bat ./_qtscript.bat cd ~/qt zip -r mricronqt mricron mv mricronqt.zip .. cd ~/gtk1 zip -r mricronlx mricron mv mricronlx.zip .. cd ~/gtk2 zip -r mricronlx2 mricron mv mricronlx2.zip .. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/histoform.pas������������������������������������������������������0000755�0001750�0001750�00000004504�12147215554�016733� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit histoform; interface uses {$IFNDEF Unix} Windows,{$ENDIF} {$IFDEF FPC} LResources,{$ENDIF} Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus, ExtCtrls,ClipBrd; type { THistogramForm } THistogramForm = class(TForm) HistoPanel: TScrollBox; HistoImage: TImage; MainMenu1: TMainMenu; File1: TMenuItem; Edit1: TMenuItem; Copy1: TMenuItem; Saveasbitmap1: TMenuItem; Closewindow1: TMenuItem; procedure Copy1Click(Sender: TObject); procedure Closewindow1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Saveasbitmap1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var HistogramForm: THistogramForm; implementation {$IFNDEF FPC} {$R *.DFM} {$ENDIF} uses nifti_img; procedure THistogramForm.Copy1Click(Sender: TObject); {$IFDEF FPC} begin if (HistoImage.Picture.Graphic = nil) then begin //1420z Showmessage('You need to load an image before you can copy it to the clipboard.'); exit; end; HistoImage.Picture.Bitmap.SaveToClipboardFormat(2); end; {$ELSE} var MyFormat : Word; AData: THandle; APalette : HPalette; //For later versions of Delphi: APalette : THandle; begin if (HistoImage.Picture.Graphic = nil) then begin //1420z Showmessage('You need to load an image before you can copy it to the clipboard.'); exit; end; HistoImage.Picture.SaveToClipBoardFormat(MyFormat,AData,APalette); ClipBoard.SetAsHandle(MyFormat,AData) end; {$ENDIF} procedure THistogramForm.Closewindow1Click(Sender: TObject); begin HistogramForm.Close; end; procedure THistogramForm.FormCreate(Sender: TObject); begin {$IFDEF Darwin} {$IFNDEF LCLgtk} //only for Carbon compile Copy1.ShortCut := ShortCut(Word('C'), [ssMeta]); Saveasbitmap1.ShortCut := ShortCut(Word('S'), [ssMeta]); Closewindow1.ShortCut := ShortCut(Word('W'), [ssMeta]); {$ENDIF} {$ENDIF} end; procedure THistogramForm.Saveasbitmap1Click(Sender: TObject); begin {$IFNDEF FPC} SaveImgAsPNGBMP (HistoImage); {$ELSE} SaveImgAsPNGBMP (HistoImage); {$ENDIF} end; {$IFDEF FPC} initialization {$I histoform.lrs} {$ENDIF} end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_gtall64.bat�������������������������������������������������������0000755�0001750�0001750�00000000212�11423327412�016301� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� cd ~/mricron chmod 777 ./_gtscript.bat ./_gtscript.bat cd ~/gtk1 zip -r mricronlx641 mricron cd ~/gtk2 zip -r mricronlx642 mricron ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/landmarks.lfm������������������������������������������������������0000755�0001750�0001750�00000003666�11450447434�016700� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object AnatForm: TAnatForm Left = 400 Height = 27 Top = 606 Width = 438 BorderStyle = bsDialog Caption = 'Landmarks' ClientHeight = 27 ClientWidth = 438 Constraints.MaxHeight = 27 Constraints.MaxWidth = 438 Constraints.MinHeight = 27 Constraints.MinWidth = 438 Font.Height = -11 Font.Name = 'MS Sans Serif' FormStyle = fsStayOnTop Position = poScreenCenter LCLVersion = '0.9.29' object ToolBar1: TToolBar Left = 0 Height = 29 Top = 0 Width = 438 ButtonHeight = 21 Caption = 'ToolBar1' Font.Name = 'MS Sans Serif' ParentFont = False TabOrder = 0 object OpenBtn: TSpeedButton Left = 1 Height = 21 Top = 2 Width = 56 Caption = 'Open' Color = clBtnFace NumGlyphs = 0 OnClick = OpenBtnClick end object SaveBtn: TSpeedButton Left = 57 Height = 21 Top = 2 Width = 56 Caption = 'Save' Color = clBtnFace NumGlyphs = 0 OnClick = SaveBtnClick end object ComboBox1: TComboBox Left = 113 Height = 24 Top = 2 Width = 145 DropDownCount = 24 ItemHeight = 16 OnChange = ComboBox1Change Style = csDropDownList TabOrder = 0 end object AddBtn: TSpeedButton Left = 258 Height = 21 Top = 2 Width = 56 Caption = 'Add' Color = clBtnFace NumGlyphs = 0 OnClick = AddBtnClick end object UpdateBtn: TSpeedButton Left = 314 Height = 21 Top = 2 Width = 56 Caption = 'Update' Color = clBtnFace NumGlyphs = 0 OnClick = UpdateBtnClick end object DeleteBtn: TSpeedButton Left = 370 Height = 21 Top = 2 Width = 56 Caption = 'Delete' Color = clBtnFace NumGlyphs = 0 OnClick = DeleteBtnClick end end end ��������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/���������������������������������������������������������������0000755�0001750�0001750�00000000000�12413465015�014764� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/colorbar.bmp���������������������������������������������������0000755�0001750�0001750�00000001626�10673034556�017307� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM������6���(������ ���������`������������������������������������������������������������������������  #(,16 9##:%%:'':)):++:--:00���������������,D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/zcolor.png�����������������������������������������������������0000755�0001750�0001750�00000000300�11034464770�017003� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR������ ���R"���IDATx10 EС0t 8O0p0T |Y7|["C4uݗ~ eLJP f6� A߀Z{z{Nd&j&3KRUTыľlA *mu����IENDB`��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/magichat.png���������������������������������������������������0000755�0001750�0001750�00000001560�11036747464�017267� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������W���sBIT|d��� pHYs��h��hH���tEXtSoftware�www.inkscape.org<��IDAT8MhTW{LgbQ1 fdh TR2(Jt],qc;RBE..Z(O)NL2:抉Ο{OvBѤgs}f𕃫iZkLV9"Աߴ&"QG Q *.|2Ǐ_J&}&?D`mGYz;&PDQVR\]8NttZQg;_Y?4n'ٰ1u ڌ\57wh]|YQYAD7QD%*cz;H0>z= Vf#8qЊU/~ /@DẂ:Mˠa ob) ;3'ONۛxƌ\G_:=䔅HPxI$y"д~0�|>k01?Q*<)#p⭘rdCcJ< רM`37]çYu5`BѢG9O YՌ"*Q,gq@&=0<V} Ƶ_#]x>oga9rel@{L mm AH7EQtŦƍEDGimU\p4۶U"*!QkWnjLOٳw(M}KDsvXl6z�<xNZК+ iEj[ٲ*.<m�?7Q��!~,&wf����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/roi3d.bmp������������������������������������������������������0000755�0001750�0001750�00000003366�10673035102�016513� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM������6���(�����������������������������������������������������������������������������������������������̺Вyyppxxڷ��������������������������zz++����������),y|������������������̑�������������� '/>������������dd��������������("6)A,G-Ir��������``���������������� )%=0M8Z=b>d;_s���������������������� "$91O=bHrN}PLyCk���������������������� ,+E:]HsU_a[O~Jo��oo��������J��0��,��@��w��LL%L,L2M'>[2PFoGq~��$$����0�������V��i�� ����� ���������������������� 4yHe����|��d��x������~��������k  ������ KxP2P��������#9����������������=�������� ������IuPQ &������m������������1������������������:]?e@g 4������ e��������������q�������W�����������*C.J+F������ ������E��"��7������ ������������������ }n#�������� 䥥��������������������y����������������������������6�``� �#�2�-�&� �����������������������������PP��W�T�R�P�N�L�J�:���������������������������h�f�d�b�`�^�\�Z�W�0������������'�8�@\{����;�x�u�s�q�o�l�k�i�U�'�$�.�A�V�Z�X�V1n��������:�������|�z�x�v�t�q�o�m�k1~������������b�����������Z����������������̪F�������B������������������������χ]F;DZݹ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/render.png�����������������������������������������������������0000755�0001750�0001750�00000007351�11041224066�016755� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���@���@���iq���sBIT|d��� pHYs�� �� bL���tEXtSoftware�www.inkscape.org<��fIDATx{T?{`df; W/\ x!hZ9/5R+uug{쭎fj%3z17 TDQAqa&e⬕ߵo}/oR[ t7 wnݍ߼�F%BD7\RV\,u:@1 <ۑ(@6H)R-%!l[jw\]Q(lBkP*U89pFUUWJ\$p8 �ҥ&m'��VGtx{Ӆao?hS͛S`ܭ&[SS׮? 6v er|6zO-Ҁ)e]@'�! `NB mK((5kM6.#G6PLL4HNS!;{guRfk RʛiGB,^z V>!o^^}l:](eehjjD1Ke]xz#! KHNN*S\ BwkSBhw)B(HJZĉk,aĮ](+;Mhh+:\szT*5*{{ *ڝ0zB ӗ/=EBR}]. 8h<INDh6{싃Y/*taD*jk뫩>CA>dAA>|))\TΝ/BSRJ!@ߠax{l۶c޼SZo׻( ?g ={:ˆj/~ѣ{sdd|3f:Ovuu7� BٷkWBGS W<V_Qqgk# O1`$p1 IiN'Sײre6W!5u9Bc3 BkmBarzz'>^kS[[ͮ]+Y:/ǘ5]Z�C,f \pܢ^GGWގ`rLz^{w`,QR "]qO0ҏvugtjwwreBryCf=g?g5ۢҞ=]q!!c{7M6!̘/F^HG !FMBR…{qv554Աmb֭{GyIrʔWNqq=*jǏ[ pWVDEM#B0}߸ާҼ'1C!\1LwLᦴWϲv=dgSO}ĉk-DEM&5Y3{߾qgRSSifwppn޽AEEG,ҦN]Kxx"zz@܍ ,pttg*`.L'O4CP*U>JFoz֎>}bx;fM(6<L^̚q*~H1e^ �Sݘ=MvJã7))88X+'r揄2Uް{9vCNQbcdݺ)D#덮o5/[B~w~OSS#))fk}k0nSfS7�œNMmmUe<$<=lZUDEMb)DD$O$oexB6瞒1'Od]Ӡ57''o >3c()1S@ՙ5 1q%dfn !)cҢ�Bs�&hZd%'܂"݃)/?c_Ji0�^JT$? So@w`fӋgOgƏ_iB�WqtyoXRiocm'K L6¬!\C=;L"3s+gS_w{ kJkhETPWWCeE3^6ͣzBצ&G !z(�@7IoVJٰa:/8E(,Lg5>/nzK݃R\if@X%@m **ptt?as�vo63blakkǕ+IeGy/rrR?~)R6!9s^G|8:9`֛""&o 0rdr[ C>BF7Kh<5˰8>cǶ/bOAf=$"n5^:kWV\qwp#bcq|v#Pчy챝EM{O~WzcN`0{u-r'S1a³|"jڕGvg'Y: ${>/LLG#McVĂaY$&.֎;*m&O~K.\{o&=RiϥK`9-QMW,rlm3g3+VŠDD$QYYoOD$gg_-ygp�Jo LZj]+*J^Q\QZz.K0mMt��̜6vv,\''N.{@�g5+`ؚv% ɌSزe!օ|Xh/J=ř\rM߆Z.(8`=h!kU ~~фeϞ7=ڝ_EEGyZT* UU唔ds!v=b7m{7*� `rd},Xގ3G_@Rr`I[bŊ`DEE1MM88z JbRX^YYV x \ODDRsF?Ν)/Dbbѿw$c'’%_P;dkhjjCQaws! PddDZZKhV تM8&4h]gcc=kքR^snh׮Uy JJyt>90;&w BB` 1;Y(}ZƆ x;� 'jhpqg^JTH�J)3BVN5_/66=ya@Rdq(1M6:{B$$b׷?qq) _ڋv 0< _X^3v!4v!)!0x*aa̘=EKXp-? t)1~`!0FXxd$elYW_`k.D(�æ+..#\ٿcX'YB!�ùAJ{ zDBBƢX%,)·nhI)?Rn&LȔk�jn455P\2DJ)7v9ň$�c[ >ޒR^Ex'd9L 6_ @wnݍt7]@w�MqW&YkF����IENDB`���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/�����������������������������������������������������������0000755�0001750�0001750�00000000000�12413465015�015555� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/bucket24x.png����������������������������������������������0000755�0001750�0001750�00000002160�11040141402�020062� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������|fu���sBIT|d��� pHYs����.���tEXtSoftware�www.inkscape.org<��IDATH}LUuǿ{q 1b͚*5@j QZ?sla5\!^Z ZR8S, zy\ s۞=s=I,u ¾ )%Fs1_ gg[nlcTT>آqK�mL5/R\<V.U~]PŘՏm[\ٿ鈣]}% Prt{;G1,, RtK(N xV^IeXbݭ |"Ыa3G .j\=G |`%s_O,X< XQ=k29M 2[evhC:7ӽ{`QW;XfWFe(.#${6ЇX.N}^*1Cޖ84v~ Ȋɀ, e@T\op ��~A ScO [)4 ͷ̦0"JDEZ= Q32U=磧rx;]lUHH=hЖ`NB Xي|,i�V fCYa!첥ѨV4b9e{nn1YtD‚jj05k6xC<4;^l(tvwsmpjZ,_1[_>YWC_Ĺ:RFc_ihw얻�<jSZms[Zڕ&yiPf.pa SoJ(g7*<s}/{C/' .Ќޔ#W'CBu&q^>=p��,N =zˤ9:&0i#˴?ρmp�5 u2�`| "-VNIg�N���Zm/^�&GsV5.A����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/ellipse.png������������������������������������������������0000755�0001750�0001750�00000001423�11040141570�017713� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������}\���sBIT|d��� pHYs����g���tEXtSoftware�www.inkscape.org<��IDATHMHQ3M#ڟ4iaRH)\ nZL.U-U.A -DZHXXh"߷|3|L#8}ν$QP5�U. Su3CKXY6`h泡)0mIl!W"Wz&zs'0R5 Qua9Qip֍p (ve BE1 .Ng(/# ʝE>df[Vνz} 1+ϐ}dst V=$%~ .ڴ &˪ȇY%pԇmuŃ55ѥ4"CӤzt2bE4Ms$x "y8kWO :\ bV節Ml$.96Gf] &lx4 8oЈRkbVW^ZrL,26>%N u eo[n, NAl/Ć!͹8ib`UpU!,<"3*-$+(o8+%\D!A\pǹ "$m2-x r F'\u40 56J (`vADPZZ$׷MʿQ *e#����IENDB`���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/refresh.png������������������������������������������������0000755�0001750�0001750�00000001273�11040143240�017713� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������!-���sBIT|d��� pHYs��h��hH���tEXtSoftware�www.inkscape.org<��8IDATHOKas[rBmF.�n\~PD/ I-51ZUࢽHhS.31b8̽a<qXuMADx.< }rJ&LKœpU aC Ra7 5ᄰ#Q ;ԅyᛰ 3%l[BҘ�څiᓰ%BW.oXX.!%̖:_˪pCX-|2;GBK:8ws$ �Vbk@4U`2 ;%T:ZA_rwW*9޺L8'^KU+p.$ǎv< <"7nT!+7*Ra2 .wC: xk[l//#ٍlV9%TPue5ZBp_/Cφl([sy][ <-7TӷKH6$f"n:3FmNtj7~y#Y4sztnO4I-$}5p*2iC}b&+����IENDB`�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/colorbarzero.png�������������������������������������������0000755�0001750�0001750�00000001200�11040221744�020754� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR������������sBIT|d��� pHYs��w��w`(���tEXtSoftware�www.inkscape.org<��IDAT8kSQ&/%$CG`tpP`N($(tҡ:H b'I^>{=HIļnFDM|lIZT. rQ6[^!(NpH&Ljrlh䤵b֝\ځj)B"$#m0?f{G�r~O>V<= r"e xl0 ,|8oWAΫ?"r5QU1os]ODb4)Cq(=ஈ,|H$D~u'wb{ ^Ow` 5`*#$4j4z 6ju1P= hY0mE @�, ܞH?<N+] X@�q%_ 7B"-�C:'R/ǁo6w`|5-KEt�J@_"����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/magichat.png�����������������������������������������������0000755�0001750�0001750�00000001747�11040222056�020043� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������} ���sBIT|d��� pHYs����{Rk���tEXtSoftware�www.inkscape.org<��dIDAT8]HWo6ju-&sRn-NCǠ4lBWJcб1(]즔F D B[jiZ]j4VsΛsvSCtϟᠵf{Ǒy7KlԠщ?u68nzaix̍Bٜvo!wF:Ck'H$=Z)]j|ŷ3gwh)B(i5p9=wGVo}.?{n.t8).WZ͆5CR76j̤5ٶb.B18f*0KXEp^+;+ei@Eggm ߨu, )v6Ǐfk(~.vlYlJ$vhGHeip yPX^c :9x'OHi4`j|EZk;"B<t=BZ`j< pp굽S'@ou>zT\TUMy<] G"Q Pm�_~.RZ{F p82�8\"ui1/u5IZ'6[ڒ(+[v+ ŤtmR)4B*Pexvh$%'9vυ �M!ՐM)MJ_~uǏ\ah,XZ*}~5?'Q*+gZv<e0}J.]:r@fՏ6MnRUZ%4"O߿z# i����IENDB`�������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/hires.png��������������������������������������������������0000755�0001750�0001750�00000001032�11036747300�017374� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������}\���sBIT|d��� pHYs����Y���tEXtSoftware�www.inkscape.org<��IDATH?HQsE,K;%XZ!bl[jaW(;@!pvD,,Qgw8߃) >qI$L/TA2 Sp3Mw g9j]RvJ|ì' 7@�z]^FHVW`)% t4A1AƨrÀj|D/&_Nlc&@$J).^fbr ]|#7IeC)rw 0fDll޳Z=&-N9&80PA{ 7~λ=륺NIf9`sjicfewa &߃xZӜ(: @Jk30~�tYGPиQ����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/hires16winz.PNG��������������������������������������������0000755�0001750�0001750�00000000437�11062647144�020327� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������}\���sRGB����gAMA�� a��� cHRM��z&���������u0��`��:��pQ<���IDATHK; 6!M>`&6 l(W&q8/J�fǼ8mL�� OeHĊH%:�u�ɶ S^v(zUyW1ɮfeMLu�Ha8IYG��Mc����IENDB`���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/hires16win.PNG���������������������������������������������0000755�0001750�0001750�00000000437�11062647126�020135� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������}\���sRGB����gAMA�� a��� cHRM��z&���������u0��`��:��pQ<���IDATHKUA ×;_Op!]7663iv38ss.mt[# (A,yϻQJڔ?rY@%r&ߎRĐG"_٨)S"|VDf~h+NdS?` ߾ z\NLq";P qEH����IENDB`���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/hires256.png�����������������������������������������������0000755�0001750�0001750�00000002267�11062646710�017646� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR������������PLTE������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tRNS����� pHYs����=f���QIDATxcN00Q%Q$ő%̇Kb0`3*i>D.7"n/_Ԕi9n wDZ {�KH����IENDB`�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/hires16b.png�����������������������������������������������0000755�0001750�0001750�00000000362�11062646436�017721� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������(SA���0PLTE���������������������L=���tRNS��lQR��� pHYs����=f���LIDATxڍ1� :N'U0t 44r � .!(#3Ahc ͓~-Z/gZ&1#����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/hat.png����������������������������������������������������0000755�0001750�0001750�00000001574�11036743466�017062� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������;~���sBIT|d��� pHYs��J��J}<���tEXtSoftware�www.inkscape.org<��IDAT8mHTYƟsqt3hҰ4B,C!P}\>}7X v,,YF!lRbIwl{{{8ϏyCJ|hzSAl SP0$4(,{/5-$|SU[m{ <s&MY18<1A.idž'<H8蛎¶BeULS  B7KX]u%KjA_FscpWa,aa5eG[f")1~YzxtJst��X?_t-H ,5"'@Ϣ@%  ]CMf>qXZeW`rV 8Oƹ7RImW5}YuTt3 i/ݫ)|L!eN@�0)%Tre swMID RmLoX1}xg=v rM} ) Ld/=cCާ|֒YEo! :XQW490lHh:f�~lj3L7wl B$8 g|F%tl]k`cҕ }D}\٪y˶V-˭:f lO\5 Qi̸Fg,{B`w i4I% yvN3PM#, @0(�n6fG-H&~����IENDB`������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/autocontrast.png�������������������������������������������0000755�0001750�0001750�00000002507�11040140634�021010� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������!-���sBIT|d��� pHYs��n��nKc���tEXtSoftware�www.inkscape.org<��IDATH]lSeue,Jڍ|,($3Fw(\l7\bY"\Hlun0|F?OyRլ;AղtZZ<n]W AEa6<6׊R|i&pP0qfz{zb-P9,ԩдEifff_{R=w[օ=^D8 !gc;}dƍLL˪۷z~w ؟Wv!@(PJE =z{|:>[_|sppp޽zhd3@& ,5J"nߞ|w} 7|,jfR{ 4GTUXX07 ì,�BkΝ8qL<8ԛ% Y(5$u a_|X*Qr\:; A,20L;p8祐|llq�IV 2(5@S]Wkd22x͛7X]Z\i ,!$I,WG$@Ou] |¶pM8/mfVMCmJz8�BHq\ڵ ^IM&Ʋl+!Wu<׎D[uR&x6<d^4-ͦyM,ص3 ςoPFB-P+Ei*f+f+!0 YΣ\.0L8~gddd,^2‡L2tkޗ@4aX (HRV+Cgꬳs-FwS 4睰l} xk׶u]'?Ϟ={'J5.߇n@l<pZ8^ �nݺСCf`6 4+%@A]WAJ)xKݻ7�ʖf"FHeRQ@!Yx-Tjv(f%v=55e<OpîvWECDBXtvdRHdO">?kk[G h4# 6mȑ#\~( Ei,Gݟ07c5鯤y:y<nd2Ar˔G1,o(����IENDB`�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/3dx.png����������������������������������������������������0000755�0001750�0001750�00000001765�11036743332�016776� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������!-���sBIT|d��� pHYs����>���tEXtSoftware�www.inkscape.org<��rIDATH[h\U}23[h&!)$F xV)Dh JՇ %>+"$m PP ؗXLRbMf\L?{fu{?Hg̘P` *>gX?$LWPUD� �w?<{|7xeF[6okf?o#qp7LuY~׻S%E}7Pzi<&/pML4~F˪ܱT�AXllh58h1my*vs|4k97V+6( YwQv't<Y: ~~}^bgucњig#W<= ,Aj,R$(9*AA[G=}lJzhLS~[/[8 <,iR ?�UXd9K7?*5[z3Iu3pL:jڋ6,`  SJ_A$qNíBɧ?!8z =$H3Lg9izmd[*f]9KɋHo^w;٘%Y5`-`X'R4QHE1(]iknk4)W`0]VAD Q` {eۢx4[˜r/fVxvJm@@ ;,oǘ9;J燀l5]uTjs|f"pv?>7^cJ WRgBD0/6^ri)ryGiu& LYTj7zIplug����IENDB`�����������mricron-0.20140804.1~dfsg.1.orig/btn/new/hires16.png������������������������������������������������0000755�0001750�0001750�00000000365�11062645732�017560� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������(SA���0PLTE���������������������{���tRNS�#]��� pHYs����=f���OIDATxڍ� CTir(3G$ t{%h()$e!$BH~pI^V1tDϑ Y;����IENDB`���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/autoclose24.png��������������������������������������������0000755�0001750�0001750�00000001541�11040222210�020412� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR��������� K���sBIT|d��� pHYs����`Z���tEXtSoftware�www.inkscape.org<��IDATHMeϹ3ej G[  HZ4"M07lmZ J+*t3Q-4Ž)9p<y_=y"3-70KRG$z/: ӂMȬU+<+(jcVx�W7[B~f/!CD  Z6f~sK8Ϋq "VW7*̏5"N!b ["Ss^v-E4pwcT)sTfGE(ccggG.p<F2eU"zJMM;GFǧ~9|;N/4݀[kZ[̛,.8S`9)DC\"^-͸n޼u/Lj?Xk\*SjuL̼l۱uΧsLL\�?\ M fAb%d~[,;0>~ꦽR-˵8S % Aσl(U;2Em8 }`l˝t#= 2SCgE?ɍyq`e65e2{ TbЋjIS1W24Ȓ%T*WW?e GjXVL7ۺu0:m펵0mXT,G8TՖJ'$j&{2Ŕ?py&u~~)z`6:ڍ����IENDB`���������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/hires256b.png����������������������������������������������0000755�0001750�0001750�00000002267�11062646754�020020� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR������������PLTE������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tRNS����� pHYs����=f���QIDATxcN00Q%Q$ő%̇Kb0`3*i>D.7"`褪Nq;q @# wb�����IENDB`�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/hires.bmp��������������������������������������������������0000755�0001750�0001750�00000000576�11062645646�017413� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM~������v���(����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/hires16lx.png����������������������������������������������0000755�0001750�0001750�00000000324�11062622440�020106� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������}\���sBIT|d���IDATHՕK D<]I)qQT@PmwăM@9[Q^ -"6Ȟۨ(�Plzkl&\Hhq<Mu?cf EM<$= @EkB.B""����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/crosshairs.png���������������������������������������������0000755�0001750�0001750�00000000611�11040222134�020430� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������|fu���sBIT|d��� pHYs��+��+к���tEXtSoftware�www.inkscape.org<��IDATHԯKQ[TDP   &f8%٢d ƥ2eDd=WQ6o_"+vd.ן|k[E_ >}x L}!  ǎ\={ یs+QWb |7ѿ+XHD!,V=$rzya}}hus3Q8[O ><)cT`GeO$#'my����IENDB`�����������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/pen24.png��������������������������������������������������0000755�0001750�0001750�00000001334�11036745410�017217� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR��������� K���sBIT|d��� pHYs����`Z���tEXtSoftware�www.inkscape.org<��YIDATHOUi|XQE`B;ݣڦE+VLv\H pYJHQ6.ZGPg9kޓ9pss=TVq=s{b[xo+_Vәufx9>.&Tkzj]x pn/U_dNfo0Dv+ظr~?WtO*∈keX}nld 񂈳"\ް}ҵʜ~,ἈGAG؃Wu*j@eفgq#b5@D|!᱑0#" aK9lqq>"G2︇ư_3'g؍2/: v:yAP؋ՠwWo)I<9yO9x}Uo6}ԗ+F/vfI'�e 1U}Ͷnei N쯇#r OTCNn^gvhc\6<(9~+5p2Ut6>9l-SGlw̬_pWn|r4Ǯt����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/colorbar.png�����������������������������������������������0000755�0001750�0001750�00000000615�11036743550�020076� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR������ ���?���sBIT|d��� pHYs����I���tEXtSoftware�www.inkscape.org<�� IDAT(jAEό3댎ƘmK& |B HM@Dmt`7N Y,epmm#�0B{ \Rj\g C2o?,Iҹ:r60kyYo:}M $֘E-My<WD)P q8sk^<I`QL&;HVYQ2eYZ B8:J/:H`Sn%k(egZI.ϲR?~u|����IENDB`�������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/new/bucket24.png�����������������������������������������������0000755�0001750�0001750�00000002522�11036746124�017715� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������w=���sBIT|d��� pHYs��[��[���tEXtSoftware�www.inkscape.org<��IDATHۋ[U}$$ssv8vj:UꋢE> /^AE_D"*( HZJE+jg2M&ɥ99C'i& oZx@ 2`v0mXdlԶǛ0g8xKmҲ"P/ 4YiOr1l 2j̈́^?|Yӟ,z8l?Fp0X.GAkEDmM০D aezfW Ͽ~兵 fݐcqb|#SGGo.~jjɇ_,i?Iz>0˷}^ٝzHu{Bk*kz>4uɫ1Z\\7Wv|DS_R)1͙p$sw>[&ԈFPr~o%4>k)UY7IzgȩYٻ"-ٜ|zbtz㧢I{>QWhI[GƜa2f2a\^i?y `POX,` XoKjޒ!R3AОX5<ZzJ񗴖L~i\sڋXX 6>[ � H;@T5:5܇ l: 6L[ պ�i4 uAa=酹0\^ˈ6-=9cpעtR7`"n躵PX1=@ Kiuc3Njs2\a'@כZ3y"B`H˶HgmD).<FW6 z}0{#d2c 6⺔iH�ץ)["[vj,iUfA3tw@DDVs7&>`-ܖ2zLVeJtXPnIl_j/\+6b4݀/@ϾLO)?;WkeBڰXJ`s9\cdm͝6 ˃%Vt!ȥ$F\ 54[~0 # dbh lhaO㐟͛Dݢ~)Na3'NiKvF� 8(%ϣ$:X<I'Z#*^W[t֎$]FZV7G<Ɓ{E! j,0:TCZ2J>lenX>t����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/autocon.bmp����������������������������������������������������0000755�0001750�0001750�00000003366�10673034450�017150� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM������6���(�������������������������������������������������˺xxx����������������������������yyyZZZ}}}֨TTT444��������������������ˊ\\\;00��������������aaa:##K--Q00K//zz����������[[[򻡡d<<|JJOOyIIa;;uu��������tttơQQeemmccOO[88������vvv̡^^yy㉉vv[[h??F11����]]]̡]]vvڃssYYf>>9##okk��oooa`ġMM__ff]]|KKT33*ǍЈ]\pFEzyǼ¹ww[77pDDxHHnBBW558!! gggչ`_USxKJiBA[98L0/=&&"'3@&&E))?&&- ��~~~ZZZҦmkbaYXPOqGFb==T44E+*'    ���������lllZZZϚqohf^]UTyLKjCB\99M0/0! ������������������lllhhhӨlkcbZXQOrGFc>=T547"") ���������������~~~ڼji_^pok^^" ������������nnnϣkj* ��������������b``ǧ1# ������ggg����~~9$#+  ������ϫI--M//R21V44M..@((��������ʙ~~߯֩ZZUUOOyIIh??xqq����������ɪל⤤jiee``SS~~��������������˽Ȋꢢwwrqii��������������������ǧҒ敕֋����������������������������Ͷʫʨó������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/roifill.bmp����������������������������������������������������0000755�0001750�0001750�00000003366�10673035150�017136� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM������6���(�����������������������������������������Ͳқؐڅ||߁މܒڧ��������������̭yyFF������������������--ww����������..��������������������������������BB������������������������������������PPꢢ����������]]��''66CCQQ__llぁޜ׷Ш___������������--������������iiiF56u[\977����������99����������������ˡ500mnܳA89����55``��������������]]]P99ࡢOFF����vv����������˖5--rs:67��rr��}}��������QQQ`@@非ŶHHHII��pp����ʉ8++vvYUVNN��JJ��GEEpFF󲮰ccc hhi@@ONȌ11 $9mnxuwrrr����76< {^CF򦢤NNN��������jjjRP����6)7૬878����������766Ŀ����' 9ശ766��������������EDC����*#:KIJ������������������RPO����;3>sopvvv����������������������TRQ���� sgiRRR������������������������DBA����XȾ:::����������������������������655vs/.TPQ756��������������������������������TTTUSR ������������������������������������˪^^^EEE��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/pastedpic_08032008_133503.png����������������������������������0000755�0001750�0001750�00000137212�11045404150�021252� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������>���sBIT|d�� �IDATx}Y\qmzYHWɒ(K`YP"# #!F�s<'y`#mBlP"-uOOOSZH(9 U:u> ELNNn�L&:L&z*>zV+:F#f3:l6b`@AC>GA޽)?oƥaNMM!H`nnfh4t:V4M d2j! l6l6#`~~V {{{CXhD0D^h^Vrlll|KѣGaXpZ-L& CEXVyz=4 a8NuX, �#ojِfa0:L&6�hwm44 V`0��, t]f- hZ(JvڧVaNMM!j"H��*Z:F#j\.<�n7"áS>p8fC݆0zFuT 8%#öV9Npd2!Nc}}FfFG_c+++p:D"0�Fp8��p\zzATf VT*z2j~j͛71;; łF˅L&C4Mx^ 4MeLLL@4 f\.n CϣZ"JX,\.ʕ+?70qIvJ%~Z-dY4M982$.j\t:h6t:T*HRZh4@:F^ǣ> Պl6n ׋pMtp8rP,h4h4PTi^/>&&''%nf}TU}ZKPX<qt] jrrdF>(B` \,lvH;;;`0\.ǃeb1LOOc0T*Z�d6 rjvjt:zhZp\�~&XGV6VWW΂?70?!�vf �F`yboonW`upݘjj!._rQa} C1B�Պ%D"~ t] łv ]t:q]L&F\zfj& v]0i8F*BF:ƛoPa]1y$IaT*z=yiz^/.\.N> ˅V- ,,,`oo?Ʋߓ'O7X,�FtuuBc355]177]nQ*PP*P,iw"L&7e?j׋-b4M6tP(`y!7I9rvB t:8NX,t: #`cc3G  CTjE$hh4 D u: l6Z6FP@Fry �'&&FaxJdFInݺb�(bC2|>w"Jᾨ|} 󘜜l?T*g}nJ( bX,xHdѣp8(J(˨뒰z=e�lH:f�l6f3Zf3V+:V+ádLz8w 077M099 ÁfT*[n�f& ~_>o}}?>^I|099 +aD`hhD<SO=^7o�  xqMܽ{xGEՂbD0ljMBRAݖr#yO� N'ZZd~_DVi(JV0 (0vaqR)8N,//cbbSSSXXXP,+jJ⵾ 3e 8z(&&&nnvd`لxvqEܾ}=N'.]7|SBѣGqqL& ɞ,6771h6p\B״Z-t]XVmh&pn Áv   ǃNz=z=ft] Wd$a:{9| _fC>Gل˗j$GQY \xS{>9bS(n%8uT*W^y=h4"bqq̙3p8D>v-C,^nj�ZTl* Z/充} 4X�pzBse4 x<x^R)R)r9t]mLMM!  H`jj ]mt:x<躎P(^U?}/>.#ioocnnN& N|& & l pz~H8\[[CTOEj58qx".^mymHvQ9n4M!2 jd. NJ�zh4*e~bT*j5 E<`@T:rP*ڵky(, v;8$"4MC&A\4!HJYL旇B!;wX nnWBFF8?Ʉ'{,c0==n iq%^cgg H$BB &fP*iB\MPT`6zt:u^On^�z]~.Ns2X,Rzp:�F?G?w8x<x' qUT*Z-A$ A\ta}}j3g$Zxtχg/~wyGClll byyPh6D"p\ǵkװ eqarr ^/�Va8  p5p8vp�FU~`�MӠil6|>PMh4 911H$"T*W_l" aaa>Z BAp8x^TUjOקbxϟEF^ h4Ff?=\rfǏꇕۍ`۷ocwwRG}@�VU$k VKRL&#F-4*w#Ul6Cn:){ln7\.fFCBhڹjG  l6cuu/^իW"f <""r� "%]s=]Eft`6qY<0 qz}+8~8 an%fh4d2c5j�H&u]ʓNS0$p^A0t:zlu]Zbۅbqfjl6gR(BC&4 Oanbi㘚,zd2h4GPRu],t]Ia Fvww�?y[Bxg{<na4M\zZM)ÁrD"Lhpl6Kx`XM&Kn\. MH4f&Z$Ylbf ш` ,j"N۷fK$F�\.'#`0ۍh z/} HDr, 3 bmm ."z-T*\px\a"E:>"B :x<  Cf}#- f3*f3~uC|dlVbh4Jt #رn{FISs^oj5t]|>R)p`qqX,Hrh۰�QN}C3c~~~_D c?<8_[n?VWW199GyO42PJކbԔT4MljF$j6Řz }M䶦i�F`0`0FfRvP%ńi8nWlǬ]Ν;Eu{d2FZh `ffflaŇ^0Ϟ=ӧOh4@v8brr`0~_Bd=k׮RjbuuUJwx\C(0BAIU?lAuz= z|>/ r0~IS-p8Fx"j G- "}cna[,߸q0 A"@$`&a4d}7̹9<0"- XYY%f˿ ^}Uh48wh4$ $_&,E}X8T*)n 4dz^PM&6jdNS �&v;|>dܺ�:Hȃ6zMEdۡlUT*躎SN!LhVX,b0`bbB@ X.\�Ӊl6bFx<??F +W*3g033nF!b(!rUj">fpi0TKH!:azWv9}gL&x<4 f$NpPR$�D7RVz]x Պmܺu ~_EKKK(ޖ~)Xԡ>5{>zfSJ�Mo;ceeO?4fff#vL&. %I|Q?KCvBUѐ`KbT=pH !�'g tJ;EB88RFP~P(VnK3aVjb0`ggG/A6o"nrɓ�숈l6#|*K/x<./vggǎWLMM? .]B2ٳgvQ*$1c Ixlg8r^/1:�0K> 8NdM%}TBلi(idzrh4G<g0Gە̜K̝oZ ncuuU, 8q* % F0LB=1 .`zzJE<4`nn 7ns�ᰔTPԑ8H}1NR)8NiI H'b6~ CB!�#Kh4f<3|,r9BJ"l63vgiԻn!Qw]iLHaLOO^֭[r &''P(Z"rISì=p<wݹsn[ɓ'0eρzJb;h0V RcfxR{`;@*}!ǢRMrnP(RHR`6%P&9~_&^%˵Z Z }Էl61R\.k׮HddJeXpi*z'|�Dc�Gÿ&vwwSO󉐖 ]JEe(Iy8JahGZE>A0 @B0=rYx>r|j*?"sT*˧d1?W|><%HjF"׋)JhP(`zzp\8884v=(s3LDbr`sk_.]˿>fggDt Dx˗,!gVK0 �igvcbb�X,I U$ P.j ƤǣI`0fhB!#^U,cM4NF!0E M @Z4Zؑy�brr.]dB(|`yyA4 iT*o||2fggqiDQd2)B%y6| 'VB99N& %di5t7M�BqCaƪ`@Rhz%D}L&b1i%INj(qppC|_2}lnnj %ua2z /  ^  77�͛7L&q,..b_ĭBA<=ix(JBFА[$ɬbH;1%KĎv]Zٞqzp( 7=:'CnG|JGQDڀ�0rG w'Q(C>m@@ y��gY9s`pe(\.mޯ ĉ8vp\ʟ"_kr'| ( ҙHC f+-(dSe YMa l4TH|SFe@5~"gKW埩]e"[P:$=z0Lj \lh6F-`Pjx裏JőP($u߆yQCs@׾5<ַB:Ƒ#G^6/~l6�t:۷oh-=[uM&Ә@Q`iqՒ>]TfZJ [(#@ ^ +Ɵ'/�`kS,QEQVpq0w:"$/~brBC"@D#ߗa>H&hۨVh6򗿌^z /ckk 8y򤨳;666 Ǽ%a �vwwQ,B7%c.K@>h|R#X4~/e9&a�.Kr dhےP#R`لUP9:N|>x<v '`0(C:)z^~z+q):u ~kkk( O؆"Ԙ] ?3ܹs. .!׋=XVrl6L`dl 9jJYF$v]^) i!�R-8<<D6̟X4"bfG: nK:qu0$!;H1ljқjp\.q8Vxdunun2%ZZرc!vwwy}l<wȬ2n7 _e<O<躎p8,^rI2Ĉ�DkHG%C#C(V@(bbT;$*Cz]rHb:F@m'Mt:Eɞsb ةJ( ;z2`4r|c ? Av]&KKK]~,<w$6 >N<_~jpQIFЪ�Mdi4~/ap5s% ހ3¬CA|G\GHb?h複�wfa1h<R].]n['�ntjjg]ױl6 ]l6?#Ν;'ZGɄ??믿B ={VHVFb͚5hՍ .֢Y;b&edRd^`0tBX? NŒJ�� �IDAThhhAP(Ȩnn�遹nlV2"�k'Q"�b7L8vΝ;ߏZT*56Ac͏<`aaAHe~7MǏhJP(  ʂGq!(mTb  "B̲!=hl!Kh,VKB4+&8@SDPIEijPMo{*%bȴ8n ߏf)Ѐr7nBzmbmջ6Mt]x<Nk!LD0 "NPA_0=*}!333xgp;N:%8Jr98NTUF5]Ke;|(C!=Ts3\.~p(&''(hMf�x8HAoƤX6ɱS 1.GZE^zp`I��|U\.<#x7rH$h#&KrTx<|7 XV,,,`~~7nQ Y3GS 9=j>VUT|la|jx%$`x+bX,&8;ZVĜkPMz^&Ed^plRI AZ1fSDF4b[xJ)z>2nFXlL涻7o󘞞KMӰ|>ܜ8 \pw+Fz7iU1"bT[^f 'q��l6+XHMIO` 9yF/{ B$9Γ?O:k Qa⡉ͦ "45$ T*D$A]r]=�Q>_Uܺu DBR g"[VپEy:frih~t:dYFcF,&Q˧rY D(HU5Mb8M.obwwW >zͽ=93 Mff}kt'|X |FD/*oH)R HHEp'=(!OD4f�C/E:I4Z5*U0gp@`@XsuhhfZMzԉ9i*LgI41%pOyFNS*Od"&p9 €.}D`P il6+D{.*jXO>p8,ԩSH$YgΜA CzS}d2P*$0`XBU)5<rq̍NRcREVOU=!1RF#j:v�gHW7cѐF2H4LMM=Ӱ YR%ٛ;9TM|FHF @N;)W\5~P0᰼l։'i^{5d2)r+V5Ba-XU*`Fʲ $k&41?FҋqE01IZ.0HQsP72 9 }LNN ^USAdJ0{ $8N! \DT]2^iܽ{W;3 B>jDBj[[[2??Xp86F"�$z4 1)qyGHاG#AͪQ\FՂcAm6:a/_Ӊ@ Z&X1ˍaHzcr8B`PU /ׁ^sVת{5qfHӸu"n7BaNOOcqqQe~mloo'CjֻXN`I 3$Qm4BI{Pi"nD8Z:HN`zcGC 7 pOFHݖ�NH@YTIwTj\snjbl+˜^9~p#`46P(Ν;X^^]rX,~Zftf>O*FQ,,, y7%FOCjHqAV) P9Gx~6 jɡ4($P Ϥ Brd70FsTa2+-|jB$Pޛ77# ,גn;֐ $fk�ܹsG瓣ofs'fPvbXXX@DPS,.." a ށqvj$|9)'P Iu!32$H!ִuۍx<.sT1�Ŀt/AfjV1%S =<7)C7 !ܴQ<BRHgZqQyNrm�ĬZV<#aAa x eKZr j衁pT0�`z>X$虩 pq +꺎`0(*ˍ1XƩNzUC7k&Gur2K.0 EwLhAHNp/yP@^Yx |>}?ׯ5L{Ξ=+J)T*2cBx8ޑajIMƦkj$$YuaI82:~Gp#fr9iU`"I h(fsl6ǵ\.b1B!WNw\~)P2rS0|BrD 0l^ّv`De\|Y&MLLaffO?'c]6MIz8|{{{ΦҺJ.r(B(?�zKgЩ�J-B{!t+L&|>0Lغ@/NcZr'cde JvJ0$4M6CcSd R>11!b9`qq�pM)^v v]lŀd2y_Y95~FiG:!!._<E!=Eqv@fV&2zG3HPI0wbV1�*y.&t:(JBEY.%fcځ^`6:M&wz$l/!FLHd*srqR[ h؁[oᩧs={r6 3338~8~_<XdRבL&q1t:=RID!_H$F8؊d>CPPOI' : S 9||>b^"~?  O)HiH0=%:ֆU/jI0Y!2hFr,^FN^MLzEiU Di뺜f6L&?a~h,<N> ɄǍ7`XpʧDJ&1(3T>%*�rl6.Y@^٩ժdLMl`0(j T8/K=[JbGVn(f&gKH<{'fR)fY-Rk4JYP~\N޹l#<"˅+WH1kdg>lJ{,žwӧqxx(xM`3 % ^\T l3RBƺ*;#֒- d aMCXl9NJ%٤HB0M8Bo g c4J(EȲ$6(UW$I3RPt:x뭷 /ĉxG;^c~~+++_1N]YY.Esf(q "uRUkHK;gbO7 $ERhPl}0S')N[YWf) 7(/ޜ )!7 <?)# y:@�d%}XL$=˨MsuYKD'g~f Qy#>WX,&;A,0 c0T%'FOGOHOǟ5m3iBmPJ �z/$ lj+Z?r~*A ɄFmPj+i*)`HeSX FGrLKЫbӲ4kkk2 CRCHȫ-H *KJjdSc˰IgM5d�Lr^j{ LF"zod~PʧDP~pX<9! p8,µ楎hV9sFJB3}WbLXf'O.x Piuq �ēPP6lU !(\ziR34bwRM*ZB8PA:rmIē.ϣ(N8!Mzj<3'b ^D;:rDB1/+Udj T=,0 ݳbp\tIT 7vD;;;T$a0 2!�">VQ cV&,b/&%>*!fSuѐQ1HXVd#0˧0ŋu!{1 I)T `6"vix�Od ڪs Mϋ.`mmMb. rb7nܐ1555&wc(Cq(tYzb(F9 Y:]v#ˠVv-z>G.CRpL1pOixb(ZʌN*ep8,9x!n߾ǒDj666( uHJ"E"4pQ`p ?yOjl{IP:8'`٣(^D"1Nodɹ/2}]?#F{ @0/|lrzCN%< 7L8<<UoU.%em_TR\"*M0;;G}t̨XXVLLL`ggA?a2$A[ꫯJX,bss'O˟c3oJt(HcgdD{ ZbuuxXL 3ɠltYD. /~16> 7{X,)71f>Z)7L (8<VuR)1\.7&UoNVxfِD*B�шW"`bbNX{{m(Ġcvvfh�E'$5t|iK,yLT=)aM(CaUl0ńeyn�S:HI WK @MNNX,R98b<VIIի8<<DeKqctRlX7,ؐ!N'Ns,Sl8j&r}L6 d̴+ qDQn!COڷH\~"z}fLTT׭Hk)�#7B&|ff)uPkQ;c~ss\NZw766dlL"F#d6L%-LD88 ` 729ȠT*IifT*l6I(##F$>U[ <Q蜚fC*BߗJ0J#!l#m*e fggq)9"=HBA=HuIt]p 3D>*8'kB!}tJX\NTfPMɍGnIq10 jRg-(?0RL&JT*='/9Z>KUi+̎F�%% /xϪj(>t*Խ^/nݺ%D51n}9̌!VyL֮]HTzDb0P rL0it΂3i4B%~^O)Q M}S%Ü H:f /%|ԁJJ ű^z|^xI׋JB 30B!KȳlJ @xrj!1).nܸRgbiiiL@x<bH/^믿. *\Kχul&oLp!f< UWHsݸV4>. \@䆬1ڐ4 h~o�"|~C~0qp(’>boqqQ Ljj3̗GU&pxx7obqqQ tbzzx\0( f j<˃ BWu8qN5&.Jxwve>7dBjp8a0ws<N&#A7ic}]hTKPtZ `\kkk8spw {mL"Nq�or, sTpXQ+@yV 8taalp#HȂ2\m9h*?C#U~&3f�—v:#ɠj'X>mGb4mGФTV+Rz3CqKMӤa]&Hlu!d"7iĖ*4?R,H2ڐDVCl09vj1z=2"k׮]dY�KNNX$uf ɃLNN"!jb;0G/m0@@k0$bbR`{{ǎ€:Rȑ#}bCH>>OFR i4PU cR@#R Ê<5jC MmTtZ:?mj-9`0#?fy:IRIKJdؓ�Gbh4* �K<ߐˑ~pXBwm0Fc\^/+KӑJ0L5Ξ= �zPR=;uz\1r*Kji*)x^mwRݢLkRj4c g_Ye,GQq""`0F3I!gⱻB бr#pĜ@�xR @�p@�{{{pݢN֐y| *L艟y$IEiYE}И8voo|0 t|H|zR |v[O# cM& ,_7o _ Bej5~t]/>.*VLX-j$7w*eoPd z7I_?�&̞Hvx0fAcॗ^p~ oJ5YYY'$f$6yA`<J@)UEĔ#pO>*{5`[):A.Ef $ij8d2%Y/dT*³>D"t:-zxA DᚭjdTUrX<N. "ml~uI/Ni~~!5q%/j۸} tp:BbLn<88@=:嗙7TIL&iP(Ll $H*FTq(r<HM�Sscq� n޼) 0I,..ĉ�z&/,,3ZjܭH* x]*`ِdC FxSxjE<hY/oC&Aە֧(ƦP )mL||N#U`0( ~_J�$]Bד0mX011!Cu5.̒%cDlnnԩS0ԶߏmPŝ0⩲٬%Ti?U)l,Jn\&2LG{#9FUU9!V|5Mnܸ CLOOC4&ݣ6fiicfфi�D(³vLW#ĄkA,^di�� �IDATYgٯDAbnK'`N% J4zm&j6L_,l6q5 lvQTP,111!ӳe̛FrT1Y,B!k&[d20Ib9e3ftZiI1+A\6M |>LOOK><b1z"FV\JӓqRjᖴs>;N# -`שޓI[8޽+\ek؆p4%Z"j:6u~t7 ,�RUQ{PO{IlsaWTR^UJFE:`$XIMtzUU677`@U=QQGHPbQ@=, $0D3Y4΀�H$$R)躎۷oP6Q_2uh4bkk kkkQK$)tVV8a SB!)B!0!pX.悫S$0@<{2[''�@$]$JkTA9n~)2)I:b N h4@ S6TqE7:T*!ɈKʈa v nd>>ѨQC�L.C$"J0W_z%sx!^<̘ȭb|6Q ""4gST54N8@cU.{sVH*~/}`dHnmma0Y:b=deNc)fh4ׯ]KzPU_eQ1 1%7?m'jש뺎}숳`A b}}gΜ iXڈ}R Eꈜç9j5,Uk@g� XS@cf,,,^Í7}Ll$L#Ä^Kv3Jz=TX,JM,R!A\`MFv6L&pSRw}sssr<xQ<0C 2n>,1]ە! Me%f^O0Ydă|Y*ìU~AllloH|PHzjdd2)�z'9fX__GXp8,V4,FutA&` ΃%~,Y>ADREG~a`yyY-6PD楆NM&r$"T*UɝOpB 9TALVTd30eI 3t:H&X\\U2LJ 3XYYgf C(A_L&#b(\D.5{QH +zrpbR=V{2Ot_i@WX́\ lQU3UR/ ^hp\X` 0R,<a ;5)zU.P-lF8F֖`j ׋pM ]>I LZx<.aOu}LFw'd|Εɞޡ T&@%t: ǃt:Ǐcqq/_d.PTm+6# VHkK+0  l/ rz0RVy ɱ:blei$*>c!"gZ(pmNw aΪ10X xhCd]#y Ldh4"d2azzZZmy,9B.:"&C8DŽ w4׊Oqcgqq#aycgg ;ibHDp.@<ɖ/IP0*jJ3(iP ?\lN`�U%1-{rHRcCt>_GPD Icq=%n7dEFp}B`Kl:+�L2d9Ƞ:"57R=&[,DaVMH-a{X,J)�LX-ISȿuJe*֬a) Ao@M!0`{{[便%)&ܾ};;;±cǭ-byyr$ QXercq4ϾT677}6*ozEM&2677QTw~. ncaaA6me6M,3T>G r97<wo\;&*%LpGFJN >4seBuB!)2;fW [ӑ6HL&# BFfڂx'L&h(FDrRP9{@ݮHؘy^J%ɴLRύ Jihj2 ٬xb'&ױ(™LF0 yU.3JGER`X,&/ob?%^Q(d#HVIZ-9h`vG1� <Q\((xaN V`4h??^#̃(SC?=^:FP;YLLLё΀+@$kHeCc6E ۊFb5VުsqqQ<G0[<j+"LC31a˞XvBF89IbjU2 LHt' C_, \p> fyyY/T*>@e.�@AT1 ^J/j$U)UL@^*JИن$`Jh޶lbvvv,TI#^px^O?4?Á_ίx@MzliH$-ei*!vT#4Ҏ$@".crCnݖItFLFr%Jչ?#x:?!}355%ny ׆I 75*{Elۓ<H#f=MfmCB ||V?gzWuKR!/_ ш_|~ϝ?'xsssد2L&VKj1�oj_8/hV\,WU`Ze{;:*% >dCY�4MghJ՘dl6+#v]IR$=,G4dɄIɫXI 'l6q\D"Mp.>E˵Z c &0*Ǥ0 BhnNaV Իヒrd2_|T p/xX[[ӧq4P~ʋ٢ZRHwv=>+WCP^GpWCc\N+7'*)5 Bv2|(ySN#BX<KrcF*[T`0pcEeld&P<<^ta >Qٔ9[:~?D㪖JoڜP.qΝ14ܸq?8Μ9#[$z뭑W&G~S=&=ԱRxkk ;;;U*1΋3f2fgg%t`h/u]b$}e8F2lqv}x~~~LHA%7C82t\X__{tZEv]L&)1IT[QԮEv)&,d2J%d?qu]PEYl ,:HAIlbeEN/$'8<;N\4%E,ɒ( B^Xt`sHJތ'C*{{J8p8,'3=&&&T*" Y=I d2|hhhC=$5xYYów^( hmmfj{l< <'wyd+** DUUU%>X 1I+F)k$ZFuu6~yl);l$l�{D*6fHy^|YTWW <čD k<Z-79|sr$cLAO(7u:L&zpS@-$E_L@+nyƷ%%%x"n7ۘnyyCxxOnZYY)KcQqD9sG&YZZZ^GMMc\b`0(on<B< n$Y^^X,& ~ )~nB5#yja0T*z919"Mb1BI%xaaA6od2)#r8B* VU@ 8x?+J b011!H&hhhlF0ą ###ޘr]R@VPsVDT6,,Te2iPx<ɓ"ߏt6)//Aw}} I0hӐ$y9<t:~?  BsxψkP VD瓇Y%dSDfJ( MI\ZZM>=r\E$SD" uuux'ģ$p�R `% �466JQS>Z b˩mb|K, YZcPZZ*py|ry-VTTl#߲ 4V \AEEV+�Ȕm"RDV 'Mpy{0HsEG6??$'*|pR!9يy!W󖛝ů~m^_,xmIZEE]i ƽqeN7$&F ;n�X#ȿggg/((;4 411!hR95,UHg DB3iNZ ?SI}ʓ$㨯* `dBT م識|ۍƓ#Ξ { xw>tSbaa!jkkQ[[ʦg|d 4-^l6H TZZ*&l$%rؼ9Y^ 5ɪKKKX,p:" v%vH'KKKDf=!ŘR^W6I<+hՅ)x^y<D"PΆV~d`0`}}]ԩ܌{oP($46]ϢA.lˊuPs$A,J#੧*oD"nLF#̌x+++r ͕J]c8NIӘ_`kk븱!t6x\$~ w(B0Ɔ\#ܐ8ccA8=puuuG/  ~<iT*f3VWWcGF. 333D"0 z6ӞCyyI9͖X\\Ғ4b,}x) *|>~?Μ9󑛒+LBl6ctttQUU@%T'HQ1;;;ݻwjvl(JKK*ÕX0\a:K� 7l6h,ūVcYYjjj䋦uGdq"ie!~} 8yY t)ZXX(/z2\%QyyH].P($N9[Fd RO;NkkkۂPf3fff7ȍRP__/&ODyrp87=cyyYN!~I٪:r'IeTXXp8,3mW8%UX%bwrӱ G2/O`0(^iDxjbR㖖 iF^Z cnllEdA&C999hmmEII :::L&uddDj|F<0uL+597W^E8y4EZ؀Dii)N'>r3nPYp"S4"v;L&_wcF0())A S,5M$|!$kUx^dq"AD"!!v~<U9r$xOT*&Zwd$f<% k/UhG*V8d}jۋ:TVVjcccHRU� F܄4v kZLLL… r $V+rrrkkkM9::zqEؚ6EQGs|@ p<knLχFQ[я~@ �*;3X0 تvzC,2nd`d\kP^eMʦmllF%h�fNʔ sZF�RLj5jjjL&_zBnnlL2x:?I.\ Ϸ)߿8 Bzhmmf3066d2fcǎmV4bR65x?�/mCNKȶ!l8'2RΔwǓ8;ig{l]~#iH5(q!He*<I�K5#&�fJZB%kre9:&[DsssB@&''E҂5x<)GA�K.`W @H7M0܄f{=vUՂes*kl0( ku*fgg QZZ N'(Ųmi �y8"e7K4>\T"r6&Głh4x<.xڳ.݌R2aզ Sz_Wmm-zzz1rrr]\\o]h4 łN̙3[gw-HS]]\$n W5'4;eKh @@8A+% 7lN1;; J6�& HSSSĥj"sR 9qB3ZߐXǥg}ZXX(F3˥q୰`0)]j0D') c iY.ٌ:R)\p>o[`.W^]]ݷ_u9rB.,,DCCd099)uW XkZl6477 F(Ml#AmFY[e{C:nM6Dd2@ qX^^no8AagƇfc~LLn9~[ӡ@,u!:6elIF|(**Fǐf)AfZ-jjjى;vP$NsFkEy߶(//h ɓ'܌NB!( -dщ ,--! IP\W<1WVV0;;~[6;ux40$ ~?, ̨gXjʟ.W1Oqv=٠d8%c$5$r$`PjX t[۩/))f NnXVi>ͥԄ={`߾}hkkCnn.&''QRRn }X-84TqP(xׄ1770<< ۍh4Ix^ϣQw@@d2iarrR&9lײkZeZT*#yu&,%R i Yeee-ddpd0{C(իW;p0hjjB,C&.I,Vn Zhhhq)~|_?Ulm`ih4X[J#b())A{{;d4tSE<fffx a4J[o ~\pA XLFuI%2# ZV|p[yfq|Sjc(: Jz�!//O`/b<4ov�� �IDATI>fY6V0oqq. .\fÝwމD"# _z, L&MK/]w݅P(˗/˿IE&^G :*++k.~~W^ ѵ-#x^b||h4Px<p\p8ĔHK6 + D""; v6V$3e=ɹoI(4S4!<ɶ!D Z-|z1GL&#xlFKK ۋM444`qqqӺM&f3$ӃD";vl}>::t:Z?l+R<GGl#A ***jeT*%CjJsf׀*J)֋"mnnޛfR)&b!''G,]I&dmmpH~>L" `vv(((^n,l6 �={'N@AA/>Μ9h4*3h. pxH,\IX嘛)6 DZCY#VTT@׋*7 �T縍8eF>;l#2֝.dPYH3V=IFA0�~``�46 Hfm[nfm=I8~8<zzzPUU~w%?P_S%9::*|+Bhmmjkk<Fb +\TnssSNFV+ v284%Lrnp`� 'e ӡ\nJe$uhBݳggff&8/oEL|Zkcc+�u}}.{9x<$IDQ|�׿5|mbbrvCѣx'W]]�H5;;+v2(=E"y RNvO@ΜN]]! $FSH4qh4*D W_M&�nT`@qX,l657D_x3334Vmm-뱺H$0==-<֧~* @{ݍzQ^^{ t:ݽWMM .\Ç K%ۃY@@@:^555$-9քk @s65ٺsr(i&CJ%x 3J[FiaC$L^4Q Q__&v.eͧG}C  l6_|,]WUU҂x^8|0|M}KƄ.]ƆX$<�ZM lHμ9yʾrY{&Dp:j2IRn%lGfږ+^ H$"ʖo%=??hꏻ#0)Bk래GWUh4:uJDdt}gHlXXXFOOT*%,L0֚aXvرqȆsʶ:\)eٛ=ە`2DN`aaAөT ^WFl0)$fBJJJ&鍮knLrgſ˿ŋrCOr c޽!'-=u(JPΓZdSF];7�iNB$#HHE7YC}A $}I*d 6n7fffɃ$Eu"fэk^uuu׾z?~\lq \ jKĢ�=嶼@$vxJ(f fg>L$LJ-.87w+V:,5XKҊ(�!\SzoDcV�"!}Lf"8n?鵴$ZT!b``qxGp1b1hZ.]?@ �ݎs}oVnnH<f3vt�ȇ8F#(iȓ_EYtKb6'cNr]TX^^bpnVX'SM(^G__rrrk.ߒBZ,2S%-`>ͫ|?l}`c*Jx<_100=zvg?nq!*Jjy!mIz؀d$ փ8$뉛I:ySGYN֊<m- $YH$"RjJE4l< k&szzS$Iv7<fd2amm S xuUR*E͓3nB3diff֚İ!Q@2OlkMٲahH=! p݋}~~j Rb6QUU%>E핎^ >4%%%"O}غf966m,u6MԄv~SOeÇYXLV+ 3xU!V,..X,Al)"#kv'8-b Zl&7;=MsJ}U)kԔ?5qXEd(¹spO@QT8vhHv:7\>\ǼVko2P^^!죜OZ^՘HR.R)!XP:/cΝjp:LTL&# Of[fEL0Dй#jTklhhIָ<].\tsssxwa7`>11ٌ!ϸƼtl"%"ܜHд<###g2TWW^ lEh+T6f;oqlTORd000\hZATvcaaGh, ,9 2xӧq "KSFOsz466JV:v;vMmL`ڊf�t35iB%{=11477uV%#Jd2F)) b$߯?i$Fx^t CCC_]](Ο?Z-=&h. ш3g7$^ԧ*Nþ}D FqU8TVVr}$lt#G`xx@�uuu#.Nwt:CVCTb0)" 響);wJZY4F'*6ݴF$4U*^/rssa4aZc=}ffF`!֡<ճ0łfy> !իWH\>jIFa0022"dH(̖_894] K0 ljjYC6eZVdS"dP̓7''dpX {.]$VT7=%(1fffPUUoQ&< Ml?;377mmm��!\Hxk&WlUB =iجAWTBӉZ^^f,P0[?%F#r]⛜¢1O'''OrII(ݩ!'gqmmM@j5p8&855"\y:;;r`4ggw)o>jēO>]zuuuؿM'~Eى'yC)7BG~~><0k-A-Uv ٖ$oP랝1D)jzx<qZpY:!A!piPEEJ`ź^&B@[(KII PMmn�=܃K.tK >u-_YY4 ,  T*T*BV#HvK:=49 r*0iK ཎ\bccC xczzZ&;9/))E,C}}=Za"cãhZk*B)7cǎW^x��NExPSSC5o~>}Ml̮.8IRE2dB(d7I- Nf g*J3Zei/[{X"l/QbF"$ obXNz_v^éSΗ&kkk@ A:ZFyy9<ƪŨ?y!77>OVŠhֆx<.Zaa &E71 W:bii Νt2LhjjBkk+9"Y6(|N98מM6`cE^^Mm8% .,,Nn7b*++a0�@ڴamIĀaC}}=2 Ѩ@B;ϻvBwwM&&''d`X`6qYyfxߏ^{ �dPcW o~"-&u]nG{{pA8!H˧%Bgg'FtmCgg'sӠL c.J%OYZW%㘳yyy *=٘Q{NY E__y cppP6MxrUvttHݎMA&FGGqa;vL+˻.NK4 VVVpqСC8x 0>>.xgPXXш]vز,ܱc.^�ZXP-M cR&&&kjj_i0DQYY-W&7 �Htb7bAx"^5鶃Ğ={$}ff333tM`0K. 3y+ 9s?0N8qKH\.x<A*\P(")3nxc@풰UXX&XVIV%^ ˉt:$@fsԗmBXӬ"CR!H/+ R)$I䠹YtllL6eCClH$Q8N\.v;o>y766w^ fP BҒP}ybjj . h?pA<Z-^n+ۇ\5�P3̏؋dR.onV}y$ I`lj $ OM‚8YPo m%SYfRܜ nݍvmXXX HyMVޭDqq1l6 4ؚkkZCR�7xㆤmmmؿ?Ѩ*KKKp8R"```@666[ϟit.DMMM?E}IYYrss/EFdnappPΫWbǎhllD^^rrr nΖB!b1d蝴$ DD"bH$D<88EvÑ#Gx x"R`2;z^磳Sl³fCST*t:ǩT Af/_Fww7Bq߿_&`PG[o%?`dd2&o^4*))Agg'OoGKK\N'N&:;;ׇp8zK!T 2b@ a<DPzEQ,39xկJpR6VVVxP]]KƘiהL&LOO2srr`2׋z�[S" |AC{F#j8/ѩT*߿?wbAcc#<Ξ=+3돻�|2Z[[^l4k T gϞxp<�JJJP^^.]3go>Ic#@;D@mvfKki @ hH'%y(JKKk.ܹsB()) #cccX\\fC(B*锲-..v˦t:xDQFfAI}Z__6˿Kill R^ӻ8c:g:t> :::w^1jصk*++QWWnٳxՊv۷BrAgg':;;ݍF@vf108!IHRµ&Skkk!YT*R)D"15cww78\{9AEHT`0H$qNP`jjJƦhoo�qTN&ؽ{7ZG{,//K@+ (NSSSEnn.x v]ѲAn]l)y괴c1e=k!ʴ;hdR3d2aǎ2!n4аiS[[+fL`0CS]]-JysSwI8J<&''mMA,..J/Sʪhpy0 x|7v:N2`P %~VQ % }@W6Q"hZZZ055Zh4;p---?'N`aahjj`4155.5& in %yPUU%I\.Vt̏ 9f}IVoi3>>.ǓTjDgNO!FPȫ‚px˞|YY j6>>Q|[BUU|> aoll DFQJ<觩R�ǃ'|A`zzZ4P�w^V6F:z1cüohiiAWW4n>(6,s(999tbK/},jшFl6 ˃lW}}=8jkk`2ꥼ;v@EEP(vԱ;ϟݻS+**BII fffD}ɾ>t:G&<qBOwZ$jqVWWxd0#L1\iS(}fN^^PTT%A/ `eef<0z)a]t`0giZFH&BOOv%#`jivq477ct(++Cccك%%%000`0׋9zC***PWW'ݭ.Z]v_2K/W:˨|>:1QTT$c]]zjaX0::`eeMMMa} 3VVVD*@7\B6 H!FAYYP$0s#3jbii O=&''"X+Gsss2qܜ|iJ򅊋a/�1z/Oe,PTАřS7d͝H&/{/**8܌H$9iP(p $ # x衇S=C|`|vh4èxϣA8`F2 >rΞ= J`0 Z +_RĽދ"tb``@lɤY ΢]j8brH2qX#.//A JDB�^|E|>tww^ZqCRɨw*++8JallL4/g^VVݻwo%ʢiXXX(7 l"cp…|'OĿ??L$h4LOOl6# ŋX__Ǜo)t[]:555�;wbzzW^"].OeA,C0&AMMxB^pPThjj- I/7 ,--򲏮=$�� �IDATPy].b1"JI [: 1<<,s|<ԠOLLܹs())d<9Tp!InM<::'Nlk`@,IO<'Fw}q|߅`Ƿt嵵hnnWш*/JEEE˗133BJjڭPz=~aZ":"<\tu8ҿǥQafCmm@7~?fffD@5(�lWWWu57'7&u}>^ znccCN^{ 0LbVU'fuwwc׮]؀N4._<|>TWW T|SSSP(OɄQHAqfC4j=#|ךxeeDZcǠVꫯbvvsss2wA[[gJ%~itttܲ2^/N':  7t25k.$ x^DQ( Z\\VwMM Fp6е.Taa!\.C혘IF]f%LbrrRF ŒC ޅ vk.jJ&<Ͳ A�o6P__ш:<xkkk"y^n[-5R5oyy$S<44V+]Mw^ ɓh>|_nbh4h4 S^ ,d.˅zъc||x"JP]]-׊fC&n^vbXZZ©Sp ͡p:˗vh[hddDA5$݋:"6<`G:N~FAgg'qb1B!1n]XXۄR}s7�I�9rdvz7`0"^]]Ŏ;p)q!V(7oB!,**Buu5VWWIu+'&-v6maa<I>< pIHtigh'|rtuu!`@0D*B8G @(ÓL˥%4Sm2W3ikqd2bF#"FGGO'Owߍ{ {C4N0VLx iIx544$`DaX#�.KˑNU CbJWޒ4'=9M455�W\ǥZ@ss}mmmbP*Ǖ+W$K9v0LpfY|4KJJNsNy.//ňFbZTT$.ġPH&<R)X,j%4#$N@D 1|>ٳmmm"PD$:?cddBcc#ZZZ��)ש^Ƶ_~TWWcss/sԄۿ ŸD"2e5X,K. 4>>YkR\zutllFxu#eST*qETTTX o&.pV/2n7V embv!x�/_NfggQ\\,eG2VcfgHt0oLjjp\vvv !7�{ߏ9<tbzzj_1==-rrra?яm܌A9lx-{<,//s~3<#%`T�+#rjR37 <FLMMHRb}mXdF0YnRl ڊD" W;t:Z۷Ͱly锄42RER)͉ד咎}}}]t?O�\笻BV^hF^^+’ ͆~lƫܹs>y$d80bii zΝDee%z!mC~ގ&+kaCEOƥKo|> jjj, `= vNn#_�PoKt2Exq))9bַBΝ;% att $TYYGMLuu5t:L&MI)‚L8!bcE$*t:,F(IMAAv܉={vyD"?߶qN8'|/ȫy@D"<S)N'FGGr8)~ٙ�@De2`0> P(FnI АLa4jaZe@KA҇-JL&cii ?O "靝xDK.rauuUWTT$А4RDBVWWeCOJrIJ>JRXPvEf6%%%X,LBEEۇ!?OSAL|>8*++_O ׋fID"[oϣ S.B>z%pӳ>~[qD"9z-׿x<ÇCbeeeÙBt:/| bG8Nîtٌf ѣGŅ0 0 x뭷o>8NA tJPߏ&ڵ ǏG~~>F#\.�>OBrMVY�D^T_Qχ&l<Pyѣ 1<< ^.={?1>>.ICAAߏp8DzuJKKQSS)q" ؿ?&''a4QYY)AYYjjj[oWUUUB0D"(**c={/-mJhoN/}Ny?Z]]]Iu֍@$ɓ'ݻJRHp~||0L?d2/~ؽ{ȓ!$�pcqqpX4B J$HjPRR^`0w^dj(˅ "7KbA*�ߏT*W^yEH?o  JJCCZZZ  DGG4yt&# ~;"WW(..o!Ov;N:_|Q3j}n}�nn;|dى3gΈ_ǝw)c2@t:رݦY Ghkkã>*n=5R@&mp8@ G}똝ŕ+W! s>N`$ESXXx<.>%3rIJ<#r2f�w0FFFpei477c޽d2m&A8w܁ j֢vVh>tww#@�/^˗055%C z@n<2bsVy0IOw܁2nq Aaa!^/666aFH�m2$n?8ZRgΜA(B�@nn.|IWeN=L Tk. Qn!j,-- frs)SbPVVjq# @_(L �ٌ={iX^^׋U444@ш"JiTVVb}}(x<8wvލ ---ښHDDW�'_~/? @HЁFkk<JȂ&C/<iG>nRGyy:PdM<} D"l6ŋq%9}AD!`Ϟ="eUqql27X;؟_EE#)rl v)SNŋͮVqwʭEY/ ˅o~(**"|_āݍp8,ٳgQ[[+^Nx7p9|+_fË/T*.8N߹naI!ѣhllwP7&�)Qըe4N RPWW3g`eeEOAnD"&~Ib ;`0cfymO<Ο?q Q*rUGEEzzz0>>.i###D"B^ԘT zFUU8WpDžư*�"/X^^"6ibFX &''122"#H ao" W^&|>.vmX]]zzz}X\\˗166&fۇ?~Z:ybbBGb/~j_WnZ3==}{L&(JG{{$J%䪢 ,+** 6Ɉtl6㩧_~?.Zmq_|ES4޻vPZZa@W*׾&??) -Hyq B'  dzr#e2)5Ν;<hZlnnvcrrA4s='^,R!<|I'*._ #+bUUUBII PSSi1x>[RI[FZ/_ɓ'ׇy ISVV9'XzpH=dc"CSS.]/UJ]]EcctG0V&�;wJRrrry=::*R455 9euuCCCX,X[[(&ƅ"~h|EDFqy�@)vի"נ1Nr!JIIAb2ÁCt �FQ3Qvvq!477;rc$W8 c޽r H2ڜ\zUX6|61d455ҥK8wp1꫰Z8phx<f3rrr088(IZ-B$>uLMMٳ;rpTUUI)u+**qF2Tp!Čs777~+++0 bw=99<F @J&ݻfY6 E&a6BH$"===(**GlfFQJObyEÑ#GPXX~"rţtZr(++3F(JI>`pѣG$ٳg^ӧO#ȑ#� ' 1 !9ښrL&QVVHO<b1d2IҒ:VFh$21I# *Ҕ8lOSn6}8s %ZTJR|G"wߍt:g}5_ߘ<!PVVq2mBiq`0999jBٳgQVV&t|n+µ2>O n7z{{z1LB_XXΝ;%v#f b}}LX OJdl^_\\JXgWVV0;;+]|^^4 vwwLF4tyc9,skkkxבN,--YNjkkNQZZ*�/57> @Nχh4*ANQTD"!X,ĉbHSNOO}}}hzz||\8EEEX,&ٽ{7ffhӳT*^p3өCP U dBIIhyj󪮨@*RDUUaZq`0fa߾}X\\~?a4E"QZZh4*$yx^ٳ---8w|>0az<ϋd;v tn[jۏnɻFӧPVV&aP?99)R,Tg|Y[[åKxL&/++wߍo}eK:FUU+ ,}]&mmmrUӼ4Lqt:z!^I)v[a0�ǘ^W:Jyp8'K###08x\Ɔt9NرcիWeJG`0DOOj4qqcUdc}VƜܜOa {)N.KRSӭH`V+'i2-ygh1MKZ-JRR*++Ñ.%GH$"1{@ bhhHN.TWWb6܌)|>gLgmmME,,,СC|ܕ+z^NLݎj ̨7?t-fw}*W9"ۇUї͆v^y0ٽb1B NHp> QRR!bQjB{A*E)..FEEl64ӣ#5 hJW~ii)ټMzRG7FQɩl6**++.u\رc>~Q^^h4;w nfW\ƆpTwލJt:<y;j&A0޽{qE1] x<)RWRR"lAA&&o_vyX7ٲ%Y,,NRH4aJhN;lNm]eC aI $1N-[d[,o-K\<ǼW IlO.rIdypy5ɌY@I#!N3KJJDbst B(++åK000�)X,qύ$''K#u5EXO $6/o8qB�L&h,y^R2'66V(Rعs'fgg'2. Z[l("066"t":*Vq. eee0Drrf3oXvԼYQ;k<KOLLÏc)CHJSFGG GIp,5\HP`vvEEE2LIIifP(cڐnbu7 ++ @@+lrdDG^(<\.[kΐ wKHHng jqet:Ȅ!66V8y5m#ONLMMhSyyЀY4SG? DzbU*P( ȭH!&"<..N"ja'}}}hΐJ2CfayyY>f$Y4 XE mvvV�N~!FGG'>iii0W||0RҜc&򒖗aZ )4mB*J@E.eĺL�=sw7"~T,QT0L9??͆X,B! bll ccceC]jSoLV /DtDUU 4=@l6 899Y2!$Y,zƉ{h;_]lV}|>Kȵbnn.Lp8,ÄyM.]͸|׹ᅬ5 M?FGGjz{n�&^�45571B000/q _& PX_V ȀBN,p>Jf,u Źhll< ]7�~fRrgXj%r 4>>.ّ$X;Eǃlp)A��IDATvx衇vرx<qsjAhp8PPP:tyyPH֧8wfggi&dff�?# ''111(++F> R)NT=ĺgL�brYXX(6v6nkko&B[6/X\\d{W~ u˺4%%|@^^L&233QSSoQ2WRR 333*_&�BΜTt-1 bZI^z *455nJ4טDa@ +KΎ PUU~�D$\"QnҒ^`շz:xW-G�;DWr09kc @>Aa󥦦bx<~'u gdd;v9%Љ qG0DZZ},7;;+JJJdTszSRPuCfKJ,..vq@jj*E W^z^1nݳgpDoo/^/bccHiRpsN⋰Z� .iz^�)))b0ţ�~0L2q{{|2pyf Ȝpbbp|qwСCeVelܸNG@\{fffbbbPqn'''ׇv<XZZٳgE8rr/__JJ,q՗#eD9v~+++"vQ_$y睨@||<z{{188}k(--JcgíT*arsN])ʈ[4- ȿ---EIIXmadeeٳ�V>,Mm۾4+ɘ4O Dl"o}݇]va޽��|UUuu5}Y͉[|| vfgg911!, … stq>}Zd)~Jei/A6 e]>=wx=N:cee/III8x\a?纬5 oFK.^_8ƊyvvϓH$"'�-܂_|Qfغu:3_V&C4Pddd>q<3/'OJ]DJi":*f(// bcc�ӉH$"ѵ3`E5cyyYbƸFJCP["y@{{{qEkOPUU%H%,O yE:::ۋz+++xD+ -Y3l2dqe0_|yhrr2z) Ie+;J^@�Q `0>'')))x9_ZZXP%`rr(++C }PTY _7qqqB$˓h"WeLL >?O0عs'~Yp�(  z^<ضmvCPRgح(Jjj^{ƍp8,5L萿SQQ*a׮]Y""FAaa!E��B[Gs-ќttt=RjEee  UQVVgy* দ Á@ bDosg3@fbv '%TWWcyyzb(@SxeMI*kSٌފ'|�p1uy0{^7bT*R{�@aaKmmmbͲa{tbE+96mBii)>,Դ ᎘L&q j7?::Vvm2hT*8N\.\{ay]GA__"jJ.ӧR@~шY$9;gnZ-n݊K.ܹs̥ /[oJmmm *J&7oQ}}}B!䬓@yMX,]{tvAׯ t8~8*++Mgź_hhh@AA<]�l t$W0ZM#rJot^R$$$`tt˂ꞙA{{;n7 Dw~TtvvpHp8҂ .ٳ2{HTNŋEPHw}7233(ĉ;6OFbb�0~|yY"httӨ@$-訫<f} yQ8w***ͺLg\t /"6l +g]v=nGBBK/ɟt"&&O<HX,(J /_4J zӃsΡ ccc8z(ڄYH Źewj%,U!QNjX,\.1ab{7v瞓<  ³>+4s-Ař3gVQZZzMc;wb׮]8[('m˅dlذ u?n( w}P[I2z(+ .hkkC$JEuu5jobhhH<px؈ZX~B8CCC2 ST $Q[[;w"-- FQf.�`֭jC}}=J477ˡȌܚ-..btt0 yhWWc ni5bkM6`0T>n"&":>ctwwrPvB෿-Q[[7 Jܹs8td5RݻwoFww GFFʪh011Z fnީ+Wgjj*ӥ$e||\lz="x[SS׋"Ypi&TTT5Fpoq�ۮ./3kZr.hlllZQPPGfIBdSRRpQ̟d2aii wq�ɓ2c}6*C4�d`́5X455GȢ"NZb\RR 1HOO⭷tyy9 Q\\,h!EɰzjjJ%i<뜀aJ7r>??\"f'ۥ8TUUa˖-hllݻeVˬ @<ΧLQM65ݣdzuV$&& x9&&Am+}]h:/Ǐ,jHbffFAD[xAe�cᮻ=܃oY. |>L&8 z�u*FFFpM7a߾}Amm-.lڴIDS annN@n{ q"WݻqM7A#//sssbZQQe,33S<,ϟ?BV9?tӴ>11 �stϕߏR]FQ@:�o[T? Z׃Lua֣u깹{V +!!AܴX,xO}p;@ee%=~p\xPRRe1r8NKR͛7&�twwF*%%^E9~iDʎveeep 6{oO~; !x~~^ k&ϋ<e^YauFb]&UGr B /g+rfx-<ѦF믿~סP(ӃnA}v v;8&$&&h4"!!. b ҂eб+{X08%!//pXd#L&d4ÁX8q�VHNN)A3VU1114ۡj%Sz_DPPF8=ϚjԩSʺ#:ֵDii)Kwnp8�V+9SGG-cccKPÒPf$''# 7z{{EgddHNNZFWWl6rrr!LMMؘH񡨨8ulMD �t:,((&gnn. ў*# Ⱆ3g@R P(DӒZHD-..ܴizBtD"_~1,;I[ftww >Y {#'<p8qt{g ܜ};jX,Ǚ3gfT* łZ477O?E  ^z%deevo-*EEEBJS(l0Egg'u˥=$wY\qhD k8ŋ8(_Tx<lٲGd% gI\.!''* ccc (,,9!+@վCcnnn=W9g J$Eqcq3B__zorr>׿5Q[[6JMME8w�/0="$0<<,p<T BfY$ jl6c011vlذ8u#tۍ!|>nB@aa|&FC-222`$;3OLLB b c\.^pU/7ojFnmۆ7\p80L"%궤ҒK9梢"8 P%%%c0pu$d8fx‚AيFՓI_ȇ~X{999x뭷DJ<x=܃lx^<yRhl>*MIOO "'rP*BC8y`@OO͉`^G}$XiĩX=P\---! '#@~~4J >'H, /A“x'o>,--jȑ#ZFkk+ 5 ##CVApbxϵ*k+Q#%U*ǡht:SSSo .U�_J{E(Z`\,,,_233K@xF>###BX6;; χazzZ`ZDFFu3JLNNʨ?tFQ|d4׈\+FOo^"#֐dBp%ۇo^b\511J˅) v]]]8t萸0:0%� tFGGEI`nnݘ`SRROK'ۋvvA$%%0n˗=J\\n�՜;<yR^jjpr0Ӆ6XXX'oc78׋ ɐ<E$AMM "n7T**NNN(6n(^D|>>|---x<XXXNXf9'1::*X0PȀc 磮3Wx{l0<ln3T{cC%XN<rȚP"@,Ϣ%AL&ݼ<$$$3Q7"BnfM"6ۨjjT*D�V>2c``�B fggӳ[^^ˑp8 )TQHJJi^ӉIݻ|R¶mpeqD,ZvgpsFZZ"߈]Y,AJ0jkk<!ihNuu5FFFuj~F# X=m&A48U3rss?sp)x^dff ( Hp!Hy6<hooVElhGW$l6XVn "//OUH4l__FFF`ZaXpQLLL`˖-8p�V+sϡ& jqQTWW :SSShllu/fY,,,+/apT~ ) cjjUj[[elr�4P-|TYY]]}&gy"E!cCB@ (6:jZJR2mJJ\$dBaa!gTWW@@H7pߏ={Fqq1>LLLe[u-th4tDSQQ2~4СC.BV555){cҥK]D_(#&I45@);)({}g#Ț<p8|U=qpѱn4v'lL[dͱd)}qqSXumct'31Ξ=o~ضm4 v\+++(++fXЍJSmm-fff`Rr6&++ h t:KŴinnFyy9;Z %]}UUFGGv&ZPܽrzE%,\ wefᣏ>xc̼ Ŵ.szzKKKB! Ih4ϟp8,~;W^ рS�b7??/F{f ٳAGG:::p8P\\bݻre5xd]B!ܹsЛ7Ɂ"~t:?gz; ",-@PRR"_>�/m ۊϟhp8,<' OMNNƉ'> <#|@/cffuɘpxͮ;h-92:Nj7`-UhO Suxqvؿ?~??. 5j� nNNN8!L0:A;;v~~NFq *f:O73͆cǎ[njř3gdo^6jjjP]]-H$a9kꖗxPPPi c}r z{{_ܧl6_F.D,&x*Wѣ3*r X�΢b(?33V.+3v;<<$5 uMɓ' F<Ο?/ch`rEl67ސӟSSSxꩧVqixw044 &;8722adffʟ i>~bȈ(@yD>=dee JIV{`@cc] �t{U ����IENDB`��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/zcolorbar.bmp��������������������������������������������������0000755�0001750�0001750�00000001626�10673034556�017501� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM������6���(������ ���������`������������������������������������������������������������������������  #(,16 9##:%%:'':)):++:--:00���������������,D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/reslicing.svg��������������������������������������������������0000755�0001750�0001750�00000020022�11045405514�017461� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="744.09448819" height="1052.3622047" id="svg2" sodipodi:version="0.32" inkscape:version="0.46" sodipodi:docname="reslicing.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" inkscape:export-filename="C:\Documents and Settings\Admin\Desktop\image.png" inkscape:export-xdpi="200" inkscape:export-ydpi="200"> <defs id="defs4"> <inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 526.18109 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="744.09448 : 526.18109 : 1" inkscape:persp3d-origin="372.04724 : 350.78739 : 1" id="perspective10" /> <inkscape:perspective id="perspective2467" inkscape:persp3d-origin="372.04724 : 350.78739 : 1" inkscape:vp_z="744.09448 : 526.18109 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_x="0 : 526.18109 : 1" sodipodi:type="inkscape:persp3d" /> </defs> <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" gridtolerance="10000" guidetolerance="10" objecttolerance="10" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="1.1394642" inkscape:cx="333.03081" inkscape:cy="664.38863" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" inkscape:window-width="1280" inkscape:window-height="740" inkscape:window-x="-4" inkscape:window-y="-4" /> <metadata id="metadata7"> <rdf:RDF> <cc:Work rdf:about=""> <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> </cc:Work> </rdf:RDF> </metadata> <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1"> <rect style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.26454818;stroke-linecap:square;stroke-linejoin:bevel;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="rect3325" width="756.53131" height="369.50735" x="-14.937018" y="178.24945" /> <g id="g3280" transform="translate(-8.7760542,1.1538605e-6)"> <rect ry="48.268299" y="194.79956" x="13.899533" height="298.67014" width="231.09453" id="rect2475" style="opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6.22613287;stroke-linecap:square;stroke-linejoin:bevel;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <rect ry="0" y="259.4205" x="13.138862" height="169.42827" width="232.61589" id="rect3260" style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4.70479012;stroke-linecap:square;stroke-linejoin:bevel;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <image transform="matrix(0.9925462,0.1218693,-0.1218693,0.9925462,0,0)" xlink:href="C:\Documents and Settings\Admin\Desktop\resx2.png" sodipodi:absref="C:\Documents and Settings\Admin\Desktop\resx2.png" width="166.48691" height="123.87494" id="image2469" x="86.945564" y="265.15503" /> </g> <image y="285.70758" x="252.0018" id="image3262" height="123.87494" width="166.48691" sodipodi:absref="C:\Documents and Settings\Admin\Desktop\resx2.png" xlink:href="C:\Documents and Settings\Admin\Desktop\resx2.png" /> <image y="435.22598" x="-423.86765" id="image3264" height="123.87494" width="166.48691" sodipodi:absref="C:\Documents and Settings\Admin\Desktop\resx2.png" xlink:href="C:\Documents and Settings\Admin\Desktop\resx2.png" transform="matrix(0,-1,1,0,0,0)" /> <g id="g3301"> <rect y="245.90759" x="587.1828" height="182.41235" width="143.79771" id="rect3268" style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.42956602999999990;stroke-linecap:square;stroke-linejoin:bevel;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <image style="stroke:#0000ff;stroke-opacity:1;fill:#00d8ff;fill-opacity:1;stroke-width:1.3;stroke-miterlimit:4;stroke-dasharray:none" transform="matrix(0.1218693,-0.9925462,0.9925462,0.1218693,0,0)" xlink:href="C:\Documents and Settings\Admin\Desktop\resx2.png" sodipodi:absref="C:\Documents and Settings\Admin\Desktop\resx2.png" width="166.48691" height="123.87495" id="image3266" x="-337.52261" y="633.31537" /> </g> <flowRoot xml:space="preserve" id="flowRoot3272" style="font-size:36px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" transform="translate(57.044353,-35.135272)"><flowRegion id="flowRegion3274"><rect id="rect3276" width="202.72685" height="78.10688" x="27.205769" y="531.06458" style="font-size:36px" /></flowRegion><flowPara id="flowPara3278">Scan</flowPara></flowRoot> <flowRoot xml:space="preserve" id="flowRoot3285" style="font-size:36px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" transform="translate(256.87221,-35.574725)"><flowRegion id="flowRegion3287"><rect id="rect3289" width="202.72685" height="78.10688" x="27.205769" y="531.06458" style="font-size:36px" /></flowRegion><flowPara id="flowPara3291">Raw</flowPara></flowRoot> <text xml:space="preserve" style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" x="435.41766" y="528.93951" id="text3293"><tspan sodipodi:role="line" id="tspan3295" x="435.41766" y="528.93951">Ortho</tspan></text> <text xml:space="preserve" style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" x="573.07635" y="528.4317" id="text3297"><tspan sodipodi:role="line" id="tspan3299" x="573.07635" y="528.4317">Resliced</tspan></text> </g> </svg> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/info.bmp�������������������������������������������������������0000755�0001750�0001750�00000003036�10673035512�016425� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM������6���(���������������������������������ܾܺܺܺ쮬䶴쪬Z\RTVTVTZ\VTZ\^\jlZ\D*,rtԢjl䲴rt vt쮬vt즤rt쪬tFDD&$ ܺ䲴䊌z|jlVTlBD<&$ Ծ䆄쎌䮬vt d:<4*,侼̬\FDܶ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/penauto.bmp����������������������������������������������������0000755�0001750�0001750�00000003366�10673035036�017154� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM������6���(�����������������������������������������̺бҰҴѼ������������������������������̤{{443333335577CCVVoo⋋ۭ����������������//::33333333333333333333AAuuุ����������bbLLίӡٌ֚ؔۂxxmm\\BB3333==��������㳳<<����������������������̎3333��������ۘ55��??��������������������``33SS��������vv..��������������������33<<ﵵ����������̩;;C[[]������������������MM44������������@@@�������������������44\\������������DDDPPP������bbb����������������GGJJ뼼������������FFF___������???������������������IIAA헗����������IIIeee������000��������������������zz77]]絵��������PPPiii������$$$����������������������̲[[::����iii[[[��������������������������������̗>>{{��PPP�������������������������������{{;;��::: ���������������������������̶llSS驩����222���������������������̮iibb域��������KKK��� ����������������nnzzߵ���������������������������͕إ��������������������������������������������������������������JJJ�������������������������������������������������eee������������������������������������������AAA���FFF������������������������������������������%%%������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/icon.png�������������������������������������������������������0000755�0001750�0001750�00000007537�11041220762�016433� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���@���@���iq���sBIT|d��� pHYs�������tEXtSoftware�www.inkscape.org<��IDATxyygzsoI 0$a$&%8+qB9P1NIr ;(B\B6H"J XTFBJ{fؙ陞?^jvYɛMݩwwR,bo`,bY� }'$N'�rm]3ET3~(r:�*y$Y\pe9҄  JCؘ4S-0~%a�S$A ua @Gy&o:P]lbvg |*  p.^pصzN(H$8oo". ȺEnw]rBPD)\![` c>�DQ$$cK"~r>7,D�]!R Y%e} ;0Rr TM`YP.A?z%[q@pH@sЌ䭧NtY/ZXc2GD 5OP+¬)oRQYQ*0Xtۖ.Ǐ~]n46Li蚧RtlѶܺ}D, A0�t&5,!oa P^L*5J;"T*PBہFj5cb*eCAo5<0=AmGll!N A44,iQLiRU@e%^DTqcYJqWN `(P`0[?ɖsT<s�hU>@Q@NwǞMX{Ff/ Y SH2%Dd�Фl ֨`iBBau@x4Tu(!"k7}=(Ú5`*§mgW"M4"ؘ¤H9ޫ@A܈"A^E1 0_vD $b`3@�f!#TbQlAYg�NTN''oN{ E!S%ɒe1e &0I!ЄSRETPV cUsTqlB*ix4&*h&`dLۺP9�UR"A) a J"ESdɒ'O0S壸<tlM?wQ`�O)Ǔ =(rP*9Ck/0K ĠiO]ZB$A rc1Ƙ#'sD jhAɨtMaKK0QRVa5Dн=y2F ǠgϮ-vo8qtca#CG9cF߷pY3Y6j j,pSGJ04އ`h�& j OŎ|]J߳>Z(C#%ĶӤqQU" >裟~F!G%T[NZ;gӊ~՘-99Y;k>R41Y vos;w JF#٧-J{ꑤL&$ѩQcq(G91dLM;J"H@6W sR);Yáp0gU)]h z<)T=3MI�E D? IN30b9B,EQJ:u]Oe\qʏ*Ǖe8^՘iSASh*&н10^Mxд�?A4b[kk>i„RP8 3,US`�@YCq8z10]w*0&Lr޾>0# x )QbbRr(_ebgW|�^ c}p *PY/x -> b@$@,ƖI%Ӯړl$ZB(c 4qV�OOW/ub9N &@UTi`bR&arfU0|t @+" ?��d2 ,}Q_p:e:$1@�%eIm*2GGR28Eߺk4ma"a!Mp)¯mo}Vq�_K^m`x۳g,13g G sr1VvMۣ~s'LZ֘0<- ,>鹿F7nHGZeڔHns?+BZm�6jMQ" � eA.ǽ(ZJH[ՠfIy+\=P̕ MlUx>Ɲ Tͩ0 "uYB\Br9b[ kW*.dDs1eڼ2)˓<gmZ>U,T`Vp%hbj225e;Â;ޠECw<� bdI6qy�)T,tlݣj NU-k>+H,8Aw  ʋj jXм*3O߳�Mp)*;x/஝Ҁ:5-?s뙊?=8I&L G?c"G0n7I n&oz�d7:|/`-@y{1%hCae{uKjj5vrޗ$<L߀?C4|2 gL+hS* ۞l.$a&/q'k? [<~Q_ *UE7i~"戡wUԪ )iBbaY=B|5_{xogJq6Zt MsMSOG* [5(o4;�!e7¥CڀUg3{J3/xZJ z,dz^ݟ.BmϏ ,�l~.;b:.{F }Â;3~T!߹hn:.H T@>GwnRŅ7,7ǷXa' r)IX@;p+<~ u^C!Xv.DM & "}=V&3@3J{3TYf\y׶,Pl(SM4Mūn(叏QOy{[�!`w3e曑NZunlqze-[p%(סTb<x$󐔔&𺷔�>\sԞQD8LD,f!ݰՑM!"eGgx)I. 3"žl6#J}oSUػ.U=׭s~QJl30v_2mgREʿb/ק19 p崪,R3@HޓVs[&egO> n}s~SJc$ /3<)Ep T kvT8 �ۀ tf(�ɯ Xl9 `7rbo`,bY�Ŗ붗‡"l����IENDB`�����������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/autocontrast.png�����������������������������������������������0000755�0001750�0001750�00000002507�11036745022�020226� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������!-���sBIT|d��� pHYs��n��nKc���tEXtSoftware�www.inkscape.org<��IDATH]lSeue,Jڍ|,($3Fw(\l7\bY"\Hlun0|F?OyRլ;AղtZZ<n]W AEa6<6׊R|i&pP0qfz{zb-P9,ԩдEifff_{R=w[օ=^D8 !gc;}dƍLL˪۷z~w ؟Wv!@(PJE =z{|:>[_|sppp޽zhd3@& ,5J"nߞ|w} 7|,jfR{ 4GTUXX07 ì,�BkΝ8qL<8ԛ% Y(5$u a_|X*Qr\:; A,20L;p8祐|llq�IV 2(5@S]Wkd22x͛7X]Z\i ,!$I,WG$@Ou] |¶pM8/mfVMCmJz8�BHq\ڵ ^IM&Ʋl+!Wu<׎D[uR&x6<d^4-ͦyM,ص3 ςoPFB-P+Ei*f+f+!0 YΣ\.0L8~gddd,^2‡L2tkޗ@4aX (HRV+Cgꬳs-FwS 4睰l} xk׶u]'?Ϟ={'J5.߇n@l<pZ8^ �nݺСCf`6 4+%@A]WAJ)xKݻ7�ʖf"FHeRQ@!Yx-Tjv(f%v=55e<OpîvWECDBXtvdRHdO">?kk[G h4# 6mȑ#\~( Ei,Gݟ07c5鯤y:y<nd2Ar˔G1,o(����IENDB`�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/roiellipse.bmp�������������������������������������������������0000755�0001750�0001750�00000003366�10673035244�017651� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM������6���(���������������������������������������������̧Ԏەٸ����������������������������������́ ==﫫����������������������������QQ qq⹹Р̥EE ��������������������������mmӳCC��mm���������������������� mmtt ����??KK����������������������zz%%̖aa��zz��������������������������OOYY����33 ����������CC��������������������CCgg����WWxccw��������������������������������TTRR�������222��������������������������ccc��������������������������������iii������~~~��>>++^^������������������������~~ ؘ___���rrr��������������������������ff22MMM���99n������������������������������̗CC??L ��� r��������������������������������������NNN(((���+++����������������������������������������SSS+++���!!!����������������������������������������eee333�������������������������������������������}}}666�������������������������������������������"""��������������������������������������������������������������������������������������EEE��������������������������������������������������������������������������������������������������������������������������������������xxx���eee��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/roihide.bmp����������������������������������������������������0000755�0001750�0001750�00000003366�10673035310�017117� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM������6���(�������������������������������������������޶}xݯٵ´������������������������ȱgU٢O{z�z�{b��������������������ȝvzҪQܾd}z�z�ԏ(ė9|Zƾ����������������ʨqfۼB˙y z�މSӪ@ݾɕ4z�z�ܯ������������������˶ym+z kƒYХDz�~ ������������������Ĕ{cK1R ѐ+z�z�F��������������������ǞʿɳrHeEۺSҪ}z�z�z�ڲ����������������������ɭȚM?ԧZ§XVӫqÌފz�z� ����������������������ʼŖf]o*%z�z�z�M������������������������ĔzӷzH/%ϒ/}z�z�ٴ��������������������������ˬ迈fMFl˝HٷJz���������������������������YS=eЧHٸ\z�T����������������������������LۭʜYC0Oz�z�׷����������������������������˿Ϯx^F-z������������������������������ƪ}fZ2{Z��������������������������������ɼ￉ʝbٹt}պ��������������������������������q?ԏď%(����������������������������������ßǗѩQ+m������������������������������������Dz{eN1Կ������������������������������������qœ������������������������������������׽Bщ����������������������������������������ĨܽШ����������������������������������������ȼyw����������������������������������������ῠ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/pen.bmp��������������������������������������������������������0000755�0001750�0001750�00000003366�10673035004�016256� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM������6���(�����������������������������������������̺бҰҴѼ������������������������������̤{{443333335577CCVVoo⋋ۭ����������������//::33333333333333333333AAuuุ����������bbLLίӡٌ֚ؔۂxxmm\\BB3333==��������㳳<<����������������������̎3333��������ۘ55��??��������������������``33SS��������vv..��������������������33<<ﵵ����������̩;;C[[]������������������MM44������������@@@�������������������44\\������������DDDPPP������bbb����������������GGJJ뼼������������FFF___������???������������������IIAA헗����������IIIeee������000��������������������zz77]]絵��������PPPiii������$$$����������������������̲[[::����iii[[[��������������������������������̗>>{{��PPP�������������������������������{{;;��::: ���������������������������̶llSS驩����222���������������������̮iibb域��������KKK��� ��������������̠nnzzߵ���������������������������͕إ��������������������������������������������������������������JJJ�������������������������������������������������eee������������������������������������������AAA���FFF������������������������������������������%%%������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/dti.svg��������������������������������������������������������0000755�0001750�0001750�00000630541�11040224152�016267� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg1141" sodipodi:version="0.32" inkscape:version="0.46" width="210mm" height="297mm" sodipodi:docname="dti.svg" sodipodi:docbase="C:\Documents and Settings\Chris Rorden\Desktop" inkscape:output_extension="org.inkscape.output.svg.inkscape"> <metadata id="metadata413"> <rdf:RDF> <cc:Work rdf:about=""> <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> </cc:Work> </rdf:RDF> </metadata> <defs id="defs1143"> <inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 526.18109 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="744.09448 : 526.18109 : 1" inkscape:persp3d-origin="372.04724 : 350.78739 : 1" id="perspective448" /> <linearGradient id="linearGradient1280"> <stop style="stop-color:#ffc000;stop-opacity:1.0000000;" offset="0.00000000" id="stop1281" /> <stop style="stop-color:#ff0000;stop-opacity:0.50000000;" offset="1.0000000" id="stop1283" /> </linearGradient> <linearGradient id="linearGradient1271"> <stop style="stop-color:#ffc87e;stop-opacity:1.0000000;" offset="0.00000000" id="stop1274" /> <stop style="stop-color:#ff0000;stop-opacity:1.0000000;" offset="1.0000000" id="stop1279" /> </linearGradient> <linearGradient id="linearGradient1270"> <stop style="stop-color:#ffc000;stop-opacity:1.0000000;" offset="0.00000000" id="stop1271" /> <stop style="stop-color:#e84a50;stop-opacity:1.0000000;" offset="0.50000000" id="stop1273" /> <stop style="stop-color:#ff0000;stop-opacity:1.0000000;" offset="1.0000000" id="stop1272" /> </linearGradient> <linearGradient id="linearGradient1608"> <stop style="stop-color:#ffffff;stop-opacity:1.0000000;" offset="0.00000000" id="stop1609" /> <stop style="stop-color:#9999ff;stop-opacity:1.0000000;" offset="0.50000000" id="stop1611" /> <stop style="stop-color:#000000;stop-opacity:1.0000000;" offset="1.0000000" id="stop1610" /> </linearGradient> <linearGradient id="linearGradient1563"> <stop style="stop-color:#898bdc;stop-opacity:1.0000000;" offset="0.00000000" id="stop1564" /> <stop style="stop-color:#000000;stop-opacity:1.0000000;" offset="1.0000000" id="stop1565" /> </linearGradient> <linearGradient id="linearGradient1547"> <stop style="stop-color:#9999ff;stop-opacity:1.0000000;" offset="0.00000000" id="stop1548" /> <stop style="stop-color:#9999fd;stop-opacity:0.00000000;" offset="1.0000000" id="stop1549" /> </linearGradient> <linearGradient id="linearGradient1391"> <stop style="stop-color:#ffc000;stop-opacity:1.0000000;" offset="0.00000000" id="stop1392" /> <stop style="stop-color:#ff0000;stop-opacity:1.0000000;" offset="1.0000000" id="stop1394" /> </linearGradient> <linearGradient id="linearGradient1111"> <stop style="stop-color:#e8e838;stop-opacity:1.0000000;" offset="0.00000000" id="stop1112" /> <stop style="stop-color:#ffff7f;stop-opacity:1.0000000;" offset="1.0000000" id="stop1114" /> </linearGradient> <linearGradient id="linearGradient1274"> <stop style="stop-color:#ff0400;stop-opacity:1.0000000;" offset="0.00000000" id="stop1275" /> <stop style="stop-color:#fd6972;stop-opacity:1.0000000;" offset="0.0099999998" id="stop1277" /> <stop style="stop-color:#ff0000;stop-opacity:1.0000000;" offset="1.0000000" id="stop1276" /> </linearGradient> <linearGradient id="linearGradient1205"> <stop style="stop-color:#ffffff;stop-opacity:0.9;" offset="0.00000000" id="stop1206" /> <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1.00000000" id="stop1207" /> </linearGradient> <linearGradient id="linearGradient1172"> <stop style="stop-color:#ffffff;stop-opacity:0.3;" offset="0.00000000" id="stop1173" /> <stop style="stop-color:#ffffff;stop-opacity:0.8;" offset="1.00000000" id="stop1174" /> </linearGradient> <linearGradient id="linearGradient969"> <stop style="stop-color:#ffffff;stop-opacity:0.70196080;" offset="0.00000000" id="stop970" /> <stop style="stop-color:#9999ff;stop-opacity:0.70196080;" offset="1.0000000" id="stop971" /> </linearGradient> <linearGradient id="linearGradient684"> <stop style="stop-color:#ffffff;stop-opacity:1.0000000;" offset="0.00000000" id="stop685" /> <stop style="stop-color:#9999ff;stop-opacity:1.0000000;" offset="1.0000000" id="stop686" /> </linearGradient> <linearGradient id="linearGradient671"> <stop style="stop-color:#ffffff;stop-opacity:1.0000000;" offset="0.00000000" id="stop672" /> <stop style="stop-color:#ffffff;stop-opacity:0.00000000;" offset="1.0000000" id="stop673" /> </linearGradient> <linearGradient id="linearGradient594"> <stop style="stop-color:#fffbfb;stop-opacity:1.0000000;" offset="0.00000000" id="stop595" /> <stop style="stop-color:#0000c0;stop-opacity:1;" offset="1" id="stop596" /> </linearGradient> <linearGradient id="linearGradient1155"> <stop style="stop-color:#fffbfb;stop-opacity:1.0000000;" offset="0.00000000" id="stop1156" /> <stop style="stop-color:#9999ff;stop-opacity:1.0000000;" offset="1.0000000" id="stop1157" /> </linearGradient> <radialGradient xlink:href="#linearGradient1155" id="radialGradient1158" cx="0.21874997" cy="0.23437454" r="0.70745194" fx="0.21874997" fy="0.23437454" /> <radialGradient xlink:href="#linearGradient684" id="radialGradient1169" cx="0.77941167" cy="0.65624988" r="0.32758817" fx="0.77941167" fy="0.65624988" /> <linearGradient xlink:href="#linearGradient1155" id="linearGradient1170" x1="0.81756759" y1="0.35156253" x2="0.17567571" y2="0.75000000" /> <linearGradient xlink:href="#linearGradient594" id="linearGradient588" x1="321.4625" y1="541.3602" x2="354.41388" y2="556.75934" gradientTransform="scale(0.8041446,1.2435574)" gradientUnits="userSpaceOnUse" /> <linearGradient xlink:href="#linearGradient1547" id="linearGradient639" x1="0.47535211" y1="-0.11428571" x2="0.58802819" y2="0.96190476" /> <linearGradient xlink:href="#linearGradient1155" id="linearGradient643" x1="0.20312500" y1="0.10687023" x2="0.50000000" y2="0.88549620" /> <linearGradient xlink:href="#linearGradient1563" id="linearGradient670" x1="0.15079366" y1="0.11450382" x2="0.71428573" y2="0.42748091" /> <linearGradient xlink:href="#linearGradient684" id="linearGradient683" x1="0.39084506" y1="-0.06603774" x2="0.59859157" y2="0.94339621" /> <linearGradient xlink:href="#linearGradient1608" id="linearGradient701" x1="0.0035211267" y1="0.42574257" x2="0.98591548" y2="0.42574257" /> <linearGradient xlink:href="#linearGradient671" id="linearGradient703" x1="0.45070422" y1="-0.93750000" x2="0.44366196" y2="1.21875000" /> <radialGradient xlink:href="#linearGradient1271" id="radialGradient704" cx="292.27442" cy="807.81573" r="24.522423" fx="292.27442" fy="807.81573" gradientUnits="userSpaceOnUse" /> <linearGradient xlink:href="#linearGradient969" id="linearGradient967" x1="0.39297354" y1="0.06249970" x2="0.46580359" y2="0.96093768" /> <linearGradient xlink:href="#linearGradient684" id="linearGradient968" x1="0.08771923" y1="0.02343778" x2="0.55263156" y2="1.32031250" /> <linearGradient xlink:href="#linearGradient671" id="linearGradient1138" x1="0.50000000" y1="0.05468750" x2="0.71717173" y2="1.70312500" /> <linearGradient xlink:href="#linearGradient671" id="linearGradient1139" x1="-0.45833334" y1="0.19531250" x2="1.12500000" y2="0.71875000" /> <radialGradient xlink:href="#linearGradient969" id="radialGradient1140" cx="0.11029412" cy="0.06250000" r="1.26334059" fx="0.11029412" fy="0.06250000" /> <linearGradient xlink:href="#linearGradient1172" id="linearGradient1175" x1="0.91071421" y1="0.53906387" x2="0.46428558" y2="0.77343899" /> <linearGradient xlink:href="#linearGradient684" id="linearGradient1202" x1="0.16197200" y1="-0.11904722" x2="0.32746491" y2="1.99999797" /> <radialGradient xlink:href="#linearGradient684" id="radialGradient1203" cx="0.77941167" cy="0.65624988" r="0.32758817" fx="0.77941167" fy="0.65624988" /> <radialGradient xlink:href="#linearGradient1547" id="radialGradient983" cx="0.73913020" cy="0.72519094" r="0.22669560" fx="0.73913020" fy="0.72519094" /> <radialGradient xlink:href="#linearGradient1205" id="radialGradient1066" cx="0.76470590" cy="0.76562488" r="0.29453236" fx="0.76470590" fy="0.76562482" /> <linearGradient xlink:href="#linearGradient1274" id="linearGradient1273" x1="-0.019230817" y1="-3.8570047e-008" x2="0.51923072" y2="0.87500006" /> <linearGradient xlink:href="#linearGradient1280" id="linearGradient1110" x1="459.4994" y1="1254.0935" x2="481.37598" y2="1325.9788" gradientTransform="matrix(1.6468933,0,0,0.6072039,-185.20999,91.717409)" gradientUnits="userSpaceOnUse" /> <linearGradient xlink:href="#linearGradient1111" id="linearGradient1118" x1="0.53521127" y1="1.0151515" x2="0.52816904" y2="0.015151516" /> <radialGradient xlink:href="#linearGradient1391" id="radialGradient1395" cx="0.69533569" cy="0.78121674" r="0.68209499" fx="0.69533557" fy="0.76559359" /> <radialGradient xlink:href="#linearGradient1547" id="radialGradient1442" cx="291.17355" cy="815.41846" r="18.939451" fx="290.62314" fy="814.83362" /> <linearGradient xlink:href="#linearGradient684" id="linearGradient1604" x1="0.52343750" y1="0.0076335878" x2="1.0312500" y2="1.1297710" /> <linearGradient xlink:href="#linearGradient684" id="linearGradient1617" x1="0.10920641" y1="-0.40239441" x2="1.2083132" y2="1.9653628" /> <linearGradient xlink:href="#linearGradient684" id="linearGradient1618" x1="0.42672610" y1="-0.31047121" x2="1.0007051" y2="2.1198800" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="radialGradient3181" cx="289.25905" cy="812.97649" fx="289.25905" fy="812.97649" r="16.96986" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="linearGradient3271" x1="299.8437" y1="1036.9841" x2="305.62924" y2="1092.2429" gradientTransform="matrix(1.646893,0,0,0.607204,-404.3959,232.2467)" gradientUnits="userSpaceOnUse" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="radialGradient3289" cx="289.25905" cy="812.97649" fx="289.25905" fy="812.97649" r="16.96986" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="linearGradient4195" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.646893,0,0,0.607204,-404.3959,232.2467)" x1="299.8437" y1="1036.9841" x2="305.62924" y2="1092.2429" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="radialGradient4197" gradientUnits="userSpaceOnUse" cx="289.25905" cy="812.97649" fx="289.25905" fy="812.97649" r="16.96986" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="linearGradient4209" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.646893,0,0,0.607204,-404.3959,232.2467)" x1="299.8437" y1="1036.9841" x2="305.62924" y2="1092.2429" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="radialGradient4211" gradientUnits="userSpaceOnUse" cx="289.25905" cy="812.97649" fx="289.25905" fy="812.97649" r="16.96986" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="linearGradient4223" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.646893,0,0,0.607204,-404.3959,232.2467)" x1="299.8437" y1="1036.9841" x2="305.62924" y2="1092.2429" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="radialGradient4225" gradientUnits="userSpaceOnUse" cx="289.25905" cy="812.97649" fx="289.25905" fy="812.97649" r="16.96986" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1172" id="linearGradient3598" x1="339.63678" y1="379.11596" x2="335.35134" y2="381.36582" gradientTransform="matrix(0.758349,0,0,1.3186542,-197.63622,-8.8758783)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient3600" x1="588.89265" y1="195.07545" x2="612.58524" y2="202.90803" gradientTransform="matrix(0.4268666,0,0,2.3426521,-197.63622,-8.8758783)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient3627" x1="833.72519" y1="196.49355" x2="857.41778" y2="204.32614" gradientTransform="matrix(0.4268666,0,0,2.3426521,-108.85068,2.4284606)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1172" id="linearGradient3629" x1="477.45044" y1="381.63529" x2="473.165" y2="383.88514" gradientTransform="matrix(0.758349,0,0,1.3186542,-108.85068,2.4284606)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1608" id="linearGradient3646" x1="-196.8662" y1="425.48517" x2="-141.23934" y2="425.48517" gradientTransform="matrix(1.677741,0,0,0.5960396,144.06957,-177.72971)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient684" id="linearGradient3670" x1="326.75421" y1="743.24066" x2="335.31547" y2="852.86278" gradientTransform="scale(1.7571663,0.5690981)" gradientUnits="userSpaceOnUse" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient969" id="radialGradient3672" cx="524.70152" cy="475.22645" fx="524.70152" fy="475.22645" r="111.10576" gradientTransform="matrix(1.075993,0,0,0.9293741,-172.89681,-540.25849)" gradientUnits="userSpaceOnUse" /> <inkscape:perspective id="perspective2865" inkscape:persp3d-origin="372.04724 : 350.78739 : 1" inkscape:vp_z="744.09448 : 526.18109 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_x="0 : 526.18109 : 1" sodipodi:type="inkscape:persp3d" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient3657" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4268666,0,0,2.3426521,490.80166,-298.10221)" x1="833.72519" y1="196.49355" x2="857.41778" y2="204.32614" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1172" id="linearGradient3659" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.758349,0,0,1.3186542,490.80166,-298.10221)" x1="477.45044" y1="381.63529" x2="473.165" y2="383.88514" /> </defs> <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="1.6899736" inkscape:cx="259.81914" inkscape:cy="210.13786" inkscape:window-width="1096" inkscape:window-height="885" inkscape:window-x="2" inkscape:window-y="-2" showgrid="true" snaptogrid="false" showguides="true" snaptoguides="true" inkscape:current-layer="svg1141" inkscape:snap-global="false" gridtolerance="23"> <inkscape:grid type="xygrid" id="grid3676" visible="true" enabled="true" /> </sodipodi:namedview> <rect style="fill:#cccccc;fill-rule:evenodd;stroke:#000000;stroke-width:2.26807213pt" id="rect1183" width="802.11261" height="680.2215" x="-643.42822" y="163.21796" /> <rect style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:2.3750000;" id="rect1295" width="69.963570" height="45.246185" x="-101.75949" y="509.82691" transform="scale(-1.000000,1.000000)" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:2.3750000;fill-opacity:1.0000000;" id="rect1262" width="69.963570" height="45.246185" x="128.72227" y="535.48883" transform="translate(-91.26626,99.11160)" /> <path sodipodi:type="arc" style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt;" id="path1286" sodipodi:cx="88.389725" sodipodi:cy="698.28027" sodipodi:rx="18.305565" sodipodi:ry="18.305565" d="M 106.69529 698.28027 A 18.305565 18.305565 0 1 0 70.084160,698.28027 A 18.305565 18.305565 0 1 0 106.69529 698.28027 z" transform="translate(-17.25953,-39.22624)" /> <path sodipodi:type="arc" style="fill-rule:evenodd;stroke-width:1.0000000pt;" id="path1573" sodipodi:cx="496.47308" sodipodi:cy="894.01904" sodipodi:rx="26.543070" sodipodi:ry="26.543070" d="M 523.01615 894.01904 A 26.543070 26.543070 0 1 0 469.93001,894.01904 A 26.543070 26.543070 0 1 0 523.01615 894.01904 z" transform="translate(185.5400,-212.9984)" /> <path sodipodi:type="arc" style="fill:url(#radialGradient1395);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;" id="path1343" sodipodi:cx="715.48608" sodipodi:cy="436.77219" sodipodi:rx="38.180180" sodipodi:ry="38.180180" d="M 753.66626 436.77219 A 38.180180 38.180180 0 1 0 677.30590,436.77219 A 38.180180 38.180180 0 1 0 753.66626 436.77219 z" transform="matrix(0.905654,0.000000,0.000000,0.919132,149.4257,12.54474)" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.0375195;" d="M 704.48491,415.34092 C 694.57329,417.80874 687.95315,428.45052 684.92534,434.86193 C 681.89753,441.01182 677.92934,447.28914 688.65031,452.73194 C 698.87767,454.00139 705.70466,453.64762 711.13899,450.11964 C 718.44814,445.58571 724.25946,439.88285 726.48955,434.60790 C 727.94598,431.77023 741.08206,432.37026 740.21539,430.37826 C 740.33314,426.85776 739.63744,419.26753 731.65870,414.99087 C 727.35252,412.29016 710.27910,412.15675 704.48491,415.34092 z " id="path1377" sodipodi:nodetypes="czcccccc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 175.16419,313.27629 C 170.59785,312.81843 161.53978,318.62958 157.57044,321.02629 C 146.72186,327.57680 135.88296,343.93132 135.88294,360.30754 C 135.88294,364.40161 132.43921,368.00533 137.35169,380.80754 C 143.39531,391.81829 170.06959,395.25262 170.28919,388.46379 C 170.50878,381.67497 166.19786,385.04854 171.50794,379.87004 C 171.67000,389.89820 175.12385,390.07619 174.97669,395.99504 C 174.88252,399.52179 174.69106,407.40659 176.03919,406.05754 L 177.97669,406.37004 L 177.97669,406.49504 L 178.35169,406.43254 L 180.28919,406.12004 C 181.63732,407.46909 181.44586,399.58428 181.35169,396.05754 C 181.20453,390.13869 184.65838,389.96069 184.82044,379.93254 C 190.13052,385.11104 185.81960,381.73746 186.03919,388.52629 C 186.25879,395.31512 212.93307,391.88078 218.97669,380.87004 C 223.88917,368.06783 220.44544,364.46410 220.44544,360.37004 C 220.44542,343.99382 209.60652,327.63929 198.75794,321.08879 C 194.78860,318.69208 185.73053,312.88092 181.16419,313.33879 C 179.64208,313.49141 178.61613,314.33756 178.44544,316.24504 L 177.64117,368.62731 L 177.88294,316.18254 C 177.71225,314.27507 176.68630,313.42891 175.16419,313.27629 z " id="path1150" sodipodi:nodetypes="ccccccccccccccccccccccc" /> <path style="fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:0.68412900pt;" d="M 182.78509,493.16200 C 171.13638,496.94695 136.68072,486.89726 135.94501,503.73375 C 135.20931,520.57025 224.59784,516.52427 212.45865,506.21355 C 200.31947,495.90282 194.43381,489.37705 182.78509,493.16200 z " id="path1140" sodipodi:nodetypes="cczz" /> <g id="g1263" transform="matrix(0.908672,-0.417511,0.685493,0.785541,-67.19158,231.4487)"> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.99068832pt;" d="M 420.68026,157.78820 C 420.68026,143.66413 411.49144,115.33358 402.38342,106.84266 C 393.27539,98.351740 375.11992,98.368210 366.03210,106.84266 C 356.94426,115.31711 347.85643,143.56526 347.85643,157.68934 C 347.85643,171.81342 356.94426,185.93749 366.03210,191.58713 C 375.11992,197.23676 393.27539,197.22028 402.38342,191.58713 C 411.49144,185.95397 420.68026,171.91228 420.68026,157.78820 z " id="path1235" sodipodi:nodetypes="czzzzzz" transform="matrix(0.937345,0.000000,-0.521597,0.915342,214.7080,20.05502)" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.90746355pt;" d="M 385.72466,104.99534 C 385.60653,104.99531 385.49150,105.02296 385.37337,105.02434 L 385.37337,105.05334 C 385.28545,105.04542 385.19871,105.02430 385.10991,105.02434 C 384.90297,105.02441 384.70203,105.07794 384.49516,105.08234 L 384.49516,105.19833 C 384.36904,105.18166 384.24249,105.16937 384.11460,105.16933 C 384.02579,105.16930 383.93906,105.19041 383.85113,105.19833 L 383.85113,105.16933 C 383.73301,105.16796 383.61798,105.14030 383.49985,105.14033 C 377.27858,105.14222 371.05063,107.10435 366.90157,110.99791 C 364.82705,112.94468 352.95338,129.00036 356.94846,131.76041 C 366.89106,139.03386 375.51079,117.62287 366.31609,135.38515 C 365.38960,141.48619 365.15147,144.66736 365.08659,146.25937 C 364.95557,143.34300 363.87193,136.50278 358.17796,133.18131 C 353.42130,130.46368 350.30330,154.46891 350.30330,157.71354 C 350.30330,170.69209 358.60347,183.66588 366.90157,188.85730 C 371.11000,191.49017 377.45333,192.75392 383.76331,192.71402 L 383.76331,192.74302 C 384.08594,192.74567 384.40678,192.71814 384.72935,192.71402 L 384.72935,192.56903 C 384.97331,192.57837 385.21671,192.60006 385.46120,192.59803 L 385.46120,192.56903 C 391.77118,192.60893 398.11451,191.34520 402.32294,188.71231 C 410.62104,183.52089 418.92121,170.54709 418.92121,157.56855 C 418.92121,154.32392 415.80320,130.31868 411.04655,133.03632 C 405.35258,136.35779 404.26894,143.19801 404.13792,146.11438 C 404.07304,144.52237 403.83491,141.34119 402.90841,135.24016 C 393.71372,117.47788 402.33345,138.88886 412.27605,131.61542 C 416.27113,128.85537 404.39746,112.79968 402.32294,110.85292 C 398.17388,106.95936 391.94593,104.99722 385.72466,104.99534 z " id="path1236" transform="matrix(0.937345,0.000000,-0.521597,0.915342,214.7080,20.05502)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.90746355pt;" d="M 380.33827,131.91200 C 380.67980,131.22522 379.75424,123.78448 378.33933,121.86149 C 376.92442,119.93850 374.82503,120.78615 374.48350,121.47293 C 374.14198,122.15971 376.25321,121.24535 377.66811,123.16834 C 379.08302,125.09132 379.99675,132.59878 380.33827,131.91200 z " id="path1237" sodipodi:nodetypes="czzzz" transform="matrix(0.937345,0.000000,-0.521597,0.915342,214.7080,20.05502)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.76453004pt;" d="M 374.01970,170.64672 C 371.03955,170.35930 370.44378,163.47294 368.37466,167.67389 C 366.21050,171.94993 370.67043,181.11939 371.06278,176.38002 C 371.36008,171.64067 376.90481,171.00921 374.01970,170.64672 z " id="path1238" sodipodi:nodetypes="czzz" transform="matrix(0.937345,0.000000,-0.521597,0.915342,214.7080,20.05502)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.90746355pt;" d="M 388.88624,131.76953 C 388.54471,131.08274 389.47027,123.64200 390.88518,121.71902 C 392.30008,119.79602 394.39948,120.64367 394.74101,121.33045 C 395.08253,122.01724 392.97130,121.10288 391.55640,123.02586 C 390.14149,124.94885 389.22776,132.45631 388.88624,131.76953 z " id="path1239" sodipodi:nodetypes="czzzz" transform="matrix(0.937345,0.000000,-0.521597,0.915342,214.7080,20.05502)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.76453004pt;" d="M 395.20481,170.50425 C 398.18496,170.21683 398.78073,163.33046 400.84985,167.53142 C 403.01401,171.80746 398.55408,180.97692 398.16173,176.23755 C 397.86443,171.49819 392.31970,170.86674 395.20481,170.50425 z " id="path1240" sodipodi:nodetypes="czzz" transform="matrix(0.937345,0.000000,-0.521597,0.915342,214.7080,20.05502)" /> </g> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:1.2724125pt;" d="M 496.61025,315.43263 C 487.70277,315.43523 472.41769,322.55172 466.47718,327.89823 C 454.59613,338.59121 447.94047,366.42388 447.94047,384.24553 C 447.94047,389.67769 447.95637,395.00686 448.18560,400.13622 L 542.84637,400.13622 C 543.08751,395.05165 543.13236,389.79833 543.13236,384.40325 C 543.13232,366.58163 539.47657,339.72728 527.56914,329.01351 C 521.61543,323.65662 505.51773,315.43003 496.61025,315.43263 z " id="path1063" sodipodi:nodetypes="cccccccc" /> <path style="fill-rule:evenodd;stroke:none;stroke-width:0.91963024pt;" d="M 342.97890,399.86026 L 434.73342,400.51279 L 433.34799,392.09524 C 432.07595,388.11087 427.72724,383.73612 426.88022,379.25826 C 425.59125,374.78040 431.80349,377.65786 431.05395,370.30329 C 430.30440,362.94871 428.89800,343.42434 418.26686,333.11605 C 407.32322,323.12026 398.18407,316.70378 378.78742,319.85497 C 360.64077,321.75616 350.23069,330.41956 342.83093,345.70413 C 335.23979,360.98870 343.64369,380.00725 343.40504,387.13431 L 342.97890,399.86026 z " id="path1052" sodipodi:nodetypes="ccczzzzzzc" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.99068832pt;" d="M 320.29479,372.55062 C 320.29479,358.42655 311.10597,330.09600 301.99795,321.60508 C 292.88992,313.11416 274.73445,313.13063 265.64663,321.60508 C 256.55879,330.07953 247.47096,358.32768 247.47096,372.45176 C 247.47096,386.57584 256.55879,400.69991 265.64663,406.34955 C 274.73445,411.99918 292.88992,411.98270 301.99795,406.34955 C 311.10597,400.71639 320.29479,386.67470 320.29479,372.55062 z " id="path1005" sodipodi:nodetypes="czzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.90746355pt;fill-opacity:1.0000000;" d="M 285.33919,319.75776 C 285.22106,319.75773 285.10603,319.78538 284.98790,319.78676 L 284.98790,319.81576 C 284.89998,319.80784 284.81324,319.78672 284.72444,319.78676 C 284.51750,319.78683 284.31656,319.84036 284.10969,319.84476 L 284.10969,319.96075 C 283.98357,319.94408 283.85702,319.93179 283.72913,319.93175 C 283.64032,319.93172 283.55359,319.95283 283.46566,319.96075 L 283.46566,319.93175 C 283.34754,319.93038 283.23251,319.90272 283.11438,319.90275 C 276.89311,319.90464 270.66516,321.86677 266.51610,325.76033 C 264.44158,327.70710 252.56791,343.76278 256.56299,346.52283 C 266.50559,353.79628 275.12532,332.38529 265.93062,350.14757 C 265.00413,356.24861 264.76600,359.42978 264.70112,361.02179 C 264.57010,358.10542 263.48646,351.26520 257.79249,347.94373 C 253.03583,345.22610 249.91783,369.23133 249.91783,372.47596 C 249.91783,385.45451 258.21800,398.42830 266.51610,403.61972 C 270.72453,406.25259 277.06786,407.51634 283.37784,407.47644 L 283.37784,407.50544 C 283.70047,407.50809 284.02131,407.48056 284.34388,407.47644 L 284.34388,407.33145 C 284.58784,407.34079 284.83124,407.36248 285.07573,407.36045 L 285.07573,407.33145 C 291.38571,407.37135 297.72904,406.10762 301.93747,403.47473 C 310.23557,398.28331 318.53574,385.30951 318.53574,372.33097 C 318.53574,369.08634 315.41773,345.08110 310.66108,347.79874 C 304.96711,351.12021 303.88347,357.96043 303.75245,360.87680 C 303.68757,359.28479 303.44944,356.10361 302.52294,350.00258 C 293.32825,332.24030 301.94798,353.65128 311.89058,346.37784 C 315.88566,343.61779 304.01199,327.56210 301.93747,325.61534 C 297.78841,321.72178 291.56046,319.75964 285.33919,319.75776 z " id="path1044" /> <path sodipodi:type="arc" style="font-size:12;fill:#fffffd;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.875;stroke-dasharray:none;" id="path695" sodipodi:cx="271.35836792" sodipodi:cy="796.11926270" sodipodi:rx="37.42873764" sodipodi:ry="37.42873764" d="M 308.787106 796.119263 A 37.428738 37.428738 0 1 0 233.929630,796.119263 A 37.4287 37.4287 0 1 0 308.787 796.119 L 271.358368 796.119263 z" transform="matrix(1.269231,0.000000,0.000000,1.209574,152.3260,-283.6191)" /> <path sodipodi:type="arc" style="font-size:12;fill:url(#linearGradient1202);fill-opacity:0.75;fill-rule:evenodd;stroke:#0050fb;stroke-width:2.47293;stroke-dasharray:none;stroke-opacity:1;" id="path1200" sodipodi:cx="604.88873291" sodipodi:cy="441.20190430" sodipodi:rx="44.21426392" sodipodi:ry="13.48378277" d="M 649.102997 441.201904 A 44.214264 13.483783 0 1 0 560.674469,441.201904 A 44.2143 13.4838 0 1 0 649.103 441.202 L 604.888733 441.201904 z" transform="matrix(1.042553,0.000000,0.000000,0.882208,-29.50271,47.34934)" inkscape:export-filename="C:\pas\mricron\btn\path.png" inkscape:export-xdpi="21.807127" inkscape:export-ydpi="21.807127" /> <path style="font-size:12;fill-opacity:0.70196;stroke:#1c66f9;stroke-width:9.25243;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99;fill:url(#linearGradient968);" d="M -49.21 243.091 C -46.9287 238.079 -38.9781 233.065 -32.1615 233.824 L 173.669 267.357 C 189.611 256.808 212.948 243.966 237.003 247.181 L 271.976 250.84 L 316.171 257.383 C 341.971 263.24 362.36 275.405 364.498 299.613 L 364.227 591.258 L -50.8332 491.502 L -49.21 243.091 z " id="path10" transform="matrix(0.180587,0.000000,0.000000,0.239519,475.9239,473.8713)" sodipodi:nodetypes="cccccccccc" /> <rect style="font-size:12;fill:none;fill-opacity:0.25;fill-rule:evenodd;stroke-width:0.0937284;stroke-opacity:0.53137;" id="rect1408" x="0.001633" y="142.499995" width="14.998365" height="14.994604" rx="0" ry="0" transform="matrix(15.78489,0.000000,0.000000,15.78489,215.6082,-1931.463)" /> <rect style="font-size:12;fill:none;fill-rule:evenodd;stroke-width:0.0520834;" id="rect702" width="25.000004" height="24.999990" x="24.999998" y="219.999988" transform="matrix(14.81984,0.000000,0.000000,14.99259,-23.10420,-2817.060)" /> <path style="font-size:12;fill:url(#linearGradient588);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.47847000000000001pt" d="M 260,712.36218 C 260.6888,710.6402 290,637.36218 290,637.36218 L 318.17786,717.86525 C 318.17786,717.86525 305,722.36218 290,722.36218 C 270,722.36218 259.65561,712.36218 260,712.36218 z" id="path593" sodipodi:nodetypes="ccczc" inkscape:export-filename="C:\pas\mricron\btn\new\magichat.png" inkscape:export-xdpi="25.411764" inkscape:export-ydpi="25.411764" /> <polygon sodipodi:type="star" style="font-size:12;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="polygon597" sodipodi:sides="6" sodipodi:cx="240.40767073" sodipodi:cy="577.30510872" sodipodi:r1="15.40403841" sodipodi:r2="7.70201920" sodipodi:arg1="0.65284663" sodipodi:arg2="1.17644541" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0.000000,0.000000,0.478471,170.7767,389.9823)" inkscape:export-filename="C:\pas\mricron\btn\new\magichat.png" inkscape:export-xdpi="22.14864" inkscape:export-ydpi="22.14864" /> <polygon sodipodi:type="star" style="font-size:12;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="polygon598" sodipodi:sides="6" sodipodi:cx="240.40767073" sodipodi:cy="577.30510872" sodipodi:r1="15.40403841" sodipodi:r2="7.70201920" sodipodi:arg1="0.65284663" sodipodi:arg2="1.17644541" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0.000000,0.000000,0.478471,161.8224,423.0443)" inkscape:export-filename="C:\pas\mricron\btn\new\magichat.png" inkscape:export-xdpi="22.14864" inkscape:export-ydpi="22.14864" /> <polygon sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon599" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,180.82663,405.61557)" inkscape:export-filename="C:\pas\mricron\btn\new\magichat.png" inkscape:export-xdpi="22.14864" inkscape:export-ydpi="22.14864" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z" /> <polygon sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon600" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,183.55602,422.73609)" inkscape:export-filename="C:\pas\mricron\btn\new\magichat.png" inkscape:export-xdpi="22.14864" inkscape:export-ydpi="22.14864" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z" /> <polygon sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon601" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,166.77658,438.30666)" inkscape:export-filename="C:\pas\mricron\btn\new\magichat.png" inkscape:export-xdpi="22.14864" inkscape:export-ydpi="22.14864" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z" /> <polygon sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon602" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,191.38779,434.54077)" inkscape:export-filename="C:\pas\mricron\btn\new\magichat.png" inkscape:export-xdpi="22.14864" inkscape:export-ydpi="22.14864" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z" /> <path style="font-size:12;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt;" d="M 274.11717,675.42762 C 272.59006,680.51787 272.50982,680.74799 270.97720,685.84931 L 272.11357,689.70698 L 274.49097,685.80445 L 278.91683,686.88101 L 276.71885,682.87382 L 279.87377,679.56938 L 275.31334,679.47966 L 274.11717,675.42762 z " id="path605" inkscape:export-filename="C:\pas\mricron\btn\new\magichat.png" inkscape:export-xdpi="22.14864" inkscape:export-ydpi="22.14864" /> <path style="font-size:12;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt;" d="M 292.16411,644.27745 L 290.93802,646.28105 L 286.49722,645.20449 L 288.69519,649.21168 L 285.55523,652.51612 L 290.11565,652.60584 L 291.40154,656.98683 L 293.77894,653.08431 L 295.40874,653.48802 L 292.16411,644.27745 z " id="path608" inkscape:export-xdpi="22.14864" inkscape:export-ydpi="22.14864" inkscape:export-filename="C:\pas\mricron\btn\new\magichat.png" /> <path sodipodi:type="arc" style="font-size:12;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.875;stroke-dasharray:none;" id="path651" sodipodi:cx="271.35836792" sodipodi:cy="796.11926270" sodipodi:rx="37.42873764" sodipodi:ry="37.42873764" d="M 308.787106 796.119263 A 37.428738 37.428738 0 1 0 233.929630,796.119263 A 37.4287 37.4287 0 1 0 308.787 796.119 L 271.358368 796.119263 z" transform="matrix(1.269231,0.000000,0.000000,1.209574,-61.55729,-176.8490)" inkscape:export-filename="C:\pas\mricron\btn\new\autocontrast.png" inkscape:export-xdpi="22.289494" inkscape:export-ydpi="22.289494" /> <path style="font-size:12;fill:url(#linearGradient670);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-opacity:1;" d="M 295.69152,743.03173 L 295.69152,775.76582 L 271.65546,775.76582 L 271.65546,765.25764 C 271.65546,765.25764 271.67456,765.22685 247.26244,785.85819 L 271.13984,805.28697 L 271.13984,795.57258 L 295.69152,795.57258 L 295.69152,829.28944 C 315.20163,823.65675 329.48478,806.54705 329.48479,786.12279 C 329.48480,765.70248 315.19580,748.66784 295.69152,743.03173 z " id="path669" inkscape:export-filename="C:\pas\mricron\btn\new\autocontrast.png" inkscape:export-xdpi="22.289494" inkscape:export-ydpi="22.289494" /> <path style="font-size:12;fill:url(#linearGradient1170);fill-rule:evenodd;stroke:#000054;stroke-width:0.67086999999999997;stroke-linejoin:round;stroke-opacity:1" d="M 37.736449,210.52722 C 39.360943,210.15769 40.548315,209.21204 41.638551,208.17037 C 42.631649,207.06469 43.624746,205.57494 43.986449,204.08519 L 35.819276,193.99093 L 26.486449,203.31704 L 37.736449,210.52722 z " id="path709" sodipodi:nodetypes="cccccc" transform="matrix(4.130527,0.000000,0.000000,4.178675,143.9011,-279.6922)" inkscape:export-filename="C:\pas\mricron\btn\new\bucket24x.png" inkscape:export-xdpi="22.773436" inkscape:export-ydpi="22.773436" /> <path sodipodi:type="arc" style="font-size:12;fill:#f5f9ff;fill-rule:evenodd;stroke:#000054;stroke-width:10.78609999999999900;stroke-opacity:1" id="path587" sodipodi:cx="220.25373840" sodipodi:cy="529.07958984" sodipodi:rx="44.62657547" sodipodi:ry="78.45639801" d="M 264.880314 529.079590 A 44.626575 78.456398 0 1 0 175.627163,529.079590 A 44.6266 78.4564 0 1 0 264.88 529.08 L 220.253738 529.079590 z" transform="matrix(0.261130,0.000000,-0.220403,0.255703,330.6188,414.5732)" inkscape:export-filename="C:\pas\mricron\btn\new\bucket24x.png" inkscape:export-xdpi="22.773436" inkscape:export-ydpi="22.773436" /> <path style="font-size:12;fill:#ff0000;fill-rule:evenodd;stroke-width:1pt;" d="M 32.982608,203.39618 C 24.345244,202.82561 29.882675,210.68326 29.960475,211.32626 C 30.038375,211.96926 25.425954,213.06265 27.366549,215.37646 C 30.570035,217.69028 45.345484,218.46139 45.105684,214.83439 C 44.865884,211.20639 33.164810,212.24817 30.632114,211.28954 C 29.797246,209.02780 29.689118,205.41944 30.954356,204.34431 C 31.695306,203.86591 31.589790,205.17495 32.982608,203.39618 z " id="path711" transform="matrix(4.130527,0.000000,0.000000,4.178675,123.2485,-284.9157)" sodipodi:nodetypes="cccccsc" inkscape:export-filename="C:\pas\mricron\btn\new\bucket24x.png" inkscape:export-xdpi="22.773436" inkscape:export-ydpi="22.773436" /> <path style="font-size:12;fill:#ff0000;fill-rule:evenodd;stroke-width:10.7861;" d="M 564.64487,498.84975 C 545.78432,498.84975 507.75654,526.26504 479.76987,560.03725 C 456.70600,587.86900 447.66587,611.34624 455.73862,618.75600 C 480.65758,610.79895 518.18623,582.81638 547.11362,549.25600 C 560.29785,533.96018 569.66613,519.82649 574.98862,508.16225 C 574.60172,502.30556 571.27296,498.84975 564.64487,498.84975 z " id="path592" transform="matrix(0.278716,0.000000,0.000000,0.278716,129.6880,395.7771)" inkscape:export-filename="C:\pas\mricron\btn\new\bucket24x.png" inkscape:export-xdpi="22.773436" inkscape:export-ydpi="22.773436" /> <rect style="font-size:12.000000;fill:url(#linearGradient643);fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000002;stroke-width:1.9439127;" id="rect642" width="71.981430" height="73.806518" x="355.56149" y="751.56487" /> <path style="font-size:12.000000;fill-rule:evenodd;stroke:#000002;stroke-width:1.9439127;" d="M 355.86912,768.41833 L 355.86912,825.08081 L 426.31248,825.08081 L 421.69830,821.88448 C 413.18767,816.07293 415.69984,808.37265 406.01003,809.09909 C 396.62784,809.24438 372.43926,821.89222 368.33775,814.53095 C 363.45690,807.88664 365.01940,752.99455 361.12114,759.56548 L 355.86912,768.41833 z " id="path640" sodipodi:nodetypes="cccczcsc" /> <rect style="font-size:12.000000;fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:4.1028190;" id="rect615" width="57.240670" height="49.173893" x="519.27698" y="1042.7878" transform="matrix(0.859371,-0.511353,0.000000,1.000000,0.000000,0.000000)" /> <text xml:space="preserve" style="font-size:48.000000;font-weight:bold;fill:#000000;stroke-width:1.0000000pt;font-family:Verdana;fill-opacity:1.0000000;" x="709.86213" y="1342.1935" id="text610" sodipodi:linespacing="100%" transform="matrix(0.632720,-0.387288,0.000000,0.813305,0.000000,0.000000)"><tspan x="709.86212" y="1342.1935" sodipodi:role="line" id="tspan613" style="fill:#000000;fill-opacity:1.0000000;">LR</tspan></text> <rect style="font-size:12.000000;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:4.1239262;" id="rect627" width="57.831149" height="49.173893" x="-632.70609" y="457.02159" transform="matrix(-0.862456,-0.506131,0.000000,1.000000,0.000000,0.000000)" /> <text xml:space="preserve" style="font-size:48.000000;font-weight:bold;stroke-width:1.0000000pt;font-family:Verdana;" x="-858.67939" y="596.71201" id="text628" sodipodi:linespacing="100%" transform="matrix(-0.632720,-0.387288,0.000000,0.813305,0.000000,0.000000)"><tspan x="-858.67938" y="596.71204" sodipodi:role="line" id="tspan629">LR</tspan></text> <rect style="font-size:12.000000;fill:url(#linearGradient1617);fill-rule:evenodd;stroke:#000000;stroke-width:0.77675028pt;" id="rect648" width="56.066268" height="49.173893" x="649.12604" y="1116.5706" transform="matrix(0.852907,-0.522062,0.000000,1.000000,0.000000,0.000000)" /> <rect style="font-size:12.000000;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:0.77675028pt;" id="rect649" width="56.066268" height="49.173893" x="-761.52524" y="380.12168" transform="matrix(-0.852907,-0.522062,0.000000,1.000000,0.000000,0.000000)" /> <path style="font-size:12.000000;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.4003696;fill-opacity:1.0000000;stroke-opacity:1.0000000;" d="M 586.02954,781.20391 C 576.62200,796.60958 567.62949,793.58791 569.22048,807.83469 C 571.77988,813.49422 577.86711,800.59504 591.84007,797.41464 C 597.37391,793.56282 600.31377,785.36998 593.29271,770.69383 C 584.81901,757.01251 564.65506,775.58222 560.50467,790.68280 C 556.35428,805.45774 563.75581,807.31272 569.01296,805.97641" id="path646" sodipodi:nodetypes="ccczzc" /> <path style="font-size:12.000000;fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:2.4003696;" d="M 618.03676,782.42607 C 627.44430,797.83174 636.43680,794.81007 634.84582,809.05685 C 632.28642,814.71638 626.19918,801.81720 612.22623,798.63680 C 606.69238,794.78498 603.75252,786.59214 610.77359,771.91599 C 619.24729,758.23467 639.41124,776.80439 643.56163,791.90496 C 647.71201,806.67990 640.31049,808.53488 635.05334,807.19857" id="path650" sodipodi:nodetypes="ccczzc" /> <path sodipodi:type="arc" style="font-size:12;fill:url(#radialGradient1158);fill-rule:evenodd;stroke:#000000;stroke-width:1pt;" id="path1411" d="M 69.375000 165.000000 A 4.375000 4.375000 0 1 0 60.625000,165.000000 A 4.375 4.375 0 1 0 69.375 165 L 65.000000 165.000000 z" sodipodi:cx="65.000000" sodipodi:cy="165.000000" sodipodi:rx="4.375000" sodipodi:ry="4.375000" transform="matrix(6.282797,0.000000,0.000000,6.282797,-36.58204,-479.7863)" /> <path style="font-size:12;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:39.4622;stroke-linecap:round;stroke-linejoin:round;" d="M 550.91978,487.64604 L 629.84423,566.57049" id="path1413" sodipodi:nodetypes="cc" transform="matrix(0.398026,0.000000,0.000000,0.398026,176.0698,386.3398)" /> <path sodipodi:type="arc" style="font-size:12;fill:url(#radialGradient1203);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.87645;stroke-dasharray:none;" id="path682" sodipodi:cx="271.35836792" sodipodi:cy="796.11926270" sodipodi:rx="37.42873764" sodipodi:ry="37.42873764" d="M 308.787106 796.119263 A 37.428738 37.428738 0 1 0 233.929630,796.119263 A 37.4287 37.4287 0 1 0 308.787 796.119 L 271.358368 796.119263 z" transform="matrix(1.269231,0.000000,0.000000,1.209574,46.26003,-283.6018)" /> <path style="font-size:12;fill:url(#linearGradient683);fill-opacity:0.38017;fill-rule:evenodd;stroke:none;stroke-width:1pt;" d="M 390.66521,633.72235 C 371.44051,633.72235 354.98613,644.70534 347.51136,660.37076 C 353.42953,663.40271 360.03471,666.27491 367.81906,664.18848 C 382.43619,660.99617 387.00568,653.47068 394.31424,650.27839 C 409.63412,649.70584 416.97120,657.57598 432.07387,657.23344 C 423.97641,643.28339 408.56719,633.72236 390.66521,633.72235 z " id="path687" /> <text xml:space="preserve" style="fill:black;fill-opacity:1;stroke:none;font-family:Palatino Linotype;font-style:normal;font-weight:bold;font-size:48;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;text-anchor:start;writing-mode:lr;" x="127.75068" y="373.16888" id="text688" sodipodi:linespacing="100%" transform="scale(2.880225,1.909157)"><tspan x="127.75068" y="373.16888" sodipodi:role="line" id="tspan693">i</tspan></text> <path style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" d="M 496.33119,633.22307 L 496.33119,725.97164 C 523.77846,725.97164 546.04854,705.21602 546.04851,679.61336 C 546.04851,654.01069 523.77844,633.22305 496.33119,633.22307 z " id="path700" /> <path style="font-size:12;fill:url(#linearGradient639);fill-opacity:0.49999997;fill-rule:evenodd;stroke:none;stroke-width:1pt;" d="M 496.76745,633.22395 C 477.54275,633.22395 461.08837,644.20694 453.61360,659.87236 C 459.53177,662.90431 466.13695,665.77651 473.92130,663.69008 C 488.53843,660.49777 493.10792,652.97228 500.41648,649.77999 C 515.73636,649.20744 523.07344,657.07758 538.17611,656.73504 C 530.07865,642.78499 514.66943,633.22396 496.76745,633.22395 z " id="path697" /> <g id="g708" transform="matrix(1.262750,0.000000,0.000000,1.262750,-71.71251,-181.4823)" style=""> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect705" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect706" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> <g id="g711" transform="matrix(1.262750,0.000000,0.000000,1.262750,10.32260,-181.7613)" style=""> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect712" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect713" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> <g id="g721" transform="matrix(0.878674,-0.906901,0.906901,0.878674,-460.8343,623.7427)" style="font-size:12;"> <g id="g722"> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect723" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect724" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> <g id="g725" transform="translate(64.96544,-0.220965)"> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect726" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect727" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> </g> <g id="g728" transform="matrix(1.073491e-5,-1.262750,1.262750,1.073491e-5,-178.5732,1437.573)" style="font-size:12;"> <g id="g729"> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect730" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect731" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> <g id="g732" transform="translate(64.96544,-0.220965)"> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect733" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect734" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> </g> <g id="g735" transform="matrix(0.893911,0.891887,-0.891887,0.893911,758.6406,-462.3620)" style="font-size:12;"> <g id="g736"> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect737" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect738" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> <g id="g739" transform="translate(64.96544,-0.220965)"> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect740" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect741" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> </g> <path style="font-size:12;fill:#e6e6e6;fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1pt;" d="M 683.81237,652.51288 C 671.83423,652.51288 661.58216,660.41352 656.92493,671.68248 C 660.61230,673.86352 664.72773,675.92965 669.57785,674.42877 C 678.68520,672.13237 681.53227,666.71889 686.08594,664.42251 C 695.63114,664.01065 700.20259,669.67205 709.61245,669.42564 C 704.56725,659.39064 694.96638,652.51289 683.81237,652.51288 z " id="path801" /> <path style="fill:#fb4100;fill-rule:evenodd;stroke:none;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;" d="M 476.34114,554.66904 C 483.92112,533.01461 496.96853,549.86409 506.53666,550.82511 C 514.86216,550.34456 515.73201,524.39800 531.51319,528.72246 C 538.84464,531.28509 536.85645,548.74295 535.61383,558.03249 C 535.48959,568.60329 536.86193,580.71156 526.29423,589.74497 C 511.50642,601.90523 468.76115,575.84293 476.34114,554.66904 z " id="path760" sodipodi:nodetypes="ccccsz" /> <path style="font-size:12;stroke:#1c4ed9;stroke-width:10.9208;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99216;fill:#4789f7;fill-opacity:1;" d="M -25.481958,248.26603 L 449.26700,273.43400 L 430.54500,310.73100 L -40.947002,275.21320 L -25.481958,248.26603 z " id="path279" transform="matrix(0.158157,4.271800e-2,5.364549e-3,0.156933,469.3436,553.4222)" sodipodi:nodetypes="ccccc" /> <path style="font-size:12;fill:url(#linearGradient967);fill-opacity:0.6993;stroke:#1c66fb;stroke-width:9.25243;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99216;" d="M -49.210000,251.69600 C -50.453100,239.20100 -40.203100,227.28000 -26.572700,228.54900 L 168.87300,263.91600 L 168.28600,299.92400 L 253.04600,316.79000 L 253.93000,278.87900 L 343.03800,291.68700 C 354.24800,294.90300 361.40100,301.55900 364.49800,316.81800 L 362.20763,586.89881 L -28.092563,469.70606 L -49.210000,251.69600 z " id="path208" transform="matrix(0.171298,0.000000,6.402228e-2,0.215063,438.9690,493.7050)" sodipodi:nodetypes="ccccccccccc" /> <path style="font-size:12;fill-opacity:0.99;stroke:#0c1dfb;stroke-width:2.63195;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99;fill:url(#radialGradient1140);" d="M 557.37226,540.24997 C 557.04724,536.47774 559.72713,532.59711 563.29085,532.12238 L 643.91869,532.55043 C 646.84958,532.82956 648.71975,534.42669 649.52947,538.93308 L 649.45887,612.42139 L 641.22180,619.79126 L 564.84594,620.14154 L 557.39252,612.04259 L 557.37226,540.24997 z " id="path1131" sodipodi:nodetypes="ccccccccc" /> <path style="font-size:12;fill:url(#linearGradient1138);fill-opacity:0.6993;stroke:#1c2942;stroke-width:2.28142;stroke-opacity:0.99216;" d="M 582.66195,589.79239 L 627.14365,589.80274 L 627.52772,620.32722 L 582.36162,620.36346 L 582.66195,589.79239 z " id="path230" sodipodi:nodetypes="ccccc" /> <path style="font-size:12;fill:#ffffff;fill-opacity:0.99216;stroke:#1c2942;stroke-width:1.10123;stroke-opacity:0.99216;" d="M 568.04305,545.40016 L 562.27509,545.17995 L 562.26523,539.14553 L 568.02662,539.08853 L 568.04305,545.40016 z " id="path313" sodipodi:nodetypes="ccccc" /> <path style="font-size:12;fill-opacity:1;stroke:#0c5cff;stroke-width:2.20247;stroke-opacity:0.99216;fill:#fffffd;" d="M 572.55890,532.87597 L 635.43355,532.88839 L 635.97643,578.77497 L 572.13438,578.81877 L 572.55890,532.87597 z " id="path412" sodipodi:nodetypes="ccccc" /> <path style="font-size:12;fill:#1c2942;fill-opacity:0.992157;stroke-width:8.96855;" d="M 600.69196,615.30986 L 590.20322,615.52766 L 590.18460,593.72001 L 600.66094,593.93144 L 600.69196,615.30986 z " id="path415" sodipodi:nodetypes="ccccc" /> <path style="font-size:12;fill:#ffffff;fill-opacity:0.99216;stroke:#1c2942;stroke-width:1.10123;stroke-opacity:0.99216;" d="M 645.41453,544.95545 L 639.64657,544.73523 L 639.63671,538.70081 L 645.39810,538.64382 L 645.41453,544.95545 z " id="path420" sodipodi:nodetypes="ccccc" /> <path style="fill:#fb4100;fill-rule:evenodd;stroke:none;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;" d="M 576.19524,551.65510 C 583.02443,538.35600 594.77948,548.70415 603.39989,549.29433 C 610.90075,548.99924 611.68442,533.06410 625.90249,535.71996 C 632.50774,537.29380 630.72141,567.64918 621.20046,573.19704 C 607.87739,580.66531 569.36604,564.65909 576.19524,551.65510 z " id="path1137" sodipodi:nodetypes="cccsz" /> <rect style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;" id="rect1148" width="106.29921722" height="106.29921722" x="336.61416260" y="414.56689177" /> <path style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 77.051277,408.7988 C 71.267817,417.21799 67.027117,423.63406 62.200887,434.68137 C 57.374657,446.11092 52.046077,474.37935 55.805647,479.02442 C 59.565217,483.66948 65.054177,480.60173 68.813737,476.487 C 72.573307,472.37227 70.668857,451.43553 71.855117,442.32214 C 72.728877,433.20875 75.073327,423.76954 77.051277,408.7988 z" id="path1163" sodipodi:nodetypes="czzzzc" /> <path style="fill:url(#linearGradient3600);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 63.057537,441.27138 C 61.657557,445.37446 60.025867,448.19672 58.857597,453.5806 C 57.689337,459.15077 56.021237,472.92733 56.931297,475.19109 C 57.841367,477.45485 59.170057,475.95979 60.080117,473.95448 C 60.990177,471.94918 60.529177,461.74571 60.816327,457.30432 C 61.027837,452.86292 62.578747,448.56734 63.057537,441.27138 z" id="path1164" sodipodi:nodetypes="czzzzc" /> <path style="font-size:12px;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt" d="M 65.027472,501.48235 C 51.407077,497.9052 50.454926,490.50156 53.966405,485.50879 C 55.290385,484.10977 58.403862,481.96591 60.211329,482.09583 C 62.018803,482.22576 63.57703,483.14148 65.898291,484.80391 C 71.165819,488.75376 61.235859,490.46929 65.027472,501.48235 z" id="path1165" sodipodi:nodetypes="ccszc" /> <path style="font-size:12px;fill:url(#linearGradient3598);fill-rule:evenodd;stroke-width:1pt" d="M 60.576947,496.88161 C 57.318997,496.05997 55.784737,496.21737 53.771847,491.29171 C 51.758957,486.67855 56.763437,485.16283 57.357717,484.53711 C 57.951997,483.91138 58.819637,484.32463 59.413917,484.87892 C 60.008197,485.4332 59.707157,488.25355 59.894667,489.48119 C 60.032787,490.70884 57.764297,492.83368 60.576947,496.88161 z" id="path1166" sodipodi:nodetypes="czzzzc" /> <path style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path1178" d="M 132.76033,454.92476 C 133.58483,461.75504 110.61862,470.65746 109.69302,474.58544 C 107.79093,478.92593 122.67406,489.23041 118.64002,494.37156 C 116.06387,502.12143 76.332667,506.06522 67.089097,503.65943 C 65.935297,502.26703 65.735177,499.08018 67.848227,497.17509 C 73.487937,493.86766 101.21717,496.69665 110.37363,491.71974 C 111.17693,489.62848 100.67532,479.10788 103.89636,473.54283 C 107.27361,466.68575 127.96186,459.52712 127.6453,455.49314 C 124.66526,450.94096 101.5795,443.77841 98.841397,439.84805 C 98.841397,439.84805 128.87,449.20724 132.76033,454.92476 z" sodipodi:nodetypes="cccccccccc" /> <path style="fill:#000054;fill-rule:evenodd;stroke:none;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1" d="M 379.19834,430.4644 C 375.81627,423.04655 369.17418,435.83206 364.34795,446.87937 C 359.52172,458.30892 354.19314,486.57735 357.95271,491.22242 C 361.71228,495.86748 367.20124,492.79973 370.9608,488.685 C 374.72037,484.57027 372.81592,463.63353 374.00218,454.52014 C 374.87594,445.40675 382.58041,437.88226 379.19834,430.4644 z" id="path1183" sodipodi:nodetypes="czzzzz" inkscape:export-filename="C:\pas\mricron\btn\new\autoclose24.png" inkscape:export-xdpi="24.462318" inkscape:export-ydpi="24.462318" /> <path style="fill:url(#linearGradient1139);fill-rule:evenodd;stroke:none;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;" d="M 365.20460,453.46938 C 363.80462,457.57246 362.17293,460.39472 361.00466,465.77860 C 359.83640,471.34877 358.16830,485.12533 359.07836,487.38909 C 359.98843,489.65285 361.31712,488.15779 362.22718,486.15248 C 363.13724,484.14718 362.67624,473.94371 362.96339,469.50232 C 363.17490,465.06092 364.72581,460.76534 365.20460,453.46938 z " id="path1184" sodipodi:nodetypes="czzzzc" inkscape:export-filename="C:\pas\mricron\btn\new\autoclose24.png" inkscape:export-xdpi="24.462318" inkscape:export-ydpi="24.462318" /> <path style="font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#ff0000;fill-opacity:1;" d="M 367.17453,513.68035 C 353.55414,510.10320 352.60199,502.69956 356.11346,497.70679 C 357.43744,496.30777 360.55092,494.16391 362.35839,494.29383 C 364.16586,494.42376 365.72409,495.33948 368.04535,497.00191 C 373.31288,500.95176 363.38292,502.66729 367.17453,513.68035 z " id="path1185" sodipodi:nodetypes="ccszc" inkscape:export-filename="C:\pas\mricron\btn\new\autoclose24.png" inkscape:export-xdpi="24.462318" inkscape:export-ydpi="24.462318" /> <path style="font-size:12;fill:url(#linearGradient1175);fill-rule:evenodd;stroke-width:1pt;" d="M 362.72401,509.07961 C 359.46606,508.25797 357.93180,508.41537 355.91891,503.48971 C 353.90602,498.87655 358.91050,497.36083 359.50478,496.73511 C 360.09906,496.10938 360.96670,496.52263 361.56098,497.07692 C 362.15526,497.63120 361.85422,500.45155 362.04173,501.67919 C 362.17985,502.90684 359.91136,505.03168 362.72401,509.07961 z " id="path1186" sodipodi:nodetypes="czzzzc" inkscape:export-filename="C:\pas\mricron\btn\new\autoclose24.png" inkscape:export-xdpi="24.462318" inkscape:export-ydpi="24.462318" /> <path style="fill:#ff0000;fill-rule:nonzero;stroke:none;fill-opacity:1;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt" id="path1187" d="M 434.90739,467.12276 C 435.73189,473.95304 412.76568,482.85546 411.84008,486.78344 C 409.93799,491.12393 424.82112,501.42841 420.78708,506.56956 C 418.21093,514.31943 378.47973,518.26322 369.23616,515.85743 C 368.08236,514.46503 367.88224,511.27818 369.99529,509.37309 C 375.63500,506.06566 403.36423,508.89465 412.52069,503.91774 C 413.32399,501.82648 402.82238,491.30588 406.04342,485.74083 C 409.42067,478.88375 430.10892,471.72512 429.79236,467.69114 C 426.81232,463.13896 403.72656,455.97641 400.98846,452.04605 C 400.98846,452.04605 431.01706,461.40524 434.90739,467.12276 z " sodipodi:nodetypes="cccccccccc" inkscape:export-filename="C:\pas\mricron\btn\new\autoclose24.png" inkscape:export-xdpi="24.462318" inkscape:export-ydpi="24.462318" /> <path style="font-size:12;fill:none;fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#0000c0;stroke-width:5;stroke-linecap:round;stroke-dasharray:5, 5;stroke-dashoffset:0;stroke-miterlimit:4;stroke-opacity:1" d="M 400.09965,456.6173 L 371.53803,505.58684" id="path1189" inkscape:export-filename="C:\pas\mricron\btn\new\autoclose24.png" inkscape:export-xdpi="24.462318" inkscape:export-ydpi="24.462318" sodipodi:nodetypes="cc" /> <path style="fill:#fb4100;fill-rule:evenodd;stroke:none;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;" d="M 561.65094,448.09913 C 571.11508,425.70443 587.40564,443.12995 599.35212,444.12377 C 609.74708,443.62687 610.83312,416.79324 630.53703,421.26553 C 639.69082,423.91576 637.21526,475.03199 624.02079,484.37417 C 605.55720,496.95021 552.18679,469.99689 561.65094,448.09913 z " id="path1196" sodipodi:nodetypes="cccsz" inkscape:export-filename="C:\pas\mricron\btn\path.png" inkscape:export-xdpi="21.807127" inkscape:export-ydpi="21.807127" /> <path style="font-size:12;fill:url(#radialGradient1140);fill-opacity:0.99;stroke:#0c1dfb;stroke-width:2.47208;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99;" d="M 555.37415,438.95253 C 566.02431,447.52015 591.18209,448.17514 604.56628,448.38069 C 617.95046,448.58624 641.07727,445.71069 647.53136,437.79076 L 639.22369,509.12451 C 628.37584,514.24774 616.58726,517.38839 602.91722,517.02493 C 589.24718,516.66148 572.12780,514.45376 562.84783,509.43353 L 555.37415,438.95253 z " id="path1199" sodipodi:nodetypes="czcczcc" inkscape:export-xdpi="21.807127" inkscape:export-ydpi="21.807127" inkscape:export-filename="C:\pas\mricron\btn\path.png" /> <rect style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;" id="rect983" width="106.29922" height="106.29922" x="229.68997" y="308.89271" /> <rect style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;" id="rect984" width="106.29922" height="106.29922" x="335.98920" y="308.89271" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.90746355pt;" d="M 279.95280,346.67442 C 280.29433,345.98764 279.36877,338.54690 277.95386,336.62391 C 276.53895,334.70092 274.43956,335.54857 274.09803,336.23535 C 273.75651,336.92213 275.86774,336.00777 277.28264,337.93076 C 278.69755,339.85374 279.61128,347.36120 279.95280,346.67442 z " id="path1018" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.76453004pt;" d="M 273.63423,385.40914 C 270.65408,385.12172 270.05831,378.23536 267.98919,382.43631 C 265.82503,386.71235 270.28496,395.88181 270.67731,391.14244 C 270.97461,386.40309 276.51934,385.77163 273.63423,385.40914 z " id="path1019" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.90746355pt;" d="M 288.50077,346.53195 C 288.15924,345.84516 289.08480,338.40442 290.49971,336.48144 C 291.91461,334.55844 294.01401,335.40609 294.35554,336.09287 C 294.69706,336.77966 292.58583,335.86530 291.17093,337.78828 C 289.75602,339.71127 288.84229,347.21873 288.50077,346.53195 z " id="path1036" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.76453004pt;" d="M 294.81934,385.26667 C 297.79949,384.97925 298.39526,378.09288 300.46438,382.29384 C 302.62854,386.56988 298.16861,395.73934 297.77626,390.99997 C 297.47896,386.26061 291.93423,385.62916 294.81934,385.26667 z " id="path1037" sodipodi:nodetypes="czzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.0507082pt;fill-opacity:1.0000000;" d="M 409.23451,358.84667 C 408.54949,363.52087 396.22993,361.07089 396.03530,368.76520 C 395.84067,375.96034 411.64662,377.37220 417.55186,375.25440 C 423.45711,373.13660 427.32607,369.84225 426.71517,362.54762 C 426.10429,355.25299 424.14266,336.89820 402.58195,326.37323 C 381.45319,316.34743 357.52241,330.01251 349.87361,344.61299 C 342.22480,359.71267 341.61655,375.00482 350.68776,369.51396 C 359.32701,364.52225 369.86822,348.78540 385.68092,346.96694 C 401.06163,345.14847 409.91950,355.17081 409.23451,358.84667 z " id="path1045" sodipodi:nodetypes="czzzzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.0877723pt;fill-opacity:1.0000000;" d="M 373.63251,370.33086 C 372.33483,368.22505 372.73946,360.23826 365.81846,361.79098 C 358.89746,363.34369 351.38109,370.76217 349.29735,373.43628 C 347.21361,376.11041 348.32990,380.85478 349.29735,381.97618 C 350.26481,383.09758 355.77183,383.70140 357.33465,385.08158 C 358.89746,386.46177 362.54401,391.63747 364.47891,391.29243 C 366.41382,390.94738 370.35806,386.80682 370.50689,385.08160 C 370.65573,383.35636 374.93016,372.43670 373.63251,370.33086 z " id="path1049" sodipodi:nodetypes="czzzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:none;stroke-width:1.0507082pt;fill-opacity:1.0000000;" d="M 369.80420,399.98508 C 370.22508,395.78373 374.95545,379.12917 375.72069,374.09587 C 376.48592,369.06258 373.57804,371.60003 374.80242,369.35376 C 376.02678,367.10748 380.15902,361.82463 383.06689,360.61829 C 385.97478,359.41197 390.10702,360.11025 392.24966,361.23339 C 394.39230,362.35653 395.73146,366.10916 395.92276,367.35707 C 396.11406,368.60500 394.43057,370.01932 393.39750,369.60335 C 392.36444,369.18737 394.01446,362.68044 391.51002,364.68476 C 389.00558,366.86555 385.84845,370.56008 384.21474,372.09919 C 382.90569,373.63828 386.12783,372.84795 386.74001,374.09587 C 387.35219,375.34380 388.50003,377.42367 387.88785,379.58674 C 387.27565,381.74980 384.63561,385.70156 383.06689,387.07427 C 381.49816,388.44699 380.12076,385.78476 378.47552,387.82304 C 376.83027,389.86131 374.60431,398.21199 373.22688,400.16706 L 369.80420,399.98508 z " id="path1050" sodipodi:nodetypes="czzzzzzzzzzzzcc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;fill-opacity:1.0000000;stroke-dasharray:none;" d="M 368.64815,355.65182 C 369.07734,357.32494 370.41856,361.26175 371.38424,362.14751 C 372.34992,363.03329 374.41542,363.29574 374.76413,362.14751 C 375.11285,360.99928 372.77913,355.22533 378.62686,352.10871 C 384.63554,348.99209 394.02411,349.71383 396.97480,351.12452 C 399.92548,352.53519 404.88802,357.78424 400.19374,361.36016 C 396.30418,364.93605 405.74639,365.03448 407.75823,363.52538 C 409.77007,362.01628 412.69261,356.42939 410.09064,353.73925 C 407.48867,351.04912 400.89223,344.62204 394.77625,343.96592 C 388.66028,343.30978 374.03986,350.59961 372.02803,351.12452 C 369.85526,351.64942 368.21896,353.97868 368.64815,355.65182 z " id="path1051" sodipodi:nodetypes="czzzzzzzzzz" /> <g id="g1422"> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.1655209pt;" d="M 500.15302,318.39576 C 498.63090,318.58535 497.62728,319.44559 497.45659,321.35308 L 496.27180,334.48360 L 495.12787,321.15593 C 494.44510,313.52598 480.11544,322.81032 474.82299,326.00594 C 463.97441,332.55643 453.12906,348.90299 453.12904,365.27921 C 453.12904,369.37327 450.53202,374.85695 458.19505,375.61014 C 471.12797,372.25560 475.71395,368.40706 475.88521,364.72718 C 475.97004,366.73597 472.22575,370.99591 477.19257,377.85771 C 471.88006,374.61864 449.68734,372.98113 454.59982,385.78334 C 460.64344,396.79407 487.30926,400.22178 487.52886,393.43295 C 487.74845,386.64413 493.79077,380.76155 483.19824,381.13048 C 485.89452,378.43241 492.43160,379.68832 495.12787,376.99022 L 496.31266,372.81053 L 497.66087,376.55648 C 500.35715,379.25456 506.64909,378.23526 509.34537,380.93333 C 500.48613,379.72791 504.79515,386.40754 505.01475,393.19637 C 505.23437,399.98518 531.94102,396.59692 537.98464,385.58618 C 542.89711,372.78397 520.66354,374.42148 515.35103,377.66055 C 520.31782,370.79874 516.57357,366.49938 516.65839,364.49060 C 516.82967,368.17046 521.41564,372.05845 534.34856,375.41298 C 542.01160,374.65978 539.45542,369.17610 539.45542,365.08206 C 539.45542,348.70583 528.61005,332.35928 517.76147,325.80879 C 513.79214,323.41205 504.71936,317.82698 500.15302,318.39576 z " id="path1060" sodipodi:nodetypes="cccccccccccccccccccccccc" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.98194113pt;" d="M 501.66595,339.08941 C 507.48057,336.85763 507.44235,336.64611 505.77764,338.68995 C 504.31721,340.73379 502.98053,336.92565 501.65049,348.68951 C 500.11618,360.84766 495.64707,341.51834 501.66595,339.08941 z " id="path1057" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.98194113pt;" d="M 491.59647,339.30071 C 485.78186,337.06892 485.82008,336.85741 487.48479,338.90125 C 488.94522,340.94509 490.28190,337.13695 491.61194,348.90080 C 493.14625,361.05897 497.61536,341.72965 491.59647,339.30071 z " id="path1059" sodipodi:nodetypes="czzz" /> </g> <path sodipodi:type="arc" style="font-size:12;fill:url(#radialGradient983);fill-opacity:0.50000000;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none;" id="path1065" sodipodi:cx="271.35836792" sodipodi:cy="796.11926270" sodipodi:rx="37.42873764" sodipodi:ry="37.42873764" d="M 308.787106 796.119263 A 37.428738 37.428738 0 1 0 233.929630,796.119263 A 37.4287 37.4287 0 1 0 308.787 796.119 L 271.358368 796.119263 z" transform="matrix(1.269231,0.000000,0.000000,1.209574,153.7331,-282.7179)" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke-width:0.84895535pt;" id="rect1074" width="42.038873" height="31.251435" x="577.48017" y="355.15182" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="59.518364" inkscape:export-ydpi="59.518364" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 590.00000,364.23718 C 600.00000,365.07051 608.75000,368.82051 614.37500,377.36218 C 620.00000,386.52885 619.37500,387.36218 619.37500,387.36218 C 619.37500,387.36218 620.62500,396.11218 608.75000,397.36218 C 596.87500,397.98718 583.56694,385.77747 569.81694,385.77747 C 556.69194,385.77747 551.87500,383.73242 553.75000,372.36218 C 555.62500,360.55000 569.06250,334.86218 591.87500,334.23718 C 614.68750,332.98718 635.31250,340.38301 643.75000,355.48718 C 651.56250,370.59135 647.81250,382.36218 643.12500,386.11218 C 638.43750,389.86218 627.70833,384.86218 619.37500,386.73718" id="path1067" sodipodi:nodetypes="czzzzzzzzz" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="59.518364" inkscape:export-ydpi="59.518364" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 605.62500,385.48718 C 598.12500,382.98718 595.00000,382.98718 588.12500,376.73718 C 581.25000,370.48718 580.00000,364.23718 580.00000,364.23718" id="path1068" sodipodi:nodetypes="ccc" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="59.518364" inkscape:export-ydpi="59.518364" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 597.50000,334.86218 C 598.12500,347.36218 604.92417,355.07014 602.71447,365.23480" id="path1069" sodipodi:nodetypes="cc" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="59.518364" inkscape:export-ydpi="59.518364" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 610.90476,341.83916 C 625.49682,341.59591 628.11190,344.21099 630.20397,355.19433 C 635.95715,352.05623 638.95397,353.81615 640.20397,366.31615" id="path1070" sodipodi:nodetypes="ccc" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="59.518364" inkscape:export-ydpi="59.518364" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 620.21706,362.57924 C 620.21706,362.57924 610.95580,381.48089 620.33080,380.85589 C 629.70580,380.23089 626.05002,380.28181 628.70167,379.17696" id="path1071" sodipodi:nodetypes="ccc" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="59.518364" inkscape:export-ydpi="59.518364" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 565.74009,361.50702 C 565.74009,361.50702 568.88733,353.92082 576.86459,349.47516 C 584.84184,345.55251 590.33862,342.77797 590.55959,337.25370 L 589.89668,342.92311 C 589.16881,349.14804 598.53331,356.11130 595.55959,362.81588" id="path1072" sodipodi:nodetypes="czczz" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="59.518364" inkscape:export-ydpi="59.518364" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 606.88925,334.11254 C 612.15464,344.40283 608.33289,359.63174 612.31037,370.45931" id="path1073" sodipodi:nodetypes="cc" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="59.518364" inkscape:export-ydpi="59.518364" /> <g id="g1132" transform="matrix(1.069142,0.000000,0.000000,1.032969,-32.93548,-15.76150)"> <g id="g1107" transform="matrix(0.841944,0.000000,0.000000,0.873445,74.35371,56.03641)"> <g id="g1099" transform="translate(1.325825,9.280777)"> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.65628657pt;" d="M 496.65430,493.31750 C 496.65430,484.55800 490.15222,466.98787 483.70730,461.72195 C 477.26238,456.45602 464.41541,456.46624 457.98479,461.72195 C 451.55416,466.97766 445.12353,484.49668 445.12353,493.25619 C 445.12353,502.01571 451.55416,510.77522 457.98479,514.27903 C 464.41541,517.78283 477.26238,517.77261 483.70730,514.27903 C 490.15222,510.78544 496.65430,502.07702 496.65430,493.31750 z " id="path1075" sodipodi:nodetypes="czzzzzz" /> <g id="g1093"> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.60115390pt;" d="M 471.91942,460.57627 C 471.83583,460.57625 471.75443,460.59340 471.67084,460.59426 L 471.67084,460.61224 C 471.60863,460.60733 471.54725,460.59423 471.48442,460.59426 C 471.33798,460.59430 471.19580,460.62750 471.04941,460.63023 L 471.04941,460.70216 C 470.96017,460.69182 470.87062,460.68420 470.78013,460.68418 C 470.71728,460.68416 470.65591,460.69725 470.59369,460.70216 L 470.59369,460.68418 C 470.51011,460.68333 470.42871,460.66617 470.34512,460.66619 C 465.94290,460.66736 461.53595,461.88424 458.60004,464.29896 C 457.13209,465.50632 448.73018,475.46378 451.55713,477.17551 C 458.59260,481.68638 464.69200,468.40765 458.18575,479.42351 C 457.53016,483.20728 457.36165,485.18018 457.31574,486.16752 C 457.22303,484.35884 456.45624,480.11665 452.42714,478.05673 C 449.06128,476.37130 446.85496,491.25894 446.85496,493.27120 C 446.85496,501.32028 452.72823,509.36640 458.60004,512.58603 C 461.57796,514.21889 466.06655,515.00265 470.53155,514.97790 L 470.53155,514.99589 C 470.75985,514.99753 470.98688,514.98046 471.21513,514.97790 L 471.21513,514.88798 C 471.38776,514.89378 471.55999,514.90723 471.73299,514.90597 L 471.73299,514.88798 C 476.19799,514.91273 480.68658,514.12899 483.66451,512.49611 C 489.53631,509.27648 495.40958,501.23035 495.40958,493.18128 C 495.40958,491.16902 493.20325,476.28138 489.83741,477.96681 C 485.80830,480.02673 485.04151,484.26892 484.94880,486.07760 C 484.90289,485.09026 484.73439,483.11735 484.07879,479.33359 C 477.57255,468.31773 483.67194,481.59646 490.70741,477.08559 C 493.53436,475.37386 485.13245,465.41639 483.66451,464.20904 C 480.72859,461.79432 476.32164,460.57744 471.91942,460.57627 z " id="path1076" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.60115390pt;" d="M 468.10796,477.26953 C 468.34963,476.84360 467.69470,472.22898 466.69350,471.03637 C 465.69229,469.84376 464.20675,470.36946 463.96508,470.79539 C 463.72341,471.22132 465.21734,470.65425 466.21853,471.84686 C 467.21974,473.03946 467.86630,477.69546 468.10796,477.26953 z " id="path1077" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.50646687pt;" d="M 463.63689,501.29214 C 461.52811,501.11389 461.10654,496.84308 459.64241,499.44844 C 458.11103,502.10037 461.26692,507.78711 461.54455,504.84784 C 461.75492,501.90857 465.67842,501.51695 463.63689,501.29214 z " id="path1078" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.60115390pt;" d="M 474.15658,477.18117 C 473.91491,476.75523 474.56985,472.14061 475.57105,470.94801 C 476.57224,469.75540 478.05780,470.28110 478.29947,470.70703 C 478.54113,471.13296 477.04720,470.56589 476.04601,471.75849 C 475.04481,472.95110 474.39824,477.60710 474.15658,477.18117 z " id="path1079" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.50646687pt;" d="M 478.62766,501.20378 C 480.73643,501.02553 481.15801,496.75472 482.62213,499.36008 C 484.15351,502.01201 480.99763,507.69875 480.72000,504.75948 C 480.50963,501.82021 476.58613,501.42859 478.62766,501.20378 z " id="path1080" sodipodi:nodetypes="czzz" /> </g> </g> <g id="g1088" transform="matrix(0.528836,0.000000,0.000000,0.528836,234.0955,290.1247)"> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:1.2724125pt;" d="M 448.76081,243.24146 C 439.85333,243.24406 424.56825,250.36055 418.62774,255.70706 C 406.74669,266.40004 400.09103,294.23271 400.09103,312.05436 C 400.09103,317.48652 400.10693,322.81569 400.33616,327.94505 L 494.99693,327.94505 C 495.23807,322.86048 495.28292,317.60716 495.28292,312.21208 C 495.28288,294.39046 491.62713,267.53611 479.71970,256.82234 C 473.76599,251.46545 457.66829,243.23886 448.76081,243.24146 z " id="path1084" sodipodi:nodetypes="cccccccc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.1655209pt;" d="M 452.30358,246.20459 C 450.78146,246.39418 449.77784,247.25442 449.60715,249.16191 L 448.42236,262.29243 L 447.27843,248.96476 C 446.59566,241.33481 432.26600,250.61915 426.97355,253.81477 C 416.12497,260.36526 405.27962,276.71182 405.27960,293.08804 C 405.27960,297.18210 402.68258,302.66578 410.34561,303.41897 C 423.27853,300.06443 427.86451,296.21589 428.03577,292.53601 C 428.12060,294.54480 424.37631,298.80474 429.34313,305.66654 C 424.03062,302.42747 401.83790,300.78996 406.75038,313.59217 C 412.79400,324.60290 439.45982,328.03061 439.67942,321.24178 C 439.89901,314.45296 445.94133,308.57038 435.34880,308.93931 C 438.04508,306.24124 444.58216,307.49715 447.27843,304.79905 L 448.46322,300.61936 L 449.81143,304.36531 C 452.50771,307.06339 458.79965,306.04409 461.49593,308.74216 C 452.63669,307.53674 456.94571,314.21637 457.16531,321.00520 C 457.38493,327.79401 484.09158,324.40575 490.13520,313.39501 C 495.04767,300.59280 472.81410,302.23031 467.50159,305.46938 C 472.46838,298.60757 468.72413,294.30821 468.80895,292.29943 C 468.98023,295.97929 473.56620,299.86728 486.49912,303.22181 C 494.16216,302.46861 491.60598,296.98493 491.60598,292.89089 C 491.60598,276.51466 480.76061,260.16811 469.91203,253.61762 C 465.94270,251.22088 456.86992,245.63581 452.30358,246.20459 z " id="path1085" sodipodi:nodetypes="cccccccccccccccccccccccc" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.98194113pt;" d="M 453.81651,266.89824 C 459.63113,264.66646 459.59291,264.45494 457.92820,266.49878 C 456.46777,268.54262 455.13109,264.73448 453.80105,276.49834 C 452.26674,288.65649 447.79763,269.32717 453.81651,266.89824 z " id="path1086" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.98194113pt;" d="M 443.74703,267.10954 C 437.93242,264.87775 437.97064,264.66624 439.63535,266.71008 C 441.09578,268.75392 442.43246,264.94578 443.76250,276.70963 C 445.29681,288.86780 449.76592,269.53848 443.74703,267.10954 z " id="path1087" sodipodi:nodetypes="czzz" /> </g> </g> <g id="g1126" transform="matrix(0.495484,0.000000,0.000000,0.495484,300.5956,311.9146)"> <path style="fill-rule:evenodd;stroke:none;stroke-width:0.91963024pt;" d="M 390.65866,301.36656 L 482.41318,302.01909 L 481.02775,293.60154 C 479.75571,289.61717 475.40700,285.24242 474.55998,280.76456 C 473.27101,276.28670 479.48325,279.16416 478.73371,271.80959 C 477.98416,264.45501 476.57776,244.93064 465.94662,234.62235 C 455.00298,224.62656 445.86383,218.21008 426.46718,221.36127 C 408.32053,223.26246 397.91045,231.92586 390.51069,247.21043 C 382.91955,262.49500 391.32345,281.51355 391.08480,288.64061 L 390.65866,301.36656 z " id="path1121" sodipodi:nodetypes="ccczzzzzzc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.0507082pt;fill-opacity:1.0000000;" d="M 456.91427,260.35297 C 456.22925,265.02717 443.90969,262.57719 443.71506,270.27150 C 443.52043,277.46664 459.32638,278.87850 465.23162,276.76070 C 471.13687,274.64290 475.00583,271.34855 474.39493,264.05392 C 473.78405,256.75929 471.82242,238.40450 450.26171,227.87953 C 429.13295,217.85373 405.20217,231.51881 397.55337,246.11929 C 389.90456,261.21897 389.29631,276.51112 398.36752,271.02026 C 407.00677,266.02855 417.54798,250.29170 433.36068,248.47324 C 448.74139,246.65477 457.59926,256.67711 456.91427,260.35297 z " id="path1122" sodipodi:nodetypes="czzzzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.0877723pt;fill-opacity:1.0000000;" d="M 421.31227,271.83716 C 420.01459,269.73135 420.41922,261.74456 413.49822,263.29728 C 406.57722,264.84999 399.06085,272.26847 396.97711,274.94258 C 394.89337,277.61671 396.00966,282.36108 396.97711,283.48248 C 397.94457,284.60388 403.45159,285.20770 405.01441,286.58788 C 406.57722,287.96807 410.22377,293.14377 412.15867,292.79873 C 414.09358,292.45368 418.03782,288.31312 418.18665,286.58790 C 418.33549,284.86266 422.60992,273.94300 421.31227,271.83716 z " id="path1123" sodipodi:nodetypes="czzzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:none;stroke-width:1.0507082pt;fill-opacity:1.0000000;" d="M 417.48396,301.49138 C 417.90484,297.29003 422.63521,280.63547 423.40045,275.60217 C 424.16568,270.56888 421.25780,273.10633 422.48218,270.86006 C 423.70654,268.61378 427.83878,263.33093 430.74665,262.12459 C 433.65454,260.91827 437.78678,261.61655 439.92942,262.73969 C 442.07206,263.86283 443.41122,267.61546 443.60252,268.86337 C 443.79382,270.11130 442.11033,271.52562 441.07726,271.10965 C 440.04420,270.69367 441.69422,264.18674 439.18978,266.19106 C 436.68534,268.37185 433.52821,272.06638 431.89450,273.60549 C 430.58545,275.14458 433.80759,274.35425 434.41977,275.60217 C 435.03195,276.85010 436.17979,278.92997 435.56761,281.09304 C 434.95541,283.25610 432.31537,287.20786 430.74665,288.58057 C 429.17792,289.95329 427.80052,287.29106 426.15528,289.32934 C 424.51003,291.36761 422.28407,299.71829 420.90664,301.67336 L 417.48396,301.49138 z " id="path1124" sodipodi:nodetypes="czzzzzzzzzzzzcc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.1391397pt;fill-opacity:1.0000000;" d="M 416.32791,257.15812 C 416.75710,258.83124 418.09832,262.76805 419.06400,263.65381 C 420.02968,264.53959 422.09518,264.80204 422.44389,263.65381 C 422.79261,262.50558 420.45889,256.73163 426.30662,253.61501 C 432.31530,250.49839 441.70387,251.22013 444.65456,252.63082 C 447.60524,254.04149 452.56778,259.29054 447.87350,262.86646 C 443.98394,266.44235 453.42615,266.54078 455.43799,265.03168 C 457.44983,263.52258 460.37237,257.93569 457.77040,255.24555 C 455.16843,252.55542 448.57199,246.12834 442.45601,245.47222 C 436.34004,244.81608 421.71962,252.10591 419.70779,252.63082 C 417.53502,253.15572 415.89872,255.48498 416.32791,257.15812 z " id="path1125" sodipodi:nodetypes="czzzzzzzzzz" /> </g> </g> <rect style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;" id="rect1173" width="106.29922" height="106.29922" x="442.28839" y="202.59353" /> <rect style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;" id="rect1174" width="106.29922" height="106.29922" x="548.58759" y="202.59353" /> <rect style="fill:url(#linearGradient701);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:3.7500000;stroke-dasharray:none;" id="rect1204" width="91.250000" height="30.000000" x="-328.75000" y="241.11218" ry="12.500000" transform="scale(-1.000000,1.000000)" inkscape:export-xdpi="24" inkscape:export-ydpi="24" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:1.2724125pt;" d="M 388.57383,213.13538 C 379.66635,213.13798 364.38127,220.25447 358.44076,225.60098 C 346.55971,236.29396 339.90405,264.12663 339.90405,281.94828 C 339.90405,287.38044 339.91995,292.70961 340.14918,297.83897 L 434.80995,297.83897 C 435.05109,292.75440 435.09594,287.50108 435.09594,282.10600 C 435.09590,264.28438 431.44015,237.43003 419.53272,226.71626 C 413.57901,221.35937 397.48131,213.13278 388.57383,213.13538 z " id="path1205" sodipodi:nodetypes="cccccccc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.1655209pt;" d="M 392.11660,216.09851 C 390.59448,216.28810 389.59086,217.14834 389.42017,219.05583 L 388.23538,232.18635 L 387.09145,218.85868 C 386.40868,211.22873 372.07902,220.51307 366.78657,223.70869 C 355.93799,230.25918 345.09264,246.60574 345.09262,262.98196 C 345.09262,267.07602 342.49560,272.55970 350.15863,273.31289 C 363.09155,269.95835 367.67753,266.10981 367.84879,262.42993 C 367.93362,264.43872 364.18933,268.69866 369.15615,275.56046 C 363.84364,272.32139 341.65092,270.68388 346.56340,283.48609 C 352.60702,294.49682 379.27284,297.92453 379.49244,291.13570 C 379.71203,284.34688 385.75435,278.46430 375.16182,278.83323 C 377.85810,276.13516 384.39518,277.39107 387.09145,274.69297 L 388.27624,270.51328 L 389.62445,274.25923 C 392.32073,276.95731 398.61267,275.93801 401.30895,278.63608 C 392.44971,277.43066 396.75873,284.11029 396.97833,290.89912 C 397.19795,297.68793 423.90460,294.29967 429.94822,283.28893 C 434.86069,270.48672 412.62712,272.12423 407.31461,275.36330 C 412.28140,268.50149 408.53715,264.20213 408.62197,262.19335 C 408.79325,265.87321 413.37922,269.76120 426.31214,273.11573 C 433.97518,272.36253 431.41900,266.87885 431.41900,262.78481 C 431.41900,246.40858 420.57363,230.06203 409.72505,223.51154 C 405.75572,221.11480 396.68294,215.52973 392.11660,216.09851 z " id="path1206" sodipodi:nodetypes="cccccccccccccccccccccccc" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.98194113pt;" d="M 393.62953,236.79216 C 399.44415,234.56038 399.40593,234.34886 397.74122,236.39270 C 396.28079,238.43654 394.94411,234.62840 393.61407,246.39226 C 392.07976,258.55041 387.61065,239.22109 393.62953,236.79216 z " id="path1207" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.98194113pt;" d="M 383.56005,237.00346 C 377.74544,234.77167 377.78366,234.56016 379.44837,236.60400 C 380.90880,238.64784 382.24548,234.83970 383.57552,246.60355 C 385.10983,258.76172 389.57894,239.43240 383.56005,237.00346 z " id="path1209" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#00ff00;stroke-width:8.1250000;stroke-linecap:round;stroke-linejoin:bevel;stroke-dashoffset:12.500000;stroke-dasharray:none;" d="M 428.23716,300.72398 L 352.16975,226.74092" id="path1210" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" d="M 845.47619,180.57813 C 845.47619,194.72313 833.99619,206.20313 819.85119,206.20313 C 805.70619,206.20313 794.22619,194.72313 794.22619,180.57813 C 794.22619,166.43313 805.70619,154.95313 819.85119,154.95313 C 833.99619,154.95313 845.47619,166.43313 845.47619,180.57813 z" id="path1291" inkscape:export-filename="C:\pas\mricron\btn\new\ellipse.png" inkscape:export-xdpi="23.179588" inkscape:export-ydpi="23.179588" /> <rect style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:4.56593418" id="rect1303" width="48.979599" height="47.110672" x="834.32587" y="135.24585" inkscape:export-filename="C:\pas\mricron\btn\new\ellipse.png" inkscape:export-xdpi="23.179588" inkscape:export-ydpi="23.179588" /> <rect style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;" id="rect1092" width="106.29922" height="106.29922" x="549.21260" y="95.669265" /> <rect style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;" id="rect1093" width="106.29922" height="106.29922" x="442.91338" y="95.669265" /> <rect style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;" id="rect1094" width="106.29922" height="106.29922" x="336.61417" y="95.669265" /> <rect style="font-size:12.000000;fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;" id="rect1095" width="106.29922" height="106.29922" x="230.31496" y="95.669269" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59819369pt;" d="M 307.52069,149.83649 C 307.73008,149.34971 307.16264,144.07588 306.29519,142.71291 C 305.42774,141.34993 304.14065,141.95073 303.93127,142.43750 C 303.72189,142.92428 305.01624,142.27620 305.88368,143.63917 C 306.75113,145.00214 307.31131,150.32326 307.52069,149.83649 z " id="path1097" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.50397291pt;" d="M 303.64692,177.29080 C 301.81986,177.08709 301.45461,172.20619 300.18608,175.18373 C 298.85928,178.21449 301.59356,184.71360 301.83410,181.35444 C 302.01637,177.99529 305.41572,177.54773 303.64692,177.29080 z " id="path1098" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59819369pt;" d="M 312.76126,149.73551 C 312.55187,149.24873 313.11931,143.97489 313.98676,142.61193 C 314.85420,141.24895 316.14130,141.84974 316.35068,142.33652 C 316.56006,142.82330 315.26571,142.17522 314.39827,143.53819 C 313.53082,144.90116 312.97063,150.22228 312.76126,149.73551 z " id="path1099" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.50397291pt;" d="M 316.63503,177.18982 C 318.46209,176.98611 318.82734,172.10520 320.09587,175.08275 C 321.42267,178.11351 318.68839,184.61262 318.44784,181.25346 C 318.26558,177.89431 314.86623,177.44675 316.63503,177.18982 z " id="path1100" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:none;stroke-width:0.99068832pt;fill:#f30000;fill-opacity:1.0000000;" d="M 277.51799,168.04576 C 277.51799,158.03493 271.88453,137.95486 266.30062,131.93668 C 260.71669,125.91850 249.58599,125.93017 244.01446,131.93668 C 238.44291,137.94318 232.87137,157.96485 232.87137,167.97569 C 232.87137,177.98652 238.44291,187.99735 244.01446,192.00169 C 249.58599,196.00603 260.71669,195.99435 266.30062,192.00169 C 271.88453,188.00903 277.51799,178.05659 277.51799,168.04576 z " id="path1101" sodipodi:nodetypes="czzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.59819369pt;" d="M 256.08751,130.62734 C 256.01509,130.62732 255.94457,130.64692 255.87215,130.64789 L 255.87215,130.66845 C 255.81824,130.66283 255.76507,130.64786 255.71062,130.64789 C 255.58375,130.64794 255.46056,130.68588 255.33374,130.68900 L 255.33374,130.77121 C 255.25641,130.75940 255.17883,130.75069 255.10042,130.75066 C 255.04598,130.75064 254.99280,130.76560 254.93890,130.77121 L 254.93890,130.75066 C 254.86648,130.74969 254.79596,130.73008 254.72353,130.73010 C 250.90942,130.73144 247.09120,132.12216 244.54751,134.88183 C 243.27567,136.26166 235.99620,147.64157 238.44549,149.59783 C 244.54107,154.75309 249.82562,139.57745 244.18857,152.16697 C 243.62056,156.49125 243.47456,158.74599 243.43479,159.87438 C 243.35446,157.80732 242.69011,152.95912 239.19927,150.60493 C 236.28307,148.67874 234.37149,165.69312 234.37149,167.99284 C 234.37149,177.19175 239.46014,186.38729 244.54751,190.06685 C 247.12760,191.93297 251.01655,192.82869 254.88505,192.80041 L 254.88505,192.82096 C 255.08285,192.82284 255.27955,192.80333 255.47731,192.80041 L 255.47731,192.69764 C 255.62688,192.70426 255.77610,192.71964 255.92599,192.71820 L 255.92599,192.69764 C 259.79450,192.72592 263.68345,191.83022 266.26354,189.96409 C 271.35091,186.28452 276.43955,177.08898 276.43955,167.89007 C 276.43955,165.59035 274.52797,148.57597 271.61178,150.50217 C 268.12094,152.85635 267.45658,157.70455 267.37626,159.77161 C 267.33648,158.64323 267.19049,156.38848 266.62248,152.06420 C 260.98542,139.47469 266.26998,154.65032 272.36556,149.49507 C 274.81485,147.53880 267.53538,136.15888 266.26354,134.77906 C 263.71984,132.01939 259.90163,130.62867 256.08751,130.62734 z " id="path1102" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59819369pt;" d="M 252.78524,149.70528 C 252.99463,149.21850 252.42719,143.94467 251.55974,142.58169 C 250.69229,141.21872 249.40520,141.81952 249.19582,142.30629 C 248.98644,142.79307 250.28079,142.14499 251.14823,143.50796 C 252.01568,144.87093 252.57586,150.19205 252.78524,149.70528 z " id="path1103" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.50397291pt;" d="M 248.91147,177.15959 C 247.08441,176.95588 246.71916,172.07498 245.45063,175.05252 C 244.12383,178.08328 246.85811,184.58239 247.09865,181.22323 C 247.28092,177.86408 250.68027,177.41652 248.91147,177.15959 z " id="path1104" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59819369pt;" d="M 258.02581,149.60430 C 257.81642,149.11751 258.38386,143.84368 259.25131,142.48072 C 260.11875,141.11774 261.40585,141.71853 261.61523,142.20531 C 261.82461,142.69209 260.53026,142.04401 259.66282,143.40697 C 258.79537,144.76995 258.23518,150.09107 258.02581,149.60430 z " id="path1105" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.50397291pt;" d="M 261.89958,177.05861 C 263.72664,176.85490 264.09189,171.97399 265.36042,174.95154 C 266.68722,177.98230 263.95294,184.48141 263.71239,181.12225 C 263.53013,177.76310 260.13078,177.31554 261.89958,177.05861 z " id="path1106" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.37908139pt;fill:#00f300;fill-opacity:1.0000000;" d="M 284.46583,153.19549 L 284.66716,159.20701 L 284.66716,159.51930 L 270.26011,159.51930 L 270.26011,172.16691 L 284.52875,172.16691 L 284.46583,178.49072 L 298.73447,165.84310 L 284.46583,153.19549 z " id="path1197" /> <g id="g1218" transform="matrix(0.937345,0.000000,-0.521597,0.915342,103.6709,16.62999)"> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.99068832pt;" d="M 420.68026,157.78820 C 420.68026,143.66413 411.49144,115.33358 402.38342,106.84266 C 393.27539,98.351740 375.11992,98.368210 366.03210,106.84266 C 356.94426,115.31711 347.85643,143.56526 347.85643,157.68934 C 347.85643,171.81342 356.94426,185.93749 366.03210,191.58713 C 375.11992,197.23676 393.27539,197.22028 402.38342,191.58713 C 411.49144,185.95397 420.68026,171.91228 420.68026,157.78820 z " id="path1198" sodipodi:nodetypes="czzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.90746355pt;fill-opacity:1.0000000;" d="M 385.72466,104.99534 C 385.60653,104.99531 385.49150,105.02296 385.37337,105.02434 L 385.37337,105.05334 C 385.28545,105.04542 385.19871,105.02430 385.10991,105.02434 C 384.90297,105.02441 384.70203,105.07794 384.49516,105.08234 L 384.49516,105.19833 C 384.36904,105.18166 384.24249,105.16937 384.11460,105.16933 C 384.02579,105.16930 383.93906,105.19041 383.85113,105.19833 L 383.85113,105.16933 C 383.73301,105.16796 383.61798,105.14030 383.49985,105.14033 C 377.27858,105.14222 371.05063,107.10435 366.90157,110.99791 C 364.82705,112.94468 352.95338,129.00036 356.94846,131.76041 C 366.89106,139.03386 375.51079,117.62287 366.31609,135.38515 C 365.38960,141.48619 365.15147,144.66736 365.08659,146.25937 C 364.95557,143.34300 363.87193,136.50278 358.17796,133.18131 C 353.42130,130.46368 350.30330,154.46891 350.30330,157.71354 C 350.30330,170.69209 358.60347,183.66588 366.90157,188.85730 C 371.11000,191.49017 377.45333,192.75392 383.76331,192.71402 L 383.76331,192.74302 C 384.08594,192.74567 384.40678,192.71814 384.72935,192.71402 L 384.72935,192.56903 C 384.97331,192.57837 385.21671,192.60006 385.46120,192.59803 L 385.46120,192.56903 C 391.77118,192.60893 398.11451,191.34520 402.32294,188.71231 C 410.62104,183.52089 418.92121,170.54709 418.92121,157.56855 C 418.92121,154.32392 415.80320,130.31868 411.04655,133.03632 C 405.35258,136.35779 404.26894,143.19801 404.13792,146.11438 C 404.07304,144.52237 403.83491,141.34119 402.90841,135.24016 C 393.71372,117.47788 402.33345,138.88886 412.27605,131.61542 C 416.27113,128.85537 404.39746,112.79968 402.32294,110.85292 C 398.17388,106.95936 391.94593,104.99722 385.72466,104.99534 z " id="path1201" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.90746355pt;" d="M 380.33827,131.91200 C 380.67980,131.22522 379.75424,123.78448 378.33933,121.86149 C 376.92442,119.93850 374.82503,120.78615 374.48350,121.47293 C 374.14198,122.15971 376.25321,121.24535 377.66811,123.16834 C 379.08302,125.09132 379.99675,132.59878 380.33827,131.91200 z " id="path1202" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.76453004pt;" d="M 374.01970,170.64672 C 371.03955,170.35930 370.44378,163.47294 368.37466,167.67389 C 366.21050,171.94993 370.67043,181.11939 371.06278,176.38002 C 371.36008,171.64067 376.90481,171.00921 374.01970,170.64672 z " id="path1203" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.90746355pt;" d="M 388.88624,131.76953 C 388.54471,131.08274 389.47027,123.64200 390.88518,121.71902 C 392.30008,119.79602 394.39948,120.64367 394.74101,121.33045 C 395.08253,122.01724 392.97130,121.10288 391.55640,123.02586 C 390.14149,124.94885 389.22776,132.45631 388.88624,131.76953 z " id="path1216" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.76453004pt;" d="M 395.20481,170.50425 C 398.18496,170.21683 398.78073,163.33046 400.84985,167.53142 C 403.01401,171.80746 398.55408,180.97692 398.16173,176.23755 C 397.86443,171.49819 392.31970,170.86674 395.20481,170.50425 z " id="path1217" sodipodi:nodetypes="czzz" /> </g> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.37908139pt;fill:#00f300;fill-opacity:1.0000000;" d="M 428.01911,162.01828 L 423.37484,168.02980 L 423.12311,168.34209 L 408.71606,168.34209 L 398.52142,180.98970 L 412.79006,180.98970 L 407.62982,187.31351 L 432.09311,174.66589 L 428.01911,162.01828 z " id="path1225" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.37908139pt;fill:#00f300;fill-opacity:1.0000000;" d="M 354.54175,137.59503 L 359.18602,131.58351 L 359.43775,131.27122 L 373.84480,131.27122 L 384.03944,118.62361 L 369.77080,118.62361 L 374.93104,112.29980 L 350.46775,124.94742 L 354.54175,137.59503 z " id="path1226" /> <path style="fill:url(#linearGradient1273);fill-rule:evenodd;stroke-width:0.70212674pt;fill-opacity:1.0000000;" d="M 467.37635,98.353752 C 463.50624,98.508099 459.42100,99.228043 455.01853,100.26653 C 449.14858,101.65118 445.35681,115.09401 447.03802,123.34197 C 448.71924,131.58992 453.74697,146.51332 454.11773,158.09757 L 460.40924,157.95512 C 460.70198,148.86493 458.20224,140.91179 457.10163,132.39714 C 456.41064,127.05144 453.86311,111.80425 462.99904,111.80425 L 470.06467,111.80425 L 470.06467,111.84495 L 478.04518,111.84495 C 487.18110,111.84495 484.61950,127.11248 483.92851,132.45819 C 482.82791,140.97284 480.32815,148.90562 480.62089,157.99581 L 486.91240,158.13826 C 487.28316,146.55402 492.31090,131.63062 493.99211,123.38267 C 495.67333,115.13471 491.88156,101.69188 486.01161,100.30723 C 480.65069,99.042651 475.78320,98.287415 471.17659,98.414798 L 471.17659,98.394449 C 469.92961,98.310515 468.66639,98.302304 467.37635,98.353752 z " id="path1231" transform="translate(43.75223,40.21670)" /> <rect style="fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.87235308pt;" id="rect1232" width="5.7452426" height="5.3810821" x="454.09512" y="152.41942" transform="translate(43.75223,40.21670)" /> <rect style="fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.87235308pt;" id="rect1233" width="5.7452426" height="5.3810821" x="481.16409" y="152.41943" transform="translate(43.75223,40.21670)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:5.0000000;stroke-opacity:1.0000000;stroke-linecap:round;stroke-dasharray:10.000000,10.000000;stroke-dashoffset:0.00000000;" d="M 555.46141,176.42468 C 559.55050,176.42960 566.62926,182.31051 567.72869,176.43945 C 568.82812,170.88089 576.44823,114.43157 580.80799,105.57330 C 585.16775,96.715032 581.98180,115.22882 595.40407,119.22734 C 609.13884,122.91336 613.18611,180.92271 621.29587,184.46848 C 629.40563,187.70175 630.95289,182.51721 635.31265,179.56445 C 639.67241,176.61170 641.84468,176.43945 646.20445,176.43945" id="path1280" sodipodi:nodetypes="czzzzzz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#040600;stroke-width:3.7500000;stroke-opacity:1.0000000;stroke-linecap:butt;stroke-dasharray:3.7500000,3.7500000;stroke-dashoffset:0.00000000;" d="M 555.25347,176.62690 C 559.34256,176.63182 566.42132,180.01273 567.52075,174.14167 C 568.62018,168.58311 571.24029,134.00879 575.60005,125.15052 C 579.95981,116.29225 583.02386,104.80604 596.13363,110.67956 C 608.93090,123.74058 622.04067,188.31243 625.15043,189.67070 C 627.32269,190.40397 630.74495,182.71943 635.10471,179.76667 C 639.46447,176.81392 641.63674,176.64167 645.99651,176.64167" id="path1281" sodipodi:nodetypes="czzzzzz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#040600;stroke-width:3.7500000;stroke-opacity:1.0000000;stroke-linecap:butt;stroke-dasharray:3.7500000,3.7500000;stroke-dashoffset:0.00000000;" d="M 557.12849,76.779411 C 561.21758,76.784331 568.29634,80.165241 569.39577,74.294181 C 570.49520,68.735621 573.11531,34.161301 577.47507,25.303031 C 581.83483,16.444761 584.89888,4.9585510 598.00865,10.832071 C 610.80592,23.893091 623.91569,88.464940 627.02545,89.823210 C 629.19771,90.556480 632.61997,82.871941 636.97973,79.919181 C 641.33949,76.966431 643.51176,76.794181 647.87153,76.794181" id="path1282" sodipodi:nodetypes="czzzzzz" /> <text xml:space="preserve" style="fill:#ff0000;fill-opacity:1.0000000;stroke:none;font-family:Arial;font-style:normal;font-weight:bold;font-size:36.000000;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;font-stretch:normal;font-variant:normal;text-anchor:start;writing-mode:lr;" x="383.35034" y="50.653559" id="text1283" sodipodi:linespacing="100%" transform="scale(1.505663,1.564296)"><tspan id="tspan1284" style="fill:#ff0000;fill-opacity:1.0000000;">?</tspan></text> <g id="g1163" transform="matrix(1.152996,0.000000,0.000000,1.000000,-68.02037,0.000000)"> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:2.0770883;stroke-dasharray:none;" d="M 472.42571,238.27147 C 472.33405,238.27145 472.24478,238.29291 472.15311,238.29398 L 472.15311,238.31648 C 472.08489,238.31034 472.01758,238.29395 471.94867,238.29398 C 471.78809,238.29403 471.63216,238.33557 471.47163,238.33899 L 471.47163,238.42899 C 471.37376,238.41606 471.27556,238.40652 471.17632,238.40649 C 471.10740,238.40647 471.04010,238.42285 470.97187,238.42899 L 470.97187,238.40649 C 470.88021,238.40543 470.79094,238.38396 470.69928,238.38399 C 465.87162,238.38545 461.03877,239.90805 457.81913,242.92943 C 456.20932,244.44011 446.99543,256.89920 450.09559,259.04098 C 457.81097,264.68512 464.49982,248.07035 457.36480,261.85375 C 456.64585,266.58811 456.46107,269.05668 456.41072,270.29207 C 456.30905,268.02898 455.46815,262.72102 451.04967,260.14359 C 447.35854,258.03472 444.93899,276.66261 444.93899,279.18042 C 444.93899,289.25168 451.37986,299.31925 457.81913,303.34776 C 461.08484,305.39084 466.00722,306.37150 470.90372,306.34054 L 470.90372,306.36305 C 471.15408,306.36510 471.40305,306.34374 471.65336,306.34054 L 471.65336,306.22803 C 471.84267,306.23528 472.03155,306.25211 472.22127,306.25053 L 472.22127,306.22803 C 477.11777,306.25899 482.04015,305.27835 485.30586,303.23524 C 491.74513,299.20674 498.18600,289.13916 498.18600,279.06791 C 498.18600,276.55010 495.76645,257.92220 492.07532,260.03107 C 487.65684,262.60851 486.81594,267.91647 486.71427,270.17956 C 486.66392,268.94417 486.47914,266.47559 485.76018,261.74124 C 478.62517,247.95784 485.31402,264.57260 493.02940,258.92847 C 496.12956,256.78669 486.91567,244.32759 485.30586,242.81691 C 482.08622,239.79554 477.25337,238.27293 472.42571,238.27147 z " id="path1211" transform="matrix(0.896078,0.000000,0.000000,0.909383,46.81814,19.67645)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.70418520pt;" d="M 468.24591,259.15861 C 468.51094,258.62567 467.79271,252.85171 466.69475,251.35949 C 465.59679,249.86726 463.96768,250.52503 463.70265,251.05797 C 463.43764,251.59090 465.07594,250.88137 466.17389,252.37359 C 467.27185,253.86581 467.98090,259.69155 468.24591,259.15861 z " id="path1212" sodipodi:nodetypes="czzzz" transform="matrix(0.896078,0.000000,0.000000,0.909383,46.81814,19.67645)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59326982pt;" d="M 463.34275,289.21648 C 461.03017,288.99344 460.56786,283.64967 458.96224,286.90958 C 457.28286,290.22776 460.74374,297.34319 461.04820,293.66548 C 461.27890,289.98777 465.58157,289.49777 463.34275,289.21648 z " id="path1213" sodipodi:nodetypes="czzz" transform="matrix(0.896078,0.000000,0.000000,0.909383,46.81814,19.67645)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.70418520pt;" d="M 474.87908,259.04805 C 474.61405,258.51511 475.33228,252.74115 476.43024,251.24893 C 477.52819,249.75670 479.15731,250.41447 479.42234,250.94740 C 479.68735,251.48035 478.04905,250.77081 476.95110,252.26303 C 475.85314,253.75526 475.14409,259.58099 474.87908,259.04805 z " id="path1214" sodipodi:nodetypes="czzzz" transform="matrix(0.896078,0.000000,0.000000,0.909383,46.81814,19.67645)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59326982pt;" d="M 479.78224,289.10592 C 482.09482,288.88288 482.55713,283.53911 484.16275,286.79902 C 485.84213,290.11720 482.38125,297.23264 482.07679,293.55492 C 481.84609,289.87721 477.54342,289.38721 479.78224,289.10592 z " id="path1215" sodipodi:nodetypes="czzz" transform="matrix(0.896078,0.000000,0.000000,0.909383,46.81814,19.67645)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59326982pt;" d="M 479.78224,289.10592 C 482.09482,288.88288 482.55713,283.53911 484.16275,286.79902 C 485.84213,290.11720 482.38125,297.23264 482.07679,293.55492 C 481.84609,289.87721 477.54342,289.38721 479.78224,289.10592 z " id="path1245" sodipodi:nodetypes="czzz" transform="matrix(0.896078,0.000000,0.000000,0.909383,71.19322,13.47142)" /> <path transform="matrix(0.820025,0.000000,0.000000,0.858963,104.9588,28.96850)" style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:2.0770884;" d="M 472.42572,238.27147 C 466.99935,238.34460 460.99557,239.27928 457.24200,243.60560 C 454.27786,247.05912 447.54300,265.39403 446.58800,268.07554 C 444.99506,275.03305 443.89364,282.61304 446.99670,289.34223 C 449.98685,297.12243 456.23622,304.66231 464.92263,305.85892 C 470.66585,306.65810 476.71462,306.56039 482.24009,304.66227 C 488.70615,302.32029 492.95294,296.28794 495.73557,290.27853 C 498.36218,284.49691 498.76947,277.90311 497.25994,271.76637 C 496.60360,267.85969 495.93735,263.78918 493.70802,260.42078 C 490.47721,259.07927 488.59909,263.53006 487.49637,265.86353 C 487.00972,267.33824 486.63024,271.50536 486.49583,267.70454 C 486.56751,263.78501 485.27565,260.09141 483.12367,256.86000 C 483.47775,256.38368 486.42646,260.44859 488.46678,259.99317 C 492.66404,261.29430 494.92727,256.76681 492.55453,253.62131 C 490.80672,249.96760 488.38631,246.65200 485.92858,243.45619 C 482.48414,239.81958 477.32986,238.26882 472.42572,238.27147 z " id="path1151" sodipodi:nodetypes="cccccccccccccccc" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.70418520pt;" d="M 469.29214,259.15861 C 471.28335,258.62567 470.01209,252.60872 468.91413,251.11650 C 467.81617,249.62427 460.51529,248.09514 463.70265,251.05797 C 467.13661,253.77781 467.05433,259.69155 469.29214,259.15861 z " id="path1242" sodipodi:nodetypes="czzz" transform="matrix(0.820025,0.000000,0.000000,0.858963,104.9588,28.96850)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59326982pt;" d="M 466.83017,280.96913 C 464.51759,280.74609 460.56786,283.64967 458.96224,286.90958 C 457.28286,290.22776 460.74374,297.34319 461.04820,293.66548 C 461.27890,289.98777 469.06899,281.25042 466.83017,280.96913 z " id="path1243" sodipodi:nodetypes="czzz" transform="matrix(0.820025,0.000000,0.000000,0.858963,104.9588,28.96850)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59100037pt;" d="M 493.43163,251.60533 C 491.79878,251.14755 492.84125,245.97921 493.74161,244.69745 C 494.64196,243.41568 500.62886,242.10222 498.01515,244.64717 C 495.19921,246.98342 495.26668,252.06310 493.43163,251.60533 z " id="path1152" sodipodi:nodetypes="czzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.5214069;" d="M 511.80663,239.60773 C 505.82577,239.32916 500.11547,244.27305 498.49491,246.98563 C 497.16791,249.22473 493.46139,261.39466 492.85327,264.14860 C 492.10462,268.10699 491.68917,272.26850 492.99906,276.15741 C 494.65527,281.44574 497.85490,286.62328 502.77269,289.10403 C 505.89347,290.48383 509.46589,290.71532 512.64653,290.47013 C 516.82711,290.39011 521.19160,289.06289 524.01723,285.66210 C 528.59029,280.58529 531.28514,273.27869 529.87427,266.31128 C 529.26796,262.87343 525.92547,250.57752 524.78129,248.36436 C 522.92298,245.30255 517.65774,239.61035 511.80663,239.60773 z " id="path1149" sodipodi:nodetypes="cccccccccc" /> </g> <path style="fill:#cccccc;fill-rule:nonzero;stroke:none;fill-opacity:1.0000000;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;" id="path1142" d="M 154.48440,498.48337 C 154.25849,492.81414 161.38338,496.65143 161.80515,496.90392 C 164.78182,498.61634 170.39318,504.14280 173.95269,504.05991 C 175.95558,503.84576 177.63390,502.63440 179.05959,501.28272 C 180.33976,499.99776 181.20682,498.58127 182.06397,497.00066 C 183.44438,494.70321 187.18348,487.99384 189.77932,488.11380 C 192.16403,488.34388 196.44293,490.85911 198.63874,491.77507 C 200.34301,492.48848 203.47991,491.83913 205.21157,492.48524 C 206.51580,492.94214 202.88897,499.07531 204.26060,499.25768 C 205.40017,499.35058 206.09747,498.86094 206.93516,498.11576 C 207.57391,497.51451 211.51747,500.31315 210.70090,501.08164 C 208.56717,502.98125 206.27814,503.85683 203.40943,503.55889 C 201.58416,503.29953 199.79391,502.83223 198.06231,502.20168 C 196.27903,501.51624 194.58389,500.64017 192.82470,499.89873 C 191.28048,499.25617 189.66739,498.59467 187.99351,498.39461 C 187.36694,498.35913 187.14450,498.30179 186.79211,498.84177 C 185.67318,500.80361 184.50376,502.56949 182.88013,504.16267 C 180.31823,506.51125 177.42085,508.14583 173.89191,508.33224 C 169.23300,508.20987 162.04502,509.96482 156.25203,500.75392 C 155.96788,500.55562 159.95745,495.74444 159.84831,498.48337 L 154.48440,498.48337 z " sodipodi:nodetypes="ccccccccccccccccccccc" /> <rect style="fill:#f9bac0;fill-rule:evenodd;stroke:#000000;stroke-width:0.49504948pt;" id="rect1120" width="12.250767" height="12.000593" x="141.62668" y="387.23074" ry="3.9226213" transform="matrix(0.801814,-0.889705,0.948595,0.752036,-334.0009,328.3647)" /> <rect style="fill:url(#linearGradient1118);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;" id="rect1117" width="53.347649" height="11.244847" x="150.89017" y="387.60864" transform="matrix(0.801814,-0.889705,0.948595,0.752036,-334.0009,328.3647)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.93750000;" d="M 153.76675,391.00825 L 202.40725,390.74674 L 202.40725,390.74674" id="path1126" transform="matrix(0.801814,-0.889705,0.948595,0.752036,-334.0009,328.3647)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.93750000;" d="M 153.76675,395.58464 L 202.40725,395.32313 L 202.40725,395.32313" id="path1128" transform="matrix(0.801814,-0.889705,0.948595,0.752036,-334.0009,328.3647)" /> <path style="fill:#e49415;fill-rule:evenodd;stroke-width:1.0000000pt;fill-opacity:1.0000000;" d="M 204.76083,387.08564 L 226.72751,392.93844 L 205.02234,399.37652 L 204.76083,387.08564 z " id="path1129" transform="matrix(0.801814,-0.889705,0.948595,0.752036,-334.0009,328.3647)" /> <path style="fill:#040023;fill-rule:evenodd;stroke-width:1.0000000pt;" d="M 219.01301,390.87754 L 227.25053,392.93225 L 219.11108,395.19241 L 219.01301,390.87754 z " id="path1132" transform="matrix(0.801814,-0.889705,0.948595,0.752036,-334.0009,328.3647)" /> <g id="g1195" transform="matrix(0.789807,0.000000,0.000000,0.829148,40.60222,144.2242)"> <path sodipodi:type="arc" style="font-size:12;fill:url(#radialGradient1169);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.87645;stroke-dasharray:none;" id="path1190" sodipodi:cx="271.35836792" sodipodi:cy="796.11926270" sodipodi:rx="37.42873764" sodipodi:ry="37.42873764" d="M 308.787106 796.119263 A 37.428738 37.428738 0 1 0 233.929630,796.119263 A 37.4287 37.4287 0 1 0 308.787 796.119 L 271.358368 796.119263 z" transform="matrix(1.269231,0.000000,0.000000,1.209574,-184.6799,-194.3941)" /> <path style="font-size:12;fill:url(#linearGradient683);fill-opacity:0.38017;fill-rule:evenodd;stroke:none;stroke-width:1pt;" d="M 159.72524,722.93003 C 140.50054,722.93003 124.04616,733.91302 116.57139,749.57844 C 122.48956,752.61039 129.09474,755.48259 136.87909,753.39616 C 151.49622,750.20385 156.06571,742.67836 163.37427,739.48607 C 178.69415,738.91352 186.03123,746.78366 201.13390,746.44112 C 193.03644,732.49107 177.62722,722.93004 159.72524,722.93003 z " id="path1191" /> <text xml:space="preserve" style="fill:black;fill-opacity:1;stroke:none;font-family:Palatino Linotype;font-style:normal;font-weight:bold;font-size:48;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;text-anchor:start;writing-mode:lr;" x="47.569456" y="419.89508" id="text1192" sodipodi:linespacing="100%" transform="scale(2.880225,1.909157)"><tspan x="47.569454" y="419.89508" sodipodi:role="line" id="tspan1193">i</tspan></text> </g> <path style="fill:#fb4100;fill-rule:evenodd;stroke:none;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;" d="M 157.91689,807.80962 C 166.13755,791.78371 180.28774,804.25361 190.66459,804.96480 C 199.69378,804.60921 200.63712,785.40677 217.75218,788.60718 C 225.70328,790.50372 223.55297,827.08308 212.09209,833.76845 C 196.05440,842.76799 149.69621,823.47991 157.91689,807.80962 z " id="path1179" sodipodi:nodetypes="cccsz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 135.72268,361.98087 C 134.67665,364.33444 139.37290,364.60684 143.68234,366.31209 C 147.99177,368.01734 152.43742,371.67846 155.07429,372.44119 C 160.34804,373.96665 169.84949,374.44608 173.64136,373.48722 C 177.43323,372.52836 177.12814,369.56460 177.82549,365.64199" id="path1135" sodipodi:nodetypes="cszzz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 163.44255,357.27376 C 158.21239,350.47455 167.88818,351.25907 168.41121,347.07494 C 171.02628,336.87613 161.08898,335.30708 161.08898,335.30708 C 161.08898,335.30708 167.10367,327.72334 168.67271,323.53921 C 163.44255,317.78603 163.96556,318.57056 155.85881,322.23167" id="path1138" sodipodi:nodetypes="ccccc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 169.19573,382.90152 C 169.80591,375.31778 164.40140,374.66401 162.13500,373.48722" id="path1141" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 135.59193,366.63075 C 138.73003,373.95298 150.19280,376.35013 155.46655,377.87559" id="path1153" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 163.44255,357.27376 C 158.21239,350.47455 167.88818,351.25907 168.41121,347.07494 C 171.02628,336.87613 161.08898,335.30708 161.08898,335.30708 C 161.08898,335.30708 167.10367,327.72334 168.67271,323.53921 C 163.44255,317.78603 163.96556,318.57056 155.85881,322.23167" id="path1167" sodipodi:nodetypes="ccccc" transform="matrix(-1.000000,0.000000,0.000000,1.000000,355.9476,-0.390884)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 169.19573,382.90152 C 169.80591,375.31778 164.40140,374.66401 162.13500,373.48722" id="path1169" sodipodi:nodetypes="cz" transform="matrix(-1.000000,0.000000,0.000000,1.000000,355.9476,-0.390884)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 135.59193,366.63075 C 138.73003,373.95298 150.19280,376.35013 155.46655,377.87559" id="path1170" sodipodi:nodetypes="cz" transform="matrix(-1.000000,0.000000,0.000000,1.000000,355.9476,-0.390884)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 220.21273,361.50548 C 221.25876,363.85905 216.56251,364.13145 212.25307,365.83670 C 207.94364,367.54195 203.49799,371.20307 200.86112,371.96580 C 195.58737,373.49126 186.08592,373.97069 182.29405,373.01183 C 178.50218,372.05297 177.49973,366.73564 177.84841,362.29001" id="path1194" sodipodi:nodetypes="cszzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 140.95285,349.68999 C 133.28195,370.78498 141.91171,361.71936 146.70603,361.98087" id="path1195" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 214.47932,349.22398 C 222.15022,370.31897 213.52046,361.25335 208.72614,361.51486" id="path1218" sodipodi:nodetypes="cz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;fill-opacity:1.0000000;stroke-dasharray:none;" d="M 185.21408,214.81126 C 177.92178,214.84746 169.89667,216.34801 165.05912,222.33190 C 161.50198,226.47814 158.94781,231.38316 156.20835,236.05592 C 154.24583,240.57871 150.03197,261.81828 149.86587,269.23814 C 150.70984,281.21595 157.20263,293.02343 167.55100,299.31527 C 175.78925,303.36046 185.45955,303.01158 194.27144,301.44543 C 202.01619,299.89951 208.18824,294.32026 212.14021,287.69026 C 217.68379,279.16981 219.82461,268.45263 217.31152,258.53961 C 216.32638,253.20688 212.48476,234.67682 209.09445,230.93333 C 205.45913,224.31738 200.50275,217.42497 192.63972,215.77674 C 190.22232,215.12439 187.71654,214.81512 185.21408,214.81126 z " id="path1223" sodipodi:nodetypes="ccccccccccc" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 180.70208,215.01333 C 181.74811,215.62352 183.81774,213.67597 184.21000,227.75382 C 184.60226,241.83167 184.55612,297.03969 184.90479,299.48044 C 185.25346,301.65968 182.57494,302.51823 179.56086,302.28043" id="path1220" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 187.98937,214.98472 C 186.94334,215.59491 184.87371,213.64736 184.48145,227.72521 C 184.08919,241.80306 185.05990,297.38091 184.71123,299.82166 C 184.36256,302.00090 187.22600,302.30470 190.24007,302.06691" id="path1221" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 198.27418,254.64653 C 190.41203,244.47236 191.26648,241.49489 199.51959,235.25317 C 193.82983,232.56245 193.75599,229.68727 203.74206,223.38038" id="path1224" sodipodi:nodetypes="ccc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 168.46763,255.66748 C 176.32978,245.49331 175.47533,242.51584 167.22222,236.27412 C 172.91198,233.58340 172.98582,230.70822 162.99975,224.40133" id="path1227" sodipodi:nodetypes="ccc" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 180.29127,257.60125 C 177.08610,261.85427 169.96690,256.58422 168.45677,255.56719 C 166.94664,254.55016 164.75849,259.45038 160.32055,257.97107 C 156.06753,256.49176 156.62226,252.23874 156.62226,252.23874" id="path1228" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 178.41857,269.78296 C 174.28883,271.44718 168.21022,264.73499 166.70009,263.71796 C 165.18996,262.70093 163.00181,267.60115 158.56387,266.12184 C 154.31085,264.64253 152.09187,253.73260 152.09187,253.73260" id="path1229" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 172.80225,296.62724 C 163.12509,284.60782 172.09341,288.02873 172.43243,282.01902 C 173.14127,276.37914 178.61280,275.40749 174.54738,276.22889 C 171.53434,276.86667 168.64169,272.21856 159.85827,276.10176" id="path1230" sodipodi:nodetypes="czsz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 187.87277,256.20713 C 191.07794,260.46015 198.19714,255.19010 199.70727,254.17307 C 201.21740,253.15604 203.40555,258.05626 207.84349,256.57695 C 212.09651,255.09764 211.54178,250.84462 211.54178,250.84462" id="path1232" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 188.17642,268.38884 C 192.30616,270.05306 199.95382,263.34087 201.46395,262.32384 C 202.97408,261.30681 205.16223,266.20703 209.60017,264.72772 C 213.85319,263.24841 216.07217,252.33848 216.07217,252.33848" id="path1233" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 196.93084,294.71010 C 206.60800,282.69068 197.63968,286.11159 197.30066,280.10188 C 196.59182,274.46200 191.12029,273.49035 195.18571,274.31175 C 198.19875,274.94953 201.09140,270.30142 209.87482,274.18462" id="path1234" sodipodi:nodetypes="czsz" /> <g id="g1278" transform="matrix(0.605285,0.000000,0.000000,0.597196,215.4523,158.0050)" style=""> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;fill-opacity:1.0000000;stroke-dasharray:none;" d="M 804.64950,250.44849 C 797.35720,250.48469 789.33209,251.98524 784.49454,257.96913 C 780.93740,262.11537 778.38323,267.02039 775.64377,271.69315 C 773.68125,276.21594 769.46739,297.45551 769.30129,304.87537 C 770.14526,316.85318 776.63805,328.66066 786.98642,334.95250 C 795.22467,338.99769 804.89497,338.64881 813.70686,337.08266 C 821.45161,335.53674 827.62366,329.95749 831.57563,323.32749 C 837.11921,314.80704 839.26003,304.08986 836.74694,294.17684 C 835.76180,288.84411 831.92018,270.31405 828.52987,266.57056 C 824.89455,259.95461 819.93817,253.06220 812.07514,251.41397 C 809.65774,250.76162 807.15196,250.45235 804.64950,250.44849 z " id="path1255" sodipodi:nodetypes="ccccccccccc" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 800.13750,250.65056 C 801.18353,251.26075 803.25316,249.31320 803.64542,263.39105 C 804.03768,277.46890 803.99154,332.67692 804.34021,335.11767 C 804.68888,337.29691 802.01036,338.15546 798.99628,337.91766" id="path1256" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 807.42479,250.62195 C 806.37876,251.23214 804.30913,249.28459 803.91687,263.36244 C 803.52461,277.44029 804.49532,333.01814 804.14665,335.45889 C 803.79798,337.63813 806.66142,337.94193 809.67549,337.70414" id="path1257" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 817.70960,290.28376 C 809.84745,280.10959 810.70190,277.13212 818.95501,270.89040 C 813.26525,268.19968 813.19141,265.32450 823.17748,259.01761" id="path1258" sodipodi:nodetypes="ccc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 787.90305,291.30471 C 795.76520,281.13054 794.91075,278.15307 786.65764,271.91135 C 792.34740,269.22063 792.42124,266.34545 782.43517,260.03856" id="path1259" sodipodi:nodetypes="ccc" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 799.72669,293.23848 C 796.52152,297.49150 789.40232,292.22145 787.89219,291.20442 C 786.38206,290.18739 784.19391,295.08761 779.75597,293.60830 C 775.50295,292.12899 776.05768,287.87597 776.05768,287.87597" id="path1260" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 802.03812,301.75908 C 797.90838,303.42330 787.64564,300.37222 786.13551,299.35519 C 784.62538,298.33816 782.43723,303.23838 777.99929,301.75907 C 773.74627,300.27976 771.52729,289.36983 771.52729,289.36983" id="path1261" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 792.23767,329.12637 C 782.56051,317.10695 791.52883,320.52786 791.86785,314.51815 C 792.57669,308.87827 798.04822,307.90662 793.98280,308.72802 C 790.96976,309.36580 788.07711,304.71769 779.29369,308.60089" id="path1262" sodipodi:nodetypes="czsz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 807.30819,291.84436 C 810.51336,296.09738 817.63256,290.82733 819.14269,289.81030 C 820.65282,288.79327 822.84097,293.69349 827.27891,292.21418 C 831.53193,290.73487 830.97720,286.48185 830.97720,286.48185" id="path1263" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 804.99676,300.36496 C 809.12650,302.02918 819.38924,298.97810 820.89937,297.96107 C 822.40950,296.94404 824.59765,301.84426 829.03559,300.36495 C 833.28861,298.88564 835.50759,287.97571 835.50759,287.97571" id="path1264" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 814.79721,327.73225 C 824.47437,315.71283 815.50605,319.13374 815.16703,313.12403 C 814.45819,307.48415 808.98666,306.51250 813.05208,307.33390 C 816.06512,307.97168 818.95777,303.32357 827.74119,307.20677" id="path1265" sodipodi:nodetypes="czsz" /> </g> <g id="g1266" transform="matrix(0.487368,0.000000,0.000000,0.429443,313.4603,114.8768)" style=""> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 794.59961,348.91352 C 790.03327,348.45566 780.97520,354.26681 777.00586,356.66352 C 766.15728,363.21403 755.31838,379.56855 755.31836,395.94477 C 755.31836,400.03884 751.87463,403.64256 756.78711,416.44477 C 762.83073,427.45552 789.50501,430.88985 789.72461,424.10102 C 789.94420,417.31220 785.63328,420.68577 790.94336,415.50727 C 791.10542,425.53543 794.55927,425.71342 794.41211,431.63227 C 794.31794,435.15902 794.12648,443.04382 795.47461,441.69477 L 797.41211,442.00727 L 797.41211,442.13227 L 797.78711,442.06977 L 799.72461,441.75727 C 801.07274,443.10632 800.88128,435.22151 800.78711,431.69477 C 800.63995,425.77592 804.09380,425.59792 804.25586,415.56977 C 809.56594,420.74827 805.25502,417.37469 805.47461,424.16352 C 805.69421,430.95235 832.36849,427.51801 838.41211,416.50727 C 843.32459,403.70506 839.88086,400.10133 839.88086,396.00727 C 839.88084,379.63105 829.04194,363.27652 818.19336,356.72602 C 814.22402,354.32931 805.16595,348.51815 800.59961,348.97602 C 799.07750,349.12864 798.05155,349.97479 797.88086,351.88227 L 797.07659,404.26454 L 797.31836,351.81977 C 797.14767,349.91230 796.12172,349.06614 794.59961,348.91352 z " id="path1241" sodipodi:nodetypes="ccccccccccccccccccccccc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 755.15810,397.61810 C 754.11207,399.97167 758.80832,400.24407 763.11776,401.94932 C 767.42719,403.65457 771.87284,407.31569 774.50971,408.07842 C 779.78346,409.60388 789.28491,410.08331 793.07678,409.12445 C 796.86865,408.16559 796.56356,405.20183 797.26091,401.27922" id="path1244" sodipodi:nodetypes="cszzz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 782.87797,392.91099 C 777.64781,386.11178 787.32360,386.89630 787.84663,382.71217 C 790.46170,372.51336 780.52440,370.94431 780.52440,370.94431 C 780.52440,370.94431 786.53909,363.36057 788.10813,359.17644 C 782.87797,353.42326 783.40098,354.20779 775.29423,357.86890" id="path1246" sodipodi:nodetypes="ccccc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 788.63115,418.53875 C 789.24133,410.95501 783.83682,410.30124 781.57042,409.12445" id="path1247" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 755.02735,402.26798 C 758.16545,409.59021 769.62822,411.98736 774.90197,413.51282" id="path1248" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 811.94047,392.52010 C 817.17063,385.72089 807.49484,386.50541 806.97181,382.32128 C 804.35674,372.12247 814.29404,370.55342 814.29404,370.55342 C 814.29404,370.55342 808.27935,362.96968 806.71031,358.78555 C 811.94047,353.03237 811.41746,353.81690 819.52421,357.47801" id="path1249" sodipodi:nodetypes="ccccc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 806.18729,418.14786 C 805.57711,410.56412 810.98162,409.91035 813.24802,408.73356" id="path1250" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 839.79109,401.87709 C 836.65299,409.19932 825.19022,411.59647 819.91647,413.12193" id="path1251" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 839.64815,397.14271 C 840.69418,399.49628 835.99793,399.76868 831.68849,401.47393 C 827.37906,403.17918 822.93341,406.84030 820.29654,407.60303 C 815.02279,409.12849 805.52134,409.60792 801.72947,408.64906 C 797.93760,407.69020 796.93515,402.37287 797.28383,397.92724" id="path1252" sodipodi:nodetypes="cszzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 760.38827,385.32722 C 752.71737,406.42221 761.34713,397.35659 766.14145,397.61810" id="path1253" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 833.91474,384.86121 C 841.58564,405.95620 832.95588,396.89058 828.16156,397.15209" id="path1254" sodipodi:nodetypes="cz" /> </g> <rect style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;" id="rect1342" width="106.29922" height="106.29922" x="678.02699" y="257.57566" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke-width:0.84895535pt;" id="rect1300" width="42.038873" height="31.251435" x="577.48017" y="355.15182" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 585.39981,368.71772 C 595.39981,369.55105 611.65089,374.39889 615.88182,379.14146 C 620.11275,384.31923 621.65174,382.78809 623.97519,388.42080 C 625.83395,393.88440 626.66596,396.13459 614.79096,397.38459 C 602.91596,398.00959 579.84943,391.38777 567.95818,382.48985 C 556.06694,374.46233 550.94562,372.94946 552.82062,361.57922 C 554.69562,349.76704 569.06250,334.86218 591.87500,334.23718 C 614.68750,332.98718 635.31250,340.38301 643.75000,355.48718 C 651.56250,370.59135 648.46967,378.29310 643.78217,382.04310 C 639.09467,385.79310 631.44519,384.45036 623.11186,386.32536" id="path1301" sodipodi:nodetypes="czzzzzzzzz" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 611.66596,385.50959 C 604.16596,383.00959 590.35311,382.60170 583.47811,376.35170" id="path1302" sodipodi:nodetypes="cc" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 592.66063,336.86850 C 598.86190,345.30503 604.92417,355.07014 602.71447,365.23480" id="path1303" sodipodi:nodetypes="cc" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 609.51069,344.81342 C 624.10275,344.57017 628.11190,344.21099 630.20397,355.19433 C 635.95715,352.05623 638.95397,353.81615 640.20397,366.31615" id="path1304" sodipodi:nodetypes="ccc" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 620.21706,362.57924 C 620.21706,362.57924 610.95580,381.48089 620.33080,380.85589 C 629.70580,380.23089 626.05002,380.28181 628.70167,379.17696" id="path1305" sodipodi:nodetypes="ccc" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 565.74009,361.50702 C 565.74009,361.50702 574.14469,356.44952 582.12195,352.00386 C 590.09920,348.08121 587.55049,347.42089 587.77146,341.89662 L 591.98094,350.60103 C 595.33715,357.54102 598.53331,356.11130 595.55959,362.81588" id="path1306" sodipodi:nodetypes="czczz" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 601.31298,337.74082 C 614.47809,348.72995 606.47413,361.56650 612.31037,373.07050" id="path1307" sodipodi:nodetypes="cc" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0903397;" d="M 707.72710,418.48163 C 703.50641,414.69683 702.27080,417.21075 699.44787,417.57363" id="path1387" sodipodi:nodetypes="cc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0903397;" d="M 725.11736,413.48274 C 719.32763,412.83604 715.73844,415.08845 712.91551,415.45133" id="path1389" sodipodi:nodetypes="cc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0903397;" d="M 699.48958,421.09685 C 695.79191,420.95903 688.54161,427.33639 686.24170,435.60327" id="path1390" sodipodi:nodetypes="cc" /> <path style="font-size:12;fill:url(#linearGradient639);fill-opacity:0.49999997;fill-rule:evenodd;stroke:none;stroke-width:1pt;" d="M 282.25529,739.70004 C 263.03059,739.70004 246.57621,750.68303 239.10144,766.34845 C 245.01961,769.38040 251.62479,772.25260 259.40914,770.16617 C 274.02627,766.97386 278.59576,759.44837 285.90432,756.25608 C 301.22420,755.68353 308.56128,763.55367 323.66395,763.21113 C 315.56649,749.26108 300.15727,739.70005 282.25529,739.70004 z " id="path1561" inkscape:export-filename="C:\pas\mricron\btn\new\autocontrast.png" inkscape:export-xdpi="22.289494" inkscape:export-ydpi="22.289494" /> <path sodipodi:type="arc" style="font-size:12px;fill:url(#radialGradient3181);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none" id="path1562" sodipodi:cx="271.35837" sodipodi:cy="796.11926" sodipodi:rx="37.428738" sodipodi:ry="37.428738" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" transform="matrix(1.269231,0,0,1.209574,-59.82695,-177.4099)" inkscape:export-filename="C:\pas\mricron\btn\new\autocontrast.png" inkscape:export-xdpi="22.289494" inkscape:export-ydpi="22.289494" /> <path sodipodi:type="arc" style="font-size:12;fill:url(#radialGradient983);fill-opacity:0.50000000;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none;" id="path1574" sodipodi:cx="271.35836792" sodipodi:cy="796.11926270" sodipodi:rx="37.42873764" sodipodi:ry="37.42873764" d="M 308.787106 796.119263 A 37.428738 37.428738 0 1 0 233.929630,796.119263 A 37.4287 37.4287 0 1 0 308.787 796.119 L 271.358368 796.119263 z" transform="matrix(0.484769,0.000000,0.000000,0.461984,554.2006,323.4255)" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:2.3750000;fill-opacity:1.0000000;" id="rect1280" width="69.963570" height="45.246185" x="128.72227" y="535.48883" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke-width:0.84895535pt;" id="rect1278" width="42.038872" height="31.251434" x="158.54723" y="572.81548" transform="matrix(-0.578460,0.000000,0.000000,0.578460,265.2767,219.3138)" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:4.1057291;" d="M 163.87618,583.27959 C 173.87618,584.11292 182.62618,587.86292 188.25118,596.40459 C 193.87618,605.57126 193.25118,606.40459 193.25118,606.40459 C 193.25118,606.40459 194.50118,615.15459 182.62618,616.40459 C 170.75118,617.02959 157.44312,604.81988 143.69312,604.81988 C 130.56812,604.81988 125.75118,602.77483 127.62618,591.40459 C 129.50118,579.59241 142.93868,553.90459 165.75118,553.27959 C 188.56368,552.02959 209.18868,559.42542 217.62618,574.52959 C 225.43868,589.63376 221.68868,601.40459 217.00118,605.15459 C 212.31368,608.90459 201.58451,603.90459 193.25118,605.77959" id="path1279" sodipodi:nodetypes="czzzzzzzzz" transform="matrix(-0.578460,0.000000,0.000000,0.578460,265.2767,219.3138)" /> <g id="g1249" transform="translate(-9.414290,-1.046033)" style=""> <rect style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:2.3750000;stroke-dasharray:none;" id="rect1289" width="69.963570" height="45.246185" x="128.72227" y="535.48883" transform="matrix(-1.000000,0.000000,0.000000,1.000000,355.1279,42.36432)" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke-width:0.84895535pt;" id="rect1291" width="42.038872" height="31.251434" x="158.54723" y="572.81548" transform="matrix(0.578460,0.000000,0.000000,0.578460,89.85120,261.6781)" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:4.1057290;stroke-dasharray:none;" d="M 163.87618,583.27959 C 173.87618,584.11292 182.62618,587.86292 188.25118,596.40459 C 193.87618,605.57126 193.25118,606.40459 193.25118,606.40459 C 193.25118,606.40459 194.50118,615.15459 182.62618,616.40459 C 170.75118,617.02959 157.44312,604.81988 143.69312,604.81988 C 130.56812,604.81988 125.75118,602.77483 127.62618,591.40459 C 129.50118,579.59241 142.93868,553.90459 165.75118,553.27959 C 188.56368,552.02959 209.18868,559.42542 217.62618,574.52959 C 225.43868,589.63376 221.68868,601.40459 217.00118,605.15459 C 212.31368,608.90459 201.58451,603.90459 193.25118,605.77959" id="path1292" sodipodi:nodetypes="czzzzzzzzz" transform="matrix(0.578460,0.000000,0.000000,0.578460,89.85120,261.6781)" /> </g> <rect style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:2.3750000;" id="rect1268" width="69.963570" height="45.246185" x="128.72227" y="535.48883" transform="matrix(-1.000000,0.000000,0.000000,1.000000,254.4474,140.4299)" /> <path sodipodi:type="arc" style="fill:#9999ff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt;" id="path1285" sodipodi:cx="88.389725" sodipodi:cy="698.28027" sodipodi:rx="18.305565" sodipodi:ry="18.305565" d="M 106.69529 698.28027 A 18.305565 18.305565 0 1 0 70.084160,698.28027 A 18.305565 18.305565 0 1 0 106.69529 698.28027 z" transform="translate(3.138097,1.046032)" /> <rect style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:2.3750000;" id="rect1290" width="69.963570" height="45.246185" x="-120.45193" y="551.95033" transform="scale(-1.000000,1.000000)" /> <path style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-opacity:1.0000000;stroke-width:2.5000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 51.673228,577.76346 L 120.04088,577.76346" id="path1299" /> <path style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-opacity:1.0000000;stroke-width:2.5000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 88.241974,551.52936 L 87.447001,596.44531" id="path1300" sodipodi:nodetypes="cc" /> <rect style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.3750000;" id="rect1301" width="69.963570" height="45.246185" x="-120.25873" y="552.13202" transform="scale(-1.000000,1.000000)" /> <rect style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt;" id="rect1302" width="8.9940901" height="9.2751551" x="83.195328" y="573.14581" /> <path style="font-size:12.000000;fill:url(#linearGradient968);fill-opacity:0.70196003;stroke:#1c66f9;stroke-width:1.9242834;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99000001;" d="M 37.920277,322.15339 C 38.332250,320.95292 39.768025,319.75197 40.999014,319.93377 L 78.169327,327.96556 C 81.048244,325.43887 85.262603,322.36297 89.606623,323.13302 L 95.922292,324.00942 L 103.90333,325.57660 C 108.56248,326.97946 112.24447,329.89321 112.63056,335.69148 L 112.58162,405.54600 L 37.627148,381.65255 L 37.920277,322.15339 z " id="path1266" sodipodi:nodetypes="cccccccccc" /> <path style="font-size:12.000000;fill:#4789f7;stroke:#1c4ed9;stroke-width:1.7125434;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99216002;" d="M 37.528348,381.35197 L 112.74823,405.58198 L 109.98730,410.63535 L 35.227003,384.92024 L 37.528348,381.35197 z " id="path1271" sodipodi:nodetypes="ccccc" /> <g id="g1279" transform="matrix(0.688750,0.000000,0.000000,0.640474,44.12231,204.0360)"> <path style="fill-rule:evenodd;stroke:none;stroke-width:0.91963024pt;" d="M 15.411826,279.67519 L 107.16635,280.32772 L 105.78092,271.91017 C 104.50888,267.92580 100.16017,263.55105 99.313146,259.07319 C 98.024176,254.59533 104.23642,257.47279 103.48688,250.11822 C 102.73733,242.76364 101.33093,223.23927 90.699786,212.93098 C 79.756146,202.93519 70.616996,196.51871 51.220346,199.66990 C 33.073696,201.57109 22.663616,210.23449 15.263856,225.51906 C 7.6727159,240.80363 16.076616,259.82218 15.837966,266.94924 L 15.411826,279.67519 z " id="path1273" sodipodi:nodetypes="ccczzzzzzc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.0507082pt;fill-opacity:1.0000000;" d="M 81.667436,238.66160 C 80.982416,243.33580 68.662856,240.88582 68.468226,248.58013 C 68.273596,255.77527 84.079546,257.18713 89.984786,255.06933 C 95.890036,252.95153 99.758996,249.65718 99.148096,242.36255 C 98.537216,235.06792 96.575586,216.71313 75.014876,206.18816 C 53.886116,196.16236 29.955336,209.82744 22.306536,224.42792 C 14.657726,239.52760 14.049476,254.81975 23.120686,249.32889 C 31.759936,244.33718 42.301146,228.60033 58.113846,226.78187 C 73.494556,224.96340 82.352426,234.98574 81.667436,238.66160 z " id="path1274" sodipodi:nodetypes="czzzzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.0877723pt;fill-opacity:1.0000000;" d="M 46.065436,250.14579 C 44.767756,248.03998 45.172386,240.05319 38.251386,241.60591 C 31.330386,243.15862 23.814016,250.57710 21.730276,253.25121 C 19.646536,255.92534 20.762826,260.66971 21.730276,261.79111 C 22.697736,262.91251 28.204756,263.51633 29.767576,264.89651 C 31.330386,266.27670 34.976936,271.45240 36.911836,271.10736 C 38.846746,270.76231 42.790986,266.62175 42.939816,264.89653 C 43.088656,263.17129 47.363086,252.25163 46.065436,250.14579 z " id="path1275" sodipodi:nodetypes="czzzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:none;stroke-width:1.0507082pt;fill-opacity:1.0000000;" d="M 42.237126,279.80001 C 42.658006,275.59866 47.388376,258.94410 48.153616,253.91080 C 48.918846,248.87751 46.010966,251.41496 47.235346,249.16869 C 48.459706,246.92241 52.591946,241.63956 55.499816,240.43322 C 58.407706,239.22690 62.539946,239.92518 64.682586,241.04832 C 66.825226,242.17146 68.164386,245.92409 68.355686,247.17200 C 68.546986,248.41993 66.863496,249.83425 65.830426,249.41828 C 64.797366,249.00230 66.447386,242.49537 63.942946,244.49969 C 61.438506,246.68048 58.281376,250.37501 56.647666,251.91412 C 55.338616,253.45321 58.560756,252.66288 59.172936,253.91080 C 59.785116,255.15873 60.932956,257.23860 60.320776,259.40167 C 59.708576,261.56473 57.068536,265.51649 55.499816,266.88920 C 53.931086,268.26192 52.553686,265.59969 50.908446,267.63797 C 49.263196,269.67624 47.037236,278.02692 45.659806,279.98199 L 42.237126,279.80001 z " id="path1276" sodipodi:nodetypes="czzzzzzzzzzzzcc" /> <path style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:#800000;stroke-width:1.875;stroke-dasharray:none" d="M 41.081076,235.46675 C 41.510266,237.13987 42.851486,241.07668 43.817166,241.96244 C 44.782846,242.84822 46.848346,243.11067 47.197056,241.96244 C 47.545776,240.81421 45.212056,235.04026 51.059786,231.92364 C 57.068466,228.80702 66.457036,229.52876 69.407726,230.93945 C 72.358406,232.35012 77.320946,237.59917 72.626666,241.17509 C 68.737106,244.75098 78.179316,244.84941 80.191156,243.34031 C 82.202996,241.83121 85.125536,236.24432 82.523566,233.55418 C 79.921596,230.86405 73.325156,224.43697 67.209176,223.78085 C 61.093206,223.12471 46.472786,230.41454 44.460956,230.93945 C 42.288186,231.46435 40.651886,233.79361 41.081076,235.46675 z" id="path1277" sodipodi:nodetypes="czzzzzzzzzz" /> </g> <path style="font-size:12.000000;fill:url(#linearGradient967);fill-opacity:0.69929999;stroke:#1c66fb;stroke-width:1.7758849;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99216002;" d="M 17.536640,337.89268 C 16.523741,335.20546 17.516336,332.64170 19.932441,332.91461 L 55.676174,340.52075 L 57.880936,348.26473 L 73.479955,351.89199 L 71.204233,343.73873 L 87.288253,346.49326 C 89.414399,347.18490 91.065826,348.61636 92.573252,351.89801 L 109.47210,409.98240 L 35.111516,384.77857 L 17.536640,337.89268 z " id="path1272" sodipodi:nodetypes="ccccccccccc" /> <g id="g1317"> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:2.0770884;" d="M 472.42571,238.27147 C 472.33405,238.27145 472.24478,238.29291 472.15311,238.29398 L 472.15311,238.31648 C 472.08489,238.31034 472.01758,238.29395 471.94867,238.29398 C 471.78809,238.29403 471.63216,238.33557 471.47163,238.33899 L 471.47163,238.42899 C 471.37376,238.41606 471.27556,238.40652 471.17632,238.40649 C 471.10740,238.40647 471.04010,238.42285 470.97187,238.42899 L 470.97187,238.40649 C 470.88021,238.40543 470.79094,238.38396 470.69928,238.38399 C 465.87162,238.38545 461.03877,239.90805 457.81913,242.92943 C 456.20932,244.44011 446.99543,256.89920 450.09559,259.04098 C 457.81097,264.68512 464.49982,248.07035 457.36480,261.85375 C 456.64585,266.58811 456.46107,269.05668 456.41072,270.29207 C 456.30905,268.02898 455.46815,262.72102 451.04967,260.14359 C 447.35854,258.03472 444.93899,276.66261 444.93899,279.18042 C 444.93899,289.25168 451.37986,299.31925 457.81913,303.34776 C 461.08484,305.39084 466.00722,306.37150 470.90372,306.34054 L 470.90372,306.36305 C 471.15408,306.36510 471.40305,306.34374 471.65336,306.34054 L 471.65336,306.22803 C 471.84267,306.23528 472.03155,306.25211 472.22127,306.25053 L 472.22127,306.22803 C 477.11777,306.25899 482.04015,305.27835 485.30586,303.23524 C 491.74513,299.20674 498.18600,289.13916 498.18600,279.06791 C 498.18600,276.55010 495.76645,257.92220 492.07532,260.03107 C 487.65684,262.60851 486.81594,267.91647 486.71427,270.17956 C 486.66392,268.94417 486.47914,266.47559 485.76018,261.74124 C 478.62517,247.95784 485.31402,264.57260 493.02940,258.92847 C 496.12956,256.78669 486.91567,244.32759 485.30586,242.81691 C 482.08622,239.79554 477.25337,238.27293 472.42571,238.27147 z " id="path1267" transform="matrix(1.033174,0.000000,0.000000,0.909383,216.4479,268.3863)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.70418520pt;" d="M 468.24591,259.15861 C 468.51094,258.62567 467.79271,252.85171 466.69475,251.35949 C 465.59679,249.86726 463.96768,250.52503 463.70265,251.05797 C 463.43764,251.59090 465.07594,250.88137 466.17389,252.37359 C 467.27185,253.86581 467.98090,259.69155 468.24591,259.15861 z " id="path1270" sodipodi:nodetypes="czzzz" transform="matrix(1.033174,0.000000,0.000000,0.909383,216.4479,268.3863)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59326982pt;" d="M 463.34275,289.21648 C 461.03017,288.99344 460.56786,283.64967 458.96224,286.90958 C 457.28286,290.22776 460.74374,297.34319 461.04820,293.66548 C 461.27890,289.98777 465.58157,289.49777 463.34275,289.21648 z " id="path1278" sodipodi:nodetypes="czzz" transform="matrix(1.033174,0.000000,0.000000,0.909383,216.4479,268.3863)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.68256974pt;" d="M 708.64967,503.43717 C 708.37585,502.95253 709.11791,497.70179 710.25229,496.34479 C 711.38666,494.98778 713.06983,495.58594 713.34365,496.07058 C 713.61745,496.55524 711.92480,495.90999 710.79043,497.26699 C 709.65604,498.62400 708.92347,503.92182 708.64967,503.43717 z " id="path1283" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.57505898pt;" d="M 710.57739,531.81732 C 712.96669,531.61449 713.44433,526.75496 715.10322,529.71946 C 716.83831,532.73696 713.26262,539.20762 712.94806,535.86317 C 712.70970,532.51872 708.26430,532.07312 710.57739,531.81732 z " id="path1284" sodipodi:nodetypes="czzz" /> </g> <g id="g1329" transform="translate(-104.0802,-97.80402)"> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.8718444;" d="M 841.03523,592.70109 C 835.90467,592.76390 830.22818,593.56676 826.67923,597.28291 C 823.87668,600.24935 817.50896,615.99836 816.60602,618.30168 C 815.09992,624.27793 814.05854,630.78886 816.99244,636.56898 C 819.81959,643.25189 825.72828,649.72836 833.94116,650.75621 C 839.37129,651.44267 845.09032,651.35874 850.31458,649.72833 C 856.42815,647.71665 860.44343,642.53509 863.07436,637.37323 C 865.55779,632.40703 865.94287,626.74320 864.51563,621.47197 C 863.89507,618.11627 856.12574,599.89965 853.80199,597.15457 C 850.54532,594.03086 845.67202,592.69881 841.03523,592.70109 z " id="path1288" sodipodi:nodetypes="cccccccccc" transform="translate(-3.661113,-7.322226)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.63460236pt;" d="M 838.07247,610.64237 C 839.95513,610.18459 838.75317,605.01626 837.71507,603.73449 C 836.67696,602.45272 829.77408,601.13926 832.78769,603.68422 C 836.03445,606.02046 835.95665,611.10014 838.07247,610.64237 z " id="path1289" sodipodi:nodetypes="czzz" transform="translate(-3.661113,-7.322226)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.53464689pt;" d="M 835.74471,629.37680 C 833.55820,629.18522 829.82379,631.67928 828.30569,634.47943 C 826.71786,637.32962 829.99008,643.44151 830.27794,640.28249 C 830.49606,637.12348 837.86149,629.61842 835.74471,629.37680 z " id="path1290" sodipodi:nodetypes="czzz" transform="translate(-3.661113,-7.322226)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.63460231pt;" d="M 842.27092,610.67154 C 840.38825,610.21376 841.59021,605.04542 842.62832,603.76366 C 843.66642,602.48189 850.56930,601.16843 847.55570,603.71338 C 844.30893,606.04963 844.38672,611.12931 842.27092,610.67154 z " id="path1293" sodipodi:nodetypes="czzz" transform="translate(-3.661113,-7.322226)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.53464689pt;" d="M 844.89363,628.76239 C 847.08014,628.57081 850.81456,631.06487 852.33265,633.86502 C 853.92048,636.71521 850.64827,642.82710 850.36040,639.66808 C 850.14228,636.50907 842.77686,629.00401 844.89363,628.76239 z " id="path1310" sodipodi:nodetypes="czzz" transform="translate(-3.661113,-7.322226)" /> </g> <path sodipodi:type="arc" style="font-size:12px;fill:url(#radialGradient704);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.87644994;stroke-dasharray:none" id="path1268" sodipodi:cx="271.35837" sodipodi:cy="796.11926" sodipodi:rx="37.428738" sodipodi:ry="37.428738" d="M 308.78711,796.11926 A 37.428738,37.428738 0 1 1 233.92963,796.11926 A 37.428738,37.428738 0 1 1 308.78711,796.11926 z" transform="matrix(1.269231,0,0,1.209574,239.61631,-65.007091)" inkscape:export-filename="C:\pas\mricron\btn\3dx.png" inkscape:export-xdpi="22.768808" inkscape:export-ydpi="22.768808" /> <path style="font-size:12px;fill:url(#linearGradient1110);fill-opacity:0.38016998;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 584.02153,852.31705 C 564.79683,852.31705 548.34245,863.30004 540.86768,878.96546 C 546.78585,881.99741 553.39103,884.86961 561.17538,882.78318 C 575.79251,879.59087 580.362,872.06538 587.67056,868.87309 C 602.99044,868.30054 610.32752,876.17068 625.43019,875.82814 C 617.33273,861.87809 601.92351,852.31706 584.02153,852.31705 z" id="path1269" inkscape:export-filename="C:\pas\mricron\btn\3dx.png" inkscape:export-xdpi="22.768808" inkscape:export-ydpi="22.768808" /> <text xml:space="preserve" style="font-size:53.10573959px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial Black" x="467.65067" y="1061.1675" id="text1284" sodipodi:linespacing="100%" transform="scale(1.1590137,0.8628026)" inkscape:export-filename="C:\pas\mricron\btn\3dx.png" inkscape:export-xdpi="22.768808" inkscape:export-ydpi="22.768808"><tspan x="467.65067" y="1061.1675" sodipodi:role="line" id="tspan1287">3D</tspan></text> <path style="font-size:12px;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 862.36154,831.74143 L 862.36154,924.49 C 889.80881,924.49 912.07889,903.73438 912.07886,878.13172 C 912.07886,852.52905 889.80879,831.74141 862.36154,831.74143 z " id="path3207" /> <g id="g4179"> <path transform="matrix(1.269231,0,0,1.209574,-252.0699,-51.3724)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path3205" style="font-size:12px;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> <path sodipodi:nodetypes="csccccccc" id="path2293" d="M 121.04942,876.41746 C 115.9942,876.41746 85.290278,896.93033 69.807528,903.81184 C 65.343898,905.79576 131.15987,906.55128 131.15987,906.55128 L 82.62969,924.35764 L 92.74016,875.04774 L 51.091495,891.29811 L 65.441938,915.45446 L 113.97211,928.4668 L 82.951128,953.93266" style="fill:none;fill-rule:evenodd;stroke:red;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path id="path3209" d="M 92.371567,865.47065 C 73.146867,865.47065 56.692487,876.45364 49.217717,892.11906 C 55.135887,895.15101 61.741067,898.02321 69.525417,895.93678 C 84.142547,892.74447 88.712037,885.21898 96.020597,882.02669 C 111.34048,881.45414 118.67756,889.32428 133.78023,888.98174 C 125.68277,875.03169 110.27355,865.47066 92.371567,865.47065 z " style="font-size:12px;fill:url(#linearGradient3271);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1pt" /> <path transform="matrix(1.269231,0,0,1.209574,-254.2131,-49.87948)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path3267" style="font-size:12px;fill:url(#radialGradient3289);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> </g> <g id="g4185" transform="matrix(0.587317,0,0,0.587317,135.8273,373.3777)"> <path transform="matrix(1.269231,0,0,1.209574,-252.0699,-51.3724)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path4187" style="font-size:12px;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> <path sodipodi:nodetypes="csccccccc" id="path4189" d="M 121.04942,876.41746 C 115.9942,876.41746 85.290278,896.93033 69.807528,903.81184 C 65.343898,905.79576 131.15987,906.55128 131.15987,906.55128 L 82.62969,924.35764 L 92.74016,875.04774 L 51.091495,891.29811 L 65.441938,915.45446 L 113.97211,928.4668 L 82.951128,953.93266" style="fill:none;fill-rule:evenodd;stroke:red;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path id="path4191" d="M 92.371567,865.47065 C 73.146867,865.47065 56.692487,876.45364 49.217717,892.11906 C 55.135887,895.15101 61.741067,898.02321 69.525417,895.93678 C 84.142547,892.74447 88.712037,885.21898 96.020597,882.02669 C 111.34048,881.45414 118.67756,889.32428 133.78023,888.98174 C 125.68277,875.03169 110.27355,865.47066 92.371567,865.47065 z " style="font-size:12px;fill:url(#linearGradient4195);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1pt" /> <path transform="matrix(1.269231,0,0,1.209574,-254.2131,-49.87948)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path4193" style="font-size:12px;fill:url(#radialGradient4197);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> </g> <g id="g4199" transform="matrix(0.75239,0,0,0.75239,212.8041,226.4211)"> <path transform="matrix(1.269231,0,0,1.209574,-252.0699,-51.3724)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path4201" style="font-size:12px;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> <path sodipodi:nodetypes="csccccccc" id="path4203" d="M 121.04942,876.41746 C 115.9942,876.41746 85.290278,896.93033 69.807528,903.81184 C 65.343898,905.79576 131.15987,906.55128 131.15987,906.55128 L 82.62969,924.35764 L 92.74016,875.04774 L 51.091495,891.29811 L 65.441938,915.45446 L 113.97211,928.4668 L 82.951128,953.93266" style="fill:none;fill-rule:evenodd;stroke:red;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path id="path4205" d="M 92.371567,865.47065 C 73.146867,865.47065 56.692487,876.45364 49.217717,892.11906 C 55.135887,895.15101 61.741067,898.02321 69.525417,895.93678 C 84.142547,892.74447 88.712037,885.21898 96.020597,882.02669 C 111.34048,881.45414 118.67756,889.32428 133.78023,888.98174 C 125.68277,875.03169 110.27355,865.47066 92.371567,865.47065 z " style="font-size:12px;fill:url(#linearGradient4209);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1pt" /> <path transform="matrix(1.269231,0,0,1.209574,-254.2131,-49.87948)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path4207" style="font-size:12px;fill:url(#radialGradient4211);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> </g> <g id="g4213" transform="matrix(0.355527,0,0,1.090014,324.7627,-82.64672)"> <path transform="matrix(1.269231,0,0,1.209574,-252.0699,-51.3724)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path4215" style="font-size:12px;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> <path sodipodi:nodetypes="csccccccc" id="path4217" d="M 121.04942,876.41746 C 115.9942,876.41746 85.290278,896.93033 69.807528,903.81184 C 65.343898,905.79576 131.15987,906.55128 131.15987,906.55128 L 82.62969,924.35764 L 92.74016,875.04774 L 51.091495,891.29811 L 65.441938,915.45446 L 113.97211,928.4668 L 82.951128,953.93266" style="fill:none;fill-rule:evenodd;stroke:red;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path id="path4219" d="M 92.371567,865.47065 C 73.146867,865.47065 56.692487,876.45364 49.217717,892.11906 C 55.135887,895.15101 61.741067,898.02321 69.525417,895.93678 C 84.142547,892.74447 88.712037,885.21898 96.020597,882.02669 C 111.34048,881.45414 118.67756,889.32428 133.78023,888.98174 C 125.68277,875.03169 110.27355,865.47066 92.371567,865.47065 z " style="font-size:12px;fill:url(#linearGradient4223);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1pt" /> <path transform="matrix(1.269231,0,0,1.209574,-254.2131,-49.87948)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path4221" style="font-size:12px;fill:url(#radialGradient4225);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> </g> <flowRoot xml:space="preserve" id="flowRoot4227" style="font-size:36px;font-weight:bold;fill:navy" transform="translate(33.72834,142.0141)"><flowRegion id="flowRegion4229"><rect id="rect4231" width="361.5441" height="35.503513" x="42.604218" y="822.77283" style="font-size:36px;font-weight:bold;fill:navy" /></flowRegion><flowPara id="flowPara4233">A B C D</flowPara></flowRoot> <rect style="fill:#9999ff;fill-rule:evenodd;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none" id="rect2823" width="42.038872" height="31.251434" x="844.13184" y="324.25101" inkscape:export-filename="C:\pas\mricron\btn\mricrogl256.png" inkscape:export-xdpi="234.8979" inkscape:export-ydpi="234.8979" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none" d="M 856.65166,333.33636 C 866.65166,334.16969 875.40166,337.91969 881.02666,346.46136 C 886.65166,355.62803 886.02666,356.46136 886.02666,356.46136 C 886.02666,356.46136 887.27666,365.21136 875.40166,366.46136 C 863.52666,367.08636 850.2186,354.87665 836.4686,354.87665 C 823.3436,354.87665 818.52666,352.8316 820.40166,341.46136 C 822.27666,329.64918 835.71416,303.96136 858.52666,303.33636 C 881.33916,302.08636 901.96416,309.48219 910.40166,324.58636 C 918.21416,339.69053 914.46416,351.46136 909.77666,355.21136 C 905.08916,358.96136 894.35999,353.96136 886.02666,355.83636" id="path2825" sodipodi:nodetypes="czzzzzzzzz" inkscape:export-filename="C:\pas\mricron\btn\mricrogl256.png" inkscape:export-xdpi="234.8979" inkscape:export-ydpi="234.8979" /> <path style="fill:none;fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none" d="M 872.27666,354.58636 C 864.77666,352.08636 861.65166,352.08636 854.77666,345.83636 C 847.90166,339.58636 846.65166,333.33636 846.65166,333.33636" id="path2827" sodipodi:nodetypes="ccc" inkscape:export-filename="C:\pas\mricron\btn\mricrogl256.png" inkscape:export-xdpi="234.8979" inkscape:export-ydpi="234.8979" /> <path style="fill:none;fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none" d="M 864.15166,303.96136 C 864.77666,316.46136 871.57583,324.16932 869.36613,334.33398" id="path2829" sodipodi:nodetypes="cc" inkscape:export-filename="C:\pas\mricron\btn\mricrogl256.png" inkscape:export-xdpi="234.8979" inkscape:export-ydpi="234.8979" /> <path style="fill:none;fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none" d="M 877.55642,310.93834 C 892.14848,310.69509 894.76356,313.31017 896.85563,324.29351 C 902.60881,321.15541 905.60563,322.91533 906.85563,335.41533" id="path2831" sodipodi:nodetypes="ccc" inkscape:export-filename="C:\pas\mricron\btn\mricrogl256.png" inkscape:export-xdpi="234.8979" inkscape:export-ydpi="234.8979" /> <path style="fill:none;fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none" d="M 886.86872,331.67842 C 886.86872,331.67842 877.60746,350.58007 886.98246,349.95507 C 896.35746,349.33007 892.70168,349.38099 895.35333,348.27614" id="path2833" sodipodi:nodetypes="ccc" inkscape:export-filename="C:\pas\mricron\btn\mricrogl256.png" inkscape:export-xdpi="234.8979" inkscape:export-ydpi="234.8979" /> <path style="fill:none;fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none" d="M 832.39175,330.6062 C 832.39175,330.6062 835.53899,323.02 843.51625,318.57434 C 851.4935,314.65169 856.99028,311.87715 857.21125,306.35288 L 856.54834,312.02229 C 855.82047,318.24722 865.18497,325.21048 862.21125,331.91506" id="path2835" sodipodi:nodetypes="czczz" inkscape:export-filename="C:\pas\mricron\btn\mricrogl256.png" inkscape:export-xdpi="234.8979" inkscape:export-ydpi="234.8979" /> <path style="fill:none;fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none" d="M 873.54091,303.21172 C 878.8063,313.50201 874.98455,328.73092 878.96203,339.55849" id="path2837" sodipodi:nodetypes="cc" inkscape:export-filename="C:\pas\mricron\btn\mricrogl256.png" inkscape:export-xdpi="234.8979" inkscape:export-ydpi="234.8979" /> <path style="fill:#000054;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 270.34766,432.89286 C 266.96559,425.47501 260.3235,438.26052 255.49727,449.30783 C 250.67104,460.73738 245.34246,489.00581 249.10203,493.65088 C 252.8616,498.29594 258.35056,495.22819 262.11012,491.11346 C 265.86969,486.99873 263.96524,466.06199 265.1515,456.9486 C 266.02526,447.83521 273.72973,440.31072 270.34766,432.89286 z" id="path3615" sodipodi:nodetypes="czzzzz" inkscape:export-filename="C:\pas\mricron\btn\pen24.png" inkscape:export-xdpi="24.462318" inkscape:export-ydpi="24.462318" /> <path style="fill:url(#linearGradient3627);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 256.35392,455.89784 C 254.95394,460.00092 253.32225,462.82318 252.15398,468.20706 C 250.98572,473.77723 249.31762,487.55379 250.22768,489.81755 C 251.13775,492.08131 252.46644,490.58625 253.3765,488.58094 C 254.28656,486.57564 253.82556,476.37217 254.11271,471.93078 C 254.32422,467.48938 255.87513,463.1938 256.35392,455.89784 z" id="path3617" sodipodi:nodetypes="czzzzc" inkscape:export-filename="C:\pas\mricron\btn\pen24.png" inkscape:export-xdpi="24.462318" inkscape:export-ydpi="24.462318" /> <path style="font-size:12px;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt" d="M 258.32385,516.10881 C 244.70346,512.53166 243.75131,505.12802 247.26278,500.13525 C 248.58676,498.73623 251.70024,496.59237 253.50771,496.72229 C 255.31518,496.85222 256.87341,497.76794 259.19467,499.43037 C 264.4622,503.38022 254.53224,505.09575 258.32385,516.10881 z" id="path3619" sodipodi:nodetypes="ccszc" inkscape:export-filename="C:\pas\mricron\btn\pen24.png" inkscape:export-xdpi="24.462318" inkscape:export-ydpi="24.462318" /> <path style="font-size:12px;fill:url(#linearGradient3629);fill-rule:evenodd;stroke-width:1pt" d="M 253.87333,511.50807 C 250.61538,510.68643 249.08112,510.84383 247.06823,505.91817 C 245.05534,501.30501 250.05982,499.78929 250.6541,499.16357 C 251.24838,498.53784 252.11602,498.95109 252.7103,499.50538 C 253.30458,500.05966 253.00354,502.88001 253.19105,504.10765 C 253.32917,505.3353 251.06068,507.46014 253.87333,511.50807 z" id="path3621" sodipodi:nodetypes="czzzzc" inkscape:export-filename="C:\pas\mricron\btn\pen24.png" inkscape:export-xdpi="24.462318" inkscape:export-ydpi="24.462318" /> <path style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path3623" d="M 326.05671,469.55122 C 326.88121,476.3815 303.915,485.28392 302.9894,489.2119 C 301.08731,493.55239 315.97044,503.85687 311.9364,508.99802 C 309.36025,516.74789 269.62905,520.69168 260.38548,518.28589 C 259.23168,516.89349 259.03156,513.70664 261.14461,511.80155 C 266.78432,508.49412 294.51355,511.32311 303.67001,506.3462 C 304.47331,504.25494 293.9717,493.73434 297.19274,488.16929 C 300.56999,481.31221 321.25824,474.15358 320.94168,470.1196 C 317.96164,465.56742 294.87588,458.40487 292.13778,454.47451 C 292.13778,454.47451 322.16638,463.8337 326.05671,469.55122 z" sodipodi:nodetypes="cccccccccc" inkscape:export-filename="C:\pas\mricron\btn\pen24.png" inkscape:export-xdpi="24.462318" inkscape:export-ydpi="24.462318" /> <rect style="fill:url(#linearGradient3646);fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:3.75;stroke-dasharray:none" id="rect3644" width="91.25" height="30" x="-184.68044" y="63.382465" ry="12.5" transform="scale(-1,1)" inkscape:export-xdpi="22.535858" inkscape:export-ydpi="22.535858" inkscape:export-filename="C:\pas\mricron\btn\new\colorbarzero.png" /> <path style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:5.22945166;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 103.12986,109.15218 C 103.12986,114.14532 100.93311,118.19773 98.226386,118.19773 C 95.519665,118.19773 93.322908,114.14532 93.322908,109.15218 C 93.322908,104.15903 95.519665,100.10663 98.226386,100.10663 C 100.93311,100.10663 103.12986,104.15903 103.12986,109.15218 z" id="path3648" inkscape:export-filename="C:\pas\mricron\btn\new\colorbarzero.png" inkscape:export-xdpi="22.535858" inkscape:export-ydpi="22.535858" /> <path sodipodi:type="star" style="opacity:0.78534031000000004;fill:#0000c0;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path3650" sodipodi:sides="3" sodipodi:cx="139.64716" sodipodi:cy="147.0226" sodipodi:r1="9.4676037" sodipodi:r2="4.7338018" sodipodi:arg1="-1.5707963" sodipodi:arg2="-0.52359878" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="M 139.64716,137.55499 L 143.74675,144.6557 L 147.84634,151.7564 L 139.64716,151.7564 L 131.44797,151.7564 L 135.54756,144.6557 L 139.64716,137.55499 z" transform="matrix(1,0,0,1.3333333,-15.384856,-87.864153)" inkscape:export-filename="C:\pas\mricron\btn\new\colorbarzero.png" inkscape:export-xdpi="22.535858" inkscape:export-ydpi="22.535858" /> <path sodipodi:type="star" style="opacity:0.78534031000000004;fill:#0000c0;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path3652" sodipodi:sides="3" sodipodi:cx="139.64716" sodipodi:cy="147.0226" sodipodi:r1="9.4676037" sodipodi:r2="4.7338018" sodipodi:arg1="-1.5707963" sodipodi:arg2="-0.52359878" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="M 139.64716,137.55499 L 143.74675,144.6557 L 147.84634,151.7564 L 139.64716,151.7564 L 131.44797,151.7564 L 135.54756,144.6557 L 139.64716,137.55499 z" transform="matrix(1,0,0,1.3333333,37.278685,-87.864153)" inkscape:export-filename="C:\pas\mricron\btn\new\colorbarzero.png" inkscape:export-xdpi="22.535858" inkscape:export-ydpi="22.535858" /> <path style="fill:none;fill-rule:evenodd;stroke:#0000c0;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 246.74941,-78.424713 L 339.05855,-78.424713" id="path3656" inkscape:export-filename="C:\pas\mricron\btn\new\crosshairs.png" inkscape:export-xdpi="20.607124" inkscape:export-ydpi="20.607124" /> <path style="fill:none;fill-rule:evenodd;stroke:#0000c0;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" d="M 269.23498,-111.56132 L 269.23498,-12.743213" id="path3660" inkscape:export-filename="C:\pas\mricron\btn\new\crosshairs.png" inkscape:export-xdpi="20.607124" inkscape:export-ydpi="20.607124" /> <path style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 246.74941,-37.595672 L 339.05855,-37.595672" id="path3658" inkscape:export-filename="C:\pas\mricron\btn\new\crosshairs.png" inkscape:export-xdpi="20.607124" inkscape:export-ydpi="20.607124" /> <path style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 301.18814,-111.56132 L 301.18814,-12.743208" id="path3662" inkscape:export-filename="C:\pas\mricron\btn\new\crosshairs.png" inkscape:export-xdpi="20.607124" inkscape:export-ydpi="20.607124" /> <path sodipodi:type="arc" style="font-size:12px;fill:url(#linearGradient3670);fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#0050fb;stroke-width:5.21357274;stroke-dasharray:none;stroke-opacity:1;stroke-miterlimit:4" id="path3664" sodipodi:cx="604.88873" sodipodi:cy="441.2019" sodipodi:rx="44.214264" sodipodi:ry="13.483783" d="M 649.103,441.2019 A 44.214264,13.483783 0 1 1 560.67447,441.2019 A 44.214264,13.483783 0 1 1 649.103,441.2019 z" transform="matrix(1.042553,0,0,0.882208,-202.39952,-492.90915)" inkscape:export-filename="C:\pas\mricron\btn\bucket24.png" inkscape:export-xdpi="21.807127" inkscape:export-ydpi="21.807127" /> <path style="fill:#fb4100;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 388.75413,-92.159361 C 398.21827,-114.55406 414.50883,-97.128541 426.45531,-96.134721 C 436.85027,-96.631621 437.93631,-123.46525 457.64022,-118.99296 C 466.79401,-116.34273 464.31845,-65.226501 451.12398,-55.884321 C 432.66039,-43.308281 379.28998,-70.261601 388.75413,-92.159361 z" id="path3666" sodipodi:nodetypes="cccsz" inkscape:export-filename="C:\pas\mricron\btn\bucket24.png" inkscape:export-xdpi="21.807127" inkscape:export-ydpi="21.807127" /> <path style="font-size:12px;fill:url(#radialGradient3672);fill-opacity:0.98999999000000005;stroke:#0c1dfb;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.98999999000000005;stroke-miterlimit:4;stroke-dasharray:none" d="M 382.47734,-101.30596 C 393.1275,-92.738341 418.28528,-92.083351 431.66947,-91.877801 C 445.05365,-91.672251 468.18046,-94.547801 474.63455,-102.46773 L 466.32688,-31.133981 C 455.47903,-26.010751 443.69045,-22.870101 430.02041,-23.233561 C 416.35037,-23.597011 399.23099,-25.804731 389.95102,-30.824961 L 382.47734,-101.30596 z" id="path3668" sodipodi:nodetypes="czcczcc" inkscape:export-xdpi="21.807127" inkscape:export-ydpi="21.807127" inkscape:export-filename="C:\pas\mricron\btn\bucket24.png" /> <rect style="opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.89315641;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="rect3682" width="19.872375" height="19.872383" x="575.12762" y="-127.5102" inkscape:export-filename="C:\pas\mricron\btn\hires.png" inkscape:export-xdpi="19.659172" inkscape:export-ydpi="19.659172" /> <rect style="font-size:12px;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" id="rect3684" width="106.29922" height="106.29922" x="375" y="6.0629654" /> <rect style="opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.89315641;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="rect3700" width="19.872375" height="19.872383" x="595.12762" y="-107.5102" inkscape:export-filename="C:\pas\mricron\btn\hires.png" inkscape:export-xdpi="19.659172" inkscape:export-ydpi="19.659172" /> <rect style="opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.89315641;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="rect3702" width="19.872375" height="19.872383" x="615.12762" y="-87.510201" inkscape:export-filename="C:\pas\mricron\btn\hires.png" inkscape:export-xdpi="19.659172" inkscape:export-ydpi="19.659172" /> <rect style="opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.89315641;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="rect3704" width="19.872375" height="19.872383" x="595.12762" y="-67.637817" inkscape:export-filename="C:\pas\mricron\btn\hires.png" inkscape:export-xdpi="19.659172" inkscape:export-ydpi="19.659172" /> <rect style="opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.89315641;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="rect3706" width="19.872375" height="19.872383" x="575.12762" y="-47.637817" inkscape:export-filename="C:\pas\mricron\btn\hires.png" inkscape:export-xdpi="19.659172" inkscape:export-ydpi="19.659172" /> <path style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 625,-127.63782 L 665,-77.637811 L 625,-27.637811 L 645,-27.637811 L 685,-77.637811 L 645,-127.63782 L 625,-127.63782 z" id="path3708" inkscape:export-filename="C:\pas\mricron\btn\hires.png" inkscape:export-xdpi="19.659172" inkscape:export-ydpi="19.659172" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke-width:0.84895535pt" id="rect2871" width="42.038872" height="31.251434" x="545.31689" y="-195.52676" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="58.834469" inkscape:export-ydpi="58.834469" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none" d="M 557.83671,-186.4414 C 567.83671,-185.60807 576.58671,-181.85807 582.21171,-173.3164 C 587.83671,-164.14973 587.21171,-163.3164 587.21171,-163.3164 C 587.21171,-163.3164 588.46171,-154.5664 576.58671,-153.3164 C 564.71171,-152.6914 551.40365,-164.90111 537.65365,-164.90111 C 524.52865,-164.90111 519.71171,-166.94616 521.58671,-178.3164 C 523.46171,-190.12858 536.89921,-215.8164 559.71171,-216.4414 C 582.52421,-217.6914 603.14921,-210.29557 611.58671,-195.1914 C 619.39921,-180.08723 615.64921,-168.3164 610.96171,-164.5664 C 606.27421,-160.8164 595.54504,-165.8164 587.21171,-163.9414" id="path2873" sodipodi:nodetypes="czzzzzzzzz" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="58.834469" inkscape:export-ydpi="58.834469" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875" d="M 573.46171,-165.1914 C 565.96171,-167.6914 562.83671,-167.6914 555.96171,-173.9414 C 549.08671,-180.1914 547.83671,-186.4414 547.83671,-186.4414" id="path2875" sodipodi:nodetypes="ccc" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="58.834469" inkscape:export-ydpi="58.834469" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875" d="M 565.33671,-215.8164 C 565.96171,-203.3164 572.76088,-195.60844 570.55118,-185.44378" id="path2877" sodipodi:nodetypes="cc" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="58.834469" inkscape:export-ydpi="58.834469" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875" d="M 578.74147,-208.83942 C 593.33353,-209.08267 595.94861,-206.46759 598.04068,-195.48425 C 603.79386,-198.62235 606.79068,-196.86243 608.04068,-184.36243" id="path2879" sodipodi:nodetypes="ccc" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="58.834469" inkscape:export-ydpi="58.834469" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875" d="M 588.05377,-188.09934 C 588.05377,-188.09934 578.79251,-169.19769 588.16751,-169.82269 C 597.54251,-170.44769 593.88673,-170.39677 596.53838,-171.50162" id="path2881" sodipodi:nodetypes="ccc" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="58.834469" inkscape:export-ydpi="58.834469" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875" d="M 533.5768,-189.17156 C 533.5768,-189.17156 536.72404,-196.75776 544.7013,-201.20342 C 552.67855,-205.12607 558.17533,-207.90061 558.3963,-213.42488 L 557.73339,-207.75547 C 557.00552,-201.53054 566.37002,-194.56728 563.3963,-187.8627" id="path2883" sodipodi:nodetypes="czczz" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="58.834469" inkscape:export-ydpi="58.834469" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875" d="M 574.72596,-216.56604 C 579.99135,-206.27575 576.1696,-191.04684 580.14708,-180.21927" id="path2885" sodipodi:nodetypes="cc" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="58.834469" inkscape:export-ydpi="58.834469" /> <path style="fill:#000054;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 870,132.36218 C 866.61793,124.94433 859.97584,137.72984 855.14961,148.77715 C 850.32338,160.2067 844.9948,188.47513 848.75437,193.1202 C 852.51394,197.76526 858.0029,194.69751 861.76246,190.58278 C 865.52203,186.46805 863.61758,165.53131 864.80384,156.41792 C 865.6776,147.30453 873.38207,139.78004 870,132.36218 z" id="path3649" sodipodi:nodetypes="czzzzz" inkscape:export-filename="C:\pas\mricron\btn\new\ellipse.png" inkscape:export-xdpi="23.179588" inkscape:export-ydpi="23.179588" /> <path style="fill:url(#linearGradient3657);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 856.00626,155.36716 C 854.60628,159.47024 852.97459,162.2925 851.80632,167.67638 C 850.63806,173.24655 848.96996,187.02311 849.88002,189.28687 C 850.79009,191.55063 852.11878,190.05557 853.02884,188.05026 C 853.9389,186.04496 853.4779,175.84149 853.76505,171.4001 C 853.97656,166.9587 855.52747,162.66312 856.00626,155.36716 z" id="path3651" sodipodi:nodetypes="czzzzc" inkscape:export-filename="C:\pas\mricron\btn\new\ellipse.png" inkscape:export-xdpi="23.179588" inkscape:export-ydpi="23.179588" /> <path style="font-size:12px;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt" d="M 857.97619,215.57813 C 844.3558,212.00098 843.40365,204.59734 846.91512,199.60457 C 848.2391,198.20555 851.35258,196.06169 853.16005,196.19161 C 854.96752,196.32154 856.52575,197.23726 858.84701,198.89969 C 864.11454,202.84954 854.18458,204.56507 857.97619,215.57813 z" id="path3653" sodipodi:nodetypes="ccszc" inkscape:export-filename="C:\pas\mricron\btn\new\ellipse.png" inkscape:export-xdpi="23.179588" inkscape:export-ydpi="23.179588" /> <path style="font-size:12px;fill:url(#linearGradient3659);fill-rule:evenodd;stroke-width:1pt" d="M 853.52567,210.97739 C 850.26772,210.15575 848.73346,210.31315 846.72057,205.38749 C 844.70768,200.77433 849.71216,199.25861 850.30644,198.63289 C 850.90072,198.00716 851.76836,198.42041 852.36264,198.9747 C 852.95692,199.52898 852.65588,202.34933 852.84339,203.57697 C 852.98151,204.80462 850.71302,206.92946 853.52567,210.97739 z" id="path3655" sodipodi:nodetypes="czzzzc" inkscape:export-filename="C:\pas\mricron\btn\new\ellipse.png" inkscape:export-xdpi="23.179588" inkscape:export-ydpi="23.179588" /> <path style="fill:#ff0000;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.17575848000000010px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 390.65262,1036.0046 C 384.32806,1048.6538 406.61585,1048.812 395.65262,1051.0046 C 370.65262,1056.0046 308.87744,994.76187 378.01952,968.07569 C 382.21768,966.45536 370.65262,961.00465 370.65262,961.00465 L 390.65262,966.00465 L 382.4278,982.48397 C 382.4278,982.48397 383.01418,970.71107 380.38642,972.15844 C 327.10227,1001.5074 370.65262,1026.0046 390.65262,1036.0046 z" id="path2868" sodipodi:nodetypes="csscccsc" inkscape:export-filename="C:\pas\mricron\btn\new\refresh.png" inkscape:export-xdpi="22.14864" inkscape:export-ydpi="22.14864" /> <path style="fill:#ff0000;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.17575848000000010px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 398.44156,972.80163 C 404.76612,960.15252 382.47833,959.99427 393.44156,957.80163 C 418.44156,952.80163 480.21674,1014.0444 411.07466,1040.7306 C 406.8765,1042.3509 418.44156,1047.8016 418.44156,1047.8016 L 398.44156,1042.8016 L 406.66638,1026.3223 C 406.66638,1026.3223 406.08,1038.0952 408.70776,1036.6478 C 461.99191,1007.2989 418.44156,982.80163 398.44156,972.80163 z" id="path2884" sodipodi:nodetypes="csscccsc" inkscape:export-filename="C:\pas\mricron\btn\new\refresh.png" inkscape:export-xdpi="22.14864" inkscape:export-ydpi="22.14864" /> </svg> ���������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/colorzero.bmp��������������������������������������������������0000755�0001750�0001750�00000003256�10673034636�017522� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM������6���(���������������x��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������  #(,16 9##:%%:'':)):++:--:00���������������,D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ���������.D((Y55oBBOO\\iivvڃ�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/blackbackbround.svg��������������������������������������������0000755�0001750�0001750�00000421247�11030505756�020632� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg1141" sodipodi:version="0.32" inkscape:version="0.46" width="210mm" height="297mm" sodipodi:docname="blackbackbround.svg" sodipodi:docbase="C:\Documents and Settings\Chris Rorden\Desktop" inkscape:output_extension="org.inkscape.output.svg.inkscape"> <metadata id="metadata413"> <rdf:RDF> <cc:Work rdf:about=""> <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> </cc:Work> </rdf:RDF> </metadata> <defs id="defs1143"> <inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 526.18109 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="744.09448 : 526.18109 : 1" inkscape:persp3d-origin="372.04724 : 350.78739 : 1" id="perspective448" /> <linearGradient id="linearGradient1280"> <stop style="stop-color:#ffc000;stop-opacity:1.0000000;" offset="0.00000000" id="stop1281" /> <stop style="stop-color:#ff0000;stop-opacity:0.50000000;" offset="1.0000000" id="stop1283" /> </linearGradient> <linearGradient id="linearGradient1271"> <stop style="stop-color:#ffc87e;stop-opacity:1.0000000;" offset="0.00000000" id="stop1274" /> <stop style="stop-color:#ff0000;stop-opacity:1.0000000;" offset="1.0000000" id="stop1279" /> </linearGradient> <linearGradient id="linearGradient1270"> <stop style="stop-color:#ffc000;stop-opacity:1.0000000;" offset="0.00000000" id="stop1271" /> <stop style="stop-color:#e84a50;stop-opacity:1.0000000;" offset="0.50000000" id="stop1273" /> <stop style="stop-color:#ff0000;stop-opacity:1.0000000;" offset="1.0000000" id="stop1272" /> </linearGradient> <linearGradient id="linearGradient1608"> <stop style="stop-color:#ffffff;stop-opacity:1.0000000;" offset="0.00000000" id="stop1609" /> <stop style="stop-color:#9999ff;stop-opacity:1.0000000;" offset="0.50000000" id="stop1611" /> <stop style="stop-color:#000000;stop-opacity:1.0000000;" offset="1.0000000" id="stop1610" /> </linearGradient> <linearGradient id="linearGradient1563"> <stop style="stop-color:#898bdc;stop-opacity:1.0000000;" offset="0.00000000" id="stop1564" /> <stop style="stop-color:#000000;stop-opacity:1.0000000;" offset="1.0000000" id="stop1565" /> </linearGradient> <linearGradient id="linearGradient1547"> <stop style="stop-color:#9999ff;stop-opacity:1.0000000;" offset="0.00000000" id="stop1548" /> <stop style="stop-color:#9999fd;stop-opacity:0.00000000;" offset="1.0000000" id="stop1549" /> </linearGradient> <linearGradient id="linearGradient1391"> <stop style="stop-color:#ffc000;stop-opacity:1.0000000;" offset="0.00000000" id="stop1392" /> <stop style="stop-color:#ff0000;stop-opacity:1.0000000;" offset="1.0000000" id="stop1394" /> </linearGradient> <linearGradient id="linearGradient1111"> <stop style="stop-color:#e8e838;stop-opacity:1.0000000;" offset="0.00000000" id="stop1112" /> <stop style="stop-color:#ffff7f;stop-opacity:1.0000000;" offset="1.0000000" id="stop1114" /> </linearGradient> <linearGradient id="linearGradient1274"> <stop style="stop-color:#ff0400;stop-opacity:1.0000000;" offset="0.00000000" id="stop1275" /> <stop style="stop-color:#fd6972;stop-opacity:1.0000000;" offset="0.0099999998" id="stop1277" /> <stop style="stop-color:#ff0000;stop-opacity:1.0000000;" offset="1.0000000" id="stop1276" /> </linearGradient> <linearGradient id="linearGradient1205"> <stop style="stop-color:#ffffff;stop-opacity:0.9;" offset="0.00000000" id="stop1206" /> <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1.00000000" id="stop1207" /> </linearGradient> <linearGradient id="linearGradient1172"> <stop style="stop-color:#ffffff;stop-opacity:0.3;" offset="0.00000000" id="stop1173" /> <stop style="stop-color:#ffffff;stop-opacity:0.8;" offset="1.00000000" id="stop1174" /> </linearGradient> <linearGradient id="linearGradient969"> <stop style="stop-color:#ffffff;stop-opacity:0.70196080;" offset="0.00000000" id="stop970" /> <stop style="stop-color:#9999ff;stop-opacity:0.70196080;" offset="1.0000000" id="stop971" /> </linearGradient> <linearGradient id="linearGradient684"> <stop style="stop-color:#ffffff;stop-opacity:1.0000000;" offset="0.00000000" id="stop685" /> <stop style="stop-color:#9999ff;stop-opacity:1.0000000;" offset="1.0000000" id="stop686" /> </linearGradient> <linearGradient id="linearGradient671"> <stop style="stop-color:#ffffff;stop-opacity:1.0000000;" offset="0.00000000" id="stop672" /> <stop style="stop-color:#ffffff;stop-opacity:0.00000000;" offset="1.0000000" id="stop673" /> </linearGradient> <linearGradient id="linearGradient594"> <stop style="stop-color:#fffbfb;stop-opacity:1.0000000;" offset="0.00000000" id="stop595" /> <stop style="stop-color:#007aff;stop-opacity:1.0000000;" offset="1.0000000" id="stop596" /> </linearGradient> <linearGradient id="linearGradient1155"> <stop style="stop-color:#fffbfb;stop-opacity:1.0000000;" offset="0.00000000" id="stop1156" /> <stop style="stop-color:#9999ff;stop-opacity:1.0000000;" offset="1.0000000" id="stop1157" /> </linearGradient> <radialGradient xlink:href="#linearGradient1155" id="radialGradient1158" cx="0.21874997" cy="0.23437454" r="0.70745194" fx="0.21874997" fy="0.23437454" /> <radialGradient xlink:href="#linearGradient684" id="radialGradient1169" cx="0.77941167" cy="0.65624988" r="0.32758817" fx="0.77941167" fy="0.65624988" /> <linearGradient xlink:href="#linearGradient1155" id="linearGradient1170" x1="39.904693" y1="205.22107" x2="28.554472" y2="212.26643" gradientTransform="matrix(4.2446192,0,0,4.0663556,526.57826,-780.11618)" gradientUnits="userSpaceOnUse" /> <linearGradient xlink:href="#linearGradient594" id="linearGradient588" x1="331.69558" y1="519.82318" x2="377.3627" y2="537.58599" gradientTransform="matrix(0.7771299,0,0,1.2867861,-1.839794,-597.93306)" gradientUnits="userSpaceOnUse" /> <linearGradient xlink:href="#linearGradient1547" id="linearGradient639" x1="0.47535211" y1="-0.11428571" x2="0.58802819" y2="0.96190476" /> <linearGradient xlink:href="#linearGradient1155" id="linearGradient643" x1="0.20312500" y1="0.10687023" x2="0.50000000" y2="0.88549620" /> <linearGradient xlink:href="#linearGradient1563" id="linearGradient670" x1="265.95663" y1="735.08612" x2="313.4116" y2="761.44375" gradientTransform="matrix(0.9763285,0,0,1.0242454,-241.01302,-713.84008)" gradientUnits="userSpaceOnUse" /> <linearGradient xlink:href="#linearGradient684" id="linearGradient683" x1="0.39084506" y1="-0.06603774" x2="0.59859157" y2="0.94339621" /> <linearGradient xlink:href="#linearGradient1608" id="linearGradient701" x1="-196.8662" y1="425.48517" x2="-141.23934" y2="425.48517" gradientTransform="matrix(1.677741,0,0,0.5960396,114.06723,-183.9794)" gradientUnits="userSpaceOnUse" /> <linearGradient xlink:href="#linearGradient671" id="linearGradient703" x1="0.45070422" y1="-0.93750000" x2="0.44366196" y2="1.21875000" /> <radialGradient xlink:href="#linearGradient1271" id="radialGradient704" cx="292.27442" cy="807.81573" r="24.522423" fx="292.27442" fy="807.81573" gradientUnits="userSpaceOnUse" /> <linearGradient xlink:href="#linearGradient969" id="linearGradient967" x1="0.39297354" y1="0.06249970" x2="0.46580359" y2="0.96093768" /> <linearGradient xlink:href="#linearGradient684" id="linearGradient968" x1="0.08771923" y1="0.02343778" x2="0.55263156" y2="1.32031250" /> <linearGradient xlink:href="#linearGradient671" id="linearGradient1138" x1="0.50000000" y1="0.05468750" x2="0.71717173" y2="1.70312500" /> <linearGradient xlink:href="#linearGradient671" id="linearGradient1139" x1="359.54053" y1="199.43834" x2="383.23312" y2="207.27092" gradientTransform="scale(0.4268666,2.3426521)" gradientUnits="userSpaceOnUse" /> <radialGradient xlink:href="#linearGradient969" id="radialGradient1140" cx="0.11029412" cy="0.06250000" r="1.26334059" fx="0.11029412" fy="0.06250000" /> <linearGradient xlink:href="#linearGradient1172" id="linearGradient1175" x1="210.53689" y1="386.86683" x2="206.25145" y2="389.11669" gradientTransform="scale(0.758349,1.3186542)" gradientUnits="userSpaceOnUse" /> <linearGradient xlink:href="#linearGradient684" id="linearGradient1202" x1="0.16197200" y1="-0.11904722" x2="0.32746491" y2="1.99999797" /> <radialGradient xlink:href="#linearGradient684" id="radialGradient1203" cx="0.77941167" cy="0.65624988" r="0.32758817" fx="0.77941167" fy="0.65624988" /> <radialGradient xlink:href="#linearGradient1547" id="radialGradient983" cx="0.73913020" cy="0.72519094" r="0.22669560" fx="0.73913020" fy="0.72519094" /> <radialGradient xlink:href="#linearGradient1205" id="radialGradient1066" cx="0.76470590" cy="0.76562488" r="0.29453236" fx="0.76470590" fy="0.76562482" /> <linearGradient xlink:href="#linearGradient1274" id="linearGradient1273" x1="-0.019230817" y1="-3.8570047e-008" x2="0.51923072" y2="0.87500006" /> <linearGradient xlink:href="#linearGradient1280" id="linearGradient1110" x1="459.4994" y1="1254.0935" x2="481.37598" y2="1325.9788" gradientTransform="matrix(1.6468933,0,0,0.6072039,115.90702,-728.55844)" gradientUnits="userSpaceOnUse" /> <linearGradient xlink:href="#linearGradient1111" id="linearGradient1118" x1="0.53521127" y1="1.0151515" x2="0.52816904" y2="0.015151516" /> <radialGradient xlink:href="#linearGradient1391" id="radialGradient1395" cx="0.69533569" cy="0.78121674" r="0.68209499" fx="0.69533557" fy="0.76559359" /> <radialGradient xlink:href="#linearGradient1547" id="radialGradient1442" cx="291.17355" cy="815.41846" r="18.939451" fx="290.62314" fy="814.83362" /> <linearGradient xlink:href="#linearGradient684" id="linearGradient1604" x1="0.52343750" y1="0.0076335878" x2="1.0312500" y2="1.1297710" /> <linearGradient xlink:href="#linearGradient684" id="linearGradient1617" x1="0.10920641" y1="-0.40239441" x2="1.2083132" y2="1.9653628" /> <linearGradient xlink:href="#linearGradient684" id="linearGradient1618" x1="0.42672610" y1="-0.31047121" x2="1.0007051" y2="2.1198800" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="linearGradient3271" x1="299.8437" y1="1036.9841" x2="305.62924" y2="1092.2429" gradientTransform="matrix(1.646893,0,0,0.607204,-404.3959,232.2467)" gradientUnits="userSpaceOnUse" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="radialGradient3289" cx="289.25905" cy="812.97649" fx="289.25905" fy="812.97649" r="16.96986" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="linearGradient4195" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.646893,0,0,0.607204,-404.3959,232.2467)" x1="299.8437" y1="1036.9841" x2="305.62924" y2="1092.2429" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="radialGradient4197" gradientUnits="userSpaceOnUse" cx="289.25905" cy="812.97649" fx="289.25905" fy="812.97649" r="16.96986" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="linearGradient4209" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.646893,0,0,0.607204,-404.3959,232.2467)" x1="299.8437" y1="1036.9841" x2="305.62924" y2="1092.2429" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="radialGradient4211" gradientUnits="userSpaceOnUse" cx="289.25905" cy="812.97649" fx="289.25905" fy="812.97649" r="16.96986" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="linearGradient4223" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.646893,0,0,0.607204,-404.3959,232.2467)" x1="299.8437" y1="1036.9841" x2="305.62924" y2="1092.2429" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="radialGradient4225" gradientUnits="userSpaceOnUse" cx="289.25905" cy="812.97649" fx="289.25905" fy="812.97649" r="16.96986" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="linearGradient2823" x1="169.59108" y1="1212.3388" x2="175.37662" y2="1267.5976" gradientTransform="matrix(1.6468933,0,0,0.6072039,-241.01302,-713.84008)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1172" id="linearGradient2825" x1="339.63678" y1="379.11596" x2="335.35134" y2="381.36582" gradientTransform="matrix(0.758349,0,0,1.3186542,125.10599,-388.19654)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient2827" x1="588.89265" y1="195.07545" x2="612.58524" y2="202.90803" gradientTransform="matrix(0.4268666,0,0,2.3426521,125.10599,-388.19654)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1172" id="linearGradient2829" x1="477.45044" y1="381.63529" x2="473.165" y2="383.88514" gradientTransform="matrix(0.758349,0,0,1.3186542,156.38249,-391.87613)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient2831" x1="833.72519" y1="196.49355" x2="857.41778" y2="204.32614" gradientTransform="matrix(0.4268666,0,0,2.3426521,156.38249,-391.87613)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1172" id="linearGradient3604" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.758349,0,0,1.3186542,596.58502,-401.58502)" x1="210.53689" y1="386.86683" x2="206.25145" y2="389.11669" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient3608" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4268666,0,0,2.3426521,596.58502,-401.58502)" x1="359.54053" y1="199.43834" x2="383.23312" y2="207.27092" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1608" id="linearGradient3613" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.677741,0,0,0.5960396,112.0526,-127.41089)" x1="-196.8662" y1="425.48517" x2="-141.23934" y2="425.48517" /> </defs> <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="1.130388" inkscape:cx="443.79091" inkscape:cy="943.32828" inkscape:window-width="1096" inkscape:window-height="675" inkscape:window-x="84" inkscape:window-y="-10" showgrid="false" snaptogrid="false" showguides="true" snaptoguides="true" inkscape:current-layer="svg1141" inkscape:snap-global="false"> <inkscape:grid type="xygrid" id="grid3623" /> </sodipodi:namedview> <rect style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffff00;stroke-width:9.29087925;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:18.58175977, 9.29087989;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="rect2821" width="962.55579" height="269.52261" x="-16.443275" y="16.154039" /> <rect style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:2.3750000;" id="rect1295" width="69.963570" height="45.246185" x="-101.75949" y="509.82691" transform="scale(-1.000000,1.000000)" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:2.3750000;fill-opacity:1.0000000;" id="rect1262" width="69.963570" height="45.246185" x="128.72227" y="535.48883" transform="translate(-91.26626,99.11160)" /> <path sodipodi:type="arc" style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt;" id="path1286" sodipodi:cx="88.389725" sodipodi:cy="698.28027" sodipodi:rx="18.305565" sodipodi:ry="18.305565" d="M 106.69529 698.28027 A 18.305565 18.305565 0 1 0 70.084160,698.28027 A 18.305565 18.305565 0 1 0 106.69529 698.28027 z" transform="translate(-17.25953,-39.22624)" /> <path sodipodi:type="arc" style="fill-rule:evenodd;stroke-width:1.0000000pt;" id="path1573" sodipodi:cx="496.47308" sodipodi:cy="894.01904" sodipodi:rx="26.543070" sodipodi:ry="26.543070" d="M 523.01615 894.01904 A 26.543070 26.543070 0 1 0 469.93001,894.01904 A 26.543070 26.543070 0 1 0 523.01615 894.01904 z" transform="translate(185.5400,-212.9984)" /> <path sodipodi:type="arc" style="fill:url(#radialGradient1395);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;" id="path1343" sodipodi:cx="715.48608" sodipodi:cy="436.77219" sodipodi:rx="38.180180" sodipodi:ry="38.180180" d="M 753.66626 436.77219 A 38.180180 38.180180 0 1 0 677.30590,436.77219 A 38.180180 38.180180 0 1 0 753.66626 436.77219 z" transform="matrix(0.905654,0.000000,0.000000,0.919132,149.4257,12.54474)" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.0375195;" d="M 704.48491,415.34092 C 694.57329,417.80874 687.95315,428.45052 684.92534,434.86193 C 681.89753,441.01182 677.92934,447.28914 688.65031,452.73194 C 698.87767,454.00139 705.70466,453.64762 711.13899,450.11964 C 718.44814,445.58571 724.25946,439.88285 726.48955,434.60790 C 727.94598,431.77023 741.08206,432.37026 740.21539,430.37826 C 740.33314,426.85776 739.63744,419.26753 731.65870,414.99087 C 727.35252,412.29016 710.27910,412.15675 704.48491,415.34092 z " id="path1377" sodipodi:nodetypes="czcccccc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 175.16419,313.27629 C 170.59785,312.81843 161.53978,318.62958 157.57044,321.02629 C 146.72186,327.57680 135.88296,343.93132 135.88294,360.30754 C 135.88294,364.40161 132.43921,368.00533 137.35169,380.80754 C 143.39531,391.81829 170.06959,395.25262 170.28919,388.46379 C 170.50878,381.67497 166.19786,385.04854 171.50794,379.87004 C 171.67000,389.89820 175.12385,390.07619 174.97669,395.99504 C 174.88252,399.52179 174.69106,407.40659 176.03919,406.05754 L 177.97669,406.37004 L 177.97669,406.49504 L 178.35169,406.43254 L 180.28919,406.12004 C 181.63732,407.46909 181.44586,399.58428 181.35169,396.05754 C 181.20453,390.13869 184.65838,389.96069 184.82044,379.93254 C 190.13052,385.11104 185.81960,381.73746 186.03919,388.52629 C 186.25879,395.31512 212.93307,391.88078 218.97669,380.87004 C 223.88917,368.06783 220.44544,364.46410 220.44544,360.37004 C 220.44542,343.99382 209.60652,327.63929 198.75794,321.08879 C 194.78860,318.69208 185.73053,312.88092 181.16419,313.33879 C 179.64208,313.49141 178.61613,314.33756 178.44544,316.24504 L 177.64117,368.62731 L 177.88294,316.18254 C 177.71225,314.27507 176.68630,313.42891 175.16419,313.27629 z " id="path1150" sodipodi:nodetypes="ccccccccccccccccccccccc" /> <path style="fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:0.68412900pt;" d="M 182.78509,493.16200 C 171.13638,496.94695 136.68072,486.89726 135.94501,503.73375 C 135.20931,520.57025 224.59784,516.52427 212.45865,506.21355 C 200.31947,495.90282 194.43381,489.37705 182.78509,493.16200 z " id="path1140" sodipodi:nodetypes="cczz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:1.2724125pt;" d="M 496.61025,315.43263 C 487.70277,315.43523 472.41769,322.55172 466.47718,327.89823 C 454.59613,338.59121 447.94047,366.42388 447.94047,384.24553 C 447.94047,389.67769 447.95637,395.00686 448.18560,400.13622 L 542.84637,400.13622 C 543.08751,395.05165 543.13236,389.79833 543.13236,384.40325 C 543.13232,366.58163 539.47657,339.72728 527.56914,329.01351 C 521.61543,323.65662 505.51773,315.43003 496.61025,315.43263 z " id="path1063" sodipodi:nodetypes="cccccccc" /> <path style="fill-rule:evenodd;stroke:none;stroke-width:0.91963024pt;" d="M 342.97890,399.86026 L 434.73342,400.51279 L 433.34799,392.09524 C 432.07595,388.11087 427.72724,383.73612 426.88022,379.25826 C 425.59125,374.78040 431.80349,377.65786 431.05395,370.30329 C 430.30440,362.94871 428.89800,343.42434 418.26686,333.11605 C 407.32322,323.12026 398.18407,316.70378 378.78742,319.85497 C 360.64077,321.75616 350.23069,330.41956 342.83093,345.70413 C 335.23979,360.98870 343.64369,380.00725 343.40504,387.13431 L 342.97890,399.86026 z " id="path1052" sodipodi:nodetypes="ccczzzzzzc" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.99068832pt;" d="M 320.29479,372.55062 C 320.29479,358.42655 311.10597,330.09600 301.99795,321.60508 C 292.88992,313.11416 274.73445,313.13063 265.64663,321.60508 C 256.55879,330.07953 247.47096,358.32768 247.47096,372.45176 C 247.47096,386.57584 256.55879,400.69991 265.64663,406.34955 C 274.73445,411.99918 292.88992,411.98270 301.99795,406.34955 C 311.10597,400.71639 320.29479,386.67470 320.29479,372.55062 z " id="path1005" sodipodi:nodetypes="czzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.90746355pt;fill-opacity:1.0000000;" d="M 285.33919,319.75776 C 285.22106,319.75773 285.10603,319.78538 284.98790,319.78676 L 284.98790,319.81576 C 284.89998,319.80784 284.81324,319.78672 284.72444,319.78676 C 284.51750,319.78683 284.31656,319.84036 284.10969,319.84476 L 284.10969,319.96075 C 283.98357,319.94408 283.85702,319.93179 283.72913,319.93175 C 283.64032,319.93172 283.55359,319.95283 283.46566,319.96075 L 283.46566,319.93175 C 283.34754,319.93038 283.23251,319.90272 283.11438,319.90275 C 276.89311,319.90464 270.66516,321.86677 266.51610,325.76033 C 264.44158,327.70710 252.56791,343.76278 256.56299,346.52283 C 266.50559,353.79628 275.12532,332.38529 265.93062,350.14757 C 265.00413,356.24861 264.76600,359.42978 264.70112,361.02179 C 264.57010,358.10542 263.48646,351.26520 257.79249,347.94373 C 253.03583,345.22610 249.91783,369.23133 249.91783,372.47596 C 249.91783,385.45451 258.21800,398.42830 266.51610,403.61972 C 270.72453,406.25259 277.06786,407.51634 283.37784,407.47644 L 283.37784,407.50544 C 283.70047,407.50809 284.02131,407.48056 284.34388,407.47644 L 284.34388,407.33145 C 284.58784,407.34079 284.83124,407.36248 285.07573,407.36045 L 285.07573,407.33145 C 291.38571,407.37135 297.72904,406.10762 301.93747,403.47473 C 310.23557,398.28331 318.53574,385.30951 318.53574,372.33097 C 318.53574,369.08634 315.41773,345.08110 310.66108,347.79874 C 304.96711,351.12021 303.88347,357.96043 303.75245,360.87680 C 303.68757,359.28479 303.44944,356.10361 302.52294,350.00258 C 293.32825,332.24030 301.94798,353.65128 311.89058,346.37784 C 315.88566,343.61779 304.01199,327.56210 301.93747,325.61534 C 297.78841,321.72178 291.56046,319.75964 285.33919,319.75776 z " id="path1044" /> <path sodipodi:type="arc" style="font-size:12;fill:#fffffd;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.875;stroke-dasharray:none;" id="path695" sodipodi:cx="271.35836792" sodipodi:cy="796.11926270" sodipodi:rx="37.42873764" sodipodi:ry="37.42873764" d="M 308.787106 796.119263 A 37.428738 37.428738 0 1 0 233.929630,796.119263 A 37.4287 37.4287 0 1 0 308.787 796.119 L 271.358368 796.119263 z" transform="matrix(1.269231,0.000000,0.000000,1.209574,152.3260,-283.6191)" /> <path sodipodi:type="arc" style="font-size:12;fill:url(#linearGradient1202);fill-opacity:0.75;fill-rule:evenodd;stroke:#0050fb;stroke-width:2.47293;stroke-dasharray:none;stroke-opacity:1;" id="path1200" sodipodi:cx="604.88873291" sodipodi:cy="441.20190430" sodipodi:rx="44.21426392" sodipodi:ry="13.48378277" d="M 649.102997 441.201904 A 44.214264 13.483783 0 1 0 560.674469,441.201904 A 44.2143 13.4838 0 1 0 649.103 441.202 L 604.888733 441.201904 z" transform="matrix(1.042553,0.000000,0.000000,0.882208,-29.50271,47.34934)" /> <path style="font-size:12;fill-opacity:0.70196;stroke:#1c66f9;stroke-width:9.25243;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99;fill:url(#linearGradient968);" d="M -49.21 243.091 C -46.9287 238.079 -38.9781 233.065 -32.1615 233.824 L 173.669 267.357 C 189.611 256.808 212.948 243.966 237.003 247.181 L 271.976 250.84 L 316.171 257.383 C 341.971 263.24 362.36 275.405 364.498 299.613 L 364.227 591.258 L -50.8332 491.502 L -49.21 243.091 z " id="path10" transform="matrix(0.180587,0.000000,0.000000,0.239519,475.9239,473.8713)" sodipodi:nodetypes="cccccccccc" /> <rect style="font-size:12;fill:none;fill-opacity:0.25;fill-rule:evenodd;stroke-width:0.0937284;stroke-opacity:0.53137;" id="rect1408" x="0.001633" y="142.499995" width="14.998365" height="14.994604" rx="0" ry="0" transform="matrix(15.78489,0.000000,0.000000,15.78489,215.6082,-1931.463)" /> <rect style="font-size:12;fill:none;fill-rule:evenodd;stroke-width:0.0520834;" id="rect702" width="25.000004" height="24.999990" x="24.999998" y="219.999988" transform="matrix(14.81984,0.000000,0.000000,14.99259,-23.10420,-2817.060)" /> <path style="font-size:12px;fill:url(#linearGradient588);fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:0.47846999pt" d="M 257.44647,124.75373 C 258.13527,123.03175 285.34249,32.111392 285.34249,32.111392 L 316.33807,119.93219 C 316.33807,119.93219 303.25105,129.23087 288.09766,129.23087 C 272.94426,131.29724 257.10208,124.75373 257.44647,124.75373 z" id="path593" sodipodi:nodetypes="ccccc" /> <polygon sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon597" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,168.93691,-207.95076)" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z" /> <polygon sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon598" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,159.98261,-174.88876)" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z" /> <polygon sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon599" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,176.51361,-187.28696)" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z" /> <polygon sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon600" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,174.79161,-171.10046)" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z" /> <polygon sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon601" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,160.67141,-156.63576)" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z" /> <polygon sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon602" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,184.09031,-159.39096)" inkscape:flatsided="false" inkscape:rounded="0" inkscape:randomized="0" d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z" /> <path style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 272.27738,77.494562 C 270.75027,82.584812 270.67003,82.814932 269.13741,87.916252 L 270.27378,91.773922 L 272.65118,87.871392 L 277.07704,88.947952 L 274.87906,84.940762 L 278.03398,81.636322 L 273.47355,81.546602 L 272.27738,77.494562 z" id="path605" /> <path style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 290.32432,46.344392 L 289.09823,48.347992 L 284.65743,47.271432 L 286.8554,51.278622 L 283.71544,54.583062 L 288.27586,54.672782 L 289.56175,59.053772 L 291.93915,55.151252 L 293.56895,55.554962 L 290.32432,46.344392 z" id="path608" /> <path sodipodi:type="arc" style="font-size:12px;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.875;stroke-dasharray:none" id="path651" sodipodi:cx="271.35837" sodipodi:cy="796.11926" sodipodi:rx="37.428738" sodipodi:ry="37.428738" d="M 308.78711,796.11926 A 37.428738,37.428738 0 1 1 233.92963,796.11926 A 37.428738,37.428738 0 1 1 308.78711,796.11926 z" transform="matrix(1.269231,0,0,1.209574,-302.57031,-890.68908)" /> <path style="font-size:12px;fill:url(#linearGradient670);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-opacity:1" d="M 54.678503,29.191648 L 54.678503,61.925738 L 30.642443,61.925738 L 30.642443,51.417558 C 30.642443,51.417558 30.661543,51.386768 6.2494227,72.018108 L 30.126823,91.446888 L 30.126823,81.732498 L 54.678503,81.732498 L 54.678503,115.44936 C 74.188613,109.81667 88.471763,92.706968 88.471773,72.282708 C 88.471783,51.862398 74.182783,34.827758 54.678503,29.191648 z" id="path669" /> <path style="font-size:12px;fill:url(#linearGradient1170);fill-rule:evenodd;stroke:#9999ff;stroke-width:2.78699999999999990;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 682.44968,99.608656 C 689.1597,98.06451 694.06417,94.112946 698.56742,89.760146 C 702.66943,85.139869 706.77145,78.914687 708.26547,72.689506 L 674.53074,30.508874 L 635.98125,69.479657 L 682.44968,99.608656 z" id="path709" sodipodi:nodetypes="cccccc" /> <path sodipodi:type="arc" style="font-size:12px;fill:#f5f9ff;fill-rule:evenodd;stroke:#9999ff;stroke-width:10.78610039000000000;stroke-opacity:1" id="path587" sodipodi:cx="220.25374" sodipodi:cy="529.07959" sodipodi:rx="44.626575" sodipodi:ry="78.456398" d="M 264.88031,529.07959 A 44.626575,78.456398 0 1 1 175.62716,529.07959 A 44.626575,78.456398 0 1 1 264.88031,529.07959 z" transform="matrix(0.26113,0,-0.220403,0.255703,713.29596,-85.850775)" /> <path style="font-size:12px;fill:#ff0000;fill-rule:evenodd;stroke-width:1pt" d="M 642.16121,64.586857 C 606.48435,62.202631 629.35685,95.037197 629.67821,97.724085 C 629.99998,100.41097 610.94825,104.97989 618.96393,114.64855 C 632.19601,124.31725 693.2264,127.53947 692.2359,112.38342 C 691.2454,97.223187 642.9138,101.57645 632.45243,97.570644 C 629.00399,88.119567 628.55736,73.041403 633.78346,68.548785 C 636.84397,66.549706 636.40814,72.019759 642.16121,64.586857 z" id="path711" sodipodi:nodetypes="cccccsc" /> <path style="font-size:12px;fill:#ff0000;fill-rule:evenodd;stroke-width:10.78610039" d="M 669.74072,34.390532 C 664.48398,34.390532 653.88503,42.031612 646.0847,51.444467 C 639.65643,59.201621 637.1368,65.745104 639.3868,67.810322 C 646.33212,65.592565 656.79195,57.793375 664.85448,48.43956 C 668.52913,44.176371 671.14022,40.237085 672.62369,36.986075 C 672.51585,35.353721 671.58807,34.390532 669.74072,34.390532 z" id="path592" /> <rect style="font-size:12.000000;fill:url(#linearGradient643);fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000002;stroke-width:1.9439127;" id="rect642" width="71.981430" height="73.806518" x="355.56149" y="751.56487" /> <path style="font-size:12.000000;fill-rule:evenodd;stroke:#000002;stroke-width:1.9439127;" d="M 355.86912,768.41833 L 355.86912,825.08081 L 426.31248,825.08081 L 421.69830,821.88448 C 413.18767,816.07293 415.69984,808.37265 406.01003,809.09909 C 396.62784,809.24438 372.43926,821.89222 368.33775,814.53095 C 363.45690,807.88664 365.01940,752.99455 361.12114,759.56548 L 355.86912,768.41833 z " id="path640" sodipodi:nodetypes="cccczcsc" /> <rect style="font-size:12.000000;fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:4.1028190;" id="rect615" width="57.240670" height="49.173893" x="519.27698" y="1042.7878" transform="matrix(0.859371,-0.511353,0.000000,1.000000,0.000000,0.000000)" /> <text xml:space="preserve" style="font-size:48.000000;font-weight:bold;fill:#000000;stroke-width:1.0000000pt;font-family:Verdana;fill-opacity:1.0000000;" x="709.86213" y="1342.1935" id="text610" sodipodi:linespacing="100%" transform="matrix(0.632720,-0.387288,0.000000,0.813305,0.000000,0.000000)"><tspan x="709.86212" y="1342.1935" sodipodi:role="line" id="tspan613" style="fill:#000000;fill-opacity:1.0000000;">LR</tspan></text> <rect style="font-size:12.000000;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:4.1239262;" id="rect627" width="57.831149" height="49.173893" x="-632.70609" y="457.02159" transform="matrix(-0.862456,-0.506131,0.000000,1.000000,0.000000,0.000000)" /> <text xml:space="preserve" style="font-size:48.000000;font-weight:bold;stroke-width:1.0000000pt;font-family:Verdana;" x="-858.67939" y="596.71201" id="text628" sodipodi:linespacing="100%" transform="matrix(-0.632720,-0.387288,0.000000,0.813305,0.000000,0.000000)"><tspan x="-858.67938" y="596.71204" sodipodi:role="line" id="tspan629">LR</tspan></text> <rect style="font-size:12.000000;fill:url(#linearGradient1617);fill-rule:evenodd;stroke:#000000;stroke-width:0.77675028pt;" id="rect648" width="56.066268" height="49.173893" x="649.12604" y="1116.5706" transform="matrix(0.852907,-0.522062,0.000000,1.000000,0.000000,0.000000)" /> <rect style="font-size:12.000000;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:0.77675028pt;" id="rect649" width="56.066268" height="49.173893" x="-761.52524" y="380.12168" transform="matrix(-0.852907,-0.522062,0.000000,1.000000,0.000000,0.000000)" /> <path style="font-size:12.000000;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.4003696;fill-opacity:1.0000000;stroke-opacity:1.0000000;" d="M 586.02954,781.20391 C 576.62200,796.60958 567.62949,793.58791 569.22048,807.83469 C 571.77988,813.49422 577.86711,800.59504 591.84007,797.41464 C 597.37391,793.56282 600.31377,785.36998 593.29271,770.69383 C 584.81901,757.01251 564.65506,775.58222 560.50467,790.68280 C 556.35428,805.45774 563.75581,807.31272 569.01296,805.97641" id="path646" sodipodi:nodetypes="ccczzc" /> <path style="font-size:12.000000;fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:2.4003696;" d="M 618.03676,782.42607 C 627.44430,797.83174 636.43680,794.81007 634.84582,809.05685 C 632.28642,814.71638 626.19918,801.81720 612.22623,798.63680 C 606.69238,794.78498 603.75252,786.59214 610.77359,771.91599 C 619.24729,758.23467 639.41124,776.80439 643.56163,791.90496 C 647.71201,806.67990 640.31049,808.53488 635.05334,807.19857" id="path650" sodipodi:nodetypes="ccczzc" /> <path sodipodi:type="arc" style="font-size:12;fill:url(#radialGradient1158);fill-rule:evenodd;stroke:#000000;stroke-width:1pt;" id="path1411" d="M 69.375000 165.000000 A 4.375000 4.375000 0 1 0 60.625000,165.000000 A 4.375 4.375 0 1 0 69.375 165 L 65.000000 165.000000 z" sodipodi:cx="65.000000" sodipodi:cy="165.000000" sodipodi:rx="4.375000" sodipodi:ry="4.375000" transform="matrix(6.282797,0.000000,0.000000,6.282797,-36.58204,-479.7863)" /> <path style="font-size:12;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:39.4622;stroke-linecap:round;stroke-linejoin:round;" d="M 550.91978,487.64604 L 629.84423,566.57049" id="path1413" sodipodi:nodetypes="cc" transform="matrix(0.398026,0.000000,0.000000,0.398026,176.0698,386.3398)" /> <path sodipodi:type="arc" style="font-size:12;fill:url(#radialGradient1203);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.87645;stroke-dasharray:none;" id="path682" sodipodi:cx="271.35836792" sodipodi:cy="796.11926270" sodipodi:rx="37.42873764" sodipodi:ry="37.42873764" d="M 308.787106 796.119263 A 37.428738 37.428738 0 1 0 233.929630,796.119263 A 37.4287 37.4287 0 1 0 308.787 796.119 L 271.358368 796.119263 z" transform="matrix(1.269231,0.000000,0.000000,1.209574,46.26003,-283.6018)" /> <path style="font-size:12;fill:url(#linearGradient683);fill-opacity:0.38017;fill-rule:evenodd;stroke:none;stroke-width:1pt;" d="M 390.66521,633.72235 C 371.44051,633.72235 354.98613,644.70534 347.51136,660.37076 C 353.42953,663.40271 360.03471,666.27491 367.81906,664.18848 C 382.43619,660.99617 387.00568,653.47068 394.31424,650.27839 C 409.63412,649.70584 416.97120,657.57598 432.07387,657.23344 C 423.97641,643.28339 408.56719,633.72236 390.66521,633.72235 z " id="path687" /> <text xml:space="preserve" style="fill:black;fill-opacity:1;stroke:none;font-family:Palatino Linotype;font-style:normal;font-weight:bold;font-size:48;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;text-anchor:start;writing-mode:lr;" x="127.75068" y="373.16888" id="text688" sodipodi:linespacing="100%" transform="scale(2.880225,1.909157)"><tspan x="127.75068" y="373.16888" sodipodi:role="line" id="tspan693">i</tspan></text> <path style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" d="M 496.33119,633.22307 L 496.33119,725.97164 C 523.77846,725.97164 546.04854,705.21602 546.04851,679.61336 C 546.04851,654.01069 523.77844,633.22305 496.33119,633.22307 z " id="path700" /> <path style="font-size:12;fill:url(#linearGradient639);fill-opacity:0.49999997;fill-rule:evenodd;stroke:none;stroke-width:1pt;" d="M 496.76745,633.22395 C 477.54275,633.22395 461.08837,644.20694 453.61360,659.87236 C 459.53177,662.90431 466.13695,665.77651 473.92130,663.69008 C 488.53843,660.49777 493.10792,652.97228 500.41648,649.77999 C 515.73636,649.20744 523.07344,657.07758 538.17611,656.73504 C 530.07865,642.78499 514.66943,633.22396 496.76745,633.22395 z " id="path697" /> <g id="g708" transform="matrix(1.262750,0.000000,0.000000,1.262750,-71.71251,-181.4823)" style=""> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect705" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect706" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> <g id="g711" transform="matrix(1.262750,0.000000,0.000000,1.262750,10.32260,-181.7613)" style=""> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect712" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect713" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> <g id="g721" transform="matrix(0.878674,-0.906901,0.906901,0.878674,-460.8343,623.7427)" style="font-size:12;"> <g id="g722"> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect723" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect724" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> <g id="g725" transform="translate(64.96544,-0.220965)"> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect726" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect727" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> </g> <g id="g728" transform="matrix(1.073491e-5,-1.262750,1.262750,1.073491e-5,-178.5732,1437.573)" style="font-size:12;"> <g id="g729"> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect730" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect731" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> <g id="g732" transform="translate(64.96544,-0.220965)"> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect733" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect734" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> </g> <g id="g735" transform="matrix(0.893911,0.891887,-0.891887,0.893911,758.6406,-462.3620)" style="font-size:12;"> <g id="g736"> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect737" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect738" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> <g id="g739" transform="translate(64.96544,-0.220965)"> <rect style="font-size:12;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;" id="rect740" width="15.90990257" height="6.62912607" x="557.73045492" y="679.80529213" ry="3.31456304" /> <rect style="font-size:12;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt;" id="rect741" width="12.47239814" height="1.37715197" x="559.37109430" y="680.06188965" ry="0.68857598" rx="1.69095615" /> </g> </g> <path style="font-size:12;fill:#e6e6e6;fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1pt;" d="M 683.81237,652.51288 C 671.83423,652.51288 661.58216,660.41352 656.92493,671.68248 C 660.61230,673.86352 664.72773,675.92965 669.57785,674.42877 C 678.68520,672.13237 681.53227,666.71889 686.08594,664.42251 C 695.63114,664.01065 700.20259,669.67205 709.61245,669.42564 C 704.56725,659.39064 694.96638,652.51289 683.81237,652.51288 z " id="path801" /> <path style="fill:#fb4100;fill-rule:evenodd;stroke:none;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;" d="M 476.34114,554.66904 C 483.92112,533.01461 496.96853,549.86409 506.53666,550.82511 C 514.86216,550.34456 515.73201,524.39800 531.51319,528.72246 C 538.84464,531.28509 536.85645,548.74295 535.61383,558.03249 C 535.48959,568.60329 536.86193,580.71156 526.29423,589.74497 C 511.50642,601.90523 468.76115,575.84293 476.34114,554.66904 z " id="path760" sodipodi:nodetypes="ccccsz" /> <path style="font-size:12;stroke:#1c4ed9;stroke-width:10.9208;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99216;fill:#4789f7;fill-opacity:1;" d="M -25.481958,248.26603 L 449.26700,273.43400 L 430.54500,310.73100 L -40.947002,275.21320 L -25.481958,248.26603 z " id="path279" transform="matrix(0.158157,4.271800e-2,5.364549e-3,0.156933,469.3436,553.4222)" sodipodi:nodetypes="ccccc" /> <path style="font-size:12;fill:url(#linearGradient967);fill-opacity:0.6993;stroke:#1c66fb;stroke-width:9.25243;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99216;" d="M -49.210000,251.69600 C -50.453100,239.20100 -40.203100,227.28000 -26.572700,228.54900 L 168.87300,263.91600 L 168.28600,299.92400 L 253.04600,316.79000 L 253.93000,278.87900 L 343.03800,291.68700 C 354.24800,294.90300 361.40100,301.55900 364.49800,316.81800 L 362.20763,586.89881 L -28.092563,469.70606 L -49.210000,251.69600 z " id="path208" transform="matrix(0.171298,0.000000,6.402228e-2,0.215063,438.9690,493.7050)" sodipodi:nodetypes="ccccccccccc" /> <path style="font-size:12;fill-opacity:0.99;stroke:#0c1dfb;stroke-width:2.63195;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99;fill:url(#radialGradient1140);" d="M 557.37226,540.24997 C 557.04724,536.47774 559.72713,532.59711 563.29085,532.12238 L 643.91869,532.55043 C 646.84958,532.82956 648.71975,534.42669 649.52947,538.93308 L 649.45887,612.42139 L 641.22180,619.79126 L 564.84594,620.14154 L 557.39252,612.04259 L 557.37226,540.24997 z " id="path1131" sodipodi:nodetypes="ccccccccc" /> <path style="font-size:12;fill:url(#linearGradient1138);fill-opacity:0.6993;stroke:#1c2942;stroke-width:2.28142;stroke-opacity:0.99216;" d="M 582.66195,589.79239 L 627.14365,589.80274 L 627.52772,620.32722 L 582.36162,620.36346 L 582.66195,589.79239 z " id="path230" sodipodi:nodetypes="ccccc" /> <path style="font-size:12;fill:#ffffff;fill-opacity:0.99216;stroke:#1c2942;stroke-width:1.10123;stroke-opacity:0.99216;" d="M 568.04305,545.40016 L 562.27509,545.17995 L 562.26523,539.14553 L 568.02662,539.08853 L 568.04305,545.40016 z " id="path313" sodipodi:nodetypes="ccccc" /> <path style="font-size:12;fill-opacity:1;stroke:#0c5cff;stroke-width:2.20247;stroke-opacity:0.99216;fill:#fffffd;" d="M 572.55890,532.87597 L 635.43355,532.88839 L 635.97643,578.77497 L 572.13438,578.81877 L 572.55890,532.87597 z " id="path412" sodipodi:nodetypes="ccccc" /> <path style="font-size:12;fill:#1c2942;fill-opacity:0.992157;stroke-width:8.96855;" d="M 600.69196,615.30986 L 590.20322,615.52766 L 590.18460,593.72001 L 600.66094,593.93144 L 600.69196,615.30986 z " id="path415" sodipodi:nodetypes="ccccc" /> <path style="font-size:12;fill:#ffffff;fill-opacity:0.99216;stroke:#1c2942;stroke-width:1.10123;stroke-opacity:0.99216;" d="M 645.41453,544.95545 L 639.64657,544.73523 L 639.63671,538.70081 L 645.39810,538.64382 L 645.41453,544.95545 z " id="path420" sodipodi:nodetypes="ccccc" /> <path style="fill:#fb4100;fill-rule:evenodd;stroke:none;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;" d="M 576.19524,551.65510 C 583.02443,538.35600 594.77948,548.70415 603.39989,549.29433 C 610.90075,548.99924 611.68442,533.06410 625.90249,535.71996 C 632.50774,537.29380 630.72141,567.64918 621.20046,573.19704 C 607.87739,580.66531 569.36604,564.65909 576.19524,551.65510 z " id="path1137" sodipodi:nodetypes="cccsz" /> <rect style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;" id="rect1148" width="106.29921722" height="106.29921722" x="336.61416260" y="414.56689177" /> <path style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 399.79349,29.478141 C 394.01003,37.897331 389.76933,44.313401 384.9431,55.360711 C 380.11687,66.790261 374.78829,95.058691 378.54786,99.703761 C 382.30743,104.34882 387.79639,101.28107 391.55595,97.166341 C 395.31552,93.051611 393.41107,72.114871 394.59733,63.001481 C 395.47109,53.888091 397.81554,44.448881 399.79349,29.478141 z" id="path1163" sodipodi:nodetypes="czzzzc" /> <path style="fill:url(#linearGradient2827);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 385.79975,61.950721 C 384.39977,66.053801 382.76808,68.876061 381.59981,74.259941 C 380.43155,79.830111 378.76345,93.606671 379.67351,95.870431 C 380.58358,98.134191 381.91227,96.639131 382.82233,94.633821 C 383.73239,92.628521 383.27139,82.425051 383.55854,77.983661 C 383.77005,73.542261 385.32096,69.246681 385.79975,61.950721 z" id="path1164" sodipodi:nodetypes="czzzzc" /> <path style="font-size:12px;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt" d="M 387.76969,122.16169 C 374.14929,118.58454 373.19714,111.18089 376.70862,106.18812 C 378.0326,104.78911 381.14608,102.64524 382.95355,102.77517 C 384.76102,102.90509 386.31925,103.82082 388.64051,105.48324 C 393.90804,109.43309 383.97808,111.14862 387.76969,122.16169 z" id="path1165" sodipodi:nodetypes="ccszc" /> <path style="font-size:12px;fill:url(#linearGradient2825);fill-rule:evenodd;stroke-width:1pt" d="M 383.31916,117.56095 C 380.06121,116.73931 378.52695,116.89671 376.51406,111.97105 C 374.50117,107.35789 379.50565,105.84217 380.09993,105.21645 C 380.69421,104.59072 381.56185,105.00397 382.15613,105.55826 C 382.75041,106.11254 382.44937,108.93289 382.63688,110.16053 C 382.775,111.38818 380.50651,113.51302 383.31916,117.56095 z" id="path1166" sodipodi:nodetypes="czzzzc" /> <path style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path1178" d="M 455.50254,75.604101 C 456.32704,82.434381 433.36083,91.336801 432.43523,95.264781 C 430.53314,99.605271 445.41627,109.90975 441.38223,115.0509 C 438.80608,122.80077 399.07488,126.74456 389.83131,124.33877 C 388.67751,122.94637 388.47739,119.75952 390.59044,117.85443 C 396.23015,114.547 423.95938,117.37599 433.11584,112.39908 C 433.91914,110.30782 423.41753,99.787221 426.63857,94.222171 C 430.01582,87.365091 450.70407,80.206461 450.38751,76.172481 C 447.40747,71.620301 424.32171,64.457751 421.58361,60.527391 C 421.58361,60.527391 451.61221,69.886581 455.50254,75.604101 z" sodipodi:nodetypes="cccccccccc" /> <path style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 535.58083,29.120673 C 529.79737,37.539863 525.55667,43.955933 520.73044,55.003243 C 515.90421,66.432793 510.57563,94.701223 514.3352,99.346293 C 518.09477,103.99135 523.58373,100.9236 527.34329,96.808873 C 531.10286,92.694143 529.19841,71.757403 530.38467,62.644013 C 531.25843,53.530623 533.60288,44.091413 535.58083,29.120673 z" id="path1183" sodipodi:nodetypes="czzzzc" /> <path style="fill:url(#linearGradient2831);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 521.58709,61.593253 C 520.18711,65.696333 518.55542,68.518593 517.38715,73.902473 C 516.21889,79.472643 514.55079,93.249203 515.46085,95.512963 C 516.37092,97.776723 517.69961,96.281663 518.60967,94.276353 C 519.51973,92.271053 519.05873,82.067583 519.34588,77.626193 C 519.55739,73.184793 521.1083,68.889213 521.58709,61.593253 z" id="path1184" sodipodi:nodetypes="czzzzc" /> <path style="font-size:12px;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt" d="M 523.55702,121.80422 C 509.93663,118.22707 508.98448,110.82343 512.49595,105.83066 C 513.81993,104.43164 516.93341,102.28778 518.74088,102.4177 C 520.54835,102.54763 522.10658,103.46335 524.42784,105.12578 C 529.69537,109.07563 519.76541,110.79116 523.55702,121.80422 z" id="path1185" sodipodi:nodetypes="ccszc" /> <path style="font-size:12px;fill:url(#linearGradient2829);fill-rule:evenodd;stroke-width:1pt" d="M 519.1065,117.20348 C 515.84855,116.38184 514.31429,116.53924 512.3014,111.61358 C 510.28851,107.00042 515.29299,105.4847 515.88727,104.85898 C 516.48155,104.23325 517.34919,104.6465 517.94347,105.20079 C 518.53775,105.75507 518.23671,108.57542 518.42422,109.80306 C 518.56234,111.03071 516.29385,113.15555 519.1065,117.20348 z" id="path1186" sodipodi:nodetypes="czzzzc" /> <path style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path1187" d="M 591.28988,75.246633 C 592.11438,82.076913 569.14817,90.979333 568.22257,94.907313 C 566.32048,99.247803 581.20361,109.55228 577.16957,114.69343 C 574.59342,122.4433 534.86222,126.38709 525.61865,123.9813 C 524.46485,122.5889 524.26473,119.40205 526.37778,117.49696 C 532.01749,114.18953 559.74672,117.01852 568.90318,112.04161 C 569.70648,109.95035 559.20487,99.429753 562.42591,93.864703 C 565.80316,87.007623 586.49141,79.848993 586.17485,75.815013 C 583.19481,71.262833 560.10905,64.100283 557.37095,60.169923 C 557.37095,60.169923 587.39955,69.529113 591.28988,75.246633 z" sodipodi:nodetypes="cccccccccc" /> <path style="font-size:12px;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#00de00;stroke-width:3.88089991;stroke-linecap:round;stroke-dasharray:7.76179, 7.76179;stroke-dashoffset:0" d="M 557.66559,66.516353 L 524.96189,118.44451" id="path1189" /> <path style="fill:#fb4100;fill-rule:evenodd;stroke:none;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;" d="M 561.65094,448.09913 C 571.11508,425.70443 587.40564,443.12995 599.35212,444.12377 C 609.74708,443.62687 610.83312,416.79324 630.53703,421.26553 C 639.69082,423.91576 637.21526,475.03199 624.02079,484.37417 C 605.55720,496.95021 552.18679,469.99689 561.65094,448.09913 z " id="path1196" sodipodi:nodetypes="cccsz" /> <path style="font-size:12;fill:url(#radialGradient1140);fill-opacity:0.99;stroke:#0c1dfb;stroke-width:2.47208;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99;" d="M 555.37415,438.95253 C 566.02431,447.52015 591.18209,448.17514 604.56628,448.38069 C 617.95046,448.58624 641.07727,445.71069 647.53136,437.79076 L 639.22369,509.12451 C 628.37584,514.24774 616.58726,517.38839 602.91722,517.02493 C 589.24718,516.66148 572.12780,514.45376 562.84783,509.43353 L 555.37415,438.95253 z " id="path1199" sodipodi:nodetypes="czcczcc" /> <rect style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;" id="rect983" width="106.29922" height="106.29922" x="229.68997" y="308.89271" /> <rect style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;" id="rect984" width="106.29922" height="106.29922" x="335.98920" y="308.89271" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.90746355pt;" d="M 279.95280,346.67442 C 280.29433,345.98764 279.36877,338.54690 277.95386,336.62391 C 276.53895,334.70092 274.43956,335.54857 274.09803,336.23535 C 273.75651,336.92213 275.86774,336.00777 277.28264,337.93076 C 278.69755,339.85374 279.61128,347.36120 279.95280,346.67442 z " id="path1018" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.76453004pt;" d="M 273.63423,385.40914 C 270.65408,385.12172 270.05831,378.23536 267.98919,382.43631 C 265.82503,386.71235 270.28496,395.88181 270.67731,391.14244 C 270.97461,386.40309 276.51934,385.77163 273.63423,385.40914 z " id="path1019" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.90746355pt;" d="M 288.50077,346.53195 C 288.15924,345.84516 289.08480,338.40442 290.49971,336.48144 C 291.91461,334.55844 294.01401,335.40609 294.35554,336.09287 C 294.69706,336.77966 292.58583,335.86530 291.17093,337.78828 C 289.75602,339.71127 288.84229,347.21873 288.50077,346.53195 z " id="path1036" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.76453004pt;" d="M 294.81934,385.26667 C 297.79949,384.97925 298.39526,378.09288 300.46438,382.29384 C 302.62854,386.56988 298.16861,395.73934 297.77626,390.99997 C 297.47896,386.26061 291.93423,385.62916 294.81934,385.26667 z " id="path1037" sodipodi:nodetypes="czzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.0507082pt;fill-opacity:1.0000000;" d="M 409.23451,358.84667 C 408.54949,363.52087 396.22993,361.07089 396.03530,368.76520 C 395.84067,375.96034 411.64662,377.37220 417.55186,375.25440 C 423.45711,373.13660 427.32607,369.84225 426.71517,362.54762 C 426.10429,355.25299 424.14266,336.89820 402.58195,326.37323 C 381.45319,316.34743 357.52241,330.01251 349.87361,344.61299 C 342.22480,359.71267 341.61655,375.00482 350.68776,369.51396 C 359.32701,364.52225 369.86822,348.78540 385.68092,346.96694 C 401.06163,345.14847 409.91950,355.17081 409.23451,358.84667 z " id="path1045" sodipodi:nodetypes="czzzzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.0877723pt;fill-opacity:1.0000000;" d="M 373.63251,370.33086 C 372.33483,368.22505 372.73946,360.23826 365.81846,361.79098 C 358.89746,363.34369 351.38109,370.76217 349.29735,373.43628 C 347.21361,376.11041 348.32990,380.85478 349.29735,381.97618 C 350.26481,383.09758 355.77183,383.70140 357.33465,385.08158 C 358.89746,386.46177 362.54401,391.63747 364.47891,391.29243 C 366.41382,390.94738 370.35806,386.80682 370.50689,385.08160 C 370.65573,383.35636 374.93016,372.43670 373.63251,370.33086 z " id="path1049" sodipodi:nodetypes="czzzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:none;stroke-width:1.0507082pt;fill-opacity:1.0000000;" d="M 369.80420,399.98508 C 370.22508,395.78373 374.95545,379.12917 375.72069,374.09587 C 376.48592,369.06258 373.57804,371.60003 374.80242,369.35376 C 376.02678,367.10748 380.15902,361.82463 383.06689,360.61829 C 385.97478,359.41197 390.10702,360.11025 392.24966,361.23339 C 394.39230,362.35653 395.73146,366.10916 395.92276,367.35707 C 396.11406,368.60500 394.43057,370.01932 393.39750,369.60335 C 392.36444,369.18737 394.01446,362.68044 391.51002,364.68476 C 389.00558,366.86555 385.84845,370.56008 384.21474,372.09919 C 382.90569,373.63828 386.12783,372.84795 386.74001,374.09587 C 387.35219,375.34380 388.50003,377.42367 387.88785,379.58674 C 387.27565,381.74980 384.63561,385.70156 383.06689,387.07427 C 381.49816,388.44699 380.12076,385.78476 378.47552,387.82304 C 376.83027,389.86131 374.60431,398.21199 373.22688,400.16706 L 369.80420,399.98508 z " id="path1050" sodipodi:nodetypes="czzzzzzzzzzzzcc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;fill-opacity:1.0000000;stroke-dasharray:none;" d="M 368.64815,355.65182 C 369.07734,357.32494 370.41856,361.26175 371.38424,362.14751 C 372.34992,363.03329 374.41542,363.29574 374.76413,362.14751 C 375.11285,360.99928 372.77913,355.22533 378.62686,352.10871 C 384.63554,348.99209 394.02411,349.71383 396.97480,351.12452 C 399.92548,352.53519 404.88802,357.78424 400.19374,361.36016 C 396.30418,364.93605 405.74639,365.03448 407.75823,363.52538 C 409.77007,362.01628 412.69261,356.42939 410.09064,353.73925 C 407.48867,351.04912 400.89223,344.62204 394.77625,343.96592 C 388.66028,343.30978 374.03986,350.59961 372.02803,351.12452 C 369.85526,351.64942 368.21896,353.97868 368.64815,355.65182 z " id="path1051" sodipodi:nodetypes="czzzzzzzzzz" /> <g id="g1422"> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.1655209pt;" d="M 500.15302,318.39576 C 498.63090,318.58535 497.62728,319.44559 497.45659,321.35308 L 496.27180,334.48360 L 495.12787,321.15593 C 494.44510,313.52598 480.11544,322.81032 474.82299,326.00594 C 463.97441,332.55643 453.12906,348.90299 453.12904,365.27921 C 453.12904,369.37327 450.53202,374.85695 458.19505,375.61014 C 471.12797,372.25560 475.71395,368.40706 475.88521,364.72718 C 475.97004,366.73597 472.22575,370.99591 477.19257,377.85771 C 471.88006,374.61864 449.68734,372.98113 454.59982,385.78334 C 460.64344,396.79407 487.30926,400.22178 487.52886,393.43295 C 487.74845,386.64413 493.79077,380.76155 483.19824,381.13048 C 485.89452,378.43241 492.43160,379.68832 495.12787,376.99022 L 496.31266,372.81053 L 497.66087,376.55648 C 500.35715,379.25456 506.64909,378.23526 509.34537,380.93333 C 500.48613,379.72791 504.79515,386.40754 505.01475,393.19637 C 505.23437,399.98518 531.94102,396.59692 537.98464,385.58618 C 542.89711,372.78397 520.66354,374.42148 515.35103,377.66055 C 520.31782,370.79874 516.57357,366.49938 516.65839,364.49060 C 516.82967,368.17046 521.41564,372.05845 534.34856,375.41298 C 542.01160,374.65978 539.45542,369.17610 539.45542,365.08206 C 539.45542,348.70583 528.61005,332.35928 517.76147,325.80879 C 513.79214,323.41205 504.71936,317.82698 500.15302,318.39576 z " id="path1060" sodipodi:nodetypes="cccccccccccccccccccccccc" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.98194113pt;" d="M 501.66595,339.08941 C 507.48057,336.85763 507.44235,336.64611 505.77764,338.68995 C 504.31721,340.73379 502.98053,336.92565 501.65049,348.68951 C 500.11618,360.84766 495.64707,341.51834 501.66595,339.08941 z " id="path1057" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.98194113pt;" d="M 491.59647,339.30071 C 485.78186,337.06892 485.82008,336.85741 487.48479,338.90125 C 488.94522,340.94509 490.28190,337.13695 491.61194,348.90080 C 493.14625,361.05897 497.61536,341.72965 491.59647,339.30071 z " id="path1059" sodipodi:nodetypes="czzz" /> </g> <path sodipodi:type="arc" style="font-size:12;fill:url(#radialGradient983);fill-opacity:0.50000000;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none;" id="path1065" sodipodi:cx="271.35836792" sodipodi:cy="796.11926270" sodipodi:rx="37.42873764" sodipodi:ry="37.42873764" d="M 308.787106 796.119263 A 37.428738 37.428738 0 1 0 233.929630,796.119263 A 37.4287 37.4287 0 1 0 308.787 796.119 L 271.358368 796.119263 z" transform="matrix(1.269231,0.000000,0.000000,1.209574,153.7331,-282.7179)" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke-width:0.84895535pt;" id="rect1074" width="42.038873" height="31.251435" x="577.48017" y="355.15182" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 590.00000,364.23718 C 600.00000,365.07051 608.75000,368.82051 614.37500,377.36218 C 620.00000,386.52885 619.37500,387.36218 619.37500,387.36218 C 619.37500,387.36218 620.62500,396.11218 608.75000,397.36218 C 596.87500,397.98718 583.56694,385.77747 569.81694,385.77747 C 556.69194,385.77747 551.87500,383.73242 553.75000,372.36218 C 555.62500,360.55000 569.06250,334.86218 591.87500,334.23718 C 614.68750,332.98718 635.31250,340.38301 643.75000,355.48718 C 651.56250,370.59135 647.81250,382.36218 643.12500,386.11218 C 638.43750,389.86218 627.70833,384.86218 619.37500,386.73718" id="path1067" sodipodi:nodetypes="czzzzzzzzz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 605.62500,385.48718 C 598.12500,382.98718 595.00000,382.98718 588.12500,376.73718 C 581.25000,370.48718 580.00000,364.23718 580.00000,364.23718" id="path1068" sodipodi:nodetypes="ccc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 597.50000,334.86218 C 598.12500,347.36218 604.92417,355.07014 602.71447,365.23480" id="path1069" sodipodi:nodetypes="cc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 610.90476,341.83916 C 625.49682,341.59591 628.11190,344.21099 630.20397,355.19433 C 635.95715,352.05623 638.95397,353.81615 640.20397,366.31615" id="path1070" sodipodi:nodetypes="ccc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 620.21706,362.57924 C 620.21706,362.57924 610.95580,381.48089 620.33080,380.85589 C 629.70580,380.23089 626.05002,380.28181 628.70167,379.17696" id="path1071" sodipodi:nodetypes="ccc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 565.74009,361.50702 C 565.74009,361.50702 568.88733,353.92082 576.86459,349.47516 C 584.84184,345.55251 590.33862,342.77797 590.55959,337.25370 L 589.89668,342.92311 C 589.16881,349.14804 598.53331,356.11130 595.55959,362.81588" id="path1072" sodipodi:nodetypes="czczz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 606.88925,334.11254 C 612.15464,344.40283 608.33289,359.63174 612.31037,370.45931" id="path1073" sodipodi:nodetypes="cc" /> <g id="g1132" transform="matrix(1.069142,0.000000,0.000000,1.032969,-32.93548,-15.76150)"> <g id="g1107" transform="matrix(0.841944,0.000000,0.000000,0.873445,74.35371,56.03641)"> <g id="g1099" transform="translate(1.325825,9.280777)"> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.65628657pt;" d="M 496.65430,493.31750 C 496.65430,484.55800 490.15222,466.98787 483.70730,461.72195 C 477.26238,456.45602 464.41541,456.46624 457.98479,461.72195 C 451.55416,466.97766 445.12353,484.49668 445.12353,493.25619 C 445.12353,502.01571 451.55416,510.77522 457.98479,514.27903 C 464.41541,517.78283 477.26238,517.77261 483.70730,514.27903 C 490.15222,510.78544 496.65430,502.07702 496.65430,493.31750 z " id="path1075" sodipodi:nodetypes="czzzzzz" /> <g id="g1093"> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:0.60115390pt;" d="M 471.91942,460.57627 C 471.83583,460.57625 471.75443,460.59340 471.67084,460.59426 L 471.67084,460.61224 C 471.60863,460.60733 471.54725,460.59423 471.48442,460.59426 C 471.33798,460.59430 471.19580,460.62750 471.04941,460.63023 L 471.04941,460.70216 C 470.96017,460.69182 470.87062,460.68420 470.78013,460.68418 C 470.71728,460.68416 470.65591,460.69725 470.59369,460.70216 L 470.59369,460.68418 C 470.51011,460.68333 470.42871,460.66617 470.34512,460.66619 C 465.94290,460.66736 461.53595,461.88424 458.60004,464.29896 C 457.13209,465.50632 448.73018,475.46378 451.55713,477.17551 C 458.59260,481.68638 464.69200,468.40765 458.18575,479.42351 C 457.53016,483.20728 457.36165,485.18018 457.31574,486.16752 C 457.22303,484.35884 456.45624,480.11665 452.42714,478.05673 C 449.06128,476.37130 446.85496,491.25894 446.85496,493.27120 C 446.85496,501.32028 452.72823,509.36640 458.60004,512.58603 C 461.57796,514.21889 466.06655,515.00265 470.53155,514.97790 L 470.53155,514.99589 C 470.75985,514.99753 470.98688,514.98046 471.21513,514.97790 L 471.21513,514.88798 C 471.38776,514.89378 471.55999,514.90723 471.73299,514.90597 L 471.73299,514.88798 C 476.19799,514.91273 480.68658,514.12899 483.66451,512.49611 C 489.53631,509.27648 495.40958,501.23035 495.40958,493.18128 C 495.40958,491.16902 493.20325,476.28138 489.83741,477.96681 C 485.80830,480.02673 485.04151,484.26892 484.94880,486.07760 C 484.90289,485.09026 484.73439,483.11735 484.07879,479.33359 C 477.57255,468.31773 483.67194,481.59646 490.70741,477.08559 C 493.53436,475.37386 485.13245,465.41639 483.66451,464.20904 C 480.72859,461.79432 476.32164,460.57744 471.91942,460.57627 z " id="path1076" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.60115390pt;" d="M 468.10796,477.26953 C 468.34963,476.84360 467.69470,472.22898 466.69350,471.03637 C 465.69229,469.84376 464.20675,470.36946 463.96508,470.79539 C 463.72341,471.22132 465.21734,470.65425 466.21853,471.84686 C 467.21974,473.03946 467.86630,477.69546 468.10796,477.26953 z " id="path1077" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.50646687pt;" d="M 463.63689,501.29214 C 461.52811,501.11389 461.10654,496.84308 459.64241,499.44844 C 458.11103,502.10037 461.26692,507.78711 461.54455,504.84784 C 461.75492,501.90857 465.67842,501.51695 463.63689,501.29214 z " id="path1078" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.60115390pt;" d="M 474.15658,477.18117 C 473.91491,476.75523 474.56985,472.14061 475.57105,470.94801 C 476.57224,469.75540 478.05780,470.28110 478.29947,470.70703 C 478.54113,471.13296 477.04720,470.56589 476.04601,471.75849 C 475.04481,472.95110 474.39824,477.60710 474.15658,477.18117 z " id="path1079" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.50646687pt;" d="M 478.62766,501.20378 C 480.73643,501.02553 481.15801,496.75472 482.62213,499.36008 C 484.15351,502.01201 480.99763,507.69875 480.72000,504.75948 C 480.50963,501.82021 476.58613,501.42859 478.62766,501.20378 z " id="path1080" sodipodi:nodetypes="czzz" /> </g> </g> <g id="g1088" transform="matrix(0.528836,0.000000,0.000000,0.528836,234.0955,290.1247)"> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:1.2724125pt;" d="M 448.76081,243.24146 C 439.85333,243.24406 424.56825,250.36055 418.62774,255.70706 C 406.74669,266.40004 400.09103,294.23271 400.09103,312.05436 C 400.09103,317.48652 400.10693,322.81569 400.33616,327.94505 L 494.99693,327.94505 C 495.23807,322.86048 495.28292,317.60716 495.28292,312.21208 C 495.28288,294.39046 491.62713,267.53611 479.71970,256.82234 C 473.76599,251.46545 457.66829,243.23886 448.76081,243.24146 z " id="path1084" sodipodi:nodetypes="cccccccc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.1655209pt;" d="M 452.30358,246.20459 C 450.78146,246.39418 449.77784,247.25442 449.60715,249.16191 L 448.42236,262.29243 L 447.27843,248.96476 C 446.59566,241.33481 432.26600,250.61915 426.97355,253.81477 C 416.12497,260.36526 405.27962,276.71182 405.27960,293.08804 C 405.27960,297.18210 402.68258,302.66578 410.34561,303.41897 C 423.27853,300.06443 427.86451,296.21589 428.03577,292.53601 C 428.12060,294.54480 424.37631,298.80474 429.34313,305.66654 C 424.03062,302.42747 401.83790,300.78996 406.75038,313.59217 C 412.79400,324.60290 439.45982,328.03061 439.67942,321.24178 C 439.89901,314.45296 445.94133,308.57038 435.34880,308.93931 C 438.04508,306.24124 444.58216,307.49715 447.27843,304.79905 L 448.46322,300.61936 L 449.81143,304.36531 C 452.50771,307.06339 458.79965,306.04409 461.49593,308.74216 C 452.63669,307.53674 456.94571,314.21637 457.16531,321.00520 C 457.38493,327.79401 484.09158,324.40575 490.13520,313.39501 C 495.04767,300.59280 472.81410,302.23031 467.50159,305.46938 C 472.46838,298.60757 468.72413,294.30821 468.80895,292.29943 C 468.98023,295.97929 473.56620,299.86728 486.49912,303.22181 C 494.16216,302.46861 491.60598,296.98493 491.60598,292.89089 C 491.60598,276.51466 480.76061,260.16811 469.91203,253.61762 C 465.94270,251.22088 456.86992,245.63581 452.30358,246.20459 z " id="path1085" sodipodi:nodetypes="cccccccccccccccccccccccc" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.98194113pt;" d="M 453.81651,266.89824 C 459.63113,264.66646 459.59291,264.45494 457.92820,266.49878 C 456.46777,268.54262 455.13109,264.73448 453.80105,276.49834 C 452.26674,288.65649 447.79763,269.32717 453.81651,266.89824 z " id="path1086" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.98194113pt;" d="M 443.74703,267.10954 C 437.93242,264.87775 437.97064,264.66624 439.63535,266.71008 C 441.09578,268.75392 442.43246,264.94578 443.76250,276.70963 C 445.29681,288.86780 449.76592,269.53848 443.74703,267.10954 z " id="path1087" sodipodi:nodetypes="czzz" /> </g> </g> <g id="g1126" transform="matrix(0.495484,0.000000,0.000000,0.495484,300.5956,311.9146)"> <path style="fill-rule:evenodd;stroke:none;stroke-width:0.91963024pt;" d="M 390.65866,301.36656 L 482.41318,302.01909 L 481.02775,293.60154 C 479.75571,289.61717 475.40700,285.24242 474.55998,280.76456 C 473.27101,276.28670 479.48325,279.16416 478.73371,271.80959 C 477.98416,264.45501 476.57776,244.93064 465.94662,234.62235 C 455.00298,224.62656 445.86383,218.21008 426.46718,221.36127 C 408.32053,223.26246 397.91045,231.92586 390.51069,247.21043 C 382.91955,262.49500 391.32345,281.51355 391.08480,288.64061 L 390.65866,301.36656 z " id="path1121" sodipodi:nodetypes="ccczzzzzzc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.0507082pt;fill-opacity:1.0000000;" d="M 456.91427,260.35297 C 456.22925,265.02717 443.90969,262.57719 443.71506,270.27150 C 443.52043,277.46664 459.32638,278.87850 465.23162,276.76070 C 471.13687,274.64290 475.00583,271.34855 474.39493,264.05392 C 473.78405,256.75929 471.82242,238.40450 450.26171,227.87953 C 429.13295,217.85373 405.20217,231.51881 397.55337,246.11929 C 389.90456,261.21897 389.29631,276.51112 398.36752,271.02026 C 407.00677,266.02855 417.54798,250.29170 433.36068,248.47324 C 448.74139,246.65477 457.59926,256.67711 456.91427,260.35297 z " id="path1122" sodipodi:nodetypes="czzzzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.0877723pt;fill-opacity:1.0000000;" d="M 421.31227,271.83716 C 420.01459,269.73135 420.41922,261.74456 413.49822,263.29728 C 406.57722,264.84999 399.06085,272.26847 396.97711,274.94258 C 394.89337,277.61671 396.00966,282.36108 396.97711,283.48248 C 397.94457,284.60388 403.45159,285.20770 405.01441,286.58788 C 406.57722,287.96807 410.22377,293.14377 412.15867,292.79873 C 414.09358,292.45368 418.03782,288.31312 418.18665,286.58790 C 418.33549,284.86266 422.60992,273.94300 421.31227,271.83716 z " id="path1123" sodipodi:nodetypes="czzzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:none;stroke-width:1.0507082pt;fill-opacity:1.0000000;" d="M 417.48396,301.49138 C 417.90484,297.29003 422.63521,280.63547 423.40045,275.60217 C 424.16568,270.56888 421.25780,273.10633 422.48218,270.86006 C 423.70654,268.61378 427.83878,263.33093 430.74665,262.12459 C 433.65454,260.91827 437.78678,261.61655 439.92942,262.73969 C 442.07206,263.86283 443.41122,267.61546 443.60252,268.86337 C 443.79382,270.11130 442.11033,271.52562 441.07726,271.10965 C 440.04420,270.69367 441.69422,264.18674 439.18978,266.19106 C 436.68534,268.37185 433.52821,272.06638 431.89450,273.60549 C 430.58545,275.14458 433.80759,274.35425 434.41977,275.60217 C 435.03195,276.85010 436.17979,278.92997 435.56761,281.09304 C 434.95541,283.25610 432.31537,287.20786 430.74665,288.58057 C 429.17792,289.95329 427.80052,287.29106 426.15528,289.32934 C 424.51003,291.36761 422.28407,299.71829 420.90664,301.67336 L 417.48396,301.49138 z " id="path1124" sodipodi:nodetypes="czzzzzzzzzzzzcc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.1391397pt;fill-opacity:1.0000000;" d="M 416.32791,257.15812 C 416.75710,258.83124 418.09832,262.76805 419.06400,263.65381 C 420.02968,264.53959 422.09518,264.80204 422.44389,263.65381 C 422.79261,262.50558 420.45889,256.73163 426.30662,253.61501 C 432.31530,250.49839 441.70387,251.22013 444.65456,252.63082 C 447.60524,254.04149 452.56778,259.29054 447.87350,262.86646 C 443.98394,266.44235 453.42615,266.54078 455.43799,265.03168 C 457.44983,263.52258 460.37237,257.93569 457.77040,255.24555 C 455.16843,252.55542 448.57199,246.12834 442.45601,245.47222 C 436.34004,244.81608 421.71962,252.10591 419.70779,252.63082 C 417.53502,253.15572 415.89872,255.48498 416.32791,257.15812 z " id="path1125" sodipodi:nodetypes="czzzzzzzzzz" /> </g> </g> <rect style="fill:url(#linearGradient701);fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#ffffff;stroke-width:3.75000000000000000;stroke-dasharray:none" id="rect1204" width="91.25" height="30" x="-214.68277" y="57.132778" ry="12.5" transform="scale(-1,1)" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" d="M 785.96002,98.902159 C 785.96002,113.04716 774.48002,124.52716 760.33502,124.52716 C 746.19002,124.52716 734.71002,113.04716 734.71002,98.902159 C 734.71002,84.757159 746.19002,73.277159 760.33502,73.277159 C 774.48002,73.277159 785.96002,84.757159 785.96002,98.902159 z" id="path1291" /> <path sodipodi:nodetypes="czzzzc" id="path1294" d="M 773.36975,26.31038 C 767.58629,34.72957 763.34559,41.14564 758.51936,52.19295 C 753.69313,63.6225 748.36455,91.89093 752.12412,96.536 C 755.88369,101.18106 761.37265,98.11331 765.13221,93.99858 C 768.89178,89.88385 766.98733,68.94711 768.17359,59.83372 C 769.04735,50.72033 771.3918,41.28112 773.36975,26.31038 z" style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> <path sodipodi:nodetypes="czzzzc" id="path1295" d="M 759.37601,58.78296 C 757.97603,62.88604 756.34434,65.7083 755.17607,71.09218 C 754.00781,76.66235 752.33971,90.43891 753.24977,92.70267 C 754.15984,94.96643 755.48853,93.47137 756.39859,91.46606 C 757.30865,89.46076 756.84765,79.25729 757.1348,74.8159 C 757.34631,70.3745 758.89722,66.07892 759.37601,58.78296 z" style="fill:url(#linearGradient3608);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> <path sodipodi:nodetypes="ccszc" id="path1296" d="M 761.34595,118.99393 C 747.72556,115.41678 746.7734,108.01313 750.28488,103.02037 C 751.60886,101.62135 754.72234,99.47749 756.52981,99.60741 C 758.33728,99.73734 759.89551,100.65306 762.21677,102.31548 C 767.4843,106.26534 757.55434,107.98087 761.34595,118.99393 z" style="font-size:12px;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt" /> <path sodipodi:nodetypes="czzzzc" id="path1297" d="M 756.89542,114.39319 C 753.63747,113.57155 752.10321,113.72895 750.09032,108.80329 C 748.07743,104.19013 753.08191,102.67441 753.67619,102.04869 C 754.27047,101.42296 755.13811,101.83621 755.73239,102.3905 C 756.32667,102.94478 756.02563,105.76513 756.21314,106.99277 C 756.35126,108.22042 754.08277,110.34526 756.89542,114.39319 z" style="font-size:12px;fill:url(#linearGradient3604);fill-rule:evenodd;stroke-width:1pt" /> <rect style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:4.56593418" id="rect1303" width="48.979599" height="47.110672" x="774.80969" y="53.56987" /> <path style="fill:#cccccc;fill-rule:nonzero;stroke:none;fill-opacity:1.0000000;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;" id="path1142" d="M 154.48440,498.48337 C 154.25849,492.81414 161.38338,496.65143 161.80515,496.90392 C 164.78182,498.61634 170.39318,504.14280 173.95269,504.05991 C 175.95558,503.84576 177.63390,502.63440 179.05959,501.28272 C 180.33976,499.99776 181.20682,498.58127 182.06397,497.00066 C 183.44438,494.70321 187.18348,487.99384 189.77932,488.11380 C 192.16403,488.34388 196.44293,490.85911 198.63874,491.77507 C 200.34301,492.48848 203.47991,491.83913 205.21157,492.48524 C 206.51580,492.94214 202.88897,499.07531 204.26060,499.25768 C 205.40017,499.35058 206.09747,498.86094 206.93516,498.11576 C 207.57391,497.51451 211.51747,500.31315 210.70090,501.08164 C 208.56717,502.98125 206.27814,503.85683 203.40943,503.55889 C 201.58416,503.29953 199.79391,502.83223 198.06231,502.20168 C 196.27903,501.51624 194.58389,500.64017 192.82470,499.89873 C 191.28048,499.25617 189.66739,498.59467 187.99351,498.39461 C 187.36694,498.35913 187.14450,498.30179 186.79211,498.84177 C 185.67318,500.80361 184.50376,502.56949 182.88013,504.16267 C 180.31823,506.51125 177.42085,508.14583 173.89191,508.33224 C 169.23300,508.20987 162.04502,509.96482 156.25203,500.75392 C 155.96788,500.55562 159.95745,495.74444 159.84831,498.48337 L 154.48440,498.48337 z " sodipodi:nodetypes="ccccccccccccccccccccc" /> <rect style="fill:#f9bac0;fill-rule:evenodd;stroke:#000000;stroke-width:0.49504948pt;" id="rect1120" width="12.250767" height="12.000593" x="141.62668" y="387.23074" ry="3.9226213" transform="matrix(0.801814,-0.889705,0.948595,0.752036,-334.0009,328.3647)" /> <rect style="fill:url(#linearGradient1118);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;" id="rect1117" width="53.347649" height="11.244847" x="150.89017" y="387.60864" transform="matrix(0.801814,-0.889705,0.948595,0.752036,-334.0009,328.3647)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.93750000;" d="M 153.76675,391.00825 L 202.40725,390.74674 L 202.40725,390.74674" id="path1126" transform="matrix(0.801814,-0.889705,0.948595,0.752036,-334.0009,328.3647)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.93750000;" d="M 153.76675,395.58464 L 202.40725,395.32313 L 202.40725,395.32313" id="path1128" transform="matrix(0.801814,-0.889705,0.948595,0.752036,-334.0009,328.3647)" /> <path style="fill:#e49415;fill-rule:evenodd;stroke-width:1.0000000pt;fill-opacity:1.0000000;" d="M 204.76083,387.08564 L 226.72751,392.93844 L 205.02234,399.37652 L 204.76083,387.08564 z " id="path1129" transform="matrix(0.801814,-0.889705,0.948595,0.752036,-334.0009,328.3647)" /> <path style="fill:#040023;fill-rule:evenodd;stroke-width:1.0000000pt;" d="M 219.01301,390.87754 L 227.25053,392.93225 L 219.11108,395.19241 L 219.01301,390.87754 z " id="path1132" transform="matrix(0.801814,-0.889705,0.948595,0.752036,-334.0009,328.3647)" /> <g id="g1195" transform="matrix(0.789807,0.000000,0.000000,0.829148,40.60222,144.2242)"> <path sodipodi:type="arc" style="font-size:12;fill:url(#radialGradient1169);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.87645;stroke-dasharray:none;" id="path1190" sodipodi:cx="271.35836792" sodipodi:cy="796.11926270" sodipodi:rx="37.42873764" sodipodi:ry="37.42873764" d="M 308.787106 796.119263 A 37.428738 37.428738 0 1 0 233.929630,796.119263 A 37.4287 37.4287 0 1 0 308.787 796.119 L 271.358368 796.119263 z" transform="matrix(1.269231,0.000000,0.000000,1.209574,-184.6799,-194.3941)" /> <path style="font-size:12;fill:url(#linearGradient683);fill-opacity:0.38017;fill-rule:evenodd;stroke:none;stroke-width:1pt;" d="M 159.72524,722.93003 C 140.50054,722.93003 124.04616,733.91302 116.57139,749.57844 C 122.48956,752.61039 129.09474,755.48259 136.87909,753.39616 C 151.49622,750.20385 156.06571,742.67836 163.37427,739.48607 C 178.69415,738.91352 186.03123,746.78366 201.13390,746.44112 C 193.03644,732.49107 177.62722,722.93004 159.72524,722.93003 z " id="path1191" /> <text xml:space="preserve" style="fill:black;fill-opacity:1;stroke:none;font-family:Palatino Linotype;font-style:normal;font-weight:bold;font-size:48;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;text-anchor:start;writing-mode:lr;" x="47.569456" y="419.89508" id="text1192" sodipodi:linespacing="100%" transform="scale(2.880225,1.909157)"><tspan x="47.569454" y="419.89508" sodipodi:role="line" id="tspan1193">i</tspan></text> </g> <path style="fill:#fb4100;fill-rule:evenodd;stroke:none;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;" d="M 157.91689,807.80962 C 166.13755,791.78371 180.28774,804.25361 190.66459,804.96480 C 199.69378,804.60921 200.63712,785.40677 217.75218,788.60718 C 225.70328,790.50372 223.55297,827.08308 212.09209,833.76845 C 196.05440,842.76799 149.69621,823.47991 157.91689,807.80962 z " id="path1179" sodipodi:nodetypes="cccsz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 135.72268,361.98087 C 134.67665,364.33444 139.37290,364.60684 143.68234,366.31209 C 147.99177,368.01734 152.43742,371.67846 155.07429,372.44119 C 160.34804,373.96665 169.84949,374.44608 173.64136,373.48722 C 177.43323,372.52836 177.12814,369.56460 177.82549,365.64199" id="path1135" sodipodi:nodetypes="cszzz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 163.44255,357.27376 C 158.21239,350.47455 167.88818,351.25907 168.41121,347.07494 C 171.02628,336.87613 161.08898,335.30708 161.08898,335.30708 C 161.08898,335.30708 167.10367,327.72334 168.67271,323.53921 C 163.44255,317.78603 163.96556,318.57056 155.85881,322.23167" id="path1138" sodipodi:nodetypes="ccccc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 169.19573,382.90152 C 169.80591,375.31778 164.40140,374.66401 162.13500,373.48722" id="path1141" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 135.59193,366.63075 C 138.73003,373.95298 150.19280,376.35013 155.46655,377.87559" id="path1153" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 163.44255,357.27376 C 158.21239,350.47455 167.88818,351.25907 168.41121,347.07494 C 171.02628,336.87613 161.08898,335.30708 161.08898,335.30708 C 161.08898,335.30708 167.10367,327.72334 168.67271,323.53921 C 163.44255,317.78603 163.96556,318.57056 155.85881,322.23167" id="path1167" sodipodi:nodetypes="ccccc" transform="matrix(-1.000000,0.000000,0.000000,1.000000,355.9476,-0.390884)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 169.19573,382.90152 C 169.80591,375.31778 164.40140,374.66401 162.13500,373.48722" id="path1169" sodipodi:nodetypes="cz" transform="matrix(-1.000000,0.000000,0.000000,1.000000,355.9476,-0.390884)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 135.59193,366.63075 C 138.73003,373.95298 150.19280,376.35013 155.46655,377.87559" id="path1170" sodipodi:nodetypes="cz" transform="matrix(-1.000000,0.000000,0.000000,1.000000,355.9476,-0.390884)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 220.21273,361.50548 C 221.25876,363.85905 216.56251,364.13145 212.25307,365.83670 C 207.94364,367.54195 203.49799,371.20307 200.86112,371.96580 C 195.58737,373.49126 186.08592,373.97069 182.29405,373.01183 C 178.50218,372.05297 177.49973,366.73564 177.84841,362.29001" id="path1194" sodipodi:nodetypes="cszzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 140.95285,349.68999 C 133.28195,370.78498 141.91171,361.71936 146.70603,361.98087" id="path1195" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 214.47932,349.22398 C 222.15022,370.31897 213.52046,361.25335 208.72614,361.51486" id="path1218" sodipodi:nodetypes="cz" /> <g id="g1278" transform="matrix(0.605285,0.000000,0.000000,0.597196,215.4523,158.0050)" style=""> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;fill-opacity:1.0000000;stroke-dasharray:none;" d="M 804.64950,250.44849 C 797.35720,250.48469 789.33209,251.98524 784.49454,257.96913 C 780.93740,262.11537 778.38323,267.02039 775.64377,271.69315 C 773.68125,276.21594 769.46739,297.45551 769.30129,304.87537 C 770.14526,316.85318 776.63805,328.66066 786.98642,334.95250 C 795.22467,338.99769 804.89497,338.64881 813.70686,337.08266 C 821.45161,335.53674 827.62366,329.95749 831.57563,323.32749 C 837.11921,314.80704 839.26003,304.08986 836.74694,294.17684 C 835.76180,288.84411 831.92018,270.31405 828.52987,266.57056 C 824.89455,259.95461 819.93817,253.06220 812.07514,251.41397 C 809.65774,250.76162 807.15196,250.45235 804.64950,250.44849 z " id="path1255" sodipodi:nodetypes="ccccccccccc" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 800.13750,250.65056 C 801.18353,251.26075 803.25316,249.31320 803.64542,263.39105 C 804.03768,277.46890 803.99154,332.67692 804.34021,335.11767 C 804.68888,337.29691 802.01036,338.15546 798.99628,337.91766" id="path1256" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 807.42479,250.62195 C 806.37876,251.23214 804.30913,249.28459 803.91687,263.36244 C 803.52461,277.44029 804.49532,333.01814 804.14665,335.45889 C 803.79798,337.63813 806.66142,337.94193 809.67549,337.70414" id="path1257" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 817.70960,290.28376 C 809.84745,280.10959 810.70190,277.13212 818.95501,270.89040 C 813.26525,268.19968 813.19141,265.32450 823.17748,259.01761" id="path1258" sodipodi:nodetypes="ccc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.7000000;stroke-dasharray:none;" d="M 787.90305,291.30471 C 795.76520,281.13054 794.91075,278.15307 786.65764,271.91135 C 792.34740,269.22063 792.42124,266.34545 782.43517,260.03856" id="path1259" sodipodi:nodetypes="ccc" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 799.72669,293.23848 C 796.52152,297.49150 789.40232,292.22145 787.89219,291.20442 C 786.38206,290.18739 784.19391,295.08761 779.75597,293.60830 C 775.50295,292.12899 776.05768,287.87597 776.05768,287.87597" id="path1260" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 802.03812,301.75908 C 797.90838,303.42330 787.64564,300.37222 786.13551,299.35519 C 784.62538,298.33816 782.43723,303.23838 777.99929,301.75907 C 773.74627,300.27976 771.52729,289.36983 771.52729,289.36983" id="path1261" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 792.23767,329.12637 C 782.56051,317.10695 791.52883,320.52786 791.86785,314.51815 C 792.57669,308.87827 798.04822,307.90662 793.98280,308.72802 C 790.96976,309.36580 788.07711,304.71769 779.29369,308.60089" id="path1262" sodipodi:nodetypes="czsz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 807.30819,291.84436 C 810.51336,296.09738 817.63256,290.82733 819.14269,289.81030 C 820.65282,288.79327 822.84097,293.69349 827.27891,292.21418 C 831.53193,290.73487 830.97720,286.48185 830.97720,286.48185" id="path1263" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 804.99676,300.36496 C 809.12650,302.02918 819.38924,298.97810 820.89937,297.96107 C 822.40950,296.94404 824.59765,301.84426 829.03559,300.36495 C 833.28861,298.88564 835.50759,287.97571 835.50759,287.97571" id="path1264" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1.7000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 814.79721,327.73225 C 824.47437,315.71283 815.50605,319.13374 815.16703,313.12403 C 814.45819,307.48415 808.98666,306.51250 813.05208,307.33390 C 816.06512,307.97168 818.95777,303.32357 827.74119,307.20677" id="path1265" sodipodi:nodetypes="czsz" /> </g> <rect style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;" id="rect1342" width="106.29922" height="106.29922" x="678.02699" y="257.57566" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke-width:0.84895535pt;" id="rect1300" width="42.038873" height="31.251435" x="577.48017" y="355.15182" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 585.39981,368.71772 C 595.39981,369.55105 611.65089,374.39889 615.88182,379.14146 C 620.11275,384.31923 621.65174,382.78809 623.97519,388.42080 C 625.83395,393.88440 626.66596,396.13459 614.79096,397.38459 C 602.91596,398.00959 579.84943,391.38777 567.95818,382.48985 C 556.06694,374.46233 550.94562,372.94946 552.82062,361.57922 C 554.69562,349.76704 569.06250,334.86218 591.87500,334.23718 C 614.68750,332.98718 635.31250,340.38301 643.75000,355.48718 C 651.56250,370.59135 648.46967,378.29310 643.78217,382.04310 C 639.09467,385.79310 631.44519,384.45036 623.11186,386.32536" id="path1301" sodipodi:nodetypes="czzzzzzzzz" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 611.66596,385.50959 C 604.16596,383.00959 590.35311,382.60170 583.47811,376.35170" id="path1302" sodipodi:nodetypes="cc" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 592.66063,336.86850 C 598.86190,345.30503 604.92417,355.07014 602.71447,365.23480" id="path1303" sodipodi:nodetypes="cc" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 609.51069,344.81342 C 624.10275,344.57017 628.11190,344.21099 630.20397,355.19433 C 635.95715,352.05623 638.95397,353.81615 640.20397,366.31615" id="path1304" sodipodi:nodetypes="ccc" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 620.21706,362.57924 C 620.21706,362.57924 610.95580,381.48089 620.33080,380.85589 C 629.70580,380.23089 626.05002,380.28181 628.70167,379.17696" id="path1305" sodipodi:nodetypes="ccc" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 565.74009,361.50702 C 565.74009,361.50702 574.14469,356.44952 582.12195,352.00386 C 590.09920,348.08121 587.55049,347.42089 587.77146,341.89662 L 591.98094,350.60103 C 595.33715,357.54102 598.53331,356.11130 595.55959,362.81588" id="path1306" sodipodi:nodetypes="czczz" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;" d="M 601.31298,337.74082 C 614.47809,348.72995 606.47413,361.56650 612.31037,373.07050" id="path1307" sodipodi:nodetypes="cc" transform="matrix(0.562759,-0.218675,0.000000,0.600895,376.0347,349.5343)" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0903397;" d="M 707.72710,418.48163 C 703.50641,414.69683 702.27080,417.21075 699.44787,417.57363" id="path1387" sodipodi:nodetypes="cc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0903397;" d="M 725.11736,413.48274 C 719.32763,412.83604 715.73844,415.08845 712.91551,415.45133" id="path1389" sodipodi:nodetypes="cc" /> <path style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0903397;" d="M 699.48958,421.09685 C 695.79191,420.95903 688.54161,427.33639 686.24170,435.60327" id="path1390" sodipodi:nodetypes="cc" /> <path style="font-size:12px;fill:url(#linearGradient2823);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 41.242273,25.859958 C 22.017573,25.859958 5.5631927,36.842948 -1.9115773,52.508368 C 4.0065927,55.540318 10.611773,58.412518 18.396123,56.326088 C 33.013253,53.133778 37.582743,45.608288 44.891303,42.415998 C 60.211183,41.843448 67.548263,49.713588 82.650933,49.371048 C 74.553473,35.420998 59.144253,25.859968 41.242273,25.859958 z" id="path1561" /> <path sodipodi:type="arc" style="font-size:12;fill:url(#radialGradient983);fill-opacity:0.50000000;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none;" id="path1574" sodipodi:cx="271.35836792" sodipodi:cy="796.11926270" sodipodi:rx="37.42873764" sodipodi:ry="37.42873764" d="M 308.787106 796.119263 A 37.428738 37.428738 0 1 0 233.929630,796.119263 A 37.4287 37.4287 0 1 0 308.787 796.119 L 271.358368 796.119263 z" transform="matrix(0.484769,0.000000,0.000000,0.461984,554.2006,323.4255)" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:2.3750000;fill-opacity:1.0000000;" id="rect1280" width="69.963570" height="45.246185" x="128.72227" y="535.48883" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke-width:0.84895535pt;" id="rect1278" width="42.038872" height="31.251434" x="158.54723" y="572.81548" transform="matrix(-0.578460,0.000000,0.000000,0.578460,265.2767,219.3138)" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:4.1057291;" d="M 163.87618,583.27959 C 173.87618,584.11292 182.62618,587.86292 188.25118,596.40459 C 193.87618,605.57126 193.25118,606.40459 193.25118,606.40459 C 193.25118,606.40459 194.50118,615.15459 182.62618,616.40459 C 170.75118,617.02959 157.44312,604.81988 143.69312,604.81988 C 130.56812,604.81988 125.75118,602.77483 127.62618,591.40459 C 129.50118,579.59241 142.93868,553.90459 165.75118,553.27959 C 188.56368,552.02959 209.18868,559.42542 217.62618,574.52959 C 225.43868,589.63376 221.68868,601.40459 217.00118,605.15459 C 212.31368,608.90459 201.58451,603.90459 193.25118,605.77959" id="path1279" sodipodi:nodetypes="czzzzzzzzz" transform="matrix(-0.578460,0.000000,0.000000,0.578460,265.2767,219.3138)" /> <g id="g1249" transform="translate(-9.414290,-1.046033)" style=""> <rect style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:2.3750000;stroke-dasharray:none;" id="rect1289" width="69.963570" height="45.246185" x="128.72227" y="535.48883" transform="matrix(-1.000000,0.000000,0.000000,1.000000,355.1279,42.36432)" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke-width:0.84895535pt;" id="rect1291" width="42.038872" height="31.251434" x="158.54723" y="572.81548" transform="matrix(0.578460,0.000000,0.000000,0.578460,89.85120,261.6781)" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:4.1057290;stroke-dasharray:none;" d="M 163.87618,583.27959 C 173.87618,584.11292 182.62618,587.86292 188.25118,596.40459 C 193.87618,605.57126 193.25118,606.40459 193.25118,606.40459 C 193.25118,606.40459 194.50118,615.15459 182.62618,616.40459 C 170.75118,617.02959 157.44312,604.81988 143.69312,604.81988 C 130.56812,604.81988 125.75118,602.77483 127.62618,591.40459 C 129.50118,579.59241 142.93868,553.90459 165.75118,553.27959 C 188.56368,552.02959 209.18868,559.42542 217.62618,574.52959 C 225.43868,589.63376 221.68868,601.40459 217.00118,605.15459 C 212.31368,608.90459 201.58451,603.90459 193.25118,605.77959" id="path1292" sodipodi:nodetypes="czzzzzzzzz" transform="matrix(0.578460,0.000000,0.000000,0.578460,89.85120,261.6781)" /> </g> <rect style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:2.3750000;" id="rect1268" width="69.963570" height="45.246185" x="128.72227" y="535.48883" transform="matrix(-1.000000,0.000000,0.000000,1.000000,254.4474,140.4299)" /> <path sodipodi:type="arc" style="fill:#9999ff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt;" id="path1285" sodipodi:cx="88.389725" sodipodi:cy="698.28027" sodipodi:rx="18.305565" sodipodi:ry="18.305565" d="M 106.69529 698.28027 A 18.305565 18.305565 0 1 0 70.084160,698.28027 A 18.305565 18.305565 0 1 0 106.69529 698.28027 z" transform="translate(3.138097,1.046032)" /> <rect style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:2.3750000;" id="rect1290" width="69.963570" height="45.246185" x="-120.45193" y="551.95033" transform="scale(-1.000000,1.000000)" /> <path style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-opacity:1.0000000;stroke-width:2.5000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 51.673228,577.76346 L 120.04088,577.76346" id="path1299" /> <path style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-opacity:1.0000000;stroke-width:2.5000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:none;" d="M 88.241974,551.52936 L 87.447001,596.44531" id="path1300" sodipodi:nodetypes="cc" /> <rect style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.3750000;" id="rect1301" width="69.963570" height="45.246185" x="-120.25873" y="552.13202" transform="scale(-1.000000,1.000000)" /> <rect style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt;" id="rect1302" width="8.9940901" height="9.2751551" x="83.195328" y="573.14581" /> <path style="font-size:12.000000;fill:url(#linearGradient968);fill-opacity:0.70196003;stroke:#1c66f9;stroke-width:1.9242834;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99000001;" d="M 37.920277,322.15339 C 38.332250,320.95292 39.768025,319.75197 40.999014,319.93377 L 78.169327,327.96556 C 81.048244,325.43887 85.262603,322.36297 89.606623,323.13302 L 95.922292,324.00942 L 103.90333,325.57660 C 108.56248,326.97946 112.24447,329.89321 112.63056,335.69148 L 112.58162,405.54600 L 37.627148,381.65255 L 37.920277,322.15339 z " id="path1266" sodipodi:nodetypes="cccccccccc" /> <path style="font-size:12.000000;fill:#4789f7;stroke:#1c4ed9;stroke-width:1.7125434;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99216002;" d="M 37.528348,381.35197 L 112.74823,405.58198 L 109.98730,410.63535 L 35.227003,384.92024 L 37.528348,381.35197 z " id="path1271" sodipodi:nodetypes="ccccc" /> <g id="g1279" transform="matrix(0.688750,0.000000,0.000000,0.640474,44.12231,204.0360)"> <path style="fill-rule:evenodd;stroke:none;stroke-width:0.91963024pt;" d="M 15.411826,279.67519 L 107.16635,280.32772 L 105.78092,271.91017 C 104.50888,267.92580 100.16017,263.55105 99.313146,259.07319 C 98.024176,254.59533 104.23642,257.47279 103.48688,250.11822 C 102.73733,242.76364 101.33093,223.23927 90.699786,212.93098 C 79.756146,202.93519 70.616996,196.51871 51.220346,199.66990 C 33.073696,201.57109 22.663616,210.23449 15.263856,225.51906 C 7.6727159,240.80363 16.076616,259.82218 15.837966,266.94924 L 15.411826,279.67519 z " id="path1273" sodipodi:nodetypes="ccczzzzzzc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.0507082pt;fill-opacity:1.0000000;" d="M 81.667436,238.66160 C 80.982416,243.33580 68.662856,240.88582 68.468226,248.58013 C 68.273596,255.77527 84.079546,257.18713 89.984786,255.06933 C 95.890036,252.95153 99.758996,249.65718 99.148096,242.36255 C 98.537216,235.06792 96.575586,216.71313 75.014876,206.18816 C 53.886116,196.16236 29.955336,209.82744 22.306536,224.42792 C 14.657726,239.52760 14.049476,254.81975 23.120686,249.32889 C 31.759936,244.33718 42.301146,228.60033 58.113846,226.78187 C 73.494556,224.96340 82.352426,234.98574 81.667436,238.66160 z " id="path1274" sodipodi:nodetypes="czzzzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.0877723pt;fill-opacity:1.0000000;" d="M 46.065436,250.14579 C 44.767756,248.03998 45.172386,240.05319 38.251386,241.60591 C 31.330386,243.15862 23.814016,250.57710 21.730276,253.25121 C 19.646536,255.92534 20.762826,260.66971 21.730276,261.79111 C 22.697736,262.91251 28.204756,263.51633 29.767576,264.89651 C 31.330386,266.27670 34.976936,271.45240 36.911836,271.10736 C 38.846746,270.76231 42.790986,266.62175 42.939816,264.89653 C 43.088656,263.17129 47.363086,252.25163 46.065436,250.14579 z " id="path1275" sodipodi:nodetypes="czzzzzzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:none;stroke-width:1.0507082pt;fill-opacity:1.0000000;" d="M 42.237126,279.80001 C 42.658006,275.59866 47.388376,258.94410 48.153616,253.91080 C 48.918846,248.87751 46.010966,251.41496 47.235346,249.16869 C 48.459706,246.92241 52.591946,241.63956 55.499816,240.43322 C 58.407706,239.22690 62.539946,239.92518 64.682586,241.04832 C 66.825226,242.17146 68.164386,245.92409 68.355686,247.17200 C 68.546986,248.41993 66.863496,249.83425 65.830426,249.41828 C 64.797366,249.00230 66.447386,242.49537 63.942946,244.49969 C 61.438506,246.68048 58.281376,250.37501 56.647666,251.91412 C 55.338616,253.45321 58.560756,252.66288 59.172936,253.91080 C 59.785116,255.15873 60.932956,257.23860 60.320776,259.40167 C 59.708576,261.56473 57.068536,265.51649 55.499816,266.88920 C 53.931086,268.26192 52.553686,265.59969 50.908446,267.63797 C 49.263196,269.67624 47.037236,278.02692 45.659806,279.98199 L 42.237126,279.80001 z " id="path1276" sodipodi:nodetypes="czzzzzzzzzzzzcc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.8750000;fill-opacity:1.0000000;stroke-dasharray:none;" d="M 41.081076,235.46675 C 41.510266,237.13987 42.851486,241.07668 43.817166,241.96244 C 44.782846,242.84822 46.848346,243.11067 47.197056,241.96244 C 47.545776,240.81421 45.212056,235.04026 51.059786,231.92364 C 57.068466,228.80702 66.457036,229.52876 69.407726,230.93945 C 72.358406,232.35012 77.320946,237.59917 72.626666,241.17509 C 68.737106,244.75098 78.179316,244.84941 80.191156,243.34031 C 82.202996,241.83121 85.125536,236.24432 82.523566,233.55418 C 79.921596,230.86405 73.325156,224.43697 67.209176,223.78085 C 61.093206,223.12471 46.472786,230.41454 44.460956,230.93945 C 42.288186,231.46435 40.651886,233.79361 41.081076,235.46675 z " id="path1277" sodipodi:nodetypes="czzzzzzzzzz" /> </g> <path style="font-size:12.000000;fill:url(#linearGradient967);fill-opacity:0.69929999;stroke:#1c66fb;stroke-width:1.7758849;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99216002;" d="M 17.536640,337.89268 C 16.523741,335.20546 17.516336,332.64170 19.932441,332.91461 L 55.676174,340.52075 L 57.880936,348.26473 L 73.479955,351.89199 L 71.204233,343.73873 L 87.288253,346.49326 C 89.414399,347.18490 91.065826,348.61636 92.573252,351.89801 L 109.47210,409.98240 L 35.111516,384.77857 L 17.536640,337.89268 z " id="path1272" sodipodi:nodetypes="ccccccccccc" /> <g id="g1317"> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:2.0770884;" d="M 472.42571,238.27147 C 472.33405,238.27145 472.24478,238.29291 472.15311,238.29398 L 472.15311,238.31648 C 472.08489,238.31034 472.01758,238.29395 471.94867,238.29398 C 471.78809,238.29403 471.63216,238.33557 471.47163,238.33899 L 471.47163,238.42899 C 471.37376,238.41606 471.27556,238.40652 471.17632,238.40649 C 471.10740,238.40647 471.04010,238.42285 470.97187,238.42899 L 470.97187,238.40649 C 470.88021,238.40543 470.79094,238.38396 470.69928,238.38399 C 465.87162,238.38545 461.03877,239.90805 457.81913,242.92943 C 456.20932,244.44011 446.99543,256.89920 450.09559,259.04098 C 457.81097,264.68512 464.49982,248.07035 457.36480,261.85375 C 456.64585,266.58811 456.46107,269.05668 456.41072,270.29207 C 456.30905,268.02898 455.46815,262.72102 451.04967,260.14359 C 447.35854,258.03472 444.93899,276.66261 444.93899,279.18042 C 444.93899,289.25168 451.37986,299.31925 457.81913,303.34776 C 461.08484,305.39084 466.00722,306.37150 470.90372,306.34054 L 470.90372,306.36305 C 471.15408,306.36510 471.40305,306.34374 471.65336,306.34054 L 471.65336,306.22803 C 471.84267,306.23528 472.03155,306.25211 472.22127,306.25053 L 472.22127,306.22803 C 477.11777,306.25899 482.04015,305.27835 485.30586,303.23524 C 491.74513,299.20674 498.18600,289.13916 498.18600,279.06791 C 498.18600,276.55010 495.76645,257.92220 492.07532,260.03107 C 487.65684,262.60851 486.81594,267.91647 486.71427,270.17956 C 486.66392,268.94417 486.47914,266.47559 485.76018,261.74124 C 478.62517,247.95784 485.31402,264.57260 493.02940,258.92847 C 496.12956,256.78669 486.91567,244.32759 485.30586,242.81691 C 482.08622,239.79554 477.25337,238.27293 472.42571,238.27147 z " id="path1267" transform="matrix(1.033174,0.000000,0.000000,0.909383,216.4479,268.3863)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.70418520pt;" d="M 468.24591,259.15861 C 468.51094,258.62567 467.79271,252.85171 466.69475,251.35949 C 465.59679,249.86726 463.96768,250.52503 463.70265,251.05797 C 463.43764,251.59090 465.07594,250.88137 466.17389,252.37359 C 467.27185,253.86581 467.98090,259.69155 468.24591,259.15861 z " id="path1270" sodipodi:nodetypes="czzzz" transform="matrix(1.033174,0.000000,0.000000,0.909383,216.4479,268.3863)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59326982pt;" d="M 463.34275,289.21648 C 461.03017,288.99344 460.56786,283.64967 458.96224,286.90958 C 457.28286,290.22776 460.74374,297.34319 461.04820,293.66548 C 461.27890,289.98777 465.58157,289.49777 463.34275,289.21648 z " id="path1278" sodipodi:nodetypes="czzz" transform="matrix(1.033174,0.000000,0.000000,0.909383,216.4479,268.3863)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.68256974pt;" d="M 708.64967,503.43717 C 708.37585,502.95253 709.11791,497.70179 710.25229,496.34479 C 711.38666,494.98778 713.06983,495.58594 713.34365,496.07058 C 713.61745,496.55524 711.92480,495.90999 710.79043,497.26699 C 709.65604,498.62400 708.92347,503.92182 708.64967,503.43717 z " id="path1283" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.57505898pt;" d="M 710.57739,531.81732 C 712.96669,531.61449 713.44433,526.75496 715.10322,529.71946 C 716.83831,532.73696 713.26262,539.20762 712.94806,535.86317 C 712.70970,532.51872 708.26430,532.07312 710.57739,531.81732 z " id="path1284" sodipodi:nodetypes="czzz" /> </g> <g id="g1329" transform="translate(-104.0802,-97.80402)"> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.8718444;" d="M 841.03523,592.70109 C 835.90467,592.76390 830.22818,593.56676 826.67923,597.28291 C 823.87668,600.24935 817.50896,615.99836 816.60602,618.30168 C 815.09992,624.27793 814.05854,630.78886 816.99244,636.56898 C 819.81959,643.25189 825.72828,649.72836 833.94116,650.75621 C 839.37129,651.44267 845.09032,651.35874 850.31458,649.72833 C 856.42815,647.71665 860.44343,642.53509 863.07436,637.37323 C 865.55779,632.40703 865.94287,626.74320 864.51563,621.47197 C 863.89507,618.11627 856.12574,599.89965 853.80199,597.15457 C 850.54532,594.03086 845.67202,592.69881 841.03523,592.70109 z " id="path1288" sodipodi:nodetypes="cccccccccc" transform="translate(-3.661113,-7.322226)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.63460236pt;" d="M 838.07247,610.64237 C 839.95513,610.18459 838.75317,605.01626 837.71507,603.73449 C 836.67696,602.45272 829.77408,601.13926 832.78769,603.68422 C 836.03445,606.02046 835.95665,611.10014 838.07247,610.64237 z " id="path1289" sodipodi:nodetypes="czzz" transform="translate(-3.661113,-7.322226)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.53464689pt;" d="M 835.74471,629.37680 C 833.55820,629.18522 829.82379,631.67928 828.30569,634.47943 C 826.71786,637.32962 829.99008,643.44151 830.27794,640.28249 C 830.49606,637.12348 837.86149,629.61842 835.74471,629.37680 z " id="path1290" sodipodi:nodetypes="czzz" transform="translate(-3.661113,-7.322226)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.63460231pt;" d="M 842.27092,610.67154 C 840.38825,610.21376 841.59021,605.04542 842.62832,603.76366 C 843.66642,602.48189 850.56930,601.16843 847.55570,603.71338 C 844.30893,606.04963 844.38672,611.12931 842.27092,610.67154 z " id="path1293" sodipodi:nodetypes="czzz" transform="translate(-3.661113,-7.322226)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.53464689pt;" d="M 844.89363,628.76239 C 847.08014,628.57081 850.81456,631.06487 852.33265,633.86502 C 853.92048,636.71521 850.64827,642.82710 850.36040,639.66808 C 850.14228,636.50907 842.77686,629.00401 844.89363,628.76239 z " id="path1310" sodipodi:nodetypes="czzz" transform="translate(-3.661113,-7.322226)" /> </g> <path sodipodi:type="arc" style="font-size:12px;fill:url(#radialGradient704);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.87644994;stroke-dasharray:none" id="path1268" sodipodi:cx="271.35837" sodipodi:cy="796.11926" sodipodi:rx="37.428738" sodipodi:ry="37.428738" d="M 308.78711,796.11926 A 37.428738,37.428738 0 1 1 233.92963,796.11926 A 37.428738,37.428738 0 1 1 308.78711,796.11926 z" transform="matrix(1.269231,0,0,1.209574,540.73332,-885.28294)" /> <path style="font-size:12px;fill:url(#linearGradient1110);fill-opacity:0.38016998;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 885.13854,32.041206 C 865.91384,32.041206 849.45946,43.024196 841.98469,58.689616 C 847.90286,61.721566 854.50804,64.593766 862.29239,62.507336 C 876.90952,59.315026 881.47901,51.789536 888.78757,48.597246 C 904.10745,48.024696 911.44453,55.894836 926.5472,55.552296 C 918.44974,41.602246 903.04052,32.041216 885.13854,32.041206 z" id="path1269" /> <text xml:space="preserve" style="font-size:53.10573959px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial Black" x="727.4552" y="110.45654" id="text1284" sodipodi:linespacing="100%" transform="scale(1.1590137,0.8628026)"><tspan x="727.4552" y="110.45654" sodipodi:role="line" id="tspan1287">3D</tspan></text> <path style="font-size:12px;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 862.36154,831.74143 L 862.36154,924.49 C 889.80881,924.49 912.07889,903.73438 912.07886,878.13172 C 912.07886,852.52905 889.80879,831.74141 862.36154,831.74143 z " id="path3207" /> <g id="g4179"> <path transform="matrix(1.269231,0,0,1.209574,-252.0699,-51.3724)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path3205" style="font-size:12px;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> <path sodipodi:nodetypes="csccccccc" id="path2293" d="M 121.04942,876.41746 C 115.9942,876.41746 85.290278,896.93033 69.807528,903.81184 C 65.343898,905.79576 131.15987,906.55128 131.15987,906.55128 L 82.62969,924.35764 L 92.74016,875.04774 L 51.091495,891.29811 L 65.441938,915.45446 L 113.97211,928.4668 L 82.951128,953.93266" style="fill:none;fill-rule:evenodd;stroke:red;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path id="path3209" d="M 92.371567,865.47065 C 73.146867,865.47065 56.692487,876.45364 49.217717,892.11906 C 55.135887,895.15101 61.741067,898.02321 69.525417,895.93678 C 84.142547,892.74447 88.712037,885.21898 96.020597,882.02669 C 111.34048,881.45414 118.67756,889.32428 133.78023,888.98174 C 125.68277,875.03169 110.27355,865.47066 92.371567,865.47065 z " style="font-size:12px;fill:url(#linearGradient3271);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1pt" /> <path transform="matrix(1.269231,0,0,1.209574,-254.2131,-49.87948)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path3267" style="font-size:12px;fill:url(#radialGradient3289);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> </g> <g id="g4185" transform="matrix(0.587317,0,0,0.587317,135.8273,373.3777)"> <path transform="matrix(1.269231,0,0,1.209574,-252.0699,-51.3724)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path4187" style="font-size:12px;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> <path sodipodi:nodetypes="csccccccc" id="path4189" d="M 121.04942,876.41746 C 115.9942,876.41746 85.290278,896.93033 69.807528,903.81184 C 65.343898,905.79576 131.15987,906.55128 131.15987,906.55128 L 82.62969,924.35764 L 92.74016,875.04774 L 51.091495,891.29811 L 65.441938,915.45446 L 113.97211,928.4668 L 82.951128,953.93266" style="fill:none;fill-rule:evenodd;stroke:red;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path id="path4191" d="M 92.371567,865.47065 C 73.146867,865.47065 56.692487,876.45364 49.217717,892.11906 C 55.135887,895.15101 61.741067,898.02321 69.525417,895.93678 C 84.142547,892.74447 88.712037,885.21898 96.020597,882.02669 C 111.34048,881.45414 118.67756,889.32428 133.78023,888.98174 C 125.68277,875.03169 110.27355,865.47066 92.371567,865.47065 z " style="font-size:12px;fill:url(#linearGradient4195);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1pt" /> <path transform="matrix(1.269231,0,0,1.209574,-254.2131,-49.87948)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path4193" style="font-size:12px;fill:url(#radialGradient4197);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> </g> <g id="g4199" transform="matrix(0.75239,0,0,0.75239,212.8041,226.4211)"> <path transform="matrix(1.269231,0,0,1.209574,-252.0699,-51.3724)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path4201" style="font-size:12px;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> <path sodipodi:nodetypes="csccccccc" id="path4203" d="M 121.04942,876.41746 C 115.9942,876.41746 85.290278,896.93033 69.807528,903.81184 C 65.343898,905.79576 131.15987,906.55128 131.15987,906.55128 L 82.62969,924.35764 L 92.74016,875.04774 L 51.091495,891.29811 L 65.441938,915.45446 L 113.97211,928.4668 L 82.951128,953.93266" style="fill:none;fill-rule:evenodd;stroke:red;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path id="path4205" d="M 92.371567,865.47065 C 73.146867,865.47065 56.692487,876.45364 49.217717,892.11906 C 55.135887,895.15101 61.741067,898.02321 69.525417,895.93678 C 84.142547,892.74447 88.712037,885.21898 96.020597,882.02669 C 111.34048,881.45414 118.67756,889.32428 133.78023,888.98174 C 125.68277,875.03169 110.27355,865.47066 92.371567,865.47065 z " style="font-size:12px;fill:url(#linearGradient4209);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1pt" /> <path transform="matrix(1.269231,0,0,1.209574,-254.2131,-49.87948)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path4207" style="font-size:12px;fill:url(#radialGradient4211);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> </g> <g id="g4213" transform="matrix(0.355527,0,0,1.090014,324.7627,-82.64672)"> <path transform="matrix(1.269231,0,0,1.209574,-252.0699,-51.3724)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path4215" style="font-size:12px;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> <path sodipodi:nodetypes="csccccccc" id="path4217" d="M 121.04942,876.41746 C 115.9942,876.41746 85.290278,896.93033 69.807528,903.81184 C 65.343898,905.79576 131.15987,906.55128 131.15987,906.55128 L 82.62969,924.35764 L 92.74016,875.04774 L 51.091495,891.29811 L 65.441938,915.45446 L 113.97211,928.4668 L 82.951128,953.93266" style="fill:none;fill-rule:evenodd;stroke:red;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path id="path4219" d="M 92.371567,865.47065 C 73.146867,865.47065 56.692487,876.45364 49.217717,892.11906 C 55.135887,895.15101 61.741067,898.02321 69.525417,895.93678 C 84.142547,892.74447 88.712037,885.21898 96.020597,882.02669 C 111.34048,881.45414 118.67756,889.32428 133.78023,888.98174 C 125.68277,875.03169 110.27355,865.47066 92.371567,865.47065 z " style="font-size:12px;fill:url(#linearGradient4223);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1pt" /> <path transform="matrix(1.269231,0,0,1.209574,-254.2131,-49.87948)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path4221" style="font-size:12px;fill:url(#radialGradient4225);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none" sodipodi:type="arc" /> </g> <flowRoot xml:space="preserve" id="flowRoot4227" style="font-size:36px;font-weight:bold;fill:navy" transform="translate(33.72834,142.0141)"><flowRegion id="flowRegion4229"><rect id="rect4231" width="361.5441" height="35.503513" x="42.604218" y="822.77283" style="font-size:36px;font-weight:bold;fill:navy" /></flowRegion><flowPara id="flowPara4233">A B C D</flowPara></flowRoot> <rect style="fill:url(#linearGradient3613);fill-opacity:0.75;fill-rule:evenodd;stroke:#ffffff;stroke-width:3.75;stroke-dasharray:none" id="rect3611" width="91.25" height="30" x="-216.6974" y="113.70129" ry="12.5" transform="scale(-1,1)" /> <path sodipodi:type="arc" style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:2.78699993999999980;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path3615" sodipodi:cx="133.34541" sodipodi:cy="168.70491" sodipodi:rx="6.5046539" sodipodi:ry="10.732679" d="M 139.85007,168.70491 A 6.5046539,10.732679 0 1 1 126.84076,168.70491 A 6.5046539,10.732679 0 1 1 139.85007,168.70491 z" transform="matrix(1.0175006,0,0,0.8287883,-2.3336285,26.932865)" /> <path style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 69.5998,-4.6441188 L 35.125132,-15.702031" id="path3621" /> <path style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 101.4726,-7.2459804 L 111.22959,-37.637817 L 121.63703,-8.5469113 L 101.4726,-7.2459804 z" id="path3625" /> <path style="fill:#ff0000;fill-rule:evenodd;stroke:none;stroke-width:0.80189854px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 148.33682,165.27754 L 155.34262,135.45182 C 155.34262,135.45182 161.4727,167.76301 160.59697,169.00575 C 160.59697,169.00575 157.49655,165.13261 155.57225,164.45262 C 153.64794,163.7726 148.33682,165.27754 148.33682,165.27754 z" id="path3627" sodipodi:nodetypes="ccczc" /> <path style="fill:#ff0000;fill-rule:evenodd;stroke:none;stroke-width:0.80189854px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 207.91289,165.27754 L 214.91869,135.45182 C 214.91869,135.45182 221.04877,167.76301 220.17304,169.00575 C 220.17304,169.00575 217.07262,165.13261 215.14832,164.45262 C 213.22401,163.7726 207.91289,165.27754 207.91289,165.27754 z" id="path3629" sodipodi:nodetypes="ccczc" /> </svg> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/refresh.bmp����������������������������������������������������0000755�0001750�0001750�00000003366�10673041454�017140� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM������6���(���������������������������������ͼк̷gg**����QQ땕jj������������������##̤##������((GGTTGG������SS̨^^荍KK샃̠00����??̌//����]]����^^̨--��������gg\\��66��������2277��EĖ���� ̵ ̊̾oo㟟[[��ii66̨��ttJJVVll99LL!!yy99##PP��̗ٽ̉��}}��JĴ==??̷̼��������BBqqTT��""��������̺��WW����kk̖��̬ԏی22̑ ����((hh剉ݏ}}YY$$����ww̯66��������������������SS̘EE ����������??ͤֈ||ޛ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/mini.svg�������������������������������������������������������0000755�0001750�0001750�00000032411�10713567150�016451� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg2256" sodipodi:version="0.32" inkscape:version="0.45.1" width="128" height="128" version="1.0" sodipodi:docbase="C:\mricron\html" sodipodi:docname="mini.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape"> <metadata id="metadata2261"> <rdf:RDF> <cc:Work rdf:about=""> <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> </cc:Work> </rdf:RDF> </metadata> <defs id="defs2259"> <filter inkscape:collect="always" id="filter3324"> <feGaussianBlur inkscape:collect="always" stdDeviation="3.8223414" id="feGaussianBlur3326" /> </filter> <filter inkscape:collect="always" id="filter3502"> <feGaussianBlur inkscape:collect="always" stdDeviation="3.1080325" id="feGaussianBlur3504" /> </filter> <filter inkscape:collect="always" x="-0.068783067" width="1.1375661" y="-0.11711711" height="1.2342342" id="filter3528"> <feGaussianBlur inkscape:collect="always" stdDeviation="3.5630003" id="feGaussianBlur3530" /> </filter> <filter inkscape:collect="always" id="filter3740"> <feGaussianBlur inkscape:collect="always" stdDeviation="2.7552379" id="feGaussianBlur3742" /> </filter> <filter inkscape:collect="always" id="filter3886"> <feGaussianBlur inkscape:collect="always" stdDeviation="4.6432082" id="feGaussianBlur3888" /> </filter> <filter inkscape:collect="always" id="filter4027"> <feGaussianBlur inkscape:collect="always" stdDeviation="3.4304274" id="feGaussianBlur4029" /> </filter> </defs> <sodipodi:namedview inkscape:window-height="870" inkscape:window-width="1240" inkscape:pageshadow="2" inkscape:pageopacity="0.0" guidetolerance="10.0" gridtolerance="10.0" objecttolerance="10.0" borderopacity="1.0" bordercolor="#666666" pagecolor="#ffffff" id="base" inkscape:zoom="0.75061011" inkscape:cx="447.21723" inkscape:cy="-211.51769" inkscape:window-x="44" inkscape:window-y="0" inkscape:current-layer="svg2256" width="128px" height="128px" /> <g id="g2187" transform="matrix(0.1391938,0,0,0.1544313,1.9456067,-0.9518683)"> <path id="path2277" d="M 470.26695,122.56853 C 365.28205,122.51433 104.26695,154.59979 104.26695,154.59978 L 61.829448,179.25603 C 61.829448,179.25603 21.863248,302.11966 17.423248,430.88103 C 12.983148,559.64238 44.079448,694.3185 44.079448,694.31853 L 132.86075,749.56858 L 318.36075,735.75603 L 674.54825,734.75603 C 674.54825,734.75603 766.33255,519.66619 785.07945,464.41228 C 803.82635,409.15837 720.92325,186.16229 720.92325,186.16228 C 720.92325,186.16228 575.90705,127.97069 489.07945,123.03728 C 483.59105,122.72894 477.26595,122.57214 470.26695,122.56853 z M 452.54825,307.53728 C 520.08425,307.53729 574.89195,359.02356 574.89195,422.47478 C 574.89205,485.926 520.08425,537.44353 452.54825,537.44353 C 385.01215,537.44352 330.20445,485.926 330.20445,422.47478 C 330.20435,359.02356 385.01215,307.53728 452.54825,307.53728 z " style="fill:#aeaeae;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.60000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path id="path3506" d="M 609.43985,154.60357 L 716.98765,188.15059 L 733.76115,227.61767 L 666.66715,190.12394 L 609.43985,154.60357 z " style="opacity:0.21666667;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter3528)" /> <path id="path3336" d="M 66.767548,182.23053 L 53.940748,220.71093 L 75.647648,195.05733 L 85.514448,218.73758 L 128.92825,182.23053 L 275.94305,153.61689 L 329.22365,160.52363 L 379.54415,131.91 L 171.35535,149.67019 L 102.28795,158.55028 L 66.767548,182.23053 z " style="opacity:0.11111109;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter3502)" /> <path sodipodi:nodetypes="ccscccsssc" id="path2281" d="M 467.79528,122.93964 C 283.97738,122.93964 131.89205,254.99623 131.89195,422.47478 C 131.89195,589.95333 281.07405,725.881 464.89195,725.88103 C 648.70985,725.88103 797.89205,589.95333 797.89195,422.47478 C 797.89195,254.99623 651.61318,122.93964 467.79528,122.93964 z M 474.76695,238.47478 C 587.23635,238.47479 678.51695,323.3403 678.51695,427.91228 C 678.51695,532.48427 587.23625,617.34978 474.76695,617.34978 C 362.29765,617.34976 271.01695,532.48426 271.01695,427.91228 C 271.01695,323.34031 362.29765,238.47478 474.76695,238.47478 z " style="opacity:1;fill:#009990;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> <path sodipodi:nodetypes="ccscsc" id="path3330" d="M 466.52265,725.68157 C 299.87515,725.68157 162.26495,611.74002 142.65745,468.59724 C 156.42695,468.85724 228.20685,714.18323 470.91455,708.76876 C 731.14935,702.96329 765.39815,528.42344 778.72845,487.00424 C 793.92915,472.92559 792.19825,449.23943 791.78785,460.80489 C 786.85445,600.80324 635.75525,722.72157 466.52265,725.68157 z " style="opacity:0.46111109;fill:#030103;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> <path id="path2294" d="M 474.76695,238.47478 C 362.29765,238.47478 271.01695,323.34031 271.01695,427.91228 C 271.01695,532.48426 362.29765,617.34976 474.76695,617.34978 C 587.23625,617.34978 678.51695,532.48427 678.51695,427.91228 C 678.51695,323.3403 587.23635,238.47479 474.76695,238.47478 z M 451.57945,320.34978 C 508.22255,320.3498 554.17325,366.55931 554.17325,423.47478 C 554.17315,480.39023 508.22255,526.56853 451.57945,526.56853 C 394.93625,526.56852 348.95445,480.39025 348.95445,423.47478 C 348.95435,366.55928 394.93635,320.34978 451.57945,320.34978 z " style="opacity:1;fill:#c0c0c0;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> <path sodipodi:nodetypes="ccccc" id="path2315" d="M 306.76523,520.33116 L 426.88496,525.12996 L 489.56056,590.7715 L 308.50345,604.52828 L 306.76523,520.33116 z " style="fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path sodipodi:nodetypes="cczc" id="path2279" d="M 108.20795,428.89977 L 60.847448,441.72657 C 60.847448,441.72657 62.080848,351.44563 72.687648,282.87158 C 83.294448,214.29753 104.26125,154.60357 104.26125,154.60357" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path sodipodi:nodetypes="cccccccc" id="path2309" d="M 751.52135,549.27437 L 751.52135,585.78141 L 720.93435,613.40837 L 561.09275,608.47498 L 530.50575,581.83471 L 526.55895,504.8739 L 735.73455,535.46089 L 751.52135,549.27437 z " style="fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path id="path2311" d="M 531.49245,578.87467 L 384.47755,555.19443 L 452.55825,591.70148 L 562.07935,608.47498 L 531.49245,578.87467 z " style="fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path sodipodi:nodetypes="ccscsc" id="path2317" d="M 463.7235,127.87852 C 297.076,127.87852 157.53025,237.94896 137.92275,381.09174 C 149.7567,345.02397 227.41885,129.58569 470.12655,135.00016 C 730.36135,140.80563 760.66345,321.26554 773.99375,362.68474 C 789.19445,376.76339 790.39498,394.5644 788.9887,383.07743 C 772.44198,247.91796 643.8095,127.87849 463.7235,127.87852 z " style="opacity:0.3;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter3324)" /> <path sodipodi:nodetypes="cccccccc" id="path2305" d="M 382.50415,501.91387 L 365.73065,482.18033 L 629.38633,496.56043 L 711.06765,535.46089 L 683.13773,575.61175 L 547.27925,561.11449 L 541.20784,513.4511 L 382.50415,501.91387 z " style="fill:#848484;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path id="path3328" d="M 634.10685,520.66073 L 384.47755,500.92719" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path sodipodi:nodetypes="ccccc" id="path2313" d="M 384.47755,555.19443 L 382.50415,500.92719 L 532.47905,511.78064 L 529.51905,578.87467 L 384.47755,555.19443 z " style="fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path sodipodi:nodetypes="ccscscsc" id="path2275" d="M 108.20795,429.88645 L 321.33025,431.8598 C 321.33025,431.8598 337.11705,439.75322 330.21025,528.55414 C 323.30355,617.35507 322.31685,735.75631 322.31685,735.75631 C 322.31685,735.75631 315.41015,749.56978 303.56995,750.55648 C 291.72985,751.54318 134.84825,750.55648 134.84825,750.55648 C 134.84825,750.55648 107.22135,642.02201 112.15475,556.18111 C 117.08805,470.34021 109.19465,428.89977 108.20795,429.88645 z " style="fill:#b4b4b4;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path sodipodi:nodetypes="ccccccccccccc" id="path2307" d="M 629.11678,496.99938 L 634.16352,520.67963 L 650.13935,527.56747 L 657.93823,541.41875 L 672.64392,548.28769 L 680.53732,575.91464 L 826.11952,576.84462 L 834.90434,548.2665 L 848.05259,541.93894 L 855.42734,528.18433 L 871.55888,521.89313 L 877.24515,498.95384 L 629.11678,496.99938 z " style="fill:#acacac;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path sodipodi:nodetypes="cszccc" id="path3534" d="M 47.034048,692.34253 C 47.034048,692.34253 20.147048,566.78788 28.287148,529.54082 C 36.427248,492.29376 39.880548,565.8012 60.847448,582.82138 C 81.814348,599.84156 106.23465,589.72812 106.23465,589.72812 L 130.90155,745.62308 L 47.034048,692.34253 z " style="opacity:0.05;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter3740)" /> <path sodipodi:nodetypes="cscscsc" id="path3744" d="M 117.08805,589.72812 C 219.70245,717.00945 313.43685,599.59489 319.35685,628.20852 C 325.27695,656.82215 308.50345,721.94284 308.50345,721.94284 C 308.50345,721.94284 290.74315,737.72967 280.87645,738.71635 C 271.00965,739.70301 138.79505,740.6897 138.79505,740.6897 C 138.79505,740.6897 123.00815,684.69578 118.07475,644.98203 C 113.14135,605.26828 117.08805,589.72812 117.08805,589.72812 z " style="opacity:0.04444442;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter3886)" /> <path sodipodi:nodetypes="cccsccc" id="path3890" d="M 473.78025,229.59469 C 434.90905,229.59469 314.69695,282.2284 294.64115,319.47409 C 290.33955,354.11247 349.78446,363.88688 360.04246,359.01822 C 377.76996,330.10206 409.13294,310.56167 463.43924,312.53502 C 509.92934,314.25561 528.74162,338.97444 542.10032,364.69155 C 595.00092,374.15948 643.67325,321.97478 643.67325,321.97478 C 607.04255,271.60155 544.05705,229.5947 473.78025,229.59469 z " style="opacity:0.13888891;fill:#646464;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4027)" /> </g> </svg> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/xbars.bmp������������������������������������������������������0000755�0001750�0001750�00000003366�10673035364�016624� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BM������6���(�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/bucket24.png���������������������������������������������������0000755�0001750�0001750�00000002160�11040141336�017107� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������|fu���sBIT|d��� pHYs����.���tEXtSoftware�www.inkscape.org<��IDATH}LUuǿ{q 1b͚*5@j QZ?sla5\!^Z ZR8S, zy\ s۞=s=I,u ¾ )%Fs1_ gg[nlcTT>آqK�mL5/R\<V.U~]PŘՏm[\ٿ鈣]}% Prt{;G1,, RtK(N xV^IeXbݭ |"Ыa3G .j\=G |`%s_O,X< XQ=k29M 2[evhC:7ӽ{`QW;XfWFe(.#${6ЇX.N}^*1Cޖ84v~ Ȋɀ, e@T\op ��~A ScO [)4 ͷ̦0"JDEZ= Q32U=磧rx;]lUHH=hЖ`NB Xي|,i�V fCYa!첥ѨV4b9e{nn1YtD‚jj05k6xC<4;^l(tvwsmpjZ,_1[_>YWC_Ĺ:RFc_ihw얻�<jSZms[Zڕ&yiPf.pa SoJ(g7*<s}/{C/' .Ќޔ#W'CBu&q^>=p��,N =zˤ9:&0i#˴?ρmp�5 u2�`| "-VNIg�N���Zm/^�&GsV5.A����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/btn/drawing4z.svg��������������������������������������������������0000755�0001750�0001750�00000455571�11041225200�017424� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="744.09448819" height="1052.3622047" id="svg2" sodipodi:version="0.32" inkscape:version="0.46" sodipodi:docbase="C:\Documents and Settings\Chris Rorden\My Documents\mx1390old\btn" sodipodi:docname="drawing4z.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape"> <defs id="defs4"> <inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 526.18109 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="744.09448 : 526.18109 : 1" inkscape:persp3d-origin="372.04724 : 350.78739 : 1" id="perspective394" /> <linearGradient id="linearGradient17937"> <stop style="stop-color:#ffffff;stop-opacity:0.74226803;" offset="0" id="stop17939" /> <stop id="stop17945" offset="1" style="stop-color:#5fbcd3;stop-opacity:1;" /> </linearGradient> <radialGradient r="24.522423" fy="808.40576" fx="280.46881" cy="808.40576" cx="280.46881" gradientUnits="userSpaceOnUse" id="radialGradient2803" xlink:href="#linearGradient684" inkscape:collect="always" /> <radialGradient fy="812.97649" fx="289.25905" r="16.96986" cy="812.97649" cx="289.25905" id="radialGradient983" xlink:href="#linearGradient1547" gradientUnits="userSpaceOnUse" /> <radialGradient fy="807.81573" fx="292.27442" r="24.522423" cy="807.81573" cx="292.27442" id="radialGradient1203" xlink:href="#linearGradient684" gradientUnits="userSpaceOnUse" /> <linearGradient y2="852.86278" x2="335.31547" y1="743.24066" x1="326.75421" id="linearGradient1202" xlink:href="#linearGradient684" gradientTransform="scale(1.7571663,0.5690981)" gradientUnits="userSpaceOnUse" /> <linearGradient y2="389.11669" x2="206.25145" y1="386.86683" x1="210.53689" id="linearGradient1175" xlink:href="#linearGradient1172" gradientTransform="scale(0.758349,1.3186542)" gradientUnits="userSpaceOnUse" /> <linearGradient y2="207.27092" x2="383.23312" y1="199.43834" x1="359.54053" id="linearGradient1139" xlink:href="#linearGradient671" gradientTransform="scale(0.4268666,2.3426521)" gradientUnits="userSpaceOnUse" /> <radialGradient fy="807.81573" fx="292.27442" r="24.522423" cy="807.81573" cx="292.27442" id="radialGradient704" xlink:href="#linearGradient1271" gradientUnits="userSpaceOnUse" /> <linearGradient y2="2051.6487" x2="187.71159" y1="2042.7123" x1="187.74077" id="linearGradient703" xlink:href="#linearGradient671" gradientTransform="scale(3.0094286,0.332289)" gradientUnits="userSpaceOnUse" /> <linearGradient y2="1239.0289" x2="101.51829" y1="1187.1978" x1="90.8512" id="linearGradient683" xlink:href="#linearGradient684" gradientTransform="scale(1.6468933,0.6072039)" gradientUnits="userSpaceOnUse" /> <radialGradient fy="807.81573" fx="292.27442" r="24.522423" cy="807.81573" cx="292.27442" id="radialGradient1169" xlink:href="#linearGradient684" gradientUnits="userSpaceOnUse" /> <radialGradient fy="162.34375" fx="62.1875" r="7.0745194" cy="162.34375" cx="62.1875" id="radialGradient1158" xlink:href="#linearGradient1155" gradientUnits="userSpaceOnUse" /> <linearGradient id="linearGradient1155"> <stop id="stop1156" offset="0.00000000" style="stop-color:#fffbfb;stop-opacity:1.0000000;" /> <stop id="stop1157" offset="1.0000000" style="stop-color:#9999ff;stop-opacity:1.0000000;" /> </linearGradient> <linearGradient id="linearGradient594"> <stop id="stop595" offset="0.00000000" style="stop-color:#fffbfb;stop-opacity:1.0000000;" /> <stop id="stop596" offset="1.0000000" style="stop-color:#007aff;stop-opacity:1.0000000;" /> </linearGradient> <linearGradient id="linearGradient671"> <stop id="stop672" offset="0.00000000" style="stop-color:#ffffff;stop-opacity:1.0000000;" /> <stop id="stop673" offset="1.0000000" style="stop-color:#ffffff;stop-opacity:0.00000000;" /> </linearGradient> <linearGradient id="linearGradient684"> <stop id="stop685" offset="0.00000000" style="stop-color:#ffffff;stop-opacity:1.0000000;" /> <stop id="stop686" offset="1.0000000" style="stop-color:#9999ff;stop-opacity:1.0000000;" /> </linearGradient> <linearGradient id="linearGradient969"> <stop id="stop970" offset="0.00000000" style="stop-color:#ffffff;stop-opacity:0.70196080;" /> <stop id="stop971" offset="1.0000000" style="stop-color:#9999ff;stop-opacity:0.70196080;" /> </linearGradient> <linearGradient id="linearGradient1172"> <stop id="stop1173" offset="0.00000000" style="stop-color:#ffffff;stop-opacity:0.3;" /> <stop id="stop1174" offset="1.00000000" style="stop-color:#ffffff;stop-opacity:0.8;" /> </linearGradient> <linearGradient id="linearGradient1274"> <stop id="stop1275" offset="0.00000000" style="stop-color:#ff0400;stop-opacity:1.0000000;" /> <stop id="stop1277" offset="0.0099999998" style="stop-color:#fd6972;stop-opacity:1.0000000;" /> <stop id="stop1276" offset="1.0000000" style="stop-color:#ff0000;stop-opacity:1.0000000;" /> </linearGradient> <linearGradient id="linearGradient1111"> <stop id="stop1112" offset="0.00000000" style="stop-color:#e8e838;stop-opacity:1.0000000;" /> <stop id="stop1114" offset="1.0000000" style="stop-color:#ffff7f;stop-opacity:1.0000000;" /> </linearGradient> <linearGradient id="linearGradient1547"> <stop id="stop1548" offset="0.00000000" style="stop-color:#9999ff;stop-opacity:1.0000000;" /> <stop id="stop1549" offset="1.0000000" style="stop-color:#9999fd;stop-opacity:0.00000000;" /> </linearGradient> <linearGradient id="linearGradient1563"> <stop id="stop1564" offset="0.00000000" style="stop-color:#898bdc;stop-opacity:1.0000000;" /> <stop id="stop1565" offset="1.0000000" style="stop-color:#000000;stop-opacity:1.0000000;" /> </linearGradient> <linearGradient id="linearGradient1608"> <stop id="stop1609" offset="0.00000000" style="stop-color:#ffffff;stop-opacity:1.0000000;" /> <stop id="stop1611" offset="0.50000000" style="stop-color:#9999ff;stop-opacity:1.0000000;" /> <stop id="stop1610" offset="1.0000000" style="stop-color:#000000;stop-opacity:1.0000000;" /> </linearGradient> <linearGradient id="linearGradient1271"> <stop id="stop1274" offset="0.00000000" style="stop-color:#ffc87e;stop-opacity:1.0000000;" /> <stop id="stop1279" offset="1.0000000" style="stop-color:#ff0000;stop-opacity:1.0000000;" /> </linearGradient> <linearGradient id="linearGradient1280"> <stop id="stop1281" offset="0.00000000" style="stop-color:#ffc000;stop-opacity:1.0000000;" /> <stop id="stop1283" offset="1.0000000" style="stop-color:#ff0000;stop-opacity:0.50000000;" /> </linearGradient> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient3036" x1="187.74077" y1="2042.7123" x2="187.71159" y2="2051.6487" gradientTransform="scale(3.0094286,0.332289)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient3038" x1="187.74077" y1="2042.7123" x2="187.71159" y2="2051.6487" gradientTransform="scale(3.0094286,0.332289)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient3040" x1="187.74077" y1="2042.7123" x2="187.71159" y2="2051.6487" gradientTransform="scale(3.0094286,0.332289)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient3042" x1="187.74077" y1="2042.7123" x2="187.71159" y2="2051.6487" gradientTransform="scale(3.0094286,0.332289)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient3044" x1="187.74077" y1="2042.7123" x2="187.71159" y2="2051.6487" gradientTransform="scale(3.0094286,0.332289)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient3046" x1="187.74077" y1="2042.7123" x2="187.71159" y2="2051.6487" gradientTransform="scale(3.0094286,0.332289)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient3048" x1="187.74077" y1="2042.7123" x2="187.71159" y2="2051.6487" gradientTransform="scale(3.0094286,0.332289)" gradientUnits="userSpaceOnUse" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="radialGradient3062" cx="289.25905" cy="812.97649" fx="289.25905" fy="812.97649" r="16.96986" gradientUnits="userSpaceOnUse" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="radialGradient3064" cx="289.25905" cy="812.97649" fx="289.25905" fy="812.97649" r="16.96986" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1280" id="linearGradient3087" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.6468933,0,0,0.6072039,-707.89942,-735.8277)" x1="459.4994" y1="1254.0935" x2="481.37598" y2="1325.9788" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient969" id="linearGradient3103" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0923649,0,0,0.915445,-15.816734,-109.09188)" x1="48.734489" y1="368.05664" x2="55.008646" y2="445.4552" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient684" id="linearGradient3113" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.9373488,0,0,1.0668387,-15.816734,-109.09188)" x1="46.314715" y1="300.89402" x2="84.46981" y2="407.3278" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="linearGradient3132" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.6468933,0,0,0.6072039,-15.816734,-109.09188)" x1="169.59108" y1="1212.3388" x2="175.37662" y2="1267.5976" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1111" id="linearGradient3202" gradientUnits="userSpaceOnUse" gradientTransform="matrix(2.5036225,0,0,0.5791021,-389.92538,-113.29149)" x1="85.863811" y1="835.45038" x2="85.679877" y2="809.33162" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1274" id="linearGradient3226" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.8935111,0,0,1.1191803,27.935496,-68.87518)" x1="498.83997" y1="87.851495" x2="527.61901" y2="134.61744" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1608" id="linearGradient3266" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.677741,0,0,0.5960396,15.816734,-109.09188)" x1="-196.8662" y1="425.48517" x2="-141.23934" y2="425.48517" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient969" id="radialGradient3315" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.075993,0,0,0.9293741,-15.816734,-109.09188)" cx="524.70152" cy="475.22645" fx="524.70152" fy="475.22645" r="111.10576" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1172" id="linearGradient3321" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.758349,0,0,1.3186542,-15.816734,-109.09188)" x1="477.45044" y1="381.63529" x2="473.165" y2="383.88514" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient3325" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4268666,0,0,2.3426521,-15.816734,-109.09188)" x1="833.72519" y1="196.49355" x2="857.41778" y2="204.32614" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1172" id="linearGradient3330" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.758349,0,0,1.3186542,-15.816734,-109.09188)" x1="339.63678" y1="379.11596" x2="335.35134" y2="381.36582" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient3334" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4268666,0,0,2.3426521,-15.816734,-109.09188)" x1="588.89265" y1="195.07545" x2="612.58524" y2="202.90803" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient3344" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.2017735,0,0,0.8321036,-15.816734,-109.09188)" x1="503.37662" y1="709.5851" x2="511.95083" y2="774.66748" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient969" id="radialGradient3347" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0227134,0,0,0.977791,-15.816734,-109.09188)" cx="553.9061" cy="548.65722" fx="553.9061" fy="548.65722" r="117.12444" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient969" id="linearGradient3350" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.1837429,0,5.9686051e-2,0.2004968,423.15227,384.61312)" x1="104.707" y1="264.74155" x2="133.43179" y2="619.09318" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="linearGradient3383" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.6468933,0,0,0.6072039,-15.816734,-109.09188)" x1="299.8437" y1="1036.9841" x2="305.62924" y2="1092.2429" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient684" id="linearGradient3389" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.6468933,0,0,0.6072039,-15.816734,-109.09188)" x1="231.07885" y1="1040.2823" x2="241.74594" y2="1092.1133" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient684" id="linearGradient3398" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0665122,0,0,0.9376353,-18.544492,-118.77326)" x1="614.02868" y1="1168.7988" x2="672.80902" y2="1295.4267" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1155" id="linearGradient3408" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.9878798,0,0,1.0122689,-15.816734,-109.09188)" x1="374.14027" y1="749.49296" x2="396.35611" y2="807.75935" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1155" id="linearGradient3414" gradientUnits="userSpaceOnUse" gradientTransform="matrix(4.2446192,0,0,4.0663556,128.08437,-388.78408)" x1="39.904693" y1="205.22107" x2="28.554472" y2="212.26643" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1563" id="linearGradient3417" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.9763285,0,0,1.0242454,-15.816734,-109.09188)" x1="265.95663" y1="735.08612" x2="313.4116" y2="761.44375" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient594" id="linearGradient3429" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.7771299,0,0,1.2867861,-15.816734,-109.09188)" x1="331.69558" y1="519.82318" x2="377.3627" y2="537.58599" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient684" id="linearGradient3434" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.1943011,0,0,0.2226133,460.10717,364.77942)" x1="-16.929597" y1="255.77006" x2="166.53211" y2="767.53721" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient4441" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,0.4268666,-2.3426521,0,866.43476,213.19778)" x1="636.48645" y1="194.28539" x2="682.59552" y2="198.65256" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1563" id="linearGradient6399" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.9763285,0,0,1.0110532,-335.13691,-86.646504)" x1="265.95663" y1="735.08612" x2="313.4116" y2="761.44375" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="linearGradient6401" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.6468933,0,0,0.6072039,-334.85916,-96.63329)" x1="169.59108" y1="1212.3388" x2="175.37662" y2="1267.5976" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient1547" id="radialGradient6403" gradientUnits="userSpaceOnUse" cx="289.25905" cy="812.97649" fx="289.25905" fy="812.97649" r="16.96986" /> <filter inkscape:collect="always" x="-0.13659227" width="1.2731845" y="-0.19308964" height="1.3861793" id="filter3825"> <feGaussianBlur inkscape:collect="always" stdDeviation="2.9455487" id="feGaussianBlur3827" /> </filter> <filter inkscape:collect="always" id="filter3995"> <feGaussianBlur inkscape:collect="always" stdDeviation="0.81463544" id="feGaussianBlur3997" /> </filter> <filter inkscape:collect="always" id="filter4043"> <feGaussianBlur inkscape:collect="always" stdDeviation="1.3482482" id="feGaussianBlur4045" /> </filter> <linearGradient inkscape:collect="always" xlink:href="#linearGradient671" id="linearGradient4653" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4268666,0,0,2.3426521,-523.80121,11.023625)" x1="833.72519" y1="196.49355" x2="857.41778" y2="204.32614" /> <filter inkscape:collect="always" id="filter3943"> <feGaussianBlur inkscape:collect="always" stdDeviation="0.75213628" id="feGaussianBlur3945" /> </filter> <filter inkscape:collect="always" id="filter3996"> <feGaussianBlur inkscape:collect="always" stdDeviation="0.65992794" id="feGaussianBlur3998" /> </filter> <linearGradient inkscape:collect="always" xlink:href="#linearGradient17937" id="linearGradient2702" gradientUnits="userSpaceOnUse" x1="7.0675211" y1="508.37253" x2="10.845769" y2="525.86481" /> </defs> <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" gridtolerance="10000" guidetolerance="10" objecttolerance="10" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.67332995" inkscape:cx="393.47267" inkscape:cy="497.65096" inkscape:document-units="px" inkscape:current-layer="layer1" inkscape:window-width="1280" inkscape:window-height="778" inkscape:window-x="0" inkscape:window-y="0" showgrid="false" /> <metadata id="metadata7"> <rdf:RDF> <cc:Work rdf:about=""> <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> </cc:Work> </rdf:RDF> </metadata> <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1"> <rect style="opacity:1;fill:none;fill-opacity:0;fill-rule:evenodd;stroke:#0000c0;stroke-width:2.65549850000000020;stroke-linecap:square;stroke-linejoin:bevel;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="rect2766" width="94.651901" height="94.651901" x="782.50494" y="193.76978" ry="11.064577" inkscape:export-filename="C:\pas\mricron\btn\render.png" inkscape:export-xdpi="59.193832" inkscape:export-ydpi="59.193832" /> <rect style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:2.375" id="rect1295" width="69.96357" height="45.246185" x="-85.942757" y="400.73502" transform="scale(-1,1)" /> <rect style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.375" id="rect1262" width="69.96357" height="45.246185" x="21.639284" y="525.50854" /> <path sodipodi:type="arc" style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="path1286" sodipodi:cx="88.389725" sodipodi:cy="698.28027" sodipodi:rx="18.305565" sodipodi:ry="18.305565" d="M 106.69529 698.28027 A 18.305565 18.305565 0 1 1 70.08416,698.28027 A 18.305565 18.305565 0 1 1 106.69529 698.28027 z" transform="translate(-33.076264,-148.31812)" /> <path sodipodi:type="arc" style="fill-rule:evenodd;stroke-width:1pt" id="path1573" sodipodi:cx="496.47308" sodipodi:cy="894.01904" sodipodi:rx="26.54307" sodipodi:ry="26.54307" d="M 523.01615 894.01904 A 26.54307 26.54307 0 1 1 469.93001,894.01904 A 26.54307 26.54307 0 1 1 523.01615 894.01904 z" transform="translate(169.72327,-322.09028)" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.03751945" d="M 688.66818,306.24904 C 678.75656,308.71686 672.13642,319.35864 669.10861,325.77005 C 666.0808,331.91994 662.11261,338.19726 672.83358,343.64006 C 683.06094,344.90951 689.88793,344.55574 695.32226,341.02776 C 702.63141,336.49383 708.44273,330.79097 710.67282,325.51602 C 712.12925,322.67835 725.26533,323.27838 724.39866,321.28638 C 724.51641,317.76588 723.82071,310.17565 715.84197,305.89899 C 711.53579,303.19828 694.46237,303.06487 688.66818,306.24904 z " id="path1377" sodipodi:nodetypes="czcccccc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-dasharray:none" d="M 159.34746,204.18441 C 154.78112,203.72655 145.72305,209.5377 141.75371,211.93441 C 130.90513,218.48492 120.06623,234.83944 120.06621,251.21566 C 120.06621,255.30973 116.62248,258.91345 121.53496,271.71566 C 127.57858,282.72641 154.25286,286.16074 154.47246,279.37191 C 154.69205,272.58309 150.38113,275.95666 155.69121,270.77816 C 155.85327,280.80632 159.30712,280.98431 159.15996,286.90316 C 159.06579,290.42991 158.87433,298.31471 160.22246,296.96566 L 162.15996,297.27816 L 162.15996,297.40316 L 162.53496,297.34066 L 164.47246,297.02816 C 165.82059,298.37721 165.62913,290.4924 165.53496,286.96566 C 165.3878,281.04681 168.84165,280.86881 169.00371,270.84066 C 174.31379,276.01916 170.00287,272.64558 170.22246,279.43441 C 170.44206,286.22324 197.11634,282.7889 203.15996,271.77816 C 208.07244,258.97595 204.62871,255.37222 204.62871,251.27816 C 204.62869,234.90194 193.78979,218.54741 182.94121,211.99691 C 178.97187,209.6002 169.9138,203.78904 165.34746,204.24691 C 163.82535,204.39953 162.7994,205.24568 162.62871,207.15316 L 161.82444,259.53543 L 162.06621,207.09066 C 161.89552,205.18319 160.86957,204.33703 159.34746,204.18441 z " id="path1150" sodipodi:nodetypes="ccccccccccccccccccccccc" /> <path style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.684129pt" d="M 166.96836,384.07012 C 155.31965,387.85507 120.86399,377.80538 120.12828,394.64187 C 119.39258,411.47837 208.78111,407.43239 196.64192,397.12167 C 184.50274,386.81094 178.61708,380.28517 166.96836,384.07012 z " id="path1140" sodipodi:nodetypes="cczz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:1.27241249pt" d="M 480.79352,206.34075 C 471.88604,206.34335 456.60096,213.45984 450.66045,218.80635 C 438.7794,229.49933 432.12374,257.332 432.12374,275.15365 C 432.12374,280.58581 432.13964,285.91498 432.36887,291.04434 L 527.02964,291.04434 C 527.27078,285.95977 527.31563,280.70645 527.31563,275.31137 C 527.31559,257.48975 523.65984,230.6354 511.75241,219.92163 C 505.7987,214.56474 489.701,206.33815 480.79352,206.34075 z " id="path1063" sodipodi:nodetypes="cccccccc" /> <path style="fill-rule:evenodd;stroke:none;stroke-width:0.91963024pt" d="M 327.16217,290.76838 L 418.91669,291.42091 L 417.53126,283.00336 C 416.25922,279.01899 411.91051,274.64424 411.06349,270.16638 C 409.77452,265.68852 415.98676,268.56598 415.23722,261.21141 C 414.48767,253.85683 413.08127,234.33246 402.45013,224.02417 C 391.50649,214.02838 382.36734,207.6119 362.97069,210.76309 C 344.82404,212.66428 334.41396,221.32768 327.0142,236.61225 C 319.42306,251.89682 327.82696,270.91537 327.58831,278.04243 L 327.16217,290.76838 z " id="path1052" sodipodi:nodetypes="ccczzzzzzc" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.99068832pt" d="M 304.47806,263.45874 C 304.47806,249.33467 295.28924,221.00412 286.18122,212.5132 C 277.07319,204.02228 258.91772,204.03875 249.8299,212.5132 C 240.74206,220.98765 231.65423,249.2358 231.65423,263.35988 C 231.65423,277.48396 240.74206,291.60803 249.8299,297.25767 C 258.91772,302.9073 277.07319,302.89082 286.18122,297.25767 C 295.28924,291.62451 304.47806,277.58282 304.47806,263.45874 z " id="path1005" sodipodi:nodetypes="czzzzzz" /> <path style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.90746355pt" d="M 269.52246,210.66588 C 269.40433,210.66585 269.2893,210.6935 269.17117,210.69488 L 269.17117,210.72388 C 269.08325,210.71596 268.99651,210.69484 268.90771,210.69488 C 268.70077,210.69495 268.49983,210.74848 268.29296,210.75288 L 268.29296,210.86887 C 268.16684,210.8522 268.04029,210.83991 267.9124,210.83987 C 267.82359,210.83984 267.73686,210.86095 267.64893,210.86887 L 267.64893,210.83987 C 267.53081,210.8385 267.41578,210.81084 267.29765,210.81087 C 261.07638,210.81276 254.84843,212.77489 250.69937,216.66845 C 248.62485,218.61522 236.75118,234.6709 240.74626,237.43095 C 250.68886,244.7044 259.30859,223.29341 250.11389,241.05569 C 249.1874,247.15673 248.94927,250.3379 248.88439,251.92991 C 248.75337,249.01354 247.66973,242.17332 241.97576,238.85185 C 237.2191,236.13422 234.1011,260.13945 234.1011,263.38408 C 234.1011,276.36263 242.40127,289.33642 250.69937,294.52784 C 254.9078,297.16071 261.25113,298.42446 267.56111,298.38456 L 267.56111,298.41356 C 267.88374,298.41621 268.20458,298.38868 268.52715,298.38456 L 268.52715,298.23957 C 268.77111,298.24891 269.01451,298.2706 269.259,298.26857 L 269.259,298.23957 C 275.56898,298.27947 281.91231,297.01574 286.12074,294.38285 C 294.41884,289.19143 302.71901,276.21763 302.71901,263.23909 C 302.71901,259.99446 299.601,235.98922 294.84435,238.70686 C 289.15038,242.02833 288.06674,248.86855 287.93572,251.78492 C 287.87084,250.19291 287.63271,247.01173 286.70621,240.9107 C 277.51152,223.14842 286.13125,244.5594 296.07385,237.28596 C 300.06893,234.52591 288.19526,218.47022 286.12074,216.52346 C 281.97168,212.6299 275.74373,210.66776 269.52246,210.66588 z " id="path1044" /> <path sodipodi:type="arc" style="font-size:12px;fill:#fffffd;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.875;stroke-dasharray:none" id="path695" sodipodi:cx="271.35837" sodipodi:cy="796.11926" sodipodi:rx="37.428738" sodipodi:ry="37.428738" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" transform="matrix(1.269231,0,0,1.209574,136.50927,-392.71098)" /> <path sodipodi:type="arc" style="font-size:12px;fill:url(#linearGradient1202);fill-opacity:0.75;fill-rule:evenodd;stroke:#0050fb;stroke-width:2.47292995;stroke-dasharray:none;stroke-opacity:1" id="path1200" sodipodi:cx="604.88873" sodipodi:cy="441.2019" sodipodi:rx="44.214264" sodipodi:ry="13.483783" d="M 649.103 441.2019 A 44.214264 13.483783 0 1 1 560.67447,441.2019 A 44.214264 13.483783 0 1 1 649.103 441.2019 z" transform="matrix(1.042553,0,0,0.882208,-45.319444,-61.74254)" /> <path style="font-size:12px;fill:url(#linearGradient3434);fill-opacity:0.70196001;stroke:#1c66f9;stroke-width:1.92428339;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.98999999" d="M 451.22048,423.00433 C 451.63246,421.80386 453.06823,420.60292 454.29922,420.78471 L 491.46953,428.8165 C 494.34845,426.28982 498.56281,423.21391 502.90683,423.98397 L 509.2225,424.86037 L 517.20354,426.42754 C 521.86269,427.8304 525.54468,430.74415 525.93077,436.54243 L 525.88183,506.39694 L 450.92735,482.50349 L 451.22048,423.00433 z " id="path10" sodipodi:nodetypes="cccccccccc" /> <rect style="font-size:12px;fill:none;fill-opacity:0.25;fill-rule:evenodd;stroke-width:0.0937284;stroke-opacity:0.53136998" id="rect1408" x="199.81725" y="208.79193" width="236.74754" height="236.68817" rx="0" ry="0" /> <rect style="font-size:12px;fill:none;fill-rule:evenodd;stroke-width:0.0520834" id="rect702" width="370.49606" height="374.81461" x="331.57504" y="372.21768" /> <path style="font-size:12px;fill:url(#linearGradient3429);fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:0.47846999pt" d="M 243.46953,613.59491 C 244.15833,611.87293 271.36555,520.95257 271.36555,520.95257 L 302.36113,608.77337 C 302.36113,608.77337 289.27411,618.07205 274.12072,618.07205 C 258.96732,620.13842 243.12514,613.59491 243.46953,613.59491 z " id="path593" sodipodi:nodetypes="ccccc" /> <polygon d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z " inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon597" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,154.95997,280.89042)" /> <polygon d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z " inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon598" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,146.00567,313.95242)" /> <polygon d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z " inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon599" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,162.53667,301.55422)" /> <polygon d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z " inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon600" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,160.81467,317.74072)" /> <polygon d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z " inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon601" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,146.69447,332.20542)" /> <polygon d="M 252.64399,586.6623 L 243.36685,584.41597 L 238.42227,592.58067 L 235.72908,583.42327 L 226.18595,583.22349 L 232.76989,576.31241 L 228.17135,567.94793 L 237.44848,570.19426 L 242.39307,562.02956 L 245.08626,571.18696 L 254.62939,571.38674 L 248.04545,578.29781 L 252.64399,586.6623 z " inkscape:randomized="0" inkscape:rounded="0" inkscape:flatsided="false" sodipodi:type="star" style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="polygon602" sodipodi:sides="6" sodipodi:cx="240.40767" sodipodi:cy="577.30511" sodipodi:r1="15.404038" sodipodi:r2="7.7020192" sodipodi:arg1="0.65284663" sodipodi:arg2="1.1764454" points="252.644,586.662 243.367,584.416 238.422,592.581 235.729,583.423 226.186,583.223 232.77,576.312 228.171,567.948 237.448,570.194 242.393,562.03 245.086,571.187 254.629,571.387 248.045,578.298 252.644,586.662 " transform="matrix(0.478471,0,0,0.478471,170.11337,329.45022)" /> <path style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 258.30044,566.33574 C 256.77333,571.42599 256.69309,571.65611 255.16047,576.75743 L 256.29684,580.6151 L 258.67424,576.71257 L 263.1001,577.78913 L 260.90212,573.78194 L 264.05704,570.4775 L 259.49661,570.38778 L 258.30044,566.33574 z " id="path605" /> <path style="font-size:12px;fill:#ffff00;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 276.34738,535.18557 L 275.12129,537.18917 L 270.68049,536.11261 L 272.87846,540.1198 L 269.7385,543.42424 L 274.29892,543.51396 L 275.58481,547.89495 L 277.96221,543.99243 L 279.59201,544.39614 L 276.34738,535.18557 z " id="path608" /> <path sodipodi:type="arc" style="font-size:12px;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.875;stroke-dasharray:none" id="path651" sodipodi:cx="271.35837" sodipodi:cy="796.11926" sodipodi:rx="37.428738" sodipodi:ry="37.428738" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" transform="matrix(1.269231,0,0,1.209574,-77.374024,-285.94088)" /> <path style="font-size:12px;fill:url(#linearGradient3417);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-opacity:1" d="M 279.87479,633.93985 L 279.87479,666.67394 L 255.83873,666.67394 L 255.83873,656.16576 C 255.83873,656.16576 255.85783,656.13497 231.44571,676.76631 L 255.32311,696.19509 L 255.32311,686.4807 L 279.87479,686.4807 L 279.87479,720.19756 C 299.3849,714.56487 313.66805,697.45517 313.66806,677.03091 C 313.66807,656.6106 299.37907,639.57596 279.87479,633.93985 z " id="path669" /> <path style="font-size:12px;fill:url(#linearGradient3414);fill-rule:evenodd;stroke:#000000;stroke-width:2.78715038;stroke-linejoin:round" d="M 283.95579,490.94075 C 290.66581,489.39661 295.57028,485.44504 300.07353,481.09224 C 304.17555,476.47196 308.27756,470.24678 309.77159,464.0216 L 276.03686,421.84097 L 237.48736,460.81175 L 283.95579,490.94075 z " id="path709" sodipodi:nodetypes="cccccc" /> <path sodipodi:type="arc" style="font-size:12px;fill:#f5f9ff;fill-rule:evenodd;stroke:#000000;stroke-width:10.78610039" id="path587" sodipodi:cx="220.25374" sodipodi:cy="529.07959" sodipodi:rx="44.626575" sodipodi:ry="78.456398" d="M 264.88031 529.07959 A 44.626575 78.456398 0 1 1 175.62716,529.07959 A 44.626575 78.456398 0 1 1 264.88031 529.07959 z" transform="matrix(0.26113,0,-0.220403,0.255703,314.80207,305.48132)" /> <path style="font-size:12px;fill:#ff0000;fill-rule:evenodd;stroke-width:1pt" d="M 243.66732,455.91895 C 207.99046,453.53473 230.86297,486.36929 231.18432,489.05618 C 231.50609,491.74307 212.45436,496.31199 220.47004,505.98065 C 233.70212,515.64935 294.73252,518.87157 293.74202,503.71551 C 292.75152,488.55528 244.41991,492.90854 233.95854,488.90274 C 230.5101,479.45166 230.06347,464.3735 235.28957,459.88088 C 238.35009,457.8818 237.91425,463.35185 243.66732,455.91895 z " id="path711" sodipodi:nodetypes="cccccsc" /> <path style="font-size:12px;fill:#ff0000;fill-rule:evenodd;stroke-width:10.78610039" d="M 271.24683,425.72263 C 265.99009,425.72263 255.39114,433.36371 247.59081,442.77656 C 241.16254,450.53372 238.64291,457.0772 240.89292,459.14242 C 247.83823,456.92466 258.29806,449.12547 266.36059,439.77166 C 270.03525,435.50847 272.64634,431.56918 274.1298,428.31817 C 274.02196,426.68582 273.09418,425.72263 271.24683,425.72263 z " id="path592" /> <rect style="font-size:12px;fill:url(#linearGradient3408);fill-opacity:1;fill-rule:evenodd;stroke:#000002;stroke-width:1.94391274" id="rect642" width="71.98143" height="73.806519" x="339.74475" y="642.47302" /> <path style="font-size:12px;fill-rule:evenodd;stroke:#000002;stroke-width:1.94391274" d="M 340.05239,659.32645 L 340.05239,715.98893 L 410.49575,715.98893 L 405.88157,712.7926 C 397.37094,706.98105 399.88311,699.28077 390.1933,700.00721 C 380.81111,700.1525 356.62253,712.80034 352.52102,705.43907 C 347.64017,698.79476 349.20267,643.90267 345.30441,650.4736 L 340.05239,659.32645 z " id="path640" sodipodi:nodetypes="cccczcsc" /> <rect style="font-size:12px;fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:4.10281944" id="rect615" width="57.240681" height="49.173893" x="496.88156" y="922.24396" transform="matrix(0.8593708,-0.5113529,0,1,0,0)" /> <text xml:space="preserve" style="font-size:34.43291092px;font-weight:bold;line-height:100%;fill:#000000;fill-opacity:1;stroke-width:1pt;font-family:Verdana" x="487.49341" y="857.62598" id="text610" sodipodi:linespacing="100%" transform="matrix(0.8820213,-0.5398853,0,1.1337595,0,0)"><tspan x="487.49341" y="857.62598" sodipodi:role="line" id="tspan613" style="fill:#000000;fill-opacity:1">LR</tspan></text> <rect style="font-size:12px;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:4.12392521" id="rect627" width="57.83112" height="49.173893" x="-614.36664" y="357.21173" transform="matrix(-0.8624565,-0.5061313,0,1,0,0)" /> <text xml:space="preserve" style="font-size:34.43291092px;font-weight:bold;line-height:100%;stroke-width:1pt;font-family:Verdana" x="-598.04327" y="340.37064" id="text628" sodipodi:linespacing="100%" transform="matrix(-0.8820213,-0.5398853,0,1.1337595,0,0)"><tspan x="-598.04327" y="340.37064" sodipodi:role="line" id="tspan629">LR</tspan></text> <rect style="font-size:12px;fill:url(#linearGradient3398);fill-rule:evenodd;stroke:#000000;stroke-width:0.77675009pt" id="rect648" width="56.066242" height="49.173893" x="630.58124" y="997.7973" transform="matrix(0.8529074,-0.5220622,0,1,0,0)" /> <rect style="font-size:12px;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:0.77675009pt" id="rect649" width="56.066242" height="49.173893" x="-742.98041" y="280.71118" transform="matrix(-0.8529074,-0.5220622,0,1,0,0)" /> <path style="font-size:12px;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.40036964;stroke-opacity:1" d="M 570.21281,672.11203 C 560.80527,687.5177 551.81276,684.49603 553.40375,698.74281 C 555.96315,704.40234 562.05038,691.50316 576.02334,688.32276 C 581.55718,684.47094 584.49704,676.2781 577.47598,661.60195 C 569.00228,647.92063 548.83833,666.49034 544.68794,681.59092 C 540.53755,696.36586 547.93908,698.22084 553.19623,696.88453" id="path646" sodipodi:nodetypes="ccczzc" /> <path style="font-size:12px;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:2.40036964" d="M 602.22003,673.33419 C 611.62757,688.73986 620.62007,685.71819 619.02909,699.96497 C 616.46969,705.6245 610.38245,692.72532 596.4095,689.54492 C 590.87565,685.6931 587.93579,677.50026 594.95686,662.82411 C 603.43056,649.14279 623.59451,667.71251 627.7449,682.81308 C 631.89528,697.58802 624.49376,699.443 619.23661,698.10669" id="path650" sodipodi:nodetypes="ccczzc" /> <path sodipodi:type="arc" style="font-size:12px;fill:url(#radialGradient1158);fill-rule:evenodd;stroke:#000000;stroke-width:1pt" id="path1411" d="M 69.375 165 A 4.375 4.375 0 1 1 60.625,165 A 4.375 4.375 0 1 1 69.375 165 z" sodipodi:cx="65" sodipodi:cy="165" sodipodi:rx="4.375" sodipodi:ry="4.375" transform="matrix(6.282797,0,0,6.282797,-52.398774,-588.87818)" /> <path style="font-size:12px;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:15.70698166;stroke-linecap:round;stroke-linejoin:round" d="M 379.53347,471.34372 L 410.94745,502.75771" id="path1413" sodipodi:nodetypes="cc" /> <path sodipodi:type="arc" style="font-size:12px;fill:url(#radialGradient1203);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.87644994;stroke-dasharray:none" id="path682" sodipodi:cx="271.35837" sodipodi:cy="796.11926" sodipodi:rx="37.428738" sodipodi:ry="37.428738" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" transform="matrix(1.269231,0,0,1.209574,30.443296,-392.69368)" /> <path style="font-size:12px;fill:url(#linearGradient3389);fill-opacity:0.38016998;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 374.84848,524.63047 C 355.62378,524.63047 339.1694,535.61346 331.69463,551.27888 C 337.6128,554.31083 344.21798,557.18303 352.00233,555.0966 C 366.61946,551.90429 371.18895,544.3788 378.49751,541.18651 C 393.81739,540.61396 401.15447,548.4841 416.25714,548.14156 C 408.15968,534.19151 392.75046,524.63048 374.84848,524.63047 z " id="path687" /> <text xml:space="preserve" style="font-size:112.55771637px;font-style:normal;font-weight:bold;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Palatino Linotype" x="286.69199" y="741.06946" id="text688" sodipodi:linespacing="100%" transform="scale(1.2282659,0.814156)"><tspan x="286.69199" y="741.06946" sodipodi:role="line" id="tspan693">i</tspan></text> <path style="font-size:12px;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 480.51446,524.13119 L 480.51446,616.87976 C 507.96173,616.87976 530.23181,596.12414 530.23178,570.52148 C 530.23178,544.91881 507.96171,524.13117 480.51446,524.13119 z " id="path700" /> <path style="font-size:12px;fill:url(#linearGradient3383);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 480.95072,524.13207 C 461.72602,524.13207 445.27164,535.11506 437.79687,550.78048 C 443.71504,553.81243 450.32022,556.68463 458.10457,554.5982 C 472.7217,551.40589 477.29119,543.8804 484.59975,540.68811 C 499.91963,540.11556 507.25671,547.9857 522.35938,547.64316 C 514.26192,533.69311 498.8527,524.13208 480.95072,524.13207 z " id="path697" /> <g id="g708" transform="matrix(1.26275,0,0,1.26275,-87.529244,-290.57418)"> <rect style="font-size:12px;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="rect705" width="15.909903" height="6.6291261" x="557.73047" y="679.8053" ry="3.314563" /> <rect style="font-size:12px;fill:url(#linearGradient3036);fill-rule:evenodd;stroke-width:1pt" id="rect706" width="12.472398" height="1.377152" x="559.37109" y="680.06189" ry="0.68857598" rx="1.6909561" /> </g> <g id="g711" transform="matrix(1.26275,0,0,1.26275,-5.494134,-290.85318)"> <rect style="font-size:12px;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="rect712" width="15.909903" height="6.6291261" x="557.73047" y="679.8053" ry="3.314563" /> <rect style="font-size:12px;fill:url(#linearGradient3038);fill-rule:evenodd;stroke-width:1pt" id="rect713" width="12.472398" height="1.377152" x="559.37109" y="680.06189" ry="0.68857598" rx="1.6909561" /> </g> <g id="g721" transform="matrix(0.878674,-0.906901,0.906901,0.878674,-476.65103,514.65082)" style="font-size:12px"> <g id="g722"> <rect style="font-size:12px;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="rect723" width="15.909903" height="6.6291261" x="557.73047" y="679.8053" ry="3.314563" /> <rect style="font-size:12px;fill:url(#linearGradient3040);fill-rule:evenodd;stroke-width:1pt" id="rect724" width="12.472398" height="1.377152" x="559.37109" y="680.06189" ry="0.68857598" rx="1.6909561" /> </g> <g id="g725" transform="translate(64.96544,-0.220965)"> <rect style="font-size:12px;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="rect726" width="15.909903" height="6.6291261" x="557.73047" y="679.8053" ry="3.314563" /> <rect style="font-size:12px;fill:url(#linearGradient3042);fill-rule:evenodd;stroke-width:1pt" id="rect727" width="12.472398" height="1.377152" x="559.37109" y="680.06189" ry="0.68857598" rx="1.6909561" /> </g> </g> <g id="g728" transform="matrix(1.073491e-5,-1.26275,1.26275,1.073491e-5,-194.38993,1328.4811)" style="font-size:12px"> <g id="g729"> <rect style="font-size:12px;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="rect730" width="15.909903" height="6.6291261" x="557.73047" y="679.8053" ry="3.314563" /> <rect style="font-size:12px;fill:url(#linearGradient3044);fill-rule:evenodd;stroke-width:1pt" id="rect731" width="12.472398" height="1.377152" x="559.37109" y="680.06189" ry="0.68857598" rx="1.6909561" /> </g> <g id="g732" transform="translate(64.96544,-0.220965)"> <rect style="font-size:12px;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="rect733" width="15.909903" height="6.6291261" x="557.73047" y="679.8053" ry="3.314563" /> <rect style="font-size:12px;fill:url(#linearGradient3046);fill-rule:evenodd;stroke-width:1pt" id="rect734" width="12.472398" height="1.377152" x="559.37109" y="680.06189" ry="0.68857598" rx="1.6909561" /> </g> </g> <g id="g735" transform="matrix(0.893911,0.891887,-0.891887,0.893911,742.82387,-571.45388)" style="font-size:12px"> <g id="g736"> <rect style="font-size:12px;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="rect737" width="15.909903" height="6.6291261" x="557.73047" y="679.8053" ry="3.314563" /> <rect style="font-size:12px;fill:url(#linearGradient3048);fill-rule:evenodd;stroke-width:1pt" id="rect738" width="12.472398" height="1.377152" x="559.37109" y="680.06189" ry="0.68857598" rx="1.6909561" /> </g> <g id="g739" transform="translate(64.96544,-0.220965)"> <rect style="font-size:12px;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="rect740" width="15.909903" height="6.6291261" x="557.73047" y="679.8053" ry="3.314563" /> <rect style="font-size:12px;fill:url(#linearGradient703);fill-rule:evenodd;stroke-width:1pt" id="rect741" width="12.472398" height="1.377152" x="559.37109" y="680.06189" ry="0.68857598" rx="1.6909561" /> </g> </g> <path style="font-size:12px;fill:#e6e6e6;fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 667.99564,543.421 C 656.0175,543.421 645.76543,551.32164 641.1082,562.5906 C 644.79557,564.77164 648.911,566.83777 653.76112,565.33689 C 662.86847,563.04049 665.71554,557.62701 670.26921,555.33063 C 679.81441,554.91877 684.38586,560.58017 693.79572,560.33376 C 688.75052,550.29876 679.14965,543.42101 667.99564,543.421 z " id="path801" /> <path style="fill:#fb4100;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 460.52441,445.57716 C 468.10439,423.92273 481.1518,440.77221 490.71993,441.73323 C 499.04543,441.25268 499.91528,415.30612 515.69646,419.63058 C 523.02791,422.19321 521.03972,439.65107 519.7971,448.94061 C 519.67286,459.51141 521.0452,471.61968 510.4775,480.65309 C 495.68969,492.81335 452.94442,466.75105 460.52441,445.57716 z " id="path760" sodipodi:nodetypes="ccccsz" /> <path style="font-size:12px;fill:#4789f7;fill-opacity:1;stroke:#1c4ed9;stroke-width:1.71254337;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99216003" d="M 450.82856,482.20291 L 526.04844,506.43293 L 523.28751,511.48629 L 448.52721,485.77118 L 450.82856,482.20291 z " id="path279" sodipodi:nodetypes="ccccc" /> <path style="font-size:12px;fill:url(#linearGradient3350);fill-opacity:0.69930001;stroke:#1c66fb;stroke-width:1.77588487;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99216003" d="M 430.83685,438.74362 C 429.82395,436.0564 430.81654,433.49264 433.23265,433.76555 L 468.97638,441.37169 L 471.18114,449.11568 L 486.78016,452.74293 L 484.50444,444.58967 L 500.58846,447.3442 C 502.71461,448.03584 504.36603,449.4673 505.87346,452.74895 L 522.77231,510.83334 L 448.41172,485.62951 L 430.83685,438.74362 z " id="path208" sodipodi:nodetypes="ccccccccccc" /> <path style="font-size:12px;fill:url(#radialGradient3347);fill-opacity:0.98999999;stroke:#0c1dfb;stroke-width:2.6319499;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.98999999" d="M 541.55553,431.15809 C 541.23051,427.38586 543.9104,423.50523 547.47412,423.0305 L 628.10196,423.45855 C 631.03285,423.73768 632.90302,425.33481 633.71274,429.8412 L 633.64214,503.32951 L 625.40507,510.69938 L 549.02921,511.04966 L 541.57579,502.95071 L 541.55553,431.15809 z " id="path1131" sodipodi:nodetypes="ccccccccc" /> <path style="font-size:12px;fill:url(#linearGradient3344);fill-opacity:0.69930001;stroke:#1c2942;stroke-width:2.28141999;stroke-opacity:0.99216003" d="M 566.84522,480.70051 L 611.32692,480.71086 L 611.71099,511.23534 L 566.54489,511.27158 L 566.84522,480.70051 z " id="path230" sodipodi:nodetypes="ccccc" /> <path style="font-size:12px;fill:#ffffff;fill-opacity:0.99216003;stroke:#1c2942;stroke-width:1.10123003;stroke-opacity:0.99216003" d="M 552.22632,436.30828 L 546.45836,436.08807 L 546.4485,430.05365 L 552.20989,429.99665 L 552.22632,436.30828 z " id="path313" sodipodi:nodetypes="ccccc" /> <path style="font-size:12px;fill:#fffffd;fill-opacity:1;stroke:#0c5cff;stroke-width:2.20247006;stroke-opacity:0.99216003" d="M 556.74217,423.78409 L 619.61682,423.79651 L 620.1597,469.68309 L 556.31765,469.72689 L 556.74217,423.78409 z " id="path412" sodipodi:nodetypes="ccccc" /> <path style="font-size:12px;fill:#1c2942;fill-opacity:0.99215698;stroke-width:8.96854973" d="M 584.87523,506.21798 L 574.38649,506.43578 L 574.36787,484.62813 L 584.84421,484.83956 L 584.87523,506.21798 z " id="path415" sodipodi:nodetypes="ccccc" /> <path style="font-size:12px;fill:#ffffff;fill-opacity:0.99216003;stroke:#1c2942;stroke-width:1.10123003;stroke-opacity:0.99216003" d="M 629.5978,435.86357 L 623.82984,435.64335 L 623.81998,429.60893 L 629.58137,429.55194 L 629.5978,435.86357 z " id="path420" sodipodi:nodetypes="ccccc" /> <path style="fill:#fb4100;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 560.37851,442.56322 C 567.2077,429.26412 578.96275,439.61227 587.58316,440.20245 C 595.08402,439.90736 595.86769,423.97222 610.08576,426.62808 C 616.69101,428.20192 614.90468,458.5573 605.38373,464.10516 C 592.06066,471.57343 553.54931,455.56721 560.37851,442.56322 z " id="path1137" sodipodi:nodetypes="cccsz" /> <path style="fill:#000048;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 258.87077,308.5828 C 253.08731,317.00199 248.84661,323.41806 244.02038,334.46537 C 239.19415,345.89492 233.86557,374.16335 237.62514,378.80842 C 241.38471,383.45348 246.87367,380.38573 250.63323,376.271 C 254.3928,372.15627 252.48835,351.21953 253.67461,342.10614 C 254.54837,332.99275 256.89282,323.55354 258.87077,308.5828 z " id="path1163" sodipodi:nodetypes="czzzzc" /> <path style="fill:url(#linearGradient3334);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 244.87703,341.05538 C 243.47705,345.15846 241.84536,347.98072 240.67709,353.3646 C 239.50883,358.93477 237.84073,372.71133 238.75079,374.97509 C 239.66086,377.23885 240.98955,375.74379 241.89961,373.73848 C 242.80967,371.73318 242.34867,361.52971 242.63582,357.08832 C 242.84733,352.64692 244.39824,348.35134 244.87703,341.05538 z " id="path1164" sodipodi:nodetypes="czzzzc" /> <path style="font-size:12px;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt" d="M 246.84696,401.26635 C 233.22657,397.6892 232.27442,390.28556 235.78589,385.29279 C 237.10987,383.89377 240.22335,381.74991 242.03082,381.87983 C 243.83829,382.00976 245.39652,382.92548 247.71778,384.58791 C 252.98531,388.53776 243.05535,390.25329 246.84696,401.26635 z " id="path1165" sodipodi:nodetypes="ccszc" /> <path style="font-size:12px;fill:url(#linearGradient3330);fill-rule:evenodd;stroke-width:1pt" d="M 242.39644,396.66561 C 239.13849,395.84397 237.60423,396.00137 235.59134,391.07571 C 233.57845,386.46255 238.58293,384.94683 239.17721,384.32111 C 239.77149,383.69538 240.63913,384.10863 241.23341,384.66292 C 241.82769,385.2172 241.52665,388.03755 241.71416,389.26519 C 241.85228,390.49284 239.58379,392.61768 242.39644,396.66561 z " id="path1166" sodipodi:nodetypes="czzzzc" /> <path style="fill:#ff0000;fill-opacity:0.75;fill-rule:nonzero;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path1178" d="M 314.57982,354.70876 C 315.40432,361.53904 292.43811,370.44146 291.51251,374.36944 C 289.61042,378.70993 304.49355,389.01441 300.45951,394.15556 C 297.88336,401.90543 258.15216,405.84922 248.90859,403.44343 C 247.75479,402.05103 247.55467,398.86418 249.66772,396.95909 C 255.30743,393.65166 283.03666,396.48065 292.19312,391.50374 C 292.99642,389.41248 282.49481,378.89188 285.71585,373.32683 C 289.0931,366.46975 309.78135,359.31112 309.46479,355.27714 C 306.48475,350.72496 283.39899,343.56241 280.66089,339.63205 C 280.66089,339.63205 310.68949,348.99124 314.57982,354.70876 z " sodipodi:nodetypes="cccccccccc" /> <path style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 363.38161,311.90492 C 357.59815,320.32411 353.35745,326.74018 348.53122,337.78749 C 343.70499,349.21704 338.37641,377.48547 342.13598,382.13054 C 345.89555,386.7756 351.38451,383.70785 355.14407,379.59312 C 358.90364,375.47839 356.99919,354.54165 358.18545,345.42826 C 359.05921,336.31487 361.40366,326.87566 363.38161,311.90492 z " id="path1183" sodipodi:nodetypes="czzzzc" /> <path style="fill:url(#linearGradient3325);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 349.38787,344.3775 C 347.98789,348.48058 346.3562,351.30284 345.18793,356.68672 C 344.01967,362.25689 342.35157,376.03345 343.26163,378.29721 C 344.1717,380.56097 345.50039,379.06591 346.41045,377.0606 C 347.32051,375.0553 346.85951,364.85183 347.14666,360.41044 C 347.35817,355.96904 348.90908,351.67346 349.38787,344.3775 z " id="path1184" sodipodi:nodetypes="czzzzc" /> <path style="font-size:12px;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt" d="M 351.3578,404.58847 C 337.73741,401.01132 336.78526,393.60768 340.29673,388.61491 C 341.62071,387.21589 344.73419,385.07203 346.54166,385.20195 C 348.34913,385.33188 349.90736,386.2476 352.22862,387.91003 C 357.49615,391.85988 347.56619,393.57541 351.3578,404.58847 z " id="path1185" sodipodi:nodetypes="ccszc" /> <path style="font-size:12px;fill:url(#linearGradient3321);fill-rule:evenodd;stroke-width:1pt" d="M 346.90728,399.98773 C 343.64933,399.16609 342.11507,399.32349 340.10218,394.39783 C 338.08929,389.78467 343.09377,388.26895 343.68805,387.64323 C 344.28233,387.0175 345.14997,387.43075 345.74425,387.98504 C 346.33853,388.53932 346.03749,391.35967 346.225,392.58731 C 346.36312,393.81496 344.09463,395.9398 346.90728,399.98773 z " id="path1186" sodipodi:nodetypes="czzzzc" /> <path style="fill:#ff0000;fill-opacity:0.75;fill-rule:nonzero;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path1187" d="M 419.09066,358.03088 C 419.91516,364.86116 396.94895,373.76358 396.02335,377.69156 C 394.12126,382.03205 409.00439,392.33653 404.97035,397.47768 C 402.3942,405.22755 362.663,409.17134 353.41943,406.76555 C 352.26563,405.37315 352.06551,402.1863 354.17856,400.28121 C 359.81827,396.97378 387.5475,399.80277 396.70396,394.82586 C 397.50726,392.7346 387.00565,382.214 390.22669,376.64895 C 393.60394,369.79187 414.29219,362.63324 413.97563,358.59926 C 410.99559,354.04708 387.90983,346.88453 385.17173,342.95417 C 385.17173,342.95417 415.20033,352.31336 419.09066,358.03088 z " sodipodi:nodetypes="cccccccccc" /> <path style="font-size:12px;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#00de00;stroke-width:3.88089991;stroke-linecap:round;stroke-dasharray:7.76179, 7.76179;stroke-dashoffset:0" d="M 385.46637,349.3006 L 352.76267,401.22876" id="path1189" /> <path style="fill:#fb4100;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 545.83421,339.00725 C 555.29835,316.61255 571.58891,334.03807 583.53539,335.03189 C 593.93035,334.53499 595.01639,307.70136 614.7203,312.17365 C 623.87409,314.82388 621.39853,365.94011 608.20406,375.28229 C 589.74047,387.85833 536.37006,360.90501 545.83421,339.00725 z " id="path1196" sodipodi:nodetypes="cccsz" /> <path style="font-size:12px;fill:url(#radialGradient3315);fill-opacity:0.98999999;stroke:#0c1dfb;stroke-width:2.47207999;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.98999999" d="M 539.55742,329.86065 C 550.20758,338.42827 575.36536,339.08326 588.74955,339.28881 C 602.13373,339.49436 625.26054,336.61881 631.71463,328.69888 L 623.40696,400.03263 C 612.55911,405.15586 600.77053,408.29651 587.10049,407.93305 C 573.43045,407.5696 556.31107,405.36188 547.0311,400.34165 L 539.55742,329.86065 z " id="path1199" sodipodi:nodetypes="czcczcc" /> <rect style="font-size:12px;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" id="rect983" width="106.29922" height="106.29922" x="213.87325" y="199.80083" /> <rect style="font-size:12px;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" id="rect984" width="106.29922" height="106.29922" x="320.17245" y="199.80083" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.90746355pt" d="M 264.13607,237.58254 C 264.4776,236.89576 263.55204,229.45502 262.13713,227.53203 C 260.72222,225.60904 258.62283,226.45669 258.2813,227.14347 C 257.93978,227.83025 260.05101,226.91589 261.46591,228.83888 C 262.88082,230.76186 263.79455,238.26932 264.13607,237.58254 z " id="path1018" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.76453004pt" d="M 257.8175,276.31726 C 254.83735,276.02984 254.24158,269.14348 252.17246,273.34443 C 250.0083,277.62047 254.46823,286.78993 254.86058,282.05056 C 255.15788,277.31121 260.70261,276.67975 257.8175,276.31726 z " id="path1019" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.90746355pt" d="M 272.68404,237.44007 C 272.34251,236.75328 273.26807,229.31254 274.68298,227.38956 C 276.09788,225.46656 278.19728,226.31421 278.53881,227.00099 C 278.88033,227.68778 276.7691,226.77342 275.3542,228.6964 C 273.93929,230.61939 273.02556,238.12685 272.68404,237.44007 z " id="path1036" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.76453004pt" d="M 279.00261,276.17479 C 281.98276,275.88737 282.57853,269.001 284.64765,273.20196 C 286.81181,277.478 282.35188,286.64746 281.95953,281.90809 C 281.66223,277.16873 276.1175,276.53728 279.00261,276.17479 z " id="path1037" sodipodi:nodetypes="czzz" /> <path style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.0507082pt" d="M 393.41778,249.75479 C 392.73276,254.42899 380.4132,251.97901 380.21857,259.67332 C 380.02394,266.86846 395.82989,268.28032 401.73513,266.16252 C 407.64038,264.04472 411.50934,260.75037 410.89844,253.45574 C 410.28756,246.16111 408.32593,227.80632 386.76522,217.28135 C 365.63646,207.25555 341.70568,220.92063 334.05688,235.52111 C 326.40807,250.62079 325.79982,265.91294 334.87103,260.42208 C 343.51028,255.43037 354.05149,239.69352 369.86419,237.87506 C 385.2449,236.05659 394.10277,246.07893 393.41778,249.75479 z " id="path1045" sodipodi:nodetypes="czzzzzzzz" /> <path style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.08777227pt" d="M 357.81578,261.23898 C 356.5181,259.13317 356.92273,251.14638 350.00173,252.6991 C 343.08073,254.25181 335.56436,261.67029 333.48062,264.3444 C 331.39688,267.01853 332.51317,271.7629 333.48062,272.8843 C 334.44808,274.0057 339.9551,274.60952 341.51792,275.9897 C 343.08073,277.36989 346.72728,282.54559 348.66218,282.20055 C 350.59709,281.8555 354.54133,277.71494 354.69016,275.98972 C 354.839,274.26448 359.11343,263.34482 357.81578,261.23898 z " id="path1049" sodipodi:nodetypes="czzzzzzz" /> <path style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.0507082pt" d="M 353.98747,290.8932 C 354.40835,286.69185 359.13872,270.03729 359.90396,265.00399 C 360.66919,259.9707 357.76131,262.50815 358.98569,260.26188 C 360.21005,258.0156 364.34229,252.73275 367.25016,251.52641 C 370.15805,250.32009 374.29029,251.01837 376.43293,252.14151 C 378.57557,253.26465 379.91473,257.01728 380.10603,258.26519 C 380.29733,259.51312 378.61384,260.92744 377.58077,260.51147 C 376.54771,260.09549 378.19773,253.58856 375.69329,255.59288 C 373.18885,257.77367 370.03172,261.4682 368.39801,263.00731 C 367.08896,264.5464 370.3111,263.75607 370.92328,265.00399 C 371.53546,266.25192 372.6833,268.33179 372.07112,270.49486 C 371.45892,272.65792 368.81888,276.60968 367.25016,277.98239 C 365.68143,279.35511 364.30403,276.69288 362.65879,278.73116 C 361.01354,280.76943 358.78758,289.12011 357.41015,291.07518 L 353.98747,290.8932 z " id="path1050" sodipodi:nodetypes="czzzzzzzzzzzzcc" /> <path style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.875;stroke-dasharray:none" d="M 352.83142,246.55994 C 353.26061,248.23306 354.60183,252.16987 355.56751,253.05563 C 356.53319,253.94141 358.59869,254.20386 358.9474,253.05563 C 359.29612,251.9074 356.9624,246.13345 362.81013,243.01683 C 368.81881,239.90021 378.20738,240.62195 381.15807,242.03264 C 384.10875,243.44331 389.07129,248.69236 384.37701,252.26828 C 380.48745,255.84417 389.92966,255.9426 391.9415,254.4335 C 393.95334,252.9244 396.87588,247.33751 394.27391,244.64737 C 391.67194,241.95724 385.0755,235.53016 378.95952,234.87404 C 372.84355,234.2179 358.22313,241.50773 356.2113,242.03264 C 354.03853,242.55754 352.40223,244.8868 352.83142,246.55994 z " id="path1051" sodipodi:nodetypes="czzzzzzzzzz" /> <g id="g1422" transform="translate(-15.816734,-109.09188)"> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.16552086pt" d="M 500.15302,318.39576 C 498.6309,318.58535 497.62728,319.44559 497.45659,321.35308 L 496.2718,334.4836 L 495.12787,321.15593 C 494.4451,313.52598 480.11544,322.81032 474.82299,326.00594 C 463.97441,332.55643 453.12906,348.90299 453.12904,365.27921 C 453.12904,369.37327 450.53202,374.85695 458.19505,375.61014 C 471.12797,372.2556 475.71395,368.40706 475.88521,364.72718 C 475.97004,366.73597 472.22575,370.99591 477.19257,377.85771 C 471.88006,374.61864 449.68734,372.98113 454.59982,385.78334 C 460.64344,396.79407 487.30926,400.22178 487.52886,393.43295 C 487.74845,386.64413 493.79077,380.76155 483.19824,381.13048 C 485.89452,378.43241 492.4316,379.68832 495.12787,376.99022 L 496.31266,372.81053 L 497.66087,376.55648 C 500.35715,379.25456 506.64909,378.23526 509.34537,380.93333 C 500.48613,379.72791 504.79515,386.40754 505.01475,393.19637 C 505.23437,399.98518 531.94102,396.59692 537.98464,385.58618 C 542.89711,372.78397 520.66354,374.42148 515.35103,377.66055 C 520.31782,370.79874 516.57357,366.49938 516.65839,364.4906 C 516.82967,368.17046 521.41564,372.05845 534.34856,375.41298 C 542.0116,374.65978 539.45542,369.1761 539.45542,365.08206 C 539.45542,348.70583 528.61005,332.35928 517.76147,325.80879 C 513.79214,323.41205 504.71936,317.82698 500.15302,318.39576 z " id="path1060" sodipodi:nodetypes="cccccccccccccccccccccccc" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.98194113pt" d="M 501.66595,339.08941 C 507.48057,336.85763 507.44235,336.64611 505.77764,338.68995 C 504.31721,340.73379 502.98053,336.92565 501.65049,348.68951 C 500.11618,360.84766 495.64707,341.51834 501.66595,339.08941 z " id="path1057" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.98194113pt" d="M 491.59647,339.30071 C 485.78186,337.06892 485.82008,336.85741 487.48479,338.90125 C 488.94522,340.94509 490.2819,337.13695 491.61194,348.9008 C 493.14625,361.05897 497.61536,341.72965 491.59647,339.30071 z " id="path1059" sodipodi:nodetypes="czzz" /> </g> <path sodipodi:type="arc" style="font-size:12px;fill:url(#radialGradient3062);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none" id="path1065" sodipodi:cx="271.35837" sodipodi:cy="796.11926" sodipodi:rx="37.428738" sodipodi:ry="37.428738" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" transform="matrix(1.269231,0,0,1.209574,137.91637,-391.80978)" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke-width:0.84895535pt" id="rect1074" width="42.038872" height="31.251434" x="806.71417" y="226.75293" inkscape:export-filename="C:\pas\mricron\btn\render.png" inkscape:export-xdpi="59.193832" inkscape:export-ydpi="59.193832" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none" d="M 819.23401,235.83827 C 829.23401,236.6716 837.98401,240.4216 843.60901,248.96327 C 849.23401,258.12994 848.60901,258.96327 848.60901,258.96327 C 848.60901,258.96327 849.85901,267.71327 837.98401,268.96327 C 826.10901,269.58827 812.80095,257.37856 799.05095,257.37856 C 785.92595,257.37856 781.10901,255.33351 782.98401,243.96327 C 784.85901,232.15109 798.29651,206.46327 821.10901,205.83827 C 843.92151,204.58827 864.54651,211.9841 872.98401,227.08827 C 880.79651,242.19244 877.04651,253.96327 872.35901,257.71327 C 867.67151,261.46327 856.94234,256.46327 848.60901,258.33827" id="path1067" sodipodi:nodetypes="czzzzzzzzz" inkscape:export-filename="C:\pas\mricron\btn\render.png" inkscape:export-xdpi="59.193832" inkscape:export-ydpi="59.193832" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875" d="M 834.85901,257.08827 C 827.35901,254.58827 824.23401,254.58827 817.35901,248.33827 C 810.48401,242.08827 809.23401,235.83827 809.23401,235.83827" id="path1068" sodipodi:nodetypes="ccc" inkscape:export-filename="C:\pas\mricron\btn\render.png" inkscape:export-xdpi="59.193832" inkscape:export-ydpi="59.193832" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875" d="M 826.73401,206.46327 C 827.35901,218.96327 834.15818,226.67123 831.94848,236.83589" id="path1069" sodipodi:nodetypes="cc" inkscape:export-filename="C:\pas\mricron\btn\render.png" inkscape:export-xdpi="59.193832" inkscape:export-ydpi="59.193832" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875" d="M 840.13877,213.44025 C 854.73083,213.197 857.34591,215.81208 859.43798,226.79542 C 865.19116,223.65732 868.18798,225.41724 869.43798,237.91724" id="path1070" sodipodi:nodetypes="ccc" inkscape:export-filename="C:\pas\mricron\btn\render.png" inkscape:export-xdpi="59.193832" inkscape:export-ydpi="59.193832" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875" d="M 849.45107,234.18033 C 849.45107,234.18033 840.18981,253.08198 849.56481,252.45698 C 858.93981,251.83198 855.28403,251.8829 857.93568,250.77805" id="path1071" sodipodi:nodetypes="ccc" inkscape:export-filename="C:\pas\mricron\btn\render.png" inkscape:export-xdpi="59.193832" inkscape:export-ydpi="59.193832" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875" d="M 794.9741,233.10811 C 794.9741,233.10811 798.12134,225.52191 806.0986,221.07625 C 814.07585,217.1536 819.57263,214.37906 819.7936,208.85479 L 819.13069,214.5242 C 818.40282,220.74913 827.76732,227.71239 824.7936,234.41697" id="path1072" sodipodi:nodetypes="czczz" inkscape:export-filename="C:\pas\mricron\btn\render.png" inkscape:export-xdpi="59.193832" inkscape:export-ydpi="59.193832" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.875" d="M 836.12326,205.71363 C 841.38865,216.00392 837.5669,231.23283 841.54438,242.0604" id="path1073" sodipodi:nodetypes="cc" inkscape:export-filename="C:\pas\mricron\btn\render.png" inkscape:export-xdpi="59.193832" inkscape:export-ydpi="59.193832" /> <rect style="font-size:12px;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" id="rect1173" width="106.29922" height="106.29922" x="426.47165" y="93.501656" /> <rect style="font-size:12px;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" id="rect1174" width="106.29922" height="106.29922" x="532.77087" y="93.501656" /> <rect style="fill:url(#linearGradient3266);fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:3.75;stroke-dasharray:none" id="rect1204" width="91.25" height="30" x="-312.93326" y="132.02031" ry="12.5" transform="scale(-1,1)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:1.27241249pt" d="M 372.7571,104.0435 C 363.84962,104.0461 348.56454,111.16259 342.62403,116.5091 C 330.74298,127.20208 324.08732,155.03475 324.08732,172.8564 C 324.08732,178.28856 324.10322,183.61773 324.33245,188.74709 L 418.99322,188.74709 C 419.23436,183.66252 419.27921,178.4092 419.27921,173.01412 C 419.27917,155.1925 415.62342,128.33815 403.71599,117.62438 C 397.76228,112.26749 381.66458,104.0409 372.7571,104.0435 z " id="path1205" sodipodi:nodetypes="cccccccc" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.16552086pt" d="M 376.29987,107.00663 C 374.77775,107.19622 373.77413,108.05646 373.60344,109.96395 L 372.41865,123.09447 L 371.27472,109.7668 C 370.59195,102.13685 356.26229,111.42119 350.96984,114.61681 C 340.12126,121.1673 329.27591,137.51386 329.27589,153.89008 C 329.27589,157.98414 326.67887,163.46782 334.3419,164.22101 C 347.27482,160.86647 351.8608,157.01793 352.03206,153.33805 C 352.11689,155.34684 348.3726,159.60678 353.33942,166.46858 C 348.02691,163.22951 325.83419,161.592 330.74667,174.39421 C 336.79029,185.40494 363.45611,188.83265 363.67571,182.04382 C 363.8953,175.255 369.93762,169.37242 359.34509,169.74135 C 362.04137,167.04328 368.57845,168.29919 371.27472,165.60109 L 372.45951,161.4214 L 373.80772,165.16735 C 376.504,167.86543 382.79594,166.84613 385.49222,169.5442 C 376.63298,168.33878 380.942,175.01841 381.1616,181.80724 C 381.38122,188.59605 408.08787,185.20779 414.13149,174.19705 C 419.04396,161.39484 396.81039,163.03235 391.49788,166.27142 C 396.46467,159.40961 392.72042,155.11025 392.80524,153.10147 C 392.97652,156.78133 397.56249,160.66932 410.49541,164.02385 C 418.15845,163.27065 415.60227,157.78697 415.60227,153.69293 C 415.60227,137.3167 404.7569,120.97015 393.90832,114.41966 C 389.93899,112.02292 380.86621,106.43785 376.29987,107.00663 z " id="path1206" sodipodi:nodetypes="cccccccccccccccccccccccc" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.98194113pt" d="M 377.8128,127.70028 C 383.62742,125.4685 383.5892,125.25698 381.92449,127.30082 C 380.46406,129.34466 379.12738,125.53652 377.79734,137.30038 C 376.26303,149.45853 371.79392,130.12921 377.8128,127.70028 z " id="path1207" sodipodi:nodetypes="czzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.98194113pt" d="M 367.74332,127.91158 C 361.92871,125.67979 361.96693,125.46828 363.63164,127.51212 C 365.09207,129.55596 366.42875,125.74782 367.75879,137.51167 C 369.2931,149.66984 373.76221,130.34052 367.74332,127.91158 z " id="path1209" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:8.125;stroke-linecap:round;stroke-linejoin:bevel;stroke-dasharray:none;stroke-dashoffset:12.5" d="M 412.42043,191.6321 L 336.35302,117.64904" id="path1210" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" d="M 591.68327,168.2703 C 591.68327,182.4153 580.20327,193.8953 566.05827,193.8953 C 551.91327,193.8953 540.43327,182.4153 540.43327,168.2703 C 540.43327,154.1253 551.91327,142.6453 566.05827,142.6453 C 580.20327,142.6453 591.68327,154.1253 591.68327,168.2703 z " id="path1291" /> <g id="g1298" transform="translate(402.30827,-332.21688)"> <path style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 176.78473,427.8954 C 171.00127,436.31459 166.76057,442.73066 161.93434,453.77797 C 157.10811,465.20752 151.77953,493.47595 155.5391,498.12102 C 159.29867,502.76608 164.78763,499.69833 168.54719,495.5836 C 172.30676,491.46887 170.40231,470.53213 171.58857,461.41874 C 172.46233,452.30535 174.80678,442.86614 176.78473,427.8954 z " id="path1294" sodipodi:nodetypes="czzzzc" /> <path style="fill:url(#linearGradient1139);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 162.79099,460.36798 C 161.39101,464.47106 159.75932,467.29332 158.59105,472.6772 C 157.42279,478.24737 155.75469,492.02393 156.66475,494.28769 C 157.57482,496.55145 158.90351,495.05639 159.81357,493.05108 C 160.72363,491.04578 160.26263,480.84231 160.54978,476.40092 C 160.76129,471.95952 162.3122,467.66394 162.79099,460.36798 z " id="path1295" sodipodi:nodetypes="czzzzc" /> <path style="font-size:12px;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt" d="M 164.76093,520.57895 C 151.14054,517.0018 150.18838,509.59815 153.69986,504.60539 C 155.02384,503.20637 158.13732,501.06251 159.94479,501.19243 C 161.75226,501.32236 163.31049,502.23808 165.63175,503.9005 C 170.89928,507.85036 160.96932,509.56589 164.76093,520.57895 z " id="path1296" sodipodi:nodetypes="ccszc" /> <path style="font-size:12px;fill:url(#linearGradient1175);fill-rule:evenodd;stroke-width:1pt" d="M 160.3104,515.97821 C 157.05245,515.15657 155.51819,515.31397 153.5053,510.38831 C 151.49241,505.77515 156.49689,504.25943 157.09117,503.63371 C 157.68545,503.00798 158.55309,503.42123 159.14737,503.97552 C 159.74165,504.5298 159.44061,507.35015 159.62812,508.57779 C 159.76624,509.80544 157.49775,511.93028 160.3104,515.97821 z " id="path1297" sodipodi:nodetypes="czzzzc" /> </g> <rect style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:4.56593418" id="rect1303" width="48.979599" height="47.110672" x="580.53296" y="122.93801" /> <rect style="font-size:12px;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" id="rect1092" width="106.29922" height="106.29922" x="533.39587" y="-13.422614" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;stroke-linecap:round;stroke-dasharray:10, 10;stroke-dashoffset:0;stroke-opacity:1" d="M 539.64468,67.3328 C 543.73377,67.33772 550.81253,73.21863 551.91196,67.34757 C 553.01139,61.78901 560.6315,5.33969 564.99126,-3.51858 C 569.35102,-12.376848 566.16507,6.13694 579.58734,10.13546 C 593.32211,13.82148 597.36938,71.83083 605.47914,75.3766 C 613.5889,78.60987 615.13616,73.42533 619.49592,70.47257 C 623.85568,67.51982 626.02795,67.34757 630.38772,67.34757" id="path1280" sodipodi:nodetypes="czzzzzz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#040600;stroke-width:3.75;stroke-linecap:butt;stroke-dasharray:3.75, 3.75;stroke-dashoffset:0;stroke-opacity:1" d="M 539.43674,67.53502 C 543.52583,67.53994 550.60459,70.92085 551.70402,65.04979 C 552.80345,59.49123 555.42356,24.91691 559.78332,16.05864 C 564.14308,7.20037 567.20713,-4.28584 580.3169,1.58768 C 593.11417,14.6487 606.22394,79.22055 609.3337,80.57882 C 611.50596,81.31209 614.92822,73.62755 619.28798,70.67479 C 623.64774,67.72204 625.82001,67.54979 630.17978,67.54979" id="path1281" sodipodi:nodetypes="czzzzzz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#040600;stroke-width:3.75;stroke-linecap:butt;stroke-dasharray:3.75, 3.75;stroke-dashoffset:0;stroke-opacity:1" d="M 395.76647,77.589073 C 399.85556,77.593993 406.93432,80.974903 408.03375,75.103843 C 409.13318,69.545283 411.75329,34.970963 416.11305,26.112693 C 420.47281,17.254423 423.53686,5.7682122 436.64663,11.641733 C 449.4439,24.702753 462.55367,89.274602 465.66343,90.632872 C 467.83569,91.366142 471.25795,83.681603 475.61771,80.728843 C 479.97747,77.776093 482.14974,77.603843 486.50951,77.603843" id="path1282" sodipodi:nodetypes="czzzzzz" /> <g id="g1163" transform="matrix(1.152996,0,0,1,-83.837104,-109.09188)"> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:2.07708836;stroke-dasharray:none" d="M 472.42571,238.27147 C 472.33405,238.27145 472.24478,238.29291 472.15311,238.29398 L 472.15311,238.31648 C 472.08489,238.31034 472.01758,238.29395 471.94867,238.29398 C 471.78809,238.29403 471.63216,238.33557 471.47163,238.33899 L 471.47163,238.42899 C 471.37376,238.41606 471.27556,238.40652 471.17632,238.40649 C 471.1074,238.40647 471.0401,238.42285 470.97187,238.42899 L 470.97187,238.40649 C 470.88021,238.40543 470.79094,238.38396 470.69928,238.38399 C 465.87162,238.38545 461.03877,239.90805 457.81913,242.92943 C 456.20932,244.44011 446.99543,256.8992 450.09559,259.04098 C 457.81097,264.68512 464.49982,248.07035 457.3648,261.85375 C 456.64585,266.58811 456.46107,269.05668 456.41072,270.29207 C 456.30905,268.02898 455.46815,262.72102 451.04967,260.14359 C 447.35854,258.03472 444.93899,276.66261 444.93899,279.18042 C 444.93899,289.25168 451.37986,299.31925 457.81913,303.34776 C 461.08484,305.39084 466.00722,306.3715 470.90372,306.34054 L 470.90372,306.36305 C 471.15408,306.3651 471.40305,306.34374 471.65336,306.34054 L 471.65336,306.22803 C 471.84267,306.23528 472.03155,306.25211 472.22127,306.25053 L 472.22127,306.22803 C 477.11777,306.25899 482.04015,305.27835 485.30586,303.23524 C 491.74513,299.20674 498.186,289.13916 498.186,279.06791 C 498.186,276.5501 495.76645,257.9222 492.07532,260.03107 C 487.65684,262.60851 486.81594,267.91647 486.71427,270.17956 C 486.66392,268.94417 486.47914,266.47559 485.76018,261.74124 C 478.62517,247.95784 485.31402,264.5726 493.0294,258.92847 C 496.12956,256.78669 486.91567,244.32759 485.30586,242.81691 C 482.08622,239.79554 477.25337,238.27293 472.42571,238.27147 z " id="path1211" transform="matrix(0.896078,0,0,0.909383,46.81814,19.67645)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.7041852pt" d="M 468.24591,259.15861 C 468.51094,258.62567 467.79271,252.85171 466.69475,251.35949 C 465.59679,249.86726 463.96768,250.52503 463.70265,251.05797 C 463.43764,251.5909 465.07594,250.88137 466.17389,252.37359 C 467.27185,253.86581 467.9809,259.69155 468.24591,259.15861 z " id="path1212" sodipodi:nodetypes="czzzz" transform="matrix(0.896078,0,0,0.909383,46.81814,19.67645)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59326982pt" d="M 463.34275,289.21648 C 461.03017,288.99344 460.56786,283.64967 458.96224,286.90958 C 457.28286,290.22776 460.74374,297.34319 461.0482,293.66548 C 461.2789,289.98777 465.58157,289.49777 463.34275,289.21648 z " id="path1213" sodipodi:nodetypes="czzz" transform="matrix(0.896078,0,0,0.909383,46.81814,19.67645)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.7041852pt" d="M 474.87908,259.04805 C 474.61405,258.51511 475.33228,252.74115 476.43024,251.24893 C 477.52819,249.7567 479.15731,250.41447 479.42234,250.9474 C 479.68735,251.48035 478.04905,250.77081 476.9511,252.26303 C 475.85314,253.75526 475.14409,259.58099 474.87908,259.04805 z " id="path1214" sodipodi:nodetypes="czzzz" transform="matrix(0.896078,0,0,0.909383,46.81814,19.67645)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59326982pt" d="M 479.78224,289.10592 C 482.09482,288.88288 482.55713,283.53911 484.16275,286.79902 C 485.84213,290.1172 482.38125,297.23264 482.07679,293.55492 C 481.84609,289.87721 477.54342,289.38721 479.78224,289.10592 z " id="path1215" sodipodi:nodetypes="czzz" transform="matrix(0.896078,0,0,0.909383,46.81814,19.67645)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59326982pt" d="M 479.78224,289.10592 C 482.09482,288.88288 482.55713,283.53911 484.16275,286.79902 C 485.84213,290.1172 482.38125,297.23264 482.07679,293.55492 C 481.84609,289.87721 477.54342,289.38721 479.78224,289.10592 z " id="path1245" sodipodi:nodetypes="czzz" transform="matrix(0.896078,0,0,0.909383,71.19322,13.47142)" /> <path transform="matrix(0.820025,0,0,0.858963,104.9588,28.9685)" style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:2.07708836" d="M 472.42572,238.27147 C 466.99935,238.3446 460.99557,239.27928 457.242,243.6056 C 454.27786,247.05912 447.543,265.39403 446.588,268.07554 C 444.99506,275.03305 443.89364,282.61304 446.9967,289.34223 C 449.98685,297.12243 456.23622,304.66231 464.92263,305.85892 C 470.66585,306.6581 476.71462,306.56039 482.24009,304.66227 C 488.70615,302.32029 492.95294,296.28794 495.73557,290.27853 C 498.36218,284.49691 498.76947,277.90311 497.25994,271.76637 C 496.6036,267.85969 495.93735,263.78918 493.70802,260.42078 C 490.47721,259.07927 488.59909,263.53006 487.49637,265.86353 C 487.00972,267.33824 486.63024,271.50536 486.49583,267.70454 C 486.56751,263.78501 485.27565,260.09141 483.12367,256.86 C 483.47775,256.38368 486.42646,260.44859 488.46678,259.99317 C 492.66404,261.2943 494.92727,256.76681 492.55453,253.62131 C 490.80672,249.9676 488.38631,246.652 485.92858,243.45619 C 482.48414,239.81958 477.32986,238.26882 472.42572,238.27147 z " id="path1151" sodipodi:nodetypes="cccccccccccccccc" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.7041852pt" d="M 469.29214,259.15861 C 471.28335,258.62567 470.01209,252.60872 468.91413,251.1165 C 467.81617,249.62427 460.51529,248.09514 463.70265,251.05797 C 467.13661,253.77781 467.05433,259.69155 469.29214,259.15861 z " id="path1242" sodipodi:nodetypes="czzz" transform="matrix(0.820025,0,0,0.858963,104.9588,28.9685)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59326982pt" d="M 466.83017,280.96913 C 464.51759,280.74609 460.56786,283.64967 458.96224,286.90958 C 457.28286,290.22776 460.74374,297.34319 461.0482,293.66548 C 461.2789,289.98777 469.06899,281.25042 466.83017,280.96913 z " id="path1243" sodipodi:nodetypes="czzz" transform="matrix(0.820025,0,0,0.858963,104.9588,28.9685)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59100037pt" d="M 493.43163,251.60533 C 491.79878,251.14755 492.84125,245.97921 493.74161,244.69745 C 494.64196,243.41568 500.62886,242.10222 498.01515,244.64717 C 495.19921,246.98342 495.26668,252.0631 493.43163,251.60533 z " id="path1152" sodipodi:nodetypes="czzz" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.52140689" d="M 511.80663,239.60773 C 505.82577,239.32916 500.11547,244.27305 498.49491,246.98563 C 497.16791,249.22473 493.46139,261.39466 492.85327,264.1486 C 492.10462,268.10699 491.68917,272.2685 492.99906,276.15741 C 494.65527,281.44574 497.8549,286.62328 502.77269,289.10403 C 505.89347,290.48383 509.46589,290.71532 512.64653,290.47013 C 516.82711,290.39011 521.1916,289.06289 524.01723,285.6621 C 528.59029,280.58529 531.28514,273.27869 529.87427,266.31128 C 529.26796,262.87343 525.92547,250.57752 524.78129,248.36436 C 522.92298,245.30255 517.65774,239.61035 511.80663,239.60773 z " id="path1149" sodipodi:nodetypes="cccccccccc" /> </g> <path style="fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path1142" d="M 138.66767,389.39149 C 138.44176,383.72226 145.56665,387.55955 145.98842,387.81204 C 148.96509,389.52446 154.57645,395.05092 158.13596,394.96803 C 160.13885,394.75388 161.81717,393.54252 163.24286,392.19084 C 164.52303,390.90588 165.39009,389.48939 166.24724,387.90878 C 167.62765,385.61133 171.36675,378.90196 173.96259,379.02192 C 176.3473,379.252 180.6262,381.76723 182.82201,382.68319 C 184.52628,383.3966 187.66318,382.74725 189.39484,383.39336 C 190.69907,383.85026 187.07224,389.98343 188.44387,390.1658 C 189.58344,390.2587 190.28074,389.76906 191.11843,389.02388 C 191.75718,388.42263 195.70074,391.22127 194.88417,391.98976 C 192.75044,393.88937 190.46141,394.76495 187.5927,394.46701 C 185.76743,394.20765 183.97718,393.74035 182.24558,393.1098 C 180.4623,392.42436 178.76716,391.54829 177.00797,390.80685 C 175.46375,390.16429 173.85066,389.50279 172.17678,389.30273 C 171.55021,389.26725 171.32777,389.20991 170.97538,389.74989 C 169.85645,391.71173 168.68703,393.47761 167.0634,395.07079 C 164.5015,397.41937 161.60412,399.05395 158.07518,399.24036 C 153.41627,399.11799 146.22829,400.87294 140.4353,391.66204 C 140.15115,391.46374 144.14072,386.65256 144.03158,389.39149 L 138.66767,389.39149 z " sodipodi:nodetypes="ccccccccccccccccccccc" /> <rect style="fill:#f9bac0;fill-rule:evenodd;stroke:#000000;stroke-width:0.59608836pt" id="rect1120" width="14.67272" height="14.527117" x="-220.29938" y="355.46417" ry="4.7484632" transform="matrix(0.6694625,-0.7428458,0.7836175,0.6212436,0,0)" /> <rect style="fill:url(#linearGradient3202);fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.20409851pt" id="rect1117" width="63.894375" height="13.612261" x="-209.20451" y="355.92163" transform="matrix(0.6694625,-0.7428458,0.7836175,0.6212436,0,0)" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.12771654" d="M 144.38317,376.51805 L 183.13574,333.04569 L 183.13574,333.04569" id="path1126" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.12771654" d="M 148.72431,379.95966 L 187.47688,336.4873 L 187.47688,336.4873" id="path1128" /> <path style="fill:#e49415;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt" d="M 181.54997,328.19842 L 204.7151,313.05607 L 193.41872,337.20894 L 181.54997,328.19842 z " id="path1129" /> <path style="fill:#040023;fill-rule:evenodd;stroke-width:1pt" d="M 196.57455,318.36983 L 205.12859,312.58608 L 200.74625,321.52752 L 196.57455,318.36983 z " id="path1132" /> <g id="g1195" transform="matrix(0.789807,0,0,0.829148,24.785486,35.13232)"> <path sodipodi:type="arc" style="font-size:12px;fill:url(#radialGradient1169);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.87644994;stroke-dasharray:none" id="path1190" sodipodi:cx="271.35837" sodipodi:cy="796.11926" sodipodi:rx="37.428738" sodipodi:ry="37.428738" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" transform="matrix(1.269231,0,0,1.209574,-184.6799,-194.3941)" /> <path style="font-size:12px;fill:url(#linearGradient683);fill-opacity:0.38016998;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 159.72524,722.93003 C 140.50054,722.93003 124.04616,733.91302 116.57139,749.57844 C 122.48956,752.61039 129.09474,755.48259 136.87909,753.39616 C 151.49622,750.20385 156.06571,742.67836 163.37427,739.48607 C 178.69415,738.91352 186.03123,746.78366 201.1339,746.44112 C 193.03644,732.49107 177.62722,722.93004 159.72524,722.93003 z " id="path1191" /> <text xml:space="preserve" style="font-size:48px;font-style:normal;font-weight:bold;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Palatino Linotype" x="47.569454" y="419.89508" id="text1192" sodipodi:linespacing="100%" transform="scale(2.880225,1.909157)"><tspan x="47.569454" y="419.89508" sodipodi:role="line" id="tspan1193">i</tspan></text> </g> <path style="fill:#fb4100;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 142.10016,698.71774 C 150.32082,682.69183 164.47101,695.16173 174.84786,695.87292 C 183.87705,695.51733 184.82039,676.31489 201.93545,679.5153 C 209.88655,681.41184 207.73624,717.9912 196.27536,724.67657 C 180.23767,733.67611 133.87948,714.38803 142.10016,698.71774 z " id="path1179" sodipodi:nodetypes="cccsz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-dasharray:none" d="M 119.90595,252.88899 C 118.85992,255.24256 123.55617,255.51496 127.86561,257.22021 C 132.17504,258.92546 136.62069,262.58658 139.25756,263.34931 C 144.53131,264.87477 154.03276,265.3542 157.82463,264.39534 C 161.6165,263.43648 161.31141,260.47272 162.00876,256.55011" id="path1135" sodipodi:nodetypes="cszzz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-dasharray:none" d="M 147.62582,248.18188 C 142.39566,241.38267 152.07145,242.16719 152.59448,237.98306 C 155.20955,227.78425 145.27225,226.2152 145.27225,226.2152 C 145.27225,226.2152 151.28694,218.63146 152.85598,214.44733 C 147.62582,208.69415 148.14883,209.47868 140.04208,213.13979" id="path1138" sodipodi:nodetypes="ccccc" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-dasharray:none" d="M 153.379,273.80964 C 153.98918,266.2259 148.58467,265.57213 146.31827,264.39534" id="path1141" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-dasharray:none" d="M 119.7752,257.53887 C 122.9133,264.8611 134.37607,267.25825 139.64982,268.78371" id="path1153" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-dasharray:none" d="M 176.68832,247.791 C 181.91848,240.99179 172.24269,241.77631 171.71966,237.59218 C 169.10459,227.39337 179.04189,225.82432 179.04189,225.82432 C 179.04189,225.82432 173.0272,218.24058 171.45816,214.05645 C 176.68832,208.30327 176.16531,209.0878 184.27206,212.74891" id="path1167" sodipodi:nodetypes="ccccc" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-dasharray:none" d="M 170.93514,273.41876 C 170.32496,265.83502 175.72947,265.18125 177.99587,264.00446" id="path1169" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-dasharray:none" d="M 204.53894,257.14799 C 201.40084,264.47022 189.93807,266.86737 184.66432,268.39283" id="path1170" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-dasharray:none" d="M 204.396,252.4136 C 205.44203,254.76717 200.74578,255.03957 196.43634,256.74482 C 192.12691,258.45007 187.68126,262.11119 185.04439,262.87392 C 179.77064,264.39938 170.26919,264.87881 166.47732,263.91995 C 162.68545,262.96109 161.683,257.64376 162.03168,253.19813" id="path1194" sodipodi:nodetypes="cszzz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="M 125.13612,240.59811 C 117.46522,261.6931 126.09498,252.62748 130.8893,252.88899" id="path1195" sodipodi:nodetypes="cz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="M 198.66259,240.1321 C 206.33349,261.22709 197.70373,252.16147 192.90941,252.42298" id="path1218" sodipodi:nodetypes="cz" /> <path style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-dasharray:none" d="M 169.39735,105.71938 C 162.10505,105.75558 154.07994,107.25613 149.24239,113.24002 C 145.68525,117.38626 143.13108,122.29128 140.39162,126.96404 C 138.4291,131.48683 134.21524,152.7264 134.04914,160.14626 C 134.89311,172.12407 141.3859,183.93155 151.73427,190.22339 C 159.97252,194.26858 169.64282,193.9197 178.45471,192.35355 C 186.19946,190.80763 192.37151,185.22838 196.32348,178.59838 C 201.86706,170.07793 204.00788,159.36075 201.49479,149.44773 C 200.50965,144.115 196.66803,125.58494 193.27772,121.84145 C 189.6424,115.2255 184.68602,108.33309 176.82299,106.68486 C 174.40559,106.03251 171.89981,105.72324 169.39735,105.71938 z " id="path1223" sodipodi:nodetypes="ccccccccccc" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="M 164.88535,105.92145 C 165.93138,106.53164 168.00101,104.58409 168.39327,118.66194 C 168.78553,132.73979 168.73939,187.94781 169.08806,190.38856 C 169.43673,192.5678 166.75821,193.42635 163.74413,193.18855" id="path1220" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="M 172.17264,105.89284 C 171.12661,106.50303 169.05698,104.55548 168.66472,118.63333 C 168.27246,132.71118 169.24317,188.28903 168.8945,190.72978 C 168.54583,192.90902 171.40927,193.21282 174.42334,192.97503" id="path1221" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-dasharray:none" d="M 182.45745,145.55465 C 174.5953,135.38048 175.44975,132.40301 183.70286,126.16129 C 178.0131,123.47057 177.93926,120.59539 187.92533,114.2885" id="path1224" sodipodi:nodetypes="ccc" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-dasharray:none" d="M 152.6509,146.5756 C 160.51305,136.40143 159.6586,133.42396 151.40549,127.18224 C 157.09525,124.49152 157.16909,121.61634 147.18302,115.30945" id="path1227" sodipodi:nodetypes="ccc" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="M 164.47454,148.50937 C 161.26937,152.76239 154.15017,147.49234 152.64004,146.47531 C 151.12991,145.45828 148.94176,150.3585 144.50382,148.87919 C 140.2508,147.39988 140.80553,143.14686 140.80553,143.14686" id="path1228" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="M 162.60184,160.69108 C 158.4721,162.3553 152.39349,155.64311 150.88336,154.62608 C 149.37323,153.60905 147.18508,158.50927 142.74714,157.02996 C 138.49412,155.55065 136.27514,144.64072 136.27514,144.64072" id="path1229" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="M 156.98552,187.53536 C 147.30836,175.51594 156.27668,178.93685 156.6157,172.92714 C 157.32454,167.28726 162.79607,166.31561 158.73065,167.13701 C 155.71761,167.77479 152.82496,163.12668 144.04154,167.00988" id="path1230" sodipodi:nodetypes="czsz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="M 172.05604,147.11525 C 175.26121,151.36827 182.38041,146.09822 183.89054,145.08119 C 185.40067,144.06416 187.58882,148.96438 192.02676,147.48507 C 196.27978,146.00576 195.72505,141.75274 195.72505,141.75274" id="path1232" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="M 172.35969,159.29696 C 176.48943,160.96118 184.13709,154.24899 185.64722,153.23196 C 187.15735,152.21493 189.3455,157.11515 193.78344,155.63584 C 198.03646,154.15653 200.25544,143.2466 200.25544,143.2466" id="path1233" sodipodi:nodetypes="czzz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.70000005;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="M 181.11411,185.61822 C 190.79127,173.5988 181.82295,177.01971 181.48393,171.01 C 180.77509,165.37012 175.30356,164.39847 179.36898,165.21987 C 182.38202,165.85765 185.27467,161.20954 194.05809,165.09274" id="path1234" sodipodi:nodetypes="czsz" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke-width:0.84895535pt" id="rect1300" width="25.381052" height="18.778831" x="735.11206" y="593.82367" transform="matrix(0.932103,-0.3621934,0,1,0,0)" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.09033966" d="M 689.65698,333.99075 C 695.28457,332.30474 704.43001,331.66408 706.81101,333.58867 C 709.192,335.77477 710.05808,334.51818 711.36562,337.39476 C 712.41166,340.27135 712.87988,341.44154 706.19712,344.78942 C 699.51435,347.76175 686.53346,348.8268 679.84155,346.0804 C 673.14965,343.85702 670.26758,344.06785 671.32275,336.82552 C 672.37792,329.31762 680.46301,317.21969 693.30095,311.8556 C 706.13889,306.11596 717.7458,306.04991 722.49408,313.28086 C 726.89063,320.64848 725.15011,325.95275 722.51218,329.23114 C 719.87425,332.50954 715.56943,333.37544 710.87978,336.32441" id="path1301" sodipodi:nodetypes="czzzzzzzzz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.09033966" d="M 704.43849,338.33715 C 700.2178,338.47498 692.4445,341.2504 688.57553,338.9982" id="path1302" sodipodi:nodetypes="cc" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.09033966" d="M 693.74307,313.26495 C 697.23289,316.97836 700.64449,321.5205 699.40096,328.1116" id="path1303" sodipodi:nodetypes="cc" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.09033966" d="M 703.2256,314.35433 C 711.43741,311.01724 713.69359,309.92471 714.87093,316.06706 C 718.10858,312.92332 719.79507,313.32552 720.49852,320.56336" id="path1304" sodipodi:nodetypes="ccc" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.09033966" d="M 709.2507,322.68851 C 709.2507,322.68851 704.03885,336.07162 709.31471,333.64598 C 714.59058,331.22034 712.53325,332.05037 714.02549,330.80662" id="path1305" sodipodi:nodetypes="ccc" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.09033966" d="M 678.5933,333.95697 C 678.5933,333.95697 683.32306,329.08006 687.81234,324.66426 C 692.30161,320.56274 690.8673,320.72329 690.99165,317.35547 L 693.36057,321.66539 C 695.24931,325.10168 697.04798,323.54365 695.37449,328.22267" id="path1306" sodipodi:nodetypes="czczz" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.09033966" d="M 698.61226,311.89707 C 706.02105,315.62151 701.51674,325.08519 704.80114,330.72165" id="path1307" sodipodi:nodetypes="cc" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.09033966" d="M 691.91037,309.38975 C 687.68968,305.60495 686.45407,308.11887 683.63114,308.48175" id="path1387" sodipodi:nodetypes="cc" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.09033966" d="M 709.30063,304.39086 C 703.5109,303.74416 699.92171,305.99657 697.09878,306.35945" id="path1389" sodipodi:nodetypes="cc" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.09033966" d="M 683.67285,312.00497 C 679.97518,311.86715 672.72488,318.24451 670.42497,326.51139" id="path1390" sodipodi:nodetypes="cc" /> <path style="font-size:12px;fill:url(#linearGradient3132);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 266.43856,630.60816 C 247.21386,630.60816 230.75948,641.59115 223.28471,657.25657 C 229.20288,660.28852 235.80806,663.16072 243.59241,661.07429 C 258.20954,657.88198 262.77903,650.35649 270.08759,647.1642 C 285.40747,646.59165 292.74455,654.46179 307.84722,654.11925 C 299.74976,640.1692 284.34054,630.60817 266.43856,630.60816 z " id="path1561" /> <path sodipodi:type="arc" style="font-size:12px;fill:url(#radialGradient3064);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none" id="path1562" sodipodi:cx="271.35837" sodipodi:cy="796.11926" sodipodi:rx="37.428738" sodipodi:ry="37.428738" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" transform="matrix(1.269231,0,0,1.209574,-76.235414,-285.91008)" /> <path sodipodi:type="arc" style="font-size:12px;fill:url(#radialGradient983);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none" id="path1574" sodipodi:cx="271.35837" sodipodi:cy="796.11926" sodipodi:rx="37.428738" sodipodi:ry="37.428738" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" transform="matrix(0.484769,0,0,0.461984,538.38387,214.33362)" /> <rect style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.375" id="rect1280" width="69.96357" height="45.246185" x="112.90554" y="426.39694" /> <rect style="fill:#9999ff;fill-rule:evenodd;stroke-width:0.84895535pt" id="rect1278" width="24.317806" height="18.077705" x="-157.74673" y="441.57275" transform="scale(-1,1)" /> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:2.375" d="M 154.66415,447.62583 C 148.87955,448.10788 143.81803,450.2771 140.56419,455.21812 C 137.31035,460.52067 137.67189,461.00272 137.67189,461.00272 C 137.67189,461.00272 136.94882,466.06424 143.81803,466.78732 C 150.68724,467.14886 158.38542,460.08603 166.33925,460.08603 C 173.93154,460.08603 176.71794,458.90305 175.63333,452.32582 C 174.54872,445.49295 166.77566,430.63357 153.57954,430.27203 C 140.38342,429.54896 128.45269,433.82715 123.57193,442.56431 C 119.05271,451.30146 121.22194,458.11042 123.93347,460.27964 C 126.645,462.44887 132.85139,459.55657 137.67189,460.64118" id="path1279" sodipodi:nodetypes="czzzzzzzzz" /> <rect transform="scale(-1,1)" y="467.71524" x="-201.17461" height="45.246185" width="69.96357" id="rect1289" style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:2.375;stroke-dasharray:none" /> <rect y="482.89105" x="156.3334" height="18.077705" width="24.317806" id="rect1291" style="fill:#9999ff;fill-rule:evenodd;stroke-width:0.84895535pt" /> <path sodipodi:nodetypes="czzzzzzzzz" id="path1292" d="M 159.41599,488.9441 C 165.20059,489.42615 170.26212,491.59537 173.51595,496.53639 C 176.76979,501.83894 176.40825,502.32099 176.40825,502.32099 C 176.40825,502.32099 177.13133,507.38251 170.26212,508.10559 C 163.3929,508.46713 155.69472,501.4043 147.7409,501.4043 C 140.14861,501.4043 137.3622,500.22132 138.44682,493.64409 C 139.53143,486.81122 147.30448,471.95184 160.5006,471.5903 C 173.69672,470.86723 185.62746,475.14542 190.50822,483.88258 C 195.02743,492.61973 192.85821,499.42869 190.14668,501.59791 C 187.43515,503.76714 181.22875,500.87484 176.40825,501.95945" style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:2.375;stroke-dasharray:none" /> <rect style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:2.375" id="rect1268" width="69.96357" height="45.246185" x="-109.90839" y="566.82684" transform="scale(-1,1)" /> <path sodipodi:type="arc" style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="path1285" sodipodi:cx="88.389725" sodipodi:cy="698.28027" sodipodi:rx="18.305565" sodipodi:ry="18.305565" d="M 106.69529 698.28027 A 18.305565 18.305565 0 1 1 70.08416,698.28027 A 18.305565 18.305565 0 1 1 106.69529 698.28027 z" transform="translate(-12.678637,-108.04585)" /> <rect style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:2.375" id="rect1290" width="69.96357" height="45.246185" x="-104.63519" y="442.85843" transform="scale(-1,1)" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="M 35.856494,468.67158 L 104.22415,468.67158" id="path1299" /> <path style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="M 72.42524,442.43748 L 71.630267,487.35343" id="path1300" sodipodi:nodetypes="cc" /> <rect style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.375" id="rect1301" width="69.96357" height="45.246185" x="-104.44199" y="443.04013" transform="scale(-1,1)" /> <rect style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt" id="rect1302" width="8.9940901" height="9.2751551" x="67.378593" y="464.05392" /> <path style="font-size:12px;fill:url(#linearGradient3113);fill-opacity:0.70196001;stroke:#1c66f9;stroke-width:1.92428339;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.98999999" d="M 22.103543,213.06151 C 22.515516,211.86104 23.951291,210.66009 25.18228,210.84189 L 62.352593,218.87368 C 65.23151,216.34699 69.445869,213.27109 73.789889,214.04114 L 80.105558,214.91754 L 88.086596,216.48472 C 92.745746,217.88758 96.427736,220.80133 96.813826,226.5996 L 96.764886,296.45412 L 21.810414,272.56067 L 22.103543,213.06151 z " id="path1266" sodipodi:nodetypes="cccccccccc" /> <path style="font-size:12px;fill:#4789f7;stroke:#1c4ed9;stroke-width:1.71254337;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99216003" d="M 21.711614,272.26009 L 96.931496,296.4901 L 94.170566,301.54347 L 19.410269,275.82836 L 21.711614,272.26009 z " id="path1271" sodipodi:nodetypes="ccccc" /> <g id="g1279" transform="matrix(0.68875,0,0,0.640474,28.305576,94.94412)"> <path style="fill-rule:evenodd;stroke:none;stroke-width:0.91963024pt" d="M 15.411826,279.67519 L 107.16635,280.32772 L 105.78092,271.91017 C 104.50888,267.9258 100.16017,263.55105 99.313146,259.07319 C 98.024176,254.59533 104.23642,257.47279 103.48688,250.11822 C 102.73733,242.76364 101.33093,223.23927 90.699786,212.93098 C 79.756146,202.93519 70.616996,196.51871 51.220346,199.6699 C 33.073696,201.57109 22.663616,210.23449 15.263856,225.51906 C 7.6727159,240.80363 16.076616,259.82218 15.837966,266.94924 L 15.411826,279.67519 z " id="path1273" sodipodi:nodetypes="ccczzzzzzc" /> <path style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.0507082pt" d="M 81.667436,238.6616 C 80.982416,243.3358 68.662856,240.88582 68.468226,248.58013 C 68.273596,255.77527 84.079546,257.18713 89.984786,255.06933 C 95.890036,252.95153 99.758996,249.65718 99.148096,242.36255 C 98.537216,235.06792 96.575586,216.71313 75.014876,206.18816 C 53.886116,196.16236 29.955336,209.82744 22.306536,224.42792 C 14.657726,239.5276 14.049476,254.81975 23.120686,249.32889 C 31.759936,244.33718 42.301146,228.60033 58.113846,226.78187 C 73.494556,224.9634 82.352426,234.98574 81.667436,238.6616 z " id="path1274" sodipodi:nodetypes="czzzzzzzz" /> <path style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.08777227pt" d="M 46.065436,250.14579 C 44.767756,248.03998 45.172386,240.05319 38.251386,241.60591 C 31.330386,243.15862 23.814016,250.5771 21.730276,253.25121 C 19.646536,255.92534 20.762826,260.66971 21.730276,261.79111 C 22.697736,262.91251 28.204756,263.51633 29.767576,264.89651 C 31.330386,266.2767 34.976936,271.4524 36.911836,271.10736 C 38.846746,270.76231 42.790986,266.62175 42.939816,264.89653 C 43.088656,263.17129 47.363086,252.25163 46.065436,250.14579 z " id="path1275" sodipodi:nodetypes="czzzzzzz" /> <path style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.0507082pt" d="M 42.237126,279.80001 C 42.658006,275.59866 47.388376,258.9441 48.153616,253.9108 C 48.918846,248.87751 46.010966,251.41496 47.235346,249.16869 C 48.459706,246.92241 52.591946,241.63956 55.499816,240.43322 C 58.407706,239.2269 62.539946,239.92518 64.682586,241.04832 C 66.825226,242.17146 68.164386,245.92409 68.355686,247.172 C 68.546986,248.41993 66.863496,249.83425 65.830426,249.41828 C 64.797366,249.0023 66.447386,242.49537 63.942946,244.49969 C 61.438506,246.68048 58.281376,250.37501 56.647666,251.91412 C 55.338616,253.45321 58.560756,252.66288 59.172936,253.9108 C 59.785116,255.15873 60.932956,257.2386 60.320776,259.40167 C 59.708576,261.56473 57.068536,265.51649 55.499816,266.8892 C 53.931086,268.26192 52.553686,265.59969 50.908446,267.63797 C 49.263196,269.67624 47.037236,278.02692 45.659806,279.98199 L 42.237126,279.80001 z " id="path1276" sodipodi:nodetypes="czzzzzzzzzzzzcc" /> <path style="fill:#9999ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.875;stroke-dasharray:none" d="M 41.081076,235.46675 C 41.510266,237.13987 42.851486,241.07668 43.817166,241.96244 C 44.782846,242.84822 46.848346,243.11067 47.197056,241.96244 C 47.545776,240.81421 45.212056,235.04026 51.059786,231.92364 C 57.068466,228.80702 66.457036,229.52876 69.407726,230.93945 C 72.358406,232.35012 77.320946,237.59917 72.626666,241.17509 C 68.737106,244.75098 78.179316,244.84941 80.191156,243.34031 C 82.202996,241.83121 85.125536,236.24432 82.523566,233.55418 C 79.921596,230.86405 73.325156,224.43697 67.209176,223.78085 C 61.093206,223.12471 46.472786,230.41454 44.460956,230.93945 C 42.288186,231.46435 40.651886,233.79361 41.081076,235.46675 z " id="path1277" sodipodi:nodetypes="czzzzzzzzzz" /> </g> <path style="font-size:12px;fill:url(#linearGradient3103);fill-opacity:0.69930001;stroke:#1c66fb;stroke-width:1.77588487;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.99216003" d="M 1.719906,228.8008 C 0.707007,226.11358 1.699602,223.54982 4.115707,223.82273 L 39.85944,231.42887 L 42.064202,239.17285 L 57.663221,242.80011 L 55.387499,234.64685 L 71.471519,237.40138 C 73.597665,238.09302 75.249092,239.52448 76.756518,242.80613 L 93.655366,300.89052 L 19.294782,275.68669 L 1.719906,228.8008 z " id="path1272" sodipodi:nodetypes="ccccccccccc" /> <g id="g1317" transform="translate(-15.816734,-109.09188)"> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:2.07708836" d="M 472.42571,238.27147 C 472.33405,238.27145 472.24478,238.29291 472.15311,238.29398 L 472.15311,238.31648 C 472.08489,238.31034 472.01758,238.29395 471.94867,238.29398 C 471.78809,238.29403 471.63216,238.33557 471.47163,238.33899 L 471.47163,238.42899 C 471.37376,238.41606 471.27556,238.40652 471.17632,238.40649 C 471.1074,238.40647 471.0401,238.42285 470.97187,238.42899 L 470.97187,238.40649 C 470.88021,238.40543 470.79094,238.38396 470.69928,238.38399 C 465.87162,238.38545 461.03877,239.90805 457.81913,242.92943 C 456.20932,244.44011 446.99543,256.8992 450.09559,259.04098 C 457.81097,264.68512 464.49982,248.07035 457.3648,261.85375 C 456.64585,266.58811 456.46107,269.05668 456.41072,270.29207 C 456.30905,268.02898 455.46815,262.72102 451.04967,260.14359 C 447.35854,258.03472 444.93899,276.66261 444.93899,279.18042 C 444.93899,289.25168 451.37986,299.31925 457.81913,303.34776 C 461.08484,305.39084 466.00722,306.3715 470.90372,306.34054 L 470.90372,306.36305 C 471.15408,306.3651 471.40305,306.34374 471.65336,306.34054 L 471.65336,306.22803 C 471.84267,306.23528 472.03155,306.25211 472.22127,306.25053 L 472.22127,306.22803 C 477.11777,306.25899 482.04015,305.27835 485.30586,303.23524 C 491.74513,299.20674 498.186,289.13916 498.186,279.06791 C 498.186,276.5501 495.76645,257.9222 492.07532,260.03107 C 487.65684,262.60851 486.81594,267.91647 486.71427,270.17956 C 486.66392,268.94417 486.47914,266.47559 485.76018,261.74124 C 478.62517,247.95784 485.31402,264.5726 493.0294,258.92847 C 496.12956,256.78669 486.91567,244.32759 485.30586,242.81691 C 482.08622,239.79554 477.25337,238.27293 472.42571,238.27147 z " id="path1267" transform="matrix(1.033174,0,0,0.909383,216.4479,268.3863)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.7041852pt" d="M 468.24591,259.15861 C 468.51094,258.62567 467.79271,252.85171 466.69475,251.35949 C 465.59679,249.86726 463.96768,250.52503 463.70265,251.05797 C 463.43764,251.5909 465.07594,250.88137 466.17389,252.37359 C 467.27185,253.86581 467.9809,259.69155 468.24591,259.15861 z " id="path1270" sodipodi:nodetypes="czzzz" transform="matrix(1.033174,0,0,0.909383,216.4479,268.3863)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.59326982pt" d="M 463.34275,289.21648 C 461.03017,288.99344 460.56786,283.64967 458.96224,286.90958 C 457.28286,290.22776 460.74374,297.34319 461.0482,293.66548 C 461.2789,289.98777 465.58157,289.49777 463.34275,289.21648 z " id="path1278" sodipodi:nodetypes="czzz" transform="matrix(1.033174,0,0,0.909383,216.4479,268.3863)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.68256974pt" d="M 708.64967,503.43717 C 708.37585,502.95253 709.11791,497.70179 710.25229,496.34479 C 711.38666,494.98778 713.06983,495.58594 713.34365,496.07058 C 713.61745,496.55524 711.9248,495.90999 710.79043,497.26699 C 709.65604,498.624 708.92347,503.92182 708.64967,503.43717 z " id="path1283" sodipodi:nodetypes="czzzz" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.57505898pt" d="M 710.57739,531.81732 C 712.96669,531.61449 713.44433,526.75496 715.10322,529.71946 C 716.83831,532.73696 713.26262,539.20762 712.94806,535.86317 C 712.7097,532.51872 708.2643,532.07312 710.57739,531.81732 z " id="path1284" sodipodi:nodetypes="czzz" /> </g> <g id="g1329" transform="translate(-119.89693,-206.8959)"> <path style="fill:#9999ff;fill-rule:evenodd;stroke:#000000;stroke-width:1.87184441" d="M 841.03523,592.70109 C 835.90467,592.7639 830.22818,593.56676 826.67923,597.28291 C 823.87668,600.24935 817.50896,615.99836 816.60602,618.30168 C 815.09992,624.27793 814.05854,630.78886 816.99244,636.56898 C 819.81959,643.25189 825.72828,649.72836 833.94116,650.75621 C 839.37129,651.44267 845.09032,651.35874 850.31458,649.72833 C 856.42815,647.71665 860.44343,642.53509 863.07436,637.37323 C 865.55779,632.40703 865.94287,626.7432 864.51563,621.47197 C 863.89507,618.11627 856.12574,599.89965 853.80199,597.15457 C 850.54532,594.03086 845.67202,592.69881 841.03523,592.70109 z " id="path1288" sodipodi:nodetypes="cccccccccc" transform="translate(-3.661113,-7.322226)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.63460236pt" d="M 838.07247,610.64237 C 839.95513,610.18459 838.75317,605.01626 837.71507,603.73449 C 836.67696,602.45272 829.77408,601.13926 832.78769,603.68422 C 836.03445,606.02046 835.95665,611.10014 838.07247,610.64237 z " id="path1289" sodipodi:nodetypes="czzz" transform="translate(-3.661113,-7.322226)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.53464689pt" d="M 835.74471,629.3768 C 833.5582,629.18522 829.82379,631.67928 828.30569,634.47943 C 826.71786,637.32962 829.99008,643.44151 830.27794,640.28249 C 830.49606,637.12348 837.86149,629.61842 835.74471,629.3768 z " id="path1290" sodipodi:nodetypes="czzz" transform="translate(-3.661113,-7.322226)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.63460231pt" d="M 842.27092,610.67154 C 840.38825,610.21376 841.59021,605.04542 842.62832,603.76366 C 843.66642,602.48189 850.5693,601.16843 847.5557,603.71338 C 844.30893,606.04963 844.38672,611.12931 842.27092,610.67154 z " id="path1293" sodipodi:nodetypes="czzz" transform="translate(-3.661113,-7.322226)" /> <path style="fill-rule:evenodd;stroke:#000000;stroke-width:0.53464689pt" d="M 844.89363,628.76239 C 847.08014,628.57081 850.81456,631.06487 852.33265,633.86502 C 853.92048,636.71521 850.64827,642.8271 850.3604,639.66808 C 850.14228,636.50907 842.77686,629.00401 844.89363,628.76239 z " id="path1310" sodipodi:nodetypes="czzz" transform="translate(-3.661113,-7.322226)" /> </g> <path sodipodi:type="arc" style="font-size:12px;fill:url(#radialGradient704);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.87644994;stroke-dasharray:none" id="path1268" sodipodi:cx="271.35837" sodipodi:cy="796.11926" sodipodi:rx="37.428738" sodipodi:ry="37.428738" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" transform="matrix(1.269231,0,0,1.209574,-283.07311,-892.5522)" /> <path style="font-size:12px;fill:url(#linearGradient3087);fill-opacity:0.38016998;fill-rule:evenodd;stroke:none;stroke-width:1pt" d="M 61.332105,24.771938 C 42.107405,24.771938 25.653025,35.754928 18.178255,51.420348 C 24.096425,54.452298 30.701605,57.324498 38.485955,55.238068 C 53.103085,52.045758 57.672575,44.520268 64.981135,41.327978 C 80.301015,40.755428 87.638095,48.625568 102.74077,48.283028 C 94.643305,34.332978 79.234085,24.771948 61.332105,24.771938 z " id="path1269" /> <text xml:space="preserve" style="font-size:53.10573959px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial Black" x="16.672869" y="102.03138" id="text1284" sodipodi:linespacing="100%" transform="scale(1.1590137,0.8628026)"><tspan x="16.672869" y="102.03138" sodipodi:role="line" id="tspan1287">3D</tspan></text> <path transform="matrix(1.002448,0,0,1.002916,-160.88153,-16.03236)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path2785" style="font-size:12px;fill:url(#radialGradient2803);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.87644994;stroke-dasharray:none" sodipodi:type="arc" /> <g id="g3768" transform="matrix(0,1,-1,0,1076.3543,565.51512)"> <path sodipodi:nodetypes="cccsccsc" id="path3705" d="M 194.12568,840.84063 C 188.41896,847.02146 185.33319,854.75383 182.33294,863.19906 L 201.47506,868.27409 C 189.87912,850.75552 209.12233,847.41039 223.32691,857.48974 C 237.53151,867.56909 241.4625,879.07179 233.76248,898.27256 L 238.42629,908.56618 C 253.06732,892.90031 247.20739,863.37366 228.90023,852.45953 C 205.99771,838.8058 192.17055,859.34731 194.12568,840.84063 z " style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" /> <path sodipodi:nodetypes="cccsccsc" id="path3766" d="M 223.43826,925.93726 C 229.14498,919.75643 232.23075,912.02406 235.231,903.57883 L 216.08888,898.5038 C 227.68482,916.02237 208.44161,919.3675 194.23703,909.28815 C 180.03243,899.2088 176.10144,887.7061 183.80146,868.50533 L 179.13765,858.21171 C 164.49662,873.87758 170.35655,903.40423 188.66371,914.31836 C 211.56623,927.97209 225.39339,907.43058 223.43826,925.93726 z " style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" /> </g> <g id="g3772" transform="matrix(0,0.616295,-0.828342,0,1009.0693,633.18962)"> <path sodipodi:nodetypes="cccsccsc" id="path3774" d="M 194.12568,840.84063 C 188.41896,847.02146 185.33319,854.75383 182.33294,863.19906 L 201.47506,868.27409 C 189.87912,850.75552 209.12233,847.41039 223.32691,857.48974 C 237.53151,867.56909 241.4625,879.07179 233.76248,898.27256 L 238.42629,908.56618 C 253.06732,892.90031 247.20739,863.37366 228.90023,852.45953 C 205.99771,838.8058 192.17055,859.34731 194.12568,840.84063 z " style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" /> <path sodipodi:nodetypes="cccsccsc" id="path3776" d="M 223.43826,925.93726 C 229.14498,919.75643 232.23075,912.02406 235.231,903.57883 L 216.08888,898.5038 C 227.68482,916.02237 208.44161,919.3675 194.23703,909.28815 C 180.03243,899.2088 176.10144,887.7061 183.80146,868.50533 L 179.13765,858.21171 C 164.49662,873.87758 170.35655,903.40423 188.66371,914.31836 C 211.56623,927.97209 225.39339,907.43058 223.43826,925.93726 z " style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" /> </g> <path style="fill:url(#linearGradient4441);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 417.63823,503.43887 C 418.93809,498.49321 401.59543,483.35417 398.57534,480.66632 C 395.46997,477.90258 384.35781,464.40329 381.52358,466.5834 C 378.58446,468.84421 384.30056,470.67943 386.30587,471.58949 C 388.31117,472.49955 396.55321,481.98821 401.26761,486.50842 C 406.07073,491.11369 414.05679,499.07672 417.63823,503.43887 z " id="path4436" sodipodi:nodetypes="czzzzc" /> <g id="g2679" transform="translate(127.72341,250.99136)"> <path transform="matrix(1.269231,0,0,1.209574,-396.41645,-273.48229)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path6385" style="font-size:12px;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#9999ff;stroke-width:1.875;stroke-dasharray:none;stroke-opacity:1" sodipodi:type="arc" /> <path id="path6387" d="M -39.445387,646.81506 L -39.445387,679.12754 L -63.481447,679.12754 L -63.481447,668.7547 C -63.481447,668.7547 -63.462347,668.72431 -87.874467,689.08992 L -63.997067,708.26846 L -63.997067,698.67919 L -39.445387,698.67919 L -39.445387,731.96178 C -19.935277,726.40164 -5.6521274,709.51231 -5.6521174,689.35111 C -5.6521074,669.19381 -19.941107,652.37858 -39.445387,646.81506 z " style="font-size:12px;fill:url(#linearGradient6399);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-opacity:1" /> <path id="path6389" d="M -52.60387,643.06675 C -71.82857,643.06675 -88.28295,654.04974 -95.75772,669.71516 C -89.83955,672.74711 -83.23437,675.61931 -75.45002,673.53288 C -60.83289,670.34057 -56.2634,662.81508 -48.95484,659.62279 C -33.63496,659.05024 -26.29788,666.92038 -11.19521,666.57784 C -19.29267,652.62779 -34.70189,643.06676 -52.60387,643.06675 z " style="font-size:12px;fill:url(#linearGradient6401);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1pt" /> <path transform="matrix(1.269231,0,3.7103497e-3,1.209574,-398.23172,-273.72923)" d="M 308.78711 796.11926 A 37.428738 37.428738 0 1 1 233.92963,796.11926 A 37.428738 37.428738 0 1 1 308.78711 796.11926 z" sodipodi:ry="37.428738" sodipodi:rx="37.428738" sodipodi:cy="796.11926" sodipodi:cx="271.35837" id="path6391" style="font-size:12px;fill:url(#radialGradient6403);fill-opacity:0.5;fill-rule:evenodd;stroke:none;stroke-width:1.875;stroke-dasharray:none;stroke-opacity:1" sodipodi:type="arc" /> </g> <flowRoot xml:space="preserve" id="flowRoot11253" transform="matrix(2.6418545,0,0,2.7544595,1761.6523,94.933864)"><flowRegion id="flowRegion11255"><rect id="rect11257" width="358.03708" height="133.35794" x="-489.9455" y="234.82002" /></flowRegion><flowPara id="flowPara11259">153 153 255</flowPara></flowRoot> <path style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#e80000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 279.19648,907.10288 C 273.31714,906.18832 254.20929,903.57528 250.19174,907.23353 C 246.5112,910.58491 242.70536,923.39061 246.66413,928.26851 C 249.47779,931.73543 254.82989,928.6278 267.82976,932.31872 C 280.82963,936.00964 287.11749,943.54535 298.66362,943.03218 C 307.48263,942.64023 308.06808,940.90589 310.29166,937.67545 C 312.40306,934.60797 310.81821,929.18158 310.42231,928.13786 C 308.98513,924.34895 302.44264,917.85122 297.87971,914.55004 C 293.19098,911.15785 282.07083,907.23354 279.19648,907.10288 z " id="path2678" sodipodi:nodetypes="czszssssc" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="45.143608" inkscape:export-ydpi="45.143608" /> <path style="fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:#e80000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 287.7957,882.82029 C 282.34097,888.30767 274.27322,923.4204 287.27309,927.11132 C 300.27296,930.80224 314.92255,930.76014 327.51389,932.86001 C 336.22135,934.31216 340.73969,924.10168 340.97106,920.18677 C 341.38398,913.19973 339.0792,901.48386 326.86063,890.92071 C 314.52634,880.25752 293.38107,877.20226 287.7957,882.82029 z " id="path2680" sodipodi:nodetypes="czsszz" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="45.143608" inkscape:export-ydpi="45.143608" /> <path style="fill:#00ff00;fill-opacity:1;fill-rule:evenodd;stroke:#e80000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 264.58065,887.18507 C 258.37906,892.56924 241.86857,906.00903 252.69131,914.75265 C 263.43519,923.43255 273.41622,925.32602 286.00756,927.42589 C 294.71502,928.87804 309.20089,895.65779 296.98232,885.09464 C 284.64803,874.43145 270.7074,881.86587 264.58065,887.18507 z " id="path2682" sodipodi:nodetypes="czszz" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="45.143608" inkscape:export-ydpi="45.143608" /> <path style="fill:#00ffff;fill-opacity:1;fill-rule:evenodd;stroke:#e80000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 290.92757,880.99004 C 289.79075,881.42333 288.84449,882.00654 288.14632,882.70879 C 282.69159,888.1962 274.6152,923.29912 287.61507,926.99004 C 287.79114,927.04003 287.96966,927.09766 288.14632,927.14629 C 296.8599,924.47318 308.74865,894.82709 297.33382,884.95879 C 295.23315,883.14273 293.07489,881.85608 290.92757,880.99004 z " id="path2684" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="45.143608" inkscape:export-ydpi="45.143608" /> <path style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#ffff00;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 259.64577,905.56358 C 255.38842,905.5919 251.77735,906.06674 250.27077,907.43858 C 249.91517,907.76238 249.52784,908.20395 249.17702,908.68858 C 249.1777,908.69901 249.1763,908.70941 249.17702,908.71983 C 249.33048,910.93718 250.38312,913.06611 252.73952,914.96983 C 263.48339,923.64972 273.49193,925.52621 286.08327,927.62608 C 289.84207,928.25294 294.65885,922.43464 297.95827,914.75108 C 293.26951,911.35891 282.14512,907.44424 279.27077,907.31358 C 275.59618,906.74198 266.74136,905.51637 259.64577,905.56358 z " id="path2686" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="45.143608" inkscape:export-ydpi="45.143608" /> <path style="fill:#ff00ff;fill-opacity:1;fill-rule:evenodd;stroke:#e80000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 280.82099,907.53045 C 280.06054,916.85265 281.46695,925.60102 287.60224,927.34295 C 295.24836,929.51385 303.44418,930.37199 311.47724,931.15545 C 311.25105,929.83044 310.91163,928.77791 310.75849,928.3742 C 309.3213,924.58531 302.79017,918.08163 298.22724,914.78045 C 294.06816,911.77148 284.85701,908.35766 280.82099,907.53045 z " id="path2688" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="45.143608" inkscape:export-ydpi="45.143608" /> <path style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffff00;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 280.77068,907.60226 C 280.00332,916.86703 281.43457,925.5553 287.66599,927.28675 C 287.78134,927.3188 287.89992,927.34855 288.01552,927.38004 C 291.46668,926.29971 295.38858,921.19722 298.21548,914.7546 C 294.07186,911.82087 284.99704,908.50815 280.77068,907.60226 z " id="path2690" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="45.143608" inkscape:export-ydpi="45.143608" /> <path style="fill:#fffcff;fill-opacity:0.76973683;fill-rule:evenodd;stroke:#e80000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3825)" d="M 264.58065,887.18507 C 258.37906,892.56924 241.86857,906.00903 252.69131,914.75265 C 258.06325,919.0926 259.85685,909.80969 258.75146,904.08527 C 258.17203,901.08461 279.46815,887.45077 280.8547,887.17526 C 289.36706,885.48382 309.20089,895.07445 296.98232,884.5113 C 284.64803,873.84811 270.7074,881.86587 264.58065,887.18507 z " id="path2692" sodipodi:nodetypes="czsszz" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="45.143608" inkscape:export-ydpi="45.143608" /> <path style="fill:#f0fcff;fill-opacity:1;fill-rule:evenodd;stroke:#e80000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter4043);opacity:0.46111111" d="M 287.7957,882.82029 C 282.34097,888.30767 290.70403,885.01703 303.7039,888.70795 C 310.20384,890.55341 329.34209,902.71925 332.09568,913.03342 C 334.84928,923.34759 321.21822,931.81007 327.51389,932.86001 C 336.22135,934.31216 339.76745,924.1989 339.99882,920.28399 C 340.41174,913.29695 338.88475,902.16443 326.66618,891.60128 C 314.33189,880.93809 293.38107,877.20226 287.7957,882.82029 z " id="path3829" sodipodi:nodetypes="czssszz" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="45.143608" inkscape:export-ydpi="45.143608" /> <path style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#e80000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3995);opacity:0.46666667" d="M 279.19648,907.10288 C 273.31714,906.18832 254.20929,903.57528 250.19174,907.23353 C 246.5112,910.58491 246.55517,919.05709 251.0392,914.65718 C 254.14453,911.61011 297.80278,918.61376 300.78861,921.91578 C 303.86342,925.31622 308.06808,940.90589 310.29166,937.67545 C 312.40306,934.60797 310.81821,929.18158 310.42231,928.13786 C 308.98513,924.34895 302.44264,917.85122 297.87971,914.55004 C 293.19098,911.15785 282.07083,907.23354 279.19648,907.10288 z " id="path3857" sodipodi:nodetypes="czszsssc" inkscape:export-filename="C:\pas\mricron\btn\icon.png" inkscape:export-xdpi="45.143608" inkscape:export-ydpi="45.143608" /> <g id="g2692" transform="translate(674.26081,392.08118)"> <path sodipodi:nodetypes="cccccczcc" id="rect16944" d="M -101.23452,555.91137 L -135.72917,591.54155 L -135.67885,595.00168 C -135.67885,595.00168 -135.69605,596.90777 -134.07752,596.90776 L -63.022358,596.90776 C -61.344963,596.90776 -59.052197,595.93775 -57.904377,594.72045 C -57.904377,594.72045 -26.337149,560.6591 -25.935153,559.8182 C -25.515851,558.94109 -25.61801,554.93919 -25.61801,554.93919 L -101.23452,555.91137 z " style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-width:1.58905315;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:14;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> <g transform="matrix(1,0,-0.7279374,0.7757272,410.51129,124.1268)" id="g16937"> <rect rx="2.2872064" style="opacity:1;fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-width:1.79999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:14;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" id="rect16931" width="76.767708" height="48.723415" x="-108.35294" y="554.36353" ry="2.8327568" /> <rect style="opacity:1;fill:#666666;fill-opacity:1;stroke:none;stroke-width:0.98140889;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:14;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" id="rect16933" width="63.422516" height="22.064268" x="-101.68034" y="557.35358" ry="1.2828063" /> <rect style="opacity:1;fill:#999999;fill-opacity:1;stroke:none;stroke-width:0.98140889;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:14;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" id="rect16935" width="19.798063" height="15.832203" x="-79.868118" y="583.83984" ry="0.92047691" /> </g> <rect transform="matrix(1,0,-0.1383274,0.9903866,0,0)" ry="2.8602536" y="510.54825" x="-26.254177" height="49.196362" width="76.767708" id="rect16919" style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-width:1.80871499;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:14;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> <rect transform="matrix(1,0,-0.1383274,0.9903866,0,0)" y="514.40961" x="-20.871944" height="41.473679" width="66.003235" id="rect16921" style="fill:url(#linearGradient2702);fill-opacity:1;stroke:none;stroke-width:2.90499997;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> <path id="path16956" d="M -92.277435,594.51054 L -64.16994,594.51054" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> </g> <g id="g2685" transform="translate(582.18114,338.61556)"> <rect transform="matrix(0.9713022,0.2378487,-0.5171396,0.855901,0,0)" y="508.92459" x="94.426369" height="60.465881" width="77.145607" id="rect2697" style="opacity:1;fill:#9999ff;fill-opacity:1;stroke:#000000;stroke-width:7.98921967;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> <path sodipodi:nodetypes="cccccccccc" d="M -117.44468,481.34737 C -116.8448,484.69863 -133.55429,489.06659 -134.22773,490.99385 C -135.61163,493.12351 -124.78314,498.17939 -127.71818,500.70189 C -129.5925,504.50435 -158.49967,506.43937 -165.22499,505.25897 C -166.06446,504.57579 -166.21006,503.01216 -164.67268,502.07743 C -160.5694,500.45465 -140.39449,501.84269 -133.73254,499.40077 C -133.14809,498.3747 -140.78872,493.21278 -138.4452,490.4823 C -135.98802,487.11788 -120.9359,483.60551 -121.16622,481.62624 C -123.3344,479.39272 -140.13087,475.87842 -142.12303,473.95 C -142.12303,473.95 -120.27517,478.54207 -117.44468,481.34737 z " id="path4659" style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter3996)" /> <rect transform="matrix(0.9713022,0.2378487,-0.5171396,0.855901,-1.485156,0)" y="508.17789" x="94.419182" height="60.465874" width="77.145607" id="rect2920" style="opacity:0.90659335;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.43310034;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter3943)" /> <path sodipodi:nodetypes="czzzzc" id="path4643" d="M -146.10287,435.77043 C -150.13633,433.93962 -160.81303,460.49087 -163.95326,471.903 C -167.02949,483.08255 -166.36953,503.35123 -164.3485,503.49605 C -162.07868,503.6587 -158.59997,498.57336 -157.34041,493.95863 C -156.09656,489.40146 -151.23529,478.15716 -150.04903,469.04377 C -149.17527,459.93038 -143.83082,437.24117 -146.10287,435.77043 z " style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> <path sodipodi:nodetypes="czzzzc" id="path4645" d="M -158.59661,464.49301 C -159.99659,468.59609 -161.62828,471.41835 -162.79655,476.80223 C -163.96481,482.3724 -165.63291,496.14896 -164.72285,498.41272 C -163.81278,500.67648 -162.48409,499.18142 -161.57403,497.17611 C -160.66397,495.17081 -161.12497,484.96734 -160.83782,480.52595 C -160.62631,476.08455 -159.0754,471.78897 -158.59661,464.49301 z " style="fill:url(#linearGradient4653);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> </g> </g> </svg> ���������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/������������������������������������������������������������0000755�0001750�0001750�00000000000�12360763370�015466� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/regmult.pas�������������������������������������������������0000755�0001750�0001750�00000013304�11326425444�017654� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Program REGMULT.PAS * * Version 1.1 * * (c) J. Debord, August 2000 * ********************************************************************** This program performs a weighted multiple linear least squares fit : y = b0 + b1 * x1 + b2 * x2 + ... The following parameters are passed on the command line : 1st parameter = name of input file (default extension = .DAT) 2nd parameter = 1 if the equation includes a constant term b0 Input files are ASCII files with the following structure : Line 1 : Title of study Line 2 : Number of variables (must be >= 2 here !) Next lines : Names of variables x1, x2, ..., y Next line : Number of observations (must be > number of variables !) The next lines contain the coordinates (x1, x2, ..., y) of the observations (1 observation by line). The coordinates must be separated by spaces or tabulations. The file INHIB.DAT is an example of data relating the inhibition of an enzyme to the physico-chemical properties of the inhibitors (J. DEBORD, P. N'DIAYE, J. C. BOLLINGER et al, J. Enzyme Inhib., 1997, 12, 13-26). The program parameters are : INHIB 1 The program may be executed from Turbo Pascal's integrated environment, in which case the parameters are entered through the "Parameters" option of the menu, or from DOS (after compilation into an executable file), in which case the parameters are entered on the command line (e.g. REGMULT INHIB 1). ********************************************************************** } unit regmult; interface uses SysUtils,utypes,umulfit,classes,define_types,dialogs; function MultipleRegressionVec (lnObservations,lnFactors: integer; var X: PMatrix; var Y: PVector; var lOutT,lOutSlope: DoubleP0): boolean; function MultipleRegression (lnObservations,lnFactors: integer; var X: PMatrix; var lImgIntensity: DoubleP0; var lOutT: DoubleP0): boolean; implementation uses usvdfit,uregtest; (*procedure WriteResults(NVar: integer; var lOutT,lOutSlope: DoubleP0); var I: integer; lStr: string; begin for I := 0 to Nvar do begin lStr := floattostr(lOutT^[I]) +' '+floattostr(lOutSlope[I]); Form1.memo1.lines.add(lStr); end; end; *) function MultipleRegressionVec (lnObservations,lnFactors: integer; var X: PMatrix; var Y: PVector; var lOutT,lOutSlope: DoubleP0): boolean; var //lmax,lmin: float; XX : PMatrix; { Independent variables } //YY : PVector; { Dependent variable } Ycalc : PVector; { Computed Y values } B : PVector; { Fitted parameters } V : PMatrix; { Variance-covariance matrix } Test : TRegTest; { Statistical tests } lVar : Float; { Variance for t value } Lb,I, J : Integer; { Loop variable } ConsTerm : boolean; { Include a constant term B(0) } begin result := false; ConsTerm := true; { Dimension arrays } DimMatrix(XX, lnObservations, lnFactors); //DimVector(YY, lnObservations); DimVector(Ycalc, lnObservations); DimVector(B, lnFactors); DimMatrix(V, lnFactors, lnFactors); { Read data } for I := 1 to lnObservations do begin for J := 1 to lnFactors do begin XX^[I]^[J] := X^[J]^[I];//Designed to be compatible with old versions of fpmath end; end; (* lmin := X^[1]^[1]; lmax := X^[1]^[1]; for I := 1 to lnFactors do begin for J := 1 to lnObservations do begin if X^[I]^[J] > lmax then lMax := X^[I]^[J]; if X^[I]^[J] < lmin then lMin := X^[I]^[J]; end; end; fx(lmin,lmax);*) { Perform regression } // MulFit(XX, Y, 1, lnObservations, lnFactors, ConsTerm, B, V); SVDFit(XX, Y, 1, lnObservations, lnFactors, ConsTerm, 1.0E-8, B, V); { Compute predicted Y values } for I := 1 to lnObservations do begin if ConsTerm then Ycalc^[I] := B^[0] else Ycalc^[I] := 0.0; for J := 1 to lnFactors do Ycalc^[I] := Ycalc^[I] + B^[J] * XX^[I]^[J]; end; { Update variance-covariance matrix and compute statistical tests } if ConsTerm then Lb := 0 else Lb := 1; RegTest(Y, Ycalc, 1, lnObservations, V, Lb, lnFactors, Test); //output Slopes for I := 0 to (lnFactors-1) do lOutSlope^[I] := B^[I+1];//first parameter is global fit lOutSlope^[lnFactors] := B^[0];//global fit //T scores for I := 0 to (lnFactors-1) do begin lVar :=Sqrt(V^[I+1]^[I+1]); //fx(lVar,B^[I+1]); if lVar <> 0 then lOutT^[I] := B^[I+1] / lVar else lOutT^[I] := 0; end; lvar := Sqrt(V^[0]^[0]); if lvar <> 0 then lOutT^[lnFactors] := B^[0]/ lvar //global fit else lOutT^[lnFactors] := 0; //cleanup DelMatrix(XX, lnObservations, lnFactors); //DelVector(YY, lnObservations); DelVector(Ycalc, lnObservations); DelVector(B, lnFactors); DelMatrix(V, lnFactors,lnFactors); result := true; end; function MultipleRegression (lnObservations,lnFactors: integer; var X: PMatrix; var lImgIntensity: DoubleP0; var lOutT: DoubleP0): boolean; var I: integer; Y : PVector; { Dependent variable } lOutSlope: DoubleP0; begin DimVector(Y, lnObservations); Getmem(lOutSlope,(lnObservations+1)*sizeof(double)); { Read data } for I := 1 to lnObservations do Y^[I] := lImgIntensity^[I-1]; result := MultipleRegressionVec (lnObservations,lnFactors,X, Y, lOutT,lOutSlope); Freemem(lOutslope); DelVector(Y,lnObservations); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uranmwc.pas�������������������������������������������������0000755�0001750�0001750�00000002255�11326425446�017656� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Marsaglia's Multiply-With-Carry random number generator ****************************************************************** } unit uranmwc; interface procedure InitMWC(Seed : LongInt); { ------------------------------------------------------------------ Initializes the 'Multiply with carry' random number generator. ------------------------------------------------------------------ } function IRanMWC : LongInt; { ------------------------------------------------------------------ Returns a 32 bit random number in [-2^31 ; 2^31-1] ------------------------------------------------------------------ } implementation var X1, X2 : LongInt; { Uniform random integers } C1, C2 : LongInt; { Carries } procedure InitMWC(Seed : LongInt); begin X1 := Seed shr 16; X2 := Seed and 65535; C1 := 0; C2 := 0; end; function IRanMWC : LongInt; var Y1, Y2 : LongInt; begin Y1 := 18000 * X1 + C1; X1 := Y1 and 65535; C1 := Y1 shr 16; Y2 := 30903 * X2 + C2; X2 := Y2 and 65535; C2 := Y2 shr 16; IRanMWC := (X1 shl 16) + (X2 and 65535); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uinvgam.pas�������������������������������������������������0000755�0001750�0001750�00000010001�11326425444�017632� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Inverses of incomplete Gamma function and Khi-2 distribution Translated from C code in Cephes library (http://www.moshier.net) ****************************************************************** } unit uinvgam; interface uses utypes, ugamma, uigamma, uinvnorm; function InvGamma(A, P : Float) : Float; { ------------------------------------------------------------------ Given P, the function finds X such that IGamma(A, X) = P It is best valid in the right-hand tail of the distribution, P > 0.5 ------------------------------------------------------------------ } function InvKhi2(Nu : Integer; P : Float) : Float; { ------------------------------------------------------------------ Inverse of Khi-2 distribution function Returns the argument, X, for which the area under the Khi-2 probability density function (integrated from 0 to X) is equal to P. ------------------------------------------------------------------ } implementation function InvGamma(A, P : Float) : Float; var x0, x1, x, Y, yl, yh, y1, d, lgm, dithresh : Float; i, ndir : Integer; label ihalve, cont, cont1, done; begin if P > 0.5 then SetErrCode(FPLoss) else SetErrCode(FOk); Y := 1.0 - P; { Bound the solution } x0 := MaxNum; yl := 0.0; x1 := 0.0; yh := 1.0; dithresh := 5 * MachEp; { Approximation to inverse function } d := 1.0 / (9.0 * a); y1 := 1.0 - d - InvNorm(Y) * sqrt(d); x := a * y1 * y1 * y1; lgm := LnGamma(a); for i := 0 to 9 do begin if (x > x0) or (x < x1) then goto ihalve; y1 := JGamma(a, x); if (y1 < yl) or (y1 > yh) then goto ihalve; if y1 < Y then begin x0 := x; yl := y1 end else begin x1 := x; yh := y1 end; { Compute the derivative of the function at this point } d := (a - 1) * Ln(x) - x - lgm; if d < MinLog then goto ihalve; d := -exp(d); { Compute the step to the next approximation of x } d := (y1 - Y) / d; if abs(d / x) < MachEp then goto done; x := x - d; end; { Resort to interval halving if Newton iteration did not converge } ihalve: d := 0.0625; if x0 = MaxNum then begin if x <= 0 then x := 1; while x0 = MaxNum do begin x := (1 + d) * x; y1 := JGamma(a, x); if y1 < Y then begin x0 := x; yl := y1; goto cont end; d := d + d end end; cont: d := 0.5; ndir := 0; for i := 0 to 399 do begin x := x1 + d * (x0 - x1); y1 := JGamma(a, x); lgm := (x0 - x1) / (x1 + x0); if abs(lgm) < dithresh then goto cont1; lgm := (y1 - Y) / Y; if abs(lgm) < dithresh then goto cont1; if x <= 0 then goto cont1; if y1 >= Y then begin x1 := x; yh := y1; if ndir < 0 then begin ndir := 0; d := 0.5 end else if ndir > 1 then d := 0.5 * d + 0.5 else d := (Y - yl) / (yh - yl); ndir := ndir + 1; end else begin x0 := x; yl := y1; if ndir > 0 then begin ndir := 0; d := 0.5 end else if ndir < -1 then d := 0.5 * d else d := (Y - yl) / (yh - yl); ndir := ndir - 1; end; end; cont1: if x = 0 then SetErrCode(FUnderflow); done: InvGamma := x end; function InvKhi2(Nu : Integer; P : Float) : Float; { ------------------------------------------------------------------ Inverse of Khi-2 distribution function Returns the argument, X, for which the area under the Khi-2 probability density function (integrated from 0 to X) is equal to P. ------------------------------------------------------------------ } begin if (P < 0.0) or (P > 1.0) or (Nu < 1) then InvKhi2 := DefaultVal(FDomain, 0.0) else InvKhi2 := 2.0 * InvGamma(0.5 * Nu, P); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ubroyden.pas������������������������������������������������0000755�0001750�0001750�00000012370�11326425444�020026� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Broyden method for system of nonlinear equations ****************************************************************** } unit ubroyden; interface uses utypes, ulinminq, ucompvec; procedure Broyden(Equations : TEquations; X, F : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float); { ------------------------------------------------------------------ Solves a system of nonlinear equations by Broyden's method ------------------------------------------------------------------ Input parameters : Equations = subroutine to compute equations X = initial roots Lb, Ub = bounds of X MaxIter = maximum number of iterations Tol = required precision ------------------------------------------------------------------ Output parameters : X = refined roots F = function values ------------------------------------------------------------------ Possible results : OptOk = no error OptNonConv = non-convergence ------------------------------------------------------------------ } implementation procedure Broyden(Equations : TEquations; X, F : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float); var I, J, K, Iter : Integer; A, DeltaXmax, Fmax, P, Q, R, S : Float; Conv : Boolean; OldX, DeltaX, dX, OldF, dF, DdF : PVector; Dinv : PMatrix; procedure Terminate(ErrCode : Integer); { Set error code and deallocate arrays } begin DelVector(OldX, Ub); DelVector(DeltaX, Ub); DelVector(dX, Ub); DelVector(OldF, Ub); DelVector(dF, Ub); DelVector(DdF, Ub); DelMatrix(Dinv, Ub, Ub); SetErrCode(ErrCode); end; begin { Initialize function vector } Equations(X, F); { Quit if no iteration required } if MaxIter < 1 then begin SetErrCode(OptOk); Exit; end; { Dimension arrays } DimVector(OldX, Ub); DimVector(DeltaX, Ub); DimVector(dX, Ub); DimVector(OldF, Ub); DimVector(dF, Ub); DimVector(DdF, Ub); DimMatrix(Dinv, Ub, Ub); { Initialize inverse jacobian to unit matrix } for I := Lb to Ub do begin Dinv^[I]^[I] := 1.0; for J := I + 1 to Ub do begin Dinv^[I]^[J] := 0.0; Dinv^[J]^[I] := 0.0 end; end; Iter := 0; { Compute max. function component } Fmax := Abs(F^[Lb]); for I := Lb + 1 to Ub do begin A := Abs(F^[I]); if A > Fmax then Fmax := A; end; { Quit if function vector is already small } if Fmax < MachEp then begin Terminate(OptOk); Exit; end; { Initialize search direction } for I := Lb to Ub do DeltaX^[I] := - F^[I]; repeat { Prepare next iteration } Iter := Iter + 1; if Iter > MaxIter then begin Terminate(OptNonConv); Exit; end; { Normalize search direction to avoid excessive displacements } DeltaXmax := Abs(DeltaX^[Lb]); for I := Lb + 1 to Ub do begin A := Abs(DeltaX^[I]); if A > DeltaXmax then DeltaXmax := A; end; if DeltaXmax > 1.0 then for I := Lb to Ub do DeltaX^[I] := DeltaX^[I] / DeltaXmax; { Save old parameters and functions } for I := Lb to Ub do begin OldX^[I] := X^[I]; OldF^[I] := F^[I]; end; { Minimize along the direction specified by DeltaX, with initial step R = 1, and compute new function } R := 1.0; LinMinEq(Equations, X, DeltaX, F, Lb, Ub, R, 10, 0.01); Equations(X, F); { Compute differences between two successive estimations of parameter vector and function vector } for I := Lb to Ub do begin dX^[I] := X^[I] - OldX^[I]; dF^[I] := F^[I] - OldF^[I]; end; { Multiply by inverse jacobian } for I := Lb to Ub do begin DdF^[I] := 0.0; for J := Lb to Ub do DdF^[I] := DdF^[I] + Dinv^[I]^[J] * dF^[J]; end; { Scalar product in denominator of Broyden formula } P := 0.0; for I := Lb to Ub do P := P + dX^[I] * DdF^[I]; if P = 0.0 then Exit; { Inverse of scalar product } Q := 1.0 / P; { Update inverse jacobian } for I := Lb to Ub do begin A := (dX^[I] - DdF^[I]) * Q; for J := Lb to Ub do begin S := 0.0; for K := Lb to Ub do S := S + dX^[K] * Dinv^[K]^[J]; Dinv^[I]^[J] := Dinv^[I]^[J] + A * S; end; end; { Update search direction } for I := Lb to Ub do begin DeltaX^[I] := 0.0; for J := Lb to Ub do DeltaX^[I] := DeltaX^[I] - Dinv^[I]^[J] * F^[J]; end; { Test for convergence } Conv := CompVec(X, OldX, Lb, Ub, Tol); until Conv; Terminate(OptOk); end; end.������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ulineq.pas��������������������������������������������������0000755�0001750�0001750�00000010620�11326425444�017470� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Solution of a system of linear equations with a single constant vector by Gauss-Jordan method ****************************************************************** } unit ulineq; interface uses utypes, uminmax; procedure LinEq(A : PMatrix; B : PVector; Lb, Ub : Integer; var Det : Float); { ------------------------------------------------------------------ Solves a linear system according to the Gauss-Jordan method ------------------------------------------------------------------ Input parameters : A = system matrix B = constant vector Lb, Ub = lower and upper array bounds ------------------------------------------------------------------ Output parameters : A = inverse matrix B = solution vector Det = determinant of A ------------------------------------------------------------------ Possible results : MatOk : No error MatSing : Singular matrix ------------------------------------------------------------------ } implementation procedure LinEq(A : PMatrix; B : PVector; Lb, Ub : Integer; var Det : Float); var Pvt : Float; { Pivot } Ik, Jk : Integer; { Pivot's row and column } I, J, K : Integer; { Loop variables } T : Float; { Temporary variable } PRow, PCol : PIntVector; { Stores pivot's row and column } MCol : PVector; { Stores a column of matrix A } procedure Terminate(ErrCode : Integer); { Set error code and deallocate arrays } begin DelIntVector(PRow, Ub); DelIntVector(PCol, Ub); DelVector(MCol, Ub); SetErrCode(ErrCode); end; begin DimIntVector(PRow, Ub); DimIntVector(PCol, Ub); DimVector(MCol, Ub); Det := 1.0; K := Lb; while K <= Ub do begin { Search for largest pivot in submatrix A[K..Ub, K..Ub] } Pvt := A^[K]^[K]; Ik := K; Jk := K; for I := K to Ub do for J := K to Ub do if Abs(A^[I]^[J]) > Abs(Pvt) then begin Pvt := A^[I]^[J]; Ik := I; Jk := J; end; { Store pivot's position } PRow^[K] := Ik; PCol^[K] := Jk; { Update determinant } Det := Det * Pvt; if Ik <> K then Det := - Det; if Jk <> K then Det := - Det; { Too weak pivot ==> quasi-singular matrix } if Abs(Pvt) < MachEp then begin Terminate(MatSing); Exit end; { Exchange current row (K) with pivot row (Ik) } if Ik <> K then begin for J := Lb to Ub do FSwap(A^[Ik]^[J], A^[K]^[J]); FSwap(B^[Ik], B^[K]); end; { Exchange current column (K) with pivot column (Jk) } if Jk <> K then for I := Lb to Ub do FSwap(A^[I]^[Jk], A^[I]^[K]); { Store column K of matrix A into MCol and set this column to zero } for I := Lb to Ub do if I <> K then begin MCol^[I] := A^[I]^[K]; A^[I]^[K] := 0.0; end else begin MCol^[I] := 0.0; A^[I]^[K] := 1.0; end; { Transform pivot row } T := 1.0 / Pvt; for J := Lb to Ub do A^[K]^[J] := T * A^[K]^[J]; B^[K] := T * B^[K]; { Transform other rows } for I := Lb to Ub do if I <> K then begin T := MCol^[I]; for J := Lb to Ub do A^[I]^[J] := A^[I]^[J] - T * A^[K]^[J]; B^[I] := B^[I] - T * B^[K]; end; Inc(K); end; { Exchange lines of inverse matrix and solution vector } for I := Ub downto Lb do begin Ik := PCol^[I]; if Ik <> I then for J := Lb to Ub do FSwap(A^[I]^[J], A^[Ik]^[J]); FSwap(B^[I], B^[Ik]); end; { Exchange columns of inverse matrix } for J := Ub downto Lb do begin Jk := PRow^[J]; if Jk <> J then for I := Lb to Ub do FSwap(A^[I]^[J], A^[I]^[Jk]); end; Terminate(MatOk); end; end. ����������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/urtpol4.pas�������������������������������������������������0000755�0001750�0001750�00000006711�11326425446�017614� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Quartic equation ****************************************************************** } unit urtpol4; interface uses utypes, urtpol2, urtpol3; function RootPol4(Coef : PVector; Z : PCompVector) : Integer; { ------------------------------------------------------------------ Solves the quartic equation: Coef^[0] + Coef^[1] * X + Coef^[2] * X^2 + Coef^[3] * X^3 + Coef^[4] * X^4 = 0 ------------------------------------------------------------------ } implementation function RootPol4(Coef : PVector; Z : PCompVector) : Integer; var A, AA, B, C, D : Float; Q , R , S : Float; K , KK, L, M : Float; I, N1, N2 : Integer; Cf : PVector; Z1, Z2 : PCompVector; function HighestRealRoot(Deg : Integer; Z : PCompVector) : Float; { Find the highest real root among the roots of a polynomial } var I : Integer; R : Float; begin R := - MaxNum; for I := 1 to Deg do if (Z^[I].Y = 0.0) and (Z^[I].X > R) then R := Z^[I].X; HighestRealRoot := R; end; begin for I := 1 to 4 do begin Z^[I].X := 0.0; Z^[I].Y := 0.0; end; if Coef^[4] = 0 then begin RootPol4 := RootPol3(Coef, Z); Exit; end; DimVector(Cf, 3); if Coef^[0] = 0.0 then begin { 0 is root. Equation becomes cubic } Cf^[0] := Coef^[1]; Cf^[1] := Coef^[2]; Cf^[2] := Coef^[3]; { Solve cubic equation } RootPol4 := RootPol3(Cf, Z) + 1; DelVector(Cf, 3); Exit; end; if Coef^[4] = 1.0 then begin A := Coef^[3] * 0.25; B := Coef^[2]; C := Coef^[1]; D := Coef^[0]; end else begin A := Coef^[3] / Coef^[4] * 0.25; B := Coef^[2] / Coef^[4]; C := Coef^[1] / Coef^[4]; D := Coef^[0] / Coef^[4]; end; AA := A * A; Q := B - 6.0 * AA; R := C + A * (8.0 * AA - 2.0 * B); S := D - A * C + AA * (B - 3.0 * AA); { Compute coefficients of cubic equation } Cf^[3] := 1.0; Cf^[2] := 0.5 * Q; Cf^[1] := 0.25 * (Sqr(Cf^[2]) - S); { Solve cubic equation and set KK = highest real root } if (R = 0.0) and (Cf^[1] < 0.0) then begin { Eq. becomes quadratic with 2 real roots } Cf^[0] := Cf^[1]; Cf^[1] := Cf^[2]; Cf^[2] := 1.0; N1 := RootPol2(Cf, Z); KK := HighestRealRoot(2, Z); end else begin Cf^[0] := - 0.015625 * Sqr(R); N1 := RootPol3(Cf, Z); KK := HighestRealRoot(3, Z); end; K := Sqrt(KK); if K = 0.0 then R := Sqrt(Sqr(Q) - 4.0 * S) else begin Q := Q + 4.0 * KK; R := 0.5 * R / K; end; L := 0.5 * (Q - R); M := 0.5 * (Q + R); { Solve quadratic equation: Y^2 + 2KY + L = 0 } DimCompVector(Z1, 2); Cf^[0] := L; Cf^[1] := 2.0 * K; Cf^[2] := 1.0; N1 := RootPol2(Cf, Z1); { Solve quadratic equation: Z^2 - 2KZ + M = 0 } DimCompVector(Z2, 2); Cf^[0] := M; Cf^[1] := -Cf^[1]; N2 := RootPol2(Cf, Z2); { Transfer roots into vectors Xr and Xi } Z^[1].X := Z1^[1].X - A; Z^[1].Y := Z1^[1].Y; Z^[2].X := Z1^[2].X - A; Z^[2].Y := Z1^[2].Y; Z^[3].X := Z2^[1].X - A; Z^[3].Y := Z2^[1].Y; Z^[4].X := Z2^[2].X - A; Z^[4].Y := Z2^[2].Y; RootPol4 := N1 + N2; DelVector(Cf, 3); DelCompVector(Z1, 2); DelCompVector(Z2, 2); end; end. �������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uibeta.pas��������������������������������������������������0000755�0001750�0001750�00000016176�11326425444�017460� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Incomplete Beta function. Translated from C code in Cephes library (http://www.moshier.net) ****************************************************************** } unit uibeta; interface uses utypes, umath, ugamma; function IBeta(A, B, X : Float) : Float; { Incomplete Beta function} implementation const Big = 1.0 / MachEp; function PSeries(A, B, X : Float) : Float; { Power series for incomplete beta integral. Use when B*X is small } var S, T, U, V, T1, Z, Ai : Float; N : Integer; begin Ai := 1.0 / A; U := (1.0 - B) * X; V := U / (A + 1.0); T1 := V; T := U; N := 2; S := 0.0; Z := MachEp * Ai; while Abs(V) > Z do begin U := (N - B) * X / N; T := T * U; V := T / (A + N); S := S + V; N := N + 1; end; S := S + T1; S := S + Ai; U := A * Ln(X); if (A + B < MaxGam) and (Abs(U) < MaxLog) then begin T := Gamma(A + B) / (Gamma(A) * Gamma(B)); S := S * T * Power(X, A); end else begin T := LnGamma(A + B) - LnGamma(A) - LnGamma(B) + U + Ln(S); if T < MinLog then S := 0.0 else S := Exp(T); end; PSeries := S; end; function CFrac1(A, B, X : Float) : Float; { Continued fraction expansion #1 for incomplete beta integral } var Xk, Pk, Pkm1, Pkm2, Qk, Qkm1, Qkm2, K1, K2, K3, K4, K5, K6, K7, K8, R, T, Ans, Thresh : Float; N : Integer; label CDone; begin K1 := A; K2 := A + B; K3 := A; K4 := A + 1.0; K5 := 1.0; K6 := B - 1.0; K7 := K4; K8 := A + 2.0; Pkm2 := 0.0; Qkm2 := 1.0; Pkm1 := 1.0; Qkm1 := 1.0; Ans := 1.0; R := 1.0; N := 0; Thresh := 3.0 * MachEp; repeat Xk := - (X * K1 * K2) / (K3 * K4); Pk := Pkm1 + Pkm2 * Xk; Qk := Qkm1 + Qkm2 * Xk; Pkm2 := Pkm1; Pkm1 := Pk; Qkm2 := Qkm1; Qkm1 := Qk; Xk := (X * K5 * K6) / (K7 * K8); Pk := Pkm1 + Pkm2 * Xk; Qk := Qkm1 + Qkm2 * Xk; Pkm2 := Pkm1; Pkm1 := Pk; Qkm2 := Qkm1; Qkm1 := Qk; if Qk <> 0.0 then R := Pk / Qk; if R <> 0.0 then begin T := Abs((Ans - R) / R); Ans := R; end else T := 1.0; if T < Thresh then goto CDone; K1 := K1 + 1.0; K2 := K2 + 1.0; K3 := K3 + 2.0; K4 := K4 + 2.0; K5 := K5 + 1.0; K6 := K6 - 1.0; K7 := K7 + 2.0; K8 := K8 + 2.0; if Abs(Qk) + Abs(Pk) > Big then begin Pkm2 := Pkm2 * MachEp; Pkm1 := Pkm1 * MachEp; Qkm2 := Qkm2 * MachEp; Qkm1 := Qkm1 * MachEp; end; if (Abs(Qk) < MachEp) or (Abs(Pk) < MachEp) then begin Pkm2 := Pkm2 * Big; Pkm1 := Pkm1 * Big; Qkm2 := Qkm2 * Big; Qkm1 := Qkm1 * Big; end; N := N + 1; until N > 400; SetErrCode(FPLoss); CDone: CFrac1 := Ans; end; function CFrac2(A, B, X : Float) : Float; { Continued fraction expansion #2 for incomplete beta integral } var Xk, Pk, Pkm1, Pkm2, Qk, Qkm1, Qkm2, K1, K2, K3, K4, K5, K6, K7, K8, R, T, Z, Ans, Thresh : Float; N : Integer; label CDone; begin K1 := A; K2 := B - 1.0; K3 := A; K4 := A + 1.0; K5 := 1.0; K6 := A + B; K7 := A + 1.0; K8 := A + 2.0; Pkm2 := 0.0; Qkm2 := 1.0; Pkm1 := 1.0; Qkm1 := 1.0; Z := X / (1.0 - X); Ans := 1.0; R := 1.0; N := 0; Thresh := 3.0 * MachEp; repeat Xk := - (Z * K1 * K2) / (K3 * K4); Pk := Pkm1 + Pkm2 * Xk; Qk := Qkm1 + Qkm2 * Xk; Pkm2 := Pkm1; Pkm1 := Pk; Qkm2 := Qkm1; Qkm1 := Qk; Xk := (Z * K5 * K6) / (K7 * K8); Pk := Pkm1 + Pkm2 * Xk; Qk := Qkm1 + Qkm2 * Xk; Pkm2 := Pkm1; Pkm1 := Pk; Qkm2 := Qkm1; Qkm1 := Qk; if Qk <> 0.0 then R := Pk / Qk; if R <> 0.0 then begin T := Abs((Ans - R) / R); Ans := R; end else T := 1.0; if T < Thresh then goto CDone; K1 := K1 + 1.0; K2 := K2 - 1.0; K3 := K3 + 2.0; K4 := K4 + 2.0; K5 := K5 + 1.0; K6 := K6 + 1.0; K7 := K7 + 2.0; K8 := K8 + 2.0; if Abs(Qk) + Abs(Pk) > Big then begin Pkm2 := Pkm2 * MachEp; Pkm1 := Pkm1 * MachEp; Qkm2 := Qkm2 * MachEp; Qkm1 := Qkm1 * MachEp; end; if (Abs(Qk) < MachEp) or (Abs(Pk) < MachEp) then begin Pkm2 := Pkm2 * Big; Pkm1 := Pkm1 * Big; Qkm2 := Qkm2 * Big; Qkm1 := Qkm1 * Big; end; N := N + 1; until N > 400; SetErrCode(FPLoss); CDone: CFrac2 := Ans; end; function IBeta(A, B, X : Float) : Float; var A1, B1, X1, T, W, Xc, Y : Float; Flag : Boolean; label Done; begin SetErrCode(FOk); if (A <= 0.0) or (B <= 0.0) or (X < 0.0) then begin IBeta := DefaultVal(FDomain, 0.0); Exit; end; if X > 1.0 then begin IBeta := DefaultVal(FDomain, 1.0); Exit; end; if (X = 0.0) or (X = 1.0) then begin IBeta := X; Exit; end; Flag := False; if (B * X <= 1.0) and (X <= 0.95) then begin T := PSeries(A, B, X); goto Done; end; W := 1.0 - X; { Reverse a and b if x is greater than the mean. } if X > A / (A + B) then begin Flag := True; A1 := B; B1 := A; Xc := X; X1 := W; end else begin A1 := A; B1 := B; Xc := W; X1 := X; end; if Flag and (B1 * X1 <= 1.0) and (X1 <= 0.95) then begin T := PSeries(A1, B1, X1); goto Done; end; { Choose expansion for optimal convergence } Y := X1 * (A1 + B1 - 2.0) - (A1 - 1.0); if Y < 0.0 then W := CFrac1(A1, B1, X1) else W := CFrac2(A1, B1, X1) / Xc; { Multiply w by the factor a b _ _ _ x (1-x) | (a+b) / ( a | (a) | (b) ) } Y := A1 * Ln(X1); T := B1 * Ln(Xc); if (A1 + B1 < MaxGam) and (Abs(Y) < MaxLog) and (Abs(T) < MaxLog) then begin T := Power(Xc, B1) ; T := T * Power(X1, A1); T := T / A1; T := T * W; T := T * Gamma(A1 + B1) / (Gamma(A1) * Gamma(B1)); end else begin { Resort to logarithms } Y := Y + T + LnGamma(A1 + B1) - LnGamma(A1) - LnGamma(B1) + Ln(W / A1); if Y < MinLog then T := 0.0 else T := Exp(Y); end; Done: if Flag then if T <= MachEp then T := 1.0 - MachEp else T := 1.0 - T; IBeta := T; end; end.��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/�������������������������������������������������������0000755�0001750�0001750�00000000000�12360760644�016413� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/proba/�������������������������������������������������0000755�0001750�0001750�00000000000�12360760644�017516� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/proba/binom.pas����������������������������������������0000755�0001750�0001750�00000001703�11326425444�021330� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program computes the binomial distribution B(N,P). For each value of K (K = 0..N), the probability Prob(X = K) is computed from function PBinom. The cumulative probability Prob(X <= K) is computed either by direct summation or by a call to function FBinom. ****************************************************************** } program Binom; uses tpmath; const N = 10; { Number of repetitions } P = 0.4; { Probability of success } var K : Integer; PK, S : Float; begin WriteLn; WriteLn('Binomial distribution: N = ', N:3, ', P = ', P:6:4); WriteLn; WriteLn(' K Prob(K) Sum FBinom'); WriteLn('-----------------------------------'); S := 0.0; for K := 0 to N do begin PK := PBinom(N, P, K); S := S + PK; WriteLn(K:2, PK:11:4, S:11:4, FBinom(N, P, K):11:4); end; end. �������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/stat/��������������������������������������������������0000755�0001750�0001750�00000000000�12360760644�017366� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/stat/av2a.pas������������������������������������������0000755�0001750�0001750�00000004404�11326425444�020726� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Two-way analysis of variance (one observation per sample) ****************************************************************** } program av2a; uses tpmath; const NA = 3; { Number of modalities of factor A } NB = 4; { Number of modalities of factor B } Alpha = 0.05; { Significance level } Prob = 1.0 - Alpha; { Probability } { The samples are stored in a matrix Z, such that Z[I, J] contains the observation for the I-th modality of factor A and the J-th modality of factor B } const Z : array[1..NA, 1..NB] of Float = ((2, 1, 3, 1), (3, 2, 3, 2), (3, 4, 5, 3)); var M : PMatrix; { Means } S : PMatrix; { Standard deviations } { Note: The S matrix does not need to be dimensioned if there is only one observation per sample. However, it must be declared. } V : PVector; { Variances (A, B, interaction) } DoF : PIntVector; { Degrees of freedom (A, B, interaction) } F : PVector; { Variance ratios (A, B) } Fc : PVector; { Critical values } I, J : Integer; { Loop variables } begin DimMatrix(M, NA, NB); { Means } DimMatrix(S, NA, NB); { Standard deviations } DimVector(V, 3); { Variances (A, B, interaction) } DimIntVector(DoF, 3); { Degrees of freedom (A, B, interaction) } DimVector(F, 2); { Variance ratios (A, B) } DimVector(Fc, 2); { Critical values } { Compare means. The matrix of means is equal to the data matrix. The matrix of standard deviations will be ignored. } for I := 1 to NA do for J := 1 to NB do M^[I]^[J] := Z[I,J]; AnOVa2(NA, NB, 1, M, S, V, F, DoF); { Compute critical values } for I := 1 to 2 do Fc^[I] := InvSnedecor(DoF^[I], DoF^[3], Prob); { Print results } WriteLn('Two-way ANOVA'); WriteLn; WriteLn('Source Variance D.o.F. F F(p = ', Alpha:4:2, ')'); WriteLn('--------------------------------------------------------'); WriteLn('Factor A ', V^[1]:10:4, DoF^[1]:10, F^[1]:10:4, Fc^[1]:10:4); WriteLn('Factor B ', V^[2]:10:4, DoF^[2]:10, F^[2]:10:4, Fc^[2]:10:4); WriteLn('Interaction ', V^[3]:10:4, DoF^[3]:10); end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/stat/stat.pas������������������������������������������0000755�0001750�0001750�00000006237�11326425444�021056� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Statistics: Concentration of hemoglobin in blood (mg/L) in men and women. ****************************************************************** } program stat; uses tpmath; const N = 30; { Number of values } Alpha = 0.05; { Significance level } { Concentrations in men } const HbM : array[1..N] of Float = (141, 144, 146, 148, 149, 150, 150, 151, 153, 153, 153, 154, 155, 156, 156, 160, 160, 160, 163, 164, 164, 165, 166, 168, 168, 170, 172, 172, 176, 179); { Concentrations in women } const HbW : array[1..N] of Float = (105, 110, 112, 112, 118, 119, 120, 120, 125, 126, 127, 128, 130, 132, 133, 134, 135, 138, 138, 138, 138, 142, 145, 148, 148, 150, 151, 154, 154, 158); var XX, YY : PVector; { Data } MM, MW, SM, SW : Float; { Means and standard deviations } SkM, SkW, KM, KW : Float; { Skewness and kurtosis } T, F : Float; { Student's t and Snedecor's F } U, Eps : Float; { Mann-Whitney's U and assoc. standard normal } DoF, DoF1, DoF2 : Integer; { Degrees of freedom } Tc, Fc, Ec : Float; { Critical values } P : Float; { Probability } procedure GetData(XX, YY : PVector); { Get data into arrays } var I : Integer; begin for I := 1 to N do begin XX^[I] := HbM[I]; YY^[I] := HbW[I]; end; end; begin DimVector(XX, N); DimVector(YY, N); GetData(XX, YY); { Compute statistical parameters } MM := Mean(XX, 1, N); MW := Mean(YY, 1, N); SM := StDev(XX, 1, N, MM); SW := StDev(YY, 1, N, MW); SkM := Skewness(XX, 1, N, MM, SM); SkW := Skewness(YY, 1, N, MW, SW); KM := Kurtosis(XX, 1, N, MM, SM); KW := Kurtosis(YY, 1, N, MW, SW); { Compare means and variances (parametric tests) } StudIndep(N, N, MM, MW, SM, SW, T, DoF); Snedecor(N, N, SM, SW, F, DoF1, DoF2); { Compare means (non-parametric test) } Mann_Whitney(N, N, XX, YY, U, Eps); { Compute critical values } P := 1.0 - 0.5 * Alpha; Tc := InvStudent(DoF, P); Fc := InvSnedecor(DoF1, DoF2, P); Ec := InvNorm(P); WriteLn('Hemoglobin in blood'); WriteLn; WriteLn(' Men Women'); WriteLn; WriteLn('Mean : ', MM:10:4, MW:10:4); WriteLn('St. dev. : ', SM:10:4, SW:10:4); WriteLn('Skewness : ', SkM:10:4, SkW:10:4); WriteLn('Kurtosis : ', KM:10:4, KW:10:4); WriteLn; WriteLn('Comparison of means (parametric test):'); WriteLn; WriteLn('Student''s t = ', T:10:4, ' (', DoF, ' DoF)'); WriteLn('Critical value (p = ', Alpha:5:3, ') = ', Tc:10:4); WriteLn; WriteLn('Comparison of variances:'); WriteLn; WriteLn('Snedecor''s F = ', F:10:4, ' (', DoF1, ' and ', DoF2, ' DoF)'); WriteLn('Critical value (p = ', Alpha:5:3, ') = ', Fc:10:4); WriteLn; WriteLn('Comparison of means (non-parametric test):'); WriteLn; WriteLn('Mann-Whitney U = ', U:10:4); WriteLn('Associated standard normal = ', Eps:10:4); WriteLn('Critical value (p = ', Alpha:5:3, ') = ', Ec:10:4); WriteLn; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/stat/av1.pas�������������������������������������������0000755�0001750�0001750�00000007021�11326425444�020562� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** One-way analysis of variance ****************************************************************** } program av1; uses tpmath; const Nsamples = 5; { Number of samples } Nmax = 12; { Max. number of observations per sample } Alpha = 0.05; { Significance level } Prob = 1.0 - Alpha; { Probability } { Sample matrix (one sample per column) } const A : array[1..Nmax, 1..Nsamples] of Float = ((7.2, 4.9, 10.4, 4.6, 6.1), (4.3, 4.8, 4.6, 5.6, 11.4), (5.5, 4.7, 8.4, 8.3, 8.2), (4.6, 5.4, 6.1, 6.9, 5.7), (4.7, 4.7, 8.1, 4.5, 6.6), (5.5, 4.7, 5.4, 4.7, 6.6), (6.6, 6.2, 6.7, 6.7, 6.3), (5.3, 5.6, 7.5, 4.8, 5.9), (5.4, 3.2, 6.4, 5.0, 5.8), (3.9, 6.1, 5.6, 5.0, 4.8), (5.5, 6.7, 6.3, 5.3, 9.1), (2.7, 5.5, 7.7, 7.8, 13.2)); var X : PVector; { Sample } Z : PMatrix; { Sample matrix } N : PIntVector; { Sizes } M : PVector; { Means } S : PVector; { Standard dev. } V_f, V_r, F : Float; { Variances and variance ratio } Khi2 : Float; { Bartlett's khi-2 } H : Float; { Kruskal-Wallis H } Fc, K2c : Float; { Critical values } DoF_f, DoF_r, DoF : Integer; { Degrees of freedom } J : Integer; { Loop variable } procedure GetSample(J : Integer; X : PVector); { Get sample J from matrix A into vector X } var I : Integer; begin for I := 1 to Nmax do X^[I] := A[I, J]; end; procedure GetSampleMatrix(Z : PMatrix); { Get sample matrix into Z } var I, J : Integer; begin for I := 1 to Nmax do for J := 1 to Nsamples do Z^[I]^[J] := A[I, J]; end; begin { Dimension arrays } DimVector(X, Nmax); { Sample } DimMatrix(Z, Nmax, Nsamples); { Sample matrix } DimIntVector(N, Nsamples); { Sizes } DimVector(M, Nsamples); { Means } DimVector(S, Nsamples); { Standard dev. } { Compute sizes, means and SD's } for J := 1 to Nsamples do begin GetSample(J, X); N^[J] := Nmax; M^[J] := Mean(X, 1, N^[J]); S^[J] := StDev(X, 1, N^[J], M^[J]); end; { Compare means and variances (parametric tests) } AnOVa1(Nsamples, N, M, S, V_f, V_r, F, DoF_f, DoF_r); Bartlett(Nsamples, N, S, Khi2, DoF); { Compare means (non-parametric test) } GetSampleMatrix(Z); Kruskal_Wallis(Nsamples, N, Z, H, DoF); { Compute critical values } Fc := InvSnedecor(DoF_f, DoF_r, Prob); K2c := InvKhi2(DoF, Prob); Writeln('Sample Mean St.Dev.'); Writeln('---------------------------'); for J := 1 to Nsamples do Writeln(J:6, M^[J]:10:4, S^[J]:10:4); Writeln; Writeln('Comparison of means (One-way analysis of variance):'); Writeln; Writeln('Factorial variance = ', V_f:10:4, ' (', DoF_f, ' DoF)'); Writeln('Residual variance = ', V_r:10:4, ' (', DoF_r, ' DoF)'); Writeln('Variance ratio = ', F:10:4); Writeln('Critical value (p = ', Alpha:4:2, ') = ', Fc:10:4); Writeln; Writeln('Comparison of variances:'); Writeln; Writeln('Bartlett''s Khi-2 = ', Khi2:10:4, ' (', DoF, ' DoF)'); Writeln('Critical value (p = ', Alpha:4:2, ') = ', K2c:10:4); Writeln; Writeln('Comparison of means (Non-parametric test):'); Writeln; Writeln('Kruskal-Wallis H = ', H:10:4, ' (', DoF, ' DoF)'); Writeln('Critical value (p = ', Alpha:4:2, ') = ', K2c:10:4); end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/stat/khi2.pas������������������������������������������0000755�0001750�0001750�00000005311�11326425444�020730� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Khi-2 and Woolf's tests ****************************************************************** } program khi2; uses tpmath; const Alpha = 0.05; { Significance level } var K2, K2c, G : Float; DoF : Integer; { ------------------------------------------------------------------ Data for the conformity test ------------------------------------------------------------------ } const N = 4; Obs : array[1..N] of Integer = (104, 76, 18, 2); Calc : array[1..N] of Float = ( 94, 86, 14, 6); { ------------------------------------------------------------------ Data for the independence test ------------------------------------------------------------------ } const Nr = 2; Nc = 3; { Number of rows and columns } T : array[1..Nr, 1..Nc] of Integer = { Contingency table } ((280, 210, 110), (220, 90, 90)); { ------------------------------------------------------------------ Procedures for reading data ------------------------------------------------------------------ } procedure GetDataConf(O : PIntVector; C : PVector); { Get data for conformity test } var I : Integer; begin for I := 1 to N do begin O^[I] := Obs[I]; C^[I] := Calc[I]; end; end; procedure GetDataInd(A : PIntMatrix); { Get data for independence test } var I, J : Integer; begin for I := 1 to Nr do for J := 1 to Nc do A^[I]^[J] := T[I,J]; end; { ------------------------------------------------------------------ Main program ------------------------------------------------------------------ } var O : PIntVector; C : PVector; A : PIntMatrix; begin DimIntVector(O, N); DimVector(C, N); DimIntMatrix(A, Nr, Nc); GetDataConf(O, C); GetDataInd(A); { Tests for conformity } Khi2_Conform(N, 0, O, C, K2, DoF); Woolf_Conform(N, 0, O, C, G, DoF); K2c := InvKhi2(DoF, 1.0 - Alpha); WriteLn('Comparison of two distributions:'); WriteLn; WriteLn('Pearson''s Khi-2 = ', K2:10:4, ' (', DoF, ' DoF)'); WriteLn('Woolf''s G = ', G:10:4, ' (', DoF, ' DoF)'); WriteLn('Critical value (p = ', Alpha:5:3, ') = ', K2c:10:4); WriteLn; WriteLn; { Tests for independence } Khi2_Indep(Nr, Nc, A, K2, DoF); Woolf_Indep(Nr, Nc, A, G, DoF); K2c := InvKhi2(DoF, 1.0 - Alpha); WriteLn('Analysis of contingency table:'); WriteLn; WriteLn('Pearson''s Khi-2 = ', K2:10:4, ' (', DoF, ' DoF)'); WriteLn('Woolf''s G = ', G:10:4, ' (', DoF, ' DoF)'); WriteLn('Critical value (p = ', Alpha:5:3, ') = ', K2c:10:4); end.�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/stat/histo.pas�����������������������������������������0000755�0001750�0001750�00000014206�11326425444�021224� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Statistical distribution and Histogram ****************************************************************** } program histo; uses tpmath, tpgraph; const N = 30; { Number of values } Alpha = 0.05; { Significance level } { Hemoglobin concentrations in men } const HbM : array[1..N] of Float = (141, 144, 146, 148, 149, 150, 150, 151, 153, 153, 153, 154, 155, 156, 156, 160, 160, 160, 163, 164, 164, 165, 166, 168, 168, 170, 172, 172, 176, 179); var M, S : Float; { Mean and standard deviation } function PltFunc(X : Float) : Float; { ------------------------------------------------------------------ Function to be plotted (density of normal distribution) ------------------------------------------------------------------ } begin PltFunc := DNorm((X - M) / S) / S; end; procedure WriteResults(C : PStatClassVector; Ncls : Integer; Calc : PVector; Khi2, G : Float; DoF : Integer; K2c : Float); { ------------------------------------------------------------------ Writes results to screen ------------------------------------------------------------------ } const Line1 = '-----------------------------'; var Sum : Float; I : Integer; begin Writeln('Statistical distribution'); Writeln(Line1); Writeln(' Inf Sup N Ncalc'); Writeln(Line1); Sum := 0.0; for I := 1 to Ncls do begin Writeln(C^[I].Inf:8:0, C^[I].Sup:7:0, C^[I].N:7, Calc^[I]:7:2); Sum := Sum + Calc^[I]; end; Writeln(Line1); Writeln('Total ', N:5, Sum:7:2); Writeln(Line1); Writeln; Writeln('Comparison with normal distribution:'); Writeln; Writeln('Pearson''s Khi-2 = ', Khi2:10:4, ' (', DoF, ' DoF)'); Writeln('Woolf''s G = ', G:10:4, ' (', DoF, ' DoF)'); Writeln('Critical value (p = ', Alpha:4:2, ') = ', K2c:10:4); end; procedure PlotGraph(C : PStatClassVector; Ncls : Integer; Xmin , Xmax, Xstep : Float); { ------------------------------------------------------------------ Plots histogram and normal curve ------------------------------------------------------------------ } var Ymin, Ymax, Ystep : Float; { Oy scale } Npts : Integer; { Number of points } X, Y : PVector; { Point coordinates } I, J : Integer; { Loop variables } begin if not InitGraphics(9, 2, 'c:\tp\bgi') then { 640x480 16 color } begin Writeln('Unable to set graphic mode'); Exit; end; SetWindow(15, 85, 15, 85, True); { The histogram is plotted as a continuous curve. Each bar of the histogram is defined by 4 points } Npts := 4 * Ncls; DimVector(X, Npts); DimVector(Y, Npts); for I := 1 to Ncls do with C^[I] do begin J := 4 * (I - 1) + 1; X^[J] := Inf; { Y^[J] := 0 } Inc(J); X^[J] := Inf; Y^[J] := D; Inc(J); X^[J] := Sup; Y^[J] := D; Inc(J); X^[J] := Sup; { Y^[J] := 0 } end; { Set scale on Oy, making sure that it starts from 0 } AutoScale(Y, 1, Ncls, LinScale, Ymin, Ymax, Ystep); if Ymin <> 0.0 then Ymin := 0.0; Ymax := Ymax + Ystep; SetOxScale(LinScale, Xmin, Xmax, Xstep); SetOyScale(LinScale, Ymin, Ymax, Ystep); SetGraphTitle('Statistical Distribution'); SetOxTitle('X'); SetOyTitle('Frequency Density'); PlotOxAxis; PlotOyAxis; WriteGraphTitle; SetClipping(True); { Plot histogram and normal curve } SetPointParam(1, 0, 0, 0); { Don't show points on histogram } SetLineParam(1, 1, 3, 1); { Use thick lines } PlotCurve(X, Y, 1, Npts, 1); PlotFunc({$IFDEF FPC}@{$ENDIF}PltFunc, Xmin, Xmax, 2); DelVector(X, Npts); DelVector(Y, Npts); Readln; LeaveGraphics; end; { ****************************************************************** Main program ****************************************************************** } var X : PVector; { Data } C : PStatClassVector; { Statistical classes } Ncls : Integer; { Number of classes } Obs : PIntVector; { Observed frequencies } Calc : PVector; { Calculated frequencies } Khi2 : Float; { Pearson's Khi-2 } G : Float; { Woolf's G } K2c : Float; { Theoretical Khi-2 } DoF : Integer; { Degrees of freedom } T : Float; { Standard normal variable } F0, F : Float; { Cumulative probability } XMin, XMax, XStep : Float; { Scale on Ox } I : Integer; { Loop variable } begin { Read data } DimVector(X, N); for I := 1 to N do X^[I] := HbM[I]; { Sort data if necessary } { QSort(X, 1, N); } { Compute an appropriate interval for the set of values } Interval(X^[1], X^[N], 5, 10, XMin, XMax, XStep); { Compute number of classes and dimension arrays } Ncls := Round((Xmax - Xmin) / XStep); DimStatClassVector(C, Ncls); DimIntVector(Obs, Ncls); DimVector(Calc, Ncls); { Compute distribution } Distrib(X, 1, N, Xmin, Xmax, XStep, C); { Compute mean and S.D. } M := Mean(X, 1, N); S := StDev(X, 1, N, M); { Compute theoretical values } F0 := 0.0; for I := 1 to Ncls do begin if I = Ncls then F := 1.0 else begin T := (C^[I].Sup - M) / S; F := FNorm(T); end; Calc^[I] := N * (F - F0); Obs^[I] := C^[I].N; F0 := F; end; { Perform Khi-2 and Woolf tests } Khi2_Conform(Ncls, 2, Obs, Calc, Khi2, DoF); Woolf_Conform(Ncls, 2, Obs, Calc, G, DoF); { Compute critical value } K2c := InvKhi2(DoF, 1.0 - Alpha); { Print results } WriteResults(C, Ncls, Calc, Khi2, G, DoF, K2c); Readln; { Plot histogram } PlotGraph(C, Ncls, Xmin - Xstep, Xmax + Xstep, Xstep); end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/stat/av2.pas�������������������������������������������0000755�0001750�0001750�00000005125�11326425444�020566� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Two-way analysis of variance (several observations per sample) ****************************************************************** } program av2; uses tpmath; const NA = 2; { Number of modalities of factor A } NB = 2; { Number of modalities of factor B } N = 12; { Number of observations for each sample } Alpha = 0.05; { Significance level } Prob = 1.0 - Alpha; { Probability } { The samples are stored in a 3D array Z, such that Z[I, J, K] contains the K-th observation for the I-th modality of factor A and the J-th modality of factor B } const Z : array[1..NA, 1..NB, 1..N] of Float = (((4.9, 2.9, 2.7, 3.9, 4.6, 3.3, 5.9, 4.8, 4.1, 3.5, 7.2, 6.1), (2.1, 2.2, 1.1, 2.9, 5.0, 3.5, 2.4, 4.4, 2.1, 3.0, 3.9, 5.6)), ((4.5, 6.9, 4.0, 5.4, 1.9, 3.6, 4.8, 3.3, 7.5, 5.8, 4.4, 6.0), (2.4, 3.6, 4.8, 3.9, 5.5, 5.0, 6.8, 2.2, 3.1, 5.0, 4.1, 4.7))); var X : PVector; { Sample } M, S : PMatrix; { Means and SD } V : PVector; { Variances (A, B, interaction, residual) } DoF : PIntVector; { Degrees of freedom (A, B, interaction, residual) } F : PVector; { Variance ratios (A, B, interaction) } Fc : PVector; { Critical values } I, J : Integer; { Loop variables } procedure GetSample(I, J : Integer; X : PVector); { Get sample [I,J] from array Z into vector X } var K : Integer; begin for K := 1 to N do X^[K] := Z[I, J, K]; end; begin DimVector(X, N); DimMatrix(M, NA, NB); DimMatrix(S, NA, NB); DimVector(V, 4); DimIntVector(DoF, 4); DimVector(F, 3); DimVector(Fc, 3); { Compute means and SD's } for I := 1 to NA do for J := 1 to NB do begin GetSample(I, J, X); M^[I]^[J] := Mean(X, 1, N); S^[I]^[J] := StDev(X, 1, N, M^[I]^[J]); end; { Compare means } AnOVa2(NA, NB, N, M, S, V, F, DoF); { Compute critical values } for I := 1 to 3 do Fc^[I] := InvSnedecor(DoF^[I], DoF^[4], Prob); { Print results } WriteLn('Two-way ANOVA'); WriteLn; WriteLn('Source Variance D.o.F. F F(p = ', Alpha:4:2, ')'); WriteLn('--------------------------------------------------------'); WriteLn('Factor A ', V^[1]:10:4, DoF^[1]:10, F^[1]:10:4, Fc^[1]:10:4); WriteLn('Factor B ', V^[2]:10:4, DoF^[2]:10, F^[2]:10:4, Fc^[2]:10:4); WriteLn('Interaction ', V^[3]:10:4, DoF^[3]:10, F^[3]:10:4, Fc^[3]:10:4); WriteLn('Residual ', V^[4]:10:4, DoF^[4]:10); end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/stat/student.pas���������������������������������������0000755�0001750�0001750�00000004410�11326425444�021560� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Comparison of means for paired samples ****************************************************************** } program student; uses tpmath; const N = 12; { Number of values } Alpha = 0.05; { Significance level } { First sample } const X : array[1..N] of Float = (9.2, 10, 9, 9.4, 10.1, 9.5, 10, 10.3, 10.2, 10.2, 9.8, 10.1); { Second sample } const Y : array[1..N] of Float = (9.5, 9, 8.8, 9.5, 9.1, 10, 10.1, 9.3, 9, 9.7, 9.1, 9.3); var XX, YY : PVector; { Data } MX, MY : Float; { Means } SX, SY : Float; { Standard deviations } T : Float; { Student's t } WT, Eps : Float; { Wilcoxon's T and assoc. standard normal } Nd : Integer; { Number of nonzero differences } DoF : Integer; { Degrees of freedom } P : Float; { Probability } Tc, Ec : Float; { Critical values } procedure GetData(XX, YY : PVector); { Get data into arrays } var I : Integer; begin for I := 1 to N do begin XX^[I] := X[I]; YY^[I] := Y[I]; end; end; begin DimVector(XX, N); DimVector(YY, N); GetData(XX, YY); { Compute statistical parameters } MX := Mean(XX, 1, N); MY := Mean(YY, 1, N); SX := StDev(XX, 1, N, MX); SY := StDev(YY, 1, N, MY); { Compare means (parametric test) } StudPaired(XX, YY, 1, N, T, DoF); { Compare means (non-parametric test) } Wilcoxon(XX, YY, 1, N, Nd, WT, Eps); { Compute critical values } P := 1.0 - 0.5 * Alpha; Tc := InvStudent(DoF, P); Ec := InvNorm(P); WriteLn(' X Y'); WriteLn; WriteLn('Mean :', MX:10:4, MY:10:4); WriteLn('St. dev. :', SX:10:4, SY:10:4); WriteLn; WriteLn('Comparison of means (paired samples, parametric test)'); WriteLn; WriteLn('Student''s t = ', T:10:4, ' (', DoF, ' DoF)'); WriteLn('Critical value (p = ', Alpha:5:3, ') = ', Tc:10:4); WriteLn; WriteLn('Comparison of means (paired samples, non-parametric test)'); WriteLn; WriteLn('Wilcoxon''s T = ', WT:10:4); WriteLn('Associated standard normal = ', Eps:10:4); WriteLn('Critical value (p = ', Alpha:5:3, ') = ', Ec:10:4); end.��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/curfit/������������������������������������������������0000755�0001750�0001750�00000000000�12360760642�017705� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/curfit/regmult.pas�������������������������������������0000755�0001750�0001750�00000014664�11326425444�022106� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program performs a multiple linear least squares fit: Y = B(0) + B(1) * X1 + B(2) * X2 + ... ****************************************************************** } program regmult; uses tpmath, tpgraph; const N = 23; { Number of observations } Nvar = 4; { Number of independent variables } Alpha = 0.05; { Significance level } ConsTerm = True; { Include a constant term B(0) } { Data } const X : array[1..N, 1..Nvar] of Float = ((-0.27, 7.327, 0, 0), (-0.55, 7.4 , 0, 0), (-0.53, 7.74 , 0, 0), (-0.57, 7.95 , 0, 0), (-0.87, 7.9 , 0, 0), (-1.36, 7.931, 0, 0), (-0.39, 6.849, 0, 0), (-0.66, 7.508, 0, 0), (-0.33, 7.419, 0, 0), (-1.7 , 7.496, 0, 0), (-0.68, 7.027, 0, 0), (-0.79, 8.15 , 0, 0), (-0.82, 8.822, 0, 0), (-0.66, 8.334, 0, 0), ( 0.02, 7.421, 0, 0), ( 0.06, 7.862, 1, 0), (-0.3 , 8.483, 1, 0), ( 0.07, 9.82 , 0, 0), ( 0 , 7.641, 1, 0), (-0.8 , 7.601, 0, 1), (-1.05, 7.565, 0, 1), (-0.35, 7.993, 0, 0), (-0.11, 7.13 , 0, 0)); const Y : array[1..N] of Float = (3.21, 3.94, 3.66, 3.99, 4.06, 4.09, 3.36, 3.92, 3.58, 4.26, 3.06, 4.13, 4.27, 4.36, 3.72, 3.89, 4.39, 3.92, 3.89, 5.1 , 5.14, 3.68, 3.7); { ****************************************************************** Subprograms ****************************************************************** } procedure WriteResults(Y, Ycalc : PVector; B : PVector; V : PMatrix; Test : TRegTest; Tc, Fc : Float); { ------------------------------------------------------------------ Writes results to screen ------------------------------------------------------------------ } var Line1, Line2 : String; { Separating lines } Delta : Float; { Residual } Sr : Float; { Residual standard deviation } SB : Float; { Standard deviations of parameters } Lb : Integer; { Index of first parameter } I : Integer; { Loop variable } begin Line1 := StrChar(73, '-'); Line2 := StrChar(73, '='); WriteLn(Line2); Write('Multiple linear regression: Y = '); if ConsTerm then Write('B(0) + '); WriteLn('B(1) * X1 + B(2) * X2 + ...'); WriteLn(Line1); WriteLn('Parameter Est.value Std.dev. ', (100 * (1 - Alpha)):2:0, '% Confidence Interval'); WriteLn(Line1); if ConsTerm then Lb := 0 else Lb := 1; for I := Lb to Nvar do begin SB := Sqrt(V^[I]^[I]); WriteLn('B(', I:1, ')', B^[I]:17:8, SB:17:8, (B^[I] - Tc * SB):17:8, ';', (B^[I] + Tc * SB):17:8); end; WriteLn(Line1); WriteLn('Number of observations : n = ', N:5); with Test do begin Sr := Sqrt(Vr); WriteLn('Residual error : s = ', Sr:10:4); WriteLn('Coefficient of correlation : r = ', (Sgn(B^[1]) * Sqrt(R2)):10:4); WriteLn('Coefficient of determination : r2 = ', R2:10:4); WriteLn('Adjusted coeff. of determination : r2a = ', R2a:10:4); WriteLn('Variance ratio (explained/resid.) : F(', Nu1:3, ', ', Nu2:3, ') = ', F:10:4); WriteLn('Critical variance ratio : F(p = ', (1 - Alpha):4:2, ') = ', Fc:10:4); end; WriteLn(Line1); WriteLn(' i Y obs. Y calc. Residual Std.dev. Std.res.'); WriteLn(Line1); for I := 1 to N do begin Delta := Y^[I] - Ycalc^[I]; WriteLn(I:3, Y^[I]:14:4, Ycalc^[I]:14:4, Delta:14:4, Sr:14:4, (Delta / Sr):14:4); end; WriteLn(Line2); end; procedure PlotGraph(Y, Ycalc : PVector); { ------------------------------------------------------------------ Plots observed vs calculated Y values ------------------------------------------------------------------ } var Xmin, Xmax, Xstep : Float; { Ox scale } Ymin, Ymax, Ystep : Float; { Oy scale } begin if not InitGraphics(9, 2, 'c:\tp\bgi') then { 640x480 16 color } begin Writeln('Unable to set graphic mode'); Exit; end; SetWindow(15, 85, 15, 85, True); AutoScale(Y, 1, N, LinScale, Xmin, Xmax, Xstep); AutoScale(Ycalc, 1, N, LinScale, Ymin, Ymax, Ystep); SetOxScale(LinScale, Xmin, Xmax, Xstep); SetOyScale(LinScale, Ymin, Ymax, Ystep); SetGraphTitle('Multiple Linear Regression'); SetOxTitle('Y obs.'); SetOyTitle('Y calc.'); PlotOxAxis; PlotOyAxis; WriteGraphTitle; SetClipping(True); SetLineParam(1, 0, 0, 0); { Don't connect points } PlotCurve(Y, Ycalc, 1, N, 1); Readln; LeaveGraphics; end; { ****************************************************************** Main program ****************************************************************** } var XX : PMatrix; { Independent variables } YY : PVector; { Dependent variable } Ycalc : PVector; { Computed Y values } B : PVector; { Fitted parameters } V : PMatrix; { Variance-covariance matrix } Test : TRegTest; { Statistical tests } Tc : Float; { Critical t value } Fc : Float; { Critical F value } Lb : Integer; { Index of first parameter } I, J : Integer; { Loop variable } begin { Dimension arrays } DimMatrix(XX, N, Nvar); DimVector(YY, N); DimVector(Ycalc, N); DimVector(B, Nvar); DimMatrix(V, Nvar, Nvar); { Read data } for I := 1 to N do begin for J := 1 to Nvar do XX^[I]^[J] := X[I,J]; YY^[I] := Y[I]; end; { Perform regression } { MulFit(XX, YY, 1, N, Nvar, ConsTerm, B, V); } SVDFit(XX, YY, 1, N, Nvar, ConsTerm, 1.0E-8, B, V); { Compute predicted Y values } for I := 1 to N do begin if ConsTerm then Ycalc^[I] := B^[0] else Ycalc^[I] := 0.0; for J := 1 to Nvar do Ycalc^[I] := Ycalc^[I] + B^[J] * XX^[I]^[J]; end; { Update variance-covariance matrix and compute statistical tests } if ConsTerm then Lb := 0 else Lb := 1; RegTest(YY, Ycalc, 1, N, V, Lb, Nvar, Test); { Compute Student's t and Snedecor's F } Tc := InvStudent(Test.Nu2, 1 - 0.5 * Alpha); Fc := InvSnedecor(Test.Nu1, Test.Nu2, 1 - Alpha); { Write results } WriteResults(YY, Ycalc, B, V, Test, Tc, Fc); Readln; { Plot curve } PlotGraph(YY, Ycalc); end. ����������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/curfit/mcsim.pas���������������������������������������0000755�0001750�0001750�00000010413�11326425444�021523� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Monte-Carlo simulation of the statistical distribution of the regression parameters for the exponential model: Y = B(1) * Exp(- B(2) * X) ****************************************************************** } program mcsim; uses tpmath, tpgraph; const FuncName = 'Y = B(1) * Exp(- B(2) * X)'; const NCycles = 10; { Number of cycles } MaxSim = 1000; { Max nb of simulations at each cycle } SavedSim = 1000; { Nb of simulations to be saved } MCFile = 'mcsim.txt'; { File for storing simulation results } const N = 10; { Number of points } FirstPar = 1; { Index of first fitted parameter } LastPar = 2; { Index of last fitted parameter } { Data } const X : array[1..N] of Float = ( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Y : array[1..N] of Float = (416, 319, 244, 188, 144, 113, 85, 66, 50, 41); function RegFunc(X : Float; B : PVector) : Float; begin RegFunc := B^[1] * Exp(- B^[2] * X); end; procedure WriteResults(B : PVector; V : PMatrix); { ------------------------------------------------------------------ Writes results to screen ------------------------------------------------------------------ } var Line1, Line2 : String; { Separating lines } SB : Float; { Standard deviations of parameters } I : Integer; { Loop variable } begin Line1 := StrChar(73, '-'); Line2 := StrChar(73, '='); WriteLn(Line2); WriteLn('Monte-Carlo simulation : ', FuncName); WriteLn(Line1); WriteLn('Parameter Est.value Std.dev. '); WriteLn(Line1); for I := FirstPar to LastPar do begin SB := Sqrt(V^[I]^[I]); WriteLn('B(', I:1, ')', B^[I]:17:8, SB:17:8); end; WriteLn(Line2); end; procedure PlotGraph(B1, B2 : PVector); { ------------------------------------------------------------------ Plots simulation results ------------------------------------------------------------------ } var Xmin, Xmax, Xstep : Float; { Ox scale } Ymin, Ymax, Ystep : Float; { Oy scale } begin if not InitGraphics(9, 2, 'c:\tp\bgi') then { 640x480 16 color } begin Writeln('Unable to set graphic mode'); Exit; end; SetWindow(15, 85, 15, 85, True); AutoScale(B1, 1, SavedSim, LinScale, Xmin, Xmax, Xstep); AutoScale(B2, 1, SavedSim, LinScale, Ymin, Ymax, Ystep); SetOxScale(LinScale, Xmin, Xmax, Xstep); SetOyScale(LinScale, Ymin, Ymax, Ystep); SetGraphTitle('Monte-Carlo simulation : ' + FuncName); SetOxTitle('B(1)'); SetOyTitle('B(2)'); SetFormat(10, 4, False, False); PlotOxAxis; PlotOyAxis; WriteGraphTitle; SetClipping(True); SetLineParam(1, 0, 0, 0); { Don't connect points } PlotCurve(B1, B2, 1, SavedSim, 1); Readln; LeaveGraphics; end; var XX, YY : PVector; { Data } B : PVector; { Regression parameters } V : PMatrix; { Variance-covariance matrix } B1, B2 : PVector; { Simulated parameters } F : Text; { Output file } Iter : Integer; { Iteration number } I : Integer; { Loop variable } begin DimVector(XX, N); DimVector(YY, N); DimVector(B, LastPar); DimMatrix(V, LastPar, LastPar); DimVector(B1, SavedSim); DimVector(B2, SavedSim); { Read data } for I := 1 to N do begin XX^[I] := X[I]; YY^[I] := Y[I]; end; { Initialize parameters } SetParamBounds(1, 100, 1000); SetParamBounds(2, 0.1, 1); { Set Metropolis-Hastings parameters } InitMHParams(NCycles, MaxSim, SavedSim); { Set output file and numeric format } SetMCFile(MCFile); SetFormat(10, 4, False, True); { Perform simulation } SimFit({$IFDEF FPC}@{$ENDIF}RegFunc, XX, YY, 1, N, B, FirstPar, LastPar, V); { Retrieve simulation results into vectors B1 and B2 } Assign(F, MCFile); Reset(F); for I := 1 to SavedSim do ReadLn(F, Iter, B1^[I], B2^[I]); Close(F); { Write results } WriteResults(B, V); { Plot curve } PlotGraph(B1, B2); DelVector(XX, N); DelVector(YY, N); DelVector(B, LastPar); DelMatrix(V, LastPar, LastPar); DelVector(B1, SavedSim); DelVector(B2, SavedSim); end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/curfit/reglin.pas��������������������������������������0000755�0001750�0001750�00000012261�11326425444�021676� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program performs a least squares fit of a straight line: Y = B(0) + B(1) * X ****************************************************************** } program reglin; uses tpmath, tpgraph; const N = 5; { Number of points } Alpha = 0.05; { Significance level } { Data } const X : array[1..N] of Float = (10, 20, 30, 40, 50); Y : array[1..N] of Float = ( 0.1865, 0.3616, 0.537, 0.7359, 0.9238); var B : PVector; { Regression parameters } function PltFunc(X : Float) : Float; { ------------------------------------------------------------------ Function to be plotted ------------------------------------------------------------------ } begin PltFunc := B^[0] + B^[1] * X end; procedure WriteResults(X, Y, Ycalc, B : PVector; V : PMatrix; Test : TRegTest; Tc, Fc : Float); { ------------------------------------------------------------------ Writes results to screen ------------------------------------------------------------------ } var Line1, Line2 : String; { Separating lines } Delta : Float; { Residual } Sr : Float; { Residual standard deviation } SB : Float; { Standard deviations of parameters } I : Integer; { Loop variable } begin Line1 := StrChar(73, '-'); Line2 := StrChar(73, '='); WriteLn(Line2); WriteLn('Linear regression: Y = B(0) + B(1) * X'); WriteLn(Line1); WriteLn('Parameter Est.value Std.dev. ', (100 * (1 - Alpha)):2:0, '% Confidence Interval'); WriteLn(Line1); for I := 0 to 1 do begin SB := Sqrt(V^[I]^[I]); WriteLn('B(', I:1, ')', B^[I]:17:8, SB:17:8, (B^[I] - Tc * SB):17:8, ';', (B^[I] + Tc * SB):17:8); end; WriteLn(Line1); WriteLn('Number of observations : n = ', N:5); with Test do begin Sr := Sqrt(Vr); WriteLn('Residual error : s = ', Sr:10:4); WriteLn('Coefficient of correlation : r = ', (Sgn(B^[1]) * Sqrt(R2)):10:4); WriteLn('Coefficient of determination : r2 = ', R2:10:4); WriteLn('Adjusted coeff. of determination : r2a = ', R2a:10:4); WriteLn('Variance ratio (explained/resid.) : F(', Nu1:3, ', ', Nu2:3, ') = ', F:10:4); WriteLn('Critical variance ratio : F(p = ', (1 - Alpha):4:2, ') = ', Fc:10:4); end; WriteLn(Line1); WriteLn(' i Y obs. Y calc. Residual Std.dev. Std.res.'); WriteLn(Line1); for I := 1 to N do begin Delta := Y^[I] - Ycalc^[I]; WriteLn(I:3, Y^[I]:14:4, Ycalc^[I]:14:4, Delta:14:4, Sr:14:4, (Delta / Sr):14:4); end; WriteLn(Line2); end; procedure PlotGraph(X, Y, B : PVector); { ------------------------------------------------------------------ Plots histogram and normal curve ------------------------------------------------------------------ } var Xmin, Xmax, Xstep : Float; { Ox scale } Ymin, Ymax, Ystep : Float; { Oy scale } begin if not InitGraphics(9, 2, 'c:\tp\bgi') then { 640x480 16 color } begin Writeln('Unable to set graphic mode'); Exit; end; SetWindow(15, 85, 15, 85, True); AutoScale(X, 1, N, LinScale, Xmin, Xmax, Xstep); AutoScale(Y, 1, N, LinScale, Ymin, Ymax, Ystep); SetOxScale(LinScale, Xmin, Xmax, Xstep); SetOyScale(LinScale, Ymin, Ymax, Ystep); SetGraphTitle('Linear Regression'); SetOxTitle('X'); SetOyTitle('Y'); PlotOxAxis; PlotOyAxis; WriteGraphTitle; SetClipping(True); SetLineParam(1, 0, 0, 0); { Don't connect points } PlotCurve(X, Y, 1, N, 1); PlotFunc({$IFDEF FPC}@{$ENDIF}PltFunc, Xmin, Xmax, 2); Readln; LeaveGraphics; end; { ****************************************************************** Main program ****************************************************************** } var XX, YY : PVector; { Data } Ycalc : PVector; { Computed Y values } V : PMatrix; { Variance-covariance matrix } Test : TRegTest; { Statistical tests } Tc : Float; { Critical t value } Fc : Float; { Critical F value } I : Integer; { Loop variable } begin { Dimension arrays } DimVector(XX, N); DimVector(YY, N); DimVector(Ycalc, N); DimVector(B, 1); DimMatrix(V, 1, 1); { Read data } for I := 1 to N do begin XX^[I] := X[I]; YY^[I] := Y[I]; end; { Perform regression } LinFit(XX, YY, 1, N, B, V); { Compute predicted Y values } for I := 1 to N do Ycalc^[I] := B^[0] + B^[1] * XX^[I]; { Update variance-covariance matrix and compute statistical tests } RegTest(YY, Ycalc, 1, N, V, 0, 1, Test); { Compute Student's t and Snedecor's F } Tc := InvStudent(N - 2, 1 - 0.5 * Alpha); Fc := InvSnedecor(1, N - 2, 1 - Alpha); { Write results } WriteResults(XX, YY, Ycalc, B, V, Test, Tc, Fc); { Plot curve } PlotGraph(XX, YY, B); end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/curfit/regpoly.pas�������������������������������������0000755�0001750�0001750�00000012601�11326425444�022075� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program performs a least squares fit of a polynomial: Y = B(0) + B(1) * X + B(2) * X + ... ****************************************************************** } program regpoly; uses tpmath, tpgraph; const N = 12; { Number of points } Deg = 2; { Degree of polynomial } Alpha = 0.05; { Significance level } { Data } const X : array[1..N] of Float = (0, 0.0136, 0.023, 0.0352, 0.048, 0.075, 0.1067, 0.1374, 0.1734, 0.2139, 0.2594, 0.3113); Y : array[1..N] of Float = (3.97, 4.03, 4.1, 4.2, 4.28, 4.47, 4.66, 4.83, 4.99, 5.12, 5.25, 5.37); var B : PVector; { Regression parameters } function PltFunc(X : Float) : Float; { ------------------------------------------------------------------ Function to be plotted ------------------------------------------------------------------ } begin PltFunc := Poly(X, B, Deg); end; procedure WriteResults(X, Y, Ycalc, B : PVector; V : PMatrix; Test : TRegTest; Tc, Fc : Float); { ------------------------------------------------------------------ Writes results to screen ------------------------------------------------------------------ } var Line1, Line2 : String; { Separating lines } Delta : Float; { Residual } Sr : Float; { Residual standard deviation } SB : Float; { Standard deviations of parameters } I : Integer; { Loop variable } begin Line1 := StrChar(73, '-'); Line2 := StrChar(73, '='); WriteLn(Line2); WriteLn('Polynomial regression: Y = B(0) + B(1) * X + B(2) * X + ...'); WriteLn(Line1); WriteLn('Parameter Est.value Std.dev. ', (100 * (1 - Alpha)):2:0, '% Confidence Interval'); WriteLn(Line1); for I := 0 to Deg do begin SB := Sqrt(V^[I]^[I]); WriteLn('B(', I:1, ')', B^[I]:17:8, SB:17:8, (B^[I] - Tc * SB):17:8, ';', (B^[I] + Tc * SB):17:8); end; WriteLn(Line1); WriteLn('Number of observations : n = ', N:5); with Test do begin Sr := Sqrt(Vr); WriteLn('Residual error : s = ', Sr:10:4); WriteLn('Coefficient of correlation : r = ', (Sqrt(R2)):10:4); WriteLn('Coefficient of determination : r2 = ', R2:10:4); WriteLn('Adjusted coeff. of determination : r2a = ', R2a:10:4); WriteLn('Variance ratio (explained/resid.) : F(', Nu1:3, ', ', Nu2:3, ') = ', F:10:4); WriteLn('Critical variance ratio : F(p = ', (1 - Alpha):4:2, ') = ', Fc:10:4); end; WriteLn(Line1); WriteLn(' i Y obs. Y calc. Residual Std.dev. Std.res.'); WriteLn(Line1); for I := 1 to N do begin Delta := Y^[I] - Ycalc^[I]; WriteLn(I:3, Y^[I]:14:4, Ycalc^[I]:14:4, Delta:14:4, Sr:14:4, (Delta / Sr):14:4); end; WriteLn(Line2); end; procedure PlotGraph(X, Y, B : PVector); { ------------------------------------------------------------------ Plots points and fitted curve ------------------------------------------------------------------ } var Xmin, Xmax, Xstep : Float; { Ox scale } Ymin, Ymax, Ystep : Float; { Oy scale } begin if not InitGraphics(9, 2, 'c:\tp\bgi') then { 640x480 16 color } begin Writeln('Unable to set graphic mode'); Exit; end; SetWindow(15, 85, 15, 85, True); AutoScale(X, 1, N, LinScale, Xmin, Xmax, Xstep); AutoScale(Y, 1, N, LinScale, Ymin, Ymax, Ystep); SetOxScale(LinScale, Xmin, Xmax, Xstep); SetOyScale(LinScale, Ymin, Ymax, Ystep); SetGraphTitle('Polynomial Regression'); SetOxTitle('X'); SetOyTitle('Y'); PlotOxAxis; PlotOyAxis; WriteGraphTitle; SetClipping(True); SetLineParam(1, 0, 0, 0); { Don't connect points } PlotCurve(X, Y, 1, N, 1); PlotFunc({$IFDEF FPC}@{$ENDIF}PltFunc, Xmin, Xmax, 2); Readln; LeaveGraphics; end; { ****************************************************************** Main program ****************************************************************** } var XX, YY : PVector; { Data } Ycalc : PVector; { Computed Y values } V : PMatrix; { Variance-covariance matrix } Test : TRegTest; { Statistical tests } Tc : Float; { Critical t value } Fc : Float; { Critical F value } I : Integer; { Loop variable } begin { Dimension arrays } DimVector(XX, N); DimVector(YY, N); DimVector(Ycalc, N); DimVector(B, Deg); DimMatrix(V, Deg, Deg); { Read data } for I := 1 to N do begin XX^[I] := X[I]; YY^[I] := Y[I]; end; { Perform regression } PolFit(XX, YY, 1, N, Deg, B, V); { Compute predicted Y values } for I := 1 to N do Ycalc^[I] := Poly(XX^[I], B, Deg); { Update variance-covariance matrix and compute statistical tests } RegTest(YY, Ycalc, 1, N, V, 0, Deg, Test); { Compute Student's t and Snedecor's F } Tc := InvStudent(Test.Nu2, 1 - 0.5 * Alpha); Fc := InvSnedecor(Test.Nu1, Test.Nu2, 1 - Alpha); { Write results } WriteResults(XX, YY, Ycalc, B, V, Test, Tc, Fc); { Plot curve } PlotGraph(XX, YY, B); end. �������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/curfit/regnlin.pas�������������������������������������0000755�0001750�0001750�00000016163�11326425444�022061� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Nonlinear regression ****************************************************************** } program regnlin; uses tpmath, tpgraph; const FuncName = 'Y = B(1) * Exp(- B(2) * X)'; N = 10; { Number of points } FirstPar = 1; { Index of first fitted parameter } LastPar = 2; { Index of last fitted parameter } MaxIter = 1000; { Max. number of iterations } Tol = 1.0E-3; { Required precision } Alpha = 0.05; { Significance level } { Data } const X : array[1..N] of Float = ( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Y : array[1..N] of Float = (416, 319, 244, 188, 144, 113, 85, 66, 50, 41); var B : PVector; { Regression parameters } procedure ApproxFit(B : PVector); { ------------------------------------------------------------------ Approximate fit of the exponential model by weighted linear regression: Ln(Y) = Ln(B(1)) - B(2) * X ------------------------------------------------------------------ } var P : Integer; { Nb. of points for linear reg. } K : Integer; { Loop variable } X1, Y1 : PVector; { Transformed coordinates } S1 : PVector; { Standard deviations } A : PVector; { Linear regression param. Y = A^[0] + A^[1] * X } V : PMatrix; { Variance-covariance matrix } begin P := 0; { Count the number of points } for K := 1 to N do { which can be transformed } if Y[K] > 0.0 then Inc(P); DimVector(X1, P); DimVector(Y1, P); DimVector(S1, P); DimVector(A, 1); DimMatrix(V, 1, 1); P := 0; for K := 1 to N do if Y[K] > 0.0 then begin Inc(P); X1^[P] := X[K]; Y1^[P] := Ln(Y[K]); S1^[P] := 1.0 / Y[K]; end; WLinFit(X1, Y1, S1, 1, P, A, V); if MathErr = MatOk then begin B^[1] := Exp(A^[0]); B^[2] := - A^[1]; end; DelVector(A, 1); DelMatrix(V, 1, 1); end; function RegFunc(X : Float; B : PVector) : Float; begin RegFunc := B^[1] * Exp(- B^[2] * X); end; procedure DerivProc(X, Y : Float; B, D : PVector); begin D^[1] := Exp(- B^[2] * X); D^[2] := - B^[1] * X * D^[1]; end; procedure WriteResults(X, Y, Ycalc, B : PVector; V : PMatrix; Test : TRegTest; Tc, Fc : Float); { ------------------------------------------------------------------ Writes results to screen ------------------------------------------------------------------ } var Line1, Line2 : String; { Separating lines } Delta : Float; { Residual } Sr : Float; { Residual standard deviation } SB : Float; { Standard deviations of parameters } I : Integer; { Loop variable } begin Line1 := StrChar(73, '-'); Line2 := StrChar(73, '='); WriteLn(Line2); WriteLn('Nonlinear regression: ', FuncName); WriteLn(Line1); WriteLn('Parameter Est.value Std.dev. ', (100 * (1 - Alpha)):2:0, '% Confidence Interval'); WriteLn(Line1); for I := FirstPar to LastPar do begin SB := Sqrt(V^[I]^[I]); WriteLn('B(', I:1, ')', B^[I]:17:8, SB:17:8, (B^[I] - Tc * SB):17:8, ';', (B^[I] + Tc * SB):17:8); end; WriteLn(Line1); WriteLn('Number of observations : n = ', N:5); with Test do begin Sr := Sqrt(Vr); WriteLn('Residual error : s = ', Sr:10:4); if R2 <= 1.0 then begin WriteLn('Coefficient of correlation : r = ', (Sqrt(R2)):10:4); WriteLn('Coefficient of determination : r2 = ', R2:10:4); WriteLn('Adjusted coeff. of determination : r2a = ', R2a:10:4); end; WriteLn('Variance ratio (explained/resid.) : F(', Nu1:3, ', ', Nu2:3, ') = ', F:10:4); WriteLn('Critical variance ratio : F(p = ', (1 - Alpha):4:2, ') = ', Fc:10:4); end; WriteLn(Line1); WriteLn(' i Y obs. Y calc. Residual Std.dev. Std.res.'); WriteLn(Line1); for I := 1 to N do begin Delta := Y^[I] - Ycalc^[I]; WriteLn(I:3, Y^[I]:14:4, Ycalc^[I]:14:4, Delta:14:4, Sr:14:4, (Delta / Sr):14:4); end; WriteLn(Line2); end; function PltFunc(X : Float) : Float; { ------------------------------------------------------------------ Function to be plotted ------------------------------------------------------------------ } begin PltFunc := RegFunc(X, B); end; procedure PlotGraph(X, Y, B : PVector); { ------------------------------------------------------------------ Plots points and fitted curve ------------------------------------------------------------------ } var Xmin, Xmax, Xstep : Float; { Ox scale } Ymin, Ymax, Ystep : Float; { Oy scale } begin if not InitGraphics(9, 2, 'c:\tp\bgi') then { 640x480 16 color } begin Writeln('Unable to set graphic mode'); Exit; end; SetWindow(15, 85, 15, 85, True); AutoScale(X, 1, N, LinScale, Xmin, Xmax, Xstep); AutoScale(Y, 1, N, LinScale, Ymin, Ymax, Ystep); SetOxScale(LinScale, Xmin, Xmax, Xstep); SetOyScale(LinScale, Ymin, Ymax, Ystep); SetGraphTitle('Polynomial Regression'); SetOxTitle('X'); SetOyTitle('Y'); PlotOxAxis; PlotOyAxis; WriteGraphTitle; SetClipping(True); SetLineParam(1, 0, 0, 0); { Don't connect points } PlotCurve(X, Y, 1, N, 1); PlotFunc({$IFDEF FPC}@{$ENDIF}PltFunc, Xmin, Xmax, 2); Readln; LeaveGraphics; end; var XX, YY : PVector; { Data } Ycalc : PVector; { Computed Y values } V : PMatrix; { Variance-covariance matrix } Test : TRegTest; { Statistical tests } Tc : Float; { Critical t value } Fc : Float; { Critical F value } I : Integer; { Loop variable } begin DimVector(XX, N); DimVector(YY, N); DimVector(Ycalc, N); DimVector(B, LastPar); DimMatrix(V, LastPar, LastPar); { Read data } for I := 1 to N do begin XX^[I] := X[I]; YY^[I] := Y[I]; end; ApproxFit(B); NLFit({$IFDEF FPC}@{$ENDIF}RegFunc, {$IFDEF FPC}@{$ENDIF}DerivProc, XX, YY, 1, N, MaxIter, Tol, B, FirstPar, LastPar, V); if MathErr = MatOk then begin { Compute predicted Y values } for I := 1 to N do Ycalc^[I] := RegFunc(XX^[I], B); { Update variance-covariance matrix and compute statistical tests } RegTest(YY, Ycalc, 1, N, V, FirstPar, LastPar, Test); { Compute Student's t and Snedecor's F } Tc := InvStudent(Test.Nu2, 1 - 0.5 * Alpha); Fc := InvSnedecor(Test.Nu1, Test.Nu2, 1 - Alpha); { Write results } WriteResults(XX, YY, Ycalc, B, V, Test, Tc, Fc); { Plot curve } PlotGraph(XX, YY, B); end else Writeln('Unable to fit curve!'); DelVector(XX, N); DelVector(YY, N); DelVector(Ycalc, N); DelVector(B, LastPar); DelMatrix(V, LastPar, LastPar); end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/curfit/wreglin.pas�������������������������������������0000755�0001750�0001750�00000013056�11326425444�022070� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program performs a weighted least squares fit of a straight line: Y = B(0) + B(1) * X ****************************************************************** } program wreglin; uses tpmath, tpgraph; const N = 6; { Number of points } Alpha = 0.05; { Significance level } { Data (S = standard deviations of observed Y values) } const X : array[1..N] of Float = (3.195, 3.247, 3.3, 3.356, 3.413, 3.472); Y : array[1..N] of Float = (1.8, 1.61, 1.38, 0.98, 0.81, 0.56); S : array[1..N] of Float = (0.03, 0.03, 0.02, 0.03, 0.01, 0.06); var B : PVector; { Regression parameters } function PltFunc(X : Float) : Float; { ------------------------------------------------------------------ Function to be plotted ------------------------------------------------------------------ } begin PltFunc := B^[0] + B^[1] * X end; procedure WriteResults(X, Y, S, Ycalc, B : PVector; V : PMatrix; Test : TRegTest; Tc, Fc : Float); { ------------------------------------------------------------------ Writes results to screen ------------------------------------------------------------------ } var Line1, Line2 : String; { Separating lines } Delta : Float; { Residual } Sr : Float; { Residual standard deviation } SB : Float; { Standard deviations of parameters } I : Integer; { Loop variable } begin Line1 := StrChar(73, '-'); Line2 := StrChar(73, '='); WriteLn(Line2); WriteLn('Linear regression: Y = B(0) + B(1) * X'); WriteLn(Line1); WriteLn('Parameter Est.value Std.dev. ', (100 * (1 - Alpha)):2:0, '% Confidence Interval'); WriteLn(Line1); for I := 0 to 1 do begin SB := Sqrt(V^[I]^[I]); WriteLn('B(', I:1, ')', B^[I]:17:8, SB:17:8, (B^[I] - Tc * SB):17:8, ';', (B^[I] + Tc * SB):17:8); end; WriteLn(Line1); WriteLn('Number of observations : n = ', N:5); with Test do begin Sr := Sqrt(Vr); WriteLn('Residual error : s = ', Sr:10:4); WriteLn('Coefficient of correlation : r = ', (Sgn(B^[1]) * Sqrt(R2)):10:4); WriteLn('Coefficient of determination : r2 = ', R2:10:4); WriteLn('Adjusted coeff. of determination : r2a = ', R2a:10:4); WriteLn('Variance ratio (explained/resid.) : F(', Nu1:3, ', ', Nu2:3, ') = ', F:10:4); WriteLn('Critical variance ratio : F(p = ', (1 - Alpha):4:2, ') = ', Fc:10:4); end; WriteLn(Line1); WriteLn(' i Y obs. Y calc. Residual Std.dev. Std.res.'); WriteLn(Line1); for I := 1 to N do begin Delta := Y^[I] - Ycalc^[I]; WriteLn(I:3, Y^[I]:14:4, Ycalc^[I]:14:4, Delta:14:4, S^[I]:14:4, (Delta / S^[I]):14:4); end; WriteLn(Line2); end; procedure PlotGraph(X, Y, S, B : PVector); { ------------------------------------------------------------------ Plots histogram and normal curve ------------------------------------------------------------------ } var Xmin, Xmax, Xstep : Float; { Ox scale } Ymin, Ymax, Ystep : Float; { Oy scale } begin if not InitGraphics(9, 2, 'c:\tp\bgi') then { 640x480 16 color } begin Writeln('Unable to set graphic mode'); Exit; end; SetWindow(15, 85, 15, 85, True); AutoScale(X, 1, N, LinScale, Xmin, Xmax, Xstep); AutoScale(Y, 1, N, LinScale, Ymin, Ymax, Ystep); SetOxScale(LinScale, Xmin, Xmax, Xstep); SetOyScale(LinScale, Ymin, Ymax, Ystep); SetGraphTitle('Weighted Linear Regression'); SetOxTitle('X'); SetOyTitle('Y'); PlotOxAxis; PlotOyAxis; WriteGraphTitle; SetClipping(True); SetPointParam(1, 1, 3, 12); SetLineParam(1, 0, 0, 12); { Don't connect points } PlotCurveWithErrorBars(X, Y, S, 1, 1, N, 1); PlotFunc({$IFDEF FPC}@{$ENDIF}PltFunc, Xmin, Xmax, 1); Readln; LeaveGraphics; end; { ****************************************************************** Main program ****************************************************************** } var XX, YY : PVector; { Data } SS : PVector; { Standard deviations of observed Y values } Ycalc : PVector; { Computed Y values } V : PMatrix; { Variance-covariance matrix } Test : TRegTest; { Statistical tests } Tc : Float; { Critical t value } Fc : Float; { Critical F value } I : Integer; { Loop variable } begin { Dimension arrays } DimVector(XX, N); DimVector(YY, N); DimVector(SS, N); DimVector(Ycalc, N); DimVector(B, 1); DimMatrix(V, 1, 1); { Read data } for I := 1 to N do begin XX^[I] := X[I]; YY^[I] := Y[I]; SS^[I] := S[I]; end; { Perform regression } WLinFit(XX, YY, SS, 1, N, B, V); { Compute predicted Y values } for I := 1 to N do Ycalc^[I] := B^[0] + B^[1] * XX^[I]; { Update variance-covariance matrix and compute statistical tests } WRegTest(YY, Ycalc, SS, 1, N, V, 0, 1, Test); { Compute Student's t and Snedecor's F } Tc := InvStudent(N - 2, 1 - 0.5 * Alpha); Fc := InvSnedecor(1, N - 2, 1 - Alpha); { Write results } WriteResults(XX, YY, SS, Ycalc, B, V, Test, Tc, Fc); Readln; { Plot curve } PlotGraph(XX, YY, SS, B); end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/curfit/pcatest.pas�������������������������������������0000755�0001750�0001750�00000007337�11326425444�022071� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Correlation and principal component analysis ****************************************************************** Example taken from: P. DAGNELIE, Analyse statistique a plusieurs variables, Presses Agronomiques de Gembloux, Belgique, 1982 ****************************************************************** } program pcatest; uses tpmath; const N = 11; { Number of observations } Nvar = 4; { Number of variables } { Data } const X : array[1..N, 1..Nvar] of Float = (( 87.9, 19.6, 1 , 1661), ( 89.9, 15.2, 90.1, 968), (153 , 19.7, 56.6, 1353), (132.1, 17 , 91 , 1293), ( 88.8, 18.3, 93.7, 1153), (220.9, 17.8, 106.9, 1286), (117.7, 17.8, 65.5, 1104), (109 , 18.3, 41.8, 1574), (156.1, 17.8, 57.4, 1222), (181.5, 16.8, 140.6, 902), (181.4, 17 , 74.3, 1150)); var XX : PMatrix; { Data } M : PVector; { Mean vector } V : PMatrix; { Variance-covariance matrix } R : PMatrix; { Correlation matrix } S : PVector; { Standard deviations } Lambda : PVector; { Eigenvalues of correlation matrix } C : PMatrix; { Eigenvectors of correlation matrix } Rc : PMatrix; { Correlation factors/variables } Z : PMatrix; { Scaled variables } F : PMatrix; { Principal factors } I, J : Integer; { Loop variables } procedure PrintMatrix(Title : String; A : PMatrix; Ub1, Ub2 : Integer); { ------------------------------------------------------------------ Print matrix A[1..Ub1, 1..Ub2] ------------------------------------------------------------------ } var I, J : Integer; begin Writeln; Writeln(Title); Writeln; for I := 1 to Ub1 do begin for J := 1 to Ub2 do Write(A^[I]^[J]:12:4); Writeln; end; end; procedure PrintVector(Title : String; B : PVector; Ub : Integer); { ------------------------------------------------------------------ Print vector B[1..Ub] ------------------------------------------------------------------ } var I : Integer; begin Writeln; Writeln(Title); Writeln; for I := 1 to Ub do Writeln(B^[I]:12:4); end; begin DimMatrix(XX, N, Nvar); DimVector(M, Nvar); DimMatrix(V, Nvar, Nvar); DimMatrix(R, Nvar, Nvar); DimVector(S, Nvar); DimVector(Lambda, Nvar); DimMatrix(C, Nvar, Nvar); DimMatrix(Rc, Nvar, Nvar); DimMatrix(Z, N, Nvar); DimMatrix(F, N, Nvar); { Read data } for I := 1 to N do for J := 1 to Nvar do XX^[I]^[J] := X[I,J]; { Compute mean vector } VecMean(XX, 1, N, Nvar, M); { Compute variance-covariance matrix } MatVarCov(XX, 1, N, Nvar, M, V); { Compute correlation matrix } MatCorrel(V, Nvar, R); { Display results } Writeln; PrintVector('Mean vector', M, Nvar); PrintMatrix('Variance-covariance matrix', V, Nvar, Nvar); PrintMatrix('Correlation matrix', R, Nvar, Nvar); { Compute standard deviations } VecSD(XX, 1, N, Nvar, M, S); { Scale variables } ScaleVar(XX, 1, N, Nvar, M, S, Z); { Perform principal component analysis The original matrix R is destroyed } PCA(R, Nvar, 1000, 1.0E-10, Lambda, C, Rc); if MathErr = MatNonConv then begin Writeln('Non-convergence of eigenvalue computation'); Exit; end; { Compute principal factors } PrinFac(Z, 1, N, Nvar, C, F); { Display results } Writeln; PrintVector('Eigenvalues of correlation matrix', Lambda, Nvar); PrintMatrix('Eigenvectors (columns) of correlation matrix', C, Nvar, Nvar); PrintMatrix('Correlations between factors (columns) and variables (lines)', Rc, Nvar, Nvar); PrintMatrix('Principal factors', F, N, Nvar); end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/optim/�������������������������������������������������0000755�0001750�0001750�00000000000�12360760644�017543� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/optim/testmarq.pas�������������������������������������0000755�0001750�0001750�00000011345�11326425444�022114� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Minimization of a function of several variables by Marquardt's method. Example: Rosenbrock's function: F(X, Y) = 100 * (Y - X^2)^2 + (1 - X)^2 ( -400 * (Y - X^2) * X - 2 + 2 * X ) Gradient: G = ( ) ( 200 * Y - 200 * X^2 ) ( 1200 * X^2 - 400 * Y + 2 -400 * X ) Hessian: H = ( ) ( -400 * X 200 ) Det(H) = 80000 * (X^2 - Y) + 400 True minimum is at (1, 1), F = 0 The inverse hessian at the minimum is: ( 1/2 1 ) ( 1 401/200 ) Ref: H. Rosenbrock, Comput. J., 1960, 3, 175 ****************************************************************** } program testmarq; uses tpmath; { ------------------------------------------------------------------ Define number of variables, number of iterations, and precision ------------------------------------------------------------------ } const Nvar = 2; { Number of variables } MaxIter = 1000; { Max number of iterations } Tol = 1.0E-6; { Required precision } { ------------------------------------------------------------------ Define the function to be minimized ------------------------------------------------------------------ } function Func(X : PVector) : Float; begin Func := 100.0 * Sqr(X^[2] - Sqr(X^[1])) + Sqr(1.0 - X^[1]); end; { ------------------------------------------------------------------ Define the subroutine which computes the gradient and hessian of the function. It is recommended to use analytical derivatives whenever possible. Otherwise you can use the alternative code provided in numhess.inc ------------------------------------------------------------------ } procedure HessGrad(X, G : PVector; H : PMatrix); var A, B, C : Float; begin C := Sqr(X^[1]); A := X^[2] - C; B := 1.0 - X^[1]; G^[1] := - 400.0 * X^[1] * A - 2.0 * B; G^[2] := 200.0 * A; H^[1]^[1] := 1200.0 * C - 400.0 * X^[2] + 2; H^[1]^[2] := - 400.0 * X^[1]; H^[2]^[1] := H^[1]^[2]; H^[2]^[2] := 200.0; end; { ------------------------------------------------------------------ Alternative code when analytical derivatives are not available ------------------------------------------------------------------ } (* {$i numhess.inc} *) { ------------------------------------------------------------------ Main program ------------------------------------------------------------------ } var X : PVector; { Variables: X^[1] = X, X^[2] = Y } G : PVector; { Gradient vector } H_inv : PMatrix; { Inverse Hessian matrix } F_min : Float; { Function value at minimum } Det : Float; { Determinant of hessian } I, J : Integer; { Loop variables } begin DimVector(X, Nvar); DimVector(G, Nvar); DimMatrix(H_inv, Nvar, Nvar); X^[1] := 2.0; X^[2] := 2.0; { Save Marquardt iterations in a file } SaveMarquardt('marquard.txt'); { Perform minimization } {$IFDEF FPC} Marquardt(@Func, @HessGrad, X, 1, Nvar, MaxIter, Tol, F_min, G, H_inv, Det); {$ELSE} Marquardt(Func, HessGrad, X, 1, Nvar, MaxIter, Tol, F_min, G, H_inv, Det); {$ENDIF} { It may be useful to perform one Newton iteration at the end of Marquardt's algorithm, to ensure that the Marquardt parameter Lambda has been effectively set to zero. } {$IFDEF FPC} Newton(@Func, @HessGrad, X, 1, Nvar, 1, Tol, F_min, G, H_inv, Det); {$ELSE} Newton(Func, HessGrad, X, 1, Nvar, 1, Tol, F_min, G, H_inv, Det); {$ENDIF} case MathErr of OptNonConv : begin Write('Non-convergence!'); Halt; end; OptSing : begin Write('Singular Hessian matrix!'); Halt; end; OptBigLambda : begin Write('Too high Marquardt parameter!'); Halt; end; end; WriteLn('Minimization of Rosenbrock''s function (Marquardt''s method)'); WriteLn('----------------------------------------------------------'); WriteLn; WriteLn('Coordinates of minimum:'); WriteLn; for I := 1 to Nvar do WriteLn(X^[I]:12:6); WriteLn; WriteLn('Function value:'); WriteLn; WriteLn('Fmin = ', F_min); WriteLn; WriteLn('Gradient:'); WriteLn; for I := 1 to Nvar do WriteLn(G^[I]:12:6); WriteLn; WriteLn('Inverse Hessian matrix:'); WriteLn; for I := 1 to Nvar do begin for J := 1 to Nvar do Write(H_inv^[I]^[J]:12:6); WriteLn; end; WriteLn; WriteLn('Determinant of Hessian:'); WriteLn; WriteLn(Det:12:6); end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/optim/minline.pas��������������������������������������0000755�0001750�0001750�00000004715�11326425444�021712� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Minimization of a function of several variables along a line Example taken from "Numerical Recipes": Func = (X(1)-1)^2 + (X(2)-1)^2 + (X(3)-1)^2 The minimum is F = 0 at (1, 1, 1), i. e. for a step R = 1 from X = (0, 0, 0) in the direction DeltaX = (1, 1, 1) The program tries a series of directions: ( Sqrt(2) * Cos [(Pi / 2) * (I / 10)] ) DeltaX = ( Sqrt(2) * Sin [(Pi / 2) * (I / 10)] ) ( 1 ) For each pass, the location of the minimum, and the value of the function at the minimum, are printed. The minimum is at I = 5 ****************************************************************** } program minline; uses tpmath; const Nvar = 3; { Number of variables } MaxIter = 1000; { Max number of iterations } Tol = 1.0E-7; { Required precision } PiDiv20 = 0.1570796326794897; { Pi / 20 } var X : PVector; { Starting point } DeltaX : PVector; { Search direction } R : Float; { Initial step } F_min : Float; { Function value at minimum } I : Integer; { Loop variable } Z : Float; { Auxiliary variable } function Func(X : PVector) : Float; { Function to be minimized } begin Func := Sqr(X^[1] - 1.0) + Sqr(X^[2] - 1.0) + Sqr(X^[3] - 1.0); end; procedure PrintResult(I : Integer; X : PVector; F_min : Float); var J : Integer; begin Write(I:3); for J := 1 to Nvar do Write(X^[J]:12:6); WriteLn(' ', F_min); end; begin WriteLn; WriteLn(' I X(1) X(2) X(3) Fmin'); WriteLn('------------------------------------------------------------------'); DimVector(X, Nvar); DimVector(DeltaX, Nvar); for I := 0 to 10 do begin X^[1] := 0.0; X^[2] := 0.0; X^[3] := 0.0; Z := I * PiDiv20; DeltaX^[1] := Sqrt2 * Cos(Z); DeltaX^[2] := Sqrt2 * Sin(Z); DeltaX^[3] := 1.0; R := 0.1; {$IFDEF FPC} LinMin(@Func, X, DeltaX, 1, Nvar, R, MaxIter, Tol, F_min); {$ELSE} LinMin(Func, X, DeltaX, 1, Nvar, R, MaxIter, Tol, F_min); {$ENDIF} if MathErr = OptOk then PrintResult(I, X, F_min) else WriteLn('Non-convergence!'); end; end. ���������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/optim/numhess.inc��������������������������������������0000755�0001750�0001750�00000003546�10652717662�021737� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Numerical hessian and gradient ****************************************************************** } procedure HessGrad(X, G : PVector; H : PMatrix); const Eta = 1.0E-6; { Relative increment } var Delta, Xminus, Xplus, Fminus, Fplus : PVector; Temp1, Temp2, F, F2plus : Float; I, J : Integer; begin DimVector(Delta, Nvar); { Increments } DimVector(Xminus, Nvar); { X - Delta } DimVector(Xplus, Nvar); { X + Delta } DimVector(Fminus, Nvar); { F(X - Delta) } DimVector(Fplus, Nvar); { F(X + Delta) } F := Func(X); for I := 1 to Nvar do begin if X^[I] <> 0.0 then Delta^[I] := Eta * Abs(X^[I]) else Delta^[I] := Eta; Xplus^[I] := X^[I] + Delta^[I]; Xminus^[I] := X^[I] - Delta^[I]; end; for I := 1 to Nvar do begin Temp1 := X^[I]; X^[I] := Xminus^[I]; Fminus^[I] := Func(X); X^[I] := Xplus^[I]; Fplus^[I] := Func(X); X^[I] := Temp1; end; for I := 1 to Nvar do begin G^[I] := (Fplus^[I] - Fminus^[I]) / (2.0 * Delta^[I]); H^[I]^[I] := (Fplus^[I] + Fminus^[I] - 2.0 * F) / Sqr(Delta^[I]); end; for I := 1 to Pred(Nvar) do begin Temp1 := X^[I]; X^[I] := Xplus^[I]; for J := Succ(I) to Nvar do begin Temp2 := X^[J]; X^[J] := Xplus^[J]; F2plus := Func(X); H^[I]^[J] := (F2plus - Fplus^[I] - Fplus^[J] + F) / (Delta^[I] * Delta^[J]); H^[J]^[I] := H^[I]^[J]; X^[J] := Temp2; end; X^[I] := Temp1; end; DelVector(Delta, Nvar); DelVector(Xminus, Nvar); DelVector(Xplus, Nvar); DelVector(Fminus, Nvar); DelVector(Fplus, Nvar); end; ����������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/optim/testnewt.pas�������������������������������������0000755�0001750�0001750�00000010420�11326425444�022122� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Minimization of a function of several variables by the Newton- Raphson method. Example: Rosenbrock's function: F(X, Y) = 100 * (Y - X^2)^2 + (1 - X)^2 ( -400 * (Y - X^2) * X - 2 + 2 * X ) Gradient: G = ( ) ( 200 * Y - 200 * X^2 ) ( 1200 * X^2 - 400 * Y + 2 -400 * X ) Hessian: H = ( ) ( -400 * X 200 ) Det(H) = 80000 * (X^2 - Y) + 400 True minimum is at (1, 1), F = 0 The inverse hessian at the minimum is: ( 1/2 1 ) ( 1 401/200 ) Ref: H. Rosenbrock, Comput. J., 1960, 3, 175 ****************************************************************** } program testnewt; uses tpmath; { ------------------------------------------------------------------ Define number of variables, number of iterations, and precision ------------------------------------------------------------------ } const Nvar = 2; { Number of variables } MaxIter = 1000; { Max number of iterations } Tol = 1.0E-6; { Required precision } { ------------------------------------------------------------------ Define the function to be minimized ------------------------------------------------------------------ } function Func(X : PVector) : Float; begin Func := 100.0 * Sqr(X^[2] - Sqr(X^[1])) + Sqr(1.0 - X^[1]); end; { ------------------------------------------------------------------ Define the subroutine which computes the gradient and hessian of the function. It is recommended to use analytical derivatives whenever possible. Otherwise you can use the alternative code provided in numhess.inc ------------------------------------------------------------------ } procedure HessGrad(X, G : PVector; H : PMatrix); var A, B, C : Float; begin C := Sqr(X^[1]); A := X^[2] - C; B := 1.0 - X^[1]; G^[1] := - 400.0 * X^[1] * A - 2.0 * B; G^[2] := 200.0 * A; H^[1]^[1] := 1200.0 * C - 400.0 * X^[2] + 2; H^[1]^[2] := - 400.0 * X^[1]; H^[2]^[1] := H^[1]^[2]; H^[2]^[2] := 200.0; end; { ------------------------------------------------------------------ Alternative code when analytical derivatives are not available ------------------------------------------------------------------ } (* {$i numhess.inc} *) { ------------------------------------------------------------------ Main program ------------------------------------------------------------------ } var X : PVector; { Variables: X^[1] = X, X^[2] = Y } G : PVector; { Gradient vector } H_inv : PMatrix; { Inverse Hessian matrix } F_min : Float; { Function value at minimum } Det : Float; { Determinant of hessian } I, J : Integer; { Loop variables } begin DimVector(X, Nvar); DimVector(G, Nvar); DimMatrix(H_inv, Nvar, Nvar); X^[1] := 2.0; X^[2] := 2.0; { Save Newton-Raphson iterations in a file } SaveNewton('newton.txt'); { Perform minimization } {$IFDEF FPC} Newton(@Func, @HessGrad, X, 1, Nvar, MaxIter, Tol, F_min, G, H_inv, Det); {$ELSE} Newton(Func, HessGrad, X, 1, Nvar, MaxIter, Tol, F_min, G, H_inv, Det); {$ENDIF} case MathErr of OptNonConv : begin Write('Non-convergence!'); Halt; end; OptSing : begin Write('Singular Hessian matrix!'); Halt; end; end; WriteLn('Minimization of Rosenbrock''s function (Newton-Raphson method)'); WriteLn('--------------------------------------------------------------'); WriteLn; WriteLn('Coordinates of minimum:'); WriteLn; for I := 1 to Nvar do WriteLn(X^[I]:12:6); WriteLn; WriteLn('Function value:'); WriteLn; WriteLn('Fmin = ', F_min); WriteLn; WriteLn('Gradient:'); WriteLn; for I := 1 to Nvar do WriteLn(G^[I]:12:6); WriteLn; WriteLn('Inverse Hessian matrix:'); WriteLn; for I := 1 to Nvar do begin for J := 1 to Nvar do Write(H_inv^[I]^[J]:12:6); WriteLn; end; WriteLn; WriteLn('Determinant of Hessian:'); WriteLn; WriteLn(Det:12:6); end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/optim/testsimp.pas�������������������������������������0000755�0001750�0001750�00000004203�11326425444�022117� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Minimization of a function of several variables by simplex method. Example: Rosenbrock's function: F(X, Y) = 100 * (Y - X^2)^2 + (1 - X)^2 True minimum is at (1, 1), F = 0 Ref: H. Rosenbrock, Comput. J., 1960, 3, 175 ****************************************************************** } program testsimp; uses tpmath; { ------------------------------------------------------------------ Define number of variables, number of iterations, and precision ------------------------------------------------------------------ } const Nvar = 2; { Number of variables } MaxIter = 1000; { Max number of iterations } Tol = 1.0E-6; { Required precision } { ------------------------------------------------------------------ Define the function to be minimized ------------------------------------------------------------------ } function Func(X : PVector) : Float; begin Func := 100.0 * Sqr(X^[2] - Sqr(X^[1])) + Sqr(1.0 - X^[1]); end; { ------------------------------------------------------------------ Main program ------------------------------------------------------------------ } var X : PVector; { Variables: X^[1] = X, X^[2] = Y } Fmin : Float; { Function value at minimum } I : Integer; { Loop variable } begin DimVector(X, Nvar); X^[1] := 2.0; X^[2] := 2.0; { Save Simplex iterations in a file } SaveSimplex('simplex.txt'); { Perform minimization } {$IFDEF FPC} Simplex(@Func, X, 1, Nvar, MaxIter, Tol, Fmin); {$ELSE} Simplex(Func, X, 1, Nvar, MaxIter, Tol, Fmin); {$ENDIF} if MathErr = OptNonConv then begin Write('Non-convergence!'); Halt; end; WriteLn('Minimization of Rosenbrock''s function (simplex method)'); WriteLn('------------------------------------------------------'); WriteLn; WriteLn('Coordinates of minimum:'); WriteLn; for I := 1 to Nvar do WriteLn('X(', I, ') = ', X^[I]:12:6); WriteLn; WriteLn('Function value:'); WriteLn; WriteLn('Fmin = ', Fmin); end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/optim/numgrad.inc��������������������������������������0000755�0001750�0001750�00000001635�10652717662�021707� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Numerical gradient ****************************************************************** } procedure Gradient(X, G : PVector); const Eta = 1.0E-4; { Relative increment } var I : Integer; { Loop variable } Temp : Float; { Temporary variable } Delta : Float; { Increment } Xm : Float; { X - Delta } Xp : Float; { X + Delta } Fm : Float; { F(X - Delta) } Fp : Float; { F(X + Delta) } begin for I := 1 to Nvar do begin if X^[I] <> 0.0 then Delta := Eta * Abs(X^[I]) else Delta := Eta; Xp := X^[I] + Delta; Xm := X^[I] - Delta; Temp := X^[I]; X^[I] := Xm; Fm := Func(X); X^[I] := Xp; Fp := Func(X); G^[I] := (Fp - Fm) / (2.0 * Delta); X^[I] := Temp end; end; ���������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/optim/testbfgs.pas�������������������������������������0000755�0001750�0001750�00000007455�11326425444�022104� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Minimization of a function of several variables by the Broyden- Fletcher-Goldfarb-Shanno (BFGS) method. Example: Rosenbrock's function: F(X, Y) = 100 * (Y - X^2)^2 + (1 - X)^2 ( -400 * (Y - X^2) * X - 2 + 2 * X ) Gradient: G = ( ) ( 200 * Y - 200 * X^2 ) ( 1200 * X^2 - 400 * Y + 2 -400 * X ) Hessian: H = ( ) ( -400 * X 200 ) True minimum is at (1, 1), F = 0 The inverse hessian at the minimum is: ( 1/2 1 ) ( 1 401/200 ) Ref: H. Rosenbrock, Comput. J., 1960, 3, 175 ****************************************************************** } program testbfgs; uses tpmath; { ------------------------------------------------------------------ Define number of variables, number of iterations, and precision ------------------------------------------------------------------ } const Nvar = 2; { Number of variables } MaxIter = 1000; { Max number of iterations } Tol = 1.0E-6; { Required precision } { ------------------------------------------------------------------ Define the function to be minimized ------------------------------------------------------------------ } function Func(X : PVector) : Float; begin Func := 100.0 * Sqr(X^[2] - Sqr(X^[1])) + Sqr(1.0 - X^[1]); end; { ------------------------------------------------------------------ Define the subroutine which computes the gradient of the function. It is recommended to use analytical derivatives whenever possible. Otherwise you can use the alternative code provided in numgrad.inc ------------------------------------------------------------------ } procedure Gradient(X, G : PVector); var A, B : Float; begin A := X^[2] - Sqr(X^[1]); B := 1.0 - X^[1]; G^[1] := - 400.0 * X^[1] * A - 2.0 * B; G^[2] := 200.0 * A; end; { ------------------------------------------------------------------ Alternative code when analytical derivatives are not available ------------------------------------------------------------------ } (* {$i numgrad.inc} *) { ------------------------------------------------------------------ Main program ------------------------------------------------------------------ } var X : PVector; { Variables: X^[1] = X, X^[2] = Y } G : PVector; { Gradient vector } H_inv : PMatrix; { Inverse Hessian matrix } F_min : Float; { Function value at minimum } I, J : Integer; { Loop variables } begin DimVector(X, Nvar); DimVector(G, Nvar); DimMatrix(H_inv, Nvar, Nvar); X^[1] := 2.0; X^[2] := 2.0; { Save BFGS iterations in a file } SaveBFGS('bfgs.txt'); { Perform minimization } {$IFDEF FPC} BFGS(@Func, @Gradient, X, 1, Nvar, MaxIter, Tol, F_min, G, H_inv); {$ELSE} BFGS(Func, Gradient, X, 1, Nvar, MaxIter, Tol, F_min, G, H_inv); {$ENDIF} if MathErr = OptNonConv then begin Write('Non-convergence!'); Halt; end; WriteLn('Minimization of Rosenbrock''s function (BFGS method)'); WriteLn('----------------------------------------------------'); WriteLn; WriteLn('Coordinates of minimum:'); WriteLn; for I := 1 to Nvar do WriteLn(X^[I]:12:6); WriteLn; WriteLn('Function value:'); WriteLn; WriteLn('Fmin = ', F_min); WriteLn; WriteLn('Gradient:'); WriteLn; for I := 1 to Nvar do WriteLn(G^[I]:12:6); WriteLn; WriteLn('Inverse Hessian matrix:'); WriteLn; for I := 1 to Nvar do begin for J := 1 to Nvar do Write(H_inv^[I]^[J]:12:6); WriteLn; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/integral/����������������������������������������������0000755�0001750�0001750�00000000000�12360760644�020220� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/integral/trap.pas��������������������������������������0000755�0001750�0001750�00000001756�11326425444�021704� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program computes the area under an experimental curve by the trapezoidal rule. The result is compared with the exact value. Data are generated with the function exp(-x) for x = 0..1 The exact integral is: (1 | exp(-x) dx = 1 - exp(-1) ~ 0.6321 )0 ****************************************************************** } program Trap; uses tpmath; const N = 10; var X, Y : PVector; I : Integer; begin DimVector(X, N); DimVector(Y, N); for I := 0 to N do begin X^[I] := 0.1 * I; Y^[I] := Exp(- X^[I]); end; WriteLn(' X Y'); WriteLn('--------------------'); for I := 0 to N do WriteLn(X^[I]:10:4, Y^[I]:10:4); WriteLn('--------------------'); WriteLn; WriteLn('Area under curve:'); WriteLn; WriteLn('TrapInt: ', TrapInt(X, Y, N):10:4); WriteLn('Exact : ', 1.0 - Exp(- 1.0):10:4); end. ������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/integral/test_rkf.pas����������������������������������0000755�0001750�0001750�00000013347�11326425444�022556� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Integrate a System of Ordinary Differential Equations By the Runge-Kutta-Fehlberg method (double precision) ----------------------------------------------------------------- REFERENCE: H A Watts and L F Shampine, Sandia Laboratories, Albuquerque, New Mexico. ----------------------------------------------------------------- Basic Release 1.1 By J-P Moreau, Paris. TPMath adaptation by J. Debord Release 1.1: added test #3. ****************************************************************** } program test_rkf; uses crt, tpmath; procedure DiffEq1(T : Float; Y, Yp : PVector); { Differential equation for Test 1 } begin Yp^[1] := 0.25 * Y^[1] * (1 - Y^[1] / 20); end; function Yexact1(T : Float) : Float; { Exact solution of the ODE for Test 1 } begin Yexact1 := 20 / (1 + 19 * Exp(- 0.25 * T)); end; procedure DiffEq2(T : Float; Y, Yp : PVector); { Differential equations for Test 2 } begin Yp^[1] := Y^[2]; Yp^[2] := - Y^[1]; end; procedure Yexact2(T : Float; var Y1, Y2 : Float); { Exact solution of the ODE's for Test 2 } begin Y1 := Cos(T); Y2 := - Sin(T); end; procedure DiffEq3(T : Float; Y, Yp : PVector); { Differential equations for Test 3 } begin Yp^[1] := Y^[2]; Yp^[2] := Y^[3]; Yp^[3] := Y^[4]; Yp^[4] := Y^[5]; Yp^[5] := (45 * Y^[3] * Y^[4] * Y^[5] - 40 * Y^[4] * Sqr(Y^[4])) / (9 * Sqr(Y^[3])); end; var { Global variables used by all test procedures } Neqn : Integer; { Number of equations } Y, Yp : PVector; { Functions and derivatives } Tstart, Tstop : Float; { Integration interval } Nstep : Integer; { Number of steps } StepSize : Float; { Step size } AbsErr, RelErr : Float; { Abs. and relative errors } Flag : Integer; { Error flag } T, Tout : Float; { Integration times } I : Integer; { Loop variable } procedure Test1; var Yc : Float; { Exact solution } begin Neqn := 1; DimVector(Y, Neqn); DimVector(Yp, Neqn); Y^[1] := 1; { Initial condition } Tstart := 0; Tstop := 20; Nstep := 5; StepSize := (Tstop - Tstart) / Nstep; AbsErr := 1.0E-6; RelErr := 1.0E-6; Flag := 1; T := Tstart; WriteLn; WriteLn('TEST01'); WriteLn('Solve a scalar equation:'); WriteLn; WriteLn(' Y'' = 0.25 * Y * ( 1 - Y / 20 )'); WriteLn; WriteLn(' T Y Y exact Error'); WriteLn; Yc := Yexact1(T); WriteLn(T:5:2, Y^[1]:14:4, Yc:14:4, (Y^[1] - Yc):14:4); for I := 1 to Nstep do begin Tout := T + StepSize; {$IFDEF FPC} RKF45(@DiffEq1, Neqn, Y, Yp, T, Tout, RelErr, AbsErr, Flag); {$ELSE} RKF45(DiffEq1, Neqn, Y, Yp, T, Tout, RelErr, AbsErr, Flag); {$ENDIF} Yc := Yexact1(Tout); WriteLn(T:5:2, Y^[1]:14:4, Yc:14:4, (Y^[1] - Yc):14:4); T := Tout; end; DelVector(Y, Neqn); DelVector(Yp, Neqn); end; procedure Test2; var Yc1, Yc2 : Float; { Exact solution } begin Neqn := 2; DimVector(Y, Neqn); DimVector(Yp, Neqn); Y^[1] := 1; { Initial conditions } Y^[2] := 0; Tstart := 0; Tstop := 2 * Pi; Nstep := 12; StepSize := (Tstop - Tstart) / Nstep; AbsErr := 1.0E-6; RelErr := 1.0E-6; Flag := 1; T := Tstart; WriteLn; WriteLn('TEST02'); WriteLn('Solve a vector equation:'); WriteLn; WriteLn(' Y''(1) = Y(2)'); WriteLn(' Y''(2) = - Y(1)'); WriteLn; WriteLn(' T Y1 Y1 exact Y2 Y2 exact'); WriteLn; Yexact2(T, Yc1, Yc2); WriteLn(T:5:2, Y^[1]:14:4, Yc1:14:4, Y^[2]:14:4, Yc2:14:4); for I := 1 to Nstep do begin Tout := T + StepSize; {$IFDEF FPC} RKF45(@DiffEq2, Neqn, Y, Yp, T, Tout, RelErr, AbsErr, Flag); {$ELSE} RKF45(DiffEq2, Neqn, Y, Yp, T, Tout, RelErr, AbsErr, Flag); {$ENDIF} Yexact2(Tout, Yc1, Yc2); WriteLn(T:5:2, Y^[1]:14:4, Yc1:14:4, Y^[2]:14:4, Yc2:14:4); T := Tout; end; DelVector(Y, Neqn); DelVector(Yp, Neqn); end; procedure Test3; begin Neqn := 5; DimVector(Y, Neqn); DimVector(Yp, Neqn); Y^[1] := 1; { Initial conditions } Y^[2] := 1; Y^[3] := 1; Y^[4] := 1; Y^[5] := 1; Tstart := 0; Tstop := 1.5; Nstep := 11; StepSize := (Tstop - Tstart) / Nstep; AbsErr := 1.0E-6; RelErr := 1.0E-6; Flag := 1; T := Tstart; WriteLn; WriteLn('TEST03'); WriteLn('Solve a vector equation:'); WriteLn; WriteLn(' Y''(1) = Y(2)'); WriteLn(' Y''(2) = Y(3)'); WriteLn(' Y''(3) = Y(4)'); WriteLn(' Y''(4) = Y(5)'); WriteLn(' Y''(5) = (45 * Y(3) * Y(4) * Y(5) - 40 * Y(4)^3) / (9 * Y(3)^2)'); WriteLn; WriteLn(' T Y1 Y2 Y3 Y4 Y5'); WriteLn; WriteLn(T:5:2, Y^[1]:14:4, Y^[2]:14:4, Y^[3]:14:4, Y^[4]:14:4, Y^[5]:14:4); for I := 1 to Nstep do begin Tout := T + StepSize; {$IFDEF FPC} RKF45(@DiffEq3, Neqn, Y, Yp, T, Tout, RelErr, AbsErr, Flag); {$ELSE} RKF45(DiffEq3, Neqn, Y, Yp, T, Tout, RelErr, AbsErr, Flag); {$ENDIF} WriteLn(T:5:2, Y^[1]:14:4, Y^[2]:14:4, Y^[3]:14:4, Y^[4]:14:4, Y^[5]:14:4); T := Tout; end; DelVector(Y, Neqn); DelVector(Yp, Neqn); end; procedure Pause; var Ch : Char; begin Writeln; Write('Press a key to continue'); Ch := ReadKey; Writeln; Writeln; end; begin WriteLn; WriteLn('PROGRAM TEST_RKF'); WriteLn('Demonstrate the RKF45 ODE integrator.'); Test1; Pause; Test2; Pause; Test3; Pause; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/integral/conv.pas��������������������������������������0000755�0001750�0001750�00000002333�11326425444�021673� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program computes the convolution product H of two functions F and G by the Gauss-Legendre method. The result is compared with the analytical solution. The example functions are: F(x) = x * exp(-x) G(x) = exp(-2 * x) The analytical solution is: H(x) = (F * G)(x) = (x - 1) * exp(-x) + exp(-2 * x) ****************************************************************** } program Conv; uses tpmath; function F(X : Float) : Float; begin F := X * Exp(-X); end; function G(X : Float) : Float; begin G := Exp(- 2 * X); end; function H(X : Float) : Float; var E : Float; begin E := Exp(-X); H := ((X - 1) + E) * E; end; const N = 10; var X, Y : array[0..N] of Float; I : Integer; begin X[0] := 0.0; Y[0] := 0.0; for I := 1 to N do begin X[I] := 0.1 * I; {$IFDEF FPC} Y[I] := Convol(@F, @G, X[I]); {$ELSE} Y[I] := Convol(F, G, X[I]); {$ENDIF} end; WriteLn(' X Convol Exact'); WriteLn('------------------------------'); for I := 0 to N do WriteLn(X[I]:10:4, Y[I]:10:4, H(X[I]):10:4); end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/integral/gauss.pas�������������������������������������0000755�0001750�0001750�00000002201�11326425444�022042� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program computes an integral by the Gauss-Legendre method. The result is compared with the analytical solution. The example function is: F(x) = x * exp(-x) The analytical solution is: (x G(x) = | F(t) dt = 1 - (x + 1) * exp(-x) )0 ****************************************************************** } program Gauss; uses tpmath; function F(X : Float) : Float; { Function to integrate } begin F := X * Exp(-X); end; function G(X : Float) : Float; { Integral } begin G := 1 - (X + 1) * Exp(-X); end; const N = 10; var X, Y : array[0..N] of Float; I : Integer; begin X[0] := 0.0; Y[0] := 0.0; for I := 1 to N do begin X[I] := I; {$IFDEF FPC} Y[I] := GausLeg0(@F, X[I]); {$ELSE} Y[I] := GausLeg0(F, X[I]); { or GausLeg(F, 0, X[I]) } {$ENDIF} end; WriteLn(' X GausLeg Exact'); WriteLn('------------------------------'); for I := 0 to N do WriteLn(X[I]:10:4, Y[I]:10:4, G(X[I]):10:4); end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/polynom/�����������������������������������������������0000755�0001750�0001750�00000000000�12360760644�020110� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/polynom/evalpoly.pas�����������������������������������0000755�0001750�0001750�00000001667�11326425444�022462� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program evaluates a polynomial Example polynomial is P(X) = 1 + X + 2*X^2 + 3*X^3 + 4*X^4 ****************************************************************** } program evalpoly; uses tpmath; var Coef : PVector; Deg : Integer; X, Y : Float; begin { ------------------------------------------------------------------ Define polynomial here, in the form: Coef(0) + Coef(1) * X + Coef(2) * X^2 + ... + Coef(Deg) * X^Deg ------------------------------------------------------------------ } Deg := 4; DimVector(Coef, Deg); Coef^[0] := 1; Coef^[1] := 1; Coef^[2] := 2; Coef^[3] := 3; Coef^[4] := 4; { ------------------------------------------------------------------ } repeat Write('X = '); ReadLn(X); Y := Poly(X, Coef, Deg); WriteLn('P(X) = ', Y:12:6); until X = 0; end. �������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/polynom/evalfrac.pas�����������������������������������0000755�0001750�0001750�00000002567�11326425444�022412� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program evaluates a rational fraction 1 + X + 2*X^2 + 3*X^3 + 4*X^4 Example fraction is F(X) = ------------------------------- 1 + 2*X - 3*X^2 + 4*X^3 - 5*X^4 ****************************************************************** } program evalfrac; uses tpmath; var Coef : PVector; Deg1, Deg2 : Integer; X, Y : Float; begin { ------------------------------------------------------------------ Define fraction here, in the form: Coef(0) + Coef(1) * X + ... + Coef(Deg1) * X^Deg1 F(X) = ----------------------------------------------------- 1 + Coef(Deg1+1) * X + ... + Coef(Deg1+Deg2) * X^Deg2 Note that the first coefficient of the denominator must be 1 ------------------------------------------------------------------ } Deg1 := 4; Deg2 := 4; DimVector(Coef, Deg1 + Deg2); Coef^[0] := 1; Coef^[1] := 1; Coef^[2] := 2; Coef^[3] := 3; Coef^[4] := 4; Coef^[5] := 2; Coef^[6] := -3; Coef^[7] := 4; Coef^[8] := -5; { ------------------------------------------------------------------ } repeat Write('X = '); ReadLn(X); Y := RFrac(X, Coef, Deg1, Deg2); WriteLn('F(X) = ', Y:12:6); until X = 0; end. �����������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/polynom/polyroot.pas�����������������������������������0000755�0001750�0001750�00000005363�11326425444�022513� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program solves a polynomial equation Analytical solutions are used up to degree 4, then the polynomial is solved by the method of the companion matrix. The example polynomial is: 720 - 1764 * X + 1624 * X^2 - 735 * X^3 + 175 * X^4 - 21 * X^5 + X^6 The roots are: X = 1, 2 ... 6 ****************************************************************** } program polyroot; uses tpmath; var Coef : PVector; Z : PCompVector; Deg, I, J, Nc, Nr : Integer; begin { ------------------------------------------------------------------ Define polynomial here, in the form: Coef(0) + Coef(1) * X + Coef(2) * X^2 + ... + Coef(Deg) * X^Deg ------------------------------------------------------------------ } Deg := 6; DimVector(Coef, Deg); DimCompVector(Z, Deg); Coef^[0] := 720; Coef^[1] := -1764; Coef^[2] := 1624; Coef^[3] := -735; Coef^[4] := 175; Coef^[5] := -21; Coef^[6] := 1; { ------------------------------------------------------------------ } Writeln; Writeln('Polynomial:'); Writeln; for I := 0 to Deg do if Coef^[I] <> 0 then begin if Coef^[I] > 0 then Write(' + '); if Coef^[I] < 0 then Write(' - '); Write(Abs(Coef^[I]):12:6, ' '); if I > 0 then Write('X'); if I > 1 then Write('^', I); Writeln; end; Writeln; Writeln; { Solve polynomial. Nr is the number of real roots } case Deg of 1 : Nr := RootPol1(Coef^[0], Coef^[1], Z^[1].X); 2 : Nr := RootPol2(Coef, Z); 3 : Nr := RootPol3(Coef, Z); 4 : Nr := RootPol4(Coef, Z); otherwise Nr := RootPol(Coef, Deg, Z); end; { Case when an error occurs } if Nr < 0 then begin Writeln('Error during root evaluation !'); Halt; end; { Set the small imaginary parts to zero (optional) } Nr := SetRealRoots(Deg, Z, 1.0E-8); { Sort roots: first real roots, in ascending order, then complex roots (unordered) } SortRoots(Deg, Z); { Print real roots } if Nr > 0 then begin Writeln(Nr, ' real root(s):'); Writeln; for I := 1 to Nr do Writeln('X[', I, '] = ', Z^[I].X:12:6); Writeln; end; { Print complex roots } Nc := Deg - Nr; if Nc > 0 then begin Writeln(Nc, ' complex roots:'); Writeln; for I := 1 to Nc do begin J := I + Nr; Write('X[', J, '] = ', Z^[J].X:12:6); if Z^[J].Y > 0.0 then Write(' + ') else Write(' - '); Writeln(Abs(Z^[J].Y):12:6, ' * i'); end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/equation/����������������������������������������������0000755�0001750�0001750�00000000000�12360760644�020240� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/equation/testnr.pas������������������������������������0000755�0001750�0001750�00000006241�11326425444�022267� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Solution to a system of nonlinear equations by the Newton-Raphson method. Example (from Numerical Recipes Example Book): F(X, Y) = X^2 + Y^2 - 2 = 0 G(X, Y) = EXP(X - 1) + Y^3 - 2 = 0 ( 2 * X 2 * Y ) Jacobian: D = ( ) ( EXP(X - 1) 3 * Y^2 ) True Solution is at (1, 1) ****************************************************************** } program testnr; uses tpmath; { ****************************************************************** Define number of variables, number of iterations, and precision ****************************************************************** } const Nvar = 2; { Number of variables } MaxIter = 1000; { Max number of iterations } Tol = 1.0E-6; { Required precision (must be > Sqrt(MachEp)) } { ****************************************************************** Define the system of equations to be solved ****************************************************************** } procedure Equations (X, F : PVector); var X1p2, X2p2, X2p3 : Float; begin X1p2 := X^[1] * X^[1]; X2p2 := X^[2] * X^[2]; X2p3 := X^[2] * X2p2; F^[1] := X1p2 + X2p2 - 2; F^[2] := Exp(X^[1] - 1) + X2p3 - 2; end; { ****************************************************************** Define the subroutine which computes the jacobian of the system. It is recommended to use analytical derivatives whenever possible. Otherwise you can use the alternative code provided in numjac.inc ****************************************************************** } procedure Jacobian(X : PVector; D : PMatrix); begin D^[1]^[1] := 2 * X^[1]; D^[1]^[2] := 2 * X^[2]; D^[2]^[1] := Exp(X^[1] - 1); D^[2]^[2] := 3 * X^[2] * X^[2]; end; { ****************************************************************** Alternative code if the analytical derivatives are not available ****************************************************************** } (* {$i numjac.inc} *) { ****************************************************************** Main program ****************************************************************** } var X, F : PVector; { Variables: X^[1] = X, X^[2] = Y } I : Integer; { Loop variable } begin DimVector(X, Nvar); DimVector(F, Nvar); { Define starting point } X^[1] := 2; X^[2] := 0.5; {$IFDEF FPC} NewtEqs(@Equations, @Jacobian, X, F, 1, Nvar, MaxIter, Tol); {$ELSE} NewtEqs(Equations, Jacobian, X, F, 1, Nvar, MaxIter, Tol); {$ENDIF} if MathErr = OptNonConv then begin writeln('Non-convergence!'); halt; end; writeln; writeln('Solution to nonlinear equation system (Newton-Raphson method)'); writeln('-------------------------------------------------------------'); writeln; writeln('Solution vector:'); writeln; for I := 1 to Nvar do writeln('X(', I, ') = ', X^[I]:10:6); writeln; writeln('Function values:'); writeln; for I := 1 to Nvar do writeln('F(', I, ') = ', F^[I]:10:6); writeln; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/equation/testnr1.pas�����������������������������������0000755�0001750�0001750�00000003513�11326425444�022347� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Solution to a nonlinear equation by the Newton-Raphson method. Example: F(X) = X * Ln(X) - 1 = 0 Derivative: F'(X) = Ln(X) + 1 True Solution is X = 1.763222834... ****************************************************************** } program testnr1; uses tpmath; { ****************************************************************** Define the function and its derivative ****************************************************************** } function Func(X : Float) : Float; begin Func := X * Ln(X) - 1 end; function Deriv(X : Float) : Float; begin Deriv := Ln(X) + 1 end; { ****************************************************************** Define number of iterations and precision ****************************************************************** } const MaxIter = 1000; { Max number of iterations } Tol = 1E-6; { Required precision } { ****************************************************************** Main program ****************************************************************** } var F, X : Float; begin { Define a starting point near the root } X := 1; {$IFDEF FPC} NewtEq(@Func, @Deriv, X, MaxIter, Tol, F); {$ELSE} NewtEq(Func, Deriv, X, MaxIter, Tol, F); {$ENDIF} case MathErr of OptNonConv : begin writeln('Non-convergence!'); halt; end; OptSing : begin writeln('Null derivative!'); halt; end; end; writeln; writeln('Solution to nonlinear equation (Newton-Raphson method)'); writeln('------------------------------------------------------'); writeln; writeln('Root: ', X:12:6); writeln; writeln('Function value:', F:12:6); writeln; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/equation/testbrdn.pas����������������������������������0000755�0001750�0001750�00000004561�11326425444�022600� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Solution to a system of nonlinear equations by Broyden's method. Example (from Numerical Recipes Example Book): F(X, Y) = X^2 + Y^2 - 2 = 0 G(X, Y) = EXP(X - 1) + Y^3 - 2 = 0 ( 2 * X 2 * Y ) Jacobian: D = ( ) ( EXP(X - 1) 3 * Y^2 ) True Solution is at (1, 1) ****************************************************************** } program testbrdn; uses tpmath; { ****************************************************************** Define the system of equations to be solved ****************************************************************** } procedure Equations(X, F : PVector); var X1p2, X2p2, X2p3 : Float; begin X1p2 := X^[1] * X^[1]; X2p2 := X^[2] * X^[2]; X2p3 := X^[2] * X2p2; F^[1] := X1p2 + X2p2 - 2; F^[2] := Exp(X^[1] - 1) + X2p3 - 2; end; { ****************************************************************** Define number of variables, number of iterations, and precision ****************************************************************** } const Nvar = 2; { Number of variables } MaxIter = 1000; { Max number of iterations } Tol = 1.0E-6; { Required precision (must be > Sqrt(MachEp)) } var X, F : PVector; { Variables: X^[1] = X, X^[2] = Y } I : Integer; { Loop variable } { ****************************************************************** Main program ****************************************************************** } begin DimVector(X, Nvar); DimVector(F, Nvar); { Define starting point } X^[1] := 2; X^[2] := 0.5; {$IFDEF FPC} Broyden(@Equations, X, F, 1, Nvar, MaxIter, Tol); {$ELSE} Broyden(Equations, X, F, 1, Nvar, MaxIter, Tol); {$ENDIF} if MathErr = OptNonConv then begin writeln('Non-convergence!'); halt; end; writeln; writeln('Solution to nonlinear equation system (Broyden''s method)'); writeln('--------------------------------------------------------'); writeln; writeln('Solution vector:'); writeln; for I := 1 to Nvar do writeln('X(', I, ') = ', X^[I]:10:6); writeln; writeln('Function values:'); writeln; for I := 1 to Nvar do writeln('F(', I, ') = ', F^[I]:10:6); writeln; end. �����������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/equation/numjac.inc������������������������������������0000755�0001750�0001750�00000002672�10652717660�022224� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Numerical jacobian ****************************************************************** } procedure Jacobian(X : PVector; D : PMatrix); const EtaMin = 1E-6; { Relative increment used to compute derivatives } var I, J : Integer; R, Temp : Float; Eta : Float; Delta : PVector; { Increment } Xminus : PVector; { X - Delta } Xplus : PVector; { X + Delta } Fminus : PVector; { F(X - Delta) } Fplus : PVector; { F(X + Delta) } begin DimVector(Delta, Nvar); DimVector(Xminus, Nvar); DimVector(Xplus, Nvar); DimVector(Fminus, Nvar); DimVector(Fplus, Nvar); Eta := Sqrt(MachEp); if Eta < EtaMin then Eta := EtaMin; for I := 1 to Nvar do begin if X^[I] <> 0 then Delta^[I] := Eta * Abs(X^[I]) else Delta^[I] := Eta; Xplus^[I] := X^[I] + Delta^[I]; Xminus^[I] := X^[I] - Delta^[I] end; for J := 1 to Nvar do begin Temp := X^[J]; X^[J] := Xminus^[J]; Equations(X, Fminus); X^[J] := Xplus^[J]; Equations(X, Fplus); R := 1.0 / (2.0 * Delta^[J]); for I := 1 to Nvar do D^[I]^[J] := R * (Fplus^[I] - Fminus^[I]); X^[J] := Temp; end; DelVector(Delta, Nvar); DelVector(Xminus, Nvar); DelVector(Xplus, Nvar); DelVector(Fminus, Nvar); DelVector(Fplus, Nvar); end; ����������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/equation/testsec.pas�����������������������������������0000755�0001750�0001750�00000003110�11326425444�022412� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Solution to a nonlinear equation by the secant method. Example: F(X) = X * Ln(X) - 1 = 0 True Solution is X = 1.763222834... ****************************************************************** } program testsec; uses tpmath; { ****************************************************************** Define the function ****************************************************************** } function Func(X : Float) : Float; begin Func := X * Ln(X) - 1 end; { ****************************************************************** Define number of iterations and precision ****************************************************************** } const MaxIter = 1000; { Max number of iterations } Tol = 1E-6; { Required precision } { ****************************************************************** Main program ****************************************************************** } var F, X, Y : Float; begin { Give two starting points near the root } X := 1; Y := 2; {$IFDEF FPC} Secant(@Func, X, Y, MaxIter, Tol, F); {$ELSE} Secant(Func, X, Y, MaxIter, Tol, F); {$ENDIF} if MathErr = OptNonConv then begin writeln('Non-convergence!'); halt; end; writeln; writeln('Solution to nonlinear equation (Secant method)'); writeln('----------------------------------------------'); writeln; writeln('Root: ', X:12:6); writeln; writeln('Function value:', F:12:6); writeln; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/equation/testbis.pas�����������������������������������0000755�0001750�0001750�00000003121�11326425444�022417� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Solution to a nonlinear equation by the bisection method. Example: F(X) = X * Ln(X) - 1 = 0 True Solution is X = 1.763222834... ****************************************************************** } program testbis; uses tpmath; { ****************************************************************** Define the function ****************************************************************** } function Func(X : Float) : Float; begin Func := X * Ln(X) - 1 end; { ****************************************************************** Define number of iterations and precision ****************************************************************** } const MaxIter = 1000; { Max number of iterations } Tol = 1E-6; { Required precision } { ****************************************************************** Main program ****************************************************************** } var F, X, Y : Float; begin { Give two starting points near the root } X := 1; Y := 2; {$IFDEF FPC} Bisect(@Func, X, Y, MaxIter, Tol, F); {$ELSE} Bisect(Func, X, Y, MaxIter, Tol, F); {$ENDIF} if MathErr = OptNonConv then begin writeln('Non-convergence!'); halt; end; writeln; writeln('Solution to nonlinear equation (Bisection method)'); writeln('-------------------------------------------------'); writeln; writeln('Root: ', X:12:6); writeln; writeln('Function value:', F:12:6); writeln; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/fmath/�������������������������������������������������0000755�0001750�0001750�00000000000�12360760644�017512� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/fmath/testfunc.pas�������������������������������������0000755�0001750�0001750�00000015604�11326425444�022060� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program tests the accuracy of the elementary functions. For each function, 20 random arguments are picked, then the function is computed, the reciprocal function is applied to the result, and the relative error between this last result and the original argument is computed. ****************************************************************** } program testfunc; uses crt, tpmath; const NARG = 20; { Number of arguments } BLANK = ' '; { Separator } type TVector = array[1..NARG] of Float; var X, Y : TVector; { Random arguments } procedure Pause; var Ch : Char; begin Writeln; Write('Press a key to continue'); Ch := ReadKey; Writeln; Writeln; end; procedure RanArgs(var X : TVector; Xmin, Xmax : Float); { Fills a table of random arguments between Xmin and Xmax, rounded to 4 decimal places and sorted in increasing order. } var I, J, K : integer; A : Float; begin for I := 1 to NARG do begin A := (Xmax - Xmin) * Random + Xmin; if Abs(A) < 1.0E-4 then A := Sgn(A) * 1.0E-4; X[I] := Int(10000 * A) / 10000; end; { Insertion sort } for I := 1 to Pred(NARG) do begin K := I; A := X[I]; for J := Succ(I) to NARG do if X[J] < A then begin K := J; A := X[J]; end; FSwap(X[I], X[K]); end; end; procedure Test_Exp; var I : Integer; Z, T, R : Float; begin RanArgs(X, -10, 10); WriteLn(' X Y = Expo(X) X = Log(Y) Rel.Error'); WriteLn('-------------------------------------------------------------------------------'); for I := 1 to NARG do begin Z := Expo(X[I]); T := Log(Z); R := (X[I] - T) / X[I]; WriteLn(X[I]:8:4, BLANK, Z:26, BLANK, T:26, BLANK, R:10); end; Pause; end; procedure Test_Exp10; var I : Integer; Z, T, R : Float; begin RanArgs(X, -5, 5); WriteLn(' X Y = Exp10(X) X = Log10(Y) Rel.Error'); WriteLn('-------------------------------------------------------------------------------'); for I := 1 to NARG do begin Z := Exp10(X[I]); T := Log10(Z); R := (X[I] - T) / X[I]; WriteLn(X[I]:8:4, BLANK, Z:26, BLANK, T:26, BLANK, R:10); end; Pause; end; procedure Test_Exp2; var I : Integer; Z, T, R : Float; begin RanArgs(X, -15, 15); WriteLn(' X Y = Exp2(X) X = Log2(Y) Rel.Error'); WriteLn('-------------------------------------------------------------------------------'); for I := 1 to NARG do begin Z := Exp2(X[I]); T := Log2(Z); R := (X[I] - T) / X[I]; WriteLn(X[I]:8:4, BLANK, Z:26, BLANK, T:26, BLANK, R:10); end; Pause; end; procedure Test_Power; var I : Integer; Z, T, R : Float; begin RanArgs(X, 0, 10); RanArgs(Y, -5, 5); WriteLn(' X Y Z = Power(X, Y) Y = Log(Z, X) Rel.Error'); WriteLn('-------------------------------------------------------------------------------'); for I := 1 to NARG do begin Z := Power(X[I], Y[I]); { X^Y } T := LogA(Z, X[I]); { Log(X^Y, X) = Y } R := (Y[I] - T) / Y[I]; WriteLn(X[I]:6:4, Y[I]:8:4, ' ', Z:26, ' ', T:26, ' ', R:10); end; Pause; end; procedure Test_Sin; var I : Integer; Z, T, R : Float; begin RanArgs(X, -PiDiv2, PiDiv2); WriteLn(' X Y = Sin(X) X = ArcSin(Y) Rel.Error'); WriteLn('-------------------------------------------------------------------------------'); for I := 1 to NARG do begin Z := Sin(X[I]); T := ArcSin(Z); R := (X[I] - T) / X[I]; WriteLn(X[I]:8:4, BLANK, Z:26, BLANK, T:26, BLANK, R:10); end; Pause; end; procedure Test_Cos; var I : Integer; Z, T, R : Float; begin RanArgs(X, 0, PI); WriteLn(' X Y = Cos(X) X = ArcCos(Y) Rel.Error'); WriteLn('-------------------------------------------------------------------------------'); for I := 1 to NARG do begin Z := Cos(X[I]); T := ArcCos(Z); R := (X[I] - T) / X[I]; WriteLn(X[I]:8:4, BLANK, Z:26, BLANK, T:26, BLANK, R:10); end; Pause; end; procedure Test_Tan; var I : Integer; Z, T, R : Float; begin RanArgs(X, -PiDiv2, PiDiv2); WriteLn(' X Y = Tan(X) X = ArcTan(Y) Rel.Error'); WriteLn('-------------------------------------------------------------------------------'); for I := 1 to NARG do begin Z := Tan(X[I]); T := ArcTan(Z); R := (X[I] - T) / X[I]; WriteLn(X[I]:8:4, BLANK, Z:26, BLANK, T:26, BLANK, R:10); end; Pause; end; procedure Test_Sinh; var I : Integer; Z, T, R : Float; begin RanArgs(X, 0, 5); WriteLn(' X Y = Sinh(X) X = ArcSinh(Y) Rel.Error'); WriteLn('-------------------------------------------------------------------------------'); for I := 1 to NARG do begin Z := Sinh(X[I]); T := ArcSinh(Z); R := (X[I] - T) / X[I]; WriteLn(X[I]:8:4, BLANK, Z:26, BLANK, T:26, BLANK, R:10); end; Pause; end; procedure Test_Cosh; var I : Integer; Z, T, R : Float; begin RanArgs(X, 0, 5); WriteLn(' X Y = Cosh(X) X = ArcCosh(Y) Rel.Error'); WriteLn('-------------------------------------------------------------------------------'); for I := 1 to NARG do begin Z := Cosh(X[I]); T := ArcCosh(Z); R := (X[I] - T) / X[I]; WriteLn(X[I]:8:4, BLANK, Z:26, BLANK, T:26, BLANK, R:10); end; Pause; end; procedure Test_Tanh; var I : Integer; Z, T, R : Float; begin RanArgs(X, -5, 5); WriteLn(' X Y = Tanh(X) X = ArcTanh(Y) Rel.Error'); WriteLn('-------------------------------------------------------------------------------'); for I := 1 to NARG do begin Z := Tanh(X[I]); T := ArcTanh(Z); R := (X[I] - T) / X[I]; WriteLn(X[I]:8:4, BLANK, Z:26, BLANK, T:26, BLANK, R:10); end; Pause; end; begin Test_Exp; Test_Exp10; Test_Exp2; Test_Power; Test_Sin; Test_Cos; Test_Tan; Test_Sinh; Test_Cosh; Test_Tanh; end. ����������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/fmath/testw.pas����������������������������������������0000755�0001750�0001750�00000040060�11326425444�021365� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Test of Lamberts's function This program has been translated from a FORTRAN program written by Barry et al. (http://www.netlib.org/toms/743) ****************************************************************** } uses tpmath; { Upper branch, X given as offset from -1/e } const DX1 : array[1..68] of Float = (1.E-40, 2.E-40, 3.E-40, 4.E-40, 5.E-40, 6.E-40, 7.E-40, 8.E-40, 9.E-40, 1.E-39, 1.E-30, 2.E-30, 3.E-30, 4.E-30, 5.E-30, 6.E-30, 7.E-30, 8.E-30, 9.E-30, 1.E-29, 1.E-20, 2.E-20, 3.E-20, 4.E-20, 5.E-20, 6.E-20, 7.E-20, 8.E-20, 9.E-20, 1.E-19, 1.E-10, 2.E-10, 3.E-10, 4.E-10, 5.E-10, 6.E-10, 7.E-10, 8.E-10, 9.E-10, 1.E-9, 1.E-5, 2.E-5, 3.E-5, 4.E-5, 5.E-5, 6.E-5, 7.E-5, 8.E-5, 9.E-5, 1.E-4, 2.E-4, 3.E-4, 4.E-4, 5.E-4, 6.E-4, 7.E-4, 8.E-4, 9.E-4, 1.E-3, 2.E-3, 3.E-3, 4.E-3, 5.E-3, 6.E-3, 7.E-3, 8.E-3, 9.E-3, 1.E-2); const WP1 : array[1..68] of Float = (- 0.9999999999999999999766835601840287579665, - 0.9999999999999999999670255745859974370634, - 0.9999999999999999999596147415871158855702, - 0.9999999999999999999533671203680575159335, - 0.9999999999999999999478628555782056161596, - 0.9999999999999999999428866198325571498809, - 0.9999999999999999999383104987875354650364, - 0.9999999999999999999340511491719948741275, - 0.9999999999999999999300506805520862739007, - 0.9999999999999999999262669432552936235556, - 0.9999999999999976683560184028776088243496, - 0.9999999999999967025574585997473306784697, - 0.9999999999999959614741587115939935280812, - 0.9999999999999953367120368057588420244704, - 0.9999999999999947862855578205706768098859, - 0.9999999999999942886619832557258611080314, - 0.9999999999999938310498787535591888253966, - 0.999999999999993405114917199501910108482, - 0.9999999999999930050680552086436996003626, - 0.9999999999999926266943255293804772564852, - 0.9999999997668356018584094585181033975713, - 0.9999999996702557458962181283375794922681, - 0.9999999995961474159255244922555603070484, - 0.9999999995336712037530626747373742782638, - 0.9999999994786285558726655558473617503914, - 0.9999999994288661984343027719079710168757, - 0.9999999993831049880022078023099082447845, - 0.9999999993405114918649237720678678043098, - 0.9999999993005068056839596486461928553989, - 0.9999999992626694327341550240404575805522, - 0.9999766837414008807143234266407434345965, - 0.9999670259370180970391011806287847685011, - 0.9999596152852334187587360603177913882165, - 0.9999533678452277190993205651165793258207, - 0.9999478637616504968301143759542621752943, - 0.9999428877071168268324462680980110604599, - 0.999938311767283189655618359697592754013, - 0.999934052598878483932035240348113191731, - 0.9999300523114688962155368933174163936848, - 0.9999262687553819399632780281900349826094, - 0.9926447551971221136721993073029112268763, - 0.9896086425917686478635208903220735023288, - 0.9872831094708759013315476674998231771112, - 0.9853253899681719161468126266199947992874, - 0.9836027178149637071691226667555243369797, - 0.9820470029764667038452666345865058694192, - 0.9806177971936827573257045283891513709368, - 0.97928874641099293421931043027104578327, - 0.9780415451927629881943028498821429186059, - 0.9768628655744219140604871252425961901255, - 0.967382626983074241885253344632666448927, - 0.9601485420712594199373375259293860324633, - 0.9540768694875733222057908617314370634111, - 0.9487478690765183543410579996573536771348, - 0.9439462911219380338176477772712853402016, - 0.9395442782590063946376623684916441100361, - 0.9354585313336439336066341889767099608018, - 0.9316311953818583253420613278986500351794, - 0.9280201500545670487600430252549212247489, - 0.8991857663963733198571950343133631348347, - 0.8774287170665477623395641312875506084256, - 0.8593275036837387237312746018678000939451, - 0.8435580020488052057849697812109882706542, - 0.8294416857114015557682843481727604063558, - 0.8165758053803078481644781849709953302847, - 0.8046981564792468915744561969751509934994, - 0.7936267540949175059651534957734689407879, - 0.7832291989812967764330746819464532478021); { Upper branch, X close to 0 } const X2 : array[1..20] of Float = (1.E-9, 2.E-9, 3.E-9, 4.E-9, 5.E-9, 6.E-9, 7.E-9, 8.E-9, 9.E-9, 1.E-8, 1.E-2, 2.E-2, 3.E-2, 4.E-2, 5.E-2, 6.E-2, 7.E-2, 8.E-2, 9.E-2, 1.E-1); const WP2 : array[1..40] of Float = (9.999999990000000014999999973333333385417E-10, 1.9999999960000000119999999573333335E-9, 2.999999991000000040499999784000001265625E-9, 3.999999984000000095999999317333338666667E-9, 4.999999975000000187499998333333349609375E-9, 5.999999964000000323999996544000040499999E-9, 6.99999995100000051449999359733342086979E-9, 7.999999936000000767999989077333503999997E-9, 8.999999919000001093499982504000307546869E-9, 9.999999900000001499999973333333854166656E-9, 9.901473843595011885336326816570107953628E-3, 1.961158933740562729168248268298370977812E-2, 2.913845916787001265458568152535395243296E-2, 3.848966594197856933287598180923987047561E-2, 4.767230860012937472638890051416087074706E-2, 5.669304377414432493107872588796066666126E-2, 6.555812274442272075701853672870305774479E-2, 7.427342455278083997072135190143718509109E-2, 8.284448574644162210327285639805993759142E-2, 9.127652716086226429989572142317956865312E-2, - 1.000000001000000001500000002666666671875E-9, - 2.000000004000000012000000042666666833333E-9, - 3.000000009000000040500000216000001265625E-9, - 4.000000016000000096000000682666672E-9, - 5.000000025000000187500001666666682942709E-9, - 6.000000036000000324000003456000040500001E-9, - 7.000000049000000514500006402666754203126E-9, - 8.000000064000000768000010922666837333336E-9, - 9.000000081000001093500017496000307546881E-9, - 1.000000010000000150000002666666718750001E-8, - 1.010152719853875327292018767138623973671E-2, - 2.041244405580766725973605390749548004159E-2, - 3.094279498284817939791038065611524917276E-2, - 4.170340843648447389872733812553976786256E-2, - 5.270598355154634795995650617915721289428E-2, - 6.396318935617251019529498180168867456393E-2, - 7.548877886579220591933915955796681153525E-2, - 8.729772086157992404091975866027313992649E-2, - 9.940635280454481474353567186786621057821E-2, - 1.118325591589629648335694568202658422726E-1); { Other results } const X3 : array[1..10] of Float = (1.E1, 1.E2, 1.E3, 1.E4, 1.E5, 1.E6, 1.E7, 1.E8, 1.E9, 1.E10); const WP3 : array[1..10] of Float = (1.745528002740699383074301264875389911535, 3.385630140290050184888244364529726867492, 5.249602852401596227126056319697306282521, 7.231846038093372706475618500141253883968, 9.284571428622108983205132234759581939317, 11.38335808614005262200015678158500428903, 13.5143440103060912090067238511621580283, 15.66899671545096218719628189389457073619, 17.84172596742146918254060066535711011039, 20.02868541330495078123430607181488729749); { Lower branch, X close to -1/e } const WM1 : array[1..68] of Float = (- 1.000000000000000000023316439815971242034, - 1.000000000000000000032974425414002562937, - 1.000000000000000000040385258412884114431, - 1.000000000000000000046632879631942484068, - 1.000000000000000000052137144421794383842, - 1.000000000000000000057113380167442850121, - 1.000000000000000000061689501212464534966, - 1.000000000000000000065948850828005125875, - 1.000000000000000000069949319447913726103, - 1.000000000000000000073733056744706376448, - 1.000000000000002331643981597126015551422, - 1.000000000000003297442541400259918073073, - 1.000000000000004038525841288416879599233, - 1.000000000000004663287963194255655478615, - 1.00000000000000521371444217944744506897, - 1.000000000000005711338016744295885146596, - 1.000000000000006168950121246466181805002, - 1.000000000000006594885082800527084897688, - 1.000000000000006994931944791388919781579, - 1.000000000000007373305674470655766501228, - 1.000000000233164398177834299194683872234, - 1.000000000329744254176269387087995047343, - 1.00000000040385258418320678088280150237, - 1.000000000466328796391912356113774800963, - 1.000000000521371444308553232716574598644, - 1.00000000057113380178315977436875260197, - 1.000000000616895012251498501679602643872, - 1.000000000659488508425026289634430354159, - 1.000000000699493194642234170768892572882, - 1.000000000737330567628282553087415117543, - 1.000023316621036696460620295453277856456, - 1.000032974787857057404928311684626421503, - 1.000040385802079313048521250390482335902, - 1.00004663360452259016530661221213359488, - 1.0000521380505373899860247162705706318, - 1.000057114467508637629346787348726350223, - 1.000061690769779852545970707346938004879, - 1.000065950300622136103491886720203687457, - 1.00006995095046930174807034225078340539, - 1.000073734868993836022551364404248563489, - 1.007391489031309264813153180819941418531, - 1.010463846806564696239430620915659099361, - 1.012825626038880105597738761474228363542, - 1.014819592594577564927398399257428492725, - 1.016578512742400177512255407989807698099, - 1.018170476517182636083407324035097024753, - 1.019635932177973215702948823070039007361, - 1.021001233780440980009663527189756124983, - 1.022284686760270309618528459224732558767, - 1.023499619082082348038906498637836105447, - 1.033342436522109918536891072083243897233, - 1.040939194524944844012076988438386306843, - 1.047373634492196231421755878017895964061, - 1.053065496629607111615572634090884988897, - 1.058230030703619902820337106917657189605, - 1.06299509412938704964298950857825124135, - 1.067443986111355120560366087010834293872, - 1.071634561663924136735470389832541413862, - 1.07560894118662498941494486924522316597, - 1.108081880631165502564629660944418191031, - 1.133487001006868638317076487349933855181, - 1.155245851821528613609784258821055266176, - 1.174682608817289477552149783867901714817, - 1.192475850408615960644596781702366026321, - 1.209028378276581220769059281765172085749, - 1.224602449817731587352403997390766826335, - 1.239380103200799714836392811991400433357, - 1.253493791367214516100457405907304877145); { Lower branch, X close to 0 } const WM2 : array[1..68] of Float = (- 96.67475603368003636615083422832414231073, - 95.97433737593292677679699834708774152264, - 95.56459382507349364043974513871359837914, - 95.27386489130628866261760496192716897551, - 95.0483515329550645558378163981346085731, - 94.86408948075132603599669916724611501067, - 94.70829516116125928735505687861553800851, - 94.57333777268864473984718625104978190798, - 94.45429521137271454134108055166168787618, - 94.34780665137385269060032461028588648619, - 73.37311031382297679706747875812087452918, - 72.67033891766978907253811160121558649554, - 72.25920015786413889986246462168541066725, - 71.9674726772681844325410195162521230103, - 71.74117979478106456261839111929684980709, - 71.55627755942675731851469544735603279342, - 71.39993966508440988906136771384270319452, - 71.26450969134836299738230265916604879247, - 71.14504894849287026061378869987876478469, - 71.03818524971357411174259539994036186653, - 49.96298427667447244531514297262540669957, - 49.25557728489066973476436802404294348267, - 48.84167348449764278180827692232244878061, - 48.54795966722336777861228992424053274064, - 48.32011181512544381639923088992262632623, - 48.13392971864323755677656581326964166718, - 47.97650308277095858785998266172487372203, - 47.84012504158555569017852884133421231303, - 47.71982419568730714141619502661365943996, - 47.61220592218922310708330388890925734186, - 26.29523881924692569411012882185491823773, - 25.57429135222126159950976461862116397347, - 25.15218334705420805339928870686463192335, - 24.85251554543232259250342343156454440592, - 24.61997095867949438248843689371454503831, - 24.42989922074834124324823589226341161866, - 24.26914663885402405126372567664280388966, - 24.12985944288624210229238972590881794092, - 24.00697058168597098928369714836882130512, - 23.8970195845316574350263109196222825525, - 14.16360081581018300910955630361089957762, - 13.41624453595298662833544556875899262976, - 12.97753279184081358418630625949303360266, - 12.66551396826200331850774017793451747947, - 12.42304039760186078066171146072124458063, - 12.22461776385387453853455424320739669321, - 12.05663003490708840623665404674007291018, - 11.91094134143842011964821167497982287763, - 11.78229922740701885487699061601349928173, - 11.66711453256635441837882744697047370583, - 10.90655739570090676132157335673785028979, - 10.45921112040100393534625826514848865968, - 10.14059243262036578763968437893562720385, - 9.892699522704254067620287857665824159861, - 9.689637966382397752838283301312347921626, - 9.517569762038614935107630230444563521109, - 9.368222172408836799233763466046500781388, - 9.236251966692597369166416348621131600216, - 9.11800647040274012125833718204681427427, - 8.335081377982507150789361715143483020265, - 7.872521380098708883395239767904984410792, - 7.541940416432904084217222998374802941589, - 7.283997135099081646930521042317118095276, - 7.072162048994701667487346245044653243434, - 6.892241486671583156187212318718730022068, - 6.735741661607793269808533725369490789074, - 6.597171733627119347342347717832724288261, - 6.472775124394004694741057892724488037104); var I, NDT : Integer; W : Float; function NDigits(W_appr : Float; W_exact : Float) : Integer; { Returns the number of correct digits found in W_appr } begin if W_appr = W_exact then NDigits := NDT else NDigits := Round(Log10(Abs(W_exact / (W_appr - W_exact))) + 0.5); end; procedure PrintTitle(Msg : String; Offset : Boolean); { Prints the title for a group of results } var I : Integer; S : String; begin WriteLn; WriteLn(Msg); for I := 1 to Length(Msg) do Write('-'); WriteLn; WriteLn; if Offset then S := ' Offset X' else S := ' X '; WriteLn(S, ' W(X) (appr) W(X) (exact) Digits correct'); end; procedure PrintResult(X, W_appr : Float; W_exact : Float); { Prints one line of results } begin WriteLn(X:17, ' ', W_appr:17, ' ', W_exact:17, ' ', NDigits(W_appr, W_exact):9); end; begin NDT := Round(0.5 - Log10(MachEp)); WriteLn('Lambert''s W-function'); PrintTitle('Upper branch results for X near -1/e', True); for I := 1 to 68 do begin { Check whether underflow occurs } if DX1[I] = 0.0 then W := LambertW(- Exp(- 1.0), True, False) else W := LambertW(DX1[I], True, True); PrintResult(DX1[I], W, WP1[I]); end; PrintTitle('Upper branch results for X near 0', False); for I := 1 to 20 do begin W := LambertW(X2[I], True, False); PrintResult(X2[I], W, WP2[I]); end; for I := 1 to 20 do begin W := LambertW(- X2[I], True, False); PrintResult(- X2[I], W, WP2[20 + I]); end; PrintTitle('Other upper branch results', False); for I := 1 to 10 do begin W := LambertW(X3[I], True, False); PrintResult(X3[I], W, WP3[I]); end; PrintTitle('Lower branch results for X near -1/e', True); for I := 1 to 68 do begin W := LambertW(DX1[I], False, True); PrintResult(DX1[I], W, WM1[I]); end; PrintTitle('Lower branch results for X near 0', False); for I := 1 to 68 do { Check for underflow } if DX1[I] >= 0.0 then begin W := LambertW(- DX1[I], False, False); PrintResult(- DX1[I], W, WM2[I]); end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/fmath/plot.pas�����������������������������������������0000755�0001750�0001750�00000002565�11326425444�021205� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program plots a function in either linear or logarithmic coordinates. ****************************************************************** } program plot; uses tpmath, tpgraph; function Func(X : Float) : Float; { Square root function (becomes linear in log-log coordinates) } begin Func := Sqrt(X) end; begin { Plot in linear coordinates, using default parameter values } if not InitGraphics(9, 2, { 640x480 16 color } 'c:\tp\bgi') then Exit; SetWindow(15, 85, 15, 85, True); PlotOxAxis; PlotOyAxis; PlotGrid(BothGrid); SetGraphTitle('SQUARE ROOT FUNCTION IN LINEAR COORDINATES'); WriteGraphTitle; SetClipping(True); PlotFunc({$IFDEF FPC}@{$ENDIF}Func, 0.0, 1.0, 1); ReadLn; LeaveGraphics; { Plot in logarithmic coordinates } if not InitGraphics(9, 2, { 640x480 16 color } 'c:\tp\bgi') then Exit; SetWindow(15, 85, 15, 85, True); SetOxScale(LogScale, 0.01, 100, 1); SetOyScale(LogScale, 0.1, 10, 1); PlotOxAxis; PlotOyAxis; PlotGrid(BothGrid); SetGraphTitle('SQUARE ROOT FUNCTION IN LOGARITHMIC COORDINATES'); WriteGraphTitle; SetClipping(True); PlotFunc({$IFDEF FPC}@{$ENDIF}Func, 0.01, 100, 2); ReadLn; LeaveGraphics; end. �������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/fmath/contour.pas��������������������������������������0000755�0001750�0001750�00000005521�11326425444�021713� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Contour plot of a two-dimensional function ****************************************************************** } program contour; uses tpmath, tpgraph; { ****************************************************************** Define here the function to be plotted ****************************************************************** } const FuncName = 'Sin(Sqrt(X^2 + Y^2)) + 0.5 / Sqrt((X + 3.05)^2 + Y^2)'; const Xmin = - TwoPi; Xmax = TwoPi; Xstep = Pi; { Ox scale } Ymin = - TwoPi; Ymax = TwoPi; Ystep = Pi; { Oy scale } const NpX = 60; NpY = 60; { Number of grid points } const Nc = 30; { Number of contours } function Func(X, Y : Float) : Float; const C = 3.05; var X2, Y2, Xc, Xc2 : Float; begin X2 := X * X; Y2 := Y * Y; Xc := X + C; Xc2 := Xc * Xc; Func := Sin(Sqrt(X2 + Y2)) + 0.5 / Sqrt(Xc2 + Y2) end; { ****************************************************************** Main program ****************************************************************** } var Dx, Dy : Float; { Increments of X and Y } Fmin, Fmax : Float; { Min. and max. function values } H : Float; { Increment for levels } X, Y : PVector; { Point coordinates } Z : PVector; { Contour array } F : PMatrix; { Function values } I, J : Integer; { Loop variables } begin { Initialize graphics } if not InitGraphics(9, 2, { 640x480 16 color } 'c:\tp\bgi') then Exit; { Set graphic area so that it will look approximately square } SetWindow(24, 76, 15, 85, True); { Dimension arrays } DimVector(X, NpX); DimVector(Y, NpY); DimVector(Z, Nc - 1); DimMatrix(F, NpX, NpY); { Set scales and plot axes } SetOxScale(LinScale, Xmin, Xmax, Xstep); SetOyScale(LinScale, Ymin, Ymax, Ystep); PlotOxAxis; PlotOyAxis; PlotGrid(BothGrid); SetGraphTitle(FuncName); WriteGraphTitle; { Generate grid points } Dx := (Xmax - Xmin) / NpX; Dy := (Ymax - Ymin) / NpY; X^[0] := Xmin; for I := 1 to NpX do X^[I] := X^[I - 1] + Dx; Y^[0] := Ymin; for J := 1 to NpY do Y^[J] := Y^[J - 1] + Dy; { Compute function values } Fmin := Func(Xmin, Ymin); Fmax := Fmin; for I := 0 to NpX do for J := 0 to NpY do begin F^[I]^[J] := Func(X^[I], Y^[J]); if F^[I]^[J] < Fmin then Fmin := F^[I]^[J] else if F^[I]^[J] > Fmax then Fmax := F^[I]^[J]; end; { Define levels } H := (Fmax - Fmin) / (Nc + 1); for I := 0 to Nc - 1 do Z^[I] := Fmin + (I + 1) * H; { Plot contour } ConRec(NpX, NpY, Nc, X, Y, Z, F); ReadLn; LeaveGraphics; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/fmath/speed.pas����������������������������������������0000755�0001750�0001750�00000007503�11326425444�021324� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program measures the execution times of several standard mathematical functions, as well as some additional functions provided in TPMATH The results are stored in the output file SPEED.OUT The execution time of each function takes into account the computation of random arguments. This corresponds to the execution time of the function Random ****************************************************************** } program Speed; uses dos, tpmath; const NFUNC = 29; { Number of functions } NMAX = 10000000; { Number of evaluations for each function } const FuncName : array[1..NFUNC] of String[8] = ('Ln ', 'Log10 ', 'Log2 ', 'Exp ', 'Exp10 ', 'Exp2 ', 'Power ', 'Sin ', 'Cos ', 'Tan ', 'ArcSin ', 'ArcCos ', 'ArcTan ', 'ArcTan2 ', 'Sinh ', 'Cosh ', 'Tanh ', 'ArcSinh ', 'ArcCosh ', 'ArcTanh ', 'Gamma ', 'DiGamma ', 'TriGamma', 'IGamma ', 'Beta ', 'IBeta ', 'Erf ', 'Erfc ', 'Random '); var F : Text; { Output file } N : Byte; { Function index } T : Float; { Time } function Time : Float; { Returns time in seconds } var H, M, S, C : Word; begin GetTime(H, M, S, C); Time := 3600.0 * H + 60.0 * M + S + 0.01 * C; end; function TimeToEval(N : Byte) : Float; { Returns time to evaluate NMAX functions } var I : LongInt; T0, Y : Float; begin T0 := Time; case N of 1 : for I := 1 to NMAX do Y := Ln(Random); 2 : for I := 1 to NMAX do Y := Log10(Random); 3 : for I := 1 to NMAX do Y := Log2(Random); 4 : for I := 1 to NMAX do Y := Exp(Random); 5 : for I := 1 to NMAX do Y := Exp10(Random); 6 : for I := 1 to NMAX do Y := Exp2(Random); 7 : for I := 1 to NMAX do Y := Power(Random, 0.5); 8 : for I := 1 to NMAX do Y := Sin(Random); 9 : for I := 1 to NMAX do Y := Cos(Random); 10 : for I := 1 to NMAX do Y := Tan(Random); 11 : for I := 1 to NMAX do Y := ArcSin(Random); 12 : for I := 1 to NMAX do Y := ArcCos(Random); 13 : for I := 1 to NMAX do Y := ArcTan(Random); 14 : for I := 1 to NMAX do Y := ArcTan2(Random, 0.5); 15 : for I := 1 to NMAX do Y := Sinh(Random); 16 : for I := 1 to NMAX do Y := Cosh(Random); 17 : for I := 1 to NMAX do Y := Tanh(Random); 18 : for I := 1 to NMAX do Y := ArcSinh(Random); 19 : for I := 1 to NMAX do Y := ArcCosh(Random + 1.0); 20 : for I := 1 to NMAX do Y := ArcTanh(Random); 21 : for I := 1 to NMAX do Y := Gamma(Random); 22 : for I := 1 to NMAX do Y := DiGamma(Random); 23 : for I := 1 to NMAX do Y := TriGamma(Random); 24 : for I := 1 to NMAX do Y := IGamma(Random, 0.5); 25 : for I := 1 to NMAX do Y := Beta(Random, 0.5); 26 : for I := 1 to NMAX do Y := IBeta(Random, 0.5, 0.5); 27 : for I := 1 to NMAX do Y := Erf(Random); 28 : for I := 1 to NMAX do Y := Erfc(Random); 29 : for I := 1 to NMAX do Y := Random; end; TimeToEval := Time - T0; end; begin { Open output file } Assign(F, 'speed.out'); Rewrite(F); Writeln; Writeln('Time in seconds to evaluate ', NMAX, ' functions'); Writeln(F, 'Time in seconds to evaluate ', NMAX, ' functions'); Writeln; Writeln(F); for N := 1 to NFUNC do begin T := TimeToEval(N); Writeln(FuncName[N], T:6:2); Writeln(F, FuncName[N], T:8:2); end; Close(F); end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/fmath/testmach.pas�������������������������������������0000755�0001750�0001750�00000003125�11326425444�022030� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program displays the floating point type and the machine- dependent constants. ****************************************************************** } program testmach; uses tpmath; var N : Byte; begin writeln; writeln('Integer type = Integer (', sizeof(Integer), ' bytes)'); writeln('Long Integer type = LongInt (', sizeof(LongInt), ' bytes)'); N := sizeof(Float); write('Floating point type = '); if N = sizeof(Single) then write('Single') else if N = sizeof(Double) then write('Double') else if N = sizeof(Extended) then write('Extended') else write('Real'); writeln(' (', N, ' bytes)'); writeln('Complex type = Complex (', sizeof(Complex), ' bytes)'); writeln; writeln('MachEp = ', MachEp); writeln; writeln('MinNum = ', MinNum); writeln('Exp(MinLog) = ', Exp(MinLog)); writeln; writeln('MinLog = ', MinLog); writeln('Ln(MinNum) = ', Ln(MinNum)); writeln; writeln('MaxNum = ', MaxNum); writeln('Exp(MaxLog) = ', Exp(MaxLog)); writeln; writeln('MaxLog = ', MaxLog); writeln('Ln(MaxNum) = ', Ln(MaxNum)); writeln; writeln('MaxFac = ', MaxFac); writeln('Fact(MaxFac) = ', Fact(MaxFac)); writeln; writeln('MaxGam = ', MaxGam); writeln('Gamma(MaxGam) = ', Gamma(MaxGam)); writeln; writeln('MaxLgm = ', MaxLgm); writeln('LnGamma(MaxLgm) = ', LnGamma(MaxLgm)); end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/fmath/specfunc.pas�������������������������������������0000755�0001750�0001750�00000015521�11326425444�022031� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This programs tests the accuracy of the special functions. The data file SPECFUNC.DAT has been modified from the 'Numerical Recipes' example file. ****************************************************************** } program specfunc; uses crt, tpmath; const FileName = 'specfunc.dat'; Blank = ' '; procedure Pause; var Ch : Char; begin Writeln; Write('Press a key to continue'); Ch := ReadKey; Writeln; Writeln; end; procedure Test_Fact; var I, M, N : Integer; Y, Ref, R : Float; F : Text; S : String; begin Assign(F, FileName); Reset(F); repeat ReadLn(F, S); until S = 'N-factorial'; ReadLn(F, M); WriteLn(' X Fact(N) Reference Rel.Error'); WriteLn('------------------------------------------------------------------------------'); for I := 1 to M do begin ReadLn(F, N, Ref); Y := Fact(N); R := (Y - Ref) / Ref; WriteLn(N:4, Blank, Y:26, Blank, Ref:26, Blank, R:10); end; Close(F); Pause; end; procedure Test_Binomial; var I, M, N, K : Integer; Y, Ref, R : Float; F : Text; S : String; begin Assign(F, FileName); Reset(F); repeat ReadLn(F, S); until S = 'Binomial Coefficients'; ReadLn(F, M); WriteLn(' N K Binomial(N, K) Reference Rel.Error'); WriteLn('---------------------------------------------------------------'); for I := 1 to M do begin ReadLn(F, N, K, Ref); Y := Binomial(N, K); R := (Y - Ref) / Ref; WriteLn(N:2, K:5, ' ', Y:13:0, ' ', Ref:13:0, ' ', R:10); end; Close(F); Pause; end; procedure Test_Gamma; var I, M : Integer; X, Y, Ref, R : Float; F : Text; S : String; begin Assign(F, FileName); Reset(F); repeat ReadLn(F, S); until S = 'Gamma Function'; ReadLn(F, M); WriteLn(' X Gamma(X) Reference Rel.Error'); WriteLn('------------------------------------------------------------------------------'); for I := 1 to M do begin ReadLn(F, X, Ref); Y := Gamma(X); { To test Gamma } { Y := SgnGamma(X) * Exp(LnGamma(X)); } { To test LnGamma } R := (Y - Ref) / Ref; WriteLn(X:4:1, Blank, Y:26, Blank, Ref:26, Blank, R:10); end; Close(F); Pause; end; procedure Test_IGamma; var I, M : Integer; A, X, Y, R, Ref : Float; F : Text; S : String; begin Assign(F, FileName); Reset(F); repeat ReadLn(F, S); until S = 'Incomplete Gamma Function'; ReadLn(F, M); WriteLn(' A X IGamma(A, X) Reference Rel.Error'); WriteLn('-------------------------------------------------------------------------------'); for I := 1 to M do begin ReadLn(F, A, X, Ref); Y := IGamma(A, X); R := (Y - Ref) / Ref; WriteLn(A:4:1, X:12:8, Y:26, Ref:26, ' ', R:10); end; Close(F); Pause; end; procedure Test_Beta; var I, M : Integer; X, Y, Z, R, Ref : Float; F : Text; S : String; begin Assign(F, FileName); Reset(F); repeat ReadLn(F, S); until S = 'Beta Function'; ReadLn(F, M); WriteLn(' X Y Beta(X, Y) Reference Rel.Error'); WriteLn('-------------------------------------------------------------------------------'); for I := 1 to M do begin ReadLn(F, X, Y, Ref); Z := Beta(X, Y); R := (Z - Ref) / Ref; WriteLn(X:4:1, ' ', Y:4:1, ' ', Z:26, ' ', Ref:26, ' ', R:10); end; Close(F); Pause; end; procedure Test_IBeta; var I, M : Integer; A, B, X, Y, R, Ref : Float; F : Text; S : String; begin Assign(F, FileName); Reset(F); repeat ReadLn(F, S); until S = 'Incomplete Beta Function'; ReadLn(F, M); WriteLn(' A B X IBeta(A, B, X) Reference Rel.Error'); WriteLn('-------------------------------------------------------------------------------'); for I := 1 to M do begin ReadLn(F, A, B, X, Ref); Y := IBeta(A, B, X); R := (Y - Ref) / Ref; WriteLn(A:4:1, ' ', B:4:1, ' ', X:4:2, ' ', Y:26, ' ', Ref:26, ' ', R:10); end; Close(F); Pause; end; procedure Test_Erf; var I, M : Integer; X, Y, R, Ref : Float; F : Text; S : String; begin Assign(F, FileName); Reset(F); repeat ReadLn(F, S); until S = 'Error Function'; ReadLn(F, M); WriteLn(' X Erf(X) Reference Rel.Error'); WriteLn('------------------------------------------------------------------------------'); for I := 1 to M do begin ReadLn(F, X, Ref); Y := Erf(X); R := (Y - Ref) / Ref; WriteLn(X:4:1, Blank, Y:26, Blank, Ref:26, Blank, R:10); end; Close(F); Pause; end; procedure Test_DiGamma; var I, M : Integer; X, Y, Ref, R : Float; F : Text; S : String; begin Assign(F, FileName); Reset(F); repeat ReadLn(F, S); until S = 'DiGamma Function'; ReadLn(F, M); WriteLn(' X DiGamma(X) Reference Rel.Error'); WriteLn('------------------------------------------------------------------------------'); for I := 1 to M do begin ReadLn(F, X, Ref); Y := DiGamma(X); R := (Y - Ref) / Ref; WriteLn(X:6:2, Blank, Y:25, Blank, Ref:25, Blank, R:10); end; Close(F); Pause; end; procedure Test_TriGamma; var I, M : Integer; X, Y, Ref, R : Float; F : Text; S : String; begin Assign(F, FileName); Reset(F); repeat ReadLn(F, S); until S = 'TriGamma Function'; ReadLn(F, M); WriteLn(' X TriGamma(X) Reference Rel.Error'); WriteLn('------------------------------------------------------------------------------'); for I := 1 to M do begin ReadLn(F, X, Ref); Y := TriGamma(X); R := (Y - Ref) / Ref; WriteLn(X:6:2, Blank, Y:25, Blank, Ref:25, Blank, R:10); end; Close(F); Pause; end; begin Test_Fact; Test_Binomial; Test_Gamma; Test_IGamma; Test_Beta; Test_IBeta; Test_Erf; Test_DiGamma; Test_TriGamma; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/fourier/�����������������������������������������������0000755�0001750�0001750�00000000000�12360760644�020066� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/fourier/testfft.pas������������������������������������0000755�0001750�0001750�00000015703�11326425444�022260� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Fast Fourier Transform (modified from Pascal program by Don Cross) ****************************************************************** The program generates a time signal consisting of a large 200 Hz sine wave added to a small 2000 Hz cosine wave, which is graphed on the screen (Press a key after you are done viewing each graph) Next, it performs the FFT and graphs the resulting complex frequency samples. Then, it filters out all frequency components above 1000 Hz in the transformed data. Finally, it performs the inverse transform to get a filtered time signal back, and graphs the result. In addition, the program compares the FFT with the direct computation, on a set of random data. Results are stored in the output file fftout.txt ****************************************************************** } program testfft; uses tpmath, tpgraph; const PathToBGI = 'c:\tp\bgi'; { Change as necessary } function F(T : Float) : Float; begin F := Sin(200 * 2 * PI * T) + 0.2 * Cos(2000 * 2 * PI * T); end; const NumSamples = 512; { Buffer size (power of 2) } SamplingRate = 22050; { Sampling rate (Hz) } MaxIndex = NumSamples - 1; { Max. array index } MidIndex = NumSamples div 2; DT = 1 / SamplingRate; { Time unit (s) } DF = SamplingRate / NumSamples; { Frequency unit (Hz) } var InArray, OutArray : PCompVector; T, Freq : PVector; OutputListingFile : Text; I, FreqIndex, SymIndex : LongInt; procedure Test_CalcFrequency; var Z : Complex; I : Integer; begin { Fill input buffers with random data } for I := 0 to MaxIndex do begin InArray^[I].X := Random(10000); InArray^[I].Y := Random(10000); end; WriteLn(OutputListingFile); WriteLn(OutputListingFile, '*** Testing procedure CalcFrequency ***'); WriteLn(OutputListingFile); FFT(NumSamples, InArray, OutArray); for I := 0 to MaxIndex do begin CalcFrequency(NumSamples, I, InArray, Z); WriteLn(OutputListingFile, I:4, OutArray^[I].X:15:6, Z.X:15:6, OutArray^[I].Y:20:6, Z.Y:15:6); end; end; procedure ListData(DataArray : PCompVector; Comment : String); var I : LongInt; begin WriteLn(OutputListingFile, '*** ', Comment, ' ***'); WriteLn(OutputListingFile); WriteLn(OutputListingFile, 'index':20, 'real':20, 'imag':20); for I := 1 to NumSamples do begin WriteLn(OutputListingFile, I:20, DataArray^[I].X:20:5, DataArray^[I].Y:20:5); end; WriteLn(OutputListingFile); WriteLn(OutputListingFile, '------------------------------------------------------------------------'); WriteLn(OutputListingFile); end; procedure PlotData(T : PVector; Z : PCompVector; Title : String); var X : PVector; { Real part of Z } Xmin, Xmax, Xstep : Float; { Ox scale } Ymin, Ymax, Ystep : Float; { Oy scale } I : Integer; { Loop variable } begin if not InitGraphics(9, 2, PathToBGI) then begin Writeln('Unable to set graphic mode!'); Exit; end; SetWindow(15, 85, 15, 85, True); DimVector(X, MaxIndex); for I := 0 to MaxIndex do X^[I] := Z^[I].X; AutoScale(T, 0, MaxIndex, LinScale, Xmin, Xmax, Xstep); AutoScale(X, 0, MaxIndex, LinScale, Ymin, Ymax, Ystep); SetOxScale(LinScale, Xmin, Xmax, Xstep); SetOyScale(LinScale, Ymin, Ymax, Ystep); SetOxTitle('Time (s)'); SetOyTitle('Amplitude'); SetGraphTitle(Title); { Set point type to 0 so that only lines will be plotted } SetPointParam(1, 0, 1, 1); PlotOxAxis; PlotOyAxis; PlotGrid(BothGrid); WriteGraphTitle; PlotCurve(T, X, 0, MaxIndex, 1); ReadLn; LeaveGraphics; end; procedure PlotFFT(Freq : PVector; Z : PCompVector; Title : String); var Fq : PVector; { Frequency } X : PVector; { Real part of FFT } Y : PVector; { Imag. part of FFT } Xmin, Xmax, Xstep : Float; { Ox scale } Yr_min, Yr_max, Yr_step : Float; { Oy scale (real part) } Yi_min, Yi_max, Yi_step : Float; { Oy scale (imag. part) } Ymin, Ymax, Ystep : Float; { Oy scale (global) } I : Integer; { Loop variable } begin DimVector(Fq, MidIndex); { Frequency } DimVector(X, MidIndex); { Real part of FFT } DimVector(Y, MidIndex); { Imag. part of FFT } if not InitGraphics(9, 2, PathToBGI) then begin Writeln('Unable to set graphic mode!'); Exit; end; SetWindow(15, 80, 15, 85, True); for I := 0 TO MidIndex do begin Fq^[I] := Freq^[I]; X^[I] := Z^[I].X; Y^[I] := Z^[I].Y; end; AutoScale(Fq, 0, MidIndex, LinScale, Xmin, Xmax, Xstep); AutoScale(X, 0, MidIndex, LinScale, Yr_min, Yr_max, Yr_step); AutoScale(Y, 0, MidIndex, LinScale, Yi_min, Yi_max, Yi_step); Ymin := FMin(Yr_min, Yi_min); Ymax := FMax(Yr_max, Yi_max); Ystep := FMin(Yr_step, Yi_step); SetOxScale(LinScale, Xmin, Xmax, Xstep); SetOyScale(LinScale, Ymin, Ymax, Ystep); SetOxTitle('Frequency (Hz)'); SetOyTitle('FFT'); SetPointParam(1, 0, 1, 1); { Set point type to 0 so that } SetPointParam(2, 0, 1, 1); { only lines will be plotted. } SetCurvLegend(1, 'Real'); SetCurvLegend(2, 'Imag.'); PlotOxAxis; PlotOyAxis; PlotGrid(BothGrid); WriteLegend(2, False, True); PlotCurve(Fq, X, 0, MidIndex, 1); PlotCurve(Fq, Y, 0, MidIndex, 2); ReadLn; LeaveGraphics; end; begin DimCompVector(InArray, MaxIndex); DimCompVector(OutArray, MaxIndex); DimVector(T, MaxIndex); DimVector(Freq, MaxIndex); Assign(OutputListingFile, 'fftout.txt'); Rewrite(OutputListingFile); for I := 0 to MaxIndex do begin T^[I] := I * DT; Freq^[I] := I * DF; InArray^[I].X := F(T^[I]); InArray^[I].Y := 0.0; end; ListData(InArray, 'Time domain data before transform'); PlotData(T, InArray, 'Original signal'); FFT(NumSamples, InArray, OutArray); PlotFFT(Freq, OutArray, 'Fourier Transform'); ListData(OutArray, 'Frequency domain data after transform'); { Filter out everything above 1000 Hz (low-pass) } FreqIndex := Trunc(1000.0 / DF); SymIndex := NumSamples - FreqIndex; for I := 0 to MaxIndex do begin if ((I > FreqIndex) and (I < MidIndex)) or ((I >= MidIndex) and (I < SymIndex)) then begin OutArray^[I].X := 0.0; OutArray^[I].Y := 0.0; end; end; IFFT(NumSamples, OutArray, InArray); ListData(InArray, 'Time domain data after inverse transform'); PlotData(T, InArray, 'Filtered signal'); Test_CalcFrequency; Close(OutputListingFile); end. �������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/random/������������������������������������������������0000755�0001750�0001750�00000000000�12360760644�017673� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/random/ranmull.pas�������������������������������������0000755�0001750�0001750�00000006740�11326425444�022061� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program simulates a multi-lognormal distribution. The mean vector and variance-covariance matrix are stored in a data file with the following structure: Line 1 : Name of distribution. Line 2 : Size of distribution (N), e.g. 2 for bi-lognormal Line 3 to (N + 2) : Means and standard deviations. Next lines : Correlation coefficients, in lower triangular matrix form. The file RANMULL.DAT is an example data file. The results are stored in an output file (one random vector by line) ****************************************************************** } program ranmull; uses tpmath; const NSIM = 400; { Number of simulations } var Name : String; { Name of distribution } N : Integer; { Dimension of distribution } M : PVector; { Mean vector of original lognormal distribution } V : PMatrix; { Variance-covariance matrix of original lognormal dist. } M0 : PVector; { Mean vector of auxiliary normal dist. } V0 : PMatrix; { Variance-covariance matrix of auxiliary normal dist. } L : PMatrix; { Cholesky factor of V0 } Z : PVector; { Random vector from the auxiliary normal dist. } X : PVector; { Random vector from the original lognormal dist. } F : Text; { Output file } I, J : Integer; { Loop variables } procedure ReadParam(FileName : String; var Name : String; var N : Integer; var M : PVector; var V : PMatrix); var F : Text; { Data file } I, J : Integer; { Loop variables } S : PVector; { Standard deviations } R : Float; { Correlation coefficient } begin Assign(F, FileName); Reset(F); Readln(F, Name); Readln(F, N); DimVector(M, N); DimVector(S, N); DimMatrix(V, N, N); { Read means and standard deviations. Compute variances } for I := 1 to N do begin Read(F, M^[I], S^[I]); V^[I]^[I] := Sqr(S^[I]); end; { Read correlation coefficients and compute covariances } for I := 2 to N do for J := 1 to Pred(I) do begin Read(F, R); V^[I]^[J] := R * S^[I] * S^[J]; V^[J]^[I] := V^[I]^[J]; end; Close(F); DelVector(S, N); end; begin { Read parameters of log-normal distribution LN(M, V) } ReadParam('ranmull.dat', Name, N, M, V); DimVector(X, N); DimVector(Z, N); DimVector(M0, N); DimMatrix(V0, N, N); DimMatrix(L, N, N); { Define auxiliary normal distribution N(M0, V0) } for I := 1 to N do begin for J := 1 to N do V0^[I]^[J] := Ln(V^[I]^[J] / (M^[I] * M^[J]) + 1.0); M0^[I] := Ln(M^[I]) - 0.5 * V0^[I]^[I]; end; { Perform Cholesky decomposition of variance-covariance matrix } Cholesky(V0, L, 1, N); if MathErr = MatNotPD then begin WriteLn('Variance-covariance matrix is not positive definite.'); Exit; end; SetRNG(RNG_MT); Assign(F, 'ranmull.out'); Rewrite(F); for I := 1 to NSIM do begin { Pick random vector from auxiliary normal distribution } RanMult(M0, L, 1, N, Z); { Convert to lognormal } for J := 1 to N do X^[J] := Exp(Z^[J]); { Output result to file } for J := 1 to N do Write(F, X^[J]:12:6); Writeln(F); end; Close(F); end. ��������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/random/testuvag.pas������������������������������������0000755�0001750�0001750�00000001167�11326425444�022247� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Test of UVAG random number generator By Alex Hay (zenjew@hotmail.com) - Adapted to TPMath by Jean Debord This program prints 1000 random integers, computed with the default initialization. The results should be identical to file uvag.txt ****************************************************************** } program testuvag; uses tpmath; var I : Word; R : LongInt; begin SetRNG(RNG_UVAG); for I := 1 to 1000 do begin R := IRanGen; Write(R:15); if I mod 5 = 0 then Writeln; end; end.���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/random/randfile.pas������������������������������������0000755�0001750�0001750�00000001507�11326425444�022167� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program generates a binary file of random numbers, to be used with Marsaglia's DIEHARD battery of tests (http://stat.fsu.edu/pub/diehard/) ****************************************************************** } program randfile; uses tpmath; const N = 3000000; { Generate N numbers } var I, R : LongInt; F : file of LongInt; begin { Select a generator } SetRNG(RNG_MWC); { or SetRNG(RNG_MT) or SetRNG(RNG_UVAG) } { Initialize the selected generator with the built-in generator } Randomize; InitGen(Trunc(Random * 2147483647)); { Create file } Assign(F, 'random.dat'); Rewrite(F); for I := 1 to N do begin R := IRanGen; Write(F, R); end; Close(F); end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/random/ranmul.pas��������������������������������������0000755�0001750�0001750�00000005275�11326425444�021707� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program simulates a multinormal distribution. The mean vector and the variance-covariance matrix are stored in a data file with the following structure: Line 1 : Name of distribution. Line 2 : Size of distribution (N), e.g. 2 for binormal Line 3 to (N + 2) : Means and standard deviations. Next lines : Correlation coefficients, in lower triangular matrix form. The file RANMUL.DAT is an example data file. The results are stored in an output file (one random vector by line) ****************************************************************** } program ranmul; uses tpmath; const NSIM = 100; { Number of simulations } var Name : String; { Name of distribution } N : Integer; { Size of distribution } M : PVector; { Mean vector } V : PMatrix; { Variance-covariance matrix } L : PMatrix; { Cholesky factor of V } X : PVector; { Random vector } F : Text; { Output file } I, J : Integer; { Loop variables } procedure ReadParam(FileName : String; var Name : String; var N : Integer; var M : PVector; var V : PMatrix); var F : Text; { Data file } I, J : Integer; { Loop variables } S : PVector; { Standard deviations } R : Float; { Correlation coefficient } begin Assign(F, FileName); Reset(F); Readln(F, Name); Readln(F, N); DimVector(M, N); DimVector(S, N); DimMatrix(V, N, N); { Read means and standard deviations. Compute variances } for I := 1 to N do begin Read(F, M^[I], S^[I]); V^[I]^[I] := Sqr(S^[I]); end; { Read correlation coefficients and compute covariances } for I := 2 to N do for J := 1 to Pred(I) do begin Read(F, R); V^[I]^[J] := R * S^[I] * S^[J]; V^[J]^[I] := V^[I]^[J]; end; Close(F); DelVector(S, N); end; begin ReadParam('ranmul.dat', Name, N, M, V); DimVector(X, N); DimMatrix(L, N, N); { Perform Cholesky decomposition of variance-covariance matrix } Cholesky(V, L, 1, N); if MathErr = MatNotPD then begin WriteLn('Variance-covariance matrix is not positive definite.'); Exit; end; SetRNG(RNG_MT); Assign(F, 'ranmul.out'); Rewrite(F); for I := 1 to NSIM do begin { Pick random vector } RanMult(M, L, 1, N, X); { Output result to file } for J := 1 to N do Write(F, X^[J]:12:6); Writeln(F); end; Close(F); end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/random/testmcmc.pas������������������������������������0000755�0001750�0001750�00000015177�11326425444�022232� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program simulates a multinormal distribution by Markov Chain Monte Carlo (MCMC) using the Hastings-Metropolis algorithm. Although MCMC is best used when there is no direct way to simulate the distribution, it is used here for demonstration purposes since its results can be compared to those of the direct method (program RANMUL.PAS). The pdf P(X) of the multinormal distribution is such that: P(X) = C * Exp(- F(X) / T) where F(X) = (X - M)' * V^(-1) * (X - M) C = 1/sqrt(|V| * (2*Pi)^N) T = 2 M is the mean vector and V the variance-covariance matrix of the distribution. N is the dimension of the distribution. The constant C is not used in the simulation. The mean vector and variance-covariance matrix are stored in a data file with the following structure: Line 1 : Title of study Line 2 : Number of variables (N), e.g. 2 for binormal Line 3 to (N + 2) : Means and standard deviations Next lines : Correlation coefficients, in lower triangular matrix form The file TESTMCMC.DAT is an example data file. The results are stored in the output file TESTMCMC.TXT ****************************************************************** } program testmcmc; uses tpmath; const Temp = 2.0; { Temperature } NCycles = 10; { Number of cycles } MaxSim = 1000; { Max nb of simulations } SavedSim = 1000; { Nb of saved simulations } var Title : String; { Title of study } N : Integer; { Number of variables } M : PVector; { Mean vector of original distribution } V : PMatrix; { Variance-covariance matrix of original distribution } V_inv : PMatrix; { Inverse variance-covariance matrix } Xmat : PMatrix; { Matrix of simulated vectors } Msim : PVector; { Mean of simulated distribution } Vsim : PMatrix; { Variance-covariance matrix of simulated distrib. } X_min : PVector; { Coordinates of the minimum of F(X) = mode of simulated distribution } F_min : Float; { Value of F(X) at minimum } I : Integer; { Loop variable } function ReadParam(FileName : String; var Title : String; var N : Integer; var M : PVector; var V, V_inv : PMatrix) : Integer; var F : Text; { Data file } I, J : Integer; { Loop variables } S : PVector; { Standard deviations } R : Float; { Correlation coefficient } Det : Float; { Determinant of var-cov. matrix } begin Assign(F, FileName); Reset(F); Readln(F, Title); Readln(F, N); DimVector(M, N); DimVector(S, N); DimMatrix(V, N, N); DimMatrix(V_inv, N, N); { Read means and standard deviations. Compute variances } for I := 1 to N do begin Read(F, M^[I], S^[I]); V^[I]^[I] := Sqr(S^[I]); end; { Read correlation coefficients and compute covariances } for I := 2 to N do for J := 1 to Pred(I) do begin Read(F, R); V^[I]^[J] := R * S^[I] * S^[J]; V^[J]^[I] := V^[I]^[J]; end; { Initialize inverse var-cov. matrix } for I := 1 to N do for J := 1 to N do V_inv^[I]^[J] := V^[I]^[J]; { Compute the inverse of the variance-covariance matrix } GaussJordan(V_inv, 1, N, N, Det); ReadParam := MathErr; Close(F); DelVector(S, N); end; function ObjFunc(X : PVector) : Float; { Computes the function F(X) } var Sum1, Sum2 : Float; I, J : Integer; D : PVector; begin DimVector(D, N); for I := 1 to N do D^[I] := X^[I] - M^[I]; Sum1 := 0.0; for I := 1 to N do Sum1 := Sum1 + V_inv^[I]^[I] * Sqr(D^[I]); Sum2 := 0.0; for I := 2 to N do for J := 1 to Pred(I) do Sum2 := Sum2 + V_inv^[I]^[J] * D^[I] * D^[J]; ObjFunc := Sum1 + 2.0 * Sum2; DelVector(D, N); end; procedure WriteResults(Title : String; M : PVector; V : PMatrix; N : Integer); var I, J : Integer; S : PVector; R : Float; begin WriteLn; WriteLn(Title); WriteLn; WriteLn(' Mean S.D.'); WriteLn('--------------------'); DimVector(S, N); for I := 1 to N do begin S^[I] := Sqrt(V^[I]^[I]); Writeln(M^[I]:10:4, S^[I]:10:4); end; WriteLn; WriteLn('Correlation matrix:'); WriteLn; for I := 2 to N do begin for J := 1 to Pred(I) do begin R := V^[I]^[J] / (S^[I] * S^[J]); Write(R:10:4); end; WriteLn; end; DelVector(S, N); end; procedure WriteOutputFile(Title : String; Xmat : PMatrix; N : Integer); var F : Text; I, J : Integer; begin Assign(F, 'testmcmc.txt'); Rewrite(F); WriteLn(F, Title); Write(F, ' Iter'); for I := 1 to N do Write(F, ' X', I); WriteLn(F); for I := 1 to SavedSim do begin Write(F, I:5); for J := 1 to N do Write(F, Xmat^[I]^[J]:10:4); WriteLn(F); end; Close(F); end; begin if ReadParam('testmcmc.dat', Title, N, M, V, V_inv) = MatSing then begin WriteLn('Variance-covariance matrix is singular!'); Exit; end; DimVector(Msim, N); DimVector(X_min, N); DimMatrix(Vsim, N, N); DimMatrix(Xmat, SavedSim, N); { Select random number generator } SetRNG(RNG_MT); { Initialize Metropolis-Hastings parameters } InitMHParams(NCycles, MaxSim, SavedSim); { Initialize the mean vector and the variance-covariance matrix. For the sake of demonstration we start at a distance from the true mean and with enhanced standard deviations. } for I := 1 to N do begin Msim^[I] := 3.0 * M^[I]; Vsim^[I]^[I] := 10.0 * V^[I]^[I]; end; { Perform Metropolis-Hastings simulations } Write('Running. Please wait...'); {$IFDEF FPC} Hastings(@ObjFunc, Temp, Msim, Vsim, 1, N, Xmat, X_min, F_min); {$ELSE} Hastings(ObjFunc, Temp, Msim, Vsim, 1, N, Xmat, X_min, F_min); {$ENDIF} if MathErr = MatOk then begin WriteResults('Original distribution', M, V, N); WriteResults('Simulated distribution', Msim, Vsim, N); WriteOutputFile(Title, Xmat, N); end else WriteLn('Variance-covariance matrix is not positive definite!'); end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/random/uvag.txt����������������������������������������0000755�0001750�0001750�00000030160�11326425444�021376� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� -288735372 620066422 656890996 -31851389 1960508036 142009603 514143789 -2107429 -1800308481 -1699363169 -473591232 -1142621326 154424346 -1287193680 1349464577 239283230 1482739267 -721447336 452726661 1190579380 1061062035 -595641077 -304148196 -415579904 -539666927 1183284213 1846533827 201571164 991854444 -1675521421 -529758722 -1230516873 1704416205 198057673 -1440946268 -735980797 1316647170 -1391191317 -1067744741 -1032529872 -620835366 -983514451 2018396996 -2034650915 -1728612224 -2087518792 1047315075 -1661175699 606270917 599792862 -1155696013 1373801371 1341489397 1213013460 1957654746 1324879829 486952443 129185128 -1441796891 -843247627 -1719945220 1803471696 829708139 222383317 1808509301 -853315928 -285646612 -912041675 -1400134876 825667450 -1184359389 -2096678096 227908829 -1875037756 4880470 -1960619431 -555914813 711233684 -2045466546 1116199672 -1379723962 -150209393 -1656464527 -122298017 -1854592656 398306950 1025572712 -463682770 1884188205 1699211440 287432606 824753486 793190871 -1236043946 877298131 -1209186320 1098626160 -1996769672 733685717 1263724751 345824283 -1371811506 334864953 -301385731 2117607145 1980024672 -1761004932 -1009340651 -795564227 -839464173 -460549772 -1091231482 1411746307 -157364707 207814538 1469977152 1311856649 -551792972 -988393891 -177744120 1970403618 -625101041 -1648045207 -1147942676 -2036954510 -1570931231 -1812700193 1926460581 -691540555 -1819682029 524015611 -2104354266 -1279382817 -966894581 916830708 -730042271 246591917 2027350344 2103431032 239761354 -503941472 -1226362160 -194807956 1206365081 -1171396889 -2030305542 -1912994125 1076603123 -571684124 1683030600 1479829785 292315932 151631996 532630254 565759005 1445481255 -1370876035 -1631616894 -1073060616 1972891037 1026765709 -1766892525 -1276701738 608262742 -532435141 105986270 1489654911 -2008345045 -1761975366 1710148380 791971501 -74351180 -1201637460 -1719340969 653084543 -1704791604 -468487310 264509028 -648601297 833978407 1445768319 -1553948802 364591000 -1146792420 -2053874503 1122008201 800670383 -1171230071 1516221383 656015272 -1687686577 -2118886633 -153582857 -212011848 1143249825 1138401598 -1690770090 -169665677 1660293526 -1941100619 -525686554 -686193863 -1145263617 -858672548 -1116075358 -2112839759 -96149114 -116213079 -976128984 1154075891 -151460575 380997851 -845520140 -548611611 -221798104 -1670114199 705953218 1451024764 1741369042 1121446700 2114494846 -907385263 -725195957 -1501072527 346696914 -272846653 -1458803631 -203591881 -2051099036 1506460382 1220467922 -789423106 -2088642632 163609642 895960252 624873685 -1476472110 -2045031283 414287886 922784909 -1001151947 993443876 -648140640 1863775843 -1430569005 296184476 -1785050085 1001575270 1491387579 -313875606 -317114224 -144416139 -804261194 1721043347 1379987718 2011312066 310231304 -1404618654 878719444 969099703 -6259379 -392535674 -813652784 829700038 47278448 -326560214 1389219422 479017699 -2096240325 -2107510534 -468914511 549726930 -1797228833 -354255985 -1679078112 1015478129 1513252749 648743528 -507776129 -1373421990 1536853107 -2136185919 1073564532 -971787099 -1644464676 1001196039 -1139652458 1977383651 -500707270 1977863040 -1182048097 1050509454 261063644 -646536167 1845375305 -2075760651 -2134830657 559086437 -1920916880 1108217264 -1303344417 1313330933 810264880 1617291142 1588450014 1638208978 -1678035851 20735793 1922392122 766498476 -628336586 -1931571809 1070182646 539295203 -77303240 -1062206291 -815659296 642858463 -1564401841 1693354483 -119038851 505898400 26893749 1229469233 -992077540 73792687 -1629700080 1862688891 1692926058 -496425499 1930363654 1739072114 -2112224176 -2081058605 -1261955521 1265545702 -674273574 423183479 1290018708 174643922 1925848100 650573107 -1896364029 631822359 -505018595 741166988 -1012429724 1372237482 556357222 1919740706 1195929823 1088624422 -780026592 391212263 767591743 -2130908724 409183169 755421029 370129504 -1042177494 47470940 -512419292 -435389645 -239454897 -747764412 -1149290964 1377568767 -402338121 -1283680893 1617681905 1323062083 1045438658 -833979730 -848837187 -236202105 -1083952578 -1032843187 844605233 1740319857 -1467633379 -202767622 297349724 995456928 -483699586 -183814681 -1178193042 1643961390 -1904319395 1925813970 -623170367 1281845654 2090486514 498640814 1528374584 -321189249 1712769522 1220770986 768359781 -1737608102 -1059667296 396152911 384609001 1515904513 -727336111 -239401145 1369007555 1975007171 445177800 398357064 -583597928 777848781 1717936091 -570496436 -70846443 947955548 46347263 991488182 43807586 1525521920 2112423297 1684033995 691940980 75403362 559249853 -1818890395 1937148483 -1698923369 -1628293907 -521130158 -1669694349 2072066787 -689735173 -462217765 -436500564 1448674617 708815457 276974596 128565484 -517541441 1134632930 572564855 563218040 845966542 -1411393523 2068644189 -929380457 1299365428 -618075493 1593687175 -362638885 -2103566098 1205724624 -2112871834 624359981 1662649652 -2124090629 68618021 -140387383 562056607 700832514 -483420660 -1638545074 -184416649 -953831404 -1418830961 1966653283 423685103 -121850745 1289463846 945638183 -176827274 -328112515 -2061502918 -36510912 -406073931 -699003804 508097093 -2013907353 -1120890986 -1152849456 -64499667 -1123377695 -894830483 -1652523801 -1247783846 938173020 -782666036 1956439682 464462946 463926335 1108215496 -1700738890 -2060973749 -1175133378 1612989163 -664249015 -388410720 -1899286742 -451286784 -1246398986 21744235 -1190315140 -1401706999 -193707251 -1680503662 -786879084 2140460492 296982879 1296409748 269426123 -2108789129 -1846477855 1793294379 1984697040 116852423 463959881 -1629418155 -2050836562 317441466 336252298 -662299334 37148973 -1412498465 1006940595 -1592299550 898976211 2073790717 671787146 284696264 -1527011806 -269932338 -1873441998 -400310276 1589231802 -534386007 348198448 -740573593 690202301 2092534986 1478153732 -259964356 -1921932283 1378541637 336429563 446648007 -460986266 -474704507 1068350388 1379007427 1517627109 817030745 -214787708 -241539116 1979044039 714802948 -1924623800 -884139943 181932989 -165166908 -501192599 204023654 1617367879 296229267 -1366015201 834005536 218737559 -1746057008 -667074756 -1229346604 -1297248966 297245887 118256395 1750304735 1142050580 -818318606 -2062777110 -904382335 -914412840 2130115925 1123659329 2098909546 1239591451 -97415983 111215982 -1672125691 1745767432 1206851028 1603053288 -1754148309 476467421 2089714779 -2081313555 -1111278941 -178113523 -1298327028 579123468 -1272559359 -1943341691 -992342863 1433207397 1951611946 4458856 -112553341 -1494041532 1280132921 -1523731343 860413728 -1881316020 656274218 1572926550 -1043416953 -315246948 1379508738 487653694 -1996179289 -1054827185 1977121579 -2120809547 -1864051860 157853526 -423886524 673009031 2071856129 517213242 743998567 -1363590650 1557755491 -412461491 -1287958028 -306707148 -686320291 -1718255644 -1136252181 1170908620 354010745 445994535 1913695283 -2061259919 -342427826 -1224463269 -957823506 196874980 -1713839257 -1405331539 1803021848 724420502 -596818689 1627671298 1311688183 -605517998 -727608897 -56370696 -1345120059 808964889 -742685804 -1945068769 -1020718703 -1248792458 915346937 -768546174 -1654130764 1006418503 -838445526 814930115 1461562745 159529326 1841010426 615615431 -483528979 1444495304 -308900524 -1939040239 508870608 -1185103901 -1914425497 1047937085 1716261027 1489601276 -405758984 1712111738 797820894 -1688459927 221302447 -168451944 -61008423 847205349 2113627624 -294371799 836644534 -879017244 -290318383 -1288399303 -895317506 398687353 421658866 392954924 1432542478 597556241 -1563847741 1138567872 -717532251 1583956231 1704081383 -520554691 -2131789457 -315630686 -1821760216 161487479 -1663882590 -81428261 -1712744840 1996414338 1768016572 -1191594058 -2111928371 1398652166 1761627480 -1086656569 -2106938168 -231248450 -1250023093 -1164689520 946813613 323879141 1827625687 1441839283 -2000678279 2021564504 -1802749610 1558803466 405093965 365824595 -531369512 236499435 -547282729 1059519473 -1408059403 -1534062784 -534947961 1152631423 -1546553973 1564834664 -794739748 -1862204009 -1376307474 1899329506 1805148048 -369475545 -51683124 741054608 -1944037904 -70085625 1429253285 -1265108978 2096049050 938874601 504128047 -1361434271 -878176241 -1983144695 12694607 1085842058 1761023085 1891906455 -700070075 -1494321608 1077887658 -1154291222 -513930985 436710108 -1172936535 616964638 -1845809059 -1580114985 1250822018 1526165025 -233611615 -1063642878 206585756 -1707856509 -1045388699 -1792246825 -161500439 -1162996637 -239120663 815750133 649143338 2016789549 53857292 -71607210 -1246901786 -919847814 261169813 -1128909900 647067783 -1924588499 -297345559 -1808702977 1146307685 -1870242467 -1786068073 -110172858 -121913045 431354937 427779812 -1935661126 842575577 472009169 -1134863367 229275880 -1613540432 1038151936 1222805411 -1466303263 -2027126958 -2093281523 -1032176149 713884405 -2024726944 1304795426 2048767157 546538749 1467109427 563081653 -757380599 -1268261014 1816271768 -814583207 -173646936 -506534256 1811873879 -1715861511 821968907 690960778 1647615630 -1380428702 -1896005516 1000080132 -1231342034 -1676355183 -995332844 1859288459 356775040 -1946007768 -34556198 1804883435 1914771257 -255383375 -677373545 -345092455 1739232610 -1763693808 1912105039 -2077629754 1855925921 -406044369 2083996910 -1688761543 1961888473 -1281633016 -57082173 -1600609424 1041421096 1113495327 1058943810 -127131775 2010447518 319830015 -1817119139 -1622986330 1099837547 1139995390 1310788984 280812824 -540253497 -1735808016 994144858 -1995322262 -1136023221 -304140801 1950219379 1622879261 1743530114 -868377628 1660967106 -931336758 2066444568 -1071548773 -354376061 1130687511 916779115 826389072 533499496 -397031301 -1821872343 -1282265802 -501744021 462371713 1017215681 -293509836 369635180 -505064016 1782325845 -82648393 1476348876 -1776648624 -1463155351 537414725 472446392 -920081454 160329326 -217624425 460567517 -2106903657 893040801 -261574330 -2021691090 1011659446 -2051336950 376946871 980297599 2134799092 471343393 399318000 366024363 -119294618 -522287216 1174578148 1912896242 1258321310 2138688869 2018206354 -55329963 -1642821413 -20651690 -902840145 833589275 1577797242 679072635 -1942177513 320222042 1195288052 1023449756 1604196330 -1855553974 -1949781618 -817719276 -1700406885 889310621 -1471514790 1020532847 -629718887 -1271695514 -1937554670 461788560 2102950303 -416406808 1078631989 1020004754 -562950235 475670268 -753909113 1909254476 -1100846535 -1501356576 1618057522 180360050 -1631962502 -1033699393 -1300167011 -1700565497 1161903681 -704031236 -1389582985 1913949679 1254539014 -1021216717 868637461 838550529 1272905945 538234140 417057615 -1031775561 -482070700 2049949948 -83768074 -877837254 -853095341 768678214 -1451589078 316521498 1520723031 794057489 818766015 461978832 353837892 1305938893 -173485360 2145076917 -619730459 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/random/testnorm.pas������������������������������������0000755�0001750�0001750�00000003270�11326425444�022255� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Test of Gaussian random number generator. This program picks a random sample of size N from a gaussian distribution with known mean and standard deviation (SD), estimates mean and SD from the sample, and computes a 95% confidence interval (CI) for the mean (i.e. an interval which has a probability of 0.95 to include the true mean). ****************************************************************** } program testnorm; uses tpmath; const Mu = 10.0; { Mean of Gaussian distribution } Sigma = 2.0; { Standard deviation of Gaussian distribution } N = 100; { Sample size, must be > 30 } var X : PVector; { Sample values } M, S : Float; { Sample mean & SD } Delta : Float; { Half-width of CI } M1, M2 : Float; { Bounds of CI } I : Integer; { Loop variable } begin { Select generator } SetRNG(RNG_MT); { Dimension array } DimVector(X, N); { Pick sample values } for I := 1 to N do X^[I] := RanGauss(Mu, Sigma); { Estimate mean and SD from sample } M := Mean(X, 1, N); S := StDev(X, 1, N, M); { Compute 95% CI, assuming that the sample mean is normally distributed. This requires N > 30 } Delta := 1.96 * S / Sqrt(N); M1 := M - Delta; M2 := M + Delta; { Output results } WriteLn; WriteLn('Population mean = ', Mu:10:4); WriteLn('Population SD = ', Sigma:10:4); WriteLn; WriteLn('Sample size = ', N:10); WriteLn('Sample mean = ', M:10:4); WriteLn('Sample SD = ', S:10:4); WriteLn; WriteLn('95% CI of mean = [', M1:10:4, ' , ', M2:10:4, ' ]'); end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/random/mt.txt������������������������������������������0000755�0001750�0001750�00000074204�11326425444�021063� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������1000 outputs of IRanGen 1067595299 955945823 477289528 -187748513 -65990820 -950634582 -939387601 227628506 810200273 -1703677129 -1734706621 -1052231088 646746669 1479517882 -49495023 1143372638 -431296802 -1073945326 1773610557 1138697238 1421897700 1269916527 -1435033255 1764463362 -420075249 -329647375 72549643 -1910978366 -1694748603 -1057474916 -1502065820 725331109 605841842 271258942 715137098 -996967760 1322965544 -65388187 1395091102 -559269576 2101727825 -564679552 -1344532966 1661921839 -1399387714 -1924455817 1004092106 -2047870615 2111242379 -1057622033 -212542537 219785033 -1840927407 -585384325 835606218 -1883017413 -1559762266 756421180 -2119757592 1873865952 -1532433059 -133159442 -943867956 181129879 -1025075400 776029799 -2076805317 -1293221500 1866825872 2133627728 34862734 1191934573 -1192655942 -1378449533 1012402762 -2110135979 -37567847 -1395470158 -476872234 -1264210562 1282161629 420003642 -1968545819 -1553511579 1278020671 -550787675 271777016 -1668637278 -1734403305 -1238989596 -61439730 1228397661 -699387974 1077915006 -1899035398 1851927286 -1281283790 1999971931 -1288078334 1049781534 1488758959 -803191066 104418065 -1846699999 -1219353181 -422634696 891912190 -358419537 -2025786333 -1661512212 1047636807 -1690354919 -1585661567 1952216715 207593580 -1445069262 670771757 -2084496188 467711165 263046873 -725299381 1042291111 -431450217 1464270005 -1536645944 -504167480 -1993688572 -1188685866 7974801 -1502505660 555991332 621766759 1322453093 853629228 686962251 1455120532 957753161 1802033300 1021534190 -808919985 1902128914 -593829240 -118542633 1795608698 560858864 -557214542 -1153796298 1553553385 -927160022 711546358 -1819841793 262969859 251416325 -1314890302 1806565895 969527843 -765640123 -1558624256 -1307770562 1649016367 -2088791485 -1246792495 -632463743 -1156115684 -1634823492 1663017612 1816683231 411916003 -407505982 -1947923217 1015311755 1203592432 -2124019530 -1725546580 813872093 1105387678 1431142475 220570551 -51334581 -115375441 -1687498165 -1204354055 282341803 1734241730 1391822177 1001254810 827927915 1886687171 -359869949 -1663178582 -389804030 110554195 -1847011650 -577764321 -990174221 -555352817 -1235839828 953919171 -1704843582 1132511021 -499373617 -1506936867 982155079 -822617740 859942552 -1613959905 -1995343243 647443547 233600422 608168955 -605639843 1849778220 1608438222 -326808939 -1601989520 -1443094724 246750393 -712148668 -965314987 -258600386 1012970930 950780808 -335198552 -1756417251 191422718 -1636824921 -1018598285 -1367229812 1234200027 1920815603 -758892607 1535612501 -2110825225 -1018012242 428488088 -1916555312 -235197746 -381222555 -1562828050 64369859 -539297222 842839565 -1475072830 -1880248323 1010060670 1839715346 -1884656160 152774329 -809957816 -192865784 -1442242992 879944024 1785007662 -1546682833 1354768064 -1027182560 -2025839579 -1293726535 -1115170533 895723219 865924942 -3396359 89355264 1471026971 -180786551 -1093027545 -1427490297 -1834101236 -691092725 -2056086864 -986551128 2072246611 -1539313457 -521230048 1709066580 -12235829 -1548797126 -1462398966 433439009 -1119188564 26248366 -1743584495 183214346 -401627780 1928168445 1337157619 -865870742 -1019796396 1782047316 -30563540 1876594403 -5307724 -1071132402 1728705513 -226722562 -1427127009 1147798696 302879820 1730407747 1923824407 1180597908 1569786639 198796327 560793173 2107345620 -1588976980 -846195190 -616593141 758635715 884524671 486356516 1774865603 -413741070 -1659753689 1181121587 1508809820 -1115979055 1594193633 1235154121 326117244 -1990935871 937054774 -1607551351 -1102577956 2003740439 1823766188 -1535423894 10067710 1533252662 -162472312 82378136 420615890 -827404133 541562091 -759017432 -2017648099 -964144443 -1079313122 -181135317 -89970305 -2132718963 -1039873774 -2075878387 -1316688259 255818579 -1435618668 -1197686985 -1725246173 1861951120 -1387887217 -1575500130 998319094 -1773032169 -1890841958 259456032 2086860995 1839848496 1893547357 -1766969771 1489393124 -1434111947 76448234 -2030033261 744914583 -1708176037 1385380501 66529922 1819103258 1899300332 2098173828 1793831094 276463159 360132945 -116755238 595015228 177071838 -1494887006 1573557746 1548998935 378454223 1460534296 1116274283 -1182582233 -585205500 827999348 -714924449 1913901014 614021289 -16439273 1905177404 45407939 -996784062 1184848810 -650040966 -371331837 1627046213 -617090537 969772772 1160524753 1522441192 452369933 1527502551 832490847 1003299676 1071381111 -1403711820 973747308 -208070188 1847554542 -399315698 -2067146957 1621250941 -1413622605 -711401475 -784562798 849362119 862871471 797858058 -1427192364 -1473684684 -1022564150 -296987391 209178708 1805135652 6783381 -1471605873 792580494 -31217526 776439581 -496773473 -1441523202 -1565459822 1071873341 1329010206 1289336450 -967286538 2011491779 80157208 922428856 1158943220 1667230961 -1833944476 -1686122137 387516115 -949615386 1495629111 -196813139 -1138317683 -769268697 -160059259 446713264 2137537399 -677563784 813966752 1157943946 -560274331 1680301658 -1114568823 -785112585 -2066852684 1008102291 486805123 863791847 -1105842006 1050308116 -517625770 -3240795 844061465 1347461791 -1468485715 745465012 2055805750 -34757821 -1908274199 -1314320555 447229436 2077782664 1232942813 -271964564 1399011509 -1154397447 -1715058074 -500109825 900758066 -1407767613 1720257997 -927472365 -1626046067 955539029 -476240864 1105704962 -405760041 -2017597989 -1548482791 1761846513 -1881050512 -1609840211 -54709353 1166726899 -79751581 -1212875229 -334505350 1663304043 2087473241 -132377310 -1787656518 1579665506 767234210 970676017 492207530 1441679602 1314785090 -1032764726 -877875554 1561989210 -1283560516 1146609202 -1032646256 1374872171 1634688712 1280458888 -2064943314 419323804 -1032067496 39783310 1641619040 1700368658 -2087020668 -1723666357 -1870887530 780290914 -1579772200 -904009601 163151474 -1985432754 1860018424 555755123 280320104 1604831083 -1581944913 1728987441 -655011794 623065489 -466336349 -19488246 -778619913 -1951016101 -1864289540 635534992 -426267547 808442435 -1224323227 -12801293 2093181383 2023555632 1568662086 -872594676 -160444946 -1277987753 -1035647062 -1406936567 -1109713420 -36187653 1267304371 1022517473 815943045 929020012 -1299716278 -923684000 -686938247 2018485115 122123397 -1484298146 1411365618 1238391329 1186786476 -1138998205 -2052025986 1765554882 279121160 -15128781 1641578514 -498643281 13351065 103516986 1609694427 551411743 -1801195687 1316337047 -362316440 -105267093 463397996 -1357232230 1855616529 -1668119306 55091862 -471616085 753448970 -249921796 1274127772 1124182256 92039808 2126345552 425973257 386287896 -1705097105 1987762798 -210140323 -2122510611 -928383841 -692000643 -1916163761 -1393202863 -578038290 -584808296 -1641518141 -825224666 -1198522820 -362402643 -1699709863 318974657 -1148764812 853571438 144400272 -526558455 782634401 -2133858293 570039522 1886241521 14249488 -2064163068 1604941699 -366253961 -373024787 -2139160404 134366254 430507376 1924011722 276713377 196481886 -680156304 1610021185 1785757066 851346168 -533818653 -1376131654 -930544911 -1282682830 -559008445 -1651813404 -516359065 1164289832 205853021 -1418855065 -791569014 -1216570295 -822929375 1748894853 -1554105821 316056182 1660426908 168885906 956005527 -310612507 566521563 1001109523 1216710575 -1342682539 -460534215 -452358995 -1827614888 -320526032 -1038365551 1409353924 1329904859 -1987407003 -1169749417 -672047112 -462181612 -412601345 -1986430181 -1635812268 1450441945 -762709693 -1108643102 1225603425 1124246549 175808705 -1285824977 -1498257137 -642977189 160762750 1902254979 1698648476 1134980669 497144426 -992277961 -237481666 -691436533 -207714709 427812652 286876201 823134128 1627554964 -549402969 -1705741204 -92942802 62878473 -1019381402 -307843232 -1503190137 1916869511 -1709105391 1375038919 1403421920 60249114 -483096846 -1273469287 -1681974094 528933105 -1537605975 -953564332 -1673105596 273128190 -279715118 -1200186294 1621621288 -1957356119 1796718448 1258965619 -53054156 2138560392 -1272777073 -120786372 450094611 -1020242716 617150026 -1590306631 1469700689 1341616587 356715071 1188789960 -2016098161 1766569160 -1499070661 57824704 -1401470916 1235723989 1630694347 -367006774 428891364 1814070806 -2006967509 -169026112 -326863407 -746243246 1025597707 1404281500 2002212197 92429143 -1981023352 -1891881216 -1288786662 -732985532 1671860914 1768520622 1803542985 844848113 -1288827375 1410888995 1157749833 2125704913 1789979528 1799263423 741157179 -1889104987 767040434 -1639725906 -631547117 -2122958200 -1783036109 1680542666 231857466 1154981000 157168255 1454112128 -789095197 1929775046 -1985544946 2143329496 -1334250394 407610648 -1356859167 -1713217697 538837155 -1952338429 430543915 740188568 1937713272 -979752164 2085587024 -264201609 766054429 -777325457 689721775 1294158986 1753287754 -92365948 1974852792 33459103 -726879761 -1150289861 1686130825 -160024283 -1289228861 -695673910 426570142 754104406 -634074732 1964545167 829466833 821587464 1746693036 1006492428 1595312919 1256599985 1024482560 1897312280 -1392064095 691790057 1037515867 -1118136088 1968401055 -2121460472 1089055278 1748401123 -1353587214 968412354 1818753861 -1321766430 -419015522 1119354008 -306363157 1647155589 -2062516470 -808909285 -639183253 -535708834 847163678 1082052057 989516446 -1423425541 -1098656226 -365004218 658187585 -630022655 -2119818126 -2091258149 -1538952607 -1838493377 -404699906 1293787864 -1464619312 -1235686365 -136164776 1561677400 -1708396358 783570352 1355506163 31495586 -505529953 -954417867 2092501630 896419368 671715824 -764517215 -691413158 1055991716 -852659077 1499434728 -1164678823 -655460296 17769680 -2035225876 487032199 -67823894 -601196040 1880482820 -370156500 381462353 -277111305 -1842932353 -1558286463 -2085100911 2128986379 437874044 595759426 641721026 1636065708 -395830363 629879088 -703792790 351984326 -1656183752 -1946523015 -1953362636 2123933692 143443325 1525942256 364660499 599149312 939093251 1523003209 106601097 376589484 1346282236 1297387043 764598052 -553749185 933457002 1886424424 -1075336280 525405256 -1280731677 323149677 2038881721 -194838253 -1443252195 -1310939218 1888574695 2014194741 -779773416 -114393766 -833142933 -1652971799 -1115737051 -1392672313 -2077646840 -254115141 1784656905 -983060365 87498458 -1541995478 -1659492999 -1463751930 -612736190 -1374923403 -522037592 -1478592352 309949752 -1911208442 154870719 385111597 1191604312 1840700563 872191186 -1369418595 1310412747 2102066999 1504727249 -720668546 1191230036 -964392030 -1114675199 -755619575 681369118 -989841544 -646733699 950049240 -121709603 1760124957 512151405 681175196 580563018 1169662867 -279933742 -1607186195 699691603 -1621473108 1137221356 123599888 472658308 1053598179 1012713758 -813902453 -535506283 -313509340 -464379634 1877191791 -643970560 988064871 -779505696 -205890064 -2069819848 1249609188 -1651815433 -398763161 -1877971395 1397735321 -834941650 1000 outputs of RanGen2 0.26275443 0.49000644 0.48670464 0.60143112 0.77933125 0.19867227 0.44218740 0.53427201 0.28842173 0.78180608 0.42179002 0.70785655 0.04534773 0.19644020 0.88107718 0.73978165 0.15286910 0.57514568 0.72765211 0.44872929 0.24557914 0.12664415 0.04708246 0.40959343 0.92043116 0.36334511 0.69189126 0.64718544 0.20259889 0.13426346 0.27408121 0.54531601 0.54605807 0.38595519 0.19398270 0.55377184 0.11711170 0.55565708 0.60133577 0.91500776 0.41810699 0.72320679 0.73353705 0.42871862 0.48897234 0.69786706 0.30558809 0.56961067 0.05840445 0.40479405 0.13288060 0.45009721 0.04948447 0.70645042 0.95000959 0.37050869 0.20806991 0.69406895 0.29286390 0.99332866 0.28483914 0.25145146 0.62341941 0.92030252 0.66728160 0.09906494 0.87575460 0.47815160 0.89815952 0.93595080 0.54952478 0.83917805 0.26509902 0.11034321 0.40654701 0.42915732 0.35365931 0.68812377 0.15913428 0.78814566 0.09476081 0.77835931 0.10722542 0.18310435 0.19387186 0.53699800 0.15897714 0.67527003 0.52889304 0.36777366 0.62352068 0.41439461 0.82022990 0.94445731 0.84903686 0.24639273 0.15918367 0.42492794 0.81872642 0.27749724 0.35413832 0.26385624 0.82744211 0.41326300 0.77458185 0.72190155 0.69865383 0.81227402 0.35321225 0.34243342 0.28544200 0.21854080 0.42503892 0.32703064 0.38306297 0.97284073 0.20059042 0.98003761 0.88671694 0.10465770 0.91747204 0.97163243 0.22750808 0.15830223 0.60955369 0.14215401 0.73456345 0.45944940 0.22822249 0.90888451 0.19980355 0.76677428 0.07333635 0.89791582 0.35377858 0.26962816 0.22004885 0.40903087 0.01376506 0.87732665 0.62691640 0.21249738 0.31217908 0.87037313 0.82772374 0.64238259 0.55614811 0.24363008 0.89773267 0.44859135 0.81452454 0.61730313 0.12962618 0.83334237 0.95547255 0.60089665 0.06550662 0.10539371 0.66027624 0.63245301 0.10959939 0.54671662 0.49356286 0.07660859 0.90269560 0.95274629 0.56699735 0.35064246 0.37742744 0.04508392 0.37242982 0.79321385 0.17660627 0.18230715 0.29052073 0.98592054 0.75186266 0.43769755 0.78565487 0.97219067 0.49054882 0.63155240 0.97110470 0.48556600 0.34397623 0.62875246 0.40953202 0.99129015 0.73792727 0.29481194 0.94337770 0.46564297 0.17749118 0.05684872 0.77286897 0.29538393 0.11965356 0.72487929 0.52226018 0.99248200 0.92247006 0.41797788 0.49250134 0.73449967 0.02531508 0.60246337 0.28685622 0.84310922 0.39892996 0.90454552 0.18608407 0.80752487 0.33601319 0.04956031 0.13777550 0.32199797 0.74890696 0.98801123 0.98661910 0.01223987 0.82969635 0.81075073 0.71393155 0.23453207 0.65565705 0.08584522 0.78976728 0.47621478 0.11498701 0.73891470 0.78518540 0.96809591 0.68371914 0.87597910 0.63492176 0.16849449 0.32811466 0.06240330 0.87548956 0.77562998 0.77521910 0.24096121 0.27176757 0.63748143 0.49747138 0.42504502 0.59175241 0.71389176 0.71766512 0.81183245 0.73271221 0.71207367 0.07903312 0.27523344 0.63242613 0.81037988 0.51204835 0.21652949 0.34487594 0.64982178 0.07423142 0.95677888 0.98420169 0.03465428 0.02667473 0.96880526 0.99849733 0.55670710 0.29022476 0.53872047 0.71697212 0.70443086 0.78949326 0.31678186 0.37629474 0.42297064 0.77373097 0.34625273 0.01505586 0.50582792 0.83295971 0.41848412 0.42537226 0.41760033 0.57541125 0.21745848 0.11158698 0.50941650 0.53135554 0.21527471 0.74821915 0.13636652 0.36159918 0.76450229 0.10160194 0.85557725 0.74477500 0.57186456 0.01757096 0.12120362 0.47981062 0.19954667 0.71065616 0.63382753 0.77693186 0.09644095 0.21500764 0.54110751 0.45730081 0.41600724 0.97704678 0.76183479 0.84706971 0.57545431 0.79398385 0.43236070 0.10486023 0.98015011 0.58870451 0.95548581 0.41872718 0.88142712 0.60668643 0.51397541 0.54520355 0.43822273 0.68011940 0.07577277 0.41427606 0.80911399 0.45853475 0.73611214 0.19619891 0.19601980 0.26765372 0.08515930 0.99479057 0.61288752 0.47187699 0.82095365 0.07563608 0.90760618 0.28703383 0.93261152 0.40877651 0.34686346 0.60599030 0.22872803 0.69315490 0.16152912 0.60210518 0.56257876 0.97950688 0.97062066 0.22701157 0.98915116 0.16110261 0.10170685 0.74516994 0.62726050 0.53451185 0.40864994 0.33494878 0.44800035 0.41035206 0.64480751 0.38458997 0.03498312 0.65963215 0.05378627 0.85171349 0.78719791 0.59097957 0.50667896 0.82309622 0.37561479 0.92534520 0.41748977 0.23908457 0.91793223 0.49279792 0.37908370 0.78458072 0.09132853 0.48672190 0.78547393 0.59452165 0.39910674 0.03681109 0.87931425 0.12683489 0.06609740 0.74801549 0.02948179 0.48328855 0.16403523 0.05523786 0.25886666 0.34784685 0.36829981 0.21448906 0.34670080 0.93922919 0.70771016 0.14157936 0.75664246 0.23055695 0.36395782 0.15852932 0.49061803 0.90280575 0.89146298 0.57291005 0.47200603 0.70555729 0.09616495 0.58138254 0.95796388 0.83681125 0.83989127 0.68717090 0.03545811 0.10550838 0.36520709 0.84290701 0.22743276 0.23023855 0.84195926 0.15019733 0.52765254 0.22575740 0.82709576 0.53420866 0.76061893 0.06997511 0.78439072 0.34422744 0.27637570 0.05982168 0.56720327 0.08449067 0.21657369 0.65819609 0.08042821 0.57947911 0.90193792 0.61376012 0.38762938 0.17532159 0.21223735 0.77829114 0.54806073 0.71144026 0.08830274 0.54140071 0.93215628 0.62952729 0.44668759 0.37391019 0.48382450 0.77750768 0.40849647 0.40962737 0.09269720 0.46102026 0.99544979 0.82007095 0.12585546 0.53119821 0.35953001 0.72017528 0.55834068 0.30731217 0.03799961 0.24166948 0.27426600 0.93938444 0.04862081 0.08575513 0.65886492 0.23214332 0.61649057 0.27463977 0.35788827 0.67061997 0.16838056 0.46076133 0.57949296 0.18521946 0.39986254 0.55667410 0.62741385 0.33470977 0.13969104 0.96612929 0.60200126 0.51194925 0.60476340 0.40285217 0.81221221 0.82980614 0.96041971 0.02024973 0.55425470 0.78330912 0.10426543 0.50598243 0.47244013 0.71135841 0.28561597 0.28428734 0.13422849 0.82909934 0.94771136 0.77380750 0.64966697 0.68156268 0.15686758 0.78726350 0.47074787 0.13676171 0.46649494 0.74526295 0.58297372 0.04257548 0.53166785 0.83735355 0.65946671 0.52102971 0.96228045 0.61892296 0.83408336 0.79875681 0.79847692 0.23767569 0.52080745 0.12980060 0.58082293 0.72993106 0.75031439 0.37787525 0.95150053 0.63673441 0.13407612 0.47907688 0.02241942 0.00580158 0.56273902 0.55270283 0.27031811 0.55113352 0.74393329 0.25036441 0.87436336 0.72877652 0.09975358 0.35707591 0.38691457 0.35547165 0.86641027 0.08720133 0.95462835 0.59243817 0.82981586 0.57820411 0.75421519 0.86004706 0.10092307 0.96192412 0.86758683 0.48424170 0.58019934 0.18594024 0.95826386 0.79962317 0.29365413 0.39231296 0.99478547 0.37645944 0.73590734 0.78106737 0.25026285 0.58136314 0.29582424 0.26010628 0.32792971 0.77947652 0.22482861 0.32191216 0.96171689 0.29189752 0.46043686 0.01609668 0.38995725 0.78998963 0.05191845 0.53934737 0.33033700 0.99553013 0.48009549 0.69017594 0.48347750 0.83452066 0.37144372 0.22106301 0.21272114 0.21465963 0.38361677 0.35571283 0.23782329 0.70920458 0.84855153 0.96766817 0.52780062 0.24898344 0.53680650 0.94866557 0.27426312 0.41025891 0.75195236 0.37319953 0.13265037 0.75552148 0.77422476 0.45217406 0.89281839 0.16441573 0.59158900 0.44515992 0.57800798 0.52507888 0.89901462 0.67382573 0.62141278 0.35502334 0.69902911 0.52160210 0.94460522 0.64688742 0.18020336 0.21323733 0.10922473 0.45400380 0.49611159 0.40897777 0.91073520 0.16206647 0.82064685 0.12805003 0.00677209 0.02690101 0.37473387 0.23918362 0.89826974 0.93683919 0.30459118 0.82422684 0.51958019 0.45319576 0.48326137 0.33931735 0.19060863 0.83671416 0.18062550 0.15152380 0.83392969 0.53451730 0.45227244 0.18200635 0.35074171 0.14721009 0.01234433 0.23402047 0.50969637 0.43835057 0.30803854 0.81485260 0.70089527 0.51323282 0.09933780 0.81584602 0.70209563 0.83754800 0.18604181 0.74443049 0.69952227 0.28162632 0.60336988 0.61360736 0.73536740 0.73262256 0.17803776 0.98749791 0.24658435 0.42156640 0.06706407 0.86683221 0.49157136 0.73421374 0.95183767 0.41609720 0.35573315 0.87706276 0.27042618 0.80891908 0.90709595 0.56944866 0.11342849 0.38817388 0.08734506 0.48711323 0.64744128 0.13242656 0.37704136 0.18347125 0.34446569 0.93265239 0.75146321 0.54130111 0.84259839 0.42697368 0.90878778 0.06990338 0.26204273 0.69820348 0.16314909 0.52482844 0.56669207 0.00205581 0.76084093 0.15139159 0.91650223 0.59733904 0.06344203 0.12651696 0.17332139 0.08037374 0.97258086 0.71010758 0.55713135 0.39390629 0.60781246 0.82037450 0.57628388 0.84227964 0.92190597 0.08201860 0.27363549 0.99595133 0.36031236 0.33906769 0.31098161 0.76694195 0.64215941 0.38210306 0.03634237 0.62090720 0.32480459 0.25930318 0.81847147 0.42768077 0.51037616 0.06201727 0.38107122 0.85925856 0.35860762 0.11109408 0.20408301 0.08434977 0.42192494 0.12667915 0.25988365 0.56858761 0.86156496 0.08057195 0.63636150 0.07719713 0.09340255 0.13530602 0.72976282 0.21915530 0.91162531 0.13979565 0.59931342 0.29344045 0.60893790 0.34450224 0.73122236 0.49485593 0.23637397 0.67276368 0.63357764 0.24965804 0.14991737 0.11990341 0.91523170 0.55878239 0.55687301 0.55497131 0.92868366 0.92571090 0.75810502 0.39642955 0.80439758 0.89310223 0.61357431 0.54288255 0.73397550 0.61200634 0.35621396 0.39733974 0.87508865 0.92077265 0.18597384 0.22781399 0.69296476 0.11699087 0.81667128 0.17756410 0.50177323 0.55725176 0.29474693 0.68885238 0.56724856 0.18193156 0.92202167 0.72082041 0.78554673 0.14995708 0.37851940 0.79124547 0.11009521 0.37374537 0.55743712 0.19902994 0.31925115 0.95653873 0.87236821 0.81118709 0.02734307 0.89672836 0.88185294 0.80163915 0.67374510 0.54913278 0.40404879 0.75742801 0.08266467 0.47663209 0.29823377 0.86437958 0.65206043 0.76529938 0.72690047 0.55839021 0.34721160 0.68622435 0.87809403 0.05706977 0.99828704 0.97659049 0.74289680 0.38477595 0.57807463 0.06245739 0.23490635 0.71099431 0.63164942 0.25840044 0.16877037 0.78988183 0.94046090 0.74967434 0.30048356 0.76029740 0.80416821 0.14151867 0.02067892 0.62880774 0.35465381 0.52690525 0.69149288 0.99630295 0.29682619 0.93566145 0.50288078 0.31484193 0.53763639 0.18529083 0.51339574 0.88405386 0.80537067 0.72994703 0.94000045 0.77217985 0.03831243 0.52870435 0.36282045 0.11831306 0.59164956 0.75609707 0.57445781 0.22185784 0.40058883 0.80070608 0.44476583 0.06822213 0.71933909 0.46772793 0.30063440 0.76307906 0.81183306 0.66501252 0.05436179 0.18562285 0.73829083 0.36511559 0.07868991 0.31888344 0.70126869 0.43172350 0.16028129 0.71786948 0.28515828 0.60262106 0.85390326 0.29303876 0.13427924 0.40479631 0.81024934 0.10635447 0.06198079 0.13573813 0.41854197 0.49701497 0.33085849 0.81692291 0.51925964 0.47446405 0.48751283 0.10944293 0.63751018 0.19519957 0.18956636 0.06969015 0.96440193 0.38341765 0.86754434 0.39223647 0.89786427 0.35055280 0.62749961 0.29452122 0.39449784 0.64567830 0.95716830 0.24822309 0.78200437 0.92546044 0.67464886 0.18308746 0.15496587 0.02935411 0.62736159 0.11523955 0.31590528 0.13107864 0.89786553 0.70102294 0.03292914 0.25485590 0.09847044 0.82861691 0.62125866 0.08917183 0.57638293 0.36845380 0.79192617 0.53989733 0.02180460 0.82503407 0.14071852 0.19516575 0.24254998 0.04587026 0.98713246 0.82920155 0.58719954 0.13497059 0.04328459 0.14178757 0.95583809 0.20694291 0.35212760 0.36074305 0.83163422 0.35739792 0.09908488 0.24566046 0.22157152 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/random/test_ga.pas�������������������������������������0000755�0001750�0001750�00000020333�11326425444�022027� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Optimization by Genetic Algorithm ****************************************************************** } program test_ga; uses tpmath; function Func1(X : PVector) : Float; { ------------------------------------------------------------------ Example taken from 'Numerical Recipes' True minimum is at (-2.0, +/-0.89442719) ------------------------------------------------------------------ } var A, AA, B, BB : Float; begin A := Sqr(X^[2]) * (3.0 - X^[1]) - Sqr(X^[1]) * (3.0 + X^[1]); B := 2.0 + X^[1]; AA := Sqr(A); BB := Sqr(B); Func1 := 10.0 * AA + BB / (1.0 + BB); end; function Func2(X : PVector) : Float; { ------------------------------------------------------------------ Example taken from 'Numerical Recipes' True minimum is at (0, 0, 0, 0), F = 1.0 ------------------------------------------------------------------ } const Nvar = 4; Rad = 0.3; Aug = 2.0; Wid : array[1..Nvar] of Float = (1.0, 3.0, 10.0, 30.0); var J : Integer; Q, R, Rad2, Sumd, Sumr : Float; begin Sumd := 0.0; Sumr := 0.0; Rad2 := Sqr(Rad); for J := 1 to Nvar do begin Q := X^[J] * Wid[J]; if Q >= 0 then R := Int(Q + 0.5) else R := Int(Q - 0.5); Sumr := Sumr + Sqr(Q); Sumd := Sumd + Sqr(Q - R); end; if Sumd > Rad2 then Func2 := 1.0 + Sumr * (1.0 + Aug) else Func2 := 1.0 + Sumr * (1.0 + Aug * Sumd / Rad2); end; function Func3(X : PVector) : Float; { ------------------------------------------------------------------ Rosenbrock function. True minimum is at (1, 1), F = 0 Ref: H. Rosenbrock, Comput. J., 1960, 3, 175 ------------------------------------------------------------------ } begin Func3 := 100.0 * Sqr(X^[2] - Sqr(X^[1])) + Sqr(1.0 - X^[1]); end; function Func4(X : PVector) : Float; { ------------------------------------------------------------------ Powell function. True minimum is at (0, 0, 0, 0), F = 0 Ref: M.J.D. Powell, Comput. J., 1962, 5, 147 ------------------------------------------------------------------ } begin Func4 := Sqr(X^[1] + 10.0 * X^[2]) + 5.0 * Sqr(X^[3] - X^[4]) + Sqr(Sqr(X^[2] - 2.0 * X^[3])) + 10.0 * Sqr(Sqr(X^[1] - X^[4])); end; function Func5(X : PVector) : Float; { ------------------------------------------------------------------ Another Powell function. Multiple minima at x1 = x2 = x3 = +/- Sqrt(4*n+1), n integer, F = -3 Ref: M.J.D. Powell, Comput. J., 1964, 7, 155 NB: The original reference maximizes F. Here we shall minimize -F. ------------------------------------------------------------------ } begin Func5 := - 1.0 / (1.0 + Sqr(X^[1] - X^[2])) - Sin(PiDiv2 * X^[2] * X^[3]) - Expo(- Sqr((X^[1] + X^[3]) / X^[2] - 2.0)); end; function Func6(X : PVector) : Float; { ------------------------------------------------------------------ Fletcher & Powell function. True minimum is at (1, 0, 0), F = 0 Ref: R. Fletcher & M.J.D. Powell, Comput. J., 1964, 7, 155 ------------------------------------------------------------------ } var R, Theta : Float; begin R := Pythag(X^[1], X^[2]); Theta := ArcTan2(X^[2], X^[1]) / TwoPi; Func6 := 100.0 * (Sqr(X^[3] - 10.0 * Theta) + Sqr(R - 1.0)) + Sqr(X^[3]); end; function Func7(X : PVector) : Float; { ------------------------------------------------------------------ Colville function (Extension of Rosenbrock function) True minimum is at (1, 1, 1, 1), F = 0 Ref: R. J. Van Iwaarden, PhD Thesis, U. Denver, 1996 ------------------------------------------------------------------ } begin Func7 := 100.0 * Sqr(X^[2] - Sqr(X^[1])) + Sqr(1.0 - X^[1]) + 90.0 * Sqr(X^[4] - Sqr(X^[3])) + Sqr(1.0 - X^[3]) + 10.1 * ((Sqr(X^[2] - 1.0) + Sqr(X^[4] - 1.0))) + 19.8 * (X^[2] - 1.0) * (X^[4] - 1.0); end; function Func8(X : PVector) : Float; { ------------------------------------------------------------------ Griewank function. True minimum is at (0, 0), F = 0 Ref: R. J. Van Iwaarden, PhD Thesis, U. Denver, 1996 ------------------------------------------------------------------ } begin Func8 := (Sqr(X^[1]) + Sqr(X^[2])) / 200.0 - Cos(X^[1]) * Cos(X^[2] / Sqrt2) + 1.0; end; function Func9(X : PVector) : Float; { ------------------------------------------------------------------ Chichinadze function. True minimum is at (5.90133, 0.5), F = -43.3159 Ref: R. J. Van Iwaarden, PhD Thesis, U. Denver, 1996 ------------------------------------------------------------------ } const FivePi = 15.707963267948966193; { 5 * Pi } InvSqrt5 = 0.44721359549995793928; { 1 / Sqrt(5) } begin Func9 := X^[1] * (X^[1] - 12.0) + 11.0 + 10.0 * Cos(PIDIV2 * X^[1]) + 8.0 * Sin(FivePi * X^[1]) - InvSqrt5 * Expo(- 0.5 * Sqr(X^[2] - 0.5)); end; function Func10(X : PVector) : Float; { ------------------------------------------------------------------ Rastrigin function. True minimum is at (0, 0), F = -2 Ref: R. J. Van Iwaarden, PhD Thesis, U. Denver, 1996 ------------------------------------------------------------------ } begin Func10 := Sqr(X^[1]) + Sqr(X^[2]) - Cos(12.0 * X^[1]) - Cos(18.0 * X^[2]); end; procedure Pause; begin WriteLn; Write('Press <Enter> to continue'); ReadLn; WriteLn; end; const NFunc = 10; { Number of functions } MaxNvar = 4; { Maximum number of variables } const FuncName : array[1..NFunc] of String[70] = ('Numerical Recipes Example 1: Minimum at (-2.0, +/-0.89442719), F = 0 ', 'Numerical Recipes Example 2: Minimum at (0, 0, 0, 0), F = 1 ', 'Rosenbrock function: Minimum at (1, 1), F = 0 ', 'Powell function: Minimum at (0, 0, 0, 0), F = 0 ', 'Another Powell function: Minimum at x1=x2=x3= +/- Sqrt(4*n+1), F = -3', 'Fletcher & Powell function: Minimum at (1, 0, 0), F = 0 ', 'Colville function: Minimum at (1, 1, 1, 1), F = 0 ', 'Griewank function: Minimum at (0, 0), F = 0 ', 'Chichinadze function: Minimum at (5.90133, 0.5), F = -43.3159 ', 'Rastrigin function: Minimum at (0, 0), F = -2 '); const Nvar : array[1..NFunc] of Integer = (2, 4, 2, 4, 3, 3, 4, 2, 2, 2); { Number of variables } var Func : array[1..NFunc] of TFuncNVar; { Functions } X, Xmin, Xmax : PVector; { Variables and limit values } F_min : Float; { Function value at minimum } I, J : Integer; { Loop variables } begin WriteLn; { Initialize function array } Func[ 1] := {$IFDEF FPC}@{$ENDIF}Func1; Func[ 2] := {$IFDEF FPC}@{$ENDIF}Func2; Func[ 3] := {$IFDEF FPC}@{$ENDIF}Func3; Func[ 4] := {$IFDEF FPC}@{$ENDIF}Func4; Func[ 5] := {$IFDEF FPC}@{$ENDIF}Func5; Func[ 6] := {$IFDEF FPC}@{$ENDIF}Func6; Func[ 7] := {$IFDEF FPC}@{$ENDIF}Func7; Func[ 8] := {$IFDEF FPC}@{$ENDIF}Func8; Func[ 9] := {$IFDEF FPC}@{$ENDIF}Func9; Func[10] := {$IFDEF FPC}@{$ENDIF}Func10; { Allocate arrays } DimVector(X, MaxNvar); DimVector(Xmin, MaxNvar); DimVector(Xmax, MaxNvar); { Select random number generator } SetRNG(RNG_MT); for I := 1 to NFunc do begin { Initialize limits } for J := 1 to Nvar[I] do begin Xmin^[J] := - 10.0; Xmax^[J] := 10.0; end; { Approximate global minimum with genetic algorithm } GA_CreateLogFile('genalg.txt'); GenAlg(Func[I], X, Xmin, Xmax, 1, Nvar[I], F_min); { Display results } Writeln(FuncName[I]); Writeln; for J := 1 to Nvar[I] do Writeln('X(', J, ') = ', X^[J]:12:6); Writeln; Writeln('F = ', F_min:10); Writeln; Pause; end; { Deallocate arrays } DelVector(X, MaxNvar); DelVector(Xmin, MaxNvar); DelVector(Xmax, MaxNvar); end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/random/testmwc.pas�������������������������������������0000755�0001750�0001750�00000002170�11326425444�022066� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program picks 20000 random numbers and displays the next 6, together with the correct values obtained with the default initialization, ****************************************************************** } program testmwc; uses tpmath; const Correct : array[1..6] of LongInt = (921625997, 1094293978, 115775252, 499820504, -1929018715, 2008943384); var I, R : LongInt; begin WriteLn; Writeln(' Test of Marsaglia random number generator'); WriteLn('---------------------------------------------'); WriteLn(' Correct Actual'); WriteLn('---------------------------------------------'); SetRNG(RNG_MWC); { Pick 20000 random numbers } for I := 1 to 20000 do R := IRanGen; { Display 6 more numbers with correct values } for I := 1 to 6 do begin R := IRanGen; Write(' ', Correct[I]:12, ' ', R:12, ' '); if Correct[I] = R then WriteLn('OK') else WriteLn('BAD'); end; WriteLn('---------------------------------------------'); end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/random/testmt.pas��������������������������������������0000755�0001750�0001750�00000001462�11326425444�021723� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Test of 'Mersenne Twister' random number generator This program prints 1000 random numbers, computed with the default initialization. The output of this program should be similar to file mt.txt ****************************************************************** } program testmt; uses tpmath; var I : Word; R : LongInt; X : Float; begin SetRNG(RNG_MT); Writeln('1000 outputs of IRanGen'); for I := 1 to 1000 do begin R := IRanGen; Write(R:15); if i mod 5 = 0 then Writeln; end; Writeln; Writeln('1000 outputs of RanGen2'); for I := 1 to 1000 do begin X := RanGen2; Write(X:15:8); if i mod 5 = 0 then Writeln; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/random/test_sa.pas�������������������������������������0000755�0001750�0001750�00000020467�11326425444�022053� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Optimization by Simulated Annealing ****************************************************************** } program test_sa; uses tpmath; function Func1(X : PVector) : Float; { ------------------------------------------------------------------ Example taken from 'Numerical Recipes' True minimum is at (-2.0, +/-0.89442719) ------------------------------------------------------------------ } var A, AA, B, BB : Float; begin A := Sqr(X^[2]) * (3.0 - X^[1]) - Sqr(X^[1]) * (3.0 + X^[1]); B := 2.0 + X^[1]; AA := Sqr(A); BB := Sqr(B); Func1 := 10.0 * AA + BB / (1.0 + BB); end; function Func2(X : PVector) : Float; { ------------------------------------------------------------------ Example taken from 'Numerical Recipes' True minimum is at (0, 0, 0, 0), F = 1.0 ------------------------------------------------------------------ } const Nvar = 4; Rad = 0.3; Aug = 2.0; Wid : array[1..Nvar] of Float = (1.0, 3.0, 10.0, 30.0); var J : Integer; Q, R, Rad2, Sumd, Sumr : Float; begin Sumd := 0.0; Sumr := 0.0; Rad2 := Sqr(Rad); for J := 1 to Nvar do begin Q := X^[J] * Wid[J]; if Q >= 0 then R := Int(Q + 0.5) else R := Int(Q - 0.5); Sumr := Sumr + Sqr(Q); Sumd := Sumd + Sqr(Q - R); end; if Sumd > Rad2 then Func2 := 1.0 + Sumr * (1.0 + Aug) else Func2 := 1.0 + Sumr * (1.0 + Aug * Sumd / Rad2); end; function Func3(X : PVector) : Float; { ------------------------------------------------------------------ Rosenbrock function. True minimum is at (1, 1), F = 0 Ref: H. Rosenbrock, Comput. J., 1960, 3, 175 ------------------------------------------------------------------ } begin Func3 := 100.0 * Sqr(X^[2] - Sqr(X^[1])) + Sqr(1.0 - X^[1]); end; function Func4(X : PVector) : Float; { ------------------------------------------------------------------ Powell function. True minimum is at (0, 0, 0, 0), F = 0 Ref: M.J.D. Powell, Comput. J., 1962, 5, 147 ------------------------------------------------------------------ } begin Func4 := Sqr(X^[1] + 10.0 * X^[2]) + 5.0 * Sqr(X^[3] - X^[4]) + Sqr(Sqr(X^[2] - 2.0 * X^[3])) + 10.0 * Sqr(Sqr(X^[1] - X^[4])); end; function Func5(X : PVector) : Float; { ------------------------------------------------------------------ Another Powell function. Multiple minima at x1 = x2 = x3 = +/- Sqrt(4*n+1), n integer, F = -3 Ref: M.J.D. Powell, Comput. J., 1964, 7, 155 NB: The original reference maximizes F. Here we shall minimize -F. ------------------------------------------------------------------ } begin Func5 := - 1.0 / (1.0 + Sqr(X^[1] - X^[2])) - Sin(PiDiv2 * X^[2] * X^[3]) - Expo(- Sqr((X^[1] + X^[3]) / X^[2] - 2.0)); end; function Func6(X : PVector) : Float; { ------------------------------------------------------------------ Fletcher & Powell function. True minimum is at (1, 0, 0), F = 0 Ref: R. Fletcher & M.J.D. Powell, Comput. J., 1964, 7, 155 ------------------------------------------------------------------ } var R, Theta : Float; begin R := Pythag(X^[1], X^[2]); Theta := ArcTan2(X^[2], X^[1]) / TwoPi; Func6 := 100.0 * (Sqr(X^[3] - 10.0 * Theta) + Sqr(R - 1.0)) + Sqr(X^[3]); end; function Func7(X : PVector) : Float; { ------------------------------------------------------------------ Colville function (Extension of Rosenbrock function) True minimum is at (1, 1, 1, 1), F = 0 Ref: R. J. Van Iwaarden, PhD Thesis, U. Denver, 1996 ------------------------------------------------------------------ } begin Func7 := 100.0 * Sqr(X^[2] - Sqr(X^[1])) + Sqr(1.0 - X^[1]) + 90.0 * Sqr(X^[4] - Sqr(X^[3])) + Sqr(1.0 - X^[3]) + 10.1 * ((Sqr(X^[2] - 1.0) + Sqr(X^[4] - 1.0))) + 19.8 * (X^[2] - 1.0) * (X^[4] - 1.0); end; function Func8(X : PVector) : Float; { ------------------------------------------------------------------ Griewank function. True minimum is at (0, 0), F = 0 Ref: R. J. Van Iwaarden, PhD Thesis, U. Denver, 1996 ------------------------------------------------------------------ } begin Func8 := (Sqr(X^[1]) + Sqr(X^[2])) / 200.0 - Cos(X^[1]) * Cos(X^[2] / Sqrt2) + 1.0; end; function Func9(X : PVector) : Float; { ------------------------------------------------------------------ Chichinadze function. True minimum is at (5.90133, 0.5), F = -43.3159 Ref: R. J. Van Iwaarden, PhD Thesis, U. Denver, 1996 ------------------------------------------------------------------ } const FivePi = 15.707963267948966193; { 5 * Pi } InvSqrt5 = 0.44721359549995793928; { 1 / Sqrt(5) } begin Func9 := X^[1] * (X^[1] - 12.0) + 11.0 + 10.0 * Cos(PIDIV2 * X^[1]) + 8.0 * Sin(FivePi * X^[1]) - InvSqrt5 * Expo(- 0.5 * Sqr(X^[2] - 0.5)); end; function Func10(X : PVector) : Float; { ------------------------------------------------------------------ Rastrigin function. True minimum is at (0, 0), F = -2 Ref: R. J. Van Iwaarden, PhD Thesis, U. Denver, 1996 ------------------------------------------------------------------ } begin Func10 := Sqr(X^[1]) + Sqr(X^[2]) - Cos(12.0 * X^[1]) - Cos(18.0 * X^[2]); end; procedure Pause; begin WriteLn; Write('Press <Enter> to continue'); ReadLn; WriteLn; end; const NFunc = 10; { Number of functions } MaxNvar = 4; { Maximum number of variables } const FuncName : array[1..NFunc] of String[70] = ('Numerical Recipes Example 1: Minimum at (-2.0, +/-0.89442719), F = 0 ', 'Numerical Recipes Example 2: Minimum at (0, 0, 0, 0), F = 1 ', 'Rosenbrock function: Minimum at (1, 1), F = 0 ', 'Powell function: Minimum at (0, 0, 0, 0), F = 0 ', 'Another Powell function: Minimum at x1=x2=x3= +/- Sqrt(4*n+1), F = -3', 'Fletcher & Powell function: Minimum at (1, 0, 0), F = 0 ', 'Colville function: Minimum at (1, 1, 1, 1), F = 0 ', 'Griewank function: Minimum at (0, 0), F = 0 ', 'Chichinadze function: Minimum at (5.90133, 0.5), F = -43.3159 ', 'Rastrigin function: Minimum at (0, 0), F = -2 '); const Nvar : array[1..NFunc] of Integer = (2, 4, 2, 4, 3, 3, 4, 2, 2, 2); { Number of variables } var Func : array[1..NFunc] of TFuncNVar; { Functions } X, Xmin, Xmax : PVector; { Variables and limit values } F_min : Float; { Function value at minimum } I, J : Integer; { Loop variables } begin WriteLn; { Initialize function array } Func[ 1] := {$IFDEF FPC}@{$ENDIF}Func1; Func[ 2] := {$IFDEF FPC}@{$ENDIF}Func2; Func[ 3] := {$IFDEF FPC}@{$ENDIF}Func3; Func[ 4] := {$IFDEF FPC}@{$ENDIF}Func4; Func[ 5] := {$IFDEF FPC}@{$ENDIF}Func5; Func[ 6] := {$IFDEF FPC}@{$ENDIF}Func6; Func[ 7] := {$IFDEF FPC}@{$ENDIF}Func7; Func[ 8] := {$IFDEF FPC}@{$ENDIF}Func8; Func[ 9] := {$IFDEF FPC}@{$ENDIF}Func9; Func[10] := {$IFDEF FPC}@{$ENDIF}Func10; { Allocate arrays } DimVector(X, MaxNvar); DimVector(Xmin, MaxNvar); DimVector(Xmax, MaxNvar); { Select random number generator } SetRNG(RNG_MT); for I := 1 to NFunc do begin { Initialize limits and pick starting point } for J := 1 to Nvar[I] do begin Xmin^[J] := - 10.0; Xmax^[J] := 10.0; X^[J] := Xmin^[J] + RanGen3 * (Xmax^[J] - Xmin^[J]); end; { Approximate global minimum with simulated annealing } SA_CreateLogFile('simann.txt'); SimAnn(Func[I], X, Xmin, Xmax, 1, Nvar[I], F_min); { Display results } Writeln(FuncName[I]); Writeln; for J := 1 to Nvar[I] do Writeln('X(', J, ') = ', X^[J]:12:6); Writeln; Writeln('F = ', F_min:10); Writeln; Pause; end; { Deallocate arrays } DelVector(X, MaxNvar); DelVector(Xmin, MaxNvar); DelVector(Xmax, MaxNvar); end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/matrices/����������������������������������������������0000755�0001750�0001750�00000000000�12360760644�020222� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/matrices/hilbert.pas�����������������������������������0000755�0001750�0001750�00000007466�11326425444�022375� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program solves a system of linear equations, of the form AX = B, by the method of Gauss-Jordan. The method is demonstrated by solving a series of Hilbert systems of increasing order. Hilbert systems have ill-conditioned matrices (i.e. with determinants close to zero), so that the matrix is considered singular for an order which depends on the numerical precision of the software. The type of real numbers is defined by the compiler directives (see UTYPES.PAS for details). The constant MachEp (defined in UTYPES.PAS) sets the numerical precision which can be obtained with each type. When the determinant falls below this value the matrix is considered singular. ****************************************************************** } program hilbert; uses tpmath; procedure HilbertSystem(N : Integer; var A : PMatrix); { ------------------------------------------------------------------ Generates the Hilbert system of order N A[1..N, 1..N] = system matrix : ( 1 1/2 1/3 1/4 ... 1/N ) ( 1/2 1/3 1/4 1/5 ... 1/(N+1) ) A = ( 1/3 1/4 1/5 1/6 ... 1/(N+2) ) ( ........................................... ) ( 1/N 1/(N+1) 1/(N+2) 1/(N+3) ... 1/(2N-1) ) A[1..N, N+1] = vector of constant terms : N A[i, N+1] = Sum A[i,j] j=1 The solution vector is X = [1 1 1 ... 1] ------------------------------------------------------------------ } var I, J, M : Integer; Sum : Float; begin { First row of matrix } A^[1]^[1] := 1.0; for J := 2 to N do A^[1]^[J] := 1.0 / J; for I := 2 to N do begin { N-th column of matrix } A^[I]^[N] := 1.0 / (N + I - 1); { Fill matrix } for J := 1 to N - 1 do A^[I]^[J] := A^[I - 1]^[J + 1]; end; { Last column = Constant vector } M := N + 1; for I := 1 to N do begin Sum := 0.0; for J := 1 to N do Sum := Sum + A^[I]^[J]; A^[I]^[M] := Sum; end; end; procedure WriteHilbertMatrix(N : Integer; A : PMatrix); var I, J, M : Integer; begin WriteLn('System matrix and constant vector :'); WriteLn; M := N + 1; for I := 1 to N do begin for J := 1 to M do Write(A^[I]^[J]:10:6); WriteLn; end; WriteLn; end; procedure WriteSolution(ErrCode, N : Integer; A : PMatrix; D : Float); var I, M : Integer; begin if ErrCode = MatSing then WriteLn('Determinant <', D:10, ' ==> Quasi-Singular Matrix !') else begin WriteLn('Solution vector :'); WriteLn; M := N + 1; for I := 1 to N do WriteLn(A^[I]^[M]:10:6); WriteLn; WriteLn('Determinant : ', D:10); end; WriteLn; Write('Press <Enter> ...'); ReadLn; end; var N : Integer; { Order of the system } M : Integer; { N + 1 } ErrCode : Integer; { Error code } A : PMatrix; { System matrix } D : Float; { Determinant } begin { Initialize } N := 1; ErrCode := 0; { Main loop } while ErrCode = 0 do begin { Set system order } Inc(N); M := N + 1; { Allocate matrix } DimMatrix(A, N, M); { Generate Hilbert system of order N } HilbertSystem(N, A); WriteLn; WriteLn('HILBERT SYSTEM OF ORDER ', N); WriteLn; if N < 7 then WriteHilbertMatrix(N, A); { Solve Hilbert system } GaussJordan(A, 1, N, M, D); ErrCode := MathErr; { Write solution } WriteSolution(ErrCode, N, A, D); { Deallocate matrix so that it may be redimensioned at the next iteration } DelMatrix(A, N, M); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/matrices/detinv.pas������������������������������������0000755�0001750�0001750�00000004601�11326425444�022221� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program computes the determinant and inverse of a square matrix. The matrix is stored in a data file with the following structure : Line 1 : dimension of the matrix (N) Lines 2 to (N + 1) : matrix The file MATRIX1.DAT is an example data file with N = 4 ****************************************************************** } program detinv; uses tpmath; procedure WriteMatrix(Title : String; A : PMatrix; N : Integer); { ------------------------------------------------------------------ Writes a matrix ------------------------------------------------------------------ } var I, J : Integer; begin WriteLn(Title, ' :'); WriteLn; for I := 1 to N do begin for J := 1 to N do Write(A^[I]^[J]:12:6); WriteLn; end; WriteLn; end; procedure WriteMatrixDet(Title : String; A : PMatrix; N : Integer; D : Float); { ------------------------------------------------------------------ Writes a matrix and its determinant ------------------------------------------------------------------ } begin WriteLn('Determinant = ', D:12:6); WriteLn; WriteMatrix(Title, A, N); end; var F : Text; { Data file } N : Integer; { Size of matrix } A : PMatrix; { Matrix } D1, D2 : Float; { Determinants } I, J : Integer; { Loop variable } begin { Read matrix from file } Assign(F, 'matrix1.dat'); Reset(F); Read(F, N); DimMatrix(A, N, N); for I := 1 to N do for J := 1 to N do Read(F, A^[I]^[J]); Close(F); { Write matrix } WriteMatrix('Original matrix', A, N); { Compute inverse matrix and determinant } GaussJordan(A, 1, N, N, D1); case MathErr of MatOk : begin WriteMatrixDet('Inverse matrix', A, N, D1); { Reinvert matrix. D2 = 1/D1 } GaussJordan(A, 1, N, N, D2); if MathErr = MatOk then WriteMatrixDet('Reinverted inverse matrix', A, N, D2); WriteLn('Product of determinants = ', (D1 * D2):12:6); end; MatSing : Write('Singular matrix!'); MatErrDim : Write('Non-compatible dimensions!'); end; end. �������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/matrices/eigenvec.pas����������������������������������0000755�0001750�0001750�00000007243�11326425444�022522� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** This program computes the eigenvalues and eigenvectors of a general square matrix. The matrix is stored in a data file with the following structure : Line 1 : dimension of the matrix (N) Lines 2 to (N + 1) : matrix The file MATRIX1.DAT is an example data file with N = 4. ********************************************************************** } program eigenvec; uses tpmath; var A : PMatrix; { Matrix } N : Integer; { Dimension of matrix } Lambda : PCompVector; { Eigenvalues } V : PMatrix; { Eigenvectors } I : Integer; { Loop variable } ErrCode : Integer; { Error code } procedure ReadMatrix(FileName : String; var A : PMatrix; var N : Integer); { ---------------------------------------------------------------------- Reads matrix from file. Note that A is passed as a VAR parameter because it is dimensioned inside the procedure. ---------------------------------------------------------------------- } var F : Text; { Data file } I, J : Integer; { Loop variable } begin Assign(F, FileName); Reset(F); Read(F, N); DimMatrix(A, N, N); for I := 1 to N do for J := 1 to N do Read(F, A^[I]^[J]); Close(F); end; procedure WriteNumber(Re, Im : Float); { ---------------------------------------------------------------------- Writes a real or complex number ---------------------------------------------------------------------- } begin Write(Re:12:6); if Im = 0.0 then WriteLn else if Im > 0.0 then WriteLn(' + ', Im:12:6, ' * i') else WriteLn(' - ', -Im:12:6, ' * i') end; procedure WriteEigenValue(Lambda : PCompVector; I : Integer); { ---------------------------------------------------------------------- Writes the I-th eigenvalue ---------------------------------------------------------------------- } begin WriteLn; Write('Eigenvalue: '); WriteNumber(Lambda^[I].X, Lambda^[I].Y); end; procedure WriteEigenVector(Lambda : PCompVector; V : PMatrix; N, I : Integer); { ---------------------------------------------------------------------- Writes the I-th eigenvector ---------------------------------------------------------------------- } var K : Integer; begin WriteLn; WriteLn('Eigenvector: '); WriteLn; if Lambda^[I].Y = 0.0 then { Eigenvector is in column I of V } for K := 1 to N do WriteNumber(V^[K]^[I], 0.0) else if Lambda^[I].Y > 0.0 then { Real and imag. parts of eigenvector are in columns I and (I+1) } for K := 1 to N do WriteNumber(V^[K]^[I], V^[K]^[I+1]) else { Conjugate of eigenvector is in columns (I-1) and I } for K := 1 to N do WriteNumber(V^[K]^[I-1], - V^[K]^[I]); end; begin ReadMatrix('matrix1.dat', A, N); DimCompVector(Lambda, N); DimMatrix(V, N, N); { Compute eigenvalues and eigenvectors (A is destroyed) } EigenVect(A, 1, N, Lambda, V); { Display results } if MathErr = 0 then for I := 1 to N do begin WriteEigenValue(Lambda, I); WriteEigenVector(Lambda, V, N, I); WriteLn; Write('Press <Enter> to continue...'); ReadLn; end else begin WriteLn('Unable to find eigenvalues Lambda[1] to Lambda[', -ErrCode, ']'); WriteLn('Eigenvalues Lambda[', 1 - ErrCode, '] to Lambda[', N, ']:'); for I := 1 - ErrCode to N do WriteEigenValue(Lambda, I); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/matrices/test_svd.pas����������������������������������0000755�0001750�0001750�00000004304�11326425444�022563� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program solves a system of linear equations (A * X = B) with a single constant vector by singular value decomposition. The system is stored in a data file with the following structure : Line 1 : dimension of the matrix (N) Following lines : first N columns = matrix last column = constant vector The file MATRIX3.DAT is an example data file with N = 4 ****************************************************************** } program test_svd; uses tpmath; procedure WriteMatrix(Title : String; A : PMatrix; N : Integer); var I, J : Integer; begin WriteLn(Title, ' :'); WriteLn; for I := 1 to N do begin for J := 1 to N do Write(A^[I]^[J]:12:6); WriteLn; end; WriteLn; end; procedure WriteVector(Title : String; V : PVector; N : Integer); var I : Integer; begin WriteLn(Title, ' :'); WriteLn; for I := 1 to N do WriteLn(V^[I]:12:6); WriteLn; end; var N : Integer; { Matrix dimension } A : PMatrix; { System matrix } B : PVector; { Constant vector } S : PVector; { Singular values } V : PMatrix; { Matrix from SVD } X : PVector; { Solution vector } F : Text; { Data file } I, J : Integer; { Loop variables } begin { Read matrix from file } Assign(F, 'matrix3.dat'); Reset(F); Read(F, N); DimMatrix(A, N, N); DimVector(B, N); for I := 1 to N do begin for J := 1 to N do Read(F, A^[I]^[J]); Read(F, B^[I]); end; Close(F); { Read and display data } WriteMatrix('System matrix', A, N); WriteVector('Constant vector', B, N); { Perform SV decomposition of A. If successful, solve system } DimVector(S, N); DimMatrix(V, N, N); SV_Decomp(A, 1, N, N, S, V); if MathErr = MatNonConv then begin WriteLn('Non-convergence!'); Halt; end; DimVector(X, N); SV_Solve(A, S, V, B, 1, N, N, X); WriteVector('Solution vector', X, N); end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/matrices/lineq1.pas������������������������������������0000755�0001750�0001750�00000004135�11326425444�022123� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program solves a system of linear equations (A * X = B) with a single constant vector by the Gauss-Jordan method. The system is stored in a data file with the following structure : Line 1 : dimension of the matrix (N) Following lines : first N columns = matrix last column = constant vector The file MATRIX3.DAT is an example data file with N = 4 ****************************************************************** } program lineq1; uses tpmath; procedure WriteMatrix(Title : String; A : PMatrix; N : Integer); var I, J : Integer; begin WriteLn(Title, ' :'); WriteLn; for I := 1 to N do begin for J := 1 to N do Write(A^[I]^[J]:12:6); WriteLn; end; WriteLn; end; procedure WriteVector(Title : String; V : PVector; N : Integer); var I : Integer; begin WriteLn(Title, ' :'); WriteLn; for I := 1 to N do WriteLn(V^[I]:12:6); WriteLn; end; var N : Integer; { Matrix dimension } A : PMatrix; { System matrix } B : PVector; { Constant vector } D : Float; { Determinant } F : Text; { Data file } I, J : Integer; { Loop variables } begin { Read matrix from file } Assign(F, 'matrix3.dat'); Reset(F); Read(F, N); DimMatrix(A, N, N); DimVector(B, N); for I := 1 to N do begin for J := 1 to N do Read(F, A^[I]^[J]); Read(F, B^[I]); end; Close(F); { Read and display data } WriteMatrix('System matrix', A, N); WriteVector('Constant vector', B, N); { Solve system } LinEq(A, B, 1, N, D); { Write results } case MathErr of MatOk : begin WriteMatrix('Inverse matrix', A, N); WriteVector('Solution vector', B, N); WriteLn('Determinant = ', D:12:6); end; MatSing : WriteLn('Singular matrix!'); end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/matrices/cholesk.pas�����������������������������������0000755�0001750�0001750�00000005446�11326425444�022370� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program computes the Cholesky factorization of a symmetric positive definite matrix. The matrix is stored in a data file with the following structure : Line 1 : dimension of the matrix (N) Lines 2 to (N + 1) : matrix The file MATRIX4.DAT is an example data file with N = 3 ****************************************************************** } program cholesk; uses tpmath; var A, L : PMatrix; { Matrix and its Cholesky factor } B : PMatrix; { Product L * L' } N : Integer; { Dimension of matrix } procedure ReadMatrix(FileName : String; var A : PMatrix; var N : Integer); { ------------------------------------------------------------------ Reads matrix from file. Note that A is passed as a VAR parameter because it is dimensioned inside the procedure. ------------------------------------------------------------------ } var F : Text; { Data file } I, J : Integer; { Loop variables } begin Assign(F, FileName); Reset(F); Read(F, N); DimMatrix(A, N, N); for I := 1 to N do for J := 1 to N do Read(F, A^[I]^[J]); Close(F); end; procedure WriteMatrix(Title : String; A : PMatrix; N : Integer); { ------------------------------------------------------------------ Writes matrix on screen ------------------------------------------------------------------ } var I, J : Integer; begin WriteLn(#10, Title, ' :', #10); for I := 1 to N do begin for J := 1 to N do Write(A^[I]^[J]:12:6); WriteLn; end; end; procedure MulMat(L : PMatrix; N : Integer; B : PMatrix); { ------------------------------------------------------------------ Computes the product B = L * L' ------------------------------------------------------------------ } var I, J, K : Integer; M : Float; begin for I := 1 to N do for J := 1 to I do begin M := 0.0; for K := 1 to J do M := M + L^[I]^[K] * L^[J]^[K]; B^[I]^[J] := M; if I <> J then B^[J]^[I] := M; end; end; begin { Read matrix A from file } ReadMatrix('matrix4.dat', A, N); WriteMatrix('Original matrix', A, N); { Dimension other matrices } DimMatrix(L, N, N); DimMatrix(B, N, N); { Perform Cholesky factorization, then compute the product L * L' which must be equal to the original matrix } Cholesky(A, L, 1, N); case MathErr of MatOk : begin WriteMatrix('Cholesky factor (L)', L, N); MulMat(L, N, B); WriteMatrix('Product L * L''', B, N); end; MatNotPD : Write('Matrix not positive definite'); end; WriteLn; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/matrices/test_lu.pas�����������������������������������0000755�0001750�0001750�00000004060�11326425444�022406� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program solves a system of linear equations (A * X = B) with a single constant vector by the LU decomposition method. The system is stored in a data file with the following structure : Line 1 : dimension of the matrix (N) Following lines : first N columns = matrix last column = constant vector The file MATRIX3.DAT is an example data file with N = 4 ****************************************************************** } program test_lu; uses tpmath; procedure WriteMatrix(Title : String; A : PMatrix; N : Integer); var I, J : Integer; begin WriteLn(Title, ' :'); WriteLn; for I := 1 to N do begin for J := 1 to N do Write(A^[I]^[J]:12:6); WriteLn; end; WriteLn; end; procedure WriteVector(Title : String; V : PVector; N : Integer); var I : Integer; begin WriteLn(Title, ' :'); WriteLn; for I := 1 to N do WriteLn(V^[I]:12:6); WriteLn; end; var N : Integer; { Matrix dimension } A : PMatrix; { System matrix } B : PVector; { Constant vector } X : PVector; { Solution vector } F : Text; { Data file } I, J : Integer; { Loop variables } begin { Read matrix from file } Assign(F, 'matrix3.dat'); Reset(F); Read(F, N); DimMatrix(A, N, N); DimVector(B, N); for I := 1 to N do begin for J := 1 to N do Read(F, A^[I]^[J]); Read(F, B^[I]); end; Close(F); { Read and display data } WriteMatrix('System matrix', A, N); WriteVector('Constant vector', B, N); { Perform LU decomposition of A. If successful, solve system } LU_Decomp(A, 1, N); if MathErr = MatSing then begin WriteLn('Singular matrix!'); Halt; end; DimVector(X, N); LU_Solve(A, B, 1, N, X); WriteVector('Solution vector', X, N); end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/matrices/eigenval.pas����������������������������������0000755�0001750�0001750�00000006044�11326425444�022525� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program computes the eigenvalues of a general square matrix (see EIGENSYM.PAS for a symmetric matrix). The matrix is stored in a data file with the following structure : Line 1 : dimension of the matrix (N) Lines 2 to (N + 1) : matrix The file MATRIX1.DAT is an example data file with N = 4 ****************************************************************** } program eigenval; uses tpmath; var A : PMatrix; { Matrix } N : Integer; { Dimension of matrix } Lambda : PCompVector; { Eigenvalues } I : Integer; { Loop variable } ErrCode : Integer; { Error code } procedure ReadMatrix(FileName : String; var A : PMatrix; var N : Integer); { ---------------------------------------------------------------------- Reads matrix from file. Note that A is passed as a VAR parameter because it is dimensioned inside the procedure. ---------------------------------------------------------------------- } var F : Text; { Data file } I, J : Integer; { Loop variable } begin Assign(F, FileName); Reset(F); Read(F, N); DimMatrix(A, N, N); for I := 1 to N do for J := 1 to N do Read(F, A^[I]^[J]); Close(F); end; procedure WriteMatrix(Title : String; A : PMatrix; N : Integer); { ---------------------------------------------------------------------- Writes matrix on screen ---------------------------------------------------------------------- } var I, J : Integer; begin WriteLn; WriteLn(Title, ':'); WriteLn; for I := 1 to N do begin for J := 1 to N do Write(A^[I]^[J]:12:6); WriteLn; end; WriteLn; end; procedure WriteEigenValue(Lambda : PCompVector; I : Integer); { ---------------------------------------------------------------------- Writes the I-th eigenvalue ---------------------------------------------------------------------- } begin if Lambda^[I].Y = 0.0 then WriteLn(Lambda^[I].X:12:6) else begin Write(Lambda^[I].X:12:6); if Lambda^[I].Y > 0.0 then Write(' + ') else Write(' - '); WriteLn(Abs(Lambda^[I].Y):12:6, ' * i'); end; end; begin { Read matrix from file } ReadMatrix('matrix1.dat', A, N); WriteMatrix('Original matrix', A, N); { Dimension the vector containing the eigenvalues } DimCompVector(Lambda, N); { Compute eigenvalues } EigenVals(A, 1, N, Lambda); ErrCode := MathErr; if ErrCode = 0 then begin WriteLn('Eigenvalues:'); WriteLn; for I := 1 to N do WriteEigenValue(Lambda, I); end else begin WriteLn('Unable to find eigenvalues Lambda[1] to Lambda[', -ErrCode, ']'); WriteLn('Eigenvalues Lambda[', 1 - ErrCode, '] to Lambda[', N, ']:'); for I := 1 - ErrCode to N do WriteEigenValue(Lambda, I); end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/matrices/test_qr.pas�����������������������������������0000755�0001750�0001750�00000004204�11326425444�022410� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program solves a system of linear equations (A * X = B) with a single constant vector by the QR decomposition method. The system is stored in a data file with the following structure : Line 1 : dimension of the matrix (N) Following lines : first N columns = matrix last column = constant vector The file MATRIX3.DAT is an example data file with N = 4 ****************************************************************** } program test_qr; uses tpmath; procedure WriteMatrix(Title : String; A : PMatrix; N : Integer); var I, J : Integer; begin WriteLn(Title, ' :'); WriteLn; for I := 1 to N do begin for J := 1 to N do Write(A^[I]^[J]:12:6); WriteLn; end; WriteLn; end; procedure WriteVector(Title : String; V : PVector; N : Integer); var I : Integer; begin WriteLn(Title, ' :'); WriteLn; for I := 1 to N do WriteLn(V^[I]:12:6); WriteLn; end; var N : Integer; { Matrix dimension } A : PMatrix; { System matrix } B : PVector; { Constant vector } R : PMatrix; { matrix from QR decomp. } X : PVector; { Solution vector } F : Text; { Data file } I, J : Integer; { Loop variables } begin { Read matrix from file } Assign(F, 'matrix3.dat'); Reset(F); Read(F, N); DimMatrix(A, N, N); DimVector(B, N); for I := 1 to N do begin for J := 1 to N do Read(F, A^[I]^[J]); Read(F, B^[I]); end; Close(F); { Read and display data } WriteMatrix('System matrix', A, N); WriteVector('Constant vector', B, N); { Perform QR decomposition of A. If successful, solve system } DimMatrix(R, N, N); QR_Decomp(A, 1, N, N, R); if MathErr = MatSing then begin WriteLn('Singular matrix!'); Halt; end; DimVector(X, N); QR_Solve(A, R, B, 1, N, N, X); WriteVector('Solution vector', X, N); end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/matrices/eigensym.pas����������������������������������0000755�0001750�0001750�00000007423�11326425444�022555� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program computes the eigenvalues and eigenvectors of a symmetric matrix by the iterative method of Jacobi. The method is demonstrated with Hilbert matrices. These matrices are ill-conditioned (i.e. the ratio of the lowest to the highest eigenvalue is very low). The Jacobi method applies a series of rotations to the original matrix in order to transform it into a diagonal matrix. The diagonal terms of this matrix are the eigenvalues. The product of the rotation matrices gives the eigenvectors. The original matrix is destroyed during the process. The parameter Tol defines the tolerance with which an off-diagonal element of the transformed matrix is considered zero (expressed as a fraction of the sum of squared diagonal terms). The parameter MaxIter defines the maximal number of iterations allowed. These two values are linked, i.e. decreasing Tol may need increasing MaxIter to avoid non-convergence of the Jacobi procedure. ****************************************************************** } program eigensym; uses tpmath; const MaxIter = 1000; { Maximum number of iterations } Tol = 1.0E-8; { Required precision } var N : Integer; { Size of matrix } A : PMatrix; { Matrix } Lambda : PVector; { Eigenvalues } V : PMatrix; { Eigenvectors } procedure Hilbert(A : PMatrix; N : Integer); { ------------------------------------------------------------------ Generates the Hilbert matrix of order N ( 1 1/2 1/3 1/4 ... 1/N ) ( 1/2 1/3 1/4 1/5 ... 1/(N+1) ) A = ( 1/3 1/4 1/5 1/6 ... 1/(N+2) ) ( ........................................... ) ( 1/N 1/(N+1) 1/(N+2) 1/(N+3) ... 1/(2N-1) ) ------------------------------------------------------------------ } var I, J : Integer; begin { First row of matrix } A^[1]^[1] := 1.0; for J := 2 to N do A^[1]^[J] := 1.0 / J; for I := 2 to N do begin { Last column of matrix } A^[I]^[N] := 1.0 / (N + I - 1); { Fill matrix } for J := 1 to N - 1 do A^[I]^[J] := A^[I - 1]^[J + 1]; end; end; procedure WriteResults(N : Integer; V : PMatrix; Lambda : PVector); { ------------------------------------------------------------------ Outputs results to screen ------------------------------------------------------------------ } var I, J : Integer; Ch : Char; begin WriteLn; WriteLn('Eigenvalues :'); WriteLn; for I := 1 to N do WriteLn(Lambda^[I]:26); if N < 8 then begin WriteLn; WriteLn('Eigenvectors (columns) :'); WriteLn; for I := 1 to N do begin for J := 1 to N do Write(V^[I]^[J]:10:6); WriteLn; end; end; end; begin repeat WriteLn; Write('Order of Hilbert matrix (1 to end) : '); ReadLn(N); if N > 1 then begin { Allocate vectors and matrices } DimMatrix(A, N, N); DimMatrix(V, N, N); DimVector(Lambda, N); { Generate Hilbert matrix of order N } Hilbert(A, N); { Compute eigenvalues and eigenvectors } Jacobi(A, 1, N, MaxIter, Tol, Lambda, V); case MathErr of MatOk : WriteResults(N, V, Lambda); MatNonConv : WriteLn('Too many iterations!'); end; { Deallocate vectors and matrices so that they may be redimensioned at the next iteration } DelMatrix(A, N, N); DelMatrix(V, N, N); DelVector(Lambda, N); end; until N < 2; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/demo/matrices/lineqm.pas������������������������������������0000755�0001750�0001750�00000004171�11326425444�022217� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** This program solves a system of linear equations (A * X = B) with several constant vectors by the Gauss-Jordan method. The system is stored in a data file with the following structure : Line 1 : size of matrix (N) and number of constant vectors (P) Following lines : first N columns = matrix other columns = constant vectors The file MATRIX2.DAT is an example data file with N = 4 and P = 5 ****************************************************************** } program lineqm; uses tpmath; procedure WriteMatrix(Title : String; A : PMatrix; N : Integer; Col1, Col2 : Integer); { ------------------------------------------------------------------ Writes a matrix from Col1 to Col2 ------------------------------------------------------------------ } var I, J : Integer; begin WriteLn(Title, ' :'); WriteLn; for I := 1 to N do begin for J := Col1 to Col2 do Write(A^[I]^[J]:12:6); WriteLn; end; WriteLn; end; var A : PMatrix; { System matrix } N, M : Integer; { Matrix dimensions } D : Float; { Determinant } F : Text; { Data file } I, J : Integer; { Loop variables } begin { Read matrix from file } Assign(F, 'matrix2.dat'); Reset(F); Read(F, N, M); DimMatrix(A, N, M); for I := 1 to N do for J := 1 to M do Read(F, A^[I]^[J]); Close(F); { Read and display data } WriteMatrix('System matrix', A, N, 1, N); WriteMatrix('Constant vectors', A, N, N + 1, M); { Solve system } GaussJordan(A, 1, N, M, D); { Write results } case MathErr of MatOk : begin WriteMatrix('Inverse matrix', A, N, 1, N); WriteMatrix('Solution vectors', A, N, N + 1, M); WriteLn('Determinant = ', D:12:6); end; MatSing : WriteLn('Singular matrix!'); MatErrDim : WriteLn('Non-compatible dimensions!'); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/umulfit.pas�������������������������������������������������0000755�0001750�0001750�00000012451�11326425446�017666� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Multiple linear regression (Gauss-Jordan method) ****************************************************************** } unit umulfit; interface uses utypes, ulineq; procedure MulFit(X : PMatrix; Y : PVector; Lb, Ub, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix); { ------------------------------------------------------------------ Multiple linear regression: Y = B(0) + B(1) * X + B(2) * X2 + ... ------------------------------------------------------------------ Input parameters: X = matrix of independent variables Y = vector of dependent variable Lb, Ub = array bounds Nvar = number of independent variables ConsTerm = presence of constant term B(0) Output parameters: B = regression parameters V = inverse matrix ------------------------------------------------------------------ } procedure WMulFit(X : PMatrix; Y, S : PVector; Lb, Ub, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix); { ---------------------------------------------------------------------- Weighted multiple linear regression ---------------------------------------------------------------------- S = standard deviations of observations Other parameters as in MulFit ---------------------------------------------------------------------- } implementation procedure MulFit(X : PMatrix; Y : PVector; Lb, Ub, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix); var Lb1 : Integer; { Index of first param. (0 if cst term, 1 otherwise) } I, J, K : Integer; { Loop variables } Det : Float; { Determinant } begin if Ub - Lb < Nvar then begin SetErrCode(MatErrDim); Exit; end; { Initialize } for I := 0 to Nvar do begin for J := 0 to Nvar do V^[I]^[J] := 0.0; B^[I] := 0.0; end; { If constant term, set line 0 and column 0 of matrix V } if ConsTerm then begin V^[0]^[0] := Int(Ub - Lb + 1); for K := Lb to Ub do begin for J := 1 to Nvar do V^[0]^[J] := V^[0]^[J] + X^[K]^[J]; B^[0] := B^[0] + Y^[K]; end; for J := 1 to Nvar do V^[J]^[0] := V^[0]^[J]; end; { Set other elements of V } for K := Lb to Ub do for I := 1 to Nvar do begin for J := I to Nvar do V^[I]^[J] := V^[I]^[J] + X^[K]^[I] * X^[K]^[J]; B^[I] := B^[I] + X^[K]^[I] * Y^[K]; end; { Fill in symmetric matrix } for I := 2 to Nvar do for J := 1 to Pred(I) do V^[I]^[J] := V^[J]^[I]; { Solve normal equations } if ConsTerm then Lb1 := 0 else Lb1 := 1; LinEq(V, B, Lb1, Nvar, Det); end; procedure WMulFit(X : PMatrix; Y, S : PVector; Lb, Ub, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix); var Lb1 : Integer; { Index of first param. (0 if cst term, 1 otherwise) } I, J, K : Integer; { Loop variables } W : PVector; { Vector of weights } WX : Float; { W * X } Det : Float; { Determinant } begin if Ub - Lb < Nvar then begin SetErrCode(MatErrDim); Exit; end; for K := Lb to Ub do if S^[K] <= 0.0 then begin SetErrCode(MatSing); Exit; end; DimVector(W, Ub); for K := Lb to Ub do W^[K] := 1.0 / Sqr(S^[K]); { Initialize } for I := 0 to Nvar do begin for J := 0 to Nvar do V^[I]^[J] := 0.0; B^[I] := 0.0; end; { If constant term, set line 0 and column 0 of matrix V } if ConsTerm then begin for K := Lb to Ub do begin V^[0]^[0] := V^[0]^[0] + W^[K]; for J := 1 to Nvar do V^[0]^[J] := V^[0]^[J] + W^[K] * X^[K]^[J]; B^[0] := B^[0] + W^[K] * Y^[K]; end; for J := 1 to Nvar do V^[J]^[0] := V^[0]^[J]; end; { Set other elements of V } for K := Lb to Ub do for I := 1 to Nvar do begin WX := W^[K] * X^[K]^[I]; for J := I to Nvar do V^[I]^[J] := V^[I]^[J] + WX * X^[K]^[J]; B^[I] := B^[I] + WX * Y^[K]; end; { Fill in symmetric matrix } for I := 2 to Nvar do for J := 1 to Pred(I) do V^[I]^[J] := V^[J]^[I]; { Solve normal equations } if ConsTerm then Lb1 := 0 else Lb1 := 1; LinEq(V, B, Lb1, Nvar, Det); DelVector(W, Ub); end; end.�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/upca.pas����������������������������������������������������0000755�0001750�0001750�00000017055�11326425446�017136� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Principal component analysis ****************************************************************** } unit upca; interface uses utypes, ujacobi; procedure VecMean(X : PMatrix; Lb, Ub, Nvar : Integer; M : PVector); { ---------------------------------------------------------------------- Computes the mean vector (M) from matrix X ---------------------------------------------------------------------- Input : X[Lb..Ub, 1..Nvar] = matrix of variables Output : M[1..Nvar] = mean vector ---------------------------------------------------------------------- } procedure VecSD(X : PMatrix; Lb, Ub, Nvar : Integer; M, S : PVector); { ---------------------------------------------------------------------- Computes the vector of standard deviations (S) from matrix X ---------------------------------------------------------------------- Input : X, Lb, Ub, Nvar, M Output : S[1..Nvar] ---------------------------------------------------------------------- } procedure MatVarCov(X : PMatrix; Lb, Ub, Nvar : Integer; M : PVector; V : PMatrix); { ---------------------------------------------------------------------- Computes the variance-covariance matrix (V) from matrix X Input : X, Lb, Ub, Nvar, M Output : V[1..Nvar, 1..Nvar] ---------------------------------------------------------------------- } procedure MatCorrel(V : PMatrix; Nvar : Integer; R : PMatrix); { ---------------------------------------------------------------------- Computes the correlation matrix (R) from the variance-covariance matrix (V) Input : V, Nvar Output : R[1..Nvar, 1..Nvar] ---------------------------------------------------------------------- } procedure PCA(R : PMatrix; Nvar : Integer; MaxIter : Integer; Tol : Float; Lambda : PVector; C, Rc : PMatrix); { ---------------------------------------------------------------------- Performs a principal component analysis of the correlation matrix R ---------------------------------------------------------------------- Input : R[1..Nvar] = Correlation matrix MaxIter = Max. number of iterations Tol = Required precision Output : Lambda[1..Nvar] = Eigenvalues of the correlation matrix (in descending order) C[1..Nvar, 1..Nvar] = Eigenvectors of the correlation matrix (stored as columns) Rc[1..Nvar, 1..Nvar] = Correlations between principal factors and variables (Rc^[I]^[J] is the correlation coefficient between variable I and factor J) ---------------------------------------------------------------------- NB : This procedure destroys the original matrix R ---------------------------------------------------------------------- } procedure ScaleVar(X : PMatrix; Lb, Ub, Nvar : Integer; M, S : PVector; Z : PMatrix); { ---------------------------------------------------------------------- Scales a set of variables by subtracting means and dividing by SD's ---------------------------------------------------------------------- Input : X, Lb, Ub, Nvar, M, S Output : Z[Lb..Ub, 1..Nvar] = matrix of scaled variables ---------------------------------------------------------------------- } procedure PrinFac(Z : PMatrix; Lb, Ub, Nvar : Integer; C, F : PMatrix); { ---------------------------------------------------------------------- Computes principal factors ---------------------------------------------------------------------- Input : Z[Lb..Ub, 1..Nvar] = matrix of scaled variables C[1..Nvar, 1..Nvar] = matrix of eigenvectors from PCA Output : F[Lb..Ub, 1..Nvar] = matrix of principal factors ---------------------------------------------------------------------- } implementation procedure VecMean(X : PMatrix; Lb, Ub, Nvar : Integer; M : PVector); var I, K, Nobs : Integer; Sum : Float; begin Nobs := Ub - Lb + 1; for I := 1 to Nvar do begin Sum := 0.0; for K := Lb to Ub do Sum := Sum + X^[K]^[I]; M^[I] := Sum / Nobs; end; end; procedure VecSD(X : PMatrix; Lb, Ub, Nvar : Integer; M, S : PVector); var I, K, Nobs : Integer; Sum : Float; begin Nobs := Ub - Lb + 1; for I := 1 to Nvar do begin Sum := 0.0; for K := Lb to Ub do Sum := Sum + Sqr(X^[K]^[I] - M^[I]); S^[I] := Sqrt(Sum / Nobs); end; end; procedure MatVarCov(X : PMatrix; Lb, Ub, Nvar : Integer; M : PVector; V : PMatrix); var I, J, K, Nobs : Integer; Sum : Float; begin Nobs := Ub - Lb + 1; for I := 1 to Nvar do for J := I to Nvar do begin Sum := 0.0; for K := Lb to Ub do Sum := Sum + (X^[K]^[I] - M^[I]) * (X^[K]^[J] - M^[J]); V^[I]^[J] := Sum / Nobs; end; for I := 2 to Nvar do for J := 1 to Pred(I) do V^[I]^[J] := V^[J]^[I]; end; procedure MatCorrel(V : PMatrix; Nvar : Integer; R : PMatrix); var I, J : Integer; P : Float; begin for I := 1 to Nvar do begin R^[I]^[I] := 1.0; for J := Succ(I) to Nvar do begin P := V^[I]^[I] * V^[J]^[J]; if P > 0.0 then R^[I]^[J] := V^[I]^[J] / Sqrt(P) else R^[I]^[J] := 0.0; R^[J]^[I] := R^[I]^[J]; end; end; end; procedure PCA(R : PMatrix; Nvar : Integer; MaxIter : Integer; Tol : Float; Lambda : PVector; C, Rc : PMatrix); var I, J : Integer; Rac : Float; begin { Compute eigenvalues and eigenvectors of correlation matrix } Jacobi(R, 1, Nvar, MaxIter, Tol, Lambda, C); if MathErr <> MatOk then Exit; { Compute correlations between principal factors and reduced variables } for J := 1 to Nvar do begin Rac := Sqrt(Lambda^[J]); for I := 1 to Nvar do Rc^[I]^[J] := C^[I]^[J] * Rac; end; end; procedure ScaleVar(X : PMatrix; Lb, Ub, Nvar : Integer; M, S : PVector; Z : PMatrix); var I, J : Integer; begin for I := Lb to Ub do for J := 1 to Nvar do Z^[I]^[J] := (X^[I]^[J] - M^[J]) / S^[J]; end; procedure PrinFac(Z : PMatrix; Lb, Ub, Nvar : Integer; C, F : PMatrix); var I, J, K : Integer; begin for I := Lb to Ub do for J := 1 to Nvar do begin F^[I]^[J] := 0.0; for K := 1 to Nvar do F^[I]^[J] := F^[I]^[J] + Z^[I]^[K] * C^[K]^[J]; end; end; end.�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/upolutil.pas������������������������������������������������0000755�0001750�0001750�00000005661�11326425446�020063� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Utility functions to handle roots of polynomials ****************************************************************** } unit upolutil; interface uses utypes, uminmax; function SetRealRoots(Deg : Integer; Z : PCompVector; Tol : Float) : Integer; { ------------------------------------------------------------------ Set the imaginary part of a root to zero if it is less than a fraction Tol of its real part. This root is therefore considered real. The function returns the total number of real roots. ------------------------------------------------------------------ } procedure SortRoots(Deg : Integer; Z : PCompVector); { ------------------------------------------------------------------ Sort roots so that: (1) The Nr real roots are stored in elements [1..Nr] of vector Z, in increasing order. (2) The complex roots are stored in elements [(Nr + 1)..Deg] of vector Z and are unordered. ------------------------------------------------------------------ } implementation function SetRealRoots(Deg : Integer; Z : PCompVector; Tol : Float) : Integer; var I, N : Integer; begin for I := 1 to Deg do if (Z^[I].Y <> 0.0) and (Abs(Z^[I].Y) < Tol * Abs(Z^[I].X)) then Z^[I].Y := 0.0; { Count real roots } N := 0; for I := 1 to Deg do if Z^[I].Y = 0.0 then Inc(N); SetRealRoots := N; end; procedure SortRoots(Deg : Integer; Z : PCompVector); var I, J, K, Nr, Nc : Integer; R, X, Y : PVector; procedure Sort(X : PVector; N : Integer); { Sort vector X (insertion sort) } var I, J, K : Integer; A : Float; begin for I := 1 to Pred(N) do begin K := I; A := X^[I]; for J := Succ(I) to N do if X^[J] < A then begin K := J; A := X^[J]; end; FSwap(X^[I], X^[K]); end; end; begin { Count real and complex roots } Nr := 0; Nc := 0; for I := 1 to Deg do if Z^[I].Y = 0.0 then Inc(Nr) else Inc(Nc); DimVector(R, Nr); DimVector(X, Nc); DimVector(Y, Nc); { Store real roots in R and complex roots in (X,Y) } J := 0; K := 0; for I := 1 to Deg do if Z^[I].Y = 0.0 then begin Inc(J); R^[J] := Z^[I].X; end else begin Inc(K); X^[K] := Z^[I].X; Y^[K] := Z^[I].Y; end; { Sort vector R (insertion sort) } if Nr > 0 then Sort(R, Nr); { Transfer real roots into elements 1..Nr } for I := 1 to Nr do begin Z^[I].X := R^[I]; Z^[I].Y := 0.0; end; { Transfer complex roots into elements (Nr+1)..Deg } for I := 1 to Nc do begin J := I + Nr; Z^[J].X := X^[I]; Z^[J].Y := Y^[I]; end; DelVector(R, Nr); DelVector(X, Nc); DelVector(Y, Nc); end; end. �������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/usnedeco.pas������������������������������������������������0000755�0001750�0001750�00000002614�11326425446�020006� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Snedecor's F-test (comparison of two variances) ****************************************************************** } unit usnedeco; interface uses utypes; procedure Snedecor(N1, N2 : Integer; S1, S2 : Float; var F : Float; var DoF1, DoF2 : Integer); { ------------------------------------------------------------------ Snedecor's F-test (comparison of two variances) ------------------------------------------------------------------ Input parameters : N1, N2 = samples sizes S1, S2 = samples SD's (computed with StDev) Output parameters: F = Snedecor's F DoF1, DoF2 = degrees of freedom ------------------------------------------------------------------ } implementation procedure Snedecor(N1, N2 : Integer; S1, S2 : Float; var F : Float; var DoF1, DoF2 : Integer); var V1, V2 : Float; { Sample variances } begin V1 := Sqr(S1); V2 := Sqr(S2); if V1 > V2 then begin F := V1 / V2; DoF1 := N1 - 1; DoF2 := N2 - 1; end else begin F := V2 / V1; DoF1 := N2 - 1; DoF2 := N1 - 1; end; end; end.��������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uinterv.pas�������������������������������������������������0000755�0001750�0001750�00000003254�11326425444�017674� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Compute an appropriate interval for a set of values ****************************************************************** } unit uinterv; interface uses utypes, umath; procedure Interval(X1, X2 : Float; MinDiv, MaxDiv : Integer; var Min, Max, Step : Float); { ------------------------------------------------------------------ Determines an interval [Min, Max] including the values from X1 to X2, and a subdivision Step of this interval ------------------------------------------------------------------ Input parameters : X1, X2 = min. & max. values to be included MinDiv = minimum nb of subdivisions MaxDiv = maximum nb of subdivisions ------------------------------------------------------------------ Output parameters : Min, Max, Step ------------------------------------------------------------------ } implementation procedure Interval(X1, X2 : Float; MinDiv, MaxDiv : Integer; var Min, Max, Step : Float); var H, R, K : Float; begin if X1 >= X2 then Exit; H := X2 - X1; R := Int(Log10(H)); if H < 1.0 then R := R - 1.0; Step := Exp10(R); repeat K := Int(H / Step); if K < MinDiv then Step := 0.5 * Step; if K > MaxDiv then Step := 2.0 * Step; until (K >= MinDiv) and (K <= MaxDiv); Min := Step * Int(X1 / Step); Max := Step * Int(X2 / Step); while Min > X1 do Min := Min - Step; while Max < X2 do Max := Max + Step; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ulinfit.pas�������������������������������������������������0000755�0001750�0001750�00000006376�11326425444�017662� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Linear regression : Y = B(0) + B(1) * X ****************************************************************** } unit ulinfit; interface uses utypes; procedure LinFit(X, Y : PVector; Lb, Ub : Integer; B : PVector; V : PMatrix); { ------------------------------------------------------------------ Unweighted linear regression ------------------------------------------------------------------ Input parameters: X, Y = point coordinates Lb, Ub = array bounds Output parameters: B = regression parameters V = inverse matrix ------------------------------------------------------------------ } procedure WLinFit(X, Y, S : PVector; Lb, Ub : Integer; B : PVector; V : PMatrix); { ------------------------------------------------------------------ Weighted linear regression ------------------------------------------------------------------ Additional input parameter: S = standard deviations of observations ------------------------------------------------------------------ } implementation procedure LinFit(X, Y : PVector; Lb, Ub : Integer; B : PVector; V : PMatrix); var SX, SY, SX2, SXY, D : Float; K, N : Integer; begin N := Ub - Lb + 1; SX := 0.0; SY := 0.0; SX2 := 0.0; SXY := 0.0; for K := Lb to Ub do begin SX := SX + X^[K]; SY := SY + Y^[K]; SX2 := SX2 + Sqr(X^[K]); SXY := SXY + X^[K] * Y^[K]; end; D := N * SX2 - Sqr(SX); if D <= 0.0 then begin SetErrCode(MatSing); Exit; end; SetErrCode(MatOk); V^[0]^[0] := SX2 / D; V^[0]^[1] := - SX / D; V^[1]^[0] := V^[0]^[1]; V^[1]^[1] := N / D; B^[0] := V^[0]^[0] * SY + V^[0]^[1] * SXY; B^[1] := V^[1]^[0] * SY + V^[1]^[1] * SXY; end; procedure WLinFit(X, Y, S : PVector; Lb, Ub : Integer; B : PVector; V : PMatrix); var W, WX, SW, SWX, SWY, SWX2, SWXY, D : Float; K : Integer; begin SW := 0.0; SWX := 0.0; SWY := 0.0; SWX2 := 0.0; SWXY := 0.0; for K := Lb to Ub do begin if S^[K] <= 0.0 then begin SetErrCode(MatSing); Exit; end; W := 1.0 / Sqr(S^[K]); WX := W * X^[K]; SW := SW + W; SWX := SWX + WX; SWY := SWY + W * Y^[K]; SWX2 := SWX2 + WX * X^[K]; SWXY := SWXY + WX * Y^[K]; end; D := SW * SWX2 - Sqr(SWX); if D <= 0.0 then begin SetErrCode(MatSing); Exit; end; SetErrCode(MatOk); V^[0]^[0] := SWX2 / D; V^[0]^[1] := - SWX / D; V^[1]^[0] := V^[0]^[1]; V^[1]^[1] := SW / D; B^[0] := V^[0]^[0] * SWY + V^[0]^[1] * SWXY; B^[1] := V^[1]^[0] * SWY + V^[1]^[1] * SWXY; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ugamdist.pas������������������������������������������������0000755�0001750�0001750�00000006376�11326425444�020025� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Probability functions related to the Gamma function ****************************************************************** } unit ugamdist; interface uses utypes, ugamma; function DBeta(A, B, X : Float) : Float; { Density of Beta distribution with parameters A and B } function DGamma(A, B, X : Float) : Float; { Density of Gamma distribution with parameters A and B } function DKhi2(Nu : Integer; X : Float) : Float; { Density of Khi-2 distribution with Nu d.o.f. } function DStudent(Nu : Integer; X : Float) : Float; { Density of Student distribution with Nu d.o.f. } function DSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; { Density of Fisher-Snedecor distribution with Nu1 and Nu2 d.o.f. } implementation function DBeta(A, B, X : Float) : Float; var L : Float; begin if (A <= 0.0) or (B <= 0.0) or (X < 0.0) or (X > 1.0) then begin DBeta := DefaultVal(FDomain, 0.0); Exit; end; if X = 0.0 then begin if A < 1.0 then DBeta := DefaultVal(FSing, MaxNum) else DBeta := DefaultVal(FOk, 0.0); Exit; end; if X = 1.0 then begin if B < 1.0 then DBeta := DefaultVal(FSing, MaxNum) else DBeta := DefaultVal(FOk, 0.0); Exit; end; L := LnGamma(A + B) - LnGamma(A) - LnGamma(B) + (A - 1.0) * Ln(X) + (B - 1.0) * Ln(1.0 - X); if L < MinLog then DBeta := DefaultVal(FUnderflow, 0.0) else DBeta := DefaultVal(FOk, Exp(L)); end; function DGamma(A, B, X : Float) : Float; var L : Float; begin if (A <= 0.0) or (B <= 0.0) or (X < 0.0) then begin DGamma := DefaultVal(FDomain, 0.0); Exit; end; if X = 0.0 then begin if A < 1.0 then DGamma := DefaultVal(FSing, MaxNum) else if A = 1.0 then DGamma := DefaultVal(FOk, B) else DGamma := DefaultVal(FOk, 0.0); Exit; end; L := A * Ln(B) - LnGamma(A) + (A - 1.0) * Ln(X) - B * X; if L < MinLog then DGamma := DefaultVal(FUnderflow, 0.0) else DGamma := DefaultVal(FOk, Exp(L)); end; function DKhi2(Nu : Integer; X : Float) : Float; begin DKhi2 := DGamma(0.5 * Nu, 0.5, X) end; function DStudent(Nu : Integer; X : Float) : Float; var L, P, Q : Float; begin if Nu < 1 then begin DStudent := DefaultVal(FDomain, 0.0); Exit; end; P := 0.5 * (Nu + 1); Q := 0.5 * Nu; L := LnGamma(P) - LnGamma(Q) - 0.5 * Ln(Nu * Pi) - P * Ln(1.0 + X * X / Nu); if L < MinLog then DStudent := DefaultVal(FUnderflow, 0.0) else DStudent := DefaultVal(FOk, Exp(L)); end; function DSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; var L, P1, P2, R, S : Float; begin if (Nu1 < 1) or (Nu2 < 1) or (X <= 0.0) then begin DSnedecor := DefaultVal(FDomain, 0.0); Exit; end; R := Nu1 / Nu2; P1 := 0.5 * Nu1; P2 := 0.5 * Nu2; S := P1 + P2; L := LnGamma(S) - LnGamma(P1) - LnGamma(P2) + P1 * Ln(R) + (P1 - 1.0) * Ln(X) - S * Ln(1.0 + R * X); if L < MinLog then DSnedecor := DefaultVal(FUnderflow, 0.0) else DSnedecor := DefaultVal(FOk, Exp(L)); end; end.������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ulu.pas�����������������������������������������������������0000755�0001750�0001750�00000011317�11326425444�017004� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** LU decomposition ****************************************************************** } unit ulu; interface uses utypes, uminmax; procedure LU_Decomp(A : PMatrix; Lb, Ub : Integer); { ---------------------------------------------------------------------- LU decomposition. Factors the square matrix A as a product L * U, where L is a lower triangular matrix (with unit diagonal terms) and U is an upper triangular matrix. This routine is used in conjunction with LU_Solve to solve a system of equations. ---------------------------------------------------------------------- Input parameters : A = matrix Lb = index of first matrix element Ub = index of last matrix element ---------------------------------------------------------------------- Output parameter : A = contains the elements of L and U ---------------------------------------------------------------------- Possible results : MatOk MatSing ---------------------------------------------------------------------- NB : This procedure destroys the original matrix A ---------------------------------------------------------------------- } procedure LU_Solve(A : PMatrix; B : PVector; Lb, Ub : Integer; X : PVector); { ---------------------------------------------------------------------- Solves a system of equations whose matrix has been transformed by LU_Decomp ---------------------------------------------------------------------- Input parameters : A = result from LU_Decomp B = constant vector Lb, Ub = as in LU_Decomp ---------------------------------------------------------------------- Output parameter : X = solution vector ---------------------------------------------------------------------- } implementation const InitDim : Integer = 0; { Initial vector size } Index : PIntVector = nil; { Records the row permutations } procedure LU_Decomp(A : PMatrix; Lb, Ub : Integer); var I, Imax, J, K : Integer; Pvt, T, Sum : Float; V : PVector; begin { Reallocate Index if necessary} if Ub > InitDim then begin DelIntVector(Index, InitDim); DimIntVector(Index, Ub); InitDim := Ub; end; DimVector(V, Ub); for I := Lb to Ub do begin Pvt := 0.0; for J := Lb to Ub do if Abs(A^[I]^[J]) > Pvt then Pvt := Abs(A^[I]^[J]); if Pvt < MachEp then begin DelVector(V, Ub); SetErrCode(MatSing); Exit; end; V^[I] := 1.0 / Pvt; end; for J := Lb to Ub do begin for I := Lb to Pred(J) do begin Sum := A^[I]^[J]; for K := Lb to Pred(I) do Sum := Sum - A^[I]^[K] * A^[K]^[J]; A^[I]^[J] := Sum; end; Imax := 0; Pvt := 0.0; for I := J to Ub do begin Sum := A^[I]^[J]; for K := Lb to Pred(J) do Sum := Sum - A^[I]^[K] * A^[K]^[J]; A^[I]^[J] := Sum; T := V^[I] * Abs(Sum); if T > Pvt then begin Pvt := T; Imax := I; end; end; if J <> Imax then begin for K := Lb to Ub do FSwap(A^[Imax]^[K], A^[J]^[K]); V^[Imax] := V^[J]; end; Index^[J] := Imax; if A^[J]^[J] = 0.0 then A^[J]^[J] := MachEp; if J <> Ub then begin T := 1.0 / A^[J]^[J]; for I := Succ(J) to Ub do A^[I]^[J] := A^[I]^[J] * T; end; end; DelVector(V, Ub); SetErrCode(MatOk); end; procedure LU_Solve(A : PMatrix; B : PVector; Lb, Ub : Integer; X : PVector); var I, Ip, J, K : Integer; Sum : Float; begin for I := Lb to Ub do X^[I] := B^[I]; K := Pred(Lb); for I := Lb to Ub do begin Ip := Index^[I]; Sum := X^[Ip]; X^[Ip] := X^[I]; if K >= Lb then for J := K to Pred(I) do Sum := Sum - A^[I]^[J] * X^[J] else if Sum <> 0.0 then K := I; X^[I] := Sum; end; for I := Ub downto Lb do begin Sum := X^[I]; if I < Ub then for J := Succ(I) to Ub do Sum := Sum - A^[I]^[J] * X^[J]; X^[I] := Sum / A^[I]^[I]; end; end; end.�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ubalbak.pas�������������������������������������������������0000755�0001750�0001750�00000005021�11326425444�017573� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Back transformation of eigenvectors ****************************************************************** } unit ubalbak; interface uses utypes; procedure BalBak(Z : PMatrix; Lb, Ub, I_low, I_igh : Integer; Scale : PVector; M : Integer); implementation procedure BalBak(Z : PMatrix; Lb, Ub, I_low, I_igh : Integer; Scale : PVector; M : Integer); { ------------------------------------------------------------------ This procedure is a translation of the EISPACK subroutine Balbak This procedure forms the eigenvectors of a real general matrix by back transforming those of the corresponding balanced matrix determined by Balance. On input: Z contains the real and imaginary parts of the eigenvectors to be back transformed. Lb, Ub are the lowest and highest indices of the elements of Z I_low and I_igh are integers determined by Balance. Scale contains information determining the permutations and scaling factors used by Balance. M is the index of the latest column of Z to be back transformed. On output: Z contains the real and imaginary parts of the transformed eigenvectors in its columns Lb..M ------------------------------------------------------------------ } var I, J, K : Integer; S : Float; begin if M < Lb then Exit; if I_igh <> I_low then for I := I_low to I_igh do begin S := Scale^[I]; { Left hand eigenvectors are back transformed if the foregoing statement is replaced by S := 1.0 / Scale^[I] } for J := Lb to M do Z^[I]^[J] := Z^[I]^[J] * S; end; for I := (I_low - 1) downto Lb do begin K := Round(Scale^[I]); if K <> I then for J := Lb to M do begin S := Z^[I]^[J]; Z^[I]^[J] := Z^[K]^[J]; Z^[K]^[J] := S; end; end; for I := (I_igh + 1) to Ub do begin K := Round(Scale^[I]); if K <> I then for J := Lb to M do begin S := Z^[I]^[J]; Z^[I]^[J] := Z^[K]^[J]; Z^[K]^[J] := S; end; end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/urtpol1.pas�������������������������������������������������0000755�0001750�0001750�00000001646�11326425446�017613� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Linear equation ****************************************************************** } unit urtpol1; interface uses utypes; function RootPol1(A, B : Float; var X : Float) : Integer; { ------------------------------------------------------------------ Solves the linear equation A + B * X = 0 Returns 1 if no error (B <> 0) -1 if X is undetermined (A = B = 0) -2 if no solution (A <> 0, B = 0) ------------------------------------------------------------------ } implementation function RootPol1(A, B : Float; var X : Float) : Integer; begin X := 0.0; if B <> 0.0 then begin if A <> 0.0 then X := - A / B; RootPol1 := 1; Exit; end; if A = 0.0 then { 0 + 0X = 0 } RootPol1 := - 1 else { A + 0X = 0 } RootPol1 := - 2; end; end. ������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/types.inc���������������������������������������������������0000755�0001750�0001750�00000022073�11050364714�017326� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ------------------------------------------------------------------ Floating point type (Default = Double) ------------------------------------------------------------------ } {$IFDEF SINGLEREAL} type Float = Single; {$ELSE} {$IFDEF EXTENDEDREAL} type Float = Extended; {$ELSE} {$DEFINE DOUBLEREAL} type Float = Double; {$ENDIF} {$ENDIF} { ------------------------------------------------------------------ Mathematical constants ------------------------------------------------------------------ } const Pi = 3.14159265358979323846; { Pi } Ln2 = 0.69314718055994530942; { Ln(2) } Ln10 = 2.30258509299404568402; { Ln(10) } LnPi = 1.14472988584940017414; { Ln(Pi) } InvLn2 = 1.44269504088896340736; { 1/Ln(2) } InvLn10 = 0.43429448190325182765; { 1/Ln(10) } TwoPi = 6.28318530717958647693; { 2*Pi } PiDiv2 = 1.57079632679489661923; { Pi/2 } SqrtPi = 1.77245385090551602730; { Sqrt(Pi) } Sqrt2Pi = 2.50662827463100050242; { Sqrt(2*Pi) } InvSqrt2Pi = 0.39894228040143267794; { 1/Sqrt(2*Pi) } LnSqrt2Pi = 0.91893853320467274178; { Ln(Sqrt(2*Pi)) } Ln2PiDiv2 = 0.91893853320467274178; { Ln(2*Pi)/2 } Sqrt2 = 1.41421356237309504880; { Sqrt(2) } Sqrt2Div2 = 0.70710678118654752440; { Sqrt(2)/2 } Gold = 1.61803398874989484821; { Golden Mean = (1 + Sqrt(5))/2 } CGold = 0.38196601125010515179; { 2 - GOLD } { ------------------------------------------------------------------ Machine-dependent constants ------------------------------------------------------------------ } {$IFDEF SINGLEREAL} const MachEp = 1.192093E-7; { Floating point precision: 2^(-23) } MaxNum = 3.402823E+38; { Max. floating point number: 2^128 } MinNum = 1.175495E-38; { Min. floating point number: 2^(-126) } MaxLog = 88.72283; { Max. argument for Exp = Ln(MaxNum) } MinLog = -87.33655; { Min. argument for Exp = Ln(MinNum) } MaxFac = 33; { Max. argument for Factorial } MaxGam = 34.648; { Max. argument for Gamma } MaxLgm = 1.0383E+36; { Max. argument for LnGamma } {$ENDIF} {$IFDEF DOUBLEREAL} const MachEp = 2.220446049250313E-16; { 2^(-52) } MaxNum = 1.797693134862315E+308; { 2^1024 } MinNum = 2.225073858507202E-308; { 2^(-1022) } MaxLog = 709.7827128933840; MinLog = -708.3964185322641; MaxFac = 170; MaxGam = 171.624376956302; MaxLgm = 2.556348E+305; {$ENDIF} {$IFDEF EXTENDEDREAL} const MachEp = 1.08420217248550444E-19; { 2^(-63) } MaxNum = 5.9486574767861588254E+4931; { 2^16383 } MinNum = 6.7242062862241870125E-4932; { 2^(-16381) } MaxLog = 11355.830259113584004; MinLog = -11354.443964752464114; MaxFac = 1754; MaxGam = 1755.455; MaxLgm = 1.04848146839019521E+4928; {$ENDIF} { ------------------------------------------------------------------ Error codes for mathematical functions ------------------------------------------------------------------ } const FOk = 0; { No error } FDomain = - 1; { Argument domain error } FSing = - 2; { Function singularity } FOverflow = - 3; { Overflow range error } FUnderflow = - 4; { Underflow range error } FTLoss = - 5; { Total loss of precision } FPLoss = - 6; { Partial loss of precision } { ------------------------------------------------------------------ Error codes for matrix computations ------------------------------------------------------------------ } const MatOk = 0; { No error } MatNonConv = -1; { Non-convergence } MatSing = -2; { Quasi-singular matrix } MatErrDim = -3; { Non-compatible dimensions } MatNotPD = -4; { Matrix not positive definite } { ------------------------------------------------------------------ Error codes for optimization and nonlinear equations ------------------------------------------------------------------ } const OptOk = 0; { No error } OptNonConv = -1; { Non-convergence } OptSing = -2; { Quasi-singular hessian matrix } OptBigLambda = -5; { Too high Marquardt parameter } { ------------------------------------------------------------------ Error codes for nonlinear regression ------------------------------------------------------------------ } const NLMaxPar = -6; { Max. number of parameters exceeded } { ------------------------------------------------------------------ Complex numbers ------------------------------------------------------------------ } type Complex = record X, Y : Float; end; { ------------------------------------------------------------------ Vectors and matrices. ------------------------------------------------------------------ } const { Maximal array size } {$IFDEF _16BIT} MaxSize = 65536; { 64 kilobytes : 2^16 } {$ELSE} MaxSize = 2147483648; { 2 gigabytes : 2^31 } {$ENDIF} FltSize = SizeOf(Float); CompSize = SizeOf(Complex); IntSize = SizeOf(Integer); BoolSize = SizeOf(Boolean); StrSize = SizeOf(String); PtrSize = SizeOf(Pointer); MAX_FLT = Trunc(MaxSize / FltSize) - 2; MAX_COMP = Trunc(MaxSize / CompSize) - 2; MAX_INT = Trunc(MaxSize / IntSize) - 2; MAX_BOOL = Trunc(MaxSize / BoolSize) - 2; MAX_STR = Trunc(MaxSize / StrSize) - 2; MAX_VEC = Trunc(MaxSize / PtrSize) - 2; type TVector = array[0..MAX_FLT] of Float; TIntVector = array[0..MAX_INT] of Integer; TCompVector = array[0..MAX_COMP] of Complex; TBoolVector = array[0..MAX_BOOL] of Boolean; TStrVector = array[0..MAX_STR] of String; PVector = ^TVector; PIntVector = ^TIntVector; PBoolVector = ^TBoolVector; PCompVector = ^TCompVector; PStrVector = ^TStrVector; type XTMatrix = array[0..MAX_VEC] of PVector; TIntMatrix = array[0..MAX_VEC] of PIntVector; TBoolMatrix = array[0..MAX_VEC] of PBoolVector; TCompMatrix = array[0..MAX_VEC] of PCompVector; TStrMatrix = array[0..MAX_VEC] of PStrVector; PMatrix = ^XTMatrix; PIntMatrix = ^TIntMatrix; PBoolMatrix = ^TBoolMatrix; PCompMatrix = ^TCompMatrix; PStrMatrix = ^TStrMatrix; { ------------------------------------------------------------------ Functional types ------------------------------------------------------------------ } { Function of one variable } type TFunc = function(X : Float) : Float; { Function of several variables } type TFuncNVar = function(X : PVector) : Float; { Nonlinear equation system } type TEquations = procedure(X, F : PVector); { Differential equation system } type TDiffEqs = procedure(X : Float; Y, Yp : PVector); { Jacobian } type TJacobian = procedure(X : PVector; D : PMatrix); { Gradient } type TGradient = procedure(X, G : PVector); { Hessian and Gradient } type THessGrad = procedure(X, G : PVector; H : PMatrix); { ------------------------------------------------------------------ Random number generators ------------------------------------------------------------------ } type RNG_Type = (RNG_MWC, { Multiply-With-Carry } RNG_MT, { Mersenne Twister } RNG_UVAG); { Universal Virtual Array Generator } { ------------------------------------------------------------------ Statistics ------------------------------------------------------------------ } type StatClass = record { Statistical class } Inf : Float; { Lower bound } Sup : Float; { Upper bound } N : Integer; { Number of values } F : Float; { Frequency } D : Float; { Density } end; const MAX_CLS = 1000; { Max. number of statistical classes } type TStatClassVector = array[0..MAX_CLS] of StatClass; PStatClassVector = ^TStatClassVector; { ------------------------------------------------------------------ Curve fit ------------------------------------------------------------------ } type TRegTest = record { Test of regression } Vr : Float; { Residual variance } R2 : Float; { Coefficient of determination } R2a : Float; { Adjusted coeff. of determination } F : Float; { Variance ratio (explained/residual) } Nu1, Nu2 : Integer; { Degrees of freedom } end; { Optimization algorithms for nonlinear regression } type TOptAlgo = ( NL_MARQ, { Marquardt algorithm } NL_SIMP, { Simplex algorithm } NL_BFGS, { BFGS algorithm } NL_SA, { Simulated annealing } NL_GA); { Genetic algorithm } { Regression function } type TRegFunc = function(X : Float; B : PVector) : Float; { Procedure to compute the derivatives of the regression function with respect to the regression parameters } type TDerivProc = procedure(X, Y : Float; B, D : PVector); { ------------------------------------------------------------------ Graphics ------------------------------------------------------------------ } type Str30 = String[30]; TScale = (LinScale, LogScale); TGrid = (NoGrid, HorizGrid, VertiGrid, BothGrid); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uminbrak.pas������������������������������������������������0000755�0001750�0001750�00000002445�11326425446�020013� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Brackets a minimum of a function ****************************************************************** } unit uminbrak; interface uses utypes, uminmax; procedure MinBrack(Func : TFunc; var A, B, C, Fa, Fb, Fc : Float); implementation procedure MinBrack(Func : TFunc; var A, B, C, Fa, Fb, Fc : Float); { ------------------------------------------------------------------ Given two points (A, B) this procedure finds a triplet (A, B, C) such that: 1) A < B < C 2) A, B, C are within the golden ratio 3) Func(B) < Func(A) and Func(B) < Func(C). The corresponding function values are returned in Fa, Fb, Fc ------------------------------------------------------------------ } begin if A > B then FSwap(A, B); Fa := Func(A); Fb := Func(B); if Fb > Fa then begin FSwap(A, B); FSwap(Fa, Fb); end; C := B + GOLD * (B - A); Fc := Func(C); while Fc < Fb do begin A := B; B := C; Fa := Fb; Fb := Fc; C := B + GOLD * (B - A); Fc := Func(C); end; if A > C then begin FSwap(A, C); FSwap(Fa, Fc); end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ugausjor.pas������������������������������������������������0000755�0001750�0001750�00000010460�11326425444�020034� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Solution of a system of linear equations by Gauss-Jordan method ****************************************************************** } unit ugausjor; interface uses utypes, uminmax; procedure GaussJordan(A : PMatrix; Lb, Ub1, Ub2 : Integer; var Det : Float); { ------------------------------------------------------------------ Transforms a matrix according to the Gauss-Jordan method ------------------------------------------------------------------ Input parameters : A = system matrix Lb = lower matrix bound in both dim. Ub1, Ub2 = upper matrix bounds ------------------------------------------------------------------ Output parameters: A = transformed matrix Det = determinant of A ------------------------------------------------------------------ Possible results : MatOk : No error MatErrDim : Non-compatible dimensions MatSing : Singular matrix ------------------------------------------------------------------ } implementation procedure GaussJordan(A : PMatrix; Lb, Ub1, Ub2 : Integer; var Det : Float); var Pvt : Float; { Pivot } Ik, Jk : Integer; { Pivot's row and column } I, J, K : Integer; { Loop variables } T : Float; { Temporary variable } PRow, PCol : PIntVector; { Stores pivot's row and column } MCol : PVector; { Stores a column of matrix A } procedure Terminate(ErrCode : Integer); { Set error code and deallocate arrays } begin DelIntVector(PRow, Ub1); DelIntVector(PCol, Ub1); DelVector(MCol, Ub1); SetErrCode(ErrCode); end; begin if Ub1 > Ub2 then begin SetErrCode(MatErrDim); Exit end; DimIntVector(PRow, Ub1); DimIntVector(PCol, Ub1); DimVector(MCol, Ub1); Det := 1.0; K := Lb; while K <= Ub1 do begin { Search for largest pivot in submatrix A[K..Ub1, K..Ub1] } Pvt := A^[K]^[K]; Ik := K; Jk := K; for I := K to Ub1 do for J := K to Ub1 do if Abs(A^[I]^[J]) > Abs(Pvt) then begin Pvt := A^[I]^[J]; Ik := I; Jk := J; end; { Store pivot's position } PRow^[K] := Ik; PCol^[K] := Jk; { Update determinant } Det := Det * Pvt; if Ik <> K then Det := - Det; if Jk <> K then Det := - Det; { Too weak pivot ==> quasi-singular matrix } if Abs(Pvt) < MachEp then begin Terminate(MatSing); Exit end; { Exchange current row (K) with pivot row (Ik) } if Ik <> K then for J := Lb to Ub2 do FSwap(A^[Ik]^[J], A^[K]^[J]); { Exchange current column (K) with pivot column (Jk) } if Jk <> K then for I := Lb to Ub1 do FSwap(A^[I]^[Jk], A^[I]^[K]); { Store column K of matrix A into MCol and set this column to zero } for I := Lb to Ub1 do if I <> K then begin MCol^[I] := A^[I]^[K]; A^[I]^[K] := 0.0; end else begin MCol^[I] := 0.0; A^[I]^[K] := 1.0; end; { Transform pivot row } T := 1.0 / Pvt; for J := Lb to Ub2 do A^[K]^[J] := T * A^[K]^[J]; { Transform other rows } for I := Lb to Ub1 do if I <> K then begin T := MCol^[I]; for J := Lb to Ub2 do A^[I]^[J] := A^[I]^[J] - T * A^[K]^[J]; end; Inc(K); end; { Exchange lines of inverse matrix } for I := Ub1 downto Lb do begin Ik := PCol^[I]; if Ik <> I then for J := Lb to Ub2 do FSwap(A^[I]^[J], A^[Ik]^[J]); end; { Exchange columns of inverse matrix } for J := Ub1 downto Lb do begin Jk := PRow^[J]; if Jk <> J then for I := Lb to Ub1 do FSwap(A^[I]^[J], A^[I]^[Jk]); end; Terminate(MatOk); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uinvbeta.pas������������������������������������������������0000755�0001750�0001750�00000016647�11326425444�020027� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Inverses of incomplete Beta function, Student and F-distributions Translated from C code in Cephes library (http://www.moshier.net) ****************************************************************** } unit uinvbeta; interface uses utypes, ugamma, uibeta, uinvnorm; function InvBeta(A, B, Y : Float) : Float; { ------------------------------------------------------------------ Inverse of incomplete Beta function. Given P, the function finds X such that IBeta(A, B, X) = Y ------------------------------------------------------------------ } function InvStudent(Nu : Integer; P : Float) : Float; { ------------------------------------------------------------------ Inverse of Student's t-distribution function Given probability P, finds the argument X such that FStudent(Nu, X) = P ------------------------------------------------------------------ } function InvSnedecor(Nu1, Nu2 : Integer; P : Float) : Float; { ------------------------------------------------------------------ Inverse of Snedecor's F-distribution function Given probability P, finds the argument X such that FSnedecor(Nu1, Nu2, X) = P ------------------------------------------------------------------ } implementation function InvBeta(A, B, Y : Float) : Float; var a1, b1, y0, y1, d, x, x0, x1 : Float; lgm, yp, di, dithresh, yl, yh, xt : Float; i, rflg, ndir, nflg : Integer; label ihalve, newt, under, noconv, done; begin SetErrCode(FOk); if Y <= 0 then begin InvBeta := 0.0; Exit; end; if Y >= 1 then begin InvBeta := 1.0; Exit; end; x0 := 0.0; yl := 0.0; x1 := 1.0; yh := 1.0; nflg := 0; if (A <= 1) or (B <= 1) then begin dithresh := 1e-6; rflg := 0; a1 := A; b1 := B; y0 := Y; x := a1 / (a1 + b1); y1 := IBeta(a1, b1, x); goto ihalve end else dithresh := 1e-4; { approximation to inverse function } yp := - InvNorm(Y); if Y > 0.5 then begin rflg := 1; a1 := B; b1 := A; y0 := 1.0 - Y; yp := -yp; end else begin rflg := 0; a1 := A; b1 := B; y0 := Y; end; lgm := (yp * yp - 3.0) / 6.0; x := 2.0 / (1.0 / (2.0 * a1 - 1.0) + 1.0 / (2.0 * b1 - 1.0)); d := yp * Sqrt(x + lgm) / x - (1.0 / (2.0 * b1 - 1.0) - 1.0 / (2.0 * a1 - 1.0)) * (lgm + 5.0 / 6.0 - 2.0 / (3.0 * x)); d := 2.0 * d; if d < MinLog then goto under; x := a1 / (a1 + b1 * Exp(d)); y1 := IBeta(a1, b1, x); yp := (y1 - y0) / y0; if Abs(yp) < 0.2 then goto newt; { Resort to interval halving if not close enough } ihalve: ndir := 0; di := 0.5; for i := 0 to 99 do begin if i <> 0 then begin x := x0 + di * (x1 - x0); if x = 1.0 then x := 1.0 - MachEp; if x = 0.0 then begin di := 0.5; x := x0 + di * (x1 - x0); if x = 0.0 then goto under end; y1 := IBeta(a1, b1, x); yp := (x1 - x0) / (x1 + x0); if abs(yp) < dithresh then goto newt; yp := (y1 - y0) / y0; if abs(yp) < dithresh then goto newt; end; if y1 < y0 then begin x0 := x; yl := y1; if ndir < 0 then begin ndir := 0; di := 0.5; end else if ndir > 3 then di := 1.0 - Sqr(1.0 - di) else if ndir > 1 then di := 0.5 * di + 0.5 else di := (y0 - y1) / (yh - yl); ndir := ndir + 1; if x0 > 0.75 then begin if rflg = 1 then begin rflg := 0; a1 := A; b1 := B; y0 := Y; end else begin rflg := 1; a1 := B; b1 := A; y0 := 1.0 - Y; end; x := 1.0 - x; y1 := IBeta(a1, b1, x); x0 := 0.0; yl := 0.0; x1 := 1.0; yh := 1.0; goto ihalve end end else begin x1 := x; if (rflg = 1) and (x1 < MachEp) then begin x := 0.0; goto done end; yh := y1; if ndir > 0 then begin ndir := 0; di := 0.5 end else if ndir < -3 then di := di * di else if ndir < -1 then di := 0.5 * di else di := (y1 - y0) / (yh - yl); ndir := ndir - 1; end; end; SetErrCode(FPLoss); if x0 >= 1.0 then begin x := 1.0 - MachEp; goto done end; if x <= 0.0 then begin under: SetErrCode(FUnderflow); x := 0.0; goto done; end; newt: if nflg = 1 then goto done; nflg := 1; lgm := LnGamma(a1 + b1) - LnGamma(a1) - LnGamma(b1); for i := 0 to 7 do begin { Compute the function at this point } if i <> 0 then y1 := IBeta(a1, b1, x); if y1 < yl then begin x := x0; y1 := yl end else if y1 > yh then begin x := x1; y1 := yh end else if y1 < y0 then begin x0 := x; yl := y1 end else begin x1 := x; yh := y1 end; if (x = 1.0) or (x = 0.0) then goto noconv; { Compute the derivative of the function at this point } d := (a1 - 1.0) * Ln(x) + (b1 - 1.0) * Ln(1 - x) + lgm; if d < MinLog then goto done; if d > MaxLog then goto noconv; d := exp(d); { Compute the step to the next approximation of x } d := (y1 - y0) / d; xt := x - d; if xt <= x0 then begin y1 := (x - x0) / (x1 - x0); xt := x0 + 0.5 * y1 * (x - x0); if xt <= 0.0 then goto noconv; end; if xt >= x1 then begin y1 := (x1 - x) / (x1 - x0); xt := x1 - 0.5 * y1 * (x1 - x); if xt >= 1.0 then goto noconv; end; x := xt; if abs(d / x) < 128.0 * MachEp then goto done end; noconv: { Did not converge } dithresh := 256.0 * MachEp; goto ihalve; done: if rflg = 1 then if x <= MachEp then x := 1.0 - MachEp else x := 1.0 - x; InvBeta := x; end; function InvStudent(Nu : Integer; P : Float) : Float; var t, rk, z : Float; rflg : Integer; begin if (Nu < 1) or (P < 0.0) or (P > 1.0) then begin InvStudent := DefaultVal(FDomain, 0.0); Exit; end; if P = 0.5 then begin SetErrCode(FOk); InvStudent := 0.0; Exit; end; rk := Nu; if (P > 0.25) and (P < 0.75) then begin z := 1.0 - 2.0 * P; z := InvBeta(0.5, 0.5 * rk, Abs(z)); t := Sqrt(rk * z / (1 - z)); if P < 0.5 then t := -t; InvStudent := t; Exit; end; if P < 0.5 then begin z := P; rflg := -1 end else begin z := 1.0 - P; rflg := 1 end; z := InvBeta(0.5 * rk, 0.5, 2 * z); if MaxNum * z < rk then begin InvStudent := rflg * MaxNum; Exit; end; t := Sqrt(rk / z - rk); InvStudent := rflg * t; end; function InvSnedecor(Nu1, Nu2 : Integer; P : Float) : Float; var w : Float; begin if (Nu1 < 1) or (Nu2 < 1) or (P < 0.0) or (P > 1.0) then begin InvSnedecor := DefaultVal(FDomain, 0.0); Exit; end; w := InvBeta(0.5 * Nu2, 0.5 * Nu1, 1.0 - P); InvSnedecor := (Nu2 - Nu2 * w) / (Nu1 * w); end; end. �����������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/usvd.pas����������������������������������������������������0000755�0001750�0001750�00000034443�11326425446�017167� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Singular value decomposition ****************************************************************** } unit usvd; interface uses utypes, uminmax, utrigo; procedure SV_Decomp(A : PMatrix; Lb, Ub1, Ub2 : Integer; S : PVector; V : PMatrix); { ------------------------------------------------------------------ Singular value decomposition. Factors the matrix A (n x m, with n >= m) as a product U * S * V' where U is a (n x m) column- orthogonal matrix, S a (m x m) diagonal matrix with elements >= 0 (the singular values) and V a (m x m) orthogonal matrix. This routine is used in conjunction with SV_Solve to solve a system of equations. ------------------------------------------------------------------ Input parameters : A = matrix Lb = index of first matrix element Ub1 = index of last matrix element in 1st dim. Ub2 = index of last matrix element in 2nd dim. ------------------------------------------------------------------ Output parameter : A = contains the elements of U S = vector of singular values V = orthogonal matrix ------------------------------------------------------------------ Possible results : MatOk : No error MatNonConv : Non-convergence MatErrDim : Non-compatible dimensions (n < m) ------------------------------------------------------------------ NB : This procedure destroys the original matrix A ------------------------------------------------------------------ } procedure SV_SetZero(S : PVector; Lb, Ub : Integer; Tol : Float); { ------------------------------------------------------------------ Sets the singular values to zero if they are lower than a specified threshold. ------------------------------------------------------------------ Input parameters : S = vector of singular values Tol = relative tolerance Threshold value will be Tol * Max(S) Lb = index of first vector element Ub = index of last vector element ------------------------------------------------------------------ Output parameter : S = modified singular values ------------------------------------------------------------------ } procedure SV_Solve(U : PMatrix; S : PVector; V : PMatrix; B : PVector; Lb, Ub1, Ub2 : Integer; X : PVector); { ------------------------------------------------------------------ Solves a system of equations by singular value decomposition, after the matrix has been transformed by SV_Decomp, and the lowest singular values have been set to zero by SV_SetZero. ------------------------------------------------------------------ Input parameters : U, S, V = vector and matrices from SV_Decomp B = constant vector Lb, Ub1, Ub2 = as in SV_Decomp ------------------------------------------------------------------ Output parameter : X = solution vector = V * Diag(1/s(i)) * U' * B, for s(i) <> 0 ------------------------------------------------------------------ } procedure SV_Approx(U : PMatrix; S : PVector; V : PMatrix; Lb, Ub1, Ub2 : Integer; A : PMatrix); { ------------------------------------------------------------------ Approximates a matrix A by the product USV', after the lowest singular values have been set to zero by SV_SetZero. ------------------------------------------------------------------ Input parameters : U, S, V = vector and matrices from SV_Decomp Lb, Ub1, Ub2 = as in SV_Decomp ------------------------------------------------------------------ Output parameter : A = approximated matrix ------------------------------------------------------------------ } implementation procedure SV_Decomp(A : PMatrix; Lb, Ub1, Ub2 : Integer; S : PVector; V : PMatrix); { ---------------------------------------------------------------------- This procedure is a translation of the EISPACK subroutine SVD This procedure determines the singular value decomposition A = U.S.V' of a real M by N rectangular matrix. Householder bidiagonalization and a variant of the QR algorithm are used. ---------------------------------------------------------------------- This is a crude translation. Many of the original goto's have been kept! ---------------------------------------------------------------------- } var I, J, K, L, I1, K1, L1, Mn, Its : Integer; C, F, G, H, T, X, Y, Z, Tst1, Tst2, Scale : Float; R : PVector; label 190, 210, 270, 290, 360, 390, 430, 460, 475, 490, 520, 540, 565, 580, 650, 700; begin if Ub2 > Ub1 then begin SetErrCode(MatErrDim); Exit end; DimVector(R, Ub2); Scale := 0.0; G := 0.0; X := 0.0; { Householder reduction to bidiagonal form } for I := Lb to Ub2 do begin L := I + 1; R^[I] := Scale * G; G := 0.0; T := 0.0; Scale := 0.0; if I > Ub1 then goto 210; for K := I to Ub1 do Scale := Scale + Abs(A^[K]^[I]); if Scale = 0.0 then goto 210; for K := I to Ub1 do begin A^[K]^[I] := A^[K]^[I] / Scale; T := T + Sqr(A^[K]^[I]); end; F := A^[I]^[I]; G := - DSgn(Sqrt(T), F); H := F * G - T; A^[I]^[I] := F - G; if I = Ub2 then goto 190; for J := L to Ub2 do begin T := 0.0; for K := I to Ub1 do T := T + A^[K]^[I] * A^[K]^[J]; F := T / H; for K := I to Ub1 do A^[K]^[J] := A^[K]^[J] + F * A^[K]^[I]; end; 190: for K := I to Ub1 do A^[K]^[I] := Scale * A^[K]^[I]; 210: S^[I] := Scale * G; G := 0.0; T := 0.0; Scale := 0.0; if (I > Ub1) or (I = Ub2) then goto 290; for K := L to Ub2 do Scale := Scale + Abs(A^[I]^[K]); if Scale = 0.0 then goto 290; for K := L to Ub2 do begin A^[I]^[K] := A^[I]^[K] / Scale; T := T + Sqr(A^[I]^[K]); end; F := A^[I]^[L]; G := - DSgn(Sqrt(T), F); H := F * G - T; A^[I]^[L] := F - G; for K := L to Ub2 do R^[K] := A^[I]^[K] / H; if I = Ub1 then goto 270; for J := L to Ub1 do begin T := 0.0; for K := L to Ub2 do T := T + A^[J]^[K] * A^[I]^[K]; for K := L to Ub2 do A^[J]^[K] := A^[J]^[K] + T * R^[K]; end; 270: for K := L to Ub2 do A^[I]^[K] := Scale * A^[I]^[K]; 290: X := FMax(X, Abs(S^[I]) + Abs(R^[I])); end; { Accumulation of right-hand transformations } for I := Ub2 downto Lb do begin if I = Ub2 then goto 390; if G = 0.0 then goto 360; for J := L to Ub2 do { Double division avoids possible underflow } V^[J]^[I] := (A^[I]^[J] / A^[I]^[L]) / G; for J := L to Ub2 do begin T := 0.0; for K := L to Ub2 do T := T + A^[I]^[K] * V^[K]^[J]; for K := L to Ub2 do V^[K]^[J] := V^[K]^[J] + T * V^[K]^[I]; end; 360: for J := L to Ub2 do begin V^[I]^[J] := 0.0; V^[J]^[I] := 0.0; end; 390: V^[I]^[I] := 1.0; G := R^[I]; L := I; end; { Accumulation of left-hand transformations } Mn := IMin(Ub1, Ub2); for I := Mn downto Lb do begin L := I + 1; G := S^[I]; if I = Ub2 then goto 430; for J := L to Ub2 do A^[I]^[J] := 0.0; 430: if G = 0.0 then goto 475; if I = Mn then goto 460; for J := L to Ub2 do begin T := 0.0; for K := L to Ub1 do T := T + A^[K]^[I] * A^[K]^[J]; { Double division avoids possible underflow } F := (T / A^[I]^[I]) / G; for K := I to Ub1 do A^[K]^[J] := A^[K]^[J] + F * A^[K]^[I]; end; 460: for J := I to Ub1 do A^[J]^[I] := A^[J]^[I] / G; goto 490; 475: for J := I to Ub1 do A^[J]^[I] := 0.0; 490: A^[I]^[I] := A^[I]^[I] + 1.0; end; { Diagonalization of the bidiagonal form } Tst1 := X; for K := Ub2 downto Lb do begin K1 := K - 1; Its := 0; 520: { Test for splitting } for L := K downto Lb do begin L1 := L - 1; Tst2 := Tst1 + Abs(R^[L]); if Tst2 = Tst1 then goto 565; { R^[Lb] is always zero, so there is no exit through the bottom of the loop } Tst2 := Tst1 + Abs(S^[L1]); if Tst2 = Tst1 then goto 540; end; 540: { Cancellation of R^[L] if L greater than 1 } C := 0.0; T := 1.0; for I := L to K do begin F := T * R^[I]; R^[I] := C * R^[I]; Tst2 := Tst1 + Abs(F); if Tst2 = Tst1 then goto 565; G := S^[I]; H := Pythag(F, G); S^[I] := H; C := G / H; T := - F / H; for J := Lb to Ub1 do begin Y := A^[J]^[L1]; Z := A^[J]^[I]; A^[J]^[L1] := Y * C + Z * T; A^[J]^[I] := - Y * T + Z * C; end; end; 565: { Test for convergence } Z := S^[K]; if L = K then goto 650; if Its = 30 then begin SetErrCode(MatNonConv); DelVector(R, Ub2); Exit; end; { Shift from bottom 2 by 2 minor } Its := Its + 1; X := S^[L]; Y := S^[K1]; G := R^[K1]; H := R^[K]; F := 0.5 * (((G + Z) / H) * ((G - Z) / Y) + Y / H - H / Y); G := Pythag(F, 1.0); F := X - (Z / X) * Z + (H / X) * (Y / (F + DSgn(G, F)) - H); { Next QR transformation } C := 1.0; T := 1.0; for I1 := L to K1 do begin I := I1 + 1; G := R^[I]; Y := S^[I]; H := T * G; G := C * G; Z := Pythag(F, H); R^[I1] := Z; C := F / Z; T := H / Z; F := X * C + G * T; G := - X * T + G * C; H := Y * T; Y := Y * C; for J := Lb to Ub2 do begin X := V^[J]^[I1]; Z := V^[J]^[I]; V^[J]^[I1] := X * C + Z * T; V^[J]^[I] := - X * T + Z * C; end; Z := Pythag(F, H); S^[I1] := Z; { Rotation can be arbitrary if Z is zero } if Z = 0.0 then goto 580; C := F / Z; T := H / Z; 580: F := C * G + T * Y; X := - T * G + C * Y; for J := Lb to Ub1 do begin Y := A^[J]^[I1]; Z := A^[J]^[I]; A^[J]^[I1] := Y * C + Z * T; A^[J]^[I] := - Y * T + Z * C; end; end; R^[L] := 0.0; R^[K] := F; S^[K] := X; goto 520; 650: { Convergence } if Z >= 0.0 then goto 700; { S^[K] is made non-negative } S^[K] := - Z; for J := Lb to Ub2 do V^[J]^[K] := - V^[J]^[K]; 700: end; DelVector(R, Ub2); SetErrCode(MatOk); end; procedure SV_SetZero(S : PVector; Lb, Ub : Integer; Tol : Float); var Threshold : Float; I : Integer; begin Threshold := S^[Lb]; for I := Lb + 1 to Ub do if S^[I] > Threshold then Threshold := S^[I]; Threshold := Tol * Threshold; for I := Lb to Ub do if S^[I] < Threshold then S^[I] := 0.0; end; procedure SV_Solve(U : PMatrix; S : PVector; V : PMatrix; B : PVector; Lb, Ub1, Ub2 : Integer; X : PVector); var I, J, K : Integer; Sum : Float; Tmp : PVector; begin DimVector(Tmp, Ub2); for J := Lb to Ub2 do begin Sum := 0.0; if S^[J] > 0.0 then begin for I := Lb to Ub1 do Sum := Sum + U^[I]^[J] * B^[I]; Sum := Sum / S^[J]; end; Tmp^[J] := Sum; end; for J := Lb to Ub2 do begin Sum := 0.0; for K := Lb to Ub2 do Sum := Sum + V^[J]^[K] * Tmp^[K]; X^[J] := Sum; end; DelVector(Tmp, Ub2); end; procedure SV_Approx(U : PMatrix; S : PVector; V : PMatrix; Lb, Ub1, Ub2 : Integer; A : PMatrix); var I, J, K : Integer; begin for I := Lb to Ub1 do for J := Lb to Ub2 do begin A^[I]^[J] := 0.0; for K := Lb to Ub2 do if S^[K] > 0.0 then A^[I]^[J] := A^[I]^[J] + U^[I]^[K] * V^[J]^[K]; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ugausleg.pas������������������������������������������������0000755�0001750�0001750�00000005525�11326425444�020017� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Gauss-Legendre integration ****************************************************************** } unit ugausleg; interface uses utypes; function GausLeg(Func : TFunc; A, B : Float) : Float; { Integral from A to B } function GausLeg0(Func : TFunc; B : Float) : Float; { Integral from 0 to B } function Convol(Func1, Func2 : TFunc; T : Float) : Float; { Convolution product at time T } implementation const Npts = 8; { Number of points / 2 } const Root : array[1..Npts] of Float = (0.0950125098376370440185, 0.281603550778258913230, 0.458016777657227386342, 0.617876244402643748447, 0.755404408355003033895, 0.865631202387831743880, 0.944575023073232576078, 0.989400934991649932596); const Weight : array[1..Npts] of Float = (0.189450610455068496285, 0.182603415044923588867, 0.169156519395002538189, 0.149595988816576732081, 0.124628971255533872052, 0.095158511682492784810, 0.062253523938647892863, 0.027152459411754094852); function GausLeg(Func : TFunc; A, B : Float) : Float; { ------------------------------------------------------------------ Computes the integral of function Func from A to B by the Gauss-Legendre method ------------------------------------------------------------------ } var P, Q, Sum, X, Y : Float; I : Integer; begin P := 0.5 * (B + A); Q := 0.5 * (B - A); Sum := 0.0; for I := 1 to Npts do begin X := Q * Root[I]; Y := Func(P + X) + Func(P - X); Sum := Sum + Weight[I] * Y; end; GausLeg := Q * Sum; end; function GausLeg0(Func : TFunc; B : Float) : Float; { ------------------------------------------------------------------ Computes the integral of function Func from 0 to B by the Gauss-Legendre method ------------------------------------------------------------------ } var P, Sum, X, Y : Float; I : Integer; begin P := 0.5 * B; Sum := 0; for I := 1 to Npts do begin X := P * Root[I]; Y := Func(P + X) + Func(P - X); Sum := Sum + Weight[I] * Y; end; GausLeg0 := P * Sum; end; function Convol(Func1, Func2 : TFunc; T : Float) : Float; { ------------------------------------------------------------------ Computes the convolution product of two functions Func1 and Func2 at time T by the Gauss-Legendre method ------------------------------------------------------------------ } var P, PpX, PmX, Sum, X, Y : Float; I : Integer; begin P := 0.5 * T; Sum := 0.0; for I := 1 to Npts do begin X := P * Root[I]; PpX := P + X; PmX := P - X; Y := Func1(T - PpX) * Func2(PpX) + Func1(T - PmX) * Func2(PmX); Sum := Sum + Weight[I] * Y; end; Convol := P * Sum; end; end.���������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uranmt.pas��������������������������������������������������0000755�0001750�0001750�00000013220�11326425446�017502� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Mersenne Twister Random Number Generator ****************************************************************** A C-program for MT19937, with initialization improved 2002/1/26. Coded by Takuji Nishimura and Makoto Matsumoto. Adapted for TPMath by Jean Debord - Feb. 2007 Before using, initialize the state by using init_genrand(seed) or init_by_array(init_key, key_length) (respectively InitMT and InitMTbyArray in the TPMath version) Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. The names of its contributors may not 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. Any feedback is very welcome. http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) ****************************************************************** } unit uranmt; interface type MTKeyArray = array[0..623] of LongInt; procedure InitMT(Seed : LongInt); { Initializes MT generator with a seed } procedure InitMTbyArray(InitKey : MTKeyArray; KeyLength : Word); { Initialize MT generator with an array InitKey[0..(KeyLength - 1)] } function IRanMT : LongInt; { Generates a Random number on [-2^31 .. 2^31 - 1] interval } implementation const N = 624; M = 397; MATRIX_A = $9908b0df; { constant vector a } UPPER_MASK = $80000000; { most significant w-r bits } LOWER_MASK = $7fffffff; { least significant r bits } mag01 : array[0..1] of LongInt = (0, MATRIX_A); var mt : MTKeyArray; { the array for the state vector } mti : Word; { mti == N+1 means mt[N] is not initialized } procedure InitMT(Seed : LongInt); var i : Word; begin mt[0] := Seed and $ffffffff; for i := 1 to N-1 do begin mt[i] := (1812433253 * (mt[i-1] Xor (mt[i-1] shr 30)) + i); { See Knuth TAOCP Vol2. 3rd Ed. P.106 For multiplier. In the previous versions, MSBs of the seed affect only MSBs of the array mt[]. 2002/01/09 modified by Makoto Matsumoto } mt[i] := mt[i] and $ffffffff; { For >32 Bit machines } end; mti := N; end; procedure InitMTbyArray(InitKey : MTKeyArray; KeyLength : Word); var i, j, k, k1 : Word; begin InitMT(19650218); i := 1; j := 0; if N > KeyLength then k1 := N else k1 := KeyLength; for k := k1 downto 1 do begin mt[i] := (mt[i] Xor ((mt[i-1] Xor (mt[i-1] shr 30)) * 1664525)) + InitKey[j] + j; { non linear } mt[i] := mt[i] and $ffffffff; { for WORDSIZE > 32 machines } i := i + 1; j := j + 1; if i >= N then begin mt[0] := mt[N-1]; i := 1; end; if j >= KeyLength then j := 0; end; for k := N-1 downto 1 do begin mt[i] := (mt[i] Xor ((mt[i-1] Xor (mt[i-1] shr 30)) * 1566083941)) - i; { non linear } mt[i] := mt[i] and $ffffffff; { for WORDSIZE > 32 machines } i := i + 1; if i >= N then begin mt[0] := mt[N-1]; i := 1; end; end; mt[0] := $80000000; { MSB is 1; assuring non-zero initial array } end; function IRanMT : LongInt; var y : LongInt; k : Word; begin if mti >= N then { generate N words at one Time } begin { If IRanMT() has not been called, a default initial seed is used } if mti = N + 1 then InitMT(5489); for k := 0 to (N-M)-1 do begin y := (mt[k] and UPPER_MASK) or (mt[k+1] and LOWER_MASK); mt[k] := mt[k+M] xor (y shr 1) xor mag01[y and $1]; end; for k := (N-M) to (N-2) do begin y := (mt[k] and UPPER_MASK) or (mt[k+1] and LOWER_MASK); mt[k] := mt[k - (N - M)] xor (y shr 1) xor mag01[y and $1]; end; y := (mt[N-1] and UPPER_MASK) or (mt[0] and LOWER_MASK); mt[N-1] := mt[M-1] xor (y shr 1) xor mag01[y and $1]; mti := 0; end; y := mt[mti]; mti := mti + 1; { Tempering } y := y xor (y shr 11); y := y xor ((y shl 7) and $9d2c5680); y := y xor ((y shl 15) and $efc60000); y := y xor (y shr 18); IRanMT := y end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ufft.pas����������������������������������������������������0000755�0001750�0001750�00000023753�11326425444�017152� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(*========================================================================== fourier.pas - Don Cross <dcross@intersrv.com> Modified by Jean Debord <JDebord@compuserve.com> for use with TP Math. This is a Turbo Pascal Unit for calculating the Fast Fourier Transform (FFT) and the Inverse Fast Fourier Transform (IFFT). Visit the following URL for the latest version of this code. This page also has a C/C++ version, and a brief discussion of the theory behind the FFT algorithm. http://www.intersrv.com/~dcross/fft.html#pascal Revision history [most recent first]: 2007 December 10 [Jean Debord] Increased the theoretical number of points to about 2^26 for a 32-bit compiler. The exact exponent is returned by function MaxPower. 2007 January 4 [Jean Debord] Modified for new TPMath version. Renamed as ufft.pas Now uses complex arrays. 1996 December 11 [Don Cross] Improved documentation of the procedure CalcFrequency. Fixed some messed up comments in procedure IFFT. 1996 December 6 [Don Cross] Made procedure 'fft_integer' more efficient when buffer size changes in successive calls: the buffer is now only resized when the input has more samples, not a differing number of samples. Also changed the way 'fft_integer_cleanup' works so that it is more "bullet-proof". 1996 December 4 [Don Cross] Adding the procedure 'CalcFrequency', which calculates the FFT at a specific frequency index p=0..n-1, instead of the whole FFT. This is O(n^2) instead of O(n*log(n)). 1996 November 30 [Don Cross] Adding a routine to allow FFT of an input array of integers. It is called 'fft_integer'. 1996 November 18 [Don Cross] Added some comments. 1996 November 17 [Don Cross] Wrote and debugged first version. ==========================================================================*) unit ufft; interface uses utypes, umath; (*--------------------------------------------------------------------------- procedure FFT Calculates the Fast Fourier Transform of the array of complex numbers represented by 'InArray' to produce the output complex numbers in 'OutArray'. ---------------------------------------------------------------------------*) procedure FFT(NumSamples : LongInt; InArray, OutArray : PCompVector); (*--------------------------------------------------------------------------- procedure IFFT Calculates the Inverse Fast Fourier Transform of the array of complex numbers represented by 'InArray' to produce the output complex numbers in 'OutArray'. ---------------------------------------------------------------------------*) procedure IFFT(NumSamples : LongInt; InArray, OutArray : PCompVector); (*--------------------------------------------------------------------------- procedure FFT_Integer Same as procedure FFT, but uses Integer input arrays instead of double. Make sure you call FFT_Integer_Cleanup after the last time you call FFT_Integer to free up memory it allocates. ---------------------------------------------------------------------------*) procedure FFT_Integer(NumSamples : LongInt; RealIn, ImagIn : PIntVector; OutArray : PCompVector); (*-------------------------------------------------------------------------- procedure FFT_Integer_Cleanup If you call the procedure 'FFT_Integer', you must call 'FFT_Integer_Cleanup' after the last time you call 'FFT_Integer' in order to free up dynamic memory. --------------------------------------------------------------------------*) procedure FFT_Integer_Cleanup; (*-------------------------------------------------------------------------- procedure CalcFrequency This procedure calculates the complex frequency sample at a given index directly. Use this instead of 'FFT' when you only need one or two frequency samples, not the whole spectrum. It is also useful for calculating the Discrete Fourier Transform (DFT) of a number of data which is not an integer power of 2. For example, you could calculate the DFT of 100 points instead of rounding up to 128 and padding the extra 28 array slots with zeroes. --------------------------------------------------------------------------*) procedure CalcFrequency(NumSamples, FrequencyIndex : LongInt; InArray : PCompVector; var FT : Complex); implementation const TempArraySize : Integer = 0; { Flag that buffer Temp is not allocated } var Temp : PCompVector; function MaxPower : LongInt; var M : Float; begin M := MAX_COMP; MaxPower := Trunc(Log2(M)); end; function IsPowerOfTwo(X : LongInt) : Boolean; var I, Y : LongInt; begin Y := 2; for I := 1 to MaxPower do begin if X = Y then begin IsPowerOfTwo := True; Exit; end; Y := Y shl 1; end; IsPowerOfTwo := False; end; function NumberOfBitsNeeded(PowerOfTwo : LongInt) : Integer; var I : Integer; begin for I := 0 to MaxPower do begin if (PowerOfTwo and (1 shl I)) <> 0 then begin NumberOfBitsNeeded := I; Exit; end; end; end; function ReverseBits(Index, NumBits : LongInt) : Integer; var I, Rev : Integer; begin Rev := 0; for I := 0 to NumBits - 1 do begin Rev := (Rev shl 1) or (Index and 1); Index := Index shr 1; end; ReverseBits := Rev; end; procedure FourierTransform(AngleNumerator : Float; NumSamples : LongInt; InArray, OutArray : PCompVector); var NumBits, I, J, K, N, BlockSize, BlockEnd : LongInt; Delta_angle, Delta_ar, Alpha, Beta, Tr, Ti, Ar, Ai : Float; begin if not IsPowerOfTwo(NumSamples) or (NumSamples < 2) then begin SetErrCode(-1); Exit; end; SetErrCode(0); NumBits := NumberOfBitsNeeded(NumSamples); for I := 0 to NumSamples - 1 do begin J := ReverseBits(I, NumBits); OutArray^[J].X := InArray^[I].X; OutArray^[J].Y := InArray^[I].Y; end; BlockEnd := 1; BlockSize := 2; while BlockSize <= NumSamples do begin Delta_angle := AngleNumerator / BlockSize; Alpha := Sin(0.5 * Delta_angle); Alpha := 2.0 * Alpha * Alpha; Beta := Sin(Delta_angle); I := 0; while I < NumSamples do begin Ar := 1.0; (* cos(0) *) Ai := 0.0; (* sin(0) *) J := I; for N := 0 to BlockEnd - 1 do begin K := J + BlockEnd; Tr := Ar * OutArray^[K].X - Ai * OutArray^[K].Y; Ti := Ar * OutArray^[K].Y + Ai * OutArray^[K].X; OutArray^[K].X := OutArray^[J].X - Tr; OutArray^[K].Y := OutArray^[J].Y - Ti; OutArray^[J].X := OutArray^[J].X + Tr; OutArray^[J].Y := OutArray^[J].Y + Ti; Delta_ar := Alpha * Ar + Beta * Ai; Ai := Ai - (Alpha * Ai - Beta * Ar); Ar := Ar - Delta_ar; Inc(J); end; I := I + BlockSize; end; BlockEnd := BlockSize; BlockSize := BlockSize shl 1; end; end; procedure FFT(NumSamples : LongInt; InArray, OutArray : PCompVector); begin FourierTransform(2 * PI, NumSamples, InArray, OutArray); end; procedure IFFT(NumSamples : LongInt; InArray, OutArray : PCompVector); var I : Integer; begin FourierTransform(- 2 * PI, NumSamples, InArray, OutArray); if MathErr <> 0 then Exit; { Normalize the resulting time samples } for I := 0 to NumSamples - 1 do begin OutArray^[I].X := OutArray^[I].X / NumSamples; OutArray^[I].Y := OutArray^[I].Y / NumSamples; end; end; procedure FFT_Integer(NumSamples : LongInt; RealIn, ImagIn : PIntVector; OutArray : PCompVector); var I : Integer; begin if NumSamples > TempArraySize then begin FFT_Integer_Cleanup; { free up memory in case we already have some } DimCompVector(Temp, NumSamples); TempArraySize := NumSamples; end; for I := 0 to NumSamples - 1 do begin Temp^[I].X := RealIn^[I]; Temp^[I].Y := ImagIn^[I]; end; FourierTransform(2 * PI, NumSamples, Temp, OutArray); end; procedure FFT_Integer_Cleanup; begin if TempArraySize > 0 then begin DelCompVector(Temp, TempArraySize); TempArraySize := 0; end; end; procedure CalcFrequency(NumSamples, FrequencyIndex : LongInt; InArray : PCompVector; var FT : Complex); var K : Integer; Cos1, Cos2, Cos3 : Float; Sin1, Sin2, Sin3 : Float; Theta, Beta : Float; begin FT.X := 0.0; FT.Y := 0.0; Theta := 2 * PI * FrequencyIndex / NumSamples; Sin1 := Sin(- 2 * Theta); Sin2 := Sin(- Theta); Cos1 := Cos(- 2 * Theta); Cos2 := Cos(- Theta); Beta := 2 * Cos2; for K := 0 to NumSamples - 1 do begin { Update trig values } Sin3 := Beta * Sin2 - Sin1; Sin1 := Sin2; Sin2 := Sin3; Cos3 := Beta * Cos2 - Cos1; Cos1 := Cos2; Cos2 := Cos3; FT.X := FT.X + InArray^[K].X * Cos3 - InArray^[K].Y * Sin3; FT.Y := FT.Y + InArray^[K].Y * Cos3 + InArray^[K].X * Sin3; end; end; end. ���������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/unewteqs.pas������������������������������������������������0000755�0001750�0001750�00000006623�11326425446�020060� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Newton-Raphson solver for system of nonlinear equations ****************************************************************** } unit unewteqs; interface uses utypes, ulineq, ulinminq, ucompvec; procedure NewtEqs(Equations : TEquations; Jacobian : TJacobian; X, F : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float); { ------------------------------------------------------------------ Solves a system of nonlinear equations by Newton's method ------------------------------------------------------------------ Input parameters : Equations = subroutine to compute equations Jacobian = subroutine to compute Jacobian X = initial root MaxIter = maximum number of iterations Tol = required precision ------------------------------------------------------------------ Output parameters : X = refined root F = function values ------------------------------------------------------------------ Possible results : OptOk = no error OptNonConv = non-convergence OptSing = singular jacobian matrix ------------------------------------------------------------------ } implementation procedure NewtEqs(Equations : TEquations; Jacobian : TJacobian; X, F : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float); var I : Integer; { Loop variables } R : Float; { Step for line minimization } Det : Float; { Determinant of Jacobian } Iter : Integer; { Iteration count } Conv : Boolean; { Test convergence } OldX : PVector; { Old parameters } DeltaX : PVector; { New search direction } D : PMatrix; { Jacobian matrix } procedure Terminate(ErrCode : Integer); { Set error code and deallocate arrays } begin DelVector(OldX, Ub); DelVector(DeltaX, Ub); DelMatrix(D, Ub, Ub); SetErrCode(ErrCode); end; begin { Initialize function vector } Equations(X, F); { Quit if no iteration required } if MaxIter < 1 then begin SetErrCode(OptOk); Exit; end; { Dimension arrays } DimVector(OldX, Ub); DimVector(DeltaX, Ub); DimMatrix(D, Ub, Ub); Iter := 0; repeat { Compute Jacobian } Jacobian(X, D); { Solve linear system } LinEq(D, F, Lb, Ub, Det); if MathErr <> MatOk then begin Terminate(OptSing); Exit; end; { Prepare next iteration } Iter := Iter + 1; if Iter > MaxIter then begin Terminate(OptNonConv); Exit; end; { Save current parameters and initialize the direction search } for I := Lb to Ub do begin OldX^[I] := X^[I]; DeltaX^[I] := - F^[I]; end; { Minimize in the direction specified by DeltaX, using an initial step of 0.1 } R := 0.1; LinMinEq(Equations, X, DeltaX, F, Lb, Ub, R, 10, 0.01); { Test for convergence } Conv := CompVec(X, OldX, Lb, Ub, Tol); until Conv; Terminate(OptOk); end; end.�������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ueltran.pas�������������������������������������������������0000755�0001750�0001750�00000004463�11326425444�017655� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Save transformations used by ElmHes ****************************************************************** } unit ueltran; interface uses utypes; procedure Eltran(A : PMatrix; Lb, Ub, I_low, I_igh : Integer; I_int : PIntVector; Z : PMatrix); implementation procedure Eltran(A : PMatrix; Lb, Ub, I_low, I_igh : Integer; I_int : PIntVector; Z : PMatrix); { ------------------------------------------------------------------ This procedure is a translation of the EISPACK subroutine Eltran. This procedure accumulates the stabilized elementary similarity transformations used in the reduction of a real general matrix to upper Hessenberg form by Elmhes. On input: A contains the multipliers which were used in the reduction by Elmhes in its lower triangle below the subdiagonal. Lb, Ub are the lowest and highest indices of the elements of A I_low and I_igh are integers determined by the balancing procedure Balance. If Balance has not been used, set I_low=Lb, I_igh=Ub. I_int contains information on the rows and columns interchanged in the reduction by Elmhes. Only elements I_low through I_igh are used. On output: Z contains the transformation matrix produced in the reduction by Elmhes. ------------------------------------------------------------------ } var I, J, Mp, Mp1 : Integer; begin { Initialize Z to identity matrix } for I := Lb to Ub do for J := Lb to Ub do if I = J then Z^[I]^[J] := 1.0 else Z^[I]^[J] := 0.0; if I_igh < I_low then Exit; for Mp := I_igh - 1 downto I_low + 1 do begin Mp1 := Mp + 1; for I := Mp1 to I_igh do Z^[I]^[Mp] := A^[I]^[Mp - 1]; I := I_int^[Mp]; if I <> Mp then begin for J := Mp to I_igh do begin Z^[Mp]^[J] := Z^[I]^[J]; Z^[I]^[J] := 0.0; end; Z^[I]^[Mp] := 1.0; end; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/utrapint.pas������������������������������������������������0000755�0001750�0001750�00000001246�11326425446�020047� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Trapezoidal integration ****************************************************************** } unit utrapint; interface uses utypes; function TrapInt(X, Y : PVector; N : Integer) : Float; { Integration by trapezoidal rule, from (X^[0], Y^[0]) to (X^[N], Y^[N]) } implementation function TrapInt(X, Y : PVector; N : Integer) : Float; var Sum : Float; I, J : Integer; begin Sum := 0.0; for I := 0 to Pred(N) do begin J := Succ(I); Sum := Sum + 0.5 * (X^[J] - X^[I]) * (Y^[J] + Y^[I]); end; TrapInt := Sum; end; end.����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/upolynom.pas������������������������������������������������0000755�0001750�0001750�00000003040�11326425446�020055� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Polynomials and rational fractions ****************************************************************** } unit upolynom; interface uses utypes; function Poly(X : Float; Coef : PVector; Deg : Integer) : Float; { ------------------------------------------------------------------ Evaluates the polynomial : P(X) = Coef[0] + Coef[1] * X + Coef[2] * X^2 + ... + Coef[Deg] * X^Deg ------------------------------------------------------------------ } function RFrac(X : Float; Coef : PVector; Deg1, Deg2 : Integer) : Float; { ------------------------------------------------------------------ Evaluates the rational fraction : Coef[0] + Coef[1] * X + ... + Coef[Deg1] * X^Deg1 F(X) = ----------------------------------------------------- 1 + Coef[Deg1+1] * X + ... + Coef[Deg1+Deg2] * X^Deg2 ------------------------------------------------------------------ } implementation function Poly(X : Float; Coef : PVector; Deg : Integer) : Float; var I : Integer; P : Float; begin P := Coef^[Deg]; for I := Pred(Deg) downto 0 do P := P * X + Coef^[I]; Poly := P; end; function RFrac(X : Float; Coef : PVector; Deg1, Deg2 : Integer) : Float; var I : Integer; P, Q : Float; begin P := Coef^[Deg1]; for I := Pred(Deg1) downto 0 do P := P * X + Coef^[I]; Q := 0.0; for I := (Deg1 + Deg2) downto Succ(Deg1) do Q := (Q + Coef^[I]) * X; RFrac := P / (1.0 + Q); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uround.pas��������������������������������������������������0000755�0001750�0001750�00000002361�11326425446�017514� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Rounding functions Based on FreeBASIC version contributed by R. Keeling ****************************************************************** } unit uround; interface uses utypes, uminmax, umath; function RoundN(X : Float; N : Integer) : Float; { Rounds X to N decimal places } function Ceil(X : Float) : Integer; { Ceiling function } function Floor(X : Float) : Integer; { Floor function } implementation function RoundN (X : Float; N : Integer) : Float; const MaxRoundPlaces = 18; var ReturnAnswer, Dec_Place : Float; I : Integer; begin if (N >= 0) and (N < MaxRoundPlaces) then I := N else I := 0; Dec_Place := Exp10(I); ReturnAnswer := Int((Abs(X) * Dec_Place) + 0.5); RoundN := Sgn(X) * ReturnAnswer / Dec_Place; end; function Ceil(X : Float) : Integer; var ReturnAnswer : Integer; begin ReturnAnswer := Trunc(X); if ReturnAnswer < X then ReturnAnswer := ReturnAnswer + 1; Ceil := ReturnAnswer; end; function Floor(X : Float) : Integer; var ReturnAnswer : Integer; begin ReturnAnswer := Trunc(X); if ReturnAnswer > X then ReturnAnswer := ReturnAnswer - 1; Floor := ReturnAnswer; end; end.�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uanova1.pas�������������������������������������������������0000755�0001750�0001750�00000004037�11326425444�017552� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** One-way analysis of variance ****************************************************************** } unit uanova1; interface uses utypes; procedure AnOVa1(Ns : Integer; N : PIntVector; M, S : PVector; var V_f, V_r, F : Float; var DoF_f, DoF_r : Integer); { ------------------------------------------------------------------ Input parameters : Ns = number of samples N = samples sizes M = samples means S = samples SD's (computed with StDev) Output parameters: V_f, V_r = variances (factorial, residual) F = ratio Vf / Vr DoF_f, DoF_r = degrees of freedom ------------------------------------------------------------------ } implementation procedure AnOVa1(Ns : Integer; N : PIntVector; M, S : PVector; var V_f, V_r, F : Float; var DoF_f, DoF_r : Integer); var I, Nt : Integer; Xbar : Float; { Global mean } SSf, SSr : Float; { Sum of squares } D : Float; { Difference of means } begin if Ns < 2 then begin SetErrCode(MatErrDim); Exit end; Nt := 0; for I := 1 to Ns do Nt := Nt + N^[I]; if Nt <= Ns then begin SetErrCode(MatErrDim); Exit; end; SetErrCode(MatOk); Xbar := 0.0; for I := 1 to Ns do Xbar := Xbar + N^[I] * M^[I]; Xbar := Xbar / Nt; SSf := 0.0; SSr := 0.0; for I := 1 to Ns do begin D := M^[I] - Xbar; SSf := SSf + N^[I] * Sqr(D); SSr := SSr + (N^[I] - 1) * Sqr(S^[I]); end; DoF_f := Ns - 1; DoF_r := Nt - Ns; V_f := SSf / DoF_f; V_r := SSr / DoF_r; F := V_f / V_r; end; end.�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uwoolf.pas��������������������������������������������������0000755�0001750�0001750�00000005542�11326425446�017517� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Woolf test ****************************************************************** } unit uwoolf; interface uses utypes; procedure Woolf_Conform(N_cls : Integer; N_estim : Integer; Obs : PIntVector; Calc : PVector; var G : Float; var DoF : Integer); { ------------------------------------------------------------------ Woolf test for conformity ------------------------------------------------------------------ } procedure Woolf_Indep(N_lin : Integer; N_col : Integer; Obs : PIntMatrix; var G : Float; var DoF : Integer); { ------------------------------------------------------------------ Woolf test for independence ------------------------------------------------------------------ } implementation procedure Woolf_Conform(N_cls : Integer; N_estim : Integer; Obs : PIntVector; Calc : PVector; var G : Float; var DoF : Integer); var I : Integer; begin for I := 1 to N_cls do if (Obs^[I] <= 0) or (Calc^[I] <= 0.0) then begin SetErrCode(FSing); Exit end; SetErrCode(FOk); G := 0.0; for I := 1 to N_cls do G := G + Obs^[I] * Ln(Obs^[I] / Calc^[I]); G := 2.0 * G; DoF := N_cls - N_estim - 1; end; procedure Woolf_Indep(N_lin : Integer; N_col : Integer; Obs : PIntMatrix; var G : Float; var DoF : Integer); var SumLin, SumCol : PIntVector; Sum : Integer; Prob, Calc : Float; I, J : Integer; begin for I := 1 to N_lin do for J := 1 to N_col do if Obs^[I]^[J] <= 0 then begin SetErrCode(FSing); Exit end; SetErrCode(FOk); DimIntVector(SumLin, N_lin); DimIntVector(SumCol, N_col); for I := 1 to N_lin do for J := 1 to N_col do SumLin^[I] := SumLin^[I] + Obs^[I]^[J]; for J := 1 to N_col do for I := 1 to N_lin do SumCol^[J] := SumCol^[J] + Obs^[I]^[J]; Sum := 0; for I := 1 to N_lin do Sum := Sum + SumLin^[I]; G := 0.0; for I := 1 to N_lin do begin Prob := SumLin^[I] / Sum; for J := 1 to N_col do begin Calc := SumCol^[J] * Prob; G := G + Obs^[I]^[J] * Ln(Obs^[I]^[J] / Calc); end; end; G := 2.0 * G; DoF := Pred(N_lin) * Pred(N_col); DelIntVector(SumLin, N_lin); DelIntVector(SumCol, N_col); end; end.��������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uwinplot.pas������������������������������������������������0000755�0001750�0001750�00000116751�11326425446�020072� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Plotting routines for Delphi ****************************************************************** } unit uwinplot; interface uses Classes, Graphics, utypes, umath, uround, uinterv, ustrings; function InitGraphics(Canvas : TCanvas; Width, Height : Integer) : Boolean; { ------------------------------------------------------------------ Enters graphic mode. ------------------------------------------------------------------ The parameters Width and Height refer to the object on which the graphic is plotted. Examples: To draw on a TImage object: InitGraph(Image1.Canvas, Image1.Width, Image1.Height) To print the graphic: InitGraph(Printer.Canvas, Printer.PageWidth, Printer.PageHeight) ------------------------------------------------------------------ } procedure SetWindow(Canvas : TCanvas; X1, X2, Y1, Y2 : Integer; GraphBorder : Boolean); { ------------------------------------------------------------------ Sets the graphic window X1, X2, Y1, Y2 : Window coordinates in % of maximum GraphBorder : Flag for drawing the window border ------------------------------------------------------------------ } procedure AutoScale(X : PVector; Lb, Ub : Integer; Scale : TScale; var XMin, XMax, XStep : Float); { ------------------------------------------------------------------ Finds an appropriate scale for plotting the data in X[Lb..Ub] ------------------------------------------------------------------ } procedure SetOxScale(Scale : TScale; OxMin, OxMax, OxStep : Float); { ------------------------------------------------------------------ Sets the scale on the Ox axis ------------------------------------------------------------------ } procedure SetOyScale(Scale : TScale; OyMin, OyMax, OyStep : Float); { ------------------------------------------------------------------ Sets the scale on the Oy axis ------------------------------------------------------------------ } procedure SetGraphTitle(Title : String); { ------------------------------------------------------------------ Sets the title for the graph ------------------------------------------------------------------ } procedure SetOxTitle(Title : String); { ------------------------------------------------------------------ Sets the title for the Ox axis ------------------------------------------------------------------ } procedure SetOyTitle(Title : String); { ------------------------------------------------------------------ Sets the title for the Oy axis ------------------------------------------------------------------ } procedure PlotOxAxis(Canvas : TCanvas); { ------------------------------------------------------------------ Plots the horizontal axis ------------------------------------------------------------------ } procedure PlotOyAxis(Canvas : TCanvas); { ------------------------------------------------------------------ Plots the vertical axis ------------------------------------------------------------------ } procedure PlotGrid(Canvas : TCanvas; Grid : TGrid); { ------------------------------------------------------------------ Plots a grid on the graph ------------------------------------------------------------------ } procedure WriteGraphTitle(Canvas : TCanvas); { ------------------------------------------------------------------ Writes the title of the graph ------------------------------------------------------------------ } procedure SetMaxCurv(NCurv : Byte); { ------------------------------------------------------------------ Sets the maximum number of curves and re-initializes their parameters ------------------------------------------------------------------ } procedure SetPointParam(CurvIndex, Symbol, Size : Integer; Color : TColor); { ------------------------------------------------------------------ Sets the point parameters for curve # CurvIndex ------------------------------------------------------------------ } procedure SetLineParam(CurvIndex : Integer; Style : TPenStyle; Width : Integer; Color : TColor); { ------------------------------------------------------------------ Sets the line parameters for curve # CurvIndex ------------------------------------------------------------------ } procedure SetCurvLegend(CurvIndex : Integer; Legend : String); { ------------------------------------------------------------------ Sets the legend for curve # CurvIndex ------------------------------------------------------------------ } procedure SetCurvStep(CurvIndex, Step : Integer); { ------------------------------------------------------------------ Sets the step for curve # CurvIndex ------------------------------------------------------------------ } procedure PlotPoint(Canvas : TCanvas; X, Y : Float; CurvIndex : Integer); { ------------------------------------------------------------------ Plots a point on the screen ------------------------------------------------------------------ Input parameters : X, Y = point coordinates CurvIndex = index of curve parameters (Symbol, Size, Color) ------------------------------------------------------------------ } procedure PlotCurve(Canvas : TCanvas; X, Y : PVector; Lb, Ub, CurvIndex : Integer); { ------------------------------------------------------------------ Plots a curve ------------------------------------------------------------------ Input parameters : X, Y = point coordinates Lb, Ub = indices of first and last points CurvIndex = index of curve parameters ------------------------------------------------------------------ } procedure PlotCurveWithErrorBars(Canvas : TCanvas; X, Y, S : PVector; Ns, Lb, Ub, CurvIndex : Integer); { ------------------------------------------------------------------ Plots a curve with error bars ------------------------------------------------------------------ Input parameters : X, Y = point coordinates S = errors Ns = number of SD to be plotted Lb, Ub = indices of first and last points CurvIndex = index of curve parameters ------------------------------------------------------------------ } procedure PlotFunc(Canvas : TCanvas; Func : TFunc; Xmin, Xmax : Float; Npt, CurvIndex : Integer); { ------------------------------------------------------------------ Plots a function ------------------------------------------------------------------ Input parameters: Func = function to be plotted Xmin, Xmax = abscissae of 1st and last point to plot Npt = number of points CurvIndex = index of curve parameters (Width, Style, Color) ------------------------------------------------------------------ The function must be programmed as : function Func(X : Float) : Float; ------------------------------------------------------------------ } procedure WriteLegend(Canvas : TCanvas; NCurv : Integer; ShowPoints, ShowLines : Boolean); { ------------------------------------------------------------------ Writes the legends for the plotted curves ------------------------------------------------------------------ NCurv : number of curves (1 to MaxCurv) ShowPoints : for displaying points ShowLines : for displaying lines ------------------------------------------------------------------ } procedure ConRec(Canvas : TCanvas; Nx, Ny, Nc : Integer; X, Y, Z : PVector; F : PMatrix); { ------------------------------------------------------------------ Contour plot Adapted from Paul Bourke, Byte, June 1987 http://astronomy.swin.edu.au/~pbourke/projection/conrec/ ------------------------------------------------------------------ Input parameters: Nx, Ny = number of steps on Ox and Oy Nc = number of contour levels X[0..Nx], Y[0..Ny] = point coordinates in pixels Z[0..(Nc - 1)] = contour levels in increasing order F[0..Nx, 0..Ny] = function values, such that F[I,J] is the function value at (X[I], Y[I]) ------------------------------------------------------------------ } function Xpixel(X : Float) : Integer; { ------------------------------------------------------------------ Converts user abscissa X to screen coordinate ------------------------------------------------------------------ } function Ypixel(Y : Float) : Integer; { ------------------------------------------------------------------ Converts user ordinate Y to screen coordinate ------------------------------------------------------------------ } function Xuser(X : Integer) : Float; { ------------------------------------------------------------------ Converts screen coordinate X to user abscissa ------------------------------------------------------------------ } function Yuser(Y : Integer) : Float; { ------------------------------------------------------------------ Converts screen coordinate Y to user ordinate ------------------------------------------------------------------ } procedure LeaveGraphics; { ------------------------------------------------------------------ Quits graphic mode ------------------------------------------------------------------ } implementation const MaxSymbol = 9; { Max. number of symbols for plotting curves } MaxCurvColor = 9; { Max. number of colors for curves } Eps = 1.0E-10; { Lower limit for an axis label } MaxColor = $02FFFFFF; { Max. color value for Delphi } const CurvColor : array[1..MaxCurvColor] of TColor = (clRed, clGreen, clBlue, clFuchsia, clAqua, clLime, clNavy, clOlive, clPurple); type TAxis = record { Coordinate axis } Scale : TScale; Min : Float; Max : Float; Step : Float; end; TPointParam = record { Point parameters } Symbol : Integer; { Symbol: 0: point (.) } Size : Integer; { 1: solid circle 2: open circle } Color : TColor; { 3: solid square 4: open square } end; { 5: solid triangle 6: open triangle } { 7: plus (+) 8: multiply (x) } { 9: star (* ) } TLineParam = record { Line parameters } Style : TPenStyle; Width : Integer; Color : TColor; end; TCurvParam = record { Curve parameters } PointParam : TPointParam; LineParam : TLineParam; Legend : Str30; { Legend of curve } Step : Integer; { Plot 1 point every Step points } end; TCurvParamVector = array[1..255] of TCurvParam; PCurvParamVector = ^TCurvParamVector; var Xwin1, Xwin2, Ywin1, Ywin2 : Integer; XminPixel, XmaxPixel : Integer; YminPixel, YmaxPixel : Integer; FactX, FactY : Float; XAxis, YAxis : TAxis; GraphTitle, XTitle, YTitle : String; MaxCurv : Integer; CurvParam : PCurvParamVector; GraphWidth, GraphHeight : Integer; SymbolSizeUnit : Integer; PenWidth : Integer; PenStyle : TPenStyle; PenColor, BrushColor : TColor; BrushStyle : TBrushStyle; procedure DimCurvParamVector(var CurvParam : PCurvParamVector; Ub : Byte); var I : Integer; begin { Allocate vector } GetMem(CurvParam, Ub * SizeOf(TCurvParam)); if CurvParam = nil then Exit; MaxCurv := Ub; { Initialize curve parameters } for I := 1 to Ub do with CurvParam^[I] do begin PointParam.Symbol := (I - 1) mod MaxSymbol + 1; PointParam.Size := 2; PointParam.Color := CurvColor[(I - 1) mod MaxCurvColor + 1]; Legend := 'Curve ' + LTrim(IntStr(I)); LineParam.Width := 1; LineParam.Style := psSolid; LineParam.Color := PointParam.Color; Step := 1; end; end; procedure DelCurvParamVector(var CurvParam : PCurvParamVector; Ub : Byte); begin if CurvParam <> nil then begin FreeMem(CurvParam, Ub * SizeOf(TCurvParam)); CurvParam := nil; MaxCurv := 0; end; end; function InitGraphics(Canvas : TCanvas; Width, Height : Integer) : Boolean; begin GraphWidth := Width; GraphHeight := Height; SymbolSizeUnit := GraphWidth div 250; XmaxPixel := Width; YmaxPixel := Height; XminPixel := 0; YminPixel := 0; XTitle := 'X'; YTitle := 'Y'; GraphTitle := ''; MaxCurv := MaxSymbol; DimCurvParamVector(CurvParam, MaxCurv); InitGraphics := True; end; procedure SetWindow(Canvas : TCanvas; X1, X2, Y1, Y2 : Integer; GraphBorder : Boolean); var R : Float; begin if (X1 >= 0) and (X2 <= 100) and (X1 < X2) then begin Xwin1 := X1; Xwin2 := X2; R := 0.01 * GraphWidth; XminPixel := Round(X1 * R); XmaxPixel := Round(X2 * R); end; if (Y1 >= 0) and (Y2 <= 100) and (Y1 < Y2) then begin Ywin1 := Y1; Ywin2 := Y2; R := 0.01 * GraphHeight; YminPixel := Round(Y1 * R); YmaxPixel := Round(Y2 * R); end; XAxis.Scale := LinScale; XAxis.Min := 0.0; XAxis.Max := 1.0; XAxis.Step := 0.2; YAxis.Scale := LinScale; YAxis.Min := 0.0; YAxis.Max := 1.0; YAxis.Step := 0.2; FactX := (XmaxPixel - XminPixel) / (XAxis.Max - XAxis.Min); FactY := (YmaxPixel - YminPixel) / (YAxis.Max - YAxis.Min); if GraphBorder then Canvas.Rectangle(XminPixel, YminPixel, Succ(XmaxPixel), Succ(YmaxPixel)); end; procedure AutoScale(X : PVector; Lb, Ub : Integer; Scale : TScale; var XMin, XMax, XStep : Float); var I : Integer; X1, X2 : Float; begin { Minimum and maximum of X } X1 := X^[Lb]; X2 := X1; for I := Lb to Ub do if X^[I] < X1 then X1 := X^[I] else if X^[I] > X2 then X2 := X^[I]; { Linear scale } if Scale = LinScale then begin Interval(X1, X2, 2, 6, XMin, XMax, XStep); Exit; end; { Logarithmic scale } XMin := 1.0E-3; XMax := 1.0E+3; XStep := 10.0; if X1 <= 0.0 then Exit; XMin := Int(Log10(X1)); if X1 < 1.0 then XMin := XMin - 1.0; XMax := Int(Log10(X2)); if X2 > 1.0 then XMax := XMax + 1.0; XMin := Exp10(XMin); XMax := Exp10(XMax); end; procedure SetOxScale(Scale : TScale; OxMin, OxMax, OxStep : Float); begin XAxis.Scale := Scale; case Scale of LinScale : begin if OxMin < OxMax then begin XAxis.Min := OxMin; XAxis.Max := OxMax; end; if OxStep > 0.0 then XAxis.Step := OxStep; end; LogScale : begin if (OxMin > 0.0) and (OxMin < OxMax) then begin XAxis.Min := Floor(Log10(OxMin)); XAxis.Max := Ceil(Log10(OxMax)); end; XAxis.Step := 1.0; end; end; FactX := (XmaxPixel - XminPixel) / (XAxis.Max - XAxis.Min); end; procedure SetOyScale(Scale : TScale; OyMin, OyMax, OyStep : Float); begin YAxis.Scale := Scale; case Scale of LinScale : begin if OyMin < OyMax then begin YAxis.Min := OyMin; YAxis.Max := OyMax; end; if OyStep > 0.0 then YAxis.Step := OyStep; end; LogScale : begin if (OyMin > 0.0) and (OyMin < OyMax) then begin YAxis.Min := Floor(Log10(OyMin)); YAxis.Max := Ceil(Log10(OyMax)); end; YAxis.Step := 1.0; end; end; FactY := (YmaxPixel - YminPixel) / (YAxis.Max - YAxis.Min); end; function Xpixel(X : Float) : Integer; var P : Float; begin P := FactX * (X - XAxis.Min); if Abs(P) > 30000 then Xpixel := 30000 else Xpixel := Round(P) + XminPixel; end; function Ypixel(Y : Float) : Integer; var P : Float; begin P := FactY * (YAxis.Max - Y); if Abs(P) > 30000 then Ypixel := 30000 else Ypixel := Round(P) + YminPixel; end; function Xuser(X : Integer) : Float; begin Xuser := XAxis.Min + (X - XminPixel) / FactX; end; function Yuser(Y : Integer) : Float; begin Yuser := YAxis.Max - (Y - YminPixel) / FactY; end; procedure SetGraphTitle(Title : String); begin GraphTitle := Title; end; procedure SetOxTitle(Title : String); begin XTitle := Title; end; procedure SetOyTitle(Title : String); begin YTitle := Title; end; procedure PlotLine(Canvas : TCanvas; X1, Y1, X2, Y2 : Integer); begin Canvas.MoveTo(X1, Y1); Canvas.LineTo(X2, Y2); end; procedure PlotOxAxis(Canvas : TCanvas); var W, X, Z : Float; Wp, Xp, Yp1, Yp2 : Integer; N, I, J : Integer; TickLength : Integer; MinorTickLength : Integer; XLabel : String; begin TickLength := Canvas.TextHeight('M') div 2; MinorTickLength := Round(0.67 * TickLength); PlotLine(Canvas, XminPixel, YmaxPixel, XmaxPixel, YmaxPixel); N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); { Nb of intervals } X := XAxis.Min; { Tick mark position } Yp1 := YmaxPixel + TickLength; { End of tick mark } Yp2 := YmaxPixel + MinorTickLength; { End of minor tick mark (log scale) } for I := 0 to N do { Label axis } begin if (XAxis.Scale = LinScale) and (Abs(X) < Eps) then X := 0.0; Xp := Xpixel(X); PlotLine(Canvas, Xp, YmaxPixel, Xp, Yp1); if XAxis.Scale = LinScale then Z := X else Z := Exp10(X); XLabel := Trim(FloatStr(Z)); Canvas.TextOut(Xp - Canvas.TextWidth(XLabel) div 2, Yp1, XLabel); { Plot minor divisions on logarithmic scale } if (XAxis.Scale = LogScale) and (I < N) then for J := 2 to 9 do begin W := X + Log10(J); Wp := Xpixel(W); PlotLine(Canvas, Wp, YmaxPixel, Wp, Yp2); end; X := X + XAxis.Step; end; { Write axis title } if XTitle <> '' then Canvas.TextOut(XminPixel + (XmaxPixel - XminPixel - Canvas.TextWidth(XTitle)) div 2, YmaxPixel + 4 * TickLength, XTitle); end; procedure PlotOyAxis(Canvas : TCanvas); var W, Y, Z : Float; Wp, Xp1, Xp2, Yp : Integer; N, I, J : Integer; TickLength : Integer; MinorTickLength : Integer; Yoffset : Integer; YLabel : String; begin TickLength := Canvas.TextWidth('M') div 2; MinorTickLength := Round(0.67 * TickLength); Yoffset := Canvas.TextHeight('M') div 2; PlotLine(Canvas, XminPixel, YminPixel, XminPixel, YmaxPixel); N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); Y := YAxis.Min; Xp1 := XminPixel - TickLength; Xp2 := XminPixel - MinorTickLength; for I := 0 to N do begin if (YAxis.Scale = LinScale) and (Abs(Y) < Eps) then Y := 0.0; Yp := Ypixel(Y); PlotLine(Canvas, XminPixel, Yp, Xp1, Yp); if YAxis.Scale = LinScale then Z := Y else Z := Exp10(Y); YLabel := Trim(FloatStr(Z)); Canvas.TextOut(Xp1 - Canvas.TextWidth(YLabel), Yp - Yoffset, YLabel); if (YAxis.Scale = LogScale) and (I < N) then for J := 2 to 9 do begin W := Y + Log10(J); Wp := Ypixel(W); PlotLine(Canvas, XminPixel, Wp, Xp2, Wp); end; Y := Y + YAxis.Step; end; if YTitle <> '' then Canvas.TextOut(XminPixel, YminPixel - 3 * Yoffset, YTitle); end; procedure PlotGrid(Canvas : TCanvas; Grid : TGrid); var X, Y : Float; I, N, Xp, Yp : Integer; var PenStyle : TpenStyle; begin PenStyle := Canvas.Pen.Style; Canvas.Pen.Style := psDot; if Grid in [HorizGrid, BothGrid] then { Horizontal lines } begin N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); { Nb of intervals } for I := 1 to Pred(N) do begin Y := YAxis.Min + I * YAxis.Step; { Origin of line } Yp := Ypixel(Y); PlotLine(Canvas, XminPixel, Yp, XmaxPixel, Yp); end; end; if Grid in [VertiGrid, BothGrid] then { Vertical lines } begin N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); for I := 1 to Pred(N) do begin X := XAxis.Min + I * XAxis.Step; Xp := Xpixel(X); PlotLine(Canvas, Xp, YminPixel, Xp, YmaxPixel); end; end; Canvas.Pen.Style := PenStyle; end; procedure WriteGraphTitle(Canvas : TCanvas); begin if GraphTitle <> '' then with Canvas do TextOut((XminPixel + XmaxPixel - TextWidth(GraphTitle)) div 2, YminPixel - 2 * TextHeight(GraphTitle), GraphTitle); end; procedure SetMaxCurv(NCurv : Byte); begin if NCurv < 1 then Exit; DelCurvParamVector(CurvParam, MaxCurv); MaxCurv := NCurv; DimCurvParamVector(CurvParam, MaxCurv); end; procedure SetPointParam(CurvIndex, Symbol, Size : Integer; Color : TColor); begin if (CurvIndex < 1) or (CurvIndex > MaxCurv) then Exit; if (Symbol >= 0) and (Symbol <= MaxSymbol) then CurvParam^[CurvIndex].PointParam.Symbol := Symbol; if Size > 0 then CurvParam^[CurvIndex].PointParam.Size := Size; if (Color >= 0) and (Color <= MaxColor) then CurvParam^[CurvIndex].PointParam.Color := Color; end; procedure SetLineParam(CurvIndex : Integer; Style : TPenStyle; Width : Integer; Color : TColor); begin if (CurvIndex < 1) or (CurvIndex > MaxCurv) then Exit; CurvParam^[CurvIndex].LineParam.Style := Style; if Width > 0 then CurvParam^[CurvIndex].LineParam.Width := Width; if (Color >= 0) and (Color <= MaxColor) then CurvParam^[CurvIndex].LineParam.Color := Color; end; procedure SetCurvLegend(CurvIndex : Integer; Legend : String); begin if (CurvIndex >= 1) and (CurvIndex <= MaxCurv) then CurvParam^[CurvIndex].Legend := Legend; end; procedure SetCurvStep(CurvIndex, Step : Integer); begin if (CurvIndex >= 1) and (CurvIndex <= MaxCurv) and (Step > 0) then CurvParam^[CurvIndex].Step := Step; end; function XOutOfBounds(X : Integer) : Boolean; { Checks if an absissa is outside the graphic bounds } begin XOutOfBounds := (X < XminPixel) or (X > XmaxPixel); end; function YOutOfBounds(Y : Integer) : Boolean; { Checks if an ordinate is outside the graphic bounds } begin YOutOfBounds := (Y < YminPixel) or (Y > YmaxPixel); end; function CheckPoint(X, Y : Float; var Xp, Yp : Integer) : Boolean; { Computes the pixel coordinates of a point and checks if it is enclosed within the graph limits } begin Xp := Xpixel(X); Yp := Ypixel(Y); CheckPoint := not(XOutOfBounds(Xp) or YOutOfBounds(Yp)); end; procedure PlotSymbol(Canvas : TCanvas; Xp, Yp, CurvIndex : Integer); var Xp1, Xp2, Yp1, Yp2, Size : Integer; begin Size := CurvParam^[CurvIndex].PointParam.Size * SymbolSizeUnit; Xp1 := Xp - Size; Yp1 := Yp - Size; Xp2 := Xp + Size + 1; Yp2 := Yp + Size + 1; with Canvas do case CurvParam^[CurvIndex].PointParam.Symbol of 0 : Pixels[Xp, Yp] := Brush.Color; 1, 2 : Ellipse(Xp1, Yp1, Xp2, Yp2); { Circle } 3, 4 : Rectangle(Xp1, Yp1, Xp2, Yp2); { Square } 5, 6 : Polygon([Point(Xp1, Yp2 - 1), Point(Xp2, Yp2 - 1), Point(Xp, Yp1 - 1)]); { Triangle } 7 : begin { + } PlotLine(Canvas, Xp, Yp1, Xp, Yp2); PlotLine(Canvas, Xp1, Yp, Xp2, Yp); end; 8 : begin { x } PlotLine(Canvas, Xp1, Yp1, Xp2, Yp2); PlotLine(Canvas, Xp1, Yp2 - 1, Xp2, Yp1 - 1); end; 9 : begin { * } PlotLine(Canvas, Xp, Yp1, Xp, Yp2); PlotLine(Canvas, Xp1, Yp, Xp2, Yp); PlotLine(Canvas, Xp1, Yp1, Xp2, Yp2); PlotLine(Canvas, Xp1, Yp2 - 1, Xp2, Yp1 - 1); end; end; end; procedure SetGraphSettings(Canvas : TCanvas; CurvIndex : Integer); { Saves the current graphic properties of the Canvas and sets them to the values of curve # CurvIndex } begin PenColor := Canvas.Pen.Color; PenStyle := Canvas.Pen.Style; PenWidth := Canvas.Pen.Width; BrushColor := Canvas.Brush.Color; BrushStyle := Canvas.Brush.Style; Canvas.Pen.Color := CurvParam^[CurvIndex].LineParam.Color; Canvas.Pen.Style := CurvParam^[CurvIndex].LineParam.Style; Canvas.Pen.Width := CurvParam^[CurvIndex].LineParam.Width; Canvas.Brush.Color := CurvParam^[CurvIndex].PointParam.Color; if CurvParam^[CurvIndex].PointParam.Symbol in [0, 1, 3, 5] then Canvas.Brush.Style := bsSolid else Canvas.Brush.Style := bsClear; end; procedure RestoreGraphSettings(Canvas : TCanvas); begin Canvas.Pen.Color := PenColor; Canvas.Pen.Style := PenStyle; Canvas.Pen.Width := PenWidth; Canvas.Brush.Color := BrushColor; Canvas.Brush.Style := BrushStyle; end; procedure PlotPoint(Canvas : TCanvas; X, Y : Float; CurvIndex : Integer); var Xp, Yp : Integer; begin if XAxis.Scale = LogScale then X := Log10(X); if YAxis.Scale = LogScale then Y := Log10(Y); if not CheckPoint(X, Y, Xp, Yp) then Exit; SetGraphSettings(Canvas, CurvIndex); PlotSymbol(Canvas, Xp, Yp, CurvIndex); RestoreGraphSettings(Canvas); end; procedure PlotErrorBar(Canvas : TCanvas; Y, S : Float; Ns, Xp, Yp, Size : Integer); { Plots an error bar with the current canvas settings } var Delta, Y1 : Float; Yp1 : Integer; PenStyle : TPenStyle; begin Size := Size * SymbolSizeUnit; PenStyle := Canvas.Pen.Style; Canvas.Pen.Style := psSolid; Delta := Ns * S; Y1 := Y - Delta; if YAxis.Scale = LogScale then Y1 := Log10(Y1); Yp1 := Ypixel(Y1); if Yp1 <= YmaxPixel then begin PlotLine(Canvas, Xp - Size, Yp1, Xp + Size + 1, Yp1); PlotLine(Canvas, Xp, Yp, Xp, Yp1); end else PlotLine(Canvas, Xp, Yp, Xp, YmaxPixel); Y1 := Y + Delta; if YAxis.Scale = LogScale then Y1 := Log10(Y1); Yp1 := Ypixel(Y1); if Yp1 >= YminPixel then begin PlotLine(Canvas, Xp - Size, Yp1, Xp + Size + 1, Yp1); PlotLine(Canvas, Xp, Yp, Xp, Yp1); end else PlotLine(Canvas, Xp, Yp, Xp, YminPixel); Canvas.Pen.Style := PenStyle; end; procedure GenPlotCurve(Canvas : TCanvas; X, Y, S : PVector; Ns, Lb, Ub, CurvIndex : Integer; ErrorBars : Boolean); { General curve plotting routine } var X1, Y1, X2, Y2 : Float; Xp1, Yp1, Xp2, Yp2 : Integer; I : Integer; Flag1, Flag2 : Boolean; begin SetGraphSettings(Canvas, CurvIndex); { Plot first point } X1 := X^[Lb]; if XAxis.Scale = LogScale then X1 := Log10(X1); Y1 := Y^[Lb]; if YAxis.Scale = LogScale then Y1 := Log10(Y1); Flag1 := CheckPoint(X1, Y1, Xp1, Yp1); if Flag1 then begin PlotSymbol(Canvas, Xp1, Yp1, CurvIndex); if ErrorBars and (S^[Lb] > 0.0) then PlotErrorBar(Canvas, Y^[Lb], S^[Lb], Ns, Xp1, Yp1, CurvIndex); end; { Plot other points and connect them by lines if necessary } I := Lb + CurvParam^[CurvIndex].Step; while I <= Ub do begin X2 := X^[I]; if XAxis.Scale = LogScale then X2 := Log10(X2); Y2 := Y^[I]; if YAxis.Scale = LogScale then Y2 := Log10(Y2); Flag2 := CheckPoint(X2, Y2, Xp2, Yp2); if Flag2 then begin PlotSymbol(Canvas, Xp2, Yp2, CurvIndex); if ErrorBars and (S^[I] > 0.0) then PlotErrorBar(Canvas, Y^[I], S^[I], Ns, Xp2, Yp2, CurvIndex); if (CurvParam^[CurvIndex].LineParam.Style <> psClear) and Flag1 then PlotLine(Canvas, Xp1, Yp1, Xp2, Yp2); end; Xp1 := Xp2; Yp1 := Yp2; Flag1 := Flag2; Inc(I, CurvParam^[CurvIndex].Step); end; RestoreGraphSettings(Canvas); end; procedure PlotCurve(Canvas : TCanvas; X, Y : PVector; Lb, Ub : Integer; CurvIndex : Integer); begin GenPlotCurve(Canvas, X, Y, nil, 0, Lb, Ub, CurvIndex, False); end; procedure PlotCurveWithErrorBars(Canvas : TCanvas; X, Y, S : PVector; Ns : Integer; Lb, Ub : Integer; CurvIndex : Integer); begin GenPlotCurve(Canvas, X, Y, S, Ns, Lb, Ub, CurvIndex, True); end; procedure PlotFunc(Canvas : TCanvas; Func : TFunc; Xmin, Xmax : Float; Npt : Integer; CurvIndex : Integer); var X1, Y1, X2, Y2, H : Float; Xp1, Yp1, Xp2, Yp2 : Integer; Flag1, Flag2 : Boolean; I : Integer; begin if (Npt < 2) or (CurvParam^[CurvIndex].LineParam.Style = psClear) then Exit; if Xmin >= Xmax then begin Xmin := XAxis.Min; Xmax := XAxis.Max; end; H := (Xmax - Xmin) / Npt; SetGraphSettings(Canvas, CurvIndex); { Check first point } X1 := Xmin; if XAxis.Scale = LinScale then Y1 := Func(X1) else Y1 := Func(Exp10(X1)); if YAxis.Scale = LogScale then Y1 := Log10(Y1); Flag1 := CheckPoint(X1, Y1, Xp1, Yp1); { Check other points and plot lines if possible } for I := 1 to Npt do begin X2 := X1 + H; if XAxis.Scale = LinScale then Y2 := Func(X2) else Y2 := Func(Exp10(X2)); if YAxis.Scale = LogScale then Y2 := Log10(Y2); Flag2 := CheckPoint(X2, Y2, Xp2, Yp2); if Flag1 and Flag2 then PlotLine(Canvas, Xp1, Yp1, Xp2, Yp2); X1 := X2; Xp1 := Xp2; Yp1 := Yp2; Flag1 := Flag2; end; RestoreGraphSettings(Canvas); end; procedure WriteLegend(Canvas : TCanvas; NCurv : Integer; ShowPoints, ShowLines : Boolean); var CharHeight, I, L, Lmax : Integer; N, Nmax, Xp, Xl, Y : Integer; begin N := 0; { Nb of legends to be plotted } Lmax := 0; { Length of the longest legend } for I := 1 to NCurv do if CurvParam^[I].Legend <> '' then begin Inc(N); L := Canvas.TextWidth(CurvParam^[I].Legend); if L > Lmax then Lmax := L; end; if (N = 0) or (Lmax = 0) then Exit; { Character height } CharHeight := Canvas.TextHeight('M'); { Max. number of legends which may be plotted } Nmax := Round((YmaxPixel - YminPixel) / CharHeight) - 1; if N > Nmax then N := Nmax; { Draw rectangle around the legends } Canvas.Rectangle(XmaxPixel + Round(0.02 * GraphWidth), YminPixel, XmaxPixel + Round(0.12 * GraphWidth) + Lmax, YminPixel + (N + 1) * CharHeight); L := Round(0.02 * GraphWidth); { Half-length of line } Xp := XmaxPixel + 3 * L; { Position of symbol } Xl := XmaxPixel + 5 * L; { Position of legend } if NCurv <= Nmax then N := NCurv else N := Nmax; for I := 1 to N do with Canvas do begin SetGraphSettings(Canvas, I); { Plot point and line } Y := YminPixel + I * CharHeight; if ShowPoints then PlotSymbol(Canvas, Xp, Y, I); if ShowLines then PlotLine(Canvas, Xp - L, Y, Xp + L, Y); { Write legend } Brush.Style := bsClear; Canvas.TextOut(Xl, Y - CharHeight div 2, CurvParam^[I].Legend); end; RestoreGraphSettings(Canvas); end; procedure ConRec(Canvas : TCanvas; Nx, Ny, Nc : Integer; X, Y, Z : PVector; F : PMatrix); const { Mapping from vertex numbers to X offsets } Im : array[0..3] of Integer = (0, 1, 1, 0); { Mapping from vertex numbers to Y offsets } Jm : array[0..3] of Integer = (0, 0, 1, 1); { Case switch table } CasTab : array[0..2, 0..2, 0..2] of Integer = (((0,0,8), (0,2,5), (7,6,9)), ((0,3,4), (1,3,1), (4,3,0)), ((9,6,7), (5,2,0), (8,0,0))); var I, J, K, M, M1, M2, M3 : Integer; X1, X2, Y1, Y2 : Float; Fmin, Fmax : Float; Xp, Yp : PIntVector; PrmErr : Boolean; var H : array[0..4] of Float; { Relative heights of the box above contour } Ish : array[0..4] of Integer; { Sign of H() } Xh : array[0..4] of Integer; { X coordinates of box } Yh : array[0..4] of Integer; { Y coordinates of box } label Case0, NoneInTri, NoneInBox; begin { Check the input parameters for validity } PrmErr := False; SetErrCode(MatOk); if (Nx <= 0) or (Ny <= 0) or (Nc <= 0) then PrmErr := True; for K := 1 to Nc - 1 do if Z^[K] <= Z^[K - 1] then PrmErr := True; if PrmErr then begin SetErrCode(MatErrDim); Exit; end; { Convert user coordinates to pixels } DimIntVector(Xp, Nx); DimIntVector(Yp, Ny); for I := 0 to Nx do Xp^[I] := Xpixel(X^[I]); for J := 0 to Ny do Yp^[J] := Ypixel(Y^[J]); { Scan the array, top down, left to right } for J := Ny - 1 downto 0 do begin for I := 0 to Nx - 1 do begin { Find the lowest vertex } if F^[I]^[J] < F^[I]^[J + 1] then Fmin := F^[I]^[J] else Fmin := F^[I]^[J + 1]; if F^[I + 1]^[J] < Fmin then Fmin := F^[I + 1]^[J]; if F^[I + 1]^[J + 1] < Fmin then Fmin := F^[I + 1]^[J + 1]; { Find the highest vertex } if F^[I]^[J] > F^[I]^[J + 1] then Fmax := F^[I]^[J] else Fmax := F^[I]^[J + 1]; if F^[I + 1]^[J] > Fmax then Fmax := F^[I + 1]^[J]; if F^[I + 1]^[J + 1] > Fmax then Fmax := F^[I + 1]^[J + 1]; if (Fmax < Z^[0]) or (Fmin > Z^[Nc - 1]) then goto NoneInBox; { Draw each contour within this box } for K := 0 to Nc - 1 do begin if (Z^[K] < Fmin) or (Z^[K] > Fmax) then goto NoneInTri; for M := 4 downto 0 do begin if M > 0 then begin H[M] := F^[I + Im[M - 1]]^[J + Jm[M - 1]] - Z^[K]; Xh[M] := Xp^[I + Im[M - 1]]; Yh[M] := Yp^[J + Jm[M - 1]]; end; if M = 0 then begin H[0] := (H[1] + H[2] + H[3] + H[4]) / 4; Xh[0] := (Xp^[I] + Xp^[I + 1]) div 2; Yh[0] := (Yp^[J] + Yp^[J + 1]) div 2; end; if H[M] > 0 then Ish[M] := 2; if H[M] < 0 then Ish[M] := 0; if H[M] = 0 then Ish[M] := 1; end; { next M } { Scan each triangle in the box } X1 := 0.0; X2 := 0.0; Y1 := 0.0; Y2 := 0.0; for M := 1 to 4 do begin M1 := M; M2 := 0; M3 := M + 1; if M3 = 5 then M3 := 1; case CasTab[Ish[M1], Ish[M2], Ish[M3]] of 0 : goto Case0; { Line between vertices M1 and M2 } 1 : begin X1 := Xh[M1]; Y1 := Yh[M1]; X2 := Xh[M2]; Y2 := Yh[M2]; end; { Line between vertices M2 and M3 } 2 : begin X1 := Xh[M2]; Y1 := Yh[M2]; X2 := Xh[M3]; Y2 := Yh[M3]; end; { Line between vertices M3 and M1 } 3 : begin X1 := Xh[M3]; Y1 := Yh[M3]; X2 := Xh[M1]; Y2 := Yh[M1]; end; { Line between vertex M1 and side M2-M3 } 4 : begin X1 := Xh[M1]; Y1 := Yh[M1]; X2 := (H[M3] * Xh[M2] - H[M2] * Xh[M3]) / (H[M3] - H[M2]); Y2 := (H[M3] * Yh[M2] - H[M2] * Yh[M3]) / (H[M3] - H[M2]); end; { Line between vertex M2 and side M3-M1 } 5 : begin X1 := Xh[M2]; Y1 := Yh[M2]; X2 := (H[M1] * Xh[M3] - H[M3] * Xh[M1]) / (H[M1] - H[M3]); Y2 := (H[M1] * Yh[M3] - H[M3] * Yh[M1]) / (H[M1] - H[M3]); end; { Line between vertex M3 and side M1-M2 } 6 : begin X1 := Xh[M3]; Y1 := Yh[M3]; X2 := (H[M2] * Xh[M1] - H[M1] * Xh[M2]) / (H[M2] - H[M1]); Y2 := (H[M2] * Yh[M1] - H[M1] * Yh[M2]) / (H[M2] - H[M1]); end; { Line between sides M1-M2 and M2-M3 } 7 : begin X1 := (H[M2] * Xh[M1] - H[M1] * Xh[M2]) / (H[M2] - H[M1]); Y1 := (H[M2] * Yh[M1] - H[M1] * Yh[M2]) / (H[M2] - H[M1]); X2 := (H[M3] * Xh[M2] - H[M2] * Xh[M3]) / (H[M3] - H[M2]); Y2 := (H[M3] * Yh[M2] - H[M2] * Yh[M3]) / (H[M3] - H[M2]); end; { Line between sides M2-M3 and M3-M1 } 8 : begin X1 := (H[M3] * Xh[M2] - H[M2] * Xh[M3]) / (H[M3] - H[M2]); Y1 := (H[M3] * Yh[M2] - H[M2] * Yh[M3]) / (H[M3] - H[M2]); X2 := (H[M1] * Xh[M3] - H[M3] * Xh[M1]) / (H[M1] - H[M3]); Y2 := (H[M1] * Yh[M3] - H[M3] * Yh[M1]) / (H[M1] - H[M3]); end; { Line between sides M3-M1 and M1-M2 } 9 : begin X1 := (H[M1] * Xh[M3] - H[M3] * Xh[M1]) / (H[M1] - H[M3]); Y1 := (H[M1] * Yh[M3] - H[M3] * Yh[M1]) / (H[M1] - H[M3]); X2 := (H[M2] * Xh[M1] - H[M1] * Xh[M2]) / (H[M2] - H[M1]); Y2 := (H[M2] * Yh[M1] - H[M1] * Yh[M2]) / (H[M2] - H[M1]); end; end; { case } Canvas.Pen.Color := CurvParam^[K mod MaxCurv + 1].LineParam.Color; PlotLine(Canvas, Trunc(X1), Trunc(Y1), Trunc(X2), Trunc(Y2)); Case0: end; { next M } NoneInTri: end; { next K } NoneInBox: end; { next I } end; { next J } end; procedure LeaveGraphics; begin DelCurvParamVector(CurvParam, MaxCurv); end; end. �����������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/unlfit.pas��������������������������������������������������0000755�0001750�0001750�00000045332�11326425446�017506� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Nonlinear regression ****************************************************************** } unit unlfit; interface uses utypes, ugausjor, umarq, ubfgs, usimplex, usimann, ugenalg, umcmc, ustrings; procedure SetOptAlgo(Algo : TOptAlgo); { ---------------------------------------------------------------------- Sets the optimization algorithm according to Algo, which must be NL_MARQ, NL_SIMP, NL_BFGS, NL_SA, NL_GA. Default is NL_MARQ ---------------------------------------------------------------------- } procedure SetMaxParam(N : Byte); { ---------------------------------------------------------------------- Sets the maximum number of regression parameters ---------------------------------------------------------------------- } procedure SetParamBounds(I : Byte; ParamMin, ParamMax : Float); { ---------------------------------------------------------------------- Sets the bounds on the I-th regression parameter ---------------------------------------------------------------------- } procedure NLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; B : PVector; FirstPar, LastPar : Integer; V : PMatrix); { ------------------------------------------------------------------ Unweighted nonlinear regression ------------------------------------------------------------------ Input parameters: RegFunc = regression function DerivProc = procedure to compute derivatives X, Y = point coordinates Lb, Ub = array bounds MaxIter = max. number of iterations Tol = tolerance on parameters B = initial parameter values FirstPar = index of first regression parameter LasttPar = index of last regression parameter Output parameters: B = fitted regression parameters V = inverse matrix ------------------------------------------------------------------ } procedure WNLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y, S : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; B : PVector; FirstPar, LastPar : Integer; V : PMatrix); { ---------------------------------------------------------------------- Weighted nonlinear regression ---------------------------------------------------------------------- S = standard deviations of observations Other parameters as in NLFit ---------------------------------------------------------------------- } procedure SetMCFile(FileName : String); { ---------------------------------------------------------------------- Set file for saving MCMC simulations ---------------------------------------------------------------------- } procedure SimFit(RegFunc : TRegFunc; X, Y : PVector; Lb, Ub : Integer; B : PVector; FirstPar, LastPar : Integer; V : PMatrix); { ------------------------------------------------------------------ Simulation of unweighted nonlinear regression by MCMC ------------------------------------------------------------------ } procedure WSimFit(RegFunc : TRegFunc; X, Y, S : PVector; Lb, Ub : Integer; B : PVector; FirstPar, LastPar : Integer; V : PMatrix); { ---------------------------------------------------------------------- Simulation of weighted nonlinear regression by MCMC ------------------------------------------------------------------ } implementation type TRegMode = (UNWEIGHTED, WEIGHTED); const MAX_BOUND = 1.0E+6; { Default parameter bound } MAX_FUNC = 1.0E+30; { Max. value for objective function (used to prevent overflow) } const MaxParam : Byte = 10; { Max. index of fitted parameter } OptAlgo : TOptAlgo = NL_MARQ; { Optimization algorithm } MCFile : String = 'mcmc.txt'; { File for saving MCMC simulations } { Global variables used by the nonlinear regression routines } const gLb : Integer = 0; { Index of first point } gUb : Integer = 0; { Index of last point } gX : PVector = nil; { X coordinates } gY : PVector = nil; { Y coordinates } gW : PVector = nil; { Weights } gYcalc : PVector = nil; { Estimated Y values } gR : PVector = nil; { Residuals (Y - Ycalc) } gFirstPar : Integer = 0; { Index of first fitted parameter } gLastPar : Integer = 0; { Index of last fitted parameter } gBmin : PVector = nil; { Lower bounds on parameters } gBmax : PVector = nil; { Higher bounds on parameters } gD : PVector = nil; { Derivatives of regression function } var gRegFunc : TRegFunc; { Regression function } gDerivProc : TDerivProc; { Derivation procedure } procedure SetOptAlgo(Algo : TOptAlgo); begin OptAlgo := Algo; end; procedure SetMaxParam(N : Byte); begin if N < 1 then Exit; DelVector(gBmin, MaxParam); DelVector(gBmax, MaxParam); DimVector(gBmin, N); DimVector(gBmax, N); MaxParam := N; end; procedure SetParamBounds(I : Byte; ParamMin, ParamMax : Float); begin if gBmin = nil then DimVector(gBmin, MaxParam); if gBmax = nil then DimVector(gBmax, MaxParam); if (I < 0) or (I > MaxParam) or (ParamMin >= ParamMax) then Exit; gBmin^[I] := ParamMin; gBmax^[I] := ParamMax; end; procedure SetGlobalVar(Mode : TRegMode; RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y, S : PVector; Lb, Ub : Integer; FirstPar, LastPar : Integer); { Checks the data and sets the global variables } var I, Npar, Npts : Integer; begin if LastPar > MaxParam then begin SetErrCode(NLMaxPar); Exit; end; Npts := Ub - Lb + 1; { Number of points } Npar := LastPar - FirstPar + 1; { Number of parameters } if Npts <= Npar then begin SetErrCode(MatErrDim); Exit; end; if Mode = WEIGHTED then for I := Lb to Ub do if S^[I] <= 0.0 then begin SetErrCode(MatSing); Exit; end; DelVector(gX, gUb); DelVector(gY, gUb); DelVector(gW, gUb); DelVector(gYcalc, gUb); DelVector(gR, gUb); DimVector(gX, Ub); DimVector(gY, Ub); DimVector(gW, Ub); DimVector(gYcalc, Ub); DimVector(gR, Ub); for I := Lb to Ub do begin gX^[I] := X^[I]; gY^[I] := Y^[I]; end; if Mode = WEIGHTED then for I := Lb to Ub do gW^[I] := 1.0 / Sqr(S^[I]); if gBmin = nil then DimVector(gBmin, MaxParam); if gBmax = nil then DimVector(gBmax, MaxParam); for I := FirstPar to LastPar do if gBmin^[I] >= gBmax^[I] then begin gBmin^[I] := - MAX_BOUND; gBmax^[I] := MAX_BOUND; end; DelVector(gD, gLastPar); DimVector(gD, LastPar); gLb := Lb; gUb := Ub; gFirstPar := FirstPar; gLastPar := LastPar; gRegFunc := RegFunc; gDerivProc := DerivProc; SetErrCode(MatOk); end; function OutOfBounds(B : PVector) : Boolean; { Check if the parameters are inside the bounds } var I : Integer; OoB : Boolean; begin I := gFirstPar; repeat OoB := (B^[I] < gBmin^[I]) or (B^[I] > gBmax^[I]); Inc(I); until OoB or (I > gLastPar); OutOfBounds := OoB; end; function OLS_ObjFunc(B : PVector) : Float; { Objective function for unweighted nonlinear regression } var K : Integer; S : Float; begin if OutOfBounds(B) then begin OLS_ObjFunc := MAX_FUNC; Exit; end; S := 0.0; K := gLb; repeat gYcalc^[K] := gRegFunc(gX^[K], B); gR^[K] := gY^[K] - gYcalc^[K]; S := S + Sqr(gR^[K]); Inc(K); until (K > gUb) or (S > MAX_FUNC); if S > MAX_FUNC then S := MAX_FUNC; OLS_ObjFunc := S; end; procedure OLS_Gradient(B, G : PVector); { Gradient for unweighted nonlinear regression } var I, K : Integer; { Loop variables } begin { Initialization } for I := gFirstPar to gLastPar do G^[I] := 0.0; { Compute Gradient } for K := gLb to gUb do begin gDerivProc(gX^[K], gYcalc^[K], B, gD); for I := gFirstPar to gLastPar do G^[I] := G^[I] - gD^[I] * gR^[K]; end; for I := gFirstPar to gLastPar do G^[I] := 2.0 * G^[I]; end; procedure OLS_HessGrad(B, G : PVector; H : PMatrix); { Gradient and Hessian for unweighted nonlinear regression } var I, J, K : Integer; { Loop variables } begin { Initializations } for I := gFirstPar to gLastPar do begin G^[I] := 0.0; for J := I to gLastPar do H^[I]^[J] := 0.0; end; { Compute Gradient & Hessian } for K := gLb to gUb do begin gDerivProc(gX^[K], gYcalc^[K], B, gD); for I := gFirstPar to gLastPar do begin G^[I] := G^[I] - gD^[I] * gR^[K]; for J := I to gLastPar do H^[I]^[J] := H^[I]^[J] + gD^[I] * gD^[J]; end; end; { Fill in symmetric matrix } for I := Succ(gFirstPar) to gLastPar do for J := gFirstPar to Pred(I) do H^[I]^[J] := H^[J]^[I]; end; function WLS_ObjFunc(B : PVector) : Float; { Objective function for weighted nonlinear regression } var K : Integer; S : Float; begin if OutOfBounds(B) then begin WLS_ObjFunc := MAX_FUNC; Exit; end; S := 0.0; K := gLb; repeat gYcalc^[K] := gRegFunc(gX^[K], B); gR^[K] := gY^[K] - gYcalc^[K]; S := S + gW^[K] * Sqr(gR^[K]); Inc(K); until (K > gUb) or (S > MAX_FUNC); if S > MAX_FUNC then S := MAX_FUNC; WLS_ObjFunc := S; end; procedure WLS_Gradient(B, G : PVector); { Gradient for weighted nonlinear regression } var I, K : Integer; { Loop variables } WR : Float; { Weighted residual } begin { Initialization } for I := gFirstPar to gLastPar do G^[I] := 0.0; { Compute Gradient } for K := gLb to gUb do begin WR := gW^[K] * gR^[K]; gDerivProc(gX^[K], gYcalc^[K], B, gD); for I := gFirstPar to gLastPar do G^[I] := G^[I] - gD^[I] * WR; end; for I := gFirstPar to gLastPar do G^[I] := 2.0 * G^[I]; end; procedure WLS_HessGrad(B, G : PVector; H : PMatrix); { Gradient and Hessian for weighted nonlinear regression } var I, J, K : Integer; { Loop variables } WR, WD : Float; { Weighted residual and derivative } begin { Initializations } for I := gFirstPar to gLastPar do begin G^[I] := 0.0; for J := I to gLastPar do H^[I]^[J] := 0.0; end; { Compute Gradient & Hessian } for K := gLb to gUb do begin WR := gW^[K] * gR^[K]; gDerivProc(gX^[K], gYcalc^[K], B, gD); for I := gFirstPar to gLastPar do begin G^[I] := G^[I] - gD^[I] * WR; WD := gW^[K] * gD^[I]; for J := I to gLastPar do H^[I]^[J] := H^[I]^[J] + WD * gD^[J]; end; end; { Fill in symmetric matrix } for I := Succ(gFirstPar) to gLastPar do for J := gFirstPar to Pred(I) do H^[I]^[J] := H^[J]^[I]; end; procedure GenNLFit(Mode : TRegMode; RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y, S : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; B : PVector; FirstPar, LastPar : Integer; V : PMatrix); { -------------------------------------------------------------------- General nonlinear regression routine -------------------------------------------------------------------- } var F_min : Float; { Value of objective function at minimum } G : PVector; { Gradient vector } Det : Float; { Determinant of Hessian matrix } ObjFunc : TFuncNVar; { Objective function } GradProc : TGradient; { Procedure to compute gradient } HessProc : THessGrad; { Procedure to compute gradient and hessian } begin SetGlobalVar(Mode, RegFunc, DerivProc, X, Y, S, Lb, Ub, FirstPar, LastPar); if MathErr <> MatOk then Exit; if Mode = UNWEIGHTED then begin ObjFunc := {$IFDEF FPC}@{$ENDIF}OLS_ObjFunc; GradProc := {$IFDEF FPC}@{$ENDIF}OLS_Gradient; HessProc := {$IFDEF FPC}@{$ENDIF}OLS_HessGrad; end else begin ObjFunc := {$IFDEF FPC}@{$ENDIF}WLS_ObjFunc; GradProc := {$IFDEF FPC}@{$ENDIF}WLS_Gradient; HessProc := {$IFDEF FPC}@{$ENDIF}WLS_HessGrad; end; DimVector(G, LastPar); case OptAlgo of NL_MARQ : Marquardt(ObjFunc, HessProc, B, FirstPar, LastPar, MaxIter, Tol, F_min, G, V, Det); NL_SIMP : Simplex(ObjFunc, B, FirstPar, LastPar, MaxIter, Tol, F_min); NL_BFGS : BFGS(ObjFunc, GradProc, B, FirstPar, LastPar, MaxIter, Tol, F_min, G, V); NL_SA : SimAnn(ObjFunc, B, gBmin, gBmax, FirstPar, LastPar, F_min); NL_GA : GenAlg(ObjFunc, B, gBmin, gBmax, FirstPar, LastPar, F_min); end; if (OptAlgo <> NL_MARQ) and (MathErr = MatOk) then begin { Compute the Hessian matrix and its inverse } HessProc(B, G, V); GaussJordan(V, FirstPar, LastPar, LastPar, Det); end; DelVector(G, LastPar); end; procedure NLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; B : PVector; FirstPar, LastPar : Integer; V : PMatrix); begin GenNLFit(UNWEIGHTED, RegFunc, DerivProc, X, Y, nil, Lb, Ub, MaxIter, Tol, B, FirstPar, LastPar, V); end; procedure WNLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y, S : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; B : PVector; FirstPar, LastPar : Integer; V : PMatrix); begin GenNLFit(WEIGHTED, RegFunc, DerivProc, X, Y, S, Lb, Ub, MaxIter, Tol, B, FirstPar, LastPar, V); end; procedure SetMCFile(FileName : String); begin MCFile := FileName; end; procedure GenSimFit(Mode : TRegMode; RegFunc : TRegFunc; X, Y, S : PVector; Lb, Ub : Integer; B : PVector; FirstPar, LastPar : Integer; V : PMatrix); var ObjFunc : TFuncNVar; { Objective function } NCycles, MaxSim, SavedSim : Integer; { Metropolis-Hastings parameters } Xmat : PMatrix; { Matrix of simulated parameters } F_min : Float; { Value of objective function at minimum } B_min : PVector; { Parameter values at minimum } R : Float; { Range of parameter values } I, J : Integer; { Loop variables } F : Text; { File for storing MCMC simulations } begin SetGlobalVar(Mode, RegFunc, nil, X, Y, S, Lb, Ub, FirstPar, LastPar); if MathErr <> MatOk then Exit; { Initialize variance-covariance matrix } for I := FirstPar to LastPar do begin R := gBmax^[I] - gBmin^[I]; B^[I] := gBmin^[I] + 0.5 * R; for J := FirstPar to LastPar do if I = J then { The parameter range is assumed to cover 6 SD's } V^[I]^[J] := R * R / 36.0 else V^[I]^[J] := 0.0; end; if Mode = UNWEIGHTED then ObjFunc := {$IFDEF FPC}@{$ENDIF}OLS_ObjFunc else ObjFunc := {$IFDEF FPC}@{$ENDIF}WLS_ObjFunc; GetMHParams(NCycles, MaxSim, SavedSim); DimMatrix(Xmat, SavedSim, LastPar); DimVector(B_min, LastPar); Hastings(ObjFunc, 2.0, B, V, FirstPar, LastPar, Xmat, B_min, F_min); if MathErr = MatOk then { Save simulations } begin Assign(F, MCFile); Rewrite(F); for I := 1 to SavedSim do begin Write(F, IntStr(I)); for J := FirstPar to LastPar do Write(F, FloatStr(Xmat^[I]^[J])); Writeln(F); end; Close(F); end; DelMatrix(Xmat, SavedSim, LastPar); end; procedure SimFit(RegFunc : TRegFunc; X, Y : PVector; Lb, Ub : Integer; B : PVector; FirstPar, LastPar : Integer; V : PMatrix); begin GenSimFit(UNWEIGHTED, RegFunc, X, Y, nil, Lb, Ub, B, FirstPar, LastPar, V); end; procedure WSimFit(RegFunc : TRegFunc; X, Y, S : PVector; Lb, Ub : Integer; B : PVector; FirstPar, LastPar : Integer; V : PMatrix); begin GenSimFit(WEIGHTED, RegFunc, X, Y, S, Lb, Ub, B, FirstPar, LastPar, V); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/usecant.pas�������������������������������������������������0000755�0001750�0001750�00000002127�11326425446�017642� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Secant method for nonlinear equation ****************************************************************** } unit usecant; interface uses utypes; procedure Secant (Func : TFunc; var X, Y : Float; MaxIter : Integer; Tol : Float; var F : Float); implementation procedure Secant (Func : TFunc; var X, Y : Float; MaxIter : Integer; Tol : Float; var F : Float); var Iter : Integer; G, Z : Float; begin Iter := 0; SetErrCode(OptOk); repeat F := Func(X); if MaxIter < 1 then Exit; G := Func(Y); Iter := Iter + 1; if (F = G) or (Iter > MaxIter) then begin SetErrCode(OptNonConv); Exit; end; Z := (X * G - Y * F) / (G - F); X := Y; Y := Z; until Abs(X - Y) < Tol * (Abs(X) + Abs(Y)); X := 0.5 * (X + Y); F := Func(X); end; end.�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/lgpl.txt����������������������������������������������������0000755�0001750�0001750�00000064466�11326425444�017206� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 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. [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. GNU LESSER GENERAL PUBLIC LICENSE 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 How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. 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. <one line to give the library's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. <signature of Ty Coon>, 1 April 1990 Ty Coon, President of Vice That's all there is to it! ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/urandom.pas�������������������������������������������������0000755�0001750�0001750�00000004342�11326425446�017646� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Random number generators ****************************************************************** } unit urandom; interface uses utypes, uranmwc, uranmt, uranuvag; procedure SetRNG(RNG : RNG_Type); { Select generator and set default initialization } procedure InitGen(Seed : LongInt); { Initialize generator } function IRanGen : LongInt; { 32-bit random integer in [-2^31 .. 2^31 - 1] } function IRanGen31 : LongInt; { 31-bit random integer in [0 .. 2^31 - 1] } function RanGen1 : Float; { 32-bit random real in [0,1] } function RanGen2 : Float; { 32-bit random real in [0,1) } function RanGen3 : Float; { 32-bit random real in (0,1) } function RanGen53 : Float; { 53-bit random real in [0,1) } implementation const Z = 1.0 / 4294967296.0; { 1 / 2^32 } Z1 = 1.0 / 4294967295.0; { 1 / (2^32 - 1) } Z2 = 1.0 / 9007199254740992.0; var gRNG : RNG_Type; procedure SetRNG(RNG : RNG_Type); var InitMT : MTKeyArray; begin gRNG := RNG; case gRNG of RNG_MWC : InitMWC(118105245); RNG_MT : begin InitMT[0] := $123; InitMT[1] := $234; InitMT[2] := $345; InitMT[3] := $456; InitMTbyArray(InitMT, 4); end; RNG_UVAG : InitUVAGbyString('abcd'); end; end; procedure InitGen(Seed : LongInt); begin case gRNG of RNG_MWC : InitMWC(Seed); RNG_MT : InitMT(Seed); RNG_UVAG : InitUVAG(Seed); end; end; function IRanGen : LongInt; begin case gRNG of RNG_MWC : IRanGen := IRanMWC; RNG_MT : IRanGen := IRanMT; RNG_UVAG : IRanGen := IRanUVAG; end; end; function IRanGen31 : LongInt; begin IRanGen31 := IRanGen shr 1; end; function RanGen1 : Float; begin RanGen1 := (IRanGen + 2147483648.0) * Z1 end; function RanGen2 : Float; begin RanGen2 := (IRanGen + 2147483648.0) * Z end; function RanGen3 : Float; begin RanGen3 := (IRanGen + 2147483648.5) * Z end; function RanGen53 : Float; var A, B : LongInt; begin A := IRanGen shr 5; B := IRanGen shr 6; RanGen53 := (A * 67108864.0 + B) * Z2; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uigmdist.pas������������������������������������������������0000755�0001750�0001750�00000004012�11326425444�020016� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Probability functions related to the incomplete Gamma function ****************************************************************** } unit uigmdist; interface uses utypes, uigamma; function FGamma(A, B, X : Float) : Float; { Cumulative probability for Gamma distrib. with param. A and B } function FPoisson(Mu : Float; K : Integer) : Float; { Cumulative probability for Poisson distrib. } function FNorm(X : Float) : Float; { Cumulative probability for standard normal distrib. } function PNorm(X : Float) : Float; { Prob(|U| > X) for standard normal distrib. } function FKhi2(Nu : Integer; X : Float) : Float; { Cumulative prob. for khi-2 distrib. with Nu d.o.f. } function PKhi2(Nu : Integer; X : Float) : Float; { Prob(Khi2 > X) for khi-2 distrib. with Nu d.o.f. } implementation function FGamma(A, B, X : Float) : Float; begin FGamma := IGamma(A, B * X); end; function FPoisson(Mu : Float; K : Integer) : Float; begin if (Mu <= 0.0) or (K < 0) then FPoisson := DefaultVal(FDomain, 0.0) else if K = 0 then if (- Mu) < MinLog then FPoisson := DefaultVal(FUnderflow, 0.0) else FPoisson := DefaultVal(FOk, Exp(- Mu)) else FPoisson := 1.0 - IGamma(K + 1, Mu); end; function FNorm(X : Float) : Float; begin FNorm := 0.5 * (1.0 + Erf(X * Sqrt2div2)); end; function PNorm(X : Float) : Float; var A : Float; begin A := Abs(X); if A = 0.0 then PNorm := DefaultVal(FOk, 1.0) else if A < 1.0 then PNorm := 1.0 - Erf(A * Sqrt2div2) else PNorm := Erfc(A * Sqrt2div2); end; function FKhi2(Nu : Integer; X : Float) : Float; begin if (Nu < 1) or (X <= 0) then FKhi2 := DefaultVal(FDomain, 0.0) else FKhi2 := IGamma(0.5 * Nu, 0.5 * X); end; function PKhi2(Nu : Integer; X : Float) : Float; begin if (Nu < 1) or (X <= 0) then PKhi2 := DefaultVal(FDomain, 0.0) else PKhi2 := 1.0 - IGamma(0.5 * Nu, 0.5 * X); end; end.����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/changes.txt�������������������������������������������������0000755�0001750�0001750�00000002044�11326425444�017640� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Version 0.50 ------------ * Added a compilation script for Linux (fpcompil.sh) * A graphic library (tpgraph) has been added, with two versions: one for Delphi, one for the Graph unit. The Linux version requires SVGAlib installed and functional. * With FPC, the libraries are now compiled in Delphi mode (option -Mdelphi) to ensure that the Integer type is 32 bits. The calling programs should be compiled with the same option (modify the FPC configuration file if necessary). * The number of points which can be handled by the FFT procedures has been increased (up to 2^26 in double precision) * More statistical methods in the main library : - Comparison of means and variances - Analysis of variance - Non-parametric tests (Wilcoxon, Mann-Whitney, Kruskal-Wallis) - Histograms - Comparison of distributions (Khi-2 and Woolf tests) - Linear, multilinear and nonlinear regressions - Monte-Carlo simulation of the distribution of regression parameters - Principal component analysis * Added some string functions ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/upoidist.pas������������������������������������������������0000755�0001750�0001750�00000001474�11326425446�020044� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Poisson distribution ****************************************************************** } unit upoidist; interface uses utypes; function PPoisson(Mu : Float; K : Integer) : Float; { Probability of Poisson distrib. } implementation function PPoisson(Mu : Float; K : Integer) : Float; var P : Float; I : Integer; begin if (Mu <= 0.0) or (K < 0) then PPoisson := DefaultVal(FDomain, 0.0) else if (- Mu) < MinLog then PPoisson := DefaultVal(FUnderflow, 0.0) else if K = 0 then PPoisson := DefaultVal(FOk, Exp(- Mu)) else begin P := Mu; for I := 2 to K do { P = Mu^K / K! } P := P * Mu / I; PPoisson := Exp(- Mu) * P; SetErrCode(FOk); end; end; end.����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ucholesk.pas������������������������������������������������0000755�0001750�0001750�00000002762�11326425444�020020� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Cholesky factorization of a positive definite symmetric matrix ****************************************************************** } unit ucholesk; interface uses utypes; procedure Cholesky(A, L : PMatrix; Lb, Ub : Integer); { ------------------------------------------------------------------ Cholesky decomposition. Factors the symmetric positive definite matrix A as a product L * L' where L is a lower triangular matrix. This procedure may be used as a test of positive definiteness. ------------------------------------------------------------------ Possible results : MatOk : No error MatNotPD : Matrix not positive definite ------------------------------------------------------------------ } implementation procedure Cholesky(A, L : PMatrix; Lb, Ub : Integer); var I, J, K : Integer; Sum : Float; begin for K := Lb to Ub do begin Sum := A^[K]^[K]; for J := Lb to K - 1 do Sum := Sum - Sqr(L^[K]^[J]); if Sum <= 0.0 then begin SetErrCode(MatNotPD); Exit end; L^[K]^[K] := Sqrt(Sum); for I := K + 1 to Ub do begin Sum := A^[I]^[K]; for J := Lb to K - 1 do Sum := Sum - L^[I]^[J] * L^[K]^[J]; L^[I]^[K] := Sum / L^[K]^[K]; L^[K]^[I] := 0.0; end; end; SetErrCode(MatOk); end; end. ��������������mricron-0.20140804.1~dfsg.1.orig/fpmath/upolev.pas��������������������������������������������������0000755�0001750�0001750�00000003354�11326425446�017515� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Polynomial evaluations for special functions. Translated from C code in Cephes library (http://www.moshier.net) ****************************************************************** } unit upolev; interface uses utypes; type TabCoef = array[0..9] of Float; function PolEvl(var X : Float; Coef : TabCoef; N : Integer) : Float; function P1Evl(var X : Float; Coef : TabCoef; N : Integer) : Float; implementation function PolEvl(var X : Float; Coef : TabCoef; N : Integer) : Float; { ------------------------------------------------------------------ Evaluates polynomial of degree N: 2 N y = C + C x + C x +...+ C x 0 1 2 N Coefficients are stored in reverse order: Coef[0] = C , ..., Coef[N] = C N 0 The function P1Evl() assumes that Coef[N] = 1.0 and is omitted from the array. Its calling arguments are otherwise the same as PolEvl(). ------------------------------------------------------------------ } var Ans : Float; I : Integer; begin Ans := Coef[0]; for I := 1 to N do Ans := Ans * X + Coef[I]; PolEvl := Ans; end; function P1Evl(var X : Float; Coef : TabCoef; N : Integer) : Float; { ------------------------------------------------------------------ Evaluate polynomial when coefficient of X is 1.0. Otherwise same as PolEvl. ------------------------------------------------------------------ } var Ans : Float; I : Integer; begin Ans := X + Coef[0]; for I := 1 to N - 1 do Ans := Ans * X + Coef[I]; P1Evl := Ans; end; end.������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ugoldsrc.pas������������������������������������������������0000755�0001750�0001750�00000005527�11326425444�020027� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Minimization of a function of one variable by Golden Search method ****************************************************************** } unit ugoldsrc; interface uses utypes, uminbrak; procedure GoldSearch(Func : TFunc; A, B : Float; MaxIter : Integer; Tol : Float; var Xmin, Ymin : Float); { ------------------------------------------------------------------ Performs a golden search for the minimum of function Func ------------------------------------------------------------------ Input parameters : Func = objective function A, B = two points near the minimum MaxIter = maximum number of iterations Tol = required precision (should not be less than the square root of the machine precision) ------------------------------------------------------------------ Output parameters : Xmin, Ymin = coordinates of minimum ------------------------------------------------------------------ Possible results : OptOk OptNonConv ------------------------------------------------------------------ } implementation procedure GoldSearch(Func : TFunc; A, B : Float; MaxIter : Integer; Tol : Float; var Xmin, Ymin : Float); var C, Fa, Fb, Fc, F1, F2, MinTol, X0, X1, X2, X3 : Float; Iter : Integer; begin MinTol := Sqrt(MachEp); if Tol < MinTol then Tol := MinTol; MinBrack(Func, A, B, C, Fa, Fb, Fc); X0 := A; X3 := C; if (C - B) > (B - A) then begin X1 := B; X2 := B + CGold * (C - B); F1 := Fb; F2 := Func(X2); end else begin X1 := B - CGold * (B - A); X2 := B; F1 := Func(X1); F2 := Fb; end; Iter := 0; while (Iter <= MaxIter) and (Abs(X3 - X0) > Tol * (Abs(X1) + Abs(X2))) do if F2 < F1 then begin X0 := X1; X1 := X2; F1 := F2; X2 := X1 + CGold * (X3 - X1); F2 := Func(X2); Inc(Iter); end else begin X3 := X2; X2 := X1; F2 := F1; X1 := X2 - CGold * (X2 - X0); F1 := Func(X1); Inc(Iter); end; if F1 < F2 then begin Xmin := X1; Ymin := F1; end else begin Xmin := X2; Ymin := F2; end; if Iter > MaxIter then SetErrCode(OptNonConv) else SetErrCode(OptOk); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ueigval.pas�������������������������������������������������0000755�0001750�0001750�00000001602�11326425444�017627� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Eigenvalues of a general square matrix ****************************************************************** } unit ueigval; interface uses utypes, ubalance, uelmhes, uhqr; procedure EigenVals(A : PMatrix; Lb, Ub : Integer; Lambda : PCompVector); implementation procedure EigenVals(A : PMatrix; Lb, Ub : Integer; Lambda : PCompVector); var I_low, I_igh : Integer; Scale : PVector; I_int : PIntVector; begin DimVector(Scale, Ub); DimIntVector(I_Int, Ub); Balance(A, Lb, Ub, I_low, I_igh, Scale); ElmHes(A, Lb, Ub, I_low, I_igh, I_int); Hqr(A, Lb, Ub, I_low, I_igh, Lambda); DelVector(Scale, Ub); DelIntVector(I_Int, Ub); end; end. ������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/dll/��������������������������������������������������������0000755�0001750�0001750�00000000000�12360760644�016242� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/dll/dcompil.bat���������������������������������������������0000755�0001750�0001750�00000000251�10727461324�020360� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������dcc32 tpmath.dpr -U..\units -DDELPHI -$J+ dcc32 tpmath.pas -I..\units -DDELPHI dcc32 tpgraph.dpr -U..\units -DDELPHI -$J+ dcc32 tpgraph.pas -I..\units -DDELPHI �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/dll/tpmath.dpr����������������������������������������������0000755�0001750�0001750�00000040573�10726466410�020260� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������library tpmath; uses utypes, uminmax, uround, umath, utrigo, uhyper, ugamma, udigamma, uigamma, ubeta, uibeta, ulambert, ufact, ubinom, upoidist, uexpdist, unormal, ugamdist, uibtdist, uigmdist, uinvnorm, uinvgam, uinvbeta, ugausjor, ulineq, ucholesk, ulu, uqr, usvd, ueigval, ueigvec, ujacobi, uminbrak, ugoldsrc, ulinmin, unewton, umarq, ubfgs, usimplex, ubisect, unewteq, usecant, unewteqs, ubroyden, upolynom, urtpol1, urtpol2, urtpol3, urtpol4, urootpol, upolutil, utrapint, ugausleg, urkf, ufft, urandom, uranmwc, uranmt, uranuvag, urangaus, uranmult, umcmc, usimann, ugenalg, umeansd, ucorrel, uqsort, umedian, uskew, uinterv, ustudind, ustdpair, uanova1, uanova2, usnedeco, ubartlet, ukhi2, uwoolf, unonpar, udistrib, ulinfit, upolfit, umulfit, usvdfit, unlfit, uregtest, upca, ustrings; exports SetErrCode, { Sets error code } DefaultVal, { Sets error code and default function value } MathErr, { Returns the error code } SetAutoInit, { Sets automatic array initialization } DimVector, { Allocates a real vector } DimIntVector, { Allocates an integer vector } DimCompVector, { Allocates a complex vector } DimBoolVector, { Allocates a boolean vector } DimStrVector, { Allocates a string vector } DimMatrix, { Allocates a real matrix } DimIntMatrix, { Allocates an integer matrix } DimCompMatrix, { Allocates a complex matrix } DimBoolMatrix, { Allocates a boolean matrix } DimStrMatrix, { Allocates a string matrix } DelVector, { Deallocates a real vector } DelIntVector, { Deallocates an integer vector } DelCompVector, { Deallocates a complex vector } DelBoolVector, { Deallocates a boolean vector } DelStrVector, { Deallocates a string vector } DelMatrix, { Deallocates a real matrix } DelIntMatrix, { Deallocates an integer matrix } DelCompMatrix, { Deallocates a complex matrix } DelBoolMatrix, { Deallocates a boolean matrix } DelStrMatrix, { Deallocates a string matrix } FMin, { Minimum of 2 reals } FMax, { Maximum of 2 reals } IMin, { Minimum of 2 integers } IMax, { Maximum of 2 integers } Sgn, { Sign, Sgn(0) = 1 } Sgn0, { Sign, Sgn(0) = 0 } DSgn, { DSgn(A, B) = Sgn(B) * |A| } FSwap, { Exchanges 2 reals } ISwap, { Exchanges 2 integers } RoundN, { Rounds a number to N decimal places } Ceil, { Ceiling function } Floor, { Floor function } Expo, { Exponential (with bound checking) } Exp2, { Exponential, base 2 } Exp10, { Exponential, base 10 } Log, { Natural log (with bound checking) } Log2, { Log, base 2 } Log10, { Log, base 10 } LogA, { Log, base A } IntPower, { Power (integer exponent) } Power, { Power (real exponent) } Pythag, { Sqrt(X^2 + Y^2) } FixAngle, { Set argument in -Pi..Pi } Tan, { Tangent } ArcSin, { Arc sinus } ArcCos, { Arc cosinus } ArcTan2, { Angle (Ox, OM) with M(X,Y) } Sinh, { Hyperbolic sine } Cosh, { Hyperbolic cosine } Tanh, { Hyperbolic tangent } ArcSinh, { Inverse hyperbolic sine } ArcCosh, { Inverse hyperbolic cosine } ArcTanh, { Inverse hyperbolic tangent } SinhCosh, { Sinh and Cosh } Gamma, { Gamma function } LnGamma, { Logarithm of Gamma function } SgnGamma, { Sign of Gamma function } Stirling, { Stirling's formula for Gamma } StirLog, { Stirling's formula for LnGamma } DiGamma, { DiGamma function } TriGamma, { TriGamma function } IGamma, { Incomplete Gamma function } JGamma, { Complement of incomplete Gamma function } Erf, { Error function } Erfc, { Complement of error function } Beta, { Beta function } IBeta, { Incomplete Beta function } LambertW, { Lambert's W-function } Fact, { Factorial } Binomial, { Binomial coefficient } PBinom, { Probability of binomial distribution } PPoisson, { Probability of Poisson distribution } DExpo, { Density of exponential distribution } FExpo, { Cumulative prob. of exponential dist. } DNorm, { Density of standard normal distribution } DBeta, { Density of Beta distribution } DGamma, { Density of Gamma distribution } DKhi2, { Density of Khi-2 distribution } DStudent, { Density of Student's distribution } DSnedecor, { Density of Fisher-Snedecor distribution } FBeta, { Cumulative prob. of Beta distribution } FBinom, { Cumulative prob. of Binomial distribution } FStudent, { Cumulative prob. of Student's distribution } PStudent, { Prob(|t| > X) for Student's distribution } FSnedecor, { Cumulative prob. of Fisher-Snedecor distribution } PSnedecor, { Prob(F > X) for Fisher-Snedecor distribution } FGamma, { Cumulative prob. of Gamma distribution } FPoisson, { Cumulative prob. of Poisson distribution } FNorm, { Cumulative prob. of standard normal distribution } PNorm, { Prob(|U| > X) for standard normal distribution } FKhi2, { Cumulative prob. of Khi-2 distribution } PKhi2, { Prob(Khi2 > X) for Khi-2 distribution } InvNorm, { Inverse of normal distribution } InvGamma, { Inverse of incomplete Gamma function } InvKhi2, { Inverse of khi-2 distribution } InvBeta, { Inverse of incomplete Beta function } InvStudent, { Inverse of Student's t-distribution } InvSnedecor, { Inverse of Snedecor's F-distribution } GaussJordan, { Linear equation system (Gauss-Jordan method) } LinEq, { Linear equation system (Gauss-Jordan method) } Cholesky, { Cholesky factorization } LU_Decomp, { LU decomposition } LU_Solve, { Linear equation system (LU method) } QR_Decomp, { QR decomposition } QR_Solve, { Linear equation system (QR method) } SV_Decomp, { Singular value decomposition } SV_Solve, { Linear equation system (SVD method) } SV_SetZero, { Set lowest singular values to zero } SV_Approx, { Matrix approximation from SVD } EigenVals, { Eigenvalues of a general square matrix } EigenVect, { Eigenvalues and eigenvectors of a general square matrix } Jacobi, { Eigenvalues and eigenvectors of a symmetric matrix } MinBrack, { Brackets the minimum of a function } GoldSearch, { Minimization of a function of one variable (golden search) } LinMin, { Minimization of a function of several variables along a line } Newton, { Minimization of a function of several var. (Newton's method) } SaveNewton, { Save Newton iterations in a file } Marquardt, { Minimization of a function of several var. (Marquardt's method) } SaveMarquardt, { Save Marquardt iterations in a file } BFGS, { Minimization of a function of several var. (BFGS method) } SaveBFGS, { Save BFGS iterations in a file } Simplex, { Minimization of a function of several variables (Simplex) } SaveSimplex, { Save Simplex iterations in a file } RootBrack, { Brackets solution of equation } Bisect, { Nonlinear equation (bisection method) } NewtEq, { Nonlinear equation (Newton-Raphson method) } Secant, { Nonlinear equation (secant method) } NewtEqs, { Nonlinear equation system (Newton-Raphson method) } Broyden, { Nonlinear equation system (Broyden's method) } Poly, { Evaluates a polynomial } RFrac, { Evaluates a rational fraction } RootPol1, { Root of linear equation } RootPol2, { Roots of quadratic equation } RootPol3, { Roots of cubic equation } RootPol4, { Roots of quartic equation } RootPol, { Roots of polynomial from companion matrix } SetRealRoots, { Set the imaginary part of a root to zero } SortRoots, { Sorts the roots of a polynomial } TrapInt, { Integration by trapezoidal rule } GausLeg, { Gauss-Legendre integration } GausLeg0, { Gauss-Legendre integration (lower bound=0) } Convol, { Convolution product } RKF45, { Integration of a system of differential equations } FFT, { Fast Fourier Transform } IFFT, { Inverse Fast Fourier Transform } FFT_Integer, { Fast Fourier Transform for integer data } FFT_Integer_Cleanup, { Clear memory after a call to FFT_Integer } CalcFrequency, { Direct computation of Fourier Transform } SetRNG, { Select random number generator } InitGen, { Initialize random number generator } IRanGen, { 32-bit random integer in [-2^31 .. 2^31 - 1] } IRanGen31, { 31-bit random integer in [0 .. 2^31 - 1] } RanGen1, { 32-bit random real in [0,1] } RanGen2, { 32-bit random real in [0,1) } RanGen3, { 32-bit random real in (0,1) } RanGen53, { 53-bit random real in [0,1) } InitMWC, { Initialize Multiply-With-Carry generator } IRanMWC, { 32-bit random integer from MWC generator } InitMT, { Initialize Mersenne Twister generator with a seed } InitMTbyArray, { Initialize MT generator with an array } IRanMT, { 32-bit random integer from MT generator } InitUVAG, { Initialize UVAG generator with a seed } InitUVAGbyString, { Initialize UVAG generator with a string } IRanUVAG, { 32-bit random integer from UVAG generator } RanGaussStd, { Random number from standard normal distribution } RanGauss, { Random number from normal distribution } RanMult, { Random vector from multinormal distrib. (correlated) } RanMultIndep, { Random vector from multinormal distrib. (uncorrelated) } InitMHParams, { Initialize Metropolis-Hastings parameters } GetMHParams, { Returns Metropolis-Hastings parameters } Hastings, { Simulation of a p.d.f. by Metropolis-Hastings } InitSAParams, { Initialize Simulated Annealing parameters } SA_CreateLogFile, { Initialize log file for Simulated Annealing } SimAnn, { Minimization of a function of several var. by Simulated Annealing } InitGAParams, { Initialize Genetic Algorithm parameters } GA_CreateLogFile, { Initialize log file for Genetic Algorithm } GenAlg, { Minimization of a function of several var. by Genetic Algorithm } Mean, { Sample mean } Median, { Sample median } StDev, { Standard deviation estimated from sample } StDevP, { Standard deviation of population } Correl, { Correlation coefficient } Skewness, { Sample skewness } Kurtosis, { Sample kurtosis } QSort, { Quick sort (ascending order) } DQSort, { Quick sort (descending order) } Interval, { Determines an interval for a set of values } StudIndep, { Student t-test for independent samples } StudPaired, { Student t-test for paired samples } AnOVa1, { One-way analysis of variance } AnOVa2, { Two-way analysis of variance } Snedecor, { Comparison of two variances } Bartlett, { Comparison of several variances } Khi2_Conform, { Khi-2 test for conformity } Khi2_Indep, { Khi-2 test for independence } Woolf_Conform, { Woolf's test for conformity } Woolf_Indep, { Woolf's test for independence } Mann_Whitney, { Mann-Whitney test } Wilcoxon, { Wilcoxon test } Kruskal_Wallis, { Kruskal-Wallis test } DimStatClassVector, { Allocates an array of statistical classes } DelStatClassVector, { Deallocates an array of statistical classes } Distrib, { Distributes an array into statistical classes } LinFit, { Linear regression } WLinFit, { Weighted linear regression } PolFit, { Polynomial regression } WPolFit, { Weighted polynomial regression } MulFit, { Multiple linear regression by Gauss-Jordan method } WMulFit, { Weighted multiple linear regression by Gauss-Jordan method } SVDFit, { Multiple linear regression by SVD method } WSVDFit, { Weighted multiple linear regression by SVD method } SetOptAlgo, { Selects optimization algorithm for nonlinear regression } SetMaxParam, { Sets the maximal number of regression parameters } SetParamBounds, { Sets the bounds on a regression parameter } NLFit, { Nonlinear regression } WNLFit, { Weighted nonlinear regression } SetMCFile, { Set file for saving MCMC simulations } SimFit, { Simulation of unweighted nonlinear regression by MCMC } WSimFit, { Simulation of weighted nonlinear regression by MCMC } RegTest, { Test of unweighted regression } WRegTest, { Test of weighted regression } VecMean, { Computes mean vector } VecSD, { Computes vector of standard deviations } MatVarCov, { Computes variance-covariance matrix } MatCorrel, { Computes correlation matrix } PCA, { Principal component analysis of correlation matrix } ScaleVar, { Scales a set of variables } PrinFac, { Computes principal factors } LTrim, { Remove leading blanks } RTrim, { Remove trailing blanks } Trim, { Remove leading and trailing blanks } StrChar, { Generate string by repeating a character } RFill, { Complete string with trailing blanks } LFill, { Complete string with leading blanks } CFill, { Center string } Replace, { Replace a character } Extract, { Extract field from string } Parse, { Parse string into several fields } SetFormat, { Set numeric format } FloatStr, { Convert real number to string } IntStr, { Convert integer to string } CompStr; { Convert complex number to string } begin end. �������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/dll/tpgraph.dpr���������������������������������������������0000755�0001750�0001750�00000004104�10702755312�020412� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������library tpgraph; uses {$IFDEF DELPHI} uwinplot; {$ELSE} uplot; {$ENDIF} exports InitGraphics, { Initializes the graphic } SetWindow, { Sets the graphic window } AutoScale, { Automatic scale determination } SetOxScale, { Sets the scale on the Ox axis } SetOyScale, { Sets the scale on the Oy axis } SetGraphTitle, { Sets the graph title } SetOxTitle, { Sets the title for the Ox axis } SetOyTitle, { Sets the title for the Oy axis } {$IFNDEF DELPHI} SetTitleFont, { Sets the font for the main graph title } SetOxFont, { Sets the font for the Ox axis } SetOyFont, { Sets the font for the Oy axis } SetLgdFont, { Sets the font for the legends } SetClipping, { Limits the graphic to the current viewport } {$ENDIF} PlotOxAxis, { Plots the X axis } PlotOyAxis, { Plots the Y axis } WriteGraphTitle, { Writes title of graph } PlotGrid, { Plots a grid on the graph } SetMaxCurv, { Sets maximum number of curves } SetPointParam, { Sets point parameters } SetLineParam, { Sets line parameters } SetCurvLegend, { Sets curve legend } SetCurvStep, { Sets curve step } PlotPoint, { Plots a point } PlotCurve, { Plots a curve } PlotCurveWithErrorBars, { Plots a curve with error bars } PlotFunc, { Plots a function } WriteLegend, { Writes the legends for the plotted curves } ConRec, { Contour plot } Xpixel, { Converts user abscissa X to screen coordinate } Ypixel, { Converts user ordinate Y to screen coordinate } Xuser, { Converts screen coordinate X to user abscissa } Yuser, { Converts screen coordinate Y to user ordinate } LeaveGraphics; { Quits the graphic mode } begin end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/dll/tpgraph.pas���������������������������������������������0000755�0001750�0001750�00000013224�11326425444�020416� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Unit TPGRAPH - Interface for TPGRAPH.DLL ****************************************************************** } unit tpgraph; interface uses tpmath {$IFDEF DELPHI}, Graphics{$ENDIF}; function InitGraphics {$IFDEF DELPHI} (Canvas : TCanvas; Width, Height : Integer) : Boolean; {$ELSE} (Pilot, Mode : Integer; BGIPath : String) : Boolean; {$ENDIF} external 'tpgraph'; { Enters graphic mode } procedure SetWindow({$IFDEF DELPHI}Canvas : TCanvas;{$ENDIF} X1, X2, Y1, Y2 : Integer; GraphBorder : Boolean); external 'tpgraph'; { Sets the graphic window } procedure AutoScale(X : PVector; Lb, Ub : Integer; Scale : TScale; var XMin, XMax, XStep : Float); external 'tpgraph'; { Finds an appropriate scale for plotting the data in X[Lb..Ub] } procedure SetOxScale(Scale : TScale; OxMin, OxMax, OxStep : Float); external 'tpgraph'; { Sets the scale on the Ox axis } procedure SetOyScale(Scale : TScale; OyMin, OyMax, OyStep : Float); external 'tpgraph'; { Sets the scale on the Oy axis } procedure SetGraphTitle(Title : String); external 'tpgraph'; { Sets the title for the graph } procedure SetOxTitle(Title : String); external 'tpgraph'; { Sets the title for the Ox axis } procedure SetOyTitle(Title : String); external 'tpgraph'; { Sets the title for the Oy axis } {$IFNDEF DELPHI} procedure SetTitleFont(FontIndex, Width, Height : Integer); external 'tpgraph'; { Sets the font for the main graph title } procedure SetOxFont(FontIndex, Width, Height : Integer); external 'tpgraph'; { Sets the font for the Ox axis (title and labels) } procedure SetOyFont(FontIndex, Width, Height : Integer); external 'tpgraph'; { Sets the font for the Oy axis (title and labels) } procedure SetLgdFont(FontIndex, Width, Height : Integer); external 'tpgraph'; { Sets the font for the legends } procedure SetClipping(Clip : Boolean); external 'tpgraph'; { Determines whether drawings are clipped at the current viewport boundaries, according to the value of the Boolean parameter Clip } {$ENDIF} procedure PlotOxAxis{$IFDEF DELPHI}(Canvas : TCanvas){$ENDIF}; external 'tpgraph'; { Plots the horizontal axis } procedure PlotOyAxis{$IFDEF DELPHI}(Canvas : TCanvas){$ENDIF}; external 'tpgraph'; { Plots the vertical axis } procedure PlotGrid({$IFDEF DELPHI}Canvas : TCanvas;{$ENDIF} Grid : TGrid); external 'tpgraph'; { Plots a grid on the graph } procedure WriteGraphTitle{$IFDEF DELPHI}(Canvas : TCanvas){$ENDIF}; external 'tpgraph'; { Writes the title of the graph } procedure SetMaxCurv(NCurv : Byte); external 'tpgraph'; { Sets the maximum number of curves and re-initializes their parameters } procedure SetPointParam {$IFDEF DELPHI} (CurvIndex, Symbol, Size : Integer; Color : TColor); {$ELSE} (CurvIndex, Symbol, Size, Color : Integer); {$ENDIF} external 'tpgraph'; { Sets the point parameters for curve # CurvIndex } procedure SetLineParam {$IFDEF DELPHI} (CurvIndex : Integer; Style : TPenStyle; Width : Integer; Color : TColor); {$ELSE} (CurvIndex, Style, Width, Color : Integer); {$ENDIF} external 'tpgraph'; { Sets the line parameters for curve # CurvIndex } procedure SetCurvLegend(CurvIndex : Integer; Legend : String); external 'tpgraph'; { Sets the legend for curve # CurvIndex } procedure SetCurvStep(CurvIndex, Step : Integer); external 'tpgraph'; { Sets the step for curve # CurvIndex } procedure PlotPoint({$IFDEF DELPHI}Canvas : TCanvas;{$ENDIF} X, Y : Float; CurvIndex : Integer); external 'tpgraph'; { Plots a point on the screen } procedure PlotCurve({$IFDEF DELPHI}Canvas : TCanvas;{$ENDIF} X, Y : PVector; Lb, Ub, CurvIndex : Integer); external 'tpgraph'; { Plots a curve } procedure PlotCurveWithErrorBars({$IFDEF DELPHI}Canvas : TCanvas;{$ENDIF} X, Y, S : PVector; Ns, Lb, Ub, CurvIndex : Integer); external 'tpgraph'; { Plots a curve with error bars } procedure PlotFunc({$IFDEF DELPHI}Canvas : TCanvas;{$ENDIF} Func : TFunc; Xmin, Xmax : Float; {$IFDEF DELPHI}Npt : Integer;{$ENDIF} CurvIndex : Integer); external 'tpgraph'; { Plots a function } procedure WriteLegend({$IFDEF DELPHI}Canvas : TCanvas;{$ENDIF} NCurv : Integer; ShowPoints, ShowLines : Boolean); external 'tpgraph'; { Writes the legends for the plotted curves } procedure ConRec({$IFDEF DELPHI}Canvas : TCanvas;{$ENDIF} Nx, Ny, Nc : Integer; X, Y, Z : PVector; F : PMatrix); external 'tpgraph'; { Contour plot } function Xpixel(X : Float) : Integer; external 'tpgraph'; { Converts user abscissa X to screen coordinate } function Ypixel(Y : Float) : Integer; external 'tpgraph'; { Converts user ordinate Y to screen coordinate } function Xuser(X : Integer) : Float; external 'tpgraph'; { Converts screen coordinate X to user abscissa } function Yuser(Y : Integer) : Float; external 'tpgraph'; { Converts screen coordinate Y to user ordinate } procedure LeaveGraphics; external 'tpgraph'; { Quits graphic mode } implementation end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/dll/fpcompil.bat��������������������������������������������0000755�0001750�0001750�00000000230�10724751272�020540� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fpc tpmath.dpr -Fu..\units -Mdelphi fpc tpmath.pas -Fi..\units -Mdelphi fpc tpgraph.dpr -Fu..\units -Mdelphi fpc tpgraph.pas -Fi..\units -Mdelphi ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/dll/fpcompil.sh���������������������������������������������0000755�0001750�0001750�00000000226�10730731110�020373� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fpc tpmath.dpr -Fu../units -Mdelphi fpc tpmath.dpr -Fi../units -Mdelphi fpc tpgraph.dpr -Fu../units -Mdelphi fpc tpgraph.dpr -Fi../units -Mdelphi��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/dll/tpmath.pas����������������������������������������������0000755�0001750�0001750�00000126304�11326425444�020252� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Unit TPMATH - Interface for TPMATH.DLL ****************************************************************** } unit tpmath; interface { ------------------------------------------------------------------ Types and constants ------------------------------------------------------------------ } {$i types.inc} { ------------------------------------------------------------------ Error handling ------------------------------------------------------------------ } procedure SetErrCode(ErrCode : Integer); external 'tpmath'; { Sets the error code } function DefaultVal(ErrCode : Integer; DefVal : Float) : Float; external 'tpmath'; { Sets error code and default function value } function MathErr : Integer; external 'tpmath'; { Returns the error code } { ------------------------------------------------------------------ Dynamic arrays ------------------------------------------------------------------ } procedure SetAutoInit(AutoInit : Boolean); external 'tpmath'; { Sets the auto-initialization of arrays } procedure DimVector(var V : PVector; Ub : Integer); external 'tpmath'; { Creates floating point vector V[0..Ub] } procedure DimIntVector(var V : PIntVector; Ub : Integer); external 'tpmath'; { Creates integer vector V[0..Ub] } procedure DimCompVector(var V : PCompVector; Ub : Integer); external 'tpmath'; { Creates complex vector V[0..Ub] } procedure DimBoolVector(var V : PBoolVector; Ub : Integer); external 'tpmath'; { Creates boolean vector V[0..Ub] } procedure DimStrVector(var V : PStrVector; Ub : Integer); external 'tpmath'; { Creates string vector V[0..Ub] } procedure DimMatrix(var A : PMatrix; Ub1, Ub2 : Integer); external 'tpmath'; { Creates floating point matrix A[0..Ub1, 0..Ub2] } procedure DimIntMatrix(var A : PIntMatrix; Ub1, Ub2 : Integer); external 'tpmath'; { Creates integer matrix A[0..Ub1, 0..Ub2] } procedure DimCompMatrix(var A : PCompMatrix; Ub1, Ub2 : Integer); external 'tpmath'; { Creates complex matrix A[0..Ub1, 0..Ub2] } procedure DimBoolMatrix(var A : PBoolMatrix; Ub1, Ub2 : Integer); external 'tpmath'; { Creates boolean matrix A[0..Ub1, 0..Ub2] } procedure DimStrMatrix(var A : PStrMatrix; Ub1, Ub2 : Integer); external 'tpmath'; { Creates string matrix A[0..Ub1, 0..Ub2] } procedure DelVector(var V : PVector; Ub : Integer); external 'tpmath'; { Deletes floating point vector V[0..Ub] } procedure DelIntVector(var V : PIntVector; Ub : Integer); external 'tpmath'; { Deletes integer vector V[0..Ub] } procedure DelCompVector(var V : PCompVector; Ub : Integer); external 'tpmath'; { Deletes complex vector V[0..Ub] } procedure DelBoolVector(var V : PBoolVector; Ub : Integer); external 'tpmath'; { Deletes boolean vector V[0..Ub] } procedure DelStrVector(var V : PStrVector; Ub : Integer); external 'tpmath'; { Deletes string vector V[0..Ub] } procedure DelMatrix(var A : PMatrix; Ub1, Ub2 : Integer); external 'tpmath'; { Deletes floating point matrix A[0..Ub1, 0..Ub2] } procedure DelIntMatrix(var A : PIntMatrix; Ub1, Ub2 : Integer); external 'tpmath'; { Deletes integer matrix A[0..Ub1, 0..Ub2] } procedure DelCompMatrix(var A : PCompMatrix; Ub1, Ub2 : Integer); external 'tpmath'; { Deletes complex matrix A[0..Ub1, 0..Ub2] } procedure DelBoolMatrix(var A : PBoolMatrix; Ub1, Ub2 : Integer); external 'tpmath'; { Deletes boolean matrix A[0..Ub1, 0..Ub2] } procedure DelStrMatrix(var A : PStrMatrix; Ub1, Ub2 : Integer); external 'tpmath'; { Deletes string matrix A[0..Ub1, 0..Ub2] } { ------------------------------------------------------------------ Minimum, maximum, sign and exchange ------------------------------------------------------------------ } function FMin(X, Y : Float) : Float; external 'tpmath'; { Minimum of 2 reals } function FMax(X, Y : Float) : Float; external 'tpmath'; { Maximum of 2 reals } function IMin(X, Y : Integer) : Integer; external 'tpmath'; { Minimum of 2 integers } function IMax(X, Y : Integer) : Integer; external 'tpmath'; { Maximum of 2 integers } function Sgn(X : Float) : Integer; external 'tpmath'; { Sign (returns 1 if X = 0) } function Sgn0(X : Float) : Integer; external 'tpmath'; { Sign (returns 0 if X = 0) } function DSgn(A, B : Float) : Float; external 'tpmath'; { Sgn(B) * |A| } procedure FSwap(var X, Y : Float); external 'tpmath'; { Exchange 2 reals } procedure ISwap(var X, Y : Integer); external 'tpmath'; { Exchange 2 integers } { ------------------------------------------------------------------ Rounding functions ------------------------------------------------------------------ } function RoundN(X : Float; N : Integer) : Float; external 'tpmath'; { Rounds X to N decimal places } function Ceil(X : Float) : Integer; external 'tpmath'; { Ceiling function } function Floor(X : Float) : Integer; external 'tpmath'; { Floor function } { ------------------------------------------------------------------ Logarithms, exponentials and power ------------------------------------------------------------------ } function Expo(X : Float) : Float; external 'tpmath'; { Exponential } function Exp2(X : Float) : Float; external 'tpmath'; { 2^X } function Exp10(X : Float) : Float; external 'tpmath'; { 10^X } function Log(X : Float) : Float; external 'tpmath'; { Natural log } function Log2(X : Float) : Float; external 'tpmath'; { Log, base 2 } function Log10(X : Float) : Float; external 'tpmath'; { Decimal log } function LogA(X, A : Float) : Float; external 'tpmath'; { Log, base A } function IntPower(X : Float; N : Integer) : Float; external 'tpmath'; { X^N } function Power(X, Y : Float) : Float; external 'tpmath'; { X^Y, X >= 0 } { ------------------------------------------------------------------ Trigonometric functions ------------------------------------------------------------------ } function Pythag(X, Y : Float) : Float; external 'tpmath'; { Sqrt(X^2 + Y^2) } function FixAngle(Theta : Float) : Float; external 'tpmath'; { Set Theta in -Pi..Pi } function Tan(X : Float) : Float; external 'tpmath'; { Tangent } function ArcSin(X : Float) : Float; external 'tpmath'; { Arc sinus } function ArcCos(X : Float) : Float; external 'tpmath'; { Arc cosinus } function ArcTan2(Y, X : Float) : Float; external 'tpmath'; { Angle (Ox, OM) with M(X,Y) } { ------------------------------------------------------------------ Hyperbolic functions ------------------------------------------------------------------ } function Sinh(X : Float) : Float; external 'tpmath'; { Hyperbolic sine } function Cosh(X : Float) : Float; external 'tpmath'; { Hyperbolic cosine } function Tanh(X : Float) : Float; external 'tpmath'; { Hyperbolic tangent } function ArcSinh(X : Float) : Float; external 'tpmath'; { Inverse hyperbolic sine } function ArcCosh(X : Float) : Float; external 'tpmath'; { Inverse hyperbolic cosine } function ArcTanh(X : Float) : Float; external 'tpmath'; { Inverse hyperbolic tangent } procedure SinhCosh(X : Float; var SinhX, CoshX : Float); external 'tpmath'; { Sinh & Cosh } { ------------------------------------------------------------------ Gamma function and related functions ------------------------------------------------------------------ } function Fact(N : Integer) : Float; external 'tpmath'; { Factorial } function SgnGamma(X : Float) : Integer; external 'tpmath'; { Sign of Gamma function } function Gamma(X : Float) : Float; external 'tpmath'; { Gamma function } function LnGamma(X : Float) : Float; external 'tpmath'; { Logarithm of Gamma function } function Stirling(X : Float) : Float; external 'tpmath'; { Stirling's formula for the Gamma function } function StirLog(X : Float) : Float; external 'tpmath'; { Approximate Ln(Gamma) by Stirling's formula, for X >= 13 } function DiGamma(X : Float ) : Float; external 'tpmath'; { Digamma function } function TriGamma(X : Float ) : Float; external 'tpmath'; { Trigamma function } function IGamma(A, X : Float) : Float; external 'tpmath'; { Incomplete Gamma function} function JGamma(A, X : Float) : Float; external 'tpmath'; { Complement of incomplete Gamma function } function InvGamma(A, P : Float) : Float; external 'tpmath'; { Inverse of incomplete Gamma function } function Erf(X : Float) : Float; external 'tpmath'; { Error function } function Erfc(X : Float) : Float; external 'tpmath'; { Complement of error function } { ------------------------------------------------------------------ Beta function and related functions ------------------------------------------------------------------ } function Beta(X, Y : Float) : Float; external 'tpmath'; { Beta function } function IBeta(A, B, X : Float) : Float; external 'tpmath'; { Incomplete Beta function } function InvBeta(A, B, Y : Float) : Float; external 'tpmath'; { Inverse of incomplete Beta function } { ------------------------------------------------------------------ Lambert's function ------------------------------------------------------------------ } function LambertW(X : Float; UBranch, Offset : Boolean) : Float; external 'tpmath'; { ------------------------------------------------------------------ Binomial distribution ------------------------------------------------------------------ } function Binomial(N, K : Integer) : Float; external 'tpmath'; { Binomial coefficient C(N,K) } function PBinom(N : Integer; P : Float; K : Integer) : Float; external 'tpmath'; { Probability of binomial distribution } function FBinom(N : Integer; P : Float; K : Integer) : Float; external 'tpmath'; { Cumulative probability for binomial distrib. } { ------------------------------------------------------------------ Poisson distribution ------------------------------------------------------------------ } function PPoisson(Mu : Float; K : Integer) : Float; external 'tpmath'; { Probability of Poisson distribution } function FPoisson(Mu : Float; K : Integer) : Float; external 'tpmath'; { Cumulative probability for Poisson distrib. } { ------------------------------------------------------------------ Exponential distribution ------------------------------------------------------------------ } function DExpo(A, X : Float) : Float; external 'tpmath'; { Density of exponential distribution with parameter A } function FExpo(A, X : Float) : Float; external 'tpmath'; { Cumulative probability function for exponential dist. with parameter A } { ------------------------------------------------------------------ Standard normal distribution ------------------------------------------------------------------ } function DNorm(X : Float) : Float; external 'tpmath'; { Density of standard normal distribution } function FNorm(X : Float) : Float; external 'tpmath'; { Cumulative probability for standard normal distrib. } function PNorm(X : Float) : Float; external 'tpmath'; { Prob(|U| > X) for standard normal distrib. } function InvNorm(P : Float) : Float; external 'tpmath'; { Inverse of standard normal distribution } { ------------------------------------------------------------------ Student's distribution ------------------------------------------------------------------ } function DStudent(Nu : Integer; X : Float) : Float; external 'tpmath'; { Density of Student distribution with Nu d.o.f. } function FStudent(Nu : Integer; X : Float) : Float; external 'tpmath'; { Cumulative probability for Student distrib. with Nu d.o.f. } function PStudent(Nu : Integer; X : Float) : Float; external 'tpmath'; { Prob(|t| > X) for Student distrib. with Nu d.o.f. } function InvStudent(Nu : Integer; P : Float) : Float; external 'tpmath'; { Inverse of Student's t-distribution function } { ------------------------------------------------------------------ Khi-2 distribution ------------------------------------------------------------------ } function DKhi2(Nu : Integer; X : Float) : Float; external 'tpmath'; { Density of Khi-2 distribution with Nu d.o.f. } function FKhi2(Nu : Integer; X : Float) : Float; external 'tpmath'; { Cumulative prob. for Khi-2 distrib. with Nu d.o.f. } function PKhi2(Nu : Integer; X : Float) : Float; external 'tpmath'; { Prob(Khi2 > X) for Khi-2 distrib. with Nu d.o.f. } function InvKhi2(Nu : Integer; P : Float) : Float; external 'tpmath'; { Inverse of Khi-2 distribution function } { ------------------------------------------------------------------ Fisher-Snedecor distribution ------------------------------------------------------------------ } function DSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; external 'tpmath'; { Density of Fisher-Snedecor distribution with Nu1 and Nu2 d.o.f. } function FSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; external 'tpmath'; { Cumulative prob. for Fisher-Snedecor distrib. with Nu1 and Nu2 d.o.f. } function PSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; external 'tpmath'; { Prob(F > X) for Fisher-Snedecor distrib. with Nu1 and Nu2 d.o.f. } function InvSnedecor(Nu1, Nu2 : Integer; P : Float) : Float; external 'tpmath'; { Inverse of Snedecor's F-distribution function } { ------------------------------------------------------------------ Beta distribution ------------------------------------------------------------------ } function DBeta(A, B, X : Float) : Float; external 'tpmath'; { Density of Beta distribution with parameters A and B } function FBeta(A, B, X : Float) : Float; external 'tpmath'; { Cumulative probability for Beta distrib. with param. A and B } { ------------------------------------------------------------------ Gamma distribution ------------------------------------------------------------------ } function DGamma(A, B, X : Float) : Float; external 'tpmath'; { Density of Gamma distribution with parameters A and B } function FGamma(A, B, X : Float) : Float; external 'tpmath'; { Cumulative probability for Gamma distrib. with param. A and B } { ------------------------------------------------------------------ Matrices and linear equations ------------------------------------------------------------------ } procedure GaussJordan(A : PMatrix; Lb, Ub1, Ub2 : Integer; var Det : Float); external 'tpmath'; { Transforms a matrix according to the Gauss-Jordan method } procedure LinEq(A : PMatrix; B : PVector; Lb, Ub : Integer; var Det : Float); external 'tpmath'; { Solves a linear system according to the Gauss-Jordan method } procedure Cholesky(A, L : PMatrix; Lb, Ub : Integer); external 'tpmath'; { Cholesky factorization of a positive definite symmetric matrix } procedure LU_Decomp(A : PMatrix; Lb, Ub : Integer); external 'tpmath'; { LU decomposition } procedure LU_Solve(A : PMatrix; B : PVector; Lb, Ub : Integer; X : PVector); external 'tpmath'; { Solution of linear system from LU decomposition } procedure QR_Decomp(A : PMatrix; Lb, Ub1, Ub2 : Integer; R : PMatrix); external 'tpmath'; { QR decomposition } procedure QR_Solve(Q, R : PMatrix; B : PVector; Lb, Ub1, Ub2 : Integer; X : PVector); external 'tpmath'; { Solution of linear system from QR decomposition } procedure SV_Decomp(A : PMatrix; Lb, Ub1, Ub2 : Integer; S : PVector; V : PMatrix); external 'tpmath'; { Singular value decomposition } procedure SV_SetZero(S : PVector; Lb, Ub : Integer; Tol : Float); external 'tpmath'; { Set lowest singular values to zero } procedure SV_Solve(U : PMatrix; S : PVector; V : PMatrix; B : PVector; Lb, Ub1, Ub2 : Integer; X : PVector); external 'tpmath'; { Solution of linear system from SVD } procedure SV_Approx(U : PMatrix; S : PVector; V : PMatrix; Lb, Ub1, Ub2 : Integer; A : PMatrix); external 'tpmath'; { Matrix approximation from SVD } procedure EigenVals(A : PMatrix; Lb, Ub : Integer; Lambda : PCompVector); external 'tpmath'; { Eigenvalues of a general square matrix } procedure EigenVect(A : PMatrix; Lb, Ub : Integer; Lambda : PCompVector; V : PMatrix); external 'tpmath'; { Eigenvalues and eigenvectors of a general square matrix } procedure Jacobi(A : PMatrix; Lb, Ub, MaxIter : Integer; Tol : Float; Lambda : PVector; V : PMatrix); external 'tpmath'; { Eigenvalues and eigenvectors of a symmetric matrix } { ------------------------------------------------------------------ Optimization ------------------------------------------------------------------ } procedure MinBrack(Func : TFunc; var A, B, C, Fa, Fb, Fc : Float); external 'tpmath'; { Brackets a minimum of a function } procedure GoldSearch(Func : TFunc; A, B : Float; MaxIter : Integer; Tol : Float; var Xmin, Ymin : Float); external 'tpmath'; { Minimization of a function of one variable (golden search) } procedure LinMin(Func : TFuncNVar; X, DeltaX : PVector; Lb, Ub : Integer; var R : Float; MaxIter : Integer; Tol : Float; var F_min : Float); external 'tpmath'; { Minimization of a function of several variables along a line } procedure Newton(Func : TFuncNVar; HessGrad : THessGrad; X : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; G : PVector; H_inv : PMatrix; var Det : Float); external 'tpmath'; { Minimization of a function of several variables (Newton's method) } procedure SaveNewton(FileName : string); external 'tpmath'; { Save Newton iterations in a file } procedure Marquardt(Func : TFuncNVar; HessGrad : THessGrad; X : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; G : PVector; H_inv : PMatrix; var Det : Float); external 'tpmath'; { Minimization of a function of several variables (Marquardt's method) } procedure SaveMarquardt(FileName : string); external 'tpmath'; { Save Marquardt iterations in a file } procedure BFGS(Func : TFuncNVar; Gradient : TGradient; X : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; G : PVector; H_inv : PMatrix); external 'tpmath'; { Minimization of a function of several variables (BFGS method) } procedure SaveBFGS(FileName : string); external 'tpmath'; { Save BFGS iterations in a file } procedure Simplex(Func : TFuncNVar; X : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; var F_min : Float); external 'tpmath'; { Minimization of a function of several variables (Simplex) } procedure SaveSimplex(FileName : string); external 'tpmath'; { Save Simplex iterations in a file } { ------------------------------------------------------------------ Nonlinear equations ------------------------------------------------------------------ } procedure RootBrack(Func : TFunc; var X, Y, FX, FY : Float); external 'tpmath'; { Brackets a root of function Func between X and Y } procedure Bisect(Func : TFunc; var X, Y : Float; MaxIter : Integer; Tol : Float; var F : Float); external 'tpmath'; { Bisection method } procedure Secant(Func : TFunc; var X, Y : Float; MaxIter : Integer; Tol : Float; var F : Float); external 'tpmath'; { Secant method } procedure NewtEq(Func, Deriv : TFunc; var X : Float; MaxIter : Integer; Tol : Float; var F : Float); external 'tpmath'; { Newton-Raphson method for a single nonlinear equation } procedure NewtEqs(Equations : TEquations; Jacobian : TJacobian; X, F : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float); external 'tpmath'; { Newton-Raphson method for a system of nonlinear equations } procedure Broyden(Equations : TEquations; X, F : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float); external 'tpmath'; { Broyden's method for a system of nonlinear equations } { ------------------------------------------------------------------ Polynomials and rational fractions ------------------------------------------------------------------ } function Poly(X : Float; Coef : PVector; Deg : Integer) : Float; external 'tpmath'; { Evaluates a polynomial } function RFrac(X : Float; Coef : PVector; Deg1, Deg2 : Integer) : Float; external 'tpmath'; { Evaluates a rational fraction } function RootPol1(A, B : Float; var X : Float) : Integer; external 'tpmath'; { Solves the linear equation A + B * X = 0 } function RootPol2(Coef : PVector; Z : PCompVector) : Integer; external 'tpmath'; { Solves a quadratic equation } function RootPol3(Coef : PVector; Z : PCompVector) : Integer; external 'tpmath'; { Solves a cubic equation } function RootPol4(Coef : PVector; Z : PCompVector) : Integer; external 'tpmath'; { Solves a quartic equation } function RootPol(Coef : PVector; Deg : Integer; Z : PCompVector) : Integer; external 'tpmath'; { Solves a polynomial equation } function SetRealRoots(Deg : Integer; Z : PCompVector; Tol : Float) : Integer; external 'tpmath'; { Set the imaginary part of a root to zero } procedure SortRoots(Deg : Integer; Z : PCompVector); external 'tpmath'; { Sorts the roots of a polynomial } { ------------------------------------------------------------------ Numerical integration and differential equations ------------------------------------------------------------------ } function TrapInt(X, Y : PVector; N : Integer) : Float; external 'tpmath'; { Integration by trapezoidal rule } function GausLeg(Func : TFunc; A, B : Float) : Float; external 'tpmath'; { Integral from A to B } function GausLeg0(Func : TFunc; B : Float) : Float; external 'tpmath'; { Integral from 0 to B } function Convol(Func1, Func2 : TFunc; T : Float) : Float; external 'tpmath'; { Convolution product at time T } procedure RKF45(F : TDiffEqs; Neqn : Integer; Y, Yp : PVector; var T : Float; Tout, RelErr, AbsErr : Float; var Flag : Integer); external 'tpmath'; { Integration of a system of differential equations } { ------------------------------------------------------------------ Fast Fourier Transform ------------------------------------------------------------------ } procedure FFT(NumSamples : LongInt; InArray, OutArray : PCompVector); external 'tpmath'; { Fast Fourier Transform } procedure IFFT(NumSamples : LongInt; InArray, OutArray : PCompVector); external 'tpmath'; { Inverse Fast Fourier Transform } procedure FFT_Integer(NumSamples : LongInt; RealIn, ImagIn : PIntVector; OutArray : PCompVector); external 'tpmath'; { Fast Fourier Transform for integer data } procedure FFT_Integer_Cleanup; external 'tpmath'; { Clear memory after a call to FFT_Integer } procedure CalcFrequency(NumSamples, FrequencyIndex : LongInt; InArray : PCompVector; var FFT : Complex); external 'tpmath'; { Direct computation of Fourier transform } { ------------------------------------------------------------------ Random numbers ------------------------------------------------------------------ } procedure SetRNG(RNG : RNG_Type); external 'tpmath'; { Select generator } procedure InitGen(Seed : LongInt); external 'tpmath'; { Initialize generator } function IRanGen : LongInt; external 'tpmath'; { 32-bit random integer in [-2^31 .. 2^31 - 1] } function IRanGen31 : LongInt; external 'tpmath'; { 31-bit random integer in [0 .. 2^31 - 1] } function RanGen1 : Float; external 'tpmath'; { 32-bit random real in [0,1] } function RanGen2 : Float; external 'tpmath'; { 32-bit random real in [0,1) } function RanGen3 : Float; external 'tpmath'; { 32-bit random real in (0,1) } function RanGen53 : Float; external 'tpmath'; { 53-bit random real in [0,1) } procedure InitMWC(Seed : LongInt); external 'tpmath'; { Initializes the 'Multiply with carry' random number generator } function IRanMWC : LongInt; external 'tpmath'; { Returns a 32 bit random number in [-2^31 ; 2^31-1] } procedure InitMT(Seed : LongInt); external 'tpmath'; { Initializes Mersenne Twister generator with a seed } procedure InitMTbyArray(InitKey : array of LongInt; KeyLength : Word); external 'tpmath'; { Initialize MT generator with an array InitKey[0..(KeyLength - 1)] } function IRanMT : LongInt; external 'tpmath'; { Random integer from MT generator } procedure InitUVAGbyString(KeyPhrase : string); external 'tpmath'; { Initializes the UVAG generator with a string } procedure InitUVAG(Seed : LongInt); external 'tpmath'; { Initializes the UVAG generator with an integer } function IRanUVAG : LongInt; external 'tpmath'; { Random integer from UVAG generator } function RanGaussStd : Float; external 'tpmath'; { Random number from standard normal distribution } function RanGauss(Mu, Sigma : Float) : Float; external 'tpmath'; { Random number from normal distrib. with mean Mu and S. D. Sigma } procedure RanMult(M : PVector; L : PMatrix; Lb, Ub : Integer; X : PVector); external 'tpmath'; { Random vector from multinormal distribution (correlated) } procedure RanMultIndep(M, S : PVector; Lb, Ub : Integer; X : PVector); external 'tpmath'; { Random vector from multinormal distribution (uncorrelated) } procedure InitMHParams(NCycles, MaxSim, SavedSim : Integer); external 'tpmath'; { Initializes Metropolis-Hastings parameters } procedure GetMHParams(var NCycles, MaxSim, SavedSim : Integer); external 'tpmath'; { Returns Metropolis-Hastings parameters } procedure Hastings(Func : TFuncNVar; T : Float; X : PVector; V : PMatrix; Lb, Ub : Integer; Xmat : PMatrix; X_min : PVector; var F_min : Float); external 'tpmath'; { Simulation of a probability density function by Metropolis-Hastings } procedure InitSAParams(NT, NS, NCycles : Integer; RT : Float); external 'tpmath'; { Initializes Simulated Annealing parameters } procedure SA_CreateLogFile(FileName : String); external 'tpmath'; { Initializes log file } procedure SimAnn(Func : TFuncNVar; X, Xmin, Xmax : PVector; Lb, Ub : Integer; var F_min : Float); external 'tpmath'; { Minimization of a function of several var. by simulated annealing } procedure InitGAParams(NP, NG : Integer; SR, MR, HR : Float); external 'tpmath'; { Initializes Genetic Algorithm parameters } procedure GA_CreateLogFile(FileName : String); external 'tpmath'; { Initializes log file } procedure GenAlg(Func : TFuncNVar; X, Xmin, Xmax : PVector; Lb, Ub : Integer; var F_min : Float); external 'tpmath'; { Minimization of a function of several var. by genetic algorithm } { ------------------------------------------------------------------ Statistics ------------------------------------------------------------------ } function Mean(X : PVector; Lb, Ub : Integer) : Float; external 'tpmath'; { Mean of sample X } function Median(X : PVector; Lb, Ub : Integer; Sorted : Boolean) : Float; external 'tpmath'; { Median of sample X } function StDev(X : PVector; Lb, Ub : Integer; M : Float) : Float; external 'tpmath'; { Standard deviation estimated from sample X } function StDevP(X : PVector; Lb, Ub : Integer; M : Float) : Float; external 'tpmath'; { Standard deviation of population } function Correl(X, Y : PVector; Lb, Ub : Integer) : Float; external 'tpmath'; { Correlation coefficient } function Skewness(X : PVector; Lb, Ub : Integer; M, Sigma : Float) : Float; external 'tpmath'; { Skewness of sample X } function Kurtosis(X : PVector; Lb, Ub : Integer; M, Sigma : Float) : Float; external 'tpmath'; { Kurtosis of sample X } procedure QSort(X : PVector; Lb, Ub : Integer); external 'tpmath'; { Quick sort (ascending order) } procedure DQSort(X : PVector; Lb, Ub : Integer); external 'tpmath'; { Quick sort (descending order) } procedure Interval(X1, X2 : Float; MinDiv, MaxDiv : Integer; var Min, Max, Step : Float); external 'tpmath'; { Determines an interval for a set of values } procedure StudIndep(N1, N2 : Integer; M1, M2, S1, S2 : Float; var T : Float; var DoF : Integer); external 'tpmath'; { Student t-test for independent samples } procedure StudPaired(X, Y : PVector; Lb, Ub : Integer; var T : Float; var DoF : Integer); external 'tpmath'; { Student t-test for paired samples } procedure AnOVa1(Ns : Integer; N : PIntVector; M, S : PVector; var V_f, V_r, F : Float; var DoF_f, DoF_r : Integer); external 'tpmath'; { One-way analysis of variance } procedure AnOVa2(NA, NB, Nobs : Integer; M, S : PMatrix; V, F : PVector; DoF : PIntVector); external 'tpmath'; { Two-way analysis of variance } procedure Snedecor(N1, N2 : Integer; S1, S2 : Float; var F : Float; var DoF1, DoF2 : Integer); external 'tpmath'; { Snedecor's F-test (comparison of two variances) } procedure Bartlett(Ns : Integer; N : PIntVector; S : PVector; var Khi2 : Float; var DoF : Integer); external 'tpmath'; { Bartlett's test (comparison of several variances) } procedure Mann_Whitney(N1, N2 : Integer; X1, X2 : PVector; var U, Eps : Float); external 'tpmath'; { Mann-Whitney test} procedure Wilcoxon(X, Y : PVector; Lb, Ub : Integer; var Ndiff : Integer; var T, Eps : Float); external 'tpmath'; { Wilcoxon test } procedure Kruskal_Wallis(Ns : Integer; N : PIntVector; X : PMatrix; var H : Float; var DoF : Integer); external 'tpmath'; { Kruskal-Wallis test } procedure Khi2_Conform(N_cls : Integer; N_estim : Integer; Obs : PIntVector; Calc : PVector; var Khi2 : Float; var DoF : Integer); external 'tpmath'; { Khi-2 test for conformity } procedure Khi2_Indep(N_lin : Integer; N_col : Integer; Obs : PIntMatrix; var Khi2 : Float; var DoF : Integer); external 'tpmath'; { Khi-2 test for independence } procedure Woolf_Conform(N_cls : Integer; N_estim : Integer; Obs : PIntVector; Calc : PVector; var G : Float; var DoF : Integer); external 'tpmath'; { Woolf's test for conformity } procedure Woolf_Indep(N_lin : Integer; N_col : Integer; Obs : PIntMatrix; var G : Float; var DoF : Integer); external 'tpmath'; { Woolf's test for independence } procedure DimStatClassVector(var C : PStatClassVector; Ub : Integer); external 'tpmath'; { Allocates an array of statistical classes: C[0..Ub] } procedure DelStatClassVector(var C : PStatClassVector; Ub : Integer); external 'tpmath'; { Deallocates an array of statistical classes: C[0..Ub] } procedure Distrib(X : PVector; Lb, Ub : Integer; A, B, H : Float; C : PStatClassVector); external 'tpmath'; { Distributes an array X[Lb..Ub] into statistical classes } { ------------------------------------------------------------------ Curve fit ------------------------------------------------------------------ } procedure LinFit(X, Y : PVector; Lb, Ub : Integer; B : PVector; V : PMatrix); external 'tpmath'; { Linear regression : Y = B(0) + B(1) * X } procedure WLinFit(X, Y, S : PVector; Lb, Ub : Integer; B : PVector; V : PMatrix); external 'tpmath'; { Weighted linear regression : Y = B(0) + B(1) * X } procedure PolFit(X, Y : PVector; Lb, Ub, Deg : Integer; B : PVector; V : PMatrix); external 'tpmath'; { Linear regression : Y = B(0) + B(1) * X + B(2) * X + ...} procedure WPolFit(X, Y, S : PVector; Lb, Ub, Deg : Integer; B : PVector; V : PMatrix); external 'tpmath'; { Weighted linear regression : Y = B(0) + B(1) * X + B(2) * X + ...} procedure MulFit(X : PMatrix; Y : PVector; Lb, Ub, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix); external 'tpmath'; { Multiple linear regression by Gauss-Jordan method } procedure WMulFit(X : PMatrix; Y, S : PVector; Lb, Ub, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix); external 'tpmath'; { Weighted multiple linear regression by Gauss-Jordan method } procedure SVDFit(X : PMatrix; Y : PVector; Lb, Ub, Nvar : Integer; ConsTerm : Boolean; SVDTol : Float; B : PVector; V : PMatrix); external 'tpmath'; { Multiple linear regression by SVD method } procedure WSVDFit(X : PMatrix; Y, S : PVector; Lb, Ub, Nvar : Integer; ConsTerm : Boolean; SVDTol : Float; B : PVector; V : PMatrix); external 'tpmath'; { Weighted multiple linear regression by SVD method } procedure SetOptAlgo(Algo : TOptAlgo); external 'tpmath'; { Sets the optimization algorithm for nonlinear regression } procedure SetMaxParam(N : Byte); external 'tpmath'; { Sets the maximum number of regression parameters for nonlinear regression } procedure SetParamBounds(I : Byte; ParamMin, ParamMax : Float); external 'tpmath'; { Sets the bounds on the I-th regression parameter } procedure NLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; B : PVector; FirstPar, LastPar : Integer; V : PMatrix); external 'tpmath'; { Unweighted nonlinear regression } procedure WNLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y, S : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; B : PVector; FirstPar, LastPar : Integer; V : PMatrix); external 'tpmath'; { Weighted nonlinear regression } procedure SetMCFile(FileName : String); external 'tpmath'; { Set file for saving MCMC simulations } procedure SimFit(RegFunc : TRegFunc; X, Y : PVector; Lb, Ub : Integer; B : PVector; FirstPar, LastPar : Integer; V : PMatrix); external 'tpmath'; { Simulation of unweighted nonlinear regression by MCMC } procedure WSimFit(RegFunc : TRegFunc; X, Y, S : PVector; Lb, Ub : Integer; B : PVector; FirstPar, LastPar : Integer; V : PMatrix); external 'tpmath'; { Simulation of weighted nonlinear regression by MCMC } procedure RegTest(Y, Ycalc : PVector; LbY, UbY : Integer; V : PMatrix; LbV, UbV : Integer; var Test : TRegTest); external 'tpmath'; { Test of unweighted regression } procedure WRegTest(Y, Ycalc, S : PVector; LbY, UbY : Integer; V : PMatrix; LbV, UbV : Integer; var Test : TRegTest); external 'tpmath'; { Test of weighted regression } { ------------------------------------------------------------------ Principal component analysis ------------------------------------------------------------------ } procedure VecMean(X : PMatrix; Lb, Ub, Nvar : Integer; M : PVector); external 'tpmath'; { Computes the mean vector M from matrix X } procedure VecSD(X : PMatrix; Lb, Ub, Nvar : Integer; M, S : PVector); external 'tpmath'; { Computes the vector of standard deviations S from matrix X } procedure MatVarCov(X : PMatrix; Lb, Ub, Nvar : Integer; M : PVector; V : PMatrix); external 'tpmath'; { Computes the variance-covariance matrix V from matrix X } procedure MatCorrel(V : PMatrix; Nvar : Integer; R : PMatrix); external 'tpmath'; { Computes the correlation matrix R from the var-cov matrix V } procedure PCA(R : PMatrix; Nvar : Integer; MaxIter : Integer; Tol : Float; Lambda : PVector; C, Rc : PMatrix); external 'tpmath'; { Performs a principal component analysis of the correlation matrix R } procedure ScaleVar(X : PMatrix; Lb, Ub, Nvar : Integer; M, S : PVector; Z : PMatrix); external 'tpmath'; { Scales a set of variables by subtracting means and dividing by SD's } procedure PrinFac(Z : PMatrix; Lb, Ub, Nvar : Integer; C, F : PMatrix); external 'tpmath'; { Computes principal factors } { ------------------------------------------------------------------ Strings ------------------------------------------------------------------ } function LTrim(S : String) : String; external 'tpmath'; { Removes leading blanks } function RTrim(S : String) : String; external 'tpmath'; { Removes trailing blanks } function Trim(S : String) : String; external 'tpmath'; { Removes leading and trailing blanks } function StrChar(N : Byte; C : Char) : String; external 'tpmath'; { Returns a string made of character C repeated N times } function RFill(S : String; L : Byte) : String; external 'tpmath'; { Completes string S with trailing blanks for a total length L } function LFill(S : String; L : Byte) : String; external 'tpmath'; { Completes string S with leading blanks for a total length L } function CFill(S : String; L : Byte) : String; external 'tpmath'; { Centers string S on a total length L } function Replace(S : String; C1, C2 : Char) : String; external 'tpmath'; { Replaces in string S all the occurences of C1 by C2 } function Extract(S : String; var Index : Byte; Delim : Char) : String; external 'tpmath'; { Extracts a field from a string } procedure Parse(S : String; Delim : Char; Field : PStrVector; var N : Byte); external 'tpmath'; { Parses a string into its constitutive fields } procedure SetFormat(NumLength, MaxDec : Integer; FloatPoint, NSZero : Boolean); external 'tpmath'; { Sets the numeric format } function FloatStr(X : Float) : String; external 'tpmath'; { Converts a real to a string according to the numeric format } function IntStr(N : LongInt) : String; external 'tpmath'; { Converts an integer to a string } function CompStr(Z : Complex) : String; external 'tpmath'; { Converts a complex number to a string } implementation end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ujacobi.pas�������������������������������������������������0000755�0001750�0001750�00000012070�11326425444�017610� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Eigenvalues and eigenvectors of a symmetric matrix ****************************************************************** } unit ujacobi; interface uses utypes, uminmax, utrigo; procedure Jacobi(A : PMatrix; Lb, Ub, MaxIter : Integer; Tol : Float; Lambda : PVector; V : PMatrix); { ------------------------------------------------------------------ Eigenvalues and eigenvectors of a symmetric matrix by the iterative method of Jacobi ------------------------------------------------------------------ Input parameters : A = matrix Lb = index of first matrix element Ub = index of last matrix element MaxIter = maximum number of iterations Tol = required precision ------------------------------------------------------------------ Output parameters : Lambda = eigenvalues in decreasing order V = matrix of eigenvectors (columns) ------------------------------------------------------------------ Possible results : MatOk MatNonConv ------------------------------------------------------------------ The eigenvectors are normalized, with their first component > 0 This procedure destroys the original matrix A ------------------------------------------------------------------ } implementation procedure Jacobi(A : PMatrix; Lb, Ub, MaxIter : Integer; Tol : Float; Lambda : PVector; V : PMatrix); var I, J, K, Im, Jm, Iter : Integer; B, C, C2, Na, Nd, P, Q, S, S2, R, T : Float; begin Iter := 0; Na := 0.0; Nd := 0.0; R := 0.0; for I := Lb to Ub do begin V^[I]^[I] := 1.0; Nd := Nd + Sqr(A^[I]^[I]); if I <> Ub then for J := Succ(I) to Ub do begin R := R + Sqr(A^[I]^[J]); V^[I]^[J] := 0.0; V^[J]^[I] := 0.0; end; end; Na := Nd + 2.0 * R; repeat R := 0.0; for I := Lb to Pred(Ub) do for J := Succ(I) to Ub do begin T := Abs(A^[I]^[J]); if T > R then begin R := T; Im := I; Jm := J; end; end; B := A^[Im]^[Im] - A^[Jm]^[Jm]; if B = 0 then begin C := Sqrt2div2; S := C * Sgn(A^[Im]^[Jm]); end else begin P := 2.0 * A^[Im]^[Jm] * Sgn(B); Q := Abs(B); R := Pythag(P, Q); C := Sqrt(0.5 * (1.0 + Q / R)); S := 0.5 * P / (R * C); end; for K := Lb to Ub do begin R := V^[K]^[Im]; V^[K]^[Im] := C * R + S * V^[K]^[Jm]; V^[K]^[Jm] := C * V^[K]^[Jm] - S * R; end; if Im <> Lb then for K := Lb to Pred(Im) do begin R := A^[K]^[Im]; A^[K]^[Im] := C * R + S * A^[K]^[Jm]; A^[K]^[Jm] := C * A^[K]^[Jm] - S * R; end; if Jm <> Succ(Im) then for K := Succ(Im) to Pred(Jm) do begin R := A^[Im]^[K]; A^[Im]^[K] := C * R + S * A^[K]^[Jm]; A^[K]^[Jm] := C * A^[K]^[Jm] - S * R; end; if Jm <> Ub then for K := Succ(Jm) to Ub do begin R := A^[Im]^[K]; A^[Im]^[K] := C * R + S * A^[Jm]^[K]; A^[Jm]^[K] := C * A^[Jm]^[K] - S * R; end; Nd := Nd + 2.0 * Sqr(A^[Im]^[Jm]); C2 := Sqr(C); S2 := Sqr(S); P := 2.0 * S * C * A^[Im]^[Jm]; R := A^[Im]^[Im]; A^[Im]^[Im] := C2 * R + S2 * A^[Jm]^[Jm] + P; A^[Jm]^[Jm] := S2 * R + C2 * A^[Jm]^[Jm] - P; A^[Im]^[Jm] := 0.0; Inc(Iter); if Iter > MaxIter then begin SetErrCode(MatNonConv); Exit; end; until Abs(1.0 - Na / Nd) < Tol; { The diagonal terms of the transformed matrix are the eigenvalues } for I := Lb to Ub do Lambda^[I] := A^[I]^[I]; { Sort eigenvalues and eigenvectors } for I := Lb to Pred(Ub) do begin K := I; R := Lambda^[I]; for J := Succ(I) to Ub do if Lambda^[J] > R then begin K := J; R := Lambda^[J]; end; FSwap(Lambda^[I], Lambda^[K]); for J := Lb to Ub do FSwap(V^[J]^[I], V^[J]^[K]); end; { Make sure that the first component of each eigenvector is > 0 } for J := Lb to Ub do if V^[Lb]^[J] < 0.0 then for I := Lb to Ub do V^[I]^[J] := - V^[I]^[J]; SetErrCode(MatOk); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uranuvag.pas������������������������������������������������0000755�0001750�0001750�00000005427�11326425446�020036� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** UVAG The Universal Virtual Array Generator by Alex Hay zenjew@hotmail.com Adapted to TPMath by Jean Debord ****************************************************************** In practice, Cardinal (6-7 times the output of Word) is the IntType of choice, but to demonstrate UVAG's scalability here, IntType can be defined as any integer data type. IRanUVAG globally provides (as rndint) an effectively infinite sequence of IntTypes, uniformly distributed (0, 2^(8*sizeof(IntType))-1). Output (bps) is dependent solely on IntSize=sizeof(IntType) and CPU speed. UVAG cycles at twice the speed of the 64-bit Mersenne Twister in a tenth the memory, tests well in DIEHARD, ENT and NIST and has a huge period. It is suitable for cryptographic purposes in that state(n) is not determinable from state(n+1). Most attractive is that it uses integers of any size and requires an array of only 255 + sizeof(IntType) bytes. Thus it is easily adapted to 128 bits and beyond with negligible memory increase. Lastly, seeding is easy. From near zero entropy (s[]=0, rndint > 0), UVAG bootstraps itself to full entropy in under 300 cycles. Very robust, no bad seeds. ****************************************************************** } unit uranuvag; interface type IntType = LongInt; procedure InitUVAGbyString(KeyPhrase : string); { Initializes the generator with a string } procedure InitUVAG(Seed : IntType); { Initializes the generator with an integer } function IRanUVAG : IntType; { Returns a 32-bit random integer } implementation const IntSize = SizeOf(IntType); type TByteArray = array[0..(255 + IntSize)] of Byte; var s : TByteArray; sp : ^IntType; { Pointer to random IntType somewhere in s } sindex : Byte; rndint : IntType; procedure InitUVAGbyString(KeyPhrase : string); var i, kindex, lk : Word; temp, tot : Byte; begin lk := Length(KeyPhrase); kindex := 1; tot := 0; { Initialize array } for i := 0 to 255 do s[i] := i; for i := 256 to (255 + IntSize) do s[i] := i - 256; { Shuffle array on keyphrase } for i := 0 to (255 + IntSize) do begin tot := tot + Ord(KeyPhrase[kindex]); temp := s[i]; s[i] := s[tot]; s[tot] := temp; kindex := kindex + 1; if kindex > lk then kindex := 1; { wrap around key } end; sindex := s[0]; rndint := 0 end; procedure InitUVAG(Seed : IntType); var S : string; begin Str(Seed, S); InitUVAGbyString(S); end; function IRanUVAG : IntType; begin sindex := sindex + 1; sp := @s[s[sindex]]; sp^ := sp^ + rndint; rndint := rndint + sp^; IRanUVAG := rndint end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uinvnorm.pas������������������������������������������������0000755�0001750�0001750�00000010400�11326425444�020044� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Inverse of Normal distribution function Translated from C code in Cephes library (http://www.moshier.net) ****************************************************************** } unit uinvnorm; interface uses utypes, uminmax, upolev; function InvNorm(P : Float) : Float; { ------------------------------------------------------------------ Inverse of Normal distribution function Returns the argument, X, for which the area under the Gaussian probability density function (integrated from minus infinity to X) is equal to P. ------------------------------------------------------------------ } implementation function InvNorm(P : Float) : Float; const P0 : TabCoef = ( 8.779679420055069160496E-3, - 7.649544967784380691785E-1, 2.971493676711545292135E0, - 4.144980036933753828858E0, 2.765359913000830285937E0, - 9.570456817794268907847E-1, 1.659219375097958322098E-1, - 1.140013969885358273307E-2, 0, 0); Q0 : TabCoef = ( - 5.303846964603721860329E0, 9.908875375256718220854E0, - 9.031318655459381388888E0, 4.496118508523213950686E0, - 1.250016921424819972516E0, 1.823840725000038842075E-1, - 1.088633151006419263153E-2, 0, 0, 0); P1 : TabCoef = ( 4.302849750435552180717E0, 4.360209451837096682600E1, 9.454613328844768318162E1, 9.336735653151873871756E1, 5.305046472191852391737E1, 1.775851836288460008093E1, 3.640308340137013109859E0, 3.691354900171224122390E-1, 1.403530274998072987187E-2, 1.377145111380960566197E-4); Q1 : TabCoef = ( 2.001425109170530136741E1, 7.079893963891488254284E1, 8.033277265194672063478E1, 5.034715121553662712917E1, 1.779820137342627204153E1, 3.845554944954699547539E0, 3.993627390181238962857E-1, 1.526870689522191191380E-2, 1.498700676286675466900E-4, 0); P2 : TabCoef = ( 3.244525725312906932464E0, 6.856256488128415760904E0, 3.765479340423144482796E0, 1.240893301734538935324E0, 1.740282292791367834724E-1, 9.082834200993107441750E-3, 1.617870121822776093899E-4, 7.377405643054504178605E-7, 0, 0); Q2 : TabCoef = ( 6.021509481727510630722E0, 3.528463857156936773982E0, 1.289185315656302878699E0, 1.874290142615703609510E-1, 9.867655920899636109122E-3, 1.760452434084258930442E-4, 8.028288500688538331773E-7, 0, 0, 0); P3 : TabCoef = ( 2.020331091302772535752E0, 2.133020661587413053144E0, 2.114822217898707063183E-1, - 6.500909615246067985872E-3, - 7.279315200737344309241E-4, - 1.275404675610280787619E-5, - 6.433966387613344714022E-8, - 7.772828380948163386917E-11, 0, 0); Q3 : TabCoef = ( 2.278210997153449199574E0, 2.345321838870438196534E-1, - 6.916708899719964982855E-3, - 7.908542088737858288849E-4, - 1.387652389480217178984E-5, - 7.001476867559193780666E-8, - 8.458494263787680376729E-11, 0, 0, 0); var X, Y, Z, Y2, X0, X1 : Float; Code : Integer; begin if (P <= 0.0) or (P >= 1.0) then begin InvNorm := DefaultVal(FDomain, Sgn(P) * MaxNum); Exit; end; Code := 1; Y := P; if Y > (1.0 - 0.13533528323661269189) then { 0.135... = exp(-2) } begin Y := 1.0 - Y; Code := 0; end; if Y > 0.13533528323661269189 then begin Y := Y - 0.5; Y2 := Y * Y; X := Y + Y * (Y2 * PolEvl(Y2, P0, 7) / P1Evl(Y2, Q0, 7)); X := X * Sqrt2Pi; InvNorm := X; Exit; end; X := Sqrt(- 2.0 * Ln(Y)); X0 := X - Ln(X) / X; Z := 1.0 / X; if X < 8.0 then X1 := Z * PolEvl(Z, P1, 9) / P1Evl(Z, Q1, 9) else if X < 32.0 then X1 := Z * PolEvl(Z, P2, 7) / P1Evl(Z, Q2, 7) else X1 := Z * PolEvl(Z, P3, 7) / P1Evl(Z, Q3, 7); X := X0 - X1; if Code <> 0 then X := - X; InvNorm := X; end; end.����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ucompvec.pas������������������������������������������������0000755�0001750�0001750�00000002164�11326425444�020020� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Comparison of two vectors ****************************************************************** } unit ucompvec; interface uses utypes; function CompVec(X, Xref : PVector; Lb, Ub : Integer; Tol : Float) : Boolean; { ------------------------------------------------------------------ Checks if each component of vector X is within a fraction Tol of the corresponding component of the reference vector Xref. In this case, the function returns True, otherwise it returns False ------------------------------------------------------------------ } implementation function CompVec(X, Xref : PVector; Lb, Ub : Integer; Tol : Float) : Boolean; var I : Integer; Ok : Boolean; ITol : Float; begin I := Lb; Ok := True; repeat ITol := Tol * Abs(Xref^[I]); if ITol < MachEp then ITol := MachEp; Ok := Ok and (Abs(X^[I] - Xref^[I]) < ITol); I := I + 1; until (not Ok) or (I > Ub); CompVec := Ok; end; end.������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/utrigo.pas��������������������������������������������������0000755�0001750�0001750�00000005421�11326425446�017511� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Trigonometric functions ****************************************************************** } unit utrigo; interface uses utypes, uminmax; function Pythag(X, Y : Float) : Float; { Sqrt(X^2 + Y^2) } function FixAngle(Theta : Float) : Float; { Set Theta in -Pi..Pi } function Tan(X : Float) : Float; { Tangent } function ArcSin(X : Float) : Float; { Arc sinus } function ArcCos(X : Float) : Float; { Arc cosinus } function ArcTan2(Y, X : Float) : Float; { Angle (Ox, OM) with M(X,Y) } implementation function Pythag(X, Y : Float) : Float; { Computes Sqrt(X^2 + Y^2) without destructive underflow or overflow } var AbsX, AbsY : Float; begin SetErrCode(FOk); AbsX := Abs(X); AbsY := Abs(Y); if AbsX > AbsY then Pythag := AbsX * Sqrt(1.0 + Sqr(AbsY / AbsX)) else if AbsY = 0.0 then Pythag := 0.0 else Pythag := AbsY * Sqrt(1.0 + Sqr(AbsX / AbsY)); end; function FixAngle(Theta : Float) : Float; begin SetErrCode(FOk); while Theta > Pi do Theta := Theta - TwoPi; while Theta <= - PI do Theta := Theta + TwoPi; FixAngle := Theta; end; function Tan(X : Float) : Float; var SinX, CosX : Float; begin SetErrCode(FOk); SinX := Sin(X); CosX := Cos(X); if CosX = 0.0 then Tan := DefaultVal(FSing, Sgn(SinX) * MaxNum) else Tan := SinX / CosX; end; function ArcSin(X : Float) : Float; begin SetErrCode(FOk); if (X < - 1.0) or (X > 1.0) then ArcSin := DefaultVal(FDomain, 0.0) else if X = 1.0 then ArcSin := PiDiv2 else if X = - 1.0 then ArcSin := - PiDiv2 else ArcSin := ArcTan(X / Sqrt(1.0 - Sqr(X))); end; function ArcCos(X : Float) : Float; begin SetErrCode(FOk); if (X < - 1.0) or (X > 1.0) then ArcCos := DefaultVal(FDomain, 0.0) else if X = 1.0 then ArcCos := 0.0 else if X = - 1.0 then ArcCos := Pi else ArcCos := PiDiv2 - ArcTan(X / Sqrt(1.0 - Sqr(X))); end; function ArcTan2(Y, X : Float) : Float; var Theta : Float; begin SetErrCode(FOk); if X = 0.0 then if Y = 0.0 then ArcTan2 := 0.0 else if Y > 0.0 then ArcTan2 := PiDiv2 else ArcTan2 := - PiDiv2 else begin { 4th/1st quadrant -Pi/2..Pi/2 } Theta := ArcTan(Y / X); { 2nd/3rd quadrants } if X < 0.0 then if Y >= 0.0 then Theta := Theta + Pi { 2nd quadrant: Pi/2..Pi } else Theta := Theta - Pi; { 3rd quadrant: -Pi..-Pi/2 } ArcTan2 := Theta; end; end; end.�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uranmult.pas������������������������������������������������0000755�0001750�0001750�00000003637�11326425446�020056� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Multinormal distribution ****************************************************************** } unit uranmult; interface uses utypes, urangaus; procedure RanMult(M : PVector; L : PMatrix; Lb, Ub : Integer; X : PVector); { ------------------------------------------------------------------ Generates a random vector X from a multinormal distribution. M is the mean vector, L is the Cholesky factor (lower triangular) of the variance-covariance matrix. ------------------------------------------------------------------ } procedure RanMultIndep(M, S : PVector; Lb, Ub : Integer; X : PVector); { ------------------------------------------------------------------ Generates a random vector X from a multinormal distribution with uncorrelated variables. M is the mean vector, S is the vector of standard deviations. ------------------------------------------------------------------ } implementation procedure RanMult(M : PVector; L : PMatrix; Lb, Ub : Integer; X : PVector); var I, J : Integer; U : PVector; begin { Form a vector U of independent standard normal variates } DimVector(U, Ub); for I := Lb to Ub do U^[I] := RanGaussStd; { Form X = M + L * U, which follows the multinormal distribution } for I := Lb to Ub do begin X^[I] := M^[I]; for J := Lb to I do X^[I] := X^[I] + L^[I]^[J] * U^[J] end; DelVector(U, Ub); end; procedure RanMultIndep(M, S : PVector; Lb, Ub : Integer; X : PVector); var I : Integer; begin for I := Lb to Ub do X^[I] := RanGauss(M^[I], S^[I]) end; end. �������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/upolfit.pas�������������������������������������������������0000755�0001750�0001750�00000010075�11326425446�017663� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Polynomial regression : Y = B(0) + B(1) * X + B(2) * X^2 + ... ****************************************************************** } unit upolfit; interface uses utypes, ulineq; procedure PolFit(X, Y : PVector; Lb, Ub, Deg : Integer; B : PVector; V : PMatrix); { ------------------------------------------------------------------ Unweighted polynomial regression ------------------------------------------------------------------ Input parameters: X, Y = point coordinates Lb, Ub = array bounds Deg = degree of polynomial Output parameters: B = regression parameters V = inverse matrix ------------------------------------------------------------------ } procedure WPolFit(X, Y, S : PVector; Lb, Ub, Deg : Integer; B : PVector; V : PMatrix); { ------------------------------------------------------------------ Weighted polynomial regression ------------------------------------------------------------------ Additional input parameter: S = standard deviations of observations ------------------------------------------------------------------ } implementation procedure PolFit(X, Y : PVector; Lb, Ub, Deg : Integer; B : PVector; V : PMatrix); var I, I1, J, K, D1 : Integer; XI, Det : Float; begin if Ub - Lb < Deg then begin SetErrCode(MatErrDim); Exit; end; { Initialize } for I := 0 to Deg do begin for J := 0 to Deg do V^[I]^[J] := 0.0; B^[I] := 0.0; end; V^[0]^[0] := Ub - Lb + 1; for K := Lb to Ub do begin XI := X^[K]; { x^i } B^[0] := B^[0] + Y^[K]; V^[0]^[1] := V^[0]^[1] + XI; B^[1] := B^[1] + XI * Y^[K]; for I := 2 to Deg do begin XI := XI * X^[K]; V^[0]^[I] := V^[0]^[I] + XI; { First line of matrix: 1 --> x^d } B^[I] := B^[I] + XI * Y^[K]; { Constant vector: y --> x^d.y } end; for I := 1 to Deg do begin XI := XI * X^[K]; V^[I]^[Deg] := V^[I]^[Deg] + XI; { Last col. of matrix: x^d --> x^2d } end; end; { Fill lower matrix } D1 := Deg - 1; for I := 1 to Deg do begin I1 := I - 1; for J := 0 to D1 do V^[I]^[J] := V^[I1]^[J + 1]; end; { Solve system } LinEq(V, B, 0, Deg, Det); end; procedure WPolFit(X, Y, S : PVector; Lb, Ub, Deg : Integer; B : PVector; V : PMatrix); var I, I1, J, K, D1 : Integer; W, WXI, Det : Float; begin if Ub - Lb < Deg then begin SetErrCode(MatErrDim); Exit; end; { Initialize } for I := 0 to Deg do begin for J := 0 to Deg do V^[I]^[J] := 0.0; B^[I] := 0.0; end; for K := Lb to Ub do begin if S^[K] <= 0.0 then begin SetErrCode(MatSing); Exit; end; W := 1.0 / Sqr(S^[K]); WXI := W * X^[K]; { w.x^i } V^[0]^[0] := V^[0]^[0] + W; B^[0] := B^[0] + W * Y^[K]; V^[0]^[1] := V^[0]^[1] + WXI; B^[1] := B^[1] + WXI * Y^[K]; for I := 2 to Deg do begin WXI := WXI * X^[K]; V^[0]^[I] := V^[0]^[I] + WXI; { First line of matrix: w --> w.x^d } B^[I] := B^[I] + WXI * Y^[K]; { Constant vector: w.y --> w.x^d.y } end; for I := 1 to Deg do begin WXI := WXI * X^[K]; V^[I]^[Deg] := V^[I]^[Deg] + WXI; { Last col. of matrix: w.x^d --> w.x^2d } end; end; { Fill lower matrix } D1 := Deg - 1; for I := 1 to Deg do begin I1 := I - 1; for J := 0 to D1 do V^[I]^[J] := V^[I1]^[J + 1]; end; { Solve system } LinEq(V, B, 0, Deg, Det); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/udistrib.pas������������������������������������������������0000755�0001750�0001750�00000005622�11326425444�020026� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Statistical distribution ****************************************************************** } unit udistrib; interface uses utypes; procedure DimStatClassVector(var C : PStatClassVector; Ub : Integer); { ------------------------------------------------------------------ Allocates an array of statistical classes: C[0..Ub] ------------------------------------------------------------------ } procedure DelStatClassVector(var C : PStatClassVector; Ub : Integer); { ------------------------------------------------------------------ Deallocates an array of statistical classes: C[0..Ub] ------------------------------------------------------------------ } procedure Distrib(X : PVector; Lb, Ub : Integer; A, B, H : Float; C : PStatClassVector); { ------------------------------------------------------------------ Distributes the values of array X[Lb..Ub] into M classes with equal width H, according to the following scheme: C[1] C[2] C[M] ]-------]-------].......]-------]-------] A A+H A+2H B such that B = A + M * H ------------------------------------------------------------------ } implementation procedure DimStatClassVector(var C : PStatClassVector; Ub : Integer); var I : Integer; begin { Check bounds } if (Ub < 0) or (Ub > MAX_CLS) then begin C := nil; Exit; end; { Allocate vector } GetMem(C, (Ub + 1) * SizeOf(StatClass)); if C = nil then Exit; { Initialize vector } for I := 0 to Ub do with C^[I] do begin Inf := 0.0; Sup := 0.0; N := 0; F := 0.0; D := 0.0; end; end; procedure DelStatClassVector(var C : PStatClassVector; Ub : Integer); begin if C <> nil then begin FreeMem(C, (Ub + 1) * SizeOf(StatClass)); C := nil; end; end; function NumCls(X, A, H : Float) : Integer; { Returns the index of the class containing X A is the lower bound of the first class H is the class width } var Y : Float; I : Integer; begin Y := (X - A) / H; I := Trunc(Y); if Y <> I then Inc(I); NumCls := I; end; procedure Distrib(X : PVector; Lb, Ub : Integer; A, B, H : Float; C : PStatClassVector); var I, K, M, Nt : Integer; begin M := Round((B - A) / H); for K := 1 to M do C^[K].N := 0; for I := Lb to Ub do begin K := NumCls(X^[I], A, H); Inc(C^[K].N); end; Nt := Ub - Lb + 1; for K := 1 to M do with C^[K] do begin Inf := A + (K - 1) * H; Sup := Inf + H; F := N / Nt; D := F / H; end; end; end.��������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/urkf.pas����������������������������������������������������0000755�0001750�0001750�00000050736�11326425446�017160� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Numerical integration of a system of differential equations by the Runge-Kutta-Fehlberg (RKF) method. Adapted from a Fortran-90 program available at: http://www.csit.fsu.edu/~burkardt/f_src/rkf45/rkf45.f90 ****************************************************************** } unit urkf; interface uses utypes, uminmax; procedure RKF45(F : TDiffEqs; Neqn : Integer; Y, Yp : PVector; var T : Float; Tout, RelErr, AbsErr : Float; var Flag : Integer); implementation const maxeqn : Integer = 0; flag_save : Integer = -1000; init : Integer = -1000; kflag : Integer = -1000; kop : Integer = -1; nfe : Integer = -1; relerr_save : Float = -1.0; abserr_save : Float = -1.0; h : Float = -1.0; f1 : PVector = nil; f2 : PVector = nil; f3 : PVector = nil; f4 : PVector = nil; f5 : PVector = nil; procedure Fehl(F : TDiffEqs; Neqn : Integer; Y : PVector; T, H : Float; Yp, F1, F2, F3, F4, F5, S : PVector); { ------------------------------------------------------------------ Fehl takes one Fehlberg fourth-fifth order step (double precision). Discussion: This routine integrates a system of Neqn first order ordinary differential equations of the form dY(i)/dT = F(T,Y(1:Neqn)) where the initial values Y and the initial derivatives YP are specified at the starting point T. The routine advances the solution over the fixed step H and returns the fifth order (sixth order accurate locally) solution approximation at T+H in array S. The formulas have been grouped to control loss of significance. The routine should be called with an H not smaller than 13 units of roundoff in T so that the various independent arguments can be distinguished. Modified: 27 March 2004 Author: H A Watts and L F Shampine, Sandia Laboratories, Albuquerque, New Mexico. Reference: E. Fehlberg, Low-order Classical Runge-Kutta Formulas with Stepsize Control, NASA Technical Report R-315. L F Shampine, H A Watts, S Davenport, Solving Non-stiff Ordinary Differential Equations - The State of the Art, SIAM Review, Volume 18, pages 376-411, 1976. Parameters: Input, external F, a user-supplied subroutine to evaluate the derivatives Y'(T), of the form: procedure(X : Float; Y, D : PVector); Input, Neqn, the number of equations to be integrated. Input, Y(Neqn), the current value of the dependent variable. Input, T, the current value of the independent variable. Input, H, the step size to take. Input, YP(Neqn), the current value of the derivative of the dependent variable. Output, F1(Neqn), F2(Neqn), F3(Neqn), F4(Neqn), F5(Neqn), derivative values needed for the computation. Output, S(Neqn), the estimate of the solution at T+H. ------------------------------------------------------------------ } const C1 = 3.0 / 32.0; C2 = 3.0 / 8.0; C3 = 1.0 / 2197.0; C4 = 12.0 / 13.0; C5 = 1.0 / 4104.0; C6 = 1.0 / 20520.0; C7 = 1.0 / 7618050.0; var ch : Float; i : Integer; begin ch := 0.25 * h; for i := 1 to neqn do f5^[i] := y^[i] + ch * yp^[i]; f(t + ch, f5, f1); ch := C1 * h; for i := 1 to neqn do f5^[i] := y^[i] + ch * (yp^[i] + 3.0 * f1^[i]); f(t + C2 * h, f5, f2); ch := C3 * h; for i := 1 to neqn do f5^[i] := y^[i] + ch * (1932.0 * yp^[i] + (7296.0 * f2^[i] - 7200.0 * f1^[i])); f(t + C4 * h, f5, f3); ch := C5 * h; for i := 1 to neqn do f5^[i] := y^[i] + ch * ((8341.0 * yp^[i] - 845.0 * f3^[i]) + (29440.0 * f2^[i] - 32832.0 * f1^[i])); f(t + h, f5, f4); ch := C6 * h; for i := 1 to neqn do f1^[i] := y^[i] + ch * ((-6080.0 * yp^[i] + (9295.0 * f3^[i] - 5643.0 * f4^[i])) + (41040.0 * f1^[i] - 28352.0 * f2^[i])); f(t + 0.5 * h, f1, f5); { Ready to compute the approximate solution at T+H. } ch := C7 * h; for i := 1 to neqn do s^[i] := y^[i] + ch * ((902880.0 * yp^[i] + (3855735.0 * f3^[i] - 1371249.0 * f4^[i])) + (3953664.0 * f2^[i] + 277020.0 * f5^[i])); end; procedure ReDim_Arrays(neqn : Integer); { Redimensions global arrays if necessary } begin DelVector(f1, maxeqn); DelVector(f2, maxeqn); DelVector(f3, maxeqn); DelVector(f4, maxeqn); DelVector(f5, maxeqn); maxeqn := neqn; DimVector(f1, maxeqn); DimVector(f2, maxeqn); DimVector(f3, maxeqn); DimVector(f4, maxeqn); DimVector(f5, maxeqn); end; procedure RKF45(F : TDiffEqs; Neqn : Integer; Y, Yp : PVector; var T : Float; Tout, RelErr, AbsErr : Float; var Flag : Integer); { ------------------------------------------------------------------ RKF45 carries out the Runge-Kutta-Fehlberg method (double precision). Discussion: This routine is primarily designed to solve non-stiff and mildly stiff differential equations when derivative evaluations are inexpensive. It should generally not be used when the user is demanding high accuracy. This routine integrates a system of Neqn first-order ordinary differential equations of the form: dY(i)/dT = F(T,Y(1),Y(2),...,Y(Neqn)) where the Y(1:Neqn) are given at T. Typically the subroutine is used to integrate from T to TOUT but it can be used as a one-step integrator to advance the solution a single step in the direction of TOUT. On return, the parameters in the call list are set for continuing the integration. The user has only to call again (and perhaps define a new value for TOUT). Before the first call, the user must * supply the subroutine F(T,Y,YP) to evaluate the right hand side; and declare F in an EXTERNAL statement; * initialize the parameters: Neqn, Y(1:Neqn), T, TOUT, RELERR, ABSERR, FLAG. In particular, T should initially be the starting point for integration, Y should be the value of the initial conditions, and FLAG should normally be +1. Normally, the user only sets the value of FLAG before the first call, and thereafter, the program manages the value. On the first call, FLAG should normally be +1 (or -1 for single step mode.) On normal return, FLAG will have been reset by the program to the value of 2 (or -2 in single step mode), and the user can continue to call the routine with that value of FLAG. (When the input magnitude of FLAG is 1, this indicates to the program that it is necessary to do some initialization work. An input magnitude of 2 lets the program know that that initialization can be skipped, and that useful information was computed earlier.) The routine returns with all the information needed to continue the integration. If the integration reached TOUT, the user need only define a new TOUT and call again. In the one-step integrator mode, returning with FLAG = -2, the user must keep in mind that each step taken is in the direction of the current TOUT. Upon reaching TOUT, indicated by the output value of FLAG switching to 2, the user must define a new TOUT and reset FLAG to -2 to continue in the one-step integrator mode. In some cases, an error or difficulty occurs during a call. In that case, the output value of FLAG is used to indicate that there is a problem that the user must address. These values include: * 3, integration was not completed because the input value of RELERR, the relative error tolerance, was too small. RELERR has been increased appropriately for continuing. If the user accepts the output value of RELERR, then simply reset FLAG to 2 and continue. * 4, integration was not completed because more than MAXNFE derivative evaluations were needed. This is approximately (MAXNFE/6) steps. The user may continue by simply calling again. The function counter will be reset to 0, and another MAXNFE function evaluations are allowed. * 5, integration was not completed because the solution vanished, making a pure relative error test impossible. The user must use a non-zero ABSERR to continue. Using the one-step integration mode for one step is a good way to proceed. * 6, integration was not completed because the requested accuracy could not be achieved, even using the smallest allowable stepsize. The user must increase the error tolerances ABSERR or RELERR before continuing. It is also necessary to reset FLAG to 2 (or -2 when the one-step integration mode is being used). The occurrence of FLAG = 6 indicates a trouble spot. The solution is changing rapidly, or a singularity may be present. It often is inadvisable to continue. * 7, it is likely that this routine is inefficient for solving this problem. Too much output is restricting the natural stepsize choice. The user should use the one-step integration mode with the stepsize determined by the code. If the user insists upon continuing the integration, reset FLAG to 2 before calling again. Otherwise, execution will be terminated. * 8, invalid input parameters, indicates one of the following: Neqn <= 0; T = TOUT and |FLAG| /= 1; RELERR < 0 or ABSERR < 0; FLAG == 0 or FLAG < -2 or 8 < FLAG. Modified: 27 March 2004 Author: H A Watts and L F Shampine, Sandia Laboratories, Albuquerque, New Mexico. Reference: E. Fehlberg, Low-order Classical Runge-Kutta Formulas with Stepsize Control, NASA Technical Report R-315. L F Shampine, H A Watts, S Davenport, Solving Non-stiff Ordinary Differential Equations - The State of the Art, SIAM Review, Volume 18, pages 376-411, 1976. Parameters: Input, external F, a user-supplied subroutine to evaluate the derivatives Y (T), of the form: sub f ( t as double, y() as double, yp() as double ) Input, Neqn, the number of equations to be integrated. Input/output, Y(Neqn), the current solution vector at T. Input/output, YP(Neqn), the current value of the derivative of the dependent variable. The user should not set or alter this information Input/output, T, the current value of the independent variable. Input, TOUT, the output point at which solution is desired. TOUT = T is allowed on the first call only, in which case the routine returns with FLAG = 2 if continuation is possible. Input, RELERR, ABSERR, the relative and absolute error tolerances for the local error test. At each step the code requires: abs ( local error ) <= RELERR * abs ( Y ) + ABSERR for each component of the local error and the solution vector Y. RELERR cannot be "too small". If the routine believes RELERR has been set too small, it will reset RELERR to an acceptable value and return immediately for user action. Input/output, FLAG, indicator for status of integration. On the first call, set FLAG to +1 for normal use, or to -1 for single step mode. On return, a value of 2 or -2 indicates normal progress, while any other value indicates a problem that should be addressed. ------------------------------------------------------------------ } const remin = 1.0E-12; maxnfe = 3000; var k, mflag : Integer; ae, dt, ee, eeoet, esttol, et : Float; hmin, relerr_min, s, scale, tol, toln, ypk : Float; hfaild, outp : Boolean; label Cont, Done; begin { Check the input parameters. } if (neqn < 1) or (relerr < 0) or (abserr < 0) or ((flag = 0) or (flag > 8) or (flag < -2)) then begin flag := 8; exit; end; mflag := abs(flag); { Is this a continuation call? } if mflag <> 1 then begin if (t = tout) and (kflag <> 3) then begin flag := 8; exit; end; if mflag = 2 then begin if kflag = 3 then begin flag := flag_save; mflag := abs(flag) end else if init = 0 then flag := flag_save else if kflag = 4 then nfe := 0 else if (kflag = 5) and (abserr = 0) then exit else if (kflag = 6) and (relerr <= relerr_save) and (abserr <= abserr_save) then exit; end else { FLAG = 3, 4, 5, 6, 7 or 8. } begin if flag = 3 then begin flag := flag_save; if kflag = 3 then mflag := abs(flag) end else if flag = 4 then begin nfe := 0; flag := flag_save; if kflag = 3 then mflag := abs(flag) end else if (flag = 5) and (abserr > 0) then begin flag := flag_save; if kflag = 3 then mflag := abs(flag) end else { Integration cannot be continued because the user did not } exit; { respond to the instructions pertaining to FLAG = 5,6,7,8 } end; end; { Save the input value of FLAG. } { Set the continuation flag KFLAG for subsequent input checking. } flag_save := flag; kflag := 0; { Save RELERR and ABSERR for checking input on subsequent calls. } relerr_save := relerr; abserr_save := abserr; { Restrict the relative error tolerance to be at least 2 * EPS + REMIN to avoid limiting precision difficulties arising from impossible accuracy requests. } relerr_min := 2 * MachEp + remin; { Is the relative error tolerance too small? } if relerr < relerr_min then begin relerr := relerr_min; flag := 3; kflag := 3; exit end; dt := tout - t; { Initialization: Set the initialization completion indicator, INIT; set the indicator for too many output points, KOP; evaluate the initial derivatives; set the counter for function evaluations, NFE; estimate the starting stepsize. } if mflag = 1 then begin init := 0; kop := 0; f(t, y, yp); nfe := 1; if t = tout then begin flag := 2; exit; end; end; if init = 0 then begin init := 1; h := abs(dt); toln := 0; for k := 1 to neqn do begin tol := relerr * abs (y^[k]) + abserr; if tol > 0 then begin toln := tol; ypk := abs(yp^[k]); if tol < ypk * h * h * h * h * h then h := Exp(0.2 * Ln(tol / ypk)); end end; if toln <= 0 then h := 0; h := FMax(h, 26 * MachEp * FMax(abs(t), abs(dt))); flag_save := sgn(flag) * 2 end; { Set the stepsize for integration in the direction from T to TOUT. } h := sgn(dt) * abs(h); { Test to see if too may output points are being requested. } if 2 * abs(dt) <= abs(h) then kop := kop + 1; { Unnecessary frequency of output. } if kop = 100 then begin kop := 0; flag := 7; exit end; { If we are too close to the output point, then simply extrapolate and return. } if abs(dt) <= 26 * MachEp * abs(t) then begin t := tout; for k := 1 to neqn do y^[k] := y^[k] + dt * yp^[k]; f(t, y, yp); nfe := nfe + 1; flag := 2; exit end; { Initialize the output point indicator. } outp := False; { To avoid premature underflow in the error tolerance function, scale the error tolerances. } scale := 2 / relerr; ae := scale * abserr; { Redimension global arrays if necessary } if neqn > maxeqn then ReDim_Arrays(neqn); { Step by step integration. } repeat hfaild := False; { Set the smallest allowable stepsize. } hmin := 26 * MachEp * abs(t); { Adjust the stepsize if necessary to hit the output point. Look ahead two steps to avoid drastic changes in the stepsize and thus lessen the impact of output points on the code. } dt := tout - t; if 2.0 * abs(h) > abs(dt) then begin { Will the next successful step complete the integration to the output point? } if abs(dt) <= abs(h) then begin outp := True; h := dt end else h := 0.5 * dt; end; { Here begins the core integrator for taking a single step. The tolerances have been scaled to avoid premature underflow in computing the error tolerance function ET. To avoid problems with zero crossings, relative error is measured using the average of the magnitudes of the solution at the beginning and end of a step. The error estimate formula has been grouped to control loss of significance. To distinguish the various arguments, H is not permitted to become smaller than 26 units of roundoff in T. Practical limits on the change in the stepsize are enforced to smooth the stepsize selection process and to avoid excessive chattering on problems having discontinuities. To prevent unnecessary failures, the code uses 9/10 the stepsize it estimates will succeed. After a step failure, the stepsize is not allowed to increase for the next attempted step. This makes the code more efficient on problems having discontinuities and more effective in general since local extrapolation is being used and extra caution seems warranted. Test the number of derivative function evaluations. If okay, try to advance the integration from T to T+H. } repeat { Have we done too much work? } if maxnfe < nfe then begin flag := 4; kflag := 4; exit end; { Advance an approximate solution over one step of length H. } Fehl(f, neqn, y, t, h, yp, f1, f2, f3, f4, f5, f1); nfe := nfe + 5; { Compute and test allowable tolerances versus local error estimates and remove scaling of tolerances. The relative error is measured with respect to the average of the magnitudes of the solution at the beginning and end of the step. } eeoet := 0; for k := 1 to neqn do begin et := abs(y^[k]) + abs(f1^[k]) + ae; if et <= 0 then begin flag := 5; exit end; ee := abs((-2090.0 * yp^[k] + (21970.0 * f3^[k] - 15048.0 * f4^[k])) + (22528.0 * f2^[k] - 27360.0 * f5^[k])); eeoet := FMax(eeoet, ee / et); end; esttol := abs(h) * eeoet * scale / 752400.0; if esttol <= 1 then goto Cont; { Unsuccessful step. Reduce the stepsize, try again. The decrease is limited to a factor of 1/10. } hfaild := True; outp := False; if esttol < 59049.0 then s := 0.9 / Exp(0.2 * Ln(esttol)) else s := 0.1; h := s * h; if abs(h) < hmin then begin flag := 6; kflag := 6; exit; end; until False; { We exited the loop because we took a successful step. Store the solution for T+H, and evaluate the derivative there. } Cont: t := t + h; for k := 1 to neqn do y^[k] := f1^[k]; f(t, y, yp); nfe := nfe + 1; { Choose the next stepsize. The increase is limited to a factor of 5. If the step failed, the next stepsize is not allowed to increase. } if 0.0001889568 < esttol then s := 0.9 / Exp(0.2 * Ln(esttol)) else s := 5.0; if hfaild then s := FMin(s, 1.0); h := sgn(h) * FMax(s * abs(h), hmin); { End of core integrator Should we take another step? } if outp then begin t := tout; flag := 2; exit end; if flag <= 0 then goto Done; until False; { One step integration mode. } Done: flag := -2; end; end. ����������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uskew.pas���������������������������������������������������0000755�0001750�0001750�00000002001�11326425446�017325� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Skewness and kurtosis ****************************************************************** } unit uskew; interface uses utypes; function Skewness(X : PVector; Lb, Ub : Integer; M, Sigma : Float) : Float; function Kurtosis(X : PVector; Lb, Ub : Integer; M, Sigma : Float) : Float; implementation function Skewness(X : PVector; Lb, Ub : Integer; M, Sigma : Float) : Float; var S, T : Float; I : Integer; begin S := 0.0; for I := Lb to Ub do begin T := (X^[I] - M) / Sigma; S := S + T * Sqr(T); end; Skewness := S / (Ub - Lb + 1); end; function Kurtosis(X : PVector; Lb, Ub : Integer; M, Sigma : Float) : Float; var S, T : Float; I : Integer; begin S := 0.0; for I := Lb to Ub do begin T := (X^[I] - M) / Sigma; S := S + Sqr(Sqr(T)); end; Kurtosis := S / (Ub - Lb + 1) - 3.0; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uregtest.pas������������������������������������������������0000755�0001750�0001750�00000012421�11326425446�020040� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Test of regression ****************************************************************** } unit uregtest; interface uses utypes, umeansd; procedure RegTest(Y, Ycalc : PVector; LbY, UbY : Integer; V : PMatrix; LbV, UbV : Integer; var Test : TRegTest); { ------------------------------------------------------------------ Test of unweighted regression ------------------------------------------------------------------ Input parameters: Y, Ycalc = observed and calculated Y values LbY, UbY = bounds of Y and Ycalc V = inverse matrix LbV, UbV = bounds of V Output parameters: V = variance-covariance matrix Test = test results ------------------------------------------------------------------ } procedure WRegTest(Y, Ycalc, S : PVector; LbY, UbY : Integer; V : PMatrix; LbV, UbV : Integer; var Test : TRegTest); { ------------------------------------------------------------------ Test of weighted regression ------------------------------------------------------------------ Additional input parameter: S = standard deviations of observations ------------------------------------------------------------------ } implementation procedure RegTest(Y, Ycalc : PVector; LbY, UbY : Integer; V : PMatrix; LbV, UbV : Integer; var Test : TRegTest); var Ybar : Float; { Average Y value } D : Float; { Difference } SSt : Float; { Total sum of squares } SSe : Float; { Explained sum of squares } SSr : Float; { Residual sum of squares } Nobs : Integer; { Number of observations } Npar : Integer; { Number of fitted parameters } I, J, K : Integer; { Loop variables } begin Nobs := UbY - LbY + 1; Npar := UbV - LbV + 1; if Nobs <= Npar then begin SetErrCode(MatSing); Exit; end; SetErrCode(MatOk); Ybar := Mean(Y, LbY, UbY); SSt := 0.0; SSe := 0.0; SSr := 0.0; for K := LbY to UbY do begin D := Y^[K] - Ybar; SSt := SSt + Sqr(D); D := Ycalc^[K] - Ybar; SSe := SSe + Sqr(D); D := Y^[K] - Ycalc^[K]; SSr := SSr + Sqr(D); end; with Test do begin Nu1 := Npar - 1; Nu2 := Nobs - Npar; R2 := SSe / SSt; R2a := 1.0 - (1.0 - R2) * (Nobs - 1) / Nu2; Vr := SSr / Nu2; if Vr = 0.0 then F := MaxNum else F := (SSe / Nu1) / Vr; end; { Compute variance-covariance matrix } for I := LbV to UbV do for J := I to UbV do V^[I]^[J] := V^[I]^[J] * Test.Vr; for I := Succ(LbV) to UbV do for J := LbV to Pred(I) do V^[I]^[J] := V^[J]^[I]; end; procedure WRegTest(Y, Ycalc, S : PVector; LbY, UbY : Integer; V : PMatrix; LbV, UbV : Integer; var Test : TRegTest); var Ybar : Float; { Average Y value } D : Float; { Difference } SW, SWY : Float; { Statistical sums } SSt : Float; { Total sum of squares } SSe : Float; { Explained sum of squares } SSr : Float; { Residual sum of squares } Nobs : Integer; { Number of observations } Npar : Integer; { Number of fitted parameters } I, J, K : Integer; { Loop variables } W : PVector; { Weights } begin Nobs := UbY - LbY + 1; Npar := UbV - LbV + 1; if Nobs <= Npar then begin SetErrCode(MatSing); Exit; end; DimVector(W, UbY); SW := 0.0; SWY := 0.0; for K := LbY to UbY do begin if S^[K] <= 0.0 then begin SetErrCode(MatSing); DelVector(W, UbY); Exit; end; W^[K] := 1.0 / Sqr(S^[K]); SW := SW + W^[K]; SWY := SWY + W^[K] * Y^[K]; end; Ybar := SWY / SW; SetErrCode(MatOk); SSt := 0.0; SSe := 0.0; SSr := 0.0; for K := LbY to UbY do begin D := Y^[K] - Ybar; SSt := SSt + W^[K] * Sqr(D); D := Ycalc^[K] - Ybar; SSe := SSe + W^[K] * Sqr(D); D := Y^[K] - Ycalc^[K]; SSr := SSr + W^[K] * Sqr(D); end; with Test do begin Nu1 := Npar - 1; Nu2 := Nobs - Npar; R2 := SSe / SSt; R2a := 1.0 - (1.0 - R2) * (Nobs - 1) / Nu2; Vr := SSr / Nu2; if Vr = 0.0 then F := MaxNum else F := (SSe / Nu1) / Vr; end; { Compute variance-covariance matrix } for I := LbV to UbV do for J := I to UbV do V^[I]^[J] := V^[I]^[J] * Test.Vr; for I := Succ(LbV) to UbV do for J := LbV to Pred(I) do V^[I]^[J] := V^[J]^[I]; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/usvdfit.pas�������������������������������������������������0000755�0001750�0001750�00000014731�11326425446�017670� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Multiple linear regression (Singular Value Decomposition) ****************************************************************** } unit usvdfit; interface uses utypes, usvd; procedure SVDFit(X : PMatrix; Y : PVector; Lb, Ub, Nvar : Integer; ConsTerm : Boolean; SVDTol : Float; B : PVector; V : PMatrix); { ------------------------------------------------------------------ Multiple linear regression: Y = B(0) + B(1) * X + B(2) * X2 + ... ------------------------------------------------------------------ Input parameters: X = matrix of independent variables Y = vector of dependent variable Lb, Ub = array bounds Nvar = number of independent variables ConsTerm = presence of constant term B(0) Output parameters: B = regression parameters V = inverse matrix ------------------------------------------------------------------ } procedure WSVDFit(X : PMatrix; Y, S : PVector; Lb, Ub, Nvar : Integer; ConsTerm : Boolean; SVDTol : Float; B : PVector; V : PMatrix); { ---------------------------------------------------------------------- Weighted multiple linear regression ---------------------------------------------------------------------- S = standard deviations of observations Other parameters as in SVDFit ---------------------------------------------------------------------- } implementation type TRegMode = (UNWEIGHTED, WEIGHTED); procedure GenSVDFit(Mode : TRegMode; X : PMatrix; Y, S : PVector; Lb, Ub, Nvar : Integer; ConsTerm : Boolean; SVDTol : Float; B : PVector; V : PMatrix); { ---------------------------------------------------------------------- General multiple linear regression routine (SVD algorithm) ---------------------------------------------------------------------- } var U : PMatrix; { Matrix of independent variables for SVD } Z : PVector; { Vector of dependent variables for SVD } S1 : PVector; { Singular values } S2inv : PVector; { Inverses of squared singular values } V1 : PMatrix; { Orthogonal matrix from SVD } LbU : Integer; { Lower bound of U matrix in both dim. } UbU : Integer; { Upper bound of U matrix in 1st dim. } I, J, K : Integer; { Loop variables } Sigma : Float; { Square root of weight } Sum : Float; { Element of variance-covariance matrix } begin if Ub - Lb < Nvar then begin SetErrCode(MatErrDim); Exit; end; if Mode = WEIGHTED then for K := Lb to Ub do if S^[K] <= 0.0 then begin SetErrCode(MatSing); Exit; end; { ---------------------------------------------------------- Prepare arrays for SVD : If constant term, use U[0..(N - Lb), 0..Nvar] and Z[0..(N - Lb)] else use U[1..(N - Lb + 1), 1..Nvar] and Z[1..(N - Lb + 1)] since the lower bounds of U for the SVD routine must be the same in both dimensions ---------------------------------------------------------- } if ConsTerm then begin LbU := 0; UbU := Ub - Lb; end else begin LbU := 1; UbU := Ub - Lb + 1; end; { Dimension arrays } DimMatrix(U, UbU, Nvar); DimVector(Z, UbU); DimVector(S1, Nvar); DimVector(S2inv, Nvar); DimMatrix(V1, Nvar, Nvar); if Mode = UNWEIGHTED then for I := LbU to UbU do begin K := I - LbU + Lb; Z^[I] := Y^[K]; if ConsTerm then U^[I]^[0] := 1.0; for J := 1 to Nvar do U^[I]^[J] := X^[K]^[J]; end else for I := LbU to UbU do begin K := I - LbU + Lb; Sigma := 1.0 / S^[K]; Z^[I] := Y^[K] * Sigma; if ConsTerm then U^[I]^[0] := Sigma; for J := 1 to Nvar do U^[I]^[J] := X^[K]^[J] * Sigma; end; { Perform singular value decomposition } SV_Decomp(U, LbU, UbU, Nvar, S1, V1); if MathErr = MatOk then begin { Set the lowest singular values to zero } SV_SetZero(S1, LbU, Nvar, SVDTol); { Solve the system } SV_Solve(U, S1, V1, Z, LbU, UbU, Nvar, B); { Compute variance-covariance matrix } for I := LbU to Nvar do if S1^[I] > 0.0 then S2inv^[I] := 1.0 / Sqr(S1^[I]) else S2inv^[I] := 0.0; for I := LbU to Nvar do for J := LbU to I do begin Sum := 0.0; for K := LbU to Nvar do Sum := Sum + V1^[I]^[K] * V1^[J]^[K] * S2inv^[K]; V^[I]^[J] := Sum; V^[J]^[I] := Sum; end; end; DelMatrix(U, UbU, Nvar); DelVector(Z, UbU); DelVector(S1, Nvar); DelVector(S2inv, Nvar); DelMatrix(V1, Nvar, Nvar); end; procedure SVDFit(X : PMatrix; Y : PVector; Lb, Ub, Nvar : Integer; ConsTerm : Boolean; SVDTol : Float; B : PVector; V : PMatrix); var S : PVector; begin S := nil; GenSVDFit(UNWEIGHTED, X, Y, S, Lb, Ub, Nvar, ConsTerm, SVDTol, B, V); end; procedure WSVDFit(X : PMatrix; Y, S : PVector; Lb, Ub, Nvar : Integer; ConsTerm : Boolean; SVDTol : Float; B : PVector; V : PMatrix); begin GenSVDFit(WEIGHTED, X, Y, S, Lb, Ub, Nvar, ConsTerm, SVDTol, B, V); end; end.���������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/usimann.pas�������������������������������������������������0000755�0001750�0001750�00000023267�11326425446�017662� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Optimization by Simulated Annealing ****************************************************************** Adapted from Fortran program SIMANN by Bill Goffe: http://www.netlib.org/opt/simann.f ****************************************************************** } unit usimann; interface uses utypes, urandom, umedian; procedure InitSAParams(NT, NS, NCycles : Integer; RT : Float); { ------------------------------------------------------------------ Initialize simulated annealing parameters ------------------------------------------------------------------ NT : Number of loops at constant temperature NS : Number of loops before step adjustment NCycles : Number of cycles RT : Temperature reduction factor ------------------------------------------------------------------ } procedure SA_CreateLogFile(FileName : String); { ------------------------------------------------------------------ Initialize log file ------------------------------------------------------------------ } procedure SimAnn(Func : TFuncNVar; X, Xmin, Xmax : PVector; Lb, Ub : Integer; var F_min : Float); { ------------------------------------------------------------------ Minimization of a function of several var. by simulated annealing ------------------------------------------------------------------ Input parameters : Func = objective function to be minimized X = initial minimum coordinates Xmin = minimum value of X Xmax = maximum value of X Lb, Ub = indices of first and last variables ------------------------------------------------------------------ Output parameter : X = refined minimum coordinates F_min = function value at minimum ------------------------------------------------------------------ } implementation { Log file headers } const Hdr1 = 'Simulated annealing: Cycle '; Hdr2 = 'Iter T F Inc Acc'; const SA_NT : Integer = 5; { Number of loops at constant temperature } SA_NS : Integer = 15; { Number of loops before step adjustment } SA_RT : Float = 0.9; { Temperature reduction factor } SA_NCycles : Integer = 1; { Number of cycles } WriteLogFile : Boolean = False; var LogFile : Text; procedure InitSAParams(NT, NS, NCycles : Integer; RT : Float); begin if NT > 0 then SA_NT := NT; if NS > 0 then SA_NS := NS; if NCycles > 1 then SA_NCycles := NCycles; if (RT > 0.0) and (RT < 1.0) then SA_RT := RT; end; procedure SA_CreateLogFile(FileName : String); begin Assign(LogFile, FileName); Rewrite(LogFile); WriteLogFile := True; end; function InitTemp(Func : TFuncNVar; X, Xmin, Range : PVector; Lb, Ub : Integer) : Float; { ------------------------------------------------------------------ Computes the initial temperature so that the probability of accepting an increase of the function is about 0.5 ------------------------------------------------------------------ } const N_EVAL = 50; { Number of function evaluations } var F, F1 : Float; { Function values } DeltaF : PVector; { Function increases } N_inc : Integer; { Number of function increases } I : Integer; { Index of function evaluation } K : Integer; { Index of parameter } begin DimVector(DeltaF, N_EVAL); N_inc := 0; F := Func(X); { Compute N_EVAL function values, changing each parameter in turn } K := Lb; for I := 1 to N_EVAL do begin X^[K] := Xmin^[K] + RanGen3 * Range^[K]; F1 := Func(X); if F1 > F then begin Inc(N_inc); DeltaF^[N_inc] := F1 - F; end; F := F1; Inc(K); if K > Ub then K := Lb; end; { The median M of these N_inc increases has a probability of 1/2. From Boltzmann's formula: Exp(-M/T) = 1/2 ==> T = M / Ln(2) } if N_inc > 0 then InitTemp := Median(DeltaF, 1, N_inc, False) * InvLn2 else InitTemp := 1.0; DelVector(DeltaF, N_EVAL); end; function Accept(DeltaF, T : Float; var N_inc, N_acc : Integer) : Boolean; { ---------------------------------------------------------------------- Checks if a variation DeltaF of the function at temperature T is acceptable. Updates the counters N_inc (number of increases of the function) and N_acc (number of accepted increases). ---------------------------------------------------------------------- } var X : Float; begin if DeltaF < 0.0 then begin Accept := True; Exit; end; Inc(N_inc); X := DeltaF / T; if X > MaxLog then { Exp(- X) ~ 0 } begin Accept := False; Exit; end; if Exp(- X) > RanGen3 then begin Accept := True; Inc(N_acc); end else Accept := False; end; procedure SimAnnCycle(Func : TFuncNVar; X, Xmin, Xmax : PVector; Lb, Ub : Integer; var F_min : Float); { ------------------------------------------------------------------ Performs one cycle of simulated annealing ------------------------------------------------------------------ } const SFact = 2.0; { Factor for step reduction } MinTemp = 1.0E-30; { Min. temperature } MinFunc = 1.0E-30; { Min. function value } var I, Iter, J, K, N_inc, N_acc : Integer; F, F1, DeltaF, Ratio, T, OldX : Float; Range, DeltaX, Xopt : PVector; Nacc : PIntVector; begin DimVector(Range, Ub); DimVector(DeltaX, Ub); DimVector(Xopt, Ub); DimIntVector(Nacc, Ub); { Determine parameter range, step and optimum } for K := Lb to Ub do begin Range^[K] := Xmax^[K] - Xmin^[K]; DeltaX^[K] := 0.5 * Range^[K]; Xopt^[K] := X^[K]; end; { Initialize function values } F := Func(X); F_min := F; { Initialize temperature and iteration count } T := InitTemp(Func, X, Xmin, Range, Lb, Ub); Iter := 0; repeat N_inc := 0; N_acc := 0; { Perform SA_NT evaluations at constant temperature } for I := 1 to SA_NT do begin for J := 1 to SA_NS do for K := Lb to Ub do begin { Save current parameter value } OldX := X^[K]; { Pick new value, keeping it within Range } X^[K] := X^[K] + (2.0 * RanGen3 - 1.0) * DeltaX^[K]; if (X^[K] < Xmin^[K]) or (X^[K] > Xmax^[K]) then X^[K] := Xmin^[K] + RanGen3 * Range^[K]; { Compute new function value } F1 := Func(X); DeltaF := F1 - F; { Check for acceptance } if Accept(DeltaF, T, N_inc, N_acc) then begin Inc(Nacc^[K]); F := F1; end else { Restore parameter value } X^[K] := OldX; { Update minimum if necessary } if F < F_min then begin Xopt^[K] := X^[K]; F_min := F; end; end; { Ajust step length to maintain an acceptance ratio of about 50% for each parameter } for K := Lb to Ub do begin Ratio := Nacc^[K] / SA_NS; if Ratio > 0.6 then begin { Increase step length, keeping it within Range } DeltaX^[K] := DeltaX^[K] * (1.0 + ((Ratio - 0.6) / 0.4) * SFact); if DeltaX^[K] > Range^[K] then DeltaX^[K] := Range^[K]; end else if Ratio < 0.4 then { Reduce step length } DeltaX^[K] := DeltaX^[K] / (1.0 + ((0.4 - Ratio) / 0.4) * SFact); { Restore counter } Nacc^[K] := 0; end; end; if WriteLogFile then WriteLn(LogFile, Iter:4, ' ', T:12, ' ', F:12, N_inc:6, N_acc:6); { Update temperature and iteration count } T := T * SA_RT; Inc(Iter); until (N_acc = 0) or (T < MinTemp) or (Abs(F_min) < MinFunc); for K := Lb to Ub do X^[K] := Xopt^[K]; DelVector(Range, Ub); DelVector(DeltaX, Ub); DelVector(Xopt, Ub); DelIntVector(Nacc, Ub); end; procedure SimAnn(Func : TFuncNVar; X, Xmin, Xmax : PVector; Lb, Ub : Integer; var F_min : Float); var Cycle : Integer; begin SetErrCode(OptOk); { Initialize the random number generator using the standard Pascal generator } Randomize; InitGen(Trunc(Random * 1.0E+8)); for Cycle := 1 to SA_NCycles do begin if WriteLogFile then begin WriteLn(LogFile, Hdr1, Cycle); WriteLn(LogFile); WriteLn(LogFile, Hdr2); end; SimAnnCycle(Func, X, Xmin, Xmax, Lb, Ub, F_min); end; if WriteLogFile then begin Close(LogFile); WriteLogFile := False; end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/urangaus.pas������������������������������������������������0000755�0001750�0001750�00000002703�11326425446�020025� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Gaussian random numbers ****************************************************************** } unit urangaus; interface uses utypes, urandom; function RanGaussStd : Float; { ------------------------------------------------------------------ Computes 2 random numbers from the standard normal distribution, returns one and saves the other for the next call ------------------------------------------------------------------ } function RanGauss(Mu, Sigma : Float) : Float; { ------------------------------------------------------------------ Returns a random number from a Gaussian distribution with mean Mu and standard deviation Sigma ------------------------------------------------------------------ } implementation const GaussSave : Float = 0.0; { Saves a Gaussian number } GaussNew : Boolean = True; { Flags a new calculation } function RanGaussStd : Float; var R, Theta : Float; begin if GaussNew then begin R := Sqrt(-2.0 * Ln(RanGen3)); Theta := TwoPi * RanGen3; RanGaussStd := R * Cos(Theta); { Return 1st number } GaussSave := R * Sin(Theta); { Save 2nd number } end else RanGaussStd := GaussSave; { Return saved number } GaussNew := not GaussNew; end; function RanGauss(Mu, Sigma : Float) : Float; begin RanGauss := Mu + Sigma * RanGaussStd; end; end.�������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/umcmc.pas���������������������������������������������������0000755�0001750�0001750�00000022101�11326425444�017274� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Simulation by Markov Chain Monte Carlo (MCMC) with the Metropolis-Hastings algorithm. This algorithm simulates the probability density function (pdf) of a vector X. The pdf P(X) is written as: P(X) = C * Exp(- F(X) / T) Simulating P by the Metropolis-Hastings algorithm is equivalent to minimizing F by simulated annealing at the constant temperature T. The constant C is not used in the simulation. The series of random vectors generated during the annealing step constitutes a Markov chain which tends towards the pdf to be simulated. It is possible to run several cycles of the algorithm. The variance-covariance matrix of the simulated distribution is re-evaluated at the end of each cycle and used for the next cycle. ****************************************************************** } unit umcmc; interface uses utypes, ucholesk, urandom, uranmult; procedure InitMHParams(NCycles, MaxSim, SavedSim : Integer); { ------------------------------------------------------------------ Initializes Metropolis-Hastings parameters ------------------------------------------------------------------ } procedure GetMHParams(var NCycles, MaxSim, SavedSim : Integer); { ------------------------------------------------------------------ Returns Metropolis-Hastings parameters ------------------------------------------------------------------ } procedure Hastings(Func : TFuncNVar; T : Float; X : PVector; V : PMatrix; Lb, Ub : Integer; Xmat : PMatrix; X_min : PVector; var F_min : Float); { ------------------------------------------------------------------ Simulation of a probability density function by the Metropolis-Hastings algorithm ------------------------------------------------------------------ Input parameters : Func = Function such that the pdf is P(X) = C * Exp(- Func(X) / T) T = Temperature X = Initial mean vector V = Initial variance-covariance matrix Lb, Ub = Indices of first and last variables ------------------------------------------------------------------ Output parameters : Xmat = Matrix of simulated vectors, stored row-wise, i.e. Xmat[1..MH_SavedSim, Lb..Ub] X = Mean of distribution V = Variance-covariance matrix of distribution X_min = Coordinates of minimum of F(X) (mode of the distribution) F_min = Value of F(X) at minimum ------------------------------------------------------------------ Possible results : MatOk : No error MatNotPD : The variance-covariance matrix is not positive definite ------------------------------------------------------------------ } implementation const MH_NCycles : Integer = 10; { Number of cycles } MH_MaxSim : Integer = 1000; { Max nb of simulations at each cycle } MH_SavedSim : Integer = 1000; { Nb of simulations to be saved } procedure InitMHParams(NCycles, MaxSim, SavedSim : Integer); begin if NCycles > 0 then MH_NCycles := NCycles; if MaxSim > 0 then MH_MaxSim := MaxSim; if (SavedSim > 0) and (SavedSim <= MaxSim) then MH_SavedSim := SavedSim; end; procedure GetMHParams(var NCycles, MaxSim, SavedSim : Integer); begin NCycles := MH_NCycles; MaxSim := MH_MaxSim; SavedSim := MH_SavedSim; end; procedure CalcSD(V : PMatrix; S : PVector; Lb, Ub : Integer); { ------------------------------------------------------------------ Computes the standard deviations for independent random numbers from the variance-covariance matrix. ------------------------------------------------------------------ } var I, ErrCode : Integer; begin I := Lb; ErrCode := MatOk; repeat if V^[I]^[I] > 0.0 then S^[I] := Sqrt(V^[I]^[I]) else ErrCode := MatNotPD; Inc(I); until (ErrCode <> MatOk) or (I > Ub); SetErrCode(ErrCode); end; function Accept(DeltaF, T : Float) : Boolean; { ------------------------------------------------------------------ Checks if a variation DeltaF of the function at temperature T is acceptable. ------------------------------------------------------------------ } var X : Float; begin if DeltaF < 0.0 then begin Accept := True; Exit; end; X := DeltaF / T; if X >= MaxLog then { Exp(- X) ~ 0 } Accept := False else Accept := (Exp(- X) > RanGen3); end; procedure HastingsCycle(Func : TFuncNVar; T : Float; X : PVector; V : PMatrix; Lb, Ub : Integer; Indep : Boolean; Xmat : PMatrix; X_min : PVector; var F_min : Float); { ------------------------------------------------------------------ Performs one cycle of the Metropolis-Hastings algorithm ------------------------------------------------------------------ } var F, F1 : Float; { Function values } DeltaF : Float; { Variation of function } Sum : Float; { Statistical sum } X1 : PVector; { New coordinates } L : PMatrix; { Standard dev. or Cholesky factor } S : PVector; { Standard deviations } I, J, K : Integer; { Loop variables } Iter : Integer; { Iteration count } FirstSavedSim : Integer; { Index of first simulation to be saved } begin { Dimension arrays } DimVector(S, Ub); DimVector(X1, Ub); DimMatrix(L, Ub, Ub); { Compute SD's or Cholesky factor } if Indep then CalcSD(V, S, Lb, Ub) else Cholesky(V, L, Lb, Ub); if MathErr = MatNotPD then Exit; { Compute initial function value } F := Func(X); { Perform MH_MaxSim simulations at constant temperature } FirstSavedSim := MH_MaxSim - MH_SavedSim + 1; Iter := 1; K := 1; repeat { Generate new vector } if Indep then RanMultIndep(X, S, Lb, Ub, X1) else RanMult(X, L, Lb, Ub, X1); { Compute new function value } F1 := Func(X1); DeltaF := F1 - F; { Check for acceptance } if Accept(DeltaF, T) then begin Write('.'); { Only for command-line programs } for I := Lb to Ub do X^[I] := X1^[I]; if Iter >= FirstSavedSim then begin { Save simulated vector into line K of matrix Xmat } for I := Lb to Ub do Xmat^[K]^[I] := X1^[I]; Inc(K); end; if F1 < F_min then begin { Update minimum } for I := Lb to Ub do X_min^[I] := X1^[I]; F_min := F1; end; F := F1; Inc(Iter); end; until Iter > MH_MaxSim; { Update mean vector } for I := Lb to Ub do begin Sum := 0.0; for K := 1 to MH_SavedSim do Sum := Sum + Xmat^[K]^[I]; X^[I] := Sum / MH_SavedSim; end; { Update variance-covariance matrix } for I := Lb to Ub do for J := I to Ub do begin Sum := 0.0; for K := 1 to MH_SavedSim do Sum := Sum + (Xmat^[K]^[I] - X^[I]) * (Xmat^[K]^[J] - X^[J]); V^[I]^[J] := Sum / MH_SavedSim; end; for I := Succ(Lb) to Ub do for J := Lb to Pred(I) do V^[I]^[J] := V^[J]^[I]; DelVector(S, Ub); DelVector(X1, Ub); DelMatrix(L, Ub, Ub); end; procedure Hastings(Func : TFuncNVar; T : Float; X : PVector; V : PMatrix; Lb, Ub : Integer; Xmat : PMatrix; X_min : PVector; var F_min : Float); var K : Integer; Indep : Boolean; begin { Initialize the Marsaglia random number generator using the standard Pascal generator } Randomize; InitGen(Trunc(Random * 1.0E+8)); K := 1; Indep := True; F_min := MaxNum; repeat HastingsCycle(Func, T, X, V, Lb, Ub, Indep, Xmat, X_min, F_min); Indep := False; Inc(K); until (MathErr <> MatOk) or (K > MH_NCycles); end; end.���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uqr.pas�����������������������������������������������������0000755�0001750�0001750�00000010773�11326425446�017015� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** QR decomposition Ref.: 'Matrix Computations' by Golub & Van Loan Pascal implementation contributed by Mark Vaughan ****************************************************************** } unit uqr; interface uses utypes; procedure QR_Decomp(A : PMatrix; Lb, Ub1, Ub2 : Integer; R : PMatrix); { ------------------------------------------------------------------ QR decomposition. Factors the matrix A (n x m, with n >= m) as a product Q * R where Q is a (n x m) column-orthogonal matrix, and R a (m x m) upper triangular matrix. This routine is used in conjunction with QR_Solve to solve a system of equations. ------------------------------------------------------------------ Input parameters : A = matrix Lb = index of first matrix element Ub1 = index of last matrix element in 1st dim. Ub2 = index of last matrix element in 2nd dim. ------------------------------------------------------------------ Output parameter : A = contains the elements of Q R = upper triangular matrix ------------------------------------------------------------------ Possible results : MatOk MatErrDim MatSing ------------------------------------------------------------------ NB : This procedure destroys the original matrix A ------------------------------------------------------------------ } procedure QR_Solve(Q, R : PMatrix; B : PVector; Lb, Ub1, Ub2 : Integer; X : PVector); { ------------------------------------------------------------------ Solves a system of equations by the QR decomposition, after the matrix has been transformed by QR_Decomp. ------------------------------------------------------------------ Input parameters : Q, R = matrices from QR_Decomp B = constant vector Lb, Ub1, Ub2 = as in QR_Decomp ------------------------------------------------------------------ Output parameter : X = solution vector ------------------------------------------------------------------ } implementation procedure QR_Decomp(A : PMatrix; Lb, Ub1, Ub2 : Integer; R : PMatrix); var I, J, K : Integer; Sum : Float; begin if Ub2 > Ub1 then begin SetErrCode(MatErrDim); Exit end; for K := Lb to Ub2 do begin { Compute the "k"th diagonal entry in R } Sum := 0.0; for I := Lb to Ub1 do Sum := Sum + Sqr(A^[I]^[K]); if Sum = 0.0 then begin SetErrCode(MatSing); Exit; end; R^[K]^[K] := Sqrt(Sum); { Divide the entries in the "k"th column of A by the computed "k"th } { diagonal element of R. this begins the process of overwriting A } { with Q . . . } for I := Lb to Ub1 do A^[I]^[K] := A^[I]^[K] / R^[K]^[K]; for J := (K + 1) to Ub2 do begin { Complete the remainder of the row entries in R } Sum := 0.0; for I := Lb to Ub1 do Sum := Sum + A^[I]^[K] * A^[I]^[J]; R^[K]^[J] := Sum; { Update the column entries of the Q/A matrix } for I := Lb to Ub1 do A^[I]^[J] := A^[I]^[J] - A^[I]^[K] * R^[K]^[J]; end; end; SetErrCode(MatOk); end; procedure QR_Solve(Q, R : PMatrix; B : PVector; Lb, Ub1, Ub2 : Integer; X : PVector); var I, J : Integer; Sum : Float; begin { Form Q'B and store the result in X } for J := Lb to Ub2 do begin X^[J] := 0.0; for I := Lb to Ub1 do X^[J] := X^[J] + Q^[I]^[J] * B^[I]; end; { Update X with the solution vector } X^[Ub2] := X^[Ub2] / R^[Ub2]^[Ub2]; for I := (Ub2 - 1) downto Lb do begin Sum := 0.0; for J := (I + 1) to Ub2 do Sum := Sum + R^[I]^[J] * X^[J]; X^[I] := (X^[I] - Sum) / R^[I]^[I]; end; end; end.�����mricron-0.20140804.1~dfsg.1.orig/fpmath/ubartlet.pas������������������������������������������������0000755�0001750�0001750�00000003447�11326425444�020026� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Bartlett's test (comparison of several variances) ****************************************************************** } unit ubartlet; interface uses utypes; procedure Bartlett(Ns : Integer; N : PIntVector; S : PVector; var Khi2 : Float; var DoF : Integer); { ------------------------------------------------------------------ Input parameters : Ns = number of samples N = samples sizes S = samples SD's (computed with StDev) Output parameters: Khi2 = Bartlett's khi-2 DoF = degrees of freedom ------------------------------------------------------------------ } implementation procedure Bartlett(Ns : Integer; N : PIntVector; S : PVector; var Khi2 : Float; var DoF : Integer); var I, Nt, N1, DoF_r : Integer; SSr, Vr, Vi, SumLog, SumInv : Float; begin if Ns < 2 then begin SetErrCode(MatErrDim); Exit end; Nt := 0; for I := 1 to Ns do Nt := Nt + N^[I]; if Nt <= Ns then begin SetErrCode(MatErrDim); Exit; end; SetErrCode(MatOk); SSr := 0.0; SumLog := 0.0; SumInv := 0.0; for I := 1 to Ns do begin N1 := N^[I] - 1; Vi := Sqr(S^[I]); SSr := SSr + N1 * Vi; SumLog := SumLog + N1 * Ln(Vi); SumInv := SumInv + 1 / N1; end; DoF := Ns - 1; DoF_r := Nt - Ns; Vr := SSr / DoF_r; Khi2 := (DoF_r * Ln(Vr) - SumLog) / (1.0 + (SumInv - 1.0 / DoF_r) / (3.0 * DoF)); end; end.�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/unormal.pas�������������������������������������������������0000755�0001750�0001750�00000001114�11326425446�017650� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Density of standard normal distribution ****************************************************************** } unit unormal; interface uses utypes; function DNorm(X : Float) : Float; { Density of standard normal distribution } implementation function DNorm(X : Float) : Float; var Y : Float; begin Y := - 0.5 * X * X; if Y < MinLog then DNorm := DefaultVal(FUnderflow, 0.0) else begin SetErrCode(FOk); DNorm := InvSqrt2Pi * Exp(Y); end; end; end.����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/unewton.pas�������������������������������������������������0000755�0001750�0001750�00000011452�11326425446�017700� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Minimization of a function of several variables by the Newton-Raphson method ****************************************************************** } unit unewton; interface uses utypes, ulineq, ulinmin, ucompvec; procedure SaveNewton(FileName : string); { ------------------------------------------------------------------ Save Newton-Raphson iterations in a file ------------------------------------------------------------------ } procedure Newton(Func : TFuncNVar; HessGrad : THessGrad; X : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; G : PVector; H_inv : PMatrix; var Det : Float); { ------------------------------------------------------------------ Minimization of a function of several variables by the Newton-Raphson method ------------------------------------------------------------------ Input parameters : Func = objective function Gradient = procedure to compute gradient X = initial minimum coordinates Lb, Ub = indices of first and last variables MaxIter = maximum number of iterations Tol = required precision ------------------------------------------------------------------ Output parameters : X = refined minimum coordinates F_min = function value at minimum G = gradient vector H_inv = inverse hessian matrix Det = determinant of hessian ------------------------------------------------------------------ Possible results : OptOk = no error OptNonConv = non-convergence OptSing = singular hessian matrix ---------------------------------------------------------------------- } implementation const WriteLogFile : Boolean = False; var LogFile : Text; procedure SaveNewton(FileName : string); begin Assign(LogFile, FileName); Rewrite(LogFile); WriteLogFile := True; end; procedure Newton(Func : TFuncNVar; HessGrad : THessGrad; X : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; G : PVector; H_inv : PMatrix; var Det : Float); var I, Iter : Integer; R : Float; OldX, DeltaX : PVector; procedure Init; { Initializes variables } var I : Integer; begin { Initialize function } F_min := Func(X); { Initialize gradient and hessian (stored in H_inv) } HessGrad(X, G, H_inv); { Initialize search direction } for I := Lb to Ub do DeltaX^[I] := - G^[I]; { Solve system } LinEq(H_inv, DeltaX, Lb, Ub, Det); end; procedure Terminate(ErrCode : Integer); { Set error code and deallocate arrays } begin DelVector(OldX, Ub); DelVector(DeltaX, Ub); SetErrCode(ErrCode); if WriteLogFile then Close(LogFile); end; begin DimVector(OldX, Ub); DimVector(DeltaX, Ub); Init; if MathErr <> MatOk then begin Terminate(OptSing); Exit; end; if MaxIter < 1 then begin Terminate(OptOk); Exit; end; if WriteLogFile then begin WriteLn(LogFile, 'Newton-Raphson'); WriteLn(LogFile, 'Iter F'); end; Iter := 0; repeat { Prepare next iteration } if WriteLogFile then WriteLn(LogFile, Iter:4, ' ', F_min:12); Iter := Iter + 1; if Iter > MaxIter then begin Terminate(OptNonConv); Exit; end; { Save old parameters } for I := Lb to Ub do OldX^[I] := X^[I]; { Minimize along the direction specified by DeltaX } R := 0.1; LinMin(Func, X, DeltaX, Lb, Ub, R, 10, 0.01, F_min); { Compute new gradient and hessian } HessGrad(X, G, H_inv); { Initialize search direction } for I := Lb to Ub do DeltaX^[I] := - G^[I]; { Solve system } LinEq(H_inv, DeltaX, Lb, Ub, Det); if MathErr <> MatOk then begin Terminate(OptSing); Exit; end; until CompVec(X, OldX, Lb, Ub, Tol); Terminate(OptOk); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ucorrel.pas�������������������������������������������������0000755�0001750�0001750�00000001757�11326425444�017661� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Correlation coefficient ****************************************************************** } unit ucorrel; interface uses utypes; function Correl(X, Y : PVector; Lb, Ub : Integer) : Float; { Correlation coefficient between samples X and Y } implementation function Correl(X, Y : PVector; Lb, Ub : Integer) : Float; var SX, SY, Xbar, Ybar, DX, DY, SSX, SSY, SP : Float; N, I : Integer; begin N := Ub - Lb + 1; SX := 0.0; SY := 0.0; for I := Lb to Ub do begin SX := SX + X^[I]; SY := SY + Y^[I]; end; Xbar := SX / N; Ybar := SY / N; SSX := 0.0; SSY := 0.0; SP := 0.0; for I := Lb to Ub do begin DX := X^[I] - Xbar; DY := Y^[I] - Ybar; SSX := SSX + DX * DX; SSY := SSY + DY * DY; SP := SP + DX * DY; end; Correl := SP / Sqrt(SSX * SSY); end; end.�����������������mricron-0.20140804.1~dfsg.1.orig/fpmath/tpmath.pdf��������������������������������������������������0000755�0001750�0001750�00001500577�10730727672�017504� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%PDF-1.2 3 0 obj << /Length 4 0 R /Filter /FlateDecode >> stream xM1o Fk;`Nt[ՁqIISq] C~Lk ,qb^8<0M,ⵣ&5}xhBz4:Y=Z\%ϾneN>Ӳ.r fjAh{1jIYivr+f_yE &pyΫЎGd`%#f |Eendstream endobj 4 0 obj 209 endobj 2 0 obj << /Type /Page /Contents 3 0 R /Resources 1 0 R /MediaBox [0 0 595.273 841.887] /Parent 8 0 R >> endobj 1 0 obj << /Font << /F17 5 0 R /F18 6 0 R /F19 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 11 0 obj << /Length 12 0 R /Filter /FlateDecode >> stream x3T0�BCcCS=CSKS=SS\..}7BHXaHJflk�f jendstream endobj 12 0 obj 62 endobj 10 0 obj << /Type /Page /Contents 11 0 R /Resources 9 0 R /MediaBox [0 0 595.273 841.887] /Parent 8 0 R >> endobj 9 0 obj << /Font << /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 15 0 obj << /Length 16 0 R /Filter /FlateDecode >> stream xݘMo@>n$lJi A&7rکS*Uvͨ;D>$$1FD2eɛs"U4jW?Щf …f39�KyD ai,Uk@f6MZiC)jo\'DJ̐ a%*D1p!v ϨBMf1hB4JfIH=U4 WKH*YYPZVo�ԂLu^jak+Z8ys@D(?�"oz{ }lzN<Y.-봄XR|:oV{dDƗy*'fqT'Ӗ-mg^9Tfp;LNAJL%is߹ߥkHU+p)2&&=�E E콀tȽ5lQKl% 50̂3`EqtFa8p 0 [v6?o\VñFD6n.xcd5Pl7*un:U\= l7>ի ezR8 zVKPחNs%Œ&/-@%DZ~\eZ/7trAk89j.q}}EPWD=Ѷx]&Ηrmޔ3RL]qg}:hrݙd1h[9jX*&>wPt+c!˶uݶVBL~yP6w)`A]>.-)fh; ON'=endstream endobj 16 0 obj 834 endobj 14 0 obj << /Type /Page /Contents 15 0 R /Resources 13 0 R /MediaBox [0 0 595.273 841.887] /Parent 8 0 R >> endobj 13 0 obj << /Font << /F23 5 0 R /F24 5 0 R /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 19 0 obj << /Length 20 0 R /Filter /FlateDecode >> stream xݚ]O8sIogRv޴3Zd*误a& j1₠ <}Xd ,�D)Ȃe(-9 �Ҝꦿu83-HeQ+mdSq<(z�/S‰}b dYDźkTT̳(o<.-:9.o*tF!2j~L0/cȢ|dwa ijnRGL؋2|TBS}QT1ѵ{,5`eyUc |[UT`je=KFA"z.e)6피޺*ď w*릲jP( lfAlǗmkp %ڶzSQ*!'@Q6)T+߃kֿ_em1Z?Cl=R-kFyuߦv @'e9J:0K'^rDPpKt4?fh�ppd.0c Vز>;Qk=m] FGtpQWom> i.7EJ+sS3<Ի^VJ,쏭2md{@e-MW W9 K*vIր.a'h�6s nzވ<Dg f۶M6jSGR-`} {+'CVnO ⱙô9`٢zõ=g[ ηhm. n|Ȼ3yk[!=w>99a;h ks54Vj->g� uO;qPUXm,dIވZ(kXjĘC·3Y2%_ cquBEF667Ν;W>GMtYwܼ{l6Wg$2Hd%_)V?r{~~XY۲wx?8yiQCQ՟ֹG[~9rn޵R؆ vVs}5endstream endobj 20 0 obj 1067 endobj 18 0 obj << /Type /Page /Contents 19 0 R /Resources 17 0 R /MediaBox [0 0 595.273 841.887] /Parent 8 0 R >> endobj 17 0 obj << /Font << /F24 5 0 R /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 23 0 obj << /Length 24 0 R /Filter /FlateDecode >> stream xYrF+Kc9NTRd.ɂHm (_)7ДsOZAVRD6\[#B(R6ͩݯGBѤs[K`ʤJL !MߤB͏ш3>T/\7Ƀ,1O`ؽ,Ul,?" &`YӶBOK bGN;WvgH{=)JWniCJ#** i+:P<[קDP%y%R@D HD M"BO]u Qw#8&ovKR$=BY4raaXD4R;F{xJ3ccfB~*RIC4 ȺLTc@~~?+�X#{4֢[WFF�x]]<>.j*]ݢS(02m\M9h&~@:k%>՟Oz`d`lodiADZR/f%3 Pę(l^'ϏGً&x!׻‡ g־_G]Jdfb.3k;!$f%sAzXE.zn4uRe40 ͝>ł{Ckl`Fmg~6S4 幩Az6hy3lϮ Spң"ECfSJSd ٫!Er1|f8H|AG!8~ rc`SIɒ8s QNӪ)k q.=+~68gྈ[~ Q֭`x{Š{JGٽ`7*kPU~=9[JHlS6IӸh%#B}Ak mÎyP} <nUfs/M@endstream endobj 24 0 obj 994 endobj 22 0 obj << /Type /Page /Contents 23 0 R /Resources 21 0 R /MediaBox [0 0 595.273 841.887] /Parent 8 0 R >> endobj 21 0 obj << /Font << /F15 7 0 R /F24 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 27 0 obj << /Length 28 0 R /Filter /FlateDecode >> stream xYK6oA ߏv-EAkQ=RZ "keEX X(7 нqa) sX77/-c|=ܚ ')BHFAQEg&I f]#E8ap+% dI "3"I!M'mbn|fZ}hx륢VRJ3*"2c$Daښ{AiA7vdKP4?a4h-t&|�w`cDW@"cL9 97Ώb).OOr< D.|PqiM¥G_iޫnF7m+MNy!6 .`&SLI#w1=Gf ƝtFnap1JP2%? LŶ >h?ll׭]Q g <z&?y^#%Xi6I*f炕GC<[k /Bn֑>+3tX<w1W]P*&Q@WF:W�q׮m E} I@=<H3{{ɌkopdVvWœ (<8SЅu߬bS%|  xބiVC\Y"pѝM�dRI)cRBz)tZ6⾰ SHGž{[&޷q+\)f)7fǾ*:]M*4MNra4^t^V֚^(YJ8K)|Ա]= P.\JQtp!|I~�H4+& S~5ANo=Eq'ֲٸmɔPNaS}_uim=fY )\ʓcӪ<Ϟ 3{4?9Xb}DV*?QG{ԼJx@($ǮVj#endstream endobj 28 0 obj 1014 endobj 26 0 obj << /Type /Page /Contents 27 0 R /Resources 25 0 R /MediaBox [0 0 595.273 841.887] /Parent 8 0 R >> endobj 25 0 obj << /Font << /F15 7 0 R /F24 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 31 0 obj << /Length 32 0 R /Filter /FlateDecode >> stream xXIsFW-Pe0w'>ċxӒT8ֿw7M#fX\I0.U 4B~[*1_`A,(\ŐU=q}5+`~Cj}<�FS֪UV$8 __^gńUHؾ!aD@$L]>ҼҠ꽘1$Y 6H"O:.ժ* ˏ嵽`+P�EP4GbB+'XbrbֲRT;#xoO\Zy ,7`wrsXqNO)FE!,~s"*rpЀ4K?!~A"sQ{uolq�$IC":0y>bk`vL#LJ$ewNg2#|F%]i>Ax\ph }YD}V3Oɲ+cfޥE]ުw.\F% {]<+x9&SP gpKn=.C5WurHN 8X H1?iuՑqhȸltZ9jRa>i\\URmD{SRNNzLsP ޵l@Jٓ/<e۶tyc*-/;}󸥘`&#Q֋''{mG9{85X(m2[Lob(a(A)}0y4LA=.gH<{<N@㢅Snu01G&b`{ ڀe$F˪j0;�[V[wej[[DuInms;8!hofealہPj{- T؏ty^U~/>wK]B/V[;M҇/GKɸ[Uܘs"7ÖNn,k_L$7LnĞu3͏4W:0D,w4g3͘g~kriɺlQ;̄1yJ|ܢ,4J$x3h8�LcN9 Fg_˒4endstream endobj 32 0 obj 1055 endobj 30 0 obj << /Type /Page /Contents 31 0 R /Resources 29 0 R /MediaBox [0 0 595.273 841.887] /Parent 33 0 R >> endobj 29 0 obj << /Font << /F24 5 0 R /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 36 0 obj << /Length 37 0 R /Filter /FlateDecode >> stream xݙMo@�m*%ZK=T=`WŸj;cpK#lcy58_�eAD# hȜ4z?b!csl3n:ӅJ* [e6]pba?+]zd+w2_'▅*<Fݺ?ɞ6z !rb-(@BĎ<\ȳhxR(�#doڡa[̰4!ʛDFsHpP䘇Zw}nh~yUQHӈO1*f*V|{XJrUύc(զ֩EЅ@Tݨ'>{;C r^Tt5O%b&-N0ц5jaNl0 7{}W'bkl ѴZޣ G;+DqSdVT^m Q#?[tCET`İc^>(smEMſ$/g3"b&}Y~) /��,'r}lîޕmw$U֚F65ɦ`5/6X2"nP-lx}Eعus͘,Ve)Ϛ}<u{rV|nLUmY$gg . Z0Gl ݱA1Vc: 6Fюt7 D el(xCȻKP V Mm |Knk]5iEڞ(R+be߉s Y'pC]u7 o7Ǩ^f52KdYL#F$IEtKMT7<VhmvߡS\#H(DRJ­6?]}]u.aendstream endobj 37 0 obj 887 endobj 35 0 obj << /Type /Page /Contents 36 0 R /Resources 34 0 R /MediaBox [0 0 595.273 841.887] /Parent 33 0 R >> endobj 34 0 obj << /Font << /F24 5 0 R /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 40 0 obj << /Length 41 0 R /Filter /FlateDecode >> stream xڍVK6GzQ5iv-`iZ 8_e{m[0yq͋bOu)Wx^V2番V]l?]'YU1I^s qpƛq f`M,_KQ I)ʃ:B`oI6Rڋ: e, k%D zR1d?xCĆh=P4rlڵӺ(X&*-q׸(]{i:3~YfDy74Z-=>6y5Mh�X*^5pSY?" )W"Rg �6 ^S2;N -8yAUzqѽ{AڴR(^Vrd9O C�"!Ln7DaRIJ*X�2Ӥ5Q`w2Uw Qw`vZ_eSVu _i޿E@Z&e&}fHg}]C JV;oM/Ī`#&O [ѺNv]Dy,HӒ@@#D>zx ]wn2y4}ȶb=:oa?b؏>}o}` &!JD6|s;;$ ΞCP@T8!LyQbGr#[O9tu,TEAabwDܑr84mV;ĢC"4]\NfazN\<V1CmDC/_ÿ8aQ3lIŏLCiF|d \%6 (sWh U攂f(_FD)\Ro S9y5BtʘhCq C!S"k'㘀Mc#|E/S\y۴8I =ZA }ihgR\Ϝ/os\8T%͜0tXñ Bz�! G22e�ԒB(cd[cuG(6xмk0kɆ]#tum#R9Di-<&'I=�B:B++#xq"ȘX,%iCg<-wF| 5E$!wl%iykm|9@gBH4k%W(x̅Lq uas endstream endobj 41 0 obj 1236 endobj 39 0 obj << /Type /Page /Contents 40 0 R /Resources 38 0 R /MediaBox [0 0 595.273 841.887] /Parent 33 0 R >> endobj 38 0 obj << /Font << /F23 5 0 R /F34 5 0 R /F15 7 0 R /F30 42 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 46 0 obj << /Length 47 0 R /Filter /FlateDecode >> stream xWKo6ҿ Č&6Xtr֖= IٖM.z+| y|͈R381,}{xbF5aTΖk'\P JH]Snk ժhq(jU9KOOp pׂXbR$+w6L';_ Ye7ʝ2\nʏkeE B(K*C|!dg_z8ɪh_j8PlMu=}|$a>\/fh{sxy2ƲzmpG/TV!.Z<ZQZn#epH7:We[}ޅ[ӳ I .H*;]yJ ׬()z]/Ѹr%ToR`|YM4@]di9_=�YӴuӖYX!en(/1ZU@A1)Mbl, o  n ZpS]aߗ[~a0�"衷׏\?D􈻌" 0\n8 Rڬq+1 $ܪp9$E&�*/èPg]gyX:'Q,@@ Ҩ|n#S>#)I(3ךfXJSbb)h�R_Kv@ȵ[.7]<DnBwh}F~:"ƜÈx1)<M(&zL�r": FՉʱJa6) ɹɴ!Z�y\`ӡ]H# ) ބ j<Ԟ}ǒ^ɻ\d)N`Y&R C @(tp=$#_qS~)�k3'J~S茍-5HuO M_h�g 4�Q"oA+HP6V]c SvYM%8QG@ec ^|#9 w"S�; uB*ZC'nt\;gHThqg,8GccjNF !R TGZ;1OA]?4HmC\Sm(H98S=R},;iR ~̰t}R_9ZO ?%_XGbmD*Jdaq(T&,Fc,}#6 J\ fdKhTr/83HwRFqs1Tێ hk;`X7ʵ?7=ot1Ⱦb꙲zI$0XUmO!Lc|Ep˻͸9endstream endobj 47 0 obj 1399 endobj 45 0 obj << /Type /Page /Contents 46 0 R /Resources 44 0 R /MediaBox [0 0 595.273 841.887] /Parent 33 0 R >> endobj 44 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F35 43 0 R /F30 42 0 R >> /ProcSet [ /PDF /Text ] >> endobj 50 0 obj << /Length 51 0 R /Filter /FlateDecode >> stream xڝVKo6WZbD;\ iSSԲ>3j�Q<<JȳHeջ{!#YUϘ3J8d|M[M߭yo-_*> v(ֿ%+r5>LPE=xr;K+m43}4Kz7lMg!wĹ;dyj'DO`حE<u!DTʑ<9߱6]t[Z0o ~3Ia!ןWk.'s5;aG^O'%MwqϷ7$xQ8PB4+_M/ř;B`${j~}IU|5 V I{?5i{,Pꠘ2m<|e|mF]hP &5҄m }!YԌ b6<^vyv־2Ȑ85geLs+^F}n6ϴ5јY{%r; 3Cy+ml*+Up/(+BXZ̬sP:Q1G2Mg�g>-ihߘ}Mf^,\Okq_骲�1"/^P%UV8:3)Թ K=*ܔ ^I.t<k}$أR/[.e56_W Hn5 T{Z='_0H$QěćɛOoOљ,�yg;d'>3ه٢Ϋ+ @%1eE <JDlaFsY㐾0R <Ǟ{xwu ’R(bˋ|q�M8 "Y"[T! Y #q("- jW7v]s7Otߦ`\"wWO򓹀KܪB` V7_z?C(( ,{ XF"?�ڗ-fo,&^@J#X&]:&ETc(QhRS($&ܜ:irtƏ1O=IR#>uq9OIYp�c︀FZLj�ҹ(􅖕阓n[2~YotBwMrEl $ x[Is;w/�VS9 @()@\|m,endstream endobj 51 0 obj 1264 endobj 49 0 obj << /Type /Page /Contents 50 0 R /Resources 48 0 R /MediaBox [0 0 595.273 841.887] /Parent 33 0 R >> endobj 48 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 54 0 obj << /Length 55 0 R /Filter /FlateDecode >> stream x3T0�BCcC#=##cKS=SS\..}7CSCC=KSS4ʐh C#/..�} endstream endobj 55 0 obj 65 endobj 53 0 obj << /Type /Page /Contents 54 0 R /Resources 52 0 R /MediaBox [0 0 595.273 841.887] /Parent 33 0 R >> endobj 52 0 obj << /Font << /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 58 0 obj << /Length 59 0 R /Filter /FlateDecode >> stream xڅVo6_GX~[8CVA,4}xm%"<M1rfEJ!f;fRC\n~Uw\E&/( _{߅52uC ;af2$`vrz8#e";"E*4i{Υ˞ZbvVLUM+g,|hGpGfZۈm�1-o GchyfqGyWz& &ŨLLs!4zπJd�eV5Y'6{vO\E((�zC:g}RtRj;7\(ztCtZq^LR]Ufiö ^W v7a@dF=ނO\]@[2LWQ^ǧ_MgFىWkjco�/8w =D@ Ga>Ec%s+T1f8Ք)۰Nt@cE6<"*y73i$H5ãX;1iޣh搭Ɣ|ۗߋO_ 2ZL=ٟ|~[aZ9G.]..nߐV(栜orY(#,g,`m̌-'C=413h}դ:4LjPtZI-SjX~-a,$K>) -d y:ՖMZynBn١7熗c :],2ɨXl'qL]f VOtP7{'\ƓWbRsCtd׬PQŻONGDuԇg\_~3 ]t~ = yh6:CbԊ |Q jZJumԦWo|d" Xf"k}='D:O::dv*e%@T-fJ5PKc#lW $Ng`Xb}-b}E+ƧŸ= | Luavm|QpEXz9v^=g k=\ul:VchPCW5:}KaW?O.%z^qAp{UFiItL- 7t8Z,]ii^"9"HhC(ܺY,o~\endstream endobj 59 0 obj 1210 endobj 57 0 obj << /Type /Page /Contents 58 0 R /Resources 56 0 R /MediaBox [0 0 595.273 841.887] /Parent 60 0 R >> endobj 56 0 obj << /Font << /F23 5 0 R /F15 7 0 R /F34 5 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 63 0 obj << /Length 64 0 R /Filter /FlateDecode >> stream xڭVn0?#XR^@ Z4=(c EC;\: \�޼!IIeE"sizr9OĔdΛ_bfP)#efQ_ 4tmog38ED8Y߬k%E 臵dR*e(o"Dt)ݦ=xۃ;﬷^딖\H #N"'- = j Q,qYVm/; !a4b<L$#s.ܾz{s\A8f ;,U]\! _ʲ ,zviuW~R&%EYdh3P퀢UvUA%ٹTTm p~j\mbmO FVfRîciW Z3A.jMP�j f6/|Ƒz8vG ѹ* /s%CL0,*DȎ ҩd8K*E8{a8Q5ZBw!f_+ymGbPaAw=1� 38Q] }ʖQv~#,EuE)~U yH?xM~jHyF0dU ET�kF$0*.Ѧ7a鐡Cؾl~^y&aTdk hQe."lˀAi`"{2%dH2Y\fi( ?QB`H-qoKxv,[3rͩbR%9$W^"h{ڄDe V f-N*g <.^Vw^wJ]{2~/% Y'.M}endstream endobj 64 0 obj 880 endobj 62 0 obj << /Type /Page /Contents 63 0 R /Resources 61 0 R /MediaBox [0 0 595.273 841.887] /Parent 60 0 R >> endobj 61 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 67 0 obj << /Length 68 0 R /Filter /FlateDecode >> stream xXMo6BGX"Ei^)Zd!@ƦmJr_!%Gv 29̼zth )' X$ςF+G <1'2΂۫ﯩ(%܊ U۩j²D4VUQ-&z*$YaYq8kL4~P9$As'uԓ(a2lW,uۙoihU,D_7nfqwKe_XĨu`c"9uj)'I D!qo/UʼD,D"yjg7WFnIuE]L.*FiZo:Jf  w@{twC?K 7.94NY¢b ٴhKm,T5bО4TtG,vc*j@²'օOtJgN&=#|"!c) t_l.O@Z�a/Xi՗Z5tY@E q#!|%$^Xp^.p}A^t;1y~CP(Ƶhl f9ai%` e._0qxB_ /hl ^CO9_\xL7vuS0>;<*u\RIV/GR AJ!M5笸 e^2!n#8eP Tj$.|#<3R^"D)t)J�CFR0=-9PzьfKJX&f1c_%k|#WBѤNTu&)و">&|RrD&`g0I(yGY'mgXR %^�jP_|t4k +4IOɍ̴w/jqI55Ɣr㞕woI%>znY b#U}KE۹uӜmY5a |NF{|d|nq >bBfN|֘*7\ݘ;qN `lJbǙǵZD]];Hn {fA(^ˑLAcn#I91Jg.g#[!= ?P9ܡ\1(x MYG GXBkkv| o]h l܅GQI@9Eh^=ye}3o@ɼ}CKtf_u߬})X3N%t)=}zs_ތs3j9_*7nEG‡1`ΜHfF3/:s[Padwo( rS` ͑418ӄd^L⯪gۿ<endstream endobj 68 0 obj 1433 endobj 66 0 obj << /Type /Page /Contents 67 0 R /Resources 65 0 R /MediaBox [0 0 595.273 841.887] /Parent 60 0 R >> endobj 65 0 obj << /Font << /F15 7 0 R /F35 43 0 R /F34 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 71 0 obj << /Length 72 0 R /Filter /FlateDecode >> stream xڍ?O0|g lQZ:ԏ%iKҦdw{SStZ:ԫ6m,)bE;Z>e兠&/(fTs\$F�@+Ȍ#fB/XEm!VϠG=;}=,?׶ü z V QEP"C&@M,kZ0f!-U%:GF4pάj2 [;1($ `i8fhV(jem{�dX$8bՌOLL=9ų}S09ؾGz}-ʵI/oS8=$erCa,}@'9<8 gEx<{endstream endobj 72 0 obj 397 endobj 70 0 obj << /Type /Page /Contents 71 0 R /Resources 69 0 R /MediaBox [0 0 595.273 841.887] /Parent 60 0 R >> endobj 69 0 obj << /Font << /F35 43 0 R /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 75 0 obj << /Length 76 0 R /Filter /FlateDecode >> stream xYK6?GrKӤhAcڵ�lwHJl"lQh8ylBFN͏oO@mdv%g?)7Ӝk__A.,1Lx7򾬧`<99~MN[&' 2(Υ `{e| :-fi(MyVY}_5/Vk 4d6*Exlmԝ y!&қ gJժrր̪l=j%a\L&]sK�'l3"{Z͹z-Ph*Bjly`"h1"^i-^(uxy3pp9Evh]k&rr$`HIxSA81T9IFm;cпp%A8#hIDȊ՗.a*Z'_cUn 1W3cj'9 Xa)-aڌ3iSA C~v��Q6G ܊ұ3 cKy\?Mt_J1]W,0J-Qw5CS #Q1(a(t,Ĕv_ >=㾧5J0D -%ƶS0C/L* `|*=9\ ga W9"#}q;pBB.ʈ0&) '&KؤXb -clx%1_ ڗ3.;b$ tjΚl= XȦ]C=P+W% W<aLqHJ5kWb=3̓\\hMr,gW%l?D=p4*G3 e XXLCSu0шoO4RSmMRǻA7�tٜDzǿ7Mυd;6 vbpf{"úUDz`s4xPx+zd gv@ƏIX@^nY"-cJAĞwmA9W.':-YiC8BJ` ('m` 1VXS.1j/N@C|r|vx!DcTʴOSߊ=W®\ }P]pPI>fX$:_:iv&V^5{VZeՔғ>@a1Їu.R^4ΟCVHcuePھvʆF>ieD*!Jqo8yzzХoEz !"{I,>1ƎdIIe/hou}Ξk&(p  1?u`p{H?WOn#S)]F}ř]`U(�}?X()ن[0'7otR .uؑXZ.& >L<x|3IJglluM1UD|ÑK&<7H> z>É.pD ۺ)}T49= Txm֛rfEV+w,:N#EuW5[5q'O88*Zkeu,M(6e׷aSΫmw<s䊔8.`zzY#¨.Ӕ\ �.?I$li,31!m:�*endstream endobj 76 0 obj 1725 endobj 74 0 obj << /Type /Page /Contents 75 0 R /Resources 73 0 R /MediaBox [0 0 595.273 841.887] /Parent 60 0 R >> endobj 73 0 obj << /Font << /F23 5 0 R /F15 7 0 R /F34 5 0 R /F35 43 0 R /F27 77 0 R /F30 42 0 R /F36 6 0 R >> /ProcSet [ /PDF /Text ] >> endobj 80 0 obj << /Length 81 0 R /Filter /FlateDecode >> stream xXnF}KA$n~Iчuj-Q6 (.iɖIIApvx?lƸ p-f󓗧BΘ!|M0I3ƸL^7ͦI3aDr˪/??<#N2nU/(v-7uxA`(QF * MY4ov[C&mL&E TdI3neFY޸ʷm1')W0˘ I~]$ͤz)nwǭN) x#`UŲۢ - J0zʫ,|>b2y]x뷐Q £܆./Da Uy]XG+V1N~aD9�RzgVjuxFHMbl_²X廪 /\Hxm۔&Ap CO>v[^TEH{SrmXʛșS$6H;(i` Wrƥ3JЂ&N\\y e8u/ ;T^'HƾbPZAIP1 x:o!5;]X;>Gr>(dZ{yƔ%H0LF v DPP+O dXX 1L 0Ă0[8@Zǽk7&#_N[xp( $rIA} fudNDCG4c=8Bڙc~o.wkB(x,Gx8qUADw'Q:WfƏ:W*147쪼)[ǔ!IY#Jp#MYU^P%�(� yQ`s dtطN7IHeqD Cf j"�õM`.3W>`EG$+3MRZ 3wk =QEԳ"'<pm* YxbQnc˭\TxpSχW?xe_i!f`^NQǮb;k`j�i:^;~ Lm@E*v—Ea"|/̼o2 2ώL; Dr|?"4Qhs>jY.`]3ޘ:Y M:߷6`L߃L쾐A5VN^ %%pUeT\Mԕ\q94W\A\qW(=mqM?NLXjAEPR|QJDR]PeeG oO^Q%e?O^LUGމjGU*' ehP"yavR?;=I # jq0F˟IMzm߃N[言!z؝}59jNPH_84 ) -mendstream endobj 81 0 obj 1511 endobj 79 0 obj << /Type /Page /Contents 80 0 R /Resources 78 0 R /MediaBox [0 0 595.273 841.887] /Parent 60 0 R >> endobj 78 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F35 43 0 R /F30 42 0 R /F27 77 0 R >> /ProcSet [ /PDF /Text ] >> endobj 84 0 obj << /Length 85 0 R /Filter /FlateDecode >> stream xڽYM۸!$w9) K|تq֮8R9*-qfX+Q}^ E)J]J$|8F,l.0r^T nzq{$o$SK΅ʾS !JR& c~0@3'Ӝv݌CQGG!{iUWI)CSﯗRGuG ;e04Ԧ$$OmG0}_ĵskJˤWKM牙aGwlBЂK!Y0y>ks1aߞl>gXc0v륰dvzf\B,d;feLiTuߥ84xl6E+ڇ2)ݔY8 ʭMڅf2ܩMaD)ήMի6ݮ)i8,k93/\1tYP}:+6e} {E-9&h`?Ce7G sAV8`P>N,ݡ^W=2K_ĪEAw!΃  {6YCL@5l<*ռwHz|wb ޑĺ\U"i)VML97io5h!Jfxhi, *r$עכݮtn+fw>Q/,  9NcidCB56_z<T"6XX3.Ȉ_$~y/}ؒ':+z$ ] ij~bqn&FYh|n*GM38F½bSu:bdOQ.BC/mYYxF-4)ulm죘NUZۨm=]^ʼ'*gOR,M}|%(o_4b+͇2<~L_FV~+ö~ԫ nOC3St~3x&($yG!/7#F5VfҨ|ZbF;,$zx0}yB dQ|*æ›j[i�qfIU qusmLNc}'lji 1GE7s%s֗$򧔺H;=B)@10zSgE[wa>Y u֡L"Ӯob(ڇWMK՜IgGQ%ucSm� 6 GV<eİZ{LYm pP wO(BJ-Qږ4ܸճi޻ȧ1=fY^WŁ 5"Kl QT|#]IE/CoPF]./`r}hLMi(B"26yqCF ]n{!HO0DNL t s2Q%)<J>l*ģaVFhyr<zqb K{7({j}<In @vw]Ϡ֠&>CAEFX="j=(;.TVfUg8 Py'Jj(i]`j>^#ٛzGQp`bt@ƙaGfx ZMgu8Kc:JFӳv[Tu|Kr/c(e6So2TEjI&?U =%rByM7erP|z1Р Wn,N4Ii9P2ˢ)wWiހ-E~Vx5X̥sy}VObH cCjYh&$q ESTh (-ϭOrb (u9WvPnՖ4c M?\O @p{)bT` بvl#RQ� �ĺttnarjkagt#[?" `8Y㠚cvN9fxȳ^ y!dQNҰp_j{w1,sQ@$8rݧYpb p)<kMwh{H)qr0!G#>_i#3<U !zSD�)V2.ǜLp"̯PA+?gJ\`r0΂$t$ͼ㭺nFPY&%/GʝFf&9>hXnϏo:9SLc%%sOÌglendstream endobj 85 0 obj 2213 endobj 83 0 obj << /Type /Page /Contents 84 0 R /Resources 82 0 R /MediaBox [0 0 595.273 841.887] /Parent 88 0 R >> endobj 82 0 obj << /Font << /F34 5 0 R /F30 42 0 R /F15 7 0 R /F35 43 0 R /F27 77 0 R /F28 86 0 R /F25 87 0 R >> /ProcSet [ /PDF /Text ] >> endobj 91 0 obj << /Length 92 0 R /Filter /FlateDecode >> stream xYIFهsngr,8FF75[4({BJlc <* 0Ɉrc \Ë^| c)?~-EnKZWz|S|o1E޴]Envx]$l?$w[(N۠BOTmTrM"$'KmJ \oJ&**\{pd%}h>^u׵]ToYߵp<FsqlO=I 3TR " ^ b%c\"_ޜQkNR }̤ WVZ^$ITTZMڧ*yQ7anPw*(ߠ}C nR!(6LEG!1dP& PAbP < !VGjT](QRR E"tu\�!ogbѯaN3:TLWM&dO'dpVZC@Ү}1Ҝ2`+`s@w_6a:lo@z'0N1&lH+u#z|و/!Ep4GDo>nj\^mKyZB)%sEݜ=KN#dp }�ڻ0J9WRA1nHtΒ`D[>76gDESΔ!l"9kl1~*UTD4I4c,Pf+nSNjY^XmbMDVbS+m,}۴;}+aV]w}Bqz="^x\3 סɕ WÚyQbC_ksՠ<ᓎCU9_Pc s�#<`b ]קm|'x /\2+w/PFPJ c~4~!M7w$zY>I&E -fR\8ixCдBWM2&Ⓢ󪍒#!a%$Ȱֹiq0+#uf8ˁiHHɴ&{Q6E8z(7~>@ߣbCv "ChgBTӰܦ<Mg]"L�Q{2Y?hXtj3q$b�U6 B:omM̳l2;7}#gyPf<K=Pm"`J˩3LOR&|P 1D`xqt+atI QX0&hhC*sQuD-VanB�[m47a0@E?i�EP7%<[+\@1_]D1/}w Dt;θX6Cf}JTf}2koܑ.e֐ga3ޣ)LgɕM1Ĕ#RL%~d L,iq; ρ:Ŋ5tҞQ`/P0r8*a=cX)TL+[ϫ#3|eOhPw|9ș,SN s-8HSk}1_H:ϐCu=YYﲻمUf13$Ă F4cq/G\op",%ʹY肇rCsDw&wrtj6?8,-N(*ι< o BD]=rEXϱ7z0f dC[s=[FŤ'zJ=1vk-1lSȐ6X>tէc?zg?grnztD&]rP2|zn+^\0m)US]ƞ껊CZ~h8l- 9pƦ[`lpj-Z~qBAwO,rQe9/Z.^\\l*@aDȠ3s9uI1i-wމ\В.9BT<W]_7iCS]ze9x| ?UX5%C!㐨XuWK8*wJ01J3*ˢ<JO.CgDCFoKfg^bO^+C,Rendstream endobj 92 0 obj 2133 endobj 90 0 obj << /Type /Page /Contents 91 0 R /Resources 89 0 R /MediaBox [0 0 595.273 841.887] /Parent 88 0 R >> endobj 89 0 obj << /Font << /F15 7 0 R /F36 6 0 R /F34 5 0 R /F30 42 0 R /F35 43 0 R /F27 77 0 R /F28 86 0 R /F25 87 0 R /F31 93 0 R /F26 94 0 R >> /ProcSet [ /PDF /Text ] >> endobj 97 0 obj << /Length 98 0 R /Filter /FlateDecode >> stream xXm+QU IA6! PzBeːK%[ + gyǟXy +W+&Zmvy|+f(+ֹRg?|=sų{SdmSotrouz` $>Lz=V"]6M>%;~]^֠6&+|n?l,VѬ+ixÙ*V/ֳBr)c6~A@gr9=>̒`URͼ} >qT0;*hCN%S`!`4xHÜC0(q C G əAgaq:Ig.7 hrϸ~$9ϔ+؅Q4+ 72r`"̄KPxh\4YhLL fƨĦJ(Hlⴌ`T䤷 %n zweƻi7S-۱BvE, sJù JyKߵÒVK3AXz%g%M%U(DBN$ù 7XyJT@&z$+kA;#\$:L;1 qa tonX6RP㙩9t8Dkpbuhc w+qN1[߈/?V2_1r p_a֐if";` 62LcANu38<|&zΥLPu94Ѣ}D:qt %įo18_;:k_O?n=3N(</Fmrٟ!Ah./(ALw ؠ/t@"`p`¸7oJ\ll?2 qYСEP_'wVIe8j;yT'W֢�@ ~ID6R{|wдs ւYg'^0]B9z3o07CW]S 0 ]Ctagw!#x}?{mU6)@vUkOz?4n}\Ƅ >Feh`& bw8+[tD/NSDJ=fxك5H86<+۸e\m?5r_Jw=>B@`ȁ+  >k_"6bpas_X KƜTf\(&+ъ•גWLv]7I1$O~ؤiNXmJdKO;H` > _vuAK=AAֶͱ킍P%R/8��Km�D!+V`"Afօ+aTn6|ad3t;Ҡ%brcڐ/_7�`gT US..N]n0^j;B̪rC#k2iYdpRtOAώ}@t:U#]|"&%&HV^g~ 0&5q̏~}|CS`DZM3؇ 61C:.tɫ I頊YSH(/)O]އcY;3u>Ð-G.pPؿ&hRx} UaJ1nz^Rd2! ib۞Ɂ\ËQ- 2w|JŧQ2�it�Qm#UeBQ J jsJ zK(gϧ9u"X_b;f u $1=&Q Q;FI6Vc~Įbž},T7r >:P|I HSEٗU 4i1є| P8C3+gA4_֍,gCc!k\& /Y6endstream endobj 98 0 obj 1919 endobj 96 0 obj << /Type /Page /Contents 97 0 R /Resources 95 0 R /MediaBox [0 0 595.273 841.887] /Parent 88 0 R >> endobj 95 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F35 43 0 R /F25 87 0 R /F27 77 0 R /F28 86 0 R /F30 42 0 R /F31 93 0 R /F37 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 101 0 obj << /Length 102 0 R /Filter /FlateDecode >> stream x3T0�BCcC#=##cKS=SS\..}7CSCC=KSS4ʐh ##/..�} endstream endobj 102 0 obj 65 endobj 100 0 obj << /Type /Page /Contents 101 0 R /Resources 99 0 R /MediaBox [0 0 595.273 841.887] /Parent 88 0 R >> endobj 99 0 obj << /Font << /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 105 0 obj << /Length 106 0 R /Filter /FlateDecode >> stream xڝWKoFNsAPsG .Z A4Ɂ(L 3KWNZ@.wv|3?>sz#fFH-o~[]\ 9Zggu\>rWݼ56 *\`jY[2d},m(}qAB+* gz?/d9 [UeW_ aIM7=/GADu_ZޖtnKr2Rޗ&4s輰ʓuHM!YUJap2 8s~$X5qY0+\htm|, |tNj6uWvQ5}BW4>M N% Dz|fe2%`6Mg!!Rt 4sTT Up yS ΅"sH E0TxrIxȅ*9t Z1YFԊ!:,%y>8~6ESݔ}}(<lC$}u+�gǘԂ:a2jĐs�!3Cè3zæEd=%~W0uFT07AIuNXGÒTƩT9}- Bʘ/3!)g329aAX x)HD|ZeBa0}5RNR>3@>q&Z7 }\ \B_n^7<_g{Y6pa!]4^y|(&\" B%)~/ooKC02�=~B?Tx�Jp#xU'|8ӔHgC _|k xIMH}Eg/C{2n0`Sz pQuLvʉ`$;. :Fci �GÌcG'v9JVJw0P=1!=r'ȅ>0j*7[Z4 &Lѝ qh�:!,t2C9j26%.<T@Oi!INoͱV!= P7JrmnBs(SalBR)tPY6肀M/a0񆻽 d/U>ud^}X'xv#'s>7{,B81 4eKfM(=U7FG#q@H98!rz}I#f>&~S5W8\7ϥ_) 8Yv~9R6 `U;;wU<OѾ>`ϱh9T@&3{YG8<Ðci51ʍ<Gg9=ZI|p)% ?ɷ�K]j%[:71/~WƏyqeGt>-.&'{(V~d ?" [ggendstream endobj 106 0 obj 1437 endobj 104 0 obj << /Type /Page /Contents 105 0 R /Resources 103 0 R /MediaBox [0 0 595.273 841.887] /Parent 88 0 R >> endobj 103 0 obj << /Font << /F23 5 0 R /F15 7 0 R /F35 43 0 R /F34 5 0 R /F27 77 0 R /F30 42 0 R /F1 107 0 R /F31 93 0 R /F25 87 0 R /F28 86 0 R >> /ProcSet [ /PDF /Text ] >> endobj 110 0 obj << /Length 111 0 R /Filter /FlateDecode >> stream xڵXM6y{wߪbߤR@6E=$mzPZ[-omy(RL7 )qď7f)&b"`ROWLZ5\rqB`1bg_/=fЇW]s/]}T:Ι害}3/V=7-Nbi`S6M=*L,Jjl[j}t]2kͫބFAsNBbF֦m^ݜKt͹1Y\jV3|ڷ)8h4y[fLcN G+l_:@ \&sKzr=/6UXGrtƦsBYxyٶ3D$ `{ @x=6˪9=V\_oUєN0-b ]Gx> q+v,$H;FA}18&G rg;RJfE\IGSF D\O+*Z2B\e''L;YꑋE&@X̷z,2a=3d�,(@}-G.)jBI^VbZĤcg$2d4 r~rY ]w+ iElQ o m~'0_t>yGy>T ,V 4LV5s9 5jnhrWeQ? azה|oʲ](EMAqݔ7k]* MA"&د)N?Kq]}@3ٗ}%ws�UM,˦{A3:a(۳r C~e Ϗ[cV!췋ܐb*i�~)'WgK%WKFIdm z�3gPh&sz"e )ѓ;Sń1L"Mo2hb*Qvrn&ddI|YpOhcpˌ M$dI`I$c̐]Dn<TB@Xƍ'ZO6ƕzm80h"T^⼸;-W_Z -WРb:I^D'bcuEӹF9I@u1uoj=9v{?}mlZA^swdخ-l7%7$&PXlOb/HbVK{<YHY''bqbʦcj+?JE! X s_ y7# ےr": "^]rnNkdh3-VU]`Y`Rn6Nӡ.�wGpˡ嗚$1>oKz'S-(͢hҧ+c" M= ?A4I:)b-wp@�zyedo]h8B<쇑c!fVON:ubwU kG=;S<;ݐ>&W>%Wn{ǓϺ*rA%ǔNe MG`L\;ۛ2icb/:qR �[x]<uxRIb$ p3ޅ,Q38 R~lR ȝ"Agi eMD0t!&^Nc#ʤBuYayLH<}'CwJhq{1=,in nTO|8>e7 jD[H/SDRF4.^*EBe1 %y,V'oGcFA(c Fw/u {`endstream endobj 111 0 obj 1804 endobj 109 0 obj << /Type /Page /Contents 110 0 R /Resources 108 0 R /MediaBox [0 0 595.273 841.887] /Parent 88 0 R >> endobj 108 0 obj << /Font << /F30 42 0 R /F15 7 0 R /F35 43 0 R /F27 77 0 R /F1 107 0 R /F28 86 0 R /F25 87 0 R /F31 93 0 R /F34 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 114 0 obj << /Length 115 0 R /Filter /FlateDecode >> stream xYKoFٗ^Co)nh1) "Ne*6-'οﷻId%1Z>"Gy~̊M(24*b2{pxts!'h$N$Ӛ1.f5jq/?~נ UH&524|Š'ƈO-Q*zhZ+ƫW "Kmiװju ΣyM\6QdmQ6 ,cS⍏"$JNxZ#? T $ZB/[=D'A܄IB ҿwVC2.B rpNjL%q`%:!_ W$;b$Y0DYӹ`@{ZJ$Fpooz1+ T{F+wd*J/4My&G:%+CQ[hKe`K:bA9%:`&M$K(ώAR2q7QX n'm3YƸaQR[Hf%N.,E۲j_G`$:"WOMWprm@ANY^1\]yv>n7m//ժi_Ư}.i+bT\/? XϪ_V[02,fGHNmI`$:/ `JHTؗu:@A"RXkQ$:3ABe㤬<Ȧ �b$>"d7/o'؍yZ�a!Nw؛p]pKcp!e0sX0ZrxK9T˕f*aVWirR8љɎyvF5yB(B�{KnX)hm0k#J| <CVgU@|9/1QC, Ww6gm{ ψW~+ͳv6-y4Xd4<*cWa>S'im,1yk6%0|32P͸%SkQLM!ɌW ~(`j!f'^ϑί7^{5 ۫uQARr8 Ac{^6,C 2 Fh1L%[l|U[ [_ım*޻\>K0T:Ty1hMuP ֱԛ-} ZY})K}Y)Sf̂>#zRՓszldo.ԏ=m[bxP=)=9N`~%&w2{;uչzx]:cA�tҭ^AaCge)WkLu- sFo /.MN&͢F} uOf-ϣZ %!qrZU狂K< F(05{]�a߰]@R1Yv&*9vPƒ8VD�+|(3<YTlpk/<CClv@*gnPvP0&� emIS&Ys%XG 5Sha\vl>i{6cBGa\C0P;M8~=./:<Q!;Cz-fb E.ܻ⦹ƢΝ4@OTxR f-KAv@Bc$W{(D&uY:}`\>ǯO$-g߯xFqvrD+!O[O ܐ_\o8s ͈tbP;S o&ҝkL(�P0;>?DAS<N/?bНpX\7m2lVr %^,Rw͕#&=᱇ضmY>Ja #Gzw<բ7ᶏ[pz5%ǸƘX"i{#<~~@mگTZYVendstream endobj 115 0 obj 1992 endobj 113 0 obj << /Type /Page /Contents 114 0 R /Resources 112 0 R /MediaBox [0 0 595.273 841.887] /Parent 116 0 R >> endobj 112 0 obj << /Font << /F34 5 0 R /F30 42 0 R /F15 7 0 R /F35 43 0 R /F27 77 0 R /F1 107 0 R /F25 87 0 R /F28 86 0 R /F31 93 0 R /F36 6 0 R >> /ProcSet [ /PDF /Text ] >> endobj 119 0 obj << /Length 120 0 R /Filter /FlateDecode >> stream xX[γпP{' !8A}(D $e>3;yr ( ^;3W+΄ZL2a:z|zVg֫|+O==ۃQ.}V{s*e'ku* ȋy<$ݡ.[͒Sٗz{j-lwkx<4C6šc9+Wyu亢`]O"*\JbJiGv:MJ'b|:90F4^؞jlfe hTDy[,R3Q,dv0k/qt'0ʡC_KW9/)",+> :?mhr�ϑc9&f#G �UnƁfK^0c9E.3EZ:Pm#:s&+pvY34=@ՆeB/EHf`_GU9ԯ#G x83v`ZO>Ybzbikr4ӆszkҌȹ\@($j;{,� /֩EP: a:7 olC-$(ʪ:eg…ٶ2YpپdǺFOh벏MBԅ#@*IK~rB9 qSK׿/]foO0E[ڗ~~}`7JDaaI']tD[FQ\fRѮiXGs@!E%!9<8qEЛ~O}x\.C̺~�ygqxJ #Y�!H.8)- VHkB%BrXLS<<gbܰ"s8!J�`_Y`FDTB'e m@\cQOo87M_WcEC{'Ùm"Wς`i;xˏ&cU,WC7Y>K<BxlD O1~x,cuOƬ.>ɻ\�)HomI,YxU_b)>c<a3_Dn1wYA;5[R"R[x)G9cMmw+#$(( $/kpƱPRXfܳ*\EuoLe4ס�y$x>~ʎ}V~a5u%<=,7^…EdahvmBGU7͎2drJ57+(Q d ^?C}yfn;NmL\3I}k#\̢D\7Az4K'``a+,zUd'˵pmZ(hn5 Ia3ySF[Yr2NT(8nmq2 <Kz-pI6kqFqMhj/wKۣLaV"Vw#pz*O#7\|j�p:8h[-<UU�77\-*-#?םϯH 5fzWxx؄+}~gu�LR5� F-w˝MCaBvzQ'9ךg{0헝wGaߓ m"דH$9n\}™}x9}i;Ng^!%XO#Pb((3OeB, &O dZ\D pԊ"y7n\d{p9t8n [{͐<xp \m8ѧ/>?vO쒿}?NyCS 5d8A7~ʨcЫ;vU*;V$,iaѱ‚/u]_z{M*6uvJYjWo^&0endstream endobj 120 0 obj 1924 endobj 118 0 obj << /Type /Page /Contents 119 0 R /Resources 117 0 R /MediaBox [0 0 595.273 841.887] /Parent 116 0 R >> endobj 117 0 obj << /Font << /F30 42 0 R /F35 43 0 R /F15 7 0 R /F27 77 0 R /F36 6 0 R /F34 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 123 0 obj << /Length 124 0 R /Filter /FlateDecode >> stream xڭXnFͳzS(p) !@S DׄuHid jvv̙YѬ %VL1NtqDzɛw庭61:nca \oVrRvl |V7lzlܦWTfJ *nO|:b:ߝ(h>)XP{WrNe$e^r2r L2°~Ww ;EAUP8]-6j_;1J1DD`!0d4V߭6| Oxpo,/7UX*y=-;wm:4yjP,޴Y] =O,Մ.zeW$ )e"]/WpfW)a&ʌn "ftpW-\vޕM\1?8wVacU>3j"Ur4To7M<TNU<G줴cKV&T10e =LF0CO`E%)h5, ;uS.gE8 ^ TNx4@p"哜ypTc3V5]:4(1S?̢tV] cr'[wu˷xЄvݖMn7Θd2(?LFro1ҺS #b2M'ZMd@`-,l}{_].9 7%@աڃ;uvrYbّĕח4͘<T"Y,c{eZh7<k:UXaJCz0!1k ?o.j%E3%B@%lSe4v۽-coˏL0t&<Nj Vi!i+#F9PȩHn ՝ugDQ;<|h s5�@#ks9N߉h(X3MtJk1ұp%HGH:xY+h?'mY/ɮBRT< �S Go/Eە*y#z "O(QԷcBg`t-}V $b~j 1N3MUݔ{hygt5Uy:#+0T۬{ͷrc>2:R}|A,Wz>$԰NF,тQ'wy uw]Bu!HFeT@uN\8IN\`64(]NNX팚jw g; w}:D)K?uYiܜ:e!+)LfCy99L<11Ѻx9W4r>Sw5�9^`4l]l~q$/ }} _qhBeb`0*78:v\s?dC}?w9 {T0!Ph%=!z@>cBr'$z0<Ʒlt0Nk: [}B�Qzհ'[Y>u Dowo ʱ#f�AZET;NOb7\ZC;GH -vdv]ѩK̀(*iX <1,]I}Ě$@^hV-WmU7-[ǖaPF QPendstream endobj 124 0 obj 1745 endobj 122 0 obj << /Type /Page /Contents 123 0 R /Resources 121 0 R /MediaBox [0 0 595.273 841.887] /Parent 116 0 R >> endobj 121 0 obj << /Font << /F23 5 0 R /F15 7 0 R /F35 43 0 R /F34 5 0 R /F27 77 0 R /F30 42 0 R /F1 107 0 R /F28 86 0 R /F31 93 0 R /F36 6 0 R /F25 87 0 R >> /ProcSet [ /PDF /Text ] >> endobj 127 0 obj << /Length 128 0 R /Filter /FlateDecode >> stream xڭYI$)lYS2'6�aKl(WEJ%ug0ЁdիlFc3&Z k1|wkf!-U}hkaYj!_֛U,Ӣw~6酮߾yhLew=^g(nO5-1r8n U >]+U5ۮY ZAbǫDf86Z>D(xA Gҳ@T:S-#RY$RMV3U\Rd6n~׬vTh?uM2 >amKvcIV 8\,q4] CQZ%p"ᶝ=\aLى(1C8Vl,*q ւW&:~ 5Vb ^C, 9o_5Ӌͺ0">7}2evCpز{ruq,4X6`zx<5xQW#ǖGDr[v3WQ2KK$-^J MHu8N(1B^JZH? ڶ[Q~,\:e'gh\s[})iPc%ka_}鄜hm MVl%鲕zjZA!g!-*onʵҲ& ( l)Կ+=j"זWQĘVQlmy{7?rAi)20ٶ;m �7);RXy$\v[?IK$X_R]+oJʀf)N A6"%{T1=bMD*nLCO_Gu!cHy y헢΍rIuF_NK̎Za82i |.2**т/ ;Ph~YL KPzJap pqODnb3ff41^nץVQj> XOm(6uS+%ڻH NB?$1or*h~ZINfW(d1pA/q3We?dٳ4gy(L[%Р;@Є4<0<q֍)wNXr'@seQqaHVQ=WǏ9kI E #AB<:+Ah9r<~,P%G h,ᔥT]МEI.xb&U�G<&"!!h$jLޔ34 g<i*gРξ,N?3wȜ<FI峇x2,FsQ;v͢]ovmD|z\ThV&|TDb`%Da<[f 2iAs Vo.X㪏jih}(62{lmOA͘DŽ�{m?Y/ۤkЯ|}7 c‹eh( Dٕ*!,CFa(O04\%PGA(rq2rpr 0I]vށ嗸e}1u ۲\',R-ۀL&ï-q-<l7xAp#L4eV'P=38 軡A01 'vR7Ox÷ 9SυG)I]ʕP |+\c_n!ҝ<0K<qC8x\vq'T#*o`8?EF l䎴^la vFeʣ^1Q քh4",r2B\2tB҄5 Mj*7 @i%Q{z8MSR?vZ堽9X4-˽_4O%Ƴv}F-B=o@Li s/?Awg u<hbH&/"~PǯrZ%qQRt ~\ǜ2r(Ƈ3# ;,p�^,F!iF-7kU Te:!'nqbi|yK?•<9q4spy%ZBPh3 TvP$CG5Kaq?pNB;E(ϋ)L(}@K#p) #C<y!| *iNq 0U.1}pu?*3endstream endobj 128 0 obj 2264 endobj 126 0 obj << /Type /Page /Contents 127 0 R /Resources 125 0 R /MediaBox [0 0 595.273 841.887] /Parent 116 0 R >> endobj 125 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F25 87 0 R /F30 42 0 R /F34 5 0 R /F35 43 0 R /F31 93 0 R /F28 86 0 R /F1 107 0 R >> /ProcSet [ /PDF /Text ] >> endobj 131 0 obj << /Length 132 0 R /Filter /FlateDecode >> stream xYM\}I,69Z`p�;A9pFGFHԬIbK36&1 Xج~ZL8Ly;\1YϾ{L0or$/(~;_{%LJ_M,fYGQՎyHo6wOd6 nn:S,:^\oU,-jZ6S鋏")=}k2)'&3GqI]*ƹMʼYiڽͤuŏc (tbe확:ׄZ|!> |MR~jQt♇!(9Mf 97 N(<mhDfi1i }%rz[f8fl"e\ۃY1?d(}~~։5D LZ rP;n|Lj$Ό-0sm=Y<)Z9- 7pzrd-daVEK!D S�$E֗6haeyux˜ "eq&Ȓ <ja$H 0J,M09W=eG/>@ ǥ?f0SQPlzԔOiZϫryZE]VW:ށd|<aLnr,Mm&d%.UYXfR3' H ËGToQmJM >+A(V `F?\|3p .}SrjSr׫vվIXl:uat())'τgGms,mJTXYR\2+ZONJ^[8TAugh=#̺!s@Dpn/9TJ|:0X+ֶ`{bLS" 1N6H)R/ld@/wvy?X($m ,Y׫~We5bHK^,(uo6n ۪ &&BGhۺZǫ"V /6wz.ہԮ[߁ߦMhQ~YfbLPCw$z='Kp_'2]]nf<eVn(e[jE57)nTi]o^MTW)8OMwoó.&i�K? IL UADk[ZoDXdVFޞ k.HAn\iWyF!|+ NT٥u^]5J5mgRJ};UtAXU$r=_/jz2b9$VgdO{Z}Umd]E1z%J]-['V<%_ڝ~FK|sыz QH!9>R=f#Y[1<EHF<Q)-'?E(I^bz$ʍވŘ&>2I5hШ-*wl5lTݰ]a}7d"^rՋmDC$~q2MlnQ8BKu2VGG&3/tFۉ*E "O鳍vOVZhʇF�JQ6٧2JȊI<d^C�nEeJ, NPSK,aQ#<#WI Zש< ,I]4+ai"5.IG(C \SQLM_QcP&.D@hXu%SoGL)7o . t#m5mP 7QN?nt"awh֗v 2e`EЂEPmWy!i CWI2;Q2a 3tx3ә(37/%0>g˺R O0Vlu4lu{IYS^TDu~OuhSٛ' MG8G8GnJ?|1_`}Ҩ܆:v~/ã~QQqsFO,4FDq5g1뇁mj\Wk5!y@7:ȺS%CaSHY2cİ8^nQ{u[*[EYf/)|;7&"fscA \M:|m\(Cw5&I-C6ggt 7$"MPOCiOPX|G#I岧YUxВi�Q-Ts#՞g:`ȼFJ9Vid2Vڒhq(ˬVODuDHuhILcF#uF:GE<IvK11EG8b<b1o<J/N7 X7HL;27.O^K5>o M9a2D.'vۏG^ 쉦҇6$5&,tendstream endobj 132 0 obj 2534 endobj 130 0 obj << /Type /Page /Contents 131 0 R /Resources 129 0 R /MediaBox [0 0 595.273 841.887] /Parent 116 0 R >> endobj 129 0 obj << /Font << /F30 42 0 R /F15 7 0 R /F35 43 0 R /F27 77 0 R /F1 107 0 R /F28 86 0 R /F31 93 0 R /F34 5 0 R /F36 6 0 R /F25 87 0 R /F29 133 0 R /F26 94 0 R >> /ProcSet [ /PDF /Text ] >> endobj 136 0 obj << /Length 137 0 R /Filter /FlateDecode >> stream xZKo#\cxa G:bHE,%٤FZm4Ùbw׻+ǟ fbҪg/9Uz&.#?+I-߮<Sr]/ɿ~_[Kˤq&H7y?eGS8)daϴ'VBUM颫I-],d142=^¿p7MrV==^ Fǝ*0'im_mOjmdϲؤ'4]*劖66n4[|y<,HKHƝﯖ Z*mGMDu>e{_MFv%,@C~/Avq{҉1 f*~ O Iu`*?`%'zK)<f{^ַrK2-hVzц@-q.ڼ6|` =LƦWY&Z4 6g//�(:+pYE z\$(o 2 pɍ/3$cs7YOC/l123)gִF{(cp<ܻH_^ dR0mL5d u3|)ۑ*ͬp]݉|h2|I6I^?C/mb`,m;֧=X2DxI"Q$i1-:@$dpr8@n4HBG3QvC!,$GILw3"q UD1Z,sJP2)&%!7ؘC d6_$@p J`$iݞ `yy+dK99ӐCwo[qZɜp8-&rD1F6I)㋒8`0!'G"LVV?.Y>sć`/+,IG'̴ӓCc(AJYPEz]Ф0L!R<'6e7ϙy,^b jB IR.z-‡jߠF%MD,D~ OLv#șI{'b"1sVR&O$Zvܐ< L*jPXBFr(.}\?NߗUe_ X9w?<vDydY y u|)$[մō}(y]ލ;*%3 Ǣ;IE*z|\G~ ] j Bۧf]𑵽pGEƲHdnq(uh7wӋYJ<RU[ʤ0�yta(d7ӳwV!\p{5߶w!IQB�WxwbL5_/M$N@ )q8PKF|ڪWs,Xi9p/|X鴰hh"di ɫջk՛Pp6u5/?۝Dord|⿠݅Rn]tѡI Zy'`6; &}\4INOEM(WIH*^U bt$fh i~Cp̗mROb, Abh6REO]؏1[{ˌ?z#]~Y=Ώ cQDT ;.J[I;(˕[=�$Pڀ $epP|^,F@zT)&c *? LP<z}/cdSPy]m" % WH:.%8}( XD f[qtv7Zvǭ,ҙ̃=L)= V(t(�Q-mA(:`TwePC eJ` . ؂x?FGQ`XwVXܡ)Z@|'.‰ynbWhyV"J)15T= SIچvmҸpI# A[E7VOaDuA+8N'kg^7{(d2F"l:9NػGTs$aMTb.(G<)(I#sS1\.j·rx|NF78$EWDmdusQwGuZ?h͛Q֪*iiՇE{EKDPu؝C p:LS`ֈf4Oz,4^Ag]n~af4?f]V8U`\Ty\-c\xdV!i 4Iǎ.:.B> }I[:@jSeZ;wHE9>4?'SG(U:6VÑK)|p c)LRhn]G80`~uGZi2qSQٷ\4= p,Vguj6_0):xρsCGdN},GF*h5TW(햆Q"ĝb>e'sj8T-dpfBF('N);rĬ2ߍtҏ5T>!o5o]endstream endobj 137 0 obj 2667 endobj 135 0 obj << /Type /Page /Contents 136 0 R /Resources 134 0 R /MediaBox [0 0 595.273 841.887] /Parent 116 0 R >> endobj 134 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F27 77 0 R /F25 87 0 R /F30 42 0 R /F35 43 0 R /F28 86 0 R /F29 133 0 R /F26 94 0 R /F1 107 0 R /F31 93 0 R >> /ProcSet [ /PDF /Text ] >> endobj 140 0 obj << /Length 141 0 R /Filter /FlateDecode >> stream xYKoFNRW) lC`>Ms%!jSD%\.J[7(rz9f(sD833Tlq{rvy\#Nu+y0tsFϰ{~><֋ZATE%RNⷺ\-{1u-+&xRJJf7\*5˰[jfŧEWY#q,$RY\p}+몸)-܌lq'hlmQMB2։}HDc^*.pk̄~%<M(i<͇t"i,0&!#d'ˆaF'B]ׁ/Z7qeX8}86Ŝs>hK@b|$ʋD+S'g " aN0jZ" 5(\d'n'nƉOAJCۆ pٛ*N w ]0#BQΘA(2 Pjt[32bòU]s6Uq #eiv\ 6KE _&oЧkwMxg)UvnNZMx}],UlR&(>/Zx [ Ϫ.j! nkĻ?5ٲ W(&x{Enp7 R2+mٔD@54YKQ;A5GcTOS\p(0{ PORÈ{FUJŸ8P,0qcuFyא ICw%ʾVpL.42H04 eJ%kYǫDssG,q+ME3.pi++; ;晆`NYIabpLrB9C{Bht}\I6naf9DD#2Mi@cH,[M1-KW!,Vst31*UguQj|"WH7r7,OcЁ eoI5>@砊eJp\L7~,=%SJB&ɭ١==ge㛹5/nn+0٬= S*uQ/W x{77jVmDm]5a |\w?<H}׳*c@с&yMiQr_}zm "Ln }NM%'Ɖ6]SqgIN->%Tzh0k_y=0L1KdGĤ^kp|S ֵI.nJq~A܍DIGv$yfJ:voYz&v'|CNb0uK \lD�4rv}(0 G?y%`}<}=N/tr8�=OQv8uΥM(X/ͳ=ޠʔ%yvxFﶔ"&VoNf, cc1'x 4}[ãSTvW3;ZE';4�U% zVz>+=4l\w36=0+l; snwP<<٧ĕϱ. =Cͺ?5[`:{1uendstream endobj 141 0 obj 1709 endobj 139 0 obj << /Type /Page /Contents 140 0 R /Resources 138 0 R /MediaBox [0 0 595.273 841.887] /Parent 142 0 R >> endobj 138 0 obj << /Font << /F30 42 0 R /F15 7 0 R /F35 43 0 R /F27 77 0 R /F28 86 0 R /F26 94 0 R /F34 5 0 R /F1 107 0 R /F25 87 0 R /F31 93 0 R >> /ProcSet [ /PDF /Text ] >> endobj 145 0 obj << /Length 146 0 R /Filter /FlateDecode >> stream xڭWMoFucyp߻l1R=P"(C.IZv€Hg͛YPqA,Up-ݵ 33ܬMwH2lE&L˺vrfc$Wׄ[5| Һ BuW5AhVeXA>[dܦ.hܮHh2g3I" s>,L]],\[dMB0{EowUq$Ǻ%LK~fYl.l©S8]j׆p3ɈDPۧC$emL/P4eDh֋\EtD F@! 3+zE $4TTd?zRE?]d?e,f$ qU~ +dlz.e}W#?y˪ik 6,% D11G\{3'9#s*yʙS S5- 4*+Y61e~(e\W a^\v#JF?ǃՀЦp#9O,N4= ]!! \2 9YPr$xɮJ֗ldATX"iJJE3h}ZH*)bo"4y|'+I.FMjW&VLD0mdD\X="6SK,13y>FhPD P"g9|*C�3tkLF2 g f0C$*A~?;&R]`DogCtSOf}:3tNxILNtU)zQz/HbgFga�Y+ULЍNҐL@MvczЗxYky1hֳ.c:FXÍC:(ZQr1|cr IaGc<XdStWq3ԄOled"ݣUFO**1=C㥟b:< B(l_Jsڼ9\x݋0G`9}fn*hdsӏfGa2FR] dPs5~6a/(B͇l (tp{Y7 /ژ ML<<5 fQct^2!}/8GfYU=6n0VWd mXRNTH. B,p^HjzG7d|o_)16$g+*%w{.s=G&v͗~/uSuw:Y<deE9�F[ MaZendstream endobj 146 0 obj 1397 endobj 144 0 obj << /Type /Page /Contents 145 0 R /Resources 143 0 R /MediaBox [0 0 595.273 841.887] /Parent 142 0 R >> endobj 143 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F27 77 0 R /F30 42 0 R /F35 43 0 R /F28 86 0 R /F31 93 0 R /F25 87 0 R /F1 107 0 R >> /ProcSet [ /PDF /Text ] >> endobj 149 0 obj << /Length 150 0 R /Filter /FlateDecode >> stream xڵWKoFW tNvR) @U_h HKRn3;KY)J(R ;;~bϬXj2_\N>\J5;& 9>=O]Lӛﰐ{U5hI"AEYyVʻZR�!;\f6(=Z6JֶawE;oiߋ(=԰�Uӯ/~U>}JϞF\䷋C"Ԧ{JY}hЂK/TW tυrDh kOs_7K40fkǖ?`(X bm u}ibkb@IzNDC0#z"gKe\x,DٟmY=S Qi)bJ 3e0 &̉FU"#^,j$o/U,7 zb{.6;[cP@JLR2?i= "=8W"V$JGA3e(5ٌCbBqԈe3keUOdο3ք2syR3GJ^I~c", N!bA)ƨIdjyB{׎!ǿ]/= (#!V TG6ʭJC_.jT&pydI%N ¤r@)+Q5>cMRs@3}Kmsu֠R2ۃBX v~tʍ9 L@ ^95zm/4pEa}Aؾ bS!%7Oa N&jbǦ,v8-BXudE\% 7<uRS{[yVp`^ }xÀ|$t ;80}MЏG%4,9߀FHxd1zj*a' ji ζZbeɗaJsw+Z j8siG .>Mb'>qZ)<O` dagB_t,5\YXj<v5p>v;5)+<Sb 2К`JVz. |R\yHyh\zq=MTqq-HNɀjCF?K2U+܏qo͛oE8!7Mh7D ou<:x!%1:k~DE+ iʊ-_k;XXRR}kendstream endobj 150 0 obj 1320 endobj 148 0 obj << /Type /Page /Contents 149 0 R /Resources 147 0 R /MediaBox [0 0 595.273 841.887] /Parent 142 0 R >> endobj 147 0 obj << /Font << /F23 5 0 R /F15 7 0 R /F35 43 0 R /F34 5 0 R /F36 6 0 R >> /ProcSet [ /PDF /Text ] >> endobj 153 0 obj << /Length 154 0 R /Filter /FlateDecode >> stream xڥWKo6߰9E XE�@� J]t."Cr|3%*O$\Uw'o>t9+tuutYǢѴ54m(*=5}<q)H2]?*cu,akQF4mܶ~-tO_)ܻ7|zJ̝]Ӓ^0fNc%T?EU,ed*W1WL4Q1 vYqlnZCKS48]tPV(%ܙ<WTS?8*I1qeTtEAa QD-~E?c*-mݙ]?<z=ďX*V圎lz#tAk ,*U8;]BEU !ѐXcwMA1tҦ&}\F�G&k6?-qK C3ztKÕX q:`:kJ UMՂO`EY0408"qe KT.Ϲ氬G펾G`)-Mw>#l8(&rA7tBDAwxަ l8E4]  (Y1b=S IqpdPc/bZsǸy0+0Q ̓q\HQ:pnd)9c . 't:"2iVs^._KS- 󥌀L@|"BD 衣;͹kO0񂐯`/goC2jrwGZU i$ÅLq҈PpB=\1xrԂD ǀOLˀ0TʛÙ+gqlvwSk-9d~QΗJb%utj;GxTh|nnu2gy % $ϟ:�rɨ8wU,2(5/$0K_O"T+QKIlMM;؉~om}h sTㅧ9p:td!p-OäEcG3y2?@?;= ]8a44 d SD FXW$/ Su̪!R5?[,T;r%#+*MK| �s._�',GJvj GNOsE O^>zmѻB:vV -p03>X(ʎ38)AtJ)lnng82~Ws$ Y5x{=e7{_e"͎DFo:Ԗn =c-n;m,MlZѬصe"gЈR'JZʌ^Z{g8qԃVW@hݤ/mAvT`yf}CH<c7-c,TAc=d</,ӟ>O(}OAŗ EU| _;Ȭ-< U( )Umv6>)zn[`/FEӼmlZÂc@R*!8gP mq�UC^?C/9g 9?PIV(endstream endobj 154 0 obj 1691 endobj 152 0 obj << /Type /Page /Contents 153 0 R /Resources 151 0 R /MediaBox [0 0 595.273 841.887] /Parent 142 0 R >> endobj 151 0 obj << /Font << /F15 7 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 157 0 obj << /Length 158 0 R /Filter /FlateDecode >> stream xXKF/Hv?d9N_X(gD*$x뷪"%AAF(VwU}j1'f`y*g+&S5[^,(=Iaf;O|JR& !N^_]/UI4\&io^ |. \8dZ>B "+3b%3dyY pզ3H;.8,V/pIffYn*5X3LXB 2PH#R@9B3Sҟ1*%)M5eka.p&\ͻAA?"]ʎz/ƩN΅2?B)!$X_ muRO[}1ug/Ԓ8a(C吹N$9p)ʁ Q.iq@y-;ZmuD8v&gA $gO7IP,:G*YN(R2[+_[$xna؟_S7Sʖxݗ_ރ|]J;$:l&N^H�p\p~esֈュ 83ąwDc x&YXu>:G!؀y@uqsS5 /J@ 8MT5b~Wo5R^V+vJ2A,3ZzA^?] %A^!g9`<5nvw%B)R =dWST)3y(,"nuёXpt uܽ(I{o_{뿄�u_n<oݻoo_=�/z(_ k'bSwZˬ+LR(eb<0zG}G`跧kD 7UmYWJJdrCWT:`1YChsFnUTRha(0>\ qB2u aVX̾Ld2g=wQSi3cڤѽ$e>J(Ptb֨tu: :mhv;hYoܗ>Lb6D…z\s(?,S1jE;�<ȻLъޕcV]ЎIYkqTuEJbѨ+�Kn嚖Q Be䡍Qy>\ʪb[~+:p?lan 6PbEYXI{X۴XM Su;,U� m$lk!ppk+*`B#X\Sy8>O[o!FB �@ .Zx, '}Pe{; -N7I^U0k)2^cxȬPT" @5t[P{BJ;h&PҌSlϣ2`pȾ܇us1^v@#6ﺢ#tM%]շT/'%Db̦ NknIђb,[MnXj/ ţ!L!B{~<_M|M!?͡2v4{0NZQ? yNL}o>xS%Ԡ7>M2蟓bYDv$'L#;{"fld",Pl\UwRTCDA]4DX9y_}B2ڔk^�/>ϱ4i&W+>>O9.1v~LN ѹ[|,9:q!vJAm4XBdQ#-jy!g#ɞ/= Hx )X!԰a&gy<|8aFˉSQCPsKj50@SB9r2gдVKV&:)/ԿwnW7Е> 9F:*Owqwhy*J؄l"5z+M̕Z@N9|6? il|F @\)> J&ú\j+]6nSl˶̊u~r[j&6h+1#z+|7EL4 ,Ѱ݆,i>iHQB#~O)endstream endobj 158 0 obj 2127 endobj 156 0 obj << /Type /Page /Contents 157 0 R /Resources 155 0 R /MediaBox [0 0 595.273 841.887] /Parent 142 0 R >> endobj 155 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F25 87 0 R /F35 43 0 R /F30 42 0 R >> /ProcSet [ /PDF /Text ] >> endobj 161 0 obj << /Length 162 0 R /Filter /FlateDecode >> stream xXM6-zKZ`p�9hnR-$9hmmV-m%9i?!)ɒ͕ zh Kp̣`A,qb\h S|ڞ=Y=x4a kt~)"c�&UUV1<ZuVX|_ lߌ"B(&õLGfS3}΋"E\d-i:{OA HI`'fQek;-b%纝<r Ł3bƅP0L]RhCO%$gtz_ ͮ7Ѯ1Q@k$JOU2nWhΏv Ehnc0(p rOiOкɧAρ@d0o@ ɜrH\7q�Ja,<Dd @FqRP�eY<-O=U1=%HBgC yp3c쓭Y1+Vm) QyUi$jV>EWzWyeӁQ,a σB9楘 o-sfڥunuo6UgjL49MԨb,b1/OzZ[͊:/#$JM4= TeǜeټyCiC(Rky>:($u_ֹ:# Ro{ z%fSSߧ_U2TU&2KݲJ;;?\%L �u$`çO%mmA어np:׮ozE.�KH,yXBmny4<O7 3W;h, ?Jҍ jnW̰Op*A�֙]c[i>짵{5Jj:9njG8Lߴ6d%逃�p^M{ޥ0Nv.oCQf݂<R7֏ʣ˰RH_ܑH$䏕NBx NE~twub2anl,[LvV <RrϺ|{ɰY 6Yv(r(t |U& Ui}C9a`g<bb")c|].T1B/i/WЏX;z5{m-+۽W7:Bn .Du5�,X.At<z!h]6Bi㦼eM^'^hBo iE |uT.͸gR< +ۘ_A&ޥ{JY RMI5S]L s4xHP=WG*Moge^BYtgsH0@P�{BS4w<<UBkO#7{&^R]OѶx _&%'rheuU`v=(s9P2Z:dqaUu71oiR 2]Hff2]3=wz_60u4qτ4mD~x>(&\=XrtH=.JB.ꂢ#;끺\!0!>Θ˲ꐶ1q ` CT*vc|ǸBgxh[#i { '}%zd?Bhv/ӏ l CBnHFU jX7cendstream endobj 162 0 obj 1745 endobj 160 0 obj << /Type /Page /Contents 161 0 R /Resources 159 0 R /MediaBox [0 0 595.273 841.887] /Parent 142 0 R >> endobj 159 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F35 43 0 R /F24 5 0 R /F27 77 0 R /F30 42 0 R /F31 93 0 R /F25 87 0 R /F38 163 0 R >> /ProcSet [ /PDF /Text ] >> endobj 166 0 obj << /Length 167 0 R /Filter /FlateDecode >> stream xڭXM6G-37$)ZhlIZ[j[[Iv?G%VH)>g޼]х[9'LjwkgX)W~c_r #rɭꦺ]lWtM"wS1:`%Y7Uו{@dރw]S_.VДrDlۢy44{�,Q%BK{kJV7Ms29TsW:k#H;_HXŒs~tei6AQW{Ӵ&ടCZ7bT>M^a|sدާk Vt&a^he4_y6kjgԍw3;Wu.4"*? ++.ξ5@<Y) 2�~�eKh ң)~J$`6F!93wgo]$AɾN!t_&PղŢmH`4#ωJKRD_bLdoUØfu[C 3ႎ(OoCr<bwBlSqE8 Z 㳬sKA"~B)_a%ßX6M>-u0ߖUxݘUoUr;9Veڱ{ )aF_Oho㰯:κ*nj_0 k1뤧]J9acs=rW bipwדGNˀ�Ĭ!Q}6ڇ+w V%}3R8TI mWʵX„IC 5aPI PKCsQ# r"I]ҙyg:X>$aHr5"#JF_\\ŸC~}LԍvR0Z3)1j'xHDG  ׅߟC70;I!�ikVr*5JӴP1XǍ&9 m'RΦΑmSh ϸj}tFu0RbpB[tW-Df VD3\l.h3 JġѐFe_D].<GIJ7Cs$,&Cd\S RTQ6&:P~|sMȻ ]5B$iJ$AmbըxXBHa<* +f9XV.oCtL iMUO2э E/I+s/.llp#J˄*|^,,CLyP6NO-i;ۢ1-Z>hТCE}ozQ85'ˌM }\,<c'l0fi݇7oRTkw;B>zngڵ 9ߛf_ek stKkjfdx PE/e ycțA"~up:g쬎^7)Rxl_B-'uUq+l9ѹ̀ql% t} XYɹ�n\pzYgWw'>ʬط@IhȌU'bu .zQCc sfL| j \&j@XH{$#SQ?endstream endobj 167 0 obj 1719 endobj 165 0 obj << /Type /Page /Contents 166 0 R /Resources 164 0 R /MediaBox [0 0 595.273 841.887] /Parent 168 0 R >> endobj 164 0 obj << /Font << /F30 42 0 R /F15 7 0 R /F24 5 0 R /F35 43 0 R /F27 77 0 R /F34 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 171 0 obj << /Length 172 0 R /Filter /FlateDecode >> stream xڽX]o=R@4|h�/R$m@4DHJRusin Hzx;s.*?˕9aǛw7_bE5aT~LPDvwp-]m'\YU}{G)2ahe fDzj{`}훶 7E\Tm`U*:zvؖrb S6VÓfi܇.^-a9}8Bi\Fn TPAQ?<;N>5e{Q8 /v)raR& 4T-%X'ǔpw)W6b^2"t1Pe<&6\ 81 �X<yw%RGX?qB&s%Pv<p#gݧ<(D7 Kdnf{}]M_̝IEݝ<.>Si1D ld֪W~iG) +Mp9] ¹KJD CtEE }9χ:LjC1zukLX�.17}Q/$j̒&eu5_% 9fah ״,)S$%cKlU6PJ)OѲC# 36n=&]9&[]?=t%7Ki4DJds3SY]P<x}\K@eXoHY]綌UUU^$@MO@҈!9گsӗ)Y"p#y4&hF9h<9<oӡ _Lnr_f^dB�V4}Q^|K.aecS?USG!-J ?&i 9,%덖"ֽYlɂl[F FHSûXΩKa_q:}k>O%Jd9D#%R$ nΣesl)Z]DONq#ޯ CCIXp,{tUs0cb|A+!%j0Epw3wx<VuuUvU*S :̦= `dohP-?+_$Q�_ ^Nȹm$-߰"54U\t=)@ Lb&1Imګ}rsjWv/wYqr hݒ\b}Zn>,l4:]-9#97<Xh*VPn& fՖ 38 ƅ >(.} JJH+]Ma5�J7 C;!]%/*O�·bn!2c?'LcT_ ܰ:/U'χT\ EU[l~nӭJ}iMЧjP4/X-q\1GJWbT 'Z(G{M¬�bFv oF N 5R�+i;7m0V>OՐ&atXjbw2Tm?flgg=%.,|45U( :m.TQ#U GNybb:~]$TSD”5B0rWtT`ԁV;)&`T*"fIưN> &0'$hpg Jdo1Сw<W`S([y7 qbAt<v[ٻk?^5+S&j~2Ahb} 83Q�Ons endstream endobj 172 0 obj 1860 endobj 170 0 obj << /Type /Page /Contents 171 0 R /Resources 169 0 R /MediaBox [0 0 595.273 841.887] /Parent 168 0 R >> endobj 169 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F24 5 0 R /F31 93 0 R /F36 6 0 R /F27 77 0 R /F30 42 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 175 0 obj << /Length 176 0 R /Filter /FlateDecode >> stream xڽYKr%yb2 A"1jaaLlfZ+<v\;<̫Y]]]WlEVPA_r L.oݏ&nan>e#k-rQjm_u۬ l*pM^LW O$Q7<?TыwpaaMڮeʡ p9SM1qio2*2Iq@{׵^q;H0nV$QIU* le3~!0W83l8lQzUWeXҔypTCNkAK#NvE )V=-.rs0"ierF/!더0ƀ`A&C[6j܎[A83;[MG/9L93';]I /y1F�ǚ~O+tm),U{\p: Aˬv\iVΟ3!D'<=�%ªWW3Ecr &ߚ5k$U>Ml|G}$Sp,|U 1S>Bp�LH="_>Č)j&FKxptrE0Qnb,{6'M<Eק9E λ_aw3aeL5~0B&:Qҗ\sXrd1*&C!(Vr i$5:5@ƨ9 #F4ȧ$QԖ_-*gm!qim$F<&0~&Yc(B?{r`BW9KP<]n ^?"@ rE3O -u_| 0O1@!p_0@H)ۘbfm2d%4>/D(!~|%9eԫoD&_:䌧`xr7?�U!"ɁߞZ,0 }FD?<H8$A6Iی2 !7N=wXșH<2%)<rD`xϥPo@vxQDG>b~wu=70G!=.^J[bGrX#V0zW7m9Pߴ]xW[6<Mf&b/SkXBTNGXtmg6OUwrK) 1z;Tz)z߆kpr?*OAV[tڶ`f׿:M񎆍5_کј\ږ}^!j⛲ cͮ­T G(}I<y&~ gPp}˦msP}UC@mo,U24=Zcqh.yt4 cAM6;|KA2+T *xP*+P-=$žy|PS:6lj!$z/qHyw=\9^˰H拝kG[6xLMyę$1<!AN9y}=橠nTX2D|fGc>WE'{qa So@Qܮ>TMh.+#sF=!cU[FNo`A 'zNCY'~RvڽC|Fo"!׿_[l؟MUW-f\yj Ɛ癣 uDr6BC Q%6|DM"~Qp ׁO00-ql_Kٱ!e PAep=YRp;|r\64~O- QZr{B7/ ,bgW]yY $G@ixX<X yG\{ۦ+7x;.UWS\Er-K07W25!jly}T9yJYezw`9زkBziOٍq%C9>D}3GKzq‘SOL{F)r\Me}Yg[iP8C1v٤TH2&qn?RQ͋zn4ـX͔]:�!@_|&:on߄4aHx汯 N=g䞰iq:!Yio<plb$96u;F麌x`qm9j8vM<k2e70l>qu>($uؿ~ &\2�qrw~endstream endobj 176 0 obj 2301 endobj 174 0 obj << /Type /Page /Contents 175 0 R /Resources 173 0 R /MediaBox [0 0 595.273 841.887] /Parent 168 0 R >> endobj 173 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F24 5 0 R /F31 93 0 R /F27 77 0 R /F28 86 0 R /F30 42 0 R /F36 6 0 R /F25 87 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 179 0 obj << /Length 180 0 R /Filter /FlateDecode >> stream xڭXMoE{9RNfk: ˆ5Ci̐?W!1bwuիW?0%F6Wo_}P+Y։^o{_+l ~\H*fBZ"k;z/-N]ּdB/VmJhcʓ8F7"(UD`RC</=xb[V߻o]{L 㮦ɚ6 S{X2zOCݳ /wu3_\([WB1 512hy`{byxjm3xJfJ1YU_n_�l]v^q}U_ί^_5ϳw7nB7u�OJi ͆z$";݈`jhڻVY_ް!*Bb O<#²],h`, +J&u:|51& thڸZX۾ڌ В�2bO˘�`Ʉ*33tgO֣%X:5݄Xz)B]aॏCOC/]8!H6nUt&voX2\R[XXOq� Fq3[I専j .xvbCx w1Ɛ/D J̴(0gb\Y$%iLF#bKXq{ŤJإ`ըbO)"^/]PQ&"k*i 嚕J(/H3T$(BZ*z{Fyy~sY,2TtA8/\�q"LL) q%.S ):&& CΓ=n�0c  5f(B0rt;L?Wh^\.\,udGg@*z#?u-ʕAڗD &0P@vzBgx–/d5u9} [HR!(&c.!AG /Dk@.6w0$F`d,`vK哄Y>0 f�/*I׵(qN`ܝ!oj*C` rql 9:. MUKW&!l]5[s7D8 1 Zwg)V2m<$"6(@fMcBT@E$a c~HY>f1@1ѵǸTj]&WHlQ-U_p W ~?4XĕSẗ2U0<BQW:jD_AymNwU#{IJmi㝮}]vUIА= ԮHF~AEmu-)"]6/\AFl3/'/@s` =mV̜CMg601zeP8SPQ*!ŭ]࣏䩽t!�j⁌DAyv{ɶ5Is."ۜj5XNαjRMYZi@6MC o(CJXGgb:ls-2rQ?i}]6QGֻ(<dlnaUa<MS]XI2w7/oN8W*Ƌe:NߐAEs'[wK}x/StʰB9]ccXT{<g $N| :Z i7 @YSGH69zL'kCI K9lK<7Z@Z7MgٜA|H)  >FҠK] yʫ~S-5V /؝95_ #ԉg6LM ΀9uH:EHSC;x6ebYaL,'Q5DtZ,?K5},\Ch(ܵw]KQ<&~V)\>6Uy~endstream endobj 180 0 obj 2042 endobj 178 0 obj << /Type /Page /Contents 179 0 R /Resources 177 0 R /MediaBox [0 0 595.273 841.887] /Parent 168 0 R >> endobj 177 0 obj << /Font << /F24 5 0 R /F35 43 0 R /F15 7 0 R /F27 77 0 R /F30 42 0 R /F28 86 0 R /F31 93 0 R /F34 5 0 R /F37 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 183 0 obj << /Length 184 0 R /Filter /FlateDecode >> stream xXK6ҿ࣌F&{(I"m/۠EV殕V<;|ɒM{]`5ESo^ +'x% j䇛'^biW7wMn0:Ddίvg/E)Pxxjokjq=HcN=ݍM5mST$/.q+[Eݙa6&,k"O_7L׵ cc.LHN0h$, ;a$!!aMf`[Edfz5Ji3M@)TU귶m>&414kym+}7KvfUcx/wٳʥDDX{vٌ ~mK_uS՟͌$d p0@]0C  !%*vO{tcLHi�+YX:e JxKm9!;s~P""i^m琀٫[qnJ8S!1TaytˌDqZ@rY()7p\6�|TWSp%}WddGBiLhljvmg6vM{grW Q%W1NYEfl ɂ-0M ?`y~z1B'j%9‘jO=D60E ^πu(9D6kτ AbpL.2 ēw* 9kgDZUPeSjB�CS ecvث< а-ޠܻc-rpuoʇiMG{S3V>(`13nNB:[i*kzAfhsƢ_-0;g9"z804"wn:`[R)<K,-&P1\c=B29VHAJ܅5\Aʕ2j\bSh< `nt- KT1th%~I%}P Ћ e&*~ێ֧E`z5p莚Ul ͬ+9 WZ܎$#.WLi L@|D9Y5=9\UrZ.a/<hۋ[̢9$ʰ ߰*ϒ1 _Av8 =SēS*BFt 5/Иҥx.$?b $Z3~>[-ў{|" #*VbMڑFjN4lRb>0ݩijgU`tSNU ;m.HrAA). AeNBEڬst RwAZ)@k0 yJ?9emNA<4(|qFBKf0&LS1ĝ8)<F x|B6:{4ZH1ϙbdS7Ň1�pVc|L<_$tדxw~qFgq CαMmΓTjV+,/w?fJ>OU?RFBÄY%h4\%O DSRonՎ:mK"\%sd?9Ӹ[g$LǑ0 k׎&5w}DtK0 ("oK'/n 6endstream endobj 184 0 obj 1780 endobj 182 0 obj << /Type /Page /Contents 183 0 R /Resources 181 0 R /MediaBox [0 0 595.273 841.887] /Parent 168 0 R >> endobj 181 0 obj << /Font << /F15 7 0 R /F35 43 0 R /F30 42 0 R /F24 5 0 R /F37 5 0 R /F28 86 0 R /F27 77 0 R /F36 6 0 R >> /ProcSet [ /PDF /Text ] >> endobj 187 0 obj << /Length 188 0 R /Filter /FlateDecode >> stream xYIsF 7*}JS29T!< d5F`Ʃoɬ T µ(f_'w> Y0C8S>N4al\2VR5/t='`8Εd8=yps8_j4ò-鮚Ǖc|_gtn>3!W]U9,5&oqE]vIbL$RS%!̈T0[,HD]UDZ`F|䷪:@`h}"}< F3HCjQ-fCKllw`6ly�/wm*4մz7bƋ$ d\J8| JbB(l㳮m!t/g]m]|LCqi/ә"CA}ۧje]/�%~I AV+jժ "1F6Qұ*h;]n}Y= DŽKɱ*߆\ŋ] N"Avz z]1/ Ӗ,:vYN=o󐹾h)'X˚TfjM  b1&Thk/$bȶ Gʩ]@! o"D7kޝ%]%$,ɌBYRxVHJ=:bɈ2L}uieFA dR3j5]ۅJ(yz}+g:v|Srh㟓x\$GcB1B;ҥ*PɅ qX*Afdl6: \pey%`L)]V%t"�'2ZG*S^D/\F PC8P}rnjDhOsF2#LlQWkԖR+M=4<Ã,8異:Z I Pn[I50 (CFE?>|բ8"BUȡΫV5Q8c~2H;B{Ncq ]gI=~7~~ ~ ?Uݘ0DO`5 j5Dp1*@0:(bþ- ~E ߯Īԗ6ΤY(U�`@\T+Cb. F//qaa[DGDHPCN%$d&$MBzJBF)ݪNJ?߸hk7Z4ޯU=VIU3ǝ?c\xmnPs=xYi<;u fcq4uY*#^k&\0Vvgܷ ( f +*>zoKΧ:ȺrTIXt7&CrϻI.qʼ5^gŕn660‰fyMp͂xz DD[QLU&7]^gendstream endobj 188 0 obj 1548 endobj 186 0 obj << /Type /Page /Contents 187 0 R /Resources 185 0 R /MediaBox [0 0 595.273 841.887] /Parent 168 0 R >> endobj 185 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F35 43 0 R /F37 5 0 R /F24 5 0 R /F1 107 0 R /F30 42 0 R /F27 77 0 R /F31 93 0 R /F25 87 0 R >> /ProcSet [ /PDF /Text ] >> endobj 191 0 obj << /Length 192 0 R /Filter /FlateDecode >> stream xYYFξί#:}�AX`!@601ɱD1{T뺚-(24_*b|w{,$B]icg?w˕Ytx)EogjjT04oMtbH'-a&q�!ci]v-`" "mn6yGx+z&DwKz~?8-h#+QRE)ア-+؂;]k槆Z7E)7T+\I.>23%l"]Xݫh2.&0 ڊ2A1ɲ'"|Dr/Ddƒe%dJ?3v:dz^Q%F XK;-7OqPPI 57LIb1Vc(.bqwÒ[jN ~a q%F%Ei$II*IdzA/_ <a8J6̘9=@O;pKИ8\JcxFЎ_�Wa[XfpaWյf}>#/3ug8h+,tds&'"-6|(%6bO[v=b&<]5|ySWO<|'(eHw>S/cXec>10ӋU:'xW{qO| C=1M-Eqd&r uOSg< )/P"{vt&i=V6TA~) =Y<?juHk̚Kp#[V|pͭʦu-%w\Ar1.lʹ3rO:jcrzLJol6"ЬZruq7>3| uvy%$vM]Ul:b ptF(WcM*sѷ^p3nl`p j8ٺ>C#`-CŹrI%LDtǗY[`Re|_ES^]$ 2ͮMHhBאַ6۲*Š }W٫c g)%\1b\S'7Q\96!lz"l#X9Fp:"uVqY͊5>u[fs|~Ʈ6'GNtoNcw[+*RUw=u8xi04?�=2[WJp)@|:?N0Y`SdA҈M9xm j`TGiſwEiӌڳ=fM)?Yvʍejw-Y%,=dmQػ״u yOt8i[5|LL^C?(w;xmtThʵw{~)e`[pL꼋~KBQXvF"?2OVpmk 3s A+h\/3#W,}X ;!sNH!]}{vJH"i}t^H:XM|Of*gqd_(@uE9MFeЩuViBOe@_9 sFc"(&U`=ڈweߴipj3g0`RwbjJ ^}mI I^|TّWz仇mq`qiQ|Q[yơ`SrtZGZ eI$c{>N5rb:8wvhzs=ZU(DUd9%l B__b ˀѰ"+ѐ^ qX2q"nP(7SO.fg6fRy9*p8FEo@AV>lâavZ4bOK4M2s *�5좎�x@ nO6)n(endstream endobj 192 0 obj 2077 endobj 190 0 obj << /Type /Page /Contents 191 0 R /Resources 189 0 R /MediaBox [0 0 595.273 841.887] /Parent 193 0 R >> endobj 189 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F35 43 0 R /F24 5 0 R /F1 107 0 R /F25 87 0 R /F30 42 0 R /F28 86 0 R /F31 93 0 R /F27 77 0 R >> /ProcSet [ /PDF /Text ] >> endobj 196 0 obj << /Length 197 0 R /Filter /FlateDecode >> stream xX[Dy}<E DPhY$"{Ι/mA(˙3g;a KdDh*"TW]_=TJ%;Gz#&mé+#Tzb uZ/V^#&LZKBc\`ۘp7 Ăt͉::4@f(!ݚkX͗tIa[K1HxFY$R'am$J2[1BU,<̟dO2'' fjmMUgi7L€QCE2TNFZ3yc~jOuk*} Li}Zj%xz:t@ncX;{2Dd]nwK/^ɫ1<8<+r/ 1+pܫ-2.;L&}UQׇ[^cJtЪ ىUyהAQJqm߉JE![Zg` ҍb֎%G;dv!7p>x\ AJ H>ŤW'|dc5QL/Y3 5r˂ٹpi/䍣"pߞѮ>j<<al62}88O*42n"<E\5DCϐ ˦, Q30[,_<dI=#zj;`Y԰I-Xӆ>˅FcjS; n2`8/D0& #G!Jc^FMMtԕ)ƙfE'p8#ZZww B@c}0}X+A@qƁ=T%%:51 \!<ؕ46PlLCLAҌL.RhdVbvԗdm9t̄ -4aG,=izT%>8O|b%�fiTؗr`*ьP&*4Ah1;Pql} #`b}1 L9O%~vK>)`CJWwOG|&n> Vu1\dˡ7T5U�Edad-~cŅ/խDo]Bt۝swqv QI2\p}" TJ �X%MXlhB؁2bO>.4 lY6`he$TqQBOqA7$Gg6"l4\60�|A d51ڻ%s&�$8bp,‘IBVKnv= UQwTۼox!!`\pP.Pp3/n0F/LMP tțˠDcHA!4EĕWOBty/CXE=B:o @DE﹠vp! v0\=έýψ"B)/rhbxDGЯG>rGswVm+ڳ�Wdׯ] @Ip/OKHr'm3 9 xj;?zZ7MyĿ*[(��lp#)cendstream endobj 197 0 obj 1650 endobj 195 0 obj << /Type /Page /Contents 196 0 R /Resources 194 0 R /MediaBox [0 0 595.273 841.887] /Parent 193 0 R >> endobj 194 0 obj << /Font << /F15 7 0 R /F24 5 0 R /F1 107 0 R /F37 5 0 R /F35 43 0 R /F27 77 0 R /F30 42 0 R /F31 93 0 R >> /ProcSet [ /PDF /Text ] >> endobj 200 0 obj << /Length 201 0 R /Filter /FlateDecode >> stream xXKs6#Ն�3CIЙzzi{%b#*Iﻋ$Ѣ4N:$žۅD_deɌIˋoɄ`1u\_.Yj]kMj廗o>:/fVجPqin$G(¾YJP,aZL*f 4iÚMk)`KzJ`VLhVx dSk5"DŒ,`-'t [ܩ-f–BJɄE%)v)X?-Uxh]W힌-fqC~?A-T Io^Qʀ3hI.^_^ $H |lYWg"VÞLOns7D|BRX+k2L�8+!GgGr(we#Z[nBCc*6!ZdI1~ŁdHPREM&V*2€@tAx|(0.ЭSM#yGblqL[gdsu :j2噏 ,X�طn͆v۵3:amVgrO0@V~3V_;VRLRiSZO 4j%fP);YzE/SAIUѣL/afSY,?VQK<1R /^ !2ԛs;*V&Xk=S 9G0NtMWftjMLJ XǑrޮuZRsb0vfL)GjzACs7@Q| ?}]B & d1:f]r  ~ M",[xuUlnL2L!AC:C\52{f*f Mw&qWFjCWAVEqkes*Y5<wz @&u?&AǗUht6t 122y~S $Mn}u7P 0|(,T1~ 9ܡP,TjEk;_dbod!ڔ2]D{no~${pa19`atp>\]ytvn 6,ܞ+[EziJ EZZV}ȎZ2ݔ]z>[Z@_CBCI=:^_M6p7IN-(qppCs\y3Qs>=p{3ܪriyOe &u@䡃AJX~<e,*lSބ6S¾Ldo L&ҬJí6StaIL%⨻&RDŽ|<�|kS61ӯa@Q?Pɡx Xw4(jPykjwMY$ 㨎.$N#o#[@ d5)>1 s!vAb�X,hT=H'�NisQЭi  DWy c'o*6fsC{ cKSB74��ԹO{Iw� .$endstream endobj 201 0 obj 1665 endobj 199 0 obj << /Type /Page /Contents 200 0 R /Resources 198 0 R /MediaBox [0 0 595.273 841.887] /Parent 193 0 R >> endobj 198 0 obj << /Font << /F15 7 0 R /F24 5 0 R /F1 107 0 R /F30 42 0 R /F25 87 0 R /F27 77 0 R /F37 5 0 R /F35 43 0 R /F36 6 0 R >> /ProcSet [ /PDF /Text ] >> endobj 204 0 obj << /Length 205 0 R /Filter /FlateDecode >> stream xVMo8ҿX~dFEZR i}ڒ5mX>"3o޼%~,a.MHֻ_Wg/.1bJVrus>[\xq VFߚ]&]7?M;ӻl;<inM]q~dZT{ un{UIY1ԭ3dL)UN�7M1ȉe,Z=_dDzN-H@p[zG;5mڗbSE?*q2v=5rMrʒC}W}@H/phbuHXIU"9Dl0c*Bid#!$B|SйO| {&%Fs�md,jPW<gÂ70hl0[7~Ww_P-b 9os"8 =T“ =H01̨v]29ձk:�͖}*kh5hYaP%7v_t].a4<DyfKF j7x*0=QHdMs&jwWɀ(M˙I ]Xdq.Z^ad'$z~^3<]V\ߗ":?^oz .Qa@{d(pft.C/"÷zAM?Kt!fu9z('0OkLXK}\m2C.a'fQa/s\^5}޺n_惟8Oѧ{(Xe0O#ۦ?>�M:|~ 0˃IJ0NDPC%V7F:)raajH9ajZBpf *TXщ zz[q5 F++uP+ <D, +I%%9}C$+KK__Rendstream endobj 205 0 obj 1040 endobj 203 0 obj << /Type /Page /Contents 204 0 R /Resources 202 0 R /MediaBox [0 0 595.273 841.887] /Parent 193 0 R >> endobj 202 0 obj << /Font << /F30 42 0 R /F15 7 0 R /F35 43 0 R /F28 86 0 R /F24 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 208 0 obj << /Length 209 0 R /Filter /FlateDecode >> stream xڍOO0 9vxc'G7 M⏄O۬*^c/9\�=WMuDU]smYV^j-!Ӌ#quܸ< h@dl/ A;)O89!ɒf=$ :e`ol`{_h' F`D1wo2)nM*1dv4t u G a 70 Qʲ8dfHҰ?"dE"ơ+4`QH%SV#oendstream endobj 209 0 obj 300 endobj 207 0 obj << /Type /Page /Contents 208 0 R /Resources 206 0 R /MediaBox [0 0 595.273 841.887] /Parent 193 0 R >> endobj 206 0 obj << /Font << /F35 43 0 R /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 212 0 obj << /Length 213 0 R /Filter /FlateDecode >> stream x3T0�BCcC#=##cKS=SS\..}7CSCC=KSS4ʐh  /..�~/ endstream endobj 213 0 obj 65 endobj 211 0 obj << /Type /Page /Contents 212 0 R /Resources 210 0 R /MediaBox [0 0 595.273 841.887] /Parent 193 0 R >> endobj 210 0 obj << /Font << /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 216 0 obj << /Length 217 0 R /Filter /FlateDecode >> stream xڭWKoFٗ{)x+{Iv)4@tH-2(:izt$wv|;3E- %VB1N)ٓk &6zaVqK=s 6*a \Ϭ(m n/8ʂ¤As%UñZd-fV1SQh\nbvup6:O538lus:>H_jU4M1R8)w2Fiz\r{ֺq;u~t!CC<ؑY%-ןeȝ-٭\Rޥv-y\n2lX^#Xd&>y:9}xٍ.ibo!A.I�ՄDAI :aM謢#.xDW&t@T,gSD@_1?ah"a/Y)2{(_> y7͡9a3P1&yqD*$|O&ruƱh.S- [u-" 68oQz(ղ~^YyY^͈_f4V6Fȁ/ðBuXto|>ńe�h; N**xؚ SW$@f580 NwG"i O}/đ>9*"i,V]I)vKdЬ#̀1D,|뷎;S<y^iar8AڔNWq}E<r]'9¬&&DC(Whz?l sB<xN(!6J\l>?M;B^ Ԑ(^OF<<6cK41(�u 6z'tq]2!G6Qf j ҅iCxd Ԅe5ʶqzB`txcs=%6#Wx abT C4L}Ę>*7$O|]^LDWLe):e]Ɨ,8dapECOJS&=r.}Yy{%]Z8 }*Θ&{JCd\*Cr%ܚbh3$n9YqNy@~WÚV~iDcB062aF @nm 0PQRO!Y%A2bǾ=(Lk rsLd -@e Kb\9dܓI9}AJ* #RY.>ITA.!#& i& 1z&]EM"pk׌Q~aM<51 0WYA� ➪$P̈VѦ?hJ9&9BOu܎)ӻendstream endobj 217 0 obj 1419 endobj 215 0 obj << /Type /Page /Contents 216 0 R /Resources 214 0 R /MediaBox [0 0 595.273 841.887] /Parent 218 0 R >> endobj 214 0 obj << /Font << /F23 5 0 R /F15 7 0 R /F34 5 0 R /F35 43 0 R /F30 42 0 R /F27 77 0 R >> /ProcSet [ /PDF /Text ] >> endobj 221 0 obj << /Length 222 0 R /Filter /FlateDecode >> stream xڕXKFNr%t[ :wA8MD8¡(DNHj<[/q$[+U?J0WwT(%nfC0YdqeӚim߭8GӹouOtVDj8)ŸXT&%D0X \%pCSN3 F8M׹mwƮ^m8r!Ԯ]o2N�.f QԹ_%Dk2a~C3|dϹ>]q{ߗ'Y3qocntRU۫qm]P )q%Afu2+)yASނ/]o$ջ"'4:'laqNM۸L=>#PD*61Q)<[! ܰpӱ2k]t8pHM c3dAn ,ǦkӕW޿cf-T PZmLl쎠C[ !B1!�IjN*t, Xws]UrZٌ/! D\0) )=KGvC5d|Vw81oWC}]5D/\ o "%Ѯn&&WpE `'p>귘E�6၀[%Cr 0M*гyЯ"ɤW4ƕ??xFGs5sܠ4L$n�7: 1ēzlJV/#bӭM"Ug}={zjg[kZ8܄(`Fڲ˲?`LkYp^K52,~et<qN !;~˾:$SbZ;X#}%]Bǚ} ]O`tvAptqw# $1~]= D`f=l/1vC�c6{q:?g y}_RC("$S:ܵ/.e 6Yf]->} j7S(}i﫺 *ɼ+\hl$&AJ6DgU10<2ΈܳS\Pzl~C1U Lb!i_Sc/.zaaoRt, q=)Rr(l i"0*�wH"rHD<GGDgܠ\/ GjPX9F{60r'w= X1xnlVɢXXUu -ϳo“hh@a #qǙ͌ :3X?xN$ɄOL{z[OjTFE~6A}bp`0.2|gɯaR o@}pI׵; ±ciA͟b\lq,Tk(<ʶϵx Xva@0~Qav( fWI;㸖P߭9p xAmM mHh2Ep=iIK.5i`<\ Lūר/, OX<<T5"pCSD-㧒(t[Amѩմ{ iHD`5G Sp}zg^T>Ϳ"1M‚ Zcؐ픮q"uu,{W-M20Ih;<9^d6 Am}=rs#=a {s,^a7Pq{#^Gݢ?^~BAMC Y1@iXweI/͂Iːo)XќJb"J}',s0[m6Ƹ r/>? ѕ`endstream endobj 222 0 obj 1965 endobj 220 0 obj << /Type /Page /Contents 221 0 R /Resources 219 0 R /MediaBox [0 0 595.273 841.887] /Parent 218 0 R >> endobj 219 0 obj << /Font << /F15 7 0 R /F35 43 0 R /F30 42 0 R /F25 87 0 R /F28 86 0 R /F27 77 0 R /F31 93 0 R /F34 5 0 R /F24 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 225 0 obj << /Length 226 0 R /Filter /FlateDecode >> stream xY[_=rk™\%օ0WD%rKQxю}p8{\s] MlrN_~}Ղrqq'?e0B/2}_7_msfme◫~}Ił"!<%cAae1 BgErkw"Obz{U˳}_v}8&X2ustև:ܬfQB "9> +#VmƦ\�cժogy󚷬'S9&}{h<еL 8~*'.T w.xS&o*, ͺ s"V9-ݥٵ)qeNb'ư\T=.y[E[O[v㶣0qmwK1sBh."|V=JIJ-o>q yx<A B3lB#j oRaN$y)xyG?U6(I2|f&T$A@# mUΤG rK7 s){whnރvU>t ݱ!#a|l@5Yͳ7ɳom_?E˻}չ7]p;Gcd%Hn!+_@C"EsZ7".#1#'.|,O/ TJ<2Q7kv1@{�Koc B~FUF~gyu"e[J Zʢj1: Ji^j,`.=D*nv<W۠L `CmWV/Ej4%Vc`2jz~hn7|JHk8̴KZs_衆( *Un3wMUwC2қ@z;TV?@B$Ca զ<l{2PM\ sv^hm|)RQ2xa.6H^\\azm,v])F^rI\e>|pNg ,su>%%w@PˣCJUnqIJ)b  18A d7΃%Ո9!"oUeI(rۜW=YNPӧ>AzC'7&#H:jٛOۡ+*91B-w2;i{E 76ǎi?ۨ1ڵ� ,gTZ�; ssG>!PG >BF5@=Ovkbm\I�8Zl.3@@wIO]2jHNh`U0Mgs5'blhzI]w]7w fG_M MبΗ)yBrJd/~uۿOJpj$Cm=fς}$?)/Da(}6cXhԚ'a/k&{vU.Ӛ Ilq-O r&A:ܵre#4w0K4Vڐ-W=N -9Uˇ2 ?zˏ}/."IT]_nf WĦ c0VN(e Kٵa6S!rK ~M ~̠@SQkzv&>x&@/'$APwU`<f,?N\dy U̹K{SЁ7xOif :$9<ژxYX_Q@&0IcDi FvQa_'qXTܽ~x 2N41N4QN4T Y N0gP$ǿFvE/Z:? b0'ӓNjZ_X`+[l :rkr3Aq[~#} >kiFuC31'ŠyDe* Tl~փvOWp|meA8{ '#vbeлGk٪Î|6ewLʡywrkvovuyMaqQ|xV-mpO1=3sKf{l#xό?B<OňD M. 1OJ.[P6I]wK/$\y[=+,Eb) l zAD*T 5s3䮘g QO2> gۧ|m8'{94*ܕ/�%B>]^pځ &>qY"~v.hfG椀6WRUg;g)f>ǙJ<TL%L5 TゑkRP&Su?NEj&P2RJǪk:endstream endobj 226 0 obj 2452 endobj 224 0 obj << /Type /Page /Contents 225 0 R /Resources 223 0 R /MediaBox [0 0 595.273 841.887] /Parent 218 0 R >> endobj 223 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F24 5 0 R /F25 87 0 R /F27 77 0 R /F30 42 0 R /F35 43 0 R /F31 93 0 R /F1 107 0 R /F28 86 0 R /F26 94 0 R >> /ProcSet [ /PDF /Text ] >> endobj 229 0 obj << /Length 230 0 R /Filter /FlateDecode >> stream xZ[n_7@7>rQs¹()h@S\H䆤Q4v׻qGsw'9 9'B DJ曋g_\`4liI__w/0}X ?<ws&gsy"[rؘ!MGvaHRdÏTD#-Lr &fa8evL1v@T}7W b H0b|/ސ ΀2 al7ei\|3) ѹN0C9I(Ԗ<`A"ˌ!#+J4L1Ǒd=Y{YG. PwY7{KHキœ2>Diqzri ,G4 =�l"m"�r++( }&#w3`i"2B9@ՑaPs'%g@(8DJa-4"O!| B) qo!H83C>c+ag>z\#`o0@}#<7<b*Žj_(li36ة33~kfu_TW~][,*J{3"f<w|C! ֍шiS#Ҕ!%bQa/# d$( dNo,d -jT�OV8֜VDT;!"be>s#Fy4$!¿)Fx�&0 )T1k5xs }<e0{Uhn^y^Yp;_7]Tu1EݼBI!&1%Ł rcDySp 8q3w*a!1j- UJd(W*Ǡ9 N_@Ct|8G{8abɘOe�(ICfZi[j^�=iZnud预!(Cח7Fs$<<)^38vU gܚn/!=r[?M튮fQ)r^cV.ܤkV?nmVG8~Du%> P1@v &dy =hB!!L5>3R \*JN1 {flڍK>mK0Osn_Kdp&{v/1֟>MojnrmK_tr5'c]$9 zkyWp&ow,׵͚$}Ǫ~RS$c]*G ͺz֡8clơsỞ!Qܬ6e2"dh#<Jmg�%:ݘ]M iE.4w1sߝt:o67o[ȖDjrKݑPE�EQԋpت |ýÑn΃ xqܖڻ!2ȒQ!l54UN8uM ^t"cq5KL욢|+򕫡/ i_bz=o;S^/c96ezH=MۖV艴1$4Y-[8ѡNCqH� M@ac  \3lUZ.,Edmu XCP/" 0 'cnoݬm=@,.#ĔE?@@S ;w�oڅ鋎v~p� LJqQ|$Z@A[NY%giޖcRxZ 9*etF9`M^ @ o&aIDͼٸWDrxőGA?�,?ӑVv=lw]E#233UT(4ӕ5sv{li#aane`pQJ(,ü�us8` Z0)'VH �/*$zjL(sc^ NSH#/r'%%7Mφκm ЏWn6Tmu\1w7m۴V<1/(rfMBy,;P<fpV:8)4߶FD� miF}nB L^(>o]nߕ oߤ7_دwW|�|+e餐ݧyKwS܍yu܎"!%�z/%243:)d|W>?o:X{ JۻH]j^ʻ7rMNendstream endobj 230 0 obj 2309 endobj 228 0 obj << /Type /Page /Contents 229 0 R /Resources 227 0 R /MediaBox [0 0 595.273 841.887] /Parent 218 0 R >> endobj 227 0 obj << /Font << /F24 5 0 R /F15 7 0 R /F25 87 0 R /F1 107 0 R /F28 86 0 R /F26 94 0 R /F27 77 0 R /F30 42 0 R /F38 163 0 R /F31 93 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 233 0 obj << /Length 234 0 R /Filter /FlateDecode >> stream xZox}CoQ/#~S) Ar$-P@wWWg}gHJ+^|Ep7Cr"?0d-t S|ڽWXPrqvWſmsYr[^,ɦ͋cL2/sWq\2FRoof _IFfISIkWng~ovnCcЇ$0@cDZ] %JQAJ]_ hJ ۖ.H,Klw#3 4F0�)ء:ο _/?PS7O)u9p++Ss&lkoo'_}%g/^^4f4) KEk4HQ3:3^m,4ɴӈaL;2'H2h~JeX9Am&)L"XPO/b�OCRͷˁeI﫪߯*("5")7# HmD'pa4ZYY\lO{xd635jz2GUUOX cLR&C'0 dChO @3W|Y$f,N C>=2օs2ā7FYR& � 4͆(p FއA({4ઇTq'o h?3Ј-UK4;y9SۜǏizf)ty6$gvaDV182C$7mB?G�P=�XFaQrXp<#`u^͉G'~?5m $Ԇڐ=)4g~Hh|H8.Œ*[KJLƍ2?o_ RbEx{q9p֚KIԧ15{~?2 uW"ZG0 h0`(xMWLW቙N:#\f CO홤;Pֿ<&_I2TRLs<3=x"�oc<mp_8DjlmkcM|.R?@0,G|<Am  � ~/mC}Ӥnz8tjT| ÌmM%f=#._z۲vߕU Llʏjr hؤRJg$<€"_"C1gGĎ^S"jSB:ؕNVjb";ijHEDdu8uoו}kWeW654(`Ws*%X@5tfdgm|@YUo:Fawm6m"X`v}mozϻ S2F^G<dqv=G@NngÍ>osP|D r[ur%D#B r+e¤吷E V`:~-R%@_uI[H;m?`Z: W.'#Gr\l@JQ曦ƛAmw2uWK1.St\ <T}J.Fw{nWy,X rĕZX-5'XM>Z88$:`>B*4V>\‰HVʶJ@qn Xe^w~<{욝 /a fvyVqWLj eH crRsQ, w d)aw/Bm.WÐ9j M3ƹ7(uַ&YGYG-UBϋ.43n37> P %nn2 L9ٹcDLp ^T֣6H<txU0H uP][]l7\ź*! , }\Γd1Op 9mSD&oGtm~ Dމ[v0ϳϙ&`L={PȦi~<4\VE|d�,[(޹N6! eYyЍ[2hLGl2<} EwsptBid˨Jc稴'_l!*. _ƪ?<tv}� Z8h?fba2K, Ѽ�CБeiGۼ@ <W`Nury}U:|EPW Byy<'>Uq|ɰJa`Iʺ/p 1jI�4ך0<qޯ�+dj`DR=EõkסM<鮚*,.о߅om<�Ӡ%,) b5>3Pq*\>2]r>No<&)%veA2*@|E~젅* ^FNj8.ﮋ1G9 991j9F¼?>R<g9˶9`s˵RqolV1:% *A< ?Xҳ)2~fûTIqلi6lBm4#W+ چp $pFendstream endobj 234 0 obj 2622 endobj 232 0 obj << /Type /Page /Contents 233 0 R /Resources 231 0 R /MediaBox [0 0 595.273 841.887] /Parent 218 0 R >> endobj 231 0 obj << /Font << /F24 5 0 R /F15 7 0 R /F27 77 0 R /F28 86 0 R /F30 42 0 R /F25 87 0 R /F35 43 0 R /F31 93 0 R /F37 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 237 0 obj << /Length 238 0 R /Filter /FlateDecode >> stream xY_oO QTH"uE wAZ878 )yh}g4VڥC`Ҋp79 L:Ldrڜ<\OL0rc`2(z}"x΢oxM}sՂs+EcF|rykaHBh"adSm&_:>l /j}]Wۢqô5-;zuJD*,j$#HTsSͣKm?MM&nx[-rfMѷ:īhxﵵt+`ulKmrUfXmI]QKAD=<XƹS/+c'.5ډ;A B&1Qȧ _EuӴe!v"zo릪\ov:UQAp`]V=* ض#<cR QeȋW**{}IWH-(qf�N"e;rD8%ch*wfi88'*(ft́Y ӆ0I888LN $;-HdΩdZ _;BzΪV€ȣX&=(wNd2 /(۸åY@KJ8쟗g /Rθbvq}]|Yq 1>ϸL^ȡd{1J9X8@6ʔm]ͭaoLRpmyڂWL -8ԂHS91|CF<2v{Fb <K|Jh{ x) KPY!Ey> 8O4G' #S9>`_HaX$DM`n2ƹ|fOgX?*x?)=oYigѿ~xKۃ`킈 c΄C  *s\w}@L U'F>'d5ƻ;�* bA)5CzOl>fe~ҧ�& "Xdӓ=`Qjiᙁ$h}PHb]=g$0QQ0xІtqPK)_X8rPs&0rP^~r0hB񡗓&+=oVM]QUؗOoEͨVM{MDSp g=M*=Qhe\>-= 2eq+i+pʮw3VvL'93w^u+ΣXI~xW"wo{ۺeM徟)]Dnћ>ól&LRr[j�Cr-TzTCu 7PE5)=jή7DelnYzϿQ~3:eS;'[DMybw2-}cˆe*nj.VX\%@ӛZ{gvd7oZ4GW܂kwG mmܨN�R(m i~}yj{.!vZW3ʢ-6<]U/D3mQ+/yu@ s0/݃rzd(iI[C-] q?qFj$ ʫҧJ.sD<sE0et�*dS�aSC Y@u;lk땻\2bb׀ԁ̀hnՖ }+xCd/}v+7vՌnhНZ;@iBy>z ዏUx'w:oVCm l':aeW݅!Od~ w/kn"ñ$c AN5 Bٹ`Ca) *x:cT@ElqE$ZO&zOa7͓(]X7}Uف=N ;k}4~e VnW7ۂ.S1;dSj[`* -zTG<*{V1ـqRtL,uQ媨7![puRҋ-斖h?x:1Rn0B0c()ԟ)endstream endobj 238 0 obj 2143 endobj 236 0 obj << /Type /Page /Contents 237 0 R /Resources 235 0 R /MediaBox [0 0 595.273 841.887] /Parent 218 0 R >> endobj 235 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F36 6 0 R /F24 5 0 R /F31 93 0 R /F25 87 0 R /F28 86 0 R /F27 77 0 R /F30 42 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 241 0 obj << /Length 242 0 R /Filter /FlateDecode >> stream xڕWY6}[} ):@h2m %WPMPx 93ߜ1,KeK&y.ެ/^dz*\o=zg2bɹuq8~0oV\_rXk:)K>Wem!Eu,$hӾ%VGPo+764lmkTUw(1*E2-Ln "W:]MߒmN08Uq@=[,QH.:56}ޅ-}v "D>sY5t%-͑$ґLl]2ca'D|` Qȝ7Q'S6<f EK2R#mx{1\MaoJ2Rh&6^-j8bV)-{~!z)jh@ BbeFbP H%9NH4�tV,_jW:Kn_ݑV @qdٲcgHy0?mM$@j_Ii'X!lZZڇ1hPąIp"23@ @b·ԓ\ E`oX# d`96r b CiV�//Wч?盰޿\g<Ze X @qf"550HmcAMB)DZ4ٷ iXx\5N+Β1V$Tf3V4"۶PܠqAįgE.ikqHwk[*4y�,I~;Dn()5`= 7UlY>,f`:"A| 5>)å̠6z=ޕ3 sI1 ꡳs̆Hj>|NYzl^~wgtaR*/ؙ0J}moclstT2*R Mc&7ôLe"3x,z{FhdrswFd `h_P`Xض-@u W"p c&$ YW7]˺0CQB",9C"]}ɽ["Ub>vš׆ Tg{6Ptm-]CbsݲE&*!r|UL'}SPi�: 0 ө Uȵ4t6A28=UbS)q.|FD3%x n{j16En0A~KY&xHEsK�oh 8C#;a3JY" b#Îv4f5HC#RjxcT4nm@"Z<WqDqaI9ZOS1|=ן+.f9-Xs xѡ[G 3m 2 A<1 h`IEB( 洫*㉮dOzkfV9,K@ $^e=YУIz`"?y~z;5b yphyz|TѾB@ %dQی^'`\4{npa.9 1JN ή1sN ^&w"^ ?F!wf:,[{*9�,Mƌ^Ykܺxgfendstream endobj 242 0 obj 1694 endobj 240 0 obj << /Type /Page /Contents 241 0 R /Resources 239 0 R /MediaBox [0 0 595.273 841.887] /Parent 243 0 R >> endobj 239 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F27 77 0 R /F35 43 0 R /F34 5 0 R /F31 93 0 R /F25 87 0 R /F28 86 0 R /F30 42 0 R >> /ProcSet [ /PDF /Text ] >> endobj 246 0 obj << /Length 247 0 R /Filter /FlateDecode >> stream xZKy97">d=|I1#b:ځ׿>_u3dsIi(ÙzW#b$bIF_o}Hhқׅc /l޴TNt1GǴ777?|R2&+d_ŻU=tOZgرeΰti%i\Nf=.Qp5H,/6yHIXXůSԫ~;m #X1,.4:37|SK_4dib褨I5'ΚU;(2x5Uьq5ilPyJ\_rSBW,!G.WBR &r&g^ KzPcY#qs $"{?2l|2;g268dM+/w0R3oG[Fzg?ȗ9"Hw(2Yll=_)/WOzҢ*yJX( [*QJ:Gm]*_R r^d&w> kԥ\UŊ4Eƥ6hb5z,s τv+ۮ3Ed@dr&h4�ΌCE0.5-DvߤH.a2.Z*vĞz|ێrB'RGg"o{ra p>ֽC-]lV:mo rkWJDTˠ�]cɴ M2 0)b t+Q$ED0UgW�?Z5+rLW{`z$yzh㶘,G" Y+jyƽw4Q7$ 8qTטHTg<g늋K"}b/Axsz{QHdXcG~`"՗ù2;)Z⏙gcCDI1ےaF*౰BTlb{YP#zB}m}MإAbI7V\L6>J4.dmyXF(:>UoYJwUz\!dt�j;|G<G: -8nrT^vqO KqkEfwfż|U/qzŬ)wo2[VNMqԩݢtna`>RJa;)aDM߄źRvvϝv?}#=ׁmz:3 'bn,W<J*SLFvvx9CH8?pi~ rk8. Op>LR?Kw\33cT{Sbv"#C'̛Qv\G?El{Lsdgېz ۖ_W*<�H|կ|K#Te"TSw�]~ eg}'jxri<KE餽31j(퇌 $٣(=g;&<ne}ϸC/` T"|IRT#hOl_ɠC($FN/5EYchð~=kT82iP1\X.<kwDRF?) <k\?ZУG#ȻƲ_>5fhXGov U\m6-b]| s~s\6l5T4l`02_ g+WW֝G\~݁&o5̣F\"Q2|hu$P(ÇX;Sz~g6\x뿔?@Va*Q<rCi$W@Mf'D.�w1ݱ>l\PU3$rr�2L ]j;Eѥ?IP,F$Οn$pm >dWC'QcN;)ۚVjVfO0͈0tP%]XIf4q=}شڤNh/ƥUiEآ$V L _> +3.qG"݄!n*Y%B;Lm[̅6];HisB�u̸ɾgY5 /F]5oendstream endobj 247 0 obj 2219 endobj 245 0 obj << /Type /Page /Contents 246 0 R /Resources 244 0 R /MediaBox [0 0 595.273 841.887] /Parent 243 0 R >> endobj 244 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F35 43 0 R /F36 6 0 R /F27 77 0 R /F25 87 0 R /F30 42 0 R /F24 5 0 R /F1 107 0 R /F31 93 0 R >> /ProcSet [ /PDF /Text ] >> endobj 250 0 obj << /Length 251 0 R /Filter /FlateDecode >> stream xڍQj0+tўk)JK[4^j)ݾC)-3z�](t)SM̓krPy5Tqv )CƑ~ xJ)cOD~N@UN}u)wL5wvLQ�~_^ &Nܢ1B?vMMcI65(噤Fhl.5.In\V-ؖx~<!Xz9X0_4a}lVQf2<Xׇ3ftb1TA~XJnT:endstream endobj 251 0 obj 326 endobj 249 0 obj << /Type /Page /Contents 250 0 R /Resources 248 0 R /MediaBox [0 0 595.273 841.887] /Parent 243 0 R >> endobj 248 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 254 0 obj << /Length 255 0 R /Filter /FlateDecode >> stream x3T0�BCcC#=##cKS=SS\..}7CSCC=KSS4ʐh S /..�~9 endstream endobj 255 0 obj 65 endobj 253 0 obj << /Type /Page /Contents 254 0 R /Resources 252 0 R /MediaBox [0 0 595.273 841.887] /Parent 243 0 R >> endobj 252 0 obj << /Font << /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 258 0 obj << /Length 259 0 R /Filter /FlateDecode >> stream xڕWKoFҿ 6e"R m:8Hr%"J.I3KQ-]0`.w)'WA©SKVջ՛kWpj{9/C0Vzgam6VpeCdkRu*Ǻkd}s-J6kIƂaQ`,Q&}5^xwplWO}k`}\[ʺ)o[~X$k񫊮ɍ4M=EyֵU:DGtˆ`ee_E_ou쏶y!}fVǎx ˾"4 $m'T5/mwXe/LW=MCۨ 5cOǗpDV#f_mVs%s|hYrR~fפۄ7�SQPc]tRXw -y'#phg*ؐJg*PE<V,1ZXD8&:~ƇgG0R -<P':pOUqH|_4-%FK_\IILӍ]ߝ+P^G$rV�5+B9s#tNʕ%ۿ /@t 9\#Ek�M|j9> X>�`bۮIdƝa4bh+bK/4 ڼ?pa[>5^|5J_𫑨UI5N2j�"` {9w Pҝ=6- Os-?5D:ޤ~^p'EŷPx)^MQׇ2=<`DoI!fpA[=|<2EKT^%e"}Dir XYI\sʖXc*!"Jroӿ䲃j2z[m}ƅ9vMӠdKSH3CxD+e4 ->,nrĘn `]\9Z{ szLڧ9U~=%.'͂eR&1~I5/ϋIN9q*\Fv0 c Qy;P/S}Z*h_hGj2Gq_>m^#xyHeu^{&SQJo.QtȲ::3QSDp~`쉘(xI铡z R$s]d\SA04LIR^g5`C[~1&T]k{S {Yue,*rm8֤%{$9n]$B1@w0Wendstream endobj 259 0 obj 1302 endobj 257 0 obj << /Type /Page /Contents 258 0 R /Resources 256 0 R /MediaBox [0 0 595.273 841.887] /Parent 243 0 R >> endobj 256 0 obj << /Font << /F23 5 0 R /F15 7 0 R /F34 5 0 R /F27 77 0 R /F37 5 0 R /F35 43 0 R /F30 42 0 R >> /ProcSet [ /PDF /Text ] >> endobj 262 0 obj << /Length 263 0 R /Filter /FlateDecode >> stream xڵX͏os7eẗdEvr,# $yӿ|$-yhϤbc}预tA%\.9a/7orA)R.~~W/WB+u9aCA.TR|:˟nǸ"ԘG\1#qAnrB:.tIȘЮǦkݗ/KbbE5'I$L $T# B4mFDIeD$ "֖�%d߷c/W\٢r?XW=N]f_m*} zleiTi;ޙP #|[oޙu%ZGݟ 'P%3ӒÉܲԳ\;oŦ˩5IK?S(1<8~wT(qhaցd2*z}z%ec[1}׵9c<wm׮p~`ΐukݮkH570^ {_sgV6}s '1|<:6 H_BKg1$:w>R70=[6�S cՏM+>5 .D~pAR^|90}a'iтKn�.ylA$l=~э9"CdK9H}|9;CcI8pJd`j(>e]7u.p$)ídI5t#ʑ{&CbT3igִ?4m,*ޏp:G|nR8D'`/bB()aD)Et!=4) Lja03f6m36ˬLJ{킐¥W}J0 !g ^u-i-EOfKHT++aJ_;)7HG*u9|@ f=~ՌsjL-W]%'摵"T8,yb|8@C3(%%bBp t{ŋu.9-S=qܩ,6JR@pB/ą >!D3c?5\PrBhm'rex41N͹2(,sF!&Fz<(®Cd`wB=Bh',/4ʀ($B&Um߅BRrIs̾:|N Q`r_ ) :qMXë́d$ "%b|H"\D F6,C֦~�Z\@KG{cJ)/Bv0DYb{Cc(5ԺXW`NWzW/ToVsX1HFaaT^tyx*Ug,a: HHò\�K Ղ)qg ׅ<%!9QCIM[P!!VzxQed6 P߆(47a.kt" 0gX *6 ԶyxBۗ qmiYf(pЛ'K>Rݷ0]:a@U6$H=4 힛@],bZTav/Iu@wC 9CU{1u= Up57<VcfҒgۆ~ 猐F]4vq7T z!M$>KWFd48ZL(sH:u!@Gѧsk(ɂWEH�})0oDƋ=A'3E.?TU+9Ne7abSuL0~O_BKT9.AsxԀ. 鶕 Y*"řҒTy-ZT}wsJ9nubuZĐΔ[w:?<y_]uEX]Gh ACkwD^`+v_v1wQ{/-wMWR/-FJ[Qelh Vendstream endobj 263 0 obj 2024 endobj 261 0 obj << /Type /Page /Contents 262 0 R /Resources 260 0 R /MediaBox [0 0 595.273 841.887] /Parent 243 0 R >> endobj 260 0 obj << /Font << /F15 7 0 R /F35 43 0 R /F30 42 0 R /F37 5 0 R /F27 77 0 R /F25 87 0 R /F31 93 0 R >> /ProcSet [ /PDF /Text ] >> endobj 266 0 obj << /Length 267 0 R /Filter /FlateDecode >> stream xYKoFN>tp}H$@CFZED$R!-MC`\gΌ?<q':~=|1ҜO G9X5%{/a& (=k\ Y uۯfaگnf3~7a\O<7"Aς & P;!�ؓb7)I$?a|�+R; J#=CJ21ǧg 3Q8"`J*5wDOR(T�#@KRw CR 7E]]L0U8sZ 6 ?&,pa7F-G�ԞTN(b c@ "{'+r$'@ $ 6]F']~n Uʬ_,`Pg8Ur[Ϟ/>9޸e/iΦhvs9󽽤?Ҵ&LdIFJA1!MYlErphwUprVf'd63mk:(w5qifz7|�}^LSi'1>B8;ee#Qyf_ �X7..VUixZGaҕ8-U_^[]!AnۙﺶTۮwG(vf\F<\.�뫫*W6Pgպ8P U&w `^?.zì\ sqco) Hc>))˲_^U"^WUۚ~~&L,ք%ӶMXt7޹ 1(-uJ?xߧdĐQE›D҄Cpٶm<)gE(qWMsS[p8#ۻgMgƩGQ^m[Mqkg̻d_=}MEŐj0,|Sp]%(OU.u9 ~Cp .pWmNŠ& c²AB\#:d 4A rWlw @pHU ޴+6%]eXzKM247u2jxԫ6e빛a:tS~_}Uw fB^u_C~p2܎{М nشgG##v͛#¢;? ?HR*AQ{R"�2M %vNv rVh"ќ^ }ȿ;<Tw>Af)ژq~]/r|Je݇h?>O2mjꨩ(/M͖Q\'[Wc b_ʞpwYThpDGlU'qzWvWPm^X\:L+zX֏Qw5$Yz1Wȓ})ܴ(M.j@jzS2J]bI]Uof9f -|/]iח~Va܄J=O M;VuQIWI;"׉p2m͛RkkEz*Z(Xy8TҌٌXn׍nmLȦ D[z"js)n)#U(�NTsؚ]helcsjGUZ^*復Jn;ծ�bco?&945IHm C1 -eN `&%|G[@%ģ ?I ":$W f{Z)_�wendstream endobj 267 0 obj 1814 endobj 265 0 obj << /Type /Page /Contents 266 0 R /Resources 264 0 R /MediaBox [0 0 595.273 841.887] /Parent 268 0 R >> endobj 264 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F30 42 0 R /F25 87 0 R /F31 93 0 R /F35 43 0 R /F34 5 0 R /F28 86 0 R /F24 5 0 R /F37 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 271 0 obj << /Length 272 0 R /Filter /FlateDecode >> stream xZIFN}9MG +623q e` ɁMQi&%=~^m\\X-_}U?2#!Lb`bs՗44ʊ.?'_]|5H^`Yۮl)<nKs%kɻs`glW_0ɚsB|eSs\J!hr"ɶqU}gW\[E. "Y/&wʍN#xGݥ|Y"0&FɁY7U~.glT5RJP&3ˁ7F#)Ao$5$�XA42a8MwG $|!#'JOSS*U\d[F1vcl74vQGĘAAk+Rsԧ >\�.eeVZ#fe' * d4V4@:-gi@3Qg�s@J$̥b yPfDe} ;- "XqqrqEFЈ3�?u7luE4I b2;E(r`PÛo(՗R]H 1Jp@vT{|@rt `9r�T &;6TL!N{ԋG{Rg'<)IzR~ O@+;g*�$N;dOfXYMϞ4KONY*#Ki$KGRzR>'G;/S(#I,)MG&LnAf4sVwXt_jo+6̾[;TQWɤM/ ,zkH-(= MDDɀY"AD-j�j2wqbCن o.&Pɲ~s7gAoxώT? Vc)<îʃ.MbT.@]]*y3M_ `\%Tur]2)0~8w ;QՔvpUIYTQ.>_4#f.ĥ P #)GOvSFzbbb@iD(0)¤z,LCӈOf?2}{i1f L~֐.sdb P"%k>aY$9nVfc0ѼhPmwu>ž Šmznf7n][`plEIR( Swǩ1F _A!ܮUm�HAF8ض|;:0 :Ca^2ͪ*xԉrauąG rNF B)gF6ewHҽp?PCX=Mfc|׽|c6p�c|[摐䵽fɵ~{coXS.{khخGdc5\-20XT .ed,` eŽ� Uh/roUnߍ}ri64SDrRM(GVp dWJDX@ &wKwa;ńs<fC䙻vI&`gxn8;<wr_OΚrȁ95mmuoPqC{öaC] RTAJAdq.Ja!3"v^ EeaG[ɾ-y&}˽;%6aȷղt/q+ lFP'wզ?~e أM?6p=?{O7^9"s+`(S5ͩ}{c]vt7VduiBBim+ңnƫc`D HXA>Ӧk} 0_OV7kV4 eP}7bDKMzibQ�>P`(A{`>FH{lR`,UMƜ{rbG w.}cH\D+P=̶1&Vmm`Lz$ 淲.J,)ꫡQh|oS7)1)UIY1x(e; ck2Mn4q47/td*CJ(L;d݅8 ^=v�oj`;dqOE? Lendstream endobj 272 0 obj 2203 endobj 270 0 obj << /Type /Page /Contents 271 0 R /Resources 269 0 R /MediaBox [0 0 595.273 841.887] /Parent 268 0 R >> endobj 269 0 obj << /Font << /F24 5 0 R /F15 7 0 R /F27 77 0 R /F25 87 0 R /F1 107 0 R /F28 86 0 R /F26 94 0 R /F30 42 0 R /F38 163 0 R /F31 93 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 275 0 obj << /Length 276 0 R /Filter /FlateDecode >> stream xڽɎվ�9[(8**x ΁-[HzU"EJe@X^}#CUlSNWPؑrrs!oJljYT6θɇl^Y9߿zG܌1Bf?-JR&j7N;|.s|ѣ`]<C`I83֛m/̶){\RQp7ꨣ-/:/+-dz Mц(_3)�m&XaQp#і{A\]\T#dN&FIJ5:]ѠRk^Y:,NCJ>DT'fb4Z RpS&aPPh@1'pE+ݣ\` .RDn2l+YFр=8bcei⤸U-d13Y5/Wɼg<f[S{)d{I:f,aQJ r7.r:/ڒ(0Dq9av]vP`,ƾ�f&]R։5SE1Q>9Sd$"p֌Y!VFRfٴe!㵸,\1c&2G,jJʪE]]M+PsV3{|fu !qU{lH[exobU7|(1}6_^od 9<DGt(@"`ys`ˢDs>.pP;pP.Epu}#"4M[d5"s}J.uW I7p�<CYO<!KH,u Ci#7l՟p]"9s_l_deznyB{ȟ65Xப;3 kHYGwGڮ$lr#weDlotBACk5#¦3JOb!?6XHv8l-}tw 4źXe5q"O_V)C 2wr�VW_LYo#< *1 O|v)Q7E(zBr>!gGLiw@}UrRggAExT?_Ձ _x3v"X#f\: t2u&Hn7LOb6*ݵo'\*9cta jyˆe�#tKKO  p6T+o"@%XGNYNiNt1ՀPS1A5ZH P3bC*@/K~֣ğJ=/*+ƍĸrr WlhqlwNw֖ $uabS+|`<�aڣ҄+62ϣXO՞U%3蓄 e J,n@zI8i|sSƥ?&UH10%>b_#ⴏ |DG5>O*<BJM,4|\:]ڽ:h?lP͇39(&86`:2co^%PMOY] /}ɼO A83:V/=7 PY>sADh~46FPܶYvEQ "Ltr%m(Qc~ Tѧ(̎G51s^  X;蜸ǽ6 wñ<lfq `<k#?n42?ݓ]x~w<,CGa=&7juRoܘh& Sd _O(@<eᾜ@g5L꺘CAC^~돱$U]cTi.gBn|׵knN]֥S۽ELjh(vvy]1ZOus=LDn?(ҝd"Z�Uת|Mw3g7exZB> ~!oq֤YSe0(4FmUQ`^ ZȜ6)DKC( mAYi#4}zp|~愣9z 6vFR\@TzQUuCX�ӹӸ 6!; ),?Bw0؄uޠ9  },{~0P 6:x&a֟'62o�, t-:#[G> svvٯv'U4΃ $xk#endstream endobj 276 0 obj 2312 endobj 274 0 obj << /Type /Page /Contents 275 0 R /Resources 273 0 R /MediaBox [0 0 595.273 841.887] /Parent 268 0 R >> endobj 273 0 obj << /Font << /F24 5 0 R /F15 7 0 R /F27 77 0 R /F28 86 0 R /F30 42 0 R /F35 43 0 R /F25 87 0 R /F37 5 0 R /F31 93 0 R /F1 107 0 R /F34 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 279 0 obj << /Length 280 0 R /Filter /FlateDecode >> stream xڵV=6M}4\OǍ'v…G]'N%Q!y_> 1;7*D}o!2N %@Y.̖O_΄RlqBmDכe~]VuyȵfUO~],|VH@E"PZe+)( <FD%ᜂ'vT5yJ0uyֱ˲>(1wawBd‡e(KboHmlM4񘢑+pR^̡prv:C-Űn8@X;]PT@[R 7-fT` PC^}Vg*nCn$MuDΜBƞFSw6wm+Y'ƃu[8Tm#7~@Cʈ MڟX۪czxZ?;CI@yߪú݃ iOmÊc_{:H;K݁ސϹlXAc.qlq箯w1+ $_oM"{f*]KfkBhξ$࿒P:PG)OvIhG)*)UʸU$o';yё>P˞PM~Ԛ~DxdjG?2&~jJ؅�{>?#}~I=>%x|,靓ާչK=ꍫipI=/Ռx1L#&U/p^vR/VH{_!%VfS'(L5wf  7𳗮U,]&,h+@)ZT8 N_ıR*,:;&}O1i&of�QR3;UC[�T#4}-Ip"™׶٫O$ iP)iAH72v ϋ}endstream endobj 280 0 obj 971 endobj 278 0 obj << /Type /Page /Contents 279 0 R /Resources 277 0 R /MediaBox [0 0 595.273 841.887] /Parent 268 0 R >> endobj 277 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F31 93 0 R /F37 5 0 R /F35 43 0 R /F36 6 0 R /F25 87 0 R /F30 42 0 R /F24 5 0 R /F1 107 0 R >> /ProcSet [ /PDF /Text ] >> endobj 283 0 obj << /Length 284 0 R /Filter /FlateDecode >> stream xڽWKoF F/8®fVmsi`7-l+ߗl9<Рx(ɏCA2 <\P�-v XW^rJ>ǮnBC~7QJ/%4۟f'ThDPWr/?_oMiȹ!zȲ>,Q[mE/ê/M?V] 29TJ &mU[SdVA; P<ɩk()� 7raD3R蘕/Sc^(sS@ P=Jjcf5,Reܜ(èijU hӹ%R<ܥgTӨ{ؽ*/ #_=n9'rv 1lF1/ -󤇂  -e*3I\/ '*l%: }HF}t�bp1L> $Z+~t E i#=o 7w =<i8R_*xgO;kOw!$PFX)1M]{Rfml3K}KL'$lކ%E!@_b3Sbbu QuAAqT8Gp˖70ØTʾw'/)O=ߝZFeJ%dwBw݉QCwCwr3 #Mhn$iVnUf [nAZuҩ%YT{71=,cv!NeQŷ [7kY?u/IB mӆכuch~!yIb?<ܼcf8l C8|,Đ8݉i\ aΖTU'  krDVzEÇmgBp]*\UKW TAáb͇}]Ჩ髣;^BP^ɳ:�~ ;K6h4=|pfRUsD'YB.²Yu߄n[_z* X}{.܇cuCIS˞r5%'lK~Y# I;s (%)+b"J5X0g@b VBlc)zfQ, RPziSL/{bOMDÎX[ ƩHk4endstream endobj 284 0 obj 1221 endobj 282 0 obj << /Type /Page /Contents 283 0 R /Resources 281 0 R /MediaBox [0 0 595.273 841.887] /Parent 268 0 R >> endobj 281 0 obj << /Font << /F23 5 0 R /F15 7 0 R /F34 5 0 R /F35 43 0 R /F27 77 0 R /F30 42 0 R /F25 87 0 R /F37 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 287 0 obj << /Length 288 0 R /Filter /FlateDecode >> stream xYKoN<$aCHAm2,wY5n/I9~tWUWWUVl$#\ k]W{8VWׁj廫~FVWWfh>Ҋ9DLaaɸIAd98kToZ1^Tm7\Wp2~)2%|Ysc*^8YKt*1˴/ (bGu=LB݇KnOM56qqkΪLj8,Us}YZ0z=e QH5DnGIAb^X1B`5=$N@ "[ыFFjug2[Kq5T>*Eqq CʙshAA# �(U6 ]pm?(9N`9|Cg ) Sy'..ݯDu)2ŊRmFN@B@˂%OlU#2+ejm)su;RrELa!|i �EFƁ,SWb!otz!Duxߠg-]:aJ~8I48ћ·8 aGWE:L4HmmՖ4]Ǟ J^}|;uIcĝ%(pI0VXgv |Yop(#�xD"Ezh:K!N]5íZm WB/ HrQ&8 (L]v>p׆-#Zs[H Y@h^ q+C` ^Gw>>)c4b տ>S|{^}RYK#|CKP00>b|Z_MzrPP�'ಹT} [][.^Fwf5S N)1GqCFq^)=-T3 GIG}]8֜P u"yA1cF T$*% ;-;!J5|eN쳖/D%Y&ͅ8vI'a䊋K� =0¨Yf|N$ߡMK!]|um@`.uzk#uZ^J;V3A/?"W[8BY0g@]+ใϡe=I{-0<Yũh\I Y|H΂;pfAD AB]8"m}=%bR".&`R!k_5w h8u0-|6Mq.CQ wbڔvȧ͈C #Hz|lm\S~a\0έ ,o)L=d~ Մod+5׃ώ|R'?y[+q#>NGioPW~Dٸ}7|)۰rsG!K7=h!DǔN?QȨ]0꿈}!&Lj**>}}K}�3:%| :d0j6j34\Ԣ?dSM"~APoY"E,HŁtTWqϽw8=.병ٓK~Bޥ2\)cSMIM&N77@g߄_V,4D 7YM+vbD,<2AK+Trh/)wMZDPS|b0z`%??>1yܬ%`d47-n6kSolb5ٓ0J'NehRdjufmflۙLO/h숧3…d&0~Tcov ͺˎ�;Q6~9 _wbl/砃&aYq51זhR%J<w8Nf'$~nh>㑳 JHaM(a 'I'?tϘM,kCW>Ԧ NY}ߴ]ly>*?ԡS 죷oV6 's:n*<Ylv1˅@88$`,I )1ŐsD6t.4 endstream endobj 288 0 obj 2197 endobj 286 0 obj << /Type /Page /Contents 287 0 R /Resources 285 0 R /MediaBox [0 0 595.273 841.887] /Parent 268 0 R >> endobj 285 0 obj << /Font << /F30 42 0 R /F15 7 0 R /F35 43 0 R /F27 77 0 R /F25 87 0 R /F28 86 0 R /F37 5 0 R /F36 6 0 R /F24 5 0 R /F1 107 0 R /F29 133 0 R /F32 289 0 R /F26 94 0 R /F34 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 292 0 obj << /Length 293 0 R /Filter /FlateDecode >> stream xڭWKs6=/HM-oCF-N%RCR_], 6\3�X~XpEU1UIoWo?*2fqu(6?/Ga&{0+U,eqlcӵDF.~g_>w8|冿˕eqPU rƕݮ[ʲ>9)Qi2n=4iy.V8ʪZfZPpJYYt744Uڢx >Κ@&R4w~q[37}Vh&eU(20H\YE$nPo]:s U<IoZWtc`+M.q�Wh( @rpbZ #2ׂ@~ą)ni#@n I2Ywqތ[^p J<D<c4ˀy(7gl \ [x!x4X8<2'B3pDc)mnw9ՙEŪJG&Q87g{?u?pLf�Z-}5\p OXw}cr&١E9hEf%/_cs 0g:_~|KtxQqMdpF1m$gHO*ӟWʣm2Eb0Ʈǰybd22'ԂbFIBfk2gx:2aR濜J ],WAvykahۘcNʸYFW4!s=. F\q`9 0J0ɖzi8t?''@Zjuֽ7ru!؂89AI!"x5;phUJxh}.@B F΄tg#_9ﭠ yLVTU6Mp~'22"htDHJ3keB*>-R׻cST=,JDA5$t XWP]v)$GUIpN…�U"jB(A9vW.4 y(`P�?``*[|)Mcüg9LBiMӇ6lΛK9>g *@}O]+W O79]t!|%j$;b[( !$H^c3!_倰: s6(I~fU|`C4X#xZfuet1SD+ 06kuxmB[t<PkMͷdx{O4vmfIc l5$"VkiN rQ]zb �T}86Op Zfh ECg<3}5ؙWfQ:wa8#"#O!$&瘏%A[W8ӻ9ܧN$}nܨ:Q^#gh#C̘xjZN/vTt1%o;#̴irFIcr{0g%:íWuaendstream endobj 293 0 obj 1615 endobj 291 0 obj << /Type /Page /Contents 292 0 R /Resources 290 0 R /MediaBox [0 0 595.273 841.887] /Parent 294 0 R >> endobj 290 0 obj << /Font << /F30 42 0 R /F15 7 0 R /F35 43 0 R /F31 93 0 R /F25 87 0 R /F27 77 0 R /F34 5 0 R /F37 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 297 0 obj << /Length 298 0 R /Filter /FlateDecode >> stream x3T0�BCcC#=##cKS=SS\..}7CSCC=KSS4ʐh 3 /..�~C endstream endobj 298 0 obj 65 endobj 296 0 obj << /Type /Page /Contents 297 0 R /Resources 295 0 R /MediaBox [0 0 595.273 841.887] /Parent 294 0 R >> endobj 295 0 obj << /Font << /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 301 0 obj << /Length 302 0 R /Filter /FlateDecode >> stream xڵWIoFH!儳ϤEShtH@ITD@]Y(M 8#MrPbKc9\0z NKO9]O\mL2uJɇ/dNf)j^MpǦhzMZl'97eSn'̦mUZ; R2)ڳOWn 3,ݼf 'i*mS\btńDʴliNhWw[twN GE%D\ 0ܖth*;w$}䞻zYt{صf^:`.LEB5aD`& d2=Ia` )sb-;FfN'Mq hZSWY6{Du4kb9|2\2 2 uyDW:^rA)= [Tz(#f9>ȐZD-lE0a͜_C !,fh!JA#Ҿ<Y"йo<:W(LD#!pkLW4N#eDඛ' VI4:ؘ 0T %sMd_.d#ZmF!pggwg&+ABAPMua4:%UАr$O O3[Q(і?bJ՗t$0je!v |vI{z1EwδI}+<X-{ּZ+l;>uӔ8MR[ay|!4h _UzA.S uUڏYT8l{̑d#VCG+IhJ&ű|3R|'1'nV20qᇳpgjs.7qo.x1Qu.i" 1k8nuhg#OqX;4S;�ϐ΢i 4"z8Xߵ- q.]k.|i9;Eۿ鸥lW!kp{Gp=0C0CEW˱2DÄ^6HT7>EZ}E٘>H!VPB@Heh?Gv6Zb Htm/McwCr "L|0[ [ !ЙS4 Bkc eAEa81K9JaLǁ1V(q|}mk:Oz0L")+vԥ"SO/N4 ]Di%_Z1PwVu(}O+\=Ok,`_S CyN J/Y3)uM' AB<)D2 >R/: endstream endobj 302 0 obj 1403 endobj 300 0 obj << /Type /Page /Contents 301 0 R /Resources 299 0 R /MediaBox [0 0 595.273 841.887] /Parent 294 0 R >> endobj 299 0 obj << /Font << /F23 5 0 R /F15 7 0 R /F34 5 0 R /F37 5 0 R /F27 77 0 R /F30 42 0 R /F28 86 0 R /F31 93 0 R /F25 87 0 R /F1 107 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 305 0 obj << /Length 306 0 R /Filter /FlateDecode >> stream xYooBpp!iMчE{`LT\:스m`$Ý͈/* 8F-l%0rڽW7\/8gN] ]Xe).U_~W7N`ŧHP/,s_fXY'IK$3J,F[#cU<.-|gL# 5~1'?U\u~MԠ|?iCMq)wءV,ՠbJv,0CܷCỉxŌKSGpe>](ҋv;O5-6=;@N%c(_c7 |nY╫;XS<{/U-9MH攌ߐ&uLIo+nزTR7˚eY2<J!m|�U|mM}_\  (xv A㪢կ3U\ tnm~6[zj\Vbwop[[T'v0!*.~jtŐ '~W9Uu=^ NH=cN 򝊉eɹ.Ro=Nt`Ka՘f+ =&} /4U+ YrO ;riC]>o8Y8`$m2{^]|,JQ�kOc*Tq$dVYh\cZ>}͌TψnX%zE8J$2(&~mWSJTTސ#UdViyQi=efL$%D-|Qrj5//Tj?gcVc]l!?cr)'Vi= c$ֹ= K;LBjQmRTC27{@NJ<` b_Z,$u($@D?<>]jv9R~G˜)% Aa G۾tXWv~Z2ѕ}yJ5{8n2y\Qb\K,&_2a�|cQm`SbJqMʉkUT)Mڧy@?_!ftj 55jbye<6�J%Ǧds)m,"9s�q>ucI Em^IPg9p&N6_ eSY=BG]ڊrݓ a=QwǾ�+OUudTj�xp$:Vfb,SxƗ)C$m6D7RH` x9de \!|)}Ю'ߓW>iOc=[ ~:C?}D"qbJE BU&<E+I7۩8cF08(.< ly:y'55)5S3lט 7KcAhZͧB }�UAoolo Y@y[PN 7 Ya+zA�Q/v%ʡRg%O癶ֳPgRXK/խk@m <4Xx,LSTv34yIVrh@@&~t8{�|-�.W~} #xSQDMG=u QC g f0Olvt+.=^0N@R[qXٷfb5sj9i*PY3^V0lqF'bh <'ifua Dd''2+h[҃=xN&[r -<|2I'EВ0e0#YKd;+\h6 tn*6g%ͱi}k0^(E2] Tloendstream endobj 306 0 obj 1959 endobj 304 0 obj << /Type /Page /Contents 305 0 R /Resources 303 0 R /MediaBox [0 0 595.273 841.887] /Parent 294 0 R >> endobj 303 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F28 86 0 R /F35 43 0 R /F34 5 0 R /F30 42 0 R /F1 107 0 R /F25 87 0 R /F31 93 0 R >> /ProcSet [ /PDF /Text ] >> endobj 309 0 obj << /Length 310 0 R /Filter /FlateDecode >> stream xYmo6޾f&#,kWhAX- ߾#eGul >wtC$pG?OPJS&cDTV[MͬLGUe륟*IfyԔ;!CF@Fp$Mz1271DJOA^o/hEcQ6Wn) )F@41- -DI(1U!B>nrM" iPSӑO)ۇ58V.maqui78^q3}$`W^OVM c ƅ}PQ0bOzK=O�Ȉ[^D'x�{Ы>u@ %(% V744ISOAʯudyD4bB~�,ABILh(O50QP {+qhj Tw N«lg(梹Wc95k?NMWa4.FP@C1:of-% dʢDCu<_uR<QB-׉LzXHAp-\Dž{woٜUUH oI�C<!4aK,uGN`WE0[K4xǗYv3pz %!DKDj?]YuHl}8]K@ z@"9@!&W3w*~ЉE'ob01 n@/1bLĐ{5Bhd%%?~84`YTEՇE𻡟\7ha= ] wPWMoo/( *~y < | hUKݥkJ(@f* :W`ɩn0Tlh.(ik|k{-[5"kq6߸)] *Ъ.iM@DQXd䞾s: 6ʵW]=u^2^p[7w?5H|B޺L+[(㌲MW:˹]XQf =.OQs̵_x{s6UVnovrdʸs@k â>\ߓ׬iX? l ɻdΩu5!zEduh;/V۬4j|\ 4`D&  [MY4:kK{"l@>l"w11+_nFQ]7{9IUhtd7뇈v:@Q-$?X�LhEJߝuz9ڍ3\f `,Α"5я6-ҹ:/.q- (AeřU# s>ȝ |nQ1pOJzUmg'b+;pTD'X"ϊ^ʝ gc2fnξ[+2-/C}O y7宐U10PG D]YdMV5QEx)nEˬ,k*T8/\ug3<9`8cno6>sw\O]ԏ*8兝 =9Pٹw?UUV5"q:.ǎ X1 (+QRyPPጳ{~65KӲ  ځ%iMA[ P4-CI %CnJ^}hZl5e`'* B•,n/TwAendstream endobj 310 0 obj 1828 endobj 308 0 obj << /Type /Page /Contents 309 0 R /Resources 307 0 R /MediaBox [0 0 595.273 841.887] /Parent 294 0 R >> endobj 307 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F28 86 0 R /F25 87 0 R /F30 42 0 R /F1 107 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 313 0 obj << /Length 314 0 R /Filter /FlateDecode >> stream xڅVO0_Gw#v4VbѤn)MB2i|>#``~w!?6d"x8ϣ`m4CDa4MŶQ#O0F.r " LJvpĞ5ȷ*F}E;X臡0jθ2#Üwprvfwo _{{fu<U. ts16B&<"y H|:iRY. dt#_{f<0N­# cc+p5:piGAZ(6~⡧16G^';m[lr9/TkLHVmmgjs"2Yx: \) 4%mPн�SFvyUj%]E/` 'Z$� "j-('@BhAZz E;dA+V<P\" = $t <s#AV%Nn2~8aF2징<Szz#B 4ya\pDB ՀЮv$gUȡZcvI]ӶMԕjP0<>حS{zY[-xklS+kv °L)3Wii2NȵoTmFrOq:�@E}YTo5' ]?pG<v8K %}'ǟ>-!z:BdPӷe!cfG4~ J11$ endstream endobj 314 0 obj 784 endobj 312 0 obj << /Type /Page /Contents 313 0 R /Resources 311 0 R /MediaBox [0 0 595.273 841.887] /Parent 294 0 R >> endobj 311 0 obj << /Font << /F35 43 0 R /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 317 0 obj << /Length 318 0 R /Filter /FlateDecode >> stream xڭXK6y{7bMiZ4 "pmӃlqdɑf_ߡ,@�e 3|lUDq2Tjq{ꖩcPj%muԅ]p[nlyu+Lˆ 4i 6? Vh߯ ъDŽ x$ 4;auo"]+s;5M^6դu[dRΡ<ϢrH(W&׶= )` I^m]K@s2a7Ckum};2cX-1nyqpoBeM;WR\{bπg넗9#TDu%L)@!Os`S8ES@YT K�u=`+\9C؍(>�!cu&}UQԔ:4D&d 1?v.i@Dz+6+WĨenk YMhH(==.(>}ؽ/rĮ<a`RŢ#,;yO縟E;v /}/a Ӯ皠oC`h9F2EhRO+u|!<v0ݤl2+b)%CP$G1"!<Bo8.d`ueX 9{9tx!�=!' <2byˁ& 5x] C( xKM@!(<?`ϨR: zߧೊ 4 ʗ;K:RȑERfꋙYg0>18H(h`^\c°ʬ 5@0HiuՕva+dc{Iϟ@a?lah?MMIʧ@zE kϓ L$2CqLh_稅4cIND/KI 4v5q" #н3ПRDKL,ͯvH/P `XQQ;'{Ydj }:wzqocr\o=ԉ+|*" lI 'S<aۅ~h�A%F䩻%t]LX-8T#9)x<nu2q4 Sm`2Sx pU7b#1b�}(:LTspO9(>$٫'vc]T]kGX W!E;'<aJA_*͐gwm0/OhtTO#& [T] .Jx%00jǿ3�c \fu*@E/bS;vi!΃&^»8jC9T͂RsP/?*Oʂ sMCS.)!6Qr"hftz{? }Zendstream endobj 318 0 obj 1576 endobj 316 0 obj << /Type /Page /Contents 317 0 R /Resources 315 0 R /MediaBox [0 0 595.273 841.887] /Parent 319 0 R >> endobj 315 0 obj << /Font << /F15 7 0 R /F30 42 0 R /F35 43 0 R /F24 5 0 R /F1 107 0 R /F28 86 0 R /F27 77 0 R /F31 93 0 R /F34 5 0 R /F25 87 0 R >> /ProcSet [ /PDF /Text ] >> endobj 322 0 obj << /Length 323 0 R /Filter /FlateDecode >> stream xYnFmН/pIdޏY@S (jbQPKrHđز[S}seX$#\f µȮg?^]|#Tv5$o/_}3\YQ?mYfAJt&ZfYhP qՂrѺ\]|}[򦜏=O"%lXOsSr}Ŀ/+x LWozϣ]A:h򟦵t熨$!TTфITsB&ZVuB;Uu"p&XKxVbMGQ( rYHvp(U(sȮj  P0UyV[jD`7 D!zTq%~rNCqJD#iA϶kE;ml;tfr7I|;"h` 9;~)$J}NᵷpoYDJXPĘ-׋C|07 m m}6_mj$]ǟp#KeoUp*\hnnJwMq,S}�gWc}N%#�h>NYPj&_ۏJFbTk|J HN{DUw9/i7ZdupCz�G0ϿN|f8z(wHwċc)sۤb8e>n<gwt?-qJ# NH@l}ޖ!\Y_\<ONm<[qwPPD]35 TuhbvOJ$z+!wr蟦ԱyOhhd Mbf.,S`Xf ~D�le6`l-,neY%_$a*]ŊՆh.G|]Y}ϐxM,~5ߛQ=y^6\s$FsWv_ ^Q{iDo<_r ^4URU3x^Ai°E0Nu w� jҭz?`W " VDIgu; l_$�ߥh6t1@؆:zI}P^)Fi nQ}Wa~O8<Ⱦlhw/ij1�-S wFv=&a9c1(~ݸgv4ŸbN{CNLbTlx`. [vUiн>1s؆شO`(pbªb{dQQY(4Win[FKȃ|tP X 9K9mWOp=gpU [sWQPƏ$CN '4H?`Y dʜ/YXoX/BwD'X JJoW*U0C<KVHk?<1bf} ;G,Q>az*NDHل%b@2y ᭽?rgX;�щ@_򫈦~c4>Q`bz=QDDy7BY N S 7<y9qGlw�endstream endobj 323 0 obj 1669 endobj 321 0 obj << /Type /Page /Contents 322 0 R /Resources 320 0 R /MediaBox [0 0 595.273 841.887] /Parent 319 0 R >> endobj 320 0 obj << /Font << /F30 42 0 R /F15 7 0 R /F35 43 0 R /F27 77 0 R /F31 93 0 R /F28 86 0 R /F1 107 0 R /F25 87 0 R >> /ProcSet [ /PDF /Text ] >> endobj 326 0 obj << /Length 327 0 R /Filter /FlateDecode >> stream xVKo0 ޮ::̊ԃaagߺ<V]$.1$(vCؔ>2*-?T:bmQ[1&VSl-&7qumP1񀆕(kNrO\ri1 nǂ6(]`QKUC}QÜ8d_{4a߯X#p4=Hz*rĖڑd2ɰGd 4I@`6gCְ;'=Ǥ?}qΜp_dmrط9|Og:|QmZH7=LPZ"|D7"N߾`#-|/!B]!(Frfl/HVfc@=ݽ3|=.֥b-|@Ɂ4P07䳲*r4O¸&"ժЃ CS1`> .wsl|%롇op^"R7g9_ֿZp"ՐB֬fP>Ue9N zQgjҾBVVk:j4lD:)lIEʔm)l z%qendstream endobj 327 0 obj 597 endobj 325 0 obj << /Type /Page /Contents 326 0 R /Resources 324 0 R /MediaBox [0 0 595.273 841.887] /Parent 319 0 R >> endobj 324 0 obj << /Font << /F27 77 0 R /F31 93 0 R /F25 87 0 R /F15 7 0 R /F30 42 0 R /F28 86 0 R >> /ProcSet [ /PDF /Text ] >> endobj 330 0 obj << /Length 331 0 R /Filter /FlateDecode >> stream x3T0�BCcC#=##cKS=SS\..}7CSCC=KSS4ʐh s3/..�~; endstream endobj 331 0 obj 65 endobj 329 0 obj << /Type /Page /Contents 330 0 R /Resources 328 0 R /MediaBox [0 0 595.273 841.887] /Parent 319 0 R >> endobj 328 0 obj << /Font << /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 334 0 obj << /Length 335 0 R /Filter /FlateDecode >> stream xڵXKyAnLr+x|HRيs!+.QZ �J ʶjĠ?+WVpwRfλ!Rmv?W֥rbͿKiSDuEHbxqfTUmp{W1) TZŔ`b] !UcV#cKa#3i+0^^7 Gë,+za_ÿf[=(#+vDilOkO.#1`C}=Jh=tu}Fxџ _ۡ;h@ϊG<nU}FA{n8B(v[6s2֥kb3j]D$o&K�~υnh"#Xx8hGZzG.n"5zU*d'-ʥC243F& ǸH_(Wb^!QЛBS�3Kń!P`+ft)zf9sCeH ,-''3 2veK iv.D(fDt`Sq w 'd!j[9;4݆?oZeK_+LiE jM}̃S;7|]S)C g++P^O.%ئ|nBTqgsۜmeZ(bpI1ibk:2C`FQP*v~֚.5}{<bblϗdþrh99EKJ+(E))3z( |$JCAT?7.!{0#*Ǽ5'Wc4.vE&C̙p" J'Pc4)�KC=h#z]M8F$`=G}Oj0 2G/YMYI3<*H0M"ۺ77ɢLAkJt[4�O~u@L‹Ks~QCugZ@񶩆zGa?ɧeJeҧq X%mV vfCBѠ�[-0Ťb޲0ܬ9>z|1)hKnh<D)yU6kNC615%U;zbE4=II0⍅ͷM"&.c syQީz�J|:%WW ,XkNݻw'62 I0S|.-MFQY1m zo-kbaaU=9wi/0p[wU=V1`֛paRx9V<^c1qJoho#{9@KĐOʈYr�|)bԭy^F WL0&8.;]i4blnNL_6)Tl"2Fns Kt"*x:B3*Hc4ë4|N&" &Rh;&O9 AH8".bHh\lsf:8\LeϤ>i;` ϕ0`MgtWDLA�i+E77yh$WNp|608M|q _1/v7/!?M{+kN2L4@b@p6#hZ LBJxqIN]nh'qkU\Gjz!?_ܧ4-G9 ؉-Rbͼ#wL]pR�ZV�YQW>ް>+]0Xz>s85x˳ \苞Nߤ)`r{U=ǛuԹ1>endstream endobj 335 0 obj 1883 endobj 333 0 obj << /Type /Page /Contents 334 0 R /Resources 332 0 R /MediaBox [0 0 595.273 841.887] /Parent 319 0 R >> endobj 332 0 obj << /Font << /F23 5 0 R /F34 5 0 R /F15 7 0 R /F27 77 0 R /F1 107 0 R /F31 93 0 R /F25 87 0 R /F30 42 0 R /F28 86 0 R >> /ProcSet [ /PDF /Text ] >> endobj 338 0 obj << /Length 339 0 R /Filter /FlateDecode >> stream xڝWYoF_H{qw!Ik EPh(H<E{gx�qٙٙo ~tE':+qro6/XQEޒnv$N)In+j׿mjE"wRN b:F=Ȓ]W9M)W2UuUL@$0KNAA)ey(שYr}qpvP4IW1V]$C1Q͚dn9Fj[Y¡w*15SA$MDii-=A{MuA>#̗DHJBHJ8%r8(дԻ8&;mek_,f <Q [< P&2^kSjhK/a!e�xXsi kCτa,")W:spE$o];I_Y'5&JGwl?2 .1-] $SRǀJ4c&~~rB+W4ܚi b?9k0.MޏN۶>Tn{,j yLb&_yNjUqwQnp}};g; !J`2?%'ۤ.8DBJ Yj{�DQ(,vK"e@k6DUpi، {σ(럑'9�+#]_P_K fr*&˔D}s*!yΧCI7_h0]pj)| "59 u&&,# )dqp'Ov*7WQ8j$#ϰtRXu4>rn�gAYAs J@am7g$#=U+IaٸJp?-JBH4x5n٢ko;"]r G維ޗ a g]5-:jw׎wQr[a`ƈ1sȈO^X~`Ck8۞ })O+;Y)gЫÆ�;W4:Mn#̍eRs:|֖x{r焂499m td[Fl24Ѓ,ίϴx!/"S1Pb n�]𚧢oK^Tb6U3Pc(?מ8l!�l XXJY-%_fбLd ]6`ɵƸ`qq>CFIDҰA, KP�5EGoݸ-C,-WPq<銓IWmuVW}*e.Bz> *&4poL6rb2 CcMqAcݿZzt'pf\s"huCӃg/f΅(-YWBvM#__<748(%ͧƂ*܁׊qVA�* &qN d*Dv"F vض!$a70kPyV 2p΄=Z_7{¨rOvSPB Bx~XR:t�U;kendstream endobj 339 0 obj 1573 endobj 337 0 obj << /Type /Page /Contents 338 0 R /Resources 336 0 R /MediaBox [0 0 595.273 841.887] /Parent 319 0 R >> endobj 336 0 obj << /Font << /F34 5 0 R /F37 5 0 R /F15 7 0 R /F27 77 0 R /F30 42 0 R /F35 43 0 R /F28 86 0 R /F25 87 0 R >> /ProcSet [ /PDF /Text ] >> endobj 342 0 obj << /Length 343 0 R /Filter /FlateDecode >> stream xڭXK%#>D!Ic:Mv6Ʀdɣtbdk'€EdW)Z&mSɄۻ8Y<vKۿd ZFz#dCYNZ-m{g4ˍdU "UV;L-4G=C?ӹrݛ&K'WT5vHNcC-^`_8&7L+pŔFtzqeGGISkt-Hh;4HMM3z-L'¾ ިT%]6j0*= uѾ�Ss(k'&, ܈ 4iݞ:|Okn3@'J짷2t )P`'łef+jTg%{.-q[:y:fNZ@Z뺡B!+QFE7LɽTtx,H,tU OJa\Fh)*aMF3)Vmˡ)-7PT|-UΔ+ἬQ)LIPɝ l 슪V,"sf+܎_<'pfL 3r~+Y:zڢ9$ׁ@f(}> ޽3񚧉Ϲ#Cw>E[87>mªӴ{Bq3$§g ɞ"!J@΋H/G'c󚫩[ܗ ud1Q6JA&fbOL87y" p~O}nBjM>N:8t[%+y7@4ý2 z|IzWǻ݋Yq�nm1tj^|u S;f% {SqۍAXAOCӱB;�h(%=x~Mfp\%CCE/! GO-G$Hϴ_qb $:|B8'HbsP4 ͟Nj:  }4lqHgs΂Z%٫  Ю* Z^F`c`'2OS"Ph4譄VPEÙ}CDi\/$P3GSh`U FH\H[xqo]V &E!rzù;(fYylBx>[!_URriħf`�ͤ1Ưִág{L&UH`%7D.؃>p!no#w7P�QG�]&Ĥg629Fė*'"  L#XC)WU*h| cn+<mt3E3^1”3. :�⧶8B $2k8q&j{lZF_f_ @Z3 ~6]32X& lƻҗX1M>.٥)+4HK}]C,sGki "* Л벪 e~~”rv^-B�RaAl~6=~#(f}�A LPZ3fEc#Od~O4AE(ĦƠ`tb�q�Ҽ0!Dstp~,u R Dyt4/O.ʦrclM)t%0xf\ ƻ-!ᄃ/[L}@� CC[ ZoG.w fq|bR؉br:|6—[*xA @]Xuڥ 1鱠ƿyu)D8A QM'1lNK nL:+X.vMۺ y];F�M͕j(PnF56WȄϻ7-<Z_F ~v "ϟȤKfE]*̆Ff{~dRsCG -e<eXFUԽz/1\ꡐ29GGra;@`?˂~AR,?Bz+ xv)|q'B=-Y+܏/6dq8 ̟f7 (^Q:>6KcQh'5Y*ן7R|߀"ܺE &Vu0͞HqN) iw/[:掎$:]47( 7yjS)i aTO/7sN5##RXĜJ;./Du$lt�5ݳt4aw}oأtj�'Н~ۡCO ,V:c6^X}endstream endobj 343 0 obj 2350 endobj 341 0 obj << /Type /Page /Contents 342 0 R /Resources 340 0 R /MediaBox [0 0 595.273 841.887] /Parent 344 0 R >> endobj 340 0 obj << /Font << /F30 42 0 R /F15 7 0 R /F35 43 0 R /F34 5 0 R /F25 87 0 R /F36 6 0 R >> /ProcSet [ /PDF /Text ] >> endobj 347 0 obj << /Length 348 0 R /Filter /FlateDecode >> stream xڽWIoFz?MR5K&C$&"J9r7oH =[y;łßXX"T-7WkaB˜fH7囤߷K%J*Zܐr/_.WZdvimʪ!Bޑ({Z٦3{A%\\5w_RS2X;>:r%4pe4*Kv]{= \BFo{? ̈"Rf^$RN>]%K3T�eJ&'sP~5L(& g<`$es!RD.) ČYp|ѹB a+/rX! "sh%KG3JaF/>A2 T NgA(jaH 6#PK@.}7d_i50@Oan[n ]u=ĎSLR%Onmg;ȖLf ,=xһFVm(i}"ko:{RU@>2G\WTz pywKckIWQlL92H W:[P2HVҵk*x,()@ n(W4 SEduS<{Olc4H$?};eUzu<meu 9BƊG$Tێ\nN4|BdR'޻jSsՎT} G$#N.tL3Ou|9X}nJC<M3s Ygp%Ӝ',<2JROPCƸ.b"cf s*Ɇ#B놊8`^=zhnHer%\Cq@*TܫǪOӡ<Β=bĪj3YJSHF챦<x[(Ho]yftc=Y"0N�trڭx?:#] ʤ٦�ב: g,ub6K-Rܺ[l.^h _boP`2R<ah~\ 5m^;!etuT 0l؋>Xy65 ^B|]_I(ƁƁ':t6Ty16ňC>�⣬:BA`}@lFkS'8>0,B@]q$@W r g;̷ 7L!v=&ɐa#9&I8ӧ UH G1 {z ;=kF5mo#*| ThW35i!N1`1rn+8,8/endstream endobj 348 0 obj 1438 endobj 346 0 obj << /Type /Page /Contents 347 0 R /Resources 345 0 R /MediaBox [0 0 595.273 841.887] /Parent 344 0 R >> endobj 345 0 obj << /Font << /F15 7 0 R /F35 43 0 R /F30 42 0 R >> /ProcSet [ /PDF /Text ] >> endobj 351 0 obj << /Length 352 0 R /Filter /FlateDecode >> stream xWK6zKn7�=AnMImjeZ%9zM>dku/XKhoI4A Lqu|FYB9RZ%['Z>t)s d<GZq'hmmd,I,0+W PNjSs ɠ]X*P& v]6Ji۱)m釅iQmӁӡw1]1?&�(v˨Lwaj[#뇪4n [8iwCUW-9d<! Q2q1b8w EdB,z?L%#>:]WN`8RDsCu1l!-xZޯ x$&\SNX/_>> `3ҐYuYV_vvۏM}QӢ>><~c>="9@2_~n.(.V<"Ԕh@ 5M^WBzڕJD:in|[yU Y~e}.ٍj X.A5ܝ!$laxA}YMCpjQ#*Jv:j0dAmFbyM4$ E LWM5U7EOε50'VlJzPS ] lߑi"O WX9@,�»~/2Ͱlw} /E{~4MibCiSoU3 rU׉UK$ D$L2wH T]yR͝k>D[>idƵchz&p>aTznչ M9v,sR?DE?� ͿE\#KmlQ 5S`O sH ɰ`:14a3b`[`LQ3;f^b1̠4H A1ʽ5sT#.NBqOaF J0732C˰S+o@rN 254)Dd2 I8P:;yhuThQy<q?urb\?< AJ ̤"V]47=ݏB69.W%"d"k2;BQ 3b[ U6ABp82&rR{WnCގ.k\=켯0((hpHb*v~ BƺX:bMs7,ka h׬jNޝ<3k*@$Fރ{2LpW;)4mX=lF,txK"@ΧG>qn&{Մ3Ч3hUۚ I.m>M5g'=On{_oBjgdKi@Fvet6,X;-?.�&endstream endobj 352 0 obj 1496 endobj 350 0 obj << /Type /Page /Contents 351 0 R /Resources 349 0 R /MediaBox [0 0 595.273 841.887] /Parent 344 0 R >> endobj 349 0 obj << /Font << /F23 5 0 R /F15 7 0 R /F34 5 0 R /F37 5 0 R /F30 42 0 R /F35 43 0 R /F27 77 0 R /F28 86 0 R /F25 87 0 R /F36 6 0 R /F31 93 0 R >> /ProcSet [ /PDF /Text ] >> endobj 355 0 obj << /Length 356 0 R /Filter /FlateDecode >> stream xڵXKs6Лnf,GfzȣvizH@KTw=3 X�ۅل0.jb \|s⒩ c)5YћŇmw>qÊU~⒛Ү2%\ՄI5AEK-JL2?ᅦ`R C^ \51L<nu`L2Vܬ<ja{\+|[5aYS4˸g1gU|۲oZtr0Drt&+egAZ$JZ"EH0$J'{@C'a݁TCSܣ��]5p4^컇nbzHe&n<@�}L'+aN4sI@�kzF Cf1AiL ():?ox.'q".@:Hfs2nEV_Lߟ!ӣOQhSrqY!%uq?]쫦pV<V2l亩f`fDuo}p�RIp1|nB|f}8{l6鵝.NmyӶP6DbmS^* #w3~?H ^@/q[}L( WTp!dq_v]\y]]yϿ<j Z"ߖ}/ OUbOd⨌1V}˞,-b(Xǯvq1AI=c2n0+BI<>1yq֨栯| ip%v#~m|mAp09 eKр&9`t#r/WMIL=* G�|HR0|o3\.:P:!x=$1"[߿ # ~P388@qmC OJOg,5BSKNR u߿ܗ##45I|@k E1m >$v'ueKdqoNΡ4Gp<ezrI][~*W'z\ǡ/U]UuhN*vj/oFWG֕tI*8k?u;qbblv;qWzڄ~waN WPt^h= wÀmZcf@~1}X~FeLUDCw' "ϽoN\ pu8r4$F&F]]aL!v c^0" XO; Y,[8 N I٦L_:0FDpfD4 2fbt^L==�AV>i}IR‘%nBQa̴sŋ 鬆� e3H]l䀆Y| -A xJ%3c )xCEMY_acbJ˯<6&H+K^&̧vU.s olcܘ)'%{ 638d*zsSDR9NPhWx(h)(unyJ9`ذ[Cn �O`4dR:z D AGQՍW&sKvnwmPZU@|-[uendstream endobj 356 0 obj 1692 endobj 354 0 obj << /Type /Page /Contents 355 0 R /Resources 353 0 R /MediaBox [0 0 595.273 841.887] /Parent 344 0 R >> endobj 353 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F25 87 0 R /F30 42 0 R /F35 43 0 R /F37 5 0 R /F24 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 359 0 obj << /Length 360 0 R /Filter /FlateDecode >> stream xڽW]o6}TjKmm>6HA;d~>bz΀h"=<(24*b~8iyRDH=[nۑnjqˆ/<s,er ʶr^꒩ , Fv均Oɶݜ쯢.=W>4jXwnTx_p2_v}髼U߇E B` DЂ훢tずX7MY4^x'Km%D`O =&nDִA2}e�[s^ g/pقII, }U4m7¢D+~[euvUe8C9nU1ꡝVc.cTFd}Du7j*_evK4!é!GhBQ ƘeTqHD[,]-:'"y08Vf_`k B؎ۍ*/7lvMr[We_ s.7=!<DflyBc@*HhL"w} #yI:y<<:T„#J 4o tG;~/ Eu|yASCK:t3)HpmwSLwHrfħc9wIw`i `*}!<9 !zM X`&0e69ʣqrnTԜ4dpuuUͭ<phhvhF4ephQP3uwRq Acȑ7 Z@d9xv΅l";R^3iq@<_ݥ#T/Ә޴zsPS^-^GscG0w (` ID»@WǛw`?؉kq;A{eUd#9z_pq Sda`Oڌ$ZNf|:y*tuSBg):Pz_;pL y /!F"_7/Q 7ZGў&}"rTeZ'K1ј0ǦM(Q}o D}!+BCRǸ XfbV',tt0 Q *v|j۰nW ,l&֛0\9b0Uzexx_7.7MK j [~^endstream endobj 360 0 obj 1283 endobj 358 0 obj << /Type /Page /Contents 359 0 R /Resources 357 0 R /MediaBox [0 0 595.273 841.887] /Parent 344 0 R >> endobj 357 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F30 42 0 R /F35 43 0 R /F27 77 0 R >> /ProcSet [ /PDF /Text ] >> endobj 363 0 obj << /Length 364 0 R /Filter /FlateDecode >> stream xXMoFٗ{ӑB~2A. 6ChHdJJN_ߙHyehZ0`-̛7o&؄qA,UCZL'_r9aJM.b!{Ӵb5 #Emrz㗂^aH&3ΉQֽ7cjhƈaS˳m=84XL/_mםoI #`zUe[l?mQ/5mVOͶ)7tp-h.n/:1NH:ƈQ{BD(aJ: K=ovBxX]5m^ʪv Lí<7ÈZCa߂$k gR$ڈ6p!y `NbPZBd},B\I89>8]dO,|T)4ibE^!:t۬77쒞 2E 5Rm2;j(cd%=ɁE2Y 46}$|,D@8[ynk6ς$'9 91A4D2>p'dy"FKF:_ yirr*<M W̛=1Q,'HN>&x@RwO{r +]UߓL@ÒɎ%SN0¬ofj<)Oz3<a}'aaSg[`jhv^] d#Z^mȁ䍢.J^_h Ao;/|`uY64#BmS;҄S,$2(o@< 'pKx.7IHs!тCզ`Ŀ BϷmebg"q@ 89u2; ~ У`u=9OMM94m*@^\yQ%*Nyml氉^T .=SuF}`}8$委>ITO00$湋pp<J6#> +p a0tػw RTu*ϷjY\XdrfHڪ,T4[Z;?4\@% S˜0f= pأzKK0Ƒ QqKӘ7Sf(D dj t=ML0Rf/n-%5:Ml/m<J!ۍnCk3rDo#s׌@ <z%W{UDq=mhU}{ E̸*q6BV^pi$v,=1oә<8tSour;KwݤNƏWHDPU//\7xQvEo=H-(SJ�eWP?b#I荽8CP<L@Z@Nrבpl\y,0)I`Cϳngr#TB?Jk"G"DIZ15c)Mgzw<\?'f:뿘&ŽT"A~8(g~2! q#,T+d^JR})iARwzq8g4kb wP8¾pjڶD;t'c8gu 88OQB*d,&Qw6 x1Ȑx#�Q4 Oh?On <3(($Tmxhn&_mG mop>M5]W]JkxjtOKh|;4)e{uP Gt�0y Avu9.)w,eG(hCL8i; "@֥ֆVoEWE3endstream endobj 364 0 obj 1897 endobj 362 0 obj << /Type /Page /Contents 363 0 R /Resources 361 0 R /MediaBox [0 0 595.273 841.887] /Parent 344 0 R >> endobj 361 0 obj << /Font << /F24 5 0 R /F30 42 0 R /F15 7 0 R /F35 43 0 R /F27 77 0 R /F25 87 0 R /F1 107 0 R /F34 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 367 0 obj << /Length 368 0 R /Filter /FlateDecode >> stream xY[v^BBd8lj8E]PH]"!){̐"vl[,Ùs9?6s(f µvW.|Ԍ1┚-7~rSs=̹Ɋre]peV|(oUVvEw%LuYۺ)]c=ܕ+\.||[TI\*u_TBl QU)ɫu/2mxMq yS컲']Q㤃yn,ڲ)԰‹I  | m7]YHe+Sv '#tv2W%軃WxIz{qJ3^]ѢUL'݆W/UAoA30|VwyYO&貂H97`̅�[2g'6_emCy0.]=_!qmC WZRc`~RԓVd+y.cЁ]?Ma ps�@Ju- J q6|v�&*|ՅWt5c-E" 6o7j+`).ǶS$SH}m`Uc:ω !�fD^"8 щ -$h/iA S ͂Cܖcx.x5'Š6jr^{&`Ǚ``M1[* Yf_yۖ+CbAq8z_B8xMQ4  (b7v*LA!WpC4 {0 ȺUUٕ^ M IZue41Mg/P' TY�a~"BJ3TV)j#b�m&Zh 9XLlx#a<qahgUE)3"Eoi�rTB~5%|wUGSWJ96`E3Ӌ0h%1JȨN+BqZ K)Dރ/,[A,3z '!y(@bљG9xC!RQLaH77 cL6)~Au*8ӓ| qH;r\υ܉KbM/7)U%=Xm$FeU6 !s^2XZ¨VLB0n{#i%n}2%P~Xd5�7C<|u$Yc?OH_g/c8M2"ʙ_㱲;QaK<@h-<fmMx%Fk03i(фO%9|#)$8&">?2Gu@ ;ՅуsWASX <-<KµP4YCraPLχ} yTS@}λ)J(PR6~$ @(z\ pxPn?w@` 8řHV'a_W+ƣl-+"5lsbgQ ޔODLYM!wVpBƸkzXڜDcc [ҙ?XӴa@48TA�KKAxtAP/"l텪:ddV!eljʡ&M[myh,c؆ҜɾUo@eeVZlvpZ] pӷ((r]l}]j_38P=}e56}tR;pZ0pV\Q?peYb0cĦd '&7s˳Quq?ƦxYT.G>O="bBjҋP`b =|.Xb?_:sވ~)F!8[ DOsK�ؼP1~( Ƨh֋3BH&qSŌpE\F -c{&0|H;0QCCWY t OZ`R=st>I/=7o7ϴhh!2_fNSv[te@BnCMM{p:݆aU41,aendstream endobj 368 0 obj 2182 endobj 366 0 obj << /Type /Page /Contents 367 0 R /Resources 365 0 R /MediaBox [0 0 595.273 841.887] /Parent 369 0 R >> endobj 365 0 obj << /Font << /F15 7 0 R /F36 6 0 R /F24 5 0 R /F27 77 0 R /F25 87 0 R /F30 42 0 R /F28 86 0 R /F31 93 0 R /F1 107 0 R >> /ProcSet [ /PDF /Text ] >> endobj 372 0 obj << /Length 373 0 R /Filter /FlateDecode >> stream xڽYmnޗ=3(>m z@̵ڒ#\}g8^Z-V9"3<*?2g˕I%\W޼zy7 gwkoZZ,5=+{mWp_oڻ6^ Șɋ· WƏkZsf eRi AC0mA_}}a!3L,hR/K&:˘5LrZTqZyE&) KueAhICۜhr/ǾDNɮ^t:əq^^U4WLky|lʨd4\~ Ӄ3R.訙Pv2ONB1 ^1@ѯ\@g 01s UDw 3f(@#iP2Lq+dXr[35Ox |Xc쐫a1«DYD2q֊�]VN_:S[IDo+$Ll*ˡaV̻<x<ŤgA@jX 8O z)l) CKKJcz04$'b9TGK#gGI3u$Kh)D:/smdt/R/x^Dr)CjP̕ܨɘ|2֋N؍ K7}CSr<P!J)Y@*meҭ�t؅_BEq8Y~FiQGr ȓ0*AQwwpG} &3@>'β2,/q/x>ЖBuʓ`rhLɊζXs:SuGuŠ6!?06wfߺ|ͼWBu`jǦ<,,$ԇ pQXG&i4=n.]pzTQ O4iϳ'}�I= AXq^QhipB#i+OY! hS{*[; %lE]#y1vW>ЛKsT~>}납|pHʦzGۑ9qɣ7УxR`$,[sC{LvnPBtC( 9{ pGca0D?.|J7N]_4МTNoskV$T<Uk2e2�~]>s DzcVӹ 펼CY}wh.L8G="w,K³u �B&t]iC�Þc"OS'/}0C7- $'m v[A QxBgw]SY[XϞP</O86w%CoDž� @\85[0sANGBtAfK fh`p]2k_wTagVRi!k;zˮ忦gL4WW2t<8k[;W:V1CcSWAh tn1ۮ3) p< *cl84t Ba()j`#VxeO!|k ܟI|`.Ԡ1XP1 љ؃z y&;A#?P &aޜ_(0su:zHp_d}Vl&DR!UŌ$xP{0E')mz%H> =槍fRKr27B]` oyk81 =ϗrB+h̖YUJK9B|6+Z|Mc質l׶v_eg*3WCk?!f?Sdn&yr+fI"g )BmzF|-c_o[6^fgQAdLa$-}PG Of_TڑP%Wbd\f>Aj 99pPwQ!AK#graޜaHpvDwTK+ .'!18\#kfyN#P60vYbendstream endobj 373 0 obj 2139 endobj 371 0 obj << /Type /Page /Contents 372 0 R /Resources 370 0 R /MediaBox [0 0 595.273 841.887] /Parent 369 0 R >> endobj 370 0 obj << /Font << /F15 7 0 R /F24 5 0 R /F25 87 0 R /F27 77 0 R /F30 42 0 R /F28 86 0 R /F31 93 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 376 0 obj << /Length 377 0 R /Filter /FlateDecode >> stream xڭWKo6=j(> G4@@@ۃ,qBAicCbmj3o bc )(Z&M}e {1BlvA#{B`˸N6/>m*V}mz2E"PPMk=.%\h1w,/4#LM Q<ec{2jM c[wU*"L<w0DQO*kg\wmoAX QEL'>QݾhsdžUzMec_O%`:k\`z Cd$@2�{zfwQD<2.' 'y&#pcx, b�؆kos[@gRf -)E$t%@XvCߌ18PR"(Y O[MTXViG(OG5ArBW \u8@"m�7#x,fp,}4V́ ]|;xiag;u7w<:0癨mstDR@})ʿU>םmu=eOX\ff}pdQ/t_ج(c+sI$!>�'-R@cwձp{+9(#Wl ӵ8 Œ!S76DvN*!0@<�<HdÂj.)nv =iIZI`k3K Sb¢ _TZQ38rK%6Lc~UŌ6a,Hlsir1DqZ9HCc1 @ X9.ya!'~IL%j�-#H ѣȻ{>Zz*uQ3꥙pyt^4-MƳlvj%2/XV0X`rF}tʠT~d%\u(v_;ۇNJ"! \fb6<6 -*~iʹ5'}N0u,#&r<x0#W? 2Pþ8[Ҍ ެ1(5n:n>F0C`KfP@R4&đml &NXPp1,YRDgz(޺ ?Lÿksu3AYt&M EY 2�?0˲}8 Je`zA,ft<(n8t3E(&IZcֵJsΒMendstream endobj 377 0 obj 1347 endobj 375 0 obj << /Type /Page /Contents 376 0 R /Resources 374 0 R /MediaBox [0 0 595.273 841.887] /Parent 369 0 R >> endobj 374 0 obj << /Font << /F30 42 0 R /F15 7 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 380 0 obj << /Length 381 0 R /Filter /FlateDecode >> stream xڽX[DC<nv $j $vjJ!#B3zr&ԾԩܾslFf i>ST^p3glE_U8^dBum;/22^^_yln΋ќYx: gjلngËk".;oL砼MQz\L)W[ 6U+q][k":zymAPΨӣWoT\ov׍ j]gj6묘ɚlq7'Pyg5Ʒ3m΄j /~^9<vJٿcl[~^p=IkjLbnRֿ@@3\U?xvxY?5GW_Sc:Ĩ^xu{ >~� }ӻyS?GwMٙ^;%JB)pPytgG]O[{:\x`;/U2 uXxMțpyШֵ&#WnD]\wq$6ygc`BXdsn_&MC}3T'<QŹT7vt._pJC R^p:r$"A䇔ޥ_6z%YՐ}] oAH?II!(=!i҂8LNA X3L!^ *E/SvNwpNzv FJ96.jSdN8[&Ib$6 N~§.?j{vAcՅ |s Nbp2<f2}O^EMF17jGϾ\\=$%} n!9-I }\F1+״. jA}>?%۪LLD�UJJX' Rv:.~БZ =XМBτԈ<Ykg;6 H4LaN3Hq#z)03L&r B5)"VdCN+5U4*+Ѧoݤ5.K.P 'rd ?T3gH'C<^_i|',E )GҌiBmf8,L''4(�|\%P($n t4[d#c8e49E`~Z73pL*-CbD݋'g E/EdG#sZmY1U!UtyK&8& r8p7Ln,Gm\R#-\5=ˎ1F뇆?!܂(4K/=pI~9FsJq�Ʀ]ߡ| GߓLn[?$ɀ&kL :Uɑh+ sZ|`X3zGG$ mAu0nC9c1muek=Dq隰w?TczuJM}?Tį2|fìٜb8 V 6>h= @d0JC }�#߹EVBʲ0ty}: >NWZ\R>˥,p5}m&[29,,[>E%9l= 4& ʮCtF)Q4>NpN3;Vendstream endobj 381 0 obj 1844 endobj 379 0 obj << /Type /Page /Contents 380 0 R /Resources 378 0 R /MediaBox [0 0 595.273 841.887] /Parent 369 0 R >> endobj 378 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F35 43 0 R /F27 77 0 R /F24 5 0 R /F28 86 0 R /F30 42 0 R /F31 93 0 R >> /ProcSet [ /PDF /Text ] >> endobj 384 0 obj << /Length 385 0 R /Filter /FlateDecode >> stream xXK6y/?>DlCX EYlkBlɐl_)KkfF7/9Ǵ+&v..] =9gOXr. :lf/ucuٕ,F n*vV0Waֈ\)O" NdeN&% =Iksc\KE(8} kכ|3CAmx! {Io]\"˾nfss@D=H O:v<[n=7tTVU660CaNjKiϾM&+4aC)I. 1g9?2ەe\P5}K+<ߴMm<,lSnhe7gãz}٬*VݴQ'txktLhgX$I.X\(#r6W D*)gg]5=On)iK.$9Mɩ5^5r8mz?KDnaXehF *k ܪ<8vm`g�C` EDU{  ]& &hԿRjW2FfUجЗR7*ǔUFG<>U֢Wls&H6DMؠ9.] 0ݽجS9$fhA n]W *.'N9 A2#  ABf-c|H<Q IqkOXA2 n;7`YH2]$ד*|NEqr"`oӛ ˅I|)iv>هN<(9~U2>p #@+,Li"@Qz�?<O0t؂ yT1C")H!�? @а{^<d8T7v`Jgk}Tմ:kG޽hI A?٫e8OfLnSuxc9d|B$ Xpԉ[Y (^&TF89 1UDK_zX֑M*WoeWv~KAhHqn&�fܣ%coSe$ @X|WPV=P qL<N)cĸjô&k b2)@C�rPm&]d"3(M<~r}۬aa<5SŴ 'i! i@F3a(rOsz2rʹp'(U*P le FǃG(̨8:?@[۔U¥i@ #ȦT࣠BPM:Vq =]ImM{,@pz$,Ϲp=%uC57^P^ܦ)h|�-'͡ i ! @{[v ժƈ<A *ӂÖw,3@zsP롑ߔalZVB�LmfKˆO9 ^)@pMxgUͿS}*'s%t-/hyz^ux Ź̛E!(3݋سh�,7ra-G[Eŏ_<v4Ž]Dߠ7s~sv7"!g qN6AQ՜eE>-ؤ߫%P u~J h*yU-=៍K+ȅ*W'XpF2W)wC_Q:Rlt0E9iQ̆FȺq+eendstream endobj 385 0 obj 1939 endobj 383 0 obj << /Type /Page /Contents 384 0 R /Resources 382 0 R /MediaBox [0 0 595.273 841.887] /Parent 369 0 R >> endobj 382 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F28 86 0 R /F31 93 0 R /F25 87 0 R /F1 107 0 R /F30 42 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 388 0 obj << /Length 389 0 R /Filter /FlateDecode >> stream xڵXKoy_r~I9(AiI9HV~}9*b* -rd6/߼(FVG/>u۝R*ÑoS;dlS55}7sDCE@>owfvN>4z:pu?n뗪ꇺu#_oyNXfL Oʹ6H%f=Ns}jw9F8UD&- yiz&7j=rV2G:oJnR$%S0[Dr8?l%PfU7'w*VIR<x6Lkfjõx?<=|󏇦0B%0-E�!i<@{UKveE.Pd'4\Qf G<xT?gohXBg#aOc. C3q8zPaѳG'.t.oqpZC1U7̽ ~P,f'%.ǦEU0 %h/e\32.tMyHw4tݷml0Ȩ a q% (0]\D??xE3] ^=l mqgu"%BZ.BWlwIO]7+y,O<aYk\t VgU]cb&Y\29fKGuz j[LRguۏ1NOi:8PyB2`B..�fٌ{L #&<kHTɀ-PH 2 ws6]̜CL�зxc _~^A 4 A/'@[H`#d i.p`Tvbd6 a�?yKh+\gv;_(I\/^p" VL6jvv6 c.hp^iG�{#&s#u2|dU B\hiͥ @ce-d7 =f Or@:` ZWR#ʭ5A%S� -KebV--  $"TɨεXe?`t9E:] sZ9[)amDT!DYw J0BmI.鐜`i[?oP$8 ̾ )"Z k j=X#JPB*`7R!E+B} P]5ݾk}K;!o}wK1\R /tq<޼o\Sf3&0q!TEci+zZ"cg9MٖL߄fcYi RjIT$gWzJ (^OIa sZI) t.ho5"KWJpIupPȅHPZ@otbv*�*L#@Q*"nZ߃K7U2"oR| ?$'ItbЊ_#r؄yB/Yw}rdA%eưхR!.ްwX4zWt%cy$rEbâ1LT*_'"|#S H^!g3!ʋ/}s&Ȱ27Ӌ., PM5c,%X;^K`@R?X lG+'$_Ah" ~PrVB- vBg7 YiCeBCnP6as#H(u/a]SU7#CI:>8J3QGΎ$Baj͋fD.,,4hZk'wW7ҷz0 22>CY͉,YQb1͇7endstream endobj 389 0 obj 2062 endobj 387 0 obj << /Type /Page /Contents 388 0 R /Resources 386 0 R /MediaBox [0 0 595.273 841.887] /Parent 369 0 R >> endobj 386 0 obj << /Font << /F15 7 0 R /F35 43 0 R /F30 42 0 R /F34 5 0 R /F27 77 0 R /F24 5 0 R /F36 6 0 R /F25 87 0 R /F28 86 0 R >> /ProcSet [ /PDF /Text ] >> endobj 392 0 obj << /Length 393 0 R /Filter /FlateDecode >> stream xڭXYoF~KBýx胛Nl1%֢<TαIV"1ܝo�Y2EefO/^ 3O]ߒO's': mlmU/ͷYso !/r'ėv&p聈N"; 5oYmUY<̐-[} Fuv劯he2W"XBZz ƳO"4QIjv^Ȗ+{oW4oN*2:E+mysԉy_ִBZBKs{=nm}omUݼb? !)d98[N@l.o$KBYڒסC mi0zue@s̚HNA`2S6rt`=4oUxS+E;8h:K (^m oǰاyQ8εn]70lyJ!E%eDo/X288GaH` �&I莗S~B<{&&d38quf;P*)3Ht�Q(4RMzxS6vEok F"Ȅ"jŝ])0ʇiP;yR'Itb~G@DJM(Hqӑu\V?bhs<eVR1? M yˬu;3-'yʆ%]uXT⻌%0yCfu\D9SuZyt(E2u20nGCwT0X] _ &$RzhNѕ)p}ۢ',,^FOu L jGk~%ĦE Nާ]H6/*҇G%!d.';2#Isrυʈ8Lh"]er뗻jFxKDK|/AhWFY(]uw9E]::v_5& qko�mi^) OwGh"CoN@ /rɜ筶n<+úɖ{7KCP Y?zF?2gi~=P+=nKC_@{/gR~ ;aMNjlc@{ Re_r;ו1 9W8- eU� S5u1$ЭQirZ*1F1ÓUAU5;#%UeuRAA?K? :Bq0(^Sh0Gph#AP\|wqb}uҭ|f觺9#]^N<o.>NQ�T hY˦ew'4PX-^e6wAЛ8V[BSBu֛x`[`HHtgU6lS, ٖ[ꆺfu{O oaIM~|E.os5/^#GOXSʫB;\]+=a_go�HvGVoݙ3 O~]@8m{el@<ՎSm vm?lr\!%'oMk 9[~"r8!f8�җ83rԋ___9endstream endobj 393 0 obj 1710 endobj 391 0 obj << /Type /Page /Contents 392 0 R /Resources 390 0 R /MediaBox [0 0 595.273 841.887] /Parent 394 0 R >> endobj 390 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F24 5 0 R /F28 86 0 R /F30 42 0 R /F25 87 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 397 0 obj << /Length 398 0 R /Filter /FlateDecode >> stream xڽXmD}_ p �N$V_όgױ=zl,?|ƅd.3K&7,o|!Ռ[&-r{5]v, iut_*=??:;IehB &W3ޭr(rK~m.E-"Ҧ29Kh!3v&C=eYwkv&-gBrzFoB$.1ؔG i (PBF?j EWCJݙAbƭA1D]+*HCQdE ˪ k6I\5i^djV{6m~u^MiTV�tb0=D1H5l("ށH&abI7DRT崺ٲ!<qbB`maZx}:-^fDʰ5tҒUȐ$Y Oj`[i j%4+mgk|=lWzc~H+ħՕB�6[#MIJb*h@]^r!5b P _~C*^>vPtwY' OiaŸ 6XD,F)ᡬ8X$tdT9>@=܀zn-7r w)G)%n9M0z4R`L{2L\r?ecyq-l~h Ogyw)XEZ=@UސF"j:0ҚymY!ݫ^|[BYPLVd;2[-Qη'T.NP?)t<Kzabxܱby U!=^m]iqN:H^81hoEY1+&7cdSxCӍju@69ߛ:#M.Z #A,GDU۵QDE?zR/ZVbZmh&{A%mb~]RMB1C>N%"9d 7$\ ч+5&QS C0'*OS |"xo=auyzQB<Z`/d[ 5!�&̱th;ƚ O#;YoGhO&)=U~3gƐ'=ևvnAM4~kDI>?e=^aXJt?˜9qHdZ!d<$`. 'SL#Hl�\tuh-0�q(舎Ξy򆛤Z.QS; 7{u)_Q;]+l@I�3ä�؞#a;X$Q+hNW1D dBqn0 Ao;geZ,t> 9k͌>/Jmxnp ׇ12+ѽ0L /ph2_E*jO :7Bendstream endobj 398 0 obj 1566 endobj 396 0 obj << /Type /Page /Contents 397 0 R /Resources 395 0 R /MediaBox [0 0 595.273 841.887] /Parent 394 0 R >> endobj 395 0 obj << /Font << /F34 5 0 R /F37 5 0 R /F15 7 0 R /F35 43 0 R /F27 77 0 R /F1 107 0 R /F30 42 0 R >> /ProcSet [ /PDF /Text ] >> endobj 401 0 obj << /Length 402 0 R /Filter /FlateDecode >> stream xYrZ Cٰ&7qyOyNET&GMItMɞ>6nH3҂ }ރ#c+HPAwW_f$Rnʫ2Ɖ"z3yvozv۲YˆlSCWu[_bjŰRas´[kor։:iHAUؕ!eQ+Be\57پ)_缐Yq~QY7;WsevuWoCoj/yl&TH"e07S _wpF#nڦi6|VʍMnSvƲM.vKMvnuuUSF\e<rhN1\h¤l^mtq@ kA?C~NsT)Yh.B<1'NB0*;9R̜*$Q"W*-hV).B/+6a8Ss>wc[m#ؒBT>1șf,HAyē\1J;Lh#V6itDEϠN;_E̜m}>*aL?bt-<KeQǟLt& &$BuP\o-XVv~] z)ݧSEK`A)`p^|:BttU4EۛIܢ].3M]9~}0 coV5IIK}4aq-AM{;a8T ߂oaH d _~NF(Ö}YG mRx/ O Y*.ac.㧔^X@_SESu8:È1\$6PSJ$&%X0N(Ah1:ל @fvV}6<!Q,vhS݅l6__$݂ɩh8N d#NHQە :dnOF%L^(G)Y 5>j4N�XSVa'ZQS}pJb$1Vyb<1rB޿?LՂJ\MiCtm|kxy"bѹ Ux+d.8 .7sB ˞Oߣd3ȃb J+oau:9Ph>2~IcQ"$'xڄ^SI{B5 *ѠL% k.lZ[rF1(8 wZ\H MKQbh=j~v2lKQ1)2EU+n<M|B( B1-̺~hnʹpZ Ӿin(tk:e_q*!1$Լx@~<E[͟ ~n0;RuR?ѹfο=ùs}\=N[c FP֟OH.U11~T=Q{|@,Ke<,ʗ$Zn&n䯾n!$IdTD>L猲ϡH"S iu]"ؘʳ~E:c?h,sfҩi~""ϱl%)Ha=8^L/ GV\bSs 38,i&tI/{D y3/(G "'fdP" F] .< {X0 ~gh0C:)>`0`iJ*~<05av$kv-8j.^ޕ^ #KC,;GYfkw.[tvețmy_F7}ƻEC|Ppq]ߎWasv#wR~ ZɬMSyLLwx3v'8j{F4uP:QF#G͢& gTʋeܟ \R9 p#26wzƻX!Ƌ endstream endobj 402 0 obj 2003 endobj 400 0 obj << /Type /Page /Contents 401 0 R /Resources 399 0 R /MediaBox [0 0 595.273 841.887] /Parent 394 0 R >> endobj 399 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F35 43 0 R /F24 5 0 R /F1 107 0 R /F27 77 0 R /F30 42 0 R /F31 93 0 R /F28 86 0 R >> /ProcSet [ /PDF /Text ] >> endobj 405 0 obj << /Length 406 0 R /Filter /FlateDecode >> stream xYKo޳9%H~7 ,b  %q1CΒ{>_w5_RK6V6@ @i?Z0eqŤUW_f#+\ѫu/.ZtY1W]y)bfhUf[.t3͹ uې(|}5>?U{vVgW㳧.C=E?\op̘Wʹ6}^Afnڎ-hsƥlH`ˊ}}ۦ<ʦx_CW_",yTRqo\خ"v0|\w I)8SZF[ݿL3V }Z0waؕa٫mX ş.rǸ7[="tBĄ Ŝ@~,Q7 :O)%styTDa> n[,B:r(YŴKiUaO.b5—>K#FP)nbiQ6H:i4yQ4htVQbx%PAb ˟_.k?Jя_%Ѫ ܯ$sA  E}bl,Yd4L"T@EV!Ҽ&tI*nHf on_7 g~yɰ "Ufw6?ˣ*if߆k+a0-B;R*OGDr 29Q U~'5q3!]G?[d?@)_n�KLJfapp0W:GY )4.otVvu3NE_XˬQR%Ꮹs179mdK&LBpbV(;UGm.1xgaU4(mWwGg2ځA Ewo#'$xur3;謫P);tHCgIx1.jѻ^ZtHi\}J�O,/^d*`BO&^959+ O'*S6io d!U<jeK::gzXX8Cn (?vWIjMy> 4[7Py=M `,݇ݡx׻0;EV=oڅva%Bs.ؕvzBe .MCo7R1#sڋ.ݎsXѶt20BѸI˄D -)_'|ffYl^{ #:Ey=I7*BS>I2DZCdV!zjIKV?p4'3E_K&Xy.?RARi@e8V`+I+6}bU<JO .?/̼@1w*,}IHܟmʘL_bщf7Pxb+W/`ms4-<.0w2{Ҡd UBtBŠқo+AVcR�1)Tշ0vLsٍTŒxA>G:?}k/鹒&j06-zzst׿7ÏF >4%̂YI"U>&6;ӡ3H#"{SQЁbA??ݮ{߽9XO`-SHTҧ rzҲB>3@/Lve-y>upy; .:O5=q[5Fɗ^G5eZ@בүY ̑vd \9uמj/caf1ߟϡ̛Z3~,󊐞d!6C^oc/q:I=Y]SXy8"St#eB)1.  Ɍ5fYX ĺoHa52JO s"I2(E9$ Pendstream endobj 406 0 obj 2090 endobj 404 0 obj << /Type /Page /Contents 405 0 R /Resources 403 0 R /MediaBox [0 0 595.273 841.887] /Parent 394 0 R >> endobj 403 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F30 42 0 R /F24 5 0 R /F1 107 0 R /F28 86 0 R /F31 93 0 R /F25 87 0 R /F37 5 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 409 0 obj << /Length 410 0 R /Filter /FlateDecode >> stream xڵW[o6~˶GXy%PAY/$'~y([r:%"'2'Xi 3 rw- fu>?nng6ri+3:H뫾f׷BgkMj eonVur6T^ݲm%PwtXTV[ZX˾9;zyl6~w۪߰!R&RAݓ/#jIuN}^vK1ڬ^2Y0{\tzioHV1JT Đx%(dbV2)$ofRo>aVQСa=)V0"תe5]a7sZ$''csf8&պojk~w=+"<ERi*~)ԆaJ7=vSg>Y0~)aWk&ס& }Ca~̂VY Zt]*ihM89}t 8nηd`TfX2I\ll}%"؜%bGxc'MFvce2@ -2"+Ƥ)3`:APsDs 2M'FRiA Cll)v&.;&7 (ℝfhZ9MGouqdby+t+KLc E?5SV|qNqՌR2<ݡ3)4*' X FhcO %p㖙X1Xn8bP8y" *_ #bq!q7 ȠM'$__fu Mev{4$fpƳht]8Nh%^\ Y7\ozJ8Lگ O#6gg_}\m0.UH4c}8"\hN=d w}1%CFW Y2m+@HgE1n.Z4Zr~Ka6VYE>g=�0=O `/BK/|!EhϏB=W#ИIXvm)Ba(ƘU%3%ȍ2AP@(g+I>#" �b%3xDVX:ھPCUF x^g�L\1U_Cëhbxy Íڟ \f4f p2%+JMxfs=xT75>j]5A_kk'l{lYٯևjo;<څA!8BxJ?Z#&2Ce=&J1(;#s;-~{.t-!~CZ7\;E--bIex%nc.G4rKӑ F8R @ډwRWendstream endobj 410 0 obj 1470 endobj 408 0 obj << /Type /Page /Contents 409 0 R /Resources 407 0 R /MediaBox [0 0 595.273 841.887] /Parent 394 0 R >> endobj 407 0 obj << /Font << /F23 5 0 R /F15 7 0 R /F34 5 0 R /F30 42 0 R /F35 43 0 R /F27 77 0 R /F28 86 0 R /F1 107 0 R /F25 87 0 R /F29 133 0 R /F26 94 0 R >> /ProcSet [ /PDF /Text ] >> endobj 413 0 obj << /Length 414 0 R /Filter /FlateDecode >> stream xYoϳ? /z+ 6yi+qHsM$&lI.IR";_۴ r4;3;Y?>Zl)0rX\8g^y<[xif}q:?lt[ezeM[W]˸T>/*嶭Ov/^˱l{fM~K"d߽"|x=)џ߽:k. B˻fAB^efus]5-PL/nWU/6m_\lۮ~EVA(A9Xb*VmvO ْlLm5:Ro׋٬30˦Zg#AE6^dӦkumUf9MT*_<JJ[}`-anpG)tA("_dIr,(I$<z/3{ɴS'T `鿪o+v n#&]b]4/oVUOgL]_Um3md)'vsbCnx⋛Eݬq4౫($CX~SdBD@NC}[-ի Ocye I j<^A!HQ+5<HJ{(ZCv ;q2ÄLIq(C|<�6L 3,2K:և~Ŏ, < Wܧz즘WpM&ĔTѐ@sx.-PXqOdd'v'FX3Cd~rnfaZ2,os ?;?v(`Lq6QhF0/y^VnTXP&Ti=Q 3\qI&f3`,뻸XXDQRWHd�JmyKq:DJ4bVm_lHa߀2hBp$@'I p LCQdÜVlY%<[t#܌-&5< ?.X8(-JXQ1!JrwM.MeL`F<$ViJ>֞#w̥8s<B3K @f yuA]|,){P9h9L�*#Vtl1}�X1W Ed( ٞ( '�Y='P7gݴm}==ݿQ??dOA܂X1bѤ."z6=Qѿ酢'jrlAp'7 GU/i ~$9bUЌ:kM"T)o\!k'/ 2 dS+P3}F'`$"hOC|D-x9lw2Mjuj#Sdp( ÁlQqfw!?c|ԵȐaINxG/;`Kc^)\4ӬaD$*+?}Hv{]>lxhmכ pLỹIÝ#]2?k@ȟ~Houu̵xXUǙ2IUhVw{C!wg5yۺSwMOCBHk;i<2PvTfU&ݠ:/7.0ÐjUm-.mm %Ģ3vNv<4ӄze4^:7͠,"LD mT&M(y48}!#\�"SGjM�Ԑ ehT }L d&6e`0Sqݯ3m?_W}^]6(m)ِGa`Ҧ5?k F++nx1B'Jc| 9.նjMOp&}5}s3#l,{]_Tu 0\;dU>("vHWu\XԇnhЈ!p$:}8=㔖çz޵s=]d^O<=O۶ҟ$(U行PU,.*s^ؼʫz[>|^߰$@Rbxbݓ*0 FT>Y 3>ZeHf|Q,s퉞(ӣK8bƛ~$endstream endobj 414 0 obj 2211 endobj 412 0 obj << /Type /Page /Contents 413 0 R /Resources 411 0 R /MediaBox [0 0 595.273 841.887] /Parent 394 0 R >> endobj 411 0 obj << /Font << /F15 7 0 R /F35 43 0 R /F30 42 0 R /F27 77 0 R /F1 107 0 R /F28 86 0 R /F25 87 0 R /F36 6 0 R >> /ProcSet [ /PDF /Text ] >> endobj 417 0 obj << /Length 418 0 R /Filter /FlateDecode >> stream xZ͓۶y}nriЦnNj3J.ܐ=_!Diw̤Â�<~x�PcL k1Yl8 SD2&:_kmm^ϸ`SO*|Wrwu?w.˶kmWI*o;'sԾfɯ=8cHɷm[`BUyLaQ]J*!ʹ*r!İ,x;N4J;p 4BMנ0<4ϛwqHS}F 33gj2Xz?՛)4ܙB9yՆD(::�h~ P|zmEu~3bmsFFojUT;hwiOzu3h&hI>GS9l,`zu%Nz({_j˟9Dq =Đ`&`\b2uD#d2m1N>Wm6]BɆl0gv)"x1o.f п:}cXV4Y\i{$"'.M(؅B)I�D0ԶMB{:?:ׯ窩7tarPLA#/1n2#Bxb8| kΩ8#p̊_+z,l�p?+pWjvck`cY8D!ߢ>zP�?3aBngl)Ub!LhJ'4DSH v*R$`a9~Z/]IW_JAqДQQ61iJ~SLVW,ГS @: Δفx ?D�3:6iM&9FǙT*>JDK%7 +Y wK|̄0fg |;~/ A,3gX'""`EGn T7u`S}HEDhX yvFL)Xw)a<⏦#D@A2ECqVD6r`A>Bs:pJb"p<@"R R&f4i@8Ѝ�MdIԍf3n y% g‡244P@òŏ%oSB81$K(xHx�b �  WuegޏgX +&�3ުuuW4 ʄIr5p i`h_%Yp�f3GaF" Bf$/])<� 8*[ ]GIt?ӳ'?-vǷЉQUn`sed+�#sX-㟚+A2M O9G=~} '@'#PvZ(=4#:vzygt�;;msE%{3N. S]~MYf { _wESr,q2<b {)0h\Fq�XgGR%H{?*f]^Ni&.S <G}opd"$#Rs$�NV )~(ݨ <cu4 :S7ݑ�syv}+DZ|WoM+q&~=q=-8nogff u)@XJcNFC &P8 R2dü`~^;{P  3uYNiΈ~^cc\'C!őivx?k8cFv<8c"2Ay .[ouoסK]\;/Ɵ\<oK^X0H3L,<4m~[0VE LCDɹK{{<^sC'/2˻4 }ˤ/X] ԞwR<HMVu? Bqw*N'%9aq<fa)376/�yEtپ=^jjQWm,|*!"0:;_ (m# (hǿ2%0JnVz]eFqELe &bTfQpscmE;&߹&Pa&Cŷ`֟WIYOE1ޥ2@'2q9(2P oElS[fOĴ{ʹ\*l|1eؑ+=;!Kv%Pó5,F?\qDS߽8{Mm>%%FDw&0>l2̡K pm {+jȆge. >O1%\/ o'Ap4!4eqNCLWP2Xk@}Ad$Sq t8w1. 2갽mendstream endobj 418 0 obj 2532 endobj 416 0 obj << /Type /Page /Contents 417 0 R /Resources 415 0 R /MediaBox [0 0 595.273 841.887] /Parent 419 0 R >> endobj 415 0 obj << /Font << /F15 7 0 R /F34 5 0 R /F37 5 0 R /F27 77 0 R /F25 87 0 R /F30 42 0 R /F1 107 0 R /F31 93 0 R /F28 86 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 422 0 obj << /Length 423 0 R /Filter /FlateDecode >> stream xYKyr-gL!aW=l`/X9#Q#)Ԏ7>UHgF6,vWW}UU[P b\h*Wb>eu P։6g d_qNY \h U?ȶm˺6~ܗ?&+ (m6_oA^lU~?t?g, VdK!FrAgn!v̹*7/_n àOWC`N`Y\)5(&z C98pS)-=P=^Dq0 |jߊpaD[d6(s"WpLja͢;g)0k[3&D3$�ȥ )+<QOĽ]0Ml5`R+k9bJKACb VK[<v!\vA,wH3bw2㝺 /lUj�Câ\"4eG>`�o6e~lS}!�ڦۭ ?BZ۬]兄 `_<@%Zlf%�\''vqYT1"] ~7 " i s{:yjɼ(=Wnma)ܟ]iV7y,T>D eKMTPbxdIH;!-q+2L㕰P^jW,v]PBn<8jg8xݞ[+c=jaT!fM(%ͺ+߹GmGu' D>G7Pa mxns\L̸ڡUqF 9lx[؏uৎ]л6.(UI, g5Z;06{OVdܻȾ30eƝ>/(e3DQu析op;}rD�AaU3SA * 1u\O pwbc1M::g\S=s'_2.2>5$ 6{s8 þ�j@3Ex D&@)prݥ�'d{jXSR02r}u) hRѐ] :M۠.L@p-jұsLY' RY\+S> FL<כ?%FXH0%[MgT >uXc! (_T!Q!IJXX ui5b�:ZA] (}Y[K X|!]̐Dp@wd_ZcW"r=M i3P#D-ΙDCZp&/==ۦE.g}\6c_مKYK 8^RK~M!Ffx ~�TXY9i{$Esv78fK^ECzJKFַ[$I"gWxiY2ec8en7S6k,.PQ+| ;N�lg(Z:2=Ek@̣=. f/<zD&}=BBF)3 /YD̙!T?ʽB#cbGz1%ٷ2ШPL(1 mJ%/1�oҷACNzMT3+S N$6 bpvtxcv`JWYL! 62?p,,pfu4x _ ![%\*1H\2�Ӣp`4Gf21\_F2f!&2Ƨ9&\ p֦ͩsXg з:8  N0RGͯnl76ɮr>#Q*!Nj sċ#f6wBM.&Y `HdJA|usODVn=u7-i%_J\20ÿep\Wk 2x,OU_/LP#UC*#} E!*93(P. /endstream endobj 423 0 obj 2139 endobj 421 0 obj << /Type /Page /Contents 422 0 R /Resources 420 0 R /MediaBox [0 0 595.273 841.887] /Parent 419 0 R >> endobj 420 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F27 77 0 R /F28 86 0 R /F30 42 0 R /F25 87 0 R /F35 43 0 R /F1 107 0 R /F29 133 0 R >> /ProcSet [ /PDF /Text ] >> endobj 426 0 obj << /Length 427 0 R /Filter /FlateDecode >> stream xZ[oN_݇5N` H6%jͬ.Iy9,q  ̜~3\6M#™p-&_o/v)o?_]15x8Q   ہ2TpSt.ta+VŪ*_ wDr֎8yxo$aN,3||())%ڊ&H(hNj`Q=!\JG%vb@EpF 'GiBx.IU)6 @ˆj#i8leHƎ0e813HaA3=ؔpN5y:d`NgBt5x5OuM"\N9tjȲ˨ Jȸt>-*,6m\¢jW7!G]|_T٥$ܚq䍴舖i/r*0y x4߬ r$TW6"4/3֢u>e0v`zR$I#Y)+.^b!P+XL>b|ƞm4PW0ڱ(cpg4.Κbm舂� xכ z-[Qs! e^uW?^²z޶ɲx Vy iL)Q I Mƫ�G}HV s21Pcbqd|  ;ƖC3$@�LH)d \,uH,JcH鏔u5wWx.Xbɭw;Y14M5 .]Pl։`gq ѓQU�`#Gɚa{36 ~;Dc$: Gs=BO)_YO8huJ;W%2{RZ Tie tL6GGkB:M /&)8ߖDmV.HF_7YGCuZ,b2>X̤E(\QDK`l#)P<45 5Kay/!^g&%d_߄xC&�G&!!*SYlD}lgݬ& ØCŦYjuD]_|YtPU=]mWϾ m"8rodרQ}87a`Y腀q6�&Ns4;Dr,t:MN*u;@pY XGA6Lx9S8!wp$ۍe||"r":?(z><2%\>9qiYB{ːiƓ p�9t�@~xm!Qc\"#*]M/m:K`C@khm&>kzaOU˂(~2bo *r[XyqUp % Ѐ:GU/wKA`ߦȾ/�<aCiC+eau~خ%Ge@pz_F"=Q@dB!¨A;9S8Nd35܆g]_Co T3dŋ[f۷_ a#]$ c f_8"W/(1VgƑ~_P\rءOPg&Dio2jQ&P.?�>=ܕ=WjUy%X>.6S$!=DUmLb_Qp)rv%5lhqx7_ j*^\oqݤy~=`P�F  uvH pϲwS+`ؐ-QpCLX"TB?0B۟r(G(w28ʞk|Ǒ4u PM:IU' BQ$Ϻ %?6-"1X ž4"2�z^6ԏuM:7KJ $'"̥龫3BU G1:׍'ƾ�yKmtBPq벑jG:̰_!Vk66 澺 ^vdP'2j98'T}1X(jlKʓ4ٱ%`8fC* zWhҳ*(}WO&MOb|R^b1{"g7 N_jAjݩV?8sFC)!Ч SR'1jAࣚy݉ Yw#1b::lg1hrwew}VPPa,PͺE>>2 z\ϚM\{Ӽe- 2 gK6/endstream endobj 427 0 obj 2451 endobj 425 0 obj << /Type /Page /Contents 426 0 R /Resources 424 0 R /MediaBox [0 0 595.273 841.887] /Parent 419 0 R >> endobj 424 0 obj << /Font << /F30 42 0 R /F15 7 0 R /F27 77 0 R /F28 86 0 R /F1 107 0 R /F25 87 0 R /F36 6 0 R /F31 93 0 R /F26 94 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 430 0 obj << /Length 431 0 R /Filter /FlateDecode >> stream xZKoF/{Y䬣b`Hr`$*Dʤ<3ίOUw",# f?ztu ?6a.' µ,6WF@#N^0BAɊwC9.?RE)czZoY߼:/wu/}BfdᗝFEKBIkޣp$G"];LP爖2JLK'Hftw2sv_MbA�#1nPu6nz߄3(l]:-M^6EU6P$Bj#k]Q`�Z"gs8^ 6#aZYI1bZ!F1EV.~)pBYsYmb&ciwd3؉oE{mnd:| `MUb-vU݄ҫR ܒ-l.6w _&R)`U$t^Tlk^U.Q[°j?\ b&`H)qՆ.ҲYo)#k2NlV] D1[Y� ztx|>o&P)B$ܴ5ۉ!΄v…q"0(E-k^~nbV/PPTIR�ZV9 9"Ā!$p[JW?%AELuv\#P@0?~dCXeLeMKv4[Pj{h�}n ُbۻ,LV\Taw"�S62sTT Āۚ8jNieCN_ĥ5�k ,Ÿ'�L@LW 2*˧ z7ajGb m1V_|}}E9<%*vRb'.�Ѱ=.cAH<R MmnD`My[1`J|vi􄃒) QR@L-hX9eh #WD_&L:J!8A8`_"͕sϹKޚ{MZ7-Y)!Y$?d: vXBj$u-;AJCy˽'sZ>$lE œ0 :Ё\% O=G^Lω8e>u2 _Ȧ�}JUpHFAIg2(č$C 0$2 ֵd]8ANmZJ۸8L3AK먓=E(u$Yx<bW3~fY{x`BjǴ2& O 8<EH*x@LOZi:IEslnEQ"ayy$Ms`DAD?aMk0ڊC7Txl_dsiُ?L c¿R¬|PA &:Kpfj1O^&ccAU$`y ~8YT) g(PhAӵ>DF'8C.%=˟Jܹ;35n_W4b\vgy_C򺦾T zeaz%y3:iK6: -?0^I%38`gV%tl#{Axp Ë#_&o-3OpGXBn=>Y/h:BaxD U*\!LsKP2:0x@ &w|`@ !ZX`OF /xnS.Kww*!x xPQ(ǗD` :p؍6%3]{2}䎋LSE64N\BS"E{r|jԶ.<uE۔&ŧ` ~HY&|䙯0KO1ru�7 PL5v)M| 弜Α;=vK#4~L8W%\LV^MV;Xۂ0]^Co|uỷStw:'o)."[Fvp$r}:l+|X a?aKR-̌FH528tXv7brendstream endobj 431 0 obj 2177 endobj 429 0 obj << /Type /Page /Contents 430 0 R /Resources 428 0 R /MediaBox [0 0 595.273 841.887] /Parent 419 0 R >> endobj 428 0 obj << /Font << /F30 42 0 R /F35 43 0 R /F15 7 0 R /F27 77 0 R /F37 5 0 R /F28 86 0 R /F1 107 0 R /F25 87 0 R >> /ProcSet [ /PDF /Text ] >> endobj 434 0 obj << /Length 435 0 R /Filter /FlateDecode >> stream xZK8sa\|#YIcf9m96ƶz$9_U|ȒM?,fEt*~U)t?:HFG:)>mn7Q9X)G 7a!{X g:<2+U v)x+}cVmvm9aq<ߕ.|wLVМ|4aP-b43jamr b׉Q|dHnn<. s5o<ܰHa˜p#Gs.F9֌rAqk)x' -&ayN1,*vVb%Ff)kn *-R%K*_ۤRⒷHmUx^ss8Oj#s'v / Q-s[+좙eub1M l漑LbEF)`T LҔ?nmB(!) 㤧b&\D+T!ƈ.24cحmo_\heٔ N# 6 )T@̞scyzB'1<pԧݺhWfmb zQߔ۹QmU͌& eS@3mgRFm_xWMTl԰:8r.ƪA`�CnM1D 9n -X@4pu9&qB"zPMx{%4h!0>iZp]Bvn@aF*_%+pԞ&4cpĈg` $hc9B}¬U'S_N-i%\uZ:q DloB j@&Vw(#{yzW9.t#I!Wٟ0 i"kEq9h=zWӬT�6 $- v?(I4W_U^Tx%�]vT0T=6e ;WMyZÅ@r+c5!8 Ncit{YWd<QTh}=cO; Q_EtLj?79Av1)ؓN~)˹&8"LkB ^YNZN 7?r e^P#\2W*goNA0Y~̪Y>XQ&2+HV=@YN$}8YaΗd˄<,=̓kb aqS];*8xj=]Ou1+H)C#.pOé^_ 1�Y<]eoC׻|wɳ=8 5]9V:~.i&t? ;KO/pҁb Y\3&8a]~r ; p>ИJx9֓Yr1�GO@qV#va�"tS΀tG ?4ҖF7M s6o?PB ӏD0= m^|R*d~‘("ѕ}CcD!8yyʼm^~^ELDfs5nEdGƿ^an]zm<h{U&mulzY 0:¾lw5T^Jnm"ZM %$Q*RECt s2K2q)yGQ@{|_*xa!;/>`g5~GWKӕ <ijM(.ihH8K }R$ְ_fk]G2Ubt"C|2h<56!K86*&O!L&b\qX$j]4Yʅ3΋]m z+xzrpVuo>v:YRlQ@+ b5 ChW{[7uZEt{pk,¦$X[sGwwA(ձ`;lt>|rF}oMLA_S~6GÊj= v 'hWRU;Ճ\mRm!Y}NF{bl%d/i;qev.?7HBAT f'EP:PPƳY*EXV|XA0HϰN N$;;혳aLq @ sjG*c+6_|)uSmR4d-ۣ*" 45bX 8~, pqǮ("uGz1령/m5GRkNŏOu, XK"4@jdsZ96PC@gr70qեq[߿!֧b4~-!DW:(]R4PphWbuoR>r*)# @ iN_endstream endobj 435 0 obj 2523 endobj 433 0 obj << /Type /Page /Contents 434 0 R /Resources 432 0 R /MediaBox [0 0 595.273 841.887] /Parent 419 0 R >> endobj 432 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F28 86 0 R /F30 42 0 R /F25 87 0 R /F31 93 0 R /F24 5 0 R /F35 43 0 R /F34 5 0 R /F37 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 438 0 obj << /Length 439 0 R /Filter /FlateDecode >> stream xYI9!4CX}qCd `" I-yXdTWzX$#BPAjo*#Nnޭ/zuh-XwG2婫pua=,-77QwMwlV,~7܌aBm &0NQ8�>%j>@ͬ5ů8@8QLƄKC ^p c~X2m23JMy99ӔX#@q VҠ SP"-ں<gؚX8PUc%JBU!c-j{T'tH:qA4 cf�nD_vU[xC!mm{P:F&6ɓoi2X=V0/&OF̩ /}8VclP$Sb!3t4m 6NX˜U>qXD1މ!T:'@e/Khy(e"<M| .y BCPMHyVY8' * t=, 0&<U.~_O/,LKsI:v&]0ؿUhh,™SsI ڂ<_W-ʤX57 R":�q_E"aTUfmqp J7i"04 `�O;ڻnF\5QWx1EK2sfĄty>q0Mά�Ɛ8 2" K�:mDزeW[iKd.# E&^X^Q /+Dw/҂E-zjC0\tU(t&�|-ClԻള Ex?"PGb(Rrb1m;K۟(Fv_f.2D|K QRU.z2z뭹 WoSׁpe0ᴍOmp8sʡQ O8aԷDrxe)p[6q>UD4C`ώCc` +R.�:QNbfJ{[>_~ɬ(BD۠Wyo~ k bo5#H7Jxa_F:9�O X�B'dOXN:zM4ekgv 2ey@یa9Ee0xÀ`/%Kald'X�[50xMe.Q0U87c4hB�<S\{AzfR=Z9//Aœ(� _ed�P@8)NMfCL m x!w>pzm0т]Hy`q0k} BJ: Y42Sw/s ʊ'Ĉ{Bύ @vpnf iLFCUsU֮wq 6GB !+J8=M ?= b ˪}_RSV`؇1Sniϊ0⟹Mq_,AOw6m(;NH}54R ]M}*fhfZBYw܍)2{e.侎C p v:PLćҌI} xĉZ9HY6r" 6cd.˚0AX ^k[V?$Onl<G$w~J,ܻ҆%/?qxzrl<џu;*Y ]F=AޢK%xUr]/XhK/W5PN rBW=` |2\\ څ(; ZC6OXRS[]үد&#X/s+To{2҃waɞ1Z$ka:TXfwͪot-24:"3(M<׬9=}Jn ҝұHTuLN(|M8Ql =OߝݹͶ9.+?~= sNnbU_-1˧&\٣0(-rDH2P'+Ɓ+14MR\sO>t"wzX 9 .h&7(nz2'[vҔgK'M$/ñҧ*.F͛\ )HM1Q$S;[/rGz3Bns 1{-dGW~]FɦsgXW$)"plbxc#*t@ #*/`N7pL p{(HcRCVG+/l.vh)CϷyO4snUP/T: BHS zj?)ۜPZdUQ Уe_)`Sendstream endobj 439 0 obj 2571 endobj 437 0 obj << /Type /Page /Contents 438 0 R /Resources 436 0 R /MediaBox [0 0 595.273 841.887] /Parent 419 0 R >> endobj 436 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F25 87 0 R /F31 93 0 R /F28 86 0 R /F35 43 0 R /F37 5 0 R /F1 107 0 R /F30 42 0 R >> /ProcSet [ /PDF /Text ] >> endobj 442 0 obj << /Length 443 0 R /Filter /FlateDecode >> stream xXKo7ٗK.{-r))P_jurwJ6n>"̐cei^*ע-~>=zJȂ™*N/ "'qQ.u[ώ'r]u_;*}>H_rҗAi9m8t<nƏXJӮ,预q?+/)?%gӅ7Л$2ԫ|K}?` S7i'/oUUm 4 ?+  E %7u\no)E5'NOE:S%\gf0+Me)TJ/퍌R>V3xeڃ)*Wt/-tuqi{',6c ^M0 sd eW->z$8L)K 0e%,MfUnF0 2Njha4[-A檟6a8š75f^yrٲ¨+M D[WNr+S3Pet,9Pk87ʧ]:䱽\qЌ,+[ z$ DYRT.vqrX,u> ^uzc 7p0Cp,h:˄qxb o)uvFDZvoU_D#=N1ND&edHb(v{~ѴHP=3{q| .pZ8\s %'gӘCK$v ´~w#s,j݋\hxH&YPC :egޣF]r/4H>R4v^Մ#G/O#{& Og*.X лC G( :<6@x[tqEQcZ&pUMz�=4\iο^/FsH3b@bJvޠDZnu8sN31*h[0լ@".j|3c&vq}}H>#ݽ+ RȺgeGwb4^lb_/|5eht0v@]@0.-6<vN֤g.n*JI!NZWi}g%A:>˸fϦ8a"ہzT2yq¨#~xzGz$ř 4FTcd*ݙ};F0Uw8  TT>5A%BrB8]l$p^ :3uR$UQg}cu`pT{c Qp[k 0a g^%]mysr|3YLU9/69-lyDK;FEXI Iʗ#F~gj_M%;xnWEeV7mږǙJ'jgz(01Emy<0Y3giuv&O84z5 }= cwQVgOH_FCȝݾy < H7.j[|΃(W(.0/Nt*=IXw\[7mxw'ͧinM60F w|PJjY1~Dz= }(�dc_{*9,rQ_S?, 56PڦNQ'�Bdaendstream endobj 443 0 obj 1734 endobj 441 0 obj << /Type /Page /Contents 442 0 R /Resources 440 0 R /MediaBox [0 0 595.273 841.887] /Parent 444 0 R >> endobj 440 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F36 6 0 R /F37 5 0 R /F27 77 0 R /F25 87 0 R /F30 42 0 R /F1 107 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 447 0 obj << /Length 448 0 R /Filter /FlateDecode >> stream xY[o}C &LHNlA]qm %;ͯ77FMSՈs\1-*eJ)^tss *[o6Kʉ leۯ8/w5ײ<4a_>NeA)R_#T)/m;Lذ+Swu m6욺݊o6a=Իm3ZTKݾ[C]k}{ v&BLLzŜ'Cxw}q &RZh1DU4:qDqh,t۽?t۽8rN4pyE*ƃLP2qukVHc(!i"FA%%fdhRQ|<R:ItF,{9R,kF%roLҟ|+XRw&[4M}S4.K"x9wCXĝG;ޱ "C~U|N7v͛ڿeLiLֳٴķ.TM-JXScq8sR?_?)JcE 5vV1W6cTim-RC,|f.QC*a:Q(ulCmNӪZQʳ:I߸ W_\Qc.ִ䰢"ܚo+[*b+XEB2Szo3EYb6C{xsPXքFKtwVbIpA6LF:N)j͓&rv͊5krV>klW/n%|HF8'EP@R="8BTbNZXGM4d3 1e9@ ϝbAa8Ycˆ?+2U> 2 ]< : J,1dݦ#u4Oݦ/xt+$⬭Z .Ve'8q>#l qөvXu`[gmZfBawmІ,0ҙ1+I;)on'כޯYy_~04YT]a7F@z-!~vUdaR65>&+(F""pwoN]Yx.goǾ&`!Knu!}SSΨ.9r@Rw˜mR'u@8(!D;Gɪ7yܫnNFaIcO+<pV“9JdΜ)(d:IvTT8[)R~n}kROq҄(|`Kg {OT{<hv!4�ƭiW~tڥgs2zf}׬}Ͽ/r+_xD)-o N}Qx*e'6m1*V%82ON{At%g ]5$!'K �ۂ0;cNk q.]6x΃Pg=,ό>9"w(AO&CZvf`;;\ jE@m.q_MTM63..kufӸ/dg#) .�+ 36c7�(ZkzxAO EɈh0Yvrc,}fJ=fBF-Y4%!fV$< bUswKg�?<Ѻ+ nYM++9&ƪ%+[+e cR<8E^M1hƗ);]$άXg2qړgce#3od(*P,mȎW2!rѿ;a �0Rس>m:I½ nBͯ.' ٴ!{r?fTy4륧\ntyWE?5uz]]z^W w=fE)!Cnv|BnL G]LZb<Z4GOwF.x>}tDm?5Zh92^d2�c*abؘX 'w<.URM^/eFysTq!01cӠh&J$~Gَendstream endobj 448 0 obj 2150 endobj 446 0 obj << /Type /Page /Contents 447 0 R /Resources 445 0 R /MediaBox [0 0 595.273 841.887] /Parent 444 0 R >> endobj 445 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F27 77 0 R /F25 87 0 R /F31 93 0 R /F30 42 0 R /F1 107 0 R /F35 43 0 R /F28 86 0 R >> /ProcSet [ /PDF /Text ] >> endobj 451 0 obj << /Length 452 0 R /Filter /FlateDecode >> stream xڽX[o6s^(/1˫H胓4H$P(AX-y4w(Rp%@Ds΅! dJb:!A>9b|@$D &fd~pDeї:mgj8bFsxٮb8 %�.Ĉ*8I4@!h1̐(ڕ]*ܾΆTFOnE^<Nt^ Ҿɭ\6r89UjqS=8F<?5(f9Fdš-y�!`84D%qNt{(R;yNI0bD3}J3cԥQ6[sif?++WR\JxLm˵OX b`3jsX|Ŝ~y3˨mB"#yG왏|c$ P(ˣљ0f߭_c.?~ 2X+Q*'$k'+4/Z@t6tb[lA1y!c)d@ֳ_,^h)Ĵǐ5)ucc !A=.uCh )n p$h-mw6˺I< xgܪ跻um^ۤRrGy#<_8@"~JݖW~"EOҟUO=yq#|S(+eKOhvYCrWf ĵ'6jMbnz"ml]oQ,צQ?m@4AltaK \U:++`P/;5X"�^XCDW2VX|4*tNd!nsfs$'x�Ǵۭg-^smi|`L^!)RИ=$a&xt1 Ȕce43X^rz5ZmTѪ&gz!"i+ɞVbYΜEc7qnʒ'0rf4 *ȋ2!^L/sr�S= Ғ�5_ @tb;] 5S,m6Ms (M^�k_ؐXN_'`_!Z Ąz �XV-c>7$5;VgSgfYEifK z2兒}o3ߗCTW1"M=M0&킴S' LĞ ӑ !P^td4>6~^/!sFٵh!Qi%:%ٵ #,xOa{PVZUq˓608t0w|@CUr؍) &)4,|+ #]endstream endobj 452 0 obj 1363 endobj 450 0 obj << /Type /Page /Contents 451 0 R /Resources 449 0 R /MediaBox [0 0 595.273 841.887] /Parent 444 0 R >> endobj 449 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F27 77 0 R /F28 86 0 R /F25 87 0 R /F30 42 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 455 0 obj << /Length 456 0 R /Filter /FlateDecode >> stream xڭYIyr)& Vj_(sChM=hrjS1�ST{[Q8LH<73V͖?g1)~ޯ~bvz=tB9YukZujǾp:0o fB3m"Pq)$eC+Q5+"fz/c7@T!X0Y⅔L <ә/dծKW}N7`sڻ*ӗإN/'n 4=u:MCr&@uv$q:#lٞ|(KFm*{$PSvҍ\7>o�BXp1 U!vYuL�<&en܂OpFaӛLƟɐ|D  =, VCfAc9{G"K϶~#J΀] p<,1#$gf[D >,.{*W`D'Ŕ#>H< 铠/μ9BPgF2$;Yw"',) CAsXsQ7pB"6yxV\0ȃnWu[Cǫb|An-ULqp}9rm:`dD 32W CCИB@|&g/1 (}xdad`NX8%Zh(J%P+.?o)(4�4uR~I/T#Nfi#c*h*TN;!j2uZ?͍ cmT}m}(`z9]0UuÈsx(P 9'VA"*(xs`IENYH~DJsImt'MlfRC{H/*oU2<P˾{(#0T# Tc^ƛ91`E,ГiGO~,95r:upFFfGҤ,I d]2BteZ6],@HR{BIdWi��FT?äMx"NNB\tT}6ߵߵFL'ڻ`]j&ӦGQ1o*$0 IU-.6e [M[ZBQ|$Clh_uy]3S7K}RD5Ѧ,;:ꜚpQNMxSVX9lIvI7&ХOO2`MkwY%r0J7c0=.a/&0 \ѝ}d9ɣsASnQp$JrzR%{SuS[K)ӣS+RcʗH4}IHgR3TuUq)RS4c5*T-!;BET6 =;njҷ3 :#�5]I֥٦CM*}.([?2 vb*B[27Op> h ;GZS(~xca2Xsll΄)Iqt8,l(jנ#Xeui=r H~νȺT e1Hq.]\Z1[S |KIsz6v09lV>&_}F_{6018>Mu'nʧߦ֎ѻU$FwBgRz̗y՟oEG>S:NY}W=p=F^V\`tҍK�P^M xbr* @echZXґ E u6pۧAUAIas^k)'v" -%'>+a0x bW8)dȑj{b;h ((Kh=^w%TrG q'$ıCY"Oč{o d%LL eu?:JrQwTh/5jk%[Y:2eFH?qzЀؑϢ$HUH25E0ɴy]絨)$|WOH:Nꇣg)zPUp; cCendstream endobj 456 0 obj 2111 endobj 454 0 obj << /Type /Page /Contents 455 0 R /Resources 453 0 R /MediaBox [0 0 595.273 841.887] /Parent 444 0 R >> endobj 453 0 obj << /Font << /F34 5 0 R /F37 5 0 R /F15 7 0 R /F30 42 0 R /F27 77 0 R /F25 87 0 R /F28 86 0 R /F1 107 0 R /F31 93 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 459 0 obj << /Length 460 0 R /Filter /FlateDecode >> stream xڭYYqG^Gʁ؆0Kwij9&0Wm_U}d3?6 k1[|afL!~%W?LM|ſu[m aT<tuޭ›զ;q/ S3Juj-+X6CxeA7Q5wf[gŲǶ9²ǧznsnc]KY*'Q1˹fpE@̤򳋃)ör9ZU35 v k* c\ҌHs$3gKJ`Ĕ‹l~ͩeDr6H}s7>j3s;>4pmTQmO?׍Pr[u]zN}7,b`Z~Sr*8㒋 /\MfP)X\YD{Um88޻1vu7.<*â1%XUUcGKqa?E)! "gcL^_"-!.4+QO�E0h`ߋu(J D8#LZ54jƱ3i~۔%L-^"`<<c)E`,TfI~ :ZJ87YP/E§`H|b b ;@w'2ꤱnK;k^ę&tid}7xD9qfZ,-,"NrEeBDP/L'^:$A<#L+;vWW"(]~Y0;aF= 9 =O:0إRVyT.'}:d'L;7/wn뻌wn't &+(sjKW&ѯ-Q%{~f7%%i$al>6m.;&cx1dFQz_$ 0v|Ip);è*ܧ`.90ʉ91ȭA+yէBRB"L0\t.1bP)8U]6Qu% FZy$r9K-_.c"r 76PpG'vׅW+}=[g pTsET˯i~&h.&p_Mj# r2GK``4GyH%zgzzXaWx/_f8[(:J�8l'$_')<"5izjqH y+R%dLsQ"%,u_dϣIt/%3qvHpOO~\<\jAW oե,J3.HFWo#X>LO+t(n]뛰S5ιE9[н1Qpf<1fCxkO"ȸdZE5|@#/u6O9\$#&p\?8qdH]$4`ܧM2J0+~8d^ n7+tbt-$̔N4u,E@Da&]�\MSwppWNnclvm=$b!P!?6]l}�%�Ż;C/o[=pfέj_xs5Xhyί&>_ҌۛgLjbfOBp2;AT/A? WB2cf.E' P9熢0t>%ui|ͪDz±zpƆl8—01O0M9Va&Yj[[TENt5Jc d~8b (f#éc]J&0x @�`(-7=N~fqR6 �fxߋ}YO>IB#�|oQ; ~Zm~ޠ)_jLj`Rإ+^Iф5Ah*I3?͆,pEIC~3w9Q|_c[򆎮ŸHGIZnUӸ7n|S S[ 9R g~w q^mzylA mÍJq $#M1豼Mt cl<MdԤ4?a%endstream endobj 460 0 obj 2178 endobj 458 0 obj << /Type /Page /Contents 459 0 R /Resources 457 0 R /MediaBox [0 0 595.273 841.887] /Parent 444 0 R >> endobj 457 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F36 6 0 R /F24 5 0 R /F27 77 0 R /F28 86 0 R /F25 87 0 R /F1 107 0 R /F30 42 0 R /F35 43 0 R /F34 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 463 0 obj << /Length 464 0 R /Filter /FlateDecode >> stream xڥWm6 ~_0zS@7`-u.F;{#E)qzIu8HD>|HQbŌTffbP+egB3:.OP21υ2ٍ\s%D6nlY ?À٪\ ] <hko3c*,UJo`kW~@ *cа<Iš?w[VSm]2ce-e;wnW:湴ﯻ~9|u8޺D)|~le g9l:.�A3cJpiG6>j8~ #4#0湩l2Dk?s[?>xLs=ѲF\Ah5iqNw\-D/~�B0jCςpx@ޏ:d#IqG#H5_è:P|6n?LA:陀:y{%Cb r߷y,4=X꘤2&it &J[Q0 �9QqZL3fhL |H0qD+RADch 9rt�c쇦INU$0_P|h6cFC3|glTͻwUHiiZGd�*vBTeGQQ)QH[BC>M[{,eۄ-#kV6k52`iYCyꖃ)Buc�pýhwϹeƨ3Ca69̸syyM=W 뺉lO(syOhIp4|UǍ :nH!rOW)>! Z?He7jYY)/`FU)+NJ$~GJHqI!jUuBkv㉉y5U~.Vv0ʞ3| a1!I2 '#2P" QŬ)1r(Lu҆ӄG m�BWΧV s<It>!{.i ::pN[>+~r qa!\"^ͦj7:nK:fHĬyy)Dcv([2NލXNPz9E1?səDXhلS68\cmPI&oFxR]{Ej~L*ĸ` ľۤoXC#E3(^XSޟALٔt[p@9$"eݳ3?+VYUl]ǿ?xa@~d2Ag4m%>N|Hc_˹g4 G =D~ŗIϥ^Dӷ;(ǖx�4m |ʭ?u-_^bqÐ.߻u*0l[oS�z0LKM6r>tDU=p}T؁ⱻ@x|u!e=#?J.B+˒J/q@Yendstream endobj 464 0 obj 1535 endobj 462 0 obj << /Type /Page /Contents 463 0 R /Resources 461 0 R /MediaBox [0 0 595.273 841.887] /Parent 444 0 R >> endobj 461 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F35 43 0 R /F30 42 0 R >> /ProcSet [ /PDF /Text ] >> endobj 467 0 obj << /Length 468 0 R /Filter /FlateDecode >> stream xڍVKo6OԷҀR{i9`mnLB0$:PVEg<*?IzL84]==X:Jdwدݩ}N/ Z8?){yrw?WRjqlojy7psp}86ogC`y<a}~/8Q*: <J$ۑꓫ)щ``[)hz#v}cj\@@gj_q3k@: =?tcc_)Jss Vхɴ`'} ֑zt~ 1 E"Gs޺Sr2}XT`x YNSfx�KN]" h!AV6ԬSm\9$;lrkQDܟڒBBp.>GX BAMowLc2o,.e;V ݁ }lOf2{c$VBT d ipٱ@KT2̑nOd7ޟGʷ W 7.)u0  j6nÑKx.|{gqt FmWPBQ+,`ζH뎒`V$իK0O{�/D"Pw]mO]*[Z"U$HzO#eYGbOהwSuU_ |³IE(?CxZ \F_PB!q3.I& } Y<2ES2|f} 83^XLXs0_]M9Y"Nia sf,V$a)#c<6U M( JQصTN1Z<Bڥv0 ]}PsuPӇjB=(Aņz0cݧ1 Pqhм(sqlq.`;Rj5Ұ4 Rg\BX| fI^ (UiCl|UM;,`H޸sraܑ ǝl>�&?lNGwq ,h1@a:WZkkL!< è_u56l逺]ظ8m 4VCa,(o~~Gendstream endobj 468 0 obj 1254 endobj 466 0 obj << /Type /Page /Contents 467 0 R /Resources 465 0 R /MediaBox [0 0 595.273 841.887] /Parent 469 0 R >> endobj 465 0 obj << /Font << /F35 43 0 R /F15 7 0 R /F27 77 0 R /F25 87 0 R /F28 86 0 R /F37 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 472 0 obj << /Length 473 0 R /Filter /FlateDecode >> stream x3T0�BCcK=#KsKS=SS\..}7CSCC=KSS4ʐh CC/..� endstream endobj 473 0 obj 66 endobj 471 0 obj << /Type /Page /Contents 472 0 R /Resources 470 0 R /MediaBox [0 0 595.273 841.887] /Parent 469 0 R >> endobj 470 0 obj << /Font << /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 476 0 obj << /Length 477 0 R /Filter /FlateDecode >> stream xVMD׹r#pow@@X$:qĒ۳;T%lg'Br.zUtAGZb3wWo_0ы}\50aYqW?I% Dڽ@= n~ _rAK/16K Sqfh ]2_h4x]ȶ]w."?gBb Vlm!LAaw ?D6>[bQQPp }x%3D_ t6yЁ A5#qx,F懶luf�,+4{|\GQO1YF8 1Ƃbb.+JGoS(--\waF0 7&"h ]p 8N�m~璋M׏n3&C66[эBz=%I)fEFϩǹI 9ӯ#P3TXi Nb:X`B$oJ8 Fl`CX:�Mh2X?N"3 3Rb 2  %HĖ%qռI%=vF}4m>4,$60toX΂Z7`ϛS!,Uo eMx*̺R:`wb4:,\%XoqT?mt Gg V HעAJ\/HK:ad H?-`m^U: p .Kɫ` 02ȗdrߞ;;{4 |G⟆B@S{ƔԾ�!:SL彄Cdu7ܻmKgWG煬N;t3,8ijt'|˅p+N:|PϚLbMK2B:{v._,4P!>ĸ9kɚ|&i#0K*jPvANG-CPUTI?) Mw/ endstream endobj 477 0 obj 1080 endobj 475 0 obj << /Type /Page /Contents 476 0 R /Resources 474 0 R /MediaBox [0 0 595.273 841.887] /Parent 469 0 R >> endobj 474 0 obj << /Font << /F23 5 0 R /F15 7 0 R /F35 43 0 R /F34 5 0 R /F27 77 0 R /F30 42 0 R /F25 87 0 R /F28 86 0 R >> /ProcSet [ /PDF /Text ] >> endobj 480 0 obj << /Length 481 0 R /Filter /FlateDecode >> stream xZ[6N_0h_dlŊwEb[}),t[Q_'=$%,{.Ad,KynwMg3*(Jt S|^臭QJw~js.|nj]ݾ~3g"zhb, 4aX-*TKdʈ`7�@e;a /1\1SEV(ٌG& <I&$vM٥]@fș4ĀmcݔUK2©܀l"wQgN(f0֏an ϩ&!T{ONo)›[3&-A y.@7J4DBvsgbHŒ>Tу½#aՃ%wC:wx@=CH$t8#Pn,p8Z܁J$J F A8(p0C5<I<<ZhqJ'c/7 )t� O*>zdĚaĪ$b�AI'‚0\141pp Ɇ cPK4¬$La蓵7eZl—. �Cf{d:\TeH!/?.}YU3QoW\C"zNRF/(W #91Tnus\Up]PzuԘ"RD:laT�_1:)ETDs6|g8s$)V7 @!hO31hq MO<Dku&CplS; ~KPRLQjy y9AC3Tra=xI%t0%YE٠Z]npJl߾=() C\%͓"{p54}opjx v[o=䃶 x#d[d-jgCͳ)pcYe$k Vخjc5+!PBCBd@?a(v?PD1P9;2Slj@ $ShRY1`V}mgy؛(m [vb\x/nvKLY aUU^L>PwZ(;^:Y@n 3 /1Mf0O�s1%ūkתU%}2ìQpؘg*鑒9y,JD&#ZcZF \dN Q3]P4B)z a_ϡ@GD,8!wQWiprn9j?`QN�;kpxUfb:حrEk3ۭ4E()*܄4k+$tTmn%!;I2e(|,`my{Z-6W_Uy(+`a#FɌؕbn2p[UoMyhQ OSaVqxM¤~b޺aӺy7IYUY2U*?~nX,CSiO%CPܭ7M>ܮ0RlIhf^ ̹A›0aaOGA&ɮ든YTA5km]=%zjیҴiꓜ`, pc#D \�Mi:=YFJ/$oZCRZ" �Q] QpIKSa W5MfiZbzRuUeHWB>u}�iVVje^;+5͈1}t$D4va:.,\=kzM &+ۦ5vyȽ֞d܀g@I` ԇ2ʥcxj92Ĺ)CQZ#8%?Y=7Ao7ɥ9KsRw+bRz:S3GHyZʔcC'BՄޗ¸$V 3rx>iҔQXK}F!ZǺR{=t!hS uP ؎ .J:zY d5 13ޅ ՘ݫﮯc[,9Y4U9{wErĪwvhajy\7'6Z3оwM 9ӈ\fP_<g\oE dBfo_NSf/�yjQ^=jA K̘(vB8!Ǟ8+u2:Jdήb)D eqɕ> @@Og5>bsOC0X~vg}?2gr3c"O Џ2̃;iL6@<yPU~@;= `.?󹀲6jendstream endobj 481 0 obj 2381 endobj 479 0 obj << /Type /Page /Contents 480 0 R /Resources 478 0 R /MediaBox [0 0 595.273 841.887] /Parent 469 0 R >> endobj 478 0 obj << /Font << /F15 7 0 R /F24 5 0 R /F27 77 0 R /F30 42 0 R /F1 107 0 R /F25 87 0 R /F28 86 0 R /F31 93 0 R /F36 6 0 R /F38 163 0 R >> /ProcSet [ /PDF /Text ] >> endobj 484 0 obj << /Length 485 0 R /Filter /FlateDecode >> stream xYMoFهֳz*FfRC/5M2")W."-ʖ0`ٙ73oV4#1\2alyqɳR2Azvz$O_2RLDBf/bn[o ie>O]ύ̊M]4j^b[g! օN+|KlZe7uֿ2YUzUn ;X4ge 8_hQ,me<׳1 Nhhؠy>`J$o7e˸ӆfb;ë'/R;f7u{>e}3 ™2G`XLwAEiuf9p,B�P 2.j:I%!B1dt/#sݟӔ9QQo C)uZݞ.YnT|d.dҽ*ل ?RHn>Abd4AHL1Rڻ!I݉ uXu* c26}6ظ7Yx1%c>2cRM(2D2h\s#3:BJG](8L!X'@ 9)m+&&OoC~$_ϵΊUL*&Xe)1߹L,a:Qabs7ThNHDT[':*,#bIhaa1=,O:i;DmNktLT) 3PH&.ٮbiͳE@ߛ9vi(16|^lC Mc`3'-?2% $WVo7UG^I_IGa"Ì�_U]K@;g=>rҒlʔ�{oI?27T< )DUD?$$!C)wzx9Z2NY1n,WiԽ,wK~dkvƢ"JEYm}ijm\U|o WlHZdXө{R$. T2}xx8;Bzx<!4?zWp@J!eKyO:eef Z1+�WTSwT}]eQsq.Fѝy{PArTxN*)KlݔQF8՛pj3)GČA^2 u_ifwI aB*f*-u L)ֶham#'E ~uPwԙc vAʶ:B;F;= h1G貔ʧ+NijT[HtA'Aeh(ٕs]#/($b$az7w"c(Zbܯ;QTͮﮚaQmxv{9WTAW6aA鼵9F{BJtMg[`iޝx3_z`t.33%Oԓ]B)ڗktYW\H RQVm+D 4=Q/dSELXyx{[dk93{>AJ$vJ^%G&J<BB3}{);RlNa.~sL6%" |zR\vaoDlF}>(&@y%Ģ֧/cZS))uSV]&(+*ͪBVDwT讴̊Ս",sކ1T j 1o_UqZ^m#9 )>`ڸ "dF@endstream endobj 485 0 obj 1828 endobj 483 0 obj << /Type /Page /Contents 484 0 R /Resources 482 0 R /MediaBox [0 0 595.273 841.887] /Parent 469 0 R >> endobj 482 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F27 77 0 R /F28 86 0 R /F1 107 0 R /F25 87 0 R /F30 42 0 R /F36 6 0 R /F24 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 488 0 obj << /Length 489 0 R /Filter /FlateDecode >> stream xڵX[o6n_Sbt_dby'E.:@ԇ(LR*+3ͿߏٔL'ng"<:<\Vl$#\ ko#R{Oyb~T7+ 0<QpJ~]=}.X盶ւc`3&2RLQ"Y83 [=Ͽ~.pSch؏r], :}v|XپСdHcpa?@]4;hA w3HRiK)T0{#?knN³KF�H)MW 7(RYfhޅ9])7<r9D 20WD!TJFL%^ZiXpcВ4XUTX86$RE=uQE3Zqô$:|q&DWrUf'ztD7p+80-sS�AcWCa1)-%Vc~i4嗟tr.(܉vc.+3?YwalKIHe }=:4< C?WD-M}xKƧmvFx ]. Ss"0q!]pD{Ak:<}o1 ~inE @~pxJ"TMk!@B8*M^n;4s\ 3KP* :1ɖf8;li,d8\ܹdjҜqǥ T+�2=Nô\u <^k(3p~2H*٘`%.ih6!v*"DRc={W�MICpNUdh& EEW=YYkay՟N3�;˰/f1<6dy!"'J$Qv6V&F[~L4T F"'Aaۙʿ"qJdagg9I7/B2D<ahiw i[kӼ]F?O咉)B,r!Ѓb?s<Iop&d(/weq]CJ:OU>h]&^"3\8.gAIOeXw9z�,/57RV2!߽R޹_JD #T֋x^tMWʥTp+PNL95@ş3 z8'UDbo. 10vOr W; 9!-Hc U~`?ʈv9I1Lcqڬ9il'?K�D ql!A~>,ѥCU!>M8BbFCTB ez1$�5)gЏMyjsW60{z:k#M;pn@F?EP s3g i\1媋{&<㧁P`sb>uD:ei~�.̅4l},@5u6„< pdαnX8N~(x2Z}q(TedԡD[?sT28$%e/_\F*Xt0(*\#Ӱ$RWߵ00Lj>fL:M&^VYO{HUoO% KX/YMSs� %h3ӂlbO. d4Ndvtl1<Gkb uRz.nqpd{s̋T&-|:wRig`7n{9SJhݾlm}l)_U t-U٤]ͺ gLE?94au<ֆސ19e,1Hendstream endobj 489 0 obj 1889 endobj 487 0 obj << /Type /Page /Contents 488 0 R /Resources 486 0 R /MediaBox [0 0 595.273 841.887] /Parent 469 0 R >> endobj 486 0 obj << /Font << /F30 42 0 R /F15 7 0 R /F24 5 0 R /F27 77 0 R /F28 86 0 R /F34 5 0 R /F31 93 0 R /F25 87 0 R /F1 107 0 R >> /ProcSet [ /PDF /Text ] >> endobj 492 0 obj << /Length 493 0 R /Filter /FlateDecode >> stream xZKܸ^K.}a =,x�faM#`5;")H֋MȁH M9a/֏y5�R.nțߋ˕Px,rtQY6< ǻaD[}laSٖU_]#t�fz"SpeA?-W4G&‚jAXlzbAai7rř,]UQ~N>j_<GI܆NX&g XPBrGj pnB.dQw<T]Йh?+;^-<G yY祔E** Hi'(/oRa]_jWELكJb P ~T(tpv Y�c!urC`XC'" l~t1Y]*Kan&$\NmJ-\^PqpL-ٰ6 NTMަWtłX Zg xQ e >DHq*.T4Q@Ww, Ղ[ <.\w8$v/uˍE ǂM6`zdjjI), SܖC/87 ju5'vCn.!\ @)r f^W˘xTZB+Ieqs 9`Ƿ3i S(}X4Kj]*D$Ă(N{2owPdwUxtQؑ2KWZeR>ݵ|pX`ݫ}Xu_ˇ^ :z(6S,̇zR q1?Y\jϼ4W z6ڗ{i4X7r 7GhC,Iebh$h]pREQ@6䏃mWo]`v'zW 7Dpa./|MN}D>buN?N`DuUm~b\$ ̫ LYjve~h*GV=Ɛ(7l-M}>;e0E5x3go#|U.+S9sA% AEI%lK8((H&#6 a2^[Zl'\pV>vsPǜ<}'MHP]{'S.WI-2s*茑xX8645y"Ȋb$ڷ$NG㫡7`Ǫvmܩ 7{OhYFӖ#oCUQ$b!XѾ`X6`Xc(2H h˃IM> FL(LA_cgI0-s\ rYgc桄*&1: IX1jZ2 l!C:hl\G;BUCdVJ"4I#,@T9S ~Ka[J'<옄pތ.*MZ_.R\\p\?>bbrz 1~,; AΩ|q [\82 pmqi ى /0nN Ӵ<~ .x3'6mY`q@랪NAHtWcƀ^%BMf46-EۺSH!X゗6Ǘ_^4_(ں\ #H 5ZܽSǍyޜ 1sx('<KicXM$"!ҵ#:&~,C?{\Uf%UL_z=^#EOtz~q=93{ۧxd!CIMȬ!1#QzZ>/9;r.q-ލfVDZ D{5m2ۦ.?6۰& %65*aX`B~Jnm{E9rcgr̲ RlN�NǎLǓK6Sᢳ ٤Pno5%X{&S% }_LvXiW&W"io 8A= =>"FS^H%WXW?j%Ǔ 4wzA�0%/`ΕP8p~K9y R d+@'̹(_!}&YHd2Tvg=S,s|8`kY)8<i�׿�endstream endobj 493 0 obj 2397 endobj 491 0 obj << /Type /Page /Contents 492 0 R /Resources 490 0 R /MediaBox [0 0 595.273 841.887] /Parent 494 0 R >> endobj 490 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F30 42 0 R /F1 107 0 R /F25 87 0 R /F31 93 0 R /F28 86 0 R /F36 6 0 R /F34 5 0 R /F24 5 0 R /F38 163 0 R >> /ProcSet [ /PDF /Text ] >> endobj 497 0 obj << /Length 498 0 R /Filter /FlateDecode >> stream xڭWɎFy.\xI9؀8pP5"!'$%_WH g1fwuWK$Ï'\q&Jl&02Y_=8{ru9+N.Nb!U:*-v'ŽvYr%.IJҲfšdə-3g(fHN2?-ش41qƉ"9V6;`8=S &2$ش 6{g0e떄S$ҫr/`@11L`R]nCY,6a8=ǯk#6<S<ej:qX*sK*LWP׶ذ `S:on-̂^[㮮32g60[fj3f0,@), %XXD8"cFd #D"Nj<d{cb%Ep-�-g,1,/ oџQvğ QƷ1~%ɜg*aG)Į N&Q yȋϷ@ 3Cj,0 ɻ 0V)1X{>,me~Oe$4 {]'XG[(Y0JAP̂]ueW^]e(&)6ə(NwE{u zKrݵ%]Wf Äd&7NaյХu(#OT }WO粫eJj@}Rzh{"9O߻\LDir¥a~h.bU_H{ZvޕɰU[raB$_)(]vZsp7g~f2]Gr w]Pu81|d$.T8>>>\1f1'~fD؈<EA-/ݦn!ryu*ꩵQ_߃R0<¦S*?a-rߤ71iɛ3ŽO=;Io3*u/&#=]U #' :RԵ$63ȤoKGfLCur)gh0 -һ̎ezep41EJCq1V&9DM*14 L ,( N2,*/Kh犴T0el <o]{ɺ5q1x"6Tކ8'  H3 ׋"mF{e&0}z׊nǾрbzSk4pzڢӦ2ٝ1l CZEhJCg4؆La tnz8͉5%H_a{*tLyK'821Bj6cdcv庮 %> E}[ҁFQ&RV8"B\.4 w)$o<�Wޝ #bJ!]3N)$R~?fzþtE@HllM|9Uendstream endobj 498 0 obj 1523 endobj 496 0 obj << /Type /Page /Contents 497 0 R /Resources 495 0 R /MediaBox [0 0 595.273 841.887] /Parent 494 0 R >> endobj 495 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F25 87 0 R /F28 86 0 R /F30 42 0 R /F34 5 0 R /F37 5 0 R /F35 43 0 R /F24 5 0 R /F31 93 0 R >> /ProcSet [ /PDF /Text ] >> endobj 501 0 obj << /Length 502 0 R /Filter /FlateDecode >> stream xڭWYoF~K)ZAZ4A*8YHÉQwfgWdq€b rpd&ŕJ&B3|N΋LNgBH盲*=Ng*1Q_rWL7̤d"\GɷMs-himG᣿ \;kƯ0DYNNSnfo+86`֤5@&#H"{IFc#&?NLq} j~msg"te݀nqCd$6vض->9qD\D$jSО/D׶- D=MWK;|HkZVNs׼@Go*F9x⯾Г!Gx6v5i!^ZҠ@ϻM^B\4KXWxKx蟪ήm=nvmKE%-e6e*ތaP|<v颤Jw>( WfSƧZ^AuGg &>#ʗ(H92,=b%Fha&<" |yOs�2m&?_$@FSH&B-J䘈i # (x�Cb @c{L^.PtOW^EWD׎i*ypxzUb9P1U ajmz* UeSҰB?yNPÚշRbI-``6p݈Z"ڿ1/fHDb e\"bq1}Uԕe^pa4*aR4c(cCYNyLR$,JɘۯjQ#LǂL((K(2DŘ@~qwMt5EUuūC>0rlcIRkj-z`_;Х|1G'~x}XoA:csҵWpA%<,#I5ʘ:2e2Om{eWL2._Ț{-1teQ Y'"q,PT, O=|\Ƕ5x @m{oԄkpגo&D7ψ;QZJBe߬D .h(#_Nqxwyw?3SF0xF+ JK& N="gendstream endobj 502 0 obj 1282 endobj 500 0 obj << /Type /Page /Contents 501 0 R /Resources 499 0 R /MediaBox [0 0 595.273 841.887] /Parent 494 0 R >> endobj 499 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F35 43 0 R /F30 42 0 R /F34 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 505 0 obj << /Length 506 0 R /Filter /FlateDecode >> stream xڭXMo6\Vmk1E)E Z.ڠh|J[Ik'PZɦ.Z(jy3hO,T,zab2V|{2 1ŋ5(.1L,C! JwK%,2:Tu8nˮzgB/`ִr(%qlmlKvjj6,]yT;2&(un;GAS`Sf]O}.G.";fMS3 *1Oa -Bh (U5!o=l\n){BF, fJ]2" ^G9ɴ8Lƣm-.wD_UpDU]v s{>)2f}[} 4 %̽倪aZTm70˺'c}k=F@^" <|o7⳸oK~;X_CLLc9Am6 [e?<КrH_={B:+p48bZyN�+@KL!nS_#;s܋>b&f>_ӣh֐CG?w'4n`%Srե4yJLi5suc�e0Dʼn8"Uz)ڭ䦉vx9?~<J &ȅ|Pr=%y$ οqEV)cb5PE7- vٺ,J(5Mʒt8ޙgI- O&&UOvtX9�U6M/S|8M; ~<p/; d7mv*<C5F!/[d AH)=] Y4 \أ>g;ajpPV.>O ZPAw tw}!qfmQmY3bmS4UnmxH*PIR;da:^hf xJHxqGv=Ș+'!ˣ#s2ȉ#V<*;TCALﰉVZ0iȻ(pV6 4` 1^Mu $N8G(RzqaA}́oq@)V&iCFJNW~ r0c sB4*ve 3X_yź/UB0*ӊo<Y'q8Jx|q3sfS OhC4I2aT~.m1ZHePUF' <|1Qw8KR(ОhOTTVͣy'-R0꡷&LݣjF]lr-$bK\>%Ƴ&o㱛FN)qԏv 9nTVX Hn;nԗ{U=] hn}O=7«;|w)vѻG/pqi<QbfWz_ Y7;fI紙4h8ؠͮua={#<ҫSD)-RX6j3h~hPG{ ^lZx|/(<X 0sԈzkeے UZeCBT7kJd85bGC#4Z&dp2#-.tt*8=P{_۲EO~8Gendstream endobj 506 0 obj 1732 endobj 504 0 obj << /Type /Page /Contents 505 0 R /Resources 503 0 R /MediaBox [0 0 595.273 841.887] /Parent 494 0 R >> endobj 503 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F35 43 0 R /F27 77 0 R /F28 86 0 R /F30 42 0 R >> /ProcSet [ /PDF /Text ] >> endobj 509 0 obj << /Length 510 0 R /Filter /FlateDecode >> stream xXKoFF/H^h-CCZ#T~ MJXM >P|1MrPR((ƉT<~\߽}xF'GG+Cխ2uJ8DA i?JGeҮU}_/xkǮn6{֛p/Mլxr׽= x)=L oQ&M7+`yMW?2|Ѱaמ[i\ˇ} /3 M0rE` #c0*s$aB%D鮎F}cͤңS?5vVdrizY{ꙵm[k3轵IPW$TFGsHPI*�sN> @k: XK|<TpFWPBEy{fLϘQS+ (Q=EDH}#e!&gJs&  7ELsUenk*}/+KpAA8pU]pK]kTL($RGUaT)$u9D ĩ f[ >x5|qj[\|%$8{jfhz]8m<m bOƾNۺz(^hQ*yi){qXz*: e 򾩇ݘQbnBauΈў8,(򬰾 B Ц0op}M8!D01Oy-SyrzQ&Aw #13F<[*b<-r/ m/BFsCrc0pfKZd--\PW^~0WxTJ4 Ћ*p!H⛋rsa7 Тd_-%Rn#/4?\=TH$=}YeӗuOF/i 8zXסR~@sNLP/MLKa?Ȅ( cٕU ~ XkOnlߴWۇ| gNDcR61h9LOح~rT6Db1'߉DZbֵIѲƓHSLB @|(j7.V?-5A P1E?v7yJ )]x3[<˦Řh!h>iE˜r 8?Ǥ$r mK)i@O+70azKI;nd~+밽# py9z@fȷ8hAŏBە$F KzaI/-IlI:/YWu^dDZݽ[8jendstream endobj 510 0 obj 1330 endobj 508 0 obj << /Type /Page /Contents 509 0 R /Resources 507 0 R /MediaBox [0 0 595.273 841.887] /Parent 494 0 R >> endobj 507 0 obj << /Font << /F23 5 0 R /F15 7 0 R /F35 43 0 R /F34 5 0 R /F37 5 0 R /F27 77 0 R /F25 87 0 R /F30 42 0 R /F28 86 0 R /F24 5 0 R /F1 107 0 R >> /ProcSet [ /PDF /Text ] >> endobj 513 0 obj << /Length 514 0 R /Filter /FlateDecode >> stream xڽZK6n/= >HĈo2E @^( 4=hm9+@t}ɢLbof/2aDBfA/7Qx|q3o'?,;GIQR7e,SJDܾv?#r3)1"W#ƕSD�&' /b0 wi_.& _t4ӗ(xCLHD!`uFتYH RB8"-HI_A?YWK"{mEN dwMA)-Cܬzvz>wu+\ϻ޵%Ėf`:IV$T'#Cj; 00)BJBTE :1]&ꘇd;ݒs#s&>GX4�@Z�I�@Ͳ<a󧲪s<25VelZLepR7҂*ܷOewo%vI'wvm^:+7QRhpudz HIE6kg_ʩV#覄")+%d>(br¿ب9`h,ZV�1яqp�uvȤ/iđ �{1ugN@E$5 z\t<Tdͦa]m!I:ُc}iLJ4P&g|`s N)Y+U^;(Gb6d_QgHsL{u)* IvQ=fX9@yLxcU(<"C}-J }č }s@jB|}E(8], Is]0gSJPZT0?`L1KcJ/i e}iBРcvyI/u9gC H@þDhIZʓO2IX*}<JÑS'ScJQܨeT#OM1-)\0l^6`]ɫ$eً(GK]*兼'�c?[I\6?JHP)(&$ON9qUD̄o4%i1 V<q:= .8Y$<l\RO[ z;khנQIݶ]Uvps4`6*7ï>;DT0�}hR*#Dpi΍VhbVuܳkUwW|gr sH+ OTؓx:"o9ASM$5<5,7CGn_k'l_~ܗ}@>*ѐlG[2p hĀ]^=cbK �)mxq?[0yo}۵%aU웡侮~'67uUY|ݻmmZVί^PݙFdzڨ/Vko>}5E;^B&2 �mڈ2%jļG}Ƴx+>>D0C/̄a<nawCzb\O(EȴC-{;|j9 >v!0*c" Bp"qKm6x5}?uWw["C"+Ŏ  |=,O)&5* g|YOѐg 8{8vx>Nc wA*b8Sg ?#"A@;hSk.ʔF|Sasj^/5Xlnp' L?Ztʞ.̄0 m9 9].?ZҀ+&/Qh4_$x/;qBUcEst6ztJHD!JJ?Q{3Wqش^ܻex VxZ_; l&e QF�ܔ֧:wN*T~a)\)Shë+ We3oC;d&ZΫOf=+vHyȥ<c5R>L0zendstream endobj 514 0 obj 2141 endobj 512 0 obj << /Type /Page /Contents 513 0 R /Resources 511 0 R /MediaBox [0 0 595.273 841.887] /Parent 494 0 R >> endobj 511 0 obj << /Font << /F30 42 0 R /F15 7 0 R /F27 77 0 R /F24 5 0 R /F31 93 0 R /F1 107 0 R /F25 87 0 R /F28 86 0 R /F37 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 517 0 obj << /Length 518 0 R /Filter /FlateDecode >> stream xڥXKDF? G½i�NH�HxlKb{ډ=dլrꫪIxӂ'6LTono^:9{Oy[m2xvSkp1OahƱ/6M:m9 }o+a̹Yy1 X,kfr(&(V :rd'}Em27o]Sm@ʅͪ<jN9$B0meqŔҞ{> )# >zN=nS0\Um۽Bv \l~7eԆ0 nσk |QPi?0[x-mMح\z&uLaL+n ' * UMTi=x++니8jq"gaR֯ԪB<m>Zp)o~nfط]9AtFGpxnS쀂BԴv s!p9v,ZG,gpIfYQ`%kSN2_;I +c\dk.|^ry+EҧL(ͬvQF{!7ވ0 fZ-S0 CG�G�]):3��0_ PLg\a fMƹOCS̔sZ<C#~ɑ/+E,N` 20Hs#s; 7 hP�ǃvDZl;zz ٖ".k 0Es/qd Ə |e`čXx ״-/ci ʴ"$ŬcYCߕ;$d*'@'C#:Ig#fdA58벌'Z)̢ ͙sɔ�qfӖC=LHrသL ~-)%ⅹPr ºO,' ܊=/U ʮ0S`+f`*7Oy#ʨPBb2GU?7݆ꇡQpj0bK˄xREV?p8y[l e]uə.2"O@1V⿅%Ho @JjRr8zq29:%=` !aK4%_ Djg5v'uL&=ԱNc;W84ӥu]w{9"%PFY uH11=ٜDP|eII Yң=b'd؉M-i zy2R M~ao[X9UPA+юO0.B.tTe=Ǒ,}&mɪf[s#W.<�a(.1\F C44R-J)eg5>>"48FC̵hR\TvϏ$ NJfL(zxrbOwٞC7>djGn*?uYq8,g(脒!BiɄWX-6mbs9E.NF+nJ/>/Q9Univ(mcqe9s5%K8/֋O4:; 1lEOBo3vCqfN< k>\ F0SAȱ`"V�J]?Qw#0r8 (үwD̈y,VyڋC}uTڴ[5R- Jxx,GƮcnD R,="pkӱ?M ΋l5 %C]`,py*CrA Y[.0Œ4endstream endobj 518 0 obj 1910 endobj 516 0 obj << /Type /Page /Contents 517 0 R /Resources 515 0 R /MediaBox [0 0 595.273 841.887] /Parent 519 0 R >> endobj 515 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F25 87 0 R /F24 5 0 R /F28 86 0 R /F30 42 0 R /F37 5 0 R /F1 107 0 R /F31 93 0 R >> /ProcSet [ /PDF /Text ] >> endobj 522 0 obj << /Length 523 0 R /Filter /FlateDecode >> stream xڭXYoF~K) p/}m@Z\YD)]v_ߙ%%ʫr|3+/,"%\ldI,[7u]~f%BDom{cjn׿=skMKVB0%rp3˕im],e JnWHPX8nUTTuq] S2&cNO;FfWUWϖ+y=U d8~stkc~ͥ_6$fyܶv<f n١)[Q:+ +0.}U Kƚ&`/,n݇O63f}(͹dR&^#z j/z[}qgՔYd` NC4+ ],a 鵒qx܁8'ppܺ*Lg ET4e@Qk1#zjrΏ܇v:6EChs+Mo;wDWǴ$*L14˅ =6{G#2ޔk?)~WLAQuqR,sr":Ӕ'wA'8zzlɃoU( g72Z |!vǕp̂JȢL]Mw`5@`IAA(^{JlDlWgNN<2tᎸ--=6⬿Inr"yTeÜU+@WWa,Gξj|%y`-I\sd#cםTݴ V2rջߡ.seV N@Vr(LLC#OHRCO[RqApArz'f2+HS!A$d{PP!:V3qqp=8-`YګcO  k^euV$=tAr+l5ENמDTM7,i-6U|sV 0]OI1zE [Hlg|~`CzڐpBi E!riħɣ#<)CDLh#IU%k<%%z }|ѷ\&4\OȽ}צW.XFBAr_ Bekhjtp#^JRdu5qV[V ( u5(<M:qΔ*>&=<'~~ ǴT<_#~ P(}�F X3T~c͛k86Eʗ ȁ?mBj8[k-I�64)w<vhx9M^Zl 5L9f/�!<xKA.MwY XߡҮXQmI%5&;l7�bl' J3�Z=exjyhJHju\Oɓ�a>I~Όb }W4ݡ.Ѳ~2{9|" U[,?]\_eendstream endobj 523 0 obj 1574 endobj 521 0 obj << /Type /Page /Contents 522 0 R /Resources 520 0 R /MediaBox [0 0 595.273 841.887] /Parent 519 0 R >> endobj 520 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F30 42 0 R /F35 43 0 R /F27 77 0 R /F25 87 0 R >> /ProcSet [ /PDF /Text ] >> endobj 526 0 obj << /Length 527 0 R /Filter /FlateDecode >> stream xYKNrCn{Q֌&'f&`t`4ڭmJv~}XLhOOC@[)X*U |8Fl)0r=w?J WaL7 Y|Ӷy덴ض'*TR>Eu}ӯu'XԮbRZt#<\LK3cvHADw 4b9*MŃwA<aI<xaT1tOj[Ê~zA:,l"ĕQ̑6 Fj`uMPG U2oqز;XY/IR.s~m|x6ͯ ?KUKurJ%B}&l;ѕ]qt1OM7۶C5Ի&Q3S;<#@\1^LxXhV1^P~_x6#>, BóPr EҶ:d7I"q7ֺ,vh^lC }F -&x'}vŝ;oFIף3/3V]MiWoH-+I�rg40ϧwG(IMºmI( ~^;!$:ߨ1m GuE?Th2 }p+'stTB6 ޅ#k~ɸ,3b^'a *)5S)S3c4o2+7M蟏κEQujm44+$ @IPͧD%^%KMG/ ~m.NoDdlqjjeFДw7,36Yt.E괣0@b7"ǜLQ7{'w8O!3]E&0 6cP1_^Z.'^XBxF 440$=bWoӞnWw#& WqoCєEʝQFbi[c*Kr(C.6̘00x~t4?*Y3j�W*&�>Iᇅb 4G < l1 ~ۜy6bMފgTT|&X$evh< 铼 kPh�IŠb}ML"iG'6!eN2BEF2G#lh1Ũ-+-` [*r /-fHŤdp> ?B.�~:^O$-(5 % d GڬWr< pEYZE1ri'^Ҫ]UaojtLb�znV %PRv*o@5ǀӃ~xC?GXhԑ6p79t>(; 1+�9(J:572vNXa<2fH\?-rXؘ@VHoE(28]z!u=d;?fҖI׽"ĀGPVFC {s8J%QiZ۩Ûn8М>V8Ε(03W.Up 0p5AEM`4.vmnԗ~[ϜB� e.><SPҶā.aic$cs�=X0\.=?&xU<k2%ِyڙ4婐Š"<\X)USG䘣{i/k| bf z^� ]@D!B|Y}=(`>fk}5ר)HS7Ѿa)uuq̳�UvfΓF$!O=D(~I$0ZFx,U|ջTh½h=U ics L}lqK0h8XQ dT.3ν{x'Bh&w>8=�8Mxqh Up&?͎3]9 nK#^!^S! 7Ƌv/g >&k]va&~S?�[eһŪ7q`tRx 6{hki* mذnnԎJ_0PGd,=2/u ByY6d[5\0)/=lq..`sO~%j觫Y="[j1}Cz~ꇺk B甠=ձF% T[*} K4wj^HFi2nyXK* X|Pꇮw]r_U ,50?vyhN#ND>tV|Cf u,t\.G<endstream endobj 527 0 obj 2383 endobj 525 0 obj << /Type /Page /Contents 526 0 R /Resources 524 0 R /MediaBox [0 0 595.273 841.887] /Parent 519 0 R >> endobj 524 0 obj << /Font << /F34 5 0 R /F37 5 0 R /F15 7 0 R /F27 77 0 R /F24 5 0 R /F25 87 0 R /F30 42 0 R /F28 86 0 R /F36 6 0 R /F1 107 0 R /F29 133 0 R >> /ProcSet [ /PDF /Text ] >> endobj 530 0 obj << /Length 531 0 R /Filter /FlateDecode >> stream xXMoFi 'w[@8 l@SET"]rߙH rI{flF͘d˙X̲c$QjX'ѯ_݃u]i*\1"~xO2&)f~3&ڂ%7pugmU'&u|1;jl$R7Vu= G۴#&bE.>%EDB=}Όpl%aJ ՛=!($Fi(6-itHۢ*1O5#Ji42&1Gspm <Y>hO&!4 ]R|TN TyWYɯz$DUqW]ߛr8EK7~8U*J"c�Ê}n^(j?$qࠪL7x7LBFk6A>\z$8t'8� Kxa@^ܾt«qOq+v]-Pzbሺ$ 1bc\f<09S.a>*0�uР#AM2$Y/hUuoמ=<Q +[:[IXrO4 01]v䀃fi2ީ #B!5bt'f6_T?>.S+�^U`1?%(bGEX^؅2/OAb ܬ L yca0wI||I忭 Y2oڲ&ꒌVDܯj`ĺaxA y؍!|V( bnn`�g}ANkֹ7DawBhZ.k~]Uov]YH&O&:5^�"Y 0|Z]yŝKUHJuƫtScGSmb=˔DK=~1Z6ޠT97-df-w@jmUݩ<F~Fʇe6K1ʉ('�^Si8^b$rkSˢk{N>GZ|eE^>Z}ꠇ}BcN;9c}WÕyVZ<Qvk\ExQl(昃|Jnu@F�2ol &l: ;;? b:DL̼5GTwc[1K ʄh*yBώ>fs#HkgcY{‚51tB#"M-4XfmrЭE]L)kg}~[HC#9zA؆/ f5py]b;HR1 X >&tl?#x XnnY=HEΡ,ہ-$Ž< 4#=qBxe 8ui]Pe< U5F{=fUyVc| 9s<~qU{QrB'סy^>%N/#;O@Q?5ۺڵE^;@μQJLC&P:S~.76#Y6#ܸL_,\߁+;IΣW:q!~gU$q .}aBWE;~$ qXV=ۘG'GTOP4.Ր<j"C!ƸsN.N8endstream endobj 531 0 obj 1762 endobj 529 0 obj << /Type /Page /Contents 530 0 R /Resources 528 0 R /MediaBox [0 0 595.273 841.887] /Parent 519 0 R >> endobj 528 0 obj << /Font << /F30 42 0 R /F35 43 0 R /F15 7 0 R /F34 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 534 0 obj << /Length 535 0 R /Filter /FlateDecode >> stream xڕXێF3yp}CY $V"X$ٱ',OUWc4D+v.NU_W1gI(VQ *;<zyV\1fg$7'k&_ ʺH۵/#M[t]͛/^qP5`1M$'r*fZ@6aǴsh8EdEk_D^Ё9*RDa /bU]O?C f瀫>Z{}BL4&b/P`JV( Wya F#rK2VE,kڼoQ{}C]SUZ$zC^R, bN+ʘqkpsy9A�8>KlËR(%&)q.%Rޕ|Gu.#xJjC<S$M[c6lrHCGfaX09[LQadl:Uka3@X.}>PnE_-b6@\~f`4a!Y0/*Asa픔DcSh` 8,J>xk>>xJ�[|{(,@2񎖑!d2"U 4a�xQU`Hʙsdb%x#C1cdmCo |"Je-HB ֘/cJ j(B 5ȩHzI1p\7e>Mit7nd_>F)&xUW+ %ޛ~`^=x`;O&\Ϩ pM)&cW8&p~+;dz.McozzEyS[Mvbf_a=foWq5߻fStRGAb<1gr5Ofx͎q!f9 Xo.+bx.֩8 Wߐ,S0 :mmvD݁)rLr\ dپ t Py~15u?>u@.w?tqG:C�uvmsd\zf`؄xl2v^׷…];B%ƖqPq\8mF})qb ߵϝxj&^} n.'X:I\hT%ThTSz6`l[mo1Yv b3}?5X`Ď/Cw/U(P.%,CͳqI= PjD}F~M? ]aMaה$)̇2fl'n芨q05U-KüD0<2#!TIlB8,aL6dO2fb?J1=͋_&`ec:0=NH*-;�4% &ʠr".xVMBM^dB!怷 @yܻ&3cBQE-/88Ua>}LM#05Y4W}@ eXN~^@NJڢ2E/BEUӓ |t UDWuOЯ#b9)z2B,zg{Qy> 'p?FŊ*kt ot] {�BM] ;aF&M%JNPUeMt9e'1S\xhrݶ+Z:bOr>frn\�\�7pV!tS$זp3?HhglaWN<'ǢE_&(Dt8w3ݣ6X0endstream endobj 535 0 obj 1767 endobj 533 0 obj << /Type /Page /Contents 534 0 R /Resources 532 0 R /MediaBox [0 0 595.273 841.887] /Parent 519 0 R >> endobj 532 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F35 43 0 R /F27 77 0 R /F28 86 0 R /F30 42 0 R >> /ProcSet [ /PDF /Text ] >> endobj 538 0 obj << /Length 539 0 R /Filter /FlateDecode >> stream xڭWKo7:�s z;MQ>큖hyծ?}f8k\>G !˹Yd\1zwrvuBe /`r%RɤfWjRLZm]וM7,`1tJJ&ԟu6h\+=\92L2,/W2K\{Ӵ*M,6cYIlӲ`An ݳJs\:̒ou?X2)t4ӚjnpO;!|͓%HGZҕm`r8ݕpSS聊e >l#AO$+& l'RøRv"gڤa #4Wv <n*j0&5nv|9]y4:mi++Y">߁.5Ky>w\hr ?k?T=Q CݺoAOȣ YP@LdaImqtp."&>a0Q 8820+$@^6U!<+ߢ7 ( ɴv~7c6ܲnvG+׵]Tap@Rz*ЗK>r)(MuQ3" 1K35M rHF<۫U:F_c{3r'(.YgGuui`mؔp?Ń6L=AJYSHQ[cdHϬ3>ʋ)$ɪi,t|zh)ih ?egxd뗽b4`KIn_i-W1p[ihB^]-)Sjl,_wmmvN Wr(4aB#oE؞FMJEϵۖ[B2߱UyS?;B>? ֻG2u1Qh2"@�06?M�BD XiXutKt-AӸlLĕ@`EK3ViU<--:g/V1#h3X`}WTj HhBa'ZBL( z({rNiud[ih�Rk5餜 ӔBncGv"m{r zYXw>ve ;Cw pkۻ*ys4:At,u~ ٹ}9H05qϱWX?}^ӖaZ~̥ϥ0׼G?~>i0W:Q.0&zx>nپ~[A+ 3;Еnxn9I p+0 5m|%:)`Vvj+ç(r9᮱Bs Cg{jT4qu>rSpO5O&NG\=!Ѣ6dӖPL|f.#Lt\AH i[WXuR`.C$:)'M_+\ܢ|D<XVd͉ <~{~j픬-Y;֎GI76j(L0NAUW$l_j7<cuXhvv2 &l2NBSOw6pseۿ%nfP .XT"es'W'�>vendstream endobj 539 0 obj 1700 endobj 537 0 obj << /Type /Page /Contents 538 0 R /Resources 536 0 R /MediaBox [0 0 595.273 841.887] /Parent 519 0 R >> endobj 536 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F35 43 0 R /F27 77 0 R /F36 6 0 R /F30 42 0 R >> /ProcSet [ /PDF /Text ] >> endobj 542 0 obj << /Length 543 0 R /Filter /FlateDecode >> stream xڭTMo0 粿�>na:J,iGQN6E4j$oIVQw\}ڮsҤ-hwns>-ol<ؿCM):cDnbagPOJd+=ʁB<BHà:kS;9@Zɑª EQqZ$EQƻdĂwbPM q?fqd؁븨21%|$(}�r8{\E[.$.D4'NRu%9>lTQMjG!b< NVonv#)߳Y i@F%"7fqpxY||lqzCK."`3t0&O`(u$B;Gk08to'/OzYbh({s> P/G grg8(ECWj{٭qE~ RJ)%:�aP@}B[ -zO{IUQ<x?E>qxvg9W9g<|5Wӄ; \j?F C #ԑOxAQ\aedY&i+/iVqy +endstream endobj 543 0 obj 688 endobj 541 0 obj << /Type /Page /Contents 542 0 R /Resources 540 0 R /MediaBox [0 0 595.273 841.887] /Parent 544 0 R >> endobj 540 0 obj << /Font << /F30 42 0 R /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 547 0 obj << /Length 548 0 R /Filter /FlateDecode >> stream x3T0�BCcK=#KsKS=SS\..}7CSCC=KSS4ʐh C# /..�* endstream endobj 548 0 obj 66 endobj 546 0 obj << /Type /Page /Contents 547 0 R /Resources 545 0 R /MediaBox [0 0 595.273 841.887] /Parent 544 0 R >> endobj 545 0 obj << /Font << /F15 7 0 R >> /ProcSet [ /PDF /Text ] >> endobj 551 0 obj << /Length 552 0 R /Filter /FlateDecode >> stream xXKo6^soQV\MvQ4E[nCR*)d}ɒ8cKcDf#qNFZDz9 aH*,7ryw۶LȨ)M4R9jWV6ܘ-ھ;<0~Ԍ3Dp_.e#zAdN/Ln"#*5:1<.`eyZb Fe'\Ѱ?nq5 V:)Ǭ?} It:T2%"'f1>ޖ~m�i{!j^]�.ݸf']m`e]M7�V'<=_(ajZV0d}>~2+XÐyBn#jĸ  bD„PD"=C*g& gXD\)@a6 k+ уāOD�.#"$GD NňQX4K06`0�؋ cB!cLD eJGwA.} '4yv7$YS qgb, d=BW(W;k'(L\ǡ)*9!|[ӘgB G9'YrFU(כ i"Z(1P$ ҶW{_aL֞t z$wk[7}љU<$=}`G5CB;8%1@ ^M0p'rM >p1 0 j$U uSvfV䖶0\WgiJ17EWn=a0T8s:qK.sNi =jA $ C59I c!j;bYFoc`$33Y4)/#O(]$p+GmH]ĚLż^=PIƨ U0q|#]\L<ZңλhR8'?ʨ"aETT0dQp! S#޹z;lxꍞҹ"uZ rm o~ 됝S$� ` N3 ,F砜( t@T1 5m\r"<1%P4{aP'L](F9N>'=ܽsS1eVM,DʁN*η |;U|Kɣl @6y s6a3 HI=G~ݓ>bL/ؿ{Ut (gaNN3AѓIjoQjz:$'Hr*ɟ, Jc\DK6&~6)q W;<0vktNm}y! :GAOP91-}ݼendstream endobj 552 0 obj 1440 endobj 550 0 obj << /Type /Page /Contents 551 0 R /Resources 549 0 R /MediaBox [0 0 595.273 841.887] /Parent 544 0 R >> endobj 549 0 obj << /Font << /F23 5 0 R /F15 7 0 R /F35 43 0 R /F27 77 0 R /F31 93 0 R /F28 86 0 R /F34 5 0 R /F30 42 0 R /F25 87 0 R /F24 5 0 R >> /ProcSet [ /PDF /Text ] >> endobj 555 0 obj << /Length 556 0 R /Filter /FlateDecode >> stream xZK\}oC8Ë �:9H"QKJۿ>UM[jdI5l$#B˙p-fWy{f΋,Q=uWy{.L#Ĭh* Mw.NuàeqN$W3t^%Ә"Θ!i"C2mR9L̸%L?F)530(bq‹ "h2!º^b᎞XG&L!BM&nVLϦ%F E=7ɍȗo>5snW5:\ \ [ ^$RL-mߦ~\ַx3M)l0EJ hffJʂD!q2d0ɠ 9,8`лB^\SX)L*`\EgsX.gKIQn<>LEnDs+1({E.H!~,:kGȟ>kGȟ>eG(yX6C&<F%³g(qҔ0YVPx|s΅i .8W1BayYDPKɳ(bЎ`pRuP,eQ)U0c’C=kpY -䥪}xlA2ME72Lb-D<#kB RIJ~(VN؍W<Ĺ ˓NL~~̯Uf>d׸ .0sЕLOP\1*J3$OJ,RӦ> )k,),45~[R^rdIH8f'mA|@$ӕn`NvƜ3Ma*a7QI~^vf\U>)|.U ~hv0^WLJn=FYM\RTy!ܘ4cı,q3ljP~[j&xJE\fK(T;N+mSQ,ɆkglޥFy_A=u{pw!ռv"s[G9"]<Гq=rnDpU{l6}v50ٴCxڎ}bmFrafV1Z郣J* u34-(=Z܄'ZM]!iHC-pHW:b-ìت<.8:6ywS)ΎyJCAe*x!(cWY-q>tE <VaM vۧM*�cSMjV?lvDe1rs z ³Uk0Z,J ?maӽ]~XÄحpv'm1ˆ zSt g,<T3>ǠzeC� u2ClePXdHn@< c< �jbFK ;5+,K j]kPGj: .w}"2ĨHr_tz6pP)½Ў�0zŽ1I1-o-j Y9"łV�t (HKp7o3ژS0v?4]!\mH@ؤeS/Ǚp:.~diMT(mUɩ2!J\wU, ! xb],E!2@ 5,~gu ⴅȸ.ED|SX ? 薾nHj� KF�;}K;OJ eM'h'U")ɅdJ-Xp^.=QKQ'jRӶ{ m,q`R@OڬƩ JDX[ TwKJyOMo_CINоSd2hq�l :~/#�*jP>2å"6HHi7+,to]q7od5v[2=ae|#J(!@' HUa!:ϺH?)0} +&(&=e™VHY#/~cP \v&{ơd4iBqQlϷ/S:<Xp~VwEXK(uE Lz`�"HCepDQ`6]ElUH7i܎OHNJ�g{+Z �[[L ^ ;I#`!әfgM�Խ -Rޮv%=�VaWߍ(dR+0}N#8J5"Qf­}پg3kZ̾[?*C lh o3'/m&x~9L)R텾ZI2`)5Nc\_mɧ.Xfs]_a1:'ءendstream endobj 556 0 obj 2485 endobj 554 0 obj << /Type /Page /Contents 555 0 R /Resources 553 0 R /MediaBox [0 0 595.273 841.887] /Parent 544 0 R >> endobj 553 0 obj << /Font << /F15 7 0 R /F24 5 0 R /F1 107 0 R /F27 77 0 R /F25 87 0 R /F30 42 0 R /F28 86 0 R /F31 93 0 R /F36 6 0 R /F38 163 0 R >> /ProcSet [ /PDF /Text ] >> endobj 559 0 obj << /Length 560 0 R /Filter /FlateDecode >> stream xZmA(͇Rio]HۈqZ$�A<>I,ߤ=99;Z.eXp'YR)+&Zw/.z%҅,K[jKr-+%mm92ɯ4MuA-e忮+i'vt! ²b/ÜЇL. u2gbul:Rq|3,=⛫ a Y4.-V/8S[4vzJôp!gK Y<˘:<QۈMVi2͘wۢ)")2f ˖ۆ[J\/WЃ[M+i j#M6Epro6 n)G.veU{߶uUPSǫNYI+¦d:�B3/2jb5vMd*N0ӫ8} ϲ$|-R+n~Ådh `c򿪽 0Lk㧸>-qx�eCM]xsK%Uцkfݽ7&o6&mWϿR,yNmMQIm Oy+4KStshhla&)TR;j BMʺjћ͖-Wۚt[¢Ly[\BG@,;1uh4} Z2#{[dX  B8^b\Ķ?4ٔ�``Eb�>(z䷷]7ov cV73f\cw�𐦆YƬ�qJu) ˕RySaX`[*rò|JX2m)3n CŇ=(İb?3~e`mÃև-6X2aӳ>@hV%SOZ!g9%fqx!t ܠG9a!<�T!@;x3Ojcٔ >Woߋp:8jam.5:xIgq`an)3<R}ngYs>'n}ȝG1]0`I\852>*[j)>e <eMFy$pUH 0!H*f[E LsEˌ~E?FTLx… oF $peX%汣dx?` i!D IYO[YHJ JA0O(ͺa!3.|؅Fi2K{HUGE!1q8D^c?I!Pt8YR1|0(lke%s&Oh�Kcv * $(+q9qb'l$-<O:dv#�|aXo^Q2oꂊwIFR� NL2FmF2)px%6<p慉)i ħ䒪Xz|Jh۶S>!#\ A+$ "8BE:R{ѩYZ[\պStPkPS b9Cf/qYk]^{-q&;w<J9޶MkAam-mD'#V?g/{^})qE)3d|< sTab/WSWc1`: d}CtS)@zS1#M )m\$%3+-u՚OM5׷_@8@E3ۗ>c?G{}pNeܪO&rf\|8=YOJd ̝,8]%)6S6Փޯ<4b_�z5l&`HgC#dҗ XX#$&X\o +Kwߋ##27H1ZWDCg-};![)EJY׳=ʇGlxSg,Wnƨ&~ e9;mCBDppцJ 5Y`}@Hj"G2ѐ$: !/Rp/WQ*G'(RsP@ v# !:¥qO�} H*ދȜԌF;.`EfV0?./z|\^@9O 7duO~\5;kmYO^><d&dv0a QX?I Vg}X@с5f+ j qVf/GbӗP ? c? sg:,m@S%I:P( %8B Aendstream endobj 560 0 obj 2411 endobj 558 0 obj << /Type /Page /Contents 559 0 R /Resources 557 0 R /MediaBox [0 0 595.273 841.887] /Parent 544 0 R >> endobj 557 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F28 86 0 R /F30 42 0 R /F25 87 0 R /F34 5 0 R /F1 107 0 R >> /ProcSet [ /PDF /Text ] >> endobj 563 0 obj << /Length 564 0 R /Filter /FlateDecode >> stream xXoܸme≿\@\is^Keؕ6N V{:Hj4|p?3i #Ww\8g֫ zm.sdvgCO{O?t6kwuꇺym{hz s*o|O3!uC֗l[u OŔD.�R=- 3C6YuۼB}] {rhX)A[_7%ł&VQ- ;hwQ6)!6 ' &Ji\Qr26,5- V2,%-J)~ʼni\2'JfP�2d&Jͷέ4ӖT)QD3sN:�<\᧾]p)x1W+�9/v~uSJHˬV 1ĉ )! P, |E�SoN YqMnR:>;`%t%ȕQ3MY-,Yʼn%3VHd`}`G)ųCfH&?1$b9JRŤ,#uLt>I 6Cggw<tUd18%y)2eZ`F PÁ5+ +}|f"z-"$,>Z`fzω_a=)͆mGmbմͮn|ѴiB&X*!zGuzTIcjoNS0X^@Kh eS)WK`ҕ޳A| q�Wr!f~١*y#e=trP. 9b<(ٿCEE"�ۛj؂?K3m;iu]mK{+ẁ^}? oޏi 6eg?RY*(HK췴ЇĦZ|1V:n�Շ_ 6FSoC}t�Ř ۙ;MOlp\w~COWe_t]5${';x!KBU#hpD~�w=%XP:�=tY|. 蘎u~A(SZe(_zgimHt̐0}۵h#"}j\4xmRjHml,_`@M=\jo^沈i6 "L@<?؜ͽqr�7|)ۛo:l517|J3Zl~ѯEaiboo"ISHXJ|S}R\BA?/@rq SgNkR ecO56K¤ -D&zG}A`քĎv$eB0yQKUAKbɬP\zh bοœ`5yD))Z0q\F m $@UdU,d܉y9m)fO~vɈ[W=˸ w�5{60C?vPGal(Zg@JMr?,ܮ̌?T ś4p8"$PaKy~C՞(+^|XY %%AgSXa"eo|~a#̈́R}Hn\). -ZEW]f{=H,}13|pp鑂"O�Os_ʪmCO^!8#^N1?MHT()UHEd�5],, Ny՗_;;܃IRZhendstream endobj 564 0 obj 1901 endobj 562 0 obj << /Type /Page /Contents 563 0 R /Resources 561 0 R /MediaBox [0 0 595.273 841.887] /Parent 544 0 R >> endobj 561 0 obj << /Font << /F15 7 0 R /F27 77 0 R /F1 107 0 R /F30 42 0 R /F28 86 0 R /F25 87 0 R /F34 5 0 R /F37 5 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 567 0 obj << /Length 568 0 R /Filter /FlateDecode >> stream xڭXo6s^/Q*V:`AAVۥh J"<IN;HE�;~IYtD2:'Lj{v8{}ARK9[8kl|Lp{w0@3 U7OIWT|ö́&]۲/[IQ#S%n#zHNԠh\s>U<e(e:2s1K BHGD[J󔙤8v,e82-eTU};Oe,6UW+4�՜ฟKn,esT2]W UAxF⾳:CjT ʪpWR֮fWo8x@ qO ePE8RƒMhmyۂzUHaPNP`# 9}ٖ{�spwKikzxINK$FP֏ؤĄpzuQ2V^+ {>om4KS$_j^xi@HߺM3{Ev=+lƫ“Ϡ):²w*;ZMJ =〖 OB(\ \ \<8Ms> 69rS s3 )WrcfBIEޓ(FJ˳͉Pn`Ss ry,f`ښՃ]"Rg|g.5T 6eA /o|xoɾ>d|\uމ84DmCm%:樞\6s-7,HbVry9%Yuo '߻uYnzWP=ɇO<,0P՝a[_[Ƌgb4'H,!dE5f%'F`/!ma %"Y5ݾwd>[~9tU@Ov1@91 xl K^w.X5s1zite53HVO 5 @9@ڷ/Ec91`%'5֠0,}Fj7=2;;AKifGxHC M]YnhhMdl_ŪYVEmOr.|ב~z.q4x. L"46'F%׫%!� X0 wrY+qcӮ]JˣpW|F(2wV둮Cv:}UŀD^bh@'5NQ&µ/࿟,Z$p5LdkcB`c\ �xc UmjÄkU 307 GwQcv _øKt�8fd6OQrC~uw7d q2/ҌjFڮD+WiQ,I̐̄r|m3M mY nIH.c >=8IM("MA.r0 :?Ӥendstream endobj 568 0 obj 1500 endobj 566 0 obj << /Type /Page /Contents 567 0 R /Resources 565 0 R /MediaBox [0 0 595.273 841.887] /Parent 569 0 R >> endobj 565 0 obj << /Font << /F15 7 0 R /F35 43 0 R /F37 5 0 R /F30 42 0 R /F24 5 0 R /F31 93 0 R /F25 87 0 R >> /ProcSet [ /PDF /Text ] >> endobj 572 0 obj << /Length 573 0 R /Filter /FlateDecode >> stream xڍXo6s^\ŏ P/*0`K`)ڢXnúYfIrTv?wwg9 lg&LrVN.^J3IU..L2}<\="Mխ6siT7kܮ\}usVjM[ͅ`jŵug� N޺f%&:wչ<jޠ0^'O 1zf`BA l6ִW (#a][85Y'u0%5h�T 6FVLϛi3|u:ݶm'> w ?٧E9 Mο]u&ϰ3OAJ*F%.7vSL!j'a L9:? ?y]S$L@GFLq>A� ~6 0 o׮(ygS> _x0#vD{Z PFMg\iWM- u˓z/ifSHgިsKR@?' 9uiutckvzLHh]]ܲ`-`ș. l﷫) "xa0XAhBF^ "Y>?ʄo<gK1Cb|zG+~T5#ڄk+wG/et(עf􍈏 |ڵǐp(,SyϹ޿9mV3@=ġbX[;j&DՖO8&$p'bLcu͆hB^<RA UMf/e# 2S IPk|>PʫCMHP|v1%a[J_Tl:3m"}[\=lc+>:g(X.ĈzDG!aO#n>m#PPw&QL _Wg0 nA)c.O�puqnY Lqh|wlC]U(_[zw h1`J P@3J6|X)I&v)oqaKtlm`l ] mOQ !znVfxNHb}(Pf/5' JEzqā}AUdM8pb.FQh@-c{9UǠ+2<g=_U怫̎ %(gOgH,%aR)LLr=E ~m 1o #=J 4P:k,vpှ8"#Kpl<Ռ`Ś|hH ɩ AjS=\k5@^&XKo-P80:ުBc~˖v>]<t<R@7Um vd A~wQ<Xbg.΃m6~iOxo.v)0x'!pWTHU;ۈ+vVi7eqO+>'=)CTZ0Ԅ q>vH,ʐJQ*o.�w-KpOH@ތ}ޔo&Qb gg"p4 4=I,IK'5؆ {'YۙM: %52|Ї-81+[+vc9NJx~p7t,}ͫTޮendstream endobj 573 0 obj 1710 endobj 571 0 obj << /Type /Page /Contents 572 0 R /Resources 570 0 R /MediaBox [0 0 595.273 841.887] /Parent 569 0 R >> endobj 570 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F30 42 0 R /F35 43 0 R /F34 5 0 R /F27 77 0 R /F31 93 0 R /F28 86 0 R >> /ProcSet [ /PDF /Text ] >> endobj 576 0 obj << /Length 577 0 R /Filter /FlateDecode >> stream xڝWKo6^|H14u&�-^Fq}g8v$A| 3<ɏqY2%qH&2y\NΏqu9+:>ven{յ6fggr(KXfӵ@n n'TCeZD j=hef<jmuni/i::@1 ps3 R]=ضrDF7ewq F|O.J&)sxB$d ƦԐ|TUKptm@ȞV i8ZfXD+]M܂AOs_qӴ]?cln#J?/bei`e,̾"ҝ{788ED;'Y) Tw8.�37O1/ h׶T$ d"y*s4\(FwzmH9JꤜdNgm8xFFYcFR#2aS)P{ �W؍MtrC'u� ހ_Bꆼetkڬh(R%�X y|-=>o0`_~L>`p$88˾D/fpsrrH~)̻&ָ6yX`i8]Ʈg*Xܜ)U:<fvM-䦇@70jigm4& S"X|Ȅٞ%It�MMzV)ܜYdX|>ё9*So9sj2ۮ˕Ȃ%6pi]Z~Ώc\3]( yPVZ=N?]f 2n H@d3 . 1m?slOa%.[LSafsvqpڒD9X|9P`>eQ\+z$<D~阚T,[8TX2dU'bBLH?EatnvW n1VL IK3I͎BvěW+kgqncUAk]ͪ+F&"᜺ vZNS*fan hlf݅͘c> *2+z8(UufDz?*kHC%֡yL :91&TqRp猇(TR$E^y2]0m$SOBɵ!4n U<]U�eX>L'98+d�rwX:p@m*_@;:)3<>6BjC%b'sHVp5j@C4x3Zߋj~xR-Y^_E=dР{1Ni2)f* m(8;%mSϥ jeл{Cыe*p2gAϫ(/_Ob8jכ-Ze`]<kHDiyQcρPvm% iDw~5)KFǝaߒo 'Z4ZAOM_qO8ʋ z܃4؋THy? endstream endobj 577 0 obj 1660 endobj 575 0 obj << /Type /Page /Contents 576 0 R /Resources 574 0 R /MediaBox [0 0 595.273 841.887] /Parent 569 0 R >> endobj 574 0 obj << /Font << /F15 7 0 R /F35 43 0 R /F27 77 0 R /F30 42 0 R >> /ProcSet [ /PDF /Text ] >> endobj 580 0 obj << /Length 581 0 R /Filter /FlateDecode >> stream xڕU[O0~_fh&!ѷ)Mi}8^41!\-XHf܌SLԸX.+fJ'僇.Hfr !eh<vTG}m ,_ 3eU,%I oׄSoq:cςul'f @4/SoX'oeipvUឈʪw]ub=}8}f A.`&',M%MJ&Ģ즳OUi۾1m&r*d̛)3&qƖgoyh3|N-]wV;.tcKjH*�'2QWTz]EDKދgQcJ5ZG_`~Ob#tt]ה +My6zBڑQ 3R *jic (wt`bEWS ȹɖ^pgY[v-mĄ=ew1P[ϨW܋;6u"//Ty@ok6)`WynƟ:zڮ 53`W__ Z %5< U0%CB�&.N%:V=tX -j_:jO&ƀ硃NwXzS3@y_l!v۔>:ee8dcA# eϙG u& sUtKhrqC__C"k[26O !p3]o.7n %).3~R}SnH1}l~ECӷ^A^0 [,a!fF[. qendstream endobj 581 0 obj 813 endobj 579 0 obj << /Type /Page /Contents 580 0 R /Resources 578 0 R /MediaBox [0 0 595.273 841.887] /Parent 569 0 R >> endobj 578 0 obj << /Font << /F37 5 0 R /F15 7 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 584 0 obj << /Length 585 0 R /Filter /FlateDecode >> stream xݖMo0 /�*Q%]W+շm7Qc(JZ4a%R#Rd4#&( TѢ}fW#Die2[~/<JLdD2][`P/Ɉ/)D3HmqAŏsqoy1_.v;|λ{PE]m :v:D&.nnK^"^!^='q[TNTNI(CxuM#aaC3 =]gw*-~E%'VSIa^n=)m+GCbZ0~;!%Lp|YEzF6/AZ I*pJ 7A R,OB^/, H O9L3L",Hl!ۮt&^iX4!2A/X|}Bgpjs5Niyp,cuS;Ћڔ!n �b� G5oմP4lK[ǁ  g3 z{Y1` W0', wN00#?Gϋ?CZ|;n v 4F5a�KOwK!I >uoz4<APs")<%F;)ܫ*_Z?jVwCW‰8q]�Sev7P,aFpokWTNաaogJendstream endobj 585 0 obj 755 endobj 583 0 obj << /Type /Page /Contents 584 0 R /Resources 582 0 R /MediaBox [0 0 595.273 841.887] /Parent 569 0 R >> endobj 582 0 obj << /Font << /F23 5 0 R /F15 7 0 R /F34 5 0 R /F30 42 0 R /F35 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 588 0 obj << /Length 589 0 R /Filter /FlateDecode >> stream xڭX[o6~&˫(it؂b6Lt $KwxrR(PKya ?" ь+"%bۭ݇V:%p&\E9~2ɒ^EݮMoϯ0!H /#96;UV6ߚa$su$oSAHrIAaD"s/7Sj0U{Q8"t!dnCQNYn &eyuʤA UJ8<"5 O2/Dg~ǍbxDt*~<)a,V)SH1=ޚp%A<#3oЖcյkD`[G`Mt]5K�v" ,K {]ACBM a*Nac�o]Y�@�*Fț2;cѽ.8 ! 1өPbllVm]0șH90hʓs+vo1S @2))ܑ΋C]X? iyihdR5U]]wkP@�̉ǂāB^{emhlFVpK[:R)%ž80\TXO~LZ()�5sjH]ѧ�=\k)b$[`anirUY*i"Gˠ܈3I4 1ʄzwdQ U^zٵiȄ@vaF_ LU>>٤\m9><Jwܺ*Bں]sʡ1$@I= Z(Iz^$ RtDP<4G)o*<,7We j 'B,?!PS+O1�@&ӟ xigSzm=W fJGd>L]$c@nA cHQp~Z+éM1N$SK !GxZTzfwj !XG襄ctndH1di+ Mׇwގ GqJvU;z^]Q%QM;9 ˧h2|t_nao|P]S$ӧ См %s0+GOx'24�6 Ӊm.GҎ;/ p8S@=�# 99R9eD?`?O5yk]A5p~ʸ\n,ȘH(\B\c.“SLxs&�VeS9;?_^b2fm9 3O6 3'9te Z /O0X_-$3Ҳ<+7ufRaC xB5R %~Ѯ;'p?~&"1`hyӆSGa; P{tUě|M4̚;\LR}ODFXYl7}2 5Yy5w>>]̇Z/]�` rиAI2/<: ǯL㑤r^Fxn9un0EXe40Br?" endstream endobj 589 0 obj 1615 endobj 587 0 obj << /Type /Page /Contents 588 0 R /Resources 586 0 R /MediaBox [0 0 595.273 841.887] /Parent 569 0 R >> endobj 586 0 obj << /Font << /F34 5 0 R /F15 7 0 R /F35 43 0 R /F30 42 0 R >> /ProcSet [ /PDF /Text ] >> endobj 289 0 obj << /Type /Font /Subtype /Type1 /FirstChar 0 /LastChar 127 /Widths 590 0 R /BaseFont 596 0 R /FontDescriptor 597 0 R >> endobj 590 0 obj [ 963 380 963 639 963 639 963 963 963 963 963 963 963 1222 639 639 963 963 963 963 963 963 963 963 963 963 963 963 1222 1222 963 963 1222 1222 639 639 1222 1222 1222 963 1222 1222 768 768 1222 1222 1222 963 366 1222 833 833 1093 1093 0 0 704 704 833 639 898 898 963 963 768 990 813 678 961 671 880 747 1059 709 846 939 854 1427 1006 973 878 1008 1061 762 711 774 785 1223 884 824 884 833 833 833 833 833 768 768 574 574 574 574 639 639 509 509 380 639 639 768 639 380 1000 924 1028 542 833 833 963 963 574 574 574 768 963 963 963 963 ] endobj 591 0 obj << /Length 592 0 R /Length1 593 0 R /Length2 594 0 R /Length3 595 0 R >> stream %!PS-AdobeFont-1.1: CMSY6 1.0 %%CreationDate: 1991 Aug 15 07:21:34 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMSY6) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.035 def /isFixedPitch false def end readonly def /FontName /AAAAAA+CMSY6 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 0 /minus put readonly def /FontBBox{-4 -948 1329 786}readonly def /UniqueID 5000816 def currentdict end currentfile eexec oc;j~EЪ/ ȭX~id}S5Q!gtⵎkJc;rN^X5.Sy +'IqV:r㚉#,# dBZ *R*"7٨y! [R߷`]{W5Iew4 9ۍBj$T>R-%thE$/JLH\wdQ_RL@C>v[2AX>'ƋX'Yb=aj1T'{!q+3^3p<�{-O$Ց0H}RX~K2SsIq V9`D̊uW^rv&{_}-z4rԨ4⅏?ńΩ"P( VT ѷNB~karɪQ}'Y":(6FI Qx@ uwGܯ|tEzSm;&KQ t<WEa2I-e/E0ko,V"'}򎁗lw9~1Gt]M ?mF6(*W Qꨮ?.=0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark endstream endobj 592 0 obj 1897 endobj 593 0 obj 766 endobj 594 0 obj 599 endobj 595 0 obj 532 endobj 596 0 obj /AAAAAA+CMSY6 endobj 597 0 obj << /Ascent 750 /CapHeight 683 /Descent 0 /FontName 596 0 R /ItalicAngle -14 /StemV 93 /XHeight 431 /FontBBox [ -4 -948 1329 786 ] /Flags 4 /CharSet (/minus) /FontFile 591 0 R >> endobj 163 0 obj << /Type /Font /Subtype /Type1 /FirstChar 0 /LastChar 127 /Widths 598 0 R /BaseFont 604 0 R /FontDescriptor 605 0 R >> endobj 598 0 obj [ 735 1021 953 854 817 955 885 953 885 953 885 715 681 681 1021 1021 340 374 613 613 613 613 613 922 544 638 885 953 613 1108 1244 953 340 373 636 1021 613 1021 953 340 476 476 613 953 340 408 340 613 613 613 613 613 613 613 613 613 613 613 340 340 373 953 578 578 953 922 869 885 938 803 769 962 955 459 631 956 735 1159 955 920 835 920 915 681 852 939 922 1263 922 922 749 340 636 340 613 340 340 595 681 544 681 561 374 613 681 340 374 647 340 1021 681 613 681 647 506 483 476 681 647 885 647 647 544 613 1225 613 613 613 ] endobj 599 0 obj << /Length 600 0 R /Length1 601 0 R /Length2 602 0 R /Length3 603 0 R >> stream %!PS-AdobeFont-1.1: CMBX8 1.0 %%CreationDate: 1991 Aug 20 16:36:07 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMBX8) readonly def /FamilyName (Computer Modern) readonly def /Weight (Bold) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /UFAAAA+CMBX8 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 48 /zero put dup 49 /one put readonly def /FontBBox{-59 -250 1235 750}readonly def /UniqueID 5000766 def currentdict end currentfile eexec oc;j~EЪ*BgNӽ ؑlKq*޲Xws|QFqv`zXMyp"5O˩YŝP(DT!�[v67XFlU&3!Rq4wσ~j+ou_rP0K,ЖJmY:8I ojqhZ�+:mmҜZW.p{`4L> wL~TO J=lvbޅu{?m}da:RJٶnjт6igx0ΫLMlGxd ;t5ct B9}/ƨNf2Iȥ˦Br]]BI~b+\1(aM-p*7ba$ǰz5OH'xऺ} %'HXNk0B(7)srDq±4<'tU%t9oy#5 @*4fZGt)ʛ ܐ_aT͡\Ɗ{#ld [#h8>[seCf CVǗxgQxH+6>;>.H_IjV,1ALRv46'{W[J^tZwL  쑵5Oµ}i^)/p+u.k^Bw sZ iܭ[0$ݚb4Ffq<aaaQP)ɮTh*5΀Fv݌Uw`4SS+z:_75DZS$UOQdM:%20oJ[cF`҉,~)xm0 %vR3 p yunnXwRμaR3Z NOE0 Ҩ"ou<QX.@6SW_lkc>qd=Wh`Cn@9+øiTY]JlB`s擭YQEe"ps8Ln΋WTbAZ9잪& 2-SxCF4̱"Iq:R([uc+fhpu]%!tkP� ,A?Ab˳Jz(FwX/@c"4$6 n I$h_Cy녬yr#p?X2j΀d^WiZ 0umذmeEi�QJƂY!J"O2պܦo,�ϡj{+\McݔD0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark endstream endobj 600 0 obj 2591 endobj 601 0 obj 775 endobj 602 0 obj 1284 endobj 603 0 obj 532 endobj 604 0 obj /UFAAAA+CMBX8 endobj 605 0 obj << /Ascent 694 /CapHeight 686 /Descent -194 /FontName 604 0 R /ItalicAngle 0 /StemV 122 /XHeight 444 /FontBBox [ -59 -250 1235 750 ] /Flags 4 /CharSet (/zero/one) /FontFile 599 0 R >> endobj 133 0 obj << /Type /Font /Subtype /Type1 /FirstChar 0 /LastChar 127 /Widths 606 0 R /BaseFont 612 0 R /FontDescriptor 613 0 R >> endobj 606 0 obj [ 743 1028 934 859 907 999 952 736 833 781 946 804 698 652 566 523 572 644 590 466 726 736 750 621 572 727 639 716 582 690 742 767 819 780 587 751 1022 639 488 812 1222 1222 1222 1222 380 380 639 639 639 639 639 639 639 639 639 639 639 639 380 380 963 639 963 639 659 924 926 884 998 900 775 953 999 548 682 1026 846 1161 967 934 780 966 922 757 731 838 730 1151 1001 726 838 509 509 509 1222 1222 518 675 548 559 642 589 601 608 726 446 512 661 402 1094 770 612 642 571 580 584 477 737 625 893 698 633 596 446 479 787 639 380 ] endobj 607 0 obj << /Length 608 0 R /Length1 609 0 R /Length2 610 0 R /Length3 611 0 R >> stream %!PS-AdobeFont-1.1: CMMI6 1.100 %%CreationDate: 1996 Jul 23 07:53:52 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.100) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMMI6) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.04 def /isFixedPitch false def end readonly def /FontName /BMBAAA+CMMI6 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 23 /nu put dup 105 /i put dup 106 /j put dup 110 /n put readonly def /FontBBox{11 -250 1241 750}readonly def /UniqueID 5087381 def currentdict end currentfile eexec oc;j~EЪ)s̾;.;rTejiK/df5A|{S/ )Sc\^ȟmp+#vL17~k d# ]LeVߐGoo٥\k 9M֨[G(aܘ|RP6n=: b9s2m4{~CD%x4,Cvj-?xvynhQ`?f\ [BhnVGXad&ǻD҃gWGa0^)|*?ZHqr@w8~'I_o3Pf4!Y^afRo 0 /băEЪTBfQ\DNy~ e<m^aipc;Ve:Q7vsċZgQmT<t]Q)'~l iIMB,3pI]rS:D͑XA)#2Nnؼz!';[_;U*a?5}q'=[?x@%맀 %ѡo)(aFJ̥:N"9Dtђ+z,Ba ƺ2˳c䰑LϚ\ zJK ]%%Cgxݧ3;mQ4#؝/P�oB鯌IJ/eOm 2(T34&Y w&t=\=dEV}<(+yEi*]PԿ62ķlz`u`XtG;%Gלcfץ,L3P.e->z.qRC3;VemB�A/TF_{} < ^niff[+/^Ї7XYO`5-;\`$,$wTv؏=h~+,h;CFRJ]ɥ?U\bJ3P'׮WC),!4}%hnDsES<!gAa1z \56$qT1A,bc�IucۇHȕ.9≛M7R⍄FE vPXo LӮ=RF˯7h4K/̢K7+1EʘF $wRW*K>YP_&ٶg-T5 jK6}\>VAcFd=j  |~q,7nH.qL=j>:B+Z4658)Es2 Giz&W6q򯅲\I$ �]ZFgTj>iYEiٽ͇5Xx9 lA.U)PNYG7=PfSY8V9m[D0q` S9H/=y{7etM' &?,DJn[9qhNཹϲO ?9/g愆%71j$\%FXpU6eJœ!*^"UH:4tg #-s9vcq3P?<lh j<P w" WGwdFogbΌ5Qwh.7ue?V>"J9cM*s}:D&bd0/AGNXOZĮ޵ 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark endstream endobj 608 0 obj 3131 endobj 609 0 obj 812 endobj 610 0 obj 1787 endobj 611 0 obj 532 endobj 612 0 obj /BMBAAA+CMMI6 endobj 613 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName 612 0 R /ItalicAngle -14 /StemV 85 /XHeight 431 /FontBBox [ 11 -250 1241 750 ] /Flags 4 /CharSet (/nu/i/j/n) /FontFile 607 0 R >> endobj 107 0 obj << /Type /Font /Subtype /Type1 /FirstChar 0 /LastChar 127 /Widths 614 0 R /BaseFont 620 0 R /FontDescriptor 621 0 R >> endobj 614 0 obj [ 458 458 417 417 472 472 472 472 583 583 472 472 333 556 578 578 597 597 736 736 528 528 583 583 583 583 750 750 750 750 1044 1044 792 792 583 583 639 639 639 639 806 806 806 806 1278 1278 811 811 875 875 667 667 667 667 667 667 889 889 889 889 889 889 889 667 875 875 875 875 611 611 833 1111 472 556 1111 1511 1111 1511 1111 1511 1056 944 472 833 833 833 833 833 1444 1278 556 1111 1111 1111 1111 1111 944 1278 556 1000 1444 556 1000 1444 472 472 528 528 528 528 667 667 1000 1000 1000 1000 1056 1056 1056 778 667 667 450 450 450 450 778 778 ] endobj 615 0 obj << /Length 616 0 R /Length1 617 0 R /Length2 618 0 R /Length3 619 0 R >> stream %!PS-AdobeFont-1.1: CMEX10 1.00 %%CreationDate: 1992 Jul 23 21:22:48 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.00) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMEX10) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /BFLVST+CMEX10 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 16 /parenleftBig put dup 17 /parenrightBig put dup 18 /parenleftbigg put dup 19 /parenrightbigg put dup 20 /bracketleftbigg put dup 21 /bracketrightbigg put dup 32 /parenleftBigg put dup 33 /parenrightBigg put dup 34 /bracketleftBigg put dup 35 /bracketrightBigg put dup 40 /braceleftBigg put dup 50 /bracketlefttp put dup 51 /bracketrighttp put dup 52 /bracketleftbt put dup 53 /bracketrightbt put dup 54 /bracketleftex put dup 55 /bracketrightex put dup 56 /bracelefttp put dup 58 /braceleftbt put dup 60 /braceleftmid put dup 62 /braceex put dup 80 /summationtext put dup 82 /integraltext put dup 88 /summationdisplay put dup 89 /productdisplay put dup 90 /integraldisplay put dup 104 /bracketleftBig put dup 105 /bracketrightBig put dup 113 /radicalBig put dup 115 /radicalBigg put dup 116 /radicalbt put dup 117 /radicalvertex put dup 118 /radicaltp put readonly def /FontBBox{-24 -2960 1454 772}readonly def /UniqueID 5000774 def currentdict end currentfile eexec oc;j~EЪ*BgNӽ ؑlKq*޲Xws|QFqv`zXMyp"5O˩YŝP(DT!�[v67XFlU&3!Rq4wσ~j+ou\Ƨ"v*o$1|#`ݧ2YȎK@瘉!QgDVWܑ>{03{iEmW~?B(403"Ԇ9NLJG9LNIWnNRY[dm+IfN|=cG5yJi,dRht x<#^!V&1qE1[nض{3#a#!LLk-(PAh1IvYK1[VYѲY*a�FnH DhPPtHH'Í=(ճAf(8JH:cX~ ۘzkcF8!hG"Vpל wp _>#5J *fvb I3YeAIȪ]%RdxL > ׺Z47ו wqc>y66| ` - E>` P5@Xmx1b@CDDx3r tK0n#5~@�rS&`YCl!;Tߞ{>MX"_|#xw{UJC31I̲r5Wn.HګX!;&/kCCݢ:lrˬ/Bn\/^Xh'$ސ>leOK((*/ =xK" 76RYJHwEM\PB쟋N ͨj=D}0ZX`:ZcMC~1!--_Ѱ zL\K2yn1_>S/؊9 \>^Ҟ[Ǹor§:p$u@8kz\y4z/G]k<ٓR^󞰚>_L e,5y5hKÖlG@3IΫӵ@e C'xQ l7\!BsLJ(Ikv(UH1.+S EB CmmF,[0>%>atMӐp5>ya FۊEfb UvQDLg2GVsRs". VKh"$z#4וFYb~e#.ꀦD+-.>l#^Ɇ1,.|[/y PZ;d?thÌJOfzqmxؔԲxfTtr�nIX/]vpn9ЎKLfufi9m2[H܆e2v1﹓Z0z{ʝWpZqmSzxǛ3x7(s.FD f(~ߺchPd^JAʶ*Y;_V):EOdȾ{[s5jȖͲl./aM֍O &رjA{C(zә7}K ܬkmƪ/-*Obd}miNJ6@]5۸ l*sK&)K"6+iz@)ZRS-:Tg;0wtyW�a@?Íu%K> >p#@z"|/7%Y"ۨھ4(ʻ^2th myS蹨Ǥe0*;|SNrs+i ~ߡIJ}^f3VBJ]P)P 7EEd̒6[�*^,?.R!FȜހA#9pvүHoX(s5obZbLh3K| R[ O8O$>-c3Ήxw]s4vT.L<`Gm*&~F J.'FGU I w`{aZo .┝X\KDM{(@;Vqcc>.?"q*p#m\ڂD> 3~'@G& hWF8&6OUrq~\ Ifq(�{<Jӝj$%m87u8N8VC:n}Afg0OMi4D3,Or ^8t&i/bǠDsDfb=,o쵤 #:2;vɁQ=3"H{3Ə'f-ڻNm2gD f -@x˸A*nד�P#ir�< <N㡼:7aP'hNrqJwՓq~s .QFNLxWYN媥S:( {Wa@\ęf*cpl^ ^C1ǒe7Y:Kvo]&oGfxJr qS;EiĤRue.5)'Z c8T{9_:fpJM<InS(#`BIŒ%nr\+f%6Tok;uٔD 1>w"Q!ՉlYs3z0\J ukQJ ͌>!v+3AdDnԳgxb*&/ofBIEZhiGH}'5LfZIF+G QڵUè)ctQ;ێ-$Q8H<[ kQpQvzrp/'Rm( j>6 (بdnGӺ=K MrOe=X|6[N(׬є=[;iPL4!LuW7?1ӧ`D<IJ;vĿ;/⃙6e&%cCPW tJ؇*Z88reFA!&Mɜ6BX+#y8hɩ&W 8Q|9 ScP{+]o/#.joj-)M +Jņsq"=O\vT!4|v' u jsl6uY/< QgT#!s%!쨪5�U~nN0$kH*yuȊBj^J ଢ଼F /Hh.ЍR" ZaNM4—6uZ~6LT>_T1x0|h2B j (UB7=؍̈́'Y<ra}A| ~N\|t>N&{$PBqhR>-)u8*Gd*'?V XˋwjQv^1RE *!q;ctQ&P'$Bן<`vk]9W<ϾѮTh;V,ݪl3*fVn"ȏHgmQ?O[E'/ �r5P!5Ablu$W)o$u7*0˭Mˉ D[7?}ωL`rj٤RZnal/s<S5n�r9r4f-Wq0H+R{ߦ{UNSfк-_kC:f`}2F/%C!O4#h/u8KyW hwO`u`pU|k陿ќN_444Ȓ~og{?[qV۞h> ߤ__s3jussw+4l@iX'1iHH%*G<-2&UW b439cξLQ)!+He2Hۿco]y2IW͉# dQtޔ×W1E �(M9qNy$}S蛉t>6M l-=܁)΋ݜn9vRU%uV5:sq~\򿺚<Zu g\3a{| zA;|P#ao?1 BL30by4vo٨#@L7g}ڀoxꦅt\t>T}f՘^kőj !Am.Ia꼇f^b5JAy~D3O~3NjjAo x i1=qx.w[!9Q%dً8]yj!a-!p~Jro\ )[oqjGMsMb<}>4qqY=͟Zr ^Bk"A6K$?p�kv7ڋg4Nc`CjGejy^{6y9ؿwHGvlkԃQMg y$"yȐ{ 醿s=( 5n^4_WcHM#tzYtc%1jQԖ>/ߚvZy)ȷsD[ @*JfDAbsX j^P@K;J/_?jGWBiU Jh8o L+˵ˉZdˀ[pVkԧつ/㎄7thlX> wu@jB04FΑdk4012J"lSm]is]оa*=~'^`zS;N,;ekedžY"sN{0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark endstream endobj 616 0 obj 7171 endobj 617 0 obj 1613 endobj 618 0 obj 5026 endobj 619 0 obj 532 endobj 620 0 obj /BFLVST+CMEX10 endobj 621 0 obj << /Ascent 40 /CapHeight 0 /Descent -1760 /FontName 620 0 R /ItalicAngle 0 /StemV 47 /XHeight 431 /FontBBox [ -24 -2960 1454 772 ] /Flags 4 /CharSet (/parenleftBig/parenrightBig/parenleftbigg/parenrightbigg/bracketleftbigg/bracketrightbigg/parenleftBigg/parenrightBigg/bracketleftBigg/bracketrightBigg/braceleftBigg/bracketlefttp/bracketrighttp/bracketleftbt/bracketrightbt/bracketleftex/bracketrightex/bracelefttp/braceleftbt/braceleftmid/braceex/summationtext/integraltext/summationdisplay/productdisplay/integraldisplay/bracketleftBig/bracketrightBig/radicalBig/radicalBigg/radicalbt/radicalvertex/radicaltp) /FontFile 615 0 R >> endobj 94 0 obj << /Type /Font /Subtype /Type1 /FirstChar 0 /LastChar 127 /Widths 622 0 R /BaseFont 628 0 R /FontDescriptor 629 0 R >> endobj 622 0 obj [ 754 1000 935 831 805 896 870 935 870 935 870 736 704 704 1055 1055 352 384 611 611 611 611 611 896 546 611 870 935 611 1078 1207 935 352 352 611 1000 611 1000 935 352 481 481 611 935 352 417 352 611 611 611 611 611 611 611 611 611 611 611 352 352 352 935 579 579 935 896 851 870 916 818 786 942 896 443 624 929 754 1091 896 935 818 935 883 676 870 896 896 1220 896 896 741 352 611 352 611 352 352 611 676 546 676 546 384 611 676 352 384 643 352 1000 676 611 676 643 481 488 481 676 643 870 643 643 546 611 1222 611 611 611 ] endobj 623 0 obj << /Length 624 0 R /Length1 625 0 R /Length2 626 0 R /Length3 627 0 R >> stream %!PS-AdobeFont-1.1: CMR6 1.0 %%CreationDate: 1991 Aug 20 16:39:02 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMR6) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /JCBAAA+CMR6 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 43 /plus put dup 48 /zero put dup 49 /one put dup 50 /two put readonly def /FontBBox{-20 -250 1193 750}readonly def /UniqueID 5000789 def currentdict end currentfile eexec oc;j~EЪ*BgNӽ ؑlKq*޲Xws|QFqv`zXMyp"5O˩YŝP(DT!�[v67XFlU&3!Rq4wσ~j+ou\@[6]nhmlhaH+4/?3&n=a6E#|~.ԅˡ}_B$~\|"4Pxҍ>P% ~ߏ4q.C3s蛼q翈by?Z72z6LpHC1D"28s B ~ OPQ O\O}<zQ}# L TRh<c8lL=5)nIbw`vdȨAtG=c"?Aˮ`=kߴ|Ns8ݩQUD˯m<X# THltĢWp:ϑХ jmNf6*t.4jK^S<cK(pKڍ5Q+'E멯ԛy#{V1P0nu]j⠪ � :)shfWPd!]BOڡ8gnYs%N+uV.wxHF&(8E)m(&,SI~fq0dLǟ-BA (žW4?_F/(`;W42ߗOP?#NdC֤0>l4x<KUhɏX@KyְQJ@lRJ> ^;CTQ됧[I/=G6n0X9q(Ck W0h%q~YPx*zz<V`0tfr#='*?vo8ȡ k)1~\-efm]~BI zږR. ZFōLNj<hx%~oa,3_t[! aDoogbWjzU K�\pIu0+10@YxU1ś^BV_'cFt 5'pm[;'U5zILfPE*LoaRjXV>E<͕KfIX tVY"m1J4 qXx*Ԥhh+\Lr HA#ɨr3' 86rMFT+-1'=Sg]iǿ5qΙ0 {N=XI;Jzy;0Vd4Tp/35G-_(?DHYeu5cߑu('IFV spf}hp˝3�tDp"1;s�"]Z:*/v19;( uiRkONǔԺE]0y{1SF !_X[X~1hF.,ѼpLDM:(O']z!˦8�0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark endstream endobj 624 0 obj 2885 endobj 625 0 obj 807 endobj 626 0 obj 1546 endobj 627 0 obj 532 endobj 628 0 obj /JCBAAA+CMR6 endobj 629 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName 628 0 R /ItalicAngle 0 /StemV 83 /XHeight 431 /FontBBox [ -20 -250 1193 750 ] /Flags 4 /CharSet (/plus/zero/one/two) /FontFile 623 0 R >> endobj 93 0 obj << /Type /Font /Subtype /Type1 /FirstChar 0 /LastChar 127 /Widths 630 0 R /BaseFont 636 0 R /FontDescriptor 637 0 R >> endobj 630 0 obj [ 826 295 826 531 826 531 826 826 826 826 826 826 826 1063 531 531 826 826 826 826 826 826 826 826 826 826 826 826 1063 1063 826 826 1063 1063 531 531 1063 1063 1063 826 1063 1063 649 649 1063 1063 1063 826 288 1063 708 708 944 944 0 0 590 590 708 531 767 767 826 826 649 849 695 563 822 561 758 631 904 585 720 807 731 1265 869 842 743 868 907 643 586 663 656 1055 756 706 764 708 708 708 708 708 649 649 472 472 472 472 531 531 413 413 295 531 531 649 531 295 885 796 885 444 708 708 826 826 472 472 472 649 826 826 826 826 ] endobj 631 0 obj << /Length 632 0 R /Length1 633 0 R /Length2 634 0 R /Length3 635 0 R >> stream %!PS-AdobeFont-1.1: CMSY8 1.0 %%CreationDate: 1991 Aug 15 07:22:10 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMSY8) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.035 def /isFixedPitch false def end readonly def /FontName /AJDAAA+CMSY8 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 0 /minus put dup 14 /openbullet put dup 48 /prime put dup 49 /infinity put dup 62 /latticetop put dup 66 /B put dup 112 /radical put readonly def /FontBBox{-30 -955 1185 779}readonly def /UniqueID 5000818 def currentdict end currentfile eexec oc;j~EЪ/ ȭX~id}S5Q!gtⵎkJc;rN^X5.Sy +'IqV:r㚉#,# dBZ *R*"7٨y! [R߻*|]~[C֨a[#ԙ jY!4J"3&ejc\J$2626wIaUIrnFB/Г(Hp%#O.,snݸt%\b9?_\ <+n6<!H<:HZF+ Zݛ\ VT ڐ=c8@0.Q㼀~>f Sf/@ 6M+E^o!L~=G>"r -gjɟӖ^ yYρHU!ҝܚ-6v7Zm 'tmjhxژ"l,te1hkh48{LMu�0y'\2ʷyiWrF0bCk@M߇i@7hrjK]nlS~ y*r˦E55FΏG?QcW1\S` =YnkN%]9WI#)F=#،T/JcGm9yle0bw;]BLc'4)GdKL5R4V_A~Eh}` a<a47"2*K-pj:KoS*DJȅoPaJ6]CwQA3Q$I:Gd=6d3Z�EO:HAh4߹j\I-^5b1͒ OK̰W\][]kԎ` @C?Pyܟ߃oMaR/ x<uQitqE(C۔gHcE:\#Ȑ۞6@S5W1 B]Eq5RSD|D_p6=ϣT2sFxa}w ޹OT-dp[ū(lur9ij* &MO-e|k7b+ Zīƚ/[9OЖ&ЉKTFs;cXG\f \ӓo$+(K�WJ1~_ [DqP&ߦ8P`d@Esvj~}莠C./.ޗ>` @E_K3ngVXY|B b<=<=)ڶˣ+y�?59e1**| 4!Sֆ1N"OY̱޿"G%n8� "ʹжTIGa nf!oGEw"Im8VT69h0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark endstream endobj 632 0 obj 2882 endobj 633 0 obj 887 endobj 634 0 obj 1463 endobj 635 0 obj 532 endobj 636 0 obj /AJDAAA+CMSY8 endobj 637 0 obj << /Ascent 750 /CapHeight 683 /Descent 0 /FontName 636 0 R /ItalicAngle -14 /StemV 89 /XHeight 431 /FontBBox [ -30 -955 1185 779 ] /Flags 4 /CharSet (/minus/openbullet/prime/infinity/latticetop/B/radical) /FontFile 631 0 R >> endobj 87 0 obj << /Type /Font /Subtype /Type1 /FirstChar 0 /LastChar 127 /Widths 638 0 R /BaseFont 644 0 R /FontDescriptor 645 0 R >> endobj 638 0 obj [ 664 885 826 737 708 796 767 826 767 826 767 620 590 590 885 885 295 325 531 531 531 531 531 796 472 531 767 826 531 959 1077 826 295 295 531 885 531 885 826 295 413 413 531 826 295 354 295 531 531 531 531 531 531 531 531 531 531 531 295 295 295 826 502 502 826 796 752 767 811 723 693 834 796 383 545 825 664 973 796 826 723 826 782 590 767 796 796 1091 796 796 649 295 531 295 531 295 295 531 590 472 590 472 325 531 590 295 325 561 295 885 590 531 590 561 414 419 413 590 561 767 561 561 472 531 1063 531 531 531 ] endobj 639 0 obj << /Length 640 0 R /Length1 641 0 R /Length2 642 0 R /Length3 643 0 R >> stream %!PS-AdobeFont-1.1: CMR8 1.0 %%CreationDate: 1991 Aug 20 16:39:40 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMR8) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /NYVDLX+CMR8 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 0 /Gamma put dup 1 /Delta put dup 40 /parenleft put dup 41 /parenright put dup 43 /plus put dup 48 /zero put dup 49 /one put dup 50 /two put dup 51 /three put dup 52 /four put dup 53 /five put dup 54 /six put dup 55 /seven put dup 56 /eight put dup 57 /nine put dup 61 /equal put dup 68 /D put dup 78 /N put dup 99 /c put dup 101 /e put dup 103 /g put dup 104 /h put dup 105 /i put dup 110 /n put dup 111 /o put dup 115 /s put readonly def /FontBBox{-36 -250 1070 750}readonly def /UniqueID 5000791 def currentdict end currentfile eexec oc;j~EЪ*BgNӽ ؑlKq*޲Xws|QFqv`zXMyp"5O˩YŝP(DT!�[v67XFlU&3!Rq4wσ~j+ou\@[6]nhmlhaH+4/?3&n=a6E#|~.ԅˡw,"rg[eH�i>u Wת>~ӖѿJmdvA [4|ܾ.Vz_1. Ff |X9^Rw] ۊ31S\DKZW` P^3 eێ 8`2?l;Ȋ!eXxh Df@=$*IBXԏ!Wx-b1 C; p}hQi=HXbgbmǣR,>_Q! Z؞Ar]< Qjt8?B,mN3v լǵ+K6 t{AJcQ%r?v60RmXsŤ+pǸi:Us)kPW\~;� 7T.N }.&:D~4LDV5bgANӪ&׏+“Ļɂ? \Sek鬁dVPzjmSȬߤj;-0@3�q!,ay ,`y۪ik9kmosrA~}wڇ$Ĥtt&px: J,Me'�EA"NL?dFG۩SC;XnROIZnekg={w/1tsy=.s %$@OB\5]`oY%`Zɴ>`",ݲchU~{IV s(M'MglMTD'lˇUdx,CRnP78$)f^9,&N`tVDAj yYfB`쉮Fwuq%e`h2aI:MU#@"Ilw*i_`9dRBaV'/ՎTpÇf !OZNJodI,V(7₝ld cYyYC3?Ҏd''TP&gj [5Su*õ 0:ڵTYí.8Sܖ fːM)Ī7`CdB o=%_kO>{'F޻vkӿw75dŏwkxH;WJVS)|)Oki+Bʭ@Hpῠ~;ڵO7)4X ?Û,2Zr1\" Jfm9k[`N 3:ؼi^eb$F&{*J@?,01ܦu9>< Uutǐ#l6 "n*҄m+-tm�u!,z*:b).3)Q˨VDO4}hCWWlL_FBZDHĄGʦD W_Awz r*LxƳPI|B*m8 d #D* VO/&1?/@ui4v3jˇ{Im^I"#S>F %gJ).\u*,ADϸCӴ여ۤ25_)e۶yB|`a\<p)-@zp�n>іSY$o�n~Ufdm @ْoMEhEٙ-Kmb2ѡpTAŭ/Ş8ŃS5t~D@Bz002V5f,1;  *Zg%ڭ˯Ie=|\dJx^ocΨ4c_)6Bhsɛ.;7䱡?wP']ȶ Nlk 9.~Ytk.�Nz6H?͋YVM'e[ !띭[tǔBz<U'm 1yuԱA"^m B56!(EH-XQ_ hU<_zL�-*k֖�}"شzA[C5B:|mZ2{g>A"b^ ).,ۭ,VFRN~@mx?,I6[xmqz"YԸlķ1]zZQM4;[md@=aӓiФ Du& dPR_~)\ Slwf4d5}z*6it*_ ;F tHZi }ܟ]*nkS}OKͤSE79f{YDaMS]hWEoR . H 419}ngDc$[9YNC5B-o!3blxkc<c<0P,B#йŶ0N.|8Q] V+9$3 ^1<IjXRv\},iP�5ficեlzğp@|ʅYFOZ6C H@Ѷ�$SB|Oy<w)з fI gpɆ[ nnyi �F<+3v̌i%+6ZIM?쟝Bڹ,ͷJ uL)ƹ e,ڴ '/f+9ONJV b kERR$ -C<&84 F*{<35ȡ?oh/BlBRGSY;ZcWp'2;"ѶtdևMɷ=K1zQ$k7*7~Ů՝Ӗduohxnk$`]# k?T#-h5e y/ -m-R+N^̙SWo(% `[0RK7o\/WcGP'okY!H_u=Qv�imV˘ o8i={j 5&ѲfEkֲ~%EY|[ʱ*o h\o7ECFօ @-`0snihH7A#?2u,_^)#71a܉]G$[a0)靴cAF{"c{{I5RfV!<~ ZF*ښ3s$83E0=sJ՜X)![JlBqoҰ[5qѪB1v�nZ\6;qr?'SXyˆK`B>;p.;).=%΍V=6}o9*`amFW|$bAc6Rz6dv̞ݯP6?<;F؀nwԝ5F/P*|~nB8:*!7| U A!ly\U3%k.!@ו΍/fL:AV5~gL7"4;5]ݲ{ D1RGiKHXqLPet�kŧ}d6NE6W=z+d^~a^* {$'jiM D&>&/?s;PIY88^b$F>f{ꂰZa1]aݿg.|Wdd;S%r(OEsgj-&Fl`H܌"O7saEATVc2; zr3%hsj ,|̄jW 'R۸tEry̒2�zqO}L˃R g7Ws@j5HSg)M9 lY! S*d $QYℱS8i[a%h#Wgݏbp^,)cD򏎓KAFm/!M'EԺĂ'|b< v;Y:&f~Y#c]s:G 87FqPVM%@fyPu6)LUPfA%'xjjL J| Ӥ3U V ( #yϛ�i;ԡ=tf ol:*p|v\ДLГ'V(:v3V&輐\jQR'M2Ѯo8JVabyuЉ{-P ̴ޑhɧO}t+&`q~DŽ0tZ"{,qmh<1#_,P1dG@)J{N_C*P\k,:(#pBwlXB5W'wll[ᢂߴgk*h-<HB ,x"XW~]T,2ƍ]ws<�3w*{&d$fnR)B,(q$,'Krt!Όq?Q#Y bx*!z1eRLT!ݓH6 ]�� &=uc\ʂ -рChUԆFDqJp 7&uvj�ۼΞkl"�K!VRn#Ph8$0Dˋ$器{AV"AO_�v z`Pe1싌`1ʵ8j|4ܵ;1%Vk0ܻ>I�Ea]Y)yK1\:N\Կ|}Ys8#_zQ%0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark endstream endobj 640 0 obj 6721 endobj 641 0 obj 1172 endobj 642 0 obj 5017 endobj 643 0 obj 532 endobj 644 0 obj /NYVDLX+CMR8 endobj 645 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName 644 0 R /ItalicAngle 0 /StemV 76 /XHeight 431 /FontBBox [ -36 -250 1070 750 ] /Flags 4 /CharSet (/Gamma/Delta/parenleft/parenright/plus/zero/one/two/three/four/five/six/seven/eight/nine/equal/D/N/c/e/g/h/i/n/o/s) /FontFile 639 0 R >> endobj 86 0 obj << /Type /Font /Subtype /Type1 /FirstChar 0 /LastChar 127 /Widths 646 0 R /BaseFont 652 0 R /FontDescriptor 653 0 R >> endobj 646 0 obj [ 643 885 806 737 783 873 823 620 708 655 817 682 596 547 470 430 467 533 496 376 612 620 639 522 467 610 544 607 472 576 632 660 694 661 491 632 882 544 389 692 1063 1063 1063 1063 295 295 531 531 531 531 531 531 531 531 531 531 531 531 295 295 826 531 826 531 560 796 801 757 872 779 672 828 873 461 580 896 723 1020 843 806 674 836 800 646 619 719 619 1002 874 616 720 413 413 413 1063 1063 434 564 455 460 547 493 510 506 612 362 430 553 317 940 645 514 535 474 479 491 384 615 517 762 598 525 494 350 400 673 531 295 ] endobj 647 0 obj << /Length 648 0 R /Length1 649 0 R /Length2 650 0 R /Length3 651 0 R >> stream %!PS-AdobeFont-1.1: CMMI8 1.100 %%CreationDate: 1996 Jul 23 07:53:54 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.100) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMMI8) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.04 def /isFixedPitch false def end readonly def /FontName /QIBDBL+CMMI8 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 11 /alpha put dup 12 /beta put dup 22 /mu put dup 23 /nu put dup 25 /pi put dup 58 /period put dup 59 /comma put dup 61 /slash put dup 64 /partialdiff put dup 65 /A put dup 66 /B put dup 67 /C put dup 70 /F put dup 75 /K put dup 78 /N put dup 82 /R put dup 83 /S put dup 84 /T put dup 88 /X put dup 89 /Y put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 109 /m put dup 110 /n put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 120 /x put dup 121 /y put readonly def /FontBBox{-24 -250 1110 750}readonly def /UniqueID 5087383 def currentdict end currentfile eexec oc;j~EЪ)s̾;.;rTejiK/df5A|{S/ )Sc\^ȟmp+#vL17~k d# ]LeVߐGoo٥\k 9M֨[G(aܘ|RP6n=: b9s2m4{~CD%xSd,&jA x"ПmѬ,+;ŝboB|ծTboI*VDZBJϟ2a{Y0Q(/e@AGƀ挄п]w}ga8.ݲ cS,t^Ujq.or!N]@j Gē75uʑm$KWNWVF2P,KP˻ 62abw;SBֳ{ u&DChNe^L2Ib^ǞY62"CSl5X!okR6D UjT|S{G3:6A| ٺJ 33kLKEnMpٽqlHZoxV <Hzg |T}8De *Ǟq'Aq)ؠϨN6LN̪] zZ`aղ?pܣ ioP}WYPeE\뫃FO&I p]&9Ik~"۽v 'ljN_pF&J\{�T"}׮j*6|*PvL:ݺREJ;E!242[m<sJEjj{q%?Ab&2rc+ИIy`8qE6HYNrL₺(CzY±bݯcU 5 Ipc[$AupSak2ڿ0޻f(2O_{,ʛ%k@Ajywx9w?fI!.nN@Ip빏٠ ʬ-vct%vԽ1 3P:ѱ~xxjCgζpsk…>|�]sgǘ"$<h1ǏաA|<NkPĭ7zs$z=fUϛRk*<qcPWVJ?r+sVp΄?rL-6PMScH\Ѷ=yR[S5GnD~pjߐ|v̂aߒN3Ja⵹u0 \c}$-7"w_#-/En|1"\xG*G[N__6rb+޿-bF/4 eSX �kM jx`|UyU\j<ٙ [ð#' ϯ _)ŵH"4[r1LA^AѪ"tqH+ `FX;@}\=/l vgmw\|U]+W(ɹyQLP f(/(x6I\%Za>oi}t1^//j$6 BZAێ'9&%ͱl;H˖5[cdE>qkZ68&Z- \,h8e0ra}5梭5QCOr/k.2rYd.^6b`ܠ yζv[ VU pҪ+y[r3W- ^|q{=Xԭ'rom ),IpͱGX6nE|7Ks~w$G:f )]7m`8"dyIhѿ; ԍr{cEOls0sV9YoִyE@ j?dK MhX:~:O Z]i9>+2:<*Lׄ8ǾV\?ib | %7)y!^&">ZX"D;ic~7%euPY6kASziW֭n>1I],-ޖCce|C_O=#d<m|I.&1@eR!ldv1vN-Ӹ,v(Q:7ʵO;RJMF3\Th慩)J-\σӑu6SXRZLn�3{ p; ]Ɛ )YգLEܸٗn2 ԈP;hvV21ɡjM {G]lPxs1N!*z6/8\DG1{s9ZYfBoКzM_{Gpj`# IEdlS E5BD0%U>f>ME|qZF^x S߯E bZt6u@2k.(+`eW +- G��_v8^S8(~'V͡$)!x1}f0(vsߢw*;(: (i4~:aءOcgHs3E02!~[PBHc]i'aW~,<rgxM`S Q_pcƱ %HL7%e2<S[lVhk03Lь/9&ʷ~vG9 NS('y5* @$^jܕFZ]I5H;˭^omXD VʐST~ξ'?T0*WTϣBxD'Jیq82`ˣ,ZVT9Fhuk'XqLBl sjMB'w5oX#|/Eie ] ,>dËpkbČib1!{s͔;VRvK-%'I$R:uIK՜Ϳ9AN,[š i(-baҗM<*vԴTkC-R 'M.8N| Ѣ`QJKk_LuN?ULuCSe[Hs{Evb̞q!49WK ;q8Gry[\1u=8={^w) 遮某:4y G [Īv:6Ҋ%B ueWh┸æ\z+孄0&&*ۛ@ @\ w 瓽B@Six|ᑼgx['j'%k3 1kg(wcbO[1ZO##3ܸ BMs.NZ øa0lj_("b_=14",GC+ntuJDʚ1ӫ�W&z-/pixmLđ  oÂ!m_#0@R]E,ѝ2u~ Β-ϔFf$GHn3inFG$ {Ejx/SZGH dE<ei8&#DPJRlK\4 DTB@Eczd/Uĩ+lǻG[pc\^̪4J8;7n^Ƙ5x ˕%0x=[/CBi飄Q 4s^MY+㓛CF{ ap=žN^*54ӜVKpZm XޭI7$PދǒL=,ODvM[W;&"ؠfO1mzcYp ʱ)S~ A$"ULrm-rڝ=s,j*>{)㊩=e?ǙZ 2\OW{:0^S3y&h戁RTb4兡זSܸ^q ,.iبп~2g*D7C ĴN4 iDAԩ2R y~zcQz׋b\Txy3awicϦhϛ?WJI.!*eH4_3'f}_<8EwRkq} }M 8< nA"NwgTPu6G!t2C;ޙDw7Z24D>0K3xA<^4jښ@#RXbЌL� hgnZs,Md"xHI\Ѡkzcp iF}a 3ܾnH,ex :jp=zt|G"ʥ~Q*6 ҩqcGP8c6w9( (3�.h ntsG ^iO%tA(~Q{<w~ڵύhQToquirvDSHC@HKy1iƀg?`ۿPUOq,JI/Rc L T0Y7IVubh%_ ‚JL>-͗A1#wF(EeQR<;nk̀},ŠlQ ܦD_Ɣ6y1\@toREvv5lZU ha.UW}\6Q NZ.[~Lgj$|)Tp--JOxgO>?W1f۶)MX=)$;bB ;;Q:d[z'mm 2zg_aP3gM`:I%1,Iѳ£QEsjb4�3 Iӣd4)?ן&[�lP/iͥ^ۙK8(p#ByQ<M {cFgSkWa ."1H6$$z+v*:' |hj�YCo@?tX.R' $�TLBq9Spkv3Yƅx/U #ۦN&̭�aʗ!:9I U^Eݬ]y2s?7C7ʫDc!OL9H.洺T�0A<Z`|=#,AoSlʬh5C96CPb-D1^iq<PD{lŝ^ #;7y’ ?pR%]CUc-ZvDML"I#nK޼xVX % )g F�M7TeB`R9u=Ĕ [Б`g.<%Ӝb#&>syv M<d$Uqr&4ؕR]Ùb 0w[k{O}b+W6(3.GK}FkNE* h;8, 7-u $|}]vZǭ%?Gfv;4D(/4jZK@3o G~.Zd9^u?83'&g�v8" y@%"[@kS-|Ym;D\}E蝀M:`դ79h*a4\Ob7mD da 5,sFalE:gWvI=vDSC.e0sD>#~t4#ݺCSV,m-<>_'kszZ؜\jKfs*_G&FhR 31Nyjh 6$g[H Ѩ%3{3�9Q MD(�Sl�C-d+KjvF!W.-LU%: <q(Emgj'#;a9uD50@,$&@]C ~wQpRclˏplmgUi<l%UwC*)gUHSg~ČbhD4To5P">ο MW|?�s):*UWԀ\]*VY 7�5JY#p>]nw}$0NB|O@z|wޭ`M' 9ž\"s _/oix80\r;t/6{%e+t~@Nj>zj2s4XxUJj:3 v0z8u$HgjuWp}~lBɏBBmw /_jSЫkYy냔gv؆MgM x3i5[6)_ Lf^Gbޗ@Х2Kz D2u k`Q 079n.cv0-zǀDssm'G@!JYbɊD, އĨ*ݠ̔/sX4v�LQG ilX&'%ƞS}{,\U[{1=mv}YYr5^i%oa)#'¸J&-{ Z{ZNΈM]mgA/;2fjq>/K8Ҁ49$n5C5W"jW�]ƓJ^^Z %HR~-{ z,L�Rrw\N۹6K$ z}WlI;`n 'l9<#@. Gyokf 2'*Bye~E#Zƒ"�2XVXG77sJ즁xm,~n!P$ 4n")fs& lz__`2נ%_m93O JטX.۶=#K[XUSbX8УNzDF�8 )]^̻8YL 18ͤ 7>k? "L 2Χfx7 2 θ HduCk&uoDdFW qg/_邈"UMתLD| YBԭR5x; '_ɵA3VۗɌ<,Vg\bH|Jo5Dv__P׹^C={iy)+7H+)AwLF*+<Vz:|@ՄJԃp񒴫\p}5‚N+=k fq&lbjy> =x >�ljS0\PGp+QJVN6D69"HtpP>}JL֯V.mUa8Xn>\C;Isw!wCc)ElgٔU3;LB d0>+qi LVdT1gռL$TYQ+p yDFG4Jox@F8V guGg?FjQ<ƒTC"7;q]e|2O*l95{VԛpfmX':'�EjP. Rx%bh3Լ:vݘu v]GQR7j+\rkS&wݭ$W\/K${zmVkܷ(;KsGMwul .2&+:^r+@3SMJw۟eu""Pù0n%B pvk*={ֳa6a; Lg/fX & jTE`mBT1!%Fog9N)[%k& ]j ʬ3'ج.%ƻa+Kw,i龜P�yFRŒ2r%F_֭TOl =\?..6yO 2S'Wt() 9~yjD=:k�.,1f\,qN"=0gLxm6a}F+f)bO(LBT}E|2HQGٗOkk!F(ӶC}mI]/Vt-}Tn{Pa͚`9yiUݸ[/!JCXM˰jޭmTFXFB#ώ oSUc"K/_b2d%#Ѕ&-֪W~+EBdp–ȴ+P) 1Dxtdi G�Cc*4 68`DτB.r])WN,(R)z{?=pn9w8/ B wqnA>kE!EO> r:]I<RX:R8)X*Ny!سw8:A w4i0_#'w2oLTb^!iM*{}B8#ii4&ې$ʌ\f o 7_S)7; +ѸvHJ݈!@v0g<䑭|;Qȁ2'{tC ^H�M6{ ;ǩj-S^m0B�73ft"G,f~rHu(j/z OMi&"K ׻X;u ,~E [n2*\}:}nְt%-~g/԰b$,5f+N/4k|Bf+]ѡԡlXr)x #nwQ0Cx뉡wO* pCOFRg޻pnYj@� *wN‹85ç nH)bKJNuc5>wF}k–B8|G$*XiB]AHsv gf:s;Ry1>8wt$ѐNL;[wDq RaHa5[/ xlK!TgDW\%U^Tx@R%Q;]kAy`S %;$Ϊ:tf;ԞcIbIjxqo?/3H|)Bb^!s]}dl!U_YP:0q\Zu^,ekLVI'w3J"h/_ݗ1M.RUx|VD,T?_:C9&2M dx//9!<7IЯװҪ&߬a5"Y0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark endstream endobj 648 0 obj 11402 endobj 649 0 obj 1363 endobj 650 0 obj 9507 endobj 651 0 obj 532 endobj 652 0 obj /QIBDBL+CMMI8 endobj 653 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName 652 0 R /ItalicAngle -14 /StemV 78 /XHeight 431 /FontBBox [ -24 -250 1110 750 ] /Flags 4 /CharSet (/alpha/beta/mu/nu/pi/period/comma/slash/partialdiff/A/B/C/F/K/N/R/S/T/X/Y/a/b/c/d/e/f/h/i/j/k/m/n/p/q/r/s/t/u/x/y) /FontFile 647 0 R >> endobj 77 0 obj << /Type /Font /Subtype /Type1 /FirstChar 0 /LastChar 127 /Widths 654 0 R /BaseFont 660 0 R /FontDescriptor 661 0 R >> endobj 654 0 obj [ 607 816 748 680 729 811 766 571 653 598 758 623 553 508 434 395 428 483 456 346 564 571 589 484 428 555 505 557 425 528 580 613 637 610 458 577 809 505 354 641 979 979 979 979 272 272 490 490 490 490 490 490 490 490 490 490 490 490 272 272 762 490 762 490 517 734 744 701 813 725 634 772 811 432 541 833 666 947 784 748 631 776 745 602 574 665 571 924 813 568 670 381 381 381 979 979 411 514 416 421 509 454 483 469 564 334 405 509 292 856 584 471 491 434 441 461 354 557 473 700 556 477 455 312 378 623 490 272 ] endobj 655 0 obj << /Length 656 0 R /Length1 657 0 R /Length2 658 0 R /Length3 659 0 R >> stream %!PS-AdobeFont-1.1: CMMI12 1.100 %%CreationDate: 1996 Jul 27 08:57:55 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.100) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMMI12) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.04 def /isFixedPitch false def end readonly def /FontName /COXKPU+CMMI12 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 11 /alpha put dup 12 /beta put dup 13 /gamma put dup 14 /delta put dup 15 /epsilon1 put dup 17 /eta put dup 21 /lambda put dup 22 /mu put dup 23 /nu put dup 25 /pi put dup 27 /sigma put dup 30 /phi put dup 31 /chi put dup 32 /psi put dup 58 /period put dup 59 /comma put dup 60 /less put dup 61 /slash put dup 62 /greater put dup 63 /star put dup 64 /partialdiff put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 70 /F put dup 71 /G put dup 72 /H put dup 73 /I put dup 75 /K put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 81 /Q put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 86 /V put dup 87 /W put dup 88 /X put dup 89 /Y put dup 90 /Z put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 122 /z put readonly def /FontBBox{-30 -250 1026 750}readonly def /UniqueID 5087386 def currentdict end currentfile eexec oc;j~EЪ)s̾;.;rTejiK/df5A|{S/ )Sc\^ȟmp+#vL17~k d# ]LeVߐGoo٥\k 9M֨[G(aܘ|RP6n=: b9s2m4{~CD%xyDOg<<Alw| Uv̬i@o *|'</BoA/Nhc\ۃW7VqPx%F4Y*5V7t~M𨙴C:2:t4p\ dz:2 gSc/yc{ 9>iSq?s"{}3w*`,\Ź g=X|Y20V O T{̀]mDU:Ms/V-|UҔ4Beg}%1%V7E]|o?41 ZYmm  w* IGK2Yd0=bsS;e`�hz9h˴ %^{x 'i{]& 9c< U6cޏ(>O1sb>HAҞ#A͇i;yZYIG 2og#!\SR8?STGA' ;%a %98ٮ( 5E= W"2b'+}»*?)bUE5Jh E.ͥq XZUgT^.и`}o>,e,yh[g 2Zzn�[or<iDVv*6_.*͖ʓ�K) v+6lFkO"#Iji a¨]BB}xlsK,C"rFJfp'dھ?(P28~hE�FTocsv}YsUCEj/�{љ!vd'N7Uǃ\秤<6 >_!](l︟ŭ=}:8@|\mlʛo<ϒM f�Y�~CN� YZtH<eEػۖ<!׆<o5'ҭd` Cdvޚq{h}8Fp6^ mƐs#VOylBʚ#3nYeFb|)uϓg|cGAeJߕS}8pγj9;?-Q YӨ=6ֺ}%Q^tT=&-7Tj1uA_՝ Ƶvq&du3xi[Z퓷CBDjR`+yOC;?Od+D=fyZ]%` n$̯2yaDp r^*mPj09XQR �!|7<IT[LR)Q⦰MHA(${~rDp)ؓ>vMLi,9!<Ȋ. :PaUHQ*xa@=Qwh\}\^ nϛ$Eij\i4 #UdupdqoTi而Mne2.^P-Vv�I¬h)&܀X-OiUpm&cBK?BmCW'N̪ (?eL~֔+ahcQzUo^ V+�1/tcp�y+o}Y#oS`g=+jK%wOjU9]Di7&a4J :hq`8J�] ;4k*zOqӲ) ϤfæmP.·�]5OQKb¯ˉMBo.+`kAoypTtrl{DxK P𛮄5J+͵-/4"+{ߍ4s)[Y48^av$OYUᖐ˒(A;& ׁYU�S!H^-/V^:aU--:uH@672W$Pv<Co]7ue<f$"0_p`4gNC mXaR?cl aXCjsmQK(c4h*)f"Ip3="CI3wkӔz/G4b.Hv3x0u6=e`| ᯘyzB) IXy~pn`}I$=Ǐ`O'[-XSV-.*=.Wsf+B4>t[{� qg[O ^Ndꏟn=; \eܡ^D[WQ�AQPLKZ溴g("+iI'sZ@X_c:V7m@F!NXó;OuH�`>M B 5\k1�(S%a ˞}\Z,5 P5�'t8tQDt*_<X{5{~)E_ߒDOy˜}b}70*|<(ի'1 \u7uC׀6Ш66J܉O@IlA̡"ӟ`ړ55G&x˞"ʰ~`# !@F  7_~%dbR~|zv+ih PcCy"?|Fu D'l9p?3^HUՃjH0B3zB0-H;e]殑џ3.B鏊9XVeBåI +?E9^~ fri x 7ADMr=`ٴk. <`Q)F<!"az- D%X1Pަ`�Ϻ~|kgԘl brVII*TI^#9CD�+4vT�@h#0s|nIڵ#:4C7YX ]j$Tazڞd[[EY`<!;I3)/r7Qr lޭo˹zYd9¸6(jn#~Vx+onр@OM_;pmCBI4(!( qe*gxՖQe(:>p_KBtޘ岛 Zy. U fX1[s1MkdžqQ^wmZQ@荎T)DpU٘E]ŐMOaqM٦ƼQ(?i/[eyF:[aLޡCp ;$S:** 4U嬟( RH2qR%%)4#=amz<46Ƥ*dѶIj^odi?~̷ 4UU1*[E VD-]p_P:+| ǩ t4"VwO2 R+zi!Zh}]eNʚ|ayH&os?cd3:[�9Q`Y _(Uՠf%ƩNC!f:ەw8V(i (D^HxE(^+\;e!>k(A B ;X3&J4gu<XلBXYrщJIk1k~0;K;d-cJ?p~]Ѫwys+ʨ̒Zi!^)ݔzAU Lkc͵mT[d?8#ӕ5E ;м!ϢVV }qylk/8!~ "\]FZ*ɕ ^@"I)o\kZޝTs9ImӒg=]8(Nw@f-+hyEϴ8 d OìȁIb�:-/]'&vp6V74Z?j0ۧ>Ub;0EɡY` Ӑ;H%nC/Q #3;y,FHK+wFp̔MP͍$],R[&]~iѯʱ:f_w <ˁA~-팺 Oa2YsCaư}}8s22TH"r=g{q> y܀'"PJ�$Xd[ܦH5Cpof3ij`wpOi!c>7jxY σYgעD*>*{Q.՝fj6H)![G>dHΗ¨R+imB;yc@6Ş᥺| B,L ߋT؆}iJ,a ޜ'uTٯk AFnOFca5[(@i4lo`Niںl7>48bIU\׷tu5SίxCW�CcO$HfFT�FΟ" g ь8,ki QU)N>u; .,ؙyqP7}t2"hO0|(H6}S#$҄,$.uGG is7J|2 al~5֚9miuSϨdM,0KXHf蕢hsF%κ:.QH)ݽcXþhT}pp̓M@B&XJ;3qw*OKUP D%?T[eXnYAk<m":FXtiBc> FCQNğw~okU}-=rG)tbIe3$Gunץ "^oKĥ32 A I 3T<n?T.gd. :\aSN]xuB#qx:b0 }N64=b7*J1rU3-jI4.n�^h693zr5e&<X!\F9;2=, wt+Qؖ�#}V| )@{zЅ,u<z W@2C^I°,x*5C\}܂u;}ҽГFn Rr5q'O`�GLIu2٬ E$R6ēh=pWnyՍ#d Ǜ )`Ӽ >ñ7=hjB'꿣VK(?.a6[w]A2q)9J3f,$t o˧UKotHs[n(c~P0򋈪q;/З5q@MɆ'B׺;jgy=K.%=*&RuХ.8/̞PAf5,nt@vMV5S6=fh ӊZ>Aϝ|:wg_ODo/N *%M@qU\ Y)}рƜ ď |� #�#/jQ}N%>LHE޴Ho' 1I00ѭ$iX lw;d*E04xMݾɂTY],�6PB&?U աuR g6hN4Z mx= ET:8͠ߗTn|J"| )q]UrLq[TeӋ-a!I; s(0~譶dنE\}Xr/ )h8Afj?vN &V{-.[\/e�Y;ouNٯ П{,Sa{W+*VEp-Ud<(B.ll#Q R?N+<<yCQ'.tۏՐ gIcҒޗ3٧ `_)>gۈ5%3[74. u:=aO@|-^tR#lGPi;}F܁4WbEẫ5 tmzes=[C T;+�&nr.*J͉rYS&rM+6"yXTc_D5Ua富 䣡<:Dh} YtN3T~8j!"*讚f>Eԓ^ϐ]>t]7%>Q堦,r:S$3t&ƴl Qlsm&!;E+v rOh%Dq%n:1"7>2*43& 2TԀ.‚bO,wtG){ 5ͮQIFTpYB`4C܂[<M8 AUw{0F �")FBtBg 4<-bT8#?o~;\ZOPY+2]ReѢG/x 3߱pk=UGmЊa;4�j3S6|4O ג閎!03#Ȇ>S ~-g=Zc]`] hҹ&".ynQ WiuI#饾X�!CWbf{.TђMv_*ceT'"Ɖe"R@BIou?Ozؘk/H2~eUiw<f)Ò7L?ɭJ@;q´26!=K E+{Iz *ϔ!fX~iǚ }e4_]K 8_9NRRjv"}8)KSUd@3Im!_9]T) bY!߻[亐 ,}eGW@y �)-/IFpv>%p8vҿQgM}<…ATE `fbe6 L=O�EcGEK~0|:u&) 5�yg9pR8h\/CLa;ӊBeSF#7ee9'dOJBz?oNTZ%'f4}J_]*xZQ?Xot6eOEf~'&d ^ZLH%_A1"KfJܢÙ)<#:1KOV� mieR?C"Y~�U~y4q]4(rTY"p:&}1 o ;-}c \0ڹ-Uh~Z-pppDŽ\S 2X9y&مy;6P܄~.Ҭ5Z;kC Obj^򱲌o9tFV<L?Rt}1 .sHue}6/\<c?1�rzmj듖-@`yLPw\yeطN*2Sn|k].eg1N_P]LǬ_j#`K:S^)W(tBRtf*&nkaV,~ld su 2>gK5?p:|Սb^ /6mޕ?yė; (n\u#k/R$Q:ԂG^ y(%g+@&:8:K|@I +Gl,QDW`#)@S?* ci�2Mę^55 Usy#Rqw2ohL!  CPgxp[kRAe)$=YO�nCP[ ZAt}hصj<Y"D[ 7έ^{mp1d: <Fn@O4آ# ByEdZ;׸jP>kC( NY1nQB4@[uì({MکMD-vT.B*FF~ 9jquWϝlLVR9$L><Eo**HtKGZ,e&rg3jzPJag{8~RMNf1/^F?x^vKiR;dS<Ĩǔ݈ŚYZus87 hv,JN_x FMhy^cϒDHv~Ĺ 8了 ITr[n]5}}nxj&DAl`߂0q@�J YuM' ?z(uȊ#I\Z n֤KPvu_⸐FEutIXԕH➏(*#NQ18VIg,Npk}mпj�Hջ]Hqsalg.P"F;0%&AggW3i y8ו�e=Y 5b֐NjyE8W<M԰q)ţQYqf,Fq<a9A%!I|f :Y @!~i1;:4ΠI|#`] A4侹WbP};,,@v W Am-JKt.6nj[1ejA:QZVeE,s~tAb=TFrJHC_\<iM i&>O<_#PK= !kt8Z?O}6#:$z ~ ɂ[F`knFO/.9$g(u0:+R?қ>8eJr@&,׾nUbɸ>o0{jQ ?בNUZm­{+\5>nCե$EbУEC-eʎm<нA`5U 6%W0ﰣ:£V•ۦRzyЌ۴ob< iF:2"%X='崥,<! *ECUc`MWM~]ݐϥq"k ' dfoa6|O C؇;-%~Ɓtc (r%J ~fԁd#οd� ~rO NﱬH`ACգiu,%p>)6^7ϙc%h%HT@lE~ ;R" Q.4\s@U.sK Њ>&:tL9p9~$ Co#A0~%w<kcZIfsCB봭_!-1=Q٣[R5!V.To;q'A'{+]x,&# EO8`I|r經*#_3 L75#1{!*qps_tJ&|4q]:@& OhC[56}�484<,"I 8)'*֫C[Gm`@bxSh<[~^un }lI:t)|k39҃w\;-i2v?n:b]]*'p0BQP'00ry7o{{a?$9⩭تmQ< ؂{UԖq %RE-B0)܃[`klCya)1h!,n,nid&ANh~U/֕rK<z6Tт0E{oQ#̴9سprk1 ղ*71|-ot~8Yeۖd Jd׆f̃bw;kƿW,rs@* i4DO:TO [:e(  @}K _q FPM򢍂%ejyc K~]{Hĥؿ9Za8n~Db# z[\UC4|Vޝx ݩ:o]t!sxUEǚM UYf /vRT} (ElsZ?Bcƣ9.31(hdk[ϖ68M " pE S`ȡeF{'}/;vMVUc]cq°| ~B/]$z5Vz߱S< }.4,NIЖp?DQuozd!ɼEHyLS ӈR4Op7OpVf8id .[8e{PI<Mo$y,K\Ծ5x߈vOB>*!6T?Bqyע}| ˠzM5 1i.+ru~Ydbh쐚-ҕІaȥ!ĉyUJ=|7q*5 gݕhǬ9kgx-.ɋ$˥x ն! 2XyM9hUS"HHfC.K;[1X%ѱ"}\`*ЙXTRT>KaVPb7‹BkTjn r/?gɵ0,*mSZYxO\;dL~:>TgZZ�$xUTR/*{f+[AV>ٍxMc0 @U#L: {ov̰"<ib d!wbvbZ^mfgXPE1Pq(߉m˓@_"׬jMHC]W<f՞:g?f` !}o9Fa=&/Dġj&dC|Kf:tb tW͓o rպ+ }!۫oMQ-LKC~{#ϐg4 'wj.}3U3KiOߛ Wtum3M_P;4ߴK-ry! ÇY6}d�bP:54^1b}E?SeA#Ƞ^డX"GP]$"4>&kOuE#ZzHq5"N;]5 O}<C(*mO2YKpՄ q&ۓ܂\mp@zVM(=!Y]e-slNͦyӚ]n"y.' LVTIЁmZqC~b; t)ަ˿ɱC\u; aMK8_ 0(C4u m|[@x5N2A冑odk1U ֳj7:m9 &hܾ9AZ Pc=u8s,>cP6ᖼl|C{mu c,:i&h1-<V+mlcRgBو$NL?B{yϭW1x,2jk90!n!5'f>pɜk-ų#CQ &9pc|^o9]g-V J&aOO2==KJ9ojNᚏS^8m v=n.'}z|^¨C,‘W8ⓒ.Kaud3 ! Jio|[c-ۤs-GۥSL_oTT�$2X10mmPv:4-vTit y @iTni{[LRwC|L|OjWQiw<uoQ)Х*/yl|hR*%26,|xԅs8<ƴiebo^˵_^^s_ͪPmY;Nb$MY]4/4&ϱX|: *n~o2z+9^54+p/Zpuf] .΄ osutHN0xC={~UքID]9mw rs'ˁv&.c6I%9fmNn`뺡('7S={~f5^f0ntc_OO%?hQͳ|=H0Hl�*_<A / �z " شh~sXsZ6a}յߴ\;J>PjȀF�V}P¼&g~9ߨ5;Ƣ`P&$OD.dcUURHTnKD2t Or"3mmGT EMxW3V[?*BF,]reDr,�jFG9yĄAN?hruU"po,ec^*rM[X? %:ӹ.1˅ gwzpZW;Z1D7N[&* qڟPk 9?Zc8sC%Qq5WT/stV5w9959tSu^%76F^l/r yg:JL={.EBwB[0o]/]Dv0 fj ;mCEj"`LT]FzCF7aH[(h ( FO7My }թ9po<oj4D/\K6eWMק+KJ6P֦'>o2'YT&*~EFTab!,%[UtnQ~WR#kƔ̯&66ub[Z0;+'6)H۩[ݭA.�ĵ_Ӹ{5<0]$$>k'n!e `- 8S2D!!ιf  Ɍ64+ dӯ۪.uv'4g[6*`3]Tl aKVjSg';؀t'W"Q<"l3'i7Me2}AԶI46|_IEOPVG%=8d@ʘr #eIzRU8X"4ތ2& GcwhPV2(c;p)+l $pGK*;n}/*l>,]mG|@vc)^c6HCLca!%%R$QClԱYۜ G5POmR3ju:SQ]H͓iIĂVr}B "JT{65GO +%M%6-<o2ȿdJ6'6dGE4<ID 8~ |fU -ɵAMo Z@`9Ĩ`j`_ZV0S.svř`ʕ%J#ff!3ENm(RtPwU+%=,h%A[i z�P,r슪}XR&E躗.}͈ sl(ʀ!%-=`OX.So3x|xFMoae-xj+>%#D>d*aR@m@�tċr?W 0dUj|9oQIҺA*EjC|X5 IĹ*1WxT b!Bj$Pu LJ9kaɻ*W}uPx~p#CnpBe>Or퀨TGラC}&uPQ p8r Z>\9 }MELwvtzbD# -hu̞ gU1*OtE^Ebg,%FZ%d8)UJe/�ԿmEC#aʼ#܂.6XsȌ6 ;hj-$c R9=+b$w4;W=lhe_i{L0מ==>X|?he⡿TԄ4tcI S3I/cи(>RA׵U)fkFFh*0PǏ6SiOVWXtUwy坈e2xo@*!V>5_⫋fnmΛL )G'wYna>Ͱ.EO$Z߲4HG ִymCKft#+IF}O_[([ʝ2ޮC?`6\p7tIe/ t6IykbS 68mhnohZcR[4&@cRj ,@? 0< !GOE`wGuj4ή1|n8dթui.ג]?Ɗ5`LBb:f\h Ot}[,*&{+ n^:}uM�#$+kwI:Z~ku Iǧd? y nS[y!R[ �J0O#!Abҏ뱕^Y;tiy9HF#L[xoE N@6rn@:j»vE**>u{i\4Sgs Yg1UJƼfDp08S UZ1T㡖1dؒX(0FdfJ7?Љ*m3tEL>2g8%of lĴSl( 9 ~P@.zEV 5cG:!5)af0Z! @x"ȣ\J%6w+> +y_`iYVevp}җ_ (ZSހpQ}n0)<Hn'#X"| @VD[71 diu|s( Y%쁬T+]gԛc^ճXJP4pHn -Sf>菍"HqQߘaW,S˫Ր~BI~KҜKXTQKG=ĭa<UF7_I|I_Pz#2[o6z>C 5t0y"V[8-? !8{O*@r^OO׉^ ;a/"⣡Yл[9c8v!N4z@ X#�$(`kD>! 8YٝèE<Ƅ]UgaWp :<vܙS^s_vqdjcCeg X~[ƍ\;Qx8Zo@pN_�uiQeJ[|??r]r].vG'!2QHGЛ^^jRֶ|ou)|tF~%ElCgUBg>ëDNTz4QN\1N/y|$sXB@Nt=۪n[a+(\~T&0Iqc&w�o@6B lEi)+[r[gz6dytOGR5!62;á 'kSSQԴ{1T肵Z\m@vbrYWaj]NgO] df Q3MXV ҿwŠ/kqj<uP.ut[N}[klAr-B276 S6S jrl? Nj/9K1Z_[ܽ@S9�cE&bp/삅"xU^I8T\fNSIvez2Z%(�`=29=/($@WApCRui~2o0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark endstream endobj 656 0 obj 18759 endobj 657 0 obj 1835 endobj 658 0 obj 16392 endobj 659 0 obj 532 endobj 660 0 obj /COXKPU+CMMI12 endobj 661 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName 660 0 R /ItalicAngle -14 /StemV 65 /XHeight 431 /FontBBox [ -30 -250 1026 750 ] /Flags 4 /CharSet (/alpha/beta/gamma/delta/epsilon1/eta/lambda/mu/nu/pi/sigma/phi/chi/psi/period/comma/less/slash/greater/star/partialdiff/A/B/C/D/F/G/H/I/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/a/b/c/d/e/f/g/h/i/j/k/m/n/o/p/q/r/s/t/u/v/w/x/y/z) /FontFile 655 0 R >> endobj 43 0 obj << /Type /Font /Subtype /Type1 /FirstChar 0 /LastChar 127 /Widths 662 0 R /BaseFont 668 0 R /FontDescriptor 669 0 R >> endobj 662 0 obj [ 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 515 ] endobj 663 0 obj << /Length 664 0 R /Length1 665 0 R /Length2 666 0 R /Length3 667 0 R >> stream %!PS-AdobeFont-1.1: CMTT12 1.0 %%CreationDate: 1991 Aug 20 16:45:46 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMTT12) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch true def end readonly def /FontName /NGSJYE+CMTT12 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 33 /exclam put dup 36 /dollar put dup 39 /quoteright put dup 40 /parenleft put dup 41 /parenright put dup 42 /asterisk put dup 43 /plus put dup 44 /comma put dup 45 /hyphen put dup 46 /period put dup 47 /slash put dup 48 /zero put dup 49 /one put dup 50 /two put dup 51 /three put dup 52 /four put dup 53 /five put dup 54 /six put dup 55 /seven put dup 56 /eight put dup 57 /nine put dup 58 /colon put dup 59 /semicolon put dup 60 /less put dup 61 /equal put dup 62 /greater put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 70 /F put dup 71 /G put dup 72 /H put dup 73 /I put dup 74 /J put dup 75 /K put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 81 /Q put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 86 /V put dup 87 /W put dup 88 /X put dup 89 /Y put dup 90 /Z put dup 91 /bracketleft put dup 92 /backslash put dup 93 /bracketright put dup 94 /asciicircum put dup 95 /underscore put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 122 /z put dup 123 /braceleft put dup 125 /braceright put dup 126 /asciitilde put readonly def /FontBBox{-1 -234 524 695}readonly def /UniqueID 5000833 def currentdict end currentfile eexec oc;j~EЪ*BgNӽ ؑlKq*޲Xws|QFqv`zXMyp"5O˩YŝP(DT!�[v67XFlU&3!Rq4wσ~j+ou_dV` H [fIs ?Sy_aOg+k%;Y`AXGSp֓Y%&n@C[KBcCE(7@$2`5ձSX/ z)ύ թFrsWa-3"ay}]*z]¶2k,2ƲXg׳�1V71y \š)~V+h7|v1j>3~ /%'5 {kz M˿G%+g@|x̅/ER~AX^o*ӳF7/q \X<~Zֿ]ŋ *8)E_oG aUXGv:.~2ڜlT3eU&:0V{]GhsH޹o?SV=9͒SaM8 pHs,omΠK>CРk%th1eh@D/!0eΨ4t`] P(hk4>r\>+rY]Q:N"F5HFx&پub9Tc_RHb Rˬ z4&)oHf ]CcuF,P=p9Qgt }$$D0C̕>mm g՝ )Y:b,<o7] GΉC�\a([vGpM8;Gƺ] C?ǑWGtYV9g\(Ւ.dvH-̀B!,_IO)9_6upTi.ɕZDIJ 7|Xk/K+3os[$IÍPoUjTe+v_$vL(R,Ўd43J$ We(1' 42kU(;: iĂ9;cDL!j+�̏_86& >wJ1֖6@F $5Z.Ts�E>@$$g*hQyx86oW;PkqBHu>=٠Yu˵uI7Fۭ6~O1N%C!9r3Ik)ĨeB AW.([b+~a<A 5%VgˣU4K!ʠ]R$\,9r\=`ZcAo`bi2s6XSfDu}`D-~՛چ"֘׮){`XM X/5{Wj[l0l[o~]E3UȲ_~59\hs,,Ύ7kZڏ< 7hrjalo5MCkA%|rxp1).`a-ǽ:{4W '<d~͋saj;?ʇ_<Lqϯ|=|֪\xI&޾\IfB[i�BeRlbS+iжY~ޅ/2gPΌCK$15?P)Ry,AWKnfuVy"5w|);ZH~) {:WIp|tFבeV;ÛjCE(b!:Wm59,遒QxR0m/&mjvtoDq߾}˨]c6WxS0sb  {CfF8޴jm,a?92<di痴,v@UөK.*Ύ4{l iad'A ψA?Bo>\ۚ%2cNktg1[T6+{(/ ks\CJטрegf%R;6΄v6bqs Se%Rめ%i9Hj(t8/D@2GY <"R۵ ,<ȖͽIa7)`�.yl!BoA @.<Bׇ4U H^!M" -K|(o"݀_(848X% I'F @]A5B�x6GcTsZ2GMek[Q ,Pcވ4CD3j ȣc5(.S\$OEq)`S$!yh|L taZP,t.6hg/:Ŋcofl;Tِ/}$ԗsf_7@rOcM.Р< ;mB~>2T R'r,2�'y%8!PƹCt&lfS{š'<lu J"7h{.=o@&">@K.䨕bHԫ+|ϼI[ Л(H)n/lZ^Ȓ@A磽&\ǸNf1hl@{fAIX8x pGt 0V{QRⓘxw}nBhEց9lrҸKK64@.8a\ѻpPeQW%oCRX~}a{WKӞ BfG lÙlW| ë*R,7{cZÑ,G~ HC~{08SpS%5nUhڪפ`qkXkK03B1-DTMtT ‚ez]kӫ|_%٧^-`8"[:1ihF MJ|KjH9M m8-W,dH 0雼'@c>J|C"o]F&S2|QVaJvUi}CXWو9ۦsN_F}?5+.:l㥜1nڅԋ59˅�s D  ~VZUΈ[Qb<]|K dN77:s fI $q gx-DnakKnKAu&Kۻ!62J(pj$a9'M$0c:t#ʒ8Lݷ (5 DschBaRq4R)7 h q K䵟H͇fʥ_O.YOC;3rS\z4 VhL4 6ב+S{$uOu^vً7{یF@dч-I^UHZ)t(M7 G3yR4nZNq|P0fvcKGqoU 17*+ֹuo>ˤY A=-YUSX#q&Q;=&uɱD5:L/@e1^9QЈoPf9?t͸i+=.% ޤrxv!i"�ljFZ]׼QyhMp%;f1'3#|9= �{MSIHx{ npK"Az+ s^.&ƕyh^Kiل*(8yӉMeT;-ƪ`0NU!Vvg0xǂ$$ _,AuԌ$ Vg!ej'l6ۦ (3Ąͨ6^ꯜDa|H6e6ƗYQ@\{AtI(8X@F}wu NŘڦCE_8 hEXW'N0MyisQ-2jμuȈ:eͿ*h 'ԠL}n!zzH L :/,aTIɣD`- F|K!ifv6J_WL{gzk5Ϝ!'AERlNVa 6xunʦR~>Ê7{F.>ى/::Oot HxHrRbdw�T\#vI$ՐkjLMaj]Ez~uto+_3SBmIѣmD\ 8G<#ӎ1䵪x{ +fcN7+ L09͗Uإ@F�{I 10dbJg(pLVEӳsXYs#�#:VW(Jq};['qp= Aahb55[^U.֥r٢m75:$˛յJb |"_q=tDxRA;o7 >BʳMf`ZS2HJ^0a~Uզ V^at} 8H#޸x:*o2+{Q2;l VPa4?R%&7sҶEiHAkL'/j@Qsv³fDvcH>#$R�f?i܏O0f 9*dzYxrmDƧAPxgG$.Mym:m"Ҵs8³;c1=u|?w-&6p%DC-jP2Zt# w`W3Z; !Cg&6+/6U{Q63n[d Hͦ/LKAkU5ܗ׿1O4yOp�JQ! K�NU+)#a Qg:@ V2>b_&k ߡ4@5 '@=9 #2uR*2?kxqr\L4n"'ݳ@^R;IgDi:m̹Un /d)2'+U/}Vڡm"q@^ n}84vĬɇ }pY34=IvE9η wԓh3pJk of,2A9Ewpfvb_@06L]|()[`GN-鈴`)ׁ¯ (CSXzou%V4Ɓ&*5zZRbkűSn{xKt--5ъҘC<r\Ab߯p㱢6 3yWVJfEwC*64 9!~; _~m/uTE5$}1wiQu+Wiۣd]n)͇!GN'ZGשė>nyTlM@ Xz?)8Q|KD%ufqוj.5(G ٵ)suwUR)u:.|Цs%0'w<#Ҹ7D'lP<ZRo z&^T::K{eS9UHI8b&h4?ePU;RMwćًu<!'#)) �$O*O{T-((C`Yb% dr"u~Ŏ銹.mf;4BU0 XLAiSʧμ:͘ c u+7^t|mUGIz i, s`ѐ3ALи47_+KZTÚ+CdAc羻-sm4iWx+Sy *Db' 4<vqDߡ~#oa;s=TRhHY DǓ A!d&h 8!ק1>w'i?ɒ%C[ p{ Z$(HJH^#;[p2ďψߙ[x贮aBEE@JPx'oaA&)7>3=&VNhGWJ[>zØ_߆ggޒ2N bMOcfj?,IZVh*"}$̳`|rV:Xnz�ܶybaE0)A3 ?'m}C3GXn~B2AĠvD,5~+:o)8;UGwfg;͌h=:l`4EaN-Um>JnΟYgCtja*iVޛdu֣M묂7"b߬>V^6 =_DĘY4SXfVw0ǒQߪ.vԈX|7�AweNzb6둼JVO%Q3*~%gĝs}\lȡ4FʊO~ߙhEړsz I Yh(bb�%(OFX&f*t0|7 b�V~t;qǓ¿@M(L^֣C2I(_.,jf!yͥGOs15H-J p&7½7wQ(4Sqa16ijwuh]mWӵ L/!c% IFuP8KHb]ѥz̿VK2xA.L585#sļr&ɝ=oYI =_7qݙىxAbXQRmuݱ 4 BK(XZy3F ?U z[N2 ;&6J[mn㒪Yʠ0ݡLF=Q_CsNVDV<tAX:j.A1u0b=-=Q{B XFn8)\8b @捙Ɩ]>G;눜T*O[8= 3]Q aɏbI)9lc^'.7lI Oݩ繯IJam<1I g2%OzZMHq֤/ <n`9-+9ˮ59S"Irf&Nd#e*i Aj]=^"q@bɎA=1KW^bU$9|a8<ݏaRυU`ܛ G_hU\Rؘmո^gWgV 4uY#SӮ(++=NwV 5z3|&>yw9\-Gbv<;A6,3B8 z~ZJi0 ySzxiWXB~yđ}p-bmN,É^.OGplF,Zj&BYkׇE4ݿ {w8Mpg-Qum EHݑ$GnJ ߱CyL5Kʿ|~ ubhlF{\'#;t`/uku3L o<J2hf&d~>R#(@H/<ޫtjmx>/-#XZBZ,ߗ?J۝<o!ٗwyͭ 'c&iz} S'ڙЧự sѣt[VH'_ ))Z kYɞ)WS%w RȰNަ:%#>#l|j_̦% ^s~$|x{ڧ]ǫF;ل(6dF#~q6.,ΛYs"1J?D?Zr&ǃLhLxC:Yn٥E4U޿\E2-[t ?Jkנ~:= ?sE7ޗDz *\[?g�wUZ@2;7 U7nT`[ZJ|.%5ub}.]L<tU']esNYDF{ݔ $67ی <B*Ә?[-JUղOk 6ko"TxkBy=ʫ"44z0C c͖~&,l~wzSQj 8{jW ˘1ic -lS?4$ :s Ƨ߼:>=9-8x�F]2A(.HsYTd[@X]=z,_P94ml=تGlAf(yn`IV!ko†1|rJk H(u]%*:ۘoKLDg0tw p)awl?kg3߬nfz-NC"Le1k}%o1D LQ~[IZ#0uW!hSWszMcr½e+ `HLP ܛ rΏTwfh"6LX_CsũCg ǹ˜kA\Y?1kdpɩpHG(XX#ɍmIjiƚI�EJ ֫!(2:Mf͓p�t/`|I]*z<Q C ǞN`ހ!Kk4hsײKǸGf`&6RZ9S2mMHeK{%w jwɇX%ox1E'Ε/W۝HY\dkY#`.M DuuIbcSz`F1 Ծ\(aSC<߶52 Wv4hDa6x w/fvUCYM]ťn{aep|M kܽ P٥f:w<̪{Pm qI2X?P-n8v {�G,CܿL5fAF�.o؍vhpt*` ҈@a /n#KnZS=;nDw|VTtDxJm.DZP�iP5}ULnc=QUDrdd_^҆f+>gO+% L:TË ? gx3Z>:¡u_e% BɜwFx崍fEbYd3 ϱh`uWkƟ*s5%-CĦ̈Y?cA՜c$U+O+d^ ZeʢO!Dځ˧z5�kSL~.1G! =3y  `? 䬂*}Oa#:@/=| F<s>+?Wܞk=G,@ӭ$I-k7�WpJG(Gp`#9_S! \lne?"S) [ѫ7:0uHac�Wvz&䜔dh}j0^דmN`QbCdӦY֚{u&lSfW=*7,K, Z'+;7* )'W=+Ѧ/%SA5҈_&?%*zP_ IFt? dCA:jF{hO Xd]ZkZ,Ӟtʫp/`R=%fq�}^`ͮSTmR)#Ru "skw FCF YGb ?k1'Ck'Ze8~VT(<`gz5c ‚?Cݜ3[E]4۝Ue:0OGVμ=?Fr; P68n씂YH; rq$& 㿝3HwBdƒ&] 6tTtŊw"STi|�<Qn; "4t4 5J6PrrN 9 7TX\ oP++Kz=ttb7ySKf:!.`\՞uZf䯂7cv' -djLyK&kg qBma^5L+QȂ098A~s_]k NSp7A>IdljLp'e|+2P$!XWL_cwwnT_6OQ:$4 (ݤe /els((~a0�TxVHEhG|@E:{y-)JshF9&̧lgW}@OiUfӠae"St~F7Q'բ0ON_iֱ`IG%alx/-YJp2PE6%g="SF ~(c b+N?Q =c"q57.v0cKIi>fRXpB bQ2T܇襞50#|їǫkgS<z Y-�UMn L9zwKޯ^d r O_}|_ly>x/}XV/ iB0LSrRԸ(G9 Cvz)( ]jǐM pƺk33mҖ)GZ來EJCӟ.HOEI4u*Wu"HhK[vV&IsoJKA6N4N8!nၪ fJ -x<=KEyZ"aŧyԱ_{%-YTp-]\<fR劂)@gQAU?t"Yӌet8f=\%)K}L}2ݽ'lwtM(mBS`1vf<�W6͊6ܼWrLGOSK* (M!#sqry.ah5"9do|Ȥ Zھ~?jsX5ǹqGmNo܎P(?i n&7땍} 3K6a &.2U#n+#GBOҎØxX]NXT;z@{#0Bj͈b_�YC Vw{#+ (CvH_EErw1jC[ ;4 >fʘ8\C^+g9u<ơݲ O?ƻnf2?$Fj@ԄwX<:KglQl}:n#1(ݺz~\8H.4ɨ}@3ft:F, Ic*tUrg뵎CṠ5X`"IWn~y0.=ocz"1>Z, ƙ8mE r@Dnu@=WL:CDGت~S5s|=_KGӐ^an]Yy^@"Tyc~\BUVpm|YS:0m FUO` rf} @[ak Gtl-QC[ o0 mG 0=xGCdBVnhs DҸuew*׌-Mt75]}E 18Z6mgfRƜUzH@_`PsM6{FmV\WFxQ]ʪXMrWLkz )<!(G{UM(A%iT} 0*p7_kV!BV&cLg3MHTsR(׽KC3H7HN4kAWN,)X!낏Ԣzr,-_,(_"8B5a6]nyZ2ynQۀB y=<}@UHۿDK~Lx6چ̟>%&%xIV8F^QFu>y)74+ ܏СܨַhL.hm^l"1f`spٵ,gQ팻vǏ6~V-1Dm\Zq _J ]r6gfDĔ�G{j\4d,]&%ZO_MޮO&|ov/;f_H1PfU^4o 8[bt{L7֜{K7pKuj+σm\^݉r\�`t. FSZw7?ɼ B,1&kA 8 @GN<)ی_I?usz5D<…y+dl}KǮ~m$IK(CŅ &1F}^dkbL5>&p4J{`mMrr|}$Fq"3D`1?$:�tWB- KHݰ#V:Nb޹i; 5;[wZhbY]jnXexRBXDCۈzرqca#.2O87rkOˀW|;͓@x-Ѷ:/b]9 / pp TzjIG\E]&vca gM~;Xne"$'Ϩ`jT#ƽghPg@Mn|:`d}beD_[ioyM<Dq֮)L슽}.0=J @_tKNwZ~:4H%B6:eScU!2OYlR6l4ud>m9�y[Jr p~T_Hy<)$W?ؗ"RY'~&=v& ΅Z:*o"Mݠi>OB'ooST~m6sErCBYrF-پ\HU[E j|Iwnp͛I(TʓS D酚bTǼ] vp8KR*_6eI(woWX &TY pVRu`ߑؙF\fv.\U\wV~:˄ՇK`�'DxQb]YǘEA+<(ÃjξX"R ncO$i0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark endstream endobj 664 0 obj 16142 endobj 665 0 obj 2167 endobj 666 0 obj 13443 endobj 667 0 obj 532 endobj 668 0 obj /NGSJYE+CMTT12 endobj 669 0 obj << /Ascent 611 /CapHeight 611 /Descent -222 /FontName 668 0 R /ItalicAngle 0 /StemV 65 /XHeight 431 /FontBBox [ -1 -234 524 695 ] /Flags 4 /CharSet (/exclam/dollar/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/asciicircum/underscore/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/braceright/asciitilde) /FontFile 663 0 R >> endobj 42 0 obj << /Type /Font /Subtype /Type1 /FirstChar 0 /LastChar 127 /Widths 670 0 R /BaseFont 676 0 R /FontDescriptor 677 0 R >> endobj 670 0 obj [ 778 278 778 500 778 500 778 778 778 778 778 778 778 1000 500 500 778 778 778 778 778 778 778 778 778 778 778 778 1000 1000 778 778 1000 1000 500 500 1000 1000 1000 778 1000 1000 611 611 1000 1000 1000 778 275 1000 667 667 889 889 0 0 556 556 667 500 722 722 778 778 611 798 657 527 771 528 719 595 845 545 678 762 690 1201 820 796 696 817 848 606 545 626 613 988 713 668 725 667 667 667 667 667 611 611 444 444 444 444 500 500 389 389 278 500 500 611 500 278 833 750 833 417 667 667 778 778 444 444 444 611 778 778 778 778 ] endobj 671 0 obj << /Length 672 0 R /Length1 673 0 R /Length2 674 0 R /Length3 675 0 R >> stream %!PS-AdobeFont-1.1: CMSY10 1.0 %%CreationDate: 1991 Aug 15 07:20:57 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMSY10) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.035 def /isFixedPitch false def end readonly def /FontName /PGATUH+CMSY10 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 0 /minus put dup 1 /periodcentered put dup 2 /multiply put dup 3 /asteriskmath put dup 5 /diamondmath put dup 6 /plusminus put dup 14 /openbullet put dup 15 /bullet put dup 20 /lessequal put dup 21 /greaterequal put dup 25 /approxequal put dup 32 /arrowleft put dup 33 /arrowright put dup 40 /arrowdblleft put dup 41 /arrowdblright put dup 49 /infinity put dup 50 /element put dup 54 /negationslash put dup 56 /universal put dup 66 /B put dup 76 /L put dup 78 /N put dup 102 /braceleft put dup 103 /braceright put dup 106 /bar put dup 107 /bardbl put dup 112 /radical put dup 120 /section put readonly def /FontBBox{-29 -960 1116 775}readonly def /UniqueID 5000820 def currentdict end currentfile eexec oc;j~EЪ/ ȭX~id}S5Q!gtⵎkJc;rN^X5.Sy +'IqV:r㚉#,# dBZ *R*"7٨y=cLIPsF'f> ba ]fv+QAwdO[x"%Sx~{p҈덡|O BÄ/GL3h+Ng03jU1~akDzq=U}.KY碌 ֻ1?C N2Muh/4Gm�&v.d)%\о .u c($E[~7�:ɿSj|"4ȉG%$6ۤs`eewÅ4(כOD4.Wa: "((&6> J^Q]s`[Mb :l%^qcfl1Q'][NLLZeBէV OsVԠk$B;>kM@jşGDi#T )s:8!b*+*^ٜ2ifW Sڝ$\!޽LPZ"X:q޸,S>y a aX^!:T~-ܱ:l-Q�r˅hmabRf'x@[1z{\~]5g )9pcB)I8y 2Cx(Ig+w<ޠ%8]-!*]m@ۍ@ƌB#<&Ljr (2 AQ>DhtOxG-9ĵG0Fg4MR,SIզZ;WuRQIMbU,77. (t E؜MZ2qBM66\` d>WX]$ؽ)t4l84aZsظ(NQG*bC%J(羨8&V497P]Ѣut9s.C0Ne]cc ` `H@4=ܤLk ϶ DnLTN4? .Ȁu_6>e#�ϩ <e2֕۩ۚ/eL\9!ְ;p6LvU7'ʷץO~V7\9&�B%aC]�NddRP82ϗ(OS!s&ΗJ]q,yj8-#NPa#/UkBu/I INA+?Ȩ,7dLjy<㦫. u(4?U xR2]+Aph8F ^:N]5! 2ejfbY|*u?Qí=WT>I%piiI܈ߏ}2 �)@JATy`thQfCe. u .Nn>WaMe-s"#_q eE@D5AToKs/Mv.J]@CW!<˴ԋ.U|[!Py rVbHn9!C$5mDRg™T(qhPsk< /th5F hz)ta`=g?ge*7:M-Zڄ_H\3cWt :AO1D u_ {Ql0 &J]oa{Z@P'X@b>fM=M8Zj=kM{x~;JЀ j>ѓ#+YϕH$fə,wOKeI mQ4ax w$ׁ ,m[$UuJڹThWSrWZZV.hyb@fd(m&`X=y+n-�Þ# "RaYm1 W±o)Tv8 =kNAܩjF.T^2I`iʋXʾ q}Ҿ�#iMAYP5YupUBAv;F[q#.z*m7㜊s"@!<߄Bo`i:j&+h .d& y9u@"P ZI-pJ jV�8Q-:% 8Vp_,G]Ƀa ` ޽4Zw;#\ݜ(Z_&7dnK4;̒'={2x(~uӨzr>M<a$IhO%jZRRc'>#/xA+tBXmHx.t7[2 MO WՄ(%6^ieJdd51MK#A3*1\I n,D>$,n"٩5D=h*,#KfQ4Sg+ 2,',o=}~G^ޟanϩ*å$]?u(y+ <xe2"þz;ď<\, /z<GIЯ#6&)x=6Oi>UK5KYcV}Zu5"꠬ K*4(0%Fea.Z mw~_8xb,i228my\Ljarr{lWp21ZyIHO耷Vi1,OJYգ@[V%]!8oЋ㖥wG{۔ Vʋs 6wLA.lEGIݛs M-D,7QդrC<㹋 ЛK6uQ~]iVǖTxSc[ʠ=Tc \qi*[g\NS KBi`CoHfc$!T*3mb{IN+%km_cY[Trs&[@^ okw!ZR8-?=tS =A=rդR-V臏-u)Pl/ASuu7_�ONnk1_·P;p=x^[_\'#_"ݱ}>g}OJ~-,O]Dg?!C,@JX*ʋ6Eo#"ŕkPP=]m 8O* JuIq!ЩO>@P�ހv0\{^R@wdq1HsӠx?IP︿yT=B>UEgR�ۚT]Jo {L%t?֍UF~>VJ)47F2Y~%-UJe4QR93<6&k,},ʞRBJA:J 2ß5^rӬu+iX6(WxOSRl0ى1|#.⏂>g3I^j-ĉj.m&l%〕[>^p3W"e17jOP^]%HeXN~o0֊ISl3A`G'KzǀS^8(s @>i~3ۛ'b7?G췃=̦4!y>:21+@1k®. Q4)dDy٢>Uw⃁?[l Lr寘APufӢʉҊMSJ p$+VgѼ՘Ӄ+Z 쿼/ y B ,cK\]r.Ĕ̒J\&,VpXZX="MgYޙ7Y|BKzMO {.r{h&w٤[gkQ]]j+P\t-b/MM3l~;imO+gPD3l_ccdoݾa-.h԰o,*hc*G"IK,2P3#*'SmޠLwigzaa ]tDoDh$V vhm1}j8e޶f<04OH ĸ)Ym'Ȇ%\Fz+%#^/W?7%y{c -Lb)#ywmO"b\Xxwy6$6_ B$ZeATNK_ǩx�]t2>\It7QEefUҏhZ_4-= 0bI*aH4Rԡ`jgF 8F~qNǜ[ i_@ž#<[NsbYDunƧN" h%SW m^!$uQ1GG%Nc(Jt"܋cjҎ^ŷLGdz�eS yHRևYi ,־q.fȣ6?-މ$ 0P~{em deM -q>ws|]Pg(?%^~n @h;o1W хglYx6`SRl5.YQM7�:w<0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark endstream endobj 672 0 obj 6693 endobj 673 0 obj 1350 endobj 674 0 obj 4811 endobj 675 0 obj 532 endobj 676 0 obj /PGATUH+CMSY10 endobj 677 0 obj << /Ascent 750 /CapHeight 683 /Descent 0 /FontName 676 0 R /ItalicAngle -14 /StemV 85 /XHeight 431 /FontBBox [ -29 -960 1116 775 ] /Flags 4 /CharSet (/minus/periodcentered/multiply/asteriskmath/diamondmath/plusminus/openbullet/bullet/lessequal/greaterequal/approxequal/arrowleft/arrowright/arrowdblleft/arrowdblright/infinity/element/negationslash/universal/B/L/N/braceleft/braceright/bar/bardbl/radical/section) /FontFile 671 0 R >> endobj 7 0 obj << /Type /Font /Subtype /Type1 /FirstChar 0 /LastChar 127 /Widths 678 0 R /BaseFont 684 0 R /FontDescriptor 685 0 R >> endobj 678 0 obj [ 612 816 762 680 653 734 707 762 707 762 707 571 544 544 816 816 272 299 490 490 490 490 490 734 435 490 707 762 490 884 993 762 272 272 490 816 490 816 762 272 381 381 490 762 272 326 272 490 490 490 490 490 490 490 490 490 490 490 272 272 272 762 462 462 762 734 693 707 748 666 639 768 734 353 503 761 612 897 734 762 666 762 721 544 707 734 734 1006 734 734 598 272 490 272 490 272 272 490 544 435 544 435 299 490 544 272 299 517 272 816 544 490 544 517 381 386 381 544 517 707 517 517 435 490 979 490 490 490 ] endobj 679 0 obj << /Length 680 0 R /Length1 681 0 R /Length2 682 0 R /Length3 683 0 R >> stream %!PS-AdobeFont-1.1: CMR12 1.0 %%CreationDate: 1991 Aug 20 16:38:05 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMR12) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /PNDTQD+CMR12 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 0 /Gamma put dup 1 /Delta put dup 6 /Sigma put dup 8 /Phi put dup 11 /ff put dup 12 /fi put dup 13 /fl put dup 14 /ffi put dup 22 /macron put dup 33 /exclam put dup 37 /percent put dup 39 /quoteright put dup 40 /parenleft put dup 41 /parenright put dup 42 /asterisk put dup 43 /plus put dup 44 /comma put dup 45 /hyphen put dup 46 /period put dup 47 /slash put dup 48 /zero put dup 49 /one put dup 50 /two put dup 51 /three put dup 52 /four put dup 53 /five put dup 54 /six put dup 55 /seven put dup 56 /eight put dup 57 /nine put dup 58 /colon put dup 59 /semicolon put dup 61 /equal put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 70 /F put dup 71 /G put dup 72 /H put dup 73 /I put dup 74 /J put dup 75 /K put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 81 /Q put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 86 /V put dup 87 /W put dup 88 /X put dup 89 /Y put dup 91 /bracketleft put dup 93 /bracketright put dup 94 /circumflex put dup 96 /quoteleft put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 122 /z put readonly def /FontBBox{-34 -251 988 750}readonly def /UniqueID 5000794 def currentdict end currentfile eexec oc;j~EЪ*BgNӽ ؑlKq*޲Xws|QFqv`zXMyp"5O˩YŝP(DT!�[v67XFlU&3!Rq4wσ~j+ou\@[6]nhmlhaH+4/?3&n=a6E#|~.ԅˠLw2.槝sNY ڻ.,VnNX3|裠k(QIOs m;fߖC1}_a Io#0wݙ\P,f *bG3Z2کP8L3r[vnc_Eh~g9|M) }YaѕH|1m![AzXpPNCU7Uֲ7ΖTgx_hyW^]W}s_Zfs@dYr ȟsy&vJx)ݱ~Kq 45hL#q:4pP?g |GJSn^i26M Ęz0. v31껰xCj 7}0a `~iEfÎ�B wS:;9l[ vqo (>DlqY?kڑo^8KLG7qZC`D<C~"A ;I[ Dڵb]C_p8pa@l(/-wQ}-v8PD|3Uemd%Vg]ƫzqRH9:ax`S U,Zf^Ybf Pq)LeE<ܐc[Z,u};KQC2 *RۇEhBU^ژ2 Y :R+w uj7S2HnÓjI đix?so6FZGeW\v]ҽ Nbo֎>t?1d1HeijQogL0?=Lvsy3DWYdCyhۃB­!(WNl  ٙyR�cQm3} #%W.Cts&K,w&~OX$ OX귞@SsTf-ȓ/X3PoI% /ҵR KFp cIbY-t+#dpţufke^ӂMl<, Ă?nPVQ%Dp t^IoKTޫʧGc>n*k*.N-f| ew=d!9oթX�s*}]HrW3מ4']kրD#J/|,+œx^79^뉌51kY=F #(ꢑ2:`8WĂ{pF_Z>!г %A/2U6daX /n6P&YY9{Fz74;ECaB3,Qy+uJ%np/s/V&<G64!~ ^0BL7<<Tw J.l`t[7gȃSX0Y6p H5keH֣+ؚ꘠ wX<Ϗ6"ڲ1gLܤFX *ctVv#v0ڠYeoD'B \?,!8\j8xSXk. 0GbjK Qk9\x{X*.qڛ݅J0h}}]2Z%6.v]GPS_-O l\Ea8՘{u܃eXBhj|z"M7�Ҡ$~'S-@6Dkݑ.R4^W;}zNh+o8;u5;뎺]K>,CיOw~NBN"sLoԡ RÛsb]^TkЕ;. _L57m~Ǎ5:o(U΁#f'E &P(e&b$Rٚ4E<(bY}z"5ϑ!:$ | IP*X�a3;lkX<յjk' \[< V)nuN4YTc"k2< !,:B\m'o^3a,f6 X C˖ e3G `нZǣ"z_Hq_.hut\b:Wh$Dd XMWswUnGb@3Һo* &+oĒ(w1NNdqp5=~ uy5!Oo+шXPR[@*ɢ/t )*㇓9<S&a?T]- 3E&sT+7fSB ]zlW Z>! xJXnSWUp:hQa`٭z{ѿbvik1/W!l6њ'ԌLxŎkFҟ9 ߇D Ç+&\q< y pzO3,�,WqO 8L!`167 éMl[-FQX*l @`Ͻ7n+.|$/V۹:B �M'}lqLݞ^)R $ #7$P!3 v2^|oii{jwy2Cۑ,i8&"XIB#{fhDq#ٴ{q)x0KfUPy|Խg#:/'ḓ&M8#K`Znq/i-MH*"=z4ٳ@iDSv?̠FI6g:#r3ѩ(�IێDpte{yb>�^# r?%{UE!Ky(+p-@יoUy@+dǷ@0lv?CPćQꍳ3<e)]fG=0yÍ@[x22z8\$Bq.Uۅ"%pArmS^ \!xu֙%/D!4*C`$wF[A<$\զApG D+<g$iXg,p.l?!:?ؿ1܎)6�Jn,/Ȉ( äf[kNɓ]LSPg:Udg#<8rYtM KAd ;% L/My)$PՉC&gqR^B#a:^?)EKp[Vd̓P@Scv<I|h .�ɴ͠Ͻj$!:"#OZg)H< _RጸO?$zy^!<C))E`֚z.Z'`1O)ķ BCk-1ovw$TܜDfs<'W鏫ß.ȝbjsiMo!XX74]­C[$o6YykA3 3 h܉Ɍ<8r}H ymEf9ȭ`#5bY,f<+dVm#TTxГvjPv4ů8$x9ᗽ՛~,hxXr͹j,YZiH7�((]+ծrbmo?pcЌB5iI]fl5g/s$762DZ%蓋G8߰v:u%dL~.tJn[)/z>bq Pťh2a?pZmp{_�&}Hpɔ{e}S5ehi0"6 \#i4/-}rYe+ҵމDaU[3nݴ'~& ,wܬ;v(U;=Db9lO%GNrUJ2fM'}\83zcqȿ.Ï,oMت\XKwC3koCr}A%+_' [בgղ~WlO) /gkBtKd Y-IʽY[h&CEbN=/UğГs9-/'3<S! &E)kY]1lfH*l>ٌZ&>_/ezWObޥK8;64o5zeAg&m6gv".%́uL7K:|Mf MHLO7+x|1IE?`]Za OG+V΢ -;fNx0OC8fZV/zJB4k)*3<q^;~R#K6 (/ Lm�&*sPquU`G‘a-k0 o8f,Y̼/*nMrfCQ޿'iFt_乔vǗqp9Ntbf�d 眧]+6TqH?:/FTq+l>*pKZcu)]91] dai 7jE2X.fzWi rf.57[quZ ȩhWIX+uYAP *ws�[Xf?IXy0ޭbqI,rMQ2Dޞ;d/9(/rA~VfY]X8gs쵏eRɎ zG<jN/ Hr WǼEqq<a {k) sh0Scg>Qn`P!>„T$Z֫k;8$Fcg934ls0HU S D/T};S'v Fe:Km Rd>iR)tg .dR^I|ukØ%I%*B *mo`(bTUQ. )Rk^*]Y]u@tb^4 r؎% iPUM!Brޝ煓t#> ̈HG݋@yեz2B%S⹡jT`Z5 ~x'c l�*ѽf_"DX&iKE1Û_u3BP/'bHybJʵ8R?4-n8_֩I'#nGV_mԥow-ШoZw.up)UJ,HzZ3v7PCLK5r6% Fa W,T-7wKtGӆϖ-Zb,M,SsﻱJd;dzLَ A-]K,[3Sq/dXKLbP e: U7hӁ8ai,7["M*c(P㒪.M'oJM؏G6Uŋ^>U!{Q?[ L SjuRopW,Xx Y5DV+ >& bmG Fl > {RZFL.ׄWlJсJW6q[d ˦bq+IgRKT;rPp 8NcGsmA 9HxLWsyW=ˍ <طpEL'$p9aіj{_ܦ %̨0B.G(CR&acfx"XSfUUcFS$%䵥韎c[L^#ᨂJe y6*Gdg랛�ѫr}M|_/5:1! hr_@[cm5@ :,Ip|Z57aOAXa/4)C,mFwv40/ҙza@ IQȈ*uư=fdZ!X)o봈实"c)FZ0>X?2߸S !ךn,OAFݢ_e30?#g|M@3 E=lTN*os*ͥ:uX(=U%#[{#~9R`Qx5NhD:$VFl90,IEUȲm%a9~c\v;vF'-j#ՙ؟"$Pek?D _ V Wѷ @g9;(a2vS't�rfb|M;9Ck<DC!x#S ��Bw:M6o5iWwg$a$Hl `6k!rRZBB+P@hq,.4vғ/`\9uG<ޔaFiuZZDMxf+*\^"<뾟rWgQC8+ .Od<LɆxT_1]1//ÊLN0}1{cb-ebLޔAd~.�l _-iiӪpi^7#sƉzx=1n,ޣ#`g+?'^ak�DZDd>E}aEqM0,qh b~ -T O+Q5MNz-p0=Ma[x@ݺ쎇mFϯՌq,T@ԈS\ĪX%?e!]y n Kf]v%t.cdEˆ:{8&f^j=1(j6dz]d ܓ5zpksBfk󻅳vFZ*e:]sޞ=�&K?XDv)46'A֤ .)%vDOY{0 ohDYdYX.w OwD:ENq6^OpJcl W&ג\0HGrx|І5Ya}7a PQMC.K0ӓ/݄$[7h"yZa~jCLEӏ|+RηxR>s|(BE|(\7SRq~9r2y&K Y-\CC8MAqs"f͉ eRk9sNsہ::Q0nGՅ;LN_;fl5 Tٸ?mjĉcf2)t2-4h+V1|B1ݾIXDݝqK]H ވe52E8-t{H5 VzAk}�LXb+|AkAp1}(:HG/W%T^KBA@Z)z "?c3Ta*z!]{iΧާFf aRuZ<խ_w& w 3S瓥J%%Z/6k>͂dD7$4Avp_Aņ1{wbev sA^؜aggJ^Pkq*.һ_cI~O/Wdo|G#Wsb8B.b" ,M2¡+}_Ǟek'jD^ewv\37@-`/2\LB‘P9'G߫ KIu44cdu!6UvOmbt߅ d.bڈXrU֙k[zZf7 Q'A:EeY}`6mR4W"DZSm�|N1tf.p7毚?M= Y ݞo~t_9߽v~鷳Ab ФKSm$6`WAiګ> Cjtň4Tk*PR!Qnmku(inAD1;]zzW}969@(CKU<{ո jx 1Z珩 ZNCA0s\7CRV(dH.uF XR1@'G%-; ,,5v1bk';&aCZkXAC4i9\BTԋ٨}7eOl\a@|�T)JyvlUՑW) V3XqzO"˾Dҗ 2 ny[@'>k1rU3"* v|(o$&(H@عF Ȥ=n_T~Gi|",@%$0 s0P5t!$;]i?eGvIs!CooGԢЯe$TtFj.&~De)NZ|` b"Dv\p/cL�F(uLʏl@(/Uh:]qFTėmU(ks4]6o~d z. ? Z| |'`:xZ %WC5s 7"K^׿kRkd+ޢ:Avt28*+ 3`>hWlVip7&Y^Dx!Q[]o B1LpC"O&j,j@事o40m"`=Kd߶:AQ_R|K(^-Q s~PΚL| o+)fq/.w,i|>)F�'{(vpw0v)7"2'!&'07D7yT҈nWlZ zR?9J M/0rPT2l p(nbLOa>1C R V^g߆ߑzin8%[tg|C/ذn ]>s43:qkIۼH B&فuPz**ͼWKpd=)%t!飕kAXy<%<鯮D^] /f:*'Tq 2 CAhPvڪ"zUP/|HoC36LOK/EN;dBq? N  Xp)JKgrbkV%rR:]]|ϊC{y}Y@wX֘\1(*;@GRmAucxt*> rUnܖ?\3@.Azvoou][=[⺘Iyw X?r *o9+oQ\Js*Kz`GFH-Kw7Ǎ%W?akU=95q/P_}1��U<k6v>5&'<Y68ZFR a szG欜j17_g[%`QWY6;D?gTtVؾVep1!S,jMsJQpwk#iu=_wiFxPz&L =SAx0FoHd#HksXlįg&(@;dcDj6X+ j*(;b]>Za݋*x۸VCiݹ� и5c憂Q_dQQ"/?t*:V?U qxjw3&+8/><k\lB,vڿ_]l/6Dcyb#uȩӖ\dt-τ�#krWVoR^CDVt{ѣj,C2 ѣшWQi0&Ƞx61|*q6",U/pXrAi%e:KTP}l/t1[3`SHКEL&Dܜ}>x8Ot͕b( aYjr]#pڜ$W2qP�\ݾ/[QȽr۬eY/v@>23[/]w;K @/6~0Ј\nJ'Bߥn^G.Ib�45krh\:aٔ N~P7EhztJztCizf&XӖ? iɘ zg(s "fۗ/_@2z8$NUo0㐝$D&|yFŴ+fT/ž4#h:y fd4%Xe LCjd˨>VwZD7G)\Km�Q ڠF!)![KyFJ47W ]x- q!?jw ~<M}WGe[}8dz@-i7! oYD]b,ueߑsߣ)ʰ2|lﶣ 8O],(0-Zçg M Z:GHP?+5Q3 r `Uϱs.kІث�1glhs34(|f�Fdxem l5٬a܀Er1<M &m xOc <ُFFvJV[hp_xU hbICPzGh%;o1 ,X*sCJKAAtU=LƦXpo3Y'AVY߫Cr2*:LT4N省AT9c @*5XA+رa\.ۏm=uO3<<b]#M-}][<U(rdQ6>^MLU+ `rPrusUNCtE@^=#H`E3�~ضHpB5.Fb"\*OYlWg22]=p cbs􌶨xF0c-ڔJU+ZJtܳE5%%Rު`E;+~MTvNJ- Xvfz@܀=ms*_2_]I$RHփk`H)$uL c7 2!Փ`l#Unђ(>aՆD JU1a` }I'맆᭦nx HӠBD 1g9Zu�Rp#Ě6k[~#S[N۳Ir, <0 4"kbߣM%#׿Ej�=Y ~1Ubz:C>S?[<'5!ݼ_g-$(v*%AXfgQ<ۏ[ ':x7ּAIA*7YlTgM^V3o\tp)vdQ/o<Fjj}yC=#ﺸ5.ޕH (oP32exu+�e G6`:#nf?f_\\IeB/R͍4TsMpl9[\HnɪjK+b U$U(#{.#sHWT-f Z$u]6s=(=_S[VxTDZ,3w&{UHq9d}hD||<gq(O<RSCr<2-wy,UYA/iw2mx:DIʡ]Zp\Zv2yL XZ?mL(ģYnHb[/ ϱ:"4jZ": .e9(`rCh81- KmB +׽0ݺ @@2-j?|$(ݖfs,c y\Tw/wz9gIq B=w$$&1E^d<|l:c܌qp9X2!UU|>{?##➜'%0a|}5b;نpOYUhvM踻[=F3r '>+ 8B:{ƏdGai|ie-k3UB Lc_'D+UO}xc :MQ1_ Y� Cw[y765}0. >8<#42:5RŌeshgP+Dž#cHDAOzxyph*svԩN^%ǪR mToA&Oc%o&1S.Ըʋ?)w7|y巀xVi|SB&w :E~[&MWR`xWcc,pT 2-7ZQk08nIZZvБ1Q>fr7nLR8!U S-Lq!ށW!׋z�߀bjOWa\ g`J$c99 @DohI)7j)&Df0E ZVwF?Y}d\nLnv߈+Iz%݋՜ 'yIuG}4@.h7L�d<r>v|a.k<Vp@q&OSΈ^gPnyk3uD(JYp4(貛t+EXQgD~W"AgW i HNxgiX[\潋VHNW,b8Vf^܀+ƺQP˓{ٙ@<|:k3O/avOh6#.uݘ|чnKk]ܣOz͕vZIuy2)ip!c'<p3f W�Nx`oHοʊ-m<KY5Fo ẗ́Ǽւ1lu&BYX>bFK? 7 h, .^"r3ttb. ʃ?N1kHZCb!@b2UԊ }eU E-TSn>IU{Ufs�HD >V\d*x)|c11Bʆݘ%a`4.%<o øp·? :8E?.w%TitBAkc/d'x6DX*j�)89;vV ~:v[`LES>alƮﷂD圚W;<P٥Yf6bq kXᏖco?+hXj2~Ü]Kx^7DzϽ<wb ?UFR `O(Ǿ0XBwpbb˲s>̭,~ ԯ~Бfmm^nGsJmc8>F�do eI3(6tS"سlR#{Uv[hViS&AwXOGfq^vG4'&)TӕTdZ<9Pp؛&[F-WQls-~uǥAѫ֟23dpoӌu.blD~O6CP=Aʌ$5 9K O$@K0-z.>_\ DsW.dܷ1qEs̹ ۧ"kԏRF tr2�omᠱ&xLь(LuBcbx<טGǞe2"Sud}^WbS8hMY>ft7PU1|"] Bp&zRP[8eyFIZk^Btҷ].?nWaٍ~b_[Al$"0;[wfFK~;e{:JN}/FBD{KuH2K&ڡ&Z#t Q-܉Hjs %@!�r{e|gvT5 ߯(#f\&J(S̾T+ץ9+,oaPewf3nfIs.vz][EJQsObfP<Ö  Fd,0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark endstream endobj 680 0 obj 17450 endobj 681 0 obj 2167 endobj 682 0 obj 14751 endobj 683 0 obj 532 endobj 684 0 obj /PNDTQD+CMR12 endobj 685 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName 684 0 R /ItalicAngle 0 /StemV 65 /XHeight 431 /FontBBox [ -34 -251 988 750 ] /Flags 4 /CharSet (/Gamma/Delta/Sigma/Phi/ff/fi/fl/ffi/macron/exclam/percent/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/equal/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/bracketleft/bracketright/circumflex/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z) /FontFile 679 0 R >> endobj 6 0 obj << /Type /Font /Subtype /Type1 /FirstChar 0 /LastChar 127 /Widths 686 0 R /BaseFont 692 0 R /FontDescriptor 693 0 R >> endobj 686 0 obj [ 613 800 750 677 650 727 700 750 700 750 700 600 550 575 863 875 300 325 500 500 500 500 500 815 450 525 700 700 500 863 963 750 250 300 500 800 755 800 750 300 400 400 500 750 300 350 300 500 500 500 500 500 500 500 500 500 500 500 300 300 300 750 500 500 750 727 688 700 738 663 638 757 727 377 513 752 613 877 727 750 663 750 713 550 700 727 727 977 727 727 600 300 500 300 500 300 300 500 450 450 500 450 300 450 500 300 300 450 250 800 550 500 500 450 413 400 325 525 450 650 450 475 400 500 1000 500 500 500 ] endobj 687 0 obj << /Length 688 0 R /Length1 689 0 R /Length2 690 0 R /Length3 691 0 R >> stream %!PS-AdobeFont-1.1: CMTI12 1.0 %%CreationDate: 1991 Aug 18 21:06:53 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMTI12) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.04 def /isFixedPitch false def end readonly def /FontName /XRAAXO+CMTI12 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 18 /grave put dup 39 /quoteright put dup 45 /hyphen put dup 46 /period put dup 47 /slash put dup 65 /A put dup 67 /C put dup 71 /G put dup 74 /J put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 82 /R put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 122 /z put readonly def /FontBBox{-36 -251 1103 750}readonly def /UniqueID 5000829 def currentdict end currentfile eexec oc;j~EЪ)s̾;.;rTejiK/df5A|{S/ )Sc\^ȟmp+#vL17~k d# ]LeVߐGoo٥\k 9M֨[G(aܘ|RP>f}|Zx'5�+jۊz3p3`/gtJ8)&ho%̸{sCVah~I"Y0'Ӷg; 怦#Ӝոgl;O6jy�g H�<yq?- fu:V͎^=ѾrPHrn'/rlh\q0Y'oiތ)*\qKl0 O4Z]=m&º(eC{<F{b!`6pM:aqeHK 1eac>@n΅ l2qŽwޗMe]}Aq}_oyѣg+JIua;5m˺ڳŞppX!cs|:J#<yO9GcT`Dj D'w|5#QvyZ=9$X"Up1o'y@1Y:S>]Ts*?~XH VH ‡9E ;ۉ?jK&\$x!/_lPK1Mgl"oË 9ёIهnXBf9)/8YNwwb�@t:0JHͮ#KW ܈OKqrDgxǷs@iE@G{1/ ݶ5zï]l<-!3ڙ̒Js^p %r]~f eL aʨkސGCsr2':Ts&yB s #CWY2@[�'l*~qtW>ppi `^TpVJ^&4f <.7XpO<36y^<|2Կ+_X1WnYDClvmHk~m`y?[D[A^ʕ۠Q_ ҭYNƒ}GGh{ʱ([%Q�ӟ PHbPe7] #L:�I0Rطw5H.Kf$I0o&̡>E[2DmjѼR&ޘn$EgXh'vd S9"}BeYOp@dH`{KVCIe7 ",;@A^+z\`9L&FK({aLW#5 8/Ł봩Y`|V% _n.F s;_P.X`&$eL4Hhz j[\U/A Zźk]M^62.`~h ֆNQ<Lũ< Z-;g+jJKj($ꗔ08襐"LL[\I໪+![Œr͛3J]I|)?kJR6aۏԦ6KHy$\ehrfN,QxB1<E&A Jw}uγn-1x y}TB4?Ng �/~?s_o\UIfLrTbA/f,BغQF!9jَl!>|]lMg}85v#)3>Y,.~BjAt(lAb`|ǧ_/8o[FWɷKR 0$:?eS;>Md)SҎ`gKR&3hN zڕS'F[/fFDࡀÖC{1dZ>v_=#BƓv\ok7.i:kqrX]GsC�?V�bGزhFYt2 ;�kCGňAd+Կ>DpW;7(ß.<i%z*wjE罶h'Ǥ -<YbX.LJU76k0suDH3˻L_eP ߶z\ӭGuK7y<ү(퓤4/Kmcj=rvqfd]2KHG^eښc/+ &LO7?X 0|)0ie,8 St\L> * :GҲ7sx ʄe!-n)ga4q\2 NcBUkKx�W`̡\MD*z-9&\yL X"LrJ$@(R_dnF S*`U1' ?A p3֧͞7BaE 1}E )pQUďf`>Yy({efFRHsCjhTf`{ڈ\0nP΀oi.mi8^M\ Lbz=a�VAT MHwq ꇵc:ljrH0֑t2y%>~#]{$,, i҉&W=e�ʐMbdZ!biZ׷~q;!xiK <j} nߓ?@>ٿ-'kfU0aȺ6a}a&O<ih|QԺ+? @1/{\g;G0h崄0 ?%{r#4͛} Gu龀iAu }tDK�jdž5o~.1'섷m;vRF!҆ɛ�_l"´6]?ƃ#ڷcD%ժ$XEop̂{\nm&rn[<kW $?(rGvȲ(#3g^+q0u‰=TDSe+-) \)06!秿!BH83\OEƎOuVyQɗLUbp'b Yc+uzrcb:7:;Vy>aO4Xqrk!w^T_"#C8́|Bw OnoONB'עbb~0C$w>FIMyTׂzG R"֩nu,"m4unYiivdXE~y4n8/q?D$P%!*MUEǮ a[`dlq\ڥ-z<�})JĦxjY)Z&-2&mzںfg% HMy0`,riOqFKe�1*b䩡 [dvSu@z!8vB2ͳw)OCJ .s4Z7E I> !rCQG\@p< ա<H'٘ϣq�uH?O:֙q{g'B<ѱ{2*3 z`^|fDvuњ+/kjQ m/l_C\V#"#LxIL8F>i By$GuD@oّ MUwN@ϔ,_[mRN姧QjT xhiֆ̯2 m- !lq&\~p7>@5&RrPR= 'vk+0jcpo"MQEiU7+4Ԫ>̊Sä蚨̍⻃c}[?wggәNo:.[ neO퇋Xt8Fj2taPE g1a+6.RÞ\Cn zVKP1mX>~5owsq˟:c6J6)$->(Q7h첋dV"b {Lm%(N-4"y=4gG_lmD6S3bp8OoS2p` ٧rM'~us<qWCdVd"JUʩtCx?m70#uL`akМ cV,hO8LblxIuvu@xk/ JnjoOh(.8T| f1ԥAdv@)(VD3P}qEx#ZU8 cGNJ i( r$Rw�24Mj^ʎY/KaT pPwAuxx3:WtGږ/,C!zi(:�4byStv dXpH&!r9<]du tΛ\FGr]juW{e]6p5G/~AO5#YqG-+Gh2,P MK3Tl_ַ-=f~`f|sK^#Cm14L͖Kp䧟T/O;FqeO^-M6o$qS=v? F^[b2٨CL9�N>dAfڇ#-mp̾}w1,1E¼R$@" {:a[ȝd^!s)6m7kX/I JwO66÷|.y7(|mN{"VAԇS2[a-?m4-b�Vx%w hf0 R? sc˖g�0w)ND ɪzNU+buK29Fo]SZ֟_w%iRYՠTrNg):«LeV5<.&d/Nf _.? > [ʆX$Q4\I٭.B )٭:zWhS#*Hݵ:]-†6$*>72DH+#蓙 4MŎ^K_`�:pz.5+k|�+/wLo'y. 먧H.:�U7bf+$.%K>)y`AϊQw_lƼMkazfn9aHl^37V6x/Q!iyx7 a/s] oUQ7HC;g[ki"0e w69bIx7IJg8f*{3 M�m@P΃Kc%>ANrcSnܮ~HO@nP[PJ{m]g tߦb }0WR^~* ژ~<h, ^`X}6F,ģJ.3<;ʹҽ݉j7--QЂ*!ûLEcvYWP˥^qg&b߹Dh(a\P$|E'Y=;Ҋt40/ Y<@Ӝrv sA_>uRH6ŘtÎX(pO6K [YmH(\$cxg+A\`?u4I.cў8 B$*ŋ4”Cmp/gT̗yW.-(pt�DÏ9+"<rF],ݢD/ƁW6łXH_d,[mK�b8zXgze{e|Jhx]tƓ+ Rs+ņ/U t{3bӹWőpBdlpLt;kf/\O}#pnmK^STt{11n0C8[MXծqh7tN$ ަu%jMUl ɊY;?`ڙGgnhTpBn^ ˓ }TtT3ʩžVՆ |32]0 VQ Iܴ]"7mTg@ݤbnXWf6. t6Yƨ QzW'}g#ܿwêI[bher !` ab-X获?0ty7VJ0<NҼWg"D}+Yx Ц]6[j /�4׾zzX V`I`qD`yA!(Hܠ X!NXQt\[V;$i=#XL0ɸXyذ4RV(ם έVʒm[z{ܶ&H!`/|=YVG[b9!^/j z;&u)"Fh<<gOq}1e/o+ow~_d<"07dՈҶN{^#$qȪA*& d΅DT!bpw"h E`)`PO$&pkL-ԸiU\Wn7 \3=72iAbH,OP; &̰h%! ?fw3qR~EWt&9rLVFE Y!l\'lf6KݥXY@nj8:|#, <ov\uB韗2)Wқ3SPEmi28c f*9f0&XF\,x7wuGC Y�݌KʴQsWNV:.ܼ^8! o䗧}%G^5+/]o xl;fIȱ XHZTPu.ۮ( ɯ>ۍ@i:ϱŰ <ɫ3c(^) xԠ[(Syb@x—t-zGܱ0ÒBML)$I4uQ\7 �kb._qlV O2y:UpĹxx(!\]m—zFNZigDAs+0R]߭=J7d?0ZngƦώ3 uDRDei ~Ј6?*'ʘ<DpҬv!׍ےc0xvJ�0<ܚX /V,:gZbǒYꎩ򮵬"H.nj/"x:maZ{*8ZSmH- ⡲.jNoirJ2״SpPkذNA BXD90(-{C*sڨ<*燅+u'kH"1x_Uc. ?'Sy!yB 'X( { Z~fNcA|(4b'RVQ]u=dl:JKv70 SKK]6MuMAd{xQaFX%i;3=z xtJ1=,,cm6%LpzJ`p\ZU~_e~B'KZ yP:Afm 6=nZL3vk' c@ے۸@nhg?f$&r]"5G_xSb&'t@oN 9h}a%XE\ D=V-=b(ʥ|RTz0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark endstream endobj 688 0 obj 9851 endobj 689 0 obj 1347 endobj 690 0 obj 7972 endobj 691 0 obj 532 endobj 692 0 obj /XRAAXO+CMTI12 endobj 693 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName 692 0 R /ItalicAngle -14 /StemV 63 /XHeight 431 /FontBBox [ -36 -251 1103 750 ] /Flags 4 /CharSet (/grave/quoteright/hyphen/period/slash/A/C/G/J/M/N/O/P/R/a/b/c/d/e/f/g/h/i/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z) /FontFile 687 0 R >> endobj 5 0 obj << /Type /Font /Subtype /Type1 /FirstChar 0 /LastChar 127 /Widths 694 0 R /BaseFont 700 0 R /FontDescriptor 701 0 R >> endobj 694 0 obj [ 676 938 875 787 750 880 813 875 813 875 813 656 625 625 938 938 313 344 563 563 563 563 563 850 500 574 813 875 563 1019 1144 875 313 343 581 938 563 938 875 313 438 438 563 875 313 375 313 563 563 563 563 563 563 563 563 563 563 563 313 313 343 875 531 531 875 850 800 813 862 738 707 884 880 419 581 881 676 1067 880 845 769 845 839 625 782 865 850 1162 850 850 688 313 581 313 563 313 313 547 625 500 625 513 344 563 625 313 344 594 313 938 625 563 625 594 460 444 438 625 594 813 594 594 500 563 1125 563 563 563 ] endobj 695 0 obj << /Length 696 0 R /Length1 697 0 R /Length2 698 0 R /Length3 699 0 R >> stream %!PS-AdobeFont-1.1: CMBX12 1.0 %%CreationDate: 1991 Aug 20 16:34:54 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.0) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMBX12) readonly def /FamilyName (Computer Modern) readonly def /Weight (Bold) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /YRLTXJ+CMBX12 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 11 /ff put dup 12 /fi put dup 14 /ffi put dup 39 /quoteright put dup 40 /parenleft put dup 41 /parenright put dup 44 /comma put dup 45 /hyphen put dup 46 /period put dup 48 /zero put dup 49 /one put dup 50 /two put dup 51 /three put dup 52 /four put dup 53 /five put dup 54 /six put dup 55 /seven put dup 56 /eight put dup 57 /nine put dup 58 /colon put dup 61 /equal put dup 65 /A put dup 66 /B put dup 67 /C put dup 68 /D put dup 69 /E put dup 70 /F put dup 71 /G put dup 72 /H put dup 73 /I put dup 74 /J put dup 75 /K put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 81 /Q put dup 82 /R put dup 83 /S put dup 84 /T put dup 85 /U put dup 86 /V put dup 87 /W put dup 88 /X put dup 89 /Y put dup 90 /Z put dup 94 /circumflex put dup 97 /a put dup 98 /b put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 104 /h put dup 105 /i put dup 106 /j put dup 107 /k put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 113 /q put dup 114 /r put dup 115 /s put dup 116 /t put dup 117 /u put dup 118 /v put dup 119 /w put dup 120 /x put dup 121 /y put dup 122 /z put dup 123 /endash put readonly def /FontBBox{-53 -251 1139 750}readonly def /UniqueID 5000769 def currentdict end currentfile eexec oc;j~EЪ*BgNӽ ؑlKq*޲Xws|QFqv`zXMyp"5O˩YŝP(DT!�[v67XFlU&3!Rq4wσ~j+ou_dV`Ky Z]uMYb[1[l',t\pڮԞZO4GJ7 i!U�&Ϸݢh`ZṆhKGz; #1&()$J3KُօEsjFf"P$-I޵˕B 6=hqDV<` EkENrraƌJG ~L{6IE6U'y 0gK>&)o>2\U]$XW-1f@'B 1mW=L%5t.O-]N CT4>&wvNXŅC�f עr1fׁVCȖ~q0 Xf^^$ӷ%G7dȱ\lFc0]g<銷_&W{>}N|ӷ 054H4ܞlG>T_cќ6Y1 nUr-u$yfOσ4nA�yغINz�+:΃΃Џ}=|z`v+D{.;F�WLEc6o, e&ۺH�%&e+ o=�'a9ܮ;-sg}l3K?SEhAr;}5٠땷7_KߔZn+ Kw$ZdvԬ|d-I&Ja OpksYlyS0jŮ͂ȡ=C 2V_]a2hN�h!5;*~ƟJY<>E&@7dspflmJ�"=){mR^$K]=I{FLj'^==ca1h m"tQ+yc+#-%=gKJ|:Ʈ\ ^_9rչ.5G"ȟ~~!M^wwΗ}-.8?Cd:c!ʻ t>fy&|e8s3"CrhC/`&Ux<xf:R<-7}9%Zi}i:   W\L\02Y(:^vΣA6^&o"csЀSSQQzwU+e%0͙GxT,؎$ 1Tk:+^zgя/ ){6@)z:<zu=yMMn6AFt0(b 'A_2-Q(۩?{:3 &}p41x[UJQܯ_? A$(sPU<*f HP c@](9FKt3fxc &jy@GƍX͝9+gC}tц(0*ISVD#DXj1ߍܸZAԶKAu --F*PAOai9KN%#Ir@Q(l1׳zFIL XQ59Z944Hj,PZҨʵ7 $>E b6"bo4tB..U馦ovl.mݙv*ȕ/N$r!5XPP^Yl_0].Jٴ!Q|OfZE KAPHYs-BخǺSA,n|`Vֻj#b! %ѬDsZOC!_5G6BX]xhf%R3E7 һgmpHcb!4GI;NjYIpD(Û0JQ�NX7 <RV&]!LoJ_mox|$Ogp"=x rZgOݎj A cNQnB90kpruƨ1r^ks8q媄03ju~tg|wY %^s=ZnޔSc~]ta~X\(Qwjq8ʠR)\~c0A$K><z4q$ڇeQ?<Hc_εTbAM;&PޡV;?<(!CÅs4v[%z1ՠ?f18G2v-c$#j>m>AHgӭœ p*_3Tx>hBuܧOF<VS%=fjVJ`ߥfl�_Q_nTpm?ie_0LϪŨQaU+҄LVvQ "+L/W(Um0Iuc3t?JkZ314lvx)&<|ù>uk>cmDEαHfbIx&|!.NLyC=}3�kODa{�܆a;۟YƊF51sAA ׁܫ 8׊sTP)q0kn8#=LD[ qwԉm|u,)F~i{^<ukb![TҍLbe6\g)R)djQpA mo %pqu8lbFk(x=[<~xm\u/M8 wRM?Ԅvf>B`�vE#{Uχ`⁈x0> f@YvQ캳rJBWhc<sBdWeW?PF(бnIנ" _!Ɲmm{ή)@=/cQ-}HjԌq罌k}Ed)3(=' .(aM ?[=໯jIvCE]=2;*5bJc_'Լ3/bHJx(6uZ)HWYF)xI;?I |*仁1扒yY Ь<ƿ; OZЉgÄܿDQ;$I>Ϲs\11*^BTy -;N&"&gD5F|Cp$-kŻyAiv?QxtX6Z]~1-L[c%a{"F"8P:\xߖ}rKs vq3?eJ�~PMV;/(5TwpiԵ*fmb[o؞ƆZ¾9H,}aŽJ`Nl.`nY_C)ߙj-@ ?EXya9t8ٜXm 1uKS!#r9?f T�c>UeWX C,qaW~w�'h &܋Sǚ"/~1W/`t<A?a^r ^i�iY =OY6vH:k:321SM0EK<A4iV BIq az޻[Q?0\qi# S0ӀY:bXj DC&۴άa P@$<q=&e2Dk=E!ZRwoLReyrUxЩy8Clt̫}zLpOD B/q.shokZ}X$^ -ҹ]ɖu~/^{FllnrtkgTb2׿Y=c *'VK p8/0t�iCARfyD㻞lXq!3RQ#L`#Rl Q  x{f x**W~QБ糜@[-�<> =|m3]E3`j% l<Uy2\/ 3/MX:W9Ml!|fO V1~^=čX�!H%G^OoYW}T X(k)֐@FgQXJp0:Lَvd|=յ/y]LKG Ttyhp& dt*euFr~j=iԒgEo|vUes*` ?TBC50=KPFR0;G}M*LtB"̥+l}1ƅJi&dCAV/o0׶:^voQ :vuq粋PL#b6.t;=E -$vu_MMRB)g~LZ]CI,d2S~-p#> s$,Znq{4V(ޣ3rS/[#3N`kxxst#&ђU"%q#vo' IVVڥɶ_Ct| L+hPoC:BxlR`)1t/*|-+d{(cӶ^ FCôșXswff 1Q>$tpiu \IP}ÔN*JG4\?**i<@Q@lu'G?' \䱫 rf0:0R7iӘ."Ĭ81o@< M(#4 8ABs.t @qzZ /Bn(̢xe_ʈ(0^Ho>\Jx3x ]і@'"|X-J%x+CG x XNX*j~nE"q<HW0iTh)&z1W@8_"L p9�'ĺD!"_;b-X5H2.Zxc&ׯ- 7oy�m( ^1gM`"b#!";dIdG�4:05Q(D }I΃xZ A\K ~4b|"VZy99Rs2eu%Iwd|D#Vc>m#V3+bk3!z\Q(/ !Cu1pqH㮙AI gٻ,B!QɔFQƇZc`u~ Zoy?*ym0wѬPz@Z^!ҵ\UtJgshTNӭ)tͨșTC@Ga7(uͮ?zO;OzH!+~KGQZ4ЍJ`%>5]ۥAtj>٘jK9 ay3Y:2tw%R!:b`/w</@dF:45G`o$uL2Fc|HWϭTc{La8̝IGÓT.%; zN9Y?".άa1/N0I`-fvxq@M\[7zj|0տRbo6= +r]s;jo|bݼW7Yor1ժKwo5D>yΕJ\]5[@%t[TS|S/]!rОE.'f"62Θ,Gڶ!8E<RM6| E3ZzЏRָn0_W-V(N[QmG{<ƻ5C@rS~M3NAuL+<i<%4y ط"|Acf1^>x3,jց{c m\;NBqOK /rjٰGʿk}io:$ߜL%niԉ}q9.*܎~( 0Պs.M|5?z{8Pk>px/'V"#:'LuAqVT}~*e1OӸ͕}f#DĝE{8:BfDe~8qY7R({TDpy{~-KHG2YŮn+QXld:[ `2F1~^;X@2R6‡.¿:7m 8ɢkc75 m~w+8�3خ5ΟM80|y%S/Ma6] R.&E|W8/:ў6I:dz &w<. m%z:gdR:KuSB0)f2g0mq㫊B@ !xyhH݅Èf9Ip0) *qͻ'BQ�:J>J@paGKi:dX;`ӜoNÝ7!E =y%[BT$>?p0P9o̵C;dlgHEƉMsM,Buhu( 4k0AyT4.bKn[spY[-qP6%e=dEB]rݦ~sa=m%@,8WA)"Cz`1bq81U- A<I|.ӐGӲYV]+E*4pl HBQN!m~<U�ZQMW~oX$]]l3gXĿ3 h,ƦCdڻ&gDF`U7l`y1 B8\D$hJ_yWF|͙MjՍe =0N^;ե,5�j9ϩu󅲇WRpZjp٬Éd7c%.>uc@FyV(o~�M, (y Ѯ[LFұݪf_+-Ra.⮀BDC%zD/Cy)qmJJZP;a vY;kaTWR,N6>eQ֯R$sk(ZS/CxS# v_jm!e=1<:3t6a#sAҀ%[/R cnUj]6V) < it[tAAbp@}nף;̚}IDw!^"B R$nu1{'G 3#Ls8W߶ R<'Ԍ?~_6}h{0俾޲4|(d5ՠ >uGkĊIǐWJ."] hϐȘ=z-{]oʤwuʠuxv$Ky NpCkYV]M+C( ?J65!!Dp<J4/3-MwrܸH΋) ovahp6r[:$v^]~< 7ψr)K�M'0u$S|#S:x.Y tnnnrQ{^Ny*`co{#c wfE4z;#oTu/ԋt'}yX`}Uj=j7Oxe3/uTC[k9H_ ?#aN[ج_'FGc.yOM塭ReƑPDzSAʞن\bu_ubb7̀ ߫BlÁUX<t}*9*wUmxjxM tŠ)3}6LCdmw0m�yi:Ms @IIkH"WyXB'b$Ý/JKV+|HsB' C]HK/b4zIJd�[dѶuJ݋/>ltЦPqMw Sͺ[5wF_lt][ / PAe!˿]HX}J'fĨѣ`yDUGP\ƛ !ڡ<_@mªadɯIyZt{$^"\ (8�Fv[mw`vXXI N( 3aà3A C^a&:hjd ȳkS ÐaB͐+R[\ P~%`ԜaٔJUk_*iќ]&l+cܯ#b lD4bSLeQ\ON Hˬ+G�JN10ٔ+l3ƟQ$rjj[ZgKO> _ڨ f@v[" Iir*I gµ)ן/g3*u 83:`2%`{+ p|n2~K:լYя ʱU<[+c`> .*?!RJ^v vG3 ĒϚَ!oMMLw/DL ̉[. _ѓ脖;йB}(\O-@8%rXu.TO4`{X_aY썎Hљ 7Mqoa6Ob<#+\J1Hb=ë{C͗œ:xЫC=8y>qgva[D|7z] (a o>`N5BKmq5`mLI'j1 % [A%)i9y bGNGMDNO澤ZfEӓ8APw+(Aɓ`Pv8 kt3DMPelаH1 >Z : 5@Pe2qEYCL"TA3)CI{Cdcڌ.?&Jb:dP2`#s� |Qms? V8|~ '*`kZ {?@0g?y܋,@3m-|W s?!)&ngpĝ2lQ%-j1' a#i<Z];6/8뀴LRsr#N)^{ 7,j{R jȊKlʁތ76(G K|hK(~鮋|XW)? lR!'\)Pd@T}!!C;%QW%X̒Q 6k41F *^oC]!6h TM59#Of�^Xޟ 8guFⓟey|/0?e˳|288(d#y$CX׮#<Gu#cZLw04 D?{D(o9ƌ|Ij'HQ@oF(`L:E\z+'(oQ%W<'}">Pa5ݦ[9`mu3rH) QʧQ}4D@בDŽ$I)^O>E1rYk5̾gg9%,Vˎ\U4QۭdW^wl:d!bΛu6ۀNaƽ֢@Bq9}S`p\zW4T-CHR.LU[Һfe1~ DVe%6B=P7qy:bgLaƲ\;k .{7"Xʹ_[jwj]/҄tiۅZOX{27/K:)['DcB~҅`-ı OScdViF˘{l3M T%uZE=\Z=OӃCE#ۦi,|7Xr�=,ܯuW-P}uu'eEYM~5'b&F|5Z*\6A1RL(poP~�0O+sP,.*gx13v&n]G<ȻR1j4^60C{v(|lX{"f$Wh#$.wj׸`mVg4:ľ7L1nzmW@Yy:YuCI5hq+ ʰ?xWG  8uubTd3|Ni,=jQNva~e`ʁ3WQWՠ:/d|dXj5*N-s$t/[`t~{.A.p4tZe`OEHsi!3NranYgJ! 2_5 aWN"{2,^n>ΙTbJB<>1nъr`̲Qn/8sSD>p>ĩV])23BtG'Zt"�1u_NھŶ v/w[BѻM|Fq!3eWDh+Nܹ2BcE| iZlK{T&>]2m`ǧg+gv t=2=�Ƴ! ]j)$;΋i~~`vfH6atZ!p`-^&EK;bɀ ebYU}㨫k}⿍#] Y�=4.%OjBmNQ/6LX34L"qT/f!G B%sE+Ib`P2(k_ S?9GmBs"6sYdA:lQBjnTtq ?kИB^8<+vt-8cL~pۃ23ax?S꼵AEypRLxC7ha7m nZ]ZI:YH( =l6TO!wuYEoIEW'i�Ԋ|4 f0Nả{僀M9,=o(YEm;"j,JHU؏;~_0v52rr^q3�T3)/9,Cw<JMj:֗oxRſ[ 9:Y�kj@:lJ踻% e6+֩R<.IE6l:T=SAS:9wdU՘Ƿ*GrHNj  Bhq0C2M;cz7Q[ y'fM<Du `؆_,{($dmu j|pBC|GQ`�SL|7 uՔSw \f io+9Fp[ԛ)zf;+?n'@J$˲[^GArT. "6~Ci.?jk+&TD!k]/&J19nd$mK$4۩;nX sc"m1nNٳ%\%msW<U`ĝ4dT _MyVQrWg)iJ=:垿46"|GJ Wv\MAE;gr3,sɲՙ^SAC;vfVjLz9ZX]AUINy{PrHzG?G^w1Hb[(zxE2ohڀ1WE$fh[Ȉ1$m~%�hQ#L=*PiŒ/IUXPL|0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark endstream endobj 696 0 obj 14588 endobj 697 0 obj 1915 endobj 698 0 obj 12141 endobj 699 0 obj 532 endobj 700 0 obj /YRLTXJ+CMBX12 endobj 701 0 obj << /Ascent 694 /CapHeight 686 /Descent -194 /FontName 700 0 R /ItalicAngle 0 /StemV 109 /XHeight 444 /FontBBox [ -53 -251 1139 750 ] /Flags 4 /CharSet (/ff/fi/ffi/quoteright/parenleft/parenright/comma/hyphen/period/zero/one/two/three/four/five/six/seven/eight/nine/colon/equal/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/circumflex/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/endash) /FontFile 695 0 R >> endobj 8 0 obj << /Type /Pages /Count 6 /Parent 702 0 R /Kids [2 0 R 10 0 R 14 0 R 18 0 R 22 0 R 26 0 R] >> endobj 33 0 obj << /Type /Pages /Count 6 /Parent 702 0 R /Kids [30 0 R 35 0 R 39 0 R 45 0 R 49 0 R 53 0 R] >> endobj 60 0 obj << /Type /Pages /Count 6 /Parent 702 0 R /Kids [57 0 R 62 0 R 66 0 R 70 0 R 74 0 R 79 0 R] >> endobj 88 0 obj << /Type /Pages /Count 6 /Parent 702 0 R /Kids [83 0 R 90 0 R 96 0 R 100 0 R 104 0 R 109 0 R] >> endobj 116 0 obj << /Type /Pages /Count 6 /Parent 702 0 R /Kids [113 0 R 118 0 R 122 0 R 126 0 R 130 0 R 135 0 R] >> endobj 142 0 obj << /Type /Pages /Count 6 /Parent 702 0 R /Kids [139 0 R 144 0 R 148 0 R 152 0 R 156 0 R 160 0 R] >> endobj 168 0 obj << /Type /Pages /Count 6 /Parent 703 0 R /Kids [165 0 R 170 0 R 174 0 R 178 0 R 182 0 R 186 0 R] >> endobj 193 0 obj << /Type /Pages /Count 6 /Parent 703 0 R /Kids [190 0 R 195 0 R 199 0 R 203 0 R 207 0 R 211 0 R] >> endobj 218 0 obj << /Type /Pages /Count 6 /Parent 703 0 R /Kids [215 0 R 220 0 R 224 0 R 228 0 R 232 0 R 236 0 R] >> endobj 243 0 obj << /Type /Pages /Count 6 /Parent 703 0 R /Kids [240 0 R 245 0 R 249 0 R 253 0 R 257 0 R 261 0 R] >> endobj 268 0 obj << /Type /Pages /Count 6 /Parent 703 0 R /Kids [265 0 R 270 0 R 274 0 R 278 0 R 282 0 R 286 0 R] >> endobj 294 0 obj << /Type /Pages /Count 6 /Parent 703 0 R /Kids [291 0 R 296 0 R 300 0 R 304 0 R 308 0 R 312 0 R] >> endobj 319 0 obj << /Type /Pages /Count 6 /Parent 704 0 R /Kids [316 0 R 321 0 R 325 0 R 329 0 R 333 0 R 337 0 R] >> endobj 344 0 obj << /Type /Pages /Count 6 /Parent 704 0 R /Kids [341 0 R 346 0 R 350 0 R 354 0 R 358 0 R 362 0 R] >> endobj 369 0 obj << /Type /Pages /Count 6 /Parent 704 0 R /Kids [366 0 R 371 0 R 375 0 R 379 0 R 383 0 R 387 0 R] >> endobj 394 0 obj << /Type /Pages /Count 6 /Parent 704 0 R /Kids [391 0 R 396 0 R 400 0 R 404 0 R 408 0 R 412 0 R] >> endobj 419 0 obj << /Type /Pages /Count 6 /Parent 704 0 R /Kids [416 0 R 421 0 R 425 0 R 429 0 R 433 0 R 437 0 R] >> endobj 444 0 obj << /Type /Pages /Count 6 /Parent 704 0 R /Kids [441 0 R 446 0 R 450 0 R 454 0 R 458 0 R 462 0 R] >> endobj 469 0 obj << /Type /Pages /Count 6 /Parent 705 0 R /Kids [466 0 R 471 0 R 475 0 R 479 0 R 483 0 R 487 0 R] >> endobj 494 0 obj << /Type /Pages /Count 6 /Parent 705 0 R /Kids [491 0 R 496 0 R 500 0 R 504 0 R 508 0 R 512 0 R] >> endobj 519 0 obj << /Type /Pages /Count 6 /Parent 705 0 R /Kids [516 0 R 521 0 R 525 0 R 529 0 R 533 0 R 537 0 R] >> endobj 544 0 obj << /Type /Pages /Count 6 /Parent 705 0 R /Kids [541 0 R 546 0 R 550 0 R 554 0 R 558 0 R 562 0 R] >> endobj 569 0 obj << /Type /Pages /Count 6 /Parent 705 0 R /Kids [566 0 R 571 0 R 575 0 R 579 0 R 583 0 R 587 0 R] >> endobj 702 0 obj << /Type /Pages /Count 36 /Parent 706 0 R /Kids [8 0 R 33 0 R 60 0 R 88 0 R 116 0 R 142 0 R] >> endobj 703 0 obj << /Type /Pages /Count 36 /Parent 706 0 R /Kids [168 0 R 193 0 R 218 0 R 243 0 R 268 0 R 294 0 R] >> endobj 704 0 obj << /Type /Pages /Count 36 /Parent 706 0 R /Kids [319 0 R 344 0 R 369 0 R 394 0 R 419 0 R 444 0 R] >> endobj 705 0 obj << /Type /Pages /Count 30 /Parent 706 0 R /Kids [469 0 R 494 0 R 519 0 R 544 0 R 569 0 R] >> endobj 706 0 obj << /Type /Pages /Count 138 /Kids [702 0 R 703 0 R 704 0 R 705 0 R] >> endobj 707 0 obj << /Type /Catalog /Pages 706 0 R >> endobj 708 0 obj << /Creator (TeX) /Producer (pdfTeX-0.13d) /CreationDate (D:20071215104300) >> endobj xref 0 709 0000000000 65535 f 0000000422 00000 n 0000000310 00000 n 0000000009 00000 n 0000000291 00000 n 0000392816 00000 n 0000381773 00000 n 0000362889 00000 n 0000408742 00000 n 0000000782 00000 n 0000000668 00000 n 0000000512 00000 n 0000000649 00000 n 0000001894 00000 n 0000001779 00000 n 0000000850 00000 n 0000001759 00000 n 0000003263 00000 n 0000003148 00000 n 0000001985 00000 n 0000003127 00000 n 0000004547 00000 n 0000004432 00000 n 0000003343 00000 n 0000004412 00000 n 0000005852 00000 n 0000005737 00000 n 0000004627 00000 n 0000005716 00000 n 0000007199 00000 n 0000007083 00000 n 0000005932 00000 n 0000007062 00000 n 0000408850 00000 n 0000008377 00000 n 0000008261 00000 n 0000007279 00000 n 0000008241 00000 n 0000009905 00000 n 0000009789 00000 n 0000008457 00000 n 0000009768 00000 n 0000354840 00000 n 0000337248 00000 n 0000011631 00000 n 0000011515 00000 n 0000010020 00000 n 0000011494 00000 n 0000013211 00000 n 0000013095 00000 n 0000011735 00000 n 0000013074 00000 n 0000013578 00000 n 0000013462 00000 n 0000013303 00000 n 0000013443 00000 n 0000015069 00000 n 0000014953 00000 n 0000013647 00000 n 0000014932 00000 n 0000408960 00000 n 0000016263 00000 n 0000016147 00000 n 0000015172 00000 n 0000016127 00000 n 0000018000 00000 n 0000017884 00000 n 0000016355 00000 n 0000017863 00000 n 0000018700 00000 n 0000018584 00000 n 0000018092 00000 n 0000018564 00000 n 0000020718 00000 n 0000020602 00000 n 0000018781 00000 n 0000020581 00000 n 0000317183 00000 n 0000022579 00000 n 0000022463 00000 n 0000020856 00000 n 0000022442 00000 n 0000025120 00000 n 0000025004 00000 n 0000022695 00000 n 0000024983 00000 n 0000304573 00000 n 0000296652 00000 n 0000409070 00000 n 0000027605 00000 n 0000027489 00000 n 0000025260 00000 n 0000027468 00000 n 0000292623 00000 n 0000288627 00000 n 0000029911 00000 n 0000029795 00000 n 0000027780 00000 n 0000029774 00000 n 0000030354 00000 n 0000030236 00000 n 0000030074 00000 n 0000030216 00000 n 0000032078 00000 n 0000031959 00000 n 0000030423 00000 n 0000031937 00000 n 0000279880 00000 n 0000034276 00000 n 0000034157 00000 n 0000032254 00000 n 0000034135 00000 n 0000036652 00000 n 0000036532 00000 n 0000034441 00000 n 0000036510 00000 n 0000409183 00000 n 0000038971 00000 n 0000038851 00000 n 0000036828 00000 n 0000038829 00000 n 0000041063 00000 n 0000040943 00000 n 0000039099 00000 n 0000040921 00000 n 0000043733 00000 n 0000043613 00000 n 0000041250 00000 n 0000043591 00000 n 0000046651 00000 n 0000046531 00000 n 0000043898 00000 n 0000046509 00000 n 0000275642 00000 n 0000049738 00000 n 0000049618 00000 n 0000046852 00000 n 0000049596 00000 n 0000051856 00000 n 0000051736 00000 n 0000049928 00000 n 0000051714 00000 n 0000409300 00000 n 0000053649 00000 n 0000053529 00000 n 0000052033 00000 n 0000053507 00000 n 0000055353 00000 n 0000055233 00000 n 0000053814 00000 n 0000055211 00000 n 0000057378 00000 n 0000057258 00000 n 0000055468 00000 n 0000057236 00000 n 0000059806 00000 n 0000059686 00000 n 0000057460 00000 n 0000059664 00000 n 0000061887 00000 n 0000061767 00000 n 0000059923 00000 n 0000061745 00000 n 0000271946 00000 n 0000063990 00000 n 0000063870 00000 n 0000062052 00000 n 0000063848 00000 n 0000409417 00000 n 0000066197 00000 n 0000066077 00000 n 0000064118 00000 n 0000066055 00000 n 0000068868 00000 n 0000068748 00000 n 0000066348 00000 n 0000068726 00000 n 0000071304 00000 n 0000071184 00000 n 0000069043 00000 n 0000071162 00000 n 0000073466 00000 n 0000073346 00000 n 0000071467 00000 n 0000073324 00000 n 0000075384 00000 n 0000075264 00000 n 0000073617 00000 n 0000075242 00000 n 0000077855 00000 n 0000077735 00000 n 0000075559 00000 n 0000077713 00000 n 0000409534 00000 n 0000079900 00000 n 0000079780 00000 n 0000078031 00000 n 0000079758 00000 n 0000081936 00000 n 0000081816 00000 n 0000080052 00000 n 0000081794 00000 n 0000083358 00000 n 0000083238 00000 n 0000082099 00000 n 0000083216 00000 n 0000083993 00000 n 0000083873 00000 n 0000083475 00000 n 0000083852 00000 n 0000084357 00000 n 0000084237 00000 n 0000084075 00000 n 0000084217 00000 n 0000086065 00000 n 0000085945 00000 n 0000084427 00000 n 0000085923 00000 n 0000409651 00000 n 0000088377 00000 n 0000088257 00000 n 0000086193 00000 n 0000088235 00000 n 0000091212 00000 n 0000091092 00000 n 0000088541 00000 n 0000091070 00000 n 0000093928 00000 n 0000093808 00000 n 0000091400 00000 n 0000093786 00000 n 0000096959 00000 n 0000096839 00000 n 0000094118 00000 n 0000096817 00000 n 0000099485 00000 n 0000099365 00000 n 0000097123 00000 n 0000099343 00000 n 0000101573 00000 n 0000101453 00000 n 0000099660 00000 n 0000101431 00000 n 0000409768 00000 n 0000104175 00000 n 0000104055 00000 n 0000101737 00000 n 0000104033 00000 n 0000104894 00000 n 0000104774 00000 n 0000104350 00000 n 0000104753 00000 n 0000105269 00000 n 0000105149 00000 n 0000104987 00000 n 0000105129 00000 n 0000106860 00000 n 0000106740 00000 n 0000105339 00000 n 0000106718 00000 n 0000109242 00000 n 0000109122 00000 n 0000106999 00000 n 0000109100 00000 n 0000111416 00000 n 0000111296 00000 n 0000109383 00000 n 0000111274 00000 n 0000409885 00000 n 0000114013 00000 n 0000113893 00000 n 0000111591 00000 n 0000113871 00000 n 0000116734 00000 n 0000116614 00000 n 0000114203 00000 n 0000116592 00000 n 0000118110 00000 n 0000117990 00000 n 0000116921 00000 n 0000117969 00000 n 0000119725 00000 n 0000119605 00000 n 0000118285 00000 n 0000119583 00000 n 0000122292 00000 n 0000122172 00000 n 0000119876 00000 n 0000122150 00000 n 0000268942 00000 n 0000124350 00000 n 0000124230 00000 n 0000122516 00000 n 0000124208 00000 n 0000410002 00000 n 0000124784 00000 n 0000124664 00000 n 0000124502 00000 n 0000124644 00000 n 0000126476 00000 n 0000126356 00000 n 0000124854 00000 n 0000126334 00000 n 0000128841 00000 n 0000128721 00000 n 0000126663 00000 n 0000128699 00000 n 0000131053 00000 n 0000130933 00000 n 0000129006 00000 n 0000130911 00000 n 0000132197 00000 n 0000132077 00000 n 0000131195 00000 n 0000132056 00000 n 0000134074 00000 n 0000133954 00000 n 0000132279 00000 n 0000133932 00000 n 0000410119 00000 n 0000136138 00000 n 0000136018 00000 n 0000134250 00000 n 0000135996 00000 n 0000137107 00000 n 0000136987 00000 n 0000136292 00000 n 0000136966 00000 n 0000137519 00000 n 0000137399 00000 n 0000137237 00000 n 0000137379 00000 n 0000139691 00000 n 0000139571 00000 n 0000137589 00000 n 0000139549 00000 n 0000141647 00000 n 0000141527 00000 n 0000139855 00000 n 0000141505 00000 n 0000144368 00000 n 0000144248 00000 n 0000141799 00000 n 0000144226 00000 n 0000410236 00000 n 0000146153 00000 n 0000146033 00000 n 0000144496 00000 n 0000146011 00000 n 0000147962 00000 n 0000147842 00000 n 0000146247 00000 n 0000147820 00000 n 0000150059 00000 n 0000149939 00000 n 0000148148 00000 n 0000149917 00000 n 0000151701 00000 n 0000151581 00000 n 0000150199 00000 n 0000151559 00000 n 0000153934 00000 n 0000153814 00000 n 0000151818 00000 n 0000153792 00000 n 0000156487 00000 n 0000156367 00000 n 0000154086 00000 n 0000156345 00000 n 0000410353 00000 n 0000159009 00000 n 0000158889 00000 n 0000156651 00000 n 0000158867 00000 n 0000160728 00000 n 0000160608 00000 n 0000159162 00000 n 0000160586 00000 n 0000162885 00000 n 0000162765 00000 n 0000160822 00000 n 0000162743 00000 n 0000165195 00000 n 0000165075 00000 n 0000163037 00000 n 0000165053 00000 n 0000167630 00000 n 0000167510 00000 n 0000165349 00000 n 0000167488 00000 n 0000169722 00000 n 0000169602 00000 n 0000167793 00000 n 0000169580 00000 n 0000410470 00000 n 0000171648 00000 n 0000171528 00000 n 0000169863 00000 n 0000171506 00000 n 0000174010 00000 n 0000173890 00000 n 0000171788 00000 n 0000173868 00000 n 0000176483 00000 n 0000176363 00000 n 0000174174 00000 n 0000176341 00000 n 0000178348 00000 n 0000178228 00000 n 0000176659 00000 n 0000178206 00000 n 0000180967 00000 n 0000180847 00000 n 0000178537 00000 n 0000180825 00000 n 0000183871 00000 n 0000183751 00000 n 0000181120 00000 n 0000183729 00000 n 0000410587 00000 n 0000186405 00000 n 0000186285 00000 n 0000184047 00000 n 0000186263 00000 n 0000189241 00000 n 0000189121 00000 n 0000186571 00000 n 0000189099 00000 n 0000191814 00000 n 0000191694 00000 n 0000189418 00000 n 0000191672 00000 n 0000194709 00000 n 0000194589 00000 n 0000191967 00000 n 0000194567 00000 n 0000197674 00000 n 0000197554 00000 n 0000194884 00000 n 0000197532 00000 n 0000199792 00000 n 0000199672 00000 n 0000197839 00000 n 0000199650 00000 n 0000410704 00000 n 0000202324 00000 n 0000202204 00000 n 0000199955 00000 n 0000202182 00000 n 0000204071 00000 n 0000203951 00000 n 0000202489 00000 n 0000203929 00000 n 0000206542 00000 n 0000206422 00000 n 0000204212 00000 n 0000206400 00000 n 0000209115 00000 n 0000208995 00000 n 0000206718 00000 n 0000208973 00000 n 0000211055 00000 n 0000210935 00000 n 0000209301 00000 n 0000210913 00000 n 0000212633 00000 n 0000212513 00000 n 0000211160 00000 n 0000212491 00000 n 0000410821 00000 n 0000213045 00000 n 0000212925 00000 n 0000212762 00000 n 0000212905 00000 n 0000214414 00000 n 0000214294 00000 n 0000213115 00000 n 0000214272 00000 n 0000217166 00000 n 0000217046 00000 n 0000214566 00000 n 0000217024 00000 n 0000219390 00000 n 0000219270 00000 n 0000217343 00000 n 0000219248 00000 n 0000221661 00000 n 0000221541 00000 n 0000219553 00000 n 0000221519 00000 n 0000224441 00000 n 0000224321 00000 n 0000221825 00000 n 0000224299 00000 n 0000410938 00000 n 0000226371 00000 n 0000226251 00000 n 0000224629 00000 n 0000226229 00000 n 0000228047 00000 n 0000227927 00000 n 0000226546 00000 n 0000227905 00000 n 0000230114 00000 n 0000229994 00000 n 0000228163 00000 n 0000229972 00000 n 0000231792 00000 n 0000231672 00000 n 0000230243 00000 n 0000231650 00000 n 0000234338 00000 n 0000234218 00000 n 0000231978 00000 n 0000234196 00000 n 0000236631 00000 n 0000236511 00000 n 0000234502 00000 n 0000236489 00000 n 0000411055 00000 n 0000238588 00000 n 0000238468 00000 n 0000236795 00000 n 0000238446 00000 n 0000241319 00000 n 0000241199 00000 n 0000238717 00000 n 0000241177 00000 n 0000243487 00000 n 0000243367 00000 n 0000241506 00000 n 0000243345 00000 n 0000245578 00000 n 0000245458 00000 n 0000243592 00000 n 0000245436 00000 n 0000247626 00000 n 0000247506 00000 n 0000245707 00000 n 0000247484 00000 n 0000248660 00000 n 0000248540 00000 n 0000247754 00000 n 0000248519 00000 n 0000411172 00000 n 0000249025 00000 n 0000248905 00000 n 0000248742 00000 n 0000248885 00000 n 0000250754 00000 n 0000250634 00000 n 0000249095 00000 n 0000250612 00000 n 0000253633 00000 n 0000253513 00000 n 0000250929 00000 n 0000253491 00000 n 0000256440 00000 n 0000256320 00000 n 0000253810 00000 n 0000256298 00000 n 0000258701 00000 n 0000258581 00000 n 0000256581 00000 n 0000258559 00000 n 0000260584 00000 n 0000260464 00000 n 0000258865 00000 n 0000260442 00000 n 0000411289 00000 n 0000262653 00000 n 0000262533 00000 n 0000260724 00000 n 0000262511 00000 n 0000264684 00000 n 0000264564 00000 n 0000262805 00000 n 0000264542 00000 n 0000265821 00000 n 0000265701 00000 n 0000264790 00000 n 0000265680 00000 n 0000266887 00000 n 0000266767 00000 n 0000265914 00000 n 0000266746 00000 n 0000268837 00000 n 0000268717 00000 n 0000267003 00000 n 0000268695 00000 n 0000269078 00000 n 0000269631 00000 n 0000271635 00000 n 0000271657 00000 n 0000271678 00000 n 0000271699 00000 n 0000271720 00000 n 0000271751 00000 n 0000272082 00000 n 0000272626 00000 n 0000275324 00000 n 0000275346 00000 n 0000275367 00000 n 0000275389 00000 n 0000275410 00000 n 0000275441 00000 n 0000275778 00000 n 0000276324 00000 n 0000279562 00000 n 0000279584 00000 n 0000279605 00000 n 0000279627 00000 n 0000279648 00000 n 0000279679 00000 n 0000280016 00000 n 0000280580 00000 n 0000287858 00000 n 0000287880 00000 n 0000287902 00000 n 0000287924 00000 n 0000287945 00000 n 0000287977 00000 n 0000288762 00000 n 0000289306 00000 n 0000292298 00000 n 0000292320 00000 n 0000292341 00000 n 0000292363 00000 n 0000292384 00000 n 0000292414 00000 n 0000292758 00000 n 0000293303 00000 n 0000296292 00000 n 0000296314 00000 n 0000296335 00000 n 0000296357 00000 n 0000296378 00000 n 0000296409 00000 n 0000296787 00000 n 0000297323 00000 n 0000304151 00000 n 0000304173 00000 n 0000304195 00000 n 0000304217 00000 n 0000304238 00000 n 0000304268 00000 n 0000304708 00000 n 0000305249 00000 n 0000316758 00000 n 0000316781 00000 n 0000316803 00000 n 0000316825 00000 n 0000316846 00000 n 0000316877 00000 n 0000317318 00000 n 0000317851 00000 n 0000336717 00000 n 0000336740 00000 n 0000336762 00000 n 0000336785 00000 n 0000336806 00000 n 0000336838 00000 n 0000337383 00000 n 0000337916 00000 n 0000354165 00000 n 0000354188 00000 n 0000354210 00000 n 0000354233 00000 n 0000354254 00000 n 0000354286 00000 n 0000354975 00000 n 0000355519 00000 n 0000362319 00000 n 0000362341 00000 n 0000362363 00000 n 0000362385 00000 n 0000362406 00000 n 0000362438 00000 n 0000363023 00000 n 0000363557 00000 n 0000381114 00000 n 0000381137 00000 n 0000381159 00000 n 0000381182 00000 n 0000381203 00000 n 0000381234 00000 n 0000381907 00000 n 0000382441 00000 n 0000392399 00000 n 0000392421 00000 n 0000392443 00000 n 0000392465 00000 n 0000392486 00000 n 0000392518 00000 n 0000392950 00000 n 0000393488 00000 n 0000408183 00000 n 0000408206 00000 n 0000408228 00000 n 0000408251 00000 n 0000408272 00000 n 0000408304 00000 n 0000411406 00000 n 0000411519 00000 n 0000411637 00000 n 0000411755 00000 n 0000411865 00000 n 0000411952 00000 n 0000412005 00000 n trailer << /Size 709 /Root 707 0 R /Info 708 0 R >> startxref 412101 %%EOF ���������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ueigvec.pas�������������������������������������������������0000755�0001750�0001750�00000002166�11326425444�017630� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Eigenvalues and eigenvectors of a general square matrix ****************************************************************** } unit ueigvec; interface uses utypes, ubalance, uelmhes, ueltran, uhqr2, ubalbak; procedure EigenVect(A : PMatrix; Lb, Ub : Integer; Lambda : PCompVector; V : PMatrix); implementation procedure EigenVect(A : PMatrix; Lb, Ub : Integer; Lambda : PCompVector; V : PMatrix); var I_low, I_igh : Integer; Scale : PVector; I_Int : PIntVector; begin DimVector(Scale, Ub); DimIntVector(I_Int, Ub); Balance(A, Lb, Ub, I_low, I_igh, Scale); ElmHes(A, Lb, Ub, I_low, I_igh, I_int); Eltran(A, Lb, Ub, I_low, I_igh, I_int, V); Hqr2(A, Lb, Ub, I_low, I_igh, Lambda, V); if MathErr = 0 then BalBak(V, Lb, Ub, I_low, I_igh, Scale, Ub); DelVector(Scale, Ub); DelIntVector(I_Int, Ub); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/tpmath.txt��������������������������������������������������0000755�0001750�0001750�00000005176�11326425444�017536� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������****************************************************************************** * * * TPMATH * * * * MATHEMATICAL LIBRARY FOR PASCAL COMPILERS * * * * Version 0.50 (December 2007) * * * ****************************************************************************** AUTHOR : Dr Jean DEBORD Laboratoire de Pharmacologie, Faculte de Medecine 2 Rue du Docteur Marcland, 87025 Limoges (France) debord.jean@orange.fr jean.debord@unilim.fr ****************************************************************************** This library is distributed under the terms of the GNU Lesser General Public License (LGPL). See file LGPL.TXT for details. ****************************************************************************** INTRODUCTION ============ TPMath is a mathematical library for Pascal compilers. It is entirely written in Pascal and does not depend on external libraries. TPMath provides routines and demo programs for numerical analysis, including mathematical functions, probabilities, matrices, optimization, linear and nonlinear equations, integration, Fast Fourier Transform, random numbers, statistics and graphics. CONTENTS ======== Main directory -------------- TPMATH.TXT : This file LGPL.TXT : License TPMATH.PDF : Documentation of TPMath in PDF format DLL directory ------------- Source files of the library. UNITS directory --------------- Source files of individual units. DEMO directory -------------- Source of demo programs. SYSTEM REQUIREMENTS =================== * PC computer with Windows or Linux * Delphi (32 bits) or Free Pascal. * Should also work (with some restrictions) with Turbo Pascal, Delphi 16 bits or GNU Pascal INSTALLATION AND COMPILATION ============================ See the instructions in file TPMATH.PDF (chapter 1) WEB LINKS ========= TPMath web page: http://www.unilim.fr/pages_perso/jean.debord/tpmath/tpmath.htm SourceForge project page: http://sourceforge.net/projects/tpmath/ Mailing list: http://groups.yahoo.com/group/tpmathlib/ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ukhi2.pas���������������������������������������������������0000755�0001750�0001750�00000004760�11326425444�017225� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Khi-2 test ****************************************************************** } unit ukhi2; interface uses utypes; procedure Khi2_Conform(N_cls : Integer; N_estim : Integer; Obs : PIntVector; Calc : PVector; var Khi2 : Float; var DoF : Integer); { ------------------------------------------------------------------ Khi-2 test for conformity ------------------------------------------------------------------ } procedure Khi2_Indep(N_lin : Integer; N_col : Integer; Obs : PIntMatrix; var Khi2 : Float; var DoF : Integer); { ------------------------------------------------------------------ Khi-2 test for independence ------------------------------------------------------------------ } implementation procedure Khi2_Conform(N_cls : Integer; N_estim : Integer; Obs : PIntVector; Calc : PVector; var Khi2 : Float; var DoF : Integer); var I : Integer; begin Khi2 := 0.0; for I := 1 to N_cls do Khi2 := Khi2 + Sqr(Obs^[I] - Calc^[I]) / Calc^[I]; DoF := N_cls - N_estim - 1; end; procedure Khi2_Indep(N_lin : Integer; N_col : Integer; Obs : PIntMatrix; var Khi2 : Float; var DoF : Integer); var SumLin, SumCol : PIntVector; Sum : Integer; Prob, Calc : Float; I, J : Integer; begin DimIntVector(SumLin, N_lin); DimIntVector(SumCol, N_col); for I := 1 to N_lin do for J := 1 to N_col do SumLin^[I] := SumLin^[I] + Obs^[I]^[J]; for J := 1 to N_col do for I := 1 to N_lin do SumCol^[J] := SumCol^[J] + Obs^[I]^[J]; Sum := 0; for I := 1 to N_lin do Sum := Sum + SumLin^[I]; Khi2 := 0.0; for I := 1 to N_lin do begin Prob := SumLin^[I] / Sum; for J := 1 to N_col do begin Calc := SumCol^[J] * Prob; Khi2 := Khi2 + Sqr(Obs^[I]^[J] - Calc) / Calc; end; end; DoF := Pred(N_lin) * Pred(N_col); DelIntVector(SumLin, N_lin); DelIntVector(SumCol, N_col); end; end.����������������mricron-0.20140804.1~dfsg.1.orig/fpmath/udigamma.pas������������������������������������������������0000755�0001750�0001750�00000007522�11326425444�017766� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** DiGamma and TriGamma functions. Contributed by Philip Fletcher (FLETCHP@WESTAT.com) ****************************************************************** } unit udigamma; interface uses utypes; function DiGamma(X : Float ) : Float; function TriGamma(X : Float ) : Float; implementation function DiGamma(X : Float ) : Float; { ------------------------------------------------------------------ Digamma calculates the Digamma or Psi function = d ( LOG ( GAMMA ( X ) ) ) / dX Reference: J Bernardo, Psi ( Digamma ) Function, Algorithm AS 103, Applied Statistics, Volume 25, Number 3, pages 315-317, 1976. Modified: 03 January 2000 Parameters: Input, real X, the argument of the Digamma function. 0 < X. Output, real Digamma, the value of the Digamma function at X. ------------------------------------------------------------------ } const c = 20 ; d1 = -0.57721566490153286061; { DiGamma(1) } s = 0.00001 ; { Sterling coefficient S(n) = B(n) / 2n where B(n) = Bernoulli number } const S2 = 0.08333333333333333333 ; { B(2)/2 } S4 = -0.83333333333333333333E-2 ; { B(4)/4 } S6 = 0.39682539682539682541E-2 ; { B(6)/6 } S8 = -0.41666666666666666666E-2 ; { B(8)/8 } S10 = 0.75757575757575757576E-2 ; { B(10)/10 } S12 = -0.21092796092796092796E-1 ; { B(12)/12 } S14 = 0.83333333333333333335E-1 ; { B(14)/14 } S16 = -0.44325980392156862745 ; { B(16)/16 } var dg, p, r, y : Float ; begin if X <= 0.0 then begin DiGamma := DefaultVal(FSing, MaxNum); Exit; end; SetErrCode(FOk); if X = 1.0 then begin DiGamma := D1; Exit; end; { Use approximation if argument <= S } if X <= s then dg := d1 - 1.0 / x else { Reduce the argument to dg(X + N) where (X + N) >= C } begin dg := 0.0; y := x ; while y < c do begin dg := dg - 1.0 / y; y := y + 1.0; end ; { Use Stirling's (actually de Moivre's) expansion if argument > C } r := 1.0 / sqr ( y ) ; p := (((((((S16 * r + S14) * r + S12) * r + S10) * r + S8) * r + S6) * r + S4) * r + S2) * r ; dg := dg + ln ( y ) - 0.5 / y - p ; end ; DiGamma := dg ; end ; function TriGamma(X : Float) : Float; { ------------------------------------------------------------------ Trigamma calculates the Trigamma or Psi Prime function = d**2 ( LOG ( GAMMA ( X ) ) ) / dX**2 Reference: Algorithm As121 Appl. Statist. (1978) vol 27, no. 1 ******************************************************************** } const a = 1.0E-4 ; b = 20 ; zero = 0 ; one = 1 ; half = 0.5 ; { Bernoulli numbers } const B2 = 0.1666666666666667 ; B4 = -3.333333333333333E-002 ; B6 = 2.380952380952381E-002 ; B8 = -3.333333333333333E-002 ; B10 = 7.575757575757576E-002 ; B12 = -0.2531135531135531 ; var y, z, Res : Float ; begin if X <= 0.0 then begin TriGamma := DefaultVal(FSing, MaxNum); Exit; end; SetErrCode(FOk); Res := 0 ; z := x ; if z <= a then { Use small value approximation } begin TriGamma := one / sqr ( z ) ; Exit ; end ; while z < b do { Increase argument to (x+i) >= b } begin Res := Res + one / sqr ( z ) ; z := z + one ; end ; { Apply asymptotic formula where argument >= b } y := one / sqr ( z ) ; Res := Res + Half * y + (One + y * (B2 + y * (B4 + y * (B6 + y * (B8 + y* (B10 + y * B12)))))) / z; TriGamma := Res; end ; end.������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/umarq.pas���������������������������������������������������0000755�0001750�0001750�00000015201�11326425444�017320� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Minimization of a function of several variables by Marquardt's method ****************************************************************** } unit umarq; interface uses utypes, ugausjor, ulinmin, ucompvec; procedure SaveMarquardt(FileName : string); { ------------------------------------------------------------------ Save Marquardt iterations in a file ------------------------------------------------------------------ } procedure Marquardt(Func : TFuncNVar; HessGrad : THessGrad; X : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; G : PVector; H_inv : PMatrix; var Det : Float); { ------------------------------------------------------------------ Minimization of a function of several variables by Marquardt's method ------------------------------------------------------------------ Input parameters : Func = objective function HessGrad = procedure to compute hessian and gradient X = initial minimum coordinates Lb, Ub = indices of first and last variables MaxIter = maximum number of iterations Tol = required precision ------------------------------------------------------------------ Output parameters : X = refined minimum coordinates F_min = function value at minimum G = gradient vector H_inv = inverse hessian matrix Det = determinant of hessian ------------------------------------------------------------------ Possible results : OptOk = no error OptNonConv = non-convergence OptSing = singular hessian matrix OptBigLambda = too high Marquardt parameter Lambda ---------------------------------------------------------------------- } implementation const WriteLogFile : Boolean = False; var LogFile : Text; procedure SaveMarquardt(FileName : string); begin Assign(LogFile, FileName); Rewrite(LogFile); WriteLogFile := True; end; procedure Marquardt(Func : TFuncNVar; HessGrad : THessGrad; X : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; G : PVector; H_inv : PMatrix; var Det : Float); const Lambda0 = 1.0E-2; { Initial lambda value } LambdaMax = 1.0E+3; { Highest lambda value } FTol = 1.0E-10; { Tolerance on function decrease } var Ub1, I, J, Iter : Integer; F1, R : Float; OldX, DeltaX : PVector; A, H : PMatrix; Lambda : Float; LambdaOk : Boolean; procedure SolveSystem(Lambda : Float); { Solve the system of linear equations : H' * DeltaX = -G where H' is the modified hessian matrix (diagonal terms multiplied by (1 + Lambda)), and G is the gradient vector, for a given value of Marquardt's Lambda parameter. The whole system is stored in a matrix A = [H'|G] which is transformed by the Gauss-jordan method. The inverse hessian matrix H_inv is then retrieved from the transformed matrix. } var Lambda1 : Float; I, J : Integer; begin if Lambda > 0.0 then begin Lambda1 := 1.0 + Lambda; for I := Lb to Ub do A^[I]^[I] := Lambda1 * H^[I]^[I]; end; GaussJordan(A, Lb, Ub, Ub1, Det); if MathErr = MatOk then for I := Lb to Ub do for J := Lb to Ub do H_inv^[I]^[J] := A^[I]^[J]; end; procedure Terminate(ErrCode : Integer); { Set error code and deallocate arrays } begin DelVector(OldX, Ub); DelVector(DeltaX, Ub); DelMatrix(A, Ub, Ub1); DelMatrix(H, Ub, Ub); SetErrCode(ErrCode); if WriteLogFile then Close(LogFile); end; begin Ub1 := Ub + 1; DimVector(OldX, Ub); DimVector(DeltaX, Ub); DimMatrix(A, Ub, Ub1); DimMatrix(H, Ub, Ub); if WriteLogFile then begin WriteLn(LogFile, 'Marquardt'); WriteLn(LogFile, 'Iter F Lambda'); end; Iter := 0; Lambda := Lambda0; F_min := Func(X); repeat if WriteLogFile then WriteLn(LogFile, Iter:4, ' ', F_min:12, ' ', Lambda:12); { Save old parameters } for I := Lb to Ub do OldX^[I] := X^[I]; { Compute Gradient and Hessian } HessGrad(X, G, H); for I := Lb to Ub do begin for J := Lb to Ub do A^[I]^[J] := H^[I]^[J]; A^[I]^[Ub1] := - G^[I]; end; if MaxIter < 1 then begin SolveSystem(0.0); if MathErr = MatOk then Terminate(OptOk) else Terminate(OptSing); Exit; end; { Prepare next iteration } Iter := Iter + 1; if Iter > MaxIter then begin Terminate(OptNonConv); Exit; end; repeat SolveSystem(Lambda); if MathErr <> MatOk then begin Terminate(OptSing); Exit; end; { Initialize parameters and search direction } for I := Lb to Ub do begin X^[I] := OldX^[I]; DeltaX^[I] := A^[I]^[Ub1]; end; { Minimize along the direction specified by DeltaX } { using an initial step of 0.1 * |DeltaX| } R := 0.1; LinMin(Func, X, DeltaX, Lb, Ub, R, 10, 0.01, F1); { Check that the function has decreased, otherwise } { increase Lambda, without exceeding LambdaMax } LambdaOk := (F1 - F_min) < F_min * FTol; if not LambdaOk then Lambda := 10.0 * Lambda; if Lambda > LambdaMax then begin Terminate(OptBigLambda); Exit; end; until LambdaOk; Lambda := 0.1 * Lambda; F_min := F1; until CompVec(X, OldX, Lb, Ub, Tol); Terminate(OptOk); end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/urtpol2.pas�������������������������������������������������0000755�0001750�0001750�00000003674�11326425446�017617� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Quadratic equation ****************************************************************** } unit urtpol2; interface uses utypes, urtpol1; function RootPol2(Coef : PVector; Z : PCompVector) : Integer; { ------------------------------------------------------------------ Solves the quadratic equation: Coef^[0] + Coef^[1] * X + Coef^[2] * X^2 = 0 ------------------------------------------------------------------ } implementation function RootPol2(Coef : PVector; Z : PCompVector) : Integer; var Delta, F, Q : Float; begin Z^[1].X := 0.0; Z^[1].Y := 0.0; Z^[2].X := 0.0; Z^[2].Y := 0.0; if Coef^[2] = 0.0 then begin RootPol2 := RootPol1(Coef^[0], Coef^[1], Z^[1].X); Exit; end; if Coef^[0] = 0.0 then begin { 0 is root. Eq. becomes linear } if RootPol1(Coef^[1], Coef^[2], Z^[1].X) = 1 then { Linear eq. has 1 solution } RootPol2 := 2 else { Linear eq. is undetermined or impossible } RootPol2 := 1; Exit; end; Delta := Sqr(Coef^[1]) - 4.0 * Coef^[0] * Coef^[2]; { 2 real roots } if Delta > 0.0 then begin RootPol2 := 2; { Algorithm for minimizing roundoff errors } { See `Numerical Recipes' } if Coef^[1] >= 0.0 then Q := - 0.5 * (Coef^[1] + Sqrt(Delta)) else Q := - 0.5 * (Coef^[1] - Sqrt(Delta)); Z^[1].X := Q / Coef^[2]; Z^[2].X := Coef^[0] / Q; Exit; end; { Double real root } if Delta = 0.0 then begin RootPol2 := 2; Z^[1].X := - 0.5 * Coef^[1] / Coef^[2]; Z^[2].X := Z^[1].X; Exit; end; { 2 complex roots } RootPol2 := 0; F := 0.5 / Coef^[2]; Z^[1].X := - F * Coef^[1]; Z^[1].Y := Abs(F) * Sqrt(- Delta); Z^[2].X := Z^[1].X; Z^[2].Y := - Z^[1].Y; end; end. ��������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/urtpol3.pas�������������������������������������������������0000755�0001750�0001750�00000005076�11326425446�017616� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Cubic equation ****************************************************************** } unit urtpol3; interface uses utypes, urtpol2; function RootPol3(Coef : PVector; Z : PCompVector) : Integer; { ------------------------------------------------------------------ Solves the cubic equation: Coef^[0] + Coef^[1] * X + Coef^[2] * X^2 + Coef^[3] * X^3 = 0 ------------------------------------------------------------------ } implementation function RootPol3(Coef : PVector; Z : PCompVector) : Integer; const OneThird = 0.333333333333333333; { 1 / 3 } TwoPiDiv3 = 2.09439510239319549; { 2 Pi / 3 } Sqrt3Div2 = 0.866025403784438647; { Sqrt(3) / 2 } var A, AA, B, C : Float; Q, QQQ, R, RR : Float; S, T, U : Float; I : Integer; Cf : PVector; begin for I := 1 to 3 do begin Z^[I].X := 0.0; Z^[I].Y := 0.0; end; if Coef^[3] = 0.0 then begin RootPol3 := RootPol2(Coef, Z); Exit; end; if Coef^[0] = 0.0 then begin DimVector(Cf, 2); { 0 is root. Equation becomes quadratic } Cf^[0] := Coef^[1]; Cf^[1] := Coef^[2]; Cf^[2] := Coef^[3]; { Solve quadratic equation } RootPol3 := RootPol2(Cf, Z) + 1; DelVector(Cf, 2); Exit; end; if Coef^[3] = 1.0 then begin A := Coef^[2] * OneThird; B := Coef^[1]; C := Coef^[0]; end else begin A := Coef^[2] / Coef^[3] * OneThird; B := Coef^[1] / Coef^[3]; C := Coef^[0] / Coef^[3]; end; AA := A * A; Q := AA - OneThird * B; R := A * (AA - 0.5 * B) + 0.5 * C; RR := Sqr(R); QQQ := Q * Sqr(Q); if RR < QQQ then { 3 real roots } begin RootPol3 := 3; S := Sqrt(Q); T := R / (Q * S); T := PiDiv2 - ArcTan(T / Sqrt(1.0 - T * T)); { ArcCos(T) } T := OneThird * T; S := - 2.0 * S; Z^[1].X := S * Cos(T) - A; Z^[2].X := S * Cos(T + TwoPiDiv3) - A; Z^[3].X := S * Cos(T - TwoPiDiv3) - A; end else { 1 real root } begin RootPol3 := 1; S := Abs(R) + Sqrt(RR - QQQ); if S > 0.0 then S := Exp(OneThird * Ln(S)); if R > 0.0 then S := - S; if S = 0.0 then T := 0.0 else T := Q / S; U := S + T; Z^[1].X := U - A; { Real root } Z^[2].X := - 0.5 * U - A; Z^[2].Y := Sqrt3Div2 * Abs(S - T); Z^[3].X := Z^[2].X; Z^[3].Y := - Z^[2].Y; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uhqr.pas����������������������������������������������������0000755�0001750�0001750�00000016401�11326425444�017155� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Eigenvalues of a real upper Hessenberg matrix by the QR method ****************************************************************** } unit uhqr; interface uses utypes, uminmax; procedure Hqr(H : PMatrix; Lb, Ub, I_low, I_igh : Integer; Lambda : PCompVector); implementation procedure Hqr(H : PMatrix; Lb, Ub, I_low, I_igh : Integer; Lambda : PCompVector); { ------------------------------------------------------------------ This function is a translation of the EISPACK subroutine hqr. This function finds the eigenvalues of a real upper Hessenberg matrix by the QR method. On input: H contains the upper Hessenberg matrix. Lb, Ub are the lowest and highest indices of the elements of H I_low and I_igh are integers determined by the balancing subroutine Balance. If Balance has not been used, set I_low = Lb, I_igh = Ub On output: H has been destroyed. Wr and Wi contain the real and imaginary parts, respectively, of the eigenvalues. The eigenvalues are unordered except that complex conjugate pairs of values appear consecutively with the eigenvalue having the positive imaginary part first. The function returns an error code: zero for normal return, -j if the limit of 30*N iterations is exhausted while the j-th eigenvalue is being sought. (N being the size of the matrix). The eigenvalues should be correct for indices j+1,...,Ub. ------------------------------------------------------------------ Note: This is a crude translation. Many of the original goto's have been kept ! ------------------------------------------------------------------ } var I, J, K, L, M, N, En, Na, Itn, Its, Mp2, Enm2 : Integer; P, Q, R, S, T, W, X, Y, Z, Norm, Tst1, Tst2 : Float; NotLas : Boolean; label 60, 70, 100, 130, 150, 170, 225, 260, 270, 280, 320, 330; begin { Store roots isolated by Balance and compute matrix norm } K := Lb; Norm := 0.0; for I := Lb to Ub do begin for J := K to Ub do Norm := Norm + Abs(H^[I]^[J]); K := I; if (I < I_low) or (I > I_igh) then begin Lambda^[I].X := H^[I]^[I]; Lambda^[I].Y := 0.0; end; end; N := Ub - Lb + 1; Itn := 30 * N; En := I_igh; T := 0.0; 60: { Search for next eigenvalues } if En < I_low then begin SetErrCode(0); Exit; end; Its := 0; Na := En - 1; Enm2 := Na - 1; 70: { Look for single small sub-diagonal element } for L := En downto I_low do begin if L = I_low then goto 100; S := Abs(H^[L - 1]^[L - 1]) + Abs(H^[L]^[L]); if S = 0.0 then S := Norm; Tst1 := S; Tst2 := Tst1 + Abs(H^[L]^[L - 1]); if Tst2 = Tst1 then goto 100; end; 100: { Form shift } X := H^[En]^[En]; if L = En then goto 270; Y := H^[Na]^[Na]; W := H^[En]^[Na] * H^[Na]^[En]; if L = Na then goto 280; if Itn = 0 then begin { Set error -- all eigenvalues have not converged after 30*N iterations } SetErrCode(- En); Exit; end; if (Its <> 10) and (Its <> 20) then goto 130; { Form exceptional shift } T := T + X; for I := I_low to En do H^[I]^[I] := H^[I]^[I] - X; S := Abs(H^[En]^[Na]) + Abs(H^[Na]^[Enm2]); X := 0.75 * S; Y := X; W := - 0.4375 * S * S; 130: Its := Its + 1; Itn := Itn - 1; { Look for two consecutive small sub-diagonal elements } for M := Enm2 downto L do begin Z := H^[M]^[M]; R := X - Z; S := Y - Z; P := (R * S - W) / H^[M + 1]^[M] + H^[M]^[M + 1]; Q := H^[M + 1]^[M + 1] - Z - R - S; R := H^[M + 2]^[M + 1]; S := Abs(P) + Abs(Q) + Abs(R); P := P / S; Q := Q / S; R := R / S; if M = L then goto 150; Tst1 := Abs(P) * (Abs(H^[M - 1]^[M - 1]) + Abs(Z) + Abs(H^[M + 1]^[M + 1])); Tst2 := Tst1 + Abs(H^[M]^[M - 1]) * (Abs(Q) + Abs(R)); if Tst2 = Tst1 then goto 150; end; 150: Mp2 := M + 2; for I := Mp2 to En do begin H^[I]^[I - 2] := 0.0; if I <> Mp2 then H^[I]^[I - 3] := 0.0; end; { Double QR step involving rows L to En and columns M to En } for K := M to Na do begin NotLas := (K <> Na); if (K = M) then goto 170; P := H^[K]^[K - 1]; Q := H^[K + 1]^[K - 1]; R := 0.0; if NotLas then R := H^[K + 2]^[K - 1]; X := Abs(P) + Abs(Q) + Abs(R); if X = 0.0 then goto 260; P := P / X; Q := Q / X; R := R / X; 170: S := DSgn(Sqrt(P * P + Q * Q + R * R), P); if K <> M then H^[K]^[K - 1] := - S * X else if L <> M then H^[K]^[K - 1] := - H^[K]^[K - 1]; P := P + S; X := P / S; Y := Q / S; Z := R / S; Q := Q / P; R := R / P; if NotLas then goto 225; { Row modification } for J := K to En do begin P := H^[K]^[J] + Q * H^[K + 1]^[J]; H^[K]^[J] := H^[K]^[J] - P * X; H^[K + 1]^[J] := H^[K + 1]^[J] - P * Y; end; J := Imin(En, K + 3); { Column modification } for I := L to J do begin P := X * H^[I]^[K] + Y * H^[I]^[K + 1]; H^[I]^[K] := H^[I]^[K] - P; H^[I]^[K + 1] := H^[I]^[K + 1] - P * Q; end; goto 260; 225: { Row modification } for J := K to En do begin P := H^[K]^[J] + Q * H^[K + 1]^[J] + R * H^[K + 2]^[J]; H^[K]^[J] := H^[K]^[J] - P * X; H^[K + 1]^[J] := H^[K + 1]^[J] - P * Y; H^[K + 2]^[J] := H^[K + 2]^[J] - P * Z; end; J := Imin(En, K + 3); { Column modification } for I := L to J do begin P := X * H^[I]^[K] + Y * H^[I]^[K + 1] + Z * H^[I]^[K + 2]; H^[I]^[K] := H^[I]^[K] - P; H^[I]^[K + 1] := H^[I]^[K + 1] - P * Q; H^[I]^[K + 2] := H^[I]^[K + 2] - P * R; end; 260: end; goto 70; 270: { One root found } Lambda^[En].X := X + T; Lambda^[En].Y := 0.0; En := Na; goto 60; 280: { Two roots found } P := 0.5 * (Y - X); Q := P * P + W; Z := Sqrt(Abs(Q)); X := X + T; if Q < 0.0 then goto 320; { Real pair } Z := P + DSgn(Z, P); Lambda^[Na].X := X + Z; Lambda^[En].X := Lambda^[Na].X; if Z <> 0.0 then Lambda^[En].X := X - W / Z; Lambda^[Na].Y := 0.0; Lambda^[En].Y := 0.0; goto 330; 320: { Complex pair } Lambda^[Na].X := X + P; Lambda^[En].X := X + P; Lambda^[Na].Y := Z; Lambda^[En].Y := - Z; 330: En := Enm2; goto 60; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ustudind.pas������������������������������������������������0000755�0001750�0001750�00000003002�11326425446�020030� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Student t-test for independent samples ****************************************************************** } unit ustudind; interface uses utypes; procedure StudIndep(N1, N2 : Integer; M1, M2, S1, S2 : Float; var T : Float; var DoF : Integer); { ------------------------------------------------------------------ Student t-test for independent samples ------------------------------------------------------------------ Input parameters : N1, N2 = samples sizes M1, M2 = samples means S1, S2 = samples SD's (computed with StDev) Output parameters: T = Student's t DoF = degrees of freedom ------------------------------------------------------------------ } implementation procedure StudIndep(N1, N2 : Integer; M1, M2, S1, S2 : Float; var T : Float; var DoF : Integer); var V1, V2 : Float; { Sample variances } VarCom : Float; { Estimate of common variance } begin V1 := Sqr(S1); V2 := Sqr(S2); DoF := N1 + N2 - 2; if (N1 >= 30) and (N2 >= 30) then T := (M1 - M2) / Sqrt(V1 / N1 + V2 / N2) else begin VarCom := ((N1 - 1) * V1 + (N2 - 1) * V2) / DoF; T := (M1 - M2) / Sqrt(VarCom / N1 + VarCom / N2); end; end; end.������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/umath.pas���������������������������������������������������0000755�0001750�0001750�00000012457�11326425444�017323� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Logarithms, exponentials and power ****************************************************************** } unit umath; interface uses utypes, uminmax; function Expo(X : Float) : Float; { Exponential } function Exp2(X : Float) : Float; { 2^X } function Exp10(X : Float) : Float; { 10^X } function Log(X : Float) : Float; { Natural log } function Log2(X : Float) : Float; { Log, base 2 } function Log10(X : Float) : Float; { Decimal log } function LogA(X, A : Float) : Float; { Log, base A } function IntPower(X : Float; N : Integer) : Float; { X^N } function Power(X, Y : Float) : Float; { X^Y, X >= 0 } implementation function Expo(X : Float) : Float; begin SetErrCode(FOk); if X < MinLog then Expo := DefaultVal(FUnderflow, 0.0) else if X > MaxLog then Expo := DefaultVal(FOverflow, MaxNum) else Expo := Exp(X); end; function Exp2(X : Float) : Float; var XLn2 : Float; begin SetErrCode(FOk); XLn2 := X * Ln2; if XLn2 < MinLog then Exp2 := DefaultVal(FUnderflow, 0.0) else if XLn2 > MaxLog then Exp2 := DefaultVal(FOverflow, MaxNum) else Exp2 := Exp(XLn2); end; function Exp10(X : Float) : Float; var XLn10 : Float; begin SetErrCode(FOk); XLn10 := X * Ln10; if XLn10 < MinLog then Exp10 := DefaultVal(FUnderflow, 0.0) else if XLn10 > MaxLog then Exp10 := DefaultVal(FOverflow, MaxNum) else Exp10 := Exp(XLn10); end; function Log(X : Float) : Float; begin SetErrCode(FOk); if X < 0.0 then Log := DefaultVal(FDomain, - MaxNum) else if X = 0.0 then Log := DefaultVal(FSing, - MaxNum) else Log := Ln(X); end; function Log10(X : Float) : Float; begin SetErrCode(FOk); if X < 0.0 then Log10 := DefaultVal(FDomain, - MaxNum) else if X = 0.0 then Log10 := DefaultVal(FSing, - MaxNum) else Log10 := Ln(X) * InvLn10; end; function Log2(X : Float) : Float; begin SetErrCode(FOk); if X < 0.0 then Log2 := DefaultVal(FDomain, - MaxNum) else if X = 0.0 then Log2 := DefaultVal(FSing, - MaxNum) else Log2 := Ln(X) * InvLn2; end; function LogA(X, A : Float) : Float; var Y : Float; begin Y := Log(X); if MathErr = FOk then if A = 1.0 then Y := DefaultVal(FSing, Sgn(Y) * MaxNum) else Y := Y / Log(A); LogA := Y; end; { ---------------------------------------------------------------------- Power functions. Thanks to Volker Walter <vw@metrohm.ch> for suggesting improvements to Power and IntPower ---------------------------------------------------------------------- } function PowerTests(X, Y : Float; var Res : Float) : Boolean; { Tests the cases X=0, Y=0 and Y=1. Returns X^Y in Res } begin if X = 0.0 then begin PowerTests := True; if Y = 0.0 then { 0^0 = lim X^X = 1 } Res := 1.0 { X->0 } else if Y > 0.0 then Res := 0.0 { 0^Y = 0 } else Res := DefaultVal(FSing, MaxNum); end else if Y = 0.0 then begin Res := 1.0; { X^0 = 1 } PowerTests := True; end else if Y = 1.0 then begin Res := X; { X^1 = X } PowerTests := True; end else PowerTests := False; end; function IntPower(X : Float; N : Integer) : Float; { Computes X^N by repeated multiplications } const InverseMaxNum = 1.0 / MaxNum; var T : Float; M : Integer; Invert : Boolean; begin if PowerTests(X, N, T) then begin IntPower := T; Exit; end; Invert := (N < 0); { Test if inverting is needed } if 1.0 < Abs(X) then { Test for 0 ..|x| .. 1 } begin X := 1.0 / X; Invert := not Invert; end; { Legendre's algorithm for minimizing the number of multiplications } T := 1.0; M := Abs(N); while 0 < M do begin if Odd(M) then T := T * X; X := Sqr(X); M := M div 2; end; if Invert then if Abs(T) < InverseMaxNum then { Only here overflow } T := DefaultVal(FOverflow, Sgn(T) * MaxNum) else T := 1.0 / T; IntPower := T; end; function Power(X, Y : Float) : Float; { Computes X^Y = Exp(Y * Ln(X)), for X > 0 Resorts to IntPower if Y is integer } var Res : Float; YLnX : Float; begin if PowerTests(X, Y, Res) then Power := Res else if (Abs(Y) < MaxInt) and (Trunc(Y) = Y) then { Integer exponent } Power := IntPower(X, Trunc(Y)) else if X <= 0.0 then Power := DefaultVal(FDomain, 0.0) else begin YLnX := Y * Ln(X); if YLnX < MinLog then Power := DefaultVal(FUnderflow, 0.0) else if YLnX > MaxLog then Power := DefaultVal(FOverflow, MaxNum) else Power := Exp(YLnX); end; end; end.�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/umeansd.pas�������������������������������������������������0000755�0001750�0001750�00000003220�11326425444�017625� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Mean and standard deviations ****************************************************************** } unit umeansd; interface uses utypes; function Mean(X : PVector; Lb, Ub : Integer) : Float; { Mean of sample X } function StDev(X : PVector; Lb, Ub : Integer; M : Float) : Float; { Standard deviation estimated from sample X } function StDevP(X : PVector; Lb, Ub : Integer; M : Float) : Float; { Standard deviation of population } implementation function Mean(X : PVector; Lb, Ub : Integer) : Float; var SX : Float; I : Integer; begin SX := 0.0; for I := Lb to Ub do SX := SX + X^[I]; Mean := SX / (Ub - Lb + 1); end; function StDev(X : PVector; Lb, Ub : Integer; M : Float) : Float; var D, SD, SD2, V : Float; I, N : Integer; begin N := Ub - Lb + 1; SD := 0.0; { Sum of deviations (used to reduce roundoff error) } SD2 := 0.0; { Sum of squared deviations } for I := Lb to Ub do begin D := X^[I] - M; SD := SD + D; SD2 := SD2 + Sqr(D) end; V := (SD2 - Sqr(SD) / N) / (N - 1); { Variance } StDev := Sqrt(V); end; function StDevP(X : PVector; Lb, Ub : Integer; M : Float) : Float; var D, SD, SD2, V : Float; I, N : Integer; begin N := Ub - Lb + 1; SD := 0.0; { Sum of deviations (used to reduce roundoff error) } SD2 := 0.0; { Sum of squared deviations } for I := Lb to Ub do begin D := X^[I] - M; SD := SD + D; SD2 := SD2 + Sqr(D) end; V := (SD2 - Sqr(SD) / N) / N; { Variance } StDevP := Sqrt(V); end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/unewteq.pas�������������������������������������������������0000755�0001750�0001750�00000004451�11326425446�017672� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Newton-Raphson solver for nonlinear equation ****************************************************************** } unit unewteq; interface uses utypes; procedure NewtEq (Func, Deriv : TFunc; var X : Float; MaxIter : Integer; Tol : Float; var F : Float); { ------------------------------------------------------------------ Solves a nonlinear equation by Newton's method ------------------------------------------------------------------ Input parameters : Func = function to be solved Deriv = derivative X = initial root MaxIter = maximum number of iterations Tol = required precision ------------------------------------------------------------------ Output parameters : X = refined root F = function value ------------------------------------------------------------------ Possible results : OptOk = no error OptNonConv = non-convergence OptSing = singularity (null derivative) ------------------------------------------------------------------ } implementation procedure NewtEq (Func, Deriv : TFunc; var X : Float; MaxIter : Integer; Tol : Float; var F : Float); var Iter : Integer; { Iteration count } OldX : Float; { Old root } D : Float; { Derivative } Xtol : Float; { Tolerance } begin Iter := 0; SetErrCode(OptOk); F := Func(X); if MaxIter < 1 then Exit; repeat { Compute derivative } D := Deriv(X); if D = 0.0 then begin SetErrCode(OptSing); Exit; end; { Prepare next iteration } Iter := Iter + 1; if Iter > MaxIter then begin SetErrCode(OptNonConv); Exit; end; { Save current root and compute new one } OldX := X; X := X - F / D; F := Func(X); Xtol := Tol * Abs(X); if Xtol < MachEp then Xtol := MachEp; until Abs(OldX - X) < Xtol; end; end.�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ufact.pas���������������������������������������������������0000755�0001750�0001750�00000002772�11326425444�017306� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Factorial ****************************************************************** } unit ufact; interface uses utypes, ugamma; function Fact(N : Integer) : Float; implementation const NFact = 33; FactArray : array[0..NFact] of Float = (1.0, 1.0, 2.0, 6.0, 24.0, 120.0, 720.0, 5040.0, 40320.0, 362880.0, 3628800.0, 39916800.0, 479001600.0, 6227020800.0, 87178291200.0, 1307674368000.0, 20922789888000.0, 355687428096000.0, 6402373705728000.0, 121645100408832000.0, 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0, 25852016738884976640000.0, 620448401733239439360000.0, 15511210043330985984000000.0, 403291461126605635584000000.0, 10888869450418352160768000000.0, 304888344611713860501504000000.0, 8841761993739701954543616000000.0, 265252859812191058636308480000000.0, 8222838654177922817725562880000000.0, 263130836933693530167218012160000000.0, 8683317618811886495518194401280000000.0); function Fact(N : Integer) : Float; begin SetErrCode(FOk); if N < 0 then Fact := DefaultVal(FDomain, 1.0) else if N > MaxFac then Fact := DefaultVal(FOverflow, MaxNum) else if N <= NFact then Fact := FactArray[N] else Fact := Gamma(N + 1); end; end.������mricron-0.20140804.1~dfsg.1.orig/fpmath/usimplex.pas������������������������������������������������0000755�0001750�0001750�00000015415�11326425446�020052� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Function minimization by the simplex method ****************************************************************** } unit usimplex; interface uses utypes; procedure SaveSimplex(FileName : string); { ------------------------------------------------------------------ Opens a file to save the Simplex iterations ------------------------------------------------------------------ } procedure Simplex(Func : TFuncNVar; X : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; var F_min : Float); { ------------------------------------------------------------------ Minimization of a function of several variables by the simplex method of Nelder and Mead ------------------------------------------------------------------ Input parameters : Func = objective function X = initial minimum coordinates Lbound, Ubound = indices of first and last variables MaxIter = maximum number of iterations Tol = required precision ------------------------------------------------------------------ Output parameters : X = refined minimum coordinates F_min = function value at minimum ------------------------------------------------------------------ The function MathErr returns one of the following codes: OptOk = no error OptNonConv = non-convergence ------------------------------------------------------------------ } implementation const WriteLogFile : Boolean = False; var LogFile : Text; procedure SaveSimplex(FileName : string); begin Assign(LogFile, FileName); Rewrite(LogFile); WriteLogFile := True; end; procedure Simplex(Func : TFuncNVar; X : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; var F_min : Float); const Step = 1.50; { Step used to construct the initial simplex } var P : PMatrix; { Simplex coordinates } F : PVector; { Function values } Pbar : PVector; { Centroid coordinates } Pstar, P2star : PVector; { New vertices } Ystar, Y2star : Float; { New function values } F0 : Float; { Function value at minimum } N : Integer; { Number of parameters } M : Integer; { Index of last vertex } L, H : Integer; { Vertices with lowest & highest F values } I, J : Integer; { Loop variables } Iter : Integer; { Iteration count } Corr, MaxCorr : Float; { Corrections } Sum : Float; Flag : Boolean; procedure UpdateSimplex(Y : Float; Q : PVector); { Update "worst" vertex and function value } var J : Integer; begin F^[H] := Y; for J := Lb to Ub do P^[H]^[J] := Q^[J]; end; begin { Quit if no iteration required } if MaxIter < 1 then begin F_min := Func(X); SetErrCode(OptOk); Exit; end; if WriteLogFile then begin WriteLn(LogFile, 'Simplex'); WriteLn(LogFile, 'Iter F'); end; N := Ub - Lb + 1; M := Ub + 1; DimMatrix(P, M, Ub); DimVector(F, M); DimVector(Pbar, Ub); DimVector(Pstar, Ub); DimVector(P2star, Ub); Iter := 1; F0 := MaxNum; { Construct initial simplex } for I := Lb to M do for J := Lb to Ub do P^[I]^[J] := X^[J]; for I := Lb to Ub do P^[I]^[I] := P^[I]^[I] * Step; { Evaluate function at each vertex } for I := Lb to M do F^[I] := Func(P^[I]); repeat { Find vertices (L,H) having the lowest and highest function values, i.e. "best" and "worst" vertices } L := Lb; H := Lb; for I := Lb + 1 to M do if F^[I] < F^[L] then L := I else if F^[I] > F^[H] then H := I; if F^[L] < F0 then F0 := F^[L]; if WriteLogFile then WriteLn(LogFile, Iter:4, ' ', F0:12); { Find centroid of points other than P(H) } for J := Lb to Ub do begin Sum := 0.0; for I := Lb to M do if I <> H then Sum := Sum + P^[I]^[J]; Pbar^[J] := Sum / N; end; { Reflect worst vertex through centroid } for J := Lb to Ub do Pstar^[J] := 2.0 * Pbar^[J] - P^[H]^[J]; Ystar := Func(Pstar); { If reflection successful, try extension } if Ystar < F^[L] then begin for J := Lb to Ub do P2star^[J] := 3.0 * Pstar^[J] - 2.0 * Pbar^[J]; Y2star := Func(P2star); { Retain extension or contraction } if Y2star < F^[L] then UpdateSimplex(Y2star, P2star) else UpdateSimplex(Ystar, Pstar); end else begin I := Lb; Flag := False; repeat if (I <> H) and (F^[I] > Ystar) then Flag := True; Inc(I); until Flag or (I > M); if Flag then UpdateSimplex(Ystar, Pstar) else begin { Contraction on the reflection side of the centroid } if Ystar <= F^[H] then UpdateSimplex(Ystar, Pstar); { Contraction on the opposite side of the centroid } for J := Lb to Ub do P2star^[J] := 0.5 * (P^[H]^[J] + Pbar^[J]); Y2star := Func(P2star); if Y2star <= F^[H] then UpdateSimplex(Y2star, P2star) else { Contract whole simplex } for I := Lb to M do for J := Lb to Ub do P^[I]^[J] := 0.5 * (P^[I]^[J] + P^[L]^[J]); end; end; { Test convergence } MaxCorr := 0.0; for J := Lb to Ub do begin Corr := Abs(P^[H]^[J] - P^[L]^[J]); if Corr > MaxCorr then MaxCorr := Corr; end; Inc(Iter); until (MaxCorr < Tol) or (Iter > MaxIter); for J := Lb to Ub do X^[J] := P^[L]^[J]; F_min := F^[L]; DelMatrix(P, M, Ub); DelVector(F, M); DelVector(Pbar, Ub); DelVector(Pstar, Ub); DelVector(P2star, Ub); if WriteLogFile then Close(LogFile); if Iter > MaxIter then SetErrCode(OptNonConv) else SetErrCode(OptOk); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ugamma.pas��������������������������������������������������0000755�0001750�0001750�00000020775�11326425444�017456� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Gamma function and related functions. Translated from C code in Cephes library (http://www.moshier.net) ****************************************************************** } unit ugamma; interface uses utypes, upolev; function SgnGamma(X : Float) : Integer; { Sign of Gamma function } function Stirling(X : Float) : Float; { Stirling's formula for the Gamma function } function StirLog(X : Float) : Float; { Approximate Ln(Gamma) by Stirling's formula, for X >= 13 } function Gamma(X : Float) : Float; { Gamma function } function LnGamma(X : Float) : Float; { Logarithm of Gamma function } implementation function SgnGamma(X : Float) : Integer; begin if X > 0.0 then SgnGamma := 1 else if Odd(Trunc(Abs(X))) then SgnGamma := 1 else SgnGamma := - 1; end; function Stirling(X : Float) : Float; { Stirling's formula for the gamma function Gamma(x) = Sqrt(2*Pi) x^(x-.5) exp(-x) (1 + 1/x P(1/x)) where P(x) is a polynomial } const STIR : TabCoef = ( 7.147391378143610789273E-4, - 2.363848809501759061727E-5, - 5.950237554056330156018E-4, 6.989332260623193171870E-5, 7.840334842744753003862E-4, - 2.294719747873185405699E-4, - 2.681327161876304418288E-3, 3.472222222230075327854E-3, 8.333333333333331800504E-2, 0); var W, P : Float; begin W := 1.0 / X; if X > 1024.0 then begin P := 6.97281375836585777429E-5 * W + 7.84039221720066627474E-4; P := P * W - 2.29472093621399176955E-4; P := P * W - 2.68132716049382716049E-3; P := P * W + 3.47222222222222222222E-3; P := P * W + 8.33333333333333333333E-2; end else P := PolEvl(W, STIR, 8); Stirling := Sqrt2Pi * Exp((X - 0.5) * Ln(X) - X) * (1.0 + W * P); end; function GamSmall(X1, Z : Float) : Float; { Gamma function for small values of the argument } const S : TabCoef = ( - 1.193945051381510095614E-3, 7.220599478036909672331E-3, - 9.622023360406271645744E-3, - 4.219773360705915470089E-2, 1.665386113720805206758E-1, - 4.200263503403344054473E-2, - 6.558780715202540684668E-1, 5.772156649015328608253E-1, 1.000000000000000000000E0, 0); SN : TabCoef = ( 1.133374167243894382010E-3, 7.220837261893170325704E-3, 9.621911155035976733706E-3, - 4.219773343731191721664E-2, - 1.665386113944413519335E-1, - 4.200263503402112910504E-2, 6.558780715202536547116E-1, 5.772156649015328608727E-1, - 1.000000000000000000000E0, 0); var P : Float; begin if X1 = 0.0 then begin GamSmall := DefaultVal(FSing, MaxNum); Exit; end; if X1 < 0.0 then begin X1 := - X1; P := PolEvl(X1, SN, 8); end else P := PolEvl(X1, S, 8); GamSmall := Z / (X1 * P); end; function StirLog(X : Float) : Float; { Approximate Ln(Gamma) by Stirling's formula, for X >= 13 } const P : TabCoef = ( 4.885026142432270781165E-3, - 1.880801938119376907179E-3, 8.412723297322498080632E-4, - 5.952345851765688514613E-4, 7.936507795855070755671E-4, - 2.777777777750349603440E-3, 8.333333333333331447505E-2, 0, 0, 0); var Q, W : Float; begin Q := Ln(X) * (X - 0.5) - X; Q := Q + LnSqrt2Pi; if X > 1.0E+10 then StirLog := Q else begin W := 1.0 / Sqr(X); StirLog := Q + PolEvl(W, P, 6) / X; end; end; function Gamma(X : Float) : Float; const P : TabCoef = ( 4.212760487471622013093E-5, 4.542931960608009155600E-4, 4.092666828394035500949E-3, 2.385363243461108252554E-2, 1.113062816019361559013E-1, 3.629515436640239168939E-1, 8.378004301573126728826E-1, 1.000000000000000000009E0, 0, 0); Q : TabCoef = ( - 1.397148517476170440917E-5, 2.346584059160635244282E-4, - 1.237799246653152231188E-3, - 7.955933682494738320586E-4, 2.773706565840072979165E-2, - 4.633887671244534213831E-2, - 2.243510905670329164562E-1, 4.150160950588455434583E-1, 9.999999999999999999908E-1, 0); var SgnGam, N : Integer; A, X1, Z : Float; begin SetErrCode(FOk); SgnGam := SgnGamma(X); if (X = 0.0) or ((X < 0.0) and (Frac(X) = 0.0)) then begin Gamma := DefaultVal(FSing, SgnGam * MaxNum); Exit; end; if X > MaxGam then begin Gamma := DefaultVal(FOverflow, MaxNum); Exit; end; A := Abs(X); if A > 13.0 then begin if X < 0.0 then begin N := Trunc(A); Z := A - N; if Z > 0.5 then begin N := N + 1; Z := A - N; end; Z := Abs(A * Sin(Pi * Z)) * Stirling(A); if Z <= Pi / MaxNum then begin Gamma := DefaultVal(FOverflow, SgnGam * MaxNum); Exit; end; Z := PI / Z; end else Z := Stirling(X); Gamma := SgnGam * Z; end else begin Z := 1.0; X1 := X; while X1 >= 3.0 do begin X1 := X1 - 1.0; Z := Z * X1; end; while X1 < - 0.03125 do begin Z := Z / X1; X1 := X1 + 1.0; end; if X1 <= 0.03125 then Gamma := GamSmall(X1, Z) else begin while X1 < 2.0 do begin Z := Z / X1; X1 := X1 + 1.0; end; if (X1 = 2.0) or (X1 = 3.0) then Gamma := Z else begin X1 := X1 - 2.0; Gamma := Z * PolEvl(X1, P, 7) / PolEvl(X1, Q, 8); end; end; end; end; function LnGamma(X : Float) : Float; const P : TabCoef = ( - 2.163690827643812857640E3, - 8.723871522843511459790E4, - 1.104326814691464261197E6, - 6.111225012005214299996E6, - 1.625568062543700591014E7, - 2.003937418103815175475E7, - 8.875666783650703802159E6, 0, 0, 0); Q : TabCoef = ( - 5.139481484435370143617E2, - 3.403570840534304670537E4, - 6.227441164066219501697E5, - 4.814940379411882186630E6, - 1.785433287045078156959E7, - 3.138646407656182662088E7, - 2.099336717757895876142E7, 0, 0, 0); var N : Integer; A, X1, Z : Float; begin SetErrCode(FOk); if (X = 0.0) or ((X < 0.0) and (Frac(X) = 0.0)) then begin LnGamma := DefaultVal(FSing, MaxNum); Exit; end; if X > MaxLgm then begin LnGamma := DefaultVal(FOverflow, MaxNum); Exit; end; A := Abs(X); if A > 34.0 then begin if X < 0.0 then begin N := Trunc(A); Z := A - N; if Z > 0.5 then begin N := N + 1; Z := N - A; end; Z := A * Sin(Pi * Z); if Z = 0.0 then begin LnGamma := DefaultVal(FOverflow, MaxNum); Exit; end; Z := LnPi - Ln(Z) - StirLog(A); end else Z := StirLog(X); LnGamma := Z; end else if X < 13.0 then begin Z := 1.0; X1 := X; while X1 >= 3 do begin X1 := X1 - 1.0; Z := Z * X1; end; while X1 < 2.0 do begin if Abs(X1) <= 0.03125 then begin LnGamma := Ln(Abs(GamSmall(X1, Z))); Exit; end; Z := Z / X1; X1 := X1 + 1.0; end; if Z < 0.0 then Z := - Z; if X1 = 2.0 then LnGamma := Ln(Z) else begin X1 := X1 - 2.0; LnGamma := X1 * PolEvl(X1, P, 6) / P1Evl(X1, Q, 7) + Ln(Z); end; end else LnGamma := StirLog(X); end; end.���mricron-0.20140804.1~dfsg.1.orig/fpmath/uanova2.pas�������������������������������������������������0000755�0001750�0001750�00000007207�11326425444�017555� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Two-way analysis of variance ****************************************************************** } unit uanova2; interface uses utypes; procedure AnOVa2(NA, NB, Nobs : Integer; M, S : PMatrix; V, F : PVector; DoF : PIntVector); { ------------------------------------------------------------------ Input parameters : NA = number of modalities for factor A NB = number of modalities for factor B Nobs = number of observations for each sample M = matrix of means (factor A as lines, factor B as columns) S = matrix of standard deviations Output parameters: V = variances (factor A, factor B, interaction, residual) F = variance ratios (factor A, factor B, interaction) DoF = degrees of freedom (factor A, factor B, interaction, residual) ------------------------------------------------------------------ } implementation procedure AnOVa2(NA, NB, Nobs : Integer; M, S : PMatrix; V, F : PVector; DoF : PIntVector); var I, J, P : Integer; Xbar : Float; { Global mean } D : Float; { Difference of means } Sum : Float; { Intermediate sum } ML, MC : PVector; { Line and columns means } SS : PVector; { Sum of squares } begin if (NA < 2) or (NB < 2) or (Nobs < 1) then begin SetErrCode(MatErrDim); Exit end; DimVector(ML, NA); DimVector(MC, NB); DimVector(SS, 3); SetErrCode(MatOk); { Line means } for I := 1 to NA do begin Sum := 0.0; for J := 1 to NB do Sum := Sum + M^[I]^[J]; ML^[I] := Sum / NB; end; { Column means } for J := 1 to NB do begin Sum := 0.0; for I := 1 to NA do Sum := Sum + M^[I]^[J]; MC^[J] := Sum / NA; end; { Global mean } Sum := 0.0; for I := 1 to NA do Sum := Sum + ML^[I]; Xbar := Sum / NA; { Residual variance } if Nobs = 1 then V^[4] := 0.0 else begin Sum := 0.0; for I := 1 to NA do for J := 1 to NB do Sum := Sum + Sqr(S^[I]^[J]); P := NA * NB; DoF^[4] := P * (Nobs - 1); V^[4] := Sum / P; end; { Factorial sum of squares } Sum := 0.0; for I := 1 to NA do for J := 1 to NB do begin D := M^[I]^[J] - Xbar; Sum := Sum + Sqr(D) end; SS^[0] := Nobs * Sum; { Factorial variance (factor A) } Sum := 0.0; for I := 1 to NA do begin D := ML^[I] - Xbar; Sum := Sum + Sqr(D) end; SS^[1] := NB * Nobs * Sum; DoF^[1] := NA - 1; V^[1] := SS^[1] / DoF^[1]; { Factorial variance (factor B) } Sum := 0.0; for J := 1 to NB do begin D := MC^[J] - Xbar; Sum := Sum + Sqr(D) end; SS^[2] := NA * Nobs * Sum; DoF^[2] := NB - 1; V^[2] := SS^[2] / DoF^[2]; { Factorial variance (interaction) } SS^[3] := SS^[0] - SS^[1] - SS^[2]; DoF^[3] := DoF^[1] * DoF^[2]; V^[3] := SS^[3] / DoF^[3]; { Variance ratios } if Nobs = 1 then begin F^[1] := V^[1] / V^[3]; F^[2] := V^[2] / V^[3] end else begin F^[1] := V^[1] / V^[4]; F^[2] := V^[2] / V^[4]; F^[3] := V^[3] / V^[4]; end; end; end.�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uhyper.pas��������������������������������������������������0000755�0001750�0001750�00000005062�11326425444�017513� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Hyperbolic functions ****************************************************************** } unit uhyper; interface uses utypes, uminmax; function Sinh(X : Float) : Float; { Hyperbolic sine } function Cosh(X : Float) : Float; { Hyperbolic cosine } function Tanh(X : Float) : Float; { Hyperbolic tangent } function ArcSinh(X : Float) : Float; { Inverse hyperbolic sine } function ArcCosh(X : Float) : Float; { Inverse hyperbolic cosine } function ArcTanh(X : Float) : Float; { Inverse hyperbolic tangent } procedure SinhCosh(X : Float; var SinhX, CoshX : Float); { Sinh & Cosh } implementation function Sinh(X : Float) : Float; var ExpX : Float; begin if (X < MinLog) or (X > MaxLog) then Sinh := DefaultVal(FOverflow, Sgn(X) * MaxNum) else begin ExpX := Exp(X); Sinh := 0.5 * (ExpX - 1.0 / ExpX); SetErrCode(FOk); end; end; function Cosh(X : Float) : Float; var ExpX : Float; begin if (X < MinLog) or (X > MaxLog) then Cosh := DefaultVal(FOverflow, MaxNum) else begin ExpX := Exp(X); Cosh := 0.5 * (ExpX + 1.0 / ExpX); SetErrCode(FOk); end; end; procedure SinhCosh(X : Float; var SinhX, CoshX : Float); var ExpX, ExpMinusX : Float; begin if (X < MinLog) or (X > MaxLog) then begin CoshX := DefaultVal(FOverflow, MaxNum); SinhX := Sgn(X) * CoshX; end else begin ExpX := Exp(X); ExpMinusX := 1.0 / ExpX; SinhX := 0.5 * (ExpX - ExpMinusX); CoshX := 0.5 * (ExpX + ExpMinusX); SetErrCode(FOk); end; end; function Tanh(X : Float) : Float; var SinhX, CoshX : Float; begin SinhCosh(X, SinhX, CoshX); Tanh := SinhX / CoshX; end; function ArcSinh(X : Float) : Float; begin SetErrCode(FOk); ArcSinh := Ln(X + Sqrt(Sqr(X) + 1.0)); end; function ArcCosh(X : Float) : Float; begin SetErrCode(FOk); if X < 1.0 then ArcCosh := DefaultVal(FDomain, 0.0) else ArcCosh := Ln(X + Sqrt(Sqr(X) - 1.0)); end; function ArcTanh(X : Float) : Float; begin SetErrCode(FOk); if (X < - 1.0) or (X > 1.0) then ArcTanh := DefaultVal(FDomain, Sgn(X) * MaxNum) else if (X = - 1.0) or (X = 1.0) then ArcTanh := Sgn(X) * DefaultVal(FSing, Sgn(X) * MaxNum) else ArcTanh := 0.5 * Ln((1.0 + X) / (1.0 - X)); end; end.������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ulinmin.pas�������������������������������������������������0000755�0001750�0001750�00000010605�11326425444�017651� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Minimization of a function of several variables along a line ****************************************************************** } unit ulinmin; interface uses utypes, uminmax; procedure LinMin(Func : TFuncNVar; X, DeltaX : PVector; Lb, Ub : Integer; var R : Float; MaxIter : Integer; Tol : Float; var F_min : Float); { ------------------------------------------------------------------ Minimizes function Func from point X in the direction specified by DeltaX ------------------------------------------------------------------ Input parameters : Func = objective function X = initial minimum coordinates DeltaX = direction in which minimum is searched Lb, Ub = indices of first and last variables R = initial step, in fraction of |DeltaX| MaxIter = maximum number of iterations Tol = required precision ------------------------------------------------------------------ Output parameters : X = refined minimum coordinates R = step corresponding to the minimum F_min = function value at minimum ------------------------------------------------------------------ Possible results : OptOk OptNonConv ------------------------------------------------------------------ } implementation procedure LinMin(Func : TFuncNVar; X, DeltaX : PVector; Lb, Ub : Integer; var R : Float; MaxIter : Integer; Tol : Float; var F_min : Float); var A, B, C : Float; Fa, Fb, Fc, F1, F2 : Float; MinTol, Norm : Float; R0, R1, R2, R3 : Float; I, Iter : Integer; P : PVector; begin MinTol := Sqrt(MachEp); if Tol < MinTol then Tol := MinTol; if R < 0.0 then R := 1.0; Norm := 0.0; for I := Lb to Ub do Norm := Norm + Sqr(DeltaX^[I]); Norm := Sqrt(Norm); A := 0; B := R * Norm; DimVector(P, Ub); { Bracket the minimum (see procedure MinBrack in unit UMINBRAK) } for I := Lb to Ub do P^[I] := X^[I]; Fa := Func(P); for I := Lb to Ub do P^[I] := X^[I] + B * DeltaX^[I]; Fb := Func(P); if Fb > Fa then begin FSwap(A, B); FSwap(Fa, Fb); end; C := B + Gold * (B - A); for I := Lb to Ub do P^[I] := X^[I] + C * DeltaX^[I]; Fc := Func(P); while Fc < Fb do begin A := B; B := C; Fa := Fb; Fb := Fc; C := B + Gold * (B - A); for I := Lb to Ub do P^[I] := X^[I] + C * DeltaX^[I]; Fc := Func(P); end; if A > C then begin FSwap(A, C); FSwap(Fa, Fc); end; { Refine the minimum (see procedure GoldSearch in unit UGOLDSRC) } R0 := A; R3 := C; if (C - B) > (B - A) then begin R1 := B; R2 := B + CGold * (C - B); F1 := Fb; for I := Lb to Ub do P^[I] := X^[I] + R2 * DeltaX^[I]; F2 := Func(P); end else begin R1 := B - CGold * (B - A); R2 := B; for I := Lb to Ub do P^[I] := X^[I] + R1 * DeltaX^[I]; F1 := Func(P); F2 := Fb; end; Iter := 0; while (Iter <= MaxIter) and (Abs(R3 - R0) > Tol * (Abs(R1) + Abs(R2))) do begin if F2 < F1 then begin R0 := R1; R1 := R2; F1 := F2; R2 := R1 + CGold * (R3 - R1); for I := Lb to Ub do P^[I] := X^[I] + R2 * DeltaX^[I]; F2 := Func(P); end else begin R3 := R2; R2 := R1; F2 := F1; R1 := R2 - CGold * (R2 - R0); for I := Lb to Ub do P^[I] := X^[I] + R1 * DeltaX^[I]; F1 := Func(P); end; Iter := Iter + 1; end; if F1 < F2 then begin R := R1; F_min := F1; end else begin R := R2; F_min := F2; end; for I := Lb to Ub do X^[I] := X^[I] + R * DeltaX^[I]; if Iter > MaxIter then SetErrCode(OptNonConv) else SetErrCode(OptOk); DelVector(P, Ub); end; end. ���������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ubalance.pas������������������������������������������������0000755�0001750�0001750�00000012204�11326425444�017745� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Balances a matrix and tries to isolate eigenvalues ****************************************************************** } unit ubalance; interface uses utypes; procedure Balance( A : PMatrix; Lb, Ub : Integer; var I_low, I_igh : Integer; Scale : PVector); implementation procedure Balance( A : PMatrix; Lb, Ub : Integer; var I_low, I_igh : Integer; Scale : PVector); { ------------------------------------------------------------------ This procedure is a translation of the EISPACK procedure Balanc. This procedure balances a real matrix and isolates eigenvalues whenever possible. On input: A contains the input matrix to be balanced. Lb, Ub are the lowest and highest indices of the elements of A. On output: A contains the balanced matrix. I_low and I_igh are two integers such that A[i,j] is equal to zero if (1) i is greater than j and (2) j=Lb,...,I_low-1 or i=I_igh+1,...,Ub. Scale contains information determining the permutations and scaling factors used. Suppose that the principal submatrix in rows I_low through I_igh has been balanced, that P[j] denotes the index interchanged with j during the permutation step, and that the elements of the diagonal matrix used are denoted by D[i,j]. then Scale[j] = P[j], for j = Lb,...,I_low-1 = D[j,j], j = I_low,...,I_igh = P[j] j = I_igh+1,...,Ub. the order in which the interchanges are made is Ub to I_igh+1, then Lb to I_low-1. Note that Lb is returned for I_igh if I_igh is < Lb formally ------------------------------------------------------------------ } const RADIX = 2; { Base used in floating number representation } var I, J, M : Integer; C, F, G, R, S, B2 : Float; Flag, Found, Conv : Boolean; procedure Exchange; { Row and column exchange } var I : Integer; begin Scale^[M] := J; if J = M then Exit; for I := Lb to I_igh do begin F := A^[I]^[J]; A^[I]^[J] := A^[I]^[M]; A^[I]^[M] := F; end; for I := I_low to Ub do begin F := A^[J]^[I]; A^[J]^[I] := A^[M]^[I]; A^[M]^[I] := F; end; end; begin B2 := RADIX * RADIX; I_low := Lb; I_igh := Ub; { Search for rows isolating an eigenvalue and push them down } repeat J := I_igh; repeat I := Lb; repeat Flag := (I <> J) and (A^[J]^[I] <> 0.0); I := I + 1; until Flag or (I > I_igh); Found := not Flag; if Found then begin M := I_igh; Exchange; I_igh := I_igh - 1; end; J := J - 1; until Found or (J < Lb); until (not Found) or (I_igh < Lb); if I_igh < Lb then I_igh := Lb; if I_igh = Lb then Exit; { Search for columns isolating an eigenvalue and push them left } repeat J := I_low; repeat I := I_low; repeat Flag := (I <> J) and (A^[I]^[J] <> 0.0); I := I + 1; until Flag or (I > I_igh); Found := not Flag; if Found then begin M := I_low; Exchange; I_low := I_low + 1; end; J := J + 1; until Found or (J > I_igh); until (not Found); { Now balance the submatrix in rows I_low to I_igh } for I := I_low to I_igh do Scale^[I] := 1.0; { Iterative loop for norm reduction } repeat Conv := True; for I := I_low to I_igh do begin C := 0.0; R := 0.0; for J := I_low to I_igh do if J <> I then begin C := C + Abs(A^[J]^[I]); R := R + Abs(A^[I]^[J]); end; { Guard against zero C or R due to underflow } if (C <> 0.0) and (R <> 0.0) then begin G := R / RADIX; F := 1.0; S := C + R; while C < G do begin F := F * RADIX; C := C * B2; end; G := R * RADIX; while C >= G do begin F := F / RADIX; C := C / B2; end; { Now balance } if (C + R) / F < 0.95 * S then begin G := 1.0 / F; Scale^[I] := Scale^[I] * F; Conv := False; for J := I_low to Ub do A^[I]^[J] := A^[I]^[J] * G; for J := Lb to I_igh do A^[J]^[I] := A^[J]^[I] * F; end; end; end; until Conv; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uplot.pas���������������������������������������������������0000755�0001750�0001750�00000113050�11326425446�017341� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Plotting routines for TP/FPC/GPC (based on the Graph unit) ****************************************************************** } unit uplot; interface uses graph, utypes, umath, uround, uinterv, ustrings; function InitGraphics(Pilot, Mode : Integer; BGIPath : String) : Boolean; { ------------------------------------------------------------------ Enters graphic mode ------------------------------------------------------------------ } procedure SetWindow(X1, X2, Y1, Y2 : Integer; GraphBorder : Boolean); { ------------------------------------------------------------------ Sets the graphic window X1, X2, Y1, Y2 : Window coordinates in % of maximum GraphBorder : Flag for drawing the window border ------------------------------------------------------------------ } procedure AutoScale(X : PVector; Lb, Ub : Integer; Scale : TScale; var XMin, XMax, XStep : Float); { ------------------------------------------------------------------ Finds an appropriate scale for plotting the data in X[Lb..Ub] ------------------------------------------------------------------ } procedure SetOxScale(Scale : TScale; OxMin, OxMax, OxStep : Float); { ------------------------------------------------------------------ Sets the scale on the Ox axis ------------------------------------------------------------------ } procedure SetOyScale(Scale : TScale; OyMin, OyMax, OyStep : Float); { ------------------------------------------------------------------ Sets the scale on the Oy axis ------------------------------------------------------------------ } procedure SetGraphTitle(Title : String); { ------------------------------------------------------------------ Sets the title for the graph ------------------------------------------------------------------ } procedure SetOxTitle(Title : String); { ------------------------------------------------------------------ Sets the title for the Ox axis ------------------------------------------------------------------ } procedure SetOyTitle(Title : String); { ------------------------------------------------------------------ Sets the title for the Oy axis ------------------------------------------------------------------ } procedure SetTitleFont(FontIndex, Width, Height : Integer); { ------------------------------------------------------------------ Sets the font for the main graph title ------------------------------------------------------------------ } procedure SetOxFont(FontIndex, Width, Height : Integer); { ------------------------------------------------------------------ Sets the font for the Ox axis (title and labels) ------------------------------------------------------------------ } procedure SetOyFont(FontIndex, Width, Height : Integer); { ------------------------------------------------------------------ Sets the font for the Oy axis (title and labels) ------------------------------------------------------------------ } procedure SetLgdFont(FontIndex, Width, Height : Integer); { ------------------------------------------------------------------ Sets the font for the legends ------------------------------------------------------------------ } procedure PlotOxAxis; { ------------------------------------------------------------------ Plots the horizontal axis ------------------------------------------------------------------ } procedure PlotOyAxis; { ------------------------------------------------------------------ Plots the vertical axis ------------------------------------------------------------------ } procedure PlotGrid(Grid : TGrid); { ------------------------------------------------------------------ Plots a grid on the graph ------------------------------------------------------------------ } procedure WriteGraphTitle; { ------------------------------------------------------------------ Writes the title of the graph ------------------------------------------------------------------ } procedure SetClipping(Clip : Boolean); { ------------------------------------------------------------------ Determines whether drawings are clipped at the current viewport boundaries, according to the value of the Boolean parameter Clip ------------------------------------------------------------------ } procedure SetMaxCurv(NCurv : Byte); { ------------------------------------------------------------------ Sets the maximum number of curves and re-initializes their parameters ------------------------------------------------------------------ } procedure SetPointParam(CurvIndex, Symbol, Size, Color : Integer); { ------------------------------------------------------------------ Sets the point parameters for curve # CurvIndex ------------------------------------------------------------------ } procedure SetLineParam(CurvIndex, Style, Width, Color : Integer); { ------------------------------------------------------------------ Sets the line parameters for curve # CurvIndex ------------------------------------------------------------------ } procedure SetCurvLegend(CurvIndex : Integer; Legend : String); { ------------------------------------------------------------------ Sets the legend for curve # CurvIndex ------------------------------------------------------------------ } procedure SetCurvStep(CurvIndex, Step : Integer); { ------------------------------------------------------------------ Sets the step for curve # CurvIndex ------------------------------------------------------------------ } procedure PlotPoint(Xp, Yp, CurvIndex : Integer); { ------------------------------------------------------------------ Plots a point on the screen ------------------------------------------------------------------ Input parameters : Xp, Yp = point coordinates in pixels CurvIndex = index of curve parameters (Symbol, Size, Color) ------------------------------------------------------------------ } procedure PlotCurve(X, Y : PVector; Lb, Ub, CurvIndex : Integer); { ------------------------------------------------------------------ Plots a curve ------------------------------------------------------------------ Input parameters : X, Y = point coordinates Lb, Ub = indices of first and last points CurvIndex = index of curve parameters ------------------------------------------------------------------ } procedure PlotCurveWithErrorBars(X, Y, S : PVector; Ns, Lb, Ub, CurvIndex : Integer); { ------------------------------------------------------------------ Plots a curve with error bars ------------------------------------------------------------------ Input parameters : X, Y = point coordinates S = errors Lb, Ub = indices of first and last points CurvIndex = index of curve parameters ------------------------------------------------------------------ } procedure PlotFunc(Func : TFunc; X1, X2 : Float; CurvIndex : Integer); { ------------------------------------------------------------------ Plots a function ------------------------------------------------------------------ Input parameters: Func = function to be plotted X1, X2 = abscissae of 1st and last point to plot CurvIndex = index of curve parameters (Width, Style, Color) ------------------------------------------------------------------ The function must be programmed as : function Func(X : Float) : Float; ------------------------------------------------------------------ } procedure WriteLegend(NCurv : Integer; ShowPoints, ShowLines : Boolean); { ------------------------------------------------------------------ Writes the legends for the plotted curves ------------------------------------------------------------------ NCurv : number of curves (1 to MaxCurv) ShowPoints : for displaying points ShowLines : for displaying lines ------------------------------------------------------------------ } procedure ConRec(Nx, Ny, Nc : Integer; X, Y, Z : PVector; F : PMatrix); { ------------------------------------------------------------------ Contour plot Adapted from Paul Bourke, Byte, June 1987 http://astronomy.swin.edu.au/~pbourke/projection/conrec/ ------------------------------------------------------------------ Input parameters: Nx, Ny = number of steps on Ox and Oy Nc = number of contour levels X[0..Nx], Y[0..Ny] = point coordinates in pixels Z[0..(Nc - 1)] = contour levels in increasing order F[0..Nx, 0..Ny] = function values, such that F[I,J] is the function value at (X[I], Y[I]) ------------------------------------------------------------------ } function Xpixel(X : Float) : Integer; { ------------------------------------------------------------------ Converts user abscissa X to screen coordinate ------------------------------------------------------------------ } function Ypixel(Y : Float) : Integer; { ------------------------------------------------------------------ Converts user ordinate Y to screen coordinate ------------------------------------------------------------------ } function Xuser(X : Integer) : Float; { ------------------------------------------------------------------ Converts screen coordinate X to user abscissa ------------------------------------------------------------------ } function Yuser(Y : Integer) : Float; { ------------------------------------------------------------------ Converts screen coordinate Y to user ordinate ------------------------------------------------------------------ } procedure LeaveGraphics; { ------------------------------------------------------------------ Quits graphic mode ------------------------------------------------------------------ } implementation const MaxSymbol = 9; { Max. number of symbols for plotting curves } MaxCurvColor = 9; { Max. number of colors for curves } Eps = 1.0E-10; { Lower limit for an axis label } CurvColor : array[1..MaxCurvColor] of Integer = (12, { LightRed } 14, { Yellow } 10, { LightGreen } 9, { LightBlue } 11, { LightCyan } 13, { LightMagenta } 4, { Red } 2, { Green } 1 { Blue }); type TAxis = record { Coordinate axis } Scale : TScale; Min : Float; Max : Float; Step : Float; end; TFont = record { Font for titles and legends } Index : Integer; Width : Integer; Height : Integer; end; TPointParam = record { Point parameters } Symbol : Integer; { Symbol: 0: point (.) } Size : Integer; { 1: solid circle 2: open circle } Color : Integer; { 3: solid square 4: open square } end; { 5: solid triangle 6: open triangle } { 7: plus (+) 8: multiply (x) } { 9: star (* ) } TLineParam = record { Line parameters } Style : Integer; { 0: none, 1: solid, 2: dotted, 3: centered, 4: dashed } Width : Integer; { 1: normal, 3: thick } Color : Integer; end; TCurvParam = record { Curve parameters } PointParam : TPointParam; LineParam : TLineParam; Legend : Str30; { Legend of curve } Step : Integer; { Plot 1 point every Step points } end; TCurvParamVector = array[1..255] of TCurvParam; PCurvParamVector = ^TCurvParamVector; var Xwin1, Xwin2, Ywin1, Ywin2 : Integer; XminPixel, XmaxPixel : Integer; YminPixel, YmaxPixel : Integer; FactX, FactY : Float; XAxis, YAxis : TAxis; GraphTitle, XTitle, YTitle : String; TitleFont, XFont, YFont, LgdFont : TFont; MaxCurv : Integer; CurvParam : PCurvParamVector; procedure DimCurvParamVector(var CurvParam : PCurvParamVector; Ub : Byte); var I : Integer; begin { Allocate vector } GetMem(CurvParam, Ub * SizeOf(TCurvParam)); if CurvParam = nil then Exit; MaxCurv := Ub; { Initialize curve parameters } for I := 1 to Ub do with CurvParam^[I] do begin PointParam.Symbol := (I - 1) mod MaxSymbol + 1; PointParam.Size := 2; PointParam.Color := CurvColor[(I - 1) mod MaxCurvColor + 1]; Legend := 'Curve ' + LTrim(IntStr(I)); LineParam.Width := 1; LineParam.Style := 1; LineParam.Color := PointParam.Color; Step := 1; end; end; procedure DelCurvParamVector(var CurvParam : PCurvParamVector; Ub : Byte); begin if CurvParam <> nil then begin FreeMem(CurvParam, Ub * SizeOf(TCurvParam)); CurvParam := nil; MaxCurv := 0; end; end; function InitGraphics(Pilot, Mode : Integer; BGIPath : String) : Boolean; var P, M : {$IFDEF FPC}Smallint{$ELSE}Integer{$ENDIF}; begin P := Pilot; M := Mode; InitGraph(P, M, BGIPath); if GraphResult <> 0 then begin InitGraphics := False; Exit; end; InitGraphics := True; MaxCurv := MaxSymbol; DimCurvParamVector(CurvParam, MaxCurv); { Obtain info about current mode } XminPixel := 0; XmaxPixel := GetMaxX; YminPixel := 0; YmaxPixel := GetMaxY; end; procedure SetWindow(X1, X2, Y1, Y2 : Integer; GraphBorder : Boolean); var R : Float; begin if (X1 >= 0) and (X2 <= 100) and (X1 < X2) then begin Xwin1 := X1; Xwin2 := X2; R := 0.01 * GetMaxX; XminPixel := Round(X1 * R); XmaxPixel := Round(X2 * R); end; if (Y1 >= 0) and (Y2 <= 100) and (Y1 < Y2) then begin Ywin1 := Y1; Ywin2 := Y2; R := 0.01 * GetMaxY; YminPixel := Round(Y1 * R); YmaxPixel := Round(Y2 * R); end; XAxis.Scale := LinScale; XAxis.Min := 0.0; XAxis.Max := 1.0; XAxis.Step := 0.2; YAxis.Scale := LinScale; YAxis.Min := 0.0; YAxis.Max := 1.0; YAxis.Step := 0.2; FactX := (XmaxPixel - XminPixel) / (XAxis.Max - XAxis.Min); FactY := (YmaxPixel - YminPixel) / (YAxis.Max - YAxis.Min); XTitle := 'X'; XFont.Index := 2; XFont.Width := 150; XFont.Height := 150; YTitle := 'Y'; YFont.Index := 2; YFont.Width := 150; YFont.Height := 150; GraphTitle := ''; TitleFont.Index := 2; TitleFont.Width := 175; TitleFont.Height := 175; LgdFont.Index := 2; LgdFont.Width := 150; LgdFont.Height := 150; if GraphBorder then Rectangle(XminPixel, YminPixel, XmaxPixel, YmaxPixel); end; procedure AutoScale(X : PVector; Lb, Ub : Integer; Scale : TScale; var XMin, XMax, XStep : Float); var I : Integer; X1, X2 : Float; begin { Minimum and maximum of X } X1 := X^[Lb]; X2 := X1; for I := Lb to Ub do if X^[I] < X1 then X1 := X^[I] else if X^[I] > X2 then X2 := X^[I]; { Linear scale } if Scale = LinScale then begin Interval(X1, X2, 2, 6, XMin, XMax, XStep); Exit; end; { Logarithmic scale } XMin := 1.0E-3; XMax := 1.0E+3; XStep := 10.0; if X1 <= 0.0 then Exit; XMin := Int(Log10(X1)); if X1 < 1.0 then XMin := XMin - 1.0; XMax := Int(Log10(X2)); if X2 > 1.0 then XMax := XMax + 1.0; XMin := Exp10(XMin); XMax := Exp10(XMax); end; procedure SetOxScale(Scale : TScale; OxMin, OxMax, OxStep : Float); begin XAxis.Scale := Scale; case Scale of LinScale : begin if OxMin < OxMax then begin XAxis.Min := OxMin; XAxis.Max := OxMax; end; if OxStep > 0.0 then XAxis.Step := OxStep; end; LogScale : begin if (OxMin > 0.0) and (OxMin < OxMax) then begin XAxis.Min := Floor(Log10(OxMin)); XAxis.Max := Ceil(Log10(OxMax)); end; XAxis.Step := 1.0; end; end; FactX := (XmaxPixel - XminPixel) / (XAxis.Max - XAxis.Min); end; procedure SetOyScale(Scale : TScale; OyMin, OyMax, OyStep : Float); begin YAxis.Scale := Scale; case Scale of LinScale : begin if OyMin < OyMax then begin YAxis.Min := OyMin; YAxis.Max := OyMax; end; if OyStep > 0.0 then YAxis.Step := OyStep; end; LogScale : begin if (OyMin > 0.0) and (OyMin < OyMax) then begin YAxis.Min := Floor(Log10(OyMin)); YAxis.Max := Ceil(Log10(OyMax)); end; YAxis.Step := 1.0; end; end; FactY := (YmaxPixel - YminPixel) / (YAxis.Max - YAxis.Min); end; procedure SetGraphTitle(Title : String); begin GraphTitle := Title; end; procedure SetOxTitle(Title : String); begin XTitle := Title; end; procedure SetOyTitle(Title : String); begin YTitle := Title; end; procedure SetFont(Select, Index, Width, Height : Integer); var Font : TFont; begin if Index in [0..10] then Font.Index := Index; if Width > 0 then Font.Width := Width; if Height > 0 then Font.Height := Height; case Select of 0 : TitleFont := Font; 1 : XFont := Font; 2 : YFont := Font; 3 : LgdFont := Font; end; end; procedure SetTitleFont(FontIndex, Width, Height : Integer); begin SetFont(0, FontIndex, Width, Height); end; procedure SetOxFont(FontIndex, Width, Height : Integer); begin SetFont(1, FontIndex, Width, Height); end; procedure SetOyFont(FontIndex, Width, Height : Integer); begin SetFont(2, FontIndex, Width, Height); end; procedure SetLgdFont(FontIndex, Width, Height : Integer); begin SetFont(3, FontIndex, Width, Height); end; function Xpixel(X : Float) : Integer; var P : Float; begin P := FactX * (X - XAxis.Min); if Abs(P) > 30000 then Xpixel := 30000 else Xpixel := Round(P) + XminPixel; end; function Ypixel(Y : Float) : Integer; var P : Float; begin P := FactY * (YAxis.Max - Y); if Abs(P) > 30000 then Ypixel := 30000 else Ypixel := Round(P) + YminPixel; end; function Xuser(X : Integer) : Float; begin Xuser := XAxis.Min + (X - XminPixel) / FactX; end; function Yuser(Y : Integer) : Float; begin Yuser := YAxis.Max - (Y - YminPixel) / FactY; end; procedure PlotOxAxis; var W, X, Z : Float; N, I, J : Integer; begin Line(XminPixel, YmaxPixel, XmaxPixel, YmaxPixel); SetTextStyle(XFont.Index, HorizDir, 1); SetUserCharSize(XFont.Width, 100, XFont.Height, 100); SetTextJustify(CenterText, TopText); N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); { Nb of intervals } X := XAxis.Min; { Tick mark position } for I := 0 to N do { Label axis } begin if (XAxis.Scale = LinScale) and (Abs(X) < Eps) then X := 0.0; MoveTo(Xpixel(X), YmaxPixel); LineRel(0, 5); { Plot tick mark } if XAxis.Scale = LinScale then Z := X else Z := Exp10(X); OutText(Trim(FloatStr(Z))); if (XAxis.Scale = LogScale) and (I < N) then for J := 2 to 9 do { Plot minor divisions } begin { on logarithmic scale } W := X + Log10(J); MoveTo(Xpixel(W), YmaxPixel); LineRel(0, 3); end; X := X + XAxis.Step; end; if XTitle <> '' then { Plot axis title } OutTextXY((XminPixel + XmaxPixel) div 2, YmaxPixel + GetMaxY div 12, XTitle); end; procedure PlotOyAxis; var W, Y, Z : Float; N, I, J : Integer; begin Line(XminPixel, YminPixel, XminPixel, YmaxPixel); SetTextStyle(YFont.Index, HorizDir, 1); SetUserCharSize(YFont.Width, 100, YFont.Height, 100); SetTextJustify(RightText, CenterText); N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); Y := YAxis.Min; for I := 0 to N do begin if (YAxis.Scale = LinScale) and (Abs(Y) < Eps) then Y := 0.0; MoveTo(XminPixel, Ypixel(Y)); LineRel(- 5, 0); MoveRel(- 2, - 2); if YAxis.Scale = LinScale then Z := Y else Z := Exp10(Y); OutText(Trim(FloatStr(Z))); if (YAxis.Scale = LogScale) and (I < N) then for J := 2 to 9 do begin W := Y + Log10(J); MoveTo(XminPixel, Ypixel(W)); LineRel(- 3, 0); end; Y := Y + YAxis.Step; end; if YTitle <> '' then begin SetTextStyle(YFont.Index, VertDir, 1); SetUserCharSize(YFont.Width, 100, YFont.Height, 100); OutTextXY(XminPixel - GetMaxX div 8, (YminPixel + YmaxPixel) div 2, YTitle); end; end; procedure PlotGrid(Grid : TGrid); var X, Y : Float; I, N, Xp, Yp : Integer; begin SetLineStyle(DottedLn, 0, NormWidth); if Grid in [HorizGrid, BothGrid] then { Horizontal lines } begin N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); { Nb of intervals } for I := 1 to Pred(N) do begin Y := YAxis.Min + I * YAxis.Step; { Origin of line } Yp := Ypixel(Y); Line(XminPixel, Yp, XmaxPixel, Yp); end; end; if Grid in [VertiGrid, BothGrid] then { Vertical lines } begin N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); for I := 1 to Pred(N) do begin X := XAxis.Min + I * XAxis.Step; Xp := Xpixel(X); Line(Xp, YminPixel, Xp, YmaxPixel); end; end; SetLineStyle(SolidLn, 0, NormWidth); end; procedure WriteGraphTitle; begin if GraphTitle = '' then Exit; SetTextStyle(TitleFont.Index, HorizDir, 1); SetUserCharSize(TitleFont.Width, 100, TitleFont.Height, 100); SetTextJustify(CenterText, TopText); OutTextXY((XminPixel + XmaxPixel) div 2, YminPixel - GetMaxY div 10, GraphTitle); end; procedure SetClipping(Clip : Boolean); begin if XminPixel = 0 then begin XminPixel := Round(Xwin1 / 100 * GetMaxX); YminPixel := Round(Ywin1 / 100 * GetMaxY); XmaxPixel := Round(Xwin2 / 100 * GetMaxX); YmaxPixel := Round(Ywin2 / 100 * GetMaxY); end; SetViewPort(XminPixel, YminPixel, XmaxPixel, YmaxPixel, Clip); XmaxPixel := XmaxPixel - XminPixel; XminPixel := 0; YmaxPixel := YmaxPixel - YminPixel; YminPixel := 0; end; procedure SetMaxCurv(NCurv : Byte); begin if NCurv < 1 then Exit; DelCurvParamVector(CurvParam, MaxCurv); MaxCurv := NCurv; DimCurvParamVector(CurvParam, MaxCurv); end; procedure SetPointParam(CurvIndex, Symbol, Size, Color : Integer); begin if (CurvIndex < 1) or (CurvIndex > MaxCurv) then Exit; if (Symbol >= 0) and (Symbol <= MaxSymbol) then CurvParam^[CurvIndex].PointParam.Symbol := Symbol; if Size > 0 then CurvParam^[CurvIndex].PointParam.Size := Size; if (Color >= 0) and (Color <= GetMaxColor) then CurvParam^[CurvIndex].PointParam.Color := Color; end; procedure SetLineParam(CurvIndex, Style, Width, Color : Integer); begin if (CurvIndex < 1) or (CurvIndex > MaxCurv) then Exit; if (Style >= 0) and (Style <= 4) then CurvParam^[CurvIndex].LineParam.Style := Style; if (Width = 1) or (Width = 3) then CurvParam^[CurvIndex].LineParam.Width := Width; if (Color >= 0) and (Color <= GetMaxColor) then CurvParam^[CurvIndex].LineParam.Color := Color; end; procedure SetCurvLegend(CurvIndex : Integer; Legend : String); begin if (CurvIndex >= 1) and (CurvIndex <= MaxCurv) then CurvParam^[CurvIndex].Legend := Legend; end; procedure SetCurvStep(CurvIndex, Step : Integer); begin if (CurvIndex >= 1) and (CurvIndex <= MaxCurv) and (Step > 0) then CurvParam^[CurvIndex].Step := Step; end; procedure PlotPoint(Xp, Yp, CurvIndex : Integer); var Xasp, Yasp : {$IFDEF __GPC__}Integer{$ELSE}Word{$ENDIF}; Size : Integer; Xp1, Xp2 : Word; Yp1, Yp2 : Word; Dx, Dy : Word; R : Float; Triangle : array[1..4] of PointType; Square : array[1..5] of PointType; begin GetAspectRatio(Xasp, Yasp); Size := CurvParam^[CurvIndex].PointParam.Size; R := 0.0001 * Size; Dx := Round(R * Yasp); Dy := Round(R * Xasp); Xp1 := Xp - Size; Xp2 := Xp + Size; Yp1 := Yp - Size; Yp2 := Yp + Size; if CurvParam^[CurvIndex].PointParam.Symbol in [3, 4] then begin Square[1].X := Xp1; Square[1].Y := Yp1; Square[2].X := Xp1; Square[2].Y := Yp2; Square[3].X := Xp2; Square[3].Y := Yp2; Square[4].X := Xp2; Square[4].Y := Yp1; Square[5].X := Xp1; Square[5].Y := Yp1; end; if CurvParam^[CurvIndex].PointParam.Symbol in [5, 6] then begin Triangle[1].X := Xp; Triangle[1].Y := Yp1; Triangle[2].X := Xp2; Triangle[2].Y := Yp2; Triangle[3].X := Xp1; Triangle[3].Y := Yp2; Triangle[4].X := Xp; Triangle[4].Y := Yp1; end; MoveTo(Xp, Yp); SetColor(CurvParam^[CurvIndex].PointParam.Color); SetFillStyle(SolidFill, CurvParam^[CurvIndex].PointParam.Color); case CurvParam^[CurvIndex].PointParam.Symbol of 0 : PutPixel(Xp, Yp, GetColor); { . } 1 : PieSlice(Xp, Yp, 0, 360, Dx); { Solid circle } 2 : Ellipse(Xp, Yp, 0, 360, Dx, Dy); { Open circle } 3 : FillPoly(5, Square); { Solid square } 4 : DrawPoly(5, Square); { Open square } 5 : FillPoly(4, Triangle); { Solid triangle } 6 : DrawPoly(4, Triangle); { Open triangle } 7 : begin { + } Line(Xp, Yp1, Xp, Yp2); Line(Xp1, Yp, Xp2, Yp); end; 8 : begin { x } Line(Xp1, Yp1, Xp2, Yp2); Line(Xp1, Yp2, Xp2, Yp1); end; 9 : begin Line(Xp, Yp1, Xp, Yp2); { * } Line(Xp1, Yp, Xp2, Yp); Line(Xp1, Yp1, Xp2, Yp2); Line(Xp1, Yp2, Xp2, Yp1); end; end; end; procedure PlotCurve(X, Y : PVector; Lb, Ub, CurvIndex : Integer); var XI, YI : Float; I, Xp, Yp : Integer; Connect : Boolean; begin Connect := CurvParam^[CurvIndex].LineParam.Style > 0; if Connect then SetLineStyle(Pred(CurvParam^[CurvIndex].LineParam.Style), 0, CurvParam^[CurvIndex].LineParam.Width); I := Lb; repeat XI := X^[I]; if XAxis.Scale = LogScale then XI := Log10(XI); YI := Y^[I]; if YAxis.Scale = LogScale then YI := Log10(YI); Xp := Xpixel(XI); Yp := Ypixel(YI); if Connect then begin SetColor(CurvParam^[CurvIndex].LineParam.Color); if I = Lb then MoveTo(Xp, Yp) else LineTo(Xp, Yp); end; PlotPoint(Xp, Yp, CurvIndex); I := I + CurvParam^[CurvIndex].Step; until I > Ub; end; procedure PlotCurveWithErrorBars(X, Y, S : PVector; Ns, Lb, Ub, CurvIndex : Integer); var Delta, XI, YI, Y1, Y2 : Float; I, Xp, Yp, Yp1, Yp2 : Integer; Connect : Boolean; begin Connect := CurvParam^[CurvIndex].LineParam.Style > 0; SetColor(CurvParam^[CurvIndex].LineParam.Color); I := Lb; repeat XI := X^[I]; if XAxis.Scale = LogScale then XI := Log10(XI); YI := Y^[I]; if YAxis.Scale = LogScale then YI := Log10(YI); Xp := Xpixel(XI); Yp := Ypixel(YI); PlotPoint(Xp, Yp, CurvIndex); if S^[I] > 0 then begin Delta := Ns * S^[I]; Y1 := Y^[I] - Delta; if YAxis.Scale = LogScale then Y1 := Log10(Y1); Y2 := Y^[I] + Delta; if YAxis.Scale = LogScale then Y2 := Log10(Y2); Yp1 := Ypixel(Y1); Yp2 := Ypixel(Y2); SetColor(CurvParam^[CurvIndex].LineParam.Color); SetLineStyle(SolidLn, 0, CurvParam^[CurvIndex].LineParam.Width); Line(Xp - 5, Yp1, Xp + 5, Yp1); Line(Xp - 5, Yp2, Xp + 5, Yp2); Line(Xp, Yp1, Xp, Yp2); end; if Connect then begin SetLineStyle(Pred(CurvParam^[CurvIndex].LineParam.Style), 0, CurvParam^[CurvIndex].LineParam.Width); if I = Lb then MoveTo(Xp, Yp) else LineTo(Xp, Yp); end; I := I + CurvParam^[CurvIndex].Step; until I > Ub; end; procedure PlotFunc(Func : TFunc; X1, X2 : Float; CurvIndex : Integer); var X, Y, H : Float; I, Npt, Xp, Yp : Integer; begin if X1 >= X2 then Exit; if XAxis.Scale = LogScale then begin X1 := Log10(X1); X2 := Log10(X2); end; SetColor(CurvParam^[CurvIndex].LineParam.Color); SetLineStyle(Pred(CurvParam^[CurvIndex].LineParam.Style), 0, CurvParam^[CurvIndex].LineParam.Width); { Nb of points to be plotted = number of pixels between X1 and X2 } Npt := Xpixel(X2) - Xpixel(X1); H := (X2 - X1) / Npt; X := X1; for I := 0 to Npt do begin if XAxis.Scale = LinScale then Y := Func(X) else Y := Func(Exp10(X)); if MathErr = FOk then begin if YAxis.Scale = LogScale then Y := Log10(Y); Xp := Xpixel(X); Yp := Ypixel(Y); if I = 0 then MoveTo(Xp, Yp) else LineTo(Xp, Yp); end; X := X + H; end; end; procedure WriteLegend(NCurv : Integer; ShowPoints, ShowLines : Boolean); var CharHeight, I, L, Lmax : Integer; N, Nmax, Xp, Xl, Yp : Integer; begin SetTextStyle(LgdFont.Index, HorizDir, 1); SetUserCharSize(LgdFont.Width, 100, LgdFont.Height, 100); SetTextJustify(LeftText, CenterText); N := 0; { Nb of legends to be plotted } Lmax := 0; { Length of the longest legend } for I := 1 to NCurv do if CurvParam^[I].Legend <> '' then begin Inc(N); L := TextWidth(CurvParam^[I].Legend); if L > Lmax then Lmax := L; end; if (N = 0) or (Lmax = 0) then Exit; { Character height } CharHeight := TextHeight('M') + 3; { Max. number of legends which may be plotted } Nmax := Round((YmaxPixel - YminPixel) / CharHeight) - 1; if N > Nmax then N := Nmax; { Draw rectangle around the legends } Rectangle(XmaxPixel + Round(0.02 * GetMaxX), YminPixel, XmaxPixel + Round(0.12 * GetMaxX) + Lmax, YminPixel + (N + 1) * CharHeight); L := Round(0.02 * GetMaxX); { Half-length of line } Xp := XmaxPixel + 3 * L; { Position of symbol } Xl := XmaxPixel + 5 * L; { Position of legend } if NCurv <= Nmax then N := NCurv else N := Nmax; for I := 1 to N do begin Yp := YminPixel + I * CharHeight; if ShowLines and (CurvParam^[I].LineParam.Style > 0) then begin SetLineStyle(Pred(CurvParam^[I].LineParam.Style), 0, CurvParam^[I].LineParam.Width); SetColor(CurvParam^[I].LineParam.Color); Line(Xp - L, Yp, Xp + L, Yp); end; if ShowPoints then PlotPoint(Xp, Yp, I); OutTextXY(Xl, Yp, CurvParam^[I].Legend); end; end; procedure ConRec(Nx, Ny, Nc : Integer; X, Y, Z : PVector; F : PMatrix); const { Mapping from vertex numbers to X offsets } Im : array[0..3] of Integer = (0, 1, 1, 0); { Mapping from vertex numbers to Y offsets } Jm : array[0..3] of Integer = (0, 0, 1, 1); { Case switch table } CasTab : array[0..2, 0..2, 0..2] of Integer = (((0,0,8), (0,2,5), (7,6,9)), ((0,3,4), (1,3,1), (4,3,0)), ((9,6,7), (5,2,0), (8,0,0))); var I, J, K, M, M1, M2, M3 : Integer; X1, X2, Y1, Y2 : Float; Fmin, Fmax : Float; Xp, Yp : PIntVector; PrmErr : Boolean; var H : array[0..4] of Float; { Relative heights of the box above contour } Ish : array[0..4] of Integer; { Sign of H() } Xh : array[0..4] of Integer; { X coordinates of box } Yh : array[0..4] of Integer; { Y coordinates of box } label Case0, NoneInTri, NoneInBox; begin { Check the input parameters for validity } PrmErr := False; SetErrCode(MatOk); if (Nx <= 0) or (Ny <= 0) or (Nc <= 0) then PrmErr := True; for K := 1 to Nc - 1 do if Z^[K] <= Z^[K - 1] then PrmErr := True; if PrmErr then begin SetErrCode(MatErrDim); Exit; end; { Convert user coordinates to pixels } DimIntVector(Xp, Nx); DimIntVector(Yp, Ny); for I := 0 to Nx do Xp^[I] := Xpixel(X^[I]); for J := 0 to Ny do Yp^[J] := Ypixel(Y^[J]); { Scan the array, top down, left to right } for J := Ny - 1 downto 0 do begin for I := 0 to Nx - 1 do begin { Find the lowest vertex } if F^[I]^[J] < F^[I]^[J + 1] then Fmin := F^[I]^[J] else Fmin := F^[I]^[J + 1]; if F^[I + 1]^[J] < Fmin then Fmin := F^[I + 1]^[J]; if F^[I + 1]^[J + 1] < Fmin then Fmin := F^[I + 1]^[J + 1]; { Find the highest vertex } if F^[I]^[J] > F^[I]^[J + 1] then Fmax := F^[I]^[J] else Fmax := F^[I]^[J + 1]; if F^[I + 1]^[J] > Fmax then Fmax := F^[I + 1]^[J]; if F^[I + 1]^[J + 1] > Fmax then Fmax := F^[I + 1]^[J + 1]; if (Fmax < Z^[0]) or (Fmin > Z^[Nc - 1]) then goto NoneInBox; { Draw each contour within this box } for K := 0 to Nc - 1 do begin if (Z^[K] < Fmin) or (Z^[K] > Fmax) then goto NoneInTri; for M := 4 downto 0 do begin if M > 0 then begin H[M] := F^[I + Im[M - 1]]^[J + Jm[M - 1]] - Z^[K]; Xh[M] := Xp^[I + Im[M - 1]]; Yh[M] := Yp^[J + Jm[M - 1]]; end; if M = 0 then begin H[0] := (H[1] + H[2] + H[3] + H[4]) / 4; Xh[0] := (Xp^[I] + Xp^[I + 1]) div 2; Yh[0] := (Yp^[J] + Yp^[J + 1]) div 2; end; if H[M] > 0 then Ish[M] := 2; if H[M] < 0 then Ish[M] := 0; if H[M] = 0 then Ish[M] := 1; end; { next M } { Scan each triangle in the box } for M := 1 to 4 do begin M1 := M; M2 := 0; M3 := M + 1; if M3 = 5 then M3 := 1; case CasTab[Ish[M1], Ish[M2], Ish[M3]] of 0 : goto Case0; { Line between vertices M1 and M2 } 1 : begin X1 := Xh[M1]; Y1 := Yh[M1]; X2 := Xh[M2]; Y2 := Yh[M2]; end; { Line between vertices M2 and M3 } 2 : begin X1 := Xh[M2]; Y1 := Yh[M2]; X2 := Xh[M3]; Y2 := Yh[M3]; end; { Line between vertices M3 and M1 } 3 : begin X1 := Xh[M3]; Y1 := Yh[M3]; X2 := Xh[M1]; Y2 := Yh[M1]; end; { Line between vertex M1 and side M2-M3 } 4 : begin X1 := Xh[M1]; Y1 := Yh[M1]; X2 := (H[M3] * Xh[M2] - H[M2] * Xh[M3]) / (H[M3] - H[M2]); Y2 := (H[M3] * Yh[M2] - H[M2] * Yh[M3]) / (H[M3] - H[M2]); end; { Line between vertex M2 and side M3-M1 } 5 : begin X1 := Xh[M2]; Y1 := Yh[M2]; X2 := (H[M1] * Xh[M3] - H[M3] * Xh[M1]) / (H[M1] - H[M3]); Y2 := (H[M1] * Yh[M3] - H[M3] * Yh[M1]) / (H[M1] - H[M3]); end; { Line between vertex M3 and side M1-M2 } 6 : begin X1 := Xh[M3]; Y1 := Yh[M3]; X2 := (H[M2] * Xh[M1] - H[M1] * Xh[M2]) / (H[M2] - H[M1]); Y2 := (H[M2] * Yh[M1] - H[M1] * Yh[M2]) / (H[M2] - H[M1]); end; { Line between sides M1-M2 and M2-M3 } 7 : begin X1 := (H[M2] * Xh[M1] - H[M1] * Xh[M2]) / (H[M2] - H[M1]); Y1 := (H[M2] * Yh[M1] - H[M1] * Yh[M2]) / (H[M2] - H[M1]); X2 := (H[M3] * Xh[M2] - H[M2] * Xh[M3]) / (H[M3] - H[M2]); Y2 := (H[M3] * Yh[M2] - H[M2] * Yh[M3]) / (H[M3] - H[M2]); end; { Line between sides M2-M3 and M3-M1 } 8 : begin X1 := (H[M3] * Xh[M2] - H[M2] * Xh[M3]) / (H[M3] - H[M2]); Y1 := (H[M3] * Yh[M2] - H[M2] * Yh[M3]) / (H[M3] - H[M2]); X2 := (H[M1] * Xh[M3] - H[M3] * Xh[M1]) / (H[M1] - H[M3]); Y2 := (H[M1] * Yh[M3] - H[M3] * Yh[M1]) / (H[M1] - H[M3]); end; { Line between sides M3-M1 and M1-M2 } 9 : begin X1 := (H[M1] * Xh[M3] - H[M3] * Xh[M1]) / (H[M1] - H[M3]); Y1 := (H[M1] * Yh[M3] - H[M3] * Yh[M1]) / (H[M1] - H[M3]); X2 := (H[M2] * Xh[M1] - H[M1] * Xh[M2]) / (H[M2] - H[M1]); Y2 := (H[M2] * Yh[M1] - H[M1] * Yh[M2]) / (H[M2] - H[M1]); end; end; { case } SetColor(CurvParam^[K mod MaxCurv + 1].LineParam.Color); Line(Trunc(X1), Trunc(Y1), Trunc(X2), Trunc(Y2)); Case0: end; { next M } NoneInTri: end; { next K } NoneInBox: end; { next I } end; { next J } end; procedure LeaveGraphics; begin DelCurvParamVector(CurvParam, MaxCurv); CloseGraph; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ugenalg.pas�������������������������������������������������0000755�0001750�0001750�00000023116�11326425444�017621� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Optimization by Genetic Algorithm ****************************************************************** Ref.: E. Perrin, A. Mandrille, M. Oumoun, C. Fonteix & I. Marc Optimisation globale par strategie d'evolution Technique utilisant la genetique des individus diploides Recherche operationnelle / Operations Research 1997, 31, 161-201 Thanks to Magali Camut for her contribution ****************************************************************** } unit ugenalg; interface uses utypes, uminmax, urandom; procedure InitGAParams(NP, NG : Integer; SR, MR, HR : Float); { ------------------------------------------------------------------ Initialize Genetic Algorithm parameters ------------------------------------------------------------------ NP : Population size NG : Max number of generations SR : Survival rate MR : Mutation rate HR : Proportion of homozygotes ------------------------------------------------------------------ } procedure GA_CreateLogFile(LogFileName : String); { ------------------------------------------------------------------ Initialize log file ------------------------------------------------------------------ } procedure GenAlg(Func : TFuncNVar; X, Xmin, Xmax : PVector; Lb, Ub : Integer; var F_min : Float); { ------------------------------------------------------------------ Minimization of a function of several variables by genetic algorithm ------------------------------------------------------------------ Input parameters : Func = objective function to be minimized X = initial minimum coordinates Xmin = minimum value of X Xmax = maximum value of X Lb, Ub = ------------------------------------------------------------------ Output parameters: X = refined minimum coordinates F_min = function value at minimum ------------------------------------------------------------------ } implementation const GA_NP : Integer = 200; { Population size } GA_NG : Integer = 40; { Max number of generations } GA_SR : Float = 0.6; { Survival rate } GA_MR : Float = 0.1; { Mutation rate } GA_HR : Float = 0.5; { Proportion of homozygotes } WriteLogFile : Boolean = False; var LogFile : Text; procedure InitGAParams(NP, NG : Integer; SR, MR, HR : Float); begin if NP > 0 then GA_NP := NP; if NG > 0 then GA_NG := NG; if (SR > 0.0) and (SR < 1.0) then GA_SR := SR; if (MR > 0.0) and (MR < 1.0) then GA_MR := MR; if (HR > 0.0) and (HR < 1.0) then GA_HR := HR; end; procedure GA_CreateLogFile(LogFileName : String); begin Assign(LogFile, LogFileName); Rewrite(LogFile); Writeln(LogFile, 'Genetic Algorithm'); Writeln(LogFile, ' Iter F '); WriteLogFile := True; end; procedure Mutate(I : Integer; C1, C2, D, P : PMatrix; Xmin, Range : PVector; Lb, Ub : Integer); { ------------------------------------------------------------------ Mutate individual I ------------------------------------------------------------------ } var J : Integer; begin for J := Lb to Ub do begin C1^[I]^[J] := Xmin^[J] + RanGen3 * Range^[J]; C2^[I]^[J] := Xmin^[J] + RanGen3 * Range^[J]; D^[I]^[J] := RanGen3; P^[I]^[J] := D^[I]^[J] * C1^[I]^[J] + (1.0 - D^[I]^[J]) * C2^[I]^[J]; end; end; procedure Cross(I1, I2, I : Integer; C1, C2, D, P : PMatrix; Lb, Ub : Integer); { ------------------------------------------------------------------ Cross two individuals I1 and I2 --> new individual I ------------------------------------------------------------------ } var J, K : Integer; begin for J := Lb to Ub do begin if RanGen3 < 0.5 then K := I1 else K := I2; C1^[I]^[J] := C1^[K]^[J]; if RanGen3 < 0.5 then K := I1 else K := I2; C2^[I]^[J] := C2^[K]^[J]; D^[I]^[J] := RanGen3; P^[I]^[J] := D^[I]^[J] * C1^[I]^[J] + (1.0 - D^[I]^[J]) * C2^[I]^[J]; end; end; procedure Homozygote(I : Integer; C1, C2, P : PMatrix; Lb, Ub : Integer); { ------------------------------------------------------------------ Make individual I homozygous ------------------------------------------------------------------ } var J : Integer; begin for J := Lb to Ub do begin C1^[I]^[J] := P^[I]^[J]; C2^[I]^[J] := P^[I]^[J]; end; end; function GA_Func(Func : TFuncNVar; I : Integer; P : PMatrix; Lb, Ub : Integer) : Float; { ------------------------------------------------------------------ Computes objective function for individual I ------------------------------------------------------------------ } var J : Integer; X : PVector; begin DimVector(X, Ub); for J := Lb to Ub do X^[J] := P^[I]^[J]; GA_Func := Func(X); DelVector(X, Ub); end; procedure CompFunc(Func : TFuncNVar; X : PVector; C1, C2, D, P : PMatrix; F : PVector; Lb, Ub : Integer; var Iter : Integer; var F_min : Float); { ------------------------------------------------------------------ Computes function values ------------------------------------------------------------------ } var I, J, K : Integer; A : Float; begin { Compute function values } for I := 1 to GA_NP do F^[I] := GA_Func(Func, I, P, Lb, Ub); { Sort population according to function values } for I := 1 to GA_NP - 1 do begin K := I; A := F^[I]; for J := I + 1 to GA_NP do if F^[J] < A then begin K := J; A := F^[J]; end; FSwap(F^[I], F^[K]); for J := Lb to Ub do begin FSwap(C1^[I]^[J], C1^[K]^[J]); FSwap(C2^[I]^[J], C2^[K]^[J]); FSwap(D^[I]^[J], D^[K]^[J]); FSwap(P^[I]^[J], P^[K]^[J]); end; end; { Update log file if necessary } if WriteLogFile then Writeln(LogFile, Iter:5, F^[1]:12); { Update minimum } if F^[1] < F_min then begin F_min := F^[1]; for J := Lb to Ub do X^[J] := P^[1]^[J]; end; Inc(Iter); end; procedure GenPop(Func : TFuncNVar; NS : Integer; C1, C2, D, P : PMatrix; F, Xmin, Range : PVector; Lb, Ub : Integer); { ------------------------------------------------------------------ Generates new population ------------------------------------------------------------------ } var I, I1, I2 : Integer; F0 : Float; begin for I := NS + 1 to GA_NP do begin I1 := Trunc(RanGen3 * NS) + 1; repeat I2 := Trunc(RanGen3 * NS) + 1 until I2 <> I1; F0 := FMax(F^[I1], F^[I2]); repeat Cross(I1, I2, I, C1, C2, D, P, Lb, Ub); until GA_Func(Func, I, P, Lb, Ub) <= F0; end; for I := 1 to GA_NP do begin if RanGen3 < GA_MR then Mutate(I, C1, C2, D, P, Xmin, Range, Lb, Ub); if RanGen3 < GA_HR then Homozygote(I, C1, C2, P, Lb, Ub); end; end; procedure GenAlg(Func : TFuncNVar; X, Xmin, Xmax : PVector; Lb, Ub : Integer; var F_min : Float); { ------------------------------------------------------------------ Minimization of a function of several variables by genetic algorithm ------------------------------------------------------------------ Input parameters : Func = objective function to be minimized X = initial minimum coordinates Xmin = minimum value of X Xmax = maximum value of X Lb, Ub = ------------------------------------------------------------------ Output parameters: X = refined minimum coordinates F_min = function value at minimum ------------------------------------------------------------------ } var I, NS, Iter : Integer; C1, C2, D, P : PMatrix; Range, F : PVector; begin SetErrCode(OptOk); { Initialize the random number generator using the standard generator } Randomize; InitGen(Trunc(Random * 1.0E+8)); { Dimension arrays } DimMatrix(C1, GA_NP, Ub); DimMatrix(C2, GA_NP, Ub); DimMatrix(D, GA_NP, Ub); DimMatrix(P, GA_NP, Ub); DimVector(F, GA_NP); DimVector(Range, Ub); for I := Lb to Ub do Range^[I] := Xmax^[I] - Xmin^[I]; NS := Trunc(GA_NP * GA_SR); { Number of survivors } Iter := 0; F_min := MaxNum; for I := 1 to GA_NP do Mutate(I, C1, C2, D, P, Xmin, Range, Lb, Ub); CompFunc(Func, X, C1, C2, D, P, F, Lb, Ub, Iter, F_min); for I := 1 to GA_NG do begin GenPop(Func, NS, C1, C2, D, P, F, Xmin, Range, Lb, Ub); CompFunc(Func, X, C1, C2, D, P, F, Lb, Ub, Iter, F_min); end; if WriteLogFile then begin Close(LogFile); WriteLogFile := False; end; DelMatrix(C1, GA_NP, Ub); DelMatrix(C2, GA_NP, Ub); DelMatrix(D, GA_NP, Ub); DelMatrix(P, GA_NP, Ub); DelVector(F, GA_NP); DelVector(Range, Ub); end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/utypes.pas��������������������������������������������������0000755�0001750�0001750�00000027306�11326425446�017537� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Types and constants - Error handling - Dynamic arrays ****************************************************************** The default real type is DOUBLE (8-byte real). Other types may be selected by defining the symbols: SINGLEREAL (Single precision, 4 bytes) EXTENDEDREAL (Extended precision, 12 bytes) ****************************************************************** } unit utypes; interface {$i types.inc} {$ifdef fpc} {$mode delphi} {$endif} { ------------------------------------------------------------------ Error handling ------------------------------------------------------------------ } procedure SetErrCode(ErrCode : Integer); { Sets the error code } function DefaultVal(ErrCode : Integer; DefVal : Float) : Float; { Sets error code and default function value } function MathErr : Integer; { Returns the error code } { ------------------------------------------------------------------ Dynamic arrays ------------------------------------------------------------------ } procedure SetAutoInit(AutoInit : Boolean); { Sets the auto-initialization of arrays } procedure DimVector(var V : PVector; Ub : Integer); { Creates floating point vector V[0..Ub] } procedure DimIntVector(var V : PIntVector; Ub : Integer); { Creates integer vector V[0..Ub] } procedure DimCompVector(var V : PCompVector; Ub : Integer); { Creates complex vector V[0..Ub] } procedure DimBoolVector(var V : PBoolVector; Ub : Integer); { Creates boolean vector V[0..Ub] } procedure DimStrVector(var V : PStrVector; Ub : Integer); { Creates string vector V[0..Ub] } procedure DimMatrix(var A : PMatrix; Ub1, Ub2 : Integer); { Creates floating point matrix A[0..Ub1, 0..Ub2] } procedure DimIntMatrix(var A : PIntMatrix; Ub1, Ub2 : Integer); { Creates integer matrix A[0..Ub1, 0..Ub2] } procedure DimCompMatrix(var A : PCompMatrix; Ub1, Ub2 : Integer); { Creates complex matrix A[0..Ub1, 0..Ub2] } procedure DimBoolMatrix(var A : PBoolMatrix; Ub1, Ub2 : Integer); { Creates boolean matrix A[0..Ub1, 0..Ub2] } procedure DimStrMatrix(var A : PStrMatrix; Ub1, Ub2 : Integer); { Creates string matrix A[0..Ub1, 0..Ub2] } procedure DelVector(var V : PVector; Ub : Integer); { Deletes floating point vector V[0..Ub] } procedure DelIntVector(var V : PIntVector; Ub : Integer); { Deletes integer vector V[0..Ub] } procedure DelCompVector(var V : PCompVector; Ub : Integer); { Deletes complex vector V[0..Ub] } procedure DelBoolVector(var V : PBoolVector; Ub : Integer); { Deletes boolean vector V[0..Ub] } procedure DelStrVector(var V : PStrVector; Ub : Integer); { Deletes string vector V[0..Ub] } procedure DelMatrix(var A : PMatrix; Ub1, Ub2 : Integer); { Deletes floating point matrix A[0..Ub1, 0..Ub2] } procedure DelIntMatrix(var A : PIntMatrix; Ub1, Ub2 : Integer); { Deletes integer matrix A[0..Ub1, 0..Ub2] } procedure DelCompMatrix(var A : PCompMatrix; Ub1, Ub2 : Integer); { Deletes complex matrix A[0..Ub1, 0..Ub2] } procedure DelBoolMatrix(var A : PBoolMatrix; Ub1, Ub2 : Integer); { Deletes boolean matrix A[0..Ub1, 0..Ub2] } procedure DelStrMatrix(var A : PStrMatrix; Ub1, Ub2 : Integer); { Deletes string matrix A[0..Ub1, 0..Ub2] } implementation const gAutoInit : Boolean = True; var gErrCode : Integer; procedure SetErrCode(ErrCode : Integer); begin gErrCode := ErrCode; end; function DefaultVal(ErrCode : Integer; DefVal : Float) : Float; begin SetErrCode(ErrCode); DefaultVal := DefVal; end; function MathErr : Integer; begin MathErr := gErrCode; end; procedure SetAutoInit(AutoInit : Boolean); begin gAutoInit := AutoInit; end; procedure DimVector(var V : PVector; Ub : Integer); var I : Integer; begin { Check bounds } if (Ub < 0) or (Ub > MAX_FLT) then begin V := nil; Exit; end; { Allocate vector } GetMem(V, (Ub + 1) * FltSize); if V = nil then Exit; { Initialize vector } if gAutoInit then for I := 0 to Ub do V^[I] := 0.0; end; procedure DimIntVector(var V : PIntVector; Ub : Integer); var I : Integer; begin { Check bounds } if (Ub < 0) or (Ub > MAX_INT) then begin V := nil; Exit; end; { Allocate vector } GetMem(V, (Ub + 1) * IntSize); if V = nil then Exit; { Initialize vector } if gAutoInit then for I := 0 to Ub do V^[I] := 0; end; procedure DimCompVector(var V : PCompVector; Ub : Integer); var I : Integer; begin { Check bounds } if (Ub < 0) or (Ub > MAX_COMP) then begin V := nil; Exit; end; { Allocate vector } GetMem(V, (Ub + 1) * CompSize); if V = nil then Exit; { Initialize vector } if gAutoInit then for I := 0 to Ub do begin V^[I].X := 0.0; V^[I].Y := 0.0; end; end; procedure DimBoolVector(var V : PBoolVector; Ub : Integer); var I : Integer; begin { Check bounds } if (Ub < 0) or (Ub > MAX_BOOL) then begin V := nil; Exit; end; { Allocate vector } GetMem(V, (Ub + 1) * BoolSize); if V = nil then Exit; { Initialize vector } if gAutoInit then for I := 0 to Ub do V^[I] := False; end; procedure DimStrVector(var V : PStrVector; Ub : Integer); var I : Integer; begin { Check bounds } if (Ub < 0) or (Ub > MAX_STR) then begin V := nil; Exit; end; { Allocate vector } GetMem(V, (Ub + 1) * StrSize); if V = nil then Exit; { Initialize vector } if gAutoInit then for I := 0 to Ub do V^[I] := ''; end; procedure DimMatrix(var A : PMatrix; Ub1, Ub2 : Integer); var I, J : Integer; RowSize : Word; begin if (Ub1 < 0) or (Ub1 > MAX_VEC) or (Ub2 < 0) or (Ub2 > MAX_FLT) then begin A := nil; Exit; end; { Allocate matrix } GetMem(A, (Ub1 + 1) * PtrSize); if A = nil then Exit; { Size of a row } RowSize := (Ub2 + 1) * FltSize; { Allocate each row } for I := 0 to Ub1 do begin GetMem(A^[I], RowSize); if A^[I] = nil then begin A := nil; Exit; end; end; { Initialize matrix } if gAutoInit then for I := 0 to Ub1 do for J := 0 to Ub2 do A^[I]^[J] := 0.0; end; procedure DimIntMatrix(var A : PIntMatrix; Ub1, Ub2 : Integer); var I, J : Integer; RowSize : Word; begin { Check bounds } if (Ub1 < 0) or (Ub1 > MAX_VEC) or (Ub2 < 0) or (Ub2 > MAX_INT) then begin A := nil; Exit; end; { Allocate matrix } GetMem(A, (Ub1 + 1) * PtrSize); if A = nil then Exit; { Size of a row } RowSize := (Ub2 + 1) * IntSize; { Allocate each row } for I := 0 to Ub1 do begin GetMem(A^[I], RowSize); if A^[I] = nil then begin A := nil; Exit; end; end; { Initialize matrix } if gAutoInit then for I := 0 to Ub1 do for J := 0 to Ub2 do A^[I]^[J] := 0; end; procedure DimCompMatrix(var A : PCompMatrix; Ub1, Ub2 : Integer); var I, J : Integer; RowSize : Word; begin { Check bounds } if (Ub1 < 0) or (Ub1 > MAX_VEC) or (Ub2 < 0) or (Ub2 > MAX_COMP) then begin A := nil; Exit; end; { Allocate matrix } GetMem(A, (Ub1 + 1) * PtrSize); if A = nil then Exit; { Size of a row } RowSize := (Ub2 + 1) * CompSize; { Allocate each row } for I := 0 to Ub1 do begin GetMem(A^[I], RowSize); if A^[I] = nil then begin A := nil; Exit; end; end; { Initialize matrix } if gAutoInit then for I := 0 to Ub1 do for J := 0 to Ub2 do begin A^[I]^[J].X := 0.0; A^[I]^[J].Y := 0.0; end; end; procedure DimBoolMatrix(var A : PBoolMatrix; Ub1, Ub2 : Integer); var I, J : Integer; RowSize : Word; begin { Check bounds } if (Ub1 < 0) or (Ub1 > MAX_VEC) or (Ub2 < 0) or (Ub2 > MAX_BOOL) then begin A := nil; Exit; end; { Allocate matrix } GetMem(A, (Ub1 + 1) * PtrSize); if A = nil then Exit; { Size of a row } RowSize := (Ub2 + 1) * BoolSize; { Allocate each row } for I := 0 to Ub1 do begin GetMem(A^[I], RowSize); if A^[I] = nil then begin A := nil; Exit; end; end; { Initialize matrix } if gAutoInit then for I := 0 to Ub1 do for J := 0 to Ub2 do A^[I]^[J] := False; end; procedure DimStrMatrix(var A : PStrMatrix; Ub1, Ub2 : Integer); var I, J : Integer; RowSize : Word; begin { Check bounds } if (Ub1 < 0) or (Ub1 > MAX_VEC) or (Ub2 < 0) or (Ub2 > MAX_STR) then begin A := nil; Exit; end; { Allocate matrix } GetMem(A, (Ub1 + 1) * PtrSize); if A = nil then Exit; { Size of a row } RowSize := (Ub2 + 1) * StrSize; { Allocate each row } for I := 0 to Ub1 do begin GetMem(A^[I], RowSize); if A^[I] = nil then begin A := nil; Exit; end; end; { Initialize matrix } if gAutoInit then for I := 0 to Ub1 do for J := 0 to Ub2 do A^[I]^[J] := ''; end; procedure DelVector(var V : PVector; Ub : Integer); begin if V <> nil then begin FreeMem(V, (Ub + 1) * FltSize); V := nil; end; end; procedure DelIntVector(var V : PIntVector; Ub : Integer); begin if V <> nil then begin FreeMem(V, (Ub + 1) * IntSize); V := nil; end; end; procedure DelCompVector(var V : PCompVector; Ub : Integer); begin if V <> nil then begin FreeMem(V, (Ub + 1) * CompSize); V := nil; end; end; procedure DelBoolVector(var V : PBoolVector; Ub : Integer); begin if V <> nil then begin FreeMem(V, (Ub + 1) * BoolSize); V := nil; end; end; procedure DelStrVector(var V : PStrVector; Ub : Integer); begin if V <> nil then begin FreeMem(V, (Ub + 1) * StrSize); V := nil; end; end; procedure DelMatrix(var A : PMatrix; Ub1, Ub2 : Integer); var I : Integer; RowSize : Word; begin if A <> nil then begin RowSize := (Ub2 + 1) * FltSize; for I := Ub1 downto 0 do FreeMem(A^[I], RowSize); FreeMem(A, (Ub1 + 1) * PtrSize); A := nil; end; end; procedure DelIntMatrix(var A : PIntMatrix; Ub1, Ub2 : Integer); var I : Integer; RowSize : Word; begin if A <> nil then begin RowSize := (Ub2 + 1) * IntSize; for I := Ub1 downto 0 do FreeMem(A^[I], RowSize); FreeMem(A, (Ub1 + 1) * PtrSize); A := nil; end; end; procedure DelCompMatrix(var A : PCompMatrix; Ub1, Ub2 : Integer); var I : Integer; RowSize : Word; begin if A <> nil then begin RowSize := (Ub2 + 1) * CompSize; for I := Ub1 downto 0 do FreeMem(A^[I], RowSize); FreeMem(A, (Ub1 + 1) * PtrSize); A := nil; end; end; procedure DelBoolMatrix(var A : PBoolMatrix; Ub1, Ub2 : Integer); var I : Integer; RowSize : Word; begin if A <> nil then begin RowSize := (Ub2 + 1) * BoolSize; for I := Ub1 downto 0 do FreeMem(A^[I], RowSize); FreeMem(A, (Ub1 + 1) * PtrSize); A := nil; end; end; procedure DelStrMatrix(var A : PStrMatrix; Ub1, Ub2 : Integer); var I : Integer; RowSize : Word; begin if A <> nil then begin RowSize := (Ub2 + 1) * StrSize; for I := Ub1 downto 0 do FreeMem(A^[I], RowSize); FreeMem(A, (Ub1 + 1) * PtrSize); A := nil; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/unonpar.pas�������������������������������������������������0000755�0001750�0001750�00000012762�11326425446�017670� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Non-parametric tests ****************************************************************** } unit unonpar; interface uses utypes; procedure Mann_Whitney(N1, N2 : Integer; X1, X2 : PVector; var U, Eps : Float); { ------------------------------------------------------------------ Mann-Whitney test ------------------------------------------------------------------ } procedure Wilcoxon(X, Y : PVector; Lb, Ub : Integer; var Ndiff : Integer; var T, Eps : Float); { ------------------------------------------------------------------ Wilcoxon test ------------------------------------------------------------------ } procedure Kruskal_Wallis(Ns : Integer; N : PIntVector; X : PMatrix; var H : Float; var DoF : Integer); { ------------------------------------------------------------------ Kruskal-Wallis test ------------------------------------------------------------------ } implementation procedure Ranks(Ns : Integer; N : PIntVector; X : PMatrix; Sr : PVector; var Corr : Float); { ------------------------------------------------------------------ Compute ranks for non-parametric tests ------------------------------------------------------------------ Sr = sum of ranks for each sample Corr = correction for ties = Sum k(k^2 - 1) k = nb of ties ------------------------------------------------------------------ } var I, J, I1, J1, NI, NE : Integer; Y, Z, R : Float; begin if Ns < 2 then begin SetErrCode(MatErrDim); Exit end; SetErrCode(MatOk); Corr := 0.0; for I := 1 to Ns do Sr^[I] := 0; for I := 1 to Ns do for J := 1 to N^[I] do begin Y := X^[J]^[I]; NE := 0; { Nb of values = Y } NI := 0; { Nb of values < Y } for I1 := 1 to Ns do for J1 := 1 to N^[I1] do begin Z := X^[J1]^[I1]; if Z < Y then Inc(NI) else if Z = Y then Inc(NE); end; R := NI + Succ(NE) / 2; { Mean rank of Y } Sr^[I] := Sr^[I] + R; { Sum of ranks for sample I } if NE > 1 then Corr := Corr + NE * (Sqr(NE) - 1); end; end; procedure Mann_Whitney(N1, N2 : Integer; X1, X2 : PVector; var U, Eps : Float); var Nmax, I : Integer; N : PIntVector; X : PMatrix; Sr : PVector; Sum, Prod, Corr : Float; U1, U2, MU, VU : Float; begin if N1 > N2 then Nmax := N1 else Nmax := N2; DimIntVector(N, 2); DimVector(Sr, 2); DimMatrix(X, Nmax, 2); N^[1] := N1; N^[2] := N2; for I := 1 to N1 do { Copy X1 into first column of X } X^[I]^[1] := X1^[I]; for I := 1 to N2 do { Copy X2 into second column of X } X^[I]^[2] := X2^[I]; Ranks(2, N, X, Sr, Corr); Sum := N1 + N2; Prod := N1 * N2; U1 := Prod + N1 * (N1 + 1) / 2 - Sr^[1]; U2 := Prod + N2 * (N2 + 1) / 2 - Sr^[2]; if U1 > U2 then U := U2 else U := U1; MU := Prod / 2; VU := Prod * ((Sum + 1) - Corr / Sum / (Sum - 1)) / 12; Eps := (U - MU) / Sqrt(VU); DelIntVector(N, 2); DelVector(Sr, 2); DelMatrix(X, Nmax, 2); end; procedure Wilcoxon(X, Y : PVector; Lb, Ub : Integer; var Ndiff : Integer; var T, Eps : Float); var J, J1, J2, N : Integer; Diff, MT, VT, Corr : Float; D : PMatrix; ND : PIntVector; Sr : PVector; begin N := Ub - Lb + 1; DimMatrix(D, N, 2); DimIntVector(ND, 2); DimVector(Sr, 2); J1 := 0; J2 := 0; for J := Lb to Ub do begin Diff := X^[J] - Y^[J]; if Diff < 0 then begin Inc(J1); D^[J1]^[1] := Abs(Diff); { Negative difference } end else if Diff > 0 then begin Inc(J2); D^[J2]^[2] := Diff; { Positive difference } end; end; ND^[1] := J1; { Nb of negative differences } ND^[2] := J2; { Nb of positive differences } Ndiff := J1 + J2; { Nb of non-null differences } Ranks(2, ND, D, Sr, Corr); if Sr^[1] > Sr^[2] then T := Sr^[2] else T := Sr^[1]; MT := N * (N + 1) / 4; VT := MT * (2 * N + 1) / 6 - Corr / 48; Eps := (T - MT) / Sqrt(VT); DelMatrix(D, N, 2); DelIntVector(ND, 2); DelVector(Sr, 2); end; procedure Kruskal_Wallis(Ns : Integer; N : PIntVector; X : PMatrix; var H : Float; var DoF : Integer); var I, NT : Integer; S, Corr : Float; Sr : PVector; begin DimVector(Sr, Ns); Ranks(Ns, N, X, Sr, Corr); S := 0.0; NT := 0; for I := 1 to Ns do begin S := S + Sqr(Sr^[I]) / N^[I]; NT := NT + N^[I]; end; H := 12 * S / NT / (NT + 1) - 3 * (NT + 1); H := H / (1 - Corr / NT / (Sqr(NT) - 1)); DoF := Pred(Ns); DelVector(Sr, Ns); end; end.��������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uminmax.pas�������������������������������������������������0000755�0001750�0001750�00000003771�11326425446�017664� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Minimum, maximum, sign and exchange ****************************************************************** } unit uminmax; interface uses utypes; function FMin(X, Y : Float) : Float; { Minimum of 2 reals } function FMax(X, Y : Float) : Float; { Maximum of 2 reals } function IMin(X, Y : Integer) : Integer; { Minimum of 2 integers } function IMax(X, Y : Integer) : Integer; { Maximum of 2 integers } function Sgn(X : Float) : Integer; { Sign (returns 1 if X = 0) } function Sgn0(X : Float) : Integer; { Sign (returns 0 if X = 0) } function DSgn(A, B : Float) : Float; { Sgn(B) * |A| } procedure FSwap(var X, Y : Float); { Exchange 2 reals } procedure ISwap(var X, Y : Integer); { Exchange 2 integers } implementation function FMin(X, Y : Float) : Float; begin if X <= Y then FMin := X else FMin := Y; end; function FMax(X, Y : Float) : Float; begin if X >= Y then FMax := X else FMax := Y; end; function IMin(X, Y : Integer) : Integer; begin if X <= Y then IMin := X else IMin := Y; end; function IMax(X, Y : Integer) : Integer; begin if X >= Y then IMax := X else IMax := Y; end; function Sgn(X : Float) : Integer; begin if X >= 0.0 then Sgn := 1 else Sgn := - 1; end; function Sgn0(X : Float) : Integer; begin if X > 0.0 then Sgn0 := 1 else if X = 0.0 then Sgn0 := 0 else Sgn0 := - 1; end; function DSgn(A, B : Float) : Float; begin if B < 0.0 then DSgn := - Abs(A) else DSgn := Abs(A) end; procedure FSwap(var X, Y : Float); var Temp : Float; begin Temp := X; X := Y; Y := Temp; end; procedure ISwap(var X, Y : Integer); var Temp : Integer; begin Temp := X; X := Y; Y := Temp; end; end. �������mricron-0.20140804.1~dfsg.1.orig/fpmath/ubfgs.pas���������������������������������������������������0000755�0001750�0001750�00000016076�11326425444�017314� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Minimization of a function of several variables by the Broyden-Fletcher-Goldfarb-Shanno (BFGS) method ****************************************************************** } unit ubfgs; interface uses utypes, ulinmin, ucompvec; procedure SaveBFGS(FileName : string); { ------------------------------------------------------------------ Save BFGS iterations in a file ------------------------------------------------------------------ } procedure BFGS(Func : TFuncNVar; Gradient : TGradient; X : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; G : PVector; H_inv : PMatrix); { ------------------------------------------------------------------ Minimization of a function of several variables by the Broyden-Fletcher-Goldfarb-Shanno method ------------------------------------------------------------------ Input parameters : Func = objective function Gradient = procedure to compute gradient X = initial minimum coordinates Lb, Ub = indices of first and last variables MaxIter = maximum number of iterations Tol = required precision ------------------------------------------------------------------ Output parameters : X = refined minimum coordinates F_min = function value at minimum G = gradient vector H_inv = inverse hessian matrix ------------------------------------------------------------------ Possible results : OptOk OptNonConv ---------------------------------------------------------------------- } implementation const WriteLogFile : Boolean = False; var LogFile : Text; procedure SaveBFGS(FileName : string); begin Assign(LogFile, FileName); Rewrite(LogFile); WriteLogFile := True; end; procedure BFGS(Func : TFuncNVar; Gradient : TGradient; X : PVector; Lb, Ub : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; G : PVector; H_inv : PMatrix); var I, J, Iter : Integer; A, DeltaXmax, Gmax, P1, P2, R, R1, R2 : Float; OldX, DeltaX, dX, OldG, dG, HdG, R1dX, R2HdG, U, P2U : PVector; procedure Init; { Initializes Function, Gradient and Inverse Hessian } var I, J : Integer; begin { Initialize function } F_min := Func(X); { Initialize gradient } Gradient(X, G); { Initialize inverse hessian to unit matrix } for I := Lb to Ub do begin H_inv^[I]^[I] := 1.0; for J := I + 1 to Ub do begin H_inv^[I]^[J] := 0.0; H_inv^[J]^[I] := 0.0; end; end; end; procedure Terminate(ErrCode : Integer); { Set error code and deallocate arrays } begin DelVector(OldX, Ub); DelVector(DeltaX, Ub); DelVector(dX, Ub); DelVector(OldG, Ub); DelVector(dG, Ub); DelVector(HdG, Ub); DelVector(R1dX, Ub); DelVector(R2HdG, Ub); DelVector(U, Ub); DelVector(P2U, Ub); SetErrCode(ErrCode); if WriteLogFile then Close(LogFile); end; begin DimVector(OldX, Ub); DimVector(DeltaX, Ub); DimVector(dX, Ub); DimVector(OldG, Ub); DimVector(dG, Ub); DimVector(HdG, Ub); DimVector(R1dX, Ub); DimVector(R2HdG, Ub); DimVector(U, Ub); DimVector(P2U, Ub); Init; if MaxIter < 1 then begin Terminate(OptOk); Exit; end; if WriteLogFile then begin WriteLn(LogFile, 'BFGS'); WriteLn(LogFile, 'Iter F'); end; { Compute max. gradient component } Gmax := Abs(G^[Lb]); for I := Lb + 1 to Ub do begin A := Abs(G^[I]); if A > Gmax then Gmax := A; end; { Quit if gradient is already small } if Gmax < MachEp then begin Terminate(OptOk); Exit; end; { Initialize search direction } for I := Lb to Ub do DeltaX^[I] := - G^[I]; Iter := 0; repeat { Prepare next iteration } if WriteLogFile then WriteLn(LogFile, Iter:4, ' ', F_min:12); Iter := Iter + 1; if Iter > MaxIter then begin Terminate(OptNonConv); Exit; end; { Normalize search direction to avoid excessive displacements } DeltaXmax := Abs(DeltaX^[Lb]); for I := Lb + 1 to Ub do begin A := Abs(DeltaX^[I]); if A > DeltaXmax then DeltaXmax := A; end; if DeltaXmax > 1.0 then for I := Lb to Ub do DeltaX^[I] := DeltaX^[I] / DeltaXmax; { Save old parameters and gradient } for I := Lb to Ub do begin OldX^[I] := X^[I]; OldG^[I] := G^[I]; end; { Minimize along the direction specified by DeltaX } R := 1.0; LinMin(Func, X, DeltaX, Lb, Ub, R, 10, 0.01, F_min); { Compute new gradient } Gradient(X, G); { Compute differences between two successive estimations of parameter vector and gradient vector } for I := Lb to Ub do begin dX^[I] := X^[I] - OldX^[I]; dG^[I] := G^[I] - OldG^[I]; end; { Multiply by inverse hessian } for I := Lb to Ub do begin HdG^[I] := 0.0; for J := Lb to Ub do HdG^[I] := HdG^[I] + H_inv^[I]^[J] * dG^[J]; end; { Scalar products in denominator of BFGS formula } P1 := 0.0; P2 := 0.0; for I := Lb to Ub do begin P1 := P1 + dX^[I] * dG^[I]; P2 := P2 + dG^[I] * HdG^[I]; end; if (P1 = 0.0) or (P2 = 0.0) then Exit; { Inverses of scalar products } R1 := 1.0 / P1; R2 := 1.0 / P2; { Compute BFGS correction terms } for I := Lb to Ub do begin R1dX^[I] := R1 * dX^[I]; R2HdG^[I] := R2 * HdG^[I]; U^[I] := R1dX^[I] - R2HdG^[I]; P2U^[I] := P2 * U^[I]; end; { Update inverse hessian } for I := Lb to Ub do for J := Lb to Ub do H_inv^[I]^[J] := H_inv^[I]^[J] + R1dX^[I] * dX^[J] - R2HdG^[I] * HdG^[J] + P2U^[I] * U^[J]; { Update search direction } for I := Lb to Ub do begin DeltaX^[I] := 0.0; for J := Lb to Ub do DeltaX^[I] := DeltaX^[I] - H_inv^[I]^[J] * G^[J]; end; until CompVec(X, OldX, Lb, Ub, Tol); Terminate(OptOk); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ubinom.pas��������������������������������������������������0000755�0001750�0001750�00000002516�11326425444�017471� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Binomial distribution ****************************************************************** } unit ubinom; interface uses utypes, umath; function Binomial(N, K : Integer) : Float; { Binomial coefficient C(N,K) } function PBinom(N : Integer; P : Float; K : Integer) : Float; { Probability of binomial distribution } implementation function Binomial(N, K : Integer) : Float; var I, N1 : Integer; Prod : Float; begin SetErrCode(FOk); if K < 0 then Binomial := 0.0 else if (K = 0) or (K = N) then Binomial := 1.0 else if (K = 1) or (K = N - 1) then Binomial := N else begin if K > N - K then K := N - K; N1 := Succ(N); Prod := N; for I := 2 to K do Prod := Prod * ((N1 - I) / I); Binomial := Int(0.5 + Prod); end; end; function PBinom(N : Integer; P : Float; K : Integer) : Float; begin SetErrCode(FOk); if (P < 0.0) or (P > 1.0) or (N <= 0) or (N < K) then PBinom := DefaultVal(FDomain, 0.0) else if K = 0 then PBinom := Power(1.0 - P, N) else if K = N then PBinom := Power(P, N) else PBinom := Binomial(N, K) * Power(P, K) * Power(1.0 - P, N - K); end; end.����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ustdpair.pas������������������������������������������������0000755�0001750�0001750�00000003055�11326425446�020034� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Student t-test for paired samples ****************************************************************** } unit ustdpair; interface uses utypes, uminmax, umeansd; procedure StudPaired(X, Y : PVector; Lb, Ub : Integer; var T : Float; var DoF : Integer); { ------------------------------------------------------------------ Student t-test for paired samples ------------------------------------------------------------------ Input parameters : X, Y = samples Lb, Ub = lower and upper bounds Output parameters: T = Student's t DoF = degrees of freedom ------------------------------------------------------------------ } implementation procedure StudPaired(X, Y : PVector; Lb, Ub : Integer; var T : Float; var DoF : Integer); var D : PVector; { Differences between samples } MD, SD : Float; { Mean & std.dev. of differences } N : Integer; { Sample size } I : Integer; { Loop variable } begin DimVector(D, Ub); for I := Lb to Ub do D^[I] := X^[I] - Y^[I]; MD := Mean(D, Lb, Ub); SD := StDev(D, Lb, Ub, MD); if SD = 0.0 then begin T := Sgn(MD) * MaxNum; SetErrCode(FSing); end; DoF := Ub - Lb; { N - 1 } N := DoF + 1; T := MD * Sqrt(N) / SD; DelVector(D, Ub); end; end.�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uigamma.pas�������������������������������������������������0000755�0001750�0001750�00000006063�11326425444�017621� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Incomplete Gamma function and related functions. Translated from C code in Cephes library (http://www.moshier.net) ****************************************************************** } unit uigamma; interface uses utypes, ugamma; function IGamma(A, X : Float) : Float; { Incomplete Gamma function} function JGamma(A, X : Float) : Float; { Complement of incomplete Gamma function } function Erf(X : Float) : Float; { Error function } function Erfc(X : Float) : Float; { Complement of error function } implementation function IGamma(A, X : Float) : Float; var Ans, Ax, C, R : Float; begin SetErrCode(FOk); if (X <= 0.0) or (A <= 0.0) then begin IGamma := 0.0; Exit; end; if (X > 1.0) and (X > A) then begin IGamma := 1.0 - JGamma(A, X); Exit; end; Ax := A * Ln(X) - X - LnGamma(A); if Ax < MinLog then begin IGamma := DefaultVal(FUnderflow, 0.0); Exit; end; Ax := Exp(Ax); { Power series } R := A; C := 1.0; Ans := 1.0; repeat R := R + 1.0; C := C * X / R; Ans := Ans + C; until C / Ans <= MachEp; IGamma := Ans * Ax / A; end; function JGamma(A, X : Float) : Float; const Big = 1.0 / MachEp; var Ans, C, Yc, Ax, Y, Z, R, T, Pk, Pkm1, Pkm2, Qk, Qkm1, Qkm2 : Float; begin SetErrCode(FOk); if (X <= 0.0) or (A <= 0.0) then begin JGamma := 1.0; Exit; end; if (X < 1.0) or (X < A) then begin JGamma := 1.0 - IGamma(A, X); Exit; end; Ax := A * Ln(X) - X - LnGamma(A); if Ax < MinLog then begin JGamma := DefaultVal(FUnderflow, 0.0); Exit; end; Ax := Exp(Ax); { Continued fraction } Y := 1.0 - A; Z := X + Y + 1.0; C := 0.0; Pkm2 := 1.0; Qkm2 := X; Pkm1 := X + 1.0; Qkm1 := Z * X; Ans := Pkm1 / Qkm1; repeat C := C + 1.0; Y := Y + 1.0; Z := Z + 2.0; Yc := Y * C; Pk := Pkm1 * Z - Pkm2 * Yc; Qk := Qkm1 * Z - Qkm2 * Yc; if Qk <> 0.0 then begin R := Pk / Qk; T := Abs((Ans - R) / R); Ans := R; end else T := 1.0; Pkm2 := Pkm1; Pkm1 := Pk; Qkm2 := Qkm1; Qkm1 := Qk; if Abs(Pk) > Big then begin Pkm2 := Pkm2 * MachEp; Pkm1 := Pkm1 * MachEp; Qkm2 := Qkm2 * MachEp; Qkm1 := Qkm1 * MachEp; end; until T <= MachEp; JGamma := Ans * Ax; end; function Erf(X : Float) : Float; begin if X < 0.0 then Erf := - IGamma(0.5, Sqr(X)) else Erf := IGamma(0.5, Sqr(X)); end; function Erfc(X : Float) : Float; begin if X < 0.0 then Erfc := 1.0 + IGamma(0.5, Sqr(X)) else Erfc := JGamma(0.5, Sqr(X)); end; end.�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/urootpol.pas������������������������������������������������0000755�0001750�0001750�00000003125�11326425446�020062� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Roots of a polynomial from the companion matrix ****************************************************************** } unit urootpol; interface uses utypes, ubalance, uhqr; function RootPol(Coef : PVector; Deg : Integer; Z : PCompVector) : Integer; { ------------------------------------------------------------------ Solves the polynomial equation: Coef(0) + Coef(1) * Z + Coef(2) * Z^2 + ... + Coef(Deg) * Z^Deg = 0 ------------------------------------------------------------------ } implementation function RootPol(Coef : PVector; Deg : Integer; Z : PCompVector) : Integer; var Lo, Hi : Integer; { Used by Balance } I, J : Integer; { Loop variables } Nr : Integer; { Number of real roots } A : PMatrix; { Companion matrix } Scale : PVector; { Used by Balance } begin { Dimension arrays } DimMatrix(A, Deg, Deg); DimVector(Scale, Deg); { Set up the companion matrix } for J := 1 to Deg do A^[1]^[J] := - Coef^[Deg - J] / Coef^[Deg]; for I := 2 to Deg do for J := 1 to Deg do if I - 1 = J then A^[I]^[J] := 1.0 else A^[I]^[J] := 0.0; { The roots of the polynomial are the eigenvalues of the companion matrix } Balance(A, 1, Deg, Lo, Hi, Scale); Hqr(A, 1, Deg, Lo, Hi, Z); if MathErr <> 0 then begin RootPol := MathErr; Exit; end; { Count real roots } Nr := 0; for I := 1 to Deg do if Z^[I].Y = 0.0 then Nr := Nr + 1; RootPol := Nr end; end.�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ulambert.pas������������������������������������������������0000755�0001750�0001750�00000011157�11326425444�020014� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Lambert's function Translated from Fortran code by Barry et al. (http://www.netlib.org/toms/743) ****************************************************************** } unit ulambert; interface uses utypes, umath; function LambertW(X : Float; UBranch, Offset : Boolean) : Float; { ---------------------------------------------------------------------- Lambert's W function: Y = W(X) ==> X = Y * Exp(Y) X >= -1/e ---------------------------------------------------------------------- X = Argument UBranch = TRUE for computing the upper branch (X >= -1/e, W(X) >= -1) FALSE for computing the lower branch (-1/e <= X < 0, W(X) <= -1) Offset = TRUE for computing W(X - 1/e), X >= 0 FALSE for computing W(X) ---------------------------------------------------------------------- } implementation {$IFDEF SINGLEREAL} const NBITS = 23; { MachEp = 2^(-NBITS) } X0 = 0.03507693900966790567; { MachEp^(1/6) / 2 } X1 = -0.30212011943278473033; { - Exp(-1) * (1 - 17 * MachEp^(2/7) } {$ELSE} {$IFDEF EXTENDEDREAL} const NBITS = 63; X0 = 0.0003452669830012439084; X1 = -0.36785558424357094358; {$ELSE} const NBITS = 52; X0 = 0.001230391650287962075; X1 = -0.36766871970031223379; {$ENDIF} {$ENDIF} const EM = -0.36787944117144232160; { - Exp(-1) } EM9 = -0.0001234098040866795495; { - Exp(-9) } C13 = 1.0 / 3.0; C23 = 2.0 * C13; EM2 = 2.0 / EM; D12 = - EM2; AN3 = 8.0 / 3.0; AN4 = 135.0 / 83.0; AN5 = 166.0 / 39.0; AN6 = 3167.0 / 3549.0; S21 = 2.0 * Sqrt2 - 3.0; S22 = 4.0 - 3.0 * Sqrt2; S23 = Sqrt2 - 2.0; function LambertW(X : Float; UBranch, Offset : Boolean) : Float; var I, NITER : Integer; AN2, DELX, ETA, RETA, T, TEMP, TEMP2, TS, WAPR, XX, ZL, ZN : Float; begin SetErrCode(FOk); if Offset then begin DELX := X; if DELX < 0.0 then begin LambertW := DefaultVal(FDomain, 0.0); Exit; end; XX := X + EM; end else begin if X < EM then begin LambertW := DefaultVal(FDomain, 0.0); Exit; end; if X = EM then begin LambertW := - 1.0; Exit; end; XX := X; DELX := XX - EM; end; if UBranch then begin if Abs(XX) <= X0 then begin LambertW := XX / (1.0 + XX / (1.0 + XX / (2.0 + XX / (0.6 + 0.34 * XX)))); Exit; end; if XX <= X1 then begin RETA := Sqrt(D12 * DELX); LambertW := RETA / (1.0 + RETA / (3.0 + RETA / (RETA / (AN4 + RETA / (RETA * AN6 + AN5)) + AN3))) - 1.0; Exit; end; if XX <= 20.0 then begin RETA := Sqrt2 * Sqrt(1.0 - XX / EM); AN2 := 4.612634277343749 * Sqrt(Sqrt(RETA + 1.09556884765625)); WAPR := RETA / (1.0 + RETA / (3.0 + (S21 * AN2 + S22) * RETA / (S23 * (AN2 + RETA)))) - 1.0; end else begin ZL := Ln(XX); WAPR := Ln(XX / Ln(XX / Power(ZL, Exp(- 1.124491989777808 / (0.4225028202459761 + ZL))))); end end else begin if XX >= 0.0 then begin LambertW := DefaultVal(FDomain, 0.0); Exit; end; if XX <= X1 then begin RETA := Sqrt(D12 * DELX); LambertW := RETA / (RETA / (3.0 + RETA / (RETA / (AN4 + RETA / (RETA * AN6 - AN5)) - AN3)) - 1.0) - 1.0; Exit; end; ZL := Ln(- XX); if XX <= EM9 then begin T := - 1.0 - ZL; TS := Sqrt(T); WAPR := ZL - (2.0 * TS) / (SQRT2 + (C13 - T / (2.7E2 + TS * 127.0471381349219)) * TS); end else begin ETA := 2.0 - EM2 * XX; WAPR := Ln(XX / Ln(- XX / ((1.0 - 0.5043921323068457 * (ZL + 1.0)) * (Sqrt(ETA) + ETA / 3.0) + 1.0))); end end; if NBITS < 56 then NITER := 1 else NITER := 2; for I := 1 to NITER do begin ZN := Ln(XX / WAPR) - WAPR; TEMP := 1.0 + WAPR; TEMP2 := TEMP + C23 * ZN; TEMP2 := 2.0 * TEMP * TEMP2; WAPR := WAPR * (1.0 + (ZN / TEMP) * (TEMP2 - ZN) / (TEMP2 - 2.0 * ZN)); end; LambertW := WAPR; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uibtdist.pas������������������������������������������������0000755�0001750�0001750�00000004710�11326425444�020025� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Probability functions related to the incomplete Beta function ****************************************************************** } unit uibtdist; interface uses utypes, umath, uibeta; function FBeta(A, B, X : Float) : Float; { Cumulative probability for Beta distrib. with param. A and B } function FBinom(N : Integer; P : Float; K : Integer) : Float; { Cumulative probability for binomial distrib. } function FStudent(Nu : Integer; X : Float) : Float; { Cumulative probability for Student distrib. with Nu d.o.f. } function PStudent(Nu : Integer; X : Float) : Float; { Prob(|t| > X) for Student distrib. with Nu d.o.f. } function FSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; { Cumulative prob. for Fisher-Snedecor distrib. with Nu1 and Nu2 d.o.f. } function PSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; { Prob(F > X) for Fisher-Snedecor distrib. with Nu1 and Nu2 d.o.f. } implementation function FBeta(A, B, X : Float) : Float; begin FBeta := IBeta(A, B, X); end; function FBinom(N : Integer; P : Float; K : Integer) : Float; begin if (P < 0.0) or (P > 1.0) or (N <= 0) or (N < K) then FBinom := DefaultVal(FDomain, 0.0) else if K = 0 then FBinom := DefaultVal(FOk, Power(1.0 - P, N)) else if K = N then FBinom := DefaultVal(FOk, 1.0) else FBinom := 1.0 - IBeta(K + 1, N - K, P); end; function FStudent(Nu : Integer; X : Float) : Float; var F : Float; begin if Nu < 1 then FStudent := DefaultVal(FDomain, 0.0) else if X = 0 then FStudent := DefaultVal(FOk, 0.5) else begin F := 0.5 * IBeta(0.5 * Nu, 0.5, Nu / (Nu + X * X)); if X < 0.0 then FStudent := F else FStudent := 1.0 - F; end; end; function PStudent(Nu : Integer; X : Float) : Float; begin if Nu < 1 then PStudent := DefaultVal(FDomain, 0.0) else PStudent := IBeta(0.5 * Nu, 0.5, Nu / (Nu + X * X)); end; function FSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; begin if (Nu1 < 1) or (Nu2 < 1) or (X <= 0) then FSnedecor := DefaultVal(FDomain, 0.0) else FSnedecor := 1.0 - IBeta(0.5 * Nu2, 0.5 * Nu1, Nu2 / (Nu2 + Nu1 * X)); end; function PSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; begin if (Nu1 < 1) or (Nu2 < 1) or (X <= 0) then PSnedecor := DefaultVal(FDomain, 0.0) else PSnedecor := IBeta(0.5 * Nu2, 0.5 * Nu1, Nu2 / (Nu2 + Nu1 * X)); end; end.��������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/umedian.pas�������������������������������������������������0000755�0001750�0001750�00000001566�11326425446�017630� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Median ****************************************************************** } unit umedian; interface uses utypes, uqsort; function Median(X : PVector; Lb, Ub : Integer; Sorted : Boolean) : Float; { ------------------------------------------------------------------ Sorts vector X in ascending order (if it's not sorted already) and returns its median value ------------------------------------------------------------------ } implementation function Median(X : PVector; Lb, Ub : Integer; Sorted : Boolean) : Float; var N, N2 : Integer; begin N := Ub - Lb + 1; N2 := N div 2 + Lb - 1; if not Sorted then QSort(X, Lb, Ub); if Odd(N) then Median := X^[N2 + 1] else Median := 0.5 * (X^[N2] + X^[N2 + 1]); end; end. ������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uhqr2.pas���������������������������������������������������0000755�0001750�0001750�00000036065�11326425444�017247� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Eigenvalues and eigenvectors of a real upper Hessenberg matrix ****************************************************************** } unit uhqr2; interface uses utypes, uminmax; procedure Hqr2(H : PMatrix; Lb, Ub, I_low, I_igh : Integer; Lambda : PCompVector; Z : PMatrix); implementation procedure Hqr2(H : PMatrix; Lb, Ub, I_low, I_igh : Integer; Lambda : PCompVector; Z : PMatrix); { ------------------------------------------------------------------ This function is a translation of the EISPACK subroutine hqr2 This procedure finds the eigenvalues and eigenvectors of a real upper Hessenberg matrix by the QR method. On input: H contains the upper Hessenberg matrix. Lb, Ub are the lowest and highest indices of the elements of H I_low and I_igh are integers determined by the balancing subroutine Balance. If Balance has not been used, set I_low=Lb, I_igh=Ub Z contains the transformation matrix produced by Eltran after the reduction by Elmhes, or by Ortran after the reduction by Orthes, if performed. If the eigenvectors of the Hessenberg matrix are desired, Z must contain the identity matrix. On output: H has been destroyed. Wr and Wi contain the real and imaginary parts, respectively, of the eigenvalues. The eigenvalues are unordered except that complex conjugate pairs of values appear consecutively with the eigenvalue having the positive imaginary part first. Z contains the real and imaginary parts of the eigenvectors. If the i-th eigenvalue is real, the i-th column of Z contains its eigenvector. If the i-th eigenvalue is complex with positive imaginary part, the i-th and (i+1)-th columns of Z contain the real and imaginary parts of its eigenvector. The eigenvectors are unnormalized. If an error exit is made, none of the eigenvectors has been found. The function returns an error code: zero for normal return, -j if the limit of 30*N iterations is exhausted while the j-th eigenvalue is being sought (N being the size of the matrix). The eigenvalues should be correct for indices j+1,...,Ub. ------------------------------------------------------------------ Note: This is a crude translation. Many of the original goto's have been kept ! ------------------------------------------------------------------ } procedure Cdiv(Ar, Ai, Br, Bi : Float; var Cr, Ci : Float); { Complex division, (Cr,Ci) = (Ar,Ai)/(Br,Bi) } var S, Ars, Ais, Brs, Bis : Float; begin S := Abs(Br) + Abs(Bi); Ars := Ar / S; Ais := Ai / S; Brs := Br / S; Bis := Bi / S; S := Sqr(Brs) + Sqr(Bis); Cr := (Ars * Brs + Ais * Bis) / S; Ci := (Ais * Brs - Ars * Bis) / S; end; var I, J, K, L, M, N, En, Na, Itn, Its, Mp2, Enm2 : Integer; P, Q, R, S, T, W, X, Y, Ra, Sa, Vi, Vr, Zz, Norm, Tst1, Tst2 : Float; NotLas : Boolean; label 60, 70, 100, 130, 150, 170, 225, 260, 270, 280, 320, 330, 340, 600, 630, 635, 640, 680, 700, 710, 770, 780, 790, 795, 800; begin { Store roots isolated by Balance and compute matrix norm } K := Lb; Norm := 0.0; for I := Lb to Ub do begin for J := K to Ub do Norm := Norm + Abs(H^[I]^[J]); K := I; if (I < I_low) or (I > I_igh) then begin Lambda^[I].X := H^[I]^[I]; Lambda^[I].Y := 0.0; end; end; N := Ub - Lb + 1; Itn := 30 * N; En := I_igh; T := 0.0; 60: { Search for next eigenvalues } if En < I_low then goto 340; Its := 0; Na := En - 1; Enm2 := Na - 1; 70: { Look for single small sub-diagonal element } for L := En downto I_low do begin if L = I_low then goto 100; S := Abs(H^[L - 1]^[L - 1]) + Abs(H^[L]^[L]); if S = 0.0 then S := Norm; Tst1 := S; Tst2 := Tst1 + Abs(H^[L]^[L - 1]); if Tst2 = Tst1 then goto 100; end; 100: { Form shift } X := H^[En]^[En]; if L = En then goto 270; Y := H^[Na]^[Na]; W := H^[En]^[Na] * H^[Na]^[En]; if L = Na then goto 280; if Itn = 0 then begin { Set error -- all eigenvalues have not converged after 30*N iterations } SetErrCode(- En); Exit; end; if (Its <> 10) and (Its <> 20) then goto 130; { Form exceptional shift } T := T + X; for I := I_low to En do H^[I]^[I] := H^[I]^[I] - X; S := Abs(H^[En]^[Na]) + Abs(H^[Na]^[Enm2]); X := 0.75 * S; Y := X; W := - 0.4375 * S * S; 130: Its := Its + 1; Itn := Itn - 1; { Look for two consecutive small sub-diagonal elements } for M := Enm2 downto L do begin Zz := H^[M]^[M]; R := X - Zz; S := Y - Zz; P := (R * S - W) / H^[M + 1]^[M] + H^[M]^[M + 1]; Q := H^[M + 1]^[M + 1] - Zz - R - S; R := H^[M + 2]^[M + 1]; S := Abs(P) + Abs(Q) + Abs(R); P := P / S; Q := Q / S; R := R / S; if M = L then goto 150; Tst1 := Abs(P) * (Abs(H^[M - 1]^[M - 1]) + Abs(Zz) + Abs(H^[M + 1]^[M + 1])); Tst2 := Tst1 + Abs(H^[M]^[M - 1]) * (Abs(Q) + Abs(R)); if Tst2 = Tst1 then goto 150; end; 150: Mp2 := M + 2; for I := Mp2 to En do begin H^[I]^[I - 2] := 0.0; if I <> Mp2 then H^[I]^[I - 3] := 0.0; end; { Double QR step involving rows L to En and columns M to En } for K := M to Na do begin NotLas := (K <> Na); if (K = M) then goto 170; P := H^[K]^[K - 1]; Q := H^[K + 1]^[K - 1]; R := 0.0; if NotLas then R := H^[K + 2]^[K - 1]; X := Abs(P) + Abs(Q) + Abs(R); if X = 0.0 then goto 260; P := P / X; Q := Q / X; R := R / X; 170: S := DSgn(Sqrt(P * P + Q * Q + R * R), P); if K <> M then H^[K]^[K - 1] := - S * X else if L <> M then H^[K]^[K - 1] := - H^[K]^[K - 1]; P := P + S; X := P / S; Y := Q / S; Zz := R / S; Q := Q / P; R := R / P; if NotLas then goto 225; { Row modification } for J := K to Ub do begin P := H^[K]^[J] + Q * H^[K + 1]^[J]; H^[K]^[J] := H^[K]^[J] - P * X; H^[K + 1]^[J] := H^[K + 1]^[J] - P * Y; end; J := Imin(En, K + 3); { Column modification } for I := Lb to J do begin P := X * H^[I]^[K] + Y * H^[I]^[K + 1]; H^[I]^[K] := H^[I]^[K] - P; H^[I]^[K + 1] := H^[I]^[K + 1] - P * Q; end; { Accumulate transformations } for I := I_low to I_igh do begin P := X * Z^[I]^[K] + Y * Z^[I]^[K + 1]; Z^[I]^[K] := Z^[I]^[K] - P; Z^[I]^[K + 1] := Z^[I]^[K + 1] - P * Q; end; goto 260; 225: { Row modification } for J := K to Ub do begin P := H^[K]^[J] + Q * H^[K + 1]^[J] + R * H^[K + 2]^[J]; H^[K]^[J] := H^[K]^[J] - P * X; H^[K + 1]^[J] := H^[K + 1]^[J] - P * Y; H^[K + 2]^[J] := H^[K + 2]^[J] - P * Zz; end; J := Imin(En, K + 3); { Column modification } for I := Lb to J do begin P := X * H^[I]^[K] + Y * H^[I]^[K + 1] + Zz * H^[I]^[K + 2]; H^[I]^[K] := H^[I]^[K] - P; H^[I]^[K + 1] := H^[I]^[K + 1] - P * Q; H^[I]^[K + 2] := H^[I]^[K + 2] - P * R; end; { Accumulate transformations } for I := I_low to I_igh do begin P := X * Z^[I]^[K] + Y * Z^[I]^[K + 1] + Zz * Z^[I]^[K + 2]; Z^[I]^[K] := Z^[I]^[K] - P; Z^[I]^[K + 1] := Z^[I]^[K + 1] - P * Q; Z^[I]^[K + 2] := Z^[I]^[K + 2] - P * R; end; 260: end; goto 70; 270: { One root found } H^[En]^[En] := X + T; Lambda^[En].X := H^[En]^[En]; Lambda^[En].Y := 0.0; En := Na; goto 60; 280: { Two roots found } P := 0.5 * (Y - X); Q := P * P + W; Zz := Sqrt(Abs(Q)); H^[En]^[En] := X + T; X := H^[En]^[En]; H^[Na]^[Na] := Y + T; if Q < 0.0 then goto 320; { Real pair } Zz := P + DSgn(Zz, P); Lambda^[Na].X := X + Zz; Lambda^[En].X := Lambda^[Na].X; if Zz <> 0.0 then Lambda^[En].X := X - W / Zz; Lambda^[Na].Y := 0.0; Lambda^[En].Y := 0.0; X := H^[En]^[Na]; S := Abs(X) + Abs(Zz); P := X / S; Q := Zz / S; R := Sqrt(P * P + Q * Q); P := P / R; Q := Q / R; { Row modification } for J := Na to Ub do begin Zz := H^[Na]^[J]; H^[Na]^[J] := Q * Zz + P * H^[En]^[J]; H^[En]^[J] := Q * H^[En]^[J] - P * Zz; end; { Column modification } for I := Lb to En do begin Zz := H^[I]^[Na]; H^[I]^[Na] := Q * Zz + P * H^[I]^[En]; H^[I]^[En] := Q * H^[I]^[En] - P * Zz; end; { Accumulate transformations } for I := I_low to I_igh do begin Zz := Z^[I]^[Na]; Z^[I]^[Na] := Q * Zz + P * Z^[I]^[En]; Z^[I]^[En] := Q * Z^[I]^[En] - P * Zz; end; goto 330; 320: { Complex pair } Lambda^[Na].X := X + P; Lambda^[En].X := Lambda^[Na].X; Lambda^[Na].Y := Zz; Lambda^[En].Y := - Zz; 330: En := Enm2; goto 60; 340: if Norm = 0.0 then Exit; { All roots found. Backsubstitute to find vectors of upper triangular form } for En := Ub downto Lb do begin P := Lambda^[En].X; Q := Lambda^[En].Y; Na := En - 1; if Q < 0.0 then goto 710 else if Q = 0.0 then goto 600 else goto 800; 600: { Real vector } M := En; H^[En]^[En] := 1.0; if Na < Lb then goto 800; for I := Na downto Lb do begin W := H^[I]^[I] - P; R := 0.0; for J := M to En do R := R + H^[I]^[J] * H^[J]^[En]; if Lambda^[I].Y >= 0.0 then goto 630; Zz := W; S := R; goto 700; 630: M := I; if Lambda^[I].Y <> 0.0 then goto 640; T := W; if T <> 0.0 then goto 635; Tst1 := Norm; T := Tst1; repeat T := 0.01 * T; Tst2 := Norm + T; until Tst2 <= Tst1; 635: H^[I]^[En] := - R / T; goto 680; 640: { Solve real equations } X := H^[I]^[I + 1]; Y := H^[I + 1]^[I]; Q := Sqr(Lambda^[I].X - P) + Sqr(Lambda^[I].Y); T := (X * S - Zz * R) / Q; H^[I]^[En] := T; if Abs(X) > Abs(Zz) then H^[I + 1]^[En] := (- R - W * T) / X else H^[I + 1]^[En] := (- S - Y * T) / Zz; 680: { Overflow control } T := Abs(H^[I]^[En]); if T = 0.0 then goto 700; Tst1 := T; Tst2 := Tst1 + 1.0 / Tst1; if Tst2 > Tst1 then goto 700; for J := I to En do H^[J]^[En] := H^[J]^[En] / T; 700: end; { End real vector } goto 800; { Complex vector } 710: M := Na; { Last vector component chosen imaginary so that eigenvector matrix is triangular } if Abs(H^[En]^[Na]) > Abs(H^[Na]^[En]) then begin H^[Na]^[Na] := Q / H^[En]^[Na]; H^[Na]^[En] := - (H^[En]^[En] - P) / H^[En]^[Na]; end else Cdiv(0.0, - H^[Na]^[En], H^[Na]^[Na] - P, Q, H^[Na]^[Na], H^[Na]^[En]); H^[En]^[Na] := 0.0; H^[En]^[En] := 1.0; Enm2 := Na - 1; if Enm2 < Lb then goto 800; for I := Enm2 downto Lb do begin W := H^[I]^[I] - P; Ra := 0.0; Sa := 0.0; for J := M to En do begin Ra := Ra + H^[I]^[J] * H^[J]^[Na]; Sa := Sa + H^[I]^[J] * H^[J]^[En]; end; if Lambda^[I].Y >= 0.0 then goto 770; Zz := W; R := Ra; S := Sa; goto 795; 770: M := I; if Lambda^[I].Y <> 0.0 then goto 780; Cdiv(- Ra, - Sa, W, Q, H^[I]^[Na], H^[I]^[En]); goto 790; { Solve complex equations } 780: X := H^[I]^[I + 1]; Y := H^[I + 1]^[I]; Vr := Sqr(Lambda^[I].X - P) + Sqr(Lambda^[I].Y) - Sqr(Q); Vi := (Lambda^[I].X - P) * 2.0 * Q; if (Vr = 0.0) and (Vi = 0.0) then begin Tst1 := Norm * (Abs(W) + Abs(Q) + Abs(X) + Abs(Y) + Abs(Zz)); Vr := Tst1; repeat Vr := 0.01 * Vr; Tst2 := Tst1 + Vr; until Tst2 <= Tst1; end; Cdiv(X * R - Zz * Ra + Q * Sa, X * S - Zz * Sa - Q * Ra, Vr, Vi, H^[I]^[Na], H^[I]^[En]); if Abs(X) > Abs(Zz) + Abs(Q) then begin H^[I + 1]^[Na] := (- Ra - W * H^[I]^[Na] + Q * H^[I]^[En]) / X; H^[I + 1]^[En] := (- Sa - W * H^[I]^[En] - Q * H^[I]^[Na]) / X; end else Cdiv(- R - Y * H^[I]^[Na], - S - Y * H^[I]^[En], Zz, Q, H^[I + 1]^[Na], H^[I + 1]^[En]); 790: { Overflow control } T := FMax(Abs(H^[I]^[Na]), Abs(H^[I]^[En])); if T = 0.0 then goto 795; Tst1 := T; Tst2 := Tst1 + 1.0 / Tst1; if Tst2 > Tst1 then goto 795; for J := I to En do begin H^[J]^[Na] := H^[J]^[Na] / T; H^[J]^[En] := H^[J]^[En] / T; end; 795: end; { End complex vector } 800: end; { End back substitution. Vectors of isolated roots } for I := Lb to Ub do if (I < I_low) or (I > I_igh) then for J := I to Ub do Z^[I]^[J] := H^[I]^[J]; { Multiply by transformation matrix to give vectors of original full matrix. } for J := Ub downto I_low do begin M := Imin(J, I_igh); for I := I_low to I_igh do begin Zz := 0.0; for K := I_low to M do Zz := Zz + Z^[I]^[K] * H^[K]^[J]; Z^[I]^[J] := Zz; end; end; SetErrCode(0); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uexpdist.pas������������������������������������������������0000755�0001750�0001750�00000002216�11326425444�020042� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Exponential distribution ****************************************************************** } unit uexpdist; interface uses utypes; function DExpo(A, X : Float) : Float; { Density of exponential distribution with parameter A } function FExpo(A, X : Float) : Float; { Cumulative probability function for exponential dist. with parameter A } implementation function DExpo(A, X : Float) : Float; var Y : Float; begin if (A <= 0.0) or (X < 0.0) then begin DExpo := DefaultVal(FDomain, 0.0); Exit; end; Y := - A * X; if Y < MinLog then begin DExpo := DefaultVal(FUnderflow, 0.0); Exit; end; SetErrCode(FOk); DExpo := A * Exp(Y); end; function FExpo(A, X : Float) : Float; var Y : Float; begin if (A <= 0.0) or (X < 0.0) then begin FExpo := DefaultVal(FDomain, 0.0); Exit; end; Y := - A * X; if Y < MinLog then begin FExpo := DefaultVal(FUnderflow, 1.0); Exit; end; SetErrCode(FOk); FExpo := 1.0 - Exp(Y); end; end.����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/filelist.txt������������������������������������������������0000755�0001750�0001750�00000051125�11326425444�020047� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Unit Routines Description ----------------------------------------------------------------------- utypes SetErrCode Sets error code * DefaultVal Sets error code and default function value * MathErr Returns the error code * SetAutoInit Sets the auto-initialization of arrays * DimVector Allocates a real vector * DimIntVector Allocates an integer vector * DimCompVector Allocates a complex vector * DimBoolVector Allocates a boolean vector * DimStrVector Allocates a string vector * DimMatrix Allocates a real matrix * DimIntMatrix Allocates an integer matrix * DimCompMatrix Allocates a complex matrix * DimBoolMatrix Allocates a boolean matrix * DimStrMatrix Allocates a string matrix * DelVector Deallocates a real vector * DelIntVector Deallocates an integer vector * DelCompVector Deallocates a complex vector * DelBoolVector Deallocates a boolean vector * DelStrVector Deallocates a string vector * DelMatrix Deallocates a real matrix * DelIntMatrix Deallocates an integer matrix * DelCompMatrix Deallocates a complex matrix * DelBoolMatrix Deallocates a boolean matrix * DelStrMatrix Deallocates a string matrix uminmax FMin Minimum of 2 reals * FMax Maximum of 2 reals * IMin Minimum of 2 integers * IMax Maximum of 2 integers * Sgn Sign, Sgn(0) = 1 * Sgn0 Sign, Sgn(0) = 0 * DSgn DSgn(A, B) = Sgn(B) * |A| * FSwap Exchanges 2 reals * ISwap Exchanges 2 integers uround RoundN Rounds a number to N decimal places * Ceil Ceiling function * Floor Floor function umath Expo Exponential (with bound checking) * Exp2 Exponential, base 2 * Exp10 Exponential, base 10 * Log Natural log (with bound checking) * Log2 Log, base 2 * Log10 Log, base 10 * LogA Log, base A * IntPower Power (integer exponent) * Power Power (real exponent) utrigo Pythag Sqrt(X^2 + Y^2) * FixAngle Set argument in -Pi..Pi * Tan Tangent * ArcSin Arc sinus * ArcCos Arc cosinus * ArcTan2 Angle (Ox, OM) with M(X,Y) uhyper Sinh Hyperbolic sine * Cosh Hyperbolic cosine * Tanh Hyperbolic tangent * ArcSinh Inverse hyperbolic sine * ArcCosh Inverse hyperbolic cosine * ArcTanh Inverse hyperbolic tangent * SinhCosh Sinh and Cosh upolev PolEvl Polynomial evaluation (coeff. of x^n <> 1) * P1Evl Polynomial evaluation (coeff. of x^n = 1) ugamma Gamma Gamma function * LnGamma Logarithm of Gamma function * SgnGamma Sign of Gamma function * Stirling Stirling's formula for Gamma * StirLog Stirling's formula for LnGamma udigamma DiGamma DiGamma function * TriGamma TriGamma function uigamma IGamma Incomplete Gamma function * JGamma Complement of incomplete Gamma function * Erf Error function * Erfc Complement of error function ubeta Beta Beta function uibeta IBeta Incomplete Beta function ulambert LambertW Lambert's W-function ufact Fact Factorial ubinom Binomial Binomial coefficient * PBinom Probability of binomial distribution upoidist PPoisson Probability of Poisson distribution uexpdist DExpo Density of exponential distribution * FExpo Cumulative prob. of exponential dist. unormal DNorm Density of standard normal distribution ugamdist DBeta Density of Beta distribution * DGamma Density of Gamma distribution * DKhi2 Density of Khi-2 distribution * DStudent Density of Student's distribution * DSnedecor Density of Fisher-Snedecor distribution uibtdist FBeta Cumulative prob. of Beta distribution * FBinom Cumulative prob. of Binomial distribution * FStudent Cumulative prob. of Student's distribution * PStudent Prob(|t| > X) for Student's distribution * FSnedecor Cumulative prob. of Fisher-Snedecor distribution * PSnedecor Prob(F > X) for Fisher-Snedecor distribution uigmdist FGamma Cumulative prob. of Gamma distribution * FPoisson Cumulative prob. of Poisson distribution * FNorm Cumulative prob. of standard normal distribution * PNorm Prob(|U| > X) for standard normal distribution * FKhi2 Cumulative prob. of Khi-2 distribution * PKhi2 Prob(Khi2 > X) for Khi-2 distribution uinvnorm InvNorm Inverse of normal distribution uinvgam InvGamma Inverse of incomplete Gamma function * InvKhi2 Inverse of khi-2 distribution uinvbeta InvBeta Inverse of incomplete Beta function * InvStudent Inverse of Student's t-distribution * InvSnedecor Inverse of Snedecor's F-distribution ucompvec CompVec Comparison of two vectors ugausjor GaussJordan Linear equation system (Gauss-Jordan method) ulineq LinEq Linear equation system (Gauss-Jordan method) ucholesk Cholesky Cholesky factorization ulu LU_Decomp LU decomposition * LU_Solve Solves a system of equations after LU decomposition uqr QR_Decomp QR decomposition * QR_Solve Solves a system of equations after QR decomposition usvd SV_Decomp Singular value decomposition * SV_Solve Solves a system of equations after SV decomposition * SV_SetZero Sets the lowest singular values to zero * SV_Approx Approximates a matrix from its SV decomposition ubalance Balance Balances a matrix and tries to isolate eigenvalues ubalbak BalBak Back transformation of eigenvectors uelmhes ElmHes Reduction of a square matrix to upper Hessenberg form ueltran Eltran Save transformations used by ElmHes uhqr Hqr Eigenvalues of a real upper Hessenberg matrix by the QR method uhqr2 Hqr2 Eigenvalues and eigenvectors of a real upper Hessenberg matrix ueigval EigenVals Eigenvalues of a general square matrix ueigvec EigenVect Eigenvalues and eigenvectors of a general square matrix ujacobi Jacobi Eigenvalues and eigenvectors of a symmetric matrix uminbrak MinBrack Brackets a minimum of a function ugoldsrc GoldSearch Minimization of a function of 1 variable (Golden Search method) ulinmin LinMin Minimization of a function of several variables along a line unewton Newton Minimization of a function of several var. (Newton's method) * SaveNewton Save Newton iterations in a file umarq Marquardt Minimization of a function of several var. (Marquardt's method) * SaveMarquardt Save Marquardt iterations in a file ubfgs BFGS Minimization of a function of several var. (BFGS method) * SaveBFGS Save BFGS iterations in a file usimplex Simplex Minimization of a function of several var. (simplex method) * SaveSimplex Save simplex iterations in a file ulinminq LinMinEq Minimization of a sum of squared functions along a line ubisect RootBrack Brackets solution of equation * Bisect Nonlinear equation (bisection method) unewteq NewtEq Nonlinear equation (Newton-Raphson method) usecant Secant Nonlinear equation (secant method) unewteqs NewtEqs Nonlinear equation system (Newton-Raphson method) ubroyden Broyden Nonlinear equation system (Broyden's method) upolynom Poly Evaluates a polynomial * RFrac Evaluates a rational fraction urtpol1 RootPol1 Root of linear equation urtpol2 RootPol2 Roots of quadratic equation urtpol3 RootPol3 Roots of cubic equation urtpol4 RootPol4 Roots of quartic equation urootpol RootPol Roots of polynomial from companion matrix upolutil SetRealRoots Set the imaginary part of a root to zero * SortRoots Sorts the roots of a polynomial utrapint TrapInt Integration by trapezoidal rule ugausleg GausLeg Gauss-Legendre integration * GausLeg0 Gauss-Legendre integration (lower bound=0) * Convol Convolution product urkf RKF45 Integration of a system of differential equations ufft FFT Fast Fourier Transform * IFFT Inverse Fast Fourier Transform * FFT_Integer Fast Fourier Transform for integer data * FFT_Integer_Cleanup Clear memory after a call to FFT_Integer * CalcFrequency Direct computation of Fourier Transform urandom SetRNG Select random number generator * InitGen Initialize random number generator * IRanGen 32-bit random integer in [-2^31 .. 2^31 - 1] * IRanGen31 31-bit random integer in [0 .. 2^31 - 1] * RanGen1 32-bit random real in [0,1] * RanGen2 32-bit random real in [0,1) * RanGen3 32-bit random real in (0,1) * RanGen53 53-bit random real in [0,1) uranmwc InitMWC Initialize Multiply-With-Carry generator * IRanMWC 32-bit random integer from MWC generator uranmt InitMT Initialize Mersenne Twister generator with a seed * InitMTbyArray Initialize MT generator with an array * IRanMT 32-bit random integer from MT generator uranuvag InitUVAG Initialize UVAG generator with a seed * InitUVAGbyString Initialize UVAG generator with a string * IRanUVAG 32-bit random integer from UVAG generator urangaus RanGaussStd Random number from standard normal distribution * RanGauss Random number from normal distribution uranmult RanMult Random vector from multinormal distrib. (correlated) * RanMultIndep Random vector from multinormal distrib. (uncorrelated) umcmc InitMHParams Initialize Metropolis-Hastings parameters * GetMHParams Returns Metropolis-Hastings parameters * Hastings Simulation of a p.d.f. by Metropolis-Hastings usimann InitSAParams Initialize Simulated Annealing parameters * SA_CreateLogFile Initialize log file for Simulated Annealing * SimAnn Minimization of a function of several var. by Simulated Annealing ugenalg InitGAParams Initialize Genetic Algorithm parameters * GA_CreateLogFile Initialize log file for Genetic Algorithm * GenAlg Minimization of a function of several var. by Genetic Algorithm umeansd Mean Sample mean * StDev Standard deviation estimated from sample * StDevP Standard deviation of population ucorrel Correl Correlation coefficient umedian Median Sample median uskew Skewness Sample skewness * Kurtosis Sample kurtosis uqsort QSort Quick sort (ascending order) * DQSort Quick sort (descending order) uinterv Interval Determines an interval for a set of values ustudind StudIndep Student t-test for independent samples ustdpair StudPaired Student t-test for paired samples uanova1 AnOVa1 One-way analysis of variance uanova2 AnOVa2 Two-way analysis of variance usnedeco Snedecor Comparison of two variances ubartlet Bartlett Comparison of several variances ukhi2 Khi2_Conform Khi-2 test for conformity * Khi2_Indep Khi-2 test for independence uwoolf Woolf_Conform Woolf's test for conformity * Woolf_Indep Woolf's test for independence unonpar Mann_Whitney Mann-Whitney test * Wilcoxon Wilcoxon test * Kruskal_Wallis Kruskal-Wallis test udistrib DimStatClassVector Allocates an array of statistical classes * DelStatClassVector Deallocates an array of statistical classes * Distrib Distributes an array into statistical classes ulinfit LinFit Linear regression * WLinFit Weighted linear regression upolfit PolFit Polynomial regression * WPolFit Weighted polynomial regression umulfit MulFit Multiple regression (Gauss-Jordan method) * WMulFit Weighted multiple regression (Gauss-Jordan method) usvdfit SVDFit Multiple regression (SVD method) * WSVDFit Weighted multiple regression (SVD method) unlfit SetOptAlgo Selects optimization algorithm for nonlinear regression * SetMaxParam Sets the maximal number of regression parameters * SetParamBounds Sets the bounds on a regression parameter * SetMCFile Set file for saving MCMC simulations * NLFit Nonlinear regression * WNLFit Weighted nonlinear regression * SimFit Simulation of unweighted nonlinear regression by MCMC * WSimFit Simulation of weighted nonlinear regression by MCMC uregtest RegTest Test of unweighted regression * WRegTest Test of weighted regression upca VecMean Computes mean vector } * VecSD Computes vector of standard deviations } * MatVarCov Computes variance-covariance matrix } * MatCorrel Computes correlation matrix } * PCA Principal component analysis of correlation matrix } * ScaleVar Scales a set of variables } * PrinFac Computes principal factors } ustrings LTrim Remove leading blanks * RTrim Remove trailing blanks * Trim Remove leading and trailing blanks * StrChar Generate string by repeating a character * RFill Complete string with trailing blanks * LFill Complete string with leading blanks * CFill Center string * Replace Replace a character * Extract Extract field from string * Parse Parse string into several fields * SetFormat Set numeric format * FloatStr Convert real number to string * IntStr Convert integer to string * CompStr Convert complex number to string uplot InitGraphics Initializes the graphic * SetWindow Sets the graphic window * AutoScale Automatic scale determination * SetOxScale Sets the scale on the Ox axis * SetOyScale Sets the scale on the Oy axis * SetGraphTitle Sets the graph title * SetOxTitle Sets the title for the Ox axis * SetOyTitle Sets the title for the Oy axis * SetTitleFont Sets the font for the main graph title * SetOxFont Sets the font for the Ox axis * SetOyFont Sets the font for the Oy axis * SetLgdFont Sets the font for the legends * PlotOxAxis Plots the Ox axis * PlotOyAxis Plots the Oy axis * WriteGraphTitle Writes title of graph * PlotGrid Plots a grid on the graph * SetClipping Limits the graphic to the current viewport * SetMaxCurv Sets maximum number of curves * SetPointParam Sets point parameters * SetLineParam Sets line parameters * SetCurvLegend Sets curve legend * SetCurvStep Sets curve step * PlotPoint Plots a point * PlotCurve Plots a curve * PlotCurveWithErrorBars Plots a curve with error bars * PlotFunc Plots a function * WriteLegend Writes the legends for the plotted curves * ConRec Contour plot * Xpixel Converts user abscissa X to screen coordinate * Ypixel Converts user ordinate Y to screen coordinate * Xuser Converts screen coordinate X to user abscissa * Yuser Converts screen coordinate Y to user ordinate * LeaveGraphics Quits the graphic mode �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uqsort.pas��������������������������������������������������0000755�0001750�0001750�00000004015�11326425446�017533� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Quick sort ****************************************************************** } unit uqsort; interface uses utypes; procedure QSort(X : PVector; Lb, Ub : Integer); { ------------------------------------------------------------------ Sorts the elements of vector X in increasing order (quick sort) ------------------------------------------------------------------ } procedure DQSort(X : PVector; Lb, Ub : Integer); { ------------------------------------------------------------------ Sorts the elements of vector X in decreasing order (quick sort) ------------------------------------------------------------------ } implementation procedure QSort(X : PVector; Lb, Ub : Integer); { Quick sort in ascending order - Adapted from Borland's BP7 demo } procedure Sort(L, R : Integer); var I, J : Integer; U, V : Float; begin I := L; J := R; U := X^[(L + R) div 2]; repeat while X^[I] < U do I := I + 1; while U < X^[J] do J := J - 1; if I <= J then begin V := X^[I]; X^[I] := X^[J]; X^[J] := V; I := I + 1; J := J - 1; end; until I > J; if L < J then Sort(L, J); if I < R then Sort(I, R); end; begin Sort(Lb, Ub); end; procedure DQSort(X : PVector; Lb, Ub : Integer); { Quick sort in descending order - Adapted from Borland's BP7 demo } procedure Sort(L, R : Integer); var I, J : Integer; U, V : Float; begin I := L; J := R; U := X^[(L + R) div 2]; repeat while X^[I] > U do I := I + 1; while U > X^[J] do J := J - 1; if I <= J then begin V := X^[I]; X^[I] := X^[J]; X^[J] := V; I := I + 1; J := J - 1; end; until I > J; if L < J then Sort(L, J); if I < R then Sort(I, R); end; begin Sort(Lb, Ub); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ubisect.pas�������������������������������������������������0000755�0001750�0001750�00000004044�11326425444�017634� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Bisection method for nonlinear equation ****************************************************************** } unit ubisect; interface uses utypes; procedure RootBrack(Func : TFunc; var X, Y, FX, FY : Float); { ------------------------------------------------------------------ Expands the interval [X,Y] until it contains a root of Func, i. e. Func(X) and Func(Y) have opposite signs. The corresponding function values are returned in FX and FY. ------------------------------------------------------------------ } procedure Bisect (Func : TFunc; var X, Y : Float; MaxIter : Integer; Tol : Float; var F : Float); implementation procedure RootBrack(Func : TFunc; var X, Y, FX, FY : Float); begin FX := Func(X); FY := Func(Y); while FX * FY > 0 do if Abs(FX) < Abs(FY) then begin X := X + Gold * (X - Y); FX := Func(X) end else begin Y := Y + Gold * (Y - X); FY := Func(Y) end; end; procedure Bisect (Func : TFunc; var X, Y : Float; MaxIter : Integer; Tol : Float; var F : Float); var Iter : Integer; G, Z, FZ : Float; begin Iter := 0; SetErrCode(OptOk); F := Func(X); if MaxIter < 1 then Exit; G := Func(Y); if F * G >= 0 then RootBrack(Func, X, Y, F, G); repeat Iter := Iter + 1; if Iter > MaxIter then begin SetErrCode(OptNonConv); Exit; end; Z := 0.5 * (X + Y); FZ := Func(Z); if F * FZ > 0 then begin X := Z; F := FZ; end else begin Y := Z; G := FZ; end; until Abs(X - Y) < Tol * (Abs(X) + Abs(Y)); X := 0.5 * (X + Y); F := Func(X); end; end.��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ubeta.pas���������������������������������������������������0000755�0001750�0001750�00000001704�11326425444�017276� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Beta function ****************************************************************** } unit ubeta; interface uses utypes, ugamma; function Beta(X, Y : Float) : Float; implementation function Beta(X, Y : Float) : Float; { Computes Beta(X, Y) = Gamma(X) * Gamma(Y) / Gamma(X + Y) } var Lx, Ly, Lxy : Float; SgnBeta : Integer; begin SetErrCode(FOk); SgnBeta := SgnGamma(X) * SgnGamma(Y) * SgnGamma(X + Y); Lxy := LnGamma(X + Y); if MathErr <> FOk then begin Beta := 0.0; Exit; end; Lx := LnGamma(X); if MathErr <> FOk then begin Beta := SgnBeta * MaxNum; Exit; end; Ly := LnGamma(Y); if MathErr <> FOk then begin Beta := SgnBeta * MaxNum; Exit; end; Beta := SgnBeta * Exp(Lx + Ly - Lxy); end; end.������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/uelmhes.pas�������������������������������������������������0000755�0001750�0001750�00000006075�11326425444�017646� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Reduction of a square matrix to upper Hessenberg form ****************************************************************** } unit uelmhes; interface uses utypes; procedure ElmHes(A : PMatrix; Lb, Ub, I_low, I_igh : Integer; I_int : PIntVector); implementation procedure ElmHes(A : PMatrix; Lb, Ub, I_low, I_igh : Integer; I_int : PIntVector); { ------------------------------------------------------------------ This procedure is a translation of the EISPACK subroutine Elmhes Given a real general matrix, this procedure reduces a submatrix situated in rows and columns I_low through I_igh to upper Hessenberg form by stabilized elementary similarity transformations. On input: A contains the input matrix. Lb, Ub are the lowest and highest indices of the elements of A. I_low and I_igh are integers determined by the balancing procedure Balance. If Balance has not been used, set I_low = Lb, I_igh = Ub. On output: A contains the Hessenberg matrix. The multipliers which were used in the reduction are stored in the remaining triangle under the Hessenberg matrix. I_int contains information on the rows and columns interchanged in the reduction. Only elements I_low through I_igh are used. ------------------------------------------------------------------ } var I, J, M, La, Kp1, Mm1, Mp1 : Integer; X, Y : Float; begin La := I_igh - 1; Kp1 := I_low + 1; if La < Kp1 then Exit; for M := Kp1 to La do begin Mm1 := M - 1; X := 0.0; I := M; for J := M to I_igh do if Abs(A^[J]^[Mm1]) > Abs(X) then begin X := A^[J]^[Mm1]; I := J; end; I_int^[M] := I; { Interchange rows and columns of A } if I <> M then begin for J := Mm1 to Ub do begin Y := A^[I]^[J]; A^[I]^[J] := A^[M]^[J]; A^[M]^[J] := Y; end; for J := Lb to I_igh do begin Y := A^[J]^[I]; A^[J]^[I] := A^[J]^[M]; A^[J]^[M] := Y; end; end; if X <> 0.0 then begin Mp1 := M + 1; for I := Mp1 to I_igh do begin Y := A^[I]^[Mm1]; if Y <> 0.0 then begin Y := Y / X; A^[I]^[Mm1] := Y; for J := M to Ub do A^[I]^[J] := A^[I]^[J] - Y * A^[M]^[J]; for J := Lb to I_igh do A^[J]^[M] := A^[J]^[M] + Y * A^[J]^[I]; end; end; end; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ustrings.pas������������������������������������������������0000755�0001750�0001750�00000020506�11326425446�020057� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Pascal string routines ****************************************************************** } unit ustrings; interface uses utypes; function LTrim(S : String) : String; { ------------------------------------------------------------------ Removes leading blanks ------------------------------------------------------------------ } function RTrim(S : String) : String; { ------------------------------------------------------------------ Removes trailing blanks ------------------------------------------------------------------ } function Trim(S : String) : String; { ------------------------------------------------------------------ Removes leading and trailing blanks ------------------------------------------------------------------ } function StrChar(N : Byte; C : Char) : String; { ------------------------------------------------------------------ Returns a string made of character C repeated N times ------------------------------------------------------------------ } function RFill(S : String; L : Byte) : String; { ------------------------------------------------------------------ Completes string S with trailing blanks for a total length L ------------------------------------------------------------------ } function LFill(S : String; L : Byte) : String; { ------------------------------------------------------------------ Completes string S with leading blanks for a total length L ------------------------------------------------------------------ } function CFill(S : String; L : Byte) : String; { ------------------------------------------------------------------ Completes string S with leading blanks to center the string on a total length L ------------------------------------------------------------------ } function Replace(S : String; C1, C2 : Char) : String; { ------------------------------------------------------------------ Replaces in string S all the occurences of character C1 by character C2 ------------------------------------------------------------------ } function Extract(S : String; var Index : Byte; Delim : Char) : String; { ------------------------------------------------------------------ Extracts a field from a string. Index is the position of the first character of the field. Delim is the character used to separate fields (e.g. blank, comma or tabulation). Blanks immediately following Delim are ignored. Index is updated to the position of the next field. ------------------------------------------------------------------ } procedure Parse(S : String; Delim : Char; Field : PStrVector; var N : Byte); { ------------------------------------------------------------------ Parses a string into its constitutive fields. Delim is the field separator. The number of fields is returned in N. The fields are returned in Field^[0]..Field^[N - 1]. Field must be dimensioned in the calling program. ------------------------------------------------------------------ } procedure SetFormat(NumLength, MaxDec : Integer; FloatPoint, NSZero : Boolean); { ------------------------------------------------------------------ Sets the numeric format NumLength = Length of numeric field MaxDec = Max. number of decimal places FloatPoint = True for floating point notation NSZero = True to write non significant zero's ------------------------------------------------------------------ } function FloatStr(X : Float) : String; { ------------------------------------------------------------------ Converts a real to a string according to the numeric format ------------------------------------------------------------------ } function IntStr(N : LongInt) : String; { ------------------------------------------------------------------ Converts an integer to a string ------------------------------------------------------------------ } function CompStr(Z : Complex) : String; { ------------------------------------------------------------------ Converts a complex number to a string ------------------------------------------------------------------ } implementation const gNumLength : Integer = 10; gMaxDec : Integer = 4; gFloatPoint : Boolean = False; gNSZero : Boolean = False; function LTrim(S : String) : String; begin if S <> '' then repeat if S[1] = ' ' then Delete(S, 1, 1); until S[1] <> ' '; LTrim := S; end; function RTrim(S : String) : String; var L1 : Byte; begin if S <> '' then repeat L1 := Length(S); if S[L1] = ' ' then Delete(S, L1, 1); until S[L1] <> ' '; RTrim := S; end; function Trim(S : String) : String; begin Trim := LTrim(RTrim(S)); end; function StrChar(N : Byte; C : Char) : String; var I : Byte; S : String; begin S := ''; for I := 1 to N do S := S + C; StrChar := S; end; function RFill(S : String; L : Byte) : String; var L1 : Byte; begin L1 := Length(S); if L1 >= L then RFill := S else RFill := S + StrChar(L - L1, ' '); end; function LFill(S : String; L : Byte) : String; var L1 : Byte; begin L1 := Length(S); if L1 >= L then LFill := S else LFill := StrChar(L - L1, ' ') + S; end; function CFill(S : String; L : Byte) : String; var L1 : Byte; begin L1 := Length(S); if L1 >= L then CFill := S else CFill := StrChar((L - L1) div 2, ' ') + S; end; function Replace(S : String; C1, C2 : Char) : String; var S1 : String; K : Byte; begin S1 := S; K := Pos(C1, S1); while K > 0 do begin S1[K] := C2; K := Pos(C1, S1); end; Replace := S1; end; function Extract(S : String; var Index : Byte; Delim : Char) : String; var I, L : Byte; begin I := Index; L := Length(S); { Search for Delim } while (I <= L) and (S[I] <> Delim) do Inc(I); { Extract field } if I = Index then Extract := '' else Extract := Copy(S, Index, I - Index); { Skip blanks after Delim } repeat Inc(I); until (I > L) or (S[I] <> ' '); { Update Index } Index := I; end; procedure Parse(S : String; Delim : Char; Field : PStrVector; var N : Byte); var I, Index, L : Byte; begin I := 0; Index := 1; L := Length(S); repeat Field^[I] := Extract(S, Index, Delim); Inc(I); until Index > L; N := I; end; procedure SetFormat(NumLength, MaxDec : Integer; FloatPoint, NSZero : Boolean); begin if (NumLength >= 1) and (NumLength <= 80) then gNumLength := NumLength; if (MaxDec >= 0) and (MaxDec <= 20) then gMaxDec := MaxDec; gFloatPoint := FloatPoint; gNSZero := NSZero; end; function RemZero(S : String) : String; var I : Integer; S1, S2 : String; C : Char; begin I := Pos('.', S); if I = 0 then begin RemZero := S; Exit end; I := Pos('E', S); if I = 0 then I := Pos('e', S); if I > 0 then begin S1 := Copy(S, 1, I - 1); S2 := Copy(S, I, Length(S) - I + 1) end else begin S1 := S; S2 := '' end; repeat I := Length(S1); C := S1[I]; if (C = '0') or (C = '.') then S1 := Copy(S1, 1, I - 1) until C <> '0'; RemZero := S1 + S2 end; function FloatStr(X : Float) : String; var S : String; begin if gFloatPoint then begin Str(X:Pred(gNumLength), S); S := ' ' + S; end else Str(X:gNumLength:gMaxDec, S); if not gNSZero then S := RemZero(S); FloatStr := S; end; function IntStr(N : LongInt) : String; var S : String; begin Str(N:(gNumLength - gMaxDec - 1), S); IntStr := S; end; function CompStr(Z : Complex) : String; var S : String; begin if Z.Y >= 0.0 then S := ' + ' else S := ' - '; CompStr := FloatStr(Z.X) + S + FloatStr(Abs(Z.Y)) + ' * i'; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpmath/ulinminq.pas������������������������������������������������0000755�0001750�0001750�00000011461�11326425444�020033� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ****************************************************************** Minimization of a sum of squared functions along a line (Used internally by equation solvers) ****************************************************************** } unit ulinminq; interface uses utypes; procedure LinMinEq(Equations : TEquations; X, DeltaX, F : PVector; Lb, Ub : Integer; R : Float; MaxIter : Integer; Tol : Float); { ------------------------------------------------------------------ Minimizes a sum of squared functions from point X in the direction specified by DeltaX, using golden search as the minimization algo. ------------------------------------------------------------------ Input parameters : SysFunc = system of functions X = starting point DeltaX = search direction Lb, Ub = bounds of X R = initial step, in fraction of |DeltaX| MaxIter = maximum number of iterations Tol = required precision ------------------------------------------------------------------ Output parameters: X = refined minimum coordinates F = function values at minimum R = step corresponding to the minimum ------------------------------------------------------------------ Possible results : OptOk = no error OptNonConv = non-convergence ------------------------------------------------------------------ } implementation procedure LinMinEq(Equations : TEquations; X, DeltaX, F : PVector; Lb, Ub : Integer; R : Float; MaxIter : Integer; Tol : Float); var I, Iter : Integer; A, B, C, Fa, Fb, Fc : Float; R0, R1, R2, R3, F1, F2 : Float; MinTol, Norm : Float; P : PVector; procedure Swap2(var A, B, Fa, Fb : Float); { Exchanges A <--> B, Fa <--> Fb } var Temp : Float; begin Temp := A; A := B; B := Temp; Temp := Fa; Fa := Fb; Fb := Temp; end; function SumSqrFn : Float; { Computes the sum of squared functions F(i)^2 at point P } var Sum : Float; I : Integer; begin Equations(P, F); Sum := 0.0; for I := Lb to Ub do Sum := Sum + Sqr(F^[I]); SumSqrFn := Sum; end; begin DimVector(P, Ub); MinTol := Sqrt(MachEp); if Tol < MinTol then Tol := MinTol; if R <= 0.0 then R := 1.0; Norm := 0.0; for I := Lb to Ub do Norm := Norm + Sqr(DeltaX^[I]); Norm := Sqrt(Norm); { Bracket the minimum } A := 0.0; B := R * Norm; for I := Lb to Ub do P^[I] := X^[I]; Fa := SumSqrFn; for I := Lb to Ub do P^[I] := X^[I] + B * DeltaX^[I]; Fb := SumSqrFn; if Fb > Fa then Swap2(A, B, Fa, Fb); C := B + Gold * (B - A); for I := Lb to Ub do P^[I] := X^[I] + C * DeltaX^[I]; Fc := SumSqrFn; while Fc < Fb do begin A := B; B := C; Fa := Fb; Fb := Fc; C := B + Gold * (B - A); for I := Lb to Ub do P^[I] := X^[I] + C * DeltaX^[I]; Fc := SumSqrFn; end; if A > C then Swap2(A, C, Fa, Fc); { Refine the minimum } R0 := A; R3 := C; if (C - B) > (B - A) then begin R1 := B; R2 := B + CGold * (C - B); F1 := Fb; for I := Lb to Ub do P^[I] := X^[I] + R2 * DeltaX^[I]; F2 := SumSqrFn; end else begin R1 := B - CGold * (B - A); R2 := B; for I := Lb to Ub do P^[I] := X^[I] + R1 * DeltaX^[I]; F1 := SumSqrFn; F2 := Fb; end; Iter := 0; while (Iter <= MaxIter) and (Abs(R3 - R0) > Tol * (Abs(R1) + Abs(R2))) do begin if F2 < F1 then begin R0 := R1; R1 := R2; F1 := F2; R2 := R1 + CGold * (R3 - R1); for I := Lb to Ub do P^[I] := X^[I] + R2 * DeltaX^[I]; F2 := SumSqrFn; end else begin R3 := R2; R2 := R1; F2 := F1; R1 := R2 - CGold * (R2 - R0); for I := Lb to Ub do P^[I] := X^[I] + R1 * DeltaX^[I]; F1 := SumSqrFn end; Iter := Iter + 1; end; if F1 < F2 then R := R1 else R := R2; for I := Lb to Ub do X^[I] := X^[I] + R * DeltaX^[I]; Equations(X, F); if Iter > MaxIter then SetErrCode(OptNonConv) else SetErrCode(OptOk); DelVector(P, Ub); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/RenderThds.pas�����������������������������������������������������0000755�0001750�0001750�00000053363�11641437500�016765� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit RenderThds; interface {$include isthreaded.inc} {$mode delphi} uses {$IFDEF UNIX} lclintf,//critical sections {$ELSE} Windows, {$ENDIF} ComCtrls,Classes, Graphics, ExtCtrls, define_types,GraphicsMathLibrary ,sysutils; const kSh = 10; //bits to shift - precision for integers to simulate floats var ThreadsRunning: Integer = 0; type TRotateVals = record InSliceSz,ZDimStart,ZDimEnd,YDimStart,YDimEnd,OutPivot,OutDim,OutSliceSz: integer; XPivotInU2,YDimIN,YPivotInU2,ZDimIN,ZPivotInU2,XDimIN: integer; XPivotIn,YPivotIn,ZPivotIn: integer; Xxra,Xyra,Xzra: longintp; //RenderCutout: boolean; end; TRenderThread = class(TThread) private lBarX: TProgressBar; lRV: TRotateVals; lMx : TMatrix; lThreadX: integer; lRenderCutoutX: boolean; lBuffInX,lBuffOutX: ByteP; lPosX: integer; procedure DoVisualSwap; protected procedure Execute; override; procedure VisualProg(lPos: Integer); procedure Rotate(lThread: integer; l: TRotateVals; var lM: TMatrix; lRenderCutout: boolean; var lBuffIn,lBuffOut: ByteP); virtual; abstract; public constructor Create(lBar: TProgressBar; lThread: integer; l: TRotateVals; var lM: TMatrix; lRenderCutout: boolean; var lBuffIn,lBuffOut: ByteP); end; { NearestNeighbor } TNNRender = class(TRenderThread) protected procedure Rotate(lThread: integer;l: TRotateVals; var lM: TMatrix; lRenderCutout: boolean; var lBuffIn,lBuffOut: ByteP); override; end; { Trilinear } TTriRender = class(TRenderThread) protected procedure Rotate(lThread: integer;l: TRotateVals; var lM: TMatrix; lRenderCutout: boolean; var lBuffIn,lBuffOut: ByteP); override; end; implementation uses Render; var {$IFDEF UNIX} {$ifdef cpux86_64} CritSect : QWord; {$else} CritSect : LongWord; {$endif} {$ELSE} CritSect : TRTLCriticalSection; {$ENDIF} procedure ThreadDone; begin EnterCriticalSection(CritSect); Dec(ThreadsRunning); LeaveCriticalSection(CritSect); end; procedure TRenderThread.DoVisualSwap; begin {$IFDEF SHOWPROG} lBarX.Position := lPosX; {$ENDIF} end; procedure TRenderThread.VisualProg(lPos: Integer); begin lPosX := lPos; {$IFDEF SHOWPROG} {$IFDEF FPC} Synchronize(DoVisualSwap); {$ELSE} Synchronize(DoVisualSwap); {$ENDIF} {$ENDIF} end; constructor TRenderThread.Create(lBar: TProgressBar;lThread: integer;l: TRotateVals; var lM: TMatrix; lRenderCutout: boolean; var lBuffIn,lBuffOut: ByteP); begin lBarX := lBar; lRV := l; lMx := lM; lRenderCutoutX := lRenderCutout; lBuffInX := lBuffIn; lBuffOutX := lBuffOut; lThreadX := lThread; FreeOnTerminate := True; inherited Create(False); end; // The Execute method is called when the thread starts procedure TRenderThread.Execute; begin Rotate(lThreadX,lRV,lMx,lRenderCutoutX, lBuffInX,lBuffOutX); end; procedure FindXBounds (var lXMax,lXMin: integer; lXDimIN,lYxiZxi,lXPivotInU2,lYDimIN,lYyiZyi,lYPivotInU2,lZDimIN,lYziZzi,lZPivotInU2,lOutDim:integer; lXxra,lXyra,lXzra : LongIntP); var lXo,lYo,lZo,Xo_at_one,Xo_at_two,Xo_grad,Xo_offs,lShiftedOne : integer; when_it_is_zero, when_it_is_max: double; lReallySmall {, debugx0, debugx1, debugy0, debugy1, debugz0, debugz1}: double; l2: integer; begin lXMax := lOutDim; lXMin := 1; l2 := 2; lShiftedOne := 1 shl ksh; lReallySmall := 1e-6; Xo_at_one := lXxRA^[1] +lYxiZxi + (lXPivotInU2 shl kSh); Xo_at_two := lXxRA^[l2] +lYxiZxi + (lXPivotInU2 shl kSh); Xo_grad := Xo_at_two - Xo_at_one; Xo_offs := Xo_at_one - Xo_grad; if Abs(Xo_grad) > lReallySmall then begin when_it_is_zero := (lShiftedOne-Xo_offs) / Xo_grad; when_it_is_max := ((lXDimIn shl kSh)-Xo_offs) / Xo_grad; //debugx0 := when_it_is_zero; debugx1 := when_it_is_max; if (when_it_is_zero < when_it_is_max) then begin if when_it_is_zero > lXMin then lXMin := Round(when_it_is_zero+0.5); if when_it_is_max < lXMax then lXMax := Round(when_it_is_max-0.5); end else begin if when_it_is_max > lXMin then lXMin := Round(when_it_is_max+0.5); if when_it_is_zero < lXMax then lXMax := Round(when_it_is_zero-0.5); end; end; Xo_at_one := lXyRA^[1] +lYyiZyi + (lYPivotInU2 shl kSh); Xo_at_two := lXyRA^[l2] +lYyiZyi + (lYPivotInU2 shl kSh); Xo_grad := Xo_at_two - Xo_at_one; Xo_offs := Xo_at_one - Xo_grad; if Abs(Xo_grad) > lReallySmall then begin when_it_is_zero := (lShiftedOne-Xo_offs) / Xo_grad; when_it_is_max := ((lYDimIn shl kSh)-Xo_offs) / Xo_grad; //debugy0 := when_it_is_zero; debugy1 := when_it_is_max; if (when_it_is_zero < when_it_is_max) then begin if when_it_is_zero > lXMin then lXMin := Round(when_it_is_zero+0.5); if when_it_is_max < lXMax then lXMax := Round(when_it_is_max-0.5); end else begin if when_it_is_max > lXMin then lXMin := Round(when_it_is_max+0.5); if when_it_is_zero < lXMax then lXMax := Round(when_it_is_zero-0.5); end; end; Xo_at_one := lXzRA^[1] +lYziZzi + (lZPivotInU2 shl kSh); Xo_at_two := lXzRA^[l2] +lYziZzi + (lZPivotInU2 shl kSh); Xo_grad := Xo_at_two - Xo_at_one; Xo_offs := Xo_at_one - Xo_grad; if Abs(Xo_grad) > lReallySmall then begin when_it_is_zero := (lShiftedOne-Xo_offs) / Xo_grad; when_it_is_max := ((lZDimIn shl kSh)-Xo_offs) / Xo_grad; //debugz0 := when_it_is_zero; debugz1 := when_it_is_max; if (when_it_is_zero < when_it_is_max) then begin if when_it_is_zero > lXMin then lXMin := Round(when_it_is_zero+0.5); if when_it_is_max < lXMax then lXMax := Round(when_it_is_max-0.5); end else begin if when_it_is_max > lXMin then lXMin := Round(when_it_is_max+0.5); if when_it_is_zero < lXMax then lXMax := Round(when_it_is_zero-0.5); end; end; // even with all the care about rounding, it's possible that we've got the // edges wrong in ultra-high-gradient cases if lXMin < lXMax then begin while true do begin lXo := ((lXxRA^[lXMin] +lYxiZxi) shr kSh)+lXPivotInU2; lYo := ((lXyRA^[lXMin] +lYyiZyi) shr kSh)+lYPivotInU2; lZo := ((lXzRA^[lXMin] +lYziZzi) shr kSh)+lZPivotInU2; if (lXMin < lXMax) and ((lXo<1) or (lXo>lXDimIn) or (lYo<1) or (lYo>lYDimIn) or (lZo<1) or (lZo>lZDimIn)) then begin lXMin := 1+lXMin; end else break; end; while true do begin lXo := ((lXxRA^[lXMax] +lYxiZxi) shr kSh)+lXPivotInU2; lYo := ((lXyRA^[lXMax] +lYyiZyi) shr kSh)+lYPivotInU2; lZo := ((lXzRA^[lXMax] +lYziZzi) shr kSh)+lZPivotInU2; if (lXMax > lXMin) and ((lXo<1) or (lXo>lXDimIn) or (lYo<1) or (lYo>lYDimIn) or (lZo<1) or (lZo>lZDimIn)) then begin lXMax := lXMax-1; end else break; end; end; end;//proc findXBounds //Nearest Neighbor procedure TNNRender.Rotate (lThread: integer;l: TRotateVals; var lM: TMatrix; lRenderCutout: boolean; var lBuffIn,lBuffOut: ByteP); const kshx = ksh shr 1; var lZxi,lZyi,lZzi,lYxiZxi,lYyiZyi,lYziZzi,lZ,lY,lX,lOutPos, lMaxX,lMinX,lXo,lYo,lZo: integer; begin for lZ := l.ZDimStart to l.ZDimEnd do begin lZxi := round(lZ*lM.matrix[1,3]* (1 shl kSh) ); lZyi := round(lZ*lM.matrix[2,3]* (1 shl kSh) ); lZzi := round(lZ*lM.matrix[3,3]* (1 shl kSh) ); if {(RenderForm.RenderRefreshTimer.enabled) or} (Terminated) then begin ThreadDone; exit; end; {$IFDEF SHOWPROG} //flicker with lazarus if (lThread = 1) and ((lZ mod 30)=0) then VisualProg(lZ); {$ENDIF} //ImgForm.ProgressBar1.Position := lZ; for lY := l.YDimStart to l.YDimEnd do begin lYxiZxi := round(lY * lM.matrix[1,2]* (1 shl kSh) )+lZxi; lYyiZyi := round(lY * lM.matrix[2,2]* (1 shl kSh) )+lZyi; lYziZzi := round(lY * lM.matrix[3,2]* (1 shl kSh) )+lZzi; lOutPos := ((lZ+l.OutPivot-1)*l.OutSliceSz)+((lY+l.OutPivot-1)*l.Outdim); //if gAbortRender > 0 then goto 345; FindXBounds (lMaxX,lMinX,l.XDimIN,lYxiZxi,l.XPivotInU2,l.YDimIN,lYyiZyi,l.YPivotInU2,l.ZDimIN,lYziZzi,l.ZPivotInU2,l.OutDim,l.Xxra,l.Xyra,l.Xzra); if lMaxX > lMinX then for lX := lMinX to lMaxX do begin lXo := ((l.XxRA^[lX] +lYxiZxi) shr kSh)+l.XPivotInU2; lYo := ((l.XyRA^[lX] +lYyiZyi) shr kSh)+l.YPivotInU2; lZo := ((l.XzRA^[lX] +lYziZzi) shr kSh)+l.ZPivotInU2; {lXo := (lXo shr 1) + 1; lYo := lYo shr 1; lZo := lZo shr 1;} lBuffOut[lX+lOutPos] := lBuffIn[(lXo)+((lYo-1)*l.XdimIn)+((lZo-1)*l.InSliceSz)] end; end; //for y end; //for z ThreadDone; end; procedure TTriRender.Rotate (lThread: integer;l: TRotateVals; var lM: TMatrix; lRenderCutout: boolean; var lBuffIn,lBuffOut: ByteP); //Trilinear - this uses integer math, and on CoreDuo CPUs is 30% faster than Floating Point //For precision, integers are multiplied by kSh (~2^10 bits) to simulate floats // However, we will use 32-bit integers and the image intensity is 8 bit values, // with the final interpolation multiplying X*Y*Z*intensity // Therefore, this final interpolation adjusts kSh to be 2^8, avoiding overflow var lMi: TMatrixi; lXr,lYr,lZr,lYxi,lYyi,lYzi,lXxi,lXyi,lXzi,lZxi,lZyi,lZzi, lYxiZxi,lYyiZyi,lYziZzi,lZ,lY,lX,lOutPos, lXPiv,lYPiv,lZPiv,lXrM1i,lYrM1i,lZrM1i, lShr,lShl,lShlTo8,lShl8, lMinZ,lMaxZ,lMinY,lMaxY,lMaxX,lMinX,lXo,lYo,lZo: integer; begin lShl := 1 shl kSh; lShl8 := 1 shl 8; //8bit precision lShlTo8 := (kSh - 8); //shr the kSh precision by this to get 8-bit precision lShr := 24;//24-bits * 8 bit intensity = 32 bits lXPiv := l.XPivotIn * lShl; lYPiv := l.YPivotIn * lShl; lZPiv := l.ZPivotIn * lShl; for lX := 1 to 3 do for lY := 1 to 3 do lMi.matrix[lX,lY] := round(lM.matrix[lX,lY] * lShl); if (lRenderCutout ) then begin //only separated to unroll IF rendercutout for lZ := l.ZDimStart to l.ZDimEnd do begin lZxi := (lZ*lMi.matrix[1,3] ); lZyi := (lZ*lMi.matrix[2,3] ); lZzi := (lZ*lMi.matrix[3,3] ); if {(RenderForm.RenderRefreshTimer.enabled) or} (Terminated) then begin ThreadDone; exit; end; {$IFDEF SHOWPROG} //flicker with lazarus if (lThread = 1) and ((lZ mod 30)=0) then VisualProg(lZ); {$ENDIF} for lY := l.YDimStart to l.YDimEnd do begin lYxi := lY * lMi.matrix[1,2]; lYyi := lY * lMi.matrix[2,2]; lYzi := lY * lMi.matrix[3,2]; lYxiZxi := (lY * lMi.matrix[1,2] )+lZxi; lYyiZyi := (lY * lMi.matrix[2,2] )+lZyi; lYziZzi := (lY * lMi.matrix[3,2] )+lZzi; FindXBounds (lMaxX,lMinX,l.XDimIN,lYxiZxi,l.XPivotInU2,l.YDimIN,lYyiZyi,l.YPivotInU2,l.ZDimIN,lYziZzi,l.ZPivotInU2,l.OutDim,l.Xxra,l.Xyra,l.Xzra); lMaxX := lMaxX - l.OutPivot -1 ; lMinX := lMinX - l.OutPivot+1; if lMaxX > lMinX then for lX := lMinX to lMaxX do begin lXr := ( (lX*lMi.matrix[1,1])+lYxi+lZxi)+lXPiv; lYr := ((lX*lMi.matrix[2,1])+lYyi+lZyi)+lYPiv; lZr := ( (lX*lMi.matrix[3,1])+lYzi+lZzi)+lZPiv; lXo := (lXr shr kSh); lYo := (lYr shr kSh); lZo := (lZr shr kSh); if (lXo > 0) and (lXo < l.XDimIn) and (lYo > 0) and (lYo < l.YDimIn) and (lZo > 0) and (lZo < l.ZDimIn) then begin lXr := (lXr- (lXo * lShl)) shr lShlTo8; lYr := (lYr- (lYo * lShl)) shr lShlTo8; lZr := (lZr- (lZo * lShl)) shr lShlTo8; lXrM1i := lShl8-lXr; lYrM1i := lShl8-lYr; lZrM1i := lShl8-lZr; lMinY := ((lYo-1)*l.XdimIn); lMinZ := ((lZo-1)*l.InSliceSz); lMaxY := ((lYo)*l.XdimIn); lMaxZ := ((lZo)*l.InSliceSz); lOutPos := ((lZ+l.OutPivot-1)*l.OutSliceSz)+((lY+l.OutPivot-1)*l.Outdim); if {(lRenderCutout ) and} ((lBuffIn^[lXo+lMinY+lMinZ]=255) or (lBuffIn^[lXo+1+lMinY+lMinZ]=255) or (lBuffIn^[lXo+lMaxY+lMinZ]=255) or (lBuffIn^[lXo+1+lMaxY+lMinZ]=255) or (lBuffIn^[lXo+lMinY+lMaxZ]=255) or (lBuffIn^[lXo+1+lMinY+lMaxZ]=255) or (lBuffIn^[lXo+lMaxY+lMaxZ]=255) or (lBuffIn^[lXo+1+lMaxY+lMaxZ]=255)) then lBuffOut^[lX+l.OutPivot+lOutPos] := 255 else lBuffOut^[lX+l.OutPivot+lOutPos] := ( (lXrM1i*lYrM1i*lZrM1i *lBuffIn^[lXo+lMinY+lMinZ] ) +(lXr*lYrM1i*lZrM1i *lBuffIn^[lXo+1+lMinY+lMinZ]) +(lXrM1i*lYr*lZrM1i *lBuffIn^[lXo+lMaxY+lMinZ] ) +(lXrM1i*lYrM1i*lZr *lBuffIn^[lXo+lMinY+lMaxZ] ) +(lXr*lYr*lZrM1i *lBuffIn^[lXo+1+lMaxY+lMinZ] ) +(lXr*lYrM1i*lZr *lBuffIn^[lXo+1+lMinY+lMaxZ] ) +(lXrM1i*lYr*lZr *lBuffIn^[lXo+lMaxY+lMaxZ]) +(lXr*lYr*lZr *lBuffIn^[lXo+1+lMaxY+lMaxZ] ) ) shr lShr; end; //values in range end; //for x end; //for y end; //for z ThreadDone; exit; end; //if RenderCutout for lZ := l.ZDimStart to l.ZDimEnd do begin lZxi := (lZ*lMi.matrix[1,3] ); lZyi := (lZ*lMi.matrix[2,3] ); lZzi := (lZ*lMi.matrix[3,3] ); if {(RenderForm.RenderRefreshTimer.enabled) or} (Terminated) then begin ThreadDone; exit; end; {$IFDEF SHOWPROG} //flicker with lazarus if (lThread = 1) and ((lZ mod 30)=0) then VisualProg(lZ); {$ENDIF} for lY := l.YDimStart to l.YDimEnd do begin lYxi := lY * lMi.matrix[1,2]; lYyi := lY * lMi.matrix[2,2]; lYzi := lY * lMi.matrix[3,2]; lYxiZxi := (lY * lMi.matrix[1,2] )+lZxi; lYyiZyi := (lY * lMi.matrix[2,2] )+lZyi; lYziZzi := (lY * lMi.matrix[3,2] )+lZzi; FindXBounds (lMaxX,lMinX,l.XDimIN,lYxiZxi,l.XPivotInU2,l.YDimIN,lYyiZyi,l.YPivotInU2,l.ZDimIN,lYziZzi,l.ZPivotInU2,l.OutDim,l.Xxra,l.Xyra,l.Xzra); lMaxX := lMaxX - l.OutPivot -1 ; lMinX := lMinX - l.OutPivot+1; if lMaxX > lMinX then for lX := lMinX to lMaxX do begin lXr := ( (lX*lMi.matrix[1,1])+lYxi+lZxi)+lXPiv; lYr := ((lX*lMi.matrix[2,1])+lYyi+lZyi)+lYPiv; lZr := ( (lX*lMi.matrix[3,1])+lYzi+lZzi)+lZPiv; lXo := (lXr shr kSh); lYo := (lYr shr kSh); lZo := (lZr shr kSh); if (lXo > 0) and (lXo < l.XDimIn) and (lYo > 0) and (lYo < l.YDimIn) and (lZo > 0) and (lZo < l.ZDimIn) then begin lXr := (lXr- (lXo * lShl)) shr lShlTo8; lYr := (lYr- (lYo * lShl)) shr lShlTo8; lZr := (lZr- (lZo * lShl)) shr lShlTo8; lXrM1i := lShl8-lXr; lYrM1i := lShl8-lYr; lZrM1i := lShl8-lZr; lMinY := ((lYo-1)*l.XdimIn); lMinZ := ((lZo-1)*l.InSliceSz); lMaxY := ((lYo)*l.XdimIn); lMaxZ := ((lZo)*l.InSliceSz); lOutPos := ((lZ+l.OutPivot-1)*l.OutSliceSz)+((lY+l.OutPivot-1)*l.Outdim); lBuffOut^[lX+l.OutPivot+lOutPos] :=( (lXrM1i*lYrM1i*lZrM1i *lBuffIn^[lXo+lMinY+lMinZ] ) +(lXr*lYrM1i*lZrM1i *lBuffIn^[lXo+1+lMinY+lMinZ]) +(lXrM1i*lYr*lZrM1i *lBuffIn^[lXo+lMaxY+lMinZ] ) +(lXrM1i*lYrM1i*lZr *lBuffIn^[lXo+lMinY+lMaxZ] ) +(lXr*lYr*lZrM1i *lBuffIn^[lXo+1+lMaxY+lMinZ] ) +(lXr*lYrM1i*lZr *lBuffIn^[lXo+1+lMinY+lMaxZ] ) +(lXrM1i*lYr*lZr *lBuffIn^[lXo+lMaxY+lMaxZ]) +(lXr*lYr*lZr *lBuffIn^[lXo+1+lMaxY+lMaxZ] ) ) shr lShr; end; //values in range end; //for x end; //for y end; //for z ThreadDone; end; (* // floating point version of the same algorithm... procedure TTriRender.Rotate (lThread: integer;l: TRotateVals; var lM: TMatrix; lRenderCutout: boolean; var lBuffIn,lBuffOut: ByteP); var lXreal,lYreal,lZreal,lZx,lZy,lZz,lYx,lYy,lYz,lXrM1,lYrM1,lZrM1: single; lXxi,lXyi,lXzi,lZxi,lZyi,lZzi,lYxiZxi,lYyiZyi,lYziZzi,lZ,lY,lX,lOutPos, lMinZ,lMaxZ,lMinY,lMaxY,lMaxX,lMinX,lXo,lYo,lZo: integer; begin if (lRenderCutout ) then begin for lZ := l.ZDimStart to l.ZDimEnd do begin lZx := lZ*lM.matrix[1,3]; lZy := lZ*lM.matrix[2,3]; lZz := lZ*lM.matrix[3,3]; lZxi := round(lZ*lM.matrix[1,3]* (1 shl kSh) ); lZyi := round(lZ*lM.matrix[2,3]* (1 shl kSh) ); lZzi := round(lZ*lM.matrix[3,3]* (1 shl kSh) ); if RenderForm.RenderRefreshTimer.enabled then exit;//abort if Terminated then exit; //goto 345;//abort if (lThread = 1) and ((lZ mod 10)=0) then VisualProg(lZ); for lY := l.YDimStart to l.YDimEnd do begin lYx := lY * lM.matrix[1,2]; lYy := lY * lM.matrix[2,2]; lYz := lY * lM.matrix[3,2]; lOutPos := ((lZ+l.OutPivot-1)*l.OutSliceSz)+((lY+l.OutPivot-1)*l.Outdim); lYxiZxi := round(lY * lM.matrix[1,2]* (1 shl kSh) )+lZxi; lYyiZyi := round(lY * lM.matrix[2,2]* (1 shl kSh) )+lZyi; lYziZzi := round(lY * lM.matrix[3,2]* (1 shl kSh) )+lZzi; FindXBounds (lMaxX,lMinX,l.XDimIN,lYxiZxi,l.XPivotInU2,l.YDimIN,lYyiZyi,l.YPivotInU2,l.ZDimIN,lYziZzi,l.ZPivotInU2,l.OutDim,l.Xxra,l.Xyra,l.Xzra); lMaxX := lMaxX - l.OutPivot -1 ; lMinX := lMinX - l.OutPivot+1; if lMaxX > lMinX then for lX := lMinX to lMaxX do begin lXreal := ( (lX*lM.matrix[1,1])+lYx+lZx)+l.XPivotIn; lYreal := ( (lX*lM.matrix[2,1])+lYy+lZy)+l.YPivotIn; lZreal := ( (lX*lM.matrix[3,1])+lYz+lZz)+l.ZPivotIn; lXo := trunc(lXreal); lYo := trunc(lYreal); lZo := trunc(lZreal); if (lXo > 0) and (lXo < l.XDimIn) and (lYo > 0) and (lYo < l.YDimIn) and (lZo > 0) and (lZo < l.ZDimIn) then begin lXreal := lXreal-lXo; lYreal := lYreal-lYo; lZreal := lZreal-lZo; lXrM1 := 1-lXreal; lYrM1 := 1-lYreal; lZrM1 := 1-lZreal; lMinY := ((lYo-1)*l.XdimIn); lMinZ := ((lZo-1)*l.InSliceSz); lMaxY := ((lYo)*l.XdimIn); lMaxZ := ((lZo)*l.InSliceSz); if {(l.RenderCutout ) and} ((lBuffIn^[lXo+lMinY+lMinZ]=255) or (lBuffIn^[lXo+1+lMinY+lMinZ]=255) or (lBuffIn^[lXo+lMaxY+lMinZ]=255) or (lBuffIn^[lXo+1+lMaxY+lMinZ]=255) or (lBuffIn^[lXo+lMinY+lMaxZ]=255) or (lBuffIn^[lXo+1+lMinY+lMaxZ]=255) or (lBuffIn^[lXo+lMaxY+lMaxZ]=255) or (lBuffIn^[lXo+1+lMaxY+lMaxZ]=255)) then lBuffOut^[lX+l.OutPivot+lOutPos] := 255 else lBuffOut^[lX+l.OutPivot+lOutPos] := round ( {all min} ( (lXrM1*lYrM1*lZrM1)*lBuffIn^[lXo+lMinY+lMinZ]) {x+1}+((lXreal*lYrM1*lZrM1)*lBuffIn^[lXo+1+lMinY+lMinZ]) {y+1}+((lXrM1*lYreal*lZrM1)*lBuffIn^[lXo+lMaxY+lMinZ]) {z+1}+((lXrM1*lYrM1*lZreal)*lBuffIn^[lXo+lMinY+lMaxZ]) {x+1,y+1}+((lXreal*lYreal*lZrM1)*lBuffIn^[lXo+1+lMaxY+lMinZ]) {x+1,z+1}+((lXreal*lYrM1*lZreal)*lBuffIn^[lXo+1+lMinY+lMaxZ]) {y+1,z+1}+((lXrM1*lYreal*lZreal)*lBuffIn^[lXo+lMaxY+lMaxZ]) {x+1,y+1,z+1}+((lXreal*lYreal*lZreal)*lBuffIn^[lXo+1+lMaxY+lMaxZ]) ); end; //values in range end; //for x end; //for y end; //for z ThreadDone; exit; end; //rendercutout for lZ := l.ZDimStart to l.ZDimEnd do begin lZx := lZ*lM.matrix[1,3]; lZy := lZ*lM.matrix[2,3]; lZz := lZ*lM.matrix[3,3]; lZxi := round(lZ*lM.matrix[1,3]* (1 shl kSh) ); lZyi := round(lZ*lM.matrix[2,3]* (1 shl kSh) ); lZzi := round(lZ*lM.matrix[3,3]* (1 shl kSh) ); if RenderForm.RenderRefreshTimer.enabled then exit;//abort if Terminated then exit; //goto 345;//abort if (lThread = 1) and ((lZ mod 10)=0) then VisualProg(lZ); for lY := l.YDimStart to l.YDimEnd do begin lYx := lY * lM.matrix[1,2]; lYy := lY * lM.matrix[2,2]; lYz := lY * lM.matrix[3,2]; lOutPos := ((lZ+l.OutPivot-1)*l.OutSliceSz)+((lY+l.OutPivot-1)*l.Outdim); lYxiZxi := round(lY * lM.matrix[1,2]* (1 shl kSh) )+lZxi; lYyiZyi := round(lY * lM.matrix[2,2]* (1 shl kSh) )+lZyi; lYziZzi := round(lY * lM.matrix[3,2]* (1 shl kSh) )+lZzi; FindXBounds (lMaxX,lMinX,l.XDimIN,lYxiZxi,l.XPivotInU2,l.YDimIN,lYyiZyi,l.YPivotInU2,l.ZDimIN,lYziZzi,l.ZPivotInU2,l.OutDim,l.Xxra,l.Xyra,l.Xzra); lMaxX := lMaxX - l.OutPivot -1 ; lMinX := lMinX - l.OutPivot+1; if lMaxX > lMinX then for lX := lMinX to lMaxX do begin lXreal := ( (lX*lM.matrix[1,1])+lYx+lZx)+l.XPivotIn; lYreal := ((lX*lM.matrix[2,1])+lYy+lZy)+l.YPivotIn; lZreal := ( (lX*lM.matrix[3,1])+lYz+lZz)+l.ZPivotIn; lXo := trunc(lXreal); lYo := trunc(lYreal); lZo := trunc(lZreal); if (lXo > 0) and (lXo < l.XDimIn) and (lYo > 0) and (lYo < l.YDimIn) and (lZo > 0) and (lZo < l.ZDimIn) then begin lXreal := lXreal-lXo; lYreal := lYreal-lYo; lZreal := lZreal-lZo; lXrM1 := 1-lXreal; lYrM1 := 1-lYreal; lZrM1 := 1-lZreal; lMinY := ((lYo-1)*l.XdimIn); lMinZ := ((lZo-1)*l.InSliceSz); lMaxY := ((lYo)*l.XdimIn); lMaxZ := ((lZo)*l.InSliceSz); lBuffOut^[lX+l.OutPivot+lOutPos] := round ( {all min} ( (lXrM1*lYrM1*lZrM1)*lBuffIn^[lXo+lMinY+lMinZ]) {x+1}+((lXreal*lYrM1*lZrM1)*lBuffIn^[lXo+1+lMinY+lMinZ]) {y+1}+((lXrM1*lYreal*lZrM1)*lBuffIn^[lXo+lMaxY+lMinZ]) {z+1}+((lXrM1*lYrM1*lZreal)*lBuffIn^[lXo+lMinY+lMaxZ]) {x+1,y+1}+((lXreal*lYreal*lZrM1)*lBuffIn^[lXo+1+lMaxY+lMinZ]) {x+1,z+1}+((lXreal*lYrM1*lZreal)*lBuffIn^[lXo+1+lMinY+lMaxZ]) {y+1,z+1}+((lXrM1*lYreal*lZreal)*lBuffIn^[lXo+lMaxY+lMaxZ]) {x+1,y+1,z+1}+((lXreal*lYreal*lZreal)*lBuffIn^[lXo+1+lMaxY+lMaxZ]) ); end; //values in range end; //for x end; //for y end; //for z // if Terminated then Exit; ThreadDone; end; *) initialization InitializeCriticalSection(CritSect); finalization DeleteCriticalSection(CritSect); end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/render_composite.pas�����������������������������������������������0000755�0001750�0001750�00000127467�12306420776�020301� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit render_composite; interface {$include isthreaded.inc} uses {$IFDEF Unix} lclintf, //gettickcount {$ELSE} Windows, {$ENDIF} {$IFNDEF NoThreads} RenderThds, {$ELSE} rendernothreads, {$ENDIF} {$IFDEF FPC} LResources, //not sure if this is used... {$ENDIF} SysUtils, GraphicsMathLibrary,Classes, Graphics, Controls, Forms, Dialogs,ExtCtrls,Buttons, nifti_img, nifti_hdr,define_types,nifti_img_view,StdCtrls, Menus,ClipBrd,ReadInt,cutout,IniFiles, ComCtrls, nifti_types; type TRender = record Zoom: single; Cutout,CutoutFrac: TCutout; //BGNearClipFrac, BGNearClip,OverlayNearClipFrac,OverlayNearClip, ClipFrac, Azimuth,Elevation,cutoutLUTindex,ShadePct, OverlayFromBGSurface,BGSurface,OverlaySurface,BGDepth,OverlayDepth,CutoutBias,Gain,Bias: integer; SmoothBG,SmoothOverlay,Trilinear,ShowCutout,FlipLR: boolean; end; procedure VolumeRotateMatrix (var lBGImg: TBGImg; var lHdr: TMRIcroHdr; var lMatrixIn: TMatrix; lBilinearSmooth,lRenderCutout,lIsBG: boolean{;lNearSlicesClipIn: integer}); procedure DrawRender; procedure SliceToFrac(var lBGImg: TBGImg); var gRender:TRender; const kBelow = 1; kInFront = 2; implementation uses math,render; procedure MinMaxFilt (var lHdr: TMRIcroHdr; var lFiltMin8bit, lFiltMax8bit: integer);var lMin,lMax: single; begin ReturnMinMax (lHdr,lMin,lMax, lFiltMin8bit, lFiltMax8bit); end; procedure Smooth2DImage (lX,lY: integer; lInBuffer: ByteP); var lSmoothBuffer: ByteP; lLine,lLineStart,lInc,lOutPixel,lV: integer; begin GetMem (lSmoothBuffer , lX*lY); FillChar(lSmoothBuffer^,lX*lY, 0); //zero array for lLine:= (lY-1) downto 2 do begin lLineStart := ((lLine-1)*(lX)); for lInc := (lX-1) downto 2 do begin lOutPixel := lLineStart+lInc; lV := (lInBuffer^[lOutPixel] shl 3) +(lInBuffer^[lOutPixel+1] shl 1)+(lInBuffer^[lOutPixel-1] shl 1) +(lInBuffer^[lOutPixel+lX] shl 1)+(lInBuffer^[lOutPixel-lX] shl 1) +(lInBuffer^[lOutPixel+lX+1])+(lInBuffer^[lOutPixel+lX-1]) +(lInBuffer^[lOutPixel-lX+1])+(lInBuffer^[lOutPixel-lX-1]) ; lV := lV div 20; lSmoothBuffer^[lOutPixel] := lV;//lV; end; //for each column end; //for each line (row) Move(lSmoothBuffer^,lInBuffer^,lX*lY); //Move(lSmoothBuffer^[1],lInBuffer[1]^,lX*lY); FreeMem(lSmoothBuffer); end; //proc Smooth2DImage procedure CreateOverlayRenderInfrontNear(var lBGHdr,lHdr: TMRIcroHdr; var lX,lY,lZ,lInRenderSurface,lInRenderDepth: Integer; var lQuadP: RGBQuadp; Smooth2D: boolean); //changes Aug2007 - make sure search depth is not MAxInt - we get wrap around var lSrc,lOutBuffer: Bytep; lLow,lHigh, lIntensity,lDepth,lPixel,lSliceSz,lRenderSurface,lRenderDepth,lSamples: integer; begin if gBGImg.RenderDepthBufferItems < 1 then exit; lSrc := lHdr.RenderBuffer;//lHdr.ScrnBuffer; lSliceSz := lX*lY; //lVolSz := lSliceSz * lZ; GetMem (lOutBuffer , lSliceSz); fillchar(lOutBuffer^,lSliceSz,0); lRenderSurface := lInRenderSurface; RenderForm.caption := inttostr(lRenderSurface); if (lHdr.IMgBufferItems > 0) {2/2008} and (lHdr.NIFTIhdr.intent_code = kNIFTI_INTENT_LABEL) then lRenderSurface := 1; for lPixel := 1 to lSliceSz do begin if gBGImg.RenderDepthBuffer^[lPixel] <> 0 then begin //background surface at this voxel lIntensity := 0; lSamples := 0; if gBGImg.RenderDepthBuffer^[lPixel] < 0 then lRenderDepth := (abs(gBGImg.RenderDepthBuffer^[lPixel])-1)+1 else lRenderDepth := (abs(gBGImg.RenderDepthBuffer^[lPixel])-1)+lInRenderDepth; if lRenderDepth >= lX then lRenderDepth := lX-1; lDepth := ((lPixel-1)* lX)+1; lRenderDepth := lDepth + lRenderDepth; while (lDepth < lRenderDepth) do begin if (lSrc^[lDepth] > lRenderSurface) then begin lIntensity := lIntensity+lSrc^[lDepth]; inc(lSamples); end; inc(lDepth); end; if lSamples > 0 then lOutBuffer^[lPixel]:= lIntensity div lSamples; end; //for each pixel with a background image end; //for each pixel (*for lPixel := 1 to lSliceSz do begin if gBGImg.RenderDepthBuffer^[lPixel] <> 0 then begin //background surface at this voxel lDepth := 0; lIntensity := 0; lSliceOffset := 0; lSamples := 0; lRenderDepth := (abs(gBGImg.RenderDepthBuffer^[lPixel])-1)+lInRenderDepth; while (lDepth < lRenderDepth) and (lSliceOffset < lVolSz) do begin if (lSrc^[lSliceOffset+lPixel] > lRenderSurface) then begin lIntensity := lIntensity+lSrc^[lSliceOffset+lPixel]; inc(lSamples); end; inc(lSliceOffset,lSliceSz); inc(lDepth); if gBGImg.RenderDepthBuffer^[lPixel] < 0 then lDepth := lRenderDepth; //only show surface for cutout end; if lSamples > 0 then lOutBuffer^[lPixel]:= lIntensity div lSamples; end ; //if background end; *) if (Smooth2D) and (lHdr.NIFTIhdr.intent_code <> kNIFTI_INTENT_LABEL) then //do not smooth labels Smooth2DImage (lX,lY, lOutBuffer); //Mar2007 start if lHdr.LUTfromZero then begin MinMaxFilt(lHdr,lLow,lHigh); //fx(lLow,lHigh); if lLow > 0 then for lPixel := 1 to (lSliceSz) do if lOutBuffer^[lPixel] < lLow then lOutBuffer^[lPixel] := 0; if lHigh < 255 then for lPixel := 1 to (lSliceSz) do if lOutBuffer^[lPixel] < lHigh then lOutBuffer^[lPixel] := 0; end; for lPixel := 1 to lSliceSz do lQuadP^[lPixel]:= lHdr.LUT[lOutBuffer^[lPixel]]; Freemem(lOutBuffer); end; procedure CreateOverlayRenderBehind(var lBGHdr,lHdr: TMRIcroHdr; var lX,lY,lZ,lInRenderSurface,lInRenderDepth: Integer; var lQuadP: RGBQuadp; Smooth2D: boolean); var lSrc,lOutBuffer: Bytep; lLow,lHigh,lQ, lSurfaceDepth,lIntensity,lDepth,lPixel,lSliceSz,lRenderSurface,lRenderDepth: integer; begin if gBGImg.RenderDepthBufferItems < 1 then exit; lSrc := lHdr.RenderBuffer;//lHdr.ScrnBuffer; lSliceSz := lX*lY; //lVolSz := lSliceSz * lZ; GetMem (lOutBuffer , lSliceSz); fillchar(lOutBuffer^,lSliceSz,0); //lRenderDepth := lInRenderDepth; //if (lRenderDepth < 1) or (lHdr.NIFTIhdr.intent_code = kNIFTI_INTENT_LABEL) then // lRenderDepth := 1; lRenderSurface := lInRenderSurface; if (lHdr.IMgBufferItems > 0) {2/2008} and (lHdr.NIFTIhdr.intent_code = kNIFTI_INTENT_LABEL) then lRenderSurface := 1; for lPixel := 1 to lSliceSz do begin lSurfaceDepth := abs(gBGImg.RenderDepthBuffer^[lPixel]); if (lSurfaceDepth > 0) and (lSurfaceDepth <= lX) then begin //background surface at this voxel lIntensity := 0; lRenderDepth := (lSurfaceDepth-1)+lInRenderDepth; if lRenderDepth >= lX then lRenderDepth := lX-1; lDepth := ((lPixel-1)* lX)+1; lRenderDepth := lDepth + lRenderDepth; lDepth := lDepth + lSurfaceDepth-1; lQ := 0; while (lDepth < lRenderDepth) do begin if (lSrc^[lDepth] > lRenderSurface) and (lSrc^[lDepth] > lIntensity) then lIntensity := lSrc^[lDepth]; //if gBGImg.RenderDepthBuffer^[lPixel] < 0 then if (gBGImg.RenderDepthBuffer^[lPixel] < 0) and (lQ > 3) then lDepth := lRenderDepth; //only show surface for cutout inc(lDepth); inc(lQ); end; lOutBuffer^[lPixel]:= lIntensity; end; //for each pixel with a background image end; //for each pixel //renderform.caption := inttostr(lQMax); (*for lPixel := 1 to lSliceSz do begin if gBGImg.RenderDepthBuffer^[lPixel] <> 0 then begin //background surface at this voxel lDepth := 0; lIntensity := 0; lSliceOffset := (abs(gBGImg.RenderDepthBuffer^[lPixel])-1)*lSliceSz; //start with nearest slice while (lDepth < lRenderDepth) and (lSliceOffset < lVolSz) do begin if (lSrc^[lSliceOffset+lPixel] > lRenderSurface) and (lSrc^[lSliceOffset+lPixel] > lIntensity) then lIntensity := lSrc^[lSliceOffset+lPixel]; inc(lSliceOffset,lSliceSz); inc(lDepth); if gBGImg.RenderDepthBuffer^[lPixel] < 0 then lDepth := lRenderDepth; //only show surface for cutout end; lOutBuffer^[lPixel]:= lIntensity; end; //background surface at this voxel end; *) if (Smooth2D) and (lHdr.NIFTIhdr.intent_code <> kNIFTI_INTENT_LABEL) then //do not smooth labels Smooth2DImage (lX,lY, lOutBuffer); //Mar2007 start if lHdr.LUTfromZero then begin MinMaxFilt(lHdr,lLow,lHigh); //fx(lLow,lHigh); if lLow > 0 then for lPixel := 1 to (lSliceSz) do if lOutBuffer^[lPixel] < lLow then lOutBuffer^[lPixel] := 0; if lHigh < 255 then for lPixel := 1 to (lSliceSz) do if lOutBuffer^[lPixel] < lHigh then lOutBuffer^[lPixel] := 0; end; //Mar2007 end for lPixel := 1 to lSliceSz do lQuadP^[lPixel]:= lHdr.LUT[lOutBuffer^[lPixel]]; Freemem(lOutBuffer); end; Function AziElevMatrix : TMatrix; var lLRFlipMatrix: TMatrix; begin // gRender.Azimuth := RenderForm.AzimuthEdit.value; //gRender.Elevation := RenderForm.ElevationEdit.value; result := ViewTransformMatrix( coordSpherical, ToRadians(gRender.Azimuth), ToRadians(gRender.Elevation), 3{Distance.Value},6{ScreenWidthHeight.Value},6{ScreenWidthHeight.Value},{ScreenToCamera.Value}3); {The ViewTransformMatrix is all that is needed for other objects defined in world coordinates.} if {RenderForm.FlipLRcheck.checked} gRender.FlipLR then begin lLRFlipMatrix := Matrix3D (-1,0,0,0, // 3D "graphics" matrix 0,1,0,0, 0,0,1,0, 0,0,0,0); result := MultiplyMatrices(lLRFlipMatrix,Result); end; end; procedure ShadeCutoutCrease (var lRenderBuffer: bytep); var lZ,lY,lX: single; lXin,lYin,lZIn,lXm,lYm,lZm,lPixel, lOutDim,lOutPivot,lXPivotIn,lYPivotIn,lZPivotIn, lXlo,lXhi,lYlo,lYhi,lZlo,lZhi,lYOffset: integer; lClose,lScale: single; lMatrix: TMatrix; begin lOutDim := gBGImg.RenderDim;//MaxDim(lBackgroundImg.ScrnDim[1],lBackgroundImg.ScrnDim[2],lBackgroundImg.ScrnDim[3]); if gRender.Zoom > 0 then lOutPivot := (round(gBGImg.RenderDim/gRender.Zoom)+1) shr 1 else lOutPivot :=(gBGImg.RenderDim+1) shr 1; //11/2007b //lOutPivot := (lOutDim+1) shr 1; //e.g. if DimMax=9, then pivot is 5 lXPivotIn := (gBGImg.ScrnDim[1]+1) shr 1; //e.g. if DimMax=9, then pivot is 5 lYPivotIn := (gBGImg.ScrnDim[2]+1) shr 1; //e.g. if DimMax=9, then pivot is 5 lZPivotIn := (gBGImg.ScrnDim[3]+1) shr 1; //e.g. if DimMax=9, then pivot is 5 lMatrix := InvertMatrix3D(AziElevMatrix); //next: dilate borders by 1 pixel - draw crease INSIDE cutout lXlo := gRender.CutOut.Lo[1]-1; lXhi := gRender.CutOut.Hi[1]+1; lYlo := gRender.CutOut.Lo[2]-1; lYhi := gRender.CutOut.Hi[2]+1; lZlo := gRender.CutOut.Lo[3]-1; lZhi := gRender.CutOut.Hi[3]+1; lScale := 1/gRender.Zoom; //11/2007 for lYin := 1 to lOutDim do begin lYOffset := ((gBGImg.RenderDim-lYin)*gBGImg.RenderDim); for lXin := 1 to lOutDim do begin lPixel := lXin+ lYOffset; if gBGImg.RenderDepthBuffer^[lPixel]<0 then begin lZin := abs(gBGImg.RenderDepthBuffer^[lPixel]); lX := (lXin *lScale)-lOutPivot ; lY := lOutPivot -(lYin * lScale); lZ := (lZin * lScale)-lOutPivot; lXm := round( (lX*lMatrix.matrix[1,1])+(lY * lMatrix.matrix[2,1])+(lZ*lMatrix.matrix[3,1])); lYm := round( (lX*(lMatrix.matrix[1,2]))+(lY * lMatrix.matrix[2,2])+(lZ*lMatrix.matrix[3,2])); lZm := round( (lX*(lMatrix.matrix[1,3]))+(lY * lMatrix.matrix[2,3])+(lZ*lMatrix.matrix[3,3])); lXm := (lXm+lXPivotIn); lYm := (lYm+lYPivotIn); lZm := (lZm+lZPivotIn); if abs(lXlo-lXm) < abs(lXhi-lXm) then lXm := abs(lXlo-lXm) else lXm := abs(lXhi-lXm); if abs(lYlo-lYm) < abs(lYhi-lYm) then lYm := abs(lYlo-lYm) else lYm := abs(lYhi-lYm); if abs(lZlo-lZm) < abs(lZhi-lZm) then lZm := abs(lZlo-lZm) else lZm := abs(lZhi-lZm); if (lXm < lYm) and (lZm < lYm) then lYm := lZm //Y is furthest, replace with Z else if lZm < lXm then //X is furthest, replace with Z lXm := lZm; lClose := sqrt((lXm*lXm) + (lYm*lYm)); if lClose < 8 then begin lClose := 1-sqr(1-(lClose/8)); lRenderBuffer^[lPixel] := round(lRenderBuffer^[lPixel]*(0.33+(0.67*lClose))); end; end; end; //for lYin end; //for lXin end; procedure LUTbiasX (var lOutLUT : TLUT); {http://dept-info.labri.fr/~schlick/DOC/gem2.html http://dept-info.labri.fr/~schlick/publi.html Fast Alternatives to Perlin's Bias and Gain Functions Christophe Schlick Graphics Gems IV, p379-382, April 1994 } var lIndex: integer; lA,lT,lBias: single; lLUT: TLUT; begin if gRender.CutoutBias = 4 then exit; lA := (gRender.CutoutBias+1)/10; for lIndex := 1 to 254 do begin lT := lIndex/255; //lBias := 255*(lt/((1/la-2)*(1-lt)+1)) ; lBias := 255*(lt/((1/la-2)*(1-lt)+1)) ; lLUT[lIndex] := lOutLUT[round(lBias)]; {lHdr.LUT[lIndex].rgbRed := round(lBias*lHdr.LUT[lIndex].rgbRed); lHdr.LUT[lIndex].rgbGreen := round(lBias*lHdr.LUT[lIndex].rgbGreen); lHdr.LUT[lIndex].rgbBlue := round(lBias*lHdr.LUT[lIndex].rgbBlue);} //lHdr.LUT[lIndex].rgbReserved := kLUTalpha; end; for lIndex := 1 to 254 do lOutLUT[lIndex] := lLUT[lIndex]; end; procedure LUTgainX (var lOutLUT : TLUT; lBiasIn,lGainIn: integer {0..99}); {http://dept-info.labri.fr/~schlick/DOC/gem2.html http://dept-info.labri.fr/~schlick/publi.html Fast Alternatives to Perlin's Bias and Gain Functions Christophe Schlick Graphics Gems IV, p379-382, April 1994 } var lIndex,lV: integer; lA,lG,lT,lGain: single; lLUT: TLUT; begin if (lGainIn = 50) and (lBiasIn = 50){gRender.CutoutBias = 4} then exit; lA := (lBiasIn)/100; if lA = 0 then lA := 0.000001; lG := (lGainIn)/100; if lG = 0 then lG := 0.00001; if lG = 1 then lG := 0.99999; for lIndex := 1 to 254 do begin lT := lIndex/255; //apply bias lT := (lt/((1/la-2)*(1-lt)+1)) ; //next apply gain if lT < 0.5 then lGain := (lT/((1/lG-2)*(1-2*lT)+1)) else lGain := (( (1/lG-2)*(1-2*lT)-lT ) / ( (1/lG-2)*(1-2*lT)-1 ) ); lGain := lGain / lT; lV := round(255*lT*lGain); if lV > 255 then lV := 255; if lV < 0 then lV := 0; //lBias := 255*(lt/((1/la-2)*(1-lt)+1)) ; lLUT[lIndex] := lOutLUT[lV]; end; for lIndex := 1 to 254 do lOutLUT[lIndex] := lLUT[lIndex]; end; function SmoothShading (lX,lY: integer; lRenderDepthBuffer: SmallintP): boolean; var kRenderInfiniteDepth,lPrevLineStart,lNextLineStart,lLineStart,lScanLines, lGap,lDepthSum,lWeightSum,lFar,lClose,lCenter,lInc,lXmG: integer; lRenderDepthBufferS: SmallIntP; procedure AddPt (lI,lW: integer; var lSumI,lSumW: integer); begin if lI = kRenderInfiniteDepth then exit; lSumI := lSumI + (lW*lI); //add scaled value lSumW := lSumW + lW;//add weight end; //problem - smoothing gives embossed look! begin //func Smoothshading kRenderInfiniteDepth := 0; result := false; if (gRender.Zoom < 1) or (lY < 5) or (lX < 5) or (gBGImg.RenderDepthBufferItems <> (lX * lY)) then exit; lFar := 2; lClose := 3; lCenter := 5; lGap := trunc((gRender.Zoom-0.001)/1)+1; //must be at least 1! lXmG := lX-lGap; Getmem(lRenderDepthBufferS,lX*lY*sizeof(smallint)); for lInc := 1 to (lX*lY) do lRenderDepthBufferS^[lInc] := lRenderDepthBuffer^[lInc]; for lScanlines := (1+lGap) to (lY - lGap) do begin //can not compute angle for 1st and last scanline lLineStart := (lScanLines-1)*lX; //inc from 0 lPrevLineStart := lLineStart-(lX*lGap); //inc from 0 lNextLineStart := lLineStart+(lX*lGap); //inc from 0 for lInc := (1+lGap) to (lXmG) do begin lWeightSum := 0; lDepthSum := 0; AddPt (lRenderDepthBuffer^[lPrevLineStart+lInc-1],lFar,lDepthSum,lWeightSum); AddPt (lRenderDepthBuffer^[lPrevLineStart+lInc],lClose,lDepthSum,lWeightSum); AddPt (lRenderDepthBuffer^[lPrevLineStart+lInc+1],lFar,lDepthSum,lWeightSum); AddPt (lRenderDepthBuffer^[lLineStart+lInc-1],lClose,lDepthSum,lWeightSum); AddPt (lRenderDepthBuffer^[lLineStart+lInc],lCenter,lDepthSum,lWeightSum); AddPt (lRenderDepthBuffer^[lLineStart+lInc+1],lClose,lDepthSum,lWeightSum); AddPt (lRenderDepthBuffer^[lNextLineStart+lInc-1],lFar,lDepthSum,lWeightSum); AddPt (lRenderDepthBuffer^[lNextLineStart+lInc],lClose,lDepthSum,lWeightSum); AddPt (lRenderDepthBuffer^[lNextLineStart+lInc+1],lFar,lDepthSum,lWeightSum); if lWeightSum > 0 then lRenderDepthBufferS^[lLineStart+lInc] := round(lDepthSum/lWeightSum); end; //columns end; //for scanlines: rows for lInc := 1 to (lX*lY) do lRenderDepthBuffer^[lInc] := lRenderDepthBufferS^[lInc]; freemem(lRenderDepthBufferS); result := true; end; //function SmoothShading function IlluminationShading (lX,lY,lPct: integer; lImgBuffer: bytep; lRenderDepthBuffer: SmallintP): boolean; var kRenderInfiniteDepth,lXm1,lPrevLineStart,lNextLineStart,lLineStart,lScanLines, lIntensity,lInc,lGrayMin,lGrayMax: integer; lShadeFrac,lImgFrac, lPhongMagic,lMagic,lYVal,lXVal,lNormalPlane,lXLight,lYLight,lZLight,lLightVectorNormalise: single; lShadeBuffer: bytep; begin //func illumination shading result := false; if (lPct < 1) or (lY < 5) or (lX < 5) or (gBGImg.RenderDepthBufferItems <> (lX * lY)) then exit; lMagic := 1; lPhongMagic := 1; kRenderInfiniteDepth := 0; lXLight := 0;//RenderForm.XL.value / 100;//lXLight / lLightVectorNormalise; lYLight := -0.5;//Renderform.YL.value / 100;//lYLight / lLightVectorNormalise; lZLight := -1;//RenderForm.ZL.value / 100;//lZLight / lLightVectorNormalise; lLightVectorNormalise := sqrt(sqr(lXLight)+sqr(lYLight)+sqr(lZLight)); lXLight := lXLight / lLightVectorNormalise; lYLight := lYLight / lLightVectorNormalise; lZLight := lZLight / lLightVectorNormalise; lGrayMin := 0{64}; lGrayMax := 255 - lGrayMin; lXm1 := lX-1; Getmem(lShadeBuffer,lX*lY*sizeof(byte)); fillchar(lShadeBuffer^,lX*lY,0); for lScanlines := 2 to (lY - 1) do begin //can not compute angle for 1st and last scanline lLineStart := (lScanLines-1)*lX; //inc from 0 lPrevLineStart := lLineStart-lX; //inc from 0 lNextLineStart := lLineStart+lX; //inc from 0 for lInc := 2 to (lXm1) do begin if lImgBuffer^[lLineStart+lInc] <> 0 then begin //only shade non-zero intensities if ( lRenderDepthBuffer^[lPrevLineStart+lInc-1]<>kRenderInfiniteDepth) and (lRenderDepthBuffer^[lPrevLineStart+lInc]<>kRenderInfiniteDepth) and (lRenderDepthBuffer^[lPrevLineStart+lInc+1]<>kRenderInfiniteDepth) and (lRenderDepthBuffer^[lLineStart+lInc-1]<>kRenderInfiniteDepth) and (lRenderDepthBuffer^[lLineStart+lInc]<>kRenderInfiniteDepth) and (lRenderDepthBuffer^[lLineStart+lInc+1]<>kRenderInfiniteDepth) and (lRenderDepthBuffer^[lNextLineStart+lInc-1]<>kRenderInfiniteDepth) and (lRenderDepthBuffer^[lNextLineStart+lInc]<>kRenderInfiniteDepth) and (lRenderDepthBuffer^[lNextLineStart+lInc+1]<>kRenderInfiniteDepth) then begin lYVal := lRenderDepthBuffer^[lPrevLineStart+lInc-1]+lRenderDepthBuffer^[lPrevLineStart+lInc]+lRenderDepthBuffer^[lPrevLineStart+lInc+1] -lRenderDepthBuffer^[lNextLineStart+lInc-1]-lRenderDepthBuffer^[lNextLineStart+lInc]-lRenderDepthBuffer^[lNextLineStart+lInc+1]; lXVal := lRenderDepthBuffer^[lPrevLineStart+lInc-1]+lRenderDepthBuffer^[lLineStart+lInc-1]+lRenderDepthBuffer^[lNextLineStart+lInc-1] -lRenderDepthBuffer^[lPrevLineStart+lInc+1]-lRenderDepthBuffer^[lLineStart+lInc+1]-lRenderDepthBuffer^[lNextLineStart+lInc+1]; lNormalPlane := sqrt(sqr(lXVal)+sqr(lYVal)+sqr(lMagic)); if lNormalPlane <> 0 then begin lNormalPlane := -((-lXLight*lXVal)-(lYLight*lYVal)+lMagic*lZLight)/lNormalPlane; if {lImageAndShade} false then begin lNormalPlane := Power(lNormalPlane,lPhongMagic); //lIntensity := gProjBuffer[lLineStart+lInc]; //lIntensity := lPropShadingPivot+round((lPctImage*(lIntensity-lPropShadingPivot))+(lPctShade*(lNormalPlane-0.5)) ); if lIntensity > 254 then lIntensity := 254; lShadeBuffer^[lLineStart+lInc] := lIntensity; end else begin //shading only //if lAbbaRandom then //abba lNormalPlane := (lNormalPlane+1) / 2; if lNormalPlane > 0 then begin lNormalPlane := Power(lNormalPlane,lPhongMagic); //if lAbbaRandom then //abba //if lNormalPlane < 0.5 then lNormalPlane := 1-lNormalPlane; //backlighting lShadeBuffer^[lLineStart+lInc] := lGrayMin{64}+ round(lNormalPlane*(lGrayMax)); end else lShadeBuffer^[lLineStart+lInc] := lGrayMin; end; //Shading vs ImageAndShading end; //NormalPlane = 0 end else begin //samples for each pixel if {lImageAndShade}false then lShadeBuffer^[lLineStart+lInc] := 0//lPropShadingPivot+round((lPctImage*(gProjBuffer[lLineStart+lInc]-lPropShadingPivot))+(lPctShade*(-0.5)) )//1362 else lShadeBuffer^[lLineStart+lInc] := lGrayMin;//1363;'# 20{64}; end; end; //only shade non-zero intensities end; //columns end; //for scanlines: rows if lPct > 99 then begin for lInc := 1 to (lX*lY) do lImgBuffer^[lInc] := lShadeBuffer^[lInc]; end else begin //partial shade lImgFrac := (100-lPct)/100; lShadeFrac := lPct/100; for lInc := 1 to (lX*lY) do lImgBuffer^[lInc] := round((lImgBuffer^[lInc]* lImgFrac) + (lShadeBuffer^[lInc]*lShadeFrac )); end; freemem(lShadeBuffer); result := true; end; //function illuminationshading procedure LUTLoad( lLUTindex: integer; var lLUT: TLUT); var lHdr: TMRIcroHdr; lStr: string; lInc: integer; begin //gMRIcroOverlay[lLayer].LUTindex := LUTdrop.ItemIndex; if lLUTindex < knAutoLUT then begin LoadMonochromeLUT(lLUTindex,gBGImg,lHdr); end else begin //if B&W lut lStr := gColorSchemeDir+pathdelim+ImgForm.LUTdrop.Items.Strings[lLUTindex]+'.lut'; if not FileExistsEX(lStr) then showmessage('Can not find '+lStr); LoadColorScheme(lStr, lHdr); end; for lInc := 0 to 255 do lLUT[lInc] := lHdr.LUT[lInc]; end; procedure CreateRender(var lBGHdr, lHdr: TMRIcroHdr; var lX,lY,lZ,lInRenderSurface,lInRenderDpeth: Integer; var lQuadP: RGBQuadp; Smooth2D, NormalizeIntensity,lCreateDepthBuffer: boolean;lUseDepthBuffer: integer); var lLUT : array [0..255] of byte; lrgbLUT: TLUT;// array[0..255] of TRGBQuad; //lTime: DWord; lSrc,lOutBuffer: Bytep; lShade,lShadePrecise: boolean; lPreciseDepthBuffer: Smallintp; lMaxInten,lDepth,lPixel,lSamples,lSliceOffset,lIntensity,lSliceSz,lSliceEnd,lSliceStart, lVolSz,lRenderDepth,lRenderSurface,lTemp,lNear,lSubPixel,lClip: integer; begin lShade := false; lShadePrecise := false; if {(gRender.BGNearClip<>0) or} (gRender.ShowCutout) then lMaxInten := 254 else lMaxInten := 257; lRenderDepth := lInRenderDpeth; if (lHdr.IMgBufferItems > 0) {2/2008} and (lHdr.NIFTIhdr.intent_code = kNIFTI_INTENT_LABEL) then lRenderDepth := 1; lRenderSurface := lInRenderSurface; //if not lCreateDepthBuffer then if (lHdr.IMgBufferItems > 0) {2/2008} and (lHdr.NIFTIhdr.intent_code = kNIFTI_INTENT_LABEL) then lRenderSurface := 1 else begin //make sure at least some voxels are below air-surface threshold if (lHdr.WindowScaledMin <= (Raw2ScaledIntensity(lHdr,lHdr.GlMinUnscaledS) )) and (lHdr.WindowScaledMax <> 0 ) then begin lTemp := round( (Raw2ScaledIntensity(lHdr,lHdr.GlMinUnscaledS)-lHdr.WindowScaledMin)/(lHdr.WindowScaledMax)*255); //showmessage(inttostr(lTemp)); if lTemp >= lRenderSurface then lRenderSurface := lTemp + 1; end; end; if (lUseDepthBuffer=kBelow) then begin CreateOverlayRenderBehind(lBGHdr,lHdr, lX,lY,lZ,lRenderSurface,lRenderDepth, lQuadP, Smooth2D); exit; end; if (lUseDepthBuffer=kInFront) then begin CreateOverlayRenderInfrontNear(lBGHdr,lHdr, lX,lY,lZ,lRenderSurface,lRenderDepth, lQuadP, Smooth2D); exit; end; lSrc := lHdr.RenderBuffer; lSliceSz := lX*lY; lVolSz := lSliceSz * lZ; GetMem (lOutBuffer , lX*lY); //gRender.ClipFrac := kMaxFrac div 2; lClip := round(gRender.ClipFrac/kMaxFrac * lX); if lClip >= lX then lClip := 0; if lCreateDepthBuffer then begin if (gRender.ShadePct > 0) then begin lShade := true; if lRenderDepth > 0 then begin//not MIP lShadePrecise := true; getmem(lPreciseDepthBuffer,lSliceSz * sizeof(smallint)); fillchar(lPreciseDepthBuffer^,lSliceSz* sizeof(smallint),0); end; end; if gBGImg.RenderDepthBufferItems <> lSliceSz then begin if gBGImg.RenderDepthBufferItems > 0 then Freemem(gBGImg.RenderDepthBuffer); gBGImg.RenderDepthBufferItems := lSliceSz; GetMem(gBGImg.RenderDepthBuffer,lSliceSz*sizeof(smallint)); end; fillchar(gBGImg.RenderDepthBuffer^,lSliceSz* sizeof(smallint),0); //lTime := gettickcount; if lRenderDepth < 1 then begin//MIP for lPixel := 1 to lSliceSz do begin lIntensity := 0; lSliceStart := ((lPixel-1)* lX)+1; lSliceOffset := lSliceStart+lClip; //start with nearest slice lSliceEnd := lSliceStart + lX; while (lSliceOffset < lSliceEnd) do begin if (lSrc^[lSliceOffset] < lMaxInten) and (lSrc^[lSliceOffset] > lIntensity) then begin lIntensity := lSrc^[lSliceOffset]; gBGImg.RenderDepthBuffer^[lPixel] := lSliceOffset - lSliceStart; end; inc(lSliceOffset,1); end; //while traversing front to back lOutBuffer^[lPixel]:= lIntensity; end; //for each pixel end else begin //if MIP else use opacity filter... for lPixel := 1 to lSliceSz do begin lDepth := 0; lSamples := 0; lIntensity := 0; lSliceStart := ((lPixel-1)* lX)+1; lSliceOffset := lSliceStart+lClip; //start with nearest slice lSliceEnd := (lPixel* lX); while (lDepth < lRenderDepth) and (lSliceOffset < lSliceEnd) do begin if (lSrc^[lSliceOffset] < lMaxInten) and ((lDepth > 0) or (lSrc^[lSliceOffset] > lRenderSurface)) then begin inc(lDepth); if (lSrc^[lSliceOffset] > lRenderSurface) then begin lIntensity := lIntensity+ lSrc^[lSliceOffset]; inc(lSamples); end; if (lDepth = 1) then begin gBGImg.RenderDepthBuffer^[lPixel] := lSliceOffset - lSliceStart; if (gBGImg.RenderDepthBuffer^[lPixel]=lCLip ) or ((gBGImg.RenderDepthBuffer^[lPixel] > 1) and (lSrc^[lSliceOffset-1]>=lMaxInten)) then begin //cutout if lSrc^[lSliceOffset-1]=lMaxInten-1 then lIntensity := 0; lDepth := lRenderDepth; gBGImg.RenderDepthBuffer^[lPixel] := -gBGImg.RenderDepthBuffer^[lPixel]; //negative: this is a cutout end; if lShade then begin if (gBGImg.RenderDepthBuffer^[lPixel] > 1) then begin //estimate surface depth with sub-pixel accuracy lNear := lSrc^[lSliceOffset-1]; lSubPixel := lIntensity-lNear; //delta lSubPixel := round(((lRenderSurface-lNear)/lSubPixel)*10); if lNear >= lMaxInten then //cutout lSubPixel := 0; end else lSubpixel := 0; lPreciseDepthBuffer^[lPixel] := (gBGImg.RenderDepthBuffer^[lPixel] * 10)+lSubPixel; end; end; end; inc(lSliceOffset,1); end; //while no voxel found if lDepth > 0 then lIntensity := lIntensity div lSamples; //lIntensity := lIntensity div lDepth; //mean of nDepth voxels lOutBuffer^[lPixel]:= lIntensity; end; //for each pixel 1..sliceSz if (Smooth2D) and (lHdr.NIFTIhdr.intent_code <> kNIFTI_INTENT_LABEL) then //do not smooth labels Smooth2DImage (lX,lY, lOutBuffer); //only smooth volume renderings - not MIPS (they looked embossed) end; //if not MIP end else begin //do not create depth buffer for lPixel := 1 to lSliceSz do begin lDepth := 0; lSamples := 0; lIntensity := 0; lSliceOffset := ((lPixel-1)* lX)+1+lClip; //start with nearest slice lSliceEnd := (lPixel* lX); while (lDepth < lRenderDepth) and (lSliceOffset < lSliceEnd) do begin if (lSrc^[lSliceOffset] < lMaxInten) and ((lDepth > 0) or (lSrc^[lSliceOffset] > lRenderSurface)) then begin inc(lDepth); if (lSrc^[lSliceOffset] > lRenderSurface) then begin lIntensity := lIntensity+ lSrc^[lSliceOffset]; inc(lSamples); end; end; inc(lSliceOffset,1); end; //while no voxel found if lDepth > 0 then lIntensity := lIntensity div lSamples; //lIntensity := lIntensity div lDepth; //mean of nDepth voxels lOutBuffer^[lPixel]:= lIntensity; end; //for each pixel end; //volume render without depth buffer //RenderForm.Caption := inttostr(gettickcount - lTime)+' '+inttostr(lRenderDepth); if (NormalizeIntensity) and (lRenderSurface < 254) then begin //do BEFORE shading! for lPixel := 0 to 255 do lLUT[lPixel] := 0; for lPixel := lRenderSurface to 255 do lLUT[lPixel] := round(255*(lPixel-lRenderSurface)/(255-lRenderSurface)); for lPixel := 1 to lSliceSz do lOutBuffer^[lPixel] := lLUT[lOutBuffer^[lPixel]]; end; if lShade then begin if lShadePrecise then begin SmoothShading (lX,lY,lPreciseDepthBuffer); IlluminationShading(lX,lY,gRender.ShadePct,lOutBuffer,lPreciseDepthBuffer{gBGImg.RenderDepthBuffer} ); freemem(lPreciseDepthBuffer); end else IlluminationShading(lX,lY,gRender.ShadePct,lOutBuffer,gBGImg.RenderDepthBuffer); end;//shading for lPixel := 0 to 255 do lrgbLUT[lPixel] := lHdr.LUT[lPixel]; if (lHdr.NIFTIhdr.intent_code <> kNIFTI_INTENT_LABEL) then LUTGainX(lrgbLUT,gRender.Bias,gRender.Gain ); //Mar2007 for lPixel := 1 to lSliceSz do lQuadP^[lPixel]:= lrgbLUT[lOutBuffer^[lPixel]]; if ((lClip >0) or (gRender.ShowCutout)) and (lCreateDepthBuffer) then begin //make cutout grayscale, shade edges if gRender.ShowCutout then ShadeCutoutCrease(lOutBuffer); LUTLoad(gRender.cutoutLUTindex,lrgblut);//11/2007 {for lPixel := 0 to 255 do begin lrgbLUT[lPixel].rgbRed := lPixel; lrgbLUT[lPixel].rgbGreen := lPixel; lrgbLUT[lPixel].rgbBlue := lPixel; lrgbLUT[lPixel].rgbReserved := kLUTalpha; end;}//create grayscale LUT LUTBiasX(lrgbLUT); for lPixel := 1 to lSliceSz do if gBGImg.RenderDepthBuffer^[lPixel]<0 then //cutout lQuadP^[lPixel]:= lrgbLUT[lOutBuffer^[lPixel]]; end; //if BGimg with Cutout Freemem(lOutBuffer); end; function RenderDepth (lVal: integer): integer;//11/2007 begin if (lVal > 0) and (lVal < 16000) and (gBGImg.ScrnMM[1] > 0.1) and (gBGImg.ScrnMM[1] < 10) then begin result:= round (lVal / gBGImg.ScrnMM[1]); if result < 1 then result := 1; end else result := lVal; result := round(result * gRender.Zoom); end; procedure DrawRender; var lBGQuadP, lOverlayQuadP, l2ndOverlayQuadP: RGBQuadp; lUseBGSurface,lnOverlay,lOverlay, lX,lY,lZ,lSliceSz,lRenderSurface,lRenderDepth: longint; lBG0Clr,lOverlay0Clr: DWord; lSmooth : boolean; begin lRenderSurface := gRender.BGSurface; //lRenderDepth:= gRender.BGDepth; lRenderDepth:= RenderDepth(gRender.BGDepth);//11/2007 lSmooth := gRender.SmoothBG; lUseBGSurface := gRender.OverlayFromBGSurface ; lX := gMRIcroOverlay[kBGOverlayNum].RenderDim; lY := lX; lZ := lX; lSliceSz := (lX * lY); if (gMRIcroOverlay[kBGOverlayNum].RenderBufferItems=0)or (lX < 2) or (lY < 2) or (lZ < 2) or ((lX*lY*lZ) > gMRIcroOverlay[kBGOverlayNum].RenderBufferItems{ScrnBufferItems}) then exit; GetMem ( lBGQuadP, lSliceSz*4); CreateRender(gMRIcroOverlay[kBGOverlayNum],gMRIcroOverlay[kBGOverlayNum], lX,lY,lZ,lRenderSurface,lRenderDepth, lBGQuadP, lSmooth, true,true,0); //next: overlays lSmooth := gRender.SmoothOverlay; lRenderSurface := gRender.OverlaySurface; //lRenderDepth:= gRender.OverlayDepth; lRenderDepth:= RenderDepth(gRender.OverlayDepth);//11/2007 lnOverlay := 0; lBG0Clr:= TRGBQuad2DWord(gMRIcroOverlay[0].LUTinvisible);//just to avoid compiler warning hint - never used... for lOverlay := knMaxOverlay downto 1 do begin if gMRIcroOverlay[lOverlay].RenderBufferItems{ScrnBufferItems} > 0 then begin if lOverlay = kVOIOverlayNum then //Aug2007 lRenderSurface := 0 else lRenderSurface := gRender.OverlaySurface;// inc(lnOverlay); if lnOverlay = 1 then begin //top overlay GetMem ( lOverlayQuadP , lSliceSz*4); lBG0Clr:= TRGBQuad2DWord(gMRIcroOverlay[lOverlay].LUTinvisible); CreateRender(gMRIcroOverlay[kBGOverlayNum],gMRIcroOverlay[lOverlay],lX,lY,lZ,lRenderSurface,lRenderDepth,lOverlayQuadP,lSmooth,false,false,lUseBGSurface); end else begin //2nd or lower overlay if lnOverlay = 2 then //2nd overlay GetMem ( l2ndOverlayQuadP , lSliceSz*4); CreateRender(gMRIcroOverlay[kBGOverlayNum],gMRIcroOverlay[lOverlay], lX,lY,lZ,lRenderSurface,lRenderDepth,l2ndOverlayQuadP,lSmooth,false,false,lUseBGSurface); lOverlay0Clr:= TRGBQuad2DWord(gMRIcroOverlay[lOverlay].LUTinvisible); AlphaBlend32(lOverlayQuadP,l2ndOverlayQuadP, lBG0Clr,lOverlay0Clr, lSliceSz,gBGImg.OverlayTransPct); end; //2nd overlay or more end; //overlay loaded end; //for knOverlay..1 //Finally: draw overlays on BG if lnOverlay > 0 then begin lOverlay0Clr := lBG0Clr; //lBG0Clr := DWord(lHdr.LUTinvisible); lBG0Clr := 0;//0=impossible, no alpha DWord(lHdr.LUT[0]); if lnOverlay > 1 then FreeMem ( l2ndOverlayQuadP); AlphaBlend32(lBGQuadP,lOverlayQuadP, lBG0Clr,lOverlay0Clr, lSliceSz,gBGImg.BGTransPct); FreeMem ( lOverlayQuadP); end; //draw image SetDimension32(lY,lX, lBGQuadP, gBGImg, RenderForm.RenderImage, RenderForm.RenderPanel); SetDimension32(lY,lX, lBGQuadP, gBGImg, RenderForm.RenderImageBUP, RenderForm.RenderPanel); FreeMem ( lBGQuadP); if gBGImg.RenderDepthBufferItems > 0 then //negative depth was used for cutouts, now set to true depth for lX := 1 to gBGImg.RenderDepthBufferItems do gBGImg.RenderDepthBuffer^[lX] := abs(gBGImg.RenderDepthBuffer^[lX]); end; procedure SliceToFrac(var lBGImg: TBGImg); var lInc: integer; begin SortCutOut (gRender.CutOut); for lInc := 1 to 3 do begin if lBGImg.ScrnDim[lInc] < 1 then begin gRender.CutoutFrac.Lo[lInc] := round (0.5* kMaxFrac); gRender.CutoutFrac.Hi[lInc] := kMaxFrac; end else begin gRender.CutoutFrac.Lo[lInc] := round(kMaxFrac * gRender.Cutout.Lo[lInc]/lBGImg.ScrnDim[lInc]); gRender.CutoutFrac.Hi[lInc] := round(kMaxFrac * gRender.Cutout.Hi[lInc]/lBGImg.ScrnDim[lInc]); end; end; end; procedure SetLimits(var lBGImg: TBGImg); var lInc: integer; lUpdateCutout: boolean; lScale: single; begin SortCutOut (gRender.CutOutFrac); if gRender.CutoutFrac.Lo[1] < 0 then SliceToFrac(lBGImg); lScale := 1/kMaxFrac; for lInc := 1 to 3 do begin gRender.Cutout.Lo[lInc] := round(gBGImg.ScrnDim[lInc] * lScale * gRender.CutoutFrac.Lo[lInc]); gRender.Cutout.Hi[lInc] := round(gBGImg.ScrnDim[lInc] * lScale * gRender.CutoutFrac.Hi[lInc]); end; lUpdateCutout := true; for lInc := 1 to 3 do if gRender.Cutout.Lo[lInc] <> gRender.Cutout.Hi[lInc] then lUpdateCutout := false; if lUpdateCutout then for lInc := 1 to 3 do begin gRender.Cutout.Lo[lInc] := gBGImg.ScrnDim[lInc] div 2; gRender.Cutout.Hi[lInc] := gBGImg.ScrnDim[lInc]; end; for lInc := 1 to 3 do begin if gRender.Cutout.Lo[lInc] < 1 then gRender.Cutout.Lo[lInc] := 1; if gRender.Cutout.Lo[lInc] > lBGImg.ScrnDim[lInc] then gRender.Cutout.Lo[lInc] := lBGImg.ScrnDim[lInc]; if gRender.Cutout.Hi[lInc] < 1 then gRender.Cutout.Hi[lInc] := 1; if gRender.Cutout.Hi[lInc] > lBGImg.ScrnDim[lInc] then gRender.Cutout.Hi[lInc] := lBGImg.ScrnDim[lInc]; end; end; procedure VolumeRotateMatrix (var lBGImg: TBGImg; var lHdr: TMRIcroHdr; var lMatrixIn: TMatrix; lBilinearSmooth,lRenderCutout,lIsBG: boolean {;lNearSlicesClipIn: integer}); label 345; const kUgly2 = 10000; //kSh = 10; //bits to shift kUgly1 = (kUgly2 shl kSh) + (1 shl kSh); var l: TRotateVals; lZinc,lZ,lY,lX,lOutVolSz, lOutPos,lInVolSz, lYo,lZo,lnThreads: integer; lBuffIn,lSrcBuff,lBuffOut: Bytep; lXxp,lXyp,lXzp: Pointer; lStartTime: DWord; lM, lScale,lMatrix: TMatrix; lZoomRatio: Single; begin lMatrix := lMatrixIn; if (gRender.Zoom <> 0) and (gRender.Zoom <> 1 )then begin lZoomRatio := 1/gRender.Zoom; lScale := Matrix3D(lZoomRatio,0,0,0, 0,lZoomRatio,0,0, 0,0,lZoomRatio,0, 0,0,0,0); lMatrix := MultiplyMatrices(lMatrixIn,lScale); end else gRender.Zoom := 1; //lScale := Matrix3D(0,1,0,0, 1,0,0,0, 0,0,1,0, 0,0,0,0); //lScale := Matrix3D(0,1,0,0, 0,0,1,0, 1,0,0,0, 0,0,0,0); lScale := Matrix3D(0,1,0,0, 0,0,1,0, 1,0,0,0, 0,0,0,0); lMatrix := MultiplyMatrices(lMatrix,lScale); lStartTime := GetTickCount; l.XdimIn := lBGImg.ScrnDim[1]; l.YdimIn := lBGImg.ScrnDim[2]; l.ZdimIn := lBGImg.ScrnDim[3];; l.InSliceSz := l.XDimIn*l.YDimIn; lInVolSz := l.XdimIn*l.YdimIn*l.ZdimIn; //InVolSz! if (lHdr.ScrnBufferItems < lInVolSz) then exit; lSrcBuff := lHdr.ScrnBuffer; l.OutDim := MaxDim(l.XDimIn,l.YDimIn,l.ZDimIn); l.OutDim := round(gRender.Zoom * l.OutDim); //11/2007 (*lNearSlicesClip := lNearSlicesClipIn;//May07 if lNearSlicesClip >= l.OutDim then //May07 lNearSlicesClip := 0; //May07*) lBGImg.RenderDim := l.OutDim; lHdr.RenderDim := l.OutDim; //l.RenderCutout := false; if (lRenderCutout) then begin //l.RenderCutout := true; SetLimits(lBGImg); GetMem(lBuffIn, lInVolSz); Move(lSrcBuff^,lBuffIn^,lInVolSz); for lZ := 1 to lInVolSz do if lBuffIn^[lZ] >= 254 then lBuffIn^[lZ] := 253; if lRenderCutout then begin for lZ := gRender.Cutout.Lo[3] to gRender.Cutout.Hi[3] do begin lZo := (lZ-1) * l.InSliceSz; Application.ProcessMessages; for lY := gRender.Cutout.Lo[2] to gRender.Cutout.Hi[2] do begin lYo := (lY-1) * l.XdimIn; for lX := gRender.Cutout.Lo[1] to gRender.Cutout.Hi[1] do lBuffIn^[lX+lYo+lZo] := 255; end; //for lY end; //for lZ end; end else lBuffIn := lSrcBuff; l.OutPivot := (lHdr.RenderDim+1) shr 1; //e.g. if DimMax=9, then pivot is 5 l.XPivotIn := ((l.XdimIn+1) shr 1); //e.g. if DimMax=9, then pivot is 5 l.YPivotIn := ((l.YdimIn+1) shr 1); //e.g. if DimMax=9, then pivot is 5 l.ZPivotIn := ((l.ZdimIn+1) shr 1); //e.g. if DimMax=9, then pivot is 5 l.YDimStart := -l.OutPivot+1; //e.g. if 9, start from -4 l.ZDimStart := l.YDimStart ; l.YDimEnd := l.YDimStart+lHdr.RenderDim-1; //e.g. if 9, go to 4 l.ZDimEnd := l.YDimEnd; if l.ZDimStart >= l.ZDimEnd then l.ZDImStart := l.ZDimStart; l.OutSliceSz := sqr(lHdr.RenderDim); lOutVolSz := lHdr.RenderDim*l.OutSliceSz; if lHdr.RenderBufferItems <> lOutVolSz then begin if lHdr.RenderBufferItems > 0 then Freemem(lHdr.RenderBuffer); lHdr.RenderBufferItems := lOutVolSz; try GetMem(lHdr.RenderBuffer,lOutVolSz); except //12/2007 showmessage('Volume Rotate Error: System memory exhausted.'); lHdr.RenderBufferItems := 0; exit; end; end; lBuffOut := lHdr.RenderBuffer; fillchar(lBuffOut^,lOutVolSz,0); //set all to zero //lMatrix := InvertMatrix3D(lMatrix); lZ := (sizeof(longint)* l.OutDim)+16; GetMem(lXxp, lZ); GetMem(lXyp, lZ); GetMem(lXzp, lZ); // if RenderForm.RenderRefreshTimer.enabled then goto 345;//abort {$IFNDEF FPC} l.XxRA := LongIntP($fffffff0 and (integer(lXxP)+15)); //data aligned to quad-word boundary l.XyRA := LongIntP($fffffff0 and (integer(lXyP)+15)); //quad-word boundary l.XzRA := LongIntP($fffffff0 and (integer(lXzP)+15)); //quad-word boundary} {$ELSE} l.XxRA := system.align(lXxP, 16); //data aligned to quad-word boundary l.XyRA := system.align(lXyP, 16); //quad-word boundary l.XzRA := system.align(lXzP, 16); //quad-word boundary {$ENDIF} for lX := 1 to l.OutDim do begin l.XxRA^[lX] := round((lX-l.OutPivot)*lMatrix.matrix[1,1]* (1 shl kSh) )+kUgly1; l.XyRA^[lX] := round((lX-l.OutPivot)*lMatrix.matrix[2,1]* (1 shl kSh) )+kUgly1; l.XzRA^[lX] := round((lX-l.OutPivot)*lMatrix.matrix[3,1]* (1 shl kSh) )+kUgly1; end; l.XPivotInU2 := l.XPivotIn-kUgly2; l.YPivotInU2 := l.YPivotIn-kUgly2; l.ZPivotInU2 := l.ZPivotIn-kUgly2; {$IFNDEF NoThreads} lnThreads := gnCPUThreads; {$ELSE} lnThreads := 1; {$ENDIF} //if lIsBG then //TextForm.Memo1.Lines.Add( 'bg'+(inttostr(RenderForm.ThreadsRunning)+' '+inttostr(lnThreads))) //else //TextForm.Memo1.Lines.Add( 'xx'+(inttostr(RenderForm.ThreadsRunning)+' '+inttostr(lnThreads))); lZ := l.ZDimStart; lZo := l.ZDimEnd; lZinc := (l.ZDimEnd - l.ZDimStart) div lnThreads; l.ZDimEnd := l.ZDimStart + lZinc; //showmessage( inttostr(l.ZDimStart)+'..'+inttostr(l.ZDimEnd) +' '+inttostr(lZo)); if l.ZDimEnd > ImgForm.ProgressBar1.Min then begin //crashes if max < min, so write order important... ImgForm.ProgressBar1.Max := l.ZDimEnd+1; ImgForm.ProgressBar1.Min := l.ZDimStart; end else begin ImgForm.ProgressBar1.Min := l.ZDimStart; ImgForm.ProgressBar1.Max := l.ZDimEnd+1; end; {$IFNDEF NoThreads} Application.processmessages; for lX := 1 to lnThreads do begin if lX = lnThreads then l.ZDimEnd := lZo; //avoid integer rounding error //TextForm.Memo1.Lines.Add('+'+inttostr(lX)); if (lBilinearSmooth) and (lHdr.NIFTIhdr.intent_code <> kNIFTI_INTENT_LABEL) then TTriRender.Create(ImgForm.ProgressBar1,lX,l,lMatrix, lRenderCutout, lBuffIn,lBuffOut) else TNNRender.Create(ImgForm.ProgressBar1,lX,l,lMatrix, lRenderCutout, lBuffIn,lBuffOut); inc(ThreadsRunning); l.ZDimStart := l.ZDimEnd + 1; l.ZDimEnd := l.ZDimEnd + lZInc; end; //for each thread l.ZDimStart := lZ; repeat Application.processmessages; until ThreadsRunning = 0; Application.processmessages; {$ELSE}//not threaded l.ZDimEnd := lZo; //avoid integer rounding error if (lBilinearSmooth) and (lHdr.NIFTIhdr.intent_code <> kNIFTI_INTENT_LABEL) then TriRotate(ImgForm.ProgressBar1,l,lMatrix, lRenderCutout, lBuffIn,lBuffOut) else NNRotate(ImgForm.ProgressBar1,l,lMatrix, lRenderCutout, lBuffIn,lBuffOut); {$ENDIF} FreeMem(lXxp); FreeMem(lXyp); FreeMem(lXzp); if (lRenderCutout) then begin FreeMem(lBuffIn); end; ImgForm.ProgressBar1.Position := l.ZDimStart; ImgForm.StatusLabel.caption :=('update(ms): '+inttostr(GetTickCount-lStartTime)); end; //proceudre VolumeRotate; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/crop_old.pas�������������������������������������������������������0000755�0001750�0001750�00000017042�11326425442�016520� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit crop; interface function CropNIfTI(lL,lR,lA,lP,lD,lV: integer):boolean; implementation uses nifti_hdr, nifti_img,define_types, GraphicsMathLibrary,dialogs, nifti_img_view; procedure NIFTIhdr_SlicesToCoord (var lHdr: TNIFTIhdr; lXslice,lYslice,lZslice: integer; var lXmm,lYmm,lZmm: single); //ignores origin offset begin lXmm := (lHdr.srow_x[0]*lXslice)+ (lHdr.srow_x[1]*lYslice)+(lHdr.srow_x[2]*lzslice); lYmm := (lHdr.srow_y[0]*lXslice)+ (lHdr.srow_y[1]*lYslice)+(lHdr.srow_y[2]*lzslice); lZmm := (lHdr.srow_z[0]*lXslice)+ (lHdr.srow_z[1]*lYslice)+(lHdr.srow_z[2]*lzslice); end; function CropNIfTI(lL,lR,lA,lP,lD,lV: integer):boolean; //to do : data swapping (errors on detection and writing zero in reverse order) var lInHdr,lOutHdr: TNIFTIhdr; lOutname,lExt: string; lXmm,lYmm,lZmm: single; lMat: TMatrix; lOutPos,lSlice,lVol,lVolBytes,lImgSamples,lInc, lX,lY,lZ,lBPP, lB, lInZOffset,lInYOffset,lInSliceSz,lInXSz,lInPos,lImgOffset: integer; lBuffer: bytep; (*lSrcBuffer,lBuffer, lBuffUnaligned: bytep; l32Buf,lImgBuffer: singlep; l16Buf : SmallIntP; l32BufI : LongIntP;*) lWordX: Word; lSPM2: boolean; lOutF,lInF: File; lACrop,lPCrop,lDorsalCrop,lVentralCrop,lLCrop,lRCrop: integer; lByteSwap: boolean; begin result := false; if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1) or (gBGImg.ScrnDim[3] < 2) or (gBGImg.ScrnMM[3] = 0) then begin showmessage('Please load a 3D background image for neck removal.'); exit; end; if (gBGImg.Resliced) then begin showmessage('You must switch reslicing OFF (Help/Preferences) for image cropping.'); exit; end; lInHdr := gMRIcroOverlay[kBGOverlayNum].NIFTIHdr; //check orthogonal alignment.... if lInHdr.dim[4] > 1 then begin Showmessage('Only able to Crop 3D images (reorienting 4D could disrupt slice timing and diffusion directions.'); exit; end; //Next create reordered or trimmed image in the correct format case lInHdr.datatype of kDT_UNSIGNED_CHAR,kDT_SIGNED_SHORT,kDT_UINT16, kDT_SIGNED_INT,kDT_FLOAT:;//Supported else begin Showmessage('Crop 3D unsupported datatype.'); exit; end; end; //Msg('Cropping NIfTI/Analyze image '+lFileName); lOutHdr := lInHdr; lImgSamples := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]; lBPP := (lInHdr.bitpix div 8); //bytes per pixel (*lVolBytes := lImgSamples*lBPP; //Msg('Automatically Cropping image'); lBuffer := (@lSrcBuffer^[lImgOffset+1]); GetMem(lBuffUnaligned ,(sizeof(single)*lImgSamples) + 16); {$IFDEF FPC} lImgBuffer := align(lBuffUnaligned,16); {$ELSE} lImgBuffer := SingleP($fffffff0 and (integer(lBuffUnaligned)+15)); {$ENDIF} case lInHdr.datatype of kDT_UNSIGNED_CHAR : begin //8 bit for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := lBuffer^[lInc]; end; kDT_SIGNED_SHORT{,kDT_UINT16}: begin //16-bit int l16Buf := SmallIntP(lBuffer ); if lByteSwap then begin for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := Swap(l16Buf^[lInc]); end else begin for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := l16Buf^[lInc]; end; end;//16bit kDT_SIGNED_INT: begin l32Buf := SingleP(lBuffer ); if lByteSwap then //unswap and convert integer to float for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := (Swap4r4i(l32Buf^[lInc])) else //convert integer to float for lInc := 1 to lImgSamples do lImgBuffer^[lInc] := Conv4r4i(l32Buf^[lInc]); end; //32-bit int kDT_FLOAT: begin l32Buf := SingleP(lBuffer); for lInc := 1 to lImgSamples do lImgBuffer[lInc] := l32Buf[lInc]; if lByteSwap then for lInc := 1 to lImgSamples do pswap4r(lImgBuffer^[lInc]); //faster as procedure than function see www.optimalcode.com for lInc := 1 to lImgSamples do if specialsingle(lImgBuffer^[lInc]) then lImgBuffer^[lInc] := 0.0; //invert= for lInc := 1 to lImgSamples do l32Buf[lInc] := -l32Buf[lInc]; end; //32-bit float else begin Showmessage('Serious error: format not supported by Crop3D.'); exit; end; end; //case *) lDorsalCrop := lD; lVentralCrop := lV; lLCrop := lL; lRCrop := lR; lACrop := lA; lPCrop := lP; //FreeMem(lBuffUnaligned); if (lDorsalCrop = 0) and (lVentralCrop = 0) and (lLCrop = 0) and (lRCrop = 0) and (lACrop = 0) and (lPCrop = 0) then begin Showmessage('Crop 3D quitting: no need to delete slices.'); //Freemem(lSrcBuffer); end; if (lDorsalCrop < 0) or (lVentralCrop < 0) or (lLCrop < 0) or (lRCrop < 0) or (lACrop < 0) or (lPCrop < 0) then begin Showmessage('Crop 3D quitting: negative values should be impossible.'); //Freemem(lSrcBuffer); end; //next compute size of cropped volume lOutHdr.Dim[1] := lInHdr.Dim[1]-lLCrop-lRCrop; lOutHdr.Dim[2] := lInHdr.Dim[2]-lACrop-lPCrop; lOutHdr.Dim[3] := lInHdr.Dim[3]-lDorsalCrop-lVentralCrop; lVolBytes := lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3]*lBPP; //next: readjust origin to take into account removed slices //REQUIRES images to be aligned to nearest orthogonal to canonical space [1 0 0; 0 1 0; 0 0 1] NIFTIhdr_SlicesToCoord (lInHdr,lLCrop,lPCrop,lVentralCrop, lXmm,lYmm,lZmm); lOutHdr.srow_x[3] := lInHdr.srow_x[3] + lXmm; lOutHdr.srow_y[3] := lInHdr.srow_y[3] + lYmm; lOutHdr.srow_z[3] := lInHdr.srow_z[3] + lZmm; lMat := Matrix3D ( lOutHdr.srow_x[0], lOutHdr.srow_x[1], lOutHdr.srow_x[2], lOutHdr.srow_x[3], lOutHdr.srow_y[0], lOutHdr.srow_y[1], lOutHdr.srow_y[2], lOutHdr.srow_y[3], lOutHdr.srow_z[0], lOutHdr.srow_z[1], lOutHdr.srow_z[2], lOutHdr.srow_z[3], 0, 0, 0, 1); nifti_mat44_to_quatern( lMat, lOutHdr.quatern_b,lOutHdr.quatern_c,lOutHdr.quatern_d, lOutHdr.qoffset_x,lOutHdr.qoffset_y,lOutHdr.qoffset_z, lXmm, lYmm, lZmm, lOutHdr.pixdim[0]{QFac}); //note we write and read to the same buffer - we will always SHRINK output //no need to byteswap data - we will save in the save format as stored lOutPos := 0; lInSliceSz := lInHdr.dim[1]*lInHdr.dim[2]*lBPP; lInXSz := lInHdr.dim[1]*lBPP; GetMem(lBuffer,lVolBytes); //Move(gMRIcroOverlay[kBGOverlayNum].ImgBuffer^,lTempBuf^,gBGImg.VOIUndoVolItems); for lZ := 1 to lOutHdr.dim[3] do begin lInZOffset := (lVentralCrop+lZ-1) * lInSliceSz; for lY := 1 to lOutHdr.dim[2] do begin lInYOffset := ((lPCrop+lY-1) * lInXSz) + lInZOffset + (lLCrop*lBPP); for lX := 1 to lOutHdr.dim[1] do begin for lB := 1 to lBPP do begin inc(lOutPos); lInPos := ((lX-1) * lBPP) + lInYOffset + lB; lBuffer^[lOutPos] := gMRIcroOverlay[kBGOverlayNum].ImgBuffer^[lInPos]; end; end; end; //for Y end; //for Z lOutname := ChangeFilePrefix (gMRIcroOverlay[kBGOverlayNum].HdrFileName,'c'); //result := SaveNIfTICore (lOutName, lSrcBuffer, kNIIImgOffset+1, lOutHdr, lPrefs,lByteSwap); SaveAsVOIorNIFTI (lBuffer,lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3], lBPP,1, false, lOutHdr, lOutname); result := true; Freemem(lBuffer); end; end.����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/drop.patch���������������������������������������������������������0000755�0001750�0001750�00000005077�12307156446�016211� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������diff -uwNr --exclude=.svn --exclude=Makefile --exclude=Makefile.fpc --exclude=Makefile.compiled --exclude='*.rst' --exclude='*.po' lazarus/lcl/interfaces/carbon/carbonobject.inc lazarus.w/lcl/interfaces/carbon/carbonobject.inc --- lazarus/lcl/interfaces/carbon/carbonobject.inc 2013-11-16 10:59:07.000000000 +0000 ++ lazarus.w/lcl/interfaces/carbon/carbonobject.inc 2013-11-16 22:03:34.000000000 +0000 @@ -449,6 +449,62 @@ end; {------------------------------------------------------------------------------ Name: CarbonApp_DragReceive Handles dropping files on application ------------------------------------------------------------------------------} function CarbonApp_DragReceive(theWindow: WindowRef; handlerRefCon: UnivPtr; theDrag: DragRef): OSErr; {$IFDEF darwin}mwpascal;{$ENDIF} var theItemRef: DragItemRef; theFlavorData: HFSFlavor; theDataSize: Size; theFilename: pchar; theFileRef: FSRef; numItems: UInt16; Files: array of string; itemNum: UInt16; begin SetLength(Files, 0); numItems := 0; if CountDragItems(theDrag, numItems) <> noErr then exit; if numItems > 0 then for itemNum := 1 to numItems do begin if GetDragItemReferenceNumber(theDrag, itemNum, theItemRef) <> noErr then continue; theDataSize := sizeof(theFlavorData); if GetFlavorData(theDrag, theItemRef, kDragFlavorTypeHFS, @theFlavorData, theDataSize, 0) <> noErr then continue; FSpMakeFSRef(theFlavorData.fileSpec, theFileRef); theFilename := stralloc(1024); //PATH_MAX = 1024 FSRefMakePath(theFileRef, theFilename, StrBufSize(theFilename)); try SetLength(Files, Length(Files) + 1); Files[High(Files)] := theFilename; finally StrDispose(theFilename); end; end; if Length(Files) > 0 then begin if Application <> nil then begin if Application.MainForm <> nil then Application.MainForm.IntfDropFiles(Files); Application.IntfDropFiles(Files); end; end; Result := noErr; end; {------------------------------------------------------------------------------ Name: CarbonApp_Quit Handles application quit ------------------------------------------------------------------------------} @@ -1213,6 +1269,8 @@ InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_LazWake), 1, @TmpSpec, nil, @FAEventHandlerRef[5]); InstallReceiveHandler(@CarbonApp_DragReceive, nil, nil); FOpenEventHandlerUPP := NewAEEventHandlerUPP(AEEventHandlerProcPtr(@CarbonApp_Open)); FQuitEventHandlerUPP := NewAEEventHandlerUPP(AEEventHandlerProcPtr(@CarbonApp_Quit)); OSError( �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/changes.txt��������������������������������������������������������0000755�0001750�0001750�00000013506�11332777634�016376� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������2/2010 +dcm2niigui: help/preferences allows you to specifiy output folder. This can be a fixed location, or the user can be prompted with each conversion. +dcm2nii: option to process only specified files rather than searching all in folder. +MRIcron: Unix version: improved peristimulus plot data export (previous version only saved up to 255 characters per row) +MRIcron: Windows7 64-bit no longer reports floating point error. +dcm2niigui: Ability to select export directory. Previous version saved data to input directory. If you select Help/Preferences you can now select three modes: "Save to source folder" (default), "Prompt user for output folder", "Always save to...". -- "Prompt user for output folder" every time a series of images is dropped onto dcm2niigui, the user is requested to specify the output folder. -- "Always save to..." when this option is selected the user is requested to select an output folder. All future conversions are sent to this folder. +dcm2niigui: The ini files (stored in ~/.dcm2niigui for Unix and in the application directory for Windows) include two new properties: OutDirMode and OutDir -- "OutDirMode" this can have three values: 0="Save to source folder", 1="Prompt user for output folder", 2="Always save to..." -- "OutDir" This string lists the location for saving files if OutDirMode=2, and the starting location for selecting a folder for OutDirMode=1. If this is blank or a non-existent folder, it reverts to the users home directory (for Windows, this is the Documents folder). +dcm2niigui: If dcm2niigui is unable to find a ini file in ~/.dcm2niigui, it will open up the defaults file dcm2niigui.ini located in the same folder as the application. This allows Unix administrators give all users consistent settings tuned for their site (e.g. defaulting to SPM or FSL style files, etc). +dcm2niigui: Previous Linux 64-bit versions of dcm2niigui could have problems if the user did not have write permissions to the input images. This has been fixed. +dcm2niigui: now checks whether the user has write permission to the output directory, and gives the user a clear description of the problem if the output folder is read-only. ---- 2009 MRIcron +Images now shown with 2x2 row column format, with Coronal, Sagital on top row and Axial on second row. To return to old horizontal layout, choose Help/Preferences and select "All slices on single row" +Improved load of overlays on images with very few slices (I suggest you make sure View/3DSmoothOverlays is UNCHECKED if your background image only has a few slices). +The .ini file now includes the option "FlipAx=0", if you change this with a text-editor to read "FlipAx=1" and relaunch MRIcron the axial images will be displayed upside down (emulating ImageJ when viewing Analyze images). +Draw/Statistics/BatchProbMaps now reports mean instead of sum (with header text now saying "mean" instead of "filename). This ensures that one gets the same values as Draw/Descriptive (which reports mean, not sum). This also means that units are easier to interpret (as you do not have to divide the sum by the VOI's volume). +Removed View/Magnify tool from Windows version (I think there are better screen magnifiers). dcm2nii +4D par/rec files can now have different scaling factors +Philips has a new value in the ini file - use "PhilipsPrecise=0" to convert the DV (display values), use "PhilipsPrecise=1" for the FP (Floating point) values. Note that the raw image data is identical, this simply adjusts the scaling factor applied to the data. The "PhilipsPrecise=1" gives the correct values for Phase maps (from -Pi..+Pi) and diffusion images, but many people complain about the huge values generated for T1/T2 images where the scaling factor is arbitrary. In most cases, your selection will not influence data processing in any way (as fMRI/T1/T2 values are relative). +GE. Some GE scanners will interpolate images to simulate higher-resolution. If you set "UseGE_0021_104F=0" then you will get one image for the actual slices and one for the interpolated slices. If you set "UseGE_0021_104F=1" you will get a single large volume that combines the interpolated and actual slices. +Philips 4D DICOM image conversion is improved, but this format is changing very rapidly. My software assume all images in a 4D image have the same scaling factors. This is fine form images where signal is relative. However, when you have a image where the 4th dimesion is between modalities (e.g. some images have modulus and some have phase) then the scaling factor may not be preserved. The raw data is correct, but some images with absolute values (phase or diffusion) images may need rescaling. +When run from the command line, specifying folders is now case sensitive. This fix is specific for Linux users. NPM +VLSM commands - Previous version did not always conduct statistical tests on all the voxels (some ventral voxels might show Z=0). MRIcroGL +Render/Clip is now viewpoint independent. Previous version always cut slices from viewer's location, new version includes sliders to specify the elevation and azimuth of the clip plane. The scripting includes the new command "CLIPAZIMUTHELEVATION" as well as the old view-point dependent "clip" command. +Program should not crash if your video card can not support the input image (you will get a polite message describing the problem). +Help/Preferences adds a new rendering pull-down menu that allows you to choose between three rendering modes: standard (best quality, but slow), fast but blurry, and disabled. In the disabled mode you see orthogonal slices instead of a rendering, which is useful for slow video cards. +Better display of statistical images as background image (SPM uses 'Not A Number' values for areas where no statistics are calculated). +More significant digits for statistcal outputs. -------------------------------- ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/cropedges.pas������������������������������������������������������0000755�0001750�0001750�00000013677�12151704170�016677� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit CropEdges; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ExtCtrls, Spin, Buttons,nifti_img,define_types; type { TCropEdgeForm } TCropEdgeForm = class(TForm) ApplyBtn: TSpeedButton; CropFileSzBtn: TSpeedButton; CancelBtn: TSpeedButton; Timer1: TTimer; DEdit: TSpinEdit; PEdit: TSpinEdit; AEdit: TSpinEdit; VEdit: TSpinEdit; REdit: TSpinEdit; LEdit: TSpinEdit; procedure ApplyCrop; procedure ApplyCrop2Img; procedure ApplyBtnClick(Sender: TObject); procedure CancelBtnClick(Sender: TObject); procedure CropEditChange(Sender: TObject); procedure CropFileSzBtnClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormHide(Sender: TObject); procedure FormShow(Sender: TObject); procedure Timer1Timer(Sender: TObject); private { private declarations } public { public declarations } end; var CropEdgeForm: TCropEdgeForm; implementation uses nifti_img_view, crop; { TCropEdgeForm } procedure TCropEdgeForm.ApplyBtnClick(Sender: TObject); begin CropEdgeForm.ModalResult := mrOK; CropEdgeForm.close; end; procedure TCropEdgeForm.CancelBtnClick(Sender: TObject); begin CropEdgeForm.close; end; procedure TCropEdgeForm.CropEditChange(Sender: TObject); begin if not CropEdgeForm.visible then exit; Timer1.Enabled := true; end; procedure TCropEdgeForm.CropFileSzBtnClick(Sender: TObject); var lV,lD,lA,lP,lL,lR: integer; begin lV := VEdit.value; lD := DEdit.value; lL := LEdit.value; lR := REdit.value; lA := AEdit.value; lP := PEdit.value; CropNIfTI(lL,lR,lA,lP,lD,lV); end; procedure TCropEdgeForm.FormCreate(Sender: TObject); begin end; procedure TCropEdgeForm.FormHide(Sender: TObject); begin UndoVolVOI; if not (CropEdgeForm.ModalResult = mrCancel) then ApplyCrop2Img else ImgForm.RefreshImagesTimer.Enabled := true; end; procedure TCropEdgeForm.FormShow(Sender: TObject); begin EnsureVOIOpen; CreateUndoVol; CropEdgeForm.ModalResult := mrCancel; CropEditChange(nil); end; procedure TCropEdgeForm.ApplyCrop2Img; var lZLo,lZHi,lXLo,lXHi,lYLo,lYHi,lPos,lX,lY,lZ: integer; l32Buf : SingleP; l16Buf : SmallIntP; begin if (gMRIcroOverlay[kBGOverlayNum].ImgBufferItems<1) then exit; if (gBGImg.ScrnDim[1]*gBGImg.ScrnDim[2]*gBGImg.ScrnDim[3]) <> gMRIcroOverlay[kBGOverlayNum].ImgBufferItems then begin Showmessage('Can not crop edges of a rotated image.'); exit; end; lXlo := round(LEdit.value); lXHi := gBGImg.ScrnDim[1] - round(REdit.value); lYlo := round(PEdit.value); lYHi := gBGImg.ScrnDim[2] - round(AEdit.value); lZLo := round(VEdit.value); lZHi := gBGImg.ScrnDim[3] - round(DEdit.value); lPos := 0; case gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP of 1: begin for lZ := 1 to gBGImg.ScrnDim[3] do for lY := 1 to gBGImg.ScrnDim[2] do for lX := 1 to gBGImg.ScrnDim[1] do begin inc(lPos); if (lZ >= lZHi) or (lZ <= lZLo) or(lY >= lYHi) or (lY <= lYLo) or (lX >= lXHi) or (lX <= lXLo) then gMRIcroOverlay[kBGOverlayNum].ImgBuffer^[lPos] := 0; end; //for X end; 2: begin l16Buf := SmallIntP(gMRIcroOverlay[kBGOverlayNum].ImgBuffer ); for lZ := 1 to gBGImg.ScrnDim[3] do for lY := 1 to gBGImg.ScrnDim[2] do for lX := 1 to gBGImg.ScrnDim[1] do begin inc(lPos); if (lZ >= lZHi) or (lZ <= lZLo) or(lY >= lYHi) or (lY <= lYLo) or (lX >= lXHi) or (lX <= lXLo) then l16Buf^[lPos] := 0; end; //for X end; 4: begin l32Buf := SingleP(gMRIcroOverlay[kBGOverlayNum].ImgBuffer ); for lZ := 1 to gBGImg.ScrnDim[3] do for lY := 1 to gBGImg.ScrnDim[2] do for lX := 1 to gBGImg.ScrnDim[1] do begin inc(lPos); if (lZ >= lZHi) or (lZ <= lZLo) or(lY >= lYHi) or (lY <= lYLo) or (lX >= lXHi) or (lX <= lXLo) then l32Buf^[lPos] := 0; end; //for X end; else begin showmessage('Unsupported data type'); end end; //case ImgForm.RescaleImagesTimer.Enabled := true; end; procedure TCropEdgeForm.ApplyCrop; var lZLo,lZHi,lXLo,lXHi,lYLo,lYHi,lPos,lX,lY,lZ: integer; begin if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems<1) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems<>gBGImg.VOIUndoVolItems) then exit; if gBGImg.VOIUndoVolItems <> gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems then exit; if (gBGImg.ScrnDim[1]*gBGImg.ScrnDim[2]*gBGImg.ScrnDim[3]) <> gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems then exit; //CreateUndoVol; //Move(gBGImg.VOIUndoVol^,gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,gBGImg.VOIUndoVolItems); FillChar(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,gBGImg.VOIUndoVolItems,0); lXlo := round(LEdit.value); lXHi := gBGImg.ScrnDim[1] - round(REdit.value); lYlo := round(PEdit.value); lYHi := gBGImg.ScrnDim[2] - round(AEdit.value); lZLo := round(VEdit.value); lZHi := gBGImg.ScrnDim[3] - round(DEdit.value); lPos := 0; for lZ := 1 to gBGImg.ScrnDim[3] do begin for lY := 1 to gBGImg.ScrnDim[2] do begin for lX := 1 to gBGImg.ScrnDim[1] do begin inc(lPos); if (lZ >= lZHi) or (lZ <= lZLo) or(lY >= lYHi) or (lY <= lYLo) or (lX >= lXHi) or (lX <= lXLo) then gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lPos] := kVOI8bit; end; //for X end; //for Y end; //for Z //gBGImg.VOIchanged := true; ImgForm.RefreshImagesTimer.enabled := true; end; procedure TCropEdgeForm.Timer1Timer(Sender: TObject); begin Timer1.Enabled := false; ApplyCrop; end; initialization {$I cropedges.lrs} end. �����������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/������������������������������������������������������������0000755�0001750�0001750�00000000000�12413465015�015471� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/gui.inc�����������������������������������������������������0000755�0001750�0001750�00000000154�11542422214�016747� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{$DEFINE GUI} //use GUI if you are using a graphic user interface - anything else for console applications ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/nifti_foreign.pas�������������������������������������������0000755�0001750�0001750�00000141200�12323212032�021006� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit nifti_foreign; interface {$H+} {$Include isgui.inc} uses {$IFNDEF FPC} gziod, {$ELSE} gzio2, {$ENDIF} {$IFDEF GUI} dialogs, {$ELSE} dialogsx, {$ENDIF} nifti_types, define_types, sysutils, classes, StrUtils;//2015! dialogsx function readForeignHeader (var lFilename: string; var lHdr: TNIFTIhdr; var gzBytes: int64; var swapEndian: boolean): boolean; procedure NII_Clear (var lHdr: TNIFTIHdr); procedure NII_SetIdentityMatrix (var lHdr: TNIFTIHdr); //create neutral rotation matrix implementation Type mat44 = array [0..3, 0..3] of Single; vect4 = array [0..3] of Single; mat33 = array [0..2, 0..2] of Single; vect3 = array [0..2] of Single; ivect3 = array [0..2] of integer; {$IFDEF GUI} procedure ShowMsg(s: string); begin Showmessage(s); end; {$ENDIF} procedure fromMatrix (m: mat44; var r11,r12,r13,r21,r22,r23,r31,r32,r33: double); begin r11 := m[0,0]; r12 := m[0,1]; r13 := m[0,2]; r21 := m[1,0]; r22 := m[1,1]; r23 := m[1,2]; r31 := m[2,0]; r32 := m[2,1]; r33 := m[2,2]; end; function Matrix2D (r11,r12,r13,r21,r22,r23,r31,r32,r33: double): mat33; begin result[0,0] := r11; result[0,1] := r12; result[0,2] := r13; result[1,0] := r21; result[1,1] := r22; result[1,2] := r23; result[2,0] := r31; result[2,1] := r32; result[2,2] := r33; end; function nifti_mat33_determ( R: mat33 ):double; //* determinant of 3x3 matrix */ begin result := r[0,0]*r[1,1]*r[2,2] -r[0,0]*r[2,1]*r[1,2] -r[1,0]*r[0,1]*r[2,2] +r[1,0]*r[2,1]*r[0,2] +r[2,0]*r[0,1]*r[1,2] -r[2,0]*r[1,1]*r[0,2] ; end; function nifti_mat33_rownorm( A: mat33 ): single; // max row norm of 3x3 matrix var r1,r2,r3: single ; begin r1 := abs(A[0,0])+abs(A[0,1])+abs(A[0,2]); r2 := abs(A[1,0])+abs(A[1,1])+abs(A[1,2]); r3 := abs(A[2,0])+abs(A[2,1])+abs(A[2,2]); if( r1 < r2 ) then r1 := r2 ; if( r1 < r3 ) then r1 := r3 ; result := r1 ; end; procedure fromMatrix33 (m: mat33; var r11,r12,r13,r21,r22,r23,r31,r32,r33: double); begin r11 := m[0,0]; r12 := m[0,1]; r13 := m[0,2]; r21 := m[1,0]; r22 := m[1,1]; r23 := m[1,2]; r31 := m[2,0]; r32 := m[2,1]; r33 := m[2,2]; end; function nifti_mat33_inverse( R: mat33 ): mat33; //* inverse of 3x3 matrix */ var r11,r12,r13,r21,r22,r23,r31,r32,r33 , deti: double ; begin FromMatrix33(R,r11,r12,r13,r21,r22,r23,r31,r32,r33); deti := r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; if( deti <> 0.0 ) then deti := 1.0 / deti ; result[0,0] := deti*( r22*r33-r32*r23) ; result[0,1] := deti*(-r12*r33+r32*r13) ; result[0,2] := deti*( r12*r23-r22*r13) ; result[1,0] := deti*(-r21*r33+r31*r23) ; result[1,1] := deti*( r11*r33-r31*r13) ; result[1,2] := deti*(-r11*r23+r21*r13) ; result[2,0] := deti*( r21*r32-r31*r22) ; result[2,1] := deti*(-r11*r32+r31*r12) ; result[2,2] := deti*( r11*r22-r21*r12) ; end; function nifti_mat33_colnorm( A: mat33 ): single; //* max column norm of 3x3 matrix */ var r1,r2,r3: single ; begin r1 := abs(A[0,0])+abs(A[1,0])+abs(A[2,0]) ; r2 := abs(A[0,1])+abs(A[1,1])+abs(A[2,1]) ; r3 := abs(A[0,2])+abs(A[1,2])+abs(A[2,2]) ; if( r1 < r2 ) then r1 := r2 ; if( r1 < r3 ) then r1 := r3 ; result := r1 ; end; function nifti_mat33_polar( A: mat33 ): mat33; var k:integer; X , Y , Z: mat33 ; dif,alp,bet,gam,gmi : single; begin dif := 1; k := 0; X := A ; gam := nifti_mat33_determ(X) ; while( gam = 0.0 )do begin //perturb matrix gam := 0.00001 * ( 0.001 + nifti_mat33_rownorm(X) ) ; X[0,0] := X[0,0]+gam ; X[1,1] := X[1,1]+gam ; X[2,2] := X[2,2] +gam ; gam := nifti_mat33_determ(X) ; end; while true do begin Y := nifti_mat33_inverse(X) ; if( dif > 0.3 )then begin // far from convergence alp := sqrt( nifti_mat33_rownorm(X) * nifti_mat33_colnorm(X) ) ; bet := sqrt( nifti_mat33_rownorm(Y) * nifti_mat33_colnorm(Y) ) ; gam := sqrt( bet / alp ) ; gmi := 1.0 / gam ; end else begin gam := 1.0; gmi := 1.0 ; //close to convergence end; Z[0,0] := 0.5 * ( gam*X[0,0] + gmi*Y[0,0] ) ; Z[0,1] := 0.5 * ( gam*X[0,1] + gmi*Y[1,0] ) ; Z[0,2] := 0.5 * ( gam*X[0,2] + gmi*Y[2,0] ) ; Z[1,0] := 0.5 * ( gam*X[1,0] + gmi*Y[0,1] ) ; Z[1,1] := 0.5 * ( gam*X[1,1] + gmi*Y[1,1] ) ; Z[1,2] := 0.5 * ( gam*X[1,2] + gmi*Y[2,1] ) ; Z[2,0] := 0.5 * ( gam*X[2,0] + gmi*Y[0,2] ) ; Z[2,1] := 0.5 * ( gam*X[2,1] + gmi*Y[1,2] ) ; Z[2,2] := 0.5 * ( gam*X[2,2] + gmi*Y[2,2] ) ; dif := abs(Z[0,0]-X[0,0])+abs(Z[0,1]-X[0,1])+abs(Z[0,2]-X[0,2]) +abs(Z[1,0]-X[1,0])+abs(Z[1,1]-X[1,1])+abs(Z[1,2]-X[1,2]) +abs(Z[2,0]-X[2,0])+abs(Z[2,1]-X[2,1])+abs(Z[2,2]-X[2,2]); k := k+1 ; if( k > 100) or (dif < 3.e-6 ) then begin result := Z; break ; //convergence or exhaustion end; X := Z ; end; result := Z ; end; procedure nifti_mat44_to_quatern( lR :mat44; var qb, qc, qd, qx, qy, qz, dx, dy, dz, qfac : single); var r11,r12,r13 , r21,r22,r23 , r31,r32,r33, xd,yd,zd , a,b,c,d : double; P,Q: mat33; //3x3 begin // offset outputs are read write out of input matrix qx := lR[0,3]; qy := lR[1,3]; qz := lR[2,3]; //load 3x3 matrix into local variables fromMatrix(lR,r11,r12,r13,r21,r22,r23,r31,r32,r33); //compute lengths of each column; these determine grid spacings xd := sqrt( r11*r11 + r21*r21 + r31*r31 ) ; yd := sqrt( r12*r12 + r22*r22 + r32*r32 ) ; zd := sqrt( r13*r13 + r23*r23 + r33*r33 ) ; //if a column length is zero, patch the trouble if( xd = 0.0 )then begin r11 := 1.0 ; r21 := 0; r31 := 0.0 ; xd := 1.0 ; end; if( yd = 0.0 )then begin r22 := 1.0 ; r12 := 0; r32 := 0.0 ; yd := 1.0 ; end; if( zd = 0.0 )then begin r33 := 1.0 ; r13 := 0; r23 := 0.0 ; zd := 1.0 ; end; //assign the output lengths dx := xd; dy := yd; dz := zd; //normalize the columns r11 := r11/xd ; r21 := r21/xd ; r31 := r31/xd ; r12 := r12/yd ; r22 := r22/yd ; r32 := r32/yd ; r13 := r13/zd ; r23 := r23/zd ; r33 := r33/zd ; { At this point, the matrix has normal columns, but we have to allow for the fact that the hideous user may not have given us a matrix with orthogonal columns. So, now find the orthogonal matrix closest to the current matrix. One reason for using the polar decomposition to get this orthogonal matrix, rather than just directly orthogonalizing the columns, is so that inputting the inverse matrix to R will result in the inverse orthogonal matrix at this point. If we just orthogonalized the columns, this wouldn't necessarily hold.} Q := Matrix2D (r11,r12,r13, // 2D "graphics" matrix r21,r22,r23, r31,r32,r33); P := nifti_mat33_polar(Q) ; //P is orthog matrix closest to Q FromMatrix33(P,r11,r12,r13,r21,r22,r23,r31,r32,r33); { [ r11 r12 r13 ] at this point, the matrix [ r21 r22 r23 ] is orthogonal [ r31 r32 r33 ] compute the determinant to determine if it is proper} zd := r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; //should be -1 or 1 if( zd > 0 )then begin // proper qfac := 1.0 ; end else begin //improper ==> flip 3rd column qfac := -1.0 ; r13 := -r13 ; r23 := -r23 ; r33 := -r33 ; end; // now, compute quaternion parameters a := r11 + r22 + r33 + 1.0; if( a > 0.5 ) then begin //simplest case a := 0.5 * sqrt(a) ; b := 0.25 * (r32-r23) / a ; c := 0.25 * (r13-r31) / a ; d := 0.25 * (r21-r12) / a ; end else begin //trickier case xd := 1.0 + r11 - (r22+r33) ;// 4*b*b yd := 1.0 + r22 - (r11+r33) ;// 4*c*c zd := 1.0 + r33 - (r11+r22) ;// 4*d*d if( xd > 1.0 ) then begin b := 0.5 * sqrt(xd) ; c := 0.25* (r12+r21) / b ; d := 0.25* (r13+r31) / b ; a := 0.25* (r32-r23) / b ; end else if( yd > 1.0 ) then begin c := 0.5 * sqrt(yd) ; b := 0.25* (r12+r21) / c ; d := 0.25* (r23+r32) / c ; a := 0.25* (r13-r31) / c ; end else begin d := 0.5 * sqrt(zd) ; b := 0.25* (r13+r31) / d ; c := 0.25* (r23+r32) / d ; a := 0.25* (r21-r12) / d ; end; if( a < 0.0 )then begin b:=-b ; c:=-c ; d:=-d; {a:=-a; this is not used} end; end; qb := b ; qc := c ; qd := d ; end; procedure NII_SetIdentityMatrix (var lHdr: TNIFTIHdr); //create neutral rotation matrix var lInc: integer; begin with lHdr do begin for lInc := 0 to 3 do srow_x[lInc] := 0; for lInc := 0 to 3 do srow_y[lInc] := 0; for lInc := 0 to 3 do srow_z[lInc] := 0; for lInc := 1 to 16 do intent_name[lInc] := chr(0); //next: create identity matrix: if code is switched on there will not be a problem srow_x[0] := 1; srow_y[1] := 1; srow_z[2] := 1; end; end; //proc NIFTIhdr_IdentityMatrix procedure NII_Clear (var lHdr: TNIFTIHdr); var lInc: integer; begin with lHdr do begin HdrSz := sizeof(TNIFTIhdr); for lInc := 1 to 10 do Data_Type[lInc] := chr(0); for lInc := 1 to 18 do db_name[lInc] := chr(0); extents:=0; session_error:= 0; regular:='r'{chr(0)}; dim_info:=(0); dim[0] := 4; for lInc := 1 to 7 do dim[lInc] := 0; intent_p1 := 0; intent_p2 := 0; intent_p3 := 0; intent_code:=0; datatype:=0 ; bitpix:=0; slice_start:=0; for lInc := 1 to 7 do pixdim[linc]:= 1.0; vox_offset:= 0.0; scl_slope := 1.0; scl_inter:= 0.0; slice_end:= 0; slice_code := 0; xyzt_units := 10; cal_max:= 0.0; cal_min:= 0.0; slice_duration:=0; toffset:= 0; glmax:= 0; glmin:= 0; for lInc := 1 to 80 do descrip[lInc] := chr(0);{80 spaces} for lInc := 1 to 24 do aux_file[lInc] := chr(0);{80 spaces} {below are standard settings which are not 0} bitpix := 16;//vc16; {8bits per pixel, e.g. unsigned char 136} DataType := 4;//vc4;{2=unsigned char, 4=16bit int 136} Dim[0] := 3; Dim[1] := 256; Dim[2] := 256; Dim[3] := 128; Dim[4] := 1; {n vols} Dim[5] := 1; Dim[6] := 1; Dim[7] := 1; glMin := 0; glMax := 255; qform_code := kNIFTI_XFORM_UNKNOWN; sform_code:= kNIFTI_XFORM_UNKNOWN; quatern_b := 0; quatern_c := 0; quatern_d := 0; qoffset_x := 0; qoffset_y := 0; qoffset_z := 0; NII_SetIdentityMatrix(lHdr); magic := kNIFTI_MAGIC_SEPARATE_HDR; end; //with the NIfTI header... end; procedure ZERO_MAT44(var m: mat44); //note sets m[3,3] to one var i,j: integer; begin for i := 0 to 3 do for j := 0 to 3 do m[i,j] := 0.0; m[3,3] := 1; end; procedure LOAD_MAT33(var m: mat33; m00,m01,m02, m10,m11,m12, m20,m21,m22: single); begin m[0,0] := m00; m[0,1] := m01; m[0,2] := m02; m[1,0] := m10; m[1,1] := m11; m[1,2] := m12; m[2,0] := m20; m[2,1] := m21; m[2,2] := m22; end; function nifti_mat33_mul( A,B: mat33): mat33; var i,j: integer; begin for i:=0 to 3 do for j:=0 to 3 do result[i,j] := A[i,0] * B[0,j] + A[i,1] * B[1,j] + A[i,2] * B[2,j] ; end; procedure LOAD_MAT44(var m: mat44; m00,m01,m02,m03, m10,m11,m12,m13, m20,m21,m22,m23: single); begin m[0,0] := m00; m[0,1] := m01; m[0,2] := m02; m[0,3] := m03; m[1,0] := m10; m[1,1] := m11; m[1,2] := m12; m[1,3] := m13; m[2,0] := m20; m[2,1] := m21; m[2,2] := m22; m[2,3] := m23; m[3,0] := 0.0; m[3,1] := 0.0; m[3,2] := 0.0; m[3,3] := 1.0; end; function validMatrix(var m: mat44): boolean; var i: integer; begin result := false; for i := 0 to 2 do begin if (m[0,i] = 0.0) and (m[1,i] = 0.0) and (m[2,i] = 0.0) then exit; if (m[i,0] = 0.0) and (m[i,1] = 0.0) and (m[i,2] = 0.0) then exit; end; result := true; end; procedure convertForeignToNifti(var nhdr: TNIFTIhdr); var i,nonSpatialMult: integer; qto_xyz: mat44; //dumqx, dumqy, dumqz, dumdx, dumdy, dumdz: single; begin nhdr.HdrSz := 348; //used to signify header does not need to be byte-swapped nhdr.magic:=kNIFTI_MAGIC_EMBEDDED_HDR; if (nhdr.dim[3] = 0) then nhdr.dim[3] := 1; //for 2D images the 3rd dim is not specified and set to zero nhdr.dim[0] := 3; //for 2D images the 3rd dim is not specified and set to zero nonSpatialMult := 1; for i := 4 to 7 do if nhdr.dim[i] > 0 then nonSpatialMult := nonSpatialMult * nhdr.dim[i]; if (nonSpatialMult > 1) then begin nhdr.dim[0] := 4; nhdr.dim[4] := nonSpatialMult; for i := 5 to 7 do nhdr.dim[i] := 0; end; nhdr.bitpix := 8; if (nhdr.datatype = 4) or (nhdr.datatype = 512) then nhdr.bitpix := 16; if (nhdr.datatype = 8) or (nhdr.datatype = 16) or (nhdr.datatype = 768) then nhdr.bitpix := 32; if (nhdr.datatype = 32) or (nhdr.datatype = 64) or (nhdr.datatype = 1024) or (nhdr.datatype = 1280) then nhdr.bitpix := 64; LOAD_MAT44(qto_xyz, nhdr.srow_x[0], nhdr.srow_x[1], nhdr.srow_x[2], nhdr.srow_x[3], nhdr.srow_y[0], nhdr.srow_y[1], nhdr.srow_y[2], nhdr.srow_y[3], nhdr.srow_z[0], nhdr.srow_z[1], nhdr.srow_z[2], nhdr.srow_z[3]); if not validMatrix(qto_xyz) then begin nhdr.sform_code := 0; nhdr.qform_code := 0; for i := 0 to 3 do begin nhdr.srow_x[i] := 0; nhdr.srow_y[i] := 0; nhdr.srow_z[i] := 0; end; nhdr.srow_x[0] := 1; nhdr.srow_y[1] := 1; nhdr.srow_z[2] := 1; exit; end; nhdr.sform_code := 1; nifti_mat44_to_quatern( qto_xyz , nhdr.quatern_b, nhdr.quatern_c, nhdr.quatern_d,nhdr.qoffset_x,nhdr.qoffset_y,nhdr.qoffset_z, dumdx, dumdy, dumdz,nhdr.pixdim[0]) ; nhdr.qform_code := kNIFTI_XFORM_SCANNER_ANAT; end; procedure NSLog( str: string); begin showmsg(str); end; function readMGHHeader (var fname: string; var nhdr: TNIFTIhdr; var gzBytes: int64; var swapEndian: boolean): boolean; Type Tmgh = packed record //Next: analyze Format Header structure version, width,height,depth,nframes,mtype,dof : longint; goodRASFlag: smallint; spacingX,spacingY,spacingZ,xr,xa,xs,yr,ya,ys,zr,za,zs,cr,ca,cs: single; end; var mgh: Tmgh; lBuff: Bytep; lExt: string; lHdrFile: file; PxyzOffset, Pcrs: vect4; i,j: integer; base: single; m: mat44; begin result := false; lExt := UpCaseExt(fname); if (lExt = '.MGZ') then begin lBuff := @mgh; UnGZip(fname,lBuff,0,sizeof(Tmgh)); //1388 gzBytes := K_gzBytes_headerAndImageCompressed; end else begin //if MGZ, else assume uncompressed MGH gzBytes := 0; {$I-} AssignFile(lHdrFile, fname); FileMode := 0; //Set file access to read only Reset(lHdrFile, 1); {$I+} if ioresult <> 0 then begin NSLog('Error in reading NIFTI header.'+inttostr(IOResult)); FileMode := 2; exit; end; BlockRead(lHdrFile, mgh, sizeof(Tmgh)); CloseFile(lHdrFile); end; {$IFDEF ENDIAN_BIG} //data always stored big endian swapEndian := false; {$ELSE} swapEndian := true; swap4(mgh.version); swap4(mgh.width); swap4(mgh.height); swap4(mgh.depth); swap4(mgh.nframes); swap4(mgh.mtype); swap4(mgh.dof); mgh.goodRASFlag := swap(mgh.goodRASFlag); Xswap4r(mgh.spacingX); Xswap4r(mgh.spacingY); Xswap4r(mgh.spacingZ); Xswap4r(mgh.xr); Xswap4r(mgh.xa); Xswap4r(mgh.xs); Xswap4r(mgh.yr); Xswap4r(mgh.ya); Xswap4r(mgh.ys); Xswap4r(mgh.zr); Xswap4r(mgh.za); Xswap4r(mgh.zs); Xswap4r(mgh.cr); Xswap4r(mgh.ca); Xswap4r(mgh.cs); {$ENDIF} if ((mgh.version <> 1) or (mgh.mtype < 0) or (mgh.mtype > 4)) then begin NSLog('Error: first value in a MGH header should be 1 and data type should be in the range 1..4.'); exit; end; if (mgh.mtype = 0) then nhdr.datatype := kDT_UINT8 else if (mgh.mtype = 4) then nhdr.datatype := kDT_INT16 else if (mgh.mtype = 1) then nhdr.datatype := kDT_INT32 else if (mgh.mtype = 3) then nhdr.datatype := kDT_FLOAT32; nhdr.dim[1]:=mgh.width; nhdr.dim[2]:=mgh.height; nhdr.dim[3]:=mgh.depth; nhdr.dim[4]:=mgh.nframes; nhdr.pixdim[1]:=mgh.spacingX; nhdr.pixdim[2]:=mgh.spacingY; nhdr.pixdim[3]:=mgh.spacingZ; nhdr.vox_offset := 284; nhdr.sform_code := 1; //convert MGH to NIfTI transform see Bruce Fischl mri.c MRIxfmCRS2XYZ https://github.com/neurodebian/freesurfer/blob/master/utils/mri.c LOAD_MAT44(m,mgh.xr*nhdr.pixdim[1],mgh.yr*nhdr.pixdim[2],mgh.zr*nhdr.pixdim[3],0, mgh.xa*nhdr.pixdim[1],mgh.ya*nhdr.pixdim[2],mgh.za*nhdr.pixdim[3],0, mgh.xs*nhdr.pixdim[1],mgh.ys*nhdr.pixdim[2],mgh.zs*nhdr.pixdim[3],0); base := 0.0; //0 or 1: are voxels indexed from 0 or 1? Pcrs[0] := (nhdr.dim[1]/2.0)+base; Pcrs[1] := (nhdr.dim[2]/2.0)+base; Pcrs[2] := (nhdr.dim[3]/2.0)+base; Pcrs[3] := 1; for i:=0 to 3 do begin //multiply Pcrs * m PxyzOffset[i] := 0; for j := 0 to 3 do PxyzOffset[i] := PxyzOffset[i]+ (m[i,j]*Pcrs[j]); end; nhdr.srow_x[0]:=m[0,0]; nhdr.srow_x[1]:=m[0,1]; nhdr.srow_x[2]:=m[0,2]; nhdr.srow_x[3]:=mgh.cr - PxyzOffset[0]; nhdr.srow_y[0]:=m[1,0]; nhdr.srow_y[1]:=m[1,1]; nhdr.srow_y[2]:=m[1,2]; nhdr.srow_y[3]:=mgh.ca - PxyzOffset[1]; nhdr.srow_z[0]:=m[2,0]; nhdr.srow_z[1]:=m[2,1]; nhdr.srow_z[2]:=m[2,2]; nhdr.srow_z[3]:=mgh.cs - PxyzOffset[2]; convertForeignToNifti(nhdr); result := true; end; procedure splitStr(delimiter: char; str: string; mArray: TStrings); begin mArray.Clear; mArray.Delimiter := delimiter; mArray.DelimitedText := str; end; procedure splitStrStrict(delimiter: char; S: string; sl: TStrings); begin sl.Clear; sl.Delimiter := delimiter; sl.DelimitedText := '"' + StringReplace(S, sl.Delimiter, '"' + sl.Delimiter + '"', [rfReplaceAll]) + '"'; end; function cleanStr (S:string): string; // "(12.31)" ->"12.31" begin result := StringReplace(S, '(', '', [rfReplaceAll]); result := StringReplace(result, ')', '', [rfReplaceAll]); end; (*function FSize (lFName: String): Int64; var SearchRec: TSearchRec; begin result := 0; if not fileexistsex(lFName) then exit; FindFirst(lFName, faAnyFile, SearchRec); result := SearchRec.size; FindClose(SearchRec); end; *) (*procedure report_mat(m: mat33); begin showmsg('mat = ['+floattostr(m[0,0])+' ' +floattostr(m[0,1]) +' ' +floattostr(m[0,2]) +'; ' +floattostr(m[1,0])+' ' +floattostr(m[1,1]) +' ' +floattostr(m[1,2]) +'; ' +floattostr(m[2,0])+' ' +floattostr(m[2,1]) +' ' +floattostr(m[2,2]) +'] '); end;*) function readMHAHeader (var fname: string; var nhdr: TNIFTIhdr; var gzBytes: int64; var swapEndian: boolean): boolean; //Read VTK "MetaIO" format image //http://www.itk.org/Wiki/ITK/MetaIO/Documentation#Reading_a_Brick-of-Bytes_.28an_N-Dimensional_volume_in_a_single_file.29 //https://www.assembla.com/spaces/plus/wiki/Sequence_metafile_format //http://itk-insight-users.2283740.n2.nabble.com/MHA-MHD-File-Format-td7585031.html var FP: TextFile; str, tagName, elementNames: string; ch: char; isLocal,compressedData: boolean; matOrient, mat, d, t: mat33; nPosition, nOffset, matElements, matElementsOrient, compressedDataSize, headerSize, nItems, nBytes, i, channels, fileposBytes: longint; offset,position, elementSize: array [0..3] of single; transformMatrix: array [0..11] of single; mArray: TStringList; begin result := false; if not FileExistsEX(fname) then exit; {$IFDEF FPC} DefaultFormatSettings.DecimalSeparator := '.' ; // DecimalSeparator := '.'; {$ELSE} DecimalSeparator := '.'; {$ENDIF} for i := 0 to 3 do begin position[i] := 0; offset[i] := 0; elementSize[i] := 1; end; nPosition := 0; nOffset := 0; gzBytes := 0; fileposBytes := 0; compressedDataSize := 0; swapEndian := false; isLocal := true; //image and header embedded in same file, if false detached image headerSize := 0; matElements := 0; matElementsOrient := 0; compressedData := false; mArray := TStringList.Create; Filemode := fmOpenRead; AssignFile(fp,fname); reset(fp); while not EOF(fp) do begin str := ''; while not EOF(fp) do begin read(fp,ch); inc(fileposBytes); if (ch = chr($0D)) or (ch = chr($0A)) then break; str := str+ch; end; if (length(str) < 1) or (str[1]='#') then continue; splitstrStrict('=',str,mArray); if (mArray.count < 2) then continue; tagName := cleanStr(mArray[0]); elementNames := mArray[1]; splitstr(',',elementNames,mArray); nItems :=mArray.count; if (nItems < 1) then continue; for i := 0 to (nItems-1) do mArray[i] := cleanStr(mArray[i]); //remove '(' and ')', if AnsiContainsText(tagName, 'ObjectType') and (not AnsiContainsText(mArray.Strings[0], 'Image')) then begin NSLog('Expecting file with tag "ObjectType = Image" instead of "ObjectType = '+mArray.Strings[0]+'"'); end {else if AnsiContainsText(tagName, 'NDims') then begin nDims := strtoint(mArray[0]); if (nDims > 4) then begin NSLog('Warning: only reading first 4 dimensions'); nDims := 4; end; end} else if AnsiContainsText(tagName, 'BinaryDataByteOrderMSB') then begin {$IFDEF ENDIAN_BIG} //data always stored big endian if not AnsiContainsText(mArray[0], 'True') then swapEndian := true; {$ELSE} if AnsiContainsText(mArray[0], 'True') then swapEndian := true; {$ENDIF} end {else if AnsiContainsText(tagName, 'BinaryData') then begin if AnsiContainsText(mArray[0], 'True') then binaryData := true; end else if AnsiContainsText(tagName, 'CompressedDataSize') then begin compressedDataSize := strtoint(mArray[0]); end} else if AnsiContainsText(tagName, 'CompressedData') then begin if AnsiContainsText(mArray[0], 'True') then compressedData := true; end else if AnsiContainsText(tagName, 'Orientation') and (not AnsiContainsText(tagName, 'Anatomical') ) then begin if (nItems > 12) then nItems := 12; matElementsOrient := nItems; for i := 0 to (nItems-1) do transformMatrix[i] := strtofloat(mArray[i]); if (matElementsOrient >= 12) then LOAD_MAT33(matOrient, transformMatrix[0],transformMatrix[1],transformMatrix[2], transformMatrix[4],transformMatrix[5],transformMatrix[6], transformMatrix[8],transformMatrix[9],transformMatrix[10]) else if (matElementsOrient >= 9) then LOAD_MAT33(matOrient, transformMatrix[0],transformMatrix[1],transformMatrix[2], transformMatrix[3],transformMatrix[4],transformMatrix[5], transformMatrix[6],transformMatrix[7],transformMatrix[8]); end else if AnsiContainsText(tagName, 'TransformMatrix') then begin if (nItems > 12) then nItems := 12; matElements := nItems; for i := 0 to (nItems-1) do transformMatrix[i] := strtofloat(mArray[i]); if (matElements >= 12) then LOAD_MAT33(mat, transformMatrix[0],transformMatrix[1],transformMatrix[2], transformMatrix[4],transformMatrix[5],transformMatrix[6], transformMatrix[8],transformMatrix[9],transformMatrix[10]) else if (matElements >= 9) then LOAD_MAT33(mat, transformMatrix[0],transformMatrix[1],transformMatrix[2], transformMatrix[3],transformMatrix[4],transformMatrix[5], transformMatrix[6],transformMatrix[7],transformMatrix[8]); end else if AnsiContainsText(tagName, 'Position') then begin if (nItems > 3) then nItems := 3; nPosition := nItems; for i := 0 to (nItems-1) do position[i] := strtofloat(mArray[i]); end else if AnsiContainsText(tagName, 'Offset') then begin if (nItems > 3) then nItems := 3; nOffset := nItems; for i := 0 to (nItems-1) do offset[i] := strtofloat(mArray[i]); end else if AnsiContainsText(tagName, 'AnatomicalOrientation') then begin //e.g. RAI end else if AnsiContainsText(tagName, 'ElementSpacing') then begin if (nItems > 4) then nItems := 4; for i := 0 to (nItems-1) do nhdr.pixdim[i+1] := strtofloat(mArray[i]); end else if AnsiContainsText(tagName, 'DimSize') then begin if (nItems > 4) then nItems := 4; for i := 0 to (nItems-1) do nhdr.dim[i+1] := strtoint(mArray[i]); end else if AnsiContainsText(tagName, 'HeaderSize') then begin headerSize := strtoint(mArray[0]); end else if AnsiContainsText(tagName, 'ElementSize') then begin if (nItems > 4) then nItems := 4; for i := 0 to (nItems-1) do elementSize[i] := strtofloat(mArray[i]); end else if AnsiContainsText(tagName, 'ElementNumberOfChannels') then begin channels := strtoint(mArray[0]); if (channels > 1) then NSLog('Unable to read MHA/MHD files with multiple channels '); end else if AnsiContainsText(tagName, 'ElementByteOrderMSB') then begin {$IFDEF ENDIAN_BIG} //data always stored big endian if not AnsiContainsText(mArray[0], 'True') then swapEndian := true; {$ELSE} if AnsiContainsText(mArray[0], 'True') then swapEndian := true; {$ENDIF} end else if AnsiContainsText(tagName, 'ElementType') then begin //convert metaImage format to NIfTI http://portal.nersc.gov/svn/visit/tags/2.2.1/vendor_branches/vtk/src/IO/vtkMetaImageWriter.cxx //set NIfTI datatype http://nifti.nimh.nih.gov/pub/dist/src/niftilib/nifti1.h if AnsiContainsText(mArray[0], 'MET_UCHAR') then nhdr.datatype := kDT_UINT8 // else if AnsiContainsText(mArray[0], 'MET_CHAR') then nhdr.dataType := kDT_INT8 // else if AnsiContainsText(mArray[0], 'MET_SHORT') then nhdr.dataType := kDT_INT16 // else if AnsiContainsText(mArray[0], 'MET_USHORT') then nhdr.dataType := kDT_UINT16 // else if AnsiContainsText(mArray[0], 'MET_INT') then nhdr.dataType := kDT_INT32 //DT_INT32 else if AnsiContainsText(mArray[0], 'MET_UINT') then nhdr.dataType := kDT_UINT32 //DT_UINT32 else if AnsiContainsText(mArray[0], 'MET_ULONG') then nhdr.dataType := kDT_UINT64 //DT_UINT64 else if AnsiContainsText(mArray[0], 'MET_LONG') then nhdr.dataType := kDT_INT64 //DT_INT64 else if AnsiContainsText(mArray[0], 'MET_FLOAT') then nhdr.dataType := kDT_FLOAT32 //DT_FLOAT32 else if AnsiContainsText(mArray[0], 'MET_DOUBLE') then nhdr.dataType := kDT_DOUBLE; //DT_FLOAT64 end else if AnsiContainsText(tagName, 'ElementDataFile') then begin if not AnsiContainsText(mArray[0], 'local') then begin str := mArray.Strings[0]; if fileexistsex(str) then fname := str else begin fname := ExtractFileDirWithPathDelim(fname)+str; end; isLocal := false; end; break; end; end; //while reading if (headerSize = 0) and (isLocal) then headerSize :=fileposBytes; //!CRAP 2015 nhdr.vox_offset := headerSize; CloseFile(FP); Filemode := 2; mArray.free; //convert transform if (matElements >= 9) or (matElementsOrient >= 9) then begin //report_Mat(matOrient); LOAD_MAT33(d, nhdr.pixdim[1],0,0, 0, nhdr.pixdim[2],0, 0,0, nhdr.pixdim[3]); if (matElements >= 9) then t := nifti_mat33_mul( d, mat) else t := nifti_mat33_mul( d, matOrient) ; if nPosition > nOffset then begin offset[0] := position[0]; offset[1] := position[1]; offset[2] := position[2]; end; nhdr.srow_x[0] := -t[0,0]; nhdr.srow_x[1] := -t[1,0]; nhdr.srow_x[2] := -t[2,0]; nhdr.srow_x[3] := -offset[0]; nhdr.srow_y[0] := -t[0,1]; nhdr.srow_y[1] := -t[1,1]; nhdr.srow_y[2] := -t[2,1]; nhdr.srow_y[3] := -offset[1]; nhdr.srow_z[0] := t[0,2]; nhdr.srow_z[1] := t[1,2]; nhdr.srow_z[2] := t[2,2]; nhdr.srow_z[3] := offset[2]; end else begin //NSLog('Warning: unable to determine image orientation (unable to decode metaIO "TransformMatrix" tag)')}; nhdr.sform_code:=0; nhdr.srow_x[0] := 0; nhdr.srow_x[1] := 0; nhdr.srow_x[2] := 0; end; //end transform convertForeignToNifti(nhdr); if (compressedData) then gzBytes := K_gzBytes_onlyImageCompressed; if (nhdr.vox_offset < 0) then begin nBytes := (nhdr.bitpix div 8); for i := 1 to 7 do begin if nhdr.dim[i] > 0 then nBytes := nBytes * nhdr.dim[i]; end; nhdr.vox_offset := FSize(fname) - nBytes; if (nhdr.vox_offset < 0) then nhdr.vox_offset := -1; end; result := true; end;//MHA Function StrToFloatSafe(Const S : String) : single; begin try result := strtofloat(S); except on EConvertError do result := 1/0 end;//except end; function readNRRDHeader (var fname: string; var nhdr: TNIFTIhdr; var gzBytes: int64; var swapEndian: boolean): boolean; //http://www.sci.utah.edu/~gk/DTI-data/ //http://teem.sourceforge.net/nrrd/format.html label 666; var FP: TextFile; ch: char; mArray: TStringList; str,tagName,elementNames: string; i,j,s,nItems,headerSize,matElements,fileposBytes: integer; mat: mat33; isDetachedFile,isFirstLine: boolean; offset: array[0..3] of single; vSqr: single; transformMatrix: array [0..11] of single; begin {$IFDEF FPC} DefaultFormatSettings.DecimalSeparator := '.' ; //DecimalSeparator := '.'; {$ELSE} DecimalSeparator := '.'; {$ENDIF} result := false; gzBytes :=0; fileposBytes := 0; swapEndian :=false; //nDims := 0; headerSize :=0; isDetachedFile :=false; matElements :=0; mArray := TStringList.Create; Filemode := 0; isFirstLine := true; AssignFile(fp,fname); reset(fp); while (not EOF(fp)) do begin str := ''; while not EOF(fp) do begin read(fp,ch); fileposBytes := fileposBytes + 1; if (ch = chr($0D)) or (ch = chr($0A)) then break; str := str+ch; end; if str = '' then break; if (isFirstLine) then begin if (length(str) <4) or (str[1]<>'N') or (str[2]<>'R') or (str[3]<>'R') or (str[4]<>'D') then goto 666; isFirstLine := false; end; //showmessage(str+'->'+inttostr(fileposBytes)); if (length(str) < 1) or (str[1]='#') then continue; splitstrStrict(':',str,mArray); if (mArray.count < 2) then continue; tagName := mArray[0]; elementNames := mArray[1]; splitstr(',',elementNames,mArray); nItems :=mArray.count; if (nItems < 1) then continue; for i := 0 to (nItems-1) do mArray.Strings[i] := cleanStr(mArray.Strings[i]); //remove '(' and ')' (*if AnsiContainsText(tagName, 'dimension') then nDims := strtoint(mArray.Strings[0]) else*) if AnsiContainsText(tagName, 'spacings') then begin if (nItems > 6) then nItems :=6; for i:=0 to (nItems-1) do nhdr.pixdim[i+1] :=strtofloat(mArray.Strings[i]); end else if AnsiContainsText(tagName, 'sizes') then begin if (nItems > 6) then nItems :=6; for i:=0 to (nItems-1) do nhdr.dim[i+1] := strtoint(mArray.Strings[i]); end else if AnsiContainsText(tagName, 'space directions') then begin j := 0; while (j < nItems) and (StrToFloatSafe( mArray.Strings[j]) = 1/0) do j := j + 1; if ((nItems-j) >= 12) then begin if ((nItems+j) > 12) then nItems :=(12+j); matElements :=nItems; for i:=0 to (nItems-1) do transformMatrix[i] :=strtofloat(mArray.Strings[i+j]); if (matElements >= 12) then LOAD_MAT33(mat, transformMatrix[0],transformMatrix[1],transformMatrix[2], transformMatrix[4],transformMatrix[5],transformMatrix[6], transformMatrix[8],transformMatrix[9],transformMatrix[10]) else if (matElements >= 9) then LOAD_MAT33(mat, transformMatrix[0],transformMatrix[1],transformMatrix[2], transformMatrix[3],transformMatrix[4],transformMatrix[5], transformMatrix[6],transformMatrix[7],transformMatrix[8]); end; //if false end else if AnsiContainsText(tagName, 'type') then begin if AnsiContainsText(mArray.Strings[0], 'uchar') or AnsiContainsText(mArray.Strings[0], 'uint8') or AnsiContainsText(mArray.Strings[0], 'uint8_t') then nhdr.datatype := KDT_UINT8 //DT_UINT8 DT_UNSIGNED_CHAR else if AnsiContainsText(mArray.Strings[0], 'short') or //specific so AnsiContainsText(mArray.Strings[0], 'int16') or AnsiContainsText(mArray.Strings[0], 'int16_t') then nhdr.datatype :=kDT_INT16 //DT_INT16 else if AnsiContainsText(mArray.Strings[0], 'float') then nhdr.datatype := kDT_FLOAT32 //DT_FLOAT32 else if AnsiContainsText(mArray.Strings[0], 'unsigned') and (nItems > 1) and AnsiContainsText(mArray.Strings[1], 'char') then nhdr.datatype := kDT_UINT8 //DT_UINT8 else if AnsiContainsText(mArray.Strings[0], 'unsigned') and (nItems > 1) and AnsiContainsText(mArray.Strings[1], 'short') then nhdr.datatype := kDT_UINT16 //DT_UINT16 else if AnsiContainsText(mArray.Strings[0], 'unsigned') and (nItems > 1) and AnsiContainsText(mArray.Strings[1], 'int') then nhdr.datatype := kDT_INT32 // else if AnsiContainsText(mArray.Strings[0], 'signed') and (nItems > 1) and AnsiContainsText(mArray.Strings[1], 'char') then nhdr.datatype := kDT_INT8 //do UNSIGNED first, as "isigned" includes string "unsigned" else if AnsiContainsText(mArray.Strings[0], 'signed') and (nItems > 1) and AnsiContainsText(mArray.Strings[1], 'short') then nhdr.datatype := kDT_INT16 //do UNSIGNED first, as "isigned" includes string "unsigned" else if AnsiContainsText(mArray.Strings[0], 'double') then nhdr.datatype := kDT_DOUBLE //DT_DOUBLE else if AnsiContainsText(mArray.Strings[0], 'int') then //do this last and "uint" includes "int" nhdr.datatype := kDT_UINT32 else begin NSLog('Unsupported NRRD datatype'+mArray.Strings[0]); end end else if AnsiContainsText(tagName, 'endian') then begin {$IFDEF ENDIAN_BIG} //data always stored big endian if AnsiContainsText(mArray.Strings[0], 'little') then swapEndian :=true; {$ELSE} if AnsiContainsText(mArray.Strings[0], 'big') then swapEndian :=true; {$ENDIF} end else if AnsiContainsText(tagName, 'encoding') then begin if AnsiContainsText(mArray.Strings[0], 'raw') then gzBytes :=0 else if AnsiContainsText(mArray.Strings[0], 'gz') or AnsiContainsText(mArray.Strings[0], 'gzip') then gzBytes := K_gzBytes_headerAndImageCompressed//K_gzBytes_headeruncompressed else NSLog('Unknown encoding format '+mArray.Strings[0]); end else if AnsiContainsText(tagName, 'space origin') then begin if (nItems > 3) then nItems :=3; for i:=0 to (nItems-1) do offset[i] := strtofloat(mArray.Strings[i]); end else if AnsiContainsText(tagName, 'data file') then begin str := mArray.Strings[0]; if fileexistsex(str) then fname := str else begin fname := ExtractFileDirWithPathDelim(fname)+str; end; isDetachedFile :=true; //break; end; //for ...else tag names end; if ((headerSize = 0) and ( not isDetachedFile)) then begin if gzBytes = K_gzBytes_headerAndImageCompressed then gzBytes := K_gzBytes_onlyImageCompressed; //raw text file followed by GZ image headerSize :=fileposBytes; end; result := true; 666: CloseFile(FP); Filemode := 2; mArray.free; if not result then exit; nhdr.vox_offset :=headerSize; if (matElements >= 9) then begin nhdr.srow_x[0] :=-mat[0,0]; nhdr.srow_x[1] :=-mat[1,0]; nhdr.srow_x[2] :=-mat[2,0]; nhdr.srow_x[3] :=-offset[0]; nhdr.srow_y[0] :=-mat[0,1]; nhdr.srow_y[1] :=-mat[1,1]; nhdr.srow_y[2] :=-mat[2,1]; nhdr.srow_y[3] :=-offset[1]; nhdr.srow_z[0] :=mat[0,2]; nhdr.srow_z[1] :=mat[1,2]; nhdr.srow_z[2] :=mat[2,2]; nhdr.srow_z[3] :=offset[2]; //next: ITK does not generate a "spacings" tag - get this from the matrix... for s :=0 to 2 do begin vSqr :=0.0; for i :=0 to 2 do vSqr := vSqr+ ( mat[s,i]*mat[s,i]); nhdr.pixdim[s+1] :=sqrt(vSqr); end //for each dimension end else NSLog('Warning: unable to determine image orientation (unable to decode metaIO "TransformMatrix" tag)'+inttostr(matElements)); convertForeignToNifti(nhdr); end; procedure THD_daxes_to_NIFTI (var nhdr: TNIFTIhdr; xyzDelta, xyzOrigin: vect3; orientSpecific: ivect3); //see http://afni.nimh.nih.gov/pub/dist/src/thd_matdaxes.c const ORIENT_xyz1 = 'xxyyzzg'; //note Pascal strings indexed from 1, not 0! ORIENT_sign1 = '+--++-'; //note Pascal strings indexed from 1, not 0! var axnum: array[0..2] of integer; axcode,axsign: array[0..2] of char; axstart,axstep: array[0..2] of single; ii, nif_x_axnum, nif_y_axnum, nif_z_axnum: integer; qto_xyz: mat44; begin nif_x_axnum := -1; nif_y_axnum := -1; nif_z_axnum := -1; axnum[0] := nhdr.dim[1]; axnum[1] := nhdr.dim[2]; axnum[2] := nhdr.dim[3]; axcode[0] := ORIENT_xyz1[1+ orientSpecific[0] ] ; axcode[1] := ORIENT_xyz1[1+ orientSpecific[1] ] ; axcode[2] := ORIENT_xyz1[1+ orientSpecific[2] ] ; axsign[0] := ORIENT_sign1[1+ orientSpecific[0] ] ; axsign[1] := ORIENT_sign1[1+ orientSpecific[1] ] ; axsign[2] := ORIENT_sign1[1+ orientSpecific[2] ] ; axstep[0] := xyzDelta[0] ; axstep[1] := xyzDelta[1] ; axstep[2] := xyzDelta[2] ; axstart[0] := xyzOrigin[0] ; axstart[1] := xyzOrigin[1] ; axstart[2] := xyzOrigin[2] ; for ii := 0 to 2 do begin if (axcode[ii] = 'x') then nif_x_axnum := ii else if (axcode[ii] = 'y') then nif_y_axnum := ii else nif_z_axnum := ii ; end; if (nif_x_axnum < 0) or (nif_y_axnum < 0) or (nif_z_axnum < 0) then exit; //not assigned if (nif_x_axnum = nif_y_axnum) or (nif_x_axnum = nif_z_axnum) or (nif_y_axnum = nif_z_axnum) then exit; //not assigned ZERO_MAT44(qto_xyz); //-- set voxel and time deltas and units -- nhdr.pixdim[1] := abs ( axstep[0] ) ; nhdr.pixdim[2] := abs ( axstep[1] ) ; nhdr.pixdim[3] := abs ( axstep[2] ) ; qto_xyz[0,nif_x_axnum] := - axstep[nif_x_axnum]; qto_xyz[1,nif_y_axnum] := - axstep[nif_y_axnum]; qto_xyz[2,nif_z_axnum] := axstep[nif_z_axnum]; nhdr.qoffset_x := -axstart[nif_x_axnum] ; nhdr.qoffset_y := -axstart[nif_y_axnum]; nhdr.qoffset_z := axstart[nif_z_axnum]; qto_xyz[0,3] := nhdr.qoffset_x ; qto_xyz[1,3] := nhdr.qoffset_y ; qto_xyz[2,3] := nhdr.qoffset_z ; //nifti_mat44_to_quatern( qto_xyz , nhdr.quatern_b, nhdr.quatern_c, nhdr.quatern_d,dumqx, dumqy, dumqz, dumdx, dumdy, dumdz,nhdr.pixdim[0]) ; //nhdr.qform_code := kNIFTI_XFORM_SCANNER_ANAT; nhdr.srow_x[0] :=qto_xyz[0,0]; nhdr.srow_x[1] :=qto_xyz[0,1]; nhdr.srow_x[2] :=qto_xyz[0,2]; nhdr.srow_x[3] :=qto_xyz[0,3]; nhdr.srow_y[0] :=qto_xyz[1,0]; nhdr.srow_y[1] :=qto_xyz[1,1]; nhdr.srow_y[2] :=qto_xyz[1,2]; nhdr.srow_y[3] :=qto_xyz[1,3]; nhdr.srow_z[0] :=qto_xyz[2,0]; nhdr.srow_z[1] :=qto_xyz[2,1]; nhdr.srow_z[2] :=qto_xyz[2,2]; nhdr.srow_z[3] :=qto_xyz[2,3]; nhdr.sform_code := kNIFTI_XFORM_SCANNER_ANAT; end; function readAFNIHeader (var fname: string; var nhdr: TNIFTIhdr; var gzBytes: int64; var swapEndian: boolean): boolean; label 666; var sl, mArray: TStringList; typeStr,nameStr, valStr: string; lineNum, itemCount,i, vInt, nVols: integer; isAllVolumesSame, isProbMap, isStringAttribute: boolean; valArray : Array of double; orientSpecific: ivect3; xyzOrigin, xyzDelta: vect3; begin {$IFDEF FPC} DefaultFormatSettings.DecimalSeparator := '.' ; //DecimalSeparator := '.'; {$ELSE} DecimalSeparator := '.'; {$ENDIF} nVols := 1; result := false; isProbMap := false; gzBytes := 0; swapEndian := false; sl := TStringList.Create; mArray := TStringList.Create; sl.LoadFromFile(fname); if(sl.count) < 4 then goto 666; lineNum := -1; repeat //read type string lineNum := lineNum + 1; if length(sl[lineNum]) < 1 then continue; splitstr('=',sl[lineNum],mArray); if mArray.Count < 2 then continue; if not AnsiContainsText(cleanStr(mArray[0]), 'type') then continue; typeStr := cleanStr(mArray[1]); isStringAttribute := AnsiContainsText(typeStr, 'string-attribute'); //next: read name string lineNum := lineNum + 1; if (lineNum >= (sl.count-1)) then continue; splitstr('=',sl[lineNum],mArray); if mArray.Count < 2 then continue; if not AnsiContainsText(cleanStr(mArray[0]), 'name') then continue; nameStr := cleanStr(mArray[1]); //if AnsiContainsText(nameStr,'BYTEORDER_STRING') and isStringAttribute then showmessage('txt'); //next: read count string lineNum := lineNum + 1; if (lineNum >= (sl.count-1)) then continue; splitstr('=',sl[lineNum],mArray); if mArray.Count < 2 then continue; if not AnsiContainsText(cleanStr(mArray[0]), 'count') then continue; itemCount := strtoint(cleanStr(mArray[1])); if itemCount < 1 then exit; //next read values lineNum := lineNum + 1; if (lineNum > (sl.count-1)) then continue; valStr := sl[lineNum]; while ((lineNum+1) <= (sl.count-1)) and (length(sl[lineNum+1]) > 0) do begin lineNum := lineNum + 1; //AFNI wraps some arrays across multiple lines valStr := valStr + ' '+ sl[lineNum]; end; splitstr(' ',valStr,mArray); if (mArray.Count < itemCount) then itemCount := mArray.Count; // <- only if corrupt if itemCount < 1 then continue; // <- only if corrupt data if isStringAttribute then begin if AnsiContainsText(nameStr,'BYTEORDER_STRING') then begin {$IFDEF ENDIAN_BIG} if AnsiContainsText(mArray[0],'LSB_FIRST') then swapEndian := true; {$ELSE} if AnsiContainsText(mArray[0],'MSB_FIRST') then swapEndian := true; {$ENDIF} end end else begin //if numeric attributes... setlength(valArray,itemCount); for i := 0 to (itemCount-1) do valArray[i] := strtofloat(cleanStr(mArray[i]) ); //next - harvest data from important names if AnsiContainsText(nameStr,'BRICK_TYPES') then begin vInt := round(valArray[0]); if (vInt = 0) then begin nhdr.datatype := kDT_UINT8; end else if (vInt = 1) then begin nhdr.datatype := kDT_INT16; //16 bit signed int end else if (vInt = 3) then begin nhdr.datatype := kDT_FLOAT32;//32-bit float end else begin NSLog('Unsupported BRICK_TYPES '+inttostr(vInt)); goto 666; end; if (itemCount > 1) then begin //check that all volumes are of the same datatype nVols := itemCount; isAllVolumesSame := true; for i := 1 to (itemCount-1) do if (valArray[0] <> valArray[i]) then isAllVolumesSame := false; if (not isAllVolumesSame) then begin NSLog('Unsupported BRICK_TYPES feature: datatype varies between sub-bricks'); goto 666; end; end; //if acount > 0 //NSLog('HEAD datatype is '+inttostr(nhdr.datatype) ); end else if AnsiContainsText(nameStr,'BRICK_FLOAT_FACS') then begin nhdr.scl_slope := valArray[0]; if (itemCount > 1) then begin //check that all volumes are of the same datatype isAllVolumesSame := true; for i := 1 to (itemCount-1) do if (valArray[0] <> valArray[i]) then isAllVolumesSame := false; if (not isAllVolumesSame) then begin NSLog('Unsupported BRICK_FLOAT_FACS feature: intensity scale between sub-bricks'); end; end; //if acount > 0 end else if AnsiContainsText(nameStr,'DATASET_DIMENSIONS') then begin if itemCount > 3 then itemCount := 3; for i := 0 to (itemCount-1) do nhdr.dim[i+1] := round(valArray[i]); end else if AnsiContainsText(nameStr,'ORIENT_SPECIFIC') then begin if itemCount > 3 then itemCount := 3; for i := 0 to (itemCount-1) do orientSpecific[i] := round(valArray[i]);; //NSLog(@"HEAD orient specific %d %d %d",orientSpecific.v[0],orientSpecific.v[1],orientSpecific.v[2]); end else if AnsiContainsText(nameStr,'ORIGIN') then begin if itemCount > 3 then itemCount := 3; for i := 0 to (itemCount-1) do xyzOrigin[i] := valArray[i]; //NSLog(@"HEAD origin %g %g %g",xyzOrigin.v[0],xyzOrigin.v[1],xyzOrigin.v[2]); end else if AnsiContainsText(nameStr,'ATLAS_PROB_MAP') then begin if (round(valArray[0]) = 1) then isProbMap := true; end else if AnsiContainsText(nameStr,'ATLAS_LABEL_TABLE') then begin nhdr.intent_code := kNIFTI_INTENT_LABEL; end else if AnsiContainsText(nameStr,'DELTA') then begin if itemCount > 3 then itemCount := 3; for i := 0 to (itemCount-1) do xyzDelta[i] := valArray[i]; //NSLog(@"HEAD delta %g %g %g",xyzDelta.v[0],xyzDelta.v[1],xyzDelta.v[2]); end else if AnsiContainsText(nameStr,'TAXIS_FLOATS') then begin if (itemCount > 1) then nhdr.pixdim[4] := valArray[1]; //second item is TR end; end;// if isStringAttribute else numeric inputs... until (lineNum >= (sl.count-1)); result := true; 666: valArray := nil; //release dynamic array Filemode := 2; sl.free; mArray.free; if not result then exit; //error - code jumped to 666 without setting result to true if (nVols > 1) then nhdr.dim[4] := nVols; if (isProbMap) and (nhdr.intent_code = kNIFTI_INTENT_LABEL) then nhdr.intent_code := kNIFTI_INTENT_NONE; THD_daxes_to_NIFTI(nhdr, xyzDelta, xyzOrigin, orientSpecific ); nhdr.vox_offset := 0; convertForeignToNifti(nhdr); fname := ChangeFileExtX(fname, '.BRIK'); if (not FileExistsEX(fname)) then begin fname := fname+'.gz'; gzBytes := K_gzBytes_headerAndImageCompressed; end; end; function readForeignHeader (var lFilename: string; var lHdr: TNIFTIhdr; var gzBytes: int64; var swapEndian: boolean): boolean; var lExt: string; begin NII_Clear (lHdr); result := false; lExt := UpCaseExt(lFilename); if (lExt = '.MGH') or (lExt = '.MGZ') then result := readMGHHeader(lFilename, lHdr, gzBytes, swapEndian) else if (lExt = '.MHD') or (lExt = '.MHA') then result := readMHAHeader(lFilename, lHdr, gzBytes, swapEndian) else if (lExt = '.NRRD') or (lExt = '.NHDR') then result := readNRRDHeader(lFilename, lHdr, gzBytes, swapEndian) else if (lExt = '.HEAD') then result := readAFNIHeader(lFilename, lHdr, gzBytes, swapEndian); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/dialogsx.pas������������������������������������������������0000755�0001750�0001750�00000006766�12271761612�020036� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit dialogsx; {$Include isgui.inc} {$H+} interface uses //,IniFiles SysUtils; type TMsgDlgBtn = (mbYes, mbNo, mbOK, mbCancel, mbAbort, mbRetry, mbIgnore, mbAll, mbNoToAll, mbYesToAll, mbHelp); TMsgDlgButtons = set of TMsgDlgBtn; TMsgDlgType = (mtWarning, mtError, mtInformation, mtConfirmation, mtCustom); //procedure Msg (lStr: string); procedure ShowMsg (lStr: string); procedure msgfx (a,b,c,d: double); overload; //fx used to help debugging - reports number values function MsgDlg(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint): Word; function GetInt(lStr: string; lMin,lDefault,lMax: integer): integer; procedure MyReadLn;//no GUI: waits for user function GetStr(lPrompt: string): string; {$IFNDEF GUI}procedure ShowMessage (lStr: string); {$ENDIF} //procedure vx (a,b,c,d: double); const mrCancel = 2; mrAbort = 1;// idAbort mrNo = 0; implementation {$IFDEF GUI}uses readint,dialogs; {$ENDIF} procedure Msg (lStr: string); begin {$IFDEF GUI} showmessage(lStr); {$ELSE} writeln(lStr) {$ENDIF} end; {$IFNDEF GUI}procedure ShowMessage (lStr: string); begin writeln(lStr) ; end; {$ENDIF} procedure vx (a,b,c,d: double); //vx used to help debugging - reports number values begin msg(floattostr(a)+':'+floattostr(b)+':'+floattostr(c)+':'+floattostr(d)); end; procedure MyReadLn; {$IFDEF GUI} begin //do nothing end; {$ELSE} begin {$IFNDEF UNIX} if IsConsole then ReadLn; {$ENDIF} end; {$ENDIF} function MsgDlg(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint): Word; {$IFDEF GUI} var lDlgType : Dialogs.TMsgDlgType; lButtons: Dialogs.TMsgDlgButtons; begin lDlgType := Dialogs.TMsgDlgType(DlgType); lButtons:= Dialogs.TMsgDlgButtons(Buttons); result := MessageDlg(Msg, lDlgType, lButtons,HelpCtx); {$ELSE} begin result := 0; writeln('WARNING: dialogs not being used. Unabled to process this '+Msg); {$ENDIF} end; procedure ShowMsg (lStr: string); begin {$IFDEF GUI} ShowMessage(lStr); {$ELSE} writeln(lStr) {$ENDIF} end; procedure msgfx (a,b,c,d: double); overload; //fx used to help debugging - reports number values begin {$IFDEF GUI} msg(floattostr(a)+'x'+floattostr(b)+'x'+floattostr(c)+'x'+floattostr(d)); {$ELSE} msg(floattostr(a)+'x'+floattostr(b)+'x'+floattostr(c)+'x'+floattostr(d)); {$ENDIF} end; function GetStr(lPrompt: string): string; {$IFDEF GUI} var lOK: boolean; begin lOK := InputQuery(lPrompt, lPrompt, result); if not lOK then result := ''; end; {$ELSE} var lS: string; begin writeln ( lPrompt); readln(lS); result := lS; end; {$ENDIF} function GetInt(lStr: string; lMin,lDefault,lMax: integer): integer; {$IFDEF GUI} begin //result := GetInt(lStr, lMin,lDefault,lMax); result := lDefault; Showmessage('Warning - unable to get values for '+lStr); end; {$ELSE} var lS: string; lError,lI: integer; begin writeln ( lStr+' ['+inttostr(lMin)+'..'+inttostr(lMax)+'], default '+inttostr(lDefault)); readln(lS); Val(lS,lI,lError); if lError = 0 then result := round(lI) else begin writeln(inttostr(lDefault)); result := lDefault; end; if result < lMin then result := lMin; if result > lMax then result := lMax; end; {$ENDIF} end. ����������mricron-0.20140804.1~dfsg.1.orig/common/DiskSpaceKludge.pas�����������������������������������������0000755�0001750�0001750�00000015201�11423642036�021202� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// The author gave written permission to distribute this file under the // same licensing terms as MRICRON. // Disk Space Kludge for Delphi 3 for > 2 GB disk drives // Works with Windows 95 OSR2 or later, Windows 98 or Windows 4.0 or later // See http://msdn.microsoft.com/library/sdkdoc/winbase/filesio_8bso.htm // // Use DiskSpaceKludge.DiskFree and DiskSpaceKludge.DiskSize now in D3 and // replace with equivalent SysUtils.DiskFree and SysUtils.DiskSize in D4 // efg, April 1999 UNIT DiskSpaceKludge; INTERFACE USES Windows; // GetDiskFreeSpace, BOOL TYPE TInteger8 = Comp; // 8-byte integer, since disk sizes may be > 2 GB pInteger8 = ^TInteger8; // Use Delphi 4 trick from D4 SysUtils.PAS VAR GetDiskFreeSpaceEx: FUNCTION (DirectoryName: pChar; FreeBytesAvailableToCaller: pInteger8; TotalNumberOfBytes : pInteger8; TotalNumberOfFreeBytes : pInteger8): BOOL StDCall = NIL; FUNCTION GetDiskFreeSpaceExA (DirectoryName: pChar; FreeBytesAvailableToCaller: pInteger8; TotalNumberOfBytes : pInteger8; TotalNumberOfFreeBytes : pInteger8): BOOL; StDCall; FUNCTION DiskFreeA(Drive: BYTE): TInteger8; FUNCTION DiskSize(Drive: BYTE): TInteger8; FUNCTION DiskFreeStr(DriveStr: String): TInteger8; FUNCTION DiskFreeEx (DriveStr: String): Integer; IMPLEMENTATION USES SysUtils; // StrCopy function DiskFreeEx (DriveStr: String): Integer; var lOutDisk: Integer; lDiskDir : string; lSize8: Tinteger8; begin lOutDisk := ord(upcase(DriveStr[1]))+1-ord('A'); if (lOutDisk >= ord('A')) and (lOutDisk <= ord('Z')) then begin DiskFreeEx := DiskFree(lOutDisk); end else begin lDiskDir :=(ExtractFileDrive(DriveStr))+'\'; lSize8 := DiskFreeStr (lDiskDir); if lSize8 > MaxINt then DiskFreeEx := MaxInt else DiskFreeEx := round(lSize8); end; end; /////////////////////////////////////////////////////////////////////////// FUNCTION GetDiskFreeSpaceExA; EXTERNAL KERNEL32 NAME 'GetDiskFreeSpaceExA'; /////////////////////////////////////////////////////////////////////////// // Borland's DiskFree and DiskSize in D3 SysUtils only return a 4-byte integer. // Use Integer8 here so values are meaningful on large disk drives. // These routines may be replaced in D4 with the same name functions that // return Int64 values. // DiskFree returns the number of free bytes on the specified drive number, // where 0 = Current, 1 = A, 2 = B, etc. DiskFree returns -1 if the drive // number is invalid. } FUNCTION DiskFreeA(Drive: BYTE): TInteger8; VAR FreeBytesAvailableToCaller: TInteger8; RootPath : ARRAY[0..4] OF CHAR; RootPtr : pChar; TotalNumberOfBytes : TInteger8; BEGIN RootPtr := NIL; IF Drive > 0 THEN BEGIN StrCopy(RootPath, 'A:\'); RootPath[0] := CHR(Drive + ORD('A') - 1); StrCopy(RootPath, 'C:\'); RootPtr := RootPath END; // Use NIL as third parameter, just like in D4 InternalGetDiskSpace routine IF GetDiskFreeSpaceEx(RootPtr, @FreeBytesAvailableToCaller, @TotalNumberOfBytes, NIL) THEN RESULT := FreeBytesAvailableToCaller ELSE RESULT := -1 END {DiskFree}; FUNCTION DiskFreeStr(DriveStr: String): TInteger8; VAR FreeBytesAvailableToCaller: TInteger8; RootPath : ARRAY[0..255] OF CHAR; RootPtr : pChar; TotalNumberOfBytes : TInteger8; BEGIN // RootPtr := NIL; // StrCopy(RootPath, DriveStr); { RootPath[0] := CHR(Drive + ORD('A') - 1); StrCopy(RootPath, 'C:\');} RootPtr := RootPath; StrPCopy(RootPtr,DriveStr); // Use NIL as third parameter, just like in D4 InternalGetDiskSpace routine IF GetDiskFreeSpaceEx(RootPtr, @FreeBytesAvailableToCaller, @TotalNumberOfBytes, NIL) THEN RESULT := FreeBytesAvailableToCaller ELSE RESULT := -1 END {DiskFree}; // DiskSize returns the size in bytes of the specified drive number, where // 0 = Current, 1 = A, 2 = B, etc. DiskSize returns -1 if the drive number // is invalid. } FUNCTION DiskSize(Drive: BYTE): TInteger8; VAR FreeBytesAvailableToCaller: TInteger8; RootPath : ARRAY[0..4] OF CHAR; RootPtr : pChar; TotalNumberOfBytes : TInteger8; BEGIN RootPtr := NIL; IF Drive > 0 THEN BEGIN StrCopy(RootPath, 'A:\'); RootPath[0] := CHR(Drive + ORD('A') - 1); RootPtr := RootPath END; // Use NIL as third parameter, just like in D4 InternalGetDiskSpace routine IF GetDiskFreeSpaceEx(RootPtr, @FreeBytesAvailableToCaller, @TotalNumberOfBytes, NIL) THEN RESULT := TotalNumberOfBytes ELSE RESULT := -1 END {DiskSize}; /////////////////////////////////////////////////////////////////////////// // Equivalent to Delphi 4 SysUtils.PAS routines FUNCTION BackfillGetDiskFreeSpaceEx(Directory: pChar; VAR FreeAvailable, TotalSpace: TInteger8; TotalFree: pInteger8): BOOL; StdCall; VAR BytesPerSector : DWORD; Dir : pChar; FreeClusters : DWORD; SectorsPerCluster: DWORD; Temp : TInteger8; TotalClusters : DWORD; BEGIN IF Directory <> NIL THEN Dir := Directory ELSE Dir := NIL; RESULT := GetDiskFreeSpaceA(Dir, SectorsPerCluster, BytesPerSector, FreeClusters, TotalClusters); Temp := SectorsPerCluster * BytesPerSector; FreeAvailable := Temp * FreeClusters; TotalSpace := Temp * TotalClusters END {BackfillGetDiskFreeSpaceEx}; PROCEDURE InitializeDriveSpacePointer; VAR Kernel: THandle; BEGIN Kernel := GetModuleHandle(Windows.Kernel32); IF Kernel <> 0 THEN @GetDiskFreeSpaceEx := GetProcAddress(Kernel, 'GetDiskFreeSpaceExA'); IF NOT Assigned(GetDiskFreespaceEx) THEN GetDiskFreeSpaceEx := @BackFillGetDiskFreeSpaceEx END {InitializeDriveSpacePointer}; INITIALIZATION InitializeDriveSpacePointer END. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/notgui.inc��������������������������������������������������0000755�0001750�0001750�00000000157�11017300752�017472� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{$DEFINE notGUI} //use GUI if you are using a graphic user interface - anything else for console applications �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/define_types.pas��������������������������������������������0000755�0001750�0001750�00000114547�12377624456�020712� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit define_types; interface {$H+} {$include isgui.inc} uses {$IFNDEF FPC} {$IFDEF GUI} FileCtrl, delphiselectfolder, {$ENDIF} DiskSpaceKludge, Controls, {$ELSE} {$IFDEF GUI} lclintf,LResources,{$ENDIF} {$ENDIF} {$IFNDEF Unix} Windows, {$ELSE} BaseUnix,{$IFDEF GUI} LCLType, {$ENDIF}//lclintf, LMessages,LCLType,//gettickcount {$ENDIF} SysUtils,classes,IniFiles, {$IFDEF GUI} forms,userdir, dialogs{$ELSE}dialogsx{$ENDIF}; const kMRIcronVersDate = '4AUGUST2014'; {$IFDEF FPC} {$ifdef CPU32} kMRIcronVers = kMRIcronVersDate+' 32bit BSD License'; {$ELSE} kMRIcronVers = kMRIcronVersDate+' 64bit BSD License'; {$ENDIF} {$ELSE} kMRIcronVers = kMRIcronVersDate+' 32bit BSD License'; {$ENDIF} NaN : double = 1/0; kMagicDouble : double = -111666222; kTxtFilter = 'Text (*.txt)|*.txt;*.csv|Comma Separated (*.csv)|*.csv'; kAnyFilter = 'Anything (*)|*'; kAnaHdrFilter = 'Analyze Header (*.hdr)|*.hdr'; //kNIIFilter = 'NIfTI (*.nii)|*.nii'; //kImgPlusVOIFilter = 'NIfTI/Analyze/VOI|*.hdr;*.nii;*.nii.gz;*.voi|NIfTI/Analyze Header (*.hdr;*.nii)|*.hdr;*.nii;*.nii.gz|Volume of interest (*.voi)|*.voi'; //kImgFilter = 'NIfTI/Analyze Header (*.hdr;*.nii)|*.hdr;*.nii;*.nii.gz|Volume of interest (*.voi)|*.voi'; //kImgFilterPlusAny = 'NIfTI/Analyze Header (*.hdr;*.nii)|*.hdr;*.nii;*.nii.gz|Volume of interest (*.voi)|*.voi|Any file (*.*)|*.*'; kNIIFilter = 'Neuroimaging (*.nii)|*.hdr;*.nii;*.nii.gz;*.voi;*.HEAD;*.mgh;*.mgz;*.mha;*.mhd;*.nhdr;*.nrrd'; kImgFilter = 'Neuroimaging|*.hdr;*.nii;*.nii.gz;*.HEAD;*.mgh;*.mgz;*.mha;*.mhd;*.nhdr;*.nrrd|Volume of interest (*.voi)|*.voi'; kImgPlusVOIFilter = 'Neuroimaging/VOI|*.hdr;*.nii;*.nii.gz;*.voi;*.HEAD;*.mgh;*.mgz;*.mha;*.mhd;*.nhdr;*.nrrd|NIfTI/Analyze Header (*.hdr;*.nii)|*.hdr;*.nii;*.nii.gz|Volume of interest (*.voi)|*.voi'; kImgFilterPlusAny = 'Neuroimaging/VOI|*.hdr;*.nii;*.nii.gz;*.voi;*.HEAD;*.mgh;*.mgz;*.mha;*.mhd;*.nhdr;*.nrrd|NIfTI/Analyze Header (*.hdr;*.nii)|*.hdr;*.nii;*.nii.gz|Volume of interest (*.voi)|*.voi|Anything (*.*)|*.*'; kHistoBins = 256;//numbers of bins for histogram/image balance PixelCountMax = 32768; kTab = chr(9); kEsc = chr(27); kCR = chr (13); kBS = #8 ; // Backspace kDel = #127 ; // Delete UNIXeoln = chr(10); kTextSep = kTab;//','; //',' for CSV, kTab for Tab-delimited values kLUTalpha = 255; //255 kVOI8bit = 1;//May07 100; {$IFDEF unix} PathDelim = '/'; {$ELSE} PathDelim = '\'; {$ENDIF} type TStrRA = Array of String; TPSPlot = RECORD //peristimulus plot TRSec,BinWidthSec: single; nNegBins,nPosBins,SPMDefaultsStatsFmriT,SPMDefaultsStatsFmriT0: integer; TextOutput,GraphOutput, SliceTime,SavePSVol,BaselineCorrect,PctSignal,RemoveRegressorVariability,TemporalDeriv,PlotModel,Batch: boolean end; TRGBquad = PACKED RECORD {$IFDEF ENDIAN_BIG} //OSX PPC rgbreserved,rgbRed,rgbGreen,rgbBlue: byte; //rgbBlue,rgbGreen,rgbRed,rgbreserved: byte; {$ELSE} {$IFDEF UNIX} {$IFDEF DARWIN} rgbreserved,rgbRed,rgbGreen,rgbBlue: byte; {$ELSE} rgbRed,rgbGreen,rgbBlue,rgbreserved: byte; {$ENDIF} {$ELSE} //not unix - windows //rgbreserved,rgbRed,rgbGreen,rgbBlue: byte; rgbBlue,rgbGreen,rgbRed,rgbreserved: byte; {$ENDIF} // rgbBlue,rgbGreen,rgbRed,rgbreserved: byte; {$ENDIF} end; TStretchQuality = (sqLow, sqHigh); //TLUTrgb = array[0..255] of TRGBQuad; //TLUTtype = DWORD; TLUT = array[0..255] of TRGBQuad; kStr20 = string[20]; kStr50 = string[50]; kStr255 = string[255]; TCutout = RECORD Lo : array [1..3] of integer; Hi : array [1..3] of integer; end; int32 = LongInt; uint32 = Cardinal; int16 = SmallInt; uint16 = Word; int8 = ShortInt; uint8 = Byte; Int64RA = array [1..1] of int64; Int64p = ^Int64RA; SingleRA0 = array [0..0] of Single; Singlep0 = ^SingleRA0; ByteRA0 = array [0..0] of byte; Bytep0 = ^ByteRA0; WordRA0 = array [0..0] of Word; Wordp0 = ^WordRA0; SmallIntRA0 = array [0..0] of SmallInt; SMallIntp0 = ^SmallIntRA0; LongIntRA0 = array [0..0] of LongInt; LongIntp0 = ^LongIntRA0; DWordRA = array [1..1] of DWord; DWordp = ^DWordRA; ByteRA = array [1..1] of byte; Bytep = ^ByteRA; WordRA = array [1..1] of Word; Wordp = ^WordRA; SmallIntRA = array [1..1] of SmallInt; SMallIntp = ^SmallIntRA; LongIntRA = array [1..1] of LongInt; LongIntp = ^LongIntRA; SingleRA = array [1..1] of Single; Singlep = ^SingleRA; SingleRARA = array [1..1] of Singlep; SingleRAp = ^SingleRARA; DoubleRA = array [1..1] of Double; Doublep = ^DoubleRA; DoubleRA0 = array [0..0] of Double; Doublep0 = ^DoubleRA0; HistoRA = array [0..kHistoBins] of longint; HistoDoubleRA = array [0..kHistoBins] of double; //pRGBQuadArray = ^TRGBQuad; //TRGBQuadeArray = ARRAY[0..PixelCountMax-1] OF TRGBQuad; //RGBQuadRA = array [1..1] of TRGBQuad; //RGBQuadp = ^RGBQuadRA; TQuadRA = array [1..1] of TRGBQuad; RGBQuadp = ^TQuadRA; // pRGBTripleArray = ^TRGBTripleArray; // TRGBTripleArray = ARRAY[0..PixelCountMax-1] OF TRGBTriple; FUNCTION specialsingle (var s:single): boolean; //check if 32-bit float is Not-A-Number, infinity, etc function FSize (lFName: String): Int64; function FileExistsEX(Name: String): Boolean; function ParseFileName (lFilewExt:String): string; function ParseFileFinalDir (lFileName:String): string; function ExtractFileDirWithPathDelim(lInFilename: string): string; function PadStr (lValIn, lPadLenIn: integer): string; function ChangeFileExtX( var lFilename: string; lExt: string): string; //function swap2i(SmallInt): Smallint; function swap4r4i (s:single): longint; //swap and convert: endian-swap and then typecast 32-bit float as 32-bit integer function conv4r4i (s:single): longint; //convert: typecast 32-bit float as 32-bit integer function swap8r(s : double):double; //endian-swap 64-bit float procedure pswap4i(var s : LongInt); //procedure to endian-swap 32-bit integer procedure pswap4r ( var s:single); //procedure to endian-swap 32-bit integer function swap64r(s : double):double; function specialdouble (d:double): boolean; function RealToStr(lR: double {was extended}; lDec: integer): string; function UpCaseExt(lFileName: string): string;//file.brik.gz->BRIK.GZ, file.nii.gz -> NII.GZ function ExtGZ (lFilename: string): boolean; procedure swap4(var s : LongInt); procedure Xswap4r ( var s:single); function Bool2Char (lBool: boolean): char; function Char2Bool (lChar: char): boolean; function Log(X, Base: single): single; //procedure GZipBuffer(var FGzipFilename,FFileDestination: String;lxInBuffer: byteP;lInSize: Integer; lOverwritewarn: boolean); //procedure GZipBuffer(var FGzipFilename,FFileDestination: String;lxInBuffer: byteP;lInSize: Integer); {$IFNDEF FPC} function DiskFreeEx (DriveStr: String): Integer; {$ELSE} function DiskFreeEx (DriveStr: String): Int64; {$ENDIF} procedure SortSingle(var lLo,lHi: single); procedure SortInteger(var lLo,lHi: integer); function IniInt(lIniFile: TIniFile; lIdent: string; lDefault: integer): integer; function IniBool(var lIniFile: TIniFile; lIdent: string; lDefault: boolean): boolean; procedure CopyFileEX (lInName,lOutName: string); procedure CopyFileEXoverwrite (lInName,lOutName: string); procedure fx (a: double); overload; //fx used to help debugging - reports number values procedure fx (a,b: double); overload; procedure fx (a,b,c: double); overload; procedure fx (a,b,c,d: double); overload; function Swap2(s: smallint): smallint; //function DefaultsDir (lSubFolder: string): string; function ChangeFilePostfixExt (lInName,lPostfix,lExt: string): string; procedure SortCutout (var lCutout : TCutout); //ensure Lo < Hi function freeRam: Int64; function OKMsg(lMsg: string): boolean; //shows dialog with OK/Cancel returns true if user presses OK function DirExists (lFolderName: String): boolean; function FilenameParts (lInName: string; var lPath,lName,lExt: string): boolean; function AddIndexToFilename (lInName: string; lIndex: integer): string; procedure createArray64 (var ptr: pointer; var ra :Doublep0; Sz: integer); overload; procedure createArray64 (var ptr: pointer; var ra :Doublep; Sz: integer); overload; function GzExt(lFileName: string): boolean; function ChangeFilePrefixExt (lInName,lPrefix,lExt: string): string; function ChangeFilePrefix(lInName,lPrefix: string): string; function makesmallint (b0,b1: byte): smallint; function makesingle( b0,b1,b2,b3: byte): single; procedure SortInt (var lMin,lMax: integer); function Bound (lDefault,lMin,lMax: integer): integer; function IsNiftiExt(lStr: string): boolean; function IsExtNIFTIHdr(lStr: string): boolean; function IsVOIExt(lStr: string): boolean; //procedure ax(a,b,c,d,e,fx: double); procedure EnsureDirEndsWithPathDelim (var lDir: string); //function IsReadOnly(const FileName: string): Boolean;//I think this only works for existing files... not folders and new files function DirWritePermission(Where: string): Boolean; //I think this is better than above function ExtractDir (lFilepath: string): string; {$IFDEF GUI} function GetDirPrompt (lDefault: string): string; {$ENDIF} function Str2Int (lStr: string): integer; function ResetDefaults : boolean; implementation function ResetDefaults : boolean; const {$IFDEF LINUX} kKey = 'Right button'; {$ELSE} kKey = 'Shift key'; {$ENDIF} var lKey: boolean; begin result := false; {$IFDEF GUI} {$IFDEF LINUX} lKey := (GetKeyState(VK_RBUTTON) And $80)<>0; {$ELSE} lKey := (ssShift in KeyDataToShiftState(vk_Shift)); {$ENDIF} if not lKey then exit; {$IFDEF GUI} case MessageDlg(kKey+' down during launch: do you want to reset the default preferences?', mtConfirmation, [mbYes, mbNo], 0) of { produce the message dialog box } idYes: result := true; end; //case {$ENDIF} {$ENDIF} end; function Str2Int (lStr: string): integer; //robust stringtoint that strips out any junk so that "Implementation Version Name=MR.VB15A" returns 15 // warning, strips out decimals, so 15.3 will return 153! //warning also ignores minus sign so -5.21 will return 521! var Len,P: integer; S: string; begin result := 0; Len := length(lStr); if Len <1 then exit; S := ''; for P := 1 to Len do if lStr[P] in ['-','0'..'9'] then S := S + lStr[P]; if length(S) < 1 then exit; result := strtoint(S); end; {$IFDEF GUI} function GetDirPrompt (lDefault: string): string; // Old versions of Delphi have a clumsy SelectDirectory function, and locks the folder until you quit your application... var lD: string; begin lD := lDefault; if not DirExists(lD) then lD := UserDataFolder; result := lD; // Set the starting directory {$IFDEF FPC} //Delphi SelectDirectory uses FileCtrl //Lazarus SelectDirectory uses Dialogs chdir(result); //start search from previous dir... if SelectDirectory(result, [sdAllowCreate,sdPerformCreate,sdPrompt], 0) then begin chdir(result); exit; end; {$ELSE} if SelectDirectoryDelphi('Select folder', result, true) then exit; {$ENDIF} //if the user aborts, make sure we use the default directory... result := lD; end; {$ENDIF} //GUI function ExtractDir (lFilepath: string): string; //if passed file \usr\temp\data.txt returns \usr\temp\ //if passed dir \usr\temp returns \usr\temp\ //note returned always includes pathdelim var lName,lExt: string; begin FilenameParts (lFilepath,Result,lName,lExt); end; function DirWritePermission(Where: string): Boolean; {$IFDEF UNIX} //Uses BaseUnix; begin result := (fpAccess (ExtractDir(Where),W_OK)=0); end; {$ELSE} Var i : Longint; lFilename: string; Begin result := false; if length(Where) < 1 then exit; if DirExists (Where) then begin if Where[length(Where)] <> PathDelim then lFilename := Where + pathdelim + 'dummy.dum' else lFilename := Where + 'dummy.dum'; end else lFilename := Where; if fileexists (lFilename) then exit; //do not overwrite existing file i:=FileCreate (lFilename); if i=-1 then Halt(1); FileClose(i); DeleteFile(lFilename); result := true; end; {$ENDIF} (*function IsReadOnly(const FileName: string): Boolean; var sr: TSearchRec; begin // Assume not read only Result := False; if FindFirst(FileName, faAnyFile, sr) = 0 then begin Result := (sr.Attr and faReadOnly) <> 0; FindClose(sr); end; end; *) procedure EnsureDirEndsWithPathDelim (var lDir: string); begin if length(lDir) < 1 then exit; if lDir[length(lDir)] = pathdelim then exit; lDir := lDir + pathdelim; end; function AddIndexToFilename (lInName: string; lIndex: integer): string; var lPath,lName,lExt: string; begin result := ''; if not FilenameParts (lInName, lPath,lName,lExt) then exit; result := lPath+lName+inttostr(lIndex)+lExt; end; function Bound (lDefault,lMin,lMax: integer): integer; begin result := lDefault; if result < lMin then result := lMin; if result > lMax then result := lMax; end; function IsVOIExt(lStr: string): boolean; var lExt: string; begin result := false; lExt := UpCaseExt(lStr); if (lExt = '.VOI') then result := true; end; function IsNiftiExt(lStr: string): boolean; var lExt: string; begin result := false; lExt := UpCaseExt(lStr); if (lExt = '.MGH') or (lExt = '.MGZ') then result := true; if (lExt = '.MHA') or (lExt = '.MHD') then result := true; if (lExt = '.HEAD') then result := true; if (lExt = '.NRRD') then result := true; if (lExt = '.NII') or (lExt = '.NII.GZ') then result := true; if (lExt = '.HDR') and (FSize(ChangeFileExt(lStr,'.img'))> 0) then result := true; if (lExt = '.IMG') and (FSize(ChangeFileExt(lStr,'.hdr'))> 0) then result := true; end; function IsExtNIFTIHdr(lStr: string): boolean; //detect hdr, nii,niigz var lExt: string; begin result := false; lExt := UpCaseExt(lStr); if (lExt = '.NII') or (lExt = '.NII.GZ') then result := true; if (lExt = '.HDR') and (FSize(ChangeFileExt(lStr,'.img'))> 0) then result := true; (*if (lExt = '.IMG') and (FSize(ChangeFileExt(lStr,'.hdr'))> 0) then result := true; *) end; procedure SortInt (var lMin,lMax: integer); var lSwap: integer; begin if lMin <= lMax then exit; lSwap := lMax; lMax := lMin; lMin := lSwap; end; function makesmallint (b0,b1: byte): smallint; type swaptype = packed record case byte of 0:(b0,b1 : byte); //word is 16 bit 1:(s:smallint); end; swaptypep = ^swaptype; var //inguy:swaptypep; outguy:swaptype; begin //inguy := @s; //assign address of s to inguy outguy.b0 := b0; outguy.b1 := b1; result:=outguy.s; end;//makesmallint function makesingle( b0,b1,b2,b3: byte): single; type swaptype = packed record case byte of 0:(b0,b1,b2,b3 : byte); //word is 16 bit 1:(long:single); end; swaptypep = ^swaptype; var outguy:swaptype; begin //inguy := @s; //assign address of s to inguy outguy.b0 := b0; outguy.b1 := b1; outguy.b2 := b2; outguy.b3 := b3; result:=outguy.long; end;//swap4r4i function ChangeFilePrefix(lInName,lPrefix: string): string; var lC,lLen,lPos: integer; lStr: string; begin //result := changefileext(lInName,lExt); result := lInName; lLen := length (result); if lLen < 1 then exit; lPos := lLen; while (lPos > 1) and (result[lPos] <> pathdelim) do dec(lPos); lStr := ''; for lC := 1 to lPos do lStr := lStr+result[lC]; lStr := lStr+lPrefix; if lPos < lLen then for lC := (lPos+1) to lLen do lStr := lStr+result[lC]; result := lStr; end; function ChangeFilePrefixExt (lInName,lPrefix,lExt: string): string; var lC,lLen,lPos: integer; lStr: string; begin result := changefileext(lInName,lExt); lLen := length (result); if lLen < 1 then exit; lPos := lLen; while (lPos > 1) and (result[lPos] <> pathdelim) do dec(lPos); lStr := ''; for lC := 1 to lPos do lStr := lStr+result[lC]; lStr := lStr+lPrefix; if lPos < lLen then begin lC := lPos+1; while (lC <= lLen) and (result[lC] <> '.') do begin lStr := lStr + result[lC]; inc(lC); end; end; lStr := lStr + lExt; result := lStr; end; function GzExt(lFileName: string): boolean; var lExt: string; begin lExt := UpCaseExt(lFilename); if (lExt = '.VOI') or (lExt = '.NII.GZ') or (lExt = '.GZ') then result := true else result := false; end; function FilenameParts (lInName: string; var lPath,lName,lExt: string): boolean; var lLen,lPos,lExtPos,lPathPos: integer; begin result := false; lPath := ''; lName := ''; lExt := ''; lLen := length(lInName); if lLen < 1 then exit; if DirExists(lInName) then begin //we have been passed a folder, not a file if lInName[lLen] = PathDelim then lPath := lInName else lPath := lInName + pathdelim; exit; end; //next find final pathdelim lPathPos := lLen; while (lPathPos > 0) and (lInName[lPathPos] <> '\') and (lInName[lPathPos] <> '/') do dec(lPathPos); if (lInName[lPathPos] = '\') or (lInName[lPathPos] = '/') then begin for lPos := 1 to lPathPos do lPath := lPath + lInName[lPos]; end; // else // dec(lPathPos); inc(lPathPos); //next find first ext //lExtPos := 1; lExtPos := length(lPath);//July 2009 -- beware of '.' in foldername... while (lExtPos <= lLen) and (lInName[lExtPos] <> '.') do inc(lExtPos); if (lInName[lExtPos] = '.') then begin for lPos := lExtPos to lLen do lExt := lExt + lInName[lPos]; end; // else // inc(lExtPos); dec(lExtPos); //next extract filename //fx(lPathPos,lExtPos); if (lPathPos <= lExtPos) then for lPos := lPathPos to lExtPos do lName := lName + lInName[lPos]; result := true; end; procedure createArray64 (var ptr: pointer; var ra :Doublep0; Sz: integer); overload; var i: integer; begin getmem(ptr,16+(sizeof(double)*Sz)); {$IFDEF FPC} ra := align(ptr,16); {$ELSE} ra := DoubleP0((integer(ptr) and $FFFFFFF0)+16); {$ENDIF} for i := (Sz-1) downto 0 do //initialise array ra^[i] := 0; end; procedure createArray64 (var ptr: pointer; var ra :Doublep; Sz: integer); overload; var i: integer; begin getmem(ptr,16+(sizeof(double)*Sz)); {$IFDEF FPC} ra := align(ptr,16); {$ELSE} ra := DoubleP((integer(ptr) and $FFFFFFF0)+16); {$ENDIF} for i := (Sz) downto 1 do //initialise array ra^[i] := 0; end; function OKMsg(lMsg: string): boolean; //shows dialog with OK/Cancel returns true if user presses OK begin result := false; {$IFDEF GUI} case MessageDlg(lMsg, mtConfirmation, [mbYes, mbCancel], 0) of idCancel {mrCancel}: exit; end; //case {$ELSE} case MsgDlg(lMsg, mtConfirmation, [mbYes, mbCancel], 0) of mrCancel: exit; end; //case {$ENDIF} result := true; end; (*function DirExists (lDir: String): boolean; var lSearchRec: TSearchRec; begin FindFirst(lDir, faAnyFile, lSearchRec); if (faDirectory and lSearchRec.attr) = faDirectory then DirExists := true else DirExists := false; FindClose(lSearchRec);{} end;*) {$IFNDEF GUI} {$IFNDEF FPC} //The FileCtrl unit is pretty bulky, and we only need this one call that it links from SysUtils function DirectoryExists(const Name: string): Boolean; var Code: Integer; begin Code := GetFileAttributes(PChar(Name)); Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0); end; {$ENDIF} {$ENDIF} function DirExists (lFolderName: string): boolean; (*{$IFNDEF GUI} var lSearchRec: TSearchRec; begin result := false; if fileexists(lFoldername) then //File not folder exit; Filemode := 0; //readonly if FindFirst(lFolderName, faDirectory, lSearchRec) = 0 then begin result := true; FindClose(lSearchRec); end else result := false; //some files found Filemode := 2; {$ELSE} *) begin result := DirectoryExists(lFolderName); //{$ENDIF} end; function freeRam: Int64; {$IFDEF UNIX} begin result := maxint; end; {$ELSE} var memory:TMemoryStatus; begin memory.dwLength:=sizeof(memory); GlobalMemoryStatus(memory); result := memory.dwavailPhys; //result := 1024; end; {$ENDIF} procedure SortCutout (var lCutout : TCutout); //ensure Lo < Hi var lInc,lSwap: integer; begin for lInc := 1 to 3 do if lCutout.Lo[lInc] > lCutout.Hi[lInc] then begin lSwap := lCutout.Lo[lInc]; lCutout.Lo[lInc] := lCutout.Hi[lInc]; lCutout.Hi[lInc] := lSwap; end; end; function ChangeFilePostfixExt (lInName,lPostfix,lExt: string): string; var lPath,lName,lExtIn: string; begin FilenameParts (lInName, lPath,lName,lExtIn); result := lPath+lName+lPostFix+lExt; //showmessage(result); end; (*var lC,lLen,lPos: integer; lStr: string; begin result := changefileext(lInName,lExt); lLen := length (result); if lLen < 1 then exit; lPos := lLen; while (lPos > 1) and (result[lPos] <> pathdelim) and (result[lPos] <> '.') do dec(lPos); if result[lPos] = '.' then dec(lPos); lStr := ''; for lC := 1 to lPos do lStr := lStr+result[lC]; lStr := lStr+lPostfix; if lPos < lLen then for lC := (lPos+1) to lLen do lStr := lStr+result[lC]; result := lStr; end; *) (*procedure ApplySaveDlgFilter (lSaveDlg: TSaveDialog); var lLen,lPos,lPipes,lPipesReq: integer; lExt: string; begin lPipesReq := (lSaveDlg.FilterIndex * 2)-1; if lPipesReq < 1 then exit; lLen := length(lSaveDlg.Filter); lPos := 1; lPipes := 0; while (lPos < lLen) and (lPipes < lPipesReq) do begin if lSaveDlg.Filter[lPos] = '|' then inc(lPipes); inc(lPos); end; if (lPos >= lLen) or (lPipes < lPipesReq) then exit; lExt := ''; while (lPos <= lLen) and (lSaveDlg.Filter[lPos] <> '|') do begin if lSaveDlg.Filter[lPos] <> '*' then lExt := lExt + lSaveDlg.Filter[lPos]; inc(lPos); end; if lExt <> '' then lSaveDlg.Filename := ChangeFileExt(lSaveDlg.Filename,lExt); end; *) (*function DefaultsDir (lSubFolder: string): string; //for Linux: DefaultsDir is ~/appname/SubFolder/, e.g. /home/username/mricron/subfolder/ //for Windows: DefaultsDir is in the location of the executable, e.g. c:\program files\mricron\subfolder\ //Note: Final character is pathdelim var lBaseDir: string; begin {$IFDEF Unix} lBaseDir := GetEnvironmentVariable ('HOME')+pathdelim+'.' +ParseFileName(ExtractFilename(paramstr(0) ) ); if not DirectoryExists(lBaseDir) then begin {$I-} MkDir(lBaseDir); if IOResult <> 0 then begin showmessage('Unble to create new folder '+lBaseDir); end; {$I+} end; lBaseDir := lBaseDir+pathdelim; {$ELSE} lBaseDir := extractfiledir(paramstr(0))+pathdelim; {$ENDIF} //if not DirectoryExists(extractfiledir(lBaseDir)) then //mkDir(extractfiledir(lBaseDir)); if lSubFolder <> '' then begin lBaseDir := lBaseDir + lSubFolder; if not DirectoryExists(lBaseDir) then begin {$I-} MkDir(lBaseDir); if IOResult <> 0 then begin showmessage('Unable to create new folder '+lBaseDir); end; {$I+} end; result := lBaseDir + pathdelim; end else result := lBaseDir; end; *) function Swap2(s : SmallInt): smallint; type swaptype = packed record case byte of 0:(Word1 : word); //word is 16 bit 1:(Small1: SmallInt); end; swaptypep = ^swaptype; var inguy:swaptypep; outguy:swaptype; begin inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word1); result :=outguy.Small1; end; {$IFDEF GUI} procedure ShowMsg(s: string); begin showmessage(s); end; {$ENDIF} procedure fx (a: double); overload; //fx used to help debugging - reports number values begin ShowMsg(floattostr(a)); end; procedure fx (a,b: double); overload; //fx used to help debugging - reports number values begin ShowMsg(floattostr(a)+'x'+floattostr(b)); end; procedure fx (a,b,c: double); overload; //fx used to help debugging - reports number values begin ShowMsg(floattostr(a)+'x'+floattostr(b)+'x'+floattostr(c)); end; procedure fx (a,b,c,d: double); overload; //fx used to help debugging - reports number values begin ShowMsg(floattostr(a)+'x'+floattostr(b)+'x'+floattostr(c)+'x'+floattostr(d)); end; procedure CopyFileEXoverwrite (lInName,lOutName: string); var lFSize: Integer; lBuff: bytep0; lFData: file; begin lFSize := FSize(lInName); if (lFSize < 1) then exit; assignfile(lFdata,lInName); filemode := 0; reset(lFdata,lFSize{1}); GetMem( lBuff, lFSize); BlockRead(lFdata, lBuff^, 1{lFSize}); closefile(lFdata); assignfile(lFdata,lOutName); filemode := 2; Rewrite(lFdata,lFSize); BlockWrite(lFdata,lBuff^, 1 {, NumWritten}); closefile(lFdata); freemem(lBuff); end; procedure CopyFileEX (lInName,lOutName: string); var lFSize: Integer; begin lFSize := FSize(lInName); if (lFSize < 1) or (fileexistsEX(lOutName)) then exit; CopyFileEXoverwrite (lInName,lOutName); end; function IniInt(lIniFile: TIniFile; lIdent: string; lDefault: integer): integer; var lStr: string; begin result := lDefault; lStr := lIniFile.ReadString('INT',lIdent, ''); if length(lStr) > 0 then result := StrToInt(lStr); end; //proc IniInt function IniBool(var lIniFile: TIniFile; lIdent: string; lDefault: boolean): boolean; var lStr: string; begin result := lDefault; lStr := lIniFile.ReadString('BOOL',lIdent, ''); //showmessage('x'+lStr+'x'); if length(lStr) > 0 then result := Char2Bool(lStr[1]); end; //nested IniBool procedure SortInteger(var lLo,lHi: integer); var lSwap: integer; begin if lLo > lHi then begin lSwap := lLo; lLo := lHi; lHi := lSwap; end; //if Lo>Hi end; //proc SortSingle procedure SortSingle(var lLo,lHi: single); var lSwap: single; begin if lLo > lHi then begin lSwap := lLo; lLo := lHi; lHi := lSwap; end; //if Lo>Hi end; //proc SortSingle {$IFDEF FPC} {$IFDEF UNIX} //FPC and Unix function DiskFreeEx (DriveStr: String): Int64; var lOutDisk: Integer; begin lOutDisk := AddDisk(DriveStr); result := DiskFree(lOutDisk); if result < 0 then result := 9223372036854775807; end; {$ELSE} //FPC and Windows function DiskFreeEx (DriveStr: String): Int64; var lOutDisk: Integer; begin lOutDisk := ord(upcase(DriveStr[1]))+1-ord('A'); if (lOutDisk >= 0) and (lOutDisk <= 26) then result := DiskFree(lOutDisk) else result := 0; //showmessage(DriveStr+'->*'+inttostr(lOutDisk)+'* :'+inttostr(result)); //showmessage(inttostr(DiskFree(0){current drive})+' :'+inttostr(DiskFree(3) {C drive})); end; {$ENDIF} {$ELSE} //Delphi Windows function DiskFreeEx (DriveStr: String): Integer; var lOutDisk: Integer; lDiskDir : string; lSize8: Tinteger8; begin lOutDisk := ord(upcase(DriveStr[1]))+1-ord('A'); if (lOutDisk >= ord('A')) and (lOutDisk <= ord('Z')) then begin DiskFreeEx := DiskFree(lOutDisk); end else begin lDiskDir :=(ExtractFileDrive(DriveStr))+'\'; lSize8 := DiskFreeStr (lDiskDir); if lSize8 > MaxINt then DiskFreeEx := MaxInt else DiskFreeEx := round(lSize8); end; end; {$ENDIF} function Log(X, Base: single): single; begin if X = 0 then result := 0 else Log := Ln(X) / Ln(Base); end; function Bool2Char (lBool: boolean): char; begin if lBool then result := '1' else result := '0'; end; function Char2Bool (lChar: char): boolean; begin if lChar = '1' then result := true else result := false; end; procedure Xswap4r ( var s:single); type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit end; swaptypep = ^swaptype; var inguy:swaptypep; outguy:swaptype; begin inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); inguy^.Word1 := outguy.Word1; inguy^.Word2 := outguy.Word2; end; procedure swap4(var s : LongInt); type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(Long:LongInt); end; swaptypep = ^swaptype; var inguy:swaptypep; outguy:swaptype; begin inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); s:=outguy.Long; end; function UpCaseExt(lFileName: string): string; var lI: integer; l2ndExt,lExt : string; begin lExt := ExtractFileExt(lFileName); if length(lExt) > 0 then for lI := 1 to length(lExt) do lExt[lI] := upcase(lExt[lI]); result := lExt; if lExt <> '.GZ' then exit; lI := length(lFileName) - 6; if li < 1 then exit; l2ndExt := upcase(lFileName[lI])+upcase(lFileName[lI+1])+upcase(lFileName[li+2])+upcase(lFileName[li+3]); if (l2ndExt = '.NII')then result := l2ndExt+lExt else if (l2ndExt = 'BRIK') and (lI > 1) and (lFileName[lI-1] = '.') then result := '.BRIK'+lExt; end; function ExtGZ (lFilename: string): boolean; var lI: integer; lExt : string; begin lExt := ExtractFileExt(lFileName); if length(lExt) > 0 then for lI := 1 to length(lExt) do lExt[lI] := upcase(lExt[lI]); if lExt = '.GZ' then result := true else result := false; end; function RealToStr(lR: double {was extended}; lDec: integer): string; begin RealTOStr := FloatToStrF(lR, ffFixed,7,lDec); end; FUNCTION specialdouble (d:double): boolean; //returns true if s is Infinity, NAN or Indeterminate //8byte IEEE: msb[63] = signbit, bits[52-62] exponent, bits[0..51] mantissa //exponent of all 1s = Infinity, NAN or Indeterminate CONST kSpecialExponent = 2047 shl 20; VAR Overlay: ARRAY[1..2] OF LongInt ABSOLUTE d; BEGIN IF ((Overlay[2] AND kSpecialExponent) = kSpecialExponent) THEN RESULT := true ELSE RESULT := false; END; function swap8r(s : double):double; type swaptype = packed record case byte of 0:(Word1,Word2,Word3,Word4 : word); //word is 16 bit 1:(float:double); end; swaptypep = ^swaptype; var inguy:swaptypep; outguy:swaptype; begin inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word4); outguy.Word2 := swap(inguy^.Word3); outguy.Word3 := swap(inguy^.Word2); outguy.Word4 := swap(inguy^.Word1); try result:=outguy.float; except result := 0; exit; end; end; //func swap8r procedure pswap4i(var s : LongInt); type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(Long:LongInt); end; swaptypep = ^swaptype; var inguy:swaptypep; outguy:swaptype; begin inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); s:=outguy.Long; end; //proc swap4 function swap64r(s : double):double; type swaptype = packed record case byte of 0:(Word1,Word2,Word3,Word4 : word); //word is 16 bit 1:(float:double); end; swaptypep = ^swaptype; var inguy:swaptypep; outguy:swaptype; begin inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word4); outguy.Word2 := swap(inguy^.Word3); outguy.Word3 := swap(inguy^.Word2); outguy.Word4 := swap(inguy^.Word1); try swap64r:=outguy.float; except swap64r := 0; exit; end;{} end; procedure pswap4r ( var s:single); type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit end; swaptypep = ^swaptype; var inguy:swaptypep; outguy:swaptype; begin inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); inguy^.Word1 := outguy.Word1; inguy^.Word2 := outguy.Word2; end; //proc Xswap4r function conv4r4i (s:single): longint; type swaptype = packed record case byte of 1:(long:longint); end; swaptypep = ^swaptype; var inguy:swaptypep; begin inguy := @s; //assign address of s to inguy conv4r4i:=inguy^.long; end; function swap4r4i (s:single): longint; type swaptype = packed record case byte of 0:(Word1,Word2 : word); //word is 16 bit 1:(long:longint); end; swaptypep = ^swaptype; var inguy:swaptypep; outguy:swaptype; begin inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word2); outguy.Word2 := swap(inguy^.Word1); swap4r4i:=outguy.long; end;//swap4r4i (*function ChangeFileExtX( var lFilename: string; lExt: string): string; begin result := ChangeFileExt(lFilename,lExt); end; *) function ChangeFileExtX(var lFilename: string; lExt: string): string;// overload; //sees .nii.gz as single extension var lPath,lName,lOrigExt: string; begin if FilenameParts (lFilename, lPath,lName,lOrigExt) then begin //showmessage('12222'+lPath +'**'+lName+'**'+lOrigExt); result := lPath+lName+lExt; end else begin //showmessage('z'); result := ChangeFileExt(lFilename,lExt); end; end; function PadStr (lValIn, lPadLenIn: integer): string; var lOrigLen,lPad : integer; begin lOrigLen := length(inttostr(lValIn)); result := inttostr(lValIn); if lOrigLen < lPadLenIn then begin lOrigLen := lPadLenIn-lOrigLen; for lPad := 1 to lOrigLen do result := '0'+result; end; end; function ExtractFileDirWithPathDelim(lInFilename: string): string; //F:\filename.ext -> 'F:\' and F:\dir\filename.ext -> 'F:\dir\' //Despite documentation, Delphi3's ExtractFileDir does not always retain final pathdelim var lFilePath: string; begin result := ''; if DirExists(lInFilename) then lFilePath := lInFilename else lFilePath := ExtractFileDir(lInFilename); if length(lFilepath) < 1 then exit; if lFilePath[length(lFilepath)] <> pathdelim then lFilepath := lFilepath + pathdelim; //Delphi3 bug: sometimes forgets pathdelim result := lFilepath; end; function ParseFileFinalDir (lFileName:String): string; var lLen,lInc,lPos: integer; lInName,lName: String; begin lInName := extractfiledir(lFilename); lName := ''; lLen := length(lInName); if lLen < 1 then exit; lInc := lLen; repeat dec(lInc); until (lInName[lInc] = pathdelim) or (lInc = 1); if lInName[lInc] = pathdelim then inc(lInc); //if '\folder' then return 'folder' for lPos := lInc to lLen do lName := lName + lInName[lPos]; ParseFileFinalDir := lName; end; function ParseFileName (lFilewExt:String): string; var lExt: string; i: integer; begin lExt := UpCaseExt(lFilewExt); if (length(lExt) < 1) or (length(lExt) >= length(lFilewExt)) then exit; result := ''; for i := 1 to (length(lFilewExt)-length(lExt)) do result := result + lFilewExt[i]; end; (*function ParseFileName (lFilewExt:String): string; var lLen,lInc: integer; lName: String; begin lName := ''; lLen := length(lFilewExt); lInc := lLen+1; if lLen > 0 then begin repeat dec(lInc); until (lFileWExt[lInc] = '.') or (lInc = 1); if (UpCaseExt(lFilewExt) = '.NII.GZ') and (lInc > 1) then repeat dec(lInc); until (lFileWExt[lInc] = '.') or (lInc = 1); end; if lInc > 1 then for lLen := 1 to (lInc - 1) do lName := lName + lFileWExt[lLen] else lName := lFilewExt; //no extension ParseFileName := lName; end; *) Function {TMainForm.}FileExistsEX(Name: String): Boolean; var F: File; begin result := false; if Name = '' then exit; result := FileExists(Name); if result then exit; //the next bit attempts to check for a file to avoid WinNT bug AssignFile(F, Name); {$I-} Reset(F); {$I+} Result:=IOresult = 0; if Result then CloseFile(F); end; function FSize (lFName: String): Int64; var SearchRec: TSearchRec; begin result := 0; if not fileexistsex(lFName) then exit; FindFirst(lFName, faAnyFile, SearchRec); result := SearchRec.size; FindClose(SearchRec); end; procedure Xswap8r(var s : double); type swaptype = packed record case byte of 0:(Word1,Word2,Word3,Word4 : word); //word is 16 bit //1:(float:double); end; swaptypep = ^swaptype; var inguy:swaptypep; outguy:swaptype; begin inguy := @s; //assign address of s to inguy outguy.Word1 := swap(inguy^.Word4); outguy.Word2 := swap(inguy^.Word3); outguy.Word3 := swap(inguy^.Word2); outguy.Word4 := swap(inguy^.Word1); inguy^.Word1 := outguy.Word1; inguy^.Word2 := outguy.Word2; inguy^.Word3 := outguy.Word3; inguy^.Word4 := outguy.Word4; end; FUNCTION specialsingle (var s:single): boolean; //returns true if s is Infinity, NAN or Indeterminate //4byte IEEE: msb[31] = signbit, bits[23-30] exponent, bits[0..22] mantissa //exponent of all 1s = Infinity, NAN or Indeterminate CONST kSpecialExponent = 255 shl 23; VAR Overlay: LongInt ABSOLUTE s; BEGIN IF ((Overlay AND kSpecialExponent) = kSpecialExponent) THEN RESULT := true ELSE RESULT := false; END; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/cpucount.pas������������������������������������������������0000755�0001750�0001750�00000004477�11326425442�020057� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit cpucount; interface //returns number of cores: a computer with two dual cores will report 4 function GetLogicalCpuCount: Integer; implementation {$Include isgui.inc} {$IFDEF UNIX} {$IFDEF Darwin} uses Process,SysUtils,Controls,classes,IniFiles, {$IFDEF GUI}dialogs;{$ELSE} dialogsx;{$ENDIF} function GetLogicalCpuCount: Integer; //returns number of CPUs for MacOSX computer //example - will return 4 if the computer has two dual core CPUs //requires Process in Uses Clause //see http://wiki.lazarus.freepascal.org/Executing_External_Programs var lProcess: TProcess; lLen,lPos: integer; lStr: string; lStringList: TStringList; begin Result := 1; lProcess := TProcess.Create(nil); lStringList := TStringList.Create; lProcess.CommandLine := 'sysctl hw.ncpu'; lProcess.Options := lProcess.Options + [poWaitOnExit, poUsePipes]; lProcess.Execute; lStringList.LoadFromStream(lProcess.Output); lLen := length(lStringList.Text); if lLen > 0 then begin lStr := ''; for lPos := 1 to lLen do if lStringList.Text[lPos] in ['0'..'9'] then lStr := lStr + lStringList.Text[lPos]; if length(lStr) > 0 then result := strtoint(lStr); end;//if at least one character returned if result < 1 then //just incase there is a horrible error, e.g. 0 result := 1; lStringList.Free; lProcess.Free; end; {$ELSE} //Not Darwin ... Assume Linux uses classes,sysutils; function GetLogicalCpuCount: Integer; var lS: TStringList; lFilename: string; lLine,lnLines: integer; begin result := 1; lFilename := '/proc/cpuinfo'; if not fileexists(lFilename) then exit; lS:= TStringList.Create; lS.LoadFromFile(lFilename); lnLines := lS.Count; if lnLines > 0 then begin result := 0; for lLine := 1 to lnLines do if lS[lLine-1] = '' then inc(result); end; if result < 1 then result := 1; lS.Free; end; {$ENDIF} //If Darwin Else Linux {$ELSE} //If UNIX ELSE NOT Unix uses Windows; function GetLogicalCpuCount: Integer; var SystemInfo: _SYSTEM_INFO; begin GetSystemInfo(SystemInfo); Result := SystemInfo.dwNumberOfProcessors; end; {$ENDIF} end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/nifti_types.pas���������������������������������������������0000755�0001750�0001750�00000013515�12310315262�020535� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit nifti_types; {$IFDEF FPC} {$mode objfpc}{$ENDIF}{$H+} interface uses Classes, SysUtils, define_types; type TNIFTIhdr = packed record //Next: analyze Format Header structure HdrSz : longint; //MUST BE 348 Data_Type: array [1..10] of ansichar; //unused db_name: array [1..18] of ansichar; //unused extents: longint; //unused session_error: smallint; //unused regular: ansichar; ////unused: in Analyze 7.5 this must be 114 dim_info: byte; //MRI slice order dim: array[0..7] of smallint; //Data array dimensions intent_p1, intent_p2, intent_p3: single; intent_code: smallint; datatype: smallint; bitpix: smallint; slice_start: smallint; pixdim: array[0..7]of single; vox_offset: single; scl_slope: single;//scaling slope scl_inter: single;//scaling intercept slice_end: smallint; slice_code: byte; //e.g. ascending xyzt_units: byte; //e.g. mm and sec cal_max,cal_min: single; //unused slice_duration: single; //time for one slice toffset: single; //time axis to shift glmax, glmin: longint; //UNUSED descrip: array[1..80] of ansichar; aux_file: array[1..24] of ansichar; qform_code, sform_code: smallint; quatern_b,quatern_c,quatern_d, qoffset_x,qoffset_y,qoffset_z: single; srow_x: array[0..3]of single; srow_y: array[0..3]of single; srow_z: array[0..3]of single; intent_name: array[1..16] of ansichar; magic: longint; end; //TNIFTIhdr Header Structure TAnalyzeHdrSection = packed record //Next: analyze Format Header structure Pad: array [1..253] of byte; originator: array [1..5] of smallint; (* 105 + 10 *) end;//TAnalyzeHdrSection Structure const K_gzBytes_headerAndImageCompressed = -2; K_gzBytes_onlyImageCompressed= -1; K_gzBytes_headerAndImageUncompressed= 0; //DataTypes kDT_BINARY =1; // binary (1 bit/voxel) kDT_UNSIGNED_CHAR =2; // unsigned char (8 bits/voxel) kDT_UINT8 = kDT_UNSIGNED_CHAR; kDT_SIGNED_SHORT =4; // signed short (16 bits/voxel) kDT_INT16 = kDT_SIGNED_SHORT; kDT_SIGNED_INT =8; // signed int (32 bits/voxel) kDT_INT32 = kDT_SIGNED_INT; kDT_FLOAT =16; // float (32 bits/voxel) kDT_FLOAT32 = kDT_FLOAT; kDT_COMPLEX =32; // complex (64 bits/voxel) kDT_DOUBLE =64; // double (64 bits/voxel) kDT_RGB =128; // RGB triple (24 bits/voxel) kDT_INT8 =256; // signed char (8 bits) kDT_UINT16 =512; // unsigned short (16 bits) kDT_UINT32 =768; // unsigned int (32 bits) kDT_INT64 =1024; // long long (64 bits) kDT_UINT64 =1280; // unsigned long long (64 bits) kDT_FLOAT128 =1536; // long double (128 bits) kDT_COMPLEX128 =1792; // double pair (128 bits) kDT_COMPLEX256 =2048; // long double pair (256 bits) // slice_code values kNIFTI_SLICE_SEQ_UNKNOWN = 0; kNIFTI_SLICE_SEQ_INC = 1; kNIFTI_SLICE_SEQ_DEC = 2; kNIFTI_SLICE_ALT_INC = 3; kNIFTI_SLICE_ALT_DEC = 4; kNIFTI_SLICE_ALT_INC2 = 5; // 05 May 2005: RWCox kNIFTI_SLICE_ALT_DEC2 = 6; // 05 May 2005: RWCox kSliceOrderStr: array [kNIFTI_SLICE_SEQ_UNKNOWN..kNIFTI_SLICE_ALT_DEC2] of string = ('UNKNOWN','ascending','descending' , 'interleaved ascending (1,3..,2,4...)', 'interleaved ascending (N,N-2...N-1,N-3...)' , 'Siemens-even interleaved ascending (2,4..,1,3...)', 'Siemens-even interleaved ascending (N-1,N-3...N,N-2...)' ); //xyzt_units values: note 3bit space and 3bit time packed into single byte kNIFTI_UNITS_UNKNOWN = 0; kNIFTI_UNITS_METER = 1; kNIFTI_UNITS_MM = 2; kNIFTI_UNITS_MICRON = 3; kNIFTI_UNITS_SEC = 8; kNIFTI_UNITS_MSEC = 16; kNIFTI_UNITS_USEC = 24; kNIFTI_UNITS_HZ = 32; kNIFTI_UNITS_PPM = 40; //qform_code, sform_code values kNIFTI_XFORM_UNKNOWN = 0; kNIFTI_XFORM_SCANNER_ANAT = 1;//Scanner-based anatomical coordinates kNIFTI_XFORM_ALIGNED_ANAT = 2; //Coordinates aligned to another file e.g. EPI coregistered to T1 kNIFTI_XFORM_TALAIRACH = 3; //Talairach-Tournoux Atlas; (0,0,0)=AC, etc. kNIFTI_XFORM_MNI_152 = 4; //MNI 152 normalized coordinates {$IFDEF ENDIAN_BIG} //Magic values kswapNIFTI_MAGIC_SEPARATE_HDR = $0031696E;//$6E693100; kswapNIFTI_MAGIC_EMBEDDED_HDR = $00312B6E;//$6E2B3100; kNIFTI_MAGIC_DCM = $0044434D;//DCM //byte-swapped magic values kNIFTI_MAGIC_SEPARATE_HDR = $6E693100; kNIFTI_MAGIC_EMBEDDED_HDR = $6E2B3100; {$ELSE} //Magic values kNIFTI_MAGIC_SEPARATE_HDR = $0031696E;//$6E693100; kNIFTI_MAGIC_EMBEDDED_HDR = $00312B6E;//$6E2B3100; kNIFTI_MAGIC_DCM = $0044434D;//DCM //byte-swapped magic values kswapNIFTI_MAGIC_SEPARATE_HDR = $6E693100; kswapNIFTI_MAGIC_EMBEDDED_HDR = $6E2B3100; {$ENDIF} //Statistics Intention kNIFTI_INTENT_NONE =0; kNIFTI_INTENT_CORREL =2; kNIFTI_INTENT_TTEST =3; kNIFTI_INTENT_FTEST =4; kNIFTI_INTENT_ZSCORE =5; kNIFTI_INTENT_CHISQ =6; kNIFTI_INTENT_BETA =7; kNIFTI_INTENT_BINOM =8; kNIFTI_INTENT_GAMMA =9; kNIFTI_INTENT_POISSON =10; kNIFTI_INTENT_NORMAL =11; kNIFTI_INTENT_FTEST_NONC =12; kNIFTI_INTENT_CHISQ_NONC =13; kNIFTI_INTENT_LOGISTIC =14; kNIFTI_INTENT_LAPLACE =15; kNIFTI_INTENT_UNIFORM =16; kNIFTI_INTENT_TTEST_NONC =17; kNIFTI_INTENT_WEIBULL =18; kNIFTI_INTENT_CHI =19; kNIFTI_INTENT_INVGAUSS =20; kNIFTI_INTENT_EXTVAL =21; kNIFTI_INTENT_PVAL =22; NIFTI_INTENT_LOGPVAL =23; NIFTI_INTENT_LOG10PVAL =24; kNIFTI_LAST_STATCODE = 24;//kNIFTI_INTENT_PVAL; kNIFTI_INTENT_ESTIMATE =1001; kNIFTI_FIRST_NONSTATCODE = kNIFTI_INTENT_ESTIMATE; kNIFTI_INTENT_LABEL =1002; kNIFTI_INTENT_NEURONAME =1003; kNIFTI_INTENT_GENMATRIX =1004; kNIFTI_INTENT_SYMMATRIX =1005; kNIFTI_INTENT_DISPVECT =1006; kNIFTI_INTENT_VECTOR =1007; kNIFTI_INTENT_POINTSET =1008; kNIFTI_INTENT_TRIANGLE =1009; kNIFTI_INTENT_QUATERNION =1010; implementation end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/isgui.inc���������������������������������������������������0000755�0001750�0001750�00000000154�11542422214�017303� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{$DEFINE GUI} //use GUI if you are using a graphic user interface - anything else for console applications ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/gzio2.pas���������������������������������������������������0000755�0001750�0001750�00000164103�12306611716�017242� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Unit gzio2; { Pascal unit based on gzio.c -- IO on .gz files Copyright (C) 1995-1998 Jean-loup Gailly. Define NO_DEFLATE to compile this file without the compression code Pascal tranlastion based on code contributed by Francisco Javier Crespo Copyright (C) 1998 by Jacques Nomssi Nzali For conditions of distribution and use, see copyright notice in readme.txt } {$H+} {$mode Delphi} interface {$I zconf.inc} uses {$ifdef UNIX} baseunix, {$else} dos, {$endif} sysutils,zbase, crc, zdeflate, zinflate,define_types; type gzFile = pointer; type z_off_t = longint; function Gunzip (var FFileSource,FFileDestination: string): integer; procedure GZipBuffer(var FGzipFilename,FFileDestination: String;lxInBuffer: byteP;lInSize: Integer; lOverwritewarn: boolean);overload; procedure GZipBuffer(var FFileDestination: String;lxInBuffer: byteP;lInSize: Integer; lOverwritewarn: boolean);overload; procedure UnGZip (var lInFname: string; var lBuf: ByteP; lOffset,lMaxSz: int64); //unzip procedure UnGZip2 (var lInFname: string; var lBuf: ByteP; lOffset,lMaxSz,Skip: int64); //unzip after skipping a few bytes procedure UnGZipCore (var infile : gzFile; var lBuf: ByteP; lReadBytes: integer; lWrite: boolean); procedure UnGZipFile (var lFname,lOUtname: string); //unzip function gzopen (path:string; mode:string) : gzFile; overload; function gzopen (path:string; mode:string; skip: integer) : gzFile; overload; function gzread (f:gzFile; buf:pointer; len:cardinal) : integer; function gzgetc (f:gzfile) : integer; function gzgets (f:gzfile; buf:Pchar; len:integer) : Pchar; procedure GZipFile(lSrcName,lDestName: String); overload; procedure GZipFile(lSrcName,lDestName: String;lDeleteSrc: boolean);overload; {$ifndef NO_DEFLATE} function gzwrite (f:gzFile; buf:pointer; len:cardinal) : integer; function gzputc (f:gzfile; c:char) : integer; function gzputs (f:gzfile; s:Pchar) : integer; function gzflush (f:gzFile; flush:integer) : integer; {$ifdef GZ_FORMAT_STRING} function gzprintf (zfile : gzFile; const format : string; a : array of integer); { doesn't compile } {$endif} {$endif} function gzseek (f:gzfile; offset:z_off_t; whence:integer) : z_off_t; function gztell (f:gzfile) : z_off_t; function gzclose (f:gzFile) : integer; function gzerror (f:gzFile; var errnum:smallint) : string; function gzsetparams (f:gzfile; level:integer; strategy:integer) : integer; function gzrewind (f:gzFile) : integer; function gzeof (f:gzfile) : boolean; const SEEK_SET {: z_off_t} = 0; { seek from beginning of file } SEEK_CUR {: z_off_t} = 1; { seek from current position } SEEK_END {: z_off_t} = 2; implementation {$include isgui.inc} uses dialogsx;//{$IFDEF GUI}uses dialogs;{$ELSE} uses dialogsx;{$ENDIF} const Z_EOF = -1; { same value as in STDIO.H } Z_BUFSIZE = 16384; { Z_PRINTF_BUFSIZE = 4096; } gz_magic : array[0..1] of byte = ($1F, $8B); { gzip magic header } { gzip flag byte } //ASCII_FLAG = $01; { bit 0 set: file probably ascii text } HEAD_CRC = $02; { bit 1 set: header CRC present } EXTRA_FIELD = $04; { bit 2 set: extra field present } ORIG_NAME = $08; { bit 3 set: original file name present } COMMENT = $10; { bit 4 set: file comment present } RESERVED = $E0; { bits 5..7: reserved } type gz_stream = record stream : z_stream; z_err : integer; { error code for last stream operation } z_eof : boolean; { set if end of input file } gzfile : file; { .gz file } inbuf : Pbyte; { input buffer } outbuf : Pbyte; { output buffer } crc : cardinal; { crc32 of uncompressed data } //msg, zpath : string[255];//6666666666666666 { path name for debugging only - limit 79 chars } transparent : boolean; { true if input file is not a .gz file } mode : char; { 'w' or 'r' } startpos : longint; { start of compressed data in file (header skipped) } end; type gz_streamp = ^gz_stream; function zdestroy (var s:gz_streamp) : integer; forward; procedure check_header(s:gz_streamp); forward; procedure UnGZip2 (var lInFname: string; var lBuf: ByteP; lOffset,lMaxSz,Skip: int64); //unzip const BUFLEN = 16384; var infile : gzFile; lFname : ansistring; lbufsz,len,lI,written : int64; buf : packed array [0..BUFLEN-1] of byte; { Global uses BSS instead of stack } begin lFName := lInFName; infile := gzopen (lFName, 'r',Skip); written := 0; if lOffset > 0 then begin Len := lOffset div BUFLEN; if Len > 0 then begin lI := 1; while (lI <= Len) do begin gzread (infile, @buf, BUFLEN {1388}); inc(lI); end; end; Len := lOffset mod BUFLEN; gzread (infile, @buf, Len); end; lbufsz := BUFLEN; if lMaxSz < BUFLEN then lbufsz := lMaxSz; while true do begin len := gzread (infile, @buf, lbufsz); if (len < 0) then begin break end; if (len = 0) then break; if (Written+len) > lMaxSz then begin if Written < lMaxSz then Move(buf,lbuf^[Written+1],lMaxSz-Written); //cr2007 break; end; Move(buf,lbuf^[Written+1],len); Written := Written + len; end; {WHILE} gzclose (infile); //filemode := 2; end; procedure UnGZip (var lInFname: string; var lBuf: ByteP; lOffset,lMaxSz: int64); begin UnGZip2 ( lInFname, lBuf, lOffset,lMaxSz,0); end; (*procedure UnGZip (var lInFname: string; var lBuf: ByteP; lOffset,lMaxSz: int64); //unzip const BUFLEN = 16384; var infile : gzFile; lFname : ansistring; lI,len ,written, lbufsz : int64; buf : packed array [0..BUFLEN-1] of byte; { Global uses BSS instead of stack } begin lFName := lInFName; //filemode := 1; //if lFName = 'z' then //showmessage('unzip'); //ImgForm.Caption := 'gz'; //ReadIntForm.GetInt('Multi-volume file, please select volume to view.',1,1,3); //infile := gzopenZ (lFName, 'r', 0); //showmessage(lFName); infile := gzopen (lFName, 'r'); written := 0; if lOffset > 0 then begin Len := lOffset div BUFLEN; if Len > 0 then begin lI := 1; while (lI <= Len) do begin gzread (infile, @buf, BUFLEN {1388}); inc(lI); end; //for lI := 1 to Len do // gzread (infile, @buf, BUFLEN {1388}); end; Len := lOffset mod BUFLEN; gzread (infile, @buf, Len); end; lbufsz := BUFLEN; if lMaxSz < BUFLEN then lbufsz := lMaxSz; while true do begin len := gzread (infile, @buf, lbufsz); if (len < 0) then begin break end; if (len = 0) then break; if (Written+len) > lMaxSz then begin if Written < lMaxSz then Move(buf,lbuf^[Written+1],lMaxSz-Written); //cr2007 break; end; Move(buf,lbuf^[Written+1],len); Written := Written + len; end; {WHILE} gzclose (infile); //filemode := 2; end; *) procedure UnGZipCore (var infile : gzFile; var lBuf: ByteP; lReadBytes: integer; lWrite: boolean); const BUFLEN = 16384; var buf : packed array [0..BUFLEN-1] of byte; { Global uses BSS instead of stack } len,lI,written : integer; begin written := 0; if lReadBytes < 1 then exit; Len := lReadBytes div BUFLEN; if Len > 0 then for lI := 1 to Len do begin gzread (infile, @buf, BUFLEN {1388}); if lWrite then Move(buf,lbuf[Written+1],BUFLEN); Written := Written + BUFLEN; end; Len := lReadBytes mod BUFLEN; if Len = 0 then exit; gzread (infile, @buf, Len); if lWrite then Move(buf,lbuf[Written+1],len); end; //ungzipCore procedure UnGZipFile (var lFname,lOUtname: string); //unzip const bufsz = 16384; var infile : gzFile; len,lI : integer; //written : integer; lF: File; buf : packed array [0..bufsz-1] of byte; { Global uses BSS instead of stack } begin //infile := gzopenZ (lFName, 'r', 0); infile := gzopen (lFName, 'r'); //written := 0; //lbufsz := BUFLEN; Filemode := 1; AssignFile(lF, lOUtname); Rewrite(lF,1); while true do begin len := gzread (infile, @buf, bufsz); if (len < 0) then begin break end; if (len = 0) then break; BlockWrite(lF,buf, len); //Move(buf,lbuf[Written+1],len); //Written := Written + len; end; {WHILE} gzclose (infile); CloseFile(lF); Filemode := 2; //1366 end; function gz_compress (var infile:file; outfile:gzFile): integer; var len : cardinal; ioerr : integer; buf : packed array [0..Z_BUFSIZE-1] of byte; { Global uses BSS instead of stack } errorcode : byte; fsize, lensize : DWord; begin errorcode := 0; //Progress := 0; fsize := FileSize(infile); lensize := 0; //if FProgressStep > 0 then DoOnProgress; while true do begin {$I-}blockread (infile, buf, Z_BUFSIZE, len);{$I+} ioerr := IOResult; if (ioerr <> 0) then begin errorcode := 1; break end; if (len = 0) then break; {$WARNINGS OFF}{Comparing signed and unsigned types} if (gzwrite (outfile, @buf, len) <> len) then begin {$WARNINGS OFF} errorcode := 2; break end; end; closeFile (infile); if (gzclose (outfile) <> 0{Z_OK}) then errorcode := 3; gz_compress := errorcode; end; // proc gz_compress procedure GZipFile(lSrcName,lDestName: String; lDeleteSrc: boolean); overload; var infile : file; outfile : gzFile; ioerr : integer; mode : string; begin //Msg('GZip ' + extractfilename(lSrcName)); //writeln(lSrcName+' -> GZ -> '+lDestName); mode := 'w6 '; Assign (infile, lSrcName); {$I-} Reset (infile,1); {$I+} ioerr := IOResult; if (ioerr <> 0) then begin ShowMsg ('GZipFile error: '+inttostr(ioerr)); halt(1); end; outfile := gzopen (lDestName, mode); if (outfile = NIL) then begin ShowMsg('unable to create '+lDestName); exit; end; gz_compress(infile, outfile); if lDeleteSrc then erase (infile); end; procedure GZipFile(lSrcName,lDestName: String); overload; var FGzipFilename : string; FGzipComments : string; outmode : string; s,FFileDestination : string; infile : file; outfile : gzFile; FCompressionLevel{,errorcode} : integer; flags : Integer; stream : gz_streamp; //p : PChar; ioerr : integer; begin //FGzipHeader := [zFilename]; FGzipFilename:= lSrcName; FGzipComments := ''; FCompressionLevel := 6; //MainForm.ProgressBar1.position :=1; //Gzip (lFile,lMulti); FFileDestination := lDestName; //result := 2; //return error if user aborts (* if fileexists(FFileDestination) then begin case MessageDlg('Overwrite the file '+FFileDestination+'?', mtConfirmation,[mbYes, mbAbort], 0) of { produce the message dialog box } mrAbort: exit; end; end;*) AssignFile (infile, lSrcName); {$I-} Reset (infile,1); {$I+} ioerr := IOResult; if (ioerr <> 0) then begin // Showmessage('Can''t open: '+lSrcName); //errorcode := 1 end else begin outmode := 'w '; //s := IntToStr(FCompressionLevel); outmode[2] := '6';//s[1]; outmode[3] := ' '; (*case FCompressionType of Standard : outmode[3] := ' '; HuffmanOnly : outmode[3] := 'h'; Filtered : outmode[3] := 'f'; end;*) //flags := 0; //if (zfilename in FGzipHeader) then flags := ORIG_NAME; //if (comment in FGzipHeader) then flags := flags + COMMENT_; outfile := gzopen (lSrcName, outmode); if (outfile = NIL) then begin //Showmessage('Can''t open: '+lSrcName); close( infile); exit; end else begin { if flags are set then write them } stream := gz_streamp(outfile); if {(zfilename in FGzipHeader)} true then begin s := lSrcName;//999 ExtractFilename(lSrcName); //p := PChar(s); blockWrite( stream^.gzfile, {p[0]}s, length(s)+1); stream^.startpos := stream^.startpos + length(s) + 1 end; gz_compress(infile, outfile); end end; end; procedure file_compress2 (filename,outname:string); var infile : file; outfile : gzFile; ioerr : integer; mode : string; begin mode := 'w6 '; Assign (infile, filename); {$I-} Reset (infile,1); {$I+} ioerr := IOResult; if (ioerr <> 0) then begin writeln ('open error: ',ioerr); halt(1); end; outfile := gzopen (outname, mode); if (outfile = NIL) then begin //999 showmessage(' can''t gzopen '+outname); halt(1); end; gz_compress(infile, outfile); erase (infile); end; (*function gz_compressBuffer (lxInBuffer: ByteP;lInSize: integer;outfile:gzFile): integer; var len : Integer; lInBufferPos,ioerr : integer; buf : packed array [0..Z_BUFSIZE-1] of byte; { Global uses BSS instead of stack } //lInBufPtr,lOutbufPtr: pointer; errorcode : byte; //fsize, lensize : DWord; function blocktransfer(var lInBuffer: ByteP; lSizeRequested: integer; var lSizeTransferred:integer): integer; begin result := 0; if lInBufferPos > lInSize then begin result := 666; exit; end else if (lInBufferPos + lSizeRequested) <= lInSize then lSizeTransferred := lSizeRequested else lSizeTransferred := lInSize-lInBufferPos; //for lC := 1 to lSizeTransferred do // buf[lC-1] := lInBuffer[lInBufferPos+lC] ; move(lInbuffer[lInBufferPos+1],buf,lSizeTransferred); //move(src,dest,count); lInBufferPos := lInBufferPos+lSizeTransferred; end; begin lInBufferPos := 0; errorcode := 0; //Progress := 0; //fsize := lInSize; //lensize := 0; //if FProgressStep > 0 then DoOnProgress; while true do begin //lll{$I-}blockread (infile, buf, Z_BUFSIZE, len);{$I+} ioerr := blocktransfer(lxInBuffer,Z_BUFSIZE, len); if (ioerr <> 0) then begin errorcode := 1; break end; if (len = 0) then break; {$WARNINGS OFF}{Comparing signed and unsigned types} if (gzwrite (outfile, @buf, len) <> len) then begin {$WARNINGS OFF} errorcode := 2; break end; end; {WHILE} if (gzclose (outfile) <> 0{Z_OK}) then errorcode := 3; result := errorcode; end; procedure GZipBuffer(var FGzipFilename,FFileDestination: String;lxInBuffer: byteP;lInSize: Integer; lOverwritewarn: boolean); var FGzipComments ,outmode,s : string; infile : file; outfile : gzFile; FCompressionLevel : integer; flags : uInt; stream : gz_streamp; p : PChar; begin FGzipComments := ''; FCompressionLevel := 6; if (FCompressionLevel > 9) or (FCompressionLevel<0) then FCompressionLevel := 6; if lOverwritewarn and fileexists(FFileDestination) then begin case MessageDlg('Overwrite the file '+FFileDestination+'?', mtConfirmation,[mbYes, mbAbort], 0) of { produce the message dialog box } mrAbort: exit; end; end; //w adds .gz extension-> outmode := 'w '; outmode := 'w '; s := IntToStr(FCompressionLevel); outmode[2] := s[1]; outmode[3] := ' '; flags := ORIG_NAME; outfile := gzopenZ (FFileDestination, outmode, flags); if (outfile = NIL) then begin MessageDlg('Can''t open: '+FFileDestination, mtError, [mbAbort], 0); close( infile); exit; end else begin stream := gz_streamp(outfile); if {(zfilename in FGzipHeader)} true then begin //s := ExtractFilename(lInFileName); s := ExtractFilename(FGzipFilename); //p := PChar(s); blockWrite( stream^.gzfile,s , length(s)+1); stream^.startpos := stream^.startpos + length(s) + 1 end; gz_compressBuffer (lxInBuffer,lInSize,outfile); end end; *) { GZOPEN ==================================================================== Opens a gzip (.gz) file for reading or writing. As Pascal does not use file descriptors, the code has been changed to accept only path names. The mode parameter defaults to BINARY read or write operations ('r' or 'w') but can also include a compression level ('w9') or a strategy: Z_FILTERED as in 'w6f' or Z_HUFFMAN_ONLY as in 'w1h'. (See the description of deflateInit2 for more information about the strategy parameter.) gzopen can be used to open a file which is not in gzip format; in this case, gzread will directly read from the file without decompression. gzopen returns NIL if the file could not be opened (non-zero IOResult) or if there was insufficient memory to allocate the (de)compression state (zlib error is Z_MEM_ERROR). ============================================================================} (*function gzopenZ(sourceFilename:string; mode:string; flags:uInt) : gzFile; var i : uInt; err: int; level: int; strategy : int; { compression strategy } s : gz_streamp; path: string; {$IFDEF MSDOS} attr : word; { file attributes } {$ENDIF} {$IFNDEF NO_DEFLATE} gzheader : array [0..9] of byte; {$ENDIF} begin //wait(30); path := sourceFilename; GetMem (s,sizeof(gz_stream)); if not Assigned (s) then begin result := Z_NULL; exit; end; if (path='') then begin //999 Showmessage('Error with path'); result := Z_NULL; exit; end; //showmessage('gzOpenCompleted'); level := Z_DEFAULT_COMPRESSION; strategy := Z_DEFAULT_STRATEGY; s^.stream.zalloc := NIL; { (alloc_func)0 } s^.stream.zfree := NIL; { (free_func)0 } s^.stream.opaque := NIL; { (voidpf)0 } s^.stream.next_in := Z_NULL; s^.stream.next_out := Z_NULL; s^.stream.avail_in := 0; s^.stream.avail_out := 0; s^.z_err := Z_OK; s^.z_eof := false; s^.inbuf := Z_NULL; s^.outbuf := Z_NULL; s^.crc := crc32(0, Z_NULL, 0); s^.msg := ''; s^.transparent := false; s^.mode := chr(0); for i:=1 to Length(mode) do begin case mode[i] of 'r' : s^.mode := 'r'; 'w' : s^.mode := 'w'; '0'..'9' : level := Ord(mode[i])-Ord('0'); 'f' : strategy := Z_FILTERED; 'h' : strategy := Z_HUFFMAN_ONLY; end; end; //if (s^.mode='w') then begin path := path+'.gz'; end; s^.path := path; { limit to 255 chars } if (s^.mode=chr(0)) then begin zdestroyS(s); result := gzFile(Z_NULL); exit; end; if (s^.mode='w') then begin {$IFDEF NO_DEFLATE} err := Z_STREAM_ERROR; {$ELSE} err := deflateInit2 (s^.stream, level, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); { windowBits is passed < 0 to suppress zlib header } GetMem (s^.outbuf, Z_BUFSIZE); s^.stream.next_out := s^.outbuf; {$ENDIF} if (err <> Z_OK) or (s^.outbuf = Z_NULL) then begin zdestroyS(s); result := gzFile(Z_NULL); exit; end; end else begin GetMem (s^.inbuf, Z_BUFSIZE); s^.stream.next_in := s^.inbuf; err := inflateInit2_ (s^.stream, -MAX_WBITS, ZLIB_VERSION, sizeof(z_stream)); { windowBits is passed < 0 to tell that there is no zlib header } if (err <> Z_OK) or (s^.inbuf = Z_NULL) then begin zdestroyS(s); result := gzFile(Z_NULL); exit; end; end; s^.stream.avail_out := Z_BUFSIZE; {$IFOPT I+} {$I-} {$define IOcheck} {$ENDIF} Assign (s^.gzfile, path {10/10/2006 s^.path}); //Assign (s^.gzfile, s^.path); {$ifdef MSDOS} GetFAttr(s^.gzfile, Attr); if (DosError <> 0) and (s^.mode='w') then ReWrite (s^.gzfile,1) else Reset (s^.gzfile,1); {$else} if {(not FileExists(s^.path)) and} (s^.mode='w') then // Vincent: changed IF because I don't want old data behind my // new made .gz-file ReWrite (s^.gzfile,1) else Reset (s^.gzfile,1); {$endif} {$IFDEF IOCheck} {$I+} {$ENDIF} if (IOResult <> 0) then begin zdestroyS(s); result := gzFile(Z_NULL); exit; end; if (s^.mode = 'w') then begin { Write a very simple .gz header } {$IFNDEF NO_DEFLATE} gzheader [0] := gz_magic [0]; gzheader [1] := gz_magic [1]; gzheader [2] := Z_DEFLATED; { method } gzheader [3] := flags; { flags } gzheader [4] := 0; { time[0] } gzheader [5] := 0; { time[1] } gzheader [6] := 0; { time[2] } gzheader [7] := 0; { time[3] } gzheader [8] := 0; { xflags } gzheader [9] := 0; { OS code = MS-DOS } blockwrite (s^.gzfile, gzheader, 10); s^.startpos := LONG(10); {$ENDIF} end else begin check_header(s); { skip the .gz header } {$WARNINGS OFF} { combining signed and unsigned types } s^.startpos := FilePos(s^.gzfile) - s^.stream.avail_in; {$WARNINGS ON} end; result := gzFile(s); end;//gzopenZ *) (*function StringMaxLen (var lInStr: ansistring; lMaxSz: integer): ansistring; var lPos: integer; begin //note: strings shortened to lMaxSz-1 //null termination requires one byte //e.g. size of 80 bytes can become a null terminated string with up to 79 characters if length(lInStr) >= lMaxSz then begin//crop string result := ''; for lPos := 1 to (lMaxSz-1) do result := result + lInStr[lPos]; end else result := lInStr; end; *) { GZOPEN ==================================================================== Opens a gzip (.gz) file for reading or writing. As Pascal does not use file descriptors, the code has been changed to accept only path names. The mode parameter defaults to BINARY read or write operations ('r' or 'w') but can also include a compression level ('w9') or a strategy: Z_FILTERED as in 'w6f' or Z_HUFFMAN_ONLY as in 'w1h'. (See the description of deflateInit2 for more information about the strategy parameter.) gzopen can be used to open a file which is not in gzip format; in this case, gzread will directly read from the file without decompression. gzopen returns nil if the file could not be opened (non-zero IOResult) or if there was insufficient memory to allocate the (de)compression state (zlib error is Z_MEM_ERROR). ============================================================================} function gzopen (path:string; mode:string; skip: integer) : gzFile; var i : cardinal; err : integer; level : integer; { compression level } strategy : integer; { compression strategy } s : gz_streamp; {$ifdef UNIX} info: stat; {$else} attr: word; {$endif} {$IFNDEF NO_DEFLATE} gzheader : array [0..9] of byte; {$ENDIF} begin if (path='') or (mode='') then begin gzopen := nil; exit; end; GetMem (s,sizeof(gz_stream)); if not Assigned (s) then begin gzopen := nil; exit; end; level := Z_DEFAULT_COMPRESSION; strategy := Z_DEFAULT_STRATEGY; s^.stream.next_in := nil; s^.stream.next_out := nil; s^.stream.avail_in := 0; s^.stream.avail_out := 0; s^.z_err := Z_OK; s^.z_eof := false; s^.inbuf := nil; s^.outbuf := nil; s^.crc := crc32(0, nil, 0); //s^.msg := ''; s^.transparent := false; s^.zpath := path; { limit to 255 chars } s^.mode := chr(0); for i:=1 to Length(mode) do begin case mode[i] of 'r' : s^.mode := 'r'; 'w' : s^.mode := 'w'; '0'..'9' : level := Ord(mode[i])-Ord('0'); 'f' : strategy := Z_FILTERED; 'h' : strategy := Z_HUFFMAN_ONLY; end; end; if (s^.mode=chr(0)) then begin zdestroy(s); gzopen := gzFile(nil); exit; end; if (s^.mode='w') then begin {$IFDEF NO_DEFLATE} err := Z_STREAM_ERROR; {$ELSE} err := deflateInit2 (s^.stream, level, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); { windowBits is passed < 0 to suppress zlib header } GetMem (s^.outbuf, Z_BUFSIZE); s^.stream.next_out := s^.outbuf; {$ENDIF} if (err <> Z_OK) or (s^.outbuf = nil) then begin zdestroy(s); gzopen := gzFile(nil); exit; end; end else begin GetMem (s^.inbuf, Z_BUFSIZE); s^.stream.next_in := s^.inbuf; err := inflateInit2_ (s^.stream, -MAX_WBITS, ZLIB_VERSION, sizeof(z_stream)); { windowBits is passed < 0 to tell that there is no zlib header } if (err <> Z_OK) or (s^.inbuf = nil) then begin zdestroy(s); gzopen := gzFile(nil); exit; end; end; s^.stream.avail_out := Z_BUFSIZE; //showmessage(s^.path+' '+inttostr(length(path))); {$IFOPT I+} {$I-} {$define IOcheck} {$ENDIF} //11/11/07 Assign (s^.gzfile, s^.path); Assign (s^.gzfile, path); {$ifdef unix} if (fpstat(s^.zpath,info)<0) and (s^.mode='w') then ReWrite (s^.gzfile,1) else begin Reset (s^.gzfile,1); if skip > 0 then Seek(s^.gzfile,skip); end; {$else} GetFAttr(s^.gzfile, Attr); if (DosError <> 0) and (s^.mode='w') then ReWrite (s^.gzfile,1) else begin Reset (s^.gzfile,1); if skip > 0 then Seek(s^.gzfile,skip); end; {$endif} {$IFDEF IOCheck} {$I+} {$ENDIF} if (IOResult <> 0) then begin zdestroy(s); gzopen := gzFile(nil); exit; end; if (s^.mode = 'w') then begin { Write a very simple .gz header } {$IFNDEF NO_DEFLATE} gzheader [0] := gz_magic [0]; gzheader [1] := gz_magic [1]; gzheader [2] := Z_DEFLATED; { method } gzheader [3] := 0; { flags } gzheader [4] := 0; { time[0] } gzheader [5] := 0; { time[1] } gzheader [6] := 0; { time[2] } gzheader [7] := 0; { time[3] } gzheader [8] := 0; { xflags } gzheader [9] := 0; { OS code = MS-DOS } blockwrite (s^.gzfile, gzheader, 10); s^.startpos := longint(10); {$ENDIF} end else begin check_header(s); { skip the .gz header } s^.startpos := FilePos(s^.gzfile) - s^.stream.avail_in; end; gzopen := gzFile(s); end; function gzopen (path:string; mode:string) : gzFile; begin result := gzopen(path,mode,0); end; (*2015 function gzopen (path:string; mode:string) : gzFile; var i : cardinal; err : integer; level : integer; { compression level } strategy : integer; { compression strategy } s : gz_streamp; {$ifdef UNIX} info: stat; {$else} attr: word; {$endif} {$IFNDEF NO_DEFLATE} gzheader : array [0..9] of byte; {$ENDIF} begin if (path='') or (mode='') then begin gzopen := nil; exit; end; GetMem (s,sizeof(gz_stream)); if not Assigned (s) then begin gzopen := nil; exit; end; level := Z_DEFAULT_COMPRESSION; strategy := Z_DEFAULT_STRATEGY; s^.stream.next_in := nil; s^.stream.next_out := nil; s^.stream.avail_in := 0; s^.stream.avail_out := 0; s^.z_err := Z_OK; s^.z_eof := false; s^.inbuf := nil; s^.outbuf := nil; s^.crc := crc32(0, nil, 0); //s^.msg := ''; s^.transparent := false; s^.zpath := path; { limit to 255 chars } s^.mode := chr(0); for i:=1 to Length(mode) do begin case mode[i] of 'r' : s^.mode := 'r'; 'w' : s^.mode := 'w'; '0'..'9' : level := Ord(mode[i])-Ord('0'); 'f' : strategy := Z_FILTERED; 'h' : strategy := Z_HUFFMAN_ONLY; end; end; if (s^.mode=chr(0)) then begin zdestroy(s); gzopen := gzFile(nil); exit; end; if (s^.mode='w') then begin {$IFDEF NO_DEFLATE} err := Z_STREAM_ERROR; {$ELSE} err := deflateInit2 (s^.stream, level, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); { windowBits is passed < 0 to suppress zlib header } GetMem (s^.outbuf, Z_BUFSIZE); s^.stream.next_out := s^.outbuf; {$ENDIF} if (err <> Z_OK) or (s^.outbuf = nil) then begin zdestroy(s); gzopen := gzFile(nil); exit; end; end else begin GetMem (s^.inbuf, Z_BUFSIZE); s^.stream.next_in := s^.inbuf; err := inflateInit2_ (s^.stream, -MAX_WBITS, ZLIB_VERSION, sizeof(z_stream)); { windowBits is passed < 0 to tell that there is no zlib header } if (err <> Z_OK) or (s^.inbuf = nil) then begin zdestroy(s); gzopen := gzFile(nil); exit; end; end; s^.stream.avail_out := Z_BUFSIZE; //showmessage(s^.path+' '+inttostr(length(path))); {$IFOPT I+} {$I-} {$define IOcheck} {$ENDIF} //11/11/07 Assign (s^.gzfile, s^.path); Assign (s^.gzfile, path); {$ifdef unix} if (fpstat(path,info)<0) and (s^.mode='w') then ReWrite (s^.gzfile,1) else Reset (s^.gzfile,1); {$else} GetFAttr(s^.gzfile, Attr); if (DosError <> 0) and (s^.mode='w') then ReWrite (s^.gzfile,1) else Reset (s^.gzfile,1); {$endif} {$IFDEF IOCheck} {$I+} {$ENDIF} if (IOResult <> 0) then begin zdestroy(s); gzopen := gzFile(nil); exit; end; if (s^.mode = 'w') then begin { Write a very simple .gz header } {$IFNDEF NO_DEFLATE} gzheader [0] := gz_magic [0]; gzheader [1] := gz_magic [1]; gzheader [2] := Z_DEFLATED; { method } gzheader [3] := 0; { flags } gzheader [4] := 0; { time[0] } gzheader [5] := 0; { time[1] } gzheader [6] := 0; { time[2] } gzheader [7] := 0; { time[3] } gzheader [8] := 0; { xflags } gzheader [9] := 0; { OS code = MS-DOS } blockwrite (s^.gzfile, gzheader, 10); s^.startpos := longint(10); {$ENDIF} end else begin check_header(s); { skip the .gz header } s^.startpos := FilePos(s^.gzfile) - s^.stream.avail_in; end; gzopen := gzFile(s); end; *) { GZSETPARAMS =============================================================== Update the compression level and strategy. ============================================================================} function gzsetparams (f:gzfile; level:integer; strategy:integer) : integer; var s : gz_streamp; written: integer; begin s := gz_streamp(f); if (s = nil) or (s^.mode <> 'w') then begin gzsetparams := Z_STREAM_ERROR; exit; end; { Make room to allow flushing } if (s^.stream.avail_out = 0) then begin s^.stream.next_out := s^.outbuf; blockwrite(s^.gzfile, s^.outbuf^, Z_BUFSIZE, written); if (written <> Z_BUFSIZE) then s^.z_err := Z_ERRNO; s^.stream.avail_out := Z_BUFSIZE; end; gzsetparams := deflateParams (s^.stream, level, strategy); end; { GET_BYTE ================================================================== Read a byte from a gz_stream. Updates next_in and avail_in. Returns EOF for end of file. IN assertion: the stream s has been sucessfully opened for reading. ============================================================================} function get_byte (s:gz_streamp) : integer; begin if (s^.z_eof = true) then begin get_byte := Z_EOF; exit; end; if (s^.stream.avail_in = 0) then begin {$I-} blockread (s^.gzfile, s^.inbuf^, Z_BUFSIZE, s^.stream.avail_in); {$I+} if (s^.stream.avail_in = 0) then begin s^.z_eof := true; if (IOResult <> 0) then s^.z_err := Z_ERRNO; get_byte := Z_EOF; exit; end; s^.stream.next_in := s^.inbuf; end; Dec(s^.stream.avail_in); get_byte := s^.stream.next_in^; Inc(s^.stream.next_in); end; { GETLONG =================================================================== Reads a Longint in LSB order from the given gz_stream. ============================================================================} { function getLong (s:gz_streamp) : cardinal; var x : array [0..3] of byte; i : byte; c : integer; n1 : longint; n2 : longint; begin for i:=0 to 3 do begin c := get_byte(s); if (c = Z_EOF) then s^.z_err := Z_DATA_ERROR; x[i] := (c and $FF) end; n1 := (ush(x[3] shl 8)) or x[2]; n2 := (ush(x[1] shl 8)) or x[0]; getlong := (n1 shl 16) or n2; end; } function getLong(s : gz_streamp) : cardinal; var x : packed array [0..3] of byte; c : integer; begin { x := cardinal(get_byte(s)); - you can't do this with TP, no unsigned longint } { the following assumes a little endian machine and TP } x[0] := Byte(get_byte(s)); x[1] := Byte(get_byte(s)); x[2] := Byte(get_byte(s)); c := get_byte(s); x[3] := Byte(c); if (c = Z_EOF) then s^.z_err := Z_DATA_ERROR; GetLong := cardinal(longint(x)); end; { CHECK_HEADER ============================================================== Check the gzip header of a gz_stream opened for reading. Set the stream mode to transparent if the gzip magic header is not present. Set s^.err to Z_DATA_ERROR if the magic header is present but the rest of the header is incorrect. IN assertion: the stream s has already been created sucessfully; s^.stream.avail_in is zero for the first time, but may be non-zero for concatenated .gz files ============================================================================} procedure check_header (s:gz_streamp); const z_magic : array[0..1] of byte = ($78, $9C); //.z files simply have an abreviated header var method : integer; { method byte } flags : integer; { flags byte } len : cardinal; c : integer; cx: array[0..1] of integer; begin { Check the gzip magic header } for len := 0 to 1 do begin c := get_byte(s); cx[len] := c; if (c <> gz_magic[len]) and (c <> z_magic[len]) then begin if (len <> 0) then begin Inc(s^.stream.avail_in); Dec(s^.stream.next_in); end; if (c <> Z_EOF) then begin Inc(s^.stream.avail_in); Dec(s^.stream.next_in); s^.transparent := TRUE; end; if (s^.stream.avail_in <> 0) then s^.z_err := Z_OK else s^.z_err := Z_STREAM_END; exit; end; end; if (cx[0] = z_magic[0]) and (cx[1] = z_magic[1]) then begin //method := Z_DEFLATED; //flags := 0; //none s^.z_err := Z_OK; exit; end; method := get_byte(s); flags := get_byte(s); if (method <> Z_DEFLATED) or ((flags and RESERVED) <> 0) then begin s^.z_err := Z_DATA_ERROR; exit; end; for len := 0 to 5 do get_byte(s); { Discard time, xflags and OS code } if ((flags and EXTRA_FIELD) <> 0) then begin { skip the extra field } len := cardinal(get_byte(s)); len := len + (cardinal(get_byte(s)) shr 8); { len is garbage if EOF but the loop below will quit anyway } while (len <> 0) and (get_byte(s) <> Z_EOF) do Dec(len); end; if ((flags and ORIG_NAME) <> 0) then begin { skip the original file name } repeat c := get_byte(s); until (c = 0) or (c = Z_EOF); end; if ((flags and COMMENT) <> 0) then begin { skip the .gz file comment } repeat c := get_byte(s); until (c = 0) or (c = Z_EOF); end; if ((flags and HEAD_CRC) <> 0) then begin { skip the header crc } get_byte(s); get_byte(s); end; if (s^.z_eof = true) then s^.z_err := Z_DATA_ERROR else s^.z_err := Z_OK; end; { DESTROY =================================================================== Cleanup then free the given gz_stream. Return a zlib error code. Try freeing in the reverse order of allocations. ============================================================================} function zdestroy (var s:gz_streamp) : integer; begin result := Z_OK; if not Assigned (s) then begin result := Z_STREAM_ERROR; exit; end; if (s^.stream.state <> nil) then begin if (s^.mode = 'w') then begin {$IFDEF NO_DEFLATE} result := Z_STREAM_ERROR; {$ELSE} //showMsg('1666'); result := deflateEnd(s^.stream); //showMsg('3666'); {$ENDIF} end else if (s^.mode = 'r') then begin result := inflateEnd(s^.stream); end; end; if (s^.zpath <> '') then begin {$I-} close(s^.gzfile); {$I+} if (IOResult <> 0) then result := Z_ERRNO; end; if (s^.z_err < 0) then result := s^.z_err; if Assigned (s^.inbuf) then FreeMem(s^.inbuf, Z_BUFSIZE); if Assigned (s^.outbuf) then FreeMem(s^.outbuf, Z_BUFSIZE); FreeMem(s, sizeof(gz_stream)); end; { GZREAD ==================================================================== Reads the given number of uncompressed bytes from the compressed file. If the input file was not in gzip format, gzread copies the given number of bytes into the buffer. gzread returns the number of uncompressed bytes actually read (0 for end of file, -1 for error). ============================================================================} function gzread (f:gzFile; buf:pointer; len:cardinal) : integer; var s : gz_streamp; start : Pbyte; next_out : Pbyte; n : cardinal; crclen : cardinal; { Buffer length to update CRC32 } filecrc : cardinal; { CRC32 stored in GZIP'ed file } filelen : cardinal; { Total lenght of uncompressed file } bytes : integer; { bytes actually read in I/O blockread } total_in : cardinal; total_out : cardinal; begin s := gz_streamp(f); start := Pbyte(buf); { starting point for crc computation } if (s = nil) or (s^.mode <> 'r') then begin gzread := Z_STREAM_ERROR; exit; end; if (s^.z_err = Z_DATA_ERROR) or (s^.z_err = Z_ERRNO) then begin gzread := -1; exit; end; if (s^.z_err = Z_STREAM_END) then begin gzread := 0; { EOF } exit; end; s^.stream.next_out := Pbyte(buf); s^.stream.avail_out := len; while (s^.stream.avail_out <> 0) do begin if (s^.transparent = true) then begin { Copy first the lookahead bytes: } n := s^.stream.avail_in; if (n > s^.stream.avail_out) then n := s^.stream.avail_out; if (n > 0) then begin move(s^.stream.next_in^,s^.stream.next_out^,n); inc (s^.stream.next_out, n); inc (s^.stream.next_in, n); dec (s^.stream.avail_out, n); dec (s^.stream.avail_in, n); end; if (s^.stream.avail_out > 0) then begin blockread (s^.gzfile, s^.stream.next_out^, s^.stream.avail_out, bytes); dec (s^.stream.avail_out, cardinal(bytes)); end; dec (len, s^.stream.avail_out); inc (s^.stream.total_in, cardinal(len)); inc (s^.stream.total_out, cardinal(len)); gzread := integer(len); exit; end; { IF transparent } if (s^.stream.avail_in = 0) and (s^.z_eof = false) then begin {$I-} blockread (s^.gzfile, s^.inbuf^, Z_BUFSIZE, s^.stream.avail_in); {$I+} if (s^.stream.avail_in = 0) then begin s^.z_eof := true; if (IOResult <> 0) then begin s^.z_err := Z_ERRNO; break; end; end; s^.stream.next_in := s^.inbuf; end; s^.z_err := inflate(s^.stream, Z_NO_FLUSH); if (s^.z_err = Z_STREAM_END) then begin crclen := 0; next_out := s^.stream.next_out; while (next_out <> start ) do begin dec (next_out); inc (crclen); { Hack because Pascal cannot substract pointers } end; { Check CRC and original size } s^.crc := crc32(s^.crc, start, crclen); start := s^.stream.next_out; filecrc := getLong (s); filelen := getLong (s); if (s^.crc <> filecrc) or (s^.stream.total_out <> filelen) then s^.z_err := Z_DATA_ERROR else begin { Check for concatenated .gz files: } check_header(s); if (s^.z_err = Z_OK) then begin total_in := s^.stream.total_in; total_out := s^.stream.total_out; inflateReset (s^.stream); s^.stream.total_in := total_in; s^.stream.total_out := total_out; s^.crc := crc32 (0, nil, 0); end; end; {IF-THEN-ELSE} end; if (s^.z_err <> Z_OK) or (s^.z_eof = true) then break; end; {WHILE} crclen := 0; next_out := s^.stream.next_out; while (next_out <> start ) do begin dec (next_out); inc (crclen); { Hack because Pascal cannot substract pointers } end; s^.crc := crc32 (s^.crc, start, crclen); gzread := integer(len - s^.stream.avail_out); end; { GZGETC ==================================================================== Reads one byte from the compressed file. gzgetc returns this byte or -1 in case of end of file or error. ============================================================================} function gzgetc (f:gzfile) : integer; var c:byte; begin if (gzread (f,@c,1) = 1) then gzgetc := c else gzgetc := -1; end; { GZGETS ==================================================================== Reads bytes from the compressed file until len-1 characters are read, or a newline character is read and transferred to buf, or an end-of-file condition is encountered. The string is then Null-terminated. gzgets returns buf, or nil in case of error. The current implementation is not optimized at all. ============================================================================} function gzgets (f:gzfile; buf:Pchar; len:integer) : Pchar; var b : Pchar; { start of buffer } bytes : integer; { number of bytes read by gzread } gzchar : char; { char read by gzread } begin if (buf = nil) or (len <= 0) then begin gzgets := nil; exit; end; b := buf; repeat dec (len); bytes := gzread (f, buf, 1); gzchar := buf^; inc (buf); until (len = 0) or (bytes <> 1) or (gzchar = Chr(13)); buf^ := Chr(0); if (b = buf) and (len > 0) then gzgets := nil else gzgets := b; end; {$IFNDEF NO_DEFLATE} { GZWRITE =================================================================== Writes the given number of uncompressed bytes into the compressed file. gzwrite returns the number of uncompressed bytes actually written (0 in case of error). ============================================================================} function gzwrite (f:gzfile; buf:pointer; len:cardinal) : integer; var s : gz_streamp; written : integer; begin s := gz_streamp(f); if (s = nil) or (s^.mode <> 'w') then begin gzwrite := Z_STREAM_ERROR; exit; end; s^.stream.next_in := Pbyte(buf); s^.stream.avail_in := len; while (s^.stream.avail_in <> 0) do begin if (s^.stream.avail_out = 0) then begin s^.stream.next_out := s^.outbuf; blockwrite (s^.gzfile, s^.outbuf^, Z_BUFSIZE, written); if (written <> Z_BUFSIZE) then begin s^.z_err := Z_ERRNO; break; end; s^.stream.avail_out := Z_BUFSIZE; end; s^.z_err := deflate(s^.stream, Z_NO_FLUSH); if (s^.z_err <> Z_OK) then break; end; {WHILE} s^.crc := crc32(s^.crc, buf, len); gzwrite := integer(len - s^.stream.avail_in); end; { =========================================================================== Converts, formats, and writes the args to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of uncompressed bytes actually written (0 in case of error). } {$IFDEF GZ_FORMAT_STRING} function gzprintf (zfile : gzFile; const format : string; a : array of integer) : integer; var buf : array[0..Z_PRINTF_BUFSIZE-1] of char; len : integer; begin {$ifdef HAS_snprintf} snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); {$else} sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); {$endif} len := strlen(buf); { old sprintf doesn't return the nb of bytes written } if (len <= 0) return 0; gzprintf := gzwrite(file, buf, len); end; {$ENDIF} { GZPUTC ==================================================================== Writes c, converted to an unsigned char, into the compressed file. gzputc returns the value that was written, or -1 in case of error. ============================================================================} function gzputc (f:gzfile; c:char) : integer; begin if (gzwrite (f,@c,1) = 1) then {$IFDEF FPC} gzputc := integer(ord(c)) {$ELSE} gzputc := integer(c) {$ENDIF} else gzputc := -1; end; { GZPUTS ==================================================================== Writes the given null-terminated string to the compressed file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. ============================================================================} function gzputs (f:gzfile; s:Pchar) : integer; begin gzputs := gzwrite (f, pointer(s), strlen(s)); end; { DO_FLUSH ================================================================== Flushes all pending output into the compressed file. The parameter flush is as in the zdeflate() function. ============================================================================} function do_flush (f:gzfile; flush:integer) : integer; var len : cardinal; done : boolean; s : gz_streamp; written : integer; begin done := false; s := gz_streamp(f); if (s = nil) or (s^.mode <> 'w') then begin do_flush := Z_STREAM_ERROR; exit; end; s^.stream.avail_in := 0; { should be zero already anyway } while true do begin len := Z_BUFSIZE - s^.stream.avail_out; if (len <> 0) then begin {$I-} blockwrite(s^.gzfile, s^.outbuf^, len, written); {$I+} if (written <> len) then begin s^.z_err := Z_ERRNO; do_flush := Z_ERRNO; exit; end; s^.stream.next_out := s^.outbuf; s^.stream.avail_out := Z_BUFSIZE; end; if (done = true) then break; s^.z_err := deflate(s^.stream, flush); { Ignore the second of two consecutive flushes: } if (len = 0) and (s^.z_err = Z_BUF_ERROR) then s^.z_err := Z_OK; { deflate has finished flushing only when it hasn't used up all the available space in the output buffer: } done := (s^.stream.avail_out <> 0) or (s^.z_err = Z_STREAM_END); if (s^.z_err <> Z_OK) and (s^.z_err <> Z_STREAM_END) then break; end; {WHILE} if (s^.z_err = Z_STREAM_END) then do_flush:=Z_OK else do_flush:=s^.z_err; end; { GZFLUSH =================================================================== Flushes all pending output into the compressed file. The parameter flush is as in the zdeflate() function. The return value is the zlib error number (see function gzerror below). gzflush returns Z_OK if the flush parameter is Z_FINISH and all output could be flushed. gzflush should be called only when strictly necessary because it can degrade compression. ============================================================================} function gzflush (f:gzfile; flush:integer) : integer; var err : integer; s : gz_streamp; begin s := gz_streamp(f); err := do_flush (f, flush); if (err <> 0) then begin gzflush := err; exit; end; if (s^.z_err = Z_STREAM_END) then gzflush := Z_OK else gzflush := s^.z_err; end; {$ENDIF} (* NO DEFLATE *) { GZREWIND ================================================================== Rewinds input file. ============================================================================} function gzrewind (f:gzFile) : integer; var s:gz_streamp; begin s := gz_streamp(f); if (s = nil) or (s^.mode <> 'r') then begin gzrewind := -1; exit; end; s^.z_err := Z_OK; s^.z_eof := false; s^.stream.avail_in := 0; s^.stream.next_in := s^.inbuf; if (s^.startpos = 0) then begin { not a compressed file } {$I-} seek (s^.gzfile, 0); {$I+} gzrewind := 0; exit; end; inflateReset(s^.stream); {$I-} seek (s^.gzfile, s^.startpos); {$I+} gzrewind := integer(IOResult); exit; end; { GZSEEK ==================================================================== Sets the starting position for the next gzread or gzwrite on the given compressed file. The offset represents a number of bytes from the beginning of the uncompressed stream. gzseek returns the resulting offset, or -1 in case of error. SEEK_END is not implemented, returns error. In this version of the library, gzseek can be extremely slow. ============================================================================} function gzseek (f:gzfile; offset:z_off_t; whence:integer) : z_off_t; var s : gz_streamp; size : cardinal; begin s := gz_streamp(f); if (s = nil) or (whence = SEEK_END) or (s^.z_err = Z_ERRNO) or (s^.z_err = Z_DATA_ERROR) then begin gzseek := z_off_t(-1); exit; end; if (s^.mode = 'w') then begin {$IFDEF NO_DEFLATE} gzseek := z_off_t(-1); exit; {$ELSE} if (whence = SEEK_SET) then dec(offset, s^.stream.total_out); if (offset < 0) then begin; gzseek := z_off_t(-1); exit; end; { At this point, offset is the number of zero bytes to write. } if s^.inbuf=nil then begin getmem(s^.inbuf,Z_BUFSIZE); fillchar(s^.inbuf^,Z_BUFSIZE,0); end; while (offset > 0) do begin size := Z_BUFSIZE; if (offset < Z_BUFSIZE) then size := cardinal(offset); size := gzwrite(f, s^.inbuf, size); if (size = 0) then begin gzseek := z_off_t(-1); exit; end; dec (offset,size); end; gzseek := z_off_t(s^.stream.total_in); exit; {$ENDIF} end; { Rest of function is for reading only } { compute absolute position } if (whence = SEEK_CUR) then inc (offset, s^.stream.total_out); if (offset < 0) then begin gzseek := z_off_t(-1); exit; end; if (s^.transparent = true) then begin s^.stream.avail_in := 0; s^.stream.next_in := s^.inbuf; {$I-} seek (s^.gzfile, offset); {$I+} if (IOResult <> 0) then begin gzseek := z_off_t(-1); exit; end; s^.stream.total_in := cardinal(offset); s^.stream.total_out := cardinal(offset); gzseek := z_off_t(offset); exit; end; { For a negative seek, rewind and use positive seek } if (cardinal(offset) >= s^.stream.total_out) then dec (offset, s^.stream.total_out) else if (gzrewind(f) <> 0) then begin gzseek := z_off_t(-1); exit; end; { offset is now the number of bytes to skip. } if (offset <> 0) and (s^.outbuf = nil) then GetMem (s^.outbuf, Z_BUFSIZE); while (offset > 0) do begin size := Z_BUFSIZE; if (offset < Z_BUFSIZE) then size := integer(offset); size := gzread (f, s^.outbuf, size); if (size <= 0) then begin gzseek := z_off_t(-1); exit; end; dec(offset, size); end; gzseek := z_off_t(s^.stream.total_out); end; { GZTELL ==================================================================== Returns the starting position for the next gzread or gzwrite on the given compressed file. This position represents a number of bytes in the uncompressed data stream. ============================================================================} function gztell (f:gzfile) : z_off_t; begin gztell := gzseek (f, 0, SEEK_CUR); end; { GZEOF ===================================================================== Returns TRUE when EOF has previously been detected reading the given input stream, otherwise FALSE. ============================================================================} function gzeof (f:gzfile) : boolean; var s:gz_streamp; begin s := gz_streamp(f); if (s=nil) or (s^.mode<>'r') then gzeof := false else gzeof := s^.z_eof; end; { PUTLONG =================================================================== Outputs a Longint in LSB order to the given file ============================================================================} procedure putLong (var f:file; x:cardinal); var n : integer; c : byte; begin for n:=0 to 3 do begin c := x and $FF; blockwrite (f, c, 1); x := x shr 8; end; end; { GZCLOSE =================================================================== Flushes all pending output if necessary, closes the compressed file and deallocates all the (de)compression state. The return value is the zlib error number (see function gzerror below). ============================================================================} function gzclose (f:gzFile) : integer; var err : integer; s : gz_streamp; begin s := gz_streamp(f); if (s = nil) then begin gzclose := Z_STREAM_ERROR; exit; end; if (s^.mode = 'w') then begin {$IFDEF NO_DEFLATE} gzclose := Z_STREAM_ERROR; exit; {$ELSE} err := do_flush (f, Z_FINISH); if (err <> Z_OK) then begin gzclose := zdestroy (gz_streamp(f)); exit; end; putLong (s^.gzfile, s^.crc); putLong (s^.gzfile, s^.stream.total_in); {$ENDIF} end; gzclose := zdestroy (gz_streamp(f)); end; { GZERROR =================================================================== Returns the error message for the last error which occured on the given compressed file. errnum is set to zlib error number. If an error occured in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. ============================================================================} function gzerror (f:gzfile; var errnum:smallint) : string; var m : string; s : gz_streamp; begin s := gz_streamp(f); if (s = nil) then begin errnum := Z_STREAM_ERROR; gzerror := zError(Z_STREAM_ERROR); end; errnum := s^.z_err; if (errnum = Z_OK) then begin gzerror := zError(Z_OK); exit; end; m := s^.stream.msg; if (errnum = Z_ERRNO) then m := ''; if (m = '') then m := zError(s^.z_err); //s^.msg := s^.path+': '+m; gzerror := 'GZ error';// s^.msg; end; procedure GZipBuffer(var FGzipFilename,FFileDestination: String;lxInBuffer: byteP;lInSize: Integer; lOverwritewarn: boolean);overload; var lTempName: string; lFdata: file; begin (*if lOverwritewarn and fileexists(FFileDestination) then begin case MessageDlg('Overwrite the file '+FFileDestination+'?', mtConfirmation,[mbYes, mbAbort], 0) of { produce the message dialog box } mrAbort: exit; end; end; //if overwrite *) lTempName := changefileext(FFileDestination,'.tmp'); assignfile(lFdata,lTempName ); filemode := 2; rewrite(lFdata,1); BlockWrite(lFdata,lxInBuffer^,lInSize); closefile(lFdata); file_compress2 (lTempName,FFileDestination ); end;//GZipBuffer procedure GZipBuffer(var FFileDestination: String;lxInBuffer: byteP;lInSize: Integer; lOverwritewarn: boolean); overload; var len,lInPos : cardinal; ioerr : integer; buf : packed array [0..Z_BUFSIZE-1] of byte; { Global uses BSS instead of stack } errorcode : byte; lensize : DWord; outfile : gzFile; mode,lDestName : string; begin if lInSize < 1 then exit; mode := 'w6 '; if not GzExt(FFileDestination) then lDestName := FFileDestination + '.gz' else lDestName := FFileDestination; outfile := gzopen (lDestName, mode); if (outfile = NIL) then begin ShowMsg('unable to create '+lDestName); exit; end; errorcode := 0; lensize := 0; lInPos := 1; while true do begin len := (lInSize-lInPos)+1; if len > Z_BUFSIZE then len := Z_BUFSIZE; if (len <= 0) then break; Move(lxInBuffer^[lInPos],buf[0],len); {$WARNINGS OFF}{Comparing signed and unsigned types} if (gzwrite (outfile, @buf, len) <> len) then begin {$WARNINGS OFF} errorcode := 2; break end; lInPos := lInPos + len; end; if (gzclose (outfile) <> 0) then errorcode := 3; //gz_compress := errorcode; end; // proc gz_compress function gz_uncompress (infile:gzFile; var outfile:file;fsize:DWord{LongWord}) : integer; var len : integer; written : Integer; buf : packed array [0..Z_BUFSIZE-1] of byte; { Global uses BSS instead of stack } errorcode : byte; lensize : DWord{LongWord}; begin errorcode := 0; //FProgress := 0; lensize := 0; //if FProgressStep > 0 then DoOnProgress; while true do begin len := gzread (infile, @buf, Z_BUFSIZE); if (len < 0) then begin errorcode := 1; break end; if (len = 0) then break; {$I-} blockwrite (outfile, buf, len, written); {$I+} {$WARNINGS OFF}{Comparing signed and unsigned types} if (written <> len) then begin {$WARNINGS ON} errorcode := 2; break end; (*if FProgressStep > 0 then begin {$WARNINGS OFF} lensize := lensize + len; if ((lensize / fsize) * 100 >= FProgress + FProgressStep) or (lensize = fsize) then begin FProgress := Trunc((lensize / fsize) * 100); DoOnProgress end {$WARNINGS ON} end *) end; {WHILE} if (gzclose (infile) <> 0{Z_OK}) then begin //if FWindowOnError then // MessageDlg('gzclose Error.', mtError, [mbAbort], 0); errorcode := 3 end; gz_uncompress := errorcode end; function Gunzip (var FFileSource,FFileDestination: string): integer; var infile : gzFile; outfile : file; ioerr : integer; errorcode : integer; fsize : DWord{LongWord}; s : gz_streamp; begin errorcode := 0; ShowMsg('unGZip ' + extractfilename(FFileSource)); infile := gzopen (FFileSource, 'r'); if (infile = NIL) then begin //if FWindowOnError then // MessageDlg('Can''t open: '+FFileSource, mtError, [mbAbort], 0); errorcode := 1 end else begin s := gz_streamp(infile); fsize := FileSize( s^.gzfile); AssignFile (outfile, FFileDestination); {$I-} Rewrite (outfile,1); {$I+} ioerr := IOResult; if (ioerr <> 0) then begin //if FWindowOnError then // MessageDlg('Can''t create: '+FFileDestination, mtError, [mbAbort], 0); errorcode := 2 end else begin { We could open all files, so time for uncompressing } gz_uncompress (infile, outfile, fsize); //if FDeleteSource then DeleteFile(FFileSource); {$I-} close (outfile); {$I+} ioerr := IOResult; if (ioerr <> 0) then begin //if FWindowOnError then // MessageDlg('Can''t close file '+FFileDestination, mtError, [mbAbort], 0); halt(1) end end end; Gunzip := errorcode end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/userdir.pas�������������������������������������������������0000755�0001750�0001750�00000014152�11326425442�017663� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit userdir; //returns directory where user has read/write permissions... {$IFDEF FPC} {$mode delphi}{$H+} {$ENDIF} interface //returns number of cores: a computer with two dual cores will report 4 function IniName: string; function DefaultsDir (lSubFolder: string): string; function UserDataFolder: string; //uses shlobj implementation {$Include isgui.inc} {$IFDEF UNIX} uses Process, SysUtils,classes,IniFiles, {$IFDEF GUI}dialogs;{$ELSE} dialogsx;{$ENDIF} function UserDataFolder: string; begin result :=expandfilename('~/'); end; function FileNameNoExt (lFilewExt:String): string; //remove final extension var lLen,lInc: integer; lName: String; begin lName := ''; lLen := length(lFilewExt); lInc := lLen+1; if lLen > 0 then begin repeat dec(lInc); until (lFileWExt[lInc] = '.') or (lInc = 1); end; if lInc > 1 then for lLen := 1 to (lInc - 1) do lName := lName + lFileWExt[lLen] else lName := lFilewExt; //no extension Result := lName; end; function DefaultsDir (lSubFolder: string): string; //for Linux: DefaultsDir is ~/appname/SubFolder/, e.g. /home/username/mricron/subfolder/ //Note: Final character is pathdelim const pathdelim = '/'; var lBaseDir: string; begin lBaseDir := GetEnvironmentVariable ('HOME')+pathdelim+'.'+ FileNameNoExt(ExtractFilename(paramstr(0) ) ); if not DirectoryExists(lBaseDir) then begin {$I-} MkDir(lBaseDir); if IOResult <> 0 then begin //Msg('Unable to create new folder '+lBaseDir); end; {$I+} end; lBaseDir := lBaseDir+pathdelim; if lSubFolder <> '' then begin lBaseDir := lBaseDir + lSubFolder; if not DirectoryExists(lBaseDir) then begin {$I-} MkDir(lBaseDir); if IOResult <> 0 then begin //you may want to show an error, e.g. showmessage('Unable to create new folder '+lBaseDir); exit; end; {$I+} end; result := lBaseDir + pathdelim; end else result := lBaseDir; end; function IniName: string; begin result := DefaultsDir('')+FileNameNoExt(extractfilename(paramstr(0)))+'.ini'; end; {$ELSE} //If UNIX ELSE NOT Unix uses SysUtils, Windows,shlobj; //for administrators, we can write to folder with executable, otherwise we will save data to the user's AppDataFolder function AppDataFolder: string; //uses shlobj {$IFDEF FPC} const CSIDL_APPDATA = 26; {$ENDIF} var Path : pchar; idList : PItemIDList; begin GetMem(Path, MAX_PATH); SHGetSpecialFolderLocation(0, CSIDL_APPDATA , idList); SHGetPathFromIDList(idList, Path); Result := string(Path); FreeMem(Path); end; function UserDataFolder: string; //uses shlobj var PIDL : PItemIDList; Folder : array[0..MAX_PATH] of Char; const CSIDL_PERSONAL = $0005; begin SHGetSpecialFolderLocation(0, CSIDL_PERSONAL, PIDL); SHGetPathFromIDList(PIDL, Folder); result :=Folder; end; (*function UserDataFolder: string; //uses shlobj var Path : pchar; idList : PItemIDList; begin GetMem(Path, MAX_PATH); SHGetSpecialFolderLocation(0, csidl_Personal , idList); SHGetPathFromIDList(idList, Path); Result := string(Path); FreeMem(Path); end; *) function IsAdmin: Boolean; const SECURITY_NT_AUTHORITY: TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5)); SECURITY_BUILTIN_DOMAIN_RID = $00000020; DOMAIN_ALIAS_RID_ADMINS = $00000220; var hAccessToken: THandle; ptgGroups: PTokenGroups; dwInfoBufferSize: DWORD; psidAdministrators: PSID; x: Integer; bSuccess: BOOL; LastError: integer; begin if Win32Platform <> VER_PLATFORM_WIN32_NT then begin Result := True; exit; end; Result := False; bSuccess := OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, hAccessToken); if not bSuccess then begin if GetLastError = ERROR_NO_TOKEN then bSuccess := OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, hAccessToken); end; if bSuccess then begin GetMem(ptgGroups, 1024); {$IFDEF FPC} bSuccess := GetTokenInformation(hAccessToken, TokenGroups, ptgGroups, 1024, @dwInfoBufferSize); {$ELSE} bSuccess := GetTokenInformation(hAccessToken, TokenGroups, ptgGroups, 1024, dwInfoBufferSize); {$ENDIF} LastError := GetLastError; if not bSuccess then begin //you may want to show an error message.. //showmessage(format('GetLastError %d',[LastError])); end; CloseHandle(hAccessToken); if bSuccess then begin AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, psidAdministrators); {$R-} for x := 0 to ptgGroups.GroupCount - 1 do if EqualSid(psidAdministrators, ptgGroups.Groups[x].Sid) then begin Result := True; break; end; {$R+} FreeSid(psidAdministrators); end; FreeMem(ptgGroups); end; end; function IniName: string; //only administrators can write to c:\program files -use AppDataFolder for non-Administrators begin if isAdmin then result := changefileext(paramstr(0),'.ini') else result := AppDataFolder+'\'+changefileext(extractfilename(paramstr(0)),'.ini'); end; function DefaultsDir (lSubFolder: string): string; const pathdelim = '\'; //for Administrators: DefaultsDir is in the location of the executable, e.g. c:\program files\mricron\subfolder\ //for non-Administrators, the AppDataFolder is returned //Note: Final character is pathdelim begin result := extractfilepath(IniName); if length(result) < 1 then exit; if result[length(result)] <> pathdelim then result := result + pathdelim; if lSubFolder = '' then exit; result := result + lSubFolder; if result[length(result)] <> pathdelim then result := result + pathdelim; end; {$ENDIF} end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/nifti_hdr.pas�����������������������������������������������0000755�0001750�0001750�00000126666�12306630214�020164� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit nifti_hdr; interface {$H+} {$Include isgui.inc} uses {$IFNDEF FPC} DiskSpaceKludge,gziod, {$ELSE} gzio2, {$ENDIF} {$IFNDEF Unix} Windows, {$ENDIF} define_types,SysUtils,GraphicsMathLibrary, nifti_types, nifti_foreign, dialogsx; type TAnalyzeHdrSection = packed record //Next: analyze Format Header structure Pad: array [1..253] of byte; originator: array [1..5] of smallint; end;//TAnalyzeHdrSection Structure TMRIcroHdr = record //Next: analyze Format Header structure NIFTIhdr : TNIFTIhdr; AutoBalMinUnscaled,AutoBalMaxUnscaled ,WindowScaledMin,WindowScaledMax ,GlMinUnscaledS,GlMaxUnscaledS,Zero8Bit,Slope8bit: single; //brightness and contrast NIfTItransform,DiskDataNativeEndian,UsesCustomPalette,UsesCustomPaletteRandomRainbow,UsesLabels,LutFromZero: boolean; HdrFileName,ImgFileName: string; gzBytesX: int64; NIFTIVersion,LUTindex,ScrnBufferItems,ImgBufferItems,RenderBufferItems,ImgBufferBPP,RenderDim,Index: longint; ImgBufferUnaligned: Pointer; //raw address of Image Buffer: address may not be aligned ScrnBuffer,ImgBuffer,RenderBuffer: Bytep; LUTinvisible: TRGBQuad;//DWord; LUT: TLUT;//array[0..255] of TRGBQuad; Mat: TMatrix; end; //TNIFTIhdr Header Structure function IsVOIROIExt (var lFName: string):boolean; function ComputeImageDataBytes (var lHdr: TMRIcroHdr): longint; //size of image data in bytes function ComputeImageDataBytes8bpp (var lHdr: TMRIcroHdr): longint; //size of image as 32-bit per voxel data in bytes function ComputeImageDataBytes32bpp (var lHdr: TMRIcroHdr): longint; //size of image as 32-bit per voxel data in bytes procedure NIFTIhdr_SwapBytes (var lAHdr: TNIFTIhdr); //Swap Byte order for the Analyze type procedure NIFTIhdr_ClearHdr (var lHdr: TMRIcroHdr); //set all values of header to something reasonable function NIFTIhdr_LoadHdr (var lFilename: string; var lHdr: TMRIcroHdr): boolean; function NIFTIhdr_SaveHdr (var lFilename: string; var lHdr: TMRIcroHdr; lAllowOverwrite: boolean): boolean; overload; function NIFTIhdr_SaveHdr (var lFilename: string; var lHdr: TNIFTIHdr; lAllowOverwrite,lSPM2: boolean): boolean; overload; procedure NIFTIhdr_SetIdentityMatrix (var lHdr: TMRIcroHdr); //create neutral rotation matrix function IsNIfTIHdrExt (var lFName: string):boolean; //1494 function IsNifTiMagic (var lHdr: TNIFTIhdr): boolean; //procedure NearestOrtho(var lHdr: TMRIcroHdr); //function nifti_mat44_orthog( lR :TMatrix; lImm,lJmm,lKmm: double): TMatrix; function CopyNiftiHdr (var lInHdr,lOutHdr: TNIFTIhdr): boolean; procedure WriteNiftiMatrix (var lHdr: TNIFTIhdr; m11,m12,m13,m14, m21,m22,m23,m24, m31,m32,m33,m34: Single); procedure nifti_mat44_to_quatern( lR :TMatrix; var qb, qc, qd, qx, qy, qz, dx, dy, dz, qfac : single); implementation uses {$IFDEF GUI} dialogs,{$ENDIF} dicomhdr;//2/2208 function CopyNiftiHdr (var lInHdr,lOutHdr: TNIFTIhdr): boolean; begin move(lInHdr,lOutHdr,sizeof(TNIFTIhdr)); result := true; end; procedure WriteNiftiMatrix (var lHdr: TNIFTIhdr; m11,m12,m13,m14, m21,m22,m23,m24, m31,m32,m33,m34: Single); begin with lHdr do begin srow_x[0] := m11; srow_x[1] := m12; srow_x[2] := m13; srow_x[3] := m14; srow_y[0] := m21; srow_y[1] := m22; srow_y[2] := m23; srow_y[3] := m24; srow_z[0] := m31; srow_z[1] := m32; srow_z[2] := m33; srow_z[3] := m34; end; //with lHdr end; function IsNifTi1Magic (var lHdr: TNIFTIhdr): boolean; begin if (lHdr.magic =kNIFTI_MAGIC_SEPARATE_HDR) or (lHdr.Magic = kNIFTI_MAGIC_EMBEDDED_HDR ) then result := true else result :=false; //analyze end; function IsNifTiMagic (var lHdr: TNIFTIhdr): boolean; begin if (IsNifTi1Magic(lHdr)) then result := true else result :=false; //analyze end; function IsNIfTIHdrExt (var lFName: string):boolean; var lExt: string; begin lExt := UpCaseExt(lFName); if (lExt='.NII') or (lExt = '.HDR') or (lExt = '.NII.GZ') or (lExt = '.VOI') then result := true else result := false; end; function IsVOIROIExt (var lFName: string):boolean; var lExt: string; begin lExt := UpCaseExt(lFName); if (lExt = '.VOI') or (lExt = '.ROI') then result := true else result := false; end; function ComputeImageDataBytes32bpp (var lHdr: TMRIcroHdr): integer; var lDim, lSzInBits : integer; begin result := 0; with lHdr.NIFTIhdr do begin if Dim[0] < 1 then begin ShowMsg('NIFTI format error: datasets must have at least one dimension (dim[0] < 1).'); exit; end; lSzInBits := 32; //bits per voxel for lDim := 1 to 3 {Dim[0]} do lSzInBits := lSzInBits * Dim[lDim]; end; //with niftihdr result := (lSzInBits + 7) div 8; //+7 to ensure binary data not clipped end; //func ComputeImageDataBytes32bpp function ComputeImageDataBytes8bpp (var lHdr: TMRIcroHdr): integer; var lDim, lSzInBits : integer; begin result := 0; with lHdr.NIFTIhdr do begin if Dim[0] < 1 then begin ShowMsg('NIFTI format error: datasets must have at least one dimension (dim[0] < 1).'); exit; end; lSzInBits := 8; //bits per voxel for lDim := 1 to 3 {Dim[0]} do lSzInBits := lSzInBits * Dim[lDim]; end; //with niftihdr result := (lSzInBits + 7) div 8; //+7 to ensure binary data not clipped end; //func ComputeImageDataBytes8bpp function ComputeImageDataBytes (var lHdr: TMRIcroHdr): integer; var lDim, lSzInBits : integer; begin result := 0; with lHdr.NIFTIhdr do begin if Dim[0] < 1 then begin ShowMsg('NIFTI format error: datasets must have at least one dimension (dim[0] < 1).'); exit; end; lSzInBits := bitpix; //bits per voxel //showmessage(inttostr(Dim[0])); for lDim := 1 to 3 {Dim[0]} do lSzInBits := lSzInBits * Dim[lDim]; end; //with niftihdr result := (lSzInBits + 7) div 8; //+7 to ensure binary data not clipped end; //func ComputeImageDataBytes function orthogonalMatrix(var lHdr: TMRIcroHdr): boolean; var lM: TMatrix; lRow,lCol,lN0: integer; begin result := false; lM := Matrix3D ( lHdr.NIFTIhdr.srow_x[0],lHdr.NIFTIhdr.srow_x[1],lHdr.NIFTIhdr.srow_x[2],lHdr.NIFTIhdr.srow_x[3], // 3D "graphics" matrix lHdr.NIFTIhdr.srow_y[0],lHdr.NIFTIhdr.srow_y[1],lHdr.NIFTIhdr.srow_y[2],lHdr.NIFTIhdr.srow_y[3], // 3D "graphics" matrix lHdr.NIFTIhdr.srow_z[0],lHdr.NIFTIhdr.srow_z[1],lHdr.NIFTIhdr.srow_z[2],lHdr.NIFTIhdr.srow_z[3], // 3D "graphics" matrix 0,0,0,1); for lRow := 1 to 3 do begin lN0 := 0; for lCol := 1 to 3 do if lM.matrix[lRow,lCol] = 0 then inc(lN0); if lN0 <> 2 then exit; //exactly two values are zero end; for lCol := 1 to 3 do begin lN0 := 0; for lRow := 1 to 3 do if lM.matrix[lRow,lCol] = 0 then inc(lN0); if lN0 <> 2 then exit; //exactly two values are zero end; result := true; end; function EmptyRow (lRow: integer; var lM: TMatrix): boolean; begin //fx(lM.matrix[lRow,1],lM.matrix[lRow,2],lM.matrix[lRow,3]); if (abs(lM.matrix[lRow,1]) < 0.00000001) and (abs(lM.matrix[lRow,2]) < 0.00000001) and (abs(lM.matrix[lRow,3]) < 0.00000001) then result := true else result := false; end; procedure ReportMatrix (lStr: string;lM:TMatrix); begin ShowMsg(lStr+kCR+ RealToStr(lM.matrix[1,1],6)+','+RealToStr(lM.matrix[1,2],6)+','+RealToStr(lM.matrix[1,3],6)+','+RealToStr(lM.matrix[1,4],6)+ kCR+RealToStr(lM.matrix[2,1],6)+','+RealToStr(lM.matrix[2,2],6)+','+RealToStr(lM.matrix[2,3],6)+','+RealToStr(lM.matrix[2,4],6)+ kCR+RealToStr(lM.matrix[3,1],6)+','+RealToStr(lM.matrix[3,2],6)+','+RealToStr(lM.matrix[3,3],6)+','+RealToStr(lM.matrix[3,4],6)+ kCR+RealToStr(lM.matrix[4,1],6)+','+RealToStr(lM.matrix[4,2],6)+','+RealToStr(lM.matrix[4,3],6)+','+RealToStr(lM.matrix[4,4],6)); end; function EmptyMatrix(var lHdr: TMRIcroHdr): boolean; var lM: TMatrix; lRow,lCol: integer; begin result := false; lM := Matrix3D ( lHdr.NIFTIhdr.srow_x[0],lHdr.NIFTIhdr.srow_x[1],lHdr.NIFTIhdr.srow_x[2],lHdr.NIFTIhdr.srow_x[3], // 3D "graphics" matrix lHdr.NIFTIhdr.srow_y[0],lHdr.NIFTIhdr.srow_y[1],lHdr.NIFTIhdr.srow_y[2],lHdr.NIFTIhdr.srow_y[3], // 3D "graphics" matrix lHdr.NIFTIhdr.srow_z[0],lHdr.NIFTIhdr.srow_z[1],lHdr.NIFTIhdr.srow_z[2],lHdr.NIFTIhdr.srow_z[3], // 3D "graphics" matrix 0,0,0,1); if EmptyRow(1,lM) or EmptyRow(2,lM) or EmptyRow(3,lM) then begin ReportMatrix('Matrix appears bogus',lm); end else begin for lRow := 1 to 3 do begin {3/2008} for lCol := 1 to 4 do begin if (lRow = lCol) then begin if lM.matrix[lRow,lCol] <> 1 then exit; end else begin if lM.matrix[lRow,lCol] <> 0 then exit; end// unity matrix does not count - mriconvert creates bogus [1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 0] end; //each col end;//each row end;//not bogus result := true; end; procedure FromMatrix (M: TMatrix; var m11,m12,m13, m21,m22,m23, m31,m32,m33: DOUBLE) ; BEGIN m11 := M.Matrix[1,1]; m12 := M.Matrix[1,2]; m13 := M.Matrix[1,3]; m21 := M.Matrix[2,1]; m22 := M.Matrix[2,2]; m23 := M.Matrix[2,3]; m31 := M.Matrix[3,1]; m32 := M.Matrix[3,2]; m33 := M.Matrix[3,3]; END {FromMatrix3D}; function nifti_mat33_determ( R: TMatrix ):double; begin result := r.matrix[1,1]*r.matrix[2,2]*r.matrix[3,3] -r.matrix[1,1]*r.matrix[3,2]*r.matrix[2,3] -r.matrix[2,1]*r.matrix[1,2]*r.matrix[3,3] +r.matrix[2,1]*r.matrix[3,2]*r.matrix[1,3] +r.matrix[3,1]*r.matrix[1,2]*r.matrix[2,3] -r.matrix[3,1]*r.matrix[2,2]*r.matrix[1,3] ; end; procedure FixCrapMat(var lMat: TMatrix); var lVec000,lVec100,lVec010,lVec001: TVector; begin lVec000 := Vector3D (0, 0, 0); lVec100 := Vector3D (1, 0, 0); lVec010 := Vector3D (0, 1, 0); lVec001 := Vector3D (0, 0, 1); lVec000 := Transform (lVec000, lMat); lVec100 := Transform (lVec100, lMat); lVec010 := Transform (lVec010, lMat); lVec001 := Transform (lVec001, lMat); if SameVec(lVec000,lVec100) or SameVec(lVec000,lVec010) or SameVec(lVec000,lVec001) then begin lMat := eye3D; ShowMsg('Warning: the transformation matrix is corrupt [some dimensions have zero size]'); end; end; function nifti_mat33_rownorm( A: TMatrix ): single; //* max row norm of 3x3 matrix */ var r1,r2,r3: single ; begin r1 := abs(A.matrix[1,1])+abs(A.matrix[1,2])+abs(A.matrix[1,3]) ; r2 := abs(A.matrix[2,1])+abs(A.matrix[2,2])+abs(A.matrix[2,3]) ; r3 := abs(A.matrix[3,1])+abs(A.matrix[3,2])+abs(A.matrix[3,3]) ; if( r1 < r2 ) then r1 := r2 ; if( r1 < r3 ) then r1 := r3 ; result := r1 ; end; function nifti_mat33_colnorm( A: TMatrix ): single; //* max column norm of 3x3 matrix */ var r1,r2,r3: single ; begin r1 := abs(A.matrix[1,1])+abs(A.matrix[2,1])+abs(A.matrix[3,1]) ; r2 := abs(A.matrix[1,2])+abs(A.matrix[2,2])+abs(A.matrix[3,2]) ; r3 := abs(A.matrix[1,3])+abs(A.matrix[2,3])+abs(A.matrix[3,3]) ; if( r1 < r2 ) then r1 := r2 ; if( r1 < r3 ) then r1 := r3 ; result := r1 ; end; function nifti_mat33_inverse( R: TMatrix ): TMatrix; //* inverse of 3x3 matrix */ var r11,r12,r13,r21,r22,r23,r31,r32,r33 , deti: double ; Q: TMatrix ; begin FromMatrix(R,r11,r12,r13,r21,r22,r23,r31,r32,r33); deti := r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; if( deti <> 0.0 ) then deti := 1.0 / deti ; Q.matrix[1,1] := deti*( r22*r33-r32*r23) ; Q.matrix[1,2] := deti*(-r12*r33+r32*r13) ; Q.matrix[1,3] := deti*( r12*r23-r22*r13) ; Q.matrix[2,1] := deti*(-r21*r33+r31*r23) ; Q.matrix[2,2] := deti*( r11*r33-r31*r13) ; Q.matrix[2,3] := deti*(-r11*r23+r21*r13) ; Q.matrix[3,1] := deti*( r21*r32-r31*r22) ; Q.matrix[3,2] := deti*(-r11*r32+r31*r12) ; Q.matrix[3,3] := deti*( r11*r22-r21*r12) ; result := Q; end; function nifti_mat33_polar( A: TMatrix ): TMatrix; var k:integer; X , Y , Z: TMatrix ; dif,alp,bet,gam,gmi : single; begin dif := 1; k := 0; X := A ; // force matrix to be nonsingular //reportmatrix('x',X); gam := nifti_mat33_determ(X) ; while( gam = 0.0 )do begin //perturb matrix gam := 0.00001 * ( 0.001 + nifti_mat33_rownorm(X) ) ; X.matrix[1,1] := X.matrix[1,1]+gam ; X.matrix[2,2] := X.matrix[2,2]+gam ; X.matrix[3,3] := X.matrix[3,3] +gam ; gam := nifti_mat33_determ(X) ; end; while true do begin Y := nifti_mat33_inverse(X) ; if( dif > 0.3 )then begin // far from convergence alp := sqrt( nifti_mat33_rownorm(X) * nifti_mat33_colnorm(X) ) ; bet := sqrt( nifti_mat33_rownorm(Y) * nifti_mat33_colnorm(Y) ) ; gam := sqrt( bet / alp ) ; gmi := 1.0 / gam ; end else begin gam := 1.0; gmi := 1.0 ; //close to convergence end; Z.matrix[1,1] := 0.5 * ( gam*X.matrix[1,1] + gmi*Y.matrix[1,1] ) ; Z.matrix[1,2] := 0.5 * ( gam*X.matrix[1,2] + gmi*Y.matrix[2,1] ) ; Z.matrix[1,3] := 0.5 * ( gam*X.matrix[1,3] + gmi*Y.matrix[3,1] ) ; Z.matrix[2,1] := 0.5 * ( gam*X.matrix[2,1] + gmi*Y.matrix[1,2] ) ; Z.matrix[2,2] := 0.5 * ( gam*X.matrix[2,2] + gmi*Y.matrix[2,2] ) ; Z.matrix[2,3] := 0.5 * ( gam*X.matrix[2,3] + gmi*Y.matrix[3,2] ) ; Z.matrix[3,1] := 0.5 * ( gam*X.matrix[3,1] + gmi*Y.matrix[1,3] ) ; Z.matrix[3,2] := 0.5 * ( gam*X.matrix[3,2] + gmi*Y.matrix[2,3] ) ; Z.matrix[3,3] := 0.5 * ( gam*X.matrix[3,3] + gmi*Y.matrix[3,3] ) ; dif := abs(Z.matrix[1,1]-X.matrix[1,1])+abs(Z.matrix[1,2]-X.matrix[1,2]) +abs(Z.matrix[1,3]-X.matrix[1,3])+abs(Z.matrix[2,1]-X.matrix[2,1]) +abs(Z.matrix[2,2]-X.matrix[2,2])+abs(Z.matrix[2,3]-X.matrix[2,3]) +abs(Z.matrix[3,1]-X.matrix[3,1])+abs(Z.matrix[3,2]-X.matrix[3,2]) +abs(Z.matrix[3,3]-X.matrix[3,3]) ; k := k+1 ; if( k > 100) or (dif < 3.e-6 ) then begin result := Z; break ; //convergence or exhaustion end; X := Z ; end; result := Z ; end; procedure nifti_mat44_to_quatern( lR :TMatrix; var qb, qc, qd, qx, qy, qz, dx, dy, dz, qfac : single); var r11,r12,r13 , r21,r22,r23 , r31,r32,r33, xd,yd,zd , a,b,c,d : double; P,Q: TMatrix; //3x3 begin (* offset outputs are read write out of input matrix *) qx := lR.matrix[1,4]; qy := lR.matrix[2,4]; qz := lR.matrix[3,4]; (* load 3x3 matrix into local variables *) FromMatrix(lR,r11,r12,r13,r21,r22,r23,r31,r32,r33); (* compute lengths of each column; these determine grid spacings *) xd := sqrt( r11*r11 + r21*r21 + r31*r31 ) ; yd := sqrt( r12*r12 + r22*r22 + r32*r32 ) ; zd := sqrt( r13*r13 + r23*r23 + r33*r33 ) ; (* if a column length is zero, patch the trouble *) if( xd = 0.0 )then begin r11 := 1.0 ; r21 := 0; r31 := 0.0 ; xd := 1.0 ; end; if( yd = 0.0 )then begin r22 := 1.0 ; r12 := 0; r32 := 0.0 ; yd := 1.0 ; end; if( zd = 0.0 )then begin r33 := 1.0 ; r13 := 0; r23 := 0.0 ; zd := 1.0 ; end; (* assign the output lengths *) dx := xd; dy := yd; dz := zd; (* normalize the columns *) r11 := r11/xd ; r21 := r21/xd ; r31 := r31/xd ; r12 := r12/yd ; r22 := r22/yd ; r32 := r32/yd ; r13 := r13/zd ; r23 := r23/zd ; r33 := r33/zd ; (* At this point, the matrix has normal columns, but we have to allow for the fact that the hideous user may not have given us a matrix with orthogonal columns. So, now find the orthogonal matrix closest to the current matrix. One reason for using the polar decomposition to get this orthogonal matrix, rather than just directly orthogonalizing the columns, is so that inputting the inverse matrix to R will result in the inverse orthogonal matrix at this point. If we just orthogonalized the columns, this wouldn't necessarily hold. *) Q := Matrix2D (r11,r12,r13, // 2D "graphics" matrix r21,r22,r23, r31,r32,r33); P := nifti_mat33_polar(Q) ; (* P is orthog matrix closest to Q *) FromMatrix(P,r11,r12,r13,r21,r22,r23,r31,r32,r33); //ReportMatrix('xxx',Q); //ReportMatrix('svd',P); (* [ r11 r12 r13 ] *) (* at this point, the matrix [ r21 r22 r23 ] is orthogonal *) (* [ r31 r32 r33 ] *) (* compute the determinant to determine if it is proper *) zd := r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; (* should be -1 or 1 *) if( zd > 0 )then begin (* proper *) qfac := 1.0 ; end else begin (* improper ==> flip 3rd column *) qfac := -1.0 ; r13 := -r13 ; r23 := -r23 ; r33 := -r33 ; end; (* now, compute quaternion parameters *) a := r11 + r22 + r33 + 1.0; if( a > 0.5 ) then begin (* simplest case *) a := 0.5 * sqrt(a) ; b := 0.25 * (r32-r23) / a ; c := 0.25 * (r13-r31) / a ; d := 0.25 * (r21-r12) / a ; end else begin (* trickier case *) xd := 1.0 + r11 - (r22+r33) ; (* 4*b*b *) yd := 1.0 + r22 - (r11+r33) ; (* 4*c*c *) zd := 1.0 + r33 - (r11+r22) ; (* 4*d*d *) if( xd > 1.0 ) then begin b := 0.5 * sqrt(xd) ; c := 0.25* (r12+r21) / b ; d := 0.25* (r13+r31) / b ; a := 0.25* (r32-r23) / b ; end else if( yd > 1.0 ) then begin c := 0.5 * sqrt(yd) ; b := 0.25* (r12+r21) / c ; d := 0.25* (r23+r32) / c ; a := 0.25* (r13-r31) / c ; end else begin d := 0.5 * sqrt(zd) ; b := 0.25* (r13+r31) / d ; c := 0.25* (r23+r32) / d ; a := 0.25* (r21-r12) / d ; end; if( a < 0.0 )then begin b:=-b ; c:=-c ; d:=-d; {a:=-a; this is not used} end; end; qb := b ; qc := c ; qd := d ; //fx(qb,qc,qd); end; procedure nifti_quatern_to_mat44( var lR :TMatrix; var qb, qc, qd, qx, qy, qz, dx, dy, dz, qfac : single); var a,b,c,d,xd,yd,zd: double; begin //a := qb; b := qb; c := qc; d := qd; //* last row is always [ 0 0 0 1 ] */ lR.matrix[4,1] := 0; lR.matrix[4,2] := 0; lR.matrix[4,3] := 0; lR.matrix[4,4] := 1; //* compute a parameter from b,c,d */ a := 1.0 - (b*b + c*c + d*d) ; if( a < 1.e-7 ) then begin//* special case */ a := 1.0 / sqrt(b*b+c*c+d*d) ; b := b*a ; c := c*a ; d := d*a ;//* normalize (b,c,d) vector */ a := 0.0 ;//* a = 0 ==> 180 degree rotation */ end else begin a := sqrt(a) ; //* angle = 2*arccos(a) */ end; //* load rotation matrix, including scaling factors for voxel sizes */ if dx > 0 then xd := dx else xd := 1; if dy > 0 then yd := dy else yd := 1; if dz > 0 then zd := dz else zd := 1; if( qfac < 0.0 ) then zd := -zd ;//* left handedness? */ lR.matrix[1,1]:= (a*a+b*b-c*c-d*d) * xd ; lR.matrix[1,2]:= 2.0 * (b*c-a*d ) * yd ; lR.matrix[1,3]:= 2.0 * (b*d+a*c ) * zd ; lR.matrix[2,1]:= 2.0 * (b*c+a*d ) * xd ; lR.matrix[2,2]:= (a*a+c*c-b*b-d*d) * yd ; lR.matrix[2,3]:= 2.0 * (c*d-a*b ) * zd ; lR.matrix[3,1]:= 2.0 * (b*d-a*c ) * xd ; lR.matrix[3,2]:= 2.0 * (c*d+a*b ) * yd ; lR.matrix[3,3]:= (a*a+d*d-c*c-b*b) * zd ; //* load offsets */ lR.matrix[1,4]:= qx ; lR.matrix[2,4]:= qy ; lR.matrix[3,4]:= qz ; end; function TryQuat2Matrix( var lHdr: TNIfTIHdr ): boolean; var lR :TMatrix; begin result := false; if (lHdr.qform_code <= kNIFTI_XFORM_UNKNOWN) or (lHdr.qform_code > kNIFTI_XFORM_MNI_152) then exit; result := true; nifti_quatern_to_mat44(lR,lHdr.quatern_b,lHdr.quatern_c,lHdr.quatern_d, lHdr.qoffset_x,lHdr.qoffset_y,lHdr.qoffset_z, lHdr.pixdim[1],lHdr.pixdim[2],lHdr.pixdim[3], lHdr.pixdim[0]); lHdr.srow_x[0] := lR.matrix[1,1]; lHdr.srow_x[1] := lR.matrix[1,2]; lHdr.srow_x[2] := lR.matrix[1,3]; lHdr.srow_x[3] := lR.matrix[1,4]; lHdr.srow_y[0] := lR.matrix[2,1]; lHdr.srow_y[1] := lR.matrix[2,2]; lHdr.srow_y[2] := lR.matrix[2,3]; lHdr.srow_y[3] := lR.matrix[2,4]; lHdr.srow_z[0] := lR.matrix[3,1]; lHdr.srow_z[1] := lR.matrix[3,2]; lHdr.srow_z[2] := lR.matrix[3,3]; lHdr.srow_z[3] := lR.matrix[3,4]; lHdr.sform_code := 1; end; {procedure ReportMatrix (lM:TMatrix); var lStr: string; begin lStr := ( RealToStr(lM.matrix[1,1],6)+','+RealToStr(lM.matrix[1,2],6)+','+RealToStr(lM.matrix[1,3],6)+','+RealToStr(lM.matrix[1,4],6)) +kCR+( RealToStr(lM.matrix[2,1],6)+','+RealToStr(lM.matrix[2,2],6)+','+RealToStr(lM.matrix[2,3],6)+','+RealToStr(lM.matrix[2,4],6)) +kCR+( RealToStr(lM.matrix[3,1],6)+','+RealToStr(lM.matrix[3,2],6)+','+RealToStr(lM.matrix[3,3],6)+','+RealToStr(lM.matrix[3,4],6)) +kCR+( RealToStr(lM.matrix[4,1],6)+','+RealToStr(lM.matrix[4,2],6)+','+RealToStr(lM.matrix[4,3],6)+','+RealToStr(lM.matrix[4,4],6)); showmessage(lStr); end; } function FixDataType (var lHdr: TMRIcroHdr {; lCompress: boolean}): boolean; //correct mistakes of datatype and bitpix - especially for software which only sets one label 191; var ldatatypebpp,lbitpix: integer; begin result := true; lbitpix := lHdr.NIFTIhdr.bitpix; case lHdr.NIFTIhdr.datatype of kDT_BINARY : ldatatypebpp := 1; kDT_UNSIGNED_CHAR : ldatatypebpp := 8; // unsigned char (8 bits/voxel) kDT_SIGNED_SHORT : ldatatypebpp := 8; // signed short (16 bits/voxel) kDT_SIGNED_INT : ldatatypebpp := 32; // signed int (32 bits/voxel) kDT_FLOAT : ldatatypebpp := 32; // float (32 bits/voxel) kDT_COMPLEX : ldatatypebpp := 64; // complex (64 bits/voxel) kDT_DOUBLE : ldatatypebpp := 64; // double (64 bits/voxel) kDT_RGB : ldatatypebpp := 24; // RGB triple (24 bits/voxel) kDT_INT8 : ldatatypebpp := 8; // signed char (8 bits) kDT_UINT16 : ldatatypebpp := 16; // unsigned short (16 bits) kDT_UINT32 : ldatatypebpp := 32; // unsigned int (32 bits) kDT_INT64 : ldatatypebpp := 64; // long long (64 bits) kDT_UINT64 : ldatatypebpp := 64; // unsigned long long (64 bits) kDT_FLOAT128 : ldatatypebpp := 128; // long double (128 bits) kDT_COMPLEX128 : ldatatypebpp := 128; // double pair (128 bits) kDT_COMPLEX256 : ldatatypebpp := 256; // long double pair (256 bits) else ldatatypebpp := 0; end; if (ldatatypebpp = lHdr.NIFTIhdr.bitpix) and (ldatatypebpp <> 0) then exit; if (lbitpix = 0) and (ldatatypebpp <> 0) then begin //use bitpix from datatype... lHdr.NIFTIhdr.bitpix := ldatatypebpp; exit; end; if (lbitpix <> 0) and (ldatatypebpp = 0) then begin //assume bitpix is correct.... //note that several datatypes correspond to each bitpix, so assume most popular... case lbitpix of 1: lHdr.NIFTIhdr.datatype := kDT_BINARY; 8: lHdr.NIFTIhdr.datatype := kDT_UNSIGNED_CHAR; 16: lHdr.NIFTIhdr.datatype := kDT_SIGNED_SHORT; 24: lHdr.NIFTIhdr.datatype := kDT_RGB; 32: lHdr.NIFTIhdr.datatype := kDT_FLOAT; 64: lHdr.NIFTIhdr.datatype := kDT_DOUBLE; else goto 191; //impossible bitpix end; exit; end; 191: //Both bitpix and datatype are wrong... assume most popular format lHdr.NIFTIhdr.bitpix := 16; lHdr.NIFTIhdr.datatype := kDT_SIGNED_SHORT; //fx(lHdr.NIFTIhdr.bitpix, lHdr.NIFTIhdr.datatype); end; function NIFTIhdr_LoadHdr (var lFilename: string; var lHdr: TMRIcroHdr): boolean; var lHdrFile: file; lOri: array [1..3] of single; lBuff: Bytep; lAHdr: TAnalyzeHdrSection; lFileSz : int64; swapEndian: boolean; lReportedSz, lSwappedReportedSz,lHdrSz: Longint; lExt: string; //1494 begin Result := false; //assume error if lFilename = '' then exit; lExt := UpCaseExt(lFilename); if lExt = '.IMG' then lFilename := changeFileExt(lFilename,'.hdr'); if (lExt = '.BRIK') or (lExt = '.BRIK.GZ') then lFilename := changeFileExtX(lFilename,'.HEAD'); lExt := UpCaseExt(lFilename); lHdrSz := sizeof(TniftiHdr); lFileSz := FSize (lFilename); if lFileSz = 0 then begin ShowMsg('Unable to find NIFTI header named '+lFilename+'. Possible solution: make sure VAL file and images are in the same folder.'); exit; end; swapEndian := false; lHdr.gzBytesX := K_gzBytes_headerAndImageUncompressed; lHdr.ImgFileName:= lFilename ; lHdr.HdrFileName:= lFilename ; FileMode := fmOpenRead; //Set file access to read only if (lExt = '.MGH') or (lExt = '.MGZ') or (lExt = '.MHD') or (lExt = '.MHA') or (lExt = '.NRRD') or (lExt = '.NHDR') or (lExt = '.HEAD') then begin result := readForeignHeader( lFilename, lHdr.NIFTIhdr,lHdr.gzBytesX, swapEndian); //we currently ignore result! lHdr.ImgFileName := lFilename; end else begin //native NIfTI if (lExt = '.NII.GZ') or (lExt = '.VOI') or (lExt = '.GZ') then begin//1388 lBuff := @lHdr; UnGZip(lFileName,lBuff,0,lHdrSz); //1388 lHdr.gzBytesX := K_gzBytes_headerAndImageCompressed; end else begin //if gzip else uncompressed if (lFileSz < lHdrSz) then begin showmsg('Error in reading NIFTI header: NIfTI headers need to be at least '+inttostr(lHdrSz)+ ' bytes: '+lFilename); result := false; end else begin {$I-} AssignFile(lHdrFile, lFileName); FileMode := 0; { Set file access to read only } Reset(lHdrFile, 1); {$I+} if ioresult <> 0 then begin ShowMessage('Error in reading NIFTI header.'+inttostr(IOResult)); CloseFile(lHdrFile); FileMode := fmOpenReadWrite; exit; end; BlockRead(lHdrFile, lHdr, lHdrSz); CloseFile(lHdrFile); if (lExt = '.HDR') then lHdr.ImgFileName:= changefileext(lFilename,'.img'); end; end; end; //native NIFTI FileMode := fmOpenReadWrite; if (IOResult <> 0) then exit; lReportedSz := lHdr.niftiHdr.HdrSz; lSwappedReportedSz := lReportedSz; swap4(lSwappedReportedSz); lHdr.NIFTIVersion := 1; if lReportedSz = lHdrSz then begin lHdr.DiskDataNativeEndian := true; end else if lSwappedReportedSz = lHdrSz then begin lHdr.DiskDataNativeEndian := false; NIFTIhdr_SwapBytes (lHdr.niftiHdr); end else begin result := NIFTIhdr_LoadDCM (lFilename,lHdr); //2/2008 if not result then ShowMsg('Warning: the header file is not in NIfTi format [the first 4 bytes do not have the value 348]. Assuming big-endian data.'); exit; end; if (lHdr.NIFTIhdr.dim[0] > 7) or (lHdr.NIFTIhdr.dim[0] < 1) then begin //only 1..7 dims, so this ShowMsg('Illegal NIfTI Format Header: this header does not specify 1..7 dimensions.'); exit; end; FixDataType(lHdr); result := true; //tx('nHdr',lHdr.NIFTIhdr.srow_x[3]); (*lHdr.HdrFileName:= lFilename; if ((lHdr.niftiHdr.magic = kNIFTI_MAGIC_EMBEDDED_HDR) and (lFileSz > lHdrSz)) or (lExt = '.NII.GZ') or (lExt = '.VOI') or (lExt = '.NII'){1494} then lHdr.ImgFileName:= lFilename else lHdr.ImgFileName:= changefileext(lFilename,'.img'); *) if IsNifTiMagic(lHdr.niftiHdr) then begin //must match MAGMA in nifti_img lOri[1] := (lHdr.NIFTIhdr.dim[1]+1) div 2; lOri[2] := (lHdr.NIFTIhdr.dim[2]+1) div 2; lOri[3] := (lHdr.NIFTIhdr.dim[3]+1) div 2; //TryQuat2Matrix(lHdr.NiftiHdr); if (lHdr.NIFTIhdr.sform_code <= kNIFTI_XFORM_UNKNOWN) or (lHdr.NIFTIhdr.sform_code > kNIFTI_XFORM_MNI_152) then TryQuat2Matrix(lHdr.NiftiHdr); if emptymatrix(lHdr) then begin (*if HasQuat(lHdr.NiftiHdr) then //HasQuat will specify else*) begin lHdr.NIFTIhdr.srow_x[0] := lHdr.NIFTIhdr.pixdim[1]; lHdr.NIFTIhdr.srow_x[1] := 0; lHdr.NIFTIhdr.srow_x[2] := 0; lHdr.NIFTIhdr.srow_y[0] := 0; lHdr.NIFTIhdr.srow_y[1] := lHdr.NIFTIhdr.pixdim[2]; lHdr.NIFTIhdr.srow_y[2] := 0; lHdr.NIFTIhdr.srow_z[0] := 0; lHdr.NIFTIhdr.srow_z[1] := 0; lHdr.NIFTIhdr.srow_z[2] := lHdr.NIFTIhdr.pixdim[3]; lHdr.NIFTIhdr.srow_x[3] := -round(lHdr.NIFTIhdr.dim[1]*lHdr.NIFTIhdr.pixdim[1]*0.5); lHdr.NIFTIhdr.srow_y[3] := -round(lHdr.NIFTIhdr.dim[2]*lHdr.NIFTIhdr.pixdim[2]*0.5); lHdr.NIFTIhdr.srow_z[3] := -round(lHdr.NIFTIhdr.dim[3]*lHdr.NIFTIhdr.pixdim[3]*0.5); lHdr.NIFTIhdr.sform_code := 1; end; end; if (lHdr.NIFTIhdr.srow_x[0] > 0) and (lHdr.NIFTIhdr.srow_y[1] > 0) and (lHdr.NIFTIhdr.srow_z[2] > 0) and (lHdr.NIFTIhdr.srow_x[3] > 0) and (lHdr.NIFTIhdr.srow_y[3] > 0) and (lHdr.NIFTIhdr.srow_z[3] > 0) then begin lHdr.NIFTIhdr.srow_x[3] := -lHdr.NIFTIhdr.srow_x[3]; lHdr.NIFTIhdr.srow_y[3] := -lHdr.NIFTIhdr.srow_y[3]; lHdr.NIFTIhdr.srow_z[3] := -lHdr.NIFTIhdr.srow_z[3]; lHdr.NIFTIhdr.sform_code := 1; end; //added 4Mar2006 -> corrects for improperly signed offset values... lHdr.NIfTItransform := true;//NIfTI 12/2010 end else begin //not NIFT: Analyze lHdr.NIfTItransform := false;//Analyze if not lHdr.DiskDataNativeEndian then begin NIFTIhdr_SwapBytes (lHdr.niftiHdr); move(lHdr.niftiHdr,lAHdr,sizeof(lAHdr)); NIFTIhdr_SwapBytes (lHdr.niftiHdr); lAHdr.Originator[1] := swap(lAHdr.Originator[1]); lAHdr.Originator[2] := swap(lAHdr.Originator[2]); lAHdr.Originator[3] := swap(lAHdr.Originator[3]); end else move(lHdr.niftiHdr,lAHdr,sizeof(lAHdr)); lOri[1] :=lAHdr.Originator[1]; lOri[2] := lAHdr.Originator[2]; lOri[3] := lAHdr.Originator[3]; if (lOri[1]=76) and (lOri[2]=116) and (lOri[3]=64) and (lHdr.NIFTIhdr.dim[1]=151) and (lHdr.NIFTIhdr.dim[2]=188) and (lHdr.NIFTIhdr.dim[3]=154) then begin lOri[2] := 111; lOri[3] := 68; end; //2/2008 Juelich fudge factor if ((lOri[1]<1) or (lOri[1]> lHdr.NIFTIhdr.dim[1])) and ((lOri[2]<1) or (lOri[2]> lHdr.NIFTIhdr.dim[2])) and ((lOri[3]<1) or (lOri[3]> lHdr.NIFTIhdr.dim[3])) then begin lOri[1] := (lHdr.NIFTIhdr.dim[1]+1) / 2; //May07 use / not div lOri[2] := (lHdr.NIFTIhdr.dim[2]+1) / 2; //May07 use / not div lOri[3] := (lHdr.NIFTIhdr.dim[3]+1) / 2; //May07 use / not div : if 20 slices, then origin is between 10 and 11 end; //showmessage(inttostr(sizeof(lAHdr))+' '+realtostr(lHdr.Ori[1],1)+' '+ realtostr(lHdr.Ori[2],1)+' '+realtostr(lHdr.Ori[3],1) ); //DANGER: This header was from ANALYZE format, not NIFTI: make sure the rotation matrix is switched off NIFTIhdr_SetIdentityMatrix(lHdr); lHdr.NIFTIhdr.qform_code := kNIFTI_XFORM_UNKNOWN; lHdr.NIFTIhdr.sform_code := kNIFTI_XFORM_UNKNOWN; //test - input estimated orientation matrix lHdr.NIFTIhdr.sform_code := kNIFTI_XFORM_SCANNER_ANAT ; lHdr.NIFTIhdr.srow_x[0] := lHdr.NIFTIhdr.pixdim[1]; lHdr.NIFTIhdr.srow_y[1] := lHdr.NIFTIhdr.pixdim[2]; lHdr.NIFTIhdr.srow_z[2] := lHdr.NIFTIhdr.pixdim[3]; lHdr.NIFTIhdr.srow_x[3] := (lOri[1]-1)*-lHdr.NIFTIhdr.pixdim[1]; lHdr.NIFTIhdr.srow_y[3] := (lOri[2]-1)*-lHdr.NIFTIhdr.pixdim[2]; lHdr.NIFTIhdr.srow_z[3] := (lOri[3]-1)*-lHdr.NIFTIhdr.pixdim[3]; //fx(lHdr.NIFTIhdr.srow_z[3],lOri[3]); //end test //Warning: some of the NIFTI float values that do exist as integer values in Analyze may have bizarre values like +INF, -INF, NaN lHdr.NIFTIhdr.toffset := 0; lHdr.NIFTIhdr.intent_code := kNIFTI_INTENT_NONE; lHdr.NIFTIhdr.dim_info := kNIFTI_SLICE_SEQ_UNKNOWN + (kNIFTI_SLICE_SEQ_UNKNOWN shl 2) + (kNIFTI_SLICE_SEQ_UNKNOWN shl 4); //Freq, Phase and Slice order all unknown lHdr.NIFTIhdr.xyzt_units := kNIFTI_UNITS_UNKNOWN; lHdr.NIFTIhdr.slice_duration := 0; //avoid +inf/-inf, NaN lHdr.NIFTIhdr.intent_p1 := 0; //avoid +inf/-inf, NaN lHdr.NIFTIhdr.intent_p2 := 0; //avoid +inf/-inf, NaN lHdr.NIFTIhdr.intent_p3 := 0; //avoid +inf/-inf, NaN lHdr.NIFTIhdr.pixdim[0] := 1; //QFactor should be 1 or -1 end; if (lHdr.NIFTIhdr.sform_code > kNIFTI_XFORM_UNKNOWN) and (lHdr.NIFTIhdr.sform_code <= kNIFTI_XFORM_MNI_152) then begin //DEC06 lHdr.Mat:= Matrix3D( lHdr.NIFTIhdr.srow_x[0],lHdr.NIFTIhdr.srow_x[1],lHdr.NIFTIhdr.srow_x[2],lHdr.NIFTIhdr.srow_x[3], // 3D "graphics" matrix lHdr.NIFTIhdr.srow_y[0],lHdr.NIFTIhdr.srow_y[1],lHdr.NIFTIhdr.srow_y[2],lHdr.NIFTIhdr.srow_y[3], // 3D "graphics" matrix lHdr.NIFTIhdr.srow_z[0],lHdr.NIFTIhdr.srow_z[1],lHdr.NIFTIhdr.srow_z[2],lHdr.NIFTIhdr.srow_z[3], // 3D "graphics" matrix 0,0,0,1); end else begin lHdr.Mat:= Matrix3D( lHdr.NIFTIhdr.pixdim[1],0,0,(lOri[1]-1)*-lHdr.NIFTIhdr.pixdim[1], // 3D "graphics" matrix 0,lHdr.NIFTIhdr.pixdim[2],0,(lOri[2]-1)*-lHdr.NIFTIhdr.pixdim[2], // 3D "graphics" matrix 0,0,lHdr.NIFTIhdr.pixdim[3],(lOri[3]-1)*-lHdr.NIFTIhdr.pixdim[3], // 3D "graphics" matrix 0,0,0,1); end; FixCrapMat(lHdr.Mat); if swapEndian then lHdr.DiskDataNativeEndian := false;//foreign data with swapped image data //ReportMatrix(lHdr.mat); end; //func NIFTIhdr_LoadHdr procedure NIFTIhdr_SetIdentityMatrix (var lHdr: TMRIcroHdr); //create neutral rotation matrix var lInc: integer; begin with lHdr.NIFTIhdr do begin for lInc := 0 to 3 do srow_x[lInc] := 0; for lInc := 0 to 3 do srow_y[lInc] := 0; for lInc := 0 to 3 do srow_z[lInc] := 0; for lInc := 1 to 16 do intent_name[lInc] := chr(0); //next: create identity matrix: if code is switched on there will not be a problem srow_x[0] := 1; srow_y[1] := 1; srow_z[2] := 1; end; end; //proc NIFTIhdr_IdentityMatrix procedure NIFTIhdr_ClearHdr (var lHdr: TMRIcroHdr); //put sensible default values into header var lInc: byte; begin lHdr.NIFTIVersion := 1; lHdr.UsesCustomPalette := false; lHdr.UsesCustomPaletteRandomRainbow:= false; lHdr.UsesLabels := false; lHdr.DiskDataNativeEndian := true; lHdr.LutFromZero := false; lHdr.NIfTItransform := true;//assume genuine NIfTI, not Analyze with lHdr.NIFTIhdr do begin {set to 0} HdrSz := sizeof(TNIFTIhdr); for lInc := 1 to 10 do Data_Type[lInc] := chr(0); for lInc := 1 to 18 do db_name[lInc] := chr(0); extents:=0; session_error:= 0; regular:='r'{chr(0)}; dim_info:=(0); dim[0] := 4; for lInc := 1 to 7 do dim[lInc] := 0; intent_p1 := 0; intent_p2 := 0; intent_p3 := 0; intent_code:=0; datatype:=0 ; bitpix:=0; slice_start:=0; for lInc := 1 to 7 do pixdim[linc]:= 1.0; vox_offset:= 0.0; scl_slope := 1.0; scl_inter:= 0.0; slice_end:= 0; slice_code := 0; xyzt_units := 10; cal_max:= 0.0; cal_min:= 0.0; slice_duration:=0; toffset:= 0; glmax:= 0; glmin:= 0; for lInc := 1 to 80 do descrip[lInc] := chr(0);{80 spaces} for lInc := 1 to 24 do aux_file[lInc] := chr(0);{80 spaces} {below are standard settings which are not 0} bitpix := 16;//vc16; {8bits per pixel, e.g. unsigned char 136} DataType := 4;//vc4;{2=unsigned char, 4=16bit int 136} Dim[0] := 3; Dim[1] := 256; Dim[2] := 256; Dim[3] := 128; Dim[4] := 1; {n vols} Dim[5] := 1; Dim[6] := 1; Dim[7] := 1; glMin := 0; glMax := 255; qform_code := kNIFTI_XFORM_UNKNOWN; sform_code:= kNIFTI_XFORM_UNKNOWN; quatern_b := 0; quatern_c := 0; quatern_d := 0; qoffset_x := 0; qoffset_y := 0; qoffset_z := 0; NIFTIhdr_SetIdentityMatrix(lHdr); magic := kNIFTI_MAGIC_SEPARATE_HDR; end; //with the NIfTI header... with lHdr do begin ScrnBufferItems := 0; ImgBufferItems := 0; ImgBufferBPP := 0; RenderBufferItems := 0; ScrnBuffer:= nil; ImgBuffer := nil; end; end; //proc NIFTIhdr_ClearHdr function NIFTIhdr_SaveHdr (var lFilename: string; var lHdr: TNIFTIHdr; lAllowOverwrite,lSPM2: boolean): boolean; overload; var lOutHdr: TNIFTIhdr; lExt: string; lF: File; lOverwrite: boolean; begin lOverwrite := false; //will we overwrite existing file? result := false; //assume failure if lHdr.magic = kNIFTI_MAGIC_EMBEDDED_HDR then begin lExt := UpCaseExt(lFileName); if (lExt = '.GZ') or (lExt = '.NII.GZ') then begin ShowMessage('Unable to save .nii.gz headers (first ungzip your image if you wish to edit the header)'); exit; end; lFilename := changefileext(lFilename,'.nii') end else lFilename := changefileext(lFilename,'.hdr'); if ((sizeof(TNIFTIhdr))> DiskFreeEx(lFileName)) then begin ShowMessage('There is not enough free space on the destination disk to save the header. '+kCR+ lFileName+ kCR+' Bytes Required: '+inttostr(sizeof(TNIFTIhdr)) ); exit; end; if Fileexists(lFileName) then begin if lAllowOverwrite then begin {$IFNDEF GUI} ShowMsg('Overwriting '+lFilename); lOverwrite := true; {$ELSE} case MessageDlg('Do you wish to modify the existing file '+lFilename+'?', mtConfirmation,[mbYes, mbNo], 0) of { produce the message dialog box } 6: lOverwrite := true; //6= mrYes, 7=mrNo... not sure what this is for Linux. Hardcoded as we do not include Form values end;//case {$ENDIF} end else showmessage('Error: the file '+lFileName+' already exists.'); if not lOverwrite then Exit; end; if lHdr.magic = kNIFTI_MAGIC_EMBEDDED_HDR then if lHdr.vox_offset < sizeof(TNIFTIHdr) then lHdr.vox_offset := sizeof(TNIFTIHdr); //embedded images MUST start after header if lHdr.magic = kNIFTI_MAGIC_SEPARATE_HDR then lHdr.vox_offset := 0; //embedded images MUST start after header if lSPM2 then begin //SPM2 does not recognize NIfTI - origin values will be wrong lHdr.magic := 0; end; result := true; move(lHdr, lOutHdr, sizeof(lOutHdr)); Filemode := 1; AssignFile(lF, lFileName); {WIN} if lOverwrite then //this allows us to modify just the 348byte header of an existing NII header without touching image data Reset(lF,sizeof(TNIFTIhdr)) else Rewrite(lF,sizeof(TNIFTIhdr)); BlockWrite(lF,lOutHdr, 1 {, NumWritten}); CloseFile(lF); Filemode := 2; end; //func NIFTIhdr_SaveHdr function NIFTIhdr_SaveHdr (var lFilename: string; var lHdr: TMRIcroHdr; lAllowOverwrite: boolean): boolean; overload; var lOutHdr: TNIFTIhdr; lExt: string; lF: File; lOverwrite: boolean; begin lOverwrite := false; //will we overwrite existing file? result := false; //assume failure if lHdr.NIFTIhdr.magic = kNIFTI_MAGIC_EMBEDDED_HDR then begin lExt := UpCaseExt(lFileName); if (lExt = '.GZ') or (lExt = '.NII.GZ') then begin showmessage('Unable to save .nii.gz headers (first ungzip your image if you wish to edit the header)'); exit; end; lFilename := changefileext(lFilename,'.nii') end else lFilename := changefileext(lFilename,'.hdr'); if ((sizeof(TNIFTIhdr))> DiskFreeEx(lFileName)) then begin ShowMessage('There is not enough free space on the destination disk to save the header. '+kCR+ lFileName+ kCR+' Bytes Required: '+inttostr(sizeof(TNIFTIhdr)) ); exit; end; if Fileexists(lFileName) then begin if lAllowOverwrite then begin {$IFNDEF GUI} ShowMsg('Overwriting '+lFilename); lOverwrite := true; {$ELSE} case MessageDlg('Do you wish to modify the existing file '+lFilename+'?', mtConfirmation,[mbYes, mbNo], 0) of { produce the message dialog box } 6: lOverwrite := true; //6= mrYes, 7=mrNo... not sure what this is for unix. Hardcoded as we do not include Form values end;//case {$ENDIF} end else showmessage('Error: the file '+lFileName+' already exists.'); if not lOverwrite then Exit; end; if lHdr.NIFTIhdr.magic = kNIFTI_MAGIC_EMBEDDED_HDR then if lHdr.NIFTIhdr.vox_offset < sizeof(TNIFTIHdr) then lHdr.NIFTIhdr.vox_offset := sizeof(TNIFTIHdr); //embedded images MUST start after header if lHdr.NIFTIhdr.magic = kNIFTI_MAGIC_SEPARATE_HDR then lHdr.NIFTIhdr.vox_offset := 0; //embedded images MUST start after header result := true; move(lHdr.NIFTIhdr, lOutHdr, sizeof(lOutHdr)); if lHdr.DiskDataNativeEndian= false then NIFTIhdr_SwapBytes (lOutHdr);{swap to big-endianformat} Filemode := 1; AssignFile(lF, lFileName); {WIN} if lOverwrite then //this allows us to modify just the 348byte header of an existing NII header without touching image data Reset(lF,sizeof(TNIFTIhdr)) else Rewrite(lF,sizeof(TNIFTIhdr)); BlockWrite(lF,lOutHdr, 1 {, NumWritten}); CloseFile(lF); Filemode := 2; end; //func NIFTIhdr_SaveHdr procedure NIFTIhdr_SwapBytes (var lAHdr: TNIFTIhdr); //Swap Byte order for the Analyze type var lInc: integer; begin with lAHdr do begin swap4(hdrsz); swap4(extents); session_error := swap(session_error); for lInc := 0 to 7 do dim[lInc] := swap(dim[lInc]); Xswap4r(intent_p1); Xswap4r(intent_p2); Xswap4r(intent_p3); intent_code:= swap(intent_code); datatype:= swap(datatype); bitpix := swap(bitpix); slice_start:= swap(slice_start); for lInc := 0 to 7 do Xswap4r(pixdim[linc]); Xswap4r(vox_offset); Xswap4r(scl_slope); Xswap4r(scl_inter); slice_end := swap(slice_end); Xswap4r(cal_max); Xswap4r(cal_min); Xswap4r(slice_duration); Xswap4r(toffset); swap4(glmax); swap4(glmin); qform_code := swap(qform_code); sform_code:= swap(sform_code); Xswap4r(quatern_b); Xswap4r(quatern_c); Xswap4r(quatern_d); Xswap4r(qoffset_x); Xswap4r(qoffset_y); Xswap4r(qoffset_z); for lInc := 0 to 3 do //alpha Xswap4r(srow_x[lInc]); for lInc := 0 to 3 do //alpha Xswap4r(srow_y[lInc]); for lInc := 0 to 3 do //alpha Xswap4r(srow_z[lInc]); end; //with NIFTIhdr end; //proc NIFTIhdr_SwapBytes end. ��������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/gziod.pas���������������������������������������������������0000755�0001750�0001750�00000036467�12306703152�017333� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Unit gziod;//GZip input/output for delphi interface uses define_types,gzio,Windows,sysutils; procedure UnGZip2 (var lFname: string; var lBuf: ByteP{}; lOffset,lMaxSz: integer; Skip: int64); //unzip procedure UnGZip (var lFname: string; var lBuf: ByteP{}; lOffset,lMaxSz: integer); //unzip procedure UnGZipCore (var infile : gzFile; var lBuf: ByteP; lReadBytes: integer; lWrite: boolean); function Gunzip (var FFileSource,FFileDestination: string): integer; procedure GZipBuffer(var lFilename: String;lxInBuffer: byteP;lInSize: Integer; lOverwritewarn: boolean); procedure GZipFile(lSrcName,lDestName: String;lDeleteSrc: boolean); procedure UnGZipFile (var lFname,lOUtname: string); //unzip implementation {$include isgui.inc} {$IFDEF GUI}uses dialogs;{$ELSE} uses dialogsx;{$ENDIF} function gz_compressBuffer (lxInBuffer: ByteP;lInSize: integer;outfile:gzFile): integer; var len : Integer; lInBufferPos,ioerr : integer; buf : packed array [0..Z_BUFSIZE-1] of byte; { Global uses BSS instead of stack } //lInBufPtr,lOutbufPtr: pointer; errorcode : byte; //fsize, lensize : DWord; function blocktransfer(var lInBuffer: ByteP; lSizeRequested: integer; var lSizeTransferred:integer): integer; begin result := 0; if lInBufferPos > lInSize then begin result := 666; exit; end else if (lInBufferPos + lSizeRequested) <= lInSize then lSizeTransferred := lSizeRequested else lSizeTransferred := lInSize-lInBufferPos; //for lC := 1 to lSizeTransferred do // buf[lC-1] := lInBuffer[lInBufferPos+lC] ; move(lInbuffer[lInBufferPos+1],buf,lSizeTransferred); //move(src,dest,count); lInBufferPos := lInBufferPos+lSizeTransferred; end; begin //showmessage(inttostr(Z_BUFSIZE)); lInBufferPos := 0; errorcode := 0; //Progress := 0; //fsize := lInSize; //lensize := 0; //if FProgressStep > 0 then DoOnProgress; while true do begin //lll{$I-}blockread (infile, buf, Z_BUFSIZE, len);{$I+} ioerr := blocktransfer(lxInBuffer,Z_BUFSIZE, len); if (ioerr <> 0) then begin errorcode := 1; break end; if (len = 0) then break; {$WARNINGS OFF}{Comparing signed and unsigned types} if (gzwrite (outfile, @buf, len) <> len) then begin {$WARNINGS OFF} errorcode := 2; break end; end; {WHILE} if (gzclose (outfile) <> 0{Z_OK}) then errorcode := 3; result := errorcode; end; procedure GZipBuffer(var lFilename: String;lxInBuffer: byteP;lInSize: Integer; lOverwritewarn: boolean); var FFileDestination,FGzipComments ,outmode,s : string; infile : file; outfile : gzFile; FCompressionLevel{,errorcode} : integer; flags : uInt; stream : gz_streamp; p : PChar; begin FGzipComments := ''; FFileDestination := lFilename; //if not GzExt(FFileDestination) then // FFileDestination := FFileDestination + '.gz'; FCompressionLevel := 6;//MainForm.CompressEdit.value; if (FCompressionLevel > 9) or (FCompressionLevel<0) then FCompressionLevel := 6; if lOverwritewarn and fileexists(FFileDestination) then begin {$IFDEF GUI} case MessageDlg('Overwrite the file '+FFileDestination+'?', mtConfirmation,[mbYes, mbAbort], 0) of { produce the message dialog box } id_Abort: exit; end; {$ELSE} case MsgDlg('Overwrite the file '+FFileDestination+'?', mtConfirmation,[mbYes, mbAbort], 0) of { produce the message dialog box } id_Abort: exit; end; {$ENDIF} end; //w adds .gz extension-> outmode := 'w '; outmode := 'w '; s := IntToStr(FCompressionLevel); outmode[2] := s[1]; outmode[3] := ' '; flags := ORIG_NAME; //if (comment in FGzipHeader) then flags := flags + COMMENT_; outfile := gzopenZ (FFileDestination, outmode, flags); //showmessage(FFileDestination); if (outfile = NIL) then begin //if FWindowOnError then {$IFDEF GUI} MessageDlg('Can''t open: '+FFileDestination, mtError, [mbAbort], 0); {$ELSE} MsgDlg('Can''t open: '+FFileDestination, mtError, [mbAbort], 0); {$ENDIF} close( infile); //errorcode := 2 exit; end else begin { if flags are set then write them } stream := gz_streamp(outfile); if {(zfilename in FGzipHeader)} true then begin //s := ExtractFilename(lInFileName); //s := ExtractFilename(FGzipFilename); s := ExtractFilename(changefileext(FFileDestination,'')); p := PChar(s); blockWrite( stream^.gzfile, p[0], length(s)+1); stream^.startpos := stream^.startpos + length(s) + 1 end; gz_compressBuffer (lxInBuffer,lInSize,outfile); end end; function gz_uncompress (infile:gzFile; var outfile:file;fsize:DWord{LongWord}) : integer; var len : integer; written : uInt; buf : packed array [0..Z_BUFSIZE-1] of byte; { Global uses BSS instead of stack } errorcode : byte; lensize : DWord{LongWord}; begin errorcode := 0; //FProgress := 0; lensize := 0; //if FProgressStep > 0 then DoOnProgress; while true do begin len := gzread (infile, @buf, Z_BUFSIZE); if (len < 0) then begin errorcode := 1; break end; if (len = 0) then break; {$I-} blockwrite (outfile, buf, len, written); {$I+} {$WARNINGS OFF}{Comparing signed and unsigned types} if (written <> len) then begin {$WARNINGS ON} errorcode := 2; break end; (*if FProgressStep > 0 then begin {$WARNINGS OFF} lensize := lensize + len; if ((lensize / fsize) * 100 >= FProgress + FProgressStep) or (lensize = fsize) then begin FProgress := Trunc((lensize / fsize) * 100); DoOnProgress end {$WARNINGS ON} end *) end; {WHILE} if (gzclose (infile) <> 0{Z_OK}) then begin {$IFDEF GUI} MessageDlg('gzclose Error.', mtError, [mbAbort], 0); {$ELSE} MsgDlg('gzclose Error.', mtError, [mbAbort], 0); {$ENDIF} errorcode := 3 end; gz_uncompress := errorcode end; function Gunzip (var FFileSource,FFileDestination: string): integer; var infile : gzFile; outfile : file; ioerr : integer; errorcode : integer; fsize : DWord{LongWord}; s : gz_streamp; begin errorcode := 0; infile := gzopenZ (FFileSource, 'r', 0); if (infile = NIL) then begin //if FWindowOnError then {$IFDEF GUI} MessageDlg('Can''t open: '+FFileSource, mtError, [mbAbort], 0); {$ELSE} MsgDlg('Can''t open: '+FFileSource, mtError, [mbAbort], 0); {$ENDIF} errorcode := 1 end else begin s := gz_streamp(infile); fsize := FileSize( s^.gzfile); AssignFile (outfile, FFileDestination); {$I-} Rewrite (outfile,1); {$I+} ioerr := IOResult; if (ioerr <> 0) then begin //if FWindowOnError then {$IFDEF GUI} MessageDlg('Can''t create: '+FFileDestination, mtError, [mbAbort], 0); {$ELSE} MsgDlg('Can''t create: '+FFileDestination, mtError, [mbAbort], 0); {$ENDIF} errorcode := 2 end else begin { We could open all files, so time for uncompressing } gz_uncompress (infile, outfile, fsize); //if FDeleteSource then DeleteFile(FFileSource); {$I-} close (outfile); {$I+} ioerr := IOResult; if (ioerr <> 0) then begin //if FWindowOnError then {$IFDEF GUI} MessageDlg('Can''t close file '+FFileDestination, mtError, [mbAbort], 0); {$ELSE} MsgDlg('Can''t close file '+FFileDestination, mtError, [mbAbort], 0); {$ENDIF} halt(1) end end end; Gunzip := errorcode end; procedure UnGZipCore (var infile : gzFile; var lBuf: ByteP; lReadBytes: integer; lWrite: boolean); const BUFLEN = 16384; var buf : packed array [0..BUFLEN-1] of byte; { Global uses BSS instead of stack } len,lI,written : integer; begin written := 0; if lReadBytes < 1 then exit; Len := lReadBytes div BUFLEN; if Len > 0 then for lI := 1 to Len do begin gzread (infile, @buf, BUFLEN {1388}); if lWrite then Move(buf,lbuf[Written+1],BUFLEN); Written := Written + BUFLEN; end; Len := lReadBytes mod BUFLEN; if Len = 0 then exit; gzread (infile, @buf, Len); if lWrite then Move(buf,lbuf[Written+1],len); end; //ungzipCore procedure UnGZip2 (var lFname: string; var lBuf: ByteP; lOffset,lMaxSz: integer; Skip: int64); const BUFLEN = 16384; var infile : gzFile; lbufsz,len,lI : integer; written : integer; buf : packed array [0..BUFLEN-1] of byte; { Global uses BSS instead of stack } begin infile := gzopenZskip (lFName, 'r', 0, Skip); written := 0; if lOffset > 0 then begin Len := lOffset div BUFLEN; if Len > 0 then for lI := 1 to Len do gzread (infile, @buf, BUFLEN {1388}); Len := lOffset mod BUFLEN; gzread (infile, @buf, Len); end; lbufsz := BUFLEN; if lMaxSz < BUFLEN then lbufsz := lMaxSz; while true do begin len := gzread (infile, @buf, lbufsz); if (len < 0) then begin break end; if (len = 0) then break; if (Written+len) > lMaxSz then begin if Written < lMaxSz then Move(buf,lbuf[Written+1],lMaxSz-Written); //cr2007 break; end; Move(buf,lbuf[Written+1],len); Written := Written + len; end; {WHILE} gzclose (infile); end; procedure UnGZip (var lFname: string; var lBuf: ByteP; lOffset,lMaxSz: integer); begin UnGZip2 (lFname, lBuf, lOffset,lMaxSz,0); end; (*procedure UnGZip (var lFname: string; var lBuf: ByteP; lOffset,lMaxSz: integer); const BUFLEN = 16384; var infile : gzFile; lbufsz,len,lI : integer; written : integer; buf : packed array [0..BUFLEN-1] of byte; { Global uses BSS instead of stack } begin infile := gzopenZ (lFName, 'r', 0); written := 0; if lOffset > 0 then begin Len := lOffset div BUFLEN; if Len > 0 then for lI := 1 to Len do gzread (infile, @buf, BUFLEN {1388}); Len := lOffset mod BUFLEN; gzread (infile, @buf, Len); end; lbufsz := BUFLEN; if lMaxSz < BUFLEN then lbufsz := lMaxSz; while true do begin len := gzread (infile, @buf, lbufsz); if (len < 0) then begin break end; if (len = 0) then break; if (Written+len) > lMaxSz then begin if Written < lMaxSz then Move(buf,lbuf[Written+1],lMaxSz-Written); //cr2007 break; end; Move(buf,lbuf[Written+1],len); Written := Written + len; end; {WHILE} gzclose (infile); end;*) procedure UnGZipFile (var lFname,lOUtname: string); //unzip //1417z- offset const bufsz = 16384; var infile : gzFile; len,lI : integer; //written : integer; lF: File; buf : packed array [0..bufsz-1] of byte; { Global uses BSS instead of stack } begin infile := gzopenZ (lFName, 'r', 0); //written := 0; //lbufsz := BUFLEN; Filemode := 1; AssignFile(lF, lOUtname); Rewrite(lF,1); while true do begin len := gzread (infile, @buf, bufsz); if (len < 0) then begin break end; if (len = 0) then break; BlockWrite(lF,buf, len); //Move(buf,lbuf[Written+1],len); //Written := Written + len; end; {WHILE} gzclose (infile); CloseFile(lF); Filemode := 2; //1366 end; function gz_compress (var infile:file; outfile:gzFile): integer; var len : uInt; ioerr : integer; buf : packed array [0..Z_BUFSIZE-1] of byte; { Global uses BSS instead of stack } errorcode : byte; // fsize, lensize : DWord; (*{$IFDEF VER100, VER90} fsize, lensize : DWord; {$ELSE} fsize, lensize : LongWord; {$ENDIF} *) begin errorcode := 0; //Progress := 0; //fsize := FileSize(infile); //lensize := 0; //if FProgressStep > 0 then DoOnProgress; while true do begin {$I-} blockread (infile, buf, Z_BUFSIZE, len); {$I+} ioerr := IOResult; if (ioerr <> 0) then begin errorcode := 1; break end; if (len = 0) then break; {$WARNINGS OFF}{Comparing signed and unsigned types} if (gzwrite (outfile, @buf, len) <> len) then begin {$WARNINGS OFF} errorcode := 2; break end; (*if FProgressStep > 0 then begin {$WARNINGS OFF}{Calculate progress and raise event} lensize := lensize + len; if ((lensize / fsize) * 100 >= FProgress + FProgressStep) or (lensize = fsize) then begin FProgress := Trunc((lensize / fsize) * 100); DoOnProgress end {$WARNINGS ON} end *) end; {WHILE} closeFile (infile); if (gzclose (outfile) <> 0{Z_OK}) then errorcode := 3; gz_compress := errorcode; end; procedure GZipFile(lSrcName,lDestName: String;lDeleteSrc: boolean); var //FGzipHeader : THeader; //FCompressionLevel,FProgress,Progress: integer; FGzipFilename : string; FGzipComments : string; outmode : string; s : string; infile : file; outfile : gzFile; FCompressionLevel{,errorcode} : integer; flags : uInt; stream : gz_streamp; p : PChar; //lProceed: TModalResult; ioerr : integer; begin //FGzipHeader := [zFilename]; FGzipFilename:= lSrcName; FGzipComments := ''; //FProgress := 0; FCompressionLevel := 6; if (FCompressionLevel > 9) or (FCompressionLevel<0) then FCompressionLevel := 6; //MainForm.ProgressBar1.position :=1; //Gzip (lFile,lMulti); //FFileDestination := lSourceFile+'.gz'; //result := 2; //return error if user aborts if fileexists(lDestName) then begin {$IFDEF GUI} case MessageDlg('Overwrite the file '+lDestName+'?', mtConfirmation,[mbYes, mbAbort], 0) of { produce the message dialog box } id_Abort: exit; end; {$ELSE} case MsgDlg('Overwrite the file '+lDestName+'?', mtConfirmation,[mbYes, mbAbort], 0) of { produce the message dialog box } id_Abort: exit; end; {$ENDIF} end; AssignFile (infile, lSrcName); {$I-} Reset (infile,1); {$I+} ioerr := IOResult; if (ioerr <> 0) then begin //if FWindowOnError then // MessageDlg('Can''t open: '+lSourceFile, mtError, [mbAbort], 0); //errorcode := 1 end else begin outmode := 'w '; s := IntToStr(FCompressionLevel); outmode[2] := s[1]; outmode[3] := ' '; (*case FCompressionType of Standard : outmode[3] := ' '; HuffmanOnly : outmode[3] := 'h'; Filtered : outmode[3] := 'f'; end;*) //flags := 0; //if (zfilename in FGzipHeader) then flags := ORIG_NAME; //if (comment in FGzipHeader) then flags := flags + COMMENT_; outfile := gzopenZ (lDestName, outmode, flags); if (outfile = NIL) then begin //if FWindowOnError then // MessageDlg('Can''t open: '+FFileDestination, mtError, [mbAbort], 0); close( infile); //errorcode := 2 exit; end else begin { if flags are set then write them } stream := gz_streamp(outfile); if {(zfilename in FGzipHeader)} true then begin s := ExtractFilename(lSrcName); p := PChar(s); blockWrite( stream^.gzfile, p[0], length(s)+1); stream^.startpos := stream^.startpos + length(s) + 1 end; {if (zcomment in FGzipHeader) then begin p := PChar(FGzipComments); blockWrite( stream^.gzfile, p[0], length(FGzipComments)+1); stream^.startpos := stream^.startpos + length(FGzipComments) + 1 end; } {errorcode :=} gz_compress(infile, outfile); {if errorcode <> 0 then errorcode := errorcode+100 else if FDeleteSource then erase (infile);} end end; if lDeleteSrc then erase (infile); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/dicomhdr.pas������������������������������������������������0000755�0001750�0001750�00000047014�12310315262�017772� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit dicomhdr; {$H+} //Simple dicom to nifti translator interface uses {$IFNDEF FPC}Controls, {$ENDIF} SysUtils,define_types,classes,nifti_hdr,GraphicsMathLibrary, nifti_types; function NIFTIhdr_LoadDCM (var lFilename: string; var lHdr: TMRIcroHdr): boolean; type kDICOMStr = String[32]; DICOMdata = record XYZdim: array [1..4] of integer; XYZori: array [1..3] of integer; XYZmm: array [1..3] of double; Orient: array [1..6] of double; Float,file4D: boolean; PatientPosX,PatientPosY,PatientPosZ,AngulationAP,AngulationFH,AngulationRL: double; TE, TR,IntenScale,IntenIntercept,location{,DTIv1,DTIv2,DTIv3}: single; {Bval,}SlicesPer3DVol,SiemensInterleaved {0=no,1=yes,2=not defined},SiemensSlices,SiemensMosaicX,SiemensMosaicY, nDTIdir,AcquNum,ImageNum,SeriesNum,ImageStart,little_endian,Allocbits_per_pixel,SamplesPerPixel, PatientIDint,CSAImageHeaderInfoPos,CSAImageHeaderInfoSz,ManufacturerID: integer; PatientPos,PatientName,ProtocolName,StudyDate,StudyTime,PhilipsSliceOrient,PhaseEncoding: kDICOMStr; Filename: string[255]; end; implementation uses dialogsx; procedure Msg(lStr: string); begin ShowMsg(lStr); end; procedure clear_dicom_data (var lDicomdata:Dicomdata); var lI: integer; begin with lDicomData do begin lDicomData.CSAImageHeaderInfoPos := 0; lDicomData.CSAImageHeaderInfoSz := 0; for lI := 1 to 6 do Orient[lI] := 0; PatientIDInt := 0; ManufacturerID := 0; AngulationFH := 0; AngulationRL := 0; AngulationAP := 0; nDTIdir := 0; PhilipsSliceOrient := 'NA'; PhaseEncoding := 'NA'; PatientPos := 'NA'; file4D := false; PatientName := 'NO NAME'; StudyDate := ''; StudyTime := ''; TR := 0; TE := 0; Float := false; ImageNum := 0; SlicesPer3DVol := 0; SiemensInterleaved := 2; //0=no,1=yes,2=undefined SiemensSlices := 0; SiemensMosaicX := 1; SiemensMosaicY := 1; IntenScale := 1; IntenIntercept := 0; SeriesNum := 1; AcquNum := 0; ImageNum := 1; SamplesPerPixel := 1; XYZmm[1] := 1; XYZmm[2] := 1; XYZmm[3] := 1; XYZdim[1] := 1; XYZdim[2] := 1; XYZdim[3] := 1; XYZdim[4] := 1; lDicomData.XYZori[1] := 0; lDicomData.XYZori[2] := 0; lDicomData.XYZori[3] := 0; ImageStart := 0; Little_Endian := 0; Allocbits_per_pixel := 16;//bits Location:=0; PatientPosX := 0;//1392 PatientPosY := 0;//1392 PatientPosZ := 0;//1392 end; end; function NIFTIhdr_LoadDCM (var lFilename: string; var lHdr: TMRIcroHdr): boolean; var lDICOMdata: DICOMdata; const kMaxBuf = (256*256)-1; //bytes kMax16bit = (256*256)-1; kImageType = $0008+($0008 shl 16 ); kStudyDate = $0008+($0020 shl 16 ); kStudyTime = $0008+($0030 shl 16 ); kPatientName = $0010+($0010 shl 16 ); kSeq = $0018+($0020 shl 16 ); kZThick = $0018+($0050 shl 16 ); kTR = $0018+($0080 shl 16 ); kTE = $0018+($0081 shl 16 ); kEchoNum = $0018+($0086 shl 16 ); kZSpacing = $0018+($0088 shl 16 ); kProtocolName = $0018+($1030shl 16 ); kPatientPos = $0018+($5100 shl 16 ); kSeriesNum = $0020+($0011 shl 16 ); kAcquNum = $0020+($0012 shl 16 ); kImageNum = $0020+($0013 shl 16 ); kOrientation = $0020+($0037 shl 16 ); kLocation = $0020+($1041 shl 16 ); kDim3 = $0028+($0008 shl 16 ); kDim2 = $0028+($0010 shl 16 ); kDim1 = $0028+($0011 shl 16 ); kXYSpacing = $0028+($0030 shl 16 ); kPosition = $0020+($0032 shl 16 ); knVol = $0020+($0105 shl 16 ); kAlloc = $0028+($0100 shl 16 ); kIntercept = $0028+($1052 shl 16 ); kSlope = $0028+($1053 shl 16 ); kCSAImageHeaderInfo = $0029+($1010 shl 16 ); kSlicesPer3DVol = $2001+($1018 shl 16 ); kTransferSyntax = $0002+($0010 shl 16); kImageStart = $7FE0+($0010 shl 16 ); kMaxFloats = 6; var vr : array [1..2] of Char; lByteRA: Bytep; lFloatRA: array [1..kMaxFloats] of double; lBufferSz,lPos,lFileSz,lBuffStart: integer; lInFile: file; lBufferError: boolean; procedure Str2FloatNum ( lStr: string; lnFloats: integer); var lFStr: string; lP,lnF: integer; begin if (length(lStr) < 1) or (lnFloats < 1) or (lnFloats > kMaxFloats) then exit; for lnF := 1 to lnFloats do lFloatRA[lnF] := 1; lStr := lStr + ' '; //terminator lFStr := ''; lP := 1; lnF:= 0; while lP <= length(lStr) do begin if lStr[lP] in ['+','-','0'..'9','.','e','E'] then lFStr := lFStr + lStr[lP] else if (lFStr <> '') then begin inc(lnF); try lFloatRA[lnF] := strtofloat(lFStr); except on EConvertError do lFloatRA[lnF] := 1; end;//except if lnF = lnFloats then exit; lFStr := ''; end; inc(lP); end; end; //function Str2Float function GetByte (lFilePos: integer): byte; var lBufPos: integer; begin //the following error checking slows down reads a lot! //a simpler alternative would be to make the buffer size the same size as the entire image... //the current strategy saves memory and is faster for large images with small headers if lFilepos > lFileSz then begin lBufferError := true; result := 0; exit; end; lBufPos := lFilepos - lBuffStart+1; if (lBufPos > lBufferSz) or (lBufPos < 1) then begin //reload buffer if lFilePos+kMaxBuf > lFileSz then lBufferSz := lFileSz - (lFilePos) else lBufferSz := kMaxBuf; //read remaining AssignFile(lInFile, lFileName); FileMode := 0; //Set file access to read only Reset(lInFile, 1); seek(lInFile,lFilePos); BlockRead(lInFile, lByteRA^[1], lBufferSz); CloseFile(lInFile); FileMode := 2; lBuffStart := lFilePos; lBufPos := 1; end; result := lByteRA^[lBufPos]; end; function ReadInt4: integer; begin if lDicomData.little_endian = 0 then result := GetByte(lPos+3)+(GetByte(lPos+2) shl 8)+(GetByte(lPos+1) shl 16)+(GetByte(lPos) shl 24) else result := GetByte(lPos)+(GetByte(lPos+1) shl 8)+(GetByte(lPos+2) shl 16)+(GetByte(lPos+3) shl 24); inc(lPos,4); end; //function Read4 procedure ReadGroupElementLength(var lGroupElement,lLength: integer); begin lGroupElement := ReadInt4; vr[1] := chr(GetByte(lPos)); vr[2] := chr(GetByte(lPos+1)); if vr[2] < 'A' then begin //implicit vr with 32-bit length lLength := ReadInt4; exit; end; if (vr = 'UN') {2/2008} or (vr = 'OB') or (vr = 'OW') or (vr = 'SQ') then begin {explicit VR with 32-bit length} lPos := lPos + 4; {skip 2 byte string and 2 reserved bytes = 4 bytes = 2 words} lLength := ReadInt4;//Ord4(buf[lPos]) + $100 * (buf[lPos+1] + $100 * (buf[lPos+2] + $100 * buf[lPos+3])) end else begin {explicit VR with 16-bit length} if lDicomData.little_endian = 0 then lLength := (GetByte(lPos+3))+(GetByte(lPos+2) shl 8) else lLength := (GetByte(lPos+2))+(GetByte(lPos+3) shl 8);//GetLength := Ord4(buf[i+2]) + $100 * (buf[i+3]); lPos := lPos + 4; {skip 2 byte string and 2 length bytes = 4 bytes = 2 words} end; end; //procedure ReadGroupElementLength function DCMStr(lBytes: integer): string; var lC: integer; begin result := ''; if lBytes < 1 then exit; for lC := lPos to (lPos+(lBytes-1)) do result := result + char(GetByte(lC)); for lC := 1 to lBytes do if result[lC] in ['+','-','/','\',' ','0'..'9','a'..'z','A'..'Z','.'] then else result[lC] := ' '; end; //function DCMStr function DCMStr2Int (lBytes: integer): integer; var lErr: integer; lStr: string; begin lStr := DCMStr(lBytes); Val(lStr,result,lErr); end; //function DCMStr2Int procedure DCMStr2FloatNum (lBytes,lnFloats: integer); begin Str2FloatNum (DCMStr(lBytes), lnFloats); end; //function DCMStr2Float function DCMStr2Float (lBytes: integer): single; begin DCMStr2FloatNum (lBytes,1); result := lFloatRA[1]; end; //function DCMStr2Float procedure DCMStr2Float2 (lBytes: integer; var lF1,lF2: double); begin DCMStr2FloatNum (lBytes,3); lF1 := lFloatRA[1]; lF2 := lFloatRA[2]; end; //function DCMStr2Float2 procedure DCMStr2Float3 (lBytes: integer; var lF1,lF2,lF3: double); begin DCMStr2FloatNum (lBytes,3); lF1 := lFloatRA[1]; lF2 := lFloatRA[2]; lF3 := lFloatRA[3]; end; //function DCMStr2Float3 procedure DCMStr2Float6 (lBytes: integer; var lF1,lF2,lF3,lF4,lF5,lF6: double); begin DCMStr2FloatNum (lBytes,6); lF1 := lFloatRA[1]; lF2 := lFloatRA[2]; lF3 := lFloatRA[3]; lF4 := lFloatRA[4]; lF5 := lFloatRA[5]; lF6 := lFloatRA[6]; end; //function DCMStr2Float6 function DCMint (lBytes: integer): integer; //read 16 bit short integer begin if lBytes <= 2 then result := GetByte(lPos)+(GetByte(lPos+1) shl 8) //shortint vs word? else result := GetByte(lPos)+(GetByte(lPos+1) shl 8)+(GetByte(lPos+2) shl 16)+(GetByte(lPos+3) shl 24);; //byte order?? end; //function DCMint var lTempStr,lStr: string; lOffset,lTemp,lGroupElement,lLength,lEchoNum,lnVol: integer; lResearchMode: boolean; lThick: double; begin //function fast_read_dicom_data lOffset := 128; lnVol := 1; lEchoNum := 1; lThick := 0; clear_dicom_data(lDicomData); lDicomData.little_endian := 1; result := false; lResearchMode := false; lBufferError := false; lFileSz := FSize(lFilename); lBufferSz := lFileSz-lOffset; if lBufferSz < 512 then begin //showmessage('Error: File too small '+lFilename); exit; end; if lBufferSz > kMaxBuf then lBufferSz := kMaxBuf; GetMem(lByteRA,kMaxBuf); lBufferSz := lBufferSz; AssignFile(lInFile, lFileName); FileMode := 0; //Set file access to read only Reset(lInFile, 1); seek(lInFile,lOffset); BlockRead(lInFile, lByteRA^[1], lBufferSz); CloseFile(lInFile); FileMode := 2; lBuffStart := lOffset; lPos := lOffset; if lOffset = 128 then begin //DICOM files start with DICM at 128, Siemens shadow headers do not if DCMStr(4) <> 'DICM' then begin //Msg(DCMStr(4)+ ' <> DICM'); FreeMem(lByteRA); exit; end; lPos := lOffset + 4;//DICM read end;//Offset = 128 //next check VR if not( chr(GetByte(lPos+4)) in ['A'..'Z']) or not( chr(GetByte(lPos+5)) in ['A'..'Z']) then Msg('implicit VR untested'); //next check Endian lTemp := lPos; ReadGroupElementLength(lGroupElement,lLength); //if lLength > kMax16bit then // Msg('ByteSwapped'); lPos := lTemp; //end VR check while (lDICOMData.imagestart = 0) and (not lBufferError) do begin ReadGroupElementLength(lGroupElement,lLength); //if (lGroupElement and $FF) > $18 then // msg(VR+inttohex(lGroupElement,8)+' '+inttostr(lLength)); case lGroupElement of kTransferSyntax: begin lTempStr := (DCMStr(lLength)); if (length(lTempStr) >= 19) and (lTempStr[19] = '2') then lDicomData.little_endian := 0; end; kImageType : begin lTempStr := DCMStr(lLength); //read last word - ver\mosaic -> MOSAIC lStr := ''; lTemp := length(lTempStr); while (lTemp > 0) and (lTempStr[lTemp] in ['a'..'z','A'..'Z']) do begin lStr := upcase(lTempStr[lTemp])+lStr; dec(lTemp); end; if lStr = 'MOSAIC' then lDicomData.SiemensMosaicX := 2; //we need to read numaris for details... end; kStudyDate: lDicomData.StudyDate := DCMStr(lLength); kStudyTime : lDicomData.StudyTime := DCMStr(lLength); kPatientName : lDicomData.PatientName := DCMStr(lLength); kProtocolName : lDicomData.ProtocolName :=DCMStr(lLength); kPatientPos : lDicomData.PatientPos :=DCMStr(lLength); //should be HFS for Siemens = Head First Supine kSeriesNum : lDicomData.SeriesNum := DCMStr2Int(lLength); kAcquNum : lDicomData.AcquNum := DCMStr2Int(lLength); kSeq: begin if DCMStr(lLength) = 'RM' then lResearchMode := True; end; kImageNum : lDicomData.ImageNum := DCMStr2Int(lLength); kDim3 :lDicomData.XYZdim[3] := DCMStr2Int(lLength); kDim2 : lDicomData.XYZdim[2] := DCMint (lLength); kDim1 : lDicomData.XYZdim[1] := DCMint (lLength); kLocation : lDICOMData.Location := DCMStr2Float(lLength); kAlloc: lDicomData.Allocbits_per_pixel := DCMint (lLength); kTR : lDicomData.TR := DCMStr2Float(lLength); kTE: lDicomData.TE := DCMStr2Float(lLength); kEchoNum: lEchoNum := round (DCMStr2Float(lLength)); kSlope : lDICOMData.IntenScale := DCMStr2Float(lLength); kIntercept : lDICOMData.IntenIntercept := DCMStr2Float(lLength); kOrientation : DCMStr2Float6(lLength, lDicomData.Orient[1], lDicomData.Orient[2],lDicomData.Orient[3],lDicomData.Orient[4], lDicomData.Orient[5],lDicomData.Orient[6]); kPosition : DCMStr2Float3 (lLength,lDicomData.PatientPosX, lDicomData.PatientPosY,lDicomData.PatientPosZ); knVol: lnVol := round (DCMStr2Float(lLength)); kZThick: begin lThick := DCMStr2Float(lLength); lDICOMData.XYZmm[3] := lThick; end;//used differently by manufacturers kZSpacing: begin lDICOMData.XYZmm[3] := DCMStr2Float(lLength); if (lThick/2) > lDICOMdata.XYZmm[3] then lDICOMdata.XYZmm[3] := lDICOMdata.XYZmm[3] + lThick end; //used different by different manufacturers kXYSpacing: DCMStr2Float2 (lLength, lDICOMdata.XYZmm[2], lDICOMdata.XYZmm[1]); (*kCSAImageHeaderInfo: begin //order ICE,Acq,Num,Vector lDICOMdata.CSAImageHeaderInfoPos := lPos; lDICOMdata.CSAImageHeaderInfoSz := lLength; end; *) kSlicesPer3DVol: lDICOMData.SlicesPer3DVol := DCMint (lLength); kImageStart: lDICOMData.ImageStart := lPos ; //-1 as indexed from 0.. not 1.. end; //Case lGroupElement //Msg(VR+inttohex(lGroupElement and kMax16bit,4) +':'+inttohex( lGroupElement shr 16,4)+' '+inttostr(lLength)+'@'+inttostr(lPos) ); lPos := lPos + (lLength); end; //while imagestart=0 and not error //clean up if (lDicomData.SiemensMosaicX > 1) then lDicomData.AcquNum := 1; if (lEchoNum > 1) and (lEchoNum < 16) then lDicomData.AcquNum := lDicomData.AcquNum + (100*lEchoNum); if lResearchMode then lDicomData.SeriesNum := lDicomData.SeriesNum + 100; if (lDICOMData.SlicesPer3DVol > 0) and (lnVol > 1) and (lDicomdata.XYZdim[3] > 1) and (lDicomData.SlicesPer3DVol > 0)and ((lDicomdata.XYZdim[3] mod lDicomData.SlicesPer3DVol) = 0) then lDICOMdata.File4D := true; if not lBufferError then result := true; FreeMem(lByteRA); if result then begin lHdr.HdrFileName:= lFilename; lHdr.ImgFileName:= lFilename; lHdr.NIfTItransform := false;//Analyze case lDicomData.Allocbits_per_pixel of 8: lHdr.NiftiHdr.datatype := kDT_UNSIGNED_CHAR; 16: lHdr.NiftiHdr.datatype := kDT_SIGNED_SHORT; 32: begin if lDicomdata.Float then lHdr.NiftiHdr.datatype := kDT_SIGNED_INT else lHdr.NiftiHdr.datatype := kDT_FLOAT; // float (32 bits/voxel) end; else begin Msg('Unsupported DICOM bit-depth : +inttostr(lDicomData.Allocbits_per_pixel.'); result := false; end; end; lHdr.NIFTIhdr.vox_offset := lDicomData.ImageStart; lHdr.NIFTIhdr.bitpix := lDicomData.Allocbits_per_pixel; lHdr.NIFTIhdr.pixdim[1] := lDicomdata.XYZmm[1]; lHdr.NIFTIhdr.pixdim[2] := lDicomdata.XYZmm[2]; lHdr.NIFTIhdr.pixdim[3] := lDicomdata.XYZmm[3]; NIFTIhdr_SetIdentityMatrix(lHdr); lHdr.NIFTIhdr.dim[1] := lDicomdata.XYZdim[1]; lHdr.NIFTIhdr.dim[2] := lDicomdata.XYZdim[2]; lHdr.NIFTIhdr.dim[3] := lDicomdata.XYZdim[3]; lHdr.NIFTIhdr.dim[4] := lDicomdata.XYZdim[4]; if lHdr.NIFTIhdr.dim[4] < 2 then lHdr.NIFTIhdr.dim[0] := 3 else lHdr.NIFTIhdr.dim[0] := 4; lHdr.NIFTIhdr.qform_code := kNIFTI_XFORM_UNKNOWN; lHdr.NIFTIhdr.sform_code := kNIFTI_XFORM_UNKNOWN; //test - input estimated orientation matrix lHdr.NIFTIhdr.sform_code := kNIFTI_XFORM_SCANNER_ANAT ; lHdr.NIFTIhdr.srow_x[0] := lHdr.NIFTIhdr.pixdim[1]; lHdr.NIFTIhdr.srow_y[1] := lHdr.NIFTIhdr.pixdim[2]; lHdr.NIFTIhdr.srow_z[2] := lHdr.NIFTIhdr.pixdim[3]; lHdr.NIFTIhdr.srow_x[3] := (lHdr.NIFTIhdr.dim[1] /2)*-lHdr.NIFTIhdr.pixdim[1]; lHdr.NIFTIhdr.srow_y[3] := (lHdr.NIFTIhdr.dim[2] /2)*-lHdr.NIFTIhdr.pixdim[2]; lHdr.NIFTIhdr.srow_z[3] := (lHdr.NIFTIhdr.dim[3] /2)*-lHdr.NIFTIhdr.pixdim[3]; lHdr.Mat:= Matrix3D( lHdr.NIFTIhdr.srow_x[0],lHdr.NIFTIhdr.srow_x[1],lHdr.NIFTIhdr.srow_x[2],lHdr.NIFTIhdr.srow_x[3], // 3D "graphics" matrix lHdr.NIFTIhdr.srow_y[0],lHdr.NIFTIhdr.srow_y[1],lHdr.NIFTIhdr.srow_y[2],lHdr.NIFTIhdr.srow_y[3], // 3D "graphics" matrix lHdr.NIFTIhdr.srow_z[0],lHdr.NIFTIhdr.srow_z[1],lHdr.NIFTIhdr.srow_z[2],lHdr.NIFTIhdr.srow_z[3], // 3D "graphics" matrix 0,0,0,1); //Warning: some of the NIFTI float values that do exist as integer values in Analyze may have bizarre values like +INF, -INF, NaN lHdr.NIFTIhdr.toffset := 0; lHdr.NIFTIhdr.intent_code := kNIFTI_INTENT_NONE; lHdr.NIFTIhdr.dim_info := kNIFTI_SLICE_SEQ_UNKNOWN + (kNIFTI_SLICE_SEQ_UNKNOWN shl 2) + (kNIFTI_SLICE_SEQ_UNKNOWN shl 4); //Freq, Phase and Slie all unknown lHdr.NIFTIhdr.xyzt_units := kNIFTI_UNITS_UNKNOWN; lHdr.NIFTIhdr.slice_duration := 0; //avoid +inf/-inf, NaN lHdr.NIFTIhdr.intent_p1 := 0; //avoid +inf/-inf, NaN lHdr.NIFTIhdr.intent_p2 := 0; //avoid +inf/-inf, NaN lHdr.NIFTIhdr.intent_p3 := 0; //avoid +inf/-inf, NaN lHdr.NIFTIhdr.pixdim[0] := 1; //QFactor should be 1 or -1 lHdr.DiskDataNativeEndian := odd(lDicomData.little_endian); lHdr.NIFTIHdr.magic := kNIFTI_MAGIC_DCM; end; end; //function NIFTIhdr_LoadDCM end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/distr.pas���������������������������������������������������0000755�0001750�0001750�00000041376�11326425442�017343� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� unit distr; interface {$Include isgui.inc} uses Math, {$IFDEF GUI}dialogs;{$ELSE} dialogsx;{$ENDIF} function TtoZ(t,df: extended): extended; function lnGamma(f:longint):extended; { Computes the logarithm of the gamma function at f/2. } function pGamma(f:longint;y:extended):extended; { Returns the right tail probability in the gamma distribution with lambda = f/2. } function pNormal(z:extended):extended; //function pNormalOld(z:extended):extended; //function pNormalOrig(z:extended):extended; //old //function pNormalOrig(u:extended):extended; //old { Returns the right tail probability in the normal distribution. } function pChi2(f:longint;y:extended):extended; { Returns the right tail probability in the chi square distribution with f degrees of freedom. } function pBeta(f1,f2:longint;y:extended):extended; { Returns the LEFT tail probability in the beta distribution with paramters lambda1=f1/2 and lambda2=f2/2. Use only f1 and f2 < 1E6. } function pFdistr(f1,f2:longint;y:extended):extended; { Returns the right tail probability in the F distribution with (f1,f2) degrees of freedom. Use only f1 and f2 < 1E6. } function pTdistr(f:longint;y:extended):extended; { Returns the right tail probability in the T distribution. Use only f < 1E6. } function pNormalInv(p:extended):extended; function pNormalInvQuickApprox(p : extended) : extended;//errors rise with Z>7 //function pNormalInvOld(p:extended):extended; { Inverse of pNormal. } function pGammaInv(f:longint;p:extended):extended; { Inverse of pGamma(f,*). } function pChi2Inv(f:longint;p:extended):extended; { Inverse of pChi2(f,*). } function pBetaInv(f1,f2:longint;p:extended):extended; { Inverse of pBeta(f1,f2,*) (notice: LEFT tail). } function pFdistrInv(f1,f2:longint;p:extended):extended; { 1-p percentile of F distribution. } function pTdistrInv(f:longint;p:extended):extended; { 1-p percentile of T distribution. } function pPoiss(lambda:extended; n:longint): extended; { Returns the right tail probability in the Poisson distribution. } function PoissCL(n:longint; p:extended): extended; { Lower 1-p confidence limits for lambda in Poisson distribution when n is observed. } function pBin(n,x:longint; p:extended): extended; { Returns the binomial right tail probability. } function BinCL(n,x:longint; pp:extended): extended; { Returns confidence limit for binomial probability parameter, i.e. inverse to pBin(n,*). } function ChiSq(x: double; n: integer): double; {---------------------------------------------------------------------------} implementation //uses stat; function ChiSq(x: double; n: integer): double; var p,t: double; var k,a: integer; begin p := exp(-0.5*x); if odd(n) then p := p * sqrt(2*x/Pi); k := round(n); while k >= 2 do begin p := p *x/k; k := k-2; end; t := p; a := round(n); while (t > 0.000001*p) do begin a := a+2; t := t*x/a; p := p + t; end; result := 1-p; end; function TtoZ(t,df: extended): extended; // Converts a t value to an approximate z value w.r.t the given df // s.t. std.norm.(z) = t(z, df) at the two-tail probability level. //from http://www.anu.edu.au/nceph/surfstat/surfstat-home/tables/t.php var A9,B9,T9,Z8, P7, B7: extended; begin A9 := df - 0.5; B9 := 48*A9*A9; T9 := t*t/df; if T9 >= 0.04 then Z8 :=A9*ln(1+T9) else Z8 := A9*(((1 - T9*0.75)*T9/3 - 0.5)*T9 + 1)*T9; P7 := ((0.4*Z8 + 3.3)*Z8 + 24)*Z8 + 85.5; B7 := 0.8*power(Z8, 2) + 100 + B9; result := (1 + (-P7/B7 + Z8 + 3)/B9)*sqrt(Z8); if t < 0 then result := -result; end; function lnGamma(f:longint):extended; var sum,y : extended; k : longint; begin y:=f/2; if f>500 then begin sum:= ln(2*pi)/2 + (y-1/2)*ln(y); sum:=sum -y + 1/(12*y); sum:=sum - 1/360/y/y/y; lnGamma:=sum; end else begin k:=f; sum:=0; while k>2 do begin k:=k-2; sum:=sum+ln(k/2); end; if k=1 then sum:=sum+ln(pi)/2; lnGamma:=sum; end; end; function pGamma(f:longint;y:extended):extended; var term,sum: extended; k : longint; begin if (y<=0) then pGamma:=1 else if (y<f/2) or (y<42) then begin term:=(f/2)*ln(y)-y-lnGamma(f+2); if term>-1000 then term:=exp(term) else term:=0; sum:=0; k:=0; while ((f+k)*term>(f+k-2*y)*1E-20) do begin sum:=sum+term; term:=2*term*y/(f+k+2); k:=k+2; end; pGamma:=abs(1-sum); end else begin term:=(f/2-1)*ln(y)-y-lnGamma(f); if term>-1000 then term:=exp(term) else term:=0; sum:=0; k:=0; while (term*y > (2*y-f+k)*0.5E-20) and (f-k>1) do begin sum:=sum+term; k:=k+2; term:=term*(f-k)/2/y; end; pGamma:=abs(sum); end; end; {---------------------------------------------------------------------------} function pNormal(z:extended):extended; const PiD2=Pi/2; var q: extended; begin q := z*z; if abs(z)>7.0 then result := (0.5)*(1-1/q+3/(q*q))*Exp(-q/2)/(Abs(z)*Sqrt(PiD2)) else result := pGamma(1,q/2)/2; if z<0 then result:=1-result; end; function pChi2(f:longint;y:extended):extended; begin pChi2:= pGamma(f,y/2); end; function pBeta0(f1,f2:longint; y:extended): extended; { Returns the left tail probability of the beta distribution with paramters lambda1=f1/2 and lambda2=f2/2. Use only f1+f2<40. Accuracy around +/- 1E-16 . } var sum,term : extended; k : longint; begin sum:=0; k:=0; term:=lnGamma(f1+f2)-lnGamma(f2); term:=term-lnGamma(f1+2)+f1*ln(y)/2; term:=exp(term); while (k<f2) or (abs(term) > 1E-20) do begin sum:=sum+term; k:=k+2; term:=-term*y*(f2-k)*(f1+k-2)/k/(f1+k); end; pBeta0:=sum; end; function pBeta(f1,f2:longint;y:extended):extended; var sum,term : extended; k : longint; intch : boolean; begin if (f1=f2) and (y=0.5) then pBeta:=0.5 else if y<=0 then pBeta:=0 else if y>=1 then pBeta:=1 else begin intch:=false; if y>(1-y) then begin intch:=true; k:=f1; f1:=f2; f2:=k; y:=1-y; end; if f1+f2<41 then sum:=pBeta0(f1,f2,y) else begin term:= (f2/2-1)*ln(1-y) + (f1/2)*ln(y) + lnGamma(f1+f2) - lnGamma(f1+2); term:=term - lnGamma(f2); if term > -1000 then term:=exp(term) else term:=0; if (term<1E-35) and (y<f1/(f1+f2)) then sum:=0 else if (term<1E-35) and (y>f1/(f1+f2)) then sum:=1 else begin k:=0; sum:=0; while (abs(term)>1E-25) or (y*(f2-k) > (1-y)*(f1+k)) do begin sum:=sum+term; k:=k+2; term:= term*y*(f2-k)/(1-y)/(f1+k); end; end; end; if intch then sum:=1-sum; pBeta:= abs(sum); end; end; function gammln (xx: double): double; {Numerical Recipes for Pascal, p 177} const stp = 2.50662827465; var x, tmp, ser: double; begin x := xx - 1.0; tmp := x + 5.5; tmp := (x + 0.5) * ln(tmp) - tmp; ser := 1.0 + 76.18009173 / (x + 1.0) - 86.50532033 / (x + 2.0) + 24.01409822 / (x + 3.0) - 1.231739516 / (x + 4.0) + 0.120858003e-2 / (x + 5.0) - 0.536382e-5 / (x + 6.0); gammln := tmp + ln(stp * ser) end; {procedure gammln} FUNCTION betacf(a,b,x: double): double; LABEL 1; CONST itmax=100; eps=3.0e-7; VAR tem,qap,qam,qab,em,d: double; bz,bpp,bp,bm,az,app: double; am,aold,ap: double; m: integer; BEGIN am := 1.0; bm := 1.0; az := 1.0; qab := a+b; qap := a+1.0; qam := a-1.0; bz := 1.0-qab*x/qap; FOR m := 1 TO itmax DO BEGIN em := m; tem := em+em; d := em*(b-m)*x/((qam+tem)*(a+tem)); ap := az+d*am; bp := bz+d*bm; d := -(a+em)*(qab+em)*x/((a+tem)*(qap+tem)); app := ap+d*az; bpp := bp+d*bz; aold := az; am := ap/bpp; bm := bp/bpp; az := app/bpp; bz := 1.0; IF ((abs(az-aold)) < (eps*abs(az))) THEN GOTO 1 END; writeln('pause in BETACF'); writeln('a or b too big, or itmax too small'); readln; 1: betacf := az END; FUNCTION betai(a,b,x: double): double; VAR bt: double; BEGIN IF ((x < 0.0) OR (x > 1.0)) THEN BEGIN writeln('pause in routine BETAI'); readln END; IF ((x = 0.0) OR (x = 1.0)) THEN bt := 0.0 ELSE bt := exp(gammln(a+b)-gammln(a)-gammln(b) +a*ln(x)+b*ln(1.0-x)); IF (x < ((a+1.0)/(a+b+2.0))) THEN betai := bt*betacf(a,b,x)/a ELSE betai := 1.0-bt*betacf(b,a,1.0-x)/b END; function pFdistr(f1,f2:longint;y:extended):extended; begin pFdistr:=pBeta(f2,f1,f2/(f1*y+f2)); end; function pTdistr(f:longint;y:extended):extended; begin if y = 0 then result := 0.5 else begin result := betai(0.5*f,0.5,f/(f+sqr(y)))/2; if y < 0 then result := 1-result; end; end;//from numerical recipes (*below x5 slower than numerical recipes! function pTdistr; //function pTdistr(f:longint;y:extended):extended; var p: extended; begin if y=0 then pTdistr:=0.5 else begin p:=f/(y*y+f); p:=pBeta(f,1,p); p:=p/2; if y<0 then p:=1-p; pTdistr:=p; end; end;*) {---------------------------------------------------------------------------} (*function pNormalInv(p:extended):extended; var v,dv,z: extended; begin v := 0.5; dv := 0.5; z := 0; while (dv>1e-15) do begin z:=1/v-1; dv:=dv/2; if(pNormal(z)>p) then v:=v-dv else v:=v+dv; end; result := z; end; *) function pNormalInv(p:extended):extended; var v,dv,z,tailp: extended; begin if p <= 0.5 then tailp := p else tailp := 1-p; if tailp = 0 then begin result := 9.2;//fails with Z<-9 exit; end; //showmessage('error'+realtostr(tailp,10)); //showmessage(realtostr(tailp,10)); v := 0.5; dv := 0.5; z := 0; while (dv>1e-15) do begin z:=1/v-1; dv:=dv/2; if(pNormal(z)>tailp) then v:=v-dv else v:=v+dv; end; if p <= 0.5 then result := z else result := -z; end; function zprob(p : extended {; VAR errorstate : boolean}) : extended; VAR z, xp, lim, p0, p1, p2, p3, p4, q0, q1, q2, q3, q4, Y : extended; begin // value of probability between approx. 0 and .5 entered in p and the // z value is returned z //errorstate := true; lim := 1E-19; p0 := -0.322232431088; p1 := -1.0; p2 := -0.342242088547; p3 := -0.0204231210245; p4 := -4.53642210148E-05; q0 := 0.099348462606; q1 := 0.588581570495; q2 := 0.531103462366; q3 := 0.10353775285; q4 := 0.0038560700634; xp := 0.0; if (p > 0.5) then p := 1 - p; if (p < lim) then //Z>9.5 Z<-9.5 z := -pNormalInv(p) //use slow method //z := xp else if (p = 0.5) then z := xp else begin Y := sqrt(ln(1.0 / (p * p))); xp := Y + ((((Y * p4 + p3) * Y + p2) * Y + p1) * Y + p0) / ((((Y * q4 + q3) * Y + q2) * Y + q1) * Y + q0); if (p < 0.5) then xp := -xp; z := xp; end; zprob := z; end; // End function zprob function pNormalInvQuickApprox(p : extended) : extended; var z, px : extended; // flag : boolean; begin // obtains the inverse of z, that is, the z for a probability associated // with a normally distributed z score. px := p; if (p > 0.5) then px := 1.0 - p; if px < 0.000000000000001 then z := -8 //lPs[lInc] := 0.000000000000001; else z := zprob(px{,flag}); if (p > 0.5) then z := abs(z); result := -z; end; //End of inversez Function (*function zprob(p : double {; VAR errorstate : boolean}) : double; VAR z, xp, lim, p0, p1, p2, p3, p4, q0, q1, q2, q3, q4, Y : double; begin // value of probability between approx. 0 and .5 entered in p and the // z value is returned z //errorstate := true; lim := 1E-19; p0 := -0.322232431088; p1 := -1.0; p2 := -0.342242088547; p3 := -0.0204231210245; p4 := -4.53642210148E-05; q0 := 0.099348462606; q1 := 0.588581570495; q2 := 0.531103462366; q3 := 0.10353775285; q4 := 0.0038560700634; xp := 0.0; if (p > 0.5) then p := 1 - p; if (p < lim) then z := xp else begin //errorstate := false; if (p = 0.5) then z := xp else begin Y := sqrt(ln(1.0 / (p * p))); xp := Y + ((((Y * p4 + p3) * Y + p2) * Y + p1) * Y + p0) / ((((Y * q4 + q3) * Y + q2) * Y + q1) * Y + q0); if (p < 0.5) then xp := -xp; z := xp; end; end; zprob := z; end; // End function zprob function pNormalInvQuickApprox(p : double) : double; var z, px : double; // flag : boolean; begin // obtains the inverse of z, that is, the z for a probability associated // with a normally distributed z score. px := p; if (p > 0.5) then px := 1.0 - p; z := zprob(px{,flag}); if (p > 0.5) then z := abs(z); result := -z; end; //End of inversez Function *) (*function pNormalInvOld; var pp,y,a,b,y0 :extended; begin y:= 0; y0:=1; pp:=0.5; while y0>1E-10 do begin y0:=y; a:=-ln(2*pi)/2-y*y/2; b:=y; if abs(b)<1E-2 then y:=y+(pp-p)*exp(-a) else y:=y+ln(1+b*(pp-p)*exp(-a))/b; pp:=pNormalOld(y); y0:=abs(y-y0); end; result:=y; end; (**) function pGammaInv(f:longint;p:extended):extended; var pp,y,y0,a,b,a0 :extended; begin a0:=-lnGamma(f); if f=1 then begin y:=pNormalInv(p/2); y:=y*y/2; end else begin if f>100 then begin y:= sqrt(2*f-1)+pNormalInv(p); y:=y*y/4; end else y:=f/2; y0:=1; pp:=pGamma(f,y); while y0>1E-7 do begin y0:=y; a:=a0+(f/2-1)*ln(y)-y; b:=(f/2-1)/y-1; if abs(b*(pp-p)*exp(-a))<1E-5 then y:=y+(pp-p)*exp(-a) else y:=y+ln(1+b*(pp-p)*exp(-a))/b; pp:=pGamma(f,y); y0:=abs(y-y0); end; end; pGammaInv:=y; end; function pChi2Inv(f:longint;p:extended):extended; var y:extended; begin y:=pGammaInv(f,p); pChi2Inv:=2*y; end; {---------------------------------------------------------------------------} function pBetaInv1(f1,f2:longint;p:extended):extended; var pp,y,y0,a,b,a0 :extended; begin if p<=0 then y:=0 else if p>=1 then y:=1 else if (f1=1) and (f2=1) then y:=sin(p*pi/2)*sin(p*pi/2) else if (f1=1) and (f2=2) then y:=p*p else if (f1=2) and (f2=1) then y:=1-(1-p)*(1-p) else if (f1=2) and (f2=2) then y:=p else begin a0:=-lnGamma(f1)-lnGamma(f2); a0:=a0+lnGamma(f1+f2); y:=f1/(f1+f2); if f1=1 then begin y:= pGammaInv(1,1-p); y:= 2*y/(2*y+f2-1/2); end; y0:=1; pp:=pBeta(f1,f2,y); while y0>1E-8 do begin a:=a0+(f1/2-1)*ln(y)+(f2/2-1)*ln(1-y); b:=(f1/2-1)/y-(f2/2-1)/(1-y); if abs(b*(pp-p))*exp(-a)<1E-5 then y0:=-(pp-p)*exp(-a) else y0:=ln(1-b*(pp-p)*exp(-a))/b; y:=y+y0; pp:=pBeta(f1,f2,y); y0:=abs(y0)/y/(1-y); end; end; pBetaInv1:=y; end; {---------------------------------------------------------------------------} function pBetaInv(f1,f2:longint;p:extended):extended; var y: extended; begin if f1<=f2 then y:=pBetaInv1(f1,f2,p) else y:= 1-pBetaInv1(f2,f1,1-p); pBetaInv := y; end; {---------------------------------------------------------------------------} function pFdistrInv(f1,f2:longint;p:extended):extended; var y : extended; begin y:=pBetaInv(f2,f1,p); if y = 0 then pFdistrInv:= 0 //infinityINF else pFdistrInv:=f2/f1*(1-y)/y; end; {---------------------------------------------------------------------------} function pTdistrInv(f:longint;p:extended):extended; var t:extended; begin if p<=0.5 then t:=sqrt(pFdistrInv(1,f,2*p)) else t:=-sqrt(pFdistrInv(1,f,2*(1-p))); pTdistrInv:=t; end; {---------------------------------------------------------------------------} function pPoiss(lambda:extended; n:longint): extended; begin pPoiss:= 1-pGamma(2*n,lambda); end; {---------------------------------------------------------------------------} function pBin(n,x:longint; p:extended): extended; begin pBin:= pBeta(2*x,2+2*(n-x),p); end; {---------------------------------------------------------------------------} function PoissCL(n:longint; p:extended): extended; begin PoissCL := pGammaInv(2*n,1-p); end; {---------------------------------------------------------------------------} function BinCL(n,x:longint; pp:extended): extended; begin BinCL:= pBetaInv(2*x,2+2*(n-x),pp); end; {---------------------------------------------------------------------------} end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/GraphicsMathLibrary.pas�������������������������������������0000755�0001750�0001750�00000113463�12332473702�022112� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// The author gave written permission to distribute this file under the // same licensing terms as MRICRON. // // Graphics Math Library // // Copyright (C) 1982, 1985, 1992, 1995-1998 Earl F. Glynn, Overland Park, KS. // All Rights Reserved. E-Mail Address: EarlGlynn@att.net UNIT GraphicsMathLibrary; // Matrix/Vector Operations for 2D/3D Graphics} {$Include isgui.inc} INTERFACE USES SysUtils {$IFDEF GUI},Dialogs {$ENDIF}; CONST sizeUndefined = 1; size2D = 3; // 'size' of 2D homogeneous vector or transform matrix size3D = 4; // 'size' of 3D homogeneous vector or transform matrix TYPE EVectorError = CLASS(Exception); EMatrixError = CLASS(Exception); TAxis = (axisX, axisY, axisZ); TCoordinate = (coordCartesian, coordSpherical, coordCylindrical); TDimension = (dimen2D, dimen3D); // two- or three-dimensional TYPE TIndex = 1..4; // index of 'TMatrix' and 'TVector' TYPEs TMatrixI = // transformation 'matrix' RECORD size: TIndex; matrix: ARRAY[TIndex,TIndex] OF integer; END; TMatrix = // transformation 'matrix' RECORD size: TIndex; matrix: ARRAY[TIndex,TIndex] OF single //azx DOUBLE END; Trotation = (rotateClockwise, rotateCounterClockwise); // Normally the TVector TYPE is used to define 2D/3D homogenous // cartesian coordinates for graphics, i.e., (x,y,1) for 2D and // (x,y,z,1) for 3D. // // Cartesian coordinates can be converted to spherical (r, theta, phi), // or cylindrical coordinates (r,theta, z). Spherical or cylindrical // coordinates can be converted back to cartesian coordinates. TVector = RECORD size: TIndex; CASE INTEGER OF 0: (vector: ARRAY[TIndex] OF single); 1: (x: single; y: single; z: single; // contains 'h' for 2D cartesian vector h: single) END; TIntVector = RECORD size: TIndex; CASE INTEGER OF 0: (vector: ARRAY[TIndex] OF integer); 1: (x: integer; y: integer; z: integer; // contains 'h' for 2D cartesian vector h: integer) END; // Vector Operations // FUNCTION Vector2D (CONST xValue, yValue: DOUBLE): TVector; FUNCTION Vector3D (CONST xValue, yValue, zValue: DOUBLE): TVector; Function SameVec (const u,v: TVector): boolean; Function Eye3D: TMatrix; //returns identity matrix FUNCTION Transform (CONST u: TVector; CONST a: TMatrix): TVector; (* FUNCTION AddVectors (CONST u,v: TVector): TVector; // FUNCTION Transform (CONST u: TVector; CONST a: TMatrix): TVector; FUNCTION DotProduct (CONST u,v: TVector): DOUBLE; FUNCTION CrossProduct(CONST u,v: TVector): TVector; *) // Basic Matrix Operations FUNCTION Matrix2D (CONST m11,m12,m13, // 2D "graphics" matrix m21,m22,m23, m31,m32,m33: DOUBLE): TMatrix; FUNCTION Matrix3D (CONST m11,m12,m13,m14, // 3D "graphics" matrix m21,m22,m23,m24, m31,m32,m33,m34, m41,m42,m43,m44: DOUBLE): TMatrix; FUNCTION DotProduct (CONST u,v: TVector): DOUBLE; FUNCTION CrossProduct(CONST u,v: TVector): TVector; procedure NormalizeVector(var u: TVector); function nifti_mat33_determ( R: TMatrix ):double; //* determinant of 3x3 matrix */ procedure nifti_mat44_to_quatern( lR :TMatrix; var qb, qc, qd, qx, qy, qz, dx, dy, dz, qfac : single); FUNCTION MultiplyMatrices (CONST a,b: TMatrix): TMatrix; FUNCTION InvertMatrix3D (CONST Input:TMatrix): TMatrix; FUNCTION InvertMatrix (CONST a,b: TMatrix; VAR determinant: DOUBLE): TMatrix; // Transformation Matrices FUNCTION RotateMatrix (CONST dimension: TDimension; CONST xyz : TAxis; CONST angle : DOUBLE; CONST rotation : Trotation): TMatrix; // FUNCTION ScaleMatrix (CONST s: TVector): TMatrix; // FUNCTION TranslateMatrix (CONST t: TVector): TMatrix; FUNCTION ViewTransformMatrix (CONST coordinate: TCoordinate; CONST azimuth {or x}, elevation {or y}, distance {or z}: DOUBLE; CONST ScreenX, ScreenY, ScreenDistance: DOUBLE): TMatrix; // conversions // FUNCTION FromCartesian (CONST ToCoordinate: TCoordinate; CONST u: TVector): TVector; // FUNCTION ToCartesian (CONST FromCoordinate: TCoordinate; CONST u: TVector): TVector; //FUNCTION ToDegrees(CONST angle {radians}: DOUBLE): DOUBLE {degrees}; FUNCTION ToRadians(CONST angle {degrees}: DOUBLE): DOUBLE {radians}; // miscellaneous FUNCTION Defuzz(CONST x: DOUBLE): DOUBLE; { FUNCTION GetFuzz: DOUBLE; PROCEDURE SetFuzz(CONST x: DOUBLE); } IMPLEMENTATION Function Eye3D: TMatrix; //returns identity matrix begin result := Matrix3D (1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1); end; // 'Transform' multiplies a row 'vector' by a transformation 'matrix' // resulting in a new row 'vector'. The 'size' of the 'vector' and 'matrix' // must agree. To save execution time, the vectors are assumed to contain // a homogeneous coordinate. FUNCTION Transform (CONST u: TVector; CONST a: TMatrix): TVector; VAR i,k : TIndex; temp: DOUBLE; BEGIN RESULT.size := a.size; IF a.size = u.size THEN BEGIN FOR i := 1 TO a.size-1 DO BEGIN temp := 0.0; FOR k := 1 TO a.size DO BEGIN temp := temp + u.vector[k]*a.matrix[k,i]; END; RESULT.vector[i] := Defuzz(temp) END; RESULT.vector[a.size] := 1.0 {assume homogeneous coordinate} END ELSE raise EMatrixError.Create('Transform multiply error'+inttostr(a.size)+' '+inttostr(u.size)) END {Transform}; VAR fuzz : DOUBLE; FUNCTION DotProduct (CONST u,v: TVector): DOUBLE; VAR i: INTEGER; BEGIN IF (u.size = v.size) THEN BEGIN RESULT := 0.0; FOR i := 1 TO u.size-1 DO BEGIN RESULT := RESULT + u.vector[i] * v.vector[i]; END; END ELSE RAISE EMatrixError.Create('Vector dot product error') END; {DotProduct} FUNCTION CrossProduct(CONST u,v: TVector): TVector; BEGIN IF (u.size = v.size) AND (u.size = size3D) THEN BEGIN RESULT := Vector3D( u.y*v.z - v.y*u.z, -u.x*v.z + v.x*u.z, u.x*v.y - v.x*u.y) END ELSE RAISE EMatrixError.Create('Vector cross product error') END; {CrossProduct} procedure NormalizeVector(var u: TVector); var lSum: double; BEGIN lSum := sqrt((u.x*u.x)+(u.y*u.y)+(u.z*u.z)); if lSum <> 0 then u := Vector3D( u.x/lSum, u.y/lSum, u.z/lSum) END; {CrossProduct} procedure FromMatrix (M: TMatrix; var m11,m12,m13, m21,m22,m23, m31,m32,m33: DOUBLE) ; BEGIN m11 := M.Matrix[1,1]; m12 := M.Matrix[1,2]; m13 := M.Matrix[1,3]; m21 := M.Matrix[2,1]; m22 := M.Matrix[2,2]; m23 := M.Matrix[2,3]; m31 := M.Matrix[3,1]; m32 := M.Matrix[3,2]; m33 := M.Matrix[3,3]; END {FromMatrix3D}; function nifti_mat33_determ( R: TMatrix ):double; //* determinant of 3x3 matrix */ begin result := r.matrix[1,1]*r.matrix[2,2]*r.matrix[3,3] -r.matrix[1,1]*r.matrix[3,2]*r.matrix[2,3] -r.matrix[2,1]*r.matrix[1,2]*r.matrix[3,3] +r.matrix[2,1]*r.matrix[3,2]*r.matrix[1,3] +r.matrix[3,1]*r.matrix[1,2]*r.matrix[2,3] -r.matrix[3,1]*r.matrix[2,2]*r.matrix[1,3] ; end; function nifti_mat33_rownorm( A: TMatrix ): single; //* max row norm of 3x3 matrix */ var r1,r2,r3: single ; begin r1 := abs(A.matrix[1,1])+abs(A.matrix[1,2])+abs(A.matrix[1,3]) ; r2 := abs(A.matrix[2,1])+abs(A.matrix[2,2])+abs(A.matrix[2,3]) ; r3 := abs(A.matrix[3,1])+abs(A.matrix[3,2])+abs(A.matrix[3,3]) ; if( r1 < r2 ) then r1 := r2 ; if( r1 < r3 ) then r1 := r3 ; result := r1 ; end; function nifti_mat33_colnorm( A: TMatrix ): single; //* max column norm of 3x3 matrix */ var r1,r2,r3: single ; begin r1 := abs(A.matrix[1,1])+abs(A.matrix[2,1])+abs(A.matrix[3,1]) ; r2 := abs(A.matrix[1,2])+abs(A.matrix[2,2])+abs(A.matrix[3,2]) ; r3 := abs(A.matrix[1,3])+abs(A.matrix[2,3])+abs(A.matrix[3,3]) ; if( r1 < r2 ) then r1 := r2 ; if( r1 < r3 ) then r1 := r3 ; result := r1 ; end; function nifti_mat33_inverse( R: TMatrix ): TMatrix; //* inverse of 3x3 matrix */ var r11,r12,r13,r21,r22,r23,r31,r32,r33 , deti: double ; Q: TMatrix ; begin FromMatrix(R,r11,r12,r13,r21,r22,r23,r31,r32,r33); deti := r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; if( deti <> 0.0 ) then deti := 1.0 / deti ; Q.matrix[1,1] := deti*( r22*r33-r32*r23) ; Q.matrix[1,2] := deti*(-r12*r33+r32*r13) ; Q.matrix[1,3] := deti*( r12*r23-r22*r13) ; Q.matrix[2,1] := deti*(-r21*r33+r31*r23) ; Q.matrix[2,2] := deti*( r11*r33-r31*r13) ; Q.matrix[2,3] := deti*(-r11*r23+r21*r13) ; Q.matrix[3,1] := deti*( r21*r32-r31*r22) ; Q.matrix[3,2] := deti*(-r11*r32+r31*r12) ; Q.matrix[3,3] := deti*( r11*r22-r21*r12) ; result := Q; end; (*procedure ReportMatrix (lStr: string;lM:TMatrix); begin showmessage(lStr); showmessage( RealToStr(lM.matrix[1,1],6)+','+RealToStr(lM.matrix[1,2],6)+','+RealToStr(lM.matrix[1,3],6)+','+RealToStr(lM.matrix[1,4],6)); showmessage( RealToStr(lM.matrix[2,1],6)+','+RealToStr(lM.matrix[2,2],6)+','+RealToStr(lM.matrix[2,3],6)+','+RealToStr(lM.matrix[2,4],6)); showmessage( RealToStr(lM.matrix[3,1],6)+','+RealToStr(lM.matrix[3,2],6)+','+RealToStr(lM.matrix[3,3],6)+','+RealToStr(lM.matrix[3,4],6)); showmessage( RealToStr(lM.matrix[4,1],6)+','+RealToStr(lM.matrix[4,2],6)+','+RealToStr(lM.matrix[4,3],6)+','+RealToStr(lM.matrix[4,4],6)); end;*) (*---------------------------------------------------------------------------*) (*! polar decomposition of a 3x3 matrix This finds the closest orthogonal matrix to input A (in both the Frobenius and L2 norms). Algorithm is that from NJ Higham, SIAM J Sci Stat Comput, 7:1160-1174. *)(*-------------------------------------------------------------------------*) function nifti_mat33_polar( A: TMatrix ): TMatrix; const dif: single=1.0 ; k: integer=0 ; var X , Y , Z: TMatrix ; alp,bet,gam,gmi : single; begin X := A ; (* force matrix to be nonsingular *) //reportmatrix('x',X); gam := nifti_mat33_determ(X) ; while( gam = 0.0 )do begin (* perturb matrix *) gam := 0.00001 * ( 0.001 + nifti_mat33_rownorm(X) ) ; X.matrix[1,1] := X.matrix[1,1]+gam ; X.matrix[2,2] := X.matrix[2,2]+gam ; X.matrix[3,3] := X.matrix[3,3] +gam ; gam := nifti_mat33_determ(X) ; end; while true do begin Y := nifti_mat33_inverse(X) ; if( dif > 0.3 )then begin (* far from convergence *) alp := sqrt( nifti_mat33_rownorm(X) * nifti_mat33_colnorm(X) ) ; bet := sqrt( nifti_mat33_rownorm(Y) * nifti_mat33_colnorm(Y) ) ; gam := sqrt( bet / alp ) ; gmi := 1.0 / gam ; end else begin gam := 1.0; gmi := 1.0 ; (* close to convergence *) end; Z.matrix[1,1] := 0.5 * ( gam*X.matrix[1,1] + gmi*Y.matrix[1,1] ) ; Z.matrix[1,2] := 0.5 * ( gam*X.matrix[1,2] + gmi*Y.matrix[2,1] ) ; Z.matrix[1,3] := 0.5 * ( gam*X.matrix[1,3] + gmi*Y.matrix[3,1] ) ; Z.matrix[2,1] := 0.5 * ( gam*X.matrix[2,1] + gmi*Y.matrix[1,2] ) ; Z.matrix[2,2] := 0.5 * ( gam*X.matrix[2,2] + gmi*Y.matrix[2,2] ) ; Z.matrix[2,3] := 0.5 * ( gam*X.matrix[2,3] + gmi*Y.matrix[3,2] ) ; Z.matrix[3,1] := 0.5 * ( gam*X.matrix[3,1] + gmi*Y.matrix[1,3] ) ; Z.matrix[3,2] := 0.5 * ( gam*X.matrix[3,2] + gmi*Y.matrix[2,3] ) ; Z.matrix[3,3] := 0.5 * ( gam*X.matrix[3,3] + gmi*Y.matrix[3,3] ) ; dif := abs(Z.matrix[1,1]-X.matrix[1,1])+abs(Z.matrix[1,2]-X.matrix[1,2]) +abs(Z.matrix[1,3]-X.matrix[1,3])+abs(Z.matrix[2,1]-X.matrix[2,1]) +abs(Z.matrix[2,2]-X.matrix[2,2])+abs(Z.matrix[2,3]-X.matrix[2,3]) +abs(Z.matrix[3,1]-X.matrix[3,1])+abs(Z.matrix[3,2]-X.matrix[3,2]) +abs(Z.matrix[3,3]-X.matrix[3,3]) ; k := k+1 ; if( k > 100) or (dif < 3.e-6 ) then begin result := Z; break ; (* convergence or exhaustion *) end; X := Z ; end; result := Z ; end; procedure nifti_mat44_to_quatern( lR :TMatrix; var qb, qc, qd, qx, qy, qz, dx, dy, dz, qfac : single); var r11,r12,r13 , r21,r22,r23 , r31,r32,r33, xd,yd,zd , a,b,c,d : double; P,Q: TMatrix; //3x3 begin (* offset outputs are read write out of input matrix *) qx := lR.matrix[1,4]; qy := lR.matrix[2,4]; qz := lR.matrix[3,4]; (* load 3x3 matrix into local variables *) FromMatrix(lR,r11,r12,r13,r21,r22,r23,r31,r32,r33); (* compute lengths of each column; these determine grid spacings *) xd := sqrt( r11*r11 + r21*r21 + r31*r31 ) ; yd := sqrt( r12*r12 + r22*r22 + r32*r32 ) ; zd := sqrt( r13*r13 + r23*r23 + r33*r33 ) ; (* if a column length is zero, patch the trouble *) if( xd = 0.0 )then begin r11 := 1.0 ; r21 := 0; r31 := 0.0 ; xd := 1.0 ; end; if( yd = 0.0 )then begin r22 := 1.0 ; r12 := 0; r32 := 0.0 ; yd := 1.0 ; end; if( zd = 0.0 )then begin r33 := 1.0 ; r13 := 0; r23 := 0.0 ; zd := 1.0 ; end; (* assign the output lengths *) dx := xd; dy := yd; dz := zd; (* normalize the columns *) r11 := r11/xd ; r21 := r21/xd ; r31 := r31/xd ; r12 := r12/yd ; r22 := r22/yd ; r32 := r32/yd ; r13 := r13/zd ; r23 := r23/zd ; r33 := r33/zd ; (* At this point, the matrix has normal columns, but we have to allow for the fact that the hideous user may not have given us a matrix with orthogonal columns. So, now find the orthogonal matrix closest to the current matrix. One reason for using the polar decomposition to get this orthogonal matrix, rather than just directly orthogonalizing the columns, is so that inputting the inverse matrix to R will result in the inverse orthogonal matrix at this point. If we just orthogonalized the columns, this wouldn't necessarily hold. *) Q := Matrix2D (r11,r12,r13, // 2D "graphics" matrix r21,r22,r23, r31,r32,r33); P := nifti_mat33_polar(Q) ; (* P is orthog matrix closest to Q *) FromMatrix(P,r11,r12,r13,r21,r22,r23,r31,r32,r33); //ReportMatrix('xxx',Q); //ReportMatrix('svd',P); (* [ r11 r12 r13 ] *) (* at this point, the matrix [ r21 r22 r23 ] is orthogonal *) (* [ r31 r32 r33 ] *) (* compute the determinant to determine if it is proper *) zd := r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; (* should be -1 or 1 *) if( zd > 0 )then begin (* proper *) qfac := 1.0 ; end else begin (* improper ==> flip 3rd column *) qfac := -1.0 ; r13 := -r13 ; r23 := -r23 ; r33 := -r33 ; end; (* now, compute quaternion parameters *) a := r11 + r22 + r33 + 1.0; if( a > 0.5 ) then begin (* simplest case *) a := 0.5 * sqrt(a) ; b := 0.25 * (r32-r23) / a ; c := 0.25 * (r13-r31) / a ; d := 0.25 * (r21-r12) / a ; end else begin (* trickier case *) xd := 1.0 + r11 - (r22+r33) ; (* 4*b*b *) yd := 1.0 + r22 - (r11+r33) ; (* 4*c*c *) zd := 1.0 + r33 - (r11+r22) ; (* 4*d*d *) if( xd > 1.0 ) then begin b := 0.5 * sqrt(xd) ; c := 0.25* (r12+r21) / b ; d := 0.25* (r13+r31) / b ; a := 0.25* (r32-r23) / b ; end else if( yd > 1.0 ) then begin c := 0.5 * sqrt(yd) ; b := 0.25* (r12+r21) / c ; d := 0.25* (r23+r32) / c ; a := 0.25* (r13-r31) / c ; end else begin d := 0.5 * sqrt(zd) ; b := 0.25* (r13+r31) / d ; c := 0.25* (r23+r32) / d ; a := 0.25* (r21-r12) / d ; end; if( a < 0.0 )then begin b:=-b ; c:=-c ; d:=-d; {a:=-a; not used} end; end; qb := b ; qc := c ; qd := d ; end; //nifti_mat44_to_quatern // ************************* Vector Operations ************************* // This procedure defines two-dimensional homogeneous coordinates (x,y,1) // as a single 'vector' data element 'u'. The 'size' of a two-dimensional // homogenous vector is 3. // This procedure defines three-dimensional homogeneous coordinates // (x,y,z,1) as a single 'vector' data element 'u'. The 'size' of a // three-dimensional homogenous vector is 4. Function SameVec (const u,v: TVector): boolean; begin if (u.x=v.x) and (u.y=v.y) and (u.z=v.z) then result := true else result := false; end; FUNCTION Vector3D (CONST xValue, yValue, zValue: DOUBLE): TVector; BEGIN WITH RESULT DO BEGIN x := xValue; y := yValue; z := zValue; h := 1.0; // homogeneous coordinate size := size3D END END {Vector3D}; // AddVectors adds two vectors defined with homogeneous coordinates. FUNCTION AddVectors (CONST u,v: TVector): TVector; VAR i: TIndex; BEGIN IF (u.size IN [size2D..size3D]) AND (v.size IN [size2D..size3D]) AND (u.size = v.size) THEN BEGIN RESULT.size := u.size; FOR i := 1 TO u.size-1 DO {2D + 2D = 2D or 3D + 3D = 3D} BEGIN RESULT.vector[i] := u.vector[i] + v.vector[i] END; RESULT.vector[u.size] := 1.0 {homogeneous coordinate} END ELSE raise EVectorError.Create('Vector Addition Mismatch') END {AddVectors}; // *********************** Basic Matrix Operations ********************** FUNCTION Matrix2D (CONST m11,m12,m13, m21,m22,m23, m31,m32,m33: DOUBLE): TMatrix; BEGIN WITH RESULT DO BEGIN matrix[1,1] := m11; matrix[1,2] := m12; matrix[1,3] := m13; matrix[2,1] := m21; matrix[2,2] := m22; matrix[2,3] := m23; matrix[3,1] := m31; matrix[3,2] := m32; matrix[3,3] := m33; size := size2D END END {Matrix2D}; FUNCTION Matrix3D (CONST m11,m12,m13,m14, m21,m22,m23,m24, m31,m32,m33,m34, m41,m42,m43,m44: DOUBLE): TMatrix; BEGIN WITH RESULT DO BEGIN matrix[1,1] := m11; matrix[1,2] := m12; matrix[1,3] := m13; matrix[1,4] := m14; matrix[2,1] := m21; matrix[2,2] := m22; matrix[2,3] := m23; matrix[2,4] := m24; matrix[3,1] := m31; matrix[3,2] := m32; matrix[3,3] := m33; matrix[3,4] := m34; matrix[4,1] := m41; matrix[4,2] := m42; matrix[4,3] := m43; matrix[4,4] := m44; size := size3D END END {Matrix3D}; // Compound geometric transformation matrices can be formed by multiplying // simple transformation matrices. This procedure only multiplies together // matrices for two- or three-dimensional transformations, i.e., 3x3 or 4x4 // matrices. The multiplier and multiplicand must be of the same dimension. FUNCTION MultiplyMatrices (CONST a,b: TMatrix): TMatrix; VAR i,j,k: TIndex; temp : DOUBLE; BEGIN RESULT.size := a.size; IF a.size = b.size THEN FOR i := 1 TO a.size DO BEGIN FOR j := 1 TO a.size DO BEGIN temp := 0.0; FOR k := 1 TO a.size DO BEGIN temp := temp + a.matrix[i,k]*b.matrix[k,j]; END; RESULT.matrix[i,j] := Defuzz(temp) END END {$IFDEF GUI} ELSE Showmessage('MultiplyMatricesError'+inttostr(a.size)+'x'+inttostr(b.size)); {$ELSE} else writeln('MultiplyMatricesError'+inttostr(a.size)+'x'+inttostr(b.size)); {$ENDIF} //ELSE EMatrixError.Create('MultiplyMatrices error') END {MultiplyMatrices}; PROCEDURE lubksb(a: {glnpbynp}TMatrix; n: integer; indx: TIntVector; VAR b: TVector); VAR j,ip,ii,i: integer; sum: double; BEGIN ii := 0; FOR i := 1 TO n DO BEGIN ip := indx.vector[i]; sum := b.vector[ip]; b.vector[ip] := b.vector[i]; IF (ii <> 0) THEN BEGIN FOR j := ii TO i-1 DO BEGIN sum := sum-a.matrix[i,j]*b.vector[j] END END ELSE IF (sum <> 0.0) THEN BEGIN ii := i END; b.vector[i] := sum END; FOR i := n DOWNTO 1 DO BEGIN sum := b.vector[i]; IF (i < n) THEN BEGIN FOR j := i+1 TO n DO BEGIN sum := sum-a.matrix[i,j]*b.vector[j] END END; b.vector[i] := sum/a.matrix[i,i] END end; PROCEDURE ludcmp(VAR a: TMatrix; n: integer; VAR indx: TIntVector; VAR d: double); CONST tiny=1.0e-20; VAR k,j,imax,i: integer; sum,dum,big: real; vv: TVector; BEGIN d := 1.0; FOR i := 1 TO n DO BEGIN big := 0.0; FOR j := 1 TO n DO IF (abs(a.matrix[i,j]) > big) THEN big := abs(a.matrix[i,j]); IF (big = 0.0) THEN BEGIN writeln('pause in LUDCMP - singular matrix'); readln END; vv.vector[i] := 1.0/big END; FOR j := 1 TO n DO BEGIN FOR i := 1 TO j-1 DO BEGIN sum := a.matrix[i,j]; FOR k := 1 TO i-1 DO BEGIN sum := sum-a.matrix[i,k]*a.matrix[k,j] END; a.matrix[i,j] := sum END; big := 0.0; FOR i := j TO n DO BEGIN sum := a.matrix[i,j]; FOR k := 1 TO j-1 DO BEGIN sum := sum-a.matrix[i,k]*a.matrix[k,j] END; a.matrix[i,j] := sum; dum := vv.vector[i]*abs(sum); IF (dum > big) THEN BEGIN big := dum; imax := i END END; IF (j <> imax) THEN BEGIN FOR k := 1 TO n DO BEGIN dum := a.matrix[imax,k]; a.matrix[imax,k] := a.matrix[j,k]; a.matrix[j,k] := dum END; d := -d; vv.vector[imax] := vv.vector[j] END; indx.vector[j] := imax; IF (a.matrix[j,j] = 0.0) THEN a.matrix[j,j] := tiny; IF (j <> n) THEN BEGIN dum := 1.0/a.matrix[j,j]; FOR i := j+1 TO n DO BEGIN a.matrix[i,j] := a.matrix[i,j]*dum END END END; END; FUNCTION InvertMatrix3D (CONST Input:TMatrix): TMatrix; var n,i,j: integer; d: double; indx: tIntVector; col: tvector; a,y: TMatrix; begin a:= Input; n := 3; y.size := size3D; ludcmp(a,n,indx,d); for j := 1 to n do begin for i := 1 to n do col.vector[i] := 0; col.vector[j] := 1.0; lubksb(a,n,indx,col); for i := 1 to n do y.matrix[i,j] := col.vector[i]; end; result := y; end; // This procedure inverts a general transformation matrix. The user need // not form an inverse geometric transformation by keeping a product of // the inverses of simple geometric transformations: translations, rotations // and scaling. A determinant of zero indicates no inverse is possible for // a singular matrix. FUNCTION InvertMatrix (CONST a,b: TMatrix; VAR determinant: DOUBLE): TMatrix; VAR c : TMatrix; i,i_pivot: TIndex; i_flag : ARRAY[TIndex] OF BOOLEAN; j,j_pivot: TIndex; j_flag : ARRAY[TIndex] OF BOOLEAN; modulus : DOUBLE; n : TIndex; pivot : DOUBLE; pivot_col: ARRAY[TIndex] OF TIndex; pivot_row: ARRAY[TIndex] OF TIndex; temporary: DOUBLE; BEGIN c := a; // The matrix inversion algorithm used here WITH c DO // is similar to the "maximum pivot strategy" BEGIN // described in "Applied Numerical Methods" FOR i := 1 TO size DO // by Carnahan, Luther and Wilkes, BEGIN // pp. 282-284. i_flag[i] := TRUE; j_flag[i] := TRUE END; modulus := 1.0; i_pivot := 1; // avoid initialization warning j_pivot := 1; // avoid initialization warning FOR n := 1 TO size DO BEGIN pivot := 0.0; IF ABS(modulus) > 0.0 THEN BEGIN FOR i := 1 TO size DO IF i_flag[i] THEN FOR j := 1 TO size DO IF j_flag[j] THEN IF ABS(matrix[i,j]) > ABS(pivot) THEN BEGIN pivot := matrix[i,j]; // largest value on which to pivot i_pivot := i; // indices of pivot element j_pivot := j END; IF Defuzz(pivot) = 0 // If pivot is too small, consider THEN modulus := 0 // the matrix to be singular ELSE BEGIN pivot_row[n] := i_pivot; pivot_col[n] := j_pivot; i_flag[i_pivot] := FALSE; j_flag[j_pivot] := FALSE; FOR i := 1 TO size DO IF i <> i_pivot THEN FOR j := 1 TO size DO // pivot column unchanged for elements IF j <> j_pivot // not in pivot row or column ... THEN matrix[i,j] := (matrix[i,j]*matrix[i_pivot,j_pivot] - matrix[i_pivot,j]*matrix[i,j_pivot]) / modulus; // 2x2 minor / modulus FOR j := 1 TO size DO IF j <> j_pivot // change signs of elements in pivot row THEN matrix[i_pivot,j] := -matrix[i_pivot,j]; temporary := modulus; // exchange pivot element and modulus modulus := matrix[i_pivot,j_pivot]; matrix[i_pivot,j_pivot] := temporary END END END {FOR n} END {WITH}; determinant := Defuzz(modulus); IF determinant <> 0 THEN BEGIN RESULT.size := c.size; // The matrix inverse must be unscrambled FOR i := 1 TO c.size DO // if pivoting was not along main diagonal. FOR j := 1 TO c.size DO RESULT.matrix[pivot_row[i],pivot_col[j]] := Defuzz(c.matrix[i,j]/determinant) END ELSE EMatrixError.Create('InvertMatrix error') END {InvertMatrix}; // *********************** Transformation Matrices ******************** // This procedure defines a matrix for a two- or three-dimensional rotation. // To avoid possible confusion in the sense of the rotation, 'rotateClockwise' // or 'roCounterlcockwise' must always be specified along with the axis // of rotation. Two-dimensional rotations are assumed to be about the z-axis // in the x-y plane. // // A rotation about an arbitrary axis can be performed with the following // steps: // (1) Translate the object into a new coordinate system where (x,y,z) // maps into the origin (0,0,0). // (2) Perform appropriate rotations about the x and y axes of the // coordinate system so that the unit vector (a,b,c) is mapped into // the unit vector along the z axis. // (3) Perform the desired rotation about the z-axis of the new // coordinate system. // (4) Apply the inverse of step (2). // (5) Apply the inverse of step (1). FUNCTION RotateMatrix (CONST dimension: TDimension; CONST xyz : TAxis; CONST angle : DOUBLE; CONST rotation : Trotation): TMatrix; VAR cosx : DOUBLE; sinx : DOUBLE; TempAngle: DOUBLE; BEGIN TempAngle := angle; // Use TempAngle since "angle" is CONST parameter IF rotation = rotateCounterClockwise THEN TempAngle := -TempAngle; cosx := Defuzz( COS(TempAngle) ); sinx := Defuzz( SIN(TempAngle) ); CASE dimension OF dimen2D: CASE xyz OF axisX,axisY: EMatrixError.Create('Invalid 2D rotation matrix. Specify axisZ'); axisZ: RESULT := Matrix2D ( cosx, -sinx, 0, sinx, cosx, 0, 0, 0, 1) END; dimen3D: CASE xyz OF axisX: RESULT := Matrix3D ( 1, 0, 0, 0, 0, cosx, -sinx, 0, 0, sinx, cosx, 0, 0, 0, 0, 1); axisY: RESULT := Matrix3D ( cosx, 0, sinx, 0, 0, 1, 0, 0, -sinx, 0, cosx, 0, 0, 0, 0, 1); axisZ: RESULT := Matrix3D ( cosx, -sinx, 0, 0, sinx, cosx, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); END END END {RotateMatrix}; // 'ScaleMatrix' accepts a 'vector' containing the scaling factors for // each of the dimensions and creates a scaling matrix. The size // of the vector dictates the size of the resulting matrix. FUNCTION ScaleMatrix (CONST s: TVector): TMatrix; BEGIN CASE s.size OF size2D: RESULT := Matrix2D (s.x, 0, 0, 0, s.y, 0, 0, 0, 1); size3D: RESULT := Matrix3D (s.x, 0, 0, 0, 0, s.y, 0, 0, 0, 0, s.z, 0, 0, 0, 0, 1) END END {ScaleMatrix}; // 'TranslateMatrix' defines a translation transformation matrix. The // components of the vector 't' determine the translation components. // (Note: 'Translate' here is from kinematics in physics.) FUNCTION TranslateMatrix (CONST t: TVector): TMatrix; BEGIN CASE t.size OF size2D: RESULT := Matrix2D ( 1, 0, 0, 0, 1, 0, t.x, t.y, 1); size3D: RESULT := Matrix3D ( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, t.x, t.y, t.z, 1) END END {TranslateMatrix}; // 'ViewTransformMatrix' creates a transformation matrix for changing // from world coordinates to eye coordinates. The location of the 'eye' // from the 'object' is given in spherical (azimuth,elevation,distance) // coordinates or Cartesian (x,y,z) coordinates. The size of the screen // is 'ScreenX' units horizontally and 'ScreenY' units vertically. The // eye is 'ScreenDistance' units from the viewing screen. A large ratio // 'ScreenDistance/ScreenX (or ScreenY)' specifies a narrow aperature // -- a telephoto view. Conversely, a small ratio specifies a large // aperature -- a wide-angle view. This view transform matrix is very // useful as the default three-dimensional transformation matrix. Once // set, all points are automatically transformed. FUNCTION ViewTransformMatrix (CONST coordinate: TCoordinate; CONST azimuth {or x}, elevation {or y}, distance {or z}: DOUBLE; CONST ScreenX, ScreenY, ScreenDistance: DOUBLE): TMatrix; CONST HalfPI = PI / 2.0; VAR a : TMatrix; b : TMatrix; cosm : DOUBLE; // COS(-angle) hypotenuse: DOUBLE; sinm : DOUBLE; // SIN(-angle) temporary : DOUBLE; u : TVector; x : DOUBLE ABSOLUTE azimuth; // x and azimuth are synonyms y : DOUBLE ABSOLUTE elevation; // synonyms z : DOUBLE ABSOLUTE distance; // synonyms BEGIN CASE coordinate OF coordCartesian: u := Vector3D (-x, -y, -z); coordSpherical: BEGIN temporary := -distance * COS(elevation); u := Vector3D (temporary * COS(azimuth - HalfPI), temporary * SIN(azimuth - HalfPI), -distance * SIN(elevation)); END END; a := TranslateMatrix(u); // translate origin to 'eye' b := RotateMatrix (dimen3D, axisX, HalfPI, rotateClockwise); a := MultiplyMatrices(a,b); CASE coordinate OF coordCartesian: BEGIN temporary := SQR(x) + SQR(y); hypotenuse := SQRT(temporary); if hypotenuse <> 0 then begin cosm := -y/hypotenuse; sinm := x/hypotenuse; end else begin cosm := 1;//abba sinm := 0; end; b := Matrix3D ( cosm, 0, sinm, 0, 0, 1, 0, 0, -sinm, 0, cosm, 0, 0, 0, 0, 1); a := MultiplyMatrices (a,b); cosm := hypotenuse; hypotenuse := SQRT(temporary + SQR(z)); cosm := cosm/hypotenuse; sinm := -z/hypotenuse; b := Matrix3D ( 1, 0, 0, 0, 0, cosm, -sinm, 0, 0, sinm, cosm, 0, 0, 0, 0, 1) END; coordSpherical: BEGIN b := RotateMatrix (dimen3D,axisY,-azimuth,rotateCounterClockwise); a := MultiplyMatrices(a,b); b := RotateMatrix (dimen3D,axisX,elevation,rotateCounterClockwise); END END {CASE}; a := MultiplyMatrices (a,b); u := Vector3D (ScreenDistance/(0.5*ScreenX), ScreenDistance/(0.5*ScreenY),-1.0); b := ScaleMatrix (u); // reverse sense of z-axis; screen transformation RESULT := MultiplyMatrices (a,b); END {ViewTransformMatrix}; // *************************** Conversions ************************** // This function converts the vector parameter from Cartesian // coordinates to the specified type of coordinates. FUNCTION FromCartesian (CONST ToCoordinate: TCoordinate; CONST u: TVector): TVector; VAR phi : DOUBLE; r : DOUBLE; temp : DOUBLE; theta: DOUBLE; BEGIN IF ToCoordinate = coordCartesian THEN RESULT := u ELSE BEGIN RESULT.size := u.size; IF (u.size = size3D) AND (ToCoordinate = coordSpherical) THEN BEGIN // spherical 3D temp := SQR(u.x)+SQR(u.y); // (x,y,z) -> (r,theta,phi) r := SQRT(temp+SQR(u.z)); IF Defuzz(u.x) = 0.0 THEN theta := PI/4 ELSE theta := ARCTAN(u.y/u.x); IF Defuzz(u.z) = 0.0 THEN phi := PI/4 ELSE phi := ARCTAN(SQRT(temp)/u.z); RESULT.x := r; RESULT.y := theta; RESULT.z := phi END ELSE BEGIN // cylindrical 2D/3D or spherical 2D // (x,y) -> (r,theta) or (x,y,z) -> (r,theta,z) r := SQRT( SQR(u.x) + SQR(u.y) ); IF Defuzz(u.x) = 0.0 THEN theta := PI/4 ELSE theta := ARCTAN(u.y/u.x); RESULT.x := r; RESULT.y := theta END END END {FromCartesian}; // This function converts the vector parameter from specified coordinates // into Cartesian coordinates. FUNCTION ToCartesian (CONST FromCoordinate: TCoordinate; CONST u: TVector): TVector; VAR phi : DOUBLE; r : DOUBLE; sinphi: DOUBLE; theta : DOUBLE; BEGIN RESULT := u; IF FromCoordinate = coordCartesian THEN RESULT := u ELSE BEGIN RESULT.size := u.size; IF (u.size = size3D) AND (FromCoordinate = coordSpherical) THEN BEGIN // spherical 3D r := u.x; // (r,theta,phi) -> (x,y,z) theta := u.y; phi := u.z; sinphi := SIN(phi); RESULT.x := r * COS(theta) * sinphi; RESULT.y := r * SIN(theta) * sinphi; RESULT.z := r * COS(phi) END ELSE BEGIN // cylindrical 2D/3D or spherical 2D r := u.x; // (r,theta) -> (x,y) or (r,theta,z) -> (x,y,z) theta := u.y; RESULT.x := r * COS(theta); RESULT.y := r * SIN(theta) END END END {ToCartesian}; // Convert angle in degrees to radians. FUNCTION ToRadians (CONST angle: DOUBLE): DOUBLE; BEGIN RESULT := PI/180.0 * angle END; {ToRadians} // *************************** Miscellaneous ************************** // 'Defuzz' is used for comparisons and to avoid propagation of 'fuzzy', // nearly-zero values. DOUBLE calculations often result in 'fuzzy' values. // The term 'fuzz' was adapted from the APL language. FUNCTION Defuzz(CONST x: DOUBLE): DOUBLE; BEGIN IF ABS(x) < fuzz THEN RESULT := 0.0 ELSE RESULT := x END {Defuzz}; INITIALIZATION fuzz := 1.0E-6; END. {GraphicsMath UNIT} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/common/delphiselectfolder.pas��������������������������������������0000755�0001750�0001750�00000006114�11341734616�022051� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit delphiselectfolder; interface function BrowseForFolder(const browseTitle: String; const initialFolder: String = ''; mayCreateNewFolder: Boolean = False): String; function SelectDirectoryDelphi(const browseTitle: String; var Folder: String; mayCreateNewFolder: Boolean = False): boolean; implementation uses Windows, Forms, shlobj; function SelectDirectoryDelphi(const browseTitle: String; var Folder: String; mayCreateNewFolder: Boolean = False): boolean; var lTemp: string; begin result := false; lTemp := BrowseForFolder(browseTitle, Folder, mayCreateNewFolder); if (lTemp <> '') then begin Folder := lTemp; result := true; end; // end; var lg_StartFolder: String; //////////////////////////////////////////////////////////////////////// // Call back function used to set the initial browse directory. //////////////////////////////////////////////////////////////////////// function BrowseForFolderCallBack(Wnd: HWND; uMsg: UINT; lParam, lpData: LPARAM): Integer stdcall; begin if uMsg = BFFM_INITIALIZED then SendMessage(Wnd,BFFM_SETSELECTION, 1, Integer(@lg_StartFolder[1])); result := 0; end; //////////////////////////////////////////////////////////////////////// // This function allows the user to browse for a folder // // Arguments:- // browseTitle : The title to display on the browse dialog. // initialFolder : Optional argument. Use to specify the folder // initially selected when the dialog opens. // mayCreateNewFolder : Flag indicating whether the user can create a // new folder. // // Returns: The empty string if no folder was selected (i.e. if the user // clicked cancel), otherwise the full folder path. //////////////////////////////////////////////////////////////////////// function BrowseForFolder(const browseTitle: String; const initialFolder: String =''; mayCreateNewFolder: Boolean = False): String; // With later versions of Delphi you may not need these constants. const BIF_NEWDIALOGSTYLE=$40; BIF_NONEWFOLDERBUTTON=$200; var browse_info: TBrowseInfo; folder: array[0..MAX_PATH] of char; find_context: PItemIDList; begin //-------------------------- // Initialise the structure. //-------------------------- FillChar(browse_info,SizeOf(browse_info),#0); lg_StartFolder := initialFolder; browse_info.pszDisplayName := @folder[0]; browse_info.lpszTitle := PChar(browseTitle); browse_info.ulFlags := BIF_RETURNONLYFSDIRS or BIF_NEWDIALOGSTYLE; if not mayCreateNewFolder then browse_info.ulFlags := browse_info.ulFlags or BIF_NONEWFOLDERBUTTON; browse_info.hwndOwner := Application.Handle; if initialFolder <> '' then browse_info.lpfn := BrowseForFolderCallBack; find_context := SHBrowseForFolder(browse_info); if Assigned(find_context) then begin if SHGetPathFromIDList(find_context,folder) then result := folder else result := ''; GlobalFreePtr(find_context); end else result := ''; end; end.����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/xfmri2.bat���������������������������������������������������������0000755�0001750�0001750�00000000274�10426762170�016112� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./mricron ./templates/ch2.nii.gz -s 3 -l 0 -h 140 -c pink -o ./templates/ch2bet.nii.gz -c -0 -l 30 -h 200 -o ./example/attention.nii.gz -l 1.96 -h 5 -z -b 40 -t 50 -r ./example/fmri2r.ini������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/render.lfm���������������������������������������������������������0000755�0001750�0001750�00000042635�12370426516�016202� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object RenderForm: TRenderForm Left = 313 Height = 512 Top = 165 Width = 955 ActiveControl = AzimuthEdit Caption = 'Volume Render' ClientHeight = 512 ClientWidth = 955 Font.Name = 'MS Sans Serif' Menu = MainMenu1 OnCreate = FormCreate OnHide = FormHide OnShow = FormShow Position = poScreenCenter LCLVersion = '1.0.12.0' object RenderBar: TPanel Left = 0 Height = 32 Top = 0 Width = 955 Align = alTop BevelOuter = bvNone ClientHeight = 32 ClientWidth = 955 TabOrder = 0 object Label4: TLabel Left = 152 Height = 18 Top = 5 Width = 58 Caption = 'Elevation' ParentColor = False end object Label1: TLabel Left = 4 Height = 18 Top = 5 Width = 53 Caption = 'Azimuth' ParentColor = False end object RefreshBtn: TSpeedButton Left = 296 Height = 31 Hint = 'Generate high-resolution rendering' Top = 0 Width = 40 Glyph.Data = { 76080000424D7608000000000000360000002800000018000000160000000100 2000000000004008000064000000640000000000000000000000FFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFF FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFF FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000 FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF } NumGlyphs = 0 OnClick = RefreshClick ShowHint = True ParentShowHint = False end object RenderImageBUP: TImage Tag = 2 Cursor = crCross Left = 360 Height = 12 Top = 8 Width = 12 AutoSize = True Center = True OnMouseDown = RenderImageMouseDown OnMouseMove = RenderImageMouseMove Stretch = True Visible = False end object Label5: TLabel Left = 616 Height = 18 Top = 5 Width = 66 Caption = 'Shading %' ParentColor = False end object AzimuthEdit: TSpinEdit Left = 72 Height = 16 Top = 2 Width = 70 Increment = 30 MaxValue = 360 OnChange = EditChange TabOrder = 0 Value = 120 end object ElevationEdit: TSpinEdit Left = 216 Height = 16 Top = 2 Width = 70 Increment = 30 MaxValue = 180 MinValue = -180 OnChange = EditChange TabOrder = 1 Value = 30 end object BiasTrack: TTrackBar Left = 352 Height = 29 Top = 2 Width = 120 Max = 100 OnChange = BiasTrackChange Position = 50 TickStyle = tsNone TabOrder = 2 end object GainTrack: TTrackBar Left = 480 Height = 29 Top = 2 Width = 120 Max = 100 OnChange = BiasTrackChange Position = 50 TickStyle = tsNone TabOrder = 3 end object ShadeEdit: TSpinEdit Left = 690 Height = 16 Top = 2 Width = 70 Increment = 10 OnChange = EditChange TabOrder = 4 end object ClipTrack: TTrackBar Left = 776 Height = 29 Top = 2 Width = 120 Max = 999 OnChange = ClipTrackChange Position = 0 TickStyle = tsNone TabOrder = 5 end end object RenderPanel: TScrollBox Left = 0 Height = 480 Top = 32 Width = 955 HorzScrollBar.Page = 955 VertScrollBar.Page = 480 Align = alClient ClientHeight = 480 ClientWidth = 955 TabOrder = 1 object RenderImage: TImage Tag = 2 Cursor = crCross Left = 2 Height = 12 Top = 2 Width = 12 AutoSize = True OnMouseDown = RenderImageMouseDown OnMouseMove = RenderImageMouseMove Stretch = True end end object MainMenu1: TMainMenu left = 16 top = 32 object FileMenu: TMenuItem Caption = 'File' object Settings1: TMenuItem Caption = 'Open settings' OnClick = Settings1Click end object Savesettings1: TMenuItem Caption = 'Save settings...' OnClick = Savesettings1Click end object Save1: TMenuItem Caption = 'Save as bitmap...' ShortCut = 16467 OnClick = Save1Click end object RotationBMPMenu: TMenuItem Caption = 'Save Rotation Bitmaps' OnClick = RotationBMPMenuClick end object SaveClipMenu: TMenuItem Caption = 'Save clip bitmaps' OnClick = SaveClipMenuClick end object Close1: TMenuItem Caption = 'Close window' ShortCut = 16471 OnClick = Close1Click end end object Edit1: TMenuItem Caption = 'Edit' object Copy1: TMenuItem Caption = 'Copy' OnClick = Copy1Click end end object Volume1: TMenuItem Caption = 'Background' object RenderBGSurfaceMenu: TMenuItem Caption = 'Air/Skin Threshold' object N1: TMenuItem Caption = '0%' GroupIndex = 119 RadioItem = True OnClick = N1Click end object N101: TMenuItem Tag = 25 Caption = '10%' Checked = True GroupIndex = 119 RadioItem = True OnClick = N1Click end object N401: TMenuItem Tag = 51 Caption = '20%' GroupIndex = 119 RadioItem = True OnClick = N1Click end object N601: TMenuItem Tag = 76 Caption = '30%' GroupIndex = 119 RadioItem = True OnClick = N1Click end object N801: TMenuItem Tag = 101 Caption = '40%' GroupIndex = 119 RadioItem = True OnClick = N1Click end object N403: TMenuItem Tag = 128 Caption = '50%' GroupIndex = 119 RadioItem = True OnClick = N1Click end object N404: TMenuItem Tag = 152 Caption = '60%' GroupIndex = 119 RadioItem = True OnClick = N1Click end object N405: TMenuItem Tag = 178 Caption = '70%' GroupIndex = 119 RadioItem = True OnClick = N1Click end end object RenderBGDepthMenu: TMenuItem Caption = 'Search Depth' object N1voxel1: TMenuItem Tag = 1 Caption = '1 voxel' Checked = True GroupIndex = 122 RadioItem = True OnClick = N1voxel1Click end object N2voxels1: TMenuItem Tag = 2 Caption = '2 voxels' GroupIndex = 122 RadioItem = True OnClick = N1voxel1Click end object N4voxels1: TMenuItem Tag = 4 Caption = '4 voxels' GroupIndex = 122 RadioItem = True OnClick = N1voxel1Click end object N8voxels1: TMenuItem Tag = 8 Caption = '8 voxels' GroupIndex = 122 RadioItem = True OnClick = N1voxel1Click end object N16voxels1: TMenuItem Tag = 12 Caption = '12 voxels' GroupIndex = 122 RadioItem = True OnClick = N1voxel1Click end object N16voxels: TMenuItem Tag = 16 Caption = '16 voxels' GroupIndex = 122 RadioItem = True OnClick = N1voxel1Click end object Infinite1: TMenuItem Tag = 2147483647 Caption = 'Infinite' GroupIndex = 122 RadioItem = True OnClick = N1voxel1Click end object MIPItem: TMenuItem Caption = 'MIP' GroupIndex = 122 RadioItem = True OnClick = N1voxel1Click end end end object Overlay1: TMenuItem Caption = 'Overlay' object RenderOverlaySurfaceMenu: TMenuItem Caption = 'Air/Skin Threshold' object N01: TMenuItem Caption = '0%' Checked = True GroupIndex = 120 RadioItem = True OnClick = N01Click end object N102: TMenuItem Tag = 25 Caption = '10%' GroupIndex = 120 RadioItem = True OnClick = N01Click end object N201: TMenuItem Tag = 51 Caption = '20%' GroupIndex = 120 RadioItem = True OnClick = N01Click end object N301: TMenuItem Tag = 76 Caption = '30%' GroupIndex = 120 RadioItem = True OnClick = N01Click end object N402: TMenuItem Tag = 101 Caption = '40%' GroupIndex = 120 RadioItem = True OnClick = N01Click end object N501: TMenuItem Tag = 128 Caption = '50%' GroupIndex = 120 RadioItem = True OnClick = N01Click end object N602: TMenuItem Tag = 152 Caption = '60%' GroupIndex = 120 RadioItem = True OnClick = N01Click end object N701: TMenuItem Tag = 178 Caption = '70%' GroupIndex = 120 RadioItem = True OnClick = N01Click end end object RenderOverlayDepthMenu: TMenuItem Caption = 'Search Depth' object N1voxel2: TMenuItem Tag = 1 Caption = '1 voxel' Checked = True GroupIndex = 122 RadioItem = True OnClick = OverlayRenderDepthItem end object N2voxels2: TMenuItem Tag = 2 Caption = '2 voxels' GroupIndex = 122 RadioItem = True OnClick = OverlayRenderDepthItem end object N4voxels2: TMenuItem Tag = 4 Caption = '4 voxels' GroupIndex = 122 RadioItem = True OnClick = OverlayRenderDepthItem end object N8voxels2: TMenuItem Tag = 8 Caption = '8 voxels' GroupIndex = 122 RadioItem = True OnClick = OverlayRenderDepthItem end object N12voxels1: TMenuItem Tag = 12 Caption = '12 voxels' GroupIndex = 122 RadioItem = True OnClick = OverlayRenderDepthItem end object N16voxels2: TMenuItem Tag = 16 Caption = '16 voxels' GroupIndex = 122 RadioItem = True OnClick = OverlayRenderDepthItem end object Infinite2: TMenuItem Tag = 2147483647 Caption = 'Infinite' GroupIndex = 122 RadioItem = True OnClick = OverlayRenderDepthItem end end object Search1: TMenuItem Caption = 'Search' object BehindBG1: TMenuItem Caption = 'Any Depth' GroupIndex = 17 RadioItem = True OnClick = SetSearch end object Infront1: TMenuItem Tag = 1 Caption = 'Below BG surface [max intensity]' GroupIndex = 17 RadioItem = True OnClick = SetSearch end object Anydepth1: TMenuItem Tag = 2 Caption = 'Infront/below BG surface' GroupIndex = 17 RadioItem = True OnClick = SetSearch end end end object Quality1: TMenuItem Caption = 'View' object CutoutMenu: TMenuItem Caption = 'Cutout' OnClick = Cutout1Click end object MenuItem1: TMenuItem Caption = '-' end object RenderSmoothBG: TMenuItem Caption = 'Smooth Background' Checked = True Hint = 'Blur rendering' OnClick = RenderSmoothBGClick end object RenderSmoothOverlay: TMenuItem Caption = 'Smooth Overlay' Checked = True Hint = 'Blur rendering' OnClick = RenderSmoothBGClick end object RenderPreciseInterpolation: TMenuItem Caption = 'Precise interpolation' Hint = 'Use trilinear interpolation [slow]' OnClick = RenderPreciseInterpolationClick end object N2: TMenuItem Caption = '-' end object FlipLRcheck: TMenuItem Caption = 'Flip L/R' OnClick = RenderSmoothClick end end end object RenderRefreshTimer: TTimer Enabled = False Interval = 150 OnTimer = RenderRefreshTimerTimer left = 48 top = 32 end end ���������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/histoform.lrs������������������������������������������������������0000755�0001750�0001750�00000002550�12147215554�016747� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('THistogramForm','FORMDATA',[ 'TPF0'#14'THistogramForm'#13'HistogramForm'#4'Left'#3#239#3#6'Height'#3'P'#1#3 +'Top'#3#16#1#5'Width'#3#209#1#7'Caption'#6#9'Histogram'#12'ClientHeight'#3'P' +#1#11'ClientWidth'#3#209#1#11'Font.Height'#2#245#9'Font.Name'#6#13'MS Sans S' +'erif'#4'Menu'#7#9'MainMenu1'#8'OnCreate'#7#10'FormCreate'#8'Position'#7#14 +'poScreenCenter'#10'LCLVersion'#6#8'0.9.30.2'#0#10'TScrollBox'#10'HistoPanel' +#4'Left'#2#0#6'Height'#3'P'#1#3'Top'#2#0#5'Width'#3#209#1#5'Align'#7#8'alCli' +'ent'#12'ClientHeight'#3'P'#1#11'ClientWidth'#3#209#1#8'TabOrder'#2#0#0#6'TI' +'mage'#10'HistoImage'#6'Cursor'#7#7'crCross'#4'Left'#2#0#6'Height'#3'P'#1#3 +'Top'#2#0#5'Width'#3#209#1#5'Align'#7#8'alClient'#8'AutoSize'#9#6'Center'#9#0 +#0#0#9'TMainMenu'#9'MainMenu1'#4'left'#2'q'#3'top'#2'3'#0#9'TMenuItem'#5'Fil' +'e1'#7'Caption'#6#4'File'#0#9'TMenuItem'#13'Saveasbitmap1'#7'Caption'#6#17'S' +'ave as bitmap...'#8'ShortCut'#3'S@'#7'OnClick'#7#18'Saveasbitmap1Click'#0#0 +#9'TMenuItem'#12'Closewindow1'#7'Caption'#6#12'Close window'#8'ShortCut'#3'W' +'@'#7'OnClick'#7#17'Closewindow1Click'#0#0#0#9'TMenuItem'#5'Edit1'#7'Caption' +#6#4'Edit'#0#9'TMenuItem'#5'Copy1'#7'Caption'#6#4'Copy'#8'ShortCut'#3'C@'#7 +'OnClick'#7#10'Copy1Click'#0#0#0#0#0 ]); ��������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/nifti_img_view.lrs�������������������������������������������������0000755�0001750�0001750�00000245217�12372022034�017732� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TImgForm','FORMDATA',[ 'TPF0'#8'TImgForm'#7'ImgForm'#4'Left'#3#209#1#6'Height'#3#213#1#3'Top'#2'r'#5 +'Width'#3#1#4#13'ActiveControl'#7#12'ControlPanel'#14'AllowDropFiles'#9#7'Ca' +'ption'#6#7'MRIcroN'#12'ClientHeight'#3#213#1#11'ClientWidth'#3#1#4#8'DockSi' +'te'#9#9'Font.Name'#6#13'MS Sans Serif'#4'Menu'#7#9'MainMenu1'#7'OnClose'#7#9 +'FormClose'#8'OnCreate'#7#10'FormCreate'#9'OnDestroy'#7#11'FormDestroy'#11'O' +'nDropFiles'#7#13'FormDropFiles'#9'OnKeyDown'#7#11'FormKeyDown'#10'OnKeyPres' +'s'#7#12'FormKeyPress'#8'OnResize'#7#10'FormResize'#6'OnShow'#7#8'FormShow'#8 +'Position'#7#14'poScreenCenter'#10'LCLVersion'#6#7'1.2.4.0'#0#6'TPanel'#12'C' +'ontrolPanel'#4'Left'#2#0#6'Height'#2'('#3'Top'#2#0#5'Width'#3#1#4#5'Align'#7 +#5'alTop'#10'BevelOuter'#7#6'bvNone'#12'ClientHeight'#2'('#11'ClientWidth'#3 +#1#4#11'ParentColor'#8#14'ParentShowHint'#8#8'ShowHint'#9#8'TabOrder'#2#0#10 +'OnDblClick'#7#20'ControlPanelDblClick'#0#6'TLabel'#6'LabelX'#4'Left'#2#6#6 +'Height'#2#17#3'Top'#2#12#5'Width'#2#8#7'Caption'#6#1'X'#11'ParentColor'#8#0 +#0#6'TLabel'#6'LabelY'#4'Left'#2'Q'#6'Height'#2#17#3'Top'#2#12#5'Width'#2#8#7 +'Caption'#6#1'Y'#11'ParentColor'#8#0#0#6'TLabel'#6'LabelZ'#4'Left'#3#153#0#6 +'Height'#2#17#3'Top'#2#12#5'Width'#2#7#7'Caption'#6#1'Z'#11'ParentColor'#8#0 +#0#12'TSpeedButton'#10'HideROIBtn'#4'Left'#3'('#3#6'Height'#2#30#4'Hint'#6#30 +'Briefly hide VOIs and Overlays'#3'Top'#2#4#5'Width'#2#30#10'Glyph.Data'#10 +':'#6#0#0'6'#6#0#0'BM6'#6#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#24#0#0#0#1#0 +' '#0#0#0#0#0#0#6#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255 +#255#0#255#255#255#0#198#28#29'%'#192#0#0#127#140'EE'#188#183#11#11#203#191#1 +#1#232#192#0#0#246#192#0#0#219#192#0#0#189#192#0#0#160#192#0#0#130#192#0#0'c' +#192#0#0'$'#255#255#255#0#255#255#255#0#214']_<'#207'AB'#196#200'%%'#255#141 +'LL'#255'G'#160#160#255'B'#168#168#255#152'55'#255#192#0#0#255#192#0#0#255 +#192#0#0#255#192#0#0#255#154'33'#255#192#0#0#255#192#0#0#255#192#0#0#197#222 +#130#132#134#216'fg'#253#209'JK'#255#202'-.'#255#171'00'#255'0'#191#191#255 +'0'#191#191#255#133'OO'#255#192#0#0#255#192#0#0#255#191#1#1#255'~XX'#255'>' +#173#173#255'Q'#148#148#255#175#22#22#255#192#0#0#149#224#138#141#187#218'np' +#255#211'RS'#255#204'56'#255#171'9:'#255#140'FF'#255'z^^'#255#191#1#1#255#192 +#0#0#255#192#0#0#255#192#0#0#255#133'OO'#255'0'#191#191#255'7'#182#182#255 +#166'""'#255#192#0#0'>'#226#147#149'W'#219'wx'#255#213'Z\'#255#206'>?'#255 +#182'66'#255#193#5#5#255#187#7#7#255#192#0#0#255#192#0#0#255#192#0#0#255#178 +#18#18#255#151'77'#255'oll'#255#147'<<'#255#186#8#8#229#192#0#0#1#228#155#158 +#7#221#127#129#236#210'gh'#255#162'op'#255'K'#176#176#255'too'#255#184#10#10 +#255#192#0#0#255#187#6#6#255#163''''''#255'N'#151#151#255'~WW'#255#184#11#11 +#255#189#4#4#255#192#0#0#143#255#255#255#0#255#255#255#0#223#135#137#144#217 +'kl'#255'r'#159#160#255'3'#204#204#255'I'#169#169#255#189#4#4#255#192#0#0#255 +#192#0#0#255'_'#129#129#255'0'#191#191#255'L'#154#154#255#191#1#1#255#192#0#0 +#255#192#0#0'8'#255#255#255#0#255#255#255#0#225#144#146','#219'su'#255#136 +#147#148#255'T'#175#175#255#133'ij'#255#175#24#24#255#192#0#0#255#192#0#0#255 +'rhh'#255'E'#163#163#255'waa'#255#175#22#22#255#192#0#0#224#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#221'{}'#201#214'_a'#255#185'WX'#255 +#200'(('#255#194#10#10#255#192#0#0#255#192#0#0#255#192#0#0#255#166'""'#255 +#191#1#1#255#192#0#0#255#192#0#0#137#255#255#255#0#255#255#255#0#255#255#255 +#0#255#255#255#0#223#132#134'e'#172#135#136#255#209'KM'#255#203'/0'#255#196 +#19#19#255#192#0#0#255#192#0#0#255#168' '#255#192#0#0#255#192#0#0#255#192#0 +#0#255#192#0#0'2'#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#225 +#140#142#13'L'#205#206#251'b'#175#176#255#199'<='#255#198#27#27#255#192#0#0 +#255#148'::'#255'N'#151#151#255'c||'#255#166'""'#255#192#0#0#218#255#255#255 +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'Z' +#200#200#204'M'#196#197#255#196'JK'#255#200'#$'#255#193#7#7#255#142'CC'#255 +'0'#191#191#255'3'#187#187#255#172#26#26#255#192#0#0#131#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'Z'#204#205 +'k'#187'xz'#255#203'MN'#255#202',,'#255#195#15#15#255#144'@@'#255'c{{'#255'r' +'gg'#255#169#30#30#255#192#0#0','#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#0#255#255#3#217'ln'#214#210'PR' +#255#201'78'#255#197#24#24#255#192#0#0#255#189#4#4#255#180#16#16#255#192#0#0 +#212#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#219'uwr'#212'YZ'#255#149'rs'#255 +#148'YY'#255#166'%%'#255#192#0#0#255#192#0#0#255#192#0#0'}'#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#221'}'#127#21#159#137#138#251'7'#205#206#255'2'#201#201 +#255#154'>>'#255#192#0#0#255#192#0#0#255#192#0#0'&'#255#255#255#0#255#255#255 +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 ,#255#255#0#255#255#255#0#176#133#135#182'B'#199#199#255'B'#188#188#255#131'b' +'c'#255#192#0#0#255#192#0#0#206#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#206'z{J'#209'XZ'#255#154'kk'#255#198#29#29#255#192#0#0 +#255#192#0#0'w'#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#220'z|'#2#214']_'#225#207'AB'#255#182'9:'#255#194#9#9#255#192#0#0'!' +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#216'fg'#128#170'kl'#255'Z'#161#162#255#132'^^'#215#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#218'np'#31#159'|}'#253'3'#205#205#255'h'#134#135#154#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#148#141#142#202'h'#158#158#254#138'gg'''#255#255#255#0#255#255#255 +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#215'cdU'#208'FH'#194#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#217'k' +'m'#6#210'OPW'#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#11'OnMouseDown'#7#19'HideROIBtnMouseD' +'own'#9'OnMouseUp'#7#17'HideROIBtnMouseUp'#0#0#12'TSpeedButton'#7'XBarBtn'#4 +'Left'#3'F'#3#6'Height'#2#30#4'Hint'#6#190'Toggle Crosshairs'#13#10'right-cl' +'ick to change gap size'#13#10'right+ctrl click to change color'#13#10'right' +'+alt click to change thickness'#13#10'right+shift to reposition origin'#13 +#10'right+ctrl+alt to adjust font size'#3'Top'#2#4#5'Width'#2#30#10'AllowAll' +'Up'#9#10'Glyph.Data'#10#218#8#0#0#214#8#0#0'BM'#214#8#0#0#0#0#0#0'6'#0#0#0 +'('#0#0#0#23#0#0#0#24#0#0#0#1#0' '#0#0#0#0#0#160#8#0#0'd'#0#0#0'd'#0#0#0#0#0 +#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#192#0#0'9'#192#0#0'4'#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#0#0#255#20#0#0#255'P'#0#0#255#10#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#192#0#0#184#192#0#0#168#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#0#0#255'@'#0#0#255#255#0#0#255' '#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#192#0#0#184#192#0#0#168#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'@'#0#0#255#255#0#0#255' ' +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#192#0#0#184#192#0#0#168#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'@'#0#0#255#255#0 +#0#255' '#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255 +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#192#0#0#184#192#0#0#168#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'@'#0#0#255 +#255#0#0#255' '#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255#25#0#0#255'P'#0 +#0#255'P'#0#0#255'P'#0#0#255'Pv'#0'c'#206'q'#0'h'#195#0#0#255'P'#0#0#255'P'#0 +#0#255'P'#0#0#255'P'#0#0#255'P'#0#0#255'|'#0#0#255#255#0#0#255'f'#0#0#255'P' +#0#0#255'P'#0#0#255'P'#0#0#255'P'#0#0#255'P'#0#0#255'P'#0#0#255'P'#0#0#255#25 +#0#0#255'P'#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0 +#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255 +#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255'P'#0#0#255#5#0#0#255#16#0#0#255 +#16#0#0#255#16#0#0#255#16#176#0#22#188#174#0#24#173#0#0#255#16#0#0#255#16#0#0 +#255#16#0#0#255#16#0#0#255#16#0#0#255'L'#0#0#255#255#0#0#255'.'#0#0#255#16#0 +#0#255#16#0#0#255#16#0#0#255#16#0#0#255#16#0#0#255#16#0#0#255#16#0#0#255#5 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#192#0 +#0#184#192#0#0#168#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#0#0#255'@'#0#0#255#255#0#0#255' '#255#255#255#0#255#255#255#0 ,#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#192#0#0#184#192#0#0#168#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#0#0#255'@'#0#0#255#255#0#0#255' '#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#192#0#0#184#192#0#0#168#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#0#0#255'@'#0#0#255#255#0#0#255' '#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#192#0#0#184#192#0#0#168#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'@'#0#0#255#255#0#0#255' ' +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#192#0#0#184#192#0#0#168#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'@'#0#0#255#255#0 +#0#255' '#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255 +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#192#0#0#184#192#0#0#168#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'@'#0#0#255 +#255#0#0#255' '#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#192#0#0#184#192#0#0#168#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'@' +#0#0#255#255#0#0#255' '#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255 +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#192#0#0'M'#192#0#0 +#248#192#0#0#248#192#0#0#248#192#0#0#248#192#0#0#253#192#0#0#253#192#0#0#248 +#192#0#0#248#192#0#0#248#192#0#0#248#192#0#0#248#143#0'A'#250#0#0#255#255#167 +#0'!'#249#192#0#0#248#192#0#0#248#192#0#0#248#192#0#0#248#192#0#0#248#192#0#0 +#248#192#0#0#248#192#0#0'M'#192#0#0' '#192#0#0'h'#192#0#0'h'#192#0#0'h'#192#0 +#0'h'#192#0#0#213#192#0#0#203#192#0#0'h'#192#0#0'h'#192#0#0'h'#192#0#0'h'#192 +#0#0'hi'#0's'#142#0#0#255#255#142#0'B{'#192#0#0'h'#192#0#0'h'#192#0#0'h'#192 +#0#0'h'#192#0#0'h'#192#0#0'h'#192#0#0'h'#192#0#0' '#255#255#255#0#255#255#255 +#0#255#255#255#0#255#255#255#0#255#255#255#0#192#0#0#184#192#0#0#168#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'@'#0#0 +#255#255#0#0#255' '#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#192#0#0#184#192#0#0#168 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0 +#255'@'#0#0#255#255#0#0#255' '#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#192#0#0#184 +#192#0#0#168#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#0#0#255'@'#0#0#255#255#0#0#255' '#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#192#0 +#0#184#192#0#0#168#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#0#0#255'@'#0#0#255#255#0#0#255' '#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#192#0#0#184#192#0#0#168#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#0#0#255'@'#0#0#255#255#0#0#255' '#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#192#0#0#184#192#0#0#168#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#0#0#255'@'#0#0#255#255#0#0#255' '#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#192#0#0'9'#192#0#0'4'#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255#20#0#0#255'P'#0#0#255#10 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#10'GroupIndex'#3'A'#1#7'OnClick'#7#12 +'XBarBtnClick'#11'OnMouseDown'#7#16'XBarBtnMouseDown'#8'ShowHint'#9#14'Paren' +'tShowHint'#8#0#0#6'TPanel'#10'LayerPanel'#4'Left'#3'0'#1#6'Height'#2'$'#3'T' ,'op'#2#2#5'Width'#3#244#1#12'ClientHeight'#2'$'#11'ClientWidth'#3#244#1#8'Ta' +'bOrder'#2#5#0#12'TSpeedButton'#15'AutoContrastBtn'#4'Left'#2'y'#6'Height'#2 +#28#4'Hint'#6#12'Autocontrast'#3'Top'#2#3#5'Width'#2#28#10'Glyph.Data'#10#218 +#8#0#0#214#8#0#0'BM'#214#8#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#24#0#0#0#23#0#0#0#1 +#0' '#0#0#0#0#0#160#8#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#0#0#0'"'#25#25#25'c...'#165'???'#194'RRR'#215'OOO'#213'<<<'#192'---' +#159#17#17#17'_'#0#0#0#26#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#0#0#0#12'...'#168'www'#232#198#198 +#198#254#244#244#244#255#255#255#255#255#255#255#255#255#255#255#255#255#255 +#255#255#255#240#240#240#255#24#24#24#255'100'#242'*(('#157#0#0#0#5#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0'###SEEE'#218#220#220#220#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#27#22#22#255#26#16#16#255 +''''#26#26#255'2(('#234'#'#30#30';'#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'000'#158#150#150#150 +#240#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 +#250#250#255', '#255'/'#28#28#255':##'#255'>%%'#255'ZEE'#248'@66'#133#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'$$$Y'#144 +#144#144#240#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#254#254#255#255#245#245#255':(('#255'B(('#255'Q11'#255'W44'#255'O//' +#255'Y@@'#248'+'#31#31'='#255#255#255#0#255#255#255#0#255#255#255#0#0#0#0#22 +'JJJ'#223#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#252#252#255#255#243#243#255'B--'#255'N//'#255'd<<'#255 +'pCC'#255'a::'#255'K--'#255'H66'#232#17#10#10#10#255#255#255#0#255#255#255#0 +'000'#194#232#232#232#255#255#255#255#255#255#255#255#255#255#255#255#255#255 +#255#255#255#255#255#255#255#251#250#250#255#253#253#253#255#255#255#255#255 +#255#255#255#255#255#255#255#255#255#252#252#255#255#242#242#255'C--'#255'O/' +'/'#255'f=='#255'uFF'#255'c;;'#255'L..'#255'B..'#255':11'#174#255#255#255#0#0 +#0#0'-'#139#139#139#238#255#255#255#255#255#255#255#255#255#255#255#255#255 +#255#255#255#255#255#255#255#243#240#239#255#130'hh'#255#244#242#242#255#255 +#255#255#255#255#255#255#255#255#255#255#255#255#254#254#255#255#245#245#255 +'<))'#255'E))'#255'U33'#255'\77'#255'S22'#255'B(('#255'-'#27#27#255'<33'#242 +#0#0#0#9'!!!r'#207#207#207#255#255#255#255#255#255#255#255#255#255#255#255 +#255#255#255#255#255#232#223#223#255#131'^]'#255'c>>'#255#244#242#242#255#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#249#249#255 +'/!!'#255'3'#31#31#255'?&&'#255'C(('#255'=%%'#255'0'#29#29#255#31#19#19#255 +' '#28#28#254#3#3#3'<111'#177#251#251#251#255#255#255#255#255#255#255#255#255 +#255#255#255#255#222#204#203#255#141']\'#255'zML'#255'kCB'#255'tWV'#255'hQP' +#255'\HH'#255'O@@'#255'C88'#255'600'#255#21#13#13#255#30#18#18#255''''#23#23 +#255')'#25#25#255'&'#23#23#255#28#17#17#255#14#8#8#255#2#2#2#255'%%%'#138'EE' +'E'#202#255#255#255#255#255#255#255#255#255#254#254#255#215#183#182#255#159 +'ed'#255#144'[Z'#255#129'RP'#255'sHG'#255'd?>'#255'U55'#255'F,+'#255'7#"'#255 +'('#25#25#255#26#16#16#255#11#7#7#255#7#4#4#255#14#8#8#255#16#10#10#255#13#8 +#8#255#5#3#3#255#0#0#0#255#0#0#0#255''''''''#199'TTT'#219#255#255#255#255#255 +#255#255#255#227#192#191#255#182'sq'#255#167'ih'#255#152'`^'#255#137'VU'#255 +'zML'#255'kDC'#255']:9'#255'N10'#255'?('''#255'0'#30#30#255'!'#21#21#255#19 +#12#11#255#4#2#2#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0 +#255'+++'#219'EEE'#202#255#255#255#255#255#255#255#255#254#252#251#255#212 +#166#166#255#175'nm'#255#160'ec'#255#145'[Z'#255#130'RQ'#255'sIH'#255'd?>' +#255'V65'#255'G-,'#255'8##'#255')'#26#25#255#26#16#16#255#12#7#7#255#0#0#0 +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255''''''''#199'111'#177 +#251#251#251#255#255#255#255#255#255#255#255#255#255#254#254#255#218#184#183 +#255#167'jh'#255#153'`_'#255#138'WV'#255'{ML'#255'lDC'#255'];:'#255'O21'#255 +'@(('#255'1'#31#30#255'"'#21#21#255#19#12#12#255#4#3#3#255#0#0#0#255#0#0#0 +#255#0#0#0#255#0#0#0#255#2#2#2#255'%%%'#137'!!!r'#207#207#207#255#255#255#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#226#202#202#255#162'ih' +#255#146'\Z'#255#225#214#213#255#246#244#244#255#245#243#243#255#244#242#242 +#255#244#242#242#255#243#241#241#255'6'''''#255#27#17#17#255#12#8#7#255#0#0#0 ,#255#0#0#0#255#0#0#0#255#0#0#0#255#22#22#22#254#3#3#3'<'#0#0#0'-'#139#139#139 +#238#255#255#255#255#255#254#254#255#255#254#254#255#255#254#254#255#255#255 +#255#255#234#219#219#255#161'mk'#255#233#223#223#255#255#255#255#255#255#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#255'>,,'#255'#'#22#21 +#255#20#12#12#255#5#3#3#255#0#0#0#255#0#0#0#255#0#0#0#255'***'#241#0#0#0#9 +#255#255#255#0':55'#196#234#226#226#255#255#247#247#255#255#247#247#255#255 +#248#248#255#255#248#248#255#255#248#248#255#243#229#229#255#243#237#237#255 +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255 +#255'E11'#255'+'#27#26#255#28#17#17#255#13#8#8#255#0#0#0#255#0#0#0#255#19#19 +#19#255''''''''#169#255#255#255#0#255#255#255#0'('#24#24#26'dVV'#227#255#241 +#241#255#255#241#241#255#255#241#241#255#255#242#242#255#255#242#242#255#255 +#242#242#255#255#243#243#255#255#248#248#255#255#255#255#255#255#255#255#255 +#255#255#255#255#255#255#255#255'L65'#255'2 '#31#255'%'#22#22#255#28#17#17 +#255#19#12#12#255#17#10#10#255'+&&'#229#0#0#0#9#255#255#255#0#255#255#255#0 +#255#255#255#0'O;;f'#166#146#146#243#255#235#235#255#255#235#235#255#255#236 +#236#255#255#236#236#255#255#236#236#255#255#237#237#255#255#237#237#255#255 +#240#240#255#255#251#251#255#255#252#252#255#255#251#251#255'`A@'#255'P21' +#255'L//'#255'A(('#255'3'#31#31#255'B44'#247#24#20#20'9'#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'YEE'#171#177#151#151#244 +#255#229#229#255#255#230#230#255#255#230#230#255#255#230#230#255#255#231#231 +#255#255#231#231#255#255#231#231#255#255#231#231#255#255#231#231#255#255#231 +#231#255#128'SS'#255'lBB'#255'`;;'#255'T43'#255'eMM'#248':22'#131#255#255#255 +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0'cFFh'#132'aa'#229#230#200#200#255#255#224#224#255#255#224#224#255 +#255#224#224#255#255#225#225#255#255#225#225#255#255#225#225#255#255#225#225 +#255#255#225#225#255#143'\\'#255'~MM'#255'vKJ'#255'cEE'#236'3((?'#255#255#255 +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#154']]'#29'qPP'#189#170#132#132#240 +#218#182#182#254#248#211#211#255#255#219#219#255#255#219#219#255#255#219#219 +#255#255#219#219#255#245#210#210#255#160'ii'#255#144'ee'#245'aFF'#170'@''''' +#7#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0'D)),uMM'#131'|VV'#190#140'cc'#215#157'qq'#231#152'nn' +#229#134'__'#212'wSS'#183'[<<r'#11#7#7#27#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#7'OnClick'#7 +#20'AutoContrastBtnClick'#0#0#12'TSpeedButton'#14'LutFromZeroBtn'#4'Left'#3 +#183#1#6'Height'#2#28#4'Hint'#6#21'Color range from zero'#3'Top'#2#4#5'Width' +#2#28#10'AllowAllUp'#9#10'Glyph.Data'#10#178#6#0#0#174#6#0#0'BM'#174#6#0#0#0 +#0#0#0'6'#0#0#0'('#0#0#0#24#0#0#0#23#0#0#0#1#0#24#0#0#0#0#0'x'#6#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#0#0#0#0#0#0#0#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#0#0#0#0#0#0#255 +#0#0#0#0#0#0#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#0#0#0#0#0#0#255#0#0#0#0#0#0#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#0#0#0#0#0#0#255#0#0#0#0#0#0 +#0#0#255#0#0#255#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#255#0#0#0#0#0#0#0#0#255#0#0#255#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#0#0#255#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#255#0#0#0#0#0#0#0#0#0#0#0#255#0#0#255#0#0#255#0#0#255#0#0#0#0#0 +#0#0#0#0#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#0#0#0#0#0#0#0#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#0#0#0#0#0#0#0#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#0#0#0#0#0#0#0#0#0#255#0#0#255#0#0 +#255#0#0#0#255#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#0#0#0#255#0 ,#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#0#0#0#255#0#0#255#0#0#255#0#0#255#0#0#0#255#0#255#0#0#255#0#0#255#0 +#0#255#0#0#255#0#0#255#0#0#0#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#0#0#0#255#0#0#255#0#128#128#128 +#128#128#128#0#0#255#128#128#128#128#128#128#128#128#128#128#128#128#128#128 +#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128 +#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128 +#128#128#128#128#128#128#128#128#128#128#128#128#128#128#0#0#0#0#0#0#10#8#8 +#14#8#8#20#12#12#25#15#15#30#18#18'#'#20#20'('#23#23','#26#26'1'#29#29'6 9#' +'#:%%:'''':)):++:--:00'#0#0#0#0#0#0#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0 +','#26#26'D((Y55oBB'#132'OO'#154'\\'#176'ii'#197'vv'#218#131#131#241#144#144 +#254#155#155#255#164#164#255#172#172#255#181#181#255#190#190#255#198#198#255 +#215#215#255#224#224#255#255#255#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0'.' +#27#27'D((Y55oBB'#132'OO'#154'\\'#176'ii'#197'vv'#218#131#131#241#144#144#254 +#155#155#255#164#164#255#172#172#255#181#181#255#190#190#255#198#198#255#215 +#215#255#224#224#255#255#255#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0'.'#27 +#27'D((Y55oBB'#132'OO'#154'\\'#176'ii'#197'vv'#218#131#131#241#144#144#254 +#155#155#255#164#164#255#172#172#255#181#181#255#190#190#255#198#198#255#215 +#215#255#224#224#255#255#255#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0'.'#27 +#27'D((Y55oBB'#132'OO'#154'\\'#176'ii'#197'vv'#218#131#131#241#144#144#254 +#155#155#255#164#164#255#172#172#255#181#181#255#190#190#255#198#198#255#215 +#215#255#224#224#255#255#255#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0'.'#27 +#27'D((Y55oBB'#132'OO'#154'\\'#176'ii'#197'vv'#218#131#131#241#144#144#254 +#155#155#255#164#164#255#172#172#255#181#181#255#190#190#255#198#198#255#215 +#215#255#224#224#255#255#255#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0'.'#27 +#27'D((Y55oBB'#132'OO'#154'\\'#176'ii'#197'vv'#218#131#131#241#144#144#254 +#155#155#255#164#164#255#172#172#255#181#181#255#190#190#255#198#198#255#215 +#215#255#224#224#255#255#255#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0'.'#27 +#27'D((Y55oBB'#132'OO'#154'\\'#176'ii'#197'vv'#218#131#131#241#144#144#254 +#155#155#255#164#164#255#172#172#255#181#181#255#190#190#255#198#198#255#215 +#215#255#224#224#255#255#255#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#128#128#128#128#128#128#128#128#128 +#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128 +#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128 +#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128 +#128#128#128#128#128#128#128#128#128#10'GroupIndex'#3#194#0#7'OnClick'#7#19 +'LutFromZeroBtnClick'#0#0#12'TSpeedButton'#11'ColorBarBtn'#4'Left'#3#211#1#6 +'Height'#2#28#4'Hint'#6#17'Draw color range '#3'Top'#2#4#5'Width'#2#28#10'Gl' +'yph.Data'#10#154#3#0#0#150#3#0#0'BM'#150#3#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#24 +#0#0#0#12#0#0#0#1#0#24#0#0#0#0#0'`'#3#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#128#128#128#128#128#128#128#128#128 +#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128 +#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128 +#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128 +#128#128#128#128#128#128#128#128#128#0#0#0#0#0#0#10#8#8#14#8#8#20#12#12#25#15 +#15#30#18#18'#'#20#20'('#23#23','#26#26'1'#29#29'6 9##:%%:'''':)):++:--:00' +#0#0#0#0#0#0#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0','#26#26'D((Y55oBB' +#132'OO'#154'\\'#176'ii'#197'vv'#218#131#131#241#144#144#254#155#155#255#164 +#164#255#172#172#255#181#181#255#190#190#255#198#198#255#215#215#255#224#224 +#255#255#255#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0'.'#27#27'D((Y55oBB' +#132'OO'#154'\\'#176'ii'#197'vv'#218#131#131#241#144#144#254#155#155#255#164 +#164#255#172#172#255#181#181#255#190#190#255#198#198#255#215#215#255#224#224 +#255#255#255#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0'.'#27#27'D((Y55oBB' +#132'OO'#154'\\'#176'ii'#197'vv'#218#131#131#241#144#144#254#155#155#255#164 +#164#255#172#172#255#181#181#255#190#190#255#198#198#255#215#215#255#224#224 +#255#255#255#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0'.'#27#27'D((Y55oBB' +#132'OO'#154'\\'#176'ii'#197'vv'#218#131#131#241#144#144#254#155#155#255#164 +#164#255#172#172#255#181#181#255#190#190#255#198#198#255#215#215#255#224#224 +#255#255#255#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0'.'#27#27'D((Y55oBB' +#132'OO'#154'\\'#176'ii'#197'vv'#218#131#131#241#144#144#254#155#155#255#164 +#164#255#172#172#255#181#181#255#190#190#255#198#198#255#215#215#255#224#224 ,#255#255#255#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0'.'#27#27'D((Y55oBB' +#132'OO'#154'\\'#176'ii'#197'vv'#218#131#131#241#144#144#254#155#155#255#164 +#164#255#172#172#255#181#181#255#190#190#255#198#198#255#215#215#255#224#224 +#255#255#255#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0'.'#27#27'D((Y55oBB' +#132'OO'#154'\\'#176'ii'#197'vv'#218#131#131#241#144#144#254#155#155#255#164 +#164#255#172#172#255#181#181#255#190#190#255#198#198#255#215#215#255#224#224 +#255#255#255#0#0#0#128#128#128#128#128#128#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 +#0#0#0#0#0#0#0#0#0#0#0#128#128#128#128#128#128#128#128#128#128#128#128#128 +#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128 +#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128 +#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128#128 +#128#128#128#128#128#11'OnMouseDown'#7#20'ColorBarBtnMouseDown'#0#0#9'TCombo' +'Box'#9'LayerDrop'#4'Left'#2#4#6'Height'#2#20#3'Top'#2#4#5'Width'#2't'#10'It' +'emHeight'#2#0#9'ItemIndex'#2#0#13'Items.Strings'#1#6#16'Background Layer'#0 +#8'OnChange'#7#15'LayerDropChange'#8'OnSelect'#7#15'LayerDropSelect'#14'Pare' +'ntShowHint'#8#8'ShowHint'#9#5'Style'#7#14'csDropDownList'#8'TabOrder'#2#0#4 +'Text'#6#16'Background Layer'#0#0#14'TFloatSpinEdit'#13'MinWindowEdit'#4'Lef' +'t'#3#153#0#6'Height'#2#16#3'Top'#2#4#5'Width'#2'X'#13'DecimalPlaces'#2#4#9 +'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0#127#150#152#22 +'@'#8'MinValue'#5#0#0#0#0#0#127#150#152#22#192#8'OnChange'#7#27'MinContrastW' +'indowEditChange'#8'TabOrder'#2#1#5'Value'#5#0#0#0#0#0#0#0#128#255'?'#0#0#14 +'TFloatSpinEdit'#13'MaxWindowEdit'#4'Left'#3#245#0#6'Height'#2#16#3'Top'#2#4 +#5'Width'#2'X'#13'DecimalPlaces'#2#4#9'Increment'#5#0#0#0#0#0#0#0#128#255'?' +#8'MaxValue'#5#0#0#0#0#0#127#150#152#22'@'#8'MinValue'#5#0#0#0#0#0#127#150 +#152#22#192#8'OnChange'#7#27'MaxContrastWindowEditChange'#8'TabOrder'#2#2#5 +'Value'#5#0#0#0#0#0#0#0#128#255'?'#0#0#9'TComboBox'#7'LUTdrop'#4'Left'#3'T'#1 +#6'Height'#2#20#3'Top'#2#5#5'Width'#2'd'#13'DropDownCount'#2'B'#10'ItemHeigh' +'t'#2#0#8'OnChange'#7#13'LUTdropChange'#8'OnSelect'#7#13'LUTdropSelect'#14'P' +'arentShowHint'#8#8'ShowHint'#9#5'Style'#7#14'csDropDownList'#8'TabOrder'#2#3 +#0#0#0#9'TComboBox'#8'ZoomDrop'#4'Left'#3#225#0#6'Height'#2#20#3'Top'#2#8#5 +'Width'#2'O'#13'DropDownCount'#2#12#10'ItemHeight'#2#0#13'Items.Strings'#1#6 +#6'To Fit'#6#6'To Int'#6#2'x1'#6#2'x2'#6#2'x3'#6#2'x4'#6#2'x5'#6#2'x6'#6#2'x' +'7'#6#2'x8'#6#2'x9'#0#8'OnChange'#7#14'ZoomDropChange'#8'OnSelect'#7#14'Zoom' +'DropSelect'#14'ParentShowHint'#8#8'ShowHint'#9#5'Style'#7#14'csDropDownList' +#8'TabOrder'#2#4#0#0#9'TSpinEdit'#9'XViewEdit'#4'Left'#2#24#6'Height'#2#16#3 +'Top'#2#12#5'Width'#2'4'#8'MinValue'#2#1#8'OnChange'#7#15'XViewEditChange'#8 +'TabOrder'#2#0#5'Value'#2'd'#0#0#9'TSpinEdit'#9'YViewEdit'#4'Left'#2'a'#6'He' +'ight'#2#16#3'Top'#2#12#5'Width'#2'4'#8'MinValue'#2#1#8'OnChange'#7#15'XView' +'EditChange'#8'TabOrder'#2#1#5'Value'#2' '#0#0#9'TSpinEdit'#9'ZViewEdit'#4'L' +'eft'#3#169#0#6'Height'#2#16#3'Top'#2#12#5'Width'#2'4'#8'MinValue'#2#1#8'OnC' +'hange'#7#15'XViewEditChange'#8'TabOrder'#2#2#5'Value'#2#14#0#0#6'TPanel'#9 +'ToolPanel'#4'Left'#3'h'#3#6'Height'#2' '#3'Top'#2#4#5'Width'#3#165#0#10'Bev' +'elOuter'#7#6'bvNone'#12'ClientHeight'#2' '#11'ClientWidth'#3#165#0#8'TabOrd' +'er'#2#3#7'Visible'#8#0#12'TSpeedButton'#6'PenBtn'#4'Left'#2#0#6'Height'#2#30 +#4'Hint'#6#8'Pen Tool'#3'Top'#2#0#5'Width'#2#30#10'AllowAllUp'#9#10'Glyph.Da' +'ta'#10#250#6#0#0#246#6#0#0'BM'#246#6#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#24#0#0#0 +#24#0#0#0#1#0#24#0#0#0#0#0#192#6#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#0 +#0#255#0#0#255#0#0#255#0#201#201#204#186#186#208#177#177#210#176#176#210#180 +#180#209#188#188#207#198#198#205#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#202#202#204#164#164#213'{{'#223'44'#241'33'#242'33'#242'33'#241'55'#241'7' +'7'#240'CC'#237'VV'#233'oo'#226#139#139#219#173#173#211#200#200#204#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#160#160#214'//'#243#23 +#23#248#151#151#216'::'#240'33'#242'33'#242'33'#242'33'#242'33'#242'33'#242 +'33'#242'33'#242'33'#242'33'#241'AA'#238'uu'#224#184#184#208#0#255#0#0#255#0 +#0#255#0#0#255#0#0#255#0#171#171#211'bb'#251'LL'#255#20#20#249#199#199#204 +#194#194#206#175#175#211#161#161#214#154#154#216#148#148#217#140#140#219#130 +#130#222'xx'#224'mm'#227'\\'#231'BB'#238'33'#241'33'#242'=='#238#186#186#207 +#0#255#0#0#255#0#0#255#0#0#255#0#127#127#227#179#179#255'<<'#255#0#0#254#148 +#148#217#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#201#201#204#142#142#218'33'#242'33'#242#165#165#213#0#255#0#0 +#255#0#0#255#0#0#255#0#159#159#219#152#152#255'55'#255#0#0#255'??'#238#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0 ,#203#203#204'``'#229'33'#242'SS'#233#201#201#204#0#255#0#0#255#0#0#255#0#0 +#255#0#202#202#204'vv'#228#26#26#251'..'#242#168#168#212#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#154#154#215'3' +'3'#241'<<'#239#181#181#209#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#204#204 +#204#169#169#169';;C[[]'#185#185#185#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0 +#0#255#0#0#255#0#0#255#0#0#255#0#202#202#204'MM'#234'44'#241#153#153#216#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#204#204#204'@@@'#14#14#14#0#0 +#0#28#28#28#180#180#180#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#184#184#208'44'#241'\\'#231#203#203#204#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#203#203#203'DDDPPP'#0#0#0#0#0#0'bbb'#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#197#197#205'GG'#236'JJ'#235 +#188#188#207#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#203#203#203'FFF' +'___'#0#0#0#0#0#0'???'#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#177#177#210'II'#235'AA'#237#151#151#216#203#203#204#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0'IIIeee'#0#0#0#0#0#0'000'#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#196#196#205'z' +'z'#223'77'#240']]'#231#181#181#209#0#255#0#0#255#0#0#255#0#0#255#0'PPPiii'#0 +#0#0#0#0#0'$$$'#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#203#203#204#178#178#210'[['#231'::'#239#139#139 +#219#202#202#204#0#255#0#0#255#0'iii[[['#0#0#0#0#0#0#29#29#29#0#255#0#0#255#0 +#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#202#202#204#151#151#216'>>'#238'{{'#223#203#203#204#0#255#0 +#145#145#145'PPP'#1#1#1#0#0#0#27#27#27#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0 +#203#203#204'{{'#223';;'#239#194#194#205#0#255#0#187#187#187':::'#10#10#10#0 +#0#0#24#24#24#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0 +#0#255#0#0#255#0#0#255#0#0#255#0#203#203#204#182#182#209'll'#227'SS'#233#169 +#169#212#0#255#0#0#255#0#202#202#202'222'#23#23#23#0#0#0#16#16#16#203#203#203 +#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#203 +#203#204#174#174#211'ii'#228'bb'#229#159#159#214#202#202#204#0#255#0#0#255#0 +#0#255#0#0#255#0'KKK'#21#21#21#0#0#0#11#11#11#198#198#198#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#202#202#204#160#160#214'nn'#226'zz' +#223#181#181#209#203#203#204#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0 +#133#133#133#2#2#2#0#0#0#5#5#5#187#187#187#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#196#196#205#149#149#216#165#165#213#200#200#204#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#191#191#191#8#8#8 +#0#0#0#0#0#0#163#163#163#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#203 +#203#204#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0'JJJ'#0#0#0#0#0#0#132#132#132#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0 +#166#166#166#3#3#3#0#0#0'eee'#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0 +#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0'AAA'#0#0#0'FFF'#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#170#170#170#5#5#5'%%%'#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#10'GroupIndex'#2','#7'OnClick'#7#11'PenBtnClick'#0#0#12'TSpeedBut' +'ton'#12'ClosedPenBtn'#4'Left'#2#30#6'Height'#2#30#4'Hint'#6#13'Autoclose Pe' +'n'#3'Top'#2#0#5'Width'#2#30#10'AllowAllUp'#9#10'Glyph.Data'#10#250#6#0#0#246 +#6#0#0'BM'#246#6#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#24#0#0#0#24#0#0#0#1#0#24#0#0#0 +#0#0#192#6#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#0#0#255#0#0#255#0#0#255 +#0#201#201#204#186#186#208#177#177#210#176#176#210#180#180#209#188#188#207 +#198#198#205#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0 +#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#202#202#204#164#164 +#213'{{'#223'44'#241'33'#242'33'#242'33'#241'55'#241'77'#240'CC'#237'VV'#233 +'oo'#226#139#139#219#173#173#211#200#200#204#0#255#0#0#255#0#0#255#0#0#255#0 +#0#255#0#0#255#0#0#255#0#0#255#0#160#160#214'//'#243#23#23#248#151#151#216':' +':'#240'33'#242'33'#242'33'#242'33'#242'33'#242'33'#242'33'#242'33'#242'33' +#242'33'#241'AA'#238'uu'#224#184#184#208#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#171#171#211'bb'#251'LL'#255#20#20#249#199#199#204#194#194#206#175#175 +#211#161#161#214#154#154#216#148#148#217#140#140#219#130#130#222'xx'#224'mm' +#227'\\'#231'BB'#238'33'#241'33'#242'=='#238#186#186#207#0#255#0#0#255#0#0 ,#255#0#0#255#0#127#127#227#179#179#255'<<'#255#0#0#254#148#148#217#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#201 +#201#204#142#142#218'33'#242'33'#242#165#165#213#0#255#0#0#255#0#0#255#0#0 +#255#0#159#159#219#152#152#255'55'#255#0#0#255'??'#238#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#203#203#204'``' +#229'33'#242'SS'#233#201#201#204#0#255#0#0#255#0#0#255#0#0#255#0#202#202#204 +'vv'#228#26#26#251'..'#242#168#168#212#0#255#0#0#255#0#255#0#0#255#0#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#154#154#215'33'#241'<<'#239#181 +#181#209#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#204#204#204#169#169#169';;C' +'[[]'#185#185#185#0#255#0#255#0#0#255#0#0#255#0#0#255#0#0#0#255#0#0#255#0#0 +#255#0#0#255#0#202#202#204'MM'#234'44'#241#153#153#216#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#204#204#204'@@@'#14#14#14#0#0#0#28#28#28#180#180 +#180#255#0#0#255#0#0#255#0#0#255#0#0#0#255#0#0#255#0#0#255#0#0#255#0#184#184 +#208'44'#241'\\'#231#203#203#204#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#203#203#203'DDDPPP'#0#0#0#0#0#0'bbb'#0#255#0#255#0#0#255#0#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#197#197#205'GG'#236'JJ'#235#188#188#207#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#203#203#203'FFF___'#0#0#0#0#0#0'?' +'??'#0#255#0#0#255#0#0#255#0#0#255#0#255#0#0#255#0#0#0#255#0#0#255#0#0#255#0 +#177#177#210'II'#235'AA'#237#151#151#216#203#203#204#0#255#0#0#255#0#0#255#0 +#0#255#0#0#255#0'IIIeee'#0#0#0#0#0#0'000'#0#255#0#0#255#0#0#255#0#255#0#0#255 +#0#0#255#0#0#255#0#0#0#255#0#0#255#0#0#255#0#196#196#205'zz'#223'77'#240']]' +#231#181#181#209#0#255#0#0#255#0#0#255#0#0#255#0'PPPiii'#0#0#0#0#0#0'$$$'#0 +#255#0#0#255#0#0#255#0#255#0#0#255#0#0#255#0#0#255#0#0#0#255#0#0#255#0#0#255 +#0#0#255#0#203#203#204#178#178#210'[['#231'::'#239#139#139#219#202#202#204#0 +#255#0#0#255#0'iii[[['#0#0#0#0#0#0#29#29#29#0#255#0#0#255#0#0#255#0#0#255#0 +#255#0#0#255#0#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#202 +#202#204#151#151#216'>>'#238'{{'#223#203#203#204#0#255#0#145#145#145'PPP'#1#1 +#1#0#0#0#27#27#27#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#255 +#0#0#255#0#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#203#203#204'{{'#223';;' +#239#194#194#205#0#255#0#187#187#187':::'#10#10#10#0#0#0#24#24#24#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#255#0#0#255#0#0#255#0#0#255#0#0#0#255 +#0#0#255#0#203#203#204#182#182#209'll'#227'SS'#233#169#169#212#0#255#0#0#255 +#0#202#202#202'222'#23#23#23#0#0#0#16#16#16#203#203#203#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#255#0#0#255#0#0#255#0#0#255#0#0#203#203#204#174#174#211'i' +'i'#228'bb'#229#159#159#214#202#202#204#0#255#0#0#255#0#0#255#0#0#255#0'KKK' +#21#21#21#0#0#0#11#11#11#198#198#198#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0 +#0#255#0#255#0#0#255#0#0#160#160#214'nn'#226'zz'#223#181#181#209#203#203#204 +#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#133#133#133#2#2#2#0#0#0#5#5 +#5#187#187#187#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#196#196#205 +#149#149#216#165#165#213#200#200#204#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0 +#0#255#0#0#255#0#0#255#0#0#255#0#191#191#191#8#8#8#0#0#0#0#0#0#163#163#163#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#203#203#204#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0'JJJ'#0#0#0#0#0#0#132#132#132#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#166#166#166#3#3#3#0#0#0'eee'#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0'AAA'#0#0#0'FFF'#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255 +#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#170#170#170#5#5#5'%%%'#0#255#0 +#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0 +#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#0#255#0#10'GroupIndex'#2','#7 +'OnClick'#7#11'PenBtnClick'#0#0#12'TSpeedButton'#7'FillBtn'#4'Left'#2'<'#6'H' +'eight'#2#30#4'Hint'#6#9'Fill tool'#3'Top'#2#0#5'Width'#2#30#10'AllowAllUp'#9 +#10'Glyph.Data'#10#218#8#0#0#214#8#0#0'BM'#214#8#0#0#0#0#0#0'6'#0#0#0'('#0#0 +#0#23#0#0#0#24#0#0#0#1#0' '#0#0#0#0#0#160#8#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0 +#0#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255#8#0#0#255'O'#0#0#255 +'z'#0#0#255#147#0#0#255#171#0#0#255#196#0#0#255#221#0#0#255#245#0#0#255#239#0 +#0#255#211#0#0#255#184#0#0#255#156#0#0#255#129#0#0#255'T'#0#0#255#3#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255#4#0#0 +#255'H'#0#0#255#160#0#0#255#241#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255 +#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#221#0#0#255'$'#255#255#255#0#255 ,#255#255#0#255#255#255#0#255#255#255#0#0#0#255#156#0#0#255#255#0#0#255#255#0 +#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0 +#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#142#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#0#0#255#212#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255 +#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0 +#255#254#0#0#255'@'#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0 +#0#255'A'#0#0#255#248#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255 +#0#0#255#255#0#0#255#255#0#0#255#237#0#0#255#182#0#0#255'6'#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'0' +#0#0#255#214#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#252#0#0#255#227#0#0 +#255#209#0#0#255#191#0#0#255#173#0#0#255#155#0#0#255'}'#0#0#255'N'#0#0#255#30 +'T'#0#0#25'\'#9#9']T'#0#0#7#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255#16#0#0#255#215#0#0 +#255'O'#0#0#255')'#0#0#255#6#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'e'#18#18'jv%%'#228#180 +'mn'#248'r##'#225'h'#24#24#140'T'#0#0#3#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#0#0#255'f'#0#0#255#171#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0'T'#0#0#28'i'#23#23#198#172'_`'#241#251#187#189#255#253 +#195#197#255#253#201#203#255#190#130#131#245'h'#25#25#195'T'#0#0#13#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255#207#0#0#255#130#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0'f'#18#18'ox%%'#229#228#154#155#255#253#187#189#255#253 +#193#195#255#253#199#201#255#252#205#207#255#252#211#213#255#217#171#173#252 +'h'#27#27#203'T'#0#0#3#255#255#255#0#255#255#255#0#0#0#255'%'#0#0#255#255#0#0 +#255'Y'#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +'T'#0#0#30'j'#21#22#201#176'^^'#242#252#178#179#255#253#185#186#255#253#191 +#192#255#253#197#199#255#252#203#205#255#252#209#211#255#252#215#217#255#252 +#221#223#255#189#142#144#245'f'#25#26#143#255#255#255#0#255#255#255#0#0#0#255 +'z'#0#0#255#255#0#0#255'9'#255#255#255#0#255#255#255#0#255#255#255#0'T'#0#0#1 +'f'#17#17'tz%%'#229#231#148#148#255#254#177#178#255#253#183#184#255#253#189 +#190#255#253#195#196#255#253#201#203#255#252#207#209#255#252#212#215#255#252 +#218#221#255#252#224#227#255#251#230#233#255#128'>?'#232'T'#0#0'#'#255#255 +#255#0#0#0#255#167#0#0#255#255#0#0#255'P'#255#255#255#0#255#255#255#0'T'#0#0 +'!j'#20#20#203#180'\\'#243#253#168#169#255#254#175#176#255#253#181#182#255 +#253#187#188#255#253#193#194#255#253#198#200#255#252#204#206#255#252#210#213 +#255#252#216#219#255#252#222#225#255#251#228#231#255#251#234#237#255#215#188 +#191#255'h'#30#30#156#255#255#255#0#0#0#255#153#0#0#255#255#0#0#255#130'T'#0 +#0#1'g'#17#17'x|$$'#230#233#141#141#255#254#167#167#255#254#173#173#255#253 +#179#180#255#253#184#186#255#253#190#192#255#253#196#198#255#252#202#204#255 +#252#208#210#255#252#214#217#255#252#220#223#255#252#226#229#255#251#232#235 +#255#251#238#241#255#251#244#247#255'i '#228#255#255#255#0#0#0#255')'#0#0 +#255#244#0#0#254#241'G'#20'd'#230'r''2'#252#223#130#130#255#254#165#165#255 +#254#170#171#255#254#176#177#255#253#182#184#255#253#188#190#255#253#194#196 +#255#253#200#202#255#252#206#208#255#252#212#214#255#252#218#221#255#252#224 +#227#255#251#230#233#255#251#236#239#255#251#241#245#255#175#134#136#243'f' +#27#27#134#255#255#255#0#255#255#255#0#0#0#255#22#13#0#217#155'5%'#205#249'C' +'?'#243#255'E+'#185#255#129':H'#255#215#135#135#255#253#180#181#255#253#186 +#187#255#253#192#194#255#253#198#200#255#252#204#206#255#252#210#212#255#252 +#216#218#255#252#222#224#255#251#228#231#255#251#233#237#255#251#239#243#255 +#211#187#190#253'g'#28#29#191#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0'T'#0#0#12'm%$'#224#173#167#243#255#0#0#255#255#22#21#253#255'[3' +#142#255#195'|}'#255#253#190#191#255#253#196#197#255#252#202#204#255#252#208 +#210#255#252#214#216#255#252#219#222#255#252#225#228#255#251#231#234#255#251 +#237#241#255#235#219#223#255'j!!'#220'T'#0#0#13#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0'_'#16#16'\'#165'wu'#239'A?'#252 +#255#0#0#255#255#0#0#255#255'P2'#169#255#183'uv'#255#253#200#201#255#252#205 +#208#255#252#211#214#255#252#217#220#255#252#223#226#255#251#229#232#255#251 +#235#238#255#248#236#240#255'w45'#231'T'#0#0')'#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'h'#29 +#29#201#197#183#219#255#6#6#255#255#0#0#255#255#0#0#255#255'P7'#184#255#169 ,'jj'#255#252#209#212#255#252#215#218#255#252#221#224#255#251#227#230#255#251 +#233#236#255#251#239#242#255#150'`b'#237'c'#22#22'\'#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0'T'#0#0'&v10'#231#163#156#241#255#4#4#255#255#0#0#255#255#0#0 +#255#255'P;'#197#255#171'pq'#255#252#219#222#255#252#225#228#255#251#231#234 +#255#251#237#240#255#191#155#157#247'g'#28#29#156#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0']'#13#12'=u10'#229#168#159#236#255#6#6 +#255#255#0#0#255#255#0#0#255#255']3'#136#255#227#190#191#255#251#229#232#255 +#251#235#238#255#222#199#202#255'h'#30#31#203'T'#0#0#3#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'W'#5#5'-q+*'#225#172 +#162#230#255#9#9#255#255#0#0#255#255#19#18#252#255'|AW'#255#251#232#236#255 +#241#224#228#255'n&'''#224'T'#0#0#21#255#255#255#0#255#255#255#0#255#255#255 +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'T'#0#0' o' +'''&'#219#192#178#217#255']['#251#255#4#4#255#255'E2'#202#255#194#156#158#255 +#129'AB'#233'['#10#11'8'#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0'T'#0#0#22'k"!'#186#139'ON'#229#199#182#209#255#220#211#235#255'w2' +'2'#252'g'#27#28'r'#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0'T'#0#0' j '#31#165'l##'#231 +'i'#31#31#190#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#10'GroupIndex'#2','#7'OnCli' +'ck'#7#11'PenBtnClick'#0#0#12'TSpeedButton'#10'EllipseBtn'#4'Left'#2'Z'#6'He' +'ight'#2#30#4'Hint'#6#12'Ellipse Tool'#3'Top'#2#0#5'Width'#2#30#10'AllowAllU' +'p'#9#10'Glyph.Data'#10'z'#8#0#0'v'#8#0#0'BMv'#8#0#0#0#0#0#0'6'#0#0#0'('#0#0 +#0#24#0#0#0#22#0#0#0#1#0' '#0#0#0#0#0'@'#8#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0 +#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255#7#0#0#255'g'#0#0 +#255#179#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255 +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#0#0#255#26#0#0#255','#0#0#255#3#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255#5'11'#255#191'>' +'>'#255#255#0#0#255#203#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255 +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#0#0#255#31#0#0#255#167#0#0#255#229#0#0#255#255#0#0#255#255#0#0#255 +#245#0#0#255#195#0#0#255'R'#255#255#255#0#255#255#255#0#0#0#255'8'#166#166 +#255#255'55'#255#255#0#0#255#249#0#0#255#20#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#0#0#255'd'#0#0#255#242#0#0#255#203#0#0#255'h'#0#0#255'4'#0#0#255'"'#0 +#0#255'U'#0#0#255#154#0#0#255#253#0#0#255#166#0#0#255#16#7#7#255'$'#163#163 +#255#255',,'#255#255#0#0#255#255#0#0#255'l'#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'N' +#0#0#255#254#0#0#255'|'#0#0#255#4#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#0#0#255'='#0#0#255#225#0#0#255#173#255#255#255#0 +',,'#255']'#15#15#255#216#0#0#255#156#0#0#255#18#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255#18#0#0#255 +#231#0#0#255#147#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'6'#0#0#255#252#0 +#0#255'YT'#0#0'''T'#0#0#185'T'#0#0#140'T'#0#0#8#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255#127#0#0#255 +#224#0#0#255#10#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255 +#138#0#0#255#224'Z'#9#9#139'_'#16#16#255'T'#0#0#255'T'#0#0#207'T'#0#0#3#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255 +#183#0#0#255#153#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255#5#0#0#255#8#0#0 +#255'<'#0#0#255#255'Z'#15#26#192#128'AA'#255'T'#0#0#255'T'#0#0#255'M'#0#21'H' +#0#0#255#8#0#0#255#8#0#0#255#8#0#0#255#8#0#0#255#8#0#0#255#235#0#0#255'h'#255 ,#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#0#0#255#176#0#0#255#255#0#0#255#255#0#0 +#255#255'8'#0'U'#255#131'FF'#255'T'#0#0#255'T'#0#0#255'%'#0#144#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#235#0#0#255'h' +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#0#0#255#176#0#0#255#141#0#0#255'.'#0#0 +#255#251'@'#0'<'#190#130'EE'#255'T'#0#0#255'T'#0#0#255'H'#0'$'#145#0#0#255'(' +#0#0#255'('#0#0#255'('#0#0#255'I'#0#0#255#255#0#0#255#183#0#0#255#152#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#0#0#255#176#0#0#255'x'#0#0#255'5'#0#0#255#255'L' +#0#23#132#130'DD'#255'T'#0#0#255'T'#0#0#255'T'#0#0#136#255#255#255#0#255#255 +#255#0#255#255#255#0#0#0#255'('#0#0#255#255#0#0#255#129#0#0#255#221#0#0#255#8 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#0#0#255#176#0#0#255'x'#0#0#255#134#0#0#255#226'T'#0 +#0'D'#130'DD'#255'T'#0#0#255'T'#0#0#255'T'#0#0#145#255#255#255#0#255#255#255 +#0#255#255#255#0#0#0#255'('#0#0#255#255#0#0#255#21#0#0#255#234#0#0#255#141 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#0#0#255#176#0#0#255#146#0#0#255#251#0#0#255'_T'#0#0 +#9#129'CC'#250'U'#1#1#255'T'#0#0#255'T'#0#0#153#255#255#255#0#255#255#255#0 +#255#255#255#0#0#0#255'('#0#0#255#255#255#255#255#0#0#0#255'S'#0#0#255#253#0 +#0#255't'#0#0#255#2#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#0#0#255#193#0#0#255#238#0#0#255#179#255#255#255#0#255#255#255 +#0'm%%'#198'X'#6#6#255'T'#0#0#255'T'#0#0#161#255#255#255#0#255#255#255#0#255 +#255#255#0#0#0#255'('#0#0#255#255#255#255#255#0#255#255#255#0#0#0#255'l'#0#0 +#255#245#0#0#255#196#0#0#255'`'#0#0#255','#0#0#255#26#0#0#255'M'#0#0#255#146 +#0#0#255#254#0#0#255#212#0#0#255#19#255#255#255#0#255#255#255#0'U'#2#2'}Y'#8 +#8#255'T'#0#0#255'T'#0#0#169#255#255#255#0#255#255#255#0#255#255#255#0#0#0 +#255'('#0#0#255#255#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'$'#0#0 +#255#175#0#0#255#236#0#0#255#255#0#0#255#255#0#0#255#249#0#0#255#203#0#0#255 +#204#0#0#255'x'#255#255#255#0#255#255#255#0#255#255#255#0'T'#0#0':U'#1#1#255 +'T'#0#0#255'T'#0#0#199#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'('#0 +#0#255#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#0#0#255'"'#0#0#255'4'#0#0#255#7#255#255#255#0#0#0#255 +#176#0#0#255'x'#255#255#255#0#255#255#255#0#255#255#255#0'T'#0#0#4'T'#0#0#243 +'T'#0#0#255'T'#0#0#254'T'#0#0#26#255#255#255#0#255#255#255#0#0#0#255'('#0#0 +#255#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255 +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0 +#255#176#0#0#255'x'#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +'T'#0#0#160'T'#0#0#255'T'#0#0#255'T'#0#0'l'#255#255#255#0#255#255#255#0#0#0 +#255'('#0#0#255#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#0#0#255#176#0#0#255'x'#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0'T'#0#0'!T'#0#0#250'T'#0#0#255'T'#0#0#190#255#255#255#0#255#255 +#255#0#0#0#255'('#0#0#255#255#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#0#0#255#176#0#0#255'x'#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0'T'#0#0#149'T'#0#0#255'T'#0#0#251'T'#0 +#0#15#255#255#255#0#0#0#255'('#0#0#255#255#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#0#0#255#176#0#0#255#243#0#0#255#232#0#0 +#255#232#0#0#255#232#0#0#255#232#0#0#255#232#9#0#228#234'Q'#0#8#254'T'#0#0 +#255#11#0#221#235#0#0#255#232#0#0#255#235#0#0#255#255#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255'1'#0#0#255'H'#0#0#255'H'#0 +#0#255'H'#0#0#255'H'#0#0#255'H'#0#0#255'H'#0#0#255'H5'#0'^'#132'L'#0#23#208#3 +#0#245'J'#0#0#255'H'#0#0#255'H'#0#0#255'H'#10'GroupIndex'#2','#7'OnClick'#7 +#11'PenBtnClick'#0#0#12'TSpeedButton'#9'Fill3DBtn'#4'Left'#2'x'#6'Height'#2 +#30#4'Hint'#6'(Create VOI based on background intensity'#3'Top'#2#0#5'Width' +#2#30#10'AllowAllUp'#9#10'Glyph.Data'#10#218#8#0#0#214#8#0#0'BM'#214#8#0#0#0 +#0#0#0'6'#0#0#0'('#0#0#0#24#0#0#0#23#0#0#0#1#0' '#0#0#0#0#0#160#8#0#0'd'#0#0 +#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255#28#0#0#255'Q'#0#0 +#255#131#0#0#255#181#0#0#255#231#0#0#255#231#0#0#255#181#0#0#255#131#0#0#255 +'Q'#2#4#255#28#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 ,#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#0#0#255#11#0#0#255#141#0#0#255#252#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#1#2#255#255 +#10#17#255#255#18#28#255#252#23'%'#255#141#26'*'#255#11#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#0#0#255'F'#0#0#255#223#0#0#255#255#0#0#255#255#0 +#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#3#5#255#255#14#23 +#255#255#24''''#255#255'!4'#255#255'''>'#255#255'+D'#255#223'+E'#255'F'#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#0#0#255#135#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#13#21#255 +#255#26')'#255#255'%<'#255#255'/K'#255#255'7W'#255#255';_'#255#255'<`'#255 +#255'9['#255#135#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#0#0#255'J'#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#8#12#255#255#22'#'#255 +#255'$9'#255#255'1N'#255#255'=`'#255#255'Fp'#255#255'Ly'#255#255'Mz'#255#255 +'It'#255#255'Ag'#255'J'#255#255#255#0#255#255#255#0#255#255#255#0#0#0#255#22 +#0#0#255#233#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0 +#255#255#0#0#255#255#0#0#255#255#0#0#255#255#13#22#255#255#29'.'#255#255',F' +#255#255':]'#255#255'Hr'#255#255'T'#133#255#255'\'#147#255#255'^'#149#255#255 +'X'#140#255#255'M{'#255#233'@f'#255#22#255#255#255#0#255#255#255#0#0#0#255 +#180#0#0#255#255#0#0#255#255#0#0#218#255#0#0#185#255#0#0#160#255#0#0#184#255 +#0#0#222#255#0#0#253#255#0#0#255#255#1#2#255#255#17#27#253#255#25''''#191#255 +'%:'#191#255'0L'#191#255'<_'#191#255'Fp'#191#255'V'#136#204#255'd'#159#231 +#255'd'#158#254#255'V'#137#255#255'Gq'#255#180#255#255#255#0#0#0#255'*'#0#0 +#255#255#0#0#224#255#0#0'E'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0 +#255#0#0'9'#255#0#0#222#255#2#3#255#255#17#28#245#255#0#0#0#255#0#0#0#255#0#0 +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#14#23'#'#255'4S'#150#255'It' +#255#255'9Z'#255'*'#0#0#255'`'#0#0#254#255#0#0'='#255#0#0#0#255#0#0#0#255#0#0 +'{'#255#0#0#236#255#0#0#141#255#0#0#0#255#0#0#0#255#0#0'3'#255#0#1#255#255#15 +#25#245#255#0#0#0#255#0#0#0#255#0#0#0#255#17#28'9'#255#31'2V'#255#21'!3'#255 +#0#0#0#255#0#0#0#255#0#0#0#255'%<'#138#255'6V'#255'`'#0#0#255#150#0#0#255#255 +#0#0#253#255#0#0#231#255#0#0#205#255#0#0#250#255#0#0#255#255#0#0#222#255#0#0 +#0#255#0#0#0#255#0#0#1#255#0#0#242#255#12#19#245#255#0#0#0#255#0#0#0#255#0#0 +#0#255'*B'#154#255'Q'#128#255#255'X'#140#255#255'%:h'#255#0#0#0#255#0#0#0#255 +#5#7#19#255'0L'#255#150#0#0#255#203#0#0#255#255#0#0#255#255#0#0#255#255#0#0 +#255#255#0#0#187#255#0#0'k'#255#0#0''''#255#0#0#0#255#0#0#0#255#0#0'j'#255#0 +#0#255#255#6#10#245#255#0#0#0#255#0#0#0#255#0#0#0#255'"7'#154#255'Bj'#255#255 +'Hr'#255#255'1N'#171#255#0#0#0#255#0#0#0#255#0#0#0#255'!5'#217#209#0#0#255 +#242#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#170#255#0#0#3#255#0 +#0#0#255#0#0#0#255#0#0'~'#255#0#0#255#255#0#0#255#255#0#0#245#255#0#0#0#255#0 +#0#0#255#0#0#0#255#27'*'#154#255'3Q'#255#255'7X'#255#255#31'1'#139#255#0#0#0 +#255#0#0#0#255#0#0#0#255#25''''#226#243#0#0#255#200#0#0#255#255#0#0#248#255#0 +#0#217#255#0#0#184#255#0#0#246#255#0#0#236#255#0#0'>'#255#0#0#0#255#0#0#0#255 +#0#0#174#255#0#0#255#255#0#0#245#255#0#0#0#255#0#0#0#255#0#0#0#255#18#28#154 +#255'#8'#255#255'!5'#217#255#8#12'2'#255#0#0#0#255#0#0#0#255#3#5#30#255#15#25 +#255#200#0#0#255#146#0#0#255#255#0#0#133#255#0#0#0#255#0#0#0#255#0#0']'#255#0 +#0#173#255#0#0'/'#255#0#0#0#255#0#0#0#255#0#0#188#255#0#0#255#255#0#0#245#255 +#0#0#0#255#0#0#0#255#0#0#0#255#1#2#24#255#2#3#22#255#0#0#0#255#0#0#0#255#0#0 +#0#255#0#0#2#255#7#11#180#255#2#3#255#146#0#0#255'\'#0#0#255#255#0#0#255#255 +#0#0'{'#255#0#0#15#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#15#255#0#0'}'#255#0 +#0#255#255#0#0#255#255#0#0#245#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0 +#0#0#255#0#0#3#255#1#1#31#255#1#2'N'#255#0#1#206#255#0#0#255#255#0#0#255'\'#0 +#0#255'%'#0#0#255#255#0#7#255#255#0#15#255#255#0#16#250#255#0#14#225#255#0#11 +#213#255#0#5#230#255#0#0#251#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255 +#255#0#0#239#255#0#0#239#255#0#0#239#255#0#0#239#255#0#0#239#255#0#0#251#255 +#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255'%'#255#255#255#0#0 +#28#255#181#0#29#255#255#0#29#255#255#0#28#255#255#0#28#255#255#0#27#255#255 +#0#27#255#255#0#23#255#255#0#10#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0 +#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#0 +#255#255#0#0#255#255#0#0#255#255#0#0#255#164#255#255#255#0#255#255#255#0#0'2' +#255#23#0'&'#255#232#0'#'#255#255#0'#'#255#255#0'"'#255#255#0'!'#255#255#0' ' +#255#255#0' '#255#255#0#31#255#255#0#23#255#255#0#4#255#255#0#0#255#255#0#0 +#255#255#0#0#255#255#0#0#255#255#0#0#255#255#0#1#255#255#0#7#255#255#0#14#255 ,#255#0#18#255#255#0#20#255#230#0'!'#255#22#255#255#255#0#255#255#255#0#255 +#255#255#0#0'4'#255'U'#0'+'#255#253#0'*'#255#255#0')'#255#255#0'('#255#255#0 +''''#255#255#0'&'#255#255#0'%'#255#255#0'%'#255#255#0'#'#255#255#0#16#255#255 +#0#8#255#255#0#11#255#255#0#14#255#255#0#22#255#255#0#30#255#255#0#31#255#255 +#0#30#255#255#0#30#255#253#0' '#255'O'#255#255#255#0#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#0','#255#136#0'1'#255#253#0'0'#255#255#0 +'/'#255#255#0'.'#255#255#0'.'#255#255#0','#255#255#0','#255#255#0'+'#255#255 +#0'*'#255#255#0'*'#255#255#0'('#255#255#0'('#255#255#0''''#255#255#0'&'#255 +#255#0'%'#255#255#0'%'#255#253#0'"'#255#135#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0'A'#255 +'J'#0'='#255#222#0'7'#255#255#0'6'#255#255#0'5'#255#255#0'5'#255#255#0'3'#255 +#255#0'2'#255#255#0'2'#255#255#0'1'#255#255#0'0'#255#255#0'/'#255#255#0'.' +#255#255#0'.'#255#255#0'0'#255#221#0'1'#255'G'#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#0#147#255#17#0'B'#255#147#0'>'#255#249#0'='#255#255 +#0'<'#255#255#0';'#255#255#0';'#255#255#0':'#255#255#0'8'#255#255#0'8'#255 +#255#0'7'#255#255#0'5'#255#249#0':'#255#146#0'{'#255#14#255#255#255#0#255#255 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0'U' +#255#18#0'['#255'['#0'O'#255#142#0'J'#255#185#0'F'#255#223#0'F'#255#223#0'H' +#255#186#0'L'#255#142#0'Q'#255'Y'#0'E'#255#16#255#255#255#0#255#255#255#0#255 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#10'GroupI' +'ndex'#2','#7'OnClick'#7#14'Fill3DBtnClick'#0#0#0#0#6'TPanel'#8'MagPanel'#4 +'Left'#2#0#6'Height'#2#18#3'Top'#3#195#1#5'Width'#3#1#4#5'Align'#7#8'alBotto' +'m'#10'BevelOuter'#7#6'bvNone'#12'ClientHeight'#2#18#11'ClientWidth'#3#1#4#8 +'TabOrder'#2#1#0#6'TLabel'#11'StatusLabel'#4'Left'#2#2#6'Height'#2#17#3'Top' +#2#2#5'Width'#3#133#0#7'Caption'#6#20' No Images Loaded '#11'ParentColor'#8 +#0#0#12'TProgressBar'#12'ProgressBar1'#4'Left'#3'k'#3#6'Height'#2#18#3'Top'#2 +#0#5'Width'#3#150#0#5'Align'#7#7'alRight'#7'Anchors'#11#7'akRight'#8'akBotto' +'m'#0#11'BorderWidth'#2#1#8'TabOrder'#2#0#0#0#0#6'TPanel'#6'Panel1'#4'Left'#2 +#0#6'Height'#3#155#1#3'Top'#2'('#5'Width'#3#1#4#5'Align'#7#8'alClient'#10'Be' +'velOuter'#7#6'bvNone'#12'ClientHeight'#3#155#1#11'ClientWidth'#3#1#4#8'TabO' +'rder'#2#2#0#10'TScrollBox'#11'TriplePanel'#3'Tag'#3#154#2#4'Left'#2#0#6'Hei' +'ght'#3#155#1#3'Top'#2#0#5'Width'#3#1#4#18'HorzScrollBar.Page'#3#7#3#18'Vert' +'ScrollBar.Page'#3#250#0#5'Align'#7#8'alClient'#12'ClientHeight'#3#140#1#11 +'ClientWidth'#3#242#3#20'Constraints.MinWidth'#2#5#5'Color'#7#7'clBlack'#11 +'ParentColor'#8#8'TabOrder'#2#0#7'OnClick'#7#13'ImgPanelClick'#0#6'TImage'#10 +'PGImageCor'#3'Tag'#2#2#6'Cursor'#7#7'crCross'#4'Left'#2#1#6'Height'#2#12#3 +'Top'#2#1#5'Width'#2#12#8'AutoSize'#9#10'OnDblClick'#7#18'PGImageCorDblClick' +#11'OnMouseDown'#7#16'PGImageMouseDown'#11'OnMouseMove'#7#16'PGImageMouseMov' +'e'#9'OnMouseUp'#7#14'PGImageMouseUp'#7'Stretch'#9#0#0#6'TImage'#10'PGImageS' +'ag'#3'Tag'#2#3#6'Cursor'#7#7'crCross'#4'Left'#3'C'#1#6'Height'#2#12#3'Top'#2 +'n'#5'Width'#2#12#8'AutoSize'#9#10'OnDblClick'#7#18'PGImageCorDblClick'#11'O' +'nMouseDown'#7#16'PGImageMouseDown'#11'OnMouseMove'#7#16'PGImageMouseMove'#9 +'OnMouseUp'#7#14'PGImageMouseUp'#7'Stretch'#9#0#0#6'TImage'#9'PGImageAx'#3'T' +'ag'#2#1#6'Cursor'#7#7'crCross'#4'Left'#3#251#2#6'Height'#2#12#3'Top'#3#238#0 +#5'Width'#2#12#8'AutoSize'#9#10'OnDblClick'#7#18'PGImageCorDblClick'#11'OnMo' +'useDown'#7#16'PGImageMouseDown'#11'OnMouseMove'#7#16'PGImageMouseMove'#9'On' +'MouseUp'#7#14'PGImageMouseUp'#7'Stretch'#9#0#0#0#0#9'TMainMenu'#9'MainMenu1' +#4'left'#2'p'#3'top'#3#212#0#0#9'TMenuItem'#5'File1'#7'Caption'#6#5'&File'#0 +#9'TMenuItem'#5'Open1'#7'Caption'#6#5'&Open'#8'ShortCut'#3'O@'#7'OnClick'#7 +#10'Open1Click'#0#0#9'TMenuItem'#7'Recent1'#7'Caption'#6#12'Open &recent'#0#0 +#9'TMenuItem'#10'Templates1'#7'Caption'#6#15'Open &templates'#0#0#9'TMenuIte' +'m'#11'CloseImages'#7'Caption'#6#13'&Close images'#7'OnClick'#7#16'CloseImag' +'esClick'#0#0#9'TMenuItem'#12'SaveasNIfTI1'#7'Caption'#6#16'Save as NIfTI...' +#8'ShortCut'#4'S'#192#0#0#7'OnClick'#7#17'SaveasNIfTI1Click'#0#0#9'TMenuItem' +#14'Saveaspicture1'#7'Caption'#6#15'&Save as bitmap'#8'ShortCut'#3'S@'#7'OnC' +'lick'#7#19'Saveaspicture1Click'#0#0#9'TMenuItem'#5'Exit1'#7'Caption'#6#5'E&' +'xit'#7'OnClick'#7#10'Exit1Click'#0#0#0#9'TMenuItem'#5'Edit1'#7'Caption'#6#5 +'&Edit'#0#9'TMenuItem'#5'Copy1'#7'Caption'#6#4'Copy'#8'ShortCut'#3'C@'#7'OnC' +'lick'#7#10'Copy1Click'#0#0#9'TMenuItem'#6'Paste1'#7'Caption'#6#5'Paste'#8'S' +'hortCut'#3'V@'#7'OnClick'#7#11'Paste1Click'#0#0#9'TMenuItem'#5'Undo1'#7'Cap' +'tion'#6#4'Undo'#8'ShortCut'#3'Z@'#7'OnClick'#7#10'Undo1Click'#0#0#0#9'TMenu' +'Item'#11'OverlayMenu'#7'Caption'#6#8'&Overlay'#0#9'TMenuItem'#11'OverlayOpe' ,'n'#7'Caption'#6#3'Add'#8'ShortCut'#3'A@'#7'OnClick'#7#16'OverlayOpenClick'#0 +#0#9'TMenuItem'#15'CloseOverlayImg'#7'Caption'#6#14'Close overlays'#7'OnClic' +'k'#7#20'CloseOverlayImgClick'#0#0#9'TMenuItem'#14'BGTransPctMenu'#7'Caption' +#6#26'Transparency on background'#0#9'TMenuItem'#8'BGtrans0'#7'Caption'#6#9 +'0% opaque'#7'Checked'#9#10'GroupIndex'#3#251#0#9'RadioItem'#9#7'OnClick'#7 +#15'BGtrans100Click'#0#0#9'TMenuItem'#9'BGtrans20'#3'Tag'#2#20#7'Caption'#6#3 +'20%'#10'GroupIndex'#3#251#0#9'RadioItem'#9#7'OnClick'#7#15'BGtrans100Click' +#0#0#9'TMenuItem'#9'BGtrans40'#3'Tag'#2'('#7'Caption'#6#3'40%'#10'GroupIndex' +#3#251#0#9'RadioItem'#9#7'OnClick'#7#15'BGtrans100Click'#0#0#9'TMenuItem'#9 +'BGtrans50'#3'Tag'#2'2'#7'Caption'#6#3'50%'#10'GroupIndex'#3#251#0#9'RadioIt' +'em'#9#7'OnClick'#7#15'BGtrans100Click'#0#0#9'TMenuItem'#9'BGtrans60'#3'Tag' +#2'<'#7'Caption'#6#3'60%'#10'GroupIndex'#3#251#0#9'RadioItem'#9#7'OnClick'#7 +#15'BGtrans100Click'#0#0#9'TMenuItem'#9'BGtrans80'#3'Tag'#2'P'#7'Caption'#6#3 +'80%'#10'GroupIndex'#3#251#0#9'RadioItem'#9#7'OnClick'#7#15'BGtrans100Click' +#0#0#9'TMenuItem'#10'BGtrans100'#3'Tag'#2'd'#7'Caption'#6#16'100% transparen' +'t'#10'GroupIndex'#3#251#0#9'RadioItem'#9#7'OnClick'#7#15'BGtrans100Click'#0 +#0#9'TMenuItem'#10'BGAdditive'#3'Tag'#2#255#7'Caption'#6#8'Additive'#10'Grou' +'pIndex'#3#251#0#9'RadioItem'#9#7'OnClick'#7#15'BGtrans100Click'#0#0#0#9'TMe' +'nuItem'#19'OverlayTransPctMenu'#7'Caption'#6#30'Transparency on other overl' +'ays'#0#9'TMenuItem'#9'N0opaque1'#7'Caption'#6#9'0% opaque'#10'GroupIndex'#3 +#253#0#9'RadioItem'#9#7'OnClick'#7#17'OverlayTransClick'#0#0#9'TMenuItem'#4 +'N201'#3'Tag'#2#20#7'Caption'#6#3'20%'#10'GroupIndex'#3#253#0#9'RadioItem'#9 +#7'OnClick'#7#17'OverlayTransClick'#0#0#9'TMenuItem'#4'N401'#3'Tag'#2'('#7'C' +'aption'#6#3'40%'#10'GroupIndex'#3#253#0#9'RadioItem'#9#7'OnClick'#7#17'Over' +'layTransClick'#0#0#9'TMenuItem'#4'N501'#3'Tag'#2'2'#7'Caption'#6#3'50%'#10 +'GroupIndex'#3#253#0#9'RadioItem'#9#7'OnClick'#7#17'OverlayTransClick'#0#0#9 +'TMenuItem'#4'N601'#3'Tag'#2'<'#7'Caption'#6#3'60%'#10'GroupIndex'#3#253#0#9 +'RadioItem'#9#7'OnClick'#7#17'OverlayTransClick'#0#0#9'TMenuItem'#4'N801'#3 +'Tag'#2'P'#7'Caption'#6#3'80%'#10'GroupIndex'#3#253#0#9'RadioItem'#9#7'OnCli' +'ck'#7#17'OverlayTransClick'#0#0#9'TMenuItem'#16'N100transparent1'#3'Tag'#2 +'d'#7'Caption'#6#16'100% transparent'#10'GroupIndex'#3#253#0#9'RadioItem'#9#7 +'OnClick'#7#17'OverlayTransClick'#0#0#9'TMenuItem'#15'OverlayAdditive'#3'Tag' +#2#255#7'Caption'#6#8'Additive'#7'Checked'#9#10'GroupIndex'#3#253#0#9'RadioI' +'tem'#9#7'OnClick'#7#17'OverlayTransClick'#0#0#0#9'TMenuItem'#9'LayerMenu'#7 +'Caption'#6#11'Layer color'#7'Visible'#8#0#9'TMenuItem'#9'Noneopen1'#7'Capti' +'on'#6#9'None open'#0#0#0#9'TMenuItem'#11'Layerrange1'#7'Caption'#6#15'Layer' +' intensity'#7'Visible'#8#0#9'TMenuItem'#9'Noneopen2'#7'Caption'#6#9'None op' +'en'#0#0#0#0#9'TMenuItem'#8'DrawMenu'#7'Caption'#6#5'&Draw'#0#9'TMenuItem'#16 +'HideDrawMenuItem'#7'Caption'#6#18'Hide drawing tools'#7'OnClick'#7#14'Toggl' +'eDrawMenu'#0#0#9'TMenuItem'#7'OpenVOI'#7'Caption'#6#11'Open VOI...'#7'OnCli' +'ck'#7#12'OpenVOIClick'#0#0#9'TMenuItem'#7'SaveVOI'#7'Caption'#6#11'Save VOI' +'...'#7'OnClick'#7#12'SaveVOIClick'#0#0#9'TMenuItem'#8'CloseVOI'#7'Caption'#6 +#12'Close VOI...'#7'OnClick'#7#13'CloseVOIClick'#0#0#9'TMenuItem'#8'VOIColor' +#7'Caption'#6#12'VOI color...'#7'OnClick'#7#13'VOIColorClick'#0#0#9'TMenuIte' +'m'#29'Applyintensityfiltertovolume1'#7'Caption'#6#19'Intensity filter...'#8 +'ShortCut'#3'F@'#7'OnClick'#7'"Applyintensityfiltertovolume1Click'#0#0#9'TMe' +'nuItem'#10'SmoothVOI1'#7'Caption'#6#13'Smooth VOI...'#7'OnClick'#7#15'Smoot' +'hVOI1Click'#0#0#9'TMenuItem'#17'MaskimagewithVOI1'#7'Caption'#6#19'Mask ima' +'ge with VOI'#0#9'TMenuItem'#13'VOImaskDelete'#7'Caption'#6#23'Delete region' +'s with VOI'#7'OnClick'#7#12'VOImaskClick'#0#0#9'TMenuItem'#15'VOImaskPreser' +'ve'#3'Tag'#2#1#7'Caption'#6#25'Preserve regions with VOI'#7'OnClick'#7#12'V' +'OImaskClick'#0#0#0#9'TMenuItem'#19'Overlaycomparisons1'#7'Caption'#6#19'Ove' +'rlay comparisons'#0#9'TMenuItem#IntersectionmutualtoVOIandoverlays1'#7'Capt' +'ion'#6#31'Intersection [VOI and overlays]'#7'OnClick'#7#18'ROIcomparisonCli' +'ck'#0#0#9'TMenuItem'#19'UnionVOIoroverlays1'#3'Tag'#2#1#7'Caption'#6#23'Uni' +'on [VOI or overlays]'#7'OnClick'#7#18'ROIcomparisonClick'#0#0#9'TMenuItem' +#22'MaskVOIbutnotoverlays1'#3'Tag'#2#2#7'Caption'#6#27'Mask [VOI but not ove' +'rlays]'#7'OnClick'#7#18'ROIcomparisonClick'#0#0#0#9'TMenuItem'#11'Statistic' +'s1'#7'Caption'#6#10'Statistics'#0#9'TMenuItem'#5'Beta1'#7'Caption'#6#21'Cre' +'ate overlap images'#7'OnClick'#7#13'CreateOverlap'#0#0#9'TMenuItem'#10'Chis' +'quare1'#7'Caption'#6#17'Subtraction Plots'#7'OnClick'#7#15'Chisquare1Click' +#0#0#9'TMenuItem'#13'BatchROImean1'#7'Caption'#6#18'Batch descriptives'#7'On' +'Click'#7#18'BatchROImean1Click'#0#0#9'TMenuItem'#14'Batchprobmaps1'#7'Capti' +'on'#6#15'Batch prob maps'#7'OnClick'#7#19'Batchprobmaps1Click'#0#0#9'TMenuI' ,'tem/Batchclusterprobmaps1Batchclusterprobmaps1Click'#7'Caption'#6#23'Batch ' +'cluster prob maps'#7'OnClick'#7'4Batchclusterprobmaps1Batchclusterprobmaps1' +'ClickClick'#0#0#0#9'TMenuItem'#8'Convert1'#7'Caption'#6#7'Convert'#0#9'TMen' +'uItem'#7'ROIVOI1'#7'Caption'#6#10'ROI -> VOI'#7'OnClick'#7#12'ROIVOI1Click' +#0#0#9'TMenuItem'#7'VOI2NII'#7'Caption'#6#10'VOI -> NII'#7'OnClick'#7#12'VOI' +'2NIIClick'#0#0#9'TMenuItem'#6'NIIVOI'#7'Caption'#6#10'NII -> VOI'#7'OnClick' +#7#11'NIIVOIClick'#0#0#0#9'TMenuItem'#6'Nudge1'#7'Caption'#6#5'Nudge'#0#9'TM' +'enuItem'#3'Up1'#7'Caption'#6#4'Left'#7'OnClick'#7#8'Up1Click'#0#0#9'TMenuIt' +'em'#5'Left1'#3'Tag'#2#1#7'Caption'#6#5'Right'#7'OnClick'#7#8'Up1Click'#0#0#9 +'TMenuItem'#6'LeftX1'#3'Tag'#2#2#7'Caption'#6#9'Posterior'#7'OnClick'#7#8'Up' +'1Click'#0#0#9'TMenuItem'#7'RightX1'#3'Tag'#2#3#7'Caption'#6#8'Anterior'#7'O' +'nClick'#7#8'Up1Click'#0#0#9'TMenuItem'#10'Posterior1'#3'Tag'#2#4#7'Caption' +#6#8'Inferior'#7'OnClick'#7#8'Up1Click'#0#0#9'TMenuItem'#10'Posterior2'#3'Ta' +'g'#2#5#7'Caption'#6#8'Superior'#7'OnClick'#7#8'Up1Click'#0#0#0#9'TMenuItem' +#2'n5'#7'Caption'#6#8'Advanced'#0#9'TMenuItem'#11'RescaleMenu'#7'Caption'#6 +#14'Phase to rad/S'#7'OnClick'#7#16'RescaleMenuClick'#0#0#9'TMenuItem'#16'Br' +'ainExtraction1'#7'Caption'#6#16'Brain extraction'#7'OnClick'#7#12'BETmenuCl' +'ick'#0#0#9'TMenuItem'#10'CropEdges1'#7'Caption'#6#10'Crop edges'#7'OnClick' +#7#13'CropMenuClick'#0#0#9'TMenuItem'#10'Brainmask1'#7'Caption'#6#11'Brain m' +'ask '#7'OnClick'#7#15'BrainMask1Click'#0#0#9'TMenuItem'#25'GenerateSPM5mask' +'slesions1'#7'Caption'#6#16'Create SPM5 mask'#7'OnClick'#7#30'GenerateSPM5ma' +'skslesions1Click'#0#0#9'TMenuItem'#7'LRFlip1'#7'Caption'#6#7'LR Flip'#7'OnC' +'lick'#7#15'MirrorNII1Click'#0#0#9'TMenuItem'#22'ApplyClusterThreshold1'#7'C' +'aption'#6#23'Apply cluster threshold'#7'OnClick'#7#27'ApplyClusterThreshold' +'1Click'#0#0#9'TMenuItem'#24'ExportasRGBAnalyzeimage1'#7'Caption'#6#19'Expor' +'t as RGB image'#7'OnClick'#7#29'ExportasRGBAnalyzeimage1Click'#0#0#9'TMenuI' +'tem'#13'Resliceimage1'#7'Caption'#6#14'Reslice images'#7'OnClick'#7#18'Resl' +'iceimage1Click'#0#0#9'TMenuItem!AdjustimagessoVOIintensityiszero1'#7'Captio' +'n'#6'&Adjust images so VOI intensity is zero'#7'OnClick'#7'&AdjustimagessoV' +'OIintensityiszero1Click'#0#0#9'TMenuItem'#8'Extract1'#7'Caption'#6#15'Extra' +'ct objects'#7'OnClick'#7#13'Extract1Click'#0#0#0#9'TMenuItem'#19'Descriptiv' +'eMenuItem'#7'Caption'#6#11'Descriptive'#7'OnClick'#7#24'DescriptiveMenuItem' +'Click'#0#0#9'TMenuItem'#2'N1'#7'Caption'#6#1'-'#0#0#9'TMenuItem'#4'Pen1'#3 +'Tag'#2#2#7'Caption'#6#3'Pen'#8'ShortCut'#2'p'#7'OnClick'#7#15'ToolSelectCli' +'ck'#0#0#9'TMenuItem'#13'Penautoclose1'#3'Tag'#2#3#7'Caption'#6#13'Autoclose' +' pen'#8'ShortCut'#2'q'#7'OnClick'#7#15'ToolSelectClick'#0#0#9'TMenuItem'#13 +'CircleSquare1'#3'Tag'#2#4#7'Caption'#6#4'Fill'#8'ShortCut'#2'r'#7'OnClick'#7 +#15'ToolSelectClick'#0#0#9'TMenuItem'#7'Circle2'#3'Tag'#2#5#7'Caption'#6#6'C' +'ircle'#8'ShortCut'#2's'#7'OnClick'#7#15'ToolSelectClick'#0#0#9'TMenuItem'#7 +'Circle1'#3'Tag'#2#6#7'Caption'#6#14'Deselect tools'#8'ShortCut'#2't'#7'OnCl' +'ick'#7#15'ToolSelectClick'#0#0#0#9'TMenuItem'#14'DrawHiddenMenu'#7'Caption' +#6#4'Draw'#7'Visible'#8#0#9'TMenuItem'#9'MenuItem2'#7'Caption'#6#18'Show dra' +'wing tools'#7'OnClick'#7#14'ToggleDrawMenu'#0#0#0#9'TMenuItem'#9'Controls1' +#7'Caption'#6#5'&View'#0#9'TMenuItem'#8'Display2'#3'Tag'#2#2#7'Caption'#6#7 +'Display'#0#9'TMenuItem'#6'Axial1'#3'Tag'#2#1#9'AutoCheck'#9#7'Caption'#6#5 +'Axial'#10'GroupIndex'#3#234#0#9'RadioItem'#9#7'OnClick'#7#14'Sagittal1Click' +#0#0#9'TMenuItem'#8'Coronal1'#3'Tag'#2#3#9'AutoCheck'#9#7'Caption'#6#7'Coron' +'al'#10'GroupIndex'#3#234#0#9'RadioItem'#9#7'OnClick'#7#14'Sagittal1Click'#0 +#0#9'TMenuItem'#9'Sagittal1'#3'Tag'#2#2#9'AutoCheck'#9#7'Caption'#6#8'Sagitt' +'al'#10'GroupIndex'#3#234#0#9'RadioItem'#9#7'OnClick'#7#14'Sagittal1Click'#0 +#0#9'TMenuItem'#9'Multiple1'#9'AutoCheck'#9#7'Caption'#6#8'Multiple'#7'Check' +'ed'#9#10'GroupIndex'#3#234#0#9'RadioItem'#9#7'OnClick'#7#14'Sagittal1Click' +#0#0#9'TMenuItem'#6'Axial2'#3'Tag'#2#255#9'AutoCheck'#9#7'Caption'#6#10'Axia' +'l only'#10'GroupIndex'#3#234#0#9'RadioItem'#9#7'OnClick'#7#14'Sagittal1Clic' +'k'#0#0#9'TMenuItem'#8'Coronal2'#3'Tag'#2#253#9'AutoCheck'#9#7'Caption'#6#12 +'Coronal only'#10'GroupIndex'#3#234#0#9'RadioItem'#9#7'OnClick'#7#14'Sagitta' +'l1Click'#0#0#9'TMenuItem'#9'Sagittal2'#3'Tag'#2#254#9'AutoCheck'#9#7'Captio' +'n'#6#13'Sagittal only'#10'GroupIndex'#3#234#0#9'RadioItem'#9#7'OnClick'#7#14 +'Sagittal1Click'#0#0#0#9'TMenuItem'#2'N3'#7'Caption'#6#1'-'#0#0#9'TMenuItem' +#12'Quicksmooth1'#7'Caption'#6#20'3D Smooth background'#7'OnClick'#7#17'Quic' +'ksmooth1Click'#0#0#9'TMenuItem'#17'OverlaySmoothMenu'#7'Caption'#6#18'3D Sm' +'ooth overlays'#7'OnClick'#7#22'OverlaySmoothMenuClick'#0#0#9'TMenuItem'#12 +'Menu2DSmooth'#7'Caption'#6#13'2D Smooth all'#7'Checked'#9#7'OnClick'#7#17'M' +'enu2DSmoothClick'#0#0#9'TMenuItem'#2'N4'#7'Caption'#6#1'-'#0#0#9'TMenuItem' ,#10'FlipLRmenu'#7'Caption'#6#8'Flip L/R'#7'OnClick'#7#15'FlipLRmenuClick'#0#0 +#9'TMenuItem'#8'YokeMenu'#7'Caption'#6#4'Yoke'#8'ShortCut'#3'Y@'#7'OnClick'#7 +#13'YokeMenuClick'#0#0#9'TMenuItem'#2'N2'#7'Caption'#6#1'-'#0#0#9'TMenuItem' +#15'MagnifyMenuItem'#7'Caption'#6#7'Magnify'#7'OnClick'#7#20'MagnifyMenuItem' +'Click'#0#0#9'TMenuItem'#10'Crosshair1'#7'Caption'#6#9'Crosshair'#7'OnClick' +#7#15'ToolSelectClick'#0#0#9'TMenuItem'#9'MenuItem1'#7'Caption'#6#1'-'#0#0#9 +'TMenuItem'#7'MNIMenu'#7'Caption'#6#15'MNI coordinates'#7'OnClick'#7#12'MNIM' +'enuClick'#0#0#9'TMenuItem'#10'Landmarks1'#7'Caption'#6#9'Landmarks'#7'OnCli' +'ck'#7#15'Landmarks1Click'#0#0#0#9'TMenuItem'#8'Display1'#7'Caption'#6#6'Win' +'dow'#0#9'TMenuItem'#10'ShowRender'#7'Caption'#6#6'Render'#8'ShortCut'#3'R@' +#7'OnClick'#7#15'ShowRenderClick'#0#0#9'TMenuItem'#14'ShowMultislice'#7'Capt' +'ion'#6#10'Multislice'#8'ShortCut'#3'M@'#7'OnClick'#7#19'ShowMultisliceClick' +#0#0#9'TMenuItem'#9'HistoMenu'#7'Caption'#6#9'Histogram'#8'ShortCut'#3'H@'#7 +'OnClick'#7#14'HistoMenuClick'#0#0#9'TMenuItem'#10'N4DTraces1'#7'Caption'#6#9 +'4D Traces'#8'ShortCut'#3'D@'#7'OnClick'#7#15'N4DTraces1Click'#0#0#9'TMenuIt' +'em'#7'Header1'#7'Caption'#6#11'Information'#8'ShortCut'#3'I@'#7'OnClick'#7 +#12'Header1Click'#0#0#0#9'TMenuItem'#5'Help1'#7'Caption'#6#5'&Help'#0#9'TMen' +'uItem'#12'Preferences1'#7'Caption'#6#14'Preferences...'#7'OnClick'#7#17'Pre' +'ferences1Click'#0#0#9'TMenuItem'#6'About1'#7'Caption'#6#5'About'#7'OnClick' +#7#11'About1Click'#0#0#0#0#11'TSaveDialog'#11'SaveDialog1'#7'OnClose'#7#16'S' +'aveDialog1Close'#10'DefaultExt'#6#4'.bmp'#6'Filter'#6#11'Bitmap|.bmp'#11'Fi' +'lterIndex'#2#0#4'left'#2#18#3'top'#3#212#0#0#0#12'TColorDialog'#12'ColorDia' +'log1'#5'Color'#7#7'clBlack'#20'CustomColors.Strings'#1#6#13'ColorA=000000'#6 +#13'ColorB=000080'#6#13'ColorC=008000'#6#13'ColorD=008080'#6#13'ColorE=80000' +'0'#6#13'ColorF=800080'#6#13'ColorG=808000'#6#13'ColorH=808080'#6#13'ColorI=' +'C0C0C0'#6#13'ColorJ=0000FF'#6#13'ColorK=00FF00'#6#13'ColorL=00FFFF'#6#13'Co' +'lorM=FF0000'#6#13'ColorN=FF00FF'#6#13'ColorO=FFFF00'#6#13'ColorP=FFFFFF'#6 +#13'ColorQ=C0DCC0'#6#13'ColorR=F0CAA6'#6#13'ColorS=F0FBFF'#6#13'ColorT=A4A0A' +'0'#0#4'left'#2'2'#3'top'#3#212#0#0#0#6'TTimer'#18'RefreshImagesTimer'#7'Ena' +'bled'#8#8'Interval'#2#20#7'OnTimer'#7#23'RefreshImagesTimerTimer'#4'left'#2 +'R'#3'top'#3#212#0#0#0#6'TTimer'#18'RescaleImagesTimer'#7'Enabled'#8#8'Inter' +'val'#2'2'#7'OnTimer'#7#23'RescaleImagesTimerTimer'#4'left'#3#178#0#3'top'#3 +#212#0#0#0#6'TTimer'#9'YokeTimer'#7'Enabled'#8#8'Interval'#3#200#0#7'OnTimer' +#7#14'YokeTimerTimer'#4'left'#3#24#1#3'top'#3#8#1#0#0#0 ]); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/perisettings.lfm���������������������������������������������������0000755�0001750�0001750�00000005433�11450447636�017442� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object PSForm: TPSForm Left = 1058 Height = 398 Top = 420 Width = 370 HorzScrollBar.Page = 369 VertScrollBar.Page = 418 ActiveControl = BinWidthEdit Caption = 'Peristimulus Plot' ClientHeight = 398 ClientWidth = 370 Constraints.MaxHeight = 398 Constraints.MaxWidth = 370 Constraints.MinHeight = 398 Constraints.MinWidth = 370 OnShow = FormShow Position = poScreenCenter LCLVersion = '0.9.29' object Label1: TLabel Left = 40 Height = 14 Top = 25 Width = 71 Caption = 'Bin width (sec)' ParentColor = False end object Label2: TLabel Left = 40 Height = 14 Top = 62 Width = 134 Caption = 'Number of pre-stimulus bins' ParentColor = False end object Label3: TLabel Left = 40 Height = 14 Top = 101 Width = 139 Caption = 'Number of post-stimulus bins' ParentColor = False end object BinWidthEdit: TFloatSpinEdit Left = 232 Height = 21 Top = 16 Width = 130 DecimalPlaces = 4 Increment = 1 MaxValue = 100 MinValue = 0 TabOrder = 0 Value = 0 end object PreBinEdit: TSpinEdit Left = 232 Height = 21 Top = 53 Width = 130 MinValue = 1 TabOrder = 1 Value = 4 end object PostBinEdit: TSpinEdit Left = 232 Height = 21 Top = 92 Width = 130 MinValue = 1 TabOrder = 2 Value = 14 end object SliceTImeCheck: TCheckBox Left = 40 Height = 17 Top = 132 Width = 139 Caption = 'Data slice-time corrected' TabOrder = 3 end object SavePSVolCheck: TCheckBox Left = 40 Height = 17 Top = 164 Width = 145 Caption = 'Save peristimulus volumes' TabOrder = 4 end object OKBtn: TButton Left = 280 Height = 25 Top = 360 Width = 75 BorderSpacing.InnerBorder = 4 Caption = 'OK' ModalResult = 1 TabOrder = 5 end object PctSignalCheck: TCheckBox Left = 40 Height = 17 Top = 200 Width = 62 Caption = '% Signal' Checked = True State = cbChecked TabOrder = 6 end object ModelCheck: TCheckBox Left = 80 Height = 17 Top = 320 Width = 192 Caption = 'Report modeled, not observed data' TabOrder = 7 Visible = False end object RegressCheck: TCheckBox Left = 40 Height = 17 Top = 240 Width = 116 Caption = 'Remove Regressors' Checked = True OnClick = RegressCheckClick State = cbChecked TabOrder = 8 end object TDCheck: TCheckBox Left = 80 Height = 17 Top = 280 Width = 181 Caption = 'Also Remove Temporal Derivative' Checked = True State = cbChecked TabOrder = 9 Visible = False end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/mricron.res��������������������������������������������������������0000755�0001750�0001750�00000074010�12374712620�016375� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ �����������������������v���0����M�A�I�N�I�C�O�N�����������������������00������� ���� ��������������h���00�� �%��� �� ������ �h�������������� �������������������(���0���`�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������~~yyDD++EEӣ������������������������������������������������������������������������������������������������������������쿿ہNN ����������<<������������������������������������������������������������������������������������������������袢``��������������������/0���������������������������������������������������������ÛvvMM66MMʭ՚ssGG��������������������������������������������������������������XY=>-."# �������������������������������� Ue������������������������������������������8:y��~������������������������������&�@�[�n�~Hamnwׂ؝������������������������������#��� ���������������������������)�U�����������������RRϊ���������������{}#Z|��������]�*��������������'�v��������������������;;jj���������obw�����������~�3�������<���������������������������;;������;? ����������������S �������������e����������������������mm������%%+�������������m����������m������������������������������))))$' .�����������������J������������������������ ++������LL8722+0! ����������A��x�E����������������������������� 11���dd>>AA;;15'!���O�������"oL-���������������������������������!!''**''__������//GGLL@?:=����������������6����"��������������������������������**,,555588���������GG[[MMLL((��������������Lc���������������������������������((6688BB;;@@������������MMRRbbXXAA�����������������Z�������������������������������������==AAFFMMIIII������������MMlleeYY�����������������`�������������������������������������--KKLLUUMMQQ������������������DDRRxxmm%%�����������������\�����?������������������������������NNUUXXaaRR���������������������bbhhSS���������������M�����u��������������������������BB``]]jj[[������������������������ffVV||EE�����������6����������������������������� EEffddrrjj__������������������������������kkQQTT ���������!�������������������������++ZZllkkxxmm\\������������������������������������]]^^pp..�����������������������77XXoopptt||ssss������������������������������������������uuQQbb##��������� �������!!99RRffqqrrtt������������������������������������������������``\\bb// ��X����('::KK[[ffmmppqqvvzznnxx������������������������������������������������������hhlj78 ��,GEQR\[aaddhhjjnnyynn���������������������������������������������������������������rrRRhhZl+�1]LT][``eekkttttuu������������������������������������������������������������������������uull& v\hmsrxx}}{{mm__xx������������������������������������������������������������������������������������yyuuopolpxu,<:MMVVWW__jj���������������������������������������������������������������������������������������������������||! H@���qp ++::oo�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?����������������������������������������������� �� �������������������(��� ���@��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������aa������������������������������������������������������������������������������ㅅRR55^^������������������������������������������������������������xx44������������$!������������������������������������psLP2645CC<<�������������� ���������������������������pk!�����������������������&�J�j��6`IZ]qψܻ���������������<�S�zu�Y�5 ������Q��������e������]]���������zgt��������A������������]��������bb������ ��������/�������������������������12'$������. ����]����������������^^���>>;=32�@�����Rcc�8 ������������������$$$$ss���QQIIKL:<���������p�����������������������005588���������WWZZWW���������"�������������������11AAGGEE���������ttSSqq33������������a������������������NNTTSSpp������������iinnff������������������������HHbbaarr������������������bbZZ����e�����������������NNllll__������������������������eeqq!!������D�� ���������AAhhxx~~||���������������������������tt]]YY �������**@@ZZoo||}}ttff������������������������������������nnb_(��@:LN^]jjuu{{{{xx������������������������������������������AA~~cL_lpmqqssrrss������������������������������������������������������}}plixjiiiiYXii{{������������������������������������������������������������������}}������ii�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?���� �������������������(������0����������������������������������������������������������������������>��L��P���������������������������������������r�������������������7� ��;��-����� ����!�$#�%-�-!�0F�22�3(�53�88�:3�;?�< �<�?1�B��I��JJ�NM�PP�PR�QZ�TS�YY�YY�Z\�\Z�^`�__�`��bb�ff�gg�o�vv�ww�zy�|z�||�~��v���������������u���H���� �__�$������ ���������� ����l�*��VT�����o�������������14��������&�6��>8�LM�TT�Yg��2����������������� ���77�::�LL�PP�QQ�UU�]\�cc�pm�tt�������������������������""�&&�44�;�AA�[[�aa�cc�ee�mm�ss�tt�yy�{{�}}��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������waO@Fc���������������hkP=0A��������gL?689<) 3>Jsu�����X2  1Mix~{z���C+' #"[}|y��;5!(!Kļ�IE7*_�TRH-,o��VY4%&t֊���]`G./qՈ����UdD$f������^l\:NՎ��������ZjnWBԘ�����������rmpev��������������bQS��������������������������������������������������������������������������������������������������������������?�?���������������������������?������h�� �������������������(������ ��������������������������������������������� �������������������������� ��k� ;� �k�K�!�&� �',�->�/!�0��9+�;2�M]�PP�Wj�YZ�bY�ff�hk�i=�jj�lk�l�oo�op�t��}n���������������x���Zn�[[���H[�B�����������j�$�������>5������{��}{�����������BB�KM�NN�PP�dd�jj��� ������������ ��#�))�::�T]�[[�uu�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������&!��������0793#�����$/18A>;�) =Scba`C@? 5hFGDENegj�% :OITRd`VWY�*( <^JM`QUZ[���+' 6pHLfilm�����-2",_KX\no��������4.BkP]������������������������������������������������������������������������������������������%�� �������������������(���0���`���� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������F��������������������������������������������������������������������������������������������������������������������������������������������P����������������������<����������������������������������������������������������������������������������������������������������������������������������������������������������==����������������������������������������������������������������������������������������������������������������������)������������������������������##hhoo�������������������� ��������������������������������������������������������������e����������������������������������LLrrpp������������������))DJHn[Wmgc ���������������������������������������������� ��n��������������������������������������hhwoU��o��������>:XTXTKGtnX�������������� �����������������������������������������t�����vva���������� )'TPtnrlhcOMx ������}������������������������������,���Z����8wn9������������=:rltorlC@&�������������������������������5����۾���^sV$������������ %#lgtntoUQ@= ��������� ��������e*ft*r����������������OKlgtnjdGDC>_�����������������%/isc��������������������:8c^rmniPL0-����  w��������ns_(a����������������������*(ZVqkpjSO1-t2155=5' #8GW7��������������������������RNojoiQM53@@%00~}wviXHELTgjloqt����������������������������" UQpjlgLH73|JJӞuttwwwwwwO ����������������������������,*[WqlgbB?SKD3~yxwwwwwwE ���J������������������������� SOnhtnXT:7 .zxusromk>����ܱ�����������������������d`rmtnMIA?r+voj[RH4|*Z 4 �����������������������������84ojtorl<9z$ uuՆcc'' ������������������<�����������������20TPjetoql`[���� uuuss77!!������s����������w���������������VQkfsmsnjeMJ����@}}ŀPP88$$ ����=�������������������������85lgsnuooj[V=:������������5dss[[//����������צ���������B>]YniuotoqkEBOJg ����������������"9ww{{LL77%%�ߣ������ 20c^ojtntoqld`JFx �������������������� %vvmmWWAA he��%$A>ZVrltouoqlfaJG ���������������������������� (?YYDD33 ')(2/HEkfrltotosnniGD=:������������������������������������'=ww{{ggSS7700.4:>IHF4-,-+LH\WidsntotoqkjdXTLJk ���������������������������������������� %kwwvv[[TToS_gmurmg[ZW\Xkfpksntosnql_ZKH<:���������������������������������������������������� 0FxxΘ|wxrsnpjjeWSIE=:˿������������������������������������������������������������*bxx}wvqqlb]WSJFFCb_F������������������������������������������������������������������������ 1A]||~zsn^[XTQMGCNKw8 ������������������������������������������������������������������������������������ *3<GIH=6- ������������������������������������������������������������������������������������������������������������ &'& ��������������������������������������������������������������������������������������������������������������������������������  ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������>����<����������������������������������������������������������������������������������������������������������������������������������������������?������?������������������������������������������������ �������������������(��� ���@���� ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������==������������������������������������������������������������������������������)��������������������##oo������������ ������������������������������ ��n������������������������hhoU������XTXTtnX������������������������������������t����va������ TPtnhcOMx���������������������5���۾��^s$��������%#lgtoUQ ������� �����e*t*r������������OKtnjdC>_���� �����ns(a��������������*(qkpj1-21=5 #8W7������������������ojoi53JJӞutwwww ������������������,*qlgbSKD3~xwwww ��J����������������� SOtnXT +vj[H4| 4 �������������������84ojrl<9 uu՞cc'' �������������������������20jeto`[����@PP$$ ��=�����������������85lguooj=:��������d[[//�������������B>niuoqkEB ������������ %mmAA ��%$ZVrluoqlJG �������������������� (YY33 '(HEkftotoniGD���������������������������� %kvv[[oS_mumg[\Xkfsntoql_Z<:������������������������������������ FxxΘxrsnjeWS=:˿��������������������������������������������1]sn^[QMGCw8 �������������������������������������������������������� *<GH=- ����������������������������������������������������������������������������  ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?����?h�� �������������������(������ ���� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������n������������hhU��XT���������������s����lgUQ���� ��s��������*(pjuww����������,*gbv[4| ���������oj<9@PP =��������lgoj���� mm��%$rlql ������������ k[[_ug[kfto_Z��������������������1^[GC �������������������������������� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �������������������(������(��������������������������������������������������������������������������������((�,,�99�AA�I�J��WW�ZZ�hh�ll�nn�x{�yy������������S��������������������������������������2������������� ����!!�&&�,,�//�DD�EE�II�LM�QQ�WW�ZZ�^^�bb�dd�ii�jj�oo�rr�ss�}}������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BDA21,+�� .49CE@>7>0,� 8EB@>>>>7:H� -;>?>>>>>>JM��"5bF>>>>>>KON��#3c>>>>>>>SV`���& /=>>>>>>XZU����� )<G>>IV\^_�������(*'6QTW[]Y�����������!%$LRPa�����������������������������������������������������������������������������������������������������������������0��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_xclean.bat��������������������������������������������������������0000755�0001750�0001750�00000000553�12147213650�016310� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rm -r *.a rm -r *.o rm -r *.ppu rm -r *.bak rm mricron cd ./rgb rm -r *.a rm -r *.o rm -r *.ppu rm -r *.bak cd .. cd ./common rm -r *.a rm -r *.o rm -r *.ppu rm -r *.bak cd .. cd ./dcm2nii rm ./dcm2niigui rm ./dcm2nii rm -r *.a rm -r *.o rm -r *.ppu rm -r *.bak rm -rf dcm2niigui.app cd .. cd ./npm rm ./npm rm -r *.o rm -r *.ppu rm -r *.bak �����������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/mricron.lpi��������������������������������������������������������0000755�0001750�0001750�00000143500�12374712620�016371� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="9"/> <PathDelim Value="\"/> <General> <Flags> <LRSInOutputDirectory Value="False"/> </Flags> <MainUnit Value="0"/> <Title Value="MRIcron"/> <Icon Value="0"/> <ActiveWindowIndexAtStart Value="0"/> </General> <BuildModes Count="1"> <Item1 Name="default" Default="True"/> </BuildModes> <PublishOptions> <Version Value="2"/> <IgnoreBinaries Value="False"/> <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/> </PublishOptions> <RunParams> <local> <FormatVersion Value="1"/> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> </RunParams> <RequiredPackages Count="2"> <Item1> <PackageName Value="FCL"/> <MinVersion Major="1" Valid="True"/> </Item1> <Item2> <PackageName Value="LCL"/> </Item2> </RequiredPackages> <Units Count="141"> <Unit0> <Filename Value="mricron.lpr"/> <IsPartOfProject Value="True"/> <UnitName Value="mricron"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="27" Y="13"/> <UsageCount Value="200"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit0> <Unit1> <Filename Value="unit1.pas"/> <ComponentName Value="Form1"/> <UnitName Value="Unit1"/> <TopLine Value="16"/> <CursorPos X="7" Y="19"/> <UsageCount Value="12"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit1> <Unit2> <Filename Value="nifti_hdr_view.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="HdrForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="nifti_hdr_view"/> <EditorIndex Value="6"/> <WindowIndex Value="0"/> <TopLine Value="273"/> <CursorPos X="36" Y="602"/> <UsageCount Value="200"/> <Loaded Value="True"/> <LoadedDesigner Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit2> <Unit3> <Filename Value="define_types.pas"/> <UnitName Value="define_types"/> <TopLine Value="410"/> <CursorPos X="23" Y="420"/> <UsageCount Value="93"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit3> <Unit4> <Filename Value="GraphicsMathLibrary.pas"/> <UnitName Value="GraphicsMathLibrary"/> <TopLine Value="326"/> <CursorPos X="38" Y="349"/> <UsageCount Value="6"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit4> <Unit5> <Filename Value="about.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="AboutForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="about"/> <WindowIndex Value="0"/> <TopLine Value="4"/> <CursorPos X="65" Y="40"/> <UsageCount Value="200"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit5> <Unit6> <Filename Value="text.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="TextForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="text"/> <WindowIndex Value="0"/> <TopLine Value="36"/> <CursorPos X="1" Y="61"/> <UsageCount Value="200"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit6> <Unit7> <Filename Value="..\lcl\include\customform.inc"/> <TopLine Value="315"/> <CursorPos X="31" Y="325"/> <UsageCount Value="1"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit7> <Unit8> <Filename Value="render.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="RenderForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="render"/> <EditorIndex Value="2"/> <WindowIndex Value="0"/> <TopLine Value="362"/> <CursorPos X="56" Y="370"/> <UsageCount Value="200"/> <Loaded Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit8> <Unit9> <Filename Value="ROIfilt.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="FilterROIform"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="ROIfilt"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="58" Y="13"/> <UsageCount Value="200"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit9> <Unit10> <Filename Value="smoothVOI.pas"/> <ComponentName Value="SmoothVOIForm"/> <HasResources Value="True"/> <UnitName Value="smoothVOI"/> <TopLine Value="382"/> <CursorPos X="31" Y="303"/> <UsageCount Value="1"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit10> <Unit11> <Filename Value="nifti_img_view.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="ImgForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="nifti_img_view"/> <IsVisibleTab Value="True"/> <EditorIndex Value="0"/> <WindowIndex Value="0"/> <TopLine Value="1384"/> <CursorPos X="50" Y="1395"/> <UsageCount Value="200"/> <Loaded Value="True"/> <LoadedDesigner Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit11> <Unit12> <Filename Value="nifti_img.pas"/> <UnitName Value="nifti_img"/> <EditorIndex Value="9"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="144" Y="3"/> <UsageCount Value="100"/> <Loaded Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit12> <Unit13> <Filename Value="cutout.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="CutoutForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="cutout"/> <TopLine Value="161"/> <CursorPos X="29" Y="166"/> <UsageCount Value="200"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit13> <Unit14> <Filename Value="MultiSlice.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="MultiSliceForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="MultiSlice"/> <WindowIndex Value="0"/> <TopLine Value="847"/> <CursorPos X="46" Y="851"/> <UsageCount Value="200"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit14> <Unit15> <Filename Value="autoroi.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="AutoROIForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="autoroi"/> <WindowIndex Value="0"/> <TopLine Value="517"/> <CursorPos X="68" Y="537"/> <UsageCount Value="200"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit15> <Unit16> <Filename Value="spread.pas"/> <ComponentName Value="SpreadForm"/> <HasResources Value="True"/> <UnitName Value="spread"/> <TopLine Value="83"/> <CursorPos X="47" Y="93"/> <UsageCount Value="192"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit16> <Unit17> <Filename Value="design.pas"/> <ComponentName Value="DesignForm"/> <HasResources Value="True"/> <UnitName Value="design"/> <TopLine Value="1"/> <CursorPos X="45" Y="167"/> <UsageCount Value="192"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit17> <Unit18> <Filename Value="histoform.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="HistogramForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="histoform"/> <WindowIndex Value="0"/> <TopLine Value="40"/> <CursorPos X="1" Y="76"/> <UsageCount Value="200"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit18> <Unit19> <Filename Value="nifti_img_view.lrs"/> <TopLine Value="2"/> <CursorPos X="1" Y="1000"/> <UsageCount Value="5"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit19> <Unit20> <Filename Value="logistic.pas"/> <UnitName Value="logistic"/> <TopLine Value="1075"/> <CursorPos X="1" Y="1100"/> <UsageCount Value="22"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit20> <Unit21> <Filename Value="ReadInt.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="ReadIntForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="ReadInt"/> <EditorIndex Value="8"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="77" Y="2"/> <UsageCount Value="200"/> <Loaded Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit21> <Unit22> <Filename Value="..\lcl\grids.pas"/> <UnitName Value="Grids"/> <TopLine Value="5919"/> <CursorPos X="1" Y="5925"/> <UsageCount Value="6"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit22> <Unit23> <Filename Value="..\lcl\include\graphic.inc"/> <TopLine Value="1"/> <CursorPos X="1" Y="104"/> <UsageCount Value="1"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit23> <Unit24> <Filename Value="nifti_img_view.lfm"/> <TopLine Value="499"/> <CursorPos X="7" Y="513"/> <UsageCount Value="10"/> <DefaultSyntaxHighlighter Value="LFM"/> </Unit24> <Unit25> <Filename Value="nifti_hdr.pas"/> <UnitName Value="nifti_hdr"/> <TopLine Value="172"/> <CursorPos X="5" Y="188"/> <UsageCount Value="85"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit25> <Unit26> <Filename Value="gzio2.pas"/> <UnitName Value="gzio2"/> <TopLine Value="278"/> <CursorPos X="11" Y="282"/> <UsageCount Value="37"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit26> <Unit27> <Filename Value="stat.pas"/> <UnitName Value="stat"/> <TopLine Value="318"/> <CursorPos X="10" Y="329"/> <UsageCount Value="14"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit27> <Unit28> <Filename Value="..\lcl\forms.pp"/> <UnitName Value="Forms"/> <TopLine Value="799"/> <CursorPos X="1" Y="806"/> <UsageCount Value="6"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit28> <Unit29> <Filename Value="..\lcl\lmessages.pp"/> <UnitName Value="LMessages"/> <TopLine Value="588"/> <CursorPos X="1" Y="600"/> <UsageCount Value="6"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit29> <Unit30> <Filename Value="cropedges.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="CropEdgeForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="CropEdges"/> <WindowIndex Value="0"/> <TopLine Value="81"/> <CursorPos X="3" Y="83"/> <UsageCount Value="200"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit30> <Unit31> <Filename Value="bet.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="BETForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="bet"/> <WindowIndex Value="0"/> <TopLine Value="54"/> <CursorPos X="59" Y="55"/> <UsageCount Value="200"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit31> <Unit32> <Filename Value="mni.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="MNIForm"/> <ResourceBaseClass Value="Form"/> <UnitName Value="mni"/> <WindowIndex Value="0"/> <TopLine Value="20"/> <CursorPos X="3" Y="53"/> <UsageCount Value="200"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit32> <Unit33> <Filename Value="RenderThds.pas"/> <UnitName Value="RenderThds"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="20" Y="4"/> <UsageCount Value="13"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit33> <Unit34> <Filename Value="..\examples\bounty\qgraphics.pas"/> <UnitName Value="qgraphics"/> <TopLine Value="30"/> <CursorPos X="15" Y="38"/> <UsageCount Value="1"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit34> <Unit35> <Filename Value="wgraphics.pas"/> <UnitName Value="wgraphics"/> <TopLine Value="1"/> <CursorPos X="1" Y="9"/> <UsageCount Value="14"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit35> <Unit36> <Filename Value="ugraphics.pas"/> <UnitName Value="ugraphics"/> <TopLine Value="1"/> <CursorPos X="15" Y="1"/> <UsageCount Value="85"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit36> <Unit37> <Filename Value="mricron_w\nifti_img.pas"/> <UnitName Value="nifti_img"/> <TopLine Value="70"/> <CursorPos X="26" Y="82"/> <UsageCount Value="1"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit37> <Unit38> <Filename Value="..\examples\bounty\fx8.pas"/> <UnitName Value="fx8"/> <TopLine Value="114"/> <CursorPos X="68" Y="121"/> <UsageCount Value="1"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit38> <Unit39> <Filename Value="fx8.pas"/> <UnitName Value="fx8"/> <EditorIndex Value="1"/> <WindowIndex Value="0"/> <TopLine Value="200"/> <CursorPos X="20" Y="246"/> <UsageCount Value="13"/> <Loaded Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit39> <Unit40> <Filename Value="MultiSlice.lfm"/> <TopLine Value="1"/> <CursorPos X="1" Y="1"/> <UsageCount Value="1"/> <DefaultSyntaxHighlighter Value="LFM"/> </Unit40> <Unit41> <Filename Value="MultiSlice.lrs"/> <TopLine Value="1"/> <CursorPos X="17" Y="3"/> <UsageCount Value="8"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit41> <Unit42> <Filename Value="smoothVOI.lfm"/> <TopLine Value="1"/> <CursorPos X="1" Y="1"/> <UsageCount Value="1"/> <DefaultSyntaxHighlighter Value="LFM"/> </Unit42> <Unit43> <Filename Value="voismooth.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="voismoothform"/> <ResourceBaseClass Value="Form"/> <UnitName Value="voismooth"/> <WindowIndex Value="0"/> <TopLine Value="385"/> <CursorPos X="36" Y="391"/> <UsageCount Value="200"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit43> <Unit44> <Filename Value="..\components\rtticontrols\rttictrls.pas"/> <UnitName Value="RTTICtrls"/> <TopLine Value="20"/> <CursorPos X="56" Y="37"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit44> <Unit45> <Filename Value="..\lcl\fileutil.pas"/> <UnitName Value="FileUtil"/> <TopLine Value="105"/> <CursorPos X="35" Y="124"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit45> <Unit46> <Filename Value="prefs.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="PrefForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="prefs"/> <EditorIndex Value="7"/> <WindowIndex Value="0"/> <TopLine Value="43"/> <CursorPos X="46" Y="58"/> <UsageCount Value="200"/> <Loaded Value="True"/> <LoadedDesigner Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit46> <Unit47> <Filename Value="dcm2nii\dcm2niigui.lrs"/> <TopLine Value="1"/> <CursorPos X="23" Y="1"/> <UsageCount Value="1"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit47> <Unit48> <Filename Value="C:\Documents and Settings\Chris Rorden\Application Data\Opera\Opera\profile\cache4\temporary_download\JclSysInfo.pas"/> <UnitName Value="JclSysInfo"/> <TopLine Value="29"/> <CursorPos X="36" Y="36"/> <UsageCount Value="7"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit48> <Unit49> <Filename Value="rgbroutines.pas"/> <UnitName Value="RGBRoutines"/> <TopLine Value="49"/> <CursorPos X="49" Y="4"/> <UsageCount Value="6"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit49> <Unit50> <Filename Value="junk.pas"/> <UnitName Value="junk"/> <TopLine Value="33"/> <CursorPos X="1" Y="46"/> <UsageCount Value="3"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit50> <Unit51> <Filename Value="rgbtypes.pas"/> <UnitName Value="RGBTypes"/> <TopLine Value="1"/> <CursorPos X="44" Y="5"/> <UsageCount Value="6"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit51> <Unit52> <Filename Value="usr\local\share\lazarus\components\rtticontrols\runtimetypeinfocontrols.pas"/> <UnitName Value="RunTimeTypeInfoControls"/> <TopLine Value="1"/> <CursorPos X="23" Y="4"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit52> <Unit53> <Filename Value="usr\local\share\lazarus\tools\svn2revisioninc.pas"/> <UnitName Value="Svn2RevisionInc"/> <TopLine Value="34"/> <CursorPos X="40" Y="49"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit53> <Unit54> <Filename Value="userdir.pas"/> <UnitName Value="userdir"/> <TopLine Value="62"/> <CursorPos X="10" Y="6"/> <UsageCount Value="6"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit54> <Unit55> <Filename Value="perisettings.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="PSForm"/> <ResourceBaseClass Value="Form"/> <UnitName Value="perisettings"/> <TopLine Value="81"/> <CursorPos X="38" Y="96"/> <UsageCount Value="224"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit55> <Unit56> <Filename Value="graphx.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="Graph4DForm"/> <ResourceBaseClass Value="Form"/> <UnitName Value="graphx"/> <TopLine Value="1043"/> <CursorPos X="29" Y="1055"/> <UsageCount Value="224"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit56> <Unit57> <Filename Value="metagraph.pas"/> <UnitName Value="metagraph"/> <TopLine Value="40"/> <CursorPos X="19" Y="45"/> <UsageCount Value="8"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit57> <Unit58> <Filename Value="render2.pas"/> <UnitName Value="render"/> <TopLine Value="1045"/> <CursorPos X="1" Y="1066"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit58> <Unit59> <Filename Value="RenderThds2.pas"/> <UnitName Value="RenderThds2"/> <TopLine Value="308"/> <CursorPos X="1" Y="333"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit59> <Unit60> <Filename Value="rgb\rgbgraphics.pas"/> <UnitName Value="RGBGraphics"/> <TopLine Value="241"/> <CursorPos X="5" Y="255"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit60> <Unit61> <Filename Value="C:\Desktop\rgbgraphics.pas"/> <UnitName Value="RGBGraphics"/> <TopLine Value="151"/> <CursorPos X="1" Y="165"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit61> <Unit62> <Filename Value="rgb\rgbtypes.pas"/> <UnitName Value="RGBTypes"/> <TopLine Value="1"/> <CursorPos X="131" Y="4"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit62> <Unit63> <Filename Value="C:\Desktop\rgbtypes.pas"/> <UnitName Value="RGBTypes"/> <TopLine Value="45"/> <CursorPos X="5" Y="59"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit63> <Unit64> <Filename Value="..\share\mango.txt"/> <TopLine Value="1"/> <CursorPos X="1" Y="5"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="None"/> </Unit64> <Unit65> <Filename Value="..\share\tempura.txt"/> <TopLine Value="1"/> <CursorPos X="1" Y="3"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="None"/> </Unit65> <Unit66> <Filename Value="rgb\rgbroutines.pas"/> <UnitName Value="RGBRoutines"/> <TopLine Value="26"/> <CursorPos X="1" Y="46"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit66> <Unit67> <Filename Value="..\share\mexico.txt"/> <TopLine Value="20"/> <CursorPos X="4" Y="23"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="None"/> </Unit67> <Unit68> <Filename Value="usr\local\share\lazarus\components\rtticontrols\rttictrls.pas"/> <UnitName Value="RTTICtrls"/> <TopLine Value="18"/> <CursorPos X="31" Y="33"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit68> <Unit69> <Filename Value="usr\local\share\lazarus\lcl\fileutil.pas"/> <UnitName Value="FileUtil"/> <TopLine Value="4"/> <CursorPos X="43" Y="10"/> <UsageCount Value="3"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit69> <Unit70> <Filename Value="cpucount.pas"/> <UnitName Value="cpucount"/> <TopLine Value="55"/> <CursorPos X="24" Y="5"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit70> <Unit71> <Filename Value="..\share\xview.pas"/> <UnitName Value="nifti_img_view"/> <TopLine Value="3594"/> <CursorPos X="20" Y="3617"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit71> <Unit72> <Filename Value="..\share\xhdr.pas"/> <UnitName Value="nifti_hdr"/> <TopLine Value="160"/> <CursorPos X="1" Y="174"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit72> <Unit73> <Filename Value="rgb\rgbcarbonroutines.pas"/> <UnitName Value="RGBCarbonRoutines"/> <TopLine Value="9"/> <CursorPos X="36" Y="23"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit73> <Unit74> <Filename Value="rgb\rgbgtkroutines.pas"/> <UnitName Value="RGBGTKRoutines"/> <TopLine Value="28"/> <CursorPos X="4" Y="36"/> <UsageCount Value="4"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit74> <Unit75> <Filename Value="rgb\lazrgbgraphics.pas"/> <UnitName Value="LazRGBGraphics"/> <TopLine Value="1"/> <CursorPos X="1" Y="1"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit75> <Unit76> <Filename Value="rgb\rgbutils.pas"/> <UnitName Value="RGBUtils"/> <TopLine Value="20"/> <CursorPos X="66" Y="47"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit76> <Unit77> <Filename Value="rgbw\RGBGraphics.pas"/> <UnitName Value="RGBGraphics"/> <TopLine Value="172"/> <CursorPos X="29" Y="186"/> <UsageCount Value="2"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit77> <Unit78> <Filename Value="irender.pas"/> <UnitName Value="render"/> <TopLine Value="1310"/> <CursorPos X="1" Y="1328"/> <UsageCount Value="7"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit78> <Unit79> <Filename Value="render_composite.pas"/> <UnitName Value="render_composite"/> <EditorIndex Value="3"/> <WindowIndex Value="0"/> <TopLine Value="824"/> <CursorPos X="66" Y="838"/> <UsageCount Value="11"/> <Loaded Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit79> <Unit80> <Filename Value="periplot.pas"/> <UnitName Value="periplot"/> <TopLine Value="532"/> <CursorPos X="20" Y="544"/> <UsageCount Value="9"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit80> <Unit81> <Filename Value="periutils.pas"/> <UnitName Value="periutils"/> <TopLine Value="159"/> <CursorPos X="1" Y="183"/> <UsageCount Value="11"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit81> <Unit82> <Filename Value="reslice.pas"/> <UnitName Value="reslice"/> <TopLine Value="202"/> <CursorPos X="46" Y="211"/> <UsageCount Value="7"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit82> <Unit83> <Filename Value="fpmath\fmath.pas"/> <UnitName Value="fmath"/> <TopLine Value="761"/> <CursorPos X="30" Y="852"/> <UsageCount Value="3"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit83> <Unit84> <Filename Value="hrf.pas"/> <UnitName Value="hrf"/> <TopLine Value="135"/> <CursorPos X="29" Y="151"/> <UsageCount Value="4"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit84> <Unit85> <Filename Value="fpmath\regmult.pas"/> <UnitName Value="regmult"/> <TopLine Value="119"/> <CursorPos X="1" Y="115"/> <UsageCount Value="4"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit85> <Unit86> <Filename Value="clustering.pas"/> <UnitName Value="clustering"/> <WindowIndex Value="0"/> <TopLine Value="161"/> <CursorPos X="6" Y="183"/> <UsageCount Value="11"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit86> <Unit87> <Filename Value="ReadFloat.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="ReadFloatForm"/> <ResourceBaseClass Value="Form"/> <UnitName Value="ReadFloat"/> <TopLine Value="38"/> <CursorPos X="38" Y="53"/> <UsageCount Value="195"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit87> <Unit88> <Filename Value="npm\gzio2.pas"/> <UnitName Value="gzio2"/> <TopLine Value="756"/> <CursorPos X="13" Y="797"/> <UsageCount Value="3"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit88> <Unit89> <Filename Value="common\nifti_hdr.pas"/> <UnitName Value="nifti_hdr"/> <WindowIndex Value="0"/> <TopLine Value="22"/> <CursorPos X="1" Y="36"/> <UsageCount Value="26"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit89> <Unit90> <Filename Value="common\define_types.pas"/> <UnitName Value="define_types"/> <EditorIndex Value="5"/> <WindowIndex Value="0"/> <TopLine Value="205"/> <CursorPos X="36" Y="147"/> <UsageCount Value="68"/> <Loaded Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit90> <Unit91> <Filename Value="common\cpucount.pas"/> <UnitName Value="cpucount"/> <TopLine Value="1"/> <CursorPos X="46" Y="12"/> <UsageCount Value="5"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit91> <Unit92> <Filename Value="common\userdir.pas"/> <UnitName Value="userdir"/> <TopLine Value="35"/> <CursorPos X="14" Y="43"/> <UsageCount Value="12"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit92> <Unit93> <Filename Value="C:\lazarus\lcl\dialogs.pp"/> <UnitName Value="Dialogs"/> <TopLine Value="466"/> <CursorPos X="43" Y="481"/> <UsageCount Value="4"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit93> <Unit94> <Filename Value="dicomhdr.pas"/> <UnitName Value="dicomhdr"/> <TopLine Value="464"/> <CursorPos X="50" Y="493"/> <UsageCount Value="4"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit94> <Unit95> <Filename Value="rgbnew\rgbgtkroutines.pas"/> <UnitName Value="RGBGTKRoutines"/> <TopLine Value="67"/> <CursorPos X="1" Y="79"/> <UsageCount Value="3"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit95> <Unit96> <Filename Value="render.lfm"/> <TopLine Value="1"/> <CursorPos X="1" Y="1"/> <UsageCount Value="3"/> <DefaultSyntaxHighlighter Value="LFM"/> </Unit96> <Unit97> <Filename Value="common\GraphicsMathLibrary.pas"/> <UnitName Value="GraphicsMathLibrary"/> <TopLine Value="45"/> <CursorPos X="15" Y="60"/> <UsageCount Value="9"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit97> <Unit98> <Filename Value="reslice_img.pas"/> <UnitName Value="reslice_img"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="46" Y="6"/> <UsageCount Value="12"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit98> <Unit99> <Filename Value="ortho_reorient.pas"/> <UnitName Value="ortho_reorient"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="81" Y="6"/> <UsageCount Value="12"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit99> <Unit100> <Filename Value="common\dicomhdr.pas"/> <UnitName Value="dicomhdr"/> <WindowIndex Value="0"/> <TopLine Value="6"/> <CursorPos X="26" Y="11"/> <UsageCount Value="31"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit100> <Unit101> <Filename Value="C:\lazarus\components\cgi\cgimodules.pas"/> <UnitName Value="cgiModules"/> <TopLine Value="1"/> <CursorPos X="53" Y="19"/> <UsageCount Value="4"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit101> <Unit102> <Filename Value="reslice_fsl.pas"/> <UnitName Value="reslice_fsl"/> <TopLine Value="25"/> <CursorPos X="27" Y="38"/> <UsageCount Value="14"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit102> <Unit103> <Filename Value="..\mricrogl\sourcex\mricrogl.lpr"/> <TopLine Value="1"/> <CursorPos X="1" Y="1"/> <UsageCount Value="3"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit103> <Unit104> <Filename Value="..\gl\Source\Base\OpenGL1x.pas"/> <UnitName Value="OpenGL1x"/> <TopLine Value="5131"/> <CursorPos X="10" Y="5142"/> <UsageCount Value="3"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit104> <Unit105> <Filename Value="imgutil.pas"/> <UnitName Value="imgutil"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="87" Y="11"/> <UsageCount Value="8"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit105> <Unit106> <Filename Value="batch.pas"/> <UnitName Value="batch"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="98" Y="2"/> <UsageCount Value="13"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit106> <Unit107> <Filename Value="fdr.pas"/> <UnitName Value="fdr"/> <TopLine Value="1"/> <CursorPos X="51" Y="73"/> <UsageCount Value="4"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit107> <Unit108> <Filename Value="statclustertable.pas"/> <UnitName Value="statclustertable"/> <WindowIndex Value="0"/> <TopLine Value="103"/> <CursorPos X="83" Y="113"/> <UsageCount Value="11"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit108> <Unit109> <Filename Value="reorient.pas"/> <UnitName Value="reorient"/> <TopLine Value="54"/> <CursorPos X="35" Y="56"/> <UsageCount Value="9"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit109> <Unit110> <Filename Value="C:\lazarus\fpc\2.2.2\source\rtl\objpas\sysutils\osutilsh.inc"/> <TopLine Value="31"/> <CursorPos X="10" Y="38"/> <UsageCount Value="7"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit110> <Unit111> <Filename Value="npm\part.pas"/> <UnitName Value="part"/> <TopLine Value="1"/> <CursorPos X="11" Y="31"/> <UsageCount Value="7"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit111> <Unit112> <Filename Value="graphx.lrs"/> <TopLine Value="1"/> <CursorPos X="1" Y="153"/> <UsageCount Value="5"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit112> <Unit113> <Filename Value="landmarks.lfm"/> <TopLine Value="1"/> <CursorPos X="1" Y="1"/> <UsageCount Value="5"/> <DefaultSyntaxHighlighter Value="LFM"/> </Unit113> <Unit114> <Filename Value="landmarks.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="AnatForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="landmarks"/> <TopLine Value="166"/> <CursorPos X="50" Y="175"/> <UsageCount Value="141"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit114> <Unit115> <Filename Value="prefs.lfm"/> <TopLine Value="1"/> <CursorPos X="1" Y="1"/> <UsageCount Value="4"/> <DefaultSyntaxHighlighter Value="LFM"/> </Unit115> <Unit116> <Filename Value="C:\usr\share\fpcsrc\rtl\unix\baseunix.pp"/> <UnitName Value="BaseUnix"/> <TopLine Value="1"/> <CursorPos X="1" Y="1"/> <UsageCount Value="4"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit116> <Unit117> <Filename Value="common\isgui.inc"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="10" Y="1"/> <UsageCount Value="18"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit117> <Unit118> <Filename Value="batchstatselect.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="batchstatselect"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="43" Y="6"/> <UsageCount Value="130"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit118> <Unit119> <Filename Value="yokeipc.pas"/> <UnitName Value="yokeipc"/> <TopLine Value="3"/> <CursorPos X="29" Y="105"/> <UsageCount Value="4"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit119> <Unit120> <Filename Value="yokesharemem.pas"/> <UnitName Value="yokesharemem"/> <WindowIndex Value="0"/> <TopLine Value="53"/> <CursorPos X="14" Y="58"/> <UsageCount Value="9"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit120> <Unit121> <Filename Value="winmemmap.pas"/> <UnitName Value="winmemmap"/> <TopLine Value="2"/> <CursorPos X="56" Y="9"/> <UsageCount Value="5"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit121> <Unit122> <Filename Value="C:\usr\lib\lazarus\lcl\interfaces\gtk\interfaces.pp"/> <UnitName Value="Interfaces"/> <TopLine Value="1"/> <CursorPos X="17" Y="13"/> <UsageCount Value="4"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit122> <Unit123> <Filename Value="C:\lazarus\fpc\2.4.1\source\rtl\win\wininc\defines.inc"/> <TopLine Value="1"/> <CursorPos X="64" Y="301"/> <UsageCount Value="5"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit123> <Unit124> <Filename Value="common\dialogsx.pas"/> <UnitName Value="dialogsx"/> <WindowIndex Value="0"/> <TopLine Value="118"/> <CursorPos X="38" Y="119"/> <UsageCount Value="14"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit124> <Unit125> <Filename Value="..\mricrogl\source\common\nifti_hdr.pas"/> <UnitName Value="nifti_hdr"/> <TopLine Value="47"/> <CursorPos X="26" Y="49"/> <UsageCount Value="4"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit125> <Unit126> <Filename Value="C:\usr\share\fpcsrc\packages\fcl-process\src\process.pp"/> <UnitName Value="process"/> <TopLine Value="25"/> <CursorPos X="70" Y="25"/> <UsageCount Value="5"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit126> <Unit127> <Filename Value="otsu.pas"/> <UnitName Value="otsu"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="9" Y="6"/> <UsageCount Value="14"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit127> <Unit128> <Filename Value="C:\Developer\lazarus\lcl\interfaces\carbon\carbonobject.inc"/> <WindowIndex Value="0"/> <TopLine Value="206"/> <CursorPos X="1" Y="228"/> <UsageCount Value="6"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit128> <Unit129> <Filename Value="otsu2.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="otsu2"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="13" Y="98"/> <UsageCount Value="107"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit129> <Unit130> <Filename Value="CarbonOpenDoc.pas"/> <UnitName Value="CarbonOpenDoc"/> <WindowIndex Value="0"/> <TopLine Value="33"/> <CursorPos X="42" Y="38"/> <UsageCount Value="7"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit130> <Unit131> <Filename Value="fastsmooth.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="fastsmooth"/> <WindowIndex Value="0"/> <TopLine Value="16"/> <CursorPos X="17" Y="28"/> <UsageCount Value="107"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit131> <Unit132> <Filename Value="common\gzio2.pas"/> <UnitName Value="gzio2"/> <WindowIndex Value="0"/> <TopLine Value="111"/> <CursorPos X="81" Y="119"/> <UsageCount Value="40"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit132> <Unit133> <Filename Value="otsuml.pas"/> <UnitName Value="otsuml"/> <WindowIndex Value="0"/> <TopLine Value="275"/> <CursorPos X="11" Y="15"/> <UsageCount Value="6"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit133> <Unit134> <Filename Value="nii_label.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="nii_label"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="1" Y="34"/> <UsageCount Value="88"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit134> <Unit135> <Filename Value="crop.pas"/> <UnitName Value="crop"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="113" Y="9"/> <UsageCount Value="6"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit135> <Unit136> <Filename Value="..\raycast\gzio2.pas"/> <UnitName Value="gzio2"/> <WindowIndex Value="0"/> <TopLine Value="1175"/> <CursorPos X="1" Y="1180"/> <UsageCount Value="6"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit136> <Unit137> <Filename Value="common\nifti_types.pas"/> <UnitName Value="nifti_types"/> <EditorIndex Value="10"/> <WindowIndex Value="0"/> <TopLine Value="109"/> <CursorPos X="3" Y="118"/> <UsageCount Value="40"/> <Loaded Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit137> <Unit138> <Filename Value="common\nifti_foreign.pas"/> <UnitName Value="nifti_foreign"/> <EditorIndex Value="4"/> <WindowIndex Value="0"/> <TopLine Value="885"/> <CursorPos X="7" Y="886"/> <UsageCount Value="40"/> <Loaded Value="True"/> <DefaultSyntaxHighlighter Value="Delphi"/> </Unit138> <Unit139> <Filename Value="..\..\..\..\..\usr\local\share\fpcsrc\rtl\objpas\sysutils\sysstrh.inc"/> <WindowIndex Value="0"/> <TopLine Value="157"/> <CursorPos X="38" Y="170"/> <UsageCount Value="25"/> </Unit139> <Unit140> <Filename Value="..\..\..\..\..\Developer\lazarus\lcl\interfaces\carbon\carbonobject.inc"/> <WindowIndex Value="0"/> <TopLine Value="668"/> <CursorPos X="42" Y="678"/> <UsageCount Value="25"/> </Unit140> </Units> <JumpHistory Count="30" HistoryIndex="29"> <Position1> <Filename Value="nifti_img_view.pas"/> <Caret Line="4110" Column="31" TopLine="4084"/> </Position1> <Position2> <Filename Value="nifti_img_view.pas"/> <Caret Line="4500" Column="20" TopLine="4475"/> </Position2> <Position3> <Filename Value="nifti_img_view.pas"/> <Caret Line="4670" Column="27" TopLine="4644"/> </Position3> <Position4> <Filename Value="nifti_img_view.pas"/> <Caret Line="4690" Column="20" TopLine="4665"/> </Position4> <Position5> <Filename Value="nifti_img_view.pas"/> <Caret Line="4884" Column="20" TopLine="4858"/> </Position5> <Position6> <Filename Value="nifti_img_view.pas"/> <Caret Line="5051" Column="28" TopLine="5025"/> </Position6> <Position7> <Filename Value="nifti_img_view.pas"/> <Caret Line="240" Column="28" TopLine="225"/> </Position7> <Position8> <Filename Value="nifti_img_view.pas"/> <Caret Line="830" Column="28" TopLine="804"/> </Position8> <Position9> <Filename Value="nifti_img_view.pas"/> <Caret Line="841" Column="37" TopLine="816"/> </Position9> <Position10> <Filename Value="nifti_img_view.pas"/> <Caret Line="1029" Column="28" TopLine="1003"/> </Position10> <Position11> <Filename Value="nifti_img_view.pas"/> <Caret Line="1392" Column="35" TopLine="1384"/> </Position11> <Position12> <Filename Value="nifti_hdr_view.pas"/> <Caret Line="171" Column="31" TopLine="156"/> </Position12> <Position13> <Filename Value="nifti_img_view.pas"/> <Caret Line="1392" Column="35" TopLine="1384"/> </Position13> <Position14> <Filename Value="nifti_img.pas"/> <Caret Line="2" Column="121" TopLine="1"/> </Position14> <Position15> <Filename Value="nifti_img_view.pas"/> <Caret Line="111" Column="31" TopLine="107"/> </Position15> <Position16> <Filename Value="nifti_img_view.pas"/> <Caret Line="3" Column="51" TopLine="1"/> </Position16> <Position17> <Filename Value="nifti_img_view.pas"/> <Caret Line="1638" Column="9" TopLine="1620"/> </Position17> <Position18> <Filename Value="nifti_img_view.pas"/> <Caret Line="3654" Column="56" TopLine="3637"/> </Position18> <Position19> <Filename Value="nifti_img_view.pas"/> <Caret Line="3702" Column="54" TopLine="3680"/> </Position19> <Position20> <Filename Value="nifti_img_view.pas"/> <Caret Line="3750" Column="52" TopLine="3733"/> </Position20> <Position21> <Filename Value="nifti_img_view.pas"/> <Caret Line="1638" Column="9" TopLine="1627"/> </Position21> <Position22> <Filename Value="nifti_img_view.pas"/> <Caret Line="3654" Column="56" TopLine="3636"/> </Position22> <Position23> <Filename Value="nifti_img_view.pas"/> <Caret Line="3702" Column="54" TopLine="3685"/> </Position23> <Position24> <Filename Value="nifti_img_view.pas"/> <Caret Line="3750" Column="52" TopLine="3733"/> </Position24> <Position25> <Filename Value="nifti_img_view.pas"/> <Caret Line="33" Column="44" TopLine="30"/> </Position25> <Position26> <Filename Value="nifti_img_view.pas"/> <Caret Line="1395" Column="50" TopLine="1385"/> </Position26> <Position27> <Filename Value="nifti_img_view.pas"/> <Caret Line="1398" Column="47" TopLine="1385"/> </Position27> <Position28> <Filename Value="nifti_img_view.pas"/> <Caret Line="1402" Column="57" TopLine="1385"/> </Position28> <Position29> <Filename Value="nifti_img_view.pas"/> <Caret Line="1720" Column="50" TopLine="1703"/> </Position29> <Position30> <Filename Value="nifti_img_view.pas"/> <Caret Line="2512" Column="50" TopLine="2494"/> </Position30> </JumpHistory> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="mricron"/> </Target> <SearchPaths> <Libraries Value="rgb;fpmath"/> <OtherUnitFiles Value="rgb;fpmath;common"/> </SearchPaths> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="2"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> <UseLineInfoUnit Value="False"/> <StripSymbols Value="True"/> </Debugging> <LinkSmart Value="True"/> <Options> <Win32> <GraphicApplication Value="True"/> </Win32> </Options> </Linking> <Other> <WriteFPCLogo Value="False"/> <CompilerMessages> <UseMsgFile Value="True"/> </CompilerMessages> <CompilerPath Value="$(CompPath)"/> </Other> </CompilerOptions> <Debugging> <Exceptions Count="2"> <Item1> <Name Value="ECodetoolError"/> </Item1> <Item2> <Name Value="EFOpenError"/> </Item2> </Exceptions> </Debugging> <EditorMacros Count="0"/> </CONFIG> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_delphi.bat��������������������������������������������������������0000755�0001750�0001750�00000001512�11775405542�016310� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������del c:\mricron\*.ini call _clean.bat copy /Y .\common\notgui.inc .\common\isgui.inc cd .\dcm2nii C:\PROGRA~2\BORLAND\DELPHI7\BIN\dcc32 -CC -B dcm2nii.dpr c:\strip dcm2nii.exe copy /Y dcm2nii.exe c:\mricron cd .. call _clean.bat copy /Y .\common\gui.inc .\common\isgui.inc cd .\npm C:\PROGRA~2\BORLAND\DELPHI7\BIN\dcc32 -U..\delphionly -B npm.dpr c:\strip npm.exe copy /Y npm.exe c:\mricron cd .. cd .\dcm2nii C:\PROGRA~2\BORLAND\DELPHI7\BIN\dcc32 -U..\delphionly;C:\pas\d7\rx275d7\Units -B dcm2niigui.dpr c:\strip dcm2niigui.exe copy /Y dcm2niigui.exe c:\mricron cd .. call _clean.bat cd c:\pas\delphi\niftiview7 C:\PROGRA~2\BORLAND\DELPHI7\BIN\dcc32 -UC:\pas\d7\rx275d7\Units;C:\PROGRA~2\PngComponents\Source -B mricron.dpr c:\strip c:\pas\delphi\niftiview7\mricron.exe copy /Y c:\pas\delphi\niftiview7\mricron.exe c:\mricron\ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/mni.lfm������������������������������������������������������������0000755�0001750�0001750�00000002022�11551145664�015472� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object MNIForm: TMNIForm Left = 444 Height = 32 Top = 300 Width = 264 HorzScrollBar.Page = 263 VertScrollBar.Page = 53 ActiveControl = XEdit BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'MNI position' ClientHeight = 32 ClientWidth = 264 Constraints.MaxHeight = 32 Constraints.MaxWidth = 264 Constraints.MinHeight = 32 Constraints.MinWidth = 264 OnCreate = FormCreate Position = poScreenCenter LCLVersion = '0.9.29' object XEdit: TSpinEdit Left = 16 Height = 21 Top = 4 Width = 66 MaxValue = 200 MinValue = -200 OnChange = XEditChange TabOrder = 0 end object YEdit: TSpinEdit Left = 96 Height = 21 Top = 4 Width = 66 MaxValue = 200 MinValue = -200 OnChange = XEditChange TabOrder = 1 end object ZEdit: TSpinEdit Left = 176 Height = 21 Top = 4 Width = 66 MaxValue = 200 MinValue = -200 OnChange = XEditChange TabOrder = 2 end end ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/render.pas���������������������������������������������������������0000755�0001750�0001750�00000067752�12370506225�016212� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit render; interface {$include isthreaded.inc} {$mode delphi} uses {$IFDEF Unix} lclintf, //gettickcount {$ELSE} Windows, {$ENDIF} {$IFNDEF NoThreads} RenderThds, {$ELSE} rendernothreads, {$ENDIF} LResources,SysUtils, GraphicsMathLibrary,Classes, Graphics, Controls, Forms, Dialogs,ExtCtrls,Buttons, nifti_img, nifti_hdr,define_types,nifti_img_view,StdCtrls, Spin, Menus,ClipBrd,ReadInt,IniFiles, ComCtrls,userdir,render_composite; type { TRenderForm } TRenderForm = class(TForm) CutoutMenu: TMenuItem; ClipTrack: TTrackBar; MenuItem1: TMenuItem; SaveClipMenu: TMenuItem; MIPItem: TMenuItem; ShadeEdit: TSpinEdit; Label5: TLabel; RotationBMPMenu: TMenuItem; RenderBar: TPanel; AzimuthEdit: TSpinEdit; ElevationEdit: TSpinEdit; MainMenu1: TMainMenu; FileMenu: TMenuItem; Close1: TMenuItem; Edit1: TMenuItem; Copy1: TMenuItem; Save1: TMenuItem; Label4: TLabel; RefreshBtn: TSpeedButton; BiasTrack: TTrackBar; GainTrack: TTrackBar; Volume1: TMenuItem; RenderBGSurfaceMenu: TMenuItem; N1: TMenuItem; N101: TMenuItem; N401: TMenuItem; N601: TMenuItem; N801: TMenuItem; N403: TMenuItem; N404: TMenuItem; N405: TMenuItem; RenderBGDepthMenu: TMenuItem; N1voxel1: TMenuItem; N2voxels1: TMenuItem; N4voxels1: TMenuItem; N8voxels1: TMenuItem; N16voxels1: TMenuItem; N16voxels: TMenuItem; RenderSmoothBG: TMenuItem; RenderPreciseInterpolation: TMenuItem; Label1: TLabel; Overlay1: TMenuItem; RenderOverlaySurfaceMenu: TMenuItem; N701: TMenuItem; N602: TMenuItem; N501: TMenuItem; N402: TMenuItem; N301: TMenuItem; N201: TMenuItem; N102: TMenuItem; N01: TMenuItem; RenderOverlayDepthMenu: TMenuItem; N16voxels2: TMenuItem; N12voxels1: TMenuItem; N8voxels2: TMenuItem; N4voxels2: TMenuItem; N2voxels2: TMenuItem; N1voxel2: TMenuItem; Quality1: TMenuItem; RenderRefreshTimer: TTimer; RenderPanel: TScrollBox; RenderImage: TImage; RenderImageBUP: TImage; //RenderImage2: TImage; RenderSmoothOverlay: TMenuItem; FlipLRcheck: TMenuItem; Settings1: TMenuItem; Savesettings1: TMenuItem; N2: TMenuItem; Infinite1: TMenuItem; Infinite2: TMenuItem; Search1: TMenuItem; BehindBG1: TMenuItem; Infront1: TMenuItem; Anydepth1: TMenuItem; procedure BiasTrackChange(Sender: TObject); procedure ClipTrackChange(Sender: TObject); procedure RenderSmoothBGClick(Sender: TObject); procedure RotationBMPMenuClick(Sender: TObject); procedure SaveClipMenuClick(Sender: TObject); procedure Settings1Click(Sender: TObject); procedure SetSearch(Sender: TObject); procedure Save1Click(Sender: TObject); procedure RenderImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure Copy1Click(Sender: TObject); procedure Close1Click(Sender: TObject); procedure N1Click(Sender: TObject); procedure N01Click(Sender: TObject); procedure N1voxel1Click(Sender: TObject); procedure N16voxels2Click(Sender: TObject); procedure RenderSmoothClick(Sender: TObject); procedure RenderPreciseInterpolationClick(Sender: TObject); procedure FormShow(Sender: TObject); procedure RenderRefreshTimerTimer(Sender: TObject); procedure EditChange(Sender: TObject); procedure OverlayRenderDepthItem(Sender: TObject); procedure RenderImageMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Cutout1Click(Sender: TObject); procedure Savesettings1Click(Sender: TObject); procedure UpdateRenderMRU; procedure OpenRenderMRU(Sender:TObject); procedure UpdateRenderDisplay; procedure FormHide(Sender: TObject); procedure FormCreate(Sender: TObject); procedure RefreshClick(Sender: TObject); procedure RefreshRotation; private { Private declarations } public { Public declarations } end; var RenderForm: TRenderForm; gZoom : single = 1; gRenderDir,gRenderStartupFilename,gRenderDefaultsFilename:string; implementation uses MultiSlice,math,cutout; {$IFNDEF FPC} {$R *.DFM} {$ENDIF} procedure MinMaxFilt (var lHdr: TMRIcroHdr; var lFiltMin8bit, lFiltMax8bit: integer);var lMin,lMax: single; begin ReturnMinMax (lHdr,lMin,lMax, lFiltMin8bit, lFiltMax8bit); end; procedure TRenderForm.UpdateRenderDisplay; begin SetSubmenuWithTag(RenderBGSurfaceMenu,gRender.BGSurface); SetSubmenuWithTag(RenderOverlaySurfaceMenu,gRender.OverlaySurface); SetSubmenuWithTag(RenderBGDepthMenu,gRender.BGDepth); SetSubmenuWithTag(RenderOverlayDepthMenu,gRender.OverlayDepth); RenderSmoothBG.checked := gRender.SmoothBG; RenderSmoothOverlay.checked := gRender.SmoothOverlay; RenderPreciseInterpolation.Checked := gRender.Trilinear; //RenderSurfaceOverlay.Checked := gRender.OverlayFromBGSurface; SetSubmenuWithTag(Search1,gRender.OverlayFromBGSurface); FlipLRCheck.Checked := gRender.FlipLR; AzimuthEdit.value := gRender.Azimuth; ElevationEdit.value := gRender.Elevation; ShadeEdit.value := gRender.ShadePct; RenderRefreshTimer.tag := -1; RenderRefreshTimer.enabled := true; end; procedure WriteRenderIniFile (lFilename: string); var lIniFile: TIniFile; lInc: integer; begin if DiskFreeEx(lFilename) < 1 then exit; if not DirectoryExists(extractfiledir(lFilename)) then begin mkDir(extractfiledir(lFilename)); end; lIniFile := TIniFile.Create(lFilename); with gRender do begin lIniFile.WriteString('BOOL', 'SmoothBG',Bool2Char( SmoothBG)); lIniFile.WriteString('BOOL', 'SmoothOverlay',Bool2Char( SmoothOverlay)); lIniFile.WriteString('BOOL', 'Trilinear',Bool2Char( Trilinear)); lIniFile.WriteString('BOOL', 'ShowCutout',Bool2Char( ShowCutout)); lIniFile.WriteString('BOOL', 'FlipLR',Bool2Char( FlipLR)); lIniFile.WriteString('INT', 'OverlayFromBGSurface',IntToStr( OverlayFromBGSurface)); //lIniFile.WriteString('INT', 'BGNearClip',IntToStr(BGNearClip)); //lIniFile.WriteString('INT', 'OverlayNearClip',IntToStr(OverlayNearClip)); lIniFile.WriteString('INT', 'Azimuth',IntToStr(Azimuth)); lIniFile.WriteString('INT', 'Elevation',IntToStr(Elevation)); lIniFile.WriteString('INT', 'BGSurface',IntToStr(BGSurface)); lIniFile.WriteString('INT', 'OverlaySurface',IntToStr(OverlaySurface)); lIniFile.WriteString('INT', 'BGDepth',IntToStr(BGDepth)); lIniFile.WriteString('INT', 'OverlayDepth',IntToStr(OverlayDepth)); lIniFile.WriteString('INT', 'CutoutBias',IntToStr(CutoutBias)); lIniFile.WriteString('INT', 'cutoutLUTindex',IntToStr(cutoutLUTindex)); lIniFile.WriteString('INT', 'ShadePct',IntToStr(ShadePct)); for lInc := 1 to 3 do begin lIniFile.WriteString('INT', 'CutoutLoFrac'+inttostr(lInc),IntToStr(CutoutFrac.Lo[lInc])); lIniFile.WriteString('INT', 'CutoutHiFrac'+inttostr(lInc),IntToStr(CutoutFrac.Hi[lInc])); end; end;//with gRender lIniFile.Free; end; procedure ReadRenderIniFile (lFilename: string); var lIniFile: TIniFile; //lStr: string; lInc: integer; begin if not FileexistsEx(lFilename) then begin exit; end; lIniFile := TIniFile.Create(lFilename); //lStr := lIniFile.ReadString('STR', 'Slices', '10,20,30');//file0 - last file viewed with gRender do begin //Booleans //SmoothBG,SmoothOverlay,Trilinear,OverlayFromBGSurface,ShowCutout SmoothBG := IniBool(lIniFile,'SmoothBG',SmoothBG); SmoothOverlay := IniBool(lIniFile,'SmoothOverlay',SmoothOverlay); Trilinear := IniBool(lIniFile,'Trilinear',Trilinear); //OverlayFromBGSurface := IniBool(lIniFile,'OverlayFromBGSurface',OverlayFromBGSurface); ShowCutout := IniBool(lIniFile,'ShowCutout',ShowCutout); FlipLR := IniBool(lIniFile,'FlipLR',FlipLR); OverlayFromBGSurface:= IniInt(lIniFile,'OverlayFromBGSurface',OverlayFromBGSurface); //BGNearClip:= IniInt(lIniFile,'BGNearClip',BGNearClip); //OverlayNearClip:= IniInt(lIniFile,'OverlayNearClip',OverlayNearClip); Azimuth:= IniInt(lIniFile,'Azimuth',Azimuth); Elevation:= IniInt(lIniFile,'Elevation',Elevation); BGSurface:= IniInt(lIniFile,'BGSurface',BGSurface); OverlaySurface:= IniInt(lIniFile,'OverlaySurface',OverlaySurface); BGDepth:= IniInt(lIniFile,'BGDepth',BGDepth); OverlayDepth:= IniInt(lIniFile,'OverlayDepth',OverlayDepth); CutoutBias:= IniInt(lIniFile,'CutoutBias', CutoutBias); ShadePct:= IniInt(lIniFile,'ShadePct', 0); cutoutLUTindex:= IniInt(lIniFile,'cutoutLUTindex',cutoutLUTindex); for lInc := 1 to 3 do begin Cutout.Lo[lInc] := IniInt(lIniFile,'CutoutLo'+inttostr(lInc),Cutout.Lo[lInc]); Cutout.Hi[lInc] := IniInt(lIniFile,'CutoutHi'+inttostr(lInc),Cutout.Hi[lInc]); end; for lInc := 1 to 3 do begin CutoutFrac.Lo[lInc] := IniInt(lIniFile,'CutoutLoFrac'+inttostr(lInc),-1); CutoutFrac.Hi[lInc] := IniInt(lIniFile,'CutoutHiFrac'+inttostr(lInc),-1); end; end;//with gRender lIniFile.Free; end; procedure TRenderForm.OpenRenderMRU(Sender:TObject); var lFilename: string; begin lFilename := gRenderDir+(Sender as TMenuItem).caption+'.ini' ; ReadRenderIniFile(lFilename); //07 CutoutForm.Prep; UpdateRenderDisplay; end; procedure TRenderForm.UpdateRenderMRU; var NewItem: TMenuItem; lSearchRec: TSearchRec; begin While Settings1.Count > 0 do Settings1.Items[0].Free; if FindFirst(gRenderDir+'*.ini', faAnyFile, lSearchRec) = 0 then repeat NewItem := TMenuItem.Create(Self); NewItem.Caption := ParseFileName(ExtractFileName(lSearchRec.Name)); {$IFDEF FPC} NewItem.onclick := OpenRenderMRU; //Lazarus {$ELSE} NewItem.onclick := OpenRenderMRU; {$ENDIF} Settings1.Add(NewItem); until (FindNext(lSearchRec) <> 0); FindClose(lSearchRec); end; Function AziElevMatrix: TMatrix; var lLRFlipMatrix: TMatrix; begin gRender.Azimuth := RenderForm.AzimuthEdit.value; gRender.Elevation := RenderForm.ElevationEdit.value; result := ViewTransformMatrix( coordSpherical, ToRadians(RenderForm.AzimuthEdit.Value), ToRadians(RenderForm.ElevationEdit.Value), 3{Distance.Value},6{ScreenWidthHeight.Value},6{ScreenWidthHeight.Value},{ScreenToCamera.Value}3); {The ViewTransformMatrix is all that is needed for other objects defined in world coordinates.} if {RenderForm.FlipLRcheck.checked} gRender.FlipLR then begin lLRFlipMatrix := Matrix3D (-1,0,0,0, // 3D "graphics" matrix 0,1,0,0, 0,0,1,0, 0,0,0,0); result := MultiplyMatrices(lLRFlipMatrix,Result); end; end; procedure InvertMatrixPoint (var lBackgroundImg: TBGImg; var lInMatrix: TMatrix; var lXin,lYin,lZIn, lXout,lYout,lZout: integer); //convert mouse click to position var lZ,lY,lX,lOutDim,lOutPivot,lXPivotIn,lYPivotIn,lZPivotIn: integer; lMatrix: TMatrix; begin //lOutDim := gBGImg.RenderDim;//MaxDim(lBackgroundImg.ScrnDim[1],lBackgroundImg.ScrnDim[2],lBackgroundImg.ScrnDim[3]); if gRender.Zoom > 0 then lOutDim := round(gBGImg.RenderDim/gRender.Zoom) else lOutDim :=gBGImg.RenderDim; //11/2007b lOutPivot := (lOutDim+1) shr 1; //e.g. if DimMax=9, then pivot is 5 lXPivotIn := (lBackgroundImg.ScrnDim[1]+1) shr 1; //e.g. if DimMax=9, then pivot is 5 lYPivotIn := (lBackgroundImg.ScrnDim[2]+1) shr 1; //e.g. if DimMax=9, then pivot is 5 lZPivotIn := (lBackgroundImg.ScrnDim[3]+1) shr 1; //e.g. if DimMax=9, then pivot is 5 lX := (lXin-lOutPivot); lY := ({lYin-}lOutPivot-lYin); lZ := (lZin-lOutPivot); lMatrix := InvertMatrix3D(lInMatrix); lXout := round( (lX*lMatrix.matrix[1,1])+(lY * lMatrix.matrix[2,1])+(lZ*lMatrix.matrix[3,1])); lYout := round( (lX*(lMatrix.matrix[1,2]))+(lY * lMatrix.matrix[2,2])+(lZ*lMatrix.matrix[3,2])); lZout := round( (lX*(lMatrix.matrix[1,3]))+(lY * lMatrix.matrix[2,3])+(lZ*lMatrix.matrix[3,3])); lXOut := (lXOut+lXPivotIn); lYOut := (lYOut+lYPivotIn); lZOut := (lZOut+lZPivotIn); end; procedure TRenderForm.Save1Click(Sender: TObject); //this code is required for OSX Lazarus, not sure about Windows/Delphi var lOutImg: TImage; begin lOutImg := TImage.Create(ImgForm); lOutImg.Width := RenderImage.Width; lOutImg.Height := RenderImage.Height; lOutImg.Canvas.Draw(0,0,RenderImage.Picture.Graphic); SaveImgAsPNGBMP (lOutImg); FreeAndNil (lOutImg); end; (*procedure TRenderForm.Save1Click(Sender: TObject); begin //if (RenderImage.Picture.Graphic = nil) then begin SaveImgAsPNGBMP (RenderImage); ///xxxx end;*) procedure TRenderForm.RenderImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin end; procedure TRenderForm.Copy1Click(Sender: TObject); {$IFDEF FPC} var lOutImg: TImage; begin lOutImg := TImage.Create(ImgForm); lOutImg.Width := RenderImage.Width; lOutImg.Height := RenderImage.Height; lOutImg.Canvas.Draw(0,0,RenderImage.Picture.Graphic); lOutImg.Picture.Bitmap.SaveToClipboardFormat(2); Clipboard.Assign(lOutImg.Picture.Graphic); FreeAndNil (lOutImg); end; (*begin {$IFDEF zxDarwin} Showmessage('Copy not yet supported with OSX: use File/Save'); exit; {$ENDIF} if (RenderImage.Picture.Graphic = nil) then begin //1420z Showmessage('You need to load an image before you can copy it to the clipboard.'); exit; end; RenderImage.Picture.Bitmap.SaveToClipboardFormat(2); end;*) {$ELSE} var MyFormat : Word; AData: THandle; APalette : HPalette; //For later versions of Delphi: APalette : THandle; begin if (RenderImage.Picture.Graphic = nil) then begin //1420z Showmessage('You need to load an image before you can copy it to the clipboard.'); exit; end; RenderImage.Picture.Bitmap.SaveToClipBoardFormat(MyFormat,AData,APalette); ClipBoard.SetAsHandle(MyFormat,AData); end; {$ENDIF} procedure TRenderForm.RotationBMPMenuClick(Sender: TObject); var lnViews,lC,lAngle,lStartA: integer; lZoom,lAzi: boolean; lBaseFilename,lFilename: string; begin lnViews:= ReadIntForm.GetInt('How many bitmaps for a 360-degree rotation?', 4,24,72); {$IFDEF ENDIAN_BIG} ImgForm.SaveDialog1.Filter := 'Bitmap|*.xpm'; ImgForm.SaveDialog1.DefaultExt := '.xpm'; {$ELSE} ImgForm.SaveDialog1.Filter := 'Bitmap|*.bmp'; ImgForm.SaveDialog1.DefaultExt := '.bmp'; {$ENDIF} if not ImgForm.SaveDialog1.Execute then exit; lBaseFilename := ImgForm.SaveDialog1.Filename; lAzi := false; case MessageDlg('Rotate azimuth?', mtConfirmation, [mbYes, mbNo], 0) of mrYes: lAzi := true; end; //case case MessageDlg('Generate super-sampled (high quality) renderings?', mtConfirmation, [mbYes, mbNo], 0) of mrYes: lZoom := true; end; //case if lAzi then lStartA := AzimuthEdit.value else lStartA := ElevationEdit.value; for lC := 1 to lnViews do begin lAngle := round((lC-1) * (360/lnviews)); if lAzi then AzimuthEdit.value := lAngle else ElevationEdit.value := lAngle - 180; RenderRefreshTimer.enabled := false; if lZoom then gZoom := 2; RefreshRotation; DrawRender; {$IFDEF ENDIAN_BIG} lFilename := ChangeFilePostfixExt (lBaseFilename,PadStr(lAngle,3),'.xpm'); {$ELSE} lFilename := ChangeFilePostfixExt (lBaseFilename,PadStr(lAngle,3),'.bmp'); {$ENDIF} RenderImage.Picture.Bitmap.SaveToFile(lFilename); //SaveImgAsPNGBMPCore(RenderImage,lFilename); end; //for each of 36 views if lAzi then AzimuthEdit.value := lStartA else ElevationEdit.value := lStartA; RenderRefreshTimer.enabled := false; RefreshRotation; DrawRender; end; procedure TRenderForm.SaveClipMenuClick(Sender: TObject); var lStartClip,lnClips,lC: integer; lBaseFilename,lFilename: string; lStartTime: DWord; begin lStartClip := gRender.ClipFrac; lnClips:= ReadIntForm.GetInt('How many bitmaps for a 360-degree rotation?', 4,24,200); ImgForm.SaveDialog1.Filter := 'PNG bitmap|*.png'; ImgForm.SaveDialog1.DefaultExt := '*.png'; if not ImgForm.SaveDialog1.Execute then exit; lBaseFilename := ImgForm.SaveDialog1.Filename; lStartTime := GetTickCount; for lC := 1 to lnClips do begin gRender.ClipFrac := round( ((lC-1)/lnClips)*kMaxFrac ); DrawRender; refresh; {$IFDEF ENDIAN_BIG} lFilename := ChangeFilePostfixExt (lBaseFilename,PadStr(lC,3),'.xpm'); {$ELSE} lFilename := ChangeFilePostfixExt (lBaseFilename,PadStr(lC,3),'.bmp'); {$ENDIF} RenderImage.Picture.Bitmap.SaveToFile(lFilename); //SaveImgAsPNGBMPCore(RenderImage,lFilename); end; //for each of 36 views ImgForm.StatusLabel.caption :=('batchtime(ms): '+inttostr(GetTickCount-lStartTime)); gRender.ClipFrac := lStartClip; end; procedure TRenderForm.Settings1Click(Sender: TObject); begin end; procedure TRenderForm.BiasTrackChange(Sender: TObject); begin gRender.Bias := BiasTrack.position; gRender.Gain := GainTrack.Position; RenderRefreshTimer.Enabled := true; //RenderForm.caption := inttostr(BiasTrack.position)+'zzz'+inttostr(GainTrack.Position); end; procedure TRenderForm.ClipTrackChange(Sender: TObject); begin gRender.ClipFrac := ClipTrack.Position; RenderRefreshTimer.Enabled := true; end; procedure TRenderForm.RenderSmoothBGClick(Sender: TObject); begin (sender as TMenuItem).checked := not (sender as TMenuItem).checked; gRender.SmoothBG := RenderSmoothBG.checked; gRender.SmoothOverlay := RenderSmoothOverlay.checked; RenderRefreshTimer.Enabled := true; end; procedure TRenderForm.Close1Click(Sender: TObject); begin RenderForm.Close; end; procedure TRenderForm.N1Click(Sender: TObject); begin (sender as TMenuItem).checked := true; gRender.BGSurface := (sender as TMenuItem).tag; RenderRefreshTimer.Enabled := true; end; procedure TRenderForm.N01Click(Sender: TObject); begin (sender as TMenuItem).checked := true; gRender.OverlaySurface := (sender as TMenuItem).tag; RenderRefreshTimer.Enabled := true; end; procedure TRenderForm.N1voxel1Click(Sender: TObject); begin (sender as TMenuItem).checked := true; gRender.BGDepth := (sender as TMenuItem).tag; RenderRefreshTimer.Enabled := true; end; procedure TRenderForm.N16voxels2Click(Sender: TObject); begin (sender as TMenuItem).checked := true; gRender.OverlayDepth := (sender as TMenuItem).tag; RenderRefreshTimer.Enabled := true; end; procedure TRenderForm.RenderSmoothClick(Sender: TObject); begin (sender as TMenuItem).checked := not (sender as TMenuItem).checked; gRender.FlipLR := FlipLRCheck.Checked; //RenderSmoothSurface.checked := not RenderSmoothSurface.Checked; gRender.SmoothBG := RenderSmoothBG.checked; gRender.SmoothOverlay := RenderSmoothOverlay.checked; RenderRefreshTimer.Tag := -1;//force a new rotation matrix to be generated RenderRefreshTimer.Enabled := true; end; procedure TRenderForm.RenderPreciseInterpolationClick(Sender: TObject); begin RenderPreciseInterpolation.Checked := not RenderPreciseInterpolation.Checked; gRender.Trilinear := RenderPreciseInterpolation.Checked; RenderRefreshTimer.Tag := -1; //force a new rotation matrix to be generated RenderRefreshTimer.Enabled := true; end; procedure TRenderForm.FormShow(Sender: TObject); var lInc: integer; begin gRender.ClipFrac := 0; gRender.Bias := 50; gRender.Gain := 50; gRender.cutoutLUTindex := 0; gRender.BGSurface := 51; gRender.OverlaySurface := 1; gRender.BGDepth := 12; gRender.OverlayDepth := 8; gRender.Azimuth := 90; gRender.Elevation := 45; gRender.ShadePct := 0; //gRender.OverlayNearClip := 0; //gRender.BGNearClip := 0; gRender.SmoothBG := true; gRender.SmoothOverlay := false; gRender.Trilinear := true; gRender.FlipLR := false; gRender.OverlayFromBGSurface := kBelow; gRender.ShowCutout := false; gRender.CutoutBias := 4; {for lInc := 1 to 3 do begin gRender.Cutout.Lo[lInc] := gBGImg.ScrnDim[lInc] div 2; gRender.Cutout.Hi[lInc] := gBGImg.ScrnDim[lInc]; end;} for lInc := 1 to 3 do begin gRender.CutoutFrac.Lo[lInc] := kMaxFrac div 2; gRender.CutoutFrac.Hi[lInc] := kMaxFrac; end; ReadRenderIniFile (gRenderStartupFilename); UpdateRenderMRU; UpdateRenderDisplay; RenderForm.BringToFront; end; function RAMok (var lBGImg: TBGImg): boolean; var lOutDim,lOutBytes,lBytesNeeded,lFreeRam: int64; lBGSz,lC: integer; begin lBGSz := lBGImg.ScrnDim[1]*lBGImg.ScrnDim[2]*lBGImg.ScrnDim[3]; lOutDim := round(MaxDim(lBGImg.ScrnDim[1],lBGImg.ScrnDim[2],lBGImg.ScrnDim[3]) * gRender.Zoom); lOutBytes := lOutDim*lOutDim*lOutDim; lBytesNeeded := 0; for lC := 0 to knMaxOverlay do begin if (gMRIcroOverlay[lC].ScrnBufferItems >= lBGSz) then begin lBytesNeeded := lBytesNeeded + (lOutBytes - gMRIcroOverlay[lC].RenderBufferItems); end; end; if (lBytesNeeded > freeRam) then begin beep; ImgForm.StatusLabel.Caption := 'Memory exhausted: unable to render at this quality'; result := false; end else result := true; end; procedure TRenderForm.RefreshRotation; var lC: integer; lMatrix: TMatrix; lStartTime: DWord; begin lMatrix := AziElevMatrix; {$IFNDEF FPC} //refresh causes flicker with lazarus Application.processmessages; Refresh; {$ENDIF} gRender.Zoom := gZoom; //11/2007b gZoom := 1; gRender.ClipFrac := ClipTrack.position; gRender.Bias := BiasTrack.position; gRender.Gain := GainTrack.Position; gRender.Azimuth := round(AzimuthEdit.value); gRender.Elevation := round(ElevationEdit.value); if not RAMok(gBGImg) then exit; lStartTime := GetTickCount; VolumeRotateMatrix (gBGImg, gMRIcroOverlay[0],lMatrix, gRender.Trilinear,gRender.ShowCutout,true{,round(gRender.BGNearClip*gRender.Zoom)}); for lC := 1 to knMaxOverlay do VolumeRotateMatrix (gBGImg, gMRIcroOverlay[lC],lMatrix, gRender.Trilinear,false,false{,round(gRender.OverlayNearClip*gRender.Zoom)}); end; var gRendering: boolean = false; procedure TRenderForm.RenderRefreshTimerTimer(Sender: TObject); begin if gMRIcroOverlay[0].ScrnBufferItems=0 then begin RenderRefreshTimer.Enabled := false; RenderImage.Width := 0; exit; end; if gRendering then exit; RenderRefreshTimer.Enabled := false; gRender.ShadePct := ShadeEdit.value; gRendering := true; if (gMRIcroOverlay[0].RenderBufferItems=0) or (RenderRefreshTimer.Tag <> 0) or (AzimuthEdit.value<>gRender.Azimuth) or (ElevationEdit.value<>gRender.Elevation) then RefreshRotation; //RenderRefreshTimer.Enabled := false; (*if RenderRefreshTimer.Enabled then begin gRendering := false; exit; end; *) RenderRefreshTimer.Tag := 0; DrawRender; //RenderRefreshTimer.Enabled := false; gRendering := false; end; procedure TRenderForm.EditChange(Sender: TObject); begin RenderRefreshTimer.Enabled := true; end; procedure TRenderForm.OverlayRenderDepthItem(Sender: TObject); begin (sender as TMenuItem).checked := true; gRender.OverlayDepth := (sender as TMenuItem).tag; RenderRefreshTimer.Enabled := true; end; procedure RenderDrawXBar ( lHorPos, lVerPos: integer;var lImage: TImage); var lL,lT,lW,lH,lZoomPct: integer; begin lImage.Picture.Graphic := RenderForm.RenderImageBUP.Picture.Graphic; {$IFNDEF Darwin} xxxx make sure next line required on this OS! {$ENDIF} lImage.Canvas.Draw(0,0,RenderForm.RenderImageBUP.Picture.Graphic); //lImage.Picture.Bitmap := RenderForm.RenderImageBUP.Picture.Bitmap; //xxxx //redraw image even if not drawing X-bar: hide visible X-bar if use toggles X-bars off. if not ImgForm.XBarBtn.Down then exit; //only draw xbars if requested //lImage.Refresh; lZoomPct := 100; //ImageZoomPct(lImage); lL := (lHorPos * lZoomPct) div 100; lT := (lVerPos * lZoomPct) div 100; lW := lImage.Width;// div 100; lH := lImage.Height;// div 100; lImage.Canvas.Pen.Color:= gBGImg.XBarClr; lImage.Canvas.Pen.Width := gBGImg.XBarThick; //next horizontal lines lImage.Canvas.MoveTo(0,lT); lImage.Canvas.LineTo(lL-gBGImg.XBarGap,lT); lImage.Canvas.MoveTo(lL+gBGImg.XBarGap,lT); lImage.Canvas.LineTo(lW,lT); //next vertical lines lImage.Canvas.MoveTo(lL,0); lImage.Canvas.LineTo(lL,lT-gBGImg.XBarGap); lImage.Canvas.MoveTo(lL,lT+gBGImg.XBarGap); lImage.Canvas.LineTo(lL,lH); end; //Proc RenderDrawXBar procedure TRenderForm.RenderImageMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var lXrender,lYrender,lZrender,lXout,lYout,lZOut,lPixelOffset,lZoom: integer; lMatrix: TMatrix; begin RenderDrawXBar ( X,Y,RenderImage); //Next: find coordinates for orthogonal views: lZoom := ImageZoomPct(RenderImage); lXrender := round((X*100) / lZoom ); lYrender := round(((Y)*100) / lZoom ); lPixelOffset := lXrender+ ((gBGImg.RenderDim-lYrender)*gBGImg.RenderDim); //ImgForm.StatusLabel.caption := inttostr(lXrender)+'x'+inttostr(lYrender)+' -> '+inttostr(gMRIcroOverlay[kBGOverlayNum].RenderDepthBufferItems ); if (lPixelOffset < 1) or (lPixelOffset >gBGImg.RenderDepthBufferItems ) then exit; lZrender := gBGImg.RenderDepthBuffer^[lPixelOffset]; lXrender := round(lXrender / gRender.Zoom); lYrender := round(lYrender / gRender.Zoom); lZrender := round(lZrender / gRender.Zoom); lMatrix := AziElevMatrix; InvertMatrixPoint (gBGImg,lMatrix,lXrender,lYrender,lZrender, lXout,lYout,lZOut); ImgForm.XViewEdit.value := lXOut; ImgForm.YViewEdit.value := lYOut; ImgForm.ZViewEdit.value := lZOut; {$IFDEF FPC} ImgForm.XViewEditChange(nil); {$ENDIF} end; procedure TRenderForm.Cutout1Click(Sender: TObject); begin CutoutForm.Show; end; procedure TRenderForm.Savesettings1Click(Sender: TObject); begin //showmessage(gRenderDir+' '+extractfiledir(gRenderDir)); MultiSliceForm.MultiSaveDialog.InitialDir := extractfiledir(gRenderDir); MultiSliceForm.MultiSaveDialog.FileName := 'a'+inttostr(gRender.Azimuth)+'e'+inttostr(gRender.Elevation); if not MultiSliceForm.MultiSaveDialog.Execute then exit; {$IFDEF Unix} WriteRenderIniFile(extractfiledir(gRenderDir)+pathdelim+extractfilename(MultiSliceForm.MultiSaveDialog.Filename)); {$ELSE} WriteRenderIniFile(MultiSliceForm.MultiSaveDialog.Filename); {$ENDIF} UpdateRenderMRU; end; procedure TRenderForm.FormHide(Sender: TObject); begin WriteRenderIniFile (gRenderDefaultsFilename); //not sure how to make this safe for currently rendering threads... if gBGImg.RenderDepthBufferItems > 0 then Freemem(gBGImg.RenderDepthBuffer); gBGImg.RenderDepthBufferItems := 0; end; procedure TRenderForm.FormCreate(Sender: TObject); begin {$IFDEF Darwin} Save1.ShortCut := ShortCut(Word('S'), [ssMeta]); Close1.ShortCut := ShortCut(Word('W'), [ssMeta]); {$ENDIF} gRenderDir := DefaultsDir('render'); //showmessage(gRenderDir); //gRenderDir := extractfiledir(paramstr(0))+pathdelim+'render'+pathdelim; gRenderDefaultsFilename := gRenderDir + 'default.ini'; gRenderStartupFilename := gRenderDefaultsFilename; RenderForm.DoubleBuffered := true; end; procedure TRenderForm.RefreshClick(Sender: TObject); begin gZoom := 2; RenderForm.RenderRefreshTimer.Tag := -1; //force a new rotation matrix to be generated RenderForm.RenderRefreshTimer.enabled := true; end; procedure TRenderForm.SetSearch(Sender: TObject); begin (sender as TMenuItem).checked := true; gRender.OverlayFromBGSurface := (sender as TMenuItem).tag; RenderRefreshTimer.Enabled := true; end; {$IFDEF FPC} initialization {$I render.lrs} {$ENDIF} end. ����������������������mricron-0.20140804.1~dfsg.1.orig/autoroi.lfm��������������������������������������������������������0000755�0001750�0001750�00000006521�11540216612�016367� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object AutoROIForm: TAutoROIForm Left = 785 Height = 355 Top = 200 Width = 265 HorzScrollBar.Page = 264 VertScrollBar.Page = 354 ActiveControl = VarianceEdit Caption = 'Create ROI' ClientHeight = 355 ClientWidth = 265 Constraints.MaxHeight = 355 Constraints.MaxWidth = 265 Constraints.MinHeight = 355 Constraints.MinWidth = 265 Font.Name = 'MS Sans Serif' OnCreate = FormCreate OnDestroy = FormDestroy OnHide = FormHide OnShow = FormShow Position = poScreenCenter LCLVersion = '0.9.28.2' object OriginLabel: TLabel Left = 4 Height = 18 Top = 42 Width = 48 Caption = 'Origin: ' ParentColor = False end object OriginBtn: TSpeedButton Left = 7 Height = 25 Hint = 'You can also double-click on the image' Top = 5 Width = 114 Caption = 'Reset origin' Color = clBtnFace NumGlyphs = 0 OnClick = OriginBtnClick ShowHint = True ParentShowHint = False end object DiffLabel: TLabel Left = 12 Height = 18 Top = 98 Width = 147 Caption = 'Difference from origin' ParentColor = False end object Label1: TLabel Left = 12 Height = 18 Top = 132 Width = 130 Caption = 'Difference at edge' ParentColor = False end object Label2: TLabel Left = 12 Height = 18 Top = 167 Width = 85 Caption = 'Radius (mm)' ParentColor = False end object Label3: TLabel Left = 12 Height = 18 Top = 202 Width = 129 Caption = 'Erode/dilate cycles' ParentColor = False end object AutoROIBtn: TSpeedButton Left = 56 Height = 25 Top = 304 Width = 65 Caption = 'Apply' Color = clBtnFace NumGlyphs = 0 OnClick = AutoROIBtnClick end object CancelBtn: TSpeedButton Left = 120 Height = 25 Top = 304 Width = 65 Caption = 'Cancel' Color = clBtnFace NumGlyphs = 0 OnClick = CancelBtnClick end object Label4: TLabel Left = 4 Height = 18 Top = 74 Width = 79 Caption = 'Constraints' ParentColor = False end object ExcludeBlackCheck: TCheckBox Left = 12 Height = 21 Top = 236 Width = 230 Caption = 'Zero intensity constrains edge' OnClick = AutoROIchange TabOrder = 0 end object VarianceEdit: TSpinEdit Left = 173 Height = 27 Top = 90 Width = 72 MaxValue = 255 OnChange = AutoROIchange TabOrder = 1 Value = 16 end object EdgeEdit: TSpinEdit Left = 173 Height = 27 Top = 126 Width = 72 MaxValue = 255 OnChange = AutoROIchange TabOrder = 2 Value = 16 end object RadiusEdit: TSpinEdit Left = 173 Height = 27 Top = 161 Width = 72 MaxValue = 9999 OnChange = AutoROIchange TabOrder = 3 Value = 32 end object ErodeEdit: TSpinEdit Left = 173 Height = 27 Top = 196 Width = 72 MaxValue = 12 OnChange = AutoROIchange TabOrder = 4 end object ROIconstraint: TComboBox Left = 12 Height = 31 Top = 268 Width = 212 ItemHeight = 0 Items.Strings = ( 'Append to current VOI' 'Delete from current VOI' 'Constain with current VOI' ) OnChange = AutoROIchange Style = csDropDownList TabOrder = 5 end object Timer1: TTimer Enabled = False Interval = 400 OnTimer = Timer1Timer left = 40 top = 34 end end �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/metagraph.pas������������������������������������������������������0000755�0001750�0001750�00000052676�11326425446�016707� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit metagraph; interface uses {$IFNDEF Unix}Windows, Messages, {$ENDIF} SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Buttons, ToolWin, ComCtrls,define_types, ExtCtrls, StdCtrls, Menus,ClipBrd; const kMaxCond = 6; knMaxRow = 20; //Niftiimgvie kMaxLines = kMaxCond* knMaxRow; kClrRA: array [1..kMaxCond] of TColor = (clRed,clGreen,clBlue,clTeal,clAqua,clSilver); kPenStyleRA: array[1..knMaxRow] of TPenStyle = (psSolid,psDot,psDash,psDashDot,psDashDotDot,psSolid,psDot,psDash,psDashDot,psDashDotDot, psSolid,psDot,psDash,psDashDot,psDashDotDot,psSolid,psDot,psDash,psDashDot,psDashDotDot); type TEventOnset = RECORD Events: integer; ELabel: string[16]; EventRA,DurRA: SingleP; END; T4DTrace = RECORD //Title: string[16]; //Samples: integer; HorzMin,HorzWidPerBin,SampleMin,SampleMax,SamplePlotMin,SamplePlotMax {SampleMean,SampleSD,SampleSE,SampleVar}: Double; //SampleRA: SingleP; Lines: array [1..kMaxLines] of TEventOnset; Conditions: array [1..kMaxLines] of TEventOnset; //DurationRA: array [1..kMaxLines] of SingleP; END; procedure Create4DTrace (var l4DTrace: T4DTrace); procedure Init4DTrace(lnSample,lnLines: integer; var l4DTrace: T4DTrace; lErrorBars: boolean); procedure Close4DTrace (var l4DTrace: T4DTrace; lCloseCond: boolean); procedure MinMax4DTrace(var l4DTrace: T4DTrace); procedure CorePlot4DTrace(var l4DTrace: T4DTrace; lImage: TImage; lStartSample,HSpeed,lnColors: integer;lTR,lVertMin,lVertMax: single; lErrorBars: boolean); procedure GraphResize(lImage: TImage); procedure CloseCond (var l4DTrace: T4DTrace; lCond: integer); procedure InitCond (var l4DTrace: T4DTrace; lCond, lnEvents: integer); {$IFNDEF FPC} var gWmf: TMetafile; {$ENDIF} implementation procedure GraphResize(lImage: TImage); var TempBitmap: TBitmap; lx,ly: integer; begin lx := lImage.Width; ly := lImage.Height; if (lx < 1) or (ly < 1) then exit; TempBitmap := TBitmap.Create; TempBitmap.Width := lx; TempBitmap.Height := ly; //Draw32Bitmap(TempBitmap.Canvas.Handle, lx, ly,lBuff {Self}); lImage.Picture.Bitmap := TempBitmap; lImage.Width := lx;//delphi lImage.Height := ly;//delphi TempBitmap.Free; end; function RealToStr(lR: double {was extended}; lDec: integer): string; begin if lR > 99999 then RealTOStr := FloatToStrF(lR, ffExponent ,lDec,7) else RealTOStr := FloatToStrF(lR, ffFixed,7,lDec); end; procedure Create4DTrace (var l4DTrace: T4DTrace); var lLine: integer; begin with l4DTrace do begin for lLine := 1 to kMaxLines do begin Lines[lLine].events := 0; Lines[lLine].elabel := ''; Conditions[lLine].events := 0; Conditions[lLine].elabel := ''; end; end; //with trace end; procedure Init4DTrace(lnSample,lnLines: integer; var l4DTrace: T4DTrace; lErrorBars: boolean); var lLine: integer; begin Close4DTrace(l4DTrace,lErrorBars); if (lnSample < 1) or (lnLines < 1) then exit; with l4DTrace do begin HorzMin := 0; HorzWidPerBin := 1; for lLine := 1 to lnLines do begin //getmem(DurationRA[lLine],lnSample*sizeof(single)); //fx(lLine,lnSample); getmem(Lines[lLine].EventRA,lnSample*sizeof(single)); Lines[lLine].events := lnSample; if lErrorBars then begin getmem(Conditions[lLine].EventRA,lnSample*sizeof(single)); getmem(Conditions[lLine].DurRA,lnSample*sizeof(single)); Conditions[lLine].events := lnSample; end; end; //for each line end; //with trace end; procedure Close4DTrace (var l4DTrace: T4DTrace; lCloseCond: boolean); var lLine: integer; begin with l4DTrace do begin for lLine := 1 to kMaxLines do begin if Lines[lLine].events > 0 then begin freemem(Lines[lLine].EventRA); end; Lines[lLine].events := 0; if lCloseCond then begin if Conditions[lLine].events > 0 then begin freemem(Conditions[lLine].EventRA); freemem(Conditions[lLine].DurRA); //1/1/2008 end; Conditions[lLine].events := 0; end; end; //for each Line end; //with trace end; procedure CloseCond (var l4DTrace: T4DTrace; lCond: integer); begin if (lCond < 1) or (lCond > kMaxLines) then exit; if l4DTrace.Conditions[lCond].events > 0 then begin freemem(l4DTrace.Conditions[lCond].EventRA); freemem(l4DTrace.Conditions[lCond].DurRA); end; l4DTrace.Conditions[lCond].events := 0; end; procedure InitCond (var l4DTrace: T4DTrace; lCond, lnEvents: integer); begin if (lCond < 1) or (lCond > kMaxLines) then exit; CloseCond (l4DTrace, lCond); if lnEvents > 0 then begin getmem(l4DTrace.Conditions[lCond].EventRA, lnEvents * sizeof(single)); //getmem(l4DTrace.DurationRA[lCond],lnEvents*sizeof(single)); getmem(l4DTrace.Conditions[lCond].DurRA,lnEvents*sizeof(single)); //fx(lLine,lnSample); end; l4DTrace.Conditions[lCond].events := lnEvents; end; procedure MinMax4DTrace(var l4DTrace: T4DTrace); var lPos,lLine: integer; l1stLine :boolean; begin l1stLine := true; with l4DTrace do begin for lLine := 1 to kMaxLines do begin if Lines[lLine].events > 0 then begin if l1stLine then begin SampleMin := Lines[lLine].EventRA^[1]; SampleMax:= Lines[lLine].EventRA^[1]; end; l1stLine := false; for lPos := 1 to Lines[lLine].events do begin if Lines[lLine].EventRA^[lPos] > SampleMax then SampleMax := Lines[lLine].EventRA^[lPos]; if Lines[lLine].EventRA^[lPos] < SampleMin then SampleMin := Lines[lLine].EventRA^[lPos]; end; //for each event end; //if events > 0 end; //for each line SamplePlotMin := SampleMin-0.1*abs(SampleMax-SampleMin); SamplePlotMax := SampleMax+0.1*abs(SampleMax-SampleMin); end; //with trace end; {$IFDEF FPC} procedure HText(lImage: TImage; lX,lY,lDec: integer; lVal: single); {$ELSE} procedure HText(lImage: TMetafileCanvas; lX,lY,lDec: integer; lVal: single); {$ENDIF} var lStr: string; begin if lDec >= 0 then lStr := realtostr(round(lVal),0) else lStr := realtostr(lVal,abs(lDec)); {$IFDEF FPC} lImage.Canvas.TextOut(lX-(lImage.Canvas.TextWidth(lStr) shr 1),lY,lStr); {$ELSE} lImage.TextOut(lX-(lImage.TextWidth(lStr) shr 1),lY,lStr); {$ENDIF} end; {$IFDEF FPC} procedure VText(lImage: TImage; lX,lY,lDec: integer; lVal: single); {$ELSE} procedure VText(lImage: TMetafileCanvas; lX,lY,lDec: integer; lVal: single); {$ENDIF} var lStr: string; begin if lDec >= 0 then lStr := realtostr(round(lVal),0) else lStr := realtostr(lVal,abs(lDec)); {$IFDEF FPC} lImage.Canvas.TextOut(lX-lImage.Canvas.TextWidth(lStr) ,lY,lStr); {$ELSE} lImage.TextOut(lX-lImage.TextWidth(lStr) ,lY,lStr); {$ENDIF} end; {$IFDEF FPC} procedure VTextLeftJustified(lImage: TIMage; lX,lY,lDec: integer; lVal: single); {$ELSE} procedure VTextLeftJustified(lImage: TMetafileCanvas; lX,lY,lDec: integer; lVal: single); {$ENDIF} var lStr: string; begin if lDec >= 0 then lStr := inttostr(round(lVal)) else lStr := realtostr(lVal,abs(lDec)); {$IFDEF FPC} lImage.Canvas.TextOut(lX ,lY,lStr); {$ELSE} lImage.TextOut(lX ,lY,lStr); {$ENDIF} end; {$IFDEF FPC} procedure ShowRange(lImage: TImage; lMin,lMax: single; lL,lT,lR,lB,lPosition: integer); {$ELSE} procedure ShowRange(lImage: TMetafileCanvas; lMin,lMax: single; lL,lT,lR,lB,lPosition: integer); {$ENDIF} //position 1=L,2=T,3=R,4=B var lRangeR,lRange,lD,lV: double; lDecimals,lPos,lLo,lHi,lHPos,lOffset : integer; begin {$IFDEF FPC} with lImage.Canvas do begin {$ELSE} with lImage do begin {$ENDIF} Font.color := clBlack; lRange := abs(lMax-lMin); lRangeR := lRange; lDecimals := 0; lD := 1; if lRangeR = 0 then exit; while lRangeR > 10 do begin//get range 1..10 lRangeR := lRangeR / 10; inc(lDecimals); lD := lD * 10; end; while lRangeR < 1 do begin//get range 1..10 lRangeR := lRangeR * 10; dec(lDecimals); lD := lD / 10; end; lLo := round((lMin + (lD/2)) / lD); lHi := trunc((lMax + (lD/20) ) / lD);//2007 //lHi := trunc((lMax ) / lD); if lHi <= (lLo+2) then begin lD := lD /2; if lDecimals <= 0 then dec(lDecimals) else inc(lDecimals); lLo := round((lMin + (lD/2)) / lD); lHi := trunc((lMax + (lD/20) ) / lD);//2007 end; if (lPosition = 2{T}) or (lPosition = 4{B}) then begin lOffset := TextHeight('0'); for lPos := lLo to lHi do begin lV := lPos * lD; lHPos := lL+ round( ((lV-lMin) / lRange)* abs(lR-lL)); if (lPosition = 2{T}) then HText(lImage, lHPos,lT- lOffset,lDecimals,lV) else HText(lImage, lHPos,lB+1,lDecimals,lV); end; end else if (lPosition = 1{L}) or (lPosition = 3{R}) then begin //vertical values lOffset := TextHeight('0') div 2; //2007 for lPos := lLo to lHi do begin lV := lPos * lD; {lHPos := lB- round( ((lV-lMin) / lRange)* abs(lT-lB)); lImage.MoveTo(1,lHPos); lImage.LineTo(1000,lHPos);} lHPos := lB- round( ((lV-lMin) / lRange)* abs(lT-lB))-lOffset; if (lPosition = 1{L}) then VText(lImage, lL-1,lHPos,lDecimals,lV) else VTextLeftJustified(lImage, lR+1,lHPos,lDecimals,lV); end; end; //if vertical end; //with limage end; {$IFDEF FPC} function ShowLegend(var l4DTrace: T4DTrace; lImage: TImage; lL,lT: integer): integer; {$ELSE} function ShowLegend(var l4DTrace: T4DTrace; lImage: TMetafileCanvas; lL,lT: integer): integer; {$ENDIF} var lC,lLegendLeft: integer; begin {$IFDEF FPC} with lImage.Canvas do begin {$ELSE} with lImage do begin {$ENDIF} lLegendLeft := lL; font.color := clBlack; for lC := 1 to kMaxCond do begin //lImage.canvas.pen.color := kClrRA[lC]; font.color := kClrRA[lC] ; if (l4DTrace.Conditions[lC].events > 0) then begin TextOut(lLegendLeft,lT,l4DTrace.Conditions[lC].ELabel); lLegendLeft := lLegendLeft + TextWidth(l4DTrace.Conditions[lC].ELabel)+5; end; //for each tevent end; //if cond has events result := lLegendLeft; end; //with limage end; //for each cond function n4DTrace(var l4DTrace: T4DTrace;var lSamples: integer; lErrorBars: boolean): integer; var lLine: integer; l1stLine :boolean; begin lSamples:= 0; result := 0; l1stLine := true; with l4DTrace do begin for lLine := 1 to kMaxLines do begin if Lines[lLine].events > 0 then begin if l1stLine then lSamples := Lines[lLine].events; l1stLine := false; if (lErrorBars) and (Lines[lLine].events <> lSamples) then exit; //all lines must have same number of samples inc(result); end; //if events > 0 end; //for each line end; //with trace end; {$IFDEF FPC} function SetColorStyle (lImage: TImage; lLine,lnColors: integer): TPenStyle; {$ELSE} function SetColorStyle (lImage: TMetafileCanvas; lLine,lnColors: integer): TPenStyle; {$ENDIF} var lC: integer; begin {$IFDEF FPC} with lImage.Canvas do begin {$ELSE} with lImage do begin {$ENDIF} if lnColors < 1 then begin pen.color := clBlack;//clRed pen.style := kPenStyleRA[lLine]; result := kPenStyleRA[lLine]; exit; end; lC := lLine mod lnColors; if lC = 0 then lC := lnColors; pen.color := kClrRA[lC]; lC := ((lLine-1) div lnColors)+1; pen.style := kPenStyleRA[lC]; result := kPenStyleRA[lC]; end; //with lImage. end; {$IFDEF FPC} procedure ShowLineLegend(var l4DTrace: T4DTrace; lImage: TImage; lL, lT,lnLines,lnColors: integer); {$ELSE} procedure ShowLineLegend(var l4DTrace: T4DTrace; lImage: TMetafileCanvas; lL, lT,lnLines,lnColors: integer); {$ENDIF} var lLineTop,lStyle,lnStyles,lLegendLeft: integer; begin if lnColors < 1 then lnStyles := lnLines else lnStyles := lnLines div lnColors; if lnStyles < 1 then lnStyles := 1; {$IFDEF FPC} with lImage.Canvas do begin {$ELSE} with lImage do begin {$ENDIF} font.color := clBlack; pen.color := clBlack; lLegendLeft := lL; lLineTop := lT+(TextHeight('X') div 2); for lStyle := 1 to lnStyles do begin pen.style := kPenStyleRA[lStyle]; MoveTo(lLegendLeft,lLineTop); lLegendLeft := lLegendLeft +40; LineTo(lLegendLeft,lLineTop); lLegendLeft := lLegendLeft + 2; TextOut(lLegendLeft,lT,l4DTrace.Lines[lStyle].ELabel); lLegendLeft := lLegendLeft + TextWidth(l4DTrace.Lines[lStyle].ELabel)+5; end; pen.style := psSolid; end;//with lImage. end; {$IFDEF FPC} procedure ShowPlot(var l4DTrace: T4DTrace; lImage: TImage; lL,lT,lR,lB,lStartSample,lHSpeedIn,lScalePos,lnColors: integer; lSecPerSample,lVertMin,lVertMax: single; lShowHRange,lErrorBars: boolean); {$ELSE} procedure ShowPlot(var l4DTrace: T4DTrace; lImage: TMetafileCanvas; lL,lT,lR,lB,lStartSample,lHSpeedIn,lScalePos,lnColors: integer; lSecPerSample,lVertMin,lVertMax: single; lShowHRange,lErrorBars: boolean); {$ENDIF} const kMinMax = 0; k2SD = 1; k12bit = 2; kMaxPt = 16000; type TPtRA= array [1..kMaxPt] of TPoint; var lnPt,lnLines,lLine,lnSamples,lC,lStartSamp,lEndSamp,lEndPix,lPos,lI: integer; lVert,lHorz,lVMax,lVMin,lScale,lHSpeed: single; lPenStyle: TPenStyle; lPtRA: TPtRA; begin lnLines := n4DTrace(l4DTrace,lnSamples,lErrorBars); if (lnLines < 1) or (lnSamples < 2) or (lB <= lT) then exit; lStartSamp := lStartSample; if (lStartSamp > lnSamples) then exit; if lStartSamp < 1 then lStartSamp := 1; lHSpeed := lHSpeedIn; if lHSpeed < 1 then begin lStartSamp := 1; lHSpeed := (lnSamples-1)/(lR-lL); end; {$IFDEF FPC} with lImage.Canvas do begin {$ELSE} with lImage do begin {$ENDIF} lEndSamp := trunc(lStartSamp + ((lR-lL)*lHSpeed))+1; ShowRange(lImage, l4DTrace.HorzMin+((lStartSamp-1)*l4DTrace.HorzWidPerBin),l4DTrace.HorzMin+((lEndSamp-1)*l4DTrace.HorzWidPerBin),lL,lT,lR,lB,4); if lShowHRange then ShowRange(lImage, l4DTrace.HorzMin+((lStartSamp-1)*l4DTrace.HorzWidPerBin),l4DTrace.HorzMin+((lEndSamp-1)*l4DTrace.HorzWidPerBin),lL,lT,lR,lB,4); lI := ShowLegend(l4DTrace,lImage, lL,5); ShowLineLegend(l4DTrace, lImage, lI+10, 5,lnLines,lnColors); //next show event onsets if not lErrorBars then for lC := 1 to kMaxCond do begin pen.color := kClrRA[lC]; if (l4DTrace.Conditions[lC].events > 0) and (lSecPerSample > 0) then begin //canvas.TextOut(lLegendLeft,lT-canvas.TextHeight('X')-2,l4DTrace.Conditions[lC].ELabel); //lLegendLeft := lLegendLeft + canvas.TextWidth(l4DTrace.Conditions[lC].ELabel)+5; for lPos := 1 to l4DTrace.Conditions[lC].events do begin lHorz := l4DTrace.Conditions[lC].EventRA^[lPos] / lSecPerSample; if (lHorz < lEndSamp) and (lHorz > lStartSamp) then begin lVert := ((lHorz - lStartSamp) / lHSpeed)+lL; moveto(round(lVert),lT); lineto(round(lVert),lB); end; //if event in range end; //for each tevent end; //if cond has events end; //for each cond if (lEndSamp > lnSamples) then begin lEndSamp := lnSamples; lEndPix := lL+trunc((lnSamples-lStartSamp) / lHSpeed); end else lEndPix := lR; lVMax := lVertMax; lVMin := lVertMin; if (lVMax <= lVMin) then begin lVMax := l4DTrace.SamplePlotMax; lVMin := l4DTrace.SamplePlotMin; end; if (lVMax < l4DTrace.SampleMin) or (lVMin > l4DTrace.SampleMax) then begin lVMax := l4DTrace.SamplePlotMax; lVMin := l4DTrace.SamplePlotMin; end; ShowRange(lImage,lVMin,lVMax,lL,lT,lR,lB,lScalePos); moveto(lL,lT); if lVMax <= lVMin then lScale := 1 else lScale := (lB-lT)/ (lVMax-lVMin); if lHSpeed < 1 then begin //lHSpeed := (l4DTrace.Samples-1)/(lR-lL); for lLine := 1 to lnLines do begin lPenStyle := SetColorStyle (lImage, lLine,lnColors); lnPt := 0; for lPos := lStartSamp to lEndSamp do begin lVert := l4DTrace.Lines[lLine].EventRA^[lPos]; if lVert > lVMax then lVert := lVMax else if lVert < lVMin then lVert := lVMin; lVert := round((lVert-lVMin)*lScale); lVert := lB-lVert; lHorz := lL+round((lPos-lStartSamp)/lHSpeed); inc(lnPt); if lnPt < kMaxPt then lPtRA[lnPt] := Point(round(lHorz),round(lVert)); if lErrorBars then begin pen.style := psSolid; moveto(round(lHorz),round(lVert-(l4DTrace.Conditions[lLine].EventRA^[lPos]*lScale))); lineto(round(lHorz) ,round(lVert+(l4DTrace.Conditions[lLine].EventRA^[lPos]*lScale))); moveto(round(lHorz) ,round(lVert)); pen.style := lPenStyle; end; end; //for lPos if lnPt > kMaxPt then lnPt := kMaxPt; if lnPt > 0 then PolyLine( Slice(lPtRA, lnPt)); end; //for each line end else begin //HSpeed >=1 so every pixel unique for lLine := 1 to lnLines do begin lPenStyle := SetColorStyle (lImage, lLine,lnColors); lI := lStartSamp; lnPt := 0; for lPos := lL to lEndPix do begin lVert := l4DTrace.Lines[lLine].EventRA^[lI]; if lVert > lVMax then lVert := lVMax else if lVert < lVMin then lVert := lVMin; lVert := round((lVert-lVMin)*lScale); //lVert := lVert + lT; lVert := lB-lVert; inc(lnPt); if lnPt < kMaxPt then lPtRA[lnPt] := Point(lPos,round(lVert)); if lErrorBars then begin pen.style := psSolid; moveto(lPos,round(lVert-(l4DTrace.Conditions[lLine].EventRA^[lPos]*lScale))); lineto(lPos ,round(lVert+(l4DTrace.Conditions[lLine].EventRA^[lPos]*lScale))); moveto(lPos ,round(lVert)); pen.style := lPenStyle; end; lI := round( lStartSamp+((lPos-lL)*lHSpeed) ); if lI < 1 then lI := 1; if lI > lEndSamp then lI := lEndSamp; end; //for lPos if lnPt > kMaxPt then lnPt := kMaxPt; if lnPt > 0 then PolyLine( Slice(lPtRA, lnPt)) end; //for each line end; //hspeed >= 1 pen.style := psSolid; end;//with .lImage end; procedure DrawBMP( lx, ly: integer; {lBuff: RGBQuadp;} var lImage: TImage); var TempBitmap: TBitmap; begin TempBitmap := TBitmap.Create; TempBitmap.Width := lx; TempBitmap.Height := ly; //Draw32Bitmap(TempBitmap.Canvas.Handle, lx, ly,lBuff {Self}); lImage.Picture.Bitmap := TempBitmap; lImage.Width := lx;//delphi lImage.Height := ly;//delphi TempBitmap.Free; end; {$IFDEF FPC} procedure PrepPlot(var lImage: TIMage; lL,lT,lR,lB,lWid,lHt,lFontSize: integer); {$ELSE} procedure PrepPlot(var lImage: TMetafileCanvas; lL,lT,lR,lB,lWid,lHt,lFontSize: integer); {$ENDIF} begin {$IFDEF FPC} with lImage.Canvas do begin {$ELSE} with lImage do begin {$ENDIF} Font.Name := 'Arial'; Font.Size := 12; pen.color := clBlack; Font.color := clBlack; Brush.Style := bsSolid; Brush.color := clWhite; Rectangle(1,1,lWid,lHt); Rectangle(lL,lT,lR,lB); end; end; procedure CorePlot4DTrace(var l4DTrace: T4DTrace; lImage: TImage; lStartSample,HSpeed,lnColors: integer;lTR,lVertMin,lVertMax: single; lErrorBars: boolean); var lWid,lHt,lBorder,lL,lT,lR,lB,lFontSize: integer; {$IFDEF FPC} //WmfCanvas: TCanvas; {$ELSE} WmfCanvas: TMetafileCanvas; {$ENDIF} begin lWid := lImage.Width; lHt := lImage.Height; lFontSize := 12; lBorder := lFontSize * 4; if (lWid <= (2*lBorder)) or (lHt <= (2*lBorder)) then exit; lL := round(1.3*lBorder); lT :=lFontSize*2; lR := lWid - lBorder; lB := lHt-(lFontSize*2); {$IFDEF FPC} //WmfCanvas := TCanvas.Create; PrepPlot(lImage,lL,lT,lR,lB,lWid,lHt,lFontSize); ShowPlot(l4DTrace,lImage,lL,lT,lR,lB,lStartSample,HSpeed,1,lnColors, lTR,lVertMin,lVertMax,true,lErrorBars); //abba lImage.Canvas.Draw (0, 0, WmfCanvas); //WmfCanvas.Free; {$ELSE} gWmf.clear; gWmf.Width := lWid; gWmf.Height := lHt; WmfCanvas := TMetafileCanvas.CreateWithComment(gWmf, 0, 'mricron', 'plot metafile'); try PrepPlot(WmfCanvas,lL,lT,lR,lB,lWid,lHt,lFontSize); ShowPlot(l4DTrace,WmfCanvas,lL,lT,lR,lB,lStartSample,HSpeed,1,lnColors, lTR,lVertMin,lVertMax,true,lErrorBars); finally WmfCanvas.Free; end;//finally lImage.Canvas.Draw (0, 0, gWmf); {$ENDIF} end; initialization begin {$IFDEF FPC} {$ELSE} gWmf := TMetafile.Create; gWmf.Enhanced := True; {$ENDIF} // Create4DTrace(g4Ddata); end; finalization begin //Close4DTrace(g4Ddata); {$IFDEF FPC} {$ELSE} gWmf.free; {$ENDIF} end; end. ������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_xcarbon.bat�������������������������������������������������������0000755�0001750�0001750�00000000602�10722040720�016456� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������rm ~/Documents/mricron/mricron.app/mricron ln -s ~/Documents/mricron/mricron ~/Documents/mricron/mricron.app/mricron rm ~/Documents/mricron/npm/npm.app/npm ln -s ~/Documents/mricron/npm/npm ~/Documents/mricron/npm/npm.app/npm rm ~/Documents/mricron/dcm2nii/dcm2niigui.app/dcm2niigui ln -s ~/Documents/mricron/dcm2nii/dcm2niigui ~/Documents/mricron/dcm2nii/dcm2niigui.app/dcm2niigui ������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/reslice_img.pas����������������������������������������������������0000755�0001750�0001750�00000052137�12306421074�017201� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit reslice_img; //12 April 2009 - added lTrilinearSmooth option to allow nearest neighbor interpolation interface uses {$ifndef fpc}{windows,} {$endif} GraphicsMathLibrary,nifti_hdr, nifti_types; function Reslice_Img_To_Unaligned (var lTargHdr: TNIfTIhdr; var lSrcHdr: TMRIcroHdr; lTrilinearSmoothIn: boolean): boolean; function Hdr2InvMat (lHdr: TNiftiHdr; var lOK: boolean): TMatrix; procedure Voxel2mm(var X,Y,Z: single; var lHdr: TNIfTIHdr); procedure mm2Voxel (var X,Y,Z: single; var lInvMat: TMatrix); implementation uses dialogs, define_types; function Hdr2Mat (lHdr: TNIFTIhdr): TMatrix; begin Result := Matrix3D ( lHdr.srow_x[0],lHdr.srow_x[1],lHdr.srow_x[2],lHdr.srow_x[3], // 3D "graphics" matrix lHdr.srow_y[0],lHdr.srow_y[1],lHdr.srow_y[2],lHdr.srow_y[3], // 3D "graphics" matrix lHdr.srow_z[0],lHdr.srow_z[1],lHdr.srow_z[2],lHdr.srow_z[3], // 3D "graphics" matrix 0,0,0,1); end; (*procedure ReportMatrix (lM:TMatrix); const kCR = chr (13); begin showmessage(RealToStr(lM.matrix[1,1],6)+','+RealToStr(lM.matrix[1,2],6)+','+RealToStr(lM.matrix[1,3],6)+','+RealToStr(lM.matrix[1,4],6)+kCR+ RealToStr(lM.matrix[2,1],6)+','+RealToStr(lM.matrix[2,2],6)+','+RealToStr(lM.matrix[2,3],6)+','+RealToStr(lM.matrix[2,4],6)+kCR+ RealToStr(lM.matrix[3,1],6)+','+RealToStr(lM.matrix[3,2],6)+','+RealToStr(lM.matrix[3,3],6)+','+RealToStr(lM.matrix[3,4],6)+kCR +RealToStr(lM.matrix[4,1],6)+','+RealToStr(lM.matrix[4,2],6)+','+RealToStr(lM.matrix[4,3],6)+','+RealToStr(lM.matrix[4,4],6) ); end; *) (* procedure SPMmat(var lDestMat: TMatrix); //SPM matrices are indexed from 1 //This function is only useful for direct comparisons with SPM var lTemp,lVS: TMatrix; begin lVS := Matrix3D (1,0,0,-1, 0,1,0,-1, 0,0,1,-1, 0,0,0,1);//VoxelShift lTemp := lDestMat; lDestMat := MultiplyMatrices(lTemp,lVS); end;*) procedure Coord(var lV: TVector; var lMat: TMatrix); //transform X Y Z by matrix var lXi,lYi,lZi: single; begin lXi := lV.x; lYi := lV.y; lZi := lV.z; lV.x := (lXi*lMat.matrix[1][1]+lYi*lMat.matrix[1][2]+lZi*lMat.matrix[1][3]+lMat.matrix[1][4]); lV.y := (lXi*lMat.matrix[2][1]+lYi*lMat.matrix[2][2]+lZi*lMat.matrix[2][3]+lMat.matrix[2][4]); lV.z := (lXi*lMat.matrix[3][1]+lYi*lMat.matrix[3][2]+lZi*lMat.matrix[3][3]+lMat.matrix[3][4]); end; procedure Transposemat(var lMat: TMatrix); var lTemp: TMatrix; i,j: integer; begin lTemp := lMat; for i := 1 to lMat.size do for j := 1 to lMat.size do lMat.matrix[i,j] := lTemp.matrix[j,i]; end; function gaussj(VAR a: TMatrix): boolean;//Invert a Matrix - see Numerical Recipes label 666; VAR big,dum,pivinv: real; n,i,icol,irow,j,k,l,ll: integer; indxc,indxr,ipiv: array [1..4] of integer; BEGIN result := true; icol := 1;//not used - avoids compiler warning irow := 1;//not used - avoids compiler warning n := a.size; FOR j := 1 TO n DO BEGIN ipiv[j] := 0 END; FOR i := 1 TO n DO BEGIN big := 0.0; FOR j := 1 TO n DO BEGIN IF (ipiv[j] <> 1) THEN BEGIN FOR k := 1 TO n DO BEGIN IF (ipiv[k] = 0) THEN BEGIN IF (abs(a.matrix[j,k]) >= big) THEN BEGIN big := abs(a.matrix[j,k]); irow := j; icol := k END END ELSE IF (ipiv[k] > 1) THEN BEGIN goto 666; END END END END; ipiv[icol] := ipiv[icol]+1; IF (irow <> icol) THEN BEGIN FOR l := 1 TO n DO BEGIN dum := a.matrix[irow,l]; a.matrix[irow,l] := a.matrix[icol,l]; a.matrix[icol,l] := dum END; END; indxr[i] := irow; indxc[i] := icol; IF (a.matrix[icol,icol] = 0.0) THEN goto 666; pivinv := 1.0/a.matrix[icol,icol]; a.matrix[icol,icol] := 1.0; FOR l := 1 TO n DO BEGIN a.matrix[icol,l] := a.matrix[icol,l]*pivinv END; FOR ll := 1 TO n DO BEGIN IF (ll <> icol) THEN BEGIN dum := a.matrix[ll,icol]; a.matrix[ll,icol] := 0.0; FOR l := 1 TO n DO BEGIN a.matrix[ll,l] := a.matrix[ll,l]-a.matrix[icol,l]*dum END; END END END; FOR l := n DOWNTO 1 DO BEGIN IF (indxr[l] <> indxc[l]) THEN BEGIN FOR k := 1 TO n DO BEGIN dum := a.matrix[k,indxr[l]]; a.matrix[k,indxr[l]] := a.matrix[k,indxc[l]]; a.matrix[k,indxc[l]] := dum END END END; exit; 666: //only get here if there is an error Showmessage('error in reslice_img - singular matrix. Spatial orientation is ambiguous.'); a := Eye3D; result := false; END; procedure SubVec (var lVx: TVector; lV0: TVector); begin lVx.x := lVx.x - lV0.x; lVx.y := lVx.y - lV0.y; lVx.z := lVx.z - lV0.z; end; (*procedure mm2Voxel (var X,Y,Z: single; var lInvMat: TMatrix); //returns voxels indexed from 1 not 0! var lV: TVector; lSrcMatInv,lSrcMat: TMatrix; begin lV := Vector3D (X,Y,Z); lV := Transform (lV,lInvMat); X := lV.x+1; Y := lV.y+1; Z := lV.z+1; end;*) procedure mm2Voxel (var X,Y,Z: single; var lInvMat: TMatrix); //returns voxels indexed from 1 not 0! var lV: TVector; lSrcMatInv,lSrcMat: TMatrix; begin lV := Vector3D (X,Y,Z); Coord (lV,lInvMat); X := lV.x+1; Y := lV.y+1; Z := lV.z+1; end; procedure Voxel2mm(var X,Y,Z: single; var lHdr: TNIfTIHdr); var lV: TVector; lMat: TMatrix; begin //lV := Vector3D (X-1,Y-1,Z-1); lV := Vector3D (X-1,Y-1,Z-1); lMat := Hdr2Mat(lHdr); Coord(lV,lMat); X := lV.x; Y := lV.y; Z := lV.z; end; function Voxel2Voxel (var lDestHdr,lSrcHdr: TNIFTIhdr): TMatrix; //returns matrix for transforming voxels from one image to the other image //results are in VOXELS not mm var lV0,lVx,lVy,lVz: TVector; lDestMat,lSrcMatInv,lSrcMat: TMatrix; begin //Step 1 - compute source coordinates in mm for 4 voxels //the first vector is at 0,0,0, with the //subsequent voxels being left, up or anterior lDestMat := Hdr2Mat(lDestHdr); //SPMmat(lDestMat); lV0 := Vector3D (0,0,0); lVx := Vector3D (1,0,0); lVy := Vector3D (0,1,0); lVz := Vector3D (0,0,1); Coord(lV0,lDestMat); Coord(lVx,lDestMat); Coord(lVy,lDestMat); Coord(lVz,lDestMat); lSrcMat := Hdr2Mat(lSrcHdr); //SPMmat(lSrcMat); lSrcMatInv := lSrcMat; gaussj(lSrcMatInv); //the vectors should be rows not columns.... //therefore we transpose the matrix Transposemat(lSrcMatInv); //the 'transform' multiplies the vector by the matrix lV0 := Transform (lV0,lSrcMatInv); lVx := Transform (lVx,lSrcMatInv); lVy := Transform (lVy,lSrcMatInv); lVz := Transform (lVz,lSrcMatInv); //subtract each vector from the origin // this reveals the voxel-space influence for each dimension SubVec(lVx,lV0); SubVec(lVy,lV0); SubVec(lVz,lV0); result := Matrix3D(lVx.x,lVy.x,lVz.x,lV0.x, lVx.y,lVy.y,lVz.y,lV0.y, lVx.z,lVy.z,lVz.z,lV0.z, 0,0,0,1); end; procedure CopyHdrMat(var lTarg,lDest: TNIfTIHdr); //destination has dimensions and rotations of destination var lI: integer; begin //destination will have dimensions of target lDest.dim[0] := 3; //3D for lI := 1 to 3 do lDest.dim[lI] := lTarg.dim[lI]; lDest.dim[4] := 1; //3D //destination will have pixdim of target for lI := 0 to 7 do lDest.pixdim[lI] := lTarg.pixdim[lI]; lDest.xyzt_units := lTarg.xyzt_units; //e.g. mm and sec lDest.qform_code := lTarg.qform_code; lDest.sform_code := lTarg.sform_code; lDest.quatern_b := lTarg.quatern_b; lDest.quatern_c := lTarg.quatern_c; lDest.quatern_d := lTarg.quatern_d; lDest.qoffset_x := lTarg.qoffset_x; lDest.qoffset_y := lTarg.qoffset_y; lDest.qoffset_z := lTarg.qoffset_z; for lI := 0 to 3 do begin lDest.srow_x[lI] := lTarg.srow_x[lI]; lDest.srow_y[lI] := lTarg.srow_y[lI]; lDest.srow_z[lI] := lTarg.srow_z[lI]; end; end; function OneToOne(lM:TMatrix): boolean; var lC,lR: integer; begin result := false; for lC := 1 to 3 do for lR := 1 to 3 do if (lM.matrix[lC,lR] <> 0) and ((abs(lM.matrix[lC,lR])- 1) > 0.00001) then exit; result := true; end; function Reslice_Img_To_Unaligned (var lTargHdr: TNIfTIhdr; var lSrcHdr: TMRIcroHdr; lTrilinearSmoothIn: boolean): boolean; var lXrM1,lYrM1,lZrM1,lZx,lZy,lZz,lYx,lYy,lYz,lXreal,lYreal,lZreal: single; lXo,lYo,lZo,lMinY,lMaxY,lMinZ,lMaxZ, lPos,lXs,lYs,lZs,lXYs,lXYZs,lX,lY,lZ,lOutVolItems, lXi,lYi,lZi: integer; lDestHdr: TNIFTIhdr; lMat: TMatrix; lTrilinearSmooth,lOverlap: boolean; lXx,lXy,lXz: Singlep0; l32fs,l32f : SingleP; l16is,l16i : SmallIntP; l8i,l8is,lSrcBuffer,lBuffUnaligned,lBuffAligned,lBuffOutUnaligned: bytep; begin lTrilinearSmooth := lTrilinearSmoothIn; result := false; lOverlap := false; lDestHdr := lSrcHdr.NIfTIHdr; //destination has the comments and voxel BPP of source CopyHdrMat(lTargHdr,lDestHdr);//destination has dimensions and rotations of destination lXs := lSrcHdr.NIfTIHdr.Dim[1]; lYs := lSrcHdr.NIfTIHdr.Dim[2]; lZs := lSrcHdr.NIfTIHdr.Dim[3]; lXYs:=lXs*lYs; //slicesz lXYZs := lXYs*lZs; lX := lDestHdr.Dim[1]; lY := lDestHdr.Dim[2]; lZ := lDestHdr.Dim[3]; lOutVolItems :=lX*lY*lZ; if lSrcHdr.ImgBufferBPP = 4 then begin l32fs := SingleP(lSrcHdr.ImgBuffer); GetMem(lBuffOutUnaligned,(lOutVolItems*sizeof(single))+16); {$IFDEF FPC} l32f := align(lBuffOutUnaligned,16); {$ELSE} l32f := SingleP($fffffff0 and (integer(lBuffOutUnaligned)+15)); {$ENDIF} for lPos := 1 to lOutVolItems do l32f^[lPos] := 0; //set all to zero end else if lSrcHdr.ImgBufferBPP = 2 then begin l16is := SmallIntP(lSrcHdr.ImgBuffer); GetMem(lBuffOutUnaligned,(lOutVolItems*sizeof(smallint))+16); {$IFDEF FPC} l16i := align(lBuffOutUnaligned,16); {$ELSE} l16i := SmallIntP($fffffff0 and (integer(lBuffOutUnaligned)+15)); {$ENDIF} for lPos := 1 to lOutVolItems do l16i^[lPos] := 0; //set all to zero end else if lSrcHdr.ImgBufferBPP = 1 then begin l8is := ByteP(lSrcHdr.ImgBuffer); GetMem(l8i,lOutVolItems); Fillchar(l8i^,lOutVolItems,0); //set all to zero end; lMat := Voxel2Voxel (lTargHdr,lSrcHdr.NIfTIHdr); //lDestHdr := lSrcHdr; //destination has the comments and voxel BPP of source //CopyHdrMat(lTargHdr,lDestHdr);//destination has dimensions and rotations of destination //now we can apply the transforms... //build lookup table - speed up inner loop getmem(lXx, lX*sizeof(single)); getmem(lXy, lX*sizeof(single)); getmem(lXz, lX*sizeof(single)); for lXi := 0 to (lX-1) do begin lXx^[lXi] := lXi*lMat.matrix[1][1]; lXy^[lXi] := lXi*lMat.matrix[2][1]; lXz^[lXi] := lXi*lMat.matrix[3][1]; end; lPos := 0; if (lTrilinearSmooth) and (OneToOne(lMat)) then begin lTrilinearSmooth := false; end; if lTrilinearSmooth then begin//compute trilinear interpolation //compute trilinear interpolation for lZi := 0 to (lZ-1) do begin //these values are the same for all voxels in the slice // compute once per slice lZx := lZi*lMat.matrix[1][3]; lZy := lZi*lMat.matrix[2][3]; lZz := lZi*lMat.matrix[3][3]; for lYi := 0 to (lY-1) do begin //these values change once per row // compute once per row lYx := lYi*lMat.matrix[1][2]; lYy := lYi*lMat.matrix[2][2]; lYz := lYi*lMat.matrix[3][2]; for lXi := 0 to (lX-1) do begin //compute each column inc(lPos); lXreal := (lXx^[lXi]+lYx+lZx+lMat.matrix[1][4]); lYreal := (lXy^[lXi]+lYy+lZy+lMat.matrix[2][4]); lZreal := (lXz^[lXi]+lYz+lZz+lMat.matrix[3][4]); //need to test Xreal as -0.01 truncates to zero if (lXreal >= 0) and (lYreal >= 0) and (lZreal >= 0) and (lXreal < (lXs -1)) and (lYreal < (lYs -1) ) and (lZreal <= (lZs -1)) //June09 lZReal <= instead of < then begin //compute the contribution for each of the 8 source voxels //nearest to the target lOverlap := true; lXo := trunc(lXreal); lYo := trunc(lYreal); lZo := trunc(lZreal); lXreal := lXreal-lXo; lYreal := lYreal-lYo; lZreal := lZreal-lZo; lXrM1 := 1-lXreal; lYrM1 := 1-lYreal; lZrM1 := 1-lZreal; lMinY := lYo*lXs; lMinZ := lZo*lXYs; lMaxY := lMinY+lXs; inc(lXo);//images incremented from 1 not 0 //Check if sample is perfectly in the Z-plane. //This requires only 8 samples, so its faster //in addition, for very thin volumes, it allows us to sample to the edge if lZReal = 0 then begin // perfectly in plane, only sample 4 voxels near each other case lSrcHdr.ImgBufferBPP of 1 : l8i^[lPos] := round ( ( (lXrM1*lYrM1)*l8is^[lXo+lMinY+lMinZ])+((lXreal*lYrM1)*l8is^[lXo+1+lMinY+lMinZ])+((lXrM1*lYreal)*l8is^[lXo+lMaxY+lMinZ])+((lXreal*lYreal)*l8is^[lXo+1+lMaxY+lMinZ])); 2: l16i^[lPos] := round (( (lXrM1*lYrM1)*l16is^[lXo+lMinY+lMinZ])+((lXreal*lYrM1)*l16is^[lXo+1+lMinY+lMinZ])+((lXrM1*lYreal)*l16is^[lXo+lMaxY+lMinZ])+((lXreal*lYreal)*l16is^[lXo+1+lMaxY+lMinZ])); 4: l32f^[lPos] := ( (lXrM1*lYrM1)*l32fs^[lXo+lMinY+lMinZ])+((lXreal*lYrM1)*l32fs^[lXo+1+lMinY+lMinZ])+((lXrM1*lYreal)*l32fs^[lXo+lMaxY+lMinZ])+((lXreal*lYreal)*l32fs^[lXo+1+lMaxY+lMinZ]); end; //case end else begin //not perfectly in plane... we need 8 samples... lMaxZ := lMinZ+lXYs; case lSrcHdr.ImgBufferBPP of 1 : l8i^[lPos] := round ({all min} ( (lXrM1*lYrM1*lZrM1)*l8is^[lXo+lMinY+lMinZ]) {x+1}+((lXreal*lYrM1*lZrM1)*l8is^[lXo+1+lMinY+lMinZ]) {y+1}+((lXrM1*lYreal*lZrM1)*l8is^[lXo+lMaxY+lMinZ]) {z+1}+((lXrM1*lYrM1*lZreal)*l8is^[lXo+lMinY+lMaxZ]) {x+1,y+1}+((lXreal*lYreal*lZrM1)*l8is^[lXo+1+lMaxY+lMinZ]) {x+1,z+1}+((lXreal*lYrM1*lZreal)*l8is^[lXo+1+lMinY+lMaxZ]) {y+1,z+1}+((lXrM1*lYreal*lZreal)*l8is^[lXo+lMaxY+lMaxZ]) {x+1,y+1,z+1}+((lXreal*lYreal*lZreal)*l8is^[lXo+1+lMaxY+lMaxZ]) ); 2:l16i^[lPos] := round ({all min} ( (lXrM1*lYrM1*lZrM1)*l16is^[lXo+lMinY+lMinZ]) {x+1}+((lXreal*lYrM1*lZrM1)*l16is^[lXo+1+lMinY+lMinZ]) {y+1}+((lXrM1*lYreal*lZrM1)*l16is^[lXo+lMaxY+lMinZ]) {z+1}+((lXrM1*lYrM1*lZreal)*l16is^[lXo+lMinY+lMaxZ]) {x+1,y+1}+((lXreal*lYreal*lZrM1)*l16is^[lXo+1+lMaxY+lMinZ]) {x+1,z+1}+((lXreal*lYrM1*lZreal)*l16is^[lXo+1+lMinY+lMaxZ]) {y+1,z+1}+((lXrM1*lYreal*lZreal)*l16is^[lXo+lMaxY+lMaxZ]) {x+1,y+1,z+1}+((lXreal*lYreal*lZreal)*l16is^[lXo+1+lMaxY+lMaxZ]) ); 4: l32f^[lPos] := {all min} ( (lXrM1*lYrM1*lZrM1)*l32fs^[lXo+lMinY+lMinZ]) {x+1}+((lXreal*lYrM1*lZrM1)*l32fs^[lXo+1+lMinY+lMinZ]) {y+1}+((lXrM1*lYreal*lZrM1)*l32fs^[lXo+lMaxY+lMinZ]) {z+1}+((lXrM1*lYrM1*lZreal)*l32fs^[lXo+lMinY+lMaxZ]) {x+1,y+1}+((lXreal*lYreal*lZrM1)*l32fs^[lXo+1+lMaxY+lMinZ]) {x+1,z+1}+((lXreal*lYrM1*lZreal)*l32fs^[lXo+1+lMinY+lMaxZ]) {y+1,z+1}+((lXrM1*lYreal*lZreal)*l32fs^[lXo+lMaxY+lMaxZ]) {x+1,y+1,z+1}+((lXreal*lYreal*lZreal)*l32fs^[lXo+1+lMaxY+lMaxZ]) ; end; //case end; //not perfectly in plane end; //if voxel is in source image's bounding box end;//z end;//y end;//z end else begin //if trilinear, else nearest neighbor //nearest neighbor - added 12 April 2009 for lZi := 0 to (lZ-1) do begin //these values are the same for all voxels in the slice // compute once per slice lZx := lZi*lMat.matrix[1][3]; lZy := lZi*lMat.matrix[2][3]; lZz := lZi*lMat.matrix[3][3]; for lYi := 0 to (lY-1) do begin //these values change once per row // compute once per row lYx := lYi*lMat.matrix[1][2]; lYy := lYi*lMat.matrix[2][2]; lYz := lYi*lMat.matrix[3][2]; for lXi := 0 to (lX-1) do begin //compute each column inc(lPos); lXo := round(lXx^[lXi]+lYx+lZx+lMat.matrix[1][4]); lYo := round(lXy^[lXi]+lYy+lZy+lMat.matrix[2][4]); lZo := round(lXz^[lXi]+lYz+lZz+lMat.matrix[3][4]); //need to test Xreal as -0.01 truncates to zero if (lXo >= 0) and (lYo >= 0{1}) and (lZo >= 0{1}) and (lXo < (lXs)) and (lYo < (lYs) ) and (lZo < (lZs)) //2012 removed -1 for nearest neighbor (lXo < (lXs -1)) and (lYo < (lYs -1) ) and (lZo < (lZs)) then begin lOverlap := true; inc(lXo);//images incremented from 1 not 0 lYo := lYo*lXs; lZo := lZo*lXYs; case lSrcHdr.ImgBufferBPP of 1 : l8i^[lPos] :=l8is^[lXo+lYo+lZo]; 2: l16i^[lPos] :=l16is^[lXo+lYo+lZo]; 4: l32f^[lPos] :=l32fs^[lXo+lYo+lZo] ; end; //case end; //if voxel is in source image's bounding box end;//z end;//y end;//z //end nearest neighbor end; //release lookup tables freemem(lXx); freemem(lXy); freemem(lXz); //check to see if image is empty... if not lOverlap then Showmessage('No overlap between overlay and background - these images do not appear coregistered.'); if lSrcHdr.ImgBufferBPP = 4 then begin FreeMem(lSrcHdr.ImgBufferUnaligned); GetMem(lSrcHdr.ImgBufferUnaligned ,(lOutVolItems*sizeof(Single)) + 16); {$IFDEF FPC} lSrcHdr.ImgBuffer := align(lSrcHdr.ImgBufferUnaligned,16); {$ELSE} lSrcHdr.ImgBuffer := ByteP($fffffff0 and (integer(lSrcHdr.ImgBufferUnaligned)+15)); {$ENDIF} lSrcHdr.ImgBufferItems := lOutVolItems; move(l32f^,lSrcHdr.ImgBuffer^,(lOutVolItems*sizeof(Single))); FreeMem(lBuffOutUnaligned); end else if lSrcHdr.ImgBufferBPP = 2 then begin FreeMem(lSrcHdr.ImgBufferUnaligned); GetMem(lSrcHdr.ImgBufferUnaligned ,(lOutVolItems*sizeof(SmallInt)) + 16); {$IFDEF FPC} lSrcHdr.ImgBuffer := align(lSrcHdr.ImgBufferUnaligned,16); {$ELSE} lSrcHdr.ImgBuffer := ByteP($fffffff0 and (integer(lSrcHdr.ImgBufferUnaligned)+15)); {$ENDIF} lSrcHdr.ImgBufferItems := lOutVolItems; //CopyMemory(Pointer(lSrcHdr.ImgBuffer),Pointer(l16i),(lOutVolItems*sizeof(SmallInt))); move(l16i^,lSrcHdr.ImgBuffer^,(lOutVolItems*sizeof(SmallInt))); FreeMem(lBuffOutUnaligned); end else if lSrcHdr.ImgBufferBPP = 1 then begin FreeMem(lSrcHdr.ImgBufferUnaligned); GetMem(lSrcHdr.ImgBufferUnaligned ,lOutVolItems + 16); {$IFDEF FPC} lSrcHdr.ImgBuffer := align(lSrcHdr.ImgBufferUnaligned,16); {$ELSE} lSrcHdr.ImgBuffer := ByteP($fffffff0 and (integer(lSrcHdr.ImgBufferUnaligned)+15)); {$ENDIF} lSrcHdr.ImgBufferItems := lOutVolItems; //CopyMemory(Pointer(lSrcHdr.ImgBuffer),Pointer(l8i),lOutVolItems); move(l8i^,lSrcHdr.ImgBuffer^,lOutVolItems); FreeMem(l8i); end; lSrcHdr.NIfTIHdr := lDestHdr; //header inherits coordinates of target end; function Hdr2InvMat (lHdr: TNiftiHdr; var lOK: boolean): TMatrix; var lSrcMat,lSrcMatInv: TMatrix; begin lSrcMat := Hdr2Mat( lHdr); lSrcMatInv := lSrcMat; lOK := gaussj(lSrcMatInv); //the vectors should be rows not columns.... //therefore we transpose the matrix //use this if you use transform instead of coord //Transposemat(lSrcMatInv); result := lSrcMatInv; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_macscriptintel.bat������������������������������������������������0000755�0001750�0001750�00000001622�12306747062�020063� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������chmod 777 ./_xclean.bat ./_xclean.bat cp ./common/notgui.inc ./common/isgui.inc lazbuild ./dcm2nii/dcm2nii.lpr --cpu=x86_64 --compiler="/usr/local/bin/ppcx64" mv ./dcm2nii/dcm2nii ../distro/dcm2nii64 lazbuild ./dcm2nii/dcm2nii.lpr cp ./dcm2nii/dcm2nii ../distro/intel/dcm2nii #assume we will not lipo PPC versions... cp ./dcm2nii/dcm2nii ../distro/dcm2nii ./_xclean.bat cp ./common/gui.inc ./common/isgui.inc lazbuild ./mricron.lpr --ws=carbon lazbuild ./npm/npm.lpr --ws=carbon lazbuild ./dcm2nii/dcm2niigui.lpr --ws=carbon cp ./mricron ../distro/intel/mricron cp ./npm/npm ../distro/intel/npm cp ./dcm2nii/dcm2niigui ../distro/intel/dcm2niigui #assume we will not lipo PPC versions... cp ./dcm2nii/dcm2nii ../distro/dcm2nii cp ./mricron ../distro/mricron.app/contents/MacOS/mricron cp ./npm/npm ../distro/npm.app/contents/MacOS/npm cp ./dcm2nii/dcm2niigui ../distro/dcm2niigui.app/contents/MacOS/dcm2niigui ��������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/autoroi.lrs��������������������������������������������������������0000755�0001750�0001750�00000007112�11540216612�016406� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TAutoROIForm','FORMDATA',[ 'TPF0'#12'TAutoROIForm'#11'AutoROIForm'#4'Left'#3#17#3#6'Height'#3'c'#1#3'Top' +#3#200#0#5'Width'#3#9#1#18'HorzScrollBar.Page'#3#8#1#18'VertScrollBar.Page'#3 +'b'#1#13'ActiveControl'#7#12'VarianceEdit'#7'Caption'#6#10'Create ROI'#12'Cl' +'ientHeight'#3'c'#1#11'ClientWidth'#3#9#1#21'Constraints.MaxHeight'#3'c'#1#20 +'Constraints.MaxWidth'#3#9#1#21'Constraints.MinHeight'#3'c'#1#20'Constraints' +'.MinWidth'#3#9#1#9'Font.Name'#6#13'MS Sans Serif'#8'OnCreate'#7#10'FormCrea' +'te'#9'OnDestroy'#7#11'FormDestroy'#6'OnHide'#7#8'FormHide'#6'OnShow'#7#8'Fo' +'rmShow'#8'Position'#7#14'poScreenCenter'#10'LCLVersion'#6#8'0.9.28.2'#0#6'T' +'Label'#11'OriginLabel'#4'Left'#2#4#6'Height'#2#18#3'Top'#2'*'#5'Width'#2'0' +#7'Caption'#6#8'Origin: '#11'ParentColor'#8#0#0#12'TSpeedButton'#9'OriginBtn' +#4'Left'#2#7#6'Height'#2#25#4'Hint'#6'&You can also double-click on the imag' +'e'#3'Top'#2#5#5'Width'#2'r'#7'Caption'#6#12'Reset origin'#5'Color'#7#9'clBt' +'nFace'#9'NumGlyphs'#2#0#7'OnClick'#7#14'OriginBtnClick'#8'ShowHint'#9#14'Pa' +'rentShowHint'#8#0#0#6'TLabel'#9'DiffLabel'#4'Left'#2#12#6'Height'#2#18#3'To' +'p'#2'b'#5'Width'#3#147#0#7'Caption'#6#22'Difference from origin'#11'ParentC' +'olor'#8#0#0#6'TLabel'#6'Label1'#4'Left'#2#12#6'Height'#2#18#3'Top'#3#132#0#5 +'Width'#3#130#0#7'Caption'#6#18'Difference at edge'#11'ParentColor'#8#0#0#6 +'TLabel'#6'Label2'#4'Left'#2#12#6'Height'#2#18#3'Top'#3#167#0#5'Width'#2'U'#7 +'Caption'#6#11'Radius (mm)'#11'ParentColor'#8#0#0#6'TLabel'#6'Label3'#4'Left' +#2#12#6'Height'#2#18#3'Top'#3#202#0#5'Width'#3#129#0#7'Caption'#6#19'Erode/d' +'ilate cycles'#11'ParentColor'#8#0#0#12'TSpeedButton'#10'AutoROIBtn'#4'Left' +#2'8'#6'Height'#2#25#3'Top'#3'0'#1#5'Width'#2'A'#7'Caption'#6#5'Apply'#5'Col' +'or'#7#9'clBtnFace'#9'NumGlyphs'#2#0#7'OnClick'#7#15'AutoROIBtnClick'#0#0#12 +'TSpeedButton'#9'CancelBtn'#4'Left'#2'x'#6'Height'#2#25#3'Top'#3'0'#1#5'Widt' +'h'#2'A'#7'Caption'#6#6'Cancel'#5'Color'#7#9'clBtnFace'#9'NumGlyphs'#2#0#7'O' +'nClick'#7#14'CancelBtnClick'#0#0#6'TLabel'#6'Label4'#4'Left'#2#4#6'Height'#2 +#18#3'Top'#2'J'#5'Width'#2'O'#7'Caption'#6#11'Constraints'#11'ParentColor'#8 +#0#0#9'TCheckBox'#17'ExcludeBlackCheck'#4'Left'#2#12#6'Height'#2#21#3'Top'#3 +#236#0#5'Width'#3#230#0#7'Caption'#6#30'Zero intensity constrains edge'#7'On' +'Click'#7#13'AutoROIchange'#8'TabOrder'#2#0#0#0#9'TSpinEdit'#12'VarianceEdit' +#4'Left'#3#173#0#6'Height'#2#27#3'Top'#2'Z'#5'Width'#2'H'#8'MaxValue'#3#255#0 +#8'OnChange'#7#13'AutoROIchange'#8'TabOrder'#2#1#5'Value'#2#16#0#0#9'TSpinEd' +'it'#8'EdgeEdit'#4'Left'#3#173#0#6'Height'#2#27#3'Top'#2'~'#5'Width'#2'H'#8 +'MaxValue'#3#255#0#8'OnChange'#7#13'AutoROIchange'#8'TabOrder'#2#2#5'Value'#2 +#16#0#0#9'TSpinEdit'#10'RadiusEdit'#4'Left'#3#173#0#6'Height'#2#27#3'Top'#3 +#161#0#5'Width'#2'H'#8'MaxValue'#3#15''''#8'OnChange'#7#13'AutoROIchange'#8 +'TabOrder'#2#3#5'Value'#2' '#0#0#9'TSpinEdit'#9'ErodeEdit'#4'Left'#3#173#0#6 +'Height'#2#27#3'Top'#3#196#0#5'Width'#2'H'#8'MaxValue'#2#12#8'OnChange'#7#13 +'AutoROIchange'#8'TabOrder'#2#4#0#0#9'TComboBox'#13'ROIconstraint'#4'Left'#2 +#12#6'Height'#2#31#3'Top'#3#12#1#5'Width'#3#212#0#10'ItemHeight'#2#0#13'Item' +'s.Strings'#1#6#21'Append to current VOI'#6#23'Delete from current VOI'#6#25 +'Constain with current VOI'#0#8'OnChange'#7#13'AutoROIchange'#5'Style'#7#14 +'csDropDownList'#8'TabOrder'#2#5#0#0#6'TTimer'#6'Timer1'#7'Enabled'#8#8'Inte' +'rval'#3#144#1#7'OnTimer'#7#11'Timer1Timer'#4'left'#2'('#3'top'#2'"'#0#0#0 ]); ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_gtall.bat���������������������������������������������������������0000755�0001750�0001750�00000000254�11265704062�016141� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� cd ~/mricron chmod 777 ./_gtscript.bat ./_gtscript.bat cd ~/gtk1 zip -r mricronlx mricron mv mricronlx.zip .. cd ~/gtk2 zip -r mricronlx2 mricron mv mricronlx2.zip .. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/nifti_hdr_view.lrs�������������������������������������������������0000755�0001750�0001750�00000071031�12307406616�017734� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('THdrForm','FORMDATA',[ 'TPF0'#8'THdrForm'#7'HdrForm'#4'Left'#3'q'#1#6'Height'#3#162#1#3'Top'#3#154#0 +#5'Width'#3#30#2#13'ActiveControl'#7#12'PageControl1'#11'BorderIcons'#11#12 +'biSystemMenu'#0#11'BorderStyle'#7#8'bsSingle'#7'Caption'#6#24'NIfTI Header ' +'Information'#12'ClientHeight'#3#162#1#11'ClientWidth'#3#30#2#21'Constraints' +'.MaxHeight'#3#162#1#20'Constraints.MaxWidth'#3#30#2#21'Constraints.MinHeigh' +'t'#3#162#1#20'Constraints.MinWidth'#3#30#2#9'Font.Name'#6#13'MS Sans Serif' +#4'Menu'#7#9'MainMenu1'#8'OnCreate'#7#10'FormCreate'#6'OnShow'#7#8'FormShow' +#8'Position'#7#14'poScreenCenter'#10'LCLVersion'#6#8'1.0.12.0'#0#12'TPageCon' +'trol'#12'PageControl1'#4'Left'#2#4#6'Height'#3#139#1#3'Top'#2#4#5'Width'#3 +#22#2#10'ActivePage'#7#11'TabRequired'#5'Align'#7#8'alClient'#18'BorderSpaci' +'ng.Left'#2#2#17'BorderSpacing.Top'#2#2#19'BorderSpacing.Right'#2#2#20'Borde' +'rSpacing.Bottom'#2#2#20'BorderSpacing.Around'#2#2#8'TabIndex'#2#0#8'TabOrde' +'r'#2#0#0#9'TTabSheet'#11'TabRequired'#7'Caption'#6#10'Dimensions'#12'Client' +'Height'#3'd'#1#11'ClientWidth'#3#16#2#0#6'TLabel'#7'Label21'#4'Left'#2#6#6 +'Height'#2#18#3'Top'#2#6#5'Width'#2'P'#7'Caption'#6#11'Header Type'#11'Paren' +'tColor'#8#0#0#6'TLabel'#6'Label1'#4'Left'#2#14#6'Height'#2#18#3'Top'#2'#'#5 +'Width'#3#13#1#7'Caption'#6'.Dimension Length Spacing Unit' +#9'Font.Name'#6#13'MS Sans Serif'#11'ParentColor'#8#10'ParentFont'#8#0#0#6'T' +'Label'#6'Label2'#4'Left'#2#16#6'Height'#2#18#3'Top'#2'C'#5'Width'#2'.'#7'Ca' +'ption'#6#7'I Space'#11'ParentColor'#8#0#0#6'TLabel'#6'Label3'#4'Left'#2#16#6 +'Height'#2#18#3'Top'#2'a'#5'Width'#2'1'#7'Caption'#6#7'J Space'#11'ParentCol' +'or'#8#0#0#6'TLabel'#6'Label4'#4'Left'#2#16#6'Height'#2#18#3'Top'#3#131#0#5 +'Width'#2'3'#7'Caption'#6#7'K Space'#11'ParentColor'#8#0#0#6'TLabel'#6'Label' +'8'#4'Left'#2#6#6'Height'#2#18#3'Top'#3')'#1#5'Width'#2#30#7'Caption'#6#4'Da' +'ta'#11'ParentColor'#8#0#0#6'TLabel'#6'Label7'#4'Left'#3'&'#1#6'Height'#2#18 +#3'Top'#3#235#0#5'Width'#2')'#7'Caption'#6#6'Offset'#11'ParentColor'#8#0#0#6 +'TLabel'#7'Label44'#4'Left'#2#16#6'Height'#2#18#3'Top'#3#166#0#5'Width'#2#31 +#7'Caption'#6#4'Time'#11'ParentColor'#8#0#0#6'TLabel'#7'Label29'#4'Left'#2#16 +#6'Height'#2#18#3'Top'#3#198#0#5'Width'#2'3'#7'Caption'#6#7'5th Dim'#11'Pare' +'ntColor'#8#0#0#6'TLabel'#7'Label41'#4'Left'#2#16#6'Height'#2#18#3'Top'#3#230 +#0#5'Width'#2'3'#7'Caption'#6#7'6th Dim'#11'ParentColor'#8#0#0#6'TLabel'#7'L' +'abel42'#4'Left'#2#16#6'Height'#2#18#3'Top'#3#9#1#5'Width'#2'3'#7'Caption'#6 +#7'7th Dim'#11'ParentColor'#8#0#0#9'TComboBox'#15'HeaderMagicDrop'#4'Left'#2 +'l'#6'Height'#2#20#3'Top'#2#2#5'Width'#3#239#0#10'ItemHeight'#2#0#13'Items.S' +'trings'#1#6#7'Unknown'#6'#ni1: NIfTI separate file (hdr+.img)'#6#28'n+1: NI' +'fTI embedded (.nii)'#6'$ni2: NIfTI2 separate file (hdr+.img)'#6#29'n+2: N' +'IfTI2 embedded (.nii)'#0#8'OnSelect'#7#21'HeaderMagicDropSelect'#5'Style' +#7#14'csDropDownList'#8'TabOrder'#2#15#0#0#9'TComboBox'#6'Endian'#4'Left'#3 +#231#0#6'Height'#2#20#3'Top'#3'#'#1#5'Width'#3#210#0#10'ItemHeight'#2#0#13'I' +'tems.Strings'#1#6#13'Native Endian'#6#14'Swapped Endian'#0#5'Style'#7#14'cs' +'DropDownList'#8'TabOrder'#2#16#0#0#9'TComboBox'#9'fTypeDrop'#4'Left'#2'8'#6 +'Height'#2#20#3'Top'#3'#'#1#5'Width'#3#152#0#13'DropDownCount'#2#20#10'ItemH' +'eight'#2#0#13'Items.Strings'#1#6#6'binary'#6#7'8-bit S'#6#12'8-bit int U*'#6 +#13'16-bit int S*'#6#12'16-bit int U'#6#13'32-bit int S*'#6#12'32-bit int U' +#6#12'64-bit int S'#6#12'64-bit int U'#6#12'32-bit real*'#6#12'64-bit real*' +#6#12'128-bit real'#6#10'24-bit rgb'#6#10'64-bit com'#6#15'128-bit complex'#6 +#15'256-bit complex'#0#8'OnSelect'#7#13'ImageSzChange'#5'Style'#7#14'csDropD' +'ownList'#8'TabOrder'#2#17#0#0#9'TComboBox'#13'xyzt_sizeDrop'#4'Left'#3#6#1#6 +'Height'#2#20#3'Top'#2'W'#5'Width'#3#128#0#10'ItemHeight'#2#0#13'Items.Strin' +'gs'#1#6#7'Unknown'#6#5'Meter'#6#10'Millimeter'#6#10'Micrometer'#6#6'Micron' +#0#5'Style'#7#14'csDropDownList'#8'TabOrder'#2#18#0#0#9'TComboBox'#13'xyzt_t' +'imeDrop'#4'Left'#3#6#1#6'Height'#2#20#3'Top'#3#157#0#5'Width'#3#128#0#10'It' +'emHeight'#2#0#13'Items.Strings'#1#6#7'Unknown'#6#6'Second'#6#11'Millisecond' +#6#11'Microsecond'#6#11'Hertzsecond'#6#5'Part '#6#16'Part per million'#0#5'S' +'tyle'#7#14'csDropDownList'#8'TabOrder'#2#19#0#0#9'TSpinEdit'#4'Xdim'#4'Left' +#2'P'#6'Height'#2#16#3'Top'#2';'#5'Width'#2'J'#8'MaxValue'#3#15''''#8'MinVal' +'ue'#2#1#6'OnExit'#7#13'ImageSzChange'#8'TabOrder'#2#0#5'Value'#2#2#0#0#9'TS' +'pinEdit'#4'Ydim'#4'Left'#2'P'#6'Height'#2#16#3'Top'#2'Y'#5'Width'#2'J'#8'Ma' +'xValue'#3#15''''#8'MinValue'#2#1#8'OnChange'#7#13'ImageSzChange'#6'OnExit'#7 +#13'ImageSzChange'#8'TabOrder'#2#1#5'Value'#2#2#0#0#9'TSpinEdit'#4'Zdim'#4'L' +'eft'#2'P'#6'Height'#2#16#3'Top'#2'{'#5'Width'#2'J'#8'MaxValue'#3#15''''#8'M' +'inValue'#2#1#8'OnChange'#7#13'ImageSzChange'#6'OnExit'#7#13'ImageSzChange'#8 +'TabOrder'#2#2#5'Value'#2#1#0#0#14'TFloatSpinEdit'#3'Xmm'#4'Left'#3#164#0#6 +'Height'#2#16#3'Top'#2';'#5'Width'#2'J'#9'Increment'#5#0#0#0#0#0#0#0#128#255 ,'?'#8'MaxValue'#5#0#0#0#0#224#31#188#190#25'@'#8'MinValue'#5#0#0#0#0#224#31 +#188#190#25#192#8'TabOrder'#2#10#5'Value'#5#0#0#0#0#0#0#0#0#0#0#0#0#14'TFloa' +'tSpinEdit'#3'Ymm'#4'Left'#3#164#0#6'Height'#2#16#3'Top'#2'Y'#5'Width'#2'J'#9 +'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#224#31#188#190 +#25'@'#8'MinValue'#5#0#0#0#0#224#31#188#190#25#192#8'TabOrder'#2#11#5'Value' +#5#0#0#0#0#0#0#0#0#0#0#0#0#14'TFloatSpinEdit'#3'Zmm'#4'Left'#3#164#0#6'Heigh' +'t'#2#16#3'Top'#2'{'#5'Width'#2'J'#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8 +'MaxValue'#5#0#0#0#0#224#31#188#190#25'@'#8'MinValue'#5#0#0#0#0#224#31#188 +#190#25#192#8'TabOrder'#2#12#5'Value'#5#0#0#0#0#0#0#0#0#0#0#0#0#9'TSpinEdit' +#10'OffsetEdit'#4'Left'#3'V'#1#6'Height'#2#16#3'Top'#3#230#0#5'Width'#2'^'#8 +'MaxValue'#4'?B'#15#0#6'OnExit'#7#13'ImageSzChange'#8'TabOrder'#2#14#5'Value' +#2#1#0#0#9'TSpinEdit'#4'TDim'#4'Left'#2'P'#6'Height'#2#16#3'Top'#3#157#0#5'W' +'idth'#2'J'#8'MaxValue'#3#15''''#8'MinValue'#2#1#8'OnChange'#7#13'ImageSzCha' +'nge'#6'OnExit'#7#13'ImageSzChange'#8'TabOrder'#2#3#5'Value'#2#1#0#0#14'TFlo' +'atSpinEdit'#4'TSec'#4'Left'#3#164#0#6'Height'#2#16#3'Top'#3#157#0#5'Width'#2 +'J'#13'DecimalPlaces'#2#4#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue' +#5#0#0#0#0#224#31#188#190#25'@'#8'MinValue'#5#0#0#0#0#224#31#188#190#25#192#8 +'TabOrder'#2#13#5'Value'#5#0#0#0#0#0#0#0#0#0#0#0#0#9'TSpinEdit'#8'Dim5Edit'#4 +'Left'#2'P'#6'Height'#2#16#3'Top'#3#191#0#5'Width'#2'J'#8'MaxValue'#4#184#136 +#0#0#8'MinValue'#2#1#8'OnChange'#7#13'ImageSzChange'#6'OnExit'#7#13'ImageSzC' +'hange'#8'TabOrder'#2#4#5'Value'#2#1#0#0#9'TSpinEdit'#8'Dim6Edit'#4'Left'#2 +'P'#6'Height'#2#16#3'Top'#3#223#0#5'Width'#2'J'#8'MaxValue'#4#184#136#0#0#8 +'MinValue'#2#1#8'OnChange'#7#13'ImageSzChange'#6'OnExit'#7#13'ImageSzChange' +#8'TabOrder'#2#5#5'Value'#2#1#0#0#9'TSpinEdit'#8'Dim7Edit'#4'Left'#2'P'#6'He' +'ight'#2#16#3'Top'#3#2#1#5'Width'#2'J'#8'MaxValue'#4#184#136#0#0#8'MinValue' +#2#1#8'OnChange'#7#13'ImageSzChange'#6'OnExit'#7#13'ImageSzChange'#8'TabOrde' +'r'#2#9#5'Value'#2#1#0#0#14'TFloatSpinEdit'#7'PixDim5'#4'Left'#3#164#0#6'Hei' +'ght'#2#16#3'Top'#3#191#0#5'Width'#2'J'#13'DecimalPlaces'#2#4#9'Increment'#5 +#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#224#31#188#190#25'@'#8'MinVa' +'lue'#5#0#0#0#0#224#31#188#190#25#192#8'TabOrder'#2#6#5'Value'#5#0#0#0#0#0#0 +#0#0#0#0#0#0#14'TFloatSpinEdit'#7'PixDim6'#4'Left'#3#164#0#6'Height'#2#16#3 +'Top'#3#223#0#5'Width'#2'J'#13'DecimalPlaces'#2#4#9'Increment'#5#0#0#0#0#0#0 +#0#128#255'?'#8'MaxValue'#5#0#0#0#0#224#31#188#190#25'@'#8'MinValue'#5#0#0#0 +#0#224#31#188#190#25#192#8'TabOrder'#2#7#5'Value'#5#0#0#0#0#0#0#0#0#0#0#0#0 +#14'TFloatSpinEdit'#7'PixDim7'#4'Left'#3#164#0#6'Height'#2#16#3'Top'#3#2#1#5 +'Width'#2'J'#13'DecimalPlaces'#2#4#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8 +'MaxValue'#5#0#0#0#0#224#31#188#190#25'@'#8'MinValue'#5#0#0#0#0#224#31#188 +#190#25#192#8'TabOrder'#2#8#5'Value'#5#0#0#0#0#0#0#0#0#0#0#0#0#0#9'TTabSheet' +#9'TabSheet4'#7'Caption'#6#8'Reorient'#12'ClientHeight'#3'd'#1#11'ClientWidt' +'h'#3#16#2#0#6'TLabel'#7'Label24'#4'Left'#2#10#6'Height'#2#18#3'Top'#3#184#0 +#5'Width'#2#9#7'Caption'#6#1'X'#11'ParentColor'#8#0#0#6'TLabel'#7'Label36'#4 +'Left'#2#10#6'Height'#2#18#3'Top'#3#218#0#5'Width'#2#9#7'Caption'#6#1'Y'#11 +'ParentColor'#8#0#0#6'TLabel'#7'Label37'#4'Left'#2#10#6'Height'#2#18#3'Top'#3 +#251#0#5'Width'#2#8#7'Caption'#6#1'Z'#11'ParentColor'#8#0#0#6'TLabel'#7'Labe' +'l39'#4'Left'#2#10#6'Height'#2#18#3'Top'#2'{'#5'Width'#2'='#7'Caption'#6#9'Q' +' Offsets'#11'ParentColor'#8#0#0#6'TLabel'#7'Label40'#4'Left'#2#10#6'Height' +#2#18#3'Top'#2'V'#5'Width'#2'L'#7'Caption'#6#11'Quaternions'#11'ParentColor' +#8#0#0#6'TLabel'#7'Label46'#4'Left'#2#10#6'Height'#2#18#3'Top'#2'.'#5'Width' +#2'm'#7'Caption'#6#17'qFactor [1 or -1]'#11'ParentColor'#8#0#0#6'TLabel'#7'L' +'abel38'#4'Left'#2#4#6'Height'#2#18#3'Top'#2#9#5'Width'#3#150#0#7'Caption'#6 +#22'Quaternion parameters '#11'ParentColor'#8#0#0#6'TLabel'#7'Label47'#4'Lef' +'t'#2#4#6'Height'#2#18#3'Top'#3#157#0#5'Width'#2'v'#7'Caption'#6#18'Affine p' +'arameters '#11'ParentColor'#8#0#0#9'TComboBox'#9'QFormDrop'#4'Left'#3#150#0 +#6'Height'#2#20#3'Top'#2#5#5'Width'#3#4#1#10'ItemHeight'#2#0#13'Items.String' +'s'#1#6#4'None'#6#16'Scanner Position'#6#16'Coregistrationon'#6#14'Normalize' +'d Tal'#6#20'Normalzied mni152ach'#6#17'Normalzied mni152'#0#8'OnSelect'#7#21 +'HeaderMagicDropSelect'#5'Style'#7#14'csDropDownList'#8'TabOrder'#2#19#0#0#9 +'TComboBox'#9'SFormDrop'#4'Left'#3#145#0#6'Height'#2#20#3'Top'#3#150#0#5'Wid' +'th'#3#204#0#10'ItemHeight'#2#0#13'Items.Strings'#1#6#4'None'#6#16'Scanner P' +'osition'#6#16'Coregistrationon'#6#14'Normalized Tal'#6#20'Normalzied mni152' +'ach'#6#17'Normalzied mni152'#0#8'OnSelect'#7#21'HeaderMagicDropSelect'#5'St' +'yle'#7#14'csDropDownList'#8'TabOrder'#2#20#0#0#14'TFloatSpinEdit'#11'srow_x' +'0Edit'#4'Left'#2'"'#6'Height'#2#16#3'Top'#3#188#0#5'Width'#2'd'#13'DecimalP' +'laces'#2#5#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0#0 ,'<'#156#12'@'#8'MinValue'#5#0#0#0#0#0#0'<'#156#12#192#8'TabOrder'#2#7#5'Valu' +'e'#5#0#0#0#0#0#0#0#128#255'?'#0#0#14'TFloatSpinEdit'#11'srow_x1Edit'#4'Left' +#3#142#0#6'Height'#2#16#3'Top'#3#188#0#5'Width'#2'd'#13'DecimalPlaces'#2#5#9 +'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0#0'<'#156#12'@' +#8'MinValue'#5#0#0#0#0#0#0'<'#156#12#192#8'TabOrder'#2#8#5'Value'#5#0#0#0#0#0 +#0#0#128#255'?'#0#0#14'TFloatSpinEdit'#11'srow_x2Edit'#4'Left'#3#254#0#6'Hei' +'ght'#2#16#3'Top'#3#188#0#5'Width'#2'd'#13'DecimalPlaces'#2#5#9'Increment'#5 +#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0#0'<'#156#12'@'#8'MinValue' +#5#0#0#0#0#0#0'<'#156#12#192#8'TabOrder'#2#9#5'Value'#5#0#0#0#0#0#0#0#128#255 +'?'#0#0#14'TFloatSpinEdit'#11'srow_y0Edit'#4'Left'#2'"'#6'Height'#2#16#3'Top' +#3#222#0#5'Width'#2'd'#13'DecimalPlaces'#2#5#9'Increment'#5#0#0#0#0#0#0#0#128 +#255'?'#8'MaxValue'#5#0#0#0#0#0#0'<'#156#12'@'#8'MinValue'#5#0#0#0#0#0#0'<' +#156#12#192#8'TabOrder'#2#11#5'Value'#5#0#0#0#0#0#0#0#128#255'?'#0#0#14'TFlo' +'atSpinEdit'#11'srow_y1Edit'#4'Left'#3#142#0#6'Height'#2#16#3'Top'#3#222#0#5 +'Width'#2'd'#13'DecimalPlaces'#2#5#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8 +'MaxValue'#5#0#0#0#0#0#0'<'#156#12'@'#8'MinValue'#5#0#0#0#0#0#0'<'#156#12#192 +#8'TabOrder'#2#12#5'Value'#5#0#0#0#0#0#0#0#128#255'?'#0#0#14'TFloatSpinEdit' +#11'srow_y2Edit'#4'Left'#3#254#0#6'Height'#2#16#3'Top'#3#222#0#5'Width'#2'd' +#13'DecimalPlaces'#2#5#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5 +#0#0#0#0#0#0'<'#156#12'@'#8'MinValue'#5#0#0#0#0#0#0'<'#156#12#192#8'TabOrder' +#2#13#5'Value'#5#0#0#0#0#0#0#0#128#255'?'#0#0#14'TFloatSpinEdit'#11'srow_z0E' +'dit'#4'Left'#2'"'#6'Height'#2#16#3'Top'#3#255#0#5'Width'#2'd'#13'DecimalPla' +'ces'#2#5#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0#0 +'<'#156#12'@'#8'MinValue'#5#0#0#0#0#0#0'<'#156#12#192#8'TabOrder'#2#15#5'Val' +'ue'#5#0#0#0#0#0#0#0#128#255'?'#0#0#14'TFloatSpinEdit'#11'srow_z1Edit'#4'Lef' +'t'#3#142#0#6'Height'#2#16#3'Top'#3#255#0#5'Width'#2'd'#13'DecimalPlaces'#2#5 +#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0#0'<'#156#12 +'@'#8'MinValue'#5#0#0#0#0#0#0'<'#156#12#192#8'TabOrder'#2#16#5'Value'#5#0#0#0 +#0#0#0#0#128#255'?'#0#0#14'TFloatSpinEdit'#11'srow_z2Edit'#4'Left'#3#254#0#6 +'Height'#2#16#3'Top'#3#255#0#5'Width'#2'd'#13'DecimalPlaces'#2#5#9'Increment' +#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0#0'<'#156#12'@'#8'MinValu' +'e'#5#0#0#0#0#0#0'<'#156#12#192#8'TabOrder'#2#17#5'Value'#5#0#0#0#0#0#0#0#128 +#255'?'#0#0#14'TFloatSpinEdit'#11'srow_x3Edit'#4'Left'#3'n'#1#6'Height'#2#16 +#3'Top'#3#188#0#5'Width'#2'd'#13'DecimalPlaces'#2#5#9'Increment'#5#0#0#0#0#0 +#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0#0'<'#156#12'@'#8'MinValue'#5#0#0#0#0 +#0#0'<'#156#12#192#8'TabOrder'#2#10#5'Value'#5#0#0#0#0#0#0#0#128#255'?'#0#0 +#14'TFloatSpinEdit'#11'srow_y3Edit'#4'Left'#3'n'#1#6'Height'#2#16#3'Top'#3 +#222#0#5'Width'#2'd'#13'DecimalPlaces'#2#5#9'Increment'#5#0#0#0#0#0#0#0#128 +#255'?'#8'MaxValue'#5#0#0#0#0#0#0'<'#156#12'@'#8'MinValue'#5#0#0#0#0#0#0'<' +#156#12#192#8'TabOrder'#2#14#5'Value'#5#0#0#0#0#0#0#0#128#255'?'#0#0#14'TFlo' +'atSpinEdit'#11'srow_z3Edit'#4'Left'#3'n'#1#6'Height'#2#16#3'Top'#3#255#0#5 +'Width'#2'd'#13'DecimalPlaces'#2#5#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8 +'MaxValue'#5#0#0#0#0#0#0'<'#156#12'@'#8'MinValue'#5#0#0#0#0#0#0'<'#156#12#192 +#8'TabOrder'#2#18#5'Value'#5#0#0#0#0#0#0#0#128#255'?'#0#0#14'TFloatSpinEdit' +#13'quatern_bEdit'#4'Left'#2'^'#6'Height'#2#16#3'Top'#2'T'#5'Width'#2'd'#13 +'DecimalPlaces'#2#5#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0 +#0#0#0#0#0#200#5'@'#8'MinValue'#5#0#0#0#0#0#0#0#0#0#0#8'TabOrder'#2#1#5'Valu' +'e'#5#0#0#0#0#0#0#0#128#255'?'#0#0#14'TFloatSpinEdit'#13'quatern_cEdit'#4'Le' +'ft'#3#212#0#6'Height'#2#16#3'Top'#2'T'#5'Width'#2'd'#13'DecimalPlaces'#2#5#9 +'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0#0#0#200#5'@'#8 +'MinValue'#5#0#0#0#0#0#0#0#0#0#0#8'TabOrder'#2#2#5'Value'#5#0#0#0#0#0#0#0#128 +#255'?'#0#0#14'TFloatSpinEdit'#13'quatern_dEdit'#4'Left'#3'L'#1#6'Height'#2 +#16#3'Top'#2'T'#5'Width'#2'd'#13'DecimalPlaces'#2#5#9'Increment'#5#0#0#0#0#0 +#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0#0#0#200#5'@'#8'MinValue'#5#0#0#0#0#0 +#0#0#0#0#0#8'TabOrder'#2#3#5'Value'#5#0#0#0#0#0#0#0#128#255'?'#0#0#14'TFloat' +'SpinEdit'#13'qoffset_xEdit'#4'Left'#2'^'#6'Height'#2#16#3'Top'#2'u'#5'Width' +#2'd'#13'DecimalPlaces'#2#5#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxVal' +'ue'#5#0#0#0#0#0#0#0#200#5'@'#8'MinValue'#5#0#0#0#0#0#0#0#0#0#0#8'TabOrder'#2 +#4#5'Value'#5#0#0#0#0#0#0#0#128#255'?'#0#0#14'TFloatSpinEdit'#13'qoffset_yEd' +'it'#4'Left'#3#212#0#6'Height'#2#16#3'Top'#2'u'#5'Width'#2'd'#13'DecimalPlac' +'es'#2#5#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0#0#0 +#200#5'@'#8'MinValue'#5#0#0#0#0#0#0#0#0#0#0#8'TabOrder'#2#5#5'Value'#5#0#0#0 +#0#0#0#0#128#255'?'#0#0#14'TFloatSpinEdit'#13'qoffset_zEdit'#4'Left'#3'L'#1#6 +'Height'#2#16#3'Top'#2'u'#5'Width'#2'd'#13'DecimalPlaces'#2#5#9'Increment'#5 ,#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0#0#0#200#5'@'#8'MinValue'#5 +#0#0#0#0#0#0#0#0#0#0#8'TabOrder'#2#6#5'Value'#5#0#0#0#0#0#0#0#128#255'?'#0#0 +#14'TFloatSpinEdit'#8'QFacEdit'#4'Left'#3#140#0#6'Height'#2#16#3'Top'#2'.'#5 +'Width'#2'd'#13'DecimalPlaces'#2#5#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8 +'MaxValue'#5#0#0#0#0#0#0#0#128#255'?'#8'MinValue'#5#0#0#0#0#0#0#0#128#255#191 +#8'TabOrder'#2#0#5'Value'#5#0#0#0#0#0#0#0#128#255'?'#0#0#0#9'TTabSheet'#9'Ta' +'bSheet3'#7'Caption'#6#15'Image Intensity'#12'ClientHeight'#3'R'#1#11'Client' +'Width'#3#14#2#0#6'TLabel'#7'Label12'#4'Left'#2#24#6'Height'#2#17#3'Top'#3 +#163#0#5'Width'#2':'#7'Caption'#6#7'Maximum'#11'ParentColor'#8#0#0#6'TLabel' +#7'Label13'#4'Left'#2#24#6'Height'#2#17#3'Top'#3#129#0#5'Width'#2'6'#7'Capti' +'on'#6#7'Minimum'#11'ParentColor'#8#0#0#6'TLabel'#7'Label23'#4'Left'#2#24#6 +'Height'#2#17#3'Top'#2#28#5'Width'#2'%'#7'Caption'#6#5'Slope'#11'ParentColor' +#8#0#0#6'TLabel'#7'Label22'#4'Left'#2#24#6'Height'#2#17#3'Top'#2'@'#5'Width' +#2'4'#7'Caption'#6#9'Intercept'#11'ParentColor'#8#0#0#6'TLabel'#7'Label30'#4 +'Left'#2#6#6'Height'#2#17#3'Top'#2#4#5'Width'#2'q'#7'Caption'#6#19'Calibrati' +'on Scaling'#11'ParentColor'#8#0#0#6'TLabel'#7'Label33'#4'Left'#2#6#6'Height' +#2#17#3'Top'#2'g'#5'Width'#3#192#0#7'Caption'#6' Display Range (calibrated u' +'nits)'#11'ParentColor'#8#0#0#14'TFloatSpinEdit'#4'cmax'#4'Left'#2'^'#6'Heig' +'ht'#2#16#3'Top'#3#165#0#5'Width'#2'n'#13'DecimalPlaces'#2#5#9'Increment'#5#0 +#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#224#31#188#190#25'@'#8'MinValu' +'e'#5#0#0#0#0#224#31#188#190#25#192#8'TabOrder'#2#3#5'Value'#5#0#0#0#0#0#0#0 +#0#0#0#0#0#14'TFloatSpinEdit'#4'cmin'#4'Left'#2'^'#6'Height'#2#16#3'Top'#3 +#129#0#5'Width'#2'n'#13'DecimalPlaces'#2#5#9'Increment'#5#0#0#0#0#0#0#0#128 +#255'?'#8'MaxValue'#5#0#0#0#0#224#31#188#190#25'@'#8'MinValue'#5#0#0#0#0#224 +#31#188#190#25#192#8'TabOrder'#2#2#5'Value'#5#0#0#0#0#0#0#0#0#0#0#0#0#14'TFl' +'oatSpinEdit'#5'Scale'#4'Left'#2'^'#6'Height'#2#16#3'Top'#2#28#5'Width'#2'n' +#13'DecimalPlaces'#2#5#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5 +#0#0#0#0#224#31#188#190#25'@'#8'MinValue'#5#0#0#0#0#224#31#188#190#25#192#8 +'TabOrder'#2#0#5'Value'#5#0#0#0#0#0#0#0#0#0#0#0#0#14'TFloatSpinEdit'#9'Inter' +'cept'#4'Left'#2'^'#6'Height'#2#16#3'Top'#2'@'#5'Width'#2'n'#13'DecimalPlace' +'s'#2#5#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#224#31 +#188#190#25'@'#8'MinValue'#5#0#0#0#0#224#31#188#190#25#192#8'TabOrder'#2#1#5 +'Value'#5#0#0#0#0#0#0#0#0#0#0#0#0#0#9'TTabSheet'#9'TabSheet1'#7'Caption'#6#10 +'Statistics'#12'ClientHeight'#3'd'#1#11'ClientWidth'#3#16#2#0#6'TLabel'#7'La' +'bel35'#4'Left'#2#8#6'Height'#2#18#3'Top'#2#14#5'Width'#2'9'#7'Caption'#6#9 +'Intention'#11'ParentColor'#8#0#0#6'TLabel'#7'Label25'#4'Left'#2#24#6'Height' +#2#18#3'Top'#2'.'#5'Width'#2'N'#7'Caption'#6#11'Parameter 1'#11'ParentColor' +#8#0#0#6'TLabel'#7'Label27'#4'Left'#2#24#6'Height'#2#18#3'Top'#2'S'#5'Width' +#2'N'#7'Caption'#6#11'Parameter 2'#11'ParentColor'#8#0#0#6'TLabel'#7'Label28' +#4'Left'#2#24#6'Height'#2#18#3'Top'#2'v'#5'Width'#2'N'#7'Caption'#6#11'Param' +'eter 3'#11'ParentColor'#8#0#0#9'TComboBox'#14'IntentCodeDrop'#4'Left'#2'L'#6 +'Height'#2#20#3'Top'#2#8#5'Width'#3#218#0#13'DropDownCount'#2','#10'ItemHeig' +'ht'#2#0#13'Items.Strings'#1#6#14'Not statistics'#6#24'Correlation coefficie' +'nt '#6#24'T-testation coefficient '#6#6'F-test'#6#7'Z-score'#6#11'Chi-squar' +'ed'#6#11'Beta distri'#6#21'Binomial distribution'#6#18'Gamma distribution'#6 +#18'Gamma distribution'#6#19'Normal distribution'#6#22'Noncentral F statisti' +'c'#6#22'Noncentral chi-squared'#6' Logistic distributiond statistic'#6#20'L' +'aplace distribution'#6#20'Uniform distribution'#6#22'Noncentral t statistic' +#6#20'Weibull distribution'#6#16'Chi distribution'#6#17'Inverse Gaussian '#6 +#20'Extreme value type I'#6#20'p-value value type I'#6#11'ln(p-value)'#6#11 +'log10(p-val'#6#14'Estimatevalue)'#6#6'Labels'#6#6'NeuroN'#6#9'Generic M'#6 +#16'Symmetric Matrix'#6#25'Displacement Field/Vector'#6#25'Vectorcement Fiel' +'d/Vector'#6#6'Points'#6#15'Triangle (mesh)'#6#10'Quaternion'#0#5'Style'#7#14 +'csDropDownList'#8'TabOrder'#2#3#0#0#14'TFloatSpinEdit'#13'intent_p1Edit'#4 +'Left'#2'n'#6'Height'#2#16#3'Top'#2'.'#5'Width'#3#138#0#13'DecimalPlaces'#2#5 +#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#224#31#188#190 +#25'@'#8'MinValue'#5#0#0#0#0#224#31#188#190#25#192#8'TabOrder'#2#0#5'Value'#5 +#0#0#0#0#0#0#0#0#0#0#0#0#14'TFloatSpinEdit'#13'intent_p2Edit'#4'Left'#2'n'#6 +'Height'#2#16#3'Top'#2'S'#5'Width'#3#138#0#13'DecimalPlaces'#2#5#9'Increment' +#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#224#31#188#190#25'@'#8'Min' +'Value'#5#0#0#0#0#224#31#188#190#25#192#8'TabOrder'#2#1#5'Value'#5#0#0#0#0#0 +#0#0#0#0#0#0#0#14'TFloatSpinEdit'#13'intent_p3Edit'#4'Left'#2'n'#6'Height'#2 +#16#3'Top'#2'w'#5'Width'#3#138#0#13'DecimalPlaces'#2#5#9'Increment'#5#0#0#0#0 +#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#224#31#188#190#25'@'#8'MinValue'#5#0 ,#0#0#0#224#31#188#190#25#192#8'TabOrder'#2#2#5'Value'#5#0#0#0#0#0#0#0#0#0#0#0 +#0#0#9'TTabSheet'#9'TabSheet2'#7'Caption'#6#4'fMRI'#12'ClientHeight'#3'd'#1 +#11'ClientWidth'#3#16#2#0#6'TLabel'#7'Label11'#4'Left'#2#12#6'Height'#2#18#3 +'Top'#3#145#0#5'Width'#2'E'#7'Caption'#6#11'Slice Order'#11'ParentColor'#8#0 +#0#6'TLabel'#7'Label16'#4'Left'#2#12#6'Height'#2#18#3'Top'#2#8#5'Width'#2'K' +#7'Caption'#6#11'Time Offset'#11'ParentColor'#8#0#0#6'TLabel'#7'Label17'#4'L' +'eft'#2#14#6'Height'#2#18#3'Top'#2''''#5'Width'#2'V'#7'Caption'#6#14'Slice d' +'uration'#11'ParentColor'#8#0#0#6'TLabel'#7'Label32'#4'Left'#2#12#6'Height'#2 +#18#3'Top'#2'J'#5'Width'#2'B'#7'Caption'#6#11'Slice Start'#11'ParentColor'#8 +#0#0#6'TLabel'#7'Label20'#4'Left'#2#12#6'Height'#2#18#3'Top'#2'i'#5'Width'#2 +'9'#7'Caption'#6#9'Slice End'#11'ParentColor'#8#0#0#6'TLabel'#7'Label31'#4'L' +'eft'#2#12#6'Height'#2#18#3'Top'#3#178#0#5'Width'#3#134#0#7'Caption'#6#19'Fr' +'equency Dimension'#11'ParentColor'#8#0#0#6'TLabel'#7'Label43'#4'Left'#2#12#6 +'Height'#2#18#3'Top'#3#214#0#5'Width'#2'j'#7'Caption'#6#15'Phase Dimension' +#11'ParentColor'#8#0#0#6'TLabel'#7'Label45'#4'Left'#2#12#6'Height'#2#18#3'To' +'p'#3#250#0#5'Width'#2'b'#7'Caption'#6#15'Slice Dimension'#11'ParentColor'#8 +#0#0#9'TComboBox'#13'SliceCodeDrop'#4'Left'#2'W'#6'Height'#2#20#3'Top'#3#137 +#0#5'Width'#3#18#1#10'ItemHeight'#2#0#13'Items.Strings'#1#6#7'Unknown'#6#31 +'Sequential Increasing (1 2 3 4)'#6#31'Sequential Decreasing (4 3 2 1)'#6' I' +'nterleaved Increasing (1 3 2 4)'#6' Interleaved Decreasing (4 2 3 1)'#6'!In' +'terleaved Increasing2 (2 4 1 3)'#6'!Interleaved Decreasing2 (3 1 4 2)'#0#8 +'OnSelect'#7#13'ImageSzChange'#5'Style'#7#14'csDropDownList'#8'TabOrder'#2#4 +#0#0#9'TComboBox'#11'FreqDimDrop'#4'Left'#3#146#0#6'Height'#2#20#3'Top'#3#174 +#0#5'Width'#3#215#0#10'ItemHeight'#2#0#13'Items.Strings'#1#6#7'Unknown'#6#1 +'I'#6#1'J'#6#1'K'#0#8'OnSelect'#7#13'ImageSzChange'#5'Style'#7#14'csDropDown' +'List'#8'TabOrder'#2#5#0#0#9'TComboBox'#12'PhaseDimDrop'#4'Left'#3#146#0#6'H' +'eight'#2#20#3'Top'#3#210#0#5'Width'#3#215#0#10'ItemHeight'#2#0#13'Items.Str' +'ings'#1#6#7'Unknown'#6#1'I'#6#1'J'#6#1'K'#0#8'OnSelect'#7#13'ImageSzChange' +#5'Style'#7#14'csDropDownList'#8'TabOrder'#2#6#0#0#9'TComboBox'#12'SliceDimD' +'rop'#4'Left'#3#146#0#6'Height'#2#20#3'Top'#3#246#0#5'Width'#3#215#0#10'Item' +'Height'#2#0#13'Items.Strings'#1#6#7'Unknown'#6#1'I'#6#1'J'#6#1'K'#0#8'OnSel' +'ect'#7#13'ImageSzChange'#5'Style'#7#14'csDropDownList'#8'TabOrder'#2#7#0#0#9 +'TSpinEdit'#15'slice_startEdit'#4'Left'#2'x'#6'Height'#2#16#3'Top'#2'I'#5'Wi' +'dth'#2'p'#8'TabOrder'#2#2#5'Value'#2#1#0#0#14'TFloatSpinEdit'#18'Slice_dura' +'tionEdit'#4'Left'#2'x'#6'Height'#2#16#3'Top'#2'&'#5'Width'#2'p'#13'DecimalP' +'laces'#2#5#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0#0 +#0#200#5'@'#8'MinValue'#5#0#0#0#0#0#0#0#0#0#0#8'TabOrder'#2#1#5'Value'#5#0#0 +#0#0#0#0#0#128#255'?'#0#0#14'TFloatSpinEdit'#11'toffsetEdit'#4'Left'#2'x'#6 +'Height'#2#16#3'Top'#2#7#5'Width'#2'p'#13'DecimalPlaces'#2#5#9'Increment'#5#0 +#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0#0#0#200#5'@'#8'MinValue'#5#0 +#0#0#0#0#0#0#0#0#0#8'TabOrder'#2#0#5'Value'#5#0#0#0#0#0#0#0#128#255'?'#0#0#9 +'TSpinEdit'#13'slice_endEdit'#4'Left'#2'x'#6'Height'#2#16#3'Top'#2'h'#5'Widt' +'h'#2'p'#8'TabOrder'#2#3#5'Value'#2#1#0#0#0#9'TTabSheet'#9'TabUnused'#7'Capt' +'ion'#6#8'Optional'#12'ClientHeight'#3'd'#1#11'ClientWidth'#3#16#2#0#6'TLabe' +'l'#7'Label34'#4'Left'#2#3#6'Height'#2#18#3'Top'#2'+'#5'Width'#2'B'#7'Captio' +'n'#6#9'Data Type'#11'ParentColor'#8#0#0#6'TLabel'#6'Label5'#4'Left'#2#3#6'H' +'eight'#2#18#3'Top'#2#8#5'Width'#2'9'#7'Caption'#6#9'Intention'#11'ParentCol' +'or'#8#0#0#6'TLabel'#6'Label6'#4'Left'#3#12#1#6'Height'#2#18#3'Top'#2't'#5'W' +'idth'#2'1'#7'Caption'#6#7'Extents'#11'ParentColor'#8#0#0#6'TLabel'#6'Label9' +#4'Left'#3#12#1#6'Height'#2#18#3'Top'#2'L'#5'Width'#2'L'#7'Caption'#6#12'Ses' +'ion Error'#11'ParentColor'#8#0#0#6'TLabel'#7'Label10'#4'Left'#3#12#1#6'Heig' +'ht'#2#18#3'Top'#3#148#0#5'Width'#2'Y'#7'Caption'#6#13'Regular [114]'#11'Par' +'entColor'#8#0#0#6'TLabel'#7'Label14'#4'Left'#3#12#1#6'Height'#2#18#3'Top'#2 +#8#5'Width'#2'#'#7'Caption'#6#5'G Min'#11'ParentColor'#8#0#0#6'TLabel'#7'Lab' +'el15'#4'Left'#3#12#1#6'Height'#2#18#3'Top'#2'+'#5'Width'#2'&'#7'Caption'#6#5 +'G Max'#11'ParentColor'#8#0#0#6'TLabel'#7'Label18'#4'Left'#2#3#6'Height'#2#18 +#3'Top'#3#148#0#5'Width'#2'2'#7'Caption'#6#8'Aux File'#11'ParentColor'#8#0#0 +#6'TLabel'#7'Label19'#4'Left'#2#3#6'Height'#2#18#3'Top'#2'o'#5'Width'#2':'#7 +'Caption'#6#7'DB Name'#11'ParentColor'#8#0#0#6'TLabel'#7'Label26'#4'Left'#2#3 +#6'Height'#2#18#3'Top'#2'L'#5'Width'#2'&'#7'Caption'#6#5'Notes'#11'ParentCol' +'or'#8#0#0#5'TEdit'#15'intent_nameEdit'#4'Left'#2'L'#6'Height'#2#22#3'Top'#2 +#6#5'Width'#3#152#0#9'MaxLength'#2#16#8'TabOrder'#2#0#4'Text'#6#11'intent_na' +'me'#0#0#5'TEdit'#13'data_typeEdit'#4'Left'#2'L'#6'Height'#2#22#3'Top'#2')'#5 +'Width'#3#152#0#9'MaxLength'#2#10#8'TabOrder'#2#1#4'Text'#6#9'data_type'#0#0 ,#5'TEdit'#11'CommentEdit'#4'Left'#2'L'#6'Height'#2#22#3'Top'#2'J'#5'Width'#3 +#152#0#9'MaxLength'#2'P'#8'TabOrder'#2#2#4'Text'#6#11'CommentEdit'#0#0#5'TEd' +'it'#3'db_'#4'Left'#2'L'#6'Height'#2#22#3'Top'#2'm'#5'Width'#3#152#0#9'MaxLe' +'ngth'#2#18#8'TabOrder'#2#3#4'Text'#6#3'db_'#0#0#5'TEdit'#3'aux'#4'Left'#2'L' +#6'Height'#2#22#3'Top'#3#148#0#5'Width'#3#152#0#9'MaxLength'#2#24#8'TabOrder' +#2#4#4'Text'#6#3'aux'#0#0#9'TSpinEdit'#4'gmax'#4'Left'#3'n'#1#6'Height'#2#16 +#3'Top'#2','#5'Width'#2'B'#8'TabOrder'#2#6#5'Value'#2#1#0#0#9'TSpinEdit'#4'g' +'min'#4'Left'#3'n'#1#6'Height'#2#16#3'Top'#2#9#5'Width'#2'B'#8'TabOrder'#2#5 +#5'Value'#2#1#0#0#9'TSpinEdit'#3'ses'#4'Left'#3'n'#1#6'Height'#2#16#3'Top'#2 +'M'#5'Width'#2'B'#8'TabOrder'#2#7#5'Value'#2#1#0#0#9'TSpinEdit'#3'ext'#4'Lef' +'t'#3'n'#1#6'Height'#2#16#3'Top'#2'u'#5'Width'#2'B'#8'TabOrder'#2#8#5'Value' +#2#1#0#0#9'TSpinEdit'#3'reg'#4'Left'#3'n'#1#6'Height'#2#16#3'Top'#3#151#0#5 +'Width'#2'B'#8'MaxValue'#3#255#0#8'TabOrder'#2#9#5'Value'#2#1#0#0#0#0#10'TSt' +'atusBar'#10'StatusBar1'#4'Left'#2#0#6'Height'#2#15#3'Top'#3#147#1#5'Width'#3 +#30#2#6'Panels'#14#1#5'Width'#3#140#0#0#1#5'Width'#2'2'#0#0#11'SimplePanel'#8 +#0#0#9'TMainMenu'#9'MainMenu1'#4'left'#3#168#1#3'top'#2'H'#0#9'TMenuItem'#5 +'File1'#7'Caption'#6#5'&File'#0#9'TMenuItem'#5'Open1'#7'Caption'#6#11'Open h' +'eader'#8'ShortCut'#3'O@'#7'OnClick'#7#10'Open1Click'#0#0#9'TMenuItem'#5'Sav' +'e1'#7'Caption'#6#11'Save header'#8'ShortCut'#3'S@'#7'OnClick'#7#10'Save1Cli' +'ck'#0#0#9'TMenuItem'#5'Exit1'#7'Caption'#6#12'Close window'#8'ShortCut'#3'W' +'@'#7'OnClick'#7#10'Exit1Click'#0#0#0#9'TMenuItem'#5'Page1'#7'Caption'#6#4'&' +'Tab'#0#9'TMenuItem'#11'Dimensions1'#7'Caption'#6#10'Dimensions'#8'ShortCut' +#3'A@'#7'OnClick'#7#12'TabMenuClick'#0#0#9'TMenuItem'#10'Rotations1'#3'Tag'#2 +#1#7'Caption'#6#8'Reorient'#8'ShortCut'#3'B@'#7'OnClick'#7#12'TabMenuClick'#0 +#0#9'TMenuItem'#15'ImageIntensity1'#3'Tag'#2#2#7'Caption'#6#15'Image Intensi' +'ty'#8'ShortCut'#3'I@'#7'OnClick'#7#12'TabMenuClick'#0#0#9'TMenuItem'#11'Sta' +'tistics1'#3'Tag'#2#3#7'Caption'#6#10'Statistics'#8'ShortCut'#3'D@'#7'OnClic' +'k'#7#12'TabMenuClick'#0#0#9'TMenuItem'#14'FunctionalMRI1'#3'Tag'#2#4#7'Capt' +'ion'#6#14'Functional MRI'#8'ShortCut'#3'E@'#7'OnClick'#7#12'TabMenuClick'#0 +#0#9'TMenuItem'#9'Optional1'#3'Tag'#2#5#7'Caption'#6#8'Optional'#8'ShortCut' +#3'F@'#7'OnClick'#7#12'TabMenuClick'#0#0#0#9'TMenuItem'#5'Help1'#7'Caption'#6 +#5'&Help'#0#9'TMenuItem'#6'About1'#7'Caption'#6#8'About...'#7'OnClick'#7#11 +'About1Click'#0#0#0#0#11'TOpenDialog'#10'OpenHdrDlg'#11'FilterIndex'#2#0#7'O' +'ptions'#11#15'ofFileMustExist'#0#4'left'#3#200#1#3'top'#2'H'#0#0#11'TSaveDi' +'alog'#10'SaveHdrDlg'#7'OnClose'#7#15'SaveHdrDlgClose'#5'Width'#2'4'#6'Filte' +'r'#6'`NIfTI (*.hdr;*.nii)|*.hdr; *.nii|NIfTI separate header (*.hdr)|*.hdr|' +'NIfTI embedded header|*.nii'#11'FilterIndex'#2#0#4'left'#3#240#1#3'top'#2'H' +#0#0#0 ]); �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_gtscript.bat������������������������������������������������������0000755�0001750�0001750�00000001760�11266170154�016700� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������chmod 777 ./_xclean.bat ./_xclean.bat cp ./common/notgui.inc ./common/isgui.inc lazbuild ./dcm2nii/dcm2nii.lpr cp ./dcm2nii/dcm2nii ../gtk1/mricron/dcm2nii cp ./dcm2nii/dcm2nii ../gtk2/mricron/dcm2nii cp ./dcm2nii/dcm2nii ../qt/mricron/dcm2nii cp ./common/gui.inc ./common/isgui.inc ./_xclean.bat lazbuild ./mricron.lpr --ws=gtk lazbuild ./npm/npm.lpr --ws=gtk lazbuild ./dcm2nii/dcm2niigui.lpr --ws=gtk cp ./mricron ../gtk1/mricron/mricron cp ./npm/npm ../gtk1/mricron/npm cp ./dcm2nii/dcm2niigui ../gtk1/mricron/dcm2niigui ./_xclean.bat lazbuild ./mricron.lpr --ws=gtk2 lazbuild ./npm/npm.lpr --ws=gtk2 lazbuild ./dcm2nii/dcm2niigui.lpr --ws=gtk2 cp ./mricron ../gtk2/mricron/mricron cp ./npm/npm ../gtk2/mricron/npm cp ./dcm2nii/dcm2niigui ../gtk2/mricron/dcm2niigui ./_xclean.bat lazbuild ./mricron.lpr --ws=qt lazbuild ./npm/npm.lpr --ws=qt lazbuild ./dcm2nii/dcm2niigui.lpr --ws=qt cp ./mricron ../qt/mricron/mricron cp ./npm/npm ../qt/mricron/npm cp ./dcm2nii/dcm2niigui ../qt/mricron/dcm2niigui ����������������mricron-0.20140804.1~dfsg.1.orig/cutout.lfm���������������������������������������������������������0000755�0001750�0001750�00000010064�11450447356�016240� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object CutoutForm: TCutoutForm Left = 384 Height = 334 Top = 175 Width = 334 HorzScrollBar.Page = 335 VertScrollBar.Page = 316 ActiveControl = RenderCutoutCheck BorderIcons = [biSystemMenu, biMinimize] BorderStyle = bsSingle Caption = 'Cutouts' ClientHeight = 334 ClientWidth = 334 Constraints.MaxHeight = 334 Constraints.MaxWidth = 334 Constraints.MinHeight = 334 Constraints.MinWidth = 334 OnClose = FormClose OnShow = FormShow Position = poScreenCenter LCLVersion = '0.9.29' object RenderCutoutCheck: TCheckBox Left = 16 Height = 17 Top = 8 Width = 80 Caption = 'Show cutout' OnClick = RenderCutoutCheckClick TabOrder = 0 end object CutoutBox: TGroupBox Left = 16 Height = 224 Top = 32 Width = 304 ClientHeight = 206 ClientWidth = 300 TabOrder = 5 object Label1: TLabel Left = 14 Height = 14 Top = 8 Width = 58 Caption = 'X [low=left]' ParentColor = False end object Label2: TLabel Left = 14 Height = 14 Top = 48 Width = 85 Caption = 'Y [low=posterior]' ParentColor = False end object Label3: TLabel Left = 14 Height = 14 Top = 88 Width = 76 Caption = 'Z [low=ventral]' ParentColor = False end object Label4: TLabel Left = 14 Height = 14 Top = 135 Width = 55 Caption = 'Cutout Tint' ParentColor = False end object Label5: TLabel Left = 14 Height = 14 Top = 175 Width = 62 Caption = 'Cutout Color' ParentColor = False end object XLo: TSpinEdit Left = 118 Height = 21 Top = 0 Width = 82 MaxValue = 1000 OnChange = PreviewClick TabOrder = 0 end object XHi: TSpinEdit Left = 206 Height = 21 Top = 0 Width = 82 MaxValue = 1000 OnChange = PreviewClick TabOrder = 1 end object YLo: TSpinEdit Left = 118 Height = 21 Top = 40 Width = 82 MaxValue = 1000 OnChange = PreviewClick TabOrder = 2 end object YHi: TSpinEdit Left = 206 Height = 21 Top = 40 Width = 82 MaxValue = 1000 OnChange = PreviewClick TabOrder = 3 end object ZLo: TSpinEdit Left = 118 Height = 21 Top = 88 Width = 82 MaxValue = 1000 OnChange = PreviewClick TabOrder = 4 end object ZHi: TSpinEdit Left = 206 Height = 21 Top = 88 Width = 82 MaxValue = 1000 OnChange = PreviewClick TabOrder = 5 end object CutoutBiasDrop: TComboBox Left = 118 Height = 19 Top = 128 Width = 170 ItemHeight = 13 Items.Strings = ( '0.1 Dark' '0.2' '0.3' '0.4' '0.5' '0.6' '0.7' '0.8' '0.9 Light' ) OnChange = PreviewClick Style = csOwnerDrawFixed TabOrder = 6 end object CutoutLUTDrop: TComboBox Left = 118 Height = 19 Top = 168 Width = 170 ItemHeight = 13 OnChange = PreviewClick Style = csOwnerDrawFixed TabOrder = 7 end end object PreviewBtn: TButton Left = 128 Height = 25 Top = 304 Width = 75 Caption = 'Preview' OnClick = PreviewClick TabOrder = 2 Visible = False end object DefBtn: TButton Left = 128 Height = 25 Top = 272 Width = 75 Caption = 'Defaults' OnClick = DefBtnClick TabOrder = 3 end object OKBtn: TButton Left = 237 Height = 25 Top = 272 Width = 75 Caption = 'OK' OnClick = OKBtnClick TabOrder = 4 end object PreviewBtn1: TButton Left = 16 Height = 25 Top = 272 Width = 75 Caption = 'Preview' OnClick = PreviewBtn1Click TabOrder = 1 end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/rgb/���������������������������������������������������������������0000755�0001750�0001750�00000000000�12413465015�014753� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/rgb/rgbgtkroutines.pas���������������������������������������������0000755�0001750�0001750�00000005255�11540170376�020546� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ /*************************************************************************** RGBGTKRoutines.pas ***************************************************************************/ ***************************************************************************** * * * See the file COPYING.modifiedLGPL, included in this distribution, * * for details about the copyright. * * * * 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. * * * ***************************************************************************** Author: Tom Gregorovic (_tom_@centrum.cz) Abstract: This unit contains routines for GTK interfaces. } unit RGBGTKRoutines; {$ifdef fpc} {$mode objfpc}{$H+} {$endif} interface uses SysUtils, Classes, LCLType, {$IFDEF LCLgtk2} gtkDef, //<- uncomment for older versions of Lazarus glib2, gdk2,gtk2Def, gtk2Proc, {$ELSE} //LCLgtk1 glib, gdk, gtkDef, gtkProc, {$ENDIF} RGBTypes; procedure WidgetSetDrawRGB32Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); procedure WidgetSetDrawRGB8Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB8BitmapCore); implementation procedure WidgetSetDrawRGB32Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); var P: TPoint; begin P := TGtkDeviceContext(Dest).Offset; //<- if compiler stops here, uncomment gtkDef in Uses Inc(DstX, P.X); Inc(DstY, P.Y); gdk_draw_rgb_32_image(TGtkDeviceContext(Dest).Drawable, TGtkDeviceContext(Dest).GC, DstX, DstY, SrcWidth, SrcHeight, GDK_RGB_DITHER_NONE, Pguchar(Bitmap.GetPixelPtrUnsafe(SrcX, SrcY)), Bitmap.RowPixelStride shl 2); end; procedure WidgetSetDrawRGB8Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB8BitmapCore); var P: TPoint; begin P := TGtkDeviceContext(Dest).Offset; Inc(DstX, P.X); Inc(DstY, P.Y); gdk_draw_gray_image(TGtkDeviceContext(Dest).Drawable, TGtkDeviceContext(Dest).GC, DstX, DstY, SrcWidth, SrcHeight, GDK_RGB_DITHER_NONE, Pguchar(Bitmap.Get8PixelPtrUnsafe(SrcX, SrcY)), Bitmap.RowPixelStride); end; initialization gdk_rgb_init; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/rgb/rgbwinroutines.pas���������������������������������������������0000755�0001750�0001750�00000010070�11326425450�020543� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ /*************************************************************************** RGBWinRoutines.pas ***************************************************************************/ ***************************************************************************** * * * See the file COPYING.modifiedLGPL, included in this distribution, * * for details about the copyright. * * * * 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. * * * ***************************************************************************** Author: Tom Gregorovic (_tom_@centrum.cz) Abstract: This unit contains routines for win32 interface. } unit RGBWinRoutines; {$ifdef fpc} {$mode objfpc}{$H+} {$endif} interface uses SysUtils, Windows, Classes, RGBTypes; procedure WidgetSetDrawRGB32Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); procedure WidgetSetStretchDrawRGB32Bitmap(Dest: HDC; DstX, DstY, DstWidth, DstHeight: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); procedure WidgetSetDrawRGB8Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB8BitmapCore); implementation procedure WidgetSetDrawRGB32Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); var Info: BITMAPINFO; begin with Info.bmiHeader do begin biSize := SizeOf(BITMAPINFOHEADER); biWidth := Bitmap.Width; biHeight := Bitmap.Height; biPlanes := 1; biBitCount := 32; biCompression := BI_RGB; biSizeImage := 0; biClrImportant := 0; end; SetStretchBltMode(Dest, COLORONCOLOR); StretchDIBits(Dest, DstX, Pred(DstY + SrcHeight), SrcWidth, -SrcHeight, SrcX, SrcY, SrcWidth, SrcHeight, Bitmap.Pixels, Info, DIB_RGB_COLORS, SRCCOPY); end; procedure WidgetSetStretchDrawRGB32Bitmap(Dest: HDC; DstX, DstY, DstWidth, DstHeight: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); var Info: BITMAPINFO; begin with Info.bmiHeader do begin biSize := SizeOf(BITMAPINFOHEADER); biWidth := Bitmap.Width; biHeight := Bitmap.Height; biPlanes := 1; biBitCount := 32; biCompression := BI_RGB; biSizeImage := 0; biClrImportant := 0; end; SetStretchBltMode(Dest, COLORONCOLOR); StretchDIBits(Dest, DstX, Pred(DstY + DstHeight), DstWidth, -DstHeight, SrcX, SrcY, SrcWidth, SrcHeight, Bitmap.Pixels, Info, DIB_RGB_COLORS, SRCCOPY); end; procedure WidgetSetDrawRGB8Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB8BitmapCore); var Info: PBITMAPINFO; I: Byte; PColor: PRGBQUAD; begin GetMem(Info, SizeOf(BITMAPINFO) + 256 * SizeOf(RGBQUAD)); try with Info^.bmiHeader do begin biSize := SizeOf(BITMAPINFOHEADER); biWidth := Bitmap.Width; biHeight := Bitmap.Height; biPlanes := 1; biBitCount := 8; biCompression := BI_RGB; biSizeImage := 0; biClrUsed := 256; biClrImportant := 0; end; PColor := @(Info^.bmiColors[0]); for I := 0 to 255 do begin PColor^.rgbRed := I; PColor^.rgbGreen := I; PColor^.rgbBlue := I; Inc(PColor); end; SetStretchBltMode(Dest, COLORONCOLOR); StretchDIBits(Dest, DstX, Pred(DstY + SrcHeight), SrcWidth, -SrcHeight, SrcX, SrcY, SrcWidth, SrcHeight, Bitmap.Pixels, Info^, DIB_RGB_COLORS, SRCCOPY); finally FreeMem(Info); end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/rgb/rgbqtroutines.pas����������������������������������������������0000755�0001750�0001750�00000006554�11326425450�020406� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ /*************************************************************************** RGBQtRoutines.pas ***************************************************************************/ ***************************************************************************** * * * See the file COPYING.modifiedLGPL, included in this distribution, * * for details about the copyright. * * * * 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. * * * ***************************************************************************** Author: Tom Gregorovic (_tom_@centrum.cz) Abstract: This unit contains routines for Qt interface. } unit RGBQtRoutines; {$ifdef fpc} {$mode objfpc}{$H+} {$endif} interface uses SysUtils, Types, LCLType, Qt4, QtObjects, Classes, RGBTypes; procedure WidgetSetDrawRGB32Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); procedure WidgetSetStretchDrawRGB32Bitmap(Dest: HDC; DstX, DstY, DstWidth, DstHeight: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); procedure WidgetSetDrawRGB8Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB8BitmapCore); implementation procedure WidgetSetDrawRGB32Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); begin WidgetSetStretchDrawRGB32Bitmap(Dest, DstX, DstY, SrcWidth, SrcHeight, SrcX, SrcY, SrcWidth, SrcHeight, Bitmap); end; procedure WidgetSetStretchDrawRGB32Bitmap(Dest: HDC; DstX, DstY, DstWidth, DstHeight: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); var DstQDC: TQtDeviceContext absolute Dest; SrcRect, DstRect: TRect; Image: TQtImage; begin DstRect := Bounds(DstX, DstY, DstWidth, DstHeight); SrcRect := Bounds(SrcX, SrcY, SrcWidth, SrcHeight); Image := TQtImage.Create(Bitmap.Pixels, Bitmap.Width, Bitmap.Height, QImageFormat_RGB32); try QPainter_drawImage(DstQDC.Widget, PRect(@DstRect), Image.Handle, @SrcRect, QtAutoColor); finally Image.Free; end; end; procedure WidgetSetDrawRGB8Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB8BitmapCore); var DstQDC: TQtDeviceContext absolute Dest; SrcRect, DstRect: TRect; Image: TQtImage; I: Integer; begin DstRect := Bounds(DstX, DstY, SrcWidth, SrcHeight); SrcRect := Bounds(SrcX, SrcY, SrcWidth, SrcHeight); Image := TQtImage.Create(Bitmap.Pixels, Bitmap.Width, Bitmap.Height, QImageFormat_Indexed8); try // initialize palette for I := 0 to 255 do QImage_setColor(Image.Handle, I, I + I shl 8 + I shl 16 + $FF shl 24); QPainter_drawImage(DstQDC.Widget, PRect(@DstRect), Image.Handle, @SrcRect, QtAutoColor); finally Image.Free; end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/rgb/lazrgbgraphics.lpk���������������������������������������������0000755�0001750�0001750�00000005031�11062270502�020461� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <CONFIG> <Package Version="3"> <PathDelim Value="\"/> <Name Value="LazRGBGraphics"/> <Author Value="Tom Gregorovic (_tom_@centrum.cz)"/> <CompilerOptions> <Version Value="5"/> <PathDelim Value="\"/> <SearchPaths> <IncludeFiles Value="include\"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)-$(LCLWidgetType)"/> <LCLWidgetType Value="gtk2"/> </SearchPaths> <CodeGeneration> <Generate Value="Faster"/> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="True"/> </Debugging> </Linking> <Other> <CompilerPath Value="$(CompPath)"/> </Other> </CompilerOptions> <Description Value="This package provides fast in memory image processing and pixel manipulations (like scan line). "/> <License Value="Modified LGPL "/> <Version Minor="2" Release="2"/> <Files Count="8"> <Item1> <Filename Value="rgbgraphics.pas"/> <UnitName Value="RGBGraphics"/> </Item1> <Item2> <Filename Value="rgbutils.pas"/> <UnitName Value="RGBUtils"/> </Item2> <Item3> <Filename Value="rgbtypes.pas"/> <UnitName Value="RGBTypes"/> </Item3> <Item4> <Filename Value="rgbroutines.pas"/> <UnitName Value="RGBRoutines"/> </Item4> <Item5> <Filename Value="rgbwinroutines.pas"/> <AddToUsesPkgSection Value="False"/> <UnitName Value="RGBWinRoutines"/> </Item5> <Item6> <Filename Value="rgbgtkroutines.pas"/> <AddToUsesPkgSection Value="False"/> <UnitName Value="RGBGTKRoutines"/> </Item6> <Item7> <Filename Value="rgbcarbonroutines.pas"/> <AddToUsesPkgSection Value="False"/> <UnitName Value="RGBCarbonRoutines"/> </Item7> <Item8> <Filename Value="rgbqtroutines.pas"/> <AddToUsesPkgSection Value="False"/> <UnitName Value="RGBQtRoutines"/> </Item8> </Files> <RequiredPkgs Count="2"> <Item1> <PackageName Value="LCL"/> </Item1> <Item2> <PackageName Value="FCL"/> <MinVersion Major="1" Valid="True"/> </Item2> </RequiredPkgs> <UsageOptions> <UnitPath Value="$(PkgOutDir)\"/> </UsageOptions> <PublishOptions> <Version Value="2"/> <DestinationDirectory Value="$(TestDir)\publishedpackage\"/> <IgnoreBinaries Value="False"/> </PublishOptions> </Package> </CONFIG> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/rgb/lazrgbgraphics.pas���������������������������������������������0000755�0001750�0001750�00000000374�11326425450�020472� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This file was automatically created by Lazarus. Do not edit! This source is only used to compile and install the package. } unit LazRGBGraphics; interface uses RGBGraphics, RGBUtils, RGBTypes, RGBRoutines; implementation end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/rgb/rgbroutines.pas������������������������������������������������0000755�0001750�0001750�00000073002�11326425450�020031� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ /*************************************************************************** RGBRoutines.pas ***************************************************************************/ ***************************************************************************** * * * See the file COPYING.modifiedLGPL, included in this distribution, * * for details about the copyright. * * * * 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. * * * ***************************************************************************** Author: Tom Gregorovic (_tom_@centrum.cz) Abstract: This unit contains routines for manipulating rgb bitmaps (stretching, drawing on canvas...) and for drawing primitives (lines, ellipses...). } unit RGBRoutines; {$ifdef fpc} {$mode objfpc}{$H+} {$endif} interface uses SysUtils, Math, Forms, LCLIntf, LCLType, LCLProc, FPImage, IntfGraphics, Classes, {$IFDEF LCLwin32} RGBWinRoutines, {$ENDIF} {$IFDEF LCLqt} RGBQtRoutines, {$ENDIF} {$IFDEF LCLgtk} {$DEFINE StretchRGB32} RGBGTKRoutines, {$ENDIF} {$IFDEF LCLgtk2} {$DEFINE StretchRGB32} RGBGTKRoutines, {$ENDIF} {$IFDEF LCLcarbon} {$DEFINE StretchRGB32} RGBCarbonRoutines, {$ENDIF} RGBTypes, RGBUtils; procedure DrawRGB32Bitmap(Dst: TRGB32BitmapCore; X, Y: Integer; Src: TRGB32BitmapCore); overload; procedure DrawRGB8Bitmap(Dst: TRGB8BitmapCore; X, Y: Integer; Src: TRGB8BitmapCore); overload; procedure StretchRGB32BitmapTrunc(Dst, Src: TRGB32BitmapCore); procedure StretchRGB8BitmapTrunc(Dst, Src: TRGB8BitmapCore); procedure DrawRGB32Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); overload; procedure StretchDrawRGB32Bitmap(Dest: HDC; DstX, DstY, DstWidth, DstHeight: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); overload; procedure StretchDrawRGBMaskShapePortion(Dest: HDC; DstX, DstY, DstWidth, DstHeight: Integer; Bitmap: TRGB8BitmapCore; DX, DY, DW, DH: Integer; BgPen: HPEN; FgPen: HPEN); procedure DrawRGB8Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB8BitmapCore); overload; type TDrawPixelProcedure = procedure (X, Y: Integer) of Object; TGetPixelFunction = function (X, Y: Integer): TRGB32Pixel of Object; TSamePixelFunction = function (X, Y: Integer; Value: TRGB32Pixel): Boolean of Object; procedure LineBresenham(X1, Y1, X2, Y2: Integer; DrawPixel: TDrawPixelProcedure); procedure FillPixelRect(X1, Y1, X2, Y2: Integer; DrawPixel: TDrawPixelProcedure); procedure NormalRectangle(X1, Y1, X2, Y2: Integer; DrawOutlinePixel, DrawFillPixel: TDrawPixelProcedure); procedure EllipticRectangle(X1, Y1, X2, Y2: Integer; LX, LY: Integer; DrawOutlinePixel, DrawFillPixel: TDrawPixelProcedure); procedure FloodFillScanLine(X, Y, W, H: Integer; GetPixel: TGetPixelFunction; SamePixel: TSamePixelFunction; DrawPixel: TDrawPixelProcedure); implementation function GetDCClipRect(Dest: HDC): TRect; begin if GetClipBox(Dest, @Result) = ERROR then begin Result.TopLeft := Point(0, 0); if not GetDeviceSize(Dest, Result.BottomRight) then Result.BottomRight := Point(8000, 8000); end; end; procedure DrawRGB32Bitmap(Dst: TRGB32BitmapCore; X, Y: Integer; Src: TRGB32BitmapCore); var SrcX, SrcWidth, SrcY, SrcHeight: Integer; I: Integer; PS, PD: PRGB32Pixel; begin if (Dst = nil) or (Src = nil) then Exit; if (Dst.Width <= 0) or (Dst.Height <= 0) or (Src.Width <= 0) or (Src.Height <= 0) then Exit; if (X >= Dst.Width) or (Y >= Dst.Height) then Exit; if (X + Src.Width <= 0) or (Y + Src.Height <= 0) then Exit; SrcX := 0; SrcY := 0; SrcWidth := Src.Width; SrcHeight := Src.Height; if X < 0 then begin SrcX := -X; Inc(SrcWidth, X); X := 0; end; if Y < 0 then begin SrcY := -Y; Inc(SrcHeight, Y); Y := 0; end; if X + SrcWidth > Dst.Width then Dec(SrcWidth, X + SrcWidth - Dst.Width); if Y + SrcHeight > Dst.Height then Dec(SrcHeight, Y + SrcHeight - Dst.Height); for I := 0 to Pred(SrcHeight) do begin PS := Src.Get32PixelPtrUnsafe(SrcX, SrcY + I); PD := Dst.Get32PixelPtrUnsafe(X, Y + I); Move(PS^, PD^, SrcWidth shl 2); end; end; procedure DrawRGB8Bitmap(Dst: TRGB8BitmapCore; X, Y: Integer; Src: TRGB8BitmapCore); var SrcX, SrcWidth, SrcY, SrcHeight: Integer; I: Integer; PS, PD: PRGB8Pixel; begin if (Dst = nil) or (Src = nil) then Exit; if (Dst.Width <= 0) or (Dst.Height <= 0) or (Src.Width <= 0) or (Src.Height <= 0) then Exit; if (X >= Dst.Width) or (Y >= Dst.Height) then Exit; if (X + Src.Width <= 0) or (Y + Src.Height <= 0) then Exit; SrcX := 0; SrcY := 0; SrcWidth := Src.Width; SrcHeight := Src.Height; if X < 0 then begin SrcX := -X; Inc(SrcWidth, X); X := 0; end; if Y < 0 then begin SrcY := -Y; Inc(SrcHeight, Y); Y := 0; end; if X + SrcWidth > Dst.Width then Dec(SrcWidth, X + SrcWidth - Dst.Width); if Y + SrcHeight > Dst.Height then Dec(SrcHeight, Y + SrcHeight - Dst.Height); for I := 0 to Pred(SrcHeight) do begin PS := Src.Get8PixelPtrUnsafe(SrcX, SrcY + I); PD := Dst.Get8PixelPtrUnsafe(X, Y + I); Move(PS^, PD^, SrcWidth); end; end; procedure StretchRGB32BitmapTrunc(Dst, Src: TRGB32BitmapCore); var Cols: TIntArray; Rows: TIntArray; X, Y, PX, TX, OX, PY, TY, OY: Integer; I: Integer; PD, PS, PDLine, PSLine: PRGB32Pixel; DstDataWidth, DstDataHeight: Integer; SrcDataWidth, SrcDataHeight: Integer; SrcRowPixelStride, DstRowPixelStride: Integer; begin DstDataWidth := Dst.Width; DstDataHeight := Dst.Height; SrcDataWidth := Src.Width; SrcDataHeight := Src.Height; SrcRowPixelStride := Src.RowPixelStride; DstRowPixelStride := Dst.RowPixelStride; Cols := DivideTrunc(SrcDataWidth, DstDataWidth); Rows := DivideTrunc(SrcDataHeight, DstDataHeight); if DstDataWidth <= SrcDataWidth then begin PX := 0; OX := 0; for X := 0 to High(Cols) do begin TX := Cols[X]; Cols[X] := (PX + TX shr 1) - OX; OX := (PX + TX shr 1); Inc(PX, TX); end; end; if DstDataHeight <= SrcDataHeight then begin PY := 0; OY := 0; for Y := 0 to High(Rows) do begin TY := Rows[Y]; Rows[Y] := (PY + Rows[Y] shr 1) - OY; OY := (PY + TY shr 1); Inc(PY, TY); end; end; PD := PRGB32Pixel(Dst.Pixels); PS := PRGB32Pixel(Src.Pixels); for Y := 0 to High(Rows) do begin if DstDataHeight <= SrcDataHeight then begin Inc(PS, Rows[Y] * SrcRowPixelStride); end; PDLine := PD; PSLine := PS; if DstDataWidth > SrcDataWidth then begin for X := 0 to High(Cols) do begin if Cols[X] = 1 then begin PDLine^ := PSLine^; Inc(PDLine); end else begin FillDWord(PDLine^, Cols[X], PSLine^); Inc(PDLine, Cols[X]); end; Inc(PSLine); end; end else begin for X := 0 to High(Cols) do begin Inc(PSLine, Cols[X]); PDLine^ := PSLine^; Inc(PDLine); end; end; if DstDataHeight > SrcDataHeight then begin PDLine := PD; Inc(PD, DstRowPixelStride); for I := 2 to Rows[Y] do begin Move(PDLine^, PD^, DstDataWidth shl 2); Inc(PD, DstRowPixelStride); end; Inc(PS, SrcRowPixelStride); end else begin Inc(PD, DstRowPixelStride); end; end; end; procedure StretchRGB8BitmapTrunc(Dst, Src: TRGB8BitmapCore); var Cols: TIntArray; Rows: TIntArray; X, Y, PX, TX, OX, PY, TY, OY: Integer; I: Integer; PD, PS, PDLine, PSLine: PRGB8Pixel; DstDataWidth, DstDataHeight: Integer; SrcDataWidth, SrcDataHeight: Integer; SrcRowPixelStride, DstRowPixelStride: Integer; begin DstDataWidth := Dst.Width; DstDataHeight := Dst.Height; SrcDataWidth := Src.Width; SrcDataHeight := Src.Height; SrcRowPixelStride := Src.RowPixelStride; DstRowPixelStride := Dst.RowPixelStride; Cols := DivideTrunc(SrcDataWidth, DstDataWidth); Rows := DivideTrunc(SrcDataHeight, DstDataHeight); if DstDataWidth <= SrcDataWidth then begin PX := 0; OX := 0; for X := 0 to High(Cols) do begin TX := Cols[X]; Cols[X] := (PX + TX shr 1) - OX; OX := (PX + TX shr 1); Inc(PX, TX); end; end; if DstDataHeight <= SrcDataHeight then begin PY := 0; OY := 0; for Y := 0 to High(Rows) do begin TY := Rows[Y]; Rows[Y] := (PY + Rows[Y] shr 1) - OY; OY := (PY + TY shr 1); Inc(PY, TY); end; end; PD := PRGB8Pixel(Dst.Pixels); PS := PRGB8Pixel(Src.Pixels); for Y := 0 to High(Rows) do begin if DstDataHeight <= SrcDataHeight then begin Inc(PS, Rows[Y] * SrcRowPixelStride); end; PDLine := PD; PSLine := PS; if DstDataWidth > SrcDataWidth then begin for X := 0 to High(Cols) do begin if Cols[X] = 1 then begin PDLine^ := PSLine^; Inc(PDLine); end else begin FillByte(PDLine^, Cols[X], PSLine^); Inc(PDLine, Cols[X]); end; Inc(PSLine); end; end else begin for X := 0 to High(Cols) do begin Inc(PSLine, Cols[X]); PDLine^ := PSLine^; Inc(PDLine); end; end; if DstDataHeight > SrcDataHeight then begin PDLine := PD; Inc(PD, DstRowPixelStride); for I := 2 to Rows[Y] do begin Move(PDLine^, PD^, DstDataWidth); Inc(PD, DstRowPixelStride); end; Inc(PS, SrcRowPixelStride); end else begin Inc(PD, DstRowPixelStride); end; end; end; procedure StretchRGB32BitmapTrunc(Dst: TRGB32BitmapCore; DstX, DstY, DstWidth, DstHeight: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Src: TRGB32BitmapCore); var Cols: TIntArray; Rows: TIntArray; X, Y: Integer; SX, SY, DX, DY: Integer; I, J, C: Integer; PD, PS, PDLine, PSLine: PRGB32Pixel; DstDataWidth, DstDataHeight: Integer; SrcDataWidth, SrcDataHeight: Integer; SrcRowPixelStride, DstRowPixelStride: Integer; begin DstDataWidth := Dst.Width; DstDataHeight := Dst.Height; SrcDataWidth := Src.Width; SrcDataHeight := Src.Height; SrcRowPixelStride := Src.RowPixelStride; DstRowPixelStride := Dst.RowPixelStride; Cols := DivideTrunc(SrcWidth, DstWidth); Rows := DivideTrunc(SrcHeight, DstHeight); if DstWidth <= SrcWidth then Cols := GetDifference(GetMidPoints(Cols)); if DstHeight <= SrcHeight then Rows := GetDifference(GetMidPoints(Rows)); PD := Dst.Get32PixelPtrUnsafe(DstX, DstY); PS := Src.Get32PixelPtrUnsafe(SrcX, SrcY); DY := DstY; SY := SrcY; for Y := 0 to High(Rows) do begin if DstHeight <= SrcHeight then begin Inc(PS, Rows[Y] * SrcRowPixelStride); Inc(SY, Rows[Y]); end; if DstHeight > SrcHeight then C := Rows[Y] else C := 1; for I := 1 to C do begin DX := DstX; SX := SrcX; PDLine := PD; PSLine := PS; if (SY >= 0) and (SY < SrcDataHeight) and (DY >= 0) and (DY < DstDataHeight) then begin if (DstWidth > SrcWidth) then begin for X := 0 to High(Cols) do begin if Cols[X] = 1 then begin if (SX >= 0) and (SX < SrcDataWidth) and (DX >= 0) and (DX < DstDataWidth) then PDLine^ := PSLine^; Inc(PDLine); Inc(DX); end else begin if (SX >= 0) and (SX < SrcDataWidth) then begin if (DX + Cols[X] <= 0) or (DX >= DstDataWidth) then begin Inc(PDLine, Cols[X]); Inc(DX, Cols[X]); end else for J := 1 to Cols[X] do begin if (DX >= 0) and (DX < DstDataWidth) then PDLine^ := PSLine^; Inc(PDLine); Inc(DX); end; end else begin Inc(PDLine, Cols[X]); Inc(DX, Cols[X]); end; end; Inc(PSLine); Inc(SX); end; end else begin for X := 0 to High(Cols) do begin Inc(PSLine, Cols[X]); Inc(SX, Cols[X]); if (SX >= 0) and (SX < SrcDataWidth) and (DX >= 0) and (DX < DstDataWidth) then PDLine^ := PSLine^; Inc(PDLine); Inc(DX); end; end; end; if DstHeight > SrcHeight then begin Inc(PD, DstRowPixelStride); Inc(DY); end; end; if DstHeight > SrcHeight then begin Inc(PS, SrcRowPixelStride); Inc(SY); end else begin Inc(PD, DstRowPixelStride); Inc(DY); end; end; end; // ! SrcX < 0, SrcY < 0, SrcX + SrcWidth > Bitmap.Width, SrcY + SrcHeight > Bitmap.Height // ! results in mash procedure DrawRGB32Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); var Clip: TRect; begin if (Bitmap = nil) or (Bitmap.Pixels = nil) then Exit; if (Bitmap.Width <= 0) or (Bitmap.Height <= 0) then Exit; if (SrcWidth <= 0) or (SrcHeight <= 0) then Exit; Clip := GetDCClipRect(Dest); if (DstX >= Clip.Right) or (DstY >= Clip.Bottom) or (DstX + SrcWidth < Clip.Left) or (DstY + SrcHeight < Clip.Top) then Exit; // clipping: ClipDimension(Clip.Left, Clip.Right, DstX, SrcX, SrcWidth); ClipDimension(Clip.Top, Clip.Bottom, DstY, SrcY, SrcHeight); WidgetSetDrawRGB32Bitmap(Dest, DstX, DstY, SrcX, SrcY, SrcWidth, SrcHeight, Bitmap); end; // ! SrcX < 0, SrcY < 0, SrcX + SrcWidth > Bitmap.Width, SrcY + SrcHeight > Bitmap.Height // ! results in mash procedure StretchDrawRGB32Bitmap(Dest: HDC; DstX, DstY, DstWidth, DstHeight: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); var Clip: TRect; {$IFDEF StretchRGB32} Temp: TRGB32BitmapCore; X, Y, W, H: Integer; {$ENDIF} begin if (Bitmap = nil) or (Bitmap.Pixels = nil) then Exit; if (Bitmap.Width <= 0) or (Bitmap.Height <= 0) then Exit; if (SrcWidth <= 0) or (SrcHeight <= 0) then Exit; if (DstWidth <= 0) or (DstHeight <= 0) then Exit; Clip := GetDCClipRect(Dest); if (DstX >= Clip.Right) or (DstY >= Clip.Bottom) or (DstX + DstWidth < Clip.Left) or (DstY + DstHeight < Clip.Top) then Exit; if (DstWidth = SrcWidth) and (DstHeight = SrcHeight) then begin DrawRGB32Bitmap(Dest, DstX, DstY, SrcX, SrcY, SrcWidth, SrcHeight, Bitmap); Exit; end; {$IFDEF StretchRGB32} X := Max(Clip.Left, DstX); Y := Max(Clip.Top, DstY); W := Min(Clip.Right, DstX + DstWidth) - X; H := Min(Clip.Bottom, DstY + DstHeight) - Y; Temp := TRGB32BitmapCore.Create(W, H); try StretchRGB32BitmapTrunc(Temp, DstX - X, DstY - Y, DstWidth, DstHeight, SrcX, SrcY, SrcWidth, SrcHeight, Bitmap); DrawRGB32Bitmap(Dest, X, Y, 0, 0, W, H, Temp); finally Temp.Free; end; {$ELSE} WidgetSetStretchDrawRGB32Bitmap(Dest, DstX, DstY, DstWidth, DstHeight, SrcX, SrcY, SrcWidth, SrcHeight, Bitmap); {$ENDIF} end; procedure StretchDrawRGBMaskShapePortion(Dest: HDC; DstX, DstY, DstWidth, DstHeight: Integer; Bitmap: TRGB8BitmapCore; DX, DY, DW, DH: Integer; BgPen: HPEN; FgPen: HPEN); var ZoomX, ZoomY: Single; Clip: TRect; procedure DrawMask(SX, SY, EX, EY: Integer); var X, Y: Integer; P: PRGB8Pixel; V1, V2: TRGB8Pixel; A, B, C: Integer; Temp: HGDIOBJ; begin if EX >= Bitmap.Width then EX := Pred(Bitmap.Width); if EY >= Bitmap.Height then EY := Pred(Bitmap.Height); Temp := SelectObject(Dest, BgPen); try for Y := SY to EY do begin if Pred(SX) >= 0 then V2 := Bitmap.Get8PixelPtr(Pred(SX), Y)^ else V2 := 0; P := Bitmap.Get8PixelPtr(SX, Y); for X := Pred(SX) to EX do begin V1 := V2; if X < Pred(Bitmap.Width) then V2 := P^ else V2 := 0; if (V1 = $FF) and (V2 <> $FF) then begin A := DstX + Round(Succ(X) * ZoomX); B := DstY + Round(Y * ZoomY); C := DstY + Round(Succ(Y) * ZoomY); if ((X + Y) and $1) > 0 then begin SelectObject(Dest, BgPen); MoveToEx(Dest, A, B, nil); LineTo(Dest, A, C); end else begin SelectObject(Dest, FgPen); MoveToEx(Dest, A, B, nil); LineTo(Dest, A, C); end; end else if (V1 <> $FF) and (V2 = $FF) then begin A := DstX + Round(Succ(X) * ZoomX); B := DstY + Round(Y * ZoomY); C := DstY + Round(Succ(Y) * ZoomY); if ((X + Y) and $1) > 0 then begin SelectObject(Dest, BgPen); MoveToEx(Dest, A - 1, B, nil); LineTo(Dest, A - 1, C); end else begin SelectObject(Dest, FgPen); MoveToEx(Dest, A - 1, B, nil); LineTo(Dest, A - 1, C); end; end; Inc(P); end; end; for X := SX to EX do begin if Pred(SY) >= 0 then V2 := Bitmap.Get8PixelPtr(X, Pred(SY))^ else V2 := 0; P := Bitmap.Get8PixelPtr(X, SY); for Y := Pred(SY) to EY do begin V1 := V2; if Y < Pred(Bitmap.Height) then V2 := P^ else V2 := 0; if (V1 = $FF) and (V2 <> $FF) then begin A := DstX + Round(X * ZoomX); B := DstX + Round(Succ(X) * ZoomX); C := DstY + Round(Succ(Y) * ZoomY); if ((X + Y) and $1) > 0 then begin SelectObject(Dest, BgPen); MoveToEx(Dest, A, C, nil); LineTo(Dest, B, C); end else begin SelectObject(Dest, FgPen); MoveToEx(Dest, A, C, nil); LineTo(Dest, B, C); end; end else if (V1 <> $FF) and (V2 = $FF) then begin A := DstX + Round(X * ZoomX); B := DstX + Round(Succ(X) * ZoomX); C := DstY + Round(Succ(Y) * ZoomY); if ((X + Y) and $1) > 0 then begin SelectObject(Dest, BgPen); MoveToEx(Dest, A, C - 1, nil); LineTo(Dest, B, C - 1); end else begin SelectObject(Dest, FgPen); MoveToEx(Dest, A, C - 1, nil); LineTo(Dest, B, C - 1); end; end; Inc(P, Bitmap.RowPixelStride); end; end; finally SelectObject(Dest, Temp); end; end; begin if (Bitmap = nil) or (Bitmap.Pixels = nil) then Exit; if (Bitmap.Width <= 0) or (Bitmap.Height <= 0) then Exit; if (DstWidth <= 0) or (DstHeight <= 0) then Exit; Clip := GetDCClipRect(Dest); ZoomX := DstWidth / Bitmap.Width; ZoomY := DstHeight / Bitmap.Height; if (Floor(DstX + DX * ZoomX) >= Clip.Right) or (Floor(DstY + DY * ZoomY) >= Clip.Bottom) or (Ceil(DstX + (DX + DW) * ZoomX) < Clip.Left) or (Ceil(DstY + (DY + DH) * ZoomY) < Clip.Top) then Exit; DrawMask(DX, DY, Pred(DX + DW), Pred(DY + DH)); end; // ! SrcX < 0, SrcY < 0, SrcX + SrcWidth > Bitmap.Width, SrcY + SrcHeight > Bitmap.Height // ! results in mash procedure DrawRGB8Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB8BitmapCore); var Clip: TRect; begin if (Bitmap = nil) or (Bitmap.Pixels = nil) then Exit; if (Bitmap.Width <= 0) or (Bitmap.Height <= 0) then Exit; if (SrcWidth <= 0) or (SrcHeight <= 0) then Exit; Clip := GetDCClipRect(Dest); if (DstX >= Clip.Right) or (DstY >= Clip.Bottom) or (DstX + SrcWidth < Clip.Left) or (DstY + SrcHeight < Clip.Top) then Exit; // clipping: ClipDimension(Clip.Left, Clip.Right, DstX, SrcX, SrcWidth); ClipDimension(Clip.Top, Clip.Bottom, DstY, SrcY, SrcHeight); WidgetSetDrawRGB8Bitmap(Dest, DstX, DstY, SrcX, SrcY, SrcWidth, SrcHeight, Bitmap); end; (* LineBresenham - standard Bresenham's line plotting algorithm Note: Result depends on order of points. *) procedure LineBresenham(X1, Y1, X2, Y2: Integer; DrawPixel: TDrawPixelProcedure); var Y, X: Integer; DX, DY, SX, SY, E: Integer; begin DrawPixel(X1, Y1); if (Y1 = Y2) and (X1 = X2) then Exit; DX := X2 - X1; DY := Y2 - Y1; if DX < 0 then begin SX := -1; DX := -DX; end else SX := 1; if DY < 0 then begin SY := -1; DY := -DY; end else SY := 1; DX := DX shl 1; DY := DY shl 1; X := X1; Y := Y1; if DX > DY then begin E := DY - DX shr 1; while X <> X2 do begin if E >= 0 then begin Inc(Y, SY); Dec(E, DX); end; Inc(X, SX); Inc(E, DY); DrawPixel(X, Y); end; end else begin E := DX - DY shr 1; while Y <> Y2 do begin if E >= 0 then begin Inc(X, SX); Dec(E, DY); end; Inc(Y, SY); Inc(E, DX); DrawPixel(X, Y); end; end; end; procedure FillPixelRect(X1, Y1, X2, Y2: Integer; DrawPixel: TDrawPixelProcedure); var X, Y: Integer; begin SortRect(X1, Y1, X2, Y2); for Y := Y1 to Y2 do for X := X1 to X2 do DrawPixel(X, Y); end; procedure FillPixelRow(X1, X2, Y: Integer; DrawPixel: TDrawPixelProcedure); inline; var X: Integer; begin MinMax(X1, X2); for X := X1 to X2 do DrawPixel(X, Y); end; procedure NormalRectangle(X1, Y1, X2, Y2: Integer; DrawOutlinePixel, DrawFillPixel: TDrawPixelProcedure); var X, Y: Integer; begin SortRect(X1, Y1, X2, Y2); for X := X1 to X2 do DrawOutlinePixel(X, Y1); if Y1 < Y2 then for X := X1 to X2 do DrawOutlinePixel(X, Y2); for Y := Succ(Y1) to Pred(Y2) do begin DrawOutlinePixel(X1, Y); if X1 < X2 then DrawOutlinePixel(X2, Y); for X := Succ(X1) to Pred(X2) do DrawFillPixel(X, Y); end; end; (* EllipticRectangle - accurate elliptic rectangle plotting algorithm LX, LY - length of straight section of elliptic rectangle If both LX and LY are set to 0, the result is ellipse. *) procedure EllipticRectangle(X1, Y1, X2, Y2: Integer; LX, LY: Integer; DrawOutlinePixel, DrawFillPixel: TDrawPixelProcedure); var CX, CY, CX1, CY1, A, B, NX, NY: Single; X, Y, EX, EY: Integer; LX1, LY1: Integer; LX2, LY2: Integer; DivSqrA, DivSqrB: Single; I, J, S: Integer; EdgeList: Array of TPoint; procedure AddEdge(X, Y: Integer); begin if (EdgeList[Y].X = -1) or (X < EdgeList[Y].X) then EdgeList[Y].X := X; if (EdgeList[Y].Y = -1) or (X > EdgeList[Y].Y) then EdgeList[Y].Y := X; end; begin if (X1 = X2) and (Y1 = Y2) then begin DrawOutlinePixel(X1, Y1); Exit; end; SortRect(X1, Y1, X2, Y2); if (X2 - X1 = 1) or (Y2 - Y1 = 1) then begin FillPixelRect(X1, Y1, X2, Y2, DrawOutlinePixel); Exit; end; if (LX > X2 - X1) or (LY > Y2 - Y1) then begin NormalRectangle(X1, Y1, X2, Y2, DrawOutlinePixel, DrawFillPixel); Exit; end; SetLength(EdgeList, Ceil((Y2 - Y1 + 1) / 2)); for I := 0 to Pred(High(EdgeList)) do EdgeList[I] := Point(-1, -1); EdgeList[High(EdgeList)] := Point(0, 0); A := (X2 - X1 + 1 - LX) / 2; B := (Y2 - Y1 + 1 - LY) / 2; CX := (X2 + X1 + 1) / 2; CY := (Y2 + Y1 + 1) / 2; CX1 := X2 + 1 - A - Floor(CX); CY1 := Y2 + 1 - B - Floor(CY); EX := Floor(Sqr(A) / Sqrt(Sqr(A) + Sqr(B)) + Frac(A)); EY := Floor(Sqr(B) / Sqrt(Sqr(A) + Sqr(B)) + Frac(B)); DivSqrA := 1 / Sqr(A); DivSqrB := 1 / Sqr(B); NY := B; AddEdge(Floor(CX1), Round(CY1 + B) - 1); for X := 1 to Pred(EX) do begin NY := B * Sqrt(1 - Sqr(X + 0.5 - Frac(A)) * DivSqrA); AddEdge(Floor(CX1) + X, Round(CY1 + NY) - 1); end; LX1 := Floor(CX1) + Pred(EX); LY1 := Round(CY1 + NY) - 1; NX := A; AddEdge(Round(CX1 + A) - 1, Floor(CY1)); for Y := 1 to Pred(EY) do begin NX := A * Sqrt(1 - Sqr(Y + 0.5 - Frac(B)) * DivSqrB); AddEdge(Round(CX1 + NX) - 1, Floor(CY1) + Y); end; LX2 := Round(CX1 + NX) - 1; LY2 := Floor(CY1) + Pred(EY); if Abs(LX1 - LX2) > 1 then begin if Abs(LY1 - LY2) > 1 then AddEdge(LX1 + 1, LY1 - 1) else AddEdge(LX1 + 1, LY1); end else if Abs(LY1 - LY2) > 1 then AddEdge(LX2, LY1 - 1); for I := 0 to High(EdgeList) do begin if EdgeList[I].X = -1 then EdgeList[I] := Point(Round(CX1 + A) - 1, Round(CX1 + A) - 1) else Break; end; for J := 0 to High(EdgeList) do begin if (J = 0) and (Frac(CY) > 0) then begin for I := EdgeList[J].X to EdgeList[J].Y do begin DrawOutlinePixel(Floor(CX) + I, Floor(CY) + J); DrawOutlinePixel(Ceil(CX) - Succ(I), Floor(CY) + J); end; for I := Ceil(CX) - EdgeList[J].X to Floor(CX) + Pred(EdgeList[J].X) do begin DrawFillPixel(I, Floor(CY) + J); end; end else if (J = High(EdgeList)) then begin if Frac(CX) > 0 then S := -EdgeList[J].Y else S := -Succ(EdgeList[J].Y); for I := S to EdgeList[J].Y do begin DrawOutlinePixel(Floor(CX) + I, Floor(CY) + J); DrawOutlinePixel(Floor(CX) + I, Ceil(CY) - Succ(J)); end; end else begin for I := EdgeList[J].X to EdgeList[J].Y do begin DrawOutlinePixel(Floor(CX) + I, Floor(CY) + J); DrawOutlinePixel(Floor(CX) + I, Ceil(CY) - Succ(J)); if Floor(CX) + I <> Ceil(CX) - Succ(I) then begin DrawOutlinePixel(Ceil(CX) - Succ(I), Floor(CY) + J); DrawOutlinePixel(Ceil(CX) - Succ(I), Ceil(CY) - Succ(J)); end; end; for I := Ceil(CX) - EdgeList[J].X to Floor(CX) + Pred(EdgeList[J].X) do begin DrawFillPixel(I, Floor(CY) + J); DrawFillPixel(I, Ceil(CY) - Succ(J)); end; end; end; end; (* FloodFillScanLine - 4-directional scan line stack based flood fill algorithm with control of visited pixels. *) procedure FloodFillScanLine(X, Y, W, H: Integer; GetPixel: TGetPixelFunction; SamePixel: TSamePixelFunction; DrawPixel: TDrawPixelProcedure); var S: TRGB32Pixel; SX, EX, I: Integer; Added: Boolean; Visited: Array of Byte; Stack: Array of Integer; StackCount: Integer; function CheckPixel(AX, AY: Integer): Boolean; inline; begin if Visited[AX + AY * W] = 1 then Result := False else begin Result := SamePixel(AX, AY, S); end; end; procedure Push(AX, AY: Integer); inline; begin if StackCount >= High(Stack) then SetLength(Stack, Length(Stack) shl 1); Stack[StackCount] := AX or (AY shl 16); Inc(StackCount); end; procedure Pop(var AX, AY: Integer); inline; begin Dec(StackCount); AX := Stack[StackCount] and $FFFF; AY := (Stack[StackCount] shr 16) and $FFFF; end; begin if (X >= 0) and (X < W) and (Y >= 0) and (Y < H) then begin S := GetPixel(X, Y); SetLength(Stack, 1); StackCount := 0; SetLength(Visited, W * H); FillChar(Visited[0], Length(Visited), #0); Push(X, Y); repeat Pop(X, Y); if not CheckPixel(X, Y) then Continue; SX := X; while (SX > 0) and CheckPixel(Pred(SX), Y) do Dec(SX); EX := X; while (EX < Pred(W)) and CheckPixel(Succ(EX), Y) do Inc(EX); FillChar(Visited[SX + Y * W], Succ(EX - SX), #1); FillPixelRow(SX, EX, Y, DrawPixel); Added := False; if Y > 0 then for I := SX to EX do if CheckPixel(I, Pred(Y)) then begin if Added then Continue; Push(I, Pred(Y)); Added := True; end else Added := False; Added := False; if Y < Pred(H) then for I := SX to EX do if CheckPixel(I, Succ(Y)) then begin if Added then Continue; Push(I, Succ(Y)); Added := True; end else Added := False; until StackCount <= 0; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/rgb/rgbutils.pas���������������������������������������������������0000755�0001750�0001750�00000007656�11326425450�017335� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ /*************************************************************************** RGBUtils.pas ***************************************************************************/ ***************************************************************************** * * * See the file COPYING.modifiedLGPL, included in this distribution, * * for details about the copyright. * * * * 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. * * * ***************************************************************************** Author: Tom Gregorovic (_tom_@centrum.cz) Abstract: } unit RGBUtils; {$ifdef fpc} {$mode objfpc}{$H+} {$endif} interface uses Classes, SysUtils; type TIntArray = array of Integer; function DivideTrunc(Src, Dest: Integer): TIntArray; function GetMidPoints(const A: TIntArray): TIntArray; function GetDifference(const A: TIntArray): TIntArray; procedure SwapInt(var A, B: Integer); procedure SwapPtr(var A, B: Pointer); procedure MinMax(var A, B: Integer); procedure SortRect(var X1, Y1, X2, Y2: Integer); overload; procedure SortRect(var R: TRect); overload; procedure ClipDimension(ClipMin, ClipMax: Integer; var DstPos, SrcPos, SrcSize: Integer); operator =(A, B: TPoint): Boolean; implementation (* DivideTrunc divides bigger value of Src and Dest into array of chunks. Length(Result) = Min(Src, Dest) *) function DivideTrunc(Src, Dest: Integer): TIntArray; var I: Integer; VMax, VMin: Integer; P, D: Single; begin if Dest > Src then begin VMax := Dest; VMin := Src; end else begin VMax := Src; VMin := Dest; end; SetLength(Result, VMin); P := 0; D := VMax / VMin; for I := 0 to High(Result) do begin Result[I] := Round(P + D) - Round(P); P := P + D; end; end; (* GetMidPoints returns array of absolute positions of the middle in each chunk. *) function GetMidPoints(const A: TIntArray): TIntArray; var I, P, V: Integer; begin SetLength(Result, Length(A)); P := 0; for I := 0 to High(A) do begin V := A[I]; Result[I] := V shr 1 + P; Inc(P, V); end; end; (* GetDifference returns array of diffences between positions. *) function GetDifference(const A: TIntArray): TIntArray; var I, P: Integer; begin SetLength(Result, Length(A)); P := 0; for I := 0 to High(A) do begin Result[I] := A[I] - P; P := A[I]; end; end; operator =(A, B: TPoint): Boolean; begin Result := (A.X = B.X) and (A.Y = B.Y); end; procedure SwapInt(var A, B: Integer); var C: Integer; begin C := A; A := B; B := C; end; procedure SwapPtr(var A, B: Pointer); var C: Pointer; begin C := A; A := B; B := C; end; procedure MinMax(var A, B: Integer); var T: Integer; begin if A > B then begin T := A; A := B; B := T; end; end; procedure SortRect(var X1, Y1, X2, Y2: Integer); begin MinMax(X1, X2); MinMax(Y1, Y2); end; procedure SortRect(var R: TRect); begin MinMax(R.Left, R.Right); MinMax(R.Top, R.Bottom); end; procedure ClipDimension(ClipMin, ClipMax: Integer; var DstPos, SrcPos, SrcSize: Integer); var C: Integer; begin if ClipMin > DstPos then begin C := ClipMin - DstPos; Inc(SrcPos, C); Dec(SrcSize, C); DstPos := ClipMin; end; if ClipMax < DstPos + SrcSize then SrcSize := ClipMax - DstPos; end; end. ����������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/rgb/rgbcarbonroutines.pas������������������������������������������0000755�0001750�0001750�00000005641�11326425450�021222� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ /*************************************************************************** RGBCarbonRoutines.pas ***************************************************************************/ ***************************************************************************** * * * See the file COPYING.modifiedLGPL, included in this distribution, * * for details about the copyright. * * * * 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. * * * ***************************************************************************** Author: Tom Gregorovic (_tom_@centrum.cz) Abstract: This unit contains routines for Carbon interface. } unit RGBCarbonRoutines; {$ifdef fpc} {$mode objfpc}{$H+} {$endif} interface uses SysUtils, Classes, LCLType, MacOSAll, CarbonProc, CarbonGDIObjects, CarbonCanvas, RGBTypes, RGBUtils; procedure WidgetSetDrawRGB32Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); procedure WidgetSetDrawRGB8Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB8BitmapCore); implementation procedure WidgetSetDrawRGB32Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB32BitmapCore); var CGImage: CGImageRef; CarbonBitmap: TCarbonBitmap; begin if not CheckDC(Dest, 'WidgetSetDrawRGB32Bitmap') then Exit; CarbonBitmap := TCarbonBitmap.Create(Bitmap.Width, Bitmap.Height, 24, 32, cbaDWord, cbtRGB, Bitmap.Pixels, False); try CGImage := CarbonBitmap.CreateSubImage(Bounds(SrcX, SrcY, SrcWidth, SrcHeight)); TCarbonDeviceContext(Dest).DrawCGImage(DstX, DstY, SrcWidth, SrcHeight, CGImage); CGImageRelease(CGImage); finally CarbonBitmap.Free; end; end; procedure WidgetSetDrawRGB8Bitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bitmap: TRGB8BitmapCore); var CGImage: CGImageRef; CarbonBitmap: TCarbonBitmap; begin if not CheckDC(Dest, 'WidgetSetDrawRGB8Bitmap') then Exit; CarbonBitmap := TCarbonBitmap.Create(Bitmap.Width, Bitmap.Height, 8, 8, cbaDWord, cbtGray, Bitmap.Pixels, False); try CGImage := CarbonBitmap.CreateSubImage(Bounds(SrcX, SrcY, SrcWidth, SrcHeight)); TCarbonDeviceContext(Dest).DrawCGImage(DstX, DstY, SrcWidth, SrcHeight, CGImage); CGImageRelease(CGImage); finally CarbonBitmap.Free; end; end; end. �����������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/rgb/rgbtypes.pas���������������������������������������������������0000755�0001750�0001750�00000056720�11326425450�017335� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ /*************************************************************************** RGBTypes.pas ***************************************************************************/ ***************************************************************************** * * * See the file COPYING.modifiedLGPL, included in this distribution, * * for details about the copyright. * * * * 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. * * * ***************************************************************************** Author: Tom Gregorovic (_tom_@centrum.cz) Abstract: TRGB32Pixel - TRGB32Bitmap picture element, contains red, green and blue component and is platform dependent! TRGBBitmapCore - universal RGB bitmap core. TRGB32BitmapCore - 32-bit core of TRGB32Bitmap. } unit RGBTypes; {$ifdef fpc} {$mode objfpc}{$H+} {$endif} {$ifdef LCLwin32} {$define RGB} {$endif} {$ifdef LCLqt} {$define RGB} {$endif} interface uses Classes, SysUtils, FPImage, IntfGraphics, Graphics, Math, LCLProc, RGBUtils; type PRGBPixel = PByte; PRGB32Pixel = ^TRGB32Pixel; TRGB32Pixel = DWord; PRGB8Pixel = ^TRGB8Pixel; TRGB8Pixel = Byte; PRGB32PixelArray = ^TRGB32PixelArray; TRGB32PixelArray = packed array [0..0] of TRGB32Pixel; TPixelDifference = Word; const MAXDIFFERENCE = 255 + 255 + 255; type // integral float with 1/256 precision TIntensityFloat = Integer; TIntensityFloatTable = Array [0..255] of TIntensityFloat; { TRGBBitmapCore } TRGBBitmapCore = class(TPersistent) private FPixels: PRGBPixel; FSizeOfPixel: Integer; FWidth: Integer; FHeight: Integer; FRowPixelStride: Integer; FDataOwner: Boolean; function GetSize: Integer; public constructor Create(AWidth, AHeight: Integer; ASizeOfPixel: Integer); virtual; constructor CreateAsCopy(ABitmap: TRGBBitmapCore; ASizeOfPixel: Integer); virtual; constructor CreateFromData(AData: Pointer; AWidth, AHeight: Integer; ASizeOfPixel: Integer; ADataOwner: Boolean = False); virtual; destructor Destroy; override; procedure Assign(Source: TPersistent); override; procedure SwapWith(ABitmap: TRGBBitmapCore); virtual; public function GetPixelPtrUnsafe(X, Y: Integer): PRGBPixel; function GetPixelPtr(X, Y: Integer): PRGBPixel; procedure Clear; virtual; procedure ClearWhite; virtual; procedure Invert; virtual; procedure FlipHorz; virtual; procedure FlipVert; virtual; procedure Rotate90; virtual; procedure Rotate180; virtual; procedure Rotate270; virtual; public property DataOwner: Boolean read FDataOwner; property Width: Integer read FWidth; property Height: Integer read FHeight; property Pixels: PRGBPixel read FPixels; property RowPixelStride: Integer read FRowPixelStride; property Size: Integer read GetSize; property SizeOfPixel: Integer read FSizeOfPixel; end; { TRGB8BitmapCore } TRGB8BitmapCore = class(TRGBBitmapCore) public constructor Create(AWidth, AHeight: Integer); virtual; constructor CreateAsCopy(ABitmap: TRGBBitmapCore); virtual; constructor CreateFromData(AData: Pointer; AWidth, AHeight: Integer; ADataOwner: Boolean = False); virtual; procedure LoadFromLazIntfImageAlpha(AImage: TLazIntfImage); virtual; procedure SaveToLazIntfImageAlpha(AImage: TLazIntfImage); virtual; procedure SaveToLazIntfImageAlpha(AImage: TLazIntfImage; const ARect: TRect); virtual; procedure Assign(Source: TPersistent); override; procedure SwapWith(ABitmap: TRGBBitmapCore); override; public function Get8PixelPtrUnsafe(X, Y: Integer): PRGB8Pixel; function Get8PixelPtr(X, Y: Integer): PRGB8Pixel; function Get8PixelUnsafe(X, Y: Integer): TRGB8Pixel; procedure Set8PixelUnsafe(X, Y: Integer; Value: TRGB8Pixel); procedure Set8Pixel(X, Y: Integer; Value: TRGB8Pixel); end; { TRGB32BitmapCore } TRGB32BitmapCore = class(TRGBBitmapCore) public constructor Create(AWidth, AHeight: Integer); virtual; constructor CreateAsCopy(ABitmap: TRGBBitmapCore); virtual; constructor CreateFromLazIntfImage(AImage: TLazIntfImage); virtual; constructor CreateFromData(AData: Pointer; AWidth, AHeight: Integer; ADataOwner: Boolean = False); virtual; procedure Assign(Source: TPersistent); override; procedure SwapWith(ABitmap: TRGBBitmapCore); override; procedure SaveToLazIntfImage(AImage: TLazIntfImage); virtual; procedure SaveToLazIntfImage(AImage: TLazIntfImage; const ARect: TRect); virtual; public function Get32PixelPtrUnsafe(X, Y: Integer): PRGB32Pixel; function Get32PixelPtr(X, Y: Integer): PRGB32Pixel; function Get32PixelUnsafe(X, Y: Integer): TRGB32Pixel; procedure Set32PixelUnsafe(X, Y: Integer; Value: TRGB32Pixel); procedure Set32Pixel(X, Y: Integer; Value: TRGB32Pixel); end; procedure FlipHorzRGBBitmap(Bitmap: TRGBBitmapCore); procedure FlipVertRGBBitmap(Bitmap: TRGBBitmapCore); // intensity tables function GetIntensityFloatTable(A, B: Single): TIntensityFloatTable; // rotate clockwise procedure Rotate90CWRGBBitmap(Bitmap: TRGBBitmapCore); procedure Rotate180CWRGBBitmap(Bitmap: TRGBBitmapCore); procedure Rotate270CWRGBBitmap(Bitmap: TRGBBitmapCore); procedure InvertRGBBitmap(Bitmap: TRGBBitmapCore); procedure GrayscaleRGB32Bitmap(Bitmap: TRGB32BitmapCore); procedure DisableRGB32Bitmap(Bitmap: TRGB32BitmapCore); function RGB32PixelToColor(P: TRGB32Pixel): TColor; function ColorToRGB32Pixel(C: TColor): TRGB32Pixel; implementation function GetRedInline(P: TRGB32Pixel): Byte; inline; begin {$IFDEF RGB} Result := (P and $FF0000) shr 16; {$ELSE} Result := P and $FF; {$ENDIF} end; function GetGreenInline(P: TRGB32Pixel): Byte; inline; begin {$IFDEF RGB} Result := (P and $FF00) shr 8; {$ELSE} Result := (P and $FF00) shr 8; {$ENDIF} end; function GetBlueInline(P: TRGB32Pixel): Byte; inline; begin {$IFDEF RGB} Result := P and $FF; {$ELSE} Result := (P and $FF0000) shr 16; {$ENDIF} end; function RGBToRGB32PixelInline(R, G, B: Byte): TRGB32Pixel; inline; begin {$IFDEF RGB} Result := B or (G shl 8) or (R shl 16); {$ELSE} Result := R or (G shl 8) or (B shl 16); {$ENDIF} end; function RGB32PixelToColorInline(P: TRGB32Pixel): TColor; inline; begin {$IFDEF RGB} Result := ((P and $FF0000) shr 16) or (P and $FF00) or ((P and $FF) shl 16); {$ELSE} Result := P and $FFFFFF; {$ENDIF} end; function ColorToRGB32PixelInline(C: TColor): TRGB32Pixel; inline; begin {$IFDEF RGB} Result := ((C and $FF0000) shr 16) or (C and $FF00) or ((C and $FF) shl 16); {$ELSE} Result := C and $FFFFFF; {$ENDIF} end; function FPColorToRGB32PixelInline(F: TFPColor): TRGB32Pixel; inline; begin {$IFDEF RGB} Result := ((F.Blue shr 8) and $FF) or (F.Green and $FF00) or ((F.Red shl 8) and $FF0000); {$ELSE} Result := ((F.Red shr 8) and $FF) or (F.Green and $FF00) or ((F.Blue shl 8) and $FF0000); {$ENDIF} end; function RGB32PixelToFPColorInline(P: TRGB32Pixel): TFPColor; inline; begin {$IFDEF RGB} Result.Red := (P shr 16) and $FF; Result.Red := Result.Red or (Result.Red shl 8); Result.Green := P and $FF00; Result.Green := Result.Green or (Result.Green shr 8); Result.Blue := P and $FF; Result.Blue := Result.Blue or (Result.Blue shl 8); {$ELSE} Result.Red := P and $FF; Result.Red := Result.Red or (Result.Red shl 8); Result.Green := P and $FF00; Result.Green := Result.Green or (Result.Green shr 8); Result.Blue := (P shr 16) and $FF; Result.Blue := Result.Blue or (Result.Blue shl 8); {$ENDIF} end; function RGB32PixelToColor(P: TRGB32Pixel): TColor; begin Result := RGB32PixelToColorInline(P); end; function ColorToRGB32Pixel(C: TColor): TRGB32Pixel; begin Result := ColorToRGB32PixelInline(C); end; procedure SwapRGBPixels(A, B: PRGBPixel; const Size: Integer); inline; var T32: TRGB32Pixel; T8: TRGB8Pixel; begin if Size = 4 then begin T32 := PRGB32Pixel(A)^; PRGB32Pixel(A)^ := PRGB32Pixel(B)^; PRGB32Pixel(B)^ := T32; end else begin T8 := PRGB8Pixel(A)^; PRGB8Pixel(A)^ := PRGB8Pixel(B)^; PRGB8Pixel(B)^ := T8; end; end; procedure CopyRGBPixels(Src, Dest: PRGBPixel; const Size: Integer); inline; begin if Size = 4 then PRGB32Pixel(Dest)^ := PRGB32Pixel(Src)^ else begin PRGB8Pixel(Dest)^ := PRGB8Pixel(Src)^; end; end; function GetRGBBitmapPixelPtr(const Bitmap: TRGBBitmapCore; X, Y: Integer): PRGBPixel; inline; begin Result := Bitmap.FPixels; Inc(Result, Y * Bitmap.FRowPixelStride * Bitmap.FSizeOfPixel + X * Bitmap.FSizeOfPixel); end; function RoundIntensityFloatInline(V: TIntensityFloat): Byte; inline; begin Result := Max(0, Min(255, (V + 128) shr 8)); end; procedure FlipHorzRGBBitmap(Bitmap: TRGBBitmapCore); var X, Y: Integer; PNew, POld: PRGBPixel; begin for Y := 0 to Pred(Bitmap.Height) do begin PNew := Bitmap.GetPixelPtrUnsafe(0, Y); POld := Bitmap.GetPixelPtrUnsafe(Pred(Bitmap.Width), Y); for X := 0 to Pred(Bitmap.Width shr 1) do begin SwapRGBPixels(PNew, POld, Bitmap.SizeOfPixel); Inc(PNew, Bitmap.SizeOfPixel); Dec(POld, Bitmap.SizeOfPixel); end; end; end; procedure FlipVertRGBBitmap(Bitmap: TRGBBitmapCore); var X, Y: Integer; PNew, POld: PRGBPixel; begin for Y := 0 to Pred(Bitmap.Height shr 1) do begin PNew := Bitmap.GetPixelPtrUnsafe(0, Y); POld := Bitmap.GetPixelPtrUnsafe(0, Pred(Bitmap.Height) - Y); for X := 0 to Pred(Bitmap.Width) do begin SwapRGBPixels(PNew, POld, Bitmap.SizeOfPixel); Inc(PNew, Bitmap.SizeOfPixel); Inc(POld, Bitmap.SizeOfPixel); end; end; end; (* Creates look-up table T[I = 0..255] = A + I * B. *) function GetIntensityFloatTable(A, B: Single): TIntensityFloatTable; var I: Integer; C: Single; begin C := A; for I := 0 to High(Result) do begin Result[I] := Round(C * 256); C := C + B; end; end; procedure Rotate90CWRGBBitmap(Bitmap: TRGBBitmapCore); var X, Y: Integer; PNew, POld: PRGBPixel; Result: TRGBBitmapCore; begin Result := TRGBBitmapCore.Create(Bitmap.Height, Bitmap.Width, Bitmap.SizeOfPixel); try for Y := 0 to Pred(Bitmap.Height) do begin PNew := Result.GetPixelPtrUnsafe(Pred(Bitmap.Height) - Y, 0); POld := Bitmap.GetPixelPtrUnsafe(0, Y); for X := 0 to Pred(Bitmap.Width) do begin CopyRGBPixels(POld, PNew, Result.SizeOfPixel); Inc(PNew, Result.RowPixelStride * Result.SizeOfPixel); Inc(POld, Result.SizeOfPixel); end; end; Bitmap.SwapWith(Result); finally FreeAndNil(Result); end; end; procedure Rotate180CWRGBBitmap(Bitmap: TRGBBitmapCore); var X, Y: Integer; PNew, POld: PRGBPixel; begin for Y := 0 to Pred(Bitmap.Height shr 1) do begin PNew := Bitmap.GetPixelPtrUnsafe(0, Y); POld := Bitmap.GetPixelPtrUnsafe(Pred(Bitmap.Width), Pred(Bitmap.Height) - Y); for X := 0 to Pred(Bitmap.Width) do begin SwapRGBPixels(PNew, POld, Bitmap.SizeOfPixel); Inc(PNew, Bitmap.SizeOfPixel); Dec(POld, Bitmap.SizeOfPixel); end; end; if Odd(Bitmap.Height) then begin PNew := Bitmap.GetPixelPtrUnsafe(0, Bitmap.Height shr 1); POld := Bitmap.GetPixelPtrUnsafe(Pred(Bitmap.Width), Bitmap.Height shr 1); for X := 0 to Pred(Bitmap.Width shr 1) do begin SwapRGBPixels(PNew, POld, Bitmap.SizeOfPixel); Inc(PNew, Bitmap.SizeOfPixel); Dec(POld, Bitmap.SizeOfPixel); end; end; end; procedure Rotate270CWRGBBitmap(Bitmap: TRGBBitmapCore); var X, Y: Integer; PNew, POld: PRGBPixel; Result: TRGBBitmapCore; begin Result := TRGBBitmapCore.Create(Bitmap.Height, Bitmap.Width, Bitmap.SizeOfPixel); try for Y := 0 to Pred(Bitmap.Height) do begin PNew := Result.GetPixelPtrUnsafe(Y, Pred(Bitmap.Width)); POld := Bitmap.GetPixelPtrUnsafe(0, Y); for X := 0 to Pred(Bitmap.Width) do begin CopyRGBPixels(POld, PNew, Result.SizeOfPixel); Dec(PNew, Result.RowPixelStride * Result.SizeOfPixel); Inc(POld, Result.SizeOfPixel); end; end; Bitmap.SwapWith(Result); finally FreeAndNil(Result); end; end; procedure InvertRGBBitmap(Bitmap: TRGBBitmapCore); var I: Integer; P: PRGBPixel; begin P := Bitmap.Pixels; for I := 0 to Pred(Bitmap.Height * Bitmap.RowPixelStride * Bitmap.SizeOfPixel) do begin P^ := $FF - P^; Inc(P); end; end; procedure GrayscaleRGB32Bitmap(Bitmap: TRGB32BitmapCore); var X, Y: Integer; P: PRGB32Pixel; S: Byte; R, G, B: TIntensityFloatTable; begin // R * 0.299 + G * 0.587 + B * 0.114 R := GetIntensityFloatTable(0, 0.299); G := GetIntensityFloatTable(0, 0.587); B := GetIntensityFloatTable(0, 0.114); for Y := 0 to Pred(Bitmap.Height) do begin P := Bitmap.Get32PixelPtr(0, Y); for X := 0 to Pred(Bitmap.Width) do begin S := RoundIntensityFloatInline(R[GetRedInline(P^)] + G[GetGreenInline(P^)] + B[GetBlueInline(P^)]); P^ := RGBToRGB32PixelInline(S, S, S); Inc(P); end; end; end; procedure DisableRGB32Bitmap(Bitmap: TRGB32BitmapCore); var X, Y: Integer; P: PRGB32Pixel; S: Byte; R, G, B: TIntensityFloatTable; begin // 128 + R * 0.299 / 4 + G * 0.587 / 4 + B * 0.114 / 4 R := GetIntensityFloatTable(128, 0.299 / 4); G := GetIntensityFloatTable(0, 0.587 / 4); B := GetIntensityFloatTable(0, 0.114 / 4); for Y := 0 to Pred(Bitmap.Height) do begin P := Bitmap.Get32PixelPtr(0, Y); for X := 0 to Pred(Bitmap.Width) do begin S := RoundIntensityFloatInline(R[GetRedInline(P^)] + G[GetGreenInline(P^)] + B[GetBlueInline(P^)]); P^ := RGBToRGB32PixelInline(S, S, S); Inc(P); end; end; end; { TRGBBitmapCore } function TRGBBitmapCore.GetSize: Integer; begin Result := Height * RowPixelStride * SizeOfPixel; end; constructor TRGBBitmapCore.Create(AWidth, AHeight: Integer; ASizeOfPixel: Integer); begin inherited Create; FWidth := AWidth; FHeight := AHeight; // TODO: check on 64-bit arch. // 32-bit alignment FRowPixelStride := (((AWidth * ASizeOfPixel + 3) shr 2) shl 2) div ASizeOfPixel; FSizeOfPixel := ASizeOfPixel; FDataOwner := True; GetMem(FPixels, FHeight * FRowPixelStride * FSizeOfPixel); end; constructor TRGBBitmapCore.CreateAsCopy(ABitmap: TRGBBitmapCore; ASizeOfPixel: Integer); begin inherited Create; FWidth := ABitmap.Width; FHeight := ABitmap.Height; FRowPixelStride := ABitmap.RowPixelStride; FSizeOfPixel := ASizeOfPixel; FDataOwner := True; GetMem(FPixels, FHeight * FRowPixelStride * SizeOfPixel); Move(ABitmap.Pixels^, FPixels^, FHeight * FRowPixelStride * SizeOfPixel); end; constructor TRGBBitmapCore.CreateFromData(AData: Pointer; AWidth, AHeight: Integer; ASizeOfPixel: Integer; ADataOwner: Boolean); begin inherited Create; FWidth := AWidth; FHeight := AHeight; // TODO: check on 64-bit arch. // 32-bit alignment FRowPixelStride := (((AWidth * ASizeOfPixel + 3) shr 2) shl 2) div ASizeOfPixel; FSizeOfPixel := ASizeOfPixel; FPixels := AData; FDataOwner := ADataOwner; end; destructor TRGBBitmapCore.Destroy; begin if FDataOwner then FreeMem(FPixels); inherited; end; procedure TRGBBitmapCore.Assign(Source: TPersistent); begin if Source = nil then Exit; if Source = Self then Exit; if Source is TRGBBitmapCore then begin FreeMem(FPixels); FWidth := (Source as TRGBBitmapCore).Width; FHeight := (Source as TRGBBitmapCore).Height; FRowPixelStride := (Source as TRGBBitmapCore).RowPixelStride; FSizeOfPixel := (Source as TRGBBitmapCore).SizeOfPixel; GetMem(FPixels, FHeight * FRowPixelStride * FSizeOfPixel); Move((Source as TRGBBitmapCore).Pixels^, FPixels^, FHeight * FRowPixelStride * FSizeOfPixel); end else inherited Assign(Source); end; procedure TRGBBitmapCore.SwapWith(ABitmap: TRGBBitmapCore); begin if ABitmap = nil then Exit; SwapPtr(FPixels, ABitmap.FPixels); SwapInt(FWidth, ABitmap.FWidth); SwapInt(FHeight, ABitmap.FHeight); SwapInt(FRowPixelStride, ABitmap.FRowPixelStride); SwapInt(FSizeOfPixel, ABitmap.FSizeOfPixel); end; function TRGBBitmapCore.GetPixelPtrUnsafe(X, Y: Integer): PRGBPixel; begin Result := GetRGBBitmapPixelPtr(Self, X, Y); end; function TRGBBitmapCore.GetPixelPtr(X, Y: Integer): PRGBPixel; begin if (X >= 0) and (X < FWidth) and (Y >= 0) and (Y < FHeight) then Result := GetRGBBitmapPixelPtr(Self, X, Y) else Result := nil; end; procedure TRGBBitmapCore.Clear; begin FillByte(Pixels^, Size, 0); end; procedure TRGBBitmapCore.ClearWhite; begin FillByte(Pixels^, Size, $FF); end; procedure TRGBBitmapCore.Invert; begin InvertRGBBitmap(Self); end; procedure TRGBBitmapCore.FlipHorz; begin FlipHorzRGBBitmap(Self); end; procedure TRGBBitmapCore.FlipVert; begin FlipVertRGBBitmap(Self); end; procedure TRGBBitmapCore.Rotate90; begin Rotate90CWRGBBitmap(Self); end; procedure TRGBBitmapCore.Rotate180; begin Rotate180CWRGBBitmap(Self); end; procedure TRGBBitmapCore.Rotate270; begin Rotate270CWRGBBitmap(Self); end; { TRGB32BitmapCore } constructor TRGB32BitmapCore.Create(AWidth, AHeight: Integer); begin inherited Create(AWidth, AHeight, SizeOf(TRGB32Pixel)); end; constructor TRGB32BitmapCore.CreateAsCopy(ABitmap: TRGBBitmapCore); begin if ABitmap.SizeOfPixel = SizeOf(TRGB32Pixel) then inherited CreateAsCopy(ABitmap, SizeOf(TRGB32Pixel)); end; constructor TRGB32BitmapCore.CreateFromLazIntfImage(AImage: TLazIntfImage); var I, J: Integer; P: PRGB32Pixel; begin Create(AImage.Width, AImage.Height); for J := 0 to Pred(Height) do begin P := Get32PixelPtr(0, J); for I := 0 to Pred(Width) do begin if AImage.Colors[I, J].alpha < $FF00 then P^ := $FFFFFFFF else P^ := FPColorToRGB32PixelInline(AImage.Colors[I, J]); Inc(P); end; end; end; constructor TRGB32BitmapCore.CreateFromData(AData: Pointer; AWidth, AHeight: Integer; ADataOwner: Boolean); begin inherited CreateFromData(AData, AWidth, AHeight, SizeOf(TRGB32Pixel), ADataOwner); end; procedure TRGB32BitmapCore.Assign(Source: TPersistent); begin if (Source is TRGBBitmapCore) and ((Source as TRGBBitmapCore).SizeOfPixel = SizeOf(TRGB32Pixel)) then inherited Assign(Source); end; procedure TRGB32BitmapCore.SwapWith(ABitmap: TRGBBitmapCore); begin if ABitmap.SizeOfPixel = SizeOf(TRGB32Pixel) then inherited SwapWith(ABitmap); end; procedure TRGB32BitmapCore.SaveToLazIntfImage(AImage: TLazIntfImage); begin SaveToLazIntfImage(AImage, Bounds(0, 0, Width, Height)); end; procedure TRGB32BitmapCore.SaveToLazIntfImage(AImage: TLazIntfImage; const ARect: TRect); var I, J: Integer; P: PRGB32Pixel; W, H: Integer; begin W := ARect.Right - ARect.Left; H := ARect.Bottom - ARect.Top; AImage.SetSize(W, H); try for J := 0 to Pred(H) do begin P := Get32PixelPtr(ARect.Left, J + ARect.Top); for I := 0 to Pred(W) do begin AImage.Colors[I, J] := RGB32PixelToFPColorInline(P^); Inc(P); end; end; except AImage.Free; end; end; function TRGB32BitmapCore.Get32PixelPtrUnsafe(X, Y: Integer ): PRGB32Pixel; begin Result := PRGB32Pixel(GetRGBBitmapPixelPtr(Self, X, Y)); end; function TRGB32BitmapCore.Get32PixelPtr(X, Y: Integer): PRGB32Pixel; begin if (X >= 0) and (X < FWidth) and (Y >= 0) and (Y < FHeight) then Result := PRGB32Pixel(GetRGBBitmapPixelPtr(Self, X, Y)) else Result := nil; end; function TRGB32BitmapCore.Get32PixelUnsafe(X, Y: Integer): TRGB32Pixel; begin Result := GetRGBBitmapPixelPtr(Self, X, Y)^; end; procedure TRGB32BitmapCore.Set32PixelUnsafe(X, Y: Integer; Value: TRGB32Pixel); begin GetRGBBitmapPixelPtr(Self, X, Y)^ := Value; end; procedure TRGB32BitmapCore.Set32Pixel(X, Y: Integer; Value: TRGB32Pixel); begin if (X >= 0) and (X < FWidth) and (Y >= 0) and (Y < FHeight) then PRGB32Pixel(GetRGBBitmapPixelPtr(Self, X, Y))^ := Value; end; { TRGB8BitmapCore } constructor TRGB8BitmapCore.Create(AWidth, AHeight: Integer); begin inherited Create(AWidth, AHeight, SizeOf(TRGB8Pixel)); end; constructor TRGB8BitmapCore.CreateAsCopy(ABitmap: TRGBBitmapCore); begin if ABitmap.SizeOfPixel = SizeOf(TRGB8Pixel) then inherited CreateAsCopy(ABitmap, SizeOf(TRGB8Pixel)); end; constructor TRGB8BitmapCore.CreateFromData(AData: Pointer; AWidth, AHeight: Integer; ADataOwner: Boolean); begin inherited CreateFromData(AData, AWidth, AHeight, SizeOf(TRGB8Pixel), ADataOwner); end; procedure TRGB8BitmapCore.LoadFromLazIntfImageAlpha(AImage: TLazIntfImage); var I, J: Integer; P: PRGB8Pixel; begin for J := 0 to Pred(Height) do begin P := Get8PixelPtr(0, J); for I := 0 to Pred(Width) do begin P^ := (AImage.Colors[I, J].alpha shr 8) and $FF; Inc(P); end; end; end; procedure TRGB8BitmapCore.SaveToLazIntfImageAlpha(AImage: TLazIntfImage); begin SaveToLazIntfImageAlpha(AImage, Bounds(0, 0, Width, Height)); end; procedure TRGB8BitmapCore.SaveToLazIntfImageAlpha(AImage: TLazIntfImage; const ARect: TRect); var I, J: Integer; P: PRGB8Pixel; F: TFPColor; begin for J := 0 to Pred(AImage.Height) do begin P := Get8PixelPtr(ARect.Left, J + ARect.Top); for I := 0 to Pred(AImage.Width) do begin F := AImage.Colors[I, J]; F.alpha := P^ shl 8; AImage.Colors[I, J] := F; Inc(P); end; end; end; procedure TRGB8BitmapCore.Assign(Source: TPersistent); begin if (Source is TRGBBitmapCore) and ((Source as TRGBBitmapCore).SizeOfPixel = SizeOf(TRGB8Pixel)) then inherited Assign(Source); end; procedure TRGB8BitmapCore.SwapWith(ABitmap: TRGBBitmapCore); begin if ABitmap.SizeOfPixel = SizeOf(TRGB8Pixel) then inherited SwapWith(ABitmap); end; function TRGB8BitmapCore.Get8PixelPtrUnsafe(X, Y: Integer): PRGB8Pixel; begin Result := GetRGBBitmapPixelPtr(Self, X, Y); end; function TRGB8BitmapCore.Get8PixelPtr(X, Y: Integer): PRGB8Pixel; begin if (X >= 0) and (X < FWidth) and (Y >= 0) and (Y < FHeight) then Result := GetRGBBitmapPixelPtr(Self, X, Y) else Result := nil; end; function TRGB8BitmapCore.Get8PixelUnsafe(X, Y: Integer): TRGB8Pixel; begin Result := GetRGBBitmapPixelPtr(Self, X, Y)^; end; procedure TRGB8BitmapCore.Set8PixelUnsafe(X, Y: Integer; Value: TRGB8Pixel); begin GetRGBBitmapPixelPtr(Self, X, Y)^ := Value; end; procedure TRGB8BitmapCore.Set8Pixel(X, Y: Integer; Value: TRGB8Pixel); begin if (X >= 0) and (X < FWidth) and (Y >= 0) and (Y < FHeight) then GetRGBBitmapPixelPtr(Self, X, Y)^ := Value; end; end. ������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/rgb/rgbgraphics.pas������������������������������������������������0000755�0001750�0001750�00000065353�11326425450�017773� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ /*************************************************************************** RGBGraphics.pas ***************************************************************************/ ***************************************************************************** * * * See the file COPYING.modifiedLGPL, included in this distribution, * * for details about the copyright. * * * * 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. * * * ***************************************************************************** Author: Tom Gregorovic (_tom_@centrum.cz) Abstract: TRGB32Bitmap is a memory image which allows fast pixel manipulations. TRGB32Canvas is a TRGB32Bitmap canvas for drawing primitives and drawing bitmap image into TCanvas. } unit RGBGraphics; {$ifdef fpc} {$mode objfpc}{$H+} {$endif} interface uses Classes, SysUtils, LCLIntf, FPWriteBMP, LCLType, LCLProc, FPImage, LResources, IntfGraphics, GraphType, Graphics, Forms, Math, Clipbrd, RGBTypes, RGBRoutines, RGBUtils; type TEraseMode = (ermNone, ermErase, ermReplace); TDrawMode = (dmFillAndOutline, dmOutline, dmFill); TRandomDensity = Word; const MAXRANDOMDENSITY = $FFFF; type TMaskFillMode = (mfAdd, mfRemove, mfXOR); { TRGBMask } TRGBMask = class(TRGB8BitmapCore) private FBGPen: TPen; FFGPen: TPen; FFillMode: TMaskFillMode; FMaskedPixels: Integer; protected procedure AddPixel(X, Y: Integer); procedure RemovePixel(X, Y: Integer); procedure XORPixel(X, Y: Integer); procedure CreatePens; virtual; function GetFillProcedure: TDrawPixelProcedure; virtual; function GetMaskedPixelsCount: Integer; public constructor Create(AWidth, AHeight: Integer); override; constructor CreateAsCopy(ABitmap: TRGBBitmapCore); override; destructor Destroy; override; procedure LoadFromLazIntfImageAlpha(AImage: TLazIntfImage); override; procedure SwapWith(ABitmap: TRGBBitmapCore); override; procedure Assign(Source: TPersistent); override; procedure UpdateMaskedPixels; procedure Draw(X, Y: Integer; AMask: TRGBMask); procedure DrawShapeTo(ACanvas: TCanvas; X, Y: Integer); procedure StretchDrawShapeTo(ACanvas: TCanvas; DstX, DstY, DstWidth, DstHeight: Integer); procedure StretchDrawShapePortionTo(ACanvas: TCanvas; DstX, DstY, DstWidth, DstHeight: Integer; DX, DY, DW, DH: Integer); procedure DrawTo(ACanvas: TCanvas; X, Y: Integer); procedure StretchTrunc(AWidth, AHeight: Integer); virtual; procedure Rectangle(X1, Y1, X2, Y2: Integer); procedure Ellipse(X1, Y1, X2, Y2: Integer); procedure Clear; override; procedure ClearWhite; override; procedure Invert; override; public function IsEmpty: Boolean; function GetMaskedRect: TRect; property BackgroundPen: TPen read FBGPen; property ForegroundPen: TPen read FFGPen; property FillMode: TMaskFillMode read FFillMode write FFillMode; end; { TRGB32Canvas } TRGB32Canvas = class private FDrawMode: TDrawMode; FEraseMode: TEraseMode; FFillColor: TRGB32Pixel; FFloodFillTolerance: TPixelDifference; FOutlineColor: TRGB32Pixel; FOwner: TRGB32BitmapCore; FPaperColor: TRGB32Pixel; FRandomDensity: TRandomDensity; FRandomEnabled: Boolean; FRectangleRoundness: Integer; function GetFillColor: TColor; function GetOutlineColor: TColor; function GetPaperColor: TColor; procedure SetFillColor(const AValue: TColor); procedure SetOutlineColor(const AValue: TColor); procedure SetPaperColor(const AValue: TColor); protected function PixelMasked(X, Y: Integer): Boolean; function SamePixelUnsafe(X, Y: Integer; Value: TRGB32Pixel): Boolean; function SamePixelUnmasked(X, Y: Integer; Value: TRGB32Pixel): Boolean; procedure DrawOutlinePixel(X, Y: Integer); procedure DrawFillPixel(X, Y: Integer); procedure DrawPaperPixel(X, Y: Integer); procedure DrawReplacePixel(X, Y: Integer); procedure DrawRandomOutlinePixel(X, Y: Integer); procedure DrawRandomFillPixel(X, Y: Integer); procedure DrawRandomPaperPixel(X, Y: Integer); procedure DrawEmptyPixel(X, Y: Integer); function GetOutlineProcedure: TDrawPixelProcedure; virtual; function GetFillProcedure: TDrawPixelProcedure; virtual; public constructor Create(AOwner: TRGB32BitmapCore); procedure SetColor(X, Y: Integer; Value: TColor); function GetColor(X, Y: Integer): TColor; procedure Fill(Color: TColor); procedure FillRect(X1, Y1, X2, Y2: Integer); procedure FillEllipse(X1, Y1, X2, Y2: Integer); procedure Line(X1, Y1, X2, Y2: Integer); procedure Rectangle(X1, Y1, X2, Y2: Integer); procedure Ellipse(X1, Y1, X2, Y2: Integer); procedure FloodFill(X, Y: Integer); procedure MaskFloodFill(X, Y: Integer); public procedure DrawTo(ACanvas: TCanvas; X, Y: Integer); procedure StretchDrawTo(ACanvas: TCanvas; DstX, DstY, DstWidth, DstHeight: Integer); public property EraseMode: TEraseMode read FEraseMode write FEraseMode; property DrawMode: TDrawMode read FDrawMode write FDrawMode; property FloodFillTolerance: TPixelDifference read FFloodFillTolerance write FFloodFillTolerance; property FillColor: TColor read GetFillColor write SetFillColor; property OutlineColor: TColor read GetOutlineColor write SetOutlineColor; property PaperColor: TColor read GetPaperColor write SetPaperColor; property RandomEnabled: Boolean read FRandomEnabled write FRandomEnabled; property RandomDensity: TRandomDensity read FRandomDensity write FRandomDensity; property RectangleRoundness: Integer read FRectangleRoundness write FRectangleRoundness; end; TSmoothMethod = (smAreaPixel, smBilinear, smBicubic); { TRGB32Bitmap } TRGB32Bitmap = class(TRGB32BitmapCore) private FCanvas: TRGB32Canvas; FMask: TRGBMask; protected function CreateDefaultLazIntfImage: TLazIntfImage; public constructor Create(AWidth, AHeight: Integer); override; constructor CreateAsCopy(ABitmap: TRGBBitmapCore); override; constructor CreateFromLazIntfImage(AImage: TLazIntfImage); override; constructor CreateFromFile(const FileName: String); virtual; constructor CreateFromBitmap(ABitmap: TRasterImage); virtual; destructor Destroy; override; procedure Assign(Source: TPersistent); override; procedure SwapWith(ABitmap: TRGBBitmapCore); override; procedure SaveToLazIntfImage(AImage: TLazIntfImage; const ARect: TRect); override; procedure SaveToStream(Stream: TStream); virtual; procedure SaveToStream(Stream: TStream; AWriterClass: TFPCustomImageWriterClass); virtual; procedure SaveToStream(Stream: TStream; const ARect: TRect; AWriterClass: TFPCustomImageWriterClass); virtual; procedure SaveToFile(const FileName: String); virtual; procedure SaveToLazarusResource(const FileName, Name: String); virtual; public procedure Draw(X, Y: Integer; ABitmap: TRGB32Bitmap); procedure StretchTrunc(AWidth, AHeight: Integer); virtual; procedure StretchSmooth(AWidth, AHeight: Integer; Method: TSmoothMethod); virtual; procedure Grayscale; virtual; procedure Disable; virtual; procedure CutToClipboard; virtual; procedure CopyToClipboard; virtual; procedure Delete; virtual; procedure FlipHorz; override; procedure FlipVert; override; procedure Rotate90; override; procedure Rotate180; override; procedure Rotate270; override; public property Canvas: TRGB32Canvas read FCanvas; property Mask: TRGBMask read FMask write FMask; end; implementation function AbsByte(Src: Integer): Byte; inline; begin if Src >= 0 then Result := Src else Result := -Src; end; function RGB32PixelDifference(A, B: TRGB32Pixel): TPixelDifference; inline; begin Result := AbsByte(((A shr 16) and $FF) - ((B shr 16) and $FF)) + AbsByte(((A shr 8) and $FF) - ((B shr 8) and $FF)) + AbsByte((A and $FF) - (B and $FF)); end; { TRGB32Bitmap } function TRGB32Bitmap.CreateDefaultLazIntfImage: TLazIntfImage; var RID: TRawImageDescription; DC: HDC; begin DC := GetDC(0); try RawImage_DescriptionFromDevice(DC, RID); finally ReleaseDC(0, DC); end; Result := TLazIntfImage.Create(0, 0); Result.DataDescription := RID; end; constructor TRGB32Bitmap.Create(AWidth, AHeight: Integer); begin inherited; FCanvas := TRGB32Canvas.Create(Self); FMask := TRGBMask.Create(AWidth, AHeight); end; constructor TRGB32Bitmap.CreateAsCopy(ABitmap: TRGBBitmapCore); begin inherited; FCanvas := TRGB32Canvas.Create(Self); if ABitmap is TRGB32Bitmap then FMask := TRGBMask.CreateAsCopy((ABitmap as TRGB32Bitmap).Mask) else FMask := TRGBMask.Create(ABitmap.Width, ABitmap.Height); end; constructor TRGB32Bitmap.CreateFromLazIntfImage(AImage: TLazIntfImage); begin inherited CreateFromLazIntfImage(AImage); FMask.LoadFromLazIntfImageAlpha(AImage); end; constructor TRGB32Bitmap.CreateFromFile(const FileName: String); var Image: TLazIntfImage; begin Image := CreateDefaultLazIntfImage; try Image.LoadFromFile(FileName); CreateFromLazIntfImage(Image); finally Image.Free; end; end; constructor TRGB32Bitmap.CreateFromBitmap(ABitmap: TRasterImage); var Image: TLazIntfImage; begin Image := ABitmap.CreateIntfImage; try CreateFromLazIntfImage(Image); finally Image.Free; end; end; destructor TRGB32Bitmap.Destroy; begin FCanvas.Free; FMask.Free; inherited; end; procedure TRGB32Bitmap.Assign(Source: TPersistent); begin inherited Assign(Source); if Source is TRGB32Bitmap then begin Mask.Assign((Source as TRGB32Bitmap).Mask); end; end; procedure TRGB32Bitmap.SwapWith(ABitmap: TRGBBitmapCore); begin inherited SwapWith(ABitmap); if ABitmap is TRGB32Bitmap then begin Mask.SwapWith((ABitmap as TRGB32Bitmap).Mask); end; end; procedure TRGB32Bitmap.SaveToLazIntfImage(AImage: TLazIntfImage; const ARect: TRect); begin inherited SaveToLazIntfImage(AImage, ARect); if not Mask.IsEmpty then FMask.SaveToLazIntfImageAlpha(AImage, ARect); end; procedure TRGB32Bitmap.SaveToStream(Stream: TStream); begin SaveToStream(Stream, Bounds(0, 0, Width, Height), TLazWriterXPM); end; procedure TRGB32Bitmap.SaveToStream(Stream: TStream; AWriterClass: TFPCustomImageWriterClass); begin SaveToStream(Stream, Bounds(0, 0, Width, Height), AWriterClass); end; procedure TRGB32Bitmap.SaveToStream(Stream: TStream; const ARect: TRect; AWriterClass: TFPCustomImageWriterClass); var Image: TLazIntfImage; Writer: TFPCustomImageWriter; begin Image := CreateDefaultLazIntfImage; Writer := AWriterClass.Create; try SaveToLazIntfImage(Image, ARect); Image.SaveToStream(Stream, Writer); finally Writer.Free; Image.Free; end; end; procedure TRGB32Bitmap.SaveToFile(const FileName: String); var Image: TLazIntfImage; begin Image := CreateDefaultLazIntfImage; try inherited SaveToLazIntfImage(Image); Image.SaveToFile(FileName); finally Image.Free; end; end; procedure TRGB32Bitmap.SaveToLazarusResource(const FileName, Name: String); var PixmapStream, ResourceStream: TMemoryStream; FileStream: TFileStream; begin PixmapStream := TMemoryStream.Create; ResourceStream := TMemoryStream.Create; try SaveToStream(PixmapStream); PixmapStream.Position := 0; BinaryToLazarusResourceCode(PixmapStream, ResourceStream, Name, 'XPM'); ResourceStream.Position := 0; FileStream := TFileStream.Create(FileName, fmCreate); try FileStream.CopyFrom(ResourceStream, ResourceStream.Size); finally FileStream.Free; end; finally PixmapStream.Free; ResourceStream.Free; end; end; procedure TRGB32Bitmap.Draw(X, Y: Integer; ABitmap: TRGB32Bitmap); begin DrawRGB32Bitmap(Self, X, Y, ABitmap); end; procedure TRGB32Bitmap.StretchTrunc(AWidth, AHeight: Integer); var Result: TRGB32Bitmap; begin if (AWidth = Width) and (AHeight = Height) then Exit; Result := TRGB32Bitmap.Create(AWidth, AHeight); try StretchRGB32BitmapTrunc(Result, Self); inherited SwapWith(Result); Mask.StretchTrunc(AWidth, AHeight); finally FreeAndNil(Result); end; end; procedure TRGB32Bitmap.StretchSmooth(AWidth, AHeight: Integer; Method: TSmoothMethod); begin // end; procedure TRGB32Bitmap.Grayscale; begin GrayscaleRGB32Bitmap(Self); end; procedure TRGB32Bitmap.Disable; begin DisableRGB32Bitmap(Self); end; procedure TRGB32Bitmap.CutToClipboard; begin CopyToClipboard; Delete; end; procedure TRGB32Bitmap.CopyToClipboard; var PixmapStream, BitmapStream: TMemoryStream; PixmapWriter, BitmapWriter: TFPCustomImageWriter; Image: TLazIntfImage; R: TRect; begin PixmapStream := TMemoryStream.Create; BitmapStream := TMemoryStream.Create; Image := CreateDefaultLazIntfImage; PixmapWriter := TLazWriterXPM.Create; BitmapWriter := TFPWriterBMP.Create; try R := Mask.GetMaskedRect; SaveToLazIntfImage(Image, R); Clipboard.Open; try Clipboard.Clear; Image.SaveToStream(PixmapStream, PixmapWriter); Clipboard.AddFormat(PredefinedClipboardFormat(pcfPixmap), PixmapStream); Image.SaveToStream(BitmapStream, BitmapWriter); Clipboard.AddFormat(PredefinedClipboardFormat(pcfBitmap), BitmapStream); finally Clipboard.Close; end; finally PixmapStream.Free; BitmapStream.Free; Image.Free; PixmapWriter.Free; BitmapWriter.Free; end; end; procedure TRGB32Bitmap.Delete; begin Canvas.Fill(Canvas.PaperColor); end; procedure TRGB32Bitmap.FlipHorz; begin inherited FlipHorz; Mask.FlipHorz; end; procedure TRGB32Bitmap.FlipVert; begin inherited FlipVert; Mask.FlipVert; end; procedure TRGB32Bitmap.Rotate90; begin inherited Rotate90; Mask.Rotate90; end; procedure TRGB32Bitmap.Rotate180; begin inherited Rotate180; Mask.Rotate180; end; procedure TRGB32Bitmap.Rotate270; begin inherited Rotate270; Mask.Rotate270; end; { TRGB32Canvas } constructor TRGB32Canvas.Create(AOwner: TRGB32BitmapCore); begin inherited Create; FOwner := AOwner; FRandomDensity := MAXRANDOMDENSITY; FFloodFillTolerance := 0; FRectangleRoundness := 0; end; procedure TRGB32Canvas.SetColor(X, Y: Integer; Value: TColor); begin FOwner.Set32Pixel(X, Y, ColorToRGB32Pixel(Value)); end; function TRGB32Canvas.GetColor(X, Y: Integer): TColor; var P: PRGB32Pixel; begin P := FOwner.Get32PixelPtr(X, Y); if P <> nil then Result := RGB32PixelToColor(P^) else Result := clNone; end; function TRGB32Canvas.GetFillColor: TColor; begin Result := RGB32PixelToColor(FFillColor); end; function TRGB32Canvas.GetOutlineColor: TColor; begin Result := RGB32PixelToColor(FOutlineColor); end; function TRGB32Canvas.GetPaperColor: TColor; begin Result := RGB32PixelToColor(FPaperColor); end; procedure TRGB32Canvas.SetFillColor(const AValue: TColor); begin FFillColor := ColorToRGB32Pixel(AValue); end; procedure TRGB32Canvas.SetOutlineColor(const AValue: TColor); begin FOutlineColor := ColorToRGB32Pixel(AValue); end; procedure TRGB32Canvas.SetPaperColor(const AValue: TColor); begin FPaperColor := ColorToRGB32Pixel(AValue); end; function TRGB32Canvas.PixelMasked(X, Y: Integer): Boolean; var P: PRGB8Pixel; begin if not (FOwner is TRGB32Bitmap) then Result := True else if (FOwner as TRGB32Bitmap).Mask.IsEmpty then Result := True else begin P := (FOwner as TRGB32Bitmap).Mask.Get8PixelPtr(X, Y); Result := (P <> nil) and (P^ = $FF); end; end; function TRGB32Canvas.SamePixelUnsafe(X, Y: Integer; Value: TRGB32Pixel): Boolean; begin Result := PixelMasked(X, Y) and (RGB32PixelDifference(FOwner.Get32PixelUnsafe(X, Y), Value) <= FFloodFillTolerance); end; function TRGB32Canvas.SamePixelUnmasked(X, Y: Integer; Value: TRGB32Pixel): Boolean; begin Result := RGB32PixelDifference(FOwner.Get32PixelUnsafe(X, Y), Value) <= FFloodFillTolerance; end; procedure TRGB32Canvas.DrawOutlinePixel(X, Y: Integer); begin if PixelMasked(X, Y) then FOwner.Set32Pixel(X, Y, FOutlineColor); end; procedure TRGB32Canvas.DrawFillPixel(X, Y: Integer); begin if PixelMasked(X, Y) then FOwner.Set32Pixel(X, Y, FFillColor); end; procedure TRGB32Canvas.DrawPaperPixel(X, Y: Integer); begin if PixelMasked(X, Y) then FOwner.Set32Pixel(X, Y, FPaperColor); end; procedure TRGB32Canvas.DrawReplacePixel(X, Y: Integer); var P: PRGB32Pixel; begin if not PixelMasked(X, Y) then Exit; P := FOwner.Get32PixelPtr(X, Y); if (P <> nil) and (P^ = FFillColor) then P^ := FPaperColor; end; procedure TRGB32Canvas.DrawRandomOutlinePixel(X, Y: Integer); begin if PixelMasked(X, Y) and (Random(MAXRANDOMDENSITY) < FRandomDensity) then FOwner.Set32Pixel(X, Y, FOutlineColor); end; procedure TRGB32Canvas.DrawRandomFillPixel(X, Y: Integer); begin if PixelMasked(X, Y) and (Random(MAXRANDOMDENSITY) < FRandomDensity) then FOwner.Set32Pixel(X, Y, FFillColor); end; procedure TRGB32Canvas.DrawRandomPaperPixel(X, Y: Integer); begin if PixelMasked(X, Y) and (Random(MAXRANDOMDENSITY) < FRandomDensity) then FOwner.Set32Pixel(X, Y, FPaperColor); end; procedure TRGB32Canvas.DrawEmptyPixel(X, Y: Integer); begin // end; function TRGB32Canvas.GetOutlineProcedure: TDrawPixelProcedure; begin if not FRandomEnabled then begin case DrawMode of dmFillAndOutline, dmOutline: begin case EraseMode of ermNone: Result := @DrawOutlinePixel; ermErase: Result := @DrawPaperPixel; ermReplace: Result := @DrawReplacePixel; end; end; else Result := @DrawEmptyPixel; end; end else begin case EraseMode of ermNone: Result := @DrawRandomFillPixel; ermErase: Result := @DrawRandomPaperPixel; ermReplace: Result := @DrawRandomFillPixel; end; end; end; function TRGB32Canvas.GetFillProcedure: TDrawPixelProcedure; begin if not FRandomEnabled then begin case DrawMode of dmFillAndOutline, dmFill: begin case EraseMode of ermNone: Result := @DrawFillPixel; ermErase: Result := @DrawPaperPixel; ermReplace: Result := @DrawReplacePixel; end; end; else Result := @DrawEmptyPixel; end; end else begin case EraseMode of ermNone: Result := @DrawRandomFillPixel; ermErase: Result := @DrawRandomPaperPixel; ermReplace: Result := @DrawRandomFillPixel; end; end; end; procedure TRGB32Canvas.Fill(Color: TColor); var P: PRGB32Pixel; C: TRGB32Pixel; PM: PRGB8Pixel; I, J: Integer; begin C := ColorToRGB32Pixel(Color); for J := 0 to Pred(FOwner.Height) do begin P := FOwner.Get32PixelPtr(0, J); if (FOwner is TRGB32Bitmap) and not (FOwner as TRGB32Bitmap).Mask.IsEmpty then begin PM := (FOwner as TRGB32Bitmap).Mask.Get8PixelPtr(0, J); for I := 0 to Pred(FOwner.Width) do begin if PM^ = $FF then P^ := C; Inc(P); Inc(PM); end; end else FillDWord(P^, FOwner.Width, C); end; end; procedure TRGB32Canvas.FillRect(X1, Y1, X2, Y2: Integer); begin FillPixelRect(X1, Y1, X2, Y2, GetFillProcedure); end; procedure TRGB32Canvas.FillEllipse(X1, Y1, X2, Y2: Integer); begin EllipticRectangle(X1, Y1, X2, Y2, 0, 0, GetFillProcedure, GetFillProcedure); end; procedure TRGB32Canvas.Line(X1, Y1, X2, Y2: Integer); begin LineBresenham(X1, Y1, X2, Y2, GetOutlineProcedure); end; procedure TRGB32Canvas.Rectangle(X1, Y1, X2, Y2: Integer); var R1, R2: Integer; begin R1 := Max(0, Succ(Abs(X2 - X1)) - RectangleRoundness); R2 := Max(0, Succ(Abs(Y2 - Y1)) - RectangleRoundness); EllipticRectangle(X1, Y1, X2, Y2, R1, R2, GetOutlineProcedure, GetFillProcedure); end; procedure TRGB32Canvas.Ellipse(X1, Y1, X2, Y2: Integer); begin EllipticRectangle(X1, Y1, X2, Y2, 0, 0, GetOutlineProcedure, GetFillProcedure); end; procedure TRGB32Canvas.FloodFill(X, Y: Integer); begin case EraseMode of ermNone: FloodFillScanLine(X, Y, FOwner.Width, FOwner.Height, @FOwner.Get32PixelUnsafe, @SamePixelUnsafe, @DrawFillPixel); ermErase: FloodFillScanLine(X, Y, FOwner.Width, FOwner.Height, @FOwner.Get32PixelUnsafe, @SamePixelUnsafe, @DrawPaperPixel); end; end; procedure TRGB32Canvas.MaskFloodFill(X, Y: Integer); begin if not (FOwner is TRGB32Bitmap) then Exit; FloodFillScanLine(X, Y, FOwner.Width, FOwner.Height, @FOwner.Get32PixelUnsafe, @SamePixelUnmasked, (FOwner as TRGB32Bitmap).Mask.GetFillProcedure);; end; procedure TRGB32Canvas.DrawTo(ACanvas: TCanvas; X, Y: Integer); begin if ACanvas <> nil then with FOwner do DrawRGB32Bitmap(ACanvas.Handle, X, Y, 0, 0, Width, Height, FOwner); end; procedure TRGB32Canvas.StretchDrawTo(ACanvas: TCanvas; DstX, DstY, DstWidth, DstHeight: Integer); begin if ACanvas <> nil then with FOwner do StretchDrawRGB32Bitmap(ACanvas.Handle, DstX, DstY, DstWidth, DstHeight, 0, 0, Width, Height, FOwner); end; { TRGBMask } procedure TRGBMask.AddPixel(X, Y: Integer); var P: PRGB8Pixel; begin P := Get8PixelPtr(X, Y); if P <> nil then begin if P^ <> $FF then Inc(FMaskedPixels); P^ := $FF; end; end; procedure TRGBMask.RemovePixel(X, Y: Integer); var P: PRGB8Pixel; begin P := Get8PixelPtr(X, Y); if P <> nil then begin if P^ = $FF then Dec(FMaskedPixels); P^ := 0; end; end; procedure TRGBMask.XORPixel(X, Y: Integer); var P: PRGB8Pixel; begin P := Get8PixelPtr(X, Y); if P <> nil then begin if P^ = 0 then Inc(FMaskedPixels); if P^ = $FF then Dec(FMaskedPixels); P^ := $FF - P^; end; end; procedure TRGBMask.CreatePens; begin FBGPen := TPen.Create; FBGPen.Color := clYellow; FFGPen := TPen.Create; FFGPen.Color := clBlue; //FFGPen.Style := psDot; end; function TRGBMask.GetFillProcedure: TDrawPixelProcedure; begin case FillMode of mfAdd: Result := @AddPixel; mfRemove: Result := @RemovePixel; mfXOR: Result := @XORPixel; end; end; function TRGBMask.GetMaskedPixelsCount: Integer; var I, J: Integer; P: PRGB8Pixel; begin Result := 0; for J := 0 to Pred(Height) do begin P := Get8PixelPtr(0, J); for I := 0 to Pred(Width) do begin if P^ = $FF then Inc(Result); Inc(P); end; end; end; constructor TRGBMask.Create(AWidth, AHeight: Integer); begin inherited Create(AWidth, AHeight); Clear; CreatePens; end; constructor TRGBMask.CreateAsCopy(ABitmap: TRGBBitmapCore); begin inherited CreateAsCopy(ABitmap); UpdateMaskedPixels; CreatePens; end; procedure TRGBMask.SwapWith(ABitmap: TRGBBitmapCore); begin inherited SwapWith(ABitmap); UpdateMaskedPixels; end; procedure TRGBMask.Assign(Source: TPersistent); begin inherited Assign(Source); UpdateMaskedPixels; end; procedure TRGBMask.UpdateMaskedPixels; begin FMaskedPixels := GetMaskedPixelsCount; end; procedure TRGBMask.Draw(X, Y: Integer; AMask: TRGBMask); begin DrawRGB8Bitmap(Self, X, Y, AMask); UpdateMaskedPixels; end; destructor TRGBMask.Destroy; begin FBGPen.Free; FFGPen.Free; inherited Destroy; end; procedure TRGBMask.LoadFromLazIntfImageAlpha(AImage: TLazIntfImage); begin inherited LoadFromLazIntfImageAlpha(AImage); UpdateMaskedPixels; end; procedure TRGBMask.DrawShapeTo(ACanvas: TCanvas; X, Y: Integer); begin StretchDrawShapeTo(ACanvas, X, Y, Width, Height); end; procedure TRGBMask.StretchDrawShapeTo(ACanvas: TCanvas; DstX, DstY, DstWidth, DstHeight: Integer); begin StretchDrawShapePortionTo(ACanvas, DstX, DstY, DstWidth, DstHeight, 0, 0, Width, Height); end; procedure TRGBMask.StretchDrawShapePortionTo(ACanvas: TCanvas; DstX, DstY, DstWidth, DstHeight: Integer; DX, DY, DW, DH: Integer); begin if ACanvas <> nil then StretchDrawRGBMaskShapePortion(ACanvas.Handle, DstX, DstY, DstWidth, DstHeight, Self, DX, DY, DW, DH, FBGPen.Reference.Handle, FFGPen.Reference.Handle); end; procedure TRGBMask.DrawTo(ACanvas: TCanvas; X, Y: Integer); begin if ACanvas <> nil then DrawRGB8Bitmap(ACanvas.Handle, X, Y, 0, 0, Width, Height, Self); end; procedure TRGBMask.StretchTrunc(AWidth, AHeight: Integer); var Result: TRGBMask; begin if (AWidth = Width) and (AHeight = Height) then Exit; Result := TRGBMask.Create(AWidth, AHeight); try StretchRGB8BitmapTrunc(Result, Self); SwapWith(Result); FMaskedPixels := GetMaskedPixelsCount; finally FreeAndNil(Result); end; end; procedure TRGBMask.Rectangle(X1, Y1, X2, Y2: Integer); begin FillPixelRect(X1, Y1, X2, Y2, GetFillProcedure); end; procedure TRGBMask.Ellipse(X1, Y1, X2, Y2: Integer); begin EllipticRectangle(X1, Y1, X2, Y2, 0, 0, GetFillProcedure, GetFillProcedure); end; procedure TRGBMask.Clear; begin inherited Clear; FMaskedPixels := 0; end; procedure TRGBMask.ClearWhite; begin inherited ClearWhite; FMaskedPixels := Width * Height; end; procedure TRGBMask.Invert; begin inherited Invert; FMaskedPixels := Width * Height - FMaskedPixels; end; function TRGBMask.IsEmpty: Boolean; begin Result := FMaskedPixels = 0; end; function TRGBMask.GetMaskedRect: TRect; var I, J: Integer; LineMasked: Boolean; P: PRGB8Pixel; begin Result := Rect(Width, Height, 0, 0); for J := 0 to Pred(Height) do begin P := Get8PixelPtr(0, J); LineMasked := False; for I := 0 to Pred(Width) do begin if P^ = $FF then begin LineMasked := True; if I < Result.Left then Result.Left := I; if Succ(I) > Result.Right then Result.Right := Succ(I); end; Inc(P); end; if LineMasked then begin if J < Result.Top then Result.Top := J; if Succ(J) > Result.Bottom then Result.Bottom := Succ(J); end; end; SortRect(Result); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/autoroi.pas��������������������������������������������������������0000755�0001750�0001750�00000051211�11540216612�016370� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit autoroi; interface uses {$IFNDEF FPC} RXSpin,capmenu, {$ELSE} Spin,lResources, {$ENDIF} {$IFNDEF Unix} Windows,{$ENDIF} SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Buttons, StdCtrls, define_types, ExtCtrls, nifti_img,nifti_img_view; type { TAutoROIForm } TAutoROIForm = class(TForm) OriginLabel: TLabel; OriginBtn: TSpeedButton; EdgeEdit: TSpinEdit; RadiusEdit: TSpinEdit; ErodeEdit: TSpinEdit; ROIconstraint: TComboBox; VarianceEdit: TSpinEdit; DiffLabel: TLabel; Label1: TLabel; Label2: TLabel; Label3: TLabel; AutoROIBtn: TSpeedButton; CancelBtn: TSpeedButton; Timer1: TTimer; Label4: TLabel; ExcludeBlackCheck: TCheckBox; procedure OriginBtnClick(Sender: TObject); procedure PreviewBtnClick(Sender: TObject); procedure FormShow(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormHide(Sender: TObject); procedure AutoROIBtnClick(Sender: TObject); procedure CancelBtnClick(Sender: TObject); procedure AutoROIchange(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } public { Public declarations } end; procedure ROICluster ({lInROIBuf: bytep;} lXdim, lYDim, lZDim,lXOriginIn,lYOrigin,lZOrigin: integer; lDeleteNotFill: boolean); var AutoROIForm: TAutoROIForm; gOriginX,gOriginY,gOriginZ: integer; implementation {$IFNDEF FPC} {$R *.DFM} {$ENDIF} procedure TAutoROIForm.OriginBtnClick(Sender: TObject); begin gOriginX := ImgForm.XViewEdit.value; gOriginY := ImgForm.YViewEdit.value; gOriginZ := ImgForm.ZViewEdit.value; OriginLabel.Caption := 'Origin: '+inttostr(gOriginX)+'x'+inttostr(gOriginY)+'x'+inttostr(gOriginZ); PreviewBtnClick(sender); end; procedure TAutoROIForm.PreviewBtnClick(Sender: TObject); var lXmm,lYmm,lZmm,lSqrRadius: single; lExcludeBlackIfZero,//lX,lY,lZ, //abba {lMaxROISz,}lEdge,lOriginPos,lROISz,lOriginIntensity,lVariance,lXdim, lYDim, lZDim: integer; lErodeCycles,lQTail,lQHead,lSliceSz,lQSz,lInc,lVolSz{,lX,lY,lZ}: integer; lROIConstrain,lReadFilteredData: boolean; lQra: LongIntP; lSourceBuffer,lBuff,lPreErodeBuff: ByteP; const kFillValue = -2; Procedure IncQra(var lVal, lQSz: integer); begin inc(lVal); if lVal >= lQSz then lVal := 1; end; function UnsmoothedIntensity(lPixel: integer): integer; //1381 begin if lReadFilteredData then result := lBuff^[lPixel] else Result :=lSourceBuffer^[lPixel]; end; function MeanIntensity(lPixel: integer): integer; var lV: integer; begin if lReadFilteredData then result := lBuff^[lPixel] else if ((lPixel-lSliceSz) > 0) and ((lPixel+lSliceSz) <= lVolSz) then begin lV :=lSourceBuffer^[lPixel]+lSourceBuffer^[lPixel+1]+lSourceBuffer^[lPixel-1] //L/R +lSourceBuffer^[lPixel+lXdim]+lSourceBuffer^[lPixel-lXdim] //Anterior/Posterior +lSourceBuffer^[lPixel+lSliceSz]+lSourceBuffer^[lPixel-lSliceSz]; //Dorsal/Ventral result := lV div 7; end else result := lSourceBuffer^[lPixel];//1401 gImageBackupBuffer[lPixel] end; procedure Check(lPixel,lIntensity: integer); var lSmoothInten :integer; begin lSmoothInten := MeanIntensity(lPixel); if (lROIConstrain) and (gBGImg.VOIUndoVol^[lPixel] > 0) then //1410 //constrain else if (lBuff^[lPixel]<> 255) and (UnsmoothedIntensity(lPixel) > lExcludeBlackIfZero {1381}) and (abs(lSmoothInten-lIntensity)<=lEdge) and(abs(lSmoothInten-lOriginIntensity)<=lVariance) {}then begin//add item incQra(lQHead,lQSz); inc(lROISz); lBuff^[lPixel] := 255; lQra^[lQHead] := lPixel; end; end; PROCEDURE RetirePixel; //FIFO cleanup function WithinRadius(lXs,lYs,lZs:integer): boolean; begin if (sqr((lXs-gOriginX)*lXmm)+sqr((lYs-gOriginY)*lYmm)+sqr((lZs-gOriginZ)*lZmm)) > lSqrRadius then result := false else result := true; end; VAR lVal,lXPos,lYPos,lZPos,lIntensity: integer; BEGIN lVal := lQra^[lQTail]; lXpos := lVal mod lXdim; if lXpos = 0 then lXPos := lXdim; lYpos := (1+((lVal-1) div lXdim)) mod lYDim; if lYPos = 0 then lYPos := lYdim; lZpos := ((lVal-1) div lSliceSz)+1; if lReadFilteredData then lIntensity := 128 else lIntensity := lSourceBuffer^[lVal];//1401 gImageBackupBuffer[lVal]; if (lXpos > 1) and WithinRadius(lXpos-1,lYpos,lZpos) then Check(lVal -1,lIntensity);//check to left if (lXPos < lXDim) and (WithinRadius(lXpos+1,lYpos,lZpos)) then Check(lVal + 1,lIntensity); //check to right if (lYpos > 1) and (WithinRadius(lXpos,lYpos-1,lZpos)) then Check(lVal -lXdim,lIntensity);//check previous line if (lYPos < lYDim) and (WithinRadius(lXpos,lYpos+1,lZpos)) then Check(lVal + lXdim,lIntensity); //check next line if (lZpos > 1) and (WithinRadius(lXpos,lYpos,lZpos-1)) then Check(lVal -lSliceSz,lIntensity);//check previous slice if (lZPos < lZDim) and (WithinRadius(lXpos,lYpos,lZpos+1)) then Check(lVal + lSliceSz,lIntensity); //check next slice incQra(lQTail,lQSz); //done with this pixel END; procedure FillStart (lPt: integer); {FIFO algorithm: keep memory VERY low} var lI: integer; begin for lI := 1 to lQsz do lQra^[lI] := 0; lQHead := 0; lQTail := 1; lROISz := 0; Check(lPt,lOriginIntensity); RetirePixel; while ((lQHead+1) <> lQTail) do begin//complete until all voxels in buffer have been tested RetirePixel; if (lQHead = lQSz) and (lQTail = 1) then exit; //break condition: avoids possible infinite loop where QTail is being incremented but QHead is stuck at maximum value end; end; function ROIOnEdge (lVal: integer): boolean; BEGIN result := false; if lBuff^[lVal] <> 255 then exit; //not ROI - is not boundary //Find if ((lVal-lSliceSz) > 0) and ((lVal+lSliceSz) <= lVolSz) then begin if lBuff^[lVal+1] = 0 then result := true; if lBuff^[lVal-1] = 0 then result := true; if lBuff^[lVal+lXdim] = 0 then result := true; if lBuff^[lVal-lXdim] = 0 then result := true; if lBuff^[lVal+lSliceSz] = 0 then result := true; if lBuff^[lVal-lSliceSz] = 0 then result := true; end; end; function ZeroOnEdge (lVal: integer): boolean; BEGIN result := false; if lBuff^[lVal] <> 0 then exit; //not ROI - is not boundary //Find if ((lVal-lSliceSz) > 0) and ((lVal+lSliceSz) <= lVolSz) then begin if lBuff^[lVal+1] = 255 then result := true; if lBuff^[lVal-1] = 255 then result := true; if lBuff^[lVal+lXdim] = 255 then result := true; if lBuff^[lVal-lXdim] = 255 then result := true; if lBuff^[lVal+lSliceSz] = 255 then result := true; if lBuff^[lVal-lSliceSz] = 255 then result := true; end; end; begin //alfa666 if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems<1) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems<>gBGImg.VOIUndoVolItems) then exit; //if gImageBackupSz <> gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems then //UpdateBackupBuffer; lXdim := gBGImg.ScrnDim[1]; lYDim := gBGImg.ScrnDim[2]; lZDim := gBGImg.ScrnDim[3]; if (gBGImg.Scrnmm[1] = 0) or (gBGImg.Scrnmm[2]=0) or (gBGImg.Scrnmm[3]=0) then begin lXmm := 1; lYmm := 1; lZmm := 1; end else begin lXmm := gBGImg.Scrnmm[1]; lYmm := gBGImg.Scrnmm[2]; lZmm := gBGImg.Scrnmm[3]; end; lSliceSz := lXdim * lYdim; lVolSz := lSliceSz*lZdim; //lMaxROISz := round(PctImg.Value/100 * lVolSz); lOriginPos := gOriginX + ((gOriginY-1)*lXdim) + ((gOriginZ-1)*lSliceSz); if (lOriginPos < 1) or (lVolSz <> gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems) or (lOriginPos > lVolSz) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems <> gBGImg.VOIUndoVolItems) then exit; {$IFNDEF FPC} lVariance := AutoROIForm.VarianceEdit.asinteger; //asinteger; lEdge := AutoROIForm.EdgeEdit.asinteger; lSqrRadius := sqr(AutoROIForm.RadiusEdit.asinteger); {$ELSE} lVariance := AutoROIForm.VarianceEdit.value; //asinteger; lEdge := AutoROIForm.EdgeEdit.value; lSqrRadius := sqr(AutoROIForm.RadiusEdit.value); {$ENDIF} if (lXDim < 4) or (lYDim < 4) or (lZDim < 4) or (lVolSz < 1) then exit; lSourceBuffer := gMRIcroOverlay[kBGOverlayNum].ScrnBuffer;//gBuffer; //Next - START count cluster size lQSz := (lVolSz div 4)+8; GetMem(lQra,lQsz * sizeof(longint) ); //check positive clusters.... Getmem(lBuff,lVolSz); FillChar(lBuff^,lVolSz, 0); //Move(gImageBackupBuffer^,lBuff^,lVolSz); if ExcludeBlackCheck.checked then //1381 lExcludeBlackIfZero := 0 //0 else lExcludeBlackIfZero := -1;//impossible 8-bit value: do not use this feature lOriginIntensity := lSourceBuffer^[lOriginPos]; //1401 gImageBackupBuffer[lOriginPos]; lReadFilteredData := false; //ROIconstrainCheck.enabled := (gROIBupSz > 1); //1410: next 3 lines ROIconstraint.enabled := (gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems > 1); //1410: next 3 lines if (ROIconstraint.ItemIndex = 2) and (ROIconstraint.enabled) then lROIConstrain := true else lROIconstrain := false; FillStart(lOriginPos); lROIConstrain := false;//1410 //START: ERODE/DILATE CYCLES {$IFNDEF FPC} lErodeCycles := AutoROIForm.ErodeEdit.asinteger; {$ELSE} lErodeCycles := AutoROIForm.ErodeEdit.value; {$ENDIF} if lErodeCycles > 0 then begin Getmem(lPreErodeBuff,lVolSz); Move(lBuff^,lPreErodeBuff^,lVolSz); for lQHead := 1 to lErodeCycles do begin//ERODE for lInc := 1 to lVolSz do if ROIonEdge(lInc) then lBuff^[lInc] :=254; for lInc := 1 to lVolSz do if lBuff^[lInc]=254 then lBuff^[lInc] := 0; //erode end;//for ErodeCycles = ERODE //SET ALL VOXELS THAT HAVE SURVIVED EROSION TO 128, WE THEN GROW THE ORIGIN for lInc := 1 to lVolSz do if lBuff^[lInc] =255 then lBuff^[lInc] := 128; //NOW - ONLY PRESERVE STUFF CONNECTED TO ORIGIN lBuff^[lOriginPos] := 128; lOriginIntensity := 128; lVariance := 2; lEdge := 2; lReadFilteredData := true; FillStart(lOriginPos); //SWITCH OFF ALL UNCONNECTED BLOBS for lInc := 1 to lVolSz do if lBuff^[lInc] =128 then lBuff^[lInc] := 0; //for lInc := 1 to lVolSz do // if lBuff[lInc] > 0 then showmessage(inttostr(lBuff[lInc]));// := 0; for lQHead := 1 to lErodeCycles do begin//DILATE for lInc := 1 to lVolSz do if (lPreErodeBuff^[lInc] = 255) and (ZeroonEdge(lInc)) then lBuff^[lInc] :=254; for lInc := 1 to lVolSz do if lBuff^[lInc]=254 then lBuff^[lInc] := 255; //erode end;//for ErodeCycles = DILATE Freemem(lPreErodeBuff); {} end; //ERODE cycles > 0 //END: ERODE/DILATE Freemem(lQra); ROIconstraint.enabled := (gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems > 1); //1410: next 3 lines if (ROIconstraint.ItemIndex = 1) and (ROIconstraint.enabled) then begin //delete ROI for lInc := 1 to gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems do //gROIBup if (lBuff^[lInc] = 255) then lBuff^[lInc] := 0 else lBuff^[lInc] := gBGImg.VOIUndoVol^[lInc]; end else (*if true {alfa (gDynSz > 1) and (gROIBupsz > 1) {and (gImageBackupSz = gDynSz){} then begin for lInc := 1 to gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems do if lBuff[lInc] = 255 then else if gImageBackupBuffer[lInc] = 255 then lBuff[lInc] := 255//255; else lBuff[lInc] := lSourceBuffer[lInc]; end else *) for lInc := 1 to lVolSz do if lBuff^[lInc] <> 255 then lBuff^[lInc] := gBGImg.VOIUndoVol^[lInc] else lBuff^[lInc] := kVOI8bit;//1401 gImageBackupBuffer[lInc]; Move(lBuff^,gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,lVolSz); Freemem(lBuff); //END check clusters ImgForm.RefreshImagesTimer.Enabled := true; end; procedure TAutoROIForm.FormShow(Sender: TObject); begin EnsureVOIOpen; CreateUndoVol; AutoROIForm.ModalResult := mrCancel; ROIconstraint.Enabled := (gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems > 1); OriginBtn.OnClick(sender); //DeleteCheck.enabled := (gROIBupSz > 1); //ROIConstrainCheck.enabled := (gROIBupSz > 1); end; procedure TAutoROIForm.FormCreate(Sender: TObject); begin {$IFNDEF FPC} ROIconstraint.SetItemIndex(0);//1410 {$ELSE} ROIconstraint.ItemIndex := (0);//1410 {$ENDIF} end; procedure TAutoROIForm.FormHide(Sender: TObject); begin // if (AutoROIForm.ModalResult = mrCancel) and (gBGImg.VOIUndoVolItems > 1) and (gBGImg.VOIUndoVolItems = gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems) then // Move(gImageBackupBuffer^,gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,gImageBackupSz); if (AutoROIForm.ModalResult = mrCancel) then UndoVolVOI; if not (AutoROIForm.ModalResult = mrCancel) then gBGImg.VOIchanged := true; //if gImageBackupSz <> 0 then Freemem(gImageBackupBuffer); //gImageBackupSz := 0; ImgForm.Fill3DBtn.Down := false; ImgForm.RefreshImagesTimer.Enabled := true; end; //Previous: create 3D ROI //Below fill bubbles in 3D ROIS //ROIcluster Follows (***********************************************************88 ************************************************************ **********************************************************) procedure ROICluster (lXdim, lYDim, lZDim,lXOriginIn,lYOrigin,lZOrigin: integer; lDeleteNotFill: boolean); var lVariability,lOrigin,lClusterInputValue,lClusterOutputValue, lClusterSz,lQTail, lXOrigin,lQHead,lSliceSz,lQSz,lInc,lVolSz: integer; lXInc,lYInc,lZInc,lSlicePos,lYPos, lMinX,lMaxX,lMinY,lMaxY,lMinZ,lMaxZ, lMinXBound,lMaxXBound,lMinYBound,lMaxYBound,lMinZBound,lMaxZBound: integer; lAtEdge: boolean; lROIBuf: bytep; lQra: LongIntP; const kFillValue = -2; Procedure IncQra(var lVal, lQSz: integer); begin inc(lVal); if lVal >= lQSz then lVal := 1; end; procedure Check(lPixel: integer); begin if (abs(lROIBuf^[lPixel] - lClusterInputValue)) <= lVariability then begin//add item incQra(lQHead,lQSz); inc(lClusterSz); lROIBuf^[lPixel] := lClusterOutputValue; lQra^[lQHead] := lPixel; end; end; PROCEDURE RetirePixel; //FIFO cleanup VAR lVal,lXPos,lYPos,lZPos: integer; BEGIN lVal := lQra^[lQTail]; lXpos := lVal mod lXdim; if lXpos = 0 then lXPos := lXdim; lYpos := (1+((lVal-1) div lXdim)) mod lYDim; if lYPos = 0 then lYPos := lYdim; lZpos := ((lVal-1) div lSliceSz)+1; if lXPos < lMinX then lMinX := lXPos; if lXPos > lMaxX then lMaxX := lXPos; if lXpos > lMinXBound then Check(lVal -1);//check to left if lXPos < lMaxXBound then Check(lVal + 1); //check to right if lYPos < lMinY then lMinY := lYPos; if lYPos > lMaxY then lMaxY := lYPos; if lYpos > lMinYBound then Check(lVal -lXdim);//check previous line if lYPos < lMaxYBound then Check(lVal + lXdim); //check next line if lZPos < lMinZ then lMinZ := lZPos; if lZPos > lMaxZ then lMaxZ := lZPos; if lZpos > lMinZBound then Check(lVal -lSliceSz);//check previous slice if lZPos < lMaxZBound then Check(lVal + lSliceSz); //check next slice incQra(lQTail,lQSz); //done with this pixel END; procedure FillStart (lPt: integer); {FIFO algorithm: keep memory VERY low} var lI: integer; begin //1414 follows for lI := 1 to lQsz do lQra^[lI] := 0; lQHead := 0; lQTail := 1; Check(lPt); RetirePixel; while ((lQHead+1) <> lQTail) do begin//complete until all voxels in buffer have been tested RetirePixel; if (lQHead = lQSz) and (lQTail = 1) then exit; //break condition: avoids possible infinite loop where QTail is being incremented but QHead is stuck at maximum value end; end; procedure SelectClusters (lInput,lOutput: integer); begin lClusterSz := 0; lClusterInputValue := lInput; lClusterOutputValue := lOutput; FillStart(lOrigin); end; function Lo (lVolumeEdge,lObjectEdge: integer): integer; begin if lVolumeEdge > lObjectEdge then result := lObjectEdge else begin lAtEdge := true; result := lVolumeEdge; end; end; function Hi (lVolumeEdge,lObjectEdge: integer): integer; begin if lVolumeEdge < lObjectEdge then result := lObjectEdge else begin lAtEdge := true; result := lVolumeEdge; end; end; begin lXOrigin := lXOriginIn; lVolSz := lXdim*lYdim*lZdim; if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems <> lVolSz then begin showmessage('You need to draw or load a VOI in order to use the 3D bubble tool.'); exit; end; CreateUndoVol; lSliceSz := lXdim * lYdim; lMinX:=lXOrigin; lMaxX:=lXOrigin; lMinY:=lYOrigin; lMaxY:=lYOrigin; lMinZ:=lZOrigin; lMaxZ:=lZOrigin; lMinXBound := 1; lMaxXBound := lXDim; lMinYBound := 1; lMaxYBound := lYDim; lMinZBound := 1; lMaxZBound := lZDim; lOrigin := lXOrigin + ((lYOrigin-1)*lXdim)+((lZOrigin-1)*lSliceSz); if (lOrigin > lVolSz) or (lXDim < 4) or (lYDim < 4) or (lZDim < 4) or (lVolSz < 1) {or (gROIBupSz <> lVolSz )} then exit; if (gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lOrigin] = 0) then begin showmessage('You must click directly on a ROI to select it. The 3D ROI bubble tool will not work unless you choose the ROI you wish to fill/delete.'); exit; end; GetMem(lROIBuf, lVolSz); for lInc := 1 to lVolSz do if gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lInc] > 0 then//ROI lROIBuf^[lInc] := 1 else lROIBuf^[lInc] := 0; //BEGIN: define selected ROI contiguous cluster lQSz := (lVolSz div 4)+8; GetMem(lQra,lQsz * sizeof(longint) ); lVariability := 0; //only convert images that are exactly 1 SelectClusters(1,255); //selected 3D ROI is 255, other ROI = 1, nonROI 0 //END: define selected roi //BEGIN: either delete selected ROI, _OR_ fill bubbles in selected ROI if lDeleteNotFill then begin for lInc := 1 to lVolSz do if lROIBuf^[lInc] = 1 then //alfa lROIBuf^[lInc] := gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lInc] //a different ROI else lROIBuf^[lInc] := 0;//gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer[lInc]; //1402 selected ROI or non-ROI end else begin //fill bubbles in selected ROI //FindROIbounds; lMinXBound := Hi(1,lMinX-1); lMaxXBound := Lo(lXDim,lMaxX+1); lMinYBound := Hi(1,lMinY-1); lMaxYBound := Lo(lYDim,lMaxY+1); lMinZBound := Hi(1,lMinZ-1); lMaxZBound := Lo(lZDim,lMaxZ+1); lOrigin := (lMinXBound) + ((lMinYBound-1)*lXdim)+((lMinZBound-1)*lSliceSz); lVariability := 2;//convert voxels that are either 0 or 1 to 1 SelectClusters(1,128); //now bubbles trapped in volume are set to zero //we next need to distinguish bubbles from unmarked voxels outside the searched object boundary for lZInc := lMinZBound to lMaxZBound do begin lSlicePos := (lZInc-1) * lSliceSz; for lYInc := lMinYBound to lMaxYBound do begin lYPos := (lYInc-1) * lXDim; for lXInc := lMinXBound to lMaxXBound do begin lInc := lXInc + lYPos + lSlicePos; if lROIBuf^[lInc] = 0 then lROIBuf^[lInc] := 33; end; //for X end; //for Y end; //for Z for lInc := 1 to lVolSz do if lROIBuf^[lInc] = 33 then lROIBuf^[lInc] := kVOI8bit //bubble in selected ROI else lROIBuf^[lInc] := gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lInc]; end; Freemem(lQra); //BEGIN: CREATE 3D UNDO BUFFER (*if (gDynSz > 1) and (gDynSz = gImageBackupSz) then begin if (gUndoBufSz > 0) then freemem(gUndoBuffer); gUndoBufSz := gDynSz; getmem(gUndoBuffer,gDynSz); Move(gImageBackupBuffer^,gUndoBuffer^,gImageBackupSz); gSaveUndoBuf := true; end; (**) //END: CREATE 3D UNDO BUFFER //BEGIN: mopping up: prepare data for viewing, report ROI change Move(lROIBuf^,gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,lVolSz); Freemem(lROIBuf); {} gBGImg.VOIchanged := true; //END: mopping up ImgForm.RefreshImagesTimer.enabled := true; end; (**) procedure TAutoROIForm.AutoROIBtnClick(Sender: TObject); begin AutoROIForm.ModalResult := mrOK; AutoROIForm.close; end; procedure TAutoROIForm.CancelBtnClick(Sender: TObject); begin AutoROIForm.close; end; procedure TAutoROIForm.AutoROIchange(Sender: TObject); begin if not AutoROIForm.visible then exit; Timer1.Enabled := true; end; procedure TAutoROIForm.Timer1Timer(Sender: TObject); begin Timer1.Enabled := false; PreviewBtnClick(sender); end; procedure TAutoROIForm.FormDestroy(Sender: TObject); begin //if gImageBackupSz <> 0 then Freemem(gImageBackupBuffer); //gImageBackupSz := 0; end; {$IFDEF FPC} initialization {$I autoroi.lrs} {$ENDIF} end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_macscriptintel104.bat���������������������������������������������0000755�0001750�0001750�00000001226�11311675512�020303� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������chmod 777 ./_xclean.bat ./_xclean.bat cp ./common/notgui.inc ./common/isgui.inc lazbuild ./dcm2nii/dcm2nii.lpr="-va -k-macosx_version_min -k10.4 -XR/Developer/SDKs/MacOSX10.4u.sdk/" cp ./dcm2nii/dcm2nii ../distro/intel/dcm2nii ./_xclean.bat cp ./common/gui.inc ./common/isgui.inc lazbuild ./mricron.lpr="-va -k-macosx_version_min -k10.4 -XR/Developer/SDKs/MacOSX10.4u.sdk/" --ws=carbon lazbuild ./npm/npm.lpr="-va -k-macosx_version_min -k10.4 -XR/Developer/SDKs/MacOSX10.4u.sdk/" --ws=carbon lazbuild ./dcm2nii/dcm2niigui.lpr --ws=carbon cp ./mricron ../distro/intel/mricron cp ./npm/npm ../distro/intel/npm cp ./dcm2nii/dcm2niigui ../distro/intel/dcm2niigui ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_clean.bat���������������������������������������������������������0000755�0001750�0001750�00000000333�12147207714�016120� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������del /S *.a del /S *.o del /S *.ppu del /S *.bak del /S *.~* del /S *.dcu del /S *.dsk del /S *.obj del /S *.hpp del /S *.ddp del /S *.mps del /S *.mpt del /S *.exe del /S *.old rmdir /S /Q mricron.app �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/mni.lrs������������������������������������������������������������0000755�0001750�0001750�00000002317�11551145664�015523� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TMNIForm','FORMDATA',[ 'TPF0'#8'TMNIForm'#7'MNIForm'#4'Left'#3#188#1#6'Height'#2' '#3'Top'#3','#1#5 +'Width'#3#8#1#18'HorzScrollBar.Page'#3#7#1#18'VertScrollBar.Page'#2'5'#13'Ac' +'tiveControl'#7#5'XEdit'#11'BorderIcons'#11#12'biSystemMenu'#0#11'BorderStyl' +'e'#7#8'bsDialog'#7'Caption'#6#12'MNI position'#12'ClientHeight'#2' '#11'Cli' +'entWidth'#3#8#1#21'Constraints.MaxHeight'#2' '#20'Constraints.MaxWidth'#3#8 +#1#21'Constraints.MinHeight'#2' '#20'Constraints.MinWidth'#3#8#1#8'OnCreate' +#7#10'FormCreate'#8'Position'#7#14'poScreenCenter'#10'LCLVersion'#6#6'0.9.29' +#0#9'TSpinEdit'#5'XEdit'#4'Left'#2#16#6'Height'#2#21#3'Top'#2#4#5'Width'#2'B' +#8'MaxValue'#3#200#0#8'MinValue'#3'8'#255#8'OnChange'#7#11'XEditChange'#8'Ta' +'bOrder'#2#0#0#0#9'TSpinEdit'#5'YEdit'#4'Left'#2'`'#6'Height'#2#21#3'Top'#2#4 +#5'Width'#2'B'#8'MaxValue'#3#200#0#8'MinValue'#3'8'#255#8'OnChange'#7#11'XEd' +'itChange'#8'TabOrder'#2#1#0#0#9'TSpinEdit'#5'ZEdit'#4'Left'#3#176#0#6'Heigh' +'t'#2#21#3'Top'#2#4#5'Width'#2'B'#8'MaxValue'#3#200#0#8'MinValue'#3'8'#255#8 +'OnChange'#7#11'XEditChange'#8'TabOrder'#2#2#0#0#0 ]); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/gzio20.pas���������������������������������������������������������0000755�0001750�0001750�00000114270�11326425446�016036� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Unit gzio2; { Pascal unit based on gzio.c -- IO on .gz files Copyright (C) 1995-1998 Jean-loup Gailly. Define NO_DEFLATE to compile this file without the compression code Pascal tranlastion based on code contributed by Francisco Javier Crespo Copyright (C) 1998 by Jacques Nomssi Nzali For conditions of distribution and use, see copyright notice in readme.txt } interface {$I zconf.inc} uses {$ifdef MSDOS} dos, strings, {$else} SysUtils, {$endif} zutil, zbase, gzcrc, zdeflate, zinflate, define_types,dialogs; type gzFile = voidp; type z_off_t = long; procedure GZipBuffer(var FGzipFilename,FFileDestination: String;lxInBuffer: byteP;lInSize: Integer; lOverwritewarn: boolean); procedure UnGZip (var lInFname: string; var lBuf: ByteP; lOffset,lMaxSz: integer); //unzip procedure UnGZipCore (var infile : gzFile; var lBuf: ByteP; lReadBytes: integer; lWrite: boolean); function gzopen (path:ansistring; mode:string) : gzFile; function gzsetparams (f:gzfile; level:int; strategy:int) : int; function gzread (f:gzFile; buf:voidp; len:uInt) : int; function gzgetc (f:gzfile) : int; function gzgets (f:gzfile; buf:PChar; len:int) : PChar; {$ifndef NO_DEFLATE} function gzwrite (f:gzFile; buf:voidp; len:uInt) : int; function gzputc (f:gzfile; c:char) : int; function gzputs (f:gzfile; s:PChar) : int; function gzflush (f:gzFile; flush:int) : int; {$ifdef GZ_FORMAT_STRING} function gzprintf (zfile : gzFile; const format : string; a : array of int); { doesn't compile } {$endif} {$endif} function gzseek (f:gzfile; offset:z_off_t; whence:int) : z_off_t; function gzrewind (f:gzFile) : int; function gztell (f:gzfile) : z_off_t; function gzeof (f:gzfile) : boolean; function gzclose (f:gzFile) : int; function gzerror (f:gzFile; var errnum:Int) : string; const SEEK_SET {: z_off_t} = 0; { seek from beginning of file } SEEK_CUR {: z_off_t} = 1; { seek from current position } SEEK_END {: z_off_t} = 2; implementation const Z_EOF = -1; { same value as in STDIO.H } Z_BUFSIZE = 16384; { Z_PRINTF_BUFSIZE = 4096; } gz_magic : array[0..1] of byte = ($1F, $8B); { gzip magic header } { gzip flag byte } ASCII_FLAG = $01; { bit 0 set: file probably ascii text } HEAD_CRC = $02; { bit 1 set: header CRC present } EXTRA_FIELD = $04; { bit 2 set: extra field present } ORIG_NAME = $08; { bit 3 set: original file name present } COMMENT = $10; { bit 4 set: file comment present } RESERVED = $E0; { bits 5..7: reserved } type gz_stream = record stream : z_stream; z_err : int; { error code for last stream operation } z_eof : boolean; { set if end of input file } gzfile : file; { .gz file } inbuf : pBytef; { input buffer } outbuf : pBytef; { output buffer } crc : uLong; { crc32 of uncompressed data } msg, { error message - limit 79 chars } path : string[79];//: ansistring; { path name for debugging only - limit 79 chars } transparent : boolean; { true if input file is not a .gz file } mode : char; { 'w' or 'r' } startpos : long; { start of compressed data in file (header skipped) } end; type gz_streamp = ^gz_stream; function destroy (var s:gz_streamp) : int; forward; procedure check_header(s:gz_streamp); forward; { GZOPEN ==================================================================== Opens a gzip (.gz) file for reading or writing. As Pascal does not use file descriptors, the code has been changed to accept only path names. The mode parameter defaults to BINARY read or write operations ('r' or 'w') but can also include a compression level ('w9') or a strategy: Z_FILTERED as in 'w6f' or Z_HUFFMAN_ONLY as in 'w1h'. (See the description of deflateInit2 for more information about the strategy parameter.) gzopen can be used to open a file which is not in gzip format; in this case, gzread will directly read from the file without decompression. gzopen returns NIL if the file could not be opened (non-zero IOResult) or if there was insufficient memory to allocate the (de)compression state (zlib error is Z_MEM_ERROR). ============================================================================} function gzopen (path:ansistring; mode:string) : gzFile; var i : uInt; err : int; level : int; { compression level } strategy : int; { compression strategy } s : gz_streamp; {$IFDEF MSDOS} attr : word; { file attributes } {$ENDIF} {$IFNDEF NO_DEFLATE} gzheader : array [0..9] of byte; {$ENDIF} begin if (path='') or (mode='') then begin gzopen := Z_NULL; exit; end; GetMem (s,sizeof(gz_stream)); if not Assigned (s) then begin gzopen := Z_NULL; exit; end; level := Z_DEFAULT_COMPRESSION; strategy := Z_DEFAULT_STRATEGY; s^.stream.zalloc := NIL; { (alloc_func)0 } s^.stream.zfree := NIL; { (free_func)0 } s^.stream.opaque := NIL; { (voidpf)0 } s^.stream.next_in := Z_NULL; s^.stream.next_out := Z_NULL; s^.stream.avail_in := 0; s^.stream.avail_out := 0; s^.z_err := Z_OK; s^.z_eof := false; s^.inbuf := Z_NULL; s^.outbuf := Z_NULL; s^.crc := crc32(0, Z_NULL, 0); s^.msg := ''; s^.transparent := false; s^.path := path; { limit to 255 chars } s^.mode := chr(0); for i:=1 to Length(mode) do begin case mode[i] of 'r' : s^.mode := 'r'; 'w' : s^.mode := 'w'; '0'..'9' : level := Ord(mode[i])-Ord('0'); 'f' : strategy := Z_FILTERED; 'h' : strategy := Z_HUFFMAN_ONLY; end; end; if (s^.mode=chr(0)) then begin destroy(s); gzopen := gzFile(Z_NULL); exit; end; if (s^.mode='w') then begin {$IFDEF NO_DEFLATE} err := Z_STREAM_ERROR; {$ELSE} err := deflateInit2 (s^.stream, level, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); { windowBits is passed < 0 to suppress zlib header } GetMem (s^.outbuf, Z_BUFSIZE); s^.stream.next_out := s^.outbuf; {$ENDIF} if (err <> Z_OK) or (s^.outbuf = Z_NULL) then begin destroy(s); gzopen := gzFile(Z_NULL); exit; end; end else begin GetMem (s^.inbuf, Z_BUFSIZE); s^.stream.next_in := s^.inbuf; err := inflateInit2_ (s^.stream, -MAX_WBITS, ZLIB_VERSION, sizeof(z_stream)); { windowBits is passed < 0 to tell that there is no zlib header } if (err <> Z_OK) or (s^.inbuf = Z_NULL) then begin destroy(s); gzopen := gzFile(Z_NULL); exit; end; end; s^.stream.avail_out := Z_BUFSIZE; {$IFOPT I+} {$I-} {$define IOcheck} {$ENDIF} Assign (s^.gzfile, s^.path); {$ifdef MSDOS} GetFAttr(s^.gzfile, Attr); if (DosError <> 0) and (s^.mode='w') then ReWrite (s^.gzfile,1) else Reset (s^.gzfile,1); {$else} if (not FileExists(s^.path)) and (s^.mode='w') then ReWrite (s^.gzfile,1) else Reset (s^.gzfile,1); {$endif} {$IFDEF IOCheck} {$I+} {$ENDIF} if (IOResult <> 0) then begin destroy(s); gzopen := gzFile(Z_NULL); exit; end; if (s^.mode = 'w') then begin { Write a very simple .gz header } {$IFNDEF NO_DEFLATE} gzheader [0] := gz_magic [0]; gzheader [1] := gz_magic [1]; gzheader [2] := Z_DEFLATED; { method } gzheader [3] := 0; { flags } gzheader [4] := 0; { time[0] } gzheader [5] := 0; { time[1] } gzheader [6] := 0; { time[2] } gzheader [7] := 0; { time[3] } gzheader [8] := 0; { xflags } gzheader [9] := 0; { OS code = MS-DOS } blockwrite (s^.gzfile, gzheader, 10); s^.startpos := LONG(10); {$ENDIF} end else begin check_header(s); { skip the .gz header } s^.startpos := FilePos(s^.gzfile) - s^.stream.avail_in; end; gzopen := gzFile(s); end; { GZSETPARAMS =============================================================== Update the compression level and strategy. ============================================================================} function gzsetparams (f:gzfile; level:int; strategy:int) : int; var s : gz_streamp; written: integer; begin s := gz_streamp(f); if (s = NIL) or (s^.mode <> 'w') then begin gzsetparams := Z_STREAM_ERROR; exit; end; { Make room to allow flushing } if (s^.stream.avail_out = 0) then begin s^.stream.next_out := s^.outbuf; blockwrite(s^.gzfile, s^.outbuf^, Z_BUFSIZE, written); if (written <> Z_BUFSIZE) then s^.z_err := Z_ERRNO; s^.stream.avail_out := Z_BUFSIZE; end; gzsetparams := deflateParams (s^.stream, level, strategy); end; { GET_BYTE ================================================================== Read a byte from a gz_stream. Updates next_in and avail_in. Returns EOF for end of file. IN assertion: the stream s has been sucessfully opened for reading. ============================================================================} function get_byte (s:gz_streamp) : int; begin if (s^.z_eof = true) then begin get_byte := Z_EOF; exit; end; if (s^.stream.avail_in = 0) then begin {$I-} blockread (s^.gzfile, s^.inbuf^, Z_BUFSIZE, Int(s^.stream.avail_in)); {$I+} if (s^.stream.avail_in = 0) then begin s^.z_eof := true; if (IOResult <> 0) then s^.z_err := Z_ERRNO; get_byte := Z_EOF; exit; end; s^.stream.next_in := s^.inbuf; end; Dec(s^.stream.avail_in); get_byte := s^.stream.next_in^; Inc(s^.stream.next_in); end; { GETLONG =================================================================== Reads a Longint in LSB order from the given gz_stream. ============================================================================} { function getLong (s:gz_streamp) : uLong; var x : array [0..3] of byte; i : byte; c : int; n1 : longint; n2 : longint; begin for i:=0 to 3 do begin c := get_byte(s); if (c = Z_EOF) then s^.z_err := Z_DATA_ERROR; x[i] := (c and $FF) end; n1 := (ush(x[3] shl 8)) or x[2]; n2 := (ush(x[1] shl 8)) or x[0]; getlong := (n1 shl 16) or n2; end; } function getLong(s : gz_streamp) : uLong; var x : packed array [0..3] of byte; c : int; begin { x := uLong(get_byte(s)); - you can't do this with TP, no unsigned long } { the following assumes a little endian machine and TP } x[0] := Byte(get_byte(s)); x[1] := Byte(get_byte(s)); x[2] := Byte(get_byte(s)); c := get_byte(s); x[3] := Byte(c); if (c = Z_EOF) then s^.z_err := Z_DATA_ERROR; GetLong := uLong(longint(x)); end; { CHECK_HEADER ============================================================== Check the gzip header of a gz_stream opened for reading. Set the stream mode to transparent if the gzip magic header is not present. Set s^.err to Z_DATA_ERROR if the magic header is present but the rest of the header is incorrect. IN assertion: the stream s has already been created sucessfully; s^.stream.avail_in is zero for the first time, but may be non-zero for concatenated .gz files ============================================================================} procedure check_header (s:gz_streamp); var method : int; { method byte } flags : int; { flags byte } len : uInt; c : int; begin { Check the gzip magic header } for len := 0 to 1 do begin c := get_byte(s); if (c <> gz_magic[len]) then begin if (len <> 0) then begin Inc(s^.stream.avail_in); Dec(s^.stream.next_in); end; if (c <> Z_EOF) then begin Inc(s^.stream.avail_in); Dec(s^.stream.next_in); s^.transparent := TRUE; end; if (s^.stream.avail_in <> 0) then s^.z_err := Z_OK else s^.z_err := Z_STREAM_END; exit; end; end; method := get_byte(s); flags := get_byte(s); if (method <> Z_DEFLATED) or ((flags and RESERVED) <> 0) then begin s^.z_err := Z_DATA_ERROR; exit; end; for len := 0 to 5 do get_byte(s); { Discard time, xflags and OS code } if ((flags and EXTRA_FIELD) <> 0) then begin { skip the extra field } len := uInt(get_byte(s)); len := len + (uInt(get_byte(s)) shr 8); { len is garbage if EOF but the loop below will quit anyway } while (len <> 0) and (get_byte(s) <> Z_EOF) do Dec(len); end; if ((flags and ORIG_NAME) <> 0) then begin { skip the original file name } repeat c := get_byte(s); until (c = 0) or (c = Z_EOF); end; if ((flags and COMMENT) <> 0) then begin { skip the .gz file comment } repeat c := get_byte(s); until (c = 0) or (c = Z_EOF); end; if ((flags and HEAD_CRC) <> 0) then begin { skip the header crc } get_byte(s); get_byte(s); end; if (s^.z_eof = true) then s^.z_err := Z_DATA_ERROR else s^.z_err := Z_OK; end; { DESTROY =================================================================== Cleanup then free the given gz_stream. Return a zlib error code. Try freeing in the reverse order of allocations. ============================================================================} function destroy (var s:gz_streamp) : int; begin destroy := Z_OK; if not Assigned (s) then begin destroy := Z_STREAM_ERROR; exit; end; if (s^.stream.state <> NIL) then begin if (s^.mode = 'w') then begin {$IFDEF NO_DEFLATE} destroy := Z_STREAM_ERROR; {$ELSE} destroy := deflateEnd(s^.stream); {$ENDIF} end else if (s^.mode = 'r') then begin destroy := inflateEnd(s^.stream); end; end; if (s^.path <> '') then begin {$I-} close(s^.gzfile); {$I+} if (IOResult <> 0) then destroy := Z_ERRNO; end; if (s^.z_err < 0) then destroy := s^.z_err; if Assigned (s^.inbuf) then FreeMem(s^.inbuf, Z_BUFSIZE); if Assigned (s^.outbuf) then FreeMem(s^.outbuf, Z_BUFSIZE); FreeMem(s, sizeof(gz_stream)); end; { GZREAD ==================================================================== Reads the given number of uncompressed bytes from the compressed file. If the input file was not in gzip format, gzread copies the given number of bytes into the buffer. gzread returns the number of uncompressed bytes actually read (0 for end of file, -1 for error). ============================================================================} function gzread (f:gzFile; buf:voidp; len:uInt) : int; var s : gz_streamp; start : pBytef; next_out : pBytef; n : uInt; crclen : uInt; { Buffer length to update CRC32 } filecrc : uLong; { CRC32 stored in GZIP'ed file } filelen : uLong; { Total lenght of uncompressed file } bytes : integer; { bytes actually read in I/O blockread } total_in : uLong; total_out : uLong; begin s := gz_streamp(f); start := pBytef(buf); { starting point for crc computation } if (s = NIL) or (s^.mode <> 'r') then begin gzread := Z_STREAM_ERROR; exit; end; if (s^.z_err = Z_DATA_ERROR) or (s^.z_err = Z_ERRNO) then begin gzread := -1; exit; end; if (s^.z_err = Z_STREAM_END) then begin gzread := 0; { EOF } exit; end; s^.stream.next_out := pBytef(buf); s^.stream.avail_out := len; while (s^.stream.avail_out <> 0) do begin if (s^.transparent = true) then begin { Copy first the lookahead bytes: } n := s^.stream.avail_in; if (n > s^.stream.avail_out) then n := s^.stream.avail_out; if (n > 0) then begin zmemcpy(s^.stream.next_out, s^.stream.next_in, n); inc (s^.stream.next_out, n); inc (s^.stream.next_in, n); dec (s^.stream.avail_out, n); dec (s^.stream.avail_in, n); end; if (s^.stream.avail_out > 0) then begin blockread (s^.gzfile, s^.stream.next_out^, s^.stream.avail_out, bytes); dec (s^.stream.avail_out, uInt(bytes)); end; dec (len, s^.stream.avail_out); inc (s^.stream.total_in, uLong(len)); inc (s^.stream.total_out, uLong(len)); gzread := int(len); exit; end; { IF transparent } if (s^.stream.avail_in = 0) and (s^.z_eof = false) then begin {$I-} blockread (s^.gzfile, s^.inbuf^, Z_BUFSIZE, Int(s^.stream.avail_in)); {$I+} if (s^.stream.avail_in = 0) then begin s^.z_eof := true; if (IOResult <> 0) then begin s^.z_err := Z_ERRNO; break; end; end; s^.stream.next_in := s^.inbuf; end; s^.z_err := inflate(s^.stream, Z_NO_FLUSH); if (s^.z_err = Z_STREAM_END) then begin crclen := 0; next_out := s^.stream.next_out; while (next_out <> start ) do begin dec (next_out); inc (crclen); { Hack because Pascal cannot substract pointers } end; { Check CRC and original size } s^.crc := crc32(s^.crc, start, crclen); start := s^.stream.next_out; filecrc := getLong (s); filelen := getLong (s); if (s^.crc <> filecrc) or (s^.stream.total_out <> filelen) then s^.z_err := Z_DATA_ERROR else begin { Check for concatenated .gz files: } check_header(s); if (s^.z_err = Z_OK) then begin total_in := s^.stream.total_in; total_out := s^.stream.total_out; inflateReset (s^.stream); s^.stream.total_in := total_in; s^.stream.total_out := total_out; s^.crc := crc32 (0, Z_NULL, 0); end; end; {IF-THEN-ELSE} end; if (s^.z_err <> Z_OK) or (s^.z_eof = true) then break; end; {WHILE} crclen := 0; next_out := s^.stream.next_out; while (next_out <> start ) do begin dec (next_out); inc (crclen); { Hack because Pascal cannot substract pointers } end; s^.crc := crc32 (s^.crc, start, crclen); gzread := int(len - s^.stream.avail_out); end; { GZGETC ==================================================================== Reads one byte from the compressed file. gzgetc returns this byte or -1 in case of end of file or error. ============================================================================} function gzgetc (f:gzfile) : int; var c:byte; begin if (gzread (f,@c,1) = 1) then gzgetc := c else gzgetc := -1; end; { GZGETS ==================================================================== Reads bytes from the compressed file until len-1 characters are read, or a newline character is read and transferred to buf, or an end-of-file condition is encountered. The string is then Null-terminated. gzgets returns buf, or Z_NULL in case of error. The current implementation is not optimized at all. ============================================================================} function gzgets (f:gzfile; buf:PChar; len:int) : PChar; var b : PChar; { start of buffer } bytes : Int; { number of bytes read by gzread } gzchar : char; { char read by gzread } begin if (buf = Z_NULL) or (len <= 0) then begin gzgets := Z_NULL; exit; end; b := buf; repeat dec (len); bytes := gzread (f, buf, 1); gzchar := buf^; inc (buf); until (len = 0) or (bytes <> 1) or (gzchar = Chr(13)); buf^ := Chr(0); if (b = buf) and (len > 0) then gzgets := Z_NULL else gzgets := b; end; {$IFNDEF NO_DEFLATE} { GZWRITE =================================================================== Writes the given number of uncompressed bytes into the compressed file. gzwrite returns the number of uncompressed bytes actually written (0 in case of error). ============================================================================} function gzwrite (f:gzfile; buf:voidp; len:uInt) : int; var s : gz_streamp; written : integer; begin s := gz_streamp(f); if (s = NIL) or (s^.mode <> 'w') then begin gzwrite := Z_STREAM_ERROR; exit; end; s^.stream.next_in := pBytef(buf); s^.stream.avail_in := len; while (s^.stream.avail_in <> 0) do begin if (s^.stream.avail_out = 0) then begin s^.stream.next_out := s^.outbuf; blockwrite (s^.gzfile, s^.outbuf^, Z_BUFSIZE, written); if (written <> Z_BUFSIZE) then begin s^.z_err := Z_ERRNO; break; end; s^.stream.avail_out := Z_BUFSIZE; end; s^.z_err := deflate(s^.stream, Z_NO_FLUSH); if (s^.z_err <> Z_OK) then break; end; {WHILE} s^.crc := crc32(s^.crc, buf, len); gzwrite := int(len - s^.stream.avail_in); end; { =========================================================================== Converts, formats, and writes the args to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of uncompressed bytes actually written (0 in case of error). } {$IFDEF GZ_FORMAT_STRING} function gzprintf (zfile : gzFile; const format : string; a : array of int) : int; var buf : array[0..Z_PRINTF_BUFSIZE-1] of char; len : int; begin {$ifdef HAS_snprintf} snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); {$else} sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); {$endif} len := strlen(buf); { old sprintf doesn't return the nb of bytes written } if (len <= 0) return 0; gzprintf := gzwrite(file, buf, len); end; {$ENDIF} { GZPUTC ==================================================================== Writes c, converted to an unsigned char, into the compressed file. gzputc returns the value that was written, or -1 in case of error. ============================================================================} function gzputc (f:gzfile; c:char) : int; begin if (gzwrite (f,@c,1) = 1) then {$IFDEF FPC} gzputc := int(ord(c)) {$ELSE} gzputc := int(c) {$ENDIF} else gzputc := -1; end; { GZPUTS ==================================================================== Writes the given null-terminated string to the compressed file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. ============================================================================} function gzputs (f:gzfile; s:PChar) : int; begin gzputs := gzwrite (f, voidp(s), strlen(s)); end; { DO_FLUSH ================================================================== Flushes all pending output into the compressed file. The parameter flush is as in the zdeflate() function. ============================================================================} function do_flush (f:gzfile; flush:int) : int; var len : uInt; done : boolean; s : gz_streamp; written : integer; begin done := false; s := gz_streamp(f); if (s = NIL) or (s^.mode <> 'w') then begin do_flush := Z_STREAM_ERROR; exit; end; s^.stream.avail_in := 0; { should be zero already anyway } while true do begin len := Z_BUFSIZE - s^.stream.avail_out; if (len <> 0) then begin {$I-} blockwrite(s^.gzfile, s^.outbuf^, len, written); {$I+} if (written <> len) then begin s^.z_err := Z_ERRNO; do_flush := Z_ERRNO; exit; end; s^.stream.next_out := s^.outbuf; s^.stream.avail_out := Z_BUFSIZE; end; if (done = true) then break; s^.z_err := deflate(s^.stream, flush); { Ignore the second of two consecutive flushes: } if (len = 0) and (s^.z_err = Z_BUF_ERROR) then s^.z_err := Z_OK; { deflate has finished flushing only when it hasn't used up all the available space in the output buffer: } done := (s^.stream.avail_out <> 0) or (s^.z_err = Z_STREAM_END); if (s^.z_err <> Z_OK) and (s^.z_err <> Z_STREAM_END) then break; end; {WHILE} if (s^.z_err = Z_STREAM_END) then do_flush:=Z_OK else do_flush:=s^.z_err; end; { GZFLUSH =================================================================== Flushes all pending output into the compressed file. The parameter flush is as in the zdeflate() function. The return value is the zlib error number (see function gzerror below). gzflush returns Z_OK if the flush parameter is Z_FINISH and all output could be flushed. gzflush should be called only when strictly necessary because it can degrade compression. ============================================================================} function gzflush (f:gzfile; flush:int) : int; var err : int; s : gz_streamp; begin s := gz_streamp(f); err := do_flush (f, flush); if (err <> 0) then begin gzflush := err; exit; end; if (s^.z_err = Z_STREAM_END) then gzflush := Z_OK else gzflush := s^.z_err; end; {$ENDIF} (* NO DEFLATE *) { GZREWIND ================================================================== Rewinds input file. ============================================================================} function gzrewind (f:gzFile) : int; var s:gz_streamp; begin s := gz_streamp(f); if (s = NIL) or (s^.mode <> 'r') then begin gzrewind := -1; exit; end; s^.z_err := Z_OK; s^.z_eof := false; s^.stream.avail_in := 0; s^.stream.next_in := s^.inbuf; if (s^.startpos = 0) then begin { not a compressed file } {$I-} seek (s^.gzfile, 0); {$I+} gzrewind := 0; exit; end; inflateReset(s^.stream); {$I-} seek (s^.gzfile, s^.startpos); {$I+} gzrewind := int(IOResult); exit; end; { GZSEEK ==================================================================== Sets the starting position for the next gzread or gzwrite on the given compressed file. The offset represents a number of bytes from the beginning of the uncompressed stream. gzseek returns the resulting offset, or -1 in case of error. SEEK_END is not implemented, returns error. In this version of the library, gzseek can be extremely slow. ============================================================================} function gzseek (f:gzfile; offset:z_off_t; whence:int) : z_off_t; var s : gz_streamp; size : uInt; begin s := gz_streamp(f); if (s = NIL) or (whence = SEEK_END) or (s^.z_err = Z_ERRNO) or (s^.z_err = Z_DATA_ERROR) then begin gzseek := z_off_t(-1); exit; end; if (s^.mode = 'w') then begin {$IFDEF NO_DEFLATE} gzseek := z_off_t(-1); exit; {$ELSE} if (whence = SEEK_SET) then dec(offset, s^.stream.total_out); if (offset < 0) then begin; gzseek := z_off_t(-1); exit; end; { At this point, offset is the number of zero bytes to write. } if (s^.inbuf = Z_NULL) then begin GetMem (s^.inbuf, Z_BUFSIZE); zmemzero(s^.inbuf, Z_BUFSIZE); end; while (offset > 0) do begin size := Z_BUFSIZE; if (offset < Z_BUFSIZE) then size := uInt(offset); size := gzwrite(f, s^.inbuf, size); if (size = 0) then begin gzseek := z_off_t(-1); exit; end; dec (offset,size); end; gzseek := z_off_t(s^.stream.total_in); exit; {$ENDIF} end; { Rest of function is for reading only } { compute absolute position } if (whence = SEEK_CUR) then inc (offset, s^.stream.total_out); if (offset < 0) then begin gzseek := z_off_t(-1); exit; end; if (s^.transparent = true) then begin s^.stream.avail_in := 0; s^.stream.next_in := s^.inbuf; {$I-} seek (s^.gzfile, offset); {$I+} if (IOResult <> 0) then begin gzseek := z_off_t(-1); exit; end; s^.stream.total_in := uLong(offset); s^.stream.total_out := uLong(offset); gzseek := z_off_t(offset); exit; end; { For a negative seek, rewind and use positive seek } if (uLong(offset) >= s^.stream.total_out) then dec (offset, s^.stream.total_out) else if (gzrewind(f) <> 0) then begin gzseek := z_off_t(-1); exit; end; { offset is now the number of bytes to skip. } if (offset <> 0) and (s^.outbuf = Z_NULL) then GetMem (s^.outbuf, Z_BUFSIZE); while (offset > 0) do begin size := Z_BUFSIZE; if (offset < Z_BUFSIZE) then size := int(offset); size := gzread (f, s^.outbuf, size); if (size <= 0) then begin gzseek := z_off_t(-1); exit; end; dec(offset, size); end; gzseek := z_off_t(s^.stream.total_out); end; { GZTELL ==================================================================== Returns the starting position for the next gzread or gzwrite on the given compressed file. This position represents a number of bytes in the uncompressed data stream. ============================================================================} function gztell (f:gzfile) : z_off_t; begin gztell := gzseek (f, 0, SEEK_CUR); end; { GZEOF ===================================================================== Returns TRUE when EOF has previously been detected reading the given input stream, otherwise FALSE. ============================================================================} function gzeof (f:gzfile) : boolean; var s:gz_streamp; begin s := gz_streamp(f); if (s=NIL) or (s^.mode<>'r') then gzeof := false else gzeof := s^.z_eof; end; { PUTLONG =================================================================== Outputs a Longint in LSB order to the given file ============================================================================} procedure putLong (var f:file; x:uLong); var n : int; c : byte; begin for n:=0 to 3 do begin c := x and $FF; blockwrite (f, c, 1); x := x shr 8; end; end; { GZCLOSE =================================================================== Flushes all pending output if necessary, closes the compressed file and deallocates all the (de)compression state. The return value is the zlib error number (see function gzerror below). ============================================================================} function gzclose (f:gzFile) : int; var err : int; s : gz_streamp; begin s := gz_streamp(f); if (s = NIL) then begin gzclose := Z_STREAM_ERROR; exit; end; if (s^.mode = 'w') then begin {$IFDEF NO_DEFLATE} gzclose := Z_STREAM_ERROR; exit; {$ELSE} err := do_flush (f, Z_FINISH); if (err <> Z_OK) then begin gzclose := destroy (gz_streamp(f)); exit; end; putLong (s^.gzfile, s^.crc); putLong (s^.gzfile, s^.stream.total_in); {$ENDIF} end; gzclose := destroy (gz_streamp(f)); end; { GZERROR =================================================================== Returns the error message for the last error which occured on the given compressed file. errnum is set to zlib error number. If an error occured in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. ============================================================================} function gzerror (f:gzfile; var errnum:int) : string; var m : string; s : gz_streamp; begin s := gz_streamp(f); if (s = NIL) then begin errnum := Z_STREAM_ERROR; gzerror := zError(Z_STREAM_ERROR); end; errnum := s^.z_err; if (errnum = Z_OK) then begin gzerror := zError(Z_OK); exit; end; m := s^.stream.msg; if (errnum = Z_ERRNO) then m := ''; if (m = '') then m := zError(s^.z_err); s^.msg := s^.path+': '+m; gzerror := s^.msg; end; procedure UnGZip (var lInFname: string; var lBuf: ByteP; lOffset,lMaxSz: integer); //unzip const BUFLEN = 16384; var infile : gzFile; lFname : ansistring; lbufsz,len,lI : integer; written : integer; buf : packed array [0..BUFLEN-1] of byte; { Global uses BSS instead of stack } begin lFName := lInFName; //filemode := 1; //if lFName = 'z' then //showmessage('unzip'); //ImgForm.Caption := 'gz'; //ReadIntForm.GetInt('Multi-volume file, please select volume to view.',1,1,3); //infile := gzopenZ (lFName, 'r', 0); infile := gzopen (lFName, 'r'); written := 0; if lOffset > 0 then begin Len := lOffset div BUFLEN; if Len > 0 then for lI := 1 to Len do gzread (infile, @buf, BUFLEN {1388}); Len := lOffset mod BUFLEN; gzread (infile, @buf, Len); end; lbufsz := BUFLEN; if lMaxSz < BUFLEN then lbufsz := lMaxSz; while true do begin len := gzread (infile, @buf, lbufsz); if (len < 0) then begin break end; if (len = 0) then break; if (Written+len) > lMaxSz then begin break; end; Move(buf,lbuf^[Written+1],len); Written := Written + len; end; {WHILE} gzclose (infile); //filemode := 2; end; procedure UnGZipCore (var infile : gzFile; var lBuf: ByteP; lReadBytes: integer; lWrite: boolean); const BUFLEN = 16384; var buf : packed array [0..BUFLEN-1] of byte; { Global uses BSS instead of stack } len,lI,written : integer; begin written := 0; if lReadBytes < 1 then exit; Len := lReadBytes div BUFLEN; if Len > 0 then for lI := 1 to Len do begin gzread (infile, @buf, BUFLEN {1388}); if lWrite then Move(buf,lbuf[Written+1],BUFLEN); Written := Written + BUFLEN; end; Len := lReadBytes mod BUFLEN; if Len = 0 then exit; gzread (infile, @buf, Len); if lWrite then Move(buf,lbuf[Written+1],len); end; //ungzipCore function gz_compress (var infile:file; outfile:gzFile): integer; var len : cardinal; ioerr : integer; buf : packed array [0..Z_BUFSIZE-1] of byte; { Global uses BSS instead of stack } errorcode : byte; fsize, lensize : DWord; begin errorcode := 0; //Progress := 0; fsize := FileSize(infile); lensize := 0; //if FProgressStep > 0 then DoOnProgress; while true do begin {$I-}blockread (infile, buf, Z_BUFSIZE, len);{$I+} ioerr := IOResult; if (ioerr <> 0) then begin errorcode := 1; break end; if (len = 0) then break; {$WARNINGS OFF}{Comparing signed and unsigned types} if (gzwrite (outfile, @buf, len) <> len) then begin {$WARNINGS OFF} errorcode := 2; break end; end; closeFile (infile); if (gzclose (outfile) <> 0{Z_OK}) then errorcode := 3; gz_compress := errorcode; end; // proc gz_compress procedure GZipFile(lSrcName,lDestName: String); var FGzipFilename : string; FGzipComments : string; outmode : string; s,FFileDestination : string; infile : file; outfile : gzFile; FCompressionLevel{,errorcode} : integer; flags : Integer; stream : gz_streamp; //p : PChar; ioerr : integer; begin //FGzipHeader := [zFilename]; FGzipFilename:= lSrcName; FGzipComments := ''; FCompressionLevel := 6; //MainForm.ProgressBar1.position :=1; //Gzip (lFile,lMulti); FFileDestination := lDestName; //result := 2; //return error if user aborts (* if fileexists(FFileDestination) then begin case MessageDlg('Overwrite the file '+FFileDestination+'?', mtConfirmation,[mbYes, mbAbort], 0) of { produce the message dialog box } mrAbort: exit; end; end;*) AssignFile (infile, lSrcName); {$I-} Reset (infile,1); {$I+} ioerr := IOResult; if (ioerr <> 0) then begin // Showmessage('Can''t open: '+lSrcName); //errorcode := 1 end else begin outmode := 'w '; //s := IntToStr(FCompressionLevel); outmode[2] := '6';//s[1]; outmode[3] := ' '; (*case FCompressionType of Standard : outmode[3] := ' '; HuffmanOnly : outmode[3] := 'h'; Filtered : outmode[3] := 'f'; end;*) //flags := 0; //if (zfilename in FGzipHeader) then flags := ORIG_NAME; //if (comment in FGzipHeader) then flags := flags + COMMENT_; outfile := gzopen (lSrcName, outmode); if (outfile = NIL) then begin //Showmessage('Can''t open: '+lSrcName); close( infile); exit; end else begin { if flags are set then write them } stream := gz_streamp(outfile); if {(zfilename in FGzipHeader)} true then begin s := lSrcName;//999 ExtractFilename(lSrcName); //p := PChar(s); blockWrite( stream^.gzfile, {p[0]}s, length(s)+1); stream^.startpos := stream^.startpos + length(s) + 1 end; gz_compress(infile, outfile); end end; end; procedure file_compress2 (filename,outname:string); var infile : file; outfile : gzFile; ioerr : integer; mode : string; begin mode := 'w6 '; Assign (infile, filename); {$I-} Reset (infile,1); {$I+} ioerr := IOResult; if (ioerr <> 0) then begin writeln ('open error: ',ioerr); halt(1); end; outfile := gzopen (outname, mode); if (outfile = NIL) then begin //999 showmessage(' can''t gzopen '+outname); halt(1); end; gz_compress(infile, outfile); erase (infile); end; procedure GZipBuffer(var FGzipFilename,FFileDestination: String;lxInBuffer: byteP;lInSize: Integer; lOverwritewarn: boolean); var lTempName: string; lFdata: file; begin (*if lOverwritewarn and fileexists(FFileDestination) then begin case MessageDlg('Overwrite the file '+FFileDestination+'?', mtConfirmation,[mbYes, mbAbort], 0) of { produce the message dialog box } mrAbort: exit; end; end; //if overwrite *) lTempName := changefileext(FFileDestination,'.tmp'); assignfile(lFdata,lTempName ); filemode := 2; rewrite(lFdata,1); BlockWrite(lFdata,lxInBuffer^,lInSize); closefile(lFdata); file_compress2 (lTempName,FFileDestination ); //GZipFile(lTempName,FFileDestination); //deletefile(lTempname); end;//GZipBuffer end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/examplefmri3.bat���������������������������������������������������0000755�0001750�0001750�00000000175�10416600142�017264� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������start mricron .\templates\aal.nii.gz -o .\example\attention.nii.gz -c -0 -l 1.96 -h 5 -z -b 40 -t 50 -r .\example\fmri3r.ini���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/text.pas�����������������������������������������������������������0000755�0001750�0001750�00000004327�12147215554�015710� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit text; {$H+} interface uses {$IFDEF FPC}LResources,{$ENDIF} {$IFNDEF Unix} Windows,{$ENDIF} SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus, StdCtrls,Define_Types; type { TTextForm } TTextForm = class(TForm) MainMenu1: TMainMenu; File1: TMenuItem; Save1: TMenuItem; Closewindow1: TMenuItem; Copy1: TMenuItem; Copy2: TMenuItem; MemoT: TMemo; procedure Closewindow1Click(Sender: TObject); procedure Copy2Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Save1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var TextForm: TTextForm; implementation uses nifti_img_view; {$IFNDEF FPC} {$R *.DFM} {$ENDIF} procedure TTextForm.Closewindow1Click(Sender: TObject); begin TextForm.Close; end; procedure TTextForm.Copy2Click(Sender: TObject); begin {$IFDEF zxDarwin} Showmessage('Copy not yet supported with OSX: use File/Save'); exit; {$ENDIF} MemoT.SelectAll; MemoT.CopyToClipboard; end; procedure TTextForm.FormCreate(Sender: TObject); begin {$IFDEF Darwin} {$IFNDEF LCLgtk} //only for Carbon compile Copy2.ShortCut := ShortCut(Word('C'), [ssMeta]); Save1.ShortCut := ShortCut(Word('S'), [ssMeta]); Closewindow1.ShortCut := ShortCut(Word('W'), [ssMeta]); {$ENDIF} {$ENDIF} end; procedure TTextForm.Save1Click(Sender: TObject); begin ImgForm.SaveDialog1.Filename := parsefilename(gMRIcroOverlay[kBGOverlayNum].HdrFilename); if kTextSep = chr(9) then ImgForm.SaveDialog1.Filter := 'Tab Separated (*.tab)|*.tab|Comma Separated (*.csv)|*.csv|Text (*.txt)|*.txt' else ImgForm.SaveDialog1.Filter := 'Comma Separated (*.csv)|*.csv|Tab Separated (*.tab)|*.tab|Text (*.txt)|*.txt'; if kTextSep = chr(9) then ImgForm.SaveDialog1.DefaultExt := '.tab' else ImgForm.SaveDialog1.DefaultExt := '.csv'; if not ImgForm.SaveDialog1.Execute then exit; MemoT.Lines.SaveToFile(ImgForm.SaveDialog1.Filename); end; {$IFDEF FPC} initialization {$I Text.lrs} {$ENDIF} end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/text.lfm�����������������������������������������������������������0000755�0001750�0001750�00000002025�12147215554�015674� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object TextForm: TTextForm Left = 417 Height = 480 Top = 195 Width = 696 HorzScrollBar.Page = 695 VertScrollBar.Page = 459 ActiveControl = MemoT Caption = 'Descriptive Statistics' ClientHeight = 480 ClientWidth = 696 Font.Height = -11 Font.Name = 'MS Sans Serif' Menu = MainMenu1 OnCreate = FormCreate LCLVersion = '0.9.30.2' object MemoT: TMemo Left = 0 Height = 480 Top = 0 Width = 696 Align = alClient ScrollBars = ssVertical TabOrder = 0 end object MainMenu1: TMainMenu left = 112 top = 10 object File1: TMenuItem Caption = 'File' object Save1: TMenuItem Caption = 'Save' OnClick = Save1Click end object Closewindow1: TMenuItem Caption = 'Close window' OnClick = Closewindow1Click end end object Copy1: TMenuItem Caption = 'Edit' object Copy2: TMenuItem Caption = 'Copy' OnClick = Copy2Click end end end end �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fdr.pas������������������������������������������������������������0000755�0001750�0001750�00000004577�11326425442�015503� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fdr; interface uses define_types; procedure EstimateFDR2(lnTests: integer; var Ps: SingleP; var lFDR05, lFDR01,lnegFDR05, lnegFDR01: double); procedure qsort(lower, upper : integer; var Data:SingleP); implementation procedure qsort(lower, upper : integer; var Data:SingleP); //40ms - very recursive... var left, right : integer; pivot,lswap: single; begin pivot:=Data^[(lower+upper) div 2]; left:=lower; right:=upper; while left<=right do begin while Data^[left] < pivot do left:=left+1; { Parting for left } while Data^[right] > pivot do right:=right-1;{ Parting for right} if left<=right then begin { Validate the change } lswap := Data^[left]; Data^[left] := Data^[right]; Data^[right] := lswap; left:=left+1; right:=right-1; end; //validate end;//while left <=right if right>lower then qsort(lower,right,Data); { Sort the LEFT part } if upper>left then qsort(left ,upper,data); { Sort the RIGHT part } end; procedure EstimateFDR2(lnTests: integer; var Ps: SingleP; var lFDR05, lFDR01,lnegFDR05, lnegFDR01: double); var lInc: integer; lrPs,Qs: SingleP; begin //rank Pvalues //ShaQuickSort(lnTests,Singlep0(Ps[1])); qSort(1,lnTests,Ps); //qcksrt(1,lnTests,Ps); GetMem(Qs,lnTests*sizeof(single)); //next findcrit FDR05 for lInc := 1 to lnTests do Qs^[lInc] := (0.05*lInc)/lnTests; lFDR05 := 0; for lInc := 1 to lnTests do if Ps^[lInc] <= Qs^[lInc] then lFDR05 := Ps^[lInc]; //next findcrit FDR01 for lInc := 1 to lnTests do Qs^[lInc] := (0.01*lInc)/lnTests; lFDR01 := 0; for lInc := 1 to lnTests do if Ps^[lInc] <= Qs^[lInc] then lFDR01 := Ps^[lInc]; //reverse GetMem(lrPs,lnTests*sizeof(single)); for lInc := 1 to lnTests do lrPs^[lInc] := 1- Ps^[lnTests-lInc+1]; for lInc := 1 to lnTests do Qs^[lInc] := (0.05*lInc)/lnTests; lnegFDR05 := 0; for lInc := 1 to lnTests do if lrPs^[lInc] <= Qs^[lInc] then lnegFDR05 := lrPs^[lInc]; //next findcrit FDR01 for lInc := 1 to lnTests do Qs^[lInc] := (0.01*lInc)/lnTests; lnegFDR01 := 0; for lInc := 1 to lnTests do if lrPs^[lInc] <= Qs^[lInc] then lnegFDR01 := lrPs^[lInc]; FreeMem(lrPs); Freemem(Qs); end; end. ���������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/ROIfilt.lfm��������������������������������������������������������0000755�0001750�0001750�00000003720�11450450000�016202� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object FilterROIform: TFilterROIform Left = 569 Height = 190 Top = 107 Width = 240 HorzScrollBar.Page = 209 VertScrollBar.Page = 196 ActiveControl = MinROIfilt BorderIcons = [biSystemMenu] BorderStyle = bsToolWindow Caption = 'Intensity filter' ClientHeight = 190 ClientWidth = 240 Constraints.MaxHeight = 190 Constraints.MaxWidth = 240 Constraints.MinHeight = 190 Font.Name = 'MS Sans Serif' OnClose = FormClose OnShow = FormShow Position = poScreenCenter LCLVersion = '0.9.29' object Label42: TLabel Left = 4 Height = 17 Top = 14 Width = 89 Caption = 'Min. Threshold' ParentColor = False end object FilterROIBtn: TSpeedButton Left = 4 Height = 25 Top = 143 Width = 221 Caption = 'Filter VOI with highlighted' Color = clBtnFace NumGlyphs = 0 OnClick = FilterROIBtnClick ShowHint = True ParentShowHint = False end object Label43: TLabel Left = 4 Height = 14 Top = 49 Width = 75 Caption = 'Max. Threshold' Font.CharSet = 13 ParentColor = False ParentFont = False end object Filter2NIfTIBtn: TSpeedButton Tag = 128 Left = 4 Height = 25 Top = 107 Width = 221 Caption = 'Save highlighted as NIfTI or VOI' Color = clBtnFace NumGlyphs = 0 OnClick = Filter2NIfTIBtnClick ShowHint = True ParentShowHint = False end object FiltROILabel: TLabel Left = 8 Height = 17 Top = 81 Width = 22 Caption = ' ' ParentColor = False end object MinROIfilt: TSpinEdit Left = 120 Height = 24 Top = 7 Width = 52 MaxValue = 254 OnChange = MinROIfiltChange TabOrder = 0 Value = 100 end object MaxROIfilt: TSpinEdit Left = 120 Height = 24 Top = 42 Width = 52 MaxValue = 255 OnChange = MinROIfiltChange TabOrder = 1 Value = 255 end end ������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fpc-res.res��������������������������������������������������������0000755�0001750�0001750�00000170170�11326463754�016276� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ �����������������������<���L����L�A�Z�_�P�I�C�_�D�I�A�L�O�G�_�T�E�M�P�L�A�T�E�������0�����������T���������,���������P����������_S�T�A�T�I�C��������� ��������� ��������(���0���`�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������~~yyDD++EEӣ������������������������������������������������������������������������������������������������������������쿿ہNN ����������<<������������������������������������������������������������������������������������������������袢``��������������������/0���������������������������������������������������������ÛvvMM66MMʭ՚ssGG��������������������������������������������������������������XY=>-."# �������������������������������� Ue������������������������������������������8:y��~������������������������������&�@�[�n�~Hamnwׂ؝������������������������������#��� ���������������������������)�U�����������������RRϊ���������������{}#Z|��������]�*��������������'�v��������������������;;jj���������obw�����������~�3�������<���������������������������;;������;? ����������������S �������������e����������������������mm������%%+�������������m����������m������������������������������))))$' .�����������������J������������������������ ++������LL8722+0! ����������A��x�E����������������������������� 11���dd>>AA;;15'!���O�������"oL-���������������������������������!!''**''__������//GGLL@?:=����������������6����"��������������������������������**,,555588���������GG[[MMLL((��������������Lc���������������������������������((6688BB;;@@������������MMRRbbXXAA�����������������Z�������������������������������������==AAFFMMIIII������������MMlleeYY�����������������`�������������������������������������--KKLLUUMMQQ������������������DDRRxxmm%%�����������������\�����?������������������������������NNUUXXaaRR���������������������bbhhSS���������������M�����u��������������������������BB``]]jj[[������������������������ffVV||EE�����������6����������������������������� EEffddrrjj__������������������������������kkQQTT ���������!�������������������������++ZZllkkxxmm\\������������������������������������]]^^pp..�����������������������77XXoopptt||ssss������������������������������������������uuQQbb##��������� �������!!99RRffqqrrtt������������������������������������������������``\\bb// ��X����('::KK[[ffmmppqqvvzznnxx������������������������������������������������������hhlj78 ��,GEQR\[aaddhhjjnnyynn���������������������������������������������������������������rrRRhhZl+�1]LT][``eekkttttuu������������������������������������������������������������������������uull& v\hmsrxx}}{{mm__xx������������������������������������������������������������������������������������yyuuopolpxu,<:MMVVWW__jj���������������������������������������������������������������������������������������������������||! H@���qp ++::oo�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?����������������������������������������������� �� ��������� ��������(��� ���@��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������aa������������������������������������������������������������������������������ㅅRR55^^������������������������������������������������������������xx44������������$!������������������������������������psLP2645CC<<�������������� ���������������������������pk!�����������������������&�J�j��6`IZ]qψܻ���������������<�S�zu�Y�5 ������Q��������e������]]���������zgt��������A������������]��������bb������ ��������/�������������������������12'$������. ����]����������������^^���>>;=32�@�����Rcc�8 ������������������$$$$ss���QQIIKL:<���������p�����������������������005588���������WWZZWW���������"�������������������11AAGGEE���������ttSSqq33������������a������������������NNTTSSpp������������iinnff������������������������HHbbaarr������������������bbZZ����e�����������������NNllll__������������������������eeqq!!������D�� ���������AAhhxx~~||���������������������������tt]]YY �������**@@ZZoo||}}ttff������������������������������������nnb_(��@:LN^]jjuu{{{{xx������������������������������������������AA~~cL_lpmqqssrrss������������������������������������������������������}}plixjiiiiYXii{{������������������������������������������������������������������}}������ii�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?���� ��������� ��������(������0����������������������������������������������������������������������>��L��P���������������������������������������r�������������������7� ��;��-����� ����!�$#�%-�-!�0F�22�3(�53�88�:3�;?�< �<�?1�B��I��JJ�NM�PP�PR�QZ�TS�YY�YY�Z\�\Z�^`�__�`��bb�ff�gg�o�vv�ww�zy�|z�||�~��v���������������u���H���� �__�$������ ���������� ����l�*��VT�����o�������������14��������&�6��>8�LM�TT�Yg��2����������������� ���77�::�LL�PP�QQ�UU�]\�cc�pm�tt�������������������������""�&&�44�;�AA�[[�aa�cc�ee�mm�ss�tt�yy�{{�}}��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������waO@Fc���������������hkP=0A��������gL?689<) 3>Jsu�����X2  1Mix~{z���C+' #"[}|y��;5!(!Kļ�IE7*_�TRH-,o��VY4%&t֊���]`G./qՈ����UdD$f������^l\:NՎ��������ZjnWBԘ�����������rmpev��������������bQS��������������������������������������������������������������������������������������������������������������?�?���������������������������?������h�� ��������� ��������(������ ��������������������������������������������� �������������������������� ��k� ;� �k�K�!�&� �',�->�/!�0��9+�;2�M]�PP�Wj�YZ�bY�ff�hk�i=�jj�lk�l�oo�op�t��}n���������������x���Zn�[[���H[�B�����������j�$�������>5������{��}{�����������BB�KM�NN�PP�dd�jj��� ������������ ��#�))�::�T]�[[�uu�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������&!��������0793#�����$/18A>;�) =Scba`C@? 5hFGDENegj�% :OITRd`VWY�*( <^JM`QUZ[���+' 6pHLfilm�����-2",_KX\no��������4.BkP]������������������������������������������������������������������������������������������%�� ��������� ��������(���0���`���� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������F��������������������������������������������������������������������������������������������������������������������������������������������P����������������������<����������������������������������������������������������������������������������������������������������������������������������������������������������==����������������������������������������������������������������������������������������������������������������������)������������������������������##hhoo�������������������� ��������������������������������������������������������������e����������������������������������LLrrpp������������������))DJHn[Wmgc ���������������������������������������������� ��n��������������������������������������hhwoU��o��������>:XTXTKGtnX�������������� �����������������������������������������t�����vva���������� )'TPtnrlhcOMx ������}������������������������������,���Z����8wn9������������=:rltorlC@&�������������������������������5����۾���^sV$������������ %#lgtntoUQ@= ��������� ��������e*ft*r����������������OKlgtnjdGDC>_�����������������%/isc��������������������:8c^rmniPL0-����  w��������ns_(a����������������������*(ZVqkpjSO1-t2155=5' #8GW7��������������������������RNojoiQM53@@%00~}wviXHELTgjloqt����������������������������" UQpjlgLH73|JJӞuttwwwwwwO ����������������������������,*[WqlgbB?SKD3~yxwwwwwwE ���J������������������������� SOnhtnXT:7 .zxusromk>����ܱ�����������������������d`rmtnMIA?r+voj[RH4|*Z 4 �����������������������������84ojtorl<9z$ uuՆcc'' ������������������<�����������������20TPjetoql`[���� uuuss77!!������s����������w���������������VQkfsmsnjeMJ����@}}ŀPP88$$ ����=�������������������������85lgsnuooj[V=:������������5dss[[//����������צ���������B>]YniuotoqkEBOJg ����������������"9ww{{LL77%%�ߣ������ 20c^ojtntoqld`JFx �������������������� %vvmmWWAA he��%$A>ZVrltouoqlfaJG ���������������������������� (?YYDD33 ')(2/HEkfrltotosnniGD=:������������������������������������'=ww{{ggSS7700.4:>IHF4-,-+LH\WidsntotoqkjdXTLJk ���������������������������������������� %kwwvv[[TToS_gmurmg[ZW\Xkfpksntosnql_ZKH<:���������������������������������������������������� 0FxxΘ|wxrsnpjjeWSIE=:˿������������������������������������������������������������*bxx}wvqqlb]WSJFFCb_F������������������������������������������������������������������������ 1A]||~zsn^[XTQMGCNKw8 ������������������������������������������������������������������������������������ *3<GIH=6- ������������������������������������������������������������������������������������������������������������ &'& ��������������������������������������������������������������������������������������������������������������������������������  ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������>����<����������������������������������������������������������������������������������������������������������������������������������������������?������?������������������������������������������������ ��������� ��������(��� ���@���� ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������==������������������������������������������������������������������������������)��������������������##oo������������ ������������������������������ ��n������������������������hhoU������XTXTtnX������������������������������������t����va������ TPtnhcOMx���������������������5���۾��^s$��������%#lgtoUQ ������� �����e*t*r������������OKtnjdC>_���� �����ns(a��������������*(qkpj1-21=5 #8W7������������������ojoi53JJӞutwwww ������������������,*qlgbSKD3~xwwww ��J����������������� SOtnXT +vj[H4| 4 �������������������84ojrl<9 uu՞cc'' �������������������������20jeto`[����@PP$$ ��=�����������������85lguooj=:��������d[[//�������������B>niuoqkEB ������������ %mmAA ��%$ZVrluoqlJG �������������������� (YY33 '(HEkftotoniGD���������������������������� %kvv[[oS_mumg[\Xkfsntoql_Z<:������������������������������������ FxxΘxrsnjeWS=:˿��������������������������������������������1]sn^[QMGCw8 �������������������������������������������������������� *<GH=- ����������������������������������������������������������������������������  ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?����?h�� ��������� ��������(������ ���� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������n������������hhU��XT���������������s����lgUQ���� ��s��������*(pjuww����������,*gbv[4| ���������oj<9@PP =��������lgoj���� mm��%$rlql ������������ k[[_ug[kfto_Z��������������������1^[GC �������������������������������� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ��������� ��������(������(��������������������������������������������������������������������������������((�,,�99�AA�I�J��WW�ZZ�hh�ll�nn�x{�yy������������S��������������������������������������2������������� ����!!�&&�,,�//�DD�EE�II�LM�QQ�WW�ZZ�^^�bb�dd�ii�jj�oo�rr�ss�}}������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BDA21,+�� .49CE@>7>0,� 8EB@>>>>7:H� -;>?>>>>>>JM��"5bF>>>>>>KON��#3c>>>>>>>SV`���& /=>>>>>>XZU����� )<G>>IV\^_�������(*'6QTW[]Y�����������!%$LRPa�����������������������������������������������������������������������������������������������������������������0��������v���0����M�A�I�N�I�C�O�N��������� ������������00������� ���� ��������������h���00�� �%��� �� ������ �h�������������� ���� ����� ��������(���0���`�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������~~yyDD++EEӣ������������������������������������������������������������������������������������������������������������쿿ہNN ����������<<������������������������������������������������������������������������������������������������袢``��������������������/0���������������������������������������������������������ÛvvMM66MMʭ՚ssGG��������������������������������������������������������������XY=>-."# �������������������������������� Ue������������������������������������������8:y��~������������������������������&�@�[�n�~Hamnwׂ؝������������������������������#��� ���������������������������)�U�����������������RRϊ���������������{}#Z|��������]�*��������������'�v��������������������;;jj���������obw�����������~�3�������<���������������������������;;������;? ����������������S �������������e����������������������mm������%%+�������������m����������m������������������������������))))$' .�����������������J������������������������ ++������LL8722+0! ����������A��x�E����������������������������� 11���dd>>AA;;15'!���O�������"oL-���������������������������������!!''**''__������//GGLL@?:=����������������6����"��������������������������������**,,555588���������GG[[MMLL((��������������Lc���������������������������������((6688BB;;@@������������MMRRbbXXAA�����������������Z�������������������������������������==AAFFMMIIII������������MMlleeYY�����������������`�������������������������������������--KKLLUUMMQQ������������������DDRRxxmm%%�����������������\�����?������������������������������NNUUXXaaRR���������������������bbhhSS���������������M�����u��������������������������BB``]]jj[[������������������������ffVV||EE�����������6����������������������������� EEffddrrjj__������������������������������kkQQTT ���������!�������������������������++ZZllkkxxmm\\������������������������������������]]^^pp..�����������������������77XXoopptt||ssss������������������������������������������uuQQbb##��������� �������!!99RRffqqrrtt������������������������������������������������``\\bb// ��X����('::KK[[ffmmppqqvvzznnxx������������������������������������������������������hhlj78 ��,GEQR\[aaddhhjjnnyynn���������������������������������������������������������������rrRRhhZl+�1]LT][``eekkttttuu������������������������������������������������������������������������uull& v\hmsrxx}}{{mm__xx������������������������������������������������������������������������������������yyuuopolpxu,<:MMVVWW__jj���������������������������������������������������������������������������������������������������||! H@���qp ++::oo�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?����������������������������������������������� �� ���� ����� ��������(��� ���@��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������aa������������������������������������������������������������������������������ㅅRR55^^������������������������������������������������������������xx44������������$!������������������������������������psLP2645CC<<�������������� ���������������������������pk!�����������������������&�J�j��6`IZ]qψܻ���������������<�S�zu�Y�5 ������Q��������e������]]���������zgt��������A������������]��������bb������ ��������/�������������������������12'$������. ����]����������������^^���>>;=32�@�����Rcc�8 ������������������$$$$ss���QQIIKL:<���������p�����������������������005588���������WWZZWW���������"�������������������11AAGGEE���������ttSSqq33������������a������������������NNTTSSpp������������iinnff������������������������HHbbaarr������������������bbZZ����e�����������������NNllll__������������������������eeqq!!������D�� ���������AAhhxx~~||���������������������������tt]]YY �������**@@ZZoo||}}ttff������������������������������������nnb_(��@:LN^]jjuu{{{{xx������������������������������������������AA~~cL_lpmqqssrrss������������������������������������������������������}}plixjiiiiYXii{{������������������������������������������������������������������}}������ii�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?���� ���� ����� ��������(������0����������������������������������������������������������������������>��L��P���������������������������������������r�������������������7� ��;��-����� ����!�$#�%-�-!�0F�22�3(�53�88�:3�;?�< �<�?1�B��I��JJ�NM�PP�PR�QZ�TS�YY�YY�Z\�\Z�^`�__�`��bb�ff�gg�o�vv�ww�zy�|z�||�~��v���������������u���H���� �__�$������ ���������� ����l�*��VT�����o�������������14��������&�6��>8�LM�TT�Yg��2����������������� ���77�::�LL�PP�QQ�UU�]\�cc�pm�tt�������������������������""�&&�44�;�AA�[[�aa�cc�ee�mm�ss�tt�yy�{{�}}��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������waO@Fc���������������hkP=0A��������gL?689<) 3>Jsu�����X2  1Mix~{z���C+' #"[}|y��;5!(!Kļ�IE7*_�TRH-,o��VY4%&t֊���]`G./qՈ����UdD$f������^l\:NՎ��������ZjnWBԘ�����������rmpev��������������bQS��������������������������������������������������������������������������������������������������������������?�?���������������������������?������h�� ���� ����� ��������(������ ��������������������������������������������� �������������������������� ��k� ;� �k�K�!�&� �',�->�/!�0��9+�;2�M]�PP�Wj�YZ�bY�ff�hk�i=�jj�lk�l�oo�op�t��}n���������������x���Zn�[[���H[�B�����������j�$�������>5������{��}{�����������BB�KM�NN�PP�dd�jj��� ������������ ��#�))�::�T]�[[�uu�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������&!��������0793#�����$/18A>;�) =Scba`C@? 5hFGDENegj�% :OITRd`VWY�*( <^JM`QUZ[���+' 6pHLfilm�����-2",_KX\no��������4.BkP]������������������������������������������������������������������������������������������%�� ���� ����� ��������(���0���`���� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������F��������������������������������������������������������������������������������������������������������������������������������������������P����������������������<����������������������������������������������������������������������������������������������������������������������������������������������������������==����������������������������������������������������������������������������������������������������������������������)������������������������������##hhoo�������������������� ��������������������������������������������������������������e����������������������������������LLrrpp������������������))DJHn[Wmgc ���������������������������������������������� ��n��������������������������������������hhwoU��o��������>:XTXTKGtnX�������������� �����������������������������������������t�����vva���������� )'TPtnrlhcOMx ������}������������������������������,���Z����8wn9������������=:rltorlC@&�������������������������������5����۾���^sV$������������ %#lgtntoUQ@= ��������� ��������e*ft*r����������������OKlgtnjdGDC>_�����������������%/isc��������������������:8c^rmniPL0-����  w��������ns_(a����������������������*(ZVqkpjSO1-t2155=5' #8GW7��������������������������RNojoiQM53@@%00~}wviXHELTgjloqt����������������������������" UQpjlgLH73|JJӞuttwwwwwwO ����������������������������,*[WqlgbB?SKD3~yxwwwwwwE ���J������������������������� SOnhtnXT:7 .zxusromk>����ܱ�����������������������d`rmtnMIA?r+voj[RH4|*Z 4 �����������������������������84ojtorl<9z$ uuՆcc'' ������������������<�����������������20TPjetoql`[���� uuuss77!!������s����������w���������������VQkfsmsnjeMJ����@}}ŀPP88$$ ����=�������������������������85lgsnuooj[V=:������������5dss[[//����������צ���������B>]YniuotoqkEBOJg ����������������"9ww{{LL77%%�ߣ������ 20c^ojtntoqld`JFx �������������������� %vvmmWWAA he��%$A>ZVrltouoqlfaJG ���������������������������� (?YYDD33 ')(2/HEkfrltotosnniGD=:������������������������������������'=ww{{ggSS7700.4:>IHF4-,-+LH\WidsntotoqkjdXTLJk ���������������������������������������� %kwwvv[[TToS_gmurmg[ZW\Xkfpksntosnql_ZKH<:���������������������������������������������������� 0FxxΘ|wxrsnpjjeWSIE=:˿������������������������������������������������������������*bxx}wvqqlb]WSJFFCb_F������������������������������������������������������������������������ 1A]||~zsn^[XTQMGCNKw8 ������������������������������������������������������������������������������������ *3<GIH=6- ������������������������������������������������������������������������������������������������������������ &'& ��������������������������������������������������������������������������������������������������������������������������������  ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������>����<����������������������������������������������������������������������������������������������������������������������������������������������?������?������������������������������������������������ ��������� ��������(��� ���@���� ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������==������������������������������������������������������������������������������)��������������������##oo������������ ������������������������������ ��n������������������������hhoU������XTXTtnX������������������������������������t����va������ TPtnhcOMx���������������������5���۾��^s$��������%#lgtoUQ ������� �����e*t*r������������OKtnjdC>_���� �����ns(a��������������*(qkpj1-21=5 #8W7������������������ojoi53JJӞutwwww ������������������,*qlgbSKD3~xwwww ��J����������������� SOtnXT +vj[H4| 4 �������������������84ojrl<9 uu՞cc'' �������������������������20jeto`[����@PP$$ ��=�����������������85lguooj=:��������d[[//�������������B>niuoqkEB ������������ %mmAA ��%$ZVrluoqlJG �������������������� (YY33 '(HEkftotoniGD���������������������������� %kvv[[oS_mumg[\Xkfsntoql_Z<:������������������������������������ FxxΘxrsnjeWS=:˿��������������������������������������������1]sn^[QMGCw8 �������������������������������������������������������� *<GH=- ����������������������������������������������������������������������������  ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?����?h�� ��������� ��������(������ ���� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������n������������hhU��XT���������������s����lgUQ���� ��s��������*(pjuww����������,*gbv[4| ���������oj<9@PP =��������lgoj���� mm��%$rlql ������������ k[[_ug[kfto_Z��������������������1^[GC �������������������������������� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ��������� ��������(������(��������������������������������������������������������������������������������((�,,�99�AA�I�J��WW�ZZ�hh�ll�nn�x{�yy������������S��������������������������������������2������������� ����!!�&&�,,�//�DD�EE�II�LM�QQ�WW�ZZ�^^�bb�dd�ii�jj�oo�rr�ss�}}������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BDA21,+�� .49CE@>7>0,� 8EB@>>>>7:H� -;>?>>>>>>JM��"5bF>>>>>>KON��#3c>>>>>>>SV`���& /=>>>>>>XZU����� )<G>>IV\^_�������(*'6QTW[]Y�����������!%$LRPa�����������������������������������������������������������������������������������������������������������������0��������v���0����M�A�I�N�I�C�O�N��������� ������������00������ � ���� �� ������� �����h�� �00�� �%�� � �� ������ �h��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/nifti_img.pas������������������������������������������������������0000755�0001750�0001750�00000630102�12371457765�016700� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit nifti_img; interface uses {$H+} {$IFNDEF FPC} RXSpin,capmenu,PNGImage,SSE,ShellAPI,Spin, {$ENDIF} {$IFNDEF Unix} Windows,wgraphics, {$ELSE} RGBGraphics,rgbroutines, {$ENDIF} nifti_types, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus, ExtCtrls, NIFTI_hdr,nii_label, //StdCtrls, ComCtrls, Math, ClipBrd,define_types, GraphicsMathLibrary,Distr,Stat,ReadInt,gzio2; const kMultiView = 0; kAxView0 = 1; kSagView0 = 2; kCoroView0 = 3; kAxViewOnly = -1; kSagViewOnly = -2; kCoroViewOnly = -3; kMaxLabel = 255; Type TBGImg = record //Next: analyze Format Header structure ScrnDim: array [1..3] of smallint; ScrnMM,ScrnOri: array [1..3] of single; XViewCenter,YViewCenter,ZViewCenter: single; SliceView,SPMDefaultsStatsFmriT,SPMDefaultsStatsFmriT0, MaxDim,LicenseID,XBarGap,XBarThick,VOIUndoSlice,VOIUndoOrient,VOIUndoVolItems, RenderDepthBufferItems,VOIInvZoom,ZoomPct,BGTransPct,OverlayTransPct, ImageSeparation,RenderDim,SigDig,LesionSmooth,LesionDilate,FontSize, SaveImgFilter, SaveVoiFilter: integer; //ResizeBeforeRescale - 0=intensity rescale, then resize; 1= nearest neighbor resize, then rescale;1=trilinear resize, then rescale;12:47 PM 7/13/2006 UseReorientHdr,XBarVisible,ThinPen,Mirror,OverlaySmooth,VOIchanged,VOImirrored, SaveDefaultIni,KnownAlignment,Resliced, FlipAx,FlipSag,SingleRow,ResliceOnLoad,Prompt4DVolume,OrthoReslice, ShowDraw: boolean; MinChar,MaxChar: array [1..3] of char; //May07 StretchQuality : TStretchQuality; VOIClr,XBarClr: TColor; BackupLUT: TLUT; //LabelStr20 : Array[0..kMaxLabel] of kstr50; LabelRA: TStrRA; {FSLDIR,}FSLBASE,FSLOUTPUTTYPE{,FSLBETEXE}: kStr255; InvMat: TMatrix; ReorientHdr: TNIFTIHdr; //Cutout: TCutout; VOIUndoVol: bytep; RenderDepthBuffer: SmallIntp; end; //TNIFTIhdr Header Structure procedure CreateAnaRGB; function SlicesToImgPos(lX,lY,lZ: integer): integer; procedure ImgPosToSlices(lPos: integer; var lX,lY,lZ: integer); procedure DrawBMP( lx, ly: integer; var lBuff: RGBQuadp; var lImage: TImage); procedure IntenBar (var lImage: TImage; var lHdr: TMRIcroHdr; lLTRB: integer {1=Left,2=Top,3=right,4=bottom}; lMin,lMax: single); procedure Balance (var lHdr: TMRIcroHdr); function ImgVaries ( var lHdr: TMRIcroHdr): boolean; function OpenImg(var lBackgroundImg: TBGImg; var lImg2Load: TMRIcroHdr; lLoadBackground,lVOILoadAsBinary,lNoScaling8bit,lResliceIn,l4D: boolean): boolean; procedure InitImgMemory(var lHdr: TMRIcroHdr); procedure FreeImgMemory(var lHdr: TMRIcroHdr); procedure SetDimension32(lInPGHt,lInPGWid:integer; lBuff: RGBQuadp; var lBackgroundImg: TBGImg; var lImage: TImage; lPanel: TScrollBox); //procedure RescaleImgIntensity(var lBackgroundImg: TBGImg; var lHdr: TMRIcroHdr ); procedure RescaleImgIntensity(var lBackgroundImg: TBGImg; var lHdr: TMRIcroHdr; lLayer: integer ); procedure LoadColorScheme(lStr: string; var lHdr: TMRIcroHdr); procedure LoadMonochromeLUT (var lLUT: integer; var lBackgroundImg: TBGImg; var lHdr: TMRIcroHdr); //lLUT: 0=gray,1=red,2=green,3=blue procedure FilterLUT (var lBackgroundImg: TBGImg; var lHdr: TMRIcroHdr; lMin, lMax: integer); //lLUT: 0=gray,1=red,2=green,3=blue function Raw2ScaledIntensity (lHdr: TMRIcroHdr; lRaw: single): single; function Scaled2RawIntensity (lHdr: TMRIcroHdr; lScaled: single): single; procedure AlphaBlend32(lBGQuad,lOverlayQuad : RGBQuadp; lBG0Clr,lOverlay0Clr: DWord; lSlicePixels, lOverlayTransPct: integer); // 630 procedure SetBGImgDefaults (var lBGImg: TBGImg); function MaxDim (lX,lY,lZ: integer): integer; //returns largest of 3 procedure DrawHistogram (var lHdr: TMRIcroHdr; var lImage: TImage); function MirrorImgBuffer(var lHdr: TMRIcroHdr ): boolean; procedure MirrorScrnBuffer(var lBackgroundImg: TBGImg; var lHdr: TMRIcroHdr ); procedure SetSubmenuWithTag (var lRootMenu: TMenuItem; lTag: Integer); procedure SaveAsVOIorNIFTIcore (var lFilename: string; var lImgBuffer: ByteP; lImgBufferItems, lImgBufferBPP,lnVol: integer; var lNiftiHdr: TNIFTIHdr); procedure SaveAsVOIorNIFTI (var lImgBuffer: ByteP; lImgBufferItems, lImgBufferBPP,lnVol: integer; DefaultFormatVOI: boolean; var lNiftiHdr: TNIFTIHdr; lDefFilename: string); function Scrn2ScaledIntensity (lHdr: TMRIcroHdr; lRaw: single): single; procedure ScaleScrn2BMP (var lX, lY: integer;lImage: TImage); procedure DrawXBar ( lHorPos, lVerPos: integer;var lImage: TImage); function ImageZoomPct( var lImage: TImage): integer; procedure ScaleBMP2Draw (var InvZoomShl10,lX, lY,lPanel: integer; lImage: TImage); function ComputeInvZoomShl10(lSelectedImageNum: integer; var lImage: TImage): integer; function ComputeZoomPct(lSelectedImageNum: integer; var lImage: TImage): integer; function SelectedImageNum: Integer; procedure EnsureVOIOpen; procedure FreeUndoVol; procedure CreateUndoVol; procedure UndoVolVOI; function IsVOIOpen: boolean; //procedure SortCutout (var lCutout : TCutout); //ensure Lo < Hi procedure SaveImgAsPNGBMP (lImage: TImage); procedure RefreshImages; procedure DrawAxial (lSlice,lMultiSlice: integer); procedure DrawSag(lSlice,lMultiSlice: integer); procedure DrawCor(lSlice,lMultiSlice: integer); procedure DrawLabel(var lImage: TImage; lValue,lXCenterIn,lXWidthIn: integer); procedure ImgCoordToMM(var lX,lY,lZ: integer; var lXmm,lYmm,lZmm: single); procedure MMToImgCoord(var lX,lY,lZ: integer; var lXmm,lYmm,lZmm: single); //function DimToMM (lIn, lDim: integer): integer; function DimToMM (lX,lY,lZ, lDim: integer): integer; function DimToMMx (lDim: integer): integer; procedure ImgPosToMM(lPos: integer; var lXmm,lYmm,lZmm: single); procedure MakeStatHdr (var lBGHdr,lStatHdr: TMRIcroHdr; lMinIntensity,lMaxIntensity,lIntent_p1,lIntent_p2,lIntent_p3: single; lIntent_code: smallint;lIntentName: string); function CenterOfMass (lOverlay: integer; var lX,lY,lZ: double): integer; procedure TextReportHisto (var lHdr: TMRIcroHdr); function TColor2TRGBQuad(lColor: TColor): TRGBQuad; function TRGBQuad2DWord (lLUT: TRGBQuad): DWord; procedure ReturnMinMax (var lHdr: TMRIcroHdr; var lMin,lMax: single; var lFiltMin8bit, lFiltMax8bit: integer); function RawBGIntensity(lPos: integer): single; //procedure FreeImgMemory(var lHdr: TMRIcroHdr); const gSelectedImageNum :integer= 1; //gTripleZoom100: integer = 1; //gImgSpacing: integer = 1; implementation uses nifti_img_view,MultiSlice,histoform,text, ortho_reorient, reslice_img; function RawBGIntensity(lPos: integer): single; var l16Buf : SmallIntP; l32Buf : SingleP; begin result := 0; if (lPos > gMRIcroOverlay[kBGOverlayNum].ImgBufferItems) or (lPos < 1) then exit; if (gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP = 4) then begin l32Buf := SingleP(gMRIcroOverlay[kBGOverlayNum].ImgBuffer ); result := l32Buf^[lPos]; end else if (gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP = 2) then begin l16Buf := SmallIntP(gMRIcroOverlay[kBGOverlayNum].ImgBuffer ); result := l16Buf^[lPos]; end else if gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP = 1 then result := gMRIcroOverlay[kBGOverlayNum].ImgBuffer^[lPos] else begin showmessage('Unknown Background Buffer Bytes Per Pixel'); exit; end; end; function TRGBQuad2DWord (lLUT: TRGBQuad): DWord; var inguy : ^DWord; begin inguy := @lLUT; result := inguy^; end; function TRGBQuad2TColor (lLUT: TRGBQuad): TColor; begin result := (lLUT.rgbred)+(lLUT.rgbgreen shl 8)+(lLUT.rgbblue shl 16); end; function TColor2TRGBQuad(lColor: TColor): TRGBQuad; begin result.rgbRed := (lColor and 255) ; result.rgbGreen := (lColor shr 8) and 255 ;// and 65280; result.rgbBlue := ((lColor shr 16) and 255) ;//and 16711680; result.rgbReserved := kLUTalpha; end; procedure InitImgMemory(var lHdr: TMRIcroHdr); begin with lHdr do begin RenderBufferItems := 0; ScrnBufferItems := 0; ImgBufferItems := 0; end; end; function CenterOfMass (lOverlay: integer; var lX,lY,lZ: double): integer; //result is volume in voxels - 0 = no volume or error var lXpos,lYpos,lZpos,lInc: integer; begin result := 0; lX := 0; lY := 0; lZ := 0; //fx((gMRIcroOverlay[lOverlay].NIFTIhdr.dim[1]*gMRIcroOverlay[lOverlay].NIFTIhdr.dim[2]* gMRIcroOverlay[lOverlay].NIFTIhdr.dim[3]), gMRIcroOverlay[lOverlay].ScrnBufferItems); if (gMRIcroOverlay[lOverlay].NIFTIhdr.dim[1]*gMRIcroOverlay[lOverlay].NIFTIhdr.dim[2]* gMRIcroOverlay[lOverlay].NIFTIhdr.dim[3]) <> gMRIcroOverlay[lOverlay].ScrnBufferItems then exit; //fx(999); lInc := 0; for lZpos := 1 to gMRIcroOverlay[lOverlay].NIFTIhdr.dim[3] do begin for lYpos := 1 to gMRIcroOverlay[lOverlay].NIFTIhdr.dim[2] do begin for lXpos := 1 to gMRIcroOverlay[lOverlay].NIFTIhdr.dim[1] do begin inc(lInc); if gMRIcroOverlay[lOverlay].ScrnBuffer^[lInc] > 0 then begin inc(result); lX := lX + lXpos; lY := lY + lYpos; lZ := lZ + lZpos; end; end; //lX end;//Y end;//Z //fx(lX,lY,lZ); if result > 0 then begin lX := lX / result; lY := lY / result; lZ := lZ / result; end; //lARDistance := round(sqrt( sqr(lRX-lAX)+sqr(lRY-lAY)+sqr(lRZ-lAZ))); //<- pythagorean theorem for dx end; procedure MakeStatHdr (var lBGHdr,lStatHdr: TMRIcroHdr; lMinIntensity,lMaxIntensity,lIntent_p1,lIntent_p2,lIntent_p3: single; lIntent_code: smallint;lIntentName: string); //lIntent kNIFTI_INTENT_CHISQ lIntent_p1 = DOF //lIntent kNIFTI_INTENT_ZSCORE no params //lIntent kNIFTI_INTENT_TTEST lIntent_p1 = DOF var lIntentNameLen,lPos: integer; begin with lStatHdr do begin move(lBGHdr.niftiHdr,lStatHdr.niftiHdr,sizeof(TniftiHdr)); ImgBufferBPP := 1; ImgBufferItems := gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems; NIFTIhdr.scl_slope:= 1; NIFTIhdr.scl_inter:= 0; NIFTIhdr.glmin := round(lMinIntensity); NIFTIhdr.glmax := round(lMaxIntensity); AutoBalMinUnscaled := lMinIntensity; AutoBalMaxUnscaled := lMaxIntensity; WindowScaledMin := lMinIntensity; WindowScaledMax := lMaxIntensity; GlMinUnscaledS := lMinIntensity; GlMaxUnscaledS := lMaxIntensity; HdrFileName := extractfilepath(HdrFilename)+'stat.nii.gz'; ImgFileName := HdrFileName; NIFTIhdr.intent_code := lIntent_Code;// kNIFTI_INTENT_ESTIMATE; NIFTIhdr.intent_p1 := lIntent_p1; NIFTIhdr.intent_p2 := lIntent_p2; NIFTIhdr.intent_p3 := lIntent_p3; lIntentNameLen := length(lIntentName); if lIntentNameLen > sizeof(NIFTIhdr.intent_name) then lIntentNameLen := sizeof(NIFTIhdr.intent_name); if lIntentNameLen > 0 then for lPos := 1 to lIntentNameLen do NIFTIhdr.intent_name[lPos] := lIntentName[lPos]; end; end; procedure MMToImgCoord(var lX,lY,lZ: integer; var lXmm,lYmm,lZmm: single); var lXx,lYy,lZz: single; begin if (not gBGImg.Resliced) and ( gMRIcroOverlay[kBGOverlayNum].NIfTItransform) then begin//vcx //mirror lxx := lXmm; lyy := lYmm; lzz := lZmm; mm2Voxel (lxx,lyy,lzz, gBGImg.InvMat); if gBGImg.Mirror then lXx := gBGImg.ScrnDim[1]-lXx; lX := round(lxx); ly := round(lyy); lz := round(lzz); exit; end; if gBGImg.Mirror then lX := round((gBGImg.ScrnDim[1]-gBGImg.ScrnOri[1]+1)-(lXmm/gBGImg.ScrnMM[1])) else lX := round((lXmm/gBGImg.ScrnMM[1])+gBGImg.ScrnOri[1]); lY := round((lYmm/gBGImg.ScrnMM[2])+gBGImg.ScrnOri[2]); lZ := round((lZmm/gBGImg.ScrnMM[3])+gBGImg.ScrnOri[3]); if lX < 1 then lX := 1; if lY < 1 then lY := 1; if lZ < 1 then lZ := 1; if lX > gBGImg.ScrnDim[1] then lX := gBGImg.ScrnDim[1]; if lY > gBGImg.ScrnDim[2] then lY := gBGImg.ScrnDim[2]; if lZ > gBGImg.ScrnDim[3] then lZ := gBGImg.ScrnDim[3]; end; (*2008 procedure MMToImgCoord(var lX,lY,lZ: integer; var lXmm,lYmm,lZmm: single); begin lX := round((lXmm/gBGImg.ScrnMM[1])+gBGImg.ScrnOri[1]); lY := round((lYmm/gBGImg.ScrnMM[2])+gBGImg.ScrnOri[2]); lZ := round((lZmm/gBGImg.ScrnMM[3])+gBGImg.ScrnOri[3]); if lX < 1 then lX := 1; if lY < 1 then lY := 1; if lZ < 1 then lZ := 1; if lX > gBGImg.ScrnDim[1] then lX := gBGImg.ScrnDim[1]; if lY > gBGImg.ScrnDim[2] then lY := gBGImg.ScrnDim[2]; if lZ > gBGImg.ScrnDim[3] then lZ := gBGImg.ScrnDim[3]; end; *) (*procedure ImgCoordToMM(var lX,lY,lZ: integer; var lXmm,lYmm,lZmm: single); begin lXmm := ((lX)-gBGImg.ScrnOri[1])*gBGImg.ScrnMM[1]; lYmm := ((lY)-gBGImg.ScrnOri[2])*gBGImg.ScrnMM[2]; lZmm := ((lZ)-gBGImg.ScrnOri[3])*gBGImg.ScrnMM[3]; end; *) procedure ImgCoordToMM(var lX,lY,lZ: integer; var lXmm,lYmm,lZmm: single); begin if (not gBGImg.Resliced) and ( gMRIcroOverlay[kBGOverlayNum].NIfTItransform) then begin//vcx //mirror lXmm := lX; if gBGImg.Mirror then lXmm := gBGImg.ScrnDim[1]-lXmm; lYmm := lY; lZmm := lZ; Voxel2mm (lxmm,lymm,lzmm, gMRIcroOverlay[kBGOverlayNum].NIftiHdr); exit; end; if gBGImg.Mirror then lXmm := ((gBGImg.ScrnDim[1]-lX+1)-gBGImg.ScrnOri[1])*gBGImg.ScrnMM[1] else lXmm := ((lX)-gBGImg.ScrnOri[1])*gBGImg.ScrnMM[1]; lYmm := ((lY)-gBGImg.ScrnOri[2])*gBGImg.ScrnMM[2]; lZmm := ((lZ)-gBGImg.ScrnOri[3])*gBGImg.ScrnMM[3]; end; function XPos(lPos,XDim: integer): integer; //given 1D array return 3D column begin result := lPos mod XDim; if result = 0 then result := XDim; end; function ZPos(lPos, XDimTimesYDim: integer): integer; //given 1D array return 3D slice begin result := lPos div XDimTimesYDim; if (lPos mod XDimTimesYDim) <> 0 then inc(result); end; function YPos(lPos, XDim,YDim: integer): integer; //given 1D array return 3D row var lSlicePos: integer; begin //first - eliminate slice offset result := ZPos(lPos,XDim*YDim); lSlicePos := lPos - ((result-1)*(XDim*YDim)); //now find row result :=lSlicePos div XDim; if (lSlicePos mod XDim) <> 0 then inc(result); end; (*function XPos(lPos,XDim: integer): integer; //given 1D array return 3D column begin result := lPos mod XDim; if result = 0 then result := XDim; end; function ZPos(lPos, XDimTimesYDim: integer): integer; //given 1D array return 3D slice begin result := lPos div XDimTimesYDim; if (lPos mod XDimTimesYDim) <> 0 then inc(result); end; function YPos(lPos, XDim,YDim: integer): integer; //given 1D array return 3D row var lSlicePos: integer; begin //first - eliminate slice offset result := ZPos(lPos,XDim*YDim); lSlicePos := lPos - ((result-1)*(XDim*YDim)); //now find row result :=lSlicePos div XDim; if (lSlicePos mod XDim) <> 0 then inc(result); end; *) function SlicesToImgPos(lX,lY,lZ: integer): integer; begin result := lX + ((lY-1) * gBGImg.ScrnDim[1])+ ((lZ-1)*gBGImg.ScrnDim[1]*gBGImg.ScrnDim[2]); end; procedure ImgPosToSlices(lPos: integer; var lX,lY,lZ: integer); begin lX := XPos(lPos,gBGImg.ScrnDim[1]); lY := YPos(lPos,gBGImg.ScrnDim[1],gBGImg.ScrnDim[2]); lZ := ZPos(lPos,gBGImg.ScrnDim[1]*gBGImg.ScrnDim[2]); end; procedure ImgPosToMM(lPos: integer; var lXmm,lYmm,lZmm: single); var lX,lY,lZ: integer; begin lX := XPos(lPos,gBGImg.ScrnDim[1]); lY := YPos(lPos,gBGImg.ScrnDim[1],gBGImg.ScrnDim[2]); lZ := ZPos(lPos,gBGImg.ScrnDim[1]*gBGImg.ScrnDim[2]); ImgCoordToMM(lX,lY,lZ, lXmm,lYmm,lZmm); //xxx lPos := lX + ((lY-1)*gBGImg.ScrnDim[1])+((lZ-1)*gBGImg.ScrnDim[1]*gBGImg.ScrnDim[2]); end; (*function DimToMM (lIn, lDim: integer): integer; var lX,lY,lZ: integer; lXmm,lYmm,lZmm: single; begin lX := lIn; lY := lIn; lZ := lIn; //if lDim = 2 then imgform.caption := inttostr(lY)+'-'; ImgCoordToMM(lX,lY,lZ,lXmm,lYmm,lZmm); case lDim of 3: result := round(lZmm); 2: result := round(lYmm); else result := round(lXmm); end; //case //imgform.caption := floattostr(lYmm); end; //DimToMM *) function DimToMM (lX,lY,lZ, lDim: integer): integer; //Sept2008 - X/Y/Z required for rotated images var lXi,lYi,lZi: integer; lXmm,lYmm,lZmm: single; begin lXi := lX; lYi := lY; lZi := lZ; ImgCoordToMM(lXi,lYi,lZi,lXmm,lYmm,lZmm); //imgform.Caption := floattostr(lxmm)+' '+floattostr(lymm)+' '+floattostr(lzmm)+' 666'; case lDim of 3: result := round(lZmm); 2: result := round(lYmm); else result := round(lXmm); end //case end; //DimToMM function DimToMMx (lDim: integer): integer; var lX,lY,lZ: integer; begin lX := round(ImgForm.XViewEdit.value); lY := round(ImgForm.YViewEdit.value); lZ := round(ImgForm.ZViewEdit.value); result := DimToMM(lX,lY,lZ,lDim); end; //DimToMM procedure DrawTextLabel(var lImage: TImage; lOutStr: string; lXCenterIn,lXWidthIn: integer); var lXWidth,lXCenter: integer; begin lXWidth := lXWidthIn; lXCenter:= lXCenterIn; if lXWidth < 1 then begin lXWidth := lImage.Picture.Bitmap.Width; end; if gBGImg.XBarClr = TColor(gMRIcroOverlay[kBGOverlayNum].LUTinvisible) then lImage.canvas.font.Color := clBlack//clWhite;//gLUT[lClr].rgbRed+(gLUT[lClr].rgbGreen shl 8)+(gLUT[lClr].rgbBlue shl 16); else lImage.canvas.font.Color := gBGImg.XBarClr; lImage.Canvas.Brush.Style := bsClear; {$IFDEF Darwin} lImage.Canvas.Font.Name := 'Helvetica'; {$ELSE} lImage.Canvas.Font.Name := 'Arial'; {$ENDIF} lImage.Canvas.Font.Size := gBGImg.FontSize; (*if lXWidth < 100 then lImage.Canvas.Font.Size := 12 else if lXWidth < 200 then lImage.Canvas.Font.Size := 14 else lImage.Canvas.Font.Size := 18; *) //lImage.Canvas.Font.Size := 18; if lXCenterIn < 1 then lImage.canvas.TextOut(2,1,lOutStr) else if lXCenterIn = MaxInt then lImage.canvas.TextOut((lXWidth div 2)-(lImage.Canvas.TextWidth(lOutStr) div 2),1,lOutStr) else lImage.canvas.TextOut(lXCenter-(lImage.Canvas.TextWidth(lOutStr) div 2),1,lOutStr) end; procedure DrawLabel(var lImage: TImage; lValue,lXCenterIn,lXWidthIn: integer); begin DrawTextLabel(lImage,inttostr(lValue),lXCenterIn,lXWidthIn); end; procedure DrawTextLabelV(var lImage: TImage; lOutStr: string); var lYHt: integer; begin lYHt := lImage.Picture.Bitmap.Height; if gBGImg.XBarClr = TColor(gMRIcroOverlay[kBGOverlayNum].LUTinvisible) then lImage.canvas.font.Color := clBlack//clWhite;//gLUT[lClr].rgbRed+(gLUT[lClr].rgbGreen shl 8)+(gLUT[lClr].rgbBlue shl 16); else lImage.canvas.font.Color := gBGImg.XBarClr; lImage.Canvas.Brush.Style := bsClear; lImage.Canvas.Font.Name := 'Arial'; lImage.canvas.TextOut(2,(lYHt div 2)-round(0.5*lImage.Canvas.TextHeight('X')),lOutStr) end; (*procedure DrawLabel(var lImage: TImage; lValue,lXCenterIn,lXWidthIn: integer); var lOutStr: string; lXWidth,lXCenter: integer; begin lXWidth := lXWidthIn; lXCenter:= lXCenterIn; if lXWidth < 1 then begin lXWidth := lImage.Picture.Bitmap.Width; end; if gBGImg.XBarClr = TColor(gMRIcroOverlay[kBGOverlayNum].LUTinvisible) then lImage.canvas.font.Color := clBlack//clWhite;//gLUT[lClr].rgbRed+(gLUT[lClr].rgbGreen shl 8)+(gLUT[lClr].rgbBlue shl 16); else lImage.canvas.font.Color := gBGImg.XBarClr; lImage.Canvas.Brush.Style := bsClear; lImage.Canvas.Font.Name := 'Arial'; if lXWidth < 100 then lImage.Canvas.Font.Size := 9 else if lXWidth < 200 then lImage.Canvas.Font.Size := 12 else lImage.Canvas.Font.Size := 14; lOutStr := inttostr(lValue); if lXCenterIn < 1 then lImage.canvas.TextOut(2,1,lOutStr) else if lXCenterIn = MaxInt then lImage.canvas.TextOut((lXWidth div 2)-(lImage.Canvas.TextWidth(lOutStr) div 2),1,lOutStr) else lImage.canvas.TextOut(lXCenter-(lImage.Canvas.TextWidth(lOutStr) div 2),1,lOutStr) end;*) {$IFNDEF FPC} procedure PasteDimension32(lInPGHt,lInPGWid:integer; lBuff: RGBQuadp; var lImage: TImage; lXOffset: integer); var sbBits : PByteArray; lPGWid,lPGHt,nBytesInImage: integer; lBMP: TBitmap; lSrcRect,lDestRect: TRect; begin if lXOffset < 1 then begin showmessage('Error with paste dimension - XOffset is <1!'); exit; end; lPGWid := lInPGWid; lPGHt := lInPGHt; lBMP := TBitmap.Create; TRY lBMP.PixelFormat := pf32bit; lBMP.Width := lPGwid; lBMP.Height := lPGHt; sbBits := lBmp.ScanLine[lPGHt-1]; nBytesInImage := lPGWid*lPGHt * 4; CopyMemory(Pointer(sbBits),Pointer(lBuff),nBytesInImage); lImage.Canvas.CopyMode := cmSrcCopy; lSrcRect := Rect(0,0,lBMP.Width,lBMP.Height); lDestRect := Rect(lXOffset,0,lXOffset+lBMP.Width,lBMP.Height); lImage.Canvas.CopyRect(lDestRect,lBMP.Canvas,lSrcRect); FINALLY lBMP.Free; END; //try..finally end; //proc PasteDimension32 {$ELSE} //PasteDimension32 FPC procedure PasteDimension32(lInPGHt,lInPGWid:integer; lBuff: RGBQuadp; lXOffset: integer); var lRowStart,x, y,lPos: Integer; begin if lBuff = nil then exit; lPos := 0; for y:= (lInPGHt-1) downto 0 do begin lRowStart := (y * gMultiWid)+lXOffset; for x:=0 to lInPGWid-1 do begin //dec(lPos); inc(lPos); gMultiBuff^[lRowStart+x] := lBuff^[lPos]; end; end; end; {$ENDIF} procedure CreateSag(var lHdr: TMRIcroHdr; lX,lXOffset,lY,lZ,lXYSliceSz: Integer; var lQuadP: RGBQuadp); var lSrc: Bytep; //lLongBuff: LongIntp; lPixel,lYPos,lZPos,lZOffset,lYOffset: integer; begin lSrc := lHdr.ScrnBuffer; lPixel := 0; // lLongBuff := LongIntp(lQuadP); for lZPos := 1 to lZ do begin lZOffset := (lZPos-1) * lXYSliceSz; lYOffset := 0; for lYPos := 1 to lY do begin inc(lPixel); lQuadP^[lPixel] := lHdr.LUT[lSrc^[lZOffset+lYOffset+lXOffset]]; lYOffset := lYOffset+ lX; end; //for each Y end; //for each Z end; //CreateSag procedure MirrorSlice (lY,lX: integer; lImage: RGBQuadp); var lRowData: RGBQuadp; lXi,lYi,lHalfX,lRowBytes,lTop: integer; begin if lX < 2 then exit; lRowBytes := lX * 4; getmem(lRowData,lRowBytes); lHalfX := lX div 2; lTop := 1; for lYi := 1 to lY do begin Move(lImage^[lTop],lRowData^[1],lRowBytes); for lXi := 1 to lX do lImage^[lTop+lXi-1] := lRowData^[lX - lXi + 1]; lTop := lTop + lX; end; freemem(lRowData); end; procedure DrawSag (lSlice,lMultiSlice: integer); var lBGQuadP, lOverlayQuadP, l2ndOverlayQuadP: RGBQuadp; lOverlay,lnOverlay,lXOffset, lX,lY,lZ,lXYSliceSz,lYZSliceSz: longint; lBG0Clr,lOverlay0Clr: DWord; begin lX := round(gBGImg.ScrnDim[1]); lY := round(gBGImg.ScrnDim[2]); lZ := round(gBGImg.ScrnDim[3]); lXOffset := round(lSlice); lXYSliceSz := (lX*lY); lYZSliceSz := (lY*lZ); if (lXOffset > lX) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems=0)or (lXOffset < 1 {999+}) or (lXYSliceSz < 1) then exit; if (lZ < 2) then begin SetDimension32(1,1, nil, gBGImg, ImgForm.PGImageSag, ImgForm.TriplePanel); exit; end; GetMem ( lBGQuadP , lYZSliceSz*4); CreateSag(gMRIcroOverlay[kBGOverlayNum], lX,lXOffset,lY,lZ,lXYSliceSz, lBGQuadP); //next: overlays lnOverlay := 0; lBG0Clr:= TRGBQuad2DWord(gMRIcroOverlay[kBGOverlayNum].LUTinvisible);//just to avoid compiler warning hint - never used... for lOverlay := knMaxOverlay downto 1 do begin if gMRIcroOverlay[lOverlay].ScrnBufferItems > 0 then begin inc(lnOverlay); if lnOverlay = 1 then begin //top overlay GetMem ( lOverlayQuadP , lYZSliceSz*4); lBG0Clr:= TRGBQuad2DWord(gMRIcroOverlay[lOverlay].LUTinvisible); CreateSag(gMRIcroOverlay[lOverlay], lX,lXOffset,lY,lZ,lXYSliceSz, lOverlayQuadP); end else begin //2nd or lower overlay if lnOverlay = 2 then //2nd overlay GetMem ( l2ndOverlayQuadP , lYZSliceSz*4); CreateSag(gMRIcroOverlay[lOverlay], lX,lXOffset,lY,lZ,lXYSliceSz, l2ndOverlayQuadP); lOverlay0Clr:= TRGBQuad2DWord(gMRIcroOverlay[lOverlay].LUTinvisible); AlphaBlend32(lOverlayQuadP,l2ndOverlayQuadP, lBG0Clr,lOverlay0Clr, lYZSliceSz,gBGImg.OverlayTransPct); end; //2nd overlay or more end; //overlay loaded end; //for knOverlay..1 //Finally: draw overlays on BG if lnOverlay > 0 then begin lOverlay0Clr := lBG0Clr; lBG0Clr := 0;//0=impossible [no alpha] DWord(lHdr.LUTinvisible); if lnOverlay > 1 then FreeMem ( l2ndOverlayQuadP); AlphaBlend32(lBGQuadP,lOverlayQuadP, lBG0Clr,lOverlay0Clr, lYZSliceSz,gBGImg.BGTransPct); FreeMem ( lOverlayQuadP); end; //draw image if gBGImg.FlipSag then MirrorSlice (lZ,lY, lBGQuadP); if lMultiSlice >= 0 then PasteDimension32(lZ,lY, lBGQuadP,lMultiSlice)//, MultiSliceForm.MultiImage,lMultiSlice) else begin SetDimension32(lZ,lY, lBGQuadP, gBGImg, ImgForm.PGImageSag, ImgForm.TriplePanel); FreeMem ( lBGQuadP); if {ImgForm.XBarBtn.Down} gBGImg.XBarVisible then begin if gBGImg.FlipSag then DrawXBar ( round(lY-gBGImg.YViewCenter), round(gBGImg.ZViewCenter),ImgForm.PGImageSag) else DrawXBar ( round(gBGImg.YViewCenter), round({lZ-}gBGImg.ZViewCenter),ImgForm.PGImageSag); DrawLabel(ImgForm.PGImageSag, DimToMMx(1),-1,-1); if gBGImg.KnownAlignment then begin DrawTextLabel(ImgForm.PGImageSag,gBGImg.MaxChar[3]{'S'},MaxInt,-1); if gBGImg.FlipSag then DrawTextLabelV(ImgForm.PGImageSag,gBGImg.MaxChar[2]) else DrawTextLabelV(ImgForm.PGImageSag,gBGImg.MinChar[2]{'P'}); end; end; //XBars end; //draw end; procedure CreateCor(var lHdr: TMRIcroHdr; lX,lYOffset,lZ,lXYSliceSz: Integer; var lQuadP: RGBQuadp); var lSrc: Bytep; lPixel,lXPos,lZPos,lZOffset: integer; begin lSrc := lHdr.ScrnBuffer; lPixel := 0; //fx(lYOffset); for lZPos := 1 to (lZ) do begin lZOffset := (lZPos-1) * lXYSliceSz; for lXPos := 1 to lX do begin inc(lPixel); lQuadP^[lPixel]:=lHdr.LUT[lSrc^[lZOffset+lYOffset+lXPos]];//+1 Mac??? end; //for each Y end; //for each Z {$IFDEF ENDIAN_BIG} lPixel := random(255); //fixes strange PPC compiler bug where lS value in DrawCor is corrupted //bug only seen in Lazarus IDE {$ENDIF} end; procedure DrawCor (lSlice,lMultiSlice: integer); var lBGQuadP, lOverlayQuadP, l2ndOverlayQuadP: RGBQuadp; lOverlay,lnOverlay, lYOffset, lX,lY,lZ,lS,lXYSliceSz,lXZSliceSz: longint; lBG0Clr,lOverlay0Clr: DWord; begin lX := round(gBGImg.ScrnDim[1]); lY := round(gBGImg.ScrnDim[2]); lZ := round(gBGImg.ScrnDim[3]); lS := round(lSlice); lXYSliceSz := (lX*lY); lXZSliceSz := (lX*lZ); lYOffset := (lX) * (lS-1); if (lS > lY) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems=0)or (lS < 1 {999+}) or (lXYSliceSz < 1) then exit; if (lZ < 2) then begin SetDimension32(1,1, nil, gBGImg, ImgForm.PGImageSag, ImgForm.TriplePanel); //these do not work when image is stretched //ImgForm.PGImage3.Width := 1; //ImgForm.PGImage3.Height := 1; exit; end; GetMem ( lBGQuadP , (lXZSliceSz*4)); //imgform.caption := inttostr(lS)+'x666'; CreateCor(gMRIcroOverlay[kBGOverlayNum], lX,lYOffset,lZ,lXYSliceSz, lBGQuadP); //next: overlays lnOverlay := 0; //imgform.caption := inttostr(lS)+'x666'; lBG0Clr:= DWord(gMRIcroOverlay[1].LUTinvisible);//just to avoid compiler warning hint - never used... for lOverlay := knMaxOverlay downto 1 do begin if gMRIcroOverlay[lOverlay].ScrnBufferItems > 0 then begin inc(lnOverlay); if lnOverlay = 1 then begin //top overlay GetMem ( lOverlayQuadP , lXZSliceSz*4); lBG0Clr:= DWord(gMRIcroOverlay[lOverlay].LUTinvisible); CreateCor(gMRIcroOverlay[lOverlay], lX,lYOffset,lZ,lXYSliceSz, lOverlayQuadP); end else begin //2nd or lower overlay if lnOverlay = 2 then //2nd overlay GetMem ( l2ndOverlayQuadP , lXZSliceSz*4); CreateCor(gMRIcroOverlay[lOverlay], lX,lYOffset,lZ,lXYSliceSz, l2ndOverlayQuadP); lOverlay0Clr:= DWord(gMRIcroOverlay[lOverlay].LUTinvisible); AlphaBlend32(lOverlayQuadP,l2ndOverlayQuadP, lBG0Clr,lOverlay0Clr, lXZSliceSz,gBGImg.OverlayTransPct); end; //2nd overlay or more end; //overlay loaded end; //for knOverlay..1 //Finally: draw overlays on BG if lnOverlay > 0 then begin lOverlay0Clr := lBG0Clr; lBG0Clr := 0;//0=impossible, no alpha DWord(lHdr.LUTinvisible); if lnOverlay > 1 then FreeMem ( l2ndOverlayQuadP); AlphaBlend32(lBGQuadP,lOverlayQuadP, lBG0Clr,lOverlay0Clr, lXZSliceSz,gBGImg.BGTransPct); FreeMem ( lOverlayQuadP); end; //draw image if lMultiSlice >= 0 then PasteDimension32(lZ,lX, lBGQuadP,lMultiSlice)// MultiSliceForm.MultiImage,lMultiSlice) else begin SetDimension32(lZ,lX, lBGQuadP, gBGImg,ImgForm.PGImageCor, ImgForm.TriplePanel); if {ImgForm.XBarBtn.Down}gBGImg.XBarVisible then begin DrawXBar ( round(gBGImg.XViewCenter), round({lZ-}gBGImg.ZViewCenter),ImgForm.PGImageCor); DrawLabel(ImgForm.PGImageCor, DimToMMx(2),-1,-1); if gBGImg.KnownAlignment then begin DrawTextLabel(ImgForm.PGImageCor,gBGImg.MaxChar[3]{'S'},MaxInt,-1); if gBGImg.Mirror then DrawTextLabelV(ImgForm.PGImageCor,gBGImg.MaxChar[1]{'R'}) else DrawTextLabelV(ImgForm.PGImageCor,gBGImg.MinChar[1]{'L'}); end; end; //XBar end; FreeMem ( lBGQuadP); end; procedure CreateAxial(var lHdr: TMRIcroHdr; lStart,lSliceSz: Integer; var lQuadP: RGBQuadp); var lSrc: Bytep; lPixel: integer; begin lSrc := lHdr.ScrnBuffer; for lPixel := 1 to lSliceSz do lQuadP^[lPixel]:=lHdr.LUT[lSrc^[lStart+lPixel]]; //abba lQuadP^[200]:=lHdr.LUT[255]; end; procedure FlipSlice (lY,lX: integer; lImage: RGBQuadp); var lRowData: RGBQuadp; lYi,lHalfY,lRowBytes,lTop,lBottom: integer; begin if lY < 2 then exit; lRowBytes := lX * 4; getmem(lRowData,lRowBytes); lHalfY := lY div 2; lTop := 1; lBottom := ((lY-1)*lX)+1; for lYi := 1 to lHalfY do begin Move(lImage^[lTop],lRowData^[1],lRowBytes); Move(lImage^[lBottom],lImage^[lTop],lRowBytes); Move(lRowData^[1],lImage^[lBottom],lRowBytes); lTop := lTop + lX; lBottom := lBottom - lX; end; freemem(lRowData); end; procedure DrawAxial (lSlice,lMultiSlice: integer); var lBGQuadP, lOverlayQuadP, l2ndOverlayQuadP: RGBQuadp; lnOverlay,lOverlay, lX,lY,lS,lStart,lSliceSz: longint; lBG0Clr,lOverlay0Clr: DWord; begin lX := round(gBGImg.ScrnDim[1]); lY := round(gBGImg.ScrnDim[2]); lS := round(lSlice{ImgForm.ZViewEdit.value}); lSliceSz := (lX * lY{*lByte}); lStart := lX*lY*(lS-1); if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems=0)or (lS < 0) or (lX < 2) or (lStart < 0) or (lSliceSz < 1) or ((lStart+lSliceSz-1) > gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems) then exit; GetMem ( lBGQuadP, lSliceSz*4); CreateAxial(gMRIcroOverlay[kBGOverlayNum], lStart,lSliceSz, lBGQuadP); //next: overlays lnOverlay := 0; lBG0Clr:= DWord(gMRIcroOverlay[1].LUTinvisible);//just to avoid compiler warning hint - never used... for lOverlay := knMaxOverlay downto 1 do begin if gMRIcroOverlay[lOverlay].ScrnBufferItems > 0 then begin inc(lnOverlay); if lnOverlay = 1 then begin //top overlay GetMem ( lOverlayQuadP , lSliceSz*4); lBG0Clr:= DWord(gMRIcroOverlay[lOverlay].LUTinvisible); CreateAxial(gMRIcroOverlay[lOverlay], lStart,lSliceSz,lOverlayQuadP); end else begin //2nd or lower overlay if lnOverlay = 2 then //2nd overlay GetMem ( l2ndOverlayQuadP , lSliceSz*4); CreateAxial(gMRIcroOverlay[lOverlay], lStart,lSliceSz,l2ndOverlayQuadP); lOverlay0Clr:= DWord(gMRIcroOverlay[lOverlay].LUTinvisible); AlphaBlend32(lOverlayQuadP,l2ndOverlayQuadP, lBG0Clr,lOverlay0Clr, lSliceSz,gBGImg.OverlayTransPct); end; //2nd overlay or more end; //overlay loaded end; //for knOverlay..1 //Finally: draw overlays on BG if lnOverlay > 0 then begin lOverlay0Clr := lBG0Clr; lBG0Clr := 0;//0=impossible, no alpha DWord(lHdr.LUT[0]); if lnOverlay > 1 then FreeMem ( l2ndOverlayQuadP); AlphaBlend32(lBGQuadP,lOverlayQuadP, lBG0Clr,lOverlay0Clr, lSliceSz,gBGImg.BGTransPct); FreeMem ( lOverlayQuadP); end; //draw image if gBGImg.FlipAx then FlipSlice (lY,lX, lBGQuadP); if lMultiSlice >= 0 then PasteDimension32(lY,lX, lBGQuadP, lMultislice)//MultiSliceForm.MultiImage,lMultiSlice) else begin SetDimension32(lY,lX, lBGQuadP, gBGImg, ImgForm.PGImageAx, ImgForm.TriplePanel); if {ImgForm.XBarBtn.Down}gBGImg.XBarVisible then begin if gBGImg.FlipAx then lS := round(lY-gBGImg.YViewCenter) else lS := round(gBGImg.YViewCenter); DrawXBar ( round(gBGImg.XViewCenter), lS{round(gBGImg.YViewCenter)},ImgForm.PGImageAx); DrawLabel(ImgForm.PGImageAx, DimToMMx(3),-1,-1); if gBGImg.KnownAlignment then begin DrawTextLabel(ImgForm.PGImageAx,gBGImg.MaxChar[2]{'A'},MaxInt,-1); if gBGImg.Mirror then DrawTextLabelV(ImgForm.PGImageAx,gBGImg.MaxChar[1]{'R'}) else DrawTextLabelV(ImgForm.PGImageAx,gBGImg.MinChar[1]{'L'}); end; end; //XBar end; FreeMem ( lBGQuadP); end; //DrawAxial procedure DrawAxialCore (lSlice: integer; var lBGQuadP: RGBQuadp); var lOverlayQuadP, l2ndOverlayQuadP: RGBQuadp; lnOverlay,lOverlay, lX,lY,lS,lStart,lSliceSz: longint; lBG0Clr,lOverlay0Clr: DWord; begin lX := round(gBGImg.ScrnDim[1]); lY := round(gBGImg.ScrnDim[2]); lS := round(lSlice{ImgForm.ZViewEdit.value}); lSliceSz := (lX * lY{*lByte}); lStart := lX*lY*(lS-1); if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems=0)or (lS < 0) or (lX < 2) or (lStart < 0) or (lSliceSz < 1) or ((lStart+lSliceSz-1) > gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems) then exit; CreateAxial(gMRIcroOverlay[kBGOverlayNum], lStart,lSliceSz, lBGQuadP); //next: overlays lnOverlay := 0; lBG0Clr:= DWord(gMRIcroOverlay[1].LUTinvisible);//just to avoid compiler warning hint - never used... for lOverlay := knMaxOverlay downto 1 do begin if gMRIcroOverlay[lOverlay].ScrnBufferItems > 0 then begin inc(lnOverlay); if lnOverlay = 1 then begin //top overlay GetMem ( lOverlayQuadP , lSliceSz*4); lBG0Clr:= DWord(gMRIcroOverlay[lOverlay].LUTinvisible); CreateAxial(gMRIcroOverlay[lOverlay], lStart,lSliceSz,lOverlayQuadP); end else begin //2nd or lower overlay if lnOverlay = 2 then //2nd overlay GetMem ( l2ndOverlayQuadP , lSliceSz*4); CreateAxial(gMRIcroOverlay[lOverlay], lStart,lSliceSz,l2ndOverlayQuadP); lOverlay0Clr:= DWord(gMRIcroOverlay[lOverlay].LUTinvisible); AlphaBlend32(lOverlayQuadP,l2ndOverlayQuadP, lBG0Clr,lOverlay0Clr, lSliceSz,gBGImg.OverlayTransPct); end; //2nd overlay or more end; //overlay loaded end; //for knOverlay..1 //Finally: draw overlays on BG if lnOverlay > 0 then begin lOverlay0Clr := lBG0Clr; lBG0Clr := 0;//0=impossible, no alpha DWord(lHdr.LUT[0]); if lnOverlay > 1 then FreeMem ( l2ndOverlayQuadP); AlphaBlend32(lBGQuadP,lOverlayQuadP, lBG0Clr,lOverlay0Clr, lSliceSz,gBGImg.BGTransPct); FreeMem ( lOverlayQuadP); end; end; //DrawAxialCore procedure SegmentRGBplanes (lSlice,lXVox,lYVox: integer; var lSliceQuadP: RGBQuadp; var lImg3: bytep); //analyze RGB saves data as red, green blue planes var lLineOffset,lHalfX,lX,lY,lPos,lOutStart,lSliceVox: integer; lTempQuadP: TRGBQuad; begin lSliceVox := lXVox*lYVox; if lSliceVox < 1 then exit; if (ImgForm.FlipLRmenu.checked) and (lXVox > 1) then begin //showmessage('Flip'); lHalfX := lXVox div 2; lLineOffset := 0; for lY := 1 to lYVox do begin for lX := 1 to lHalfX do begin lTempQuadP := lSliceQuadP^[lX+lLineOffset]; lSliceQuadP^[lX+lLineOffset] := lSliceQuadP^[1+lXVox-lX+lLineOffset]; lSliceQuadP^[1+lXVox-lX+lLineOffset] := lTempQuadP; end; //for X lLineOffset := lLineOffset + lXVox; end;//lY end; //mirror lOutStart := (lSlice-1)*lSliceVox*3; for lPos := 1 to lSliceVox do begin lImg3^[lPos+lOutStart] := lSliceQuadP^[lPos].rgbRed; lImg3^[lPos+lOutStart+lSliceVox] := lSliceQuadP^[lPos].rgbGreen; lImg3^[lPos+lOutStart+lSliceVox+lSliceVox] := lSliceQuadP^[lPos].rgbBlue; end; end; procedure CreateAnaRGB; var lFilename: string; lImg3: bytep; lSliceQuadP: RGBQuadp; lVolVox,lX,lY,lZ,lI,lnSlice: integer; begin ImgForm.SaveDialog1.Filter := 'NIfTI compressed (.nii.gz)|*.nii.gz|NIfTI (.nii)|*.nii|NIfTI (.hdr/.img)|*.hdr|Volume of Interest(.voi)|*.voi|MRIcro (.roi)|*.roi'; ImgForm.SaveDialog1.DefaultExt := '.hdr'; ImgForm.SaveDialog1.Filename := ChangeFileExt(ImgForm.SaveDialog1.Filename, ImgForm.SaveDialog1.DefaultExt); //10102006 if not ImgForm.SaveDialog1.Execute then exit; lFilename := ImgForm.SaveDialog1.Filename; lX := round(gBGImg.ScrnDim[1]); lY := round(gBGImg.ScrnDim[2]); lZ := round(gBGImg.ScrnDim[3]); lVolVox := lX*lY*lZ ; if DiskFreeEx(lFilename) < (lVolVox*3) then begin case MessageDlg('Very little space on the selected drive. Attempt to save to this disk?', mtConfirmation, [mbYes, mbCancel], 0) of mrCancel: exit; end; //case end; getmem(lImg3, lVolVox* 3) ; //for Sag lnSlice := lZ; //fx(lX,lY,lZ); getmem(lSliceQuadP, lX*lY* sizeof(TRGBQuad)) ; for lI := 1 to lnSlice do begin //[1+ ((lI-1)*lSliceBytes)] DrawAxialCore (lI,lSliceQuadP ); SegmentRGBplanes (lI,lX,lY,lSliceQuadP,lImg3); end; freemem(lSliceQuadP); //output data SaveAsVOIorNIFTIcore (lFilename, lImg3, lVolVox, 3,1, gMRIcroOverlay[kBGOverlayNum].NiftiHdr); freemem(lImg3); end; procedure ComputeTripleZoom; //computes axial, coronal and sagittal zoom //values are SHL 10, so a 1% signal change will be 1024 //this preserves precision (though at the moment we round to nearest 1%) label 543,641; //const // kSHval = 1 shl 10; procedure SetPct(lAfrac,lCfrac,lSfrac: single); begin ImgForm.PGImageAx.Tag := trunc(lAfrac*100); ImgForm.PGImageCor.Tag := trunc(lCfrac*100) ; ImgForm.PGImageSag.Tag := trunc(lSfrac*100) ; end; var lHpanel,lWpanel,lH,lW: integer; lPrimaryZoom,l2ndZoom,lZoomw,lZoomh: single; begin SetPct(1,1,1); lHpanel := ImgForm.TriplePanel.ClientHeight-1; lWpanel := ImgForm.TriplePanel.ClientWidth-1; //gBGImg.ZoomPct := (ZoomDrop.ItemIndex-1)*100; if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems=0 then exit; if gBGImg.ZoomPct > 0 then begin SetPct(gBGImg.ZoomPct/100,gBGImg.ZoomPct/100,gBGImg.ZoomPct/100); lPrimaryZoom := ImgForm.PGImageAx.Tag/100; if abs(gBGImg.SliceView) <> kSagView0 then lW := gBGImg.ScrnDim[1] //Axial and Coronal width is X else lW := gBGImg.ScrnDim[2]; //Sagittal width is Y goto 543; exit; end; if (abs(gBGImg.SliceView) = kAxView0) or(abs(gBGImg.SliceView) = kCoroView0) or(abs(gBGImg.SliceView) = kSagView0) then begin //only show a single slice if abs(gBGImg.SliceView) <> kAxView0 then lH := gBGImg.ScrnDim[3] //Coronal and Sagitall height is Z else lH := gBGImg.ScrnDim[2]; //Axial height is Y if abs(gBGImg.SliceView) <> kSagView0 then lW := gBGImg.ScrnDim[1] //Axial and Coronal width is X else lW := gBGImg.ScrnDim[2]; //Sagittal width is Y lH := lH+1; lW := lW + 1; end else if gBGImg.SingleRow then begin //show 3 slices in row lW := gBGImg.ScrnDim[2]+gBGImg.ScrnDim[1]+gBGImg.ScrnDim[1]; lWpanel := lWpanel-2- (2*gBGImg.ImageSeparation); if gBGImg.ScrnDim[2]>gBGImg.ScrnDim[3] then lH := gBGImg.ScrnDim[2]+1 else lH := gBGImg.ScrnDim[3]+1 end else begin //show three slices, 2 in top row, one in bottom lW := gBGImg.ScrnDim[1]+gBGImg.ScrnDim[2]+4; lWpanel := lWpanel - 1 - gBGImg.ImageSeparation; lH := gBGImg.ScrnDim[3]+gBGImg.ScrnDim[2]+4; lHpanel := lHpanel - 1 - gBGImg.ImageSeparation; end; if (lW<1) or (lH < 1) or (lHpanel < 1) or (lWpanel < 1) then exit; lZoomw := lWpanel/ lW; lZoomh := lHpanel/ lH; if lZoomw < lZoomh then lPrimaryZoom := lZoomw else lPrimaryZoom := lZoomh; if (gBGImg.ZoomPct = 0) then begin//nearest integer lPrimaryZoom := trunc(lPrimaryZoom); if lPrimaryZoom < 1 then lPrimaryZoom := 1; end; SetPct(lPrimaryZoom,lPrimaryZoom,lPrimaryZoom); 543: //for single slice views, set residual ... if gBGImg.SliceView = kMultiView then exit;//All orientations use primary zoom if gBGImg.SliceView < 0 then begin l2ndZoom := 0; goto 641; end; lWpanel := lWpanel-2- (2*gBGImg.ImageSeparation); //see if we can fit in two more images horizontally //note all images are currently set to primary zooom, so we will read PGImageAx lWpanel := lWPanel - round(lW*lPrimaryZoom); l2ndZoom := 0; if lWpanel < 3 then goto 641; if (abs(gBGImg.SliceView) = kAxView0) then lW := gBGImg.ScrnDim[1]+gBGImg.ScrnDim[2] //CorX + SagY else if (abs(gBGImg.SliceView) = kCoroView0) then lW := gBGImg.ScrnDim[1]+gBGImg.ScrnDim[2] //AxX + SagY else //(gBGImg.SliceView = kSagView) lW := gBGImg.ScrnDim[1]+gBGImg.ScrnDim[1];//AxX+CorX if lW < 1 then //avoid div0 lZoomw := 0 else lZoomw := lWpanel/ lW; if gBGImg.ScrnDim[2] > gBGImg.ScrnDim[3] then lH := gBGImg.ScrnDim[2] else lH := gBGImg.ScrnDim[3]; if lH < 1 then //avoid div0 lZoomh := 0 else lZoomh := lHpanel/ lH; if lZoomw < lZoomh then l2ndZoom := lZoomw else l2ndZoom := lZoomh; 641: if (abs(gBGImg.SliceView) = kAxView0) then SetPct(lPrimaryZoom,l2ndZoom,l2ndZoom) else if (abs(gBGImg.SliceView) = kCoroView0) then SetPct(l2ndZoom,lPrimaryZoom,l2ndZoom) else //(gBGImg.SliceView = kSagView) SetPct(l2ndZoom,l2ndZoom,lPrimaryZoom); end; (*function ComputeTripleZoom : single; var lHc,lWc,lH,lW: integer; lZw,lZh: single; begin result := 1; lHc := ImgForm.TriplePanel.ClientHeight-1; lWc := ImgForm.TriplePanel.ClientWidth-1; //gBGImg.ZoomPct := (ZoomDrop.ItemIndex-1)*100; if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems=0 then exit; if gBGImg.ZoomPct > 0 then begin result := gBGImg.ZoomPct / 100; exit; end; if (gBGImg.SliceView = kAxView) or(gBGImg.SliceView = kCoroView) or(gBGImg.SliceView = kSagView) then begin //only show a single slice case gBGImg.SliceView of kSagView: lH := gBGImg.ScrnDim[3]; kCoroView: lH := gBGImg.ScrnDim[3]; else lH := gBGImg.ScrnDim[2]; end;//case case gBGImg.SliceView of kSagView: lW := gBGImg.ScrnDim[2]; kCoroView: lW := gBGImg.ScrnDim[1]; else lW := gBGImg.ScrnDim[1]; end;//case lH := lH+1; lW := lW + 1; end else if gBGImg.SingleRow then begin //show 3 slices in row lW := gBGImg.ScrnDim[2]+gBGImg.ScrnDim[1]+gBGImg.ScrnDim[1]; lWc := lWc-2- (2*gBGImg.ImageSeparation); if gBGImg.ScrnDim[2]>gBGImg.ScrnDim[3] then lH := gBGImg.ScrnDim[2]+1 else lH := gBGImg.ScrnDim[3]+1 end else begin //show three slices, 2 in top row, one in bottom lW := gBGImg.ScrnDim[1]+gBGImg.ScrnDim[2]+4; lWc := lWc - 1 - gBGImg.ImageSeparation; lH := gBGImg.ScrnDim[3]+gBGImg.ScrnDim[2]+4; lHc := lHc - 1 - gBGImg.ImageSeparation; end; if (lW<1) or (lH < 1) or (lHc < 1) or (lWc < 1) then exit; lZw := lWc/ lW; lZh := lHc/ lH; if lZw < lZh then result := lZw else result := lZh; if (gBGImg.ZoomPct = 0) then begin//nearest integer result := trunc(result); if result < 1 then result := 1; end; end; *) procedure ImageLT (lLScroll,lTScroll,lL,lT: integer; var lImage: TImage); begin //if (lImage.Left = lL) and (lImage.Top = lT) then // exit; ImgForm.Caption := 'a'+inttostr(lL)+'x'+inttostr(lT)+'debug'+inttostr(lImage.Left)+'x'+inttostr(lImage.Top); //if lImage.Left <> lL then lImage.Left := lL-lLScroll; //if lImage.Top <> lT then lImage.Top := lT-lTScroll; end; procedure RefreshImages; var lL,lT: integer; begin if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems=0 then begin ImgForm.PGImageAx.Width := 0; ImgForm.PGImageSag.Width := 0; ImgForm.PGImageCor.Width := 0; exit; end; {$IFDEF FPC} lL := 0; lT := 0; {$ELSE} lL := imgForm.Triplepanel.HorzScrollBar.Position; lT := imgForm.Triplepanel.VertScrollBar.Position; {$ENDIF} //imgform.Caption := inttostr(lL)+'x'+inttostr(lT); ComputeTripleZoom; ImgForm.PGImageAx.visible := ImgForm.PGImageAx.tag <> 0; ImgForm.PGImageCor.visible := ImgForm.PGImageCor.tag <> 0; ImgForm.PGImageSag.visible := ImgForm.PGImageSag.tag <> 0; if (gBGImg.SliceView = kMultiView) and (not gBGImg.SingleRow) then begin //Coronal is upper-left ImageLT(lL,lT,1,1,ImgForm.PGImageCor); //Axial is below Coronal ImageLT(lL,lT,1,round(gBGImg.ScrnDim[3]*ImgForm.PGImageCor.Tag/100)+gBGImg.ImageSeparation+1,ImgForm.PGImageAx); //Sag is to right of coronal ImageLT(lL,lT,round(gBGImg.ScrnDim[1]*ImgForm.PGImageCor.Tag/100)+gBGImg.ImageSeparation+1,1,ImgForm.PGImageSag); end else begin //Sag is left-most ImageLT(lL,lT,1,1,ImgForm.PGImageSag); //Next is coronal... ImageLT(lL,lT,round(gBGImg.ScrnDim[2]*ImgForm.PGImageSag.Tag/100)+gBGImg.ImageSeparation+1,1,ImgForm.PGImageCor); //Axial is rightmost ImageLT(lL,lT,round(gBGImg.ScrnDim[2]*ImgForm.PGImageSag.Tag/100)+round(gBGImg.ScrnDim[1]*ImgForm.PGImageCor.Tag/100)+gBGImg.ImageSeparation+gBGImg.ImageSeparation+1,1,ImgForm.PGImageAx); end; (* //Coronal is upper-left ImageLT(lL,lT,1,1,ImgForm.PGImageCor); //Axial is below Coronal ImageLT(lL,lT,1,round(gBGImg.ScrnDim[3]*ImgForm.PGImageCor.Tag/100)+gBGImg.ImageSeparation+1,ImgForm.PGImageAx); //Sag is to right of coronal ImageLT(lL,lT,round(gBGImg.ScrnDim[1]*ImgForm.PGImageCor.Tag/100)+gBGImg.ImageSeparation+1,1,ImgForm.PGImageCor); ImgForm.PGImageAx.visible := true; ImgForm.PGImageCor.visible := true; ImgForm.PGImageSag.visible := true; end; if (gBGImg.SliceView = kAxView) or(gBGImg.SliceView = kCoroView) or(gBGImg.SliceView = kSagView) then begin //only show a single slice if (gBGImg.SliceView = kAxView) then begin ImageLT(lL,lT,1,1,ImgForm.PGImageAx); ImgForm.PGImageAx.visible := true; ImgForm.PGImageCor.visible := false; ImgForm.PGImageSag.visible := false; end; if (gBGImg.SliceView = kCoroView) then begin ImageLT(lL,lT,1,1,ImgForm.PGImageCor); ImgForm.PGImageAx.visible := false; ImgForm.PGImageCor.visible := true; ImgForm.PGImageSag.visible := false; end; if (gBGImg.SliceView = kSagView) then begin ImageLT(lL,lT,1,1,ImgForm.PGImageSag); ImgForm.PGImageAx.visible := false; ImgForm.PGImageCor.visible := false; ImgForm.PGImageSag.visible := true; end; end else if gBGImg.SingleRow then begin //Sag is left-most ImageLT(lL,lT,1,1,ImgForm.PGImageSag); //Next is coronal... ImageLT(lL,lT,round(gBGImg.ScrnDim[2]*ImgForm.PGImageSag.Tag/100)+gBGImg.ImageSeparation+1,1,ImgForm.PGImageCor); //Axial is rightmost ImageLT(lL,lT,round(gBGImg.ScrnDim[2]*ImgForm.PGImageSag.Tag/100)+round(gBGImg.ScrnDim[1]*ImgForm.PGImageCor.Tag/100)+gBGImg.ImageSeparation+gBGImg.ImageSeparation+1,1,ImgForm.PGImageAx); ImgForm.PGImageAx.visible := true; ImgForm.PGImageCor.visible := true; ImgForm.PGImageSag.visible := true; end else begin //Coronal is upper-left ImageLT(lL,lT,1,1,ImgForm.PGImageCor); //Axial is below Coronal ImageLT(lL,lT,1,round(gBGImg.ScrnDim[3]*ImgForm.PGImageCor.Tag/100)+gBGImg.ImageSeparation+1,ImgForm.PGImageAx); //Sag is to right of coronal ImageLT(lL,lT,round(gBGImg.ScrnDim[1]*ImgForm.PGImageCor.Tag/100)+gBGImg.ImageSeparation+1,1,ImgForm.PGImageCor); ImgForm.PGImageAx.visible := true; ImgForm.PGImageCor.visible := true; ImgForm.PGImageSag.visible := true; end; *) DrawAxial(round(gBGImg.ZViewCenter),-1); DrawSag (round(gBGImg.XViewCenter),-1); DrawCor (round(gBGImg.YViewCenter),-1); end; //RefreshImages (*procedure RefreshImages; begin if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems=0 then begin ImgForm.PGImageAx.Width := 0; ImgForm.PGImageSag.Width := 0; ImgForm.PGImageCor.Width := 0; exit; end; gTripleZoom100 := trunc(100*ComputeTripleZoom); if gTripleZoom100 < 1 then gTripleZOom100 := 1; if (gBGImg.SliceView = kAxView) or(gBGImg.SliceView = kCoroView) or(gBGImg.SliceView = kSagView) then begin //only show a single slice if (gBGImg.SliceView = kAxView) then begin ImgForm.PGImageAx.Top := 1; ImgForm.PGImageAx.Left := 1; ImgForm.PGImageAx.visible := true; ImgForm.PGImageCor.visible := false; ImgForm.PGImageSag.visible := false; end; if (gBGImg.SliceView = kCoroView) then begin ImgForm.PGImageCor.Top := 1; ImgForm.PGImageCor.Left := 1; ImgForm.PGImageAx.visible := false; ImgForm.PGImageCor.visible := true; ImgForm.PGImageSag.visible := false; end; if (gBGImg.SliceView = kSagView) then begin ImgForm.PGImageSag.Top := 1; ImgForm.PGImageSag.Left := 1; ImgForm.PGImageAx.visible := false; ImgForm.PGImageCor.visible := false; ImgForm.PGImageSag.visible := true; end; end else if gBGImg.SingleRow then begin ImgForm.PGImageCor.Left := round(gBGImg.ScrnDim[2]*gTripleZoom100/100)+gBGImg.ImageSeparation+1; ImgForm.PGImageCor.Top := 1; ImgForm.PGImageSag.Left := 1; ImgForm.PGImageSag.Top := 1; ImgForm.PGImageAx.Left := round(gBGImg.ScrnDim[1]*gTripleZoom100/100)+round(gBGImg.ScrnDim[2]*gTripleZoom100/100)+gBGImg.ImageSeparation+gBGImg.ImageSeparation+1; ImgForm.PGImageAx.Top := 1; ImgForm.PGImageAx.visible := true; ImgForm.PGImageCor.visible := true; ImgForm.PGImageSag.visible := true; end else begin ImgForm.PGImageCor.Left := 1; ImgForm.PGImageCor.Top := 1; ImgForm.PGImageSag.Left := round(gBGImg.ScrnDim[1]*gTripleZoom100/100)+gBGImg.ImageSeparation+1; ImgForm.PGImageSag.Top := 1; ImgForm.PGImageAx.Left := 1; ImgForm.PGImageAx.Top := round(gBGImg.ScrnDim[3]*gTripleZoom100/100)+gBGImg.ImageSeparation+1; ImgForm.PGImageAx.visible := true; ImgForm.PGImageCor.visible := true; ImgForm.PGImageSag.visible := true; end; DrawAxial(round(gBGImg.ZViewCenter),-1); DrawSag (round(gBGImg.XViewCenter),-1); DrawCor (round(gBGImg.YViewCenter),-1); end; //RefreshImages *) (*function ComputeTripleZoom : single; var lHc,lWc,lH,lW: integer; lZw,lZh: single; begin result := 1; lHc := ImgForm.TriplePanel.ClientHeight-1; lWc := ImgForm.TriplePanel.ClientWidth-1; //gBGImg.ZoomPct := (ZoomDrop.ItemIndex-1)*100; if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems=0 then exit; if gBGImg.ZoomPct > 0 then begin result := gBGImg.ZoomPct / 100; exit; end; if (gBGImg.SliceView = kAxView) or(gBGImg.SliceView = kCoroView) or(gBGImg.SliceView = kSagView) then begin //only show a single slice case gBGImg.SliceView of kSagView: lH := gBGImg.ScrnDim[3]; kCoroView: lH := gBGImg.ScrnDim[3]; else lH := gBGImg.ScrnDim[2]; end;//case case gBGImg.SliceView of kSagView: lW := gBGImg.ScrnDim[2]; kCoroView: lW := gBGImg.ScrnDim[1]; else lW := gBGImg.ScrnDim[1]; end;//case lH := lH+1; lW := lW + 1; end else if gBGImg.SingleRow then begin //show 3 slices in row lW := gBGImg.ScrnDim[2]+gBGImg.ScrnDim[1]+gBGImg.ScrnDim[1]; lWc := lWc-4; if gBGImg.ScrnDim[2]>gBGImg.ScrnDim[3] then lH := gBGImg.ScrnDim[2]+1 else lH := gBGImg.ScrnDim[3]+1 end else begin //show three slices, 2 in top row, one in bottom lW := gBGImg.ScrnDim[1]+gBGImg.ScrnDim[2]+4; lWc := lWc - 2; lH := gBGImg.ScrnDim[3]+gBGImg.ScrnDim[2]+4; lHc := lHc - 2; end; if (lW<1) or (lH < 1) or (lHc < 1) or (lWc < 1) then exit; lZw := lWc/ lW; lZh := lHc/ lH; if lZw < lZh then result := lZw else result := lZh; if (gBGImg.ZoomPct = 0) then begin//nearest integer result := trunc(result); if result < 1 then result := 1; end; end; procedure RefreshImages; //var // lZoom: single; begin if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems=0 then begin ImgForm.PGImageAx.Width := 0; ImgForm.PGImageSag.Width := 0; ImgForm.PGImageCor.Width := 0; //yui exit; end; gTripleZoom100 := trunc(100*ComputeTripleZoom); if gTripleZoom100 < 1 then gTripleZOom100 := 1; if (gBGImg.SliceView = kAxView) or(gBGImg.SliceView = kCoroView) or(gBGImg.SliceView = kSagView) then begin //only show a single slice if (gBGImg.SliceView = kAxView) then begin ImgForm.PGImageAx.Top := 1; ImgForm.PGImageAx.Left := 1; ImgForm.PGImageAx.visible := true; ImgForm.PGImageCor.visible := false; ImgForm.PGImageSag.visible := false; end; if (gBGImg.SliceView = kCoroView) then begin ImgForm.PGImageCor.Top := 1; ImgForm.PGImageCor.Left := 1; ImgForm.PGImageAx.visible := false; ImgForm.PGImageCor.visible := true; ImgForm.PGImageSag.visible := false; end; if (gBGImg.SliceView = kSagView) then begin ImgForm.PGImageSag.Top := 1; ImgForm.PGImageSag.Left := 1; ImgForm.PGImageAx.visible := false; ImgForm.PGImageCor.visible := false; ImgForm.PGImageSag.visible := true; end; end else if gBGImg.SingleRow then begin ImgForm.PGImageCor.Left := round(gBGImg.ScrnDim[2]*gTripleZoom100/100)+2; ImgForm.PGImageCor.Top := 1; ImgForm.PGImageSag.Left := 1; ImgForm.PGImageSag.Top := 1; ImgForm.PGImageAx.Left := round(gBGImg.ScrnDim[1]*gTripleZoom100/100)+round(gBGImg.ScrnDim[2]*gTripleZoom100/100)+3; ImgForm.PGImageAx.Top := 1; ImgForm.PGImageAx.visible := true; ImgForm.PGImageCor.visible := true; ImgForm.PGImageSag.visible := true; end else begin ImgForm.PGImageCor.Left := 1; ImgForm.PGImageCor.Top := 1; ImgForm.PGImageSag.Left := round(gBGImg.ScrnDim[1]*gTripleZoom100/100)+2; ImgForm.PGImageSag.Top := 1; ImgForm.PGImageAx.Left := 1; ImgForm.PGImageAx.Top := round(gBGImg.ScrnDim[3]*gTripleZoom100/100)+2; ImgForm.PGImageAx.visible := true; ImgForm.PGImageCor.visible := true; ImgForm.PGImageSag.visible := true; end; DrawAxial(round(gBGImg.ZViewCenter),-1); DrawSag (round(gBGImg.XViewCenter),-1); DrawCor (round(gBGImg.YViewCenter),-1); end; //RefreshImages *) {$IFNDEF FPC} function PNGFilterSize(lFilter: integer; lImage: TImage): integer; var lStream: TMemoryStream; lPNGFilters : TEncodeFilterSet; begin result := 0; if (lImage.Picture.Graphic = nil) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1) then begin Showmessage('You need to load an image before you can save it.'); exit; end; lStream := TMemoryStream.Create; try with TPNGImage.Create do begin //gPNGSaveFilters := []; case lFilter of 1: lPNGFilters := [efSub]; 2: lPNGFilters := [efUp]; 3: lPNGFilters := [efAverage]; 4: lPNGFilters := [efPaeth];//Include(SaveFilters, efPaeth); else lPNGFilters := [efNone];//[efNone,efSub,efUp,efAverage,efPaeth]; end; Filter := lPNGFilters; //filters(efNone, efSub, efUp, efAverage, efPaeth); Assign(lImage.Picture.Graphic); SaveToStream(lStream); result := (lStream.Size); end; finally lStream.Free; end; //Stream TRY..FINALLY end; procedure SaveImgAsPNGBMP (lImage: TImage); var lPNGFilter,lMinFilter,lMinFilterSz,lFilter,lSz: integer; lPNGFilters : TEncodeFilterSet; begin if (lImage.Picture.Graphic = nil) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1) then begin Showmessage('You need to load an image before you can save it.'); exit; end; ImgForm.SaveDialog1.Filename := parsefilename(gMRIcroOverlay[kBGOverlayNum].HdrFilename); ImgForm.SaveDialog1.Filter := 'PNG bitmap|*.png'; ImgForm.SaveDialog1.DefaultExt := '*.png'; if not ImgForm.SaveDialog1.Execute then exit; lPNGFilter := 5; if lPNGFilter = 5 then begin //find PNG filter for smallest filesize lMinFilter := 0; lMinFilterSz := PNGFilterSize(0,lImage); for lFilter := 1 to 4 do begin Application.ProcessMessages; lSz := PNGFilterSize(lFilter,lImage); if lSz < lMinFilterSz then begin lMinFilter := lFilter; lMinFilterSz := lSz; end; end; //Filter 1..4 try each filter end else lMinFilter := lPNGFilter; //if look for smallest filter case lMinFilter of 1: lPNGFilters := [efSub]; 2: lPNGFilters := [efUp]; 3: lPNGFilters := [efAverage]; 4: lPNGFilters := [efPaeth];//Include(SaveFilters, efPaeth); else lPNGFilters := [efNone];//[efNone,efSub,efUp,efAverage,efPaeth]; end; with TPNGImage.Create do begin //filters(efNone, efSub, efUp, efAverage, efPaeth); Filter := lPNGFilters; Assign(lImage.Picture.Bitmap); SaveToFile(ChangeFileExt(ImgForm.SaveDialog1.FileName,'.png')); free; end; end; {$ELSE} procedure SaveImgAsPNGCore (lImage: TBitmap; lFilename: string); var PNG: TPortableNetworkGraphic; begin if (lImage = nil) then begin Showmessage('No image found to save.'); exit; end; PNG := TPortableNetworkGraphic.Create; try PNG.Assign(lImage); //Convert data into png PNG.SaveToFile(ChangeFileExt(lFilename,'.png')); finally PNG.Free; end end; procedure SaveImgAsPNGBMP (lImage: TImage); begin if (lImage.Picture.Graphic = nil) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1) then begin Showmessage('You need to load an image before you can save it.'); exit; end; ImgForm.SaveDialog1.Filename := parsefilename(gMRIcroOverlay[kBGOverlayNum].HdrFilename); {$IFDEF ENDIAN_BIG} ImgForm.SaveDialog1.Filter := 'NG (*.png)|*.png;Bitmap|*.xpm'; ImgForm.SaveDialog1.DefaultExt := '.png'; {$ELSE} ImgForm.SaveDialog1.Filter := 'PNG (*.png)|*.png;Bitmap|*.bmp'; ImgForm.SaveDialog1.DefaultExt := '.png'; {$ENDIF} if not ImgForm.SaveDialog1.Execute then exit; //showmessage(ImgForm.SaveDialog1.FileName); if upcaseext(ImgForm.SaveDialog1.Filename)='.BMP' then lImage.Picture.Bitmap.SaveToFile(ImgForm.SaveDialog1.Filename) else SaveImgAsPNGCore(lImage.Picture.Bitmap,ImgForm.SaveDialog1.Filename); end; {$ENDIF} (*procedure SaveImgAsBMP (lImage: TImage); begin if (lImage.Picture.Graphic = nil) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1) then begin Showmessage('You need to load an image before you can save it.'); exit; end; ImgForm.SaveDialog1.Filename := parsefilename(gMRIcroOverlay[kBGOverlayNum].HdrFilename); ImgForm.SaveDialog1.Filter := 'Bitmap|*.bmp'; ImgForm.SaveDialog1.DefaultExt := '*.bmp'; if not ImgForm.SaveDialog1.Execute then exit; lImage.Picture.Bitmap.SaveToFile(ImgForm.SaveDialog1.Filename); end;*) procedure UndoVolVOI; var lTempBuf: ByteP; begin if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems < 1 then exit; if gBGImg.VOIUndoVolItems <> gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems then exit; GetMem(lTempBuf,gBGImg.VOIUndoVolItems); Move(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,lTempBuf^,gBGImg.VOIUndoVolItems); Move(gBGImg.VOIUndoVol^,gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,gBGImg.VOIUndoVolItems); Move(lTempBuf^,gBGImg.VOIUndoVol^,gBGImg.VOIUndoVolItems); FreeMem(lTempBuf); end; procedure FreeUndoVol; begin if gBGImg.VOIUndoVolItems > 0 then freemem(gBGImg.VOIUndoVol); gBGImg.VOIUndoVolItems := 0; if gBGImg.RenderDepthBufferItems > 0 then freemem(gBGImg.RenderDepthBuffer); gBGImg.RenderDepthBufferItems := 0; end; procedure CreateUndoVol; begin if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems < 1 then exit; gBGImg.VOIUndoSlice := 1; gBGImg.VOIUndoOrient := 4; if gBGImg.VOIUndoVolItems <> gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems then begin FreeUndoVol; gBGImg.VOIUndoVolItems := gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems; getmem(gBGImg.VOIUndoVol,gBGImg.VOIUndoVolItems); end; Move(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,gBGImg.VOIUndoVol^,gBGImg.VOIUndoVolItems); end; function IsVOIOpen: boolean; begin result := false; if (gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems = gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems) and (gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems > 0) then result := true; end; function SameAsBG(var lBGImg: TBGImg; var lHdr: TMRIcroHdr): boolean; var lMatrixBG: TMatrix; i, j: Integer; begin result := false; for i := 1 to 3 do //999 if lHdr.NIFTIhdr.dim[i] <>lBGImg.ScrnDim[i] then //999 exit; //999 lMatrixBG := Matrix3D ( lBGImg.Scrnmm[1],0,0,-lBGImg.Scrnmm[1]*(lBGImg.ScrnOri[1]-1), 0,lBGImg.Scrnmm[2],0,-lBGImg.Scrnmm[2]*(lBGImg.ScrnOri[2]-1), 0,0,lBGImg.Scrnmm[3],-lBGImg.Scrnmm[3]*(lBGImg.ScrnOri[3]-1), 0,0,0,1); for i := 1 to 3 do for j := 1 to 4 do begin if lMatrixBG.matrix[i,j] <> lHdr.Mat.matrix[i,j] then exit; end; //showmessage('same'); //for i := 1 to 3 do if (lBGIMg.ScrnDim[i])<>lHdr.NIFTIhdr.dim[i] then exit; result := true; end; procedure EnsureVOIOpen; var lMaxi: integer; begin if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems = gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems then exit; //showmessage(inttostr(gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems)); if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems > 0 then Freemem(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer); gMRIcroOverlay[kVOIOverlayNum].NIFTIhdr.dim[1] := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[1]; gMRIcroOverlay[kVOIOverlayNum].NIFTIhdr.dim[2] := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[2]; gMRIcroOverlay[kVOIOverlayNum].NIFTIhdr.dim[3] := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[3]; gMRIcroOverlay[kVOIOverlayNum].NIFTIhdr.pixdim[1] := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.pixdim[1]; gMRIcroOverlay[kVOIOverlayNum].NIFTIhdr.pixdim[2] := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.pixdim[2]; gMRIcroOverlay[kVOIOverlayNum].NIFTIhdr.pixdim[3] := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.pixdim[3]; gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems := gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems; gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems := gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems; Getmem(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer,gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems); fillchar(gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems,0); lMaxI := maxint; LoadMonochromeLUT(lMaxi,gBGImg,gMRIcroOverlay[kVOIOverlayNum]); if (gBGImg.Resliced) and (not SameAsBG(gBGImg,gMRIcroOverlay[kBGOverlayNum])) then //fv showmessage('Warning: you are about to draw a region of interest on an resliced image, which can problems with SPM and FSL. Solution: choose Help/Preferences and uncheck ''Reorient images when loading'', then reload your image.'); end; function SelectedImageNum: Integer; begin result := gSelectedImageNum; if (result < 1) or (result > 3) then result := 1; { with ImgForm do begin if TriplePanel.BorderStyle = bsSingle then result := 3 else if TriplePanel.BorderStyle = bsSingle then result := 2 else result := 1 end;} //with ImgForm end;//SelectedImageNum function ComputeInvZoomShl10(lSelectedImageNum: integer; var lImage: TImage): integer; const kSHval = 1 shl 10; var lPGWid,lImgWid: integer; begin result := kSHval;//100% lPGWid := lImage.Picture.Bitmap.Width; if lImage.Tag > 0 then begin result := round((100/lImage.Tag)*kShVal); exit; end; if lSelectedImageNum = 2 then lImgWid := gBGImg.ScrnDim[2] //Sag - horizontal is Y else lImgWid := gBGImg.ScrnDim[1]; //cor and ax - horizontal is X If (lPGWid < 1) or (lImgWid < 1) then exit; result := round(lImgWid/lPGWid* kShVal); end; function ComputeZoomPct(lSelectedImageNum: integer; var lImage: TImage): integer; var lPGWid,lImgWid: integer; begin result := 100;//100% lPGWid := lImage.Picture.Bitmap.Width; if lImage.Tag > 0 then begin result := lImage.Tag; exit; end; if lSelectedImageNum = 2 then lImgWid := gBGImg.ScrnDim[2] //Sag - horizontal is Y else lImgWid := gBGImg.ScrnDim[1]; //cor and ax - horizontal is X If (lPGWid < 1) or (lImgWid < 1) then exit; result := round(lPGWid/lImgWid* 100); end; //ComputeZoomPct procedure ScaleBMP2Draw (var InvZoomShl10,lX, lY, lPanel: integer; lImage: TImage); begin //lScaleShl10 := ComputeInvZoomShl10(SelectedImageNum,lImage); //ImgForm.StatusLabel.Caption := inttostr(InvZoomShl10); {$IFNDEF Darwin} please check if next line required for this OS! 8/8/2014 {$ENDIF} lX := lX -1; if (gBGImg.FlipSag) and (lPanel = 2) then lX := ((lImage.Width-lX) * InvZoomShl10) shr 10 else if (lX < 1) then lX := 0 else lX := (lX * InvZoomShl10) shr 10; if (gBGImg.FlipAx) and (lPanel = 1) then lY := ((lImage.Height-lY) * InvZoomShl10) shr 10 else if (lY < 1) then lY := 0 else lY := (lY * InvZoomShl10) shr 10; end; function ImageZoomPct( var lImage: TImage): integer; begin result := ComputeZoomPct(SelectedImageNum,lImage); end; procedure DrawXBar ( lHorPos, lVerPos: integer;var lImage: TImage); var lL,lT,lW,lH,lZoomPct: integer; lOffset: single; begin lZoomPct := ImageZoomPct(lImage); //amx - must match XYscrn2Img and DrawXBar lW := lImage.Width;// div 100; lH := lImage.Height;// div 100; //lL := lHorPos-1; if lZoomPct > 100 then lOffset := 0.5 else lOffset := 0; lL := round((lHorPos-lOffset) * lZoomPct/100)-1;// div 100; //-1 as indexed from zero, 0.5 for middle of slice lT := lH-round((lVerPos-lOffset) * lZoomPct/100);// div 100; //ImgForm.Caption := inttostr(lZoomPct); //lL := (lHorPos * lZoomPct) div 100; //lT := (lVerPos * lZoomPct) div 100; lImage.Canvas.Pen.Color:=gBGImg.XBarClr; //lImage.Canvas.Pen.Color:=$03FF0000; lImage.Canvas.Pen.Width := gBGImg.XBarThick; //next horizontal lines lImage.Canvas.MoveTo(0,lT); lImage.Canvas.LineTo(lL-gBGImg.XBarGap,lT); lImage.Canvas.MoveTo(lL+gBGImg.XBarGap,lT); lImage.Canvas.LineTo(lW,lT); //next vertical lines lImage.Canvas.MoveTo(lL,0); lImage.Canvas.LineTo(lL,lT-gBGImg.XBarGap); lImage.Canvas.MoveTo(lL,lT+gBGImg.XBarGap); lImage.Canvas.LineTo(lL,lH); end; //Proc DrawXBar procedure ScaleScrn2BMP (var lX, lY: integer;lImage: TImage); var lScale: single; begin if (lImage.Height = 0) or (lImage.Width = 0) then exit; lScale := lImage.Picture.Bitmap.Height /lImage.Height; lX := round(lX * lScale); lY := round(lY * lScale); end; function Scrn2ScaledIntensity (lHdr: TMRIcroHdr; lRaw: single): single; var lRange,lMin,lMax: single; begin lMin := lHdr.WindowScaledMin; lMax := lHdr.WindowScaledMax; if lMin > lMax then begin lRange := lMin; lMin := lMax; lMax := lRange; end; lRange := lMax - lMin; result := lMin+(lRaw/255*lRange); end; procedure SaveMRIcroROI (lFilename: string); const kMax12bit = 4095; kMax16bit = (256*256)-1; kMax20bit = (16*256*256)-1; k20v16bit = kMax20bit - kMax16bit; kMaxRuns = 10000; kMaxFile = 65536; var lFilePos,lZPos,lZ,lSliceSz,lSliceOffset,lPrevVoxel,lVoxel,lRun,lnRuns,lSlicePos: integer; lRunStartRA,lRunLengthRA : array [1..kMaxRuns] of longint; lOutputRA: array [1..kMaxFile] of word; lF: File; lBigFormat: boolean; begin lSliceSz := gBGImg.ScrnDim[1]*gBGImg.ScrnDim[2]; lZ := gBGImg.ScrnDim[3]; if lSliceSz > 65535 then lBigFormat := true else lBigFormat := false; if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems<> (lSLiceSz*lZ) then begin Showmessage('You need to create a VOI before you can save it.'); exit; end; lSliceOffset := 0; lFilePos := 0; for lZPos := 1 to lZ do begin lnRuns := 0; lPrevVoxel := 0; for lSlicePos := 1 to lSliceSz do begin lVoxel := gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lSlicePos+lSliceOffset]; if lVoxel > 1 then lVoxel := 1; if lVoxel <> lPrevVoxel then begin //start or end run lPrevVoxel := lVoxel; if lnRuns = kMaxRuns then Showmessage('Error: To many runs...') else if lVoxel = 1 then begin //start new run inc(lnRuns); lRunStartRA[lnRuns] := lSlicePos; end else begin lRunLengthRA[lnRuns] := lSlicePos-lRunStartRA[lnRuns]; end; end; //if start or end if (lVoxel > 0) and ((lSlicePos-lRunStartRA[lnRuns])>4090) then begin //end this run, begin new lRunLengthRA[lnRuns] := lSlicePos-lRunStartRA[lnRuns]+1; lPrevVoxel := 0; end; //run >4090 end; //for each voxel in slice if lPrevVoxel = 1 then lRunLengthRA[lnRuns] := lSliceSz-lRunStartRA[lnRuns]+1; lSliceOffset := lSliceOffset+lSliceSz; if lnRuns > 0 then begin inc(lFilePos); lOutputRA[lFilePos] := lZPos; //record slice number inc(lFilePos); lOutputRA[lFilePos] := 2*(lnRuns+1); //words to store this slice: 2 per run, plus 2 for slice number and size if lBigFormat then begin for lRun := 1 to lnRuns do begin inc(lFilePos); lOutputRA[lFilePos] := (lRunStartRA[lRun] and kMax16bit); //record slice number inc(lFilePos); lOutputRA[lFilePos] := (lRunLengthRA[lRun] and kMax12bit)+ ((lRunStartRA[lRun] and k20v16bit)shr 4) ; //record slice number end; end else begin for lRun := 1 to lnRuns do begin inc(lFilePos); lOutputRA[lFilePos] := lRunStartRA[lRun]; //record slice number inc(lFilePos); lOutputRA[lFilePos] := lRunLengthRA[lRun]; //record slice number end;//for each run end; //small format end; //if data on this slice end; //for lZ if lFilePos = 0 then begin Showmessage('No VOIs detected - unable to create blank MRIcro ROI.'); exit; end; if lBigFormat then lOutputRA[1] := lOutputRA[1]+ 32768; //set MSB to 1 to denote this file uses 12/20 bytes Filemode := 1; AssignFile(lF, lFileName); {WIN} Rewrite(lF,lFilePos*2); BlockWrite(lF,lOutputRA, 1 {, NumWritten}); CloseFile(lF); Filemode := 2; end; procedure SaveAsVOIorNIFTIinnercore (var lFilename: string; var lImgBuffer: ByteP; lImgBufferItems, lImgBufferBPP,lnVol: integer; var lNiftiHdr: TNIFTIHdr); const kImgOffset = 352; //header is 348 bytes, but 352 is divisible by 8... kImgOffset2 = 480; //header is 348 bytes, but 352 is divisible by 8... lNII2 = false; var lHdr: TNIFTIhdr; lBuff: ByteP; lF: File; lXmm,lYmm,lZmm: single; lUnCompressedFilename,lExt: string; lImgOffset,lC,lFSize: integer; lMat: TMatrix; begin lExt := UpCaseExt(lFileName); move(lNiftiHdr,lHdr,sizeof(lHdr)); if (lExt='.VOI') then begin lHdr.intent_code := kNIFTI_INTENT_NONE; lHdr.intent_name[1] := 'B';//Binary lHdr.scl_slope := 1/kVOI8bit; lHdr.scl_inter := 0; end; if lnVol > 1 then begin lHdr.dim[0] := 4;//3D july2006 lHdr.dim[4] := lnVol;//3D july2006 end else begin lHdr.dim[0] := 3;//3D july2006 lHdr.dim[4] := 1;//3D july2006 end; //if not (lImgBufferItems = (lHdr.dim[1]*lHdr.dim[2]*lHdr.dim[3])) then begin //july2006 //below - images are repositioned to match background if gBGImg.Resliced then begin lHdr.dim[1] := gBGImg.ScrnDim[1]; lHdr.dim[2] := gBGImg.ScrnDim[2]; lHdr.dim[3] := gBGImg.ScrnDim[3]; lHdr.pixdim[1] := gBGImg.ScrnMM[1]; //Apr07 lHdr.pixdim[2] := gBGImg.ScrnMM[2]; //Apr07 lHdr.pixdim[3] := gBGImg.ScrnMM[3]; //Apr07 lHdr.sform_code :=kNIFTI_XFORM_SCANNER_ANAT; //10102006 WriteNiftiMatrix ( lHdr, //must match MAGMA in nifti_hdr gBGImg.ScrnMM[1],0,0,(gBGImg.ScrnOri[1]-1)*-gBGImg.ScrnMM[1], 0,gBGImg.ScrnMM[2],0,(gBGImg.ScrnOri[2]-1)*-gBGImg.ScrnMM[2], 0,0,gBGImg.ScrnMM[3],(gBGImg.ScrnOri[3]-1)*-gBGImg.ScrnMM[3]); lHdr.qform_code := kNIFTI_XFORM_SCANNER_ANAT; //May07 lMat:= Matrix3D ( gBGImg.ScrnMM[1],0,0,(gBGImg.ScrnOri[1]-1)*-gBGImg.ScrnMM[1], 0,gBGImg.ScrnMM[2],0,(gBGImg.ScrnOri[2]-1)*-gBGImg.ScrnMM[2], 0,0,gBGImg.ScrnMM[3],(gBGImg.ScrnOri[3]-1)*-gBGImg.ScrnMM[3], 0,0,0,1); nifti_mat44_to_quatern( lMat,lHdr.quatern_b,lHdr.quatern_c,lHdr.quatern_d, lHdr.qoffset_x,lHdr.qoffset_y,lHdr.qoffset_z, lXmm,lYmm,lZmm,lHdr.pixdim[0]); end else begin //Apr07 - for unresliced data, use raw header for data end; case lImgBufferBPP of 4: begin {lSingleRA := SingleP(lImgBuffer); for lPos := 1 to 4 do fx(22,lSingleRA^[lPos]);} lHdr.bitpix := 32; lHdr.datatype := kDT_FLOAT;//note 32-bit integers saved internally as 32-bit float end; 3: begin lHdr.bitpix := 24; lHdr.datatype := kDT_RGB; end; 2: begin lHdr.bitpix := 16; lHdr.datatype := kDT_SIGNED_SHORT; end; 1: begin lHdr.bitpix := 8; lHdr.datatype := kDT_UNSIGNED_CHAR; //lHdr.scl_inter := lHdr.WindowScaledMin; //lHdr.scl_slope := (lHdr.WindowScaledMax-lHdr.WindowScaledMin) /255; end; else begin showmessage('Error: Unsupported bytes per voxel: '+inttostr(lImgBufferBPP)); exit; end; end; if (lExt='.IMG') or (lExt ='.HDR') then begin lHdr.magic := kNIFTI_MAGIC_SEPARATE_HDR; lHdr.vox_offset := 0; Filemode := 1; //next write header data as .hdr lFilename := changeFileExt(lFilename,'.hdr'); AssignFile(lF, lFileName); Rewrite(lF,sizeof(TNIFTIhdr)); BlockWrite(lF,lHdr, 1); CloseFile(lF); //next write image data as .img lFilename := changeFileExt(lFilename,'.img'); AssignFile(lF, lFileName); {WIN} Rewrite(lF,lImgBufferItems*lImgBufferBPP); BlockWrite(lF,lImgBuffer^,1); CloseFile(lF); Filemode := 2; exit; end; //separate header lHdr.magic := kNIFTI_MAGIC_EMBEDDED_HDR; lImgOffset := kImgOffset; lHdr.vox_offset := lImgOffset;//352 bytes lFSize := lImgOffset+(lImgBufferItems*lImgBufferBPP); getmem(lBuff,lFSize); move(lHdr,lBuff^,sizeof(lHdr)); //Next: NIfTI 1.1 requires bytes 349..352 set to zero when no XML information lC := lImgOffset; lBuff^[lC-3] := 0; lBuff^[lC-2] := 0; lBuff^[lC-1] := 0; lBuff^[lC] := 0; lC := lImgOffset+1; //move(lImgBuffer^[1],lBuff[lC],lImgBufferItems*lImgBufferBPP); move(lImgBuffer^,lBuff^[lC],lImgBufferItems*lImgBufferBPP); if (lExt='.NII') then begin Filemode := 1; AssignFile(lF, lFileName); Rewrite(lF,lFSize); BlockWrite(lF,lBuff^,1); CloseFile(lF); Filemode := 2; exit; end; //uncompressed lUnCompressedFilename := changefileextx(lFilename,'.nii'); GZipBuffer(lUnCompressedFilename,lFilename,lBuff,lFSize,false); freemem(lBuff); end; procedure SaveAsVOIorNIFTIcoreOrtho (var lFilename: string; var lImgBuffer: ByteP; lImgBufferItems, lImgBufferBPP,lnVol: integer; var lNiftiHdr: TNIFTIHdr); var lISize: integer; lTempHdr: TMRIcroHdr; begin if not gBGImg.UseReorientHdr then exit; lTempHdr.NIFTIhdr := lNIftIHdr; lISize := (lImgBufferItems*lImgBufferBPP); GetMem(lTempHdr.ImgBufferUnaligned ,lISize + 16); {$IFDEF FPC} lTempHdr.ImgBuffer := align(lTempHdr.ImgBufferUnaligned,16); {$ELSE} lTempHdr.ImgBuffer := ByteP($fffffff0 and (integer(lTempHdr.ImgBufferUnaligned)+15)); {$ENDIF} lTempHdr.ImgBufferItems := lImgBufferItems; lTempHdr.ImgBufferBPP := lImgBufferBPP; move(lImgBuffer^,lTempHdr.ImgBuffer^,lISize); Reslice_Img_To_Unaligned (gBGImg.ReorientHdr, lTempHdr ,true); SaveAsVOIorNIFTIinnercore (lFilename, lTempHdr.ImgBuffer,lImgBufferItems, lImgBufferBPP,lnVol, lTempHdr.NIFTIhdr); //restore orientation //12/2010 remove this line - we changed TMPHdr lNiftiHdr := lTempHdr.NIFtiHdr; //reslease memory FreeMem(lTempHdr.ImgBufferUnaligned); end; procedure SaveAsVOIorNIFTIcore (var lFilename: string; var lImgBuffer: ByteP; lImgBufferItems, lImgBufferBPP,lnVol: integer; var lNiftiHdr: TNIFTIHdr); const kImgOffset = 352; //header is 348 bytes, but 352 is divisible by 8... begin //10/2007 - scl_slope; //lExt := UpCaseExt(lFileName); if DiskFreeEx(lFilename) < (kImgOffset+(lImgBufferItems*lImgBufferBPP)) then begin case MessageDlg('Very little space on the selected drive. Attempt to save to this disk?', mtConfirmation, [mbYes, mbCancel], 0) of mrCancel: exit; end; //case end; if FileExistsEX(lFileName) then begin case MessageDlg('Overwrite the file named '+lFileName+'?', mtConfirmation, [mbYes, mbCancel], 0) of mrCancel: exit; end; //case end; //file exists if not gBGImg.UseReorientHdr then SaveAsVOIorNIFTIinnercore (lFilename, lImgBuffer,lImgBufferItems, lImgBufferBPP,lnVol, lNiftiHdr) else SaveAsVOIorNIFTIcoreOrtho (lFilename, lImgBuffer,lImgBufferItems, lImgBufferBPP,lnVol, lNiftiHdr); end; (*procedure SaveAsVOIorNIFTIcore (var lFilename: string; var lImgBuffer: ByteP; lImgBufferItems, lImgBufferBPP,lnVol: integer; var lNiftiHdr: TNIFTIHdr); const kImgOffset = 352; //header is 348 bytes, but 352 is divisible by 8... var lHdr: TNIFTIhdr; lBuff: ByteP; lMat: TMatrix; lXmm,lYmm,lZmm: single; lF: File; lUnCompressedFilename,lExt: string; lC,lFSize: integer; begin lExt := UpCaseExt(lFileName); if DiskFreeEx(lFilename) < (kImgOffset+(lImgBufferItems*lImgBufferBPP)) then begin case MessageDlg('Very little space on the selected drive. Attempt to save to this disk?', mtConfirmation, [mbYes, mbCancel], 0) of mrCancel: exit; end; //case end; if FileExistsEX(lFileName) then begin case MessageDlg('Overwrite the file named '+lFileName+'?', mtConfirmation, [mbYes, mbCancel], 0) of mrCancel: exit; end; //case end; //file exists move(lNiftiHdr,lHdr,sizeof(lHdr)); if (lExt='.VOI') then begin lHdr.intent_code := kNIFTI_INTENT_NONE; lHdr.intent_name[1] := 'B';//Binary lHdr.scl_slope := 1/kVOI8bit; lHdr.scl_inter := 0; end; if lnVol > 1 then begin lHdr.dim[0] := 4;//3D july2006 lHdr.dim[4] := lnVol;//3D july2006 end else begin lHdr.dim[0] := 3;//3D july2006 lHdr.dim[4] := 1;//3D july2006 end; //if not (lImgBufferItems = (lHdr.dim[1]*lHdr.dim[2]*lHdr.dim[3])) then begin //july2006 //below - images are repositioned to match background if gBGImg.Resliced then begin lHdr.dim[1] := gBGImg.ScrnDim[1]; lHdr.dim[2] := gBGImg.ScrnDim[2]; lHdr.dim[3] := gBGImg.ScrnDim[3]; lHdr.pixdim[1] := gBGImg.ScrnMM[1]; //Apr07 lHdr.pixdim[2] := gBGImg.ScrnMM[2]; //Apr07 lHdr.pixdim[3] := gBGImg.ScrnMM[3]; //Apr07 lHdr.sform_code :=kNIFTI_XFORM_SCANNER_ANAT; //10102006 WriteNiftiMatrix ( lHdr, //must match MAGMA in nifti_hdr gBGImg.ScrnMM[1],0,0,(gBGImg.ScrnOri[1]-1)*-gBGImg.ScrnMM[1], 0,gBGImg.ScrnMM[2],0,(gBGImg.ScrnOri[2]-1)*-gBGImg.ScrnMM[2], 0,0,gBGImg.ScrnMM[3],(gBGImg.ScrnOri[3]-1)*-gBGImg.ScrnMM[3]); lHdr.qform_code := kNIFTI_XFORM_SCANNER_ANAT; //May07 lMat:= Matrix3D ( gBGImg.ScrnMM[1],0,0,(gBGImg.ScrnOri[1]-1)*-gBGImg.ScrnMM[1], 0,gBGImg.ScrnMM[2],0,(gBGImg.ScrnOri[2]-1)*-gBGImg.ScrnMM[2], 0,0,gBGImg.ScrnMM[3],(gBGImg.ScrnOri[3]-1)*-gBGImg.ScrnMM[3], 0,0,0,1); nifti_mat44_to_quatern( lMat,lHdr.quatern_b,lHdr.quatern_c,lHdr.quatern_d, lHdr.qoffset_x,lHdr.qoffset_y,lHdr.qoffset_z, lXmm,lYmm,lZmm,lHdr.pixdim[0]); end else begin //Apr07 - for unresliced data, use raw header for data end; case lImgBufferBPP of 4: begin {lSingleRA := SingleP(lImgBuffer); for lPos := 1 to 4 do fx(22,lSingleRA^[lPos]);} lHdr.bitpix := 32; lHdr.datatype := kDT_FLOAT;//note 32-bit integers saved internally as 32-bit float end; 3: begin lHdr.bitpix := 24; lHdr.datatype := kDT_RGB; end; 2: begin lHdr.bitpix := 16; lHdr.datatype := kDT_SIGNED_SHORT; end; 1: begin lHdr.bitpix := 8; lHdr.datatype := kDT_UNSIGNED_CHAR; //lHdr.scl_inter := lHdr.WindowScaledMin; //lHdr.scl_slope := (lHdr.WindowScaledMax-lHdr.WindowScaledMin) /255; end; else begin showmessage('Error: Unsupported bytes per voxel: '+inttostr(lImgBufferBPP)); exit; end; end; if (lExt='.IMG') or (lExt ='.HDR') then begin lHdr.magic := kNIFTI_MAGIC_SEPARATE_HDR; lHdr.vox_offset := 0; Filemode := 1; //next write header data as .hdr lFilename := changeFileExt(lFilename,'.hdr'); AssignFile(lF, lFileName); Rewrite(lF,sizeof(TNIFTIhdr)); BlockWrite(lF,lHdr, 1); CloseFile(lF); //next write image data as .img lFilename := changeFileExt(lFilename,'.img'); AssignFile(lF, lFileName); {WIN} Rewrite(lF,lImgBufferItems*lImgBufferBPP); BlockWrite(lF,lImgBuffer^,1); CloseFile(lF); Filemode := 2; exit; end; //separate header lHdr.magic := kNIFTI_MAGIC_EMBEDDED_HDR; lHdr.vox_offset := kImgOffset;//352 bytes lFSize := kImgOffset+(lImgBufferItems*lImgBufferBPP); getmem(lBuff,lFSize); move(lHdr,lBuff^,sizeof(lHdr)); //Next: NIfTI 1.1 requires bytes 349..352 set to zero when no XML information lC := kImgOffset; lBuff^[lC-3] := 0; lBuff^[lC-2] := 0; lBuff^[lC-1] := 0; lBuff^[lC] := 0; lC := kImgOffset+1; //move(lImgBuffer^[1],lBuff[lC],lImgBufferItems*lImgBufferBPP); move(lImgBuffer^,lBuff^[lC],lImgBufferItems*lImgBufferBPP); if (lExt='.NII') then begin Filemode := 1; AssignFile(lF, lFileName); Rewrite(lF,lFSize); BlockWrite(lF,lBuff^,1); CloseFile(lF); Filemode := 2; exit; end; //uncompressed lUnCompressedFilename := changefileext(lFilename,'.nii'); GZipBuffer(lUnCompressedFilename,lFilename,lBuff,lFSize,false); freemem(lBuff); end;*) {$IFDEF FPC} // http://bugs.freepascal.org/view.php?id=7797 function GetExtensionFromFilterAtIndex(Filter: String; Index: Integer): String; var p, pipe: Integer; begin Result := ''; if Index < 1 then Exit; p := 0; pipe := 0; while (p < Length(Filter)) do begin Inc(p); if Filter[p] = '|' then Inc(pipe); if (pipe = 2 * (Index - 1)) then break; end; if (p = length(Filter)) then exit; System.Delete(Filter,1,p); p := Pos('|',Filter); if (p = 0) then exit; System.Delete(Filter,1,p); Filter := Copy(Filter,1,MaxInt); p := Pos(';',Filter); pipe := Pos('|',Filter); if (pipe < p) or (p = 0) then p := pipe; if (p > 0) then System.Delete(Filter,p,Length(Filter) - p +1); Filter := StringReplace(Filter, '*', '',[rfReplaceAll, rfIgnoreCase]); if (Pos('?',Filter) > 0) {or (Pos('*',Filter) > 0)} then exit; Result := Filter; end; {$ENDIF} procedure SaveAsVOIorNIFTI (var lImgBuffer: ByteP; lImgBufferItems, lImgBufferBPP,lnVol: integer; DefaultFormatVOI: boolean; var lNiftiHdr: TNIFTIHdr; lDefFilename: string); var lFileName,lExt: string; begin if DefaultFormatVOI then begin ImgForm.SaveDialog1.Filter := 'Volume of Interest(.voi)|*.voi|NIfTI (.nii)|*.nii|NIfTI compressed (.nii.gz)|*.nii.gz|NIfTI (.hdr/.img)|*.hdr|MRIcro (.roi)|*.roi'; ImgForm.SaveDialog1.FilterIndex:= gBGImg.SaveVoiFilter; //+1since default added ImgForm.SaveDialog1.Filename := changefileext(ImgForm.SaveDialog1.Filename,'.voi');//10/10/06 ImgForm.SaveDialog1.DefaultExt := '.voi'; end else begin ImgForm.SaveDialog1.Filter := 'NIfTI compressed (.nii.gz)|*.nii.gz|NIfTI (.nii)|*.nii|NIfTI (.hdr/.img)|*.hdr|Volume of Interest(.voi)|*.voi|MRIcro (.roi)|*.roi'; ImgForm.SaveDialog1.Filename := changefileext(ImgForm.SaveDialog1.Filename,'.nii.gz');//10/10/06 ImgForm.SaveDialog1.FilterIndex:= gBGImg.SaveImgFilter; //8/8/2014 removed +1 new behavior with new lazarus 1.2+1since default added ImgForm.SaveDialog1.DefaultExt := '.nii.gz'; end; if lDefFilename <> '' then ImgForm.SaveDialog1.Filename := ParseFilename(lDefFilename); if not ImgForm.SaveDialog1.Execute then exit; if DefaultFormatVOI then gBGImg.SaveVoiFilter := ImgForm.SaveDialog1.FilterIndex else gBGImg.SaveImgFilter := ImgForm.SaveDialog1.FilterIndex; lFileName := ImgForm.SaveDialog1.Filename; {$IFDEF FPC} //recent versions of Lazarus (1.2) do handle this, but will put .gz not .nii.gz if ImgForm.SaveDialog1.filterIndex > 0 then begin {$IFNDEF Darwin} check next line in each OS {$ENDIF} lExt := GetExtensionFromFilterAtIndex(ImgForm.SaveDialog1.Filter,ImgForm.SaveDialog1.FilterIndex); //8/8/2014 check on OSX 10.4 lFilename := ChangeFileExtX(lFilename,lExt); end; {$ENDIF} lExt := UpCaseExt(lFileName); gBGImg.VOIchanged := false; if (lExt='.ROI') then begin Showmessage('Note that the MRIcro ROI format does not save image dimensions. You may want to save a copy as VOI format.'); SaveMRIcroROI (lFileName); exit; end; SaveAsVOIorNIFTIcore (lFilename,lImgBuffer, lImgBufferItems, lImgBufferBPP,lnVol,lNiftiHdr); end; procedure SetSubmenuWithTag (var lRootMenu: TMenuItem; lTag: Integer); var lCount,lSubMenu: integer; begin lCount := lRootMenu.Count; if lCount < 1 then exit; for lSubMenu := (lCount-1) downto 0 do if lRootmenu.Items[lSubmenu].Tag = lTag then begin lRootmenu.Items[lSubmenu].Checked := true; exit end; //will exit unless tag not found: default select 1st item lRootmenu.Items[0].Checked := true; //While Recent1.Count > 0 do Recent1.Items[0].Free; end; function MaxDim (lX,lY,lZ: integer): integer; //returns largest of 3 begin result := lX; if lY > result then result := lY; if lZ > result then result := lZ; end; procedure SetBGImgDefaults (var lBGImg: TBGImg); begin with lBGImg do begin FlipAx := false; FlipSag := false; SaveImgFilter := 0; SaveVoiFilter := 0; OverlayTransPct := -1; FontSize := 12; BGTransPct := 0; LicenseID := 0; ShowDraw := false; ResliceOnLoad := false; OrthoReslice := true; Prompt4DVolume := true; MaxDim := 384; XBarGap := 7; XBarThick := 3; XBarClr := clBlue; VOIClr := 255;//clRed; VOIInvZoom := 1 shl 10; //1024 = 100% LesionSmooth := 3;//3mm smoothing LesionDilate := 8; VOIUndoSlice := 0; VOIUndoOrient := 0; VOIChanged := false; VOImirrored := false; VOIUndoVolItems := 0; RenderDepthBufferItems := 0; SigDig := 5; ImageSeparation := 0; SliceView := 0;//multiple slices SPMDefaultsStatsFmriT := 16; SingleRow := false; SPMDefaultsStatsFmriT0 := 1; SaveDefaultIni := true; ThinPen := true; XBarVisible := true; OverlaySmooth := true; //FSLDIR := 'FSLDIR=/usr/local/fsl'; FSLBASE := '/usr/local/fsl'; //FSLBETEXE := '/usr/local/fsl/bin/bet'; FSLOUTPUTTYPE := 'FSLOUTPUTTYPE=NIFTI_GZ'; //AutoFill := false; KnownAlignment := false; StretchQuality := sqHigh; end; end; procedure AlphaBlend32(lBGQuad,lOverlayQuad : RGBQuadp; lBG0Clr,lOverlay0Clr: DWord; lSlicePixels, lOverlayTransPct: integer); // 630 var lBGwt,lOverlaywt,lPixel,lPos:integer; lBGp,lOverlayP: ByteP; lBGDWordp,lOverlayDWordp : DWordp; begin //note Here we blend the RGBA values - in fact we only need to blend RGB //however, the position of Alpha varies between OSX ARGB and Linux/Windows RGBA //this routine would be ~25% faster if we use a compiler-switch for the OS, //but I do not want to do this until the Compiler code settles a bit more... lBGp := ByteP(lBGQuad); lOverlayP := ByteP(lOverlayQuad); lOverlayDWordp := DWordp(lOverlayQuad); lBGDWordp := DWordp(lBGQuad); //next: transparency weighting lBGwt := round((lOverlayTransPct)/100 * 1024); lOverlaywt := round((100-lOverlayTransPct)/100 * 1024); //next redraw each pixel lPos := 1; if lOverlayTransPct > -1 then begin for lPixel := 1 to lSlicePixels do begin if lOverlayDWordp^[lPixel] = lOverlay0Clr then inc(lPos,4) else if lBGDWordp^[lPixel] = lBG0Clr then begin lBGDWordp^[lPixel] := lOverlayDWordp^[lPixel]; inc(lPos,4); end else begin lBGp^[lPos] := (lBGp^[lPos]*lBGwt+lOverlayP^[lPos]*lOverlaywt) shr 10; inc(lPos); lBGp^[lPos] := (lBGp^[lPos]*lBGwt+lOverlayP^[lPos]*lOverlaywt) shr 10; inc(lPos); lBGp^[lPos] := (lBGp^[lPos]*lBGwt+lOverlayP^[lPos]*lOverlaywt) shr 10; inc(lPos); lBGp^[lPos] := (lBGp^[lPos]*lBGwt+lOverlayP^[lPos]*lOverlaywt) shr 10; inc(lPos); end; end; end else begin for lPixel := 1 to lSlicePixels do begin if lOverlayDWordp^[lPixel] = lOverlay0Clr then inc(lPos,4) else if lBGDWordp^[lPixel] = lBG0Clr then begin lBGDWordp^[lPixel] := lOverlayDWordp^[lPixel]; inc(lPos,4); end else begin if lOverlayP^[lPos] > lBGp^[lPos] then lBGp^[lPos] := lOverlayP^[lPos]; inc(lPos); if lOverlayP^[lPos] > lBGp^[lPos] then lBGp^[lPos] := lOverlayP^[lPos]; inc(lPos); if lOverlayP^[lPos] > lBGp^[lPos] then lBGp^[lPos] := lOverlayP^[lPos]; inc(lPos); if lOverlayP^[lPos] > lBGp^[lPos] then lBGp^[lPos] := lOverlayP^[lPos]; inc(lPos); end; end; end; end; function Raw2ScaledIntensity (lHdr: TMRIcroHdr; lRaw: single): single; begin if lHdr.NIFTIhdr.scl_slope = 0 then result := lRaw+lHdr.NIFTIhdr.scl_inter else result := (lRaw * lHdr.NIFTIhdr.scl_slope)+lHdr.NIFTIhdr.scl_inter; end; function Scaled2RawIntensity (lHdr: TMRIcroHdr; lScaled: single): single; begin if lHdr.NIFTIhdr.scl_slope = 0 then result := (lScaled)-lHdr.NIFTIhdr.scl_inter else result := (lScaled-lHdr.NIFTIhdr.scl_inter) / lHdr.NIFTIhdr.scl_slope; end; procedure FilterLUT (var lBackgroundImg: TBGImg; var lHdr: TMRIcroHdr; lMin, lMax: integer); //lLUT: 0=gray,1=red,2=green,3=blue var lInc: integer; lRGB : TRGBQuad; begin for lInc := 0 to 255 do lHdr.LUT[lInc] := lBackgroundImg.BackupLUT[lInc]; if (lMin < 0) or (lMin > 255) or (lMax < 0) or (lMax > 255) then exit; if lMin > lMax then begin lInc := lMin; lMin := lMax; lMax := lInc; end; //swap lMin/lMax lRGB.rgbRed := (lBackgroundImg.XBarClr and 255) ; lRGB.rgbGreen := ((lBackgroundImg.XBarClr shr 8) and 255) ;// and 65280; lRGB.rgbBlue := ((lBackgroundImg.XBarClr shr 16) and 255) ;//and 16711680; lRGB.rgbReserved := kLUTalpha; for lInc := lMin to lMax do lHdr.LUT[lInc] := lRGB; //z end; procedure LoadLabelsOld(var lBackgroundImg: TBGImg; var lHdr: TMRIcroHdr); var lLUTname: string; lInc: integer; lTextFile: TextFile; lStr1: string; lCh: char; begin SetLength(lBackgroundImg.LabelRA,kMaxLabel+1); //+1 as indexed from 0 for lInc := 0 to High(lBackgroundImg.LabelRA) do lBackgroundImg.LabelRA[lInc] := inttostr(lInc); lLUTname := changefileext(lHdr.HdrFileName,'.txt'); if not Fileexists(lLUTname) then begin lLUTname := ParseFileName(lHdr.HdrFileName)+'.txt'; //file.nii.gz -> file.txt if not Fileexists(lLUTname) then exit; end; assignfile(lTextFile,lLUTname); lHdr.UsesLabels := true; Filemode := 0; reset(lTextFile); while not EOF(lTextFile) do begin lStr1 := ''; repeat read(lTextFile,lCh); if (lCh >= '0') and (lCh <= '9') then lStr1 := lStr1 + lCh; until (EOF(lTextFile)) or (lCh=kCR) or (lCh=UNIXeoln) or (((lCh=kTab)or (lCh=' ')) and (length(lStr1)>0)); if (length(lStr1) > 0) and (not EOF(lTextFile)) then begin linc := strtoint(lStr1); if (lInc >= 0) and (lInc <= kMaxLabel) then begin lStr1 := ''; repeat read(lTextFile,lCh); if (EOF(lTextFile)) or (lCh=kCR) or (lCh=UNIXeoln) {or (lCh=kTab) or (lCh=' ')} then else lStr1 := lStr1 + lCh; until (EOF(lTextFile)) or (lCh=kCR) or (lCh=UNIXeoln) {or (lCh=kTab)or (lCh=' ')}; //showmessage(inttostr(lInc)+'x'+lStr1); lBackgroundImg.LabelRA[lInc] := lStr1; end; end; end; CloseFile(lTextFile); Filemode := 2; end; procedure LoadLabelLUT(var lBackgroundImg: TBGImg; var lHdr: TMRIcroHdr {; isBackground: boolean}); var lLUTname: string; (* lInc: integer; lTextFile: TextFile; lStr1: string; lCh: char; *) begin lLUTname := changefileext(lHdr.HdrFileName,'.lut'); if Fileexists(lLUTname) then begin lHdr.UsesCustomPalette := true; LoadColorScheme(lLUTname,lHdr); end; //if isBackground then begin LoadLabelsOld(lBackgroundImg,lHdr); lHdr.UsesLabels := true; //end; end; procedure LoadMonochromeLUT (var lLUT: integer; var lBackgroundImg: TBGImg; var lHdr: TMRIcroHdr); //lLUT: 0=gray,1=red,2=green,3=blue var lR,lG,lB,lInc: integer; begin for lInc := 0 to 255 do lHdr.LUT[lInc].rgbReserved := kLUTalpha; case lLUT of 1: for lInc := 0 to 255 do begin lHdr.LUT[lInc].rgbRed := lInc; lHdr.LUT[lInc].rgbGreen := 0; lHdr.LUT[lInc].rgbBlue := 0; end;//red 2: for lInc := 0 to 255 do begin lHdr.LUT[lInc].rgbRed := 0; lHdr.LUT[lInc].rgbGreen := 0; lHdr.LUT[lInc].rgbBlue := lInc; end;//blue 3: for lInc := 0 to 255 do begin lHdr.LUT[lInc].rgbRed := 0; lHdr.LUT[lInc].rgbGreen := lInc; lHdr.LUT[lInc].rgbBlue := 0; end;//green 4: for lInc := 0 to 255 do begin lHdr.LUT[lInc].rgbRed := lInc; lHdr.LUT[lInc].rgbGreen := 0; lHdr.LUT[lInc].rgbBlue := lInc; end;//r+b=violet 5: for lInc := 0 to 255 do begin lHdr.LUT[lInc].rgbRed := lInc; lHdr.LUT[lInc].rgbGreen := lInc; lHdr.LUT[lInc].rgbBlue := 0; end;//red + green = yellow 6: for lInc := 0 to 255 do begin lHdr.LUT[lInc].rgbRed := 0; lHdr.LUT[lInc].rgbGreen := lInc; lHdr.LUT[lInc].rgbBlue := lINc; end;//green+blue = cyan maxint: begin// //showmessage(inttostr(lBackgroundImg.VOIClr)+' '+'r'+inttostr(lR)+'g'+inttostr(lG)+'b'+inttostr(lB)); lHdr.LUT[0].rgbRed := 0; lHdr.LUT[0].rgbGreen := 0; lHdr.LUT[0].rgbBlue := 0; lR := (lBackgroundImg.VOIClr and 255) ; lG := ((lBackgroundImg.VOIClr shr 8) and 255) ;// and 65280; lB:= ((lBackgroundImg.VOIClr shr 16) and 255) ;//and 16711680; for lInc := 1 to kVOI8bit do begin lHdr.LUT[lInc].rgbRed := round((lInc*lR) div kVOI8bit); lHdr.LUT[lInc].rgbGreen := round((lInc*lG) div kVOI8bit); lHdr.LUT[lInc].rgbBlue := round((lInc*lB) div kVOI8bit); end;//green+blue = cyan end; else begin lLUT := 0; for lInc := 0 to 255 do begin lHdr.LUT[lInc].rgbRed := lInc; lHdr.LUT[lInc].rgbGreen := lInc; lHdr.LUT[lInc].rgbBlue := lInc; end;//for gray end//else... gray end; lHdr.LUTinvisible := (lHdr.LUT[0]); end; procedure LUTbias (var lHdr: TMRIcroHdr); {http://dept-info.labri.fr/~schlick/DOC/gem2.html http://dept-info.labri.fr/~schlick/publi.html Fast Alternatives to Perlin's Bias and Gain Functions Christophe Schlick Graphics Gems IV, p379-382, April 1994 } var lIndex,lBias: integer; lA,lT: single; lLUT: TLUT; begin //if gBias = 0.5 then exit; lA := 0.2; for lIndex := 1 to 254 do begin lT := lIndex/255; //lBias := 255*(lt/((1/la-2)*(1-lt)+1)) ; lBias := round(255*(lt/((1/la-2)*(1-lt)+1)) ); lLUT[lIndex] := lHdr.LUT[(lBias)]; //lHdr.LUT[lIndex].rgbReserved := kLUTalpha; end; for lIndex := 1 to 254 do lHdr.LUT[lIndex] := lLUT[lIndex]; end; procedure LoadColorScheme(lStr: string; var lHdr: TMRIcroHdr); const UNIXeoln = chr(10); var lF: textfile; lBuff: bytep0; lFData: file; lCh: char; lNumStr: String; lZ : integer; lByte,lIndex: byte; //lType, lIndx,lLong,lR,lG: boolean; procedure ResetBools; //nested begin //lType := false; lIndx := false; lR := false; lG := false; lNumStr := ''; end; //nested proc ResetBools begin //proc LoadColorScheme if not fileexistsex(lStr) then exit; lZ := FSize(lStr); if (lZ =768) or (lZ = 800) or (lZ=970) then begin //binary LUT assignfile(lFdata,lStr); Filemode := 0; reset(lFdata,1); seek(lFData,lZ-768); GetMem( lBuff, 768); BlockRead(lFdata, lBuff^, 768); for lZ := 0 to 255 do begin lHdr.LUT[lZ].rgbRed := lBuff^[lZ]; lHdr.LUT[lZ].rgbGreen := lBuff^[lZ+256]; lHdr.LUT[lZ].rgbBlue := lBuff^[lZ+512]; lHdr.LUT[lZ].rgbReserved := kLUTalpha; end; closefile(lFdata); Filemode := 2; freemem(lBuff); //LUTBIas (lHdr); lHdr.LUTinvisible := (lHdr.LUT[0]); exit; end; //Text LUT assignfile(lF,lStr); Filemode := 0; reset(lF); lLong := false; lIndex := 0; ResetBools; for lZ := 0 to 255 do begin lHdr.LUT[lZ].rgbRed := 0; lHdr.LUT[lZ].rgbGreen := 0; lHdr.LUT[lZ].rgbBlue := 0; lHdr.LUT[lZ].rgbReserved := kLUTalpha; end; while not EOF(lF) do begin read(lF,lCh); if lCh = '*' then //comment character while (not EOF(lF)) and (lCh <> kCR) and (lCh <> UNIXeoln) do read(lF,lCh); if (lCh = 'L') or (lCh = 'l') then begin //lType := true; lLong := true; end; //'l' if (lCh = 's') or (lCh = 'S') then begin //lType := true; lLong := false; end; //'s' if lCh in ['0'..'9'] then lNumStr := lNumStr + lCh; if ((not(lCh in ['0'..'9'])) or (EOF(lF)) ) and (length(lNumStr) > 0) then begin //not a number = space??? try to read number string if not lIndx then begin lIndex := strtoint(lNumStr); lIndx := true; end else begin //not index if lLong then lByte := trunc(strtoint(lNumStr) / 256) else lByte := strtoint(lNumStr); if not lR then begin lHdr.LUT[lIndex].rgbRed := lByte; lR := true; end else if not lG then begin lHdr.LUT[lIndex].rgbGreen := lByte; lG := true; end else {final value is blue} begin lHdr.LUT[lIndex].rgbBlue := lByte; ResetBools; end; end; lNumStr := ''; end; end; //not eof CloseFile(lF); Filemode := 2; //LUTBIas (lHdr); lHdr.LUTinvisible := (lHdr.LUT[0]); end; //Proc LoadColorScheme procedure FreeImgMemory(var lHdr: TMRIcroHdr); begin with lHdr do begin if ScrnBufferItems > 0 then freemem(ScrnBuffer); if ImgBufferItems > 0 then freemem(ImgBufferUnaligned); if RenderBufferItems > 0 then freemem(RenderBuffer); RenderBufferItems := 0; ScrnBufferItems := 0; ImgBufferItems := 0; end; end; procedure DrawFrame (var lImage: TImage; lL,lT,lR,lB: integer); begin lImage.Canvas.Brush.Style := bsSolid; lImage.canvas.pen.color := clWhite; lImage.canvas.pen.color := clSilver; lImage.Canvas.Rectangle(lL,lT,lR,lB); lImage.canvas.pen.color := clBlack; lImage.Canvas.Rectangle(lL+1,lT+1,lR-1,lB-1); end; procedure IntenLabel (var lImage: TImage; var lHdr: TMRIcroHdr; lLTRB: integer;lMinIn,lMaxIn: single); //special: if lMin=lMax, assumes current window values var lDesiredSteps,lPower,lTxtWid,lTxtTop,lPGWid,lPGHt,lBarTop,lBarLeft,lBarLength,lBarBorder,lBarThick: integer; lMin,lMax,l1stStep,lRange,lStepSize,lStepPos: single; lSteps,lStep,lDecimals,lStepPosScrn: integer; begin lMin := lMinIn; lMax := lMaxIn; lBarBorder := 6; lBarThick := 10; lPGWid := lImage.Width; lPGHt := lImage.Height; if gBGImg.XBarClr = TColor(gMRIcroOverlay[kBGOverlayNum].LUTinvisible) then lImage.canvas.font.Color := clBlack//clWhite;//gLUT[lClr].rgbRed+(gLUT[lClr].rgbGreen shl 8)+(gLUT[lClr].rgbBlue shl 16); else lImage.canvas.font.Color := gBGImg.XBarClr; //lImage.canvas.font.Color := clWhite;//gXBarClr; lImage.Canvas.Brush.Style := bsClear; lImage.Canvas.Font.Name := 'Arial'; (*if lPGWid < 100 then lImage.Canvas.Font.Size := 9 else if lPGWid < 200 then lImage.Canvas.Font.Size := 12 else lImage.Canvas.Font.Size := 14;*) lImage.Canvas.Font.Size := gBGImg.FontSize; lTxtTop := lPGHt - ( lBarBorder +(lImage.Canvas.TextHeight('X') div 2)); //next: compute increment lDesiredSteps := 4; if lMin=lMax then begin lMin := lHdr.WindowScaledMin; lMax := lHdr.WindowScaledMax; SortSingle(lMin,lMax); if (lHdr.WindowScaledMin <= 0) and (lHdr.WindowScaledMax <= 0) then begin if (lHdr.LutFromZero) then lMax := 0; lStepPos := lMin; lMin := lMax; lMax := lStepPos; end else if (lHdr.LutFromZero) and (lMin > 0) then lMin := 0; end; //lMinIn=lMaxIn if lMin = lMax then exit; //showmessage(realtostr(lMin,4)+' '+realtostr(lMax,4)); lRange := abs(lMax - lMin); //if lRange = 0 then exit; if lRange < 0.000001 then exit; lStepSize := lRange / lDesiredSteps; lPower := 0; while lStepSize >= 10 do begin lStepSize := lStepSize/10; inc(lPower); end; while lStepSize < 1 do begin lStepSize := lStepSize * 10; dec(lPower); end; lStepSize := round(lStepSize) *Power(10,lPower); if lPower < 0 then lDecimals := abs(lPower) else lDecimals := 0; if lMin > lMax then begin // inverted l1stStep := trunc((lMax) / lStepSize)*lStepSize; if l1stStep < (lMax) then l1stStep := l1stStep+lStepSize; lSteps := trunc( abs((lMin+0.0001)-l1stStep) / lStepSize)+1; end else begin l1stStep := trunc((lMin) / lStepSize)*lStepSize; if l1stStep < (lMin) then l1stStep := l1stStep+lStepSize; lSteps := trunc( abs((lMax+0.0001)-l1stStep) / lStepSize)+1; end; if not odd(lLTRB) then begin //vertical if lLTRB > 2 then //right lBarLeft := lPGWid - (lBarThick+lBarBorder+3) else //if right else LEFT lBarLeft := (lBarThick+lBarBorder+3); lBarLength := lPGHt - (lBarBorder+lBarBorder+2); for lStep := 1 to lSteps do begin lStepPos := l1stStep+((lStep-1)*lStepSize); lStepPosScrn := round( abs(lStepPos-lMin)/lRange*lBarLength); if lLTRB > 2 then //right - align text for width lImage.canvas.TextOut(lBarLeft-(lImage.Canvas.TextWidth(realtostr(lStepPos,lDecimals))),lTxtTop-lStepPosScrn,realtostr(lStepPos,lDecimals)) else lImage.canvas.TextOut(lBarLeft,lTxtTop-lStepPosScrn,realtostr(lStepPos,lDecimals)); end; end else begin //if vert else HORIZ lBarLength := lPGWid - (lBarBorder+lBarBorder+2); if lLTRB > 2 then //bottom lBarTop := lPGHt - (lBarThick+lBarBorder+lImage.Canvas.TextHeight('X')+1 ) else //top lBarTop := lBarThick+lBarBorder+1; for lStep := 1 to lSteps do begin lStepPos := l1stStep+((lStep-1)*lStepSize); lStepPosScrn := round(abs(lStepPos-lMin)/lRange*lBarLength); //lStepPosScrn := 15*lStep; lTxtWid := lImage.Canvas.TextWidth(realtostr(lStepPos,lDecimals)); lImage.canvas.TextOut(lBarBorder+lStepPosScrn-(lTxtWid div 2),lBarTop,realtostr(lStepPos,lDecimals)); end; end;//if vert else HORIZ end; procedure IntenBar (var lImage: TImage; var lHdr: TMRIcroHdr; lLTRB: integer; lMin,lMax: single); var lPGHt, lPGWid,lClr,lStripe,lBarBorder,lnStripes,lHorBarTop,lVerBarLeft,lBarThick: integer; begin //if lMin = lMax then lBarBorder := 6; lBarThick := 10; lPGWid := lImage.Width; lPGHt := lImage.Height; lHorBarTop := lBarBorder; lVerBarLeft := lBarBorder; lImage.canvas.pen.width := 1; if not odd(lLTRB) then begin //vertical if lLTRB > 2 then //right lVerBarLeft := lPGWid - (lBarThick+lBarBorder); lnStripes := lPGHt - (lBarBorder+lBarBorder+2); if lnStripes < 1 then exit; {$IFNDEF FPC} DrawFrame(lImage, lVerBarLeft-2, lBarBorder-2,lVerBarLeft+lBarThick+2, lBarBorder+lnStripes+3); {$ELSE} DrawFrame(lImage, lVerBarLeft-2, lBarBorder-2,lVerBarLeft+lBarThick+2, lBarBorder+lnStripes+2); lBarBorder := lBarBorder; lBarThick := lBarThick +1; {$ENDIF} for lStripe := 0 to lnStripes do begin lClr := round(((lnStripes- lStripe) / lnStripes)*255); lImage.canvas.pen.color := TRGBQuad2TColor(lHdr.LUT[lClr]); lImage.canvas.moveto(lVerBarLeft, lBarBorder+lStripe); lImage.canvas.lineto(lVerBarLeft+lBarThick,lBarBorder+lStripe); end; //draw each stripe end else begin //LTRB //Horizontal if lLTRB > 2 then //bottom lHorBarTop := lPGHt - (lBarThick+lBarBorder)-1; lnStripes := lPGWid - (lBarBorder+lBarBorder+1); {$IFNDEF FPC} DrawFrame(lImage,lBarBorder+1, lHorBarTop-2, lBarBorder+lnStripes+3,lHorBarTop+lBarThick+2); {$ELSE} DrawFrame(lImage,lBarBorder, lHorBarTop-2, lBarBorder+lnStripes+4,lHorBarTop+lBarThick+2); lBarBorder := lBarBorder+2; lBarThick := lBarThick +1; {$ENDIF} if lnStripes < 1 then exit; for lStripe := 0 to lnStripes do begin lClr := round((lStripe / lnStripes)*255); {$IFNDEF FPC} lImage.canvas.pen.color := lHdr.LUT[lClr].rgbRed+(lHdr.LUT[lClr].rgbGreen shl 8)+(lHdr.LUT[lClr].rgbBlue shl 16); {$ELSE}lImage.canvas.pen.Color := TRGBQuad2TColor(lHdr.LUT[lClr]);{$ENDIF} lImage.canvas.moveto(lBarBorder+lStripe,lHorBarTop); lImage.canvas.lineto(lBarBorder+lStripe,lHorBarTop+lBarThick); end; //draw each stripe end; //if horizontal IntenLabel(lImage,lHdr,lLTRB,lMin,lMax); end; //procedure SetDimension32(lInPGHt,lInPGWid:integer; lBuff: RGBQuadp; var lBackgroundImg: TBGImg; var lImage: TImage; lPanel: TScrollBox); (*procedure DrawBMPZoom( lx, ly, lZoomPct: integer; lBuff: RGBQuadp; var lImage: TImage); var x, y,lYPos,lPos,lImgSz,lOutX,lOutY: Integer; lRatio,lRatioRecip: single; TempBitmap: TBitmap; lLongBuff: LongIntp; lXlut: LongIntp0; begin if lZoomPct > 1 then lRatio := lZoomPct/100 else lRatio := 1; lRatioRecip := 1/lRatio;//e.g. 200% -> ratio = 2, recip = 0.5 lImgSz := lx * ly; TempBitmap := TBitmap.Create; lLongBuff := LongIntp(lBuff); lOutX := round(lx*lRatio); lOutY := round(ly*lRatio); TempBitmap.Width := lOutX; TempBitmap.Height := lOutY; //TempBitmap.PixelFormat := pf32bit ; TempBitmap.Transparent := False; if lBuff <> nil then begin getmem(lXlut,lOutX*sizeof(longint)); for x:=0 to lOutx-1 do lXlut^[x] := trunc((x+lRatio)*lRatioRecip); //find col for y:= (lOutY-1) downto 0 do begin lYPos := trunc((lOutY-y-0.5)*lRatioRecip) * lx; //find row for x:=0 to lOutx-1 do begin lPos := lXlut^[x] + lYPos; if (lPos > 0) and (lPos <= lImgSz) then TempBitmap.Canvas.Pixels[x,y] := lLongBuff^[lPos]; end; //for x end;//for y freemem(lXlut); end; //if Buff<> nil lImage.Picture.Bitmap := TempBitmap; TempBitmap.Free; end;*) {$IFDEF Unix} procedure DrawBMP( lx, ly: integer; var lBuff: RGBQuadp; var lImage: TImage); var TempBitmap: TBitmap; lRGBBitmap: TRGB32Bitmap; begin TempBitmap := TBitmap.Create; TempBitmap.Width := lx; TempBitmap.Height := ly; if lBuff <> nil then begin lRGBBitmap := TRGB32Bitmap.CreateFromData(@lBuff[1],lx,ly); DrawRGB32Bitmap(TempBitmap.Canvas.Handle, 0, 0, 0, 0, lx, ly,lRGBBitmap {Self}); end; //if lBuff=nil lImage.Picture.Bitmap := TempBitmap; TempBitmap.Free; end; procedure DrawBMPZoom( lSrcWid, lSrcHt, lZoomPct: integer; lRGBBuff: RGBQuadp; var lImage: TImage); //very fast nearest-neighbor rescaling: // integer math, not floating point // uses lookup table for columns // repeated rows are copied rather than recalculated var lRGBBitmap: TRGB32Bitmap; TempBitmap: TBitmap; lBuff,lInBuff,lXBuff: LongintP; //lOutRGBBuff: RGBQuadp; lOutWid,lOutHt,lOutWidx4: integer; lPos,P,Pinc,lRowPos,lPrevRowPos, x,y: integer; lXRatio,lYRatio: single; begin lInBuff:= LongIntP(lRGBBuff);; lXRatio := lZoomPct / 100; lYRatio := lZoomPct/100; lOutwid := round(lSrcWid*lXRatio); lOutHt := round(lSrcHt*lYRatio); lOutWidx4 := lOutWid * sizeof(longint); getmem(lBuff, lOutHt*lOutWid*4); getmem(lXBuff, lOutWid*sizeof(longint)); Pinc:=((lSrcWid)shl 15)div (lOutWid ); P := Pinc shr 1; for x := 1 to lOutWid do begin lXBuff^[x] := (P shr 15)+1; Inc(P,Pinc); end; lPrevRowPos := -MaxInt; Pinc:=((lSrcHt)shl 15)div (lOutHt); P := Pinc shr 1; lPos := 1; if lOutHt > lSrcHt then begin //check for repeated lines for y:=0 to lOutHt-1 do begin lRowPos:=lSrcWid *(P shr 15) ; //top row if lRowPos = lPrevRowPos then begin //repeated line //Move(Pointer(lBuff^[lPos-lOutWid]),Pointer(lBuff^[lPos]),lOutWidx4); Move(lBuff^[lPos-lOutWid],lBuff^[lPos],lOutWidx4); inc(lPos,lOutWid); end else begin //if lRowPos = lPrevRowPos else unique line for x := 1 to lOutWid do begin lBuff^[lPos] :=lInBuff^[lRowPos+lXBuff^[x]]; inc(lPos); end; lPrevRowPos := lRowPos; end; Inc(P,Pinc); end;//for each line end else begin //if lOutHt>lSrcHt else all lines unique for y:=0 to lOutHt-1 do begin lRowPos:=lSrcWid *(P shr 15) ; for x := 1 to lOutWid do begin lBuff^[lPos] :=lInBuff^[lRowPos+lXBuff^[x]]; inc(lPos); end; Inc(P,Pinc); end;//for each line end; freemem(lxBuff); TempBitmap := TBitmap.Create; TempBitmap.Width := lOutWid; TempBitmap.Height := lOutHt; //DrawBMP( lOutWid, lOutHt, lOutRGBBuff, lImage ); //Draw32Bitmap(TempBitmap.Canvas.Handle, lOutWid, lOutHt, lOutRGBBuff); lRGBBitmap := TRGB32Bitmap.CreateFromData(@lBuff[1],lOutWid,lOutHt); DrawRGB32Bitmap(TempBitmap.Canvas.Handle, 0, 0, 0, 0, lOutWid, lOutHt,lRGBBitmap {Self}); lImage.Picture.Bitmap := TempBitmap; TempBitmap.Free; freemem(lBuff); end; {$ELSE}//start windows specific procedure DrawBMPZoom( lx, ly, lZoomPct: integer; lBuff: RGBQuadp; var lImage: TImage); var //lImgSz, lOutX,lOutY: Integer; lRatio: single; TempBitmap: TBitmap; begin if lZoomPct > 1 then lRatio := lZoomPct/100 else lRatio := 1; //lImgSz := lx * ly; TempBitmap := TBitmap.Create; lOutX := round(lx*lRatio); lOutY := round(ly*lRatio); TempBitmap.Width := lOutX; TempBitmap.Height := lOutY; StretchDraw32Bitmap(TempBitmap.Canvas.Handle, lOutX, lOutY,lx, ly, lBuff); lImage.Picture.Bitmap := TempBitmap; TempBitmap.Free; end; procedure DrawBMP( lx, ly: integer; var lBuff: RGBQuadp; var lImage: TImage); //best general var TempBitmap: TBitmap; begin TempBitmap := TBitmap.Create; TempBitmap.Width := lx; TempBitmap.Height := ly; Draw32Bitmap(TempBitmap.Canvas.Handle, lx, ly,lBuff ); lImage.Picture.Bitmap := TempBitmap; TempBitmap.Free; end; //end windows specific {$ENDIF} procedure ScaleStretch(lSrcHt,lSrcWid: integer; lInXYRatio: single; var lRGBBuff: RGBQuadp; var lImage: TImage); var lInBuff,lBuff: ByteP; lOutRGBBuff: RGBQuadp; lOutWid,lOutHt: integer; lPos,xP,yP,yP2,xP2,t,z, z2,iz2,w1,w2,w3,w4,lTopPos,lBotPos, lINSz, lDstWidM,x,y: integer; lXRatio,lYRatio: single; begin lInBuff:= ByteP(lRGBBuff); yP:=0; lXRatio := lInXYRatio; lYRatio := lInXYRatio; lInSz := lSrcWid *lSrcHt; lOutwid := round(lSrcWid*lXRatio); lOutHt := round(lSrcHt*lYRatio); // //showmessage(inttostr(lOutwid)+' '+inttostr(lOutHt)+' '+floattostr(lXRatio)+' '+floattostr(lYRatio)); if (lOutwid < 2) or (lOutHt < 2) then exit; xP2:=((lSrcWid-1)shl 15)div (lOutWid -1 ); yP2:=((lSrcHt-1)shl 15)div (lOutHt -1); lPos := 1; lDstWidM := lOutWid - 1; getmem(lBuff, lOutHt*lOutWid*4); lInSz := lInSz * 4; //32bytesperpixel for y:=0 to lOutHt-1 do begin xP:= 0; lTopPos:=lSrcWid *(yP shr 15) *4; //top row if yP shr 16<lSrcHt-1 then lBotPos:=lSrcWid *(yP shr 15+1) *4 //bottom column else lBotPos:=lTopPos; z2:=yP and $7FFF; iz2:=$8000-z2; x := 0; while x < lOutWid do begin t:=((xP shr 15) * 4); if ((lBotPos+t+8{999+}) > lInSz) or ((lTopPos+t) < 0) then begin lBuff^[lPos] :=0; inc(lPos); //reds lBuff^[lPos] :=0; inc(lPos); //greens lBuff^[lPos] :=0; inc(lPos); //blues lBuff^[lPos] :=0; inc(lPos); //reserved end else begin z:=xP and $7FFF; w2:=(z*iz2)shr 15; w1:=iz2-w2; w4:=(z*z2)shr 15; w3:=z2-w4; //burp ScaleStretch 10/2009 {$IFDEF Darwin} lBuff^[lPos] :=0; inc(lPos); //red lBuff^[lPos] :=(lInBuff^[lTopPos+t+2]*w1+lInBuff^[lTopPos+t+6]*w2+lInBuff^[lBotPos+t+2]*w3+lInBuff^[lBotPos+t+6]*w4)shr 15; inc(lPos); //green lBuff^[lPos] := (lInBuff^[lTopPos+t+3]*w1+lInBuff^[lTopPos+t+7]*w2+lInBuff^[lBotPos+t+3]*w3+lInBuff^[lBotPos+t+7]*w4)shr 15; inc(lPos); //reserved lBuff^[lPos] :=(lInBuff^[lTopPos+t+4]*w1+lInBuff^[lTopPos+t+8]*w2+lInBuff^[lBotPos+t+4]*w3+lInBuff^[lBotPos+t+8]*w4)shr 15; inc(lPos); {$ELSE} lBuff^[lPos] :=(lInBuff^[lTopPos+t+1]*w1+lInBuff^[lTopPos+t+5]*w2 +lInBuff^[lBotPos+t+1]*w3+lInBuff^[lBotPos+t+5]*w4)shr 15; inc(lPos); //red lBuff^[lPos] :=(lInBuff^[lTopPos+t+2]*w1+lInBuff^[lTopPos+t+6]*w2 +lInBuff^[lBotPos+t+2]*w3+lInBuff^[lBotPos+t+6]*w4)shr 15; inc(lPos); //green lBuff^[lPos] :=(lInBuff^[lTopPos+t+3]*w1+lInBuff^[lTopPos+t+7]*w2 +lInBuff^[lBotPos+t+3]*w3+lInBuff^[lBotPos+t+7]*w4)shr 15; inc(lPos); //blue lBuff^[lPos] :=0; inc(lPos); //reserved {$ENDIF} end; Inc(xP,xP2); inc(x); end; //inner loop Inc(yP,yP2); end; lOutRGBBuff := RGBQuadp(lBuff); DrawBMP( lOutWid, lOutHt, lOutRGBBuff, lImage ); freemem(lBuff); end; procedure SetDimension32(lInPGHt,lInPGWid:integer; lBuff: RGBQuadp; var lBackgroundImg: TBGImg; var lImage: TImage; lPanel: TScrollBox); var lZoom,lZoomY,lZoomX,lY,lLen,lSrc,lDest: integer; lTBuff: RGBQuadp; begin //first, compute zoom if (lPanel = nil) then lImage.Tag := 100 else if (lPanel.Tag < 1) then begin//autosize lZoomY := round(100*(lPanel.Height-8)/lInPGHt); lZoomX := round(100*(lPanel.Width-8)/lInPGWid); if lZoomX < lZoomY then lZoom := lZoomX else lZoom := lZoomY; if lZoom < 1 then //nearest integer e.g. 100% or 200%, not 148% lZoom := 100; lImage.Tag := lZoom; end; if (lImage.Tag < 1) then lImage.Tag := 100 ; //next draw bitmap if lBuff = nil then begin getmem(lTBuff,lInPGHt*lInPGWid*4); Fillchar(lTBuff^,lInPGHt*lInPGWid*4,0); //set all to zero DrawBMP( lInPGWid, lInPGHt, lTBuff, lImage); freemem(lTBuff); end else if (lImage.Tag = 100) or (lPanel = nil) then begin getmem(lTBuff,lInPGHt*lInPGWid*4); lLen := lInPGWid*4; lSrc := 1; lDest := ((lInPGHt-1)*lInPGWid)+1; for lY := 1 to lInPGHt do begin //svn Move(Pointer(lBuff^[lSrc]),Pointer(lTBuff^[lDest]),lLen); Move(lBuff^[lSrc],lTBuff^[lDest],lLen); lSrc := lSrc + lInPGWid; lDest := lDest - lInPGWid; end; DrawBMP( lInPGWid, lInPGHt, lTBuff, lImage); freemem(lTBuff); //3/2011- the following code creates problems for "toInt" scaling: lImage.Tag := lBackgroundImg.ZoomPct; end else begin //not 100% lZoom := lImage.Tag; getmem(lTBuff,lInPGHt*lInPGWid*4); lLen := lInPGWid*4; lSrc := 1; lDest := ((lInPGHt-1)*lInPGWid)+1; for lY := 1 to lInPGHt do begin //Move(Pointer(lBuff^[lSrc]),Pointer(lTBuff^[lDest]),lLen); Move(lBuff^[lSrc],lTBuff^[lDest],lLen); lSrc := lSrc + lInPGWid; lDest := lDest - lInPGWid; end; if lZoom = 100 then DrawBMP( lInPGWid, lInPGHt, lTBuff, lImage) else begin if gBGImg.StretchQuality = sqHigh then //bilinear smoothed zoom ScaleStretch(lInPGHt,lInPGWid,lZoom/100,lTBuff, lImage) else //nearest neighbor DrawBMPZoom( lInPGWid, lInPGHt, lZoom, lTBuff, lImage) end; freemem(lTBuff);//flip lImage.Tag := lZoom; end; end; procedure FindImgMinMax8 (var lHdr: TMRIcroHdr; var lMini,lMaxi: integer); var lInc: integer; begin if (lHdr.ImgBufferBPP <> 1) or (lHdr.ImgBufferItems < 1) then exit; lMini := lHdr.ImgBuffer^[1]; lMaxi := lHdr.ImgBuffer^[1]; for lInc := 1 to lHdr.ImgBufferItems do begin if lHdr.ImgBuffer^[lInc] > lMaxi then lMaxi := lHdr.ImgBuffer^[lInc]; if lHdr.ImgBuffer^[lInc] < lMini then lMini := lHdr.ImgBuffer^[lInc]; end; end; //FindImgMinMax8 procedure FindImgMinMax16 (var lHdr: TMRIcroHdr; var lMini,lMaxi: integer); //very fast routine for finding brightest and darkest intensity... var lImgSamples,lInc,lFinalVal: integer; l16Buf: SmallIntP; begin if (lHdr.ImgBufferBPP <> 2) or (lHdr.ImgBufferItems < 1) then exit; lImgSamples := lHdr.ImgBufferItems; lInc:=1; l16Buf := SmallIntP(lHdr.ImgBuffer ); lMaxI := l16Buf^[lImgSamples]; lMinI := lMaxi; lFinalVal := lMaxi; l16Buf^[lImgSamples]:=32767; // set last value to the maximum integer value while true do // no check here at all now begin while (lMaxI>l16Buf^[lInc]) and (l16Buf^[lInc] >= lMini) do // stop for a >= value inc(lInc); if lInc=lImgSamples then begin l16Buf^[lImgSamples]:=lFinalVal; exit; // check to see if new max is actually end of data end; if l16Buf^[lInc] >lMaxi then lMaxI:=l16Buf^[lInc]; if l16Buf^[lInc] < lMini then lMini:=l16Buf^[lInc]; inc(lInc); end; end; //FindImgMinMax16 procedure FindImgMinMax32 (var lHdr: TMRIcroHdr; var lMin,lMax: single); var lInc: integer; l32Buf : SingleP; begin if (lHdr.ImgBufferBPP <> 4) or (lHdr.ImgBufferItems < 2) then exit; l32Buf := SingleP(lHdr.ImgBuffer ); //if specialsingle(lHdr.MRIcroHdr.gMultiBuf[1]) then lHdr.MRIcroHdr.gMultiBuf[1] := 0.0; lMin := l32Buf^[1]; lMax := l32Buf^[1]; for lInc := 2 to lHdr.ImgBufferItems do begin if (l32Buf^[lInc] > lMax) then lMax := l32Buf^[lInc]; if (l32Buf^[lInc] < lMin) then lMin := l32Buf^[lInc]; end; end; //FindImgMinMax32 function ImgVaries ( var lHdr: TMRIcroHdr): boolean; var lF: single; lI,lPos: integer; l32Buf : SingleP; l16Buf : SmallIntP; begin result := false; if lHdr.ImgBufferItems = 2 then exit; result := true; //assume variance... if lHdr.ImgBufferBPP = 4 then begin //32bit l32Buf := SingleP(lHdr.ImgBuffer ); lF := l32Buf^[1]; for lPos := 2 to lHdr.ImgBufferItems do if l32Buf^[lPos] <> lF then exit; end else if lHdr.ImgBufferBPP = 2 then begin //if 16bit ints l16Buf := SmallIntP(lHdr.ImgBuffer ); lI := l16Buf^[1]; for lPos := 2 to lHdr.ImgBufferItems do if l16Buf^[lPos] <> lI then exit; end else if lHdr.ImgBufferBPP = 1 then begin //if 16bit ints lI := lHdr.ImgBuffer^[1]; for lPos := 2 to lHdr.ImgBufferItems do if lHdr.ImgBuffer^[lPos] <> lI then exit; end else showmessage('ImgVaries error: Unsupported format'); result := false; //entire image has no variability... end; procedure CreateHisto (var lHdr: TMRIcroHdr; var lHisto: HistoRA); var lModShl10,lMinI,lC: integer; lMod,lRng: double {was extended}; l32Buf : SingleP; l16Buf : SmallIntP; begin if lHdr.ImgBufferItems = 0 then exit; for lC := 0 to kHistoBins do lHisto[lC] := 0; if lHdr.ImgBufferBPP = 4 then begin //32bit l32Buf := SingleP(lHdr.ImgBuffer ); lRng := lHdr.GlMaxUnscaledS - lHdr.GlMinUnscaledS; if lRng > 0 then lMod := (kHistoBins)/lRng else lMod := 0; for lC := 1 to lHdr.ImgBufferItems do inc(lHisto[round((l32Buf^[lC]-lHdr.GlMinUnscaledS)*lMod)]); end else {if lHdr.g16Sz >= lHdr.ScrnBufferSz then}begin //<>32bit.. integer lMinI := round(lHdr.GlMinUnscaledS); lRng := lHdr.GlMaxUnscaledS - lHdr.GlMinUnscaledS; if lRng > 0 then lMod := (kHistoBins)/lRng else lMod := 0; lModShl10 := trunc(lMod * 1024); if lHdr.ImgBufferBPP = 2 then begin //if 16bit ints l16Buf := SmallIntP(lHdr.ImgBuffer ); for lC := 1 to lHdr.ImgBufferItems do inc(lHisto[((l16Buf^[lC]-lMinI)*lModShl10)shr 10]) end else //else 8 bit data for lC := 1 to lHdr.ImgBufferItems do inc(lHisto[((lHdr.ImgBuffer^[lC]-lMinI)*lModShl10)shr 10]); end; //not 32bit end; function BinCenter (lBin: integer; var lHdr: TMRIcroHdr): single; begin result := (lHdr.GlMaxUnscaledS - lHdr.GlMinUnscaledS)/(kHistoBins-1); //range div bins result := (lBin * result)+ lHdr.GlMinUnscaledS+ (0.5*result); end; procedure TextReportHisto (var lHdr: TMRIcroHdr); var lC: integer; var lHisto: HistoRA; begin CreateHisto (lHdr, lHisto); TextForm.MemoT.Lines.Clear; TextForm.MemoT.Lines.add('#Histogram summary ~ Approximate Values'); TextForm.MemoT.Lines.add('#Image intensity range: '+realtostr(lHdr.GlMinUnscaledS,3)+'..'+realtostr(lHdr.GlMaxUnscaledS,3)); TextForm.MemoT.Lines.add('#BinNumber'+kTextSep+'BinCenter'+kTextSep+'BinCount'); for lC := 0 to kHistoBins do TextForm.MemoT.Lines.Add( inttostr(lC) + kTextSep +realtostr(BinCenter(lC,lHdr),3) +kTextSep+ inttostr(lHisto[lC]) ); TextForm.Show; end; procedure DrawHistogram (var lHdr: TMRIcroHdr; var lImage: TImage); var lPGHt, lPGWid,lIntenBarHt,lStripe,lBarBorder,lnStripes,lHorBarTop,lBarHt, l005Pct,ln005Pct,l02Pct,ln02Pct,l0005Pct,ln0005Pct,l001Pct,ln001Pct,l01Pct,ln01Pct,lMaxFreq,lMaxBarHt,lHistoPos,lPrevHistoPos,lFreq,lPos,lTotFreq: integer; lPct: double; lHisto: HistoRA; begin lPGWid := lImage.Width; lPGHt := lImage.Height; SetDimension32(lPGHt,lPGWid,nil,gBGImg,lImage,nil); lImage.Canvas.Font.Name := 'Arial'; (*if lPGWid < 100 then lImage.Canvas.Font.Size := 9 else if lPGWid < 200 then lImage.Canvas.Font.Size := 12 else lImage.Canvas.Font.Size := 14;*) lImage.Canvas.Font.Size := gBGImg.FontSize; CreateHisto (lHdr, lHisto); lBarBorder := 6; lIntenBarHt := 14; DrawFrame(lImage, 0, 0,lPGWid,lPGHt); lHorBarTop := lPGHt - lBarBorder-lIntenBarHt-lImage.Canvas.TextHeight('X'); lMaxBarHt := lHorBarTop - lBarBorder- lBarBorder- lBarBorder; lMaxFreq := 0; lnStripes := lPGWid - (lBarBorder+lBarBorder+1); if gBGImg.XBarClr = clWhite then lImage.canvas.pen.color := clBlack//clWhite;//gLUT[lClr].rgbRed+(gLUT[lClr].rgbGreen shl 8)+(gLUT[lClr].rgbBlue shl 16); else lImage.canvas.pen.color := gBGImg.XBarClr;//clWhite;//gLUT[lClr].rgbRed+(gLUT[lClr].rgbGreen shl 8)+(gLUT[lClr].rgbBlue shl 16); lImage.Canvas.Font.Color := lImage.canvas.pen.color; lImage.Canvas.Brush.Style := bsSolid; lImage.Canvas.Pen.Width := 1; lImage.Canvas.Pen.Style := psDot; lImage.canvas.moveto(lBarBorder,lHorBarTop-lMaxBarHt-1); lImage.canvas.lineto(lPGWid-lBarBorder,lHorBarTop-lMaxBarHt-1); lImage.Canvas.Brush.Style := bsClear; if (lnStripes < 1) then exit; //Next: compute scale find freq in graph - not same as image, as with large graphs bars resampled lPrevHistoPos := 0; lTotFreq := 0; for lStripe := 0 to lnStripes do begin lHistoPos := round(lStripe / lnStripes*kHistoBins); if lPrevHistoPos > lHistoPos then lPrevHistoPos := lHistoPos; for lPos := lPrevHistoPos to lHistoPos do lTotFreq := lTotFreq+lHisto[lPos]; lPrevHistoPos := lHistoPos+1; end; ln02Pct := 0; ln01Pct := 0; ln005Pct := 0; ln001Pct := 0; ln0005Pct := 0; l02Pct := round(lTotFreq/50); l01Pct := round(lTotFreq/100); l005Pct := round(lTotFreq/200); l001Pct := round(lTotFreq/1000); l0005Pct := round(lTotFreq/2000); lPrevHistoPos := 0; for lStripe := 0 to lnStripes do begin lHistoPos := round(lStripe / lnStripes*kHistoBins); if lPrevHistoPos > lHistoPos then lPrevHistoPos := lHistoPos; lFreq := 0; for lPos := lPrevHistoPos to lHistoPos do lFreq := lFreq+lHisto[lPos]; if lFreq > lMaxFreq then lMaxFreq := lFreq; if lFreq > l02Pct then inc(ln02Pct); if lFreq > l01Pct then inc(ln01Pct); if lFreq > l005Pct then inc(ln005Pct); if lFreq > l001Pct then inc(ln001Pct); if lFreq > l0005Pct then inc(ln0005Pct); //lTotFreq := lTotFreq + lFreq; lPrevHistoPos := lHistoPos+1; end; lImage.Canvas.Pen.Style := psSolid; if ln02Pct > 5 then lPct := 5 else if ln01Pct > 5 then lPct := 2 else if ln005Pct > 5 then lPct := 1 else if ln001Pct > 4 then lPct := 0.5 else if ln0005Pct > 4 then lPct := 0.01 else lPct := 0.05; lMaxFreq :=round( lTotFreq * (lPct/100)); if (lMaxFreq = 0) then exit; //Next: draw bars lImage.canvas.TextOut(lPGWid div 2,lHorBarTop-lMaxBarHt-1-6,' '+floattostr(lPct)+'% '); lImage.Canvas.Brush.Style := bsClear; lPrevHistoPos := 0; for lStripe := 0 to lnStripes do begin lHistoPos := round(lStripe / lnStripes*kHistoBins); if lPrevHistoPos > lHistoPos then lPrevHistoPos := lHistoPos; lFreq := 0; for lPos := lPrevHistoPos to lHistoPos do lFreq := lFreq+lHisto[lPos]; if lFreq > lMaxFreq then begin lFreq := lMaxFreq; lImage.canvas.moveto(lBarBorder+lStripe,lHorBarTop-lMaxBarHt-8); lImage.canvas.lineto(lBarBorder+lStripe,lHorBarTop-lMaxBarHt-6); lImage.canvas.moveto(lBarBorder+lStripe,lHorBarTop-lMaxBarHt-4); lImage.canvas.lineto(lBarBorder+lStripe,lHorBarTop-lMaxBarHt-2); end; lBarHt := round(lFreq/lMaxFreq*lMaxBarHt); lImage.canvas.moveto(lBarBorder+lStripe,lHorBarTop); lImage.canvas.lineto(lBarBorder+lStripe,lHorBarTop-lBarHt); lPrevHistoPos := lHistoPos+1; end; //draw each stripe intenBar(lImage,lHdr,3,Raw2ScaledIntensity(lHdr,lHdr.GlMinUnScaledS),Raw2ScaledIntensity(lHdr,lHdr.GlMaxUnscaledS)); end; procedure Balance (var lHdr: TMRIcroHdr); var lPct,lNum,lC: integer; lHisto: HistoRA; lBlackAUtoBal,lWhiteAutoBal: integer; begin //dsa if lHdr.ImgBufferItems = 0 then exit; CreateHisto (lHdr, lHisto); lPct := (lHdr.ImgBufferItems *2) div 100; lNum := 0; lC := kHistoBins; repeat lNum := lNum + lHisto[lC]; dec(lC); until (lC = 0) or (lNum >= lPct); if (lNum >= lPct) and (lC > 0) then lWHiteAUtoBal:= lC else begin lC := kHistoBins; repeat lNum := lHisto[lC]; dec(lC); until (lC = 0) or (lNum > 0); if lC = 0 then lWHiteAUtoBal := kHistoBins else lWHiteAUtoBal := lC; end; lNum := 0; lC := 0; repeat lNum := lNum + lHisto[lC]; inc(lC); until (lC >= kHistoBins) or (lNum >= lPct); if (lNum >= lPct) and (lC < kHistoBins) and (lC >2) then lBlackAutoBal := lC else lBlackAutoBal := 2; if (lWHiteAUtoBal-lBlackAutoBal) < (kHistoBins/20) then begin //5% of range.. lBlackAutoBal := 2; lWHiteAUtoBal := kHistoBins; end; lHdr.AutoBalMaxUnscaled := ((lWhiteAutoBal/kHistoBins)*(lHdr.GlMaxUnscaledS-lHdr.GlMinUnscaledS))+lHdr.GlMinUnscaledS; lHdr.AutoBalMinUnscaled := ((lBlackAutoBal/kHistoBins)*(lHdr.GlMaxUnscaledS-lHdr.GlMinUnscaledS))+lHdr.GlMinUnscaledS; //only apply rounding if there is a large difference - e.g. if range is 0..1 then rounding will hurt if (lHdr.ImgBufferBPP < 4) and ((lHdr.AutoBalMaxUnscaled-lHdr.AutoBalMinUnscaled) > 50) then begin //round integer values lHdr.AutoBalMinUnscaled := round(lHdr.AutoBalMinUnscaled); lHdr.AutoBalMaxUnscaled := round(lHdr.AutoBalMaxUnscaled); end; end; //proc Balance procedure ReturnMinMax (var lHdr: TMRIcroHdr; var lMin,lMax: single; var lFiltMin8bit, lFiltMax8bit: integer); var lSwap,lMinS,lMaxS {,lHalfBit}: single; begin lFiltMin8bit := 0; lFiltMax8bit := 255; lMinS := lHdr.WindowScaledMin; lMaxS := lHdr.WindowScaledMax; if lMinS > lMaxS then begin //swap lSwap := lMinS; lMinS := lMaxS; lMaxS := lSwap; end;//swap lMin := (Scaled2RawIntensity(lHdr, lMinS)); lMax := (Scaled2RawIntensity(lHdr, lMaxS)); //if lMin = lMax then exit; if (lHdr.LutFromZero) then begin if (lMinS > 0) and (lMaxS <> 0) then begin //lMin := Scaled2RawIntensity(lHdr, 0); lFiltMin8bit := round(lMinS/lMaxS*255); //lMinS := - lHalfBit;//0; lHdr.Zero8Bit := 0; end else if (lMaxS < 0) and (lMinS <> 0) then begin //lMax := Scaled2RawIntensity(lHdr, -0.000001); lFiltMax8bit := 255-round(lMaxS/lMinS*255); //lMaxS := lHalfBit; //0; //lFiltMax8bit := (Scaled2RawIntensity(lHdr, lHdr.WindowScaledMax)); end; //> 0 end; //LUTfrom Zero lHdr.Zero8Bit := lMinS; lHdr.Slope8bit := (lMaxS-lMinS)/255; end; //ReturnMinMax procedure FilterScrnImg (var lHdr: TMRIcroHdr); var lInc,lItems,lFiltMin8bit,lFiltMax8bit: integer; lMinS,lMaxS,lScale: single; begin ReturnMinMax(lHdr,lMinS,lMaxS,lFiltMin8bit,lFiltMax8bit); lItems :=lHdr.ScrnBufferItems; if lItems < 1 then exit; if lFiltMax8Bit < 255 then begin lFiltMin8bit := 255-lFiltMax8bit; lFiltMax8Bit := 255; end; lScale := (lFiltMax8bit-lFiltMin8bit)/255; if (lFiltMin8bit > 0) or (lFiltMax8bit < 255) then for lInc := 1 to lItems do if lHdr.ScrnBuffer^[lInc] <> 0 then lHdr.ScrnBuffer^[lInc] := lFiltMin8bit+round(lHdr.ScrnBuffer^[lInc]*lScale); end; //FilterScrnImg procedure RescaleImgIntensity8(var lHdr: TMRIcroHdr ); var lRng: single; lLUTra: array[0..255] of byte; lMax,lMin,lSwap,lMod: single; lFiltMin8bit,lFiltMax8bit,lInc: integer; begin if (lHdr.ImgBufferItems < 2) or (lHdr.ImgBufferBPP <> 1) then exit; if (lHdr.UsesCustomPaletteRandomRainbow) then begin createLutLabel (lHdr.LUT, abs(lHdr.WindowScaledMax-lHdr.WindowScaledMin)/100); for lInc := 1 to lHdr.ScrnBufferItems do lHdr.ScrnBuffer^[lInc] := lHdr.ImgBuffer^[lInc]; (* l16Buf := SmallIntP(lHdr.ImgBuffer ); for lInc := 1 to lHdr.ScrnBufferItems do lHdr.ScrnBuffer^[lInc] := ((l16Buf^[lInc]-1) mod 100)+1; *) exit; end; ReturnMinMax (lHdr, lMin,lMax,lFiltMin8bit,lFiltMax8bit); lRng := (lMax - lMin); if lRng <> 0 then lMod := abs({trunc}(((254)/lRng))) else lMod := 0; if lMin > lMax then begin //maw lSwap := lMin; lMin := lMax; lMax := lSwap; end; for lInc := 0 to 255 do begin if lInc < lMin then lLUTra[lInc] := 0 else if lInc >= lMax then lLUTra[lInc] := 255 else lLUTra[lInc] := trunc(((lInc-lMin)*lMod)+1); end; //fill LUT if lRng < 0 then //inverted scale... e.g. negative scale factor for lInc := 0 to 255 do lLUTra[lInc] := 255-lLUTra[lInc]; for lInc := 1 to lHdr.ScrnBufferItems do lHdr.ScrnBuffer^[lInc] := lLUTra[lHdr.ImgBuffer^[lInc]]; end;//proc RescaleImgIntensity8 procedure ReturnMinMaxInt (var lHdr: TMRIcroHdr; var lMin,lMax, lFiltMin8bit, lFiltMax8bit: integer); var lMinS,lMaxS: single; begin ReturnMinMax (lHdr, lMinS,lMaxS,lFiltMin8bit, lFiltMax8bit); lMin := round(lMinS); lMax := round(lMaxS); end; procedure RescaleImgIntensity16(var lHdr: TMRIcroHdr ); var lRng: single; lBuff: bytep0; l16Buf : SmallIntP; lFiltMin8bit,lFiltMax8bit,lRngi,lMin16Val,lMax,lMin,lSwap,lModShl10,lInc,lInt: integer; begin if (lHdr.ImgBufferBPP <> 2) or (lHdr.ImgBufferItems < 2) then exit; if (lHdr.UsesCustomPaletteRandomRainbow) then begin createLutLabel (lHdr.LUT, abs(lHdr.WindowScaledMax-lHdr.WindowScaledMin)/100); l16Buf := SmallIntP(lHdr.ImgBuffer ); for lInc := 1 to lHdr.ScrnBufferItems do lHdr.ScrnBuffer^[lInc] := ((l16Buf^[lInc]-1) mod 100)+1; exit; end; ReturnMinMaxInt (lHdr, lMin,lMax,lFiltMin8bit,lFiltMax8bit); lRng := lMax - lMin; if lRng <> 0 then lModShl10 := abs( trunc(((254)/lRng)* 1024)) else lModShl10 := 0; if lMin > lMax then begin lSwap := lMin; lMin := lMax; lMax := lSwap; end; lMin16Val := trunc(lHdr.GlMinUnscaledS); lRngi := (1+ trunc(lHdr.GlMaxUnscaledS))-lMin16Val; getmem(lBuff, lRngi+1); //+1 if the only values are 0,1,2 the range is 2, but there are 3 values! for lInc := 0 to (lRngi) do begin //build lookup table lInt := lInc+lMin16Val; if lInt >= lMax then lBuff^[lInc] := (255) else if lInt < lMin then lBuff^[lInc] := 0 else lBuff^[lInc] := (((lInt-lMin)*lModShl10) shr 10)+1 ; //lBuff[lInc] := (((lInt-lMin)*lModShl10) shr 10) ; end; //build lookup table if lRng < 0 then //inverted scale... e.g. negative scale factor for lInc := 0 to lRngi do lBuff^[lInc] := 255-lBuff^[lInc]; l16Buf := SmallIntP(lHdr.ImgBuffer ); for lInc := 1 to lHdr.ImgBufferItems do lHdr.ScrnBuffer^[lInc] := lBuff^[l16Buf^[lInc]-lMin16Val] ; freemem(lBuff); //release lookup table end;//proc RescaleImgIntensity16; procedure RescaleImgIntensity32(var lHdr: TMRIcroHdr ); var lRng: double; lMod,lMax,lMin,lSwap: single {was extended}; lInc,lItems,lFiltMin8bit,lFiltMax8bit: integer; l32Buf : SingleP; begin lItems := lHdr.ImgBufferItems ; //fx(lItems,777); if (lHdr.ImgBufferBPP <> 4) or (lItems< 2) then exit; l32Buf := SingleP(lHdr.ImgBuffer ); //fx(lHdr.WindowScaledMin , lHdr.WindowScaledMax); ReturnMinMax (lHdr, lMin,lMax,lFiltMin8bit,lFiltMax8bit); //qaz lRng := (lMax - lMin); if lRng <> 0 then lMod := abs(254/lRng) else begin //June 2007 - binary contrast for lInc := 1 to lItems do begin if l32Buf^[lInc] >= lMax then lHdr.ScrnBuffer^[lInc] := 255 else //if l32Buf[lInc] < lMin then lHdr.ScrnBuffer^[lInc] := 0; end; exit; end; (*if lRng <> 0 then lMod := abs(254/lRng) else lMod := 0;*) if lMin > lMax then begin lSwap := lMin; lMin := lMax; lMax := lSwap; end; lMin := lMin - abs(lRng/255);//lMod; //showmessage(realtostr(lMin,3)+' '+realtostr(lMax,3)); begin//not SSE for lInc := 1 to lItems do begin if l32Buf^[lInc] > lMax then lHdr.ScrnBuffer^[lInc] := 255 else if l32Buf^[lInc] < lMin then lHdr.ScrnBuffer^[lInc] := 0 //alfa else begin lHdr.ScrnBuffer^[lInc] := round ((l32Buf^[lInc]-lMin)*lMod); end; end; //for each voxel end; // SSE-vs-x87 choice //next - flip intensity range OPTIONAL if lRng < 0 then //inverted scale... e.g. negative scale factor for lInc := 1 to lItems do lHdr.ScrnBuffer^[lInc] := 255-lHdr.ScrnBuffer^[lInc]; end; //RescaleImgIntensity32 function MirrorImgBuffer(var lHdr: TMRIcroHdr ): boolean; var lXPos,lYPos,lZPos,lX,lY,lZ,lHlfX,lLineOffset: integer; lTemp32: single; lTemp16: SmallInt; lTemp: byte; l32: SingleP; l16: SmallIntP; begin result := false; lX := lHdr.NIFTIhdr.Dim[1]; lY := lHdr.NIFTIhdr.Dim[2]; lZ := lHdr.NIFTIhdr.Dim[3]; if lHdr.NIFTIhdr.Dim[4] > 1 then begin Showmessage('Can not mirror 4D data : '+lHdr.HdrFileName); exit; end; if (lHdr.ImgBufferItems < (lX*lY*lZ)) or (lX < 2) then begin Showmessage('Unsupported filetype : '+lHdr.HdrFileName); exit; end; lHlfX := lX div 2; lLineOffset := 0; //for each datatype... if lHdr.ImgBufferBPP = 4 then begin l32 := SingleP(lHdr.ImgBuffer); for lZPos := 1 to lZ do begin for lYPos := 1 to lY do begin for lXPos := 1 to lHlfX do begin lTemp32 := l32^[lXPos+lLineOffset]; l32^[lXPos+lLineOffset] := l32^[1+lX-lXPos+lLineOffset]; l32^[1+lX-lXPos+lLineOffset] := lTemp32; end; //for X lLineOffset := lLineOffset + lX; end; //for Y end; //for Z end else if lHdr.ImgBufferBPP = 2 then begin l16 := SmallIntP(lHdr.ImgBuffer); for lZPos := 1 to lZ do begin for lYPos := 1 to lY do begin for lXPos := 1 to lHlfX do begin lTemp16 := l16^[lXPos+lLineOffset]; l16^[lXPos+lLineOffset] := l16^[1+lX-lXPos+lLineOffset]; l16^[1+lX-lXPos+lLineOffset] := lTemp16; end; //for X lLineOffset := lLineOffset + lX; end; //for Y end; //for Z end else if lHdr.ImgBufferBPP = 1 then begin for lZPos := 1 to lZ do begin for lYPos := 1 to lY do begin for lXPos := 1 to lHlfX do begin lTemp := lHdr.ImgBuffer^[lXPos+lLineOffset]; lHdr.ImgBuffer^[lXPos+lLineOffset] := lHdr.ImgBuffer^[1+lX-lXPos+lLineOffset]; lHdr.ImgBuffer^[1+lX-lXPos+lLineOffset] := lTemp; end; //for X lLineOffset := lLineOffset + lX; end; //for Y end; //for Z end else //unsupported bits-per-pixel dataformat Showmessage('Unsupported BPP ='+inttostr(lHdr.ImgBufferBPP) ); result := true; end; //proc MirrorImgBuffer procedure MirrorScrnBuffer(var lBackgroundImg: TBGImg; var lHdr: TMRIcroHdr ); var lXPos,lYPos,lZPos,lX,lY,lZ,lHlfX,lLineOffset: integer; lTemp: byte; begin lX := lBackgroundImg.ScrnDim[1]; lY := lBackgroundImg.ScrnDim[2]; lZ := lBackgroundImg.ScrnDim[3]; if (lHdr.ScrnBufferItems < (lX*lY*lZ)) or (lX < 2) then exit; lHlfX := lX div 2; lLineOffset := 0; for lZPos := 1 to lZ do begin for lYPos := 1 to lY do begin for lXPos := 1 to lHlfX do begin lTemp := lHdr.ScrnBuffer^[lXPos+lLineOffset]; lHdr.ScrnBuffer^[lXPos+lLineOffset] := lHdr.ScrnBuffer^[1+lX-lXPos+lLineOffset]; lHdr.ScrnBuffer^[1+lX-lXPos+lLineOffset] := lTemp; end; //for X lLineOffset := lLineOffset + lX; end; //for Y end; //for Z end; //proc MirrorImScrnBuffer procedure FindMatrixPt (lX,lY,lZ: single; var lXout,lYOut,lZOut: single; var lMatrix: TMatrix); begin lXOut := (lX*lMatrix.matrix[1,1])+(lY*lMatrix.matrix[1,2])+(lZ*lMatrix.matrix[1,3])+lMatrix.matrix[1,4]; lYOut := (lX*lMatrix.matrix[2,1])+(lY*lMatrix.matrix[2,2])+(lZ*lMatrix.matrix[2,3])+lMatrix.matrix[2,4]; lZOut := (lX*lMatrix.matrix[3,1])+(lY*lMatrix.matrix[3,2])+(lZ*lMatrix.matrix[3,3])+lMatrix.matrix[3,4]; end; procedure CheckMaxMin(var lX,lY,lZ,lXMax,lYMax,lZMax,lXMin,lYMin,lZMin: single); begin if lX > lXMax then lXMax := lX; if lY > lYMax then lYMax := lY; if lZ > lZMax then lZMax := lZ; if lX < lXMin then lXMin := lX; if lY < lYMin then lYMin := lY; if lZ < lZMin then lZMin := lZ; end; function FindOriMM (lX1,lY1,lZ1,lX2,lY2,lZ2: integer; var lMatrix: TMatrix): single; var lXdx,lYdx,lZdx,lXmm1,lYmm1,lZmm1,lXmm2,lYmm2,lZmm2: single; begin FindMatrixPt(lX1,lY1,lZ1,lXmm1,lYmm1,lZmm1,lMatrix); FindMatrixPt(lX2,lY2,lZ2,lXmm2,lYmm2,lZmm2,lMatrix); lXdx := abs(lXmm1-lXmm2); lYdx := abs(lYmm1-lYmm2); lZdx := abs(lZmm1-lZmm2); if (lXdx > lYdx) and (lXdx > lZdx) then begin //X greatest result := lXmm1; end else if (lYdx > lZdx) then begin //Y greatest result := lYmm1; end else begin //Z greatest result := lZmm1; end; result := -(result); end; procedure FindMatrixBounds (var lBGImg: TBGImg; var lHdr: TMRIcroHdr; lReslice: boolean); label 121; var lMatrix: TMatrix; lPos,lPass: integer; lXc,lYc,lZc,lXmin,lXMax,lYMin,lYMax,lZMin,lZMax,lX,lY,lZ,lmmMin,lDimMMMax: single; begin if not lReslice then begin //Dec06 lBGImg.ScrnDim[1] := lHdr.NIFTIhdr.Dim[1];//+0.5 Dec06 lBGImg.ScrnDim[2] := lHdr.NIFTIhdr.Dim[2];//+0.5 Dec06 lBGImg.ScrnDim[3] := lHdr.NIFTIhdr.Dim[3];//+0.5 Dec06 lBGImg.ScrnMM[1] := lHdr.NIFTIhdr.pixdim[1]; lBGImg.ScrnMM[2] := lHdr.NIFTIhdr.pixdim[2]; lBGImg.ScrnMM[3] := lHdr.NIFTIhdr.pixdim[3]; //Sept07 -estimate origin lBGImg.ScrnOri[1] := lBGImg.ScrnDim[1] div 2; lBGImg.ScrnOri[2] := lBGImg.ScrnDim[2] div 2; lBGImg.ScrnOri[3] := lBGImg.ScrnDim[3] div 2; if lHdr.NIfTItransform then begin lBGImg.ScrnOri[1] := 0; lBGImg.ScrnOri[2] := 0; lBGImg.ScrnOri[3] := 0; mm2Voxel (lBGImg.ScrnOri[1],lBGImg.ScrnOri[2],lBGImg.ScrnOri[3], lBGImg.invMat);//vcx (* lMatrix := lHdr.Mat; if lBGImg.ScrnMM[1] <> 0 then lBGImg.ScrnOri[1] := 1+FindOriMM (0,0,0,lBGImg.ScrnDim[1]-1,0,0, lMatrix)/lBGImg.ScrnMM[1]; if lBGImg.ScrnMM[2] <> 0 then lBGImg.ScrnOri[2] := 1+FindOriMM (0,0,0,0,lBGImg.ScrnDim[2]-1,0, lMatrix)/lBGImg.ScrnMM[2]; if lBGImg.ScrnMM[3] <> 0 then lBGImg.ScrnOri[3] := 1+FindOriMM (0,0,0,0,0,lBGImg.ScrnDim[3]-1, lMatrix)/lBGImg.ScrnMM[3]; *) end; //end estimate origin //fx(lBGImg.ScrnOri[1],lBGImg.ScrnMM[1],lBGImg.ScrnOri[3],1112); exit; end; lPass := 0; if (abs(lHdr.Mat.matrix[1,4]) > maxInt) or (abs(lHdr.Mat.matrix[2,4]) > MaxInt) or (abs(lHdr.Mat.matrix[3,4]) > maxint) then begin showmessage('Error: the origin is not plausible.'); lHdr.Mat.matrix[1,4] := 0; lHdr.Mat.matrix[2,4] := 0; lHdr.Mat.matrix[3,4] := 0; end; 121: inc(lPass); lMatrix := lHdr.Mat; FindMatrixPt(0,0,0,lX,lY,lZ,lMatrix); lXMax := lX; lYMax := lY; lZMax := lZ; lXMin := lX; lYMin := lY; lZMin := lZ; for lPos := 1 to 7 do begin if odd(lPos) then lXc := lHdr.NIFTIhdr.Dim[1]-1 else lXc := 0; if odd(lPos shr 1) then lYc := lHdr.NIFTIhdr.Dim[2]-1 else lYc := 0; if odd(lPos shr 2) then lZc := lHdr.NIFTIhdr.Dim[3]-1 else lZc := 0; //showmessage(floattostr(lXc)+' '+floattostr(lYc)+' '+floattostr(lZc) ); FindMatrixPt(lXc,lYc,lZc,lX,lY,lZ,lMatrix); CheckMaxMin(lX,lY,lZ,lXMax,lYMax,lZMax,lXMin,lYMin,lZMin); end; //fx(lXMax,lXMin,lZMax,lZMin); //next find min MM //fx(lZMin,lZMax); lmmMin := abs(lHdr.NIFTIhdr.pixdim[1]); if abs(lHdr.NIFTIhdr.pixdim[2]) < lmmMin then lmmMin := abs(lHdr.NIFTIhdr.pixdim[2]); if abs(lHdr.NIFTIhdr.pixdim[3]) < lmmMin then lmmMin := abs(lHdr.NIFTIhdr.pixdim[3]); if lmmMin = 0 then lmmMin := 1; //next find max Dim lDimMMMax := abs(lXMax-lXMin); if abs(lYMax-lYMin) > lDimMMMax then lDimMMMax := abs(lYMax-lYMin); if abs(lZMax-lZMin) > lDimMMMax then lDimMMMax := abs(lZMax-lZMin); if (1+trunc(lDimMMMax/lmmMin)) > gBGImg.MaxDim then begin //image will be too large if isotropically scalled by smallest mm, try largest mm lmmMin := lHdr.NIFTIhdr.pixdim[1]; if lHdr.NIFTIhdr.pixdim[2] > lmmMin then lmmMin := lHdr.NIFTIhdr.pixdim[2]; if lHdr.NIFTIhdr.pixdim[3] > lmmMin then lmmMin := lHdr.NIFTIhdr.pixdim[3]; if lmmMin = 0 then lmmMin := 1; if (1+trunc(lDimMMMax/lmmMin)) > gBGImg.MaxDim then begin //image will be too large if isotropically scalled by largest mm, try isotropic 1mm lmmMin := 1; end; if (1+trunc(lDimMMMax/lmmMin)) > gBGImg.MaxDim then begin //image will be too large if isotropically scaled by 1mm, find optimal scaling factor lmmMin := lDimMMMax/gBGImg.MaxDim; Showmessage('Maximum dimension is >'+inttostr(gBGImg.MaxDim)+' voxels. Therefore the image will resolution will be reduced. If you have a fast computer, you may consider increasing the ''MaxDim'' value saved in the mricron.ini file.'); //showmessage('Warning: having to downsample this large image - you may wish to view this image with MRIcro.'); end; //showmessage( floattostr(lmmMin)); //lmmMin := 3.5;// end; lBGImg.ScrnDim[1] := 1+trunc(0.5+((lXMax-lXMin)/lmmMin));//+0.5 May06 lBGImg.ScrnDim[2] := 1+trunc(0.5+((lYMax-lYMin)/lmmMin));//+0.5 May06 lBGImg.ScrnDim[3] := 1+trunc(0.5+((lZMax-lZMin)/lmmMin));//+0.5 May06 //fx(lBGImg.ScrnDim[3],lmmMin); lBGImg.ScrnMM[1] := lmmMin; lBGImg.ScrnMM[2] := lmmMin; lBGImg.ScrnMM[3] := lmmMin; //fx(lBGImg.ScrnDim[1],lBGImg.ScrnDim[2],lBGImg.ScrnDim[3]); //showmessage(floattostr(lZMin)+'...'+floattostr(lZMax)+' '+floattostr((lZMin)/lmmMin)); lBGImg.ScrnOri[1] := -(((lXMin)/lmmMin))+1; lBGImg.ScrnOri[2] := -(((lYMin)/lmmMin))+1; lBGImg.ScrnOri[3] := -(((lZMin)/lmmMin))+1; //fx(lBGImg.ScrnOri[1],lBGImg.ScrnOri[2],lBGImg.ScrnOri[3]); if (lXMin > 0) and (lYMin > 0) and (lZMin > 0) and (lPass <= 2) then begin lHdr.Mat.matrix[1,4] := -lHdr.Mat.matrix[1,4]; lHdr.Mat.matrix[2,4] := -lHdr.Mat.matrix[2,4]; lHdr.Mat.matrix[3,4] := -lHdr.Mat.matrix[3,4]; {lHdr.NIFTIhdr.srow_x[3] := -lHdr.NIFTIhdr.srow_x[3]; lHdr.NIFTIhdr.srow_y[3] := -lHdr.NIFTIhdr.srow_y[3]; lHdr.NIFTIhdr.srow_z[3] := -lHdr.NIFTIhdr.srow_z[3];} {lHdr.Mat.matrix[1,4] := 0; lHdr.Mat.matrix[2,4] := 0; lHdr.Mat.matrix[3,4] := 0; } if lPass = 1 then begin Showmessage('The origin is not in the image... check your transformation matrix - will attempt to invert offsets'); goto 121; end else if lPass = 2 then begin lHdr.Mat.matrix[1,4] := 0; lHdr.Mat.matrix[2,4] := 0; lHdr.Mat.matrix[3,4] := 0; Showmessage('The origin is not in the image... check your transformation matrix - will attempt to zero offsets'); goto 121; end else showmessage('The origin is not in the image... unable to correct.'); end; end; function mat44_inverse(var R: Tmatrix ) : TMatrix; var r11,r12,r13,r21,r22,r23,r31,r32,r33,v1,v2,v3 , deti : double; Q: TMatrix; begin r11 := R.matrix[1,1]; r12 := R.matrix[1,2]; r13 := R.matrix[1,3]; //* [ r11 r12 r13 v1 ] */ r21 := R.matrix[2,1]; r22 := R.matrix[2,2]; r23 := R.matrix[2,3]; //* [ r21 r22 r23 v2 ] */ r31 := R.matrix[3,1]; r32 := R.matrix[3,2]; r33 := R.matrix[3,3]; //* [ r31 r32 r33 v3 ] */ v1 := R.matrix[1,4]; v2 := R.matrix[2,4]; v3 := R.matrix[3,4]; //* [ 0 0 0 1 ] */ deti := r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; if( deti <> 0.0 ) then deti := 1.0 / deti ; Q.matrix[1,1] := deti*( r22*r33-r32*r23) ; Q.matrix[1,2] := deti*(-r12*r33+r32*r13) ; Q.matrix[1,3] := deti*( r12*r23-r22*r13) ; Q.matrix[1,4] := deti*(-r12*r23*v3+r12*v2*r33+r22*r13*v3 -r22*v1*r33-r32*r13*v2+r32*v1*r23) ; Q.matrix[2,1] := deti*(-r21*r33+r31*r23) ; Q.matrix[2,2] := deti*( r11*r33-r31*r13) ; Q.matrix[2,3] := deti*(-r11*r23+r21*r13) ; Q.matrix[2,4] := deti*( r11*r23*v3-r11*v2*r33-r21*r13*v3 +r21*v1*r33+r31*r13*v2-r31*v1*r23) ; Q.matrix[3,1] := deti*( r21*r32-r31*r22) ; Q.matrix[3,2] := deti*(-r11*r32+r31*r12) ; Q.matrix[3,3] := deti*( r11*r22-r21*r12) ; Q.matrix[3,4] := deti*(-r11*r22*v3+r11*r32*v2+r21*r12*v3 -r21*r32*v1-r31*r12*v2+r31*r22*v1) ; Q.matrix[4,1] := 0; Q.matrix[4,2] := 0; Q.matrix[4,3] := 0.0 ; Q.matrix[4,4] := 1;// (deti == 0.0l) ? 0.0l : 1.0l ; /* failure flag if deti == 0 */ result := Q ; end; function TestSameOrtho(var lHdr: TMRIcroHdr): boolean; var lRow,lCol: integer; begin result := false; for lRow := 1 to 3 do for lCol := 1 to 3 do if (lRow=lCol) then begin if lHdr.Mat.Matrix[lRow,lCol] <= 0 then exit; end else if lHdr.Mat.Matrix[lRow,lCol] <> 0 then exit; result := true; end; function OrthoReslice (var lBGImg: TBGImg; var lHdr: TMRIcroHdr): boolean; label 666; Type TXImg = record //Next: analyze Format Header structure rDim: array [1..3] of integer; rOri,rMM: array [1..3] of single; rSliceSz: integer; end; //TNIFTIhdr Header Structure var //lStartTime,lEndTime: DWord; lIn,lOut: TXImg; lBuffIn,lBuffOut,lBuffOutUnaligned: Bytep; lBuffIn16,lBuffOut16 : SmallIntP; lBuffIn32,lBuffOut32 : SingleP; lX,lY,lZ,lI,lPos,lOutVolItems,lInZPos,lInYPos,lOutZPos,lOutYPos,lInZPosHi,lInYPosHi: integer; lXmodLo,lXmodHi,lYmodLo,lYmodHi,lZmodLo,lZmodHi: single; lScale,lFloatPos: single; lMin,lMax: array [1..3] of integer; lLUTra: array [1..3] of LongIntp; lLUTmodRA: array [1..3] of Singlep; begin result := false; // if lHdr.ImgBufferBPP = 4 then exit; if not TestSameOrtho(lHdr) then exit; //if lHdr.ImgBufferBPP <> 1 then exit; //lStartTime := GetTickCount; for lI := 1 to 3 do begin lIn.rDim[lI] := lHdr.NIFTIhdr.dim[lI]; lIn.rMM[lI] := lHdr.NIFTIhdr.pixdim[lI]; lIn.rOri[lI] := (abs(lHdr.Mat.Matrix[lI,4]))/abs(lHdr.NIFTIhdr.pixdim[lI])+1;//May07 end; lIn.rSliceSz := lIn.rDim[1]*lIn.rDim[2]; //Output to background size for lI := 1 to 3 do begin lOut.rDim[lI] := lBGImg.ScrnDim[lI]; lOut.rMM[lI] := lBGImg.ScrnMM[lI]; lOut.rOri[lI] := lBGImg.ScrnOri[lI]; // fx(lOut.rDim[lI],lOut.rMM[lI],lOut.rOri[lI]); end; lOut.rSliceSz := lOut.rDim[1]*lOut.rDim[2]; lOutVolItems := lOut.rSliceSz * lOut.rDim[3]; //InVolSz! //find bounding box for overlay, and create lookup tables for lI := 1 to 3 do begin lScale := lOut.rMM[lI] / lIn.rMM[lI]; getmem(lLUTra[lI],lOut.rDim[lI]*4); getmem(lLUTmodra[lI],lOut.rDim[lI]*4); lMin[lI] := maxint; lMax[lI] := -1; for lPos := 1 to lOut.rDim[lI] do begin if lBGImg.OverlaySmooth then begin lFloatPos := ((lPos-lOut.rOri[lI]) *lScale)+lIn.rOri[lI] {-0.5}; lLUTra[lI]^[lPos] := trunc ( lFloatPos ); lLUTmodra[lI]^[lPos] := ( frac (lFloatPos )); end else begin lLUTra[lI]^[lPos] := round ( ((lPos-lOut.rOri[lI]) *lScale)+lIn.rOri[lI] ); lLUTmodra[lI]^[lPos] :=0;//not used end; if (lLUTra[lI]^[lPos] > 0) and (lMin[lI]=MaxInt) then lMin[lI] := lPos; if (lLUTra[lI]^[lPos] < lIn.rDim[lI]) {danger! <=} then lMax[lI] := lPos; end; end; //for lI := 1 to 3 do fx( lOut.rMM[lI],lIn.rMM[lI]); for lI := 1 to 3 do if lMin[lI] > lMax[lI] then begin showmessage ('Unusual rotation matrix - consider viewing with MRIcro.');//goto 345; //do after previous loop so we are sure all buffers used goto 666; end; lMax[1] := lMax[1] -1;{-1 as we do not want to sample past edge} ImgForm.ProgressBar1.Min := lMin[3]; ImgForm.ProgressBar1.Max := lMax[3]; //next - core if lHdr.ImgBufferBPP = 4 then begin //next- 32 bit lBuffIn32 := SingleP(lHdr.ImgBuffer); GetMem(lBuffOutUnaligned,(lOutVolItems*sizeof(single))+16); //svn lBuffOut32 := SingleP($fffffff0 and (integer(lBuffOutUnaligned)+15)); lBuffOut32 := Align(lBuffOutUnaligned, 16); for lX := 1 to lOutVolItems do lBuffOut32^[lX] := 0; //set all to zero //fx(lOutVolItems,lHdr.ImgBufferItems); for lZ := lMin[3] to lMax[3] do begin ImgForm.ProgressBar1.Position := lZ; lOutZPos := (lZ-1) * lOut.rSliceSz; lInZPos:= (lLUTra[3]^[lZ]-1) * lIn.rSliceSz; lInZPosHi := lInZPos + lIn.rSliceSz; lZmodHi := lLUTmodra[3]^[lZ]; lZModLo := 1 - lZmodHi; for lY := lMin[2] to lMax[2] do begin lOutYPos := (lY-1) * lOut.rDim[1]; lInYPos := (lLUTra[2]^[lY]-1) * lIn.rDim[1]; //number of lines lInYPosHi := lInYPos + lIn.rDim[1]; lYmodHi := lLUTmodra[2]^[lY]; lYModLo := 1 - lYmodHi; for lX := lMin[1] to lMax[1] do begin lXmodHi := lLUTmodra[1]^[lX]; lXModLo := 1 - lXmodHi; lBuffOut32^[lOutZPos+lOutYPos+lX] := ( lBuffIn32^[lInZPos+lInYPos+lLUTra[1]^[lX]]*lXModLo*lYModLo*lZModLo + lBuffIn32^[lInZPos+lInYPos+lLUTra[1]^[lX]+1]*lXModHi*lYModLo*lZModLo + lBuffIn32^[lInZPos+lInYPosHi+lLUTra[1]^[lX]]*lXModLo*lYModHi*lZModLo + lBuffIn32^[lInZPos+lInYPosHi+lLUTra[1]^[lX]+1]*lXModHi*lYModHi*lZModLo + lBuffIn32^[lInZPosHi+lInYPos+lLUTra[1]^[lX]]*lXModLo*lYModLo*lZModHi + lBuffIn32^[lInZPosHi+lInYPos+lLUTra[1]^[lX]+1]*lXModHi*lYModLo*lZModHi + lBuffIn32^[lInZPosHi+lInYPosHi+lLUTra[1]^[lX]]*lXModLo*lYModHi*lZModHi + lBuffIn32^[lInZPosHi+lInYPosHi+lLUTra[1]^[lX]+1]*lXModHi*lYModHi*lZModHi) ; end; //for X end; //for Y end; //for Z FreeMem(lHdr.ImgBufferUnaligned); GetMem(lHdr.ImgBufferUnaligned ,(lOutVolItems*sizeof(Single)) + 16); //svn lHdr.ImgBuffer := ByteP ($fffffff0 and (integer(lHdr.ImgBufferUnaligned )+15)); lHdr.ImgBuffer := align(lHdr.ImgBufferUnaligned, 16); lHdr.ImgBufferItems := lOutVolItems; Move(lBuffOut32^,lHdr.ImgBuffer^,lOutVolItems*sizeof(Single));//source/dest //678 winOnly-> CopyMemory(Pointer(lHdr.ImgBuffer),Pointer(lBuffOut32),(lOutVolItems*sizeof(Single))); FreeMem(lBuffOutUnaligned); end else if lHdr.ImgBufferBPP = 2 then begin //next- 16 bit lBuffIn16 := SmallIntP(lHdr.ImgBuffer); GetMem(lBuffOutUnaligned,(lOutVolItems*sizeof(smallint))+16); //svn lBuffOut16 := SmallIntP($fffffff0 and (integer(lBuffOutUnaligned)+15)); lBuffOut16 := align(lBuffOutUnaligned, 16); for lX := 1 to lOutVolItems do lBuffOut16^[lX] := 0; //set all to zero for lZ := lMin[3] to lMax[3] do begin ImgForm.ProgressBar1.Position := lZ; lOutZPos := (lZ-1) * lOut.rSliceSz; lInZPos:= (lLUTra[3]^[lZ]-1) * lIn.rSliceSz; lInZPosHi := lInZPos + lIn.rSliceSz; lZmodHi := lLUTmodra[3]^[lZ]; lZModLo := 1 - lZmodHi; for lY := lMin[2] to lMax[2] do begin lOutYPos := (lY-1) * lOut.rDim[1]; lInYPos := (lLUTra[2]^[lY]-1) * lIn.rDim[1]; //number of lines lInYPosHi := lInYPos + lIn.rDim[1]; lYmodHi := lLUTmodra[2]^[lY]; lYModLo := 1 - lYmodHi; for lX := lMin[1] to lMax[1] do begin lXmodHi := lLUTmodra[1]^[lX]; lXModLo := 1 - lXmodHi; lBuffOut16^[lOutZPos+lOutYPos+lX] := round( lBuffIn16^[lInZPos+lInYPos+lLUTra[1]^[lX]]*lXModLo*lYModLo*lZModLo + lBuffIn16^[lInZPos+lInYPos+lLUTra[1]^[lX+1]]*lXModHi*lYModLo*lZModLo + lBuffIn16^[lInZPos+lInYPosHi+lLUTra[1]^[lX]]*lXModLo*lYModHi*lZModLo + lBuffIn16^[lInZPos+lInYPosHi+lLUTra[1]^[lX+1]]*lXModHi*lYModHi*lZModLo + lBuffIn16^[lInZPosHi+lInYPos+lLUTra[1]^[lX]]*lXModLo*lYModLo*lZModHi + lBuffIn16^[lInZPosHi+lInYPos+lLUTra[1]^[lX+1]]*lXModHi*lYModLo*lZModHi + lBuffIn16^[lInZPosHi+lInYPosHi+lLUTra[1]^[lX]]*lXModLo*lYModHi*lZModHi + lBuffIn16^[lInZPosHi+lInYPosHi+lLUTra[1]^[lX+1]]*lXModHi*lYModHi*lZModHi) ; end; //for X end; //for Y end; //for Z FreeMem(lHdr.ImgBufferUnaligned); GetMem(lHdr.ImgBufferUnaligned ,(lOutVolItems*sizeof(SmallInt)) + 16); //lHdr.ImgBuffer := ByteP($fffffff0 and (integer(lHdr.ImgBufferUnaligned)+15)); lHdr.ImgBuffer := align(lHdr.ImgBufferUnaligned, 16); lHdr.ImgBufferItems := lOutVolItems; Move((lBuffOut16^),(lHdr.ImgBuffer^),lOutVolItems*sizeof(SmallInt));//source/dest //678 winOnly-> CopyMemory(Pointer(lHdr.ImgBuffer),Pointer(lBuffOut16),(lOutVolItems*sizeof(SmallInt))); FreeMem(lBuffOutUnaligned); end else if lHdr.ImgBufferBPP = 1 then begin //next- 8 bit lBuffIn := lHdr.ImgBuffer; GetMem(lBuffOut,lOutVolItems); Fillchar(lBuffOut^,lOutVolItems,0); //set all to zero //for lI := 1 to lOutVolItems do lBuffOut[lI] := 0; //set all to zero for lZ := lMin[3] to lMax[3] do begin ImgForm.ProgressBar1.Position := lZ; lOutZPos := (lZ-1) * lOut.rSliceSz; lInZPos:= (lLUTra[3]^[lZ]-1) * lIn.rSliceSz; lInZPosHi := lInZPos + lIn.rSliceSz; lZmodHi := lLUTmodra[3]^[lZ]; lZModLo := 1 - lZmodHi; for lY := lMin[2] to lMax[2] do begin lOutYPos := (lY-1) * lOut.rDim[1]; lInYPos := (lLUTra[2]^[lY]-1) * lIn.rDim[1]; //number of lines lInYPosHi := lInYPos + lIn.rDim[1]; lYmodHi := lLUTmodra[2]^[lY]; lYModLo := 1 - lYmodHi; for lX := lMin[1] to lMax[1] do begin lXmodHi := lLUTmodra[1]^[lX]; lXModLo := 1 - lXmodHi; lBuffOut^[lOutZPos+lOutYPos+lX] := round( lBuffIn^[lInZPos+lInYPos+lLUTra[1]^[lX]]*lXModLo*lYModLo*lZModLo + lBuffIn^[lInZPos+lInYPos+lLUTra[1]^[lX+1]]*lXModHi*lYModLo*lZModLo + lBuffIn^[lInZPos+lInYPosHi+lLUTra[1]^[lX]]*lXModLo*lYModHi*lZModLo + lBuffIn^[lInZPos+lInYPosHi+lLUTra[1]^[lX+1]]*lXModHi*lYModHi*lZModLo + lBuffIn^[lInZPosHi+lInYPos+lLUTra[1]^[lX]]*lXModLo*lYModLo*lZModHi + lBuffIn^[lInZPosHi+lInYPos+lLUTra[1]^[lX+1]]*lXModHi*lYModLo*lZModHi + lBuffIn^[lInZPosHi+lInYPosHi+lLUTra[1]^[lX]]*lXModLo*lYModHi*lZModHi + lBuffIn^[lInZPosHi+lInYPosHi+lLUTra[1]^[lX+1]]*lXModHi*lYModHi*lZModHi); end; //for X end; //for Y end; //for Z FreeMem(lHdr.ImgBufferUnaligned); GetMem(lHdr.ImgBufferUnaligned ,lOutVolItems + 16); //svn lHdr.ImgBuffer := ByteP($fffffff0 and (integer(lHdr.ImgBufferUnaligned)+15)); lHdr.ImgBuffer := align(lHdr.ImgBufferUnaligned, 16); lHdr.ImgBufferItems := lOutVolItems; Move(lBuffOut^,lHdr.ImgBuffer^,lOutVolItems);//source/dest //678winonly-> CopyMemory((lHdr.ImgBuffer),(lBuffOut),lOutVolItems); FreeMem(lBuffOut); end else Showmessage('Unsupported BPP '+inttostr(lHdr.ImgBufferBPP)); ImgForm.ProgressBar1.Position := lMin[3]; result := true; 666: for lI := 1 to 3 do begin freemem(lLUTra[lI]); freemem(lLUTmodra[lI]); end; //Output dimensions: size of background image //lEndTime := GetTickCount; //ImgForm.Label1.caption :=('update(ms): '+inttostr(lEndTime-lStartTime)); end; //procedure OrthogonalResliceImg procedure fSwap(var lX,lY: single); var lSwap: single; begin lSwap := lX; lX := lY; lY := lSwap; end; procedure ResliceScrnImg (var lBGImg: TBGImg; var lHdr: TMRIcroHdr; lTrilinearSmooth: boolean); var lOverlap: boolean; lMinY,lMinZ,lMaxY,lMaxZ: integer; //<- used by trilinear lXreal,lYreal,lZreal,lXrM1,lYrM1,lZrM1, //<- used by trilinear lZr,lYr,lXr,lZx,lZy,lZz,lYx,lYy,lYz: single;//lSwap lZ,lY,lX,lOutVolItems,lOutSliceSz,lInVolItems, lXdimIn,lYDimIn,lZDimIn,lInSliceSz, lOutPos,lOutDimX,lOutDimY,lOutDimZ,lXo,lYo,lZo: integer;//lSrcPos lXxp,lXyp,lXzp: Pointer; lXxra,lXyra,lXzra : SingleP; lMatrix,lMatrixBG: TMatrix; lBuffIn,lBuffOut,lBuffOutUnaligned: Bytep; lBuffIn16,lBuffOut16 : SmallIntP;//16bit lBuffIn32,lBuffOut32: SingleP; begin if SameAsBG(lBGImg,lHdr) then exit; if not lBGImg.Resliced then begin //2008 Reslice_Img_To_Unaligned (gMRIcroOverlay[kBGOverlayNum].NIftiHdr, lHdr, lBGImg.OverlaySmooth); exit; end; if OrthoReslice(lBGImg,lHdr) then exit; lOverlap := false; lMatrix := lHdr.Mat; lMatrix := mat44_inverse(lMatrix); lMatrixBG := Matrix3D ( lBGImg.Scrnmm[1],0,0,0, 0,lBGImg.Scrnmm[2],0,0, 0,0,lBGImg.Scrnmm[3],0, 0,0,0,1); lMatrix.size := size3D; lMatrix := MultiplyMatrices(lMatrix,lMatrixBG); lXdimIn := lHdr.NiftiHdr.dim[1]; lYdimIn := lHdr.NiftiHdr.dim[2]; lZDimIn := lHdr.NiftiHdr.dim[3]; lInSliceSz := lHdr.NiftiHdr.dim[1]*lHdr.NiftiHdr.dim[2]; lInVolItems := lInSliceSz*lHdr.NiftiHdr.dim[3]; if (lHdr.ImgBufferItems < lInVolItems) then exit; lBuffIn := lHdr.ImgBuffer; lOutDimX := lBGImg.ScrnDim[1]; lOutDimY := lBGImg.ScrnDim[2]; lOutDimZ := lBGImg.ScrnDim[3]; lOutSliceSz := lOutDimX*lOutDimY; lOutVolItems := lBGImg.ScrnDim[1]*lBGImg.ScrnDim[2]*lBGImg.ScrnDim[3]; lOutPos := 0; //start look up table... GetMem(lXxp, (sizeof(single)* lOutDimX)+16); GetMem(lXyp, (sizeof(single)* lOutDimX)+16); GetMem(lXzp, (sizeof(single)* lOutDimX)+16); lXxRA := align(lXxp, 16); //SingleP($fffffff0 and (integer(lXxP)+15)); //data aligned to quad-word boundary lXyRA := align(lXyp, 16);//SingleP($fffffff0 and (integer(lXyP)+15)); //quad-word boundary lXzRA := align(lXzp, 16);//SingleP($fffffff0 and (integer(lXzP)+15)); //quad-word boundary for lX := 1 to lOutDimX do begin lXr := lX-(lBGImg.ScrnOri[1]);//* lBGImg.ScrnMM[1]) ; //lXr := lX; lXxRA^[lX] := lXr*lMatrix.matrix[1,1]+1; lXyRA^[lX] := lXr*lMatrix.matrix[2,1]+1; lXzRA^[lX] := lXr*lMatrix.matrix[3,1]+1; end; //end look up table if lTrilinearSmooth then begin //smooth data if lHdr.ImgBufferBPP = 4 then begin lBuffIn32 := SingleP(lHdr.ImgBuffer); GetMem(lBuffOutUnaligned,(lOutVolItems*sizeof(single))+16); lBuffOut32 := align(lBuffOutUnaligned, 16); //SingleP($fffffff0 and (integer(lBuffOutUnaligned)+15)); for lX := 1 to lOutVolItems do lBuffOut32^[lX] := 0; //set all to zero for lZ := 1 to lOutDimZ do begin lZr := lZ -(lBGImg.ScrnOri[3]); lZx := lZr*lMatrix.matrix[1,3]+lMatrix.matrix[1,4]; lZy := lZr*lMatrix.matrix[2,3]+lMatrix.matrix[2,4]; lZz := lZr*lMatrix.matrix[3,3]+lMatrix.matrix[3,4]; for lY := 1 to lOutDimY do begin lYr := lY -(lBGImg.ScrnOri[2]); lYx := lYr*lMatrix.matrix[1,2]; lYy := lYr*lMatrix.matrix[2,2]; lYz := lYr*lMatrix.matrix[3,2]; for lX := 1 to lOutDimX do begin inc(lOutPos); lXreal := lXxRA^[lX]+lYx+lZx; lYreal := lXyRA^[lX]+lYy+lZy; lZreal := lXzRA^[lX]+lYz+lZz; lXo := trunc(lXreal); lYo := trunc(lYreal); lZo := trunc(lZreal); if (lXo > 0) and (lXo < lXDimIn) and (lYo > 0) and (lYo < lYDimIn) and (lZo > 0) and (lZo < lZDimIn) then begin lXreal := lXreal-lXo; lYreal := lYreal-lYo; lZreal := lZreal-lZo; lXrM1 := 1-lXreal; lYrM1 := 1-lYreal; lZrM1 := 1-lZreal; lMinY := ((lYo-1)*lXdimIn); lMinZ := ((lZo-1)*lInSliceSz); lMaxY := ((lYo)*lXdimIn); lMaxZ := ((lZo)*lInSliceSz); lOverlap := true; lBuffOut32^[lOutPos] := ( {all min} ( (lXrM1*lYrM1*lZrM1)*lBuffIn32^[lXo+lMinY+lMinZ]) {x+1}+((lXreal*lYrM1*lZrM1)*lBuffIn32^[lXo+1+lMinY+lMinZ]) {y+1}+((lXrM1*lYreal*lZrM1)*lBuffIn32^[lXo+lMaxY+lMinZ]) {z+1}+((lXrM1*lYrM1*lZreal)*lBuffIn32^[lXo+lMinY+lMaxZ]) {x+1,y+1}+((lXreal*lYreal*lZrM1)*lBuffIn32^[lXo+1+lMaxY+lMinZ]) {x+1,z+1}+((lXreal*lYrM1*lZreal)*lBuffIn32^[lXo+1+lMinY+lMaxZ]) {y+1,z+1}+((lXrM1*lYreal*lZreal)*lBuffIn32^[lXo+lMaxY+lMaxZ]) {x+1,y+1,z+1}+((lXreal*lYreal*lZreal)*lBuffIn32^[lXo+1+lMaxY+lMaxZ]) ); end; //values in range end; //for X end; //for OutY end; //for OutZ //core 32 end FreeMem(lHdr.ImgBufferUnaligned); GetMem(lHdr.ImgBufferUnaligned ,(lOutVolItems*sizeof(Single)) + 16); lHdr.ImgBuffer := align(lHdr.ImgBufferUnaligned, 16);//ByteP($fffffff0 and (integer(lHdr.ImgBufferUnaligned)+15)); lHdr.ImgBufferItems := lOutVolItems; Move(lBuffOut32^,lHdr.ImgBuffer^,lOutVolItems*sizeof(Single));//source/dest FreeMem(lBuffOutUnaligned); end else if lHdr.ImgBufferBPP = 2 then begin lBuffIn16 := SmallIntP(lHdr.ImgBuffer); GetMem(lBuffOutUnaligned,(lOutVolItems*sizeof(smallint))+16); lBuffOut16 := align(lBuffOutUnaligned, 16); //SmallIntP($fffffff0 and (integer(lBuffOutUnaligned)+15)); for lX := 1 to lOutVolItems do lBuffOut16^[lX] := 0; //set all to zero //core 16 start for lZ := 1 to lOutDimZ do begin lZr := lZ -(lBGImg.ScrnOri[3]); lZx := lZr*lMatrix.matrix[1,3]+lMatrix.matrix[1,4]; lZy := lZr*lMatrix.matrix[2,3]+lMatrix.matrix[2,4]; lZz := lZr*lMatrix.matrix[3,3]+lMatrix.matrix[3,4]; for lY := 1 to lOutDimY do begin lYr := lY -(lBGImg.ScrnOri[2]); lYx := lYr*lMatrix.matrix[1,2]; lYy := lYr*lMatrix.matrix[2,2]; lYz := lYr*lMatrix.matrix[3,2]; for lX := 1 to lOutDimX do begin inc(lOutPos); lXreal := lXxRA^[lX]+lYx+lZx; lYreal := lXyRA^[lX]+lYy+lZy; lZreal := lXzRA^[lX]+lYz+lZz; lXo := trunc(lXreal); lYo := trunc(lYreal); lZo := trunc(lZreal); if (lXo > 0) and (lXo < lXDimIn) and (lYo > 0) and (lYo < lYDimIn) and (lZo > 0) and (lZo < lZDimIn) then begin lXreal := lXreal-lXo; lXrM1 := 1-lXreal; lYreal := lYreal-lYo; lYrM1 := 1-lYreal; lZreal := lZreal-lZo; lZrM1 := 1-lZreal; lMinY := ((lYo-1)*lXdimIn); lMaxY := lMinY+lXdimIn; lMinZ := ((lZo-1)*lInSliceSz); lMaxZ := lMinZ+lInSliceSz; lOverlap := true; lBuffOut16^[lOutPos] := round ( {all min} ( (lXrM1*lYrM1*lZrM1)*lBuffIn16^[lXo+lMinY+lMinZ]) {x+1}+((lXreal*lYrM1*lZrM1)*lBuffIn16^[lXo+1+lMinY+lMinZ]) {y+1}+((lXrM1*lYreal*lZrM1)*lBuffIn16^[lXo+lMaxY+lMinZ]) {z+1}+((lXrM1*lYrM1*lZreal)*lBuffIn16^[lXo+lMinY+lMaxZ]) {x+1,y+1}+((lXreal*lYreal*lZrM1)*lBuffIn16^[lXo+1+lMaxY+lMinZ]) {x+1,z+1}+((lXreal*lYrM1*lZreal)*lBuffIn16^[lXo+1+lMinY+lMaxZ]) {y+1,z+1}+((lXrM1*lYreal*lZreal)*lBuffIn16^[lXo+lMaxY+lMaxZ]) {x+1,y+1,z+1}+((lXreal*lYreal*lZreal)*lBuffIn16^[lXo+1+lMaxY+lMaxZ]) ); (**) end; //values in range end; //for X end; //for OutY end; //for OutZ //core 16 end FreeMem(lHdr.ImgBufferUnaligned); GetMem(lHdr.ImgBufferUnaligned ,(lOutVolItems*sizeof(SmallInt)) + 16); lHdr.ImgBuffer := align(lHdr.ImgBufferUnaligned, 16); //ByteP($fffffff0 and (integer(lHdr.ImgBufferUnaligned)+15)); lHdr.ImgBufferItems := lOutVolItems; Move(lBuffOut16^,lHdr.ImgBuffer^,lOutVolItems*sizeof(SmallInt));//source/dest FreeMem(lBuffOutUnaligned); end else if lHdr.ImgBufferBPP = 1 then begin GetMem(lBuffOut,lOutVolItems); Fillchar(lBuffOut^,lOutVolItems,0); //set all to zero for lZ := 1 to lOutDimZ do begin lZr := lZ -(lBGImg.ScrnOri[3]); lZx := lZr*lMatrix.matrix[1,3]+lMatrix.matrix[1,4]; lZy := lZr*lMatrix.matrix[2,3]+lMatrix.matrix[2,4]; lZz := lZr*lMatrix.matrix[3,3]+lMatrix.matrix[3,4]; for lY := 1 to lOutDimY do begin lYr := lY -(lBGImg.ScrnOri[2]); lYx := lYr*lMatrix.matrix[1,2]; lYy := lYr*lMatrix.matrix[2,2]; lYz := lYr*lMatrix.matrix[3,2]; for lX := 1 to lOutDimX do begin inc(lOutPos); lXreal := lXxRA^[lX]+lYx+lZx; lYreal := lXyRA^[lX]+lYy+lZy; lZreal := lXzRA^[lX]+lYz+lZz; lXo := trunc(lXreal); lYo := trunc(lYreal); lZo := trunc(lZreal); if (lXo > 0) and (lXo < lXDimIn) and (lYo > 0) and (lYo < lYDimIn) and (lZo > 0) and (lZo < lZDimIn) then begin lXreal := lXreal-lXo; lYreal := lYreal-lYo; lZreal := lZreal-lZo; lXrM1 := 1-lXreal; lYrM1 := 1-lYreal; lZrM1 := 1-lZreal; lMinY := ((lYo-1)*lXdimIn); lMinZ := ((lZo-1)*lInSliceSz); lMaxY := ((lYo)*lXdimIn); lMaxZ := ((lZo)*lInSliceSz); lOverlap := true; lBuffOut^[lOutPos] := round ( {all min} ( (lXrM1*lYrM1*lZrM1)*lBuffIn^[lXo+lMinY+lMinZ]) {x+1}+((lXreal*lYrM1*lZrM1)*lBuffIn^[lXo+1+lMinY+lMinZ]) {y+1}+((lXrM1*lYreal*lZrM1)*lBuffIn^[lXo+lMaxY+lMinZ]) {z+1}+((lXrM1*lYrM1*lZreal)*lBuffIn^[lXo+lMinY+lMaxZ]) {x+1,y+1}+((lXreal*lYreal*lZrM1)*lBuffIn^[lXo+1+lMaxY+lMinZ]) {x+1,z+1}+((lXreal*lYrM1*lZreal)*lBuffIn^[lXo+1+lMinY+lMaxZ]) {y+1,z+1}+((lXrM1*lYreal*lZreal)*lBuffIn^[lXo+lMaxY+lMaxZ]) {x+1,y+1,z+1}+((lXreal*lYreal*lZreal)*lBuffIn^[lXo+1+lMaxY+lMaxZ]) ); end; //values in range end; //for X end; //for OutY end; //for OutZ FreeMem(lHdr.ImgBufferUnaligned); GetMem(lHdr.ImgBufferUnaligned ,lOutVolItems + 16); lHdr.ImgBuffer := align(lHdr.ImgBufferUnaligned, 16); //ByteP($fffffff0 and (integer(lHdr.ImgBufferUnaligned)+15)); lHdr.ImgBufferItems := lOutVolItems; Move(lBuffOut^,lHdr.ImgBuffer^,lOutVolItems);//source/dest FreeMem(lBuffOut); end else //unsupported bits-per-pixel dataformat Showmessage('Unsupported BPP ='+inttostr(lHdr.ImgBufferBPP) ); end else begin //not trilinear - use nearest neighbor //start nearest neighbor if lHdr.ImgBufferBPP = 4 then begin lBuffIn32 := SingleP(lHdr.ImgBuffer); GetMem(lBuffOutUnaligned,(lOutVolItems*sizeof(single))+16); lBuffOut32 := align(lBuffOutUnaligned, 16);//SingleP($fffffff0 and (integer(lBuffOutUnaligned)+15)); for lX := 1 to lOutVolItems do lBuffOut32^[lX] := 0; //set all to zero //core 32 start for lZ := 1 to lOutDimZ do begin lZr := lZ -(lBGImg.ScrnOri[3]); lZx := lZr*lMatrix.matrix[1,3]+lMatrix.matrix[1,4]; lZy := lZr*lMatrix.matrix[2,3]+lMatrix.matrix[2,4]; lZz := lZr*lMatrix.matrix[3,3]+lMatrix.matrix[3,4]; for lY := 1 to lOutDimY do begin lYr := lY -(lBGImg.ScrnOri[2]); lYx := lYr*lMatrix.matrix[1,2]; lYy := lYr*lMatrix.matrix[2,2]; lYz := lYr*lMatrix.matrix[3,2]; for lX := 1 to lOutDimX do begin inc(lOutPos); lXo := round(lXxRA^[lX]+lYx+lZx); lYo := round(lXyRA^[lX]+lYy+lZy); lZo := round(lXzRA^[lX]+lYz+lZz); if (lXo > 0) and (lXo < lXDimIn) and (lYo > 0) and (lYo < lYDimIn) and (lZo > 0) and (lZo < lZDimIn) then begin lOverlap := true; lMinY := ((lYo-1)*lXdimIn); lMinZ := ((lZo-1)*lInSliceSz); lBuffOut32^[lOutPos] := lBuffIn32^[lXo+lMinY+lMinZ]; end; end; //for X end; //for OutY end; //for OutZ //core 32 end FreeMem(lHdr.ImgBufferUnaligned); GetMem(lHdr.ImgBufferUnaligned ,(lOutVolItems*sizeof(Single)) + 16); lHdr.ImgBuffer := align(lHdr.ImgBufferUnaligned, 16);//ByteP($fffffff0 and (integer(lHdr.ImgBufferUnaligned)+15)); lHdr.ImgBufferItems := lOutVolItems; Move(lBuffOut32^,lHdr.ImgBuffer^,lOutVolItems*sizeof(Single));//source/dest FreeMem(lBuffOutUnaligned); end else if lHdr.ImgBufferBPP = 2 then begin lBuffIn16 := SmallIntP(lHdr.ImgBuffer); GetMem(lBuffOutUnaligned,(lOutVolItems*sizeof(smallint))+16); lBuffOut16 := align(lBuffOutUnaligned, 16);//SmallIntP($fffffff0 and (integer(lBuffOutUnaligned)+15)); for lX := 1 to lOutVolItems do lBuffOut16^[lX] := 0; //set all to zero //core 16 start for lZ := 1 to lOutDimZ do begin lZr := lZ -(lBGImg.ScrnOri[3]); lZx := lZr*lMatrix.matrix[1,3]+lMatrix.matrix[1,4]; lZy := lZr*lMatrix.matrix[2,3]+lMatrix.matrix[2,4]; lZz := lZr*lMatrix.matrix[3,3]+lMatrix.matrix[3,4]; for lY := 1 to lOutDimY do begin lYr := lY -(lBGImg.ScrnOri[2]); lYx := lYr*lMatrix.matrix[1,2]; lYy := lYr*lMatrix.matrix[2,2]; lYz := lYr*lMatrix.matrix[3,2]; for lX := 1 to lOutDimX do begin inc(lOutPos); lXo := round(lXxRA^[lX]+lYx+lZx); lYo := round(lXyRA^[lX]+lYy+lZy); lZo := round(lXzRA^[lX]+lYz+lZz); if (lXo > 0) and (lXo < lXDimIn) and (lYo > 0) and (lYo < lYDimIn) and (lZo > 0) and (lZo < lZDimIn) then begin lOverlap := true; lMinY := ((lYo-1)*lXdimIn); lMinZ := ((lZo-1)*lInSliceSz); lBuffOut16^[lOutPos] := lBuffIn16^[lXo+lMinY+lMinZ]//lBuffIn16[lXo+lYo+lZo]; xxxx end; //values in range end; //for X end; //for OutY end; //for OutZ //core 16 end FreeMem(lHdr.ImgBufferUnaligned); GetMem(lHdr.ImgBufferUnaligned ,(lOutVolItems*sizeof(SmallInt)) + 16); lHdr.ImgBuffer := align(lHdr.ImgBufferUnaligned, 16);// ByteP($fffffff0 and (integer(lHdr.ImgBufferUnaligned)+15)); lHdr.ImgBufferItems := lOutVolItems; Move(lBuffOut16^,lHdr.ImgBuffer^,lOutVolItems*sizeof(SmallInt));//source/dest FreeMem(lBuffOutUnaligned); end else if lHdr.ImgBufferBPP = 1 then begin GetMem(lBuffOut,lOutVolItems); Fillchar(lBuffOut^,lOutVolItems,0); //set all to zero for lZ := 1 to lOutDimZ do begin lZr := lZ -(lBGImg.ScrnOri[3]); lZx := lZr*lMatrix.matrix[1,3]+lMatrix.matrix[1,4]; lZy := lZr*lMatrix.matrix[2,3]+lMatrix.matrix[2,4]; lZz := lZr*lMatrix.matrix[3,3]+lMatrix.matrix[3,4]; for lY := 1 to lOutDimY do begin lYr := lY -(lBGImg.ScrnOri[2]); lYx := lYr*lMatrix.matrix[1,2]; lYy := lYr*lMatrix.matrix[2,2]; lYz := lYr*lMatrix.matrix[3,2]; for lX := 1 to lOutDimX do begin inc(lOutPos); lXo := round(lXxRA^[lX]+lYx+lZx); lYo := round(lXyRA^[lX]+lYy+lZy); lZo := round(lXzRA^[lX]+lYz+lZz); if (lXo > 0) and (lXo < lXDimIn) and (lYo > 0) and (lYo < lYDimIn) and (lZo > 0) and (lZo < lZDimIn) then begin lMinY := ((lYo-1)*lXdimIn); lMinZ := ((lZo-1)*lInSliceSz); lOverlap := true; lBuffOut^[lOutPos] := lBuffIn^[lXo+lMinY+lMinZ]; end; //values in range end; //for X end; //for OutY end; //for OutZ FreeMem(lHdr.ImgBufferUnaligned); GetMem(lHdr.ImgBufferUnaligned ,lOutVolItems + 16); lHdr.ImgBuffer := align(lHdr.ImgBufferUnaligned, 16);//ByteP($fffffff0 and (integer(lHdr.ImgBufferUnaligned)+15)); lHdr.ImgBufferItems := lOutVolItems; Move(lBuffOut^,lHdr.ImgBuffer^,lOutVolItems);//source/dest FreeMem(lBuffOut); end else //unsupported bits-per-pixel dataformat Showmessage('Unsupported BPP ='+inttostr(lHdr.ImgBufferBPP) ); //end nearest neighbor end; //end if trilinear else nearest neighbor if not lOverlap then showmessage('No overlap between image and background bounding box - check the transfomation matrices.'); FreeMem(lXxp); FreeMem(lXyp); FreeMem(lXzp); end; //ResliceScrnImg procedure InvertScrnBuffer(var lHdr: TMRIcroHdr); var lPos: integer; begin if lHdr.ScrnBufferItems < 1 then exit; lHdr.Zero8Bit := lHdr.Zero8Bit+(255*lHdr.Slope8bit); lHdr.Slope8bit := -lHdr.Slope8bit; for lPos := 1 to lHdr.ScrnBufferItems do lHdr.ScrnBuffer^[lPos] := 255- lHdr.ScrnBuffer^[lPos]; {lMin := 255; for lPos := 1 to lHdr.ScrnBufferItems do if lMin > lHdr.ScrnBuffer[lPos] then lMin := lHdr.ScrnBuffer[lPos]; } //showmessage('inv'+inttostr(lMin)); end; const kMin8bit = 1; procedure RescaleImgIntensity(var lBackgroundImg: TBGImg; var lHdr: TMRIcroHdr; lLayer: integer ); var lImgSamples: integer; //lFiltMin8bit,lFiltMax8bit: integer; //lMin,lMax: single; begin lImgSamples := round(ComputeImageDataBytes8bpp(lHdr)); if (lHdr.ImgBufferItems = 0) and (lHdr.ScrnBufferItems > 0) then begin //image buffer loaded - not VOIs have screen but not img buffers if lBackgroundImg.VOImirrored then MirrorScrnBuffer(lBackgroundImg,lHdr); lBackgroundImg.VOImirrored := false; exit; end; if lHdr.ImgBufferItems<>lHdr.ScrnBufferItems then begin if lHdr.ScrnBufferItems > 0 then freemem(lHdr.ScrnBuffer); lHdr.ScrnBufferItems := lHdr.ImgBufferItems; GetMem(lHdr.ScrnBuffer ,lHdr.ScrnBufferItems); end; if lHdr.ImgBufferItems = 0 then exit; //2/2010 if (lHdr.UsesCustomPalette) and (not lHdr.UsesCustomPaletteRandomRainbow) then begin //2014 lHdr.WindowScaledMin := kMin8bit; lHdr.WindowScaledMax := 255; end; if lImgSamples < 1 then exit; if (lHdr.ImgBufferBPP = 4) then RescaleImgIntensity32(lHdr) else if (lHdr.ImgBufferBPP = 2) then RescaleImgIntensity16(LHdr) else if lHdr.ImgBufferBPP = 1 then RescaleImgIntensity8(lHdr) else begin showmessage(inttostr(lHdr.ImgBufferItems)+'Unknown Image Buffer Bytes Per Pixel: '+inttostr(lHdr.ImgBufferBPP)+' : '+lHdr.HdrFileName); exit; end; //if not lHdr.SameDimsAsBG then OrthogonalResliceScrnImg (lBackgroundImg, lHdr); //ReturnRawMinMax (lHdr, lMin,lMax,lFiltMin8bit,lFiltMax8bit); if (lLayer <> kBGOverlayNum) and ((lHdr.WindowScaledMin <= 0) and (lHdr.WindowScaledMax <= 0)) then InvertScrnBuffer(lHdr); FilterScrnImg (lHdr);//,lFiltMin8bit,lFiltMax8bit); if lBackgroundImg.Mirror then MirrorScrnBuffer(lBackgroundImg,lHdr); end; //RescaleImgIntensity32 function PtoLog10 ( lIn: double): double; //in= pvalue <=1 begin //result := -log(abs(lIn),10) result := -log((lIn),10) end; function Log10toP (lIn: double): double; begin //result := log((lIn),10) result := 1/power(10,lIn); //requires Math unit end; procedure ComputeFDR (var lInHdr: TMRIcroHdr; var lP05,lP01,lFWE05,lFWE01,lFDR05,lFDR01: single); //(lImg2Load.NIFTIhdr.intent_code,round(lImg2Load.NIFTIhdr.intent_p1),lImg2Load.ImgBufferItems,lImg2Load.ImgBufferBPP,lImg2Load.ImgBuffer,lP05,lP01,lFWE05,lFWE01,lFDR05,lFDR01); //procedure ComputeFDR(lStatIntent,lDF,lImgSamples,lImgBPP: integer; l32Buf:SingleP; var lP05,lP01,lFWE05,lFWE01,lFDR05,lFDR01: single); //StatIntents in kNIFTI_INTENT_CHISQ, kNIFTI_INTENT_ZSCORE,kNIFTI_INTENT_TTEST //Note DF meaningless for ZScore label 555; var lPs: SingleP; //array of tests lStr: string; lStatIntent,lImgSamples,lnTests,lInc,lDF: integer; lPrevP,lP,lFDR05p, lFDR01p,lnegFDR05p, lnegFDR01p,lnegFDR05, lnegFDR01 : double; l32Buf : SingleP; begin lStatIntent := lInHdr.NIFTIhdr.intent_code; lDF := round(lInHdr.NIFTIhdr.intent_p1); if ((lStatIntent = kNIFTI_INTENT_CHISQ) or (lStatIntent = kNIFTI_INTENT_TTEST)) and (lDF <= 1) then //May07 lDF := ReadIntForm.GetInt('Please specify degrees of freedom for '+extractfilename(lInHdr.HdrFileName),1,16,32000); lImgSamples := lInHdr.ImgBufferItems; if (lImgSamples < 1) then exit; ImgForm.StatusLabel.Caption := 'Computing FDR rates...'; ImgForm.refresh; //next: count number of tests [we could just rely on value lChiSamples to us, but perhaps value in intention is not correct lnTests := 0; l32Buf := SingleP(lInHdr.ImgBuffer ); for lInc := 1 to lImgSamples do if l32Buf^[lInc] <> 0 then inc(lnTests); if lnTests < 1 then exit; GetMem(lPs,lnTests*sizeof(single)); //for lInc := 1 to lnTests do lPs[lInc] := 1; //next - place Pvalues in array, as computing P is slow, we remember last Pvalue lPrevP := 0; lnTests := 0; lP := 1; //never used //lStartTime := GetTickCount; for lInc := 1 to lImgSamples do if l32Buf^[lInc] <> 0 then begin inc(lnTests); if l32Buf^[lInc] <> lPrevP then case lStatIntent of kNIFTI_INTENT_TTEST: lP := pTdistr(lDF,l32Buf^[lInc]);//slow!! 110ms kNIFTI_INTENT_ZSCORE: lP := pNormal(l32Buf^[lInc]);//slow!! 94ms kNIFTI_INTENT_PVAL: lP := l32Buf^[lInc]; NIFTI_INTENT_LOG10PVAL: lP := Log10toP(l32Buf^[lInc]); else {kNIFTI_INTENT_CHISQ:}begin if l32Buf^[lInc] < 0 then //MRIcro saves negative Chi lP := 0.6 else lP := pChi2(lDF,l32Buf^[lInc]);//slow! 47ms end; end; lPs^[lnTests] := lP; lPrevP := l32Buf^[lInc]; end; //Chi <> 0 //ImgForm.caption :=('update(ms): '+inttostr(GetTickCount-lStartTime)); //EstimateFDR(lnTests, lPs, lFDR05p, lFDR01p); EstimateFDR2(lnTests, lPs, lFDR05p, lFDR01p,lnegFDR05p, lnegFDR01p); //lStartTime := GetTickCount; //next histogram! (*for lInc := 1 to lnTests do lPs^[lInc] := pNormalInvQuickApprox(lPs^[lInc]); //slow!!!!!!!!! >5100ms lHdr.ImgBufferBPP := 4; lHdr.ImgBufferItems :=lnTests; lHdr.GlMaxUnscaledS :=lPs^[1]; lHdr.GlMinUnscaledS := lPs^[lnTests]; lHdr.ImgBuffer :=bytep(lPs); lHdr.NIFTIhdr.scl_slope := 1; lHdr.NIFTIhdr.scl_inter := 0; lInc := 0;//B&W LoadMonochromeLUT(lInc,gBGImg,lHdr); DrawHistogram(lHdr,HistogramForm.HistoImage); HistogramForm.Caption := 'Z Histogram'+realtostr(lHdr.GlMinUnscaledS,6)+'..'+realtostr(lHdr.GlMaxUnscaledS,6); HistogramForm.show; ImgForm.PGImageCor.refresh; //ImgForm.caption :=('update(ms): '+inttostr(GetTickCount-lStartTime)); //showmessage('Z Histogram'+realtostr(lHdr.GlMinUnscaledS,6)+'..'+realtostr(lHdr.GlMaxUnscaledS,6)); //end histogram *) 555: FreeMem(lPs); case lStatIntent of kNIFTI_INTENT_CHISQ:begin lP05:= pChi2Inv(lDF,0.05); lP01 := pChi2Inv(lDF,0.01); lFWE05 := pChi2Inv(lDF,0.05/lnTests); lFWE01 := pChi2Inv(lDF,0.01/lnTests); lFDR05 := pChi2Inv(lDF,lFDR05p); lFDR01 := pChi2Inv(lDF,lFDR01p); lnegFDR05 := pChi2Inv(lDF,lnegFDR05p); lnegFDR01 := pChi2Inv(lDF,lnegFDR01p); lStr := 'X DF='+inttostr(lDF); end; kNIFTI_INTENT_ZSCORE: begin lP05:= pNormalInv(0.05); lP01 := pNormalInv(0.01); lFWE05 := pNormalInv(0.05/lnTests); lFWE01 := pNormalInv(0.01/lnTests); lFDR05 := pNormalInv(lFDR05p); lFDR01 := pNormalInv(lFDR01p); lnegFDR05 := pNormalInv(lnegFDR05p); lnegFDR01 := pNormalInv(lnegFDR01p); lStr := 'Z'; end; kNIFTI_INTENT_TTEST: begin lP05:= pTdistrInv(lDF,0.05); lP01 := pTdistrInv(lDF,0.01); lFWE05 := pTdistrInv(lDF,0.05/lnTests); lFWE01 := pTdistrInv(lDF,0.01/lnTests); lFDR05 := pTdistrInv(lDF,lFDR05p); lFDR01 := pTdistrInv(lDF,lFDR01p); lnegFDR05 := pTdistrInv(lDF,lnegFDR05p); lnegFDR01 := pTdistrInv(lDF,lnegFDR01p); lStr := 't DF='+inttostr(lDF); end; kNIFTI_INTENT_PVAL:begin lP05:= (0.05); lP01 := (0.01); lFWE05 := (0.05/lnTests); lFWE01 := (0.01/lnTests); lFDR05 := (lFDR05p); lFDR01 := (lFDR01p); lnegFDR05 := (lnegFDR05p); lnegFDR01 := (lnegFDR01p); lStr := 'p'; end; NIFTI_INTENT_LOG10PVAL: begin lP05:= PtoLog10(0.05); lP01 := PtoLog10(0.01); lFWE05 := PtoLog10(0.05/lnTests); lFWE01 := PtoLog10(0.01/lnTests); lFDR05 := PtoLog10(lFDR05p); lFDR01 := PtoLog10(lFDR01p); lnegFDR05 := PtoLog10(lnegFDR05p); lnegFDR01 := PtoLog10(lnegFDR01p); lStr := 'log10p'; end; else Showmessage('Error: unknown stats intent'); end; //case if (lStatIntent = kNIFTI_INTENT_PVAL) then begin if (lFDR05 < lFWE05) then lFDR05 := lFWE05; end else if (lFDR05 > lFWE05) then lFDR05 := lFWE05; if (lStatIntent = kNIFTI_INTENT_PVAL) then begin if (lFDR01 < lFWE01) then lFDR01 := lFWE01; end else if (lFDR01 > lFWE01) then lFDR01 := lFWE01; if (lStatIntent = kNIFTI_INTENT_PVAL) then begin if (lnegFDR05 > -lFWE05) then lnegFDR05 := -lFWE05; if (lnegFDR01 > -lFWE01) then lnegFDR01 := -lFWE01; end else begin if (lnegFDR05 < -lFWE05) then lnegFDR05 := -lFWE05; if (lnegFDR01 < -lFWE01) then lnegFDR01 := -lFWE01; end; ImgForm.StatusLabel.Caption := lStr+' Tests='+inttostr(lnTests)+' p05='+realtostr(lP05,4)+ ' p01='+realtostr(lP01,4)+' fwe05='+realtostr(lFWE05,4)+ ' fwe01='+realtostr(lFWE01,4) +' fdr05='+realtostr(lFDR05,4)+' fdr01='+realtostr(lFDR01,4) +' -fdr05='+realtostr(lnegFDR05,4)+' -fdr01='+realtostr(lnegFDR01,4) ; end; function MakeSameOrtho(var lBGImg: TBGImg; var lHdr: TMRIcroHdr):boolean; //this function disables reslicing - images will be shown unrotated and unscaled... var lRow: integer; begin result := false; for lRow := 1 to 3 do begin //lHdr.NIFTIhdr.pixdim[lRow] := 1; //Apr07 if lHdr.NIFTIhdr.dim[lRow] <>lBGImg.ScrnDim[lRow] then exit; end; lHdr.Mat:= Matrix3D ( lBGImg.Scrnmm[1],0,0,-lBGImg.Scrnmm[1]*(lBGImg.ScrnOri[1]-1), 0,lBGImg.Scrnmm[2],0,-lBGImg.Scrnmm[2]*(lBGImg.ScrnOri[2]-1), 0,0,lBGImg.Scrnmm[3],-lBGImg.Scrnmm[3]*(lBGImg.ScrnOri[3]-1), 0,0,0,1); result := true; end; procedure FindAlignment (var lBGImg: TBGImg; var lHdr: TMRIcroHdr); //identifies spatial position of low X,Y,Z voxels : A/P/L/R/S/I var lDim: integer; lXMid,lYMid,lZMid,laX,laY,laZ,lX,lY,lZ,lX2,lY2,lZ2: single; lMatrix: TMatrix; begin lBGImg.KnownAlignment := false; if not IsNifTiMagic (lHdr.NIFTIHdr) then exit; //Analyze format: spatial coordinates are amibguous if (lHdr.NIFTIhdr.sform_code <= 0) and (lHdr.NIFTIhdr.qform_code <= 0) then exit; //NIfTI format with unspecified coordinates lBGImg.KnownAlignment := true; if (lBGImg.Resliced) and (lHdr.NIFTIhdr.sform_code > 0) then begin lBGImg.MinChar[1] := 'L'; lBGImg.MaxChar[1] := 'R'; lBGImg.MinChar[2] := 'P'; lBGImg.MaxChar[2] := 'A'; lBGImg.MinChar[3] := 'I'; lBGImg.MaxChar[3] := 'S'; exit; end; if (not gBGImg.OrthoReslice) then begin lBGImg.MinChar[1] := ' '; lBGImg.MaxChar[1] := ' '; lBGImg.MinChar[2] := ' '; lBGImg.MaxChar[2] := ' '; lBGImg.MinChar[3] := ' '; lBGImg.MaxChar[3] := ' '; exit; end; //there are two approaches to solve this - a more elegant solution is to find the nearest orthogonal aligment //the method below is simpler, but might give unusual results if the field of view in one dimension is much larger than another lMatrix := lHdr.Mat; lXMid := lHdr.NIFTIhdr.Dim[1] div 2; lYMid := lHdr.NIFTIhdr.Dim[2] div 2; lZMid := lHdr.NIFTIhdr.Dim[3] div 2; for lDim := 1 to 3 do begin if lDim = 1 then begin FindMatrixPt(0,lYMid,lZMid,lX,lY,lZ,lMatrix); FindMatrixPt(lXMid*2,lYMid,lZMid,lX2,lY2,lZ2,lMatrix); end else if lDim = 2 then begin FindMatrixPt(lXMid,0,lZMid,lX,lY,lZ,lMatrix); FindMatrixPt(lXMid,lYMid*2,lZMid,lX2,lY2,lZ2,lMatrix); end else begin //lDim=3 FindMatrixPt(lXMid,lYMid,0,lX,lY,lZ,lMatrix); FindMatrixPt(lXMid,lYMid,lZMid*2,lX2,lY2,lZ2,lMatrix); end; lX := lX-lX2; laX := abs(lX); lY := lY-lY2; laY := abs(lY); lZ := lZ-lZ2; laZ := abs(lZ); if (laX > laY) and (laX > laZ) then begin if lX < 0 then begin lBGImg.MinChar[lDim] := 'L'; lBGImg.MaxChar[lDim] := 'R'; end else begin lBGImg.MinChar[lDim] := 'R'; lBGImg.MaxChar[lDim] := 'L'; end; end else if (laY > laZ) then begin if lY < 0 then begin lBGImg.MinChar[lDIm] := 'P'; lBGImg.MaxChar[lDim] := 'A'; end else begin lBGImg.MinChar[lDim] := 'A'; lBGImg.MaxChar[lDim] := 'P'; end; end else if (laZ > laX) then begin if lZ < 0 then begin lBGImg.MinChar[lDim] := 'I'; lBGImg.MaxChar[lDim] := 'S'; end else begin lBGImg.MinChar[lDim] := 'S'; lBGImg.MaxChar[lDim] := 'I'; end; end else begin //all dims are equal lBGImg.MinChar[lDim] := '?'; lBGImg.MaxChar[lDim] := '?'; end; end;//for each dim end; //proc FindAlignment function DICOMMirrorImgBuffer(var lHdr: TMRIcroHdr ): boolean; var lXPos,lYPos,lZPos,lX,lY,lZ,lHlfY,lLineOffset,lLineOffsetIn: integer; lTemp32: single; lTemp16: SmallInt; lTemp: byte; l32: SingleP; l16: SmallIntP; begin result := false; lX := lHdr.NIFTIhdr.Dim[1]; lY := lHdr.NIFTIhdr.Dim[2]; lZ := lHdr.NIFTIhdr.Dim[3]; if lHdr.NIFTIhdr.Dim[4] > 1 then begin Showmessage('Can not mirror 4D data : '+lHdr.HdrFileName); exit; end; if (lHdr.ImgBufferItems < (lX*lY*lZ)) or (lX < 2) then begin Showmessage('Unsupported filetype : '+lHdr.HdrFileName); exit; end; lHlfY := lY div 2; lLineOffset := 0; //for each datatype... if lHdr.ImgBufferBPP = 4 then begin l32 := SingleP(lHdr.ImgBuffer); for lZPos := 1 to lZ do begin lLineOffsetIn := lLineOffset + ((lY-1)*lX ); for lYPos := 1 to lHlfY do begin for lXPos := 1 to lX do begin lTemp32 := l32^[lXPos+lLineOffsetIn]; l32^[lXPos+lLineOffsetIn] := l32^[lXPos+lLineOffset]; l32^[lXPos+lLineOffset] := lTemp32; end; //for X lLineOffset := lLineOffset + lX; lLineOffsetIn := lLineOffsetIn - lX; end; //for Y end; //for Z end else if lHdr.ImgBufferBPP = 2 then begin l16 := SmallIntP(lHdr.ImgBuffer); for lZPos := 1 to lZ do begin lLineOffsetIn := lLineOffset + ((lY-1)*lX ); for lYPos := 1 to lHlfY do begin for lXPos := 1 to lX do begin lTemp16 := l16^[lXPos+lLineOffsetIn]; l16^[lXPos+lLineOffsetIn] := l16^[lXPos+lLineOffset]; l16^[lXPos+lLineOffset] := lTemp16; end; //for X lLineOffset := lLineOffset + lX; lLineOffsetIn := lLineOffsetIn - lX; end; //for Y end; //for Z end else if lHdr.ImgBufferBPP = 1 then begin for lZPos := 1 to lZ do begin lLineOffsetIn := lLineOffset + ((lY-1)*lX ); for lYPos := 1 to lHlfY do begin for lXPos := 1 to lX do begin lTemp := lHdr.ImgBuffer^[lXPos+lLineOffsetIn]; lHdr.ImgBuffer^[lXPos+lLineOffsetIn] := lHdr.ImgBuffer^[lXPos+lLineOffset]; lHdr.ImgBuffer^[lXPos+lLineOffset] := lTemp; end; //for X lLineOffset := lLineOffset + lX; lLineOffsetIn := lLineOffsetIn - lX; end; //for Y end; //for Z end else //unsupported bits-per-pixel dataformat Showmessage('Unsupported BPP ='+inttostr(lHdr.ImgBufferBPP) ); result := true; end; //proc DICOMMirrorImgBuffer function ParseRGB (var lHdr: TMRIcroHdr): boolean;//RGB //red green blue saved as contiguous planes... var lInSlice,lOutSlice,lZ,lSliceSz,lSliceVox: integer; lP: bytep; begin result := false; lSliceSz := lHdr.NIFTIhdr.Dim[1]*lHdr.NIFTIhdr.Dim[2]; lZ := lSliceSz * 3 * lHdr.NIFTIhdr.Dim[3]; if lZ < 1 then exit; getmem( lP,lZ); Move(lHdr.ImgBuffer^,lP^,lZ); freemem(lHdr.ImgBufferUnaligned); lZ := lSliceSz * lHdr.NIFTIhdr.Dim[3]; GetMem(lHdr.ImgBufferUnaligned ,lZ+16); lHdr.ImgBuffer := ByteP($fffffff0 and (integer(lHdr.ImgBufferUnaligned)+15)); if (lHdr.Index mod 3) = 1 then //green lInSlice := lSliceSz else if (lHdr.Index mod 3) = 2 then//blue lInSlice := lSliceSz+lSliceSz else lInSlice := 0; lOutSlice := 0; for lZ := 1 to lHdr.NIFTIhdr.Dim[3] do begin for lSliceVox := 1 to lSliceSz do begin lHdr.ImgBuffer^[lSliceVox+lOutSlice] := lP^[lSliceVox+lInSlice]; end; inc(lOutSlice,lSliceSz); inc(lInSlice,lSliceSz+lSliceSz+lSliceSz); end; freemem(lP); for lZ := 0 to 255 do begin lHdr.LUT[lZ].rgbRed := 0; lHdr.LUT[lZ].rgbGreen := 0; lHdr.LUT[lZ].rgbBlue := 0; lHdr.LUT[lZ].rgbReserved := kLUTalpha; end; if (lHdr.Index mod 3) = 1 then begin//green for lZ := 0 to 255 do lHdr.LUT[lZ].rgbGreen := lZ; end else if (lHdr.Index mod 3) = 2 then begin //blue for lZ := 0 to 255 do lHdr.LUT[lZ].rgbBlue := lZ; end else begin for lZ := 0 to 255 do lHdr.LUT[lZ].rgbRed := lZ; end; result := true; end; (*function ParseRGB (var lHdr: TMRIcroHdr): boolean;//RGB //red green blue saved as contiguous planes... var lInSlice,lOutSlice,lZ,lSliceSz,lSliceVox: integer; lP: bytep; begin result := false; lSliceSz := lHdr.NIFTIhdr.Dim[1]*lHdr.NIFTIhdr.Dim[2]; lZ := lSliceSz * 3 * lHdr.NIFTIhdr.Dim[3]; if lZ < 1 then exit; getmem( lP,lZ); Move(lHdr.ImgBuffer^,lP^,lZ); freemem(lHdr.ImgBufferUnaligned); lZ := lSliceSz * lHdr.NIFTIhdr.Dim[3]; GetMem(lHdr.ImgBufferUnaligned ,lZ+16); {$IFDEF FPC} lHdr.ImgBuffer := align(lHdr.ImgBufferUnaligned,16); {$ELSE} lHdr.ImgBuffer := ByteP($fffffff0 and (integer(lHdr.ImgBufferUnaligned)+15)); {$ENDIF} if (lHdr.Index mod 3) = 1 then //green lInSlice := lSliceSz else if (lHdr.Index mod 3) = 2 then//blue lInSlice := lSliceSz+lSliceSz else lInSlice := 0; lOutSlice := 0; for lZ := 1 to lHdr.NIFTIhdr.Dim[3] do begin for lSliceVox := 1 to lSliceSz do begin lHdr.ImgBuffer^[lSliceVox+lOutSlice] := lP^[lSliceVox+lInSlice]; end; inc(lOutSlice,lSliceSz); inc(lInSlice,lSliceSz+lSliceSz+lSliceSz); end; freemem(lP); if (lHdr.Index mod 3) = 1 then //green lZ := 3 else if (lHdr.Index mod 3) = 2 then //blue lZ := 2 else //red lZ := 1; LoadMonochromeLUT (lZ, gBGImg, lHdr) ; result := true; end; *) procedure NonReslicedGB (var lBackgroundImg: TBGImg; var lImg2Load: TMRIcroHdr);//vcx begin if lImg2Load.NIfTItransform then lBackgroundImg.InvMat := Hdr2InvMat (lImg2Load.NIftiHdr,lImg2Load.NIfTItransform ); FindMatrixBounds(lBackgroundImg,lImg2Load,false); FindAlignment(lBackgroundImg,lImg2Load); MakeSameOrtho(lBackgroundImg,lImg2Load); end; procedure ReorientToNearestOrtho (var lBackgroundImg: TBGImg; var lImg2Load: TMRIcroHdr; lLoadBackground: boolean); //only apply this to the background image - other routines will reorient overlays begin lBackgroundImg.ReorientHdr := lImg2Load.NIFTIhdr;//vcx if not OrthoReorientCore(lImg2Load,false) then exit;//no change if not lLoadBackground then exit; //no change in bounding box lBackgroundImg.UseReorientHdr := true; NonReslicedGB(lBackgroundImg,lImg2Load); end; function OpenImg(var lBackgroundImg: TBGImg; var lImg2Load: TMRIcroHdr; lLoadBackground,lVOILoadAsBinary,lNoScaling8bit,lResliceIn,l4D: boolean): boolean; //lReslice: use orientation matrix to transform image -> do not use if l4D = true //l4D: load all slices of a 4D volume label 456; var lReslice,lSwap: boolean; lWordX: word; lP05,lP01,lFWE05,lFWE01,lFDR05,lFDR01:single; lMinI,lMaxI,lInc: integer; lMultiImgSzOff,lMultiImgSz,lOffset, lVol,lnVol,lFileSz,lDataType,lFSz,lImgSamples: Int64; //,lRow lP: Bytep; lFName,lParseName: String; F: file; l16Buf : SmallIntP; l32Buf,l32TempBuf : SingleP; l64Buf : DoubleP; begin lReslice := lResliceIn; if lLoadBackground then begin lBackgroundImg.LabelRA := nil; ImgForm.CloseImagesClick(nil); end; result := false; FreeImgMemory(lImg2Load); if not lImg2Load.DiskDataNativeEndian then lSwap := true else lSwap := false; if lLoadBackground then begin lBackgroundImg.UseReorientHdr := false;//vcx if(lImg2Load.NIFTIhdr.Dim[3] = 1) then lReslice := false; lBackgroundImg.Resliced := lReslice; if not lReslice then NonReslicedGB(lBackgroundImg,lImg2Load); FindMatrixBounds(lBackgroundImg,lImg2Load,lReslice); if (gBGImg.ScrnDim[1] < 2) or (gBGImg.ScrnDim[2] < 2) or (gBGImg.ScrnDim[3] < 1) then begin Showmessage('Error: this does not appear to be a valid 2D or 3D image.'); exit; end; if (gBGImg.ScrnDim[3] = 1) then begin lBackgroundImg.Resliced := false; //showmessage('x'); end; FindAlignment(lBackgroundImg,lImg2Load); end; if (not IsNifTiMagic(lImg2Load.niftiHdr)) or (lImg2Load.NIFTIhdr.sform_code < 1) or (lImg2Load.NIFTIhdr.sform_code > 10) then lBackgroundImg.KnownAlignment := false; if not lReslice then begin if lLoadBackground then begin //MakeSameOrtho(lBackgroundImg,lImg2Load); FindMatrixBounds(lBackgroundImg,lImg2Load,false); FindAlignment(lBackgroundImg,lImg2Load); MakeSameOrtho(lBackgroundImg,lImg2Load); end; end; //no reslice... lDataType := lImg2Load.NIFTIhdr.datatype; lFName := lImg2Load.ImgFileName; lMultiImgSz := ComputeImageDataBytes(lImg2Load); lOffset := round(lImg2Load.NIFTIhdr.vox_offset); lMultiImgSzOff := lMultiImgSz + abs(lOffset); if lImg2Load.NIFTIhdr.dim[4] < 1 then //June2009 - prevent error if 3D image sets field to zero instead of one lImg2Load.NIFTIhdr.dim[4] := 1; if lImg2Load.NIFTIhdr.dim[5] < 1 then //June2009 - prevent error if DTI image sets field to zero instead of one lImg2Load.NIFTIhdr.dim[5] := 1; lnVol := lImg2Load.NIFTIhdr.dim[4]*lImg2Load.NIFTIhdr.dim[5];//June2009 - for DTI data where direction is 5th dimension if lMultiImgSz < 1 then exit; lFSz := FSize(lFName); if (lFSz = 0) then Showmessage('Unable to find the image file '+lFName); lVol := 1; if lnVol > 1 then begin if lOffset < 0 then lFileSz := lMultiImgSzOff * lnVol else lFileSz := (lnVol * lMultiImgSz) + lOffset; lVol := 1; //alpha if {not l4D} lBackgroundImg.Prompt4DVolume then begin lVol := ReadIntForm.GetInt('Multi-volume file, please select volume to view.',1,1,lnVol); application.processmessages; end; end else lFileSz := lMultiImgSzOff; if ((lFileSz) > lFSz) and (lImg2Load.gzBytesX = K_gzBytes_headerAndImageUncompressed) then begin ShowMessage('Error: This image file is smaller than described in header.'+ ' Expected: '+inttostr(lFileSz)+' Selected:'+inttostr(lFSz)+ ' '+lFname); exit; end; {$I-} AssignFile(F, lFName); FileMode := 0; { Set file access to read only } Reset(F, 1); if (lImg2Load.gzBytesX <> K_gzBytes_headerAndImageUncompressed) then begin //deal with compressed data if (lImg2Load.gzBytesX = K_gzBytes_headerAndImageCompressed) then begin if lOffset < 0 then lOffset := abs(lOffset) + (lMultiImgSzOff *(lVol-1)) else lOffset := lOffset + (lMultiImgSz *(lVol-1)); end else lOffset := (lMultiImgSz *(lVol-1));//header UNCOMPRESSED! end else if lOffset < 0 then Seek (F,abs(lOffset) + (lMultiImgSzOff *(lVol-1)) ) else Seek (F,lOffset + (lMultiImgSz *(lVol-1)) ); case lDataType of kDT_SIGNED_SHORT,kDT_UINT16: lImg2Load.ImgBufferBPP := 2; kDT_SIGNED_INT,kDT_FLOAT: lImg2Load.ImgBufferBPP := 4; kDT_DOUBLE: lImg2Load.ImgBufferBPP := 8; kDT_UNSIGNED_CHAR : lImg2Load.ImgBufferBPP := 1; kDT_RGB: lImg2Load.ImgBufferBPP := 1;//rgb else begin showmessage('Unable to read this image format '+inttostr(lDataType)); goto 456; end; end; //Next get memory lImgSamples := round(ComputeImageDataBytes8bpp(lImg2Load)); lImg2Load.ImgBufferItems := lImgSamples; lMultiImgSz := (lImgSamples * lImg2Load.ImgBufferBPP); if lDataType = kDT_RGB then lMultiImgSz := lMultiImgSz * 3;//RGB if l4D then begin lMultiImgSz := lMultiImgSz * lnVol; lImgSamples := lImgSamples * lnVol; //Apr07 end; if lMultiImgSz > freeRam then begin Showmessage('Unable to load image: not enough RAM.'); goto 456; //exit; end; try GetMem(lImg2Load.ImgBufferUnaligned ,lMultiImgSz+16); except showmessage('Load Image Error: System memory exhausted.'); freemem(lImg2Load.ImgBufferUnaligned); //do goto 456 exit; end; lImg2Load.ImgBuffer := align(lImg2Load.ImgBufferUnaligned, 16); //Next Load Image if (lImg2Load.gzBytesX <> K_gzBytes_headerAndImageUncompressed) then begin lP := ByteP(lImg2Load.ImgBuffer); if lImg2Load.gzBytesX = K_gzBytes_headerAndImageCompressed then UnGZip(lFName,lP,lOffset,lMultiImgSz) else UnGZip2 (lFName,lP,lOffset,lMultiImgSz, round(lImg2Load.NIFTIhdr.vox_offset)); //unzip end else BlockRead(F,lImg2Load.ImgBuffer^,lMultiImgSz); if IOResult <> 0 then ShowMessage('Open image file error: '+inttostr(IOResult)); //Next: prepare image : byte swap, check for special.. case lDataType of kDT_RGB: ParseRGB(lImg2Load);//RGB kDT_SIGNED_SHORT,kDT_UINT16: begin //16-bit int l16Buf := SmallIntP(lImg2Load.ImgBuffer ); if lSwap then for lInc := 1 to lImgSamples do begin l16Buf^[lInc] := Swap2(l16Buf^[lInc]); end; if (kDT_UINT16=lDataType ) then begin //avoid wrap around if read as signed value for lInc := 1 to lImgSamples do begin lWordX := word(l16Buf^[lInc]); l16Buf^[lInc] := lWordX shr 1; end; //for end; //if kDT_UINT16 end; //16-bit kDT_SIGNED_INT: begin l32Buf := SingleP(lImg2Load.ImgBuffer ); if lSwap then //unswap and convert integer to float for lInc := 1 to lImgSamples do l32Buf^[lInc] := (Swap4r4i(l32Buf^[lInc])) else //convert integer to float for lInc := 1 to lImgSamples do l32Buf^[lInc] := Conv4r4i(l32Buf^[lInc]); end; //32-bit int kDT_FLOAT: begin l32Buf := SingleP(lImg2Load.ImgBuffer ); if lSwap then for lInc := 1 to lImgSamples do begin pswap4r(l32Buf^[lInc]) //faster as procedure than function see www.optimalcode.com end; for lInc := 1 to lImgSamples do if specialsingle(l32Buf^[lInc]) then l32Buf^[lInc] := 0.0; //thresh= for lInc := 1 to lImgSamples do if l32Buf[lInc] < 2.300611 then l32Buf[lInc] := 0.0; //invert= for lInc := 1 to lImgSamples do l32Buf[lInc] := -l32Buf[lInc]; end; //32-bit float kDT_DOUBLE: begin l64Buf := DoubleP(lImg2Load.ImgBuffer ); lImg2Load.ImgBufferBPP := 4; //we will save as 32-bit lMultiImgSz := (lImgSamples * lImg2Load.ImgBufferBPP); if l4D then begin lMultiImgSz := lMultiImgSz * lnVol; lImgSamples := lImgSamples * lnVol; //Apr07 end; try GetMem(l32TempBuf ,lMultiImgSz+16); except showmessage('64-bit Image Error: System memory exhausted.'); freemem(l32TempBuf); freemem(lImg2Load.ImgBufferUnaligned); exit; end; if lSwap then begin for lInc := 1 to lImgSamples do begin try l32TempBuf^[lInc] := Swap64r(l64Buf^[lInc]) except l32TempBuf^[lInc] := 0; end; //except end; //for end else begin for lInc := 1 to lImgSamples do begin try l32TempBuf^[lInc] := l64Buf^[lInc] except l32TempBuf^[lInc] := 0; end; //except end; //for end; //not swap //now copy from temp buffer to longer-term buffer freemem(lImg2Load.ImgBufferUnaligned); try GetMem(lImg2Load.ImgBufferUnaligned ,lMultiImgSz+16); except showmessage('Load Image Error: System memory exhausted.'); freemem(lImg2Load.ImgBufferUnaligned); exit; end; {$IFDEF FPC} lImg2Load.ImgBuffer := Align(lImg2Load.ImgBufferUnaligned, 16); {$ELSE} lImg2Load.ImgBuffer := ByteP($fffffff0 and (integer(lImg2Load.ImgBufferUnaligned)+15)); {$ENDIF} l32Buf := SingleP(lImg2Load.ImgBuffer ); Move(l32TempBuf^,l32Buf^,lMultiImgSz); freemem(l32TempBuf); for lInc := 1 to lImgSamples do if specialsingle(l32Buf^[lInc]) then l32Buf^[lInc] := 0.0; //for lInc := 1 to lImgSamples do // if specialsingle(l32Buf^[lInc]) then l32Buf^[lInc] := 0.0; end; //64-bit float kDT_UNSIGNED_CHAR : ; //else will be aborted at previous case end;//case lDataType of if (lDataType = kDT_RGB) then //do not transform else if lImg2Load.NIFTIhdr.magic = kNIFTI_MAGIC_DCM then DICOMMirrorImgBuffer(lImg2Load) else if (lLoadBackground) and (not lReslice) and (lBackgroundImg.KnownAlignment) and (lBackgroundImg.OrthoReslice) then ReorientToNearestOrtho(lBackgroundImg,lImg2Load,lLoadBackground) else if (l4D) and (not lReslice) and (lBackgroundImg.KnownAlignment) and (lBackgroundImg.OrthoReslice) then OrthoReorientCore(lImg2Load,true); //next correct image size if lImg2Load.NIFTIhdr.scl_slope = 0 then lImg2Load.NIFTIhdr.scl_slope := 1; if (lLoadBackground) and (not l4D) then ResliceScrnImg ( lBackgroundImg,lImg2Load,true) else if not l4D then ResliceScrnImg ( lBackgroundImg,lImg2Load,lBackgroundImg.OverlaySmooth); //12 April 2009 - allow nearest neighbor //Next: find min/max - better after reslicing incase we have padded zeros at the edges and zero < min case lImg2Load.ImgBufferBPP of 1: begin FindImgMinMax8 (lImg2Load, lMini,lMaxi); lImg2Load.GlMaxUnscaledS := lMaxI; lImg2Load.GlMinUnscaledS := lMinI;; end; 2: begin FindImgMinMax16 (lImg2Load, lMini,lMaxi); lImg2Load.GlMaxUnscaledS := lMaxI; lImg2Load.GlMinUnscaledS := lMinI;; end; 4: FindImgMinMax32 (lImg2Load,lImg2Load.GlMinUnscaledS,lImg2Load.GlMaxUnscaledS); else Showmessage('OpenImg and LoadImg error'); end; //case ImgBufferBPP balance(lImg2Load); //preparecontrast autobalance lImg2Load.WindowScaledMin := raw2ScaledIntensity(lImg2Load,lImg2Load.AutoBalMinUnscaled); lImg2Load.WindowScaledMax := raw2ScaledIntensity(lImg2Load,lImg2Load.AutoBalMaxUnscaled); if (lVOILoadAsBinary) then begin lImg2Load.WindowScaledMin := kMin8bit;//MAW lImg2Load.WindowScaledMax := kVOI8bit; lImg2Load.NIFTIhdr.scl_slope := 1; lImg2Load.NIFTIhdr.scl_inter := 0; end else if lDataType = kDT_RGB then begin//RGB lImg2Load.UsesCustomPalette := true; lImg2Load.NIFTIhdr.scl_slope := 1; lImg2Load.NIFTIhdr.scl_inter := 0; lImg2Load.WindowScaledMin := kMin8bit; lImg2Load.WindowScaledMax := 255; lImg2Load.AutoBalMinUnscaled := lImg2Load.WindowScaledMin; lImg2Load.AutoBalMaxUnscaled := lImg2Load.WindowScaledMax; end else if (lNoScaling8bit) and (lImg2Load.ImgBufferBPP = 1) then begin lImg2Load.UsesCustomPalette := false; lImg2Load.NIFTIhdr.scl_slope := 1; lImg2Load.NIFTIhdr.scl_inter := 0; lImg2Load.WindowScaledMin := kMin8bit; lImg2Load.WindowScaledMax := 255; lImg2Load.AutoBalMinUnscaled := lImg2Load.WindowScaledMin; lImg2Load.AutoBalMaxUnscaled := lImg2Load.WindowScaledMax; end else if (lImg2Load.NIFTIhdr.intent_code = kNIFTI_INTENT_ESTIMATE) and (lImg2Load.NIFTIhdr.intent_name[1] = '%') then begin lImg2Load.WindowScaledMin := kMin8bit; lImg2Load.WindowScaledMax := 100;//lImg2Load.GlMaxUnscaledS; lImg2Load.LutFromZero := true; lImg2Load.AutoBalMinUnscaled := lImg2Load.WindowScaledMin; lImg2Load.AutoBalMaxUnscaled := lImg2Load.WindowScaledMax; end else if ( (lImg2Load.NIFTIhdr.intent_code = NIFTI_INTENT_LOG10PVAL) or (lImg2Load.NIFTIhdr.intent_code =kNIFTI_INTENT_PVAL) or (lImg2Load.NIFTIhdr.intent_code = kNIFTI_INTENT_ZSCORE) or ((lImg2Load.NIFTIhdr.intent_code = kNIFTI_INTENT_TTEST) or (lImg2Load.NIFTIhdr.intent_code = kNIFTI_INTENT_CHISQ))) and (lImg2Load.ImgBufferBPP = 4) and (not l4D) then begin //ComputeFDR(lImg2Load.NIFTIhdr.intent_code,round(lImg2Load.NIFTIhdr.intent_p1),lImg2Load.ImgBufferItems,lImg2Load.ImgBufferBPP,lImg2Load.ImgBuffer,lP05,lP01,lFWE05,lFWE01,lFDR05,lFDR01); ComputeFDR(lImg2Load,lP05,lP01,lFWE05,lFWE01,lFDR05,lFDR01); if (Raw2ScaledIntensity(lImg2Load,lImg2Load.GlMaxUnscaledS)> lFDR05) and (lFDR05 > 0) then begin lImg2Load.WindowScaledMin := lFDR05; //0.001 xxx if lFDR01 > 0 then lImg2Load.WindowScaledMax := lFDR01 else lImg2Load.WindowScaledMax := 2*lFDR05; //0.000001 end else begin lImg2Load.WindowScaledMin := lP05; //0.001 xxx lImg2Load.WindowScaledMax := lP01; //0.000001 end; if (lImg2Load.WindowScaledMax < 0.00001) and (lImg2Load.WindowScaledMin < 0.00001) then begin lImg2Load.WindowScaledMax := 5; lImg2Load.WindowScaledMin := 0; end; lImg2Load.LutFromZero := true; lImg2Load.AutoBalMinUnscaled := lImg2Load.WindowScaledMin; lImg2Load.AutoBalMaxUnscaled := lImg2Load.WindowScaledMax; end else if (lImg2Load.NIFTIhdr.intent_code = kNIFTI_INTENT_LABEL) and (lImg2Load.ImgBufferBPP = 1) and (lImg2Load.NIFTIhdr.regular = char(98)) then begin //createLutLabel (lImg2Load, 1.0); LoadLabelLUT(lBackgroundImg,lImg2Load); lImg2Load.NIFTIhdr.scl_slope := 1; lImg2Load.NIFTIhdr.scl_inter := 0; lImg2Load.WindowScaledMin := kMin8bit; lImg2Load.WindowScaledMax := 255; lImg2Load.UsesCustomPalette := true; lImg2Load.AutoBalMinUnscaled := lImg2Load.WindowScaledMin; lImg2Load.AutoBalMaxUnscaled := lImg2Load.WindowScaledMax; end else if (lImg2Load.NIFTIhdr.intent_code = kNIFTI_INTENT_LABEL) and ((lImg2Load.ImgBufferBPP = 1) or (lImg2Load.ImgBufferBPP = 2)) then begin createLutLabel (lImg2Load.LUT, 1.0); lImg2Load.NIFTIhdr.scl_slope := 1; lImg2Load.NIFTIhdr.scl_inter := 0; lImg2Load.WindowScaledMin := 0;//kMin8bit; lImg2Load.WindowScaledMax := 100;//255; lImg2Load.UsesCustomPalette := true; lImg2Load.UsesCustomPaletteRandomRainbow := true; lImg2Load.AutoBalMinUnscaled := lImg2Load.WindowScaledMin; lImg2Load.AutoBalMaxUnscaled := lImg2Load.WindowScaledMax; if {lLoadBackground} true then begin if (( lImg2Load.NIFTIhdr.vox_offset- lImg2Load.NIFTIhdr.HdrSz) > 128) then LoadLabels(lImg2Load.HdrFileName,lBackgroundImg.LabelRA, lImg2Load.NIFTIhdr.HdrSz, round( lImg2Load.NIFTIhdr.vox_offset)) else LoadLabelsTxt(lImg2Load.HdrFileName, lBackgroundImg.LabelRA); if (High(lBackgroundImg.LabelRA) < 1) and (lImg2Load.ImgBufferBPP = 1) then LoadLabelsOld(lBackgroundImg,lImg2Load); if High(lBackgroundImg.LabelRA) > 0 then lImg2Load.UsesLabels := true; //showmessage(inttostr(High(lBackgroundImg.LabelRA) )+'xxx'); end //ImgForm.Help1.caption := 'imaw'+realtostr(lImg2Load.WindowScaledMin,4);//maw end else begin if (lImg2Load.NIFTIhdr.intent_code = kNIFTI_INTENT_LABEL) then begin//>only called when BPP <> 1 LoadLabelLUT(lBackgroundImg,lImg2Load); end; lImg2Load.UsesCustomPalette := false; lImg2Load.WindowScaledMin := raw2ScaledIntensity(lImg2Load,lImg2Load.AutoBalMinUnscaled); lImg2Load.WindowScaledMax := raw2ScaledIntensity(lImg2Load,lImg2Load.AutoBalMaxUnscaled); end; lParseName := parsefilename(extractfilename(lImg2Load.HdrFileName)); if (lParsename = 'ch2bet') or (lParseName = 'ch2better') then begin lImg2Load.WindowScaledMin := 45; lImg2Load.WindowScaledMax := 120; lImg2Load.AutoBalMinUnscaled := lImg2Load.WindowScaledMin; lImg2Load.AutoBalMaxUnscaled := lImg2Load.WindowScaledMax; end; if lParseName = 'ch2' then begin lImg2Load.WindowScaledMin := 30; lImg2Load.WindowScaledMax := 120; lImg2Load.AutoBalMinUnscaled := lImg2Load.WindowScaledMin; lImg2Load.AutoBalMaxUnscaled := lImg2Load.WindowScaledMax; end; //Next: create screen buffer [scaled to background] //if not l4D then //12/2007: do not create screen buffer for 4D load! saves memory and time // RescaleImgIntensity (lBackgroundImg,lImg2Load); if not l4D then begin//12/2007: do not create screen buffer for 4D load! saves memory and time if lLoadBackground then RescaleImgIntensity (lBackgroundImg,lImg2Load,kBGOverlayNum) else RescaleImgIntensity (lBackgroundImg,lImg2Load,kVOIOverlayNum); end; if (lVOILoadAsBinary) and (lImg2Load.ScrnBufferItems> 0) then begin if lImg2Load.NIFTIhdr.intent_name[1] = 'I' then //indexed showmessage('Indexed drawing - assuming drawing is binary. You may want to upgrade this software.'); gBGImg.VOIchanged := false; for lInc := 1 to lImg2Load.ScrnBufferItems do if lImg2Load.ScrnBuffer^[lInc] > 1 then lImg2Load.ScrnBuffer^[lInc] := kVOI8bit; lMaxI := maxint; LoadMonochromeLUT(lMaxi,lBackgroundImg,lImg2Load); if lImg2Load.ImgBufferItems > 1 then freemem(lImg2Load.ImgBufferUnaligned); lImg2Load.ImgBufferItems := 0; end else begin ImgForm.LayerDropSelect(nil); ImgForm.LUTdropSelect(nil); end; result := true; 456: CloseFile(F); {$I+} FileMode := 2; end; //proc OpenImg end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_macscriptppc.bat��������������������������������������������������0000755�0001750�0001750�00000000671�11266164562�017537� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������chmod 777 ./_xclean.bat ./_xclean.bat cp ./common/notgui.inc ./common/isgui.inc lazbuild ./dcm2nii/dcm2nii.lpr cp ./dcm2nii/dcm2nii ../distro/ppc/dcm2nii ./_xclean.bat cp ./common/gui.inc ./common/isgui.inc lazbuild ./mricron.lpr --ws=carbon lazbuild ./npm/npm.lpr --ws=carbon lazbuild ./dcm2nii/dcm2niigui.lpr --ws=carbon cp ./mricron ../distro/ppc/mricron cp ./npm/npm ../distro/ppc/npm cp ./dcm2nii/dcm2niigui ../distro/ppc/dcm2niigui �����������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/winres.res���������������������������������������������������������0000755�0001750�0001750�00000022432�10617722466�016243� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ������������������������� �������������������(��� ���@���� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ������������������������������������������������������������������������������������������$"�|z����� �����������������������������������������������������������������������������������0*�ja�����+ ���������������������������������������������������������������������������� /)� >� ������������������������������������������������������������������������� �@� ��������������������������42�42�43�������m������������ ���������������DBDBDC�Tf�����`j�����/}�� N����������������DL�DL�DNA=#k#(��G(���������  ��������#�� 7^q{��|�wmeU<��������a� � �}�r�I���a� ��*Z(���$�o> ����/�~�7YeW@���M�������������d�L�  ��{���������))��� ,.+-!&(,,�"" � $ O�� " "�vx�����##� �..���������uw�������� ��gy� [�������Z\���������������� �����pr��������������������������������+��;� g���������������������������������������������� �c� � '�� ���������������������������������������������������''!�-'�5k<4/5 55�45������� ����������������������������������������������������������&&�!,'���n;�.� ������������������������������������������������������������������������������������ �,5# �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?���� �� �������������������(������0���� �����` ������������������������������������������������������������������� ������������������������������������������������������������������������������ ������������������������������������������������������$"��������� KC����������������������������������������������$&�����  � %  ��������������42�42�64*-��''�*,�V ������ �������M"��0�1�3�)/�Yb�BG�U����U[�Y Z����������3�4 �6$"a++`%(����'p l � N) 0 0 ,������7P�� C �0z�\�� �g>�N�l �� �v�GY����� `�^f����O� {����|������������B���D��� /1x.0�02�� Y��x � ���  �@ ��   � ���������������O���"$M��JL�JL��������������� � �� K �!#����������������������������������� ER P"OPP�J ������!#���������������������������������������� �Q!�#� ���� ����������������������������������������������������||������ _1  ���������������������������������������������������������������������������������������������������������������������������������������?�������������������������������������O����h�� �������������������(������ ���� �����@���������������������������������������� �� ������������������������$&�48���� �  � � �����!7<���� YA���� ����������-�*3�'.�: �� ,*b* �������%$ 3 A '���I� MOu���O0�%��"�A�n L��� 5#�N�����^�v����� �  �� +-<>� L�#S����������� P�d� 2 ������������!!��� (Pk*i�jP �56�������������� �X �1��� ��13������������������������ T D � �(*��������������������������������������������������������*��� �����������������������E�m�p�t�y�������������������������������0���.����M�A�I�N�I�C�O�N����������������������� ������������� ��������h���t�� ���������������������t4���V�S�_�V�E�R�S�I�O�N�_�I�N�F�O����������������������������������������������������S�t�r�i�n�g�F�i�l�e�I�n�f�o�������0�4�0�9�0�4�E�4���>���C�o�m�p�a�n�y�N�a�m�e�����w�w�w�.�m�r�i�c�r�o�.�c�o�m�����0���F�i�l�e�V�e�r�s�i�o�n�����0�.�7�.�5�.�0���*���F�i�l�e�D�e�s�c�r�i�p�t�i�o�n���������0���I�n�t�e�r�n�a�l�N�a�m�e���m�r�i�c�r�o�n���&���L�e�g�a�l�C�o�p�y�r�i�g�h�t�������*���L�e�g�a�l�T�r�a�d�e�m�a�r�k�s���������*���O�r�i�g�i�n�a�l�F�i�l�e�n�a�m�e�������"���P�r�o�d�u�c�t�N�a�m�e���������&���P�r�o�d�u�c�t�V�e�r�s�i�o�n�������D�����V�a�r�F�i�l�e�I�n�f�o�����$����T�r�a�n�s�l�a�t�i�o�n����� �� ��������������������<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Lazarus Program" type="win32" /> <description>A program made under Lazarus</description> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" /> </dependentAssembly> </dependency> </assembly> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/examplecut.bat�����������������������������������������������������0000755�0001750�0001750�00000000127�10416600046�017037� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������start mricron .\templates\ch2bet.nii.gz -s 3 -c pink -l 40 -h 120 -r .\example\cutr.ini�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/���������������������������������������������������������������0000755�0001750�0001750�00000000000�12413465015�014773� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/ReadInt.lrs����������������������������������������������������0000755�0001750�0001750�00000002317�11540170632�017047� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TReadIntForm','FORMDATA',[ 'TPF0'#12'TReadIntForm'#11'ReadIntForm'#4'Left'#3'2'#1#6'Height'#2'P'#3'Top'#3 +'*'#2#5'Width'#3#213#1#18'HorzScrollBar.Page'#3#212#1#18'VertScrollBar.Page' +#2'O'#13'ActiveControl'#7#11'ReadIntEdit'#11'BorderStyle'#7#8'bsDialog'#7'Ca' +'ption'#6#16'Integer required'#12'ClientHeight'#2'P'#11'ClientWidth'#3#213#1 +#21'Constraints.MaxHeight'#2'P'#20'Constraints.MaxWidth'#3#213#1#21'Constrai' +'nts.MinHeight'#2'P'#20'Constraints.MinWidth'#3#213#1#9'Font.Name'#6#13'MS S' +'ans Serif'#8'OnCreate'#7#10'FormCreate'#8'Position'#7#14'poScreenCenter'#10 +'LCLVersion'#6#8'0.9.28.2'#0#6'TLabel'#12'ReadIntLabel'#4'Left'#2#16#6'Heigh' +'t'#2#14#3'Top'#2#12#5'Width'#3'P'#1#9'Alignment'#7#14'taRightJustify'#8'Aut' +'oSize'#8#7'Caption'#6#14'Enter a number'#11'ParentColor'#8#0#0#9'TSpinEdit' +#11'ReadIntEdit'#4'Left'#3'h'#1#6'Height'#2#27#3'Top'#2#12#5'Width'#2']'#8'M' +'axValue'#2#0#8'TabOrder'#2#0#0#0#7'TButton'#5'OKBtn'#4'Left'#3'p'#1#6'Heigh' +'t'#2#25#3'Top'#2','#5'Width'#2'K'#25'BorderSpacing.InnerBorder'#2#4#7'Capti' +'on'#6#2'OK'#7'OnClick'#7#10'OKBtnClick'#8'TabOrder'#2#1#0#0#0 ]); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/spread.lrs�����������������������������������������������������0000755�0001750�0001750�00000012021�12147213330�016765� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TSpreadForm','FORMDATA',[ 'TPF0'#11'TSpreadForm'#10'SpreadForm'#4'Left'#3#145#1#6'Height'#3#26#2#3'Top' +#3#183#0#5'Width'#3'F'#1#13'ActiveControl'#7#8'DataGrid'#7'Caption'#6#29'Vox' +'elwise Analysis of Lesions'#12'ClientHeight'#3#26#2#11'ClientWidth'#3'F'#1#9 +'Font.Name'#6#13'MS Sans Serif'#4'Menu'#7#9'MainMenu1'#7'OnClose'#7#9'FormCl' +'ose'#8'OnCreate'#7#10'FormCreate'#8'OnResize'#7#10'FormResize'#8'Position'#7 +#14'poScreenCenter'#10'LCLVersion'#6#8'0.9.30.2'#0#11'TStringGrid'#8'DataGri' +'d'#4'Left'#2#0#6'Height'#3#242#1#3'Top'#2#25#5'Width'#3'F'#1#5'Align'#7#8'a' +'lClient'#9'FixedRows'#2#2#7'Options'#11#15'goFixedVertLine'#10'goVertLine' +#10'goHorzLine'#13'goRangeSelect'#19'goDrawFocusSelected'#6'goTabs'#15'goThu' +'mbTracking'#0#8'RowCount'#2#12#8'TabOrder'#2#0#14'TitleFont.Name'#6#13'MS S' +'ans Serif'#10'OnDrawCell'#7#16'DataGridDrawCell'#10'OnKeyPress'#7#16'DataGr' +'idKeyPress'#11'OnMouseDown'#7#17'DataGridMouseDown'#11'OnMouseMove'#7#17'Da' +'taGridMouseMove'#12'OnSelectCell'#7#18'DataGridSelectCell'#0#0#8'TToolBar'#8 +'ToolBar1'#4'Left'#2#0#6'Height'#2#25#3'Top'#2#0#5'Width'#3'F'#1#11'EdgeBord' +'ers'#11#0#8'TabOrder'#2#1#0#12'TSpeedButton'#9'DesignBtn'#4'Left'#2#1#6'Hei' +'ght'#2#22#4'Hint'#6#5'ANOVA'#3'Top'#2#0#5'Width'#2'x'#7'Caption'#6#6'Design' +#10'Glyph.Data'#10'z'#1#0#0'v'#1#0#0'BMv'#1#0#0#0#0#0#0'v'#0#0#0'('#0#0#0' ' +#0#0#0#16#0#0#0#1#0#4#0#0#0#0#0#0#1#0#0#0#0#0#0#0#0#0#0#16#0#0#0#16#0#0#0#0#0 +#0#0#0#0#128#0#0#128#0#0#0#128#128#0#128#0#0#0#128#0#128#0#128#128#0#0#127 +#127#127#0#191#191#191#0#0#0#255#0#0#255#0#0#0#255#255#0#255#0#0#0#255#0#255 +#0#255#255#0#0#255#255#255#0'3s3s3s3s3'#127'?'#127'?'#127'?'#127'3sssssss?' +#127#127#127#127#127#127#127'w'#0#0#0#0#0#0#0'wwwwwwww3'#3'33<3333'#127#255 +'37'#243'3?7'#9#147'3<33'#153'7ws'#243'7'#243'3w3'#3'93<393?'#127#247#255#247 +#255#247#255'w'#7'w'#151'|w'#151'wwwwwwwww3'#3'3'#147'<3'#147'33'#127'3s'#247 +#243's37'#3'39<9337'#127'377'#247'333'#3'33'#153#147'33?'#127#255#255'w'#127 +#255#255'w'#7'ww|wwwwwwwwwww3'#3'33<3'#3'33'#127'337'#255#127#243'7'#3'33<'#0 +#0'<7'#127'337ww73'#3'33<3'#3'3?'#127#255#255#247#255#127#255'w'#7'wwwwwwwww' +'wwwww3333333333333333'#9'NumGlyphs'#2#2#7'OnClick'#7#14'DesignBtnClick'#8'S' +'howHint'#9#14'ParentShowHint'#8#0#0#0#10'TStatusBar'#10'StatusBar1'#4'Left' +#2#0#6'Height'#2#15#3'Top'#3#11#2#5'Width'#3'F'#1#6'Panels'#14#1#5'Width'#3 +#140#0#0#1#5'Width'#2'2'#0#0#11'SimplePanel'#8#0#0#9'TMainMenu'#9'MainMenu1' +#4'left'#2'l'#3'top'#2','#0#9'TMenuItem'#5'File1'#7'Caption'#6#5'&File'#0#9 +'TMenuItem'#4'New1'#7'Caption'#6#6'New...'#8'ShortCut'#3'N@'#7'OnClick'#7#11 +'NewBtnClick'#0#0#9'TMenuItem'#5'Open1'#7'Caption'#6#7'Open...'#8'ShortCut'#3 +'O@'#7'OnClick'#7#12'OpenBtnClick'#0#0#9'TMenuItem'#5'Save1'#7'Caption'#6#4 +'Save'#8'ShortCut'#3'S@'#7'OnClick'#7#12'SaveBtnClick'#0#0#9'TMenuItem'#5'Qu' +'it1'#7'Caption'#6#12'Close window'#8'ShortCut'#3'W@'#7'OnClick'#7#10'Quit1C' +'lick'#0#0#0#9'TMenuItem'#5'Edit1'#7'Caption'#6#4'Edit'#0#9'TMenuItem'#5'Cop' +'y1'#7'Caption'#6#4'Copy'#8'ShortCut'#3'C@'#7'OnClick'#7#10'Copy1Click'#0#0#9 +'TMenuItem'#6'Paste1'#7'Caption'#6#5'Paste'#8'ShortCut'#3'V@'#7'OnClick'#7#11 +'Paste1Click'#0#0#9'TMenuItem'#10'Selectall1'#7'Caption'#6#16'Select all cel' +'ls'#8'ShortCut'#3'A@'#7'OnClick'#7#15'Selectall1Click'#0#0#9'TMenuItem'#14 +'Clearallcells1'#7'Caption'#6#18'Clear all cells...'#7'OnClick'#7#19'Clearal' +'lcells1Click'#0#0#9'TMenuItem'#15'DescriptiveMenu'#7'Caption'#6#12'Descript' +'ives'#7'OnClick'#7#16'DescriptiveClick'#0#0#0#9'TMenuItem'#4'View'#7'Captio' +'n'#6#4'View'#0#9'TMenuItem'#5'Font1'#7'Caption'#6#4'Font'#0#9'TMenuItem'#3 +'N81'#3'Tag'#2#8#7'Caption'#6#1'8'#7'Checked'#9#10'GroupIndex'#2'o'#9'RadioI' +'tem'#9#7'OnClick'#7#14'FontSizeChange'#0#0#9'TMenuItem'#4'N101'#3'Tag'#2#10 +#7'Caption'#6#2'10'#10'GroupIndex'#2'o'#9'RadioItem'#9#7'OnClick'#7#14'FontS' +'izeChange'#0#0#9'TMenuItem'#4'N121'#3'Tag'#2#12#7'Caption'#6#2'12'#10'Group' +'Index'#2'o'#9'RadioItem'#9#7'OnClick'#7#14'FontSizeChange'#0#0#9'TMenuItem' +#4'N141'#3'Tag'#2#14#7'Caption'#6#2'14'#10'GroupIndex'#2'o'#9'RadioItem'#9#7 +'OnClick'#7#14'FontSizeChange'#0#0#0#9'TMenuItem'#7'Design1'#7'Caption'#6#6 +'Design'#8'ShortCut'#3'D@'#7'OnClick'#7#14'DesignBtnClick'#0#0#0#9'TMenuItem' +#5'Help1'#7'Caption'#6#5'&Help'#0#9'TMenuItem'#18'Aboutthissoftware1'#7'Capt' +'ion'#6#20'&About this software'#7'OnClick'#7#23'Aboutthissoftware1Click'#0#0 +#0#0#11'TOpenDialog'#11'OpenDialog1'#10'DefaultExt'#6#4'.val'#6'Filter'#6'<N' +'ative [val]|.val|Tab delimited text [txt]|.txt|All files|.*'#11'FilterIndex' +#2#0#4'left'#2'$'#3'top'#2','#0#0#11'TSaveDialog'#11'SaveDialog1'#10'Default' +'Ext'#6#4'.val'#6'Filter'#6'8Native format [val]|*.val|Tab delimited text [t' +'xt]|*.txt'#11'FilterIndex'#2#0#7'Options'#11#17'ofOverwritePrompt'#14'ofHid' +'eReadOnly'#0#4'left'#2'J'#3'top'#2','#0#0#0 ]); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/Copy of turbolesion.pas����������������������������������������0000755�0001750�0001750�00000026274�11326443506�021346� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit turbolesion; interface {$H+} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes; Type TLDMPrefs = record NULP,BMtest,Ttest,Ltest: boolean; nCrit,nPermute,Run{0 except for montecarlo}: integer; NameAppend: string; end; implementation uses npmform; {$DEFINE NOTmedianfx} function TurboLDM (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lPrefs: TLDMPrefs ; var lSymptomRA: SingleP;var lFactname,lOutName: string): boolean; label 123,667; var lOutNameMod: string; lPlankImg: byteP; lOutImgSum,lOutImgBM,lOutImgT,lOutImgAUC, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP; lPos,lPlank,lThread: integer; lVolVox,lMinMask,lMaxMask,lTotalMemory,lnPlanks,lVoxPerPlank, lThreadStart,lThreadEnd,lThreadInc,lnLesion,//,lnPermute, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT,lBMz, lSum,lThresh,lThreshPermute,lThreshBonf,lThreshNULP :double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; lPlankAllocated: boolean; //lttest,lBM: boolean; {$IFDEF medianfx} lmedianFX,lmeanFX,lsummean,lsummedian: double; lmediancount: integer; {$ENDIF} begin //lttest:= ttestmenu.checked; //lBM := BMmenu.checked; lPlankAllocated := false; //lnPermute := MainForm.ReadPermute; MainForm.NPMmsg('Permutations = ' +IntToStr(lPrefs.nPermute)); MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; MainForm.NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); MainForm.NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) //assumes 1bpp else getmem(lPlankImg,kPlankSz); lPlankAllocated := true; lStartVox := lMinMask; lEndVox := lMinMask-1; {$IFDEF medianfx} lsummean := 0; lsummedian:= 0; lmediancount := 0; {$ENDIF} for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; createArray64(lObsp,lObs,lImages.Count); getmem(lOutImgSum,lVolVox* sizeof(single)); getmem(lOutImgBM,lVolVox* sizeof(single)); getmem(lOutImgT,lVolVox* sizeof(single)); getmem(lOutImgAUC,lVolVox* sizeof(single)); MainForm.InitPermute (lImages.Count, lPrefs.nPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; lOutImgAUC^[lPos] := 0; end; //next create permuted BM bounds if lPrefs.BMtest then begin MainForm.NPMmsg('Generating BM permutation thresholds'); MainForm.Refresh; for lPos := 1 to lImages.Count do lObs^[lPos-1] := lSymptomRA^[lPos]; genBMsim (lImages.Count, lObs); end; ClearThreadData(gnCPUThreads,lPrefs.nPermute) ; for lPlank := 1 to lnPlanks do begin MainForm.NPMmsg('Computing plank = ' +Inttostr(lPlank)); MainForm.Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TLesionContinuous.Create (MainForm.ProgressBar1,lPrefs.ttest,lPrefs.BMtest,lPrefs.nCrit, lPrefs.nPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,0,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA) do //with TLesionContinuous.Create (MainForm.ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,lSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; //freemem(lPlankImg); //lPlankAllocated := false; lThreshPermute := 0; lnVoxTested := SumThreadData(gnCPUThreads,lPrefs.nPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //next report findings if lnVoxTested < 1 then begin MainForm.NPMmsg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lPrefs.nCrit)+' patients**'); goto 123; end; MainForm.NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); {$IFDEF medianfx} MainForm.NPMmsg('Average MEAN effect size = ' +realtostr((lsummean/lmediancount),3)); MainForm.NPMmsg('Average MEDIAN effect size = ' +realtostr((lsummedian/lmediancount),3)); {$ENDIF} MainForm.NPMmsg('Only tested voxels with more than '+inttostr(lPrefs.nCrit)+' lesions'); //Next: save results from permutation thresholding.... lThreshBonf := MainForm.reportBonferroni('Std',lnVoxTested); //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); if lPrefs.Run < 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //save Area Under Curve lOutNameMod := ChangeFilePostfixExt(lOutName,'rocAUC'+lFactName,'.hdr'); if lPrefs.Run < 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgAUC,1); //create new header - subsequent images will use Z-scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lPrefs.Run < 1) and (Sum2PowerCont(lOutImgSum,lVolVox,lImages.Count)) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; if lPrefs.Run > 0 then //terrible place to do this - RAM problems, but need value to threshold maps lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap2 (lImages, lPrefs.nCrit,lnVoxTested,lPlankImg)); //MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if lPrefs.ttest then begin //save Ttest //next: convert t-scores to z scores for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lPrefs.nPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; lThresh := MainForm.reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); lThreshPermute := MainForm.reportPermute('ttest',lPrefs.nPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'ttest'+lFactName,'.hdr'); if lPrefs.Run > 0 then MainForm.NPMmsgAppend('threshtt,'+inttostr(lPrefs.Run)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgT))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if lPrefs.BMtest then begin //save Brunner Munzel lThresh := MainForm.reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); lThreshPermute := MainForm.reportPermute('BM',lPrefs.nPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'BM'+lFactName,'.hdr'); if lPrefs.Run > 0 then MainForm.NPMmsgAppend('threshbm,'+inttostr(lPrefs.Run)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgBM))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end; //next: free dynamic memory 123: MainForm.FreePermute (lPrefs.nPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgT); freemem(lOutImgAUC); freemem(lOutImgBM); freemem(lOutImgSum); freemem(lObsp); if lPlankAllocated then freemem(lPlankImg); //Next: NULPS - do this after closing all memory - this is a memory hog if lPrefs.NULP then lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap (lImages, lPrefs.nCrit,lnVoxTested)); MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); MainForm.MsgSave(lOutNameMod); MainForm.ProgressBar1.Position := 0; //if lRun > 0 then // AX(freeram,freeram,freeram,freeram,freeram,freeram); exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; //LesionNPMAnalyze end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/���������������������������������������������������������0000755�0001750�0001750�00000000000�12360760644�016077� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/polynom.pas����������������������������������������������0000755�0001750�0001750�00000015174�11326443506�020310� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit POLYNOM.PAS * * Version 1.3 * * (c) J. Debord, January 1998 * ********************************************************************** This unit implements routines for polynomials and rational fractions. ********************************************************************** Reference: 'Numerical Recipes' by Press et al. ********************************************************************** } unit Polynom; interface uses FMath, Matrices, Eigen, Stat; function Poly(X : Float; Coef : PVector; Deg : Integer) : Float; { ---------------------------------------------------------------------- Evaluates the polynomial : P(X) = Coef[0] + Coef[1] * X + Coef[2] * X^2 +...+ Coef[Deg] * X^Deg ---------------------------------------------------------------------- } function RRootPol(Coef : PVector; Deg : Integer; X : PVector) : Integer; { ---------------------------------------------------------------------- Real roots of a polynomial. The roots are computed analytically if Deg <= 3, otherwise they are computed numerically from the eigenvalues of the companion matrix (function RootPol in EIGEN.PAS). The roots are returned in X (in increasing order). The function returns the number of real roots found. ---------------------------------------------------------------------- } function CRootPol(Coef : PVector; Deg : Integer; X_Re, X_Im : PVector) : Integer; { ---------------------------------------------------------------------- Complex roots of a polynomial. The roots are computed numerically from the eigenvalues of the companion matrix (function RootPol in EIGEN.PAS). The real and imaginary parts of the roots are returned in X_Re and X_Im (in increasing order of the real parts). The function returns the number of roots found, which may be Deg or zero if the method did not converge. ---------------------------------------------------------------------- } function RFrac(X : Float; Coef : PVector; Deg1, Deg2 : Integer) : Float; { ---------------------------------------------------------------------- Evaluates the rational fraction : Coef[0] + Coef[1] * X + ... + Coef[Deg1] * X^Deg1 F(X) = ----------------------------------------------------- 1 + Coef[Deg1+1] * X + ... + Coef[Deg1+Deg2] * X^Deg2 ---------------------------------------------------------------------- } implementation const MAXDEG = 3; { Maximal degree for analytical solution of polynomial } function Poly(X : Float; Coef : PVector; Deg : Integer) : Float; var I : Integer; Y : Float; begin Y := Coef^[Deg]; for I := Pred(Deg) downto 0 do Y := Y * X + Coef^[I]; Poly := Y; end; function RFrac(X : Float; Coef : PVector; Deg1, Deg2 : Integer) : Float; var I : Integer; Sum : Float; { Denominator sum } begin Sum := 0.0; for I := (Deg1 + Deg2) downto Succ(Deg1) do Sum := (Sum + Coef^[I]) * X; RFrac := Poly(X, Coef, Deg1) / (1.0 + Sum); end; function RootPol3(Coef : PVector; Deg : Integer; X : PVector) : Integer; { Real roots of polynomial up to degree 3 (Analytical solution) } const PI2DIV3 = 2.0943951023931954923; { 2*pi/3 } var NR : Integer; { Number of roots } R, R2, Q, Q3, Delta, A0, A1, A2, A22, A3, AA, BB, Theta, Z : Float; begin if (Deg < 1) or (Deg > MAXDEG) then begin RootPol3 := 0; Exit; end; case Deg of 1 : begin NR := 1; X^[1] := - Coef^[0] / Coef^[1]; end; 2 : begin Delta := Sqr(Coef^[1]) - 4.0 * Coef^[0] * Coef^[2]; if Delta < 0 then NR := 0 else begin NR := 2; if Coef^[1] >= 0 then Q := - 0.5 * (Coef^[1] + Sqrt(Delta)) else Q := - 0.5 * (Coef^[1] - Sqrt(Delta)); X^[1] := Q / Coef^[2]; X^[2] := Coef^[0] / Q; end; end; 3 : begin A0 := Coef^[0] / Coef^[3]; A1 := Coef^[1] / Coef^[3]; A2 := Coef^[2] / Coef^[3]; A3 := A2 / 3.0; A22 := Sqr(A2); Q := (A22 - 3.0 * A1) / 9.0; R := (A2 * (2.0 * A22 - 9.0 * A1) + 27.0 * A0) / 54.0; R2 := R * R; Q3 := Q * Q * Q; Delta := Q3 - R2; if Delta < 0 then begin NR := 1; AA := Power(Abs(R) + Sqrt(- Delta), 0.333333333333333); if R >= 0 then AA := - AA; if AA <> 0 then BB := Q / AA else BB := 0.0; X^[1] := (AA + BB) - A3; end else begin NR := 3; Theta := ArcCos(R / Sqrt(Q3)) / 3.0; Z := - 2.0 * Sqrt(Q); X^[1] := Z * Cos(Theta) - A3; X^[2] := Z * Cos(Theta + PI2DIV3) - A3; X^[3] := Z * Cos(Theta - PI2DIV3) - A3; end; end; end; QSort(X, 1, Deg); RootPol3 := NR; end; function RRootPol(Coef : PVector; Deg : Integer; X : PVector) : Integer; var N : Integer; { Number of real roots } X_Re, X_Im : PVector; { Real and imaginary parts } ErrCode : Integer; { Error code } I : Integer; { Loop variable } begin DimVector(X_Re, Deg); DimVector(X_Im, Deg); if Deg <= MAXDEG then RRootPol := RootPol3(Coef, Deg, X) else begin ErrCode := RootPol(Coef, Deg, X_Re, X_Im); if ErrCode = MAT_OK then begin { Get real roots } N := 0; for I := 1 to Deg do if Abs(X_Im^[I]) <= MACHEP then begin Inc(N); X^[N] := X_Re^[I]; end; { Set other roots to zero } for I := Succ(N) to Deg do X^[I] := 0.0; RRootPol := N; end else RRootPol := 0; end; DelVector(X_Re, Deg); DelVector(X_Im, Deg); end; function CRootPol(Coef : PVector; Deg : Integer; X_Re, X_Im : PVector) : Integer; begin if RootPol(Coef, Deg, X_Re, X_Im) = MAT_OK then CRootPol := Deg else CRootPol := 0; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/fitmich.pas����������������������������������������������0000755�0001750�0001750�00000011675�11326443506�020240� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITMICH.PAS * * Version 1.0 * * (c) J. Debord, April 1998 * ********************************************************************** This unit fits the Michaelis equation : Ymax . x y = -------- Km + x ********************************************************************** } unit FitMich; {$F+} interface uses FMath, Matrices, Stat, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X, Y : Float; B, D : PVector); function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; implementation function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } begin FuncName := 'y = Ymax . x / (Km + x)'; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 1; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'Ymax'; 1 : ParamName := 'Km '; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = Ymax B^[1] = Km -------------------------------------------------------------------- } begin RegFunc := B^[0] * X / (B^[1] + X); end; procedure DerivProc(X, Y : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point (X,Y) with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter -------------------------------------------------------------------- } begin D^[0] := Y / B^[0]; { dy/dYmax = x / (Km + x) } D^[1] := - Y / (B^[1] + X); { dy/dKm = - Ymax.x / (Km + x)^2 } end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of the Michaelis equation by linear regression: 1/y = 1/Ymax + (Km/Ymax) * (1/x) -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- } var X1, Y1 : PVector; { Transformed coordinates } W1 : PVector; { Weights } A : PVector; { Linear regression parameters } V : PMatrix; { Variance-covariance matrix } P : Integer; { Number of points for linear regression } K : Integer; { Loop variable } ErrCode : Integer; { Error code } begin DimVector(X1, N); DimVector(Y1, N); DimVector(W1, N); DimVector(A, 1); DimMatrix(V, 1, 1); P := 0; for K := 1 to N do if (X^[K] > 0.0) and (Y^[K] > 0.0) then begin Inc(P); X1^[P] := 1.0 / X^[K]; Y1^[P] := 1.0 / Y^[K]; W1^[P] := Sqr(Sqr(Y^[K])); if Method = 1 then W1^[P] := W1^[P] * W^[K]; end; ErrCode := WLinFit(X1, Y1, W1, P, A, V); if ErrCode = MAT_OK then begin B^[0] := 1.0 / A^[0]; B^[1] := A^[1] / A^[0]; end; FitModel := ErrCode; DelVector(X1, N); DelVector(Y1, N); DelVector(W1, N); DelVector(A, 1); DelMatrix(V, 1, 1); end; end. �������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/pastring.pas���������������������������������������������0000755�0001750�0001750�00000020101�11326443506�020424� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit PASTRING.PAS * * Version 1.8 * * (c) J. Debord, December 2000 * ********************************************************************** Turbo Pascal string routines ********************************************************************** } unit PaString; interface uses FMath, FComp, Matrices; { *** Global variables controlling the appearance of a numeric string ** } const NumLength : Integer = 10; { Length of a numeric field } MaxDec : Integer = 4; { Max. number of decimal places } FloatPoint : Boolean = False; { Floating point notation } NSZero : Boolean = True; { Write non significant zero's } { ************************** String routines *************************** } function LTrim(S : String) : String; { ---------------------------------------------------------------------- Removes leading blanks ---------------------------------------------------------------------- } function RTrim(S : String) : String; { ---------------------------------------------------------------------- Removes trailing blanks ---------------------------------------------------------------------- } function Trim(S : String) : String; { ---------------------------------------------------------------------- Removes leading and trailing blanks ---------------------------------------------------------------------- } function StrChar(N : Byte; C : Char) : String; { ---------------------------------------------------------------------- Returns a string made of character C repeated N times ---------------------------------------------------------------------- } function RFill(S : String; L : Byte) : String; { ---------------------------------------------------------------------- Completes string S with trailing blanks for a total length L ---------------------------------------------------------------------- } function LFill(S : String; L : Byte) : String; { ---------------------------------------------------------------------- Completes string S with leading blanks for a total length L ---------------------------------------------------------------------- } function CFill(S : String; L : Byte) : String; { ---------------------------------------------------------------------- Completes string S with leading blanks to center the string on a total length L ---------------------------------------------------------------------- } function Replace(S : String; C1, C2 : Char) : String; { ---------------------------------------------------------------------- Replaces in string S all the occurences of character C1 by character C2 ---------------------------------------------------------------------- } function Extract(S : String; var Index : Byte; Delim : Char) : String; { ---------------------------------------------------------------------- Extracts a field from a string. Index is the position of the first character of the field. Delim is the character used to separate fields (e.g. blank, comma or tabulation). Blanks immediately following Delim are ignored. Index is updated to the position of the next field. ---------------------------------------------------------------------- } procedure Parse(S : String; Delim : Char; Field : PStrVector; var N : Byte); { ---------------------------------------------------------------------- Parses a string into its constitutive fields. Delim is the field separator. The number of fields is returned in N. The fields are returned in Field^[0]..Field^[N - 1]. Field must be dimensioned in the calling program. ---------------------------------------------------------------------- } function FloatToStr(X : Float) : String; { ---------------------------------------------------------------------- Converts a real to a string according to the values of the global variables NumLength, MaxDec, FloatPoint and NSZero ---------------------------------------------------------------------- } function IntToStr(N : LongInt) : String; { ---------------------------------------------------------------------- Converts an integer to a string according to the values of the global variables NumLength and MaxDec. ---------------------------------------------------------------------- } function CompToStr(Z : Complex) : String; { ---------------------------------------------------------------------- Converts a complex number to a string. ---------------------------------------------------------------------- } implementation function LTrim(S : String) : String; begin if S <> '' then repeat if S[1] = ' ' then Delete(S, 1, 1); until S[1] <> ' '; LTrim := S; end; function RTrim(S : String) : String; var L1 : Byte; begin if S <> '' then repeat L1 := Length(S); if S[L1] = ' ' then Delete(S, L1, 1); until S[L1] <> ' '; RTrim := S; end; function Trim(S : String) : String; begin Trim := LTrim(RTrim(S)); end; function StrChar(N : Byte; C : Char) : String; var I : Byte; S : String; begin S := ''; for I := 1 to N do S := S + C; StrChar := S; end; function RFill(S : String; L : Byte) : String; var L1 : Byte; begin L1 := Length(S); if L1 >= L then RFill := S else RFill := S + StrChar(L - L1, ' '); end; function LFill(S : String; L : Byte) : String; var L1 : Byte; begin L1 := Length(S); if L1 >= L then LFill := S else LFill := StrChar(L - L1, ' ') + S; end; function CFill(S : String; L : Byte) : String; var L1 : Byte; begin L1 := Length(S); if L1 >= L then CFill := S else CFill := StrChar((L - L1) div 2, ' ') + S; end; function Replace(S : String; C1, C2 : Char) : String; var S1 : String; K : Byte; begin S1 := S; K := Pos(C1, S1); while K > 0 do begin S1[K] := C2; K := Pos(C1, S1); end; Replace := S1; end; function Extract(S : String; var Index : Byte; Delim : Char) : String; var I, L : Byte; begin I := Index; L := Length(S); { Search for Delim } while (I <= L) and (S[I] <> Delim) do Inc(I); { Extract field } if I = Index then Extract := '' else Extract := Copy(S, Index, I - Index); { Skip blanks after Delim } repeat Inc(I); until (I > L) or (S[I] <> ' '); { Update Index } Index := I; end; procedure Parse(S : String; Delim : Char; Field : PStrVector; var N : Byte); var I, Index, L : Byte; begin I := 0; Index := 1; L := Length(S); repeat Field^[I] := Extract(S, Index, Delim); Inc(I); until Index > L; N := I; end; function FloatToStr(X : Float) : String; var S : String; C : Char; L : Byte; begin if FloatPoint then begin Str(X:Pred(NumLength), S); S := ' ' + S; end else begin Str(X:NumLength:MaxDec, S); if not NSZero then repeat L := Length(S); C := S[L]; if (C = '0') or (C = '.') then Delete(S, L, 1); until C <> '0'; end; FloatToStr := S; end; function IntToStr(N : LongInt) : String; var S : String; begin Str(N:(NumLength - MaxDec - 1), S); IntToStr := S; end; function CompToStr(Z : Complex) : String; var S : String; begin if Z.Form = Rec then begin if Z.Y >= 0.0 then S := ' + ' else S := ' - '; CompToStr := FloatToStr(Z.X) + S + FloatToStr(Abs(Z.Y)) + ' * i'; end else CompToStr := FloatToStr(Z.R) + ' * Exp(' + FloatToStr(Z.Theta) + ' * i)'; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/fithill.pas����������������������������������������������0000755�0001750�0001750�00000013525�11326443506�020244� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITHILL.PAS * * Version 1.1 * * (c) J. Debord, August 2000 * ********************************************************************** This unit fits the Hill equation : Ymax . x^n y = ---------- K^n + x^n ********************************************************************** } unit FitHill; {$F+} interface uses FMath, Matrices, Stat, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X, Y : Float; B, D : PVector); function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; implementation function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } begin FuncName := 'y = Ymax . x^n / (K^n + x^n)'; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 2; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'Ymax'; 1 : ParamName := 'K '; 2 : ParamName := 'n '; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = Ymax B^[1] = K B^[2] = n -------------------------------------------------------------------- } begin if X = 0.0 then if B^[2] > 0.0 then RegFunc := 0.0 else RegFunc := B^[0] else { Compute function according to y = Ymax / [1 + (K/x)^n] } RegFunc := B^[0] / (1.0 + Power(B^[1] / X, B^[2])); end; procedure DerivProc(X, Y : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point (X,Y) with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter -------------------------------------------------------------------- } var Q, R, S : Float; begin if X = 0.0 then begin if B^[2] > 0.0 then D^[0] := 0.0 else D^[0] := 1.0; D^[1] := 0.0; D^[2] := 0.0; end else begin Q := Power(B^[1] / X, B^[2]); { (K/x)^n } R := 1.0 / (1.0 + Q); { 1 / [1 + (K/x)^n] } S := - Y * R * Q; { -Ymax.(K/x)^n / [1 + (K/x)^n]^2 } { dy/dYmax = 1 / [1 + (K/x)^n] } D^[0] := R; { dy/dK = -Ymax.(K/x)^n.(n/K)/[1 + (K/x)^n]^2 } D^[1] := S * B^[2] / B^[1]; { dy/dn = -Ymax.(K/x)^n.Ln(K/x)/[1 + (K/x)^n]^2 } D^[2] := S * Log(B^[1] / X); end; end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of the Hill equation by linear regression: Ln(Ymax/y - 1) = n.Ln(K) - n.Ln(x) -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- } var Ymax : Float; { Estimated value of Ymax } X1, Y1 : PVector; { Transformed coordinates } W1 : PVector; { Weights } A : PVector; { Linear regression parameters } V : PMatrix; { Variance-covariance matrix } P : Integer; { Number of points for linear regression } K : Integer; { Loop variable } ErrCode : Integer; { Error code } begin DimVector(X1, N); DimVector(Y1, N); DimVector(W1, N); DimVector(A, 1); DimMatrix(V, 1, 1); P := 0; Ymax := Max(Y, 1, N); for K := 1 to N do if (X^[K] > 0.0) and (Y^[K] > 0.0) and (Y^[K] < Ymax) then begin Inc(P); X1^[P] := Log(X^[K]); Y1^[P] := Log(Ymax / Y^[K] - 1.0); W1^[P] := Sqr(Y^[K] * (1.0 - Y^[K] / Ymax)); if Method = 1 then W1^[P] := W1^[P] * W^[K]; end; ErrCode := WLinFit(X1, Y1, W1, P, A, V); if ErrCode = MAT_OK then begin B^[0] := Ymax; B^[1] := Expo(- A^[0] / A^[1]); B^[2] := - A^[1]; end; FitModel := ErrCode; DelVector(X1, N); DelVector(Y1, N); DelVector(W1, N); DelVector(A, 1); DelMatrix(V, 1, 1); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/stat.pas�������������������������������������������������0000755�0001750�0001750�00000025573�11326443506�017572� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit STAT.PAS * * Version 1.5 * * (c) J. Debord, June 2001 * ********************************************************************** Statistical routines ********************************************************************** } unit Stat; interface uses FMath, Matrices; { ---------------------------------------------------------------------- Common input parameters : X : Vector of statistical variable Lbound, Ubound : Indices of first and last elements of X W : Vector of weights ---------------------------------------------------------------------- } procedure QSort(X : PVector; Lbound, Ubound : Integer); { ---------------------------------------------------------------------- Sorts the elements of vector X in increasing order (quick sort) ---------------------------------------------------------------------- } procedure DQSort(X : PVector; Lbound, Ubound : Integer); { ---------------------------------------------------------------------- Sorts the elements of vector X in decreasing order (quick sort) ---------------------------------------------------------------------- } function Median(X : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Sorts vector X is ascending order and returns its median value ---------------------------------------------------------------------- } function Sum(X : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the sum of the elements of vector X ---------------------------------------------------------------------- } function SumSqr(X : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the sum of squared elements of vector X ---------------------------------------------------------------------- } function SumSqrDif(X : PVector; Lbound, Ubound : Integer; A : Float) : Float; { ---------------------------------------------------------------------- Returns the sum of squared differences between the elements of vector X and the constant A ---------------------------------------------------------------------- } function SumSqrDifVect(X, Y : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the sum of squared differences between two vectors ---------------------------------------------------------------------- } function SumWSqr(X, W : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the sum of weighted squared elements of vector X ---------------------------------------------------------------------- } function SumWSqrDif(X, W : PVector; Lbound, Ubound : Integer; A : Float) : Float; { ---------------------------------------------------------------------- Returns the sum of weighted squared differences between the elements of vector X and the constant A ---------------------------------------------------------------------- } function SumWSqrDifVect(X, Y, W : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the sum of weighted squared differences between two vectors ---------------------------------------------------------------------- } function Average(X : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the average value of vector X ---------------------------------------------------------------------- } function Variance(X : PVector; Lbound, Ubound : Integer; Avg : Float) : Float; { ---------------------------------------------------------------------- Returns the variance of vector X, with average Avg ---------------------------------------------------------------------- } function EstVar(X : PVector; Lbound, Ubound : Integer; Avg : Float) : Float; { ---------------------------------------------------------------------- Returns the estimated variance of the population to which vector X belongs ---------------------------------------------------------------------- } function Skewness(X : PVector; Lbound, Ubound : Integer; Avg, Sigma : Float) : Float; { ---------------------------------------------------------------------- Returns the skewness of vector X, with average Avg and standard deviation Sigma ---------------------------------------------------------------------- } function Kurtosis(X : PVector; Lbound, Ubound : Integer; Avg, Sigma : Float) : Float; { ---------------------------------------------------------------------- Returns the kurtosis of vector X, with average Avg and standard deviation Sigma ---------------------------------------------------------------------- } procedure RanMult(M : PVector; L : PMatrix; N : Integer; X : PVector); { ---------------------------------------------------------------------- Samples a vector X from the N-dimensioned multinormal distribution with mean vector M. L is the Cholesky factor of the variance-covariance matrix. ---------------------------------------------------------------------- } implementation procedure QSort(X : PVector; Lbound, Ubound : Integer); { Quick sort in ascending order - Adapted from Borland's BP7 demo } procedure Sort(L, R : Integer); var I, J : Integer; U, V : Float; begin I := L; J := R; U := X^[(L + R) div 2]; repeat while X^[I] < U do I := I + 1; while U < X^[J] do J := J - 1; if I <= J then begin V := X^[I]; X^[I] := X^[J]; X^[J] := V; I := I + 1; J := J - 1; end; until I > J; if L < J then Sort(L, J); if I < R then Sort(I, R); end; begin Sort(Lbound, Ubound); end; procedure DQSort(X : PVector; Lbound, Ubound : Integer); { Quick sort in descending order - Adapted from Borland's BP7 demo } procedure Sort(L, R : Integer); var I, J : Integer; U, V : Float; begin I := L; J := R; U := X^[(L + R) div 2]; repeat while X^[I] > U do I := I + 1; while U > X^[J] do J := J - 1; if I <= J then begin V := X^[I]; X^[I] := X^[J]; X^[J] := V; I := I + 1; J := J - 1; end; until I > J; if L < J then Sort(L, J); if I < R then Sort(I, R); end; begin Sort(Lbound, Ubound); end; function Median(X : PVector; Lbound, Ubound : Integer) : Float; var N, N2 : Integer; begin N := Ubound - Lbound + 1; N2 := N div 2 + Lbound - 1; QSort(X, Lbound, Ubound); if Odd(N) then Median := X^[N2 + 1] else Median := 0.5 * (X^[N2] + X^[N2 + 1]); end; function Sum(X : PVector; Lbound, Ubound : Integer) : Float; var S : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do S := S + X^[I]; Sum := S; end; function SumSqr(X : PVector; Lbound, Ubound : Integer) : Float; var S : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do S := S + Sqr(X^[I]); SumSqr := S; end; function SumSqrDif(X : PVector; Lbound, Ubound : Integer; A : Float) : Float; var S : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do S := S + Sqr(X^[I] - A); SumSqrDif := S; end; function SumSqrDifVect(X, Y : PVector; Lbound, Ubound : Integer) : Float; var S : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do S := S + Sqr(X^[I] - Y^[I]); SumSqrDifVect := S; end; function SumWSqr(X, W : PVector; Lbound, Ubound : Integer) : Float; var S : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do S := S + W^[I] * Sqr(X^[I]); SumWSqr := S; end; function SumWSqrDif(X, W : PVector; Lbound, Ubound : Integer; A : Float) : Float; var S : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do S := S + W^[I] * Sqr(X^[I] - A); SumWSqrDif := S; end; function SumWSqrDifVect(X, Y, W : PVector; Lbound, Ubound : Integer) : Float; var S : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do S := S + W^[I] * Sqr(X^[I] - Y^[I]); SumWSqrDifVect := S; end; function Average(X : PVector; Lbound, Ubound : Integer) : Float; begin Average := Sum(X, Lbound, Ubound) / (Ubound - Lbound + 1); end; function Variance(X : PVector; Lbound, Ubound : Integer; Avg : Float) : Float; begin Variance := SumSqrDif(X, Lbound, Ubound, Avg) / (Ubound - Lbound + 1); end; function EstVar(X : PVector; Lbound, Ubound : Integer; Avg : Float) : Float; begin EstVar := SumSqrDif(X, Lbound, Ubound, Avg) / (Ubound - Lbound); end; function Skewness(X : PVector; Lbound, Ubound : Integer; Avg, Sigma : Float) : Float; var S, T : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do begin T := (X^[I] - Avg) / Sigma; S := S + T * Sqr(T); end; Skewness := S / (Ubound - Lbound + 1); end; function Kurtosis(X : PVector; Lbound, Ubound : Integer; Avg, Sigma : Float) : Float; var S, T : Float; I : Integer; begin S := 0.0; for I := Lbound to Ubound do begin T := (X^[I] - Avg) / Sigma; S := S + Sqr(Sqr(T)); end; Kurtosis := S / (Ubound - Lbound + 1) - 3.0; end; procedure RanMult(M : PVector; L : PMatrix; N : Integer; X : PVector); var U : PVector; I, J : Integer; begin { Form a vector of N independent standard normal variates } DimVector(U, N); for I := 1 to N do U^[I] := RanGaussStd; { Form X = M + L*U, which follows the multinormal distribution } for I := 1 to N do begin X^[I] := M^[I]; for J := 1 to I do X^[I] := X^[I] + L^[I]^[J] * U^[J]; end; DelVector(U, N); end; end. �������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/fitlin.pas�����������������������������������������������0000755�0001750�0001750�00000006435�11326443506�020100� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITLIN.PAS * * Version 1.0 * * (c) J. Debord, April 1998 * ********************************************************************** This unit fits a linear function : y = a + b.x ********************************************************************** } unit FitLin; {$F+} interface uses FMath, Matrices, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; implementation function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } begin FuncName := 'y = a + b.x'; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 1; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'a'; 1 : ParamName := 'b'; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = a B^[1] = b -------------------------------------------------------------------- } begin RegFunc := B^[0] + B^[1] * X; end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; { -------------------------------------------------------------------- Fit the straight line -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters V = variance-covariance matrix of the parameters -------------------------------------------------------------------- } begin case Method of 0 : FitModel := LinFit(X, Y, N, B, V); 1 : FitModel := WLinFit(X, Y, W, N, B, V); end; end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/plotvar.inc����������������������������������������������0000755�0001750�0001750�00000006737�07316774504�020306� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * PLOTVAR.INC * ********************************************************************** Constants, types and global variables common to PLOT.PAS and TEXPLOT.PAS ********************************************************************** } const MAXSYMBOL = 9; { Max. number of graphic symbols } EPS = 1.0E-10; { Lower limit for an axis label } type TScale = (LIN_SCALE, { Scale } LOG_SCALE); TGrid = (NO_GRID, { Grid } HORIZ_GRID, VERTIC_GRID, BOTH_GRID); TAxis = record { Coordinate axis } Scale : TScale; Min : Float; Max : Float; Step : Float; end; TTitle = record { Title for main graph or axis } Text : String[70]; Font : Integer; CharWidth : Integer; CharHeight : Integer; end; TLegend = record { Legends of plotted curves } Text : array[1..MAXSYMBOL] of String[40]; Font : Integer; CharWidth : Integer; CharHeight : Integer; SymbolSize : Integer; end; { ******** Global variables defining the appearance of the graph ******* } const Xwin1 : Integer = 15; { Window limits in % } Ywin1 : Integer = 15; Xwin2 : Integer = 85; Ywin2 : Integer = 85; GraphBorder : Boolean = True; { Plot graph border } XAxis : TAxis = (Scale : LIN_SCALE; { Horizontal axis } Min : 0.0; Max : 1.0; Step : 0.2); YAxis : TAxis = (Scale : LIN_SCALE; { Vertical axis } Min : 0.0; Max : 1.0; Step : 0.2); Grid : TGrid = NO_GRID; { Grid } GraphTitle : TTitle = (Text : ''; { Title of graph } Font : 2; CharWidth : 300; CharHeight : 350); XTitle : TTitle = (Text : 'X'; { Title of X axis } Font : 2; CharWidth : 200; CharHeight : 250); YTitle : TTitle = (Text : 'Y'; { Title of Y axis } Font : 2; CharWidth : 200; CharHeight : 250); Legend : TLegend = (Text : ('A', { Legends of curves } 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'); Font : 2; CharWidth : 50; CharHeight : 50; SymbolSize : 3); ���������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/regmultdelphi.pas����������������������������������������0000755�0001750�0001750�00000050220�11326443506�021447� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Program REGMULT.PAS * * Version 1.1 * * (c) J. Debord, August 2000 * ********************************************************************** This program performs a weighted multiple linear least squares fit : y = b0 + b1 * x1 + b2 * x2 + ... The following parameters are passed on the command line : 1st parameter = name of input file (default extension = .DAT) 2nd parameter = 1 if the equation includes a constant term b0 Input files are ASCII files with the following structure : Line 1 : Title of study Line 2 : Number of variables (must be >= 2 here !) Next lines : Names of variables x1, x2, ..., y Next line : Number of observations (must be > number of variables !) The next lines contain the coordinates (x1, x2, ..., y) of the observations (1 observation by line). The coordinates must be separated by spaces or tabulations. The file INHIB.DAT is an example of data relating the inhibition of an enzyme to the physico-chemical properties of the inhibitors (J. DEBORD, P. N'DIAYE, J. C. BOLLINGER et al, J. Enzyme Inhib., 1997, 12, 13-26). The program parameters are : INHIB 1 The program may be executed from Turbo Pascal's integrated environment, in which case the parameters are entered through the "Parameters" option of the menu, or from DOS (after compilation into an executable file), in which case the parameters are entered on the command line (e.g. REGMULT INHIB 1). ********************************************************************** } unit RegMultDelphi; interface uses SysUtils,FMath, Matrices, Regress, Models, PaString,messages,dialogs,classes,define_types; const kMaxRA = 127; kCR = chr (13); kMaxObs = 100; kMaxFact = 64; //type // TIVra = array [1..kMaxFact,1..kMaxObs] of integer; {SpaceType = record mrix,mriy,mriz,fobx,foby,fobz: integer; end;} function MultipleRegression (lnObservations,lnFactors: integer; var X: PMatrix; var lImgIntensity: DoubleP0; var lOutT: DoubleP0): boolean; function MultipleRegressionVec (lnObservations,lnFactors: integer; var X: PMatrix; var Y: PVector; var lOutT,lOutSlope: DoubleP0): boolean; //var // gMRIFOBra: array [1..kMaxRA] of SpaceType; // gCoregRA: array[1..3,0..3] of double; {MRIx,y,z, Offset,FOBx,FOBy,FOBz} implementation (*var InFName : String; { Name of input file } Title : String; { Title of study } XName : PStrVector; { Names of independent variables } YName : String; { Name of dependent variable } N : Integer; { Number of observations } X : PMatrix; { Matrix of independent variables } Y : PVector; { Vector of dependent variable } Z : PVector; { Vector of independent variable (not used here) } Ycalc : PVector; { Expected Y values } S : PVector; { Standard deviations of Y values } CstPar : PVector; { Constant parameters } B : PVector; { Regression parameters } B_min, B_max : PVector; { Parameter bounds (not used, but must be declared in order to use the WLSFit routine ) } V : PMatrix; { Variance-covariance matrix of regression parameters } Theta : PVector; { Variance parameters } RegTest : TRegTest; { Regression tests } gErrCode : Integer; { Error code } *) (* procedure ReadCmdLine(var InFName : String; var CstPar : PVector); { ---------------------------------------------------------------------- Reads command line parameters. Stores constant parameters in CstPar, such that : CstPar^[0] = Number of independent variables (this one is set by ReadInputFile) CstPar^[1] = 1 to include a constant term (b0) The contents of CstPar are defined in the unit FITMULT.PAS, in the subdirectory REG of the TP Math units directory. ---------------------------------------------------------------------- } var I : Integer; begin DimVector(CstPar, 1); { Name of input file } InFName := ParamStr(1); if Pos('.', InFName) = 0 then InFName := InFName + '.dat'; { Presence of constant term } //I := 0; Val(ParamStr(2), I, gErrCode); CstPar^[1] := I; end; function ReadInputFile(InFName : String; var Title : String; var XName : PStrVector; var YName : String; var N : Integer; var X : PMatrix; var Y : PVector; CstPar : PVector) : Integer; var InF : Textfile; { Input file } Nvar : Integer; { Nb of independent variables } I, K : Integer; { Loop variables } begin Assign(InF, InFName); Reset(InF); ReadLn(InF, Title); ReadLn(InF, Nvar); { Total number of variables } if Nvar < 2 then begin showmessage('Data file must contain at least 2 variables !'); ReadInputFile := - 1; Exit; end; Nvar := Pred(Nvar); showmessage('trap3x'+inttostr(NVar)); DimStrVector(XName, Nvar);{crashes here} showmessage('trap4x'+inttostr(NVar)); for I := 1 to Nvar do begin ReadLn(InF, XName^[I]); showmessage(XName^[I]); end; ReadLn(InF, YName); ReadLn(InF, N); DimMatrix(X, Nvar, N); DimVector(Y, N); for K := 1 to N do begin for I := 1 to Nvar do Read(InF, X^[I]^[K]); Read(InF, Y^[K]); end; Close(InF); CstPar^[0] := Nvar; ReadInputFile := 0; end; procedure WriteOutputFile(InFName, Title : String; XName : PStrVector; YName : String; N : Integer; Y, CstPar, Ycalc, S, B : PVector; V : PMatrix; Test : TRegTest); var OutFName : String; { Name of output file } OutF : TextFile; { Output file } Line1, Line2 : String; { Separating lines } Nvar : Integer; { Nb of independent variables } Delta : Float; { Residual } Sr : Float; { Residual error } SB : PVector; { Standard deviations of parameters } T : PVector; { Student's t } Prob : PVector; { Probabilities } I, K : Integer; { Loop variables } begin Nvar := Round(CstPar^[0]); DimVector(SB, LastParam); DimVector(T, LastParam); DimVector(Prob, LastParam); K := Pos('.', InFName); OutFName := Copy(InFName, 1, Pred(K)) + '.out'; Assign(OutF, OutFName); Rewrite(OutF); Line1 := StrChar(73, '-'); Line2 := StrChar(73, '='); WriteLn(OutF, Line2); WriteLn(OutF, 'Data file : ', InFName); WriteLn(OutF, 'Study name : ', Title); for I := 1 to Nvar do WriteLn(OutF, 'x', I:1, ' : ', XName^[I]); WriteLn(OutF, 'y : ', YName); WriteLn(OutF, 'Function : ', FuncName); { Perform tests on parameters } ParamTest(B, V, N, FirstParam, LastParam, SB, T, Prob); WriteLn(OutF, Line1); WriteLn(OutF, 'Parameter Est.value Std.dev. t Student Prob(>|t|)'); WriteLn(OutF, Line1); showmessage(inttostr(nVar)+':'+inttostr(FirstParam)+':'+inttostr(LastParam)); for I := FirstParam to LastParam do if SB^[I] > 0.0 then WriteLn(OutF, ParamName(I):5, B^[I]:17:8, SB^[I]:17:8, T^[I]:17:2, Prob^[I]:17:4) else WriteLn(OutF, ParamName(I):5, B^[I]:17:8); WriteLn(OutF, Line1); WriteLn(OutF, 'Number of observations : n = ', N:5); with Test do begin Sr := Sqrt(Vr); WriteLn(OutF, 'Residual error : s = ', Sr:10:8); if (R2 >= 0.0) and (R2 <= 1.0) then WriteLn(OutF, 'Coefficient of determination : r2 = ', R2:10:8); if (R2a >= 0.0) and (R2a <= 1.0) then WriteLn(OutF, 'Adjusted coeff. of determination : r2a = ', R2a:10:8); Write(OutF, 'Variance ratio (explained/resid.) : F = ', F:10:4); WriteLn(OutF, ' Prob(>F) = ', Prob:6:4); end; WriteLn(OutF, Line1); WriteLn(OutF, ' i Y obs. Y calc. Residual Std.dev. Std.res.'); WriteLn(OutF, Line1); for K := 1 to N do begin Delta := Y^[K] - Ycalc^[K]; WriteLn(OutF, K:3, Y^[K]:14:4, Ycalc^[K]:14:4, Delta:14:4, S^[K]:14:4, (Delta / S^[K]):14:4); end; WriteLn(OutF, Line2); Close(OutF); Showmessage('Results written to file '+OutFName); DelVector(SB, LastParam); DelVector(T, LastParam); DelVector(Prob, LastParam); end; { *************************** Main program ***************************** } procedure RunReg; begin { Read command line parameters } //ReadCmdLine(InFName, CstPar); InFName := 'C:\inhib.dat'; DimVector(CstPar, 1); CstPar^[1] := 1; { Read input file } if ReadInputFile(InFName, Title, XName, YName, N, X, Y, CstPar) <> 0 then begin showmessage('Error reading file '+ InFName); exit; end; { Initialize regression and variance models. See MODELS.PAS in the REG subdirectory for a list of available models } InitModel(REG_MULT, VAR_CONST, { Here we use a constant variance } CstPar); { Set the regression algorithm which must be GAUSS_JORDAN or SVD. The default algorithm is SVD. Comment off the following line if you wish to change the algorithm. } { SetRegAlgo(GAUSS_JORDAN); } { Dimension arrays. Note: the variance parameters Theta^[1]..Theta^[LastVarParam] must be supplied if we use a non-constant variance model } DimVector(Theta, LastVarParam); DimVector(B, LastParam); DimMatrix(V, LastParam, LastParam); DimVector(Ycalc, N); DimVector(S, N); { Perform regression. The numbers 1 and 0.1 denote the maximal number of iterations and the tolerance on the parameters. They are purely formal values here since the multiple linear regression does not use an iterative minimization algorithm. } gErrCode := WLSFit(Z, X, Y, N, True, 1, 0.1, Theta, B, B_min, B_max, V, Ycalc, S, RegTest); { Write results } case gErrCode of MAT_OK : WriteOutputFile(InFName, Title, XName, YName, N, Y, CstPar, Ycalc, S, B, V, RegTest); MAT_SINGUL : WriteLn('Singular matrix !'); MAT_NON_CONV : WriteLn('Non-convergence of SVD algorithm !'); end; end; *) //ComputeRegress(lnObservations,lnFactors, Y, CstPar, Ycalc, S, B, V, lRegTest); procedure ComputeRegress (N,lnFactors : Integer; var Y, CstPar, Ycalc, S, B : PVector; var V : PMatrix; var Test : TRegTest; var lOutT: DoubleP0); var I: integer; SB : PVector; { Standard deviations of parameters } T : PVector; { Student's t } Prob : PVector; { Probabilities } begin DimVector(SB, LastParam); DimVector(T, LastParam); DimVector(Prob, LastParam); { Perform tests on parameters } ParamTest(B, V, N, FirstParam, LastParam, SB, T, Prob); for I := 0 to (lnFactors-1) do lOutT[I] := T^[FirstParam+I+1];//first parameter is global fit lOutT[lnFactors] := T^[FirstParam];//global fit //for I := FirstParam to LastParam do // Showmessage(floattostr(T^[I]) ); DelVector(SB, LastParam); DelVector(T, LastParam); DelVector(Prob, LastParam); end; (* procedure ScreenOutputFile( var YName : String; N,ldimension : Integer; var Y, CstPar, Ycalc, S, B : PVector; var V : PMatrix; var Test : TRegTest; var lDynStr: String); var lA,lB,lC,lD : String; { Name of output file } Nvar : Integer; { Nb of independent variables } Delta : Float; { Residual } Sr : Float; { Residual error } SB : PVector; { Standard deviations of parameters } T : PVector; { Student's t } Prob : PVector; { Probabilities } I, K : Integer; { Loop variables } begin Nvar := Round(CstPar^[0]); DimVector(SB, LastParam); DimVector(T, LastParam); DimVector(Prob, LastParam); { Perform tests on parameters } ParamTest(B, V, N, FirstParam, LastParam, SB, T, Prob); lDynStr:=lDynStr+'|'+( 'Parameter Est.value Std.dev. t Student Prob(>|t|)'); //showmessage(inttostr(nVar)+':'+inttostr(FirstParam)+':'+inttostr(LastParam)); for I := FirstParam to LastParam do begin if SB^[I] > 0.0 then begin Str(B^[I]:17:8,lA); Str(SB^[I]:17:8,lB); Str(T^[I]:17:2,lC); Str(Prob^[I]:17:4,lD); lDynStr:=lDynStr+'|'+(ParamName(I)+lA+lB+'T='+lC+lD); end else begin B^[I]:= 0; Str(B^[I]:17:8,lA); lDynStr:=lDynStr+'|'+(ParamName(I)+lA); end; //gCoregRA[lDImension,I]:= B^[I]; end; DelVector(SB, LastParam); DelVector(T, LastParam); DelVector(Prob, LastParam); end; *) //function PredictData(lnObservations: integer; var lStr: tstringlist): boolean; function MultipleRegression (lnObservations,lnFactors: integer; var X: PMatrix; var lImgIntensity: DoubleP0; var lOutT: DoubleP0): boolean; var K : Integer; { Nb of independent variables } //X : PMatrix; { Matrix of independent variables } Y : PVector; { Vector of dependent variable } Z : PVector; { Vector of independent variable (not used here) } Ycalc : PVector; { Expected Y values } S : PVector; { Standard deviations of Y values } CstPar : PVector; { Constant parameters } B : PVector; { Regression parameters } B_min, B_max : PVector; { Parameter bounds (not used, but must be declared in order to use the WLSFit routine ) } V : PMatrix; { Variance-covariance matrix of regression parameters } Theta : PVector; { Variance parameters } lRegTest : TRegTest; { Regression tests } gErrCode : Integer; { Error code } begin result := false; if lnObservations < 5 then begin showmessage('At least 5 samples required for 3D registration.'); exit; end; DimVector(CstPar, 1); DimVector(Y, lnObservations); CstPar^[1] := 1; CstPar^[0] := lnFactors; for K := 1 to lnObservations do Y^[K] := lImgIntensity[K-1]; { Initialize regression and variance models.} InitModel(REG_MULT,VAR_CONST,{ Here we use a constant variance }CstPar); { Set the regression algorithm which must be GAUSS_JORDAN or SVD. The default algorithm is SVD. Comment off the following line if you wish to change the algorithm. } { SetRegAlgo(GAUSS_JORDAN); } DimVector(Theta, LastVarParam); DimVector(B, LastParam); DimMatrix(V, LastParam, LastParam); DimVector(Ycalc, lnObservations); DimVector(S, lnObservations); { Perform regression. The numbers 1 and 0.1 denote the maximal number of iterations and the tolerance on the parameters. They are purely formal values here since the multiple linear regression does not use an iterative minimization algorithm. } gErrCode := WLSFit(Z, X, Y, lnObservations, True, 1, 0.1, Theta, B,B_min, B_max, V, Ycalc, S, lRegTest); { Write results } //showmessage(inttostr(xx)); case gErrCode of MAT_OK : begin //ScreenOutputFile({XName,}YName,lnObservations,lDim, Y, CstPar, Ycalc, S, B, V, lRegTest,lStr); //Showmessage(lStr); ComputeRegress(lnObservations,lnFactors, Y, CstPar, Ycalc, S, B, V, lRegTest,lOutT); end; { MAT_OK : WriteOutputFile(InFName, Title, XName, YName, N, Y, CstPar, Ycalc, S, B, V, RegTest); } MAT_SINGUL : Showmessage('Singular matrix !'); MAT_NON_CONV : Showmessage('Non-convergence of SVD algorithm !'); end; DelVector(CstPar, 1); DelVector(Y, lnObservations); //DelStrVector(XName,lnXFactors); DelVector(Theta, LastVarParam); DelVector(B, LastParam); DelMatrix(V, LastParam, LastParam); DelVector(Ycalc, lnObservations); DelVector(S, lnObservations); result := true; end; function MultipleRegressionVec (lnObservations,lnFactors: integer; var X: PMatrix; var Y: PVector; var lOutT,lOutSlope: DoubleP0): boolean; var K : Integer; { Nb of independent variables } Z : PVector; { Vector of independent variable (not used here) } Ycalc : PVector; { Expected Y values } S : PVector; { Standard deviations of Y values } CstPar : PVector; { Constant parameters } B : PVector; { Regression parameters } B_min, B_max : PVector; { Parameter bounds (not used, but must be declared in order to use the WLSFit routine ) } V : PMatrix; { Variance-covariance matrix of regression parameters } Theta : PVector; { Variance parameters } lRegTest : TRegTest; { Regression tests } gErrCode : Integer; { Error code } begin result := false; if lnObservations < 5 then begin showmessage('At least 5 samples required for 3D registration.'); exit; end; DimVector(CstPar, 1); CstPar^[1] := 1; CstPar^[0] := lnFactors; { Initialize regression and variance models.} InitModel(REG_MULT,VAR_CONST,{ Here we use a constant variance }CstPar); { Set the regression algorithm which must be GAUSS_JORDAN or SVD. The default algorithm is SVD. Comment off the following line if you wish to change the algorithm. } { SetRegAlgo(GAUSS_JORDAN); } DimVector(Theta, LastVarParam); DimVector(B, LastParam); DimMatrix(V, LastParam, LastParam); DimVector(Ycalc, lnObservations); DimVector(S, lnObservations); { Perform regression. The numbers 1 and 0.1 denote the maximal number of iterations and the tolerance on the parameters. They are purely formal values here since the multiple linear regression does not use an iterative minimization algorithm. } gErrCode := WLSFit(Z, X, Y, lnObservations, True, 1, 0.1, Theta, B,B_min, B_max, V, Ycalc, S, lRegTest); { Write results } //showmessage(inttostr(xx)); case gErrCode of MAT_OK : begin //ScreenOutputFile({XName,}YName,lnObservations,lDim, Y, CstPar, Ycalc, S, B, V, lRegTest,lStr); //Showmessage(lStr); ComputeRegress(lnObservations,lnFactors, Y, CstPar, Ycalc, S, B, V, lRegTest,lOutT); end; { MAT_OK : WriteOutputFile(InFName, Title, XName, YName, N, Y, CstPar, Ycalc, S, B, V, RegTest); } MAT_SINGUL : Showmessage('Singular matrix !'); MAT_NON_CONV : Showmessage('Non-convergence of SVD algorithm !'); end; for K := 0 to (lnFactors-1) do lOutSlope^[K] := B^[FirstParam+K+1];//first parameter is global fit lOutSlope^[lnFactors] := B^[FirstParam];//global fit DelVector(CstPar, 1); //DelVector(Y, lnObservations); //DelStrVector(XName,lnXFactors); DelVector(Theta, LastVarParam); DelVector(B, LastParam); DelMatrix(V, LastParam, LastParam); DelVector(Ycalc, lnObservations); DelVector(S, lnObservations); result := true; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/fcomp.pas������������������������������������������������0000755�0001750�0001750�00000043407�11326443506�017717� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FCOMP.PAS * * Version 1.1 * * (c) J. Debord, July 2000 * ********************************************************************** Complex functions for TPMATH (Based on CMPLX.ZIP by E.F. Glynn) ********************************************************************** } unit FComp; interface uses FMath; { ********************************************************************** Complex type ********************************************************************** } type ComplexForm = (Rec, Pol); { Rectangular or Polar form } Complex = record case Form : ComplexForm of Rec : (X, Y : Float); Pol : (R, Theta : Float); end; const C_infinity : Complex = (Form : Rec; X : MAXNUM; Y : 0.0); C_zero : Complex = (Form : Rec; X : 0.0; Y : 0.0); C_one : Complex = (Form : Rec; X : 1.0; Y : 0.0); C_i : Complex = (Form : Rec; X : 0.0; Y : 1.0); C_pi : Complex = (Form : Rec; X : PI; Y : 0.0); C_pi_div_2 : Complex = (Form : Rec; X : PIDIV2; Y : 0.0); { ********************************************************************** Complex number initialization and conversion ********************************************************************** } procedure CSet(var Z : Complex; A, B : Float; F : ComplexForm); { ---------------------------------------------------------------------- Initializes a complex number according to the form specified by F F = Rec ==> Z = A + i * B F = Pol ==> Z = A * Exp(i * B) ---------------------------------------------------------------------- } procedure CConvert(var Z : Complex; F : ComplexForm); { Converts the complex number Z to the form specified by F } procedure CSwap(var X, Y : Complex); { Exchanges two complex numbers } { ********************************************************************** Complex functions ********************************************************************** } function CReal(Z : Complex) : Float; { Re(Z) } function CImag(Z : Complex) : Float; { Im(Z) } function CAbs(Z : Complex) : Float; { |Z| } function CArg(Z : Complex) : Float; { Arg(Z) } function CSgn(Z : Complex) : Integer; { Complex sign } procedure CNeg(A : Complex; var Z : Complex); { Z = -A } procedure CConj(A : Complex; var Z : Complex); { Z = A* } procedure CAdd(A, B : Complex; var Z : Complex); { Z = A + B } procedure CSub(A, B : Complex; var Z : Complex); { Z = A - B } procedure CDiv(A, B : Complex; var Z : Complex); { Z = A / B } procedure CMult(A, B : Complex; var Z : Complex); { Z = A * B } procedure CLn(A : Complex; var Z : Complex); { Z = Ln(A) } procedure CExp(A : Complex; var Z : Complex); { Z = Exp(A) } procedure CPower(A, B : Complex; var Z : Complex); { Z = A^B } procedure CIntPower(A : Complex; N : Integer; var Z : Complex); { Z = A^N } procedure CRealPower(A : Complex; X : Float; var Z : Complex); { Z = A^X } procedure CSqrt(A : Complex; var Z : Complex); { Z = Sqrt(A) } procedure CRoot(A : Complex; K, N : Integer; var Z : Complex); { Z = A^(1/N) } procedure CSin(A : Complex; var Z : Complex); { Z = Sin(A) } procedure CCos(A : Complex; var Z : Complex); { Z = Cos(A) } procedure CTan(A : Complex; var Z : Complex); { Z = Tan(A) } procedure CArcSin(A : Complex; var Z : Complex); { Z = ArcSin(A) } procedure CArcCos(A : Complex; var Z : Complex); { Z = ArcCos(A) } procedure CArcTan(A : Complex; var Z : Complex); { Z = ArcTan(A) } procedure CSinh(A : Complex; var Z : Complex); { Z = Sinh(A) } procedure CCosh(A : Complex; var Z : Complex); { Z = Cosh(A) } procedure CTanh(A : Complex; var Z : Complex); { Z = Tanh(A) } procedure CArcSinh(A : Complex; var Z : Complex); { Z = ArcSinh(A) } procedure CArcCosh(A : Complex; var Z : Complex); { Z = ArcCosh(A) } procedure CArcTanh(A : Complex; var Z : Complex); { Z = ArcTanh(A) } procedure CLnGamma(A : Complex; var Z : Complex); { Z = Ln(Gamma(A)) } implementation {$IFDEF CPU387} {$DEFINE USE_ASM} {$ENDIF} {$IFDEF CPUP2} {$DEFINE USE_ASM} {$ENDIF} procedure CSet(var Z : Complex; A, B : Float; F : ComplexForm); begin Z.Form := F; if F = Pol then begin Z.R := A; Z.Theta := B; end else begin Z.X := A; Z.Y := B; end; end; function CAbs(Z : Complex) : Float; begin if Z.Form = Rec then CAbs := Pythag(Z.X, Z.Y) else CAbs := Z.R; end; function CArg(Z : Complex) : Float; begin if Z.Form = Rec then CArg := ArcTan2(Z.Y, Z.X) else CArg := Z.Theta; end; function CReal(Z : Complex) : Float; begin if Z.Form = Rec then CReal := Z.X else CReal := Z.R * {$IFDEF USE_ASM}fCos{$ELSE}Cos{$ENDIF}(Z.Theta); end; function CImag(Z : Complex) : Float; begin if Z.Form = Rec then CImag := Z.Y else CImag := Z.R * {$IFDEF USE_ASM}fSin{$ELSE}Sin{$ENDIF}(Z.Theta); end; function CSgn(Z : Complex) : Integer; var Re, Im : Float; begin Re := CReal(Z); if Re > 0.0 then CSgn := 1 else if Re < 0.0 then CSgn := - 1 else begin Im := CImag(Z); if Im > 0.0 then CSgn := 1 else if Im < 0.0 then CSgn := - 1 else CSgn := 0; end; end; procedure CConvert(var Z : Complex; F : ComplexForm); var A : Complex; begin if Z.Form = F then Exit; if Z.Form = Pol then begin { Polar-to-rectangular conversion } A.Form := Rec; A.X := Z.R * {$IFDEF USE_ASM}fCos{$ELSE}Cos{$ENDIF}(Z.Theta); A.Y := Z.R * {$IFDEF USE_ASM}fSin{$ELSE}Sin{$ENDIF}(Z.Theta); end else begin { Rectangular-to-polar conversion } A.Form := Pol; if Z.X = 0.0 then if Z.Y = 0.0 then A.R := 0.0 else if Z.Y > 0.0 then A.R := Z.Y else A.R := - Z.Y else A.R := CAbs(Z); A.Theta := ArcTan2(Z.Y, Z.X); end; Z := A; end; procedure CSwap(var X, Y : Complex); var Temp : Complex; begin Temp := X; X := Y; Y := Temp; end; procedure CNeg(A : Complex; var Z : Complex); begin Z.Form := A.Form; if A.Form = Pol then begin Z.R := A.R; Z.Theta := FixAngle(A.Theta + PI) end else begin Z.X := - A.X; Z.Y := - A.Y end; end; procedure CConj(A : Complex; var Z : Complex); begin Z.Form := A.Form; if A.Form = Pol then begin Z.R := A.R; Z.Theta := FixAngle(- A.Theta) end else begin Z.X := A.X; Z.Y := - A.Y end end; procedure CAdd(A, B : Complex; var Z : Complex); begin CConvert(A, Rec); CConvert(B, Rec); Z.Form := Rec; Z.X := A.X + B.X; Z.Y := A.Y + B.Y; end; procedure CSub(A, B : Complex; var Z : Complex); begin CConvert(A, Rec); CConvert(B, Rec); Z.Form := Rec; Z.X := A.X - B.X; Z.Y := A.Y - B.Y; end; procedure CMult(A, B : Complex; var Z : Complex); begin CConvert(B, A.Form); { arbitrarily convert one to type of other } Z.Form := A.Form; if A.Form = Pol then begin Z.R := A.R * B.R; Z.Theta := FixAngle(A.Theta + B.Theta) end else begin Z.X := A.X * B.X - A.Y * B.Y; Z.Y := A.X * B.Y + A.Y * B.X end; end; procedure CDiv(A, B : Complex; var Z : Complex); var Temp : Float; begin if ((B.Form = Rec) and (B.X = 0.0) and (B.Y = 0.0)) or ((B.Form = Pol) and (B.R = 0.0)) then begin MathErr := FN_OVERFLOW; Z := C_infinity; Exit; end; CConvert(B, A.Form); { arbitrarily convert one to type of other } Z.Form := A.Form; if A.Form = Pol then begin Z.R := A.R / B.R; Z.Theta := FixAngle(A.Theta - B.Theta); end else begin Temp := Sqr(B.X) + Sqr(B.Y); Z.X := (A.X * B.X + A.Y * B.Y) / Temp; Z.Y := (A.Y * B.X - A.X * B.Y) / Temp; end; end; procedure CLn(A : Complex; var Z : Complex); var LnR : Float; begin CConvert(A, Pol); LnR := Log(A.R); if MathErr = FN_OK then CSet(Z, LnR, FixAngle(A.Theta), Rec) else CSet(Z, - MAXNUM, 0.0, Rec); end; procedure CExp(A : Complex; var Z : Complex); var ExpX, SinY, CosY : Float; begin CConvert(A, Rec); ExpX := Expo(A.X); if MathErr = FN_OK then begin SinY := {$IFDEF USE_ASM}fSin{$ELSE}Sin{$ENDIF}(A.Y); CosY := {$IFDEF USE_ASM}fCos{$ELSE}Cos{$ENDIF}(A.Y); CSet(Z, ExpX * CosY, ExpX * SinY, Rec); end else CSet(Z, ExpX, 0.0, Rec); end; procedure CPower(A, B : Complex; var Z : Complex); var BLnA, LnA : Complex; begin CConvert(A, Rec); CConvert(B, Rec); if (A.X = 0.0) and (A.Y = 0.0) then if (B.X = 0.0) and (B.Y = 0.0) then Z := C_one { lim a^a = 1 as a -> 0 } else Z := C_zero { 0^b = 0, b > 0 } else begin CLn(A, LnA); CMult(B, LnA, BLnA); CExp(BLnA, Z); end; end; procedure CIntPower(A : Complex; N : Integer; var Z : Complex); { CIntPower directly applies DeMoivre's theorem to calculate an integer power of a complex number. The formula holds for both positive and negative values of N } begin CConvert(A, Pol); if A.R = 0.0 then if N = 0 then Z := C_one else if N > 0 then Z := C_zero else begin MathErr := FN_SING; Z := C_infinity; end else CSet(Z, IntPower(A.R, N), FixAngle(N * A.Theta), Pol); end; procedure CRealPower(A : Complex; X : Float; var Z : Complex); begin CConvert(A, Pol); if A.R = 0.0 then if X = 0.0 then Z := C_one else if X > 0.0 then Z := C_zero else begin MathErr := FN_SING; Z := C_infinity; end else CSet(Z, Power(A.R, X), FixAngle(X * A.Theta), Pol); end; procedure CRoot(A : Complex; K, N : Integer; var Z : Complex); { CRoot can calculate all 'N' roots of 'A' by varying 'K' from 0..N-1 } { This is another application of DeMoivre's theorem. See CIntPower. } begin if (N <= 0) or (K < 0) or (K >= N) then begin MathErr := FN_DOMAIN; Z := C_zero; Exit; end; CConvert(A, Pol); if A.R = 0.0 then Z := C_zero else CSet(Z, Power(A.R, 1.0 / N), FixAngle((A.Theta + K * TWOPI) / N), Pol); end; procedure CSqrt(A : Complex; var Z : Complex); begin CConvert(A, Pol); if A.R = 0.0 then Z := C_zero else CSet(Z, Sqrt(A.R), FixAngle(0.5 * A.Theta), Pol); end; procedure CCos(A : Complex; var Z : Complex); var SinX, CosX, SinhY, CoshY : Float; begin CConvert(A, Rec); SinCos(A.X, SinX, CosX); SinhCosh(A.Y, SinhY, CoshY); { Called here to set MathErr } CSet(Z, CosX * CoshY, - SinX * SinhY, Rec) end; procedure CSin(A : Complex; var Z : Complex); var SinX, CosX, SinhY, CoshY : Float; begin CConvert(A, Rec); SinCos(A.X, SinX, CosX); SinhCosh(A.Y, SinhY, CoshY); { Called here to set MathErr } CSet(Z, SinX * CoshY, CosX * SinhY, Rec) end; procedure CTan(A : Complex; var Z : Complex); var X2, Y2, SinX2, CosX2, SinhY2, CoshY2, Temp : Float; begin CConvert(A, Rec); X2 := 2.0 * A.X; Y2 := 2.0 * A.Y; SinCos(X2, SinX2, CosX2); SinhCosh(Y2, SinhY2, CoshY2); if MathErr = FN_OK then Temp := CosX2 + CoshY2 else Temp := CoshY2; if Temp <> 0.0 then CSet(Z, SinX2 / Temp, SinhY2 / Temp, Rec) else begin { A = Pi/2 + k*Pi } MathErr := FN_SING; CSet(Z, MAXNUM, 0.0, Rec); end; end; procedure CCosh(A : Complex; var Z : Complex); var SinhX, CoshX, SinY, CosY : Float; begin CConvert(A, Rec); SinCos(A.Y, SinY, CosY); SinhCosh(A.X, SinhX, CoshX); CSet(Z, CoshX * CosY, SinhX * SinY, Rec) end; procedure CSinh(A : Complex; var Z : Complex); var SinhX, CoshX, SinY, CosY : Float; begin CConvert(A, Rec); SinCos(A.Y, SinY, CosY); SinhCosh(A.X, SinhX, CoshX); CSet(Z, SinhX * CosY, CoshX * SinY, Rec) end; procedure CTanh(A : Complex; var Z : Complex); var X2, Y2, SinY2, CosY2, SinhX2, CoshX2, Temp : Float; begin CConvert(A, Rec); X2 := 2.0 * A.X; Y2 := 2.0 * A.Y; SinCos(Y2, SinY2, CosY2); SinhCosh(X2, SinhX2, CoshX2); if MathErr = FN_OK then Temp := CoshX2 + CosY2 else Temp := CoshX2; if Temp <> 0.0 then CSet(Z, SinhX2 / Temp, SinY2 / Temp, Rec) else begin { A = i * (Pi/2 + k*Pi) } MathErr := FN_SING; CSet(Z, 0.0, MAXNUM, Rec); end; end; procedure CArcSin(A : Complex; var Z : Complex); var Rp, Rm, S, T, X2, XX, YY : Float; B : Complex; begin CConvert(A, Rec); CSet(B, A.Y, - A.X, Rec); { Y - i*X } X2 := 2.0 * A.X; XX := Sqr(A.X); YY := Sqr(A.Y); S := XX + YY + 1.0; Rp := 0.5 * Sqrt(S + X2); Rm := 0.5 * Sqrt(S - X2); T := Rp + Rm; Z.Form := Rec; Z.X := ArcSin(Rp - Rm); Z.Y := CSgn(B) * Log(T + Sqrt(Sqr(T) - 1.0)); end; procedure CArcCos(A : Complex; var Z : Complex); begin CArcSin(A, Z); CSub(C_pi_div_2, Z, Z); { Pi/2 - ArcSin(Z) } end; procedure CArcTan(A : Complex; var Z : Complex); var XX, Yp1, Ym1 : Float; begin CConvert(A, Rec); if (A.X = 0.0) and (Abs(A.Y) = 1.0) then { A = +/- i } begin MathErr := FN_SING; CSet(Z, 0.0, Sgn(A.Y) * MAXNUM, Rec); Exit; end; XX := Sqr(A.X); Yp1 := A.Y + 1.0; Ym1 := A.Y - 1.0; Z.Form := Rec; Z.X := 0.5 * (ArcTan2(A.X, - Ym1) - ArcTan2(- A.X, Yp1)); Z.Y := 0.25 * Log((XX + Sqr(Yp1)) / (XX + Sqr(Ym1))); end; procedure CArcSinh(A : Complex; var Z : Complex); { ArcSinH(A) = -i*ArcSin(i*A) } begin CMult(C_i, A, Z); CArcSin(Z, Z); CMult(C_i, Z, Z); CNeg(Z, Z); end; procedure CArcCosh(A : Complex; var Z : Complex); { ArcCosH(A) = CSgn(Y + i(1-X))*i*ArcCos(A) where A = X+iY } var B : Complex; begin CArcCos(A, Z); CMult(C_i, Z, Z); CSet(B, A.Y, 1.0 - A.X, Rec); { Y + i*(1-X) } if CSgn(B) = -1 then CNeg(Z, Z); end; procedure CArcTanh(A : Complex; var Z : Complex); { ArcTanH(A) = -i*ArcTan(i*A) } begin CConvert(A, Rec); if (Abs(A.X) = 1.0) and (A.Y = 0.0) then { A = +/- 1 } begin MathErr := FN_SING; CSet(Z, Sgn(A.X) * MAXNUM, 0.0, Rec); Exit; end; CMult(C_i, A, Z); CArcTan(Z, Z); CMult(C_i, Z, Z); CNeg(Z, Z); end; procedure CApproxLnGamma(Z : Complex; var Sum : Complex); { This is the approximation used in the National Bureau of Standards "Table of the Gamma Function for Complex Arguments," Applied Mathematics Series 34, 1954. The NBS table was created using this approximation over the area 9 < Re(z) < 10 and 0 < Im(z) < 10. Other table values were computed using the relationship: _ _ ln | (z+1) = ln z + ln | (z) } const C : array[1..8] of Float = (8.33333333333333E-02, - 2.77777777777778E-03, 7.93650793650794E-04, - 5.95238095238095E-04, 8.41750841750842E-04, - 1.91752691752692E-03, 6.41025641025641E-03, - 2.95506535947712E-02); var I : Integer; Powers : array[1..8] of Complex; Temp1, Temp2 : Complex; begin CConvert(Z, Rec); CLn(Z, Temp1); { Ln(Z) } CSet(Temp2, Z.X - 0.5, Z.Y, Rec); { Z - 0.5 } CMult(Temp1, Temp2, Sum); { (Z - 0.5)*Ln(Z) } CSub(Sum, Z, Sum); { (Z - 0.5)*ln(Z) - Z } Sum.X := Sum.X + LN2PIDIV2; Temp1 := C_one; CDiv(Temp1, Z, Powers[1]); { Z^(-1) } CMult(Powers[1], Powers[1], Temp2); { Z^(-2) } for I := 2 to 8 do CMult(Powers[I - 1], Temp2, Powers[I]); for I := 8 downto 1 do begin CSet(Temp1, C[I] * Powers[I].X, C[I] * Powers[I].Y, Rec); CAdd(Sum, Temp1, Sum); end end; procedure CLnGamma(A : Complex; var Z : Complex); var LnA, Temp : Complex; begin CConvert(A, Rec); if (A.X <= 0.0) and (A.Y = 0.0) then if (Int(A.X - 1E-8) - A.X) = 0.0 then { Negative integer? } begin MathErr := FN_SING; Z := C_infinity; Exit end; if A.Y < 0.0 then { 3rd or 4th quadrant? } begin CConj(A, A); CLnGamma(A, Z); { Try again in 1st or 2nd quadrant } CConj(Z, Z) { Left this out! 1/3/91 } end else begin if A.X < 9.0 then { "left" of NBS table range } begin CLn(A, LnA); CSet(A, A.X + 1.0, A.Y, Rec); CLnGamma(A, Temp); CSub(Temp, LnA, Z) end else CApproxLnGamma(A, Z) { NBS table range: 9 < Re(z) < 10 } end end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/winplot.pas����������������������������������������������0000755�0001750�0001750�00000071142�11326443506�020304� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit WINPLOT.PAS * * Version 1.1 * * (c) J. Debord, October 1999 * ********************************************************************** Plotting routines for DELPHI ********************************************************************** } unit WinPlot; interface uses { DELPHI units } WinTypes, Graphics, { TPMath units } FMath, Matrices, Stat, PaString; { ************************* Constants and types ************************ } const MAXCURV = 255; { Max. number of curves which may be plotted } MAXSYMBOL = 9; { Max. number of symbols for plotting curves } EPS = 1.0E-10; { Lower limit for an axis label } type TScale = (LIN_SCALE, { Scale } LOG_SCALE); TGrid = (NO_GRID, { Grid } HORIZ_GRID, VERTIC_GRID, BOTH_GRID); TAxis = record { Coordinate axis } Scale : TScale; Min, Max, Step : Float; Title : String; end; TPointParam = record { Point parameters } Symbol : Integer; { Symbol index } Size : Integer; { Symbol size in 1/250 of graphic width } Color : TColor; end; TLineParam = record { Line parameters } Width : Integer; Style : TPenStyle; Color : TColor; end; TCurvParam = record { Curve parameters } PointParam : TPointParam; LineParam : TLineParam; Legend : String[30]; { Legend of curve } Step : Integer; { Plot 1 point every Step points } Connect : Boolean; { Connect points with line? } end; TCurvParamArray = array[1..MAXCURV] of TCurvParam; PCurvParamArray = ^TCurvParamArray; { ******** Global variables defining the appearance of the graph ******* } const Xwin1 : Integer = 15; { Window coordinates in percent of maximum } Ywin1 : Integer = 15; Xwin2 : Integer = 75; Ywin2 : Integer = 75; GraphBorder : Boolean = True; { For plotting a rectangle around the graph } XAxis : TAxis = (Scale : LIN_SCALE; { Horizontal axis } Min : 0.0; Max : 1.0; Step : 0.2; Title : 'X'); YAxis : TAxis = (Scale : LIN_SCALE; { Vertical axis } Min : 0.0; Max : 1.0; Step : 0.2; Title : 'Y'); Grid : TGrid = BOTH_GRID; { Grid } GraphTitle : String = ''; { Title of graph } { ************************** Graphic routines ************************** } procedure InitGraph(Canvas : TCanvas; Width, Height : Integer); { ---------------------------------------------------------------------- Initializes the graphic ---------------------------------------------------------------------- The parameters refer to the object on which the graphic is plotted. Examples: To draw on a TImage object: InitGraph(Image1.Canvas, Image1.Width, Image1.Height); To print the graphic: InitGraph(Printer.Canvas, Printer.PageWidth, Printer.PageHeight); ---------------------------------------------------------------------- } procedure PlotXAxis(Canvas : TCanvas); { ---------------------------------------------------------------------- Plots the X axis ---------------------------------------------------------------------- } procedure PlotYAxis(Canvas : TCanvas); { ---------------------------------------------------------------------- Plots the Y axis ---------------------------------------------------------------------- } procedure WriteTitle(Canvas : TCanvas); { ---------------------------------------------------------------------- Writes the title of the graph ---------------------------------------------------------------------- } procedure PlotGrid(Canvas : TCanvas); { ---------------------------------------------------------------------- Plots a grid on the graph ---------------------------------------------------------------------- } procedure PlotPoint(Canvas : TCanvas; X, Y : Float; PointParam : TPointParam); { ---------------------------------------------------------------------- Plots a point ---------------------------------------------------------------------- X, Y : point coordinates PointParam : point parameters ---------------------------------------------------------------------- } procedure PlotCurve(Canvas : TCanvas; X, Y : PVector; Lbound, Ubound : Integer; CurvParam : TCurvParam); { ---------------------------------------------------------------------- Plots a curve ---------------------------------------------------------------------- X, Y : point coordinates Lbound, Ubound : indices of first and last points CurvParam : curve parameters ---------------------------------------------------------------------- } procedure PlotCurveWithErrorBars(Canvas : TCanvas; X, Y, S : PVector; Ns : Integer; Lbound, Ubound : Integer; CurvParam : TCurvParam); { ---------------------------------------------------------------------- Plots a curve with error bars ---------------------------------------------------------------------- X, Y : point coordinates S : errors (e.g. standard deviations) Ns : error multiplier (e.g. 2 for plotting 2 SD's) Lbound, Ubound : indices of first and last points CurvParam : curve parameters ---------------------------------------------------------------------- } procedure PlotFunc(Canvas : TCanvas; Func : TFunc; Xmin, Xmax : Float; Npt : Integer; LineParam : TLineParam); { ---------------------------------------------------------------------- Plots a function ---------------------------------------------------------------------- Func : function to be plotted must be programmed as: function Func(X : Float) : Float; Xmin, Xmax : abscissae of 1st and last point to plot Npt : number of points LineParam : line parameters ---------------------------------------------------------------------- } procedure WriteLegend(Canvas : TCanvas; NCurv : Integer; CurvParam : PCurvParamArray; ShowPoints, ShowLines : Boolean); { ---------------------------------------------------------------------- Writes the legends for the plotted curves ---------------------------------------------------------------------- NCurv : number of curves (1 to MAXCURV) CurvParam : curve parameters ShowPoints : for displaying points ShowLines : for displaying lines ---------------------------------------------------------------------- } { *********** The following routines are defined in PLOT.INC *********** } procedure Interval(X1, X2 : Float; MinDiv, MaxDiv : Integer; var Min, Max, Step : Float); { ---------------------------------------------------------------------- Determines an interval [Min, Max] including the values from X1 to X2, and a subdivision Step of this interval ---------------------------------------------------------------------- Input parameters : X1, X2 = min. & max. values to be included MinDiv = minimum nb of subdivisions MaxDiv = maximum nb of subdivisions ---------------------------------------------------------------------- Output parameters : Min, Max, Step ---------------------------------------------------------------------- } procedure AutoScale(Z : PVector; Lbound, Ubound : Integer; var Axis : TAxis); { ---------------------------------------------------------------------- Determines the scale of an axis ---------------------------------------------------------------------- Input parameters : Z = array of values to be plotted Lbound, Ubound = indices of first and last elements of Z ---------------------------------------------------------------------- Output parameters : Axis ---------------------------------------------------------------------- } function Xpixel(X : Float) : Integer; { ---------------------------------------------------------------------- Converts user abscissa X to screen coordinate ---------------------------------------------------------------------- } function Ypixel(Y : Float) : Integer; { ---------------------------------------------------------------------- Converts user ordinate Y to screen coordinate ---------------------------------------------------------------------- } function Xuser(X : Integer) : Float; { ---------------------------------------------------------------------- Converts screen coordinate X to user abscissa ---------------------------------------------------------------------- } function Yuser(Y : Integer) : Float; { ---------------------------------------------------------------------- Converts screen coordinate Y to user ordinate ---------------------------------------------------------------------- } implementation uses Classes; var GraphWidth, GraphHeight, SymbolSizeUnit : Integer; { ---------------------------------------------------------------------- Include the variables and routines common to PLOT.PAS and WINPLOT.PAS ---------------------------------------------------------------------- } {$I PLOT.INC} { ---------------------------------------------------------------------- } procedure PlotXAxis(Canvas : TCanvas); var W, X, Z : Float; N, I, J, TickLength, MinorTickLength, Wp, Xp : Integer; XLabel : String; NSZ : Boolean; begin TickLength := Canvas.TextHeight('M') div 2; MinorTickLength := Round(0.67 * TickLength); { For log scale } { Draw axis } Canvas.MoveTo(XminPixel, YmaxPixel); Canvas.LineTo(XmaxPixel, YmaxPixel); NSZ := NSZero; NSZero := False; { Don't write non significant zero's } N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); { Nb of intervals } X := XAxis.Min; { Tick mark position } for I := 0 to N do { Label axis } begin if (XAxis.Scale = LIN_SCALE) and (Abs(X) < EPS) then X := 0.0; Xp := Xpixel(X); { Draw tick mark } Canvas.MoveTo(Xp, YmaxPixel); Canvas.LineTo(Xp, YmaxPixel + TickLength); { Write label } if XAxis.Scale = LIN_SCALE then Z := X else Z := Exp10(X); XLabel := Trim(PaString.FloatToStr(Z)); Canvas.TextOut(Xp - Canvas.TextWidth(XLabel) div 2, YmaxPixel + TickLength, XLabel); { Plot minor divisions on logarithmic scale } if (XAxis.Scale = LOG_SCALE) and (I < N) then for J := 2 to 9 do begin W := X + Log10(J); Wp := Xpixel(W); Canvas.MoveTo(Wp, YmaxPixel); Canvas.LineTo(Wp, YmaxPixel + MinorTickLength); end; X := X + XAxis.Step; end; NSZero := NSZ; { Write axis title } if XAxis.Title <> '' then Canvas.TextOut(XminPixel + (XmaxPixel - XminPixel - Canvas.TextWidth(XAxis.Title)) div 2, YmaxPixel + 2 * Canvas.TextHeight('M'), XAxis.Title); end; procedure PlotYAxis(Canvas : TCanvas); var W, Y, Z : Float; N, I, J, Wp, Yp : Integer; TickLength, MinorTickLength, Yoffset : Integer; YLabel : String; NSZ : Boolean; begin TickLength := Canvas.TextWidth('M') div 2; MinorTickLength := Round(0.67 * TickLength); { For log scale } Yoffset := Canvas.TextHeight('M') div 2; { Draw axis } Canvas.MoveTo(XminPixel, YminPixel); Canvas.LineTo(XminPixel, YmaxPixel); NSZ := NSZero; NSZero := False; { Don't write non significant zero's } N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); { Nb of intervals } Y := YAxis.Min; { Tick mark position } for I := 0 to N do { Label axis } begin if (YAxis.Scale = LIN_SCALE) and (Abs(Y) < EPS) then Y := 0.0; Yp := Ypixel(Y); { Draw tick mark } Canvas.MoveTo(XminPixel, Yp); Canvas.LineTo(XminPixel - TickLength, Yp); { Write label } if YAxis.Scale = LIN_SCALE then Z := Y else Z := Exp10(Y); YLabel := Trim(PaString.FloatToStr(Z)); Canvas.TextOut(XminPixel - TickLength - Canvas.TextWidth(YLabel), Yp - Yoffset, YLabel); { Plot minor divisions on logarithmic scale } if (YAxis.Scale = LOG_SCALE) and (I < N) then for J := 2 to 9 do begin W := Y + Log10(J); Wp := Ypixel(W); Canvas.MoveTo(XminPixel, Wp); Canvas.LineTo(XminPixel - MinorTickLength, Wp); end; Y := Y + YAxis.Step; end; NSZero := NSZ; { Write axis title } if YAxis.Title <> '' then Canvas.TextOut(XminPixel, YminPixel - 3 * Yoffset, YAxis.Title); end; procedure InitGraph(Canvas : TCanvas; Width, Height : Integer); begin GraphWidth := Width; GraphHeight := Height; SymbolSizeUnit := GraphWidth div 250; XminPixel := Round(Xwin1 / 100 * Width); YminPixel := Round(Ywin1 / 100 * Height); XmaxPixel := Round(Xwin2 / 100 * Width); YmaxPixel := Round(Ywin2 / 100 * Height); FactX := (XmaxPixel - XminPixel) / (XAxis.Max - XAxis.Min); FactY := (YmaxPixel - YminPixel) / (YAxis.Max - YAxis.Min); if GraphBorder then Canvas.Rectangle(XminPixel, YminPixel, Succ(XmaxPixel), Succ(YmaxPixel)); end; procedure WriteTitle(Canvas : TCanvas); begin if GraphTitle <> '' then with Canvas do TextOut((XminPixel + XmaxPixel - TextWidth(GraphTitle)) div 2, YminPixel - 2 * TextHeight(GraphTitle), GraphTitle); end; procedure PlotGrid(Canvas : TCanvas); var X, Y : Float; I, N, Xp, Yp : Integer; PenStyle : TpenStyle; begin { Save current settings } PenStyle := Canvas.Pen.Style; Canvas.Pen.Style := psDot; if Grid in [HORIZ_GRID, BOTH_GRID] then { Horizontal lines } begin N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); { Nb of intervals } for I := 1 to Pred(N) do begin Y := YAxis.Min + I * YAxis.Step; { Origin of line } Yp := Ypixel(Y); Canvas.MoveTo(XminPixel, Yp); Canvas.LineTo(XmaxPixel, Yp); end; end; if Grid in [VERTIC_GRID, BOTH_GRID] then { Vertical lines } begin N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); for I := 1 to Pred(N) do begin X := XAxis.Min + I * XAxis.Step; Xp := Xpixel(X); Canvas.MoveTo(Xp, YminPixel); Canvas.LineTo(Xp, YmaxPixel); end; end; { Restore settings } Canvas.Pen.Style := PenStyle; end; function XOutOfBounds(X : Integer) : Boolean; { Checks if an absissa is outside the graphic bounds } begin XOutOfBounds := (X < XminPixel) or (X > XmaxPixel); end; function YOutOfBounds(Y : Integer) : Boolean; { Checks if an ordinate is outside the graphic bounds } begin YOutOfBounds := (Y < YminPixel) or (Y > YmaxPixel); end; function CheckPoint(X, Y : Float; var Xp, Yp : Integer) : Boolean; { Computes the pixel coordinates of a point and checks if it is enclosed within the graph limits } begin Xp := Xpixel(X); Yp := Ypixel(Y); CheckPoint := not(XOutOfBounds(Xp) or YOutOfBounds(Yp)); end; procedure PlotSymbol(Canvas : TCanvas; Xp, Yp : Integer; Symbol, Size : Integer); { Plots a symbol at pixel coordinates (Xp, Yp) with the current canvas settings } var Xp1, Xp2, Yp1, Yp2 : Integer; begin if Symbol > 0 then begin Size := Size * SymbolSizeUnit; Xp1 := Xp - Size; Yp1 := Yp - Size; Xp2 := Xp + Size + 1; Yp2 := Yp + Size + 1; end; with Canvas do case Symbol of 0 : Pixels[Xp, Yp] := Brush.Color; 1, 2 : Ellipse(Xp1, Yp1, Xp2, Yp2); { Circle } 3, 4 : Rectangle(Xp1, Yp1, Xp2, Yp2); { Square } 5, 6 : Polygon([Point(Xp1, Yp2 - 1), Point(Xp2, Yp2 - 1), Point(Xp, Yp1 - 1)]); { Triangle } 7 : begin { + } MoveTo(Xp, Yp1); LineTo(Xp, Yp2); MoveTo(Xp1, Yp); LineTo(Xp2, Yp); end; 8 : begin { x } MoveTo(Xp1, Yp1); LineTo(Xp2, Yp2); MoveTo(Xp1, Yp2 - 1); LineTo(Xp2, Yp1 - 1); end; 9 : begin { * } MoveTo(Xp, Yp1); LineTo(Xp, Yp2); MoveTo(Xp1, Yp); LineTo(Xp2, Yp); MoveTo(Xp1, Yp1); LineTo(Xp2, Yp2); MoveTo(Xp1, Yp2 - 1); LineTo(Xp2, Yp1 - 1); end; end; end; procedure PlotLine(Canvas : TCanvas; Xp1, Yp1, Xp2, Yp2 : Integer); { Plots a line with the current canvas settings } begin Canvas.MoveTo(Xp1, Yp1); Canvas.LineTo(Xp2, Yp2); end; procedure PlotPoint(Canvas : TCanvas; X, Y : Float; PointParam : TPointParam); var Xp, Yp : Integer; BrushStyle : TBrushStyle; PenColor, BrushColor : TColor; begin if XAxis.Scale = LOG_SCALE then X := Log10(X); if YAxis.Scale = LOG_SCALE then Y := Log10(Y); if not CheckPoint(X, Y, Xp, Yp) then Exit; with Canvas do begin { Save current settings } PenColor := Pen.Color; BrushColor := Brush.Color; BrushStyle := Brush.Style; Pen.Color := PointParam.Color; Brush.Color := PointParam.Color; if PointParam.Symbol in [0, 1, 3, 5] then Brush.Style := bsSolid else Brush.Style := bsClear; PlotSymbol(Canvas, Xp, Yp, PointParam.Symbol, PointParam.Size); { Restore settings } Pen.Color := PenColor; Brush.Color := BrushColor; Brush.Style := BrushStyle; end; end; procedure PlotErrorBar(Canvas : TCanvas; Y, S : Float; Ns : Integer; Xp, Yp, Size : Integer); { Plots an error bar with the current canvas settings } var Delta, Y1 : Float; Yp1 : Integer; begin Size := Size * SymbolSizeUnit; Delta := Ns * S; Y1 := Y - Delta; if YAxis.Scale = LOG_SCALE then Y1 := Log10(Y1); Yp1 := Ypixel(Y1); if Yp1 <= YmaxPixel then begin PlotLine(Canvas, Xp - Size, Yp1, Xp + Size + 1, Yp1); PlotLine(Canvas, Xp, Yp, Xp, Yp1); end else PlotLine(Canvas, Xp, Yp, Xp, YmaxPixel); Y1 := Y + Delta; if YAxis.Scale = LOG_SCALE then Y1 := Log10(Y1); Yp1 := Ypixel(Y1); if Yp1 >= YminPixel then begin PlotLine(Canvas, Xp - Size, Yp1, Xp + Size + 1, Yp1); PlotLine(Canvas, Xp, Yp, Xp, Yp1); end else PlotLine(Canvas, Xp, Yp, Xp, YminPixel); end; procedure GenPlotCurve(Canvas : TCanvas; X, Y, S : PVector; Ns : Integer; Lbound, Ubound : Integer; CurvParam : TCurvParam; ErrorBars : Boolean); { General curve plotting routine } var X1, Y1, X2, Y2 : Float; Xp1, Yp1, Xp2, Yp2 : Integer; I : Integer; Flag1, Flag2 : Boolean; PenWidth : Integer; PenStyle : TpenStyle; PenColor, BrushColor : TColor; BrushStyle : TBrushStyle; begin with Canvas do begin { Save current settings } PenColor := Pen.Color; PenStyle := Pen.Style; PenWidth := Pen.Width; BrushColor := Brush.Color; BrushStyle := Brush.Style; Pen.Color := CurvParam.LineParam.Color; Pen.Style := CurvParam.LineParam.Style; Pen.Width := CurvParam.LineParam.Width; Brush.Color := CurvParam.PointParam.Color; if CurvParam.PointParam.Symbol in [0, 1, 3, 5] then Brush.Style := bsSolid else Brush.Style := bsClear; { Plot first point } X1 := X^[Lbound]; if XAxis.Scale = LOG_SCALE then X1 := Log10(X1); Y1 := Y^[Lbound]; if YAxis.Scale = LOG_SCALE then Y1 := Log10(Y1); Flag1 := CheckPoint(X1, Y1, Xp1, Yp1); if Flag1 then begin PlotSymbol(Canvas, Xp1, Yp1, CurvParam.PointParam.Symbol, CurvParam.PointParam.Size); if ErrorBars and (S^[Lbound] > 0.0) then PlotErrorBar(Canvas, Y^[Lbound], S^[Lbound], Ns, Xp1, Yp1, CurvParam.PointParam.Size); end; { Plot other points and connect them by lines if necessary } I := Lbound + CurvParam.Step; while I <= Ubound do begin X2 := X^[I]; if XAxis.Scale = LOG_SCALE then X2 := Log10(X2); Y2 := Y^[I]; if YAxis.Scale = LOG_SCALE then Y2 := Log10(Y2); Flag2 := CheckPoint(X2, Y2, Xp2, Yp2); if Flag2 then begin PlotSymbol(Canvas, Xp2, Yp2, CurvParam.PointParam.Symbol, CurvParam.PointParam.Size); if ErrorBars and (S^[I] > 0.0) then PlotErrorBar(Canvas, Y^[I], S^[I], Ns, Xp2, Yp2, CurvParam.PointParam.Size); if CurvParam.Connect and Flag1 then PlotLine(Canvas, Xp1, Yp1, Xp2, Yp2); end; Xp1 := Xp2; Yp1 := Yp2; Flag1 := Flag2; Inc(I, CurvParam.Step); end; { Restore settings } Pen.Color := PenColor; Pen.Style := PenStyle; Pen.Width := PenWidth; Brush.Color := BrushColor; Brush.Style := BrushStyle; end; end; procedure PlotCurve(Canvas : TCanvas; X, Y : PVector; Lbound, Ubound : Integer; CurvParam : TCurvParam); var Ns : Integer; { Dummy variables } S : PVector; begin GenPlotCurve(Canvas, X, Y, S, Ns, Lbound, Ubound, CurvParam, False); end; procedure PlotCurveWithErrorBars(Canvas : TCanvas; X, Y, S : PVector; Ns : Integer; Lbound, Ubound : Integer; CurvParam : TCurvParam); begin GenPlotCurve(Canvas, X, Y, S, Ns, Lbound, Ubound, CurvParam, True); end; procedure PlotFunc(Canvas : TCanvas; Func : TFunc; Xmin, Xmax : Float; Npt : Integer; LineParam : TLineParam); var PenColor : TColor; PenStyle : TpenStyle; PenWidth : Integer; X1, Y1, X2, Y2, H : Float; Xp1, Yp1, Xp2, Yp2 : Integer; Flag1, Flag2 : Boolean; I : Integer; begin if (Npt < 2) or (LineParam.Style = psClear) then Exit; if Xmin >= Xmax then begin Xmin := XAxis.Min; Xmax := XAxis.Max; end; H := (Xmax - Xmin) / Npt; with Canvas do begin { Save current settings } PenColor := Pen.Color; PenStyle := Pen.Style; PenWidth := Pen.Width; Pen.Color := LineParam.Color; Pen.Style := LineParam.Style; Pen.Width := LineParam.Width; { Check first point } X1 := Xmin; if XAxis.Scale = LIN_SCALE then Y1 := Func(X1) else Y1 := Func(Exp10(X1)); if YAxis.Scale = LOG_SCALE then Y1 := Log10(Y1); Flag1 := CheckPoint(X1, Y1, Xp1, Yp1); { Check other points and plot lines if possible } for I := 1 to Npt do begin X2 := X1 + H; if XAxis.Scale = LIN_SCALE then Y2 := Func(X2) else Y2 := Func(Exp10(X2)); if YAxis.Scale = LOG_SCALE then Y2 := Log10(Y2); Flag2 := CheckPoint(X2, Y2, Xp2, Yp2); if Flag1 and Flag2 then PlotLine(Canvas, Xp1, Yp1, Xp2, Yp2); X1 := X2; Xp1 := Xp2; Yp1 := Yp2; Flag1 := Flag2; end; { Restore settings } Pen.Color := PenColor; Pen.Style := PenStyle; Pen.Width := PenWidth; end; end; procedure WriteLegend(Canvas : TCanvas; NCurv : Integer; CurvParam : PCurvParamArray; ShowPoints, ShowLines : Boolean); var CharHeight, I, L, Lmax, N, Nmax, Xp, Xl, Y : Integer; PenWidth : Integer; PenStyle : TpenStyle; PenColor, BrushColor : TColor; BrushStyle : TBrushStyle; begin N := 0; { Nb of legends to be plotted } Lmax := 0; { Length of the longest legend } for I := 1 to NCurv do if CurvParam^[I].Legend <> '' then begin Inc(N); L := Canvas.TextWidth(CurvParam^[I].Legend); if L > Lmax then Lmax := L; end; if (N = 0) or (Lmax = 0) then Exit; { Character height } CharHeight := Canvas.TextHeight('M'); { Max. number of legends which may be plotted } Nmax := Round((YmaxPixel - YminPixel) / CharHeight) - 1; if N > Nmax then N := Nmax; { Draw rectangle around the legends } Canvas.Rectangle(XmaxPixel + Round(0.02 * GraphWidth), YminPixel, XmaxPixel + Round(0.12 * GraphWidth) + Lmax, YminPixel + (N + 1) * CharHeight); L := Round(0.02 * GraphWidth); { Half-length of line } Xp := XmaxPixel + 3 * L; { Position of symbol } Xl := XmaxPixel + 5 * L; { Position of legend } { Save current settings } with Canvas do begin PenColor := Pen.Color; PenStyle := Pen.Style; PenWidth := Pen.Width; BrushColor := Brush.Color; BrushStyle := Brush.Style; end; for I := 1 to IMin(NCurv, Nmax) do with Canvas do begin Pen.Color := CurvParam^[I].LineParam.Color; Pen.Style := CurvParam^[I].LineParam.Style; Pen.Width := CurvParam^[I].LineParam.Width; Brush.Color := CurvParam^[I].PointParam.Color; if CurvParam^[I].PointParam.Symbol in [0, 1, 3, 5] then Brush.Style := bsSolid else Brush.Style := bsClear; { Plot point and line } Y := YminPixel + I * CharHeight; if ShowPoints then PlotSymbol(Canvas, Xp, Y, CurvParam^[I].PointParam.Symbol, CurvParam^[I].PointParam.Size); if ShowLines then PlotLine(Canvas, Xp - L, Y, Xp + L, Y); { Write legend } Brush.Style := bsClear; Canvas.TextOut(Xl, Y - CharHeight div 2, CurvParam^[I].Legend); end; { Restore settings } with Canvas do begin Pen.Color := PenColor; Pen.Style := PenStyle; Pen.Width := PenWidth; Brush.Color := BrushColor; Brush.Style := BrushStyle; end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/fitmult.pas����������������������������������������������0000755�0001750�0001750�00000010761�11326443506�020274� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITMULT.PAS * * Version 1.1 * * (c) J. Debord, October 1998 * ********************************************************************** This unit fits the multiple linear equation: y = b0 + b1.x1 + b2.x2 + ... ********************************************************************** } unit FitMult; {$F+} interface uses FMath, Matrices, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X, B : PVector) : Float; function FitModel(Method : Integer; X : PMatrix; Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; procedure InitModel(CstPar : PVector); implementation const Nvar : Integer = 2; { Number of independent variables } ConsTerm : Boolean = True; { Flags the presence of a constant term b0 } function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } var Name, S : String; I : Integer; begin Name := 'y = '; if ConsTerm then Name := Name + 'b0 + '; Name := Name + 'b1.x1'; for I := 2 to Nvar do begin Str(I, S); Name := Name + ' + b' + S + '.x' + S; end; FuncName := Name; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted -------------------------------------------------------------------- } begin if ConsTerm then FirstParam := 0 else FirstParam := 1; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := Nvar; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } var S : String; begin Str(I, S); ParamName := 'b' + S; end; function RegFunc(X, B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at observation X B is the vector of parameters. -------------------------------------------------------------------- } var I : Integer; Y : Float; begin if ConsTerm then Y := B^[0] else Y := 0.0; for I := 1 to Nvar do Y := Y + B^[I] * X^[I]; RegFunc := Y; end; function FitModel(Method : Integer; X : PMatrix; Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; { -------------------------------------------------------------------- Multiple linear regression -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X = matrix of independent variables Y = vector of dependent variable W = vector of weights N = number of observations Output : B = estimated regression parameters V = variance-covariance matrix of parameters -------------------------------------------------------------------- } begin case Method of 0 : FitModel := MulFit(X, Y, N, Nvar, ConsTerm, B, V); 1 : FitModel := WMulFit(X, Y, W, N, Nvar, ConsTerm, B, V); end; end; procedure InitModel(CstPar : PVector); { -------------------------------------------------------------------- Initializes the global variables of the unit -------------------------------------------------------------------- CstPar^[0] = number of independent variables CstPar^[1] = 1 to include a constant term (b0) -------------------------------------------------------------------- } begin Nvar := Round(CstPar^[0]); ConsTerm := (CstPar^[1] = 1); end; end. ���������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/eigen.pas������������������������������������������������0000755�0001750�0001750�00000060372�11326443506�017702� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit EIGEN.PAS * * Version 1.8 * * (c) J. Debord, May 2001 * ********************************************************************** Procedures for computing eigenvalues and eigenvectors ********************************************************************** References: 1) Borland's Numerical Methods Toolbox : Jacobi 2) 'Numerical Recipes' by Press et al. : EigenVals, RootPol ********************************************************************** } unit Eigen; interface uses FMath, Matrices; function Jacobi(A : PMatrix; Lbound, Ubound, MaxIter : Integer; Tol : Float; V : PMatrix; Lambda : PVector) : Integer; { ---------------------------------------------------------------------- Eigenvalues and eigenvectors of a symmetric matrix by the iterative method of Jacobi ---------------------------------------------------------------------- Input parameters : A = matrix Lbound = index of first matrix element Ubound = index of last matrix element MaxIter = maximum number of iterations Tol = required precision ---------------------------------------------------------------------- Output parameters : V = matrix of eigenvectors (stored by lines) Lambda = eigenvalues in decreasing order ---------------------------------------------------------------------- Possible results : MAT_OK MAT_NON_CONV ---------------------------------------------------------------------- NB : 1. The eigenvectors are normalized, with their first component > 0 2. This procedure destroys the original matrix A ---------------------------------------------------------------------- } function EigenVals(A : PMatrix; Lbound, Ubound : Integer; Lambda_Re, Lambda_Im : PVector) : Integer; { ---------------------------------------------------------------------- Eigenvalues of a general square matrix ---------------------------------------------------------------------- Input parameters : A = matrix Lbound = index of first matrix element Ubound = index of last matrix element ---------------------------------------------------------------------- Output parameters : Lambda_Re = real part of eigenvalues Lambda_Im = imaginary part of eigenvalues ---------------------------------------------------------------------- Possible results : MAT_OK MAT_NON_CONV ---------------------------------------------------------------------- NB : This procedure destroys the original matrix A ---------------------------------------------------------------------- } function EigenVect(A : PMatrix; Lbound, Ubound : Integer; Lambda, Tol : Float; V : PVector) : Integer; { ---------------------------------------------------------------------- Computes the eigenvector associated to a real eigenvalue ---------------------------------------------------------------------- Input parameters : A = matrix Lbound = index of first matrix element Ubound = index of last matrix element Lambda = eigenvalue Tol = required precision ---------------------------------------------------------------------- Output parameters : V = eigenvector ---------------------------------------------------------------------- Possible results : MAT_OK MAT_NON_CONV ---------------------------------------------------------------------- NB : 1. The eigenvector is normalized, with its first component > 0 2. The function returns only one eigenvector, even if the eigenvalue has a multiplicity greater than 1. ---------------------------------------------------------------------- } procedure DivLargest(V : PVector; Lbound, Ubound : Integer; var Largest : Float); { ---------------------------------------------------------------------- Normalizes an eigenvector V by dividing by the element with the largest absolute value ---------------------------------------------------------------------- } function RootPol(Coef : PVector; Deg : Integer; X_Re, X_Im : PVector) : Integer; { ---------------------------------------------------------------------- Real and complex roots of a real polynomial by the method of the companion matrix ---------------------------------------------------------------------- Input parameters : Coef = coefficients of polynomial Deg = degree of polynomial ---------------------------------------------------------------------- Output parameters : X_Re = real parts of root (in increasing order) X_Im = imaginary parts of root ---------------------------------------------------------------------- Possible results : MAT_OK MAT_NON_CONV ---------------------------------------------------------------------- } implementation function Jacobi(A : PMatrix; Lbound, Ubound, MaxIter : Integer; Tol : Float; V : PMatrix; Lambda : PVector) : Integer; var SinTheta, CosTheta, TanTheta, Tan2Theta : Float; CosSqr, SinSqr, SinCos, SumSqrDiag : Float; AII, AJJ, AIJ, AIK, AJK, VIK, VJK, D : Float; I, J, K, Iter : Integer; Done : Boolean; begin Iter := 0; for I := Lbound to Ubound do for J := Lbound to Ubound do if I = J then V^[I]^[J] := 1.0 else V^[I]^[J] := 0.0; repeat Iter := Succ(Iter); SumSqrDiag := 0.0; for I := Lbound to Ubound do SumSqrDiag := SumSqrDiag + Sqr(A^[I]^[I]); Done := True; for I := Lbound to Pred(Ubound) do for J := Succ(I) to Ubound do if Abs(A^[I]^[J]) > Tol * SumSqrDiag then begin Done := False; { Calculate rotation } D := A^[I]^[I] - A^[J]^[J]; if Abs(D) > MACHEP then begin Tan2Theta := D / (2.0 * A^[I]^[J]); TanTheta := - Tan2Theta + Sgn(Tan2Theta) * Sqrt(1.0 + Sqr(Tan2Theta)); CosTheta := 1.0 / Sqrt(1.0 + Sqr(TanTheta)); SinTheta := CosTheta * TanTheta; end else begin CosTheta := SQRT2DIV2; { Sqrt(2)/2 } SinTheta := Sgn(A^[I]^[J]) * SQRT2DIV2; end; { Rotate matrix } CosSqr := Sqr(CosTheta); SinSqr := Sqr(SinTheta); SinCos := SinTheta * CosTheta; AII := A^[I]^[I] * CosSqr + 2.0 * A^[I]^[J] * SinCos + A^[J]^[J] * SinSqr; AJJ := A^[I]^[I] * SinSqr - 2.0 * A^[I]^[J] * SinCos + A^[J]^[J] * CosSqr; AIJ := (A^[J]^[J] - A^[I]^[I]) * SinCos + A^[I]^[J] * (CosSqr - SinSqr); for K := Lbound to Ubound do if not(K in [I, J]) then begin AIK := A^[I]^[K] * CosTheta + A^[J]^[K] * SinTheta; AJK := - A^[I]^[K] * SinTheta + A^[J]^[K] * CosTheta; A^[I]^[K] := AIK; A^[K]^[I] := AIK; A^[J]^[K] := AJK; A^[K]^[J] := AJK; end; A^[I]^[I] := AII; A^[J]^[J] := AJJ; A^[I]^[J] := AIJ; A^[J]^[I] := AIJ; { Rotate eigenvectors } for K := Lbound to Ubound do begin VIK := CosTheta * V^[I]^[K] + SinTheta * V^[J]^[K]; VJK := - SinTheta * V^[I]^[K] + CosTheta * V^[J]^[K]; V^[I]^[K] := VIK; V^[J]^[K] := VJK; end; end; until Done or (Iter > MaxIter); { The diagonal terms of the transformed matrix are the eigenvalues } for I := Lbound to Ubound do Lambda^[I] := A^[I]^[I]; if Iter > MaxIter then begin Jacobi := MAT_NON_CONV; Exit; end; { Sort eigenvalues and eigenvectors } for I := Lbound to Pred(Ubound) do begin K := I; D := Lambda^[I]; for J := Succ(I) to Ubound do if Lambda^[J] > D then begin K := J; D := Lambda^[J]; end; FSwap(Lambda^[I], Lambda^[K]); SwapRows(I, K, V, Lbound, Ubound); end; { Make sure that the first component of each eigenvector is > 0 } for I := Lbound to Ubound do if V^[I]^[Lbound] < 0.0 then for J := Lbound to Ubound do V^[I]^[J] := - V^[I]^[J]; Jacobi := MAT_OK; end; procedure Balance(A : PMatrix; Lbound, Ubound : Integer); { Balances the matrix, i.e. reduces norm without affecting eigenvalues } const RADIX = 2; { Base used for machine computations } var I, J, Last : Integer; C, F, G, R, S, Sqrdx : Float; begin Sqrdx := Sqr(RADIX); repeat Last := 1; for I := Lbound to Ubound do begin C := 0.0; R := 0.0; for J := Lbound to Ubound do if J <> I then begin C := C + Abs(A^[J]^[I]); R := R + Abs(A^[I]^[J]); end; if (C <> 0.0) and (R <> 0.0) then begin G := R / RADIX; F := 1.0; S := C + R; while C < G do begin F := F * RADIX; C := C * Sqrdx; end; G := R * RADIX; while C > G do begin F := F / RADIX; C := C / Sqrdx; end; if (C + R) / F < 0.95 * S then begin Last := 0; G := 1.0 / F; for J := Lbound to Ubound do A^[I]^[J] := A^[I]^[J] * G; for J := Lbound to Ubound do A^[J]^[I] := A^[J]^[I] * F; end; end; end; until Last <> 0; end; procedure ElmHes(A : PMatrix; Lbound, Ubound : Integer); { Reduces the matrix to upper Hessenberg form by elimination } var I, J, M : Integer; X, Y : Float; begin for M := Succ(Lbound) to Pred(Ubound) do begin X := 0.0; I := M; for J := M to Ubound do if Abs(A^[J]^[M - 1]) > Abs(X) then begin X := A^[J]^[M - 1]; I := J; end; if I <> M then begin for J := Pred(M) to Ubound do FSwap(A^[I]^[J], A^[M]^[J]); for J := Lbound to Ubound do FSwap(A^[J]^[I], A^[J]^[M]); end; if X <> 0.0 then for I := Succ(M) to Ubound do begin Y := A^[I]^[M - 1]; if Y <> 0.0 then begin Y := Y / X; A^[I]^[M - 1] := Y; for J := M to Ubound do A^[I]^[J] := A^[I]^[J] - Y * A^[M]^[J]; for J := Lbound to Ubound do A^[J]^[M] := A^[J]^[M] + Y * A^[J]^[I]; end; end; end; for I := (Lbound + 2) to Ubound do for J := Lbound to (I - 2) do A^[I]^[J] := 0.0; end; function Hqr(A : PMatrix; Lbound, Ubound : Integer; Lambda_Re, Lambda_Im : PVector) : Integer; { Finds the eigenvalues of an upper Hessenberg matrix } label 2, 3, 4; var I, Its, J, K, L, M, N : Integer; Anorm, P, Q, R, S, T, U, V, W, X, Y, Z : Float; function Sign(A, B : Float) : Float; begin if B < 0.0 then Sign := - Abs(A) else Sign := Abs(A) end; begin Anorm := Abs(A^[1]^[1]); for I := Succ(Lbound) to Ubound do for J := I - 1 to Ubound do Anorm := Anorm + Abs(A^[I]^[J]); N := Ubound; T := 0.0; while N >= Lbound do begin Its := 0; 2: for L := N downto Succ(Lbound) do begin S := Abs(A^[L - 1]^[L - 1]) + Abs(A^[L]^[L]); if S = 0.0 then S := Anorm; if Abs(A^[L]^[L - 1]) <= MACHEP * S then goto 3 end; L := Lbound; 3: X := A^[N]^[N]; if L = N then begin Lambda_Re^[N] := X + T; Lambda_Im^[N] := 0.0; N := N - 1 end else begin Y := A^[N - 1]^[N - 1]; W := A^[N]^[N - 1] * A^[N - 1]^[N]; if L = N - 1 then begin P := 0.5 * (Y - X); Q := Sqr(P) + W; Z := Sqrt(Abs(Q)); X := X + T; if Q >= 0.0 then begin Z := P + Sign(Z, P); Lambda_Re^[N] := X + Z; Lambda_Re^[N - 1] := Lambda_Re^[N]; if Z <> 0.0 then Lambda_Re^[N] := X - W / Z; Lambda_Im^[N] := 0.0; Lambda_Im^[N - 1] := 0.0 end else begin Lambda_Re^[N] := X + P; Lambda_Re^[N - 1] := Lambda_Re^[N]; Lambda_Im^[N] := Z; Lambda_Im^[N - 1] := - Z end; N := N - 2 end else begin if Its = 30 then begin Hqr := MAT_NON_CONV; Exit; end; if (Its = 10) or (Its = 20) then begin T := T + X; for I := Lbound to N do A^[I]^[I] := A^[I]^[I] - X; S := Abs(A^[N]^[N - 1]) + Abs(A^[N - 1]^[N - 2]); X := 0.75 * S; Y := X; W := - 0.4375 * Sqr(S) end; Its := Its + 1; for M := N - 2 downto L do begin Z := A^[M]^[M]; R := X - Z; S := Y - Z; P := (R * S - W) / A^[M + 1]^[M] + A^[M]^[M + 1]; Q := A^[M + 1]^[M + 1] - Z - R - S; R := A^[M + 2]^[M + 1]; S := Abs(P) + Abs(Q) + Abs(R); P := P / S; Q := Q / S; R := R / S; if M = L then goto 4; U := Abs(A^[M]^[M - 1]) * (Abs(Q) + Abs(R)); V := Abs(P) * (Abs(A^[M - 1]^[M - 1]) + Abs(Z) + Abs(A^[M + 1]^[M + 1])); if U <= MACHEP * V then goto 4 end; 4: for I := M + 2 to N do begin A^[I]^[I - 2] := 0.0; if I <> (M + 2) then A^[I]^[I - 3] := 0.0 end; for K := M to N - 1 do begin if K <> M then begin P := A^[K]^[K - 1]; Q := A^[K + 1]^[K - 1]; R := 0.0; if K <> (N - 1) then R := A^[K + 2]^[K - 1]; X := Abs(P) + Abs(Q) + Abs(R); if X <> 0.0 then begin P := P / X; Q := Q / X; R := R / X end end; S := Sign(Sqrt(Sqr(P) + Sqr(Q) + Sqr(R)), P); if S <> 0.0 then begin if K = M then begin if L <> M then A^[K]^[K - 1] := - A^[K]^[K - 1]; end else begin A^[K]^[K - 1] := - S * X end; P := P + S; X := P / S; Y := Q / S; Z := R / S; Q := Q / P; R := R / P; for J := K to N do begin P := A^[K]^[J] + Q * A^[K + 1]^[J]; if K <> (N - 1) then begin P := P + R * A^[K + 2]^[J]; A^[K + 2]^[J] := A^[K + 2]^[J] - P * Z end; A^[K + 1]^[J] := A^[K + 1]^[J] - P * Y; A^[K]^[J] := A^[K]^[J] - P * X end; for I := L to IMin(N, K + 3) do begin P := X * A^[I]^[K] + Y * A^[I]^[K + 1]; if K <> (N - 1) then begin P := P + Z * A^[I]^[K + 2]; A^[I]^[K + 2] := A^[I]^[K + 2] - P * R end; A^[I]^[K + 1] := A^[I]^[K + 1] - P * Q; A^[I]^[K] := A^[I]^[K] - P end end end; goto 2 end end end; Hqr := MAT_OK; end; function EigenVals(A : PMatrix; Lbound, Ubound : Integer; Lambda_Re, Lambda_Im : PVector) : Integer; begin Balance(A, Lbound, Ubound); ElmHes(A, Lbound, Ubound); EigenVals := Hqr(A, Lbound, Ubound, Lambda_Re, Lambda_Im); end; procedure DivLargest(V : PVector; Lbound, Ubound : Integer; var Largest : Float); var I : Integer; begin Largest := V^[Lbound]; for I := Succ(Lbound) to Ubound do if Abs(V^[I]) > Abs(Largest) then Largest := V^[I]; for I := Lbound to Ubound do V^[I] := V^[I] / Largest; end; function EigenVect(A : PMatrix; Lbound, Ubound : Integer; Lambda, Tol : Float; V : PVector) : Integer; procedure SetMatrix(A, A1 : PMatrix; Lbound, Ubound : Integer; Lambda : Float); { Form A1 = A - Lambda * I } var I : Integer; begin CopyMatrix(A1, A, Lbound, Lbound, Ubound, Ubound); for I := Lbound to Ubound do A1^[I]^[I] := A^[I]^[I] - Lambda; end; function Solve(A : PMatrix; Lbound, Ubound, N : Integer; Tol : Float; V : PVector) : Integer; { Solve the system A*X = 0 after fixing the N-th unknown to 1 } var A1, W : PMatrix; B, S, X : PVector; ErrCode, I, I1, J, J1, Ubound1 : Integer; begin Ubound1 := Pred(Ubound); DimMatrix(A1, Ubound1, Ubound1); DimMatrix(W, Ubound1, Ubound1); DimVector(B, Ubound1); DimVector(S, Ubound1); DimVector(X, Ubound1); I1 := Pred(Lbound); for I := Lbound to Ubound do if I <> N then begin Inc(I1); J1 := 0; for J := Lbound to Ubound do if J <> N then begin Inc(J1); A1^[I1]^[J1] := A^[I]^[J]; end else B^[I1] := - A^[I]^[J]; end; ErrCode := SV_Decomp(A1, Lbound, Ubound1, Ubound1, S, W); if ErrCode = 0 then begin SV_SetZero(S, Lbound, Ubound1, Tol); SV_Solve(A1, S, W, B, Lbound, Ubound1, Ubound1, X); { Update eigenvector } I1 := 0; for I := Lbound to Ubound do if I = N then V^[I] := 1.0 else begin Inc(I1); V^[I] := X^[I1]; end; end; DelMatrix(A1, Ubound1, Ubound1); DelMatrix(W, Ubound1, Ubound1); DelVector(B, Ubound1); DelVector(S, Ubound1); DelVector(X, Ubound1); Solve := ErrCode; end; function ZeroVector(B : PVector; Lbound, Ubound : Integer; Tol : Float) : Boolean; { Check if vector B is zero } var I : Integer; Z : Boolean; begin Z := True; for I := Lbound to Ubound do Z := Z and (Abs(B^[I]) < Tol); ZeroVector := Z; end; function CheckEigenVector(A1 : PMatrix; V : PVector; Lbound, Ubound : Integer; Tol : Float) : Boolean; { Check if the equation A1 * V = 0 holds } var I, K : Integer; B : PVector; begin DimVector(B, Ubound); { Form B = A1 * V } for I := Lbound to Ubound do for K := Lbound to Ubound do B^[I] := B^[I] + A1^[I]^[K] * V^[K]; { Check if B is zero } CheckEigenVector := ZeroVector(B, Lbound, Ubound, Tol); DelVector(B, Ubound); end; procedure Normalize(V : PVector; Lbound, Ubound : Integer); { Normalize eigenvector and make sure that the first component is >= 0 } var Sum, Norm : Float; I : Integer; begin Sum := 0.0; for I := Lbound to Ubound do Sum := Sum + Sqr(V^[I]); Norm := Sqrt(Sum); for I := Lbound to Ubound do if V^[I] <> 0.0 then V^[I] := V^[I] / Norm; if V^[Lbound] < 0.0 then for I := Lbound to Ubound do if V^[I] <> 0.0 then V^[I] := - V^[I]; end; var ErrCode, I : Integer; A1 : PMatrix; begin DimMatrix(A1, Ubound, Ubound); { Form A1 = A - Lambda * I } SetMatrix(A, A1, Lbound, Ubound, Lambda); { Try to solve the system A1*V=0 by eliminating 1 equation } I := Lbound; repeat if (Solve(A1, Lbound, Ubound, I, Tol, V) = 0) and CheckEigenVector(A1, V, Lbound, Ubound, Tol) then ErrCode := 0 else ErrCode := - 1; Inc(I); until (ErrCode = 0) or (I > Ubound); if ErrCode = 0 then begin Normalize(V, Lbound, Ubound); EigenVect := MAT_OK; end else EigenVect := MAT_NON_CONV; DelMatrix(A1, Ubound, Ubound); end; function RootPol(Coef : PVector; Deg : Integer; X_Re, X_Im : PVector) : Integer; var A : PMatrix; { Companion matrix } N : Integer; { Size of matrix } I, J, K : Integer; { Loop variables } ErrCode : Integer; { Error code } Temp : Float; begin N := Pred(Deg); DimMatrix(A, N, N); { Set up the companion matrix (to save space, begin at index 0) } for J := 0 to N do A^[0]^[J] := - Coef^[Deg - J - 1] / Coef^[Deg]; for J := 0 to Pred(N) do A^[J + 1]^[J] := 1.0; { The roots of the polynomial are the eigenvalues of the companion matrix } Balance(A, 0, N); ErrCode := Hqr(A, 0, N, X_Re, X_Im); if ErrCode = MAT_OK then begin { Sort roots in increasing order of real parts } for I := 0 to N - 1 do begin K := I; Temp := X_Re^[I]; for J := Succ(I) to N do if X_Re^[J] < Temp then begin K := J; Temp := X_Re^[J]; end; FSwap(X_Re^[I], X_Re^[K]); FSwap(X_Im^[I], X_Im^[K]); end; { Transfer roots from 0..(Deg - 1) to 1..Deg } for J := N downto 0 do begin X_Re^[J + 1] := X_Re^[J]; X_Im^[J + 1] := X_Im^[J]; end; end; DelMatrix(A, N, N); RootPol := ErrCode; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/math387.inc����������������������������������������������0000755�0001750�0001750�00000027663�07140500074�017773� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * MATH387.INC * ********************************************************************** Mathematical functions for TPMATH (Assembler version for 387/486/Pentium with BP7 and Delphi1) ********************************************************************** } (* Bibliotheque mathematique pour utilisation du coprocesseur flottant JD GAYRARD Sept. 95 ---------------------------------------------------------------------- Unite d'origine : MATH387.PAS, disponible dans MATHLIB2.ZIP (http://wcarchive.cdrom.com/pub/delphi_www/) Convertie en fichier Include par J. DEBORD, Juin 97 avec ajout des fonctions fexp2 et flog2 ---------------------------------------------------------------------- la bibliotheque est batie partir des fonctions du coprocesseur du type 386, elle fournit les fonctions suivantes: fsin, fcos, ftan, farctan, farctan2, farcsin, farccos, fmod, mod_2PI, ften_to, fy_to_x, fexp, fexp2, fln, flog, flog2... Aucune verification du domaine de definition des fonctions n'est faite, pas plus qu'un controle de la validite des operandes. Il est conseille d'utiliser cette bibliotheque pour les types single et double exclusivement *) { table opcode du 387 non comprise par turbo pascal V7 } { FSIN : D9 FE FCOS : D9 FF FSINCOS : D9 FB FPREM1 : D9 F5 } (* use only with 80387, 80486 or pentium for type single, double and extended, no check of definition domain of the function or range (FPU limitation). The f prefix avoids function redefinition of system runtime library *) function fsin(x : Float): Float; assembler; {if x < pi.2^62, then C2 is set to 0 and ST = sin(x) else C2 is set to 1 and ST = x } {no check range validity is performed in this function} asm FLD x { load x } DB $D9, $FE { opcode for FSIN } end; function fcos(x : Float): Float; assembler; { if x < pi.2^62, then C2 is set to 0 and ST = sin(x) else C2 is set to 1 and ST = x } {no range validity check is performed in this function} asm FLD x { load angle } DB $D9, $FF { opcode for FCOS } end; (* procedure dsincos(x : Float; var sinus, cosinus : double); assembler; { retourne sinus et cosinus(x), utilisable uniquement avec 80387, 80468 et pentium et type double } asm { ST(0) ST(1) } FLD x { x - } DB $D9, $FB { cos(x) sin(x) } LES DI,cosinus { } FSTP ES:QWORD PTR [DI] { sin(x) - } LES DI,sinus { } FSTP ES:QWORD PTR [DI] { - - } end; procedure ssincos(x : Float; var sinus, cosinus : single); assembler; { retourne sinus et cosinus(x), utilisable uniquement avec 80387, 80468 et pentium et type single } asm { ST(0) ST(1) } FLD x { x - } DB $D9, $FB { cos(x) sin(x) } LES DI,cosinus { } FSTP ES:DWORD PTR [DI] { sin(x) - } LES DI,sinus { } FSTP ES:DWORD PTR [DI] { - - } end; procedure fsincos(x : Float; var sinus, cosinus : Float); { retourne sinus et cosinus(x), utilisable uniquement avec 80387, 80486 et pentium } var lcos, lsin : Float; begin asm { ST(0) ST(1) } FLD x { x - } DB $D9, $FB { cos(x) sin(x) } FSTP lcos { sin(x) - } FSTP lsin { - - } end; cosinus := lcos; sinus := lsin end; *) function ftan(x : Float): Float; assembler; { if x < pi.2^62, then C2 is set to 0 and ST = 1 and ST(1) = tan(x) else C2 is set to 1 and ST = x } {no range validity check is performed in this function} asm { ST(0) ST(1) } FLD x { x - } FPTAN { 1 tan(x) } FSTP ST(0) { tan(x) - } end; function farcsin(x : Float): Float; assembler; (* retourne l'arcsin de x *) { methode : ________ arcsin(x) = arctan( x / V 1 - x.x ) } {no range validity check is performed in this function |x| > 1 } asm { ST(0) ST(1) ST(2) } FLD X { x - - } FLD ST(0) { x x - } FMUL ST(0), ST { x.x x - } FLD1 { 1 x.x x } FSUBRP ST(1), ST { 1 - x x - } FSQRT { sqrt(1-x) x - } FPATAN { arcsin(x) - - } end; function farccos(x : Float): Float; assembler; { retourne arccos(x) methode : ________ arcsin(x) = arctan( V 1 - x.x / x ) } { pas de controle de domaine de definition |x| > 1 } asm { ST(0) ST(1) ST(2) } FLD X { x - - } FLD ST(0) { x x - } FMUL ST(0), ST { x.x x - } FLD1 { 1 x.x x } FSUBRP ST(1), ST { 1 - x x - } FSQRT { sqrt(1-x) x - } FXCH { x z - } FPATAN { arccos(x) - - } end; function farctan(x : Float): Float; assembler; asm { ST(0) ST(1) } FLD x { x - } FLD1 { 1 x } FPATAN { atan(x/1) - } end; function farctan2(y, x : Float): Float; assembler; { retourne arctan (y / x) } asm { ST(0) ST(1) } FLD y { y - } FLD x { x y } FPATAN { atan(y/x) - } end; (* function fmod(x, y : Float): Float; assembler; { retourne x mod y } asm { ST(0) ST(1) } FLD Y { y - } FLD X { x y } @repeat_mod: FPREM { x mod y y } FSTSW AX SAHF JP @repeat_mod FSTP ST(1) { x mod y - } end; function fmod_2PI( x : Float): Float; assembler; { retourne x mod 2.pi } asm { ST(0) ST(1) } FLDPI { pi - } FADD ST, ST { 2.pi - } FLD x { x 2.pi } @unit_circle: FPREM { x mod 2pi 2pi } FSTSW AX SAHF JP @unit_circle FSTP ST(1) { x mod 2pi - } end; *) function fln(x : Float): Float; assembler; { retourne le logarithme naturel de x, utilise la methode loge(x) = loge(2).log2(x) } { pas de verification du domaine de definition (x < 0) } asm { ST(0) ST(1) } FLDLN2 { ln(2) - } FLD X { x ln(2) } FYL2X { ln(2).log2(x) - } end; function flog2(x : Float): Float; assembler; { retourne le logarithme de base 2 de x } { pas de verification du domaine de definition (x < 0) } asm { ST(0) ST(1) } FLD1 { 1 - } FLD X { x 1 } FYL2X { log2(x) - } end; function flog10(x : Float): Float; assembler; { retourne le logarithme base 10 de x, utilise la methode log10(x) = log10(2).log2(x) } { pas de verification du domaine de definition (x < 0) } asm { ST(0) ST(1) } FLDLG2 { log10(2) - } FLD X { x log10(2) } FYL2X {log2(x).log10(2) - } end; function fexp(x : Float): Float; assembler; { retourne e^x, par la methode e^x = 2^(x.log2(e)) } { 2^z = 2^f.2^i with f = frac(z) and i = int(z) } { 2^f is computed with F2XM1, 2^i with FSCALE } const round_down : word = $177F; var control_ww : word; asm { ST(0) ST(1) ST(2) } FLD X { x - - } FLDL2E { log2(e) x - } FMULP ST(1), ST { x.log2(e) - - } FSTCW control_ww FLDCW round_down FLD ST(0) { z z - } FRNDINT { int(z) z - } FLDCW control_ww FXCH { z i - } FSUB ST, ST(1) { f i - } F2XM1 { 2^f-1 i - } FLD1 { 1 2^f-1 i } FADDP ST(1), ST { 2^f i - } FSCALE { 2^f.2^i i - } FSTP ST(1) { e^x - - } end; function fexp2(x : Float): Float; assembler; { retourne 2^x par la methode 2^z = 2^f.2^i } { with f = frac(z) and i = int(z) } { 2^f is computed with F2XM1, 2^i with FSCALE } const round_down : word = $177F; var control_ww : word; asm { ST(0) ST(1) ST(2) } FLD X { x - - } FSTCW control_ww FLDCW round_down FLD ST(0) { x x - } FRNDINT { int(x) x - } FLDCW control_ww FXCH { x i - } FSUB ST, ST(1) { f i - } F2XM1 { 2^f-1 i - } FLD1 { 1 2^f-1 i } FADDP ST(1), ST { 2^f i - } FSCALE { 2^f.2^i i - } FSTP ST(1) { 2^x - - } end; function fexp10(x : Float): Float; assembler; { retourne 10^x, par la methode 10^x = 2^(x.log2(10)) { 2^z = 2^f.2^i with f = frac(z) and i = int(z) { 2^f is computed with F2XM1, 2^i with FSCALE } const round_down : word = $177F; var control_ww : word; asm { ST(0) ST(1) ST(2) } FLD X { x - - } FLDL2T { log2(10) x - } FMULP ST(1), ST { x.log2(10) - - } FSTCW control_ww FLDCW round_down FLD ST(0) { z z - } FRNDINT { int(z) z - } FLDCW control_ww FXCH { z i - } FSUB ST, ST(1) { f i - } F2XM1 { 2^f-1 i - } FLD1 { 1 2^f-1 i } FADDP ST(1), ST { 2^f i - } FSCALE { 2^f.2^i i - } FSTP ST(1) { 10^x - - } end; (* function fpower(y, x : Float): Float; assembler; { retourne y^x, par la methode y^x = 2^(y.log2(y)) {no range validity check is performed in this function (y > 0) } { 2^z = 2^f.2^i with f = frac(z) and i = int(z) { 2^f is computed with F2XM1, 2^i with FSCALE } const round_down : word = $177F; var control_ww : word; asm { ST(0) ST(1) ST(2) } FLD Y { y - - } FLD X { x y - } FYL2X { x.log2(y) - - } FSTCW control_ww FLDCW round_down FLD ST(0) { z z - } FRNDINT { int(z) z - } FLDCW control_ww FXCH { z i - } FSUB ST, ST(1) { f i - } F2XM1 { 2^f-1 i - } FLD1 { 1 2^f-1 i } FADDP ST(1), ST { 2^f i - } FSCALE { 2^f.2^i i - } FSTP ST(1) { y^x - - } end; function module(x, y : Float): Float; assembler; { retourne le module du complexe (x,y) } asm { ST(0) ST(1) } FLD Y { y - } FMUL ST(0), ST { y.y - } FLD X { x y.y } FMUL ST(0), ST { x.x y.y } FADDP ST(1), ST { d.d - } FSQRT { d - } end; *) �����������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/plot.inc�������������������������������������������������0000755�0001750�0001750�00000005236�07275617620�017565� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * PLOT.INC * ********************************************************************** Variables and routines common to PLOT.PAS and WINPLOT.PAS ********************************************************************** } var XminPixel, YminPixel : Integer; { Pixel coord. of upper left corner } XmaxPixel, YmaxPixel : Integer; { Pixel coord. of lower right corner } FactX, FactY : Float; { Scaling factors } function Xpixel(X : Float) : Integer; var P : Float; begin P := FactX * (X - XAxis.Min); if Abs(P) > 30000 then Xpixel := 30000 else Xpixel := Round(P) + XminPixel; end; function Ypixel(Y : Float) : Integer; var P : Float; begin P := FactY * (YAxis.Max - Y); if Abs(P) > 30000 then Ypixel := 30000 else Ypixel := Round(P) + YminPixel; end; function Xuser(X : Integer) : Float; begin Xuser := XAxis.Min + (X - XminPixel) / FactX; end; function Yuser(Y : Integer) : Float; begin Yuser := YAxis.Max - (Y - YminPixel) / FactY; end; procedure Interval(X1, X2 : Float; MinDiv, MaxDiv : Integer; var Min, Max, Step : Float); var H, R, K : Float; begin if X1 >= X2 then Exit; H := X2 - X1; R := Int(Log10(H)); if H < 1.0 then R := R - 1.0; Step := Exp10(R); repeat K := Int(H / Step); if K < MinDiv then Step := 0.5 * Step; if K > MaxDiv then Step := 2.0 * Step; until (K >= MinDiv) and (K <= MaxDiv); Min := Step * Int(X1 / Step); Max := Step * Int(X2 / Step); while Min > X1 do Min := Min - Step; while Max < X2 do Max := Max + Step; end; procedure AutoScale(Z : PVector; Lbound, Ubound : Integer; var Axis : TAxis); var I : Integer; Zmin, Zmax, Z1, Z2 : Float; begin if Axis.Scale = LIN_SCALE then Interval(Min(Z, Lbound, Ubound), Max(Z, Lbound, Ubound), 2, 6, Axis.Min, Axis.Max, Axis.Step) else begin Zmin := MAXNUM; Zmax := 0.0; for I := Lbound to Ubound do if Z^[I] > 0.0 then if Z^[I] < Zmin then Zmin := Z^[I] else if Z^[I] > Zmax then Zmax := Z^[I]; Z1 := Int(Log10(Zmin)); Z2 := Int(Log10(Zmax)); if Zmin < 1.0 then Z1 := Z1 - 1.0; if Zmax > 1.0 then Z2 := Z2 + 1.0; Axis.Min := Z1; Axis.Max := Z2; Axis.Step := 1.0; end; end; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/fitiexpo.pas���������������������������������������������0000755�0001750�0001750�00000011251�11326443506�020432� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITIEXPO.PAS * * Version 1.2 * * (c) J. Debord, August 2000 * ********************************************************************** This unit fits the increasing exponential : y = A.[1 - exp(-k.x)] ********************************************************************** } unit FitIExpo; {$F+} interface uses FMath, Matrices, Stat, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X : Float; B, D : PVector); function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; implementation function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } begin FuncName := 'y = A[1 - exp(-k.x)]'; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 1; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'A'; 1 : ParamName := 'k'; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = A B^[1] = k -------------------------------------------------------------------- } begin RegFunc := B^[0] * (1.0 - Expo(- B^[1] * X)); end; procedure DerivProc(X : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point X with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter. -------------------------------------------------------------------- } var E : Float; begin E := Expo(- B^[1] * X); { exp(-k.x) } D^[0] := 1.0 - E; { dy/dA = 1 - exp(-k.x) } D^[1] := B^[0] * X * E; { dy/dk = A.x.exp(-k.x) } end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of the increasing exponential by linear regression: Ln(1 - y/A) = -k.x -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- } var Y1 : PVector; { Transformed ordinates } W1 : PVector; { Weights } A : PVector; { Linear regression parameters } V : PMatrix; { Variance-covariance matrix } K : Integer; { Loop variable } ErrCode : Integer; { Error code } begin DimVector(Y1, N); DimVector(W1, N); DimVector(A, 1); DimMatrix(V, 1, 1); { Estimation of A } B^[0] := 1.1 * Max(Y, 1, N); for K := 1 to N do begin Y1^[K] := Log(1.0 - Y^[K] / B^[0]); W1^[K] := Sqr(Y^[K] - B^[0]); if Method = 1 then W1^[K] := W1^[K] * W^[K]; end; ErrCode := WLinFit(X, Y1, W1, N, A, V); if ErrCode = MAT_OK then B^[1] := - A^[1]; FitModel := ErrCode; DelVector(Y1, N); DelVector(W1, N); DelVector(A, 1); DelMatrix(V, 1, 1); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/optim.pas������������������������������������������������0000755�0001750�0001750�00000100642�11326443506�017736� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit OPTIM.PAS * * Version 2.1 * * (c) J. Debord, June 2001 * ********************************************************************** This unit implements the following methods for function minimization: * Golden search for a function of one variable * Simplex, Marquardt, BFGS for a function of several variables ********************************************************************** References: 1) 'Numerical Recipes' by Press et al. 2) D. W. MARQUARDT, J. Soc. Indust. Appl. Math., 1963, 11, 431-441 3) J. A. NELDER & R. MEAD, Comput. J., 1964, 7, 308-313 4) R. O'NEILL, Appl. Statist., 1971, 20, 338-345 ********************************************************************** } unit Optim; interface uses FMath, Matrices; { ********************************************************************** Error codes ********************************************************************** } const OPT_OK = 0; { No error } OPT_SING = - 1; { Singular hessian matrix } OPT_BIG_LAMBDA = - 2; { Too high Marquardt's parameter } OPT_NON_CONV = - 3; { Non-convergence } { ********************************************************************** Functional types ********************************************************************** } type { Function of several variables } TFuncNVar = function(X : PVector) : Float; { Procedure to compute gradient vector } TGradient = procedure(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; G : PVector); { Procedure to compute gradient vector and hessian matrix } THessGrad = procedure(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; G : PVector; H : PMatrix); { ********************************************************************** Log file ********************************************************************** } const WriteLogFile : Boolean = False; { Write iteration info to log file } LogFileName : String = 'optim.log'; { Name of log file } { ********************************************************************** Minimization routines ********************************************************************** } function GoldSearch(Func : TFunc; A, B : Float; MaxIter : Integer; Tol : Float; var Xmin, Ymin : Float) : Integer; { ---------------------------------------------------------------------- Performs a golden search for the minimum of function Func ---------------------------------------------------------------------- Input parameters : Func = objective function A, B = two points near the minimum MaxIter = maximum number of iterations Tol = required precision (should not be less than the square root of the machine precision) ---------------------------------------------------------------------- Output parameters : Xmin, Ymin = coordinates of minimum ---------------------------------------------------------------------- Possible results : OPT_OK OPT_NON_CONV ---------------------------------------------------------------------- } function LinMin(Func : TFuncNVar; X, DeltaX : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float) : Integer; { ---------------------------------------------------------------------- Minimizes function Func from point X in the direction specified by DeltaX ---------------------------------------------------------------------- Input parameters : Func = objective function X = initial minimum coordinates DeltaX = direction in which minimum is searched Lbound, Ubound = indices of first and last variables MaxIter = maximum number of iterations Tol = required precision ---------------------------------------------------------------------- Output parameters : X = refined minimum coordinates F_min = function value at minimum ---------------------------------------------------------------------- Possible results : OPT_OK OPT_NON_CONV ---------------------------------------------------------------------- } function Simplex(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float) : Integer; { ---------------------------------------------------------------------- Minimization of a function of several variables by the simplex method of Nelder and Mead ---------------------------------------------------------------------- Input parameters : Func = objective function X = initial minimum coordinates Lbound, Ubound = indices of first and last variables MaxIter = maximum number of iterations Tol = required precision ---------------------------------------------------------------------- Output parameters : X = refined minimum coordinates F_min = function value at minimum ---------------------------------------------------------------------- Possible results : OPT_OK OPT_NON_CONV ---------------------------------------------------------------------- } procedure NumGradient(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; G : PVector); { ---------------------------------------------------------------------- Computes the gradient vector of a function of several variables by numerical differentiation ---------------------------------------------------------------------- Input parameters : Func = function of several variables X = vector of variables Lbound, Ubound = indices of first and last variables ---------------------------------------------------------------------- Output parameter : G = gradient vector ---------------------------------------------------------------------- } procedure NumHessGrad(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; G : PVector; H : PMatrix); { ---------------------------------------------------------------------- Computes gradient vector & hessian matrix by numerical differentiation ---------------------------------------------------------------------- Input parameters : as in NumGradient ---------------------------------------------------------------------- Output parameters : G = gradient vector H = hessian matrix ---------------------------------------------------------------------- } function Marquardt(Func : TFuncNVar; HessGrad : THessGrad; X : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; H_inv : PMatrix) : Integer; { ---------------------------------------------------------------------- Minimization of a function of several variables by Marquardt's method ---------------------------------------------------------------------- Input parameters : Func = objective function HessGrad = procedure to compute gradient & hessian X = initial minimum coordinates Lbound, Ubound = indices of first and last variables MaxIter = maximum number of iterations Tol = required precision ---------------------------------------------------------------------- Output parameters : X = refined minimum coordinates F_min = function value at minimum H_inv = inverse hessian matrix ---------------------------------------------------------------------- Possible results : OPT_OK OPT_SING OPT_BIG_LAMBDA OPT_NON_CONV ---------------------------------------------------------------------- } function BFGS(Func : TFuncNVar; Gradient : TGradient; X : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; H_inv : PMatrix) : Integer; { ---------------------------------------------------------------------- Minimization of a function of several variables by the Broyden-Fletcher-Goldfarb-Shanno method ---------------------------------------------------------------------- Parameters : Gradient = procedure to compute gradient vector Other parameters as in Marquardt ---------------------------------------------------------------------- Possible results : OPT_OK OPT_NON_CONV ---------------------------------------------------------------------- } implementation var Eps : Float; { Fractional increment for numer. derivation } X1 : PVector; { Initial point for line minimization } DeltaX1 : PVector; { Direction for line minimization } Lbound1, Ubound1 : Integer; { Bounds of X1 and DeltaX1 } LinObjFunc : TFuncNVar; { Objective function for line minimization } LogFile : Text; { Stores the result of each minimization step } procedure MinBrack(Func : TFunc; var A, B, C, Fa, Fb, Fc : Float); { ---------------------------------------------------------------------- Given two points (A, B) this procedure finds a triplet (A, B, C) such that: 1) A < B < C 2) A, B, C are within the golden ratio 3) Func(B) < Func(A) and Func(B) < Func(C). The corresponding function values are returned in Fa, Fb, Fc ---------------------------------------------------------------------- } begin if A > B then FSwap(A, B); Fa := Func(A); Fb := Func(B); if Fb > Fa then begin FSwap(A, B); FSwap(Fa, Fb); end; C := B + GOLD * (B - A); Fc := Func(C); while Fc < Fb do begin A := B; B := C; Fa := Fb; Fb := Fc; C := B + GOLD * (B - A); Fc := Func(C); end; if A > C then begin FSwap(A, C); FSwap(Fa, Fc); end; end; function GoldSearch(Func : TFunc; A, B : Float; MaxIter : Integer; Tol : Float; var Xmin, Ymin : Float) : Integer; var C, Fa, Fb, Fc, F1, F2, MinTol, X0, X1, X2, X3 : Float; Iter : Integer; begin MinTol := Sqrt(MACHEP); if Tol < MinTol then Tol := MinTol; MinBrack(Func, A, B, C, Fa, Fb, Fc); X0 := A; X3 := C; if (C - B) > (B - A) then begin X1 := B; X2 := B + CGOLD * (C - B); F1 := Fb; F2 := Func(X2); end else begin X1 := B - CGOLD * (B - A); X2 := B; F1 := Func(X1); F2 := Fb; end; Iter := 0; while (Iter <= MaxIter) and (Abs(X3 - X0) > Tol * (Abs(X1) + Abs(X2))) do if F2 < F1 then begin X0 := X1; X1 := X2; F1 := F2; X2 := X1 + CGOLD * (X3 - X1); F2 := Func(X2); Inc(Iter); end else begin X3 := X2; X2 := X1; F2 := F1; X1 := X2 - CGOLD * (X2 - X0); F1 := Func(X1); Inc(Iter); end; if F1 < F2 then begin Xmin := X1; Ymin := F1; end else begin Xmin := X2; Ymin := F2; end; if Iter > MaxIter then GoldSearch := OPT_NON_CONV else GoldSearch := OPT_OK; end; procedure CreateLogFile; begin Assign(LogFile, LogFileName); Rewrite(LogFile); end; function Simplex(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float) : Integer; const STEP = 1.50; { Step used to construct the initial simplex } var P : PMatrix; { Simplex coordinates } F : PVector; { Function values } Pbar : PVector; { Centroid coordinates } Pstar, P2star : PVector; { New vertices } Ystar, Y2star : Float; { New function values } F0 : Float; { Function value at minimum } N : Integer; { Number of parameters } M : Integer; { Index of last vertex } L, H : Integer; { Vertices with lowest & highest F values } I, J : Integer; { Loop variables } Iter : Integer; { Iteration count } Corr, MaxCorr : Float; { Corrections } Sum : Float; Flag : Boolean; procedure UpdateSimplex(Y : Float; Q : PVector); { Update "worst" vertex and function value } begin F^[H] := Y; CopyVector(P^[H], Q, Lbound, Ubound); end; begin if WriteLogFile then begin CreateLogFile; WriteLn(LogFile, 'Simplex'); WriteLn(LogFile, 'Iter F'); end; N := Ubound - Lbound + 1; M := Succ(Ubound); DimMatrix(P, M, Ubound); DimVector(F, M); DimVector(Pbar, Ubound); DimVector(Pstar, Ubound); DimVector(P2star, Ubound); Iter := 1; F0 := MAXNUM; { Construct initial simplex } for I := Lbound to M do CopyVector(P^[I], X, Lbound, Ubound); for I := Lbound to Ubound do P^[I]^[I] := P^[I]^[I] * STEP; { Evaluate function at each vertex } for I := Lbound to M do F^[I] := Func(P^[I]); repeat { Find vertices (L,H) having the lowest and highest function values, i.e. "best" and "worst" vertices } L := Lbound; H := Lbound; for I := Succ(Lbound) to M do if F^[I] < F^[L] then L := I else if F^[I] > F^[H] then H := I; if F^[L] < F0 then F0 := F^[L]; if WriteLogFile then WriteLn(LogFile, Iter:4, ' ', F0:12); { Find centroid of points other than P(H) } for J := Lbound to Ubound do begin Sum := 0.0; for I := Lbound to M do if I <> H then Sum := Sum + P^[I]^[J]; Pbar^[J] := Sum / N; end; { Reflect worst vertex through centroid } for J := Lbound to Ubound do Pstar^[J] := 2.0 * Pbar^[J] - P^[H]^[J]; Ystar := Func(Pstar); { If reflection successful, try extension } if Ystar < F^[L] then begin for J := Lbound to Ubound do P2star^[J] := 3.0 * Pstar^[J] - 2.0 * Pbar^[J]; Y2star := Func(P2star); { Retain extension or contraction } if Y2star < F^[L] then UpdateSimplex(Y2star, P2star) else UpdateSimplex(Ystar, Pstar); end else begin I := Lbound; Flag := False; repeat if (I <> H) and (F^[I] > Ystar) then Flag := True; Inc(I); until Flag or (I > M); if Flag then UpdateSimplex(Ystar, Pstar) else begin { Contraction on the reflection side of the centroid } if Ystar <= F^[H] then UpdateSimplex(Ystar, Pstar); { Contraction on the opposite side of the centroid } for J := Lbound to Ubound do P2star^[J] := 0.5 * (P^[H]^[J] + Pbar^[J]); Y2star := Func(P2star); if Y2star <= F^[H] then UpdateSimplex(Y2star, P2star) else { Contract whole simplex } for I := Lbound to M do for J := Lbound to Ubound do P^[I]^[J] := 0.5 * (P^[I]^[J] + P^[L]^[J]); end; end; { Test convergence } MaxCorr := 0.0; for J := Lbound to Ubound do begin Corr := Abs(P^[H]^[J] - P^[L]^[J]); if Corr > MaxCorr then MaxCorr := Corr; end; Inc(Iter); until (MaxCorr < Tol) or (Iter > MaxIter); CopyVector(X, P^[L], Lbound, Ubound); F_min := F^[L]; DelMatrix(P, M, Ubound); DelVector(F, M); DelVector(Pbar, Ubound); DelVector(Pstar, Ubound); DelVector(P2star, Ubound); if WriteLogFile then Close(LogFile); if Iter > MaxIter then Simplex := OPT_NON_CONV else Simplex := OPT_OK; end; {$F+} function F1dim(R : Float) : Float; { ---------------------------------------------------------------------- Function used by LinMin to find the minimum of the objective function LinObjFunc in the direction specified by the global variables X1 and DeltaX1. R is the step in this direction. ---------------------------------------------------------------------- } const Xt : PVector = nil; var I : Integer; begin if Xt = nil then DimVector(Xt, Ubound1); for I := Lbound1 to Ubound1 do Xt^[I] := X1^[I] + R * DeltaX1^[I]; F1dim := LinObjFunc(Xt); end; {$F-} function LinMin(Func : TFuncNVar; X, DeltaX : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float) : Integer; var I, ErrCode : Integer; R : Float; begin { Redimension global vectors } DelVector(X1, Ubound1); DelVector(DeltaX1, Ubound1); DimVector(X1, Ubound); DimVector(DeltaX1, Ubound); Lbound1 := Lbound; Ubound1 := Ubound; { Initialize global variables } LinObjFunc := Func; for I := Lbound to Ubound do begin X1^[I] := X^[I]; DeltaX1^[I] := DeltaX^[I] end; { Perform golden search } ErrCode := GoldSearch({$IFDEF FPK}@{$ENDIF}F1dim, 0.0, 1.0, MaxIter, Tol, R, F_min); { Update variables } if ErrCode = OPT_OK then for I := Lbound to Ubound do X^[I] := X^[I] + R * DeltaX^[I]; LinMin := ErrCode; end; {$F+} procedure NumGradient(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; G : PVector); var Temp, Delta, Fplus, Fminus : Float; I : Integer; begin for I := Lbound to Ubound do begin Temp := X^[I]; if Temp <> 0.0 then Delta := Eps * Abs(Temp) else Delta := Eps; X^[I] := Temp - Delta; Fminus := Func(X); X^[I] := Temp + Delta; Fplus := Func(X); G^[I] := (Fplus - Fminus) / (2.0 * Delta); X^[I] := Temp; end; end; {$F-} {$F+} procedure NumHessGrad(Func : TFuncNVar; X : PVector; Lbound, Ubound : Integer; G : PVector; H : PMatrix); var Delta, Xminus, Xplus, Fminus, Fplus : PVector; Temp1, Temp2, F, F2plus : Float; I, J : Integer; begin DimVector(Delta, Ubound); { Increments } DimVector(Xminus, Ubound); { X - Delta } DimVector(Xplus, Ubound); { X + Delta } DimVector(Fminus, Ubound); { F(X - Delta) } DimVector(Fplus, Ubound); { F(X + Delta) } F := Func(X); for I := Lbound to Ubound do begin if X^[I] <> 0.0 then Delta^[I] := Eps * Abs(X^[I]) else Delta^[I] := Eps; Xplus^[I] := X^[I] + Delta^[I]; Xminus^[I] := X^[I] - Delta^[I]; end; for I := Lbound to Ubound do begin Temp1 := X^[I]; X^[I] := Xminus^[I]; Fminus^[I] := Func(X); X^[I] := Xplus^[I]; Fplus^[I] := Func(X); X^[I] := Temp1; end; for I := Lbound to Ubound do begin G^[I] := (Fplus^[I] - Fminus^[I]) / (2.0 * Delta^[I]); H^[I]^[I] := (Fplus^[I] + Fminus^[I] - 2.0 * F) / Sqr(Delta^[I]); end; for I := Lbound to Pred(Ubound) do begin Temp1 := X^[I]; X^[I] := Xplus^[I]; for J := Succ(I) to Ubound do begin Temp2 := X^[J]; X^[J] := Xplus^[J]; F2plus := Func(X); H^[I]^[J] := (F2plus - Fplus^[I] - Fplus^[J] + F) / (Delta^[I] * Delta^[J]); H^[J]^[I] := H^[I]^[J]; X^[J] := Temp2; end; X^[I] := Temp1; end; DelVector(Delta, Ubound); DelVector(Xminus, Ubound); DelVector(Xplus, Ubound); DelVector(Fminus, Ubound); DelVector(Fplus, Ubound); end; {$F-} function ParamConv(OldX, X : PVector; Lbound, Ubound : Integer; Tol : Float) : Boolean; { ---------------------------------------------------------------------- Check for convergence on parameters ---------------------------------------------------------------------- } var I : Integer; Conv : Boolean; begin I := Lbound; Conv := True; repeat Conv := Conv and (Abs(X^[I] - OldX^[I]) < FMax(Tol, Tol * Abs(OldX^[I]))); Inc(I); until (Conv = False) or (I > Ubound); ParamConv := Conv; end; function Marquardt(Func : TFuncNVar; HessGrad : THessGrad; X : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; H_inv : PMatrix) : Integer; const LAMBDA0 = 1.0E-2; { Initial lambda value } LAMBDAMAX = 1.0E+3; { Highest lambda value } FTOL = 1.0E-10; { Tolerance on function decrease } var Lambda, Lambda1 : Float; { Marquardt's lambda } I : Integer; { Loop variable } OldX : PVector; { Old parameters } G : PVector; { Gradient vector } H : PMatrix; { Hessian matrix } A : PMatrix; { Modified Hessian matrix } DeltaX : PVector; { New search direction } F1 : Float; { New minimum } Lambda_Ok : Boolean; { Successful Lambda decrease } Conv : Boolean; { Convergence reached } Done : Boolean; { Iterations done } Iter : Integer; { Iteration count } ErrCode : Integer; { Error code } begin if WriteLogFile then begin CreateLogFile; WriteLn(LogFile, 'Marquardt'); WriteLn(LogFile, 'Iter F Lambda'); end; Lambda := LAMBDA0; ErrCode := OPT_OK; DimVector(OldX, Ubound); DimVector(G, Ubound); DimMatrix(H, Ubound, Ubound); DimMatrix(A, Ubound, Ubound); DimVector(DeltaX, Ubound); F_min := Func(X); { Initial function value } LinObjFunc := Func; { Function for line minimization } Iter := 1; Conv := False; Done := False; repeat if WriteLogFile then WriteLn(LogFile, Iter:4, ' ', F_min:12, ' ', Lambda:12); { Save current parameters } CopyVector(OldX, X, Lbound, Ubound); { Compute Gradient and Hessian } HessGrad(Func, X, Lbound, Ubound, G, H); CopyMatrix(A, H, Lbound, Lbound, Ubound, Ubound); { Change sign of gradient } for I := Lbound to Ubound do G^[I] := - G^[I]; if Conv then { Newton-Raphson iteration } begin ErrCode := GaussJordan(A, G, Lbound, Ubound, H_inv, DeltaX); if ErrCode = MAT_OK then for I := Lbound to Ubound do X^[I] := OldX^[I] + DeltaX^[I]; Done := True; end else { Marquardt iteration } begin repeat { Multiply each diagonal term of H by (1 + Lambda) } Lambda1 := 1.0 + Lambda; for I := Lbound to Ubound do A^[I]^[I] := Lambda1 * H^[I]^[I]; ErrCode := GaussJordan(A, G, Lbound, Ubound, H_inv, DeltaX); if ErrCode = MAT_OK then begin { Initialize parameters } CopyVector(X, OldX, Lbound, Ubound); { Minimize in the direction specified by DeltaX } ErrCode := LinMin(Func, X, DeltaX, Lbound, Ubound, 100, 0.01, F1); { Check that the function has decreased. Otherwise increase Lambda, without exceeding LAMBDAMAX } Lambda_Ok := (F1 - F_min) < F_min * FTOL; if not Lambda_Ok then Lambda := 10.0 * Lambda; if Lambda > LAMBDAMAX then ErrCode := OPT_BIG_LAMBDA; end; until Lambda_Ok or (ErrCode <> MAT_OK); { Check for convergence } Conv := ParamConv(OldX, X, Lbound, Ubound, Tol); { Prepare next iteration } Lambda := 0.1 * Lambda; F_min := F1; end; Inc(Iter); if Iter > MaxIter then ErrCode := OPT_NON_CONV; until Done or (ErrCode <> OPT_OK); DelVector(OldX, Ubound); DelVector(G, Ubound); DelMatrix(H, Ubound, Ubound); DelMatrix(A, Ubound, Ubound); DelVector(DeltaX, Ubound); if WriteLogFile then Close(LogFile); if ErrCode = MAT_SINGUL then ErrCode := OPT_SING; Marquardt := ErrCode; end; function BFGS(Func : TFuncNVar; Gradient : TGradient; X : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float; H_inv : PMatrix) : Integer; var I, J, Iter, ErrCode : Integer; DeltaXmax, Gmax, P1, P2, R1, R2 : Float; OldX, DeltaX, dX, G, OldG, dG, HdG, R1dX, R2HdG, U, P2U : PVector; Conv : Boolean; function AbsMax(V : PVector; Lbound, Ubound : Integer) : Float; { Returns the component with maximum absolute value } var I : Integer; AbsV : PVector; begin DimVector(AbsV, Ubound); for I := Lbound to Ubound do AbsV^[I] := Abs(V^[I]); AbsMax := Max(AbsV, Lbound, Ubound); DelVector(AbsV, Ubound); end; begin if WriteLogFile then begin CreateLogFile; WriteLn(LogFile, 'BFGS'); WriteLn(LogFile, 'Iter F'); end; DimVector(OldX, Ubound); DimVector(DeltaX, Ubound); DimVector(dX, Ubound); DimVector(G, Ubound); DimVector(OldG, Ubound); DimVector(dG, Ubound); DimVector(HdG, Ubound); DimVector(R1dX, Ubound); DimVector(R2HdG, Ubound); DimVector(U, Ubound); DimVector(P2U, Ubound); Iter := 0; Conv := False; LinObjFunc := Func; { Function for line minimization } { Initialize function } F_min := Func(X); { Initialize inverse hessian to unit matrix } for I := Lbound to Ubound do for J := Lbound to Ubound do if I = J then H_inv^[I]^[J] := 1.0 else H_inv^[I]^[J] := 0.0; { Initialize gradient } Gradient(Func, X, Lbound, Ubound, G); Gmax := AbsMax(G, Lbound, Ubound); { Initialize search direction } if Gmax > MACHEP then for I := Lbound to Ubound do DeltaX^[I] := - G^[I] else Conv := True; { Quit if gradient is already small } while (not Conv) and (Iter < MaxIter) do begin if WriteLogFile then WriteLn(LogFile, Iter:4, ' ', F_min:12); { Normalize search direction to avoid excessive displacements } DeltaXmax := AbsMax(DeltaX, Lbound, Ubound); if DeltaXmax > 1.0 then for I := Lbound to Ubound do DeltaX^[I] := DeltaX^[I] / DeltaXmax; { Save old parameters and gradient } CopyVector(OldX, X, Lbound, Ubound); CopyVector(OldG, G, Lbound, Ubound); { Minimize along the direction specified by DeltaX } ErrCode := LinMin(Func, X, DeltaX, Lbound, Ubound, 100, 0.01, F_min); { Compute new gradient } Gradient(Func, X, Lbound, Ubound, G); { Compute differences between two successive estimations of parameter vector and gradient vector } for I := Lbound to Ubound do begin dX^[I] := X^[I] - OldX^[I]; dG^[I] := G^[I] - OldG^[I]; end; { Multiply by inverse hessian } for I := Lbound to Ubound do begin HdG^[I] := 0.0; for J := Lbound to Ubound do HdG^[I] := HdG^[I] + H_inv^[I]^[J] * dG^[J]; end; { Scalar products in denominator of BFGS formula } P1 := 0.0; P2 := 0.0; for I := Lbound to Ubound do begin P1 := P1 + dX^[I] * dG^[I]; P2 := P2 + dG^[I] * HdG^[I]; end; if (P1 = 0.0) or (P2 = 0.0) then Conv := True else begin { Inverses of scalar products } R1 := 1.0 / P1; R2 := 1.0 / P2; { Compute BFGS correction terms } for I := Lbound to Ubound do begin R1dX^[I] := R1 * dX^[I]; R2HdG^[I] := R2 * HdG^[I]; U^[I] := R1dX^[I] - R2HdG^[I]; P2U^[I] := P2 * U^[I]; end; { Update inverse hessian } for I := Lbound to Ubound do for J := Lbound to Ubound do H_inv^[I]^[J] := H_inv^[I]^[J] + R1dX^[I] * dX^[J] - R2HdG^[I] * HdG^[J] + P2U^[I] * U^[J]; { Update search direction } for I := Lbound to Ubound do begin DeltaX^[I] := 0.0; for J := Lbound to Ubound do DeltaX^[I] := DeltaX^[I] - H_inv^[I]^[J] * G^[J]; end; { Test convergence and update iteration count } Conv := ParamConv(OldX, X, Lbound, Ubound, Tol); Inc(Iter); end; end; DelVector(OldX, Ubound); DelVector(DeltaX, Ubound); DelVector(dX, Ubound); DelVector(G, Ubound); DelVector(OldG, Ubound); DelVector(dG, Ubound); DelVector(HdG, Ubound); DelVector(R1dX, Ubound); DelVector(R2HdG, Ubound); DelVector(U, Ubound); DelVector(P2U, Ubound); if WriteLogFile then Close(LogFile); if Iter > MaxIter then BFGS := OPT_NON_CONV else BFGS := OPT_OK; end; begin X1 := nil; DeltaX1 := nil; Ubound1 := 1; Eps := Power(MACHEP, 0.333); end. ����������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/fitlogis.pas���������������������������������������������0000755�0001750�0001750�00000016076�11326443506�020435� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITLOGIS.PAS * * Version 1.4 * * (c) J. Debord, August 2000 * ********************************************************************** This unit fits the logistic function : B - A y = A + ----------------- 1 + exp(-a.x + b) ********************************************************************** } unit FitLogis; {$F+} interface uses FMath, Matrices, Stat, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X : Float; B, D : PVector); function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; procedure InitModel(CstPar : PVector); implementation const ConsTerm : Boolean = True; { Flags the presence of a constant term A } function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function. -------------------------------------------------------------------- } begin if ConsTerm then FuncName := 'y = A + (B - A) / [1 + exp(-a.x + b)]' else FuncName := 'y = B / [1 + exp(-a.x + b)]'; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted (0 if there is a constant term A, 1 otherwise) -------------------------------------------------------------------- } begin if ConsTerm then FirstParam := 0 else FirstParam := 1; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 3; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter. -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'A'; 1 : ParamName := 'B'; 2 : ParamName := 'a'; 3 : ParamName := 'b'; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X. B is the vector of parameters, such that : B^[0] = A B^[1] = B B^[2] = a B^[3] = b -------------------------------------------------------------------- } begin if ConsTerm then RegFunc := B^[0] + (B^[1] - B^[0]) / (1.0 + Expo(- B^[2] * X + B^[3])) else RegFunc := B^[1] / (1.0 + Expo(- B^[2] * X + B^[3])); end; procedure DerivProc(X : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point X with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter -------------------------------------------------------------------- } var Q, R : Float; begin Q := Expo(- B^[2] * X + B^[3]); { exp(-ax+b) } R := 1.0 / (1.0 + Q); { 1 / [1 + exp(-ax+b)] } D^[0] := 1.0 - R; { dy/dA = 1 - 1 / [1 + exp(-ax+b)] } D^[1] := R; { dy/dB = 1 / [1 + exp(-ax+b)] } { dy/db = (A-B).exp(-ax+b) / [1 + exp(-ax+b)]^2 } D^[3] := (B^[0] - B^[1]) * Q * Sqr(R); { dy/da = (B-A).x.exp(-ax+b) / [1 + exp(-ax+b)]^2 } D^[2] := - D^[3] * X; end; procedure SortPoints(X, Y : PVector; N : Integer); { ---------------------------------------------------------------------- Sort points by increasing X values ---------------------------------------------------------------------- } var I, J, K : Integer; A : Float; begin for I := 1 to Pred(N) do begin K := I; A := X^[I]; for J := Succ(I) to N do if X^[J] < A then begin K := J; A := X^[J]; end; FSwap(X^[I], X^[K]); FSwap(Y^[I], Y^[K]); end; end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of a logistic function by linear regression: Ln[(B - A)/(y - A) - 1] = -ax + b -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- } var XX : PVector; { Transformed X coordinates } YY : PVector; { Transformed Y coordinates } WW : PVector; { Weights } A : PVector; { Linear regression parameters } V : PMatrix; { Variance-covariance matrix } P : Integer; { Number of points for linear regression } K : Integer; { Loop variable } ErrCode : Integer; { Error code } D : Float; { B - A } begin DimVector(XX, N); DimVector(YY, N); DimVector(WW, N); DimVector(A, 1); DimMatrix(V, 1, 1); SortPoints(X, Y, N); if ConsTerm then B^[0] := Y^[1] else B^[0] := 0.0; B^[1] := Y^[N]; P := 0; D := B^[1] - B^[0]; for K := 1 to N do if (X^[K] > X^[1]) and (X^[K] < X^[N]) then begin Inc(P); XX^[P] := X^[K]; YY^[P] := Log(D / (Y^[K] - B^[0]) - 1.0); WW^[P] := Sqr((Y^[K] - B^[0]) * (Y^[K] - B^[1]) / D); if Method = 1 then WW^[P] := WW^[P] * W^[K]; end; ErrCode := WLinFit(XX, YY, WW, P, A, V); if ErrCode = MAT_OK then begin B^[2] := - A^[1]; B^[3] := A^[0]; end; FitModel := ErrCode; DelVector(XX, N); DelVector(YY, N); DelVector(WW, N); DelVector(A, 1); DelMatrix(V, 1, 1); end; procedure InitModel(CstPar : PVector); { -------------------------------------------------------------------- Initializes the global variables of the unit. -------------------------------------------------------------------- CstPar^[0] = 1 to include a constant term (A) -------------------------------------------------------------------- } begin ConsTerm := (CstPar^[0] = 1); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/mcmc.pas�������������������������������������������������0000755�0001750�0001750�00000024075�11326443506�017532� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit MCMC.PAS * * Version 1.2 * * (c) J. Debord, June 2001 * ********************************************************************** Simulation by Markov Chain Monte Carlo (MCMC) with the Metropolis-Hastings algorithm. This algorithm simulates the probability density function (pdf) of a vector X. The pdf P(X) is written as: P(X) = C * Exp(- F(X) / T) Simulating P by the Metropolis-Hastings algorithm is equivalent to minimizing F by simulated annealing at the constant temperature T. The constant C is not used in the simulation. The series of random vectors generated during the annealing step constitutes a Markov chain which tends towards the pdf to be simulated. It is possible to run several cycles of the algorithm. The variance-covariance matrix of the simulated distribution is re-evaluated at the end of each cycle and used for the next cycle. ********************************************************************** } unit MCMC; interface uses FMath, Matrices, Optim, Regress; { ********************************************************************** Metropolis-Hastings parameters ********************************************************************** } const MH_NCycles : Integer = 1; { Number of cycles } MH_MaxSim : Integer = 1000; { Max nb of simulations at each cycle } MH_SavedSim : Integer = 200; { Nb of simulations to be saved } { ********************************************************************** Simulation routine ********************************************************************** } function Hastings(Func : TFuncNVar; T : Float; X : PVector; V : PMatrix; Lbound, Ubound : Integer; Xmat : PMatrix; X_min : PVector; var F_min : Float) : Integer; { ---------------------------------------------------------------------- Simulation of a probability density function by the Metropolis-Hastings algorithm ---------------------------------------------------------------------- Input parameters : Func = Function such that the pdf is P(X) = C * Exp(- Func(X) / T) T = Temperature X = Initial mean vector V = Initial variance-covariance matrix Lbound, Ubound = Indices of first and last variables ---------------------------------------------------------------------- Output parameters : Xmat = Matrix of simulated vectors, stored columnwise, i.e. Xmat[Lbound..Ubound, 1..MH_SavedSim] X = Mean of distribution V = Variance-covariance matrix of distribution X_min = Coordinates of minimum of F(X) (mode of the distribution) F_min = Value of F(X) at minimum ---------------------------------------------------------------------- Possible results : MAT_OK : No error MAT_NOT_PD : The variance-covariance matrix is not positive definite ---------------------------------------------------------------------- } implementation function CalcSD(V : PMatrix; Lbound, Ubound : Integer; L : PMatrix) : Integer; { ---------------------------------------------------------------------- Computes the standard deviations for independent random numbers from the variance-covariance matrix. ---------------------------------------------------------------------- } var I, ErrCode : Integer; begin I := LBound; ErrCode := 0; repeat if V^[I]^[I] > 0.0 then L^[I]^[I] := Sqrt(V^[I]^[I]) else ErrCode := MAT_NOT_PD; Inc(I); until (ErrCode <> 0) or (I > Ubound); CalcSD := ErrCode; end; procedure GenIndepRandomVector(X : PVector; L : PMatrix; Lbound, Ubound : Integer; X1 : PVector); { ---------------------------------------------------------------------- Generates a random vector X1 from X, using independent gaussian random increments. L is the diagonal matrix of the standard deviations. ---------------------------------------------------------------------- } var I : Integer; begin for I := Lbound to Ubound do X1^[I] := RanGauss(X^[I], L^[I]^[I]); end; procedure GenRandomVector(X : PVector; L : PMatrix; Lbound, Ubound : Integer; X1 : PVector); { ---------------------------------------------------------------------- Generates a random vector X1 from X, using correlated gaussian random increments. L is the Cholesky factor of the variance-covariance matrix ---------------------------------------------------------------------- } var U : PVector; I, J : Integer; begin { Form a vector U of independent standard normal variates } DimVector(U, Ubound); for I := Lbound to Ubound do U^[I] := RanGaussStd; { Form X1 = X + L*U, which follows the multinormal distribution } for I := Lbound to Ubound do begin X1^[I] := X^[I]; for J := Lbound to I do X1^[I] := X1^[I] + L^[I]^[J] * U^[J]; end; DelVector(U, Ubound); end; function Accept(DeltaF, T : Float) : Boolean; { ---------------------------------------------------------------------- Checks if a variation DeltaF of the function at temperature T is acceptable. ---------------------------------------------------------------------- } begin Accept := (DeltaF < 0.0) or (Expo(- DeltaF / T) > RanMar); end; function HastingsCycle(Func : TFuncNVar; T : Float; X : PVector; V : PMatrix; Lbound, Ubound : Integer; Indep : Boolean; Xmat : PMatrix; X_min : PVector; var F_min : Float) : Integer; { ---------------------------------------------------------------------- Performs one cycle of the Metropolis-Hastings algorithm ---------------------------------------------------------------------- } var F, F1 : Float; { Function values } DeltaF : Float; { Variation of function } X1 : PVector; { New coordinates } L : PMatrix; { Standard dev. or Cholesky factor } I, K : Integer; { Loop variable } Iter : Integer; { Iteration count } FirstSavedSim : Integer; { Index of first simulation to be saved } ErrCode : Integer; { Error code } begin { Dimension arrays } DimVector(X1, Ubound); DimMatrix(L, Ubound, Ubound); { Compute SD's or Cholesky factor } if Indep then ErrCode := CalcSD(V, Lbound, Ubound, L) else ErrCode := Cholesky(V, Lbound, Ubound, L); HastingsCycle := ErrCode; if ErrCode = MAT_NOT_PD then Exit; { Compute initial function value } F := Func(X); { Perform MH_MaxSim simulations at constant temperature } FirstSavedSim := MH_MaxSim - MH_SavedSim + 1; Iter := 1; K := 1; repeat { Generate new vector } if Indep then GenIndepRandomVector(X, L, Lbound, Ubound, X1) else GenRandomVector(X, L, Lbound, Ubound, X1); { Compute new function value } F1 := Func(X1); DeltaF := F1 - F; { Check for acceptance } if Accept(DeltaF, T) then begin CopyVector(X, X1, Lbound, Ubound); if Iter >= FirstSavedSim then begin { Save simulated vector into column K of matrix Xmat } CopyColFromVector(Xmat, X1, Lbound, Ubound, K); Inc(K); end; if F1 < F_min then begin { Update minimum } CopyVector(X_min, X1, Lbound, Ubound); F_min := F1; end; F := F1; Inc(Iter); end; until Iter > MH_MaxSim; { Update mean vector and variance-covariance matrix } VecMean(Xmat, MH_SavedSim, Lbound, Ubound, X); MatVarCov(Xmat, MH_SavedSim, Lbound, Ubound, X, V); DelVector(X1, Ubound); DelMatrix(L, Ubound, Ubound); end; function Hastings(Func : TFuncNVar; T : Float; X : PVector; V : PMatrix; Lbound, Ubound : Integer; Xmat : PMatrix; X_min : PVector; var F_min : Float) : Integer; var K, ErrCode : Integer; Indep : Boolean; begin { Initialize the Marsaglia random number generator using the standard Pascal generator } Randomize; RMarIn(System.Random(10000), System.Random(10000)); K := 1; Indep := True; F_min := MAXNUM; repeat ErrCode := HastingsCycle(Func, T, X, V, Lbound, Ubound, Indep, Xmat, X_min, F_min); Indep := False; Inc(K); until (ErrCode <> 0) or (K > MH_NCycles); Hastings := ErrCode; end; end.�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/simopt.pas�����������������������������������������������0000755�0001750�0001750�00000024425�11326443506�020125� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit SIMOPT.PAS * * Version 1.0 * * (c) J. Debord, August 2000 * ********************************************************************** This unit implements simulated annealing for function minimization ********************************************************************** Reference: Program SIMANN.FOR by Bill Goffe (http://www.netlib.org/simann) ********************************************************************** } unit SimOpt; interface uses FMath, Matrices, Optim, Stat; const SA_Nt : Integer = 5; { Number of loops at constant temperature } SA_Ns : Integer = 15; { Number of loops before step adjustment } SA_Rt : Float = 0.9; { Temperature reduction factor } SA_NCycles : Integer = 1; { Number of cycles } function SimAnn(Func : TFuncNVar; X, Xmin, Xmax : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float) : Integer; { ---------------------------------------------------------------------- Minimization of a function of several variables by simulated annealing ---------------------------------------------------------------------- Input parameters : Func = objective function to be minimized X = initial minimum coordinates Xmin = minimum value of X Xmax = maximum value of X Lbound, Ubound = indices of first and last variables MaxIter = max number of annealing steps Tol = required precision ---------------------------------------------------------------------- Output parameter : X = refined minimum coordinates F_min = function value at minimum ---------------------------------------------------------------------- Possible results : OPT_OK OPT_NON_CONV ---------------------------------------------------------------------- } implementation var LogFile : Text; { Stores the result of each minimization step } procedure CreateLogFile; begin Assign(LogFile, LogFileName); Rewrite(LogFile); end; function InitTemp(Func : TFuncNVar; X, Xmin, Range : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Computes the initial temperature so that the probability of accepting an increase of the function is about 0.5 ---------------------------------------------------------------------- } const N_EVAL = 50; { Number of function evaluations } var T : Float; { Temperature } F, F1 : Float; { Function values } DeltaF : PVector; { Function increases } N_inc : Integer; { Number of function increases } I : Integer; { Index of function evaluation } K : Integer; { Index of parameter } begin DimVector(DeltaF, N_EVAL); T := 0.0; N_inc := 0; F := Func(X); { Compute N_EVAL function values, changing each parameter in turn } K := Lbound; for I := 1 to N_EVAL do begin X^[K] := Xmin^[K] + RanMar * Range^[K]; F1 := Func(X); if F1 > F then begin Inc(N_inc); DeltaF^[N_inc] := F1 - F; end; F := F1; Inc(K); if K > Ubound then K := Lbound; end; { The median M of these N_eval values has a probability of 1/2. From Boltzmann's formula: Exp(-M/T) = 1/2 ==> T = M / Ln(2) } T := Median(DeltaF, 1, N_inc) / LN2; if T = 0.0 then T := 1.0; InitTemp := T; DelVector(DeltaF, N_EVAL); end; function ParamConv(X, Step : PVector; Lbound, Ubound : Integer; Tol : Float) : Boolean; { ---------------------------------------------------------------------- Checks for convergence on parameters ---------------------------------------------------------------------- } var I : Integer; Conv : Boolean; begin I := Lbound; Conv := True; repeat Conv := Conv and (Step^[I] < FMax(Tol, Tol * Abs(X^[I]))); Inc(I); until (Conv = False) or (I > Ubound); ParamConv := Conv; end; function Accept(DeltaF, T : Float; var N_inc, N_acc : Integer) : Boolean; { ---------------------------------------------------------------------- Checks if a variation DeltaF of the function at temperature T is acceptable. Updates the counters N_inc (number of increases of the function) and N_acc (number of accepted increases). ---------------------------------------------------------------------- } begin if DeltaF < 0.0 then Accept := True else begin Inc(N_inc); if Expo(- DeltaF / T) > RanMar then begin Accept := True; Inc(N_acc); end else Accept := False; end; end; function SimAnnCycle(Func : TFuncNVar; X, Xmin, Xmax : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var LogFile : Text; var F_min : Float) : Integer; { ---------------------------------------------------------------------- Performs one cycle of simulated annealing ---------------------------------------------------------------------- } const N_FACT = 2.0; { Factor for step reduction } var I, Iter, J, K, N_inc, N_acc : Integer; F, F1, DeltaF, Ratio, T, OldX : Float; Range, Step, Xopt : PVector; Nacc : PIntVector; begin DimVector(Step, Ubound); DimVector(Xopt, Ubound); DimVector(Range, Ubound); DimIntVector(Nacc, Ubound); { Determine parameter range, step and optimum } for K := Lbound to Ubound do begin Range^[K] := Xmax^[K] - Xmin^[K]; Step^[K] := 0.5 * Range^[K]; Xopt^[K] := X^[K]; end; { Initialize function values } F := Func(X); F_min := F; { Initialize temperature and iteration count } T := InitTemp(Func, X, Xmin, Range, Lbound, Ubound); Iter := 0; repeat { Perform SA_Nt evaluations at constant temperature } N_inc := 0; N_acc := 0; for I := 1 to SA_Nt do begin for J := 1 to SA_Ns do for K := Lbound to Ubound do begin { Save current parameter value } OldX := X^[K]; { Pick new value, keeping it within Range } X^[K] := X^[K] + (2.0 * RanMar - 1.0) * Step^[K]; if (X^[K] < Xmin^[K]) or (X^[K] > Xmax^[K]) then X^[K] := Xmin^[K] + RanMar * Range^[K]; { Compute new function value } F1 := Func(X); DeltaF := F1 - F; { Check for acceptance } if Accept(DeltaF, T, N_inc, N_acc) then begin Inc(Nacc^[K]); F := F1; end else { Restore parameter value } X^[K] := OldX; { Update minimum if necessary } if F < F_min then begin Xopt^[K] := X^[K]; F_min := F; end; end; { Ajust step length to maintain an acceptance ratio of about 50% for each parameter } for K := Lbound to Ubound do begin Ratio := Int(Nacc^[K]) / Int(SA_Ns); if Ratio > 0.6 then begin { Increase step length, keeping it within Range } Step^[K] := Step^[K] * (1.0 + ((Ratio - 0.6) / 0.4) * N_FACT); if Step^[K] > Range^[K] then Step^[K] := Range^[K]; end else if Ratio < 0.4 then { Reduce step length } Step^[K] := Step^[K] / (1.0 + ((0.4 - Ratio) / 0.4) * N_FACT); { Restore counter } Nacc^[K] := 0; end; end; if WriteLogFile then WriteLn(LogFile, Iter:4, ' ', T:12, ' ', F:12, N_inc:6, N_acc:6); { Update temperature and iteration count } T := T * SA_Rt; Inc(Iter); until ParamConv(Xopt, Step, Lbound, Ubound, Tol) or (Iter > MaxIter); for K := Lbound to Ubound do X^[K] := Xopt^[K]; DelVector(Step, Ubound); DelVector(Xopt, Ubound); DelVector(Range, Ubound); DelIntVector(Nacc, Ubound); if Iter > MaxIter then SimAnnCycle := OPT_NON_CONV else SimAnnCycle := OPT_OK; end; function SimAnn(Func : TFuncNVar; X, Xmin, Xmax : PVector; Lbound, Ubound : Integer; MaxIter : Integer; Tol : Float; var F_min : Float) : Integer; var Cycle, ErrCode : Integer; begin if WriteLogFile then CreateLogFile; { Initialize the Marsaglia random number generator using the standard Pascal generator } Randomize; RMarIn(System.Random(10000), System.Random(10000)); Cycle := 1; repeat if WriteLogFile then begin WriteLn(LogFile, 'Simulated annealing: Cycle ', Cycle); WriteLn(LogFile); WriteLn(LogFile, 'Iter T F Inc Acc'); end; ErrCode := SimAnnCycle(Func, X, Xmin, Xmax, Lbound, Ubound, MaxIter, Tol, LogFile, F_min); Inc(Cycle); until (Cycle > SA_NCycles) or (ErrCode <> OPT_OK); if WriteLogFile then Close(LogFile); SimAnn := ErrCode; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/plot.pas�������������������������������������������������0000755�0001750�0001750�00000043115�11326443506�017565� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit PLOT.PAS * * Version 1.7 * * (c) J. Debord, June 2001 * ********************************************************************** Plotting routines for Turbo Pascal ********************************************************************** } unit Plot; interface uses Graph, FMath, Matrices, PaString; const BGIPath : String = 'C:\BP\BGI'; { Access path for graphic drivers } DefSymbSize : Integer = 3; { Default symbol size } { ********************** Include global variables ********************** } {$I PLOTVAR.INC} { ************************** Graphic routines ************************** } function GraphOk : Boolean; { ---------------------------------------------------------------------- Initializes high resolution graphics and plots the axes ---------------------------------------------------------------------- } procedure PlotGrid; { ---------------------------------------------------------------------- Plots a grid on the graph ---------------------------------------------------------------------- } procedure WriteLegend(NCurv : Integer); { ---------------------------------------------------------------------- Writes the graph title and the legends for the plotted curves Input parameter : NCurv = number of curves (1 to MAXCURV) ---------------------------------------------------------------------- } procedure SetClipping(Clip : Boolean); { ---------------------------------------------------------------------- Determines whether drawings are clipped at the current viewport boundaries, according to the value of the Boolean parameter Clip ---------------------------------------------------------------------- } procedure PlotPoint(Xp, Yp, Symbol, Size, Trace : Integer); { ---------------------------------------------------------------------- Plots a point on the screen ---------------------------------------------------------------------- Input parameters : Xp, Yp : point coordinates in pixels Symbol : 0 = point (.) 1 = solid circle 2 = open circle 3 = solid square 4 = open square 5 = solid triangle 6 = open triangle 7 = plus (+) 8 = multiply (x) 9 = star (*) Size : symbol size Trace : type of line between points 0 = none 1 = solid 2 = dotted 3 = centered 4 = dashed ---------------------------------------------------------------------- } procedure PlotCurve(X, Y : PVector; Lbound, Ubound, Symbol, Trace : Integer); { ---------------------------------------------------------------------- Plots a curve ---------------------------------------------------------------------- Input parameters : X, Y = point coordinates Lbound, Ubound = indices of first and last points Symbol, Trace = as in PlotPoint ---------------------------------------------------------------------- } procedure PlotCurveWithErrorBars(X, Y, S : PVector; Lbound, Ubound, Symbol, Trace : Integer); { ---------------------------------------------------------------------- Plots a curve with error bars ---------------------------------------------------------------------- Input parameters : X, Y = point coordinates S = errors (standard deviations) Lbound, Ubound = indices of first and last points Symbol, Trace = as in PlotPoint ---------------------------------------------------------------------- } procedure PlotFunc(Func : TFunc; X1, X2 : Float; Trace : Integer); { ---------------------------------------------------------------------- Plots a function ---------------------------------------------------------------------- Input parameters : Func = function to be plotted X1, X2 = abscissae of 1st and last point to plot Trace = as in PlotPoint ---------------------------------------------------------------------- The function must be programmed as : function Func(X : Float) : Float; ---------------------------------------------------------------------- } { *********** The following routines are defined in PLOT.INC *********** } procedure Interval(X1, X2 : Float; MinDiv, MaxDiv : Integer; var Min, Max, Step : Float); { ---------------------------------------------------------------------- Determines an interval [Min, Max] including the values from X1 to X2, and a subdivision Step of this interval ---------------------------------------------------------------------- Input parameters : X1, X2 = min. & max. values to be included MinDiv = minimum nb of subdivisions MaxDiv = maximum nb of subdivisions ---------------------------------------------------------------------- Output parameters : Min, Max, Step ---------------------------------------------------------------------- } procedure AutoScale(Z : PVector; Lbound, Ubound : Integer; var Axis : TAxis); { ---------------------------------------------------------------------- Determines the scale of an axis ---------------------------------------------------------------------- Input parameters : Z = array of values to be plotted Lbound, Ubound = indices of first and last elements of Z ---------------------------------------------------------------------- Output parameters : Axis ---------------------------------------------------------------------- } function Xpixel(X : Float) : Integer; { ---------------------------------------------------------------------- Converts user abscissa X to screen coordinate ---------------------------------------------------------------------- } function Ypixel(Y : Float) : Integer; { ---------------------------------------------------------------------- Converts user ordinate Y to screen coordinate ---------------------------------------------------------------------- } function Xuser(X : Integer) : Float; { ---------------------------------------------------------------------- Converts screen coordinate X to user abscissa ---------------------------------------------------------------------- } function Yuser(Y : Integer) : Float; { ---------------------------------------------------------------------- Converts screen coordinate Y to user ordinate ---------------------------------------------------------------------- } implementation { ---------------------------------------------------------------------- Include the variables and routines common to PLOT.PAS and WINPLOT.PAS ---------------------------------------------------------------------- } {$I PLOT.INC} { ---------------------------------------------------------------------- } procedure PlotXAxis; var W, X, Z : Float; N, I, J : Integer; NSZ : Boolean; begin Line(XminPixel, YmaxPixel, XmaxPixel, YmaxPixel); SetTextStyle(XTitle.Font, HorizDir, 1); SetUserCharSize(XTitle.CharWidth, 100, XTitle.CharHeight, 100); SetTextJustify(CenterText, TopText); N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); { Nb of intervals } X := XAxis.Min; { Tick mark position } NSZ := NSZero; NSZero := False; { Don't write non significant zero's } for I := 0 to N do { Label axis } begin if (XAxis.Scale = LIN_SCALE) and (Abs(X) < EPS) then X := 0.0; MoveTo(Xpixel(X), YmaxPixel); LineRel(0, 5); { Plot tick mark } if XAxis.Scale = LIN_SCALE then Z := X else Z := Exp10(X); OutText(Trim(FloatToStr(Z))); if (XAxis.Scale = LOG_SCALE) and (I < N) then for J := 2 to 9 do { Plot minor divisions } begin { on logarithmic scale } W := X + Log10(J); MoveTo(Xpixel(W), YmaxPixel); LineRel(0, 3); end; X := X + XAxis.Step; end; if XTitle.Text <> '' then { Plot axis title } OutTextXY((XminPixel + XmaxPixel) div 2, YmaxPixel + GetMaxY div 12, XTitle.Text); NSZero := NSZ; end; procedure PlotYAxis; var W, Y, Z : Float; N, I, J : Integer; NSZ : Boolean; begin Line(XminPixel, YminPixel, XminPixel, YmaxPixel); SetTextStyle(YTitle.Font, HorizDir, 1); SetUserCharSize(YTitle.CharWidth, 100, YTitle.CharHeight, 100); SetTextJustify(RightText, CenterText); N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); Y := YAxis.Min; NSZ := NSZero; NSZero := False; for I := 0 to N do begin if (YAxis.Scale = LIN_SCALE) and (Abs(Y) < EPS) then Y := 0.0; MoveTo(XminPixel, Ypixel(Y)); LineRel(- 5, 0); MoveRel(- 2, - 2); if YAxis.Scale = LIN_SCALE then Z := Y else Z := Exp10(Y); OutText(Trim(FloatToStr(Z))); if (YAxis.Scale = LOG_SCALE) and (I < N) then for J := 2 to 9 do begin W := Y + Log10(J); MoveTo(XminPixel, Ypixel(W)); LineRel(- 3, 0); end; Y := Y + YAxis.Step; end; if YTitle.Text <> '' then begin SetTextStyle(YTitle.Font, VertDir, 1); SetUserCharSize(YTitle.CharWidth, 100, YTitle.CharHeight, 100); OutTextXY(XminPixel - GetMaxX div 8, (YminPixel + YmaxPixel) div 2, YTitle.Text); end; NSZero := NSZ; end; function GraphOk : Boolean; var Pilot, Mode : Integer; begin Pilot := Detect; InitGraph(Pilot, Mode, BGIPath); if GraphResult <> 0 then begin GraphOk := False; Exit; end; GraphOk := True; XminPixel := Round(Xwin1 / 100 * GetMaxX); YminPixel := Round(Ywin1 / 100 * GetMaxY); XmaxPixel := Round(Xwin2 / 100 * GetMaxX); YmaxPixel := Round(Ywin2 / 100 * GetMaxY); FactX := (XmaxPixel - XminPixel) / (XAxis.Max - XAxis.Min); FactY := (YmaxPixel - YminPixel) / (YAxis.Max - YAxis.Min); if GraphBorder then Rectangle(XminPixel, YminPixel, XmaxPixel, YmaxPixel); PlotXAxis; PlotYAxis; end; procedure PlotGrid; var X, Y : Float; I, N, Xp, Yp : Integer; begin SetLineStyle(DottedLn, 0, NormWidth); if Grid in [HORIZ_GRID, BOTH_GRID] then { Horizontal lines } begin N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); { Nb of intervals } for I := 1 to Pred(N) do begin Y := YAxis.Min + I * YAxis.Step; { Origin of line } Yp := Ypixel(Y); Line(XminPixel, Yp, XmaxPixel, Yp); end; end; if Grid in [VERTIC_GRID, BOTH_GRID] then { Vertical lines } begin N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); for I := 1 to Pred(N) do begin X := XAxis.Min + I * XAxis.Step; Xp := Xpixel(X); Line(Xp, YminPixel, Xp, YmaxPixel); end; end; SetLineStyle(SolidLn, 0, NormWidth); end; procedure PlotPoint(Xp, Yp, Symbol, Size, Trace : Integer); var Xasp, Yasp, Xp1, Xp2, Yp1, Yp2, Dx, Dy : Word; R : Float; Triangle : array[1..4] of PointType; Square : array[1..5] of PointType; begin if Trace = 0 then MoveTo(Xp, Yp) else begin SetLineStyle(Pred(Trace), 0, NormWidth); LineTo(Xp, Yp); SetLineStyle(0, 0, 1); end; GetAspectRatio(Xasp, Yasp); R := 0.0001 * Size; Dx := Round(R * Yasp); Dy := Round(R * Xasp); Xp1 := Xp - Size; Xp2 := Xp + Size; Yp1 := Yp - Size; Yp2 := Yp + Size; if Symbol in [3, 4] then begin Square[1].X := Xp1; Square[1].Y := Yp1; Square[2].X := Xp1; Square[2].Y := Yp2; Square[3].X := Xp2; Square[3].Y := Yp2; Square[4].X := Xp2; Square[4].Y := Yp1; Square[5].X := Xp1; Square[5].Y := Yp1; end; if Symbol in [5, 6] then begin Triangle[1].X := Xp; Triangle[1].Y := Yp1; Triangle[2].X := Xp2; Triangle[2].Y := Yp2; Triangle[3].X := Xp1; Triangle[3].Y := Yp2; Triangle[4].X := Xp; Triangle[4].Y := Yp1; end; case Symbol of 0 : PutPixel(Xp, Yp, GetColor); { } 1 : PieSlice(Xp, Yp, 0, 360, Dx); { Solid circle } 2 : Ellipse(Xp, Yp, 0, 360, Dx, Dy); { Open circle } 3 : FillPoly(5, Square); { Solid square } 4 : DrawPoly(5, Square); { Open square } 5 : FillPoly(4, Triangle); { Solid triangle } 6 : DrawPoly(4, Triangle); { Open triangle } 7 : begin { + } Line(Xp, Yp1, Xp, Yp2); Line(Xp1, Yp, Xp2, Yp); end; 8 : begin { x } Line(Xp1, Yp1, Xp2, Yp2); Line(Xp1, Yp2, Xp2, Yp1); end; 9 : begin Line(Xp, Yp1, Xp, Yp2); { * } Line(Xp1, Yp, Xp2, Yp); Line(Xp1, Yp1, Xp2, Yp2); Line(Xp1, Yp2, Xp2, Yp1); end; end; end; procedure WriteLegend(NCurv : Integer); var I, Xp, Yp, Dy : Integer; begin with GraphTitle do if Text <> '' then begin SetTextStyle(Font, HorizDir, 1); SetUserCharSize(CharWidth, 100, CharHeight, 100); SetTextJustify(CenterText, TopText); OutTextXY((XminPixel + XmaxPixel) div 2, YminPixel - GetMaxY div 10, Text); end; with Legend do begin SetTextStyle(Font, HorizDir, 1); SetUserCharSize(CharWidth, 100, CharHeight, 100); SetTextJustify(LeftText, CenterText); Dy := (YmaxPixel - YminPixel) div 10; Xp := XmaxPixel + 30; Yp := YminPixel + Dy; for I := 1 to NCurv do if Text[I] <> '' then begin PlotPoint(Xp, Yp, I, SymbolSize, 0); OutTextXY(Xp + 20, Yp, Text[I]); Yp := Yp + Dy; end; end; end; procedure SetClipping(Clip : Boolean); begin if XminPixel = 0 then begin XminPixel := Round(Xwin1 / 100 * GetMaxX); YminPixel := Round(Ywin1 / 100 * GetMaxY); XmaxPixel := Round(Xwin2 / 100 * GetMaxX); YmaxPixel := Round(Ywin2 / 100 * GetMaxY); end; SetViewPort(XminPixel, YminPixel, XmaxPixel, YmaxPixel, Clip); XmaxPixel := XmaxPixel - XminPixel; XminPixel := 0; YmaxPixel := YmaxPixel - YminPixel; YminPixel := 0; end; procedure PlotCurve(X, Y : PVector; Lbound, Ubound, Symbol, Trace : Integer); var XI, YI : Float; I, NL : Integer; begin NL := 0; for I := Lbound to Ubound do begin XI := X^[I]; if XAxis.Scale = LOG_SCALE then XI := Log10(XI); YI := Y^[I]; if YAxis.Scale = LOG_SCALE then YI := Log10(YI); PlotPoint(Xpixel(XI), Ypixel(YI), Symbol, DefSymbSize, NL); NL := Trace; end; end; procedure PlotCurveWithErrorBars(X, Y, S : PVector; Lbound, Ubound, Symbol, Trace : Integer); var XI, YI, Y1, Y2 : Float; I, NL, Xp, Yp, Yp1, Yp2 : Integer; begin NL := 0; for I := Lbound to Ubound do begin XI := X^[I]; if XAxis.Scale = LOG_SCALE then XI := Log10(XI); YI := Y^[I]; if YAxis.Scale = LOG_SCALE then YI := Log10(YI); Xp := Xpixel(XI); Yp := Ypixel(YI); PlotPoint(Xp, Yp, Symbol, DefSymbSize, NL); if S^[I] > 0 then begin Y1 := Y^[I] - S^[I]; if YAxis.Scale = LOG_SCALE then Y1 := Log10(Y1); Y2 := Y^[I] + S^[I]; if YAxis.Scale = LOG_SCALE then Y2 := Log10(Y2); Yp1 := Ypixel(Y1); Yp2 := Ypixel(Y2); Line(Xp - 5, Yp1, Xp + 5, Yp1); Line(Xp - 5, Yp2, Xp + 5, Yp2); Line(Xp, Yp1, Xp, Yp2); end; NL := Trace; end; end; procedure PlotFunc(Func : TFunc; X1, X2 : Float; Trace : Integer); var X, Y, H : Float; I, Npt, NL, Xp, Yp : Integer; begin NL := 0; { Indicates if a line must be drawn from the previous point } X := X1; { Nb of points to be plotted = number of pixels between X1 and X2 } Npt := Xpixel(X2) - Xpixel(X1); H := (X2 - X1) / Npt; for I := 0 to Npt do begin X := X1 + I * H; if XAxis.Scale = LIN_SCALE then Y := Func(X) else Y := Func(Exp10(X)); if MathError <> FN_OK then NL := 0 else begin if YAxis.Scale = LOG_SCALE then Y := Log10(Y); Xp := Xpixel(X); Yp := Ypixel(Y); PlotPoint(Xp, Yp, 0, 0, NL); NL := Trace; end; end; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/matcomp.pas����������������������������������������������0000755�0001750�0001750�00000022156�11326443506�020251� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit MATCOMP.PAS * * Version 1.3 * * (c) J. Debord, August 2000 * ********************************************************************** Matrices with complex elements. See MATRICES.PAS for details concerning the dynamic allocation and use of matrices. ********************************************************************** References: 1) 'Basic Programs for Scientists and Engineers' by A.R. Miller 2) 'Numerical Recipes' by Press et al. ********************************************************************** } unit MatComp; interface uses FMath, FComp, Matrices; { ********************************************************************** This section defines the vector and matrix types. Maximal sizes are given for a 16-bit compiler (TP/BP). Higher values may be used with a 32-bit compiler such as FPC. ********************************************************************** } const {$IFDEF DOUBLEREAL} MAX_COMP = 3854; { Max size of complex vector } {$ELSE} {$IFDEF SINGLEREAL} MAX_COMP = 7280; {$ELSE} {$IFDEF PASCALREAL} MAX_COMP = 5040; {$ELSE} {$DEFINE EXTENDEDREAL} MAX_COMP = 3119; {$ENDIF} {$ENDIF} {$ENDIF} type TCompVector = array[0..MAX_COMP] of Complex; PCompVector = ^TCompVector; TCompMatrix = array[0..MAX_VEC] of PCompVector; PCompMatrix = ^TCompMatrix; { ********************************************************************** Memory allocation routines ********************************************************************** } procedure DimCompVector(var V : PCompVector; Ubound : Integer); { ---------------------------------------------------------------------- Creates complex vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DimCompMatrix(var A : PCompMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Creates complex matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } { ********************************************************************** Memory deallocation routines ********************************************************************** } procedure DelCompVector(V : PCompVector; Ubound : Integer); { ---------------------------------------------------------------------- Deletes complex vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DelCompMatrix(A : PCompMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Deletes complex matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } { ********************************************************************** Complex matrix functions ********************************************************************** } function C_LU_Decomp(A : PCompMatrix; Lbound, Ubound : Integer) : Integer; { ---------------------------------------------------------------------- LU decomposition ---------------------------------------------------------------------- } procedure C_LU_Solve(A : PCompMatrix; B : PCompVector; Lbound, Ubound : Integer; X : PCompVector); { ---------------------------------------------------------------------- Solves a system of equations whose matrix has been transformed by C_LU_Decomp ---------------------------------------------------------------------- } implementation const { Used by LU procedures } LastDim : Integer = 1; { Dimension of the last system solved } Index : PIntVector = nil; { Records the row permutations } procedure DimCompVector(var V : PCompVector; Ubound : Integer); var I : Integer; begin { Check bounds } if (Ubound < 0) or (Ubound > MAX_COMP) then begin V := nil; Exit; end; { Allocate vector } GetMem(V, Succ(Ubound) * SizeOf(Complex)); if V = nil then Exit; { Initialize vector } for I := 0 to Ubound do V^[I] := C_zero; end; procedure DimCompMatrix(var A : PCompMatrix; Ubound1, Ubound2 : Integer); var I, J : Integer; RowSize : Word; begin { Check bounds } if (Ubound1 < 0) or (Ubound1 > MAX_VEC) or (Ubound2 < 0) or (Ubound2 > MAX_COMP) then begin A := nil; Exit; end; { Size of a row } GetMem(A, Succ(Ubound1) * SizeOf(PCompVector)); if A = nil then Exit; { Allocate each row } for I := 0 to Ubound1 do begin GetMem(A^[I], RowSize); if A^[I] = nil then begin A := nil; Exit; end; end; { Initialize matrix } for I := 0 to Ubound1 do for J := 0 to Ubound2 do A^[I]^[J] := C_zero; end; procedure DelCompVector(V : PCompVector; Ubound : Integer); begin if V <> nil then begin FreeMem(V, Succ(Ubound) * SizeOf(Complex)); V := nil; end; end; procedure DelCompMatrix(A : PCompMatrix; Ubound1, Ubound2 : Integer); var I : Integer; RowSize : Word; begin if A <> nil then begin RowSize := Succ(Ubound2) * SizeOf(Complex); for I := Ubound1 downto 0 do FreeMem(A^[I], RowSize); FreeMem(A, Succ(Ubound1) * SizeOf(PCompVector)); A := nil; end; end; function C_LU_Decomp(A : PCompMatrix; Lbound, Ubound : Integer) : Integer; const TINY = 1.0E-20; var I, Imax, J, K : Integer; C, Pvt, T : Float; Sum, Z : Complex; V : PVector; begin DimVector(V, Ubound); { Reallocate Index } if Index <> nil then DelIntVector(Index, LastDim); DimIntVector(Index, Ubound); LastDim := Ubound; for I := Lbound to Ubound do begin Pvt := 0.0; for J := Lbound to Ubound do begin C := CAbs(A^[I]^[J]); if C > Pvt then Pvt := C; end; if Pvt < MACHEP then begin DelVector(V, Ubound); C_LU_Decomp := MAT_SINGUL; Exit; end; V^[I] := 1.0 / Pvt; end; for J := Lbound to Ubound do begin for I := Lbound to Pred(J) do begin Sum := A^[I]^[J]; for K := Lbound to Pred(I) do begin { Sum := Sum - A^[I]^[K] * A^[K]^[J]; } CMult(A^[I]^[K], A^[K]^[J], Z); CSub(Sum, Z, Sum); end; A^[I]^[J] := Sum; end; Pvt := 0.0; for I := J to Ubound do begin Sum := A^[I]^[J]; for K := Lbound to Pred(J) do begin { Sum := Sum - A^[I]^[K] * A^[K]^[J]; } CMult(A^[I]^[K], A^[K]^[J], Z); CSub(Sum, Z, Sum); end; A^[I]^[J] := Sum; T := V^[I] * CAbs(Sum); if T > Pvt then begin Pvt := T; Imax := I; end; end; if J <> Imax then begin { SwapRows(Imax, J, A, Lbound, Ubound); } for K := Lbound to Ubound do CSwap(A^[Imax]^[K], A^[J]^[K]); V^[Imax] := V^[J]; end; Index^[J] := Imax; if CAbs(A^[J]^[J]) = 0.0 then CSet(A^[J]^[J], TINY, TINY, Rec); if J <> Ubound then for I := Succ(J) to Ubound do { A^[I]^[J] := A^[I]^[J] / A^[J]^[J]; } CDiv(A^[I]^[J], A^[J]^[J], A^[I]^[J]); end; DelVector(V, Ubound); C_LU_Decomp := MAT_OK; end; procedure C_LU_Solve(A : PCompMatrix; B : PCompVector; Lbound, Ubound : Integer; X : PCompVector); var I, Ip, J, K : Integer; Sum, Z : Complex; begin K := Pred(Lbound); { CopyVector(X, B, Lbound, Ubound); } for I := Lbound to Ubound do X^[I] := B^[I]; for I := Lbound to Ubound do begin Ip := Index^[I]; Sum := X^[Ip]; X^[Ip] := X^[I]; if K >= Lbound then for J := K to Pred(I) do begin { Sum := Sum - A^[I]^[J] * X^[J] } CMult(A^[I]^[J], X^[J], Z); CSub(Sum, Z, Sum); end else if CAbs(Sum) <> 0.0 then K := I; X^[I] := Sum; end; for I := Ubound downto Lbound do begin Sum := X^[I]; if I < Ubound then for J := Succ(I) to Ubound do begin { Sum := Sum - A^[I]^[J] * X^[J]; } CMult(A^[I]^[J], X^[J], Z); CSub(Sum, Z, Sum); end; { X^[I] := Sum / A^[I]^[I]; } CDiv(Sum, A^[I]^[I], X^[I]); end; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/fitfrac.pas����������������������������������������������0000755�0001750�0001750�00000015540�11326443506�020226� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITFRAC.PAS * * Version 1.2 * * (c) J. Debord, April 1999 * ********************************************************************** This unit fits a rational fraction : p0 + p1.x + p2.x^2 + ... y = ------------------------ 1 + q1.x + q2.x^2 + ... ********************************************************************** } unit FitFrac; {$F+} interface uses FMath, Matrices, Polynom, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X, Y : Float; B, D : PVector); function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; procedure InitModel(CstPar : PVector); implementation const Deg1 : Integer = 1; { Degree of numerator } Deg2 : Integer = 1; { Degree of denominator } ConsTerm : Boolean = True; { Flags the presence of a constant term p0 } function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } var Name, S : String; I : Integer; begin Name := 'y = ('; if ConsTerm then Name := Name + 'p0 + '; Name := Name + 'p1.x'; for I := 2 to Deg1 do begin Str(I, S); Name := Name + ' + p' + S + '.x^' + S; end; Name := Name + ') / (1 + q1.x'; for I := (Deg1 + 2) to (Deg1 + Deg2) do begin Str(I - Deg1, S); Name := Name + ' + q' + S + '.x^' + S; end; Name := Name + ')'; FuncName := Name; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted (0 if there is a constant term p0, 1 otherwise) -------------------------------------------------------------------- } begin if ConsTerm then FirstParam := 0 else FirstParam := 1; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := Deg1 + Deg2; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } var S : String; begin if I <= Deg1 then begin Str(I, S); ParamName := 'p' + S; end else begin Str(I - Deg1, S); ParamName := 'q' + S; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = p0 B^[1] = p1 B^[2] = p2 ... B^[Deg1 + 1] = q1 B^[Deg1 + 2] = q2 ... -------------------------------------------------------------------- } begin RegFunc := RFrac(X, B, Deg1, Deg2); end; procedure DerivProc(X, Y : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point (X,Y) with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter -------------------------------------------------------------------- } var I : Integer; Den : Float; begin { Compute denominator (1 + q1.x + q2.x^2 + ...) } Den := 0.0; for I := (Deg1 + Deg2) downto Succ(Deg1) do Den := (Den + B^[I]) * X; Den := 1.0 + Den; { dy/dp0 = 1 / (1 + q1.x + q2.x^2 + ...) } D^[0] := 1.0 / Den; { dy/dpi = x^i / (1 + q1.x + q2.x^2 + ...) } for I := 1 to Deg1 do D^[I] := D^[I - 1] * X; { dy/dq1 = -x.y / (1 + q1.x + q2.x^2 + ...) } D^[Deg1 + 1] := - X * Y / Den; { dy/dqi = -x^i.y / (1 + q1.x + q2.x^2 + ...) } for I := (Deg1 + 2) to (Deg1 + Deg2) do D^[I] := D^[I - 1] * X; end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of a rational fraction by linear regression: y = p0 + p1.x + p2.x^2 + ... - q1.(x.y) - q2.(x^2.y) - ... -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- } var I, J : Integer; { Loop variables } M : Integer; { Index of last fitted parameter } U : PMatrix; { Matrix of independent variables } V : PMatrix; { Variance-covariance matrix } begin M := LastParam; DimMatrix(U, M, N); DimMatrix(V, M, M); for J := 1 to N do begin U^[1]^[J] := X^[J]; for I := 2 to Deg1 do U^[I]^[J] := U^[I - 1]^[J] * X^[J]; U^[Deg1 + 1]^[J] := - X^[J] * Y^[J]; for I := (Deg1 + 2) to M do U^[I]^[J] := U^[I - 1]^[J] * X^[J]; end; case Method of 0 : FitModel := MulFit(U, Y, N, M, ConsTerm, B, V); 1 : FitModel := WMulFit(U, Y, W, N, M, ConsTerm, B, V); end; if not ConsTerm then B^[0] := 0.0; DelMatrix(U, M, N); DelMatrix(V, M, M); end; procedure InitModel(CstPar : PVector); { -------------------------------------------------------------------- Initializes the global variables of the unit -------------------------------------------------------------------- CstPar^[0] = Degree of numerator CstPar^[1] = Degree of denominator CstPar^[2] = 1 to include a constant term (p0) -------------------------------------------------------------------- } var D1, D2 : Integer; begin D1 := Round(CstPar^[0]); D2 := Round(CstPar^[1]); if D1 > 0 then Deg1 := D1; if D2 > 0 then Deg2 := D2; ConsTerm := (CstPar^[2] = 1); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/fmath.pas������������������������������������������������0000755�0001750�0001750�00000171614�11326443506�017714� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FMATH.PAS * * Version 2.4 * * (c) J. Debord, June 2001 * ********************************************************************** This unit implements some mathematical functions in Pascal ********************************************************************** Notes: 1) The default real type is DOUBLE (8-byte real). Depending on the compiler, other types may be selected by defining the symbols: ------------------------------------------------------- Symbol Type TP-BP-Delphi FPC GPC ------------------------------------------------------- SINGLEREAL Single X X X PASCALREAL Real X EXTENDEDREAL Extended X X X ------------------------------------------------------- Note: "Real" is equivalent to "Double" in FPC and GPC 2) Error handling: The function MathError returns the error code from the last function evaluation. It must be checked immediately after a function call: Y := f(X); (* f is one of the functions of the library *) if MathError = FN_OK then ... The possible error codes, and the default values attributed to the function, are the following: ------------------------------------------------------------------ Error code Value Significance Function default value ------------------------------------------------------------------ FN_OK 0 No error FN_DOMAIN -1 Argument domain error 0 FN_SING -2 Function singularity +/- MAXNUM FN_OVERFLOW -3 Overflow range error MAXNUM FN_UNDERFLOW -4 Underflow range error 0 ------------------------------------------------------------------ where MAXNUM is a constant defining the highest number which may be represented within the chosen floating point type. The standard functions Exp and Ln have been redefined according to the above conventions as Expo and Log. 3) Assembler functions: some functions are written in assembler. There are two versions: * One for BP 7 or Delphi 1 with a 387, 486 or Pentium processor. This version may be selected by defining the symbol CPU387 * The other for FPC with a Pentium II or Pentium III processor. This version may be selected by defining the symbol CPUP2 Units and programs must be compiled with the options -Si and -Rintel (e.g. ppc386 -Si -Rintel -dCPUP2 fmath) Once you have selected a version you have two possibilities: * Call the Pascal functions (e.g. Expo, ArcSin...). This will provide some acceleration while keeping the error handling. * Call the assembler functions directly (e.g. fExp, fArcSin...) This will provide further acceleration but without error handling. Thus it is the responsibility of the calling program to check the arguments passed to the function. See the interface files MATH387.INT and MATHP2.INT for a list of available functions. ********************************************************************** } unit FMath; interface { ---------------------------------------------------------------------- Floating point type (Default = Double) ---------------------------------------------------------------------- } {$IFDEF __GPC__} {$UNDEF PASCALREAL} {$ENDIF} {$IFDEF FPK} {$UNDEF PASCALREAL} {$ENDIF} {$IFDEF PASCALREAL} {$IFDEF VER120} type Float = Real48; { Delphi 4 } {$ELSE} type Float = Real; {$ENDIF} {$ELSE} {$IFDEF SINGLEREAL} type Float = Single; {$ELSE} {$IFDEF EXTENDEDREAL} type Float = Extended; {$ELSE} {$DEFINE DOUBLEREAL} type Float = Double; {$ENDIF} {$ENDIF} {$ENDIF} { ---------------------------------------------------------------------- Mathematical constants ---------------------------------------------------------------------- } const PI = 3.14159265358979323846; { Pi } LN2 = 0.69314718055994530942; { Ln(2) } LN10 = 2.30258509299404568402; { Ln(10) } LNPI = 1.14472988584940017414; { Ln(Pi) } INVLN2 = 1.44269504088896340736; { 1/Ln(2) } INVLN10 = 0.43429448190325182765; { 1/Ln(10) } TWOPI = 6.28318530717958647693; { 2*Pi } PIDIV2 = 1.57079632679489661923; { Pi/2 } SQRTPI = 1.77245385090551602730; { Sqrt(Pi) } SQRT2PI = 2.50662827463100050242; { Sqrt(2*Pi) } INVSQRT2PI = 0.39894228040143267794; { 1/Sqrt(2*Pi) } LNSQRT2PI = 0.91893853320467274178; { Ln(Sqrt(2*Pi)) } LN2PIDIV2 = 0.91893853320467274178; { Ln(2*Pi)/2 } SQRT2 = 1.41421356237309504880; { Sqrt(2) } SQRT2DIV2 = 0.70710678118654752440; { Sqrt(2)/2 } GOLD = 1.61803398874989484821; { Golden Mean = (1 + Sqrt(5))/2 } CGOLD = 0.38196601125010515179; { 2 - GOLD } { ---------------------------------------------------------------------- Machine-dependent constants ---------------------------------------------------------------------- } {$IFDEF SINGLEREAL} const MACHEP = 1.192093E-7; { Floating point precision: 2^(-23) } MAXNUM = 3.402823E+38; { Max. floating point number: 2^128 } MINNUM = 1.175495E-38; { Min. floating point number: 2^(-126) } MAXLOG = 88.72283; { Max. argument for Exp = Ln(MAXNUM) } MINLOG = -87.33655; { Min. argument for Exp = Ln(MINNUM) } MAXFAC = 33; { Max. argument for Factorial } MAXGAM = 34.648; { Max. argument for Gamma } MAXLGM = 1.0383E+36; { Max. argument for LnGamma } {$ELSE} {$IFDEF DOUBLEREAL} const MACHEP = 2.220446049250313E-16; { 2^(-52) } MAXNUM = 1.797693134862315E+308; { 2^1024 } MINNUM = 2.225073858507202E-308; { 2^(-1022) } MAXLOG = 709.7827128933840; MINLOG = -708.3964185322641; MAXFAC = 170; MAXGAM = 171.624376956302; MAXLGM = 2.556348E+305; {$ELSE} {$IFDEF EXTENDEDREAL} const MACHEP = 1.08420217248550444E-19; { 2^(-63) } MAXNUM = 1.18973149535723103E+4932; { 2^16384 } MINNUM = 3.36210314311209558E-4932; { 2^(-16382) } MAXLOG = 11356.5234062941439; MINLOG = - 11355.137111933024; MAXFAC = 1754; MAXGAM = 1755.455; MAXLGM = 1.04848146839019521E+4928; {$ELSE} {$IFDEF PASCALREAL} const MACHEP = 1.818989404E-12; { 2^(-39) } MAXNUM = 4.253529586E+37; { 2^126 } MINNUM = 2.350988703E-38; { 2^(-125) } MAXLOG = 8.664339757E+01; MINLOG = - 4.253529586E+01; MAXFAC = 33; MAXGAM = 34.64809785; MAXLGM = 1.038324114E+36; {$ENDIF} {$ENDIF} {$ENDIF} {$ENDIF} { ---------------------------------------------------------------------- Error codes for mathematical functions ---------------------------------------------------------------------- } const FN_OK = 0; { No error } FN_DOMAIN = - 1; { Argument domain error } FN_SING = - 2; { Function singularity } FN_OVERFLOW = - 3; { Overflow range error } FN_UNDERFLOW = - 4; { Underflow range error } FN_TLOSS = - 5; { Total loss of precision } FN_PLOSS = - 6; { Partial loss of precision } { ---------------------------------------------------------------------- Global variables and constants ---------------------------------------------------------------------- } const NFACT = 33; { The factorials of the first NFACT integers are stored in a table } var MathErr : Integer; { Error code from the latest function evaluation } FactArray : array[0..NFACT] of Float; { Table of factorials } { ---------------------------------------------------------------------- Functional type ---------------------------------------------------------------------- } type TFunc = function(X : Float) : Float; { ---------------------------------------------------------------------- Error handling function ---------------------------------------------------------------------- } function MathError : Integer; { Error code from the last function call } { ---------------------------------------------------------------------- Minimum, maximum, sign and exchange ---------------------------------------------------------------------- } function FMin(X, Y : Float) : Float; { Minimum of 2 reals } function FMax(X, Y : Float) : Float; { Maximum of 2 reals } function IMin(X, Y : Integer) : Integer; { Minimum of 2 integers } function IMax(X, Y : Integer) : Integer; { Maximum of 2 integers } function Sgn(X : Float) : Integer; { Sign (returns 1 if X = 0) } function Sgn0(X : Float) : Integer; { Sign (returns 0 if X = 0) } procedure FSwap(var X, Y : Float); { Exchange 2 reals } procedure ISwap(var X, Y : Integer); { Exchange 2 integers } { ---------------------------------------------------------------------- Assembler functions ---------------------------------------------------------------------- } {$IFDEF CPU387} {$UNDEF CPUP2} {$I MATH387.INT} {$ENDIF} {$IFDEF CPUP2} {$UNDEF CPU387} {$I MATHP2.INT} {$ENDIF} { ---------------------------------------------------------------------- Sign, logarithms, exponentials and power ---------------------------------------------------------------------- } function Expo(X : Float) : Float; { Exponential } function Exp2(X : Float) : Float; { 2^X } function Exp10(X : Float) : Float; { 10^X } function Log(X : Float) : Float; { Natural log } function Log2(X : Float) : Float; { Log, base 2 } function Log10(X : Float) : Float; { Decimal log } function LogA(X, A : Float) : Float; { Log, base A } function IntPower(X : Float; N : Integer) : Float; { X^N } function Power(X, Y : Float) : Float; { X^Y, X >= 0 } function Pythag(X, Y : Float) : Float; { Sqrt(X^2 + Y^2) } { ---------------------------------------------------------------------- Trigonometric and inverse trigonometric functions ---------------------------------------------------------------------- } function FixAngle(Theta : Float) : Float; { Set Theta in -Pi..Pi } function Tan(X : Float) : Float; { Tangent } function ArcSin(X : Float) : Float; { Arc sinus } function ArcCos(X : Float) : Float; { Arc cosinus } function ArcTan2(Y, X : Float) : Float; { Angle (Ox, OM) with M(X,Y) } procedure SinCos(X : Float; var SinX, CosX : Float); { Sin & Cos } { ---------------------------------------------------------------------- Hyperbolic and inverse hyperbolic functions ---------------------------------------------------------------------- } function Sinh(X : Float) : Float; { Hyperbolic sine } function Cosh(X : Float) : Float; { Hyperbolic cosine } function Tanh(X : Float) : Float; { Hyperbolic tangent } function ArcSinh(X : Float) : Float; { Inverse hyperbolic sine } function ArcCosh(X : Float) : Float; { Inverse hyperbolic cosine } function ArcTanh(X : Float) : Float; { Inverse hyperbolic tangent } procedure SinhCosh(X : Float; var SinhX, CoshX : Float); { Sinh & Cosh } { ---------------------------------------------------------------------- Special functions ---------------------------------------------------------------------- } function Fact(N : Integer) : Float; { Factorial } function Binomial(N, K : Integer) : Float; { Binomial coef. C(N,K) } function Gamma(X : Float) : Float; { Gamma function } function SgnGamma(X : Float) : Integer; { Sign of Gamma function } function LnGamma(X : Float) : Float; { Log(|Gamma(X)|) } function IGamma(A, X : Float) : Float; { Incomplete Gamma function } function JGamma(A, X : Float) : Float; { Complement of IGamma } function Beta(X, Y : Float) : Float; { Beta function } function IBeta(A, B, X : Float) : Float; { Incomplete Beta function } function Erf(X : Float) : Float; { Error function } function Erfc(X : Float) : Float; { Complement of Erf } { ---------------------------------------------------------------------- Binomial distribution with probability P and number of repetitions N ---------------------------------------------------------------------- } function PBinom(N : Integer; P : Float; K : Integer) : Float; { Prob(X = K) } function FBinom(N : Integer; P : Float; K : Integer) : Float; { Prob(X <= K) } { ---------------------------------------------------------------------- Poisson distribution with mean Mu ---------------------------------------------------------------------- } function PPoisson(Mu : Float; K : Integer) : Float; { Prob(X = K) } function FPoisson(Mu : Float; K : Integer) : Float; { Prob(X <= K) } { ---------------------------------------------------------------------- Standard normal distribution ---------------------------------------------------------------------- } function DNorm(X : Float) : Float; { Density of standard normal } function FNorm(X : Float) : Float; { Prob(U <= X) } function PNorm(X : Float) : Float; { Prob(|U| >= |X|) } function InvNorm(P : Float) : Float; { Inverse of FNorm : returns X such that Prob(U <= X) = P} { ---------------------------------------------------------------------- Student distribution with Nu d.o.f. ---------------------------------------------------------------------- } function DStudent(Nu : Integer; X : Float) : Float; { Density of t } function FStudent(Nu : Integer; X : Float) : Float; { Prob(t <= X) } function PStudent(Nu : Integer; X : Float) : Float; { Prob(|t| >= |X|) } { ---------------------------------------------------------------------- Khi-2 distribution with Nu d.o.f. ---------------------------------------------------------------------- } function DKhi2(Nu : Integer; X : Float) : Float; { Density of Khi2 } function FKhi2(Nu : Integer; X : Float) : Float; { Prob(Khi2 <= X) } function PKhi2(Nu : Integer; X : Float) : Float; { Prob(Khi2 >= X) } { ---------------------------------------------------------------------- Fisher-Snedecor distribution with Nu1 and Nu2 d.o.f. ---------------------------------------------------------------------- } function DSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; { Density of F } function FSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; { Prob(F <= X) } function PSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; { Prob(F >= X) } { ---------------------------------------------------------------------- Exponential distribution ---------------------------------------------------------------------- } function DExpo(A, X : Float) : Float; { Density of exponential distrib. } function FExpo(A, X : Float) : Float; { Prob( <= X) } { ---------------------------------------------------------------------- Beta distribution ---------------------------------------------------------------------- } function DBeta(A, B, X : Float) : Float; { Density of Beta distribution } function FBeta(A, B, X : Float) : Float; { Prob( <= X) } { ---------------------------------------------------------------------- Gamma distribution ---------------------------------------------------------------------- } function DGamma(A, B, X : Float) : Float; { Density of Gamma distribution } function FGamma(A, B, X : Float) : Float; { Prob( <= X) } { ---------------------------------------------------------------------- Random numbers ---------------------------------------------------------------------- } procedure RMarIn(Seed1, Seed2 : Integer); { Initializes the random number generator. The default initialization corresponds to RMarIn(1802, 9373) } function IRanMar : LongInt; { Returns a 32 bit random number in [ -2,147,483,648 ; 2,147,483,647 ] } function RanMar : Float; { Returns a random number in [0, 1[ } function RanGaussStd : Float; { Returns a random number from the standard normal distribution (i.e. the Gaussian distribution with zero mean and unit variance) } function RanGauss(Mu, Sigma : Float) : Float; { Returns a random number from a Gaussian distribution with mean Mu and standard deviation Sigma } { ********************************************************************** } implementation { ---------------------------------------------------------------------- Error handling functions ---------------------------------------------------------------------- } function DefaultVal(ErrCode : Integer) : Float; { Sets the global variable MathErr and the function default value according to the error code } begin MathErr := ErrCode; case ErrCode of FN_DOMAIN : DefaultVal := 0.0; FN_SING : DefaultVal := MAXNUM; FN_OVERFLOW : DefaultVal := MAXNUM; FN_UNDERFLOW : DefaultVal := 0.0; else DefaultVal := 0.0; end; end; function MathError : Integer; begin MathError := MathErr; end; { ---------------------------------------------------------------------- Minimum, maximum and sign ---------------------------------------------------------------------- } function FMin(X, Y : Float) : Float; begin if X <= Y then FMin := X else FMin := Y; end; function FMax(X, Y : Float) : Float; begin if X >= Y then FMax := X else FMax := Y; end; function IMin(X, Y : Integer) : Integer; begin if X <= Y then IMin := X else IMin := Y; end; function IMax(X, Y : Integer) : Integer; begin if X >= Y then IMax := X else IMax := Y; end; procedure FSwap(var X, Y : Float); var Temp : Float; begin Temp := X; X := Y; Y := Temp; end; procedure ISwap(var X, Y : Integer); var Temp : Integer; begin Temp := X; X := Y; Y := Temp; end; function Sgn(X : Float) : Integer; begin if X >= 0.0 then Sgn := 1 else Sgn := - 1; end; function Sgn0(X : Float) : Integer; begin if X > 0.0 then Sgn0 := 1 else if X = 0.0 then Sgn0 := 0 else Sgn0 := - 1; end; { ---------------------------------------------------------------------- Assembler functions ---------------------------------------------------------------------- } {$IFDEF CPU387} {$I MATH387.INC} {$DEFINE USE_ASM} {$ENDIF} {$IFDEF CPUP2} {$I MATHP2.INC} {$DEFINE USE_ASM} {$ENDIF} { ---------------------------------------------------------------------- Elementary functions ---------------------------------------------------------------------- } function Expo(X : Float) : Float; begin MathErr := FN_OK; if X < MINLOG then Expo := DefaultVal(FN_UNDERFLOW) else if X > MAXLOG then Expo := DefaultVal(FN_OVERFLOW) else Expo := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(X); end; function Exp2(X : Float) : Float; var XLn2 : Float; begin MathErr := FN_OK; XLn2 := X * LN2; if XLn2 < MINLOG then Exp2 := DefaultVal(FN_UNDERFLOW) else if XLn2 > MAXLOG then Exp2 := DefaultVal(FN_OVERFLOW) else Exp2 := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(XLn2); end; function Exp10(X : Float) : Float; var XLn10 : Float; begin MathErr := FN_OK; XLn10 := X * LN10; if XLn10 < MINLOG then Exp10 := DefaultVal(FN_UNDERFLOW) else if XLn10 > MAXLOG then Exp10 := DefaultVal(FN_OVERFLOW) else Exp10 := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(XLn10); end; function Log(X : Float) : Float; begin MathErr := FN_OK; if X < 0.0 then Log := DefaultVal(FN_DOMAIN) else if X = 0.0 then Log := DefaultVal(FN_SING) else Log := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X); end; function Log10(X : Float) : Float; begin MathErr := FN_OK; if X < 0.0 then Log10 := DefaultVal(FN_DOMAIN) else if X = 0.0 then Log10 := DefaultVal(FN_SING) else Log10 := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) * INVLN10; end; function Log2(X : Float) : Float; begin MathErr := FN_OK; if X < 0.0 then Log2 := DefaultVal(FN_DOMAIN) else if X = 0.0 then Log2 := DefaultVal(FN_SING) else Log2 := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) * INVLN2; end; function LogA(X, A : Float) : Float; begin MathErr := FN_OK; if (X < 0.0) or (A <= 0.0) or (A = 1.0) then LogA := DefaultVal(FN_DOMAIN) else if X = 0.0 then LogA := Sgn(1.0 - A) * DefaultVal(FN_SING) else {$IFDEF USE_ASM} LogA := fLn(X) / fLn(A); {$ELSE} LogA := Ln(X) / Ln(A); {$ENDIF} end; function IntPower(X : Float; N : Integer) : Float; { Computes X^N by repeated multiplications } var M : Integer; T : Float; begin MathErr := FN_OK; if X = 0.0 then begin if N = 0 then { 0^0 = lim x^x = 1 } IntPower := 1.0 { x->0 } else if N > 0 then IntPower := 0.0 { 0^N = 0 } else IntPower := DefaultVal(FN_SING); Exit; end; if N = 0 then begin IntPower := 1.0; Exit; end; { Legendre's algorithm for minimizing the number of multiplications } T := 1.0; M := Abs(N); repeat if Odd(M) then begin Dec(M); T := T * X; end else begin M := M div 2; X := Sqr(X); end; until M = 0; if N > 0 then IntPower := T else IntPower := 1.0 / T; end; function Power(X, Y : Float) : Float; { Computes X^Y = Exp(Y * Ln(X)), for X >= 0 } var YLnX : Float; begin MathErr := FN_OK; if X < 0.0 then begin Power := DefaultVal(FN_DOMAIN); Exit; end; if X = 0.0 then begin if Y = 0.0 then { 0^0 = lim x^x = 1 } Power := 1.0 { x->0 } else if Y > 0.0 then Power := 0.0 { 0^Y = 0 } else Power := DefaultVal(FN_SING); Exit; end; if Y = 0.0 then begin Power := 1.0; Exit; end; YLnX := Y * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X); if YLnX < MINLOG then Power := DefaultVal(FN_UNDERFLOW) else if YLnX > MAXLOG then Power := DefaultVal(FN_OVERFLOW) else Power := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(YLnX); end; function Pythag(X, Y : Float) : Float; { Computes Sqrt(X^2 + Y^2) without destructive underflow or overflow } var AbsX, AbsY : Float; begin MathErr := FN_OK; AbsX := Abs(X); AbsY := Abs(Y); if AbsX > AbsY then Pythag := AbsX * Sqrt(1.0 + Sqr(AbsY / AbsX)) else if AbsY = 0.0 then Pythag := 0.0 else Pythag := AbsY * Sqrt(1.0 + Sqr(AbsX / AbsY)); end; procedure SinCos(X : Float; var SinX, CosX : Float); begin MathErr := FN_OK; SinX := {$IFDEF USE_ASM}fSin{$ELSE}Sin{$ENDIF}(X); CosX := {$IFDEF USE_ASM}fCos{$ELSE}Cos{$ENDIF}(X); end; function FixAngle(Theta : Float) : Float; begin MathErr := FN_OK; while Theta > PI do Theta := Theta - TWOPI; while Theta <= - PI do Theta := Theta + TWOPI; FixAngle := Theta; end; function Tan(X : Float) : Float; var SinX, CosX : Float; begin MathErr := FN_OK; SinX := {$IFDEF USE_ASM}fSin{$ELSE}Sin{$ENDIF}(X); CosX := {$IFDEF USE_ASM}fCos{$ELSE}Cos{$ENDIF}(X); if CosX = 0.0 then Tan := Sgn(SinX) * DefaultVal(FN_SING) else Tan := SinX / CosX; end; function ArcSin(X : Float) : Float; begin MathErr := FN_OK; if (X < - 1.0) or (X > 1.0) then ArcSin := DefaultVal(FN_DOMAIN) else if X = 1.0 then ArcSin := PIDIV2 else if X = - 1.0 then ArcSin := - PIDIV2 else ArcSin := {$IFDEF USE_ASM}fArcTan{$ELSE}ArcTan{$ENDIF}(X / Sqrt(1.0 - Sqr(X))); end; function ArcCos(X : Float) : Float; begin MathErr := FN_OK; if (X < - 1.0) or (X > 1.0) then ArcCos := DefaultVal(FN_DOMAIN) else if X = 1.0 then ArcCos := 0.0 else if X = - 1.0 then ArcCos := PI else ArcCos := PIDIV2 - {$IFDEF USE_ASM}fArcTan{$ELSE}ArcTan{$ENDIF}(X / Sqrt(1.0 - Sqr(X))); end; function ArcTan2(Y, X : Float) : Float; var Theta : Float; begin MathErr := FN_OK; if X = 0.0 then if Y = 0.0 then ArcTan2 := 0.0 else if Y > 0.0 then ArcTan2 := PIDIV2 else ArcTan2 := - PIDIV2 else begin { 4th/1st quadrant -PI/2..PI/2 } Theta := {$IFDEF USE_ASM}fArcTan{$ELSE}ArcTan{$ENDIF}(Y / X); { 2nd/3rd quadrants } if X < 0.0 then if Y >= 0.0 then Theta := Theta + PI { 2nd quadrant: PI/2..PI } else Theta := Theta - PI; { 3rd quadrant: -PI..-PI/2 } ArcTan2 := Theta; end; end; { ---------------------------------------------------------------------- Hyperbolic functions ---------------------------------------------------------------------- } function Sinh(X : Float) : Float; var ExpX : Float; begin MathErr := FN_OK; if (X < MINLOG) or (X > MAXLOG) then Sinh := Sgn(X) * DefaultVal(FN_OVERFLOW) else begin ExpX := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(X); Sinh := 0.5 * (ExpX - 1.0 / ExpX); end; end; function Cosh(X : Float) : Float; var ExpX : Float; begin MathErr := FN_OK; if (X < MINLOG) or (X > MAXLOG) then Cosh := DefaultVal(FN_OVERFLOW) else begin ExpX := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(X); Cosh := 0.5 * (ExpX + 1.0 / ExpX); end; end; procedure SinhCosh(X : Float; var SinhX, CoshX : Float); var ExpX, ExpMinusX : Float; begin MathErr := FN_OK; if (X < MINLOG) or (X > MAXLOG) then begin CoshX := DefaultVal(FN_OVERFLOW); SinhX := Sgn(X) * CoshX; end else begin ExpX := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(X); ExpMinusX := 1.0 / ExpX; SinhX := 0.5 * (ExpX - ExpMinusX); CoshX := 0.5 * (ExpX + ExpMinusX); end; end; function Tanh(X : Float) : Float; var SinhX, CoshX : Float; begin SinhCosh(X, SinhX, CoshX); Tanh := SinhX / CoshX; end; function ArcSinh(X : Float) : Float; begin MathErr := FN_OK; ArcSinh := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X + Sqrt(Sqr(X) + 1.0)); end; function ArcCosh(X : Float) : Float; begin MathErr := FN_OK; if X < 1.0 then ArcCosh := DefaultVal(FN_DOMAIN) else ArcCosh := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X + Sqrt(Sqr(X) - 1.0)); end; function ArcTanh(X : Float) : Float; begin MathErr := FN_OK; if (X < - 1.0) or (X > 1.0) then ArcTanh := DefaultVal(FN_DOMAIN) else if (X = - 1.0) or (X = 1.0) then ArcTanh := Sgn(X) * DefaultVal(FN_SING) else ArcTanh := 0.5 * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}((1.0 + X) / (1.0 - X)); end; { ---------------------------------------------------------------------- Special functions (translated from Cephes math library by S. Moshier: http://www.netlib.org/cephes) ---------------------------------------------------------------------- } const { Used by IGamma and IBeta } BIG = 9.223372036854775808E18; BIGINV = 1.084202172485504434007E-19; type TabCoef = array[0..9] of Float; function PolEvl(var X : Float; var Coef : TabCoef; N : Integer) : Float; { ---------------------------------------------------------------------- Evaluates polynomial of degree N: 2 N y = C + C x + C x +...+ C x 0 1 2 N Coefficients are stored in reverse order: Coef[0] = C , ..., Coef[N] = C N 0 The function P1Evl() assumes that Coef[N] = 1.0 and is omitted from the array. Its calling arguments are otherwise the same as PolEvl(). ---------------------------------------------------------------------- } var Ans : Float; I : Integer; begin Ans := Coef[0]; for I := 1 to N do Ans := Ans * X + Coef[I]; PolEvl := Ans; end; function P1Evl(var X : Float; var Coef : TabCoef; N : Integer) : Float; { ---------------------------------------------------------------------- Evaluate polynomial when coefficient of X is 1.0. Otherwise same as PolEvl. ---------------------------------------------------------------------- } var Ans : Float; I : Integer; begin Ans := X + Coef[0]; for I := 1 to N - 1 do Ans := Ans * X + Coef[I]; P1Evl := Ans; end; function SgnGamma(X : Float) : Integer; begin if X > 0.0 then SgnGamma := 1 else if Odd(Trunc(Abs(X))) then SgnGamma := 1 else SgnGamma := - 1; end; function Stirf(X : Float) : Float; { Stirling's formula for the gamma function Gamma(x) = Sqrt(2*Pi) x^(x-.5) exp(-x) (1 + 1/x P(1/x)) where P(x) is a polynomial } const STIR : TabCoef = ( 7.147391378143610789273E-4, - 2.363848809501759061727E-5, - 5.950237554056330156018E-4, 6.989332260623193171870E-5, 7.840334842744753003862E-4, - 2.294719747873185405699E-4, - 2.681327161876304418288E-3, 3.472222222230075327854E-3, 8.333333333333331800504E-2, 0); var W, P : Float; begin W := 1.0 / X; if X > 1024.0 then begin P := 6.97281375836585777429E-5 * W + 7.84039221720066627474E-4; P := P * W - 2.29472093621399176955E-4; P := P * W - 2.68132716049382716049E-3; P := P * W + 3.47222222222222222222E-3; P := P * W + 8.33333333333333333333E-2; end else P := PolEvl(W, STIR, 8); {$IFDEF USE_ASM} Stirf := SQRT2PI * fExp((X - 0.5) * fLn(X) - X) * (1.0 + W * P); {$ELSE} Stirf := SQRT2PI * Exp((X - 0.5) * Ln(X) - X) * (1.0 + W * P); {$ENDIF} end; function GamSmall(X1, Z : Float) : Float; { Gamma function for small values of the argument } const S : TabCoef = ( - 1.193945051381510095614E-3, 7.220599478036909672331E-3, - 9.622023360406271645744E-3, - 4.219773360705915470089E-2, 1.665386113720805206758E-1, - 4.200263503403344054473E-2, - 6.558780715202540684668E-1, 5.772156649015328608253E-1, 1.000000000000000000000E0, 0); SN : TabCoef = ( 1.133374167243894382010E-3, 7.220837261893170325704E-3, 9.621911155035976733706E-3, - 4.219773343731191721664E-2, - 1.665386113944413519335E-1, - 4.200263503402112910504E-2, 6.558780715202536547116E-1, 5.772156649015328608727E-1, - 1.000000000000000000000E0, 0); var P : Float; begin if X1 = 0.0 then begin GamSmall := DefaultVal(FN_SING); Exit; end; if X1 < 0.0 then begin X1 := - X1; P := PolEvl(X1, SN, 8); end else P := PolEvl(X1, S, 8); GamSmall := Z / (X1 * P); end; function StirfL(X : Float) : Float; { Approximate Ln(Gamma) by Stirling's formula, for X >= 13 } const P : TabCoef = ( 4.885026142432270781165E-3, - 1.880801938119376907179E-3, 8.412723297322498080632E-4, - 5.952345851765688514613E-4, 7.936507795855070755671E-4, - 2.777777777750349603440E-3, 8.333333333333331447505E-2, 0, 0, 0); var Q, W : Float; begin Q := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) * (X - 0.5) - X; Q := Q + LNSQRT2PI; if X > 1.0E+10 then StirfL := Q else begin W := 1.0 / Sqr(X); StirfL := Q + PolEvl(W, P, 6) / X; end; end; function Gamma(X : Float) : Float; const P : TabCoef = ( 4.212760487471622013093E-5, 4.542931960608009155600E-4, 4.092666828394035500949E-3, 2.385363243461108252554E-2, 1.113062816019361559013E-1, 3.629515436640239168939E-1, 8.378004301573126728826E-1, 1.000000000000000000009E0, 0, 0); Q : TabCoef = ( - 1.397148517476170440917E-5, 2.346584059160635244282E-4, - 1.237799246653152231188E-3, - 7.955933682494738320586E-4, 2.773706565840072979165E-2, - 4.633887671244534213831E-2, - 2.243510905670329164562E-1, 4.150160950588455434583E-1, 9.999999999999999999908E-1, 0); var SgnGam, N : Integer; A, X1, Z : Float; begin MathErr := FN_OK; SgnGam := SgnGamma(X); if (X = 0.0) or ((X < 0.0) and (Frac(X) = 0.0)) then begin Gamma := SgnGam * DefaultVal(FN_SING); Exit; end; if X > MAXGAM then begin Gamma := DefaultVal(FN_OVERFLOW); Exit; end; A := Abs(X); if A > 13.0 then begin if X < 0.0 then begin N := Trunc(A); Z := A - N; if Z > 0.5 then begin N := N + 1; Z := A - N; end; Z := Abs(A * {$IFDEF USE_ASM}fSin{$ELSE}Sin{$ENDIF}(PI * Z)) * Stirf(A); if Z <= PI / MAXNUM then begin Gamma := SgnGam * DefaultVal(FN_OVERFLOW); Exit; end; Z := PI / Z; end else Z := Stirf(X); Gamma := SgnGam * Z; end else begin Z := 1.0; X1 := X; while X1 >= 3.0 do begin X1 := X1 - 1.0; Z := Z * X1; end; while X1 < - 0.03125 do begin Z := Z / X1; X1 := X1 + 1.0; end; if X1 <= 0.03125 then Gamma := GamSmall(X1, Z) else begin while X1 < 2.0 do begin Z := Z / X1; X1 := X1 + 1.0; end; if (X1 = 2.0) or (X1 = 3.0) then Gamma := Z else begin X1 := X1 - 2.0; Gamma := Z * PolEvl(X1, P, 7) / PolEvl(X1, Q, 8); end; end; end; end; function LnGamma(X : Float) : Float; const P : TabCoef = ( - 2.163690827643812857640E3, - 8.723871522843511459790E4, - 1.104326814691464261197E6, - 6.111225012005214299996E6, - 1.625568062543700591014E7, - 2.003937418103815175475E7, - 8.875666783650703802159E6, 0, 0, 0); Q : TabCoef = ( - 5.139481484435370143617E2, - 3.403570840534304670537E4, - 6.227441164066219501697E5, - 4.814940379411882186630E6, - 1.785433287045078156959E7, - 3.138646407656182662088E7, - 2.099336717757895876142E7, 0, 0, 0); var N : Integer; A, X1, Z : Float; begin MathErr := FN_OK; if (X = 0.0) or ((X < 0.0) and (Frac(X) = 0.0)) then begin LnGamma := DefaultVal(FN_SING); Exit; end; if X > MAXLGM then begin LnGamma := DefaultVal(FN_OVERFLOW); Exit; end; A := Abs(X); if A > 34.0 then begin if X < 0.0 then begin N := Trunc(A); Z := A - N; if Z > 0.5 then begin N := N + 1; Z := N - A; end; Z := A * {$IFDEF USE_ASM}fSin{$ELSE}Sin{$ENDIF}(PI * Z); if Z = 0.0 then begin LnGamma := DefaultVal(FN_OVERFLOW); Exit; end; Z := LNPI - {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(Z) - StirfL(A); end else Z := StirfL(X); LnGamma := Z; end else if X < 13.0 then begin Z := 1.0; X1 := X; while X1 >= 3 do begin X1 := X1 - 1.0; Z := Z * X1; end; while X1 < 2.0 do begin if Abs(X1) <= 0.03125 then begin LnGamma := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(Abs(GamSmall(X1, Z))); Exit; end; Z := Z / X1; X1 := X1 + 1.0; end; if Z < 0.0 then Z := - Z; if X1 = 2.0 then LnGamma := {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(Z) else begin X1 := X1 - 2.0; LnGamma := X1 * PolEvl(X1, P, 6) / P1Evl(X1, Q, 7) + {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(Z); end; end else LnGamma := StirfL(X); end; function IGamma(A, X : Float) : Float; var Ans, Ax, C, R : Float; begin MathErr := FN_OK; if (X <= 0.0) or (A <= 0.0) then begin IGamma := 0.0; Exit; end; if (X > 1.0) and (X > A) then begin IGamma := 1.0 - JGamma(A, X); Exit; end; Ax := A * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) - X - LnGamma(A); if Ax < MINLOG then begin IGamma := DefaultVal(FN_UNDERFLOW); Exit; end; Ax := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(Ax); { power series } R := A; C := 1.0; Ans := 1.0; repeat R := R + 1.0; C := C * X / R; Ans := Ans + C; until C / Ans <= MACHEP; IGamma := Ans * Ax / A; end; function JGamma(A, X : Float) : Float; var Ans, C, Yc, Ax, Y, Z, R, T, Pk, Pkm1, Pkm2, Qk, Qkm1, Qkm2 : Float; begin MathErr := FN_OK; if (X <= 0.0) or (A <= 0.0) then begin JGamma := 1.0; Exit; end; if (X < 1.0) or (X < A) then begin JGamma := 1.0 - IGamma(A, X); Exit; end; Ax := A * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) - X - LnGamma(A); if Ax < MINLOG then begin JGamma := DefaultVal(FN_UNDERFLOW); Exit; end; Ax := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(Ax); { continued fraction } Y := 1.0 - A; Z := X + Y + 1.0; C := 0.0; Pkm2 := 1.0; Qkm2 := X; Pkm1 := X + 1.0; Qkm1 := Z * X; Ans := Pkm1 / Qkm1; repeat C := C + 1.0; Y := Y + 1.0; Z := Z + 2.0; Yc := Y * C; Pk := Pkm1 * Z - Pkm2 * Yc; Qk := Qkm1 * Z - Qkm2 * Yc; if Qk <> 0.0 then begin R := Pk / Qk; T := Abs((Ans - R) / R); Ans := R; end else T := 1.0; Pkm2 := Pkm1; Pkm1 := Pk; Qkm2 := Qkm1; Qkm1 := Qk; if Abs(Pk) > BIG then begin Pkm2 := Pkm2 / BIG; Pkm1 := Pkm1 / BIG; Qkm2 := Qkm2 / BIG; Qkm1 := Qkm1 / BIG; end; until T <= MACHEP; JGamma := Ans * Ax; end; function Fact(N : Integer) : Float; begin MathErr := FN_OK; if N < 0 then Fact := DefaultVal(FN_DOMAIN) else if N > MAXFAC then Fact := DefaultVal(FN_OVERFLOW) else if N <= NFACT then Fact := FactArray[N] else Fact := Gamma(N + 1); end; function Binomial(N, K : Integer) : Float; var I, N1 : Integer; Prod : Float; begin MathErr := FN_OK; if K < 0 then Binomial := 0.0 else if (K = 0) or (K = N) then Binomial := 1.0 else if (K = 1) or (K = N - 1) then Binomial := N else begin if K > N - K then K := N - K; N1 := Succ(N); Prod := N; for I := 2 to K do Prod := Prod * (Int(N1 - I) / Int(I)); Binomial := Int(0.5 + Prod); end; end; function Beta(X, Y : Float) : Float; { Computes Beta(X, Y) = Gamma(X) * Gamma(Y) / Gamma(X + Y) } var Lx, Ly, Lxy : Float; SgnBeta : Integer; begin MathErr := FN_OK; SgnBeta := SgnGamma(X) * SgnGamma(Y) * SgnGamma(X + Y); Lxy := LnGamma(X + Y); if MathErr <> FN_OK then begin Beta := 0.0; Exit; end; Lx := LnGamma(X); if MathErr <> FN_OK then begin Beta := SgnBeta * MAXNUM; Exit; end; Ly := LnGamma(Y); if MathErr <> FN_OK then begin Beta := SgnBeta * MAXNUM; Exit; end; Beta := SgnBeta * {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(Lx + Ly - Lxy); end; function PSeries(A, B, X : Float) : Float; { Power series for incomplete beta integral. Use when B*X is small } var S, T, U, V, T1, Z, Ai : Float; N : Integer; begin Ai := 1.0 / A; U := (1.0 - B) * X; V := U / (A + 1.0); T1 := V; T := U; N := 2; S := 0.0; Z := MACHEP * Ai; while Abs(V) > Z do begin U := (N - B) * X / N; T := T * U; V := T / (A + N); S := S + V; N := N + 1; end; S := S + T1; S := S + Ai; U := A * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X); if (A + B < MAXGAM) and (Abs(U) < MAXLOG) then begin T := Gamma(A + B) / (Gamma(A) * Gamma(B)); S := S * T * Power(X, A); end else begin T := LnGamma(A + B) - LnGamma(A) - LnGamma(B) + U + {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(S); if T < MINLOG then S := 0.0 else S := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(T); end; PSeries := S; end; function CFrac1(A, B, X : Float) : Float; { Continued fraction expansion #1 for incomplete beta integral } var Xk, Pk, Pkm1, Pkm2, Qk, Qkm1, Qkm2, K1, K2, K3, K4, K5, K6, K7, K8, R, T, Ans, Thresh : Float; N : Integer; label CDone; begin K1 := A; K2 := A + B; K3 := A; K4 := A + 1.0; K5 := 1.0; K6 := B - 1.0; K7 := K4; K8 := A + 2.0; Pkm2 := 0.0; Qkm2 := 1.0; Pkm1 := 1.0; Qkm1 := 1.0; Ans := 1.0; R := 1.0; N := 0; Thresh := 3.0 * MACHEP; repeat Xk := - (X * K1 * K2) / (K3 * K4); Pk := Pkm1 + Pkm2 * Xk; Qk := Qkm1 + Qkm2 * Xk; Pkm2 := Pkm1; Pkm1 := Pk; Qkm2 := Qkm1; Qkm1 := Qk; Xk := (X * K5 * K6) / (K7 * K8); Pk := Pkm1 + Pkm2 * Xk; Qk := Qkm1 + Qkm2 * Xk; Pkm2 := Pkm1; Pkm1 := Pk; Qkm2 := Qkm1; Qkm1 := Qk; if Qk <> 0.0 then R := Pk / Qk; if R <> 0.0 then begin T := Abs((Ans - R) / R); Ans := R; end else T := 1.0; if T < Thresh then goto CDone; K1 := K1 + 1.0; K2 := K2 + 1.0; K3 := K3 + 2.0; K4 := K4 + 2.0; K5 := K5 + 1.0; K6 := K6 - 1.0; K7 := K7 + 2.0; K8 := K8 + 2.0; if Abs(Qk) + Abs(Pk) > BIG then begin Pkm2 := Pkm2 * BIGINV; Pkm1 := Pkm1 * BIGINV; Qkm2 := Qkm2 * BIGINV; Qkm1 := Qkm1 * BIGINV; end; if (Abs(Qk) < BIGINV) or (Abs(Pk) < BIGINV) then begin Pkm2 := Pkm2 * BIG; Pkm1 := Pkm1 * BIG; Qkm2 := Qkm2 * BIG; Qkm1 := Qkm1 * BIG; end; N := N + 1; until N > 400; MathErr := FN_PLOSS; CDone: CFrac1 := Ans; end; function CFrac2(A, B, X : Float) : Float; { Continued fraction expansion #2 for incomplete beta integral } var Xk, Pk, Pkm1, Pkm2, Qk, Qkm1, Qkm2, K1, K2, K3, K4, K5, K6, K7, K8, R, T, Z, Ans, Thresh : Float; N : Integer; label CDone; begin K1 := A; K2 := B - 1.0; K3 := A; K4 := A + 1.0; K5 := 1.0; K6 := A + B; K7 := A + 1.0; K8 := A + 2.0; Pkm2 := 0.0; Qkm2 := 1.0; Pkm1 := 1.0; Qkm1 := 1.0; Z := X / (1.0 - X); Ans := 1.0; R := 1.0; N := 0; Thresh := 3.0 * MACHEP; repeat Xk := - (Z * K1 * K2) / (K3 * K4); Pk := Pkm1 + Pkm2 * Xk; Qk := Qkm1 + Qkm2 * Xk; Pkm2 := Pkm1; Pkm1 := Pk; Qkm2 := Qkm1; Qkm1 := Qk; Xk := (Z * K5 * K6) / (K7 * K8); Pk := Pkm1 + Pkm2 * Xk; Qk := Qkm1 + Qkm2 * Xk; Pkm2 := Pkm1; Pkm1 := Pk; Qkm2 := Qkm1; Qkm1 := Qk; if Qk <> 0.0 then R := Pk / Qk; if R <> 0.0 then begin T := Abs((Ans - R) / R); Ans := R; end else T := 1.0; if T < Thresh then goto CDone; K1 := K1 + 1.0; K2 := K2 - 1.0; K3 := K3 + 2.0; K4 := K4 + 2.0; K5 := K5 + 1.0; K6 := K6 + 1.0; K7 := K7 + 2.0; K8 := K8 + 2.0; if Abs(Qk) + Abs(Pk) > BIG then begin Pkm2 := Pkm2 * BIGINV; Pkm1 := Pkm1 * BIGINV; Qkm2 := Qkm2 * BIGINV; Qkm1 := Qkm1 * BIGINV; end; if (Abs(Qk) < BIGINV) or (Abs(Pk) < BIGINV) then begin Pkm2 := Pkm2 * BIG; Pkm1 := Pkm1 * BIG; Qkm2 := Qkm2 * BIG; Qkm1 := Qkm1 * BIG; end; N := N + 1; until N > 400; MathErr := FN_PLOSS; CDone: CFrac2 := Ans; end; function IBeta(A, B, X : Float) : Float; var A1, B1, X1, T, W, Xc, Y : Float; Flag : Boolean; label Done; begin MathErr := FN_OK; if (A <= 0.0) or (B <= 0.0) or (X < 0.0) or (X > 1.0) then begin IBeta := DefaultVal(FN_DOMAIN); Exit; end; if (X = 0.0) or (X = 1.0) then begin IBeta := X; Exit; end; Flag := False; if (B * X <= 1.0) and (X <= 0.95) then begin T := PSeries(A, B, X); goto Done; end; W := 1.0 - X; { Reverse a and b if x is greater than the mean. } if X > A / (A + B) then begin Flag := True; A1 := B; B1 := A; Xc := X; X1 := W; end else begin A1 := A; B1 := B; Xc := W; X1 := X; end; if Flag and (B1 * X1 <= 1.0) and (X1 <= 0.95) then begin T := PSeries(A1, B1, X1); goto Done; end; { Choose expansion for optimal convergence } Y := X1 * (A1 + B1 - 2.0) - (A1 - 1.0); if Y < 0.0 then W := CFrac1(A1, B1, X1) else W := CFrac2(A1, B1, X1) / Xc; { Multiply w by the factor a b _ _ _ x (1-x) | (a+b) / ( a | (a) | (b) ) } Y := A1 * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X1); T := B1 * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(Xc); if (A1 + B1 < MAXGAM) and (Abs(Y) < MAXLOG) and (Abs(T) < MAXLOG) then begin T := Power(Xc, B1) ; T := T * Power(X1, A1); T := T / A1; T := T * W; T := T * Gamma(A1 + B1) / (Gamma(A1) * Gamma(B1)); end else begin { Resort to logarithms } Y := Y + T + LnGamma(A1 + B1) - LnGamma(A1) - LnGamma(B1) + {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(W / A1); if Y < MINLOG then T := 0.0 else T := {$IFDEF USE_ASM}fExp{$ELSE}Exp{$ENDIF}(Y); end; Done: if Flag then if T <= MACHEP then T := 1.0 - MACHEP else T := 1.0 - T; IBeta := T; end; function Erf(X : Float) : Float; begin if X < 0.0 then Erf := - IGamma(0.5, Sqr(X)) else Erf := IGamma(0.5, Sqr(X)); end; function Erfc(X : Float) : Float; begin if X < 0.0 then Erfc := 1.0 + IGamma(0.5, Sqr(X)) else Erfc := JGamma(0.5, Sqr(X)); end; { ---------------------------------------------------------------------- Probability functions ---------------------------------------------------------------------- } function PBinom(N : Integer; P : Float; K : Integer) : Float; begin MathErr := FN_OK; if (P < 0.0) or (P > 1.0) or (N <= 0) or (N < K) then PBinom := DefaultVal(FN_DOMAIN) else if K = 0 then PBinom := IntPower(1.0 - P, N) else if K = N then PBinom := IntPower(P, N) else PBinom := Binomial(N, K) * IntPower(P, K) * IntPower(1.0 - P, N - K); end; function FBinom(N : Integer; P : Float; K : Integer) : Float; begin MathErr := FN_OK; if (P < 0.0) or (P > 1.0) or (N <= 0) or (N < K) then FBinom := DefaultVal(FN_DOMAIN) else if K = 0 then FBinom := IntPower(1.0 - P, N) else if K = N then FBinom := 1.0 else FBinom := 1.0 - IBeta(K + 1, N - K, P); end; function PPoisson(Mu : Float; K : Integer) : Float; var P : Float; I : Integer; begin MathErr := FN_OK; if (Mu <= 0.0) or (K < 0) then PPoisson := DefaultVal(FN_DOMAIN) else if K = 0 then PPoisson := Expo(- Mu) else begin P := Mu; for I := 2 to K do P := P * Mu / I; PPoisson := Expo(- Mu) * P; end; end; function FPoisson(Mu : Float; K : Integer) : Float; begin MathErr := FN_OK; if (Mu <= 0.0) or (K < 0) then FPoisson := DefaultVal(FN_DOMAIN) else if K = 0 then FPoisson := Expo(- Mu) else FPoisson := JGamma(K + 1, Mu); end; function DNorm(X : Float) : Float; begin DNorm := INVSQRT2PI * Expo(- 0.5 * Sqr(X)); end; function FNorm(X : Float) : Float; begin FNorm := 0.5 * (1.0 + Erf(X * SQRT2DIV2)); end; function InvNorm(P : Float) : Float; { ---------------------------------------------------------------------- Inverse of Normal distribution function Returns the argument, X, for which the area under the Gaussian probability density function (integrated from minus infinity to X) is equal to P. Translated from Cephes library. ---------------------------------------------------------------------- } const P0 : TabCoef = ( 8.779679420055069160496E-3, - 7.649544967784380691785E-1, 2.971493676711545292135E0, - 4.144980036933753828858E0, 2.765359913000830285937E0, - 9.570456817794268907847E-1, 1.659219375097958322098E-1, - 1.140013969885358273307E-2, 0, 0); Q0 : TabCoef = ( - 5.303846964603721860329E0, 9.908875375256718220854E0, - 9.031318655459381388888E0, 4.496118508523213950686E0, - 1.250016921424819972516E0, 1.823840725000038842075E-1, - 1.088633151006419263153E-2, 0, 0, 0); P1 : TabCoef = ( 4.302849750435552180717E0, 4.360209451837096682600E1, 9.454613328844768318162E1, 9.336735653151873871756E1, 5.305046472191852391737E1, 1.775851836288460008093E1, 3.640308340137013109859E0, 3.691354900171224122390E-1, 1.403530274998072987187E-2, 1.377145111380960566197E-4); Q1 : TabCoef = ( 2.001425109170530136741E1, 7.079893963891488254284E1, 8.033277265194672063478E1, 5.034715121553662712917E1, 1.779820137342627204153E1, 3.845554944954699547539E0, 3.993627390181238962857E-1, 1.526870689522191191380E-2, 1.498700676286675466900E-4, 0); P2 : TabCoef = ( 3.244525725312906932464E0, 6.856256488128415760904E0, 3.765479340423144482796E0, 1.240893301734538935324E0, 1.740282292791367834724E-1, 9.082834200993107441750E-3, 1.617870121822776093899E-4, 7.377405643054504178605E-7, 0, 0); Q2 : TabCoef = ( 6.021509481727510630722E0, 3.528463857156936773982E0, 1.289185315656302878699E0, 1.874290142615703609510E-1, 9.867655920899636109122E-3, 1.760452434084258930442E-4, 8.028288500688538331773E-7, 0, 0, 0); P3 : TabCoef = ( 2.020331091302772535752E0, 2.133020661587413053144E0, 2.114822217898707063183E-1, - 6.500909615246067985872E-3, - 7.279315200737344309241E-4, - 1.275404675610280787619E-5, - 6.433966387613344714022E-8, - 7.772828380948163386917E-11, 0, 0); Q3 : TabCoef = ( 2.278210997153449199574E0, 2.345321838870438196534E-1, - 6.916708899719964982855E-3, - 7.908542088737858288849E-4, - 1.387652389480217178984E-5, - 7.001476867559193780666E-8, - 8.458494263787680376729E-11, 0, 0, 0); var X, Y, Z, Y2, X0, X1 : Float; Code : Integer; begin if (P <= 0.0) or (P >= 1.0) then begin InvNorm := DefaultVal(FN_DOMAIN); Exit; end; Code := 1; Y := P; if Y > (1.0 - 0.13533528323661269189) then { 0.135... = exp(-2) } begin Y := 1.0 - Y; Code := 0; end; if Y > 0.13533528323661269189 then begin Y := Y - 0.5; Y2 := Y * Y; X := Y + Y * (Y2 * PolEvl(Y2, P0, 7) / P1Evl(Y2, Q0, 7)); X := X * SQRT2PI; InvNorm := X; Exit; end; X := Sqrt(- 2.0 * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(Y)); X0 := X - {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) / X; Z := 1.0 / X; if X < 8.0 then X1 := Z * PolEvl(Z, P1, 9) / P1Evl(Z, Q1, 9) else if X < 32.0 then X1 := Z * PolEvl(Z, P2, 7) / P1Evl(Z, Q2, 7) else X1 := Z * PolEvl(Z, P3, 7) / P1Evl(Z, Q3, 7); X := X0 - X1; if Code <> 0 then X := - X; InvNorm := X; end; function PNorm(X : Float) : Float; var A : Float; begin A := Abs(X); MathErr := FN_OK; if A = 0.0 then PNorm := 1.0 else if A < 1.0 then PNorm := 1.0 - Erf(A * SQRT2DIV2) else PNorm := Erfc(A * SQRT2DIV2); end; function DStudent(Nu : Integer; X : Float) : Float; var L, P, Q : Float; begin MathErr := FN_OK; if Nu < 1 then DStudent := DefaultVal(FN_DOMAIN) else begin P := 0.5 * (Nu + 1); Q := 0.5 * Nu; L := LnGamma(P) - LnGamma(Q) - 0.5 * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(Nu * PI) - P * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(1.0 + Sqr(X) / Nu); DStudent := Expo(L); end; end; function FStudent(Nu : Integer; X : Float) : Float; begin MathErr := FN_OK; if Nu < 1 then FStudent := DefaultVal(FN_DOMAIN) else FStudent := 1.0 - IBeta(0.5 * Nu, 0.5, Nu / (Nu + Sqr(X))); end; function PStudent(Nu : Integer; X : Float) : Float; begin MathErr := FN_OK; if Nu < 1 then PStudent := DefaultVal(FN_DOMAIN) else PStudent := IBeta(0.5 * Nu, 0.5, Nu / (Nu + Sqr(X))); end; function DKhi2(Nu : Integer; X : Float) : Float; begin MathErr := FN_OK; DKhi2 := DGamma(0.5 * Nu, 0.5, X); end; function FKhi2(Nu : Integer; X : Float) : Float; begin MathErr := FN_OK; if (Nu < 1) or (X <= 0.0) then FKhi2 := DefaultVal(FN_DOMAIN) else FKhi2 := IGamma(0.5 * Nu, 0.5 * X); end; function PKhi2(Nu : Integer; X : Float) : Float; begin MathErr := FN_OK; if (Nu < 1) or (X <= 0.0) then PKhi2 := DefaultVal(FN_DOMAIN) else PKhi2 := JGamma(0.5 * Nu, 0.5 * X); end; function DSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; var P1, P2, R, S, L : Float; begin MathErr := FN_OK; if (Nu1 < 1) or (Nu2 < 1) or (X <= 0.0) then DSnedecor := DefaultVal(FN_DOMAIN) else begin R := Int(Nu1) / Int(Nu2); P1 := 0.5 * Nu1; P2 := 0.5 * Nu2; S := P1 + P2; L := LnGamma(S) - LnGamma(P1) - LnGamma(P2) + P1 * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(R); L := L + (P1 - 1.0) * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) - S * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(1.0 + R * X); DSnedecor := Expo(L); end; end; function FSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; begin MathErr := FN_OK; if (Nu1 < 1) or (Nu2 < 1) or (X <= 0.0) then FSnedecor := DefaultVal(FN_DOMAIN) else FSnedecor := 1.0 - IBeta(0.5 * Nu2, 0.5 * Nu1, Nu2 / (Nu2 + Nu1 * X)); end; function PSnedecor(Nu1, Nu2 : Integer; X : Float) : Float; begin MathErr := FN_OK; if (Nu1 < 1) or (Nu2 < 1) or (X <= 0.0) then PSnedecor := DefaultVal(FN_DOMAIN) else PSnedecor := IBeta(0.5 * Nu2, 0.5 * Nu1, Nu2 / (Nu2 + Nu1 * X)); end; function DExpo(A, X : Float) : Float; begin if (A <= 0.0) or (X < 0.0) then DExpo := DefaultVal(FN_DOMAIN) else DExpo := A * Expo(- A * X); end; function FExpo(A, X : Float) : Float; begin if (A <= 0.0) or (X < 0.0) then FExpo := DefaultVal(FN_DOMAIN) else FExpo := 1.0 - Expo(- A * X); end; function DBeta(A, B, X : Float) : Float; var L : Float; begin MathErr := FN_OK; if (A <= 0.0) or (B <= 0.0) or (X < 0.0) or (X > 1.0) then DBeta := DefaultVal(FN_DOMAIN) else if X = 0.0 then if A < 1.0 then DBeta := DefaultVal(FN_SING) else DBeta := 0.0 else if X = 1.0 then if B < 1.0 then DBeta := DefaultVal(FN_SING) else DBeta := 0.0 else begin L := LnGamma(A + B) - LnGamma(A) - LnGamma(B); L := L + (A - 1.0) * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) + (B - 1.0) * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(1.0 - X); DBeta := Expo(L); end; end; function FBeta(A, B, X : Float) : Float; begin FBeta := IBeta(A, B, X); end; function DGamma(A, B, X : Float) : Float; var L : Float; begin MathErr := FN_OK; if (A <= 0.0) or (B <= 0.0) or (X < 0.0) then DGamma := DefaultVal(FN_DOMAIN) else if X = 0.0 then if A < 1.0 then DGamma := DefaultVal(FN_SING) else if A = 1.0 then DGamma := B else DGamma := 0.0 else begin L := A * Ln(B) - LnGamma(A) + (A - 1.0) * {$IFDEF USE_ASM}fLn{$ELSE}Ln{$ENDIF}(X) - B * X; DGamma := Expo(L); end; end; function FGamma(A, B, X : Float) : Float; begin FGamma := IGamma(A, B * X); end; { ---------------------------------------------------------------------- Random numbers ---------------------------------------------------------------------- } var X1, X2, C1, C2 : LongInt; procedure RMarIn(Seed1, Seed2 : Integer); begin X1 := Seed1; X2 := Seed2; C1 := 0; C2 := 0; end; function IRanMar : LongInt; var Y1, Y2 : LongInt; begin Y1 := 18000 * X1 + C1; X1 := Y1 and 65535; C1 := Y1 shr 16; Y2 := 30903 * X2 + C2; X2 := Y2 and 65535; C2 := Y2 shr 16; IRanMar := (X1 shl 16) + (X2 and 65535); end; function RanMar : Float; begin RanMar := (IRanMar + 2147483648.0) / 4294967296.0; end; function RanGaussStd : Float; { Computes 2 random numbers from the standard normal distribution, returns one and saves the other for the next call } const Gauss_Save : Float = 0.0; { Saves a random number } Gauss_Set : Boolean = False; { Flags if a number has been saved } var R, Theta, SinTheta, CosTheta : Float; begin if not Gauss_Set then begin R := Sqrt(- 2.0 * Log(RanMar)); Theta := TWOPI * RanMar; SinCos(Theta, SinTheta, CosTheta); RanGaussStd := R * CosTheta; { Return 1st number } Gauss_Save := R * SinTheta; { Save 2nd number } end else RanGaussStd := Gauss_Save; { Return saved number } Gauss_Set := not Gauss_Set; end; function RanGauss(Mu, Sigma : Float) : Float; { Returns a random number from the normal distribution with mean Mu and standard deviation Sigma } begin RanGauss := Mu + Sigma * RanGaussStd; end; { ---------------------------------------------------------------------- Initialization code ---------------------------------------------------------------------- } var I : Integer; begin { Initialize MathErr } MathErr := FN_OK; { Store the factorials of the first NFACT integers in a table } FactArray[0] := 1.0; FactArray[1] := 1.0; FactArray[2] := 2.0; for I := 3 to NFACT do FactArray[I] := FactArray[I - 1] * I; { Initialize random number generator } RMarIn(1802, 9373); end. ��������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/fitpka.pas�����������������������������������������������0000755�0001750�0001750�00000012532�11326443506�020064� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITPKA.PAS * * Version 1.1 * * (c) J. Debord, July 1999 * ********************************************************************** This unit fits the acid/base titration function : B - A y = A + ---------------- 1 + 10^(pKa - x) where x is pH y is some property (e.g. absorbance) which depends on the ratio of the acidic and basic forms of the compound A is the property for the pure acidic form B is the property for the pure basic form pKa is the acidity constant ********************************************************************** } unit FitPKa; {$F+} interface uses FMath, Matrices, Stat, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X : Float; B, D : PVector); function FitModel(X, Y : PVector; N : Integer; B : PVector) : Integer; implementation function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } begin FuncName := 'y = A + (B - A) / [1 + 10^(pKa - x)]' end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted (0 if there is a constant term A, 1 otherwise) -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 2; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'A'; 1 : ParamName := 'B'; 2 : ParamName := 'pKa'; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = A B^[1] = B B^[2] = pKa -------------------------------------------------------------------- } begin RegFunc := B^[0] + (B^[1] - B^[0]) / (1.0 + Exp10(B^[2] - X)); end; procedure DerivProc(X : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point X with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter. -------------------------------------------------------------------- } var Q, R : Float; begin Q := Exp10(B^[2] - X); { 10^(pKa - x) } R := 1.0 / (1.0 + Q); { 1/[1 + 10^(pKa - x)] } D^[0] := 1.0 - R; { dy/dA = 1 - 1/[1 + 10^(pKa - x)] } D^[1] := R; { dy/dB = 1/[1 + 10^(pKa - x)] } { dy/dpKa = (A-B).10^(pKa - x).Ln(10) / [1 + 10^(pKa - x)]^2 } D^[2] := (B^[0] - B^[1]) * Q * LN10 * Sqr(R); end; procedure SortPoints(X, Y : PVector; N : Integer); { ---------------------------------------------------------------------- Sort points by increasing X values ---------------------------------------------------------------------- } var I, J, K : Integer; A : Float; begin for I := 1 to Pred(N) do begin K := I; A := X^[I]; for J := Succ(I) to N do if X^[J] < A then begin K := J; A := X^[J]; end; FSwap(X^[I], X^[K]); FSwap(Y^[I], Y^[K]); end; end; function FitModel(X, Y : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of the acid/base titration function -------------------------------------------------------------------- Input : X, Y = point coordinates N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- } var K : Integer; { Loop variable } Z : Float; { (A + B) / 2 } begin SortPoints(X, Y, N); B^[0] := Y^[1]; B^[1] := Y^[N]; Z := 0.5 * (B^[0] + B^[1]); for K := 2 to N - 1 do if Y^[K] = Z then B^[2] := X^[K] else if ((Y^[K] < Z) and (Y^[K + 1] > Z)) or ((Y^[K] > Z) and (Y^[K + 1] < Z)) then B^[2] := 0.5 * (X^[K] + X^[K + 1]); FitModel := 0; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/Regress.pas����������������������������������������������0000755�0001750�0001750�00000132600�11326443506�020217� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit REGRESS.PAS * * Version 2.2 * * (c) J. Debord, August 2000 * ********************************************************************** Regression routines ********************************************************************** } unit Regress; interface uses FMath, Matrices, Eigen, Optim, SimOpt, Stat,dialogs; { ********************************************************************** Type definitions ********************************************************************** } { Algorithm for linear regression } type TRegAlgo = ( GAUSS_JORDAN, { Gauss-Jordan solution of normal equations } SVD); { Singular value decomposition } { Optimization algorithm for nonlinear regression } type TOptAlgo = ( NL_MARQ, { Marquardt algorithm } NL_SIMP, { Simplex algorithm } NL_BFGS, { BFGS algorithm } NL_SA); { Simulated annealing } { Regression modes } type TRegMode = (UNWEIGHTED, WEIGHTED); { Regression function } type TRegFunc = function(X : Float; B : PVector) : Float; { Procedure to compute the derivatives of the regression function with respect to the regression parameters } type TDerivProc = procedure(RegFunc : TRegFunc; X, Y : Float; B, D : PVector); { Test of regression } type TRegTest = record Vr, { Residual variance } R2, { Coefficient of determination } R2a, { Adjusted coeff. of determination } F, { Variance ratio (explained/residual) } Prob : Float; { Probability of F } end; { ********************************************************************** Procedures to modify the regression settings ********************************************************************** } procedure SetRegAlgo(Algo : TRegAlgo); { ---------------------------------------------------------------------- Sets the linear regression algorithm according to Algo, which must be GAUSS_JORDAN or SVD. The default algorithm is SVD. ---------------------------------------------------------------------- } procedure SetOptAlgo(Algo : TOptAlgo); { ---------------------------------------------------------------------- Sets the optimization algorithm according to Algo, which must be NL_MARQ, NL_SIMP, NL_BFGS or NL_SA. The default algorithm is NL_MARQ. ---------------------------------------------------------------------- } procedure SetFirstPoint(Index : Integer); { ---------------------------------------------------------------------- Sets the index of the first data point (usually 0 or 1). The default value is 1. ---------------------------------------------------------------------- } function GetRegAlgo : TRegAlgo; { ---------------------------------------------------------------------- Returns the linear regression algorithm ---------------------------------------------------------------------- } function GetOptAlgo : TOptAlgo; { ---------------------------------------------------------------------- Returns the optimization algorithm ---------------------------------------------------------------------- } function GetFirstPoint : Integer; { ---------------------------------------------------------------------- Returns the index of the first data point ---------------------------------------------------------------------- } { ********************************************************************** Unweighted regression routines ********************************************************************** These routines fit equations to data by minimizing the sum of squared residuals : SS = Sum [y(k) - ycalc(k)]^2 where y(k) and ycalc(k) are respectively the observed and calculated value of the dependent variable for observation k. ycalc(k) is a function of the regression parameters b(0), b(1) ... The following regression types are implemented : * Simple linear regression : y(k) = b(0) + b(1) * x(k) * Multiple linear regression : y(k) = b(0) + b(1) * x(1,k) + b(2) * x(2,k) + ... + b(Nvar) * x(Nvar,k) * Polynomial regression : y(k) = b(0) + b(1) * x(k) + b(2) * x(k)^2 + ... + b(Deg) * x(k)^Deg * Nonlinear regression : y(k) = f[x(k), b(0), b(1), ... ] where f is a user-specified function. The following parameters are common to all routines : Input : X = Vector or matrix of independent variables Y = Vector of dependent variable N = Index of the last observation Output : B = Regression parameters V = Inverse matrix of normal equations ********************************************************************** } function LinFit(X, Y : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- Simple linear regression ---------------------------------------------------------------------- } function MulFit(X : PMatrix; Y : PVector; N, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- Multiple linear regression ---------------------------------------------------------------------- Additional input parameters : Nvar = Index of the last independent variable ConsTerm = Flags the presence of a constant term b(0) ---------------------------------------------------------------------- } function PolFit(X, Y : PVector; N, Deg : Integer; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- Polynomial regression ---------------------------------------------------------------------- Additional input parameter : Deg = Degree of polynomial ---------------------------------------------------------------------- } function NLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y : PVector; N, Lbound, Ubound, MaxIter : Integer; Tol : Float; B, B_min, B_max : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- Nonlinear regression ---------------------------------------------------------------------- Additional input parameters : RegFunc = Regression function DerivProc = Procedure to compute the derivatives of RegFunc Lbound, Ubound = Indices of first and last function parameters MaxIter = Maximum number of iterations Tol = Required parameter precision B = Initial parameter values B_min, B_max = Lower and upper parameter bounds ---------------------------------------------------------------------- } { ********************************************************************** Weighted regression routines ********************************************************************** These routines fit equations to data by minimizing the sum of weighted squared residuals : SWS = Sum w(k)*[y(k) - ycalc(k)]^2 where the "weight" w(k) is inversely proportional to the variance v(k) of the observation y(k). v(k) is usually computed as : v(k) = Vr * g[y(k)] = Vr / w(k) where Vr is the residual variance and g is a user-specified function (e.g. g[y(k)] = y(k)^2 for a constant coefficient of variation). Function syntax and results are the same than for unweighted regression except that the vector of weights (W) is passed as an additional input parameter. ********************************************************************** } function WLinFit(X, Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; function WMulFit(X : PMatrix; Y, W : PVector; N, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix) : Integer; function WPolFit(X, Y, W : PVector; N, Deg : Integer; B : PVector; V : PMatrix) : Integer; function WNLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y, W : PVector; N, Lbound, Ubound, MaxIter : Integer; Tol : Float; B, B_min, B_max : PVector; V : PMatrix) : Integer; { ********************************************************************** Procedure to compute the derivatives of the regression function by numerical differentiation. ********************************************************************** } procedure NumDeriv(RegFunc : TRegFunc; X, Y : Float; B, D : PVector); { ---------------------------------------------------------------------- Input parameters : RegFunc = Regression function X, Y = Coordinates of point B = Regression parameters Output parameter : D = Derivatives (D^[I] contains the derivative w.r.t. parameter B^[I]) ---------------------------------------------------------------------- } { ********************************************************************** Routines to test the quality of the regression ********************************************************************** These routines compute the variance-covariance matrix of the fitted parameters and the different statistics used to test the quality of the fit. Input parameters : Y = Vector of dependent variable Ycalc = Computed Y values W = Vector of weights (if any) N = Index of the last observation Lbound, Ubound = Indices of first & last fitted parameters V = Inverse normal equations matrix Output parameters : V = Variance-covariance matrix Test = Test statistics (Vr, R2, R2a, F, Prob) ********************************************************************** } procedure RegTest(Y, Ycalc : PVector; N, Lbound, Ubound : Integer; V : PMatrix; var Test : TRegTest); { ---------------------------------------------------------------------- Test of unweighted regression ---------------------------------------------------------------------- } procedure WRegTest(Y, Ycalc, W : PVector; N, Lbound, Ubound : Integer; V : PMatrix; var Test : TRegTest); { ---------------------------------------------------------------------- Test of weighted regression ---------------------------------------------------------------------- } { ********************************************************************** Test of regression parameters ********************************************************************** } procedure ParamTest(B : PVector; V : PMatrix; N, Lbound, Ubound : Integer; S, T, Prob : PVector); { ---------------------------------------------------------------------- This routine tests the significance of the parameters. It must be called AFTER RegTest or WRegTest since it uses the variance-covariance matrix. ---------------------------------------------------------------------- Input parameters : B = Regression parameters V = Variance-covariance matrix N = Index of the last observation Lbound, Ubound = Indices of first & last fitted parameters ---------------------------------------------------------------------- Output parameters : S = Standard deviations of parameters T = Student's t Prob = Probabilities ---------------------------------------------------------------------- } { ********************************************************************** Correlation and principal component analysis Common parameters: X = matrix of variables (X^[I] contains the I-th variable) N = Index of the last observation Lbound, Ubound = Indices of first & last variables M = Mean vector (M^[I] = mean of X^[I]) S = Vector of standard deviations V = Variance-covariance matrix R = Correlation matrix ********************************************************************** } procedure VecMean(X : PMatrix; N, Lbound, Ubound : Integer; M : PVector); { ---------------------------------------------------------------------- Computes the mean vector (M) from matrix X Input : X, Lbound, Ubound Output : M ---------------------------------------------------------------------- } procedure VecSD(X : PMatrix; N, Lbound, Ubound : Integer; M, S : PVector); { ---------------------------------------------------------------------- Computes the vector of standard deviations (S) from matrix X Input : X, Lbound, Ubound, M Output : S ---------------------------------------------------------------------- } procedure MatVarCov(X : PMatrix; N, Lbound, Ubound : Integer; M : PVector; V : PMatrix); { ---------------------------------------------------------------------- Computes the variance-covariance matrix (V) from matrix X Input : X, Lbound, Ubound, M Output : V ---------------------------------------------------------------------- } procedure MatCorrel(V : PMatrix; Lbound, Ubound : Integer; R : PMatrix); { ---------------------------------------------------------------------- Computes the correlation matrix (R) from the variance-covariance matrix (V) Input : V, Lbound, Ubound Output : R ---------------------------------------------------------------------- } function PCA(R : PMatrix; Lbound, Ubound : Integer; Lambda : PVector; C, Rc : PMatrix) : Integer; { ---------------------------------------------------------------------- Performs a principal component analysis of the correlation matrix R ---------------------------------------------------------------------- Input : R, Lbound, Ubound Output : Lambda = Eigenvalues of the correlation matrix (in descending order) C = Eigenvectors of the correlation matrix (C^[I] is the I-th eigenvector) Rc = Correlations between principal factors and variables (R^[I]^[J] is the correlation coefficient between factor I and variable J) ---------------------------------------------------------------------- Possible results : MAT_OK : No error MAT_NON_CONV : Non-convergence of eigenvalue determination ---------------------------------------------------------------------- NB : This procedure destroys the original matrix R ---------------------------------------------------------------------- } procedure ScaleVar(X : PMatrix; N, Lbound, Ubound : Integer; M, S : PVector; Z : PMatrix); { ---------------------------------------------------------------------- Scales a set of variables by subtracting means and dividing by SD's ---------------------------------------------------------------------- Input : X, N, Lbound, Ubound, M, S Output : Z = matrix of scaled variables (Z^[I] contains the I-th var.) ---------------------------------------------------------------------- } procedure PrinFac(Z : PMatrix; N, Lbound, Ubound : Integer; C, F : PMatrix); { ---------------------------------------------------------------------- Computes principal factors ---------------------------------------------------------------------- Input : Z, N, Lbound, Ubound C = matrix of eigenvectors from PCA Output : F = matrix of principal factors (F^[I] contains the I-th factor) ---------------------------------------------------------------------- } implementation { Constants for eigenvalue determination in PCA } const PCA_MAXITER = 100; { Max number of iterations } PCA_TOL = 1.0E-6; { Required precision } MAX_FUNC = 1.0E+30; { Max. value for objective function (used to prevent overflow) } { Default settings } const RegAlgo : TRegAlgo = SVD; { Linear regression algorithm } OptAlgo : TOptAlgo = NL_MARQ; { Optimization algorithms } FirstPoint : Integer = 1; { Index of first data point } { Global variables used by the nonlinear regression routines } const NN : Integer = 1; { Number of observations } XX : PVector = nil; { X coordinates } YY : PVector = nil; { Y coordinates } WW : PVector = nil; { Weights } YYcalc : PVector = nil; { Estimated Y values } FirstParam : Integer = 0; { Index of first fitted parameter } LastParam : Integer = 1; { Index of last fitted parameter } ParamMin : PVector = nil; { Lower bounds on parameters } ParamMax : PVector = nil; { Higher bounds on parameters } var RegFunc1 : TRegFunc; { Regression function } DerivProc1 : TDerivProc; { Derivation procedure } function TolSVD(N : Integer) : Float; { This function sets the relative threshold below which a singular value is considered zero. N is the number of observations. } begin TolSVD := N * MACHEP; end; procedure SetRegAlgo(Algo : TRegAlgo); begin RegAlgo := Algo; end; procedure SetOptAlgo(Algo : TOptAlgo); begin OptAlgo := Algo; end; procedure SetFirstPoint(Index : Integer); begin if Index >= 0 then FirstPoint := Index; end; function GetRegAlgo : TRegAlgo; begin GetRegAlgo := RegAlgo; end; function GetOptAlgo : TOptAlgo; begin GetOptAlgo := OptAlgo; end; function GetFirstPoint : Integer; begin GetFirstPoint := FirstPoint; end; function GenLinFit(Mode : TRegMode; X, Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- General linear regression routine ---------------------------------------------------------------------- } var WX, S, SX, SY, SX2, SXY, D : Float; K : Integer; begin S := 0.0; SX := 0.0; SY := 0.0; SX2 := 0.0; SXY := 0.0; if Mode = UNWEIGHTED then begin S := N - FirstPoint + 1; for K := FirstPoint to N do begin SX := SX + X^[K]; SY := SY + Y^[K]; SX2 := SX2 + Sqr(X^[K]); SXY := SXY + X^[K] * Y^[K]; end; end else begin for K := FirstPoint to N do begin WX := W^[K] * X^[K]; S := S + W^[K]; SX := SX + WX; SY := SY + W^[K] * Y^[K]; SX2 := SX2 + WX * X^[K]; SXY := SXY + WX * Y^[K]; end; end; D := S * SX2 - Sqr(SX); if D <= 0.0 then GenLinFit := MAT_SINGUL else begin V^[0]^[0] := SX2 / D; V^[0]^[1] := - SX / D; V^[1]^[0] := V^[0]^[1]; V^[1]^[1] := S / D; B^[0] := V^[0]^[0] * SY + V^[0]^[1] * SXY; B^[1] := V^[1]^[0] * SY + V^[1]^[1] * SXY; GenLinFit := MAT_OK; end; end; function LinFit(X, Y : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; var W : PVector; begin LinFit := GenLinFit(UNWEIGHTED, X, Y, W, N, B, V); end; function WLinFit(X, Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; begin WLinFit := GenLinFit(WEIGHTED, X, Y, W, N, B, V); end; function Gauss_GenMulFit(Mode : TRegMode; X : PMatrix; Y, W : PVector; N, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- General multiple linear regression routine (Gauss-Jordan algorithm) ---------------------------------------------------------------------- } var A : PMatrix; { Matrix of normal equations } G : PVector; { Constant vector } I, J, K : Integer; { Loop variables } WX : Float; begin DimMatrix(A, Nvar, Nvar); DimVector(G, Nvar); { If constant term, set line 0 and column 0 of matrix A, and element 0 of vecteur G } if ConsTerm then begin if Mode = UNWEIGHTED then begin A^[0]^[0] := Int(N - FirstPoint + 1); for K := FirstPoint to N do begin for J := 1 to Nvar do A^[0]^[J] := A^[0]^[J] + X^[J]^[K]; G^[0] := G^[0] + Y^[K]; end; end else begin for K := FirstPoint to N do begin A^[0]^[0] := A^[0]^[0] + W^[K]; for J := 1 to Nvar do A^[0]^[J] := A^[0]^[J] + W^[K] * X^[J]^[K]; G^[0] := G^[0] + W^[K] * Y^[K]; end; end; for J := 1 to Nvar do A^[J]^[0] := A^[0]^[J]; end; { Set other elements of A and G } if Mode = UNWEIGHTED then for K := FirstPoint to N do for I := 1 to Nvar do begin for J := I to Nvar do A^[I]^[J] := A^[I]^[J] + X^[I]^[K] * X^[J]^[K]; G^[I] := G^[I] + X^[I]^[K] * Y^[K]; end else for K := FirstPoint to N do for I := 1 to Nvar do begin WX := W^[K] * X^[I]^[K]; for J := I to Nvar do A^[I]^[J] := A^[I]^[J] + WX * X^[J]^[K]; G^[I] := G^[I] + WX * Y^[K]; end; { Fill in symmetric matrix } for I := 2 to Nvar do for J := 1 to Pred(I) do A^[I]^[J] := A^[J]^[I]; { Solve normal equations } if ConsTerm then Gauss_GenMulFit := GaussJordan(A, G, 0, Nvar, V, B) else Gauss_GenMulFit := GaussJordan(A, G, 1, Nvar, V, B); DelMatrix(A, Nvar, Nvar); DelVector(G, Nvar); end; function SVD_GenMulFit(Mode : TRegMode; X : PMatrix; Y, W : PVector; N, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- General multiple linear regression routine (SVD algorithm) ---------------------------------------------------------------------- } var U : PMatrix; { Matrix of independent variables for SVD } Z : PVector; { Vector of dependent variables for SVD } S : PVector; { Singular values } S2inv : PVector; { Inverses of squared singular values } V1 : PMatrix; { Orthogonal matrix from SVD } Lbound : Integer; { Lower bound of U matrix in both dims. } Ubound : Integer; { Upper bound of U matrix in 1st dim. } I, J, K : Integer; { Loop variables } Sigma : Float; { Square root of weight } Sum : Float; { Element of variance-covariance matrix } ErrCode : Integer; { Error code } begin if ConsTerm then begin Lbound := 0; Ubound := N - FirstPoint; end else begin Lbound := 1; Ubound := N - FirstPoint + 1; end; { Dimension arrays } DimMatrix(U, Ubound, Nvar); DimVector(Z, Ubound); DimVector(S, Nvar); DimVector(S2inv, Nvar); DimMatrix(V1, Nvar, Nvar); { ---------------------------------------------------------- Prepare arrays for SVD : If constant term, use U[0..(N - FirstPoint), 0..Nvar] and Z[0..(N - FirstPoint)] Else use U[1..(N - FirstPoint + 1), 1..Nvar] and Z[1..(N - FirstPoint + 1)] ---------------------------------------------------------- } if Mode = UNWEIGHTED then for I := Lbound to Ubound do begin K := I - Lbound + FirstPoint; Z^[I] := Y^[K]; if ConsTerm then U^[I]^[0] := 1.0; for J := 1 to Nvar do U^[I]^[J] := X^[J]^[K]; end else for I := Lbound to Ubound do begin K := I - Lbound + FirstPoint; Sigma := Sqrt(W^[K]); Z^[I] := Y^[K] * Sigma; if ConsTerm then U^[I]^[0] := Sigma; for J := 1 to Nvar do U^[I]^[J] := X^[J]^[K] * Sigma; end; { Perform singular value decomposition } ErrCode := SV_Decomp(U, Lbound, Ubound, Nvar, S, V1); if ErrCode = MAT_OK then begin { Set the lowest singular values to zero } SV_SetZero(S, Lbound, Nvar, TolSVD(N - FirstPoint + 1)); { Solve the system } SV_Solve(U, S, V1, Z, Lbound, Ubound, Nvar, B); { Compute variance-covariance matrix } for I := Lbound to Nvar do if S^[I] > 0.0 then S2inv^[I] := 1.0 / Sqr(S^[I]) else S2inv^[I] := 0.0; for I := Lbound to Nvar do for J := Lbound to I do begin Sum := 0.0; for K := Lbound to Nvar do Sum := Sum + V1^[I]^[K] * V1^[J]^[K] * S2inv^[K]; V^[I]^[J] := Sum; V^[J]^[I] := Sum; end; end; SVD_GenMulFit := ErrCode; DelMatrix(U, Ubound, Nvar); DelVector(Z, Ubound); DelVector(S, Nvar); DelVector(S2inv, Nvar); DelMatrix(V1, Nvar, Nvar); end; function GenMulFit(Mode : TRegMode; X : PMatrix; Y, W : PVector; N, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- General multiple linear regression routine ---------------------------------------------------------------------- } begin case RegAlgo of GAUSS_JORDAN : GenMulFit := Gauss_GenMulFit(Mode, X, Y, W, N, Nvar, ConsTerm, B, V); SVD : GenMulFit := SVD_GenMulFit(Mode, X, Y, W, N, Nvar, ConsTerm, B, V); end; end; function MulFit(X : PMatrix; Y : PVector; N, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix) : Integer; var W : PVector; begin MulFit := GenMulFit(UNWEIGHTED, X, Y, W, N, Nvar, ConsTerm, B, V); end; function WMulFit(X : PMatrix; Y, W : PVector; N, Nvar : Integer; ConsTerm : Boolean; B : PVector; V : PMatrix) : Integer; begin WMulFit := GenMulFit(WEIGHTED, X, Y, W, N, Nvar, ConsTerm, B, V); end; procedure PowMat(X : PVector; N, Deg : Integer; U : PMatrix); { ---------------------------------------------------------------------- Computes matrix of increasing powers of X for polynomial regression ---------------------------------------------------------------------- } var I, K : Integer; begin for K := FirstPoint to N do begin U^[1]^[K] := X^[K]; for I := 2 to Deg do U^[I]^[K] := U^[I - 1]^[K] * X^[K]; end; end; function GenPolFit(Mode : TRegMode; X, Y, W : PVector; N, Deg : Integer; B : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- General polynomial regression routine ---------------------------------------------------------------------- } var U : PMatrix; begin DimMatrix(U, Deg, N); PowMat(X, N, Deg, U); GenPolFit := GenMulFit(Mode, U, Y, W, N, Deg, True, B, V); DelMatrix(U, Deg, N); end; function PolFit(X, Y : PVector; N, Deg : Integer; B : PVector; V : PMatrix) : Integer; var W : PVector; begin PolFit := GenPolFit(UNWEIGHTED, X, Y, W, N, Deg, B, V); end; function WPolFit(X, Y, W : PVector; N, Deg : Integer; B : PVector; V : PMatrix) : Integer; begin WPolFit := GenPolFit(WEIGHTED, X, Y, W, N, Deg, B, V); end; procedure SetGlobalVar(RegFunc : TRegFunc; DerivProc : TDerivProc; Mode : TRegMode; X, Y, W : PVector; N, Lbound, Ubound : Integer; B_min, B_max : PVector); { Sets the global variables used by the nonlinear regression routines } begin DelVector(XX, NN); DelVector(YY, NN); DelVector(YYcalc, NN); DimVector(XX, N); DimVector(YY, N); DimVector(YYcalc, N); CopyVector(XX, X, FirstPoint, N); CopyVector(YY, Y, FirstPoint, N); if Mode = WEIGHTED then begin DelVector(WW, NN); DimVector(WW, N); CopyVector(WW, W, FirstPoint, N); end; NN := N; DelVector(ParamMin, LastParam); DelVector(ParamMax, LastParam); DimVector(ParamMin, Ubound); DimVector(ParamMax, Ubound); CopyVector(ParamMin, B_min, Lbound, Ubound); CopyVector(ParamMax, B_max, Lbound, Ubound); FirstParam := Lbound; LastParam := Ubound; RegFunc1 := RegFunc; DerivProc1 := DerivProc; end; {$F+} procedure NumDeriv(RegFunc : TRegFunc; X, Y : Float; B, D : PVector); var I : Integer; Eps, Temp, Y1 : Float; begin Eps := Sqrt(MACHEP); for I := FirstParam to LastParam do begin Temp := B^[I]; { Save parameter } B^[I] := B^[I] + Eps * Abs(B^[I]); { Modified parameter } Y1 := RegFunc(X, B); D^[I] := (Y1 - Y) / (B^[I] - Temp); { Derivative } B^[I] := Temp; { Restore parameter } end; end; function OutOfBounds(B, B_min, B_max : PVector) : Boolean; { Check if the parameters are inside the bounds } var I : Integer; OoB : Boolean; begin I := FirstParam; OoB := False; repeat OoB := (B^[I] < B_min^[I]) or (B^[I] > B_max^[I]); Inc(I); until OoB or (I > LastParam); OutOfBounds := OoB; end; function OLS_ObjFunc(B : PVector) : Float; { Objective function for unweighted nonlinear regression } var K : Integer; S : Float; begin if OutOfBounds(B, ParamMin, ParamMax) then begin OLS_ObjFunc := MAX_FUNC; Exit; end; S := 0.0; K := FirstPoint; repeat YYcalc^[K] := RegFunc1(XX^[K], B); S := S + Sqr(YY^[K] - YYcalc^[K]); Inc(K); until (K > NN) or (S > MAX_FUNC); if S > MAX_FUNC then S := MAX_FUNC; OLS_ObjFunc := S; end; procedure OLS_Gradient(Func : TFuncNVar; B : PVector; Lbound, Ubound : Integer; G : PVector); { Gradient for unweighted nonlinear regression. Func is a dummy parameter here. } var I, K : Integer; { Loop variables } R : Float; { Residual } D : PVector; { Derivatives of the regression function } begin DimVector(D, Ubound); { Initialization } for I := Lbound to Ubound do G^[I] := 0.0; { Compute Gradient } for K := FirstPoint to NN do begin R := YY^[K] - YYcalc^[K]; DerivProc1(RegFunc1, XX^[K], YYcalc^[K], B, D); for I := Lbound to Ubound do G^[I] := G^[I] - D^[I] * R; end; for I := Lbound to Ubound do G^[I] := 2.0 * G^[I]; DelVector(D, Ubound); end; procedure OLS_HessGrad(Func : TFuncNVar; B : PVector; Lbound, Ubound : Integer; G : PVector; H : PMatrix); { Gradient and Hessian for unweighted nonlinear regression. Func is a dummy parameter here. } var I, J, K : Integer; { Loop variables } R : Float; { Residual } D : PVector; { Derivatives of the regression function } begin DimVector(D, Ubound); { Initializations } for I := Lbound to Ubound do begin G^[I] := 0.0; for J := I to Ubound do H^[I]^[J] := 0.0; end; { Compute Gradient & Hessian } for K := FirstPoint to NN do begin R := YY^[K] - YYcalc^[K]; DerivProc1(RegFunc1, XX^[K], YYcalc^[K], B, D); for I := Lbound to Ubound do begin G^[I] := G^[I] - D^[I] * R; for J := I to Ubound do H^[I]^[J] := H^[I]^[J] + D^[I] * D^[J]; end; end; { Fill in symmetric matrix } for I := Succ(Lbound) to Ubound do for J := Lbound to Pred(I) do H^[I]^[J] := H^[J]^[I]; DelVector(D, Ubound); end; function WLS_ObjFunc(B : PVector) : Float; { Objective function for weighted nonlinear regression } var K : Integer; S : Float; begin if OutOfBounds(B, ParamMin, ParamMax) then begin WLS_ObjFunc := MAX_FUNC; Exit; end; S := 0.0; K := FirstPoint; repeat YYcalc^[K] := RegFunc1(XX^[K], B); S := S + WW^[K] * Sqr(YY^[K] - YYcalc^[K]); Inc(K); until (K > NN) or (S > MAX_FUNC); if S > MAX_FUNC then S := MAX_FUNC; WLS_ObjFunc := S; end; procedure WLS_Gradient(Func : TFuncNVar; B : PVector; Lbound, Ubound : Integer; G : PVector); { Gradient for weighted nonlinear regression. Func is a dummy parameter here. } var I, K : Integer; { Loop variables } R : Float; { Residual } D : PVector; { Derivatives of the regression function } WD : Float; { Weighted derivative } begin DimVector(D, Ubound); { Initialization } for I := Lbound to Ubound do G^[I] := 0.0; { Compute Gradient } for K := FirstPoint to NN do begin R := YY^[K] - YYcalc^[K]; DerivProc1(RegFunc1, XX^[K], YYcalc^[K], B, D); for I := Lbound to Ubound do begin WD := WW^[K] * D^[I]; G^[I] := G^[I] - WD * R; end; end; for I := Lbound to Ubound do G^[I] := 2.0 * G^[I]; DelVector(D, Ubound); end; procedure WLS_HessGrad(Func: TFuncNVar; B : PVector; Lbound, Ubound : Integer; G : PVector; H : PMatrix); { Gradient and Hessian for weighted nonlinear regression. Func is a dummy parameter here. } var I, J, K : Integer; { Loop variables } R : Float; { Residual } D : PVector; { Derivatives of the regression function } WD : Float; { Weighted derivative } begin DimVector(D, Ubound); { Initialization } for I := Lbound to Ubound do begin G^[I] := 0.0; for J := I to Ubound do H^[I]^[J] := 0.0; end; { Compute Gradient & Hessian } for K := FirstPoint to NN do begin R := YY^[K] - YYcalc^[K]; DerivProc1(RegFunc1, XX^[K], YYcalc^[K], B, D); for I := Lbound to Ubound do begin WD := WW^[K] * D^[I]; G^[I] := G^[I] - WD * R; for J := I to Ubound do H^[I]^[J] := H^[I]^[J] + WD * D^[J]; end; end; { Fill in symmetric matrix } for I := Succ(Lbound) to Ubound do for J := Lbound to Pred(I) do H^[I]^[J] := H^[J]^[I]; DelVector(D, Ubound); end; {$F-} function GenNLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; Mode : TRegMode; X, Y, W : PVector; N, Lbound, Ubound, MaxIter : Integer; Tol : Float; B, B_min, B_max : PVector; V : PMatrix) : Integer; { -------------------------------------------------------------------- General nonlinear regression routine -------------------------------------------------------------------- } var F_min : Float; { Value of objective function at minimum } ErrCode : Integer; { Error code } G : PVector; { Gradient vector } H : PMatrix; { Hessian matrix } ObjFunc : TFuncNVar; { Objective function } GradProc : TGradient; { Procedure to compute gradient } HessProc : THessGrad; { Procedure to compute gradient and hessian } begin SetGlobalVar(RegFunc, DerivProc, Mode, X, Y, W, N, Lbound, Ubound, B_min, B_max); case Mode of UNWEIGHTED : begin ObjFunc := {$IFDEF FPK}@{$ENDIF}OLS_ObjFunc; GradProc := {$IFDEF FPK}@{$ENDIF}OLS_Gradient; HessProc := {$IFDEF FPK}@{$ENDIF}OLS_HessGrad; end; WEIGHTED : begin ObjFunc := {$IFDEF FPK}@{$ENDIF}WLS_ObjFunc; GradProc := {$IFDEF FPK}@{$ENDIF}WLS_Gradient; HessProc := {$IFDEF FPK}@{$ENDIF}WLS_HessGrad; end; end; case OptAlgo of NL_MARQ : ErrCode := Marquardt(ObjFunc, HessProc, B, Lbound, Ubound, MaxIter, Tol, F_min, V); NL_SIMP : ErrCode := Simplex(ObjFunc, B, Lbound, Ubound, MaxIter, Tol, F_min); NL_BFGS : ErrCode := BFGS(ObjFunc, GradProc, B, Lbound, Ubound, MaxIter, Tol, F_min, V); NL_SA : ErrCode := SimAnn(ObjFunc, B, B_min, B_max, Lbound, Ubound, MaxIter, Tol, F_min); end; if (OptAlgo <> NL_MARQ) and (OptAlgo <> NL_BFGS) and (ErrCode = OPT_OK) then begin { Compute the Hessian matrix and its inverse } DimVector(G, Ubound); DimMatrix(H, Ubound, Ubound); case Mode of UNWEIGHTED : OLS_HessGrad(ObjFunc, B, Lbound, Ubound, G, H); WEIGHTED : WLS_HessGrad(ObjFunc, B, Lbound, Ubound, G, H); end; if InvMat(H, Lbound, Ubound, V) = 0 then ErrCode := OPT_OK else ErrCode := OPT_SING; DelVector(G, Ubound); DelMatrix(H, Ubound, Ubound); end; GenNLFit := ErrCode; end; function NLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y : PVector; N, Lbound, Ubound, MaxIter : Integer; Tol : Float; B, B_min, B_max : PVector; V : PMatrix) : Integer; var W : PVector; begin NLFit := GenNLFit(RegFunc, DerivProc, UNWEIGHTED, X, Y, W, N, Lbound, Ubound, MaxIter, Tol, B, B_min, B_max, V); end; function WNLFit(RegFunc : TRegFunc; DerivProc : TDerivProc; X, Y, W : PVector; N, Lbound, Ubound, MaxIter : Integer; Tol : Float; B, B_min, B_max : PVector; V : PMatrix) : Integer; begin WNLFit := GenNLFit(RegFunc, DerivProc, WEIGHTED, X, Y, W, N, Lbound, Ubound, MaxIter, Tol, B, B_min, B_max, V); end; procedure GenRegTest(Mode : TRegMode; Y, Ycalc, W : PVector; N, Lbound, Ubound : Integer; V : PMatrix; var Test : TRegTest); var Ybar : Float; { Average Y value } SSt : Float; { Total sum of squares } SSe : Float; { Explained sum of squares } SSr : Float; { Residual sum of squares } Nobs : Integer; { Number of observations } Npar : Integer; { Number of fitted parameters } Nu1, Nu2 : Integer; { Degrees of freedom } I, J : Integer; { Loop variables } begin Nobs := N - FirstPoint + 1; Npar := Ubound - Lbound + 1; with Test do if Nobs > Npar then begin Ybar := Average(Y, FirstPoint, N); if Mode = UNWEIGHTED then begin SSt := SumSqrDif(Y, FirstPoint, N, Ybar); SSe := SumSqrDif(Ycalc, FirstPoint, N, Ybar); SSr := SumSqrDifVect(Y, Ycalc, FirstPoint, N); end else begin SSt := SumWSqrDif(Y, W, FirstPoint, N, Ybar); SSe := SumWSqrDif(Ycalc, W, FirstPoint, N, Ybar); SSr := SumWSqrDifVect(Y, Ycalc, W, FirstPoint, N); end; Nu1 := Npar - 1; Nu2 := Nobs - Npar; if (SSt = 0) or (Nu2=0) then begin //showmessage('Error: are all you data points in the same plane?'); exit; end; R2 := SSe / SSt; R2a := 1.0 - (1.0 - R2) * (Nobs - 1) / Nu2; Vr := SSr / Nu2; if (Vr > 0.0) and (Nu1 > 0.0) then begin F := (SSe / Nu1) / Vr; Prob := PSnedecor(Nu1, Nu2, F); end else begin F := MAXNUM; Prob := 0.0; end; end else begin Vr := 0.0; R2 := 1.0; R2a := 0.0; F := 0.0; Prob := 1.0; end; { Compute variance-covariance matrix } for I := Lbound to Ubound do for J := I to Ubound do V^[I]^[J] := V^[I]^[J] * Test.Vr; for I := Succ(Lbound) to Ubound do for J := Lbound to Pred(I) do V^[I]^[J] := V^[J]^[I]; end; procedure RegTest(Y, Ycalc : PVector; N, Lbound, Ubound : Integer; V : PMatrix; var Test : TRegTest); var W : PVector; begin GenRegTest(UNWEIGHTED, Y, Ycalc, W, N, Lbound, Ubound, V, Test); end; procedure WRegTest(Y, Ycalc, W : PVector; N, Lbound, Ubound : Integer; V : PMatrix; var Test : TRegTest); begin GenRegTest(WEIGHTED, Y, Ycalc, W, N, Lbound, Ubound, V, Test); end; procedure ParamTest(B : PVector; V : PMatrix; N, Lbound, Ubound : Integer; S, T, Prob : PVector); var I : Integer; Nu : Integer; { Degrees of freedom } Nobs : Integer; { Number of observations } Nvar : Integer; { Number of indep. variables } begin Nobs := N - FirstPoint + 1; Nvar := Ubound - Lbound + 1; Nu := Nobs - Nvar; { DoF = Nb points - Nb parameters } for I := Lbound to Ubound do if V^[I]^[I] > 0.0 then begin S^[I] := Sqrt(V^[I]^[I]); T^[I] := B^[I] / S^[I]; Prob^[I] := PStudent(Nu, T^[I]); end else begin S^[I] := 0.0; T^[I] := 0.0; Prob^[I] := 1.0; end; end; procedure VecMean(X : PMatrix; N, Lbound, Ubound : Integer; M : PVector); var I, K, Nobs : Integer; Sum : Float; begin Nobs := N - FirstPoint + 1; for I := Lbound to Ubound do begin Sum := 0.0; for K := FirstPoint to N do Sum := Sum + X^[I]^[K]; M^[I] := Sum / Nobs; end; end; procedure VecSD(X : PMatrix; N, Lbound, Ubound : Integer; M, S : PVector); var I, K, Nobs : Integer; Sum : Float; begin Nobs := N - FirstPoint + 1; for I := Lbound to Ubound do begin Sum := 0.0; for K := FirstPoint to N do Sum := Sum + Sqr(X^[I]^[K] - M^[I]); S^[I] := Sqrt(Sum / Nobs); end; end; procedure MatVarCov(X : PMatrix; N, Lbound, Ubound : Integer; M : PVector; V : PMatrix); var I, J, K, Nobs : Integer; Sum : Float; begin Nobs := N - FirstPoint + 1; for I := Lbound to Ubound do for J := I to Ubound do begin Sum := 0.0; for K := FirstPoint to N do Sum := Sum + (X^[I]^[K] - M^[I]) * (X^[J]^[K] - M^[J]); V^[I]^[J] := Sum / Nobs; end; for I := Succ(Lbound) to Ubound do for J := Lbound to Pred(I) do V^[I]^[J] := V^[J]^[I]; end; procedure MatCorrel(V : PMatrix; Lbound, Ubound : Integer; R : PMatrix); var I, J : Integer; begin for I := Lbound to Ubound do begin R^[I]^[I] := 1.0; for J := Succ(I) to Ubound do begin R^[I]^[J] := V^[I]^[J] / Sqrt(V^[I]^[I] * V^[J]^[J]); R^[J]^[I] := R^[I]^[J]; end; end; end; function PCA(R : PMatrix; Lbound, Ubound : Integer; Lambda : PVector; C, Rc : PMatrix) : Integer; var I, J, ErrCode : Integer; Rac : Float; begin { Compute eigenvalues and eigenvectors of correlation matrix } ErrCode := Jacobi(R, Lbound, Ubound, PCA_MAXITER, PCA_TOL, C, Lambda); if ErrCode <> 0 then begin PCA := ErrCode; Exit; end; { Compute correlations between principal factors and reduced variables } for I := Lbound to Ubound do begin Rac := Sqrt(Lambda^[I]); for J := Lbound to Ubound do Rc^[I]^[J] := C^[I]^[J] * Rac; end; PCA := ErrCode; end; procedure ScaleVar(X : PMatrix; N, Lbound, Ubound : Integer; M, S : PVector; Z : PMatrix); var I, K : Integer; begin for I := Lbound to Ubound do for K := FirstPoint to N do Z^[I]^[K] := (X^[I]^[K] - M^[I]) / S^[I]; end; procedure PrinFac(Z : PMatrix; N, Lbound, Ubound : Integer; C, F : PMatrix); var I, J, K : Integer; begin for I := Lbound to Ubound do for K := FirstPoint to N do begin F^[I]^[K] := 0.0; for J := Lbound to Ubound do F^[I]^[K] := F^[I]^[K] + C^[I]^[J] * Z^[J]^[K]; end; end; end. ��������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/mathp2.inc�����������������������������������������������0000755�0001750�0001750�00000070025�07140473620�017767� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * MATHP2.INC * ********************************************************************** Mathematical functions for TPMATH (Assembler version for Pentium II/III with FPC) ********************************************************************** } { Bibliotheque mathematique pour utilisation du coprocesseur flottant JD GAYRARD Sept. 95 ---------------------------------------------------------------------- Unite d'origine : MATH387.PAS, disponible dans MATHLIB2.ZIP (http://wcarchive.cdrom.com/pub/delphi_www/) Adapte aux pentiums II/III et complete par P. NOGARET (2000) ---------------------------------------------------------------------- } {***********************************************************************} {* function fexp(x : Float): Float;assembler; *} {***********************************************************************} {* Fonction dveloppe partir du document de Agner Fog *} {* www.agner.org/assem *} {***********************************************************************} {* retourne e^x, par la methode e^x = 2^(x.log2(e)) *} {* 2^z = 2^f.2^i avec f = frac(z) and i = int(z) *} {* 2^f is computed with F2XM1, *} {* 2^i pourrait tre calcul avec FSCALE mais cette instruction *} {* est trs lente 56 micro-ops sur un pentium II *} {* pour la mthode utilis pour calculer 2^i voir Agner Fog *} {***********************************************************************} {* st(0) st(1) *} {* log2(e) - *} {* x log2(e) *} {* z:=x.log2(e) - *} {* z - *} {* z - round(z) - *} {* 2^(z - round(z)) - 1 - *} {* 1 2^(z - round(z)) - 1 *} {* 2^(z - round(z)) - *} {* temp:=2^i 2^f:=2^(z - round(z)) *} {* e^x - *} {***********************************************************************} function fexp(x : Float): Float;assembler; var round_z : dword; temp : extended; asm FLDL2E FLD x FMULP FIST round_z MOV DWORD PTR [temp], 00000000H MOV DWORD PTR [temp+4],80000000H FISUB round_z MOV EAX, round_z ADD EAX, 00003FFFH MOV DWORD PTR [temp+8],EAX F2XM1 FLD1 FADDP FLD TBYTE PTR [temp] FMULP end ['eax']; {***********************************************************************} {* function fexp2(x : Float): Float; assembler; *} {***********************************************************************} {* Fonction dveloppe partir du document de Agner Fog *} {* www.agner.org/assem *} {***********************************************************************} {* retourne 2^x par la methode 2^z = 2^f.2^i *} {* avec f = frac(z) and i = int(z) *} {* 2^f is computed with F2XM1, *} {* 2^i pourrait tre calcul avec FSCALE mais cette instruction *} {* est trs lente 56 micro-ops sur un pentium II *} {* pour la mthode utilis pour calculer 2^i voir Agner Fog *} {***********************************************************************} {* st(0) st(1) *} {* x - *} {* z:=x - *} {* z - *} {* z - round(z) - *} {* 2^(z - round(z)) - 1 - *} {* 1 2^(z - round(z)) - 1 *} {* 2^(z - round(z)) - *} {* temp:=2^i 2^f:=2^(z - round(z)) *} {* e^x - *} {***********************************************************************} function fexp2(x : Float): Float; assembler; var round_z : dword; temp : extended; asm FLD x FIST round_z MOV DWORD PTR [temp], 00000000H MOV DWORD PTR [temp+4],80000000H FISUB round_z MOV EAX, round_z { round_zmax := 16384 } ADD EAX, 00003FFFH MOV DWORD PTR [temp+8],EAX F2XM1 FLD1 FADDP FLD TBYTE PTR [temp] FMULP end ['EAX']; {***********************************************************************} {* function fexp10(x : Float): Float; assembler; *} {***********************************************************************} {* Fonction dveloppe partir du document de Agner Fog *} {* www.agner.org/assem *} {***********************************************************************} {* retourne 10^x, par la methode 10^x = 2^(x.log2(10)) *} {* 2^z = 2^f.2^i with f = frac(z) and i = int(z) *} {* 2^f is computed with F2XM1 *} {* 2^i pourrait tre calcul avec FSCALE mais cette instruction *} {* est trs lente 56 micro-ops sur un pentium II *} {* pour la mthode utilis pour calculer 2^i voir Agner Fog *} {***********************************************************************} {* st(0) st(1) *} {* log2(10) - *} {* x log2(10) *} {* z:=x.log2(10) - *} {* z - *} {* z - round(z) - *} {* 2^(z - round(z)) - 1 - *} {* 1 2^(z - round(z)) - 1 *} {* 2^(z - round(z)) - *} {* temp:=2^i 2^f:=2^(z - round(z)) *} {* 10^x - *} {***********************************************************************} function fexp10(x : Float): Float; assembler; var round_z : dword; temp : extended; asm FLDL2T FLD X FMULP FIST round_z MOV DWORD PTR [temp], 00000000H MOV DWORD PTR [temp+4],80000000H FISUB round_z MOV EAX, round_z ADD EAX, 00003FFFH MOV DWORD PTR [temp+8],EAX F2XM1 FLD1 FADDP FLD TBYTE PTR [temp] FMULP end ['EAX']; function fln(x : Float): Float; assembler; { retourne le logarithme naturel de x, utilise la methode loge(x) = loge(2).log2(x) } { pas de verification du domaine de definition (x < 0) } asm { ST(0) ST(1) } FLDLN2 { ln(2) - } FLD X { x ln(2) } FYL2X { ln(2).log2(x) - } end; function flog2(x : Float): Float; assembler; { retourne le logarithme de base 2 de x } { pas de verification du domaine de definition (x < 0) } asm { ST(0) ST(1) } FLD1 { 1 - } FLD X { x 1 } FYL2X { log2(x) - } end; {***********************************************************************} {* function flog10(X : Float) : Float; *} {***********************************************************************} {* Compute a common (base 10) logarithm. If X is near 1.0, then we *} {* use the FYL2XP1 instruction instead of FYL2X. "Near" means between *} {* 1.0 and 1+Sqrt(2)/2. We use an approximation for Sqrt(2)/2, so we *} {* don't have to compute it. The exact value isn't important, since *} {* FYL2X works fine for values near the transition. *} {***********************************************************************} function flog10(x : Float): Float; assembler; const HalfSqrt2p1: Extended = 1.7071; asm fldlg2 { push Log2 } fld X { push X } fld1 { push 1.0 } fcomp ST(1) { if (X < 1.0) } jl @@1 { goto @@1 } fld HalfSqrt2p1 { push 1.707 } fcomp ST(1) { if (X > 1.707) } jg @@1 { goto @@1 } fld1 { X is small, so subtract 1.0 } fsubrp { X := X - 1.0 } fyl2xp1 { Log10(2) * Log2(X+1) } jmp @@2 @@1: { X is not near 1.0 } fyl2x { Log10(2) * Log2(X) } @@2: end; {***********************************************************************} {* function fsin(X : Float) : Float; *} {***********************************************************************} {* if x < pi.2^62, then C2 is set to 0 and ST = sin(x) *} {* else C2 is set to 1 and ST = x *} {* no check range validity is performed in this function *} {***********************************************************************} function fsin(X : Float) : Float; assembler; asm FLD x fsin end; {***********************************************************************} {* function fcos(X : Float) : Float; *} {***********************************************************************} function fcos(X : Float) : Float; assembler; asm FLD x fcos end; {***********************************************************************} {* function ftan(X : Float) : Float;assembler; *} {***********************************************************************} function ftan(X : Float) : Float; assembler; asm { ST(0) ST(1) } FLD x { x - } FPTAN { 1 tan(x) } FSTP ST(0) { tan(x) - } end; {***********************************************************************} {* function farctan(X : Float) : Float; *} {***********************************************************************} function farctan(x : Float): Float; assembler; asm { ST(0) ST(1) } FLD x { x - } FLD1 { 1 x } FPATAN { atan(x/1) - } end; {***********************************************************************} {* function farctan2(Y, X : Float) : Float; *} {***********************************************************************} function farctan2(y, x : Float): Float; assembler; { retourne arctan (y / x) } asm { ST(0) ST(1) } FLD y { y - } FLD x { x y } FPATAN { atan(y/x) - } end; {***********************************************************************} {* function farcsin(X : Float) : Float; *} {***********************************************************************} {* retourne l'arcsin de x *} {* methode : ________ *} {* arcsin(x) = arctan( x / V 1 - x.x ) *} {* no range validity check is performed in this function |x| > 1 *} {***********************************************************************} {* ST(0) ST(1) ST(2) *} {* x - - *} {* x x - *} {* x.x x - *} {* 1 x.x x *} {* 1 - x x - *} {* sqrt(1-x) x - *} {* arcsin(x) - - *} {***********************************************************************} function farcsin(x : Float): Float; assembler; asm FLD X FLD ST(0) FMUL ST(0), ST FLD1 FSUBRP ST(1), ST FSQRT FPATAN end; {***********************************************************************} {* function farccos(x : Float): Float; assembler; *} {***********************************************************************} {* retourne l'arccos de x *} {* methode : ________ *} {* arccos(x) = arctan( V 1 - x.x / x) *} {* pas de controle de domaine de definition |x| > 1 *} {***********************************************************************} {* ST(0) ST(1) ST(2) *} {* x - - *} {* x x - *} {* x.x x - *} {* 1 x.x x *} {* 1 - x x - *} {* sqrt(1-x) x - *} {* x z - *} {* arccos(x) - - *} {***********************************************************************} function farccos(x : Float): Float; assembler; asm FLD X FLD ST(0) FMUL ST(0), ST FLD1 FSUBRP ST(1), ST FSQRT FXCH FPATAN end; {***********************************************************************} {* function fsinh(X : Float) : Float; *} {***********************************************************************} {* retourne le sinus hyperbolique de l'argument *} {* sh(x) = [exp(x) - exp(-x)] / 2 *} {* methode : z = exp(x), ch(x) = 1/2 (z - 1/z) *} {* z = 2^y, y = x.log2(e), *} {* z = 2^f.2^i, f = frac(y), i = int(y) *} {* 2^f est calcul avec F2XM1, 2^i sans FSCALE *} {***********************************************************************} {* ST(0) ST(1) ST(2) *} {* log2(e) - - *} {* x log2(e) - *} {* z:=x.log2(e) - - *} {* z - - *} {* z - round(z) - - *} {* 2^(z - round(z)) - 1 - - *} {* 1 2^(z - round(z)) - 1 - *} {* 2^(z - round(z)) - - *} {* temp:=2^i 2^f:=2^(z - round(z)) - *} {* e^x - - *} {* e^x e^x - *} {* 1 z z *} {* 1/z z - *} {* z-1/z - - *} {* 0.5 z-1/z - *} {* sh(x) - - *} {***********************************************************************} function fsinh(x : float): float; assembler; const one_half : float = 0.5; var round_z : dword; temp : extended; asm FLDL2E FLD x FMULP FIST round_z MOV DWORD PTR [temp], 00000000H MOV DWORD PTR [temp+4],80000000H FISUB round_z MOV EAX, round_z ADD EAX, 00003FFFH MOV DWORD PTR [temp+8],EAX F2XM1 FLD1 FADDP FLD TBYTE PTR [temp] FMULP FST ST(1) FLD1 FDIVRP ST(1), ST FSUBP ST(1), ST FLD one_half FMULP ST(1), ST end; {***********************************************************************} {* function fcosh(X : Float) : Float; *} {***********************************************************************} {* retourne le cosinus hyperbolique de l'argument *} {* ch(x) = [exp(x) + exp(-x)] / 2 *} {* methode : z = exp(x), ch(x) = 1/2 (z + 1/z) *} {* z = 2^y, y = x.log2(e), *} {* z = 2^f.2^i, f = frac(y), i = int(y) *} {* 2^f est calcul avec F2XM1, 2^i sans FSCALE *} {***********************************************************************} {* st(0) st(1) st(2) *} {* log2(e) - *} {* x log2(e) *} {* z:=x.log2(e) - *} {* z - *} {* z - round(z) - *} {* 2^(z - round(z)) - 1 - *} {* 1 2^(z - round(z)) - 1 *} {* 2^(z - round(z)) - *} {* temp:=2^i 2^f:=2^(z - round(z)) *} {* e^x - *} {* e^x e^x - *} {* 1 z z *} {* 1/z z - *} {* z+1/z - - *} {* 0.5 z+1/z - *} {* ch(x) - - *} {***********************************************************************} function fcosh(x : float): float; assembler; const one_half : float = 0.5; var round_z : dword; temp : extended; asm FLDL2E FLD x FMULP FIST round_z MOV DWORD PTR [temp], 00000000H MOV DWORD PTR [temp+4],80000000H FISUB round_z MOV EAX, round_z ADD EAX, 00003FFFH MOV DWORD PTR [temp+8],EAX F2XM1 FLD1 FADDP FLD TBYTE PTR [temp] FMULP FST ST(1) FLD1 FDIVRP ST(1), ST FADDP ST(1), ST FLD one_half FMULP ST(1), ST end; {***********************************************************************} {* function ftanh(X : Float) : Float; *} {***********************************************************************} {* retourne la tangente hyperbolique de l'argument *} {* th(x) = sh(x) / ch(x) *) *} {* th(x) = [exp(x) - exp(-x)] / [exp(x) + exp(-x)] *} {* methode : z = exp(x), ch(x) = (z - 1/z) / (z + 1/z) *} {* z = 2^y, y = x.log2(e), *} {* z = 2^f.2^i, f = frac(y), i = int(y) *} {* 2^f est calcul avec F2XM1, 2^i sans FSCALE *} {***********************************************************************} {* st(0) st(1) st(2) *} {* log2(e) - *} {* x log2(e) *} {* z:=x.log2(e) - *} {* z - *} {* z - round(z) - *} {* 2^(z - round(z)) - 1 - *} {* 1 2^(z - round(z)) - 1 *} {* 2^(z - round(z)) - *} {* temp:=2^i 2^f:=2^(z - round(z)) *} {* e^x - *} {* e^x e^x - *} {* 1 z z *} {* 1/z z z *} {* 1/z z z-1/z *} {* z+1/z z-1/z - *} {* th(x) - - *} {***********************************************************************} function ftanh(x : float): float; assembler; const one_half : float = 0.5; var round_z : dword; temp : extended; asm FLDL2E FLD x FMULP FIST round_z MOV DWORD PTR [temp], 00000000H MOV DWORD PTR [temp+4],80000000H FISUB round_z MOV EAX, round_z ADD EAX, 00003FFFH MOV DWORD PTR [temp+8],EAX F2XM1 FLD1 FADDP FLD TBYTE PTR [temp] FMULP FST ST(1) FLD1 FDIV ST, ST(1) FSUB ST(2), ST FADDP ST(1), ST FDIVP ST(1), ST end; {***********************************************************************} {* function farcsinh(X : Float) : Float; *} {***********************************************************************} {* retourne l'arc sinus hyperbolique de l'argument *} {* _________ *} {* arg sh(x) = ln ( x + V x.x + 1 ) *} {***********************************************************************} {* ST(0) ST(1) ST(2) ST(3) *} {* ln(2) - - - *} {* x ln(2) - - *} {* x x ln(2) - *} {* x.x x ln(2) - *} {* 1 x.x x ln(2) *} {* x.x + 1 x ln(2) - *} {* sqrt(x.x+1) x ln(2) - *} {* x + z ln(2) - - *} {* arg_sh(x) - - - *} {***********************************************************************} function farcsinh(x : float): float; assembler; asm FLDLN2 FLD X FLD ST(0) FMUL ST(0), ST FLD1 FADDP ST(1), ST FSQRT FADDP ST(1), ST FYL2X end; {***********************************************************************} {* function farccosh(X : Float) : Float; *} {***********************************************************************} {* retourne l'arc cosinus hyperbolique de l'argument *} {* ________ *} {* arg ch(x) = ln ( x + V x.x - 1 ) x >=1 *} {***********************************************************************} {* ST(0) ST(1) ST(2) ST(3) *} {* ln(2) - - - *} {* x ln(2) - - *} {* x x ln(2) - *} {* x.x x ln(2) - *} {* 1 x.x x ln(2) *} {* x.x - 1 x ln(2) - *} {* sqrt(x2-1) x ln(2) - *} {* x + z ln(2) - - *} {* arg_ch(x) - - - *} {***********************************************************************} function farccosh(x : float): float; assembler; asm FLDLN2 FLD X FLD ST(0) FMUL ST(0), ST FLD1 FSUBP ST(1), ST FSQRT FADDP ST(1), ST FYL2X end; {***********************************************************************} {* function farctanh(X : Float) : Float; *} {***********************************************************************} {* retourne l'arc tangente hyperbolique de l'argument *} {* arg th(x) = 1/2 ln [ (1 + x) / (1 - x) ] *} {***********************************************************************} {* ST(0) ST(1) ST(2) ST(3) *} {* ln(2) - - - *} {* x ln(2) - - *} {* x x ln(2) - *} {* 1 x x ln(2) *} {* 1 x 1 + x ln(2) *} {* 1 - x 1 + x ln(2) - *} {* 1+x/1-x ln(2) - - *} {* ln(z) - - - *} {***********************************************************************} function farctanh(x : float): float; assembler; asm FLDLN2 FLD X FLD ST(0) FLD1 FADD ST(2),ST FSUBRP ST(1),ST FDIVP ST(1),ST FYL2X end; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/fourier.pas����������������������������������������������0000755�0001750�0001750�00000025437�11326443506�020271� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(*========================================================================== fourier.pas - Don Cross <dcross@intersrv.com> Modified by Jean Debord <JDebord@compuserve.com> for use with TP Math. This is a Turbo Pascal Unit for calculating the Fast Fourier Transform (FFT) and the Inverse Fast Fourier Transform (IFFT). Visit the following URL for the latest version of this code. This page also has a C/C++ version, and a brief discussion of the theory behind the FFT algorithm. http://www.intersrv.com/~dcross/fft.html#pascal Revision history [most recent first]: 1998 November 27 [Jean Debord] Replaced the constant MAXPOWER by a variable which is initialized according to the value of MAX_FLT defined in MATRICES.PAS 1997 March 1 [Jean Debord] Modifications for use with the TP Math library: 1. Added a USES clause for the TP Math units. 2. Set real type to Float (defined in FMATH.PAS) 3. Added a constant MAXPOWER to define the maximum number of points. Modified functions IsPowerOfTwo and NumberOfBitsNeeded accordingly. 4. Changed array types to those defined in TP Math. Modified array allocation, deallocation and reference accordingly. 5. Removed compiler directives, which were no longer necessary. 6. Modified some typographical and formatting options so that the code looks like the other TP Math units. No modification was made to the original algorithm. 1996 December 11 [Don Cross] Improved documentation of the procedure CalcFrequency. Fixed some messed up comments in procedure IFFT. 1996 December 6 [Don Cross] Made procedure 'fft_integer' more efficient when buffer size changes in successive calls: the buffer is now only resized when the input has more samples, not a differing number of samples. Also changed the way 'fft_integer_cleanup' works so that it is more "bullet-proof". 1996 December 4 [Don Cross] Adding the procedure 'CalcFrequency', which calculates the FFT at a specific frequency index p=0..n-1, instead of the whole FFT. This is O(n^2) instead of O(n*log(n)). 1996 November 30 [Don Cross] Adding a routine to allow FFT of an input array of integers. It is called 'fft_integer'. 1996 November 18 [Don Cross] Added some comments. 1996 November 17 [Don Cross] Wrote and debugged first version. ==========================================================================*) unit Fourier; interface uses FMath, Matrices; (*--------------------------------------------------------------------------- procedure FFT Calculates the Fast Fourier Transform of the array of complex numbers represented by 'RealIn' and 'ImagIn' to produce the output complex numbers in 'RealOut' and 'ImagOut'. ---------------------------------------------------------------------------*) procedure FFT(NumSamples : Integer; RealIn, ImagIn, RealOut, ImagOut : PVector); (*--------------------------------------------------------------------------- procedure IFFT Calculates the Inverse Fast Fourier Transform of the array of complex numbers represented by 'RealIn' and 'ImagIn' to produce the output complex numbers in 'RealOut' and 'ImagOut'. ---------------------------------------------------------------------------*) procedure IFFT(NumSamples : Integer; RealIn, ImagIn, RealOut, ImagOut : PVector); (*--------------------------------------------------------------------------- procedure FFT_Integer Same as procedure FFT, but uses Integer input arrays instead of double. Make sure you call FFT_Integer_Cleanup after the last time you call FFT_Integer to free up memory it allocates. ---------------------------------------------------------------------------*) procedure FFT_Integer(NumSamples : Integer; RealIn, ImagIn : PIntVector; RealOut, ImagOut : PVector); (*-------------------------------------------------------------------------- procedure FFT_Integer_Cleanup If you call the procedure 'FFT_Integer', you must call 'FFT_Integer_Cleanup' after the last time you call 'FFT_Integer' in order to free up dynamic memory. --------------------------------------------------------------------------*) procedure FFT_Integer_Cleanup; (*-------------------------------------------------------------------------- procedure CalcFrequency This procedure calculates the complex frequency sample at a given index directly. Use this instead of 'FFT' when you only need one or two frequency samples, not the whole spectrum. It is also useful for calculating the Discrete Fourier Transform (DFT) of a number of data which is not an integer power of 2. For example, you could calculate the DFT of 100 points instead of rounding up to 128 and padding the extra 28 array slots with zeroes. --------------------------------------------------------------------------*) procedure CalcFrequency(NumSamples, FrequencyIndex : Integer; RealIn, ImagIn : PVector; var RealOut, ImagOut : Float); implementation var MaxPower : Integer; function IsPowerOfTwo(X : Integer) : Boolean; var I, Y : Integer; begin Y := 2; for I := 1 to Pred(MaxPower) do begin if X = Y then begin IsPowerOfTwo := True; Exit; end; Y := Y shl 1; end; IsPowerOfTwo := False; end; function NumberOfBitsNeeded(PowerOfTwo : Integer) : Integer; var I : Integer; begin for I := 0 to MaxPower do begin if (PowerOfTwo and (1 shl I)) <> 0 then begin NumberOfBitsNeeded := I; Exit; end; end; end; function ReverseBits(Index, NumBits : Integer) : Integer; var I, Rev : Integer; begin Rev := 0; for I := 0 to NumBits - 1 do begin Rev := (Rev shl 1) or (Index and 1); Index := Index shr 1; end; ReverseBits := Rev; end; procedure FourierTransform(AngleNumerator : Float; NumSamples : Integer; RealIn, ImagIn, RealOut, ImagOut : PVector); var NumBits, I, J, K, N, BlockSize, BlockEnd : Integer; Delta_angle, Delta_ar : Float; Alpha, Beta : Float; Tr, Ti, Ar, Ai : Float; begin if not IsPowerOfTwo(NumSamples) or (NumSamples < 2) then begin Write('Error in procedure Fourier: NumSamples=', NumSamples); WriteLn(' is not a positive integer power of 2.'); Halt; end; NumBits := NumberOfBitsNeeded(NumSamples); for I := 0 to NumSamples - 1 do begin J := ReverseBits(I, NumBits); RealOut^[J] := RealIn^[I]; ImagOut^[J] := ImagIn^[I]; end; BlockEnd := 1; BlockSize := 2; while BlockSize <= NumSamples do begin Delta_angle := AngleNumerator / BlockSize; Alpha := Sin(0.5 * Delta_angle); Alpha := 2.0 * Alpha * Alpha; Beta := Sin(Delta_angle); I := 0; while I < NumSamples do begin Ar := 1.0; (* cos(0) *) Ai := 0.0; (* sin(0) *) J := I; for N := 0 to BlockEnd - 1 do begin K := J + BlockEnd; Tr := Ar * RealOut^[K] - Ai * ImagOut^[K]; Ti := Ar * ImagOut^[K] + Ai * RealOut^[K]; RealOut^[K] := RealOut^[J] - Tr; ImagOut^[K] := ImagOut^[J] - Ti; RealOut^[J] := RealOut^[J] + Tr; ImagOut^[J] := ImagOut^[J] + Ti; Delta_ar := Alpha * Ar + Beta * Ai; Ai := Ai - (Alpha * Ai - Beta * Ar); Ar := Ar - Delta_ar; Inc(J); end; I := I + BlockSize; end; BlockEnd := BlockSize; BlockSize := BlockSize shl 1; end; end; procedure FFT(NumSamples : Integer; RealIn, ImagIn, RealOut, ImagOut : PVector); begin FourierTransform(2 * PI, NumSamples, RealIn, ImagIn, RealOut, ImagOut); end; procedure IFFT(NumSamples : Integer; RealIn, ImagIn, RealOut, ImagOut : PVector); var I : Integer; begin FourierTransform(- 2 * PI, NumSamples, RealIn, ImagIn, RealOut, ImagOut); { Normalize the resulting time samples } for I := 0 to NumSamples - 1 do begin RealOut^[I] := RealOut^[I] / NumSamples; ImagOut^[I] := ImagOut^[I] / NumSamples; end; end; var RealTemp, ImagTemp : PVector; TempArraySize : Integer; procedure FFT_Integer(NumSamples : Integer; RealIn, ImagIn : PIntVector; RealOut, ImagOut : PVector); var I : Integer; begin if NumSamples > TempArraySize then begin FFT_Integer_Cleanup; { free up memory in case we already have some } DimVector(RealTemp, NumSamples); DimVector(ImagTemp, NumSamples); TempArraySize := NumSamples; end; for I := 0 to NumSamples - 1 do begin RealTemp^[I] := RealIn^[I]; ImagTemp^[I] := ImagIn^[I]; end; FourierTransform(2 * PI, NumSamples, RealTemp, ImagTemp, RealOut, ImagOut); end; procedure FFT_Integer_Cleanup; begin if TempArraySize > 0 then begin if RealTemp <> nil then DelVector(RealTemp, TempArraySize); if ImagTemp <> nil then DelVector(ImagTemp, TempArraySize); TempArraySize := 0; end; end; procedure CalcFrequency(NumSamples, FrequencyIndex : Integer; RealIn, ImagIn : PVector; var RealOut, ImagOut : Float); var K : Integer; Cos1, Cos2, Cos3, Theta, Beta : Float; Sin1, Sin2, Sin3 : Float; begin RealOut := 0.0; ImagOut := 0.0; Theta := 2 * PI * FrequencyIndex / NumSamples; Sin1 := Sin(- 2 * Theta); Sin2 := Sin(- Theta); Cos1 := Cos(- 2 * Theta); Cos2 := Cos(- Theta); Beta := 2 * Cos2; for K := 0 to NumSamples - 1 do begin { Update trig values } Sin3 := Beta * Sin2 - Sin1; Sin1 := Sin2; Sin2 := Sin3; Cos3 := Beta * Cos2 - Cos1; Cos1 := Cos2; Cos2 := Cos3; RealOut := RealOut + RealIn^[K] * Cos3 - ImagIn^[K] * Sin3; ImagOut := ImagOut + ImagIn^[K] * Cos3 + RealIn^[K] * Sin3; end; end; begin { Unit initialization code } MaxPower := Trunc(Log2(MAX_FLT)); { Max power of two } TempArraySize := 0; { flag that buffers RealTemp, RealImag not allocated } RealTemp := nil; ImagTemp := nil; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/_clean.bat�����������������������������������������������0000755�0001750�0001750�00000000213�10722125610�017773� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������del /S *.~* del /S *.dcu del /S *.dsk del /S *.cfg del /S *.dof del /S *.obj del /S *.hpp del /S *.ddp del /S *.mps del /S *.mpt �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/fitexpo.pas����������������������������������������������0000755�0001750�0001750�00000024271�11326443506�020267� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITEXPO.PAS * * Version 1.4 * * (c) J. Debord, August 2000 * ********************************************************************** This unit fits a sum of decreasing exponentials : y = Ymin + A1.exp(-a1.x) + A2.exp(-a2.x) + A3.exp(-a3.x) + ... ********************************************************************** } unit FitExpo; {$F+} interface uses FMath, Matrices, Polynom, Stat, Regress; const NO_REAL_ROOT = - 2; { No real exponent } function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X : Float; B, D : PVector); function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; procedure InitModel(CstPar : PVector); implementation const N_exp : Integer = 1; { Number of exponentials } ConsTerm : Boolean = True; { Flags the presence of a constant term Ymin } function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } var I : Integer; Name, S : String; begin Name := 'y = '; if ConsTerm then Name := Name + 'Ymin + '; Name := Name + 'A1.exp(-a1.x)'; for I := 2 to N_exp do begin Str(I, S); Name := Name + ' + A' + S + '.exp(-a' + S + '.x)'; end; FuncName := Name; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted (0 if there is a constant term Ymin, 1 otherwise) -------------------------------------------------------------------- } begin if ConsTerm then FirstParam := 0 else FirstParam := 1; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 2 * N_exp; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } var S : String; begin if I = 0 then ParamName := 'Ymin' else if Odd(I) then begin Str(Succ(I) div 2, S); ParamName := 'A' + S; end else begin Str(I div 2, S); ParamName := 'a' + S; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = Ymin B^[1] = A1 B^[2] = a1 ............................... B^[2*i-1] = Ai B^[2*i] = ai i = 1..N_exp -------------------------------------------------------------------- } var I : Integer; S : Float; begin if ConsTerm then S := B^[0] else S := 0.0; for I := 1 to N_exp do S := S + B^[2 * I - 1] * Expo(- B^[2 * I] * X); RegFunc := S; end; procedure DerivProc(X : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point X with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter. -------------------------------------------------------------------- } var I, P, Q : Integer; E : Float; begin D^[0] := 1.0; { dy/dYmin = 1 } for I := 1 to N_exp do begin Q := 2 * I; P := Pred(Q); E := Expo(- B^[Q] * X); D^[P] := E; { dy/dAi = exp(-ai.x) } D^[Q] := - X * B^[P] * E; { dy/dai = -x.Ai.exp(-ai.x) } end; end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of a sum of exponentials by linear regression -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- Ref. : R. GOMENI & C. GOMENI, Automod : A polyalgorithm for an integrated analysis of linear pharmacokinetic models Comput. Biol. Med., 1979, 9, 39-48 -------------------------------------------------------------------- } var I, K, M : Integer; X1, Y1 : PVector; { Modified coordinates } U : PMatrix; { Variables for linear regression } P : PVector; { Linear regression parameters } C, Z : PVector; { Coefficients and roots of polynomial } V : PMatrix; { Variance-covariance matrix } H : Float; { Integration step } ErrCode : Integer; { Error code } begin M := Pred(2 * N_exp); DimVector(X1, N); DimVector(Y1, N); DimMatrix(U, M, N); DimMatrix(V, M, M); DimVector(P, M); DimVector(C, N_exp); DimVector(Z, N_exp); CopyVector(X1, X, 1, N); CopyVector(Y1, Y, 1, N); { Change scale so that the X's begin at zero } if X^[1] <> 0.0 then for K := 1 to N do X1^[K] := X1^[K] - X^[1]; { Estimate the constant term at 90% of the lowest observed value, then subtract it from each Y value } if ConsTerm then begin B^[0] := 0.9 * Min(Y1, 1, N); for K := 1 to N do Y1^[K] := Y1^[K] - B^[0]; end; { ------------------------------------------------------------------ Fit the linearized form of the function : y = p(0) + p(1) * x + p(2) * x^2 + ... + p(N_exp-1) * x^(N_exp-1) (x (x (x + p(N_exp) | y dx + ... + p(2*N_exp-1) | ....| y dx )0 )0 )0 ------------------------------------------------------------------ } { Compute increasing powers of X } if N_exp > 1 then for K := 2 to N do begin U^[1]^[K] := X1^[K]; for I := 2 to Pred(N_exp) do U^[I]^[K] := U^[I - 1]^[K] * X1^[K]; end; { Compute integrals by the trapezoidal rule } for K := 2 to N do begin H := 0.5 * (X1^[K] - X1^[K - 1]); U^[N_exp]^[K] := U^[N_exp]^[K - 1] + (Y1^[K] + Y1^[K - 1]) * H; for I := Succ(N_exp) to M do U^[I]^[K] := U^[I]^[K - 1] + (U^[I - 1]^[K] + U^[I - 1]^[K - 1]) * H; end; { Fit the equation } case Method of 0 : ErrCode := MulFit(U, Y1, N, M, True, P, V); 1 : ErrCode := WMulFit(U, Y1, W, N, M, True, P, V); end; if ErrCode = MAT_SINGUL then FitModel := ErrCode else begin { ---------------------------------------------------------------- The exponents are the roots of the polynomial : x^N_exp + p(N_exp) * x^(N_exp-1) - p(N_exp+1) * x^(N_exp-2) +... ---------------------------------------------------------------- } { Compute polynomial coefficients } C^[N_exp] := 1.0; for I := 1 to N_exp do if Odd(I) then C^[N_exp - I] := P^[N_exp + I - 1] else C^[N_exp - I] := - P^[N_exp + I - 1]; { Solve polynomial } if RRootPol(C, N_exp, Z) <> N_exp then FitModel := NO_REAL_ROOT else begin { Sort exponents in decreasing order } DQSort(Z, 1, N_exp); { Compute the coefficients of the exponentials by linear regression on the exponential terms } for I := 1 to N_exp do for K := 1 to N do U^[I]^[K] := Expo(- Z^[I] * X1^[K]); case Method of 0 : ErrCode := MulFit(U, Y1, N, N_exp, False, P, V); 1 : ErrCode := WMulFit(U, Y1, W, N, N_exp, False, P, V); end; if ErrCode = MAT_SINGUL then FitModel := ErrCode else begin { Extract model parameters } for I := 1 to N_exp do begin { Correct for scale change if necessary } if X^[1] <> 0.0 then P^[I] := P^[I] * Expo(Z^[I] * X^[1]); { Extract coefficients and exponents } B^[2 * I - 1] := P^[I]; { Coefficients } B^[2 * I] := Z^[I]; { Exponents } end; FitModel := MAT_OK; end; end; end; DelVector(X1, N); DelVector(Y1, N); DelMatrix(U, M, N); DelMatrix(V, M, M); DelVector(P, M); DelVector(C, N_exp); DelVector(Z, N_exp); end; procedure InitModel(CstPar : PVector); { -------------------------------------------------------------------- Initializes the global variables of the unit -------------------------------------------------------------------- CstPar^[0] = number of exponentials CstPar^[1] = 1 to include a constant term (Ymin) -------------------------------------------------------------------- } var N : Integer; begin N := Round(CstPar^[0]); if N > 0 then N_exp := N; ConsTerm := (CstPar^[1] = 1); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/models.pas�����������������������������������������������0000755�0001750�0001750�00000047411�11326443506�020075� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit MODELS.PAS * * Version 1.4 * * (c) J. Debord, August 2000 * ********************************************************************** Library of regression and variance models ********************************************************************** } unit Models; {$F+} interface uses FMath, Matrices, Regress, FitLin, FitMult, FitPoly, FitFrac, FitExpo, FitIExpo, FitExLin, FitPower, FitMich, FitHill, FitLogis, FitPKa; { --------------------------------------------------------------------- Highest index of regression models --------------------------------------------------------------------- } const MAXMODEL = 11; { --------------------------------------------------------------------- Highest index of variance models --------------------------------------------------------------------- } const MAXVARMODEL = 5; { --------------------------------------------------------------------- Definition of regression models --------------------------------------------------------------------- } const REG_LIN = 0; { Linear } REG_MULT = 1; { Multiple linear } REG_POL = 2; { Polynomial } REG_FRAC = 3; { Rational fraction } REG_EXPO = 4; { Sum of exponentials } REG_IEXPO = 5; { Increasing exponential } REG_EXLIN = 6; { Exponential + linear } REG_POWER = 7; { Power } REG_MICH = 8; { Michaelis } REG_HILL = 9; { Hill } REG_LOGIS = 10; { Logistic } REG_PKA = 11; { Acid/Base titration curve } { --------------------------------------------------------------------- Definition of variance models --------------------------------------------------------------------- } const VAR_CONST = 0; { Constant } VAR_LIN = 1; { Linear } VAR_POL2 = 2; { 2nd degree polynomial } VAR_POL3 = 3; { 3rd degree polynomial } VAR_EXPO = 4; { Exponential } VAR_POWER = 5; { Power } { --------------------------------------------------------------------- Names of regression models --------------------------------------------------------------------- } const MODELNAME : array[0..MAXMODEL] of String = {$IFDEF FRENCH} ('Lineaire', 'Lineaire multiple', 'Polynomial', 'Fraction rationnelle', 'Somme d''exponentielles', 'Exponentielle croissante', 'Exponentielle + lineaire', 'Puissance', 'Michaelis', 'Hill', 'Logistique', 'Titrage acide/base'); {$ELSE} ('Linear', 'Multiple linear', 'Polynomial', 'Rational fraction', 'Sum of exponentials', 'Increasing exponential', 'Exponential + linear', 'Power', 'Michaelis', 'Hill', 'Logistic', 'Acid/Base titration curve'); {$ENDIF} { --------------------------------------------------------------------- Names of variance models --------------------------------------------------------------------- } const VARMODELNAME : array[0..MAXVARMODEL] of String = {$IFDEF FRENCH} ('Constante', 'Lineaire', 'Polynome de degre 2', 'Polynome de degre 3', 'Exponentielle', 'Puissance'); {$ELSE} ('Constant', 'Linear', '2nd degree polynomial', '3rd degree polynomial', 'Exponential', 'Power'); {$ENDIF} function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first fitted parameter -------------------------------------------------------------------- } function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last fitted parameter -------------------------------------------------------------------- } function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th fitted parameter -------------------------------------------------------------------- } function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function for one independent variable B is the vector of parameters -------------------------------------------------------------------- } function RegFuncNVar(X, B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function for several independent variables B is the vector of parameters -------------------------------------------------------------------- } procedure DerivProc(RegFunc : TRegFunc; X, Y : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point (X,Y) with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter. -------------------------------------------------------------------- } procedure InitModel(Reg_Model, Var_Model : Integer; CstPar : PVector); { -------------------------------------------------------------------- Initializes the regression and variance models. Constant parameters (e.g. degree of polynomial) are passed in vector CstPar. -------------------------------------------------------------------- } function WLSFit(X : PVector; U : PMatrix; Y : PVector; N : Integer; Init : Boolean; MaxIter : Integer; Tol : Float; Theta, B : PVector; B_min, B_max : PVector; V : PMatrix; Ycalc, S : PVector; var Test : TRegTest) : Integer; { ---------------------------------------------------------------------- Fits the regression function and computes the regression tests ---------------------------------------------------------------------- Input : X, U = vector or matrix of independent variable(s) Y = vector of dependent variable N = number of observations Init = TRUE to compute initial parameter estimates FALSE to use the current values MaxIter = maximum number of iterations (if 0 the parameters will not be refined) Tol = required parameter precision Theta = variance parameters B = initial parameters values B_min, B_max = parameter bounds -------------------------------------------------------------------- Output : Theta = updated variance parameters (residual variance stored in Theta^[0]) B = regression parameters V = variance-covariance matrix Ycalc = estimated Y values S = standard deviations of Y Test = regression tests -------------------------------------------------------------------- Possible results = OPT_OK : no error OPT_SING : singular matrix OPT_BIG_LAMBDA : too high Marquardt's parameter OPT_NON_CONV : non-convergence -------------------------------------------------------------------- } function VarFuncName : String; { -------------------------------------------------------------------- Returns the name of the variance function -------------------------------------------------------------------- } function LastVarParam : Integer; { ---------------------------------------------------------------------- Returns the index of the last variance parameter (upper bound of Theta) ---------------------------------------------------------------------- } function VarFunc(Y : Float; Theta : PVector) : Float; { -------------------------------------------------------------------- Computes the variance of an observation Y. The parameters are Theta^[1], Theta^[2],... The true variance is Theta^[0] * VarFunc, where Theta^[0] (equal to the residual variance Vr) is estimated by the regression program. -------------------------------------------------------------------- } implementation const RegModel : Integer = 0; { Index of regression model } VarModel : Integer = 0; { Index of variance model } function FuncName : String; begin case RegModel of REG_LIN : FuncName := FitLin.FuncName; REG_MULT : FuncName := FitMult.FuncName; REG_POL : FuncName := FitPoly.FuncName; REG_FRAC : FuncName := FitFrac.FuncName; REG_EXPO : FuncName := FitExpo.FuncName; REG_IEXPO : FuncName := FitIExpo.FuncName; REG_EXLIN : FuncName := FitExLin.FuncName; REG_POWER : FuncName := FitPower.FuncName; REG_MICH : FuncName := FitMich.FuncName; REG_HILL : FuncName := FitHill.FuncName; REG_LOGIS : FuncName := FitLogis.FuncName; REG_PKA : FuncName := FitPKa.FuncName; end; end; function FirstParam : Integer; begin case RegModel of REG_LIN : FirstParam := FitLin.FirstParam; REG_MULT : FirstParam := FitMult.FirstParam; REG_POL : FirstParam := FitPoly.FirstParam; REG_FRAC : FirstParam := FitFrac.FirstParam; REG_EXPO : FirstParam := FitExpo.FirstParam; REG_IEXPO : FirstParam := FitIExpo.FirstParam; REG_EXLIN : FirstParam := FitExLin.FirstParam; REG_POWER : FirstParam := FitPower.FirstParam; REG_MICH : FirstParam := FitMich.FirstParam; REG_HILL : FirstParam := FitHill.FirstParam; REG_LOGIS : FirstParam := FitLogis.FirstParam; REG_PKA : FirstParam := FitPKa.FirstParam; end; end; function LastParam : Integer; begin case RegModel of REG_LIN : LastParam := FitLin.LastParam; REG_MULT : LastParam := FitMult.LastParam; REG_POL : LastParam := FitPoly.LastParam; REG_FRAC : LastParam := FitFrac.LastParam; REG_EXPO : LastParam := FitExpo.LastParam; REG_IEXPO : LastParam := FitIExpo.LastParam; REG_EXLIN : LastParam := FitExLin.LastParam; REG_POWER : LastParam := FitPower.LastParam; REG_MICH : LastParam := FitMich.LastParam; REG_HILL : LastParam := FitHill.LastParam; REG_LOGIS : LastParam := FitLogis.LastParam; REG_PKA : LastParam := FitPKa.LastParam; end; end; function ParamName(I : Integer) : String; begin case RegModel of REG_LIN : ParamName := FitLin.ParamName(I); REG_MULT : ParamName := FitMult.ParamName(I); REG_POL : ParamName := FitPoly.ParamName(I); REG_FRAC : ParamName := FitFrac.ParamName(I); REG_EXPO : ParamName := FitExpo.ParamName(I); REG_IEXPO : ParamName := FitIExpo.ParamName(I); REG_EXLIN : ParamName := FitExLin.ParamName(I); REG_POWER : ParamName := FitPower.ParamName(I); REG_MICH : ParamName := FitMich.ParamName(I); REG_HILL : ParamName := FitHill.ParamName(I); REG_LOGIS : ParamName := FitLogis.ParamName(I); REG_PKA : ParamName := FitPKa.ParamName(I); end; end; function RegFunc(X : Float; B : PVector) : Float; begin case RegModel of REG_LIN : RegFunc := FitLin.RegFunc(X, B); REG_POL : RegFunc := FitPoly.RegFunc(X, B); REG_FRAC : RegFunc := FitFrac.RegFunc(X, B); REG_EXPO : RegFunc := FitExpo.RegFunc(X, B); REG_IEXPO : RegFunc := FitIExpo.RegFunc(X, B); REG_EXLIN : RegFunc := FitExLin.RegFunc(X, B); REG_POWER : RegFunc := FitPower.RegFunc(X, B); REG_MICH : RegFunc := FitMich.RegFunc(X, B); REG_HILL : RegFunc := FitHill.RegFunc(X, B); REG_LOGIS : RegFunc := FitLogis.RegFunc(X, B); REG_PKA : RegFunc := FitPKa.RegFunc(X, B); end; end; function RegFuncNVar(X, B : PVector) : Float; begin case RegModel of REG_MULT : RegFuncNVar := FitMult.RegFunc(X, B); end; end; procedure DerivProc(RegFunc : TRegFunc; X, Y : Float; B, D : PVector); begin case RegModel of REG_FRAC : FitFrac.DerivProc(X, Y, B, D); REG_EXPO : FitExpo.DerivProc(X, B, D); REG_IEXPO : FitIExpo.DerivProc(X, B, D); REG_EXLIN : FitExLin.DerivProc(X, B, D); REG_POWER : FitPower.DerivProc(X, Y, B, D); REG_MICH : FitMich.DerivProc(X, Y, B, D); REG_HILL : FitHill.DerivProc(X, Y, B, D); REG_LOGIS : FitLogis.DerivProc(X, B, D); REG_PKA : FitPKa.DerivProc(X, B, D); else NumDeriv(RegFunc, X, Y, B, D); end; end; procedure InitModel(Reg_Model, Var_Model : Integer; CstPar : PVector); begin RegModel := Reg_Model; VarModel := Var_Model; case RegModel of REG_MULT : FitMult.InitModel(CstPar); REG_POL : FitPoly.InitModel(CstPar); REG_FRAC : FitFrac.InitModel(CstPar); REG_EXPO : FitExpo.InitModel(CstPar); REG_LOGIS : FitLogis.InitModel(CstPar); end; end; function FitModel(Method : Integer; X : PVector; U : PMatrix; Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; { -------------------------------------------------------------------- Fits the regression model by unweighted linear least squares. For nonlinear models, this is only an approximate fit, to be refined by the nonlinear regression procedure WLSFit -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, U = vector or matrix of independent variable(s) Y = vector of dependent variable W = weights N = number of observations -------------------------------------------------------------------- Output : B = estimated regression parameters V = unscaled variance-covariance matrix (for linear and polynomial models only). The true matrix will be Vr * V, where Vr is the residual variance. -------------------------------------------------------------------- The function returns 0 if no error occurred -------------------------------------------------------------------- } begin case RegModel of REG_LIN : FitModel := FitLin.FitModel(Method, X, Y, W, N, B, V); REG_MULT : FitModel := FitMult.FitModel(Method, U, Y, W, N, B, V); REG_POL : FitModel := FitPoly.FitModel(Method, X, Y, W, N, B, V); REG_FRAC : FitModel := FitFrac.FitModel(Method, X, Y, W, N, B); REG_EXPO : FitModel := FitExpo.FitModel(Method, X, Y, W, N, B); REG_IEXPO : FitModel := FitIExpo.FitModel(Method, X, Y, W, N, B); REG_EXLIN : FitModel := FitExLin.FitModel(X, Y, N, B); REG_POWER : FitModel := FitPower.FitModel(Method, X, Y, W, N, B); REG_MICH : FitModel := FitMich.FitModel(Method, X, Y, W, N, B); REG_HILL : FitModel := FitHill.FitModel(Method, X, Y, W, N, B); REG_LOGIS : FitModel := FitLogis.FitModel(Method, X, Y, W, N, B); REG_PKA : FitModel := FitPKa.FitModel(X, Y, N, B); end; end; function WLSFit(X : PVector; U : PMatrix; Y : PVector; N : Integer; Init : Boolean; MaxIter : Integer; Tol : Float; Theta, B : PVector; B_min, B_max : PVector; V : PMatrix; Ycalc, S : PVector; var Test : TRegTest) : Integer; var Method : Integer; { Regression method } W : PVector; { Weights } Xk : PVector; { Vector of variables for observation k } Sr : Float; { Residual standard deviation } ErrCode : Integer; { Error code } K : Integer; { Loop variable } begin DimVector(W, N); DimVector(Xk, LastParam); { Determine regression method } if VarModel = VAR_CONST then Method := 0 else Method := 1; { Compute weights if necessary } if Method = 1 then for K := 1 to N do W^[K] := 1.0 / VarFunc(Y^[K], Theta); { Compute initial parameter estimates if necessary } if Init then ErrCode := FitModel(Method, X, U, Y, W, N, B, V) else ErrCode := 0; { Refine parameters if necessary } if not(RegModel in [REG_LIN, REG_MULT, REG_POL]) and (MaxIter > 0) and (ErrCode = 0) then if VarModel = VAR_CONST then ErrCode := NLFit({$IFDEF FPK}@{$ENDIF}RegFunc, {$IFDEF FPK}@{$ENDIF}DerivProc, X, Y, N, FirstParam, LastParam, MaxIter, Tol, B, B_min, B_max, V) else ErrCode := WNLFit({$IFDEF FPK}@{$ENDIF}RegFunc, {$IFDEF FPK}@{$ENDIF}DerivProc, X, Y, W, N, FirstParam, LastParam, MaxIter, Tol, B, B_min, B_max, V); if ErrCode = 0 then begin { Estimate Y values } if RegModel = REG_MULT then for K := 1 to N do begin CopyVectorFromCol(Xk, U, FirstParam, LastParam, K); Ycalc^[K] := RegFuncNVar(Xk, B); end else for K := 1 to N do Ycalc^[K] := RegFunc(X^[K], B); { Compute regression tests and update variance-covariance matrix } if VarModel = VAR_CONST then RegTest(Y, Ycalc, N, FirstParam, LastParam, V, Test) else WRegTest(Y, Ycalc, W, N, FirstParam, LastParam, V, Test); { Store residual variance in Theta^[0] } Theta^[0] := Test.Vr; { Compute standard deviations } Sr := Sqrt(Test.Vr); for K := 1 to N do S^[K] := Sr; if VarModel <> VAR_CONST then for K := 1 to N do S^[K] := S^[K] / Sqrt(W^[K]); end; DelVector(W, N); DelVector(Xk, LastParam); WLSFit := ErrCode; end; function VarFuncName : String; begin case VarModel of VAR_CONST : VarFuncName := 'v = e0'; VAR_LIN : VarFuncName := 'v = e0.(1 + e1.y)'; VAR_POL2 : VarFuncName := 'v = e0.(1 + e1.y + e2.y^2)'; VAR_POL3 : VarFuncName := 'v = e0.(1 + e1.y + e2.y^2 + e3.y^3)'; VAR_EXPO : VarFuncName := 'v = e0.exp(e1.y)'; VAR_POWER : VarFuncName := 'v = e0.y^e1'; end; end; function VarFunc(Y : Float; Theta : PVector) : Float; begin case VarModel of VAR_CONST : VarFunc := 1.0; VAR_LIN : VarFunc := 1.0 + Theta^[1] * Y; VAR_POL2 : VarFunc := 1.0 + Y * (Theta^[1] + Theta^[2] * Y); VAR_POL3 : VarFunc := 1.0 + Y * (Theta^[1] + Y * (Theta^[2] + Theta^[3] * Y)); VAR_EXPO : VarFunc := Exp(Theta^[1] * Y); VAR_POWER : VarFunc := Power(Y, Theta^[1]); end; end; function LastVarParam : Integer; begin case VarModel of VAR_CONST : LastVarParam := 0; VAR_LIN : LastVarParam := 1; VAR_POL2 : LastVarParam := 2; VAR_POL3 : LastVarParam := 3; VAR_EXPO : LastVarParam := 1; VAR_POWER : LastVarParam := 1; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/fitpoly.pas����������������������������������������������0000755�0001750�0001750�00000007775�11326443506�020311� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITPOLY.PAS * * Version 1.2 * * (c) J. Debord, March 1999 * ********************************************************************** This unit fits a polynomial : y = b0 + b1.x + b2.x^2 + ... ********************************************************************** } unit FitPoly; {$F+} interface uses FMath, Matrices, Polynom, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; procedure InitModel(CstPar : PVector); implementation const Deg : Integer = 2; { Degree of polynomial } function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function. -------------------------------------------------------------------- } var Name, S : String; I : Integer; begin Name := 'y = b0 + b1.x'; for I := 2 to Deg do begin Str(I, S); Name := Name + ' + b' + S + '.x^' + S; end; FuncName := Name; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted. -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted. -------------------------------------------------------------------- } begin LastParam := Deg; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter. -------------------------------------------------------------------- } var S : String; begin Str(I, S); ParamName := 'b' + S; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X. B is the vector of parameters (coefficients of polynomial). -------------------------------------------------------------------- } begin RegFunc := Poly(X, B, Deg); end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector; V : PMatrix) : Integer; { -------------------------------------------------------------------- Fit of polynomial. -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters V = variance-covariance matrix of parameters -------------------------------------------------------------------- } begin case Method of 0 : FitModel := PolFit(X, Y, N, Deg, B, V); 1 : FitModel := WPolFit(X, Y, W, N, Deg, B, V); end; end; procedure InitModel(CstPar : PVector); { -------------------------------------------------------------------- Initializes the global variables of the unit. -------------------------------------------------------------------- CstPar^[0] = Degree of polynomial -------------------------------------------------------------------- } var D : Integer; begin D := Round(CstPar^[0]); if D > 1 then Deg := D; end; end. ���mricron-0.20140804.1~dfsg.1.orig/npm/dmath/texplot.pas����������������������������������������������0000755�0001750�0001750�00000036214�11326443506�020310� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit TEXPLOT.PAS * * Version 1.1 * * (c) J. Debord, June 2001 * ********************************************************************** Plotting routines for TeX/PSTricks ********************************************************************** } unit TexPlot; interface uses FMath, Matrices, PaString; { ********************** Include global variables ********************** } {$I PLOTVAR.INC} { ************************** Graphic routines ************************** } procedure InitTexGraph(var F : Text; FileName : String); { ---------------------------------------------------------------------- Initializes TeX graphics. Writes a border around the graph according to the value of the global variable GraphBorder (defined in PLOTVAR.INC) ---------------------------------------------------------------------- F : file to be written FileName : name of TeX file (e.g. 'figure.tex') ---------------------------------------------------------------------- } function Xcm(X : Float) : Float; { ---------------------------------------------------------------------- Converts user coordinate X to cm ---------------------------------------------------------------------- } function Ycm(Y : Float) : Float; { ---------------------------------------------------------------------- Converts user coordinate Y to cm ---------------------------------------------------------------------- } procedure WriteXAxis(var F : Text); { ---------------------------------------------------------------------- Writes horizontal axis (global variable XAxis in PLOTVAR.INC) ---------------------------------------------------------------------- } procedure WriteYAxis(var F : Text); { ---------------------------------------------------------------------- Writes vertical axis (global variable YAxis in PLOTVAR.INC) ---------------------------------------------------------------------- } procedure WriteGrid(var F : Text); { ---------------------------------------------------------------------- Writes a grid (global variable Grid in PLOTVAR.INC) ---------------------------------------------------------------------- } procedure WriteLine(var F : Text; X1, Y1, X2, Y2 : Float; Style : String); { ---------------------------------------------------------------------- Writes a line between two points ---------------------------------------------------------------------- F : output file X1, Y1 : coordinates of first point X2, Y2 : coordinates of second point Style : line style (must be 'solid', 'dotted' or 'dashed') ---------------------------------------------------------------------- } procedure WritePoints(var F : Text; X, Y : PVector; Lbound, Ubound, Symbol, Size : Integer); { ---------------------------------------------------------------------- Writes a set of points ---------------------------------------------------------------------- F : output file X, Y : point coordinates Lbound, Ubound : indices of first and last point Symbol : 1 = solid circle 2 = open circle 3 = solid square 4 = open square 5 = solid triangle 6 = open triangle 7 = plus (+) 8 = multiply (x) 9 = star (*) Size : size of points ---------------------------------------------------------------------- } procedure WriteText(var F : Text; Place : String; X, Y : Float; S : String); { ---------------------------------------------------------------------- Writes a text ---------------------------------------------------------------------- F : output file Place : defines the position of point (X,Y) with respect to the box enclosing the text the possible values are 'tl', 't', 'tr', 'l', 'r', 'Bl', 'B', 'Br', 'bl', 'b', 'br' according to the following scheme: t tl +---------------------+ tr | | | | l | | r | | Bl |----------B----------| Br bl +---------------------+ br b X, Y : position of text S : text to be written ---------------------------------------------------------------------- } procedure WriteNumber(var F : Text; Place : String; X, Y, Z : Float); { ---------------------------------------------------------------------- Writes a number ---------------------------------------------------------------------- Z is the number to be written Other parameters as in WriteText ---------------------------------------------------------------------- } procedure WriteCurve(var F : Text; X, Y : PVector; Lbound, Ubound, Width : Integer; Style : String; Smooth : Boolean); { ---------------------------------------------------------------------- Writes a curve ---------------------------------------------------------------------- F : output file X, Y : point coordinates Lbound, Ubound : indices of first and last point Width : curve width in units of 0.01 cm Style : curve style (must be 'solid', 'dotted' or 'dashed') Smooth : indicates if the curve must be smoothed ---------------------------------------------------------------------- } procedure WriteFunc(var F : Text; Func : TFunc; X1, X2 : Float; Npt, Width : Integer; Style : String); { ---------------------------------------------------------------------- Writes the curve representing a function ---------------------------------------------------------------------- F : output file Func : function to be plotted X1, X2 : abscissae of 1st and last point to plot Npt : number of points Width, Style : width of curve (as in WriteCurve) ---------------------------------------------------------------------- The function must be programmed as: function Func(X : Float) : Float; ---------------------------------------------------------------------- } procedure CloseTexGraph(var F : Text); { ---------------------------------------------------------------------- Close graphics ---------------------------------------------------------------------- } implementation const PAGEWIDTH = 13; { Graph width in cm } PAGEHEIGHT = 10; { Graph height in cm } var XminCm, YminCm : Float; { Coord. of lower left corner in cm } XmaxCm, YmaxCm : Float; { Coord. of upper right corner in cm } FactX, FactY : Float; { Scaling factors } function Xcm(X : Float) : Float; { Converts user coordinate X to cm } begin Xcm := XminCm + FactX * (X - XAxis.Min); end; function Ycm(Y : Float) : Float; { Converts user coordinate Y to cm } begin Ycm := YminCm + FactY * (Y - YAxis.Min); end; procedure WriteHeader(var F : Text); begin WriteLn(F, '\documentclass[12pt,a4paper]{article}'); WriteLn(F, '\usepackage{t1enc}'); WriteLn(F, '\usepackage{pst-plot}'); WriteLn(F, '\begin{document}'); WriteLn(F); WriteLn(F, '\begin{pspicture}(', PAGEWIDTH, ',', PAGEHEIGHT, ')'); end; procedure WriteCoord(var F : Text; X, Y : Float); { Writes the coordinates (in cm) of a point } var NSZ : Boolean; begin NSZ := NSZEro; NSZero := False; Write(F, '(', Trim(FloatToStr(X)), ',', Trim(FloatToStr(Y)), ')'); NSZEro := NSZ; end; procedure WriteLine(var F : Text; X1, Y1, X2, Y2 : Float; Style : String); begin Write(F, '\psline'); if Style <> '' then Write(F, '[linestyle=', Style, ']'); WriteCoord(F, X1, Y1); WriteCoord(F, X2, Y2); WriteLn(F); end; procedure WriteText(var F : Text; Place : String; X, Y : Float; S : String); begin Write(F, '\rput[', Place, ']'); WriteCoord(F, X, Y); WriteLn(F, '{', S, '}'); end; procedure WriteNumber(var F : Text; Place : String; X, Y, Z : Float); begin Write(F, '\rput[', Place, ']'); WriteCoord(F, X, Y); WriteLn(F, '{', Trim(FloatToStr(Z)), '}'); end; procedure WriteXAxis(var F: Text); var W, X, Xc, Z : Float; N, I, J : Integer; NSZ : Boolean; begin WriteLine(F, XminCm, YminCm, XmaxCm, YminCm, ''); N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); { Nb of intervals } X := XAxis.Min; { Tick mark position } NSZ := NSZero; NSZero := False; { Don't write non significant zero's } for I := 0 to N do { Label axis } begin if (XAxis.Scale = LIN_SCALE) and (Abs(X) < EPS) then X := 0.0; Xc := Xcm(X); WriteLine(F, Xc, YminCm, Xc, YminCm - 0.25, ''); { Tick mark } if XAxis.Scale = LIN_SCALE then Z := X else Z := Exp10(X); WriteNumber(F, 't', Xc, YminCm - 0.35, Z); { Label } if (XAxis.Scale = LOG_SCALE) and (I < N) then for J := 2 to 9 do { Plot minor divisions } begin { on logarithmic scale } W := X + Log10(J); Xc := Xcm(W); WriteLine(F, Xc, YminCm, Xc, YminCm - 0.15, ''); end; X := X + XAxis.Step; end; { Write axis title } if XTitle.Text <> '' then WriteText(F, 't', 0.5 * (XminCm + XmaxCm), YminCm - 1.0, XTitle.Text); NSZero := NSZ; end; procedure WriteYAxis(var F : Text); var W, Y, Yc, Z : Float; N, I, J : Integer; NSZ : Boolean; begin WriteLine(F, XminCm, YminCm, XminCm, YmaxCm, ''); N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); Y := YAxis.Min; NSZ := NSZero; NSZero := False; for I := 0 to N do begin if (YAxis.Scale = LIN_SCALE) and (Abs(Y) < EPS) then Y := 0.0; Yc := Ycm(Y); WriteLine(F, XminCm, Yc, XminCm - 0.25, Yc, ''); if YAxis.Scale = LIN_SCALE then Z := Y else Z := Exp10(Y); WriteNumber(F, 'r', XminCm - 0.35, Yc, Z); if (YAxis.Scale = LOG_SCALE) and (I < N) then for J := 2 to 9 do begin W := Y + Log10(J); Yc := Ycm(W); WriteLine(F, XminCm, Yc, XminCm - 0.15, Yc, ''); end; Y := Y + YAxis.Step; end; { Write axis title } if YTitle.Text <> '' then WriteText(F, 'l', XminCm, YmaxCm + 0.5, YTitle.Text); NSZero := NSZ; end; procedure WriteGrid(var F : Text); var X, Y, Xc, Yc : Float; I, N : Integer; begin { Horizontal lines } if Grid in [HORIZ_GRID, BOTH_GRID] then begin N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); { Nb of intervals } for I := 1 to Pred(N) do begin Y := YAxis.Min + I * YAxis.Step; { Origin of line } Yc := Ycm(Y); WriteLine(F, XminCm, Yc, XmaxCm, Yc, 'dotted'); end; end; { Vertical lines } if Grid in [VERTIC_GRID, BOTH_GRID] then begin N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); for I := 1 to Pred(N) do begin X := XAxis.Min + I * XAxis.Step; Xc := Xcm(X); WriteLine(F, Xc, YminCm, Xc, YmaxCm, 'dotted'); end; end; end; procedure InitTexGraph(var F : Text; Filename : String); begin XminCm := 0.01 * Xwin1 * PAGEWIDTH; XmaxCm := 0.01 * Xwin2 * PAGEWIDTH; YminCm := 0.01 * Ywin1 * PAGEHEIGHT; YmaxCm := 0.01 * Ywin2 * PAGEHEIGHT; FactX := (XmaxCm - XminCm) / (XAxis.Max - XAxis.Min); FactY := (YmaxCm - YminCm) / (YAxis.Max - YAxis.Min); Assign(F, FileName); Rewrite(F); WriteHeader(F); if GraphBorder then begin Write(F, '\pspolygon'); WriteCoord(F, XminCm, YminCm); WriteCoord(F, XmaxCm, YminCm); WriteCoord(F, XmaxCm, YmaxCm); WriteCoord(F, XminCm, YmaxCm); WriteLn(F); end; end; procedure WritePoint(var F : Text; X, Y : Float); var Xc, Yc : Float; begin if XAxis.Scale = LOG_SCALE then X := Log10(X); if YAxis.Scale = LOG_SCALE then Y := Log10(Y); Xc := Xcm(X); Yc := Ycm(Y); if (Xc >= XminCm) and (Xc <= XmaxCm) and (Yc >= YminCm) and (Yc <= YmaxCm) then WriteCoord(F, Xc, Yc); end; procedure WritePoints(var F : Text; X, Y : PVector; Lbound, Ubound, Symbol, Size : Integer); var I, N : Integer; begin Write(F, '\psdots[dotscale=', Size, ' ', Size, ', dotstyle='); case Symbol of 1 : Write(F, '*'); 2 : Write(F, 'o'); 3 : Write(F, 'square*'); 4 : Write(F, 'square'); 5 : Write(F, 'triangle*'); 6 : Write(F, 'triangle'); 7 : Write(F, '+'); 8 : Write(F, 'x'); 9 : Write(F, 'asterisk'); end; WriteLn(F, ']%'); I := Lbound; repeat WritePoint(F, X^[I], Y^[I]); if (I > 0) and (I < Ubound) and (I mod 5 = 0) then WriteLn(F, '%'); Inc(I); until I > Ubound; WriteLn(F); end; procedure WriteCurve(var F : Text; X, Y : PVector; Lbound, Ubound, Width : Integer; Style : String; Smooth : Boolean); var I, N : Integer; W : Float; Ws : String; begin W := 0.01 * Width; Str(W:5:2, Ws); Ws := Trim(Ws); if Smooth then Write(F, '\pscurve') else Write(F, '\psline'); WriteLn(F, '[linewidth=', Ws, ', linestyle=', Style, ']%'); I := Lbound; repeat WritePoint(F, X^[I], Y^[I]); if (I > 0) and (I < Ubound) and (I mod 5 = 0) then WriteLn(F, '%'); Inc(I); until I > Ubound; WriteLn(F); end; procedure WriteFunc(var F : Text; Func : TFunc; X1, X2 : Float; Npt, Width : Integer; Style : String); const X : PVector = nil; Y : PVector = nil; N : Integer = 0; var H : Float; I : Integer; begin if Npt <> N then begin DelVector(X, N); DelVector(Y, N); DimVector(X, Npt); DimVector(Y, Npt); N := Npt; end; H := (X2 - X1) / N; for I := 0 to N do begin X^[I] := X1 + I * H; if XAxis.Scale = LIN_SCALE then Y^[I] := Func(X^[I]) else Y^[I] := Func(Exp10(X^[I])); end; WriteCurve(F, X, Y, 0, N, Width, Style, True); end; procedure CloseTexGraph(var F: Text); begin WriteLn(F, '\end{pspicture}'); WriteLn(F); WriteLn(F, '\end{document}'); Close(F); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/GraphicsMathLibrary.pas����������������������������������0000755�0001750�0001750�00000061473�11326443506�022515� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// Graphics Math Library // // Copyright (C) 1982, 1985, 1992, 1995-1998 Earl F. Glynn, Overland Park, KS. // All Rights Reserved. E-Mail Address: EarlGlynn@att.net UNIT GraphicsMathLibrary; // Matrix/Vector Operations for 2D/3D Graphics} INTERFACE USES SysUtils,dialogs; {Exception} CONST sizeUndefined = 1; size2D = 3; // 'size' of 2D homogeneous vector or transform matrix size3D = 4; // 'size' of 3D homogeneous vector or transform matrix TYPE EVectorError = CLASS(Exception); EMatrixError = CLASS(Exception); TAxis = (axisX, axisY, axisZ); TCoordinate = (coordCartesian, coordSpherical, coordCylindrical); TDimension = (dimen2D, dimen3D); // two- or three-dimensional TYPE TIndex = 1..4; // index of 'TMatrix' and 'TVector' TYPEs TMatrix = // transformation 'matrix' RECORD size: TIndex; matrix: ARRAY[TIndex,TIndex] OF single //azx DOUBLE END; Trotation = (rotateClockwise, rotateCounterClockwise); // Normally the TVector TYPE is used to define 2D/3D homogenous // cartesian coordinates for graphics, i.e., (x,y,1) for 2D and // (x,y,z,1) for 3D. // // Cartesian coordinates can be converted to spherical (r, theta, phi), // or cylindrical coordinates (r,theta, z). Spherical or cylindrical // coordinates can be converted back to cartesian coordinates. TVector = RECORD size: TIndex; CASE INTEGER OF 0: (vector: ARRAY[TIndex] OF single); 1: (x: single; y: single; z: single; // contains 'h' for 2D cartesian vector h: single) END; TIntVector = RECORD size: TIndex; CASE INTEGER OF 0: (vector: ARRAY[TIndex] OF integer); 1: (x: integer; y: integer; z: integer; // contains 'h' for 2D cartesian vector h: integer) END; // Vector Operations // FUNCTION Vector2D (CONST xValue, yValue: DOUBLE): TVector; FUNCTION Vector3D (CONST xValue, yValue, zValue: DOUBLE): TVector; (* FUNCTION AddVectors (CONST u,v: TVector): TVector; // FUNCTION Transform (CONST u: TVector; CONST a: TMatrix): TVector; FUNCTION DotProduct (CONST u,v: TVector): DOUBLE; FUNCTION CrossProduct(CONST u,v: TVector): TVector; *) // Basic Matrix Operations FUNCTION Matrix2D (CONST m11,m12,m13, // 2D "graphics" matrix m21,m22,m23, m31,m32,m33: DOUBLE): TMatrix; FUNCTION Matrix3D (CONST m11,m12,m13,m14, // 3D "graphics" matrix m21,m22,m23,m24, m31,m32,m33,m34, m41,m42,m43,m44: DOUBLE): TMatrix; FUNCTION MultiplyMatrices (CONST a,b: TMatrix): TMatrix; FUNCTION InvertMatrix3D (CONST Input:TMatrix): TMatrix; FUNCTION InvertMatrix (CONST a,b: TMatrix; VAR determinant: DOUBLE): TMatrix; // Transformation Matrices FUNCTION RotateMatrix (CONST dimension: TDimension; CONST xyz : TAxis; CONST angle : DOUBLE; CONST rotation : Trotation): TMatrix; // FUNCTION ScaleMatrix (CONST s: TVector): TMatrix; // FUNCTION TranslateMatrix (CONST t: TVector): TMatrix; FUNCTION ViewTransformMatrix (CONST coordinate: TCoordinate; CONST azimuth {or x}, elevation {or y}, distance {or z}: DOUBLE; CONST ScreenX, ScreenY, ScreenDistance: DOUBLE): TMatrix; // conversions // FUNCTION FromCartesian (CONST ToCoordinate: TCoordinate; CONST u: TVector): TVector; // FUNCTION ToCartesian (CONST FromCoordinate: TCoordinate; CONST u: TVector): TVector; //FUNCTION ToDegrees(CONST angle {radians}: DOUBLE): DOUBLE {degrees}; FUNCTION ToRadians(CONST angle {degrees}: DOUBLE): DOUBLE {radians}; // miscellaneous FUNCTION Defuzz(CONST x: DOUBLE): DOUBLE; { FUNCTION GetFuzz: DOUBLE; PROCEDURE SetFuzz(CONST x: DOUBLE); } IMPLEMENTATION VAR fuzz : DOUBLE; // ************************* Vector Operations ************************* // This procedure defines two-dimensional homogeneous coordinates (x,y,1) // as a single 'vector' data element 'u'. The 'size' of a two-dimensional // homogenous vector is 3. // This procedure defines three-dimensional homogeneous coordinates // (x,y,z,1) as a single 'vector' data element 'u'. The 'size' of a // three-dimensional homogenous vector is 4. FUNCTION Vector3D (CONST xValue, yValue, zValue: DOUBLE): TVector; BEGIN WITH RESULT DO BEGIN x := xValue; y := yValue; z := zValue; h := 1.0; // homogeneous coordinate size := size3D END END {Vector3D}; // AddVectors adds two vectors defined with homogeneous coordinates. FUNCTION AddVectors (CONST u,v: TVector): TVector; VAR i: TIndex; BEGIN IF (u.size IN [size2D..size3D]) AND (v.size IN [size2D..size3D]) AND (u.size = v.size) THEN BEGIN RESULT.size := u.size; FOR i := 1 TO u.size-1 DO {2D + 2D = 2D or 3D + 3D = 3D} BEGIN RESULT.vector[i] := u.vector[i] + v.vector[i] END; RESULT.vector[u.size] := 1.0 {homogeneous coordinate} END ELSE raise EVectorError.Create('Vector Addition Mismatch') END {AddVectors}; // *********************** Basic Matrix Operations ********************** FUNCTION Matrix2D (CONST m11,m12,m13, m21,m22,m23, m31,m32,m33: DOUBLE): TMatrix; BEGIN WITH RESULT DO BEGIN matrix[1,1] := m11; matrix[1,2] := m12; matrix[1,3] := m13; matrix[2,1] := m21; matrix[2,2] := m22; matrix[2,3] := m23; matrix[3,1] := m31; matrix[3,2] := m32; matrix[3,3] := m33; size := size2D END END {Matrix2D}; FUNCTION Matrix3D (CONST m11,m12,m13,m14, m21,m22,m23,m24, m31,m32,m33,m34, m41,m42,m43,m44: DOUBLE): TMatrix; BEGIN WITH RESULT DO BEGIN matrix[1,1] := m11; matrix[1,2] := m12; matrix[1,3] := m13; matrix[1,4] := m14; matrix[2,1] := m21; matrix[2,2] := m22; matrix[2,3] := m23; matrix[2,4] := m24; matrix[3,1] := m31; matrix[3,2] := m32; matrix[3,3] := m33; matrix[3,4] := m34; matrix[4,1] := m41; matrix[4,2] := m42; matrix[4,3] := m43; matrix[4,4] := m44; size := size3D END END {Matrix3D}; // Compound geometric transformation matrices can be formed by multiplying // simple transformation matrices. This procedure only multiplies together // matrices for two- or three-dimensional transformations, i.e., 3x3 or 4x4 // matrices. The multiplier and multiplicand must be of the same dimension. FUNCTION MultiplyMatrices (CONST a,b: TMatrix): TMatrix; VAR i,j,k: TIndex; temp : DOUBLE; BEGIN RESULT.size := a.size; IF a.size = b.size THEN FOR i := 1 TO a.size DO BEGIN FOR j := 1 TO a.size DO BEGIN temp := 0.0; FOR k := 1 TO a.size DO BEGIN temp := temp + a.matrix[i,k]*b.matrix[k,j]; END; RESULT.matrix[i,j] := Defuzz(temp) END END ELSE Showmessage('shit'+inttostr(a.size)+'x'+inttostr(b.size)); //ELSE EMatrixError.Create('MultiplyMatrices error') END {MultiplyMatrices}; PROCEDURE lubksb(a: {glnpbynp}TMatrix; n: integer; indx: TIntVector; VAR b: TVector); VAR j,ip,ii,i: integer; sum: double; BEGIN ii := 0; FOR i := 1 TO n DO BEGIN ip := indx.vector[i]; sum := b.vector[ip]; b.vector[ip] := b.vector[i]; IF (ii <> 0) THEN BEGIN FOR j := ii TO i-1 DO BEGIN sum := sum-a.matrix[i,j]*b.vector[j] END END ELSE IF (sum <> 0.0) THEN BEGIN ii := i END; b.vector[i] := sum END; FOR i := n DOWNTO 1 DO BEGIN sum := b.vector[i]; IF (i < n) THEN BEGIN FOR j := i+1 TO n DO BEGIN sum := sum-a.matrix[i,j]*b.vector[j] END END; b.vector[i] := sum/a.matrix[i,i] END end; PROCEDURE ludcmp(VAR a: TMatrix; n: integer; VAR indx: TIntVector; VAR d: double); CONST tiny=1.0e-20; VAR k,j,imax,i: integer; sum,dum,big: real; vv: TVector; BEGIN d := 1.0; FOR i := 1 TO n DO BEGIN big := 0.0; FOR j := 1 TO n DO IF (abs(a.matrix[i,j]) > big) THEN big := abs(a.matrix[i,j]); IF (big = 0.0) THEN BEGIN writeln('pause in LUDCMP - singular matrix'); readln END; vv.vector[i] := 1.0/big END; FOR j := 1 TO n DO BEGIN FOR i := 1 TO j-1 DO BEGIN sum := a.matrix[i,j]; FOR k := 1 TO i-1 DO BEGIN sum := sum-a.matrix[i,k]*a.matrix[k,j] END; a.matrix[i,j] := sum END; big := 0.0; FOR i := j TO n DO BEGIN sum := a.matrix[i,j]; FOR k := 1 TO j-1 DO BEGIN sum := sum-a.matrix[i,k]*a.matrix[k,j] END; a.matrix[i,j] := sum; dum := vv.vector[i]*abs(sum); IF (dum > big) THEN BEGIN big := dum; imax := i END END; IF (j <> imax) THEN BEGIN FOR k := 1 TO n DO BEGIN dum := a.matrix[imax,k]; a.matrix[imax,k] := a.matrix[j,k]; a.matrix[j,k] := dum END; d := -d; vv.vector[imax] := vv.vector[j] END; indx.vector[j] := imax; IF (a.matrix[j,j] = 0.0) THEN a.matrix[j,j] := tiny; IF (j <> n) THEN BEGIN dum := 1.0/a.matrix[j,j]; FOR i := j+1 TO n DO BEGIN a.matrix[i,j] := a.matrix[i,j]*dum END END END; END; FUNCTION InvertMatrix3D (CONST Input:TMatrix): TMatrix; var n,i,j: integer; d: double; indx: tIntVector; col: tvector; a,y: TMatrix; begin a:= Input; n := 3; ludcmp(a,n,indx,d); for j := 1 to n do begin for i := 1 to n do col.vector[i] := 0; col.vector[j] := 1.0; lubksb(a,n,indx,col); for i := 1 to n do y.matrix[i,j] := col.vector[i]; end; result := y; end; // This procedure inverts a general transformation matrix. The user need // not form an inverse geometric transformation by keeping a product of // the inverses of simple geometric transformations: translations, rotations // and scaling. A determinant of zero indicates no inverse is possible for // a singular matrix. FUNCTION InvertMatrix (CONST a,b: TMatrix; VAR determinant: DOUBLE): TMatrix; VAR c : TMatrix; i,i_pivot: TIndex; i_flag : ARRAY[TIndex] OF BOOLEAN; j,j_pivot: TIndex; j_flag : ARRAY[TIndex] OF BOOLEAN; modulus : DOUBLE; n : TIndex; pivot : DOUBLE; pivot_col: ARRAY[TIndex] OF TIndex; pivot_row: ARRAY[TIndex] OF TIndex; temporary: DOUBLE; BEGIN c := a; // The matrix inversion algorithm used here WITH c DO // is similar to the "maximum pivot strategy" BEGIN // described in "Applied Numerical Methods" FOR i := 1 TO size DO // by Carnahan, Luther and Wilkes, BEGIN // pp. 282-284. i_flag[i] := TRUE; j_flag[i] := TRUE END; modulus := 1.0; i_pivot := 1; // avoid initialization warning j_pivot := 1; // avoid initialization warning FOR n := 1 TO size DO BEGIN pivot := 0.0; IF ABS(modulus) > 0.0 THEN BEGIN FOR i := 1 TO size DO IF i_flag[i] THEN FOR j := 1 TO size DO IF j_flag[j] THEN IF ABS(matrix[i,j]) > ABS(pivot) THEN BEGIN pivot := matrix[i,j]; // largest value on which to pivot i_pivot := i; // indices of pivot element j_pivot := j END; IF Defuzz(pivot) = 0 // If pivot is too small, consider THEN modulus := 0 // the matrix to be singular ELSE BEGIN pivot_row[n] := i_pivot; pivot_col[n] := j_pivot; i_flag[i_pivot] := FALSE; j_flag[j_pivot] := FALSE; FOR i := 1 TO size DO IF i <> i_pivot THEN FOR j := 1 TO size DO // pivot column unchanged for elements IF j <> j_pivot // not in pivot row or column ... THEN matrix[i,j] := (matrix[i,j]*matrix[i_pivot,j_pivot] - matrix[i_pivot,j]*matrix[i,j_pivot]) / modulus; // 2x2 minor / modulus FOR j := 1 TO size DO IF j <> j_pivot // change signs of elements in pivot row THEN matrix[i_pivot,j] := -matrix[i_pivot,j]; temporary := modulus; // exchange pivot element and modulus modulus := matrix[i_pivot,j_pivot]; matrix[i_pivot,j_pivot] := temporary END END END {FOR n} END {WITH}; determinant := Defuzz(modulus); IF determinant <> 0 THEN BEGIN RESULT.size := c.size; // The matrix inverse must be unscrambled FOR i := 1 TO c.size DO // if pivoting was not along main diagonal. FOR j := 1 TO c.size DO RESULT.matrix[pivot_row[i],pivot_col[j]] := Defuzz(c.matrix[i,j]/determinant) END ELSE EMatrixError.Create('InvertMatrix error') END {InvertMatrix}; // *********************** Transformation Matrices ******************** // This procedure defines a matrix for a two- or three-dimensional rotation. // To avoid possible confusion in the sense of the rotation, 'rotateClockwise' // or 'roCounterlcockwise' must always be specified along with the axis // of rotation. Two-dimensional rotations are assumed to be about the z-axis // in the x-y plane. // // A rotation about an arbitrary axis can be performed with the following // steps: // (1) Translate the object into a new coordinate system where (x,y,z) // maps into the origin (0,0,0). // (2) Perform appropriate rotations about the x and y axes of the // coordinate system so that the unit vector (a,b,c) is mapped into // the unit vector along the z axis. // (3) Perform the desired rotation about the z-axis of the new // coordinate system. // (4) Apply the inverse of step (2). // (5) Apply the inverse of step (1). FUNCTION RotateMatrix (CONST dimension: TDimension; CONST xyz : TAxis; CONST angle : DOUBLE; CONST rotation : Trotation): TMatrix; VAR cosx : DOUBLE; sinx : DOUBLE; TempAngle: DOUBLE; BEGIN TempAngle := angle; // Use TempAngle since "angle" is CONST parameter IF rotation = rotateCounterClockwise THEN TempAngle := -TempAngle; cosx := Defuzz( COS(TempAngle) ); sinx := Defuzz( SIN(TempAngle) ); CASE dimension OF dimen2D: CASE xyz OF axisX,axisY: EMatrixError.Create('Invalid 2D rotation matrix. Specify axisZ'); axisZ: RESULT := Matrix2D ( cosx, -sinx, 0, sinx, cosx, 0, 0, 0, 1) END; dimen3D: CASE xyz OF axisX: RESULT := Matrix3D ( 1, 0, 0, 0, 0, cosx, -sinx, 0, 0, sinx, cosx, 0, 0, 0, 0, 1); axisY: RESULT := Matrix3D ( cosx, 0, sinx, 0, 0, 1, 0, 0, -sinx, 0, cosx, 0, 0, 0, 0, 1); axisZ: RESULT := Matrix3D ( cosx, -sinx, 0, 0, sinx, cosx, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); END END END {RotateMatrix}; // 'ScaleMatrix' accepts a 'vector' containing the scaling factors for // each of the dimensions and creates a scaling matrix. The size // of the vector dictates the size of the resulting matrix. FUNCTION ScaleMatrix (CONST s: TVector): TMatrix; BEGIN CASE s.size OF size2D: RESULT := Matrix2D (s.x, 0, 0, 0, s.y, 0, 0, 0, 1); size3D: RESULT := Matrix3D (s.x, 0, 0, 0, 0, s.y, 0, 0, 0, 0, s.z, 0, 0, 0, 0, 1) END END {ScaleMatrix}; // 'TranslateMatrix' defines a translation transformation matrix. The // components of the vector 't' determine the translation components. // (Note: 'Translate' here is from kinematics in physics.) FUNCTION TranslateMatrix (CONST t: TVector): TMatrix; BEGIN CASE t.size OF size2D: RESULT := Matrix2D ( 1, 0, 0, 0, 1, 0, t.x, t.y, 1); size3D: RESULT := Matrix3D ( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, t.x, t.y, t.z, 1) END END {TranslateMatrix}; // 'ViewTransformMatrix' creates a transformation matrix for changing // from world coordinates to eye coordinates. The location of the 'eye' // from the 'object' is given in spherical (azimuth,elevation,distance) // coordinates or Cartesian (x,y,z) coordinates. The size of the screen // is 'ScreenX' units horizontally and 'ScreenY' units vertically. The // eye is 'ScreenDistance' units from the viewing screen. A large ratio // 'ScreenDistance/ScreenX (or ScreenY)' specifies a narrow aperature // -- a telephoto view. Conversely, a small ratio specifies a large // aperature -- a wide-angle view. This view transform matrix is very // useful as the default three-dimensional transformation matrix. Once // set, all points are automatically transformed. FUNCTION ViewTransformMatrix (CONST coordinate: TCoordinate; CONST azimuth {or x}, elevation {or y}, distance {or z}: DOUBLE; CONST ScreenX, ScreenY, ScreenDistance: DOUBLE): TMatrix; CONST HalfPI = PI / 2.0; VAR a : TMatrix; b : TMatrix; cosm : DOUBLE; // COS(-angle) hypotenuse: DOUBLE; sinm : DOUBLE; // SIN(-angle) temporary : DOUBLE; u : TVector; x : DOUBLE ABSOLUTE azimuth; // x and azimuth are synonyms y : DOUBLE ABSOLUTE elevation; // synonyms z : DOUBLE ABSOLUTE distance; // synonyms BEGIN CASE coordinate OF coordCartesian: u := Vector3D (-x, -y, -z); coordSpherical: BEGIN temporary := -distance * COS(elevation); u := Vector3D (temporary * COS(azimuth - HalfPI), temporary * SIN(azimuth - HalfPI), -distance * SIN(elevation)); END END; a := TranslateMatrix(u); // translate origin to 'eye' b := RotateMatrix (dimen3D, axisX, HalfPI, rotateClockwise); a := MultiplyMatrices(a,b); CASE coordinate OF coordCartesian: BEGIN temporary := SQR(x) + SQR(y); hypotenuse := SQRT(temporary); if hypotenuse <> 0 then begin cosm := -y/hypotenuse; sinm := x/hypotenuse; end else begin cosm := 1;//abba sinm := 0; end; b := Matrix3D ( cosm, 0, sinm, 0, 0, 1, 0, 0, -sinm, 0, cosm, 0, 0, 0, 0, 1); a := MultiplyMatrices (a,b); cosm := hypotenuse; hypotenuse := SQRT(temporary + SQR(z)); cosm := cosm/hypotenuse; sinm := -z/hypotenuse; b := Matrix3D ( 1, 0, 0, 0, 0, cosm, -sinm, 0, 0, sinm, cosm, 0, 0, 0, 0, 1) END; coordSpherical: BEGIN b := RotateMatrix (dimen3D,axisY,-azimuth,rotateCounterClockwise); a := MultiplyMatrices(a,b); b := RotateMatrix (dimen3D,axisX,elevation,rotateCounterClockwise); END END {CASE}; a := MultiplyMatrices (a,b); u := Vector3D (ScreenDistance/(0.5*ScreenX), ScreenDistance/(0.5*ScreenY),-1.0); b := ScaleMatrix (u); // reverse sense of z-axis; screen transformation RESULT := MultiplyMatrices (a,b); END {ViewTransformMatrix}; // *************************** Conversions ************************** // This function converts the vector parameter from Cartesian // coordinates to the specified type of coordinates. FUNCTION FromCartesian (CONST ToCoordinate: TCoordinate; CONST u: TVector): TVector; VAR phi : DOUBLE; r : DOUBLE; temp : DOUBLE; theta: DOUBLE; BEGIN IF ToCoordinate = coordCartesian THEN RESULT := u ELSE BEGIN RESULT.size := u.size; IF (u.size = size3D) AND (ToCoordinate = coordSpherical) THEN BEGIN // spherical 3D temp := SQR(u.x)+SQR(u.y); // (x,y,z) -> (r,theta,phi) r := SQRT(temp+SQR(u.z)); IF Defuzz(u.x) = 0.0 THEN theta := PI/4 ELSE theta := ARCTAN(u.y/u.x); IF Defuzz(u.z) = 0.0 THEN phi := PI/4 ELSE phi := ARCTAN(SQRT(temp)/u.z); RESULT.x := r; RESULT.y := theta; RESULT.z := phi END ELSE BEGIN // cylindrical 2D/3D or spherical 2D // (x,y) -> (r,theta) or (x,y,z) -> (r,theta,z) r := SQRT( SQR(u.x) + SQR(u.y) ); IF Defuzz(u.x) = 0.0 THEN theta := PI/4 ELSE theta := ARCTAN(u.y/u.x); RESULT.x := r; RESULT.y := theta END END END {FromCartesian}; // This function converts the vector parameter from specified coordinates // into Cartesian coordinates. FUNCTION ToCartesian (CONST FromCoordinate: TCoordinate; CONST u: TVector): TVector; VAR phi : DOUBLE; r : DOUBLE; sinphi: DOUBLE; theta : DOUBLE; BEGIN RESULT := u; IF FromCoordinate = coordCartesian THEN RESULT := u ELSE BEGIN RESULT.size := u.size; IF (u.size = size3D) AND (FromCoordinate = coordSpherical) THEN BEGIN // spherical 3D r := u.x; // (r,theta,phi) -> (x,y,z) theta := u.y; phi := u.z; sinphi := SIN(phi); RESULT.x := r * COS(theta) * sinphi; RESULT.y := r * SIN(theta) * sinphi; RESULT.z := r * COS(phi) END ELSE BEGIN // cylindrical 2D/3D or spherical 2D r := u.x; // (r,theta) -> (x,y) or (r,theta,z) -> (x,y,z) theta := u.y; RESULT.x := r * COS(theta); RESULT.y := r * SIN(theta) END END END {ToCartesian}; // Convert angle in degrees to radians. FUNCTION ToRadians (CONST angle: DOUBLE): DOUBLE; BEGIN RESULT := PI/180.0 * angle END; {ToRadians} // *************************** Miscellaneous ************************** // 'Defuzz' is used for comparisons and to avoid propagation of 'fuzzy', // nearly-zero values. DOUBLE calculations often result in 'fuzzy' values. // The term 'fuzz' was adapted from the APL language. FUNCTION Defuzz(CONST x: DOUBLE): DOUBLE; BEGIN IF ABS(x) < fuzz THEN RESULT := 0.0 ELSE RESULT := x END {Defuzz}; INITIALIZATION fuzz := 1.0E-6; END. {GraphicsMath UNIT} �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/Matrices.pas���������������������������������������������0000755�0001750�0001750�00000162023�11326443506�020356� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit MATRICES.PAS * * Version 2.0 * * (c) J. Debord, May 2001 * ********************************************************************** This unit implements dynamic allocation of vectors and matrices in Pascal, together with various matrix operations. Dynamic allocation is allowed by declaring arrays as pointers. There are 8 types available : PVector, PMatrix for floating point arrays PIntVector, PIntMatrix for integer arrays PBoolVector, PBoolMatrix for boolean arrays PStrVector, PStrMatrix for string arrays (255 char.) To use these arrays in your programs, you must : (1) Declare variables of the appropriate type, e.g. var V : PVector; A : PMatrix; (2) Allocate each array BEFORE using it : DimVector(V, N); creates vector V[0..N] DimMatrix(A, N, M); creates matrix A[0..N, 0..M] where N, M are two integer variables If the allocation succeeds, all array elements are initialized to zero (for numeric arrays), False (for boolean arrays), or the null string (for string arrays). Otherwise, the pointer is initialized to NIL. (3) Use arrays as in standard Turbo Pascal, with the following exceptions : (a) You must use the indirection operator (^) to reference any array element, i.e. write V^[I] and A^[I]^[J] instead of V[I] and A[I,J]. (b) You cannot use the assignment operator (:=) to copy the contents of an array into another array. Writing B := A simply makes B point to the same memory block than A. You must use one of the provided Copy... procedures (see their documentation in the interface part of the unit). In addition, note that : (a) All arrays begin at index 0, so that the 0-indexed element is always present, even if you don't use it. (b) A matrix is declared as an array of vectors, so that A^[I] denotes the I-th vector of matrix A and may be used as any vector. (4) Deallocate arrays when you no longer need them. This will free the corresponding memory : DelVector(V, N); DelMatrix(A, N, M); For more information, read the comments of each routine in the interface part of the unit, and check the demo programs. ********************************************************************** References : 1) 'Basic Programs for Scientists and Engineers' by A.R. Miller : GaussJordan, InvMat 2) Borland's Numerical Methods Toolbox : Det 3) 'Numerical Recipes' by Press et al. : Cholesky, LU, SVD 4) 'Matrix Computations' by Golub & Van Loan : QR_Decomp & QR_Solve (Pascal implementation contributed by Mark Vaughan) ********************************************************************** } unit Matrices; interface uses FMath,dialogs,sysutils; { ********************************************************************** This section defines some error codes. ********************************************************************** } const MAT_OK = 0; { No error } MAT_SINGUL = - 1; { Singular matrix } MAT_NON_CONV = - 2; { Non convergence of iterative procedure } MAT_NOT_PD = - 3; { Matrix not positive definite } { ********************************************************************** This section defines the vector and matrix types. Maximal sizes are given for a 16-bit compiler (TP / BP / Delphi 1). Higher values may be used with the 32-bit compilers (Delphi 2-4, FPK, GPC). ********************************************************************** } const {$IFDEF EXTENDEDREAL} MAX_FLT = 6552; { Max size of real vector } {$ELSE} {$IFDEF SINGLEREAL} MAX_FLT = 16382; {$ELSE} {$IFDEF PASCALREAL} MAX_FLT = 10921; {$ELSE} {$DEFINE DOUBLEREAL} MAX_FLT = 8190; {$ENDIF} {$ENDIF} {$ENDIF} MAX_INT = 16382; { Max size of integer vector } MAX_BOOL = 32766; { Max size of boolean vector } MAX_STR = 254; { Max size of string vector } MAX_VEC = 16382; { Max number of vectors in a matrix } type Str255= string[255]; TVector = array[0..MAX_FLT] of Float; TIntVector = array[0..MAX_INT] of Integer; TBoolVector = array[0..MAX_BOOL] of Boolean; TStrVector = array[0..MAX_STR] of Str255; PVector = ^TVector; PIntVector = ^TIntVector; PBoolVector = ^TBoolVector; PStrVector = ^TStrVector; TMatrix = array[0..MAX_VEC] of PVector; TIntMatrix = array[0..MAX_VEC] of PIntVector; TBoolMatrix = array[0..MAX_VEC] of PBoolVector; TStrMatrix = array[0..MAX_VEC] of PStrVector; PMatrix = ^TMatrix; PIntMatrix = ^TIntMatrix; PBoolMatrix = ^TBoolMatrix; PStrMatrix = ^TStrMatrix; { ********************************************************************** Memory allocation routines ********************************************************************** } procedure DimVector(var V : PVector; Ubound : Integer); { ---------------------------------------------------------------------- Creates floating point vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DimIntVector(var V : PIntVector; Ubound : Integer); { ---------------------------------------------------------------------- Creates integer vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DimBoolVector(var V : PBoolVector; Ubound : Integer); { ---------------------------------------------------------------------- Creates boolean vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DimStrVector(var V : PStrVector; Ubound : Integer); { ---------------------------------------------------------------------- Creates string vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DimMatrix(var A : PMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Creates floating point matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } procedure DimIntMatrix(var A : PIntMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Creates integer matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } procedure DimBoolMatrix(var A : PBoolMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Creates boolean matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } procedure DimStrMatrix(var A : PStrMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Creates string matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } { ********************************************************************** Memory deallocation routines ********************************************************************** } procedure DelVector(var V : PVector; Ubound : Integer); { ---------------------------------------------------------------------- Deletes floating point vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DelIntVector(var V : PIntVector; Ubound : Integer); { ---------------------------------------------------------------------- Deletes integer vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DelBoolVector(var V : PBoolVector; Ubound : Integer); { ---------------------------------------------------------------------- Deletes boolean vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DelStrVector(var V : PStrVector; Ubound : Integer); { ---------------------------------------------------------------------- Deletes string vector V[0..Ubound] ---------------------------------------------------------------------- } procedure DelMatrix(var A : PMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Deletes floating point matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } procedure DelIntMatrix(var A : PIntMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Deletes integer matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } procedure DelBoolMatrix(var A : PBoolMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Deletes boolean matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } procedure DelStrMatrix(var A : PStrMatrix; Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Deletes string matrix A[0..Ubound1, 0..Ubound2] ---------------------------------------------------------------------- } { ********************************************************************** Routines for copying vectors and matrices ---------------------------------------------------------------------- Lbound, Ubound : indices of first and last vector elements Lbound1, Lbound2 : indices of first matrix element in each dimension Ubound1, Ubound2 : indices of last matrix element in each dimension ********************************************************************** } procedure SwapRows(I, K : Integer; A : PMatrix; Lbound, Ubound : Integer); { ---------------------------------------------------------------------- Exchanges rows I and K of matrix A ---------------------------------------------------------------------- } procedure SwapCols(J, K : Integer; A : PMatrix; Lbound, Ubound : Integer); { ---------------------------------------------------------------------- Exchanges columns J and K of matrix A ---------------------------------------------------------------------- } procedure CopyVector(Dest, Source : PVector; Lbound, Ubound : Integer); { ---------------------------------------------------------------------- Copies vector Source into vector Dest ---------------------------------------------------------------------- } procedure CopyMatrix(Dest, Source : PMatrix; Lbound1, Lbound2, Ubound1, Ubound2 : Integer); { ---------------------------------------------------------------------- Copies matrix Source into matrix Dest ---------------------------------------------------------------------- } procedure CopyRowFromVector(Dest : PMatrix; Source : PVector; Lbound, Ubound, Row : Integer); { ---------------------------------------------------------------------- Copies vector Source into line Row of matrix Dest ---------------------------------------------------------------------- } procedure CopyColFromVector(Dest : PMatrix; Source : PVector; Lbound, Ubound, Col : Integer); { ---------------------------------------------------------------------- Copies vector Source into column Col of matrix Dest ---------------------------------------------------------------------- } procedure CopyVectorFromRow(Dest : PVector; Source : PMatrix; Lbound, Ubound, Row : Integer); { ---------------------------------------------------------------------- Copies line Row of matrix Source into vector Dest ---------------------------------------------------------------------- } procedure CopyVectorFromCol(Dest : PVector; Source : PMatrix; Lbound, Ubound, Col : Integer); { ---------------------------------------------------------------------- Copies column Col of matrix Source into vector Dest ---------------------------------------------------------------------- } { ********************************************************************** Vector and matrix functions ********************************************************************** } function Min(X : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the lowest value of vector X ---------------------------------------------------------------------- } function Max(X : PVector; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Returns the highest value of vector X ---------------------------------------------------------------------- } function IntMin(X : PIntVector; Lbound, Ubound : Integer) : Integer; { ---------------------------------------------------------------------- Returns the lowest value of integer vector X ---------------------------------------------------------------------- } function IntMax(X : PIntVector; Lbound, Ubound : Integer) : Integer; { ---------------------------------------------------------------------- Returns the highest value of integer vector X ---------------------------------------------------------------------- } procedure Transpose(A : PMatrix; Lbound1, Lbound2, Ubound1, Ubound2 : Integer; A_t : PMatrix); { ---------------------------------------------------------------------- Transposes a matrix ---------------------------------------------------------------------- Input parameters : A = original matrix Lbound1, Lbound2 = indices of 1st matrix elem. in each dim. Ubound1, Ubound2 = indices of last matrix elem. in each dim. ---------------------------------------------------------------------- Output parameter : A_t = transposed matrix ---------------------------------------------------------------------- } function GaussJordan(A : PMatrix; B : PVector; Lbound, Ubound : Integer; A_inv : PMatrix; X : PVector) : Integer; { ---------------------------------------------------------------------- Solves a system of linear equations by the Gauss-Jordan method ---------------------------------------------------------------------- Input parameters : A = system matrix B = constant vector Lbound = index of first matrix element Ubound = index of last matrix element ---------------------------------------------------------------------- Output parameters : A_inv = inverse matrix X = solution vector ---------------------------------------------------------------------- Possible results : MAT_OK MAT_SINGUL ---------------------------------------------------------------------- } function InvMat(A : PMatrix; Lbound, Ubound : Integer; A_inv : PMatrix) : Integer; { ---------------------------------------------------------------------- Computes the inverse of a square matrix by the Gauss-Jordan method ---------------------------------------------------------------------- Parameters : as in Gauss-Jordan ---------------------------------------------------------------------- Possible results : MAT_OK MAT_SINGUL ---------------------------------------------------------------------- } function Det(A : PMatrix; Lbound, Ubound : Integer) : Float; { ---------------------------------------------------------------------- Computes the determinant of a square matrix ---------------------------------------------------------------------- Parameters : as in Gauss-Jordan ---------------------------------------------------------------------- NB : This procedure destroys the original matrix A ---------------------------------------------------------------------- } function Cholesky(A : PMatrix; Lbound, Ubound : Integer; L : PMatrix) : Integer; { ---------------------------------------------------------------------- Cholesky decomposition. Factors the symmetric positive definite matrix A as a product L * L', where L is a lower triangular matrix. This procedure may be used as a test of positive definiteness. ---------------------------------------------------------------------- Input parameters : A = matrix Lbound = index of first matrix element Ubound = index of last matrix element ---------------------------------------------------------------------- Output parameter : L = Cholesky factor of matrix A ---------------------------------------------------------------------- Possible results : MAT_OK MAT_NOT_PD ---------------------------------------------------------------------- } function LU_Decomp(A : PMatrix; Lbound, Ubound : Integer) : Integer; { ---------------------------------------------------------------------- LU decomposition. Factors the square matrix A as a product L * U, where L is a lower triangular matrix (with unit diagonal terms) and U is an upper triangular matrix. This routine is used in conjunction with LU_Solve to solve a system of equations. ---------------------------------------------------------------------- Input parameters : A = matrix Lbound = index of first matrix element Ubound = index of last matrix element ---------------------------------------------------------------------- Output parameter : A = contains the elements of L and U ---------------------------------------------------------------------- Possible results : MAT_OK MAT_SINGUL ---------------------------------------------------------------------- NB : This procedure destroys the original matrix A ---------------------------------------------------------------------- } procedure LU_Solve(A : PMatrix; B : PVector; Lbound, Ubound : Integer; X : PVector); { ---------------------------------------------------------------------- Solves a system of equations whose matrix has been transformed by LU_Decomp ---------------------------------------------------------------------- Input parameters : A = result from LU_Decomp B = constant vector Lbound, Ubound = as in LU_Decomp ---------------------------------------------------------------------- Output parameter : X = solution vector ---------------------------------------------------------------------- } function SV_Decomp(A : PMatrix; Lbound, Ubound1, Ubound2 : Integer; S : PVector; V : PMatrix) : Integer; { ---------------------------------------------------------------------- Singular value decomposition. Factors the matrix A (n x m, with n >= m) as a product U * S * V' where U is a (n x m) column-orthogonal matrix, S a (m x m) diagonal matrix with elements >= 0 (the singular values) and V a (m x m) orthogonal matrix. This routine is used in conjunction with SV_Solve to solve a system of equations. ---------------------------------------------------------------------- Input parameters : A = matrix Lbound = index of first matrix element Ubound1 = index of last matrix element in 1st dim. Ubound2 = index of last matrix element in 2nd dim. ---------------------------------------------------------------------- Output parameter : A = contains the elements of U S = vector of singular values V = orthogonal matrix ---------------------------------------------------------------------- Possible results : MAT_OK MAT_NON_CONV ---------------------------------------------------------------------- NB : This procedure destroys the original matrix A ---------------------------------------------------------------------- } procedure SV_SetZero(S : PVector; Lbound, Ubound : Integer; Tol : Float); { ---------------------------------------------------------------------- Sets the singular values to zero if they are lower than a specified threshold. ---------------------------------------------------------------------- Input parameters : S = vector of singular values Tol = relative tolerance Threshold value will be Tol * Max(S) Lbound = index of first vector element Ubound = index of last vector element ---------------------------------------------------------------------- Output parameter : S = modified singular values ---------------------------------------------------------------------- } procedure SV_Solve(U : PMatrix; S : PVector; V : PMatrix; B : PVector; Lbound, Ubound1, Ubound2 : Integer; X : PVector); { ---------------------------------------------------------------------- Solves a system of equations by singular value decomposition, after the matrix has been transformed by SV_Decomp, and the lowest singular values have been set to zero by SV_SetZero. ---------------------------------------------------------------------- Input parameters : U, S, V = vector and matrices from SV_Decomp B = constant vector Lbound, Ubound1, Ubound2 = as in SV_Decomp ---------------------------------------------------------------------- Output parameter : X = solution vector = V * Diag(1/s(i)) * U' * B, for s(i) <> 0 ---------------------------------------------------------------------- } procedure SV_Approx(U : PMatrix; S : PVector; V : PMatrix; Lbound, Ubound1, Ubound2 : Integer; A : PMatrix); { ---------------------------------------------------------------------- Approximates a matrix A by the product USV', after the lowest singular values have been set to zero by SV_SetZero. ---------------------------------------------------------------------- Input parameters : U, S, V = vector and matrices from SV_Decomp Lbound, Ubound1, Ubound2 = as in SV_Decomp ---------------------------------------------------------------------- Output parameter : A = approximated matrix ---------------------------------------------------------------------- } function QR_Decomp(A : PMatrix; Lbound, Ubound1, Ubound2 : Integer; R : PMatrix) : Integer; { ---------------------------------------------------------------------- QR decomposition. Factors the matrix A (n x m, with n >= m) as a product Q * R where Q is a (n x m) column-orthogonal matrix, and R a (m x m) upper triangular matrix. This routine is used in conjunction with QR_Solve to solve a system of equations. ---------------------------------------------------------------------- Input parameters : A = matrix Lbound = index of first matrix element Ubound1 = index of last matrix element in 1st dim. Ubound2 = index of last matrix element in 2nd dim. ---------------------------------------------------------------------- Output parameter : A = contains the elements of Q R = upper triangular matrix ---------------------------------------------------------------------- Possible results : MAT_OK MAT_SING ---------------------------------------------------------------------- NB : This procedure destroys the original matrix A ---------------------------------------------------------------------- } procedure QR_Solve(Q, R : PMatrix; B : PVector; Lbound, Ubound1, Ubound2 : Integer; X : PVector); { ---------------------------------------------------------------------- Solves a system of equations by the QR decomposition, after the matrix has been transformed by QR_Decomp. ---------------------------------------------------------------------- Input parameters : Q, R = matrices from QR_Decomp B = constant vector Lbound, Ubound1, Ubound2 = as in QR_Decomp ---------------------------------------------------------------------- Output parameter : X = solution vector ---------------------------------------------------------------------- } implementation const { Used by LU procedures } LastDim : Integer = 1; { Dimension of the last system solved } Index : PIntVector = nil; { Records the row permutations } procedure DimVector(var V : PVector; Ubound : Integer); var I : Integer; begin { Check bounds } if (Ubound < 0) or (Ubound > MAX_FLT) then begin V := nil; Exit; end; { Allocate vector } GetMem(V, Succ(Ubound) * SizeOf(Float)); if V = nil then Exit; { Initialize vector } for I := 0 to Ubound do V^[I] := 0.0; end; procedure DimIntVector(var V : PIntVector; Ubound : Integer); var I : Integer; begin { Check bounds } if (Ubound < 0) or (Ubound > MAX_INT) then begin V := nil; Exit; end; { Allocate vector } GetMem(V, Succ(Ubound) * SizeOf(Integer)); if V = nil then Exit; { Initialize vector } for I := 0 to Ubound do V^[I] := 0; end; procedure DimBoolVector(var V : PBoolVector; Ubound : Integer); var I : Integer; begin { Check bounds } if (Ubound < 0) or (Ubound > MAX_BOOL) then begin V := nil; Exit; end; { Allocate vector } GetMem(V, Succ(Ubound) * SizeOf(Boolean)); if V = nil then Exit; { Initialize vector } for I := 0 to Ubound do V^[I] := False; end; procedure DimStrVector(var V : PStrVector; Ubound : Integer); var I : Integer; begin { Check bounds } if (Ubound < 0) or (Ubound > MAX_STR) then begin showmessage('DIMstr error'); V := nil; Exit; end; { Allocate vector } GetMem(V, Succ(Ubound) * sizeof(TStrVector) {256}); if V = nil then Exit; { Initialize vector } for I := 0 to Ubound do V^[I] := ''; //showmessage(inttostr(Ubound)+'b'+inttostr(MAX_STR)); end; procedure DimMatrix(var A : PMatrix; Ubound1, Ubound2 : Integer); var I, J : Integer; RowSize : Word; begin if (Ubound1 < 0) or (Ubound1 > MAX_VEC) or (Ubound2 < 0) or (Ubound2 > MAX_FLT) then begin A := nil; Exit; end; { Allocate matrix } GetMem(A, Succ(Ubound1) * SizeOf(PVector)); if A = nil then Exit; { Size of a row } RowSize := Succ(Ubound2) * SizeOf(Float); { Allocate each row } for I := 0 to Ubound1 do begin GetMem(A^[I], RowSize); if A^[I] = nil then begin A := nil; Exit; end; end; { Initialize matrix } for I := 0 to Ubound1 do for J := 0 to Ubound2 do A^[I]^[J] := 0.0; end; procedure DimIntMatrix(var A : PIntMatrix; Ubound1, Ubound2 : Integer); var I, J : Integer; RowSize : Word; begin { Check bounds } if (Ubound1 < 0) or (Ubound1 > MAX_VEC) or (Ubound2 < 0) or (Ubound2 > MAX_INT) then begin A := nil; Exit; end; { Allocate matrix } GetMem(A, Succ(Ubound1) * SizeOf(PIntVector)); if A = nil then Exit; { Size of a row } RowSize := Succ(Ubound2) * SizeOf(Integer); { Allocate each row } for I := 0 to Ubound1 do begin GetMem(A^[I], RowSize); if A^[I] = nil then begin A := nil; Exit; end; end; { Initialize matrix } for I := 0 to Ubound1 do for J := 0 to Ubound2 do A^[I]^[J] := 0; end; procedure DimBoolMatrix(var A : PBoolMatrix; Ubound1, Ubound2 : Integer); var I, J : Integer; RowSize : Word; begin { Check bounds } if (Ubound1 < 0) or (Ubound1 > MAX_VEC) or (Ubound2 < 0) or (Ubound2 > MAX_BOOL) then begin A := nil; Exit; end; { Allocate matrix } GetMem(A, Succ(Ubound1) * SizeOf(PBoolVector)); if A = nil then Exit; { Size of a row } RowSize := Succ(Ubound2) * SizeOf(Boolean); { Allocate each row } for I := 0 to Ubound1 do begin GetMem(A^[I], RowSize); if A^[I] = nil then begin A := nil; Exit; end; end; { Initialize matrix } for I := 0 to Ubound1 do for J := 0 to Ubound2 do A^[I]^[J] := False; end; procedure DimStrMatrix(var A : PStrMatrix; Ubound1, Ubound2 : Integer); var I, J : Integer; RowSize : Word; begin { Check bounds } if (Ubound1 < 0) or (Ubound1 > MAX_VEC) or (Ubound2 < 0) or (Ubound2 > MAX_STR) then begin A := nil; Exit; end; { Allocate matrix } GetMem(A, Succ(Ubound1) * SizeOf(PStrVector)); if A = nil then Exit; { Size of a row } RowSize := Succ(Ubound2) * 256; { Allocate each row } for I := 0 to Ubound1 do begin GetMem(A^[I], RowSize); if A^[I] = nil then begin A := nil; Exit; end; end; { Initialize matrix } for I := 0 to Ubound1 do for J := 0 to Ubound2 do A^[I]^[J] := ''; end; procedure DelVector(var V : PVector; Ubound : Integer); begin if V <> nil then begin FreeMem(V, Succ(Ubound) * SizeOf(Float)); V := nil; end; end; procedure DelIntVector(var V : PIntVector; Ubound : Integer); begin if V <> nil then begin FreeMem(V, Succ(Ubound) * SizeOf(Integer)); V := nil; end; end; procedure DelBoolVector(var V : PBoolVector; Ubound : Integer); begin if V <> nil then begin FreeMem(V, Succ(Ubound) * SizeOf(Boolean)); V := nil; end; end; procedure DelStrVector(var V : PStrVector; Ubound : Integer); begin if V <> nil then begin FreeMem(V{, Succ(Ubound) * 256}); V := nil; end; end; procedure DelMatrix(var A : PMatrix; Ubound1, Ubound2 : Integer); var I : Integer; RowSize : Word; begin if A <> nil then begin RowSize := Succ(Ubound2) * SizeOf(Float); for I := Ubound1 downto 0 do FreeMem(A^[I], RowSize); FreeMem(A, Succ(Ubound1) * SizeOf(PVector)); A := nil; end; end; procedure DelIntMatrix(var A : PIntMatrix; Ubound1, Ubound2 : Integer); var I : Integer; RowSize : Word; begin if A <> nil then begin RowSize := Succ(Ubound2) * SizeOf(Integer); for I := Ubound1 downto 0 do FreeMem(A^[I], RowSize); FreeMem(A, Succ(Ubound1) * SizeOf(PIntVector)); A := nil; end; end; procedure DelBoolMatrix(var A : PBoolMatrix; Ubound1, Ubound2 : Integer); var I : Integer; RowSize : Word; begin if A <> nil then begin RowSize := Succ(Ubound2) * SizeOf(Boolean); for I := Ubound1 downto 0 do FreeMem(A^[I], RowSize); FreeMem(A, Succ(Ubound1) * SizeOf(PBoolVector)); A := nil; end; end; procedure DelStrMatrix(var A : PStrMatrix; Ubound1, Ubound2 : Integer); var I : Integer; RowSize : Word; begin if A <> nil then begin RowSize := Succ(Ubound2) * 256; for I := Ubound1 downto 0 do FreeMem(A^[I], RowSize); FreeMem(A, Succ(Ubound1) * SizeOf(PStrVector)); A := nil; end; end; procedure SwapRows(I, K : Integer; A : PMatrix; Lbound, Ubound : Integer); var J : Integer; begin for J := Lbound to Ubound do FSwap(A^[I]^[J], A^[K]^[J]); end; procedure SwapCols(J, K : Integer; A : PMatrix; Lbound, Ubound : Integer); var I : Integer; begin for I := Lbound to Ubound do FSwap(A^[I]^[J], A^[I]^[K]); end; procedure CopyVector(Dest, Source : PVector; Lbound, Ubound : Integer); var I : Integer; begin for I := Lbound to Ubound do Dest^[I] := Source^[I]; end; procedure CopyMatrix(Dest, Source : PMatrix; Lbound1, Lbound2, Ubound1, Ubound2 : Integer); var I, J : Integer; begin for I := Lbound1 to Ubound1 do for J := Lbound2 to Ubound2 do Dest^[I]^[J] := Source^[I]^[J]; end; procedure CopyRowFromVector(Dest : PMatrix; Source : PVector; Lbound, Ubound, Row : Integer); var J : Integer; begin for J := Lbound to Ubound do Dest^[Row]^[J] := Source^[J]; end; procedure CopyColFromVector(Dest : PMatrix; Source : PVector; Lbound, Ubound, Col : Integer); var I : Integer; begin for I := Lbound to Ubound do Dest^[I]^[Col] := Source^[I]; end; procedure CopyVectorFromRow(Dest : PVector; Source : PMatrix; Lbound, Ubound, Row : Integer); var J : Integer; begin for J := Lbound to Ubound do Dest^[J] := Source^[Row]^[J]; end; procedure CopyVectorFromCol(Dest : PVector; Source : PMatrix; Lbound, Ubound, Col : Integer); var I : Integer; begin for I := Lbound to Ubound do Dest^[I] := Source^[I]^[Col]; end; function Min(X : PVector; Lbound, Ubound : Integer) : Float; var Xmin : Float; I : Integer; begin Xmin := X^[Lbound]; for I := Succ(Lbound) to Ubound do if X^[I] < Xmin then Xmin := X^[I]; Min := Xmin; end; function Max(X : PVector; Lbound, Ubound : Integer) : Float; var Xmax : Float; I : Integer; begin Xmax := X^[Lbound]; for I := Succ(Lbound) to Ubound do if X^[I] > Xmax then Xmax := X^[I]; Max := Xmax; end; function IntMin(X : PIntVector; Lbound, Ubound : Integer) : Integer; var I, Xmin : Integer; begin Xmin := X^[Lbound]; for I := Succ(Lbound) to Ubound do if X^[I] < Xmin then Xmin := X^[I]; IntMin := Xmin; end; function IntMax(X : PIntVector; Lbound, Ubound : Integer) : Integer; var I, Xmax : Integer; begin Xmax := X^[Lbound]; for I := Succ(Lbound) to Ubound do if X^[I] > Xmax then Xmax := X^[I]; IntMax := Xmax; end; procedure Transpose(A : PMatrix; Lbound1, Lbound2, Ubound1, Ubound2 : Integer; A_t : PMatrix); var I, J : Integer; begin for I := Lbound1 to Ubound1 do for J := Lbound2 to Ubound2 do A_t^[J]^[I] := A^[I]^[J]; end; function GaussJordan(A : PMatrix; B : PVector; Lbound, Ubound : Integer; A_inv : PMatrix; X : PVector) : Integer; var I, J, K : Integer; Pvt, T : Float; PRow, PCol : PIntVector; { Store line and column of pivot } begin DimIntVector(PRow, Ubound); DimIntVector(PCol, Ubound); { Copy A into A_inv and B into X } CopyMatrix(A_inv, A, Lbound, Lbound, Ubound, Ubound); CopyVector(X, B, Lbound, Ubound); K := Lbound; while K <= Ubound do begin { Search for largest pivot in submatrix A_inv[K..Ubound, K..Ubound] } Pvt := A_inv^[K]^[K]; PRow^[K] := K; PCol^[K] := K; for I := K to Ubound do for J := K to Ubound do if Abs(A_inv^[I]^[J]) > Abs(Pvt) then begin Pvt := A_inv^[I]^[J]; PRow^[K] := I; PCol^[K] := J; end; { Pivot too weak ==> quasi-singular matrix } if Abs(Pvt) < MACHEP then begin DelIntVector(PRow, Ubound); DelIntVector(PCol, Ubound); GaussJordan := MAT_SINGUL; Exit; end; { Exchange current row (K) with pivot row } if PRow^[K] <> K then begin SwapRows(PRow^[K], K, A_inv, Lbound, Ubound); FSwap(X^[PRow^[K]], X^[K]); end; { Exchange current column (K) with pivot column } if PCol^[K] <> K then SwapCols(PCol^[K], K, A_inv, Lbound, Ubound); { Transform pivot row } A_inv^[K]^[K] := 1.0; for J := Lbound to Ubound do A_inv^[K]^[J] := A_inv^[K]^[J] / Pvt; X^[K] := X^[K] / Pvt; { Transform other rows } for I := Lbound to Ubound do if I <> K then begin T := A_inv^[I]^[K]; A_inv^[I]^[K] := 0.0; for J := Lbound to Ubound do A_inv^[I]^[J] := A_inv^[I]^[J] - T * A_inv^[K]^[J]; X^[I] := X^[I] - T * X^[K]; end; Inc(K); end; { Rearrange inverse matrix } for I := Ubound downto Lbound do if PCol^[I] <> I then begin SwapRows(PCol^[I], I, A_inv, Lbound, Ubound); FSwap(X^[PCol^[I]], X^[I]); end; for J := Ubound downto Lbound do if PRow^[J] <> J then SwapCols(PRow^[J], J, A_inv, Lbound, Ubound); DelIntVector(PRow, Ubound); DelIntVector(PCol, Ubound); GaussJordan := MAT_OK; end; function InvMat(A : PMatrix; Lbound, Ubound : Integer; A_inv : PMatrix) : Integer; var I, J, K : Integer; Pvt, T : Float; PRow, PCol : PIntVector; { Store line and column of pivot } begin DimIntVector(PRow, Ubound); DimIntVector(PCol, Ubound); { Copy A into A_inv } CopyMatrix(A_inv, A, Lbound, Lbound, Ubound, Ubound); K := Lbound; while K <= Ubound do begin { Search for largest pivot in submatrix A_inv[K..Ubound, K..Ubound] } Pvt := A_inv^[K]^[K]; PRow^[K] := K; PCol^[K] := K; for I := K to Ubound do for J := K to Ubound do if Abs(A_inv^[I]^[J]) > Abs(Pvt) then begin Pvt := A_inv^[I]^[J]; PRow^[K] := I; PCol^[K] := J; end; { Pivot too weak ==> quasi-singular matrix } if Abs(Pvt) < MACHEP then begin DelIntVector(PRow, Ubound); DelIntVector(PCol, Ubound); InvMat := MAT_SINGUL; Exit; end; { Exchange current row (K) with pivot row } if PRow^[K] <> K then SwapRows(PRow^[K], K, A_inv, Lbound, Ubound); { Exchange current column (K) with pivot column } if PCol^[K] <> K then SwapCols(PCol^[K], K, A_inv, Lbound, Ubound); { Transform pivot row } A_inv^[K]^[K] := 1.0; for J := Lbound to Ubound do A_inv^[K]^[J] := A_inv^[K]^[J] / Pvt; { Transform other rows } for I := Lbound to Ubound do if I <> K then begin T := A_inv^[I]^[K]; A_inv^[I]^[K] := 0.0; for J := Lbound to Ubound do A_inv^[I]^[J] := A_inv^[I]^[J] - T * A_inv^[K]^[J]; end; Inc(K); end; { Rearrange inverse matrix } for I := Ubound downto Lbound do if PCol^[I] <> I then SwapRows(PCol^[I], I, A_inv, Lbound, Ubound); for J := Ubound downto Lbound do if PRow^[J] <> J then SwapCols(PRow^[J], J, A_inv, Lbound, Ubound); DelIntVector(PRow, Ubound); DelIntVector(PCol, Ubound); InvMat := MAT_OK; end; function Det(A : PMatrix; Lbound, Ubound : Integer) : Float; var D, T : Float; { Partial determinant & multiplier } I, J, K : Integer; { Loop variables } ZeroDet : Boolean; { Flags a null determinant } begin ZeroDet := False; D := 1.0; K := Lbound; { Make the matrix upper triangular } while not(ZeroDet) and (K < Ubound) do begin { If diagonal element is zero then switch rows } if Abs(A^[K]^[K]) < MACHEP then begin ZeroDet := True; I := K; { Try to find a row with a non-zero element in this column } while ZeroDet and (I < Ubound) do begin I := Succ(I); if Abs(A^[I]^[K]) > MACHEP then begin { Switch these two rows } SwapRows(I, K, A, Lbound, Ubound); ZeroDet := False; { Switching rows changes the sign of the determinant } D := - D; end; end; end; if not(ZeroDet) then for I := Succ(K) to Ubound do if Abs(A^[I]^[K]) > MACHEP then begin { Make the K element of this row zero } T := - A^[I]^[K] / A^[K]^[K]; for J := 1 to Ubound do A^[I]^[J] := A^[I]^[J] + T * A^[K]^[J]; end; D := D * A^[K]^[K]; { Multiply the diagonal term into D } Inc(K); end; if ZeroDet then Det := 0.0 else Det := D * A^[Ubound]^[Ubound]; end; function Cholesky(A : PMatrix; Lbound, Ubound : Integer; L : PMatrix) : Integer; var I, J, K : Integer; Sum : Float; begin for K := Lbound to Ubound do begin Sum := A^[K]^[K]; for J := Lbound to K - 1 do Sum := Sum - Sqr(L^[K]^[J]); if Sum <= 0.0 then begin Cholesky := MAT_NOT_PD; Exit; end; L^[K]^[K] := Sqrt(Sum); for I := K + 1 to Ubound do begin Sum := A^[I]^[K]; for J := Lbound to K - 1 do Sum := Sum - L^[I]^[J] * L^[K]^[J]; L^[I]^[K] := Sum / L^[K]^[K]; end; end; Cholesky := MAT_OK; end; function LU_Decomp(A : PMatrix; Lbound, Ubound : Integer) : Integer; const TINY = 1.0E-20; var I, Imax, J, K : Integer; Pvt, T, Sum : Float; V : PVector; begin DimVector(V, Ubound); { Reallocate Index } if Index <> nil then DelIntVector(Index, LastDim); DimIntVector(Index, Ubound); LastDim := Ubound; for I := Lbound to Ubound do begin Pvt := 0.0; for J := Lbound to Ubound do if Abs(A^[I]^[J]) > Pvt then Pvt := Abs(A^[I]^[J]); if Pvt < MACHEP then begin DelVector(V, Ubound); LU_Decomp := MAT_SINGUL; Exit; end; V^[I] := 1.0 / Pvt; end; for J := Lbound to Ubound do begin for I := Lbound to Pred(J) do begin Sum := A^[I]^[J]; for K := Lbound to Pred(I) do Sum := Sum - A^[I]^[K] * A^[K]^[J]; A^[I]^[J] := Sum; end; Pvt := 0.0; for I := J to Ubound do begin Sum := A^[I]^[J]; for K := Lbound to Pred(J) do Sum := Sum - A^[I]^[K] * A^[K]^[J]; A^[I]^[J] := Sum; T := V^[I] * Abs(Sum); if T > Pvt then begin Pvt := T; Imax := I; end; end; if J <> Imax then begin SwapRows(Imax, J, A, Lbound, Ubound); V^[Imax] := V^[J]; end; Index^[J] := Imax; if A^[J]^[J] = 0.0 then A^[J]^[J] := TINY; if J <> Ubound then begin T := 1.0 / A^[J]^[J]; for I := Succ(J) to Ubound do A^[I]^[J] := A^[I]^[J] * T; end; end; DelVector(V, Ubound); LU_Decomp := MAT_OK; end; procedure LU_Solve(A : PMatrix; B : PVector; Lbound, Ubound : Integer; X : PVector); var I, Ip, J, K : Integer; Sum : Float; begin K := Pred(Lbound); CopyVector(X, B, Lbound, Ubound); for I := Lbound to Ubound do begin Ip := Index^[I]; Sum := X^[Ip]; X^[Ip] := X^[I]; if K >= Lbound then for J := K to Pred(I) do Sum := Sum - A^[I]^[J] * X^[J] else if Sum <> 0.0 then K := I; X^[I] := Sum; end; for I := Ubound downto Lbound do begin Sum := X^[I]; if I < Ubound then for J := Succ(I) to Ubound do Sum := Sum - A^[I]^[J] * X^[J]; X^[I] := Sum / A^[I]^[I]; end; end; function SV_Decomp(A : PMatrix; Lbound, Ubound1, Ubound2 : Integer; S : PVector; V : PMatrix) : Integer; label 1, 2, 3; var I, Its, J, JJ, K, L, N : Integer; Anorm, C, F, G, H, Sum, Scale, T, X, Y, Z : Float; R : PVector; begin G := 0.0; Scale := 0.0; Anorm := 0.0; DimVector(R, Ubound2); for I := Lbound to Ubound2 do begin L := I + 1; R^[I] := Scale * G; G := 0.0; Sum := 0.0; Scale := 0.0; if I <= Ubound1 then begin for K := I to Ubound1 do Scale := Scale + Abs(A^[K]^[I]); if Scale <> 0.0 then begin for K := I to Ubound1 do begin A^[K]^[I] := A^[K]^[I] / Scale; Sum := Sum + A^[K]^[I] * A^[K]^[I]; end; F := A^[I]^[I]; G := - Sgn(F) * Sqrt(Sum); H := F * G - Sum; A^[I]^[I] := F - G; if I <> Ubound2 then begin for J := L to Ubound2 do begin Sum := 0.0; for K := I to Ubound1 do Sum := Sum + A^[K]^[I] * A^[K]^[J]; F := Sum / H; for K := I to Ubound1 do A^[K]^[J] := A^[K]^[J] + F * A^[K]^[I]; end; end; for K := I to Ubound1 do A^[K]^[I] := Scale * A^[K]^[I]; end; end; S^[I] := Scale * G; G := 0.0; Sum := 0.0; Scale := 0.0; if (I <= Ubound1) and (I <> Ubound2) then begin for K := L to Ubound2 do Scale := Scale + Abs(A^[I]^[K]); if Scale <> 0.0 then begin for K := L to Ubound2 do begin A^[I]^[K] := A^[I]^[K] / Scale; Sum := Sum + A^[I]^[K] * A^[I]^[K]; end; F := A^[I]^[L]; G := - Sgn(F) * Sqrt(Sum); H := F * G - Sum; A^[I]^[L] := F - G; for K := L to Ubound2 do R^[K] := A^[I]^[K] / H; if I <> Ubound1 then for J := L to Ubound1 do begin Sum := 0.0; for K := L to Ubound2 do Sum := Sum + A^[J]^[K] * A^[I]^[K]; for K := L to Ubound2 do A^[J]^[K] := A^[J]^[K] + Sum * R^[K]; end; for K := L to Ubound2 do A^[I]^[K] := Scale * A^[I]^[K]; end; end; Anorm := FMax(Anorm, Abs(S^[I]) + Abs(R^[I])); end; for I := Ubound2 downto Lbound do begin if I < Ubound2 then begin if G <> 0.0 then begin for J := L to Ubound2 do V^[J]^[I] := (A^[I]^[J] / A^[I]^[L]) / G; for J := L to Ubound2 do begin Sum := 0.0; for K := L to Ubound2 do Sum := Sum + A^[I]^[K] * V^[K]^[J]; for K := L to Ubound2 do V^[K]^[J] := V^[K]^[J] + Sum * V^[K]^[I]; end; end; for J := L to Ubound2 do begin V^[I]^[J] := 0.0; V^[J]^[I] := 0.0; end; end; V^[I]^[I] := 1.0; G := R^[I]; L := I; end; for I := Ubound2 downto Lbound do begin L := I + 1; G := S^[I]; if I < Ubound2 then for J := L to Ubound2 do A^[I]^[J] := 0.0; if G <> 0.0 then begin G := 1.0 / G; if I <> Ubound2 then for J := L to Ubound2 do begin Sum := 0.0; for K := L to Ubound1 do Sum := Sum + A^[K]^[I] * A^[K]^[J]; F := (Sum / A^[I]^[I]) * G; for K := I to Ubound1 do A^[K]^[J] := A^[K]^[J] + F * A^[K]^[I]; end; for J := I to Ubound1 do A^[J]^[I] := A^[J]^[I] * G; end else for J := I to Ubound1 do A^[J]^[I] := 0.0; A^[I]^[I] := A^[I]^[I] + 1.0; end; for K := Ubound2 downto Lbound do begin for Its := 1 to 30 do begin for L := K downto Lbound do begin N := L - 1; if (Abs(R^[L]) + Anorm) = Anorm then goto 2; if (Abs(S^[N]) + Anorm) = Anorm then goto 1; end; 1: T := 1.0; for I := L to K do begin F := T * R^[I]; if (Abs(F) + Anorm) <> Anorm then begin G := S^[I]; H := Pythag(F, G); S^[I] := H; H := 1.0 / H; C := G * H; T := - (F * H); for J := Lbound to Ubound1 do begin Y := A^[J]^[N]; Z := A^[J]^[I]; A^[J]^[N] := (Y * C) + (Z * T); A^[J]^[I] := - (Y * T) + (Z * C); end; end; end; 2: Z := S^[K]; if L = K then begin if Z < 0.0 then begin S^[K] := - Z; for J := Lbound to Ubound2 do V^[J]^[K] := - V^[J]^[K]; end; goto 3 end; if Its = 30 then begin DelVector(R, Ubound2); SV_Decomp := MAT_NON_CONV; Exit; end; X := S^[L]; N := K - 1; Y := S^[N]; G := R^[N]; H := R^[K]; F := ((Y - Z) * (Y + Z) + (G - H) * (G + H)) / (2.0 * H * Y); G := Pythag(F, 1.0); F := ((X - Z) * (X + Z) + H * ((Y / (F + Sgn(F) * Abs(G))) - H)) / X; C := 1.0; T := 1.0; for J := L to N do begin I := J + 1; G := R^[I]; Y := S^[I]; H := T * G; G := C * G; Z := Pythag(F, H); R^[J] := Z; C := F / Z; T := H / Z; F := (X * C) + (G * T); G := - (X * T) + (G * C); H := Y * T; Y := Y * C; for JJ := Lbound to Ubound2 do begin X := V^[JJ]^[J]; Z := V^[JJ]^[I]; V^[JJ]^[J] := (X * C) + (Z * T); V^[JJ]^[I] := - (X * T) + (Z * C); end; Z := Pythag(F, H); S^[J] := Z; if Z <> 0.0 then begin Z := 1.0 / Z; C := F * Z; T := H * Z; end; F := (C * G) + (T * Y); X := - (T * G) + (C * Y); for JJ := Lbound to Ubound1 do begin Y := A^[JJ]^[J]; Z := A^[JJ]^[I]; A^[JJ]^[J] := (Y * C) + (Z * T); A^[JJ]^[I] := - (Y * T) + (Z * C); end end; R^[L] := 0.0; R^[K] := F; S^[K] := X; end; 3: end; DelVector(R, Ubound2); SV_Decomp := MAT_OK; end; procedure SV_SetZero(S : PVector; Lbound, Ubound : Integer; Tol : Float); var Threshold : Float; I : Integer; begin Threshold := Tol * Max(S, Lbound, Ubound); for I := Lbound to Ubound do if S^[I] < Threshold then S^[I] := 0.0; end; procedure SV_Solve(U : PMatrix; S : PVector; V : PMatrix; B : PVector; Lbound, Ubound1, Ubound2 : Integer; X : PVector); var I, J, JJ : Integer; Sum : Float; Tmp : PVector; begin DimVector(Tmp, Ubound2); for J := Lbound to Ubound2 do begin Sum := 0.0; if S^[J] > 0.0 then begin for I := Lbound to Ubound1 do Sum := Sum + U^[I]^[J] * B^[I]; Sum := Sum / S^[J]; end; Tmp^[J] := Sum; end; for J := Lbound to Ubound2 do begin Sum := 0.0; for JJ := Lbound to Ubound2 do Sum := Sum + V^[J]^[JJ] * Tmp^[JJ]; X^[J] := Sum; end; DelVector(Tmp, Ubound2); end; procedure SV_Approx(U : PMatrix; S : PVector; V : PMatrix; Lbound, Ubound1, Ubound2 : Integer; A : PMatrix); var I, J, K : Integer; begin for I := Lbound to Ubound1 do for J := Lbound to Ubound2 do begin A^[I]^[J] := 0.0; for K := Lbound to Ubound2 do if S^[K] > 0.0 then A^[I]^[J] := A^[I]^[J] + U^[I]^[K] * V^[J]^[K]; end; end; function QR_Decomp(A : PMatrix; Lbound, Ubound1, Ubound2 : Integer; R : PMatrix) : Integer; var I, J, K : Integer; Sum : Float; begin for K := Lbound to Ubound2 do begin { Compute the "k"th diagonal entry in R } Sum := 0.0; for I := Lbound to Ubound1 do Sum := Sum + Sqr(A^[I]^[K]); if Sum = 0.0 then begin QR_Decomp := MAT_SINGUL; Exit; end; R^[K]^[K] := Sqrt(Sum); { Divide the entries in the "k"th column of A by the computed "k"th } { diagonal element of R. this begins the process of overwriting A } { with Q . . . } for I := Lbound to Ubound1 do A^[I]^[K] := A^[I]^[K] / R^[K]^[K]; for J := (K + 1) to Ubound2 do begin { Complete the remainder of the row entries in R } Sum := 0.0; for I := Lbound to Ubound1 do Sum := Sum + A^[I]^[K] * A^[I]^[J]; R^[K]^[J] := Sum; { Update the column entries of the Q/A matrix } for I := Lbound to Ubound1 do A^[I]^[J] := A^[I]^[J] - A^[I]^[K] * R^[K]^[J]; end; end; QR_Decomp := MAT_OK; end; procedure QR_Solve(Q, R : PMatrix; B : PVector; Lbound, Ubound1, Ubound2 : Integer; X : PVector); var I, J : Integer; Sum : Float; begin { Form Q'B and store the result in X } for J := Lbound to Ubound2 do begin X^[J] := 0.0; for I := Lbound to Ubound1 do X^[J] := X^[J] + Q^[I]^[J] * B^[I]; end; { Update X with the solution vector } X^[Ubound2] := X^[Ubound2] / R^[Ubound2]^[Ubound2]; for I := (Ubound2 - 1) downto Lbound do begin Sum := 0.0; for J := (I + 1) to Ubound2 do Sum := Sum + R^[I]^[J] * X^[J]; X^[I] := (X^[I] - Sum) / R^[I]^[I]; end; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/fitexlin.pas���������������������������������������������0000755�0001750�0001750�00000010330�11326443506�020422� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITEXLIN.PAS * * Version 1.1 * * (c) J. Debord, August 2000 * ********************************************************************** This unit fits the "exponential + linear" model: y = A.[1 - exp(-k.x)] + B.x ********************************************************************** } unit FitExLin; {$F+} interface uses FMath, Matrices, Stat, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X : Float; B, D : PVector); function FitModel(X, Y : PVector; N : Integer; B : PVector) : Integer; implementation function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function -------------------------------------------------------------------- } begin FuncName := 'y = A[1 - exp(-k.x)] + B.x'; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted -------------------------------------------------------------------- } begin LastParam := 2; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'A'; 1 : ParamName := 'k'; 2 : ParamName := 'B'; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X B is the vector of parameters, such that : B^[0] = A B^[1] = k B^[2] = B -------------------------------------------------------------------- } begin RegFunc := B^[0] * (1.0 - Expo(- B^[1] * X)) + B^[2] * X; end; procedure DerivProc(X : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point X with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter. -------------------------------------------------------------------- } var E : Float; begin E := Expo(- B^[1] * X); { exp(-k.x) } D^[0] := 1.0 - E; { dy/dA = 1 - exp(-k.x) } D^[1] := B^[0] * X * E; { dy/dk = A.x.exp(-k.x) } D^[2] := X; { dy/dB = x } end; function FitModel(X, Y : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Computes initial estimates of the regression parameters -------------------------------------------------------------------- Input : N = number of points X, Y = point coordinates Output : B = estimated regression parameters -------------------------------------------------------------------- } var K : Integer; D : Float; begin { B is the slope of the last (linear) part of the curve } K := Round(0.9 * N); if K = N then K := Pred(N); B^[2] := (Y^[N] - Y^[K]) / (X^[N] - X^[K]); { A is the intercept of the linear part } B^[0] := Y^[N] - B^[2] * X^[N]; { Slope of the tangent at origin = B + k.A } K := Round(0.1 * N); if K = 1 then K := 2; D := (Y^[K] - Y^[1]) / (X^[K] - X^[1]); B^[1] := (D - B^[1]) / B^[0]; FitModel := 0; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dmath/fitpower.pas���������������������������������������������0000755�0001750�0001750�00000011415�11326443506�020444� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ ********************************************************************** * Unit FITPOWER.PAS * * Version 1.1 * * (c) J. Debord, August 2000 * ********************************************************************** This unit fits a power function : y = A.x^n ********************************************************************** } unit FitPower; {$F+} interface uses FMath, Matrices, Stat, Regress; function FuncName : String; function FirstParam : Integer; function LastParam : Integer; function ParamName(I : Integer) : String; function RegFunc(X : Float; B : PVector) : Float; procedure DerivProc(X, Y : Float; B, D : PVector); function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; implementation function FuncName : String; { -------------------------------------------------------------------- Returns the name of the regression function. -------------------------------------------------------------------- } begin FuncName := 'y = A.x^n'; end; function FirstParam : Integer; { -------------------------------------------------------------------- Returns the index of the first parameter to be fitted. -------------------------------------------------------------------- } begin FirstParam := 0; end; function LastParam : Integer; { -------------------------------------------------------------------- Returns the index of the last parameter to be fitted. -------------------------------------------------------------------- } begin LastParam := 1; end; function ParamName(I : Integer) : String; { -------------------------------------------------------------------- Returns the name of the I-th parameter. -------------------------------------------------------------------- } begin case I of 0 : ParamName := 'A'; 1 : ParamName := 'n'; end; end; function RegFunc(X : Float; B : PVector) : Float; { -------------------------------------------------------------------- Computes the regression function at point X. B is the vector of parameters, such that : B^[0] = A B^[1] = n -------------------------------------------------------------------- } begin RegFunc := B^[0] * Power(X, B^[1]); end; procedure DerivProc(X, Y : Float; B, D : PVector); { -------------------------------------------------------------------- Computes the derivatives of the regression function at point (X,Y) with respect to the parameters B. The results are returned in D. D^[I] contains the derivative with respect to the I-th parameter. -------------------------------------------------------------------- } begin D^[0] := Y / B^[0]; { dy/dA = x^n } D^[1] := Y * Log(X); { dy/dk = A.x^n.Ln(x) } end; function FitModel(Method : Integer; X, Y, W : PVector; N : Integer; B : PVector) : Integer; { -------------------------------------------------------------------- Approximate fit of a power function by linear regression: Ln(y) = Ln(A) + n.Ln(x) -------------------------------------------------------------------- Input : Method = 0 for unweighted regression, 1 for weighted X, Y = point coordinates W = weights N = number of points Output : B = estimated regression parameters -------------------------------------------------------------------- } var X1, Y1 : PVector; { Transformed coordinates } W1 : PVector; { Weights } A : PVector; { Linear regression parameters } V : PMatrix; { Variance-covariance matrix } P : Integer; { Number of points for linear regression } K : Integer; { Loop variable } ErrCode : Integer; { Error code } begin DimVector(X1, N); DimVector(Y1, N); DimVector(W1, N); DimVector(A, 1); DimMatrix(V, 1, 1); P := 0; for K := 1 to N do if (X^[K] > 0.0) and (Y^[K] > 0.0) then begin Inc(P); X1^[P] := Log(X^[K]); Y1^[P] := Log(Y^[K]); W1^[P] := Sqr(Y^[K]); if Method = 1 then W1^[P] := W1^[P] * W^[K]; end; ErrCode := WLinFit(X1, Y1, W1, P, A, V); if ErrCode = MAT_OK then begin B^[0] := Expo(A^[0]); B^[1] := A^[1]; end; FitModel := ErrCode; DelVector(X1, N); DelVector(Y1, N); DelVector(W1, N); DelVector(A, 1); DelMatrix(V, 1, 1); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/old/�����������������������������������������������������������0000755�0001750�0001750�00000000000�12360760644�015560� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/old/montecarlo.pas���������������������������������������������0000755�0001750�0001750�00000017307�11326443510�020432� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit montecarlo; interface {$H+} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes; procedure LesionMonteCarlo (lBinomial,lTTest,lBM: boolean); implementation uses npmform,filename,turbolesion; procedure RandomGroup(kSamplesPerTest: integer;lImageNames: TStrings;lSymptomRA: SingleP;var lPartImageNames: TStrings; var lPartSymptomRA: SingleP); var lTotal,lInc,lRand,lSwap: integer; lRanOrder: longintP; begin lPartImageNames.Clear; lTotal := lImageNames.Count; if kSamplesPerTest > lTotal then begin showmessage('Monte carlo error: population must be larger than sample size.'); exit; end; //fx(lTOtal); Getmem(lRanOrder,lTotal*sizeof(longint)); for lInc := 1 to lTotal do lRanOrder^[lInc] := lInc; for lInc := lTotal downto 2 do begin lRand := Random(lInc)+1; lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc]; lRanOrder^[lInc] := lSwap; end; for lInc := 1 to kSamplesPerTest do begin lPartImageNames.Add(lImageNames.Strings[lRanOrder^[lInc]-1]);//indexed from 0 lPartSymptomRA^[lInc] := lSymptomRA^[lRanOrder^[lInc]]; end; Freemem(lRanOrder); end; {$DEFINE notanacom} procedure LesionMonteCarlo (lBinomial,lTTest,lBM: boolean); label 666; const kSimSampleSize = 64; knSim = 5; kCrit = 3; {$IFDEF anacom} knControls = 64; {$ENDIF} var lPrefs: TLDMPrefs ; lSim,lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCrit: integer; lPartImageNames,lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lOutName,lFactname,lOutNameSim: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA,lPartSymptomRA: singleP; {$IFDEF anacom} lnControlObservations: integer; lControlSymptomRA: singleP; {$ENDIF} begin //lBinomial := not odd( (Sender as tMenuItem).tag); lPrefs.NULP := true{gNULP false}; if not lBinomial then begin lPrefs.BMtest := lbm;//BMmenu.checked; lPrefs.Ttest := lttest;//ttestmenu.checked; if (not lPrefs.BMtest) and (not lPrefs.ttest) then lPrefs.ttest := true; lPrefs.Ltest:= false; end else begin lPrefs.BMtest := false; lPrefs.Ttest := false; lPrefs.Ltest:= true; end; lPrefs.nCrit := kCrit; lPrefs.nPermute := MainForm.ReadPermute;; lPrefs.Run := 0;{0 except for montecarlo} if (not lBinomial) and (not lTTest) and (not lBM) then begin Showmessage('Error: you need to compute at least on test [options/test menu]'); exit; end; lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? lPartImageNames := TStringList.Create; getmem(lPartSymptomRA,kSimSampleSize*sizeof(single)); {$IFDEF anacom} lnControlObservations := knControls; getmem(lControlSymptomRA,lnControlObservations*sizeof(single)); for lSim := 1 to lnControlObservations do lControlSymptomRA^[lSim] := 5; {$ENDIF} //next, get 1st group if not MainForm.GetVal(lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCrit{,binom},lPredictorList) then begin showmessage('Error with VAL file'); goto 666; end; lTemp4D := CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) or (lnSubjAll < kSimSampleSize) then begin Showmessage('Not enough subjects ('+inttostr(lnSubjAll)+') [sample size is '+inttostr(kSimSampleSize)+']or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; MainForm.SaveHdrDlg.Filename := loutname; lOutName := lOutName+'.nii.gz'; if not MainForm.SaveHdrName ('Base Statistical Map', lOutName) then goto 666; for lFact := 1 to lnFactors do begin lImageNames.clear; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); lnSubj := lImageNames.Count; if lnSubj > 1 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; //randomization loop.... for lSim := 1 to knSim do begin RandomGroup(kSimSampleSize, lImageNames,lSymptomRA, lPartImageNames, lPartSymptomRA); lOutNameSim := AddIndexToFilename(lOutName,lSim); lnCrit := kCrit; MainForm.NPMMsgClear; //Msg(GetKVers); MainForm.NPMMsg('Threads: '+inttostr(gnCPUThreads)); lFactName := lPredictorList.Strings[lFact-1]; lFactName := LegitFilename(lFactName,lFact); MainForm.NPMMsg('Factor = '+lFactname); For lSubj := 1 to kSimSampleSize do MainForm.NPMMsg (lPartImageNames.Strings[lSubj-1] + ' = '+realtostr(lPartSymptomRA^[lSubj],2) ); MainForm.NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); MainForm.NPMMsg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); MainForm.NPMMsg('Number of Lesion maps = '+inttostr(kSimSampleSize)); if not CheckVoxelsGroup(lPartImageNames,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; lPrefs.Run := lSim; if lBinomial then TurboLDM (lPartImageNames, lMaskHdr, lPrefs, lPartSymptomRA, lFactname,lOutNameSim) else begin MainForm.ReportDescriptives(lPartSymptomRA,lnSubj); //TurboLDM (lPartImageNames, lMaskHdr, lPrefs, lPartSymptomRA, lFactname,lOutNameSim); {$IFDEF anacom} AnacomLesionNPMAnalyze (lPartImageNames, lMaskHdr, lnCrit,lSim,lnControlObservations, lPartSymptomRA,lControlSymptomRA, lFactname,lOutNameSim,lPrefs.Ttest,lPrefs.BMtest {lttest,lBM}); {$ENDIF} end; end; //for each simulation... Freemem(lSymptomRA); end; //lnsubj > 1 end; //for each factor if lnSubjAll > 0 then begin Freemem(lMultiSymptomRA); end; 666: lPartImageNames.free; lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; freemem(lPartSymptomRA); {$IFDEF anacom} freemem(lControlSymptomRA); {$ENDIF} DeleteDecompressed4D(lTemp4D); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/old/anacom.pas�������������������������������������������������0000755�0001750�0001750�00000061664�11326443510�017532� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit anacom; interface {$H+} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr,filename, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes; //procedure DoAnaCOM; function AnacomLesionNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttestIn,lBMIn: boolean): boolean; implementation uses npmform; {$DEFINE NOTmedianfx} function AnacomLesionNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttestIn,lBMIn: boolean): boolean; label 123,667; var lOutNameMod: string; lPlankImg: byteP; lOutImgSum,lOutImgBM,lOutImgT, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM,lCombinedSymptomRA: singleP; lPos,lPlank,lThread,lnControlsPlusPatients: integer; lVolVox,lMinMask,lMaxMask,lTotalMemory,lnPlanks,lVoxPerPlank, lThreadStart,lThreadEnd,lThreadInc,lnLesion,lnPermute, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT,lBMz, lSum,lThresh,lThreshBonf,lThreshPermute,lThreshNULP :double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; lBM,lttest,lLtest: boolean; lnControlNeg: integer; {$IFDEF medianfx} lmedianFX,lmeanFX,lsummean,lsummedian: double; lmediancount: integer; {$ENDIF} begin lnControlNeg := lnControl; //negative for binomial test lttest := lttestin; lbm := lbmin; if (not (lttest)) and (not (lbm)) then begin lLtest := true; lBM := true; lnControlNeg := -lnControl; end; //lttest:= ttestmenu.checked; //lBM := BMmenu.checked; if lnControl < 1 then begin MainForm.NPMmsg('AnaCom aborted - need data from at least 1 control individual'); exit; end; lnPermute := 0;//MainForm.ReadPermute; MainForm.NPMmsg('Permutations = ' +IntToStr(lnPermute)); MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; MainForm.NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); MainForm.NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) //assumes 1bpp else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; {$IFDEF medianfx} lsummean := 0; lsummedian:= 0; lmediancount := 0; {$ENDIF} for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; lnControlsPlusPatients := lImages.Count+lnControl; createArray64(lObsp,lObs,lnControlsPlusPatients); getmem(lOutImgSum,lVolVox* sizeof(single)); getmem(lOutImgBM,lVolVox* sizeof(single)); getmem(lOutImgT,lVolVox* sizeof(single)); MainForm.InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; end; //sumptom array for lesions AND controls for lPos := 1 to lImages.Count do lObs^[lPos-1] := lSymptomRA^[lPos]; for lPos := 1 to lnControl do lObs^[lPos-1+lImages.Count] := lControlSymptomRA^[lPos]; getmem(lCombinedSymptomRA,lnControlsPlusPatients* sizeof(single)); for lPos := 1 to lnControlsPlusPatients do lCombinedSymptomRA^[lPos] := lObs^[lPos-1]; //next create permuted BM bounds if lBM then begin MainForm.NPMmsg('Generating BM permutation thresholds'); MainForm.Refresh; //for lPos := 1 to lImages.Count do // lObs^[lPos-1] := lSymptomRA^[lPos]; genBMsim (lnControlsPlusPatients, lObs); end; ClearThreadData(gnCPUThreads,lnPermute) ; for lPlank := 1 to lnPlanks do begin MainForm.NPMmsg('Computing plank = ' +Inttostr(lPlank)); MainForm.Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TLesionContinuous.Create (MainForm.ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lnControlNeg,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,nil,lCombinedSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; lThreshPermute := 0; lnVoxTested := SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //next report findings if lnVoxTested < 1 then begin MainForm.NPMmsg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lnCrit)+' patients**'); goto 123; end; MainForm.NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); {$IFDEF medianfx} MainForm.NPMmsg('Average MEAN effect size = ' +realtostr((lsummean/lmediancount),3)); MainForm.NPMmsg('Average MEDIAN effect size = ' +realtostr((lsummedian/lmediancount),3)); {$ENDIF} MainForm.NPMmsg('Only tested voxels with more than '+inttostr(lnCrit)+' lesions'); //Next: save results from permutation thresholding.... //Next: save results from permutation thresholding.... lThreshBonf := MainForm.reportBonferroni('Std',lnVoxTested); //Next: NULPS if lRun > 0 then //terrible place to do this - RAM problems, but need value to threshold maps lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap2 (lImages, lnCrit,lnVoxTested,lPlankImg)); //lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap (lImages, lnCrit)); //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); if (lRun < 1) then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //create new header - subsequent images will use Z-scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lRun < 1) and (Sum2PowerCont(lOutImgSum,lVolVox,lImages.Count)) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; //MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if lttest then begin //save Ttest //next: convert t-scores to z scores if lnControl < 1 then for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lnPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; lThresh := MainForm.reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); lThreshPermute := MainForm.reportPermute('attest',lnPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'attest'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('AnaComthreshtt,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgT))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if lBM then begin //save Mann Whitney lThresh := MainForm.reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); lThreshPermute := MainForm.reportPermute('aBM',lnPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'aBM'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('AnaCOMthreshbm,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgBM))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end; //next: free dynamic memory 123: MainForm.FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgT); freemem(lOutImgBM); freemem(lOutImgSum); freemem(lObsp); freemem(lPlankImg); MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); MainForm.MsgSave(lOutNameMod); MainForm.ProgressBar1.Position := 0; exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; //LesionNPMAnalyze (*function readCSV2 (lFilename: string; lCol1,lCol2: integer; var lnObservations : integer; var ldataRA1,ldataRA2: singlep): boolean; const kHdrRow = 0;//1; kHdrCol = 0;//1; var lNumStr: string; F: TextFile; lTempFloat: double; lCh: char; lnFactors,MaxC,R,C:integer; lError: boolean; begin lError := false; result := false; if not fileexists(lFilename) then begin showmessage('Can not find '+lFilename); exit; end; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); if (R <= (kHdrRow+1)) or (MaxC < (kHdrCol+lCol1)) or (MaxC < (kHdrCol+lCol2)) then begin showmessage('problems reading CSV - not enough columns/rows '+inttostr(lCol1)+' '+inttostr(lCol2)); exit; end; lnObservations := R -kHdrRow ; //-1: first row is header.... lnFactors := MaxC-1;// -1: first column is Y values //fx(lnObservations,lnFactors); //exit; getmem(ldataRA1,lnObservations*sizeof(single)); getmem(ldataRA2,lnObservations*sizeof(single)); //second pass Reset(F); C := 1; MaxC := 0; R := 1; lNumStr := ''; lTempfloat := 0; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin if (R > kHdrRow) and (C > kHdrCol) then begin if ((C-kHdrCol) = lCol1) or ((C-kHdrCol) = lCol2) then begin if lNumStr = '-' then begin lTempFloat := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(lNumStr); if (C-kHdrCol) = lCol1 then ldataRA1^[R-kHdrRow] := lTempFloat else if (C-kHdrCol) = lCol2 then ldataRA2^[R-kHdrRow] := lTempFloat; end; //number end; //col1 or col2 end;// else //R > 1 lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 1; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if (lNumStr <> '') and (C = lnFactors) then begin //unterminated string try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except ldataRA2^[R-1] := lTempFloat; end;//unterminated string //read finel item CloseFile(F); FileMode := 2; //Set file access to read/write result := true; end; *) function readTxt (lFilename: string; var lnObservations : integer; var ldataRA1: singlep): boolean; const kHdrRow = 0;//1; kHdrCol = 0;//1; var lCol1: integer; lNumStr: string; F: TextFile; lTempFloat: double; lCh: char; lnFactors,MaxC,R,C:integer; lError: boolean; begin lCol1:= 1; lError := false; result := false; if not fileexists(lFilename) then begin showmessage('Can not find '+lFilename); exit; end; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); if (R <= (kHdrRow+1)) or (MaxC < (kHdrCol+lCol1)) then begin showmessage('problems reading CSV - not enough columns/rows '); exit; end; lnObservations := R -kHdrRow ; //-1: first row is header.... lnFactors := kHdrCol+lCol1;// -1: first column is Y values //fx(lnObservations,lnFactors); //exit; getmem(ldataRA1,lnObservations*sizeof(single)); //second pass Reset(F); C := 1; MaxC := 0; R := 1; lNumStr := ''; lTempfloat := 0; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin if (R > kHdrRow) and (C > kHdrCol) then begin if ((C-kHdrCol) = lCol1) {or ((C-kHdrCol) = lCol2)} then begin if lNumStr = '-' then begin lTempFloat := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(lNumStr); if (C-kHdrCol) = lCol1 then begin //showmessage(lNumStr); ldataRA1^[R-kHdrRow] := lTempFloat; end; {else if (C-kHdrCol) = lCol2 then ldataRA2^[R-kHdrRow] := lTempFloat;} end; //number end; //col1 or col2 end;// else //R > 1 lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 1; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; //showmessage(lNumStr+' '+inttostr(lnFactors)+' '+inttostr(C)); if (lNumStr <> '') and (C = lnFactors) then begin //unterminated string try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(inttostr(R)+' '+floattostr(lTempFLoat)); ldataRA1^[R] := lTempFloat; end;//unterminated string //read finel item CloseFile(F); FileMode := 2; //Set file access to read/write result := true; end; (*procedure DoAnaCOM; label 666; var lControlFilename: string; lI, lnControlObservations : integer; lControldata: singlep; lBinomial: boolean; lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCrit: integer; lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lOutName,lFactname: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA: singleP; begin npmform.MainForm.memo1.lines.clear; npmform.MainForm.memo1.lines.add('AnaCOM analysis requires TXT/CSV format text file.'); npmform.MainForm.memo1.lines.add('One row per control participant.'); npmform.MainForm.memo1.lines.add('First column is performance of that participant.'); npmform.MainForm.memo1.lines.add('Example file:'); //npmform.MainForm.memo1.lines.add('deficit, voxels'); npmform.MainForm.memo1.lines.add('11'); npmform.MainForm.memo1.lines.add('19'); npmform.MainForm.memo1.lines.add('2'); npmform.MainForm.memo1.lines.add('22'); npmform.MainForm.memo1.lines.add('19'); npmform.MainForm.memo1.lines.add('6'); lControlFilename := 'c:\fx.txt'; if (not readTxt (lControlFilename, lnControlObservations,lControldata)) or (lnControlObservations < 1) then begin showmessage('Error reading file '+lControlFilename); exit; end; npmform.MainForm.memo1.lines.add('Control (n='+inttostr(lnControlObservations)+')performance: '); for lI := 1 to lnControlObservations do begin npmform.MainForm.memo1.lines.add(inttostr(lI)+' '+floattostr(lControldata^[lI])); end; //begin - copy lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? //next, get 1st group if not MainForm.GetVal(lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCrit,{,binom}lPredictorList) then begin showmessage('Error with VAL file'); goto 666; end; lTemp4D := CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) then begin Showmessage('Not enough subjects ('+inttostr(lnSubjAll)+') or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; MainForm.SaveHdrDlg.Filename := loutname; lOutName := lOutName+'.nii.gz'; if not MainForm.SaveHdrName ('Base Statistical Map', lOutName) then exit; for lFact := 1 to lnFactors do begin lImageNames.clear; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); lnSubj := lImageNames.Count; if lnSubj > 1 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; MainForm.NPMmsgClear; MainForm.NPMMsg(MainForm.GetKVers); MainForm.NPMMsg('Threads: '+inttostr(gnCPUThreads)); lFactName := lPredictorList.Strings[lFact-1]; lFactName := LegitFilename(lFactName,lFact); MainForm.NPMMsg('Factor = '+lFactname); For lSubj := 1 to lnSubj do MainForm.NPMMsg (lImageNames.Strings[lSubj-1] + ' = '+realtostr(lSymptomRA^[lSubj],2) ); MainForm.NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); MainForm.NPMMsg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); MainForm.NPMMsg('Number of Lesion maps = '+inttostr(lnSubj)); if not CheckVoxelsGroup(lImageNames,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; MainForm.ReportDescriptives(lSymptomRA,lnSubj); AnacomLesionNPMAnalyze(lImageNames,lMaskHdr,lnCrit,-1,lnControlObservations,lSymptomRA,lControldata,lFactName,lOutname,true {ttest},false{BM}); Freemem(lSymptomRA); end; //lnsubj > 1 end; //for each factor if lnSubjAll > 0 then begin Freemem(lMultiSymptomRA); end; 666: lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); ///end //AnacomLesionNPMAnalyze ( lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttest,lBM: boolean): boolean; freemem(lControldata); end;*) end. ����������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/old/lesion.pas�������������������������������������������������0000755�0001750�0001750�00000047300�11326443510�017554� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit lesion; interface {$H+} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes; function LesionNPMAnalyze2 (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnPermute: integer; var lSymptomRA: SingleP;var lFactname,lOutName: string; lttest,lBM: boolean): boolean; function LesionNPMAnalyzeBinomial2 (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lnPermute: integer; var lSymptomRA: SingleP; var lFactname,lOutName: string): boolean; var gNULP,gROI: boolean; implementation uses npmform; {$DEFINE NOTmedianfx} function LesionNPMAnalyze2 (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnPermute: integer; var lSymptomRA: SingleP;var lFactname,lOutName: string; lttest,lBM: boolean): boolean; label 123,667; var lOutNameMod: string; lPlankImg: byteP; lOutImgSum,lOutImgBM,lOutImgT,lOutImgAUC, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP; lPos,lPlank,lThread: integer; lVolVox,lMinMask,lMaxMask,lTotalMemory,lnPlanks,lVoxPerPlank, lThreadStart,lThreadEnd,lThreadInc,lnLesion,//,lnPermute, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT,lBMz, lSum,lThresh,lThreshPermute,lThreshBonf,lThreshNULP :double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; lPlankAllocated: boolean; //lttest,lBM: boolean; {$IFDEF medianfx} lmedianFX,lmeanFX,lsummean,lsummedian: double; lmediancount: integer; {$ENDIF} begin //lttest:= ttestmenu.checked; //lBM := BMmenu.checked; lPlankAllocated := false; //lnPermute := MainForm.ReadPermute; MainForm.NPMmsg('Permutations = ' +IntToStr(lnPermute)); MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; MainForm.NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); MainForm.NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) //assumes 1bpp else getmem(lPlankImg,kPlankSz); lPlankAllocated := true; lStartVox := lMinMask; lEndVox := lMinMask-1; {$IFDEF medianfx} lsummean := 0; lsummedian:= 0; lmediancount := 0; {$ENDIF} for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; createArray64(lObsp,lObs,lImages.Count); getmem(lOutImgSum,lVolVox* sizeof(single)); getmem(lOutImgBM,lVolVox* sizeof(single)); getmem(lOutImgT,lVolVox* sizeof(single)); getmem(lOutImgAUC,lVolVox* sizeof(single)); MainForm.InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; lOutImgAUC^[lPos] := 0; end; //next create permuted BM bounds if lBM then begin MainForm.NPMmsg('Generating BM permutation thresholds'); MainForm.Refresh; for lPos := 1 to lImages.Count do lObs^[lPos-1] := lSymptomRA^[lPos]; genBMsim (lImages.Count, lObs); end; ClearThreadData(gnCPUThreads,lnPermute) ; for lPlank := 1 to lnPlanks do begin MainForm.NPMmsg('Computing plank = ' +Inttostr(lPlank)); MainForm.Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TLesionContinuous.Create (MainForm.ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,0,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA) do //with TLesionContinuous.Create (MainForm.ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,lSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; //freemem(lPlankImg); //lPlankAllocated := false; lThreshPermute := 0; lnVoxTested := SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //next report findings if lnVoxTested < 1 then begin MainForm.NPMmsg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lnCrit)+' patients**'); goto 123; end; MainForm.NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); {$IFDEF medianfx} MainForm.NPMmsg('Average MEAN effect size = ' +realtostr((lsummean/lmediancount),3)); MainForm.NPMmsg('Average MEDIAN effect size = ' +realtostr((lsummedian/lmediancount),3)); {$ENDIF} MainForm.NPMmsg('Only tested voxels with more than '+inttostr(lnCrit)+' lesions'); //Next: save results from permutation thresholding.... lThreshBonf := MainForm.reportBonferroni('Std',lnVoxTested); //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); if lRun < 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //save Area Under Curve lOutNameMod := ChangeFilePostfixExt(lOutName,'rocAUC'+lFactName,'.hdr'); if lRun < 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgAUC,1); //create new header - subsequent images will use Z-scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lRun < 1) and (Sum2PowerCont(lOutImgSum,lVolVox,lImages.Count)) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; if lRun > 0 then //terrible place to do this - RAM problems, but need value to threshold maps lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap2 (lImages, lnCrit,lnVoxTested,lPlankImg)); //MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if lttest then begin //save Ttest //next: convert t-scores to z scores for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lnPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; lThresh := MainForm.reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); lThreshPermute := MainForm.reportPermute('ttest',lnPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'ttest'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('threshtt,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgT))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if lBM then begin //save Brunner Munzel lThresh := MainForm.reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); lThreshPermute := MainForm.reportPermute('BM',lnPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'BM'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('threshbm,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgBM))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end; //next: free dynamic memory 123: MainForm.FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgT); freemem(lOutImgAUC); freemem(lOutImgBM); freemem(lOutImgSum); freemem(lObsp); if lPlankAllocated then freemem(lPlankImg); //Next: NULPS - do this after closing all memory - this is a memory hog if gNULP then lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap (lImages, lnCrit,lnVoxTested)); MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); MainForm.MsgSave(lOutNameMod); MainForm.ProgressBar1.Position := 0; //if lRun > 0 then // AX(freeram,freeram,freeram,freeram,freeram,freeram); exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; //LesionNPMAnalyze function LesionNPMAnalyzeBinomial2 (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lnPermute: integer; var lSymptomRA: SingleP; var lFactname,lOutName: string): boolean; label 123,667; var lVal: single; lOutNameMod: string; lPlankImg: byteP; lOutImgSum,lOutImgL,lOutImgAUC,lDummyImg, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP; lPos,lPlank,lThread,lnDeficit: integer; lTotalMemory,lVolVox,lMinMask,lMaxMask,lnPlanks,lVoxPerPlank, lThreadStart,lThreadInc,lThreadEnd, lnLesion, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT, lSum: double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; begin MainForm.NPMmsg('Permutations = ' +IntToStr(lnPermute)); //lOutName := lMaskHdr.ImgFileName; //if not SaveHdrName ('Statistical Map', lOutName) then exit; MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; MainForm.NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); MainForm.NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) //assumes 1bp else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; createArray64(lObsp,lObs,lImages.Count); getmem(lOutImgSum,lVolVox* sizeof(single)); getmem(lOutImgL,lVolVox* sizeof(single)); getmem(lOutImgAUC,lVolVox* sizeof(single)); MainForm.InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgL^[lPos] := 0; lOutImgAUC^[lPos] := 0; end; ClearThreadDataPvals(gnCPUThreads,lnPermute) ; for lPlank := 1 to lnPlanks do begin MainForm.ProgressBar1.Position := 1; MainForm.NPMmsg('Computing plank = ' +Inttostr(lPlank)); MainForm.Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error //with TLesionBinomial.Create (ProgressBar1,false,true,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,666, lDummyImg,lPlankImg,lOutImgSum,lOutImgL,lDummyImg,lSymptomRA) do with TLesionBinom.Create (MainForm.ProgressBar1,false,true,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,0,lPlankImg,lOutImgSum,lOutImgL,lDummyImg,lOutImgAUC,lSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} inc(gThreadsRunning); MainForm.NPMmsg('Thread ' +Inttostr(gThreadsRunning)+' = '+inttostr(lThreadStart)+'..'+inttostr(lThreadEnd)); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; lnVoxTested := SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); for lPos := 1 to lnPermute do begin if (lPermuteMinT^[lPos] > 1.1) or (lPermuteMinT^[lPos] < -1.1) then lPermuteMinT^[lPos] := 0.5; if (lPermuteMaxT^[lPos] > 1.1) or (lPermuteMaxT^[lPos] < -1.1) then lPermuteMaxT^[lPos] := 0.5; lVal := lPermuteMaxT^[lPos]; lPermuteMaxT^[lPos] := lPermuteMinT^[lPos]; lPermuteMinT^[lPos] := lVal; if lPermuteMaxT^[lPos] < 0 then lPermuteMaxT^[lPos] := -pNormalInv(abs(lPermuteMaxT^[lPos])) else lPermuteMaxT^[lPos] := pNormalInv(lPermuteMaxT^[lPos]); if lPermuteMinT^[lPos] < 0 then lPermuteMinT^[lPos] := -pNormalInv(abs(lPermuteMinT^[lPos])) else lPermuteMinT^[lPos] := pNormalInv(lPermuteMinT^[lPos]); end; if lnVoxTested < 1 then begin MainForm.NPMmsg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lnCrit)+' patients**'); goto 123; end; //next report findings MainForm.NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); MainForm.NPMmsg('Only tested voxels with more than '+inttostr(lnCrit)+' lesions'); //Next: save results from permutation thresholding.... MainForm.reportBonferroni('Std',lnVoxTested); //next: save data //savedata MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //save Area Under Curve lOutNameMod := ChangeFilePostfixExt(lOutName,'rocAUC'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgAUC,1); //future images will store Z-scores... MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); //save power map lnDeficit := 0; for lPos := 1 to lImages.Count do if lSymptomRA^[lPos] = 0 then inc(lnDeficit); if Sum2PowerBinom(lOutImgSum,lVolVox,lImages.Count,lnDeficit) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; //save Liebermeister lOutNameMod := ChangeFilePostfixExt(lOutName,'L'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgL,1); //save end MainForm.reportFDR ('L', lVolVox, lnVoxTested, lOutImgL); MainForm.reportPermute('L',lnPermute,lPermuteMaxT, lPermuteMinT); 123: //next: free dynamic memory MainForm.FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgL); freemem(lOutImgAUC); freemem(lOutImgSum); freemem(lObsp); freemem(lPlankImg); //Next: NULPS - do this at the end, it is a memory hog! if gNULP then MainForm.reportBonferroni('Unique overlap',CountOverlap (lImages, lnCrit,lnVoxTested)); MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); MainForm.MsgSave(lOutNameMod); MainForm.ProgressBar1.Position := 0; exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/npmcl.lpr������������������������������������������������������0000755�0001750�0001750�00000012144�12156654546�016645� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������program npmcl; {$mode objfpc}{$H+} uses {$IFDEF UNIX}{$IFDEF UseCThreads} //cthreads, {$ENDIF}{$ENDIF} cthreads, Classes, SysUtils, CustApp,prefs, unpm, userdir,StatThdsUtil, cpucount, define_types, turbolesion; type TNPMcl = class(TCustomApplication) protected procedure DoRun; override; public constructor Create(TheOwner: TComponent); override; destructor Destroy; override; function GetOptionValueInt(lCmd: string; lDefault: integer): integer; //procedure WriteHelp; virtual; procedure ThreadDone(Sender: TObject); end; var Application: TNPMcl; procedure msg(s: string); begin { add your help code here } writeln(s); end; procedure ShowOptions (lTestInt: integer; lMaskFilename,lOutFilename: string); begin msg(' -c : CPU threads, Default : '+inttostr(gnCPUThreads)); msg(' -m : mask name. Default "' +lMaskFilename+'"'); msg(' -n : neighbors for TFCE, 0 for none. Default ' +inttostr(gNPMprefs.TFCE)); msg(' -o : output name. Default "' +lOutFilename+'"'); msg(' -p : Permutations, 0 for none. Default '+inttostr(gNPMprefs.nPermute)); msg(' -r : RAM for processing (Mb). Default '+inttostr(kPlankMB)); msg(' -t : test (0=continuous,1=binomial,2=regress,3=multiregress). Default '+inttostr(lTestInt)); end; procedure WriteHelp ; begin msg(GetKVers); msg(' usage: '+ExtractFileName(FileNameNoExt(paramstr(0)))+' [options] [-t test] [valfilename]' ); msg('Examples:'); msg(' '+ ExtractFileName(FileNameNoExt(paramstr(0)))+' -t 0 test.val'); msg(' '+ ExtractFileName(FileNameNoExt(paramstr(0)))+' -r 1024 -p 1000 -m mymask.nii -t 0 test.val'); msg('Options:'); msg(' -h : Help displayed'); end; procedure TNPMcl.ThreadDone(Sender: TObject); begin Dec(gThreadsRunning); end; function TNPMcl.GetOptionValueInt(lCmd: string; lDefault: integer): integer; var lResp : string; begin lResp := GetOptionValue(lCmd); if length(lResp) < 1 then result := lDefault; try result := strtoint(lResp); except Writeln('Error '+(lResp)+' is not a valid integer.'); result := lDefault; end; end; procedure doVLSM(lBinomial: boolean; VALFilename, lMaskFilename,lOutFilename: string); var lPrefs: TLDMPrefs ; begin lPrefs.NULP := gNPMPrefs.NULP; if (not lBinomial) then begin //continuous lPrefs.BMtest := true; lPrefs.Ttest := true; lPrefs.Ltest:= false; end else begin //binomial lPrefs.BMtest := false; lPrefs.Ttest := false; lPrefs.Ltest:= true; end; lPrefs.CritPct := -1; lPrefs.nPermute := gNPMprefs.nPermute; lPrefs.Run := 0;{0 except for montecarlo} lPrefs.VALFilename := VALFilename; lPrefs.OutName := lOutFilename; lPrefs.ExplicitMaskName := lMaskFilename; DoLesion (lPrefs); end; procedure TNPMcl.DoRun; label 666; var lTestInt: integer = 0; lMaskFilename : string = ''; lValFilename : string = ''; lOutFilename : string = ''; begin gnCPUThreads := GetLogicalCpuCount; ReadIniFile; // parse parameters if (HasOption('h','help')) or (ParamCount = 0) then begin WriteHelp; ShowOptions(lTestInt, lMaskFilename, lOutFilename); goto 666; end; if (HasOption('c')) then gnCPUThreads := GetOptionValueInt('c', gnCPUThreads); if (HasOption('m')) then begin lMaskFilename := GetOptionValue('m'); if not (not FileExistsEX(lMaskFilename)) then begin writeln('Can not fine masking image '+ lMaskFilename); goto 666; end; end; if (HasOption('n')) then gnCPUThreads := GetOptionValueInt('n', gNPMprefs.TFCE); if (HasOption('o')) then begin lOutFilename := GetOptionValue('o'); end; if (HasOption('p')) then gNPMprefs.nPermute := GetOptionValueInt('p', gNPMprefs.nPermute); if (HasOption('r')) then begin kPlankMB := GetOptionValueInt('r', kPlankMB); ComputePlankSize(kPlankMB); end; if (HasOption('t')) then lTestInt := GetOptionValueInt('t', lTestInt); lValFilename := (paramstr(ParamCount)); if (UpCaseExt(lValFilename) <> '.VAL') or (not FileExistsEX(lValFilename)) then begin Writeln('Error: final option should be an existing file with the .val extension'); goto 666; end; if (lOutFilename = '') then begin lOutFilename := ChangeFileExtX( lValFilename,''); end; //show settings ShowOptions(lTestInt,lMaskFilename,lOutFilename); Writeln('VAL File: '+lValFilename); //run test case lTestInt of 0: doVLSM(false, lVALFilename, lMaskFilename,lOutFilename);//continuous : t-test 1: doVLSM(true, lVALFilename, lMaskFilename,lOutFilename);//binomial: Liebermeister 2: NPMSingleRegress ( lVALFilename, lMaskFilename,lOutFilename); 3: NPMMultipleRegressClick( lVALFilename, lMaskFilename,lOutFilename); end; WriteIniFile; // stop program loop 666: Terminate; end; constructor TNPMcl.Create(TheOwner: TComponent); begin inherited Create(TheOwner); StopOnException:=True; end; destructor TNPMcl.Destroy; begin inherited Destroy; end; begin Application:=TNPMcl.Create(nil); Application.Title:='NPMcl'; Application.Run; Application.Free; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/lesion_pattern.pas���������������������������������������������0000755�0001750�0001750�00000004777�11326425446�020556� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit lesion_pattern; interface uses define_types; Type TLesionPattern = RECORD lowest, lo,hi,highest : int64; end; function SetOrderX (var lObs: Bytep; var lObsCount: integer): TLesionPattern ; function SameOrder(lO1,lO2: TLesionPattern; lObsCount: integer): boolean; function EmptyOrder: TLesionPattern; procedure SetBit(lPos: integer; var lVal: TLesionPattern); const kMaxBit = 63; kMaxBitx2 = 2*kMaxBit; kMaxBitx3 = 3*kMaxBit; kMaxObs = {126}kMaxBit*4; implementation var lPowerRA: array [1..kMaxBit] of int64; procedure SetBit(lPos: integer; var lVal: TLesionPattern); begin if (lPos <= kMaxBit) then lVal.Lowest := lVal.Lowest + lPowerRA[lPos] else if (lPos <= kMaxBitx2) then lVal.Lo := lVal.Lo + lPowerRA[lPos-kMaxBit] else if (lPos <= kMaxBitx3) then lVal.Hi := lVal.Hi + lPowerRA[lPos-kMaxBitx2] else lVal.Highest := lVal.Highest + lPowerRA[lPos-kMaxBitx3]; end; function EmptyOrder: TLesionPattern; begin result.lowest := 0; result.lo := 0; result.hi := 0; result.highest := 0; end; function SameOrder(lO1,lO2: TLesionPattern; lObsCount: integer): boolean; begin result := false; if lObsCount > kMaxObs then exit; if (lO1.lowest = lo2.lowest) and (lO1.highest = lO2.highest) and (lO1.lo = lo2.lo) and (lO1.hi = lO2.hi) then result := true else result := false; end; (*function SetOrder (var lObs: Singlep; var lObsCount: integer): TLesionPattern ; var lPos: integer; begin result := EmptyOrder; if ( lObsCount > kMaxObs) or (lObsCount < 1) then exit; for lPos := 1 to lObsCount do if lObs[lPos] <> 0 then SetBit(lPos,result); end; function SetOrderI (var lObs: LongIntp; var lObsCount: integer): TLesionPattern ; var lPos: integer; begin result := EmptyOrder; if ( lObsCount > kMaxObs) or (lObsCount < 1) then exit; for lPos := 1 to lObsCount do if lObs[lPos] <> 0 then SetBit(lPos,result); end;*) function SetOrderX (var lObs: Bytep; var lObsCount: integer): TLesionPattern ; var lPos: integer; begin result := EmptyOrder; if ( lObsCount > kMaxObs) or (lObsCount < 1) then exit; for lPos := 1 to (lObsCount) do if lObs^[lPos] <> 0 then SetBit(lPos,result); end; var lPowerPos: integer; initialization lPowerRA[1] := 1; for lPowerPos := 2 to kMaxBit do lPowerRA[lPowerPos] := lPowerRA[lPowerPos-1]*2; end. �mricron-0.20140804.1~dfsg.1.orig/npm/xanacom.pas����������������������������������������������������0000755�0001750�0001750�00000063310�11326443510�017132� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit anacom; interface {$H+} uses define_types,SysUtils,part,StatThds,statcr,StatThdsUtil,Brunner, DISTR,nifti_img, hdr,filename,Messages, Classes, Graphics, Controls, Forms, Dialogs,StdCtrls,ComCtrls,ExtCtrls,Menus, overlap, ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, upower,firthThds,firth,IniFiles,cpucount,userdir,math, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} regmult,utypes; function AnacomLesionNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttestIn,lBMIn: boolean): boolean; procedure DoAnaCOM; function readTxt (lFilename: string; var lnObservations : integer; var ldataRA1: singlep): boolean; implementation uses npmform; {$DEFINE NOTmedianfx} function AnacomLesionNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttestIn,lBMIn: boolean): boolean; label 123,667; var lOutNameMod: string; lPlankImg: byteP; lOutImgSum,lOutImgBM,lOutImgT, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM,lCombinedSymptomRA: singleP; lPos,lPlank,lThread,lnControlsPlusPatients: integer; lVolVox,lMinMask,lMaxMask,lTotalMemory,lnPlanks,lVoxPerPlank, lThreadStart,lThreadEnd,lThreadInc,lnLesion,lnPermute, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT,lBMz, lSum,lThresh,lThreshBonf,lThreshPermute,lThreshNULP :double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; lSave,lBM,lttest,lLtest: boolean; lnControlNeg: integer; {$IFDEF medianfx} lmedianFX,lmeanFX,lsummean,lsummedian: double; lmediancount: integer; {$ENDIF} begin lSave := true; lnControlNeg := lnControl; //negative for binomial test lttest := lttestin; lbm := lbmin; if (not (lttest)) and (not (lbm)) then begin lLtest := true; lBM := true; lnControlNeg := -lnControl; end; //lttest:= ttestmenu.checked; //lBM := BMmenu.checked; if lnControl < 1 then begin MainForm.NPMmsg('AnaCOM aborted - need data from at least 1 control individual'); exit; end; lnPermute := 0;//MainForm.ReadPermute; MainForm.NPMmsg('Permutations = ' +IntToStr(lnPermute)); MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; MainForm.NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); MainForm.NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) //assumes 1bpp else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; {$IFDEF medianfx} lsummean := 0; lsummedian:= 0; lmediancount := 0; {$ENDIF} for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; lnControlsPlusPatients := lImages.Count+lnControl; createArray64(lObsp,lObs,lnControlsPlusPatients); getmem(lOutImgSum,lVolVox* sizeof(single)); getmem(lOutImgBM,lVolVox* sizeof(single)); getmem(lOutImgT,lVolVox* sizeof(single)); MainForm.InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; end; //sumptom array for lesions AND controls for lPos := 1 to lImages.Count do lObs^[lPos-1] := lSymptomRA^[lPos]; for lPos := 1 to lnControl do lObs^[lPos-1+lImages.Count] := lControlSymptomRA^[lPos]; getmem(lCombinedSymptomRA,lnControlsPlusPatients* sizeof(single)); for lPos := 1 to lnControlsPlusPatients do lCombinedSymptomRA^[lPos] := lObs^[lPos-1]; //next create permuted BM bounds if lBM then begin MainForm.NPMmsg('Generating BM permutation thresholds'); MainForm.Refresh; //for lPos := 1 to lImages.Count do // lObs^[lPos-1] := lSymptomRA^[lPos]; genBMsim (lnControlsPlusPatients, lObs); end; ClearThreadData(gnCPUThreads,lnPermute) ; for lPlank := 1 to lnPlanks do begin MainForm.NPMmsg('Computing plank = ' +Inttostr(lPlank)); MainForm.Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TLesionContinuous.Create (MainForm.ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lnControlNeg,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,nil,lCombinedSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; lThreshPermute := 0; lnVoxTested := SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //next report findings if lnVoxTested < 1 then begin MainForm.NPMmsg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lnCrit)+' patients**'); goto 123; end; MainForm.NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); {$IFDEF medianfx} MainForm.NPMmsg('Average MEAN effect size = ' +realtostr((lsummean/lmediancount),3)); MainForm.NPMmsg('Average MEDIAN effect size = ' +realtostr((lsummedian/lmediancount),3)); {$ENDIF} MainForm.NPMmsg('Only tested voxels with more than '+inttostr(lnCrit)+' lesions'); //Next: save results from permutation thresholding.... //Next: save results from permutation thresholding.... lThreshBonf := MainForm.reportBonferroni('Std',lnVoxTested); //Next: NULPS if lRun > 0 then //terrible place to do this - RAM problems, but need value to threshold maps lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap2 (lImages, lnCrit,lnVoxTested,lPlankImg)); //lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap (lImages, lnCrit)); //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); if (lSave) and (lRun < 1) then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //create new header - subsequent images will use Z-scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lSave) and (lRun < 1) and (Sum2PowerCont(lOutImgSum,lVolVox,lImages.Count)) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; //MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if lttest then begin //save Ttest //next: convert t-scores to z scores if lnControl < 1 then //do not convert t-scores for anaCOM - numbers vary from voxel to voxel... for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lnPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; lThresh := MainForm.reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); lThreshPermute := MainForm.reportPermute('attest',lnPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'attest'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('AnaComthreshtt,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgT))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); if lSave then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if lBM then begin //save Mann Whitney lThresh := MainForm.reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); lThreshPermute := MainForm.reportPermute('aBM',lnPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'aBM'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('AnaCOMthreshbm,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgBM))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); if lSave then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end; //next: free dynamic memory 123: MainForm.FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgT); freemem(lOutImgBM); freemem(lOutImgSum); freemem(lObsp); freemem(lPlankImg); freemem(lCombinedSymptomRA); MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); if lSave then MainForm.MsgSave(lOutNameMod); MainForm.ProgressBar1.Position := 0; exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; //LesionNPMAnalyze (*function readCSV2 (lFilename: string; lCol1,lCol2: integer; var lnObservations : integer; var ldataRA1,ldataRA2: singlep): boolean; const kHdrRow = 0;//1; kHdrCol = 0;//1; var lNumStr: string; F: TextFile; lTempFloat: double; lCh: char; lnFactors,MaxC,R,C:integer; lError: boolean; begin lError := false; result := false; if not fileexists(lFilename) then begin showmessage('Can not find '+lFilename); exit; end; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); if (R <= (kHdrRow+1)) or (MaxC < (kHdrCol+lCol1)) or (MaxC < (kHdrCol+lCol2)) then begin showmessage('problems reading CSV - not enough columns/rows '+inttostr(lCol1)+' '+inttostr(lCol2)); exit; end; lnObservations := R -kHdrRow ; //-1: first row is header.... lnFactors := MaxC-1;// -1: first column is Y values //fx(lnObservations,lnFactors); //exit; getmem(ldataRA1,lnObservations*sizeof(single)); getmem(ldataRA2,lnObservations*sizeof(single)); //second pass Reset(F); C := 1; MaxC := 0; R := 1; lNumStr := ''; lTempfloat := 0; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin if (R > kHdrRow) and (C > kHdrCol) then begin if ((C-kHdrCol) = lCol1) or ((C-kHdrCol) = lCol2) then begin if lNumStr = '-' then begin lTempFloat := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(lNumStr); if (C-kHdrCol) = lCol1 then ldataRA1^[R-kHdrRow] := lTempFloat else if (C-kHdrCol) = lCol2 then ldataRA2^[R-kHdrRow] := lTempFloat; end; //number end; //col1 or col2 end;// else //R > 1 lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 1; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if (lNumStr <> '') and (C = lnFactors) then begin //unterminated string try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except ldataRA2^[R-1] := lTempFloat; end;//unterminated string //read finel item CloseFile(F); FileMode := 2; //Set file access to read/write result := true; end; *) function readTxt (lFilename: string; var lnObservations : integer; var ldataRA1: singlep): boolean; const kHdrRow = 0;//1; kHdrCol = 0;//1; var lCol1: integer; lNumStr: string; F: TextFile; lTempFloat: double; lCh: char; lnFactors,MaxC,R,C:integer; lError: boolean; begin lCol1:= 1; lError := false; result := false; if not fileexists(lFilename) then begin showmessage('Can not find '+lFilename); exit; end; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); if (R <= (kHdrRow+1)) or (MaxC < (kHdrCol+lCol1)) then begin showmessage('problems reading CSV - not enough columns/rows '); exit; end; lnObservations := R -kHdrRow ; //-1: first row is header.... lnFactors := kHdrCol+lCol1;// -1: first column is Y values //fx(lnObservations,lnFactors); //exit; getmem(ldataRA1,lnObservations*sizeof(single)); //second pass Reset(F); C := 1; MaxC := 0; R := 1; lNumStr := ''; lTempfloat := 0; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin if (R > kHdrRow) and (C > kHdrCol) then begin if ((C-kHdrCol) = lCol1) {or ((C-kHdrCol) = lCol2)} then begin if lNumStr = '-' then begin lTempFloat := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(lNumStr); if (C-kHdrCol) = lCol1 then begin //showmessage(lNumStr); ldataRA1^[R-kHdrRow] := lTempFloat; end; {else if (C-kHdrCol) = lCol2 then ldataRA2^[R-kHdrRow] := lTempFloat;} end; //number end; //col1 or col2 end;// else //R > 1 lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 1; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; //showmessage(lNumStr+' '+inttostr(lnFactors)+' '+inttostr(C)); if (lNumStr <> '') and (C = lnFactors) then begin //unterminated string try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(inttostr(R)+' '+floattostr(lTempFLoat)); ldataRA1^[R] := lTempFloat; end;//unterminated string //read finel item CloseFile(F); FileMode := 2; //Set file access to read/write result := not lError; end; procedure DoAnaCOM; label 666; var lControlFilename: string; lI, lnControlObservations : integer; lControldata: singlep; //lBinomial: boolean; lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCrit: integer; lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lOutName,lFactname: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA: singleP; begin npmform.MainForm.memo1.lines.clear; npmform.MainForm.memo1.lines.add('AnaCOM analysis requires TXT/CSV format text file.'); npmform.MainForm.memo1.lines.add('One row per control participant.'); npmform.MainForm.memo1.lines.add('First column is performance of that participant.'); npmform.MainForm.memo1.lines.add('Example file:'); npmform.MainForm.memo1.lines.add('11'); npmform.MainForm.memo1.lines.add('19'); npmform.MainForm.memo1.lines.add('2'); npmform.MainForm.memo1.lines.add('22'); npmform.MainForm.memo1.lines.add('19'); npmform.MainForm.memo1.lines.add('6'); if not MainForm.OpenDialogExecute('Select text file',false,false,'Text file (*.txt)|*.txt;*.csv') then begin showmessage('AnaCOM aborted: Control data file selection failed.'); exit; end; //if not selected lControlFilename := MainForm.OpenHdrDlg.Filename; if (not readTxt (lControlFilename, lnControlObservations,lControldata)) or (lnControlObservations < 1) then begin showmessage('Error reading file '+lControlFilename); exit; end; npmform.MainForm.memo1.lines.add('Control (n='+inttostr(lnControlObservations)+')performance ['+lControlFilename+']'); for lI := 1 to lnControlObservations do npmform.MainForm.memo1.lines.add(inttostr(lI)+' '+floattostr(lControldata^[lI])); //begin - copy lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? //next, get 1st group if not MainForm.GetValX(lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCrit,{,binom}lPredictorList) then begin showmessage('Error with VAL file'); goto 666; end; lTemp4D := CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) then begin Showmessage('AnaCOM error: not enough patients ('+inttostr(lnSubjAll)+') or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st file: '+lMaskName); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; MainForm.SaveHdrDlg.Filename := loutname; lOutName := lOutName+'.nii.gz'; if not MainForm.SaveHdrName ('Base Statistical Map', lOutName) then exit; for lFact := 1 to lnFactors do begin lImageNames.clear; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); lnSubj := lImageNames.Count; if lnSubj > 1 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; MainForm.NPMmsgClear; MainForm.NPMMsg(MainForm.GetKVers); MainForm.NPMMsg('Threads: '+inttostr(gnCPUThreads)); npmform.MainForm.memo1.lines.add('Control (n='+inttostr(lnControlObservations)+')performance ['+lControlFilename+']'); for lI := 1 to lnControlObservations do npmform.MainForm.memo1.lines.add(inttostr(lI)+' '+floattostr(lControldata^[lI])); lFactName := lPredictorList.Strings[lFact-1]; lFactName := LegitFilename(lFactName,lFact); MainForm.NPMMsg('Patient performance, (n= '+inttostr(lnSubj)+') Factor = '+lFactname); For lSubj := 1 to lnSubj do MainForm.NPMMsg (lImageNames.Strings[lSubj-1] + ' = '+realtostr(lSymptomRA^[lSubj],2) ); MainForm.NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); MainForm.NPMMsg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); MainForm.NPMMsg('Number of Lesion maps = '+inttostr(lnSubj)); if not CheckVoxelsGroup(lImageNames,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; MainForm.ReportDescriptives(lSymptomRA,lnSubj); AnacomLesionNPMAnalyze(lImageNames,lMaskHdr,lnCrit,-1,lnControlObservations,lSymptomRA,lControldata,lFactName,lOutname,true {ttest},false{BM}); Freemem(lSymptomRA); end; //lnsubj > 1 end; //for each factor if lnSubjAll > 0 then Freemem(lMultiSymptomRA); 666: lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); freemem(lControldata); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/turbolesion_cmdLine.pas����������������������������������������0000755�0001750�0001750�00000054541�12204671230�021510� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit turbolesion; interface {$H+} {$Include ..\common\isgui.inc} uses // Messages, Graphics, Controls, Forms, Dialogs,StdCtrls, ComCtrls,ExtCtrls,Menus, {$IFDEF GUI} ComCtrls,ReadInt,Forms, {$ENDIF} Classes,dialogsx, define_types,SysUtils,unpm, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr, overlap,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} {$IFDEF GUI} LResources,{$ENDIF} gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes; Type TLDMPrefs = record NULP,BMtest,Ttest,Ltest: boolean; CritPct,nCrit,nPermute,Run: integer; ValFilename, OutName, ExplicitMaskName: string; end; function TurboLDM (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; var lPrefs: TLDMPrefs ; var lSymptomRA: SingleP;var lFactname,lOutName: string): boolean; implementation {$IFDEF GUI} uses npmform; {$ELSE} // uses npmcl; {$ENDIF} (*procedure Debog (var lSumImg: Smallintp; lVox: integer); var lInName : string; lFData: file; begin lInName := 'c:\16.img'; assignfile(lFdata,lInName); filemode := 2; Rewrite(lFdata,lVox*sizeof(smallint)); BlockWrite(lFdata,lSumImg^, 1 {, NumWritten}); closefile(lFdata); end;*) function MakeSum (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; var lSumImg: Smallintp): boolean; //if successful, you MUST freemem(lSumImg)... label 667; var lVolVox,lVox,lImg,lPosPct: integer; lVolImg: byteP; begin result := false; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then exit; getmem(lVolImg,lVolVox* sizeof(byte)); getmem(lSumImg,lVolVox* sizeof(smallint)); for lVox := 1 to lVolVox do //June 2009 init array lSumImg^[lVox] := 0; (* for lVox := 1 to lVolVox do if lVolImg^[lVox] <> 0 then lSumImg^[lVox] := lSumImg^[lVox]+1;*) for lImg := 1 to lImages.Count do begin lPosPct := round(100*(lImg / lImages.Count)); NPMProgressBar(lPosPct); if not LoadImg8(lImages[lImg-1], lVolImg, 1, lVolVox,round(gOffsetRA[lImg]),1,gDataTypeRA[lImg],lVolVox) then goto 667; for lVox := 1 to lVolVox do if lVolImg^[lVox] <> 0 then lSumImg^[lVox] := lSumImg^[lVox]+1; end;//for each image NPMmsg('Sum image finished = ' +TimeToStr(Now)); NPMProgressBar( 0); //Debog(lSumImg, lVolVox); freemem(lVolImg); result := true; exit; 667: //you only get here if you aborted ... free memory and report error freemem(lVolImg); freemem(lSumImg); NPMMsg('Unable to complete analysis.'); NPMProgressBar( 0 ); end; function ThreshSumImg (var lSumImg: Smallintp; lVolVox,lThresh: integer): integer; //sets all voxels with values < lThresh to zero, returns number of voxels to survive threshold. var lPos: integer; begin result := 0; if lVolVox < 1 then exit; for lPos := 1 to lVolVox do if lSumImg^[lPos] < lThresh then lSumImg^[lPos] := 0 else inc(result); end; function ExplicitMaskSumImg (lMaskName: string; var lSumImg: Smallintp; lVolVox: integer): integer; //Any voxels in MaskImg that are 0 are zeroed in the SumImg var lOK: boolean; lPos: integer; lMaskHdr: TMRIcroHdr; lMaskData: bytep; label 666; begin result := 0; if (lVolVox < 1) or (not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr)) then begin NPMmsg('Error: unable to load explicit mask named '+lMaskName); exit; end; if lVolVox <> (lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]) then begin NPMmsg('Error: data and explicit mask have different sizes '+lMaskName); exit; end; getmem(lMaskData,lVolVox* sizeof(byte)); lOK := LoadImg8(lMaskName, lMaskData, 1, lVolVox,round(lMaskHdr.NIFTIhdr.vox_offset),1,lMaskHdr.NIFTIhdr.DataType,lVolVox); if not lOK then goto 666; if lVolVox < 1 then exit; for lPos := 1 to lVolVox do if lMaskData^[lPos] < 1 then lSumImg^[lPos] := 0 else inc(result); 666: freemem(lMaskData); end; function LoadImg8Masked(lInName: string; lImgData: bytep; lMaskData: SmallIntP; lStartMaskPos, lEndMaskPos,linvox_offset,lRApos,lDataType,lVolVox: integer): boolean; label 111; var lFullImgData: bytep; lMaskPos,lPos: integer; begin result := false; if (lVolVox < 1) or (lEndMaskPos < lStartMaskPos) then exit; getmem(lFullImgData,lVolVox* sizeof(byte)); result := LoadImg8(lInName, lFullImgData, 1, lVolVox,linvox_offset,1,lDataType,lVolVox); if result then begin lMaskPos := 0; for lPos := 1 to lVolVox do begin if lMaskData^[lPos] <> 0 then begin inc(lMaskPos); if (lMaskPos >=lStartMaskPos) then lImgData^[lRApos+lMaskPos-1] := lFullImgData^[lPos]; if lMaskPos = lEndMaskPos then goto 111; end;//voxel in mask end; //for each voxel in image end;//if LoadImg8 success 111: freemem(lFullImgData); end; function reformat(var lStatImg: singlep; lMaskImg: smallintp; lVolVox: integer): boolean; var lPos,lStatPos,lMaskItems: integer; begin result := false; if lVolVox < 1 then exit; lMaskItems := 0; for lPos := 1 to lVolVox do if lMaskImg^[lPos] <> 0 then inc(lMaskItems); result := true; if (lMaskItems < 1) or (lMaskItems >= lVolVox) then exit;//no need to reformat //note that we do this in descending order, so we do not overwrite... lStatPos := lMaskItems; for lPos := lVolVox downto 1 do if lMaskImg^[lPos] <> 0 then begin lStatImg^[lPos] := lStatImg^[lStatPos]; dec(lStatPos); end else lStatImg^[lPos] := 0; end;//reformat function NULPcount (lPlankImg: bytep; lVoxPerPlank,lImagesCount: integer; var lUniqueOrders: integer; var lOverlapRA: Overlapp): boolean; procedure CheckOrder(var lObservedOrder: TLesionPattern); var lInc: integer; begin if lUniqueOrders > 0 then begin //see if this is unique for lInc := 1 to lUniqueOrders do if SameOrder(lObservedOrder,lOverlapRA^[lInc],lImagesCount) then exit; //not unique end; //UniqueOrders > 0 //if we have not exited yet, we have found a new ordering! lUniqueOrders := lUniqueOrders + 1; lOverlapRA^[lUniqueOrders] := lObservedOrder; end; var lVox,lPlankImgPos,lPos: integer; lOrder,lPrevOrder: TLesionPattern; begin result := false; lPrevOrder := EmptyOrder;//impossible: forces first voxel of each order to be checked for lVox := 1 to lVoxPerPlank do begin (*if (lVox mod lVoxPerPlankDiv10) = 0 then begin MainForm.ProgressBar1.Position := (lVox div lVoxPerPlankDiv10)*10; MainForm.Refresh; Application.processmessages; end;*) lOrder := EmptyOrder; lPlankImgPos := 0; //lnDeficits := 0; for lPos := 1 to lImagesCount do begin if (lPlankImg^[lPlankImgPos + lVox] > 0) then begin //inc(lnDeficits); SetBit(lPos,lOrder); end; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end; //if (lnDeficits >= lminDeficits) then begin //this is different from the last voxel: perhaps this is a new ordering if (not SameOrder(lOrder,lPrevOrder,lImagesCount)) then CheckOrder(lOrder); //inc(lnVoxels); //end;//nDeficies lPrevOrder := lOrder; end;//for lVox result := true; end; procedure PtoZpermute (lnPermute: integer; lPermuteMaxT, lPermuteMinT: singlep); var lPos: integer; lVal : single; begin if lPos < 1 then exit; for lPos := 1 to lnPermute do begin if (lPermuteMinT^[lPos] > 1.1) or (lPermuteMinT^[lPos] < -1.1) then lPermuteMinT^[lPos] := 0.5; if (lPermuteMaxT^[lPos] > 1.1) or (lPermuteMaxT^[lPos] < -1.1) then lPermuteMaxT^[lPos] := 0.5; lVal := lPermuteMaxT^[lPos]; lPermuteMaxT^[lPos] := lPermuteMinT^[lPos]; lPermuteMinT^[lPos] := lVal; if lPermuteMaxT^[lPos] < 0 then lPermuteMaxT^[lPos] := -pNormalInv(abs(lPermuteMaxT^[lPos])) else lPermuteMaxT^[lPos] := pNormalInv(lPermuteMaxT^[lPos]); if lPermuteMinT^[lPos] < 0 then lPermuteMinT^[lPos] := -pNormalInv(abs(lPermuteMinT^[lPos])) else lPermuteMinT^[lPos] := pNormalInv(lPermuteMinT^[lPos]); end; end; function TurboLDM (var lImages: TStrings; var lMaskHdr: TMRIcroHdr;var lPrefs: TLDMPrefs ; var lSymptomRA: SingleP;var lFactname,lOutName: string): boolean; label 123,667; var lOutNameMod: string; lStatHdr: TNIfTIhdr; lThreshFDR,lThreshPermute,lThreshBonf,lThreshNULP :double; lObsp: pointer; lObs: Doublep0; lRanOrderp: pointer; lRanOrder: Doublep0; lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM,lOutImgSum,lOutImgBM,lOutImgT,lOutImgAUC: singlep; lSumImg: Smallintp; lPlankImg: byteP; lVoxPerPlank,lnPlanks,lTotalMemory,lnVoxTested,lVolVox: int64; lUniqueOrders,lThread,lThreadStart,lThreadInc,lThreadEnd, lPos2,lPosPct,lPos,lPlankImgPos,lPlank,lStartVox,lEndVox: integer; lOverlapRA: Overlapp; {$IFNDEF FPC} lStartTime :DWord;{$ENDIF} begin {$IFNDEF FPC} lStartTime := GetTickCount;{$ENDIF} result := false; lSumImg := nil; lPlankImg := nil; lOutImgSum := nil; lOutImgBM := nil; lOutImgT := nil; lOutImgAUC := nil; lOverlapRA := nil; lUniqueOrders := 0; if lPrefs.Ltest then begin lPrefs.Ttest := false; lPrefs.BMtest := false; end else if (not lPrefs.Ttest) and (not lPrefs.BMtest) then begin//not binomial NPMmsg('Error no tests specified'); exit; end; NPMmsg('Permutations = ' +IntToStr(lPrefs.nPermute)); NPMmsg('Analysis began = ' +TimeToStr(Now)); lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; if not MakeSum( lImages, lMaskHdr, lSumImg) then goto 667; lnVoxTested := ThreshSumImg(lSumImg,lVolVox,lPrefs.nCrit); NPMmsg('Voxels damaged in at least '+inttostr(lPrefs.nCrit)+' individuals = ' +Floattostr(lnVoxTested)); if lnVoxTested < 1 then begin NPMmsg('Error: no voxels damaged in at least '+inttostr(lPrefs.nCrit)+' individuals.'); goto 667; end; if (lPrefs.ExplicitMaskName <> '') then begin lnVoxTested := ExplicitMaskSumImg (lPrefs.ExplicitMaskName, lSumImg, lVolVox); NPMmsg('Voxels also non-zero in mask '+lPrefs.ExplicitMaskName+' = ' +Floattostr(lnVoxTested)); if lnVoxTested < 1 then begin NPMmsg('Error: no remaing voxels also non-zero in mask '+lPrefs.ExplicitMaskName); goto 667; end; end; //compute planks and acquire memory lTotalMemory := lnVoxTested * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/kPlankSz ) + 1; NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/kPlankSz)); if (lnPlanks = 1) then begin lVoxPerPlank := lnVoxTested; //we can do this in a single pass getmem(lPlankImg,lTotalMemory) end else begin getmem(lPlankImg,kPlankSz); lVoxPerPlank := kPlankSz div lImages.Count; end; //spatial maps for results getmem(lOutImgSum,lVolVox*sizeof(single)); getmem(lOutImgBM,lVolVox*sizeof(single)); getmem(lOutImgT,lVolVox*sizeof(single)); getmem(lOutImgAUC,lVolVox*sizeof(single)); //initialize memory InitPermute (lImages.Count, lPrefs.nPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; lOutImgAUC^[lPos] := 0; end; //next create permuted BM bounds if lPrefs.BMtest then begin NPMmsg('Generating BM permutation thresholds'); createArray64(lObsp,lObs,lImages.Count); for lPos := 1 to lImages.Count do lObs^[lPos-1] := lSymptomRA^[lPos]; genBMsim (lImages.Count, lObs); freemem(lObsp); end; if lPrefs.NULP then getmem(lOverlapRA,lnVoxTested* sizeof(TLesionPattern)); if lPrefs.Ltest then ClearThreadDataPvals(gnCPUThreads,lPrefs.nPermute) else ClearThreadData(gnCPUThreads,lPrefs.nPermute) ; //load and process data lStartVox := 1; lEndVox := 0; for lPlank := 1 to lnPlanks do begin NPMmsg('Computing plank = ' +Inttostr(lPlank)+' of '+inttostr(lnPlanks)); lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lnVoxTested then begin lVoxPerPlank := lnVoxTested-lStartVox+1{lVoxPerPlank - (lEndVox-lVolVox)}; lEndVox := lnVoxTested; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8Masked(lImages[lPos-1], lPlankImg,lSumImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; NPMmsg('starting threads '+inttostr(gnCPUThreads)); {$IFDEF aaaaa} for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error ThreadArray[lThread]:= TLesionContinuous.Create (MainForm.ProgressBar1,lPrefs.ttest,lPrefs.BMtest,lPrefs.nCrit, lPrefs.nPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,0,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA) ; inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; NPMmsg('started threads '+inttostr(gnCPUThreads)); for lThread := 1 to gnCPUThreads do if not ThreadArray[lThread].Terminated then Sleep(100); NPMmsg('done threads '+inttostr(gnCPUThreads)); {$ELSE} for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error if lPrefs.Ltest then begin with TLesionBinom.Create (MainForm.ProgressBar1,false,true,lPrefs.nCrit, lPrefs.nPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,0,lPlankImg,lOutImgSum,lOutImgBM,lOutIMgT{not used},lOutImgAUC,lSymptomRA) do {$IFDEF GUI} {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} {$ELSE} NPMmsg(inttostr(gThreadsRunning)); //OnTerminate := @NPMThreadDone; {$ENDIF} end else begin with TLesionContinuous.Create (MainForm.ProgressBar1,lPrefs.ttest,lPrefs.BMtest,lPrefs.nCrit, lPrefs.nPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,0,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA) do //with TLesionContinuous.Create (MainForm.ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,lSymptomRA) do {$IFDEF GUI} {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} {$ELSE} OnTerminate := @Application.ThreadDone; NPMmsg('starting '+inttostr(gThreadsRunning)); {$ENDIF} end; inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Sleep(100); refresher; until gThreadsRunning = 0; refresher; {$ENDIF} //end of threading if lPrefs.NULP then NULPcount (lPlankImg, lVoxPerPlank,lImages.Count, lUniqueOrders, lOverlapRA); lStartVox := lEndVox + 1; end; //calculate max per thread SumThreadData(gnCPUThreads,lPrefs.nPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //data in maps is stored in voxels 1..lnVoxTested - put in spatial order reformat(lOutImgSum,lSumImg,lVolVox); reformat(lOutImgBM,lSumImg,lVolVox); reformat(lOutImgT,lSumImg,lVolVox); reformat(lOutImgAUC,lSumImg,lVolVox); lThreshBonf := reportBonferroni('Std',lnVoxTested); if lPrefs.NULP then lThreshBonf := reportBonferroni('Number of Unique Lesion Patterns',lUniqueOrders); //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); if lPrefs.Run < 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //save Area Under Curve lOutNameMod := ChangeFilePostfixExt(lOutName,'rocAUC'+lFactName,'.hdr'); if lPrefs.Run < 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgAUC,1); //create new header - subsequent images will use Z-scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lPrefs.Run < 1) and (Sum2Power(lOutImgSum,lVolVox,lImages.Count,lPrefs.nCrit, lPrefs.LTest)) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; //if lPrefs.Run > 0 then //terrible place to do this - RAM problems, but need value to threshold maps // lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap2 (lImages, lPrefs.nCrit,lnVoxTested,lPlankImg)); if lPrefs.ttest then begin //save Ttest //next: convert t-scores to z scores for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lPrefs.nPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; lThreshFDR := reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); lThreshPermute := reportPermute('ttest',lPrefs.nPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'ttest'+lFactName,'.hdr'); {$IFNDEF FPC} if lPrefs.Run > 0 then begin MainForm.NPMmsgAppend('threshtt,'+inttostr(lPrefs.Run)+','+inttostr(MainForm.ThreshMap(lThreshBonf,lVolVox,lOutImgT))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)+','+inttostr(round((GetTickCount - lStartTime)/1000))); end; {$ENDIF} NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if lPrefs.LTest then begin PtoZpermute (lPrefs.nPermute, lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'L'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); reportFDR ('L', lVolVox, lnVoxTested, lOutImgBM); reportPermute('L',lPrefs.nPermute,lPermuteMaxT, lPermuteMinT); end;//Liebermeister if lPrefs.BMtest then begin //save Brunner Munzel lThreshFDR := reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); lThreshPermute := reportPermute('BM',lPrefs.nPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'BM'+lFactName,'.hdr'); if lPrefs.Run > 0 then NPMmsg('threshbm,'+inttostr(lPrefs.Run)+','+inttostr(ThreshMap(lThreshBonf,lVolVox,lOutImgBM))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end; NPMmsg('Analysis finished = ' +TimeToStr(Now)); {$IFNDEF FPC} MainForm.NPMmsg('Processing Time = ' +inttostr(round((GetTickCount - lStartTime)/1000)));{$ENDIF} lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); NPMMsgSave(lOutNameMod); //all done result := true;//all done without aborting 667: // free memory and report error if lPlankImg <> nil then freemem(lPlankImg); if lSumImg <> nil then freemem(lSumImg); if lOutImgSum <> nil then freemem(lOutImgSum); if lOutImgBM <> nil then freemem(lOutImgBM); if lOutImgT <> nil then freemem(lOutImgT); if lOutImgAUC <> nil then freemem(lOutImgAUC); if lOverlapRA <> nil then freemem(lOverlapRA); if not result then NPMmsg('Unable to complete analysis.'); NPMProgressBar( 0); end; //TurboLDM end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/montecarlo.pas�������������������������������������������������0000755�0001750�0001750�00000017274�12156156744�017673� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit montecarlo; interface {$H+} {$DEFINE anacom} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr, Messages, Classes, Graphics, Controls, Forms, Dialogsx, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes{$IFDEF anacom} ,anacom{$ENDIF}; procedure LesionMonteCarlo (lBinomial,lTTest,lBM: boolean); implementation uses npmform,filename,turbolesion; procedure RandomGroup(kSamplesPerTest: integer;lImageNames: TStrings;lSymptomRA: SingleP;var lPartImageNames: TStrings; var lPartSymptomRA: SingleP); var lTotal,lInc,lRand,lSwap: integer; lRanOrder: longintP; begin lPartImageNames.Clear; lTotal := lImageNames.Count; if kSamplesPerTest > lTotal then begin showmessage('Monte carlo error: population must be larger than sample size.'); exit; end; Getmem(lRanOrder,lTotal*sizeof(longint)); for lInc := 1 to lTotal do lRanOrder^[lInc] := lInc; for lInc := lTotal downto 2 do begin lRand := Random(lInc)+1; lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc]; lRanOrder^[lInc] := lSwap; end; for lInc := 1 to kSamplesPerTest do begin lPartImageNames.Add(lImageNames.Strings[lRanOrder^[lInc]-1]);//indexed from 0 lPartSymptomRA^[lInc] := lSymptomRA^[lRanOrder^[lInc]]; end; Freemem(lRanOrder); end; procedure LesionMonteCarlo (lBinomial,lTTest,lBM: boolean); label 666; const kSimSampleSize = 64; knSim = 2; kCrit = 3; {$IFDEF anacom} knControls = 64; {$ENDIF} var lPrefs: TLDMPrefs ; lSim,lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCrit: integer; lPartImageNames,lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lOutName,lFactname,lOutNameSim: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA,lPartSymptomRA: singleP; {$IFDEF anacom} lnControlObservations: integer; lControlSymptomRA: singleP; {$ENDIF} begin //lBinomial := not odd( (Sender as tMenuItem).tag); lPrefs.NULP := true{gNULP false}; if not lBinomial then begin lPrefs.BMtest := lbm;//BMmenu.checked; lPrefs.Ttest := lttest;//ttestmenu.checked; if (not lPrefs.BMtest) and (not lPrefs.ttest) then lPrefs.ttest := true; lPrefs.Ltest:= false; end else begin lPrefs.BMtest := false; lPrefs.Ttest := false; lPrefs.Ltest:= true; end; lPrefs.nCrit := kCrit; lPrefs.nPermute := 0;//MainForm.ReadPermute;; lPrefs.Run := 0;{0 except for montecarlo} if (not lBinomial) and (not lTTest) and (not lBM) then begin Showmessage('Error: you need to compute at least on test [options/test menu]'); exit; end; lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? lPartImageNames := TStringList.Create; getmem(lPartSymptomRA,kSimSampleSize*sizeof(single)); {$IFDEF anacom} lnControlObservations := knControls; getmem(lControlSymptomRA,lnControlObservations*sizeof(single)); for lSim := 1 to lnControlObservations do lControlSymptomRA^[lSim] := 1000; {$ENDIF} //next, get 1st group if not MainForm.GetValX(lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCrit{,binom},lPredictorList) then begin showmessage('Error with VAL file'); goto 666; end; lTemp4D := CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) or (lnSubjAll < kSimSampleSize) then begin Showmessage('Not enough subjects ('+inttostr(lnSubjAll)+') [sample size is '+inttostr(kSimSampleSize)+']or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; MainForm.SaveHdrDlg.Filename := loutname; lOutName := lOutName+'.nii.gz'; if not MainForm.SaveHdrName ('Base Statistical Map', lOutName) then goto 666; for lFact := 1 to lnFactors do begin lImageNames.clear; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); lnSubj := lImageNames.Count; if lnSubj > 1 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; //randomization loop.... for lSim := 1 to knSim do begin RandomGroup(kSimSampleSize, lImageNames,lSymptomRA, lPartImageNames, lPartSymptomRA); lOutNameSim := AddIndexToFilename(lOutName,lSim); lnCrit := kCrit; MainForm.NPMMsgClear; //Msg(GetKVers); MainForm.NPMMsg('Threads: '+inttostr(gnCPUThreads)); lFactName := lPredictorList.Strings[lFact-1]; lFactName := LegitFilename(lFactName,lFact); MainForm.NPMMsg('Factor = '+lFactname); For lSubj := 1 to kSimSampleSize do MainForm.NPMMsg (lPartImageNames.Strings[lSubj-1] + ' = '+realtostr(lPartSymptomRA^[lSubj],2) ); MainForm.NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); MainForm.NPMMsg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); MainForm.NPMMsg('Number of Lesion maps = '+inttostr(kSimSampleSize)); if not CheckVoxelsGroup(lPartImageNames,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; lPrefs.Run := lSim; if lBinomial then TurboLDM (lPartImageNames, lMaskHdr, lPrefs, lPartSymptomRA, lFactname,lOutNameSim) else begin MainForm.ReportDescriptives(lPartSymptomRA,lnSubj); TurboLDM (lPartImageNames, lMaskHdr, lPrefs, lPartSymptomRA, lFactname,lOutNameSim); {$IFDEF anacom} AnacomLesionNPMAnalyze (lPartImageNames, lMaskHdr, lnCrit,lSim,lnControlObservations, lPartSymptomRA,lControlSymptomRA, lFactname,lOutNameSim,true,false); {$ENDIF} end; end; //for each simulation... Freemem(lSymptomRA); end; //lnsubj > 1 end; //for each factor if lnSubjAll > 0 then begin Freemem(lMultiSymptomRA); end; 666: lPartImageNames.free; lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; freemem(lPartSymptomRA); {$IFDEF anacom} freemem(lControlSymptomRA); {$ENDIF} DeleteDecompressed4D(lTemp4D); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/xLesionStatThds.pas��������������������������������������������0000755�0001750�0001750�00000044527�11354667732�020634� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit LesionStatThds; interface uses SysUtils, ComCtrls,Classes, Graphics, ExtCtrls, define_types,stats,StatThdsUtil,Brunner,lesion_pattern; type TLesionStatThread = class(TThread) private lBarX: TProgressBar; lttestx,lBMx: boolean; lnCritx,lBarPosX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx, lImagesCountx,lControlsx : integer; lPlankImgx:ByteP; lOutImgMnx,lOutImgBMx,lOutImgTx,lOutImgAUCX,lSymptomRAx: SingleP; //lBarX: TProgressBar; procedure DoVisualSwap; protected procedure Execute; override; procedure VisualProg(lPos: Integer); procedure Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg:bytep;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); virtual; abstract; public constructor Create(lBar: TProgressBar;lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg:ByteP;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); end; { Lesion - image reveals value } TLesionContinuous = class(TLesionStatThread ) protected procedure Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: byteP;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); override; end; TLesionBinom = class(TLesionStatThread ) protected procedure Analyze(lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: byteP;lOutImgMn,lOutImgL,lOutImgX,lOutImgAUC,lSymptomRA: SingleP); override; end; implementation (*procedure OutStr(lStr: string); var lOutname: string; f: TextFile; begin lOutname:='c:\fx.txt'; if fileexists(lOutname) then begin { open a text file } AssignFile(f, lOutname); Append(f); Writeln(f, lStr); Flush(f); { ensures that the text was actually written to file } { insert code here that would require a Flush before closing the file } CloseFile(f); end; end; *) Const Two32 = 4294967296.0 ; function GenRandThreaded(lRange: integer; var lRandSeed:comp): integer; //normal random function does not work well when threaded - randseed is changed by each thread const lFactor = $08088405 ; lTerm = 1 ; type lT = array [0..1] of longint ; var lX: extended; begin lRandSeed := lRandSeed*lFactor + lTerm; lT(lRandSeed)[1] := 0 ; // < May'04 was: RS := RS - Trunc(RS/Two32)*Two32 ; lX := lRandSeed/Two32 ; result := trunc((lRange)*lX); end; procedure GenPermuteThreaded (lnSubj: integer; var lOrigOrder,lRanOrder: DoubleP0; var lRandSeed:comp); var lInc,lRand: integer; lSwap: double; begin Move(lOrigOrder^,lRanOrder^,lnSubj*sizeof(double)); for lInc := lnSubj downto 2 do begin lRand := GenRandThreaded(lInc,lRandSeed); lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc-1]; lRanOrder^[lInc-1] := lSwap; end; end; procedure StatPermuteThreaded (lttest,lBM: boolean; lnSubj, lnGroup0,lnPermute,lThread: integer;var lOrigOrder: DoubleP0); var lInc: integer; lOutT,lDF,lBMz: double; lRS: Comp; lRanOrderp: pointer; lRanOrder: Doublep0; begin if (lnSubj < 1) or (lnPermute < 1) then exit; createArray64(lRanOrderp,lRanOrder,lnSubj); lRS := 128; for lInc := 1 to lnPermute do begin GenPermuteThreaded(lnSubj, lOrigOrder,lRanOrder,lRS); //generate random order of participants if lttest then begin TStat2 (lnSubj, lnGroup0, lRanOrder, lOutT); if lOutT > gPermuteMaxT[lThread,lInc] then gPermuteMaxT[lThread,lInc] := lOutT; if lOutT < gPermuteMinT[lThread,lInc] then gPermuteMinT[lThread,lInc] := lOutT; end; //compute ttest if lBM then begin //BMTest (lnSubj, lnGroup0, lRanOrder,lOutT); tBM (lnSubj, lnGroup0, lRanOrder,lBMz,lDF); lBMz := BMzVal (lnSubj, lnGroup0,lBMz,lDF); if lBMz > gPermuteMaxBM[lThread,lInc] then gPermuteMaxBM[lThread,lInc] := lBMz; if lBMz < gPermuteMinBM[lThread,lInc] then gPermuteMinBM[lThread,lInc] := lBMz; end; //compute BM end; freemem(lRanOrderp); end; procedure GenPermuteThreadedBinom (lnSubj: integer; var lOrigOrder,lRanOrder: ByteP0; var lRandSeed:comp); var lInc,lRand: integer; lSwap: byte; begin Move(lOrigOrder^,lRanOrder^,lnSubj); for lInc := lnSubj downto 2 do begin lRand := GenRandThreaded(lInc,lRandSeed); lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc-1]; lRanOrder^[lInc-1] := lSwap; end; end; procedure StatPermuteBinomialThreaded (lnSubj, lnGroup0,lnPermute,lThread: integer;var lOrigOrder: ByteP0); var lInc: integer; lOutP: double; lRS: Comp; lRanOrder: byteP0; begin if (lnSubj < 1) or (lnPermute < 1) then exit; //createArray64(lRanOrderp,lRanOrder,lnSubj); getmem(lRanOrder,lnSubj); lRS := 128; for lInc := 1 to lnPermute do begin GenPermuteThreadedBinom(lnSubj, lOrigOrder,lRanOrder,lRS); //generate random order of participants (*if lChi2 then begin Chi2 (lnSubj, lnGroup0, lRanOrder, lOutT); if lOutT > gPermuteMaxT[lThread,lInc] then gPermuteMaxT[lThread,lInc] := lOutT; if lOutT < gPermuteMinT[lThread,lInc] then gPermuteMinT[lThread,lInc] := lOutT; end; //compute ttest if lLieber then begin*) //Liebermeister2bP (lnSubj, lnGroup0, lRanOrder,lOutP); Liebermeister2bP (lnSubj, lnGroup0, lRanOrder,lOutP); if (lOutP > 0) and (lOutP < gPermuteMinT[lThread,lInc]) then begin //negative correlation //fx(lOutP, gPermuteMinBM[lThread,lInc]); gPermuteMinT[lThread,lInc] := lOutP; end; if (lOutP < 0) and ( lOutP > gPermuteMaxT[lThread,lInc]) then //negative correlation gPermuteMaxT[lThread,lInc] := lOutP; //end; //compute BM end; freemem(lRanOrder); end; procedure TLesionStatThread .DoVisualSwap; begin lBarX.Position := lBarPosX; end; procedure TLesionStatThread .VisualProg(lPos: Integer); begin lBarPosX := lPos; {$IFDEF FPC}Synchronize(@DoVisualSwap); {$ELSE} Synchronize(DoVisualSwap);{$ENDIF} end; constructor TLesionStatThread.Create(lBar: TProgressBar; lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: byteP;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); begin lBarX := lBar; lttestx := lttest; lBMx:= lBM; lThreadX := lThread; lThreadStartX := lThreadStart; lThreadEndX := lThreadEnd; lStartVoxx := lStartVox; lVoxPerPlankx := lVoxPerPlank; lImagesCountX := lImagesCount; lControlsX := lControlsIn; lPlankImgx := lPlankImg; lOutImgMnx := lOutImgMn; lOutImgBMx := lOutImgBM; lOutImgTx := lOutImgT; lOutImgAUCx := lOutImgAUC; lSymptomRAx := lSymptomRA; lnPermuteX := lnPermute; lnCritX := lnCrit; FreeOnTerminate := True; inherited Create(False); end; { The Execute method is called when the thread starts } procedure TLesionStatThread .Execute; begin Analyze(lttestx,lBMx, lnCritX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx,lImagesCountx,lControlsx,lPlankImgX,lOutImgMnx,lOutImgBMx,lOutImgTx,lOutImgAUCx,lSymptomRAx); end; procedure TLesionContinuous.Analyze (lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIN : integer; lPlankImg:bytep;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); //pattern variables const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lPrevZValsT,lPrevZValsBM,lPrevAUCVals: array [1..knPrevPattern] of Single; lPatternPos: integer; lLesionOrderp: bytep; //standard variables var lStr: string; lObstp,lObsp: pointer; lObst,lObs: Doublep0; lT,lBMz,lDF: Double; lObsB: bytep0; lnLesion,lnNoLesion,lPosPct,lPos,lPos2,lPos2Offset,lnControl, lnControlsPlusLesion,lnControlsPlusPatients : integer; begin //statthread //init patterns lnControl := abs(lControlsIn); if lControlsIn < 0 then begin //binomial getmem(lObsB, lImagesCount+lnControl); end; lnControlsPlusPatients := lImagesCount+lnControl; for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; //lMaxLesion := lImagesCount-lnCrit; getmem(lLesionOrderp, lImagesCount *sizeof(byte)); //now init standard variables createArray64(lObsp,lObs,lnControlsPlusPatients); lPosPct := (lThreadEnd-lThreadStart) div 100; //if lThread = 1 then // OutStr( inttostr(lThreadStart)+':'+inttostr(lThreadEnd)); //xxxxx for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; lnNoLesion := 0; for lPos := 1 to lImagesCount do begin if lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2] = 0 then begin //no lesion inc(lnNoLesion); lLesionOrderp^[lPos] := 0; lObs^[lnNoLesion-1] := lSymptomRA^[lPos]; end else begin //lesion inc(lnLesion); lLesionOrderp^[lPos] := 1; //lObs^[lImagesCount-lnLesion] := lSymptomRA^[lPos]; //note: lObs indexed from zero! lObs^[lImagesCount-lPos+lnNoLesion] := lSymptomRA^[lPos]; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) {and (lnLesion <= lMaxLesion)} then begin inc(gnVoxTestedRA[lThread]); //now check if we have seen this precise lesion order recently... lPattern := SetOrderX (lLesionOrderp,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin //lesion pattern is not novel if lttest then lOutImgT^[lPos2Offset] := lPrevZvalsT[lPos]; if lBM then lOutImgBM^[lPos2Offset] := lPrevZvalsBM[lPos]; if lOutImgAUC <> nil then lOutImgAUC^[lPos2Offset] := lPrevAUCvals[lPos]; end else begin //lesion pattern is novel //record novel pattern inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; lPrevPatternRA[lPatternPos] := lPattern; lnControlsPlusLesion := lnControlsPlusPatients; if (lControlsIn > 0) {and (lnLesion > 0)} then begin //anaCOm createArray64(lObstp,lObst,lImagesCount); for lPos := 1 to lImagesCount do lObst^[lPos-1] := lObs^[lPos-1]; for lPos := 1 to lnLesion do lObs^[lPos-1+lnControl] := lObst^[lPos-1+lnNoLesion]; freemem(lObstP); for lPos := 1 to lnControl do lObs^[lPos-1] := lSymptomRA^[lPos+lImagesCount]; lnControlsPlusLesion := lnControl+lnLesion; lnNoLesion := {lnNoLesion +} lnControl; end;//controls (*if lPos2 = 2570879 then begin //xxxx for lPos := 1 to lImagesCount do begin outstr(inttostr(lPos)+'>'+floattostr(lObs^[lPos-1]) ); end; end;*) if lttest then begin if lControlsIn > 0 then begin//anacom TStat2Z (lnControlsPlusLesion, lnControl {lnNoLesion},lObs,lT); (* if lPos2 = 2570879 then begin outstr( floattostr(lT)+ ' '+inttostr(lnControl)); //xxxx for lPos := 1 to lnControlsPlusLesion do begin outstr(inttostr(lPos)+', '+floattostr(lObs^[lPos-1]) ); end; end; *) end else TStat2 (lnControlsPlusLesion, lnNoLesion, lObs,lT); lOutImgT^[lPos2Offset] := lT; lPrevZValsT[lPatternPos] := lT; end; if lBM then begin tBM (lnControlsPlusLesion, lnNoLesion, lObs,lBMz,lDF); lBMz := BMzVal (lnControlsPlusPatients, lnNoLesion,lBMz,lDF); lOutImgBM^[lPos2Offset] := lBMz; lPrevZValsBM[lPatternPos] := lBMz; end; if lOutImgAUC <> nil then begin lOutImgAUC^[lPos2Offset] := continROC (lnControlsPlusLesion, lnNoLesion, lObs); lPrevAUCVals[lPatternPos] := lOutImgAUC^[lPos2Offset]; end; StatPermuteThreaded (lttest,lBM,lImagesCount, lnNoLesion,lnPermute,lThread, lObs); end; //novel lesion pattern end; //in brain mask - compute end; //for each voxel freemem(lObsP); freemem(lLesionOrderp); if lControlsIn < 0 then //binomial freemem(lObsB); end; procedure TLesionBinom.Analyze (lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: bytep;lOutImgMn,lOutImgL,lOutImgX,lOutImgAUC,lSymptomRA: SingleP); //procedure TLesionBinomial.Analyze (lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgL,lOutImgX,lSymptomRA: SingleP); //pattern variables const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lPrevZValsL ,lPrevAUCVals: array [1..knPrevPattern] of Single; lPatternPos: integer; lLesionOrderp: bytep; //standard variables var //lObsp: pointer; //lObs: Doublep0; lPrevZVals lObs: ByteP0; lAUC,lZ: Double; lnLesion,lPosPct,lPos,lPos2,lPos2Offset,lnVoxTested: integer; begin //Binomial StatThread //init patterns for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; getmem(lLesionOrderp, lImagesCount *sizeof(byte)); //now init standard variables //createArray64(lObsp,lObs,lImagesCount); getmem(lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; for lPos := 1 to lImagesCount do begin if ((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]) = 0 then begin //no lesion lObs^[lImagesCount-lPos+lnLesion] := round(lSymptomRA^[lPos]); lLesionOrderp^[lPos] := 0; end else begin //lesion inc(lnLesion); lLesionOrderp^[lPos] := 1; lObs^[lnLesion-1] := round(lSymptomRA^[lPos]); //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) then begin inc(gnVoxTestedRA[lThread]); //next check patterns //x lPattern := SetOrderX (lLesionOrderp,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin //lesion pattern is not novel //if lChi2 then // lOutImgX^[lPos2Offset] := lPrevZvalsX[lPos]; //if lLieber then lOutImgL^[lPos2Offset] := lPrevZvalsL[lPos]; if lOutImgAUC <> nil then lOutImgAUC^[lPos2Offset] := lPrevAUCvals[lPos]; end else begin //lesion pattern is novel //record novel pattern inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; lPrevPatternRA[lPatternPos] := lPattern; {if lChi2 then begin Chi2 (lImagesCount, lnLesion, lObs,lT); lOutImgX^[lPos2Offset] := lT;//lT; lPrevZValsX[lPatternPos] := lT; end; if lLieber then begin} Liebermeister2b(lImagesCount, lnLesion, lObs,lAUC,lZ); if lOutImgAUC <> nil then lOutImgAUC^[lPos2Offset] := lAUC; lPrevAUCVals[lPatternPos] := lAUC; lOutImgL^[lPos2Offset] := lZ; lPrevZValsL[lPatternPos] := lZ; //end; StatPermuteBinomialThreaded (lImagesCount, lnLesion,lnPermute,lThread, lObs); end; end; //in brain mask - compute end; //for each voxel freemem(lObs); freemem(lLesionOrderp) end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/npmform.lrs����������������������������������������������������0000755�0001750�0001750�00000014531�12306741004�017176� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TMainForm','FORMDATA',[ 'TPF0'#9'TMainForm'#8'MainForm'#4'Left'#3#212#1#6'Height'#3#162#1#3'Top'#3#213 +#0#5'Width'#3#30#2#13'ActiveControl'#7#5'Memo1'#7'Caption'#6#22'Non-Parametr' +'ic Mapping'#12'ClientHeight'#3#162#1#11'ClientWidth'#3#30#2#4'Menu'#7#9'Mai' +'nMenu1'#7'OnClose'#7#9'FormClose'#8'OnCreate'#7#10'FormCreate'#6'OnShow'#7#8 +'FormShow'#8'Position'#7#14'poScreenCenter'#10'LCLVersion'#6#8'1.0.12.0'#0#5 +'TMemo'#5'Memo1'#4'Left'#2#0#6'Height'#3#137#1#3'Top'#2#0#5'Width'#3#30#2#5 +'Align'#7#8'alClient'#10'ScrollBars'#7#10'ssAutoBoth'#8'TabOrder'#2#0#0#0#6 +'TPanel'#6'Panel1'#4'Left'#2#0#6'Height'#2#25#3'Top'#3#137#1#5'Width'#3#30#2 +#5'Align'#7#8'alBottom'#12'ClientHeight'#2#25#11'ClientWidth'#3#30#2#8'TabOr' +'der'#2#1#0#12'TProgressBar'#12'ProgressBar1'#4'Left'#2#1#6'Height'#2#23#3'T' +'op'#2#1#5'Width'#3#28#2#5'Align'#7#8'alClient'#8'TabOrder'#2#0#0#0#0#9'TMai' +'nMenu'#9'MainMenu1'#4'left'#2#8#3'top'#2#8#0#9'TMenuItem'#5'File1'#7'Captio' +'n'#6#4'File'#0#9'TMenuItem'#9'SaveText1'#7'Caption'#6#12'Save text...'#7'On' +'Click'#7#14'Savetext1Click'#0#0#9'TMenuItem'#5'Exit1'#7'Caption'#6#4'Exit'#7 +'OnClick'#7#10'Exit1Click'#0#0#0#9'TMenuItem'#5'Edit1'#7'Caption'#6#4'Edit'#0 +#9'TMenuItem'#5'Copy1'#7'Caption'#6#4'Copy'#7'OnClick'#7#10'Copy1Click'#0#0#0 +#9'TMenuItem'#5'VLSM1'#7'Caption'#6#4'VLSM'#0#9'TMenuItem'#24'BinomialAnalys' +'islesions1'#7'Caption'#6'''Binary images, binary groups (lesions) '#8'Short' +'Cut'#3'B@'#7'OnClick'#7#14'LesionBtnClick'#0#0#9'TMenuItem!Binaryimagescont' +'inuousgroupsfast1'#3'Tag'#2#1#7'Caption'#6'''Binary images, continuous grou' +'ps (vlsm)'#8'ShortCut'#3'L@'#7'OnClick'#7#14'LesionBtnClick'#0#0#9'TMenuIte' +'m'#28'PenalizedLogisticRegerssion1'#7'Caption'#6#31'Binary images, multiple' +' factors'#7'OnClick'#7'!PenalizedLogisticRegerssion1Click'#0#0#9'TMenuItem' +#12'ROIanalysis1'#7'Caption'#6#12'ROI analysis'#7'OnClick'#7#17'ROIanalysis1' +'Click'#0#0#9'TMenuItem'#7'Design1'#7'Caption'#6#9'Design...'#8'ShortCut'#3 +'D@'#7'OnClick'#7#12'Design1Click'#0#0#0#9'TMenuItem'#4'VBM1'#7'Caption'#6#3 +'VBM'#0#9'TMenuItem'#22'ContinuousanalysisVBM1'#7'Caption'#6'&Continuous ima' +'ges, binary groups (VBM)'#8'ShortCut'#3'V@'#7'OnClick'#7#8'NPMclick'#0#0#9 +'TMenuItem'#11'PairedTMenu'#7'Caption'#6#22'Paired Measures T-test'#7'OnClic' +'k'#7#16'PairedTMenuClick'#0#0#9'TMenuItem'#15'MultipleRegress'#7'Caption'#6 +#23'Multiple WLS Regression'#7'Visible'#8#7'OnClick'#7#20'MultipleRegressCli' +'ck'#0#0#9'TMenuItem'#13'SingleRegress'#7'Caption'#6#21'Single WLS Regressio' +'n'#7'Visible'#8#7'OnClick'#7#18'SingleRegressClick'#0#0#9'TMenuItem'#21'Dua' +'lImageCorrelation1'#7'Caption'#6#22'Dual image correlation'#7'Visible'#8#7 +'OnClick'#7#26'DualImageCorrelation1Click'#0#0#0#9'TMenuItem'#8'Options1'#7 +'Caption'#6#7'Options'#0#9'TMenuItem'#13'Permutations1'#7'Caption'#6#12'Perm' +'utations'#0#9'TMenuItem'#2'N0'#9'AutoCheck'#9#7'Caption'#6#4'None'#7'Checke' +'d'#9#10'GroupIndex'#2'{'#9'RadioItem'#9#7'OnClick'#7#14'radiomenuclick'#0#0 +#9'TMenuItem'#5'N1000'#3'Tag'#3#232#3#9'AutoCheck'#9#7'Caption'#6#4'1000'#10 +'GroupIndex'#2'{'#9'RadioItem'#9#7'OnClick'#7#14'radiomenuclick'#0#0#9'TMenu' +'Item'#5'N2000'#3'Tag'#3#208#7#9'AutoCheck'#9#7'Caption'#6#4'2000'#10'GroupI' +'ndex'#2'{'#9'RadioItem'#9#7'OnClick'#7#14'radiomenuclick'#0#0#9'TMenuItem'#5 +'N3000'#3'Tag'#3#184#11#9'AutoCheck'#9#7'Caption'#6#4'3000'#10'GroupIndex'#2 +'{'#9'RadioItem'#9#7'OnClick'#7#14'radiomenuclick'#0#0#9'TMenuItem'#5'N4000' +#3'Tag'#3#160#15#9'AutoCheck'#9#7'Caption'#6#4'4000'#10'GroupIndex'#2'{'#9'R' +'adioItem'#9#7'OnClick'#7#14'radiomenuclick'#0#0#0#9'TMenuItem'#6'Tests1'#7 +'Caption'#6#5'Tests'#0#9'TMenuItem'#9'ttestmenu'#7'Caption'#6#6't-test'#7'On' +'Click'#7#13'testmenuclick'#0#0#9'TMenuItem'#6'BMmenu'#7'Caption'#6#14'Brunn' +'er Munzel'#7'Checked'#9#7'OnClick'#7#13'testmenuclick'#0#0#0#9'TMenuItem'#8 +'Threads1'#7'Caption'#6#7'Threads'#0#9'TMenuItem'#2'T1'#9'AutoCheck'#9#7'Cap' +'tion'#6#1'1'#7'Checked'#9#10'GroupIndex'#3#131#0#9'RadioItem'#9#7'OnClick'#7 +#12'threadChange'#0#0#9'TMenuItem'#2'T2'#9'AutoCheck'#9#7'Caption'#6#1'2'#10 +'GroupIndex'#3#131#0#9'RadioItem'#9#7'OnClick'#7#12'threadChange'#0#0#9'TMen' +'uItem'#2'T3'#9'AutoCheck'#9#7'Caption'#6#1'3'#10'GroupIndex'#3#131#0#9'Radi' +'oItem'#9#7'OnClick'#7#12'threadChange'#0#0#9'TMenuItem'#2'T4'#9'AutoCheck'#9 +#7'Caption'#6#1'4'#10'GroupIndex'#3#131#0#9'RadioItem'#9#7'OnClick'#7#12'thr' +'eadChange'#0#0#9'TMenuItem'#2'T7'#9'AutoCheck'#9#7'Caption'#6#1'7'#10'Group' +'Index'#3#131#0#9'RadioItem'#9#7'OnClick'#7#12'threadChange'#0#0#9'TMenuItem' +#2'T8'#9'AutoCheck'#9#7'Caption'#6#1'8'#10'GroupIndex'#3#131#0#9'RadioItem'#9 +#7'OnClick'#7#12'threadChange'#0#0#9'TMenuItem'#3'T15'#9'AutoCheck'#9#7'Capt' +'ion'#6#2'15'#10'GroupIndex'#3#131#0#9'RadioItem'#9#7'OnClick'#7#12'threadCh' +'ange'#0#0#9'TMenuItem'#3'T16'#9'AutoCheck'#9#7'Caption'#6#2'16'#10'GroupInd' +'ex'#3#131#0#9'RadioItem'#9#7'OnClick'#7#12'threadChange'#0#0#0#9'TMenuItem' +#16'PlankSzMenuItem1'#7'Caption'#6#10'Plank Size'#7'OnClick'#7#21'PlankSzMen' ,'uItem1Click'#0#0#0#9'TMenuItem'#10'Utilities1'#7'Caption'#6#9'Utilities'#0#9 +'TMenuItem'#9'Variance1'#7'Caption'#6#14'Variance image'#7'OnClick'#7#14'Var' +'iance1Click'#0#0#9'TMenuItem'#14'Makemeanimage2'#3'Tag'#2#1#7'Caption'#6#19 +'Make binarized mean'#7'OnClick'#7#19'Makemeanimage1Click'#0#0#9'TMenuItem' +#14'Makemeanimage1'#7'Caption'#6#21'Make mean/StDev image'#7'OnClick'#7#19'M' +'akemeanimage1Click'#0#0#9'TMenuItem'#21'SingleSubjectZScores1'#7'Caption'#6 +#22'Single Subject Z-Score'#7'OnClick'#7#26'SingleSubjectZScores1Click'#0#0#9 +'TMenuItem'#24'IntensitynormalizationA1'#3'Tag'#2#1#7'Caption'#6#25'Intensit' +'y normalization A'#7'OnClick'#7#13'Balance1Click'#0#0#9'TMenuItem'#8'Balanc' +'e1'#7'Caption'#6#25'Intensity normalization B'#7'OnClick'#7#13'Balance1Clic' +'k'#0#0#0#9'TMenuItem'#5'Help1'#7'Caption'#6#4'Help'#7'Visible'#8#0#9'TMenuI' +'tem'#6'About1'#7'Caption'#6#5'About'#7'OnClick'#7#11'About1Click'#0#0#0#0#11 +'TSaveDialog'#10'SaveHdrDlg'#11'FilterIndex'#2#0#4'left'#2#8#3'top'#2'('#0#0 +#11'TOpenDialog'#10'OpenHdrDlg'#11'FilterIndex'#2#0#4'left'#2#8#3'top'#2'H'#0 +#0#0 ]); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/valformat.pas��������������������������������������������������0000755�0001750�0001750�00000023643�12156163720�017510� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit valformat; {$H+} interface uses {$IFNDEF UNIX} Windows,{Registry,ShlObj,}{$ENDIF} //Messages, Graphics, Controls, Forms, Dialogs, SysUtils, Classes,dialogsx, //Grids, Menus, ToolWin, ComCtrls, Buttons,Clipbrd, StdCtrls,Spin, ,npmform define_types; const {$IFDEF FPC} kNaN = -maxint; {$ELSE} kNaN : double = 1/0; {$ENDIF} kVALNativeSignatureBase = '#Version:'; kValMaxVers = 1; //version 0 = 3D, version 1 = 4D, version 2 not yet supported kTxtExt = '.txt'; kVALNativeExt = '.val'; kValFilter = 'Text description (*.val)|*.val'; function RowColPos (lRow,lCol,lnCol: integer): integer; function OpenValFile (var lFilename,lTemplateName:string; var lnRow,lnCol,lnColWObs,lnCritPct: integer; var lDesignUnspecified : boolean; var lPredictorList,lFileList:TStringList; var lDoublePtr: Pointer): boolean; function GetValCore (var lVALFilename:string; var lnSubj, lnFactors: integer; var lSymptomRA: singleP; var lImageNames: TStrings; var lCrit,lCritPct: integer; {lBinomial : boolean;} var lPredictorList: TStringList):boolean; implementation procedure MsgX (lStr: string); begin //output something here showmsg(lStr); end; function VALNativeSignature (lStr: string): boolean; var lP,lLen: integer; lVers: string; begin result := false; lLen := length(lStr); if lLen < (length(kVALNativeSignatureBase)+1) then exit; for lP := 1 to length(kVALNativeSignatureBase) do if lStr[lP] <> kVALNativeSignatureBase[lP] then exit; //VAL format, but can we read this version? for lP := (length(kVALNativeSignatureBase)+1) to lLen do lVers := lVers + lStr[lP]; if strtoint(lVers) <= kValMaxVers then result := true; end; function ReadTabStr (var lStr: string; var lPos: integer): string; var lLen: integer; begin result := ''; if lPos < 1 then lPos := 1; lLen := length(lStr); while (lPos <= lLen) and (lStr[lPos] <> kTab) do begin result := result + lStr[lPos]; inc(lPos); end; inc(lPos); end; function RowColPos (lRow,lCol,lnCol: integer): integer; begin result := ((lRow-1{alfa})*lnCol)+lCol; end; //Replicates Readln, but works for Unix files... Delphi 4's readln fails for non-MSDOS EOLs procedure ReadlnX (var F: TextFile; var lResult: string); var lCh: char; begin lResult := ''; while not Eof(F) do begin Read(F, lCh); if (lCh in [#10,#13]) then begin if lResult <> '' then begin //Showmessage(lResult); exit; end; end else lResult := lResult + lCh; end; end; //ReadlnX function OpenValFile (var lFilename,lTemplateName:string; var lnRow,lnCol,lnColwObs,lnCritPct: integer; var lDesignUnspecified : boolean; var lPredictorList,lFileList:TStringList; var lDoublePtr: Pointer): boolean; var lNumStr,lStr,lExt,lPrevNumStr,lCmdStr: string; F: TextFile; lTempFloat: double; lCh: char; lPos,MaxC,R,C:integer; lDoubleBuf: DoubleP; lError: boolean; lDecimalSep: char; begin lnRow := 0; lnCol := 0; result := false; if not fileexists(lFilename) then exit; lError:= false; lnCritPct := 0; lExt := StrLower(PChar(extractfileext(lFilename))); if (lExt = kTxtExt) or (lExt = kVALNativeExt) then else begin ShowMsg('This version is unable to recognize the extension of the file: '+lFilename); exit; end; lDecimalSep := DecimalSeparator; DecimalSeparator := '.'; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; if lExt = kVALNativeExt then begin ReadlnX(F,lStr);//Version if not VALNativeSignature(lStr) then begin showMsg('This software can not read this file. Perhaps you need to upgrade your software. The first line should read "'+kVALNativeSignatureBase+'x" where "x" is <'+inttostr(kValMaxVers+1)); CloseFile(F); FileMode := 2; //Set file access to read/write exit; end; lDesignUnspecified := false; lStr := '#'; while (length(lStr)> 0) and (lStr[1] = '#') and (not Eof(F)) do begin ReadlnX(F,lStr); lPos := 0; //start at beginning of line lCmdStr := ReadTabStr(lStr,lPos); if lCmdStr = '#Template' then lTemplateName := ReadTabStr(lStr,lPos); if lCmdStr = '#CritPct' then lnCritPct := StrToInt(ReadTabStr(lStr,lPos)); end; if (length(lStr)> 0) and (lStr[1] = '#') then showmsg(lCmdStr); end else begin lnCritPct := 0; lDesignUnspecified := true; lTemplateName := '-'; end;//Ext=native version Reset(F); while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9]) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); lnRow:= R; lnCol := MaxC-1; lnColWObs := lnCol+1; getmem(lDoublePtr,(lnRow*lnColWObs* sizeof(double))+16); {$IFDEF FPC} lDoubleBuf := align(lDoublePtr,16); {$ELSE} //lDoubleBuf := DoubleP((integer(lDoublePtr) and $FFFFFFF0)+16); lDoubleBuf := DoubleP($fffffff0 and (integer(lDoublePtr)+15)); {$ENDIF} for C := 1 to (lnRow*lnColWObs) do lDoubleBuf^[C] := 0; //Second pass: fill values Reset(F); C := 0; MaxC := 0; R := 1; lNumStr := ''; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9]) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin //read current entry if R = 1 then begin //1st Row if C > 0 then lPredictorList.Add( lNumStr) end else if C = 0 then begin //1st Row //showmessage(lNumStr); lFileList.Add( lNumStr) end else begin //note: below -1 as we strip first header row for predictor names if lNumStr = '-' then begin lDoubleBuf^[RowColPos (R-1{ july 06 alfa},C,lnColWObs)] := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmsg('Empty cells? Error reading VAL file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := knan; end; end; lDoubleBuf^[RowColPos (R-1{ july 06 alfa},C,lnColWObs)] := lTempFloat;//DataGrid.Cells[ C, kMaxFactors+R-1 ] := (lNumStr) ; end; end; lPrevNumStr := lNumStr; lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if (lNumStr <> '') and (C>0) then //alfa read data immediately prior to EOF lDoubleBuf^[RowColPos (R-1{alfa},C,lnColWObs)] := strtofloat(lNumStr); CloseFile(F); FileMode := 2; //Set file access to read/write result := true; DecimalSeparator := lDecimalSep; //fx(lPredictorList.Count,lnCol); if lPredictorList.Count < lnCol then begin for C := (lPredictorList.Count+1) to lnCol do lPredictorList.Add('Predictor'+inttostr(C)); end; end; function GetValCore (var lVALFilename:string; var lnSubj, lnFactors: integer; var lSymptomRA: singleP; var lImageNames: TStrings; var lCrit,lCritPct: integer; {lBinomial : boolean;} var lPredictorList: TStringList):boolean; //warning: you MUST free lPredictorList var lTemplateName: string; lnRow,lCol,lnColWObs,lInc,lRow: integer; lDesignUnspecified : boolean; lFileList:TStringList; lInRA: DoubleP0; lInP: Pointer; begin lPredictorList := TStringList.Create; result := false; lnSubj := 0; if not Fileexists(lVALFilename) then begin MsgX('NPM aborted: VAL file selection failed:' +lValFilename); exit; end; //if not selected lFileList := TStringList.Create; //MsgX( 'VAL filename: '+lVALFilename); if not OpenValFile (lVALFilename,lTemplateName, lnRow,lnFactors,lnColWObs,lCritPct, lDesignUnspecified,lPredictorList,lFileList, lInP) then exit; if lnRow > 1 then begin lnSubj := lnRow -1; //top row is predictor {$IFDEF FPC} lInRA := align(lInP,16); {$ELSE} lInRA := DoubleP0($fffffff0 and (integer(lInP)+15)); {$ENDIF} getmem(lSymptomRA,lnSubj*lnFactors* sizeof(single)); for lCol := 1 to lnFactors do begin for lRow := 1 to lnSubj do begin lSymptomRA^[lRow+ ((lCol-1)*lnSubj)] := lInRA^[(lRow*lnColWObs)-lnColWObs-1+lCol]; end; end; for lInc := 1 to lnSubj do lImageNames.add(ExtractFileDirWithPathDelim(lVALFilename)+lFileList.Strings[lInc-1]); //end reverse end; //for lRow = each subject lFileList.free; Freemem(lInP); lCrit := round( (lnSubj*lCritPct)/100); result := true; end; end. ���������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/npm.dpr��������������������������������������������������������0000755�0001750�0001750�00000001254�10772470554�016313� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������program npm; uses Forms, npmform in 'npmform.pas' {MainForm}, stats in 'stats.pas', spread in 'spread.pas' {SpreadForm}, design in 'design.pas' {DesignForm}, valformat in 'valformat.pas', ReadInt in 'ReadInt.pas' {ReadIntForm}, firth in 'firth.pas', roc in 'roc.pas', prefs in 'prefs.pas'; {$R *.RES} {$IFNDEF FPC} {$R windowsxp.res} {$ENDIF} begin Application.Initialize; Application.Title := 'NPM'; Application.CreateForm(TMainForm, MainForm); Application.CreateForm(TSpreadForm, SpreadForm); Application.CreateForm(TDesignForm, DesignForm); Application.CreateForm(TReadIntForm, ReadIntForm); Application.Run; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/unpm.pas�������������������������������������������������������0000755�0001750�0001750�00000171532�12306715072�016475� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit unpm; {$IFDEF FPC}{$mode objfpc}{$H+} {$ENDIF} {$Include ..\common\isgui.inc} interface uses upower,math,utypes, regmult,IniFiles,Classes, SysUtils , nifti_types, define_types,distr, statcr, StatThdsUtil, userdir, dialogsx, nifti_hdr, StatThds, lesion_pattern; Type TNPMPrefs = record NULP,ROI,ttest,BMtest: boolean; TFCE,PlankMB,nPermute: integer; end; procedure ComputePlankSize (var lPlankMB: integer); procedure InitPermute (lnSubj, lnPermute: integer; var lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP; var lRanOrderp: pointer; var lRanOrder: Doublep0); procedure NPMThreadDone; function reportBonferroni(lLabel: string; lnTests: integer): double; //returns 5% Z score function reportFDR (lLabel:string; lnVox, lnTests: integer; var lData: SingleP): double; function reportPermute (lLabel:string; lnPermute: integer; var lPermuteMaxZ, lPermuteMinZ: singleP): double; function ThreshMap(lThresh: single; lVolVox: integer;lOutImg: singleP): integer; procedure NPMMsgSave(lFilename: string); procedure NPMProgressBar(lPos: integer); procedure NPMmsg(str: string); procedure NPMMsgClear; function GetKVers: string; function ReportDescriptives (var RA: SingleP; n: integer): boolean; procedure FreePermute (lnPermute: integer; var lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP;var lRanOrderp: pointer); procedure ReadIniFile; procedure WriteIniFile; function Add2ndScans(var lImageNames: TStrings): boolean; function ChangeName (lInName: string): string; function NPMzscore (var lImages: TStrings; var lMnHdr,lStDevHdr: TMRIcroHdr): boolean; function NPMAnalyze (var lImages: TStrings; var lMaskname: string; lMaskVoxels,lnGroup1: integer; lNPMPrefs: TNPMPrefs; var lOutName: string): boolean; //function NPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lMaskVoxels,lnGroup1: integer; lNPMPrefs: TNPMPrefs; var lOutName: string): boolean; function ComputeLesionVolume (lImgName: string): integer; procedure Refresher; function MakeMean (lImages: TStrings; lBinarize,lVariance : boolean; lOutName: string): boolean; procedure NPMTitleMsg (S: string); //function MakeMean (var lImages: TStrings; lBinarize,lVariance : boolean; lOutName: string): boolean; function NPMAnalyzePaired (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lMaskVoxels: integer; lOutName: string): boolean; procedure NPMMultipleRegressClick(var lVALFilename, lMaskname,lOutname: string); procedure NPMSingleRegress (var lVALFilename, lMaskname,lOutname: string); function ComputeOverlap ( lROIname: string; var lLesionNames: TStrings; var lROIvol: double; lFracROIinjured: singlep): boolean; function Balance (var lImageName,lMaskName: String; {lInflection: boolean}lMethod: integer): boolean; function ReadPairedFilenames(var lImageNames: TStrings): boolean; var gNPMPrefs: TNPMPrefs; implementation uses {$IFDEF GUI}npmform,Forms,{$ENDIF} regression, valformat, firthThds,firth,hdr, prefs, nifti_img, tfce_clustering; {$IFNDEF GUI} var NPMmemo: TStringList; {$ENDIF} var gThreadsRunning: integer = 0; procedure NPMTitleMsg (S: string); begin MainForm.Caption := S; end; procedure NPMProgressBar(lPos: integer); begin {$IFDEF GUI} MainForm.ProgressBar1.Position := lPos; MainForm.Refresh; {$ENDIF} end; procedure NPMMsgClear; begin {$IFDEF GUI} MainForm.NPMMsgClearUI; {$ELSE} //shittt {$ENDIF} end; procedure NPMmsg(str: string); begin {$IFDEF GUI} MainForm.NPMmsgUI(str); {$ELSE} writeln(str); //shittt {$ENDIF} end; procedure NPMMsgSave(lFilename: string); var i: integer; f: textfile; begin {$IFDEF GUI} MainForm.NPMmsgSaveUI(lFilename); {$ELSE} ShowMsg('SHITTTT'); {$ENDIF} end; function GetKVers: string; begin result := 'Chris Rorden''s NPM '+kMRIcronVers+' :: '+inttostr(sizeof(integer)*8)+'-bit :: Threads used = '+inttostr(gnCPUThreads )+' :: plankSize = '+inttostr(gNPMPrefs.PlankMB)+'mb'; end; procedure Refresher; begin {$IFDEF GUI} Application.processmessages; MainForm.Refresh; {$ENDIF} end; function ReadPairedFilenames(var lImageNames: TStrings): boolean; var lLen,lPos: integer; lFilenames,lF1,lF2: string; lImageNames2: TStrings; lF: TextFile; begin result := false; ShowMsg('Please select a text file with the image names. '+kCR+ 'Each line of the file should specify the control and experimental filenames, separated by an *'+kCR+ 'C:\vbmdata\c1.nii.gz*C:\vbmdata\e1.nii.gz'+kCR + 'C:\vbmdata\c2.nii.gz*C:\vbmdata\e2.nii.gz'+kCR+ 'C:\vbmdata\c3.nii.gz*C:\vbmdata\e3.nii.gz'+kCR+ '...' ); (*SHITTT if not MainForm.OpenDialogExecute('Select asterix separated filenames ',false,false,kTxtFilter) then exit; lImageNames2:= TStringList.Create; //not sure why TStrings.Create does not work??? //xxx assignfile(lF,MainForm.OpenHdrDlg.FileName ); *) FileMode := 0; //read only reset(lF); while not EOF(lF) do begin readln(lF,lFilenames); lLen := length(lFilenames); if lLen > 0 then begin lF1:= ''; lF2 := ''; lPos := 1; while (lPos <= lLen) and (lFilenames[lPos] <> '*') do begin lF1 := lF1 + lFilenames[lPos]; inc(lPos); end; inc(lPos); while (lPos <= lLen) do begin lF2 := lF2 + lFilenames[lPos]; inc(lPos); end; if (length(lF1) > 0) and (length(lF2)>0) then begin if Fileexists4D(lF1) then begin if Fileexists4D(lF2) then begin lImageNames.add(lF1); lImageNames2.add(lF2); end else //F2exists ShowMsg('Can not find image '+lF2); end else //F1 exists ShowMsg('Can not find image '+lF1); end; end;//len>0 end; //while not EOF closefile(lF); FileMode := 2; //read/write if (lImageNames.count > 0) and (lImageNames2.count = lImageNames.count) then begin lImageNames.AddStrings(lImageNames2); result := true; end; lImageNames2.Free; end; function MinMax (var lImg: SingleP; var lVolVox: integer; var lMin, lMax: single): boolean; var lC: integer; begin result := false; if lVolVox < 1 then exit; lMax := lImg^[1]; for lC := 1 to lVolVox do if lImg^[lC] > lMax then lMax := lImg^[lC]; //lCx := lC; lMin := lImg^[1]; for lC := 1 to lVolVox do if lImg^[lC] < lMin then lMin := lImg^[lC]; result := true; end; function DetectMode (var lImg: SingleP; var lVolVox: integer; var lMin, lMax, lModeLo,lModeHi: single; lInflection: boolean): boolean; const kHistoBins = 255;//numbers of bins for histogram/image balance var lSmooth,lPrevSmooth,lModeWid,lC,lMinPos,lMode,lModePos,lMaxModePos,lMode2NotInflection: integer; lMod,lRng: single; lHisto : array [0..kHistoBins] of longint; begin result := false; if (lVolVox < 1) or (lMax < lMin) then exit; //zero array for lC := 1 to kHistoBins do lHisto[lC] := 0; //find scaling lRng := abs(lMax-lMin); if lRng > 0 then lMod := (kHistoBins)/lRng else lMod := 0; //fill histogram for lC := 1 to lVolVox do if lImg^[lC] <> 0 then inc(lHisto[round((lImg^[lC]-lMin)*lMod)]); {for lC := 1 to lVolVox do inc(lHisto[round((lImg^[lC]-lMin)*lMod)]); } //smooth histogram lPrevSmooth := lHisto[1]; for lC := 2 to (kHistoBins-1) do begin lSmooth := round( (lHisto[lC-1]+lHisto[lC]+lHisto[lC]+lHisto[lC+1])/4); lHisto[lC-1] := lPrevSmooth; lPrevSmooth := lSmooth; end; lHisto[kHistoBins-1] := lPrevSmooth; //find mode lMode := 0; lMinPos := 1;//indexed from zero //find highest peak for lC := lMinPos to kHistoBins do begin if lHisto[lC] > lMode then begin lModePos := lC; lMode := lHisto[lC]; end;//if new mode end; //for each bin if lMode > 0 then lMaxModePos := lModePos else exit; //find 2nd highest peak //find 2nd highest peak lModeWid := 25; lModePos := lMinPos; lMode := lHisto[lMinPos]; if (lMaxModePos - lModeWid) > lMinPos then begin for lC := lMinPos to (lMaxModePos - lModeWid) do begin if lHisto[lC] > lMode then begin lModePos := lC; lMode := lHisto[lC]; end;//if new mode end; //for each bin end; //check below highest peak if (lMaxModePos + lModeWid) < kHistoBins then begin for lC := (lMaxModePos + lModeWid) to kHistoBins do begin if lHisto[lC] > lMode then begin lModePos := lC; lMode := lHisto[lC]; end;//if new mode end; //for each bin end; //check above highest peak //fx(lModePos); //an alternative method to find mode is to look for inflection - less assumptions, more sensitive to noise if lInflection then begin lMode2NotInflection := lModePos; lModePos := lMinPos; lMode := 0; lC := lMaxModePos; while ((lC-1) > lMinPos) and (lHisto[lC] > lHisto[lC-1]) do dec(lC); //find inflection while ((lC-1) > lMinPos) do begin dec(lC); if lHisto[lC] > lMode then begin lModePos := lC; lMode := lHisto[lC]; end;//if new mode end; //look for mode lC := lMaxModePos; while ((lC+1) <= kHistoBins) and (lHisto[lC] > lHisto[lC+1]) do inc(lC); //find inflection while ((lC+1) <= kHistoBins) do begin inc(lC); if lHisto[lC] > lMode then begin lModePos := lC; lMode := lHisto[lC]; end;//if new mode end; //look for mode if abs(lMode2NotInflection-lModePos) > 3 then ShowMsg('Warning: inflection and windowed algorithms find different 2nd modes. Using inflection 2nd mode. inflection ='+inttostr(lModePos)+' windowed: '+inttostr(lMode2NotInflection)); end; //now, return scaled values... if lMod = 0 then exit; lModeLo := (lModePos/lMod)+lMin; lModeHi := (lMaxModePos/lMod)+lMin; if lModeLo > lModeHi then begin lMod := lModeLo; lModeLo := lModeHi; lModeHi := lMod; end; result := true; end; function DetectMeanStDev (var lImg: SingleP; var lVolVox: integer; var lMean,lStDev: double): boolean; var lIncVox,lVox: integer; lSum,lSumSqr,lSE: double; begin lMean := 0; lStDev := 0; result := false; if (lVolVox < 1) then exit; lSum := 0; lSumSqr := 0; lIncVox := 0; //voxels included - e.g. not masked for lVox := 1 to lVolVox do begin if lImg^[lVox] <> 0 then begin //not in mask inc(lIncVox); lSum := lSum + lImg^[lVox]; lSumSqr := lSumSqr + sqr(lImg^[lVox]); end; end; if lincVox < 3 then exit; Descriptive (lincVox, lSumSqr, lSum,lMean,lStDev,lSE); result := true; end; //DetectMeanStDev function Balance (var lImageName,lMaskName: String; {lInflection: boolean}lMethod: integer): boolean; //0 = masked peak //1 = inflection //2 = mean =1, stdev=1 var lImg,lMaskImg: SingleP; lHdr,lMaskHdr: TMRIcroHdr; lVolVox,lVox,lMasked: integer; lMaskedInten,lMean,lStDev: double; lMin,lMax: single; lModeLo,lModeHi,lIntercept,lSlope: single; lOutNameMod: string; begin //lOutName := lMaskHdr.ImgFileName; result := false; //if not SaveHdrName ('Statistical Map', lOutName) then exit; if not NIFTIhdr_LoadHdr(lImageName,lHdr) then begin ShowMsg('Error reading '+lImageName); exit; end; lVolVox := lHdr.NIFTIhdr.dim[1]*lHdr.NIFTIhdr.dim[2]* lHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then exit; getmem(lImg,lVolVox*sizeof(single)); if not LoadImg(lHdr.ImgFileName, lImg, 1, lVolVox,round(lHdr.NIFTIhdr.vox_offset),1,lHdr.NIFTIhdr.datatype,lVolVox) then begin NPMMsg('Unable to load ' +lHdr.ImgFileName); exit; end; if lMaskName <> '' then begin if not NIFTIhdr_LoadHdr(lMaskName,lMaskHdr) then begin ShowMsg('Error reading '+lMaskName); exit; end; if lVolVox <> (lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]) then begin ShowMsg('Mask and header must have identical dimensions '+lMaskName+ ' ' + lImageName); exit; end; getmem(lMaskImg,lVolVox*sizeof(single)); if not LoadImg(lMaskHdr.ImgFileName, lMaskImg, 1, lVolVox,round(lMaskHdr.NIFTIhdr.vox_offset),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin NPMMsg('Unable to load mask ' +lMaskHdr.ImgFileName); exit; end; lMasked := 0; lMaskedInten := 0; for lVox := 1 to lVolVox do if lMaskImg^[lVox] = 0 then begin lMaskedInten := lMaskedInten + lImg^[lVox]; lImg^[lVox] := 0; inc(lMasked); end; if lMasked < 1 then NPMMsg('Warning: no voxels masked with image '+lMaskName) else NPMMsg('Mask='+ lMaskName+' Number of voxels masked= '+inttostr(lMasked)+' Mean unscaled intensity of masked voxels= '+floattostr(lMaskedInten/lMasked)); freemem(lMaskImg); end;//mask if not MinMax(lImg,lVolVox,lMin,lMax) then exit; NPMMsg(lImageName+' -> '+lHdr.ImgFileName); NPMMsg('min..max ' +floattostr(lMin)+'..'+floattostr(lMax)); if (lMethod = 0) or (lMethod = 1) then begin if not DetectMode(lImg,lVolVox,lMin,lMax,lModeLo,lModeHi, odd(lMethod)) then exit; if odd(lMethod) then NPMMsg('method for finding second mode: inflection') else NPMMsg('method for finding second mode: masked peak'); NPMMsg('modes Lo Hi ' +floattostr(lModeLo)+'..'+floattostr(lModeHi)); if lModeLo >= lModeHi then exit; lSlope := 1/abs(lModeHi-lModeLo); lIntercept := (abs(lModeHi-lModeLo)-(lModeLo))*lSlope ; //make mode lo = 1; end else begin DetectMeanStDev (lImg, lVolVox, lMean,lStDev); if lStDev <>0 then lSlope := 1/lStDev else begin NPMMsg('Warning: StDev = 0!!!!'); lSlope := 1; end; lIntercept := (-lMean*lSlope)+2; //mean voxel has intensity of zero NPMMsg('method for intensity normalization: Mean = 2, StDev = 1'); NPMMsg('raw_Mean = '+floattostr(lMean)+' '+' raw_StDev = '+floattostr(lStDev)); end; NPMMsg('Slope/Intercept ' +floattostr(lSlope)+'..'+floattostr(lIntercept)); lHdr.NIFTIhdr.scl_slope := lSlope; lHdr.NIFTIhdr.scl_inter := lIntercept; //CopyFileEX(lHdr.HdrFilename,changefileext( lHdr.HdrFilename,'.hdx')); RenameFile(lHdr.HdrFilename,changefileext( lHdr.HdrFilename,'.hdx')); //optional - save input lOutNameMod := ChangeFilePrefixExt(lImageName,'i','.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lHdr.NIFTIhdr,true,not IsNifTiMagic(lHdr.NIFTIhdr),true,lImg,1); //end optional NIFTIhdr_SaveHdr(lHdr.HdrFilename,lHdr.NIFTIhdr,true,not IsNifTiMagic(lHdr.NIFTIhdr)); freemem(lImg); end; function ComputeOverlap ( lROIname: string; var lLesionNames: TStrings; var lROIvol: double; lFracROIinjured: singlep): boolean; label 667; var lName: string; lSum: double; lLesion,lnLesions,lVolVox,lVolVoxA,lVox: integer; lROIImg,lImgB: SingleP; lMaskHdr: TMRIcroHdr; begin lROIvol := 0; result := false; lnLesions := lLesionNames.count; if lnLesions < 1 then begin ShowMsg('Error: no lesion names'); exit; end; for lLesion := 1 to lnLesions do lFracROIinjured^[lLesion] := 0; //read A if not NIFTIhdr_LoadHdr(lROIname,lMaskHdr) then begin ShowMsg('Error reading ROI - '+lROIname); exit; end; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then begin ShowMsg('Error with Mask voxels ' + inttostr(lVolVox)); exit; end; if not CheckVoxelsGroupX(lLesionNames, lMaskHdr) then begin ShowMsg('Error image dimensions vary.'); exit; end; getmem(lROIImg,lVolVox*sizeof(single)); getmem(lImgB,lVolVox*sizeof(single)); if not LoadImg(lROIname, lROIImg, 1, lVolVox,round(lMaskHdr.NIFTIhdr.vox_offset),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin NPMmsg('Unable to load lesion ' +lMaskHdr.ImgFileName); goto 667; end; lVolVoxA := lVolVox; for lVox := 1 to lVolVox do if (lROIImg^[lVox] > 0) then lROIvol := lROIvol +lROIImg^[lVox]; //read Lesion if lROIvol < 1 then begin NPMmsg('ROI volume < 1'); goto 667; end; //for each lesion //NPMmsg('Compute overlap started '+inttostr(lnLesions)+' '+floattostr(lROIvol)+' '+inttostr(lVolVoxA)); NPMProgressBar( 0); for lLesion := 1 to lnLesions do begin NPMProgressBar(round((lLesion/lnLesions)*100)) ; lSum := 0; lName := lLesionNames.Strings[lLesion-1]; if not NIFTIhdr_LoadHdr(lName,lMaskHdr) then begin ShowMsg('Error reading lesion - '+lName); exit; end; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVoxA <> lVolVox) or (lVolVox < 1) then begin NPMmsg('Volume does not have expected number of voxels ' +lMaskHdr.ImgFileName +'<>'+lROIname+ ' found ' +inttostr(lVolVox)+' expected '+inttostr(lVolVoxA)); goto 667; end; if not LoadImg(lName, lImgB, 1, lVolVox,round(lMaskHdr.NIFTIhdr.vox_offset),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin NPMmsg('Unable to load mask ' +lMaskHdr.ImgFileName); goto 667; end; for lVox := 1 to lVolVox do begin //if {(lImgB^[lVox] <> 0) and} (lROIImg^[lVox] <> 0) then fx(lROIImg^[lVox]); if (lROIImg^[lVox] > 0) and (lImgB^[lVox] <> 0) then lSum := lSum + lROIImg^[lVox]; end; lFracROIinjured^[lLesion] := lSum/lROIvol; end;//for each lesion result := true; NPMProgressBar( 0); (*for lLesion := 1 to lnLesions do begin if lFracROIinjured^[lLesion] > 0 then fx( lFracROIinjured^[lLesion], lLesion); end; *) 667: freemem(lImgB); freemem(lROIImg); end; procedure NPMSingleRegress (var lVALFilename, lMaskname,lOutname: string); label 666; var lnSubj1,lnFactors,lnSubj,lMaskVoxels,lRow,lCol: integer; lImageNames,lImageNames1: TStrings; lPredictorList,lPredictorList1: TStringList; lTemp4D: string; lMaskHdr: TMRIcroHdr; X,X1 : PMatrix; begin lTemp4D := ''; lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? lPredictorList := TStringList.Create; lPredictorList1 := TStringList.Create; if not GetValReg(lVALFilename,lnSubj,lnFactors,X,lImageNames,lPredictorList) then goto 666; if (length(lMaskname) < 1) then lMaskName := lImageNames[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin ShowMsg('Error reading mask image.'); exit; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,-1)){make sure there is uncompressed .img file} then begin ShowMsg('Mask file size too small.'); goto 666; end; if not CheckVoxelsGroupX(lImageNames,lMaskHdr{lMaskVoxels}) then begin ShowMsg('File dimensions differ from mask.'); goto 666; end; lTemp4D := CreateDecompressed4D(lImageNames); lImageNames1:= TStringList.Create; for lCol := 1 to lnFactors do begin lPredictorList1.Clear; lPredictorList1.Add(lPredictorList[lCol-1]); lImageNames1.clear; for lRow := 1 to lnSubj do if X^[lCol]^[lRow] <> kNaN then lImageNames1.Add(lImageNames[lRow-1]); DimMatrix(X1, 1, lImageNames1.Count); lnSubj1 := 0; for lRow := 1 to lnSubj do if X^[lCol]^[lRow] <> kNaN then begin inc(lnSubj1); X1^[1]^[lnSubj1] := X^[lCol]^[lRow]; end; if lnSubj1 <> lImageNames1.Count then //should be impossible ShowMsg('NPMSingleRegress: serious error - number of participants does not match'); NPMMsgClear; NPMMsg(GetKVers); NPMMsg('Single Linear Regression [Weighted Least Squares]'); NPMMsg('Mask = '+lMaskname); NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); NPMMsg('Number of observations = '+inttostr(lnSubj1)); NPMMsg('Image,'+ lPredictorList1.Strings[0]); for lRow := 1 to lnSubj1 do NPMMsg(lImageNames1[lRow-1]+','+floattostr(X1^[1]^[lRow]) ) ; ARegressNPMAnalyze(lImageNames1,lMaskHdr,X1,1,lPredictorList1,lOutName, gNPMPrefs.nPermute,gNPMPrefs.TFCE); //PermuteRegressNPMAnalyze (lImageNames1,lMaskHdr,X1,1,lPredictorList1,lOutName); DelMatrix(X1, 1, lnSubj1); end; lImageNames1.Free; DelMatrix(X, lnFactors, lnSubj); 666: DeleteDecompressed4D(lTemp4D); lImageNames.Free; lPredictorList.Free; lPredictorList1.Free; end; procedure NPMMultipleRegressClick(var lVALFilename, lMaskname,lOutname: string); label 666; var lnFactors,lnSubj,lMaskVoxels,lRow,lCol: integer; lImageNames: TStrings; lPredictorList: TStringList; lTemp4D,lStr: string; lMaskHdr: TMRIcroHdr; X : PMatrix; begin lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? lPredictorList := TStringList.Create; NPMMsgClear; NPMMsg(GetKVers); NPMMsg('Multiple Linear Regression [Weighted Least Squares]'); if not GetValReg(lVALFilename,lnSubj,lnFactors,X,lImageNames,lPredictorList) then goto 666; lTemp4D := CreateDecompressed4D(lImageNames); //lMaskname := lImageNames[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin ShowMsg('Error reading 1st image.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,-1)){make sure there is uncompressed .img file} then begin ShowMsg('Mask file size too small.'); goto 666; end; NPMMsg('Mask = '+lMaskname); NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); NPMMsg('Number of observations = '+inttostr(lnSubj)); if not CheckVoxelsGroupX(lImageNames,lMaskHdr {lMaskVoxels}) then begin ShowMsg('File dimensions differ from mask.'); goto 666; end; //show matrix lStr := 'Image,'; for lCol := 1 to lnFactors do lStr := lStr + lPredictorList.Strings[lCol-1]+', '; NPMmsg(lStr); for lRow := 1 to lnSubj do begin lStr := lImageNames[lRow-1]+','; for lCol := 1 to lnFactors do lStr := lStr + floattostr(X^[lCol]^[lRow])+', '; NPMmsg(lStr); end; ARegressNPMAnalyze(lImageNames,lMaskHdr,X,lnFactors,lPredictorList,lOutName,0,0); DelMatrix(X, lnFactors, lnSubj); 666: lImageNames.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); end; function NPMAnalyzePaired (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lMaskVoxels: integer; lOutName: string): boolean; label 667; var //lOutName, lOutNameMod: string; lMaskImg,lPlankImg,lOutImgMn,lOutImgT,lDummy,lDummy2: SingleP; lTotalMemory: double; //not integer - limit for 32bit int is 2Gb lPlank,lVolVox,lPos,lMinMask,lMaxMask,lnPlanks,lVoxPerPlank, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lThreadStart,lThreadEnd,lThreadInc: integer; lT, lSum, lMn: double; lStatHdr: TNIfTIhdr; lFdata: file; lThread,lnPermute: integer; lPermuteMaxT, lPermuteMinT: singleP; lRanOrderp: pointer; lRanOrder: Doublep0; begin //lnPermute := ReadPermute; lnPermute := 0;//not yet NPMmsg('Permutations = ' +IntToStr(lnPermute)); NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; //load mask getmem(lMaskImg,lVolVox*sizeof(single)); if not LoadImg(lMaskHdr.ImgFileName, lMaskImg, 1, lVolVox,round(gOffsetRA[0]),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin NPMmsg('Unable to load mask ' +lMaskHdr.ImgFileName); goto 667; end; //next find start and end of mask lPos := 0; repeat inc(lPos); until (lMaskImg^[lPos] > 0) or (lPos = lVolVox); lMinMask := lPos; lPos := lVolVox+1; repeat dec(lPos); until (lMaskImg^[lPos] > 0) or (lPos = 1); lMaxMask := lPos; if lMaxMask = 1 then begin NPMmsg('Mask appears empty' +lMaskHdr.ImgFileName); goto 667; end; NPMmsg('Mask has voxels from '+inttostr(lMinMask)+'..'+inttostr(lMaxMask)); lVoxPerPlank := kPlankSz div lImages.Count div sizeof(single) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; getmem(lOutImgMn,lVolVox* sizeof(single)); getmem(lOutImgT,lVolVox* sizeof(single)); //not yet InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgMn^[lPos] := 0; lOutImgT^[lPos] := 0; end; ClearThreadData(gnCPUThreads,lnPermute); for lPlank := 1 to lnPlanks do begin NPMmsg('Computing plank = ' +Inttostr(lPlank)); Refresher; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start (**SHITTTT lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TPairedTStat.Create (ProgressBar1,false,false,0, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,666, lMaskImg,lPlankImg,lOutImgMn,lDummy2,lOutImgT,lDummy) do {$IFDEF FPC} OnTerminate := @ThreadDone; {$ELSE}OnTerminate := ThreadDone;{$ENDIF} inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; *) //threading end lStartVox := lEndVox + 1; end; lnVoxTested := SumThreadDataLite(gnCPUThreads);//not yet SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //next report findings NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); reportBonferroni('Std',lnVoxTested); //next: save data (*savedata *) MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save mean lOutNameMod := ChangeFilePostfixExt(lOutName,'Mean','.hdr'); if lnVoxTested > 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgMn,1); MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lnVoxTestED > 1 ) then begin //save Ttest //next: convert t-scores to z scores for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],(lImages.Count div 2)-1); for lPos := 1 to lnPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); reportPermute('ttest',lnPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'ttest','.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; //next: close images //not yet FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgT); freemem(lOutImgMn); //freemem(lObsp); freemem(lMaskImg); freemem(lPlankImg); NPMmsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes','.txt'); NPMMsgSave(lOutNameMod); NPMProgressBar(0); exit; 667: //you only get here if you aborted ... free memory and report error if lVolVox > 1 then freemem(lMaskImg); if lTotalMemory > 1 then freemem(lPlankImg); NPMmsg('Unable to complete analysis.'); NPMProgressBar(0); end; (*function ApplyTFCE (lImageName: string): boolean; var lImg: SingleP; lHdr: TMRIcroHdr; lVolVox: integer; maxTFCE, maxNegTFCE: single; lOutNameMod: string; begin result := false; if not NIFTIhdr_LoadHdr(lImageName,lHdr) then begin ShowMsg('Error reading '+lImageName); exit; end; lVolVox := lHdr.NIFTIhdr.dim[1]*lHdr.NIFTIhdr.dim[2]* lHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then exit; getmem(lImg,lVolVox*sizeof(single)); if not LoadImg(lHdr.ImgFileName, lImg, 1, lVolVox,round(lHdr.NIFTIhdr.vox_offset),1,lHdr.NIFTIhdr.datatype,lVolVox) then begin NPMMsg('Unable to load ' +lHdr.ImgFileName); exit; end; //lHdr.NIFTIhdr.scl_slope := 1; lHdr.NIFTIhdr.scl_inter := 0; doTFCEbothPolarities (lHdr.NIFTIhdr, lImg, 6 {NumConn}, 2.0 {H}, 0.5 { E}, 0, 0,0,0 ,maxTFCE, maxNegTFCE); lOutNameMod := ChangeFilePrefixExt(lImageName,'i','.hdr'); NPMMsg('Creating ' +lOutNameMod); NIFTIhdr_SaveHdrImg(lOutNameMod,lHdr.NIFTIhdr,true,not IsNifTiMagic(lHdr.NIFTIhdr),true,lImg,1); freemem(lImg); end;*) function MakeMean ( lImages: TStrings; lBinarize,lVariance : boolean; lOutName: string): boolean; label 667; var lMaskname,lOutNameMod: string; lMaskHdr: TMRIcroHdr; lCountRA,lOutImgMn,lOutStDev,lPlankImg: SingleP; lTotalMemory: double; lMaskVoxels,lPlank,lVolVox,lPos,lMinMask,lMaxMask,lnPlanks,lVoxPerPlank, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: integer; lStDev: boolean; lT, lSum,lSumSqr,lSD, lMn,lTotalSum,lTotalN: double; lStatHdr: TNIfTIhdr; lFdata: file; begin if lImages.count < 2 then begin ShowMsg('Error: you must select at least two images'); exit; end; lMaskname := lImages[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin ShowMsg('Error reading '+lMaskName); exit; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if not CheckVoxelsGroupX(lImages,lMaskHdr {lMaskVoxels}) then begin ShowMsg('File dimensions differ from mask.'); exit; end; result := false; NPMMsgClear; NPMMsg(GetKVers); if (not lVariance) and (not lBinarize) then lStDev := true else lStDev := false; NPMMsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; NPMMsg('Voxels = '+inttostr(lMaskVoxels)+' '+inttostr(kPlankSz)); if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(single) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; NPMMsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); NPMMsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); // fx(kPlankSz,8888); getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; NPMMsg('Number of scans = '+inttostr(lImages.count)); NPMMsg(' Index,Filename,Intercept,Slope'); if lBinarize then begin getmem(lCountRA,lImages.Count*sizeof(single)); for lPos := 1 to lImages.Count do begin gInterceptRA[lPos] := 0; gScaleRA[lPos] := 1; lCountRA^[lPos] := 0; end; end else begin for lPos := 1 to lImages.Count do begin NPMMsg(' '+inttostr(lPos)+','+lImages[lPos-1]+','+realtostr(gInterceptRA[lPos],4)+','+realtostr(gScaleRA[lPos],4)); if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; end; end; lTotalSum := 0; lTotalN := 0; //createArray64(lObsp,lObs,lImages.Count); getmem(lOutImgMn,lVolVox* sizeof(single)); if lStDev then getmem(lOutStDev,lVolVox* sizeof(single)); for lPlank := 1 to lnPlanks do begin NPMMsg('Computing plank = ' +Inttostr(lPlank)); Refresher; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image lPosPct := lVoxPerPlank div 100; for lPos2 := 1 to lVoxPerPlank do begin if (lPos2 mod lPosPct) = 0 then begin NPMProgressBar(round((lPos2/lVoxPerPlank)*100)); refresher; end; lPos2Offset := lPos2+lStartVox-1; lSum := 0; if lVariance then begin lSum := sqr(lPlankImg^[lPos2]-lPlankImg^[lVoxPerPlank+lPos2]);//actually variance... //% signal //if lPlankImg[lVoxPerPlank+lPos2] <> 0 then // lSum := lPlankImg[lPos2]/lPlankImg[lVoxPerPlank+lPos2] //else // lSum := 0;//pct signal... //end % signal lOutImgMn^[lPos2Offset] := lSum; lTotalSum := lTotalSum + lOutImgMn^[lPos2Offset]; lTotalN := lTotalN + 1; end else begin //not variance if lBinarize then begin for lPos := 1 to lImages.Count do if lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2] <> 0 then begin lSum := lSum+1; lCountRA^[lPos] := lCountRA^[lPos] + 1; end; end else for lPos := 1 to lImages.Count do lSum := lSum +(gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; // fx(lPos, gScaleRA[lPos],gInterceptRA[lPos]); lOutImgMn^[lPos2Offset] := lSum/lImages.Count; if lStDev then begin //lSum := 0; //for lPos := 1 to lImages.Count do // lSum := lSum + (gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; lSumSqr := 0; for lPos := 1 to lImages.Count do lSumSqr := lSumSqr + Sqr((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]); lSD := (lSumSqr - ((Sqr(lSum))/lImages.Count)); if (lSD > 0) then lSD := Sqrt ( lSD/(lImages.Count-1)) else begin lSD := 0; end; lOutStDev^[lPos2Offset] := lSD; end; end; //not variance if lSum > 0 then begin lTotalSum := lTotalSum + lOutImgMn^[lPos2Offset]; lTotalN := lTotalN + 1; end; end; lStartVox := lEndVox + 1; end; if lBinarize then begin for lPos := 1 to lImages.Count do begin NPMMsg(' '+inttostr(lPos)+','+lImages[lPos-1]+','+inttostr(round(lCountRA^[lPos])) ); lCountRA^[lPos] := 0; end; freemem(lCountRA); end; //if binar //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save mean if lVariance then lOutNameMod := ChangeFilePostfixExt(lOutName,'var','.hdr') else lOutNameMod := ChangeFilePostfixExt(lOutName,'Mean','.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgMn,1); freemem(lOutImgMn); if lStDev then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'StDev','.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutStDev,1); freemem(lOutStDev); end; //freemem(lObsp); freemem(lPlankImg); NPMMsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes','.txt'); NPMMsgSave(lOutNameMod); if (lTotalN > 0) then NPMMsg('num voxels >0 = ' +inttostr(round(lTotalN))+' mean value for voxels >0: '+floattostr(lTotalSum/lTotalN)); NPMProgressBar(0); exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); NPMMsg('Unable to complete analysis.'); NPMProgressBar(0); end; function ComputeLesionVolume (lImgName: string): integer; var lHdr: TMRIcroHdr; lImg: byteP; lVolVox,lVox:integer; begin result := -1; //error NIFTIhdr_LoadHdr(lImgName,lHdr); lVolVox := lHdr.NIFTIhdr.dim[1]*lHdr.NIFTIhdr.dim[2]* lHdr.NIFTIhdr.dim[3]; getmem(lImg,lVolVox*sizeof(byte)); if not LoadImg8(lImgName, lImg, 1, lVolVox,round(lHdr.NIFTIhdr.vox_offset),1,lHdr.NIFTIhdr.datatype,lVolVox) then begin NPMMsg('Unable to load ' +lHdr.ImgFileName); freemem(lImg); exit; end; result := 0; for lVox := 1 to lVolVox do if (lImg^[lVox] <> 0) then inc(result); freemem(lImg); end; function NPMAnalyze (var lImages: TStrings; var lMaskname: string; lMaskVoxels,lnGroup1: integer; lNPMPrefs: TNPMPrefs; var lOutName: string): boolean; label 667; var //lOutName, lOutNameMod: string; lMaskHdr: TMRIcroHdr; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lDummy: SingleP; lTotalMemory: double; //not integer - limit for 32bit int is 2Gb lPlank,lVolVox,lPos,lMinMask,lMaxMask,lnPlanks,lVoxPerPlank, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lThreadStart,lThreadEnd,lThreadInc: integer; lT, lSum, lMn: double; lStatHdr: TNIfTIhdr; lFdata: file; lThread: integer; lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP; lRanOrderp: pointer; lRanOrder: Doublep0; begin result := false; NPMMsgClear; NPMMsg(GetKVers); NPMMsg('Threads: '+inttostr(gnCPUThreads)); NPMMsg('Mask name = '+ lMaskname); NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); NPMMsg('Scans in Group 1 = '+inttostr(lnGroup1)); NPMMsg('Scans in Group 2 = '+inttostr(lImages.count-lnGroup1)); if (lnGroup1 < 1) or ((lImages.count-lnGroup1) < 1) then begin ShowMsg('Error: group size(s) too small'); exit; end; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showMsg('Error reading mask.'); exit; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin ShowMsg('Mask file size too small.'); exit; end; if not CheckVoxelsGroupX(lImages,lMaskHdr ) then begin ShowMsg('File dimensions differ from mask.'); exit; end; NPMmsg('Permutations = ' +IntToStr(lNPMPrefs.nPermute)); NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; //load mask getmem(lMaskImg,lVolVox*sizeof(single)); if not LoadImg(lMaskHdr.ImgFileName, lMaskImg, 1, lVolVox,round(gOffsetRA[0]),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin NPMmsg('Unable to load mask ' +lMaskHdr.ImgFileName); goto 667; end; //next find start and end of mask lPos := 0; repeat inc(lPos); until (lMaskImg^[lPos] > 0) or (lPos = lVolVox); lMinMask := lPos; lPos := lVolVox+1; repeat dec(lPos); until (lMaskImg^[lPos] > 0) or (lPos = 1); lMaxMask := lPos; if lMaxMask = 1 then begin NPMmsg('Mask appears empty' +lMaskHdr.ImgFileName); goto 667; end; NPMmsg('Mask has voxels from '+inttostr(lMinMask)+'..'+inttostr(lMaxMask)); lVoxPerPlank := kPlankSz div lImages.Count div sizeof(single) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; getmem(lOutImgMn,lVolVox* sizeof(single)); getmem(lOutImgBM,lVolVox* sizeof(single)); getmem(lOutImgT,lVolVox* sizeof(single)); InitPermute (lImages.Count, lNPMPrefs.nPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgMn^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; end; ClearThreadData(gnCPUThreads,lNPMPrefs.nPermute); for lPlank := 1 to lnPlanks do begin NPMmsg('Computing plank = ' +Inttostr(lPlank)); Refresher; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; (*SHITTTT Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TNNStat.Create (ProgressBar1,lttest,lBM,0, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lnGroup1, lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lDummy) do {$IFDEF FPC} OnTerminate := @ThreadDone; {$ELSE}OnTerminate := ThreadDone;{$ENDIF} inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; *) //threading end lStartVox := lEndVox + 1; end; lnVoxTested := SumThreadData(gnCPUThreads,lNPMPrefs.nPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //next report findings NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); reportBonferroni('Std',lnVoxTested); //next: save data (*savedata*) MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save mean lOutNameMod := ChangeFilePostfixExt(lOutName,'Mean','.hdr'); if lnVoxTested > 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgMn,1); MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lNPMPrefs.ttest) and (lnVoxTestED > 1 ) then begin //save Ttest //reportRange ('ttest', lVolVox, lnVoxTested, lOutImgT); //next: convert t-scores to z scores for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lNPMPrefs.nPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); reportPermute('ttest',lNPMPrefs.nPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'ttest','.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if (lNPMPrefs.BMtest) and (lnVoxTested > 1 ) then begin //save Brunner Munzel reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); reportPermute('BM',lNPMPrefs.nPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'BM','.hdr'); {reportFDR ('absT', lVolVox, lnVoxTested, lOutImgBM); reportPermute('absT',lnPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'absT','.hdr'); } //NIFTIhdr_SaveHdr(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr)); lOutNameMod := changefileext(lOutNameMod,'.img'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end;(**) //next: close images FreePermute (lNPMPrefs.nPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgT); freemem(lOutImgBM); freemem(lOutImgMn); //freemem(lObsp); freemem(lMaskImg); freemem(lPlankImg); NPMmsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes','.txt'); NPMMsgSave(lOutNameMod); NPMProgressBar(0); result := true; exit; 667: //you only get here if you aborted ... free memory and report error if lVolVox > 1 then freemem(lMaskImg); if lTotalMemory > 1 then freemem(lPlankImg); NPMmsg('Unable to complete analysis.'); NPMProgressBar(0); end; (*procedure MakeStatHdr (var lBGHdr,lStatHdr: TniftiHdr; lMinIntensity,lMaxIntensity,lIntent_p1,lIntent_p2,lIntent_p3: single; lIntent_code: smallint;lIntentName: string); var lIntentNameLen,lPos: integer; lStr: string; begin move(lBGHdr,lStatHdr,sizeof(TniftiHdr)); with lStatHdr do begin magic :=kNIFTI_MAGIC_SEPARATE_HDR; bitpix := 32; //32-bit real data datatype := kDT_FLOAT; scl_slope:= 1; scl_inter:= 0; glmin := round(lMinIntensity); glmax := round(lMaxIntensity); intent_code := lIntent_Code;// kNIFTI_INTENT_ESTIMATE; intent_p1 := lIntent_p1; intent_p2 := lIntent_p2; intent_p3 := lIntent_p3; lIntentNameLen := length(lIntentName); descrip[1] := 'N'; descrip[2] := 'P'; descrip[3] := 'M'; if lIntent_code=kNIFTI_INTENT_TTEST then begin descrip[4] := 't' ; lStr := inttostr(trunc(lIntent_p1)); for lPos := 1 to length (lStr) do descrip[4+lPos] := lStr[lPos] ; end else descrip[4] := 'z'; if lIntentNameLen > sizeof(intent_name) then lIntentNameLen := sizeof(intent_name); if lIntentNameLen > 0 then for lPos := 1 to lIntentNameLen do intent_name[lPos] := lIntentName[lPos]; end; end; *) function NPMzscore (var lImages: TStrings; var lMnHdr,lStDevHdr: TMRIcroHdr): boolean; label 667; var lOutNameMod: string; lMnImg,lStDevImg,lSubjImg,lOutImg: SingleP; lVal: single; lSubj,lPos,lVolVox: integer; lStatHdr: TNIfTIhdr; begin result := false; NPMMsg('Analysis began = ' +TimeToStr(Now)); lVolVox := lMnHdr.NIFTIhdr.dim[1]*lMnHdr.NIFTIhdr.dim[2]* lMnHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; //load mask for lPos := 0 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; if gScaleRA[kMaxImages] = 0 then gScaleRA[kMaxImages] := 1; getmem(lMnImg,lVolVox*sizeof(single)); if not LoadImg(lMnHdr.ImgFileName, lMnImg, 1, lVolVox,round(gOffsetRA[0]),1,lMnHdr.NIFTIhdr.datatype,lVolVox) then begin NPMMsg('Unable to load mean ' +lMnHdr.ImgFileName); goto 667; end; //load StDev getmem(lStDevImg,lVolVox*sizeof(single)); if not LoadImg(lStDevHdr.ImgFileName, lStDevImg, 1, lVolVox,round(gOffsetRA[kMaxImages]),1,lStDevHdr.NIFTIhdr.datatype,lVolVox) then begin NPMMsg('Unable to load StDev ' +lStDevHdr.ImgFileName); goto 667; end; getmem(lOutImg,lVolVox* sizeof(single)); for lPos := 1 to lVolVox do begin lMnImg^[lPos] := (gScaleRA[0]*lMnImg^[lPos])+gInterceptRA[0]; lStDevImg^[lPos] := (gScaleRA[kMaxImages]*lStDevImg^[lPos])+gInterceptRA[kMaxImages]; if lStDevImg^[lPos] = 0 then lOutImg^[lPos] := 0; end; getmem(lSubjImg,lVolVox* sizeof(single)); for lSubj := 1 to lImages.Count do begin NPMProgressBar(round((lSubj/lImages.Count)*100)); NPMMsg( lImages.Strings[lSubj-1]); ShowMsg(inttostr(round(gOffsetRA[lSubj]))); LoadImg(lImages.Strings[lSubj-1], lSubjImg, 1, lVolVox,round(gOffsetRA[lSubj]),1,gDataTypeRA[lSubj],lVolVox); for lPos := 1 to lVolVox do begin if lStDevImg^[lPos] <> 0 then begin lVal := (gScaleRA[lSubj]*lSubjImg^[lPos])+gInterceptRA[lSubj]; lOutImg^[lPos] := (lVal-lMnImg^[lPos])/lStDevImg^[lPos]; end; //for each voxel with variance end; //for each voxel lOutNameMod := ChangeFilePostfixExt(lImages.Strings[lSubj-1],'Z','.hdr'); MakeStatHdr (lMnHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lVolVox,kNIFTI_INTENT_ZSCORE,inttostr(lVolVox) ); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMnHdr.NIFTIhdr),true,lOutImg,1); end; //for each subj freemem(lSubjImg); freemem(lOutImg); freemem(lMnImg); freemem(lStDevImg); NPMMsg('Analysis finished = ' +TimeToStr(Now)); NPMProgressBar(0); result := true; exit; 667: //you only get here if you aborted ... free memory and report error if lVolVox > 1 then freemem(lMnImg); NPMMsg('Unable to complete analysis.'); NPMProgressBar(0); end; function ChangeName (lInName: string): string; var lPath,lName,lExt: string; begin FilenameParts (lInName, lPath,lName,lExt); if length(lName) > 0 then lName[1] := 'e' else lName := 'Unable to convert '+lInName; result := lPath+lName+lExt; end; function Add2ndScans(var lImageNames: TStrings): boolean; var lnSubj,lSubj: integer; lFilename: string; begin result := false; lnSubj :=lImageNames.Count; if lnSubj < 1 then exit; for lSubj := 1 to lnSubj do begin lFilename := ChangeName(lImageNames[lSubj-1]); if not (fileexists4D(lFilename)) then begin ShowMsg('Unable to find a file named '+ lFilename); exit; end; lImageNames.add(lFilename); end; result := true; end; procedure ComputePlankSize (var lPlankMB: integer); begin if lPlankMB < 128 then lPlankMB := 128; {$IFDEF CPU32} if lPlankMB > 1536 then lPlankMB := 1536; //we use signed 32-bit pointers, so we can not exceed 2Gb {$ELSE} if lPlankMB > 8000 then lPlankMB := 8000; //64-bit pointers, perhaps 8Gb is reasonable limit {$ENDIF} kPlankSz :=1024 {bytes/kb} * 1024 {bytes/mb} * lPlankMB; //kVers := GetKVers + ' CacheMB = '+inttostr(kPlankMB); end; procedure DefaultPrefs( var lNPMPrefs: TNPMPrefs); begin lNPMPrefs.NULP := true; lNPMPrefs.ROI := true; lNPMPrefs.TFCE := 0; lNPMPrefs.ttest := true; lNPMPrefs.BMtest := true; lNPMPrefs.PlankMB := 512; lNPMPrefs.nPermute := 0; ComputePlankSize(lNPMPrefs.PlankMB); end; procedure ReadIniFile; var lFilename: string; lThreads: integer; lIniFile: TIniFile; begin DefaultPrefs(gNPMprefs); lFilename := IniName; if not FileexistsEx(lFilename) then exit; lIniFile := TIniFile.Create(lFilename); //ttestmenu.checked := IniBool(lIniFile,'computettest',true); //BMmenu.checked := IniBool(lIniFile,'computebm',false); gNPMprefs.ttest := IniBool(lIniFile,'computettest',gNPMprefs.ttest); gNPMprefs.BMtest := IniBool(lIniFile,'computebm',gNPMprefs.BMtest); gNPMPrefs.NULP := IniBool(lIniFile,'countlesionpatterns',gNPMPrefs.NULP); gNPMPrefs.ROI := IniBool(lIniFile,'ROI',gNPMPrefs.ROI); gNPMPrefs.TFCE := IniInt(lIniFile,'TFCE',gNPMPrefs.TFCE); gNPMPrefs.PlankMB := IniInt(lIniFile,'CacheMB',gNPMPrefs.PlankMB); ComputePlankSize(gNPMPrefs.PlankMB); gNPMPrefs.nPermute := IniInt(lIniFile,'nPermute',gNPMPrefs.nPermute); //WritePermute(IniInt(lIniFile,'nPermute',0)); lThreads := IniInt(lIniFile,'nThread', gnCPUThreads ); if lThreads > gnCPUThreads then lThreads := gnCPUThreads; gnCPUThreads := lThreads; ComputePlankSize(gNPMPrefs.PlankMB); lIniFile.Free; end; //ReadIniFile procedure WriteIniFile; var lIniName: string; lIniFile: TIniFile; begin lIniName := IniName; if (DiskFreeEx(lIniName) < 1) then exit; lIniFile := TIniFile.Create(lIniName); lIniFile.WriteString('BOOL', 'computettest',Bool2Char(gNPMprefs.ttest)); lIniFile.WriteString('BOOL', 'computebm',Bool2Char(gNPMprefs.BMtest)); lIniFile.WriteString('BOOL', 'countlesionpatterns',Bool2Char(gNPMPrefs.NULP)); lIniFile.WriteString('BOOL', 'ROI',Bool2Char(gNPMPrefs.ROI)); lIniFile.WriteString('INT', 'TFCE',inttostr(gNPMPrefs.TFCE)); lIniFile.WriteString('INT', 'CacheMB',inttostr(gNPMPrefs.PlankMB)); lIniFile.WriteString('INT', 'nPermute',inttostr(gNPMPrefs.nPermute)); lIniFile.WriteString('INT', 'nThread',inttostr(gnCPUThreads)); lIniFile.Free; end; procedure FreePermute (lnPermute: integer; var lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP;var lRanOrderp: pointer); begin if (lnPermute < 2) then exit; Freemem(lRanOrderp); Freemem(lPermuteMaxT); Freemem(lPermuteMinT); Freemem(lPermuteMaxBM); Freemem(lPermuteMinBM); end; function ReportDescriptives (var RA: SingleP; n: integer): boolean; var lMn,lSD,lSE,lSkew,lZSkew: double; begin SuperDescriptive (RA, n, lMn,lSD,lSE,lSkew,lZSkew); NPMMsg('mean='+floattostr(lMn)+',StDev='+floattostr(lSD)+',StEr='+floattostr(lSE)+',Skew='+floattostr(lSkew)+',ZSkew='+floattostr(lZSkew)); end; function ThreshMap(lThresh: single; lVolVox: integer;lOutImg: singleP): integer; var lVox: integer; begin result := 0; for lVox := 1 to lVolVox do if lOutImg^[lVox] >= lThresh then inc(result); for lVox := 1 to lVolVox do if lOutImg^[lVox] >= lThresh then lOutImg^[lVox] := 1 else lOutImg^[lVox] := 0; end; procedure sort (lo, up: integer; var r:SingleP); //62ms Shell Sort http://www.dcc.uchile.cl/~rbaeza/handbook/algs/4/414.sort.p.html label 999; var d, i, j : integer; tempr : single; begin d := up-lo+1; while d>1 do begin if d<5 then d := 1 else d := trunc( 0.45454*d ); //Do linear insertion sort in steps size d for i:=up-d downto lo do begin tempr := r^[i]; j := i+d; while j <= up do if tempr > r^[j] then begin r^[j-d] := r^[j]; j := j+d end else goto 999; //break 999: r^[j-d] := tempr end //for end //while end; //proc Sort function IndexPct(lnPermute: integer; lPct: single; lTop: boolean): integer; begin result := round(lnPermute * lPct); if lTop then result := (lnPermute - result)+1; if (result < 1) then result := 1; if (result > lnPermute) then result := lnPermute; end; function ReportThresh (lLabel: string; lnPermute: integer; var lRankedData: singleP;lTop:boolean): double; begin result := lRankedData^[IndexPct(lnPermute,0.050,lTop)]; NPMmsg(lLabel+': permutationFWE '+ //'0.500='+realtostr(lRankedData[IndexPct(lnPermute,0.500,lTop)],3)+ ', 0.050='+realtostr({lRankedData^[IndexPct(lnPermute,0.050,lTop)]} result,8)+ ', 0.025='+realtostr(lRankedData^[IndexPct(lnPermute,0.025,lTop)],8)+ ', 0.01='+realtostr(lRankedData^[IndexPct(lnPermute,0.010,lTop)],8)+ ' '); end; function reportPermute (lLabel:string; lnPermute: integer; var lPermuteMaxZ, lPermuteMinZ: singleP): double; begin result := 0; if (lnPermute < 2) then exit; sort (1, lnPermute,lPermuteMaxZ); result := ReportThresh(lLabel+'+',lnPermute,lPermuteMaxZ,true); sort (1, lnPermute,lPermuteMinZ); ReportThresh(lLabel+'-',lnPermute,lPermuteMinZ,false); //for lPos := 1 to lnPermute do // msg(inttostr(lPos)+', '+realtostr(lPermuteMinZ[lPos],4)); end; function reportFDR (lLabel:string; lnVox, lnTests: integer; var lData: SingleP): double; var lC,lN: integer; lPs: SingleP; lFDR05r, lFDR01r,lFDR05p, lFDR01p,lMin,lMax : double; begin result := 10000; if (lnTests < 1) or (lnVox < 1) then exit; GetMem(lPs,lnTests*sizeof(single)); for lC := 1 to lnTests do lPs^[lC] := 0; lN := 0; lMin := 0; lMax := 0; for lC := 1 to lnVox do begin if lData^[lC] <> 0 then begin inc(lN); if lData^[lC] > lMax then lMax := lData^[lC] else if lData^[lC] < lMin then lMin := lData^[lC]; if lN <= lnTests then lPs^[lN] := pNormal(lData^[lC]); end; end; EstimateFDR2(lnTests, lPs, lFDR05p, lFDR01p,lFDR05r, lFDR01r); NPMmsg(lLabel+' Range ' +realtostr(lMin,3)+ '...'+realtostr(lMax,3)); {Msg(lLabel+' Range ' +realtostr(pNormalInv(lPs[lnTests]),3)+ '...'+realtostr(pNormalInv(lPs[1]),3)+ ' '); } //we could use this and save time computing lmin/lmax, but loss in precision NPMmsg(lLabel+' +FDR Z '+ '0.050='+realtostr(pNormalInv(lFDR05p),8)+ ', 0.01='+realtostr(pNormalInv(lFDR01p),8)+ ' '); NPMmsg(lLabel+' -FDR Z '+ '0.050='+realtostr(pNormalInv(1-lFDR05r),8)+ ', 0.01='+realtostr(pNormalInv(1-lFDR01r),8)+ ' '); result := pNormalInv(lFDR01p); end; function reportBonferroni(lLabel: string; lnTests: integer): double; //returns 5% Z score begin if lnTests < 1 then exit; result := pNormalInv(0.05/lnTests); NPMmsg(inttostr(lnTests)+' test '+lLabel+' Bonferroni FWE Z '+ '0.050='+realtostr(result,3)+ ', 0.025='+realtostr(pNormalInv(0.025/lnTests),3)+ ', 0.01='+realtostr(pNormalInv(0.01/lnTests),3)); end; procedure NPMThreadDone; begin Dec(gThreadsRunning); end; procedure InitRA (lnPermute: integer; var lRA: singleP); var lInc: integer; begin getmem(lRA,lnPermute* sizeof(single)); for lInc := 1 to lnPermute do lRA^[lInc] := 0; end; procedure InitPermute (lnSubj, lnPermute: integer; var lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP; var lRanOrderp: pointer; var lRanOrder: Doublep0); begin if (lnPermute < 2) then exit; InitRA(lnPermute,lPermuteMaxT); InitRA(lnPermute,lPermuteMinT); InitRA(lnPermute,lPermuteMaxBM); InitRA(lnPermute,lPermuteMinBM); createArray64(lRanOrderp,lRanOrder,lnSubj); end; //init permute initialization {$IFNDEF GUI} NPMmemo:= TStringList.Create; {$ENDIF} finalization {$IFNDEF GUI} NPMmemo.Free; {$ENDIF} end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/tfce_clustering.pas��������������������������������������������0000755�0001750�0001750�00000020067�12306422732�020670� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit tfce_clustering; //USED by stats to select only regions with a given number of connected/contiguous voxels {$IFDEF FPC} {$mode delphi}{$H+} {$ENDIF} {$Include ..\common\isgui.inc} interface uses {$IFNDEF UNIX} Windows, {$ELSE} {$IFDEF GUI} LCLType, LCLintf,{$ENDIF} {$ENDIF} define_types,dialogsx,SysUtils,nifti_hdr,nifti_img, math,unpm, nifti_types; //procedure FindClusters (lMultiBuf: SingleP; lXdim, lYDim, lZDim, lThreshClusterSz: integer; lMinNeg, lMinPos: single); //function ClusterTFCE (var lHdr: TMRIcroHdr; lThreshClusterSz: integer; lThresh: double ): boolean; function doTFCE (var lHdr: TNIFTIhdr; lImg: SingleP; NumConn: integer; H, E, minT, deltaT: single ): boolean; //mimics FSL's function "TFCE" in newimagefns.h function doTFCEbothPolarities (var lHdr: TNIFTIhdr; lImg: SingleP; NumConn: integer; H, E, minT, deltaT, minNegT, NegdeltaT: single; var maxTFCE, maxNegTFCE: single): boolean; //both polarities computes TFCE for both positive and negative values implementation procedure countClusterSize (lX,lY,lZ, lnumConnIn: integer; var lClusterBuff: LongIntP); //input CountImg is volume X*Y*Z where voxels are either 0 or 1 // output: CountImg voxels report number of connected neighbors const lClusterSign = 1; //input CountImg has this value set to 1 lClusterFillValue = -1; //impossible cluster size - used to denote actively growing cluster var lQHead,lV,lXY, lXYZ,lClusterSz, lQTail,lnumConn,lI,lNeighbor: integer; lQra: LongIntP; ConnOffset : ARRAY [1..26] of integer; procedure InitConn; begin //first 6 share face ConnOffset[1] := -1;//L ConnOffset[2] := 1; //R ConnOffset[3] := -lX; //A ConnOffset[4] := lX; //P ConnOffset[5] := -lXY;//I ConnOffset[6] := lXY;//S if lnumConnIn < 7 then begin lnumConn := 6; exit; end; //share edge //..check plane above ConnOffset[7] := (lXY-1); //left ConnOffset[8] := (lXY+1); //right ConnOffset[9] := (lXY-lX); //up ConnOffset[10] := (lXY+lX); //down //..check plane below ConnOffset[11] := (-lXY-1); //left ConnOffset[12] := (-lXY+1); //right ConnOffset[13] := (-lXY-lX); //up ConnOffset[14] := (-lXY+lX); //down //..check diagonals of current plane ConnOffset[15] := (-lX-1); //up, left ConnOffset[16] := (-lX+1); //up, right ConnOffset[17] := (+lX-1); //down, left ConnOffset[18] := (+lX+1); //down, right if lnumConnIn < 19 then begin lnumConn := 18; exit; end; //share corner //..check plane above ConnOffset[19] := (lXY-1-lX); //left ConnOffset[20] := (lXY-1+lX); //right ConnOffset[21] := (lXY+1-lX); //up ConnOffset[22] := (lXY+1+lX); //down //..check plane BELOW ConnOffset[23] := (-lXY-1-lX); //left ConnOffset[24] := (-lXY-1+lX); //right ConnOffset[25] := (-lXY+1-lX); //up ConnOffset[26] := (-lXY+1+lX); //down lnumConn := 26; end; //InitConn begin lXY := lX * lY; lXYZ := lX*lY*lZ; InitConn; if lXYZ < 1 then exit; GetMem(lQra,lXYZ * sizeof(longint) ); //check every voxel to see if it is isolated for lV := 1 to lXYZ do begin if (lClusterBuff^[lV]=lClusterSign) then begin //new cluster detected lClusterSz := 1; lQHead := 1; lQTail := 1; lQra^[lQTail] := lV; lClusterBuff^[lV] := lClusterFillValue; while (lQHead >= lQTail) do begin //RetirePixel: lQTail incremented once, lQHead is incremented 0..nummConn for lI := 1 to lnumConn do begin lNeighbor := lQra^[lQTail]+ConnOffset[lI]; if (lClusterBuff^[lNeighbor]=lClusterSign) then begin//add item inc(lQHead); inc(lClusterSz); lClusterBuff^[lNeighbor] := lClusterFillValue; lQra^[lQHead] := lNeighbor; end; //if new item detected end; //for each connector inc(lQTail); //done with this pixel end; //while items in Queue for lI := lV to lXYZ do if (lClusterBuff^[lI]=lClusterFillValue) then lClusterBuff^[lI] := lClusterSz; end; //new item found end; //for each voxel freemem(lQra); end; procedure ZeroFaces (var lHdr: TNIFTIhdr; lImg: SingleP ); var lV,lX,lY,lZ,lZi,lYi,lXi: integer; begin lX := lHdr.Dim[1]; lY := lHdr.Dim[2]; lZ := lHdr.Dim[3]; if (lX < 3) or (lY < 3) or (lZ < 3) then exit; for lV := 1 to (lX*lY) do lImg[lV] := 0; //bottom slice for lV := ((lX*lY*lZ)-(lX*lY)) to (lX*lY*lZ) do lImg[lV] := 0; //top slice //left side lV := 1; for lZi := 1 to lZ do begin for lYi := 1 to lY do begin lImg[lV] := 0; lV := lV+lX; end; end; //right side lV := lX; for lZi := 1 to lZ do begin for lYi := 1 to lY do begin lImg[lV] := 0; lV := lV+lX; end; end; //anterior for lZi := 1 to lZ do begin lV := (lZi-1) * lX*lY; for lXi := 1 to lX do begin lV := lV+1; lImg[lV] := 0; end; end; //posterior for lZi := 1 to lZ do begin lV := (lZi-1) * lX*lY; lV := lV + ((lY-1) *lX); for lXi := 1 to lX do begin lV := lV+1; lImg[lV] := 0; end; end; end; function doTFCEbothPolarities (var lHdr: TNIFTIhdr; lImg: SingleP; NumConn: integer; H, E, minT, deltaT, minNegT, NegdeltaT: single; var maxTFCE, maxNegTFCE: single): boolean; var lV,lXYZ,lX,lY,lZ: integer; lNegImg: SingleP; begin result := false; lX := lHdr.Dim[1]; lY := lHdr.Dim[2]; lZ := lHdr.Dim[3]; lXYZ := lX*lY*lZ; if lXYZ < 1 then exit; getmem(lNegImg,lXYZ*sizeof(single)); for lV := 1 to lXYZ do lNegImg[lV] := -lImg[lV]; doTFCE (lHdr, lImg, NumConn, H, E, minT, deltaT); maxTFCE :=lImg[lV]; for lV := 1 to lXYZ do if (maxTFCE < lImg[lV]) then maxTFCE:= lImg[lV]; doTFCE (lHdr, lNegImg, NumConn, H, E, abs(minNegT), abs(NegdeltaT)); maxNegTFCE :=lImg[lV]; for lV := 1 to lXYZ do if (maxNegTFCE < lNegImg[lV]) then maxNegTFCE:= lNegImg[lV]; maxNegTFCE := -maxNegTFCE; for lV := 1 to lXYZ do begin if (lNegImg[lV] > 0) then lImg[lV] := -lNegImg[lV]; end; freemem(lNegImg); end; function doTFCE (var lHdr: TNIFTIhdr; lImg: SingleP; NumConn: integer; H, E, minT, deltaT: single ): boolean; const kSteps = 100; label 777; var lV,lXYZ,lX,lY,lZ: integer; maxval, lThresh, ThreshPowerHxdh, dh: single; lThreshImg: SingleP; lCountImg: LongIntP; lStartTime: DWord; begin lX := lHdr.Dim[1]; lY := lHdr.Dim[2]; lZ := lHdr.Dim[3]; {$IFDEF GUI} lStartTime := GetTickCount; {$ENDIF} result := false;//assume failure lXYZ := lX*lY*lZ; if lXYZ < 1 then exit; //E := 0.5; //0.5 //H := 2;//2 getmem(lThreshImg,lXYZ*sizeof(single)); getmem(lCountImg,lXYZ*sizeof(longint)); ZeroFaces (lHdr, lImg ); maxval := lImg[1]; for lV := 1 to lXYZ do begin lThreshImg[lV] := lImg[lV]; if lImg[lV] > maxval then maxval := lImg[lV]; lImg[lV] := 0; //initialize sum map to zero end; if (maxval <= 0) then goto 777; if (maxval < minT) then goto 777; if (deltaT = 0) then dh := (maxval-minT) / kSteps else dh := deltaT; NPMmsg('max = '+floattostr(maxval)+' deltaT = '+floattostr(dh)); lThresh := minT+dh; while lThresh < maxval do begin for lV := 1 to lXYZ do begin if (lThreshImg[lV] <= lThresh) then lCountImg[lV] := 0 else lCountImg[lV] := 1; end; countClusterSize (lX,lY,lZ,NumConn, lCountImg); ThreshPowerHxdh := power(lThresh,H)*dh; for lV := 1 to lXYZ do if (lCountImg[lV] > 0) then lImg[lV] := lImg[lV] + (exp(E*ln(lCountImg[lV])) * ThreshPowerHxdh); //faster than power (*for lV := 1 to lXYZ do if (lCountImg[lV] > 0) then lImg[lV] := lImg[lV] + (power(lCountImg[lV],E) * ThreshPowerHxdh); *) lThresh := lThresh + dh; end; 777: {$IFDEF GUI} NPMmsg('Time = '+inttostr(GetTickCount - lStartTime)); {$ENDIF} freemem(lCountImg); freemem(lThreshImg); result := true; //report success! end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/ReadFloat.dfm��������������������������������������������������0000755�0001750�0001750�00000001252�10737134244�017333� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �TREADFLOATFORM�0��TPF0TReadFloatForm ReadFloatFormLeftTop BorderStylebsDialogCaptionReal number required ClientHeightG ClientWidthColor clBtnFace Font.CharsetDEFAULT_CHARSET Font.Color clWindowText Font.Height Font.Name MS Sans Serif Font.Style �OldCreateOrderPositionpoScreenCenter PixelsPerInch` TextHeight �TLabelReadFloatLabelLeft�TopWidthKHeight AlignmenttaRightJustifyCaptionEnter a number ��TButtonOKBtnLeftXTop(WidthKHeightCaptionOK ModalResultTabOrder�OnClick OKBtnClick�� TRxSpinEdit ReadFloatEditLeft0Top WidthyHeight ButtonKind bkStandardDecimal ValueTypevtFloatTabOrder���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/prefs.pas������������������������������������������������������0000755�0001750�0001750�00000023266�12204670244�016633� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit prefs; {$H+} interface uses inifiles, define_types,SysUtils,classes,turbolesion,dialogsx; function DoLesion (var lPrefs: TLDMPrefs): boolean; procedure SetDefaultPrefs (var lPrefs: TLDMPrefs); function WarnIfLowNCrit(lnSubj,lnCrit: integer): boolean; //procedure ReadParamStr; implementation uses nifti_img, hdr,nifti_hdr, valformat,StatThdsUtil,filename, unpm; procedure SetDefaultPrefs (var lPrefs: TLDMPrefs); begin lPrefs.tTest := true; lPrefs.BMtest := false; lPrefs.Ltest := false; lPrefs.nPermute := 0; lPrefs.CritPct := -1;//use default in val file lPrefs.ExplicitMaskName := ''; lPrefs.ValFilename := ''; lPrefs.Outname := ''; end; function noVariance (lRA: singlep; lnSubj: integer): boolean; var lI : integer; begin result := false; if lnSubj < 2 then exit; for lI := 2 to lnSubj do if lRA^[1] <> lRA^[lI] then exit; result := true; end; function WarnIfLowNCrit(lnSubj,lnCrit: integer): boolean; //returns true if warning generated begin result := (round(lnSubj * 0.15) ) > lnCrit; //15% if result then Showmsg('Warning: low statistical power as tests computed for voxels damaged in at least '+inttostr(lnCrit) +' people. Solution: change Design value "Ignore voxels damaged in less than N%".'); end; function DoLesion (var lPrefs: TLDMPrefs): boolean; label 666; var lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCritV,lCritPctV: integer; lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lFactname: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA: singleP; begin if (not lPrefs.BMtest) and (not lPrefs.ttest) and (not lPrefs.LTest) then begin NPMmsg('Error: you need to compute at least on test [options/test menu]'); exit; end; lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? if not GetValCore(lPrefs.ValFilename, lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCritV,lCritPctV,lPredictorList) then begin NPMmsg('Error with VAL file'); goto 666; end; if lPrefs.critPct < 0 then //-1 denotes using the values specified in the VAL file lPrefs.critPct := lCritPctV; lTemp4D := CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) then begin NPMmsg('Not enough subjects ('+inttostr(lnSubjAll)+') or factors ('+inttostr(lnFactors)+').'); goto 666; end; WarnIfLowNCrit(lnSubjAll, round( (lnSubjAll*lPrefs.CritPct)/100)); lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin NPMmsg('Error reading 1st mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin NPMmsg('Mask file size too small.'); goto 666; end; if (lPrefs.OutName = '') or (not DirExists(extractfiledir(lPrefs.Outname))) then begin lPrefs.Outname := extractfiledir(lPrefs.ValFilename)+pathdelim+'results.nii.gz'; NPMmsg('Output stored as '+lPrefs.Outname); end; for lFact := 1 to lnFactors do begin NPMMsgClear; NPMMsg(GetKVers); lImageNames.clear; for lSubj := 1 to lnSubjAll do if (not lPrefs.LTest) or (lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] = 0) OR (lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] = 1) THEN begin {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); end else begin NPMMsg('Data rejected: behavior must be zero or one for binomial test '+lImageNamesAll.Strings[lSubj-1]); end; lnSubj := lImageNames.Count; if lnSubj > 2 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do begin if (not lPrefs.LTest) or (lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] = 0) OR (lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] = 1) THEN begin {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; //valid value end; //not binomial, or 1/0 end; //for each subject NPMMsg('Threads: '+inttostr(gnCPUThreads)); lFactName := lPredictorList.Strings[lFact-1]; lFactName := LegitFilename(lFactName,lFact); NPMMsg('Factor = '+lFactname); For lSubj := 1 to lnSubj do NPMMsg (lImageNames.Strings[lSubj-1] + ' = '+realtostr(lSymptomRA^[lSubj],2) ); NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); lPrefs.nCrit := round( (lnSubj*lPrefs.CritPct)/100); NPMMsg('Only testing voxels damaged in at least '+inttostr(lPrefs.nCrit)+' individual[s]'); NPMMsg('Number of Lesion maps = '+inttostr(lnSubj)); if not CheckVoxelsGroupX(lImageNames,lMaskHdr {lMaskVoxels}) then begin NPMMsg('Error: File dimensions differ from mask.'); goto 666; end; if noVariance (lSymptomRA,lnSubj) then NPMMsg('Error no variability in behavioral data ') else TurboLDM (lImageNames, lMaskHdr, lPrefs, lSymptomRA, lFactname,lPrefs.OutName); Freemem(lSymptomRA); end else begin NPMMsg('At least 2 individuals required to compute statistics for '+lPredictorList.Strings[lFact-1]); end; //lnsubj > 2 end; //for each factor if lnSubjAll > 0 then begin Freemem(lMultiSymptomRA); end; 666: lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); end; (*procedure ShowHelp; begin NPMMsg('usage ''npm [options] -o resultsfilname valfilename'' '); NPMMsg(' Options '); NPMMsg(' -c: critical percent 0..100 '); NPMMsg(' -p: permutations 0..4000 '); NPMMsg(' -t: Test [1=Liebermeister, 2=TTest, 4=BMtest, 6=t&BMtests'); NPMMsg(' -o: Output filename'); NPMMsg('examples:'); NPMMsg(' npm -c 25 -p 1000 -o c:\results.nii.gz c:\mri\data.val'); NPMMsg(' npm -c 25 -o "c:\program files\results.hdr" c:\mri\data.val'); end; procedure ReadParamStr; var lStr: String; I,lError: integer; lCommandChar: Char; lSingle: single; lHelpShown: boolean; lPrefs: TLDMPrefs; begin if (ParamCount < 1) then exit; SetDefaultPrefs(lPrefs); lHelpShown := false; lStr := paramstr(0); lStr := extractfilename(lStr); lStr := string(StrUpper(PChar(lStr))) ; if (ParamCount > 0) then begin I := 0; repeat lStr := ''; repeat inc(I); if I = 1 then lStr := ParamStr(I) else begin if lStr <> '' then lStr := lStr +' '+ ParamStr(I) else lStr := ParamStr(I); end; if (length(lStr)>1) and (lStr[1] = '-') and (ParamCount > I) then begin //special command //-z= zoom, -f= format [png,jpeg,bmp], -o= output directory lCommandChar := UpCase(lStr[2]); inc(I); lStr := ParamStr(I); lStr := string(StrUpper(PChar(lStr))) ; case lCommandChar of 'C','P','T': begin //CritPct Val(lStr,lSingle,lError); if lError = 0 then begin if lCommandChar = 'C' then lPrefs.CritPct := round(lSingle) else if lCOmmandChar = 'P' then lPrefs.nPermute := round(lSingle) else if lCOmmandChar = 'T' then begin case round(lSingle) of 1: begin lPrefs.LTest := true; lPrefs.Ttest := false; lPrefs.BMtest := false; end; 2: begin lPrefs.LTest := false; lPrefs.Ttest := true; lPrefs.BMtest := false; end; 4: begin lPrefs.LTest := false; lPrefs.Ttest := false; lPrefs.BMtest := true; end; 6: begin lPrefs.LTest := false; lPrefs.Ttest := true; lPrefs.BMtest := true; end; //1=Liebermeister, 2=TTest, 4=BMtest, 6=t&BMtests end;//xxx end; end; //not lError end; //C= CritPct,P=permutations,T=test 'O': begin //output filename lPrefs.OutName :=lStr; end; end; //case lStr[2] lStr := ''; end; //special command until (I=ParamCount) or (fileexists(lStr)) {or (gAbort)}; if fileexists(lStr) then begin //lStr := GetLongFileName(lStr); lPrefs.ValFilename := lStr; //if lPrefs.OutName = '' then // lPrefs.Outname := extractfiledir(paramstr(0))+pathdelim+'results.nii.gz'; NPMMsg ('output ' + lPrefs.Outname); NPMMsg ('val file: '+lPrefs.ValFilename); DoLesion(lPrefs); //MainForm.close; end else begin NPMMsg('Error: unable to find '+lStr); if not lHelpShown then Showhelp; lHelpShown := true; end; until I >= ParamCount; end else begin ShowHelp; end;{param count > 0} end; *) end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/ReadInt.dfm����������������������������������������������������0000755�0001750�0001750�00000001204�10621133136�017004� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �TREADINTFORM�0n��TPF0 TReadIntForm ReadIntFormLeft9Top� BorderStylebsDialogCaptionInteger required ClientHeightI ClientWidthColor clBtnFace Font.CharsetDEFAULT_CHARSET Font.Color clWindowText Font.Height Font.Name MS Sans Serif Font.Style �OldCreateOrderPositionpoScreenCenter PixelsPerInch` TextHeight �TLabel ReadIntLabelLeftTopWidthKHeight AlignmenttaRightJustifyCaptionEnter a number �� TSpinEdit ReadIntEditLefthTop WidthYHeightMaxValue�MinValue�TabOrderValue���TButtonOKBtnLeftXTop(WidthKHeightCaptionOK ModalResultTabOrder�OnClick OKBtnClick�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/_npmcl.bat�����������������������������������������������������0000755�0001750�0001750�00000000163�12156075736�016751� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� lazbuild ./npmcl.lpr --cpu=x86_64 --compiler="/usr/local/bin/ppcx64" mv ./npmcl ./npmcl64 lazbuild ./npmcl.lpr �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/ReadFloat.pas��������������������������������������������������0000755�0001750�0001750�00000002031�11326425450�017341� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit ReadFloat; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, RXSpin; type TReadFloatForm = class(TForm) OKBtn: TButton; ReadFloatLabel: TLabel; ReadFloatEdit: TRxSpinEdit; function GetFloat(lStr: string; lMin,lDefault,lMax: double): double; procedure OKBtnClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var ReadFloatForm: TReadFloatForm; implementation {$R *.DFM} function TReadFloatForm.GetFloat(lStr: string; lMin,lDefault,lMax: double): double; begin //result := lDefault; ReadFloatLabel.caption := lStr+' ['+floattostr(lMin)+'..'+floattostr(lMax)+']'; ReadFloatEdit.MinValue := lMin; ReadFloatEdit.MaxValue := lMax; ReadFloatEdit.Value := lDefault; ReadFloatForm.ShowModal; result := ReadFloatEdit.Value; end; procedure TReadFloatForm.OKBtnClick(Sender: TObject); begin ReadFloatForm.ModalResult := mrOK; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/design.lrs�����������������������������������������������������0000755�0001750�0001750�00000005733�11540170650�016777� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TDesignForm','FORMDATA',[ 'TPF0'#11'TDesignForm'#10'DesignForm'#4'Left'#3#225#1#6'Height'#3#207#0#3'Top' +#3#179#0#5'Width'#3'|'#2#18'HorzScrollBar.Page'#3'{'#2#18'VertScrollBar.Page' +#3#206#0#13'ActiveControl'#7#4'AVal'#11'BorderStyle'#7#8'bsDialog'#7'Caption' +#6#6'Design'#12'ClientHeight'#3#207#0#11'ClientWidth'#3'|'#2#21'Constraints.' +'MaxHeight'#3#207#0#20'Constraints.MaxWidth'#3'|'#2#21'Constraints.MinHeight' +#3#207#0#20'Constraints.MinWidth'#3'|'#2#9'Font.Name'#6#13'MS Sans Serif'#8 +'OnCreate'#7#10'FormCreate'#8'Position'#7#14'poScreenCenter'#10'LCLVersion'#6 +#8'0.9.28.2'#0#6'TLabel'#6'Label4'#4'Left'#2#4#6'Height'#2#18#3'Top'#2#8#5'W' +'idth'#2'F'#7'Caption'#6#10'Predictors'#11'ParentColor'#8#0#0#6'TLabel'#6'La' +'bel5'#4'Left'#2'L'#6'Height'#2#18#3'Top'#2#8#5'Width'#2'r'#7'Caption'#6#15 +'Predictor Names'#11'ParentColor'#8#0#0#6'TLabel'#6'Label1'#4'Left'#2#12#6'H' +'eight'#2#18#3'Top'#2'{'#5'Width'#2'Q'#7'Caption'#6#12'Participants'#11'Pare' +'ntColor'#8#0#0#6'TLabel'#13'TemplateLabel'#4'Left'#3#148#0#6'Height'#2#18#3 +'Top'#2'_'#5'Width'#2'p'#7'Caption'#6#15'C:\template.img'#11'ParentColor'#8#0 +#0#6'TLabel'#6'Label2'#4'Left'#2#12#6'Height'#2#18#3'Top'#3#168#0#5'Width'#3 +#7#1#7'Caption'#6'%Ignore voxels damaged in less than N%'#11'ParentColor'#8#0 +#0#7'TButton'#5'OKBtn'#4'Left'#3#15#2#6'Height'#2#25#3'Top'#3#168#0#5'Width' +#2'K'#25'BorderSpacing.InnerBorder'#2#4#7'Caption'#6#2'OK'#11'ModalResult'#2 +#1#8'TabOrder'#2#0#0#0#9'TSpinEdit'#4'AVal'#4'Left'#2#12#6'Height'#2#27#3'To' +'p'#2'%'#5'Width'#2'F'#8'MaxValue'#2'c'#8'MinValue'#2#1#8'OnChange'#7#10'AVa' +'lChange'#8'TabOrder'#2#1#5'Value'#2#2#0#0#11'TStringGrid'#11'ALevelNames'#4 +'Left'#2'b'#6'Height'#2'*'#3'Top'#2#30#5'Width'#3#15#2#8'ColCount'#2#2#9'Fix' +'edCols'#2#0#9'FixedRows'#2#0#7'Options'#11#15'goFixedVertLine'#15'goFixedHo' +'rzLine'#10'goVertLine'#19'goDrawFocusSelected'#9'goEditing'#0#8'RowCount'#2 +#1#10'ScrollBars'#7#12'ssHorizontal'#8'TabOrder'#2#2#16'TitleFont.Height'#2 +#245#14'TitleFont.Name'#6#13'MS Sans Serif'#7'OnEnter'#7#16'ALevelNamesEnter' +#6'OnExit'#7#15'ALevelNamesExit'#0#0#9'TCheckBox'#17'LesionCovaryCheck'#4'Le' +'ft'#3#255#0#6'Height'#2#21#3'Top'#2'{'#5'Width'#3#11#1#7'Caption'#6'"Automa' +'tically Covary Lesion Volume'#8'TabOrder'#2#5#7'Visible'#8#0#0#7'TButton'#9 +'AddMRIBtn'#4'Left'#2']'#6'Height'#2#25#3'Top'#2'v'#5'Width'#3#129#0#25'Bord' +'erSpacing.InnerBorder'#2#4#7'Caption'#6#13'Select Images'#7'OnClick'#7#14'A' +'ddMRIBtnClick'#8'TabOrder'#2#4#0#0#7'TButton'#11'TemplateBtn'#4'Left'#2#12#6 +'Height'#2#25#3'Top'#2'Y'#5'Width'#3#129#0#25'BorderSpacing.InnerBorder'#2#4 +#7'Caption'#6#15'Select Template'#7'OnClick'#7#16'TemplateBtnClick'#8'TabOrd' +'er'#2#3#0#0#9'TSpinEdit'#11'CritPctEdit'#4'Left'#3'0'#1#6'Height'#2#27#3'To' +'p'#3#162#0#5'Width'#2'L'#8'OnChange'#7#10'AValChange'#8'TabOrder'#2#6#5'Val' +'ue'#2#1#0#0#0 ]); �������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/design.pas�����������������������������������������������������0000755�0001750�0001750�00000013005�11540170650�016751� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit design; interface uses {$IFNDEF FPC} //Utils, {$ELSE} LResources, {$ENDIF} //{$IFNDEF Unix} Windows,{$ENDIF} Buttons, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Spin, Grids,nifti_hdr; type String10= String[10]; { TDesignForm } TDesignForm = class(TForm) OKBtn: TButton; AVal: TSpinEdit; Label4: TLabel; Label5: TLabel; ALevelNames: TStringGrid; LesionCovaryCheck: TCheckBox; AddMRIBtn: TButton; Label1: TLabel; TemplateBtn: TButton; TemplateLabel: TLabel; CritPctEdit: TSpinEdit; Label2: TLabel; //procedure LRsetup (var NumColumns,Vars,L1,L2,L3: integer; var OK: boolean); procedure AValChange(Sender: TObject); procedure FormCreate(Sender: TObject); procedure ALevelNamesEnter(Sender: TObject); procedure ALevelNamesExit(Sender: TObject); procedure AddMRIBtnClick(Sender: TObject); procedure TemplateBtnClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var DesignForm: TDesignForm; implementation uses npmform,spread,hdr; {$IFNDEF FPC} {$R *.DFM} {$ENDIF} const kMaxColumns = 16; {for ANOVA} //maxElements = kMaxColumns; {ANOVA} MaxLen = 12; //kCR = chr (13); //kTab = chr(9); kVALImgFilter = 'Image (*.hdr;*.nii;*.voi)|*.hdr;*.nii;*.nii.gz;*.voi'; procedure TDesignForm.AValChange(Sender: TObject); {$IFDEF FPC} var lOrig,lP: integer; begin lOrig := ALevelNames.ColCount; DesignForm.Caption := inttostr(AVal.Value); ALevelNames.ColCount := AVal.Value; if AVal.value > lOrig then for lP := lOrig to (AVal.value-1) do AlevelNames.Cells[lP,0] := 'Pred'+inttostr(lP+1); end; {$ELSE} begin ALevelNames.ColCount := AVal.Value; end; {$ENDIF} procedure TDesignForm.FormCreate(Sender: TObject); var lC: integer; begin ALevelNames.ColCount := 16 ; AlevelNames.Selection:=TGridRect(Rect(-1,-1,-1,-1)); //AlevelNames.Cells[8,0] := 'Pred'; for lC := 0 to 15 do begin AlevelNames.Cells[lC,0] := 'Pred'+inttostr(lC+1); end; SpreadForm.UpdateLabels; AValChange(nil); end; procedure TDesignForm.ALevelNamesEnter(Sender: TObject); begin AlevelNames.Selection:=TGridRect(Rect(0,0,0,0)); end; procedure TDesignForm.ALevelNamesExit(Sender: TObject); begin AlevelNames.Selection:=TGridRect(Rect(-1,-1,-1,-1)); end; function LeadingZeroFilename (lInX: string): string; var lIn: string; lC,lnPad,lPos,lnDec,lExtPos,lLen: integer; begin {$IFDEF Unix} lIn := lInX; {$ELSE} lIn := Lowercase(lInX); {$ENDIF} lnPad := 8; lLen := length(lIn); result := lIn; if lLen < 1 then exit; lExtPos := 1; while (lExtPos <= lLen) and (lIn[lExtPos] <> '.') do inc(lExtPos); if lExtPos <= 1 then exit; lnDec := 0; lPos := lExtPos -1; while (lPos > 0) and ( lIn[lPos] in ['0'..'9']) do dec(lPos); lnDec := (lExtPos-lPos)-1; if (lnDec = 0) or (lnDec >= lnPad) then exit; result := ''; if lPos > 0 then for lC := 1 to lPos do result := result + lIn[lC]; for lC := 1 to (lnPad-lnDec) do result := result + '0'; for lC := (lPos+1) to lLen do result := result+lIn[lC]; end; procedure SortStrPadded (var lStr: TStringList); {file1,file2...file10 not file1,file10..file2} var counter, look:integer; temp:Tstrings; begin if lStr.Count < 2 then exit; temp := TStringList.Create; for counter:=0 to lStr.Count-1 do temp.Append(LeadingZeroFilename{LowerCase}(lStr[counter])); for counter:=0 to temp.Count-1 do for look:=counter+1 to temp.Count-1 do if temp[look]<temp[counter] then begin lStr.Exchange(look, counter); temp.Exchange(look,counter); end; temp.Free; end; procedure TDesignForm.AddMRIBtnClick(Sender: TObject); var lNumberofFiles,lC: integer; lFileStrs: TStringList; begin if not MainForm.OpenDialogExecute('Select VOIs you wish to analyze',true,false,kVALImgFilter) then exit; lNumberofFiles:= MainForm.OpenHdrDlg.Files.Count; if lNumberofFiles < 2 then begin lNumberofFiles := NIFTIhdr_HdrVolumes(MainForm.OpenHdrDlg.Filename); if lNumberofFiles < 2 then begin Showmessage('Error: This function is designed to overlay MULTIPLE images. You selected less than two images.'); exit; end; lFileStrs := TStringList.Create; for lC:= 1 to lNumberofFiles do lFileStrs.Add(extractfilename(MainForm.OpenHdrDlg.Filename)+':'+inttostr(lC)); end else begin lFileStrs := TStringList.Create; for lC:= 1 to lNumberofFiles do lFileStrs.Add(extractfilename(MainForm.OpenHdrDlg.Files[lC-1])); SortStrPadded (lFileStrs); end; SpreadForm.DataGrid.RowCount := lNumberofFiles+1+kMaxFactors; //10/10/2006 -must resize BEFORE to populating cells for lC:= 1 to lNumberofFiles do SpreadForm.DataGrid.Cells[0,kMaxFactors+lC] := lFileStrs[lC-1]; lFileStrs.free; end; procedure TDesignForm.TemplateBtnClick(Sender: TObject); begin if not MainForm.OpenDialogExecute('Select Template image [determines bounding box and dimensions]',false,false,kVALImgFilter) then exit; TemplateLabel.Caption := (MainForm.OpenHdrDlg.Filename); end; {$IFDEF FPC} initialization {$I design.lrs} {$ENDIF} end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/windowsxp.res��������������������������������������������������0000755�0001750�0001750�00000001340�07374553744�017572� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ������������������������� ���������0� ��������<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity name="CiaoSoftware.Ciao.Shell.Contacts" processorArchitecture="x86" version="5.1.0.0" type="win32"/> <description>Windows Shell</description> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*" /> </dependentAssembly> </dependency> </assembly> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/spread.lfm�����������������������������������������������������0000755�0001750�0001750�00000012232�12147213330�016747� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object SpreadForm: TSpreadForm Left = 401 Height = 538 Top = 183 Width = 326 ActiveControl = DataGrid Caption = 'Voxelwise Analysis of Lesions' ClientHeight = 538 ClientWidth = 326 Font.Name = 'MS Sans Serif' Menu = MainMenu1 OnClose = FormClose OnCreate = FormCreate OnResize = FormResize Position = poScreenCenter LCLVersion = '0.9.30.2' object DataGrid: TStringGrid Left = 0 Height = 498 Top = 25 Width = 326 Align = alClient FixedRows = 2 Options = [goFixedVertLine, goVertLine, goHorzLine, goRangeSelect, goDrawFocusSelected, goTabs, goThumbTracking] RowCount = 12 TabOrder = 0 TitleFont.Name = 'MS Sans Serif' OnDrawCell = DataGridDrawCell OnKeyPress = DataGridKeyPress OnMouseDown = DataGridMouseDown OnMouseMove = DataGridMouseMove OnSelectCell = DataGridSelectCell end object ToolBar1: TToolBar Left = 0 Height = 25 Top = 0 Width = 326 EdgeBorders = [] TabOrder = 1 object DesignBtn: TSpeedButton Left = 1 Height = 22 Hint = 'ANOVA' Top = 0 Width = 120 Caption = 'Design' Glyph.Data = { 76010000424D7601000000000000760000002800000020000000100000000100 0400000000000001000000000000000000001000000010000000000000000000 800000800000008080008000000080008000808000007F7F7F00BFBFBF000000 FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00337333733373 3373337F3F7F3F7F3F7F33737373737373733F7F7F7F7F7F7F7F770000000000 00007777777777777777330333333C333333337FFF3337F3333F370993333C33 3399377773F337F33377330339333C3339333F7FF7FFF7FFF7FF770777977C77 97777777777777777777330333933C339333337F3373F7F37333370333393C39 3333377F333737F7333333033333999333333F7FFFFF777FFFFF770777777C77 77777777777777777777330333333C330333337F333337FF7FF3370333333C00 003C377F333337777737330333333C3303333F7FFFFFF7FF7FFF770777777777 7777777777777777777733333333333333333333333333333333 } NumGlyphs = 2 OnClick = DesignBtnClick ShowHint = True ParentShowHint = False end end object StatusBar1: TStatusBar Left = 0 Height = 15 Top = 523 Width = 326 Panels = < item Width = 140 end item Width = 50 end> SimplePanel = False end object MainMenu1: TMainMenu left = 108 top = 44 object File1: TMenuItem Caption = '&File' object New1: TMenuItem Caption = 'New...' ShortCut = 16462 OnClick = NewBtnClick end object Open1: TMenuItem Caption = 'Open...' ShortCut = 16463 OnClick = OpenBtnClick end object Save1: TMenuItem Caption = 'Save' ShortCut = 16467 OnClick = SaveBtnClick end object Quit1: TMenuItem Caption = 'Close window' ShortCut = 16471 OnClick = Quit1Click end end object Edit1: TMenuItem Caption = 'Edit' object Copy1: TMenuItem Caption = 'Copy' ShortCut = 16451 OnClick = Copy1Click end object Paste1: TMenuItem Caption = 'Paste' ShortCut = 16470 OnClick = Paste1Click end object Selectall1: TMenuItem Caption = 'Select all cells' ShortCut = 16449 OnClick = Selectall1Click end object Clearallcells1: TMenuItem Caption = 'Clear all cells...' OnClick = Clearallcells1Click end object DescriptiveMenu: TMenuItem Caption = 'Descriptives' OnClick = DescriptiveClick end end object View: TMenuItem Caption = 'View' object Font1: TMenuItem Caption = 'Font' object N81: TMenuItem Tag = 8 Caption = '8' Checked = True GroupIndex = 111 RadioItem = True OnClick = FontSizeChange end object N101: TMenuItem Tag = 10 Caption = '10' GroupIndex = 111 RadioItem = True OnClick = FontSizeChange end object N121: TMenuItem Tag = 12 Caption = '12' GroupIndex = 111 RadioItem = True OnClick = FontSizeChange end object N141: TMenuItem Tag = 14 Caption = '14' GroupIndex = 111 RadioItem = True OnClick = FontSizeChange end end object Design1: TMenuItem Caption = 'Design' ShortCut = 16452 OnClick = DesignBtnClick end end object Help1: TMenuItem Caption = '&Help' object Aboutthissoftware1: TMenuItem Caption = '&About this software' OnClick = Aboutthissoftware1Click end end end object OpenDialog1: TOpenDialog DefaultExt = '.val' Filter = 'Native [val]|.val|Tab delimited text [txt]|.txt|All files|.*' FilterIndex = 0 left = 36 top = 44 end object SaveDialog1: TSaveDialog DefaultExt = '.val' Filter = 'Native format [val]|*.val|Tab delimited text [txt]|*.txt' FilterIndex = 0 Options = [ofOverwritePrompt, ofHideReadOnly] left = 74 top = 44 end end ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/npmform.lfm����������������������������������������������������0000755�0001750�0001750�00000016703�12306741004�017157� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object MainForm: TMainForm Left = 468 Height = 418 Top = 213 Width = 542 ActiveControl = Memo1 Caption = 'Non-Parametric Mapping' ClientHeight = 418 ClientWidth = 542 Menu = MainMenu1 OnClose = FormClose OnCreate = FormCreate OnShow = FormShow Position = poScreenCenter LCLVersion = '1.0.12.0' object Memo1: TMemo Left = 0 Height = 393 Top = 0 Width = 542 Align = alClient ScrollBars = ssAutoBoth TabOrder = 0 end object Panel1: TPanel Left = 0 Height = 25 Top = 393 Width = 542 Align = alBottom ClientHeight = 25 ClientWidth = 542 TabOrder = 1 object ProgressBar1: TProgressBar Left = 1 Height = 23 Top = 1 Width = 540 Align = alClient TabOrder = 0 end end object MainMenu1: TMainMenu left = 8 top = 8 object File1: TMenuItem Caption = 'File' object SaveText1: TMenuItem Caption = 'Save text...' OnClick = Savetext1Click end object Exit1: TMenuItem Caption = 'Exit' OnClick = Exit1Click end end object Edit1: TMenuItem Caption = 'Edit' object Copy1: TMenuItem Caption = 'Copy' OnClick = Copy1Click end end object VLSM1: TMenuItem Caption = 'VLSM' object BinomialAnalysislesions1: TMenuItem Caption = 'Binary images, binary groups (lesions) ' ShortCut = 16450 OnClick = LesionBtnClick end object Binaryimagescontinuousgroupsfast1: TMenuItem Tag = 1 Caption = 'Binary images, continuous groups (vlsm)' ShortCut = 16460 OnClick = LesionBtnClick end object PenalizedLogisticRegerssion1: TMenuItem Caption = 'Binary images, multiple factors' OnClick = PenalizedLogisticRegerssion1Click end object ROIanalysis1: TMenuItem Caption = 'ROI analysis' OnClick = ROIanalysis1Click end object Design1: TMenuItem Caption = 'Design...' ShortCut = 16452 OnClick = Design1Click end end object VBM1: TMenuItem Caption = 'VBM' object ContinuousanalysisVBM1: TMenuItem Caption = 'Continuous images, binary groups (VBM)' ShortCut = 16470 OnClick = NPMclick end object PairedTMenu: TMenuItem Caption = 'Paired Measures T-test' OnClick = PairedTMenuClick end object MultipleRegress: TMenuItem Caption = 'Multiple WLS Regression' Visible = False OnClick = MultipleRegressClick end object SingleRegress: TMenuItem Caption = 'Single WLS Regression' Visible = False OnClick = SingleRegressClick end object DualImageCorrelation1: TMenuItem Caption = 'Dual image correlation' Visible = False OnClick = DualImageCorrelation1Click end end object Options1: TMenuItem Caption = 'Options' object Permutations1: TMenuItem Caption = 'Permutations' object N0: TMenuItem AutoCheck = True Caption = 'None' Checked = True GroupIndex = 123 RadioItem = True OnClick = radiomenuclick end object N1000: TMenuItem Tag = 1000 AutoCheck = True Caption = '1000' GroupIndex = 123 RadioItem = True OnClick = radiomenuclick end object N2000: TMenuItem Tag = 2000 AutoCheck = True Caption = '2000' GroupIndex = 123 RadioItem = True OnClick = radiomenuclick end object N3000: TMenuItem Tag = 3000 AutoCheck = True Caption = '3000' GroupIndex = 123 RadioItem = True OnClick = radiomenuclick end object N4000: TMenuItem Tag = 4000 AutoCheck = True Caption = '4000' GroupIndex = 123 RadioItem = True OnClick = radiomenuclick end end object Tests1: TMenuItem Caption = 'Tests' object ttestmenu: TMenuItem Caption = 't-test' OnClick = testmenuclick end object BMmenu: TMenuItem Caption = 'Brunner Munzel' Checked = True OnClick = testmenuclick end end object Threads1: TMenuItem Caption = 'Threads' object T1: TMenuItem AutoCheck = True Caption = '1' Checked = True GroupIndex = 131 RadioItem = True OnClick = threadChange end object T2: TMenuItem AutoCheck = True Caption = '2' GroupIndex = 131 RadioItem = True OnClick = threadChange end object T3: TMenuItem AutoCheck = True Caption = '3' GroupIndex = 131 RadioItem = True OnClick = threadChange end object T4: TMenuItem AutoCheck = True Caption = '4' GroupIndex = 131 RadioItem = True OnClick = threadChange end object T7: TMenuItem AutoCheck = True Caption = '7' GroupIndex = 131 RadioItem = True OnClick = threadChange end object T8: TMenuItem AutoCheck = True Caption = '8' GroupIndex = 131 RadioItem = True OnClick = threadChange end object T15: TMenuItem AutoCheck = True Caption = '15' GroupIndex = 131 RadioItem = True OnClick = threadChange end object T16: TMenuItem AutoCheck = True Caption = '16' GroupIndex = 131 RadioItem = True OnClick = threadChange end end object PlankSzMenuItem1: TMenuItem Caption = 'Plank Size' OnClick = PlankSzMenuItem1Click end end object Utilities1: TMenuItem Caption = 'Utilities' object Variance1: TMenuItem Caption = 'Variance image' OnClick = Variance1Click end object Makemeanimage2: TMenuItem Tag = 1 Caption = 'Make binarized mean' OnClick = Makemeanimage1Click end object Makemeanimage1: TMenuItem Caption = 'Make mean/StDev image' OnClick = Makemeanimage1Click end object SingleSubjectZScores1: TMenuItem Caption = 'Single Subject Z-Score' OnClick = SingleSubjectZScores1Click end object IntensitynormalizationA1: TMenuItem Tag = 1 Caption = 'Intensity normalization A' OnClick = Balance1Click end object Balance1: TMenuItem Caption = 'Intensity normalization B' OnClick = Balance1Click end end object Help1: TMenuItem Caption = 'Help' Visible = False object About1: TMenuItem Caption = 'About' OnClick = About1Click end end end object SaveHdrDlg: TSaveDialog FilterIndex = 0 left = 8 top = 40 end object OpenHdrDlg: TOpenDialog FilterIndex = 0 left = 8 top = 72 end end �������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/part.pas�������������������������������������������������������0000755�0001750�0001750�00000052623�12156151236�016462� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit part; //Physiological Artifact Removal Tool {$H+} interface uses define_types,dialogsx,SysUtils; function ApplyPart( lFilename: string;lImgData: singleP; lBins,lVolVox,lSlices, lImgVol : integer; lTRsec: single): string; implementation type TPhysioT = RECORD Triggers,InterpolatedTriggers: integer; TriggerMedian,TriggerQ1,TriggerQ3: Double; TriggerRA: singleP; END; function SaveTriggersAs3ColumnFSL(lPhysioIn: TPhysioT; lOutName: string): boolean; var lF: textfile; lPos: integer; begin result := false; if (lPhysioIn.Triggers < 1) then exit; assignfile(lF,lOutName+'.txt'); Filemode := 0; rewrite(lF); for lPos := 1 to lPhysioIn.Triggers do Writeln(lf,realtostr(lPhysioIn.TriggerRA^[lPos],3)+' 1 1'); closefile(lF); Filemode := 2; result := true; end; procedure qsort(lower, upper : integer; var Data:SingleP); //40ms - fast but very recursive... var left, right : integer; pivot,lswap: single; begin pivot:=Data^[(lower+upper) div 2]; left:=lower; right:=upper; while left<=right do begin while Data^[left] < pivot do left:=left+1; { Parting for left } while Data^[right] > pivot do right:=right-1;{ Parting for right} if left<=right then begin { Validate the change } lswap := Data^[left]; Data^[left] := Data^[right]; Data^[right] := lswap; left:=left+1; right:=right-1; end; //validate end;//while left <=right if right>lower then qsort(lower,right,Data); { Sort the LEFT part } if upper>left then qsort(left ,upper,data); { Sort the RIGHT part } end; procedure QuartileTriggerSpacing(var lPhysio: TPhysioT); var lTriggerDelayRA: singleP; lPos: integer; begin lPhysio.TriggerQ1 := 0; lPhysio.TriggerMedian := 0; lPhysio.TriggerQ3 := 0; if lPhysio.Triggers < 4 then exit; getmem(lTriggerDelayRA,(lPhysio.Triggers-1)*sizeof(single)); for lPos := 1 to (lPhysio.Triggers-1) do lTriggerDelayRA^[lPos] := abs(lPhysio.TriggerRA^[lPos]-lPhysio.TriggerRA^[lPos+1]); qsort(1,lPhysio.Triggers-1,lTriggerDelayRA);//-1 : fence post vs wire lPos := lPhysio.Triggers div 2; lPhysio.TriggerMedian := lTriggerDelayRA^[lPos]; lPos := lPhysio.Triggers div 4; lPhysio.TriggerQ1 := lTriggerDelayRA^[lPos]; lPos := round(0.75*lPhysio.Triggers ); lPhysio.TriggerQ3 := lTriggerDelayRA^[lPos]; freemem(lTriggerDelayRA); end; function PARTool (var lPhysio: TPhysioT; lImgData: singleP; lTRsec: single; lnVolVox,lnSlices, lImgVol, lBinIn : integer): string; const kMinSamplesPerBin = 4; var lV,lSliceTime,lMeanSignal,lOnsetTime,lBinWidth,lBinMin,lBinMax,lTimeSinceTrigger,lPrevTriggerTime: double; lSlice,lSlicePos,lnSliceVox,lnSlicePos,lVoxel,lBin,lSample,lnBin,lnBinDiv2,lNextTrigger,lSamplesWithVariance,lCorrectedSamples,lVolOffset: integer; lBinCountRA,lVolBinRA: longintp; lVariance : boolean; lBinEstimateRA: doublep; begin result := ''; if (lPhysio.Triggers < 4) or (lnVolVox < 4) or (lImgVol < 4) then begin ShowMsg('PART requires at least 4 triggers and at least 4 volumes each with at least 4 voxels'); exit; end; if (lBinIn < 4) then begin ShowMsg('PART requires at least 4 data bins'); exit; end; lnSliceVox := lnVolVox div lnSlices; if (lnVolVox mod lnSlices) <> 0 then begin ShowMsg('PART requires volvox to be evenly divisible by number of slices.'); exit; end; lSamplesWithVariance := 0; lCorrectedSamples := 0; QuartileTriggerSpacing(lPhysio); //find number bin range - this is median-1.5IQR..median+1.5IQR lBinMin := -lPhysio.TriggerMedian/2-(abs(lPhysio.TriggerQ1-lPhysio.TriggerQ3)*0.75); lBinMax := +lPhysio.TriggerMedian/2+abs(lPhysio.TriggerQ1-lPhysio.TriggerQ3)*0.75; //next - create bins lnBin := lBinIn; //could adjust number of bins and return here wth a label lBinWidth := abs((lBinMax-lBinMin)/(lnBin-1));//lnBin-1: fenceposts vs wire lnBinDiv2 := (lnBin div 2)+1; getmem(lBinCountRA,lnBin*sizeof(integer)); getmem(lBinEstimateRA,lnBin*sizeof(double)); getmem(lVolBinRA,lImgVol*sizeof(integer)); lVoxel := 0; for lSlice := 1 to lnSlices do begin //adjust slices so slice 1 occurs at 0, slice 2 at 1/nslices... lSliceTime := ((lSlice-1)/lnSlices)-1; //-1 as 1st volume starts at zero, not 1 //do next step for each slice - different slices have different bin distributions due to different slicetime //next count number of samples in each bin for lBin := 1 to lnBin do lBinCountRA^[lBin] := 0; lPrevTriggerTime := -MaxInt; lNextTrigger := 1; for lSample := 1 to lImgVol do begin //for each sample, find nearest trigger lOnsetTime := lSample+lSliceTime; if lOnsetTime > lPhysio.TriggerRA^[lNextTrigger] then begin while (lNextTrigger <= lPhysio.Triggers ) and (lOnsetTime > lPhysio.TriggerRA^[lNextTrigger]) do begin lPrevTriggerTime := lPhysio.TriggerRA^[lNextTrigger]; inc(lNextTrigger); end; //while end;//if onset > lTimeSinceTrigger := lOnsetTime-lPrevTriggerTime; if lTimeSinceTrigger > abs(lPhysio.TriggerRA^[lNextTrigger]-lOnsetTime) then lTimeSinceTrigger := -abs(lPhysio.TriggerRA^[lNextTrigger]-lOnsetTime);//use abs in case we are past final trigger //now compute bin... //inc(lCorrectedSamples); if (lTimeSinceTrigger > lBinMin) and (lTimeSinceTrigger < lBinMax) then begin lBin := round( (lTimeSinceTrigger)/ lBinWidth)+lnBinDiv2; lVolBinRA^[lSample] := lBin; if (lBin < 1) or (lBin > lnBin) then fx(-661,lBin,lTimeSinceTrigger) else inc(lBinCountRA^[lBin]); end else lVolBinRA^[lSample] := 0; end; //for each volume for lSlicePos := 1 to lnSliceVox do begin inc(lVoxel); //first - only correct voxels with variability - do not waste time outside brain lVolOffset := lVoxel; lVariance := false; lSample := 1; lV := lImgData^[lVolOffset]; while (not lVariance) and (lSample <= lImgVol) do begin if lV <> lImgData^[lVolOffset] then lVariance := true; inc(lSample); lVolOffset := lVolOffset+lnVolVox; end; //while no variance if lVariance then begin //voxel intensity varies accross time - attempt to remove artifact lSamplesWithVariance := lSamplesWithVariance +lImgVol; //1st - sum effects for lBin := 1 to lnBin do lBinEstimateRA^[lBin] := 0; lMeanSignal := 0; lVolOffset := lVoxel; for lSample := 1 to lImgVol do begin lMeanSignal := lImgData^[lVolOffset] + lMeanSignal; lBin := lVolBinRA^[lSample]; if (lBin > 0) and (lBinCountRA^[lBin] > kMinSamplesPerBin) then lBinEstimateRA^[lBin] := lBinEstimateRA^[lBin]+ lImgData^[lVolOffset]; lVolOffset := lVolOffset+lnVolVox; end; //for each volume lMeanSignal := lMeanSignal /lImgVol; //next compute correction... average signal in bin - average voxel intensity irrelevant of bin for lBin := 1 to lnBin do if lBinCountRA^[lBin] > kMinSamplesPerBin then lBinEstimateRA^[lBin] := (lBinEstimateRA^[lBin]/lBinCountRA^[lBin])-lMeanSignal; //lBinEstimateRA[lBin] := lBinEstimateRA[lBin]-lBinMeanCount; //next apply correction - inner loop complete for each voxel! lVolOffset := lVoxel; for lSample := 1 to lImgVol do begin //for each sample, find nearest trigger lBin := lVolBinRA^[lSample]; if (lBin > 0) and (lBinCountRA^[lBin] > kMinSamplesPerBin) then begin lImgData^[lVolOffset] := (lImgData^[lVolOffset]-lBinEstimateRA^[lBin]); inc(lCorrectedSamples) end; lVolOffset := lVolOffset+lnVolVox; end; //for each volume end; //if variance end;//for each voxel in slice end; //for slice //**INNER LOOP end - //next - report results result :=' Time per vol (TR) [sec] '+realtostr(lTRsec,4)+kCR; result :=result +' fMRI Volumes '+inttostr(lImgVol)+kCR; result :=result +' Triggers n/First...Last [vol] '+realtostr(lPhysio.Triggers,0)+'/'+realtostr(lPhysio.TriggerRA^[1],2)+'...'+realtostr(lPhysio.TriggerRA^[lPhysio.Triggers],2)+kCR; if abs(lImgVol-lPhysio.TriggerRA^[lPhysio.Triggers]) > 10 then begin result :=result +'******* WARNING: Duration of fMRI session and duration of triggers is very different *******'; result :=result +'******* Please ensure specified TR is correct, files are correct and onset of fMRI was synchronized with physio data *******'; end; result := result + ' Q1/Median/Q2 [sec] '+realtostr(lTRsec*lPhysio.TriggerQ1,2)+'/'+realtostr(lTRsec*lPhysio.TriggerMedian,2)+'/'+realtostr(lTRsec*lPhysio.TriggerQ3,2)+kCR; result := result + ' Bin n/Range [sec] '+inttostr(lnBin)+'/'+realtostr(lTRsec*lBinMin,2)+ '...'+realtostr(lTRsec*lBinMax,2)+kCR; result := result+ ' voxels without variance (outside brain) %: '+realtostr(100*( (lnVolVox-(lSamplesWithVariance/lImgVol))/lnVolVox),2)+kCR; if lSamplesWithVariance > 0 then result := result+ ' voxels with variance which were corrected %: '+realtostr(100*(lCorrectedSamples/lSamplesWithVariance),2)+kCR; for lBin := 1 to lnBin do result := result+(' Bin '+inttostr(lBin)+ ' '+realtostr(lBin*lBinWidth+lBinMin ,2) +' '+inttostr(lBinCountRA^[lBin]) )+kCR; freemem(lBinCountRA); freemem(lBinEstimateRA); freemem(lVolBinRA); end; function StrVal (var lNumStr: string): integer; begin try result := strtoint(lNumStr); except on EConvertError do begin ShowMsg('StrVal Error - Unable to convert the string '+lNumStr+' to a number'); result := MaxInt; end; end; end; procedure AddSample(var lNumStr: string; var lnTotal,lnSample, lnTrigger: integer; var lPhysio: TPhysioT); var lVal: integer; begin lVal := StrVal(lNumStr); if lVal = 5003 then exit; lNumStr := ''; inc(lnTotal); if lnTotal < 5 then exit; if lVal > 4096 then begin if lVal <> 5000 then begin ShowMsg('Potentially serious error: unknown trigger type : '+inttostr(lVal)); end; inc(lnTrigger); if (lPhysio.Triggers <> 0) then lPhysio.TriggerRA^[lnTrigger] := lnSample; end else begin inc(lnSample); end; end; function AdjustStartPos (var lStr: string; var lStartPos: integer): boolean; //Some Siemens physio files appear to have nonsense characters befor real data<bh:ef><bh:bb><bh:bf>1 var lLen: integer; begin lLen := length(lStr); result := false; if (lLen-lStartPos)<2 then exit; result := true; repeat if lStr[lStartPos] in [ '0'..'9'] then exit; inc(lStartPos); until (lStartPos = lLen); result := false; end; procedure CountValidItems(var lStr: string; var lStartPos,lnSample, lnTrigger: integer; var lPhysio: TPhysioT); label 123; var lPos,lnTotal: integer; lNumStr: string; begin lnTotal:= 0; lnSample := 0; lnTrigger := 0; lNumStr := ''; if length(lStr)<2 then exit; if not AdjustStartPos ( lStr, lStartPos) then exit; //Oct 2009 for lPos := lStartPos to length(lStr) do begin if (lStr[lPos] = ' ') and (lNumStr <> '') then begin if lNumStr = '5003' then begin lNumStr := ''; goto 123; //end of recording end else AddSample(lNumStr, lnTotal,lnSample, lnTrigger, lPhysio); end else begin if lStr[lPos] in [ '0'..'9'] then lNumStr := lNumStr + lStr[lPos] else if lStr[lPos] in [' '] then else begin //Showmessage(lStr[lPos]); goto 123; end; end; end; //for length 123: if (lNumStr <> '') then AddSample(lNumStr, lnTotal,lnSample, lnTrigger, lPhysio); lStartPos := lPos; while (lStartPos < length(lStr)) and ( lStr[lStartPos] <> ' ') do begin inc(lStartPos); end; end; procedure CreatePhysio (var lPhysio: TPhysioT); begin lPhysio.Triggers := 0; end; procedure ClosePhysio (var lPhysio: TPhysioT); begin with lPhysio do begin if Triggers > 0 then freemem(TriggerRA); Triggers := 0; end; end; procedure InitPhysio(lnTrigger: integer; var lPhysio: TPhysioT); begin ClosePhysio (lPhysio); with lPhysio do begin Triggers := lnTrigger; InterpolatedTriggers := 0; if Triggers > 0 then getmem(TriggerRA,Triggers*sizeof(single)); end; end; function load3ColTxtPhysio (lFilename: string; var lPhysio: TPhysioT): boolean; var F: TextFile; lnTrigger: integer; lFloat,lFloat2,lFloat3: single; begin result := false; if not fileexists(lFilename) then exit; ClosePhysio(lPhysio); AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //pass 1 - count number of triggers lnTrigger := 0; Reset(F); while not EOF(F) do begin {$I-} read(F,lFloat,lFloat2,lFloat3); //read triplets instead of readln: this should load UNIX files {$I+} if (ioresult = 0) and (lFloat > 0) then inc(lnTrigger); end; //pass 2 - load array InitPhysio(lnTrigger, lPhysio); lnTrigger := 0; Reset(F); while not EOF(F) do begin {$I-} read(F,lFloat,lFloat2,lFloat3); //read triplets instead of readln: this should load UNIX files {$I+} if (ioresult = 0) and (lFloat > 0) then begin inc(lnTrigger); lPhysio.TriggerRA^[lnTrigger] := lFloat; end; end; FileMode := 2; //Set file access to read/write CloseFile(F); result := true; end; procedure ReadlnX (var F: TextFile; var lResult: string); var lCh: char; begin lResult := ''; while not Eof(F) do begin Read(F, lCh); if (lCh in [#10,#13]) then begin if lResult <> '' then begin //Showmessage(lResult); exit; end; end else lResult := lResult + lCh; end; end; //ReadlnX function loadSiemensPhysio (lFilename: string; var lPhysio: TPhysioT): boolean; var F: TextFile; lStr: string; lPos,lnSample,lnTrigger: integer; begin result := false; if not fileexists(lFilename) then exit; ClosePhysio(lPhysio); AssignFile(F, lFilename); FileMode := 0; //Set file access to read only Reset(F); ReadlnX(F,lStr);//ColNames if length(lStr) < 1 then begin CloseFile(F); exit; end; //first pass - count items lPos := 1; CountValidItems(lStr,lPos,lnSample,lnTrigger,lPhysio); //second pass - load array if (lnSample < 1) and (lnTrigger < 1) then begin CloseFile(F); exit; end; //2nd pass... InitPhysio(lnTrigger, lPhysio); lPos := 1; CountValidItems(lStr,lPos,lnSample,lnTrigger,lPhysio); FileMode := 2; //Set file access to read/write CloseFile(F); result := true; end; function InterpolateGaps (var lPhysioIn: TPhysioT): boolean; //attempts to fill missing trigger pulses //you must call QuartileTriggerSpacing before this function! // it assumes q1/median/q3 are filled var lGap,l2Min,l2Max,l3Min,l3Max: double; lnReplace,lTrigger,lTrigger2: integer; lTempPhysio: TPhysioT; begin result := false; if (lPhysioIn.Triggers < 4) then begin ShowMsg('InterpolateGaps requires at least 4 triggers.'); exit; end; l2Min := 2*lPhysioIn.TriggerMedian-(abs(lPhysioIn.TriggerQ1-lPhysioIn.TriggerQ3)*1.5); l2Max := 2*lPhysioIn.TriggerMedian+(abs(lPhysioIn.TriggerQ1-lPhysioIn.TriggerQ3)*1.5); l3Min := 3*lPhysioIn.TriggerMedian-(abs(lPhysioIn.TriggerQ1-lPhysioIn.TriggerQ3)*1.5); l3Max := 3*lPhysioIn.TriggerMedian+(abs(lPhysioIn.TriggerQ1-lPhysioIn.TriggerQ3)*1.5); if l2Max > l3Min then exit; //variability too high to determine gaps lnReplace := 0; for lTrigger := 2 to lPhysioIn.Triggers do begin lGap := lPhysioIn.TriggerRA^[lTrigger] - lPhysioIn.TriggerRA^[lTrigger-1]; if (lGap > l2Min) and (lGap < l2Max) then inc(lnReplace); if (lGap > l3Min) and (lGap < l3Max) then inc(lnReplace,2); end; if lnReplace = 0 then begin result := true; exit; end; //create temp backup CreatePhysio(lTempPhysio); InitPhysio(lPhysioIn.Triggers, lTempPhysio); for lTrigger := 1 to lPhysioIn.Triggers do lTempPhysio.TriggerRA[lTrigger] := lPhysioIn.TriggerRA[lTrigger]; //create resized array InitPhysio(lTempPhysio.Triggers+lnReplace, lPhysioIn); //fill gaps lPhysioIn.TriggerRA[1] := lTempPhysio.TriggerRA[1]; lTrigger2 := 1; for lTrigger := 2 to lTempPhysio.Triggers do begin inc(lTrigger2); lGap := lTempPhysio.TriggerRA^[lTrigger] - lTempPhysio.TriggerRA^[lTrigger-1]; if ((lGap > l2Min) and (lGap < l2Max)) then begin //1 beat lPhysioIn.TriggerRA^[lTrigger2] := lTempPhysio.TriggerRA^[lTrigger-1]+(lgap / 2); inc(lTrigger2); end; if ((lGap > l3Min) and (lGap < l3Max)) then begin //2 beats lPhysioIn.TriggerRA^[lTrigger2] := lTempPhysio.TriggerRA^[lTrigger-1]+(lgap / 3); inc(lTrigger2); lPhysioIn.TriggerRA^[lTrigger2] := lTempPhysio.TriggerRA^[lTrigger-1]+(2*lgap / 3); inc(lTrigger2); end; lPhysioIn.TriggerRA^[lTrigger2] := lTempPhysio.TriggerRA^[lTrigger]; end; ClosePhysio (lTempPhysio); lPhysioIn.InterpolatedTriggers := lnReplace; result := true; end; function ScalePhysioToTime(lPhysio: TPhysioT; lSamplesPerUnit: single): boolean; var lScale: single; lTrigger: integer; begin result := false; if (lPhysio.Triggers < 4) then begin ShowMsg('ScalePhysioToTR requires at least 4 triggers.'); exit; end; if (lSamplesPerUnit <= 0) then begin ShowMsg('ScalePhysioToTime requires TR(sec) and samples/sec >0.'); exit; end; lScale := 1/(lSamplesPerUnit); //use reciprocal: mults faster than divides for lTrigger := 1 to lPhysio.Triggers do lPhysio.TriggerRA^[lTrigger] := lPhysio.TriggerRA^[lTrigger] * lScale; result := true; end; procedure EnsureAscending(lPhysio: TPhysioT); //check if order is correct - if not the sort... //an alternative is to always sort, but this method is faster and less resource intensive for sorted data var lPos: integer; begin if lPhysio.Triggers < 2 then exit; for lPos := 2 to lPhysio.Triggers do begin if lPhysio.TriggerRA^[lPos] < lPhysio.TriggerRA^[lPos-1] then begin ShowMsg('Warning: input times are not in ascending order - data will be sorted.'); qsort(1,lPhysio.Triggers,lPhysio.TriggerRA); //ensure trigger timings are in order... exit; end; end; end; function ApplyPart( lFilename: string;lImgData: singleP; lBins,lVolVox,lSlices, lImgVol : integer; lTRsec: single): string; var lPhysio: TPhysioT; begin result := ''; if not fileexists (lFilename) then exit; CreatePhysio(lPhysio); if UpCaseExt(lFilename) = '.TXT' then begin if not load3ColTxtPhysio(lFilename,lPhysio) then exit; end else if not loadSiemensPhysio(lFilename,lPhysio) then exit; EnsureAscending(lPhysio); QuartileTriggerSpacing(lPhysio); if not InterpolateGaps (lPhysio) then exit; if UpCaseExt(lFilename) <> '.TXT' then begin//export Siemens file as 3-column text ScalePhysioToTime(lPhysio,50); //50: siemens files use 50 Hz sampling -> convert to sec SaveTriggersAs3ColumnFSL(lPhysio,lFilename); //do this before TR conversion... end; ScalePhysioToTime(lPhysio,lTRsec); //Convert sec to volumes result := PARTool (lPhysio,lImgData,lTRsec,lVolVox,lSlices, lImgVol, lBins); ClosePhysio(lPhysio); end; end. �������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/tfce_clustering.7z���������������������������������������������0000755�0001750�0001750�00000004071�12110676124�020441� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������7z'�Ip������h�������z0�:bA.٘ '&E񚯬mK**s1dfF lX꿖KQ9&{J:`Ac$Q!Wfi`#*ELL꘎ eTR4>Wc17(׸նR~}e^k+PqݎNYC\7*s^!i?rA>NE7X tie #hsLv1M+}P_5)wtqYEzPuK6zi>l= 95\tB\pSSÞt�j}ފd}Ş|2^-G団V@kVt+3(Rk+/6ėlgFB{GˊaQx8tT*zL2?> Cb`~O͙58bɿf2Ib'F,X.Ĺ *|H9c<<($ޮp$*Pt )]}F,$QJNJу߿`tH ;z1.~_rˏO=`hǟKcjgy:*.G}e^ n!W/\UDIBE ~jV|.Ma+*v94J;Qr(ʲU'Fý=vgKd/D; (-e4>m&]E'%[^1z * ;RZZMȪ |nG�56:\YT#W W,X2s @W0bQg;JH7iM$@i2PoUfd=VG XBrއwYDS4r[Bw r$Â0^, Cڼ`*ff :_+V0̩7ud(9ſSy=�̩U/"(5/R<a8yyڔ VDQo@^H*튔/kvz(NYK1s+iByٟd/7.l[}j7gWdB78kIvkr9Cѐ8u)~$EȚ\44ЋlXE)EW/žF_3dQE,;WE3Cf9㙼ʖ J><¤$߳1Fiq6~D!ƛ蝃Cɭb #nZo!2wAv{vtңUIH) D H+�uOGaVdž$ʨGԥݹU"+(quMd*'oΊ^.6=i6lNhvıdHw_@bO/ޜ[S<g~P4q5"6g@!+z0O<'H;o[,Wotô(giKK; -1#ෛ)r1V :!8z]Ϋk'肽U/F*^ mۉ T�SRWg 8H !)Y[H` Ԟ q0L]�Q؃~ y捐�TC(0Wi^D)@sKOG9r/&/_*3RϱWg9QՎS3z=sť٣|S2S6?@QhCr?-\ܣZD[qpJ.ЗڞBVd Yl 0[+f܁^˛bͿ ^_ïS/kR힍'j}XA;"?, QSN.na9C$}5ZLpuK4:E->^(ZZa~\ab�%b7yK{O"8Fϰ_UyF GFPkH{хmT0I&X9�|h z R^�� � �#]��� � SC��)�t�f�c�e�_�c�l�u�s�t�e�r�i�n�g�.�p�a�s��� ��2Y7� ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/ReadInt.pas����������������������������������������������������0000755�0001750�0001750�00000002363�11540170630�017031� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit ReadInt; interface uses {$IFDEF FPC} LResources,{$ENDIF} Buttons{only Lazarus?},SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Spin; type TReadIntForm = class(TForm) ReadIntEdit: TSpinEdit; ReadIntLabel: TLabel; OKBtn: TButton; function GetInt(lStr: string; lMin,lDefault,lMax: integer): integer; procedure OKBtnClick(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var ReadIntForm: TReadIntForm; implementation {$IFNDEF FPC} {$R *.DFM} {$ENDIF} function TReadIntForm.GetInt(lStr: string; lMin,lDefault,lMax: integer): integer; begin //result := lDefault; ReadIntLabel.caption := lStr+' ['+inttostr(lMin)+'..'+inttostr(lMax)+']'; ReadIntEdit.MinValue := lMin; ReadIntEdit.MaxValue := lMax; ReadIntEdit.Value := lDefault; ReadIntForm.ShowModal; result := ReadIntEdit.Value; end; procedure TReadIntForm.OKBtnClick(Sender: TObject); begin ReadIntForm.ModalResult := mrOK; end; procedure TReadIntForm.FormCreate(Sender: TObject); begin end; {$IFDEF FPC} initialization {$I ReadInt.lrs} {$ENDIF} end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/Copy of prefs.pas����������������������������������������������0000755�0001750�0001750�00000021432�11326425446�020112� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit prefs; {$H+} interface uses inifiles, define_types,SysUtils,classes; type TPrefs = record UnusedBool: boolean; Test, Permutations,CritPct: integer; end; const knotest = 0; //no test specified kltest = 1;//binomial Liebermeister test kttest = 2; //t-test kbmtest = 4;//Bruneer-Mnuzel test klrtest = 8; //logisitic regression test //procedure ReadIni(var lIniName: string; var lPrefs: TPrefs); procedure SetDefaultPrefs (var lPrefs: TPrefs); //procedure SaveIni (var lIniName: string; var lPrefs: TPrefs); //procedure CorrectPrefs (var lPrefs: TPrefs); //ensures only usable file types are created procedure ReadParamStr; implementation uses nifti_img, hdr,nifti_hdr; procedure Msg(lStr: string); begin // end; procedure SetDefaultPrefs (var lPrefs: TPrefs); begin lPrefs.unusedbool := true; lPrefs.Test := knotest; lPrefs.Permutations := 0; lPrefs.CritPct := 0; end; function CheckBool (lPref, lFlag: integer): boolean; //check if Flag is ni lPref. For example, if Flag is 1 then returns true for all odd lPrefs begin result := (lPref and lFlag) = lFlag; end; function DoLesion (lPrefs: TPrefs): boolean; label 666; const kSimSampleSize = 64; knSim = 100; kCrit = 3; var //lBinomial: boolean; lSim,lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCrit,lnControlObservations: integer; lPartImageNames,lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lOutName,lFactname,lOutNameSim: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA,lPartSymptomRA,lControlSymptomRA: singleP; begin result := false; //lBinomial := not odd( (Sender as tMenuItem).tag); if (not CheckBool(lPrefs.test ,kltest)) and (not CheckBool(lPrefs.test, kttest)) and (not CheckBool(lPrefs.test, kbmtest)) then begin Msg('Error: you need to compute at least on test [options/test menu]'); exit; end; lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? lPartImageNames := TStringList.Create; getmem(lPartSymptomRA,kSimSampleSize*sizeof(single)); lnControlObservations := 20; getmem(lControlSymptomRA,lnControlObservations*sizeof(single)); for lSim := 1 to lnControlObservations do lControlSymptomRA[lSim] := 5; //next, get 1st group if not MainForm.GetVal(lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCrit,lBinomial,lPredictorList) then begin showmessage('Error with VAL file'); goto 666; end; lTemp4D := MainForm.CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) then begin Showmessage('Not enough subjects ('+inttostr(lnSubjAll)+') or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not MainForm.CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; MainForm.SaveHdrDlg.Filename := loutname; lOutName := lOutName+'.nii.gz'; if not MainForm.SaveHdrName ('Base Statistical Map', lOutName) then goto 666; for lFact := 1 to lnFactors do begin lImageNames.clear; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); lnSubj := lImageNames.Count; if lnSubj > 1 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; //randomization loop.... for lSim := 1 to knSim do begin RandomGroup(kSimSampleSize, lImageNames,lSymptomRA, lPartImageNames, lPartSymptomRA); lOutNameSim := AddIndexToFilename(lOutName,lSim); lnCrit := kCrit; MainForm.NPMMsgClear; //Msg(GetKVers); MainForm.NPMMsg('Threads: '+inttostr(gnCPUThreads)); lFactName := lPredictorList.Strings[lFact-1]; lFactName := MainForm.LegitFilename(lFactName,lFact); MainForm.NPMMsg('Factor = '+lFactname); For lSubj := 1 to kSimSampleSize do MainForm.NPMMsg (lPartImageNames.Strings[lSubj-1] + ' = '+realtostr(lPartSymptomRA^[lSubj],2) ); MainForm.NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); MainForm.NPMMsg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); MainForm.NPMMsg('Number of Lesion maps = '+inttostr(kSimSampleSize)); if not MainForm.CheckVoxelsGroup(lPartImageNames,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; if lBinomial then MainForm.LesionNPMAnalyzeBinomial(lPartImageNames,lMaskHdr,lnCrit,lPartSymptomRA,lFactname,lOutNameSim) else begin MainForm.ReportDescriptives(lPartSymptomRA,lnSubj); //LesionNPMAnalyze2(lImageNames,lMaskHdr,lnCrit,-1,lSymptomRA,lFactName,lOutname); LesionNPMAnalyze2(lPartImageNames,lMaskHdr,lnCrit,lSim{-1},MainForm.ReadPermute,lPartSymptomRA,lFactName,lOutNameSim,lTTest,lBM); end; end; //for each simulation... Freemem(lSymptomRA); end; //lnsubj > 1 end; //for each factor if lnSubjAll > 0 then begin Freemem(lMultiSymptomRA); end; result := true; 666: lPartImageNames.free; lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; freemem(lPartSymptomRA); MainForm.DeleteDecompressed4D(lTemp4D); end; procedure ReadParamStr; var lStr: String; I,lError: integer; //lResult,lHelpShown : boolean; lCommandChar: Char; //I,lError: integer; lSingle: single; //lOrigWinWid,lOrigWinCen: Integer;*) lPrefs: TPrefs; begin SetDefaultPrefs(lPrefs); lStr := paramstr(0); lStr := extractfilename(lStr); lStr := string(StrUpper(PChar(lStr))) ; {$IFDEF PNG} if (lStr = 'DCM2PNG.EXE') then gOutputFormat := kPNG; {$ENDIF} if (ParamCount > 0) then begin I := 0; repeat lStr := ''; repeat inc(I); if I = 1 then lStr := ParamStr(I) else begin if lStr <> '' then lStr := lStr +' '+ ParamStr(I) else lStr := ParamStr(I); end; if (length(lStr)>1) and (lStr[1] = '-') and (ParamCount > I) then begin //special command //-z= zoom, -f= format [png,jpeg,bmp], -o= output directory lCommandChar := UpCase(lStr[2]); inc(I); lStr := ParamStr(I); lStr := string(StrUpper(PChar(lStr))) ; case lCommandChar of 'C','P','T': begin //CritPct Val(lStr,lSingle,lError); if lError = 0 then begin if lCommandChar = 'C' then lPrefs.CritPct := round(lSingle) else if lCOmmandChar = 'P' then lPrefs.Permutations := round(lSingle) else if lCOmmandChar = 'T' then lPrefs.Test := round(lSingle); end; //not lError end; //C= CritPct end; //case lStr[2] lStr := ''; end; //special command until (I=ParamCount) or (fileexists(lStr)) {or (gAbort)}; if fileexists(lStr) then begin //lStr := GetLongFileName(lStr); xxx end else if not (gSilent) then begin MyWriteln('0 dcm2jpg ERROR: unable to find '+lStr); if lHelpShown then MyReadln else Showhelp; lHelpShown := true; end; until I >= ParamCount; end else begin //begin test routines.... (* lStr := 'D:\yuv2.dcm'; ResetDCMvalues; lOrigWinWid := gWinWid; lOrigWinCen := gWinCen; LoadData(lStr); gWinWid := lOrigWinWid; gWinCen := lOrigWinCen; //...end test routines(**) ShowHelp; end;{param count > 0} end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/firth.pas������������������������������������������������������0000755�0001750�0001750�00000036373�12203546532�016634� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit firth; interface uses {$Include ..\common\isgui.inc} //ComCtrls,Classes, Graphics, ExtCtrls, //{$IFDEF FPC}ComCtrls, {$ENDIF} {$IFDEF GUI} ComCtrls,{$ENDIF} //progressbar classes,define_types,{stats,}StatThdsUtil,lesion_pattern,Mat,Math,Distr,Vector,dialogsx, unpm, SysUtils; procedure FirthAnalyzeNoThread(lnCond, lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: bytep;lOutImgMn,lSymptomRA: SingleP;lOutImg: SingleRAp); implementation procedure VisualProg(lPos,lTestNumber: Integer); begin NPMTitleMsg(inttostr(lTestNumber)); NPMProgressBar( lPos); end; var finalloglik: SingleP0; KxKA1,KxKB1,KxKA,KxKB :TMatrix; Kvec,Kvec1 : TVector; Kveci,kVeci1 : TVectori; betak,xbeta,yin,pi,ustar, XXx,XXXW2,XXFisher,XXcovs,XXXWPrime, deltahalfs,deltat,delta,covs,x,Fisher,XW2,W,XWprime,Hprime,H,ustarmat,negx: TMatrix; lBarX: TProgressBar; lnCondx,lnCritx,lBarPosX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx,lImagesCountx : integer; lPlankImgx: byteP;lOutImgMnx,lSymptomRAx: SingleP; lOutImgX: SingleRAp; procedure logistfx (xin: SingleP; var lZvals: SingleP0; numSubj,numCond: integer; lComputeIntercept: boolean); //todo zero output incase exit //yin = 1..numSubj binary 0/1 values //xin = numSubj*numCond predictors //Chivals = 0..numCond p-values - the 0th Khi-value is the intercept // [0th value will not be computed if ; lComputeIntercept= false] label 123,666; const maxit = 25; maxhs = 5; epsilon = 0.0001; maxstep = 10; var SumY0,SumY1,mx, beta0,loglik,loglikold: double; sumy, n, i,j, k, iter,halfs,lCond,dropCond: integer; variability,firth: boolean; procedure crossprodustar; var inc,row: integer; begin for row := 1 to k do begin ustarmat[row,1] := 0; for inc := 1 to ustar.r do ustarmat[row,1] := ustarmat[row,1] + (x[row,inc]*ustar[inc,1]); end; end; procedure Diag2Vec; var inc: integer; begin for inc := 1 to pi.r do ustar[inc,1] := ustar[inc,1]+ H[inc,inc]*(0.5-pi[inc,1]); end; //nested DiagP2 procedure DiagP2 (var W, P: TMatrix); var inc: integer; begin W.Zero; for inc := 1 to P.r do W[inc,inc] := Power((P[inc,1] * (1-P[inc,1])),0.5) ; end; //nested DiagP2 procedure ComputeFisher; begin DiagP2(W,pi); XW2.mult(x,W); //XWPrime.copy( XW2); //XWPrime.transpose; XWPrime.transpose(XW2); Fisher.mult(XW2,XWPrime); covs.copy( Fisher); covs.Invert2(KxKA,KxKB,Kvec,Kveci) end; //nested computeFisher procedure computedropdelta; var jinc,iinc,ii,jj: integer; begin DiagP2(W,pi); XXXW2.mult(XXx,W); //XXXWPrime.copy( XXXW2); //XXXWPrime.transpose; XXXWPrime.transpose(XXXW2); XXFisher.mult(XXXW2,XXXWPrime); XXcovs.copy( XXFisher); //XXcovs.Invert; XXcovs.Invert2(KxKA1,KxKB1,Kvec1,Kveci1); covs.Zero; ii := 0; for iinc := 1 to (k) do begin if iinc <> (dropCond+1) then begin //leave the specified column zeros... inc(ii); jj := 0; for jinc := 1 to (k) do begin if jinc <> (dropCond+1) then begin inc(jj); covs[iinc,jinc] := xxCovs[ii,jj]; end; end; end; end; end; function firthpenalty: double; begin ComputeFisher; //result := 0.5 * ln(abs(Fisher.det)); result := 0.5 * ln(abs(Fisher.Det2(KxKA,kVeci,kVec))); end; //nested firthpenalty function ComputeLogLik: double; var inc: integer; lDenom: double; begin xbeta.mult(betak,negx); for inc := 1 to n do begin lDenom := (1 + exp( xbeta[inc,1])); if lDenom = 0 then showMsg('yikes') else pi[inc,1] := 1/lDenom; end; result := 0; for inc := 1 to n do if yin[inc,1] = 1 then //if pi[inc,1] <> 1 then result := result+ln(pi[inc,1]); for inc := 1 to n do if yin[inc,1] = 0 then //if pi[inc,1] <> 1 then result := result+ln(1-pi[inc,1]); if firth then result := result + firthpenalty; end;//nested ComputeLogLik begin for i := 0 to (numCond) do lZVals^[i] := 0; // if (numSubj < 2) or (numCond < 1) then exit; //ensure there is some variability in the input data... variability := false; i := 1; repeat inc(i); if xin^[i] <> xin^[1] then variability := true; until (i= (numSubj*numCond)) or (variability); if not variability then exit; //no variance in the regressors... variability := false; i := 1; repeat inc(i); if yin[i,1] <> yin[1,1] then variability := true; until (i= (numSubj)) or (variability); if not variability then exit; //no variance in the dependent variable... dropCond := -1; //initially compute full model, then compute effect of removing individual conditions firth := true; n := numSubj; k := numCond + 1; //get memory //beta := TMatrix.Create(n,1); //design our model //first row = 1: ell samples have equal weight for i := 1 to n do x.M[1,i] := 1; //next load model into x iter := 0; for j := 2 to k do for i := 1 to n do begin inc(iter); x.M[j,i] := xin^[iter]; end; //WriteMatrix('Observations',y); //WriteMatrix('Model',x); //negx is just sing-swapped - we will generate this as we use it a lot... for j := 1 to k do for i := 1 to n do begin negx.M[j,i] := -x.M[j,i]; end; //now start computations sumy := 0; for i := 1 to n do sumy := sumy + round(yin[i,1]); if (sumy <= 0) or (sumy >= n) then begin //serious error: no variability. This should have been detected earlier in the procedure when yin was tested for variability goto 666; end; beta0 := ln((sumy/n)/(1 - sumy/n));//initial estimate 123: //go here for each dropcond if DropCond >= 0 then begin betak.Ones; betak.mult( 0) //start with a null model... does not really make sense end else begin betak.zero; betak[1,1] := (beta0); end; iter := 0; if DropCond >= 0 then begin //drop one of the factors... if dropCond <> 0 then begin//include intercept for i := 1 to n do XXx.M[1,i] := 1; lCond := 1; end else lCond := 0; for j := 1 to NumCond do begin if j <> DropCond then begin inc(lCond); for i := 1 to n do XXx.M[lCond,i] := x.M[j+1,i]; end; //if j <> dropCond end; end;//if lDropCond >= 0 loglik := ComputeLogLik; repeat inc(iter); ComputeFisher; HPrime.mult(XWPrime,covs); H.mult(HPrime,XW2); //WriteMatrix(covs); ustar.Sub(yin,pi); if firth then Diag2Vec; crossprodustar; if dropCond >= 0 then // model with dropped factor computedropdelta; deltat.mult(covs,ustarmat); delta.transpose(deltat); mx := delta.MatAbsMax/MaxStep; if mx > 1 then delta.mult(mx);//scale delta betak.add(delta); loglikold := loglik; halfs := 1; while halfs <= maxhs do begin // Half-Steps //fx(iter,halfs,loglik); loglik := ComputeLogLik; deltahalfs.mult(delta,power(2,-halfs)); betak.sub(deltahalfs); if (loglik > loglikold) then break; inc(halfs); end; if delta.MatAbsMax <= epsilon then break; until (iter >= maxit); //fx(DropCond,loglik); //done with this model - record model fit if DropCond < 0 then finalloglik^[k] := loglik //full model else begin finalloglik^[DropCond] := loglik; //model with a factor removed end; if DropCond < numCond then begin inc(DropCond); if (DropCond = 0) and (not lComputeIntercept) then //only compute intercept model if requested inc(DropCond); goto 123; end; //finally - results //ResultsForm.Memo1.lines.add (inttostr(j)+' cases have Y=0, '+inttostr(n-j)+' cases have Y=1'); if lComputeIntercept then J := 0 else J := 1; for i := J to (k-1) do begin lZVals^[i] := abs(2*(finalloglik^[i]-finalloglik^[k])); //find direction of effect - does a larger value of the IV predict more zeros or ones lZVals^[i] := pNormalInv(ChiSq(lZVals^[i],1)); //we have now computed a Z scores - but Chi is one tailed, so all Z > 0... lets check direction Sumy0 := 0; Sumy1 := 0; for iter := 1 to n do begin if yin[iter,1] = 0 then Sumy0 := Sumy0 + x.M[i+1,iter] //+1: M indexed from 1, ZVal indexed from 0 else Sumy1 := Sumy1 + x.M[i+1,iter]; //+1 M indexed from 1 end; //compute means Sumy1 := Sumy1/sumy; Sumy0 := Sumy0/(n-sumy); if Sumy0 < Sumy1 then //negative z-scores: damage here predicts performance is BETTER lZVals^[i] := -lZVals^[i]; end; (*if lComputeIntercept then //intercept is the 0th value lChiVals[0] := abs(2*(finalloglik[0]-finalloglik[k])); for i := 1 to (k-1) do //k-1 as this is indexed from 0 lChiVals[i] := abs(2*(finalloglik[i]-finalloglik[k])); *) 666: end; //FirthAnalyzeNoThread (lnCond,lnCrit, lnPermute,1,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lPlankImg,lOutImgSum,lSymptomRA,lOutImg); procedure FirthAnalyzeNoThread(lnCond, lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: bytep;lOutImgMn,lSymptomRA: SingleP;lOutImg: SingleRAp); //calls logistf (yin,xin: SingleP; var lChivals: SingleP0; numSubj,numCond: integer); label 666; const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lObs: Bytep; lPrevZVals: array [1..knPrevPattern] of SingleP0; lZVals: SingleP0; lPatternPos,lC,lnLesion,lPosPct,lPos,lPos2,lPos2Offset,lnCritLocal,n,k: integer; (* myFile : TextFile; procedure Hdr2File; var myI: integer; begin for myI := 1 to (lImagesCount*lnCond ) do begin write(myFile, floattostr(lSymptomRA^[myI])+kTab); end; WriteLn(myFile, ''); end; procedure Data2File; var myI: integer; begin for myI := 1 to (lImagesCount ) do begin write(myFile, inttostr(round(yIn[myI,1]))+kTab); end; WriteLn(myFile, ''); end; *) begin //statthread (*Assign(myFile,'/Users/rorden/logreg.txt'); ReWrite(myFile); Hdr2File; *) lnCritLocal := lnCrit; if lnCritLocal < 1 then lnCritLocal := 1; Getmem(lObs,lImagesCount*sizeof(byte)); Getmem(lZVals,(lnCond+1)*sizeof(single)); for lPos := 1 to knPrevPattern do Getmem(lPrevZVals[lPos],(lnCond+1)*sizeof(single)); n := lImagesCount; k := lnCond + 1; yin:= TMatrix.Create(n,1); GetMem(finalloglik,(k+1)*sizeof(single));//finalloglik := TVector.Create(k+1); x := TMatrix.Create (k, n); betak:=TMatrix.Create(1,k); covs:=TMatrix.Create(k,k); delta:=TMatrix.Create(1,k); deltahalfs:=TMatrix.Create(1,k); deltat:=TMatrix.Create(k,1); Fisher:=TMatrix.Create(k,k); H:=TMatrix.Create(n,n); HPrime:=TMatrix.Create(n,k); negx:=TMatrix.Create(k,n); pi:=TMatrix.Create(n,1); ustar:=TMatrix.Create(n,1); ustarmat:=TMatrix.create(k,1); W:=TMatrix.Create(n,n); xbeta:=TMatrix.Create(1,n); XW2:=TMatrix.Create(k,n); //XWPrime:=TMatrix.Create(k,n); XWPrime:=TMatrix.Create(n,k); XXcovs:=TMatrix.Create(k-1,k-1); XXFisher:=TMatrix.Create(k-1,k-1); XXx:=TMatrix.Create(k-1,n); XXXW2:=TMatrix.Create(k-1,n); //XXXWPrime:=TMatrix.Create(k-1,n); XXXWPrime := TMatrix.Create ( n, k-1); KxKA := TMatrix.Create(k,k); KxKB := TMatrix.Create(k,k); Kvec := TVector.Create(k); Kveci := TVectori.Create(k); KxKA1 := TMatrix.Create(k-1,k-1); KxKB1 := TMatrix.Create(k-1,k-1); Kvec1 := TVector.Create(k-1); Kveci1 := TVectori.Create(k-1); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) or ((gnVoxTestedRA[lThread] mod 100) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100), gnVoxTestedRA[lThread]); lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; for lPos := 1 to lImagesCount do begin if lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2] = 0 then begin //no lesion yin[lPos,1] := 0; lObs^[lPos] := 0; end else begin //lesion inc(lnLesion); lObs^[lPos] := 1; yin[lPos,1] := 1; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCritLocal) and (lnLesion < lImagesCount) then begin lPattern := SetOrderX (lObs,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin //logistfx(lObs,lSymptomRA, lZvals, lImagesCount,lnCond,false); for lC := 1 to lnCond do lOutImg^[lC]^[lPos2Offset] := lPrevZvals[lPos]^[lC]; end else begin //new pattern - need to compute inc(gnVoxTestedRA[lThread]); //logistfx(lSymptomRA, lZvals, lImagesCount,lnCond,false); for lC := 1 to lnCond do lOutImg^[lC]^[lPos2Offset] := lZvals^[lC]; lPrevPatternRA[lPatternPos] := lPattern; for lC := 1 to lnCond do lPrevZVals[lPatternPos]^[lC] := lZvals^[lC]; inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; end; //new pattern end; //nlesion > nCritical end; //for each voxel //gMat := false; 666: freemem(lObs); for lPos := 1 to knPrevPattern do freemem(lPrevZVals[lPos]); freemem(lZVals); yin.free; x.free; betak.free; covs.free; delta.free; deltahalfs.free; deltat.free; Fisher.free; H.free; HPrime.free; negx.free; pi.free; ustar.free; ustarmat.Free; W.free; xbeta.free; XW2.free; XWPrime.free; XXcovs.free; XXFisher.free; XXx.free; XXXW2.free; XXXWPrime.free; KxKA.free; KxKB.free; Kvec.free; Kveci.free; KxKA1.free; KxKB1.free; Kvec1.free; Kveci1.free; freemem(finalloglik); end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/LesionStatThds.pas���������������������������������������������0000755�0001750�0001750�00000045334�12156646050�020430� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit LesionStatThds; {$Include ..\common\isgui.inc} interface uses // ComCtrls,Classes, Graphics, ExtCtrls, {$IFDEF GUI} ComCtrls,{$ENDIF} SysUtils, Classes, dialogsx, define_types,stats,StatThdsUtil,Brunner,lesion_pattern; type TLesionStatThread = class(TThread) private lBarX: TProgressBar; lttestx,lBMx: boolean; lnCritx,lBarPosX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx, lImagesCountx,lControlsx : integer; lPlankImgx:ByteP; lOutImgMnx,lOutImgBMx,lOutImgTx,lOutImgAUCX,lSymptomRAx: SingleP; //lBarX: TProgressBar; procedure DoVisualSwap; protected procedure Execute; override; procedure VisualProg(lPos: Integer); procedure Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg:bytep;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); virtual; abstract; public property Terminated; constructor Create(lBar: TProgressBar;lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg:ByteP;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); end; { Lesion - image reveals value } TLesionContinuous = class(TLesionStatThread ) protected procedure Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: byteP;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); override; end; TLesionBinom = class(TLesionStatThread ) protected procedure Analyze(lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: byteP;lOutImgMn,lOutImgL,lOutImgX,lOutImgAUC,lSymptomRA: SingleP); override; end; implementation (*procedure OutStr(lStr: string); var lOutname: string; f: TextFile; begin lOutname:='c:\fx.txt'; if fileexists(lOutname) then begin { open a text file } AssignFile(f, lOutname); Append(f); Writeln(f, lStr); Flush(f); { ensures that the text was actually written to file } { insert code here that would require a Flush before closing the file } CloseFile(f); end; end; *) Const Two32 = 4294967296.0 ; function GenRandThreaded(lRange: integer; var lRandSeed:comp): integer; //normal random function does not work well when threaded - randseed is changed by each thread const lFactor = $08088405 ; lTerm = 1 ; type lT = array [0..1] of longint ; var lX: extended; begin lRandSeed := lRandSeed*lFactor + lTerm; lT(lRandSeed)[1] := 0 ; // < May'04 was: RS := RS - Trunc(RS/Two32)*Two32 ; lX := lRandSeed/Two32 ; result := trunc((lRange)*lX); end; procedure GenPermuteThreaded (lnSubj: integer; var lOrigOrder,lRanOrder: DoubleP0; var lRandSeed:comp); var lInc,lRand: integer; lSwap: double; begin Move(lOrigOrder^,lRanOrder^,lnSubj*sizeof(double)); for lInc := lnSubj downto 2 do begin lRand := GenRandThreaded(lInc,lRandSeed); lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc-1]; lRanOrder^[lInc-1] := lSwap; end; end; procedure StatPermuteThreaded (lttest,lBM: boolean; lnSubj, lnGroup0,lnPermute,lThread: integer;var lOrigOrder: DoubleP0); var lInc: integer; lOutT,lDF,lBMz: double; lRS: Comp; lRanOrderp: pointer; lRanOrder: Doublep0; begin if (lnSubj < 1) or (lnPermute < 1) then exit; createArray64(lRanOrderp,lRanOrder,lnSubj); lRS := 128; for lInc := 1 to lnPermute do begin GenPermuteThreaded(lnSubj, lOrigOrder,lRanOrder,lRS); //generate random order of participants if lttest then begin TStat2 (lnSubj, lnGroup0, lRanOrder, lOutT); if lOutT > gPermuteMaxT[lThread,lInc] then gPermuteMaxT[lThread,lInc] := lOutT; if lOutT < gPermuteMinT[lThread,lInc] then gPermuteMinT[lThread,lInc] := lOutT; end; //compute ttest if lBM then begin //BMTest (lnSubj, lnGroup0, lRanOrder,lOutT); tBM (lnSubj, lnGroup0, lRanOrder,lBMz,lDF); lBMz := BMzVal (lnSubj, lnGroup0,lBMz,lDF); if lBMz > gPermuteMaxBM[lThread,lInc] then gPermuteMaxBM[lThread,lInc] := lBMz; if lBMz < gPermuteMinBM[lThread,lInc] then gPermuteMinBM[lThread,lInc] := lBMz; end; //compute BM end; freemem(lRanOrderp); end; procedure GenPermuteThreadedBinom (lnSubj: integer; var lOrigOrder,lRanOrder: ByteP0; var lRandSeed:comp); var lInc,lRand: integer; lSwap: byte; begin Move(lOrigOrder^,lRanOrder^,lnSubj); for lInc := lnSubj downto 2 do begin lRand := GenRandThreaded(lInc,lRandSeed); lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc-1]; lRanOrder^[lInc-1] := lSwap; end; end; procedure StatPermuteBinomialThreaded (lnSubj, lnGroup0,lnPermute,lThread: integer;var lOrigOrder: ByteP0); var lInc: integer; lOutP: double; lRS: Comp; lRanOrder: byteP0; //lRanOrderp: pointer; //lRanOrder: Doublep0; begin if (lnSubj < 1) or (lnPermute < 1) then exit; //createArray64(lRanOrderp,lRanOrder,lnSubj); getmem(lRanOrder,lnSubj); lRS := 128; for lInc := 1 to lnPermute do begin GenPermuteThreadedBinom(lnSubj, lOrigOrder,lRanOrder,lRS); //generate random order of participants (*if lChi2 then begin Chi2 (lnSubj, lnGroup0, lRanOrder, lOutT); if lOutT > gPermuteMaxT[lThread,lInc] then gPermuteMaxT[lThread,lInc] := lOutT; if lOutT < gPermuteMinT[lThread,lInc] then gPermuteMinT[lThread,lInc] := lOutT; end; //compute ttest if lLieber then begin*) //Liebermeister2bP (lnSubj, lnGroup0, lRanOrder,lOutP); Liebermeister2bP (lnSubj, lnGroup0, lRanOrder,lOutP); if (lOutP > 0) and (lOutP < gPermuteMinT[lThread,lInc]) then begin //negative correlation //fx(lOutP, gPermuteMinBM[lThread,lInc]); gPermuteMinT[lThread,lInc] := lOutP; end; if (lOutP < 0) and ( lOutP > gPermuteMaxT[lThread,lInc]) then //negative correlation gPermuteMaxT[lThread,lInc] := lOutP; //end; //compute BM end; freemem(lRanOrder); end; procedure TLesionStatThread .DoVisualSwap; begin lBarX.Position := lBarPosX; end; procedure TLesionStatThread .VisualProg(lPos: Integer); begin lBarPosX := lPos; {$IFDEF FPC}Synchronize(@DoVisualSwap); {$ELSE} Synchronize(DoVisualSwap);{$ENDIF} end; constructor TLesionStatThread .Create(lBar: TProgressBar; lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: byteP;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); begin lBarX := lBar; lttestx := lttest; lBMx:= lBM; lThreadX := lThread; lThreadStartX := lThreadStart; lThreadEndX := lThreadEnd; lStartVoxx := lStartVox; lVoxPerPlankx := lVoxPerPlank; lImagesCountX := lImagesCount; lControlsX := lControlsIn; lPlankImgx := lPlankImg; lOutImgMnx := lOutImgMn; lOutImgBMx := lOutImgBM; lOutImgTx := lOutImgT; lOutImgAUCx := lOutImgAUC; lSymptomRAx := lSymptomRA; lnPermuteX := lnPermute; lnCritX := lnCrit; FreeOnTerminate := True; inherited Create(False); //inherited Create(CreateSuspended); end; { The Execute method is called when the thread starts } procedure TLesionStatThread .Execute; begin Analyze(lttestx,lBMx, lnCritX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx,lImagesCountx,lControlsx,lPlankImgX,lOutImgMnx,lOutImgBMx,lOutImgTx,lOutImgAUCx,lSymptomRAx); end; procedure TLesionContinuous.Analyze (lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIN : integer; lPlankImg:bytep;lOutImgMn,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA: SingleP); //pattern variables const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lPrevZValsT,lPrevZValsBM,lPrevAUCVals: array [1..knPrevPattern] of Single; lPatternPos: integer; lLesionOrderp: bytep; //standard variables var lStr: string; lObstp,lObsp: pointer; lObst,lObs: Doublep0; lT,lBMz,lDF: Double; lObsB: bytep0; lnLesion,lnNoLesion,lPosPct,lPos,lPos2,lPos2Offset,lnControl, lnControlsPlusLesion,lnControlsPlusPatients : integer; begin //statthread //init patterns lnControl := abs(lControlsIn); if lControlsIn < 0 then begin //binomial getmem(lObsB, lImagesCount+lnControl); end; lnControlsPlusPatients := lImagesCount+lnControl; for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; //lMaxLesion := lImagesCount-lnCrit; getmem(lLesionOrderp, lImagesCount *sizeof(byte)); //now init standard variables createArray64(lObsp,lObs,lnControlsPlusPatients); lPosPct := (lThreadEnd-lThreadStart) div 100; //if lThread = 1 then // OutStr( inttostr(lThreadStart)+':'+inttostr(lThreadEnd)); //xxxxx for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; lnNoLesion := 0; for lPos := 1 to lImagesCount do begin if lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2] = 0 then begin //no lesion inc(lnNoLesion); lLesionOrderp^[lPos] := 0; lObs^[lnNoLesion-1] := lSymptomRA^[lPos]; end else begin //lesion inc(lnLesion); lLesionOrderp^[lPos] := 1; //lObs^[lImagesCount-lnLesion] := lSymptomRA^[lPos]; //note: lObs indexed from zero! lObs^[lImagesCount-lPos+lnNoLesion] := lSymptomRA^[lPos]; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) and (lnLesion < lImagesCount) then begin //when there are 0 lesions or all lesions there is no variability! inc(gnVoxTestedRA[lThread]); //now check if we have seen this precise lesion order recently... lPattern := SetOrderX (lLesionOrderp,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin //lesion pattern is not novel if lttest then lOutImgT^[lPos2Offset] := lPrevZvalsT[lPos]; if lBM then lOutImgBM^[lPos2Offset] := lPrevZvalsBM[lPos]; if lOutImgAUC <> nil then lOutImgAUC^[lPos2Offset] := lPrevAUCvals[lPos]; end else begin //lesion pattern is novel //record novel pattern inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; lPrevPatternRA[lPatternPos] := lPattern; lnControlsPlusLesion := lnControlsPlusPatients; if (lControlsIn > 0) {and (lnLesion > 0)} then begin //anaCOm createArray64(lObstp,lObst,lImagesCount); for lPos := 1 to lImagesCount do lObst^[lPos-1] := lObs^[lPos-1]; for lPos := 1 to lnLesion do lObs^[lPos-1+lnControl] := lObst^[lPos-1+lnNoLesion]; freemem(lObstP); for lPos := 1 to lnControl do lObs^[lPos-1] := lSymptomRA^[lPos+lImagesCount]; lnControlsPlusLesion := lnControl+lnLesion; lnNoLesion := {lnNoLesion +} lnControl; end;//controls (*if lPos2 = 2570879 then begin //xxxx for lPos := 1 to lImagesCount do begin outstr(inttostr(lPos)+'>'+floattostr(lObs^[lPos-1]) ); end; end;*) if lttest then begin if lControlsIn > 0 then begin//anacom TStat2Z (lnControlsPlusLesion, lnControl {lnNoLesion},lObs,lT); (* if lPos2 = 2570879 then begin outstr( floattostr(lT)+ ' '+inttostr(lnControl)); //xxxx for lPos := 1 to lnControlsPlusLesion do begin outstr(inttostr(lPos)+', '+floattostr(lObs^[lPos-1]) ); end; end; *) end else TStat2 (lnControlsPlusLesion, lnNoLesion, lObs,lT); lOutImgT^[lPos2Offset] := lT; lPrevZValsT[lPatternPos] := lT; end; if lBM then begin tBM (lnControlsPlusLesion, lnNoLesion, lObs,lBMz,lDF); lBMz := BMzVal (lnControlsPlusPatients, lnNoLesion,lBMz,lDF); lOutImgBM^[lPos2Offset] := lBMz; lPrevZValsBM[lPatternPos] := lBMz; end; if lOutImgAUC <> nil then begin lOutImgAUC^[lPos2Offset] := continROC (lnControlsPlusLesion, lnNoLesion, lObs); lPrevAUCVals[lPatternPos] := lOutImgAUC^[lPos2Offset]; end; StatPermuteThreaded (lttest,lBM,lImagesCount, lnNoLesion,lnPermute,lThread, lObs); end; //novel lesion pattern end; //in brain mask - compute end; //for each voxel freemem(lObsP); freemem(lLesionOrderp); if lControlsIn < 0 then //binomial freemem(lObsB); end; procedure TLesionBinom.Analyze (lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lControlsIn : integer; lPlankImg: bytep;lOutImgMn,lOutImgL,lOutImgX,lOutImgAUC,lSymptomRA: SingleP); //procedure TLesionBinomial.Analyze (lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgL,lOutImgX,lSymptomRA: SingleP); //pattern variables const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lPrevZValsL ,lPrevAUCVals: array [1..knPrevPattern] of Single; lPatternPos: integer; lLesionOrderp: bytep; //standard variables var //lObsp: pointer; //lObs: Doublep0; lPrevZVals lObs: ByteP0; lAUC,lZ: Double; lnLesion,lPosPct,lPos,lPos2,lPos2Offset,lnVoxTested: integer; begin //Binomial StatThread //init patterns for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; getmem(lLesionOrderp, lImagesCount *sizeof(byte)); //now init standard variables //createArray64(lObsp,lObs,lImagesCount); getmem(lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; for lPos := 1 to lImagesCount do begin if ((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]) = 0 then begin //no lesion lObs^[lImagesCount-lPos+lnLesion] := round(lSymptomRA^[lPos]); lLesionOrderp^[lPos] := 0; end else begin //lesion inc(lnLesion); lLesionOrderp^[lPos] := 1; lObs^[lnLesion-1] := round(lSymptomRA^[lPos]); //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) and (lnLesion < lImagesCount) then begin //when there are 0 lesions or all lesions there is no variability! inc(gnVoxTestedRA[lThread]); //next check patterns lPattern := SetOrderX (lLesionOrderp,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin //lesion pattern is not novel //if lChi2 then // lOutImgX^[lPos2Offset] := lPrevZvalsX[lPos]; //if lLieber then lOutImgL^[lPos2Offset] := lPrevZvalsL[lPos]; if lOutImgAUC <> nil then lOutImgAUC^[lPos2Offset] := lPrevAUCvals[lPos]; end else begin //lesion pattern is novel //record novel pattern inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; lPrevPatternRA[lPatternPos] := lPattern; {if lChi2 then begin Chi2 (lImagesCount, lnLesion, lObs,lT); lOutImgX^[lPos2Offset] := lT;//lT; lPrevZValsX[lPatternPos] := lT; end; if lLieber then begin} Liebermeister2b(lImagesCount, lnLesion, lObs,lAUC,lZ); if lOutImgAUC <> nil then lOutImgAUC^[lPos2Offset] := lAUC; lPrevAUCVals[lPatternPos] := lAUC; lOutImgL^[lPos2Offset] := lZ; lPrevZValsL[lPatternPos] := lZ; //end; StatPermuteBinomialThreaded (lImagesCount, lnLesion,lnPermute,lThread, lObs); end; end; //in brain mask - compute end; //for each voxel freemem(lObs); freemem(lLesionOrderp) end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/npm.lpr��������������������������������������������������������0000755�0001750�0001750�00000001275�11421113036�016303� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������program npm; {$mode objfpc}{$H+} {$I options.inc} uses {$IFDEF UNIX}cthreads,{$ENDIF} Interfaces, // this includes the LCL widgetset Forms, npmform,stats ,nifti_hdr,valformat, part, gzio2, StatThds, StatThdsUtil, brunner, statcr, distr, GraphicsMathLibrary, define_types, ReadInt {$IFDEF SPREADSHEET} ,design,spread{$ENDIF}; {$IFNDEF FPC} {$R npm.res} {$ENDIF} begin Application.Initialize; Application.CreateForm(TMainForm, MainForm); {$IFDEF SPREADSHEET} Application.CreateForm(TSpreadForm, SpreadForm); Application.CreateForm(TDesignForm, DesignForm); {$ENDIF} Application.CreateForm(TReadIntForm, ReadIntForm); Application.Run; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/ReadInt.lfm����������������������������������������������������0000755�0001750�0001750�00000001762�11540170632�017030� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object ReadIntForm: TReadIntForm Left = 306 Height = 80 Top = 554 Width = 469 HorzScrollBar.Page = 468 VertScrollBar.Page = 79 ActiveControl = ReadIntEdit BorderStyle = bsDialog Caption = 'Integer required' ClientHeight = 80 ClientWidth = 469 Constraints.MaxHeight = 80 Constraints.MaxWidth = 469 Constraints.MinHeight = 80 Constraints.MinWidth = 469 Font.Name = 'MS Sans Serif' OnCreate = FormCreate Position = poScreenCenter LCLVersion = '0.9.28.2' object ReadIntLabel: TLabel Left = 16 Height = 14 Top = 12 Width = 336 Alignment = taRightJustify AutoSize = False Caption = 'Enter a number' ParentColor = False end object ReadIntEdit: TSpinEdit Left = 360 Height = 27 Top = 12 Width = 93 MaxValue = 0 TabOrder = 0 end object OKBtn: TButton Left = 368 Height = 25 Top = 44 Width = 75 BorderSpacing.InnerBorder = 4 Caption = 'OK' OnClick = OKBtnClick TabOrder = 1 end end ��������������mricron-0.20140804.1~dfsg.1.orig/npm/Copy of npm.cfg������������������������������������������������0000755�0001750�0001750�00000001011�11031052252�017510� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-$A+ -$B- -$C+ -$D+ -$E- -$F- -$G+ -$H+ -$I+ -$J+ -$K- -$L+ -$M- -$N+ -$O+ -$P+ -$Q- -$R- -$S- -$T- -$U- -$V+ -$W- -$X+ -$YD -$Z1 -cg -AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; -H+ -W+ -M -$M16384,1048576 -K$00400000 -LN"c:\program files\borland\delphi4\Lib" -U"C:\pas\mricron\common;C:\pas\mricron\fpmath" -O"C:\pas\mricron\common;C:\pas\mricron\fpmath" -I"C:\pas\mricron\common;C:\pas\mricron\fpmath" -R"C:\pas\mricron\common;C:\pas\mricron\fpmath" �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/turbolesion.pas������������������������������������������������0000755�0001750�0001750�00000054160�12306423022�020047� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit turbolesion; interface {$H+} {$Include ..\common\isgui.inc} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr, Messages, Classes, Graphics, Controls, Forms, Dialogs, nifti_types, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, unpm, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes; Type TLDMPrefs = record NULP,BMtest,Ttest,Ltest: boolean; CritPct,nCrit,nPermute,Run: integer; ValFilename, OutName, ExplicitMaskName: string; end; function TurboLDM (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; var lPrefs: TLDMPrefs ; var lSymptomRA: SingleP;var lFactname,lOutName: string): boolean; implementation {$IFDEF GUI} uses npmform; {$ELSE} // uses npmcl; {$ENDIF} (*procedure Debog (var lSumImg: Smallintp; lVox: integer); var lInName : string; lFData: file; begin lInName := 'c:\16.img'; assignfile(lFdata,lInName); filemode := 2; Rewrite(lFdata,lVox*sizeof(smallint)); BlockWrite(lFdata,lSumImg^, 1 {, NumWritten}); closefile(lFdata); end;*) function MakeSum (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; var lSumImg: Smallintp): boolean; //if successful, you MUST freemem(lSumImg)... label 667; var lVolVox,lVox,lImg,lPosPct: integer; lVolImg: byteP; begin result := false; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then exit; getmem(lVolImg,lVolVox* sizeof(byte)); getmem(lSumImg,lVolVox* sizeof(smallint)); for lVox := 1 to lVolVox do //June 2009 init array lSumImg^[lVox] := 0; (* for lVox := 1 to lVolVox do if lVolImg^[lVox] <> 0 then lSumImg^[lVox] := lSumImg^[lVox]+1;*) for lImg := 1 to lImages.Count do begin lPosPct := round(100*(lImg / lImages.Count)); NPMProgressBar( lPosPct); Application.Processmessages; if not LoadImg8(lImages[lImg-1], lVolImg, 1, lVolVox,round(gOffsetRA[lImg]),1,gDataTypeRA[lImg],lVolVox) then goto 667; for lVox := 1 to lVolVox do if lVolImg^[lVox] <> 0 then lSumImg^[lVox] := lSumImg^[lVox]+1; end;//for each image NPMmsg('Sum image finished = ' +TimeToStr(Now)); NPMProgressBar(0); //Debog(lSumImg, lVolVox); freemem(lVolImg); result := true; exit; 667: //you only get here if you aborted ... free memory and report error freemem(lVolImg); freemem(lSumImg); NPMMsg('Unable to complete analysis.'); NPMProgressBar(0); end; function ThreshSumImg (var lSumImg: Smallintp; lVolVox,lThresh: integer): integer; //sets all voxels with values < lThresh to zero, returns number of voxels to survive threshold. var lPos: integer; begin result := 0; if lVolVox < 1 then exit; for lPos := 1 to lVolVox do if lSumImg^[lPos] < lThresh then lSumImg^[lPos] := 0 else inc(result); end; function ExplicitMaskSumImg (lMaskName: string; var lSumImg: Smallintp; lVolVox: integer): integer; //Any voxels in MaskImg that are 0 are zeroed in the SumImg var lOK: boolean; lPos: integer; lMaskHdr: TMRIcroHdr; lMaskData: bytep; label 666; begin result := 0; if (lVolVox < 1) or (not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr)) then begin NPMmsg('Error: unable to load explicit mask named '+lMaskName); exit; end; if lVolVox <> (lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]) then begin NPMmsg('Error: data and explicit mask have different sizes '+lMaskName); exit; end; getmem(lMaskData,lVolVox* sizeof(byte)); lOK := LoadImg8(lMaskName, lMaskData, 1, lVolVox,round(lMaskHdr.NIFTIhdr.vox_offset),1,lMaskHdr.NIFTIhdr.DataType,lVolVox); if not lOK then goto 666; if lVolVox < 1 then exit; for lPos := 1 to lVolVox do if lMaskData^[lPos] < 1 then lSumImg^[lPos] := 0 else inc(result); 666: freemem(lMaskData); end; function LoadImg8Masked(lInName: string; lImgData: bytep; lMaskData: SmallIntP; lStartMaskPos, lEndMaskPos,linvox_offset,lRApos,lDataType,lVolVox: integer): boolean; label 111; var lFullImgData: bytep; lMaskPos,lPos: integer; begin result := false; if (lVolVox < 1) or (lEndMaskPos < lStartMaskPos) then exit; getmem(lFullImgData,lVolVox* sizeof(byte)); result := LoadImg8(lInName, lFullImgData, 1, lVolVox,linvox_offset,1,lDataType,lVolVox); if result then begin lMaskPos := 0; for lPos := 1 to lVolVox do begin if lMaskData^[lPos] <> 0 then begin inc(lMaskPos); if (lMaskPos >=lStartMaskPos) then lImgData^[lRApos+lMaskPos-1] := lFullImgData^[lPos]; if lMaskPos = lEndMaskPos then goto 111; end;//voxel in mask end; //for each voxel in image end;//if LoadImg8 success 111: freemem(lFullImgData); end; function reformat(var lStatImg: singlep; lMaskImg: smallintp; lVolVox: integer): boolean; var lPos,lStatPos,lMaskItems: integer; begin result := false; if lVolVox < 1 then exit; lMaskItems := 0; for lPos := 1 to lVolVox do if lMaskImg^[lPos] <> 0 then inc(lMaskItems); result := true; if (lMaskItems < 1) or (lMaskItems >= lVolVox) then exit;//no need to reformat //note that we do this in descending order, so we do not overwrite... lStatPos := lMaskItems; for lPos := lVolVox downto 1 do if lMaskImg^[lPos] <> 0 then begin lStatImg^[lPos] := lStatImg^[lStatPos]; dec(lStatPos); end else lStatImg^[lPos] := 0; end;//reformat function NULPcount (lPlankImg: bytep; lVoxPerPlank,lImagesCount,lnCrit: integer; var lUniqueOrders: integer; var lOverlapRA: Overlapp): boolean; procedure CheckOrder(var lObservedOrder: TLesionPattern); var lInc: integer; begin if lUniqueOrders > 0 then begin //see if this is unique for lInc := lUniqueOrders downto 1 do //check most recent patterns first if SameOrder(lObservedOrder,lOverlapRA^[lInc],lImagesCount) then exit; //not unique end; //UniqueOrders > 0 //if we have not exited yet, we have found a new ordering! lUniqueOrders := lUniqueOrders + 1; lOverlapRA^[lUniqueOrders] := lObservedOrder; end; var lVox,lPlankImgPos,lPos,lnLesion: integer; lOrder,lPrevOrder: TLesionPattern; begin result := false; if lImagesCount > kMaxObs then begin NPMmsg('Warning: unable to count unique lesion patterns for so many participants'); exit; end; if lImagesCount > 64 then NPMMsg('Counting unique lesion patterns - this may take a while (edit preferences to skip this step)'); Application.Processmessages; NPMProgressBar(0); //this forces a refresh for GUI applications Sleep(30); lPrevOrder := EmptyOrder;//impossible: forces first voxel of each order to be checked for lVox := 1 to lVoxPerPlank do begin (*if (lVox mod lVoxPerPlankDiv10) = 0 then begin MainForm.ProgressBar1.Position := (lVox div lVoxPerPlankDiv10)*10; MainForm.Refresh; Application.processmessages; end;*) lOrder := EmptyOrder; lnLesion := 0; lPlankImgPos := 0; //lnDeficits := 0; for lPos := 1 to lImagesCount do begin if (lPlankImg^[lPlankImgPos + lVox] > 0) then begin inc(lnLesion); SetBit(lPos,lOrder); end; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end; if (lnLesion >= lnCrit) then begin //statistics computed - more than nCrit injured if (not SameOrder(lOrder,lPrevOrder,lImagesCount)) then CheckOrder(lOrder); //inc(lnVoxels); end;//lnLesion lPrevOrder := lOrder; end;//for lVox result := true; end; procedure PtoZpermute (lnPermute: integer; lPermuteMaxT, lPermuteMinT: singlep); var lPos: integer; lVal : single; begin if lPos < 1 then exit; for lPos := 1 to lnPermute do begin if (lPermuteMinT^[lPos] > 1.1) or (lPermuteMinT^[lPos] < -1.1) then lPermuteMinT^[lPos] := 0.5; if (lPermuteMaxT^[lPos] > 1.1) or (lPermuteMaxT^[lPos] < -1.1) then lPermuteMaxT^[lPos] := 0.5; lVal := lPermuteMaxT^[lPos]; lPermuteMaxT^[lPos] := lPermuteMinT^[lPos]; lPermuteMinT^[lPos] := lVal; if lPermuteMaxT^[lPos] < 0 then lPermuteMaxT^[lPos] := -pNormalInv(abs(lPermuteMaxT^[lPos])) else lPermuteMaxT^[lPos] := pNormalInv(lPermuteMaxT^[lPos]); if lPermuteMinT^[lPos] < 0 then lPermuteMinT^[lPos] := -pNormalInv(abs(lPermuteMinT^[lPos])) else lPermuteMinT^[lPos] := pNormalInv(lPermuteMinT^[lPos]); end; end; function TurboLDM (var lImages: TStrings; var lMaskHdr: TMRIcroHdr;var lPrefs: TLDMPrefs ; var lSymptomRA: SingleP;var lFactname,lOutName: string): boolean; label 123,667; var lOutNameMod: string; lNULPcalculated: boolean; lStatHdr: TNIfTIhdr; lThreshFDR,lThreshPermute,lThreshBonf,lThreshNULP :double; lObsp: pointer; lObs: Doublep0; lRanOrderp: pointer; lRanOrder: Doublep0; lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM,lOutImgSum,lOutImgBM,lOutImgT,lOutImgAUC: singlep; lSumImg: Smallintp; lPlankImg: byteP; lVoxPerPlank,lnPlanks,lTotalMemory,lnVoxTested,lVolVox: int64; lUniqueOrders,lThread,lThreadStart,lThreadInc,lThreadEnd, lPos2,lPosPct,lPos,lPlankImgPos,lPlank,lStartVox,lEndVox: integer; lOverlapRA: Overlapp; lPrevThreadsRunning: integer; {$IFNDEF FPC} lStartTime :DWord;{$ENDIF} begin {$IFNDEF FPC} lStartTime := GetTickCount;{$ENDIF} result := false; lNULPcalculated := false; lSumImg := nil; lPlankImg := nil; lOutImgSum := nil; lOutImgBM := nil; lOutImgT := nil; lOutImgAUC := nil; lOverlapRA := nil; lUniqueOrders := 0; if lPrefs.Ltest then begin lPrefs.Ttest := false; lPrefs.BMtest := false; end else if (not lPrefs.Ttest) and (not lPrefs.BMtest) then begin//not binomial NPMmsg('Error no tests specified'); exit; end; NPMmsg('Permutations = ' +IntToStr(lPrefs.nPermute)); NPMmsg('Analysis began = ' +TimeToStr(Now)); lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; if not MakeSum( lImages, lMaskHdr, lSumImg) then goto 667; lnVoxTested := ThreshSumImg(lSumImg,lVolVox,lPrefs.nCrit); NPMmsg('Voxels damaged in at least '+inttostr(lPrefs.nCrit)+' individuals = ' +Floattostr(lnVoxTested)); if lnVoxTested < 1 then begin NPMmsg('Error: no voxels damaged in at least '+inttostr(lPrefs.nCrit)+' individuals.'); goto 667; end; if (lPrefs.ExplicitMaskName <> '') then begin lnVoxTested := ExplicitMaskSumImg (lPrefs.ExplicitMaskName, lSumImg, lVolVox); NPMmsg('Voxels also non-zero in mask '+lPrefs.ExplicitMaskName+' = ' +Floattostr(lnVoxTested)); if lnVoxTested < 1 then begin NPMmsg('Error: no remaing voxels also non-zero in mask '+lPrefs.ExplicitMaskName); goto 667; end; end; //compute planks and acquire memory lTotalMemory := lnVoxTested * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/kPlankSz ) + 1; NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/kPlankSz)); if (lnPlanks = 1) then begin lVoxPerPlank := lnVoxTested; //we can do this in a single pass getmem(lPlankImg,lTotalMemory) end else begin getmem(lPlankImg,kPlankSz); lVoxPerPlank := kPlankSz div lImages.Count; end; //spatial maps for results getmem(lOutImgSum,lVolVox*sizeof(single)); getmem(lOutImgBM,lVolVox*sizeof(single)); getmem(lOutImgT,lVolVox*sizeof(single)); getmem(lOutImgAUC,lVolVox*sizeof(single)); //initialize memory InitPermute (lImages.Count, lPrefs.nPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; lOutImgAUC^[lPos] := 0; end; //next create permuted BM bounds if lPrefs.BMtest then begin NPMmsg('Generating BM permutation thresholds'); //MainForm.Refresh; createArray64(lObsp,lObs,lImages.Count); for lPos := 1 to lImages.Count do lObs^[lPos-1] := lSymptomRA^[lPos]; genBMsim (lImages.Count, lObs); freemem(lObsp); end; if lPrefs.NULP then getmem(lOverlapRA,lnVoxTested* sizeof(TLesionPattern)); if lPrefs.Ltest then ClearThreadDataPvals(gnCPUThreads,lPrefs.nPermute) else ClearThreadData(gnCPUThreads,lPrefs.nPermute) ; //load and process data lStartVox := 1; lEndVox := 0; for lPlank := 1 to lnPlanks do begin NPMmsg('Computing plank = ' +Inttostr(lPlank)+' of '+inttostr(lnPlanks)); lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lnVoxTested then begin lVoxPerPlank := lnVoxTested-lStartVox+1{lVoxPerPlank - (lEndVox-lVolVox)}; lEndVox := lnVoxTested; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8Masked(lImages[lPos-1], lPlankImg,lSumImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error if lPrefs.Ltest then begin with TLesionBinom.Create (MainForm.ProgressBar1,false,true,lPrefs.nCrit, lPrefs.nPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,0,lPlankImg,lOutImgSum,lOutImgBM,lOutIMgT{not used},lOutImgAUC,lSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} end else begin with TLesionContinuous.Create (MainForm.ProgressBar1,lPrefs.ttest,lPrefs.BMtest,lPrefs.nCrit, lPrefs.nPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,0,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,lOutImgAUC,lSymptomRA) do //with TLesionContinuous.Create (MainForm.ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,lSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} end; inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread lPrevThreadsRunning := gThreadsRunning; repeat Application.processmessages; sleep(30); if (gThreadsRunning <> lPrevThreadsRunning) then begin NPMmsg(' '+inttostr(gThreadsRunning)+' threads still running ' +TimeToStr(Now)); lPrevThreadsRunning := gThreadsRunning; end; until gThreadsRunning = 0; Application.processmessages; //end of threading if lPrefs.NULP then lNULPcalculated := NULPcount (lPlankImg, lVoxPerPlank,lImages.Count,lPrefs.nCrit, lUniqueOrders, lOverlapRA); lStartVox := lEndVox + 1; end; //calculate max per thread x SumThreadData(gnCPUThreads,lPrefs.nPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //data in maps is stored in voxels 1..lnVoxTested - put in spatial order reformat(lOutImgSum,lSumImg,lVolVox); reformat(lOutImgBM,lSumImg,lVolVox); reformat(lOutImgT,lSumImg,lVolVox); reformat(lOutImgAUC,lSumImg,lVolVox); lThreshBonf := reportBonferroni('Std',lnVoxTested); if lNULPcalculated {lPrefs.NULP} then lThreshBonf := reportBonferroni('(Number of Unique Lesion Patterns with at least '+inttostr(lPrefs.nCrit)+' lesions)',lUniqueOrders); //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); if lPrefs.Run < 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //save Area Under Curve lOutNameMod := ChangeFilePostfixExt(lOutName,'rocAUC'+lFactName,'.hdr'); if lPrefs.Run < 1 then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgAUC,1); //create new header - subsequent images will use Z-scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lPrefs.Run < 1) and (Sum2Power(lOutImgSum,lVolVox,lImages.Count,lPrefs.nCrit, lPrefs.LTest)) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; //if lPrefs.Run > 0 then //terrible place to do this - RAM problems, but need value to threshold maps // lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap2 (lImages, lPrefs.nCrit,lnVoxTested,lPlankImg)); if lPrefs.ttest then begin //save Ttest //next: convert t-scores to z scores for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lPrefs.nPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; lThreshFDR := reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); lThreshPermute := reportPermute('ttest',lPrefs.nPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'ttest'+lFactName,'.hdr'); {$IFNDEF FPC} //if lPrefs.Run > 0 then begin // NPMmsg('threshtt,'+inttostr(lPrefs.Run)+','+inttostr(MainForm.ThreshMap(lThreshBonf,lVolVox,lOutImgT))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)+','+inttostr(round((GetTickCount - lStartTime)/1000))); //end; {$ENDIF} NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if lPrefs.LTest then begin PtoZpermute (lPrefs.nPermute, lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'L'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); reportFDR ('L', lVolVox, lnVoxTested, lOutImgBM); reportPermute('L',lPrefs.nPermute,lPermuteMaxT, lPermuteMinT); end;//Liebermeister if lPrefs.BMtest then begin //save Brunner Munzel lThreshFDR := reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); lThreshPermute := reportPermute('BM',lPrefs.nPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'BM'+lFactName,'.hdr'); if lPrefs.Run > 0 then NPMmsg('threshbm,'+inttostr(lPrefs.Run)+','+inttostr(ThreshMap(lThreshBonf,lVolVox,lOutImgBM))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); //NPMmsgAppend('threshbm,'+inttostr(lPrefs.Run)+','+inttostr(MainForm.ThreshMap(lThreshBonf,lVolVox,lOutImgBM))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end; NPMmsg('Analysis finished = ' +TimeToStr(Now)); {$IFNDEF FPC} NPMmsg('Processing Time = ' +inttostr(round((GetTickCount - lStartTime)/1000)));{$ENDIF} lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); NPMMsgSave(lOutNameMod); //all done result := true;//all done without aborting 667: // free memory and report error if lPlankImg <> nil then freemem(lPlankImg); if lSumImg <> nil then freemem(lSumImg); if lOutImgSum <> nil then freemem(lOutImgSum); if lOutImgBM <> nil then freemem(lOutImgBM); if lOutImgT <> nil then freemem(lOutImgT); if lOutImgAUC <> nil then freemem(lOutImgAUC); if lOverlapRA <> nil then freemem(lOverlapRA); if not result then NPMmsg('Unable to complete analysis.'); NPMProgressBar( 0); end; //TurboLDM end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/anacom.pas�����������������������������������������������������0000755�0001750�0001750�00000061664�11326443506�016761� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit anacom; interface {$H+} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr,filename, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes; //procedure DoAnaCOM; function AnacomLesionNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttestIn,lBMIn: boolean): boolean; implementation uses npmform; {$DEFINE NOTmedianfx} function AnacomLesionNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttestIn,lBMIn: boolean): boolean; label 123,667; var lOutNameMod: string; lPlankImg: byteP; lOutImgSum,lOutImgBM,lOutImgT, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM,lCombinedSymptomRA: singleP; lPos,lPlank,lThread,lnControlsPlusPatients: integer; lVolVox,lMinMask,lMaxMask,lTotalMemory,lnPlanks,lVoxPerPlank, lThreadStart,lThreadEnd,lThreadInc,lnLesion,lnPermute, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT,lBMz, lSum,lThresh,lThreshBonf,lThreshPermute,lThreshNULP :double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; lBM,lttest,lLtest: boolean; lnControlNeg: integer; {$IFDEF medianfx} lmedianFX,lmeanFX,lsummean,lsummedian: double; lmediancount: integer; {$ENDIF} begin lnControlNeg := lnControl; //negative for binomial test lttest := lttestin; lbm := lbmin; if (not (lttest)) and (not (lbm)) then begin lLtest := true; lBM := true; lnControlNeg := -lnControl; end; //lttest:= ttestmenu.checked; //lBM := BMmenu.checked; if lnControl < 1 then begin MainForm.NPMmsg('AnaCom aborted - need data from at least 1 control individual'); exit; end; lnPermute := 0;//MainForm.ReadPermute; MainForm.NPMmsg('Permutations = ' +IntToStr(lnPermute)); MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; MainForm.NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); MainForm.NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) //assumes 1bpp else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; {$IFDEF medianfx} lsummean := 0; lsummedian:= 0; lmediancount := 0; {$ENDIF} for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; lnControlsPlusPatients := lImages.Count+lnControl; createArray64(lObsp,lObs,lnControlsPlusPatients); getmem(lOutImgSum,lVolVox* sizeof(single)); getmem(lOutImgBM,lVolVox* sizeof(single)); getmem(lOutImgT,lVolVox* sizeof(single)); MainForm.InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do begin lOutImgSum^[lPos] := 0; lOutImgBM^[lPos] := 0; lOutImgT^[lPos] := 0; end; //sumptom array for lesions AND controls for lPos := 1 to lImages.Count do lObs^[lPos-1] := lSymptomRA^[lPos]; for lPos := 1 to lnControl do lObs^[lPos-1+lImages.Count] := lControlSymptomRA^[lPos]; getmem(lCombinedSymptomRA,lnControlsPlusPatients* sizeof(single)); for lPos := 1 to lnControlsPlusPatients do lCombinedSymptomRA^[lPos] := lObs^[lPos-1]; //next create permuted BM bounds if lBM then begin MainForm.NPMmsg('Generating BM permutation thresholds'); MainForm.Refresh; //for lPos := 1 to lImages.Count do // lObs^[lPos-1] := lSymptomRA^[lPos]; genBMsim (lnControlsPlusPatients, lObs); end; ClearThreadData(gnCPUThreads,lnPermute) ; for lPlank := 1 to lnPlanks do begin MainForm.NPMmsg('Computing plank = ' +Inttostr(lPlank)); MainForm.Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TLesionContinuous.Create (MainForm.ProgressBar1,lttest,lBM,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lnControlNeg,lPlankImg,lOutImgSum,lOutImgBM,lOutImgT,nil,lCombinedSymptomRA) do {$IFDEF FPC} OnTerminate := @MainForm.ThreadDone; {$ELSE}OnTerminate := MainForm.ThreadDone;{$ENDIF} inc(gThreadsRunning); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; //threading end lStartVox := lEndVox + 1; end; lThreshPermute := 0; lnVoxTested := SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); //next report findings if lnVoxTested < 1 then begin MainForm.NPMmsg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lnCrit)+' patients**'); goto 123; end; MainForm.NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); {$IFDEF medianfx} MainForm.NPMmsg('Average MEAN effect size = ' +realtostr((lsummean/lmediancount),3)); MainForm.NPMmsg('Average MEDIAN effect size = ' +realtostr((lsummedian/lmediancount),3)); {$ENDIF} MainForm.NPMmsg('Only tested voxels with more than '+inttostr(lnCrit)+' lesions'); //Next: save results from permutation thresholding.... //Next: save results from permutation thresholding.... lThreshBonf := MainForm.reportBonferroni('Std',lnVoxTested); //Next: NULPS if lRun > 0 then //terrible place to do this - RAM problems, but need value to threshold maps lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap2 (lImages, lnCrit,lnVoxTested,lPlankImg)); //lThreshNULP := MainForm.reportBonferroni('Unique overlap',CountOverlap (lImages, lnCrit)); //next: save data MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum'+lFactName,'.hdr'); if (lRun < 1) then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); //create new header - subsequent images will use Z-scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if (lRun < 1) and (Sum2PowerCont(lOutImgSum,lVolVox,lImages.Count)) then begin lOutNameMod := ChangeFilePostfixExt(lOutName,'Power'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); end; //MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); if lttest then begin //save Ttest //next: convert t-scores to z scores if lnControl < 1 then for lPos := 1 to lVolVox do lOutImgT^[lPos] := TtoZ (lOutImgT^[lPos],lImages.Count-2); for lPos := 1 to lnPermute do begin lPermuteMaxT^[lPos] := TtoZ (lPermuteMaxT^[lPos],lImages.Count-2); lPermuteMinT^[lPos] := TtoZ (lPermuteMinT^[lPos],lImages.Count-2); end; lThresh := MainForm.reportFDR ('ttest', lVolVox, lnVoxTested, lOutImgT); lThreshPermute := MainForm.reportPermute('attest',lnPermute,lPermuteMaxT, lPermuteMinT); lOutNameMod := ChangeFilePostfixExt(lOutName,'attest'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('AnaComthreshtt,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgT))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgT,1); end; if lBM then begin //save Mann Whitney lThresh := MainForm.reportFDR ('BM', lVolVox, lnVoxTested, lOutImgBM); lThreshPermute := MainForm.reportPermute('aBM',lnPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,'aBM'+lFactName,'.hdr'); if lRun > 0 then MainForm.NPMmsgAppend('AnaCOMthreshbm,'+inttostr(lRun)+','+inttostr(MainForm.ThreshMap(lThreshNULP,lVolVox,lOutImgBM))+','+realtostr(lThreshNULP,3)+','+realtostr(lThreshPermute,3)+','+realtostr(lThreshBonf,3)); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgBM,1); end; //next: free dynamic memory 123: MainForm.FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); freemem(lOutImgT); freemem(lOutImgBM); freemem(lOutImgSum); freemem(lObsp); freemem(lPlankImg); MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lFactName,'.txt'); MainForm.MsgSave(lOutNameMod); MainForm.ProgressBar1.Position := 0; exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); MainForm.NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; //LesionNPMAnalyze (*function readCSV2 (lFilename: string; lCol1,lCol2: integer; var lnObservations : integer; var ldataRA1,ldataRA2: singlep): boolean; const kHdrRow = 0;//1; kHdrCol = 0;//1; var lNumStr: string; F: TextFile; lTempFloat: double; lCh: char; lnFactors,MaxC,R,C:integer; lError: boolean; begin lError := false; result := false; if not fileexists(lFilename) then begin showmessage('Can not find '+lFilename); exit; end; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); if (R <= (kHdrRow+1)) or (MaxC < (kHdrCol+lCol1)) or (MaxC < (kHdrCol+lCol2)) then begin showmessage('problems reading CSV - not enough columns/rows '+inttostr(lCol1)+' '+inttostr(lCol2)); exit; end; lnObservations := R -kHdrRow ; //-1: first row is header.... lnFactors := MaxC-1;// -1: first column is Y values //fx(lnObservations,lnFactors); //exit; getmem(ldataRA1,lnObservations*sizeof(single)); getmem(ldataRA2,lnObservations*sizeof(single)); //second pass Reset(F); C := 1; MaxC := 0; R := 1; lNumStr := ''; lTempfloat := 0; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin if (R > kHdrRow) and (C > kHdrCol) then begin if ((C-kHdrCol) = lCol1) or ((C-kHdrCol) = lCol2) then begin if lNumStr = '-' then begin lTempFloat := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(lNumStr); if (C-kHdrCol) = lCol1 then ldataRA1^[R-kHdrRow] := lTempFloat else if (C-kHdrCol) = lCol2 then ldataRA2^[R-kHdrRow] := lTempFloat; end; //number end; //col1 or col2 end;// else //R > 1 lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 1; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if (lNumStr <> '') and (C = lnFactors) then begin //unterminated string try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except ldataRA2^[R-1] := lTempFloat; end;//unterminated string //read finel item CloseFile(F); FileMode := 2; //Set file access to read/write result := true; end; *) function readTxt (lFilename: string; var lnObservations : integer; var ldataRA1: singlep): boolean; const kHdrRow = 0;//1; kHdrCol = 0;//1; var lCol1: integer; lNumStr: string; F: TextFile; lTempFloat: double; lCh: char; lnFactors,MaxC,R,C:integer; lError: boolean; begin lCol1:= 1; lError := false; result := false; if not fileexists(lFilename) then begin showmessage('Can not find '+lFilename); exit; end; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); if (R <= (kHdrRow+1)) or (MaxC < (kHdrCol+lCol1)) then begin showmessage('problems reading CSV - not enough columns/rows '); exit; end; lnObservations := R -kHdrRow ; //-1: first row is header.... lnFactors := kHdrCol+lCol1;// -1: first column is Y values //fx(lnObservations,lnFactors); //exit; getmem(ldataRA1,lnObservations*sizeof(single)); //second pass Reset(F); C := 1; MaxC := 0; R := 1; lNumStr := ''; lTempfloat := 0; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin if (R > kHdrRow) and (C > kHdrCol) then begin if ((C-kHdrCol) = lCol1) {or ((C-kHdrCol) = lCol2)} then begin if lNumStr = '-' then begin lTempFloat := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(lNumStr); if (C-kHdrCol) = lCol1 then begin //showmessage(lNumStr); ldataRA1^[R-kHdrRow] := lTempFloat; end; {else if (C-kHdrCol) = lCol2 then ldataRA2^[R-kHdrRow] := lTempFloat;} end; //number end; //col1 or col2 end;// else //R > 1 lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 1; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; //showmessage(lNumStr+' '+inttostr(lnFactors)+' '+inttostr(C)); if (lNumStr <> '') and (C = lnFactors) then begin //unterminated string try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then showmessage('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(inttostr(R)+' '+floattostr(lTempFLoat)); ldataRA1^[R] := lTempFloat; end;//unterminated string //read finel item CloseFile(F); FileMode := 2; //Set file access to read/write result := true; end; (*procedure DoAnaCOM; label 666; var lControlFilename: string; lI, lnControlObservations : integer; lControldata: singlep; lBinomial: boolean; lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCrit: integer; lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lOutName,lFactname: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA: singleP; begin npmform.MainForm.memo1.lines.clear; npmform.MainForm.memo1.lines.add('AnaCOM analysis requires TXT/CSV format text file.'); npmform.MainForm.memo1.lines.add('One row per control participant.'); npmform.MainForm.memo1.lines.add('First column is performance of that participant.'); npmform.MainForm.memo1.lines.add('Example file:'); //npmform.MainForm.memo1.lines.add('deficit, voxels'); npmform.MainForm.memo1.lines.add('11'); npmform.MainForm.memo1.lines.add('19'); npmform.MainForm.memo1.lines.add('2'); npmform.MainForm.memo1.lines.add('22'); npmform.MainForm.memo1.lines.add('19'); npmform.MainForm.memo1.lines.add('6'); lControlFilename := 'c:\fx.txt'; if (not readTxt (lControlFilename, lnControlObservations,lControldata)) or (lnControlObservations < 1) then begin showmessage('Error reading file '+lControlFilename); exit; end; npmform.MainForm.memo1.lines.add('Control (n='+inttostr(lnControlObservations)+')performance: '); for lI := 1 to lnControlObservations do begin npmform.MainForm.memo1.lines.add(inttostr(lI)+' '+floattostr(lControldata^[lI])); end; //begin - copy lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? //next, get 1st group if not MainForm.GetVal(lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCrit,{,binom}lPredictorList) then begin showmessage('Error with VAL file'); goto 666; end; lTemp4D := CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) then begin Showmessage('Not enough subjects ('+inttostr(lnSubjAll)+') or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; MainForm.SaveHdrDlg.Filename := loutname; lOutName := lOutName+'.nii.gz'; if not MainForm.SaveHdrName ('Base Statistical Map', lOutName) then exit; for lFact := 1 to lnFactors do begin lImageNames.clear; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); lnSubj := lImageNames.Count; if lnSubj > 1 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; MainForm.NPMmsgClear; MainForm.NPMMsg(MainForm.GetKVers); MainForm.NPMMsg('Threads: '+inttostr(gnCPUThreads)); lFactName := lPredictorList.Strings[lFact-1]; lFactName := LegitFilename(lFactName,lFact); MainForm.NPMMsg('Factor = '+lFactname); For lSubj := 1 to lnSubj do MainForm.NPMMsg (lImageNames.Strings[lSubj-1] + ' = '+realtostr(lSymptomRA^[lSubj],2) ); MainForm.NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); MainForm.NPMMsg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); MainForm.NPMMsg('Number of Lesion maps = '+inttostr(lnSubj)); if not CheckVoxelsGroup(lImageNames,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; MainForm.ReportDescriptives(lSymptomRA,lnSubj); AnacomLesionNPMAnalyze(lImageNames,lMaskHdr,lnCrit,-1,lnControlObservations,lSymptomRA,lControldata,lFactName,lOutname,true {ttest},false{BM}); Freemem(lSymptomRA); end; //lnsubj > 1 end; //for each factor if lnSubjAll > 0 then begin Freemem(lMultiSymptomRA); end; 666: lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); ///end //AnacomLesionNPMAnalyze ( lImages: TStrings; var lMaskHdr: TMRIcroHdr; lnCrit,lRun,lnControl: integer; var lSymptomRA,lControlSymptomRA: SingleP;var lFactname,lOutName: string; lttest,lBM: boolean): boolean; freemem(lControldata); end;*) end. ����������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/StatThdsUtil.pas�����������������������������������������������0000755�0001750�0001750�00000007244�12204664666�020121� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit StatThdsUtil; interface uses //ComCtrls,Graphics, ExtCtrls, Classes, define_types,dialogsx; const kMaxThreads = 16; kSh = 10; //bits to shift kMaxImages = 1024; kMaxPermute = 4000; //kPlankMB : integer = 512; var gnCPUThreads, gThreadsRunning: Integer; kPlankSz : int64;// =1024 {bytes/kb} * 1024 {bytes/mb} * kPlankMB; //e.g. 512 MB gDataTypeRA: array [0..kMaxImages] of integer; gOffsetRA,gScaleRA,gInterceptRA: array [0..kMaxImages] of single; gnVoxTestedRA : array [0..kMaxThreads] of integer; gPermuteMinT,gPermuteMaxT,gPermuteMinBM,gPermuteMaxBM : array [0..kMaxThreads,0..kMaxPermute ] of double; procedure ClearThreadData(lnThreads,lnPermute: integer); function SumThreadDataLite (lnThreads: integer): integer; function SumThreadData (lnThreads,lnPermute: integer;lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP): integer; procedure ClearThreadDataPvals (lnThreads,lnPermute: integer); implementation procedure ClearThreadDataPvals (lnThreads,lnPermute: integer); var lT,lP: integer; begin if lnThreads < 1 then exit; if lnPermute > kMaxPermute then ShowMsg('Error: recompile with larger kMaxPermute'); for lT := 1 to lnThreads do gnVoxTestedRA[lT] := 0; if lnPermute < 1 then exit; for lT := 1 to lnThreads do begin for lP := 1 to lnPermute do begin gPermuteMinT[lT,lP] := 10; gPermuteMaxT[lT,lP] := -10; gPermuteMinBM[lT,lP] := 10; gPermuteMaxBM[lT,lP] := -10; end; end; end; procedure ClearThreadData (lnThreads,lnPermute: integer); var lT,lP: integer; begin if lnThreads < 1 then exit; if lnPermute > kMaxPermute then ShowMsg('Error: recompile with larger kMaxPermute'); for lT := 1 to lnThreads do gnVoxTestedRA[lT] := 0; if lnPermute < 1 then exit; for lT := 1 to lnThreads do begin for lP := 1 to lnPermute do begin gPermuteMinT[lT,lP] := 0; gPermuteMaxT[lT,lP] := 0; gPermuteMinBM[lT,lP] := 0; gPermuteMaxBM[lT,lP] := 0; end; end; end; function SumThreadDataLite (lnThreads: integer): integer; var lT: integer; begin result := 0; if lnThreads < 1 then exit; for lT := 1 to lnThreads do result := result + gnVoxTestedRA[lT]; end; function SumThreadData (lnThreads,lnPermute: integer;lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM: singleP): integer; var lT,lP: integer; begin result := 0; if lnThreads < 1 then exit; for lT := 1 to lnThreads do result := result + gnVoxTestedRA[lT]; if lnPermute < 1 then exit; for lP := 1 to lnPermute do begin lPermuteMinT^[lP] := gPermuteMinT[1,lP]; lPermuteMaxT^[lP] := gPermuteMaxT[1,lP]; lPermuteMinBM^[lP] := gPermuteMinBM[1,lP]; lPermuteMaxBM^[lP] := gPermuteMaxBM[1,lP]; end; if lnThreads < 2 then exit; for lT := 2 to lnThreads do begin for lP := 1 to lnPermute do begin if lPermuteMinT^[lP] > gPermuteMinT[lT,lP] then lPermuteMinT^[lP] := gPermuteMinT[lT,lP]; if lPermuteMinBM^[lP] > gPermuteMinBM[lT,lP] then lPermuteMinBM^[lP] := gPermuteMinBM[lT,lP]; if lPermuteMaxT^[lP] < gPermuteMaxT[lT,lP] then lPermuteMaxT^[lP] := gPermuteMaxT[lT,lP]; if lPermuteMaxBM^[lP] < gPermuteMaxBM[lT,lP] then lPermuteMaxBM^[lP] := gPermuteMaxBM[lT,lP]; end; end; end; //SumThreadData end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/zconf.inc������������������������������������������������������0000755�0001750�0001750�00000001274�10251433460�016611� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ -------------------------------------------------------------------- } {$DEFINE MAX_MATCH_IS_258} { Compile with -DMAXSEG_64K if the alloc function cannot allocate more than 64k bytes at a time (needed on systems with 16-bit int). } {- $DEFINE MAXSEG_64K} {$IFNDEF WIN32} {$DEFINE UNALIGNED_OK} { requires SizeOf(ush) = 2 ! } {$ENDIF} {$UNDEF DYNAMIC_CRC_TABLE} {$UNDEF FASTEST} {$define patch112} { apply patch from the zlib home page } { -------------------------------------------------------------------- } {$IFDEF FPC} {$DEFINE Use32} {$UNDEF DPMI} {$UNDEF MSDOS} {$UNDEF UNALIGNED_OK} { requires SizeOf(ush) = 2 ! } {$UNDEF MAXSEG_64K} {$ENDIF} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/npm.dof��������������������������������������������������������0000755�0001750�0001750�00000004531�12306713726�016273� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[FileVersion] Version=7.0 [Compiler] A=8 B=0 C=1 D=1 E=0 F=0 G=1 H=1 I=1 J=1 K=0 L=1 M=0 N=1 O=1 P=1 Q=0 R=0 S=0 T=0 U=0 V=1 W=0 X=1 Y=1 Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; NamespacePrefix= SymbolDeprecated=1 SymbolLibrary=1 SymbolPlatform=1 UnitLibrary=1 UnitPlatform=1 UnitDeprecated=1 HResultCompat=1 HidingMember=1 HiddenVirtual=1 Garbage=1 BoundsError=1 ZeroNilCompat=1 StringConstTruncated=1 ForLoopVarVarPar=1 TypedConstVarPar=1 AsgToTypedConst=1 CaseLabelRange=1 ForVariable=1 ConstructingAbstract=1 ComparisonFalse=1 ComparisonTrue=1 ComparingSignedUnsigned=1 CombiningSignedUnsigned=1 UnsupportedConstruct=1 FileOpen=1 FileOpenUnitSrc=1 BadGlobalSymbol=1 DuplicateConstructorDestructor=1 InvalidDirective=1 PackageNoLink=1 PackageThreadVar=1 ImplicitImport=1 HPPEMITIgnored=1 NoRetVal=1 UseBeforeDef=1 ForLoopVarUndef=1 UnitNameMismatch=1 NoCFGFileFound=1 MessageDirective=1 ImplicitVariants=1 UnicodeToLocale=1 LocaleToUnicode=1 ImagebaseMultiple=1 SuspiciousTypecast=1 PrivatePropAccessor=1 UnsafeType=1 UnsafeCode=1 UnsafeCast=1 [Linker] MapFile=0 OutputObjs=0 ConsoleApp=1 DebugInfo=0 RemoteSymbols=0 MinStackSize=16384 MaxStackSize=1048576 ImageBase=4194304 ExeDescription= [Directories] OutputDir= UnitOutputDir= PackageDLLOutputDir= PackageDCPOutputDir= SearchPath=..\common;..\delphionly;C:\pas\mricron\fpmath Packages=Vcl40;Vclx40;VclSmp40;Qrpt40;Vcldb40;RxCtl4 Conditionals= DebugSourceDirs= UsePackages=0 [Parameters] RunParams= HostApplication= Launcher= UseLauncher=0 DebugCWD= [Language] ActiveLang= ProjectLang= RootDir= [Version Info] IncludeVerInfo=0 AutoIncBuild=0 MajorVer=1 MinorVer=0 Release=0 Build=0 Debug=0 PreRelease=0 Special=0 Private=0 DLL=0 Locale=1033 CodePage=1252 [Version Info Keys] CompanyName= FileDescription= FileVersion=1.0.0.0 InternalName= LegalCopyright= LegalTrademarks= OriginalFilename= ProductName= ProductVersion=1.0.0.0 Comments= [HistoryLists\hlUnitAliases] Count=1 Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; [HistoryLists\hlSearchPath] Count=3 Item0=..\common;..\delphionly;C:\pas\mricron\fpmath Item1=C:\pas\mricron\common;C:\pas\mricron\fpmath Item2=C:\pas\mricron\common �����������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/StatThds.pas���������������������������������������������������0000755�0001750�0001750�00000056576�12156641506�017271� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit StatThds; {$Include ..\common\isgui.inc} interface uses {$IFDEF GUI} ComCtrls,{$ENDIF} //ComCtrls, Graphics, ExtCtrls, Classes, define_types,stats,StatThdsUtil,Brunner,lesion_pattern, dialogsx; type TStatThread = class(TThread) private lBarX: TProgressBar; lttestx,lBMx: boolean; lnCritx,lBarPosX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx,lImagesCountx,lnGroup1x : integer; lMaskImgx,lPlankImgx,lOutImgMnx,lOutImgBMx,lOutImgTx,lSymptomRAx: SingleP; procedure DoVisualSwap; protected procedure Execute; override; //procedure Terminate; procedure VisualProg(lPos: Integer); procedure Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); virtual; abstract; public constructor Create(lBar: TProgressBar;lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); end; { VBM - two groups } TNNStat = class(TStatThread) protected procedure Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); override; end; TPairedTStat = class(TStatThread) protected procedure Analyze(lunused1,lunused2: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); override; end; { Lesion - image reveals value } TLesionStat = class(TStatThread) protected procedure Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); override; end; TLesionBinomial = class(TStatThread) protected procedure Analyze(lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgL,lOutImgX,lSymptomRA: SingleP); override; end; implementation uses unpm; //uses Stat; { TSortThread } (*tpIdle The thread executes only when the system is idle. The system will not interrupt other threads to execute a thread with tpIdle priority. tpLowest The thread's priority is two points below normal. tpLower The thread's priority is one point below normal. tpNormal The thread has normal priority. tpHigher The thread's priority is one point above normal. tpHighest The thread's priority is two points above normal. tpTimeCritical*) Const Two32 = 4294967296.0 ; function GenRandThreaded(lRange: integer; var lRandSeed:comp): integer; //normal random function does not work well when threaded - randseed is changed by each thread const lFactor = $08088405 ; lTerm = 1 ; type lT = array [0..1] of longint ; var lX: extended; begin lRandSeed := lRandSeed*lFactor + lTerm; lT(lRandSeed)[1] := 0 ; // < May'04 was: RS := RS - Trunc(RS/Two32)*Two32 ; lX := lRandSeed/Two32 ; result := trunc((lRange)*lX); end; procedure GenPermuteThreaded (lnSubj: integer; var lOrigOrder,lRanOrder: DoubleP0; var lRandSeed:comp); var lInc,lRand: integer; lSwap: double; begin Move(lOrigOrder^,lRanOrder^,lnSubj*sizeof(double)); for lInc := lnSubj downto 2 do begin lRand := GenRandThreaded(lInc,lRandSeed); lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc-1]; lRanOrder^[lInc-1] := lSwap; end; end; procedure StatPermuteThreaded (lttest,lBM: boolean; lnSubj, lnGroup0,lnPermute,lThread: integer;var lOrigOrder: DoubleP0); var lInc: integer; lOutT: double; lRS: Comp; lRanOrderp: pointer; lRanOrder: Doublep0; begin if (lnSubj < 1) or (lnPermute < 1) then exit; createArray64(lRanOrderp,lRanOrder,lnSubj); lRS := 128; for lInc := 1 to lnPermute do begin GenPermuteThreaded(lnSubj, lOrigOrder,lRanOrder,lRS); //generate random order of participants if lttest then begin TStat2 (lnSubj, lnGroup0, lRanOrder, lOutT); if lOutT > gPermuteMaxT[lThread,lInc] then gPermuteMaxT[lThread,lInc] := lOutT; if lOutT < gPermuteMinT[lThread,lInc] then gPermuteMinT[lThread,lInc] := lOutT; end; //compute ttest if lBM then begin BMTest (lnSubj, lnGroup0, lRanOrder,lOutT); if lOutT > gPermuteMaxBM[lThread,lInc] then gPermuteMaxBM[lThread,lInc] := lOutT; if lOutT < gPermuteMinBM[lThread,lInc] then gPermuteMinBM[lThread,lInc] := lOutT; end; //compute BM end; freemem(lRanOrderp); end; procedure StatPermuteBinomialThreaded (lChi2,lLieber: boolean; lnSubj, lnGroup0,lnPermute,lThread: integer;var lOrigOrder: DoubleP0); var lInc: integer; lOutT: double; lRS: Comp; lRanOrderp: pointer; lRanOrder: Doublep0; begin if (lnSubj < 1) or (lnPermute < 1) then exit; createArray64(lRanOrderp,lRanOrder,lnSubj); lRS := 128; for lInc := 1 to lnPermute do begin GenPermuteThreaded(lnSubj, lOrigOrder,lRanOrder,lRS); //generate random order of participants if lChi2 then begin Chi2 (lnSubj, lnGroup0, lRanOrder, lOutT); if lOutT > gPermuteMaxT[lThread,lInc] then gPermuteMaxT[lThread,lInc] := lOutT; if lOutT < gPermuteMinT[lThread,lInc] then gPermuteMinT[lThread,lInc] := lOutT; end; //compute ttest if lLieber then begin Liebermeister2 (lnSubj, lnGroup0, lRanOrder,lOutT); if lOutT > gPermuteMaxBM[lThread,lInc] then gPermuteMaxBM[lThread,lInc] := lOutT; if lOutT < gPermuteMinBM[lThread,lInc] then gPermuteMinBM[lThread,lInc] := lOutT; end; //compute BM end; freemem(lRanOrderp); end; procedure TStatThread.DoVisualSwap; begin {$IFDEF GUI} lBarX.Position := lBarPosX; {$ENDIF} end; procedure TStatThread.VisualProg(lPos: Integer); begin {$IFDEF GUI} lBarPosX := lPos; {$IFDEF FPC}Synchronize(@DoVisualSwap); {$ELSE} Synchronize(DoVisualSwap);{$ENDIF} {$ENDIF} end; constructor TStatThread.Create(lBar: TProgressBar; lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); begin lBarX := lBar; lttestx := lttest; lBMx:= lBM; lThreadX := lThread; lThreadStartX := lThreadStart; lThreadEndX := lThreadEnd; lStartVoxx := lStartVox; lVoxPerPlankx := lVoxPerPlank; lImagesCountX := lImagesCount; lnGroup1x := lnGroup1; lMaskImgx := lMaskImg; lPlankImgx := lPlankImg; lOutImgMnx := lOutImgMn; lOutImgBMx := lOutImgBM; lOutImgTx := lOutImgT; lSymptomRAx := lSymptomRA; lnPermuteX := lnPermute; lnCritX := lnCrit; FreeOnTerminate := True; inherited Create(False); end; { The Execute method is called when the thread starts } procedure TStatThread.Execute; begin Analyze(lttestx,lBMx, lnCritX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx,lImagesCountx,lnGroup1x,lMaskImgx,lPlankImgX,lOutImgMnx,lOutImgBMx,lOutImgTx,lSymptomRAx); end; (*procedure TStatThread.Terminate; begin Dec(gThreadsRunning); NPMmsg('Thread done'); inherited Terminate; end; *) { Nearest Nighbor } procedure TNNStat.Analyze(lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); var lObsp: pointer; lObs: Doublep0; lT: Double; lPosPct,lPos,lPos2,lPos2Offset: integer; lSum: single; begin //statthread createArray64(lObsp,lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; if lMaskImg^[lPos2Offset] <> 0 then begin inc(gnVoxTestedRA[lThread]); lSum := 0; for lPos := 1 to lImagesCount do begin lObs^[lPos-1] := (gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; lSum := lSum + lObs^[lPos-1]; end; lOutImgMn^[lPos2Offset] := lSum/lImagesCount; if lttest then begin TStat2 (lImagesCount, lnGroup1, lObs,lT); lOutImgT^[lPos2Offset] := lT; end; if lBM then begin BMTest(lImagesCount, lnGroup1, lObs,lT); lOutImgBM^[lPos2Offset] := lT; //TStatAbs (lImagesCount, lnGroup1, lObs,lT); //lOutImgBM[lPos2Offset] := lT; end; StatPermuteThreaded (lttest,lBM,lImagesCount, lnGroup1,lnPermute,lThread, lObs); end; //in brain mask - compute end; //for each voxel freemem(lObsP); Terminate; end; { Paired T-Test} (*procedure PairedTTest (N, SumOfDifSqrs, SumDif: double;var t, p,DF: double); var meanDif, SumDifSqr, temp: double; begin df := n - 1; t := 0; p := 1; if (SumOfDifSqrs <> 0)and (SumDif <> 0)and (df <> 0) and (N <> 0) then begin meanDif := SumDif / N; SumDifSqr := sqr(SumDif); temp := SumOfDifSqrs - (SumDifSqr / n); temp := temp / (n * df); temp := sqrt(temp); if temp <> 0 then begin t := meanDif / temp; p := betai(0.5 * df, 0.5, df / (df + sqr(t))) end else {t is infinitely big} p := -1.0; end; end; {paired ttest} *) procedure TPairedTStat.Analyze(lUnused1,lUnused2: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); var lObsp: pointer; lObs: Doublep0; lT: Double; lPosPct,lPos,lPos2,lPos2Offset: integer; lSum: single; begin //statthread createArray64(lObsp,lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; if lMaskImg^[lPos2Offset] <> 0 then begin inc(gnVoxTestedRA[lThread]); lSum := 0; for lPos := 1 to lImagesCount do begin lObs^[lPos-1] := (gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; lSum := lSum + lObs^[lPos-1]; end; lOutImgMn^[lPos2Offset] := lSum/lImagesCount; PairedTStat (lImagesCount, lObs,lT); lOutImgT^[lPos2Offset] := lT; //StatPermuteThreaded (lttest,lBM,lImagesCount, lnGroup1,lnPermute,lThread, lObs); end; //in brain mask - compute end; //for each voxel freemem(lObsP); end; (*procedure TLesionStat.Analyze (lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); var lObsp: pointer; lObs: Doublep0; lT,lBMz,lDF: Double; lnLesion,lnNoLesion,lPosPct,lPos,lPos2,lPos2Offset,lnVoxTested: integer; begin //statthread createArray64(lObsp,lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; lnNoLesion := 0; for lPos := 1 to lImagesCount do begin if ((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]) = 0 then begin //no lesion inc(lnNoLesion); lObs^[lnNoLesion-1] := lSymptomRA^[lPos]; end else begin //lesion inc(lnLesion); lObs^[lImagesCount-lPos+lnNoLesion] := lSymptomRA^[lPos]; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) then begin inc(gnVoxTestedRA[lThread]); if lttest then begin TStat2 (lImagesCount, lnNoLesion, lObs,lT); lOutImgT^[lPos2Offset] := lT; end; if lBM then begin tBM (lImagesCount, lnNoLesion, lObs,lBMz,lDF); BMzVal (lImagesCount, lnNoLesion,lBMz,lDF); lOutImgBM^[lPos2Offset] := lBMz; end; StatPermuteThreaded (lttest,lBM,lImagesCount, lnNoLesion,lnPermute,lThread, lObs); end; //in brain mask - compute end; //for each voxel freemem(lObsP); end;*) procedure TLesionStat.Analyze (lttest,lBM: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgBM,lOutImgT,lSymptomRA: SingleP); //pattern variables const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lPrevZValsT,lPrevZValsBM: array [1..knPrevPattern] of Single; lPatternPos: integer; lLesionOrderp: bytep; //standard variables var lObsp: pointer; lObs: Doublep0; lT,lBMz,lDF: Double; lnLesion,lnNoLesion,lPosPct,lPos,lPos2,lPos2Offset,lnVoxTested: integer; begin //statthread //init patterns for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; getmem(lLesionOrderp, lImagesCount *sizeof(byte)); //now init standard variables createArray64(lObsp,lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; lnNoLesion := 0; for lPos := 1 to lImagesCount do begin if ((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]) = 0 then begin //no lesion inc(lnNoLesion); lLesionOrderp^[lPos] := 0; lObs^[lnNoLesion-1] := lSymptomRA^[lPos]; end else begin //lesion inc(lnLesion); lLesionOrderp^[lPos] := 1; lObs^[lImagesCount-lPos+lnNoLesion] := lSymptomRA^[lPos]; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) then begin inc(gnVoxTestedRA[lThread]); //now check if we have seen this precise lesion order recently... lPattern := SetOrderX (lLesionOrderp,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin //lesion pattern is not novel if lttest then lOutImgT^[lPos2Offset] := lPrevZvalsT[lPos]; if lBM then lOutImgBM^[lPos2Offset] := lPrevZvalsBM[lPos]; end else begin //lesion pattern is novel //record novel pattern inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; lPrevPatternRA[lPatternPos] := lPattern; if lttest then begin TStat2 (lImagesCount, lnNoLesion, lObs,lT); lOutImgT^[lPos2Offset] := lT; lPrevZValsT[lPatternPos] := lT; end; if lBM then begin tBM (lImagesCount, lnNoLesion, lObs,lBMz,lDF); BMzVal (lImagesCount, lnNoLesion,lBMz,lDF); lOutImgBM^[lPos2Offset] := lBMz; lPrevZValsBM[lPatternPos] := lBMz; end; StatPermuteThreaded (lttest,lBM,lImagesCount, lnNoLesion,lnPermute,lThread, lObs); end; //novel lesion pattern end; //in brain mask - compute end; //for each voxel freemem(lObsP); freemem(lLesionOrderp) end; procedure TLesionBinomial.Analyze (lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgL,lOutImgX,lSymptomRA: SingleP); //pattern variables const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lPrevZValsL,lPrevZValsX: array [1..knPrevPattern] of Single; lPatternPos: integer; lLesionOrderp: bytep; //standard variables var lObsp: pointer; lObs: Doublep0; lT: Double; lnLesion,lPosPct,lPos,lPos2,lPos2Offset,lnVoxTested: integer; begin //Binomial StatThread //init patterns for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; getmem(lLesionOrderp, lImagesCount *sizeof(byte)); //now init standard variables createArray64(lObsp,lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; for lPos := 1 to lImagesCount do begin if ((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]) = 0 then begin //no lesion lObs^[lImagesCount-lPos+lnLesion] := lSymptomRA^[lPos]; lLesionOrderp^[lPos] := 0; end else begin //lesion inc(lnLesion); lLesionOrderp^[lPos] := 1; lObs^[lnLesion-1] := lSymptomRA^[lPos]; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) then begin inc(gnVoxTestedRA[lThread]); //next check patterns lPattern := SetOrderX (lLesionOrderp,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin //lesion pattern is not novel //if lChi2 then // lOutImgX^[lPos2Offset] := lPrevZvalsX[lPos]; //if lLieber then lOutImgL^[lPos2Offset] := lPrevZvalsL[lPos]; end else begin //lesion pattern is novel //record novel pattern inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; lPrevPatternRA[lPatternPos] := lPattern; {if lChi2 then begin Chi2 (lImagesCount, lnLesion, lObs,lT); lOutImgX^[lPos2Offset] := lT;//lT; lPrevZValsX[lPatternPos] := lT; end; if lLieber then begin} Liebermeister2(lImagesCount, lnLesion, lObs,lT); lOutImgL^[lPos2Offset] := lT; lPrevZValsL[lPatternPos] := lT; //end; StatPermuteBinomialThreaded ({lChi2}false,lLieber,lImagesCount, lnLesion,lnPermute,lThread, lObs); end; end; //in brain mask - compute end; //for each voxel freemem(lObsP); freemem(lLesionOrderp) end; (*procedure TLesionBinomial.Analyze (lChi2,lLieber: boolean; lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount,lnGroup1 : integer; lMaskImg,lPlankImg,lOutImgMn,lOutImgL,lOutImgX,lSymptomRA: SingleP); var lObsp: pointer; lObs: Doublep0; lT: Double; lnLesion,lPosPct,lPos,lPos2,lPos2Offset,lnVoxTested: integer; begin //statthread createArray64(lObsp,lObs,lImagesCount); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; for lPos := 1 to lImagesCount do begin if ((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]) = 0 then begin //no lesion lObs^[lImagesCount-lPos+lnLesion] := lSymptomRA^[lPos]; end else begin //lesion inc(lnLesion); lObs^[lnLesion-1] := lSymptomRA^[lPos]; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCrit) and (lnLesion > 0) then begin inc(gnVoxTestedRA[lThread]); if lChi2 then begin Chi2 (lImagesCount, lnLesion, lObs,lT); lOutImgX^[lPos2Offset] := lT;//lT; end; if lLieber then begin Liebermeister2(lImagesCount, lnLesion, lObs,lT); lOutImgL^[lPos2Offset] := lT; end; StatPermuteBinomialThreaded (lChi2,lLieber,lImagesCount, lnLesion,lnPermute,lThread, lObs); end; //in brain mask - compute end; //for each voxel freemem(lObsP); end;*) end. ����������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/roc.pas��������������������������������������������������������0000755�0001750�0001750�00000027215�12156164746�016310� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit roc; interface //demonstrates the ROC tests that are in the Brunner.pas file uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,//Brunner,nifti_img, DISTR Messages, Classes, Graphics, Controls, Forms, Dialogsx, StdCtrls, ComCtrls,ExtCtrls,Menus, //overlap,ReadInt,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,IniFiles,cpucount,userdir,math, regmult,utypes; procedure testROC; procedure testROC2; function AUCbinomcont (lBinomdataRA,lContdataRA: singlep; lnSubj :integer): double; function AUCcontcont (ldatara1,ldatara2: singlep; lnSubj :integer): double; implementation uses npmform; function readCSV2 (lFilename: string; lCol1,lCol2: integer; var lnObservations : integer; var ldataRA1,ldataRA2: singlep): boolean; const kHdrRow = 0;//1; kHdrCol = 0;//1; var lNumStr: string; F: TextFile; lTempFloat: double; lCh: char; lnFactors,MaxC,R,C:integer; lError: boolean; begin lError := false; result := false; if not fileexists(lFilename) then begin ShowMsg('Can not find '+lFilename); exit; end; AssignFile(F, lFilename); FileMode := 0; //Set file access to read only //First pass: determine column height/width Reset(F); C := 0; MaxC := 0; R := 0; while not Eof(F) do begin //read next line //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 0; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if lNumStr <> '' then //july06- read data immediately prior to EOF inc(R); if (R <= (kHdrRow+1)) or (MaxC < (kHdrCol+lCol1)) or (MaxC < (kHdrCol+lCol2)) then begin ShowMsg('problems reading CSV - not enough columns/rows '+inttostr(lCol1)+' '+inttostr(lCol2)); exit; end; lnObservations := R -kHdrRow ; //-1: first row is header.... lnFactors := MaxC-1;// -1: first column is Y values //fx(lnObservations,lnFactors); //exit; getmem(ldataRA1,lnObservations*sizeof(single)); getmem(ldataRA2,lnObservations*sizeof(single)); //second pass Reset(F); C := 1; MaxC := 0; R := 1; lNumStr := ''; lTempfloat := 0; while not Eof(F) do begin //read next line Read(F, lCh); if lCh = '#' then while not (lCh in [#10,#13]) do Read(F, lCh) else if not (lCh in [#10,#13,#9,',']) then begin lNumStr := lNumStr + lCh; end else if lNumStr <> '' then begin if (R > kHdrRow) and (C > kHdrCol) then begin if ((C-kHdrCol) = lCol1) or ((C-kHdrCol) = lCol2) then begin if lNumStr = '-' then begin lTempFloat := 0; end else begin //number try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then ShowMsg('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except //showmessage(lNumStr); if (C-kHdrCol) = lCol1 then ldataRA1^[R-kHdrRow] := lTempFloat else if (C-kHdrCol) = lCol2 then ldataRA2^[R-kHdrRow] := lTempFloat; end; //number end; //col1 or col2 end;// else //R > 1 lNumStr := ''; inc(C); if C > MaxC then MaxC := C; if (lCh in [#10,#13]) then begin C := 1; inc(R); end; //eoln end; //if lNumStr <> '' and not tab end; if (lNumStr <> '') and (C = lnFactors) then begin //unterminated string try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin if not lError then ShowMsg('Empty cells? Error reading CSV file row:'+inttostr(R)+' col:'+inttostr(C)+' - Unable to convert the string '+lNumStr+' to a number'); lError := true; lTempFloat := nan; end; end;//except ldataRA2^[R-1] := lTempFloat; end;//unterminated string //read finel item CloseFile(F); FileMode := 2; //Set file access to read/write result := true; end; function AUCcontcont (ldatara1,ldatara2: singlep; lnSubj :integer): double; var lIn,lInDX : DoubleP0; lnGroup0,lnGroup1,lI: integer; begin result := 0.5; if lnSubj < 1 then exit; Getmem(lIn,lnSubj*sizeof(double)); Getmem(lInDX,lnSubj*sizeof(double)); for lI := 1 to lnSubj do begin lIn^[lI-1] := ldatara2^[lI]; lInDX^[lI-1] := ldatara1^[lI]; end; result := continROC2 (lnSubj, lIn, lInDX); freemem(lIn); freemem(lInDX); end; function AUCbinomcont (lBinomdataRA,lContdataRA: singlep; lnSubj :integer): double; var lIn : DoubleP0; lnGroup0,lnGroup1,lI: integer; begin result := 0.5; if lnSubj < 1 then exit; Getmem(lIn,lnSubj*sizeof(double)); lnGroup0 := 0; lnGroup1 := 0; for lI := 1 to lnSubj do begin if lBinomdataRA^[lI] = 0 then begin lIn^[lnGroup0] := lContdataRA^[lI]; inc (lnGroup0); end else begin inc (lnGroup1); lIn^[lnSubj-lnGroup1] := lContdataRA^[lI]; end; end; result := continROC (lnSubj, lnGroup0, lIn); freemem(lIn); end; procedure testROC; var lROC : single; lI,lnSubj,lnGroup0: integer; //lIn : DoubleP0; //csv lnGroup1,lCol1,lCol2: integer; var lnObservations : integer; var ldataRA1,ldataRA2: singlep ; begin npmform.MainForm.memo1.lines.clear; npmform.MainForm.memo1.lines.add('ROC analysis requires CSV format text file.'); npmform.MainForm.memo1.lines.add('First column is the filename (ignored).'); npmform.MainForm.memo1.lines.add('Second column is 0 [deficit present] or 1 [no deficit].'); npmform.MainForm.memo1.lines.add('Third column is number of voxels injured in ROI [0 or greater]:'); npmform.MainForm.memo1.lines.add('Example file:'); //npmform.MainForm.memo1.lines.add('deficit, voxels'); npmform.MainForm.memo1.lines.add('c:\c01.voi,0, 121'); npmform.MainForm.memo1.lines.add('c:\c02.voi,1, 33'); npmform.MainForm.memo1.lines.add('c:\c03.voi,0, 222'); npmform.MainForm.memo1.lines.add('c:\c04.voi,1, 56'); npmform.MainForm.memo1.lines.add('c:\c05.voi,1, 96'); npmform.MainForm.memo1.lines.add('c:\c06.voi,0, 100'); //get csv npmform.MainForm.memo1.lines.add(' ...requesting CSV file'); if not MainForm.OpenDialogExecute('Select comma separated filenames ',false,false,kTxtFilter) then exit; npmform.MainForm.memo1.lines.add(' ...reading CSV file'); if not readCSV2 (MainForm.OpenHdrDlg.Filename, 2,3, lnObservations, ldataRA1,ldataRA2) then exit; npmform.MainForm.memo1.lines.add(' ...observations: '+inttostr(lnObservations)); if lnObservations < 3 then begin ShowMsg('At least 3 subjects required.'); exit; end; lnSubj := lnObservations; lnGroup0 := 0; for lI := 1 to lnSubj do if ldatara1^[lI] = 0 then inc (lnGroup0); npmform.MainForm.memo1.lines.add(' ...observations with deficit [0]: '+inttostr(lnGroup0)); if (lnGroup0 = lnSubj) or (lnGroup0 = 0) then begin ShowMsg('Some values in the first column must be zero, some must be non-zero.'); exit; end; lROC := AUCbinomcont (ldatara1,ldatara2, lnSubj); (*Getmem(lIn,lnSubj*sizeof(double)); lnGroup0 := 0; lnGroup1 := 0; for lI := 1 to lnSubj do begin if ldatara1[lI] = 0 then begin lIn[lnGroup0] := ldatara2[lI]; inc (lnGroup0); end else begin inc (lnGroup1); lIn[lnSubj-lnGroup1] := ldatara2[lI]; end; end; lROC := continROC (lnSubj, lnGroup0, lIn); freemem(lIn); *) freemem(ldataRA1); freemem(ldataRA2); //now analyze npmform.MainForm.memo1.lines.add('ROC = '+floattostr(lROC)); //fx(lROC); end; procedure testROC2; var //lDouble: double; lVariable: boolean; lF,lROC : single; lI,lnSubj: integer; lIn,lInDX : DoubleP0; //csv lnGroup1,lCol1,lCol2: integer; var lnObservations : integer; var ldataRA1,ldataRA2: singlep ; begin npmform.MainForm.memo1.lines.clear; npmform.MainForm.memo1.lines.add('ROC analysis requires CSV format text file.'); npmform.MainForm.memo1.lines.add('First column is the filename (ignored).'); npmform.MainForm.memo1.lines.add('Second column is degree of deficit [lower value = more impaired].'); npmform.MainForm.memo1.lines.add('Third column is number of voxels injured in ROI [0 or greater]:'); npmform.MainForm.memo1.lines.add('Example file:'); //npmform.MainForm.memo1.lines.add('deficit, voxels'); npmform.MainForm.memo1.lines.add('c:\c01.voi,0.3, 121'); npmform.MainForm.memo1.lines.add('c:\c02.voi,0.1, 33'); npmform.MainForm.memo1.lines.add('c:\c03.voi,0.2, 222'); npmform.MainForm.memo1.lines.add('c:\c04.voi,1.3, 56'); npmform.MainForm.memo1.lines.add('c:\c05.voi,1.7, 96'); npmform.MainForm.memo1.lines.add('c:\c06.voi,1.5, 100'); //get csv npmform.MainForm.memo1.lines.add(' ...requesting CSV file'); if not MainForm.OpenDialogExecute('Select comma separated filenames ',false,false,kTxtFilter) then exit; npmform.MainForm.memo1.lines.add(' ...reading CSV file'); if not readCSV2 (MainForm.OpenHdrDlg.Filename, 2,3, lnObservations, ldataRA1,ldataRA2) then exit; npmform.MainForm.memo1.lines.add(' ...observations: '+inttostr(lnObservations)); if lnObservations < 3 then begin ShowMsg('At least 3 subjects required.'); exit; end; lnSubj := lnObservations; lF := ldatara1^[1]; lVariable := false; for lI := 1 to lnSubj do if ldatara1^[lI] <> lF then lVariable := true; if (not lVariable) then begin ShowMsg('The columns must have some variability.'); exit; end; Getmem(lIn,lnSubj*sizeof(double)); Getmem(lInDX,lnSubj*sizeof(double)); for lI := 1 to lnSubj do begin lIn^[lI-1] := ldatara2^[lI]; lInDX^[lI-1] := ldatara1^[lI]; end; freemem(ldataRA1); freemem(ldataRA2); //now analyze (*lnSubj := 10; lnGroup0 := 5; Getmem(lIn,lnSubj*sizeof(double)); for lI := 0 to (lnSubj-1) do lIn[lI] := -lI;//random(99); *) lROC := continROC2 (lnSubj, lIn, lInDX); npmform.MainForm.memo1.lines.add('ROC = '+floattostr(lROC)); freemem(lIn); freemem(lInDX); end; (*procedure testROC; var lROC : single; lI,lnSubj,lnGroup0: integer; lIn : DoubleP0; begin lnSubj := 10; lnGroup0 := 5; Getmem(lIn,lnSubj*sizeof(double)); for lI := 0 to (lnSubj-1) do lIn[lI] := -lI;//random(99); lROC := continROC (lnSubj, lnGroup0, lIn); npmform.MainForm.memo1.lines.add('ROC = '+floattostr(lROC)); //fx(lROC); freemem(lIn); end; *) end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/Notes.txt������������������������������������������������������0000755�0001750�0001750�00000005172�12251125330�016625� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Chris Rorden's 32-bit NPM: 28 August 2013 32bit; Threads used = 4 plankSize: 512mb Single Linear Regression [Weighted Least Squares] Mask = /Users/rorden/Downloads/dazhou_npm_glitch/BinaryLesionMask.nii Total voxels = 510340 Number of observations = 35 Image,FLU /Users/rorden/Downloads/dazhou_npm_glitch/zwrTW_T2.nii,0 /Users/rorden/Downloads/dazhou_npm_glitch/zwrRH_T2.nii,5 /Users/rorden/Downloads/dazhou_npm_glitch/zwrRW_T2.nii,9 /Users/rorden/Downloads/dazhou_npm_glitch/zwrDE_T2.nii,4 /Users/rorden/Downloads/dazhou_npm_glitch/zwrJR_T2.nii,5 /Users/rorden/Downloads/dazhou_npm_glitch/zwrFJ_T2.nii,0 /Users/rorden/Downloads/dazhou_npm_glitch/zwrAC_T2.nii,7 /Users/rorden/Downloads/dazhou_npm_glitch/zwrMJ_T2.nii,4 /Users/rorden/Downloads/dazhou_npm_glitch/zwrAS_T2.nii,8 /Users/rorden/Downloads/dazhou_npm_glitch/zwrSH_T2.nii,1 /Users/rorden/Downloads/dazhou_npm_glitch/zwrDV_T2.nii,1 /Users/rorden/Downloads/dazhou_npm_glitch/zwrLO_T2.nii,10 /Users/rorden/Downloads/dazhou_npm_glitch/zwrMB_T2.nii,9 /Users/rorden/Downloads/dazhou_npm_glitch/zwrAS2_T2.nii,7 /Users/rorden/Downloads/dazhou_npm_glitch/zwrJR2_T2.nii,9 /Users/rorden/Downloads/dazhou_npm_glitch/zwrSF_T2.nii,1 /Users/rorden/Downloads/dazhou_npm_glitch/zwrTC_T2.nii,7 /Users/rorden/Downloads/dazhou_npm_glitch/zwrTR2_T2.nii,2 /Users/rorden/Downloads/dazhou_npm_glitch/zwrGK2_T2.nii,8 /Users/rorden/Downloads/dazhou_npm_glitch/zwrMH_T2.nii,1 /Users/rorden/Downloads/dazhou_npm_glitch/zwrTM_T2.nii,3 /Users/rorden/Downloads/dazhou_npm_glitch/zwrRS_T2.nii,9 /Users/rorden/Downloads/dazhou_npm_glitch/zwrAH_T2.nii,4 /Users/rorden/Downloads/dazhou_npm_glitch/zwrMB2_T2.nii,6 /Users/rorden/Downloads/dazhou_npm_glitch/zwrJM2_T2.nii,2 /Users/rorden/Downloads/dazhou_npm_glitch/zwrRC2_T2.nii,7 /Users/rorden/Downloads/dazhou_npm_glitch/zwrLM_T2.nii,4 /Users/rorden/Downloads/dazhou_npm_glitch/zwrMK_T2.nii,1 /Users/rorden/Downloads/dazhou_npm_glitch/zwrPC_T2.nii,7 /Users/rorden/Downloads/dazhou_npm_glitch/zwr125_T2.nii,4 /Users/rorden/Downloads/dazhou_npm_glitch/zwrJE_T2.nii,9 /Users/rorden/Downloads/dazhou_npm_glitch/zwrJY_T2.nii,4 /Users/rorden/Downloads/dazhou_npm_glitch/zwrJA_T2.nii,9 /Users/rorden/Downloads/dazhou_npm_glitch/zwrMW_T2.nii,5 /Users/rorden/Downloads/dazhou_npm_glitch/zwrML_T2.nii,9 Analysis began = 2013-22-08 13:22:21 Mask has voxels from 4080..468678 Memory planks = 0.121153637537577 Max voxels per Plank = 3834792 Computing plank = 1 Voxels tested = 75335 75335 test Std Bonferroni FWE Z 0.050=4.836, 0.025=4.972, 0.01=5.146 wlsFLU Range -5.551...3.209 wlsFLU +FDR Z 0.050=9.20000000, 0.01=9.20000000 wlsFLU -FDR Z 0.050=-2.31827721, 0.01=-3.42041674 Analysis finished = 2013-22-08 13:22:31������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/brunner.pas����������������������������������������������������0000755�0001750�0001750�00000040071�11326425446�017166� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit brunner; interface uses define_types,math,Distr; procedure tBM (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var ltBM,lDF: double); procedure genBMsim (lnSubj: integer; var lOrigOrder: DoubleP0); function BMzVal(lnSubj, lnGroup0: integer; ltBM,lDF: double): double; function continROC (lnSubj, lnGroup0: integer; var lIn: DoubleP0): single; function continROC2 (lnSubj: integer; var lInIV, lInDV: DoubleP0): single; const knPermute= 20000; knSim = 15; var gSimRA: array [1..knSim] of DoubleP; gSimRAp: array [1..knSim] of pointer; implementation function BMzVal(lnSubj,lnGroup0 : integer; ltBM,lDF: double): double; //can be approximated by result := TtoZ(ltBM,lDF); var lnSmallGroup,lJump,lEstimate,i,tie: integer; ltBMs : double; lSwap: boolean; begin //result := TtoZ(ltBM,lDF); exit; lSwap := false; ltBMs := ltBM; result := 0; tie := 0; if (lnSubj div 2) > lnGroup0 then lnSmallGroup := lnGroup0 else lnSmallGroup := lnSubj-lnGroup0; if lnSmallGroup < 1 then exit; if lnSmallGroup > knSim then begin result := TtoZ(ltBMs,lDF); exit; end; if (lnSubj div 2) < lnGroup0 then begin ltBMs := -ltBMs; lSwap := not lSwap; //distributions are not symetrical end; lEstimate := knPermute div 2; //start half way through data lJump := lEstimate div 2; for i := 1 to 9 do begin if gSimRA[lnSmallGroup]^[lEstimate] > ltBMs then lEstimate := lEstimate - lJump else lEstimate := lEstimate + lJump; lJump := (lJump+1) div 2; end; if lEstimate < (knPermute div 2) then begin //p < 0.5 count up for less extreme i := lEstimate-lJump-lJump; if i < 1 then i := 1; while ltBMs > gSimRA[lnSmallGroup]^[i] do begin inc(i); end; if ltBMs = gSimRA[lnSmallGroup]^[i] then begin while ltBMs = gSimRA[lnSmallGroup]^[i] do begin inc(i); dec(tie); end; dec(tie); end; end else begin //p < 0.5 count down for less extreme i := lEstimate+lJump+lJump; if i >= knPermute then i := knPermute; while ltBMs < gSimRA[lnSmallGroup]^[i] do dec(i); if ltBMs = gSimRA[lnSmallGroup]^[i] then begin while ltBMs = gSimRA[lnSmallGroup]^[i] do begin dec(i); inc(tie); end; inc(tie); end; i := i - 1; //indexed from 1 not 0 end; //result := (i+(tie/2)); //result := (1-( (i+(tie/2))/knPermute)); result := pNormalInv(1-( (i+(tie/2))/knPermute)); if lSwap then result := -result; end; procedure Sort (lo, up: integer; var r:DoubleP); //62ms Shell Sort http://www.dcc.uchile.cl/~rbaeza/handbook/algs/4/414.sort.p.html label 999; var d, i, j : integer; tempr : single; begin d := up-lo+1; while d>1 do begin if d<5 then d := 1 else d := trunc( 0.45454*d ); // Do linear insertion sort in steps size d for i:=up-d downto lo do begin tempr := r^[i]; j := i+d; while j <= up do if tempr > r^[j] then begin r^[j-d] := r^[j]; j := j+d end else goto 999; {*** break ***} 999: r^[j-d] := tempr end end end; //sort procedure GenPermute (lnSubj: integer; var lOrigOrder,lRanOrder: DoubleP0); var lInc,lRand: integer; lSwap: double; begin //next lines commented out - this check should be done before inner loop //if lnSubj < 2 then //can not randomize order of single value // exit; //Move(src,dest,count); Move(lOrigOrder^,lRanOrder^,lnSubj*sizeof(double)); //for lInc := 1 to lnSubj do // lRanOrder[lInc-1] := lOrigOrder[lInc-1]; for lInc := lnSubj downto 2 do begin lRand := Random(lInc); lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc-1]; lRanOrder^[lInc-1] := lSwap; end; end; procedure genBMsim (lnSubj: integer; var lOrigOrder: DoubleP0); //1.) creates kSim random permutations of the data //2.) sorts permutations var lRanOrderp: pointer; lRanOrder: DoubleP0; lInc,lnSmallGroup: integer; lOutT,lDF: double; begin if (lnSubj < 1) or (knPermute < 1) then exit; createArray64(lRanOrderp,lRanOrder,lnSubj); //lnSmallGroup := lnGroup0; //if lnSmallGroup > knSim then exit; for lnSmallGroup := 1 to knSim do begin //RandSeed := 128; //same order for all voxels for lInc := 1 to knPermute do begin GenPermute(lnSubj, lOrigOrder,lRanOrder); //generate random order of participants tBM (lnSubj, lnSmallGroup, lRanOrder,lOutT,lDF); gSimRA[lnSmallGroup]^[lInc] := lOutT; end; //next sort permutes... Sort(1,knPermute,gSimRA[lnSmallGroup]); end; freemem(lRanOrderp); end; procedure SortDouble (first, last: integer; var DynDataRA:DoubleP0; var lGroupRA: Bytep0); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} {less memory intensive than recursive quicksort} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n, nn, m, lognb2, l, k, j, i: INTEGER; swap: Single; swapbyte: byte; begin n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 0 to k do begin i := j; 555: {<- LABEL} l := i + m; if (DynDataRA^[l] < DynDataRA^[i]) then begin swap := DynDataRA^[i]; DynDataRA^[i] := DynDataRA^[l]; DynDataRA^[l] := swap; swapbyte := lGroupRA^[i]; lGroupRA^[i] := lGroupRA^[l]; lGroupRA^[l] := swapbyte; i := i - m; if (i >= 0) then goto 555; end end end end;//sort procedure RankArray (first, last: integer; var DynDataRA:DoubleP0; var lGSum: double); var lnTies,lPos,lStartPos,lRankPos: integer; lScore,lTie : double; begin lGSum := 0; lPos := first; while lPos <= last do begin lStartPos := lPos; lScore := DynDataRA^[lPos]; while (lPos < last) and (lScore = DynDataRA^[lPos+1]) do inc(lPos); //count ties lnTies := lPos - lStartPos; lTie := (lnTies) *0.5; if lnTies > 0 then begin lnTies := lnTies+1;//tj on page 135 of Siegel lGSum := lGSum + (( (lnTies*lnTies*lnTies) - lnTies)/12); //showmessage(inttostr(lnTies)+' '+realtostr(lGSum,4)); end; for lRankPos := lStartPos to lPos do DynDataRA^[lRankPos] := lStartPos+1+lTie; inc(lPos);//start with next value end; end; procedure LocalRank (first, last: integer; var DynDataRA,DynDataRAX:DoubleP0; var lGroupRA: Bytep0); var lGroup,lnTies,lPos,lStartPos,lRankPos,lLocalRank: integer; lScore,lTie : double; begin for lGroup := 0 to 1 do begin lPos := first; lLocalRank := 0; while lPos <= last do begin if lGroupRA^[lPos] = lGroup then begin// inc(lLocalRank); lStartPos := lPos; lScore := DynDataRA^[lPos]; lnTies := 0; while (lPos < last) and (0.001 > abs (lScore - DynDataRA^[lPos+1]) ) do begin inc(lPos); //count ties if lGroupRA^[lPos] = lGroup then inc(lnTies); end; lTie := (lnTies) *0.5; for lRankPos := lStartPos to lPos do begin if lGroupRA^[lRankPos] = lGroup then DynDataRAX^[lRankPos] := (lLocalRank+lTie); end; lLocalRank := lLocalRank + lnTies; end; //if in group inc(lPos);//start with next value end; //while... for each observation end; //for each group end; (*procedure tBM (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var ltBM,lDF: double); //this is a t-test - only use to test BM!!! var i,lnGroupY,lnGroupX: integer; lSumX,lSumY,lSumSqrx,lSumSqry,lVarx,lVary,lS: double; begin lnGroupX := lnGroup0; lnGroupY := lnSubj - lnGroupX; lDF := lnSubj -1; if (lnGroupX < 1) or (lnGroupY < 1) then begin //need at least 1 subj in each group ltBM := 0; exit; end; lSumx := 0; lSumSqrX := 0; for i := 0 to (lnGroupX-1) do begin //for each subject //lVal := lIn[i]; lsumx := lsumx + lIn[i]; lSumSqrX := lSumSqrX + sqr(lIn[i]); end; //lMnX := lsumx/lnGroupX; lVarx := (lnGroupX*lSumSqrX) - Sqr(lsumx); if lnGroupX > 1 then lVarX := lVarX / (lnGroupX*(lnGroupX-1)) else lVarx := 0; lSumy := 0; lSumSqry := 0; for i := lnGroupX to (lnSubj-1) do begin //for each subject //lVal := lIn[i]; lsumy := lsumy + lIn[i]; lSumSqry := lSumSqry + sqr(lIn[i]); end; //for each sub //lMnY := lsumy/lnGroupY; lVary := (lnGroupY*lSumSqrY) - Sqr(lsumy); if lnGroupY > 1 then lVary := lVary / (lnGroupY*(lnGroupY-1)) else lVary := 0; //lm := (lsumx/lnGroupX)-(lsumy/lnGroupY); //mean effect size lmnx - lmny; //ldf := lnSubj - 2; ls := sqrt( ( ((lnGroupX - 1) * lvarx + (lnGroupY - 1) * lvary) / (lnSubj - 2){ldf}) ) ; ls := ls * sqrt(1 / lnGroupX + 1 / lnGroupY); //note - to get here both lnx and lny > 0 if ls = 0 then ltBM := 0 else ltBM := ( ((lsumx/lnGroupX)-(lsumy/lnGroupY))/ls);//t = lm / ls; end; *) procedure tBM (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var ltBM,lDF: double); var lObspX,lObsp: pointer; lObsX,lObs: Doublep0; lGroupRA: Bytep0; i,ln0,ln1: integer; lZ,lGSum: double; lSum0,lSum1,lMean0,lMean1,lSqr0,lSqr1,lk0,lk1: double; begin createArray64(lObsp,lObs,lnSubj); getmem(lGroupRA,lnSubj*sizeof(Byte)); createArray64(lObspX,lObsX,lnSubj); ln0 := 0; ln1 := 0; for i := 0 to (lnSubj-1) do begin //for each subject //lVal := lIn[i]; lObs[i] := lIn[i]; if i < lnGroup0 then //group0 lGroupRA^[i] := 0 else lGroupRA^[i] := 1; end; //for each sub for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then inc(ln0) //number of observations in group zero else inc(ln1); //number of observations in group one if (ln0 > 1) and (ln1 > 1) then begin SortDouble(0,lnSubj-1,lObs,lGroupRA); RankArray(0,lnSubj-1,lObs,lGSum); lSum0 := 0; lSum1 := 0; for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then lSum0 := lSum0 + lObs^[i] else lSum1 := lSum1 + lObs^[i]; lMean0 := lSum0 / ln0; lMean1 := lSum1 / ln1; //fx(lmean0,lMean1); lSqr0 := 0; lSqr1 := 1; lk0 := (ln0+1)/2; lk1 := (ln1+1)/2; LocalRank(0,lnSubj-1,lObs,lObsX,lGroupRA); for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then lSqr0 := lSqr0 + Sqr(lObs^[i]-lObsX^[i]-lMean0+lk0) else lSqr1 := lSqr1 + Sqr(lObs^[i]-lObsX^[i]-lMean1+lk1); lSqr0 := (1/(ln0-1))*lSqr0; lSqr1 := (1/(ln1-1))*lSqr1; lZ := -(ln0*ln1*(lMean1-lMean0))/((ln0+ln1)*sqrt((ln0*lSqr0)+(ln1*lSqr1) ) ); lDF := sqr(ln0*lSqr0+ln1*lSqr1) / ( (sqr(ln0*lSqr0)/(ln0-1)) + (sqr(ln1*lSqr1)/(ln1-1)) ) ; //lZ := TtoZ(lZ,lDF); ltBM := lZ; //fx(lZ,lDF); end else //>1 ltBM := 0; freemem(lObsp); freemem(lObspX); freemem(lGroupRA); end; //tBM (**) procedure SortDoubleP0 (first, last: integer; var DynDataRA:DoubleP0); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} {less memory intensive than recursive quicksort} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n, nn, m, lognb2, l, k, j, i: INTEGER; swap: Single; //swapbyte: byte; begin n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 0 to k do begin i := j; 555: {<- LABEL} l := i + m; if (DynDataRA^[l] < DynDataRA^[i]) then begin swap := DynDataRA^[i]; DynDataRA^[i] := DynDataRA^[l]; DynDataRA^[l] := swap; i := i - m; if (i >= 0) then goto 555; end end end end;//sort function continROC (lnSubj, lnGroup0: integer; var lIn: DoubleP0): single; //see equation 1 of Obuchiwski, Statistics in Medicine, 25: 481-493 var lSum,lV: double; linc0,linc1,lnGroup1,i: integer; lObsp0,lObsp1: pointer; lObs0,lObs1: Doublep0; begin result := -1; lnGroup1 := lnSubj - lnGroup0; if (lnGroup1 < 1) or (lnGroup0 < 1) then exit; createArray64(lObsp1,lObs1,lnSubj); createArray64(lObsp0,lObs0,lnSubj); for i := 0 to (lnGroup0-1) do //for each subject without disease lObs0[i] := lIn[i]; SortDoubleP0(0,lnGroup0-1,lObs0); for i := lnGroup0 to (lnSubj-1) do //for each subject with disease lObs1[i-lnGroup0] := lIn[i]; SortDoubleP0(0,lnGroup1-1,lObs1); lSum := 0; for linc0 := 0 to (lnGroup0-1) do begin for linc1 := 0 to (lnGroup1-1) do begin if (lObs0^[linc0]) > (lObs1^[linc1]) then lV := 1 else if (lObs0^[linc0]) = (lObs1^[linc1]) then //tie lV := 0.5 else lV := 0; lSum := lV + lSum; end;//for group1 end;//for group0 lSum := lSum * (1/ (lnGroup0*lnGroup1 ) ); result := lSum; freemem(lObsp1); freemem(lObsp0); end; //continROC procedure SortDoubleDouble (first, last: integer; var DynDataRA, lGroupRA: DoubleP0); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} {less memory intensive than recursive quicksort} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n, nn, m, lognb2, l, k, j, i: INTEGER; swap,swapbyte: double; begin n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 0 to k do begin i := j; 555: {<- LABEL} l := i + m; if (DynDataRA^[l] < DynDataRA^[i]) then begin swap := DynDataRA^[i]; DynDataRA^[i] := DynDataRA^[l]; DynDataRA^[l] := swap; swapbyte := lGroupRA^[i]; lGroupRA^[i] := lGroupRA^[l]; lGroupRA^[l] := swapbyte; i := i - m; if (i >= 0) then goto 555; end end end end;//sort function continROC2 (lnSubj: integer; var lInIV, lInDV: DoubleP0): single; //see equation 9 of Obuchiwski, Statistics in Medicine, 25: 481-493 var lSum,lV: double; linci,lincj,i: integer; lObspIV,lObspDV: pointer; lObsIV,lObsDV: Doublep0; begin result := -1; if (lnSubj < 1) then exit; createArray64(lObspIV,lObsIV,lnSubj); createArray64(lObspDV,lObsDV,lnSubj); for i := 0 to (lnSubj-1) do //for each subject without disease lObsIV[i] := lInIV[i]; for i := 0 to (lnSubj-1) do //for each subject without disease lObsDV[i] := lInDV[i]; SortDoubleDouble(0,lnSubj-1,lObsIV,lObsDV); lSum := 0; for linci := 0 to (lnSubj-1) do begin for lincj := 0 to (lnSubj-1) do begin if lincj <> linci then begin if ((lObsDV^[linci] > lObsDV^[lincj]) and (lObsIV^[linci] > lObsIV^[lincj])) or ((lObsDV^[linci] < lObsDV^[lincj]) and (lObsIV^[linci] < lObsIV^[lincj])) then lV := 1 else if (lObsDV^[linci] = lObsDV^[lincj]) or (lObsIV^[linci] = lObsIV^[lincj]) then //tie lV := 0.5 else lV := 0; lSum := lV + lSum; end; end;//for group1 end;//for group0 lSum := lSum * (1/ (lnSubj* (lnSubj-1) ) ); result := lSum; freemem(lObspDV); freemem(lObspIV); end; //continROC2 var i: integer; initialization begin for i := 1 to knSim do createArray64(gSimRAp[i],gSimRA[i],knPermute); end; finalization begin for i := 1 to knSim do freemem(gSimRAp[i]); end; end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/associate.pas��������������������������������������������������0000755�0001750�0001750�00000002643�11326425446�017471� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit associate; interface uses Windows,registry,Forms,dialogs,SysUtils; function registerfiletype(inft,inkey,desc,icon:string): boolean; implementation function registerfiletype(inft,inkey,desc,icon:string): boolean; var myreg : treginifile; ct : integer; ft,key: string; begin result := true; ft := inft; key := inkey; ct := pos('.',ft); while ct > 0 do begin delete(ft,ct,1); ct := pos('.',ft); end; if (ft = '') or (Application.ExeName = '') then exit; //not a valid file-ext or ass. app ft := '.'+ft; myreg := treginifile.create(''); try myreg.rootkey := hkey_classes_root; // where all file-types are described if key = '' then key := copy(ft,2,maxint)+'_auto_file'; // if no key-name is given, create one myreg.writestring(ft,'',key); // set a pointer to the description-key myreg.writestring(key,'',desc); // write the description myreg.writestring(key+'\DefaultIcon','',icon); // write the def-icon if given //showmessage(key); myreg.writestring(key+'\shell\open\command','',Application.ExeName+' %1'); //association except result := false; showmessage('Only administrators can change file associations. You are currently logged in as a restricted user.'); end; //finally myreg.free; //end; end; end.���������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/npm.res��������������������������������������������������������0000755�0001750�0001750�00000001554�12306713722�016312� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ������������������������� ��������� ��������(��� ���@�����������������������������������������������������������������������3wywwywwwwww������������������������wwww���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������0����M�A�I�N�I�C�O�N��������� ������������ ����������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/stats.pas������������������������������������������������������0000755�0001750�0001750�00000101774�12266252140�016652� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit stats; interface uses define_types,statcr,DISTR ,SysUtils,Dialogsx; procedure TStat2 (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutT: double); //procedure TStatAbs (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutT: double); procedure PairedTStat (lnSubj: integer; var lIn: DoubleP0; var lOutT: double); procedure TStatWelch (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var lOutT: double); procedure WilcoxonMW2 (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var lOutT: double); procedure MeanMedian(lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lMeanFX,lMedianFX: double); procedure TStat2Z (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutT: double); procedure BMTest (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var lOutT: double); procedure Liebermeister2 (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutZ: double); procedure Liebermeister2b (lnSubj, lnGroupX: integer; var lIn: ByteP0; var lAUC,lOutZ: double); procedure Liebermeister2bP (lnSubj, lnGroupX: integer; var lIn: ByteP0; var lOutP: double); //procedure Liebermeister2bPlus (lnSubj, lnGroupX: integer; var lIn: ByteP0; var lAUC, lOutP: double); //function Aprime (lHit,lFA: double): double; //function AUC (lHit,lFA: double): double; //function rocAUC (lHit,lFA: double): double; function rocAUC (lnYesDeficitYesLesion,lnNoDeficitYesLesion,lnYesDeficitNoLesion,lnNoDeficitNoLesion: integer): double; procedure Chi2 (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutZ: double); implementation procedure Chi2 (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutZ: double); var lVal: double; // luChiP: double; i,lnYesDeficit1,lnYesDeficit0,lnNoDeficit1,lnNoDeficit0, lnYesDeficit,lnNoDeficit: integer; begin lnYesDeficit0 := 0; lnYesDeficit1 := 0; lnNoDeficit0 := 0; lnNoDeficit1 := 0; for i := 0 to (lnGroupX-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit0) else inc(lnNoDeficit0); end; for i := lnGroupX to (lnSubj-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit1) else inc(lnNoDeficit1); end; //for each sub lnYesDeficit :=lnYesDeficit0+lnYesDeficit1; lnNoDeficit := lnNoDeficit0+lnNoDeficit1; if (lnYesDeficit<1) or (lnNoDeficit<1) then lOutZ := 0 else begin lVal := Fisher(lnYesDeficit0, lnYesDeficit1, lnNoDeficit0, lnNoDeficit1); if lVal < 0 then lOutZ := -pNormalInv(abs(lVal)) else lOutZ := pNormalInv(lVal) (*Chi2x2 (lnYesDeficit0, lnYesDeficit1, lnNoDeficit0, lnNoDeficit1,lMinExp,lChi,lChip,luChi, luChiP); if (lnYesDeficit1/lnYesDeficit) > (lnNoDeficit1/lnNoDeficit) then lOutZ := -luChi//t = m / d; else lOutZ := luChi;//t = m / d; *) end; //compute chi end; function rocAz (lHit,lFA: double): double; //see Zhang and Mueller, 2005, Psychometrika 70, 145-154 var lH,lF: double; begin if (lHit = 1) and (lFA = 0) then begin result := 1; exit; end; if (lHit = 0) and (lFA = 1) then begin result := 0; exit; end; if lHit >= lFA then begin//normal: better than chance lH := lHit; lF := lFA; end else begin //..else worse than chance lF := lHit; lH := lFA; end; if (lF <= 0.5) and (0.5 <= lH) then result := 0.75+ ((lH-lF)*0.25)- lF*(1-lH) else if (lF <= lH) and (lH < 0.5) then begin if (4*lH) = 0 then result := 0.5 else result := 0.75+ ((lH-lF)*0.25)- (lF/(4*lH)) end else if (0.5 < lF) and (lF <= lH) then begin if (4*(1-lF)) = 0 then result := 0.5 else result := 0.75 + ((lH-lF)*0.25) - ((1-lH)/(4*(1-lF))) end else ShowMsg('error in Zhang and Mueller, 2005 (func rocA)'); if lHit < lFA then //worse than chance result := 1 - result; end; function rocAUC (lnYesDeficitYesLesion,lnNoDeficitYesLesion,lnYesDeficitNoLesion,lnNoDeficitNoLesion: integer): double; var lHitRate,lFalseAlarmRate: double; begin result := 0.5; if ((lnYesDeficitYesLesion+lnNoDeficitYesLesion)=0) or ((lnYesDeficitNoLesion+lnNoDeficitNoLesion)=0) then exit; lHitRate := lnYesDeficitYesLesion/(lnYesDeficitYesLesion+lnNoDeficitYesLesion); lFalseAlarmRate := lnYesDeficitNoLesion/(lnYesDeficitNoLesion+lnNoDeficitNoLesion); result := rocAz(lHitRate,lFalseAlarmRate); end; (*function Aprime (lHit,lFA: double): double; //see Wickens Elementary Signal Detection, equation 4.11, page 71 //problem - not symetrical: values less than 0.5 extreme - // does not deal with lFA > lHit begin if (lFA=1) or (lHit = 0) then result := 0.5 //avoid divide by zero else result := 1 - 0.25*( ((1-lHit)/(1-lFA)) + lFA/lHit); end;*) (*function AUC (lHit,lFA: double): double; var lNum,lDenom: double; begin if (lHit> lFA) then begin lNum := (lHit-lFA)*(1+lHit-lFA); lDenom := 4 * lHit * (1 - lFA); if lDenom = 0 then result := 0 else result := 0.5+ (lNum/lDenom); end else begin lNum := (lFA-lHit)*(1+lFA-lHit); lDenom := 4 * lFA * (1 - lHit); if lDenom = 0 then result := 0 else result := 0.5- (lNum/lDenom); end; end; *) procedure ROCbinomialAUC (lnSubj, lnGroupX: integer; var lIn: ByteP0; var lAUC: double); //Receiver operating characteristic area under curve for binimial data //Liebermeister QuasiExact - excellent power var i,lnYesDeficit1,lnYesDeficit0,lnNoDeficit1,lnNoDeficit0, lnYesDeficit,lnNoDeficit: integer; //lHitRate,lFalseAlarmRate: double; begin lnYesDeficit0 := 0; lnYesDeficit1 := 0; lnNoDeficit0 := 0; lnNoDeficit1 := 0; for i := 0 to (lnGroupX-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit0) else inc(lnNoDeficit0); end; for i := lnGroupX to (lnSubj-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit1) else inc(lnNoDeficit1); end; //for each sub lAUC := rocAUC (lnYesDeficit1,lnNoDeficit1,lnYesDeficit0,lnNoDeficit0); (*lHitRate := lnYesDeficit1/(lnYesDeficit1+lnNoDeficit1); lFalseAlarmRate := lnYesDeficit0/(lnYesDeficit0+lnNoDeficit0); lAUC := rocA {AUC} (lHitRate,lFalseAlarmRate); *) end; procedure Liebermeister2bP (lnSubj, lnGroupX: integer; var lIn: ByteP0; var lOutP: double); //Liebermeister QuasiExact - excellent power var i,lnYesDeficit1,lnYesDeficit0,lnNoDeficit1,lnNoDeficit0, lnYesDeficit,lnNoDeficit: integer; //lMaxChi,lMinChi: single; begin lnYesDeficit0 := 0; lnYesDeficit1 := 0; lnNoDeficit0 := 0; lnNoDeficit1 := 0; for i := 0 to (lnGroupX-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit0) else inc(lnNoDeficit0); end; for i := lnGroupX to (lnSubj-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit1) else inc(lnNoDeficit1); end; //for each sub lnYesDeficit :=lnYesDeficit0+lnYesDeficit1; lnNoDeficit := lnNoDeficit0+lnNoDeficit1; if (lnYesDeficit<1) or (lnNoDeficit<1) then lOutP := 0 else begin lOutP := Liebermeister(lnYesDeficit0, lnYesDeficit1, lnNoDeficit0, lnNoDeficit1); end; //compute chi end; procedure Liebermeister2b (lnSubj, lnGroupX: integer; var lIn: ByteP0; var lAUC,lOutZ: double); //(lnRow,lnCol: integer; var lIn,lOutZ: DoubleP0); //Liebermeister QuasiExact - excellent power var lVal: double; i,lnYesDeficitNoLesion,lnYesDeficitYesLesion,lnNoDeficitNoLesion,lnNoDeficitYesLesion, lnYesDeficit,lnNoDeficit: integer; //lHitRate,lFalseAlarmRate: double; //lMaxChi,lMinChi: single; begin lnYesDeficitYesLesion := 0; lnYesDeficitNoLesion := 0; lnNoDeficitYesLesion := 0; lnNoDeficitNoLesion := 0; for i := 0 to (lnGroupX-1) do begin //for each lesioned subject if lIn^[i] = 0 then inc(lnYesDeficitYesLesion) else inc(lnNoDeficitYesLesion); end; for i := lnGroupX to (lnSubj-1) do begin //for each unlesioned subject if lIn^[i] = 0 then inc(lnYesDeficitNoLesion) else inc(lnNoDeficitNoLesion); end; //for each sub lnYesDeficit :=lnYesDeficitYesLesion+lnYesDeficitNoLesion; lnNoDeficit := lnNoDeficitYesLesion+lnNoDeficitNoLesion; if (lnYesDeficit<1) or (lnNoDeficit<1) then lOutZ := 0 else begin lVal := Liebermeister(lnYesDeficitYesLesion, lnYesDeficitNoLesion, lnNoDeficitYesLesion, lnNoDeficitNoLesion); if lVal < 0 then lOutZ := -pNormalInv(abs(lVal)) else lOutZ := pNormalInv(lVal) end; //compute chi lAUC := rocAUC (lnYesDeficitYesLesion,lnNoDeficitYesLesion,lnYesDeficitNoLesion,lnNoDeficitNoLesion); {lFalseAlarmRate := lnYesDeficitNoLesion/(lnYesDeficitNoLesion+lnNoDeficitNoLesion); lHitRate := lnYesDeficitYesLesion/(lnYesDeficitYesLesion+lnNoDeficitYesLesion); lAUC := rocAz (lHitRate,lFalseAlarmRate); } //if lOutZ > 4 then ax(lnYesDeficitYesLesion,lnNoDeficitYesLesion,lnYesDeficitNoLesion,lnNoDeficitNoLesion,lauc,lOutZ); end; procedure Liebermeister2 (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutZ: double); //(lnRow,lnCol: integer; var lIn,lOutZ: DoubleP0); //Liebermeister QuasiExact - excellent power var lVal: double; i,lnYesDeficit1,lnYesDeficit0,lnNoDeficit1,lnNoDeficit0, lnYesDeficit,lnNoDeficit: integer; //lMaxChi,lMinChi: single; begin lnYesDeficit0 := 0; lnYesDeficit1 := 0; lnNoDeficit0 := 0; lnNoDeficit1 := 0; for i := 0 to (lnGroupX-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit0) else inc(lnNoDeficit0); end; for i := lnGroupX to (lnSubj-1) do begin //for each subject if lIn^[i] = 0 then inc(lnYesDeficit1) else inc(lnNoDeficit1); end; //for each sub lnYesDeficit :=lnYesDeficit0+lnYesDeficit1; lnNoDeficit := lnNoDeficit0+lnNoDeficit1; if (lnYesDeficit<1) or (lnNoDeficit<1) then lOutZ := 0 else begin lVal := Liebermeister(lnYesDeficit0, lnYesDeficit1, lnNoDeficit0, lnNoDeficit1); if lVal < 0 then lOutZ := -pNormalInv(abs(lVal)) else lOutZ := pNormalInv(lVal) end; //compute chi end; procedure SortDouble (first, last: integer; var DynDataRA:DoubleP0; var lGroupRA: Bytep0); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} {less memory intensive than recursive quicksort} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n, nn, m, lognb2, l, k, j, i: INTEGER; swap: Single; swapbyte: byte; begin n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 0 to k do begin i := j; 555: {<- LABEL} l := i + m; if (DynDataRA^[l] < DynDataRA^[i]) then begin swap := DynDataRA^[i]; DynDataRA^[i] := DynDataRA^[l]; DynDataRA^[l] := swap; swapbyte := lGroupRA^[i]; lGroupRA^[i] := lGroupRA^[l]; lGroupRA^[l] := swapbyte; i := i - m; if (i >= 0) then goto 555; end end end end;//sort procedure RankArray (first, last: integer; var DynDataRA:DoubleP0; var lGSum: double); var lnTies,lPos,lStartPos,lRankPos: integer; lScore,lTie : double; begin lGSum := 0; lPos := first; while lPos <= last do begin lStartPos := lPos; lScore := DynDataRA^[lPos]; while (lPos < last) and (lScore = DynDataRA^[lPos+1]) do inc(lPos); //count ties lnTies := lPos - lStartPos; lTie := (lnTies) *0.5; if lnTies > 0 then begin lnTies := lnTies+1;//tj on page 135 of Siegel lGSum := lGSum + (( (lnTies*lnTies*lnTies) - lnTies)/12); //showmessage(inttostr(lnTies)+' '+realtostr(lGSum,4)); end; for lRankPos := lStartPos to lPos do DynDataRA^[lRankPos] := lStartPos+1+lTie; inc(lPos);//start with next value end; end; function k_out_n (k,n: integer): double; //total possible permutations //k= smaller group, n=sum of both groups var lVal: double; begin if not gFactRAready then InitFact; if (k < 1) or (n <0) then begin result := 20000001; ShowMsg('error k_out_n: k and n must be positive '+inttostr(n)+':'+inttostr(k)) end else if (n > kMaxFact) or (k > kMaxFact) then result := 20000001 else begin lVal := gFactRA[n] / (gFactRA[k]*gFactRA[n-k] ); if lVal > 20000001 then result := 20000001 else result := round(lVal); //result := round(gFactRA[n] / (gFactRA[k]*gFactRA[n-k] ) ); end; // k out n = n!/(k!*(n-k)! which is equal to the PROD(i=k; 1){(n-i+1)/i} end; //k_out_n //http://www.fon.hum.uva.nl/rob/ //# samples for which the sum of the ranks in the smaller sample is smaller than or //# equal to a given upper bound W. //# $W = the bound, $Sum = the sum of ranks upto now, $m-1 = one less than the //# number of elements in the smaller sample that still have to be done, //# $Start = the current position in the ranks list, *RankList = the array //# with all the ranks (this is NOT just the numbers from 1 - N because of ties). //# The list with ranks MUST be sorted in INCREASING order. function CountSmallerRanks(var W,Sum: double; lm, Start,N: integer; var RankList: DoubleP0): integer; var Temp: double; i, mminus1: integer; begin Temp:= 0; result := 0; if(Sum > W) then exit; //Check all subsets of the remaining of RankList mminus1 := lm-1; if(mminus1 > 0) then begin for i := Start to (N-mminus1) do begin Temp := Sum + RankList^[i]; if(Temp > W) then exit;// No smaller values expected anymore result := result +CountSmallerRanks(W,Temp, mminus1, i+1, N, RankList); end; end else begin //If even adding the highest rank doesn't reach $W, //return the remaining number of items if( (Sum + N + 1) <= W) then begin result := N - Start + 1; exit; end; for i := Start to N do begin Temp := Sum + RankList^[i]; if(Temp <= W) then inc(result) else // No smaller values expected anymore exit; end; //for end; //m = 0 end; procedure SortD (first, last: integer; var DynDataRA:DoubleP0); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} {less memory intensive than recursive quicksort} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n, nn, m, lognb2, l, k, j, i: INTEGER; swap: Single; begin n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 1 to k do begin i := j; 555: {<- LABEL} l := i + m; if (DynDataRA^[l] < DynDataRA^[i]) then begin swap := DynDataRA^[i]; DynDataRA^[i] := DynDataRA^[l]; DynDataRA^[l] := swap; i := i - m; if (i >= 0) then goto 555; end end end end;//sort function Median (var lObs: DoubleP0; lnSubj: integer): double; begin SortD(0,lnSubj-1,lObs); if odd(lnSubj) then result := lObs^[lnSubj div 2] else result := 0.5* (lObs^[(lnSubj div 2)-1]+lObs^[lnSubj div 2]); end; (* getmem(lGroupRA,lnSubj*sizeof(Byte)); createArray64(lObspX,lObsX,lnSubj); ln0 := 0; ln1 := 0; for i := 0 to (lnSubj-1) do begin //for each subject //lVal := lIn[i]; lObs[i] := lIn[i]; if i < lnGroup0 then //group0 lGroupRA[i] := 0 else lGroupRA[i] := 1; end; //for each sub for i := 0 to (lnSubj-1) do if lGroupRA[i] = 0 then inc(ln0) //number of observations in group zero else inc(ln1); //number of observations in group one if (ln0 > 1) and (ln1 > 1) then begin SortDouble(0,lnSubj-1,lObs,lGroupRA); *) procedure MeanMedian(lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lMeanFX,lMedianFX: double); //compute mean and median effect size var i: integer; lMeanY,lMeanX,lMedianY,lMedianX: double; lObsp: pointer; lObs: Doublep0; begin lMeanFX := 0; lMedianFX := 0; if (lnSubj=lnGroupX) or (lnSubj < 2) or (lnGroupX = 0) then exit; //at least one empty group - no effect size //next compute mean/median for groupX lMeanX := 0; createArray64(lObsp,lObs,lnSubj); for i := 0 to (lnGroupX-1) do begin //for each subject lMeanX := lMeanX + lIn^[i]; lObs[i] := lIn[i]; end; lMeanX := lMeanX/lnGroupX; lMedianX := Median (lObs,lnGroupX); freemem(lObsp); //next compute mean/median for groupY lMeanY := 0; createArray64(lObsp,lObs,(lnSubj-lnGroupX)); for i := lnGroupX to (lnSubj-1) do begin //for each subject lMeanY := lMeany + lIn^[i]; lObs^[i-lnGroupX] := lIn^[i]; end; lMeanY := lMeanY/ (lnSubj-lnGroupX); lMedianY := Median (lObs,(lnSubj-lnGroupX)); freemem(lObsp); //finally, compute effect sizes lMeanFX := lMeanX-lMeanY; lMedianFX := lMedianX-lMedianY; end; procedure PairedTStat (lnSubj: integer; var lIn: DoubleP0; var lOutT: double); //lIn has data for controls 1...n followed by 1..n paired measures. //e.g. if three observations, 1x,2x,3x,1c,2c,3c var i,lnObs: integer; lSqrSumDif,lSumDif,lSumDifSqr,lDF,lDif,lmeanDif,lVar: double; begin lOutT := 0; if (odd(lnSubj)) or (lnSubj < 4) then exit; //must have even number lnObs := lnSubj shr 1; lSumDif := 0; lSumDifSqr := 0; for i := 0 to (lnObs-1) do begin //for each subject lDif := lIn^[i]-(lIn^[lnObs+i]) ; lSumDif := lSumDif + lDif; lSumDifSqr := lSumDifSqr + sqr(lDif); end; lDF := lnObs - 1; if (lSumDifSqr <> 0)and (lSumDif <> 0){and (lDF <> 0) and (lnObs <> 0)} then begin lmeanDif := lSumDif / lnObs; lSqrSumDif := sqr(lSumDif); lVar := lSumDifSqr - (lSqrSumDif / lnObs); lVar := lVar / (lnObs * lDF); lVar := sqrt(lVar); if lVar <> 0 then lOutT := lmeanDif / lVar; end; end; (*procedure ReportError (lnSubj, lnGroupX: integer; var lIn: DoubleP0; lS: double); var myFile : TextFile; text : string; i: integer; begin AssignFile(myFile, 'c:\Test666.txt'); ReWrite(myFile); WriteLn(myFile,'Subj = '+INTTOSTR(lnSubj)); WriteLn(myFile,'Group1 = '+INTTOSTR(lnGroupX)); WriteLn(myFile,'Var = '+FLOATTOSTR(lS)); for i := 0 to (lnSubj-1) do WriteLn(myFile,floattostr(lIn^[i])); CloseFile(myFile); end;*) procedure TStat2 (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutT: double); //pooled variance t-test http://www.okstate.edu/ag/agedcm4h/academic/aged5980a/5980/newpage26.htm const tiny = 1.0e-5; var i,lnGroupY: integer; lSumX,lSumY,lSumSqrx,lSumSqry,lVarx,lVary,lS: double; begin lnGroupY := lnSubj - lnGroupX; lOutT := 0; if (lnGroupX < 1) or (lnGroupY < 1) or (lnSubj < 3) then //need at least 1 subj in each group exit; lSumx := 0; lSumSqrX := 0; for i := 0 to (lnGroupX-1) do begin //for each subject //lVal := lIn[i]; lsumx := lsumx + lIn^[i]; lSumSqrX := lSumSqrX + sqr(lIn^[i]); end; lVarx := (lnGroupX*lSumSqrX) - Sqr(lsumx); if lnGroupX > 1 then lVarX := lVarX / (lnGroupX*(lnGroupX-1)) else lVarx := 0; lSumy := 0; lSumSqry := 0; for i := lnGroupX to (lnSubj-1) do begin //for each subject lsumy := lsumy + lIn^[i]; lSumSqry := lSumSqry + sqr(lIn^[i]); end; //for each sub //lMnY := lsumy/lnGroupY; lVary := (lnGroupY*lSumSqrY) - Sqr(lsumy); if lnGroupY > 1 then lVary := lVary / (lnGroupY*(lnGroupY-1)) else lVary := 0; //lm := (lsumx/lnGroupX)-(lsumy/lnGroupY); //mean effect size lmnx - lmny; //ldf := lnSubj - 2; ls := ( ((lnGroupX - 1) * lvarx + (lnGroupY - 1) * lvary) / (lnSubj - 2){ldf}) ; if abs(ls) < tiny then exit; if ls < 0 then ShowMsg('Error: t-test variance should not be zero.'); //deepshit (lnSubj, lnGroupX, lIn,lS); //if ls <= 0 then // exit; xxx ls := sqrt( ls) ; ls := ls * sqrt(1 / lnGroupX + 1 / lnGroupY); //note - to get here both lnx and lny > 0 if ls = 0 then lOutT := 0 else lOutT := ( ((lsumx/lnGroupX)-(lsumy/lnGroupY))/ls);//t = lm / ls; end; (*procedure TStatAbs (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutT: double); var i,lnGroupY: integer; lSumX,lSumY,lSumSqrx,lSumSqry,lVarx,lVary,lS: double; begin lnGroupY := lnSubj - lnGroupX; if (lnGroupX < 1) or (lnGroupY < 1) then begin //need at least 1 subj in each group lOutT := 0; exit; end; lSumx := 0; lSumSqrX := 0; for i := 0 to (lnGroupX-1) do begin //for each subject lsumx := lsumx + lIn[i]; lSumSqrX := lSumSqrX + sqr(lIn[i]); end; lVarx := (lnGroupX*lSumSqrX) - Sqr(lsumx); if lnGroupX > 1 then lVarX := lVarX / (lnGroupX*(lnGroupX-1)) else lVarx := 0; lSumy := 0; lSumSqry := 0; for i := lnGroupX to (lnSubj-1) do begin //for each subject //lVal := lIn[i]; lsumy := lsumy + lIn[i]; lSumSqry := lSumSqry + sqr(lIn[i]); end; //for each sub lVary := (lnGroupY*lSumSqrY) - Sqr(lsumy); if lnGroupY > 1 then lVary := lVary / (lnGroupY*(lnGroupY-1)) else lVary := 0; ls := sqrt( ( ((lnGroupX - 1) * lvarx + (lnGroupY - 1) * lvary) / (lnSubj - 2)) ) ; ls := ls * sqrt(1 / lnGroupX + 1 / lnGroupY); //note - to get here both lnx and lny > 0 if ls = 0 then lOutT := 0 else lOutT := ( ((lsumx/lnGroupX)-(lsumy/lnGroupY))/ls);//t = lm / ls; //next - create direction map if (abs(lOutT) >= 1.96) then begin if abs (lsumx/lnGroupX) > abs(lsumy/lnGroupY) then lOutT := 4 else lOutT := -4 end else lOutT := 0; end;*) procedure TStat2Z (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutT: double); var i,lnGroupY: integer; lSumX,lSumY,lSumSqrx,lSumSqry,lVarx,lVary,lS: double; begin lnGroupY := lnSubj - lnGroupX; if (lnGroupX < 1) or (lnGroupY < 1) then begin //need at least 1 subj in each group lOutT := 0; exit; end; lSumx := 0; lSumSqrX := 0; for i := 0 to (lnGroupX-1) do begin //for each subject //lVal := lIn[i]; lsumx := lsumx + lIn^[i]; lSumSqrX := lSumSqrX + sqr(lIn^[i]); end; lVarx := (lnGroupX*lSumSqrX) - Sqr(lsumx); if lnGroupX > 1 then lVarX := lVarX / (lnGroupX*(lnGroupX-1)) else lVarx := 0; lSumy := 0; lSumSqry := 0; for i := lnGroupX to (lnSubj-1) do begin //for each subject //lVal := lIn[i]; lsumy := lsumy + lIn^[i]; lSumSqry := lSumSqry + sqr(lIn^[i]); end; //for each sub //lMnY := lsumy/lnGroupY; lVary := (lnGroupY*lSumSqrY) - Sqr(lsumy); if lnGroupY > 1 then lVary := lVary / (lnGroupY*(lnGroupY-1)) else lVary := 0; //lm := (lsumx/lnGroupX)-(lsumy/lnGroupY); //mean effect size lmnx - lmny; //ldf := lnSubj - 2; ls := sqrt( ( ((lnGroupX - 1) * lvarx + (lnGroupY - 1) * lvary) / (lnSubj - 2){ldf}) ) ; ls := ls * sqrt(1 / lnGroupX + 1 / lnGroupY); //note - to get here both lnx and lny > 0 if ls = 0 then lOutT := 0 else begin lOutT := ( ((lsumx/lnGroupX)-(lsumy/lnGroupY))/ls);//t = lm / ls; lOutT := TtoZ (lOutT,lnSubj-2); //fx((lsumx/lnGroupX),(lsumy/lnGroupY)); end; end; procedure TStatWelch (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var lOutT: double); //see R. D. DeVeaux 'The t -test: Some details' for details //uses Welch's Test to protect against unequal variances //uses true [often fractional] Degrees of Freedom label 129; var i,lNx,lNy: integer; lVal,lSumX,lSumY,lSumSqrx,lSumSqry,lVarx,lVary,lMnX,lMnY,lM,lDF,lDenom,lZ,lT: double; begin lZ := 0; lNx := 0; lSumx := 0; lSumSqrX := 0; lNy := 0; lSumy := 0; lSumSqry := 0; for i := 0 to (lnSubj-1) do begin //for each subject lVal := lIn^[i]; if i < lnGroup0 then begin //group0 inc(lNx); lsumx := lsumx + lVal; lSumSqrX := lSumSqrX + sqr(lVal); end else begin //else group1 inc(lNy); lsumy := lsumy + lVal; lSumSqry := lSumSqry + sqr(lVal); end;//group1 end; //for each sub if (lNy < 2) or (lNx < 2) then goto 129; //unable to calculate lVarX := (lNx*lSumSqrX) - Sqr(lSumX); lVarX := lVarX / (lNx*(lNx-1)); lMnX := lSumX/lNx; lVary := (lNy*lSumSqrY) - Sqr(lsumy); lVary := lVary / (lNy*(lNy-1)); lMnY := lSumY/lNy; lm := lMnX - lMnY; //difference between means = t-Numerator if (lm = 0) {or (lVarY=0) or (lVarX = 0)} then goto 129; //no difference in proportions - do not waste time computing DF //next compute true Degrees of Freedom lDF := sqr( (lVarX/lNx)+(lVarY/lNy)); //lDF := lDF /( ((Sqr(lVarX/lNx)) / (lnx-1) ) + ((Sqr(lVarY/lNy)) / (lny-1) ) ); if (lVarX=0) or (lVarY=0) then begin //forced to estimate based on pooled variance lDF := lnx+lny -2; lDenom:= ( ((lnx - 1) * lvarx + (lny - 1) * lvary) / (lNx+lNy-2)); lDenom := sqrt(lDenom / lnx + lDenom / lny); end else begin lDF := lDF /( ((Sqr(lVarX/lNx)) / (lnx-1) ) + ((Sqr(lVarY/lNy)) / (lny-1) ) ); lDenom := sqrt(lVarX/lNx + lVary/lNy);//assume Unequal variances "Welch's Test" end; if lDenom = 0 then goto 129; lT := ( lm/lDenom);//t = m / d; lZ := TtoZ(lT,lDF); //az //lP := pNormal(TtoZ(lT,lDF)); 129: lOutT := lZ; //vlsm compatible = lOutT[lColX] := ( lm/lD);//t = m / d; end; FUNCTION specialdouble (d:double): boolean; //returns true if s is Infinity, NAN or Indeterminate //8byte IEEE: msb[63] = signbit, bits[52-62] exponent, bits[0..51] mantissa //exponent of all 1s = Infinity, NAN or Indeterminate CONST kSpecialExponent = 2047 shl 20; VAR Overlay: ARRAY[1..2] OF LongInt ABSOLUTE d; BEGIN IF ((Overlay[2] AND kSpecialExponent) = kSpecialExponent) THEN RESULT := true ELSE RESULT := false; END; procedure LocalRank (first, last: integer; var DynDataRA,DynDataRAX:DoubleP0; var lGroupRA: Bytep0); var lGroup,lnTies,lPos,lStartPos,lRankPos,lLocalRank: integer; lScore,lTie : double; begin for lGroup := 0 to 1 do begin lPos := first; lLocalRank := 0; while lPos <= last do begin if lGroupRA^[lPos] = lGroup then begin// inc(lLocalRank); lStartPos := lPos; lScore := DynDataRA^[lPos]; lnTies := 0; while (lPos < last) and (0.001 > abs (lScore - DynDataRA^[lPos+1]) ) do begin inc(lPos); //count ties if lGroupRA^[lPos] = lGroup then inc(lnTies); end; lTie := (lnTies) *0.5; for lRankPos := lStartPos to lPos do begin if lGroupRA^[lRankPos] = lGroup then DynDataRAX^[lRankPos] := (lLocalRank+lTie); end; lLocalRank := lLocalRank + lnTies; end; //if in group inc(lPos);//start with next value end; //while... for each observation end; //for each group end; procedure BMTest (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var lOutT: double); //procedure BMtest (lnRow,lnCol: integer; var lIn,lOutT: DoubleP0); var lObspX,lObsp: pointer; lObsX,lObs: Doublep0; lGroupRA: Bytep0; i,ln0,ln1,lColX: integer; lDF,lZ,lGSum: double; lSum0,lSum1,lMean0,lMean1,lSqr0,lSqr1,lk0,lk1: double; begin createArray64(lObsp,lObs,lnSubj); getmem(lGroupRA,lnSubj*sizeof(Byte)); createArray64(lObspX,lObsX,lnSubj); ln0 := 0; ln1 := 0; for i := 0 to (lnSubj-1) do begin //for each subject //lVal := lIn[i]; lObs^[i] := lIn^[i]; if i < lnGroup0 then //group0 lGroupRA^[i] := 0 else lGroupRA^[i] := 1; end; //for each sub for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then inc(ln0) //number of observations in group zero else inc(ln1); //number of observations in group one if (ln0 > 1) and (ln1 > 1) then begin SortDouble(0,lnSubj-1,lObs,lGroupRA); RankArray(0,lnSubj-1,lObs,lGSum); lSum0 := 0; lSum1 := 0; for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then lSum0 := lSum0 + lObs^[i] else lSum1 := lSum1 + lObs^[i]; lMean0 := lSum0 / ln0; lMean1 := lSum1 / ln1; //fx(lmean0,lMean1); lSqr0 := 0; lSqr1 := 1; lk0 := (ln0+1)/2; lk1 := (ln1+1)/2; LocalRank(0,lnSubj-1,lObs,lObsX,lGroupRA); for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then lSqr0 := lSqr0 + Sqr(lObs^[i]-lObsX^[i]-lMean0+lk0) else lSqr1 := lSqr1 + Sqr(lObs^[i]-lObsX^[i]-lMean1+lk1); lSqr0 := (1/(ln0-1))*lSqr0; lSqr1 := (1/(ln1-1))*lSqr1; lZ := -(ln0*ln1*(lMean1-lMean0))/((ln0+ln1)*sqrt((ln0*lSqr0)+(ln1*lSqr1) ) ); lDF := sqr(ln0*lSqr0+ln1*lSqr1) / ( (sqr(ln0*lSqr0)/(ln0-1)) + (sqr(ln1*lSqr1)/(ln1-1)) ) ; lZ := TtoZ(lZ,lDF); //az lOutT := lZ; //fx(lZ,lDF); end else //>1 lOutT := 0; freemem(lObsp); freemem(lObspX); freemem(lGroupRA); end; //bmtest procedure WilcoxonMW2 (lnSubj, lnGroup0: integer; var lIn: DoubleP0; var lOutT: double); var lObsp: pointer; lObs: Doublep0; lGroupRA: Bytep0; m,n,i,ln0,ln1,mplusn: integer; lPermutations,lVal,lWsmalln,lZ,lZi,lTail,lGSum,lWTotal,lH0,lSum: double; begin createArray64(lObsp,lObs,lnSubj); getmem(lGroupRA,lnSubj*sizeof(Byte)); ln0 := 0; ln1 := 0; for i := 0 to (lnSubj-1) do begin //for each subject //lVal := lIn[i]; lObs[i] := lIn[i]; if i < lnGroup0 then //group0 lGroupRA^[i] := 0 else lGroupRA^[i] := 1; end; //for each sub for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then inc(ln0) //number of observations in group zero else inc(ln1); //number of observations in group one SortDouble(0,lnSubj-1,lObs,lGroupRA); RankArray(0,lnSubj-1,lObs,lGSum); lWsmalln := 0; if ln1 < ln0 then begin //Group1 smaller than Group0 m := ln1; n := ln0; for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 1 then lWsmalln := lWsmalln + lObs^[i]; end else begin//Group0 smaller than Group1 m := ln0; n := ln1; for i := 0 to (lnSubj-1) do if lGroupRA^[i] = 0 then lWsmalln := lWsmalln + lObs^[i]; end; mplusn := m + n; lZ := 0; if lWsmalln > (mplusn*(mplusn+1)/4) then lTail := -0.5 else lTail := 0.5; if m < 1 then lZ := 0 else if lGSum = 0 then begin //no ties lZ := ( lWsmalln + lTail - m * ( m + n + 1 ) / 2 ) / sqrt( m * n * ( m + n + 1 ) / 12 ); end else begin //correct for ties, see Siegel page 135 if ((12-lGSum)<>0) and (((lnSubj*(lnSubj-1)) * (((lnSubj*lnSubj*lnSubj) -lnSubj) /12-lGSum))<> 0) then begin lZ := lWsmalln + lTail - (m * ( lnSubj + 1 ) / 2 ); lZ := lZ/sqrt ( (m*n)/ (lnSubj*(lnSubj-1)) * (((lnSubj*lnSubj*lnSubj) -lnSubj) /12-lGSum)); end else begin lZ := ( lWsmalln + lTail - m * ( m + n + 1 ) / 2 ) / sqrt( m * n * ( m + n + 1 ) / 12 ); end; end; {if lStr = '' then begin for i := 0 to (lnSubj-1) do lStr := lStr+inttostr(lGroupRA[i])+', '+floattostr( lObs[i])+';'; lStr := ('w'+floattostr(lWsmalln)+'Z'+floattostr(lZ)+'ties'+floattostr(lgSum)+'m'+inttostr(m)+'n'+inttostr(n)+':'+lStr); end; } if m < 10 then lPermutations := k_out_n(m,mplusn); if (m < 10) and (lPermutations < 20000000) and (abs(lZ) > 1) {}then begin lWTotal :=mplusn*(mplusn+1)/2; //sum ranks for both groups m and n lH0 := lWTotal * (m/mplusn); //null hypothesis lSum := 0; //next - use smallest value of W if lWSmallN > lH0 then begin lWSmallN := lH0 - (lWSmallN-lH0); //Due to ties, we need to flip the order as well, as we are searching smaller for i := 0 to (lnSubj-1) do lObs^[i] := (lnSubj+1)-lObs^[i]; for i := 0 to ((lnSubj-2) div 2) do begin //swap lVal := lObs^[i]; lObs^[i] := lObs^[lnSubj-1-i]; lObs^[lnSubj-1-i] := lVal; end; end; lVal := CountSmallerRanks(lWSmallN, lSum, m, 0,(mplusn-1), lObs); lZi := lZ; lZ :=pNormalInvQuickApprox(lVal/lPermutations); if ((lZ > 0) and (lZi < -1)) or ((lZ < 0) and (lZi > 1)) then lZ := -lZ; end; if ln1 < ln0 then //we computed unexpected tail lOutT := -lZ else lOutT := lZ;//t = m / d; freemem(lObsp); freemem(lGroupRA); end; end. ����mricron-0.20140804.1~dfsg.1.orig/npm/hdr.pas��������������������������������������������������������0000755�0001750�0001750�00000050546�12306422710�016266� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit hdr; interface {$H+} {$Include ..\common\isgui.inc} uses nifti_hdr,define_types,classes, unpm, nifti_types; procedure MakeStatHdr (var lBGHdr,lStatHdr: TniftiHdr; lMinIntensity,lMaxIntensity,lIntent_p1,lIntent_p2,lIntent_p3: single; lIntent_code: smallint;lIntentName: string); procedure MakeHdr (var lBGHdr,lStatHdr: TniftiHdr); function NIFTIhdr_SaveHdrImg (var lFilename: string; var lHdr: TNIFTIHdr; lAllowOverwrite,lSPM2,lSingleFile: boolean;var lImg: SingleP; lnVol: integer): boolean; function NIFTIhdr_SaveHdrImg8 (var lFilename: string; var lHdr: TNIFTIHdr; lAllowOverwrite,lSPM2,lSingleFile: boolean;var lImg: ByteP; lnVol: integer): boolean; function Files4D (lFilename: string): boolean; function Vol4D (lFilename: string): integer; function FileExists4D (lFilename: string): boolean; function Filename4D(lFilename: string): string; function FilenameVol4D (lFilename: string; var lBaseName: string; var lVol: integer): boolean; function NIFTIhdr_HdrVolumes (lFilenameIn: string): integer; function BPP (lDataType: integer): integer; function CreateDecompressed4D(var lImageNames: TStrings): string; function CheckVoxels(var lHdrNameIn : string; lMaskVoxels, lImageNumber: integer):boolean; //function CheckVoxelsGroupX(var lG: TStrings; lMaskVoxels: integer):boolean; function CheckVoxelsGroupX(var lG: TStrings; lMaskHdr: TMRIcroHdr): boolean; //function CheckVoxelsGroupY(var lG: TStrings):boolean; procedure DeleteDecompressed4D(lDecomName: string); implementation uses {$IFDEF FPC} gzio2,Controls, {$ELSE} {gzio,ZLib,}DiskSpaceKludge,gziod,{$ENDIF} {$IFNDEF UNIX}Windows, {$ENDIF} {$IFDEF GUI}Dialogs,{$ENDIF} Dialogsx ,SysUtils,StatThdsUtil; //define_types,GraphicsMathLibrary; {$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF} procedure DeleteDecompressed4D(lDecomName: string); begin if lDecomName = '' then exit; if not fileexists(lDecomName) then exit; sysutils.deletefile(lDecomName); end; function CheckVoxels(var lHdrNameIn : string; lMaskVoxels, lImageNumber: integer):boolean; var lHdr: TMRIcroHdr; lHdrName: string; lVox: integer; begin result := false; lHdrName := Filename4D(lHdrNameIn); if not NIFTIhdr_LoadHdr(lHdrName,lHdr) then begin NPMmsg('Unable to load image '+lHdrName); exit; end; lVox := ComputeImageDataBytes8bpp(lHdr); if lVox <> lMaskVoxels then begin NPMmsg('Voxels differ for '+lHdrName+' expected '+inttostr(lMaskVoxels)+' described '+inttostr(lVox)); exit; end; if UpCaseExt(lHdrName) = '.HDR' then lHdrName := changefileext(lHdrName,'.img'); if (not GzExt(lHdrName) ) and (FSize(lHdrName) < lMaskVoxels) then begin ShowMsg('The uncompressed image data should be at least '+inttostr(lMaskVoxels)+' bytes. '+lHdrName); exit; end; result := true; if (lImageNumber < 0) or (lImageNumber > kMaxImages) then exit; gDataTypeRA[lImageNumber] := lHdr.NIFTIhdr.datatype; gOffsetRA[lImageNumber] := lHdr.NIFTIhdr.vox_offset; gScaleRA[lImageNumber] := lHdr.NIFTIhdr.scl_slope; gInterceptRA[lImageNumber] := lHdr.NIFTIhdr.scl_inter; end; (*function CheckVoxelsGroup(var lG: TStrings; lMaskVoxels: integer):boolean; var lC: integer; lHdrName : string; begin result := false; if lG.count < 1 then exit; for lC := 1 to lG.count do begin lHdrName:= lG[lC-1]; result := CheckVoxels(lHdrName, lMaskVoxels,lC); end; end;*) (*function CheckVoxelsGroup(var lG: TStrings; lMaskVoxels: integer):boolean; var lC: integer; lHdrName : string; begin result := false; if lG.count < 1 then exit; for lC := 1 to lG.count do begin lHdrName:= lG[lC-1]; if not CheckVoxels(lHdrName, lMaskVoxels,lC) then begin if not fileexists (lHdrName) then MainForm.NPMmsg('File not found "'+lHdrName+'"') else MainForm.NPMmsg('Problem with "'+lHdrName+'" expected '+inttostr(lMaskVoxels)); exit; end; end; result := true; end;*) function SameTransform (A,B:TNIFTIhdr): boolean; var lDim: integer; begin result := false; for lDim := 0 to 3 do begin if A.srow_x[lDim] <> B.srow_x[lDim] then exit; if A.srow_y[lDim] <> B.srow_y[lDim] then exit; if A.srow_z[lDim] <> B.srow_z[lDim] then exit; end; result := true; end; function TransformTxt (A:TNIFTIhdr): string; var lDim: integer; begin result := '['; for lDim := 0 to 3 do result := result + ' '+floattostr(A.srow_x[lDim]); result := result + ';'; for lDim := 0 to 3 do result := result + ' '+floattostr(A.srow_y[lDim]); result := result + ';'; for lDim := 0 to 3 do result := result + ' '+floattostr(A.srow_z[lDim]); result := result + ']'; end; function CheckVoxelsX(var lHdrNameIn : string; lMaskHdr: TMRIcroHdr; lImageNumber: integer):boolean; var lHdr: TMRIcroHdr; lHdrName: string; lDim: integer; begin result := false; lHdrName := Filename4D(lHdrNameIn); if not NIFTIhdr_LoadHdr(lHdrName,lHdr) then begin NPMmsg('Unable to load image '+lHdrName+' Possible solution: make sure VAL file and images are in the same folder'); exit; end; (*lVox := ComputeImageDataBytes8bpp(lHdr); lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if lVox <> lMaskVoxels then begin NPMmsg('Voxels differ for '+lHdrName+' expected '+inttostr(lMaskVoxels)+' described '+inttostr(lVox)); exit; end; *) for lDim := 1 to 3 do begin if (lHdr.NIFTIhdr.dim[lDim] <> lMaskHdr.NIFTIhdr.dim[lDim]) then begin NPMmsg('Dimension '+inttostr(lDim)+' of '+lHdrName+' does not match '+lMaskHdr.HdrFileName); exit; end; end; if (not lHdr.NIfTItransform) then NPMmsg('Warning: no spatial transform for '+lHdrName+' (Analyze not NIfTI). Please ensure images are coregistered.') else if (not lMaskHdr.NIfTItransform) then NPMmsg('Warning: no spatial transform for '+lMaskHdr.HdrFileName+' (Analyze not NIfTI). Please ensure images are coregistered.') else begin if not SameTransform (lHdr.NIFTIhdr, lMaskHdr.NIFTIhdr) then begin NPMmsg('Warning: spatial transforms differ for '+lHdrName+' and '+lMaskHdr.HdrFileName); NPMmsg(TransformTxt(lHdr.NIFTIhdr)+' <> '+ TransformTxt(lMaskHdr.NIFTIhdr)); end; end; (*if (lHdr.NIFTIhdr.bitpix <> 8) and (lHdr.NIFTIhdr.datatype <> kDT_FLOAT) and (lHdr.NIFTIhdr.datatype <> kDT_SIGNED_INT) then begin showmessage('Error: This software can only read uncompressed images that are either 8-bit integer or 32-bit real precision.'); exit; end; //beta *) if UpCaseExt(lHdrName) = '.HDR' then lHdrName := changefileext(lHdrName,'.img'); if (not GzExt(lHdrName) ) and (FSize(lHdrName) < (lHdr.NIFTIhdr.dim[1]*lHdr.NIFTIhdr.dim[2]*lHdr.NIFTIhdr.dim[3])) then begin ShowMsg('The file size appears too small '+lHdrName); exit; end; result := true; //gBitPixRA[lImageNumber] := lHdr.NIFTIhdr.bitpix; gDataTypeRA[lImageNumber] := lHdr.NIFTIhdr.datatype; gOffsetRA[lImageNumber] := lHdr.NIFTIhdr.vox_offset; gScaleRA[lImageNumber] := lHdr.NIFTIhdr.scl_slope; gInterceptRA[lImageNumber] := lHdr.NIFTIhdr.scl_inter; end; function CheckVoxelsGroupX(var lG: TStrings; lMaskHdr: TMRIcroHdr):boolean; var lC: integer; lHdrName : string; begin result := false; if lG.count < 1 then exit; for lC := 1 to lG.count do begin lHdrName:= lG[lC-1]; if not CheckVoxelsX(lHdrName, lMaskHdr,lC) then begin if not fileexists (lHdrName) then NPMmsg('File not found "'+lHdrName+'". Possible solution: make sure VAL file and images are in the same folder') else NPMmsg('Problem with "'+lHdrName); exit; end; end; result := true; end; (*function CheckVoxelsGroupY(var lG: TStrings):boolean; var lMaskHdr: TMRIcroHdr; lS: string; begin result := false; if lG.count < 1 then exit; lS := lG[0]; if not NIFTIhdr_LoadHdr(lS,lMaskHdr) then begin NPMmsg('Unable to load image '+lS); exit; end; result := CheckVoxelsGroupX(lG,lMaskHdr); end; *) function BPP (lDataType: integer): integer; begin result := 0; case lDataType of kDT_UNSIGNED_CHAR: result := 1; kDT_SIGNED_SHORT: result := 2; // signed short (16 bits/voxel) kDT_SIGNED_INT : result := 4; // signed int (32 bits/voxel) kDT_FLOAT : result := 4; // float (32 bits/voxel) kDT_COMPLEX : result := 8; // complex (64 bits/voxel) end; end; function NIFTIhdr_HdrVolumes (lFilenameIn: string): integer; var lFilename: string; lHdr: TMRIcroHdr; begin result := 0; lFilename := lFilenameIn; if not NIFTIhdr_LoadHdr (lFilename, lHdr)then exit; result := lHdr.niftiHdr.dim[4]; end; function FileExists4D (lFilename: string): boolean; var lBaseName: string; var lVol: integer; begin FilenameVol4D (lFilename, lBasename,lVol); result := fileexists(lBasename); end; function FilenameVol4D (lFilename: string; var lBaseName: string; var lVol: integer): boolean; //4D files end with the image index number c:\dir\filename:1 //returns true if 4D file (with lVol = volume), otherwise returns false with lvol = 1 var lLen,lP: integer; lNumStr: string; begin lVol := 1; lBasename := lFilename; result := false; lLen := length(lFilename); if lLen < 1 then exit; lP := lLen; lNumStr := ''; while (lP > 0) and (lFilename[lP] in ['0'..'9']) do begin lNumStr := lFilename[lP]+lNumStr; dec(lP); end; //showmessage(lNumStr + '*'+lFilename[lP]); if (lNumStr = '') or (lP < 2) or (lFilename[lP] <> ':') then exit; lVol := strtoint(lNumStr); lLen := lP -1; lBasename := ''; for lP := 1 to lLen do lBasename := lBasename + lFilename[lP]; result := true; end; function Filename4D(lFilename: string): string; var lVol: integer; begin FilenameVol4D (lFilename, result,lVol); end; function Vol4D (lFilename: string): integer; var lBaseName: string; begin FilenameVol4D (lFilename, lBasename,result); end; function Files4D (lFilename: string): boolean; var lBaseName: string; var lVol: integer; begin result := FilenameVol4D (lFilename, lBasename,lVol); end; function CreateDecompressed4D(var lImageNames: TStrings): string; //returns temp filename if all imagenames are a single compressed 4D datafile //this means that a nii.gz file is only decompressed once, instead of once per volume*plank var lP: integer; lFilename : string; begin result := ''; if lImageNames.Count < 2 then exit; if not Files4D(lImageNames.Strings[0]) then exit; lFilename := Filename4D(lImageNames.Strings[0]); if not Fileexists(lFilename) then exit; if not GzExt(lFilename) then exit; //not a decompressed file //see if single 4D image for lP := 2 to lImageNames.Count do if not Files4D(lImageNames.Strings[lP-1]) then exit; for lP := 2 to lImageNames.Count do if lFilename <> Filename4D(lImageNames.Strings[lP-1]) then exit; //find unique filename for extracted file result := lFilename +'.nii'; while fileexists(result) do //make sure we do not overwrite anything result := lFilename +inttostr(random(9999))+'.nii'; //unzip Gunzip(lFilename,result); //set image names to point to uncompressed volume for lP := 1 to lImageNames.Count do lImageNames.Strings[lP-1] := result +':'+inttostr(Vol4D(lImageNames.Strings[lP-1]) ); end; procedure MakeStatHdr (var lBGHdr,lStatHdr: TniftiHdr; lMinIntensity,lMaxIntensity,lIntent_p1,lIntent_p2,lIntent_p3: single; lIntent_code: smallint;lIntentName: string); var lIntentNameLen,lPos: integer; lStr: string; begin move(lBGHdr,lStatHdr,sizeof(TniftiHdr)); with lStatHdr do begin magic :=kNIFTI_MAGIC_SEPARATE_HDR; bitpix := 32; //32-bit real data datatype := kDT_FLOAT; scl_slope:= 1; scl_inter:= 0; glmin := round(lMinIntensity); glmax := round(lMaxIntensity); intent_code := lIntent_Code;// kNIFTI_INTENT_ESTIMATE; intent_p1 := lIntent_p1; intent_p2 := lIntent_p2; intent_p3 := lIntent_p3; lIntentNameLen := length(lIntentName); descrip[1] := 'N'; descrip[2] := 'P'; descrip[3] := 'M'; if lIntent_code=kNIFTI_INTENT_TTEST then begin descrip[4] := 't' ; lStr := inttostr(trunc(lIntent_p1)); for lPos := 1 to length (lStr) do descrip[4+lPos] := lStr[lPos] ; end else descrip[4] := 'z'; if lIntentNameLen > sizeof(intent_name) then lIntentNameLen := sizeof(intent_name); if lIntentNameLen > 0 then for lPos := 1 to lIntentNameLen do intent_name[lPos] := lIntentName[lPos]; end; end; procedure SaveAsVOIorNIFTIcore (var lFilename: string; var lNiftiHdr: TNIFTIHdr; var lImg: SingleP; lnVolIn,lImgBufferBPP: integer); const kImgOffset = 352; //header is 348 bytes, but 352 is divisible by 8... var lHdr: TNIFTIhdr; lBuff: ByteP; lF: File; lCompressedFilename,lExt: string; lnVol,lC,lFSize: integer; lImgBuffer: ByteP; lImgBufferItems{, lImgBufferBPP}: integer; begin lnVol := lnVolIn; move(lNiftiHdr,lHdr,sizeof(lHdr)); lImgBufferItems := lHdr.dim[1]*lHdr.dim[2]*lHdr.dim[3]; //lImgBufferBPP:= 4; lImgBuffer := ByteP(lImg); lExt := UpCaseExt(lFileName); if DiskFreeEx(lFilename) < (kImgOffset+(lImgBufferItems*lImgBufferBPP*lnVol)) then begin {$IFDEF GUI} case MsgDlg('Very little space on the selected drive. Attempt to save to this disk?', mtConfirmation,[mbYes, mbCancel], 0) of {$IFDEF FPC}mrCancel: exit; {$ELSE} id_Cancel: exit;{$ENDIF} end; //case {$ELSE} ShowMsg('Very little space on the selected drive. Data may be lost.'); {$ENDIF} end; if FileExistsEX(lFileName) then begin {$IFDEF GUI} if (ParamCount < 1) then begin case MsgDlg('Overwrite the file named '+lFileName+'?', mtConfirmation,[mbYes, mbCancel], 0) of //MessageDlg {$IFDEF FPC}mrCancel: exit; {$ELSE} id_Cancel: exit;{$ENDIF} //requires Uses Controls end; //case end else begin NPMMsg('Warning: overwriting '+lFilename); end; {$ELSE} ShowMsg('Warning: overwriting '+lFilename); {$ENDIF} DeleteFile(lFilename); end; //file exists if (lExt='.VOI') then begin lHdr.intent_name[1] := 'B';//Binary lHdr.scl_slope := 1/kVOI8bit; lHdr.scl_inter := 0; end; if lnVol < 2 then begin lHdr.dim[0] := 3;//3D july2006 lHdr.dim[4] := 1;//3D Aug 2007 lnVol := 1; end else begin lHdr.dim[0] := 4;//3D july2006 lHdr.dim[4] := lnVol;//3D july2006 end; (*if not (lImgBufferItems = (lHdr.dim[1]*lHdr.dim[2]*lHdr.dim[3])) then begin //july2006 lHdr.sform_code := 1; WriteNiftiMatrix ( lHdr, //must match MAGMA in nifti_hdr gBGImg.ScrnMM[1],0,0,(gBGImg.ScrnOri[1]-1)*-gBGImg.ScrnMM[1], 0,gBGImg.ScrnMM[2],0,(gBGImg.ScrnOri[2]-1)*-gBGImg.ScrnMM[2], 0,0,gBGImg.ScrnMM[3],(gBGImg.ScrnOri[3]-1)*-gBGImg.ScrnMM[3]); end;*) if not IsNifTiMagic(lHdr) then begin {lHdr.sform_code := 1; WriteNiftiMatrix ( lHdr, //must match MAGMA in nifti_hdr gBGImg.ScrnMM[1],0,0,(gBGImg.ScrnOri[1]-1)*-gBGImg.ScrnMM[1], 0,gBGImg.ScrnMM[2],0,(gBGImg.ScrnOri[2]-1)*-gBGImg.ScrnMM[2], 0,0,gBGImg.ScrnMM[3],(gBGImg.ScrnOri[3]-1)*-gBGImg.ScrnMM[3]); } end; case lImgBufferBPP of 4: begin lHdr.bitpix := 32; lHdr.datatype := kDT_FLOAT;//note 32-bit integers saved internally as 32-bit float end; 2: begin lHdr.bitpix := 16; lHdr.datatype := kDT_SIGNED_SHORT; end; 1: begin lHdr.bitpix := 8; lHdr.datatype := kDT_UNSIGNED_CHAR; //lHdr.scl_inter := lHdr.WindowScaledMin; //lHdr.scl_slope := (lHdr.WindowScaledMax-lHdr.WindowScaledMin) /255; end; else begin showmsg('Error: Unsupported bytes per voxel: '+inttostr(lImgBufferBPP)); exit; end; end; if (lExt='.IMG') or (lExt ='.HDR') then begin //done previously lHdr.magic := kNIFTI_MAGIC_SEPARATE_HDR; lHdr.vox_offset := 0; Filemode := 1; //next write header data as .hdr lFilename := changeFileExt(lFilename,'.hdr'); AssignFile(lF, lFileName); Rewrite(lF,sizeof(TNIFTIhdr)); BlockWrite(lF,lHdr, 1); CloseFile(lF); //next write image data as .img lFilename := changeFileExt(lFilename,'.img'); AssignFile(lF, lFileName); {WIN} Rewrite(lF,lImgBufferItems*lImgBufferBPP*lnVol); BlockWrite(lF,lImgBuffer^,1); CloseFile(lF); Filemode := 2; exit; end; //separate header lHdr.magic := kNIFTI_MAGIC_EMBEDDED_HDR; lHdr.vox_offset := kImgOffset;//352 bytes lFSize := kImgOffset+(lImgBufferItems*lImgBufferBPP*lnVol); getmem(lBuff,lFSize); move(lHdr,lBuff^,sizeof(lHdr)); //Next: NIfTI 1.1 requires bytes 349..352 set to zero when no XML information lC := kImgOffset; lBuff^[lC-3] := 0; lBuff^[lC-2] := 0; lBuff^[lC-1] := 0; lBuff^[lC] := 0; lC := kImgOffset+1; move(lImgBuffer^[1],lBuff^[lC],lImgBufferItems*lImgBufferBPP*lnVol); if (lExt='.NII') then begin Filemode := 1; AssignFile(lF, lFileName); Rewrite(lF,lFSize); BlockWrite(lF,lBuff^,1); CloseFile(lF); Filemode := 2; exit; end; //uncompressed if (lExt<>'.VOI') then lCompressedFilename := changefileextX(lFilename,'.nii.gz') else lCompressedFilename := lFilename; GZipBuffer(lCompressedFilename,lBuff,lFSize,false); freemem(lBuff); end; procedure MakeHdr (var lBGHdr,lStatHdr: TniftiHdr); //lIntent kNIFTI_INTENT_CHISQ lIntent_p1 = DOF //lIntent kNIFTI_INTENT_ZSCORE no params //lIntent kNIFTI_INTENT_TTEST lIntent_p1 = DOF begin move(lBGHdr,lStatHdr,sizeof(TniftiHdr)); with lStatHdr do begin magic :=kNIFTI_MAGIC_SEPARATE_HDR; bitpix := 32; //32-bit real data datatype := kDT_FLOAT; scl_slope:= 1; scl_inter:= 0; descrip[1] := 'X';//can not be npm end; end; function NIFTIhdr_SaveHdrImg (var lFilename: string; var lHdr: TNIFTIHdr; lAllowOverwrite,lSPM2,lSingleFile: boolean;var lImg: SingleP; lnVol: integer): boolean; var lOutNameMod: string; lSPM2output: boolean; begin lOutNameMod := lFilename; lOutNameMod := changefileextX(lOutNameMod,'.hdr'); lSPM2output := lSPM2; //fx(lHdr.srow_x[3],lHdr.srow_y[3],lHdr.srow_z[3]); (*if not IsNifTiMagic(lHdr) then lSPM2output := true;*) if (lSingleFile) and (not lSPM2output) then begin lHdr.magic := kNIFTI_MAGIC_EMBEDDED_HDR; lOutNameMod := changefileextX(lOutNameMod,'.nii.gz'); //HACK lOutNameMod := changefileextX(lOutNameMod,'.nii'); end else if (not lSPM2output) then lHdr.magic := kNIFTI_MAGIC_SEPARATE_HDR else //the nifti_hdr reader converts the Analyze to NIfTI, so we need to save as NIfTI with NPM lHdr.magic := kNIFTI_MAGIC_SEPARATE_HDR; //lHdr.magic := 1984; SaveAsVOIorNIFTIcore (lOutNameMod, lHdr, lImg,lnVol,4); end; function NIFTIhdr_SaveHdrImg8 (var lFilename: string; var lHdr: TNIFTIHdr; lAllowOverwrite,lSPM2,lSingleFile: boolean;var lImg: ByteP; lnVol: integer): boolean; var lOutNameMod: string; begin lOutNameMod := lFilename; if IsVOIExt (lOutNameMod) then begin lHdr.magic := kNIFTI_MAGIC_EMBEDDED_HDR; end else begin lOutNameMod := changefileextX(lOutNameMod,'.hdr'); if (lSingleFile) and (not lSPM2) then begin lHdr.magic := kNIFTI_MAGIC_EMBEDDED_HDR; lOutNameMod := changefileextX(lOutNameMod,'.nii.gz'); end else if (not lSPM2) then lHdr.magic := kNIFTI_MAGIC_SEPARATE_HDR else lHdr.magic := 1984; end; SaveAsVOIorNIFTIcore (lOutNameMod, lHdr, SingleP(lImg),lnVol,1); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/options.inc����������������������������������������������������0000755�0001750�0001750�00000000336�10673315046�017172� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ -------------------------------------------------------------------- } {$DEFINE SPREADSHEET} {If "DEFINE SPREADSHEET" then the VAL file design for will be created.} {This uses the spread.* and design.* files} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/spread.dfm�����������������������������������������������������0000755�0001750�0001750�00000006425�12147211710�016746� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �TSPREADFORM�0� ��TPF0 TSpreadForm SpreadFormLeft�Top�WidthlHeightCaptionVoxelwise Analysis of LesionsColor clBtnFace Font.CharsetDEFAULT_CHARSET Font.Color clWindowText Font.Height Font.Name MS Sans Serif Font.Style �Menu MainMenu1OldCreateOrder PositionpoScreenCenterOnClose FormCloseOnCreate FormCreateOnResize FormResize PixelsPerInch` TextHeight � TStringGridDataGridLeft�TopWidthdHeightAlignalClientDefaultRowHeightRowCount FixedRowsOptions goFixedVertLine goVertLine goHorzLine goRangeSelectgoDrawFocusSelectedgoTabsgoThumbTracking�TabOrder� OnDrawCellDataGridDrawCell OnKeyPressDataGridKeyPress OnMouseDownDataGridMouseDown OnMouseMoveDataGridMouseMove OnSelectCellDataGridSelectCell ColWidths@@@@@� RowHeights���TToolBarToolBar1Left�Top�WidthdHeight EdgeBorders �TabOrder� TSpeedButton SpeedButton1Left�TopWidthHeightEnabledFlat �� TSpeedButton DesignBtnLeftTopWidth�HeightHintANOVACaptionDesign Glyph.Data z��v��BMv������v���(��� ������������������������������������������������������������������3s3s3s3s3???3sssssss?w�������wwwwwwww333<3333373?7 3<337ws73w393<393?ww|wwwwwwwwww33<3333ss3739<93373773333333?wwww|wwwwwwwwwww333<333337733<��<7337ww7333<33?wwwwwwwwwwwwwww3333333333333333 NumGlyphsParentShowHintShowHint OnClickDesignBtnClick��� TStatusBar StatusBar1Left�TopWidthdHeightPanelsWidth��Width2���� TMainMenu MainMenu1LeftlTop,� TMenuItemFile1Caption&File� TMenuItemNew1CaptionNew...ShortCutN@OnClick NewBtnClick�� TMenuItemOpen1CaptionOpen...ShortCutO@OnClick OpenBtnClick�� TMenuItemSave1CaptionSaveShortCutS@OnClick SaveBtnClick�� TMenuItem Descriptives1Caption DescriptivesOnClickDescriptiveClick�� TMenuItemQuit1Caption Close windowShortCutW@OnClick Quit1Click��� TMenuItemEdit1CaptionEdit� TMenuItemCopy1CaptionCopyShortCutC@OnClick Copy1Click�� TMenuItemPaste1CaptionPasteShortCutV@OnClick Paste1Click�� TMenuItem Selectall1CaptionSelect all cellsShortCutA@OnClickSelectall1Click�� TMenuItemClearallcells1CaptionClear all cells...OnClickClearallcells1Click�� TMenuItemDescriptiveMenuCaption DescriiptiveShortCutD@OnClickDescriptiveClick��� TMenuItemViewCaptionView� TMenuItemFont1CaptionFont� TMenuItemN81TagCaption8Checked GroupIndexo RadioItem OnClickFontSizeChange�� TMenuItemN101Tag Caption10 GroupIndexo RadioItem OnClickFontSizeChange�� TMenuItemN121Tag Caption12 GroupIndexo RadioItem OnClickFontSizeChange�� TMenuItemN141TagCaption14 GroupIndexo RadioItem OnClickFontSizeChange��� TMenuItemDesign1CaptionDesignShortCutD@OnClickDesignBtnClick��� TMenuItemHelp1Caption&HelpVisible� TMenuItemAboutthissoftware1Caption&About this softwareOnClickAboutthissoftware1Click���� TOpenDialog OpenDialog1 DefaultExt*.valFilter?Native [val]|*.val|Tab delimited text [txt]|*.txt|All files|*.*Left$Top,�� TSaveDialog SaveDialog1 DefaultExt.valFilter8Native format [val]|*.val|Tab delimited text [txt]|*.txtOptions ofOverwritePromptofHideReadOnly�LeftJTop,����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/design.lfm�����������������������������������������������������0000755�0001750�0001750�00000005332�11540170650�016750� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object DesignForm: TDesignForm Left = 481 Height = 207 Top = 179 Width = 636 HorzScrollBar.Page = 635 VertScrollBar.Page = 206 ActiveControl = AVal BorderStyle = bsDialog Caption = 'Design' ClientHeight = 207 ClientWidth = 636 Constraints.MaxHeight = 207 Constraints.MaxWidth = 636 Constraints.MinHeight = 207 Constraints.MinWidth = 636 Font.Name = 'MS Sans Serif' OnCreate = FormCreate Position = poScreenCenter LCLVersion = '0.9.28.2' object Label4: TLabel Left = 4 Height = 18 Top = 8 Width = 70 Caption = 'Predictors' ParentColor = False end object Label5: TLabel Left = 76 Height = 18 Top = 8 Width = 114 Caption = 'Predictor Names' ParentColor = False end object Label1: TLabel Left = 12 Height = 18 Top = 123 Width = 81 Caption = 'Participants' ParentColor = False end object TemplateLabel: TLabel Left = 148 Height = 18 Top = 95 Width = 112 Caption = 'C:\template.img' ParentColor = False end object Label2: TLabel Left = 12 Height = 18 Top = 168 Width = 263 Caption = 'Ignore voxels damaged in less than N%' ParentColor = False end object OKBtn: TButton Left = 527 Height = 25 Top = 168 Width = 75 BorderSpacing.InnerBorder = 4 Caption = 'OK' ModalResult = 1 TabOrder = 0 end object AVal: TSpinEdit Left = 12 Height = 27 Top = 37 Width = 70 MaxValue = 99 MinValue = 1 OnChange = AValChange TabOrder = 1 Value = 2 end object ALevelNames: TStringGrid Left = 98 Height = 42 Top = 30 Width = 527 ColCount = 2 FixedCols = 0 FixedRows = 0 Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goDrawFocusSelected, goEditing] RowCount = 1 ScrollBars = ssHorizontal TabOrder = 2 TitleFont.Height = -11 TitleFont.Name = 'MS Sans Serif' OnEnter = ALevelNamesEnter OnExit = ALevelNamesExit end object LesionCovaryCheck: TCheckBox Left = 255 Height = 21 Top = 123 Width = 267 Caption = 'Automatically Covary Lesion Volume' TabOrder = 5 Visible = False end object AddMRIBtn: TButton Left = 93 Height = 25 Top = 118 Width = 129 BorderSpacing.InnerBorder = 4 Caption = 'Select Images' OnClick = AddMRIBtnClick TabOrder = 4 end object TemplateBtn: TButton Left = 12 Height = 25 Top = 89 Width = 129 BorderSpacing.InnerBorder = 4 Caption = 'Select Template' OnClick = TemplateBtnClick TabOrder = 3 end object CritPctEdit: TSpinEdit Left = 304 Height = 27 Top = 162 Width = 76 OnChange = AValChange TabOrder = 6 Value = 1 end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/filename.pas���������������������������������������������������0000755�0001750�0001750�00000001117�11326425446�017271� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit filename; interface {$H+} function LegitFilename(var lInName: string; lIndex: integer): string; implementation uses SysUtils; function LegitFilename(var lInName: string; lIndex: integer): string; var I: integer; begin if length(lInName) < 1 then begin result := inttostr(lIndex); exit; end; result := ''; for I := 1 to length(lInName) do if lInName[I] in [ '0'..'9','a'..'z','A'..'Z'] then result := result + lInName[I]; if length(result) < 1 then result := inttostr(lIndex); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/npm.lpi��������������������������������������������������������0000755�0001750�0001750�00000056176�12332435346�016321� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <CONFIG> <ProjectOptions> <Version Value="9"/> <PathDelim Value="\"/> <General> <Flags> <LRSInOutputDirectory Value="False"/> </Flags> <MainUnit Value="0"/> <ActiveWindowIndexAtStart Value="0"/> </General> <VersionInfo> <StringTable ProductVersion=""/> </VersionInfo> <BuildModes Count="1"> <Item1 Name="default" Default="True"/> </BuildModes> <PublishOptions> <Version Value="2"/> <IgnoreBinaries Value="False"/> <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/> </PublishOptions> <RunParams> <local> <FormatVersion Value="1"/> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> </RunParams> <RequiredPackages Count="1"> <Item1> <PackageName Value="LCL"/> </Item1> </RequiredPackages> <Units Count="69"> <Unit0> <Filename Value="npm.lpr"/> <IsPartOfProject Value="True"/> <UnitName Value="npm"/> <EditorIndex Value="0"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="34" Y="11"/> <UsageCount Value="111"/> <Loaded Value="True"/> <LoadedDesigner Value="True"/> </Unit0> <Unit1> <Filename Value="npmform.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="MainForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="npmform"/> <EditorIndex Value="1"/> <WindowIndex Value="0"/> <TopLine Value="1046"/> <CursorPos X="8" Y="1058"/> <UsageCount Value="111"/> <Loaded Value="True"/> <LoadedDesigner Value="True"/> </Unit1> <Unit2> <Filename Value="nifti_hdr.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="nifti_hdr"/> <TopLine Value="358"/> <CursorPos X="49" Y="368"/> <UsageCount Value="107"/> </Unit2> <Unit3> <Filename Value="define_types.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="define_types"/> <TopLine Value="945"/> <CursorPos X="38" Y="959"/> <UsageCount Value="107"/> </Unit3> <Unit4> <Filename Value="GraphicsMathLibrary.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="GraphicsMathLibrary"/> <TopLine Value="681"/> <CursorPos X="1" Y="738"/> <UsageCount Value="107"/> </Unit4> <Unit5> <Filename Value="distr.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="distr"/> <TopLine Value="99"/> <CursorPos X="1" Y="107"/> <UsageCount Value="107"/> </Unit5> <Unit6> <Filename Value="statcr.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="statcr"/> <WindowIndex Value="0"/> <TopLine Value="4"/> <CursorPos X="11" Y="25"/> <UsageCount Value="107"/> </Unit6> <Unit7> <Filename Value="stats.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="stats"/> <WindowIndex Value="0"/> <TopLine Value="615"/> <CursorPos X="1" Y="635"/> <UsageCount Value="107"/> </Unit7> <Unit8> <Filename Value="brunner.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="brunner"/> <TopLine Value="500"/> <CursorPos X="29" Y="517"/> <UsageCount Value="107"/> </Unit8> <Unit9> <Filename Value="StatThdsUtil.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="StatThdsUtil"/> <WindowIndex Value="0"/> <TopLine Value="49"/> <CursorPos X="38" Y="4"/> <UsageCount Value="107"/> </Unit9> <Unit10> <Filename Value="StatThds.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="StatThds"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="24" Y="6"/> <UsageCount Value="107"/> </Unit10> <Unit11> <Filename Value="valformat.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="valformat"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="9" Y="12"/> <UsageCount Value="107"/> </Unit11> <Unit12> <Filename Value="design.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="DesignForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="design"/> <WindowIndex Value="0"/> <TopLine Value="37"/> <CursorPos X="36" Y="58"/> <UsageCount Value="106"/> </Unit12> <Unit13> <Filename Value="spread.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="SpreadForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="spread"/> <IsVisibleTab Value="True"/> <EditorIndex Value="2"/> <WindowIndex Value="0"/> <TopLine Value="547"/> <CursorPos X="11" Y="557"/> <UsageCount Value="106"/> <Loaded Value="True"/> </Unit13> <Unit14> <Filename Value="gzio2.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="gzio2"/> <TopLine Value="774"/> <CursorPos X="22" Y="793"/> <UsageCount Value="107"/> </Unit14> <Unit15> <Filename Value="part.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="part"/> <TopLine Value="91"/> <CursorPos X="38" Y="108"/> <UsageCount Value="107"/> </Unit15> <Unit16> <Filename Value="markorder.pas"/> <UnitName Value="markorder"/> <TopLine Value="8"/> <CursorPos X="44" Y="23"/> <UsageCount Value="6"/> </Unit16> <Unit17> <Filename Value="ztopform.pas"/> <ComponentName Value="ZForm"/> <UnitName Value="ztopform"/> <TopLine Value="9"/> <CursorPos X="18" Y="23"/> <UsageCount Value="18"/> </Unit17> <Unit18> <Filename Value="..\examples\opendialogcrash\unit1.pas"/> <ComponentName Value="Form1"/> <HasResources Value="True"/> <UnitName Value="Unit1"/> <TopLine Value="19"/> <CursorPos X="40" Y="14"/> <UsageCount Value="6"/> </Unit18> <Unit19> <Filename Value="nifti_img.pas"/> <UnitName Value="nifti_img"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="77" Y="4"/> <UsageCount Value="10"/> </Unit19> <Unit20> <Filename Value="lesion_pattern.pas"/> <UnitName Value="lesion_pattern"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="13" Y="21"/> <UsageCount Value="11"/> </Unit20> <Unit21> <Filename Value="ReadInt.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="ReadIntForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="ReadInt"/> <WindowIndex Value="0"/> <TopLine Value="23"/> <CursorPos X="9" Y="50"/> <UsageCount Value="105"/> </Unit21> <Unit22> <Filename Value="ReadInt.lrs"/> <IsPartOfProject Value="True"/> <TopLine Value="1"/> <CursorPos X="1" Y="3"/> <UsageCount Value="103"/> </Unit22> <Unit23> <Filename Value="LesionStatThds.pas"/> <UnitName Value="LesionStatThds"/> <WindowIndex Value="0"/> <TopLine Value="319"/> <CursorPos X="28" Y="335"/> <UsageCount Value="35"/> </Unit23> <Unit24> <Filename Value="power.pas"/> <UnitName Value="power"/> <TopLine Value="1"/> <CursorPos X="1" Y="1"/> <UsageCount Value="7"/> </Unit24> <Unit25> <Filename Value="Mat.pas"/> <UnitName Value="Mat"/> <TopLine Value="225"/> <CursorPos X="18" Y="239"/> <UsageCount Value="7"/> </Unit25> <Unit26> <Filename Value="Vector.pas"/> <UnitName Value="Vector"/> <TopLine Value="1"/> <CursorPos X="1" Y="1"/> <UsageCount Value="6"/> </Unit26> <Unit27> <Filename Value="firth.pas"/> <UnitName Value="firth"/> <WindowIndex Value="0"/> <TopLine Value="294"/> <CursorPos X="38" Y="23"/> <UsageCount Value="34"/> </Unit27> <Unit28> <Filename Value="overlap.pas"/> <UnitName Value="overlap"/> <WindowIndex Value="0"/> <TopLine Value="280"/> <CursorPos X="23" Y="301"/> <UsageCount Value="8"/> </Unit28> <Unit29> <Filename Value="firthThds.pas"/> <UnitName Value="firthThds"/> <WindowIndex Value="0"/> <TopLine Value="604"/> <CursorPos X="52" Y="36"/> <UsageCount Value="29"/> </Unit29> <Unit30> <Filename Value="design.lfm"/> <TopLine Value="1"/> <CursorPos X="1" Y="1"/> <UsageCount Value="6"/> <DefaultSyntaxHighlighter Value="LFM"/> </Unit30> <Unit31> <Filename Value="options.inc"/> <TopLine Value="1"/> <CursorPos X="21" Y="3"/> <UsageCount Value="7"/> </Unit31> <Unit32> <Filename Value="userdir.pas"/> <UnitName Value="userdir"/> <TopLine Value="1"/> <CursorPos X="64" Y="45"/> <UsageCount Value="7"/> </Unit32> <Unit33> <Filename Value="..\..\lcl\forms.pp"/> <UnitName Value="Forms"/> <TopLine Value="642"/> <CursorPos X="14" Y="661"/> <UsageCount Value="7"/> </Unit33> <Unit34> <Filename Value="..\gzio2.pas"/> <UnitName Value="gzio2"/> <TopLine Value="627"/> <CursorPos X="22" Y="635"/> <UsageCount Value="6"/> </Unit34> <Unit35> <Filename Value="..\..\fpc\2.0.4\source\rtl\objpas\sysutils\finah.inc"/> <TopLine Value="17"/> <CursorPos X="22" Y="27"/> <UsageCount Value="6"/> </Unit35> <Unit36> <Filename Value="..\define_types.pas"/> <UnitName Value="define_types"/> <TopLine Value="1"/> <CursorPos X="31" Y="5"/> <UsageCount Value="6"/> </Unit36> <Unit37> <Filename Value="..\..\fpc\2.0.4\source\rtl\win32\wininc\messages.inc"/> <TopLine Value="1191"/> <CursorPos X="6" Y="1201"/> <UsageCount Value="6"/> </Unit37> <Unit38> <Filename Value="regression.pas"/> <UnitName Value="regression"/> <EditorIndex Value="6"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="69" Y="13"/> <UsageCount Value="42"/> <Loaded Value="True"/> </Unit38> <Unit39> <Filename Value="Regmult.pas"/> <UnitName Value="RegMult"/> <TopLine Value="30"/> <CursorPos X="27" Y="43"/> <UsageCount Value="6"/> </Unit39> <Unit40> <Filename Value="..\fpmath\regmult.pas"/> <UnitName Value="regmult"/> <TopLine Value="39"/> <CursorPos X="69" Y="45"/> <UsageCount Value="6"/> </Unit40> <Unit41> <Filename Value="..\common\distr.pas"/> <UnitName Value="distr"/> <TopLine Value="296"/> <CursorPos X="1" Y="308"/> <UsageCount Value="7"/> </Unit41> <Unit42> <Filename Value="..\common\define_types.pas"/> <UnitName Value="define_types"/> <EditorIndex Value="5"/> <WindowIndex Value="0"/> <TopLine Value="8"/> <CursorPos X="57" Y="25"/> <UsageCount Value="36"/> <Loaded Value="True"/> </Unit42> <Unit43> <Filename Value="hdr.pas"/> <UnitName Value="hdr"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="42" Y="5"/> <UsageCount Value="34"/> </Unit43> <Unit44> <Filename Value="..\common\gzio2.pas"/> <UnitName Value="gzio2"/> <WindowIndex Value="0"/> <TopLine Value="1770"/> <CursorPos X="11" Y="1778"/> <UsageCount Value="12"/> </Unit44> <Unit45> <Filename Value="..\common\nifti_hdr.pas"/> <UnitName Value="nifti_hdr"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="52" Y="14"/> <UsageCount Value="9"/> </Unit45> <Unit46> <Filename Value="..\common\GraphicsMathLibrary.pas"/> <UnitName Value="GraphicsMathLibrary"/> <TopLine Value="1"/> <CursorPos X="17" Y="8"/> <UsageCount Value="6"/> </Unit46> <Unit47> <Filename Value="..\fpmath\utypes.pas"/> <UnitName Value="utypes"/> <TopLine Value="470"/> <CursorPos X="41" Y="482"/> <UsageCount Value="8"/> </Unit47> <Unit48> <Filename Value="lesion.pas"/> <UnitName Value="lesion"/> <TopLine Value="299"/> <CursorPos X="64" Y="313"/> <UsageCount Value="6"/> </Unit48> <Unit49> <Filename Value="anacom.pas"/> <UnitName Value="anacom"/> <TopLine Value="579"/> <CursorPos X="32" Y="593"/> <UsageCount Value="6"/> </Unit49> <Unit50> <Filename Value="filename.pas"/> <UnitName Value="filename"/> <TopLine Value="1"/> <CursorPos X="6" Y="4"/> <UsageCount Value="6"/> </Unit50> <Unit51> <Filename Value="montecarlo.pas"/> <UnitName Value="montecarlo"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="6" Y="3"/> <UsageCount Value="7"/> </Unit51> <Unit52> <Filename Value="roc.pas"/> <UnitName Value="roc"/> <WindowIndex Value="0"/> <TopLine Value="2"/> <CursorPos X="41" Y="14"/> <UsageCount Value="7"/> </Unit52> <Unit53> <Filename Value="..\fpmath\types.inc"/> <WindowIndex Value="0"/> <TopLine Value="153"/> <CursorPos X="3" Y="174"/> <UsageCount Value="11"/> </Unit53> <Unit54> <Filename Value="C:\Developer\lazarus\lcl\interfaces\carbon\carbonprivatecommon.inc"/> <TopLine Value="170"/> <CursorPos X="1" Y="184"/> <UsageCount Value="6"/> </Unit54> <Unit55> <Filename Value="tfce_clustering.pas"/> <UnitName Value="tfce_clustering"/> <WindowIndex Value="0"/> <TopLine Value="8"/> <CursorPos X="75" Y="11"/> <UsageCount Value="10"/> </Unit55> <Unit56> <Filename Value="C:\Developer\lazarus\lcl\include\menuitem.inc"/> <WindowIndex Value="0"/> <TopLine Value="61"/> <CursorPos X="1" Y="83"/> <UsageCount Value="8"/> </Unit56> <Unit57> <Filename Value="..\common\isgui.inc"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="10" Y="1"/> <UsageCount Value="36"/> </Unit57> <Unit58> <Filename Value="..\common\dialogsx.pas"/> <UnitName Value="dialogsx"/> <WindowIndex Value="0"/> <TopLine Value="8"/> <CursorPos X="10" Y="35"/> <UsageCount Value="31"/> </Unit58> <Unit59> <Filename Value="..\common\dicomhdr.pas"/> <UnitName Value="dicomhdr"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="13" Y="7"/> <UsageCount Value="6"/> </Unit59> <Unit60> <Filename Value="unpm.pas"/> <UnitName Value="unpm"/> <EditorIndex Value="4"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="49" Y="8"/> <UsageCount Value="40"/> <Loaded Value="True"/> </Unit60> <Unit61> <Filename Value="turbolesion.pas"/> <UnitName Value="turbolesion"/> <EditorIndex Value="3"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="63" Y="8"/> <UsageCount Value="35"/> <Loaded Value="True"/> </Unit61> <Unit62> <Filename Value="prefs.pas"/> <UnitName Value="prefs"/> <WindowIndex Value="0"/> <TopLine Value="129"/> <CursorPos X="22" Y="134"/> <UsageCount Value="33"/> </Unit62> <Unit63> <Filename Value="C:\usr\local\share\fpcsrc\rtl\objpas\sysutils\sysstrh.inc"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="10" Y="107"/> <UsageCount Value="7"/> </Unit63> <Unit64> <Filename Value="..\common\cpucount.pas"/> <UnitName Value="cpucount"/> <WindowIndex Value="0"/> <TopLine Value="1"/> <CursorPos X="10" Y="5"/> <UsageCount Value="31"/> </Unit64> <Unit65> <Filename Value="C:\Developer\lazarus\lcl\include\progressbar.inc"/> <WindowIndex Value="0"/> <TopLine Value="155"/> <CursorPos X="1" Y="178"/> <UsageCount Value="8"/> </Unit65> <Unit66> <Filename Value="C:\Developer\lazarus\lcl\dialogs.pp"/> <UnitName Value="Dialogs"/> <WindowIndex Value="0"/> <TopLine Value="486"/> <CursorPos X="10" Y="500"/> <UsageCount Value="31"/> </Unit66> <Unit67> <Filename Value="..\..\..\..\..\..\usr\local\share\fpcsrc\packages\paszlib\src\zdeflate.pas"/> <UnitName Value="zdeflate"/> <WindowIndex Value="0"/> <TopLine Value="1035"/> <CursorPos X="10" Y="1049"/> <UsageCount Value="12"/> </Unit67> <Unit68> <Filename Value="..\..\..\..\..\..\Developer\lazarus\lcl\include\menuitem.inc"/> <WindowIndex Value="0"/> <TopLine Value="5"/> <CursorPos X="1" Y="83"/> <UsageCount Value="10"/> </Unit68> </Units> <JumpHistory Count="30" HistoryIndex="29"> <Position1> <Filename Value="npmform.pas"/> <Caret Line="1484" Column="8" TopLine="1470"/> </Position1> <Position2> <Filename Value="turbolesion.pas"/> <Caret Line="398" Column="113" TopLine="379"/> </Position2> <Position3> <Filename Value="npmform.pas"/> <Caret Line="4" Column="52" TopLine="1"/> </Position3> <Position4> <Filename Value="npmform.pas"/> <Caret Line="83" Column="10" TopLine="63"/> </Position4> <Position5> <Filename Value="npmform.pas"/> <Caret Line="335" Column="16" TopLine="324"/> </Position5> <Position6> <Filename Value="npmform.pas"/> <Caret Line="422" Column="30" TopLine="402"/> </Position6> <Position7> <Filename Value="npmform.pas"/> <Caret Line="462" Column="40" TopLine="460"/> </Position7> <Position8> <Filename Value="npmform.pas"/> <Caret Line="799" Column="35" TopLine="786"/> </Position8> <Position9> <Filename Value="npmform.pas"/> <Caret Line="800" Column="58" TopLine="786"/> </Position9> <Position10> <Filename Value="npmform.pas"/> <Caret Line="801" Column="29" TopLine="786"/> </Position10> <Position11> <Filename Value="npmform.pas"/> <Caret Line="805" Column="26" TopLine="786"/> </Position11> <Position12> <Filename Value="npmform.pas"/> <Caret Line="906" Column="26" TopLine="886"/> </Position12> <Position13> <Filename Value="npmform.pas"/> <Caret Line="2" Column="127" TopLine="1"/> </Position13> <Position14> <Filename Value="npmform.pas"/> <Caret Line="130" Column="21" TopLine="110"/> </Position14> <Position15> <Filename Value="npmform.pas"/> <Caret Line="2" Column="129" TopLine="1"/> </Position15> <Position16> <Filename Value="npmform.pas"/> <Caret Line="25" Column="18" TopLine="5"/> </Position16> <Position17> <Filename Value="npmform.pas"/> <Caret Line="3" Column="130" TopLine="1"/> </Position17> <Position18> <Filename Value="npmform.pas"/> <Caret Line="82" Column="17" TopLine="62"/> </Position18> <Position19> <Filename Value="npmform.pas"/> <Caret Line="94" Column="15" TopLine="74"/> </Position19> <Position20> <Filename Value="npmform.pas"/> <Caret Line="119" Column="25" TopLine="99"/> </Position20> <Position21> <Filename Value="npmform.pas"/> <Caret Line="3" Column="129" TopLine="1"/> </Position21> <Position22> <Filename Value="npmform.pas"/> <Caret Line="104" Column="30" TopLine="84"/> </Position22> <Position23> <Filename Value="npmform.pas"/> <Caret Line="414" Column="49" TopLine="394"/> </Position23> <Position24> <Filename Value="npmform.pas"/> <Caret Line="992" Column="7" TopLine="991"/> </Position24> <Position25> <Filename Value="npmform.pas"/> <Caret Line="991" Column="7" TopLine="990"/> </Position25> <Position26> <Filename Value="npmform.pas"/> <Caret Line="5" Column="105" TopLine="1"/> </Position26> <Position27> <Filename Value="npmform.pas"/> <Caret Line="103" Column="7" TopLine="83"/> </Position27> <Position28> <Filename Value="npmform.pas"/> <Caret Line="118" Column="32" TopLine="98"/> </Position28> <Position29> <Filename Value="npmform.pas"/> <Caret Line="434" Column="8" TopLine="410"/> </Position29> <Position30> <Filename Value="spread.pas"/> <Caret Line="584" Column="1" TopLine="555"/> </Position30> </JumpHistory> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <SearchPaths> <OtherUnitFiles Value="..\fpmath;..\common"/> </SearchPaths> <Parsing> <SyntaxOptions> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> <UseLineInfoUnit Value="False"/> <StripSymbols Value="True"/> </Debugging> <LinkSmart Value="True"/> <Options> <LinkerOptions Value=" -macosx_version_min 10.4 "/> <Win32> <GraphicApplication Value="True"/> </Win32> </Options> </Linking> <Other> <CompilerMessages> <UseMsgFile Value="True"/> </CompilerMessages> <CompilerPath Value="$(CompPath)"/> </Other> </CompilerOptions> <Debugging> <Exceptions Count="2"> <Item1> <Name Value="ECodetoolError"/> </Item1> <Item2> <Name Value="EFOpenError"/> </Item2> </Exceptions> </Debugging> </CONFIG> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/tfce_clustering.zip��������������������������������������������0000755�0001750�0001750�00000004375�12110670532�020707� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PK����BdSBy!Q�������tfce_clustering.pasio0'.krA%ch�eZ8vqCwm6 G=p^sN$"#gHn!L*% #D gA9<Sœ<O@$8G\wq<y'a% #g$$d~LC&9{(|NE/bV4j#s .HK{*ALy2#ԍ!ILSٯ I;ye�Z9OS@d )Nr)4/uJ`c9H \ >h�ȏo�B0rè`9y:.I W&e}ŗi"dj0*KF"~!h͉Ϧ>54"|Ձg"e!=mtAqI00z $�\!AId) /Dq3S[J@0nG{ l�d"˨Kȴ5v܈ @9!s)NII&Sc|"=#ʔfKYdD�ޛ›_jW} ч;H419~@wo쁷w�n7c£UV !9N/!kD6l =g1qai[>{0zpDQI xD:G%\ z@л]eimowhkY|[+.?z4~ZTNLܷVjXI'vYiB;з�M O>n.`i`,81 :FO8HX;0)T-# ͅD2�>B~W)0q$6ۺ7\}w'>UYRVeDy+LU.%.N|C;]PAq< Hc|`muiz %FiP!V{y[lBsǒFki5CplS1ciцeִ'mP)B-}Z*״nIGC {M4^|Հ-V"q|݀-jA9)v:S`BLX4aHn!j`,v,DU/_6Mګ9,BL&=G<C;Gv ,5w\JP䵒nY%N_w4RY"TȎjxEBr"&[C~~P 3Ώ'^7q�U{C W2@ߒnkflf3YUJ,mf 'iK)ߠZ$-Zx_Y3"?۽}$:UdDʦTf˨;ޟkI" I,?#Ra .~UoF=xKWBjgݰ</p/.ͧ}m_`1'+BzZ[s%2as,)dFdhU(xZ˒K X?2U2ʫ3WnaZC_ט]?13ܞ ۥ\lr=B8G!uh֤ۜO yY7$oSP4 "dXJEJ*jYfz$O}qJO1E1G <vʬ*l~AS2Z8kG#8ԠoXd9ez 6MM>72ӹ~ziNn> sڮ7KնiQK÷A^blvmsVQd%`P@&fDo{71'K-Ԥ^2Cp.yzf߁; RXNdKsn#u BץK=lp}Y3Pu\ aq!lH Һ"Zv)o9 xZSehK|(u{xqu-*z M7nqb]@oxf:bG]nxw겹jjJWk9yFYa~gjt.~"z+VݦoZ,XNzͲPK?�����BdSBy!Q�����$������� �������tfce_clustering.pas � ��������NO QnTJ^ PK������e��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/npmcl.lpi������������������������������������������������������0000755�0001750�0001750�00000003670�12156644020�016622� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <CONFIG> <ProjectOptions> <Version Value="9"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> </Flags> <SessionStorage Value="InProjectDir"/> <MainUnit Value="0"/> <Title Value="NPMcl"/> <UseAppBundle Value="False"/> <ResourceType Value="res"/> </General> <i18n> <EnableI18N LFM="False"/> </i18n> <VersionInfo> <StringTable ProductVersion=""/> </VersionInfo> <BuildModes Count="1"> <Item1 Name="Default" Default="True"/> </BuildModes> <PublishOptions> <Version Value="2"/> <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> <ExcludeFileFilter Value="*.(bak|ppu|o|so);*~;backup"/> </PublishOptions> <RunParams> <local> <FormatVersion Value="1"/> </local> </RunParams> <Units Count="2"> <Unit0> <Filename Value="npmcl.lpr"/> <IsPartOfProject Value="True"/> <UnitName Value="npmcl"/> </Unit0> <Unit1> <Filename Value="unpm.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="unpm"/> </Unit1> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="npmcl"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="../common;../fpmath"/> <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Other> <CompilerMessages> <MsgFileName Value=""/> </CompilerMessages> <CompilerPath Value="$(CompPath)"/> </Other> </CompilerOptions> <Debugging> <Exceptions Count="3"> <Item1> <Name Value="EAbort"/> </Item1> <Item2> <Name Value="ECodetoolError"/> </Item2> <Item3> <Name Value="EFOpenError"/> </Item3> </Exceptions> </Debugging> </CONFIG> ������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/dice.ico�������������������������������������������������������0000755�0001750�0001750�00000001376�07522725654�016422� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ��������(��� ���@�����������������������������������������������������������������������3wywwywwwwww������������������������wwww������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/npm.ini��������������������������������������������������������0000755�0001750�0001750�00000000173�12306715132�016271� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[BOOL] computettest=1 computebm=0 countlesionpatterns=1 ROI=1 [INT] CacheMB=888 nPermute=4000 nThread=2 TFCE=0 �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/spread.pas�����������������������������������������������������0000755�0001750�0001750�00000102332�12332435346�016766� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit spread; interface {$H+} uses {$IFNDEF FPC} //Utils, Toolwin,shlobj,Spin,ShellApi,windows,messages, {$ELSE} LResources, {$ENDIF} SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Grids, Menus, ComCtrls, Buttons,Clipbrd,design, StdCtrls, define_types,valformat;//Registry, type { TSpreadForm } TSpreadForm = class(TForm) DataGrid: TStringGrid; MainMenu1: TMainMenu; File1: TMenuItem; //DescriptiveMenu: TMenuItem; New1: TMenuItem; Open1: TMenuItem; Design1:TMenuItem; Quit1: TMenuItem; ToolBar1: TToolBar; Help1: TMenuItem; Aboutthissoftware1: TMenuItem; StatusBar1: TStatusBar; Save1: TMenuItem; Edit1: TMenuItem; Copy1: TMenuItem; Paste1: TMenuItem; OpenDialog1: TOpenDialog; SaveDialog1: TSaveDialog; Selectall1: TMenuItem; View: TMenuItem; Font1: TMenuItem; N81: TMenuItem; N101: TMenuItem; N121: TMenuItem; N141: TMenuItem; DesignBtn: TSpeedButton; Clearallcells1: TMenuItem; DescriptiveMenu: TMenuItem; procedure UpdateLabels; function GetVal (lC,lR: integer; var lVal: double): boolean; procedure Quit1Click(Sender: TObject); procedure FormResize(Sender: TObject); procedure Aboutthissoftware1Click(Sender: TObject); procedure OpenBtnClick(Sender: TObject); procedure DataGridSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); procedure NewBtnClick(Sender: TObject); procedure Save1Click(var NoCancel: boolean); procedure FormCreate(Sender: TObject); procedure DataGridMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure OpenTextFile (var lFilename:string); function CheckSave2Close (lAllowCancel: boolean): boolean; procedure DataGridKeyPress(Sender: TObject; var Key: Char); procedure Copy1Click(Sender: TObject); procedure Paste1Click(Sender: TObject); procedure SaveBtnClick(Sender: TObject); procedure ShowStatus; procedure ReadCells2Buffer; procedure Selectall1Click(Sender: TObject); procedure FontSizeChange(Sender: TObject); procedure DataGridMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure DataGridDrawCell(Sender: TObject; Col, Row: Integer; Rect: TRect; State: TGridDrawState); procedure Clearallcells1Click(Sender: TObject); procedure DesignBtnClick(Sender: TObject); procedure AddMRIScansClick(Sender: TObject); procedure DescriptiveClick(Sender: TObject); function SOpenDialogExecute (lCaption: string;lAllowMultiSelect,lForceMultiSelect: boolean; lFilter: string): boolean; {$IFNDEF FPC} procedure FormClose(Sender: TObject; var Action: TCloseAction); {$ELSE} procedure FormClose(Sender: TObject); //procedure SpeedButton3Click(Sender: TObject); {$ENDIF} private //procedure WMDropFiles(var Msg: TWMDropFiles); message WM_DROPFILES; { Private declarations } public { Public declarations } end; var SpreadForm: TSpreadForm; const kRegressSWName = 'VAL'; kRegressSWVers = kRegressSWName+' v1.0'; kMaxFactors = 1; gVALChanges: boolean = false; gDesignUnspecified : boolean = true; gEnterCell : boolean= false; gVALFontSize: integer = 8; kMagicDouble : double = -111666222; //kVALNativeSignature = 'abba'; //kTxtExt = '.txt'; //kVALNativeExt = '.val'; implementation uses statcr,hdr; {$IFNDEF FPC} {$R *.DFM} {$ENDIF} function TSpreadForm.SOpenDialogExecute (lCaption: string;lAllowMultiSelect,lForceMultiSelect: boolean; lFilter: string): boolean;//; lAllowMultiSelect: boolean): boolean; var lNumberofFiles: integer; begin OpenDialog1.Filter := lFilter;//kAnaHdrFilter;//lFilter; OpenDialog1.FilterIndex := 1; OpenDialog1.Title := lCaption; if lAllowMultiSelect then OpenDialog1.Options := [ofAllowMultiSelect,ofFileMustExist] else OpenDialog1.Options := [ofFileMustExist]; result := OpenDialog1.Execute; if not result then exit; if lForceMultiSelect then begin lNumberofFiles:= OpenDialog1.Files.Count; if lNumberofFiles < 2 then begin Showmessage('Error: This function is designed to overlay MULTIPLE images. You selected less than two images.'); result := false; end; end; end; (*procedure TSpreadForm.WMDropFiles(var Msg: TWMDropFiles); var lStr: string; CFileName: array[0..MAX_PATH] of Char; begin try if DragQueryFile(Msg.Drop, 0, CFileName, MAX_PATH) > 0 then //requires ShellAPI in 'uses' clause begin if gChanges then begin if not CheckSave2Close(true) then exit; end; lStr := CFilename; OpenTextFile(lStr); OpenDialog1.FileName := lStr; Msg.Result := 0; end; finally DragFinish(Msg.Drop); end; end; *) procedure TSpreadForm.Quit1Click(Sender: TObject); begin if not CheckSave2Close(true) then exit; gVALChanges := false; SpreadForm.Close; end; procedure TSpreadForm.FormResize(Sender: TObject); var lClient,lWid,lCount: integer; begin lCount := DataGrid.ColCount; lClient := DataGrid.ClientWidth; if lCount < 1 then begin DataGrid.ColWidths[0] := lClient; exit; end; lWid := ((lClient) div lCount); DataGrid.DefaultColWidth := lWid-1; (*if lWid <> lCol1Wid then begin lCol1Wid := (lClient-((lCount) * lWid))-lCount{-14}; lGrid.ColWidths[0] := lCol1Wid; end;*) end; function ColLabel (lCol: integer): string; //first column= A, 26th=Z,27th AA, etc... var lColDiv,lColMod: integer; begin result := ''; lColDiv := lCol; repeat lColMod := lColDiv mod 26; if lColMod = 0 then lColMod := 26; result := chr(ord('A')+lColMod-1)+result; {if lColDiv = 26 then lColDiv := 0 else} lColDiv := (lColDiv-1) div 26; until lColDiv <= 0; end; procedure UpdateGridLabels(lGrid: TStringGrid); var lA,lInc,lInc2: integer; begin if lGrid.RowCount < 2 then exit; //for lInc := (lGrid.RowCount -1) downto 1 do // lGrid.Cells[0,kMaxFactors+lInc] := inttostr(lInc); if (lGrid.ColCount) < 1 then exit; //Next enter ANOVA labels for each row for lInc := (lGrid.ColCount-1 {-1 for Lazarus 999}) downto 0 do for lInc2 := 0 to kMaxFactors do lGrid.Cells[lInc,lInc2] := ''; lA := DesignForm.AVal.value; //999 showmessage(inttostr(lGrid.RowCount)+'x'+inttostr(lGrid.ColCount)+'alpha'+inttostr(lA)); //lGrid.Cells[0,0] := ''; for lInc := 1 to lA do lGrid.Cells[lInc,0] := DesignForm.ALevelNames.Cells[lInc-1,0]; {$IFDEF FPC} for lInc := (lGrid.ColCount -2) downto 0 do lGrid.Cells[lInc +1 ,kMaxFactors] := ColLabel(lInc+1); {$ELSE} for lInc := (lGrid.ColCount -1) downto 0 do lGrid.Cells[lInc+1,kMaxFactors] := ColLabel(lInc+1);//chr(ord('A')+lInc); {$ENDIF} end; procedure TSpreadForm.UpdateLabels; begin DataGrid.ColCount := DesignForm.AVal.value+1; //2007 For FPC UpdateGridLabels(DataGrid); DataGrid.ColCount := DesignForm.AVal.value+1; end; procedure TSpreadForm.Aboutthissoftware1Click(Sender: TObject); begin Showmessage(kRegressSWVers); // AboutForm.Showmodal; end; procedure ClearDesignMatrix; begin gDesignUnspecified := true; SpreadForm.DesignBtn.Caption := 'Design: not specified'; end; procedure DesignBtnLabelUpdate; begin SpreadForm.DesignBtn.Caption := 'Design IVs: '+inttostr(DesignForm.AVal.Value) ; SpreadForm.UpdateLabels; SpreadForm.FormResize(nil); end; {$ifdef fpc} function alignx(addr : Pointer;alignment : PtrUInt) : Pointer; begin result:=align(addr,alignment); end; {$endif} procedure TSpreadForm.OpenTextFile (var lFilename:string); var lTemplateName:string; lnCritPct,lnRow,lnCol,lnColWObs,lCol,lRow: integer; //lLesionCovary : boolean; lPredictorList,lFileList:TStringList; lDoublePtr: Pointer; lDoubleBuf : DoubleP; begin Self.Caption := kRegressSWVers+': '+extractfilename(lFilename); ClearDesignMatrix; lPredictorList := TStringList.Create; lFileList := TStringList.Create; gVALChanges := false; OpenValFile (lFilename,lTemplateName, lnRow,lnCol,lnColWObs,lnCritPct,gDesignUnspecified,lPredictorList,lFileList,lDoublePtr); {$IFDEF FPC} DataGrid.RowCount := kMaxFactors+lnRow{-1}; {$ELSE} DataGrid.RowCount := kMaxFactors+lnRow; {$ENDIF} DataGrid.ColCount := lnCol+1; DataGrid.refresh; {$IFDEF FPC} lDoubleBuf := alignx(lDoublePtr, 16); // note: lDoubleBuf > lDoublePtr always (VSDS); {$ELSE} lDoubleBuf := DoubleP($fffffff0 and (integer(lDoublePtr)+15)); {$ENDIF} if lFileList.Count < lnRow then lnRow := lFileList.Count; for lRow := 1 to lnRow do begin DataGrid.Cells[ 0, kMaxFactors+lRow ] := lFileList.Strings[lRow-1]; for lCol := 1 to lnCol do begin if lDoubleBuf^[RowColPos (lRow,lCol,lnColWObs)] = kMagicDouble then DataGrid.Cells[ lCol, kMaxFactors+lRow ] := '' else DataGrid.Cells[ lCol, kMaxFactors+lRow ] := floattostr((lDoubleBuf^[RowColPos (lRow,lCol,lnColWObs)])); end; end; if lPredictorList.Count < lnRow then for lCol := (lPredictorList.Count+1) to lnRow do lPredictorList.Add( 'Pred'+inttostr(lCol) ); DesignForm.ALevelNames.ColCount := lnCol; for lCol := 1 to lnCol do DesignForm.ALevelNames.Cells[lCol-1,0] := lPredictorList.Strings[lCol-1]; Freemem(lDoublePtr); lPredictorList.Free; lFileList.free; //DesignForm.LesionCovaryCheck.Checked := lLesionCovary; DesignForm.CritPctEdit.value := lnCritPct; DesignForm.TemplateLabel.Caption := lTemplateName; //Tidy Up... DesignForm.AVal.Value := lnCol; UpdateLabels; DesignBtnLabelUpdate; FormResize(nil); if gDesignUnspecified then Showmessage('You need to define the experiment design [press the ''Design'' button]'); end; procedure TSpreadForm.OpenBtnClick(Sender: TObject); var lFileName: string; begin if gVALChanges then begin if not CheckSave2Close(true) then exit; end; if not SOpenDialogExecute('Select VAL design file',false,false, kValFilter) then exit; lFilename := OpenDialog1.filename; if not fileexists(lFilename) then exit; OpenTextFile(lFilename); end; procedure GridToStatusBar(lGrid: TStringGrid; lStatus: TStatusBar); begin {$IFDEF FPC} //SpreadForm.StatusBar1.Panels[1].Text := inttostr(random(888)); if (lGrid.Selection.Top <= kMaxFactors) or (lGrid.Selection.Left <= 0) then begin lGrid.Selection:=TGridRect(Rect(-1,-1,-1,-1)); SpreadForm.Caption := ''; exit; end; if lGrid.Selection.Top < 0 then exit; if((lGrid.Selection.Top = lGrid.Selection.Bottom ) and ( lGrid.Selection.Left = lGrid.Selection.Right )) then begin SpreadForm.Caption := lGrid.Cells[0,lGrid.Selection.Top]+' = '+lGrid.Cells[lGrid.Selection.Left,lGrid.Selection.Top]+' '+ lGrid.Cells[lGrid.Selection.Left,0]+' '+ lGrid.Cells[lGrid.Selection.Left,1]+inttostr(lGrid.Selection.Top-kMaxFactors); end else begin SpreadForm.Caption := inttostr(lGrid.Selection.Bottom-lGrid.Selection.Top + 1)+'R x '+ inttostr(lGrid.Selection.Right-lGrid.Selection.Left + 1)+'C'; end; (*if((lGrid.Selection.Top <> lGrid.Selection.Bottom ) or ( lGrid.Selection.Left <> lGrid.Selection.Right )) then exit; if (lGrid.Selection.Top <= kMaxFactors) or (lGrid.Selection.Left <= 0) then begin lGrid.Selection:=TGridRect(Rect(-1,-1,-1,-1)); lStatus.Panels[0].Text := ''; exit; end; if (lGrid.Selection.Top < 0) then exit; //lStatus.Panels[1].Text := inttostr(lGrid.Selection.Bottom-lGrid.Selection.Top + 1)+'R x '+ inttostr(lGrid.Selection.Right-lGrid.Selection.Left + 1)+'C'; //lStatus.Panels[1].Text := inttostr(lGrid.Selection.Top)+'R x '+ inttostr(lGrid.Selection.Bottom)+'C'; SpreadForm.Caption := inttostr(lGrid.Selection.Top)+'R x '+ inttostr(lGrid.Selection.Left)+'C'; exit; if((lGrid.Selection.Top = lGrid.Selection.Bottom ) and ( lGrid.Selection.Left = lGrid.Selection.Right )) then begin lStatus.Panels[1].Text := {ColLabel(lGrid.Selection.Left)+}lGrid.Cells[0,lGrid.Selection.Top]{inttostr(lGrid.Selection.Top-kMaxFactors)}+' = '+lGrid.Cells[lGrid.Selection.Left,lGrid.Selection.Top]; // lStatus.Panels[0].Text := lGrid.Cells[lGrid.Selection.Left,0]+' '+ lGrid.Cells[lGrid.Selection.Left,1]+' '+lGrid.Cells[lGrid.Selection.Left,2]; // lStatus.Panels[0].Text := lGrid.Cells[lGrid.Selection.Left,0]+' '+ lGrid.Cells[lGrid.Selection.Left,1]+inttostr(lGrid.Selection.Top-kMaxFactors); //lStatus.Panels[0].Text := lGrid.Cells[lGrid.Selection.Left,0]+' '+ lGrid.Cells[lGrid.Selection.Left,1]+inttostr(lGrid.Selection.Top-kMaxFactors); end else begin lStatus.Panels[0].Text := inttostr(lGrid.Selection.Bottom-lGrid.Selection.Top + 1)+'R x '+ inttostr(lGrid.Selection.Right-lGrid.Selection.Left + 1)+'C'; lStatus.Panels[1].Text := ''; end; *) {$ELSE} //Delphi if (lGrid.Selection.Top <= kMaxFactors) or (lGrid.Selection.Left <= 0) then begin lGrid.Selection:=TGridRect(Rect(-1,-1,-1,-1)); lStatus.Panels[0].Text := ''; exit; end; if lGrid.Selection.Top < 0 then exit; if((lGrid.Selection.Top = lGrid.Selection.Bottom ) and ( lGrid.Selection.Left = lGrid.Selection.Right )) then begin lStatus.Panels[1].Text := lGrid.Cells[0,lGrid.Selection.Top]+' = '+lGrid.Cells[lGrid.Selection.Left,lGrid.Selection.Top]; lStatus.Panels[0].Text := lGrid.Cells[lGrid.Selection.Left,0]+' '+ lGrid.Cells[lGrid.Selection.Left,1]+inttostr(lGrid.Selection.Top-kMaxFactors); end else begin lStatus.Panels[0].Text := inttostr(lGrid.Selection.Bottom-lGrid.Selection.Top + 1)+'R x '+ inttostr(lGrid.Selection.Right-lGrid.Selection.Left + 1)+'C'; lStatus.Panels[1].Text := ''; end; {$ENDIF} end; procedure TSpreadForm.ShowStatus; begin //SpreadForm.Caption := inttostr(random(888)); GridToStatusBar(DataGrid,StatusBar1); end; procedure TSpreadForm.DataGridSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); begin //ShowStatus; //bxxx gEnterCell := true; end; procedure TSpreadForm.NewBtnClick(Sender: TObject); begin DesignForm.Showmodal; gDesignUnspecified := false; DesignBtnLabelUpdate; end; function RemoveColons( lStr: string): string; var lLen,lPos: integer; begin result := lStr; lLen := length(lStr); if lLen < 1 then exit; for lPos := 1 to lLen do if result[lPos] = ':' then result[lPos] := ';'; end; function Str2Float (var lStr: string; var lError: boolean): single; begin lError := false; try result := Strtofloat(lStr); except on EConvertError do lError := true; end; //except end; procedure TSpreadForm.Save1Click(var NoCancel: boolean); const kNative = 1; kTxt = 2; var f: TextFile; lFormat,C, R,lLen,lPos,ColStart,ColEnd,RowStart,RowEnd : integer ; lLevelStr,lFilename,S,lCell,lExt : string ; kSpacer,lDecimalSep : char; lError: boolean; begin NoCancel := false; if not SaveDialog1.Execute then exit; lFormat := SaveDialog1.FilterIndex; if (lFormat < kNative) or (lFormat > kTxt) then lFormat := kNative; case lFormat of kTxt: lExt := kTXText; else lExt := kValNativeExt; end; if lFormat <> kNative then begin case MessageDlg( 'Export file as a text format? Note you will lose information about the experiment design [save to Native format to preserve condition information]', mtWarning, [mbYes, mbCancel], 0 ) of mrCancel : exit ; end ; end; //not native if (lFormat = kNative) and (gDesignUnspecified) then begin showmessage('Unable to save this data as '+kRegressSWVers+' format file until you have specified the conditions [press the ''Design'' button]'); exit; end; //lExt := StrUpper(PChar(extractfileext(SaveDialog1.Filename))); lFilename := SaveDialog1.Filename; lDecimalSep := DecimalSeparator; DecimalSeparator := '.'; ChangeFileExt(lFilename,lExt); // Setup... kSpacer := #9; //tab S := '' ; RowStart := kMaxFactors+1 ; RowEnd := DataGrid.RowCount - 1; ColStart := 0 ; ColEnd := DataGrid.ColCount - 1; if (ColEnd < ColStart) or (RowEnd < RowStart) then exit; // Copy to string for R := RowStart to RowEnd do begin for C := ColStart to ColEnd do begin lCell := DataGrid.Cells[ C, R ]; if C <> ColStart then begin if lCell = '' then //this simply prevents error reports when run from debugger lError := true else Str2Float (lCell, lError); if (lError) then lCell := '-'; end; S := S + lCell; if( C < DataGrid.ColCount - 1 ) then S := S + kSpacer{#9} ; // Tab end ; if R <> (DataGrid.RowCount - 1) then //all except last line S := S + #13#10 ; // End line end ; AssignFile(f, lFileName); rewrite(f); if lFormat = kNative then begin Self.Caption := kRegressSWVers+': '+extractfilename(SaveDialog1.Filename);//remove any previous filename if Files4D(DataGrid.Cells[ ColStart, RowStart ]) then writeln(f,kVALNativeSignatureBase + '1')//version 1 supports 4D images else writeln(f,kVALNativeSignatureBase + '0');//version 0 supports 3D images only //Details for 1st factor //writeln(f,'#Predictors:'+inttostr(lLen)+lLevelStr+lWithinSubjStr); writeln(f,'#Covary Volume'+kSpacer+bool2char(DesignForm.LesionCovaryCheck.Checked)); writeln(f,'#Template'+kSpacer+DesignForm.TemplateLabel.Caption); writeln(f,'#CritPct'+kSpacer+inttostr(DesignForm.CritPctEdit.value)); lLevelStr := 'ImageName'; lLen := DesignForm.AVal.value; if lLen >= 1 then for lPos := 1 to lLen do lLevelStr := lLevelStr+kTab+(DesignForm.ALevelNames.Cells[lPos-1,0]); writeln(f,lLevelStr); gVALChanges := false; end; Writeln(f, S); Flush(f); { ensures that the text was actually written to file } CloseFile(f); NoCancel := true; DecimalSeparator :=lDecimalSep; end; (* procedure registerfiletype(inft,inkey,desc,icon:string); var myreg : treginifile; ct : integer; ft,key: string; begin ft := inft; key := inkey; ct := pos('.',ft); while ct > 0 do begin delete(ft,ct,1); ct := pos('.',ft); end; if (ft = '') or (Application.ExeName = '') then exit; //not a valid file-ext or ass. app ft := '.'+ft; myreg := treginifile.create(''); try myreg.rootkey := hkey_classes_root; // where all file-types are described if key = '' then key := copy(ft,2,maxint)+'_auto_file'; // if no key-name is given, create one myreg.writestring(ft,'',key); // set a pointer to the description-key myreg.writestring(key,'',desc); // write the description myreg.writestring(key+'\DefaultIcon','',icon); // write the def-icon if given myreg.writestring(key+'\shell\open\command','',Application.ExeName+' %1'); //association finally myreg.free; end; end; *) procedure TSpreadForm.FormCreate(Sender: TObject); begin SpreadForm.Caption := kRegressSWName; (* registerfiletype(kNativeExt,kRegressSWName{key},kRegressSWName,Application.ExeName+',1'); DragAcceptFiles(Handle, True); *) DataGrid.Selection:=TGridRect(Rect(-1,-1,-1,-1)); gVALFontSize := 8; //DecSeparator := DecimalSeparator; //l64rBufP := nil; gEnterCell := false; gVALChanges := false; DataGrid.ColCount := 9; DataGrid.RowCount := 15; FormResize(nil); {$IFDEF Darwin} {$IFNDEF LCLgtk} //only for Carbon compile New1.ShortCut := ShortCut(Word('N'), [ssMeta]); Open1.ShortCut := ShortCut(Word('O'), [ssMeta]); Save1.ShortCut := ShortCut(Word('S'), [ssMeta]); Quit1.ShortCut := ShortCut(Word('W'), [ssMeta]); Copy1.ShortCut := ShortCut(Word('C'), [ssMeta]); Paste1.ShortCut := ShortCut(Word('V'), [ssMeta]); Selectall1.ShortCut := ShortCut(Word('A'), [ssMeta]); DescriptiveMenu.ShortCut := ShortCut(Word('L'), [ssMeta]); {$ENDIF}//Carbon {$ENDIF}//Darwin end; procedure TSpreadForm.DataGridMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var C, R : integer ; Rect : TGridRect ; begin DataGrid.MouseToCell( X, Y, C, R ) ; Rect.Left := C ; Rect.Right := C ; Rect.Top := R ; Rect.Bottom := R ; DataGrid.Selection := Rect ; end; procedure TSpreadForm.DataGridKeyPress(Sender: TObject; var Key: Char); var S : string ; begin if (Key in ['0'..'9','.',kBS,kDel,kCR]) or ((Key='-') and (gEnterCell)) then else exit; if(( DataGrid.Selection.Top = DataGrid.Selection.Bottom ) and ( DataGrid.Selection.Left = DataGrid.Selection.Right )) then begin gVALChanges := true; if gEnterCell then begin S := '' end else S := DataGrid.Cells[ DataGrid.Selection.Left,DataGrid.Selection.Top ] ; gEnterCell := false; if ( ( Key = kDEL ) or ( Key = kBS ) )then begin if( length( S ) > 0 ) then begin setlength( S, length( S ) - 1 ) ; end ; end else if ( Key = kCR ) then begin //Edit_Box.Text := S ; exit ; end else begin S := S + Key ; end ; DataGrid.Cells[ DataGrid.Selection.Left, DataGrid.Selection.Top ] := S ; //Format_Grid.Cells[ DataGrid.Selection.Left, DataGrid.Selection.Top ] := '' ; end ; end; procedure TSpreadForm.Copy1Click(Sender: TObject); var C, R : integer ; P: PChar; S : string ; RStart,CStart,REnd,CEnd : integer ; begin // Setup... S := '' ; if (DataGrid.Selection.Left < 0) or (DataGrid.Selection.Top < 0) then begin DataGrid.Selection:= TGridRect(Rect(1,1+kMaxFactors,DataGrid.ColCount-1,DataGrid.RowCount-1)); end; CStart := DataGrid.Selection.Left; CEnd := DataGrid.Selection.Right; RStart := DataGrid.Selection.Top; REnd := DataGrid.Selection.Bottom; // Copy to string for R := RStart to REnd do begin for C := CStart to CEnd do begin S := S + DataGrid.Cells[ C, R ] ; if( C < CEnd ) then begin S := S + #9 ; // Tab end ; end ; S := S + #13#10 ; // End line end ; // Set clipboard {$IFNDEF FPC} Clipboard.SetTextBuf( PChar( S ) ) ; {$ELSE} p:=StrAlloc (length(S)+1); if StrPCopy (P,S)=P then Clipboard.SetTextBuf(P); {$ENDIF} end; procedure TSpreadForm.Paste1Click(Sender: TObject); const BS = #8 ; { Backspace } CR = #13 ; { Carriage return } DEL = #127 ; { Delete } //HT = #9 ; { Horizontal Tab } //LF = #10 ; { Line Feed } //VT = #11 ; { Vertical Tab } var StartC,C, R,I : integer ; Dummy : integer ; lSciNotation,EOF: boolean; lValue: double; DecSeparator : char; Line, S, Work,WorkFilter : string ; begin // Setup... DecSeparator := DecimalSeparator; S := Clipboard.AsText ; EOF:= false; if (DataGrid.Selection.Left < 0) or (DataGrid.Selection.Top < 0) then begin Selectall1Click(nil); end; //gChanges := true; StartC := DataGrid.Selection.Left; R := DataGrid.Selection.Top; C := StartC; while( length( S ) > 0 ) do begin // Extract next line... {$IFDEF UNIX} Dummy := pos( #13, S + #13 ) ; {$ELSE} Dummy := pos( #13#10, S + #13#10 ) ; {$ENDIF} Line := copy( S, 1, Dummy - 1 ) ; if (Dummy+1) < length(S) then //last line may not have eol S := copy( S, Dummy + 1, length( S ) ) else EOF := true; while( length( Line ) > 0 ) do begin // Extract next cell... lSciNotation := false; Dummy := pos( #9, Line + #9 ) ; Work := copy( Line, 1, Dummy - 1 ) ; Line := copy( Line, Dummy + 1, length( S ) ) ; WorkFilter := ''; if length(Work) > 0 then begin for I := length(Work) downto 1 do begin if (Work[i] in ['-','0'..'9','E','e',DecSeparator,BS,DEL,CR]) then WorkFilter := Work[i]+WorkFilter; if (Work[i] in ['E','e']) then lSciNotation := true; end; end; if lSciNotation then begin try lValue := strtofloat(Workfilter); except on EConvertError do lValue := NaN else lValue := NaN; end; //try..except if lValue <> NaN then DataGrid.Cells[ C, R ] :=(floattostr(lValue)); end else if(length(WorkFilter) > 0) and ( C < DataGrid.ColCount ) then begin DataGrid.Cells[ C, R ] := WorkFilter ; //Format_Grid.Cells[ C, R ] := '' ; end ; inc( C ) ; end ; inc( R ) ; // Move to next row if( R >= DataGrid.RowCount ) or (EOF) then begin break ; // All done with paste end ; C := StartC; end ; // While length(S) > 0 end; //proc Paste1Click (*var StartC,C, R,I : integer ; Dummy : integer ; lSciNotation,EOF,lData: boolean; lValue: double; Line, S, Work,WorkFilter : string ; begin // Setup... lValue := 0; //only to prevent compiler warning... S := Clipboard.AsText ; EOF:= false; if (DataGrid.Selection.Left < 0) or (DataGrid.Selection.Top < 0) then begin Selectall1Click(nil); end; //R := 1 ; //StartC := 1 ; StartC := DataGrid.Selection.Left; //CEnd := DataGrid.Selection.Right; R := DataGrid.Selection.Top; //REnd := DataGrid.Selection.Bottom; // Do the paste C := StartC; while( length( S ) > 0 ) do begin // Extract next line... Dummy := pos( #13#10, S + #13#10 ) ; Line := copy( S, 1, Dummy - 1 ) ; if (Dummy+1) < length(S) then //last line may not have eol S := copy( S, Dummy + 1, length( S ) ) else EOF := true; //showmessage(inttostr(C)+'x'+Line); while( length( Line ) > 0 ) do begin // Extract next cell... lSciNotation := false; //old //Dummy := pos( #9, Line + #9 ) ; //new - comma separated, etc lData := false; Dummy := length(line)+1; I := 1; repeat if (Line[i] in ['-','0'..'9','E','e']) then lData := true else begin if lData then Dummy := I; end; inc(I); until (I > length(Line)) or (Dummy = (I-1)); //end new Work := copy( Line, 1, Dummy - 1 ); //showmessage(inttostr(Dummy)+'x'+Work); Line := copy( Line, Dummy + 1, length( S ) ) ; //showmessage(Line); WorkFilter := ''; if length(Work) > 0 then begin for I := length(Work) downto 1 do begin if (Work[i] in ['-','0'..'9','E','e','.',kBS,kDEL,kCR]) then WorkFilter := Work[i]+WorkFilter; if (Work[i] in ['E','e']) then lSciNotation := true; end; end; if lSciNotation then begin try lValue := strtofloat(Workfilter); except on EConvertError do lValue := NaN; end; //try..except if lValue <> NaN then DataGrid.Cells[ C, R ] :=(floattostr(lValue)); end else if(length(WorkFilter) > 0) and ( C < DataGrid.ColCount ) then begin DataGrid.Cells[ C, R ] := WorkFilter ; //Format_Grid.Cells[ C, R ] := '' ; end ; inc( C ) ; end ; inc( R ) ; // Move to next row if( R >= DataGrid.RowCount ) or (EOF) then begin break ; // All done with paste end ; //Showmessage(inttostr(StartC)); C := StartC; end ; // TMainForm.Paste1Click end; *) procedure TSpreadForm.SaveBtnClick(Sender: TObject); var b: boolean; begin Save1Click(b); end; function TSpreadForm.CheckSave2Close (lAllowCancel: boolean): boolean; begin result := true; if not gVALChanges then exit; result := false; if lAllowCancel then begin case MessageDlg( 'Save changes?', mtWarning, [mbYes, mbNo, mbCancel], 0 ) of mrYes : begin Save1Click( result ) ; end ; mrCancel : exit ; end ; end else case MessageDlg( 'Save changes?', mtWarning, [mbYes, mbNo], 0 ) of mrYes : begin Save1Click( result ) ; end ; end; result := true; end; procedure TSpreadForm.ReadCells2Buffer; var lDbl: double; lRend,lRStart,lCStart,lCEnd,lC,lR,lPos: integer; lStr: string; l64rBufP: pointer; l64rBuf: DoubleP; begin //if l64rBufP <> nil then // freemem(l64rBufP); GetMem(l64rBufP,(DataGrid.ColCount*DataGrid.RowCount*sizeof(double))+16); {$IFDEF FPC} l64rBuf := alignx(l64rBufP, 16); {$ELSE} l64rBuf := DoubleP((integer(l64rBufP) and $FFFFFFF0)+16); {$ENDIF} lRStart := {1}kMaxFactors+1; lREnd := DataGrid.RowCount - 1; lCstart := 1; lCend := DataGrid.ColCount - 1; //gnCol := lCEnd; //gnRow := lREnd-lRStart+1; // Copy to string lPos := 0; for lR := lRStart to lREnd do begin for lC := lCStart to lCEnd do begin inc(lPos); lStr := (DataGrid.Cells[ lC, lR ]); lDbl := NaN; if length(lStr) > 0 then begin try lDbl := Strtofloat(lStr); except on EConvertError do begin showmessage('Cell '+ColLabel(lC)+inttostr(lR-kMaxFactors)+ ': Unable to convert the string '+lStr+' to a number'); DataGrid.Cells[ lC, lR ] := ''; lDbl := NaN; //NAN? Not-A-Number end; //Error end; //except end; //length > 0 l64rBuf^[lPos] :=lDbl; end ; //for each col end ; //for each row freemem(l64rBufP); end; procedure TSpreadForm.Selectall1Click(Sender: TObject); begin DataGrid.Selection:= TGridRect(Rect(1,1+kMaxFactors,DataGrid.ColCount-1,DataGrid.RowCount-1)); end; procedure TSpreadForm.FontSizeChange(Sender: TObject); begin (sender as TMenuItem).Checked := true; gVALFontSize := (sender as TMenuItem).tag; DataGrid.Font.Size := (sender as TMenuItem).tag; DataGrid.DefaultRowHeight := (sender as TMenuItem).tag+12; FormResize(nil); end; procedure TSpreadForm.DataGridMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin ShowStatus; end; procedure TSpreadForm.DataGridDrawCell(Sender: TObject; Col, Row: Integer; Rect: TRect; State: TGridDrawState); begin ShowStatus; end; procedure TSpreadForm.Clearallcells1Click(Sender: TObject); var lR,lC,lRi,lCi: integer; begin lR := DataGrid.RowCount-1; lC := DataGrid.ColCount-1; for lRi := 1 to lR do begin for lCi := 1 to lC do begin DataGrid.Cells[lCi,kMaxFactors+lRi] := ''; end;//for cols end;//for rows end; procedure TSpreadForm.DesignBtnClick(Sender: TObject); begin DesignForm.Showmodal; gDesignUnspecified := false; DesignBtnLabelUpdate; end; procedure TSpreadForm.AddMRIScansClick(Sender: TObject); begin DesignForm.AddMRIBtnClick(nil); end; function TSpreadForm.GetVal (lC,lR: integer; var lVal: double): boolean; var lStr: string; lDbl: double; begin result := false; lVal := 0; lStr := (DataGrid.Cells[ lC, lR ]); if lStr = '' then exit; try lDbl := Strtofloat(lStr); except on EConvertError do begin showmessage('Cell '+ColLabel(lC)+inttostr(lR-kMaxFactors)+ ': Unable to convert the string '+lStr+' to a number'); exit; end; end; //try..except lVal := lDbl; result := true; end;//GetVal procedure TSpreadForm.DescriptiveClick(Sender: TObject); var lMn,lSD,lSE,lSkew,lZSkew: double; n,lR,lC,lRi,lCi: integer; lVal: double; RA: SingleP; begin lR := DataGrid.RowCount-1; if (lR <= kMaxFactors+1) then exit; lC := DataGrid.ColCount-1; Getmem(RA,lR * sizeof(single)); for lCi := 1 to lC do begin n := 0; for lRi := (kMaxFactors+1) to lR do begin if GetVal (lCi,lRi,lVal) then begin inc(n); RA^[n] := lVal; end; end;//for rows if n > 0 then begin SuperDescriptive (RA, n, lMn,lSD,lSE,lSkew,lZSkew); Showmessage('"'+DataGrid.Cells[ lC, 0]+'" mean='+floattostr(lMn)+',StDev='+floattostr(lSD)+',StEr='+floattostr(lSE)+',Skew='+floattostr(lSkew)+',ZSkew='+floattostr(lZSkew)); end; //n > 0 end;//for cols Freemem(RA); end; {$IFNDEF FPC} procedure TSpreadForm.FormClose(Sender: TObject; var Action: TCloseAction); {$ELSE} procedure TSpreadForm.FormClose(Sender: TObject); {$ENDIF} begin CheckSave2Close(false); end; {$IFDEF FPC} initialization {$I spread.lrs} {$ENDIF} end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/fpc-res.res����������������������������������������������������0000755�0001750�0001750�00000001764�11316122230�017046� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ �����������������������<���L����L�A�Z�_�P�I�C�_�D�I�A�L�O�G�_�T�E�M�P�L�A�T�E�������0�����������T���������,���������P����������_S�T�A�T�I�C��������� ��������� ��������(��� ���@�����������������������������������������������������������������������3wywwywwwwww������������������������wwww���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������0����M�A�I�N�I�C�O�N��������� ������������ ������������������mricron-0.20140804.1~dfsg.1.orig/npm/nifti_img.pas��������������������������������������������������0000755�0001750�0001750�00000045124�12306422720�017453� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit nifti_img; interface {$Include ..\common\isgui.inc} uses hdr,define_types,Classes,nifti_hdr,sysutils,dialogsx, unpm, nifti_types {$IFDEF FPC},gzio2 {$ELSE} ,gziod {$ENDIF} ; {$H+} function LoadImg(lInName: string; lImgData: SingleP; lStart, lEnd,linvox_offset,lRApos,lDataType,lVolVox: integer): boolean; function LoadImg8(lInName: string; lImgData: ByteP; lStart, lEnd,linvox_offset,lRApos,lDataType,lVolVox: integer): boolean; implementation function LoadImg(lInName: string; lImgData: SingleP; lStart, lEnd,linvox_offset,lRApos,lDataType,lVolVox: integer): boolean; var lvox_offset,lInc,lFSize,lP2: integer; lFData: file; lImgName: string; lByteP: ByteP; lSmallIntP: SmallIntP; lV,lMin,lMax: single; begin result := false; if (lStart >= lEnd) or (lStart < 1) or (lEnd < 1) then begin NPMmsg('Error: LoadImg '+inttostr(lStart)+'>='+inttostr(lEnd)+' or zero'); exit; end; if Files4D(lInName) then begin lImgName := Filename4D(lInName); lP2 := BPP (lDataType); if lP2 = 0 then begin ShowMsg(lImgName +' is an unsupported file type'); exit; end; lvox_offset := linvox_offset+ ((Vol4D(lInName)-1)* (lP2 * lVolVox)); end else begin lImgName := lInName; lvox_offset := linvox_offset; end; if UpCaseExt(lImgName) = '.HDR' then lImgName := changefileext(lImgName,'.img'); lFSize := FSize(lImgName); if (not GzExt(lImgName)) and (lFSize < (lEnd+ lvox_offset)) then begin NPMmsg('Error: LoadImg '+lImgName+' FSize = '+inttostr(lFSize)+' Expected '+inttostr(lEnd+ lvox_offset)); exit; end; filemode := 0; if GzExt(lImgName) then begin if lDataType = kDT_UNSIGNED_CHAR then begin getmem(lByteP, (lEnd+1)-lStart); UnGZip(lImgName,lByteP,lvox_offset+lStart-1,(lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lByteP^[lInc]; freemem(lByteP); end else if (lDataType = kDT_SIGNED_SHORT) then begin //getmem(lSmallIntP, sizeof(smallint)* ((lEnd+1)-lStart)); getmem(lByteP, ((lEnd+1)-lStart)*sizeof(smallint)); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(smallint)),((lEnd+1)-lStart)*sizeof(smallint)); for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*2)+1 ; lImgData^[lRApos+lInc-1] := makesmallint(lByteP^[lP2],lByteP^[lP2+1]); end; freemem(lByteP); end else if (lDataType = kDT_SIGNED_INT) or (lDataType = kDT_FLOAT) then begin lByteP := ByteP(@lImgData^[lRApos]); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(single)),((lEnd+1)-lStart)*sizeof(single)); (*getmem(lByteP, ((lEnd+1)-lStart)*sizeof(single)); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(single)),((lEnd+1)-lStart)*sizeof(single)); for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*4)+1 ; lImgData^[lRApos+lInc-1] := makesingle(lByteP^[lP2],lByteP^[lP2+1],lByteP^[lP2+2],lByteP^[lP2+3]); //lImgData^[lRApos+lInc-1] := makesingle(lByteP^[lP2+3],lByteP^[lP2+2],lByteP^[lP2+1],lByteP^[lP2]); end; freemem(lByteP); *) //test range (*lINc := 1; lMin := lImgData^[lRApos+lInc-1]; lMax := lMin; for lInc := 1 to ((lEnd+1)-lStart) do begin lV := lImgData^[lRApos+lInc-1]; if lV > lMax then lMax := lV; if lV < lMin then lMin := lMax; end; MainForm.NPMmsg(inttostr(lvox_offset)+' '+realtostr(lMin,8)+' '+realtostr(lMax,8)); *) //end if lDataType = kDT_SIGNED_INT then begin for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := conv4r4i (lImgData^[lRApos+lInc-1]); end else begin for lInc := 1 to ((lEnd+1)-lStart) do if specialsingle(lImgData^[lRApos+lInc-1])then lImgData^[lRApos+lInc-1] := 0; end; end else begin ShowMsg(lImgName + ' is an unsupported compressed data type '+inttostr(lDataType)); exit; end; end else begin assignfile(lFdata,lImgName); if lDataType = kDT_UNSIGNED_CHAR then begin getmem(lByteP, (lEnd+1)-lStart); reset(lFdata,1); //12/2010 seek(lFdata,lvox_offset+lStart-1); BlockRead(lFdata, lByteP^, (lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lByteP^[lInc]; freemem(lByteP); end else if (lDataType = kDT_SIGNED_SHORT) then begin getmem(lSmallIntP, sizeof(smallint)* ((lEnd+1)-lStart)); reset(lFdata,2); if (lvox_offset mod 2) <> 0 then begin ShowMsg('Error: this software can only read headers with dataoffsets that are divisible by 4.'); end; seek(lFdata,(lvox_offset div 2)+ (lStart-1)); BlockRead(lFdata, lSmallIntP^, (lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lSmallIntP^[lInc]; freemem(lSmallIntP); end else if (lDataType = kDT_SIGNED_INT) or (lDataType = kDT_FLOAT) then begin //next: 4 byte data reset(lFdata,4); if (lvox_offset mod 4) <> 0 then begin ShowMsg('Error: this software can only read headers with dataoffsets that are divisible by 4.'); end; seek(lFdata,(lvox_offset div 4)+ (lStart-1) ); BlockRead(lFdata, lImgData[lRApos], (lEnd+1)-lStart); if lDataType = kDT_SIGNED_INT then begin for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := conv4r4i (lImgData^[lRApos+lInc-1]); end else begin for lInc := 1 to ((lEnd+1)-lStart) do if specialsingle(lImgData^[lRApos+lInc-1]) then lImgData^[lRApos+lInc-1] := 0; end; end else ShowMsg('Unsupported COMPRESSED data type '+inttostr(lDataType)); closefile(lFdata); end; //not gz result := true; end; (*function LoadImgx(lInName: string; lImgData: SingleP; lStart, lEnd,linvox_offset,lRApos,lDataType,lVolVox: integer): boolean; var lvox_offset,lInc,lFSize,lP2: integer; lFData: file; lImgName: string; lByteP: ByteP; lSmallIntP: SmallIntP; lV,lMin,lMax: single; begin result := false; if (lStart >= lEnd) or (lStart < 1) or (lEnd < 1) then begin MainForm.NPMmsg('Error: LoadImg '+inttostr(lStart)+'>='+inttostr(lEnd)+' or zero'); exit; end; if Files4D(lInName) then begin lImgName := Filename4D(lInName); lP2 := BPP (lDataType); if lP2 = 0 then begin ShowMsg(lImgName +' is an unsupported file type'); exit; end; lvox_offset := linvox_offset+ ((Vol4D(lInName)-1)* (lP2 * lVolVox)); end else begin lImgName := lInName; lvox_offset := linvox_offset; end; if UpCaseExt(lImgName) = '.HDR' then lImgName := changefileext(lImgName,'.img'); lFSize := FSize(lImgName); if (not GzExt(lImgName)) and (lFSize < (lEnd+ lvox_offset)) then begin MainForm.NPMmsg('Error: LoadImg '+lImgName+' FSize = '+inttostr(lFSize)+' Expected '+inttostr(lEnd+ lvox_offset)); exit; end; filemode := 0; if GzExt(lImgName) then begin if lDataType = kDT_UNSIGNED_CHAR then begin getmem(lByteP, (lEnd+1)-lStart); UnGZip(lImgName,lByteP,lvox_offset+lStart-1,(lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lByteP^[lInc]; freemem(lByteP); end else if (lDataType = kDT_SIGNED_SHORT) then begin //getmem(lSmallIntP, sizeof(smallint)* ((lEnd+1)-lStart)); getmem(lByteP, ((lEnd+1)-lStart)*sizeof(smallint)); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(smallint)),((lEnd+1)-lStart)*sizeof(smallint)); for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*2)+1 ; lImgData^[lRApos+lInc-1] := makesmallint(lByteP^[lP2],lByteP^[lP2+1]); end; freemem(lByteP); end else if (lDataType = kDT_SIGNED_INT) or (lDataType = kDT_FLOAT) then begin lByteP := ByteP(@lImgData^[lRApos]); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(single)),((lEnd+1)-lStart)*sizeof(single)); {getmem(lByteP, ((lEnd+1)-lStart)*sizeof(single)); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(single)),((lEnd+1)-lStart)*sizeof(single)); for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*4)+1 ; lImgData^[lRApos+lInc-1] := makesingle(lByteP^[lP2],lByteP^[lP2+1],lByteP^[lP2+2],lByteP^[lP2+3]); //lImgData^[lRApos+lInc-1] := makesingle(lByteP^[lP2+3],lByteP^[lP2+2],lByteP^[lP2+1],lByteP^[lP2]); end; freemem(lByteP);} //test range {lINc := 1; lMin := lImgData^[lRApos+lInc-1]; lMax := lMin; for lInc := 1 to ((lEnd+1)-lStart) do begin lV := lImgData^[lRApos+lInc-1]; if lV > lMax then lMax := lV; if lV < lMin then lMin := lMax; end; MainForm.NPMmsg(inttostr(lvox_offset)+' '+realtostr(lMin,8)+' '+realtostr(lMax,8)); } //end if lDataType = kDT_SIGNED_INT then begin for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := conv4r4i (lImgData^[lRApos+lInc-1]); end else begin for lInc := 1 to ((lEnd+1)-lStart) do if specialsingle(lImgData^[lRApos+lInc-1])then lImgData^[lRApos+lInc-1] := 0; end; end else begin ShowMsg(lImgName + ' is an unsupported compressed data type '+inttostr(lDataType)); exit; end; end else begin assignfile(lFdata,lImgName); if lDataType = kDT_UNSIGNED_CHAR then begin getmem(lByteP, (lEnd+1)-lStart); reset(lFdata,1); seek(lFdata,lvox_offset+lStart-1); BlockRead(lFdata, lByteP^, (lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lByteP^[lInc]; freemem(lByteP); end else if (lDataType = kDT_SIGNED_SHORT) then begin getmem(lSmallIntP, sizeof(smallint)* ((lEnd+1)-lStart)); reset(lFdata,2); if (lvox_offset mod 2) <> 0 then begin ShowMsg('Error: this software can only read headers with dataoffsets that are divisible by 4.'); end; seek(lFdata,(lvox_offset div 2)+ (lStart-1)); BlockRead(lFdata, lSmallIntP^, (lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lSmallIntP^[lInc]; freemem(lSmallIntP); end else if (lDataType = kDT_SIGNED_INT) or (lDataType = kDT_FLOAT) then begin //next: 4 byte data reset(lFdata,4); if (lvox_offset mod 4) <> 0 then begin ShowMsg('Error: this software can only read headers with dataoffsets that are divisible by 4.'); end; seek(lFdata,(lvox_offset div 4)+ (lStart-1) ); BlockRead(lFdata, lImgData[lRApos], (lEnd+1)-lStart); if lDataType = kDT_SIGNED_INT then begin for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := conv4r4i (lImgData^[lRApos+lInc-1]); end else begin for lInc := 1 to ((lEnd+1)-lStart) do if specialsingle(lImgData^[lRApos+lInc-1]) then lImgData^[lRApos+lInc-1] := 0; end; end else ShowMsg('Unsupported COMPRESSED data type '+inttostr(lDataType)); closefile(lFdata); end; //not gz result := true; end; *) function LoadImg8(lInName: string; lImgData: ByteP; lStart, lEnd,linvox_offset,lRApos,lDataType,lVolVox: integer): boolean; //loads BINARY data - ignore scaling: zero or not zero var lvox_offset,lInc,lFSize,lP2: integer; lFData: file; lImgName: string; lByteP: ByteP; lSmallIntP: SmallIntP; lSingle: single; begin result := false; if (lStart >= lEnd) or (lStart < 1) or (lEnd < 1) then begin NPMmsg('Error: LoadImg '+inttostr(lStart)+'>='+inttostr(lEnd)+' or zero'); exit; end; if Files4D(lInName) then begin lImgName := Filename4D(lInName); lP2 := BPP (lDataType); if lP2 = 0 then begin ShowMsg(lImgName +' is an unsupported file type'); exit; end; lvox_offset := linvox_offset+ ((Vol4D(lInName)-1)* (lP2 * lVolVox)); end else begin lImgName := lInName; lvox_offset := linvox_offset; end; if UpCaseExt(lImgName) = '.HDR' then lImgName := changefileext(lImgName,'.img'); lFSize := FSize(lImgName); if (not GzExt(lImgName)) and (lFSize < (lEnd+ lvox_offset)) then begin NPMmsg('Error: LoadImg '+lImgName+' FSize = '+inttostr(lFSize)+' Expected '+inttostr(lEnd+ lvox_offset)); exit; end; filemode := 0; //zero array for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := 0;//makesingle(lByteP^[lP2],lByteP^[lP2+1],lByteP^[lP2+2],lByteP^[lP2+3]); if GzExt(lImgName) then begin if lDataType = kDT_UNSIGNED_CHAR then begin getmem(lByteP, (lEnd+1)-lStart); UnGZip(lImgName,lByteP,lvox_offset+lStart-1,(lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lByteP^[lInc]; freemem(lByteP); end else if (lDataType = kDT_SIGNED_SHORT) then begin //getmem(lSmallIntP, sizeof(smallint)* ((lEnd+1)-lStart)); getmem(lByteP, ((lEnd+1)-lStart)*sizeof(smallint)); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(smallint)),((lEnd+1)-lStart)*sizeof(smallint)); for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*2)+1 ; lImgData^[lRApos+lInc-1] := makesmallint(lByteP^[lP2],lByteP^[lP2+1]); end; freemem(lByteP); end else if (lDataType = kDT_SIGNED_INT) or (lDataType = kDT_FLOAT) then begin getmem(lByteP, ((lEnd+1)-lStart)*sizeof(single)); UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(single)),((lEnd+1)-lStart)*sizeof(single)); if lDataType = kDT_SIGNED_INT then begin for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*4)+1 ; lSingle := conv4r4i (makesingle(lByteP^[lP2],lByteP^[lP2+1],lByteP^[lP2+2],lByteP^[lP2+3])); if lSingle <> 0 then lImgData^[lRApos+lInc-1] := 1; end; end else begin //32 bit float for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*4)+1 ; lSingle := makesingle(lByteP^[lP2],lByteP^[lP2+1],lByteP^[lP2+2],lByteP^[lP2+3]); if (not specialsingle(lSingle)) and (lSingle <> 0) then lImgData^[lRApos+lInc-1] := 1; end; end; freemem(lByteP); end else begin ShowMsg(lImgName + ' is an unsupported compressed data type '+inttostr(lDataType)); exit; end; end else begin assignfile(lFdata,lImgName); if lDataType = kDT_UNSIGNED_CHAR then begin getmem(lByteP, (lEnd+1)-lStart); reset(lFdata,1); seek(lFdata,lvox_offset+lStart-1); BlockRead(lFdata, lByteP^, (lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lByteP^[lInc]; freemem(lByteP); end else if (lDataType = kDT_SIGNED_SHORT) then begin getmem(lSmallIntP, sizeof(smallint)* ((lEnd+1)-lStart)); reset(lFdata,2); if (lvox_offset mod 2) <> 0 then begin ShowMsg('Error: this software can only read headers with dataoffsets that are divisible by 4.'); end; seek(lFdata,(lvox_offset div 2)+ (lStart-1)); BlockRead(lFdata, lSmallIntP^, (lEnd+1)-lStart); for lInc := 1 to ((lEnd+1)-lStart) do lImgData^[lRApos+lInc-1] := lSmallIntP^[lInc]; freemem(lSmallIntP); end else if (lDataType = kDT_SIGNED_INT) or (lDataType = kDT_FLOAT) then begin //next: 4 byte data reset(lFdata,4); if (lvox_offset mod 4) <> 0 then begin ShowMsg('Error: this software can only read headers with dataoffsets that are divisible by 4.'); end; seek(lFdata,(lvox_offset div 4)+ (lStart-1) ); getmem(lByteP, ((lEnd+1)-lStart)*sizeof(single)); //fx(((lEnd+1)-lStart)*sizeof(single)); BlockRead(lFdata, lByteP^, ((lEnd+1)-lStart)); //April 2009 //UnGZip(lImgName,lByteP,lvox_offset+((lStart-1)*sizeof(single)),((lEnd+1)-lStart)*sizeof(single)); if lDataType = kDT_SIGNED_INT then begin for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*4)+1 ; lSingle := conv4r4i (makesingle(lByteP^[lP2],lByteP^[lP2+1],lByteP^[lP2+2],lByteP^[lP2+3])); if lSingle <> 0 then lImgData^[lRApos+lInc-1] := 1; end; end else begin for lInc := 1 to ((lEnd+1)-lStart) do begin lP2 := ((lInc-1)*4)+1 ; lSingle := makesingle(lByteP^[lP2],lByteP^[lP2+1],lByteP^[lP2+2],lByteP^[lP2+3]); if (not specialsingle(lSingle)) and (lSingle <> 0) then lImgData^[lRApos+lInc-1] := 1; end; end; freemem(lByteP); end else ShowMsg('Unsupported COMPRESSED data type '+inttostr(lDataType)); closefile(lFdata); end; //not gz result := true; end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/firthThds.pas��������������������������������������������������0000755�0001750�0001750�00000051721�12204475222�017447� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit firthThds; //Unit for running penalized multiple logistic regression //creates multiple threads //Requires firth interface {$Include ..\common\isgui.inc} uses //ComCtrls,Graphics, ExtCtrls, {$IFDEF GUI}ComCtrls, {$ENDIF} Classes, define_types,{stats,}StatThdsUtil,lesion_pattern,Mat,Math,Distr,Vector,dialogsx,Forms,SysUtils; type TMultiRegThread = class(TThread) private finalloglik: SingleP0; KxKA1,KxKB1,KxKA,KxKB :TMatrix; Kvec,Kvec1 : TVector; Kveci,kVeci1 : TVectori; betak,xbeta,y,pi,ustar, XXx,XXXW2,XXFisher,XXcovs,XXXWPrime, deltahalfs,deltat,delta,covs,x,Fisher,XW2,W,XWprime,Hprime,H,ustarmat,negx: TMatrix; lBarX: TProgressBar; lFormX: TForm; lShowProgressX: boolean; lnCondx,lnCritx,lBarPosX,lTestPosX, lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx,lImagesCountx : integer; lPlankImgx: byteP;lOutImgMnx,lSymptomRAx: SingleP; lOutImgX: SingleRAp; //lBarX: TProgressBar; procedure DoVisualSwap; protected procedure Execute; override; procedure VisualProg(lPos,lTestNumber: Integer); procedure Analyze(lnCond,lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: bytep;lOutImgMn,lSymptomRA: SingleP; lOutImg: SingleRAp); virtual; abstract; public constructor Create(lShowProgress: boolean; lForm: TForm; lBar: TProgressBar; lnCond,lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: byteP;lOutImgMn,lSymptomRA: SingleP; lOutImg: SingleRAp); end; TFirthThreadStat = class(TMultiRegThread ) protected procedure Analyze(lnCond,lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: bytep;lOutImgMn,lSymptomRA: SingleP; lOutImg: SingleRAp); override; procedure logistfx (xin: SingleP; var lZvals: SingleP0; numSubj,numCond: integer; lComputeIntercept: boolean); end; implementation procedure TMultiRegThread .DoVisualSwap; begin lBarX.Position := lBarPosX; lFormX.Caption := inttostr(lTestPosX); end; procedure TMultiRegThread.VisualProg(lPos,lTestNumber: Integer); begin lBarPosX := lPos; lTestPosX := lTestNumber; //NPMTitleMsg(inttostr(lTestNumber)); {$IFDEF FPC}Synchronize(@DoVisualSwap); {$ELSE} Synchronize(DoVisualSwap);{$ENDIF} end; constructor TMultiRegThread.Create(lShowProgress: boolean; lForm: TForm; lBar: TProgressBar; lnCond,lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: bytep;lOutImgMn,lSymptomRA: SingleP;lOutImg: SingleRAp); begin lShowProgressX := lShowProgress; lBarX := lBar; lFormX := lForm; lThreadX := lThread; lThreadStartX := lThreadStart; lThreadEndX := lThreadEnd; lStartVoxx := lStartVox; lVoxPerPlankx := lVoxPerPlank; lImagesCountX := lImagesCount; lPlankImgx := lPlankImg; lOutImgMnx := lOutImgMn; lOutImgX := lOutImg; lSymptomRAx := lSymptomRA; lnPermuteX := lnPermute; lnCritX := lnCrit; lnCondX := lnCond; FreeOnTerminate := True; inherited Create(False); end; { The Execute method is called when the thread starts } procedure TMultiRegThread .Execute; begin Analyze(lnCondX,lnCritX,lnPermuteX,lThreadx,lThreadStartx,lThreadEndx,lStartVoxx,lVoxPerPlankx,lImagesCountx,lPlankImgX,lOutImgMnx,lSymptomRAx,lOutImgX); end; procedure TFirthThreadStat.logistfx (xin: SingleP; var lZvals: SingleP0; numSubj,numCond: integer; lComputeIntercept: boolean); //todo zero output incase exit //yin = 1..numSubj binary 0/1 values //xin = numSubj*numCond predictors //Chivals = 0..numCond p-values - the 0th Khi-value is the intercept // [0th value will not be computed if ; lComputeIntercept= false] label 123,666; const maxit = 25; maxhs = 5; epsilon = 0.0001; maxstep = 10; var SumY0,SumY1,mx, beta0,loglik,loglikold: double; sumy, n, i,j, k, iter,halfs,lCond,dropCond: integer; variability,firth: boolean; procedure crossprodustar; var inc,row: integer; begin for row := 1 to k do begin ustarmat[row,1] := 0; for inc := 1 to ustar.r do ustarmat[row,1] := ustarmat[row,1] + (x[row,inc]*ustar[inc,1]); end; end; procedure Diag2Vec; var inc: integer; begin for inc := 1 to pi.r do ustar[inc,1] := ustar[inc,1]+ H[inc,inc]*(0.5-pi[inc,1]); end; //nested DiagP2 procedure DiagP2 (var W, P: TMatrix); var inc: integer; begin W.Zero; for inc := 1 to P.r do W[inc,inc] := Power((P[inc,1] * (1-P[inc,1])),0.5) ; end; //nested DiagP2 procedure ComputeFisher; begin DiagP2(W,pi); XW2.mult(x,W); //XWPrime.copy( XW2); //XWPrime.transpose; XWPrime.transpose(XW2); Fisher.mult(XW2,XWPrime); covs.copy( Fisher); covs.Invert2(KxKA,KxKB,Kvec,Kveci) end; //nested computeFisher procedure computedropdelta; var jinc,iinc,ii,jj: integer; begin DiagP2(W,pi); XXXW2.mult(XXx,W); //XXXWPrime.copy( XXXW2); //XXXWPrime.transpose; XXXWPrime.transpose(XXXW2); XXFisher.mult(XXXW2,XXXWPrime); XXcovs.copy( XXFisher); //XXcovs.Invert; XXcovs.Invert2(KxKA1,KxKB1,Kvec1,Kveci1); covs.Zero; ii := 0; for iinc := 1 to (k) do begin if iinc <> (dropCond+1) then begin //leave the specified column zeros... inc(ii); jj := 0; for jinc := 1 to (k) do begin if jinc <> (dropCond+1) then begin inc(jj); covs[iinc,jinc] := xxCovs[ii,jj]; end; end; end; end; end; function firthpenalty: double; begin ComputeFisher; //result := 0.5 * ln(abs(Fisher.det)); result := 0.5 * ln(abs(Fisher.Det2(KxKA,kVeci,kVec))); end; //nested firthpenalty function ComputeLogLik: double; var inc: integer; begin xbeta.mult(betak,negx); for inc := 1 to n do pi[inc,1] := (1/(1 + exp( xbeta[inc,1]))); result := 0; for inc := 1 to n do if y[inc,1] = 1 then result := result+ln(pi[inc,1]); for inc := 1 to n do if y[inc,1] = 0 then result := result+ln(1-pi[inc,1]); if firth then result := result + firthpenalty; end;//nested ComputeLogLik begin for i := 0 to (numCond) do lZVals^[i] := 0; // if (numSubj < 2) or (numCond < 1) then exit; //ensure there is some variability in the input data... variability := false; i := 1; repeat inc(i); if xin^[i] <> xin^[1] then variability := true; until (i= (numSubj*numCond)) or (variability); if not variability then exit; //no variance in the regressors... variability := false; i := 1; repeat inc(i); if y[i,1] <> y[1,1] then variability := true; until (i= (numSubj)) or (variability); if not variability then exit; //no variance in the dependent variable... dropCond := -1; //initially compute full model, then compute effect of removing individual conditions firth := true; n := numSubj; k := numCond + 1; //get memory //beta := TMatrix.Create(n,1); //design our model //first row = 1: ell samples have equal weight for i := 1 to n do x.M[1,i] := 1; //next load model into x iter := 0; for j := 2 to k do for i := 1 to n do begin inc(iter); x.M[j,i] := xin^[iter]; end; //WriteMatrix('Observations',y); //WriteMatrix('Model',x); //negx is just sing-swapped - we will generate this as we use it a lot... for j := 1 to k do for i := 1 to n do begin negx.M[j,i] := -x.M[j,i]; end; //now start computations sumy := 0; for i := 1 to n do sumy := sumy + round(y[i,1]); if (sumy <= 0) or (sumy >= n) then begin //serious error: no variability. This should have been detected earlier in the procedure when yin was tested for variability goto 666; end; beta0 := ln((sumy/n)/(1 - sumy/n));//initial estimate 123: //go here for each dropcond if DropCond >= 0 then begin betak.Ones; betak.mult( 0) //start with a null model... does not really make sense end else begin betak.zero; betak[1,1] := (beta0); end; iter := 0; if DropCond >= 0 then begin //drop one of the factors... if dropCond <> 0 then begin//include intercept for i := 1 to n do XXx.M[1,i] := 1; lCond := 1; end else lCond := 0; for j := 1 to NumCond do begin if j <> DropCond then begin inc(lCond); for i := 1 to n do XXx.M[lCond,i] := x.M[j+1,i]; end; //if j <> dropCond end; end;//if lDropCond >= 0 loglik := ComputeLogLik; repeat inc(iter); ComputeFisher; HPrime.mult(XWPrime,covs); H.mult(HPrime,XW2); //WriteMatrix(covs); ustar.Sub(y,pi); if firth then Diag2Vec; crossprodustar; if dropCond >= 0 then // model with dropped factor computedropdelta; deltat.mult(covs,ustarmat); delta.transpose(deltat); mx := delta.MatAbsMax/MaxStep; if mx > 1 then delta.mult(mx);//scale delta betak.add(delta); loglikold := loglik; halfs := 1; while halfs <= maxhs do begin // Half-Steps //fx(iter,halfs,loglik); loglik := ComputeLogLik; deltahalfs.mult(delta,power(2,-halfs)); betak.sub(deltahalfs); if (loglik > loglikold) then break; inc(halfs); end; if delta.MatAbsMax <= epsilon then break; until (iter >= maxit); //fx(DropCond,loglik); //done with this model - record model fit if DropCond < 0 then finalloglik^[k] := loglik //full model else begin finalloglik^[DropCond] := loglik; //model with a factor removed end; if DropCond < numCond then begin inc(DropCond); if (DropCond = 0) and (not lComputeIntercept) then //only compute intercept model if requested inc(DropCond); goto 123; end; //finally - results //ResultsForm.Memo1.lines.add (inttostr(j)+' cases have Y=0, '+inttostr(n-j)+' cases have Y=1'); if lComputeIntercept then J := 0 else J := 1; for i := J to (k-1) do begin lZVals^[i] := abs(2*(finalloglik^[i]-finalloglik^[k])); //find direction of effect - does a larger value of the IV predict more zeros or ones lZVals^[i] := pNormalInv(ChiSq(lZVals^[i],1)); //we have now computed a Z scores - but Chi is one tailed, so all Z > 0... lets check direction Sumy0 := 0; Sumy1 := 0; for iter := 1 to n do begin if y[iter,1] = 0 then Sumy0 := Sumy0 + x.M[i+1,iter] //+1: M indexed from 1, ZVal indexed from 0 else Sumy1 := Sumy1 + x.M[i+1,iter]; //+1 M indexed from 1 end; //compute means Sumy1 := Sumy1/sumy; Sumy0 := Sumy0/(n-sumy); if Sumy0 < Sumy1 then //negative z-scores: damage here predicts performance is BETTER lZVals^[i] := -lZVals^[i]; end; (*if lComputeIntercept then //intercept is the 0th value lChiVals[0] := abs(2*(finalloglik[0]-finalloglik[k])); for i := 1 to (k-1) do //k-1 as this is indexed from 0 lChiVals[i] := abs(2*(finalloglik[i]-finalloglik[k])); *) 666: end; {Firth penalized logisitic regression} procedure TFirthThreadStat.Analyze(lnCond, lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg: bytep;lOutImgMn,lSymptomRA: SingleP;lOutImg: SingleRAp); //calls logistf (yin,xin: SingleP; var lChivals: SingleP0; numSubj,numCond: integer); label 666; const knPrevPattern = 10; var lPrevPatternRA: array[1..knPrevPattern] of TLesionPattern; lPattern: TLesionPattern; lObs: Bytep; lPrevZVals: array [1..knPrevPattern] of SingleP0; lZVals: SingleP0; lPatternPos,lC,lnLesion,lPosPct,lPos,lPos2,lPos2Offset,lnCritLocal,n,k: integer; begin //statthread lnCritLocal := lnCrit; if lnCritLocal < 1 then lnCritLocal := 1; Getmem(lObs,lImagesCount*sizeof(byte)); Getmem(lZVals,(lnCond+1)*sizeof(single)); for lPos := 1 to knPrevPattern do Getmem(lPrevZVals[lPos],(lnCond+1)*sizeof(single)); n := lImagesCount; k := lnCond + 1; y := TMatrix.Create(n,1); GetMem(finalloglik,(k+1)*sizeof(single));//finalloglik := TVector.Create(k+1); x := TMatrix.Create (k, n); betak:=TMatrix.Create(1,k); covs:=TMatrix.Create(k,k); delta:=TMatrix.Create(1,k); deltahalfs:=TMatrix.Create(1,k); deltat:=TMatrix.Create(k,1); Fisher:=TMatrix.Create(k,k); H:=TMatrix.Create(n,n); HPrime:=TMatrix.Create(n,k); negx:=TMatrix.Create(k,n); pi:=TMatrix.Create(n,1); ustar:=TMatrix.Create(n,1); ustarmat:=TMatrix.create(k,1); W:=TMatrix.Create(n,n); xbeta:=TMatrix.Create(1,n); XW2:=TMatrix.Create(k,n); //XWPrime:=TMatrix.Create(k,n); XWPrime:=TMatrix.Create(n,k); XXcovs:=TMatrix.Create(k-1,k-1); XXFisher:=TMatrix.Create(k-1,k-1); XXx:=TMatrix.Create(k-1,n); XXXW2:=TMatrix.Create(k-1,n); //XXXWPrime:=TMatrix.Create(k-1,n); XXXWPrime := TMatrix.Create ( n, k-1); KxKA := TMatrix.Create(k,k); KxKB := TMatrix.Create(k,k); Kvec := TVector.Create(k); Kveci := TVectori.Create(k); KxKA1 := TMatrix.Create(k-1,k-1); KxKB1 := TMatrix.Create(k-1,k-1); Kvec1 := TVector.Create(k-1); Kveci1 := TVectori.Create(k-1); lPosPct := (lThreadEnd-lThreadStart) div 100; for lPatternPos := 1 to knPrevPattern do lPrevPatternRA[lPatternPos] := EmptyOrder; lPatternPos := 1; for lPos2 := lThreadStart to lThreadEnd do begin if (lShowProgressX) and ( ((lPos2 mod lPosPct) = 0) or ((lPos2 mod 200) = 0) ) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100),lPos2); if Terminated then exit; lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; for lPos := 1 to lImagesCount do begin if lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2] = 0 then begin //no lesion y[lPos,1] := 0; lObs^[lPos] := 0; end else begin //lesion inc(lnLesion); lObs^[lPos] := 1; y[lPos,1] := 1; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCritLocal) and (lnLesion < lImagesCount) then begin lPattern := SetOrderX (lObs,lImagesCount); lPos := 1; while (lPos <= knPrevPattern) and not (SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount)) do inc(lPos); if SameOrder(lPattern,lPrevPatternRA[lPos],lImagesCount) then begin inc(gnVoxTestedRA[lThread]); //logistf(lObs,lSymptomRA, lZvals, lImagesCount,lnCond,false); for lC := 1 to lnCond do lOutImg^[lC]^[lPos2Offset] := lPrevZvals[lPos]^[lC]; end else begin //new pattern - need to compute inc(gnVoxTestedRA[lThread]); logistfx(lSymptomRA, lZvals, lImagesCount,lnCond,false); for lC := 1 to lnCond do lOutImg^[lC]^[lPos2Offset] := lZvals^[lC]; lPrevPatternRA[lPatternPos] := lPattern; for lC := 1 to lnCond do lPrevZVals[lPatternPos]^[lC] := lZvals^[lC]; inc(lPatternPos); if lPatternPos > knPrevPattern then lPatternPos := 1; end; //new pattern end; //nlesion > nCritical end; //for each voxel //gMat := false; 666: freemem(lObs); for lPos := 1 to knPrevPattern do freemem(lPrevZVals[lPos]); freemem(lZVals); y.free; x.free; betak.free; covs.free; delta.free; deltahalfs.free; deltat.free; Fisher.free; H.free; HPrime.free; negx.free; pi.free; ustar.free; ustarmat.Free; W.free; xbeta.free; XW2.free; XWPrime.free; XXcovs.free; XXFisher.free; XXx.free; XXXW2.free; XXXWPrime.free; KxKA.free; KxKB.free; Kvec.free; Kveci.free; KxKA1.free; KxKB1.free; Kvec1.free; Kveci1.free; freemem(finalloglik); end; (* {Firth penalized logisitic regression} procedure TFirthThreadStat .Analyze(lnCond, lnCrit,lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImagesCount : integer; lPlankImg,lOutImgMn,lSymptomRA: SingleP;lOutImg: SingleRAp); //calls logistf (yin,xin: SingleP; var lChivals: SingleP0; numSubj,numCond: integer); var lPattern,lPrevPattern: TLesionPattern; lObs: Singlep; lZVals,lPrevZVals: SingleP0; lC,lnLesion,lPosPct,lPos,lPos2,lPos2Offset,lnCritLocal,n,k: integer; begin //statthread lnCritLocal := lnCrit; if lnCritLocal < 1 then lnCritLocal := 1; Getmem(lObs,lImagesCount*sizeof(single)); Getmem(lZVals,(lnCond+1)*sizeof(single)); Getmem(lPrevZVals,(lnCond+1)*sizeof(single)); n := lImagesCount; k := lnCond + 1; y := TMatrix.Create(n,1); GetMem(finalloglik,(k+1)*sizeof(single));//finalloglik := TVector.Create(k+1); x := TMatrix.Create (k, n); betak:=TMatrix.Create(1,k); covs:=TMatrix.Create(k,k); delta:=TMatrix.Create(1,k); deltahalfs:=TMatrix.Create(1,k); deltat:=TMatrix.Create(k,1); Fisher:=TMatrix.Create(k,k); H:=TMatrix.Create(n,n); HPrime:=TMatrix.Create(n,k); negx:=TMatrix.Create(k,n); pi:=TMatrix.Create(n,1); ustar:=TMatrix.Create(n,1); ustarmat:=TMatrix.create(k,1); W:=TMatrix.Create(n,n); xbeta:=TMatrix.Create(1,n); XW2:=TMatrix.Create(k,n); //XWPrime:=TMatrix.Create(k,n); XWPrime:=TMatrix.Create(n,k); XXcovs:=TMatrix.Create(k-1,k-1); XXFisher:=TMatrix.Create(k-1,k-1); XXx:=TMatrix.Create(k-1,n); XXXW2:=TMatrix.Create(k-1,n); //XXXWPrime:=TMatrix.Create(k-1,n); XXXWPrime := TMatrix.Create ( n, k-1); KxKA := TMatrix.Create(k,k); KxKB := TMatrix.Create(k,k); Kvec := TVector.Create(k); Kveci := TVectori.Create(k); KxKA1 := TMatrix.Create(k-1,k-1); KxKB1 := TMatrix.Create(k-1,k-1); Kvec1 := TVector.Create(k-1); Kveci1 := TVectori.Create(k-1); //gMat := true; lPosPct := (lThreadEnd-lThreadStart) div 100; lPrevPattern := EmptyOrder; for lPos2 := lThreadStart to lThreadEnd do begin if (lThread = 1) and ((lPos2 mod lPosPct) = 0) then VisualProg(round((lPos2/(lThreadEnd-lThreadStart))*100)); if Terminated then exit; //goto 345;//abort lPos2Offset := lPos2+lStartVox-1; lnLesion := 0; for lPos := 1 to lImagesCount do begin if ((gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]) = 0 then begin //no lesion y[lPos,1] := 0; lObs[lPos] := 0; end else begin //lesion inc(lnLesion); lObs[lPos] := 1; y[lPos,1] := 1; //note: lObs indexed from zero! end; end; lOutImgMn^[lPos2Offset] := lnLesion;///lImages.Count; if (lnLesion >= lnCritLocal) and (lnLesion < lImagesCount) then begin lPattern := SetOrder (lObs,lImagesCount); if SameOrder(lPattern,lPrevPattern,lImagesCount) then begin inc(gnVoxTestedRA[lThread]); //logistf(lObs,lSymptomRA, lZvals, lImagesCount,lnCond,false); for lC := 1 to lnCond do lOutImg^[lC]^[lPos2Offset] := lPrevZvals[lC]; end else begin //new pattern - need to compute inc(gnVoxTestedRA[lThread]); logistfx(lSymptomRA, lZvals, lImagesCount,lnCond,false); for lC := 1 to lnCond do lOutImg^[lC]^[lPos2Offset] := lZvals[lC]; end; lPrevPattern := lPattern; for lC := 1 to lnCond do lPrevZVals[lC] := lZvals[lC]; end; end; //for each voxel //gMat := false; freemem(lObs); freemem(lPrevZVals); freemem(lZVals); y.free; x.free; betak.free; covs.free; delta.free; deltahalfs.free; deltat.free; Fisher.free; H.free; HPrime.free; negx.free; pi.free; ustar.free; ustarmat.Free; W.free; xbeta.free; XW2.free; XWPrime.free; XXcovs.free; XXFisher.free; XXx.free; XXXW2.free; XXXWPrime.free; KxKA.free; KxKB.free; Kvec.free; Kveci.free; KxKA1.free; KxKB1.free; Kvec1.free; Kveci1.free; freemem(finalloglik); end; (**) end. �����������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/npm.cfg��������������������������������������������������������0000755�0001750�0001750�00000001132�12306713726�016254� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-$A8 -$B- -$C+ -$D+ -$E- -$F- -$G+ -$H+ -$I+ -$J+ -$K- -$L+ -$M- -$N+ -$O+ -$P+ -$Q- -$R- -$S- -$T- -$U- -$V+ -$W- -$X+ -$YD -$Z1 -cg -AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; -H+ -W+ -M -$M16384,1048576 -K$00400000 -LE"c:\program files (x86)\borland\delphi7\Projects\Bpl" -LN"c:\program files (x86)\borland\delphi7\Projects\Bpl" -U"..\common;..\delphionly;C:\pas\mricron\fpmath" -O"..\common;..\delphionly;C:\pas\mricron\fpmath" -I"..\common;..\delphionly;C:\pas\mricron\fpmath" -R"..\common;..\delphionly;C:\pas\mricron\fpmath" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/design.dfm�����������������������������������������������������0000755�0001750�0001750�00000003262�10653724326�016751� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �TDESIGNFORM�0��TPF0 TDesignForm DesignFormLeft Topf BorderStylebsDialogCaptionDesign ClientHeight� ClientWidthdColor clBtnFace Font.CharsetDEFAULT_CHARSET Font.Color clWindowText Font.Height Font.Name MS Sans Serif Font.Style �OldCreateOrder PositionpoScreenCenterOnCreate FormCreate PixelsPerInch` TextHeight �TLabelLabel4LeftTopWidth/Height Caption Predictors��TLabelLabel5LeftLTopWidthNHeight CaptionPredictor Names��TLabelLabel1LeftTop6Width7Height Caption Participants��TLabel TemplateLabelLeft�ToprWidthJHeight CaptionC:\template.imgVisible��TLabelLabel2Left TopTWidth�Height Caption%Ignore voxels damaged in less than N%��TButtonOKBtnLeftToppWidthKHeightCaptionOK ModalResultTabOrder��� TSpinEditAValLeftTopWidth@Height MaxLengthMaxValuecMinValueTabOrderValueOnChange AValChange�� TStringGrid ALevelNamesLeftJTopWidthHeightColCountDefaultRowHeight FixedCols�RowCount FixedRows�Options goFixedVertLinegoFixedHorzLine goVertLinegoDrawFocusSelected goEditing� ScrollBarsssNoneTabOrderOnEnterALevelNamesEnterOnExitALevelNamesExit�� TCheckBoxLesionCovaryCheckLeft�Top6Width�HeightCaption"Automatically Covary Lesion VolumeTabOrderVisible��TButton AddMRIBtnLeftHTop0Width�HeightCaption Select ImagesTabOrderOnClickAddMRIBtnClick��TButton TemplateBtnLeftToplWidth�HeightCaptionSelect TemplateTabOrderVisibleOnClickTemplateBtnClick�� TSpinEdit CritPctEditLeft�TopNWidth@Height MaxLengthMaxValuedMinValue�TabOrderValue�OnChange AValChange�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/overlap.pas����������������������������������������������������0000755�0001750�0001750�00000040553�12156372432�017166� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit overlap; {$H+} {$Include ..\common\isgui.inc} interface uses // Graphics, Controls, Forms, StdCtrls, ComCtrls,ExtCtrls, Classes,nifti_hdr,define_types,SysUtils,dialogsx, StatThdsUtil,Brunner,nifti_img,lesion_pattern, unpm; Type OverlapRA = array [1..1] of TLesionPattern;//Toverlap; Overlapp = ^OverlapRA; function CountOverlap (var lImages: TStrings; lMinDeficits,lnVoxTested: integer): integer; procedure EvaluatePower(var lFilenames: TStrings; lOverlapInc,lOverlapMax,lReps,lPct: integer); function CountOverlap2(var lImages: TStrings; lMinDeficits, lnVoxTested: integer; lPlankImg: bytep): integer; implementation function SelectFiles (var lIn,lOut: TStrings; lN: integer): boolean; //select (without replacement) lN filenames from the population lIn var lnFound,lTrial,lRan,lSwap: integer; lRandRA: longintP; begin result := false; lnFound := lIn.count; if (lnFound < lN) then exit; //not enough items found getmem(lRandRA,lnFound*sizeof(longint)); for lTrial := 1 to lnFound do lRandRA^[lTrial] := lTrial-1; //index to each strong for lTrial := lnFound downto 2 do begin //jumble order lRan := random(lTrial)+1; lSwap := lRandRA^[lTrial]; lRandRA^[lTrial] := lRandRA^[lRan]; lRandRA^[lRan] := lSwap; end; for lTrial := 1 to lN do lOut.Add(lIn[lRandRA^[lTrial]]); freemem(lRandRA); result := true; end; procedure EvaluatePower(var lFilenames: TStrings; lOverlapInc,lOverlapMax,lReps,lPct: integer); label 666; var lG: TStrings; lSize,lRep: integer; begin if (lReps < 1) or (lOverlapMax < 1) or (lOverlapInc < 1) or (lOverlapMax > lFilenames.count) or (lOverlapInc > lOverlapMax) then begin ShowMsg('Error with EvaluatePower inputs...'); exit; end; NPMMsgClear; //MainForm.NPMmsg(kVers); randomize; NPMmsg('Power Analysis began = ' +TimeToStr(Now)); lSize := lOverlapInc; while lSize <= lOverlapMax do begin for lRep := 1 to lReps do begin lG:= TStringList.Create; if not SelectFiles(lFilenames,lG,lSize) then begin ShowMsg('Error selecting '+inttostr(lSize)+'files!'); goto 666; end; CountOverlap(lG, round((lPct/100)*lSize),-1 ); lG.Free; end; //for lLoop lSize := lSize + lOverlapInc; end; //for lRep NPMmsg('Analysis finished = ' +TimeToStr(Now)); exit; 666: //there has been a critical failure! lG.Free; end; (*function SelectFiles (lN: integer; var lOut: TStrings): boolean; var lnFound,lTrial,lRan,lSwap: integer; lMaskExt,lFilePath: string; lSearchRec: TSearchRec; lF: TStrings; lRandRA: longintP; begin result := false; lF:= TStringList.Create; lFilepath := 'C:\140\'; lMaskExt := '*.voi'; if FindFirst(lFilePath{+PathDelim}+lMaskExt, faAnyFile-faSysFile-faDirectory, lSearchRec) = 0 then begin repeat lF.add(lFilePath+lSearchRec.Name); until (FindNext(lSearchRec) <> 0); end; lnFound := lF.count; if (lnFound < lN) then begin lF.free; exit; end; //not enough items found getmem(lRandRA,lnFound*sizeof(longint)); for lTrial := 1 to lnFound do lRandRA[lTrial] := lTrial-1; //index to each strong for lTrial := lnFound downto 2 do begin //jumble order lRan := random(lTrial)+1; lSwap := lRandRA[lTrial]; lRandRA[lTrial] := lRandRA[lRan]; lRandRA[lRan] := lSwap; end; for lTrial := 1 to lN do lOut.Add(lF[lRandRA[lTrial]]); freemem(lRandRA); lF.Free; result := true; end; procedure EvaluatePower; label 666; var lG: TStrings; lMaskname: string; lMaskHdr: TMRIcroHdr; lMaskVoxels,lN,lLoop,lRep: integer; begin MainForm.NPMMsgClear; //MainForm.NPMmsg(kVers); randomize; MainForm.NPMmsg('Power Analysis began = ' +TimeToStr(Now)); for lRep := 7 to 10 do begin for lLoop := 1 to 10 do begin lN := lRep * 10; lG:= TStringList.Create; if not SelectFiles(lN,lG) then begin ShowMsg('Error selecting '+inttostr(lN)+'files!'); goto 666; end; {if not OpenDialogExecute('Select images to average',true,true,kImgFilter) then begin ShowMsg('NPM aborted: file selection failed.'); exit; end; //if not selected lG:= TStringList.Create; lG.addstrings(OpenHdrDlg.Files);} {$IFDEF FORMATVARIES} //this next bit allows different types of scans to be read, but it is slow.... lMaskname := lG[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin ShowMsg('Error reading mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if not MainForm.CheckVoxelsGroup(lG,lMaskVoxels) then begin ShowMsg('File dimensions differ from mask.'); goto 666; end; {$ENDIF} CountOverlap(lG, {round(0.1*lN)} 0); lG.Free; end; //for lLoop end; //for lRep MainForm.NPMmsg('Analysis finished = ' +TimeToStr(Now)); exit; 666: //there has been a critical failure! lG.Free; end; *) function CountOverlap2(var lImages: TStrings; lMinDeficits, lnVoxTested: integer; lPlankImg: bytep): integer; label 123,667; const kMaxBit = 63; var lMaskName: string; //lPlankImg: byteP; lDouble,lTotalMemory: double; lVoxPerPlankDiv10,lOffset,lnDeficits,lUniqueOrders, lVolVox,lPos,lPlank,lVox,lDataType,lnVoxels,lImagesCount: integer; lnPlanks,lVoxPerPlank,lStartVox,lEndVox,lPlankImgPos: int64; lOverlapRA: Overlapp; lOrder,lPrevOrder: TLesionPattern;//x TOverlap; lMaskHdr: TMRIcroHdr; //lPowerRA: array [1..kMaxBit] of int64; procedure CheckOrder(var lObservedOrder: TLesionPattern); var lInc: integer; begin if lUniqueOrders > 0 then begin //see if this is unique for lInc := 1 to lUniqueOrders do if SameOrder(lObservedOrder,lOverlapRA^[lInc],lImagesCount) then exit; //not unique end; //UniqueOrders > 0 //if we have not exited yet, we have found a new ordering! lUniqueOrders := lUniqueOrders + 1; lOverlapRA^[lUniqueOrders] := lObservedOrder; end; begin result := -1; //MainForm.NPMmsg('Analysis began = ' +TimeToStr(Now)); //lMinDeficits := 0; lUniqueOrders := 0; lTotalMemory := 0; lMaskName := lImages[0]; lImagesCount := lImages.Count; if lImagesCount < 1 then goto 667; if lImages.Count > (kMaxObs) then begin NPMmsg('Only able to compute tests for <= '+inttostr(kMaxObs)+' overlays.'); goto 667; end; if not NIFTIhdr_LoadHdr(lMaskName,lMaskHdr) then begin NPMmsg('Error reading 1st image.'); goto 667; end; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; lDataType := lMaskHdr.NIFTIhdr.datatype; lOffset := round(lMaskHdr.NIFTIhdr.vox_offset); //ShowMsg(inttostr(lVolVox)); if (lVolVox < 1) then goto 667; lVoxPerPlank := kPlankSz div lImages.Count {div sizeof(single)} ; if (lVoxPerPlank = 0) then goto 667; //no data lDouble := lVolVox;//force floating point multiplication in next step... lTotalMemory := lDouble * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; lnVoxels := 0; lStartVox := 1; lEndVox := 0; if lnVoxTested <= 0 then getmem(lOverlapRA,lVolVox* sizeof(TLesionPattern)) else getmem(lOverlapRA,lnVoxTested* sizeof(TLesionPattern)); for lPlank := 1 to lnPlanks do begin NPMProgressBar(1); lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lVolVox then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lVolVox); lEndVox := lVolVox; end; lVoxPerPlankDiv10 := lVoxPerPlank div 10; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin {$IFDEF FORMATVARIES} if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then {$ELSE} if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,lOffset,lPlankImgPos,lDataType,lVolVox) then {$ENDIF} goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image lPrevOrder := EmptyOrder;//impossible: forces first voxel of each order to be checked for lVox := 1 to lVoxPerPlank do begin if (lVox mod lVoxPerPlankDiv10) = 0 then begin NPMProgressBar((lVox div lVoxPerPlankDiv10)*10); end; lOrder := EmptyOrder; lPlankImgPos := 0; lnDeficits := 0; for lPos := 1 to lImages.Count do begin if (lPlankImg^[lPlankImgPos + lVox] > 0) then begin inc(lnDeficits); SetBit(lPos,lOrder); end; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end; if (lnDeficits >= lminDeficits) then begin //this is different from the last voxel: perhaps this is a new ordering if (not SameOrder(lOrder,lPrevOrder,lImagesCount)) then CheckOrder(lOrder); inc(lnVoxels); end; lPrevOrder := lOrder; end; lStartVox := lEndVox + 1; end; NPMmsg('n=,'+inttostr( lImages.Count)+',minN=,'+inttostr(lMinDeficits) +',unique overlap patterns,' +Inttostr(lUniqueOrders) +',voxels tested,' +Inttostr(lnVoxels)); 123: //next: free dynamic memory freemem(lOverlapRA); NPMProgressBar(0); result := lUniqueOrders; exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 0 then begin freemem(lPlankImg); freemem(lOverlapRA); end; NPMmsg('Unable to complete analysis.'); NPMProgressBar( 0); end; function CountOverlap(var lImages: TStrings; lMinDeficits,lnVoxTested: integer): integer; var lPlankImg: byteP; begin getmem(lPlankImg,kPlankSz); result := CountOverlap2( lImages, lMinDeficits,lnVoxTested,lPlankImg); freemem(lPlankImg); end; (*function CountOverlap2(var lImages: TStrings; lMinDeficits: integer; lPlankImg: bytep): integer; label 123,667; var lMaskName: string; lVoxPerPlankDiv10,lOffset,lnDeficits,lUniqueOrders,lTotalMemory, lImagesCount,lVolVox,lPos,lPlank,lVox,lDataType,lnVoxels: integer; lnPlanks,lVoxPerPlank,lStartVox,lEndVox,lPlankImgPos: int64; lOverlapRA: Overlapp; lOrder,lPrevOrder: TLesionPattern; lMaskHdr: TMRIcroHdr; //lPowerRA: array [1..kMaxBit] of int64; procedure CheckOrder(var lObservedOrder: TLesionPattern); var lInc: integer; begin if lUniqueOrders > 0 then begin //see if this is unique for lInc := 1 to lUniqueOrders do if SameOrder(lObservedOrder,lOverlapRA^[lInc],lImagesCount) then exit; //not unique end; //UniqueOrders > 0 //if we have not exited yet, we have found a new ordering! lUniqueOrders := lUniqueOrders + 1; lOverlapRA^[lUniqueOrders] := lObservedOrder; end; begin result := -1; //NPMmsg('Analysis began = ' +TimeToStr(Now)); //lMinDeficits := 0; lUniqueOrders := 0; lTotalMemory := 0; lImagesCount := lImages.Count; lMaskName := lImages[0]; if lImages.Count < 1 then goto 667; if lImages.Count > (kMaxObs) then begin NPMmsg('Only able to compute tests for <= '+inttostr(kMaxObs)+' overlays.'); goto 667; end; if not NIFTIhdr_LoadHdr(lMaskName,lMaskHdr) then begin NPMmsg('Error reading 1st image.'); goto 667; end; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; lDataType := lMaskHdr.NIFTIhdr.datatype; lOffset := round(lMaskHdr.NIFTIhdr.vox_offset); //ShowMsg(inttostr(lVolVox)); if (lVolVox < 1) then goto 667; lVoxPerPlank := kPlankSz div lImages.Count ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := lVolVox * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data //ShowMsg('xx'); lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; //NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); //NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); //if lTotalMemory > kPLankSz then // getmem(lPlankImg,kPlankSz); //else // getmem(lPlankImg,lTotalMemory); lnVoxels := 0; lStartVox := 1; lEndVox := 0; getmem(lOverlapRA,lVolVox* sizeof(TLesionPattern)); for lPlank := 1 to lnPlanks do begin MainForm.ProgressBar1.Position := 1; MainForm.Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lVolVox then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lVolVox); lEndVox := lVolVox; end; lVoxPerPlankDiv10 := lVoxPerPlank div 10; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin {$IFDEF FORMATVARIES} if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then {$ELSE} if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,lOffset,lPlankImgPos,lDataType,lVolVox) then {$ENDIF} goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image lPrevOrder := EmptyOrder;//impossible: forces first voxel of each order to be checked for lVox := 1 to lVoxPerPlank do begin if (lVox mod lVoxPerPlankDiv10) = 0 then begin MainForm.ProgressBar1.Position := (lVox div lVoxPerPlankDiv10)*10; MainForm.Refresh; Application.processmessages; end; lOrder := EmptyOrder; lPlankImgPos := 0; lnDeficits := 0; for lPos := 1 to lImages.Count do begin if (lPlankImg^[lPlankImgPos + lVox] > 0) then begin inc(lnDeficits); SetBit(lPos,lOrder); end; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end; if (lnDeficits >= lminDeficits) then begin //this is different from the last voxel: perhaps this is a new ordering if (not SameOrder(lOrder,lPrevOrder,lImagesCount)) then CheckOrder(lOrder); inc(lnVoxels); end; lPrevOrder := lOrder; end; lStartVox := lEndVox + 1; end; NPMmsg('n=,'+inttostr( lImagesCount)+',minN=,'+inttostr(lMinDeficits) +',unique overlap patterns,' +Inttostr(lUniqueOrders) +',voxels tested,' +Inttostr(lnVoxels)); 123: //next: free dynamic memory //freemem(lPlankImg); freemem(lOverlapRA); //NPMmsg('Analysis finished = ' +TimeToStr(Now)); MainForm.ProgressBar1.Position := 0; result := lUniqueOrders; exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 0 then begin freemem(lPlankImg); freemem(lOverlapRA); end; NPMmsg('Unable to complete analysis.'); MainForm.ProgressBar1.Position := 0; end; *) end. �����������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/xmontecarlo.pas������������������������������������������������0000755�0001750�0001750�00000021004�11326443510�020031� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit montecarlo; interface {$H+} {$DEFINE anacom} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, hdr, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls,ExtCtrls,Menus, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,userdir,math, regmult,utypes{$IFDEF anacom} ,anacom{$ENDIF}; procedure LesionMonteCarlo (lBinomial,lTTest,lBM: boolean); implementation uses npmform,filename,turbolesion; procedure RandomGroup(kSamplesPerTest: integer;lImageNames: TStrings;lSymptomRA: SingleP;var lPartImageNames: TStrings; var lPartSymptomRA: SingleP); var lTotal,lInc,lRand,lSwap: integer; lRanOrder: longintP; begin lPartImageNames.Clear; lTotal := lImageNames.Count; if kSamplesPerTest > lTotal then begin showmessage('Monte carlo error: population must be larger than sample size.'); exit; end; Getmem(lRanOrder,lTotal*sizeof(longint)); for lInc := 1 to lTotal do lRanOrder^[lInc] := lInc; for lInc := lTotal downto 2 do begin lRand := Random(lInc)+1; lSwap := lRanOrder^[lRand]; lRanOrder^[lRand] := lRanOrder^[lInc]; lRanOrder^[lInc] := lSwap; end; for lInc := 1 to kSamplesPerTest do begin lPartImageNames.Add(lImageNames.Strings[lRanOrder^[lInc]-1]);//indexed from 0 lPartSymptomRA^[lInc] := lSymptomRA^[lRanOrder^[lInc]]; end; Freemem(lRanOrder); end; procedure LesionMonteCarlo (lBinomial,lTTest,lBM: boolean); label 666; //const //kSimSampleSize = 64; //knSim = 2; //kCrit = 3; {$IFDEF anacom} //knControls = 64; {$ENDIF} var lPrefs: TLDMPrefs ; lCrit,lnSim, lSimSampleSize,lSim,lFact,lnFactors,lSubj,lnSubj,lnSubjAll,lMaskVoxels,lnCrit: integer; lPartImageNames,lImageNames,lImageNamesAll: TStrings; lPredictorList: TStringList; lControlFilename,lTemp4D,lMaskname,lOutName,lFactname,lOutNameSim: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lSymptomRA,lPartSymptomRA: singleP; {$IFDEF anacom} lnControlObservations: integer; lControlSymptomRA: singleP; {$ENDIF} begin lnSim := ReadIntForm.GetInt('Enter total numbers of simulations ', 10,25,1000); lSimSampleSize := ReadIntForm.GetInt('Number of patients per simulation? ', 2,10,1000); lCrit := ReadIntForm.GetInt('Only analyze voxels damaged in at least N patients ', 2,10,1000); //lBinomial := not odd( (Sender as tMenuItem).tag); lPrefs.NULP := true{gNULP false}; if not lBinomial then begin lPrefs.BMtest := lbm;//BMmenu.checked; lPrefs.Ttest := lttest;//ttestmenu.checked; if (not lPrefs.BMtest) and (not lPrefs.ttest) then lPrefs.ttest := true; lPrefs.Ltest:= false; end else begin lPrefs.BMtest := false; lPrefs.Ttest := false; lPrefs.Ltest:= true; end; lPrefs.nCrit := lCrit; lPrefs.nPermute := 0;//MainForm.ReadPermute;; lPrefs.Run := 0;{0 except for montecarlo} if (not lBinomial) and (not lTTest) and (not lBM) then begin Showmessage('Error: you need to compute at least on test [options/test menu]'); exit; end; lImageNamesAll:= TStringList.Create; //not sure why TStrings.Create does not work??? lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? lPartImageNames := TStringList.Create; getmem(lPartSymptomRA,lSimSampleSize*sizeof(single)); {$IFDEF anacom} if not MainForm.OpenDialogExecute('Select text file',false,false,'Text file (*.txt)|*.txt;*.csv') then begin showmessage('AnaCOM aborted: Control data file selection failed.'); exit; end; //if not selected lControlFilename := MainForm.OpenHdrDlg.Filename; if (not readTxt (lControlFilename, lnControlObservations,lControlSymptomRA)) or (lnControlObservations < 1) then begin showmessage('Error reading file '+lControlFilename); exit; end; //lnControlObservations := knControls; //getmem(lControlSymptomRA,lnControlObservations*sizeof(single)); //for lSim := 1 to lnControlObservations do // lControlSymptomRA^[lSim] := 1000; {$ENDIF} //next, get 1st group if not MainForm.GetValX(lnSubjAll,lnFactors,lMultiSymptomRA,lImageNamesAll,lnCrit{,binom},lPredictorList) then begin showmessage('Error with VAL file'); goto 666; end; lTemp4D := CreateDecompressed4D(lImageNamesAll); if (lnSubjAll < 1) or (lnFactors < 1) or (lnSubjAll < lSimSampleSize) then begin Showmessage('Not enough subjects ('+inttostr(lnSubjAll)+') [sample size is '+inttostr(lSimSampleSize)+']or factors ('+inttostr(lnFactors)+').'); goto 666; end; lMaskname := lImageNamesAll[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; MainForm.SaveHdrDlg.Filename := loutname; lOutName := lOutName+'.nii.gz'; if not MainForm.SaveHdrName ('Base Statistical Map', lOutName) then goto 666; for lFact := 1 to lnFactors do begin lImageNames.clear; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then {$ENDIF} lImageNames.Add(lImageNamesAll[lSubj-1]); lnSubj := lImageNames.Count; if lnSubj > 1 then begin getmem(lSymptomRA,lnSubj * sizeof(single)); lnSubj := 0; for lSubj := 1 to lnSubjAll do {$IFNDEF FPC}if lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)] <> NaN then begin {$ELSE} begin{$ENDIF} inc(lnSubj); lSymptomRA^[lnSubj] := lMultiSymptomRA^[lSubj+((lFact-1)*lnSubjAll)]; end; //randomization loop.... for lSim := 1 to lnSim do begin RandomGroup(lSimSampleSize, lImageNames,lSymptomRA, lPartImageNames, lPartSymptomRA); lOutNameSim := AddIndexToFilename(lOutName,lSim); lnCrit := lCrit; MainForm.NPMMsgClear; //Msg(GetKVers); MainForm.NPMMsg('Threads: '+inttostr(gnCPUThreads)); lFactName := lPredictorList.Strings[lFact-1]; lFactName := LegitFilename(lFactName,lFact); MainForm.NPMMsg('Factor = '+lFactname); For lSubj := 1 to lSimSampleSize do MainForm.NPMMsg (lPartImageNames.Strings[lSubj-1] + ' = '+realtostr(lPartSymptomRA^[lSubj],2) ); MainForm.NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); MainForm.NPMMsg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); MainForm.NPMMsg('Number of Lesion maps = '+inttostr(lSimSampleSize)); if not CheckVoxelsGroup(lPartImageNames,lMaskVoxels) then begin showmessage('File dimensions differ from mask.'); goto 666; end; lPrefs.Run := lSim; if lBinomial then TurboLDM (lPartImageNames, lMaskHdr, lPrefs, lPartSymptomRA, lFactname,lOutNameSim) else begin MainForm.ReportDescriptives(lPartSymptomRA,lnSubj); TurboLDM (lPartImageNames, lMaskHdr, lPrefs, lPartSymptomRA, lFactname,lOutNameSim); {$IFDEF anacom} AnacomLesionNPMAnalyze (lPartImageNames, lMaskHdr, lnCrit,lSim,lnControlObservations, lPartSymptomRA,lControlSymptomRA, lFactname,lOutNameSim,true,false); {$ENDIF} end; end; //for each simulation... Freemem(lSymptomRA); end; //lnsubj > 1 end; //for each factor if lnSubjAll > 0 then begin Freemem(lMultiSymptomRA); end; 666: lPartImageNames.free; lImageNames.Free; lImageNamesAll.Free; lPredictorList.Free; freemem(lPartSymptomRA); {$IFDEF anacom} freemem(lControlSymptomRA); {$ENDIF} DeleteDecompressed4D(lTemp4D); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/Mat.pas��������������������������������������������������������0000755�0001750�0001750�00000244524�12156157630�016244� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit Mat; { Basic Matrix Unit for Delphi, May 1996. Implemented using original iMAP C matrix library } { Use this instead of matrix } interface Uses SysUtils, Classes, Vector,dialogsx; //var gMat: boolean = false; type EMatrixError = class (Exception); EMatrixSizeError = class (EMatrixError); ESingularMatrix = class (EMatrixError); ENonSquareMatrix = class (EMatrixError); TMatError = (Singular, NonSingular, NonSquare); { A Matrix is made up of a set of rows of type TRow, pTRow is a pointer to a single row and a matrix is a row of pTRows, this allows arrays larger then 65K to be built, the max size of a matrix is roughly 4096 MBytes } MatRA = array [1..1] of Double; Matp = ^MatRA; { forward declare the Matrix class } TMatrix = class; { Used by svdfit, supplies basis functions at x } BasisProc = procedure (x : TMatElement; var BasisFunc : TVector); { Define a dynamic matrix type for holding doubles } TMatrix = class (TObject) private nr, nc : integer; mx :matp;//: pTRowList; { pointer to a list of rows } procedure SetSize (ri, ci : integer); procedure FreeSpace; public constructor create (r, c : integer); overload; virtual; constructor create (n : integer); overload; virtual; constructor create (c : integer; d : array of TMatElement); overload; virtual; destructor destroy; override; procedure Setval (ri, ci : integer; v : TMatElement); function Getval (ri, ci : integer) : TMatElement; property M[x, y : Integer] : TMatElement read GetVal write SetVal; default; property r : integer read nr; property c : integer read nc; function IsSquare : boolean; function SameDimensions (m1, m2 : TMatrix) : boolean; function Identity : TMatrix; function Diagonal (k : TMatElement) : TMatrix; overload; function Diagonal (v : TVector) : TMatrix; overload; function Zero : TMatrix; function Ones : TMatrix; function L (ci :integer; d : array of TMatElement) : TMatrix; function transpose : TMatrix; overload; function transpose (m1 : TMatrix) : TMatrix; overload; function add (m1, m2 : TMatrix) : TMatrix; overload; function add (m1 : TMatrix) : TMatrix; overload; function sub (m1, m2 : TMatrix) : TMatrix; overload; function sub (m1 : TMatrix) : TMatrix; overload; function mult (m1 : TMatrix; k : TMatElement) : TMatrix; overload; function mult (k : TMatElement) : TMatrix; overload; function mult (m1, m2 : TMatrix) : TMatrix; overload; function copy (m1 : TMatrix) : TMatrix; procedure ExtractColumn (var v : TVector; cc : integer); procedure ExtractRow (var v : TVector; rr : integer); function ExchangeRows (r1, r2 : integer) : TMatrix; function ExchangeCols (c1, c2 : integer) : TMatrix; function Rank (echelon : TMatrix; eps : double) : integer; procedure Invert (inv : TMatrix); overload; procedure Invert; overload; procedure Invert2 (var dest, src : TMatrix; var col: TVector; var index : TVectori); function Det2 (m1 : TMatrix; var index : TVectori; var v : TVector): double; procedure SolveLinear (v, b : TVector; SelfToInv : boolean); procedure LUSolve (index : TVectori; b : TVector); procedure LUDecomp (m1 : TMatrix; index : TVectori); procedure LUDecomp2 (var m1 : TMatrix; var index : TVectori; var v : TVector); function MatMax: double; function MatAbsMax: double; function Det : double; procedure NullSpace (var NullVectors : TMatrix; var BasisSize : integer; var Echelon : TMatrix; var TheRank : integer); procedure svd (var u : TMatrix; var w : TVector; var v : TMatrix); procedure svd2 (var u : TMatrix; var w : TVector; var v : TMatrix); procedure svdSolve (var u : TMatrix; var w : TVector; var v : TMatrix; b : TVector; var x : TVector); function svdfit (x, y, yerr : TVector; var fit : TVector; var u, v : TMatrix; var w : TVector; funcs : BasisProc): TMatElement; procedure svdCovar (v : TMatrix; w : TVector; alpha : TMatrix); procedure eliminate_cms (S, Tk1 : TMatrix; var cr, N : integer); procedure ElementaryModes (D : TVectori; var mf, mb, C1, k : integer; Tk : TMatrix); class procedure Tableau (N, R1 : integer; var mf, mb, C1, k : integer; Tk, Tk1 : TMatrix); class function grecodiv_of_vector (N, R1 : integer; vec : TVector) : integer; class function grecodiv(P, Rest: integer) : integer; procedure Conserve(st : TMatrix); end; { ------------------------------------------------------------------------- } implementation const MATERROR = 'Matrix Operation Error:'; { ------------------------------------------------------------------------- } { START OF MATRIX IMPLEMETATION } { ------------------------------------------------------------------------- } { ------------------------- Constructors first ---------------------------- } { ******************************************************************** } { Usage: A := TMatrix.create (3, 2); } { ******************************************************************** } constructor TMatrix.create (r, c : integer); begin Inherited Create; nr := 0; nc := 0; mx := Nil; Self.SetSize (r, c); end; { ******************************************************************** } { Create an identity matrix } { } { Usage: A := TMatrix.createI (3); } { ******************************************************************** } constructor TMatrix.create (n : integer); var i : integer; begin Inherited Create; nr := 0; nc := 0; mx := Nil; Self.SetSize (n, n); for i := 1 to n do Self[i,i] := 1.0; end; { ******************************************************************** } { Create a matrix filled with values from array d given that the } { number of columns equals c. } { } { Usage: A := TMatrix.createLit (2, [1, 2, 3, 4]); } { Creates a 2 by 2 array } { ******************************************************************** } constructor TMatrix.create (c : integer; d : array of TMatElement); var i, j, ri, count : integer; begin Inherited Create; nr := 0; nc := 0; mx := Nil; ri := (High(d)+1) div c; Self.SetSize (ri, c); count := 0; for i := 1 to ri do for j := 1 to c do begin Self[i,j] := d[count]; inc (count); end; end; { ******************************************************************** } { Usage: A.destroy, use a.free in a program } { ******************************************************************** } destructor TMatrix.destroy; begin FreeSpace; Inherited Destroy; end; { Free the data space but not the object } procedure TMatrix.FreeSpace; //var i : integer; begin if mx <> Nil then begin FreeMem (mx); mx := Nil; end; end; { Internal routine used set size of matrix and allocate space } procedure TMatrix.SetSize (ri, ci : integer); //var i : integer; begin if (mx <> Nil) and ((ri*ci)= (nr*nc) ) then begin nr := ri; nc := ci; exit; end; //if gMat then beep; FreeSpace; nr := ri; nc := ci; //if gMat then beep; Getmem(mx,ri*ci*sizeof(TMatElement));//AllocMem (sizeof (pTRowList) * (nr+1)); { r+1 so that I can index from 1 } end; { ---------------------------------------------------------------------------- } { BASIC ROUTINES } { ---------------------------------------------------------------------------- } { ******************************************************************** } { Used internally but is also accessible from the outside } { } { Normal Usage: A[2, 3] := 1.2; } { } { ******************************************************************** } procedure TMatrix.Setval (ri, ci : integer; v : TMatElement); begin if ri > r then raise EMatrixSizeError.Create ('ri index out of range: ' + inttostr (ri)); if ci > c then raise EMatrixSizeError.Create ('ci index out of range: ' + inttostr (ci)); mx^[ri + ((ci-1)* r )] := v; end; { ******************************************************************** } { Used internally but is also accessible from the outside } { } { Normal Usage: d := A[2, 3]; } { } { ******************************************************************** } function TMatrix.Getval (ri, ci : integer) : TMatElement; begin result := mx^[ri + ((ci-1)* r )]; end; { ******************************************************************** } { Fill an existing matrix with the array d of numbers. ci equals } { the number of columns. } { } { Usage: A.L(3, [1, 2, 3, 4, 5, 6, 7, 8, 9]); } { } { ******************************************************************** } function TMatrix.L (ci :integer; d : array of TMatElement) : TMatrix; var i, j, ri, count : integer; begin ri := (High(d)+1) div ci; FreeMem (mx, sizeof (TMatElement) * nr * nc); Self.SetSize (ri, ci); count := 0; for i := 1 to ri do for j := 1 to ci do begin Self[i,j] := d[count]; inc (count); end; result := Self; end; { ******************************************************************** } { Set all elements to one } { } { Usage: A.Ones; } { } { ******************************************************************** } function TMatrix.Ones : TMatrix; var i, j : integer; begin for i := 1 to r do for j := 1 to c do Self[i,j] := 1.0; result := Self; end; { ******************************************************************** } { Zero the Self matrix } { } { Usage: A.Zero; } { } { ******************************************************************** } function TMatrix.Zero : TMatrix; var i, j : integer; begin for i := 1 to r do for j := 1 to c do Self[i,j] := 0.0; result := Self; end; { ******************************************************************** } { Returns true if matrices m1 and m2 have the same dimensions } { } { Usage: if SameDimensions (A, B) then } { } { ******************************************************************** } function TMatrix.SameDimensions (m1, m2 : TMatrix) : boolean; begin result := (m1.nr = m2.nr) and (m1.nc = m2.nc); { use nr, nc for direct access } end; { ******************************************************************** } { Returns true if matrix m is square } { } { Usage: if IsSquare then } { } { ******************************************************************** } function TMatrix.IsSquare : boolean; begin result := Self.nr = Self.nc; end; { ******************************************************************** } { Turn the matrix Self into an identify matrix } { } { Usage: A.Identity } { } { ******************************************************************** } function TMatrix.Identity : TMatrix; var i : integer; begin if Self.IsSquare then begin Self.Zero; for i := 1 to r do Self[i,i] := 1.0; result := Self; end else raise EMatrixSizeError.Create ('An identity matrix can only be formed from a square matrix'); end; { ******************************************************************** } { Make the matrix object a diagonal matrix with the value, k } { } { Usage: A.Diagonal (3.1415); } { } { ******************************************************************** } function TMatrix.Diagonal (k : TMatElement) : TMatrix; var i : integer; begin if Self.IsSquare then begin Self.Zero; for i := 1 to r do Self[i,i] := k; result := Self; end else raise EMatrixSizeError.Create ('Can only form a diagonal matrix from a square matrix'); end; { ******************************************************************** } { This forms a diagonal matrix from the elements of vector v. } { } { Usage: A.Diagonal (v) } { } { ******************************************************************** } function TMatrix.Diagonal (v : TVector) : TMatrix; var i : integer; begin if Self.IsSquare then begin if v.size = Self.nr then begin Self.zero; for i := 1 to r do Self[i,i] := v[i]; result := Self; end else raise EMatrixSizeError.Create ('Vector must be same size as matrix in DiagonalV'); end else raise EMatrixSizeError.Create ('Can only form a diagonal matrix from a square matrix'); end; { ******************************************************************** } { Transpose matrix 'Self', Self is thus destroyed and replaced } { } { Usage: A.transpose } { } { ******************************************************************** } function TMatrix.Transpose : TMatrix; var i, j : integer; tmp : TMatrix; begin if (r=1) or (c=1) then begin i := nr; nr := nc; nc := i; exit; end; tmp := TMatrix.create (c, r); try for i := 1 to r do for j := 1 to c do tmp [j,i] := Self[i,j]; Self.FreeSpace; Self.SetSize (tmp.nr, tmp.nc); { move data from transpose to Self } Self.Copy (tmp); finally tmp.Destroy; end; result := Self; end; { ******************************************************************** } { Transpose the matrix 'm' into Self } { } { Usage: T.transpose (A); Tranposes A and puts result into T } { Will also accept T.transpose (T) } { ******************************************************************** } function TMatrix.Transpose (m1 : TMatrix) : TMatrix; var i, j : integer; t : TMatrix; begin if (m1.r <> Self.c) and (m1.c <> Self.r) then raise EMatrixSizeError.Create ('Destination matrix has incorrect dimensions for transpose'); { If the user is trying to transpose itself.... } if Self = m1 then begin t := TMatrix.Create (r, c); try t.Copy (m1); for i := 1 to m1.r do for j := 1 to m1.c do Self[j,i] := t[i,j]; finally t.free; result := Self; end; exit; end; for i := 1 to m1.r do for j := 1 to m1.c do Self[j,i] := m1[i,j]; result := Self; end; { ******************************************************************** } { Copy matrix 'm' to Self, Self must exist and is overwritten } { in the process. This procedure does a fast deep copy of the matrix. } { } { Usage: B.Copy (A); performs the operation: B = A with deep copy } { } { ******************************************************************** } function TMatrix.Copy (m1 : TMatrix) : TMatrix; begin if ( r<> m1.r) or (c <> m1.c) then begin (*if r <> m.r then raise EMatrixSizeError.Create (MATERROR + #13#10'Cannot copy matrices with different sized rows: dest<' + inttostr (r) + '> src<' + inttostr (m.r) + '>') else raise EMatrixSizeError.Create (MATERROR + #13#10'Cannot copy matrices with different sized columns: dest<' + inttostr (c) + '> src<' + inttostr (m.c) + '>'); *) SetSize (self.r, self.c); end; { Copy a whole row at a time using move } //for i := 1 to r do move (m.mx^[i]^, Self.mx^[i]^, sizeof(TMatElement) * (c+1)); move(m1.mx^,self.mx^,r*c*sizeof(double)); // Copy over column and row names, clear destination first then copy result := Self; end; { ******************************************************************** } { Extract column cc from the Self matrix and return it as a TVector } { } { Usage: m.ExtractColumn (v, 1) extract column 1 from m and place in v} { } { ******************************************************************** } procedure TMatrix.ExtractColumn (var v : TVector; cc : integer); var i : integer; begin v.freeSpace; v.SetSize (Self.r); { Create result vector of appropriate size } for i := 1 to Self.r do v[i] := Self[i, cc]; end; { ******************************************************************** } { Extract rwo rr from the Self matrix and return it as a TVector } { } { Usage: m.ExtractRow (v, 1) extract row 1 from m and place in v } { } { ******************************************************************** } procedure TMatrix.ExtractRow (var v : TVector; rr : integer); var i : integer; begin v.freespace; v.SetSize (Self.c); for i := 1 to Self.c do v[i] := Self[rr, i]; end; { ******************************************************************** } { Add matrix 'm' to Self, giving a new Self } { } { Usage: A.addU (B); add B to A, giving A } { } { ******************************************************************** } function TMatrix.add (m1 : TMatrix) : TMatrix; var i, j : integer; begin if Not SameDimensions (m1, Self) then raise EMatrixSizeError.Create ('Incorrectly sized result matrix for matrix addition'); for i := 1 to r do for j := 1 to c do Self[i,j] := Self[i,j] + m1[i,j]; result := Self; end; { ******************************************************************** } { Add matrix 'm1' and 'm2' and assign to Self } { } { Usage: A.add (A1, A2); add A1 to A2 giving A } { } { ******************************************************************** } function TMatrix.add (m1, m2 : TMatrix) : TMatrix; var i, j : integer; begin if Not SameDimensions (m1, m2) then raise EMatrixSizeError.Create ('Incompatible matrix operands to add'); if Not SameDimensions (m1, Self) then raise EMatrixSizeError.Create ('Incorrectly sized result matrix for matrix addition'); for i := 1 to r do for j := 1 to c do Self[i,j] := m1[i,j] + m2[i,j]; result := Self; end; { ******************************************************************** } { Subtract matrix m from Self giving a new Self } { } { Usage: A.subU (B); subtract B from A giving A } { } { ******************************************************************** } function TMatrix.sub (m1 : TMatrix) : TMatrix; var i, j : integer; begin if Not SameDimensions (m1, Self) then raise EMatrixSizeError.Create ('Incorrecly sized result matrix for matrix subtraction'); for i := 1 to r do for j := 1 to c do Self[i,j] := Self[i,j] - m1[i,j]; result := Self; end; { ******************************************************************** } { Subtract m2 from m1 giving Self } { } { Usage: A.sub (A1, A2); subtract A2 from A1 giving A (A = A2 - A1) } { } { ******************************************************************** } function TMatrix.sub (m1, m2 : TMatrix) : TMatrix; var i, j : integer; begin if Not SameDimensions (m1, m2) then raise EMatrixSizeError.Create ('Incompatible matrix operands to subtract'); if Not SameDimensions (m1, Self) then raise EMatrixSizeError.Create ('Incorrectly sized result matrix for matrix subtraction'); for i := 1 to r do for j := 1 to c do Self[i,j] := m1[i,j] - m2[i,j]; result := Self; end; { ******************************************************************** } { Multiply a matrix 'm' by scalar constant k and assign result to Self } { } { Usage: A.multk (B, 0.5); multiply scalar, 0.5 by B giving A } { } { ******************************************************************** } function TMatrix.mult (m1 : TMatrix; k : TMatElement) : TMatrix; var i, j : integer; begin for i := 1 to m1.r do for j := 1 to m1.c do Self[i, j] := m1[i,j] * k; result := Self; end; { ******************************************************************** } { Multiply the Self matrix by the scalar constant k } { } { Usage: A.multKU (0.5); multiply scalar 0.5 by A giving A } { } { ******************************************************************** } function TMatrix.mult (k : TMatElement) : TMatrix; var i, j : integer; begin for i := 1 to r do for j := 1 to c do Self[i, j] := Self[i,j] * k; result := Self; end; { ******************************************************************** } { Multiply matrix 'm1' by 'm2' to give result in Self } { } { Usage: A.mult (A1, A2); multiply A1 by A2 giving A } { } { ******************************************************************** } function TMatrix.mult (m1, m2 : Tmatrix) : TMatrix; var i, j, k, m1_Col : integer; sum : TMatElement; begin if m1.c = m2.r then begin m1_col := m1.c; for i := 1 to Self.r do for j := 1 to Self.c do begin sum := 0.0; for k := 1 to m1_Col do sum := sum + m1[i, k]* m2[k, j]; Self[i,j] := sum; end; result := Self; end else raise EMatrixSizeError.Create ('Incompatible matrix operands to multiply'); end; { ******************************************************************** } { LU Solve. Solve the linear system represented by m and right-hand } { side b m is assumed have have been decomposed by LUDecomp } { } { Usage: m.LUSolve (index, b) } { } { ******************************************************************** } procedure TMatrix.LUSolve (index : TVectori; b : TVector); var i, j, ii, ip, nRows : integer; sum : TMatElement; begin ii := 0; nRows := r; for i := 1 to nRows do begin ip := index[i]; sum := b[ip]; b[ip] := b[i]; if ii <> 0 then for j := ii TO i-1 do sum := sum - Self[i,j]*b[j] else if sum <> 0.0 then ii := i; b[i] := sum; end; for i := nRows downto 1 do begin sum := b[i]; if i < nRows then for j := i+1 to nRows do sum := sum - Self[i,j]*b[j]; b[i] := sum/Self[i,i]; end end; { ******************************************************************** } { Form LU decomposition of Self matrix. Result goes into m } { } { Usage: m.LUDecomp(result, index); } { } { ******************************************************************** } procedure TMatrix.LUDecomp (m1 : TMatrix; index : TVectori); var v : TVector; i, k, j, imax, nRows : integer; sum, big, tmp : TMatElement; begin if Self.r = m1.c then begin m1.Copy (Self); v := TVector.Create (m1.r); try { Find the largest element in every row, and store its reciprocal in v[i] } nRows := m1.r; for i := 1 to nRows do begin big := 0.0; { needed to test for singularity } { Although we're working across columns we can use nRows since m1 is square } for j := 1 to nRows do if (abs(m[i,j]) > big) then big := abs(m[i,j]); if big = 0.0 then raise ESingularMatrix.Create ('LUDecomp: Singular matrix in LUDecomp, found row of zeros'); v[i] := 1.0/big end; for j := 1 TO nRows do begin { Form beta = aij - sum_k=1^i-1 aik * bkj } for i := 1 TO j-1 do begin sum := m[i,j]; for k := 1 to i-1 do sum := sum - m[i,k]*m[k,j]; m[i,j] := sum end; big := 0.0; for i := j to nRows do begin sum := m[i,j]; for k := 1 to j-1 do sum := sum - m[i,k]*m[k,j]; m[i,j] := sum; if v[i]*abs(sum) >= big then begin big := v[i]*abs(sum); imax := i end end; { Interchange rows if necessary } if j <> imax then begin { Swap row names aswell } for k := 1 to nRows do begin tmp := m[imax,k]; m[imax,k] := m[j,k]; m[j,k] := tmp end; v[imax] := v[j] end; index[j] := imax; { Get ready to divide by pivot element } if m[j,j] = 0.0 then raise ESingularMatrix.Create ('LUDecomp: Singular Matrix, pivot value is zero'); if j <> nRows then begin tmp := 1.0/m[j,j]; for i := j+1 to nRows do m[i,j] := m[i,j]*tmp end end; finally v.destroy; end; end else raise ENonSquareMatrix.Create ('LUDecomp: Matrix must be square'); end; //return max value in a matrix function TMatrix.MatMax : double; var i,j : integer; begin if (r < 1) or (c<1) then begin result := 0; exit; end; result := m[1,1]; for i := 1 to r do for j := 1 to c do if m[i, j] > result then result := m[i,j]; end; //return max value in a matrix function TMatrix.MatAbsMax : double; var i,j : integer; begin if (r < 1) or (c<1) then begin result := 0; exit; end; result := abs(m[1,1]); for i := 1 to r do for j := 1 to c do if abs(m[i, j]) > result then result := abs(m[i,j]); end; { ******************************************************************** } { Find determinant of matrix } { } { Usage: d := m.det } { } { ******************************************************************** } function TMatrix.Det : double; var m1 : TMatrix; index : TVectori; i : integer; begin result := 1; if r = c then begin index := TVectori.Create (r); m1 := TMatrix.Create (r,r); try m1.copy (Self); Self.LUDecomp (m1, index); for i := 1 to r do result := result * m1[i,i]; finally m1.free; index.free; end; end else raise ENonSquareMatrix.Create ('Determinant: Matrix must be square'); end; (*procedure wMatrix( lTitle: string; A : TMatrix); var lR,lC: integer; lStr: string; begin if (A.r < 1) or (A.c < 1) then exit; lStr := (lTitle)+chr($0D)+chr($0A); for lR := 1 to (A.r) do begin for lC := 1 to (A.c) do lStr := lStr + floattostr(A.Getval(lr, lc))+' '; lStr := lStr + chr($0D)+chr($0A); end; //each row showmessage(lStr); end;*) procedure TMatrix.LUDecomp2 (var m1 : TMatrix; var index : TVectori; var v : TVector); var i, k, j, imax, nRows : integer; sum, big, tmp : TMatElement; begin if Self.r = m1.c then begin m1.Copy (Self); //wmatrix('m1',m1); //v := TVector.Create (m.r); try { Find the largest element in every row, and store its reciprocal in v[i] } nRows := m1.r; for i := 1 to nRows do begin big := 0.0; { needed to test for singularity } { Although we're working across columns we can use nRows since m1 is square } for j := 1 to nRows do if (abs(m1[i,j]) > big) then big := abs(m1[i,j]); if big = 0.0 then raise ESingularMatrix.Create ('LUDecomp: Singular matrix in LUDecomp, found row of zeros'); v[i] := 1.0/big end; for j := 1 TO nRows do begin { Form beta = aij - sum_k=1^i-1 aik * bkj } for i := 1 TO j-1 do begin sum := m1[i,j]; for k := 1 to i-1 do sum := sum - m1[i,k]*m1[k,j]; m1[i,j] := sum end; big := 0.0; for i := j to nRows do begin sum := m1[i,j]; for k := 1 to j-1 do sum := sum - m1[i,k]*m1[k,j]; m1[i,j] := sum; if v[i]*abs(sum) >= big then begin big := v[i]*abs(sum); imax := i end end; { Interchange rows if necessary } if j <> imax then begin { Swap row names aswell } for k := 1 to nRows do begin tmp := m1[imax,k]; m1[imax,k] := m1[j,k]; m1[j,k] := tmp end; v[imax] := v[j] end; index[j] := imax; { Get ready to divide by pivot element } if m1[j,j] = 0.0 then raise ESingularMatrix.Create ('LUDecomp: Singular Matrix, pivot value is zero'); if j <> nRows then begin tmp := 1.0/m1[j,j]; for i := j+1 to nRows do m1[i,j] := m1[i,j]*tmp end end; finally //v.destroy; end; end else raise ENonSquareMatrix.Create ('LUDecomp: Matrix must be square'); end; function TMatrix.Det2 (m1 : TMatrix; var index : TVectori; var v : TVector): double; var i : integer; begin result := 1; if r = c then begin //index := TVectori.Create (r); //m := TMatrix.Create (r,r); try m1.copy (Self); Self.LUDecomp2 (m1, index,v); for i := 1 to r do result := result * m1[i,i]; finally //m.free; index.free; end; end else raise ENonSquareMatrix.Create ('Determinant: Matrix must be square'); end; { ******************************************************************** } { Solve a linear system of equations: Self.v = b, i.e solve for v } { } { Usage: A.SolveLinear (v, b, t); } { Solution in v } { If the boolean t is true then self is replaced by the inverse } { ******************************************************************** } procedure TMatrix.SolveLinear (v, b : TVector; SelfToInv : boolean); var n, i, j : integer; indx : TVectori; col : TVector; dest, src : TMatrix; begin if Self.r = Self.c then begin n := Self.r; { Make a copy and work on the copy } dest := TMatrix.Create (n, n); src := TMatrix.Create (n, n); indx := TVectori.Create (n); try src.Copy (Self); for i := 1 to n do v[i] := b[i]; src.LUDecomp (dest, indx); dest.LUSolve (indx, v); if SelfToInv then begin col := TVector.Create (n); try for j := 1 to n do begin for i := 1 to n do col[i] := 0.0; col[j] := 1.0; dest.LUSolve (indx, col); for i := 1 to n do Self[i,j] := col[i]; end; finally col.free; end; end; finally indx.destroy; dest.destroy; src.destroy; end; end else raise ENonSquareMatrix.Create ('SolveLinear: Matrix must be square'); end; { ******************************************************************** } { Fast method for inverting a matrix (Self) } { Result in inv } { } { Usage: A.Invert (inv); } { ******************************************************************** } procedure TMatrix.Invert2 (var dest, src : TMatrix; var col: TVector; var index : TVectori); var n, i, j : integer; begin n := Self.r; try src.Copy (Self); try //wmatrix('w1',src); src.LUDecomp2 (dest, index,col); //wmatrix('w2',src); except on ESingularMatrix do raise ESingularMatrix.Create ('Invert: Singular Matrix'); end; for j := 1 to n do begin for i := 1 to n do col[i] := 0.0; col[j] := 1.0; dest.LUSolve (index, col); for i := 1 to n do Self[i,j] := col[i]; end; finally //col.destroy; dest.destroy; src.destroy; index.destroy; end; end; procedure TMatrix.Invert (inv : TMatrix); var col : TVector; n, i, j : integer; dest, src : TMatrix; indx : TVectori; begin n := Self.r; col := TVector.Create (n); dest := TMatrix.Create (n, n); src := TMatrix.Create (n, n); indx := TVectori.Create (n); try src.Copy (Self); try src.LUDecomp (dest, indx); except on ESingularMatrix do raise ESingularMatrix.Create ('Invert: Singular Matrix'); end; for j := 1 to n do begin for i := 1 to n do col[i] := 0.0; col[j] := 1.0; dest.LUSolve (indx, col); for i := 1 to n do inv[i,j] := col[i]; end; finally col.destroy; dest.destroy; src.destroy; indx.destroy; end; end; { ******************************************************************** } { Fast method for inverting a matrix (Self) } { Result in Self } { } { Usage: A.Invert } { ******************************************************************** } procedure TMatrix.Invert; var col : TVector; n, i, j : integer; dest, src : TMatrix; index : TVectori; begin n := Self.r; col := TVector.Create (n); dest := TMatrix.Create (n, n); src := TMatrix.Create (n, n); index := TVectori.Create (n); try src.Copy (Self); try src.LUDecomp (dest, index); except on ESingularMatrix do raise ESingularMatrix.Create ('Invert: Singular Matrix'); end; for j := 1 to n do begin for i := 1 to n do col[i] := 0.0; col[j] := 1.0; dest.LUSolve (index, col); for i := 1 to n do Self[i,j] := col[i]; end; finally col.destroy; dest.destroy; src.destroy; index.destroy; end; end; { Internal routine that sets any values less than eps to 0.0 } procedure CleanUpMatrix (m : TMatrix; eps : double); var i, j, ri, ci : integer; begin { Removes all numbers close to zero, i.e between -eps and +eps } ri := m.r; ci := m.c; for i := 1 to ri do for j := 1 to ci do if abs (m [i, j]) < eps then m [i, j] := 0.0; end; { Internal routine to work out the rank of a matrix given the reduced row-echelon } function ComputeRank (m : TMatrix; eps : double) : integer; var i, j, ri, ci, rank : integer; begin ri := m.r; ci := m.c; { find the rank - brute force algorithm } rank := 0; { search row by row for zero rows } for i := 1 to ri do begin { search along the row looking for nonzero entry } for j := 1 to ci do if abs (m [i, j]) > eps then begin inc (rank); break; end; end; result := rank; end; { ******************************************************************** } { Routine to exchange two rows, r1 and r2 in matrix Self } { } { Usage: A.exchangeRows (1, 2); } { } { ******************************************************************** } function TMatrix.ExchangeRows (r1, r2 : integer) : TMatrix; var ci, i : integer; t : double; begin if (r1 > 0) and (r1 <= Self.r) and (r2 > 0) and (r2 <= Self.r) then begin ci := Self.c; for i := 1 to ci do begin t := Self[r1, i]; Self[r1, i] := Self[r2, i]; Self[r2, i] := t; end; result := Self; end else raise EMatrixSizeError.Create ('Rows not in range for exchange'); end; { ******************************************************************** } { Routine to exchange two columns, c1 and c2 in matrix Self } { } { Usage: A.exchangeCols (1, 2); } { } { ******************************************************************** } function TMatrix.ExchangeCols (c1, c2 : integer) : TMatrix; var ri, i : integer; t : double; begin if (c1 > 0) and (c1 <= Self.c) and (c2 > 0) and (c2 <= Self.c) then begin ri := Self.r; for i := 1 to ri do begin t := Self[c1, i]; Self[c1, i] := Self[c2, i]; Self[c2, i] := t; end; result := Self; end else raise EMatrixSizeError.Create ('Columns not in range for exchange'); end; { ******************************************************************** } { Find the rank r, of the matrix Self, The reduced Row } { echelon is returned in mat. eps is the magnitude of } { the largest number before it is assumed to be zero. } { } { Usage: r := A.Rank (echelon, 1e-8) } { Find the rank of A, place echelon in echelon } { } { ******************************************************************** } function TMatrix.Rank (echelon : TMatrix; eps : double) : integer; var Arow, Acol, i, j, n, m1, RowScan : integer; factor : double; begin echelon.copy (Self); { we work on mat, not Self } if (eps = 0.0) then eps := 1.0E-14; n := echelon.r; m1 := echelon.c; Arow := 1; Acol := 1; repeat { locate a nonzero column } if abs(echelon [Arow, Acol]) <= eps then { i.e equals zero } begin { First entry was zero, therefore work our way down the matrix looking for a nonzero entry, when found, swap it for Arow } RowScan := Arow; repeat { next row } inc (RowScan); { have we reached the end of the rows but we've still got columns left to scan } if (RowScan > n) and (Acol < m1) then begin { reset row counter back to where it was and try next column } RowScan := Arow; inc (Acol); end; { If we've scanned the whole matrix, so lets get out... } if (RowScan > n) then begin CleanUpMatrix (echelon, eps); result := ComputeRank (echelon, eps); exit; end; until abs (echelon [RowScan, Acol]) > eps; { keep searching until non-zero entry found } { We've found a nonzero row entry so swap it with 'Arow' which did have a zero as its entry } echelon.exchangeRows (Arow, RowScan); end; { Arow now holds the row of interest } factor := 1.0/echelon [Arow, Acol]; { reduce all the entries along the column by the factor } for i := Acol to m1 do echelon[Arow,i] := echelon[Arow, i] * factor; { now eliminate all entries above and below Arow, this generates the reduced form } for i := 1 to n do { miss out Arow itself } if (i <> Arow) and (abs (echelon [i, Acol]) > eps) then begin factor := echelon [i, Acol]; { work your way along the column doing the same operation } for j := Acol to m1 do echelon[i,j] := echelon [i, j] - factor * echelon [Arow, j]; end; inc (Arow); inc (Acol); until (Arow > n) or (Acol > m1); CleanUpMatrix (echelon, eps); result := ComputeRank (echelon, eps); { This is just a patch for the moment } end; (* Algorithm 1. Reduce matrix to reduced echelon form 2. There will be as many null space vectors as there are non-leading columns. Select one of these non-leading columns. 3. Select the ith non-leading column and place a 1 at the ith position in the growing null space vector 4. Consider the remaining non-leading columns, say j,k,l... and place zero's at positions j,k,l... in the growing null vector. 5. Consider now the column positions of the leading columns, say l,m,n... The equivalent entries in the growing null space are what remains to be filled in. Select each of these leading columns in turn, say the lth first. Record which row the leading one is in, say r. Then place at position l in the growing null space vector, the element -1 * element (r, i) where i is the original ith non-leading column selected in step 3. Continue for leading columns m,n... until the growing null space vector is complete. 6. Go back to step 2 and pick another non-leading column to compute the next null space vector. Does not disturb the matrix Self. Null space to be found in NullVectors, size of the basis in BasisSize, the reduced row-echelon in Echelon and the rank in TheRank } Usage: A.NullSpace (N, b, Echelon, r); *) procedure TMatrix.NullSpace (var NullVectors : TMatrix; var BasisSize : integer; var Echelon : TMatrix; var TheRank : integer); var eps, x: double; i, j, k : integer; mask : TVectori; tmpNullVectors : TMatrix; VectorCounter, maskcount : integer; minus999, minus888, EchelonCols : integer; begin try eps := 0.000000001; minus999 := -999; { leading column } minus888 := -888; { non-leading column } if NullVectors <> Nil then NullVectors.free; if Echelon <> Nil then Echelon.free; tmpNullVectors := TMatrix.Create (Self.c, Self.c); Echelon := TMatrix.Create (Self.r, Self.c); EchelonCols := Echelon.c; mask := TVectori.create (EchelonCols); // STEP 1 k := Self.Rank (Echelon, eps); TheRank := k; k := Self.c - TheRank; BasisSize := k; if BasisSize > 0 then begin for i := 1 to EchelonCols do mask [i] := minus888; for i := 1 to Echelon.r do begin { scan along columns looking for a leading one } j := 1; repeat x := Echelon[i, j]; if (x > -eps) and (x < eps) then { check if its practically zero } Echelon [i, j] := 0.0; if (x > 1.0-eps) and (x < 1.0+eps) then { x is then = 1.0 } begin mask [j] := minus999; { tag as leading column } j := 0; { exit signal } end else j := j + 1; until (j = 0) or (j > EchelonCols); end; { end row scan } { Find non-leading columns } VectorCounter := 1; i := 1; { i = column counter, check all columns } repeat for j := 1 to EchelonCols do tmpNullVectors[j, VectorCounter] := minus888; { STEP 5 } { remember, all minus888's in mask = non-leading columns } if mask [i] = minus888 then { found a non-leading column } begin j := 1; { move down mask } for maskcount := 1 to EchelonCols do if (mask [maskcount] = minus999) then begin tmpNullVectors[maskcount, VectorCounter] := -Echelon[j, i]; inc (j); end; { STEP 4 } { zero all -888 (free) entries } for j := 1 to EchelonCols do if tmpNullVectors[j, VectorCounter] = minus888 then tmpNullVectors[j, VectorCounter] := 0.0; { STEP 2 AND 3 } { mark free variable } tmpNullVectors[i, VectorCounter] := 1.0; VectorCounter := VectorCounter + 1; end; inc (i); until i > EchelonCols; end else begin BasisSize := 0; NullVectors := Nil; end; finally if BasisSize > 0 then begin NullVectors := TMatrix.Create (Self.c, BasisSize); for i := 1 to Self.c do for j := 1 to BasisSize do NullVectors[i,j] := tmpNullVectors[i,j]; end; mask.free; tmpNullVectors.free; end; end; function sign (a, b : TMatElement) : TMatElement; begin if b >= 0.0 then result := abs (a) else result := -abs(a); end; function max (a, b : TMatElement) : TMatElement; begin if a > b then result := a else result := b; end; { Compute sqrt (a^2 + b^2) using numerically more stable method. If x = sqrt(a^2 + b^2), then, x/a^2 = 1/a^2 sqrt (a^2 + b^2), mult both sides by sqrt(..), so x/a^2 * sqrt (a^2 + b^2) = 1/a^2 (a^2 + b^2) or x/a^2 * sqrt (a^2 + b^2) = 1 + (b/a)^2 but on left side 1/a^2 sqrt(a^2 + b^2) equals x/a^2, therefore x * x/a^2 = 1 + (b/a) ^2, take square roots on both side yields: x/a := sqrt (1+(b/a)^2), or FINALLY: x := a sqrt (1 + (b/a)^2) } function pythag (a, b : TMatElement) : TMatElement; var at, bt, ct : TMatElement; begin result := sqrt (a*a + b*b); exit; at := abs (a); bt := abs (b); if at > bt then begin ct := bt/at; result := at*sqrt (1 + ct*ct); end else begin if bt > 0 then begin ct := at/bt; result := bt*sqrt (1 + ct*ct); end else result := 0.0; end; end; function MyAbs (x : TMatElement) : TMatElement; begin if x < 0.0 then x := -x; result := x; end; {procedure TMatrix.svd2 (var u : TMatrix; var w : TVector; var v : TMatrix);} procedure TMatrix.svd2 (var u : TMatrix; var w : TVector; var v : TMatrix); LABEL 1,2,3; CONST nmax=100; VAR n, m1, nm, l1, k, j, jj, its, i : integer; z, y, x, scale, s, h, g, f, cc, anorm : real; rv1 : TVector; //Aug : TMatrix; AugMatrix : boolean; function sign(a,b: TMatElement): TMatElement; begin if (b >= 0.0) then sign := abs(a) else sign := -abs(a) end; function max(a,b: TMatElement): TMatElement; begin if (a > b) then max := a else max := b end; begin m1 := r; n := c; AugMatrix := false; (*if m < n then begin { More parameters than data ! Change structure of Self by augmenting Self with additional rows (entries set to zero) so that m = n, don't change m or n though } {Aug := TMatrix.Create (n, n); Aug.zero; try for i := 1 to m do for j := 1 to n do Aug[i,j] := Self[i,j]; u.FreeSpace; u.SetSize (n, n); u.Copy (Aug); AugMatrix := true; finally Aug.free; end; end else*) u.Copy(Self); { Work on U, don't destroy Self } if AugMatrix then rv1 := TVector.Create (n) { Make enough room } else rv1 := TVector.Create (m1); { Save some space } g := 0.0; scale := 0.0; anorm := 0.0; FOR i := 1 TO n DO BEGIN l1 := i+1; rv1[i] := scale*g; g := 0.0; s := 0.0; scale := 0.0; IF (i <= m1) THEN BEGIN FOR k := i TO m1 DO scale := scale + Myabs(u[k,i]); IF (Myabs(scale) > 1e-12) THEN BEGIN {IF (scale <> 0.0) THEN BEGIN} for k := i to m1 do begin u[k,i] := u[k,i]/scale; s := s + u[k,i]*u[k,i] end; f := u[i,i]; g := -sign(sqrt(s),f); h := f*g-s; u[i,i] := f-g; if (i <> n) then begin for j := l1 to n do begin s := 0.0; for k := i to m1 do s := s + u[k,i]*u[k,j]; f := s/h; for k := i to m1 do u[k,j] := u[k,j] + f*u[k,i]; end end; for k := i to m1 do u[k,i] := scale*u[k,i] END END; w[i] := scale*g; g := 0.0; s := 0.0; scale := 0.0; IF ((i <= m1) AND (i <> n)) THEN BEGIN for k := l1 to n do scale := scale + Myabs(u[i,k]); if (Myabs(scale) > 1e-12) then begin {if (scale <> 0.0) then begin} for k := l1 to n do begin u[i,k] := u[i,k]/scale; s := s + u[i,k]*u[i,k] end; f := u[i,l1]; g := -sign(sqrt(s),f); h := f*g-s; u[i,l1] := f-g; for k := l1 to n do rv1[k] := u[i,k]/h; if (i <> m1) then begin for j := l1 to m1 do begin s := 0.0; for k := l1 to n do s := s + u[j,k]*u[i,k]; for k := l1 to n do u[j,k] := u[j,k] + s*rv1[k]; end end; for k := l1 to n do u[i,k] := scale*u[i,k]; END END; anorm := max(anorm,(Myabs(w[i]) + Myabs(rv1[i]))) END; FOR i := n DOWNTO 1 DO BEGIN IF (i < n) THEN BEGIN if (Myabs(g) > 1e-12) then {IF (g <> 0.0) THEN} begin for j := l1 to n do v[j,i] := (u[i,j]/u[i,l1])/g; for j := l1 to n do begin s := 0.0; for k := l1 to n do s := s + u[i,k]*v[k,j]; for k := l1 to n do v[k,j] := v[k,j] + s*v[k,i] end end; for j := l1 to n do begin v[i,j] := 0.0; v[j,i] := 0.0; end END; v[i,i] := 1.0; g := rv1[i]; l1 := i end; FOR i := n DOWNTO 1 DO BEGIN l1 := i+1; g := w[i]; if (i < n) then for j := l1 to n do u[i,j] := 0.0; if (Myabs(g) > 1e-12) then {IF (g <> 0.0) THEN} begin g := 1.0/g; IF (i <> n) THEN begin for j := l1 to n do begin s := 0.0; for k := l1 to m1 do s := s + u[k,i]*u[k,j]; f := (s/u[i,i])*g; for k := i to m1 do u[k,j] := u[k,j] + f*u[k,i]; end end; for j := i to m1 do u[j,i] := u[j,i]*g; end else begin for j := i to m1 do u[j,i] := 0.0; end; u[i,i] := u[i,i]+1.0 END; FOR k := n DOWNTO 1 DO BEGIN FOR its := 1 TO 30 DO BEGIN for l1 := k downto 1 do begin nm := l1-1; if ((Myabs(rv1[l1]) + anorm) - anorm < 1e-12) then goto 2; {if ((Myabs(rv1[l]) + anorm) = anorm) then goto 2;} if ((Myabs(w[nm]) + anorm) - anorm < 1e-12) then goto 1 {if ((Myabs(w[nm]) + anorm) = anorm) then goto 1} end; 1: cc := 0.0; s := 1.0; for i := l1 to k do begin f := s*rv1[i]; if ((Myabs(f) + anorm) - anorm > 1e-12) then {if ((Myabs(f)+anorm) <> anorm) then} begin g := w[i]; h := sqrt(f*f+g*g); w[i] := h; h := 1.0/h; cc := (g*h); s := -(f*h); for j := 1 to m1 do begin y := u[j,nm]; z := u[j,i]; u[j,nm] := (y*cc)+(z*s); u[j,i] := -(y*s)+(z*cc) end end end; 2: z := w[k]; if (l1 = k) then begin if (z < 0.0) then begin w[k] := -z; for j := 1 to n do v[j,k] := -v[j,k]; end; GOTO 3 end; if (its = 30) then writeln ('no convergence in 30 SVDCMP iterations'); x := w[l1]; nm := k-1; y := w[nm]; g := rv1[nm]; h := rv1[k]; f := ((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y); g := sqrt(f*f+1.0); f := ((x-z)*(x+z)+h*((y/(f+sign(g,f)))-h))/x; cc := 1.0; s := 1.0; for j := l1 to nm do begin i := j+1; g := rv1[i]; y := w[i]; h := s*g; g := cc*g; z := sqrt(f*f+h*h); rv1[j] := z; cc := f/z; s := h/z; f := (x*cc)+(g*s); g := -(x*s)+(g*cc); h := y*s; y := y*cc; for jj := 1 to n do begin x := v[jj,j]; z := v[jj,i]; v[jj,j] := (x*cc)+(z*s); v[jj,i] := -(x*s)+(z*cc) end; z := sqrt(f*f+h*h); w[j] := z; if (Myabs(z) > 1e-12) then {if (z <> 0.0) then} begin z := 1.0/z; cc := f*z; s := h*z end; f := (cc*g)+(s*y); x := -(s*g)+(cc*y); for jj := 1 to m1 do begin y := u[jj,j]; z := u[jj,i]; u[jj,j] := (y*cc)+(z*s); u[jj,i] := -(y*s)+(z*cc) end end; rv1[l1] := 0.0; rv1[k] := f; w[k] := x END; 3: END END; { Perform a Singular Value Decompostion on self, returning u, w, and v, modified from Numerical Recipes and Forsythe et al 1977, Computer methods for Math Calc } procedure TMatrix.svd (var u : TMatrix; var w : TVector; var v : TMatrix); label 3; var i, j, k, l1, n, m1, its, flag, nm, jj : integer; rv1 : TVector; scale, g, h, f, anorm, s, cc, x, y, z : TMatElement; Aug : TMatrix; AugMatrix : boolean; begin m1:= r; n := c; AugMatrix := false; if m1 < n then begin { More parameters than data ! Change structure of Self by augmenting Self with additional rows (entries set to zero) so that m = n, don't change m or n though } Aug := TMatrix.Create (n, n); Aug.zero; try for i := 1 to m1 do for j := 1 to n do Aug[i,j] := Self[i,j]; u.FreeSpace; u.SetSize (n, n); u.Copy (Aug); AugMatrix := true; finally Aug.free; end; end else u.Copy(Self); { Work on U, don't destroy Self } scale := 0.0; g := 0.0; anorm := 0.0; if AugMatrix then rv1 := TVector.Create (n) { Make enough room } else rv1 := TVector.Create (m1); { Save some space } try for i := 1 to n do begin l1 := i + 1; rv1[i] := scale * g; g := 0.0; s := 0.0; scale := 0.0; if i <= m1 then begin for k := i to m1 do scale := scale + abs (u[k,i]); if scale <> 0.0 then begin for k := i to m1 do begin u[k, i] := u[k, i] / scale; s := s + u[k,i]*u[k,i]; end; f := u[i,i]; g := -sign (sqrt (s), f); h := f*g - s; u[i,i] := f - g; if i <> n then begin for j := l1 to n do begin s := 0.0; for k := i to m1 do s := s + u[k,i]*u[k,j]; f := s/h; for k := i to m1 do u[k,j] := u[k,j] + f*u[k,i]; end; end; for k := i to m1 do u[k,i] := u[k,i] * scale; end; end; w[i] := scale * g; g := 0.0; s := 0.0; scale := 0.0; if (i <= m1) and (i <> n) then begin for k := l1 to n do scale := scale + abs (u[i,k]); if scale <> 0.0 then begin for k := l1 to n do begin u[i,k] := u[i,k] / scale; s := s + u[i,k]*u[i,k]; end; f := u[i,l1]; g := -sign(sqrt (s), f); h := f*g - s; u[i,l1] := f - g; for k := l1 to n do rv1[k] := u[i,k]/h; if i <> m1 then begin for j := l1 to m1 do begin s := 0.0; for k := l1 to n do s := s + u[j,k]*u[i,k]; for k := l1 to n do u[j,k] := u[j,k] + s*rv1[k]; end; end; for k := l1 to n do u[i,k] := u[i,k] * scale; end; end; anorm := max (anorm, abs(w[i]) + abs(rv1[i])); end; { ------------------------------------------ } { Accumulation of right-hand transformations } for i := n downto 1 do begin if i < n then begin if g <> 0.0 then begin for j := l1 to n do v[j,i] := (u[i,j]/u[i,l1])/g; for j := l1 to n do begin s := 0.0; for k := l1 to n do s := s + u[i,k]*v[k,j]; for k := l1 to n do v[k,j] := v[k,j] + s*v[k,i]; end; end; for j := l1 to n do begin v[i,j] := 0.0; v[j,i] := 0.0; end; end; v[i,i] := 1.0; g := rv1[i]; l1 := i; end; { ------------------------------------------ } { Accumulation of left-hand transformations } for i := n downto 1 do begin l1 := i + 1; g := w[i]; if i < n then for j := l1 to n do u[i,j] := 0.0; if g <> 0.0 then begin g := 1.0/g; if i <> n then begin for j := l1 to n do begin s := 0.0; for k := l1 to m1 do s := s + u[k,i]*u[k,j]; f := (s/u[i,i])*g; for k := i to m1 do u[k,j] := u[k,j] + f*u[k,i]; end; end; for j := i to m1 do u[j,i] := u[j,i] * g; end else begin for j := i to m1 do u[j,i] := 0.0; end; u[i,i] := u[i,i] + 1.0; end; { --------------------------------------------- } { Diagonalization of the bidiagonal form } for k := n downto 1 do begin for its := 1 to 30 do begin flag := 1; for l1 := k downto 1 do begin nm := l1 - 1; if abs (rv1[l1] + anorm) = anorm then begin flag := 0; break; end; if abs (w[nm] + anorm) = anorm then break; end; if flag <> 0 then begin cc := 0.0; s := 1.0; for i := l1 to k do begin f := s * rv1[i]; if (abs (f) + anorm) <> anorm then begin g := w[i]; h := pythag (f, g); w[i] := h; h := 1.0/h; cc := g*h; s := -f*h; for j := 1 to m1 do begin y := u[j,nm]; z := u[j, i]; u[j,nm] := y*cc + z*s; u[j,i] := z*cc - y*s; end; end; end; end; z := w[k]; if l1 = k then begin if z < 0.0 then begin w[k] := -z; for j := 1 to n do v[j,k] := -v[j,k]; end; {break;} goto 3; end; if (its = 30) then raise Exception.Create ('Exceeded iterations in SVD routine'); x := w[l1]; nm := k - 1; y := w[nm]; g := rv1[nm]; h := rv1[k]; f := ((y - z)*(y + z) + (g - h)*(g + h))/(2.0*h*y); g := pythag (f, 1.0); f := ((x - z) * (x + z) + h*((y/(f + sign(g, f))) - h))/x; cc := 1.0; s := 1.0; for j := l1 to nm do begin i := j + 1; g := rv1[i]; y := w[i]; h := s*g; g := cc*g; z := pythag (f, h); rv1[j] := z; cc := f/z; s := h/z; f := x*cc + g*s; g := g*cc - x*s; h := y*s; y := y*cc; for jj := 1 to n do begin x := v[jj,j]; z := v[jj,i]; v[jj,j] := x*cc + z*s; v[jj,i] := z*cc - x*s; end; z := pythag (f, h); w[j] := z; if z <> 0 then begin z := 1.0/z; cc := f*z; s := h*z; end; f := (cc*g) + (s*y); x := (cc*y) - (s*g); for jj := 1 to m1 do begin y := u[jj,j]; z := u[jj,i]; u[jj,j] := y*cc + z*s; u[jj,i] := z*cc - y*s; end; end; rv1[l1] := 0.0; rv1[k] := f; w[k] := x; 3: end; end; finally rv1.free; end; if AugMatrix then begin { This means that originally m < n, therefore u has some junk rows, remove them here } Aug := TMatrix.Create (m1, n); try for i := 1 to m1 do for j := 1 to n do Aug[i,j] := u[i,j]; u.FreeSpace; u.SetSize (m1, n); u.Copy (Aug); finally Aug.free; end; end; end; { Call this after having called svd, computes x = V [diag (1/wj)]. U^t.b } procedure TMatrix.svdSolve (var u : TMatrix; var w : TVector; var v : TMatrix; b : TVector; var x : TVector); var j, i, n, m1 : integer; s: TMatElement; tmp: TVector; begin m1 := u.r; n := u.c; tmp := TVector.Create (u.c); try { Compute diag (1/wj) . U^t . b } for j := 1 to n do begin s := 0.0; if (w[j] <> 0.0) then begin for i := 1 to m1 do s := s + u[i,j]*b[i]; s := s/w[j] end; tmp[j] := s end; { ...mult by V to get solution vector x } for i := 1 to n do begin s := 0.0; for j := 1 to w.size do s := s + v[i,j]*tmp[j]; x[i] := s end; finally tmp.free; end; end; { Solves the equation: (A.a - b)^2 = 0 for a. Where, A is the 'design matrix', Aij = Xj(xi)/sigi, where Xj is the value of the jth basis function; b is the set of weighted observed y values, b = yi/sigi; and a is the set of fitting coefficients for the basis functions. Thus A.a - b expresses predicted - observed } { BasisProc is a procedure which must return in an array the values for the basis functions at a particular value of xi, i.e it computes, Xj(xi) } function TMatrix.svdfit (x, y, yerr : TVector; var fit : TVector; var u, v : TMatrix; var w : TVector; funcs : BasisProc): TMatElement; const tol=1.0e-5; var i, j : integer; wmax, weight, thresh, sum: TMatElement; BasisVal, b : TVector; A : TMatrix; begin BasisVal := TVector.Create (fit.size); b := TVector.Create (x.size); A := TMatrix.Create (x.size, fit.size); try { Form the A matrix } for i := 1 to x.size do begin funcs(x[i], BasisVal); weight := 1.0/yerr[i]; for j := 1 to fit.size do A[i,j] := BasisVal[j]*weight; b[i] := y[i]*weight end; A.svd (u, w, v); wmax := 0.0; for j := 1 to fit.size do if (w[j] > wmax) then wmax := w[j]; thresh := tol*wmax; for j := 1 to fit.size do if (w[j] < thresh) then w[j] := 0.0; svdSolve (u, w, v, b, fit); result := 0.0; { chisqr set to zero ready to accumulate } for i := 1 to x.size do begin funcs(x[i], BasisVal); sum := 0.0; for j := 1 to fit.size do sum := sum + fit[j]*BasisVal[j]; result := result + sqr((y[i]-sum)/yerr[i]); { Accumulate chisqr } end; finally BasisVal.free; A.free; b.free; end; end; procedure TMatrix.svdCovar (v : TMatrix; w : TVector; alpha : TMatrix); var i, j, k : integer; wti : TVector; sum : TMatElement; begin wti := TVector.Create (w.size); try for i := 1 to w.size do begin wti[i] := 0.0; if w[i] > 0.0 then wti[i] := 1.0/(w[i]*w[i]); end; for i := 1 to w.size do begin for j := 1 to i do begin sum := 0.0; for k := 1 to w.size do sum := sum + v[i,k]*v[j,k]*wti[k]; alpha[j,i] := sum; alpha[i,j] := alpha[j,i]; end; end; finally wti.free; end; end; procedure TMatrix.eliminate_cms (S, Tk1 : TMatrix; var cr, N : integer); (* eliminating conserved moieties *) var i,j,x,y,crc,old_cr : byte; begin x := 0; cr := 0; (* cr - conservation relations *) for i := 1 to N do begin old_cr := cr; for j := i+1 to N do begin crc := 0; (* crc - cr counter *) // S.c = number of reactions for y := 1 to S.c do crc := crc + trunc (abs(S[i,y]+S[j,y])); if crc = 0 then cr := cr+1; end; if cr = old_cr then begin x := x+1; for y := 1 to S.c do Tk1[x,y] := S[i,y]; end; end; end; procedure TMatrix.ElementaryModes (D : TVectori; var mf, mb, C1, k : integer; Tk : TMatrix); var i, j, cr, N, k1 : integer; Tk1 : TMatrix; hlpRow : TVector; begin N := Self.r; Tk1 := TMatrix.Create (Self.r, Self.c); hlpRow := TVector.Create (Self.c); try {eliminate_cms; (* also transscribing S into Tk1 *) N := N-cr; for i := 1 to R do begin for j := 1 to N do Tk[i,j] := Tk1[j,i]; (* transposing matrix *) for j:=N+1 to N+R do if i=j-N then Tk[i,j]:=1 (* appending.. *) else Tk[i,j]:=0; (*..unity matrix*) end; (* (preliminary) fund. rows to the top *) i := 0; (* splitting indices into F/B *) for j := 1 TO R DO begin if (D[j] <> 0) then begin i := i+1; hlprow := Tk[i]; Tk[i] := Tk[j]; Tk[j] := hlprow; end; end; mf := i; (* no. of fundamental rows *) mb := R-mf;} eliminate_cms (Self, Tk1, cr, N); (* also transscribing S into Tk1 *) N := N-cr; for i := 1 to Self.c do begin for j := 1 to N do Tk[i,j] := Tk1[j,i]; (* transposing matrix *) for j := N+1 to N+Self.c do if i=j-N then Tk[i,j] := 1 (* appending.. *) else Tk[i,j] := 0; (*..unity matrix*) end; (* (preliminary) fund. rows to the top *) i := 0; (* splitting indices into F/B *) for j := 1 TO Self.c DO begin if (D[j] <> 0) then begin i := i+1; for k1 := 1 to Self.c do hlprow[k1] := Tk[i,k1]; for k1 := 1 to Self.c do Tk[i,k1] := Tk[j,k1]; for k1 := 1 to Self.c do Tk[j,k1] := hlprow[k1]; //hlprow := Tk[i]; //Tk[i] := Tk[j]; //Tk[j] := hlprow; end; end; mf := i; (* no. of fundamental rows *) mb := Self.c-mf; (* no. of basis rows *) Tableau (N, Self.c, mf, mb, C1, k, Tk, Tk1); finally hlpRow.Free; Tk1.Free; end; end; class function TMatrix.grecodiv(P, Rest: integer) : integer; var old_Rest : integer; begin grecodiv := 1; if (Rest*P <> 0) then begin if ABS(P) < ABS(Rest) then begin old_Rest := Rest; Rest := P; P := old_Rest; (* swap P 'n' R *) end; repeat (* Euclidean Algorithm: *) old_Rest := Rest; Rest := P mod old_Rest; P := old_Rest; until (Rest = 0); grecodiv := P; end else if (P = 0) then begin if (Rest = 0) then grecodiv := 1 else grecodiv := Rest; end else grecodiv := P; end; class function TMatrix.grecodiv_of_vector (N, R1 : integer; vec : TVector) : integer; var x : byte; coeff : integer; begin coeff := trunc (vec[1]); for x := 2 to (N+R1) do begin if (vec[x] <> 0) then coeff := grecodiv(trunc (vec[x]), coeff); end; grecodiv_of_vector := coeff; end; class procedure TMatrix.Tableau (N, R1 : integer; var mf, mb, C1, k : integer; Tk, Tk1 : TMatrix); var i,j,k1,x,xa,y,m1 : integer; cf,dir,ifrom,iend : integer; index,bool,allow_comb : boolean; l1 : integer; vec : TVector; begin C1 := R1; (* C: number of rows of the tableau *) k := 0; (* k: tableau index *) vec := TVector.Create (Tk1.c); repeat //output; (* HELPFUL MONITORING*) //write(' k = ');writeln(k);writeln('cf=',cf); (* OF TABLEAU STEPS *) {write(' Press <ENTER> to continue.'); readln;} l1 := 1; (* l: row index in the tableau k+1 *) cf := 0; (* counter for f-rows in the tableau k+1*) for dir :=1 to 2 do BEGIN IF dir=1 THEN BEGIN ifrom:=1; iend:=mf; END ELSE BEGIN ifrom:=mf+1; iend:=c1 END; FOR i := ifrom TO iend DO BEGIN IF Tk[i,k+1] = 0 THEN (* copying rows that *) BEGIN (* have a zero element *) for k1 := 1 to Tk1.c do Tk1[l1, k1] := Tk[i, k1]; (* already *) //Tk1[l] := Tk[i]; (* already *) l1 := l1+1; IF i <= mf THEN cf := cf+1; END END; FOR i:=ifrom TO iend DO BEGIN IF Tk[i,k+1]<>0 THEN BEGIN FOR j := i+1 TO C1 DO BEGIN IF Tk[j,k+1] <> 0 THEN BEGIN IF Tk[i,k+1]*Tk[j,k+1] > 0 THEN BEGIN (* not for f-rows with *) IF j <= mf THEN allow_comb := false (* same signum *) ELSE BEGIN FOR y := 1 TO N+R1 DO Tk[j,y] := -1 * Tk[j,y]; (* invert b-row *) allow_comb := true; END; END ELSE allow_comb := true; IF allow_comb THEN BEGIN index:=true; (* first simplicity (S) test: *) IF (l1>1) THEN BEGIN IF dir=1 THEN x:=0 ELSE x:=cf; WHILE (x<l1-1) AND (INDEX) DO BEGIN x:=x+1; y:=n; bool:=true; REPEAT y:=y+1; IF ((Tk[i,y] = 0) and (Tk[j,y] = 0)) THEN IF Tk1[x,y] <> Tk[i,y] THEN bool:=false; UNTIL (y=n+r1)or NOT bool; IF (y=n+r1)and bool THEN index:=false; END; END; IF index THEN BEGIN (* combine rows *) FOR y:=1 TO R1+N DO Tk1[l1,y]:=abs(Tk[i,k+1])*Tk[j,y]+abs(Tk[j,k+1])*Tk[i,y]; for k1 := 1 to Tk1.c do vec[i] := Tk1[l1,k1]; m1:= Grecodiv_of_vector(N, R1, vec) ; //m:= Grecodiv_of_vector(Tk1[l]) ; IF (ABS(m1)<>1) AND (m1<>0) THEN FOR y:=1 to R1+N DO Tk1[l1,y]:= trunc (Tk1[l1,y]) DIV ABS(m1); l1:= l1+1; IF i <= mf THEN cf := cf+1; (* second simplicity (S) test: *) IF dir=1 THEN x:=0 ELSE x:=cf; bool:=true; WHILE (X<L1-2) AND (bool=true) DO BEGIN x:=x+1; y:=n; bool:=false; REPEAT y:=y+1; IF Tk1[x,y]=0 THEN IF (Tk1[x,y]<>Tk[i,y]) OR (Tk1[x,y]<>Tk[j,y]) THEN bool:=true; UNTIL (y=n+r1)or bool; IF (y=n+r1)and NOT(bool) THEN BEGIN {writeln('Jetzt hat folgende Zeile:'); FOR Y:=n+1 to n+r DO write(Tk1[x,y]:3); writeln; writeln('x=',x); writeln; writeln('l-1=',l-1); writeln('verloren gegen folgende Zeilen:'); FOR Y:=n+1 to n+r DO write(Tk[i,y]:3); writeln; writeln('i=',i); FOR Y:=n+1 to n+r DO write(Tk[j,y]:3); writeln; writeln('j=',j); writeln; writeln(x,'+1te Zeile:'); FOR Y:=n+1 to n+r DO write(Tk1[x+1,y]:3); writeln;} FOR xa:=x TO l1-2 DO BEGIN FOR y:=1 TO n+r1 DO Tk1[xa,y]:=Tk1[xa+1,y]; END; l1:=l1-1; IF x<=cf THEN cf:=cf-1; END; END; END; END; END; END; END; END; END; C1 := l1-1; (* new no. of rows *) mf := cf; mb := C1-mf; k := k+1; (* next tableau *) for i := 1 to C1 do begin for k1 := 1 to Tk.c do Tk[i, k1] := Tk1[i, k1]; (* restarting with Tk1 *) end; //for i := 1 to C do Tk[i] := Tk1[i]; (* restarting with Tk1 *) until (k = N) or ((mb = 0) and (mf = 0)); //if ((mb = 0) and (mf = 0)) then // writeln(' There exist neither irreversible nor reversible flux modes.') //else // output; vec.Free; end; // Evaluate conservation relations, uses the algorthim: tr(ns(tr(m))) procedure TMatrix.Conserve(st : TMatrix); var tmp, ns, echelon : TMatrix; b, r1 : integer; begin tmp := TMatrix.Create (st.c, st.r); ns := TMatrix.Create (1,1); echelon := TMatrix.Create (1,1); try tmp.Transpose (st); tmp.NullSpace (ns, b, Echelon, r1); Self.SetSize (ns.c, ns.r); Self.Transpose (ns); finally ns.free; echelon.free; tmp.free; end; end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/upower.pas�����������������������������������������������������0000755�0001750�0001750�00000011726�12156157332�017037� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit upower; interface uses define_types, statcr, distr, dialogsx; function Sum2Power(lOutImgSum: SingleP; lVolVox,lnTotal,lnDeficit: integer; lBinomial: boolean): boolean; function Sum2PowerCont(lOutImgSum: SingleP; lVolVox,lnTotal: integer): boolean; function Sum2PowerBinom(lOutImgSum: SingleP; lVolVox,lnTotal,lnDeficit: integer): boolean; function k_out_n (k,n: integer): double; //total possible permutations implementation function k_out_n (k,n: integer): double; //total possible permutations //k= smaller group, n=sum of both groups begin if not gFactRAready then InitFact; result := round(gFactRA[n] / (gFactRA[k]*gFactRA[n-k] ) ); // k out n = n!/(k!*(n-k)! which is equal to the PROD(i=k; 1){(n-i+1)/i} end; //k_out_n function Sum2Power(lOutImgSum: SingleP; lVolVox,lnTotal,lnDeficit: integer; lBinomial: boolean): boolean; begin if lBinomial then result := Sum2PowerBinom(lOutImgSum, lVolVox,lnTotal,lnDeficit) else result := Sum2PowerCont(lOutImgSum, lVolVox,lnTotal) end; function Sum2PowerCont(lOutImgSum: SingleP; lVolVox,lnTotal: integer): boolean; //convert Sum image to power map showing maximum possible effect size //'Cont' version is for continuous data var lDensity,lN,lRank: integer; lDensityPowerRA: singleP; begin result := false; if (lnTotal < 2) or (lVolVox < 1) then exit; getmem(lDensityPowerRA,lnTotal* sizeof(single)); //no need to compute power for [lnTotal] and [0] - no variability when everyone or no one has a lesion //lDensityPowerRA[lnTotal] := 0; //everyone has a lesion = no variability lRank := 0; for lN := 1 to (lnTotal -1) do begin //most power when all participants with a lesion have most extreme behavioural data //therefore, they will have the lowest ranks: rank 1,2,3,4 lRank := lRank + lN; if (lnTotal > 360) then //cannot calculate values this large... lDensityPowerRA^[lN] := 0 else if (lN > 10) and (lnTotal > 64) then //avoid overflow... lDensityPowerRA^[lN] := pNormalInv ( 1/(k_out_n(10,lnTotal)) ) else begin lDensityPowerRA^[lN] := 1/(k_out_n(lN,lnTotal)); //compute Wilcoxon probability lDensityPowerRA^[lN] := pNormalInv (lDensityPowerRA^[lN]);//convert p to z-score end; //max power when every possible person with a lesion has a defict, and everyone w/o lesion does not... //lDensityPowerRA[lN] := Liebermeister (lLD,lnoLD,lLnoD,lnoLnoD); //probability of this observation //lDensityPowerRA[lN] := pNormalInv (lDensityPowerRA[lN]);//convert p to z-score //fx(lDensityPowerRA[lN]); end; //now use lookup table to convert overlay density to effective power for lN := 1 to lVolVox do begin lDensity := round( lOutImgSum^[lN]); if (lDensity > 0) and (lDensity < lnTotal) then lOutImgSum^[lN] := lDensityPowerRA^[lDensity] else lOutImgSum^[lN] := 0; end; //for each voxel freemem(lDensityPowerRA); result := true; end; function Sum2PowerBinom(lOutImgSum: SingleP; lVolVox,lnTotal,lnDeficit: integer): boolean; //convert Sum image to power map showing maximum possible effect size var lDensity,lN,lLD,lLnoD,lnoLD,lnoLnoD: integer; lDensityPowerRA: singleP; begin result := false; if (lnTotal < 2) or (lnDeficit < 1) or (lVolVox < 1) then exit; if(lnDeficit >= lnTotal) then begin ShowMsg('Sum2Power error: people with deficit must be less than sample size'); exit; end; getmem(lDensityPowerRA,lnTotal* sizeof(single)); //no need to compute power for lnTotal and 0 - no variability when everyone or no one has a lesion //lDensityPowerRA[lnTotal] := 0; //everyone has a lesion = no variability for lN := 1 to (lnTotal -1) do begin //max power when every possible person with a lesion has a defict, and everyone w/o lesion does not... if lN > lnDeficit then begin lLD := lnDeficit; lLnoD := lN - lnDeficit; end else begin lLD := lN; lLnoD := 0; end; lnoLD := lnDeficit-lLD; //number of people with deficit who do not have a lesion - as close to zero as possible lnoLnoD := lnTotal-lnoLD-lLnoD-lLD; lDensityPowerRA^[lN] := Liebermeister (lLD,lnoLD,lLnoD,lnoLnoD); //probability of this observation lDensityPowerRA^[lN] := pNormalInv (lDensityPowerRA^[lN]);//convert p to z-score //fx(lLD,lnoLD,lLnoD,lnoLnoD,lDensityPowerRA[lN]); end; //now use lookup table to convert overlay density to effective power for lN := 1 to lVolVox do begin lDensity := round( lOutImgSum^[lN]); if (lDensity > 0) and (lDensity < lnTotal) then lOutImgSum^[lN] := lDensityPowerRA^[lDensity] else lOutImgSum^[lN] := 0; end; //for each voxel freemem(lDensityPowerRA); result := true; end; end. ������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/extrafpc.cfg���������������������������������������������������0000755�0001750�0001750�00000000130�11316122054�017257� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#IFDEF Darwin -k-macosx_version_min -k10.4 -XR/Developer/SDKs/MacOSX10.4u.sdk/ #ENDIF����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/regression.pas�������������������������������������������������0000755�0001750�0001750�00000071001�12306422752�017664� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit regression; //only for Delphi - not Freepascal //Unit for running multiple regression interface {$Include ..\common\isgui.inc} uses {$H+} {$IFDEF GUI} Forms, {$ENDIF} {$IFNDEF UNIX} Windows, {$ENDIF} {$IFDEF FPC} utypes,regmult,{$ELSE} utypes,regmult, {$ENDIF}define_types,Classes,nifti_hdr,sysutils,nifti_img, StatThdsUtil,Distr,Dialogsx, tfce_clustering, unpm, nifti_types; function GetValReg (var lVALFilename: string; var lnSubj,lnFactors: integer; var X : PMatrix; var lImageNames: TStrings; var lPredictorList: TStringList): boolean; function ARegressNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; var X: PMatrix; lnFactors: integer; var lPredictorList: TStringList; lOutname: string; lnPermute, TFCEconn: integer): boolean; function Regress2NPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lOutname: string; var lXadditional: PMatrix; lnAdditionalFactors, lnPermute: integer ): boolean; function TtoR(t,df: double): double; implementation uses valformat,hdr,math; function Sign(value: double): double; begin if value > 0 then result := 1 else if value < 0 then result := -1 else result := 0; end; function TtoR(t,df: double): double; CONST eps=3.0e-7; begin result := 0; if (t = 0) or (df = 0) then exit; result := sign(t)/ sqrt( (df/(t*t+eps)) +1 ); end; {$DEFINE SaveT} //if SaveT then t-score map will be saved {$DEFINE SaveRnotZ} //if SaveRnotZ then r-value map will be saved, but not Z-score map function Regress2NPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lOutname: string; var lXadditional: PMatrix; lnAdditionalFactors, lnPermute: integer ): boolean; //lImages is list 1..N of 1st images followed by 1..N of corresponding control images //example c1.img, c2.img,c3.img,e1.img,e2.img,e3.img //lImages.Count must be even label 667; const kMaxFact = 80; var lOutNameMod,lFactName,lRunName: string; lMaskImg,lPlankImg,lOutImgMn: SingleP; lOutImgR: array [1..kMaxFact] of SingleP; lTotalMemory: int64; lnFactors,lnObservations,lnObservationsDiv2,lPlank,lVolVox,lPos,lMinMask,lMaxMask,lnPlanks,lVoxPerPlank, lDF,lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct,lFact,lnStatFact: integer; l1st, lSum, lMn: double; lVar: boolean; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; lZP: Pointer; lZra : DoubleP0; X : PMatrix; begin lnFactors := 1+lnAdditionalFactors; if odd(lImages.Count) then begin ShowMsg('Regress2NPMAnalyze must be passed an even number of images: the first half of the list is the experimental images, followed by corresponding control images.'); exit; end; lnObservations := lImages.Count; lnObservationsDiv2 := lImages.Count div 2; lDF := lnObservationsDiv2-lnFactors-1; if lDF < 1 then begin ShowMsg('Regress2NPMAnalyze: DF must be >0 (DF=[Num-Factors-1]) Num='+inttostr(lnObservationsDiv2)+' Factors='+inttostr(lnFactors) ); exit; end; DimMatrix(X, lnFactors, lnObservationsDiv2); //fx(lnAdditionalFactors); if lnAdditionalFactors > 0 then begin for lPos2 := 1 to lnAdditionalFactors do begin for lPos := 1 to lnObservationsDiv2 do begin X^[lPos2+1]^[lPos] := lXadditional^[lPos2]^[lPos]; //fx(lPos2+1,lPos, X^[lPos2+1]^[lPos]); end; end; //pos 2 end; //additional factros //Memo1.Lines.Add('Permutations = ' +IntToStr(lnPermute)); NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lnStatFact := lnFactors + 1; //factors + overall model if lnStatFact > (kMaxFact-1) then begin //-1 because factors + model NPMmsg('ERROR: Can not analyze more than = ' +inttostr(kMaxFact-1)+' factors'); goto 667; end; //load mask getmem(lMaskImg,lVolVox*sizeof(single)); if not LoadImg(lMaskHdr.ImgFileName, lMaskImg, 1, lVolVox,round(gOffsetRA[0]),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin NPMmsg('Unable to load mask ' +lMaskHdr.ImgFileName); goto 667; end; //next find start and end of mask lPos := 0; repeat inc(lPos); until (lMaskImg^[lPos] > 0) or (lPos = lVolVox); lMinMask := lPos; lPos := lVolVox+1; repeat dec(lPos); until (lMaskImg^[lPos] > 0) or (lPos = 1); lMaxMask := lPos; if lMaxMask = 1 then begin NPMmsg('Mask appears empty' +lMaskHdr.ImgFileName); goto 667; end; NPMmsg('Mask has voxels from '+inttostr(lMinMask)+'..'+inttostr(lMaxMask)); lVoxPerPlank := kPlankSz div lnObservations div sizeof(single) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lnObservations; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lnObservations) ) + 1; NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lnObservations))); NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory*sizeof(single)) //assumes 4bpp else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; lnVoxTested := 0; for lPos := 1 to lnObservations do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; createArray64(lObsp,lObs,lnObservations); getmem(lOutImgMn,lVolVox* sizeof(single)); for lPos := 1 to lVolVox do lOutImgMn^[lPos] := 0; for lFact := 1 to (lnStatFact) do begin //+1 as we include full model getmem(lOutImgR[lFact],lVolVox* sizeof(single)); for lPos := 1 to lVolVox do lOutImgR[lFact]^[lPos] := 0; end; createArray64(lZp,lZra,lnFactors+1); //+1 as we include full model //InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxTW, lPermuteMinTW,lPermuteMaxWMW, lPermuteMinWMW, lRanOrderp, lRanOrder); for lPlank := 1 to lnPlanks do begin NPMmsg('Computing plank = ' +Inttostr(lPlank)); Refresher; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lnObservations do begin if not LoadImg(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image lPosPct := lVoxPerPlank div 100; for lPos2 := 1 to lVoxPerPlank do begin if (lPos2 mod lPosPct) = 0 then begin NPMProgressBar( round((lPos2/lVoxPerPlank)*100) ); end; lPos2Offset := lPos2+lStartVox-1; if lMaskImg^[lPos2Offset] <> 0 then begin inc(lnVoxTested); lSum := 0; //check for variance lVar := false; lPos := 1; l1st := (gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; for lPos := 1 to lnObservations do lObs^[lPos-1] := (gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; for lPos := 1 to lnObservationsDiv2 do begin lSum := lSum + lObs^[lPos-1]; if (not lVar) and (lObs^[lPos-1]<>l1st) then lVar := true; //lSumOfSqrs := lSumOfSqrs + sqr(lObs[lPos-1]); X^[1]^[lPos] := lObs^[lnObservationsDiv2+lPos-1]; end; lOutImgMn^[lPos2Offset] := lSum/lnObservationsDiv2; if lVar then begin MultipleRegression (lnObservationsDiv2,lnFactors, X, lObs, lZra); //if lPos2Offset = 359948 then rx(lnObservationsDiv2,lnFactors,X,lObs); for lFact := 1 to lnStatFact do lOutImgR[lFact]^[lPos2Offset] := lZra^[lFact-1]; end; //StatPermute (lttest,lwelch,lWMW,lImages.Count, lnGroup1,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxTW, lPermuteMinTW,lPermuteMaxWMW, lPermuteMinWMW, lObs,lRanOrder); end; //in brain mask - compute end; lStartVox := lEndVox + 1; end; //next report findings NPMMsg('Voxels tested = ' +Inttostr(lnVoxTested)); reportBonferroni('Std',lnVoxTested); //next: save data if lnFactors = 1 then lRunName := 'reg' else lRunName := ''; //savedata MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save mean lOutNameMod := ChangeFilePostfixExt(lOutName,'Mn'+lRunName,'.hdr'); if not FileExistsEX(lOutNameMod) then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgMn,1); //save regression for lFact := 1 to (lnStatFact) do begin if (lFact > lnFactors) and (lnFactors = 1) then lFactName := 'intercept'+'reg' //for analysis of multiple single regressions else if (lFact > lnFactors) then lFactName := 'intercept' else lFactName := 'reg'+inttostr(lFact); MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); {$IFDEF SaveT} //if SaveTRnotZ then t-score and r-score maps will be created, but no Z-score maps //the next bit is optional - save data as T-values instead of Z-scores // this allows direct comparison with SPM... MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,lDF,0,lnVoxTested,kNIFTI_INTENT_TTEST,inttostr(lnVoxTested) ); lOutNameMod := ChangeFilePostfixExt(lOutName, 'wlsT'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgR[lFact],1); {$ENDIF} {$IFDEF SaveRnotZ} MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,lDF,0,lnVoxTested,kNIFTI_INTENT_CORREL,inttostr(lnVoxTested) ); for lPos := 1 to lVolVox do lOutImgR[lFact]^[lPos] := TtoR (lOutImgR[lFact]^[lPos],lDF); lOutNameMod := ChangeFilePostfixExt(lOutName, 'wlsR'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgR[lFact],1); {$ELSE} //next - save Zscores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,lDF,0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); //{ DoF = Nb points - Nb parameters } for lPos := 1 to lVolVox do lOutImgR[lFact]^[lPos] := TtoZ (lOutImgR[lFact]^[lPos],lDF); MainForm.reportFDR ('wls'+lFactName, lVolVox, lnVoxTested, lOutImgR[lFact]); lOutNameMod := ChangeFilePostfixExt(lOutName, 'wls'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgR[lFact],1); {$ENDIF} freemem(lOutImgR[lFact]); end; //next: close images Freemem(lZp); freemem(lOutImgMn); freemem(lObsp); freemem(lMaskImg); freemem(lPlankImg); NPMmsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lRunName,'.txt'); NPMMsgSave(lOutNameMod); NPMProgressBar(0); DelMatrix(X, lnFactors, lnObservationsDiv2); exit; 667: //you only get here if you aborted ... free memory and report error DelMatrix(X, 1, lnObservationsDiv2); if lVolVox > 1 then freemem(lMaskImg); if lTotalMemory > 1 then freemem(lPlankImg); NPMmsg('Unable to complete analysis.'); NPMProgressBar(0); end; {$DEFINE NoThread} function InnerARegressNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; var X: PMatrix; lnFactors: integer; var lPredictorList: TStringList; lOutname: string; lSaveData: boolean; var lMinZ,lMaxZ: double; var lMaxNegTFCEZ, lMaxTFCEZ:single; TFCEconn: integer): boolean; //TFCEmode 0 = no TFCE, 1 = only report min/maxTFCE, 2 = save TFCE map to disk {$IFNDEF Thread} const kMaxFact = 80; {$ENDIF} label 667; var lOutNameMod,lFactName,lRunName: string; lMaskImg,lPlankImg,lOutImgMn: SingleP; {$IFDEF Thread} lOutImgR: TRegRA; {$ELSE} lOutImgR: array [1..kMaxFact] of SingleP; {$ENDIF} lTotalMemory: int64; lnObservations,lPlank,lVolVox,lPos,lMinMask,lMaxMask,lnPlanks,lVoxPerPlank, //lPos2,lPos2Offset, lDF,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lFact,lnStatFact: integer; //l1st, lSum, lMn: double; //lVar: boolean; //lObsp: pointer;lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; {$IFDEF Thread} lThread,lThreadStart,lThreadEnd,lThreadInc: integer; {$ELSE} lObsP,lZP: Pointer; lObs,lZra : DoubleP0; lSum,l1st: double; lVar: boolean; lPos2,lPosPct,lPos2Offset: integer; {$ENDIF} begin lnObservations := lImages.Count; lDF := lnObservations-lnFactors-1; if lDF < 1 then begin ShowMsg('Regress2NPMAnalyze: DF must be >0 (DF=[Num-Factors-1]) Num='+inttostr(lnObservations)+' Factors='+inttostr(lnFactors) ); exit; end; if (lSaveData) then NPMmsg('Analysis began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lnStatFact := lnFactors + 1; //factors + overall model if lnStatFact > (kMaxFact-1) then begin //-1 because factors + model NPMmsg('ERROR: Can not analyze more than = ' +inttostr(kMaxFact-1)+' factors'); goto 667; end; //load mask getmem(lMaskImg,lVolVox*sizeof(single)); if not LoadImg(lMaskHdr.ImgFileName, lMaskImg, 1, lVolVox,round(gOffsetRA[0]),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin NPMmsg('Unable to load mask ' +lMaskHdr.ImgFileName); goto 667; end; //next find start and end of mask lPos := 0; repeat inc(lPos); until (lMaskImg^[lPos] > 0) or (lPos = lVolVox); lMinMask := lPos; lPos := lVolVox+1; repeat dec(lPos); until (lMaskImg^[lPos] > 0) or (lPos = 1); lMaxMask := lPos; if lMaxMask = 1 then begin NPMmsg('Mask appears empty' +lMaskHdr.ImgFileName); goto 667; end; if (lSaveData) then NPMmsg('Mask has voxels from '+inttostr(lMinMask)+'..'+inttostr(lMaxMask)); lVoxPerPlank := kPlankSz div lnObservations div sizeof(single) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lnObservations; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lnObservations) ) + 1; if (lSaveData) then NPMmsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lnObservations))); if (lSaveData) then NPMmsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory* sizeof(single)) //assumes 4bpp else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; //lnVoxTested := 0; for lPos := 1 to lnObservations do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; //createArray64(lObsp,lObs,lnObservations); getmem(lOutImgMn,lVolVox* sizeof(single)); for lPos := 1 to lVolVox do lOutImgMn^[lPos] := 0; for lFact := 1 to (lnStatFact) do begin //+1 as we include full model getmem(lOutImgR[lFact],lVolVox* sizeof(single)); for lPos := 1 to lVolVox do lOutImgR[lFact]^[lPos] := 0; end; //createArray64(lZp,lZra,lnFactors+1); //+1 as we include full model {$IFDEF Thread} ClearThreadDataPvals(gnCPUThreads,0) ; {$ELSE} lnVoxTested := 0; {$ENDIF} for lPlank := 1 to lnPlanks do begin if (lSaveData) then NPMmsg('Computing plank = ' +Inttostr(lPlank)); Refresher; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lnObservations do begin if not LoadImg(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image {$IFDEF Thread} lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TLinThreadStat.Create (X,ProgressBar1, lnFactors,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lnObservations, lMaskImg,lPlankImg,lOutImgMn,lOutImgR) do {$IFDEF FPC} OnTerminate := @ThreadDone; {$ELSE}OnTerminate := ThreadDone;{$ENDIF} inc(gThreadsRunning); Msg('Thread ' +Inttostr(gThreadsRunning)+' = '+inttostr(lThreadStart)+'..'+inttostr(lThreadEnd)); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; Application.processmessages; {$ELSE} //not threaded createArray64(lZp,lZra,lnFactors+1); //+1 as we include full model createArray64(lObsp,lObs,lnObservations); lPosPct := lVoxPerPlank div 100; for lPos2 := 1 to lVoxPerPlank do begin if (lPos2 mod lPosPct) = 0 then begin NPMProgressBar(round((lPos2/lVoxPerPlank)*100)); end; lPos2Offset := lPos2+lStartVox-1; if lMaskImg^[lPos2Offset] <> 0 then begin inc(lnVoxTested); lSum := 0; //check for variance lVar := false; lPos := 1; l1st := (gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; for lPos := 1 to lnObservations do begin lObs^[lPos-1] := (gScaleRA[lPos]*lPlankImg^[((lPos-1)* lVoxPerPlank)+lPos2])+gInterceptRA[lPos]; lSum := lSum + lObs^[lPos-1]; if (not lVar) and (lObs^[lPos-1]<>l1st) then lVar := true; end; lOutImgMn^[lPos2Offset] := lSum/lnObservations; if lVar then begin MultipleRegression (lnObservations,lnFactors, X, lObs, lZra); //if {lZra^[0] < -5.548} lPos2Offset = 762287 then // ReportRegression (lPos2Offset,lnObservations,lnFactors, X, lObs, lZra ); for lFact := 1 to lnStatFact do lOutImgR[lFact]^[lPos2Offset] := lZra^[lFact-1]; end; end; //in brain mask - compute end; //for each voxel Freemem(lZp); Freemem(lObsp); {$ENDIF} //if threaded else not threaded lStartVox := lEndVox + 1; end; //for each plank {$IFDEF Thread} lnVoxTested := SumThreadDataLite(gnCPUThreads); {$ENDIF} //FACTOR 1 MinMax lFact := 1; lMinZ := lOutImgR[lFact]^[1]; for lPos := 1 to lVolVox do if (lOutImgR[lFact]^[lPos] < lMinZ) then lMinZ :=lOutImgR[lFact]^[lPos]; lMinZ := TtoZ (lMinZ,lDF); lMaxZ := lOutImgR[lFact]^[1]; for lPos := 1 to lVolVox do if (lOutImgR[lFact]^[lPos] > lMaxZ) then lMaxZ :=lOutImgR[lFact]^[lPos]; lMaxZ := TtoZ (lMaxZ,lDF); //NPMmsg('Factor1MinMax ' +floattostr(lMinZ)+' '+floattostr(lMaxZ)); if (lSaveData) then begin //next report findings NPMmsg('Voxels tested = ' +Inttostr(lnVoxTested)); reportBonferroni('Std',lnVoxTested); //next: save data if lnFactors = 1 then lRunName := lPredictorList[0] else lRunName := ''; //savedata MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save mean lOutNameMod := ChangeFilePostfixExt(lOutName,'Mean'+lRunName,'.hdr'); if not FileExistsEX(lOutNameMod) then NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgMn,1); //save regression for lFact := 1 to (lnStatFact) do begin if (lFact > lnFactors) and (lnFactors = 1) then begin //nothing end else begin if (lFact > lnFactors) and (lnFactors = 1) then lFactName := 'intercept'+lPredictorList[0] //for analysis of multiple single regressions else if (lFact > lnFactors) then lFactName := 'model' else lFactName := lPredictorList[lFact-1]; MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //NEXT : optional save t-maps //MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,lDF,0,lnVoxTested,kNIFTI_INTENT_TTEST,inttostr(lnVoxTested) ); //lOutNameMod := ChangeFilePostfixExt(lOutName, 'wlsT'+lFactName,'.hdr'); //NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgR[lFact],1); //END: t-maps //next - Z scores MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,lDF,0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); //{ DoF = Nb points - Nb parameters } for lPos := 1 to lVolVox do lOutImgR[lFact]^[lPos] := TtoZ (lOutImgR[lFact]^[lPos],lDF); reportFDR ('wls'+lFactName, lVolVox, lnVoxTested, lOutImgR[lFact]); lOutNameMod := ChangeFilePostfixExt(lOutName, 'wls'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgR[lFact],1); if (lFact = 1) and (TFCEconn > 0) then begin //TFCE //lMinZ := lOutImgR[lFact]^[1]; MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,lDF,0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); doTFCEbothPolarities (lStatHdr, lOutImgR[lFact], TFCEconn {NumConn}, 2.0{H}, 0.5 {E}, 0, lMaxZ/100, 0, lMinZ/100, lMaxTFCEZ, lMaxNegTFCEZ); lOutNameMod := ChangeFilePostfixExt(lOutName, 'tfce'+lFactName,'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgR[lFact],1); end; //TFCE end;//if..else intercept and lnFactors = 1 end;//for each statfactor end; //if lSaveData if (not (lSaveData)) and (TFCEconn > 0) and ((lMaxTFCEZ <> 0) or (lMaxNegTFCEZ <> 0)) then begin //lMinZ := lOutImgR[lFact]^[1]; lFact := 1; MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,lDF,0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); doTFCEbothPolarities (lStatHdr, lOutImgR[lFact], TFCEconn {NumConn}, 2.0{H}, 0.5 {E}, 0, lMaxTFCEZ, 0, lMaxNegTFCEZ, lMaxTFCEZ, lMaxNegTFCEZ) end; //xxx //next: close images for lFact := 1 to (lnStatFact) do freemem(lOutImgR[lFact]); //Freemem(lZp); freemem(lOutImgMn); //freemem(lObsp); freemem(lMaskImg); freemem(lPlankImg); //lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes'+lRunName,'.txt'); //MainForm.MsgSave(lOutNameMod); NPMProgressBar(0); exit; 667: //you only get here if you aborted ... free memory and report error if lVolVox > 1 then freemem(lMaskImg); if lTotalMemory > 1 then freemem(lPlankImg); NPMmsg('Unable to complete analysis.'); NPMProgressBar(0); end; procedure PermuteMatrix(var Src, Dest: PMatrix; lnSubj: integer); //assumes only one column/factor!!! var lRow,lPos: integer; lSwap: double; begin for lRow := 1 to lnSubj do Dest^[1]^[lRow] := Src^[1]^[lRow]; for lRow := lnSubj downto 1 do begin lPos := random(lRow)+1; lSwap := Dest^[1]^[lRow]; Dest^[1]^[lRow] := Dest^[1]^[lPos]; Dest^[1]^[lPos] := lSwap; end; end; function ARegressNPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; var X: PMatrix; lnFactors: integer; var lPredictorList: TStringList; lOutname: string; lnPermute, TFCEconn: integer ): boolean; label 777; var //SaveData: boolean; var lMaxTFCEZ, lMaxNegTFCEZ: single; lMinZ,lMaxZ,lTFCEdh,lNegTFCEdh:double; Xp : PMatrix; lp,lnSubj,lRow : integer; lPermuteMaxZ, lPermuteMinZ,lPermuteMaxTFCEZ, lPermuteMinTFCEZ: singleP; begin InnerARegressNPMAnalyze (lImages, lMaskHdr, X, lnFactors, lPredictorList, lOutname, TRUE,lMinZ,lMaxZ, lMaxNegTFCEZ, lMaxTFCEZ, TFCEconn ); if lnFactors > 1 then goto 777; if (lnPermute < 1) then goto 777; //NPMmsg('0 ObservedzMinMax ' +floattostr(lMinZ)+' '+floattostr(lMaxZ)); NPMmsg('OBSERVED Factor1 zMin zMax zMinTFCE zMaxTFCE ' +floattostr(lMinZ)+' '+floattostr(lMaxZ) +' ' +floattostr(lMaxNegTFCEZ)+' '+floattostr(lMaxTFCEZ)); lnSubj := lImages.Count; DimMatrix(Xp, lnFactors, lnSubj); randomize; getmem(lPermuteMaxZ,lnPermute* sizeof(single)); getmem(lPermuteMinZ,lnPermute* sizeof(single)); getmem(lPermuteMaxTFCEZ,lnPermute* sizeof(single)); getmem(lPermuteMinTFCEZ,lnPermute* sizeof(single)); lTFCEdh := lMaxZ / 100; lNegTFCEdh := abs(lMinZ) / 100; for lp := 1 to lnPermute do begin //for lRow := 1 to lnSubj do // Xp^[1]^[lRow] := X^[1]^[lRow]; lMaxNegTFCEZ := lNegTFCEdh; lMaxTFCEZ := lTFCEdh; PermuteMatrix(X,Xp,lnSubj); InnerARegressNPMAnalyze (lImages, lMaskHdr, Xp, lnFactors, lPredictorList, lOutname, FALSE,lMinZ,lMaxZ,lMaxNegTFCEZ, lMaxTFCEZ, TFCEconn); NPMmsg(inttostr(lp)+' Factor1 zMin zMax zMinTFCE zMaxTFCE ' +floattostr(lMinZ)+' '+floattostr(lMaxZ) +' ' +floattostr(lMaxNegTFCEZ)+' '+floattostr(lMaxTFCEZ)); lPermuteMaxZ^[lp] := lMaxZ; lPermuteMinZ^[lp] := lMinZ; lPermuteMaxTFCEZ^[lp] := lMaxTFCEZ; lPermuteMinTFCEZ^[lp] := lMaxNegTFCEZ; end; DelMatrix(Xp, lnFactors, lnSubj); reportPermute ('Permutation', lnPermute, lPermuteMaxZ, lPermuteMinZ); reportPermute ('TFCEPermutation', lnPermute, lPermuteMaxTFCEZ, lPermuteMinTFCEZ); Freemem(lPermuteMaxZ); Freemem(lPermuteMinZ); Freemem(lPermuteMaxTFCEZ); Freemem(lPermuteMinTFCEZ); 777: NPMmsg('Analysis finished = ' +TimeToStr(Now)); NPMMsgSave( ChangeFilePostfixExt(lOutName,'Notes','.txt')); end; function GetValReg (var lVALFilename: string; var lnSubj,lnFactors: integer; var X : PMatrix; var lImageNames: TStrings; var lPredictorList: TStringList): boolean; var lTemplateName: string; lnRow,lnColWObs,lnCritPct,lInc,lRow,lCol: integer; lDesignUnspecified : boolean; lFileList:TStringList; lInRA: DoubleP0; lInP: Pointer; begin result := false; lnSubj := 0; if not FileExistsEX(lVALFilename) then begin ShowMsg('NPM aborted: VAL file selection failed.'); exit; end; //if not selected NPMmsg( 'VAL filename: '+lVALFilename); lFileList := TStringList.Create; if not OpenValFile (lVALFilename,lTemplateName, lnRow,lnFactors,lnColWObs,lnCritPct, lDesignUnspecified,lPredictorList,lFileList, lInP) then exit; if lnRow > 1 then begin lnSubj := lnRow -1; //top row is predictor {$IFDEF FPC} lInRA := align(lInP,16); {$ELSE} lInRA := DoubleP0($fffffff0 and (integer(lInP)+15)); //lInRA := DoubleP0((integer(lInP) and $FFFFFFF0)+16); {$ENDIF} DimMatrix(X, lnFactors, lnSubj); for lCol := 1 to lnFactors do begin for lRow := 1 to lnSubj do begin //NPMmsg(inttostr( (lRow*lnColWObsAndCovary)-4+lCol )); X^[lCol]^[lRow] := lInRA^[(lRow*lnColWObs)-lnColWObs-1+lCol]; end; end; NPMmsg(inttostr(lnFactors)+' '+inttostr(lnSubj)); for lInc := 1 to lnSubj do lImageNames.add(ExtractFileDirWithPathDelim(lVALFilename)+lFileList.Strings[lInc-1]); result := true; end else result := false; lFileList.free; Freemem(lInP); end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/Vector.pas�����������������������������������������������������0000755�0001750�0001750�00000043354�12156157526�016767� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit Vector; {$Include ..\common\isgui.inc} interface uses SysUtils; //var gMat: boolean = false; type EVectorSizeError = class (Exception); TMatElement = double; //extended; { The 1000 in the array types below does not impose a limit at runtime! If you compile with range checking on then the compiled code will impose an effective limit of 1000, but with range checking off the size of vector is limited to 64K under 16bit OS or *much* greater under 32bit OS } TArrayd = array[1..1000] of TMatElement; pTArrayd = ^TArrayd; TArrayi = array[1..1000] of integer; pTArrayi = ^TArrayi; { Define a dynamic array type for holding integers } TVectori = class (TObject) private s : integer; { size of vector } vx : pTArrayi; { pointer to the data } private procedure SetSize (NewSize : integer); public constructor create (i : integer); virtual; destructor destroy; override; procedure EnlargeBy (n : integer); procedure ReduceBy (n : integer); procedure Enlarge; procedure Reduce; procedure Zero; procedure Clear; procedure Assign (v : TVectori); procedure Setval (i : integer; v : integer); function Getval (i : integer) : integer; function GetSize : integer; property Elem[x : Integer] : integer read GetVal write SetVal; default; property Size : integer read s; end; { Define a dynamic array type for holding Extendeds } TVector = class (TObject) private s : integer; { size of vector } vx : pTArrayd; { pointer to the data } Tmp : boolean; { set to true if temporary } public { Declare as a class method, saves having a self variable } class function Dot (u, v : TVector) : TMatElement; constructor create (i : integer); virtual; constructor createTmp (i : integer); destructor destroy; override; procedure FreeSpace; procedure SetSize (i : integer); procedure EnlargeBy (n : integer); procedure ReduceBy (n : integer); procedure Enlarge; procedure Reduce; procedure Zero; procedure Clear; procedure Setval (i : integer; v : TMatElement); function Getval (i : integer) : TMatElement; property Elem[x : Integer] : TMatElement read GetVal write SetVal; default; property Size : integer read s; procedure Assign (v : TVector); function Add (v, u : TVector) : TVector; function Sub (v, u : TVector) : TVector; class function xAdd (v, u : TVector) : TVector; class function xSub (v, u : TVector) : TVector; function DotU (v : TVector) : TMatElement; function CrossU (v : TVector) : TVector; function Cross (v1, v2 : TVector) : TVector; function Sum : TMatElement; function Mean : TMatElement; function SumofSquares : TMatElement; function Norm : TMatElement; function StdDev : TMatElement; procedure Scale (factor : TMatElement); end; implementation // ------------------------------------------------------------------------- // START OF VECTOR TYPE IMPLEMETATION // ------------------------------------------------------------------------- { The data space which holds the data for a vector is typed as [1..x] so that indexing autmatically starts at one, therefore there is no need in the following code to add 1 to the size of the vector when creating or destroying it } { Create a vector of size i } constructor TVector.create(i : integer); begin Inherited Create; s := 0; vx := Nil; { vx set to Nil to indicate empty vector, used by SetSize } if i > 0 then Self.SetSize (i); end; constructor TVector.createTmp (i : integer); begin Inherited Create; s := 0; vx := Nil; { vx set to Nil to indicate empty vector, used by SetSize } if i > 0 then Self.SetSize (i); Tmp := true; end; destructor TVector.destroy; begin FreeSpace; Inherited Destroy; end; { Private internal procedure } procedure TVector.FreeSpace; begin if vx <> Nil then FreeMem (vx, sizeof (TMatElement) * s); vx := Nil; s := 0; end; { Internal routine to allocate space. If space already exists then it frees it first } procedure TVector.SetSize (i : integer); begin if vx <> Nil then FreeMem (vx, sizeof (TMatElement) * s); s := i; vx := AllocMem (sizeof (TMatElement) * s); //if gMat then beep; end; { Increase the size of the vector without destroying and existing data } procedure TVector.EnLargeBy (n : integer); begin if n < 0 then raise EVectorSizeError.Create ('Argument to EnLargeBy must be positive'); ReAllocMem (vx, sizeof (TMatElement)*(s+n)); inc (s,n); { Modified for D2 } end; { Reduce the size of the vector } procedure TVector.ReduceBy (n : integer); begin if n >= s then raise EVectorSizeError.Create ('Can''t reduce size of vector to below zero elements'); ReAllocMem (vx, sizeof (TMatElement)*(s-n)); dec (s,n); { modified for D2 } end; { Enlarge the vector by one element without destroying any existing data } procedure TVector.Enlarge; begin ReAllocMem (vx, sizeof (TMatElement)*(s+1)); inc (s); { Modified for D2 } end; { Reduce the vector by one element, the top most element is destroyed } procedure TVector.Reduce; begin ReAllocMem (vx, sizeof (TMatElement)*(s-1)); dec (s); { Modified for D2 } end; { Clears the vector, sets all elements to zero } procedure TVector.Zero; var i : integer; begin for i := 1 to s do vx^[i] := 0.0; end; { Clears the vector, sets all elements to zero } procedure TVector.Clear; begin Zero; end; { used internally but is also accessible from the outside } procedure TVector.Setval (i : integer; v : TMatElement); begin vx^[i] := v; end; { used internally but is also accessible from the outside } function TVector.Getval (i : integer) : TMatElement; begin result := vx^[i]; end; // ------------------------------------------------------------------------- // Copies vector v, including contects to self. If self is not the same // size as v then self is resized // Copy v to u: // Usage: u.Assign (v) // ------------------------------------------------------------------------- procedure TVector.Assign (v : TVector); begin v.Tmp := False; { just in case its a temporary variable } if v.s <> Self.s then Self.SetSize (v.s); move (v.vx^, Self.vx^, sizeof(TMatElement) * s) end; // ------------------------------------------------------------------------- // Add the vectors, 'v' and 'u' together to produce Self. Error if v and u are // the the same size. If Self is not sized correctly, then Add will resize Self // Usage: w.Add (u, v) // Add u to v giving result w // ------------------------------------------------------------------------- function TVector.Add (v, u : TVector) : TVector; var i : integer; begin if v.s <> u.s then raise EVectorSizeError.Create ('Vectors must be the same size to sum them'); if Self.s <> v.s then Self.SetSize (v.s); for i := 1 to v.s do Self[i] := v[i] + u[i]; if v.tmp then v.free; if u.tmp then u.free; result := Self; end; // ------------------------------------------------------------------------- // Add the vectors, 'v' and 'u' together and RETURN the result. An Error // occurs if v and u are the the same size. xAdd returns the result to the // caller therefore it is the responsibility of the caller to dispose of the // memory allocated by xSub. Note, the variable which is used to store the // returned result must not have been previously allocated, otherwise you'll // get memory leak! // w must be unallocated // Usage: w := Add (u, v) // Add u to v giving result w // ------------------------------------------------------------------------- class function TVector.xAdd (v, u : TVector) : TVector; var i : integer; t : TVector; begin if v.s <> u.s then raise EVectorSizeError.Create ('Vectors must be the same size to sum them'); t := TVector.CreateTmp (v.s); for i := 1 to v.s do t[i] := v[i] + u[i]; result := t; end; // ------------------------------------------------------------------------- // Subtract the vectors, 'v' and 'u' together to produce Self. Error if v and u are // the the same size. If Self is not sized correctly, then Add will resize Self // Usage: w.Sub (u, v) // Add u to v giving result w // ------------------------------------------------------------------------- function TVector.Sub (v, u : TVector) : TVector; var i : integer; begin if v.s <> u.s then raise EVectorSizeError.Create ('Vectors must be the same size to subtract them'); if Self.s <> v.s then Self.SetSize (v.s); for i := 1 to v.s do Self[i] := v[i] - u[i]; if v.tmp then v.free; if u.tmp then u.free; result := Self; end; // ------------------------------------------------------------------------- // Subtract the vectors, 'v' and 'u' together and RETURN the result. An Error // occurs if v and u are the the same size. xSub returns the result to the // caller therefore it is the responsibility of the caller to dispose of the // memory allocated by xSub. Note, the variable which is used to store the // returned result must not have been previously allocated, otherwise you'll // get memory leak! // w must be unallocated // Usage: w := Sub (u, v) // Add u to v giving result w // ------------------------------------------------------------------------- class function TVector.xSub (v, u : TVector) : TVector; var i : integer; t : TVector; begin if v.s <> u.s then raise EVectorSizeError.Create ('Vectors must be the same size to subtract them'); t := TVector.CreateTmp (v.s); for i := 1 to v.s do t[i] := v[i] - u[i]; result := t; end; // ------------------------------------------------------------------------- // Compute the dot product of vectors 'u' and 'v' // Usage: d := dot (u, v); // ------------------------------------------------------------------------- class function TVector.Dot (u, v : TVector) : TMatElement; var i : integer; begin if u.Size <> v.Size then raise EVectorSizeError.Create ('Vectors must be of the same size to compute dot product'); result := 0.0; for i := 1 to u.Size do result := result + u[i]*v[i]; end; // ------------------------------------------------------------------------- // Apply a dot product to Self and argument, 'v' // Usage: d := u.dotU (v); // ------------------------------------------------------------------------- function TVector.DotU (v : TVector) : TMatElement; var i : integer; begin if Self.Size <> v.Size then raise EVectorSizeError.Create ('Vectors must be of the same size to compute dot product'); result := 0.0; for i := 1 to Self.Size do result := result + Self[i]*v[i]; end; // ------------------------------------------------------------------------- // Compute the cross product of Self and vector 'v', replacing Self // Usage: v.CrossU (u) // ------------------------------------------------------------------------- function TVector.CrossU (v : TVector) : TVector; begin if (v.Size = 3) and (Self.Size = 3) then begin Self[1] := Self[2]*v[3] - Self[3]*v[2]; Self[2] := Self[3]*v[1] - Self[1]*v[3]; Self[3] := Self[1]*v[2] - Self[2]*v[1]; result := Self; end else raise EVectorSizeError.Create ('Cross product can only be calculated for vectors in 3D'); end; // ------------------------------------------------------------------------- // Compute the cross product of 'v1' and vector 'v2' giving Self // Usage: v.Cross (v1, v2) // ------------------------------------------------------------------------- function TVector.Cross (v1, v2 : TVector) : TVector; begin if (v1.Size = 3) and (v2.Size = 3) and (Self.Size = 3) then begin Self[1] := v1[2]*v2[3] - v1[3]*v2[2]; Self[2] := v1[3]*v2[1] - v1[1]*v2[3]; Self[3] := v1[1]*v2[2] - v1[2]*v2[1]; result := Self; end else raise EVectorSizeError.Create ('Cross product can only be calculated for vectors in 3D'); end; // ------------------------------------------------------------------------- // Returns the sum of values in the vector // Usage: total := v.sum // ------------------------------------------------------------------------- function TVector.Sum : TMatElement; var i : integer; begin result := 0.0; for i := 1 to s do result := result + vx^[i]; end; // ------------------------------------------------------------------------- // Returns the mean of the elements of the vector // Usage: average := v.mean; // ------------------------------------------------------------------------- function TVector.Mean : TMatElement; begin if s > 0 then result := sum / s else raise Exception.Create ('Vector must have at least one element to compute mean'); end; // ------------------------------------------------------------------------- // Returns the sum of the squares of values in Data // Usage: s := v.SumOfSquares; // ------------------------------------------------------------------------- function TVector.SumOfSquares : TMatElement; var i : integer; begin result := 0.0; for i := 1 to s do result := result + sqr(vx^[i]); end; // ------------------------------------------------------------------------- // Returns the Euclidean norm of the Self vector // ------------------------------------------------------------------------- function TVector.Norm : TMatElement; begin result := sqrt (Self.SumOfSquares); end; // ------------------------------------------------------------------------- // Returns the sample standard deviation // Usage: sd := v.StdDev; // ------------------------------------------------------------------------- function TVector.StdDev : TMatElement; var sq, total : TMatElement; i : integer; begin sq := 0; total := 0; if s > 1 then begin for i := 1 to s do begin sq := sq + sqr(vx^[i]); total := total + vx^[i]; end; result := sqrt ((sq - sqr(total)/s)/(s-1)); // The following code is easier to read but slightly slower in execution: // result := sqrt ((SumOfSquares - sqr (sum)/s)/(s-1));} end else raise Exception.Create ('Can''t calculate stddev for vector with one or no elements'); end; // ------------------------------------------------------------------------- // Scale the vector by factor // Usage: v.Scale (2) Multiplies all elements by 2 // ------------------------------------------------------------------------- procedure TVector.Scale (factor : TMatElement); var i : integer; begin for i := 1 to s do vx^[i] := vx^[i]*factor; end; { ------------------------------------------------------------------------- } { START OF INTEGER VECTOR IMPLEMETATION } { ------------------------------------------------------------------------- } { Create a vector of size i } constructor TVectori.create(i : integer); begin Inherited Create; vx := Nil; Self.SetSize (i); end; destructor TVectori.destroy; begin if vx <> Nil then FreeMem (vx, sizeof (integer) * s); Inherited Destroy; end; { Internal routine used by define } procedure TVectori.SetSize (NewSize : integer); begin if vx <> Nil then FreeMem (vx, sizeof (integer) * s); s := NewSize; vx := AllocMem (sizeof (integer) * NewSize); end; procedure TVectori.EnLargeBy (n : integer); begin ReAllocMem (vx, sizeof (integer)*(s+n)); inc (s,n); { Modified for D2 } end; procedure TVectori.ReduceBy (n : integer); begin if n >= s then raise EVectorSizeError.Create ('Can''t reduce size of vector to below zero elements'); ReAllocMem (vx, sizeof (integer)*(s-n)); dec (s,n); { Modified for D2 } end; { Enlarge the vector by one element without destroying any existing data } procedure TVectori.Enlarge; begin ReAllocMem (vx, sizeof (integer)*(s+1)); inc (s); { Modified for D2 } end; { Reduce the vector by one element, the top most element is destroyed } procedure TVectori.Reduce; begin ReAllocMem (vx, sizeof (integer)*(s-1)); dec (s); { Modified for D2 } end; { Clear the vector, sets all elements to zero } procedure TVectori.Zero; var i : integer; begin for i := 1 to s do vx^[i] := 0; end; { Clear the vector, sets all elements to zero } procedure TVectori.Clear; begin Zero; end; procedure TVectori.Assign (v : TVectori); begin if v.s <> Self.s then Self.SetSize (v.s); move (v.vx^, Self.vx^, sizeof(integer) * s) end; { used internally but is also accessible from the outside } procedure TVectori.Setval (i : integer; v : integer); begin vx^[i] := v; end; { used internally but is also accessible from the outside } function TVectori.Getval (i : integer) : integer; begin result := vx^[i]; end; function TVectori.GetSize : integer; begin result := s; end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/npmform.pas����������������������������������������������������0000755�0001750�0001750�00000231051�12306741004�017157� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit npmform; {$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF} {$DEFINE SINGLETHREAD} //{$DEFINE FIRTHNOTHREAD} interface {$I options.inc} uses define_types,SysUtils, part,StatThds,statcr,StatThdsUtil,Brunner,DISTR,nifti_img, Messages, userDir, Classes, Graphics, Controls, Forms, DialogsX,Dialogs, nifti_types , Menus, ComCtrls, ExtCtrls, StdCtrls, overlap,ReadInt,lesion_pattern,stats,LesionStatThds,nifti_hdr, {$IFDEF FPC} LResources,gzio2, {$ELSE} gziod,associate,{$ENDIF} //must be in search path, e.g. C:\pas\mricron\npm\math {$IFNDEF UNIX} Windows, {$ELSE} LCLType, {$ENDIF} upower,firthThds,firth,IniFiles,cpucount,math, regmult,utypes,turbolesion {$IFDEF compileANACOM}, anacom{$ENDIF} {$IFDEF benchmark}, montecarlo{$ENDIF} ; //regmultdelphi,matrices; type { TMainForm } TMainForm = class(TForm) Binaryimagescontinuousgroupsfast1: TMenuItem; Memo1: TMemo; Design1: TMenuItem; //PlankSzMenuItem1: TMenuItem; DualImageCorrelation1: TMenuItem; MultipleRegress: TMenuItem; SaveText1: TMenuItem; ROIanalysis1: TMenuItem; OpenHdrDlg: TOpenDialog; SaveHdrDlg: TSaveDialog; Panel1: TPanel; ProgressBar1: TProgressBar; MainMenu1: TMainMenu; About1: TMenuItem; AssociatevalfileswithNPM1: TMenuItem; Balance1: TMenuItem; BinomialAnalysislesions1: TMenuItem; BMmenu: TMenuItem; ContinuousanalysisVBM1: TMenuItem; Copy1: TMenuItem; Edit1: TMenuItem; Exit1: TMenuItem; File1: TMenuItem; Help1: TMenuItem; IntensitynormalizationA1: TMenuItem; Makemeanimage1: TMenuItem; Makemeanimage2: TMenuItem; N0: TMenuItem; N1000: TMenuItem; N2000: TMenuItem; N3000: TMenuItem; N4000: TMenuItem; Options1: TMenuItem; PairedTMenu: TMenuItem; PenalizedLogisticRegerssion1: TMenuItem; Permutations1: TMenuItem; SingleRegress: TMenuItem; SingleSubjectZScores1: TMenuItem; T1: TMenuItem; T15: TMenuItem; T16: TMenuItem; T2: TMenuItem; T3: TMenuItem; T4: TMenuItem; T7: TMenuItem; T8: TMenuItem; Tests1: TMenuItem; Threads1: TMenuItem; //StartTimer: TTimer; ttestmenu: TMenuItem; Utilities1: TMenuItem; Variance1: TMenuItem; VBM1: TMenuItem; VLSM1: TMenuItem; Intensitynormalization1: TMenuItem; Masked1: TMenuItem; MaskedintensitynormalizationA1: TMenuItem; MaskedintensitynormalizationB1: TMenuItem; Binarizeimages1: TMenuItem; PlankSzMenuItem1: TMenuItem; //Setnonseroto1001: TMenuItem; //AnaCOMmenu: TMenuItem; //MonteCarloSimulation1: TMenuItem; //Subtract1: TMenuItem; //LogPtoZ1: TMenuItem; procedure PlankSzMenuItem1Click(Sender: TObject); procedure NPMmsgUI( lStr: string); procedure NPMmsgClearUI; procedure NPMmsgSaveUI(lFilename: string); //procedure ProcessParamStr; function GetValX (var lnSubj, lnFactors: integer; var lSymptomRA: singleP; var lImageNames: TStrings; var lCrit: integer; {lBinomial : boolean;} var lPredictorList: TStringList):boolean; function FirthNPMAnalyze (var lImages: TStrings; var lPredictorList: TStringList; var lMaskHdr: TMRIcroHdr; lnCond,lnCrit: integer; var lSymptomRA: SingleP; var lOutName: string): boolean; procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); function SaveHdrName (lCaption: string; var lFilename: string): boolean; procedure NPMclick(Sender: TObject); function OpenDialogExecute (lCaption: string;lAllowMultiSelect,lForceMultiSelect: boolean; lFilter: string): boolean;//; lAllowMultiSelect: boolean): boolean; //function NPMAnalyze (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lMaskVoxels,lnGroup1: integer): boolean; //function NPMAnalyzePaired (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lMaskVoxels: integer): boolean; procedure FormCreate(Sender: TObject); //function MakeSubtract (lPosName,lNegName: string): boolean; //function MakeMean (var lImages: TStrings; var lMaskHdr: TMRIcroHdr; lBinarize,lVariance: boolean): boolean; //function Balance (var lImageName,lMaskName: String; lMethod: integer{lInflection: boolean}): boolean; procedure LesionBtnClick(Sender: TObject); procedure Copy1Click(Sender: TObject); //procedure StartTimerTimer(Sender: TObject); procedure testmenuclick(Sender: TObject); procedure radiomenuclick(Sender: TObject); procedure Makemeanimage1Click(Sender: TObject); procedure Exit1Click(Sender: TObject); procedure Balance1Click(Sender: TObject); procedure Variance1Click(Sender: TObject); procedure About1Click(Sender: TObject); procedure Design1Click(Sender: TObject); procedure DualImageCorrelation1Click(Sender: TObject); procedure FormShow(Sender: TObject); procedure PairedTMenuClick(Sender: TObject); procedure SingleSubjectZScores1Click(Sender: TObject); procedure MultipleRegressClick(Sender: TObject); function ReadPermute: integer; procedure SingleRegressClick(Sender: TObject); procedure AssociatevalfileswithNPM1Click(Sender: TObject); procedure threadChange(Sender: TObject); //procedure Countlesionoverlaps1Click(Sender: TObject); procedure PenalizedLogisticRegerssion1Click(Sender: TObject); //procedure ROCbinomialdeficit1Click(Sender: TObject); //procedure ROCcontinuousdeficit1Click(Sender: TObject); procedure ThreadDone(Sender: TObject); procedure ROIanalysis1Click(Sender: TObject); procedure Masked1Click(Sender: TObject); procedure Binarizeimages1Click(Sender: TObject); procedure Setnonseroto1001Click(Sender: TObject); procedure Savetext1Click(Sender: TObject); //procedure Subtract1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var MainForm: TMainForm; implementation uses unpm, filename,prefs,hdr,roc,regression,valformat {$IFDEF SPREADSHEET} ,design,spread{$ENDIF} {$IFNDEF UNIX},ActiveX {$ENDIF}; {$IFNDEF FPC} {$R *.DFM} {$ENDIF} (*function WarnIfLowNCrit(lnSubj,lnCrit: integer): boolean; //returns true if warning generated begin result := (round(lnSubj * 0.15) ) > lnCrit; //15% if result then Showmessage('Warning: low statistical power as tests computed for voxels damaged in at least '+inttostr(lnCrit) +' people. Solution: change Design value "Ignore voxels damaged in less than N%".'); end; *) procedure TMainForm.NPMmsgUI( lStr: string); begin Memo1.Lines.add(lStr); end; procedure TMainForm.PlankSzMenuItem1Click(Sender: TObject); var str : string; v,max: integer; begin {$IFDEF CPU32} max := 1536; {$ELSE} max := 8000; {$ENDIF} str := inttostr(gNPMPrefs.PlankMB); if not InputQuery('Specify cache size', 'Mb for computation (256..'+inttostr(max)+')', str) then exit; try v := StrToInt(str); // Trailing blanks are not supported except on Exception : EConvertError do begin ShowMessage(Exception.Message); exit; end; end; if (v < 256) then v := 256; if v > max then v := max; gNPMPrefs.PlankMB := v; NPMMsgClear; NPMMsg(GetKVers); ComputePlankSize(gNPMPrefs.PlankMB); end; procedure TMainForm.NPMmsgClearUI; begin Memo1.Lines.Clear; end; procedure TMainForm.NPMMsgSaveUI(lFilename: string); var i: integer; f: textfile; begin if (Memo1.Lines.Count < 1) then exit; if fileexists(lFilename) then begin AssignFile(f, lFilename); {$I-} append(f); {$I+} if IOResult= 0 then for i:= 0 to Memo1.Lines.Count- 1 do WriteLn(f, Memo1.Lines[i]); CloseFile(f); end else MainForm.Memo1.Lines.SaveToFile(lFilename); end; procedure TMainForm.ThreadDone(Sender: TObject); begin Dec(gThreadsRunning); end; function TMainForm.SaveHdrName (lCaption: string; var lFilename: string): boolean; begin result := false; SaveHdrDlg.InitialDir := lFilename; SaveHdrDlg.Title := lCaption; SaveHdrDlg.Filter := kAnaHdrFilter; if not SaveHdrDlg.Execute then exit; lFilename := SaveHdrDlg.Filename; result := true; end; procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin WriteIniFile; end; procedure WriteThread( lnThread: integer); begin case lnThread of 2: MainForm.T2.checked := true; 3: MainForm.T3.checked := true; 4: MainForm.T4.checked := true; 7: MainForm.T7.checked := true; 8: MainForm.T8.checked := true; 15: MainForm.T15.checked := true; 16: MainForm.T16.checked := true; else MainForm.T1.checked := true; end; gnCPUThreads := lnThread; end; function ReadThread: integer; begin if MainForm.T16.checked then result := 16 else if MainForm.T15.checked then result := 15 else if MainForm.T8.checked then result := 8 else if MainForm.T7.checked then result := 7 else if MainForm.T4.checked then result := 4 else if MainForm.T3.checked then result := 3 else if MainForm.T2.checked then result := 2 else result := 1; gnCPUThreads := result; end; procedure WritePermute( lnPermute: integer); begin case lnPermute of 4000: MainForm.N4000.checked := true; 3000: MainForm.N3000.checked := true; 2000: MainForm.N2000.checked := true; 1000: MainForm.N1000.checked := true; else MainForm.N0.checked := true; end; end; function TMainForm.ReadPermute: integer; begin if MainForm.N4000.checked then result := 4000 else if MainForm.N3000.checked then result := 3000 else if MainForm.N2000.checked then result := 2000 else if MainForm.N1000.checked then result := 1000 else result := 0; end; function TMainForm.OpenDialogExecute (lCaption: string;lAllowMultiSelect,lForceMultiSelect: boolean; lFilter: string): boolean;//; lAllowMultiSelect: boolean): boolean; var lNumberofFiles: integer; begin OpenHdrDlg.Filter := lFilter;//kAnaHdrFilter;//lFilter; OpenHdrDlg.FilterIndex := 1; OpenHdrDlg.Title := lCaption; if lAllowMultiSelect then OpenHdrDlg.Options := [ofAllowMultiSelect,ofFileMustExist] else OpenHdrDlg.Options := [ofFileMustExist]; result := OpenHdrDlg.Execute; if not result then exit; if lForceMultiSelect then begin lNumberofFiles:= OpenHdrDlg.Files.Count; if lNumberofFiles < 2 then begin ShowMsg('Error: This function is designed to overlay MULTIPLE images. You selected less than two images.'); result := false; end; end; end; procedure TMainForm.NPMclick(Sender: TObject); label 666; var lnGroup1,lMaskVoxels: integer; lG: TStrings; lMaskname, lOutName: string; lMaskHdr: TMRIcroHdr; begin if (not ttestmenu.checked) and (not BMmenu.checked) then begin ShowMsg('Error: you need to compute at least on test [options/test menu]'); exit; end; if not OpenDialogExecute('Select brain mask ',false,false,kImgFilter) then begin ShowMsg('NPM aborted: mask selection failed.'); exit; end; //if not selected lMaskname := OpenHdrDlg.Filename; (*if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showMsg('Error reading mask.'); exit; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin ShowMsg('Mask file size too small.'); exit; end; *) //next, get 1st group if not OpenDialogExecute('Select postive group (Z scores positive if this group is brighter)',true,true,kImgFilter) then begin ShowMsg('NPM aborted: file selection failed.'); exit; end; //if not selected lG:= TStringList.Create; //not sure why TStrings.Create does not work??? lG.addstrings(OpenHdrDlg.Files); lnGroup1 :=OpenHdrDlg.Files.Count; //next, get 2nd group if not OpenDialogExecute('Select negative group (Z scores negative if this group is brighter)',true,true,kImgFilter) then begin ShowMsg('NPM aborted: file selection failed.'); goto 666; end; //if not selected lG.addstrings(OpenHdrDlg.Files); if not CheckVoxelsGroupX(lG,lMaskHdr {lMaskVoxels}) then begin ShowMsg('File dimensions differ from mask.'); goto 666; end; lOutName := lMaskHdr.ImgFileName; if not SaveHdrName ('Statistical Map', lOutName) then exit; NPMAnalyze(lG,lMaskName,lMaskVoxels,lnGroup1,gNPMPrefs,lOutName); 666: lG.Free; end; function TMainForm.GetValX (var lnSubj, lnFactors: integer; var lSymptomRA: singleP; var lImageNames: TStrings; var lCrit: integer; var lPredictorList: TStringList):boolean; //warning: you MUST free lPredictorList var lVALFilename: string; lCritPct: integer; begin lPredictorList := TStringList.Create; result := false; lnSubj := 0; if not MainForm.OpenDialogExecute('Select MRIcron VAL file',false,false,'MRIcron VAL (*.val)|*.val') then begin ShowMsg('NPM aborted: VAL file selection failed.'); exit; end; //if not selected lVALFilename := MainForm.OpenHdrDlg.Filename; result := GetValCore ( lVALFilename, lnSubj, lnFactors, lSymptomRA, lImageNames, lCrit,lCritPct{,binom},lPredictorList); end; procedure TMainForm.Copy1Click(Sender: TObject); begin Memo1.SelectAll; Memo1.CopyToClipboard; end; (*procedure TMainForm.StartTimerTimer(Sender: TObject); begin if StartTimer.Tag < 2 then begin StartTimer.tag := StartTimer.tag + 1; exit; end; StartTimer.Enabled := false; //if (ParamCount > 0) then ProcessParamStr; end; *) procedure TMainForm.testmenuclick(Sender: TObject); begin (sender as TMenuItem).checked := not (sender as TMenuItem).checked; gNPMprefs.BMtest := BMmenu.Checked; gNPMprefs.ttest := TTestmenu.Checked; end; procedure TMainForm.radiomenuclick(Sender: TObject); begin (sender as tmenuitem).checked := true; gNPMprefs.nPermute:= readPermute; end; procedure TMainForm.FormCreate(Sender: TObject); begin {$IFDEF Darwin} File1.visible := false;//for OSX, exit is in the application's menu //Edit1.visible := false;//clipboard note yet working for OSX {$ENDIF} {$IFDEF FPC} Application.ShowButtonGlyphs := sbgNever; {$ENDIF} {$IFDEF Darwin} {$IFNDEF LCLgtk} //only for Carbon compile Copy1.ShortCut := ShortCut(Word('C'), [ssMeta]); BinomialAnalysislesions1.ShortCut := ShortCut(Word('B'), [ssMeta]); Binaryimagescontinuousgroupsfast1.ShortCut := ShortCut(Word('L'), [ssMeta]); Design1.ShortCut := ShortCut(Word('D'), [ssMeta]); ContinuousanalysisVBM1.ShortCut := ShortCut(Word('V'), [ssMeta]); MultipleRegress.ShortCut := ShortCut(Word('R'), [ssMeta]); Makemeanimage1.ShortCut := ShortCut(Word('M'), [ssMeta]); About1.ShortCut := ShortCut(Word('A'), [ssMeta]); {$ENDIF}//Carbon {$ENDIF}//Darwin gnCPUThreads := GetLogicalCpuCount; (*if (ssShift in KeyDataToShiftState(vk_Shift)) then begin case MessageDlg('Shift key down during launch: do you want to reset the default preferences?', mtConfirmation, [mbYes, mbNo], 0) of { produce the message dialog box } mrNo: ReadIniFile; end; //case end else *) if not ResetDefaults then ReadIniFile; ttestmenu.checked := gNPMprefs.ttest; bmmenu.Checked:= gNPMprefs.BMtest; WritePermute(gNPMprefs.nPermute); WriteThread(gnCPUThreads); end; (*procedure TMainForm.Makemeanimage1Click(Sender: TObject); label 666; var lG: TStrings; loutname: string; begin if not OpenDialogExecute('Select images to average',true,true,kImgFilter) then begin ShowMsg('NPM aborted: file selection failed.'); exit; end; //if not selected if not SaveHdrName ('Output image', lOutName) then exit; lG:= TStringList.Create; lG.addstrings(OpenHdrDlg.Files); MakeMean(lG,odd((Sender as TMenuItem).tag),false,loutname); 666: lG.Free; end; *) procedure TMainForm.Makemeanimage1Click(Sender: TObject); var loutname: string; begin if not OpenDialogExecute('Select images to average666',true,true,kImgFilter) then begin ShowMsg('NPM aborted: file selection failed.'); exit; end; //if not selected if not SaveHdrName ('Output image', lOutName) then exit; MakeMean(OpenHdrDlg.Files,odd((Sender as TMenuItem).tag),false,loutname); end; procedure TMainForm.Exit1Click(Sender: TObject); begin Close; end; (*procedure CopyFileEXoverwrite (lInName,lOutName: string); var lFSize: Integer; lBuff: bytep0; lFData: file; begin lFSize := FSize(lInName); if (lFSize < 1) then exit; assignfile(lFdata,lInName); filemode := 0; reset(lFdata,lFSize{1}); GetMem( lBuff, lFSize); BlockRead(lFdata, lBuff^, 1{lFSize}); closefile(lFdata); assignfile(lFdata,lOutName); filemode := 2; Rewrite(lFdata,lFSize); BlockWrite(lFdata,lBuff^, 1 {, NumWritten}); closefile(lFdata); freemem(lBuff); end;*) procedure TMainForm.Balance1Click(Sender: TObject); var lFilename,lMaskName: string; lPos: Integer; begin NPMMsgClear; NPMMsg(GetKVers); if not OpenDialogExecute('Select images for intensity normalization',true,false,kImgFilter) then begin ShowMsg('NPM aborted: file selection failed.'); exit; end; //if not selected if OpenHdrDlg.Files.Count < 1 then exit; lMaskName := ''; for lPos := 1 to OpenHdrDlg.Files.Count do begin lFilename := OpenHdrDlg.Files[lPos-1]; balance(lFilename,lMaskname,(Sender as TMenuItem).tag); end; end; procedure TMainForm.Variance1Click(Sender: TObject); label 666; var lMaskVoxels: integer; lG: TStrings; lMaskname,loutname: string; lMaskHdr: TMRIcroHdr; begin NPMMsgClear; NPMMsg(GetKVers); if not OpenDialogExecute('Select 2 images)',true,true,kImgFilter) then begin ShowMsg('NPM aborted: file selection failed.'); exit; end; //if not selected lG:= TStringList.Create; lG.addstrings(OpenHdrDlg.Files); if lG.count <> 2 then begin ShowMsg('You must select exactly two image.'); goto 666; end; if not SaveHdrName ('Output image', lOutName) then exit; MakeMean(lG, odd((Sender as TMenuItem).tag),true,loutname); 666: lG.Free; end; procedure TMainForm.About1Click(Sender: TObject); begin ShowMsg(GetkVers ); end; procedure TMainForm.Design1Click(Sender: TObject); begin {$IFDEF SPREADSHEET} SpreadForm.Show; {$ELSE} ShowMsg('Spreadsheet not yet supported on the Operating System');{$ENDIF} end; function AddNumStr(var X : PMatrix; var lNumStr: string; lRow,lCol: integer):boolean; var lTempFloat: double; begin result := false; if (lNumStr = '') or (lRow < 1) or (lCol < 1) then exit; try lTempFloat := strtofloat(lNumStr); except on EConvertError do begin ShowMsg('Empty cells? Error reading TXT file row:'+inttostr(lRow)+' col:'+inttostr(lCol)+' - Unable to convert the string '+lNumStr+' to a number'); exit; end; end; //fx(lRow,lCol,lTempFloat); X^[lCol]^[lRow] := lTempFloat; lNumStr := ''; result := true; end; function ReadPairedFilenamesReg(var lImageNames: TStrings; var X : PMatrix; var lnAdditionalFactors: integer): boolean; var lLen,lPos,lSep,lMaxSep,lLine: integer; lFilenames,lF1,lF2,lNumStr: string; lImageNames2: TStrings; lF: TextFile; begin result := false; ShowMsg('Please select a text file with the image names. '+kCR+ 'Each line of the file should specify the control and experimental filenames, separated by an *'+kCR+ 'C:\vbmdata\c1.nii.gz*C:\vbmdata\e1.nii.gz'+kCR + 'C:\vbmdata\c2.nii.gz*C:\vbmdata\e2.nii.gz'+kCR+ 'C:\vbmdata\c3.nii.gz*C:\vbmdata\e3.nii.gz'+kCR+ '...' ); if not MainForm.OpenDialogExecute('Select asterix separated filenames ',false,false,kTxtFilter) then exit; lImageNames2:= TStringList.Create; //not sure why TStrings.Create does not work??? //xxx assignfile(lF,MainForm.OpenHdrDlg.FileName ); FileMode := 0; //read only reset(lF); while not EOF(lF) do begin readln(lF,lFilenames); lLen := length(lFilenames); if lLen > 0 then begin lF1:= ''; lF2 := ''; lPos := 1; while (lPos <= lLen) and (lFilenames[lPos] <> '*') do begin lF1 := lF1 + lFilenames[lPos]; inc(lPos); end; inc(lPos); while (lPos <= lLen) and (lFilenames[lPos] <> '*') do begin lF2 := lF2 + lFilenames[lPos]; inc(lPos); end; if (length(lF1) > 0) and (length(lF2)>0) then begin if Fileexists4D(lF1) then begin if Fileexists4D(lF2) then begin lImageNames.add(lF1); lImageNames2.add(lF2); end else //F2exists ShowMsg('Can not find image '+lF2); end else //F1 exists ShowMsg('Can not find image '+lF1); end; end;//len>0 end; //while not EOF //fx(lImageNames.count); //next - count additional factors lnAdditionalFactors := 0; reset(lF); lMaxSep := 0; while not EOF(lF) do begin readln(lF,lFilenames); lLen := length(lFilenames); lSep := 0; if lLen > 0 then begin for lPos := 1 to lLen do if lFilenames[lPos] = '*' then inc(lSep) end;//len>0 if lSep > lMaxSep then lMaxSep := lSep; end; //while not EOF if (lMaxSep > 1) and (lImageNames2.count > 1) then begin //additional factors present //final pas - load additional factors lnAdditionalFactors := lMaxSep - 1; DimMatrix(X, lnAdditionalFactors, lImageNames2.count); reset(lF); lLine := 0; while not EOF(lF) do begin readln(lF,lFilenames); lLen := length(lFilenames); lSep := 0; if lLen > 0 then begin inc(lLine); lPos := 1; lNumStr := ''; while lPos <= lLen do begin if (lFilenames[lPos] = '*') then begin AddNumStr(X,lNumStr,lLine,lSep-1); inc(lSep); end else if (lSep >= 2) and (not (lFilenames[lPos] in [#10,#13,#9]) ) then begin lNumStr := lNumStr+lFilenames[lPos]; //ShowMsg(lNumStr); end; inc(lPos); end; //while not EOLN AddNumStr(X,lNumStr,lLine,lSep-1); end;//len>0 end; //while not EOF //next - read final line of unterminated string... end;//maxsepa > 1 //2nd pass vals closefile(lF); FileMode := 2; //read/write if (lImageNames.count > 0) and (lImageNames2.count = lImageNames.count) then begin lImageNames.AddStrings(lImageNames2); result := true; end; lImageNames2.Free; result := true; end; procedure TMainForm.DualImageCorrelation1Click(Sender: TObject); label 666; var lnSubj,lSubj,lMaskVoxels,lnAdditionalFactors,lI: integer; lImageNames: TStrings; X: PMatrix; lMaskname,lStr,lOutName: string; lMaskHdr: TMRIcroHdr; begin lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? NPMMsgClear; NPMMsg(GetKVers); NPMMsg('Dual-image Linear Regression [Weighted Least Squares]'); if not OpenDialogExecute('Select brain mask ',false,false,kImgFilter) then begin ShowMsg('NPM aborted: mask selection failed.'); goto 666; end; //if not selected lMaskname := OpenHdrDlg.Filename; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin ShowMsg('Error reading Mask image.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin ShowMsg('Mask file size too small.'); goto 666; end; if not ReadPairedFilenamesReg(lImageNames,X,lnAdditionalFactors) then exit; lnSubj :=lImageNames.Count div 2; //fx(lnAdditionalFactors); //show matrix //MsgStrings (lImageNames); NPMMsg ('n Subjects = '+inttostr(lnSubj)); for lSubj := 0 to (lnSubj-1) do begin lStr := lImageNames[lSubj]+' <-> '+lImageNames[lSubj+lnSubj]; if lnAdditionalFactors > 0 then for lI := 1 to lnAdditionalFactors do lStr := lStr+','+floattostr(X^[lI]^[lSubj+1]); NPMMsg(lStr); end; if not CheckVoxelsGroupX(lImageNames,lMaskHdr{lMaskVoxels}) then begin ShowMsg('File dimensions differ from mask.'); goto 666; end; NPMMsg('Mask = '+lMaskname); NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); NPMMsg('Number of observations = '+inttostr(lnSubj)); if lnSubj < 5 then begin ShowMsg('Paired regression error: Requires at least 5 images per group.'); goto 666; end; lOutName := lMaskName; if not SaveHdrName ('Base Statistical Map', lOutName) then exit; //ShowMsg('Unimplemented Regress');// Regress2NPMAnalyze (lImageNames, lMaskHdr, lOutname,X,lnAdditionalFactors,gNPMprefs.nPermute); if lnAdditionalFactors > 1 then DelMatrix(X, lnAdditionalFactors, lnSubj); 666: lImageNames.Free; end; procedure TMainForm.LesionBtnClick(Sender: TObject); label 666; var lPrefs: TLDMPrefs ; begin lPrefs.NULP := gNPMPrefs.NULP; if (1= (Sender as tMenuItem).tag) then begin //continuous lPrefs.BMtest := BMmenu.checked; lPrefs.Ttest := ttestmenu.checked; if (not lPrefs.BMtest) and (not lPrefs.ttest) then lPrefs.ttest := true; lPrefs.Ltest:= false; end else begin //binomial lPrefs.BMtest := false; lPrefs.Ttest := false; lPrefs.Ltest:= true; end; lPrefs.CritPct := -1; lPrefs.nPermute := ReadPermute; lPrefs.Run := 0;{0 except for montecarlo} {if (not lPrefs.Ltest) and (not lPrefs.Ttest) and (not lPrefs.BMtest) then begin ShowMsg('Error: you need to compute at least on test [options/test menu]'); exit; end; code above defaults to t-test} if not MainForm.OpenDialogExecute('Select MRIcron VAL file',false,false,'MRIcron VAL (*.val)|*.val') then begin ShowMsg('NPM aborted: VAL file selection failed.'); exit; end; //if not selected lPrefs.VALFilename := MainForm.OpenHdrDlg.Filename; lPrefs.OutName := ExtractFileDirWithPathDelim(lPrefs.VALFilename)+'results'; lPrefs.OutName := lPrefs.OutName+'.nii.gz'; SaveHdrDlg.Filename := lPrefs.Outname; if not SaveHdrName ('Base Statistical Map', lPrefs.OutName) then exit; //Explicit mask if not OpenDialogExecute('Select explicit mask [optional]',false,false,kImgPlusVOIFilter) then lPrefs.ExplicitMaskName := '' else lPrefs.ExplicitMaskName := OpenHdrDlg.FileName; DoLesion (lPrefs); //Prefs.pas end; function HasOption(const S: string):Boolean; var i: integer; begin result := false; if (ParamCount < 1) then exit; for i := 1 to ParamCount do if ParamStr(i) = ('-'+S) then result := true; end; procedure msg (s: string); begin writeln(s); end; procedure ShowOptions (lTestInt: integer; lMaskFilename,lOutFilename: string); begin msg(' -c : CPU threads, Default : '+inttostr(gnCPUThreads)); msg(' -m : mask name. Default "' +lMaskFilename+'"'); msg(' -n : neighbors for TFCE, 0 for none. Default ' +inttostr(gNPMprefs.TFCE)); msg(' -o : output name. Default "' +lOutFilename+'"'); msg(' -p : Permutations, 0 for none. Default '+inttostr(gNPMprefs.nPermute)); msg(' -r : RAM for processing (Mb). Default '+inttostr(gNPMPrefs.PlankMB)); msg(' -t : test (0=continuous,1=binomial,2=regress,3=multiregress). Default '+inttostr(lTestInt)); end; procedure WriteHelp ; begin msg(GetKVers); msg(' usage: '+ExtractFileName(ParseFileName(paramstr(0)))+' [options] [-t test] [valfilename]' ); msg('Examples:'); msg(' '+ ExtractFileName(ParseFileName(paramstr(0)))+' -t 0 test.val'); msg(' '+ ExtractFileName(ParseFileName(paramstr(0)))+' -r 1024 -p 1000 -m mymask.nii -t 0 test.val'); msg('Options:'); msg(' -h : Help displayed'); end; function GetOptionValue(const S: string):string; var i: integer; begin result := ''; if (ParamCount < 2) then exit; for i := 1 to (ParamCount-1) do if ParamStr(i) = ('-'+S) then begin result := ParamStr(i+1); exit; end; end; function GetOptionValueInt(lCmd: string; lDefault: integer): integer; var lResp : string; begin lResp := GetOptionValue(lCmd); if length(lResp) < 1 then result := lDefault; try result := strtoint(lResp); except Writeln('Error '+(lResp)+' is not a valid integer.'); result := lDefault; end; end; procedure doVLSM(lBinomial: boolean; VALFilename, lMaskFilename,lOutFilename: string); var lPrefs: TLDMPrefs ; begin lPrefs.NULP := gNPMPrefs.NULP; if (not lBinomial) then begin //continuous lPrefs.BMtest := true; lPrefs.Ttest := true; lPrefs.Ltest:= false; end else begin //binomial lPrefs.BMtest := false; lPrefs.Ttest := false; lPrefs.Ltest:= true; end; lPrefs.CritPct := -1; lPrefs.nPermute := gNPMprefs.nPermute; lPrefs.Run := 0;{0 except for montecarlo} lPrefs.VALFilename := VALFilename; lPrefs.OutName := lOutFilename; lPrefs.ExplicitMaskName := lMaskFilename; DoLesion (lPrefs); end; (*procedure TMainForm.ProcessParamStr; label 666; var lTestInt: integer; lMaskFilename : string; lValFilename : string; lOutFilename : string; begin lTestInt := 0; lMaskFilename := ''; lValFilename := ''; lOutFilename := ''; gnCPUThreads := GetLogicalCpuCount; ReadIniFile; // parse parameters if (HasOption('h')) or (ParamCount = 0) then begin WriteHelp; ShowOptions(lTestInt, lMaskFilename, lOutFilename); goto 666; end; if (HasOption('c')) then gnCPUThreads := GetOptionValueInt('c', gnCPUThreads); if (HasOption('m')) then begin lMaskFilename := GetOptionValue('m'); if (not FileExistsEX(lMaskFilename)) then begin WriteHelp ; writeln('Can not find masking image '+ lMaskFilename); ShowOptions(lTestInt,lMaskFilename,lOutFilename); goto 666; end; end; if (HasOption('n')) then gnCPUThreads := GetOptionValueInt('n', gNPMprefs.TFCE); if (HasOption('o')) then begin lOutFilename := GetOptionValue('o'); end; if (HasOption('p')) then gNPMprefs.nPermute := GetOptionValueInt('p', gNPMprefs.nPermute); if (HasOption('r')) then begin gNPMPrefs.PlankMB := GetOptionValueInt('r', gNPMPrefs.PlankMB); ComputePlankSize(gNPMPrefs.PlankMB); end; if (HasOption('t')) then lTestInt := GetOptionValueInt('t', lTestInt); lValFilename := (paramstr(ParamCount)); if (UpCaseExt(lValFilename) <> '.VAL') or (not FileExistsEX(lValFilename)) then begin Writeln('Error: final option should be an existing file with the .val extension'); WriteHelp ; ShowOptions(lTestInt,lMaskFilename,lOutFilename); goto 666; end; if (lOutFilename = '') then begin lOutFilename := ChangeFileExtX( lValFilename,'res.nii'); end; //show settings ShowOptions(lTestInt,lMaskFilename,lOutFilename); Writeln('VAL File: '+lValFilename); if (lTestInt > 1) and (lMaskFilename = '') then begin Writeln('Error: this test require you to specify a mask image'); goto 666; end; //run test Application.ProcessMessages; case lTestInt of 0: doVLSM(false, lVALFilename, lMaskFilename,lOutFilename);//continuous : t-test 1: doVLSM(true, lVALFilename, lMaskFilename,lOutFilename);//binomial: Liebermeister 2: NPMSingleRegress ( lVALFilename, lMaskFilename,lOutFilename); 3: NPMMultipleRegressClick( lVALFilename, lMaskFilename,lOutFilename); end; Writeln('Goodbye'); Application.ProcessMessages; //WriteIniFile; // stop program loop 666: Close; end; *) (*function TestT: string; var T: double; l1,l0,lN: integer; lIn: DoubleP0; lInp: pointer; //TStat2 (lnSubj, lnGroupX: integer; var lIn: DoubleP0; var lOutT: double); begin T := 666; l1 := 16; l0 := 8; lN := l0+l1; createArray64(lInp,lIn,lN); lIn^[0] := 44 ; lIn^[1] := 23 ; lIn^[2] := 41 ; lIn^[3] := 32 ; lIn^[4] := 60 ; lIn^[5] := 58 ; lIn^[6] := 57 ; lIn^[7] := 57 ; lIn^[8] := 55 ; lIn^[9] := 56 ; lIn^[10] := 60; lIn^[11] := 59; lIn^[12] := 57; lIn^[13] := 58; lIn^[14] := 56; lIn^[15] := 57; lIn^[16] := 2 ; lIn^[17] := 22; lIn^[18] := 24; lIn^[19] := 22; lIn^[20] := 18; lIn^[21] := 12; lIn^[22] := 15 ; lIn^[23] := 22; TStat2 (lN, l1, lIn, T); result := floattostr(T); freemem(lInp); end; *) procedure TMainForm.FormShow(Sender: TObject); begin NPMMsgClear; NPMMsg(GetkVers); {$IFNDEF UNIX} {GUILaunch;}{$ENDIF} LongTimeFormat := 'YYYY-MMM-DD hh:nn:ss'; //delphi TimeToStr ShortTimeFormat := 'YYYY-MMM-DD hh:nn:ss'; //freepascal TimeToStr {$IFDEF FPC}{$IFNDEF UNIX} ReadParamStr; {$ENDIF} {$ENDIF} {$IFDEF benchmark} //MonteCarloSimulation1.visible := true; {$ENDIF} //StartTimer.enabled := true; end; procedure TMainForm.PairedTMenuClick(Sender: TObject); label 666; var lnSubj,lSubj,lMaskVoxels: integer; lImageNames: TStrings; lMaskname,lStr,lOutName: string; lMaskHdr: TMRIcroHdr; begin lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? NPMMsgClear; NPMMsg(GetKVers); NPMMsg('Paired T-test [Repeated Measures]'); if not OpenDialogExecute('Select brain mask ',false,false,kImgFilter) then begin ShowMsg('NPM aborted: mask selection failed.'); goto 666; end; //if not selected //OpenHdrDlg.FileName := 'c:\vbmdata\mask50.nii.gz'; lMaskname := OpenHdrDlg.Filename; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin ShowMsg('Error reading Mask image.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin ShowMsg('Mask file size too small.'); goto 666; end; if not ReadPairedFilenames(lImageNames) then exit; lnSubj :=lImageNames.Count div 2; if not CheckVoxelsGroupX(lImageNames,lMaskHdr{lMaskVoxels}) then begin ShowMsg('File dimensions differ from mask.'); goto 666; end; NPMMsg('Mask = '+lMaskname); NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); NPMMsg('Number of observations = '+inttostr(lnSubj)); NPMMsg('Degrees of Freedom = '+inttostr(lnSubj-1)); if not CheckVoxelsGroupX(lImageNames,lMaskHdr{lMaskVoxels}) then begin ShowMsg('File dimensions differ from mask.'); goto 666; end; //show matrix //MsgStrings (lImageNames); NPMMsg ('n Subjects = '+inttostr(lnSubj)); lStr := 'Image,'; for lSubj := 0 to (lnSubj-1) do NPMMsg(lImageNames[lSubj]+' <-> '+lImageNames[lSubj+lnSubj]); if lnSubj < 4 then begin ShowMsg('Paired t-test error: Requires at least 4 images per group.'); goto 666; end; lOutName := lMaskName; if not SaveHdrName ('Statistical Map', lOutName) then exit; //if not SaveHdrName ('Base Statistical Map', lOutName) then exit; NPMAnalyzePaired (lImageNames, lMaskHdr, lMaskVoxels,lOutName); //Regress2NPMAnalyze (lImageNames, lMaskHdr, lOutname); 666: lImageNames.Free; end; procedure TMainForm.SingleSubjectZScores1Click(Sender: TObject); label 666; var lnSubj,lMnVoxels: integer; lG: TStrings; lMn,lStDev: string; lMnHdr,lStDevHdr: TMRIcroHdr; begin if (not ttestmenu.checked) and (not BMmenu.checked) then begin ShowMsg('Error: you need to compute at least on test [options/test menu]'); exit; end; NPMMsgClear; NPMMsg(GetKVers); NPMMsg('Threads: '+inttostr(gnCPUThreads)); if not OpenDialogExecute('Select mean image ',false,false,kImgFilter) then begin ShowMsg('NPM aborted: mean selection failed.'); exit; end; //if not selected lMn := OpenHdrDlg.Filename; if not NIFTIhdr_LoadHdr(lMn,lMnHdr) then begin ShowMsg('Error reading mask.'); exit; end; lMnVoxels := ComputeImageDataBytes8bpp(lMnHdr); if (lMnVoxels < 2) or (not CheckVoxels(lMn,lMnVoxels,0)){make sure there is uncompressed .img file} then begin ShowMsg('Mean file size too small.'); exit; end; if not OpenDialogExecute('Select StDev image ',false,false,kImgFilter) then begin ShowMsg('NPM aborted: StDev selection failed.'); exit; end; //if not selected lStDev := OpenHdrDlg.Filename; if not NIFTIhdr_LoadHdr(lStDev,lStDevHdr) then begin showmessage('Error reading StDev.'); exit; end; if not CheckVoxels(lStDev, lMnVoxels,kMaxImages) then begin showmessage('Error Mean and StDev must have same size.'); exit; end; NPMMsg('Mean name = '+ lMn); NPMMsg('Total voxels = '+inttostr(lMnVoxels)); //next, get 1st group if not OpenDialogExecute('Select postive group (Z scores positive if this group is brighter)',true,false,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected lG:= TStringList.Create; //not sure why TStrings.Create does not work??? lG.addstrings(OpenHdrDlg.Files); lnSubj :=OpenHdrDlg.Files.Count; NPMMsg('Subjects= '+inttostr(lnSubj)); if not CheckVoxelsGroupX(lG,lMnHdr {lMnVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; NPMzscore (lG, lMnHdr,lStDevHdr); 666: lG.Free; end; procedure TMainForm.MultipleRegressClick(Sender: TObject); var lVALFilename, lMaskname,lOutname: string; begin Showmessage('This function has been superceded by nii_stat'); exit; if not MainForm.OpenDialogExecute('Select MRIcron VAL file',false,false,'MRIcron VAL (*.val)|*.val') then begin ShowMsg('NPM aborted: VAL file selection failed.'); exit; end; //if not selected lVALFilename := MainForm.OpenHdrDlg.Filename; if not OpenDialogExecute('Select brain mask ',false,false,kImgFilter) then begin showmessage('NPM aborted: mask selection failed.'); exit; end; //if not selected lMaskname := OpenHdrDlg.Filename; lOutName := lMaskName; if not SaveHdrName ('Base Statistical Map', lOutName) then exit; NPMMultipleRegressClick(lVALFilename, lMaskname,lOutname); end; procedure TMainForm.SingleRegressClick(Sender: TObject); var lVALFilename, lMaskname,lOutname: string; begin showmessage('This function has been superceded with nii_stat'); exit; if not MainForm.OpenDialogExecute('Select MRIcron VAL file',false,false,'MRIcron VAL (*.val)|*.val') then exit; lVALFilename := MainForm.OpenHdrDlg.Filename; if not OpenDialogExecute('Select brain mask ',false,false,kImgFilter) then exit; lMaskname := OpenHdrDlg.Filename; lOutname := lVALFilename; NPMSingleRegress (lVALFilename, lMaskname,lOutname); end; procedure TMainForm.AssociatevalfileswithNPM1Click(Sender: TObject); begin {$IFNDEF FPC}//unsupported by FreePascal case MessageDlg('NPM installation:'+kCR+'Do you want .val fiels to automatically open NPM when you double click on their icons?', mtConfirmation, [mbYes, mbNo], 0) of { produce the message dialog box } id_No: exit; end; registerfiletype(kVALNativeExt,'NPM'{key},'NPM',Application.ExeName+',1'); {$ENDIF} end; procedure TMainForm.threadChange(Sender: TObject); begin (sender as tmenuitem).checked := true; ReadThread; end; (*procedure TMainForm.Countlesionoverlaps1Click(Sender: TObject); label 666; var lReps,lMax,lInc,lMaskVoxels,lDefault,lTotal,lPct: integer; lG: TStrings; lMaskname: string; lMaskHdr: TMRIcroHdr; begin NPMMsgClear; NPMMsg(GetKVers); if not OpenDialogExecute('Select images to overlap',true,false,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected if MainForm.OpenHdrDlg.Files.Count < 2 then begin lTotal := NIFTIhdr_HdrVolumes(MainForm.OpenHdrDlg.Filename); if lTotal < 2 then begin Showmessage('Error: This function is designed to overlay MULTIPLE volumes. You selected less than two images.'); exit; end; lG:= TStringList.Create; for lReps := 1 to lTotal do lG.Add(MainForm.OpenHdrDlg.Filename+':'+inttostr(lReps) ); end else begin lG:= TStringList.Create; lG.addstrings(OpenHdrDlg.Files); end; lMaskname := lG[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading mask.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if not CheckVoxelsGroupX(lG,lMaskHdr{lMaskVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; lTotal := lG.Count; if lTotal > kMaxObs then lTotal := kMaxObs; //this implemmentation uses 126 bits per voxel - we can not test more than this! if lTotal > 100 then lDefault := 100 else lDefault := lTotal; lMax := ReadIntForm.GetInt('Enter maximum number of overlaps to test ', 3,lDefault,lTotal); lDefault := lMax div 10; if lDefault < 1 then lDefault := 1; lInc := ReadIntForm.GetInt('Enter overlap increment (e.g. if 5; then 5, 10, 15...) ', 1,lDefault,lMax); lReps := ReadIntForm.GetInt('Enter number of times each increment is tested ', 1,10,100); lPct := ReadIntForm.GetInt('Only include voxels damaged in N% of patients ', 0,5,100); NPMMsg('Voxels = '+inttostr(lMaskVoxels)); NPMMsg('Scans to permute = '+inttostr(lG.count)); EvaluatePower (lG,lInc,lMax,lReps,lPct); //MakeMean(lG,lMaskHdr, odd((Sender as TMenuItem).tag),false); 666: lG.Free; end; *) function TMainForm.FirthNPMAnalyze (var lImages: TStrings; var lPredictorList: TStringList; var lMaskHdr: TMRIcroHdr; lnCond,lnCrit: integer; var lSymptomRA: SingleP; var lOutName: string): boolean; label 123,667; var lOutNameMod: string; lPlankImg: bytep; lOutImgSum : singleP; lOutImg: SingleRAp; {$IFDEF SINGLETHREAD}lnCPUThreads,{$ENDIF} lCond,lPos,lPlank,lThread,lnDeficit: integer; lTotalMemory,lVolVox,lMinMask,lMaxMask,lnPlanks,lVoxPerPlank, lThreadStart,lThreadInc,lThreadEnd, lnLesion,lnPermute, lPos2,lPos2Offset,lStartVox,lEndVox,lPlankImgPos,lnTests,lnVoxTested,lPosPct: int64; lT, lSum: double; lObsp: pointer; lObs: Doublep0; lStatHdr: TNIfTIhdr; lFdata: file; lRanOrderp: pointer; lRanOrder: Doublep0; begin if lnCond < 1 then exit; lnPermute := ReadPermute; if lnPermute > 1 then begin NPMMsg('NPM does not (yet) support permutation thresholding with Logisitic Regression.'); lnPermute := 0; end; {$IFDEF SINGLETHREAD} lnCPUThreads := gnCPUThreads; if gnCPUThreads > 1 then NPMMsg('July 2007 logistic regression will only use 1 thread. You may want to check for a software update'); gnCPUThreads := 1; {$ENDIF} NPMMsg('Permutations = ' +IntToStr(lnPermute)); NPMMsg('Logisitic Regression began = ' +TimeToStr(Now)); lTotalMemory := 0; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; lMinMask := 1; lMaxMask := lVolVox; lVoxPerPlank := kPlankSz div lImages.Count div sizeof(byte) ; if (lVoxPerPlank = 0) then goto 667; //no data lTotalMemory := ((lMaxMask+1)-lMinMask) * lImages.Count; if (lTotalMemory = 0) then goto 667; //no data lnPlanks := trunc(lTotalMemory/(lVoxPerPlank*lImages.Count) ) + 1; NPMMsg('Memory planks = ' +Floattostr(lTotalMemory/(lVoxPerPlank*lImages.Count))); NPMMsg('Max voxels per Plank = ' +Floattostr(lVoxPerPlank)); if (lnPlanks = 1) then getmem(lPlankImg,lTotalMemory) else getmem(lPlankImg,kPlankSz); lStartVox := lMinMask; lEndVox := lMinMask-1; for lPos := 1 to lImages.Count do if gScaleRA[lPos] = 0 then gScaleRA[lPos] := 1; createArray64(lObsp,lObs,lImages.Count); getmem(lOutImgSum,lVolVox* sizeof(single)); //getmem(lOutImgL,lVolVox* sizeof(single)); getmem(lOutImg,lnCond*sizeof(Singlep)); for lCond := 1 to lnCond do begin getmem(lOutImg^[lCond],lVolVox* sizeof(single)); for lPos := 1 to lVolVox do lOutImg^[lCond]^[lPos] := 0; end; //InitPermute (lImages.Count, lnPermute, lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp, lRanOrder); for lPos := 1 to lVolVox do lOutImgSum^[lPos] := 0; ClearThreadData(gnCPUThreads,lnPermute) ; for lPlank := 1 to lnPlanks do begin ProgressBar1.Position := 1; NPMMsg('Computing plank = ' +Inttostr(lPlank)); Refresh; Application.processmessages; lEndVox := lEndVox + lVoxPerPlank; if lEndVox > lMaxMask then begin lVoxPerPlank := lVoxPerPlank - (lEndVox-lMaxMask); lEndVox := lMaxMask; end; lPlankImgPos := 1; for lPos := 1 to lImages.Count do begin if not LoadImg8(lImages[lPos-1], lPlankImg, lStartVox, lEndVox,round(gOffsetRA[lPos]),lPlankImgPos,gDataTypeRA[lPos],lVolVox) then goto 667; lPlankImgPos := lPlankImgPos + lVoxPerPlank; end;//for each image //threading start lThreadStart := 1; lThreadInc := lVoxPerPlank div gnCPUThreads; lThreadEnd := lThreadInc; Application.processmessages; {$IFDEF FIRTHNOTHREAD} FirthAnalyzeNoThread (lnCond, lnCrit,lnPermute,1,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lPlankImg,lOutImgSum,lSymptomRA,lOutImg); {$ELSE} for lThread := 1 to gnCPUThreads do begin if lThread = gnCPUThreads then lThreadEnd := lVoxPerPlank; //avoid integer rounding error with TFirthThreadStat.Create ((lThread = ((gnCPUThreads+1) div 2)),MainForm, ProgressBar1,lnCond,lnCrit, lnPermute,lThread,lThreadStart,lThreadEnd,lStartVox,lVoxPerPlank,lImages.Count,lPlankImg,lOutImgSum,lSymptomRA,lOutImg) do {$IFDEF FPC} OnTerminate := @ThreadDone; {$ELSE}OnTerminate := ThreadDone;{$ENDIF} inc(gThreadsRunning); NPMMsg('Thread ' +Inttostr(gThreadsRunning)+' = '+inttostr(lThreadStart)+'..'+inttostr(lThreadEnd)); lThreadStart := lThreadEnd + 1; lThreadEnd :=lThreadEnd + lThreadInc; end; //for each thread repeat Application.processmessages; until gThreadsRunning = 0; {$ENDIF} //THREADED Application.processmessages; //showmessage('Threads done'); //threading end lStartVox := lEndVox + 1; end; lnVoxTested := SumThreadDataLite(gnCPUThreads); //not yet lnVoxTested := SumThreadData(gnCPUThreads,lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM); if lnVoxTested < 1 then begin NPMMsg('**Error: no voxels tested: no regions lesioned in at least '+inttostr(lnCrit)+' patients**'); goto 123; end; //next report findings NPMMsg('Voxels tested = ' +Inttostr(lnVoxTested)); NPMMsg('Only tested voxels with more than '+inttostr(lnCrit)+' lesions'); //Next: save results from permutation thresholding.... reportBonferroni('Std',lnVoxTested); //next: save data (*savedata *) MakeHdr (lMaskHdr.NIFTIhdr,lStatHdr); //save sum map lOutNameMod := ChangeFilePostfixExt(lOutName,'Sum','.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImgSum,1); MakeStatHdr (lMaskHdr.NIFTIhdr,lStatHdr,-6, 6,1{df},0,lnVoxTested,kNIFTI_INTENT_ZSCORE,inttostr(lnVoxTested) ); for lCond := 1 to lnCond do begin reportFDR (lPredictorList[lCond-1]+inttostr(lCond), lVolVox, lnVoxTested, lOutImg^[lCond]); //reportPermute('L',lnPermute,lPermuteMaxBM, lPermuteMinBM); lOutNameMod := ChangeFilePostfixExt(lOutName,lPredictorList[lCond-1]+inttostr(lCond),'.hdr'); NIFTIhdr_SaveHdrImg(lOutNameMod,lStatHdr,true,not IsNifTiMagic(lMaskHdr.NIFTIhdr),true,lOutImg^[lCond],1); end; 123: //next: free dynamic memory //FreePermute (lnPermute,lPermuteMaxT, lPermuteMinT,lPermuteMaxBM, lPermuteMinBM, lRanOrderp); for lCond := 1 to lnCond do freemem(lOutImg^[lCond]); freemem(lOutImg); freemem(lOutImgSum); freemem(lObsp); freemem(lPlankImg); NPMMsg('Analysis finished = ' +TimeToStr(Now)); lOutNameMod := ChangeFilePostfixExt(lOutName,'Notes','.txt'); NPMMsgSave(lOutNameMod); ProgressBar1.Position := 0; {$IFDEF SINGLETHREAD} gnCPUThreads := lnCPUThreads; {$ENDIF} exit; 667: //you only get here if you aborted ... free memory and report error if lTotalMemory > 1 then freemem(lPlankImg); NPMMsg('Unable to complete analysis.'); ProgressBar1.Position := 0; {$IFDEF SINGLETHREAD} gnCPUThreads := lnCPUThreads; {$ENDIF} end; procedure TMainForm.PenalizedLogisticRegerssion1Click(Sender: TObject); label 666; var lVol,lMin,lMax,lI,lFact,lnFactors,lSubj,lnSubj,lMaskVoxels,lnCrit: integer; lImageNames: TStrings; lPredictorList: TStringList; lTemp4D,lMaskname,lOutName,lStr: string; lMaskHdr: TMRIcroHdr; lMultiSymptomRA,lTempRA: singleP; //lBinomial: boolean; begin Showmessage('This function has been superceded by nii_stat'); exit; // lBinomial := false; lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? //next, get 1st group if not GetValX(lnSubj,lnFactors,lMultiSymptomRA,lImageNames,lnCrit{,binom},lPredictorList) then goto 666; if (lnSubj < 2) or (lnFactors < 1) then begin showmessage('This analysis requires at least 2 participants and one factor'); goto 666; end; WarnIfLowNCrit(lnSubj,lnCrit); lTemp4D := CreateDecompressed4D(lImageNames); lMaskname := lImageNames[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading 1st image: '+lMaskname); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if not CheckVoxelsGroupX(lImageNames,lMaskHdr{lMaskVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; case MessageDlg('Do you want to add lesion volume as a regressor?', mtConfirmation, [mbYes, mbNo], 0) of { produce the message dialog box } mrYes: begin //add a new condition called lesionvolume - create a new larger array for data NPMMsg('Computing lesion volumes...'); lPredictorList.Add('LesionVolume'); GetMem(lTempRA,lnSubj*lnFactors*sizeof(single)); for lI := 1 to (lnSubj*lnFactors) do lTempRA^[lI] := lMultiSymptomRA^[lI]; Freemem(lMultiSymptomRA); GetMem(lMultiSymptomRA,lnSubj*(lnFactors+1)*sizeof(single)); for lI := 1 to (lnSubj*lnFactors) do lMultiSymptomRA^[lI] := lTempRA^[lI]; Freemem(lTempRA); //now create the new factor lI := lnSubj*lnFactors; for lSubj := 1 to lnSubj do lMultiSymptomRA^[lI+lSubj] := ComputeLesionVolume(lImageNames[lSubj-1]); //ensure there is variability in this regressor lMin := round(lMultiSymptomRA^[lI+1]); lMax := round(lMultiSymptomRA^[lI+1]); for lSubj := 1 to lnSubj do begin lVol := round(lMultiSymptomRA^[lI+lSubj]); if lVol < lMin then lMin := lVol; if lVol > lMax then lMax := lVol; end; if (lMin < 0) then begin showmessage('Regression aborted: Error computing lesion volumes.'); goto 666; end; if (lMin = lMax) then begin showmessage('Regression aborted: no variability in lesion volume.'); goto 666; end; inc(lnFactors); end; //if user decides to include lesion volume end; //case lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Mask file size too small.'); goto 666; end; lOutName := ExtractFileDirWithPathDelim(lMaskName)+'results'; SaveHdrDlg.Filename := loutname; NPMMsgClear; NPMMsg(GetKVers); NPMMsg('Firth Penalized regression is still beta software...'); NPMMsg('Number of participants: '+inttostr(lnSubj)); NPMMsg('Number of factors: '+inttostr(lnFactors)); NPMMsg('Threads: '+inttostr(gnCPUThreads)); //next - header shows factor names lStr :='imagename'; for lFact := 1 to lnFactors do lStr := lStr+','+lPredictorList[lFact-1]; NPMMsg(lStr); For lSubj := 1 to lnSubj do begin lStr :=''; for lFact := 1 to lnFactors do begin lStr := lStr+','+realtostr(lMultiSymptomRA^[lSubj+ ((lFact-1)*lnSubj)],2); end; NPMMsg (lImageNames.Strings[lSubj-1] + ' = '+lStr ); end; NPMMsg('Total voxels = '+inttostr(lMaskVoxels)); NPMMsg('Only testing voxels damaged in at least '+inttostr(lnCrit)+' individual[s]'); NPMMsg('Number of Lesion maps = '+inttostr(lnSubj)); lOutName := lOutName+'.nii.gz'; if not SaveHdrName ('Base Statistical Map', lOutName) then goto 666; if not CheckVoxelsGroupX(lImageNames,lMaskHdr{lMaskVoxels}) then begin showmessage('File dimensions differ from mask.'); goto 666; end; FirthNPMAnalyze (lImageNames,lPredictorList,lMaskHdr,lnFactors,lnCrit, lMultiSymptomRA, lOutName); 666: lImageNames.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); end; (*function ComputeIntersection ( lAname,lBname: string; var lUnion,lIntersection,lAnotB,lBnotA: integer): boolean; label 667; var lOutName,lOutNameMod: string; lVolVox,lVolVoxA,lVox: integer; lImgA,lImgB: SingleP; lMaskHdr: TMRIcroHdr; lA,lB: boolean; begin lUnion:= 0; lIntersection := 0; lAnotB := 0; lBnotA := 0; result := false; //read A if not NIFTIhdr_LoadHdr(lAname,lMaskHdr) then begin showmessage('Error reading image A - '+lAname); exit; end; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then goto 667; getmem(lImgA,lVolVox*sizeof(single)); if not LoadImg(lAname, lImgA, 1, lVolVox,round(lMaskHdr.NIFTIhdr.vox_offset),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin NPMMsg('Unable to load mask ' +lMaskHdr.ImgFileName); goto 667; end; lVolVoxA := lVolVox; //read B if not NIFTIhdr_LoadHdr(lBname,lMaskHdr) then begin showmessage('Error reading image B - '+lBname); exit; end; lVolVox := lMaskHdr.NIFTIhdr.dim[1]*lMaskHdr.NIFTIhdr.dim[2]* lMaskHdr.NIFTIhdr.dim[3]; if (lVolVoxA <> lVolVox) or (lVolVox < 1) then goto 667; getmem(lImgB,lVolVox*sizeof(single)); if not LoadImg(lBname, lImgB, 1, lVolVox,round(lMaskHdr.NIFTIhdr.vox_offset),1,lMaskHdr.NIFTIhdr.datatype,lVolVox) then begin NPMMsg('Unable to load mask ' +lMaskHdr.ImgFileName); goto 667; end; for lVox := 1 to lVolVox do begin lA := (lImgA^[lVox] <> 0); lB := (lImgB^[lVox] <> 0); if lA and lB then begin //fx(lVox,lImgA^[lVox],lImgB^[lVox]); inc(lIntersection); end; if lA or lB then inc(lUnion); if lA and not lB then inc(lAnotB); if lB and not lA then inc(lBnotA); end; freemem(lImgA); freemem(lImgB); result := true; 667: end; procedure TMainForm.ZtoP1Click(Sender: TObject); var lAname,lBname: string; var lUnion,lIntersection,lAnotB,lBnotA: integer; begin //removed lAName := 'C:\mri\roc\p2.nii.gz'; lBName := 'C:\mri\roc\RBD35.voi'; if not ComputeIntersection ( lAName,lBName,lUnion,lIntersection,lAnotB,lBnotA) then NPMMsg('Error'); NPMMsg( lAName+' '+lBName+' I'+inttostr(lIntersection)+' U'+inttostr(lUnion)+' AnotB'+inttostr(lAnotB)+' BnotA'+inttostr(lBnotA)); end; *) (*procedure TMainForm.ComputeIntersectionandUnion1Click(Sender: TObject); label 666; var lUnion,lIntersection,lAnotB,lBnotA, lnSubj,lSubj,lMaskVoxels,lnAdditionalFactors: integer; lImageNames: TStrings; lMaskname, lStr,lOutName: string; lMaskHdr: TMRIcroHdr; X: PMatrix; begin lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? NPMMsgClear; NPMMsg(GetKVers); NPMMsg('Compute intersection [A and B] and union [A or B] for a series of images'); if not ReadPairedFilenamesReg(lImageNames,X,lnAdditionalFactors) then exit; lnSubj :=lImageNames.Count div 2; if lnAdditionalFactors > 1 then DelMatrix(X, lnAdditionalFactors, lnSubj); lMaskname :=lImageNames[0]; if not NIFTIhdr_LoadHdr(lMaskname,lMaskHdr) then begin showmessage('Error reading first image.'); goto 666; end; lMaskVoxels := ComputeImageDataBytes8bpp(lMaskHdr); if (lMaskVoxels < 2) or (not CheckVoxels(lMaskname,lMaskVoxels,0)){make sure there is uncompressed .img file} then begin showmessage('Image file size too small.'); goto 666; end; if not CheckVoxelsGroupX(lImageNames,lMaskHdr{lMaskVoxels}) then begin showmessage('File dimensions differ from first image.'); goto 666; end; NPMMsg ('n Subjects = '+inttostr(lnSubj)); for lSubj := 0 to (lnSubj-1) do begin lStr := 'A=,'+lImageNames[lSubj]+',B=,'+lImageNames[lSubj+lnSubj]; ComputeIntersection ( lImageNames[lSubj],lImageNames[lSubj+lnSubj],lUnion,lIntersection,lAnotB,lBnotA); lStr := lStr + ',A and B=,'+inttostr(lIntersection); lStr := lStr + ',A or B=,'+inttostr(lUnion); lStr := lStr + ',A not B=,'+inttostr(lAnotB); lStr := lStr + ',B not A=,'+inttostr(lBnotA); NPMMsg(lStr); end; //Msg('Mask = '+lMaskname); //Msg('Total voxels = '+inttostr(lMaskVoxels)); NPMMsg('Number of observations = '+inttostr(lnSubj)); 666: lImageNames.Free; end; //compute intersection and union *) (*procedure TMainForm.ROCbinomialdeficit1Click(Sender: TObject); begin testROC; end; procedure TMainForm.ROCcontinuousdeficit1Click(Sender: TObject); begin testROC2; end; *) function isBinom ( lRA: singleP; lnObs: integer): boolean; var lI: integer; begin result := false; if lnObs < 1 then exit; for lI := 1 to lnObs do if (lRA^[lI] <> 0) and (lRA^[lI] <> 1) then exit; result := true; end; procedure Means ( lBinomRA,lContRA: singleP; lnObs: integer); var lI,ln0: integer; lMeans0, lMeans1: double; begin lMeans0 := 0; lMeans1 := 0; ln0 := 0; if lnObs < 1 then exit; for lI := 1 to lnObs do begin if (lBinomRA^[lI] = 0) then begin inc(ln0); lMeans0 := lMeans0 + lContRA^[lI]; end else lMeans1 := lMeans1 + lContRA^[lI]; end; if ln0 > 0 then lMeans0 := lMeans0 / ln0; if ln0 < lnObs then lMeans1 := lMeans1 / (lnObs-ln0); npmform.MainForm.memo1.lines.add('mean volume for '+inttostr(ln0)+' people who scored 0 is = '+floattostr(lmeans0)); npmform.MainForm.memo1.lines.add('mean volume for '+inttostr(lnObs-ln0)+' people who scored 1 is = '+floattostr(lmeans1)); end; function AUCbinomcontT (lBinomdataRA,lContdataRA: singlep; lnSubj :integer; var lT: double): double; var lIn : DoubleP0; lnGroup0,lnGroup1,lI: integer; begin result := 0.5; if lnSubj < 1 then exit; Getmem(lIn,lnSubj*sizeof(double)); lnGroup0 := 0; lnGroup1 := 0; for lI := 1 to lnSubj do begin if lBinomdataRA^[lI] = 0 then begin lIn^[lnGroup0] := lContdataRA^[lI]; inc (lnGroup0); end else begin inc (lnGroup1); lIn^[lnSubj-lnGroup1] := lContdataRA^[lI]; end; end; result := continROC (lnSubj, lnGroup0, lIn); TStat2 (lnSubj, lnGroup0, lIn,lT); freemem(lIn); end; procedure Contrast(lBehavName,lROIname: string; lBehavRA,lLesionVolRA: singleP; lnSubj: integer); var lDF: integer; lROC,lT,lP: double; begin if isBinom (lBehavRA,lnSubj) then begin lROC := AUCbinomcontT (lBehavRA,lLesionVolRA, lnSubj,lT); lDF := lnSubj-2; lP := pTdistr(lDF,lT); Means ( lBehavRA,lLesionVolRA, lnSubj); npmform.MainForm.memo1.lines.add('ROI=,'+lROIname+',Behav=,'+lBehavName+', Area Under Curve=,'+floattostr(lROC)+', T('+inttostr(lDF)+')=,'+floattostr(lT)+',p<,'+floattostr(lp)); end else begin lROC := AUCcontcont (lBehavRA,lLesionVolRA, lnSubj); npmform.MainForm.memo1.lines.add('ROI=,'+lROIname+',Behav=,'+lBehavName+', Area Under Curve = '+floattostr(lROC)); end; //xxx end; (* procedure ROIanalysis(var lROInames,lImageNames: TStrings; var lVALFilename: string); label 666; var lROI,lnROI,lVol,lMin,lMax,lI,lFact,lnFactors,lSubj,lnSubj,lMaskVoxels,lnCrit: integer; //lROInames,lImageNames: TStrings; lPredictorList: TStringList; lVolStr,lTemp4D,lOutName,lStr: string; lBehav: single; lROIvolRA: doubleP; lMultiSymptomRA,lLesionVolRA,lBehavRA: singleP; lError: boolean; begin lnROI := lROINames.Count; if lnROI < 1 then begin showmessage('You need to select at least one ROI.'); goto 666; end; //lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? if not GetValCore ( lVALFilename,lnSubj,lnFactors,lMultiSymptomRA,lImageNames,lnCrit,lPredictorList) then goto 666; lTemp4D := CreateDecompressed4D(lImageNames); if (lnSubj < 1) or (lnFactors < 1) then begin showmessage('This analysis requires at least 1 participant and one factor'); goto 666; end; NPMMsgClear; NPMMsg(GetKVers); NPMmsg('Analysis began = ' +TimeToStr(Now)); NPMMsg('VAL file name: '+MainForm.OpenHdrDlg.Filename); NPMMsg('Number of participants: '+inttostr(lnSubj)); NPMMsg('Number of factors: '+inttostr(lnFactors)); NPMMsg('Number of Lesion maps = '+inttostr(lnSubj)); //next - header shows factor names lStr :='imagename'; for lFact := 1 to lnFactors do lStr := lStr+','+lPredictorList[lFact-1]; for lROI := 1 to lnROI do lStr := lStr+','+lROInames[lROI-1]; NPMMsg(lStr+',LesionVolume'); lError := false; Getmem(lROIVolRA, lnSubj*lnROI*sizeof(double)); Getmem(lLesionVolRA, lnSubj*lnROI*sizeof(single)); Getmem(lBehavRA, lnSubj*lnFactors*sizeof(single)); for lROI := 1 to lnROI do begin //if not ComputeIntersection ( lImageNames.Strings[lSubj-1],lROInames[lROI-1],lUnion,lIntersection,lAnotB,lBnotA) then if not ComputeOverlap (lROInames[lROI-1],lImageNames, lROIvolRA^[lROI], singlep(@lLesionVolRA^[((lROI-1)*lnSubj)+1])) then begin NPMmsg('Error computing overlap'); goto 666; end; end; For lSubj := 1 to lnSubj do begin lStr :=''; for lFact := 1 to lnFactors do begin lBehav := lMultiSymptomRA^[lSubj+ ((lFact-1)*lnSubj)]; lStr := lStr+','+realtostr(lBehav,2); lBehavRA^[((lFact-1)*lnSubj) +lSubj] := lBehav; end; for lROI := 1 to lnROI do lStr := lStr+','+floattostr(lLesionVolRA^[((lROI-1)*lnSubj) +lSubj]); lVolStr := floattostr(ComputeLesionVolume(lImageNames.Strings[lSubj-1])); NPMMsg (lImageNames.Strings[lSubj-1] + ' = '+lStr +','+lVolStr ); end; for lROI := 1 to lnROI do begin for lFact := 1 to lnFactors do begin Contrast(lPredictorList[lFact-1],lROInames[lROI-1],singlep(@lBehavRA^[((lFact-1)*lnSubj)+1]),singlep(@lLesionVolRA^[((lROI-1)*lnSubj)+1]),lnSubj);//,((lFact-1)*lnSubj),((lROI-1)*lnSubj)); end; //for each factor end; //for each ROI for lROI := 1 to lnROI do begin NPMMsg( lROInames[lROI-1] +' volume = '+floattostr(lROIvolRA^[lROI]) ) end; //for each ROI Freemem(lLesionVolRA); Freemem(lBehavRA); Freemem(lROIvolRA); 666: lROInames.free; lImageNames.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); NPMmsg('Analysis finished = ' +TimeToStr(Now)); end; *) procedure TMainForm.ROIanalysis1Click(Sender: TObject); label 666; var lROI,lnROI,lVol,lMin,lMax,lI,lFact,lnFactors,lSubj,lnSubj,lMaskVoxels,lnCrit: integer; lROInames,lImageNames: TStrings; lPredictorList: TStringList; lVolStr,lTemp4D,lOutName,lStr: string; lBehav: single; lROIvolRA: doubleP; lMultiSymptomRA,lLesionVolRA,lBehavRA: singleP; lError: boolean; begin if not OpenDialogExecute('Select regions of interest',true,false,kImgPlusVOIFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected lROInames:= TStringList.Create; lROInames.addstrings(OpenHdrDlg.Files); lnROI := lROINames.Count; if lnROI < 1 then begin showmessage('You need to select at least one ROI.'); exit; end; lImageNames:= TStringList.Create; //not sure why TStrings.Create does not work??? if not GetValX(lnSubj,lnFactors,lMultiSymptomRA,lImageNames,lnCrit,lPredictorList) then goto 666; lTemp4D := CreateDecompressed4D(lImageNames); if (lnSubj < 1) or (lnFactors < 1) then begin showmessage('This analysis requires at least 1 participant and one factor'); goto 666; end; NPMMsgClear; NPMMsg(GetKVers); NPMmsg('Analysis began = ' +TimeToStr(Now)); NPMMsg('VAL file name: '+MainForm.OpenHdrDlg.Filename); NPMMsg('Number of participants: '+inttostr(lnSubj)); NPMMsg('Number of factors: '+inttostr(lnFactors)); NPMMsg('Number of Lesion maps = '+inttostr(lnSubj)); //next - header shows factor names lStr :='imagename'; for lFact := 1 to lnFactors do lStr := lStr+','+lPredictorList[lFact-1]; for lROI := 1 to lnROI do lStr := lStr+','+lROInames[lROI-1]; NPMMsg(lStr+',LesionVolume'); lError := false; Getmem(lROIVolRA, lnSubj*lnROI*sizeof(double)); Getmem(lLesionVolRA, lnSubj*lnROI*sizeof(single)); Getmem(lBehavRA, lnSubj*lnFactors*sizeof(single)); for lROI := 1 to lnROI do begin //if not ComputeIntersection ( lImageNames.Strings[lSubj-1],lROInames[lROI-1],lUnion,lIntersection,lAnotB,lBnotA) then if not ComputeOverlap (lROInames[lROI-1],lImageNames, lROIvolRA^[lROI], singlep(@lLesionVolRA^[((lROI-1)*lnSubj)+1])) then begin NPMmsg('Error computing overlap'); goto 666; end; end; For lSubj := 1 to lnSubj do begin lStr :=''; for lFact := 1 to lnFactors do begin lBehav := lMultiSymptomRA^[lSubj+ ((lFact-1)*lnSubj)]; lStr := lStr+','+realtostr(lBehav,2); lBehavRA^[((lFact-1)*lnSubj) +lSubj] := lBehav; end; for lROI := 1 to lnROI do lStr := lStr+','+floattostr(lLesionVolRA^[((lROI-1)*lnSubj) +lSubj]); lVolStr := floattostr(ComputeLesionVolume(lImageNames.Strings[lSubj-1])); NPMMsg (lImageNames.Strings[lSubj-1] + ' = '+lStr +','+lVolStr ); end; for lROI := 1 to lnROI do begin for lFact := 1 to lnFactors do begin Contrast(lPredictorList[lFact-1],lROInames[lROI-1],singlep(@lBehavRA^[((lFact-1)*lnSubj)+1]),singlep(@lLesionVolRA^[((lROI-1)*lnSubj)+1]),lnSubj);//,((lFact-1)*lnSubj),((lROI-1)*lnSubj)); end; //for each factor end; //for each ROI for lROI := 1 to lnROI do begin NPMMsg( lROInames[lROI-1] +' volume = '+floattostr(lROIvolRA^[lROI]) ) end; //for each ROI Freemem(lLesionVolRA); Freemem(lBehavRA); Freemem(lROIvolRA); 666: lROInames.free; lImageNames.Free; lPredictorList.Free; DeleteDecompressed4D(lTemp4D); NPMmsg('Analysis finished = ' +TimeToStr(Now)); end; procedure TMainForm.Masked1Click(Sender: TObject); var lFilename,lMaskname: string; lPos: Integer; begin NPMMsgClear; NPMMsg(GetKVers); if not OpenDialogExecute('Select brain mask ',false,false,kImgFilter) then begin showmessage('NPM aborted: mask selection failed.'); exit; end; //if not selected lMaskname := OpenHdrDlg.Filename; if not OpenDialogExecute('Select images for intensity normalization',true,false,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected if OpenHdrDlg.Files.Count < 1 then exit; for lPos := 1 to OpenHdrDlg.Files.Count do begin lFilename := OpenHdrDlg.Files[lPos-1]; balance(lFilename,lMaskname,(Sender as TMenuItem).tag); end; end; function Binarize (var lImageName:String; lNonZeroVal: integer; lZeroThresh: boolean): boolean; var lImg8: ByteP; lImg: SingleP; lHdr: TMRIcroHdr; lVolVox,lVox: integer; lMin,lMax: single; lModeLo,lModeHi,lIntercept,lSlope: single; lOutNameMod: string; begin //lOutName := lMaskHdr.ImgFileName; result := false; //if not SaveHdrName ('Statistical Map', lOutName) then exit; if not NIFTIhdr_LoadHdr(lImageName,lHdr) then begin showmessage('Error reading '+lImageName); exit; end; lVolVox := lHdr.NIFTIhdr.dim[1]*lHdr.NIFTIhdr.dim[2]* lHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then exit; getmem(lImg,lVolVox*sizeof(single)); getmem(lImg8,lVolVox*sizeof(byte)); if not LoadImg(lHdr.ImgFileName, lImg, 1, lVolVox,round(lHdr.NIFTIhdr.vox_offset),1,lHdr.NIFTIhdr.datatype,lVolVox) then begin NPMMsg('Unable to load ' +lHdr.ImgFileName); exit; end; lHdr.NIFTIhdr.scl_slope := 1; lHdr.NIFTIhdr.scl_inter := 0; if lZeroThresh then begin lOutNameMod := ChangeFilePrefixExt(lImageName,'i','.nii'); lMin := 0; lMax := 0 end else begin lOutNameMod := ChangeFilePrefixExt(lImageName,'i','.voi'); lMin := lIMg^[1]; for lVox := 1 to lVolVox do if lImg^[lVox] < lMin then lMin := lIMg^[lVox]; lMax := lIMg^[1]; for lVox := 1 to lVolVox do if lImg^[lVox] > lMax then lMax := lIMg^[lVox]; for lVox := 1 to lVolVox do lImg8^[lVox] := 0; lMax := ((lMax-lMin) / 2)+lMin; end; for lVox := 1 to lVolVox do if lImg^[lVox] > lMax then lImg8^[lVox] := lNonZeroVal; NPMMsg('Creating ' +lOutNameMod+' Threshold = '+floattostr(lMax)); NIFTIhdr_SaveHdrImg8(lOutNameMod,lHdr.NIFTIhdr,true,not IsNifTiMagic(lHdr.NIFTIhdr),true,lImg8,1); freemem(lIMg8); freemem(lImg); end; procedure TMainForm.Binarizeimages1Click(Sender: TObject); var lFilename: string; lPos: Integer; begin NPMMsgClear; NPMMsg(GetKVers); if not OpenDialogExecute('Select images for intensity normalization',true,false,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected if OpenHdrDlg.Files.Count < 1 then exit; for lPos := 1 to OpenHdrDlg.Files.Count do begin lFilename := OpenHdrDlg.Files[lPos-1]; Binarize(lFilename,1,false); //Binarize (var lImageName:String; lNonZeroVal: integer; lZeroThresh: boolean): boolean; end; NPMMsg('Done'); end; procedure TMainForm.Setnonseroto1001Click(Sender: TObject); var lFilename: string; lPos: Integer; begin NPMMsgClear; NPMMsg(GetKVers); if not OpenDialogExecute('Select images for intensity normalization',true,false,kImgFilter) then begin showmessage('NPM aborted: file selection failed.'); exit; end; //if not selected if OpenHdrDlg.Files.Count < 1 then exit; for lPos := 1 to OpenHdrDlg.Files.Count do begin lFilename := OpenHdrDlg.Files[lPos-1]; Binarize(lFilename,100,true); //Binarize (var lImageName:String; lNonZeroVal: integer; lZeroThresh: boolean): boolean; end; end; procedure TMainForm.Savetext1Click(Sender: TObject); begin SaveHdrDlg.Title := 'Save file as comma separated values (to open with Excel)'; SaveHdrDlg.Filter := 'Comma Separated (*.csv)|*.csv|Text (*.txt)|*.txt'; SaveHdrDlg.DefaultExt := '*.csv'; if not SaveHdrDlg.Execute then exit; Memo1.Lines.SaveToFile(SaveHdrDlg.Filename); end; (* function TMainForm.MakeSubtract (lPosName,lNegName: string): boolean; var lNegImg,lImg,lOutImg: SingleP; lHdr,lNegHdr: TMRIcroHdr; lVolVox,lVox: integer; lOutNameMod: string; begin result := false; if not NIFTIhdr_LoadHdr(lPosName,lHdr) then begin ShowMsg('Error reading '+lPosName); exit; end; lVolVox := lHdr.NIFTIhdr.dim[1]*lHdr.NIFTIhdr.dim[2]* lHdr.NIFTIhdr.dim[3]; if (lVolVox < 1) then exit; getmem(lImg,lVolVox*sizeof(single)); if not LoadImg(lHdr.ImgFileName, lImg, 1, lVolVox,round(lHdr.NIFTIhdr.vox_offset),1,lHdr.NIFTIhdr.datatype,lVolVox) then begin NPMMsg('Unable to load ' +lHdr.ImgFileName); exit; end; if not NIFTIhdr_LoadHdr(lNegName,lNegHdr) then begin showmessage('Error reading '+lNegName); exit; end; if lVolVox <> (lNegHdr.NIFTIhdr.dim[1]*lNegHdr.NIFTIhdr.dim[2]* lNegHdr.NIFTIhdr.dim[3]) then begin ShowMsg('Volumes differ'); exit; end; getmem(lImg,lVolVox*sizeof(single)); if not LoadImg(lHdr.ImgFileName, lImg, 1, lVolVox,round(lHdr.NIFTIhdr.vox_offset),1,lHdr.NIFTIhdr.datatype,lVolVox) then begin NPMMsg('Unable to load ' +lHdr.ImgFileName); exit; end; getmem(lNegImg,lVolVox*sizeof(single)); if not LoadImg(lNegHdr.ImgFileName, lNegImg, 1, lVolVox,round(lNegHdr.NIFTIhdr.vox_offset),1,lNegHdr.NIFTIhdr.datatype,lVolVox) then begin NPMMsg('Unable to load ' +lNegHdr.ImgFileName); exit; end; getmem(lOutImg,lVolVox*sizeof(single)); for lVox := 1 to lVolVox do lOutImg^[lVox] := lImg^[lVox] - lNegImg^[lVox]; lHdr.NIFTIhdr.scl_slope := 1; lHdr.NIFTIhdr.scl_inter := 0; lOutNameMod := ChangeFilePrefixExt(lPosName,'subtract_','.hdr'); NPMMsg(lPosName+' - ' + lNegName+ ' = '+lOutNameMod); NIFTIhdr_SaveHdrImg(lOutNameMod,lHdr.NIFTIhdr,true,not IsNifTiMagic(lHdr.NIFTIhdr),true,lOutImg,1); freemem(lImg); freemem(lOutImg); freemem(lNegImg); end;//makesubtract *) (*procedure TMainForm.Subtract1Click(Sender: TObject); var lPosName,lNegName: string; begin if not OpenDialogExecute('Select positive',false,false,kImgPlusVOIFilter) then exit; lPosName := OpenHdrDlg.FileName; if not OpenDialogExecute('Select negative',false,false,kImgPlusVOIFilter) then exit; lNegName := OpenHdrDlg.FileName; MakeSubtract (lPosName,lNegName); end; *) {$IFDEF UNIX} initialization {$I npmform.lrs} {$ELSE} //not unix: windows initialization {$IFDEF FPC} {$I npmform.lrs} {$ENDIF}//FPC OleInitialize(nil); finalization OleUninitialize {$ENDIF} //Windows end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/npmform.dfm����������������������������������������������������0000755�0001750�0001750�00000011732�12306714056�017153� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �TMAINFORM�0��TPF0 TMainFormMainFormLeftTopxWidthHeightCaptionNon-Parametric MappingColor clBtnFace Font.CharsetDEFAULT_CHARSET Font.Color clWindowText Font.Height Font.Name MS Sans Serif Font.Style �Menu MainMenu1OldCreateOrder PositionpoScreenCenterOnClose FormCloseOnCreate FormCreateOnShowFormShow PixelsPerInch` TextHeight �TMemoMemo1Left�Top�WidthHeightAlignalClient ScrollBars ssVerticalTabOrder�WordWrap��TPanelPanel1Left�TopWidthHeightAlignalBottom BevelOuterbvNoneCaptionPanel1TabOrder� TProgressBar ProgressBar1Left�Top�WidthHeightAlignalClientTabOrder���� TOpenDialog OpenHdrDlgLeftTop<�� TSaveDialog SaveHdrDlgLeftTop$�� TMainMenu MainMenu1LeftTop� TMenuItemFile1CaptionFile� TMenuItem Savetext1Caption Save text....OnClickSavetext1Click�� TMenuItemExit1CaptionExitOnClick Exit1Click��� TMenuItemEdit1CaptionEdit� TMenuItemCopy1CaptionCopyShortCutC@OnClick Copy1Click��� TMenuItemVLSM1CaptionVLSM� TMenuItemBinomialAnalysislesions1CaptionBinary images, binary behaviorShortCutB@OnClickLesionBtnClick�� TMenuItem!Binaryimagescontinuousgroupsfast1TagCaption"Binary images, continuous behaviorShortCutL@OnClickLesionBtnClick�� TMenuItemPenalizedLogisticRegerssion1Caption"Binary Images, Multiple RegressorsOnClick!PenalizedLogisticRegerssion1Click�� TMenuItem AnaCOMmenuCaptionAnaCOMVisible�� TMenuItemMonteCarloSimulation1CaptionMonteCarloSimulation�� TMenuItem ROIanalysis1Caption ROI analysisOnClickROIanalysis1Click�� TMenuItemDesign1Caption Design...ShortCutD@OnClick Design1Click��� TMenuItemVBM1CaptionVBM� TMenuItemContinuousanalysisVBM1Caption&Continuous images, binary groups (VBM)ShortCutV@OnClickNPMclick�� TMenuItemMultipleRegressCaptionMultiple WLS RegressionShortCutR@OnClickMultipleRegressClick�� TMenuItem SingleRegressTagCaptionSingle WLS RegressionOnClickSingleRegressClick�� TMenuItemDualImageCorrelation1CaptionDual Image CorrelationOnClickDualImageCorrelation1Click�� TMenuItem PairedTMenuCaptionPaired Measures T-testOnClickPairedTMenuClick��� TMenuItemOptions1CaptionOptions� TMenuItem Permutations1Caption Permutations� TMenuItemN0CaptionNoneChecked GroupIndex{ RadioItem OnClickradiomenuclick�� TMenuItemN1000TagCaption1000 GroupIndex{ RadioItem OnClickradiomenuclick�� TMenuItemN2000TagCaption2000 GroupIndex{ RadioItem OnClickradiomenuclick�� TMenuItemN3000Tag Caption3000 GroupIndex{ RadioItem OnClickradiomenuclick�� TMenuItemN4000TagCaption4000 GroupIndex{ RadioItem OnClickradiomenuclick��� TMenuItemTests1CaptionTests� TMenuItem ttestmenuCaptionttestChecked OnClick testmenuclick�� TMenuItemBMmenuCaptionBrunner MunzelChecked GroupIndexOnClick testmenuclick��� TMenuItemThreads1CaptionThreads� TMenuItemT1Caption1Checked GroupIndex� RadioItem OnClick threadChange�� TMenuItemT2Caption2 GroupIndex� RadioItem OnClick threadChange�� TMenuItemT3Caption3 GroupIndex� RadioItem OnClick threadChange�� TMenuItemT4Caption4 GroupIndex� RadioItem OnClick threadChange�� TMenuItemT7Caption7 GroupIndex� RadioItem OnClick threadChange�� TMenuItemT8Caption8 GroupIndex� RadioItem OnClick threadChange�� TMenuItemT15Caption15 GroupIndex� RadioItem OnClick threadChange�� TMenuItemT16Caption16 GroupIndex� RadioItem OnClick threadChange��� TMenuItemPlankSzMenuItem1Caption Plank SizeOnClickPlankSzMenuItem1Click��� TMenuItem Utilities1Caption Utilities� TMenuItem Variance1CaptionVariance imageOnClickVariance1Click�� TMenuItemMakemeanimage2TagCaptionMake binarized mean OnClickMakemeanimage1Click�� TMenuItemBinarizeimages1CaptionBinarize imagesOnClickBinarizeimages1Click�� TMenuItemMakemeanimage1CaptionMake mean/StDev imageShortCutM@OnClickMakemeanimage1Click�� TMenuItemSingleSubjectZScores1CaptionSingle Subject Z-ScoresOnClickSingleSubjectZScores1Click�� TMenuItemIntensitynormalization1CaptionIntensity normalization� TMenuItemMaskedintensitynormalizationA1TagCaption Masked intensity normalization AShortCutI@OnClick Masked1Click�� TMenuItemMasked1Caption Masked intensity normalization BOnClick Masked1Click�� TMenuItemMaskedintensitynormalizationB1TagCaption Masked intensity normalization COnClick Masked1Click�� TMenuItemIntensitynormalizationA1TagCaptionIntensity normalization AOnClick Balance1Click�� TMenuItemBalance1CaptionIntensity normalization BOnClick Balance1Click�� TMenuItemSetnonseroto1001CaptionSet non-zero to 100OnClickSetnonseroto1001Click���� TMenuItemHelp1CaptionHelp� TMenuItemAbout1CaptionAboutShortCutA@OnClick About1Click�� TMenuItemAssociatevalfileswithNPM1CaptionAssociate .val files with NPMOnClickAssociatevalfileswithNPM1Click����TTimer StartTimerEnabledOnTimerStartTimerTimerLeft�TopP�����������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/results.niiNotesseverity.txt�����������������������������������0000755�0001750�0001750�00000004403�11326425450�022624� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Threads: 2 Factor = severity c:\mri\anacom\n01.voi = 4.00 c:\mri\anacom\n02.voi = 4.50 c:\mri\anacom\n03.voi = 0.00 c:\mri\anacom\n04.voi = 2.50 c:\mri\anacom\n05.voi = 5.00 c:\mri\anacom\n06.voi = 4.00 c:\mri\anacom\n07.voi = 3.25 c:\mri\anacom\n08.voi = 0.75 c:\mri\anacom\n09.voi = 4.50 c:\mri\anacom\n10.voi = 4.50 c:\mri\anacom\n11.voi = 0.50 c:\mri\anacom\n12.voi = 1.63 c:\mri\anacom\n13.voi = 0.00 c:\mri\anacom\n14.voi = 3.50 c:\mri\anacom\n15.voi = 3.00 c:\mri\anacom\n17.voi = 4.00 c:\mri\anacom\n18.voi = 2.00 c:\mri\anacom\n19.voi = 4.50 c:\mri\anacom\n20.voi = 5.00 c:\mri\anacom\n21.voi = 0.00 c:\mri\anacom\n22.voi = 1.50 c:\mri\anacom\n23.voi = 5.00 c:\mri\anacom\n24.voi = 2.50 c:\mri\anacom\n25.voi = 5.00 c:\mri\anacom\n26.voi = 4.00 c:\mri\anacom\n27.voi = 0.00 c:\mri\anacom\n28.voi = 0.00 c:\mri\anacom\n29.voi = 2.00 c:\mri\anacom\n30.voi = 1.50 c:\mri\anacom\n31.voi = 1.75 c:\mri\anacom\n32.voi = 0.00 c:\mri\anacom\n33.voi = 2.50 c:\mri\anacom\n34.voi = 5.00 c:\mri\anacom\n35.voi = 0.00 c:\mri\anacom\n37.voi = 0.00 c:\mri\anacom\n38.voi = 3.25 c:\mri\anacom\n39.voi = 4.38 c:\mri\anacom\n40.voi = 0.00 c:\mri\anacom\n41.voi = 3.75 c:\mri\anacom\n42.voi = 0.25 c:\mri\anacom\n43.voi = 0.00 c:\mri\anacom\n44.voi = 2.00 c:\mri\anacom\n45.voi = 5.00 c:\mri\anacom\n46.voi = 0.00 c:\mri\anacom\n47.voi = 0.50 c:\mri\anacom\n48.voi = 0.00 c:\mri\anacom\n49.voi = 2.25 c:\mri\anacom\n50.voi = 0.00 c:\mri\anacom\n51.voi = 2.25 c:\mri\anacom\n52.voi = 2.00 c:\mri\anacom\n53.voi = 0.00 c:\mri\anacom\n54.voi = 0.25 c:\mri\anacom\n55.voi = 0.00 Total voxels = 7109137 Only testing voxels damaged in at least 5 individual[s] Number of Lesion maps = 53 Permutations = 0 Analysis began = 2008-Mar-24 14:41:02 Memory planks = 0.701815434883711 Max voxels per Plank = 10129639 Computing plank = 1 Voxels tested = 40826 Only tested voxels with more than 5 lesions 40826 test Std Bonferroni FWE Z 0.050=4.712, 0.025=4.852, 0.01=5.030 n=,53,minN=,5,unique overlap patterns,9785,voxels tested,20016 9785 test Unique overlap Bonferroni FWE Z 0.050=4.412, 0.025=4.560, 0.01=4.749 ttest Range -3.936...5.118 ttest +FDR Z 0.050=2.085, 0.01=3.152 ttest -FDR Z 0.050=-3.440, 0.01=9.200 Analysis finished = 2008-Mar-24 14:41:50 �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/npm/statcr.pas�����������������������������������������������������0000755�0001750�0001750�00000037371�12156151406�017016� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Unit statcr; interface uses dialogsx,define_types; const ITMAX = 300; EPS = 3.0e-7; kMaxFact = 1700; {<= 1754} gFactRAready : boolean = false; type FactRA = array[0..kMaxFact] of extended; var gFactRA : FactRA; FUNCTION betai(a,b,x: double): double; procedure AlertMsg (pWarningStr: String); function gammq( a,x: real): real; function Fisher (A,B,C,D: integer): double; procedure Chi2x2 (A, B, C, D: integer; var pMinExp, pChi, p, puChi, pup: double); function Liebermeister (A,B,C,D: integer): extended; procedure EstimateFDR(lnTests: integer; Ps: SingleP; var lFDR05, lFDR01: double); function Fisher1TailMidP (A,B,C,D: integer): double; { use instead of chi2x2: returns p-value} procedure InitFact; procedure EstimateFDR2(lnTests: integer; var Ps: SingleP; var lFDR05, lFDR01,lnegFDR05, lnegFDR01: double); procedure Descriptive (nV, SumOfSqrs, Sum: double; var lMn,lSD,lSE: double); procedure SuperDescriptive (var RA: SingleP; n: integer; var lMn,lSD,lSE,lSkew,lZSkew: double); implementation uses Math{power}; procedure Descriptive (nV, SumOfSqrs, Sum: double; var lMn,lSD,lSE: double); //given nV,SumOfSqrs,and Sum, returns Mean, StandardDeviation,StandardError and Skew begin //first: initialize values lSD := 0; lSE := 0; lMn := 0; if nV < 1 then exit; //next: compute mean lMn := Sum / nV; if (nV < 2) then exit; lSD := SumOfSqrs-(Sum*Sum/nV); lSD := sqrt((lSD)/(nV-1) ); lSE := lSD/ sqrt(nV); end; procedure SuperDescriptive (var RA: SingleP; n: integer; var lMn,lSD,lSE,lSkew,lZSkew: double); var i: integer; SumOfSqrs,Sum,Sigma: double; begin lMn:= 0; lSD := 0; lSE := 0; lSkew := 0; lZSkew := 0; if n < 1 then exit; Sum := 0; SumOfSqrs := 0; for i := 1 to n do begin Sum := Sum + RA^[i]; SumOfSqrs := SumOfSqrs + sqr(RA^[i]); end; Descriptive (n, SumOfSqrs, Sum,lMn,lSD,lSE); if (n < 3) or (lSD = 0) then lSkew := 0 else begin Sigma := 0; for i := 1 to n do Sigma := Sigma + Power( ((RA^[i]-lMn) / lSD) ,3); lSkew := (n/ ( (n-1)*(n-2) ) ) * Sigma; end; lZSkew := lSkew/(sqrt(6/N)); end; procedure InitFact; var lX: word; begin gFactRA[0]:= 1; gFactRA[1] := 1; for lx := 2 to kMaxFact do gFactRA[lx] := lx * gFactRA[lx-1]; gFactRAready := true; end; function FisherX (A,B,C,D: integer): double; {FisherExactTest, use instead of chi} {FisherX computes odds for this specific config only, not more extreme cases} {alternate to Chi Square, see Siegel & Castellan, Nonparametric Statistics} {use instead of Chi when n <= 20} {A= X hits, B= control hits, C = X misses, D = control misses} var N: word; begin N := A+B+C+D; if (N <= kMaxFact) and (A>=0) and (B>=0) and (C>=0) and (D>=0) and (N > 0) then begin FisherX := ( (gFactRA[A+B]/gFactRA[A])* (gFactRA[B+D]/gFactRA[B])* (gFactRA[A+C]/gFactRA[C])* (gFactRA[C+D]/gFactRA[D]) )/ gFactRA[N]; end else FisherX := 0; end; function MidPKingFisher (lSmal,lCross1,lCross2,lSmalDiag: integer): extended; var lProb1, lProb2: extended; lA,lB,lC,lD,lCnt: integer; l1st : boolean; begin lA :=lSmal; lB:=lCross1; lC:=lCross2; lD:=lSmalDiag; lProb1:=0; l1st := true; //set to true for midP for lCnt := lA downto 0 do begin if l1st then lProb1 := 0.5* FisherX(lA,lB,lC,lD) else lProb1 := lProb1 + FisherX(lA,lB,lC,lD); l1st := false; dec(lA); dec(lD); inc(lB); inc(lC); end; lA :=lSmal; lB:=lCross1; lC:=lCross2; lD:=lSmalDiag; lProb2:=0; l1st := true; //alfa -set to true for MidP while (lB >= 0) and (lC >= 0) do begin if l1st then lProb2 := 0.5* FisherX(lA,lB,lC,lD) else lProb2 := lProb2 + FisherX(lA,lB,lC,lD); l1st := false; inc(lA); inc(lD); dec(lB); dec(lC); end; if lProb1 < lProb2 then result := lProb1 else result := lProb2; //result := lprob1; end; function KingFisher (lSmal,lCross1,lCross2,lSmalDiag: integer): double; var lProb1, lProb2: double; lA,lB,lC,lD,lCnt: integer; begin lA :=lSmal; lB:=lCross1; lC:=lCross2; lD:=lSmalDiag; lProb1:=0; for lCnt := lA downto 0 do begin lProb1 := lProb1 + FisherX(lA,lB,lC,lD); dec(lA); dec(lD); inc(lB); inc(lC); end; lA :=lSmal; lB:=lCross1; lC:=lCross2; lD:=lSmalDiag; lProb2:=0; while (lB >= 0) and (lC >= 0) do begin lProb2 := lProb2 + FisherX(lA,lB,lC,lD); inc(lA); inc(lD); dec(lB); dec(lC); end; if lProb1 < lProb2 then result := lProb1 else result := lProb2; end; function Lieber (lSmal,lCross1,lCross2,lSmalDiag: integer): extended; var lA,lB,lC,lD,lCnt: integer; begin lA :=lSmal; lB:=lCross1+1; lC:=lCross2+1; lD:=lSmalDiag; result :=0; for lCnt := lA downto 0 do begin result := result + FisherX(lA,lB,lC,lD); dec(lA); dec(lD); inc(lB); inc(lC); end; //TabbedNotebookDlg.caption := realtostr(result,6) ; //TabbedNotebookDlg.caption := realtostr(result,6) ; if result <= 0.5 then exit; lA :=lSmal+1; lB:=lCross1; lC:=lCross2; lD:=lSmalDiag+1; result:=0; while (lB >= 0) and (lC >= 0) do begin result := result + FisherX(lA,lB,lC,lD); inc(lA); inc(lD); dec(lB); dec(lC); end; end; function Liebermeister (A,B,C,D: integer): extended; {A= X hits, B= control hits, C = X misses, D = control misses} begin result := 1; if (A+B+C+D)<1 then exit; if not gFactRAready then InitFact; if (A<=B) and (A<=C) and (A<=D) then {lA smallest} result :=Lieber(A,B,C,D) else if (B<=C) and (B<=D) then {lB smallest} result :=Lieber(B,A,D,C) else if (C<=D) then {lC smallest} result :=Lieber(C,D,A,B) else {d smallest} result :=Lieber(D,C,B,A); if ((A+C)>0) and ((B+D)>0) then begin if (A/(A+C)) < (B/(B+D)) then result := -result; end; end; (*function Liebermeister (Ain,Bin,Cin,Din: integer): extended; var A,B,C,D: integer; {A= X hits, B= control hits, C = X misses, D = control misses} begin A := Ain; B := Bin; C := Cin; D := Din; if (A+B+C+D)<1 then begin result := 1; exit; end; //easy way to calculate Lieberman - make more extreme, then calculate Fisher if abs(A-D) > abs(B-C) then begin inc(A); inc(D); end else begin inc(B); inc(C); end; if not gFactRAready then InitFact; if (A<=B) and (A<=C) and (A<=D) then {lA smallest} result :=KingFisher(A,B,C,D) else if (B<=C) and (B<=D) then {lB smallest} result :=KingFisher(B,A,D,C) else if (C<=D) then {lC smallest} result :=KingFisher(C,D,A,B) else {d smallest} result :=KingFisher(D,C,B,A); if ((A+C)>0) and ((B+D)>0) then begin if (A/(A+C)) < (B/(B+D)) then result := -result; end; end;*) function Fisher (A,B,C,D: integer): double; {A= X hits, B= control hits, C = X misses, D = control misses} begin if (A+B+C+D)<1 then begin result := 1; exit end; if not gFactRAready then InitFact; if (A<=B) and (A<=C) and (A<=D) then {lA smallest} result :=KingFisher(A,B,C,D) else if (B<=C) and (B<=D) then {lB smallest} result :=KingFisher(B,A,D,C) else if (C<=D) then {lC smallest} result :=KingFisher(C,D,A,B) else {d smallest} result :=KingFisher(D,C,B,A); if ((A+C)>0) and ((B+D)>0) then begin if (A/(A+C)) < (B/(B+D)) then result := -result; end; end; function Fisher1TailMidP (A,B,C,D: integer): double; {A= X hits, B= control hits, C = X misses, D = control misses} begin if (A+B+C+D)<1 then begin result := 1; exit end; if not gFactRAready then InitFact; if (A<=B) and (A<=C) and (A<=D) then {lA smallest} result :=MidPKingFisher(A,B,C,D) else if (B<=C) and (B<=D) then {lB smallest} result :=MidPKingFisher(B,A,D,C) else if (C<=D) then {lC smallest} result :=MidPKingFisher(C,D,A,B) else {d smallest} result :=MidPKingFisher(D,C,B,A); if ((A+C)>0) and ((B+D)>0) then begin if (A/(A+C)) < (B/(B+D)) then result := -result; end; end; procedure Sort (first, last: integer; var DynDataRA:SingleP); {Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.} {less memory intensive than recursive quicksort} label 555; const tiny = 1.0e-5; aln2i = 1.442695022; var n, nn, m, lognb2, l, k, j, i: INTEGER; swap: Single; begin n := abs(last - first + 1); lognb2 := trunc(ln(n) * aln2i + tiny); m := last; for nn := 1 to lognb2 do begin m := m div 2; k := last - m; for j := 1 to k do begin i := j; 555: {<- LABEL} l := i + m; if (DynDataRA^[l] < DynDataRA^[i]) then begin swap := DynDataRA^[i]; DynDataRA^[i] := DynDataRA^[l]; DynDataRA^[l] := swap; i := i - m; if (i >= 1) then goto 555; end end end end;//sort procedure EstimateFDR(lnTests: integer; Ps: SingleP; var lFDR05, lFDR01: double); var lInc: integer; Qs: SingleP; begin //rank Pvalues Sort(1,lnTests,Ps); {lStr := 'sort='; for lInc := 1 to knTests do lStr := lStr+realtostr(Ps[lInc],4)+','; Memo1.Lines.Add(lStr); } GetMem(Qs,lnTests*sizeof(single)); //next findcrit FDR05 for lInc := 1 to lnTests do Qs^[lInc] := (0.05*lInc)/lnTests; lFDR05 := 0; for lInc := 1 to lnTests do if Ps^[lInc] <= Qs^[lInc] then lFDR05 := Ps^[lInc]; //next findcrit FDR01 for lInc := 1 to lnTests do Qs^[lInc] := (0.01*lInc)/lnTests; lFDR01 := 0; for lInc := 1 to lnTests do if Ps^[lInc] <= Qs^[lInc] then lFDR01 := Ps^[lInc]; Freemem(Qs); end; procedure EstimateFDR2(lnTests: integer; var Ps: SingleP; var lFDR05, lFDR01,lnegFDR05, lnegFDR01: double); var lInc: integer; lrPs,Qs: SingleP; begin //rank Pvalues Sort(1,lnTests,Ps); {lStr := 'sort='; for lInc := 1 to knTests do lStr := lStr+realtostr(Ps[lInc],4)+','; Memo1.Lines.Add(lStr); } GetMem(Qs,lnTests*sizeof(single)); //next findcrit FDR05 for lInc := 1 to lnTests do Qs^[lInc] := (0.05*lInc)/lnTests; lFDR05 := 0; for lInc := 1 to lnTests do if Ps^[lInc] <= Qs^[lInc] then lFDR05 := Ps^[lInc]; //next findcrit FDR01 for lInc := 1 to lnTests do Qs^[lInc] := (0.01*lInc)/lnTests; lFDR01 := 0; for lInc := 1 to lnTests do if Ps^[lInc] <= Qs^[lInc] then lFDR01 := Ps^[lInc]; //reverse GetMem(lrPs,lnTests*sizeof(single)); for lInc := 1 to lnTests do lrPs^[lInc] := 1- Ps^[lnTests-lInc+1]; //for lInc := 1 to lnTests do // Ps[lInc] := lR[lnTests-lInc+1]; for lInc := 1 to lnTests do Qs^[lInc] := (0.05*lInc)/lnTests; lnegFDR05 := 0; for lInc := 1 to lnTests do if lrPs^[lInc] <= Qs^[lInc] then lnegFDR05 := lrPs^[lInc]; //next findcrit FDR01 for lInc := 1 to lnTests do Qs^[lInc] := (0.01*lInc)/lnTests; lnegFDR01 := 0; for lInc := 1 to lnTests do if lrPs^[lInc] <= Qs^[lInc] then lnegFDR01 := lrPs^[lInc]; FreeMem(lrPs); Freemem(Qs); end; procedure AlertMsg (pWarningStr: String); begin ShowMsg(pWarningStr); end; function gammln (xx: double): double; {Numerical Recipes for Pascal, p 177} const stp = 2.50662827465; var x, tmp, ser: double; begin x := xx - 1.0; tmp := x + 5.5; tmp := (x + 0.5) * ln(tmp) - tmp; ser := 1.0 + 76.18009173 / (x + 1.0) - 86.50532033 / (x + 2.0) + 24.01409822 / (x + 3.0) - 1.231739516 / (x + 4.0) + 0.120858003e-2 / (x + 5.0) - 0.536382e-5 / (x + 6.0); gammln := tmp + ln(stp * ser) end; {procedure gammln} FUNCTION betacf(a,b,x: double): double; LABEL 1; CONST itmax=100; eps=3.0e-7; VAR tem,qap,qam,qab,em,d: double; bz,bpp,bp,bm,az,app: double; am,aold,ap: double; m: integer; BEGIN am := 1.0; bm := 1.0; az := 1.0; qab := a+b; qap := a+1.0; qam := a-1.0; bz := 1.0-qab*x/qap; FOR m := 1 TO itmax DO BEGIN em := m; tem := em+em; d := em*(b-m)*x/((qam+tem)*(a+tem)); ap := az+d*am; bp := bz+d*bm; d := -(a+em)*(qab+em)*x/((a+tem)*(qap+tem)); app := ap+d*az; bpp := bp+d*bz; aold := az; am := ap/bpp; bm := bp/bpp; az := app/bpp; bz := 1.0; IF ((abs(az-aold)) < (eps*abs(az))) THEN GOTO 1 END; writeln('pause in BETACF'); writeln('a or b too big, or itmax too small'); readln; 1: betacf := az END; FUNCTION betai(a,b,x: double): double; VAR bt: double; BEGIN IF ((x < 0.0) OR (x > 1.0)) THEN BEGIN writeln('pause in routine BETAI'); readln END; IF ((x = 0.0) OR (x = 1.0)) THEN bt := 0.0 ELSE bt := exp(gammln(a+b)-gammln(a)-gammln(b) +a*ln(x)+b*ln(1.0-x)); IF (x < ((a+1.0)/(a+b+2.0))) THEN betai := bt*betacf(a,b,x)/a ELSE betai := 1.0-bt*betacf(b,a,1.0-x)/b END; procedure gser(var gamser, a,x, gln: real); var n: integer; sum, del, ap: real; begin gln := gammln(a); if x <= 0.0 then begin if x < 0.0 then AlertMsg('x less then 0 in routine GSER'); gamser:= 0.0; end else begin ap := a; sum := 1.0/a; del := sum; for n := 1 to ITMAX do begin ap := ap + 1; del := del * (x/ap); sum := sum + del; if (abs(del) < abs((sum)*EPS) )then begin gamser := sum * exp(-x+a*ln(x)-gln); exit; end; end; Alertmsg('GSER error: ITMAX too small for requested a-value'); end; end; procedure gcf(var gammcf: real; a,x, gln: real); var n: integer; gold,fac,b1,b0,a0,g,ana,anf,an,a1: real; begin fac := 1.0; b1 := 1.0; b0 := 0.0; a0 := 1.0; gold := 0.0; gln := gammln(a); a1 := x; for n := 1 to ITMAX do begin an :=(n); ana := an - a; a0 := (a1 + a0*ana)*fac; b0 := (b1 + b0*ana)*fac; anf := an * fac; a1 := x*a0+anf*a1; b1 := x*b0+anf*b1; if a1 <> 0 then begin fac := 1.0/a1; g := b1*fac; if (abs((g-gold)/g)<EPS) then begin gammcf := exp(-x+a*ln(x)-gln)*g; exit; end; gold := g; end; end; Alertmsg('GCF error: ITMAX too small for requested a-value'); end; function gammq( a,x: real): real; var gamser, gammcf, gln: real; begin gammq := 0; if (x < 0) or (a <= 0.0) then alertmsg('Invalid arguments in routine GAMMQ') else begin if (x < (a+1.0)) then begin gser(gamser,a,x,gln); gammq := 1.0 - gamser; end else begin gcf(gammcf,a,x,gln); gammq := gammcf; end; end; end; procedure Chi2x2 (A, B, C, D: integer; var pMinExp, pChi, p, puChi, pup: double); {A= X hits, B= control hits, C = X misses, D = control misses} var lA, lB, lC, lD, lN: extended; {AEXp, BExp, CExp, Dexp, } lSameOdds: boolean; begin lA := A; {convert to extended} lB := B; lC := C; lD := D; ln := lA + lB + lC + lD; if lN > 0 then begin {avoid divide by 0} pMinExp := ((lA + lB) * (lA + lC)) / lN; if (((lA + lB) * (lB + lD)) / lN) < pMinExp then pMinExp := ((lA + lB) * (lB + lD)) / lN; if (((lC + lD) * (lA + lC)) / lN) < pMinExp then pMinExp := ((lC + lD) * (lA + lC)) / lN; if (((lC + lD) * (lB + lD)) / lN) < pMinExp then pMinExp := ((lC + lD) * (lB + lD)) / lN; end else pMinExp := 0; lSameOdds := false; if (lC > 0) and (lD > 0) then begin if (lA / lC) = (lB / lD) then lSameOdds := true; end; if (lC = 0) and (lD = 0) then lSameOdds := true; if ((lA+lC) = 0) or ((lB+lD) = 0) then lSameOdds := true; if (lSameOdds = true) then begin pChi := 0; {same odds} p := 1.0; puChi := 0; pup := 1.0; end else begin puChi := ((sqr((lA * lD) - (lB * lC))) * lN) / ((la + lb) * (lc + ld) * (lb + ld) * (la + lc)); pup := gammq(0.5, 0.5 * puChi); {half df} pChi := ((sqr(abs((lA * lD) - (lB * lC)) - (0.5 * lN))) * lN) / ((la + lb) * (lc + ld) * (lb + ld) * (la + lc)); p := gammq(0.5, 0.5 * pChi); end; end; END. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/rendernothreads.pas������������������������������������������������0000755�0001750�0001750�00000032066�11326425450�020110� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit rendernothreads; interface {$include isthreaded.inc} {$mode objfpc}{$H+} uses {$IFDEF SHOWPROG}Forms,{$ENDIF} ComCtrls,Classes, SysUtils, define_types,GraphicsMathLibrary; const kSh = 10; //bits to shift - precision for integers to simulate floats type TRotateVals = record InSliceSz,ZDimStart,ZDimEnd,YDimStart,YDimEnd,OutPivot,OutDim,OutSliceSz: integer; XPivotInU2,YDimIN,YPivotInU2,ZDimIN,ZPivotInU2,XDimIN: integer; XPivotIn,YPivotIn,ZPivotIn: integer; Xxra,Xyra,Xzra: longintp; //RenderCutout: boolean; end; procedure NNRotate (lBar: TProgressBar; l: TRotateVals; var lM: TMatrix; lRenderCutout: boolean; var lBuffIn,lBuffOut: ByteP); procedure TriRotate (lBar: TProgressBar; l: TRotateVals; var lM: TMatrix; lRenderCutout: boolean; var lBuffIn,lBuffOut: ByteP); implementation {$IFDEF SHOWPROG} procedure VisualProg(lBar: TProgressBar; lPos: Integer); begin lBar.Position := lPos; Application.ProcessMessages; end; {$ENDIF}//IFDEF SHOWPROG procedure FindXBounds (var lXMax,lXMin: integer; lXDimIN,lYxiZxi,lXPivotInU2,lYDimIN,lYyiZyi,lYPivotInU2,lZDimIN,lYziZzi,lZPivotInU2,lOutDim:integer; lXxra,lXyra,lXzra : LongIntP); var lXo,lYo,lZo,Xo_at_one,Xo_at_two,Xo_grad,Xo_offs,lShiftedOne : integer; when_it_is_zero, when_it_is_max: double; lReallySmall {, debugx0, debugx1, debugy0, debugy1, debugz0, debugz1}: double; l2: integer; begin lXMax := lOutDim; lXMin := 1; l2 := 2; lShiftedOne := 1 shl ksh; lReallySmall := 1e-6; Xo_at_one := lXxRA^[1] +lYxiZxi + (lXPivotInU2 shl kSh); Xo_at_two := lXxRA^[l2] +lYxiZxi + (lXPivotInU2 shl kSh); Xo_grad := Xo_at_two - Xo_at_one; Xo_offs := Xo_at_one - Xo_grad; if Abs(Xo_grad) > lReallySmall then begin when_it_is_zero := (lShiftedOne-Xo_offs) / Xo_grad; when_it_is_max := ((lXDimIn shl kSh)-Xo_offs) / Xo_grad; //debugx0 := when_it_is_zero; debugx1 := when_it_is_max; if (when_it_is_zero < when_it_is_max) then begin if when_it_is_zero > lXMin then lXMin := Round(when_it_is_zero+0.5); if when_it_is_max < lXMax then lXMax := Round(when_it_is_max-0.5); end else begin if when_it_is_max > lXMin then lXMin := Round(when_it_is_max+0.5); if when_it_is_zero < lXMax then lXMax := Round(when_it_is_zero-0.5); end; end; Xo_at_one := lXyRA^[1] +lYyiZyi + (lYPivotInU2 shl kSh); Xo_at_two := lXyRA^[l2] +lYyiZyi + (lYPivotInU2 shl kSh); Xo_grad := Xo_at_two - Xo_at_one; Xo_offs := Xo_at_one - Xo_grad; if Abs(Xo_grad) > lReallySmall then begin when_it_is_zero := (lShiftedOne-Xo_offs) / Xo_grad; when_it_is_max := ((lYDimIn shl kSh)-Xo_offs) / Xo_grad; //debugy0 := when_it_is_zero; debugy1 := when_it_is_max; if (when_it_is_zero < when_it_is_max) then begin if when_it_is_zero > lXMin then lXMin := Round(when_it_is_zero+0.5); if when_it_is_max < lXMax then lXMax := Round(when_it_is_max-0.5); end else begin if when_it_is_max > lXMin then lXMin := Round(when_it_is_max+0.5); if when_it_is_zero < lXMax then lXMax := Round(when_it_is_zero-0.5); end; end; Xo_at_one := lXzRA^[1] +lYziZzi + (lZPivotInU2 shl kSh); Xo_at_two := lXzRA^[l2] +lYziZzi + (lZPivotInU2 shl kSh); Xo_grad := Xo_at_two - Xo_at_one; Xo_offs := Xo_at_one - Xo_grad; if Abs(Xo_grad) > lReallySmall then begin when_it_is_zero := (lShiftedOne-Xo_offs) / Xo_grad; when_it_is_max := ((lZDimIn shl kSh)-Xo_offs) / Xo_grad; //debugz0 := when_it_is_zero; debugz1 := when_it_is_max; if (when_it_is_zero < when_it_is_max) then begin if when_it_is_zero > lXMin then lXMin := Round(when_it_is_zero+0.5); if when_it_is_max < lXMax then lXMax := Round(when_it_is_max-0.5); end else begin if when_it_is_max > lXMin then lXMin := Round(when_it_is_max+0.5); if when_it_is_zero < lXMax then lXMax := Round(when_it_is_zero-0.5); end; end; // even with all the care about rounding, it's possible that we've got the // edges wrong in ultra-high-gradient cases if lXMin < lXMax then begin while true do begin lXo := ((lXxRA^[lXMin] +lYxiZxi) shr kSh)+lXPivotInU2; lYo := ((lXyRA^[lXMin] +lYyiZyi) shr kSh)+lYPivotInU2; lZo := ((lXzRA^[lXMin] +lYziZzi) shr kSh)+lZPivotInU2; if (lXMin < lXMax) and ((lXo<1) or (lXo>lXDimIn) or (lYo<1) or (lYo>lYDimIn) or (lZo<1) or (lZo>lZDimIn)) then begin lXMin := 1+lXMin; end else break; end; while true do begin lXo := ((lXxRA^[lXMax] +lYxiZxi) shr kSh)+lXPivotInU2; lYo := ((lXyRA^[lXMax] +lYyiZyi) shr kSh)+lYPivotInU2; lZo := ((lXzRA^[lXMax] +lYziZzi) shr kSh)+lZPivotInU2; if (lXMax > lXMin) and ((lXo<1) or (lXo>lXDimIn) or (lYo<1) or (lYo>lYDimIn) or (lZo<1) or (lZo>lZDimIn)) then begin lXMax := lXMax-1; end else break; end; end; end;//proc findXBounds procedure NNRotate (lBar: TProgressBar; l: TRotateVals; var lM: TMatrix; lRenderCutout: boolean; var lBuffIn,lBuffOut: ByteP); const kshx = ksh shr 1; var lZxi,lZyi,lZzi,lYxiZxi,lYyiZyi,lYziZzi,lZ,lY,lX,lOutPos, lMaxX,lMinX,lXo,lYo,lZo: integer; begin for lZ := l.ZDimStart to l.ZDimEnd do begin lZxi := round(lZ*lM.matrix[1,3]* (1 shl kSh) ); lZyi := round(lZ*lM.matrix[2,3]* (1 shl kSh) ); lZzi := round(lZ*lM.matrix[3,3]* (1 shl kSh) ); {$IFDEF SHOWPROG} //flicker with lazarus if ((lZ mod 30)=0) then VisualProg(lBar,lZ); {$ENDIF} //ImgForm.ProgressBar1.Position := lZ; for lY := l.YDimStart to l.YDimEnd do begin lYxiZxi := round(lY * lM.matrix[1,2]* (1 shl kSh) )+lZxi; lYyiZyi := round(lY * lM.matrix[2,2]* (1 shl kSh) )+lZyi; lYziZzi := round(lY * lM.matrix[3,2]* (1 shl kSh) )+lZzi; lOutPos := ((lZ+l.OutPivot-1)*l.OutSliceSz)+((lY+l.OutPivot-1)*l.Outdim); //if gAbortRender > 0 then goto 345; FindXBounds (lMaxX,lMinX,l.XDimIN,lYxiZxi,l.XPivotInU2,l.YDimIN,lYyiZyi,l.YPivotInU2,l.ZDimIN,lYziZzi,l.ZPivotInU2,l.OutDim,l.Xxra,l.Xyra,l.Xzra); if lMaxX > lMinX then for lX := lMinX to lMaxX do begin lXo := ((l.XxRA^[lX] +lYxiZxi) shr kSh)+l.XPivotInU2; lYo := ((l.XyRA^[lX] +lYyiZyi) shr kSh)+l.YPivotInU2; lZo := ((l.XzRA^[lX] +lYziZzi) shr kSh)+l.ZPivotInU2; {lXo := (lXo shr 1) + 1; lYo := lYo shr 1; lZo := lZo shr 1;} lBuffOut[lX+lOutPos] := lBuffIn[(lXo)+((lYo-1)*l.XdimIn)+((lZo-1)*l.InSliceSz)] end; end; //for y end; //for z end; procedure TriRotate (lBar: TProgressBar; l: TRotateVals; var lM: TMatrix; lRenderCutout: boolean; var lBuffIn,lBuffOut: ByteP); //Trilinear - this uses integer math, and on CoreDuo CPUs is 30% faster than Floating Point //For precision, integers are multiplied by kSh (~2^10 bits) to simulate floats // However, we will use 32-bit integers and the image intensity is 8 bit values, // with the final interpolation multiplying X*Y*Z*intensity // Therefore, this final interpolation adjusts kSh to be 2^8, avoiding overflow var lMi: TMatrixi; lXr,lYr,lZr,lYxi,lYyi,lYzi,lXxi,lXyi,lXzi,lZxi,lZyi,lZzi, lYxiZxi,lYyiZyi,lYziZzi,lZ,lY,lX,lOutPos, lXPiv,lYPiv,lZPiv,lXrM1i,lYrM1i,lZrM1i, lShr,lShl,lShlTo8,lShl8, lMinZ,lMaxZ,lMinY,lMaxY,lMaxX,lMinX,lXo,lYo,lZo: integer; begin lShl := 1 shl kSh; lShl8 := 1 shl 8; //8bit precision lShlTo8 := (kSh - 8); //shr the kSh precision by this to get 8-bit precision lShr := 24;//24-bits * 8 bit intensity = 32 bits lXPiv := l.XPivotIn * lShl; lYPiv := l.YPivotIn * lShl; lZPiv := l.ZPivotIn * lShl; for lX := 1 to 3 do for lY := 1 to 3 do lMi.matrix[lX,lY] := round(lM.matrix[lX,lY] * lShl); if (lRenderCutout ) then begin //only separated to unroll IF rendercutout for lZ := l.ZDimStart to l.ZDimEnd do begin lZxi := (lZ*lMi.matrix[1,3] ); lZyi := (lZ*lMi.matrix[2,3] ); lZzi := (lZ*lMi.matrix[3,3] ); {$IFDEF SHOWPROG} //flicker with lazarus if ((lZ mod 30)=0) then VisualProg(lBar,lZ); {$ENDIF} for lY := l.YDimStart to l.YDimEnd do begin lYxi := lY * lMi.matrix[1,2]; lYyi := lY * lMi.matrix[2,2]; lYzi := lY * lMi.matrix[3,2]; lYxiZxi := (lY * lMi.matrix[1,2] )+lZxi; lYyiZyi := (lY * lMi.matrix[2,2] )+lZyi; lYziZzi := (lY * lMi.matrix[3,2] )+lZzi; FindXBounds (lMaxX,lMinX,l.XDimIN,lYxiZxi,l.XPivotInU2,l.YDimIN,lYyiZyi,l.YPivotInU2,l.ZDimIN,lYziZzi,l.ZPivotInU2,l.OutDim,l.Xxra,l.Xyra,l.Xzra); lMaxX := lMaxX - l.OutPivot -1 ; lMinX := lMinX - l.OutPivot+1; if lMaxX > lMinX then for lX := lMinX to lMaxX do begin lXr := ( (lX*lMi.matrix[1,1])+lYxi+lZxi)+lXPiv; lYr := ((lX*lMi.matrix[2,1])+lYyi+lZyi)+lYPiv; lZr := ( (lX*lMi.matrix[3,1])+lYzi+lZzi)+lZPiv; lXo := (lXr shr kSh); lYo := (lYr shr kSh); lZo := (lZr shr kSh); if (lXo > 0) and (lXo < l.XDimIn) and (lYo > 0) and (lYo < l.YDimIn) and (lZo > 0) and (lZo < l.ZDimIn) then begin lXr := (lXr- (lXo * lShl)) shr lShlTo8; lYr := (lYr- (lYo * lShl)) shr lShlTo8; lZr := (lZr- (lZo * lShl)) shr lShlTo8; lXrM1i := lShl8-lXr; lYrM1i := lShl8-lYr; lZrM1i := lShl8-lZr; lMinY := ((lYo-1)*l.XdimIn); lMinZ := ((lZo-1)*l.InSliceSz); lMaxY := ((lYo)*l.XdimIn); lMaxZ := ((lZo)*l.InSliceSz); lOutPos := ((lZ+l.OutPivot-1)*l.OutSliceSz)+((lY+l.OutPivot-1)*l.Outdim); if {(lRenderCutout ) and} ((lBuffIn^[lXo+lMinY+lMinZ]=255) or (lBuffIn^[lXo+1+lMinY+lMinZ]=255) or (lBuffIn^[lXo+lMaxY+lMinZ]=255) or (lBuffIn^[lXo+1+lMaxY+lMinZ]=255) or (lBuffIn^[lXo+lMinY+lMaxZ]=255) or (lBuffIn^[lXo+1+lMinY+lMaxZ]=255) or (lBuffIn^[lXo+lMaxY+lMaxZ]=255) or (lBuffIn^[lXo+1+lMaxY+lMaxZ]=255)) then lBuffOut^[lX+l.OutPivot+lOutPos] := 255 else lBuffOut^[lX+l.OutPivot+lOutPos] := ( (lXrM1i*lYrM1i*lZrM1i *lBuffIn^[lXo+lMinY+lMinZ] ) +(lXr*lYrM1i*lZrM1i *lBuffIn^[lXo+1+lMinY+lMinZ]) +(lXrM1i*lYr*lZrM1i *lBuffIn^[lXo+lMaxY+lMinZ] ) +(lXrM1i*lYrM1i*lZr *lBuffIn^[lXo+lMinY+lMaxZ] ) +(lXr*lYr*lZrM1i *lBuffIn^[lXo+1+lMaxY+lMinZ] ) +(lXr*lYrM1i*lZr *lBuffIn^[lXo+1+lMinY+lMaxZ] ) +(lXrM1i*lYr*lZr *lBuffIn^[lXo+lMaxY+lMaxZ]) +(lXr*lYr*lZr *lBuffIn^[lXo+1+lMaxY+lMaxZ] ) ) shr lShr; end; //values in range end; //for x end; //for y end; //for z exit; end; //if RenderCutout for lZ := l.ZDimStart to l.ZDimEnd do begin lZxi := (lZ*lMi.matrix[1,3] ); lZyi := (lZ*lMi.matrix[2,3] ); lZzi := (lZ*lMi.matrix[3,3] ); {$IFDEF SHOWPROG} //flicker with lazarus if ((lZ mod 30)=0) then VisualProg(lBar,lZ); {$ENDIF} for lY := l.YDimStart to l.YDimEnd do begin lYxi := lY * lMi.matrix[1,2]; lYyi := lY * lMi.matrix[2,2]; lYzi := lY * lMi.matrix[3,2]; lYxiZxi := (lY * lMi.matrix[1,2] )+lZxi; lYyiZyi := (lY * lMi.matrix[2,2] )+lZyi; lYziZzi := (lY * lMi.matrix[3,2] )+lZzi; FindXBounds (lMaxX,lMinX,l.XDimIN,lYxiZxi,l.XPivotInU2,l.YDimIN,lYyiZyi,l.YPivotInU2,l.ZDimIN,lYziZzi,l.ZPivotInU2,l.OutDim,l.Xxra,l.Xyra,l.Xzra); lMaxX := lMaxX - l.OutPivot -1 ; lMinX := lMinX - l.OutPivot+1; if lMaxX > lMinX then for lX := lMinX to lMaxX do begin lXr := ( (lX*lMi.matrix[1,1])+lYxi+lZxi)+lXPiv; lYr := ((lX*lMi.matrix[2,1])+lYyi+lZyi)+lYPiv; lZr := ( (lX*lMi.matrix[3,1])+lYzi+lZzi)+lZPiv; lXo := (lXr shr kSh); lYo := (lYr shr kSh); lZo := (lZr shr kSh); if (lXo > 0) and (lXo < l.XDimIn) and (lYo > 0) and (lYo < l.YDimIn) and (lZo > 0) and (lZo < l.ZDimIn) then begin lXr := (lXr- (lXo * lShl)) shr lShlTo8; lYr := (lYr- (lYo * lShl)) shr lShlTo8; lZr := (lZr- (lZo * lShl)) shr lShlTo8; lXrM1i := lShl8-lXr; lYrM1i := lShl8-lYr; lZrM1i := lShl8-lZr; lMinY := ((lYo-1)*l.XdimIn); lMinZ := ((lZo-1)*l.InSliceSz); lMaxY := ((lYo)*l.XdimIn); lMaxZ := ((lZo)*l.InSliceSz); lOutPos := ((lZ+l.OutPivot-1)*l.OutSliceSz)+((lY+l.OutPivot-1)*l.Outdim); lBuffOut^[lX+l.OutPivot+lOutPos] :=( (lXrM1i*lYrM1i*lZrM1i *lBuffIn^[lXo+lMinY+lMinZ] ) +(lXr*lYrM1i*lZrM1i *lBuffIn^[lXo+1+lMinY+lMinZ]) +(lXrM1i*lYr*lZrM1i *lBuffIn^[lXo+lMaxY+lMinZ] ) +(lXrM1i*lYrM1i*lZr *lBuffIn^[lXo+lMinY+lMaxZ] ) +(lXr*lYr*lZrM1i *lBuffIn^[lXo+1+lMaxY+lMinZ] ) +(lXr*lYrM1i*lZr *lBuffIn^[lXo+1+lMinY+lMaxZ] ) +(lXrM1i*lYr*lZr *lBuffIn^[lXo+lMaxY+lMaxZ]) +(lXr*lYr*lZr *lBuffIn^[lXo+1+lMaxY+lMaxZ] ) ) shr lShr; end; //values in range end; //for x end; //for y end; //for z end; end. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/voismooth.lrs������������������������������������������������������0000755�0001750�0001750�00000005623�11545433540�016766� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('Tvoismoothform','FORMDATA',[ 'TPF0'#14'Tvoismoothform'#13'voismoothform'#4'Left'#3#138#2#6'Height'#3#222#0 +#3'Top'#3#241#0#5'Width'#3#252#0#13'ActiveControl'#7#8'XROIfwhm'#11'BorderIc' +'ons'#11#12'biSystemMenu'#0#11'BorderStyle'#7#8'bsDialog'#7'Caption'#6#8'Blu' +'r VOI'#12'ClientHeight'#3#222#0#11'ClientWidth'#3#252#0#21'Constraints.MaxH' +'eight'#3#222#0#20'Constraints.MaxWidth'#3#252#0#21'Constraints.MinHeight'#3 +#222#0#20'Constraints.MinWidth'#3#252#0#8'OnCreate'#7#10'FormCreate'#6'OnSho' +'w'#7#8'FormShow'#8'Position'#7#14'poScreenCenter'#10'LCLVersion'#6#6'0.9.29' +#0#6'TLabel'#7'Label37'#4'Left'#2#12#6'Height'#2#17#3'Top'#2'.'#5'Width'#2'>' +#7'Caption'#6#9'Threshold'#12'Font.CharSet'#7#12'ANSI_CHARSET'#9'Font.Name'#6 +#13'MS Sans Serif'#11'ParentColor'#8#10'ParentFont'#8#0#0#12'TSpeedButton'#9 +'CancelBtn'#4'Left'#2'^'#6'Height'#2#25#4'Hint'#6'#Save to small-endian [Int' +'el] format'#3'Top'#3#167#0#5'Width'#2'B'#7'Caption'#6#6'Cancel'#5'Color'#7#9 +'clBtnFace'#9'NumGlyphs'#2#0#7'OnClick'#7#8'BtnClick'#8'ShowHint'#9#14'Paren' +'tShowHint'#8#0#0#12'TSpeedButton'#5'OKBtn'#3'Tag'#2#1#4'Left'#3#165#0#6'Hei' +'ght'#2#25#4'Hint'#6#31'Save to big-endian [Sun] format'#3'Top'#3#167#0#5'Wi' +'dth'#2'B'#7'Caption'#6#2'OK'#5'Color'#7#9'clBtnFace'#9'NumGlyphs'#2#0#7'OnC' +'lick'#7#8'BtnClick'#8'ShowHint'#9#14'ParentShowHint'#8#0#0#12'TSpeedButton' +#7'HelpBtn'#3'Tag'#2#2#4'Left'#2#21#6'Height'#2#25#3'Top'#3#167#0#5'Width'#2 +'B'#7'Caption'#6#4'Help'#5'Color'#7#9'clBtnFace'#9'NumGlyphs'#2#0#7'OnClick' +#7#12'HelpBtnClick'#14'ParentShowHint'#8#0#0#6'TLabel'#7'Label38'#4'Left'#2 +#12#6'Height'#2#17#3'Top'#2#9#5'Width'#3#143#0#7'Caption'#6#19'Smoothing (FW' +'HM mm)'#12'Font.CharSet'#7#12'ANSI_CHARSET'#9'Font.Name'#6#13'MS Sans Serif' +#11'ParentColor'#8#10'ParentFont'#8#0#0#9'TComboBox'#10'ScaleSides'#4'Left'#2 +#12#6'Height'#2#21#3'Top'#2'T'#5'Width'#3#229#0#10'ItemHeight'#2#13#13'Items' +'.Strings'#1#6'"Adjust sides in Z-plane only [SPM]'#6' Adjust sides in X,Y a' +'nd Z planes'#0#5'Style'#7#14'csDropDownList'#8'TabOrder'#2#0#0#0#9'TComboBo' +'x'#10'xROIoutput'#4'Left'#2#12#6'Height'#2#21#3'Top'#2'u'#5'Width'#3#229#0 +#10'ItemHeight'#2#13#13'Items.Strings'#1#6#22'ROI is 1 [reslice ROI]'#6#26'R' +'OI is 0 [SPM object mask]'#0#5'Style'#7#14'csDropDownList'#8'TabOrder'#2#1#0 +#0#14'TFloatSpinEdit'#10'XROIthresh'#4'Left'#3#175#0#6'Height'#2#21#3'Top'#2 +')'#5'Width'#2'F'#13'DecimalPlaces'#2#4#9'Increment'#5#0'('#206#251#255'n'#18 +#131#245'?'#8'MaxValue'#5#0#0#0#0#0#0#0#128#255'?'#8'MinValue'#5#0#0#0#0#0#0 +#0#0#0#0#8'TabOrder'#2#2#5'Value'#5#0#0#0#0#0#0#0#128#255'?'#0#0#9'TSpinEdit' +#8'XROIfwhm'#4'Left'#3#175#0#6'Height'#2#21#3'Top'#2#4#5'Width'#2'F'#8'MaxVa' +'lue'#2'('#8'MinValue'#2#1#8'TabOrder'#2#3#5'Value'#2#1#0#0#0 ]); �������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/graphx.pas���������������������������������������������������������0000755�0001750�0001750�00000114757�11425734216�016225� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit graphx; {$IFDEF FPC} {$mode objfpc}{$H+} {$ENDIF} interface {$DEFINE noFFTs} uses {$IFDEF FFTs} FFTs, {$ENDIF} {$IFDEF FPC} LResources, Spin, {$ELSE} ShlObj,Windows,RXSpin, {$ENDIF} Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Buttons, ToolWin, ComCtrls,define_types, ExtCtrls,Text, StdCtrls, perisettings, Menus,ClipBrd,metagraph,periplot,userdir; Type { TGraph4DForm } TGraph4DForm = class(TForm) Image1: TImage; MainMenu1: TMainMenu; MenuItem1: TMenuItem; Edit1: TMenuItem; CopyMenu: TMenuItem; CloseMenu: TMenuItem; FSLBatchMenu: TMenuItem; FFTMenu: TMenuItem; Extract4Drois: TMenuItem; BatchMenu: TMenuItem; SaveMenu: TMenuItem; OpenMenu: TMenuItem; MinEdit: TFloatSpinEdit; MaxEdit: TFloatSpinEdit; HSpeedDrop: TComboBox; PlotBtn: TSpeedButton; TextBtn: TSpeedButton; SelectDirectoryDialog1: TSelectDirectoryDialog; StatusBar1: TStatusBar; TrackBar1: TTrackBar; TREdit: TFloatSpinEdit; FourDBar: TPanel; TRLabel: TLabel; OpenDataBtn: TSpeedButton; RefreshBtn: TSpeedButton; //procedure Plot4DFFT(lStartSample: integer); //function XL: boolean; procedure FormShow(Sender: TObject); function ReadGraf(lFilename: string; lBatch,lTRcritical: boolean): boolean; procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure Plot4DTrace(lStartSample: integer); procedure TextBtnClick(Sender: TObject); procedure TrackBar1Change(Sender: TObject); procedure OpenDataClick(Sender: TObject); procedure FormResize(Sender: TObject); procedure PSPlotClick(Sender: TObject); procedure PSTextClick(Sender: TObject); //procedure rfx; procedure Copy1Click(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Closewindow1Click(Sender: TObject); procedure SaveasEMF1Click(Sender: TObject); procedure FFTitemClick(Sender: TObject); procedure RefreshBtnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Extract4DroisClick(Sender: TObject); procedure Batchdata1Click(Sender: TObject); procedure RefreshBtnClick(Sender: TObject); procedure FSLbatch1Click(Sender: TObject); procedure FSLtest1Click(Sender: TObject); private public { Public declarations } end; var Graph4DForm: TGraph4DForm; implementation uses nifti_img_view, nifti_img,nifti_hdr, nifti_hdr_view,periutils, reslice_fsl; const //kMaxCond = 6; kMaxLines = kMaxCond* knMaxOverlay; //kClrRA: array [1..kMaxCond] of TColor = (clRed,clBlue,clGreen,clTeal,clAqua,clSilver); //kPenStyleRA: array[1..kVOIOverlayNum] of TPenStyle = (psDot,psDot,psDash,psDashDot,psDashDotDot);//abba //kPenStyleRA: array[1..kVOIOverlayNum] of TPenStyle = (psSolid,psDot,psDash,psDashDot,psDashDotDot); {$IFNDEF FPC} {$R *.DFM} {$ENDIF} var g4DHdr: TMRIcroHdr; g4Ddata: T4DTrace; (*procedure PrepPlot(var lImage: TMetafileCanvas; lL,lT,lR,lB,lWid,lHt,lFontSize: integer); begin lImage.Font.Name := 'Arial'; lImage.Font.Size := 12; lImage.pen.color := clBlack; lImage.Font.color := clBlack; lImage.Brush.Style := bsSolid; lImage.Brush.color := clWhite; lImage.Rectangle(1,1,lWid,lHt); lImage.Rectangle(lL,lT,lR,lB); end; *) {$IFDEF FFTs} procedure ROI2FFT (var l4DHdr: TMRIcroHdr; lROInum: integer; var lFFTLines: SingleP); var lVolSz,lnVol,lVol,lVox,lCount,lVolOffset,lnFFTOut,lP: integer; l16Buf : SmallIntP; lFFT,lFFTOut,l32Buf : SingleP; lFFTsum: doubleP; begin lnVol := l4DHdr.NIFTIhdr.dim[4]; if lnVol < 5 then exit; lVolSz :=l4DHdr.NIFTIhdr.dim[1]*l4DHdr.NIFTIhdr.dim[2]*l4DHdr.NIFTIhdr.dim[3]; Getmem(lFFT,(lnVol) * Sizeof(Single)); lnFFTout := ((lnVol) div 2)-1 ; Getmem(lFFTout,(lnFFTout) * Sizeof(Single)); Getmem(lFFTsum,(lnFFTout) * Sizeof(double)); for lP := 1 to lnFFTout do lFFTSum[lP] := 0; for lP := 1 to lnFFTout do lFFTout[lP] := 0; lVolOffset := lVolSz; //next - compute sum of signal - unrolled loops for each datatype lCount := 0; if (l4DHdr.ImgBufferBPP = 4) then begin l32Buf := SingleP(l4DHdr.ImgBuffer ); for lVox := 1 to lVolSz do begin if gMRIcroOverlay[lROInum].ScrnBuffer[lVox] > 0 then begin for lVol := 1 to lnVol do lFFT[lVol] := l32Buf[lVox+((lVol-1)*lVolOffset)]; FFTPower(lFFT,lFFTout,lnVol); for lP := 1 to lnFFTout do lFFTSum[lP] := lFFTSum[lP]+lFFTout[lP]; inc(lCount); end; //part of ROI end; //for each vox end else if (l4DHdr.ImgBufferBPP = 2) then begin l16Buf := SmallIntP(l4DHdr.ImgBuffer ); for lVox := 1 to lVolSz do begin if gMRIcroOverlay[lROInum].ScrnBuffer[lVox] > 0 then begin for lVol := 1 to lnVol do lFFT[lVol] := l16Buf[lVox+((lVol-1)*lVolOffset)]; FFTPower(lFFT,lFFTout,lnVol); //FFTPower(lFFT,lFFx,lnVol); for lP := 1 to lnFFTout do lFFTSum[lP] := lFFTSum[lP]+lFFTout[lP]; inc(lCount); end; //part of ROI end; //for each vox end else if l4DHdr.ImgBufferBPP = 1 then begin for lVox := 1 to lVolSz do begin if gMRIcroOverlay[lROInum].ScrnBuffer[lVox] > 0 then begin for lVol := 1 to lnVol do lFFT[lVol] := l4DHdr.ImgBuffer[lVox+((lVol-1)*lVolOffset)]; FFTPower(lFFT,lFFTout,lnVol); for lP := 1 to lnFFTout do lFFTSum[lP] := lFFTSum[lP]+lFFTout[lP]; inc(lCount); end; //part of ROI end; //for each vox end else showmessage('Serious error: unknown data size!'); //now compute mean signal if lCount > 0 then begin for lP := 1 to lnFFTout do lFFTSum[lP] := lFFTSum[lP] / lCount; for lP := 1 to lnFFTout do if specialdouble(lFFTSum[lP]) then lFFTSum[lP] := 0; end; for lP := 1 to lnFFTout do lFFTLines[lP] := lFFTSum[lP]; freemem(lFFT); freemem(lFFTout); freemem(lFFTsum); end; procedure Plot4DFFT(lStartSample: integer); var //lDataOut: SingleP; lLines,N,I: Integer; l4DTrace: T4DTrace; begin if (g4dData.lines[1].events < 5) then exit; lLines := 1; for I := 2 to kMaxLines do if g4dData.lines[I].events =g4dData.lines[1].events then inc(lLines); N := g4dData.lines[1].events; N := (N div 2)-1; Create4DTrace ( l4DTrace); Init4DTrace(N,lLines,l4DTrace,false); lLines := 0; for I := 1 to kMaxLines do if g4dData.lines[I].events =g4dData.lines[1].events then begin inc(lLines); l4DTrace.lines[lLines].eLabel := ROIoverlayNameShort(0);// g4dData.lines[I].eLabel; N := g4dData.lines[I].events; FFTPower(g4dData.lines[I].EventRA,l4DTrace.lines[lLines].EventRA,N); end; //events[i] = events[1] MinMax4DTrace(l4dtrace); l4dtrace.HorzMin := 0; //range will be 0.. 1/TR*Nyquist Sec/Cycle if Graph4DForm.TREdit.value = 0 then l4dtrace.HorzWidPerBin := (0.5)/(l4dTrace.lines[1].events-1) else l4dtrace.HorzWidPerBin := ((1/Graph4DForm.TREdit.value)*0.5)/(l4dTrace.lines[1].events-1); CorePlot4DTrace(l4Dtrace,Graph4DForm.Image1,lStartSample,Graph4DForm.HSpeedDrop.ItemIndex,-1,Graph4DForm.TREdit.value,Graph4DForm.MinEdit.value,Graph4DForm.MaxEdit.value,false); Close4DTrace(l4Dtrace,true); end; procedure FFT4ROI (var l4DHdr: TMRIcroHdr); var l4DTrace: T4DTrace; lnROI,lROI,lnVol,lnFFTOut: integer; begin lnVol := l4DHdr.NIFTIhdr.dim[4]; if lnVol < 5 then exit; lnROI := numROI; if lnROI < 1 then begin Plot4DFFT(1); exit; end; Create4DTrace ( l4DTrace); lnFFTout := (lnVol div 2) -1; Init4DTrace(lnFFTout,lnROI,l4DTrace,false); for lROI := 1 to lnROI do begin ROI2FFT(l4DHdr,ROIoverlayNum(lROI),l4DTrace.Lines[lROI].EventRA); l4DTrace.Lines[lROI].elabel := ROIoverlayNameShort(lROI); end; MinMax4DTrace(l4dtrace); l4dtrace.HorzMin := 0; //range will be 0.. 1/TR*Nyquist Sec/Cycle if Graph4DForm.TREdit.value = 0 then l4dtrace.HorzWidPerBin := (0.5)/(l4dTrace.lines[1].events-1) else l4dtrace.HorzWidPerBin := ((1/Graph4DForm.TREdit.value)*0.5)/(l4dTrace.lines[1].events-1); CorePlot4DTrace(l4Dtrace,Graph4DForm.Image1,1,Graph4DForm.HSpeedDrop.ItemIndex,-1,Graph4DForm.TREdit.value,Graph4DForm.MinEdit.value,Graph4DForm.MaxEdit.value,false); Close4DTrace(l4Dtrace,true); end; {$ENDIF} procedure TGraph4DForm.Plot4DTrace(lStartSample: integer); begin g4Ddata.HorzWidPerBin := TREdit.value; CorePlot4DTrace(g4Ddata,Image1,lStartSample,HSpeedDrop.ItemIndex,-1,TREdit.value,MinEdit.value,MaxEdit.value,false); //StatusBar1.Panels[1].Text := 'Offset:'+inttostr(lStartSample); //ShowLegend(g4Ddata,Image1, 50,5); end; procedure TGraph4DForm.TextBtnClick(Sender: TObject); begin end; procedure TextToTrace (var l4DTrace: T4DTrace); var lStr: string; lCond, lnCond,lE: integer; begin lncond := 0; for lCond := 1 to kMaxCond do if l4DTrace.Lines[lCond].Events > 0 then inc(lnCond); if lncond = 0 then exit; for lCond := 1 to kMaxCond do begin if l4DTrace.Lines[lCond].Events > 0 then begin lStr := gMRIcroOverlay[kBGOverlayNum].HdrFileName+kTextSep+l4DTrace.Lines[lCond].ELabel; for lE := 1 to l4DTrace.Lines[lCond].Events do lStr := lStr + kTextSep+ realtostr(l4DTrace.Lines[lCond].EventRA^[lE],4) ; TextForm.MemoT.lines.add(lStr); end; end; end; function TGraph4DForm.ReadGraf(lFilename: string; lBatch,lTRcritical: boolean): boolean; label 666; var lnVol: integer; lReslice : boolean; begin ImgForm.CloseImagesClick(nil); Close4DTrace(g4Ddata,true); FreeImgMemory(g4DHdr); result := false; if not fileexists(lFilename) then exit; Graph4DForm.Caption := 'Viewing: '+lFilename; lReslice := gBGImg.ResliceOnLoad; gBGImg.ResliceOnLoad := false; gBGImg.Prompt4DVolume := false; //if not lBatch then begin //12/2007 ImgForm.OpenAndDisplayImg(lFilename,True); lnVol := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[4]; if (lnVol < 2) then begin showmessage('You need to open a 4D image.'); goto 666; end; if not HdrForm.OpenAndDisplayHdr(lFilename,g4DHdr) then goto 666; if not OpenImg(gBGImg,g4DHdr,false,false,false,false,true {4D!}) then goto 666; TrackBar1.Max := lnVol; if gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.PixDim[4] = 0 then begin beep; ImgForm.StatusLabel.caption := 'Assuming TR = '+floattostr(TREdit.value); end else TREdit.value := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.PixDim[4];//TR if (TREdit.value = 0) and (lTRcritical) then showmessage('Please set the TR value [in seconds]'); result := true; 666: gBGImg.ResliceOnLoad := lReslice; gBGImg.Prompt4DVolume := true; end; procedure TGraph4DForm.FormShow(Sender: TObject); begin end; (*{x$IFDEF FFTs} procedure TGraph4DForm.FormShow(Sender: TObject); var lFilename: string; begin //abba lFilename := 'C:\cygwin\home\mscae\20061220_140508\'; //ReadCond(lFilename+'puls.txt',g4Ddata,1); //ReadCond(lFilename+'resp.txt',g4Ddata,2); HdrForm.OpenHdrDlg.Filename := lFilename+'rachris.nii.gz'; ReadGraf(HdrForm.OpenHdrDlg.Filename ); ImgForm.XViewEdit. value := 43; ImgForm.YViewEdit. value := 37; ImgForm.ZViewEdit. value := 22; PSForm.BinWidthEdit.value := 0.1; PSForm.PreBinEdit.value := 5; PSForm.PostBinEdit.value := 5; lFilename := 'C:\cygwin\home\mscae\20061220_140508\ravoi.voi'; //ImgForm.OverlayOpenCore ( lFilename, kBGOverlayNum+1); RefreshBtnClick(nil); end; {x$ELSE} //no FFT procedure TGraph4DForm.FormShow(Sender: TObject); var lFilename: string; //lReslice : boolean; begin //lReslice :=gReslice; //gReslice := false; ReadCond(extractfiledir(paramstr(0))+'\L_Tap.txt',g4Ddata,1); ReadCond(extractfiledir(paramstr(0))+'\R_Tap.txt',g4Ddata,2); HdrForm.OpenHdrDlg.Filename := extractfiledir(paramstr(0))+'\filtered_func_data.nii.gz'; ReadGraf(HdrForm.OpenHdrDlg.Filename ); ImgForm.XViewEdit. value := 42; ImgForm.YViewEdit. value := 29; ImgForm.ZViewEdit. value := 28; lFilename := extractfiledir(paramstr(0))+'\Left.voi'; ImgForm.OverlayOpenCore ( lFilename, kBGOverlayNum+1); //VR( lFilename, 1); //ImgForm.OpenVOICore(lFilename); lFilename := extractfiledir(paramstr(0))+'\Right.voi'; ImgForm.OverlayOpenCore ( lFilename,kBGOverlayNum+2); //VR(lFilename,2); RefreshBtnClick(nil); //gReslice := lReslice; end; {x$ENDIF} *) procedure TGraph4DForm.FormCreate(Sender: TObject); begin {$IFNDEF FPC} gWmf := TMetafile.Create; gWmf.Enhanced := True; {$ENDIF} Create4DTrace(g4Ddata); Graph4DForm.DoubleBuffered := true; HSpeedDrop.ItemIndex := 0; InitImgMemory(g4DHdr); end; procedure TGraph4DForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin Close4DTrace(g4Ddata,true); FreeImgMemory(g4DHdr); //gWmf.Free; end; procedure TGraph4DForm.TrackBar1Change(Sender: TObject); begin Trackbar1.visible := (HSpeedDrop.ItemIndex > 0); Plot4DTrace(TrackBar1.position); end; {$DEFINE notTest4D} procedure TGraph4DForm.OpenDataClick(Sender: TObject); var lI,lCnt: integer; lStr: string; begin Close4DTrace(g4Ddata,true); FreeImgMemory(g4DHdr); {$IFDEF Test4D} if not ReadGraf('C:\tx\20091006\fsl\filtered_func_data.nii.gz',false,true) then exit; ReadCond('C:\tx\20091006\fsl\timing.txt',g4Ddata,1); //ReadCond('C:\fatigue\TD\b.txt',g4Ddata,2); PSPlotClick(nil); exit; if not ReadGraf('C:\fatigue\perisample\filtered_func_data.nii.gz',false,true) then exit; ReadCond('C:\fatigue\perisample\L_Tap.txt',g4Ddata,1); ReadCond('C:\fatigue\perisample\R_Tap.txt',g4Ddata,2); lI := 1; lStr := 'C:\fatigue\perisample\left.voi'; ImgForm.OverlayOpenCore(lStr,lI+kBGOverlayNum); PSPlotClick(nil); exit; {$ENDIF} if not OpenDialogExecute(kImgFilter,'Select 4D image',false) then exit; if not ReadGraf(HdrForm.OpenHdrDlg.Filename,false,true) then exit; ImgForm.XViewEdit.value := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[1] div 2; ImgForm.YViewEdit.value := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[2] div 2; ImgForm.ZViewEdit.value := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[3] div 2; if OpenDialogExecute(kTxtFilter,'Select 3-column event onset time files [optional]',true) then begin if HdrForm.OpenHdrDlg.Files.Count > 0 then begin lCnt := HdrForm.OpenHdrDlg.Files.Count; if lCnt > kMaxCond then begin showmessage('Can only load '+inttostr(kMaxCond)+'conditions'); lCnt := kMaxCond; end; for lI := 1 to lCnt do ReadCond(HdrForm.OpenHdrDlg.Files[lI-1],g4Ddata,lI); end;//if count > 1 end; //if opendialog if OpenDialogExecute(kImgPlusVOIFilter,'Select regions of interest',true) then begin if HdrForm.OpenHdrDlg.Files.Count > 0 then begin lCnt := HdrForm.OpenHdrDlg.Files.Count; //Apr07 if lCnt > (knMaxOverlay-2) then begin showmessage('Can only load '+inttostr(knMaxOverlay-2)+'conditions'); lCnt := knMaxOverlay; end; for lI := 1 to lCnt do begin lStr := HdrForm.OpenHdrDlg.Files[lI-1]; ImgForm.OverlayOpenCore(lStr,lI+kBGOverlayNum); end; end;//if count > 1 end; //if opendialog RefreshBtnMouseDown(nil,mbleft,[],1,1); end; procedure TGraph4DForm.FormResize(Sender: TObject); begin if not Graph4DForm.visible then exit; GraphResize(Image1); Plot4DTrace(TrackBar1.position); end; procedure TGraph4DForm.PSPlotClick(Sender: TObject); var lPSPlot: TPSPlot; {var lTRSec,lBinWidthSec: single; lnNegBins,lnPosBins: integer; lSliceTime, lSavePSVol,lTextOutput,lGraphOutput,lBaselineCorrect,lPctSignal, lRemoveRegressorVariability,lTemporalDeriv,lPlotModel: boolean; } begin if NCond ( g4Ddata) < 1 then begin RefreshBtnMouseDown(nil,mbleft,[],1,1); exit; end; lPSPlot.TRSec := TREdit.value; if not PSForm.GetPeriSettings(lPSPlot) then exit; lPSPlot.TextOutput := false; lPSPlot.GraphOutput := true; lPSPlot.batch := false; CreatePeristimulusPlot (g4DHdr,g4Ddata, lPSPlot); end; procedure TGraph4DForm.PSTextClick(Sender: TObject); var lPSPlot: TPSPlot; begin if NCond ( g4Ddata) < 1 then begin RefreshBtnMouseDown(nil,mbleft,[],1,1); TextForm.MemoT.Lines.Clear;//prepare to report results TextToTrace (g4Ddata); TextForm.show; exit; end; lPSPlot.TRSec := TREdit.value; if not PSForm.GetPeriSettings(lPSPlot) then exit; lPSPlot.TextOutput := true; lPSPlot.GraphOutput := true; lPSPlot.batch := false; CreatePeristimulusPlot (g4DHdr,g4Ddata, lPSPlot); end; procedure TGraph4DForm.Copy1Click(Sender: TObject); {$IFDEF FPC} begin if (Image1.Picture.Graphic = nil) then begin //1420z Showmessage('You need to generate an image before you can copy it to the clipboard.'); exit; end; Image1.Picture.Bitmap.SaveToClipboardFormat(2); end; {$ELSE} var MyFormat : Word; AData: THandle; APalette : HPalette; begin if gWMF.Empty then begin showmessage('Please Open a dataset first.'); exit; end; gWmf.SaveToClipboardFormat(MyFormat,AData,APalette); ClipBoard.SetAsHandle(MyFormat,AData); end; {$ENDIF} procedure TGraph4DForm.FormDestroy(Sender: TObject); begin //gWmf.Free; end; procedure TGraph4DForm.Closewindow1Click(Sender: TObject); begin Graph4DForm.Close; end; procedure TGraph4DForm.SaveasEMF1Click(Sender: TObject); begin {$IFDEF FPC} SaveImgAsPNGBMP (Image1); {$ELSE} if gWMF.Empty then begin showmessage('Please Open a dataset first.'); exit; end; ImgForm.SaveDialog1.Filter := 'Enhanced Metafile|*.emf'; ImgForm.SaveDialog1.DefaultExt := '*.emf'; if not ImgForm.SaveDialog1.Execute then exit; gWmf.SaveToFile (ChangeFileExt(ImgForm.SaveDialog1.FileName,'.emf')); {$ENDIF} end; procedure TGraph4DForm.FFTitemClick(Sender: TObject); begin {$IFDEF FFTs} FFT4ROI (g4DHdr); exit; {$ENDIF} showmessage('FFT not included with this build.'); end; procedure TGraph4DForm.RefreshBtnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if (g4DHdr.ImgBufferItems = 0) then begin showmessage('You must first load 4D data [Press the ''Open Data'' button.'); exit; end; ConvertToTrace(g4DHdr,g4Ddata,ImgForm.XViewEdit.value,ImgForm.YViewEdit.value,ImgForm.ZViewEdit.value); Plot4DTrace(TrackBar1.position); end; procedure TGraph4DForm.Extract4DroisClick(Sender: TObject); const kMin8bit = 0; kMax8bit = 255; var lROInum,lVol,lnVol,lPos,lROI,lVolSz,lVolOffset: integer; lStr: string; SumRA : array [kMin8bit..kMax8bit] of double; nRA : array [kMin8bit..kMax8bit] of longint; l16Buf : SmallIntP; l32Buf : SingleP; lOutStr: string; begin Close4DTrace(g4Ddata,true); FreeImgMemory(g4DHdr); if not OpenDialogExecute(kImgFilter,'Select 4D image',false) then exit; if not ReadGraf(HdrForm.OpenHdrDlg.Filename,false,true) then exit; ImgForm.XViewEdit.value := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[1] div 2; ImgForm.YViewEdit.value := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[2] div 2; ImgForm.ZViewEdit.value := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[3] div 2; lVolSz := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[1]*gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[2]*gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[3]; if not OpenDialogExecute(kImgPlusVOIFilter,'Select regions of interest',false) then exit; lROInum := 1+kBGOverlayNum; lStr := HdrForm.OpenHdrDlg.Filename; ImgForm.OverlayOpenCore(lStr,lROInum); if gMRIcroOverlay[lROInum].ImgBufferBPP <> 1 then begin showmessage('Overlay must be 8-bit image'); exit; end; if (gMRIcroOverlay[lROInum].ImgBufferItems <> lVolSz) or (lVOlSz < 1) then begin showmessage('Overlay must have identical dimensions as 4D image'); exit; end; lnVol := gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.dim[4]; if lnVol < 2 then begin showmessage('Requires 4D data'); exit; end; if (g4DHdr.ImgBufferItems <> ({lnVol*}lVolSz)) then begin showmessage('4D image not loaded correctly '+inttostr(g4DHdr.ImgBufferItems)+' <> '+inttostr(lVolSz)); exit; end; TextForm.MemoT.Lines.Clear;//prepare to report results //count frequency of each column... for lPos := kMin8Bit to kMax8bit do nRA[lPos] := 0; for lPos := 1 to lVolSz do begin lROI := gMRIcroOverlay[lROInum].ImgBuffer^[lPos]; //ROI must be 8-bit! nRA[lROI] := nRA[lROI] + 1; end; //report detected ROI volumes lOutStr := 'vol'; for lROI := kMin8Bit to kMax8bit do if nRA[lROI] > 0 then lOutStr := lOutStr+kTextSep+inttostr(nRA[lROI]); TextForm.MemoT.lines.add(lOutStr); //report detected ROIs [column labels] lOutStr := 'ROI'; for lROI := kMin8Bit to kMax8bit do if nRA[lROI] > 0 then lOutStr := lOutStr+kTextSep+inttostr(lROI); TextForm.MemoT.lines.add(lOutStr); //compute mean intensity for each ROI at each timepoint l32Buf := SingleP(g4DHdr.ImgBuffer); l16Buf := SmallIntP(g4DHdr.ImgBuffer); for lVol := 1 to lnVol do begin lVolOffset := (lVol-1)*lVolSz; for lPos := kMin8Bit to kMax8bit do //initialize all ROIs for this volume SumRA[lPos] := 0; if (gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP = 4) then begin for lPos := 1 to lVolSz do begin lROI := gMRIcroOverlay[lROInum].ImgBuffer^[lPos]; //ROI must be 8-bit! SumRA[lROI] := SumRA[lROI] + l32Buf^[lPos+lVolOffset]; end; end else if (gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP = 2) then begin for lPos := 1 to lVolSz do begin lROI := g4DHdr.ImgBuffer^[lPos]; //ROI must be 8-bit! SumRA[lROI] := SumRA[lROI] + l16Buf^[lPos+lVolOffset]; end; end else if gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP = 1 then begin for lPos := 1 to lVolSz do begin lROI := gMRIcroOverlay[lROInum].ImgBuffer^[lPos]; //ROI must be 8-bit! SumRA[lROI] := SumRA[lROI] + gMRIcroOverlay[kBGOverlayNum].ImgBuffer^[lPos+lVolOffset]; end; end else begin showmessage('Serious error: unsupported datatype!'); exit; end; lOutStr := inttostr(lvol); for lROI := kMin8Bit to kMax8bit do if nRA[lROI] > 0 then lOutStr := lOutStr+kTextSep+realtostr(SumRA[lROI]/nRA[lROI],4); TextForm.MemoT.lines.add(lOutStr); end; //for each volume TextForm.show; RefreshBtnMouseDown(nil,mbleft,[],1,1); end; procedure TGraph4DForm.Batchdata1Click(Sender: TObject); label 111; var lStr: string; l4D,lVectors,lVOI: TStringList; lPSPlot: TPSPlot; lImg,lI: integer; (*lTRSec,lBinWidthSec: single; lI,lImg,lnNegBins,lnPosBins: integer; lSliceTime,lSavePSVol,lTextOutput,lGraphOutput,lBaselineCorrect,lPctSignal, lRemoveRegressorVariability,lTemporalDeriv,lPlotModel: boolean; *) begin ImgForm.CloseImagesClick(nil); Close4DTrace(g4Ddata,true); FreeImgMemory(g4DHdr); if not OpenDialogExecute(kImgFilter,'Select 4D images',true) then exit; l4D := TStringList.Create; lVectors := TStringList.Create;//empty lVOI := TStringList.Create; l4D.AddStrings(HdrForm.OpenHdrDlg.Files); if OpenDialogExecute(kTxtFilter,'Select 3-column event onset time files',true) then begin if HdrForm.OpenHdrDlg.Files.Count > kMaxCond then begin showmessage('Can only load '+inttostr(kMaxCond)+'conditions'); goto 111; end; lVectors.AddStrings(HdrForm.OpenHdrDlg.Files); end; if not OpenDialogExecute(kImgPlusVOIFilter,'Select region[s] of interest',true) then goto 111; if HdrForm.OpenHdrDlg.Files.Count > (knMaxOverlay-2) then begin showmessage('Can only load '+inttostr(knMaxOverlay-2)+'conditions'); goto 111; end; lVOI.AddStrings(HdrForm.OpenHdrDlg.Files); if not ReadGraf(l4D[0],false, (lVectors.count > 0) ) then goto 111; //read first dataset to set TR! //get plot settings.... lPSPlot.TRSec := TREdit.value; if lVectors.count > 0 then if not PSForm.GetPeriSettings(lPSPlot) then goto 111; lPSPlot.TextOutput := true; lPSPlot.GraphOutput := false; lPSPlot.Batch := true; TextForm.MemoT.Lines.Clear;//prepare to report results for lImg := 1 to l4D.Count do begin //showmessage(l4D[lImg-1]); if lImg > 1 then begin//we have already read 1st img Refresh; Close4DTrace(g4Ddata,true); ImgForm.CloseImagesClick(nil); FreeImgMemory(g4DHdr); if not ReadGraf(l4D[lImg-1],true,(lVectors.count > 0)) then goto 111; //read first dataset to set TR! end; //all except 1st image if lVectors.count > 0 then begin for lI := 1 to lVectors.count do ReadCond(lVectors[lI-1],g4Ddata,lI); end;//vectors > 0 if lVOI.count > 0 then begin for lI := 1 to lVOI.count do begin lStr := lVOI[lI-1]; ImgForm.OverlayOpenCore(lStr,lI+kBGOverlayNum); end;//for each VOI end; //VOI > 0 if lVectors.Count > 0 then CreatePeristimulusPlot (g4DHdr,g4Ddata, lPSPlot) else begin // RefreshBtnMouseDown(nil,mbleft,[],1,1); ConvertToTrace(g4DHdr,g4Ddata,ImgForm.XViewEdit.value,ImgForm.YViewEdit.value,ImgForm.ZViewEdit.value); TextToTrace (g4Ddata); RegressTrace(g4Ddata); end; end; TextForm.show; 111: lVOI.Free; lVectors.Free; l4D.Free; end; procedure TGraph4DForm.RefreshBtnClick(Sender: TObject); begin RefreshBtnMouseDown(nil,mbleft,[],1,1); end; function ResliceFSLVOIs(var lFeatDirs,lVOI: TStringList): boolean; //uses reslice var lDir,lV: integer; lMatName,lFuncName,lReslicedVOIName:string; begin result := false; if lFeatDirs.count < 1 then exit; if lVOI.count < 1 then exit; for lDir := 1 to (lFeatDirs.Count) do begin lMatName := FSLMatName (lFeatDirs[lDir-1]); lFuncName := FSLFuncName (lFeatDirs[lDir-1]); for lV := 1 to lVOI.Count do begin lReslicedVOIName := FSLReslicedVOIName (lFeatDirs[lDir-1], lVOI[lV-1]); if not ResliceImg (lFuncName,lVOI[lV-1],lMatName,lReslicedVOIName) then begin Showmessage('graphx reslice FSL failed.'); exit; end; end;//for each VOI end;//for each Dir result := true; end; {$DEFINE notTEST} function FindFEATFolders (var lFeatDirs:TStringList): boolean; var lDir,lFeatPath: string; lSearchRec: TSearchRec; begin result := false; {$IFDEF TEST} lDir := 'C:\cygwin\home\express'; {$ELSE} //lDir := 'C:\cygwin\home\express'; //lDir := SelectDirectory('Choose root folder that contains .feat folders', BIF_RETURNONLYFSDIRS); LDir := UserDataFolder; lDir := GetDirPrompt (lDir); {$ENDIF} if lDir = '' then exit; lFeatDirs := TStringList.Create; if FindFirst(lDir+pathdelim+'*'+'.feat', faAnyFile, lSearchRec) = 0 then begin repeat if (faDirectory and lSearchRec.attr) = faDirectory then begin lFeatPath := lDir+pathdelim+lSearchRec.Name; if Fileexists(FSLMatName(lFeatPath)) and Fileexists(FSLFuncName(lFeatPath)) then lFeatDirs.Add(lFeatPath) else Showmessage('Can not find '+FSLMatName(lFeatPath) +' or '+FSLFuncName(lFeatPath) ); end; until (FindNext(lSearchRec) <> 0); end; FindClose(lSearchRec); if lFeatDirs.Count < 1 then begin Showmessage('Unable to find any feat dirs in path '+lDir); lFeatDirs.free; exit; end; result := true; end; procedure TGraph4DForm.FSLbatch1Click(Sender: TObject); label 111; var lStr: string; lFeatDirs,lVectors,lVOI: TStringList; //lTRSec,lBinWidthSec: single; lI,lImg: integer; lUseFSLEVs: Boolean; lPSPlot: TPSPlot; {lSliceTime,lSavePSVol,lTextOutput,lBaselineCorrect,lPctSignal, lRemoveRegressorVariability,lTemporalDeriv,lUseFSLEVs,lPlotModel: boolean; } begin ImgForm.CloseImagesClick(nil); Close4DTrace(g4Ddata,true); FreeImgMemory(g4DHdr); if not FindFEATFolders (lFeatDirs) then exit; lVectors := TStringList.Create;//empty lVOI := TStringList.Create; {$IFDEF TEST} lUseFSLEVs := false; lFeatDirs.AddStrings(lFeatDirs); lFeatDirs.AddStrings(lFeatDirs); lFeatDirs.AddStrings(lFeatDirs); lFeatDirs.AddStrings(lFeatDirs); lFeatDirs.AddStrings(lFeatDirs); lVectors.Add('C:\cygwin\home\express\20070420_132327fMRIcontin30x30x36s004a001.feat\custom_timing_files\ev1.txt'); lVectors.Add('C:\cygwin\home\express\20070420_132327fMRIcontin30x30x36s004a001.feat\custom_timing_files\ev2.txt'); lVectors.Add('C:\cygwin\home\express\20070420_132327fMRIcontin30x30x36s004a001.feat\custom_timing_files\ev3.txt'); lVOI.Add('C:\fatigue\v1.nii.gz'); lVOI.Add('C:\fatigue\v2.nii.gz'); {$ELSE} FSLEVNames (lFeatDirs[0], lVectors); lUseFSLEVs := false; if lVectors.count > 0 then lUseFSLEVs := OKMsg('Use event vectors from the .FEAT'+pathdelim+'custom_timing_files folder?'); //shows dialog with OK/Cancel returns true if user presses OK if not lUseFSLEVs then begin lVectors.clear; if OpenDialogExecute(kTxtFilter,'Select 3-column event onset time files',true) then begin if HdrForm.OpenHdrDlg.Files.Count > kMaxCond then begin showmessage('Can only load '+inttostr(kMaxCond)+'conditions'); goto 111; end; lVectors.AddStrings(HdrForm.OpenHdrDlg.Files); end; end; //manually select EVs if not OpenDialogExecute(kImgPlusVOIFilter,'Select volume[s] of interest [2mm MNI space]',true) then goto 111; if HdrForm.OpenHdrDlg.Files.Count > (knMaxOverlay-2) then begin showmessage('Can only load '+inttostr(knMaxOverlay-2)+'conditions'); goto 111; end; lVOI.AddStrings(HdrForm.OpenHdrDlg.Files); {$ENDIF} if not ResliceFSLVOIs(lFeatDirs,lVOI) then begin showmessage('Unable to reslice VOIs!'); goto 111; end; lPSPlot.TextOutput := true; lPSPlot.GraphOutput := false; TextForm.MemoT.Lines.Clear;//prepare to report results if not ReadGraf(FSLFuncName (lFeatDirs[0]),false, (lVectors.count > 0) ) then goto 111; //read first dataset to set TR! //la1 := (FreeRAM); //get plot settings.... lPSPlot.TRSec := TREdit.value; if lVectors.count > 0 then if not PSForm.GetPeriSettings(lPSPlot) then goto 111; for lImg := 1 to lFeatDirs.Count do begin if lImg > 1 then begin//we have already read 1st img Refresh; Application.processmessages; Close4DTrace(g4Ddata,true); ImgForm.CloseImagesClick(nil); FreeImgMemory(g4DHdr); //Textform.memo1.lines.add(inttostr(FreeRAM));//rascal if not ReadGraf(FSLFuncName (lFeatDirs[lImg-1]),true,(lVectors.count > 0)) then goto 111; //read first dataset to set TR! if lUseFSLEVs then FSLEVNames (lFeatDirs[lImg-1], lVectors) end; //all except 1st image if lVectors.count > 0 then begin for lI := 1 to lVectors.count do ReadCond(lVectors[lI-1],g4Ddata,lI); end;//vectors > 0 if lVOI.count > 0 then begin for lI := 1 to lVOI.count do begin lStr := FSLReslicedVOIName (lFeatDirs[lImg-1], lVOI[lI-1]); ImgForm.OverlayOpenCore(lStr,lI+kBGOverlayNum); end;//for each VOI end; //VOI > 0 if lVectors.Count > 0 then begin if lImg = lFeatDirs.Count then lPSPlot.GraphOutput := true; CreatePeristimulusPlot (g4DHdr,g4Ddata, lPSPlot) end else begin ConvertToTrace(g4DHdr,g4Ddata,ImgForm.XViewEdit.value,ImgForm.YViewEdit.value,ImgForm.ZViewEdit.value); TextToTrace (g4Ddata); RegressTrace(g4Ddata); end; end; TextForm.show; 111: lVOI.Free; lVectors.Free; lFeatDirs.free; end; {$DEFINE TEST} procedure TGraph4DForm.FSLtest1Click(Sender: TObject); label 111; var lStr: string; lFeatDirs,lVectors,lVOI: TStringList; lI,lImg: integer; lUseFSLEVs: Boolean; lPSPlot: TPSPlot; {lSliceTime,lSavePSVol,lTextOutput,lBaselineCorrect,lPctSignal, lRemoveRegressorVariability,lTemporalDeriv,lUseFSLEVs,lPlotModel: boolean; } begin ImgForm.CloseImagesClick(nil); Close4DTrace(g4Ddata,true); FreeImgMemory(g4DHdr); //x if not FindFEATFolders (lFeatDirs) then //x exit; lVectors := TStringList.Create;//empty lVOI := TStringList.Create; {$IFDEF TEST} lFeatDirs := TStringList.Create; for lI := 1 to 100 do lFeatDirs.Add('C:\mri\fds.feat'); {lUseFSLEVs := true; FSLEVNames (lFeatDirs[0], lVectors); } lUseFSLEVs := false; lVectors.Add('C:\mri\fds.feat\custom_timing_files\ev1.txt'); lVectors.Add('C:\mri\fds.feat\custom_timing_files\ev2.txt'); //lVectors.Add('C:\cygwin\home\express\20070420_132327fMRIcontin30x30x36s004a001.feat\custom_timing_files\ev3.txt'); lVOI.Add('C:\mri\left.voi'); lVOI.Add('C:\mri\right.voi'); lVOI.Add('C:\mri\v1.voi'); {$ELSE} FSLEVNames (lFeatDirs[0], lVectors); lUseFSLEVs := false; if lVectors.count > 0 then lUseFSLEVs := OKMsg('Use event vectors from the .FEAT'+pathdelim+'custom_timing_files folder?'); //shows dialog with OK/Cancel returns true if user presses OK if not lUseFSLEVs then begin lVectors.clear; if OpenDialogExecute(kTxtFilter,'Select 3-column event onset time files',true) then begin if HdrForm.OpenHdrDlg.Files.Count > kMaxCond then begin showmessage('Can only load '+inttostr(kMaxCond)+'conditions'); goto 111; end; lVectors.AddStrings(HdrForm.OpenHdrDlg.Files); end; end; //manually select EVs if not OpenDialogExecute(kImgPlusVOIFilter,'Select volume[s] of interest [2mm MNI space]',true) then goto 111; if HdrForm.OpenHdrDlg.Files.Count > (knMaxOverlay-2) then begin showmessage('Can only load '+inttostr(knMaxOverlay-2)+'conditions'); goto 111; end; lVOI.AddStrings(HdrForm.OpenHdrDlg.Files); {$ENDIF} if not ResliceFSLVOIs(lFeatDirs,lVOI) then begin showmessage('Unable to reslice VOIs!'); goto 111; end; lPSPlot.TextOutput := true; lPSPlot.GraphOutput := false; TextForm.MemoT.Lines.Clear;//prepare to report results if not ReadGraf(FSLFuncName (lFeatDirs[0]),false, (lVectors.count > 0) ) then goto 111; //read first dataset to set TR! //la1 := (FreeRAM); //get plot settings.... lPSPlot.TRSec := TREdit.value; if lVectors.count > 0 then if not PSForm.GetPeriSettings(lPSPlot) then goto 111; for lImg := 1 to lFeatDirs.Count do begin if lImg > 1 then begin//we have already read 1st img Refresh; Application.processmessages; Close4DTrace(g4Ddata,true); ImgForm.CloseImagesClick(nil); FreeImgMemory(g4DHdr); //Textform.memo1.lines.add(inttostr(FreeRAM));//rascal if not ReadGraf(FSLFuncName (lFeatDirs[lImg-1]),true,(lVectors.count > 0)) then goto 111; //read first dataset to set TR! if lUseFSLEVs then FSLEVNames (lFeatDirs[lImg-1], lVectors) end; //all except 1st image if lVectors.count > 0 then begin for lI := 1 to lVectors.count do ReadCond(lVectors[lI-1],g4Ddata,lI); end;//vectors > 0 if lVOI.count > 0 then begin for lI := 1 to lVOI.count do begin lStr := FSLReslicedVOIName (lFeatDirs[lImg-1], lVOI[lI-1]); ImgForm.OverlayOpenCore(lStr,lI+kBGOverlayNum); end;//for each VOI end; //VOI > 0 if lVectors.Count > 0 then begin if lImg = lFeatDirs.Count then lPSPlot.GraphOutput := true; CreatePeristimulusPlot (g4DHdr,g4Ddata, lPSPlot) end else begin ConvertToTrace(g4DHdr,g4Ddata,ImgForm.XViewEdit.value,ImgForm.YViewEdit.value,ImgForm.ZViewEdit.value); TextToTrace (g4Ddata); RegressTrace(g4Ddata); end; end; TextForm.show; 111: lVOI.Free; lVectors.Free; lFeatDirs.free; showmessage('done'); end; //test initialization {$IFDEF FPC} {$I graphx.lrs} {$ENDIF} end. �����������������mricron-0.20140804.1~dfsg.1.orig/exampleclip.bat����������������������������������������������������0000755�0001750�0001750�00000000134�10416577744�017213� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������start mricron .\templates\ch2bet.nii.gz -s 3 -c pink -l 40 -h 120 -r .\example\clipnearr.ini������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/niftiview.ico������������������������������������������������������0000755�0001750�0001750�00000017316�10332560504�016711� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ��� ���6������ � ������� �h��f��(��� ���@���� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ������������������������������������������������������������������������������������������$"�|z����� �����������������������������������������������������������������������������������0*�ja�����+ ���������������������������������������������������������������������������� /)� >� ������������������������������������������������������������������������� �@� ��������������������������42�42�43�������m������������ ���������������DBDBDC�Tf�����`j�����/}�� N����������������DL�DL�DNA=#k#(��G(���������  ��������#�� 7^q{��|�wmeU<��������a� � �}�r�I���a� ��*Z(���$�o> ����/�~�7YeW@���M�������������d�L�  ��{���������))��� ,.+-!&(,,�"" � $ O�� " "�vx�����##� �..���������uw�������� ��gy� [�������Z\���������������� �����pr��������������������������������+��;� g���������������������������������������������� �c� � '�� ���������������������������������������������������''!�-'�5k<4/5 55�45������� ����������������������������������������������������������&&�!,'���n;�.� ������������������������������������������������������������������������������������ �,5# �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?����(������0���� �����` ������������������������������������������������������������������� ������������������������������������������������������������������������������ ������������������������������������������������������$"��������� KC����������������������������������������������$&�����  � %  ��������������42�42�64*-��''�*,�V ������ �������M"��0�1�3�)/�Yb�BG�U����U[�Y Z����������3�4 �6$"a++`%(����'p l � N) 0 0 ,������7P�� C �0z�\�� �g>�N�l �� �v�GY����� `�^f����O� {����|������������B���D��� /1x.0�02�� Y��x � ���  �@ ��   � ���������������O���"$M��JL�JL��������������� � �� K �!#����������������������������������� ER P"OPP�J ������!#���������������������������������������� �Q!�#� ���� ����������������������������������������������������||������ _1  ���������������������������������������������������������������������������������������������������������������������������������������?�������������������������������������O����(������ ���� �����@���������������������������������������� �� ������������������������$&�48���� �  � � �����!7<���� YA���� ����������-�*3�'.�: �� ,*b* �������%$ 3 A '���I� MOu���O0�%��"�A�n L��� 5#�N�����^�v����� �  �� +-<>� L�#S����������� P�d� 2 ������������!!��� (Pk*i�jP �56�������������� �X �1��� ��13������������������������ T D � �(*��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/periutils.pas������������������������������������������������������0000755�0001750�0001750�00000024334�11425734036�016743� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit periutils; interface {$IFDEF FPC} {$H+} {$ENDIF} uses metagraph, define_types, sysutils,nifti_hdr, classes; function FSLMatName (lFeatDir: string): string; function FSLFuncName (lFeatDir: string): string;//Given feat folder returns name of filtered data function FSLReslicedVOIName (lFeatDir, lMNIVOIName: string): string; procedure RegressTrace (var l4DTrace: T4DTrace); function ConvertToTrace (var l4DHdr: TMRIcroHdr;var l4DTrace: T4DTrace; lX,lY,lZ: integer): boolean; function ReadCond (l3ColTextFileName: string; var l4DTrace: T4DTrace; lCond: integer): boolean; procedure FSLEVNames (lFeatDir: string; var lEVlist: TStringList); implementation uses nifti_img_view, text,dialogs,periplot; function ReadCond (l3ColTextFileName: string; var l4DTrace: T4DTrace; lCond: integer): boolean; var lOnsetText: TextFile; lnEvents: integer; lFloat,lFloat2,lFloat3: single; begin result := false; if (lCond < 1) or (lCond > kMaxCond) then exit; CloseCond(l4DTrace,lCond); Filemode := 0; assignfile(lOnsetText,l3ColTextFileName); {I-} reset(lOnsetText); {$I+} if ioresult <> 0 then begin Showmessage('Unable to read file [may be in use by another program '+ l3ColTextFileName); exit; end; lnEvents := 0; while not EOF(lOnsetText) do begin {$I-} read(lOnsetText,lFloat,lFloat2,lFloat3); //read triplets instead of readln: this should load UNIX files {$I+} if (ioresult = 0) and (lFloat3 > 0) then inc(lnEvents); end; if lnEvents < 1 then begin closefile(lOnsetText); showmessage('No events detected. Is this really a FSL-style 3 Column format file? '+l3ColTextFileName); exit; end; InitCond (l4DTrace, lCond, lnEvents); reset(lOnsetText); lnEvents := 0; while not EOF(lOnsetText) do begin lFloat := 0; {$I-} read(lOnsetText,lFloat,lFloat2,lFloat3); //read triplets instead of readln: this should load UNIX files {$I+} if (ioresult = 0) and (lFloat3 > 0) then begin inc(lnEvents); l4DTrace.Conditions[lCond].EventRA^[lnEvents] := lFloat; l4DTrace.Conditions[lCond].DurRA^[lnEvents] := lFloat2; //l4DTrace.DurRA[lCond]^[lnEvents] := lFloat2; end; end; closefile(lOnsetText); l4DTrace.Conditions[lCond].ELabel := parsefilename(extractfilename(l3ColTextFileName)); result := true; end; function ConvertToTrace (var l4DHdr: TMRIcroHdr;var l4DTrace: T4DTrace; lX,lY,lZ: integer): boolean; var lVol,lVolSz,lPos,lSamples,lLine,lnLines,lROI: integer; l16Buf : SmallIntP; l32Buf : SingleP; begin result := false; lSamples := l4DHdr.NIFTIhdr.dim[4]; lVolSz := l4DHdr.NIFTIhdr.dim[1]*l4DHdr.NIFTIhdr.dim[2]*l4DHdr.NIFTIhdr.dim[3]; if lSamples < 2 then exit; lnLines := 0; for lVol := (kBGOverlayNum+1) to knMaxOverlay do if gMRIcroOverlay[lVol].ScrnBufferItems > 0 then //for each ROI inc(lnLines); if lnLines = 0 then begin //no ROIs lLine := 1; lPos := lX + ((lY-1)*gBGImg.ScrnDim[1])+((lZ-1)*gBGImg.ScrnDim[1]*gBGImg.ScrnDim[2]); if (lPos > l4DHdr.ImgBufferItems) or (lPos < 1) then exit; Init4DTrace(lSamples, 1,l4DTrace,false); l4DTrace.Lines[1].ELabel := inttostr(lX)+'x'+inttostr(lY)+'x'+inttostr(lZ); if (l4DHdr.ImgBufferBPP = 4) then begin l32Buf := SingleP(l4DHdr.ImgBuffer ); for lVol := 1 to lSamples do begin l4DTrace.Lines[lLine].EventRA[lVol] := l32Buf[lPos]; lPos := lPos + lVolSz; end; end else if (l4DHdr.ImgBufferBPP = 2) then begin l16Buf := SmallIntP(l4DHdr.ImgBuffer ); for lVol := 1 to lSamples do begin l4DTrace.Lines[lLine].EventRA^[lVol] := l16Buf^[lPos]; lPos := lPos + lVolSz; end; end else if l4DHdr.ImgBufferBPP = 1 then begin for lVol := 1 to lSamples do begin l4DTrace.Lines[lLine].EventRA^[lVol] := l4DHdr.ImgBuffer^[lPos]; lPos := lPos + lVolSz; end; end else showmessage('Serious error: unknown data size!'); end else begin //>0 ROIS Init4DTrace(lSamples, lnLines,l4DTrace,false); for lLine := 1 to lnLines do begin lROI := ROIoverlayNum(lLine); l4DTrace.Lines[lLine].ELabel := ParseFileName(extractfilename(gMRIcroOverlay[lROI].HdrFileName)); for lVol := 1 to lSamples do l4DTrace.Lines[lLine].EventRA^[lVol] := ROImean(l4DHdr,lROI,lVol{,lVolSz}); end; end; MinMax4DTrace(l4DTrace); result := true; end; function ComputeRegress (ldataRA: singlep; lndata: integer): string; const //kMax = 1000; kCR = chr (13); Var gx : Array[1..4] of extended; gy : Array[1..4] of extended; Exy : Array[1..4] of extended; Ex : Array[1..4] of extended; Ey : Array[1..4] of extended; Ex2 : Array[1..4] of extended; Ey2 : Array[1..4] of extended; a : Array[1..4] of extended; b : Array[1..4] of extended; r : Array[1..4] of extended; chtX: Array[1..4] of extended; chtY: Array[1..4] of extended; no : Integer; gInter, gSlope,gRSqr : extended; function calcit: string; Var q : Integer; Begin For q := 1 To 4 Do Begin b[q] := (no * Exy[q] - Ex[q] * Ey[q]) / (no * Ex2[q] - (Ex[q]*Ex[q]) ); a[q] := (Ey[q] - b[q] * Ex[q]) / no; r[q] := (no * Exy[q] - Ex[q] * Ey[q]) / (Sqrt((no * Ex2[q] - (Ex[q]*Ex[q]) ) * (no * Ey2[q] - (Ey[q]*Ey[q]) ) )); End; // for a[2] := Exp(a[2]); a[4] := Exp(a[4]); result := (' Linear Y=' + RealToStr(a[1],8) + ' +' + RealToStr(b[1],8) + ' * X'+' R=' + RealToStr(r[1],8)+' R^2=' + RealToStr(r[1]*r[1],8)); gInter := a[1]; gSlope := b[1]; gRSqr := r[1]; result := result + (', Exp Y=' + RealToStr(a[2],8) + ' * e ^' + RealToStr(b[2],8) + ' * X'+' R=' + RealToStr(r[2],8)+' R^2=' + RealToStr(r[2]*r[2],8)); result := result + (', Log Y=' + RealToStr(a[3],8) + ' +' + RealToStr(b[3],8) + ' * LOG(X)'+' R=' + RealToStr(r[3],8)+' R^2=' + RealToStr(r[3]*r[3],8)); result := result +(', Power Y=' + RealToStr(a[4],8) + ' * X ^' + RealToStr(b[4],8)+' R=' + RealToStr(r[4],8)+' R^2=' + RealToStr(r[4]*r[4],8)); End; // nested calcit() Procedure inpcalc (lX, lY: extended); Var q : Integer; Begin gx[1] := lX; gy[1] := lY; //inc(gnVal); inc(no); gx[2] := gx[1]; gy[2] := Ln(gy[1]); // exp gx[3] := Ln(gx[1]); gy[3] := gy[1]; // log gx[4] := Ln(gx[1]); gy[4] := Ln(gy[1]); // power For q := 1 To 4 Do Begin Exy[q] := Exy[q] + gx[q] * gy[q]; Ex[q] := Ex[q] + gx[q]; Ey[q] := Ey[q] + gy[q]; Ex2[q] := Ex2[q] + (gx[q]*gx[q]); Ey2[q] := Ey2[q] + (gy[q]*gy[q]); End; // For End; //nested inpcalc procedure initReg; var lC: byte; begin for lC := 1 to 4 do begin gx [lC]:= 0; gy [lC]:= 0; Exy [lC]:= 0; Ex[lC]:= 0; Ey[lC]:= 0; Ex2[lC]:= 0; Ey2[lC]:= 0; a[lC]:= 0; b[lC]:= 0; r[lC]:= 0; chtX[lC]:= 0; chtY[lC]:= 0; end; //for lC end;//nested inp calc const kDeleteVols = 3; var i: integer; begin //computeRegress result := ''; no := 0; if lndata < (kDeleteVols+5) then exit; //gnVal := 0; initReg; for i := kDeleteVols to lndata do begin //fx(i,ldatara[i]); inpcalc (i, ldataRA^[i]); end; result := calcit; end; //func ComputeRegress procedure RegressTrace (var l4DTrace: T4DTrace); var lStr: string; lE,lCond, lnCond,lnE: integer; lMean : double; ldataRA: singlep; begin lncond := 0; for lCond := 1 to kMaxCond do if l4DTrace.Lines[lCond].Events > 0 then inc(lnCond); if lncond = 0 then exit; for lCond := 1 to kMaxCond do begin if l4DTrace.Lines[lCond].Events > 0 then begin lnE := l4DTrace.Lines[lCond].Events; getmem(ldataRA,lnE * sizeof(single)); lStr := gMRIcroOverlay[kBGOverlayNum].HdrFileName+','+l4DTrace.Lines[lCond].ELabel; //load data lMean := 0; for lE := 1 to lnE do begin ldataRA[lE] := l4DTrace.Lines[lCond].EventRA[lE]; lMean := ldataRA^[lE] + lMean; //sum end; lMean := lMean / lnE; //fx(lMean); //normalize data... for lE := 1 to lnE do ldataRA^[lE] := ldataRA^[lE]/lMean; //compute functions lStr := lStr +kTextSep+ (ComputeRegress (ldataRA, lnE) ); TextForm.MemoT.lines.add(lStr); //TextForm.Memo1.lines.add(lStr); freemem(ldataRA); end; end; //TextForm.show; end; //NEXT SECTION - FSL UTILITIES procedure FSLEVNames (lFeatDir: string; var lEVlist: TStringList); //Given feat folder returns name of matrix to reorient MNI image to functional data var lEVdir : string; lSearchRec: TSearchRec; begin lEVList.clear; lEVdir := lFEATDir+pathdelim+'custom_timing_files'; //showmessage(lEVdir); if not DirExists(lEVdir) then exit; //showmessage(lEVdir); if FindFirst(lEVdir+pathdelim+'*'+'.txt', faAnyFile, lSearchRec) = 0 then begin repeat lEVlist.Add(lEVdir+pathdelim+lSearchRec.Name) until (FindNext(lSearchRec) <> 0); end; FindClose(lSearchRec); //fx(lEVlist.count); //result := lFeatDir+PathDelim+'reg'+PathDelim+'example_func2standard.mat'; end; //MatName function FSLMatName (lFeatDir: string): string; //Given feat folder returns name of matrix to reorient MNI image to functional data begin result := lFeatDir+PathDelim+'reg'+PathDelim+'example_func2standard.mat'; end; //MatName function FSLFuncName (lFeatDir: string): string;//Given feat folder returns name of filtered data begin result := lFeatDir+PathDelim+'filtered_func_data.nii.gz'; end; //FuncName function FSLReslicedVOIName (lFeatDir, lMNIVOIName: string): string; //Given FSL .feat folder name and source MNI volume name retuns resliced VOI name begin result := lFeatDir+PathDelim+extractfilename(lMNIVOIName); (*result := extractfilename(lMNIVOIName); result := lFeatDir+PathDelim+ChangeFileExtX(result,'.nii.gz'); //; *) end; //ReslicedVOIName end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/bet.lrs������������������������������������������������������������0000755�0001750�0001750�00000003254�11540266274�015512� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TBETForm','FORMDATA',[ 'TPF0'#8'TBETForm'#7'BETForm'#4'Left'#3#229#1#6'Height'#3'9'#1#3'Top'#3#27#2#5 +'Width'#3'!'#2#13'ActiveControl'#7#6'Panel1'#7'Caption'#6#16'Brain extractio' +'n'#12'ClientHeight'#3'9'#1#11'ClientWidth'#3'!'#2#21'Constraints.MaxHeight' +#3'9'#1#20'Constraints.MaxWidth'#3'!'#2#21'Constraints.MinHeight'#3'9'#1#20 +'Constraints.MinWidth'#3'!'#2#8'Position'#7#14'poScreenCenter'#10'LCLVersion' +#6#8'0.9.28.2'#0#5'TMemo'#5'Memo1'#4'Left'#2#0#6'Height'#3#25#1#3'Top'#2' '#5 +'Width'#3'!'#2#5'Align'#7#8'alClient'#8'TabOrder'#2#0#0#0#6'TPanel'#6'Panel1' +#4'Left'#2#0#6'Height'#2' '#3'Top'#2#0#5'Width'#3'!'#2#5'Align'#7#5'alTop'#10 +'BevelOuter'#7#6'bvNone'#12'ClientHeight'#2' '#11'ClientWidth'#3'!'#2#8'TabO' +'rder'#2#1#0#12'TSpeedButton'#5'GoBtn'#4'Left'#2#8#6'Height'#2#25#3'Top'#2#2 +#5'Width'#2'X'#7'Caption'#6#2'Go'#5'Color'#7#9'clBtnFace'#9'NumGlyphs'#2#0#7 +'OnClick'#7#10'GoBtnClick'#0#0#12'TSpeedButton'#8'AboutBtn'#4'Left'#2'd'#6'H' +'eight'#2#25#3'Top'#2#2#5'Width'#2'X'#7'Caption'#6#5'About'#5'Color'#7#9'clB' +'tnFace'#9'NumGlyphs'#2#0#7'OnClick'#7#17'SpeedButton2Click'#0#0#12'TSpeedBu' +'tton'#7'CropBtn'#4'Left'#3#192#0#6'Height'#2#25#3'Top'#2#2#5'Width'#2'X'#7 +'Caption'#6#10'Crop Edges'#5'Color'#7#9'clBtnFace'#9'NumGlyphs'#2#0#7'OnClic' +'k'#7#12'CropBtnClick'#0#0#14'TFloatSpinEdit'#14'SmoothnessEdit'#4'Left'#3'4' +#1#6'Height'#2#27#3'Top'#2#5#5'Width'#2']'#9'Increment'#5#0#0#0#0#0#0#0#128 +#255'?'#8'MaxValue'#5#0#0#0#0#0#0#0#128#255'?'#8'MinValue'#5#0#0#0#0#0#0#0#0 +#0#0#8'TabOrder'#2#0#5'Value'#5#0#0#0#0#0#0#0#128#254'?'#0#0#0#0 ]); ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/about.lfm����������������������������������������������������������0000755�0001750�0001750�00000002674�12151703722�016026� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object AboutForm: TAboutForm Left = 683 Height = 127 Top = 153 Width = 327 ActiveControl = Panel1 BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'About...' ClientHeight = 127 ClientWidth = 327 Constraints.MaxHeight = 127 Constraints.MaxWidth = 327 Constraints.MinHeight = 127 Constraints.MinWidth = 327 Font.Name = 'MS Sans Serif' OnCreate = FormCreate Position = poScreenCenter LCLVersion = '1.0.2.0' object Panel1: TPanel Left = 0 Height = 48 Top = 0 Width = 327 Align = alTop Alignment = taLeftJustify BevelOuter = bvNone Caption = ' MRIcron' Font.Color = clBlack Font.Height = -19 Font.Name = 'helvetica [adobe]' Font.Style = [fsBold] ParentColor = False ParentFont = False TabOrder = 0 OnClick = Panel1Click OnDragDrop = Panel1DragDrop end object Panel2: TPanel Left = 8 Height = 67 Top = 47 Width = 307 ClientHeight = 67 ClientWidth = 307 TabOrder = 1 object HomepageLabel: TLabel Left = 0 Height = 20 Top = 10 Width = 305 Alignment = taCenter AutoSize = False Caption = 'version' ParentColor = False OnClick = HomePageClick end object ThreadLabel: TLabel Left = 1 Height = 20 Top = 36 Width = 305 Alignment = taCenter AutoSize = False Caption = ' Threads' ParentColor = False end end end ��������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_macscript.bat�����������������������������������������������������0000755�0001750�0001750�00000000714�11017303514�017014� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������chmod 777 ./_xclean.bat ./_xclean.bat cp ./common/notgui.inc ./common/isgui.inc lazbuild ./dcm2nii/dcm2nii.lpr cp ./dcm2nii/dcm2nii ../distro/dcm2nii ./_xclean.bat cp ./common/gui.inc ./common/isgui.inc lazbuild ./mricron.lpr --ws=carbon lazbuild ./npm/npm.lpr --ws=carbon lazbuild ./dcm2nii/dcm2niigui.lpr --ws=carbon cp ./mricron ../distro/mricron.app/mricron cp ./npm/npm ../distro/npm.app/npm cp ./dcm2nii/dcm2niigui ../distro/dcm2niigui.app/dcm2niigui ����������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/ortho_reorient.pas�������������������������������������������������0000755�0001750�0001750�00000042135�12306421062�017753� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit ortho_reorient; //reorient image to nearest orthogonal plane interface uses SysUtils,define_types,GraphicsMathLibrary,prefs,nifti_hdr,dialogs, nifti_types; function OrthoReorientCore(var lHdr: TMRIcroHdr; l4D: boolean): boolean; implementation function NIfTIAlignedM (var lM: TMatrix): boolean; //check that diagonals are positive and all other cells are zero //negative diagonals suggests flipping... //non-negative other cells suggests the image is not pure axial var lr,lc: integer; begin result := false; for lr := 1 to 3 do for lc := 1 to 3 do begin if (lr = lc) and (lM.matrix[lr,lc] <= 0) then exit; if (lr <> lc) and (lM.matrix[lr,lc] <> 0) then exit; end; result := true; end; function NIfTIAligned (var lHdr: TNIFTIhdr): boolean; //check that diagonals are positive and all other cells are zero //negative diagonals suggests flipping... //non-negative other cells suggests the image is not pure axial var lM: TMatrix; begin lM := Matrix3D ( lHdr.srow_x[0],lHdr.srow_x[1],lHdr.srow_x[2],lHdr.srow_x[3], lHdr.srow_y[0],lHdr.srow_y[1],lHdr.srow_y[2],lHdr.srow_y[3], lHdr.srow_z[0],lHdr.srow_z[1],lHdr.srow_z[2],lHdr.srow_z[3], 0,0,0,1); result := NIfTIAlignedM(lM); end; procedure FromMatrix (M: TMatrix; var m11,m12,m13, m21,m22,m23, m31,m32,m33: DOUBLE) ; BEGIN m11 := M.Matrix[1,1]; m12 := M.Matrix[1,2]; m13 := M.Matrix[1,3]; m21 := M.Matrix[2,1]; m22 := M.Matrix[2,2]; m23 := M.Matrix[2,3]; m31 := M.Matrix[3,1]; m32 := M.Matrix[3,2]; m33 := M.Matrix[3,3]; END {FromMatrix3D}; function nifti_mat44_orthogx( lR :TMatrix): TMatrix; //returns rotation matrix required to orient image so it is aligned nearest to the identity matrix = // 1 0 0 0 // 0 1 0 0 // 0 0 1 0 // 0 0 0 1 //Therefore, image is approximately oriented in space var lrow,lcol,lMaxRow,lMaxCol,l2ndMaxRow,l2ndMaxCol,l3rdMaxRow,l3rdMaxCol: integer; r11,r12,r13 , r21,r22,r23 , r31,r32,r33, val,lAbsmax,lAbs: double; Q: TMatrix; //3x3 begin // load 3x3 matrix into local variables FromMatrix(lR,r11,r12,r13,r21,r22,r23,r31,r32,r33); Q := Matrix2D( r11,r12,r13,r21,r22,r23,r31,r32,r33); // normalize row 1 val := Q.matrix[1,1]*Q.matrix[1,1] + Q.matrix[1,2]*Q.matrix[1,2] + Q.matrix[1,3]*Q.matrix[1,3] ; if( val > 0.0 )then begin val := 1.0 / sqrt(val) ; Q.matrix[1,1] := Q.matrix[1,1]*val ; Q.matrix[1,2] := Q.matrix[1,2]*val ; Q.matrix[1,3] := Q.matrix[1,3]*val ; end else begin Q.matrix[1,1] := 1.0 ; Q.matrix[1,2] := 0.0; Q.matrix[1,3] := 0.0 ; end; // normalize row 2 val := Q.matrix[2,1]*Q.matrix[2,1] + Q.matrix[2,2]*Q.matrix[2,2] + Q.matrix[2,3]*Q.matrix[2,3] ; if( val > 0.0 ) then begin val := 1.0 / sqrt(val) ; Q.matrix[2,1] := Q.matrix[2,1]* val ; Q.matrix[2,2] := Q.matrix[2,2] * val ; Q.matrix[2,3] := Q.matrix[2,3] * val ; end else begin Q.matrix[2,1] := 0.0 ; Q.matrix[2,2] := 1.0 ; Q.matrix[2,3] := 0.0 ; end; // normalize row 3 val := Q.matrix[3,1]*Q.matrix[3,1] + Q.matrix[3,2]*Q.matrix[3,2] + Q.matrix[3,3]*Q.matrix[3,3] ; if( val > 0.0 ) then begin val := 1.0 / sqrt(val) ; Q.matrix[3,1] := Q.matrix[3,1] *val ; Q.matrix[3,2] := Q.matrix[3,2] *val ; Q.matrix[3,3] := Q.matrix[3,3] *val ; end else begin Q.matrix[3,1] := Q.matrix[1,2]*Q.matrix[2,3] - Q.matrix[1,3]*Q.matrix[2,2] ; //* cross */ Q.matrix[3,2] := Q.matrix[1,3]*Q.matrix[2,1] - Q.matrix[1,1]*Q.matrix[2,3] ; //* product */ Q.matrix[3,3] := Q.matrix[1,1]*Q.matrix[2,2] - Q.matrix[1,2]*Q.matrix[2,1] ; end; //next - find closest orthogonal coordinates - each matrix cell must be 0,-1 or 1 //First: find axis most aligned to a principal axis lAbsmax := 0; lMaxRow := 1; lMaxCol := 1; for lrow := 1 to 3 do begin for lcol := 1 to 3 do begin lAbs := abs(Q.matrix[lrow,lcol]); if lAbs > lAbsMax then begin lAbsmax := lAbs; lMaxRow := lRow; lMaxCol := lCol; end; end; //for rows end; //for columns //Second - find find axis that is 2nd closest to principal axis lAbsmax := 0; l2ndMaxRow := 2; l2ndMaxCol := 2; for lrow := 1 to 3 do begin for lcol := 1 to 3 do begin if (lrow <> lMaxRow) and (lCol <> lMaxCol) then begin lAbs := abs(Q.matrix[lrow,lcol]); if lAbs > lAbsMax then begin lAbsmax := lAbs; l2ndMaxRow := lRow; l2ndMaxCol := lCol; end; //new max end; //do not check MaxRow/MaxCol end; //for rows end; //for columns //next - no degrees of freedom left: third prinicple axis is the remaining axis if ((lMaxRow = 1) or (l2ndMaxRow = 1)) and ((lMaxRow = 2) or (l2ndMaxRow = 2)) then l3rdMaxRow := 3 else if ((lMaxRow = 1) or (l2ndMaxRow = 1)) and ((lMaxRow = 3) or (l2ndMaxRow = 3)) then l3rdMaxRow := 2 else l3rdMaxRow := 1; if ((lMaxCol = 1) or (l2ndMaxCol = 1)) and ((lMaxCol = 2) or (l2ndMaxCol = 2)) then l3rdMaxCol := 3 else if ((lMaxCol = 1) or (l2ndMaxCol = 1)) and ((lMaxCol = 3) or (l2ndMaxCol = 3)) then l3rdMaxCol := 2 else l3rdMaxCol := 1; //finally, fill in our rotation matrix //cells in the canonical rotation transform can only have values 0,1,-1 result := Matrix3D( 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0); if Q.matrix[lMaxRow,lMaxCol] < 0 then result.matrix[lMaxRow,lMaxCol] := -1 else result.matrix[lMaxRow,lMaxCol] := 1; if Q.matrix[l2ndMaxRow,l2ndMaxCol] < 0 then result.matrix[l2ndMaxRow,l2ndMaxCol] := -1 else result.matrix[l2ndMaxRow,l2ndMaxCol] := 1; if Q.matrix[l3rdMaxRow,l3rdMaxCol] < 0 then result.matrix[l3rdMaxRow,l3rdMaxCol] := -1 else result.matrix[l3rdMaxRow,l3rdMaxCol] := 1; end; FUNCTION QuickInvertMatrix3D (CONST Input:TMatrix): TMatrix; //http://www.cellperformance.com/articles/2006/06/a_4x4_matrix_inverse_1.html //Most of the time in the video games, programmers are not doing a standard inverse matrix. //It is too expensive. Instead, to inverse a matrix, they consider it as orthonormal //and they just do a 3x3 transpose of the rotation part with a dot product for the translation. //Sometimes the full inverse algorithm is necessary.... var i,j: integer; begin result.size := Input.size; for i := 1 to 3 do for j := 1 to 3 do result.matrix[i,j] := input.matrix[j,i]; //next - fill in edge if 3D if result.size <> size3D then exit; //do not fill in final column for 2D matrices for i := 1 to 3 do result.matrix[4,i] := 0; for i := 1 to 3 do result.matrix[i,4] := 0; result.matrix[4,4] := 1; end; procedure FindMatrixPt (lX,lY,lZ: single; var lXout,lYOut,lZOut: single; var lMatrix: TMatrix); begin lXOut := (lX*lMatrix.matrix[1,1])+(lY*lMatrix.matrix[1,2])+(lZ*lMatrix.matrix[1,3])+lMatrix.matrix[1,4]; lYOut := (lX*lMatrix.matrix[2,1])+(lY*lMatrix.matrix[2,2])+(lZ*lMatrix.matrix[2,3])+lMatrix.matrix[2,4]; lZOut := (lX*lMatrix.matrix[3,1])+(lY*lMatrix.matrix[3,2])+(lZ*lMatrix.matrix[3,3])+lMatrix.matrix[3,4]; end; procedure CheckMin(var lX,lY,lZ,lXMin,lYMin,lZMin: single); begin if lX < lXMin then lXMin := lX; if lY < lYMin then lYMin := lY; if lZ < lZMin then lZMin := lZ; end; procedure Mins (var lMatrix: TMatrix; var lHdr: TNIFTIhdr; var lXMin,lYMin,lZMin: single); var lPos,lXc,lYc,lZc: integer; lx,ly,lz: single; begin FindMatrixPt(0,0,0,lX,lY,lZ,lMatrix); lXMin := lX; lYMin := lY; lZMin := lZ; for lPos := 1 to 7 do begin if odd(lPos) then lXc := lHdr.Dim[1]-1 else lXc := 0; if odd(lPos shr 1) then lYc := lHdr.Dim[2]-1 else lYc := 0; if odd(lPos shr 2) then lZc := lHdr.Dim[3]-1 else lZc := 0; FindMatrixPt(lXc,lYc,lZc,lX,lY,lZ,lMatrix); CheckMin(lX,lY,lZ,lXMin,lYMin,lZMin); end; end; (*procedure ReportMatrix (lM:TMatrix); const kCR = chr (13); begin showmessage(RealToStr(lM.matrix[1,1],6)+','+RealToStr(lM.matrix[1,2],6)+','+RealToStr(lM.matrix[1,3],6)+','+RealToStr(lM.matrix[1,4],6)+kCR+ RealToStr(lM.matrix[2,1],6)+','+RealToStr(lM.matrix[2,2],6)+','+RealToStr(lM.matrix[2,3],6)+','+RealToStr(lM.matrix[2,4],6)+kCR+ RealToStr(lM.matrix[3,1],6)+','+RealToStr(lM.matrix[3,2],6)+','+RealToStr(lM.matrix[3,3],6)+','+RealToStr(lM.matrix[3,4],6)+kCR +RealToStr(lM.matrix[4,1],6)+','+RealToStr(lM.matrix[4,2],6)+','+RealToStr(lM.matrix[4,3],6)+','+RealToStr(lM.matrix[4,4],6) ); end;*) function OrthoReorientCore(var lHdr: TMRIcrohdr; l4D: boolean): boolean; var //lF: File; lOutHdr: TNIFTIhdr; lOutName: string; lResidualMat: TMatrix; lInMinX,lInMinY,lInMinZ,lOutMinX,lOutMinY,lOutMinZ, dx, dy, dz: single; //, QFac //lStartY,lStartZ, lStartX,lZ,lY,lX,lB, lOutZ,lOutY, lXInc, lYInc, lZInc,lBPP,lVol,lnVol: integer; lInPos,lVolBytes,lOutPos,lInOffset: integer; lBufferOut: bytep; lByteSwap,lFlipX,lFlipY,lFlipZ: boolean; lInMat,lRotMat: TMatrix; begin result := false; if {(lhdr.NIfTIhdr.dim[4] > 1) or} (lhdr.NIfTIhdr.dim[3] < 2) then begin //Showmessage('Can only orient 3D images '+inttostr(lhdr.NIfTIhdr.dim[3])+' '+inttostr(lhdr.NIfTIhdr.dim[4])); exit; end; if (lHdr.ImgBufferItems < lhdr.NIfTIhdr.dim[1]*lhdr.NIfTIhdr.dim[2]*lhdr.NIfTIhdr.dim[3]) then exit; //Msg(lHdrName); lInMat := Matrix3D ( lhdr.NIfTIhdr.srow_x[0],lhdr.NIfTIhdr.srow_x[1],lhdr.NIfTIhdr.srow_x[2],lhdr.NIfTIhdr.srow_x[3], lhdr.NIfTIhdr.srow_y[0],lhdr.NIfTIhdr.srow_y[1],lhdr.NIfTIhdr.srow_y[2],lhdr.NIfTIhdr.srow_y[3], lhdr.NIfTIhdr.srow_z[0],lhdr.NIfTIhdr.srow_z[1],lhdr.NIfTIhdr.srow_z[2],lhdr.NIfTIhdr.srow_z[3], 0,0,0,1); //ReportMatrix(lInMat); if (NIfTIAlignedM (lInMat)) then begin //Msg('According to header, image is already canonically oriented'); exit; end; lRotMat := nifti_mat44_orthogx( lInMat); if NIfTIAlignedM (lRotMat) then begin //Msg('According to header, image is already approximately canonically oriented'); exit; //already as close as possible end; lOutHdr := lHdr.NIFTIhdr; //Some software uses negative pixdims to represent a spatial flip - now that the image is canonical, all dimensions are positive lOutHdr.pixdim[1] := abs(lhdr.NIfTIhdr.pixdim[1]); lOutHdr.pixdim[2] := abs(lhdr.NIfTIhdr.pixdim[2]); lOutHdr.pixdim[3] := abs(lhdr.NIfTIhdr.pixdim[3]); //sort out dim1 lFlipX := false; if lRotMat.Matrix[1,2] <> 0 then begin lXinc := lhdr.NIfTIhdr.dim[1]; lOutHdr.dim[1] := lhdr.NIfTIhdr.dim[2]; lOutHdr.pixdim[1] := abs(lhdr.NIfTIhdr.pixdim[2]); if lRotMat.Matrix[1,2] < 0 then lFlipX := true end else if lRotMat.Matrix[1,3] <> 0 then begin lXinc := lhdr.NIfTIhdr.dim[1]*lhdr.NIfTIhdr.dim[2]; lOutHdr.dim[1] := lhdr.NIfTIhdr.dim[3]; lOutHdr.pixdim[1] := abs(lhdr.NIfTIhdr.pixdim[3]); if lRotMat.Matrix[1,3] < 0 then lFlipX := true end else begin lXinc := 1; if lRotMat.Matrix[1,1] < 0 then lFlipX := true end; //sort out dim2 lFlipY := false; if lRotMat.Matrix[2,2] <> 0 then begin lYinc := lhdr.NIfTIhdr.dim[1]; //lOutHdr.dim[2] := lhdr.NIfTIhdr.dim[2]; //lOutHdr.pixdim[2] := lhdr.NIfTIhdr.pixdim[2]; if lRotMat.Matrix[2,2] < 0 then lFlipY := true end else if lRotMat.Matrix[2,3] <> 0 then begin lYinc := lhdr.NIfTIhdr.dim[1]*lhdr.NIfTIhdr.dim[2]; lOutHdr.dim[2] := lhdr.NIfTIhdr.dim[3]; lOutHdr.pixdim[2] := abs(lhdr.NIfTIhdr.pixdim[3]); if lRotMat.Matrix[2,3] < 0 then lFlipY := true end else begin lYinc := 1; lOutHdr.dim[2] := lhdr.NIfTIhdr.dim[1]; lOutHdr.pixdim[2] := abs(lhdr.NIfTIhdr.pixdim[1]); if lRotMat.Matrix[2,1] < 0 then lFlipY := true end; //sort out dim3 lFlipZ := false; if lRotMat.Matrix[3,2] <> 0 then begin lZinc := lhdr.NIfTIhdr.dim[1]; lOutHdr.dim[3] := lhdr.NIfTIhdr.dim[2]; lOutHdr.pixdim[3] := lhdr.NIfTIhdr.pixdim[2]; if lRotMat.Matrix[3,2] < 0 then lFlipZ := true; end else if lRotMat.Matrix[3,3] <> 0 then begin lZinc := lhdr.NIfTIhdr.dim[1]*lhdr.NIfTIhdr.dim[2]; //lOutHdr.dim[3] := lhdr.NIfTIhdr.dim[3]; //lOutHdr.pixdim[3] := lhdr.NIfTIhdr.pixdim[3]; if lRotMat.Matrix[3,3] < 0 then lFlipZ := true; end else begin lZinc := 1; lOutHdr.dim[3] := lhdr.NIfTIhdr.dim[1]; lOutHdr.pixdim[3] := lhdr.NIfTIhdr.pixdim[1]; if lRotMat.Matrix[3,1] < 0 then lFlipZ := true; end; //details for writing... lBPP := (lhdr.NIfTIhdr.bitpix div 8); //bytes per pixel if lBPP > 4 then lBPP := 4;//64bit data is stored as 32-bit precision June 2009 lXinc := lXinc * lBPP; lYinc := lYinc * lBPP; lZinc := lZinc * lBPP; lVolBytes := lhdr.NIfTIhdr.dim[1]*lhdr.NIfTIhdr.dim[2]*lhdr.NIfTIhdr.dim[3]*lBPP; //now write header... //create Matrix of residual orientation... lResidualMat := QuickInvertMatrix3D(lRotMat); //the next steps are inelegant - the translation values are computed by brute force //at the moment, our lResidualMat looks like this //lResidualMat = [ 0 -1 0 0; 0 0 1 0; 1 0 0 0; 0 0 0 1]; //however, it should specify the dimensions in mm of the dimensions that are flipped //However, note that whenever you reverse the direction of //voxel coordinates, you need to include the appropriate offset //in the 'a' matrix. That is: //lResidualMat = [0 0 1 0; -1 0 0 Nx-1; 0 1 0 0; 0 0 0 1] //where Nx is the number of voxels in the x direction. //So, if you took Nx=256, then for your values before, you'd get: //TransRot = [ 0 -1 0 255; 0 0 1 0; 1 0 0 0; 0 0 0 1]; //Because we do not do this, we use the function mins to compute the translations... //I have not implemented refined version yet - require sample volumes to check //Ensure Nx is voxels not mm, etc.... //start of kludge lResidualMat := multiplymatrices(lInMat,lResidualMat); //source lResidualMat.Matrix[1,4] := 0; lResidualMat.Matrix[2,4] := 0; lResidualMat.Matrix[3,4] := 0; Mins (lInMat, lHdr.NIFTIHdr,lInMinX,lInMinY,lInMinZ); Mins (lResidualMat, lOutHdr,lOutMinX,lOutMinY,lOutMinZ); lResidualMat.Matrix[1,4] := lInMinX-lOutMinX; lResidualMat.Matrix[2,4] := lInMinY-lOutMinY; lResidualMat.Matrix[3,4] := lInMinZ-lOutMinZ; //End of kuldge lOutHdr.srow_x[0] := lResidualMat.Matrix[1,1]; lOutHdr.srow_x[1] := lResidualMat.Matrix[1,2]; lOutHdr.srow_x[2] := lResidualMat.Matrix[1,3]; lOutHdr.srow_y[0] := lResidualMat.Matrix[2,1]; lOutHdr.srow_y[1] := lResidualMat.Matrix[2,2]; lOutHdr.srow_y[2] := lResidualMat.Matrix[2,3]; lOutHdr.srow_z[0] := lResidualMat.Matrix[3,1]; lOutHdr.srow_z[1] := lResidualMat.Matrix[3,2]; lOutHdr.srow_z[2] := lResidualMat.Matrix[3,3]; lOutHdr.srow_x[3] := lResidualMat.Matrix[1,4]; lOutHdr.srow_y[3] := lResidualMat.Matrix[2,4]; lOutHdr.srow_z[3] := lResidualMat.Matrix[3,4]; nifti_mat44_to_quatern( lResidualMat, lOutHdr.quatern_b,lOutHdr.quatern_c,lOutHdr.quatern_d, lOutHdr.qoffset_x,lOutHdr.qoffset_y,lOutHdr.qoffset_z, dx, dy, dz, lOutHdr.pixdim[0]); GetMem(lBufferOut,lVolBytes); lnVol := 1; if (lhdr.NIfTIhdr.dim[4] > 1) and (l4D) then lnVol := lhdr.NIfTIhdr.dim[4]; //convert (*if lFlipX then fx(1); if lFlipY then fx(2); if lFlipZ then fx(3);*) if lFlipX then lXInc := -lXInc; if lFlipY then lYInc := -lYInc; if lFlipZ then lZInc := -lZInc; for lVol := 1 to lnVol do begin lOutPos := 0; if lFlipX then lStartX := (lOutHdr.dim[1]-1)*-lXInc else lStartX := 0; if lFlipY then lStartX := lStartX + (lOutHdr.dim[2]-1)*-lYInc; if lFlipZ then lStartX := lStartX + (lOutHdr.dim[3]-1)*-lZInc; lStartX := lStartX+ ((lVol-1)*lVolBytes); for lZ := 1 to lOutHdr.dim[3] do begin lOutZ := lStartX + (lZ-1) * lZInc; for lY := 1 to lOutHdr.dim[2] do begin lOutY := ((lY-1) * lYInc) + lOutZ; for lX := 1 to lOutHdr.dim[1] do begin for lB := 1 to (lBPP) do begin inc(lOutPos); //lInPos := ((lX-1) * lXInc) + lOutY + lB; lInPos := lOutY + lB; lBufferOut^[lOutPos] := lHdr.ImgBuffer^[lInPos]; end; inc(lOutY,lXinc); end; end; //for Y end; //for Z Move(lBufferOut^,lHdr.ImgBuffer^[1+((lVol-1)*lVolBytes)],lVolBytes); end; //for each volume (* Filemode := 2; AssignFile(lF,'C:\Documents and Settings\Admin\Desktop\rorden\perisample\shit.img'); {WIN} Rewrite(lF,1); BlockWrite(lF,lHdr.ImgBuffer^,lnVol*lVolBytes); CloseFile(lF);*) Freemem(lBufferOut); lHdr.NIFTIhdr := lOutHdr; //fx(lOutHdr.srow_x[3],lOutHdr.srow_y[3],lOutHdr.srow_z[3]); result := true; end;//ReorientCore end. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_qtscript.bat������������������������������������������������������0000755�0001750�0001750�00000001725�11070221006�016675� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������chmod 777 ./_xclean.bat ./_xclean.bat cp ./common/notgui.inc ./common/isgui.inc lazbuild ./dcm2nii/dcm2nii.lpr cp ./dcm2nii/dcm2nii ../gtk1/mricron/dcm2nii cp ./dcm2nii/dcm2nii ../gtk2/mricron/dcm2nii cp ./dcm2nii/dcm2nii ../qt/mricron/dcm2nii cp ./common/gui.inc ./common/isgui.inc ./_xclean.bat lazbuild ./mricron.lpr lazbuild ./npm/npm.lpr lazbuild ./dcm2nii/dcm2niigui.lpr cp ./mricron ../gtk1/mricron/mricron cp ./npm/npm ../gtk1/mricron/npm cp ./dcm2nii/dcm2niigui ../gtk1/mricron/dcm2niigui ./_xclean.bat lazbuild ./mricron.lpr --ws=gtk2 lazbuild ./npm/npm.lpr --ws=gtk2 lazbuild ./dcm2nii/dcm2niigui.lpr --ws=gtk2 cp ./mricron ../gtk2/mricron/mricron cp ./npm/npm ../gtk2/mricron/npm cp ./dcm2nii/dcm2niigui ../gtk2/mricron/dcm2niigui ./_xclean.bat lazbuild ./mricron.lpr --ws=qt lazbuild ./npm/npm.lpr --ws=qt lazbuild ./dcm2nii/dcm2niigui.lpr --ws=qt cp ./mricron ../qt/mricron/mricron cp ./npm/npm ../qt/mricron/npm cp ./dcm2nii/dcm2niigui ../qt/mricron/dcm2niigui �������������������������������������������mricron-0.20140804.1~dfsg.1.orig/hrf.pas������������������������������������������������������������0000755�0001750�0001750�00000014560�11326425446�015504� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit hrf; interface uses define_types, utypes,metagraph; const kHRFdur = 24000; //ms for 'full' HRF - window size for HRF function CreateHRF (lTRsec: double; var lKernelBins: integer; lDefaultsStatsFmriT: integer; var lHRFra, lTDra: doublep): boolean; function ConvolveTimeCourse(var lTimeCourse: PMatrix; var lKernel: doublep; var l4DTrace: T4DTrace; lCond,lCondOut,lnVol,lKernelBins,lDefaultsStatsFmriT,lDefaultsStatsFmriT0: integer; lTRSec: single; lSliceTime: boolean): boolean; implementation uses math {power}, ugamma {gamma},sysutils,dialogs; const kHRFkernelSec = 32; //kDefaultsStatsFmriT = 16; //each TR is supersampled at 16x resolution //from SPM's hrf.m function spm_Gpdf(x,h,l: double): double; //emulates spm_Gpdf begin result := power(l,h)*power(x,(h-1))* exp(-l*x); result := result / gamma(h); end; function fHRF (u,dt: double): double; //emulates spm_hrf.m const //TR = 1; p1= 6; //delay of response p2=16;//delay of undershoot (relative to onset) p3=1; //dispersion of response p4=1; //dispersion of undershoot p5=6; //ratio of response to undershoot p7=kHRFkernelSec;//length of kernel (seconds) begin if u <= 0 then result := 0 else result := spm_Gpdf(u,p1/p3,dt/p3) - spm_Gpdf(u,p2/p4,dt/p4)/p5; end; function CreateHRF (lTRsec: double; var lKernelBins: integer; lDefaultsStatsFmriT: integer; var lHRFra, lTDra: doublep): boolean; //NOTE: if this returns TRUE, you MUST freemem lHRFra, lTDra //returns lHRFra and lTDra with lBins of data - equal to 32sec convolution kernel for //hemodynamic response (HRF) and the HRF's temporal derivative var lDT,lSum,l1sec: double; lI: integer; begin result := false; if lDefaultsStatsFmriT < 1 then exit; lDT := (lTRsec / lDefaultsStatsFmriT); //DeltaTime - width of each sample in sec lKernelBins := round ( kHRFkernelSec / lDT); if lKernelBins < 1 then exit; getmem(lHRFra,lKernelBins*sizeof(double)); //generate whole HRF kernel for lI := 1 to lKernelBins do lHRFra^[lI] := fHRF (lI-1,lDT); //find sum lSum := 0; for lI := 1 to lKernelBins do lSum := lSum + lHRFra^[lI]; //normalize - so sum = 1 for lI := 1 to lKernelBins do lHRFra^[lI] := lHRFra^[lI]/lsum; //next temporal derivative getmem(ltdra,lKernelBins*sizeof(double)); l1sec := 1/lDT; for lI := 1 to lKernelBins do ltdra^[lI] := fHRF((lI-1)-l1sec,lDT); //tdHRF (lI-1,lDT); //find sum lSum := 0; for lI := 1 to lKernelBins do lSum := lSum + ltdra^[lI]; //normalize - so sum = 1 for lI := 1 to lKernelBins do ltdra^[lI] := ltdra^[lI]/lsum; //temporal derivative is difference between normalized TD and normalized HRF for lI := 1 to lKernelBins do ltdra^[lI] := lHRFra^[lI]- ltdra^[lI]; result := true; end; function Convolve(var lTimeCoursePrecise,lKernel: doublep; lEventBin,lnVolPrecise,lKernelBins: integer): boolean; var lVol,lStart,lEnd: integer; begin result := false; if (lEventBin > lnVolPrecise) then exit; //event too late to influence timecourse if ((lEventBin+lKernelBins)< 1) then exit;//event too early to influence timecourse lStart := lEventBin; if lStart < 1 then lStart := 1; lEnd := (lEventBin+lKernelBins-1); if lEnd > lnVolPrecise then lEnd := lnVolPrecise; //lOffset := lEventBin; for lVol := lStart to lEnd do begin lTimeCoursePrecise^[lVol] := lTimeCoursePrecise^[lVol] + lKernel^[lVol -lEventBin+1]; end; result := true; end; function ConvolveTimeCourse(var lTimeCourse: PMatrix; var lKernel: doublep; var l4DTrace: T4DTrace; lCond,lCondOut, lnVol,lKernelBins,lDefaultsStatsFmriT,lDefaultsStatsFmriT0: integer; lTRSec: single; lSliceTime: boolean): boolean; var lnVolPrecise,lEvent,lVol,lVolx,lEventBin,lEventEnd: integer; lDT: double; lTimeCoursePrecise: doublep;//supersampled by kDefaultsStatsFmriT lAllEvents: boolean; begin result := false; if (l4DTrace.Conditions[lCond].Events < 1) or (lnVol < 1) or (lTRSec <= 0) then exit; lnVolPrecise := lnVol * lDefaultsStatsFmriT; getmem(lTimeCoursePrecise,lnVolPrecise * sizeof(double)); for lVol := 1 to lnVolPrecise do lTimeCoursePrecise^[lVol] := 0; lDT := (lTRsec / lDefaultsStatsFmriT); //DeltaTime - width of each sample in sec //spm_fmri_design //X is supersampled at 16 times (fMRI_T) the number of volumes - with (32 bin offset) //k = SPM.nscan(s); //X = X([0:(k - 1)]*fMRI_T + fMRI_T0 + 32,:); for lEvent := 1 to l4DTrace.Conditions[lCond].Events do begin lEventBin := round((l4DTrace.Conditions[lCond].EventRA^[lEvent])/lDT); //incorrect: same dur will have different number of bins due to rounding: //lEventEnd := round((l4DTrace.Conditions[lCond].EventRA^[lEvent]+l4DTrace.Conditions[lCond].DurRA^[lEvent])/lDT); //correct: all stimuli of same duration will have identical number of bins lEventEnd := lEventBin+round(l4DTrace.Conditions[lCond].DurRA^[lEvent]/lDT); //if lEvent = 1 then fx(lEventBin,lEventEnd,l4DTrace.Conditions[lCond].DurRA^[lEvent]); repeat if (lEventBin > 0) and (lEventBin <= lnVolPrecise) then Convolve(lTimeCoursePrecise,lKernel,lEventBin,lnVolPrecise,lKernelBins); inc(lEventBin); until lEventBin > lEventEnd; end; //for each event //output - scaled by reciprocal of DT: e.g. if TR=2, DT=0.125, Scale = 8 //if TR=2.2, DT=0.1375 Scale = 7.2727 //this linear scaling does not change any effects - it simply clones SPM2 lAllEvents := true; for lEvent := 1 to l4DTrace.Conditions[lCond].Events do if l4DTrace.Conditions[lCond].DurRA^[lEvent] > lDT then lAllEvents := false; if lAllEvents then lDT := 1/lDT else lDT := 1; lVolx := lDefaultsStatsFmriT0; for lVol := 1 to lnVol do begin if (lVolx > 0) and (lVolx < lnVolPrecise) then lTimeCourse^[lCondOut]^[lVol] := lDT * lTimeCoursePrecise^[lVolx]; inc(lVolx,lDefaultsStatsFmriT); end; freemem(lTimeCoursePrecise); result := true; end;//func ConvolveTimeCourse end. ������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/examplefmri2.bat���������������������������������������������������0000755�0001750�0001750�00000000300�10416600102�017245� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������start mricron .\templates\ch2.nii.gz -s 3 -l 0 -h 140 -c pink -o .\templates\ch2bet.nii.gz -c -0 -l 30 -h 200 -o .\example\attention.nii.gz -l 1.96 -h 5 -z -b 40 -t 50 -r .\example\fmri2r.ini��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/isthreaded.inc�����������������������������������������������������0000755�0001750�0001750�00000000645�11063011162�017006� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//x86-64 GTK2 crashes with progress bars //GTK2 crashes with threading {$IFDEF LCLgtk2} {$ifndef cpux86_64} {$DEFINE SHOWPROG}//SHOWPROG =ShowProgressBar {$ENDIF} {$ELSE} {$DEFINE SHOWPROG}//SHOWPROG =ShowProgressBar {$ENDIF} {$IFDEF UNIX} //Windows is always threaded {$IFDEF LCLgtk2} {$DEFINE NoThreads}//NoThreads - single threaded execution //GTK2 does not allow threading {$ENDIF} {$ENDIF} �������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/xfmri3.bat���������������������������������������������������������0000755�0001750�0001750�00000000171�10426762252�016110� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./mricron ./templates/aal.nii.gz -o ./example/attention.nii.gz -c -0 -l 1.96 -h 5 -z -b 40 -t 50 -r ./example/fmri3r.ini�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_maclipo.bat�������������������������������������������������������0000755�0001750�0001750�00000000720�12154112022�016443� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# lipo -create ../distro/ppc/dcm2nii ../distro/intel/dcm2nii -output ../distro/dcm2nii cp ../distro/intel/dcm2nii ../distro/dcm2nii lipo -create ../distro/ppc/mricron ../distro/intel/mricron -output ../distro/mricron.app/Contents/MacOS/mricron lipo -create ../distro/ppc/dcm2niigui ../distro/intel/dcm2niigui -output ../distro/dcm2niigui.app/Contents/MacOS/dcm2niigui lipo -create ../distro/ppc/npm ../distro/intel/npm -output ../distro/npm.app/Contents/MacOS/npm ������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_script.bat��������������������������������������������������������0000755�0001750�0001750�00000001300�11070231504�016321� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������chmod 777 ./_xclean.bat ./_xclean.bat cp ./common/notgui.inc ./common/isgui.inc lazbuild ./dcm2nii/dcm2nii.lpr cp ./dcm2nii/dcm2nii ../gtk1/mricron/dcm2nii cp ./dcm2nii/dcm2nii ../gtk2/mricron/dcm2nii cp ./common/gui.inc ./common/isgui.inc ./_xclean.bat lazbuild ./mricron.lpr lazbuild ./npm/npm.lpr lazbuild ./dcm2nii/dcm2niigui.lpr cp ./mricron ../gtk1/mricron/mricron cp ./npm/npm ../gtk1/mricron/npm cp ./dcm2nii/dcm2niigui ../gtk1/mricron/dcm2niigui ./_xclean.bat lazbuild ./mricron.lpr --ws=gtk2 lazbuild ./npm/npm.lpr --ws=gtk2 lazbuild ./dcm2nii/dcm2niigui.lpr --ws=gtk2 cp ./mricron ../gtk2/mricron/mricron cp ./npm/npm ../gtk2/mricron/npm cp ./dcm2nii/dcm2niigui ../gtk2/mricron/dcm2niigui ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/prefs.lfm����������������������������������������������������������0000755�0001750�0001750�00000006134�12332435212�016023� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object PrefForm: TPrefForm Left = 932 Height = 456 Top = 200 Width = 393 ActiveControl = ResliceCheck BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Preferences' ClientHeight = 456 ClientWidth = 393 Constraints.MaxHeight = 456 Constraints.MaxWidth = 393 Constraints.MinHeight = 456 Constraints.MinWidth = 393 OnCreate = FormCreate OnShow = FormShow Position = poScreenCenter LCLVersion = '1.0.12.0' object GroupBox1: TGroupBox Left = 8 Height = 280 Top = 8 Width = 368 Caption = 'Image Display' ClientHeight = 258 ClientWidth = 360 TabOrder = 0 object Label1: TLabel Left = 120 Height = 17 Top = 71 Width = 190 Caption = 'Maximum Dimension [Voxels]' ParentColor = False end object Label2: TLabel Left = 120 Height = 17 Top = 113 Width = 120 Caption = 'Rendering Threads' ParentColor = False end object Label3: TLabel Left = 120 Height = 17 Top = 145 Width = 161 Caption = 'Decimal places Displayed' ParentColor = False end object ResliceCheck: TCheckBox Left = 15 Height = 18 Top = 9 Width = 210 Caption = 'Reorient images when loading' OnClick = ResliceCheckClick TabOrder = 0 end object MaxDimEdit: TSpinEdit Left = 14 Height = 16 Top = 64 Width = 100 MaxValue = 4096 MinValue = 256 TabOrder = 1 Value = 256 end object ThreadEdit: TSpinEdit Left = 14 Height = 16 Top = 101 Width = 100 MaxValue = 4096 MinValue = 1 TabOrder = 2 Value = 1 end object SigDigEdit: TSpinEdit Left = 14 Height = 16 Top = 138 Width = 100 MaxValue = 32 TabOrder = 3 end object OrthoCheck: TCheckBox Left = 43 Height = 18 Top = 37 Width = 240 Caption = 'Rotate to nearest orthogonal angle' TabOrder = 4 end object SingleRowCheck: TCheckBox Left = 15 Height = 18 Top = 208 Width = 174 Caption = 'All slices on a single row' TabOrder = 5 end end object GroupBox2: TGroupBox Left = 8 Height = 64 Top = 296 Width = 368 Caption = 'Drawing' ClientHeight = 42 ClientWidth = 360 TabOrder = 1 object ThinPenCheck: TCheckBox Left = 15 Height = 18 Top = 16 Width = 75 Caption = 'Thin Pen' TabOrder = 0 end end object OKBtn: TButton Left = 296 Height = 25 Top = 416 Width = 75 BorderSpacing.InnerBorder = 4 Caption = 'OK' OnClick = OKBtnClick TabOrder = 2 end object CancelBtn: TButton Left = 192 Height = 25 Top = 416 Width = 75 BorderSpacing.InnerBorder = 4 Caption = 'Cancel' OnClick = CancelBtnClick TabOrder = 3 end object XBarClr: TButton Left = 26 Height = 25 Top = 197 Width = 178 BorderSpacing.InnerBorder = 4 Caption = 'Choose Cross-Bar Color' OnClick = XBarClrClick TabOrder = 4 end end ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/crop.pas�����������������������������������������������������������0000755�0001750�0001750�00000026144�12306421050�015653� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit crop; interface function CropNIfTI(lL,lR,lA,lP,lD,lV: integer):boolean; function GrowNeck (lFilename: string; lVox: integer): boolean; implementation uses nifti_hdr_view, nifti_hdr, nifti_img,define_types, GraphicsMathLibrary,dialogs, nifti_img_view, nifti_types; // nifti_img_view, nifti_img,nifti_hdr, nifti_hdr_view,{ShellAPI,}ShlObj,periutils, reslice_fsl; procedure NIFTIhdr_SlicesToCoord (var lHdr: TNIFTIhdr; lXslice,lYslice,lZslice: integer; var lXmm,lYmm,lZmm: single); //ignores origin offset begin lXmm := (lHdr.srow_x[0]*lXslice)+ (lHdr.srow_x[1]*lYslice)+(lHdr.srow_x[2]*lzslice); lYmm := (lHdr.srow_y[0]*lXslice)+ (lHdr.srow_y[1]*lYslice)+(lHdr.srow_y[2]*lzslice); lZmm := (lHdr.srow_z[0]*lXslice)+ (lHdr.srow_z[1]*lYslice)+(lHdr.srow_z[2]*lzslice); end; function CropNIfTI(lL,lR,lA,lP,lD,lV: integer):boolean; //to do : data swapping (errors on detection and writing zero in reverse order) var lInHdr,lOutHdr: TNIFTIhdr; lOutname,lExt: string; lXmm,lYmm,lZmm: single; lMat: TMatrix; lOutPos,lSlice,lVol,lOutVolBytes,lInVolBytes,lImgSamples,lInc, lX,lY,lZ,lBPP, lB, lInZOffset,lInYOffset,lInSliceSz,lInXSz,lInPos,lImgOffset: integer; lBuffer: bytep; lWordX: Word; lSPM2: boolean; lOutF,lInF: File; lACrop,lPCrop,lDorsalCrop,lVentralCrop,lLCrop,lRCrop: integer; lByteSwap: boolean; begin result := false; if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1) or (gBGImg.ScrnDim[3] < 2) or (gBGImg.ScrnMM[3] = 0) then begin showmessage('Please load a 3D background image for neck removal.'); exit; end; if (gBGImg.Resliced) then begin showmessage('You must switch reslicing OFF (Help/Preferences) for image cropping.'); exit; end; lInHdr := gMRIcroOverlay[kBGOverlayNum].NIFTIHdr; //check orthogonal alignment.... if lInHdr.dim[4] > 1 then begin Showmessage('Only Cropping 1st 3D image (reorienting 4D could disrupt slice timing and diffusion directions.'); //exit; end; //Next create reordered or trimmed image in the correct format case lInHdr.datatype of kDT_UNSIGNED_CHAR,kDT_SIGNED_SHORT,kDT_UINT16, kDT_SIGNED_INT,kDT_FLOAT:;//Supported else begin Showmessage('Crop 3D unsupported datatype.'); exit; end; end; lOutHdr := lInHdr; lImgSamples := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]; lBPP := (lInHdr.bitpix div 8); //bytes per pixel lDorsalCrop := lD; lVentralCrop := lV; lLCrop := lL; lRCrop := lR; lACrop := lA; lPCrop := lP; //FreeMem(lBuffUnaligned); if (lDorsalCrop = 0) and (lVentralCrop = 0) and (lLCrop = 0) and (lRCrop = 0) and (lACrop = 0) and (lPCrop = 0) then begin Showmessage('Grow 3D quitting: no need to add or delete slices.'); //Freemem(lSrcBuffer); end; if (lDorsalCrop < 0) or (lVentralCrop < 0) or (lLCrop < 0) or (lRCrop < 0) or (lACrop < 0) or (lPCrop < 0) then begin Showmessage('Grow 3D quitting: negative values should be impossible.'); //Freemem(lSrcBuffer); end; //next compute size of cropped volume lInVolBytes := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]*lBPP; lOutHdr.Dim[1] := lInHdr.Dim[1]-lLCrop-lRCrop; lOutHdr.Dim[2] := lInHdr.Dim[2]-lACrop-lPCrop; lOutHdr.Dim[3] := lInHdr.Dim[3]-lDorsalCrop-lVentralCrop; lOutVolBytes := lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3]*lBPP; //next: readjust origin to take into account removed slices //REQUIRES images to be aligned to nearest orthogonal to canonical space [1 0 0; 0 1 0; 0 0 1] NIFTIhdr_SlicesToCoord (lInHdr,lLCrop,lPCrop,lVentralCrop, lXmm,lYmm,lZmm); lOutHdr.srow_x[3] := lInHdr.srow_x[3] + lXmm; lOutHdr.srow_y[3] := lInHdr.srow_y[3] + lYmm; lOutHdr.srow_z[3] := lInHdr.srow_z[3] + lZmm; lMat := Matrix3D ( lOutHdr.srow_x[0], lOutHdr.srow_x[1], lOutHdr.srow_x[2], lOutHdr.srow_x[3], lOutHdr.srow_y[0], lOutHdr.srow_y[1], lOutHdr.srow_y[2], lOutHdr.srow_y[3], lOutHdr.srow_z[0], lOutHdr.srow_z[1], lOutHdr.srow_z[2], lOutHdr.srow_z[3], 0, 0, 0, 1); nifti_mat44_to_quatern( lMat, lOutHdr.quatern_b,lOutHdr.quatern_c,lOutHdr.quatern_d, lOutHdr.qoffset_x,lOutHdr.qoffset_y,lOutHdr.qoffset_z, lXmm, lYmm, lZmm, lOutHdr.pixdim[0]{QFac}); //note we write to a different buffer, as we may need to grow output //no need to byteswap data - we will save in the save format as stored lOutPos := 0; lInSliceSz := lInHdr.dim[1]*lInHdr.dim[2]*lBPP; lInXSz := lInHdr.dim[1]*lBPP; GetMem(lBuffer,lOutVolBytes); //Move(gMRIcroOverlay[kBGOverlayNum].ImgBuffer^,lTempBuf^,gBGImg.VOIUndoVolItems); for lZ := 1 to lOutHdr.dim[3] do begin lInZOffset := (lVentralCrop+lZ-1) * lInSliceSz; if lInZOffset < 0 then lInZOffset := 0; for lY := 1 to lOutHdr.dim[2] do begin lInYOffset := ((lPCrop+lY-1) * lInXSz) + lInZOffset + (lLCrop*lBPP); for lX := 1 to lOutHdr.dim[1] do begin for lB := 1 to lBPP do begin inc(lOutPos); lInPos := ((lX-1) * lBPP) + lInYOffset + lB; if (lInPos < 1) or (lInPos > lInVolBytes) then lBuffer^[lOutPos] := 128 else lBuffer^[lOutPos] := gMRIcroOverlay[kBGOverlayNum].ImgBuffer^[lInPos]; end; end; end; //for Y end; //for Z lOutname := ChangeFilePrefix (gMRIcroOverlay[kBGOverlayNum].HdrFileName,'c'); //result := SaveNIfTICore (lOutName, lSrcBuffer, kNIIImgOffset+1, lOutHdr, lPrefs,lByteSwap); result := gBGImg.UseReorientHdr; gBGImg.UseReorientHdr := false; SaveAsVOIorNIFTI (lBuffer,lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3], lBPP,1, false, lOutHdr, lOutname); gBGImg.UseReorientHdr := result; result := true; Freemem(lBuffer); end; function GrowNeck (lFilename: string; lVox: integer): boolean; //to do : data swapping (errors on detection and writing zero in reverse order) var lInHdr,lOutHdr: TNIFTIhdr; lOutname,lExt: string; lXmm,lYmm,lZmm: single; lMat: TMatrix; lOutPos,lSlice,lVol,lOutVolBytes,lInVolBytes,lImgSamples,lInc, lX,lY,lZ,lBPP, lB, lVolOffset,lInZOffset,lInYOffset,lInSliceSz,lInXSz,lInPos,lImgOffset: integer; lBuffer: bytep; lWordX: Word; lSPM2: boolean; lOutF,lInF: File; lACrop,lPCrop,lDorsalCrop,lVentralCrop,lLCrop,lRCrop: integer; lByteSwap: boolean; begin gBGImg.Prompt4DVolume := false; if not HdrForm.OpenAndDisplayHdr(lFilename,gMRIcroOverlay[kBGOverlayNum]) then exit; gBGImg.Prompt4DVolume := true; if not OpenImg(gBGImg,gMRIcroOverlay[kBGOverlayNum],false,false,false,false,true {4D!}) then exit; lInHdr := gMRIcroOverlay[kBGOverlayNum].NIFTIHdr; result := false; if (gMRIcroOverlay[kBGOverlayNum].ImgBufferItems < 1) or (lInHdr.dim[1] < 2) or (lInHdr.dim[2] < 2) then begin showmessage('Please load a 3D background image for neck removal.'); exit; end; if (gBGImg.Resliced) then begin showmessage('You must switch reslicing OFF (Help/Preferences) for image cropping.'); exit; end; //check orthogonal alignment.... lOutHdr := lInHdr; lImgSamples := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]; lBPP := (lInHdr.bitpix div 8); //bytes per pixel lDorsalCrop := 0; lVentralCrop := lVox; lLCrop := 0; lRCrop := 0; lACrop := 0; lPCrop := 0; //FreeMem(lBuffUnaligned); if (lDorsalCrop = 0) and (lVentralCrop = 0) and (lLCrop = 0) and (lRCrop = 0) and (lACrop = 0) and (lPCrop = 0) then begin Showmessage('Grow 3D quitting: no need to add or delete slices.'); //Freemem(lSrcBuffer); end; if (lDorsalCrop < 0) or (lVentralCrop < 0) or (lLCrop < 0) or (lRCrop < 0) or (lACrop < 0) or (lPCrop < 0) then begin Showmessage('Grow 3D quitting: negative values should be impossible.'); //Freemem(lSrcBuffer); end; //next compute size of cropped volume lOutHdr.Dim[1] := lInHdr.Dim[1]-lLCrop-lRCrop; lOutHdr.Dim[2] := lInHdr.Dim[2]-lACrop-lPCrop; lOutHdr.Dim[3] := lInHdr.Dim[3]-lDorsalCrop-lVentralCrop; //next: readjust origin to take into account removed slices //REQUIRES images to be aligned to nearest orthogonal to canonical space [1 0 0; 0 1 0; 0 0 1] NIFTIhdr_SlicesToCoord (lInHdr,lLCrop,lPCrop,lVentralCrop, lXmm,lYmm,lZmm); lOutHdr.srow_x[3] := lInHdr.srow_x[3] + lXmm; lOutHdr.srow_y[3] := lInHdr.srow_y[3] + lYmm; lOutHdr.srow_z[3] := lInHdr.srow_z[3] + lZmm; lMat := Matrix3D ( lOutHdr.srow_x[0], lOutHdr.srow_x[1], lOutHdr.srow_x[2], lOutHdr.srow_x[3], lOutHdr.srow_y[0], lOutHdr.srow_y[1], lOutHdr.srow_y[2], lOutHdr.srow_y[3], lOutHdr.srow_z[0], lOutHdr.srow_z[1], lOutHdr.srow_z[2], lOutHdr.srow_z[3], 0, 0, 0, 1); nifti_mat44_to_quatern( lMat, lOutHdr.quatern_b,lOutHdr.quatern_c,lOutHdr.quatern_d, lOutHdr.qoffset_x,lOutHdr.qoffset_y,lOutHdr.qoffset_z, lXmm, lYmm, lZmm, lOutHdr.pixdim[0]{QFac}); //note we write to a different buffer, as we may need to grow output //no need to byteswap data - we will save in the save format as stored lOutPos := 0; lInSliceSz := lInHdr.dim[1]*lInHdr.dim[2]*lBPP; lInXSz := lInHdr.dim[1]*lBPP; lInVolBytes := lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]*lInHdr.dim[4]*lBPP; lOutVolBytes := lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3]*lOutHdr.dim[4]*lBPP; GetMem(lBuffer,lOutVolBytes); //Move(gMRIcroOverlay[kBGOverlayNum].ImgBuffer^,lTempBuf^,gBGImg.VOIUndoVolItems); for lVol := 1 to lOutHdr.dim[4] do begin lVolOffset := (lVol-1) * lInHdr.dim[1]*lInHdr.dim[2]*lInHdr.dim[3]* lBPP; for lZ := 1 to lOutHdr.dim[3] do begin if lZ > -lVentralCrop then lInZOffset := ((lVentralCrop+lZ-1) * lInSliceSz) else lInZOffset := 0; for lY := 1 to lOutHdr.dim[2] do begin lInYOffset := ((lPCrop+lY-1) * lInXSz) + lInZOffset + (lLCrop*lBPP); for lX := 1 to lOutHdr.dim[1] do begin for lB := 1 to lBPP do begin inc(lOutPos); lInPos := ((lX-1) * lBPP) + lInYOffset + lB; if (lInPos < 1) or (lInPos > lInVolBytes) then lBuffer^[lOutPos] := 0 else lBuffer^[lOutPos] := gMRIcroOverlay[kBGOverlayNum].ImgBuffer^[lInPos+lVolOffset]; end; end; end; //for Y end; //for Z end; //lvol lOutname := ChangeFilePrefix (gMRIcroOverlay[kBGOverlayNum].HdrFileName,'c'); //result := SaveNIfTICore (lOutName, lSrcBuffer, kNIIImgOffset+1, lOutHdr, lPrefs,lByteSwap); result := gBGImg.UseReorientHdr; gBGImg.UseReorientHdr := false; SaveAsVOIorNIFTI (lBuffer,lOutHdr.dim[1]*lOutHdr.dim[2]*lOutHdr.dim[3], lBPP,lOutHdr.dim[4], false, lOutHdr, lOutname); gBGImg.UseReorientHdr := result; result := true; Freemem(lBuffer); end; end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/mricron.ico��������������������������������������������������������0000755�0001750�0001750�00000073306�12371445245�016370� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������00��������� ���� ��.��������)������h��0��00�� �%��6�� �� ���[���� �h��Vl��������p��(���0���`�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������~~yyDD++EEӣ������������������������������������������������������������������������������������������������������������쿿ہNN ����������<<������������������������������������������������������������������������������������������������袢``��������������������/0���������������������������������������������������������ÛvvMM66MMʭ՚ssGG��������������������������������������������������������������XY=>-."# �������������������������������� Ue������������������������������������������8:y��~������������������������������&�@�[�n�~Hamnwׂ؝������������������������������#��� ���������������������������)�U�����������������RRϊ���������������{}#Z|��������]�*��������������'�v��������������������;;jj���������obw�����������~�3�������<���������������������������;;������;? ����������������S �������������e����������������������mm������%%+�������������m����������m������������������������������))))$' .�����������������J������������������������ ++������LL8722+0! ����������A��x�E����������������������������� 11���dd>>AA;;15'!���O�������"oL-���������������������������������!!''**''__������//GGLL@?:=����������������6����"��������������������������������**,,555588���������GG[[MMLL((��������������Lc���������������������������������((6688BB;;@@������������MMRRbbXXAA�����������������Z�������������������������������������==AAFFMMIIII������������MMlleeYY�����������������`�������������������������������������--KKLLUUMMQQ������������������DDRRxxmm%%�����������������\�����?������������������������������NNUUXXaaRR���������������������bbhhSS���������������M�����u��������������������������BB``]]jj[[������������������������ffVV||EE�����������6����������������������������� EEffddrrjj__������������������������������kkQQTT ���������!�������������������������++ZZllkkxxmm\\������������������������������������]]^^pp..�����������������������77XXoopptt||ssss������������������������������������������uuQQbb##��������� �������!!99RRffqqrrtt������������������������������������������������``\\bb// ��X����('::KK[[ffmmppqqvvzznnxx������������������������������������������������������hhlj78 ��,GEQR\[aaddhhjjnnyynn���������������������������������������������������������������rrRRhhZl+�1]LT][``eekkttttuu������������������������������������������������������������������������uull& v\hmsrxx}}{{mm__xx������������������������������������������������������������������������������������yyuuopolpxu,<:MMVVWW__jj���������������������������������������������������������������������������������������������������||! H@���qp ++::oo�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?�����������������������������������������������(��� ���@��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������aa������������������������������������������������������������������������������ㅅRR55^^������������������������������������������������������������xx44������������$!������������������������������������psLP2645CC<<�������������� ���������������������������pk!�����������������������&�J�j��6`IZ]qψܻ���������������<�S�zu�Y�5 ������Q��������e������]]���������zgt��������A������������]��������bb������ ��������/�������������������������12'$������. ����]����������������^^���>>;=32�@�����Rcc�8 ������������������$$$$ss���QQIIKL:<���������p�����������������������005588���������WWZZWW���������"�������������������11AAGGEE���������ttSSqq33������������a������������������NNTTSSpp������������iinnff������������������������HHbbaarr������������������bbZZ����e�����������������NNllll__������������������������eeqq!!������D�� ���������AAhhxx~~||���������������������������tt]]YY �������**@@ZZoo||}}ttff������������������������������������nnb_(��@:LN^]jjuu{{{{xx������������������������������������������AA~~cL_lpmqqssrrss������������������������������������������������������}}plixjiiiiYXii{{������������������������������������������������������������������}}������ii�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?��(������0����������������������������������������������������������������������>��L��P���������������������������������������r�������������������7� ��;��-����� ����!�$#�%-�-!�0F�22�3(�53�88�:3�;?�< �<�?1�B��I��JJ�NM�PP�PR�QZ�TS�YY�YY�Z\�\Z�^`�__�`��bb�ff�gg�o�vv�ww�zy�|z�||�~��v���������������u���H���� �__�$������ ���������� ����l�*��VT�����o�������������14��������&�6��>8�LM�TT�Yg��2����������������� ���77�::�LL�PP�QQ�UU�]\�cc�pm�tt�������������������������""�&&�44�;�AA�[[�aa�cc�ee�mm�ss�tt�yy�{{�}}��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������waO@Fc���������������hkP=0A��������gL?689<) 3>Jsu�����X2  1Mix~{z���C+' #"[}|y��;5!(!Kļ�IE7*_�TRH-,o��VY4%&t֊���]`G./qՈ����UdD$f������^l\:NՎ��������ZjnWBԘ�����������rmpev��������������bQS��������������������������������������������������������������������������������������������������������������?�?���������������������������?������(������ ��������������������������������������������� �������������������������� ��k� ;� �k�K�!�&� �',�->�/!�0��9+�;2�M]�PP�Wj�YZ�bY�ff�hk�i=�jj�lk�l�oo�op�t��}n���������������x���Zn�[[���H[�B�����������j�$�������>5������{��}{�����������BB�KM�NN�PP�dd�jj��� ������������ ��#�))�::�T]�[[�uu�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������&!��������0793#�����$/18A>;�) =Scba`C@? 5hFGDENegj�% :OITRd`VWY�*( <^JM`QUZ[���+' 6pHLfilm�����-2",_KX\no��������4.BkP]������������������������������������������������������������������������������������������(���0���`���� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������F��������������������������������������������������������������������������������������������������������������������������������������������P����������������������<����������������������������������������������������������������������������������������������������������������������������������������������������������==����������������������������������������������������������������������������������������������������������������������)������������������������������##hhoo�������������������� ��������������������������������������������������������������e����������������������������������LLrrpp������������������))DJHn[Wmgc ���������������������������������������������� ��n��������������������������������������hhwoU��o��������>:XTXTKGtnX�������������� �����������������������������������������t�����vva���������� )'TPtnrlhcOMx ������}������������������������������,���Z����8wn9������������=:rltorlC@&�������������������������������5����۾���^sV$������������ %#lgtntoUQ@= ��������� ��������e*ft*r����������������OKlgtnjdGDC>_�����������������%/isc��������������������:8c^rmniPL0-����  w��������ns_(a����������������������*(ZVqkpjSO1-t2155=5' #8GW7��������������������������RNojoiQM53@@%00~}wviXHELTgjloqt����������������������������" UQpjlgLH73|JJӞuttwwwwwwO ����������������������������,*[WqlgbB?SKD3~yxwwwwwwE ���J������������������������� SOnhtnXT:7 .zxusromk>����ܱ�����������������������d`rmtnMIA?r+voj[RH4|*Z 4 �����������������������������84ojtorl<9z$ uuՆcc'' ������������������<�����������������20TPjetoql`[���� uuuss77!!������s����������w���������������VQkfsmsnjeMJ����@}}ŀPP88$$ ����=�������������������������85lgsnuooj[V=:������������5dss[[//����������צ���������B>]YniuotoqkEBOJg ����������������"9ww{{LL77%%�ߣ������ 20c^ojtntoqld`JFx �������������������� %vvmmWWAA he��%$A>ZVrltouoqlfaJG ���������������������������� (?YYDD33 ')(2/HEkfrltotosnniGD=:������������������������������������'=ww{{ggSS7700.4:>IHF4-,-+LH\WidsntotoqkjdXTLJk ���������������������������������������� %kwwvv[[TToS_gmurmg[ZW\Xkfpksntosnql_ZKH<:���������������������������������������������������� 0FxxΘ|wxrsnpjjeWSIE=:˿������������������������������������������������������������*bxx}wvqqlb]WSJFFCb_F������������������������������������������������������������������������ 1A]||~zsn^[XTQMGCNKw8 ������������������������������������������������������������������������������������ *3<GIH=6- ������������������������������������������������������������������������������������������������������������ &'& ��������������������������������������������������������������������������������������������������������������������������������  ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������>����<����������������������������������������������������������������������������������������������������������������������������������������������?������?����������������������������������������������(��� ���@���� ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������==������������������������������������������������������������������������������)��������������������##oo������������ ������������������������������ ��n������������������������hhoU������XTXTtnX������������������������������������t����va������ TPtnhcOMx���������������������5���۾��^s$��������%#lgtoUQ ������� �����e*t*r������������OKtnjdC>_���� �����ns(a��������������*(qkpj1-21=5 #8W7������������������ojoi53JJӞutwwww ������������������,*qlgbSKD3~xwwww ��J����������������� SOtnXT +vj[H4| 4 �������������������84ojrl<9 uu՞cc'' �������������������������20jeto`[����@PP$$ ��=�����������������85lguooj=:��������d[[//�������������B>niuoqkEB ������������ %mmAA ��%$ZVrluoqlJG �������������������� (YY33 '(HEkftotoniGD���������������������������� %kvv[[oS_mumg[\Xkfsntoql_Z<:������������������������������������ FxxΘxrsnjeWS=:˿��������������������������������������������1]sn^[QMGCw8 �������������������������������������������������������� *<GH=- ����������������������������������������������������������������������������  ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?����?(������ ���� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������n������������hhU��XT���������������s����lgUQ���� ��s��������*(pjuww����������,*gbv[4| ���������oj<9@PP =��������lgoj���� mm��%$rlql ������������ k[[_ug[kfto_Z��������������������1^[GC �������������������������������� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(������(��������������������������������������������������������������������������������((�,,�99�AA�I�J��WW�ZZ�hh�ll�nn�x{�yy������������S��������������������������������������2������������� ����!!�&&�,,�//�DD�EE�II�LM�QQ�WW�ZZ�^^�bb�dd�ii�jj�oo�rr�ss�}}������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BDA21,+�� .49CE@>7>0,� 8EB@>>>>7:H� -;>?>>>>>>JM��"5bF>>>>>>KON��#3c>>>>>>>SV`���& /=>>>>>>XZU����� )<G>>IV\^_�������(*'6QTW[]Y�����������!%$LRPa�����������������������������������������������������������������������������������������������������������������0����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/reorient.pas�������������������������������������������������������0000755�0001750�0001750�00000010251�11326425450�016540� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit reorient; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, RXSpin,nifti_hdr,graphicsMathLibrary, ExtCtrls; type TReorientForm = class(TForm) ZEdit: TRxSpinEdit; YEdit: TRxSpinEdit; XEdit: TRxSpinEdit; ReorientTimer: TTimer; PitchEdit: TRxSpinEdit; RollEdit: TRxSpinEdit; YawEdit: TRxSpinEdit; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; Label6: TLabel; Xlabel: TLabel; YLabel: TLabel; ZLabel: TLabel; procedure ReorientTimerTimer(Sender: TObject); procedure EditChange(Sender: TObject); private { Private declarations } public procedure ApplyTransform ( var lHdr: TMRIcroHdr); { Public declarations } end; var ReorientForm: TReorientForm; implementation uses nifti_img_view,nifti_img, nifti_hdr_view; {$R *.DFM} procedure TReorientForm.ApplyTransform ( var lHdr: TMRIcroHdr); var lM,lRot: TMatrix; begin //exit; if (XEdit.value = 0) and (YEdit.value = 0) and (ZEdit.value = 0) and (PitchEdit.value = 0) and (YawEdit.value = 0) and (RollEdit.value = 0) then exit; lRot := Matrix3D (1,0,0,XEdit.value, 0,1,0,YEdit.value, 0,0,1,ZEdit.value, 0,0,0,1); lM := Matrix3D ( lHdr.NIFTIhdr.srow_x[0],lHdr.NIFTIhdr.srow_x[1],lHdr.NIFTIhdr.srow_x[2],lHdr.NIFTIhdr.srow_x[3], // 3D "graphics" matrix lHdr.NIFTIhdr.srow_y[0],lHdr.NIFTIhdr.srow_y[1],lHdr.NIFTIhdr.srow_y[2],lHdr.NIFTIhdr.srow_y[3], // 3D "graphics" matrix lHdr.NIFTIhdr.srow_z[0],lHdr.NIFTIhdr.srow_z[1],lHdr.NIFTIhdr.srow_z[2],lHdr.NIFTIhdr.srow_z[3], // 3D "graphics" matrix 0,0,0,1); if PitchEdit.value <> 0 then RotatePitch(PitchEdit.value{-11.4592},lRot); if RollEdit.value <> 0 then RotateRoll(RollEdit.value,lRot); if YawEdit.value <> 0 then RotateYaw(YawEdit.value,lRot); //lM := lRot; lM := MultiplyMatrices(lRot,lM); (* WriteNiftiMatrix (lHdr.NiftiHdr, lM.matrix[1,1],lM.matrix[1,2],lM.matrix[1,3],lM.matrix[1,4], lM.matrix[2,1],lM.matrix[2,2],lM.matrix[1,3],lM.matrix[2,4], lM.matrix[3,1],lM.matrix[3,2],lM.matrix[1,3],lM.matrix[3,4]); lHdr.Mat := lM; *) //Caption := inttostr(random(888))+floattostr(lM.matrix[1,4]); XLabel.caption:= floattostr(lM.matrix[1,1])+'x'+floattostr(lM.matrix[1,2])+'x'+floattostr(lM.matrix[1,3])+'x'+floattostr(lM.matrix[1,4]); YLabel.caption:= floattostr(lM.matrix[2,1])+'x'+floattostr(lM.matrix[2,2])+'x'+floattostr(lM.matrix[2,3])+'x'+floattostr(lM.matrix[2,4]); ZLabel.caption:= floattostr(lM.matrix[3,1])+'x'+floattostr(lM.matrix[3,2])+'x'+floattostr(lM.matrix[3,3])+'x'+floattostr(lM.matrix[3,4]); end; (*procedure DrawLine(lIMage: TImage; lXmm,lYmm,lZmm,lXmm2,lYmm2,lZmm2: integer); var lX,lY,lZ: integer; begin lImage.Canvas.Pen.Color:=gBGImg.XBarClr; lImage.Canvas.Pen.Width := gBGImg.XBarThick; MMToImgCoord( lX,lY,lZ, lXmm,lYmm,lZmm); lImage.Canvas.MoveTo(lX,lY); MMToImgCoord( lX,lY,lZ, lXmm2,lYmm2,lZmm2); lImage.Canvas.LineTo(lX,lY); end;*) procedure TReorientForm.ReorientTimerTimer(Sender: TObject); begin ReorientTimer.enabled := false; //ImgForm.CloseOverlayImgClick(nil); (*DrawLine(ImgForm.PGImage2,0,-104,0,0,72,0);//horizontal line on Sag DrawLine(ImgForm.PGImage2,0,0,78,0,0,-48);//horizontal line on Sag DrawLine(ImgForm.PGImage3,0,0,77,0,0,-48);//horizontal line on Sag DrawLine(ImgForm.PGImage3,-64,0,0,64,0,0);//horizontal line on Sag *) ApplyTransform(gMRIcroOverlay[kBGOverlayNum]); //MMToImgCoord(var lX,lY,lZ: integer; var lXmm,lYmm,lZmm: single); end; (*procedure TReorientForm.ReorientTimerTimer(Sender: TObject); var lFilename: string; begin ReorientTimer.enabled := false; ImgForm.CloseOverlayImgClick(nil); ReorientTimer.enabled := false; lFilename := 'C:\pas\Delphi\niftiview\grey.voi'; ImgForm.LoadOverlay (lFilename); end; *) procedure TReorientForm.EditChange(Sender: TObject); begin ReorientTimer.enabled := true; end; end. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/nii_label.pas������������������������������������������������������0000755�0001750�0001750�00000017016�12306627412�016636� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit nii_label; {$IFDEF FPC} {$mode delphi} {$ENDIF} interface uses {$IFNDEF FPC} gziod, {$ELSE} gzio2, {$ENDIF} dialogs,Classes, SysUtils, define_types; procedure createLutLabel (var lut: TLUT; lSaturationFrac: single); procedure LoadLabels(lFileName: string; var lLabels: TStrRA; lOffset,lLength: integer); procedure LoadLabelsTxt(lFileName: string; var lLabels: TStrRA); implementation procedure LoadLabelsCore(lInStr: string; var lLabels: TStrRA); var lIndex,lPass,lMaxIndex,lPos,lLength: integer; lStr1: string; lCh: char; begin lLabels := nil; lLength := length(lInStr); lMaxIndex := -1; for lPass := 1 to 2 do begin lPos := 1; if lPass = 2 then begin if lMaxIndex < 1 then exit; SetLength(lLabels,lMaxIndex+1); for lIndex := 0 to lMaxIndex do lLabels[lIndex] := ''; end; while lPos <= lLength do begin lStr1 := ''; repeat lCh := lInStr[lPos]; inc(lPos); if (lCh >= '0') and (lCh <= '9') then lStr1 := lStr1 + lCh; until (lPos > lLength) or (lCh=kCR) or (lCh=UNIXeoln) or (((lCh=kTab)or (lCh=' ')) and (length(lStr1)>0)); if (length(lStr1) > 0) and (lPos <= lLength) then begin lIndex := strtoint(lStr1); if lPass = 1 then begin if lIndex > lMaxIndex then lMaxIndex := lIndex end else if lIndex >= 0 then begin //pass 2 lStr1 := ''; repeat lCh := lInStr[lPos]; inc(lPos); if (lPos > lLength) or (lCh=kCR) or (lCh=UNIXeoln) {or (lCh=kTab) or (lCh=' ')} then // else lStr1 := lStr1 + lCh; until (lPos > lLength) or (lCh=kCR) or (lCh=UNIXeoln) {or (lCh=kTab)or (lCh=' ')}; lLabels[lIndex] := lStr1; end; //if pass 2 end; //if lStr1>0 end; //while not EOF end; //for each pass end; procedure LoadLabels(lFileName: string; var lLabels: TStrRA; lOffset,lLength: integer); var f : file; // untyped file s : string; // string for reading a file sz: int64; ptr: bytep; begin if GzExt(lFilename) then begin if (lLength < 1) then exit; SetLength(s, lLength); ptr := @s[1]; UnGZip (lFileName,ptr, lOffset,lLength); end else begin AssignFile(f, lFileName); FileMode := fmOpenRead; reset(f, 1); if lOffset > 0 then seek(f, lOffset); if (lLength < 1) then sz := FileSize(f)-lOffset else sz := lLength; if (lOffset+sz) > FileSize(f) then exit; SetLength(s, sz); BlockRead(f, s[1], length(s)); CloseFile(f); FileMode := fmOpenReadWrite; end; LoadLabelsCore(s, lLabels); //showmessage(lLabels[1]); end; procedure LoadLabelsTxt(lFileName: string; var lLabels: TStrRA); //filename = 'all.nii' will read 'aal.txt' var lLUTname: string; begin lLabels := nil; //empty current labels lLUTname := changefileext(lFileName,'.txt'); if not Fileexists(lLUTname) then begin lLUTname := ParseFileName(lFileName)+'.txt'; //file.nii.gz -> file.txt if not Fileexists(lLUTname) then exit; end; LoadLabels(lLUTname, lLabels,0,-1); end; procedure desaturateRGBA( var lRGBA: TRGBquad; frac: single); var r,g,b: byte; y: single; begin r := lRGBA.rgbRed; g := lRGBA.rgbGreen; b := lRGBA.rgbBlue; //convert RGB->YUV http://en.wikipedia.org/wiki/YUV y := 0.299 * r + 0.587 * g + 0.114 * b; r := round(y * (1-frac) + r * frac); g := round(y * (1-frac) + g * frac); b := round(y * (1-frac) + b * frac); lRGBA.rgbRed := r; lRGBA.rgbGreen := g; lRGBA.rgbBlue := b; end; function makeRGB(r,g,b: byte): TRGBquad; begin result.rgbRed := r; result.rgbGreen := g; result.rgbBlue := b; result.rgbReserved := 64; end; procedure createLutLabel (var lut: TLUT; lSaturationFrac: single); //lLUT: 0=gray,1=red,2=green,3=blue var i:integer; begin lut[0] := makeRGB(0,0,0); lut[0].rgbReserved:= 0; lut[1] := makeRGB(71,46,154); lut[2] := makeRGB(33,78,43); lut[3] := makeRGB(192,199,10); lut[4] := makeRGB(32,79,207); lut[5] := makeRGB(195,89,204); lut[6] := makeRGB(208,41,164); lut[7] := makeRGB(173,208,231); lut[8] := makeRGB(233,135,136); lut[9] := makeRGB(202,20,58); lut[10] := makeRGB(25,154,239); lut[11] := makeRGB(210,35,30); lut[12] := makeRGB(145,21,147); lut[13] := makeRGB(89,43,230); lut[14] := makeRGB(87,230,101); lut[15] := makeRGB(245,113,111); lut[16] := makeRGB(246,191,150); lut[17] := makeRGB(38,147,35); lut[18] := makeRGB(3,208,128); lut[19] := makeRGB(25,37,57); lut[20] := makeRGB(57,28,252); lut[21] := makeRGB(167,27,79); lut[22] := makeRGB(245,86,173); lut[23] := makeRGB(86,203,120); lut[24] := makeRGB(227,25,25); lut[25] := makeRGB(208,209,126); lut[26] := makeRGB(81,148,81); lut[27] := makeRGB(64,187,85); lut[28] := makeRGB(90,139,8); lut[29] := makeRGB(199,111,7); lut[30] := makeRGB(140,48,122); lut[31] := makeRGB(48,102,237); lut[32] := makeRGB(212,76,190); lut[33] := makeRGB(180,110,152); lut[34] := makeRGB(70,106,246); lut[35] := makeRGB(120,130,182); lut[36] := makeRGB(9,37,130); lut[37] := makeRGB(192,160,219); lut[38] := makeRGB(245,34,67); lut[39] := makeRGB(177,222,76); lut[40] := makeRGB(65,90,167); lut[41] := makeRGB(157,165,178); lut[42] := makeRGB(9,245,235); lut[43] := makeRGB(193,222,250); lut[44] := makeRGB(100,102,28); lut[45] := makeRGB(181,47,61); lut[46] := makeRGB(125,19,186); lut[47] := makeRGB(145,130,250); lut[48] := makeRGB(62,4,199); lut[49] := makeRGB(8,232,67); lut[50] := makeRGB(108,137,58); lut[51] := makeRGB(36,211,50); lut[52] := makeRGB(140,240,86); lut[53] := makeRGB(237,11,182); lut[54] := makeRGB(242,140,108); lut[55] := makeRGB(248,21,77); lut[56] := makeRGB(161,42,89); lut[57] := makeRGB(189,22,112); lut[58] := makeRGB(41,241,59); lut[59] := makeRGB(114,61,125); lut[60] := makeRGB(65,99,226); lut[61] := makeRGB(121,115,50); lut[62] := makeRGB(97,199,205); lut[63] := makeRGB(50,166,227); lut[64] := makeRGB(238,114,125); lut[65] := makeRGB(149,190,128); lut[66] := makeRGB(44,204,104); lut[67] := makeRGB(214,60,27); lut[68] := makeRGB(124,233,59); lut[69] := makeRGB(167,66,66); lut[70] := makeRGB(40,115,53); lut[71] := makeRGB(167,230,133); lut[72] := makeRGB(127,125,159); lut[73] := makeRGB(178,103,203); lut[74] := makeRGB(231,203,97); lut[75] := makeRGB(30,125,125); lut[76] := makeRGB(173,13,139); lut[77] := makeRGB(244,176,159); lut[78] := makeRGB(193,94,158); lut[79] := makeRGB(203,131,7); lut[80] := makeRGB(204,39,215); lut[81] := makeRGB(238,198,47); lut[82] := makeRGB(139,167,140); lut[83] := makeRGB(135,124,226); lut[84] := makeRGB(71,67,223); lut[85] := makeRGB(234,175,231); lut[86] := makeRGB(234,254,44); lut[87] := makeRGB(217,1,110); lut[88] := makeRGB(66,15,184); lut[89] := makeRGB(14,198,61); lut[90] := makeRGB(129,62,233); lut[91] := makeRGB(19,237,47); lut[92] := makeRGB(97,159,67); lut[93] := makeRGB(165,31,148); lut[94] := makeRGB(112,218,22); lut[95] := makeRGB(244,58,120); lut[96] := makeRGB(35,244,173); lut[97] := makeRGB(73,47,156); lut[98] := makeRGB(192,61,117); lut[99] := makeRGB(12,67,181); lut[100] := makeRGB(149,94,94); for i := 1 to 100 do lut[i+100] := lut[i]; //fill 101..200 for i := 1 to 55 do lut[i+200] := lut[i]; //fill 201..255 if (lSaturationFrac < 0) or (lSaturationFrac >= 1.0) then exit; for i := 1 to 255 do desaturateRGBA(lut[i], lSaturationFrac); end; end. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/ROIfilt.pas��������������������������������������������������������0000755�0001750�0001750�00000013533�12306421016�016220� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit ROIfilt; interface uses {$IFNDEF FPC} RXSpin, {$ELSE} Spin,LResources, {$ENDIF} {$IFNDEF Unix} Windows,{$ENDIF} Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons,define_types, nifti_hdr, nifti_types; type TFilterROIform = class(TForm) Label42: TLabel; FilterROIBtn: TSpeedButton; Label43: TLabel; Filter2NIfTIBtn: TSpeedButton; FiltROILabel: TLabel; MinROIfilt: TSpinEdit; MaxROIfilt: TSpinEdit; procedure MinROIfiltChange(Sender: TObject); procedure FilterROIBtnClick(Sender: TObject); {$IFNDEF FPC} procedure FormClose(Sender: TObject; var Action: TCloseAction); {$ELSE} procedure FormClose(Sender: TObject); {$ENDIF} procedure FormShow(Sender: TObject); procedure Filter2NIfTIBtnClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var FilterROIform: TFilterROIform; implementation uses nifti_img_view,nifti_img; {$IFNDEF FPC} {$R *.DFM} {$ENDIF} procedure TFilterROIform.MinROIfiltChange(Sender: TObject); begin if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1 then exit; FilterLUT (gBGImg, gMRIcroOverlay[kBGOverlayNum], round(MinROIFilt.Value),round(MaxROIfilt.value)); //lLUT: 0=gray,1=red,2=green,3=blue FiltROILabel.caption := 'Calibrated range: '+realtostr(Scrn2ScaledIntensity (gMRIcroOverlay[kBGOverlayNum],MinROIfilt.value),3) +'...'+realtostr(Scrn2ScaledIntensity (gMRIcroOverlay[kBGOverlayNum],MaxROIfilt.value),3); ImgForm.RefreshImagesTimer.enabled := true; end; procedure TFilterROIform.FilterROIBtnClick(Sender: TObject); var lBGBuffer,lVOIBuffer:ByteP; lInc,lMin,lMax,lBufferItems,lVOIvoxelsAfter,lVOIvoxelsBefore: integer; begin lBufferItems := gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems; if lBufferItems < 1 then begin showmessage('You need to open up a VOI (Draw/Open) in order to apply an intensity filter to the VOI.'); exit; end; if gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems <> lBufferItems then begin showmessage('Error: VOI dimensions do not match background image.'); exit; end; CreateUndoVol; (*case MessageDlg('Unable to undo this operation. You should save a backup copy prior to this (Draw/Save). Are you sure you wish to filter your VOI?', mtConfirmation, [mbYes, mbCancel], 0) of id_Cancel: exit; end; //case *) lMin := round(MinROIFilt.value); lMax := round(MaxROIFilt.value); if lMin > lMax then begin //swap lInc := lMin; lMin := lMax; lMax := lInc; end; //swap if lBufferItems < 1 then showmessage('Error: no background image open to filter.') else begin lBGBuffer := gMRIcroOverlay[kBGOverlayNum].ScrnBuffer; lVOIBuffer := gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer; lVOIvoxelsBefore := 0; for lInc := 1 to lBufferItems do if (lVOIBuffer^[lInc] > 0) then inc(lVOIvoxelsBefore); for lInc := 1 to lBufferItems do if (lBGBuffer^[lInc] < lMin) or (lBGBuffer^[lInc] > lMax) then lVOIBuffer^[lInc] := 0; lVOIvoxelsAfter := 0; for lInc := 1 to lBufferItems do if (lVOIBuffer^[lInc] > 0) then inc(lVOIvoxelsAfter); showmessage('VOI voxels prior to filter = '+inttostr(lVOIvoxelsBefore)+kCR + 'VOI voxels after filter = '+inttostr(lVOIvoxelsAfter)); gBGImg.VOIchanged := true; //Save8BitAsVOIorNIFTI(lFilteredBuffer,lBufferItems); end; //BGimage open FilterROIForm.Close; //nn end; {$IFNDEF FPC} procedure TFilterROIform.FormClose(Sender: TObject; var Action: TCloseAction); {$ELSE} procedure TFilterROIform.FormClose(Sender: TObject); {$ENDIF} begin FilterLUT (gBGImg, gMRIcroOverlay[kBGOverlayNum], -1,-1); //lLUT: 0=gray,1=red,2=green,3=blue ImgForm.RefreshImagesTimer.enabled := true; end; procedure TFilterROIform.FormShow(Sender: TObject); var lInc: integer; begin for lInc := 0 to 255 do gBGImg.BackupLUT[lInc]:= gMRIcroOverlay[kBGOverlayNum].LUT[lInc]; MinROIfiltChange(nil); end; procedure MirrorBuffer(var lBuffer8:ByteP; lX,lXYZ: integer ); var lnRow,lRow,lHlfX,lLineOffset,lXPos,lTemp: integer; begin if (lXYZ < 2) or (lX > lXYZ) or ((lXYZ mod lX) <> 0) then exit; lnRow := lXYZ div lX; lHlfX := lX div 2; lLineOffset := 0; for lRow := 1 to lnRow do begin for lXPos := 1 to lHlfX do begin lTemp := lBuffer8^[lXPos+lLineOffset]; lBuffer8^[lXPos+lLineOffset] := lBuffer8^[1+lX-lXPos+lLineOffset]; lBuffer8^[1+lX-lXPos+lLineOffset] := lTemp; end; //for X lLineOffset := lLineOffset + lX; end;//for each row... end; //MirrorBuffer procedure TFilterROIform.Filter2NIfTIBtnClick(Sender: TObject); var lFilteredBuffer:ByteP; lInc,lMin,lMax,lBufferItems: integer; lNiftiHdr : TNIFTIhdr; begin lBufferItems := gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems; lMin := round(MinROIFilt.value); lMax := round(MaxROIFilt.value); if lMin > lMax then begin //swap lInc := lMin; lMin := lMax; lMax := lInc; end; //swap if lBufferItems < 1 then showmessage('Error: no background image open to filter.') else begin getmem(lFilteredBuffer,lBufferItems); move(gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^,lFilteredBuffer^,lBufferItems); for lInc := 1 to lBufferItems do if (lFilteredBuffer^[lInc] < lMin) or (lFilteredBuffer^[lInc] > lMax) then lFilteredBuffer^[lInc] := 0; lNiftiHdr := gMRIcroOverlay[kBGOverlayNum].NiftiHdr; if gBGImg.Mirror then MirrorBuffer(lFilteredBuffer,gMRIcroOverlay[kBGOverlayNum].NIFTIhdr.Dim[1], lBufferItems); //10/2010 SaveAsVOIorNIFTI(lFilteredBuffer,lBufferItems,1,1,true,{gMRIcroOverlay[kBGOverlayNum].}lNiftiHdr,''); //SaveAsVOIorNIFTI(lFilteredBuffer,lBufferItems,1,true,gMRIcroOverlay[kBGOverlayNum].NiftiHdr,''); freemem(lFilteredBuffer); end; FilterROIForm.Close; end; {$IFDEF FPC} initialization {$I ROIfilt.lrs} {$ENDIF} end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/bet.lfm������������������������������������������������������������0000755�0001750�0001750�00000002724�11540266274�015471� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object BETForm: TBETForm Left = 485 Height = 313 Top = 539 Width = 545 ActiveControl = Panel1 Caption = 'Brain extraction' ClientHeight = 313 ClientWidth = 545 Constraints.MaxHeight = 313 Constraints.MaxWidth = 545 Constraints.MinHeight = 313 Constraints.MinWidth = 545 Position = poScreenCenter LCLVersion = '0.9.28.2' object Memo1: TMemo Left = 0 Height = 281 Top = 32 Width = 545 Align = alClient TabOrder = 0 end object Panel1: TPanel Left = 0 Height = 32 Top = 0 Width = 545 Align = alTop BevelOuter = bvNone ClientHeight = 32 ClientWidth = 545 TabOrder = 1 object GoBtn: TSpeedButton Left = 8 Height = 25 Top = 2 Width = 88 Caption = 'Go' Color = clBtnFace NumGlyphs = 0 OnClick = GoBtnClick end object AboutBtn: TSpeedButton Left = 100 Height = 25 Top = 2 Width = 88 Caption = 'About' Color = clBtnFace NumGlyphs = 0 OnClick = SpeedButton2Click end object CropBtn: TSpeedButton Left = 192 Height = 25 Top = 2 Width = 88 Caption = 'Crop Edges' Color = clBtnFace NumGlyphs = 0 OnClick = CropBtnClick end object SmoothnessEdit: TFloatSpinEdit Left = 308 Height = 27 Top = 5 Width = 93 Increment = 1 MaxValue = 1 MinValue = 0 TabOrder = 0 Value = 0.5 end end end ��������������������������������������������mricron-0.20140804.1~dfsg.1.orig/nifti_hdr_view.pas�������������������������������������������������0000755�0001750�0001750�00000062574�12307406616�017733� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit nifti_hdr_view; interface {$H+} uses {$IFNDEF FPC} RXSpin,capmenu, {$ELSE} LResources, Spin, {$ENDIF} {$IFNDEF Unix} ShellAPI, {$ENDIF} SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, nifti_hdr, Menus, ComCtrls, define_types, nifti_types; type { THdrForm } THdrForm = class(TForm) Ymm: TFloatSpinEdit; MainMenu1: TMainMenu; File1: TMenuItem; Open1: TMenuItem; Exit1: TMenuItem; Save1: TMenuItem; Help1: TMenuItem; About1: TMenuItem; OpenHdrDlg: TOpenDialog; SaveHdrDlg: TSaveDialog; PageControl1: TPageControl; TabRequired: TTabSheet; TabUnused: TTabSheet; intent_nameEdit: TEdit; data_typeEdit: TEdit; CommentEdit: TEdit; db_: TEdit; aux: TEdit; gmax: TSpinEdit; gmin: TSpinEdit; ses: TSpinEdit; ext: TSpinEdit; reg: TSpinEdit; Label34: TLabel; Label5: TLabel; Label6: TLabel; Label9: TLabel; Label10: TLabel; Label14: TLabel; Label15: TLabel; Label18: TLabel; Label19: TLabel; Label26: TLabel; HeaderMagicDrop: TComboBox; Label21: TLabel; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label8: TLabel; Label7: TLabel; Endian: TComboBox; fTypeDrop: TComboBox; Label44: TLabel; xyzt_sizeDrop: TComboBox; xyzt_timeDrop: TComboBox; Xdim: TSpinEdit; Ydim: TSpinEdit; Zdim: TSpinEdit; Zmm: TFloatSpinEdit; OffsetEdit: TSpinEdit; TDim: TSpinEdit; Xmm: TFloatSpinEdit; TSec: TFloatSpinEdit; StatusBar1: TStatusBar; Label29: TLabel; Dim5Edit: TSpinEdit; TabSheet1: TTabSheet; Label35: TLabel; IntentCodeDrop: TComboBox; intent_p1Edit: TFloatSpinEdit; intent_p2Edit: TFloatSpinEdit; intent_p3Edit: TFloatSpinEdit; Label25: TLabel; Label27: TLabel; Label28: TLabel; TabSheet2: TTabSheet; Label11: TLabel; Label16: TLabel; Label17: TLabel; Label32: TLabel; slice_startEdit: TSpinEdit; Slice_durationEdit: TFloatSpinEdit; toffsetEdit: TFloatSpinEdit; TabSheet3: TTabSheet; cmax: TFloatSpinEdit; cmin: TFloatSpinEdit; Label12: TLabel; Label13: TLabel; Scale: TFloatSpinEdit; Label23: TLabel; Intercept: TFloatSpinEdit; Label22: TLabel; Label30: TLabel; Label33: TLabel; Page1: TMenuItem; Dimensions1: TMenuItem; ImageIntensity1: TMenuItem; Statistics1: TMenuItem; FunctionalMRI1: TMenuItem; Optional1: TMenuItem; TabSheet4: TTabSheet; Rotations1: TMenuItem; srow_x0Edit: TFloatSpinEdit; srow_x1Edit: TFloatSpinEdit; srow_x2Edit: TFloatSpinEdit; Label24: TLabel; Label36: TLabel; Label37: TLabel; srow_y0Edit: TFloatSpinEdit; srow_y1Edit: TFloatSpinEdit; srow_y2Edit: TFloatSpinEdit; srow_z0Edit: TFloatSpinEdit; srow_z1Edit: TFloatSpinEdit; srow_z2Edit: TFloatSpinEdit; srow_x3Edit: TFloatSpinEdit; srow_y3Edit: TFloatSpinEdit; srow_z3Edit: TFloatSpinEdit; quatern_bEdit: TFloatSpinEdit; quatern_cEdit: TFloatSpinEdit; quatern_dEdit: TFloatSpinEdit; qoffset_xEdit: TFloatSpinEdit; qoffset_yEdit: TFloatSpinEdit; qoffset_zEdit: TFloatSpinEdit; Label39: TLabel; Label40: TLabel; Label41: TLabel; Dim6Edit: TSpinEdit; Label42: TLabel; Dim7Edit: TSpinEdit; PixDim5: TFloatSpinEdit; PixDim6: TFloatSpinEdit; PixDim7: TFloatSpinEdit; SliceCodeDrop: TComboBox; Label20: TLabel; slice_endEdit: TSpinEdit; FreqDimDrop: TComboBox; PhaseDimDrop: TComboBox; SliceDimDrop: TComboBox; Label31: TLabel; Label43: TLabel; Label45: TLabel; QFacEdit: TFloatSpinEdit; Label46: TLabel; QFormDrop: TComboBox; SFormDrop: TComboBox; Label38: TLabel; Label47: TLabel; //procedure FormShow(Sender: TObject); procedure FormShow(Sender: TObject); procedure SaveHdrDlgClose(Sender: TObject); procedure WriteHdrForm (var lHdr: TMRIcroHdr); procedure ReadHdrDimensionsOnly (var lHdr: TMRIcroHdr); //reads only size dimensions: useful for computing estimated filesize procedure ReadHdrForm (var lHdr: TMRIcroHdr); //reads entire header procedure About1Click(Sender: TObject); procedure Open1Click(Sender: TObject); procedure Save1Click(Sender: TObject); procedure TabMenuClick(Sender: TObject); procedure Exit1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure ImageSzChange(Sender: TObject); procedure HeaderMagicDropSelect(Sender: TObject); function OpenAndDisplayHdr (var lFilename: string; var lHdr: TMRIcroHdr): boolean; //procedure ReadXForm (var lHdr: TMRIcroHdr); private { Private declarations } {$IFNDEF FPC} procedure WMDropFiles(var Msg: TWMDropFiles); message WM_DROPFILES; {$ENDIF} public { Public declarations } end; function OpenDialogExecute (lFilter,lCaption: string; lAllowMultiSelect: boolean): boolean; var HdrForm: THdrForm; implementation uses nifti_img_view, render,nifti_img; {$IFNDEF FPC} {$R *.DFM} {$ENDIF} function OpenDialogExecute (lFilter,lCaption: string; lAllowMultiSelect: boolean): boolean; begin HdrForm.OpenHdrDlg.Filter := lFilter; HdrForm.OpenHdrDlg.FilterIndex := 1; HdrForm.OpenHdrDlg.Title := lCaption; if lAllowMultiSelect then HdrForm.OpenHdrDlg.Options := [ofAllowMultiSelect,ofFileMustExist]; result := HdrForm.OpenHdrDlg.Execute; HdrForm.OpenHdrDlg.Options := [ofFileMustExist]; end; function DropItem2DataType(lItemIndex: integer): integer; //returns NIfTI datatype number begin case lItemIndex of 0: result :=1; //binary 1 : result := 256; //8-bit S 2 : result := 2; //8-bit int U* 3 : result := 4; //16-bit int S* 4 : result := 512; //16-bit int U 5 : result := 8; //32-bit int S* 6 : result := 768; //32-bit int U 7: result := 1024; //64-bit int S 8: result := 1280; //64-bit int U 9: result := 16; //32-bit real* 10: result := 64; //64-bit real* 11: result := 1536; //128-bit real 12: result := 128; //24-bit rgb 13: result := 32; //64-bit complex 14: result := 1792; //128-bit complex 15: result := 2048; //256-bit complex else result := 0; end; //case end; //func DropItem2DataType function DataType2DropItem (lDataType: smallint): integer; begin case lDataType of 1: result := 0; //binary 256: result := 1; //8-bit S 2: result := 2; //8-bit int U* 4: result := 3; //16-bit int S* 512: result := 4; //16-bit int U 8: result := 5; //32-bit int S* 768: result := 6; //32-bit int U 1024: result := 7; //64-bit int S 1280: result := 8; //64-bit int U 16: result := 9; //32-bit real* 64: result := 10; //64-bit real* 1536: result := 11; //128-bit real 128: result := 12; //24-bit rgb 32: result := 13; //64-bit complex 1792: result := 14; //128-bit complex 2048: result := 15; //256-bit complex else result := 0; end; //case end; //func DataType2DropItem function DataType2BitsPerVoxel (lDataType: smallint): integer; begin case lDataType of 1: result := 1; //binary 256: result := 8; //8-bit S 2: result := 8; //8-bit int U* 4: result := 16; //16-bit int S* 512: result := 16; //16-bit int U 8: result := 32; //32-bit int S* 768: result := 32; //32-bit int U 1024: result := 64; //64-bit int S 1280: result := 64; //64-bit int U 16: result := 32; //32-bit real* 64: result := 64; //64-bit real* 1536: result := 128; //128-bit real 128: result := 24; //24-bit rgb 32: result := 64; //64-bit complex 1792: result := 128; //128-bit complex 2048: result := 256; //256-bit complex else result := 0; end; //case end; //func DataType2BitsPerVoxel function time_units2DropItem (lxyzt_units: byte): integer; var lxyzt_unitsClipped: byte; begin lxyzt_unitsClipped := lxyzt_units and 56; case lxyzt_unitsClipped of kNIFTI_UNITS_SEC : result := 1;//= 8; kNIFTI_UNITS_MSEC : result := 2;//= 16; kNIFTI_UNITS_USEC : result := 3;//= 24; kNIFTI_UNITS_HZ : result := 4;//= 32; kNIFTI_UNITS_PPM : result := 5;//= 40; else result := 0; //unknown end; //case end; //func time_units2DropItem function DropItem2time_units (lDropItemIndex: byte): integer; //convert ComboBox index to NIFTI time units begin case lDropItemIndex of 1: result := kNIFTI_UNITS_SEC; 2: result := kNIFTI_UNITS_MSEC; 3: result := kNIFTI_UNITS_USEC; 4: result := kNIFTI_UNITS_HZ; 5: result := kNIFTI_UNITS_PPM; else result := 0; //unknown end; //case end; //func DropItem2time_units procedure THdrForm.WriteHdrForm (var lHdr: TMRIcroHdr); //writes a header to the various controls var //lCStr: string[80]; lInc: Integer; begin with lHdr.NIFTIhdr do begin //numDimEdit.value := dim[0]; XDim.Value := dim[1]; YDim.Value := dim[2]; ZDim.Value := dim[3]; TDim.Value := dim[4]; Dim5Edit.value := dim[5]; Dim6Edit.value := dim[6]; Dim7Edit.value := dim[7]; Xmm.Value := pixdim[1]; Ymm.Value := pixdim[2]; Zmm.Value := pixdim[3]; TSec.Value := pixdim[4]; PixDim5.value := pixdim[5]; PixDim6.value := pixdim[6]; PixDim7.value := pixdim[7]; OffsetEdit.value := round(vox_offset); Scale.value := scl_slope; Intercept.value := scl_inter; {$IFNDEF FPC} fTypeDrop.SetItemIndex( DataType2DropItem( datatype)); if lHdr.NativeEndian then Endian.SetItemIndex(0) else Endian.SetItemIndex(1); //caption := inttohex(Magic); if Magic = kNIFTI_MAGIC_EMBEDDED_HDR then HeaderMagicDrop.SetItemIndex(2) else if Magic = kNIFTI_MAGIC_SEPARATE_HDR then HeaderMagicDrop.SetItemIndex(1) else if Magic = kswapNIFTI_MAGIC_EMBEDDED_HDR then HeaderMagicDrop.SetItemIndex(2) else if Magic = kswapNIFTI_MAGIC_SEPARATE_HDR then HeaderMagicDrop.SetItemIndex(1) else HeaderMagicDrop.SetItemIndex(0); xyzt_sizeDrop.SetItemIndex(xyzt_units and 3); xyzt_timeDrop.SetItemIndex(time_units2DropItem(xyzt_units)); {$ELSE} fTypeDrop.ItemIndex := ( DataType2DropItem( datatype)); if lHdr.DiskDataNativeEndian then Endian.ItemIndex:=(0) else Endian.ItemIndex:=(1); if Magic = kNIFTI_MAGIC_EMBEDDED_HDR then HeaderMagicDrop.ItemIndex:=(2) else if Magic = kNIFTI_MAGIC_SEPARATE_HDR then HeaderMagicDrop.ItemIndex:=(1) else if Magic = kswapNIFTI_MAGIC_EMBEDDED_HDR then HeaderMagicDrop.ItemIndex:=(2) else if Magic = kswapNIFTI_MAGIC_SEPARATE_HDR then HeaderMagicDrop.ItemIndex:=(1) else HeaderMagicDrop.ItemIndex:=(0); xyzt_sizeDrop.ItemIndex:=(xyzt_units and 3); xyzt_timeDrop.ItemIndex:=(time_units2DropItem(xyzt_units)); {$ENDIF} CommentEdit.text := descrip; data_typeEdit.text := data_type; db_.text := db_name; aux.text := aux_file; intent_nameEdit.text := intent_name; ext.value := extents; lInc := intent_code; if (intent_code > 1) and (intent_code <= kNIFTI_LAST_STATCODE) then lInc := lInc - 1 //intent_codes start from 2 not 1 else if intent_code >= kNIFTI_FIRST_NONSTATCODE then //remove gap in numbers that follow final statcode lInc := (intent_code - kNIFTI_FIRST_NONSTATCODE)+kNIFTI_LAST_STATCODE else begin lInc := 0; //unknown end; {$IFNDEF FPC} IntentCodeDrop .SetItemIndex(lInc); SliceCodeDrop.SetItemIndex(slice_code); FreqDimDrop.SetItemIndex(dim_info and 3); PhaseDimDrop.SetItemIndex((dim_info shr 2) and 3); SliceDimDrop.SetItemIndex((dim_info shr 4) and 3); {$ELSE} IntentCodeDrop.ItemIndex:=lInc; SliceCodeDrop.ItemIndex:=(slice_code); FreqDimDrop.ItemIndex:=(dim_info and 3); PhaseDimDrop.ItemIndex:=((dim_info shr 2) and 3); SliceDimDrop.ItemIndex:=((dim_info shr 4) and 3); {$ENDIF} intent_p1Edit.value := intent_p1; intent_p2Edit.value := intent_p2; intent_p3Edit.value := intent_p3; ses.value := session_error; reg.value := ord(regular); slice_startEdit.value := slice_start; slice_endEdit.value := slice_end; cmax.value := cal_max; cmin.value := cal_min; slice_durationEdit.value := slice_duration; toffsetEdit.value := toffset; gmax.value := glmax; gmin.value := glmin; //Next: 3D orientation rotations QFacEdit.value := pixdim[0]; {$IFNDEF FPC} QFormDrop.SetItemIndex(qform_code); SFormDrop.SetItemIndex(sform_code); {$ELSE} QFormDrop.ItemIndex:= (qform_code); SFormDrop.ItemIndex :=(sform_code); {$ENDIF} quatern_bEdit.value := quatern_b; quatern_cEdit.value := quatern_c; quatern_dEdit.value := quatern_d; qoffset_xEdit.value := qoffset_x; qoffset_yEdit.value := qoffset_y; qoffset_zEdit.value := qoffset_z; srow_x0Edit.value := srow_x[0];//12 affine matrix values srow_x1Edit.value := srow_x[1]; srow_x2Edit.value := srow_x[2]; srow_x3Edit.value := srow_x[3]; srow_y0Edit.value := srow_y[0]; srow_y1Edit.value := srow_y[1]; srow_y2Edit.value := srow_y[2]; srow_y3Edit.value := srow_y[3]; srow_z0Edit.value := srow_z[0]; srow_z1Edit.value := srow_z[1]; srow_z2Edit.value := srow_z[2]; srow_z3Edit.value := srow_z[3]; //Finally... check values HeaderMagicDropSelect(nil); //disable or enable offset based on image format end; //with lHdr end; procedure ApplySaveDlgFilter (lSaveDlg: TSaveDialog); var lLen,lPos,lPipes,lPipesReq: integer; lExt: string; begin lPipesReq := (lSaveDlg.FilterIndex * 2)-1; if lPipesReq < 1 then exit; lLen := length(lSaveDlg.Filter); lPos := 1; lPipes := 0; while (lPos < lLen) and (lPipes < lPipesReq) do begin if lSaveDlg.Filter[lPos] = '|' then inc(lPipes); inc(lPos); end; if (lPos >= lLen) or (lPipes < lPipesReq) then exit; lExt := ''; while (lPos <= lLen) and (lSaveDlg.Filter[lPos] <> '|') do begin if lSaveDlg.Filter[lPos] <> '*' then lExt := lExt + lSaveDlg.Filter[lPos]; inc(lPos); end; if lExt <> '' then lSaveDlg.Filename := ChangeFileExt(lSaveDlg.Filename,lExt); end; procedure THdrForm.SaveHdrDlgClose(Sender: TObject); begin ApplySaveDlgFilter(SaveHdrDlg); end; procedure THdrForm.FormShow(Sender: TObject); begin // ImgForm.OnLaunch; end; procedure THdrForm.ReadHdrDimensionsOnly (var lHdr: TMRIcroHdr); //reads only size dimensions: useful for computing estimated filesize var lInc: Integer; begin with lHdr.NIFTIhdr do begin dim[1] := round(XDim.Value); dim[2] := round(YDim.Value); dim[3] := round(ZDim.Value); dim[4] := round(TDim.Value); dim[5] := round(Dim5Edit.value); dim[6] := round(Dim6Edit.value); dim[7] := round(Dim7Edit.value); //Next: compute Dim[0]: compute number of dimensions by finding largest dimension with at least two samples lInc := 7; while dim[lInc] < 2 do dec(lInc); Dim[0] := lInc; //comp //showmessage(inttostr(Dim[0])); vox_offset := OffsetEdit.value; DataType := DropItem2DataType(FTypeDrop.ItemIndex); bitpix := DataType2BitsPerVoxel(DataType); if Endian.ItemIndex = 0 then lHdr.DiskDataNativeEndian := true else lHdr.DiskDataNativeEndian := false; end; //with NIfTIhdr end; //proc ReadHdrDimensionsOnly procedure THdrForm.ReadHdrForm (var lHdr: TMRIcroHdr); //read the values the user has entered var lInc: Integer; begin NIFTIhdr_ClearHdr(lHdr); //important: reset values like first 4 bytes = 348 ReadHdrDimensionsOnly(lHdr); //StatusBar1.Panels[0].text := 'ImageData (bytes)= '+inttostr(ComputeImageDataBytes(lHdr)); with lHdr.NIFTIhdr do begin pixdim[1] := Xmm.Value; pixdim[2] := Ymm.Value; pixdim[3] := Zmm.Value; pixdim[4] := TSec.Value; pixdim[5] := PixDim5.Value; pixdim[6] := PixDim6.Value; pixdim[7] := PixDim7.Value; scl_slope := Scale.value; scl_inter := Intercept.value; if HeaderMagicDrop.ItemIndex = 2 then Magic := kNIFTI_MAGIC_EMBEDDED_HDR else if HeaderMagicDrop.ItemIndex = 1 then Magic := kNIFTI_MAGIC_SEPARATE_HDR else Magic := 0; //not saed as NIFTI for lInc := 1 to 80 do descrip[lInc] := chr(0); for lInc := 1 to length(CommentEdit.text) do descrip[lInc] := CommentEdit.text[lInc]; for lInc := 1 to 10 do data_type[lInc] := chr(0); for lInc := 1 to length(data_typeEdit.text) do data_type[lInc] := data_typeEdit.text[lInc]; for lInc := 1 to 18 do db_name[lInc] := chr(0); for lInc := 1 to length(db_.text) do db_name[lInc] := db_.text[lInc]; for lInc := 1 to 24 do aux_file[lInc] := chr(0); for lInc := 1 to length(aux.text) do aux_file[lInc] := aux.text[lInc]; for lInc := 1 to 16 do intent_name[lInc] := chr(0); for lInc := 1 to length(intent_nameEdit.text) do intent_name[lInc] := intent_nameEdit.text[lInc]; xyzt_units := xyzt_sizeDrop.ItemIndex; xyzt_units := xyzt_units+ (DropItem2time_units(xyzt_timeDrop.ItemIndex)); lInc := IntentCodeDrop.ItemIndex; if (lInc > 0) and (lInc < kNIFTI_LAST_STATCODE) then lInc := lInc + 1 //intent_codes start from 2 not 1 else if (lInc >= kNIFTI_LAST_STATCODE) then //add gap in numbers between last stat code and misc codes lInc := (lInc - kNIFTI_LAST_STATCODE)+kNIFTI_FIRST_NONSTATCODE else lInc := 0; //unknown intent_code := lInc; intent_p1 := intent_p1Edit.value; intent_p2 := intent_p2Edit.value; intent_p3 := intent_p3Edit.value; extents:= round(ext.value); session_error := round(ses.value); regular := chr(round(reg.value)); dim_Info := FreqDimDrop.ItemIndex+(PhaseDimDrop.ItemIndex shl 2)+(SliceDimDrop.ItemIndex shl 4); slice_start := round(slice_startEdit.value); slice_end := round(slice_endEdit.value); slice_code := SliceCodeDrop.ItemIndex; Slice_duration := (Slice_DurationEdit.value); toffset := (toffsetEdit.value); cal_max := cmax.value; cal_min := cmin.value; glmax := round(gmax.value); glmin := round(gmin.value); //Next: 3D orientation rotations pixdim[0] := QFacEdit.value; qform_code := QFormDrop.ItemIndex; quatern_b := quatern_bEdit.value; quatern_c := quatern_cEdit.value; quatern_d := quatern_dEdit.value; qoffset_x := qoffset_xEdit.value; qoffset_y := qoffset_yEdit.value; qoffset_z := qoffset_zEdit.value; sform_code := SFormDrop.ItemIndex; srow_x[0] := srow_x0Edit.value;//12 affine matrix values srow_x[1] := srow_x1Edit.value; srow_x[2] := srow_x2Edit.value; srow_x[3] := srow_x3Edit.value; srow_y[0] := srow_y0Edit.value; srow_y[1] := srow_y1Edit.value; srow_y[2] := srow_y2Edit.value; srow_y[3] := srow_y3Edit.value; srow_z[0] := srow_z0Edit.value; srow_z[1] := srow_z1Edit.value; srow_z[2] := srow_z2Edit.value; srow_z[3] := srow_z3Edit.value; end; //with lHdr //zero_intercept := intercept.value; end; procedure THdrForm.About1Click(Sender: TObject); begin Showmessage('Chris Rorden''s NIfTI header viewer release 1/1/2006.'); end; function THdrForm.OpenAndDisplayHdr (var lFilename: string; var lHdr: TMRIcroHdr): boolean; var lFileDir: string; begin FreeImgMemory(lHdr); result := false; NIFTIhdr_ClearHdr(lHdr); if not NIFTIhdr_LoadHdr(lFilename, lHdr) then exit; WriteHdrForm (lHdr); lFileDir := extractfiledir(lFilename); if lFileDir <> gTemplateDir then OpenHdrDlg.InitialDir := lFileDir; SaveHdrDlg.InitialDir := lFileDir; //999 ImgForm.SaveDialog1.InitialDir := lFileDir; SaveHdrDlg.FileName := lFilename; //make this default file to write StatusBar1.Panels[1].text := lFilename; StatusBar1.Panels[0].text := 'Img= '+inttostr(ComputeImageDataBytes(lHdr)); result := true; end; procedure THdrForm.Open1Click(Sender: TObject); var lHdr: TMRIcroHdr; lFilename: string; begin //NIfTI (*.hdr;*.nii)|*.hdr; *.nii; *.nii.gz|NIfTI separate header (*.hdr)|*.hdr|NIfTI embedded header|*.nii|NIfTI compressed|*.nii.gz //if not OpenHdrDlg.Execute then exit; if not OpenDialogExecute(kImgFilter,'Select header',false) then exit; lFilename := OpenHdrDlg.Filename; OpenAndDisplayHdr(lFilename,lHdr); end; procedure THdrForm.Save1Click(Sender: TObject); var lHdr: TMRIcroHdr; lFilename: string; begin NIFTIhdr_ClearHdr(lHdr); if not SaveHdrDlg.Execute then exit; lFilename := SaveHdrDlg.Filename; OpenHdrDlg.InitialDir := extractfiledir(lFilename); //999 ImgForm.SaveDialog1.InitialDir := extractfiledir(lFilename); ReadHdrForm (lHdr); if not NIFTIhdr_SaveHdr (lFilename, lHdr,true) then exit; OpenHdrDlg.FileName := lFilename; //make this default file to open StatusBar1.Panels[1].text := 'wrote: '+lFilename; end; procedure THdrForm.TabMenuClick(Sender: TObject); begin PageControl1.ActivePage := PageControl1.Pages[(Sender as TMenuItem).Tag]; end; procedure THdrForm.Exit1Click(Sender: TObject); //Quit the program or form begin Close; end; {$IFNDEF FPC} procedure THdrForm.WMDropFiles(var Msg: TWMDropFiles); //implement drag and drop //NOTE: requires 'ShellAPI' in uses clause var lHdr: TMRIcroHdr; CFileName: array[0..MAX_PATH] of Char; lFilename: string; begin try if DragQueryFile(Msg.Drop, 0, CFileName, MAX_PATH) > 0 then begin lFilename := CFilename; OpenAndDisplayHdr(lFileName, lHdr); Msg.Result := 0; end; finally DragFinish(Msg.Drop); end; end; {$ENDIF} procedure THdrForm.FormCreate(Sender: TObject); var lHdr: TMRIcroHdr; begin //DecimalSeparator := '.'; //important for reading DICOM data: e.g. Germans write '12,00' but DICOM is '12.00' {$IFNDEF Unix} DragAcceptFiles(Handle, True); //engage drag and drop {$ENDIF} NIFTIhdr_ClearHdr(lHdr); HdrForm.WriteHdrForm (lHdr); //show default header {$IFDEF Darwin} {$IFNDEF LCLgtk} //only for Carbon compile Open1.ShortCut := ShortCut(Word('O'), [ssMeta]); Save1.ShortCut := ShortCut(Word('S'), [ssMeta]); Exit1.ShortCut := ShortCut(Word('W'), [ssMeta]); Dimensions1.ShortCut := ShortCut(Word('A'), [ssMeta]); Rotations1.ShortCut := ShortCut(Word('B'), [ssMeta]); ImageIntensity1.ShortCut := ShortCut(Word('I'), [ssMeta]); Statistics1.ShortCut := ShortCut(Word('D'), [ssMeta]); FunctionalMRI1.ShortCut := ShortCut(Word('E'), [ssMeta]); Optional1.ShortCut := ShortCut(Word('F'), [ssMeta]); {$ENDIF} {$ENDIF} end; procedure THdrForm.ImageSzChange(Sender: TObject); //report size of image data var lHdr: TMRIcroHdr; begin NIFTIhdr_ClearHdr(lHdr); //important: reset values like first 4 bytes = 348 ReadHdrDimensionsOnly(lHdr); StatusBar1.Panels[0].text := 'Img= '+inttostr(ComputeImageDataBytes(lHdr)); end; procedure THdrForm.HeaderMagicDropSelect(Sender: TObject); var lHdrIndex: integer; begin lHdrIndex := HeaderMagicDrop.ItemIndex; //0=unkown, 1=nifti hdr+img, 2=nifti .nii embedded if lHdrIndex = 1 then begin//nifti hdr+img, offset must be = 0 OffsetEdit.MinValue := 0; OffsetEdit.Enabled := false; OffsetEdit.value := 0; end else if lHdrIndex = 2 then begin//embedded header, offset must be at least 348 OffsetEdit.Enabled := true; if OffsetEdit.value < sizeof(TNIFTIHdr) then OffsetEdit.value := sizeof(TNIFTIHdr); OffsetEdit.MinValue := sizeof(TNIFTIHdr); end else begin //no embedded header... therefore offset can be zero OffsetEdit.MinValue := 0; OffsetEdit.Enabled := true; if OffsetEdit.value = sizeof(TNIFTIHdr) then OffsetEdit.value := 0; end; end; {$IFDEF FPC} initialization {$I nifti_hdr_view.lrs} {$ENDIF} end. ������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/cutout.pas���������������������������������������������������������0000755�0001750�0001750�00000013012�11450447356�016241� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit cutout; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls, Spin; const kMaxFrac = 1000;//e.g. if 100 then cutouts are done by percent, if 1000 then 0.001 type { TCutoutForm } TCutoutForm = class(TForm) CutoutBiasDrop: TComboBox; CutoutLUTDrop: TComboBox; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; PreviewBtn: TButton; DefBtn: TButton; OKBtn: TButton; CutoutBox: TGroupBox; PreviewBtn1: TButton; RenderCutoutCheck: TCheckBox; XLo: TSpinEdit; XHi: TSpinEdit; YLo: TSpinEdit; YHi: TSpinEdit; ZLo: TSpinEdit; ZHi: TSpinEdit; procedure Prep; procedure DefBtnClick(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormShow(Sender: TObject); procedure OKBtnClick(Sender: TObject); procedure PreviewBtn1Click(Sender: TObject); procedure PreviewClick(Sender: TObject); procedure RenderCutoutCheckClick(Sender: TObject); private { private declarations } public { public declarations } end; var CutoutForm: TCutoutForm; implementation {$DEFINE REND} //if you define "REND" render form will be interactively adjusted uses render_composite{grender}, nifti_img_view {LUTdrop},define_types {sortcutout} {$IFDEF REND}, render {$ENDIF}{azimuth,elevation,timer} ; var gInit: boolean = false; { TCutoutForm } procedure TCutoutForm.Prep; begin gInit := true; CutoutForm.caption := 'Cutouts: '+inttostr(kMaxFrac)+'= 100%'; cutoutlutdrop.Items := ImgForm.LUTdrop.items; if (gRender.cutoutLUTindex < 1) or (gRender.cutoutLUTindex > cutoutlutdrop.Items.Count) then cutoutlutdrop.itemindex := 0 else cutoutlutdrop.itemindex := gRender.cutoutLUTindex; if gRender.CutoutFrac.Lo[1] < 0 then SliceToFrac(gBGImg); SortCutout(gRender.CutoutFrac); Xlo.maxValue := kMaxFrac;//gBGImg.ScrnDim[1]; Xhi.maxValue := kMaxFrac;//gBGImg.ScrnDim[1]; Ylo.maxValue := kMaxFrac;//gBGImg.ScrnDim[2]; Yhi.maxValue := kMaxFrac;//gBGImg.ScrnDim[2]; Zlo.maxValue := kMaxFrac;//gBGImg.ScrnDim[3]; Zhi.maxValue := kMaxFrac;//gBGImg.ScrnDim[3]; Xlo.Value := gRender.CutoutFrac.Lo[1]; Xhi.Value := gRender.CutoutFrac.Hi[1]; Ylo.Value := gRender.CutoutFrac.Lo[2]; Yhi.Value := gRender.CutoutFrac.Hi[2]; Zlo.Value := gRender.CutoutFrac.Lo[3]; Zhi.Value := gRender.CutoutFrac.Hi[3]; //OverlayClipEdit.value := gRender.OverlayNearClipFrac; //BGClipEdit.value := gRender.BGNearClipFrac; RenderCutoutCheck.checked := gRender.ShowCutout; CutoutBiasDrop.ItemIndex:=( gRender.CutoutBias); RenderCutoutCheckClick(nil); gInit := false; end; procedure ReadCutoutForm; begin with CutoutForm do begin gRender.CutoutFrac.Lo[1] := round(Xlo.Value); gRender.CutoutFrac.Hi[1] := round(Xhi.Value); gRender.CutoutFrac.Lo[2] := round(Ylo.Value); gRender.CutoutFrac.Hi[2] := round(Yhi.Value); gRender.CutoutFrac.Lo[3] := round(Zlo.Value); gRender.CutoutFrac.Hi[3] := round(Zhi.Value); SortCutout(gRender.CutoutFrac); gRender.ShowCutout := RenderCutoutCheck.checked; gRender.CutoutBias := CutoutBiasDrop.ItemIndex; gRender.cutoutLUTindex := cutoutlutdrop.itemindex; //gRender.OverlayNearClipFrac := round(OverlayClipEdit.value); // gRender.BGNearClipFrac := round(BGClipEdit.value); end; end; procedure TCutoutForm.RenderCutoutCheckClick(Sender: TObject); begin CutoutBox.visible := RenderCutoutCheck.Checked; PreviewClick(nil); end; procedure TCutoutForm.PreviewClick(Sender: TObject); begin if gInit then exit; ReadCutoutForm; {$IFDEF REND} gZoom := 0.5; RenderForm.RenderRefreshTimer.Tag := -1; //force a new rotation matrix to be generated RenderForm.RenderRefreshTimer.enabled := true; {$ENDIF} end; procedure TCutoutForm.DefBtnClick(Sender: TObject); begin gInit := true; Ylo.Value := kMaxFrac shr 1; Yhi.Value := kMaxFrac ; Zlo.Value := kMaxFrac shr 1; Zhi.Value := kMaxFrac ; //OverlayClipEdit.value := 0; //BGClipEdit.value := 0; RenderCutoutCheck.checked := true; CutoutLUTdrop.ItemIndex := 0; CutoutBiasDrop.ItemIndex:= 3; {$IFDEF REND} if renderForm.FlipLRcheck.checked then begin Xlo.Value := 0; Xhi.Value := kMaxFrac shr 1; end else begin Xlo.Value := kMaxFrac shr 1; Xhi.Value := kMaxFrac ; end; RenderForm.AzimuthEdit.value := 120; RenderForm.ElevationEdit.value := 45; {$ELSE} Xlo.Value := 0; Xhi.Value := kMaxFrac shr 1; {$ENDIF} gInit := false; RenderCutoutCheckClick(nil);//PreviewClick(nil); end; procedure TCutoutForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin ReadCutoutForm; //note: exit if no changes {$IFDEF REND} RenderForm.RenderRefreshTimer.Tag := -1; //force a new rotation matrix to be generated RenderForm.RenderRefreshTimer.enabled := true; {$ENDIF} end; procedure TCutoutForm.FormShow(Sender: TObject); begin Prep; end; procedure TCutoutForm.OKBtnClick(Sender: TObject); begin CutoutForm.close; end; procedure TCutoutForm.PreviewBtn1Click(Sender: TObject); begin ReadCutoutForm; RenderForm.RenderRefreshTimer.Tag := -1; //force a new rotation matrix to be generated RenderForm.RenderRefreshTimer.enabled := true; end; initialization {$I cutout.lrs} end. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/Readme.txt���������������������������������������������������������0000755�0001750�0001750�00000005735�11424072604�016153� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������This is a beta release of MRIcron. You can compile this using Lazarus. It has been compiled on Windows, Linux-x86, OSX-x86 and OSX-PPC. It requires builds of Lazarus and FreePascal created after October 7, 2007. http://www.hu.freepascal.org/lazarus/ ------------------------------------------- To compile for OSX [Carbon] - 1.) Launch Lazarus and open the project. 2.) Select Project/CompilerOptions Paths tab: make sure the "LCL widget type" is set to "carbon" Linking tab: make sure the "Pass options to linker" checkbox is selected and set the text to "-framework carbon" (no quotes). 3.) Select Project/ProjectOptions and set "Use application bundle for running and debugging" 4.) If using OSX 10.5 or later, add to Project / Compiler options / Other / Custom options: -k-macosx_version_min -k10.4 -XR/Developer/SDKs/MacOSX10.4u.sdk/ Alternative: Project/ProjectOptions/Linking/ Check 'pass options to linker' and add this line -macosx_version_min 10.4 5.) For debugging, you will want to create an alias from the application folder to the compiled executable: The exact value will depend on your paths, but it will be similar to this: rm ~/Documents/mricron/mricron.app/mricron ln -s ~/Documents/mricron/mricron ~/Documents/mricron/mricron.app/mricron rm ~/Documents/mricron/npm/npm.app/npm ln -s ~/Documents/mricron/npm/npm ~/Documents/mricron/npm/npm.app/npm rm ~/Documents/mricron/dcm2nii/dcm2niigui.app/dcm2niigui ln -s ~/Documents/mricron/dcm2nii/dcm2niigui ~/Documents/mricron/dcm2nii/dcm2niigui.app/dcm2niigui 6.) Select Run/Run to build and execute your program 7.) For making an executable to distribute, control+click on the program's .app folder (e.g. the file named mricron that has a brain icon) and choose "show package contents" - move the executable generated with Lazarus into the folder, overwriting the symbolic link created in step 4. ------------------------------------------- To compile for Linux GTK1 - 1.) Launch Lazarus and open the project. 2.) Select Project/CompilerOptions Paths tab: make sure the "LCL widget type" is set to "default [gtk]" Linking tab: make sure the "Pass options to linker" checkbox is UNCHECKED. 3.) Choose Run/Run to build and execute the program ------------------------------------------- To compile for Linux GTK2 - 1.) Launch Lazarus and open the project. 2.) Select Project/CompilerOptions Paths tab: make sure the "LCL widget type" is set to "gtk2" Linking tab: make sure the "Pass options to linker" checkbox is UNCHECKED. 3.) Choose Run/Run to build and execute the program ------------------------------------------- To compile for Windows - 1.) Launch Lazarus and open the project. 2.) Select Project/CompilerOptions Paths tab: make sure the "LCL widget type" is set to "default [Win API]" Linking tab: make sure the "Pass options to linker" checkbox is UNCHECKED. 3.) Choose Run/Run to build and execute the program �����������������������������������mricron-0.20140804.1~dfsg.1.orig/cropedges.lfm������������������������������������������������������0000755�0001750�0001750�00000004313�12151704170�016655� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������object CropEdgeForm: TCropEdgeForm Left = 562 Height = 142 Top = 209 Width = 398 ActiveControl = DEdit BorderIcons = [biSystemMenu] BorderStyle = bsDialog Caption = 'Crop Edges' ClientHeight = 142 ClientWidth = 398 Constraints.MaxHeight = 321 Constraints.MaxWidth = 398 Constraints.MinHeight = 12 Constraints.MinWidth = 398 OnCreate = FormCreate OnHide = FormHide OnShow = FormShow Position = poScreenCenter LCLVersion = '1.0.2.0' object CancelBtn: TSpeedButton Left = 320 Height = 25 Top = 104 Width = 65 Caption = 'Cancel' NumGlyphs = 0 OnClick = CancelBtnClick end object ApplyBtn: TSpeedButton Left = 256 Height = 25 Top = 104 Width = 65 Caption = 'Apply' NumGlyphs = 0 OnClick = ApplyBtnClick end object CropFileSzBtn: TSpeedButton Left = 136 Height = 25 Top = 104 Width = 105 Caption = 'Save Cropped' NumGlyphs = 0 OnClick = CropFileSzBtnClick end object DEdit: TSpinEdit Left = 57 Height = 21 Top = 8 Width = 72 MaxValue = 255 OnChange = CropEditChange TabOrder = 0 Value = 8 end object PEdit: TSpinEdit Left = 8 Height = 21 Top = 41 Width = 72 MaxValue = 255 OnChange = CropEditChange TabOrder = 1 Value = 8 end object AEdit: TSpinEdit Left = 104 Height = 21 Top = 41 Width = 72 MaxValue = 255 OnChange = CropEditChange TabOrder = 2 Value = 8 end object VEdit: TSpinEdit Left = 57 Height = 21 Top = 73 Width = 72 MaxValue = 255 OnChange = CropEditChange TabOrder = 3 Value = 8 end object REdit: TSpinEdit Left = 311 Height = 21 Top = 41 Width = 72 MaxValue = 255 OnChange = CropEditChange TabOrder = 4 Value = 8 end object LEdit: TSpinEdit Left = 224 Height = 21 Top = 41 Width = 72 MaxValue = 255 OnChange = CropEditChange TabOrder = 5 Value = 8 end object Timer1: TTimer Enabled = False Interval = 150 OnTimer = Timer1Timer left = 328 top = 72 end end ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_dcm2nii.bat�������������������������������������������������������0000755�0001750�0001750�00000000376�12156077726�016402� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������chmod 777 ./_xclean.bat ./_xclean.bat cp ./common/notgui.inc ./common/isgui.inc lazbuild ./dcm2nii/dcm2nii.lpr --cpu=x86_64 --compiler="/usr/local/bin/ppcx64" mv ./dcm2nii/dcm2nii ../distro/dcm2nii64 ./_xclean.bat cp ./common/gui.inc ./common/isgui.inc ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/batchstatselect.pas������������������������������������������������0000755�0001750�0001750�00000004671�11425650330�020074� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit batchstatselect; {$H+} interface uses Classes, SysUtils,StrUtils, define_types, Dialogs; procedure GetFilesInDir (lDefaultFolder: string; var lFilenames: TStrings); implementation function IsStatHdr(lStr: string): boolean; //detects 'spmT_000*.hdr and zstat*.nii.gz //requires StrUtils var lExt: string; begin result := false; if not IsExtNIFTIHdr(lStr) then exit; if AnsiContainsText(lStr, 'spmT_') or AnsiContainsText(lStr, pathdelim+'zstat') then result := true; end; procedure FindNIIhdrRecursive (var lFolderNameIn: string; var lStringList : TStrings); var len: integer; lFolderName,lNewDir,lNewName,lExt: String; lSearchRec: TSearchRec; begin lFolderName := lFolderNameIn; if not DirExists (lFolderName) then begin lFolderName := ExtractFileDir(lFolderName); end; if (length(lFolderName) > 1) and (lFolderName[length(lFolderName)] <> PathDelim) then lNewDir := lFolderName+PathDelim; if DirExists (lNewDir) then begin {$IFDEF UNIX} if FindFirst(lNewDir+'*',faAnyFile-faSysFile,lSearchRec) = 0 then begin {$ELSE} if FindFirst(lNewDir+'*.*',faAnyFile-faSysFile,lSearchRec) = 0 then begin {$ENDIF} repeat lNewName := lNewDir+lSearchRec.Name; if (lSearchRec.Name = '.') or (lSearchRec.Name = '..') then //current or parent folder - do nothing else if DirExists(lNewName) then FindNIIhdrRecursive (lNewName, lStringList) else if IsStatHdr(lNewName) then lStringList.Add(lNewName); until (FindNext(lSearchRec) <> 0); end; //if findfirst FindClose(lSearchRec); end;//Direxists end; procedure FilterForText (lRequiredText: string; var lFilenames: TStrings); var i,len: integer; begin len := lFilenames.Count; if (length(lRequiredText) < 1) or (len < 1) then exit; for i := len-1 downto 0 do if not AnsiContainsText(lFilenames[i], lRequiredText) then lFilenames.Delete(i); end; procedure GetFilesInDir (lDefaultFolder: string; var lFilenames: TStrings); var lParentDir,lFilter : string; begin lParentDir := GetDirPrompt (lDefaultFolder); FindNIIhdrRecursive(lParentDir,lFilenames); lFilter := '.gfeat'; InputQuery('Filter data', 'Filter for statistical maps [e.g. ''.gfeat'' will only analyze files with this in their path. Set to blank to analyze all files',lFilter); FilterForText(lFilter,lFilenames); end; end. �����������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_delphizip.bat�����������������������������������������������������0000755�0001750�0001750�00000000512�12153677324�017032� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������REM COMPILE MRIcron call _delphi.bat REM compress MRIcron c:\Progra~1\7-Zip\7z a -tzip c:\pas\wincron.zip c:\mricron copy /Y c:\pas\wincron.zip Y:\mcbi\MCBI\CRNL\sw\mricron\win.zip REM compress Source c:\Progra~1\7-Zip\7z a -tzip c:\pas\srccron.zip c:\pas\mricron copy c:\pas\srccron.zip Y:\mcbi\MCBI\CRNL\sw\mricron\source.zip��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/CarbonOpenDoc.pas��������������������������������������������������0000755�0001750�0001750�00000004335�11372364210�017370� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit CarbonOpenDoc; interface {$H+} uses //FPCMacOSAll, MacOSAll, CarbonProc; //type // TFormOpenFileMethod = procedure(const FileName : string) of object; //procedure InitOpenDocHandler(MethodToUse : TFormOpenFileMethod); procedure InitOpenDocHandler; implementation uses nifti_img_view; //var // OpenFileMethod : TFormOpenFileMethod; function OpenDocEventHandler(var theAppleEvent: AppleEvent; var reply: AppleEvent; handlerRefcon: SInt32): OSErr; stdcall; var DocList: AEDescList; FileCount: Integer; FileIdx: Integer; Keyword: AEKeyword; FileDesc: AEDesc; FileRef: FSRef; FileURL: CFURLRef; FileCFStr: CFStringRef; begin if OSError(AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, DocList), 'OpenDocEventHandler', '', 'AEGetParamDesc') then Exit; try if OSError(AECountItems(DocList, FileCount), 'OpenDocEventHandler', '', 'AECountItems') then Exit; for FileIdx := 1 to FileCount do begin if OSError(AEGetNthDesc(DocList, FileIdx, typeFSRef, @Keyword, FileDesc), 'OpenDocEventHandler', '', 'AEGetNthDesc') then Exit; if OSError(AEGetDescData(FileDesc, @FileRef, SizeOf(FSRef)), 'OpenDocEventHandler', '', 'AEGetDescData') then Exit; if OSError(AEDisposeDesc(FileDesc), 'OpenDocEventHandler', '', 'AEDisposeDesc') then Exit; FileURL := CFURLCreateFromFSRef(kCFAllocatorDefault, FileRef); FileCFStr := CFURLCopyFileSystemPath(FileURL, kCFURLPOSIXPathStyle); ImgForm.FormOpenFileMethod(CFStringToStr(FileCFStr)); //ImgForm.OpenFileMethod(CFStringToStr(FileCFStr)); FreeCFString(FileURL); FreeCFString(FileCFStr); end; finally AEDisposeDesc(DocList); end; end; {OpenDocEventHandler} procedure InitOpenDocHandler {(MethodToUse : TFormOpenFileMethod)}; begin //OpenFileMethod := MethodToUse; AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerUPP( AEEventHandlerProcPtr(Pointer(@OpenDocEventHandler))), 0, False); end; {InitOpenDocHandler} end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/statclustertable.pas�����������������������������������������������0000755�0001750�0001750�00000023743�12306665226�020316� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit statclustertable; //USED by stats to select only regions with a given number of connected/contiguous voxels interface {$H+} uses define_types,dialogs,SysUtils,nifti_hdr,nifti_img, classes; //procedure FindClustersText (var lHdr: TMRIcroHdr; lThreshClusterSz: integer; lThresh: double); procedure BatchCluster; implementation uses text,nifti_img_view, nifti_hdr_view, readfloat, readint; procedure FindClustersText (var lHdr: TMRIcroHdr; lThreshIn: single; lMinClusterSz: integer); var lClusterMaxPos,lXdim,lYdim,lZdim,lScaledThresh,lClusterSz,lClusterFillVal,lQTail,lQHead,lSliceSz,lQSz,lInc,lVolSz: integer; lThresh,lClusterMax: single; lClusterBuffS: SingleP; lQra: LongIntP; lXcom,lYcom,lZcom,lBuffIn32 : SingleP; lBuffIn16 : SmallIntP; lCh: char; procedure InitCenterOfMass; begin getmem(lXcom, lXDim*sizeof(single)); getmem(lYcom, lYDim*sizeof(single)); getmem(lZcom, lZDim*sizeof(single)); end; procedure FreeCenterOfMass; begin freemem(lXcom); freemem(lYcom); freemem(lZcom); end; procedure ClearCenterOfMass; var i: integer; begin for i := 1 to lXDim do lXcom^[i] := 0; for i := 1 to lYDim do lYcom^[i] := 0; for i := 1 to lZDim do lZcom^[i] := 0; end; procedure AddCenterOfMass (lVox: integer; lInten: single); var lXi,lYi,lZi: integer; begin //lukas ImgPosToSlices(lVox,lXi,lYi,lZi); lXcom^[lXi] := lXcom^[lXi] + lInten; lYcom^[lYi] := lYcom^[lYi] + lInten; lZcom^[lZi] := lZcom^[lZi] + lInten; end; function CenterOfMassPosition: integer; var i : integer; lSum,lXs,lYs,lZs: double; begin lSum := 0; lXs := 0; for i := 1 to lXDim do lSum := lSum +lXcom^[i]; for i := 1 to lXDim do lXs := lXs +(i*lXcom^[i]); if lSum > 0 then lXs := lXs/lSum; // lSum := 0; lYs := 0; for i := 1 to lYDim do lSum := lSum +lYcom^[i]; for i := 1 to lYDim do lYs := lYs +(i*lYcom^[i]); if lSum > 0 then lYs := lYs/lSum; //Z lSum := 0; lZs := 0; for i := 1 to lZDim do lSum := lSum +lZcom^[i]; for i := 1 to lZDim do lZs := lZs +(i*lZcom^[i]); if lSum > 0 then lZs := lzs/lSum; result := SlicesToImgPos(round(lXs),round(lYs),round(lZs)); //fx(result, lXs,lYs,lZs); end; function XYZstr (lPos: integer): string; var lXmm,lYmm,lZmm: single; begin ImgPosToMM(lPos, lXmm,lYmm,lZmm); result := inttostr(round(lXmm))+kTextSep+inttostr(round(lYmm))+kTextSep+inttostr(round(lZmm)); end; procedure Report (lClusterMax: single; lClusterSz, lClusterMaxPos: integer); var lTemplateLabel: string; begin if lClusterSz < lMinClusterSz then exit; //lTemplateLabel := ImgForm.BGLabelString(lClusterMaxPos); //burger ImgIntensityString lTemplateLabel := ImgForm.ImgIntensityString(gMRIcroOverlay[2], lClusterMaxPos); TextForm.MemoT.lines.add(XYZstr(lClusterMaxPos)+kTextSep+XYZstr(CenterOfMassPosition)+kTextSep+inttostr(lClusterSz)+kTextSep+lCh+floattostr(lClusterMax)+kTextSep+lTemplateLabel); end; procedure ReportLabel; begin TextForm.MemoT.lines.add('# Data='+kTextSep+lHdr.HdrFileName +kTextSep+'Threshold='+kTextSep+floattostr(lThreshIn) +kTextSep+'MinCluster='+kTextSep+inttostr(lMinClusterSz)); TextForm.MemoT.lines.add('#X'+kTextSep+'Y'+kTextSep+'Z'+kTextSep+'Xcom'+kTextSep+'Ycom'+kTextSep+'Zcom'+kTextSep+'ClusterSize[Vox]'+kTextSep+'Max'+kTextSep+'Template'); end; Procedure IncQra(var lVal, lQSz: integer); begin inc(lVal); if lVal >= lQSz then lVal := 1; end; procedure Check(lPixel: integer); var lVal: single; begin lVal := lClusterBuffS^[lPixel]; if (lVal= 0) then exit; AddCenterOfMass(lPixel,lVal); if lVal > lClusterMax then begin lClusterMax := lVal; lClusterMaxPos := lPixel; end; incQra(lQHead,lQSz); inc(lClusterSz); lClusterBuffS^[lPixel] := 0; lQra^[lQHead] := lPixel; end; PROCEDURE RetirePixel; //FIFO cleanup , 1410: added 18-voxel check VAR lVal,lValX,lXPos,lYPos,lZPos: integer; BEGIN lVal := lQra^[lQTail]; if lVal = 0 then begin incQra(lQTail,lQSz); //done with this pixel exit; end; lXpos := lVal mod lXdim; if lXpos = 0 then lXPos := lXdim; lYpos := (1+((lVal-1) div lXdim)) mod lYDim; if lYPos = 0 then lYPos := lYdim; lZpos := ((lVal-1) div lSliceSz)+1; if (lXPos <= 1) or (lXPos >= lXDim) or (lYPos <= 1) or (lYPos >= lYDim) or (lZPos <= 1) or (lZPos >= lZDim) then // retire and exiT else begin //lXDimM := lXDim; Check(lVal-1); //left Check(lVal+1); //right Check(lVal-lXDim); //up Check(lVal+lXDim); //down Check(lVal-lSliceSz); //up Check(lVal+lSliceSz); //down //check plane above lValX := lVal + lSLiceSz; Check(lValX-1); //left Check(lValX+1); //right Check(lValX-lXDim); //up Check(lValX+lXDim); //down //check plane below lValX := lVal - lSLiceSz; Check(lValX-1); //left Check(lValX+1); //right Check(lValX-lXDim); //up Check(lValX+lXDim); //down //check diagonals of current plane Check(lVal-lXDim-1); //up, left Check(lVal-lXDim+1); //up, right Check(lVal+lXDim-1); //down, left Check(lVal+lXDim+1); //down, right end; //not edge incQra(lQTail,lQSz); //done with this pixel END; procedure FillStart (lPt: integer); {FIFO algorithm: keep memory VERY low} var lI: integer; begin if (lClusterBuffS^[lPt]=0) then exit; for lI := 1 to lQsz do lQra^[lI] := 0; lQHead := 0; lQTail := 1; Check(lPt); RetirePixel; // check that there was anything in the cluster at all //showmessage('head'+inttostr(lQHead)+'.'+inttostr(lQTail)); //if lQHead > 2 then begin // and do the recursion to get rid of it while ((lQHead+1) <> lQTail) do begin//complete until all voxels in buffer have been tested RetirePixel; if (lQHead = lQSz) and (lQTail = 1) then exit; //break condition: avoids possible infinite loop where QTail is being incremented but QHead is stuck at maximum value end; end; begin lCh := ' '; //assume positive values lXDim := lHdr.NIFTIhdr.dim[1]; lYDim := lHdr.NIFTIhdr.dim[2]; lZDim := lHdr.NIFTIhdr.dim[3]; InitCenterOfMass; lVolSz := lXdim*lYdim*lZdim; lSliceSz := lXdim * lYdim; if (lXDim < 4) or (lYDim < 4) or (lZDim < 4) or (lVolSz < 1) or (lHdr.ImgBufferItems <> lVolSz) then exit; GetMem(lClusterBuffS, lVolSz* sizeof(Single)); ReportLabel; if lHdr.ImgBufferBPP = 4 then begin lBuffIn32 := SingleP(lHdr.ImgBuffer); for lInc := 1 to lVolSz do lClusterBuffS^[lInc] := lBuffIn32^[lInc]; end else if lHdr.ImgBufferBPP = 2 then begin //not 32bit - if 16bit input lBuffIn16 := SmallIntP(lHdr.ImgBuffer); for lInc := 1 to lVolSz do lClusterBuffS^[lInc] := lBuffIn16^[lInc]; end else begin //not 16 or 32 bit input for lInc := 1 to lVolSz do lClusterBuffS^[lInc] := lHdr.ImgBuffer^[lInc]; end; //8-bit input //Next - apply scale and intercept if (lHdr.NIFTIhdr.scl_slope <> 0) and (lHdr.NIFTIhdr.scl_slope <> 1) then //if one then no effect - zero is meaningless for lInc := 1 to lVolSz do lClusterBuffS^[lInc] := lClusterBuffS^[lInc]*lHdr.NIFTIhdr.scl_slope; if (lHdr.NIFTIhdr.scl_inter <> 0) then //if zero then no effect for lInc := 1 to lVolSz do lClusterBuffS^[lInc] := lClusterBuffS^[lInc]+lHdr.NIFTIhdr.scl_inter; lThresh := lThreshIn; if lThreshIn < 0 then begin //invert all values... for lInc := 1 to lVolSz do lClusterBuffS^[lInc] := -lClusterBuffS^[lInc]; lThresh := -lThresh; lCh := '-'; end; //Next - zero all voxels less than threshold for lInc := 1 to lVolSz do if (lClusterBuffS^[lInc]) < lThresh then lClusterBuffS^[lInc] := 0; //Next - get memory lQSz := (lVolSz div 4)+8; GetMem(lQra,lQsz * sizeof(longint) ); //check positive clusters.... ClearCenterOfMass; for lInc := 1 to lVolSz do begin if lClusterBuffS^[lInc] <> 0 then begin lClusterSz := 0; lClusterMax := 0; FillStart(lInc); // now fill the cluster with its size (=1 if the voxel was isolated) Report (lClusterMax,lClusterSz,lClusterMaxPos); ClearCenterOfMass; end; end; FreeCenterOfMass; Freemem(lQra); Freemem(lClusterBuffS); end; procedure BatchCluster; var lInc,lNumberofFiles,lMinClusterSz: integer; lFilename,lTemplateName:string; lPref: boolean; lThresh: single; begin for lInc := 1 to (knMaxOverlay-1) do FreeImgMemory(gMRIcroOverlay[lInc]); ImgForm.UpdateLayerMenu; lMinClusterSz := ReadIntForm.GetInt('Minimum cluster size [in voxels]: ', 1,4,9999); lThresh := ReadFloatForm.GetFloat('Please enter statistical threshold. ', -9999,2.3,9999); lTemplateName := ''; if OpenDialogExecute(kImgFilter,'Select anatomical template (optional)',false) then begin lTemplateName := HdrForm.OpenHdrDlg.Filename; end; if not OpenDialogExecute(kImgFilter,'Select statistical maps',true) then exit; lNumberofFiles:= HdrForm.OpenHdrDlg.Files.Count; if lNumberofFiles < 1 then exit; if not fileexists(lTemplateName) then lTemplateName := ''; TextForm.MemoT.Lines.Clear; lPref := gBGImg.ResliceOnLoad; gBGImg.ResliceOnLoad := false; for lInc:= 1 to lNumberofFiles do begin lFilename := HdrForm.OpenHdrDlg.Files[lInc-1]; ImgForm.OpenAndDisplayImg(lFilename,false); if lTemplateName <> '' then ImgForm.OverlayOpenCore ( lTemplateName, 2); FindClustersText(gMRIcroOverlay[kBGOverlayNum], lThresh,lMinClusterSz); end;//lLoop gBGImg.ResliceOnLoad := lPref; TextForm.Show; end; end. �����������������������������mricron-0.20140804.1~dfsg.1.orig/extrafpc.cfg�������������������������������������������������������0000755�0001750�0001750�00000000130�11316122054�016465� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#IFDEF Darwin -k-macosx_version_min -k10.4 -XR/Developer/SDKs/MacOSX10.4u.sdk/ #ENDIF����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/fx8.pas������������������������������������������������������������0000755�0001750�0001750�00000053057�11326425446�015436� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������unit fx8; {$DEFINE VFLIP} {$mode objfpc}{$H+} interface uses SysUtils, define_types, Classes,dialogs{, Graphics, Controls, Forms, Dialogs,Menus,ComCtrls, ExtCtrls}; type Tfx8 = RECORD Width,Height,X,Y,PenThick: integer; Img: Bytep; end; procedure CreateFX8(var lFX8: Tfx8); procedure DefineFX8(var lFX8: Tfx8; lWid,lHt: integer); procedure DefineBuffFX8(var lFX8: Tfx8; lWid,lHt: integer; lBuff: ByteP); procedure CopyFX8(var lFX8src, lFX8dest: Tfx8); procedure RectangleFX8(var lFX8: Tfx8; lLin,lTin,lRin,lBin: integer; lClr: byte); procedure FillRectFX8(var lFX8: Tfx8; lLin,lTin,lRin,lBin: integer; lClr: byte); procedure EllipseFX8(var lFX8: Tfx8; lLin,lTin,lRin,lBin: integer; lClr: byte); procedure FillEllipseFX8(var lFX8: Tfx8; lLin,lTin,lRin,lBin: integer; lClr: byte); procedure MoveToFX8(var lFX8: Tfx8; lXin,lYin: integer); procedure LineToFX8(var lFX8: Tfx8; lXin,lYin: integer; lClr: byte); overload; procedure LineToFX8(var lFX8: Tfx8; lXin,lYin: integer; lClr, lLineThick: byte); overload; procedure FloodFillFX8 (var lFX8: Tfx8; lXin, lYin: Integer; lBoundClr,lWriteClr: byte; lfsSurface: boolean); procedure FreeFX8(var lFX8: Tfx8); implementation procedure sortLTRB(var lXoutLow,lYOutLow,lXoutHi,lYOutHi: integer); //left<right, top<bottom var lXin1,lYin1,lXin2,lYin2: integer; begin lXin1 := lXoutLow; lYin1 := lYOutLow; lXin2 := lXoutHi; lYin2 := lYOutHi; if lXIn1 < lXin2 then begin lXoutLow := lXIn1; lXOutHi := lXIn2; end else begin lXoutLow := lXIn2; lXOutHi := lXIn1; end; if lYIn1 < lYin2 then begin lYoutLow := lYIn1; lYOutHi := lYIn2; end else begin lYoutLow := lYIn2; lYOutHi := lYIn1; end; end; //sortLTRB procedure Bound(var lX,lY: integer; var lFX8: TFX8); begin if lX < 1 then lX := 1; if lX > lFX8.width then lX := lFX8.width; if lY < 1 then lY := 1; if lY > lFX8.height then lY := lFX8.height; end; procedure boundrect(var lL,lT,lR,lB: integer; var lFX8: TFX8); begin sortLTRB(lL,lT,lR,lB); bound(lL,lT,lFX8); bound(lR,lB,lFX8); end; procedure MoveToFX8(var lFX8: Tfx8; lXin,lYin: integer); var lX,lY: integer; begin {$IFDEF VFLIP} lX := lXin+1; {$IFDEF UNIX} lX := lX+1; {$ENDIF} lY := lFX8.Height- lYin; {$ELSE} lX := lXin; lY := lYin; {$ENDIF} bound(lX,lY,lFX8); lFX8.X := lX; lFX8.Y := lY; end; procedure HorLine(var lFX8: Tfx8; x1,x2,y: integer; lClr: byte); var x,lStart: integer; begin if lFX8.img = nil then exit; //not defined lStart := (y -1)* lFX8.Width; if x1 < x2 then begin for x := x1 to x2 do lFX8.Img^[lStart+x] := lClr; end else for x := x2 to x1 do lFX8.Img^[lStart+x] := lClr; end; function getpixel(var lFX8: Tfx8; x,y: integer): byte; begin result := lFX8.Img^[(Y -1)* lFX8.Width+x]; end; procedure putpixel(var lFX8: Tfx8; x,y: integer; lClr: byte); begin if (x < 1) or (y < 1) or (x > lFX8.width) or (y > lFX8.height) then exit; //putwidepixel and puttallpixel can have x < 1, x > width, etc... lFX8.Img^[(Y -1)* lFX8.Width+x] := lClr; end; procedure putwidepixel(var lFX8: Tfx8; x,y: integer; lClr, lLineThick: byte); var lBar: integer; begin putpixel(lFX8,x,y,lClr); if lLineThick < 2 then exit; for lBar := 1 to ((lLineThick-1) div 2) do begin putpixel(lFX8,x-lBar,y,lClr); putpixel(lFX8,x+lBar,y,lClr); end; end; procedure puttallpixel(var lFX8: Tfx8; x,y: integer; lClr, lLineThick: byte); var lBar: integer; begin putpixel(lFX8,x,y,lClr); if lLineThick < 2 then exit; for lBar := 1 to ((lLineThick-1) div 2) do begin putpixel(lFX8,x,y-lBar,lClr); putpixel(lFX8,x,y+lBar,lClr); end; end; procedure LineToFX8(var lFX8: Tfx8; lXin,lYin: integer; lClr, lLineThick: byte) ; overload; var lSlope: single; lX2,lY2,lX1,lY1,lP,lCol,lStart,lX,lY: integer; begin lX1 := lFX8.X; lY1 := lFX8.Y; //Bound(lX1,lY1,lFX8); {$IFDEF VFLIP} lX2 := lXin+1; {$IFDEF UNIX} lX2 := lX2+1; {$ENDIF} ; lY2 := lFX8.Height- lYin; {$ELSE} lX2 := lXin; lY2 := lYin; {$ENDIF} Bound(lX2,lY2,lFX8); lFX8.X := lX2; lFX8.Y := lY2; //next: endpoints - required if no line lFX8.Img^[(lY1 -1)* lFX8.Width+lX1] := lClr; lFX8.Img^[(lY2 -1)* lFX8.Width+lX2] := lClr; if (lX1 = lX2) and (lY1 = lY2) then exit; if abs(lY1-lY2) > abs(lX1-lX2) then begin //mostly vertical if lY1 > lY2 then begin lSlope := (lX1-lX2) /(lY1-lY2); for lY := lY2 to lY1 do putwidepixel(lFX8,lX2+round(lSlope*(lY-lY2)),lY, lClr, lLineThick); //lFX8.Img^[((lY -1)* lFX8.Width)+lX2+round(lSlope*(lY-lY2))] := lClr; end else begin lSlope := (lX2-lX1) /(lY2-lY1); for lY := lY1 to lY2 do putwidepixel(lFX8,lX1+round(lSlope*(lY-lY1)),lY, lClr, lLineThick); //lFX8.Img^[((lY -1)* lFX8.Width)+lX1+round(lSlope*(lY-lY1))] := lClr; end; end else begin //mostly horizontal - primary change in X if lX1 > lX2 then begin lSlope := (lY1-lY2) /(lX1-lX2); for lX := lX2 to lX1 do puttallpixel(lFX8,lX,lY2+round(lSlope*(lX-lX2) ) , lClr, lLineThick); //lFX8.Img^[((lY2+round(lSlope*(lX-lX2) ) -1)* lFX8.Width)+lX] := lClr; end else begin lSlope := (lY2-lY1) /(lX2-lX1); for lX := lX1 to lX2 do puttallpixel(lFX8,lX,lY1+round(lSlope*(lX-lX1) ) , lClr, lLineThick); //lFX8.Img^[((lY1+round(lSlope*(lX-lX1) ) -1)* lFX8.Width)+lX] := lClr; end; end; end; //for speed: lSingle could use integer math (*var lSlope: single; lX2,lY2,lX1,lY1,lP,lCol,lStart,lX,lY: integer; begin {$IFDEF VFLIP} lX2 := lXin+1; lY2 := lFX8.Height- lYin; {$ELSE} lX2 := lXin; lY2 := lYin; {$ENDIF} Bound(lX2,lY2,lFX8); lFX8.X := lX2; lFX8.Y := lY2; //next: endpoints - required if no line lFX8.Img^[(lY1 -1)* lFX8.Width+lX1] := lClr; lFX8.Img^[(lY2 -1)* lFX8.Width+lX2] := lClr; if (lX1 = lX2) and (lY1 = lY2) then exit; exit; if abs(lY1-lY2) > abs(lX1-lX2) then begin //mostly vertical if lY1 > lY2 then begin lSlope := (lX1-lX2) /(lY1-lY2); for lY := lY2 to lY1 do putwidepixel(lFX8,lX2+round(lSlope*(lY-lY2)),lY, lClr, lLineThick); end else begin lSlope := (lX2-lX1) /(lY2-lY1); for lY := lY1 to lY2 do putwidepixel(lFX8,lX1+round(lSlope*(lY-lY1)),lY, lClr, lLineThick); //lFX8.Img^[((lY -1)* lFX8.Width)+lX1+round(lSlope*(lY-lY1))] := lClr; end; end else begin //mostly horizontal - primary change in X if lX1 > lX2 then begin lSlope := (lY1-lY2) /(lX1-lX2); for lX := lX2 to lX1 do puttallpixel(lFX8,lX,lY2+round(lSlope*(lX-lX2) ) , lClr, lLineThick); //lFX8.Img^[((lY2+round(lSlope*(lX-lX2) ) -1)* lFX8.Width)+lX] := lClr; end else begin lSlope := (lY2-lY1) /(lX2-lX1); for lX := lX1 to lX2 do puttallpixel(lFX8,lX,lY1+round(lSlope*(lX-lX1) ) , lClr, lLineThick); //lFX8.Img^[((lY1+round(lSlope*(lX-lX1) ) -1)* lFX8.Width)+lX] := lClr; end; end; end;*) procedure LineToFX8(var lFX8: Tfx8; lXin,lYin: integer; lClr: byte); overload; //for speed: lSingle could use integer math var lSlope: single; lX2,lY2,lX1,lY1,lP,lCol,lStart,lX,lY: integer; begin if lFX8.PenThick > 2 then begin LineToFX8(lFX8,lXin,lYin, lClr,lFX8.PenThick); exit; end; lX1 := lFX8.X; lY1 := lFX8.Y; //Bound(lX1,lY1,lFX8); {$IFDEF VFLIP} lX2 := lXin+1; {$IFDEF UNIX} lX2 := lX2+1; {$ENDIF} lY2 := lFX8.Height- lYin; {$ELSE} lX2 := lXin; lY2 := lYin; {$ENDIF} Bound(lX2,lY2,lFX8); lFX8.X := lX2; lFX8.Y := lY2; //next: endpoints - required if no line lFX8.Img^[(lY1 -1)* lFX8.Width+lX1] := lClr; lFX8.Img^[(lY2 -1)* lFX8.Width+lX2] := lClr; if (lX1 = lX2) and (lY1 = lY2) then exit; if abs(lY1-lY2) > abs(lX1-lX2) then begin //mostly vertical if lY1 > lY2 then begin lSlope := (lX1-lX2) /(lY1-lY2); for lY := lY2 to lY1 do lFX8.Img^[((lY -1)* lFX8.Width)+lX2+round(lSlope*(lY-lY2))] := lClr; end else begin lSlope := (lX2-lX1) /(lY2-lY1); for lY := lY1 to lY2 do lFX8.Img^[((lY -1)* lFX8.Width)+lX1+round(lSlope*(lY-lY1))] := lClr; end; end else begin //mostly horizontal - primary change in X if lX1 > lX2 then begin lSlope := (lY1-lY2) /(lX1-lX2); for lX := lX2 to lX1 do lFX8.Img^[((lY2+round(lSlope*(lX-lX2) ) -1)* lFX8.Width)+lX] := lClr; end else begin lSlope := (lY2-lY1) /(lX2-lX1); for lX := lX1 to lX2 do lFX8.Img^[((lY1+round(lSlope*(lX-lX1) ) -1)* lFX8.Width)+lX] := lClr; end; end; end; Procedure FillEllipseDefault(var lFX8: Tfx8; X,Y: smallint;XRadius: word; YRadius:word; lClr: byte); Const ConvFac = Pi/180.0; var j, Delta, DeltaEnd: single; NumOfPixels: longint; TempTerm: single; xtemp, ytemp, xp, yp, xm, ym, xnext, ynext, plxpyp, plxmyp, plxpym, plxmym: smallint; BackupColor, TmpAngle, OldLineWidth: word; Begin If xradius = 0 then inc(xradius); if yradius = 0 then inc(yradius); { check for an ellipse with negligable x and y radius } If (xradius <= 1) and (yradius <= 1) then begin putpixel(lFX8, x,y, lClr); exit; end; { approximate the number of pixels required by using the circumference } { equation of an ellipse. } { Changed this formula a it (trial and error), but the net result is that } { less pixels have to be calculated now } NumOfPixels:=Round(Sqrt(3)*sqrt(sqr(XRadius)+sqr(YRadius))); { Calculate the angle precision required } Delta := 90.0 / NumOfPixels; { for restoring after PatternLine } { removed from inner loop to make faster } { Always just go over the first 90 degrees. Could be optimized a } { bit if StAngle and EndAngle lie in the same quadrant, left as an } { exercise for the reader :) (JM) } j := 0; { calculate stop position, go 1 further than 90 because otherwise } { 1 pixel is sometimes not drawn (JM) } DeltaEnd := 91; { Calculate points } xnext := XRadius; ynext := 0; Repeat xtemp := xnext; ytemp := ynext; { this is used by both sin and cos } TempTerm := (j+Delta)*ConvFac; { Calculate points } xnext := round(XRadius*Cos(TempTerm)); ynext := round(YRadius*Sin(TempTerm+Pi)); xp := x + xtemp; xm := x - xtemp; yp := y + ytemp; ym := y - ytemp; plxpyp := maxsmallint; plxmyp := -maxsmallint-1; plxpym := maxsmallint; plxmym := -maxsmallint-1; plxpyp := xp; PutPixel(lFX8,xp,yp,lClr); plxmyp := xm; PutPixel(lFX8,xm,yp,lClr); plxmym := xm; PutPixel(lFX8,xm,ym,lClr); plxpym := xp; PutPixel(lFX8,xp,ym,lClr); If (ynext <> ytemp) and (xp - xm >= 1) then begin //CurrentColor := FillSettings.Color; HorLine(lFX8,plxmyp+1,plxpyp-1,yp,lClr); HorLine(lFX8,plxmym+1,plxpym-1,ym,lClr); //CurrentColor := BackupColor;*) end; j:=j+Delta; Until j > (DeltaEnd); end; Procedure EllipseDefault(var lFX8: Tfx8; X,Y: smallint;XRadius: word; YRadius:word; lClr: byte); Const ConvFac = Pi/180.0; var j, Delta, DeltaEnd: single; NumOfPixels: longint; TempTerm: single; xtemp, ytemp, xp, yp, xm, ym, xnext, ynext, plxpyp, plxmyp, plxpym, plxmym: smallint; BackupColor, TmpAngle, OldLineWidth: word; Begin If xradius = 0 then inc(xradius); if yradius = 0 then inc(yradius); { check for an ellipse with negligable x and y radius } If (xradius <= 1) and (yradius <= 1) then begin putpixel(lFX8, x,y, lClr); exit; end; { approximate the number of pixels required by using the circumference } { equation of an ellipse. } { Changed this formula a it (trial and error), but the net result is that } { less pixels have to be calculated now } NumOfPixels:=Round(Sqrt(3)*sqrt(sqr(XRadius)+sqr(YRadius))); { Calculate the angle precision required } Delta := 90.0 / NumOfPixels; { for restoring after PatternLine } { removed from inner loop to make faster } { Always just go over the first 90 degrees. Could be optimized a } { bit if StAngle and EndAngle lie in the same quadrant, left as an } { exercise for the reader :) (JM) } j := 0; { calculate stop position, go 1 further than 90 because otherwise } { 1 pixel is sometimes not drawn (JM) } DeltaEnd := 91; { Calculate points } xnext := XRadius; ynext := 0; Repeat xtemp := xnext; ytemp := ynext; { this is used by both sin and cos } TempTerm := (j+Delta)*ConvFac; { Calculate points } xnext := round(XRadius*Cos(TempTerm)); ynext := round(YRadius*Sin(TempTerm+Pi)); xp := x + xtemp; xm := x - xtemp; yp := y + ytemp; ym := y - ytemp; PutPixel(lFX8,xp,yp,lClr); PutPixel(lFX8,xm,yp,lClr); PutPixel(lFX8,xm,ym,lClr); PutPixel(lFX8,xp,ym,lClr); j:=j+Delta; Until j > (DeltaEnd); end; procedure EllipseFX8(var lFX8: Tfx8; lLin,lTin,lRin,lBin: integer; lClr: byte); var lL,lT,lR,lB,lP,lStart: integer; begin if lFX8.img = nil then exit; //not defined {$IFDEF VFLIP} lL := lLIn+1; lR := lRin+1; {$IFDEF UNIX} lL := lL+1;lR := lR+1; {$ENDIF} lT := lFX8.Height- lTin; lB := lFX8.Height- lBin; {$ELSE} lL := lLIn; lR := lRin; lT := lTin; lB := lBin; {$ENDIF} BoundRect(lL,lT,lR,lB,lFX8); EllipseDefault(lFX8, (lL+lR) shr 1,(lT+lB) shr 1, (lR-lL) shr 1, (lB-lT) shr 1,lClr); end; procedure FillEllipseFX8(var lFX8: Tfx8; lLin,lTin,lRin,lBin: integer; lClr: byte); var lL,lT,lR,lB,lP,lStart: integer; begin if lFX8.img = nil then exit; //not defined {$IFDEF VFLIP} lL := lLIn+1; lR := lRin+1; {$IFDEF UNIX} lL := lL+1;lR := lR+1; {$ENDIF} lT := lFX8.Height- lTin; lB := lFX8.Height- lBin; {$ELSE} lL := lLIn; lR := lRin; lT := lTin; lB := lBin; {$ENDIF} BoundRect(lL,lT,lR,lB,lFX8); FillEllipseDefault(lFX8, (lL+lR) shr 1,(lT+lB) shr 1, (lR-lL) shr 1, (lB-lT) shr 1,lClr); end; procedure RectangleFX8(var lFX8: Tfx8; lLin,lTin,lRin,lBin: integer; lClr: byte); var lL,lT,lR,lB,lP,lStart: integer; begin if lFX8.img = nil then exit; //not defined {$IFDEF VFLIP} lL := lLIn+1; lR := lRin+1; {$IFDEF UNIX} lL := lL+1;lR := lR+1; {$ENDIF} lT := lFX8.Height- lTin; lB := lFX8.Height- lBin; {$ELSE} lL := lLIn; lR := lRin; lT := lTin; lB := lBin; {$ENDIF} BoundRect(lL,lT,lR,lB,lFX8); //top line lStart := (lT -1)* lFX8.Width; for lP := lL to lR do lFX8.Img^[lStart+lP] := lClr; //bottom line lStart := (lB -1)* lFX8.Width; for lP := lL to lR do lFX8.Img^[lStart+lP] := lClr; //left and right lines lStart := (lT -1)* lFX8.Width; for lP := lT to lB do begin lFX8.Img^[lStart+lL] := lClr; lFX8.Img^[lStart+lR] := lClr; lStart := lStart + lFX8.Width; end; end; procedure FillRectFX8(var lFX8: Tfx8; lLin,lTin,lRin,lBin: integer; lClr: byte); var lL,lT,lR,lB,lRow,lCol,lStart: integer; begin if lFX8.img = nil then exit; //not defined {$IFDEF VFLIP} lL := lLIn+1; lR := lRin+1; {$IFDEF UNIX} lL := lL+1;lR := lR+1; {$ENDIF} lT := lFX8.Height- lTin; lB := lFX8.Height- lBin; {$ELSE} lL := lLIn; lR := lRin; lT := lTin; lB := lBin; {$ENDIF} BoundRect(lL,lT,lR,lB,lFX8); lStart := (lT -1)* lFX8.Width; for lRow := lT to lB do begin for lCol := lL to lR do lFX8.Img^[lStart+lCol] := lClr; lStart := lStart + lFX8.Width; end; end; procedure DefineFX8(var lFX8: Tfx8; lWid,lHt: integer); begin if (lFX8.img = nil) or (lWid <> lFX8.Width) or (lHt <> lFX8.Height) then begin if lFX8.img <> nil then freemem(lFX8.Img); Getmem(lFX8.img, lWid*lHt); lFX8.Height := lHt; lFX8.Width := lWid; end; fillchar(lFX8.Img^,lWid*lHt,0); lFX8.X := 1; lFX8.Y := 1; end; procedure DefineBuffFX8(var lFX8: Tfx8; lWid,lHt: integer; lBuff: ByteP); begin if lBuff = nil then exit; DefineFX8(lFX8, lWid,lHt); Move(lBuff^,lFX8.Img^,lWid*lHt); end; procedure CopyFX8(var lFX8src, lFX8dest: Tfx8); begin if (lFX8src.Img = nil) then exit; DefineFX8(lFX8dest, lFX8src.Width,lFX8src.Height); Move(lFX8src.Img^,lFX8dest.Img^,lFX8src.Width*lFX8src.Height); end; procedure FloodFillFX8 (var lFX8: Tfx8; lXin, lYin: Integer; lBoundClr,lWriteClr: byte; lfsSurface: boolean); //Written by Chris Rorden //A simple first-in-first-out circular buffer (the queue) for flood-filling contiguous voxels. //This algorithm avoids stack problems associated simple recursive algorithms //http://steve.hollasch.net/cgindex/polygons/floodfill.html const kFill = 0; //pixels we will want to flood fill kFillable = 128; //voxels we might flood fill kUnfillable = 255; //voxels we can not flood fill var lWid,lHt,lQSz,lQHead,lQTail: integer; lQRA: LongIntP; lMaskRA: ByteP; procedure IncQra(var lVal, lQSz: integer);//nested inside FloodFill begin inc(lVal); if lVal >= lQSz then lVal := 1; end; //nested Proc IncQra function Pos2XY (lPos: integer): TPoint; begin result.X := ((lPos-1) mod lWid)+1; //horizontal position result.Y := ((lPos-1) div lWid)+1; //vertical position end; //nested Proc Pos2XY procedure TestPixel(lPos: integer); begin if (lMaskRA^[lPos]=kFillable) then begin lMaskRA^[lPos] := kFill; lQra^[lQHead] := lPos; incQra(lQHead,lQSz); end; end; //nested Proc TestPixel procedure RetirePixel; //nested inside FloodFill var lVal: integer; lXY : TPoint; begin lVal := lQra^[lQTail]; lXY := Pos2XY(lVal); if lXY.Y > 1 then TestPixel (lVal-lWid);//pixel above if lXY.Y < lHt then TestPixel (lVal+lWid);//pixel below if lXY.X > 1 then TestPixel (lVal-1); //pixel to left if lXY.X < lWid then TestPixel (lVal+1); //pixel to right incQra(lQTail,lQSz); //done with this pixel end; //nested proc RetirePixel var lTargetColorVal,lDefaultVal: byte; lX,lY,lPos,x,y: integer; begin //FloodFill {$IFDEF VFLIP} x := lxin+1; {$IFDEF UNIX} lx := lx+1; {$ENDIF} y := lFX8.Height- lyin; {$ELSE} x := lxin; y := lyin; {$ENDIF} if lfsSurface then begin if getpixel(lFX8, x,y) <> lBoundClr then exit; lTargetColorVal := kFillable; lDefaultVal := kUnfillable; end else begin //fsBorder //fill non-target color with brush - bounded by target-color if getpixel(lFX8, x,y) = lBoundClr then exit; lTargetColorVal := kUnfillable; lDefaultVal := kFillable; end; lHt := lFX8.Height; lWid := lFX8.Width; lQSz := lHt * lWid; //Qsz should be more than the most possible simultaneously active pixels //Worst case scenario is a click at the center of a 3x3 image: all 9 pixels will be active simultaneously //for larger images, only a tiny fraction of pixels will be active at one instance. //perhaps lQSz = ((lHt*lWid) div 4) + 32; would be safe and more memory efficient if (lHt < 1) or (lWid < 1) then exit; getmem(lQra,lQSz*sizeof(longint)); //very wasteful - getmem(lMaskRA,lHt*lWid*sizeof(byte)); for lPos := 1 to (lHt*lWid) do if lFX8.Img^[lPos] = lBoundClr then lMaskRA^[lPos] := lTargetColorVal //assume all voxels are non targets else lMaskRA^[lPos] := lDefaultVal; //assume all voxels are non targets lQHead := 2; lQTail := 1; lQra^[lQTail] := ((Y * lWid)+X+1); //NOTE: both X and Y start from 0 not 1 lMaskRA^[lQra^[lQTail]] := kFill; RetirePixel; {for lPos := 1 to 100 do RetirePixel;} while lQHead <> lQTail do RetirePixel; lPos := 0; for lY := 0 to (lHt-1) do for lX := 0 to (lWid-1) do begin lPos := lPos + 1; if lMaskRA^[lPos] = kFill then lFX8.Img^[lPos] := lWriteClr; end; freemem(lMaskRA); freemem(lQra); end;// proc FloodFill procedure CreateFX8(var lFX8: Tfx8); begin lFX8.Img := nil; end; procedure FreeFX8(var lFX8: Tfx8); begin if lFX8.Img <> nil then Freemem(lFX8.Img); lFX8.Img := nil; end; end. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/mricron.ini��������������������������������������������������������0000755�0001750�0001750�00000001617�12306667722�016375� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[MRU] file1=C:\Users\neuropsych\Desktop\fx\afni\ax.BRIK.gz file0=C:\Users\neuropsych\Desktop\fx\afni\ax.HEAD file2=C:\mricrogl\templates\jhu189.nii.gz file3=C:\Users\neuropsych\Desktop\fx\afni\sag.BRIK file4=C:\Users\neuropsych\Desktop\fx\xmha_z\cor.mha file5=C:\Users\neuropsych\Desktop\fx\nhdr\sag.raw file6=C:\pas\mricron\templates\ch2bet.nii.gz file7= file8= file9= file10= file11= file12= [STR] FSLBASE=/usr/local/fsl FSLOUTPUTTYPE=FSLOUTPUTTYPE=NIFTI_GZ [BOOL] Reslice=0 ResliceOrtho=1 ShowDraw=1 ThinPen=1 Smooth2D=1 XBar=1 OverlaySmooth=0 LRmirror=0 Yoke=1 SingleRow=1 FlipAx=0 FlipSag=0 [INT] FontSize=12 MaxDim=384 LicenseID=0 Zoom=0 LUT=0 XBarGap=7 XBarThick=3 XBarClr=16711680 VOIClr=255 BGTransPct=20 OverlayTransPct=20 MaxThreads=2 LesionSmooth=3 SigDigits=5 ImageSeparation=0 SPMDefaultsStatsFmriT=16 SPMDefaultsStatsFmriT0=1 LesionDilate=0 �����������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/render/������������������������������������������������������������0000755�0001750�0001750�00000000000�12360763603�015465� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/render/cut.ini�����������������������������������������������������0000755�0001750�0001750�00000000510�10532005604�016745� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[BOOL] SmoothBG=0 SmoothOverlay=0 Trilinear=1 ShowCutout=1 FlipLR=0 [INT] OverlayFromBGSurface=1 BGNearClip=0 OverlayNearClip=0 Azimuth=110 Elevation=30 BGSurface=0 OverlaySurface=1 BGDepth=12 OverlayDepth=8 CutoutBias=3 CutoutLo1=96 CutoutHi1=181 CutoutLo2=118 CutoutHi2=217 CutoutLo3=87 CutoutHi3=181 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/render/default.ini�������������������������������������������������0000755�0001750�0001750�00000000603�11645667574�017633� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[BOOL] SmoothBG=1 SmoothOverlay=1 Trilinear=1 ShowCutout=0 FlipLR=0 [INT] OverlayFromBGSurface=1 BGNearClip=0 OverlayNearClip=0 Azimuth=90 Elevation=45 BGSurface=25 OverlaySurface=1 BGDepth=12 OverlayDepth=8 CutoutBias=3 cutoutLUTindex=0 ShadePct=0 CutoutLoFrac1=530 CutoutHiFrac1=1000 CutoutLoFrac2=544 CutoutHiFrac2=1000 CutoutLoFrac3=481 CutoutHiFrac3=1000 �����������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/render/a0e90.ini���������������������������������������������������0000755�0001750�0001750�00000000506�10531435316�017003� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[BOOL] SmoothBG=0 SmoothOverlay=0 Trilinear=1 ShowCutout=0 FlipLR=0 [INT] OverlayFromBGSurface=1 BGNearClip=0 OverlayNearClip=0 Azimuth=0 Elevation=90 BGSurface=0 OverlaySurface=1 BGDepth=12 OverlayDepth=8 CutoutBias=3 CutoutLo1=96 CutoutHi1=181 CutoutLo2=118 CutoutHi2=217 CutoutLo3=87 CutoutHi3=181 ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/mini.bmp�����������������������������������������������������������0000755�0001750�0001750�00000000106�10423315160�015627� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������BMF�������6���(����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/icons/�������������������������������������������������������������0000755�0001750�0001750�00000000000�12360760644�015323� 5����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/icons/npm.png������������������������������������������������������0000755�0001750�0001750�00000054570�11464116164�016635� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������>a��iCCPICC Profile��xTkA6n"Zkx"IYhE6bk Ed3In6&*Ezd/JZE(ޫ(b-nL~7}ov� r4 Ril|Bj� A4%UN$As{z[V{wwҶ@G*q Y<ߡ)t9Nyx+=Y"|@5-MS%@H8qR>׋infObN~N>! ?F?aĆ=5`5_M'Tq. VJp8dasZHOLn}&wVQygE0  HPEaP@<14r?#{2u$jtbDA{6=Q<("qCA*Oy\V;噹sM^|vWGyz?W15s-_̗)UKuZ17ߟl;=..s7VgjHUO^gc)1&v!.K `m)m$``/]?[xF QT*d4o(/lșmSqens}nk~8X<R5 vz)Ӗ9R,bRPCRR%eKUbvؙn9BħJeRR~NցoEx��� pHYs�� �� ��� �IDATx duyrϬWT/ tc� Hٔ((˖Fь噰-ђelfc9b,3nIII,$z޷*++rU_.�HlTԫx/߻ss]ˈmYX5e ,k`YX5e ,k`YX5@[[[Xnݺ, FLOOGOOO<쳱?711?O݇^Uvw]87EU%X P[\sj@WZXVcʕE?{lj8w\@bff&?J֬YVU^~C~Z(#@O>sO\@_ _U\wu~ƍ={wttq \.;w^x!o 7 !ǎ(fR.G J8>|yĻ SNU /LNNIJ?t_ћokM@k ]]]qg}̙�زeK۶mˮI2`?>�3`E+̮nHqM7B>O>DF Yo?G>y=Α=?l x@9.n_ر37l} V܋>dž;串r]Btwwg�d|C{,MT,+μV/zx;L3䓱×\km6bll,F ijidxEʹ{ᥗ^:~zIQ|"ꫯwu̾Cw^sյbq^x>Z؊nb/_ Ow$6m(=#Zd00\zuFtL9ʡ2Hqz  c }{7oH!$t~ЀsS#O?Bs},;�rݽW8_;]l銁:w<,q&&h? 6��LZ @ܺuk,ZmzԂͅ <7}4Μ?;LNL~1KՏfMЮ]fGn67k< A=H%|+2\[~ջuv}gvEtMuŚQj>q._�rK\{wlB0%Y7k}HFa uߴE<u7p =x&ơf)*馲f'yz dS"<3FO#A>@n<mNfϿϊ~}Omr5m'㶸+.荕6\\/јqߖMq]w.rj:]p/;qW_h-7v{ult7tY�\wȝ]碽3/ioZ1͒/Ym&N}? :}PűOVVG~tGTiw\ٵ"*3Qh+m 䟈kT8Dglgl}zU.c߾}D~eeA^5ch0Xd͠X(FڈB^梜<DPS"ȒKR3W;)I!D|ȟG% eظWV['OT67Z{KtZCh媑l{tvw3OG{!s{#GWق}w`$0m.v%cj='o"T.W="r'V+gɈ&anƬӛ%'9$c'NȈfønws I�g)m#�Y.nXVrX`uwUXE(]M@je*?)Z-b-XM4 "`hABs6hk{2n Bee[ƣsZwfOB)!ɦL6;ޫǡA X&mA*]OJ+W&'ƉzQikGE֞-;"UUbjm^zi\B=mZ ^rfw5v9w .xjݹJFP4I4as#ٴn %>t�f& kt H? J$oy&@ Wy}ff2=-%,xtObh=JU\`c-xZnp(H:毵 ^M jnco1+x* ݼ{7+@ `#K9,k zI=L"Zx XO3ߒ"YT&[$@{hާM-ՎwDgŶOΓ~NT:>[%dUILmC+w_MDc *�A[^F/hJ6S6')"!"&ʦd:iz2.IBoVu;v?w-ܮ5w*n-cC=*]Q}:oF[qsN~ P-Yuʀ`7 F*w;6:<@V@(* nd6rD8<n&Kp%I2w{2GǒA&%4 CYo⿷�XG}6V_'6Įӫb\[U`u$s碫 g;Qjo`5{Ql U .[0tݬhJpt+x*Y]EA;o 70,XELk'^91A') <]-CY=f"ɮ\sX$.Ҍנyȣ/^s1>2ON]|L""(,ucLh+5RZTz4Oie*MRqC\3 =em&_Oa;5y^Ob~U♟x9GX7cI -GBoHI|~ISBtM$i!{� qytc*#fkcιMn_Y9 v&_,Fg8nB ;WRUI&pZHݠ__G(Z�M%͂m6v|%$3$Vozd/@*|SUi^׃!HNN'}tx4�|J�x;{k|(s|4떵ZFEWȣX]a7rjj%*܀sw}w\~*JnT 2TZ'T^@r`kf'A֣蝴|Ieɑ^Jb}`zA4YR 3)2?^E 퍓:2F� U(bew- ?ݱmJ_}[٧3tb)'14>簚Yv0;-IdڂU]4Ӫ$-kʦR$폫\=K.A` w: Sob^Qxlyʩװ2])9#-`l'$y'rlw~4@q7)@)j\;oƺh]_Gsਸ)[r<V>>3'W-fZ՘]MH0BqQ?+WQqR*G'@<UJBMuz=Kʼ&Z2 -C|70A`I:•G"]v\ey^ˉ+I(9R/FY )缇|Hy܄7�XЯ`5>5k 3L67W \tLNMG>dK lD2szly,&֮-t J}TUZr&h,ssئ{ݴ$ '"xNY״ 2rf3e~~'YB\9RI*ϦHhFn#X2F`UVP?:�Ԝ_Q9YePU ؏�oNGsq$J5QmGya&zATwmm*~&T^,�Z-ާz^x �J|kozϛ^=c~l>{9@k@k|`Keޒ\g_<>di uo? ^u7h1uL fm= J3Yj[\Qٓh>V+=(x4V6ʊQVuiF%@-`ɚTJ` MvXD br jZuLԕ^y!+K4}G+l$n `JN⎜m",<&]sΝ7TcUmTH%h)ܿš�x:sbOs}13^({3ִnp92Ҟ@hue(*k (*OJ�A3**ZdHdLw_u7ouKQ&<wK{HW+O%SO= 0y"el e >taPaeym~b� {w_7u}蜙#51M]A2k`�(g2AZI?B7Qif{qz>m&boġ:k*GXm,-W�T FL],DiɓUGKYy}�Y,u ,s6Z:dI?n@Jv^$27ӥu5X?ua//pXq|(6?{26pl_\ff Qg¡=?sTln@lh֮ƖW2Ӗ=h/g;`b#rKUv_E' Z K lp% ʣ"C2tP*Q[c/3ASR,Lо`zݚ\6Oe%Mrw(e.l|~}~ شJ :/CRO~?Æu,G5sT]*yWϠ'+>cb>L螻E=rX^Lʟ*[yP2,ry@ ߵ^YqS*Y+M9*RT*W;kg\'*<`5?<,׵7skGauche~*~wz =QRTxǒހ$XO%Md(, zkں~Tر;ǩ`4Ep%BPb@g_B1:\xt3(SEyu7"?Gd;KEpvXDyǴNDaTGtʶMptGEl9G-RM#T`xc=J:]==c7E; 󻢸xmUnj-;7|/q˖x觧XC [,;ײ]r%{O=ԓX?p3% ToKYw +W5džƮloa2ph'(}ERiF+pcXskKFW˯KcTf"'cj/EP٢-Qy29*"yi�%$*{<,-mD}`ol<>j~GWF[ustw B/)'eL1o=S~eHVnyZ^H![y m*JdSip!^C7n}0O]5s,<"_{1:ӝLkfgk�1dc&lgVvxdm^'vK}oQ/h`z w8E.(R4�Odm%Iq/)lk9tQa*^UTl.<6�z`.XQ=Up6oV'q09o¦xi<ODr)ɒ%M״Z$5 R2e7ҫ\l=<]d&ߏUR0c|[έ sIVx1MPƓX !{R6]F*Ӗ�D!]C-s#< 8Q`$3U,idd@ 2 wkM?6u&waA马i9|=DeP[р&-ḽHuIxݽK�ɦ̂y*w"Ytq?̛uNbP;m�;ZN}}gaUke,&Fa}1=r(aoQHP-:r4 P`ܯe6Xd(Reʘz]+CëHoeUk \uzoIQ*\% NR|YB<kivv3`҂tn!8dUjҢǎٯF`5 FpYtZDL9s|svk~*WXZj_\{@B#!>XOG^uE;k!ǢN*+j8k #G,CX'oTh%SgO?;ڷMd?ύS9ؽ|4s1}+zJƢ!1&2FЊ NQw*ZLyWbW]uUvV}ѲH+3 _w΃"a=Y˼魐VYu,g�09V6{!ܙģ(z,rHl=.q=b:eЃxMA$rH8Io׿ !@\fgMFiSLش '`#*/0>ܯrk򽱻w'@GZxl-�=-*_k0%4?Gը.�ؽXƍ0EUhrz7XWZT",7Bٶ 'E�:u~? _Zg$Yh9{}|O+6?/ҥX!kVA<HH$,zitu6]/)zyzټMb <+WҾ?tDkTT/P̂ >tw={*=72]!RXA!dn"L ew.|k?w r `axBAo9s*P�Ӟ&sT֤2uEŹ)W&B:ٷܩX=bR9WfښA.<?0+g-#(�`= GK@JTpl$((uDv$~ez nN9/=N.4!_#of.`ջZ+p,ʫƢy4t+2ñI,F87;3ε3 t+gEWvuaU+ z-,tr_>o?>kupWT(oZSn%IxC}'`.sM"˔w\p-Sǣy6b %ne\G9#:"(@KleQf]M@&o$nt6#)w=HAHu^#N> k 3zE틩M[#QJRpVN//2Jcw{~3\"L+0d%\+Ԧ.-0[ `F�/21O_r)+k?�L=v~T)f;V VN79hCx,`C}$S1Jv. 7oD26ls)[ ֬)$z0wf姻r{SB['* 85*(&Q?RQhŘ}Du*-BtGvd@�� �IDATӻyc :V ksKUtw峬`qi#�3ypF,<D3ub~nLk*ID ӫ4{O<DPC5-"iNm3āƃ}CqWGB4WOUh=eOeU7wG�tK% , RK<yWk~a8v$g('eBdJg_|!Dz{*O( /@7" g#J`U-@2_ȧ �e@DG %rUn}Vvz$%%WB_h scz8zp )‚q;4 qw$I),[JA+Y, quSI,Iq{kf$x:yzd<¿I]]~mz(_;mHۺI+XVql\RebH!d*$Rl `~Θ<K$Q3Ãt ]hr"Z[G# GB ׌)ST n&*P�$qyi<{rXpӺ�a<qOk}+�\nf8JwOߖ~_2xM`ZorתLWmzM'$g'`YfiNl~!On_>.Mɳ*M֚̽{�B}Xqʟ@XvH2eP }I01ɳ(=J{eZޱd|R`! ;/}r Txd)hVpx%+-橛(Y T閝{tnZk\ę@(AT" ꀩMvC':Ʉ>_h k}ɥg@]<A*m9<qч=7y^^%m^&7x]9<;T߉�LlL +_JLc)P:(n@#i;GϏgB@7@pZoK+Ӑ<^Xp Rߊv7y(;-H~"Tm�aT#%תB2,J :P4GsnK.xy7˶i8z,.N5AQI ʓzW t?Owvw^X-xaHu)@.ȳxwBT[i3m1S@wկ~�nP|=0u7n#h `H@8>ᒦiB�&WrxIGxX0"!!+yf#nXd?'yЁVg S_$TtQ%(3ak4'+L~X4"{7=hsN"By~֩׼`OA Ny<,u%Ƹ`k7(v[H�qC[W7<*p!נOE3',8 \WdPۘqJ1cV`1K[ľ^ڮ3 $'?G&/Ye=3oީhi+mLҦ.TnUc0yuYa4q` E#T9n*\S}۶ғu9ldtcR,bdt_.8,=Ud~II~d0i\CQ |.5A-7)qzk+y}] N\v @A)lr7hƲձu+V_z]l<W.Da<+�]('kGs1$pjG7MB+;L S �K [rޓ13úԁ&Bt*Fpa곅⬛uH2CPv?y F{h&>ܥӦiTnء"ݿμA7^AYfD 0  - Ng~z载ϲ=Oy+wb�@{[7o^#qF|ג{^u�mY X Zy.g'޺T(6\ؼ8:NEAx幇Y>u'pt"Bg,0W�nrL-H=ZB!GɕX$dZҳwvc ̴NWy*S6u&qa6.ͅV[ $m-:0c'☁Mٜ$o㱀͎kP(o�JΙ^yٸg.&3�#@?$= Kyo#U7(אKT1l`%Ħ@DZV)WWGY^.tLպpGep~?^bֵuW<LXzKDt<lbaJ I@ >'XF6>BSF*4Ѭ'Q::~OuGQ`=l*cQѺl% }6H H-A$hznl> (k:0F( T`@u7.]l-kzv<Oٳg)cp8Ob56DJX^tK K9Pdl$q0`(xmJXK 1JU)ZO.=ItϮ8<&esLq=Tz~cq'brtT^2g+U,5]ً˯|Q GxŹ <+XO8EZ>@ Wa ]ǣsd<?o=KW%Jzw=aKQdO!ok�x+.g )CgG#-Cp$@g^M}*J2\M+9 0`c~J<B,ÿ ˫6tǩP1SYja b]]1<:GbQ\vlMF|�5A֙_GQo_gys;rhv@6Tqo` ! rp9遼.X.l5|%'?{ص{kV$*Ϧ@P\?,�KF !}sI( YR(E \,x曚kz *ڴEjpfZc2{Q(2[]y 6^7lB;ٛ6(Tg?,Z`><!]/,4pݜ;bw1y/qx0u@cl86p _[,E9OsrX8;e,zfv(Z5Bբ0ƪA)r]\WxMH}z=㱅+PW%)PXx(6>(k}Ȗbx<A=I)G&)W%l n)x^wW*tӳ/WٽCT|p4m綼[o5#5 s1�m/ض�kzYE$emo*ױ*hK>sks-m"hmܣ<?pś>o$`-9+(b r~ Ls(dX{f&as=&tS9sk9i 34o8^"?u3�$ww@z܆,+Z ]fqvw9EsAm�G6h<u~m~ G4v`j$/>+Y$[h<ƒXʱYb nڴi;Zƀxَ{+Č}lR.QfJ+b"KDwV&p ¨iܘ!%`{anۥq݊a% m($Vped~`hs<rXS� }MJ>q>5,*j,$od^|m]ѪtV46,ҽ:N ]!R/�s3 L�n&tfsc{MOI9XdYȘWR6I0^ <+ �7 > T�!N$>-(3Oh@lm^Y-A qǰh ]1/esiCa ϘNꡩeq%po辤{Sch/楗@ix5(tB"iJ!j3(ךʔ&\$J�hO ~u)UM~w336kir&S4́z�Y7zUnsWn70PO#]<K_A�;E�4uۈYG>8: *Š_uPXG5ЏMN/DQF,@uAy YH\+WaHK2yWiO{yc|U'|Gxf fo,rzb NW@o5(.YS~f2PʕB'1h<B2wNOH YUA��W0xf鱮zW&uQ$(298Kz17ԫP^1JMD// 8K0 W @>v8v_ @2c;kmԙ9&ceamU<NZ *ZNZYY,B:z?vi6xArUk+#SUb$+zcgWlɢΨXʪ0ݦPyܔQG%^y8wؕ�iCpe6<@ꢭ˺k)<%mNG�Ɉԟ[/Ӻ٩R0/|7.!ʬA<@v-(se(΢3x".qu`!Lx 21Ìr{)S2ᱻZ"ZJT"#:m(k(W( F ]l۲Zy<BrӨТC旾_(؍NkOdӵK.U~Te+#ɧ[ݘu7=yW{^=A?W ;#Ѯrs Sk7mZ]$;4ZxqݳY_Ȝ8dȖ/LxV5�K# -M%h)VT`A @[9㻀f�@{PWda6bfe6A>}t*[kU*ZpHY3ͤc٫AfqTsr&42@eJA[%i>Oy #`-(3=e`:۩@SsZ Btx%zVlghߧfJ Ǿy<s(yoσSt˘U,3_+ayR)TTR׭%Vl^*4)]IS#NU\0A>g ut7@%'2Z9tSł09ȹ8K@yu+)~8eO`<'ʯ+xl$yTHn&Alԩ]JXl|8w⥃Ji:Ha3[)VR%Vͬ ]^O5VЎx&7, [QA+.N`:7eqq4*YkMU)wSq5N<C _ eFhe@S&*'ٲ9I&.,7+y[y6#%k뮻4A"꩔=Jr/5g:ANb{E/ ]}n! #c8L{ Pl%X@/nS4 rI梋(2.p DuHQcIX�T9VBv Xά ehV."u2^L`IyxMiYn),K Mǖce>2fldk3':K9kӫ$)$ٲ<om;#y Y^vRs"?~W>Ud^|,*+rUѬ89ŀl>ֲr9% ie%s=*)%We,*Aha oU7?AW9e1Vk֪=fzuqX��i.ș{y(n³blOWʛʩlvϴ^˰.C kܬr3 l x#[r=@|^ nǠ-a x<&giO gO�#gj%zNO(t`m.~EZQ&P*݊xXzjMo:覒Ut.)9[,rY \@R )(S1J \7kZF]{ '8CqbI[Ss3o)zA7IܬDYt)NUuPw�)ٙ[ L婐ˏu<ܖHsP1ܪmfӨhJ0R= 2bʵ\;~[as-Mj`ݫ VkJO=*swlZ<gZϻK0N%_Pb_@ٶMa{* T$SiK֝ m,@ȫz3~Hr 筏<=SX~Jz%2i ;u o׸tߴnI]Xݛ cOG)Ƞ_0.3!U*k\g g|/Q+kz)kY%hVX%J~j9*I˶kZJd<FǶNr�6q1Ź`k٦PmVQTt`{F_: %2*ߍ 7y(|J(L(yM<Ճ͇}tIoE3lcٸ<ʞ0WN!x sn#B=?+W0ˏ>4xoH61<�A }T(a%}}iv_Y *TJIOm5LIoYHk!?UVYr e vNb J42Gɴi^܂m!`=YY\> K�{̂Aun2OA�V'ڋLW{M}5Ŷ q? !qאv|\'yrzXU'h֢ #cS *bq1uu ɽaӋݢהT 0&{'@PTl:g^jTUI*(wPtL~]gZ]Yts@H$yE9!_`O29T(5}T9sx#YAkz�2ܯ8㚏STfٷx9b/sncDs0ytlx7dPMK*AHUtbHdI*TC6Y ֪z\)ް=C"Lm՚OY$@V K9-Ѽ::xl> ByVI$߽{ΞeP{PRw!+}^IQ/ >Dy9i>bMΞ& Y \a|}47ⱅAJ< `rF*܊@I'TVXeJ)L@P=*p*=*^+Pӻif(552 @͍x>|n],SK'6{L 6s=d�R[F$$,<kyoP2B~֩`?[v>\ɾn^yuz/^'V <M| RXִ-�ɉIu,LXbU *|C ۲��IDAT�k*k\3sHZ%JT)_|9ɡEz^WkZ0oWzTV?@-_0@n.'N�p9ݔϼn$(͏i$,1zd6>2uo?|&+{Mp_tB^K%Q^x@ (9k;#97\ <ȩo6o5W>7,0SVDZ95.ʤTݵ=S'? U4-*FMcw?*˲nY@_M5eRFckR^=m@ƺP.nc}$e{ʓ7?3r4U*~,汳ܿk6R#e3cQ(K|d! @ j5L]/C`n'g"i5!>e=]zQsʔZ JR xJ+0*Ƚ �ݠ)óh'*2|_ ֬h lM ϫ|rs}@|rz}k$R;y.˕,knd-k=c<}ٜfS9Y4#&{{=FQc vIS89E0uX~WLcy($]O| %]A[yVp HbJR-_ei[bLnwbI"x VAfBَfȔXTD@tPݭMB<8ݲJN"[)M|'MI,Cݬi$t}ܹGƿC�BKUQ ¦x3T= >~>YP'瘿Σ0~  Uk ~&=6YEWDk37ⱛ@I�4~ݼM#*^Kk&QTp'Qzct~Zc[kȖ#P`z<$ds<lVxc<Qn0ZDXY0epz+ض؃gFG,K:.<+ |_jua rr8|h. X2튏q3&€(#ϋ :sXӡxm̖<崫CZK*_%j)@Pf*n\;˼ (4R.ZEϧꆭJT~YXB�Ee`3u*ѲիM 6|Y浗|9s'iЏL 0qI`1_)3\.p;Cv:*? pb,F1 MWre+ er~6V{W<X$[$ps Z,Q~U7.p@H7(%PV :jY�y,45~o`=y *9�˺%b KѲs N .)#xΙC;p#Il6ԫ >e9)d!aeD?x2܃A>i7z=y1Y2i*[ϩJ.Z-S:u UZ} Ds,)8ٲs9ݿ3zKo[ybbcay:{2i7Q@I�z�ѷc# 3�ⰭM+TAnQf�]߀P$"q $<IK@̷ �KuC"%/i=g٦dK�JؿI۽uŸՓ2</$Qu1^q De {oh{#_z~^+U統yO/X4}BYkQ q�"M_o6,` gh+@=G;=([m=P�ϡ(w?4Kv6fL" @.WTn*Zp]bm}lL7@aM@̍B^ i?5; i=iKHɢnmܾDX6_xd:%Mo`{#H<EÇG>fiN^3QeΥsU5/ O,bmy|^ 0 4a�ߟeC؀1ì(rQыr:uoHGW toۏ+Ih&}弊nE^B ѾDGA(H1HkOvQ�=.b㌤e(I:yTʃN>C6Y=ȿ7BoJ<zmFmbagm+<0ְg[H+u]k`i txvOX;k7ƥxS ,cos5Q&˞?gH֭=QkaZ='Xgi~@pXvJ0fDpLn6|l^Pgahh,"#{=x˜'IWe$5Q?e%|n?f5incPn6_YOTJkFXୟu.ddT=7{c!3|gc.\(~⸞ri/}qd|*>YJpr�hZ[@=w-|<'X]K�37@K {H)|b'K,˖黱?9+w~kV| ݺio^!nmض^oeQJow8*'̷~Ƭp|?@q,nxVr?ECf!X{wӆ"o`TX*[plI-z!P  #PZ/lHz {V.aL+ȺxifY<.o5 {#t+>?5&9'iS.)q\<;bV yVH&,;81š=4ZRs'ZmLX7AiU2 iTBZϹ ^@Mׯ%p%-[Oz%x]x!~| pV&�=,[Vn@)fyt{qō(^Dy1y D=b$Um JT.A]hA `3㧀i�|Lg~7e* 2RG4cIi P@E~ O>"NSg9=:�V>ޭ� ^ʘ7 )%l&�l�¼V*MjuV*^�=4.T@$x]�M rVu擬Z-Sҹ,_,iyc)>),~( `uw %QM3Me}p?tUpWLbhySy,<Dɤ /X7E�%&+l)pE"@{5/htVrx4G [b>k^8MQ~8z8� (u~ac.o"hhR_(!o pn{ Q5[.\uD\v|(#x$7)Yk?!e�D*Xk@5i.PђO{YLfۮ2RR F[/MczA=+)ǼòL$µD3aoF 2%E*aKc""v % <Gza p8JSqZ֥f<7Vc0d~W㴛69AKSI%nNZYHIy߼L<cp(YIM# BQY^oVbN9_:%%a(Y_ٹzj%tW*U=/hXg^kO-u~z8$XA_/aY ^{q9Z͖+~?-sWaf@PҴ!�*LeX]IRDxQkZ l7rSޛLH)l ̓_[X$O-ݴkzrMk rs M͏Ldu_%*TpT#&e iIEtɊU�JkަxA2/7-{r$yYrݵRː\oMy]e{.%]g^u1!913񳈙Pݩ0SepӞ(*U"T5+~qJJi؉X hzɠ%Zऀ$$22r.h'TIAyXV.)+uY|ZCCCRyfM��(fPU VZ OȦ`jQ5/LI4X#(n*M2y]<J|QnJ"w@rx޺(;`6m9~/~<'WY[e|� Da,Tm Uْ@Q*tf'$=DO{cϙey,i<o>{^[<\7r�Z0o|%$"aYHĤΝt鬀wɿ�*nePm@w7AQat@6X8]ʷ$hz %6f9{ b"`y]2<Wb,_`ɼ ϰ@FAY&a /)`"{ !tZRd ǂ _!8o[Ju?Y&$'9\.)z�s!pƵYskSF/cYQ~ Y6q߯q (wF!PT`2m?,O&~7K 9_]Kdyq ~:5wQ{!,eKTIWp%_vՂLu$ m#_gj$LmZ{j%u*ݽ&AB$ xIs "6m׍;mxN*S<­v\0ukn n՛F6@wm]:.z?^tw4[~pK�x+HK˩.M$H1F;Kt)FhwKq"% :MS}/3xl~ ౻md/Hz9#~z}hh "@& ڞ% )x\n3` K7ɔ`"׭w"XStdwǽyo<+ÅcLwB/wq!]4M2UN ;x_d/q?&⻾2^>CW] KOW,|u I?5e ,k`YX5e ,k`YX5e ,k[qIZ����IENDB`����������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/icons/mricron.png��������������������������������������������������0000755�0001750�0001750�00000004075�11247262662�017513� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���0���0���`n���tRNS���7X}��IDATx^ TeeyTlԸ*iLMkkm4(bwSZ VhKݴ+"%&R\ dAefٝ{ӹ3B5i/''Ln?ܹBB#`ThTapm0:)eUlmmPWgoA.Սp!Kiҷ-3Oo4)L&Sox1W#5}m.[b<<V2XhW,t=Z֣{oX._<== z睚?ݧݦ-E}n]̒:iF|`.\ʕ- -_?JVH]uL%%y%xQq}2$$;{F>OZiJ*cĒ$&m_v \icZugI"24D?LLw7KbBT<p#sk96ڶ8� q#t H yQJKT&M⋩ 5˗XZckC>,\iԱ0uW!i@T9c7iӘ:u)) VȖ$IrRvE^~EE�:@HjD(`-Es3[kx'<2?=KouV6Ӝ !(H5Ac](™9!n�oli,D!(ѽ Y,P �PAp. ~" ‘#~'8<ňUQCO8&U�-.(P*F y)jAc`x8Sp)N'IPV0`]D(m8ucǸRDBl6xVB詗TB]5(*Zf.Ae䴷Z@72cdL*IgS ٞjc(+#Nڠ&1)N<IK&N y,Ԫ JVpN؆(XFZ+}}j J*3dHT&.SfJR@ƒ>co?rz =XMq𱘔yd8N(`.%]iJJCSexo+:1xA?6=9'--hdQYvlSIld�`E{?&_ͺ6J!84#4 6PDLIINZZ[BuzFH\n6izW`5jɕ x(SO�oLq2&pDu(t?g/b[0R*`EC͠[W@(3 Az@L1* 1I@CCMcPh?7OYģZEŠ:8`Rh+6Gd?d@+B@V6oV,#9iL\$7XjC!w]rGe3ԫ U< 9A).|ך!|DR4#2t7 4bՔjp 9h͚x˻V $Ճ(D %78r9Lp\rhofƏO_}rܚk!td-lg(@<kFDU]k=DaԀ*2.Qy_hxlYS^bܲW߱3ޞtpDҤ&jNR(Ҝxj=-hb|~�ʺ&�.͛]]'zNuwꪙ&WWg&)~Qc"fx OԌ/}i5b ν{OtNN@Y"U;}A_{{۶m-?I-y4eؐٻiG,߾nݦGݼbsm7 }1BBBBB| wPċ����IENDB`�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/icons/dcm2niigui.png�����������������������������������������������0000755�0001750�0001750�00000025326�11247263402�020067� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������>a��� pHYs�� �� ��� �IDATxwt\Ǖo#g�H$EI1)PheK4uJVNYۣuA{{fd-YlY"WD1 "94}nt7P8]^ n[^B9 0@9 0@9 0@9 0@9 0@9 0@9 0@9 0 7To&wpKMM57Vuw-?}3]hdp_WGbƆŋ,)knokYT^m}'j]/E&7~z=1@ҥK+O?*bɒ% j)z^E⒂º‚ʡPtuWh~IIaohqE l4/d!],h$bCD ѶCz"yj ܆|=3k6o\UQQQX3ʆRE:F庖]ҬTQD<FȰ [舵F#6 "t4U OP(dyʥ癇bDe"bс(1op詅'8_*e6CƍU+ImpKE%%%% "fktsiYYAX=[~~N@h.蚯oA{V8j*ލFGmDDE<AxO仺c<bJS(rW?1EEThOutVwv?dkϞ٠x Jr-\Fz$u8a!p�*VHWRk+G}0aQmȐyvHڻEt "= c uu3 0xHZ5l,贕]}{N$رcg| |38/I'-t%'?<nyDpɚ"B=eOqۚ{F@3 R].mY4d [cgOpG]O>Ku�yG?z/tuu->M*{X2L ؞<#C"3'F֢4n6$)Y 9&:% �Ev}iX[ssۑǎ;>/« )1 7po_M_-[؈,xBۿWc<{)2l ٱ}=#'%#6 `  Q@nյ9ҦءC~"x>%e�Ywhuݸ-/M0DMtJ�?& ۑN>8`b�[n@+0[ʫ5XXssG{ȑ8>OqW )g۷oUV ?!vϛLJdpH=ӭmۈ$gD M:_c<;iEvee4}0I<Ӧw}=$/X-L 0appІŭ0Ài_!RBSV@LF Ώ |24g#@c*1lŊrsO<y{loV<nx{޳L/ay I"սSs<˓&9c}o(=>ia;dd˯�n* lٲT.!ufrb5~٢E xF`qZJ'RE/ˍDZ>"oNMm?wɞ" i}M7ݴ)zɛ^{zzʍS$@| Fh﷦ng̼̱.]m|DfivZHݙמd\/^ $CЧ%:[רK,R}Gz{D$.}5?w_vQiCl0i轛nVwBo'gii1vwkJAȍyzx?W_=|8gF!D &@x֊ˇ GY  HL߫_; DS'~n r3(Buxz{J*՝akJ HCvS[ @\ՃG@ 0"`L�asz/%bd(ˁA|p*#V!EtJ0bO 򭿸ȆJK,^SL0 p|+. Z튀0409ŏQ3d׼!EF߬Zjsl lmdZ+HgyҪ\"c۠q@+_D]e%60R N=d$e1A֜wk˿sOVzMxU`}~:> 9a8~U}fow.H6ku m56O|< L0Tdefym"ёځT1>n,R;AlQ4kq%O664d}�o�`KR%R&5>YH<Q,+[O[+ ֢0Y#.xf@sWV؆ygY{i:`{О,E q d,LZV<\Nj cQuQB[ ) i&$%v4ϳq4=6ld=xn7ϓB" ]p X!.=}u5lG-3@<K9W8{>>{wfTYBh0�T:�>T $\{ k[jVPti-o2g�aN⨘{ Ջ.O Y()&P; YU1 .={+'�5}6Lŝ@= [)*Lc~897al}zХ[0t|X8ʓ }{`an4E} ui[/)+_~ WOb�o?/��X|?XX`=,l.s7e557mMN4y55,Yj>dzlw~߿_ '1g=$ O 5{|H{1I>$ b~k>{ɛֆ_.n2tȊ '8 4J h9^8th+͛ gP+: *�"?UB4f X25/q3d͖xPcM- kt} ̜ X9tZ@] Ek_r�%3t z߭CܼX3 CnAK-"c-�1^T+/Az@Ckц`(u&X/tu|\ihn˷V K!;x�WIDΘ=|5%?/BGŌh~]Ɩ ƆCηG䙙}^A:bN:0J|} "kOLfLeSUN^sS%^ Nu7uXhۈ4CH:| vI<s@�<ޓWɺ9&#W Dz:- 8p/Y} 鏏r?2r:gB1qYyyO%jw h i*`mܽjSϚjܸk9:,LBh{y6ݻ^:k,D}Æ `$y`tp`7]d;Վ].;O Ͷ;m?w%m`�utT`Or.{!{TeouH/Gmgybos=$W4^i\sG>{ K?n?bjfK75BRyEEj?`NO03@_% �$Lp=a7^pxka4%BXH_S?OoUmUW]u=Bm<!�Cgo~{ VFˢ<:abڣ\r e6~g,ia zA,x01NG߹m۶yҽߵkW۵m1FY73X|a9nm{wXx2$-]t$+~[FK>ge�� Љ EP�_u.k+ot:{`93@ 73%~wyg|i0H-DX:cJ""[B’I<d4-;e~6z}A<LW1&QO8feuhN+{U5'<0LDtwtp?B!^;rpyMFTg%;]Gdu dv ˗oTĪ0::]6c~_ԲWu$yI>͘Ϲ~Gy䩬xƣm"ϞR[հ6lhl}t%N86}Ht c�Is`O  `?,?)Gf%/-՘;:"?蟲~Jvٮvn׹=Gp K.չ@g옒g!N,b:Qozi1 pp`�Id;4!k{K|Ӈ-�8P)|K7{^zvg*77,T"Iiyk6mRL/8` �@Y b6pnOɞw}e ʑC BLÈfV= RU {ӭ3B:t4�5n];8lKo!8ٳ o~ӠLa~Whjj�U46IAiP=ڗT[ y:¬ ^z V[cfLn^n:UY^1R/o7[V4{)O=Ԟ3�@/wr}-D;& ե[c�|�s밈5 e-H,БB!g�dG3],j1iO*jv4uq~ϩ^HT`!�ҏ �SHI� 6/# X!Ǐsd#a']0Wc語]wwS]ZOw*`#LJI2S닟'2 e<^@< SG8ALb 2 ҦuJ7�Eґ�ql0ׅ9xAQ.F`X;k=�] R{qrK>a{'6|IaB>R\h2tC4u4L ۥytD4�ixqx1U0A>|sXSDX�8 ꟊ=ǻ嘸*Z"vV!"„9#Q6m7Xߟ 毅 gb6iOW2fVA6aKx"wgE?h؊S|vT>^LV dōbVPA΄ 3Lcڇ^6R >#"DhXf4 #u鋥+%f=Om=i{間iP-:�'!N?ݳ7!z{^@,phE h3~N4˕+fNiJk,*bz1S- R-|@<k߅]v٨?:֬Y!ƙ0�3,-4,W6$G"m뫪Zӭ#c˙a V3LÀh #]6} Ik/,d_*uQM3CV!._vg�#}shOM}<)n袋}̖|qjb (N.Ͳz*7S<ODU lc 2Nu&uBwܟȄo@]Zn[tD! 1 !]I{ jYh1ۭ<s-l뮻δTk.8|͟⋯wq8՗ I<qL—v@OvYA!ܸ)=N`aҞt J~Ѵ°p7?CQ, S WJڋ{ a!]{7>}kSQM;rηu�#ЮǏ' ZDE0ػ^ SRss; Lsƃ"2-wL{�ʽuZ8N :~u`4\zW#=0H,a 1\9]3.- =:_8ᇿRBM_~]fP_vC,I'ZPzg$"}d8RcpO_=w0:;Ӧ~H1LT|ce_t)<6v޽-p`ũV>1 zRw&)p s%+Ġ."=(. %"͞QL㙊+UPV xHO{SxpHpXgTq,ت'H6M57:SAU'W ģo4'%+?Q96Q9?LQmڊ+c\AaD 4\`OdV:@UsA{gJ kB8q4sp$_xr)uh)ZJ ω`I7Cxܣ}p d� @ Y y4em"Q, 1K0@$ӧlOTNp {#Tsq#Ql{ީz'6Y8+J6�]{L|ʼnf:z6BO[i`=P;@N#x=P(GD?\y >8PØ@S�Vai*[6x1 K<y7]~ a Ua;+g(2Ddl 0K~:Ǥb_&Lϕz<`=O566:i\6~>e3�ww+]St+葑,OrJD Hܹ|ƑnA@2sXx=^7#CD \DD$P5;vqv}>HVc�Mip mt =*Ȉn.@H IĐ8aHךA ^!(]1 &mge* Ȏ)A8R s2MQx~%/en˹K wOҀOs 3u]_ :J'$Qx5��_2 DQY'o0 pT/W bO`1D>�P{.Cz BO~gLtVc4kvEN_7m60C=<C;1KO<ċ n<pɐ#9<0w'nPd"DҨ N|0b>bQ@=0H~p-h-݌ivr<#zQL{_K"۔�Dgk% a<W` xͽj8iD3A(hdLX6 ,&Y04ן_9YtM0A8(�&<<Ę@T*ϲ␬tEMB}Ψ`/y!NO  !E;QC dL n 30i'O&ȖQ3VX,0<;3a "#(2(Ԣ;_ч"cQ35SدjsãvźvJ+կ}Y'#Hx>Q�� |IDAT"*ē{LLQ&بǝva-?@Q749Mu AӦ 9|_W_8+;wA8X �^<sI*η V$nS~pZ4 l]TSg5آ5"bA̮-~ײl~|8,ѥqI=-Po\Ol}c@l~kSMi;OyPDb_/ƣL&@Ӑ#Rept b`LZeD-V8e][Ј5 2^TZfEri~淅t\ϳ#M�|Y[Wck! .)yJ H{*-_xok,_umCMeek '8ys8ot@p�{mk0і4�kx<bj[y ldvܾ07H%?M {qJ]|,Ff.7m0�WCAny*M1~BtayA NDsAh2=3bj,{0$-ay\d S>ݺlm/~"3}7i5GT+ī~_4}W_u#|hqdQTkT#4&n焐$O7m|>N2M25*aڗJ@gѽC$IǠ}xm2 #H%0hRg}lUkY=oI Ö;&pD 0E.GD2\!;3FgMVb~Mۦz}Q}A6&1 +U<�sTܗP3|2tWNH{ 4=vVYv Ka rYߩ'Xde<xsDQ${�1^cL|Zl9 |_/˜z .ДXظ>VEA|ksl$ %{u]1]hD #1SہR.*gkqR:dv࠭7>tUvVuQM\:ϵ{'퓾Uue�ܟϋWOW e>\|]6R= Q2 _1Ma-9׮_~H3'~f:$Q޲O�~t?# kap?N=a[lsG&4 IsD1|T\H޽z~xl7=\MdzH?mOt" Xf&A8ħW�f|k?c-Z/F`YH.iưз >aS#mh{[]V|�dl`ǯ5l>Oa�c&",@ uuƯ &pv2}m;c!ML?ϷG#E-_L  ǝ&1tL;ʏE B,\7B |I% Çwi`<>޻UtMWZG΂DcF'Lm!Odh}˓,?oO:h'S V"WoUEKIyL�'Q`j=q|P΀>Iwzv[U=9/Yh.Z}{P~ 0P?lll܊+ʼK| ug&L&W!pԩVѶN_B~bGG=}^>vԎwBJ *`h ? /\!>LU1S' l7/^bgKfJ)0|jkxkQpJi Tw+Їފm%2NMSmJ Mn vof(xu0^?2bGz{lbO[5*+U=Ai$r `[+%"|"Zi3j묱jdB82$4֭[;>8YNO뮗mz-.FX 1 >DV==t<5`T_5Ul]`zjjR[z]}t-ݧs]lD̂5,Aˊp!P_ O~]ʥ!8F;tX=\㽃OgN?WJ 3?%\;m9|1vxu{."'x]b%0֚~ A[e$1F,R&oArJsmQCKNǶ9ҩߡRvS.-�,<TEF/38�{ \݀>xOFĔ-Yr' A(Wِհv|Hޥy`z`Z`h9\_Oa:oO𷋓+8ư .6K`z~Ʌb`*u2_^jY&X@E5C0Ϳ ^dn\ZBڭ{D;._5 ša ra ra ra ra ra ra ra ra ^[;7v!����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/icons/mricrogl.png�������������������������������������������������0000755�0001750�0001750�00000031640�11213057342�017644� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������>a��3gIDATx]|U?w2IB3*T@@E�WVZqVqu njWo?x摄�%Ϗw޽=~נvڡN[S;�vpjN��;8`v�S;�vp_@G <Jy[FdZY`F:n "w*+xQ#o5i{@xeY:VRsEݺ]PNTPMDlb ]9FTUe5v]Z֬ᱮ|}ҪDsxc ־�;8>[}s=v6 Az@0۶-3n'}ysG乮S<^]A _A}]p튕*$Oy|KRS[{RK �: ew٧^RҁB!<cy~&7wR�?'UӼykYisW.`0}cx`^Bڀu� "^Z|yChذ](|'' gƷ!4 @`|y9b0LbK>b0~BҟpH`¶ Y_<dHǝ0<ѻNd'.K1�M͘yg,XjY<6�R90lk�8e]5bDǞu!)??KH{Oߌi`�8/)ϯ||Z<^€%$Vm� +r{|ه<B9Ͳ` +F2؇91?1)Hp 0mXD:>:wڵ5L2R[M+le�pvKu;m|vvٌ t8S"r0מ`8hӅNd!sTlnRJ�ٓc8l/XKx}6Ɨ[+gi<*I��E=zq~T\KX <~AoGQ)%12Sȡri-Bo%^53A9NZRS ;8X Q7{^P1 d06][I74Z'?$'<)�v֟9+Mv5=^JV�e= Qf@W;F<klZR wQ'IծC1h ?óS·ZID"!OLĝ9cTK<o@i U-ۿw߮7\yc"T$-%(;v63٥BX|r,rl2 äPMRuG jf]9:0{>R)}'0Df2M <G m'i@ƱU5B 4{O>yC?zt/du-פ(p=ފ=vgM@#4)`!c[q<Q<*�f*ע J&oi@MoC=a#$CH8H.Jc^֫O]{QEG5Dd" ܀X.^B&{M1M6<rr!GkJ � 3<<xmrXZ�|GPᕗg}aϰ?o/#Yjk?J{ oiț'RbT+&3Q'< _86?T3+ZJG YwM+kyia4qTzijc=I $B+۵[SڒR$ ל@54?V ?0||JS-3ڗ3>Db'^,'bU ֤KӦ-{?+BeeoYh;궃Gzon Ѝ>b~KG%2 қtY _{ˊ/_} B¶Oi-XMLh੧>G`ņSxiudAaޟ]tȮw &=|MH`Ȧ;^<BB4Cr/k60 K;<}-fJ 42/?1¬!ARNyMhmn ^aB?6hE�7Woq{x^v_h U&/w:,h2* ٥Q:T7�C1^!,6L܅avxFlsS~g9gx!vBH;gIvcThF)ψ`'fglRٗ$YЦ?D({U)D{$iaU(�h~`@TVyzo\''&s ik�YǸFQ,i5QE3̢y LZ_ O FDmܧ>eT77d V?׌j0 %F os Fl WL=W.\0]A|HyH.;Y*v-LĢl΢ dcjԣ@MS/2nu6CADf3Z7O_]s}]Cټ͌4\"hJ$K$)tSNK'N2X(;HIް@P�0E)3`G"|m$�`Isz|An =8yܹB8T?ʥ�^R*dP3>}]y+9dcl�{G.dg?zS6D~RHTC6(Uƨ(:te`|00W�0ӭv�H^}$ 6p%Å&pSf!DyS ʙ d~l�AM`MS%(pGԥ%|j#JEUWϚr".85/L�Xҳn?A s K={3f~MY0D9sK1(8` `k+Iz{ԹXy|S1,e�fFZ ԽU)�4^kW�<? 堂h(E@Um8JcIt: .Q|g9g{*gO_B#*n9 �X<#K)m[: _Ҡ?MK(7`@|씙2pФ<! Tb3!hnDS^욹R @7@ fP_FZW_^�tO)'0 #<5ʧfG, �RfzjZ 8tHIzr -)�hV^i�l} ]v$(3?@fS h*�*-'S2xpi=k oYz%̞629|  .gRzCkk)s@}c?@Ο4m2kkd'Q.uIe�B:HbH"/-�PuA+nӛ�� V@q9'KyW S>AS�P;c#]TDB9{wC`mӭ]h;��G?6ٷR>A[[#&\O9 R.5Z �'P.u m8c~mC!#*5 Fq�i8�K D58hF4&~?њU+/@�^ǰ �1^sQ2fxwD,L{�w6ܐ`>3mD7_zĒ^f]!%_i@WT~  i\pW xAK]oB hY�<>F0bBR~lp(�P6;o%eD!tHF{ӓ. ]j@G6oa _/ O3dkFN&]zGB$ѷ K7�ߨH@ZFO} 6=<eZ ]rv5ڣ:cℯ)!ޗ18xǗB}&e=) nF,eͿ||G0,"'� geg:ݚTɃ#޿0}4RmYZ߀)9=a# }۟"0N~8|"̀wSNdl *6pԦ@hO*yML!ҿ,Uij>o7~hK| -ϐI0�n6G!iCE-򴇒? !:!'Qǫ&cQÞOڢOgZ4I dlh f3񩰃O:ԯO4I,iIv-b+|-2ɡHR~:H 82@f@k'�ס<Z0 �;ˋ_R->LU�HT(\AngJHM2%3y|GH�`Yo><1UCBxM�j1 8y")KGO`gfJEigLEDFhGOu@e= �R)pk{ .k"gddDﳦcyײA4PkPc �Z3'ӧE+[$;5ύX,[R5 00տP1YM̷ED2)ojaBºϴA HI7 -|WsΠM*! IpÇn,9oJ)^EW^1i_+Rp �`yoOq6iW'�[UAE).7@&O $?Ӫ i 7?#Zoed,N9-G^�ͦX@�PPԱ&_2o.lj�4MfJG?hc�TG0;�u�G�ŝ&Uh[%_xlUCbp뛝G70$rmv�~ �[4|h� 8=��l� (�# ]/*�c=V~�|h}sW}n:Ӳ� L M@oi v'V`�pQ,:h  H>qCl;;~!,md`A`c�llćR>!5pF)O??Ok�N`c'Ќ6C?!4 +2gk<ݺɒW+q�n0 нducL`f@)O�*M�!� �@]5yZp_�L�5tx?qzndoj ou6P,d0?uU@D$R[oMxX<ǁ w�8~-[mOF:33AoP0L @$v0ϗ}7pS&A۞�E1+LBٙ:.s7`t2( *Zt:Lu ]\W쿯;ADio_f:YPt %DB(x}{�̹d�g]+9f@\I~&[�po*_ ZDi8hhGP?3̛@($9 1¿qjß[%MPN*88D7UP33eM4�@,J&PNN7&>٧{M^˫ 2=BGIq,"̸t!!JYbbLHi3Dr - TV̞ Aiu]LW7_w?gSE5IUJqZ7FN 8TF1Z@]B/ZT]Q�ГLᰉ>N ?Gx@FC@tfoR$fRvGY o]YKFM- !##?#I j.Ejz4YFq- ,bV�祢�^!vEf֮rJ"ՙ CbT/r*OlJ*�U ߝ[2.+") GlI~Mᐱ(�gLy:tzu,F=_UZWEFu-(y8y<(d'1#$UŚ=)ٿX}7!nP0\*A`@Hg6@BHw. OS&nj7̥iUMubwQ)x�$^ -iQ.Jw̦q�ȪO}5/a|�l^|޻}#�E8|r%J0b:G>C#z'ڟ >+ɧ082oD%>3 Rb-Z,bR)4~҉'N4G|m7>\D;rʢ|yv`|>fDPlUnrk聝nM׬kp�h��!/_:u@mRޗ˨9dWǑ,Վb:zh0UÏnW'_ N_RB,Uc@@Eu  * ] h vZf330Y@az FQ3Jv vBAHAonOgM`pw��xW.֯o Ϟ:639!0l,ծhEoV"o^6+rFG PKTQH%_I2(siXe##*O-`O9[>^N7r;:Z62ӳEXن\ qyZ]D$�stpF] F;"YaYb:>��P�xɗ 0[�Y!*M}q:{ZGl i~N5$C (%b:m]$|R` H)L*-O@'ẈJY1s~|//IP 8 >k|wFjԟ{cG?Bdh] s_ϐ!)��#{䱤:K(9ҫ^-[7|qv+N4dW%EzX1>b`F& jY .~ V׮ޫZ*r`~>_gC(C&>1 w8N+ߠ#K,[O'x?UUD<0,C@* nPdό;hH75laaFT'(iVTf:Ov^%FC(vH?:Da~KMC 1�� bNvsEY/[_znd(W&>uH2: h(5</:@{،4a@u�tn|:6.t?5Ƞ;| O>z<-XYEj&ip �㔦"#{ H&WO}˗ZL/O'#ܒb;&t( ,|[۟cߩs3$_m}�`nuر6L :y*P =&krDQbX)9}Ri61M�Hu9(db RuU}U/po<FÌxXNonzç5+)H#nѰ f>~ ũ m_e?P" @= �T˯6P ] e[%%,)c?%Rbϝ)[W pWMKӎ_0 46? :@k�@^&�7:P: {6ͬ]M?cs8X؛Ɨ vN!ۭo#/s'  'N&Ǹgty˿7.\F֪J1^A6ҁlş6_BxHh=5~zLϤk}CY3[x謎T`7D菫gЂD b{bA+J[N9Z $]8B,I2ǟ8d70­n"K} knζDyi̅nm5ؕaE ;mMu3>YE?Σ.Jx^gT l,ʐ)|_1o,T7.B3/|Yi'73z蝷rYeYt�ճ$lVx5Zѫ{i=]4)9Аnr^2\Drj< ` F<opQI/Og][mw%W^)x_(kگ0\څ}[Ehwcli9!AaJPLh�8A�m'<vށX] {d¶ÎnK~'L8NO#hy/DR} M$86�‰ �2 [qǞ;~& CnsD];QiXnjN<>^p{]D?G͍Т<)Ɨ=X 00h n<~1!w<y(虧? Ҭt|cXuu 1 M#dMkkЎ55 KkW FA\^/u/0;to]alsXg't P�@v^~ޘW\ޱoی$vPSO6Ԋg>G)eiȯaɟ>z�#^F2B] 3f̠F;䢧 P7Nb8+Ե`"eݳmvfycF %ZP?Xp xJ1ij|X:<?xC<x\;�~6D闿x=ڵ|I2+iz b6Z̸=s'ժׯ gzU_GLu6(_jZ`)| W[* %d?ݴPK5s}2twڹݬF޶|T+Tݬ?" 8v!DZ ِzqAW?'>vGz }gbBBaq<p3f� VU׭+*h2Z-[/m/*~(o- ;n#G1?a*(cL�@C~睿GY4`'=@VP&1PՅXvk76s񻯼zYin@WALLB,La퐔R[ph7=IIǥdggQ <|?ʟQRJ1(AYDH:� g&"Լ426D|gqlH=lkBx‹G_p PLY?o[~ ABrJs3+3tp` aa! p!n#_Wf؅ôSw?kmXa?{rՍhihআf䏧78jʾ%o}M..3C_Vu邾TӄQ&):Qaft υ7j֗Q)79y`}�L0DGvV<n3Ah뮛L/>9&9Rp h֞bu|>x.xTQG oMŖnKZΗ.FR[Ũ,E1dOr4(+fG4}D@~H;Tjzv k#NbS0G6v)hհ ?1~}3tOu`8g88;'Cz~#SaaֶVg9kGVciP|AP�jUîUs4ن 0=HHq̐=zym'a; w'>VUUMZf(c={1OΨQiRal%-I˖I'O1:vR\ŘjJ@wn 2 ULƼc8m3F^9X }¢ғOً?a8әrr"*$Iǿ`<2^ܹKV?v*-^J{Bxd1_d(<q#ᭌaR]PhʔvbNj�g-+hmby ءt͋P@_ J):QAAl*K]T ~lҵ 0 Z>霳>'үN2>=rHRAl-hc7�:jY"x!x g G!ՠ3D^qaQ[wBEvkusRj*J5�FF&e (Z=9@j9<zcm.,2?Cn ?ٟnX :$mf5c~sW$qúE�bM@;I�8wf0"4;: "bom' Fmy%YY6q?/4atA05[|oM<�'Is+ɚaJo~nj>9>%Ey_rSi6//חF5(F8aT 6h` 6]BI9�A5ta&`KSk;ׯ}D<B`. -pBIG8L E7 NP@㏫g>yv?ua n6�:E  B}0h+ !~2r߁=̅Zو-rh5k1};g-x"�t`>լlr9ɍP.!~9TVVM) 'V�`j/6� `,�P��>FzG%cvy~D;#gVY7oШ:ul6pT5NZ` D!GQ Gi�4Hxvu+''/_ aKlCGI?l`і# u\^ʠ)UI?f*LBB?O4n}" 7 5qw0Cc,UV3b2WFjXfܑJ< GOg*q8~E}uw+'j9�4F0= 3cO|і@3_7^"9BOKrv6 4A\PAs|0?8(i\ � a]�`[M }.}[qD:Ku:}ji`өYQz 6\Ro7�ܰ} 9-�Q$: sT\o;sĎ$% *u,׾LfFύn�GzZ0l;Ǟ8糖l�{*#9NbKZJg`*uri�TRx$/jgJv|=M�~/c̦+/VAP&HzTHi-:&@Wt}Ԧ�(`~m� (Ɯˇ雯1�DjE2}]|d;(ZRcZ};Il3|�O>y8Y�O2K<D5bz$GBL~VѭMmش>x߃g|q6*Gn~G/ {ުD"Lw #E ?'-Mm�n.jn1tœR17yG(rPogf7o {b㰐~_4b@ .v$CoWM��j�`ô嶟? Փ`_ݰ-P[�@o@&c;w)/AWA!aJ5j x<w+n ��a $Xhr>#0j2_Fwd K!X*=o pb֦@B:CuשT\Wj,XCgux MPHBFm �zIo{.4dk9ݷTO?1W_-Mɞ?~!$m7 � p  ,k/߷CV<`]sAKի+S۝l0F�$}Fm�&x c~/;>q"y*69LL"wҿݵamKԖ�ߧjPhOdZ5D[�Aۏ_��$ %Ф�0-iyQ~XV&Ġ3_om �`M �bh�]AMk;^Տ�!@1Ć0�hACW;ގ-L[� ;~�Xn&ZxNO[� ,(wTC (wh-m�:�b@2pk'A �2)ؓ׺Osi[@;!`v�S;�vpjN��;8?݈p����IENDB`������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/ReadFloat.lrs������������������������������������������������������0000755�0001750�0001750�00000002540�11450447710�016572� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ This is an automatically generated lazarus resource file } LazarusResources.Add('TReadFloatForm','FORMDATA',[ 'TPF0'#14'TReadFloatForm'#13'ReadFloatForm'#4'Left'#3'O'#1#6'Height'#2'_'#3'T' +'op'#3'4'#1#5'Width'#3#209#1#18'HorzScrollBar.Page'#3#208#1#18'VertScrollBar' +'.Page'#2'^'#11'BorderIcons'#11#12'biSystemMenu'#0#11'BorderStyle'#7#8'bsDia' +'log'#7'Caption'#6#20'Real number required'#12'ClientHeight'#2'_'#11'ClientW' +'idth'#3#209#1#21'Constraints.MaxHeight'#2'_'#20'Constraints.MaxWidth'#3#209 +#1#21'Constraints.MinHeight'#2'_'#20'Constraints.MinWidth'#3#209#1#8'Positio' +'n'#7#14'poScreenCenter'#10'LCLVersion'#6#6'0.9.29'#0#6'TLabel'#14'ReadFloat' +'Label'#4'Left'#2#16#6'Height'#2#14#3'Top'#2#15#5'Width'#3'8'#1#9'Alignment' +#7#14'taRightJustify'#8'AutoSize'#8#7'Caption'#6#14'Enter a number'#11'Paren' +'tColor'#8#0#0#7'TButton'#5'OKBtn'#4'Left'#3'p'#1#6'Height'#2#25#3'Top'#2'7' +#5'Width'#2'K'#25'BorderSpacing.InnerBorder'#2#4#7'Caption'#6#2'OK'#7'OnClic' +'k'#7#10'OKBtnClick'#8'TabOrder'#2#0#0#0#14'TFloatSpinEdit'#13'ReadFloatEdit' +#4'Left'#3'P'#1#6'Height'#2#21#3'Top'#2#12#5'Width'#2'w'#13'DecimalPlaces'#2 +#4#9'Increment'#5#0#0#0#0#0#0#0#128#255'?'#8'MaxValue'#5#0#0#0#0#0' '#188#190 +#25'@'#8'MinValue'#5#0#0#0#0#0' '#188#190#25#192#8'TabOrder'#2#1#5'Value'#5#0 +#0#0#0#0#0#0#0#0#0#0#0#0 ]); ����������������������������������������������������������������������������������������������������������������������������������������������������������������mricron-0.20140804.1~dfsg.1.orig/_winscript.bat�����������������������������������������������������0000755�0001750�0001750�00000000735�11050365466�017067� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������call _clean.bat copy .\common\notgui.inc .\common\isgui.inc c:\lazarus\lazbuild .\dcm2nii\dcm2nii.lpr copy .\dcm2nii\dcm2nii.exe c:\mricron\dcm2nii.exe call _clean.bat copy .\common\gui.inc .\common\isgui.inc c:\lazarus\lazbuild .\npm\npm.lpr copy .\npm\npm.exe c:\mricron\npm.exe c:\lazarus\lazbuild .\dcm2nii\dcm2niigui.lpr copy .\dcm2nii\dcm2niigui.exe c:\mricron\dcm2niigui.exe c:\lazarus\lazbuild .\mricron.lpr copy .\mricron.exe c:\mricron\mricron.exe call _clean.bat �����������������������������������mricron-0.20140804.1~dfsg.1.orig/xclip.bat����������������������������������������������������������0000755�0001750�0001750�00000000130�10426745666�016024� 0����������������������������������������������������������������������������������������������������ustar �mih�����������������������������mih��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./mricron ./templates/ch2bet.nii.gz -s 3 -c pink -l 40 -h 120 -r ./example/clipnearr.ini��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������