From 55ced1343a6eda579a6b54a09dd8e6a9ce4dca15 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 4 Dec 2013 02:05:44 +0530 Subject: [PATCH 001/115] Updated application folder, fixes #33 --- application/Info.plist.tmpl | 75 ++++++++++++++++++++++++++++++++++++ application/sketch.icns | Bin 0 -> 174666 bytes 2 files changed, 75 insertions(+) create mode 100644 application/Info.plist.tmpl create mode 100644 application/sketch.icns diff --git a/application/Info.plist.tmpl b/application/Info.plist.tmpl new file mode 100644 index 0000000..787f56e --- /dev/null +++ b/application/Info.plist.tmpl @@ -0,0 +1,75 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + @@sketch@@ + CFBundleIconFile + sketch.icns + CFBundleIdentifier + @@sketch@@ + CFBundleDisplayName + @@sketch@@ + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + @@sketch@@ + CFBundlePackageType + APPL + + + CFBundleShortVersionString + 1 + CFBundleVersion + 1 + CFBundleSignature + ???? + NSHumanReadableCopyright + Your copyright here + CFBundleGetInfoString + Created with Processing + + + JVMRuntime + @@jdk_folder@@ + + JVMMainClassName + @@sketch@@ + + LSMinimumSystemVersion + 10.7.3 + + NSHighResolutionCapable + + + LSArchitecturePriority + + x86_64 + + + LSEnvironment + + LC_CTYPE + UTF-8 + + + LSUIPresentationMode + @@lsuipresentationmode@@ + + JVMOptions + + @@jvm_options_list@@ + -Xdock:icon=Contents/Resources/sketch.icns + -Dapple.laf.useScreenMenuBar=true + -Dcom.apple.macos.use-file-dialog-packages=true + -Dcom.apple.macos.useScreenMenuBar=true + -Dcom.apple.mrj.application.apple.menu.about.name=@@sketch@@ + -Dcom.apple.smallTabs=true + + JVMArguments + + + + diff --git a/application/sketch.icns b/application/sketch.icns new file mode 100644 index 0000000000000000000000000000000000000000..2bdb4dfc22bf16a82544999627970c89d7d63939 GIT binary patch literal 174666 zcmeFa2S8NU_QuN;idbUr8e@r3qp_E$vD14UV1^mmF!VC?dd@U@?@|>}5wM^Lj9|fn zVz06H-lMUXd263DLs8Tu{}}Ik4{mY;9Q@YVd#|j!af6mF|(&Y$#oxn~@MDk;zJG zw$xXat;owtj>Qv0WwJ8qrt*@4tdux$ULxO1CRh1^8DE{S!PPCP%Pj_1aqAn?R;gjC}CJYu$Qx^kDVRcmL-#Q3h?)KB_ZZJFr;RmR1(#rZSnM3!7za%rv*KF*7kXl*xP?46PUz=9VUg<_7xun5?rI z{1{v@vozMxPLh4i5ia|iBjm7IpB^EzWrV!8BlLDKKqIthJ3=Ev)2}^3Jn7RT6p?G_ z&~^=BgiM)iZp#{4TU#}+A(Pp>hKdndlWW*!gnIHdG=>pc5NpVv>EWiNL{U@v=tI`( z11`4u3O@aR-`8yh@X=tET-;IBsuvW=GW;ogzCcDvO2JnTEG^x#W$Wg3rKRPi>sA&Q zB{AWa49t@VX06Yj4qb##%m*M8usm3Uyd&3FVNyt`}A=gNevSSH(gsG9orOJbrytUM7#@?0~Lk78SxY z!BvSMQW)eAF7g(7r3ihCliXbG(e=ENqV(i=9dtQNEC^zSc*fyw&Rl4AQEXH61F6f9 zv>-A(G%(W3D>C0d+8Hi7I@sCy2BPa3@n}fl!2x~&fquS$(32gN>@m9m9JVbngUKnN z92~&+5ee}ie@CAPSIlk%T(o7eY|x)y3gZp%_4e>|_jPh|uy?l$WuuEs8_aqDx*ibZ z4_DoITqkFHJ3D{480dm7Mlu*y=z4^&mxn9Q*$FOk*kR~Tx-g-J8I~3nmgu@CT;)2V zi);@sPg|z7tu7tPI0&CzuiXNYPCvMd&p=VfDUWnpP}=s5kZ!ghUT~#6|Q5(UCj-Rb&V`QTi28$lVM6q7E#vmHkd3{ zDOuK0hJUvVqrP$(E^k|gU8CESA;z86x(wsnlws88$}j+x;RsX`pDsi4BE}lhei??4 zCGqJp3?Rx7V??4P|DXz?T>fGenzd7fo=`5It-^VX<|>3DoP=(mRTY{MRcK*qVc4n) zeH2w_PF7+6PgWsj+R20sRcL^!5Yy??T!j`;h0qpEjE#&8jTBX=sXc#x%qp*aRs zXljBRtC$<0D%8VtX&qJgrOhz%i<{y9u?lm)v>7f>Y_l1*szMLg3^8ux7pf5UkB>G( zf7lEIa?)Ud-*G8 zmY@IlGkYbl_e{RmoHmZR9H}uUy-}MAulV0AHYwP(fs{`i*lr0x4eCR`oRn7y?gcBf4_T9 zAXPhc;m8rGboZH~0_lVu+fVFlmRt*xWgxinx))wWy)-JNI7G+@$+wYyF=kaxO%Eh$?nmt78bT3C>u zm%Fs8syM6hP)=#-b|IfHmI;(-oQvMfI{2SpqrglQdF3c-c+}`a!YwCpHQX*g-dGFq+RPD%U&EmB$d`Ze0cf6?kMS)#->Xb z&!5@1XZP{#aJ$5ck*X_Oslq(u{^c>X$x_p&uixFga#Xra`up9xkG8>VOQp5ay6Wv4DmOJ9J$B^uwyo>rYxiMF z1k(rT^UXZgaH6=Ok(CLGj@u_iS0E(Y~Ty2un^vZMD+bi!LynOKB#oIp~KR(lV z?&#IVx{GJd?L2?>?9l@!wtrqdGb24cEjv3iIVmakT)*Rh_ zaDQw}bRaQ96hCo%ZM@Wc&pz4h^NqJ&{(0iw&70469y@jF%+af7PF_5H@{06K_10Z$ ztIEsQ$n&qbP5!~$%k@)|*RM}ZNXRNWdgSb>Jq=MoWCUJtLT#M1>z=o_rP9W_J$08Z z{qg1rcA0+V>izp?vCZFC)}TCG2m0;jA(k}&-G5q2N^)}2`rL&0xXh+waS74C*KOh1 zp;e~v!V+p@rL-L{?%ozk^|oAm^6c5Q>xcL4+g4Sz39|gN`ADP=sKe4GCnaW;CdI|Y zZas1$HabdjXupq5vwn<}R{!AXU7_^XEsy^ADJD8; zM-()95ltXa1PB+@#MDMfslPwGFO(WyxPS6;Z4K(TU+7;@T+R7I4j>+uU~>lSAvqGU zSR@h(1-K(I2r4gh6AB`hQk#xG6iCNxy>a_a6B(qrnYEv!(00foAZ95sAs&nC6&qW+ zDk>^AQ4s`-RD=;67S=>V7)sM^f%K=wJNJIyy1A-q;|CqHo!<6cOQt45khnN3RxKu` zY)x#WomhkksW^sVkrXlvjTdq3m;mC4q?8>u1X7*f4`10?4JnIe>~k%&ZOX!u!+gP# zM@L6(EEk%a!wZWLMmaJvBEo@~Hf3J;u08wr;x$pVLMe6Y*2|bwr(SybcVgl`xxp&( z7cCBSkLL7>m&b})la-J#Q-WftMn;B*hlP>RRCs~M5AAE*jlswSQcB%9TxzuER?`=D z-u6>DK8_q$lq9OL5t|@J!6G9d78XjeC&s4A^Q$>@aR1>Q7>o{wa8;PpvhMVa&Gp3D z;nO=Z(bYf7Y={Tb2$?Ms)-z^GqHrP{KOi(DIGD_Hb)Mh$>guLL@GCYV;;$to^|iYm zJUIIo61}BSl8KJReHR-`#6xMGnLlHO1oQ9g7t9aGA|vAj5;9NJdHkkb)z!OqA0Z=- zUa__I*s(|3K1|1tHt=?GzCSD;j8C5NqBTP}ktr#ntm2|VEP*Z-;pC*!cp*(Yuxi@w zokxyE)nd{gORBckpFg(wOT84!YMcL%m?;0FqscnP1YIz$J3AsGBc~ueEjb7egmar6 zv5YhxwtX93O{-}*c0^KZEtM|cwDG|2JO6Se5Zx6uKe7_!BNPZAT?_*~>{9UX(2&sJ zpunI2%%93v#EeLSm?||jTet7pyhT`R48L2bId!bMT3&wb91vSh10RUyoJeHH)@YmDg>nt%aRrRrS%md)GtNw{67o zqb{6rK9R05(O8r!nq46=*6tAzyd*pSw7g&#t2`{t*N3B+<9#q*yhf{bXZ@On-8I!! ztC|iSY}oM0B58AaP;4*I)KCgZAgT}(D8XPmMMQ-2MH-yEltL^})!)zG&yUad#e67= zxM9Uo6xX`8R=Tk;Z_lQ()q4-rl4sg4pDD;vffg4NLqsL^1BeQJAS~2BTIjS=l2QPV zB%L9uudk1fx3?D=m(B}IPp?H2JsP&U>P^|HyQB@`XKaFQ zR2g4exxT$eCq-w6GjsFF1Z`H(8?flkXsiNxR4lwlSXgLqa7Y1{9l0UaFF6Y)8245q z;(BR@8V+3o8hsEJsGj5Q$4^@B;~SZsf_Zm_u$~_7?r!exWaw$Uu!9Gso2xbw zha1S`{GDa+gxcQYS?l8smN>aNaLb_sMhuxu1csUoS?2G>_bpuM@%;A5b2*$v&|w74G-?)@P#q-|1cucO z!Ge`w#6A3jON;${eWMdgpn`JaV4^X18U%L3Tq$JeA9Zn%w}{(3B^LFXn_M% zP?HK?FT{MhdrNDIV0Br}Tz5BDH#b*TfeVEUtjY`7aBfrOTF9!|Yc>|HE?ZRsFF+_> zfoM}ksql0HohlK{vZ6aGN;ez}rNi;SBiVmJXY+l!rW-CZk8i4 z7ZH!<>`czE3NN_4>g47MY&C0Z61);qOze0qFF_Db2E;H?NN7-~SID0Uh_)yX33&v2 ztiNASPcumErO=T;~veJv2UrSNE z=m8HS=vkQRt!JYquz$vdKat3xS79C%SfB=&T_$PF7} z*H&k**isOmxo_XjP3|jJtlJ~KaP7ReE6$^G7dr}^g^HNtctNXHHf1z!a!qeuO2t`1 zai}NP5|S2^^g!nb97kJgcvv`OPZ(+pxh45))@6!)eY1V}pmo3BwStVDO&70T z%Ed6AvNOlkz}Z>Mr8=>QdhNsuELn3ht=OWl2rD!%$VV@LD=xUHAr3Ou%`-Ug;J%G3R$VyhiaS$0*&;6P zL?L6U^8#0_ZVa(0EGR6%@|7VX1jI5`(PE~iz>{}Ew|LZs;Hk2?4GoP53k?g6_aE&l zz%$dL{Ud$&===Z?Jv|B!7r0|?y?8M(4NX{>&!#P#$&~@YGPcUekA&!R7hC;(aBA2?&8D*Lt9PX+wM9TzwW6+zW`0Y&Rd*DOafi{;RXEe1;)M?9ht zXJDdC&_J78kWdnmx?DKMRcq4segSY$!hCu|oA-n+AGB#hj+YzH-o7#?$ioeXgjLJl zy;mIR6eaMKI8q%HYZ_3vA!k)_@zSMO_GI+P4ns^P+Yj1U6f;W%MC~V3ELgdGwL3oD z&tG?l192Sm_QpKBLBm@r-stNZpsUO9<@0c75mz-{yg$&Fx!hamh&#yVbuQ0;U20nD z2BPo4b5lCe*HPyoi;_4nwA3VQpHWNGm#<`+r&h5&QK9B_O1Wg>c!XF4x9Cp)!H{#swUyq^;bNF=Jf=@7?GVz-Wt zOGzu@MB#j8--vK7iiWv&4RRAz1oM3DtlW4!X9$Kl;f~$0J@x4rE8NkZW#_@Mvm@j6 z;sq~TQwK|zk%2OlY^qp%H!?{TEiMuZ?*`FAgF|AYVpCJ~G9($8uZp*KQUWX;?%vro zpd{DT!zCcp#h-{KcKpuYKi^U}Y%Xic5AMdER^&4|R3yB3o|_44hNbi+`giMt7demQ zu?rnU0;42p9$`BC7;*lqS=Kc~E0-@k3B|1@@>E-|@_gHaC8suc&GR#fg zH6=T#ASeardP6fKL*e#a?J!}k*jv|*!7;G5A!0!#l)v|tvp6go^Snfc?1c1y@6;&ZV+&@PCnkh^bZIp2PZ~__1=X-eybYsyf zc({AHxkd_Q}Rau$~kyYJ!`2GTP&_K6M9B%N) z&cw_R(&#`n4CPUvcTf~`P=EhKZ_oJD#I(rB7#^G=>%5lclu3j{cTtE7Sk!7~LcALf z--vc0bZR0dJ+cRCm&E=agibN&F&2)cLEfdS!absr((@DJV!Ts5TrlS@Tqn-jkPydp zJN^6|+sKPpG$z}R(AVTe#>&;7lMXPt>ir zPEK4W+t?^aM?Sxy+5uXl;^svxj7hVxA$Nj4Ji+qjCq!a1L+crg1@`rajRie|qr?}B zpr>U6Nbcey;8D1cj$IucjglMy0C6Z^y3`)DF=Ez5ES!ni(5&SJt;P!{Qw8#!3MVZr zgo2*O`l1^rc4w6E9-^e|w6r+P#Rcc75O5~+bjQvH`8jL{2YW|{T?e@0Hu3^%3Yj)t zczm(}5mSzZU_o6WQxw{;^J5;W?oa|kR~I;sE5oD!+=+oW&A~Rx3ImXn8nI!6ppCd# zAr3i-&M|mcZz99t7>t&ad{M&7+Y|HXgqmn37UkjsJCPd9x1%Ha7dE{hw%CrAv(~AN zaI`|0#`BB}$HMxfjR55~ETg}lFEJfxHlR4&sBq-O{AdEWW6X(8=;97^dwX82uf&eJ zX`_6uF(z&kWsO@=tchG1!t;jqh(u9W0ns+HZ~*EAvT&A-42%U?8j?l*k#1*ZwcJJk zbwhQDO2DCZP==7o7(=ezmFGd`H2Fdl&ZolR3iF~t!GLg2Bn(-{<%Wg=PvqzXd4b#G zc2rKLF9yOmo3>_+pR=%)vQVL{!gEK{5Pi_ z*bTFn*wG!l;yIuwu%#v>MhKfnFJ|DD&Et1RnFZ@lY&n=071|Kyt_msO0y`)O!b!x@ z!O?Su6HyFGg{TQBvp88P4n$2vTVqxd(8Da`iWHt3=0}Bm!r|u7D+3@$hv!u&1K3nL zBMR9b@}JEPauPx!!QPeWfq|xwMR!S#U_zNGB!vpe&OA4`L3HMYJrVPuxkI1CT$N$G z&=4@L63Tpgdk0t;ii0T*q5?K0Bb;1sTGA?4xgusMv7nlhGl}lfhYtA;uUvp2^mNR% z3#>HiFht73k_hdT9X#Eg&`hhfroqf3v6vM7Bx@05r;YyTB|c{Jp8>f zGE$tnc?uwh(0yWNB2%gfDM{zKz+Mi|{%FXkOfY+8G-^9SQD{pI#5fp>o>5TCCG@_t zx3%?f1w>8Xj1dtr-J_KxZX&MT|O-xpxm^x#m; zMr7T|%h}n^*_g>RW?~FwmfHZPrKQ+HNZhHwgl254SSgUjoIAnxMC7gAnOy8KCB$2fmi{-p{QFo5DwU9x#v|O^pOVq3=FqYq{x_rNL06h^gav+0I`H5Kl znM`|sop49T%4{oZXKQPp$Y0%z4U8FfmI7EAx`l7dFr<(|G@i4)y#Q_p_-XQX zP`?*htFs&(rg!hJtjzOek`hFP=}#4!3Sn|^Be6n(!gI##)H!Sp$JQ23qPE11AQ7>3 z4;yFhLe;^}&f`^RojdDKZn%B3WRGy?<0?Ql69jIByau~?{sAT5b? zUt13k!@eUlG&rl4`TG8(q};a`dpy$unkXs&p($mu6+eQP{?6=azPr;33Uq*Q^^LCZwgR;OZpi6%z&E{TTrv$Ng2`!$Zs1{2P+Sc zFt)q7z*t$=%86klzc*ZurmIWdAC1Rlff#0^Bo~95gEynh)R|*}8l=h?1&@ zi3!7mVa#)jada~>HrBQFF%uIb#q|Wb&7*Y^!t_(&K!|oLoI$tovC&#YwpyB*z}FWg zr@&a<+{D7w-I~i<;%z1%L@+%eaIwuYj%XDzYl@YX7!Eu*L)FH{&BoA3OWw0-rZLev z7)V7Ks~edZnixAS7SClg3kelMU3kvc0xcsWYYQt&D=Q&L2^cC?u55V!j3Jq&0#ho} z-=EAXfuXXQp@-gNOAOWz-H=#^s!dK)FJ5Q^UKzJFx=`EV7fn4&YaJ^CxGgm+D~1z` z$uwUqmiK676BCyp4SA9(8yMK?ni66HU5O5^O|c-7VyJUqeoL&9r?Imxm&+Ey456D5YETW3icqPOjg=*I z7c)NJMrfg;_uH?t?OOM7i6Py8h(cV}`TE9M~qb&2%6Ukdj0LmXARGtZl5I zuUG^Hn+q)HdPApbFvy!htq#pE&5&hkgc0lBX_CF(q)BEvCZ?w3{X}Wdmgw4$It&&E zv*;SYwU0g?b@mzf!TO&-Hre$Yjgv&MPix->N z*ob6eC1qovm$coGi`F%YZg)f!C{lL4tjVKQT(N`yAC5Ku{W&89Uw z+xqhkj<$oN?ciuTINFj9j<$oN?cit;LGl60@gYYT-@(y#aJ1w*X$U0of1jgO5T^eL zM~em0;kA23$o~YSh2KE_=OAq$1cevW{}YfFkXAWJ8-xYY$guxk2WcHkz6nSx`tL#7 zkZ%IgqTh!7=O8Wmz4A8zX$gn`{o=L-q|HkC`XDUz;Tlx=4+GcK%1kMpjyX-HJv=}fM|A?fGY84Rm zA0TN<+97GXe?ZbA-1Hxiv?v}2^6g81i=s^m z0!*S^ik9&SiWa^50TH2q4z_A7A5pY1A5*m0Cn#FBf}-u!ilQa>@qa|oCgx)8QM9hD zC|clK6%;KVNB<`fZBkaw2N12qPKCqy1V$Sl_ZKkQ6LyT6?4n|9=3v5+btW|6NIY{df*FH$A zkQelw$^oIY0wA1V4qCCaB2W}4z}Ge`E!^K{SX#6^a+Vh1$gNpgBq>%% zwy?ASWq+2Xr8$_Qr6E{aRJhO-6f7-LjQWtJMU407SXz6JW|kHsYN<6#ODY1{C+A)f zOpB=T&%m@o;5C&1rlk`wEm@p^(n@kklvV`jOtb~UUF10B7f@OOjI}jNThSV&U5ilK z7DY?}y?%kEMV&*=(qf2wEsJV_X>Dv2FfGC($vXw|?+Y+31uY30vmF4|@OF(Bme!_) zrNx^C#h+toN$3^HA<#FVElb<&1D2M&Ma)bB1mI^;TEx5(_b31yQ0>zsEe(;hQGib) z%`b4Yh)G6wDQXMRG8GUl4*5tWAX493=vzRS10m(jvYSr5p`F+Gd@$94*4ODTt$0 zw0q!anGVeytwI6Hi{xn0ornyna`yE*o->-67LZnk5#!4&bwhcSKs? ztgNG>z=b~mXjKS+7D-`nPgJ};f))Xf5&-IOU4a68rSLu^XjN>i5kaeogb*D}jV1|N zk#QFzaCmQqXmPoeSRwT>Ln~w`xx%|1Z2_T0T0%KOi_%kIr~(MB?qo~3O4OGLS_Z?3 z$+STPEfN!($_ZLB*)anu5VT@qa8VxsvYrO*!4$7NKP@Ep3?=77Iv(wna-|gb-SsKr~h52(A3Ca7~&< zTZEPp>5q<6BtY9*12?2v&mz)EmEdP>12vQ&72ly<_H_Q^+w+eyJlI=hsZ&7pu z9bE$=0|4aLXOT*@ zf}N#V+c40c6o}Ya6@r~LYwp~rSe5nl4Vff8i|eZE5csSqiO-Tk^d)Wi*)DDPS#fjU zMQk#O&*DI;t0R0C{nZ74&yqUW5~=Cnd+ zF=AlY5@25!$r)M|lA(pdpiR~x5n4sJMHNre)w5-bTL@Y>b6aXF=vU=Mi#|YTO-(s7 zXF4H-Rv{uL+K;l14xBGrAX;3DrfF#-hiK`G7PW)X##v<%7_E)KQbmr@!ttERjIj`P zP_$rh+u=rwJWD#Ufg7y?Y3-nBiJtzK95v;RRq&g3@>lHyDbdP~wu7SOeN{W! z|36W*;rM@VN83Tsesw$A|1FAk1z6L_?P%4I9WD6XknrKZW=H#1C|V^~T;U4)@7U3{ zOVJ82pKc%6(TWsd{{=JJj~LoMeBYpt&1hYP|DG4^|1Lu7;%f14dC~q=gch8dNH5y| z5TRY$%8m9vLTGo_o^NrZ{g)BiAs@TZf;DA9db1ntzmL!^`_PLv7MWqT@}m7$5ZWOM zGurkMTD(1i*5e;}(f(C}c5Sst*xHL02-=O?QvQh-Z8NjjnxOsZV=r3wwqCR(LA$Gw z^r97k;i23dwiE9QX0$DoB+Km<%+D>va+H?Vg6Z{1)+AkoqYNQt}&>fijrx@BuR@h&&qW!B3 zEs!L*`-cpz$g#V_U$&zCs}QYca!P9}+GdCrug>y%1FItT2MR?Jo zSi)9bv|plV2NSq1GKOr=ix%_h)z*u)g`!1)keQf@5WHwz(eLS7Tw*^*(e@Qut0krE_`r?! zFJrVGo^9P|V`2)EiMZ7E&BzQss8EOFnByOWrt`JCb&^pP*=ccWf565*Pd> zGg`vbwZ)9KEkg@driMwlgR*@Y@}foeEe3E&1SV^r^`af5_-l1qd(pOs(9-nta@b&g zNO;jAoUTRwa|kW^%P>g)QRD~Tz89?uI4ia`qeV24m{?Ka=NMYzFWP8rMvEBQ47nGr zs=|vFLwg=Fqoo5x%aJc8(v?`#tgPf7T5a5D;XT>trdzqu0+iYYqeZr{(8_RoDwxrV zkcZ&LjpPjr2-FC(qA?gG=h@1SmUNA6CHyf)i#t*rAnQmsT4YX2XR}?R;&Ea!6xxCh zF}cV3+t|?($ZIQ# zR@tA+15p9^iqgT27ELV)(W0Cq1totIqIGm|aYb&l;2ew~T2y$*j21ZsD(>*_AhejH zvb_T`qeay~VHc1HEe#M_dsGz?V#t4ypvAadMRGY|-7WwZ|*v$wnl0@#E$_SwapR!io zv7bO_m7RHLys#*w9WAn)#@TcaN4Xts1)E%Fp|vtAcP;MRO7Rm2EqY4f!uzObFoT45 zEZQZZ+QI7)09qOVv_#^787;xjrlhPfwjk|Akv(4f{Hzk3Ae2Cpw4()r7Huvq1Z}Ot zjTRBKo*5a*j@>*FK})*kicD!HAK1|<6KgCtq$MF*a=U7VX!C1GL)woaT7|`}Pyx{@ zlYX>d9LwcG2a@~I5)dsZinFKzV71PqHrvs1xprJ*8yjRtOF*#El!e&=SkwT9G^Uqa=y8|^5^fH9JlA8s_>??Pol|!@<$cfen zoM=gimJSdtGW}H8wYGw2iP0h}S}^tHfMUz;18%f(hBk~nR@1~A+-MaH?IeO2RyY_^ zFg{g zX{}8i7#{9nY&Wo?rR!P&NsH!RM9^ncIs1x8S`jQDa-v0B0mkTrtY}G;7VQbjgcmI_ zU22xbq!lg6(t4ZWFmI$Bt^ijlJSUtfB+O`$oRFblX-ThE#L}X?5*c?U+-R-1%q3oC z%`zf|43*~yDufp;ayLgZBuR^8h@=9NmPjfD(i)l=8iO0HXpSW^5JhZnltKtVTB{Z_ zTC_Qd6(B8{p9DzjhY>E&qGpg*p@M14-ErY1>^5GsR^UY|04rJrNQ?RuDqqZm>Jqd> z3>LzOgG3yy5Y~<)Uujxet*mI}B&`#&qSc(yY()7pxlc#HX$rN#wpCHwHGZyX-O+*ghL7ll$KQMM4+_RQ|N@cz-VMa?ru)-FQ7A%e#Ld#YhEt7>fTC&&Sz(G^35J!uuMFknr+6HKf z36NI!8Iab2!yx;CqD5f_G;JVhQ3`a@o$2XeOrW$lAtd+|N~?>UXj}R>(dbNcky$FH zt1h>pMJO!-mIay;@Q+%C)d1w8c8D z-Dqh6d<)o`=!6+(x`vkdU7tzp_=Hz*Ee1k)<4$x+KiGMFxvq-ph#AFUP8 zxE4wP(@HeZ&0vd~{b;+8ezYV^3yF+edKDT74W=QM7SmDH);81A($cX9V_Qvx(<+48 zbES>5%4EcWD{Tu-i{9CFwr}C``7$9uzh>7 z_ry<(w!8Pe7N_Q~`Pp6X?(N*d#Q!Kd8rj{C=YaDyNBprir}Yd_D3nPb|H#+v za0;cze>nN%xbDhxfCx|V`MQH`Pu-hb0W$u7K77c*R`LJy)khOTW&kn%Z!rBb8My#N z{N(l)=xcv3nOFcK{`RjOt3Cbg^7vFL^_#@sOU8%r)C29^-`D=$VIn>X|82%k&VNUI zDwVe5Yp->C`pxrC`?m3E-!?vk|EA;r#_>`3Z#jMxp8gH<|9>Dp{Tq+}|L5`P-+25T z@xN{Ucg%ms{I_>L`r6+k&tI_nb@ZQay8nOU`G@e|wEjBccg+8{tiO)@>&U;3{QKI6 zjdt|q=Z}v1>!`nu`fH~?zV^2|>Q4zi(Bn_X`S)w*T6_8(`PY$u9rf4Ie>(ba$Ntma z{_wTG*RlT)`%lN~zu)%!*D?Pc^ZzZMe>?K8Bmcf>{y_qE#Q)ldop$u)=bsM#>6`Os z-;#f$A^`0h*55aek8a>wjvw$_+L3n3^Q(W0tbc-k-u=~swG*IK{BOd)w~D{4o!k5B z-zri<9~86z_*W0sP5_LIk8WT=JD0!ux8}>^!#gmjFTQ%Tj{>|P!YdK)|DY6obor}) zgM9mmJpK>=`2@Te)_VLDyRSap4+3z=@bd9f{_7Pel80}OPqF(Cm*9nB^icoJA3qfR zM|bcdd6;7K#DAObKxsZ!^fljpinNQc`E7!Ce9 z>QUYTqQcX0zXAl{In7k{s+JHLf-~C2brPFSZOl)N-l>!B|bj*nyyNrH2)(rQR)Ie zM4>3t=}HtCQ>oW5BL;(`_y_);MTX2#sfQ9p*Urt((SLlvv;5L~j&1){YyR!1ISUfDnjSp7L#ap7rJu)Z_xF2JmzeV|S^e3T zsf!!~@O78(7xxW5Kdo_p{|wD>JI+-E&R$nG?v0F{^z5m6{CEA&X&J1`Z<-UhJ7wpC zsf9V4=FyV7?O9aSG~xR5{XQ{!_HomOU)glqWZt7o1&{4$PpLZHdyl?dIJ2@(^hSg0 zO^>#&F=Z6z=KVBxZ~5MJMnH(&CntQj@AByNklKzMJ~s>+DW<2xOGIyCv-u%vgPjhAP9kDZuD>E5mJw%SySZYjU< zkKFI1`NV!^c6~`i^6k;{k5}~n!OV6~S`2wQe+gZXqydG>c_ zQlI`|$!@eek?%gg@rsq^73-ak*J5#;Q#HM>UDnyTbbH#V-Lk<-5>8Y2g{?JKV-C)i zh8a%}veihsnt6TKzSno(9o}~4?9Ot7l7szkm9I=1{?p3SozpHaySICN&Mc!Fk&n)w z^tk)#-P1v`h@P)w{9}fW|E=g=W*{Zvns=wgL#(n3f4TbBaFZ+~!eG~fQ|tiKqs7-R ztsV06-pLro!IviW6r1%A7xjyaI6cOm;qPMLydzvTc6Hg*Uco2qjjrF?=a9ZW$=mJK z^s)5?b*pq@4}8B^>!63$=-R_Iq8^%+dgmt%^4v8(w9M}5qhquB1a-EWrgL=e!QT=G z&EOByI{S3jt|e*X*6VHAP<8j@!$%>%xyNs`G(J*#Y$koG*MskV9%wz!#J1G=jhFiB zo%(b zMx2*7;xN5qtbNDM26>(y#UJKf*L}3d@)1RJZ%Y5-af8cDCT<^6jLlx4G}|EBAy+x_ z`{667`C6Wn9=t7Bn-taP>^#mUUb9fvE7W_U-~PMe266G>^Twj$KHhtNnzYS)^oxlP zS^871RlQ)8XJm@wWB8B51Gb#>b9FHN`N^!xw9<*udfj47Tn-PNaWnnbfg}Abd-C^< zoOSr1N`&)~w`v%tBuD9rYUtdzdCyrcqw9{ivZ5OXt{&Nk+2?SWgPF;~u!c}^j<}C> zbC&6Vm6N@VUtjt4e5GfXv?DWSANQy)Ry$i*JIgX9O2eaR%ptvfrzdhp<{oFPT{zVB zOyt!rIgbkq9=*&J?>RQ#@O!uI!vklDl)qnQRF%;6yNguuy+78gv7d78C%^v5Nk>?F zEFflLQ%dT&a(%Tg`Y%UlYhe{h<4X3SpE%PaTxOw4$s`Fc<2FWu+T-h}Nb==*a+K@HE2ao;~r3Fy1)(GiixfjGxA&&@hD#s$1B{jT?6*Lxe%BGY)YPn^2;d%Kh))qKF8>`{UowYRc za^$_xOV28H4xQK;%jKUedc%~&Oq_c6W-8BfN5E9|_$CQq$Vbt`Lu z*4eB-deVBZW z*3wA0S+samP>q+9aO9d-rgxqlsW|xXfZw0#+`~gm%o+}jSUr9B`lxZki)y#Knmn1r zf4t+o#kogR?wHNRH;SKL-mtiG64$43>bRdMLXABMSI)`wC$BypX z+P1DsNffIo;WA6rFQ9gW@p*U6Ju=Zwm*FS+540Tg&gG|u2Zxh3tmG)4d2Hf!WbR50 zm1Jj0^3}4<2kC!gZ+-Hz%VWK&eGf+QtKx2GxSXQ*q-LJnwl^MsO7p$Fsb~JH$yW1O z&h$;mw$c$lt$*ud7&Fgq(Dbgu`Ca!`yuS2v<zJH^Q&TX5Ok%YqpNOR-buDc|y44 zoc;dnSrPC>i6F*So-qp@wauw^UI#uzrFk1 zyWVf@!ag3I&pe^I(~O>#-utzx-v;yenLjX9?blV*{502XDeu>dwa&j^cyHX7nL8`& zd35M)-KjsCb)9T~a-KSyD#xvB8uXtTb{e5q?hj44Tc{-VU)A`q~^4(DRmEyj2=&&GkeD@^HV1~ zl}vp2)3cgms^`uZH93yiZsDt8-nnzifNr^!FYjj`VCj?_tm}P0x#w*=C$p&i#WQ9{ zuK#6Tr;s^&RIZml{jO~*!8 z^c^%SKv3Pe&P=@GOx=2&E>lG7#%%JL-FW*zk2=xleWN?w(|Vyj<-D869PCbyCk8p{ zRoyBsh|4brZFoL;yjkU$?pf}mp9Ri)a{Bq>EV|}u*GX3{FMOF|@ch@h3#rrIU(ehf z*vI6>%^btUr>~fBA6ne&I&a9!q}2~BuoFn@QP7$ zT_|e#)6II%TFeN`-Sl(*)I$?I%xcnm^{Lfj*vedf8FXW1|NV~lD>~c9I@34zzP{?u z0X?*tF)meCBe%ufe#h2y-#tA0C3T^}qInIy0}q{^b|fxaG-Qk4^RXEYIwQ*b8y$wojmsT^JVJ?hxj;IU-*$a_t#gmFR-qg8~Nsr zf2`Y=W0Ph0LR`mrA9UwXhGwV2>z9|m>3Q{3uOY&QUUdbD%GWi&UsG1PV`B2Yr#GMW z>X)8AOUL=~?D+V&6}zTJ-n`q->h+U?(+*p9-L5q=dPAYiNT!=!xc@MYH~RAK>yjCE zDUX>y#8#Lrpl=+_o9j1?ZM|pn53^PnH4HC5|8n`Z9sPcoJEqohPEM^&egDkWme#k7 z6Tj-AP;YwBf(J+qgrky5_`tM{-Ib?GqaQK+o zKF5lMc{6^hc#6~i*t*uQ@ydM7%hy!Th77p+o>G!Wk#(8D^WJFrV3x_e$oKW}{X|NG zxi`0J`zBWTck|b1xOCWQsqW8PZ!jKTe%Y@}SKW!f*hTcae3>svJ=0Hl!fVf+O(k9O z_w~Kk`7~Snk}WBlnmfbCMSb4;s8Lm-Ww*TyCx+CGJvDn={-mHm7Z?@V5hhQv(zC6r zwZ+U~7kdRgRo6)jztVG7TL0w*+NXZC_V$^7QS;;*8`mib(k1+F?vLIFDs?n9*5pu;XGUI5-!dE^HyEJ zPgWk+y%=xr>7G{(0Pj-7Yj%#pT`h3*S!-iO1ntj_PeYaO>kGDIQZV8#XdYf6zo^G3D z>a$+$*YzrK`*X)E^$|*IcJ1#I<0{j8-qTOz+AV!g28$bSr)6`r-j4Nh;6U5i6Uv4g zyG(f8d-VIe&y0GdjMvXhX6WxTE>*F9-pk5h@K7Ts%TDHb*ZyQmwr=!t=zotZi~Ln( z+VR@D^RF94M=GX_N>H8sdx=l(Ae)JkP0PzKJsCWMex$Bs^wccz4^11l{2A3*Y{a;; zVqAq_ina3mS*I*}&$TLe>9Z(gYjs$5l<&=7JhG35E-(0*cU(UrAzMhay0BG|A=yY>YH%g!np^RXsq4Qf6kz?)DxxyU&vgYE)~0PSS4itaqyMp z%DisjMY-$&A%|z}t51kpeAR=#aK+O~%@w}(EAfTuo!9i6afQ2edgJcZ=@};l^M@V1 za-8wxwb#8rlJ=+Cq&iizPM8*qm{IiTtv*{e#mT!^?;_px$DiY5lf2FpRPJ);IA-sq zj<8HfGwkVe=%yDZAg*>^LgkM`8R2twJzJZz2z$XxEg8ocb>z{mv^@(ipRMWH`1|SZ zcY2Q;ZhbFbxbxBXx~J>?&OQp;d(A8?M&@?C(+usw{V&d5G5yVo#|>L@%I{_6#$BK3 z=Fn+gzoK)Q1D`IQr{g}e`=Ee@nWAUomJMlY+8lDuyX=i@Xz=L1o7US`Dj#nsDDU>8 z?kfQ|?a2<8&i9V44=Ujgo_?;u?8gb3u65!tE8a+rbc;7f?_BxqsPkYQz5Q>uohjD! z>yjKe;5~*q02qUS9JotxL8qf59KW8A`{_xblu6;mi~7mg)^HHtyuS z@L5CW2i<P?sG=Ttv9WR3vb8aslgsXB#O{4QK1F|i z;FP0-%=hzL44*Phc$@oOzjycHMSO;anYUVxDNU2!bg`sK=6VDv-JCGfHN~7ZZ^Q4y zHN@K%x!!%*sek_E9?Pw2&G`66!v}_}P2mQ?TJzukyr65}JsWLjZN1=k+|DC(Sk#n$ zZ%VJ}44rT+(qJ-o>+IRJzvqwYUDxGy@UcTqe_om8w&PCe!M;V2j~(=;2b@%Y=&{$x zLCvtDcS7;H7t1Q`9}Q%8-=c0}V7qr~PWT+<`w#b09%wJ>Gk4ML^N}_y7uw}L+ZyzX zv_9)aN?@M`$E^>2Xxn^j-=vtA);;6COfBK1D|f$x&My@nNPod+EcX8b~Cpgxc$7|JhQS5 z7O#`prvrHRi@IhOc2>1^x*K71c+k8dZw9V;dpLOV+_xK#&%HmCHo@rr~(&M64c3P>DLr)E&f4F?$nd`2Y3686tJgi=Q<9DVb~G+_q(T!=gysTu%M#8WbmYUKSUp&I@;RECvm1_ z;Q4;6=Z4}Z_o@d~4%k*vwdj$$Uh-1=vm=Zi8;yV2kQEvE+v%5!T%MGUIqoyK!KU}L zeGT;|ro~blj0W^zynp9*=)M~#y6-Pdsc!v5TY66EX*KIp0rv^UQJxrA3)t{4w`&W*P&F5~|dlJ^Zqc*T)Fv zpFER=C*9;3pIh{5?4rGm=O+)owf!qrG~8L4b>aJgsVY_d zHmQYNqC7a9r?KwTp*`u-`moo(D(ky1@zg6}->BsVokAbtrzA@(i`I;KbbIv7-GL#6 zS53#(PKrM=Z<<|R_T9xwk1iev>}0<6of2zA%$O@PlIDB%F?+1~W^UL1dkx11yfj(2 zW5OxXn8vv#F1bS|a_hPnzWvQ(Uzz<@pP$%Wd3q`HWMd>wU5aL38u9qMfzw6jvWs>1 z_L;*vR+@BVtb<>=iuqF2hu!B~z7y-M->V#tDy#W_04G4$zqB52_o={m+IC93p*f5K zw2pJoO$}B7aB^Ye@z9gFVkzY83Mv)?1KM=weMt}E(aGOXFD>%ey6;H-Mc^*+if~Tru_4b{L~peI z%%?$WliC>6!mAn(+}~-~lB*;kwaLXia#s(ZU>es0f_AjCrTKEH8m4*N!^7sAm31&I zEGWc^mEfc&9;4jW)Nzd4vL9e@Pms|JHVH`!o?bE-*8@S4HkzL(u+X|D7S!W(2FR#{ z8Dx5t76kHx@W6el`y@LP}Xl9DwQ6lm8ryW1APdpHBU=ne*p?^^;lXL z553$QHOMaGqD`7JdLCTnl92bTJm7UBnQU4ezbe#cgB-*z=qPBtNNNmtmmDqk9&TSE2u04@fBzH(Qnj?VQyrtV z3DiWqR)rRyj!C<;J$5(iR~S{v2-*w=)4%dbL||qSG)h=Yf+H3NKQIB!q23~Qjk6xe zJ=sn+|A4A4xCflNJd(WchZiw*S4Y3|DWQNH+;bf84zq+R)_WsLkH7rZA*xqa_f zUVqhgGrWU&uO5BmFEs!@_@9u&dwY9gccTuUUZ>z>?d&3m4&~s@a)1Px;_!u-F!CO| z+0+b1)_t*)fbq)_C|v$E8zSO-4+A$fk)SIdm6zNf5%1Gyqr5LJR#2nBFD> zom-gPzxw>APWtgH5Mjt}#*g1Q52&6$glzLnB5+0ANv}T?_W^vm7vL(E>gAF}e}EWP z_y2?B)x+H$_pc@fAaC{sN_>GmNU|T1my z6rA@6HiYBSf-GR0&6y7@tvND5&{!3e>4q7*In{jkRf`Z z^5zZ|+;&uLKdpH5=&(2*Un~sz@0l3bN*x}7d11Lrm6;kPfk1?dxf)Gz7K18gEMO&l z`MZFOSd?_`cv46x-d<-bHM>!2C%4=0muX85kC5D(A4@(zX}$Co9VJ7qjT52uu`MHK z3M>qob=Eecrg#RJT@~X!*X`n`-Hybrp=F#nTaw^ncB{Ko6v<~Ohp08t>y`8fHJeaU zpmKHjzC0HviRe#6h4ABWC#r|1fbqM)< zvvWubMS4)=P7oDwI+&CeoY`%Ebi;4HtTA)h?CA3W2;0LE_#xD+H_6r^9-C8^=y<*F=H%?`X7&BJ8h~cZuVKP;|kRQ|e_~-E9f= z;|3Mk8Cj;>$K$vt`Isyi*~r8}m%Ve;(VZ^YZ%Ax2rj`2n(5iw37nj!px7b}Ydqwdy zDI(Bw?9trNydj61raBngX>7gRdke_HyBf<=8bAoK8(JKmwx>_Pyfu$CL-gve?<_fV zLX;w}oSHj~RkB?qfF0D0C0YPdi2@}KcEyCFo&vN${=!+T2yOkRhHR*okqY@P+#3il z$Pd=rcXa82oFKXe^N~Oa5Rb3I2AH*8O?aHiT*?;waG`I5)tq^THr6@A3plS0W z%uK!38&VKWfln$6xu-+qlh^U+bgDajq!uPJR&xkzDOmpEb4qW`SFv-qImE~+avBm* z3DQikGoy~#zu z!|l00jwY2m_AlKAO+%A|GMeX)zmtx$WgQ0k)6^hsslXtlpx{P1dg~bCB!{z3vwXD1 zhG~^`#V{a#5gc>a8mJ2FdK8zCpb)XxGyB;nN7qWH^ug_8dB0I+FIn~O8F{Y@q+Zb(S*d3s%pC&DDKW{~dq4y1yfeTb18R zk!2*nU^9xtB)Se>s#A+5lQ$K1f>ZDiLbi40JW*CqUsc5YZWC7-f)&oKN+*nz zY}{0c9*u�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

QXfc16$dVbe$MlV15l4Yvr8~)<% z34>H;6T}B(L=)i#O3yLx?4&}P7RR%~e36r4&!?k=k4HacUuS~YKqeVq_K%SGG`tn` zu+@MM{LRdid;$Cg^#_8OgyFiq#r_xLV%ADo&~6m%WYIY#rfDCpF;o%_5a z8VQ7CqJ^EB29Fkl#qO?aIAi-cpxZNb6Y!eDEUK6mn37p4mx#u*g;52Jp>^yQ4+$@X zjD|bfySHD-ibVRg?o1{G*y_6*$pnAH?}NOqeVE9X4RU263u$peFf54y)Ml-bf0&z^ z^NyH_)8k^#ma?PLcX${`FeM|~euAs)&XfuMiuA!}lT`q*&=ds5$kJ8$n0Eh#r^Mp8 zFM|=_Hy6twY>Bbov7vAfjFq=eUs3ct0qzQ{YkG~r9<#TH zWob?QG$y0Q6~IH-LMUJp)bjY$DR9!4IhA!ILjuN7?qB2k8$GF~)Ixtw{}lNmx^e$p zpuy&NC^B+`)i`N4u<8n<@XbZ(ue}e%w&g9cr{%&4I46~6o06%W`2(sW5{R62dJ{Eu zu%C+Ne@Dx9QkJz*J>hXnfwxH3w0D>cmnE=U7i0uq?!p4d z>;N1_W!OHk6KK@}(QJXBAHc`rVC%q$N;~Pso2Cf@K_ept!XIXdd%<5yc2=16d-I@EGZ&32Dc6M~HXbJ;SBJG)_z|x}3PdsbJXAknA`T)l9piOsIffdv z?ReKFu+I+EOm)7{@zy7k<4bH_R>ILs7R|M|YhX;h_HyWxY-FXDt!blz``a2sQNMDR zMNE!D>ei*X`gzZOE#)Rds!MK`-~p%)nH}mcrfk~A7LBYbotRy_M|FEG4`^V3RVtd} zNX_>BA26$7Nv+qs{nE2@H)zGLvCn{tgUl%3FVHEc<*%Z#`H?b>fzLrKLZ_ODr1~k#~P|4>DNDwRjkdn4Fc>s@afp=sp?WfMu z+ObxUYUmY$ceQM;WihUeqrTN|5bJv@lJo2@bR#%L@rrXl|9_nNRmIl>(?~NypSh z+K4_C90yc~%mV>Vmq|7jENVg*dIm;a!A}F?bknRGuS5&Vts(Jf8lugWYD)}UYa@FG zA#Jkr7qDC94S%oUNT4^APCr0cuhV_u{{q)o*uC0+An+;i6!nL8EY<6_qpG#HM7|L7 z!l@)>9b)P-`1}P$&TKiv$Tb1ajnh$aC?{F)Q&{y6V#IkMU+4AQf4m)MOlta2n48)4 zFBKO%3451R(7|uNg~FOp!Ci!1nnf*x()Dollyvm9gxfN^K{25HbZlU(#%CGn6wB2W zC-yPOy9B+_StMAfm4{W17L|i9p6$2mH~@ z>HjbPd01$5%?1S@+RCiGmSe+2!~@5EhotIm?HByxzcgG1*X zTC=;j6dQdcNkK@g93yd2n{Hvobw(}fhOs@IOsDou8Ow^tLQ3I=&hR3O1X4+|OTU4< za)9JfX|-+}NOdvS7d)pAwpQZP1gl-!$VdPH000000004aqBDYL3tV+#Q#zcT8$z<# zDr}a&YXylulS=4<Ok}5PHGz;uKyWw*L2HFb>3Z6 zMo5!^newxgRWS+0Z)rp1*z%SIBBGJrhJoLDu3@;uaZm%}M3j}eiHuuXz>_pON&)S% zegI_kc^Xp9I5Yj?_X(K$7v*Ul+iaeLe)ai5NTVlxs6Ls@d zvRe!*&w*NC^+cIkF=J#o_n9@Ez|qLxOnbpb%n(5M|35->Vj2Dx1({1%>dXA& z>RtTr636t@T+ELb>mx-}dt0B@ekVQBR&bC@QaG@5+~@+jNAa*x+05)Ue)PwpDnavJ zu*}8GKA3l}xl8Zou@DVU1ne6|zZ)HGC;nX%CRCk3WPf}xwJYF;=@J!NNWi>sCa37jYf3W1x2E??RP_n^;M@1rUFr!k+>6 zp{>Xg5kP71X&GY6Eu%2OYnTn2P*m=s$-ZZ)iq1ek!YFE^C1-zU!&et1QR@hy2rhKn zp)xp!%4JV~n@#L33^V5C8c5cS{B}RS9%v)2-}H7v+BV8*u2#JXpa>|M{GMLEUUBYf zf~Lv74W6I#7*D^b|#R?ctp$6@leRvZlVqNpj7YJ6!jW!1CE=i(mcG;hSDun8%4_KF zFzM272DA{4Lxy;o4N3>UX^UBCG`8reXEcDN9CdnJ`+!}*n}qyLsaQ-h%;%_w>l!Ya z%6+up$gG2=-3X<~G&|6q_y;@?1y|i+_Oiv(fnrAwnwxEsFQO4c>h;H)_Lf}I0bO`c zLh~-Ed?ZpE=%zPGB2M6HeyYx;x>xP$?`;J4^-26itnSwY|4->yxTL||E91&^+*26T ziM~Okz850FXch{17P znx=Z6N@N*?6tXk*m4;!hJ0kr+LkaGO7jAMTYlo;)r-?2q)eY#IT-&Oiabbnk1b5kojJ0(B>6wu=TL`tJnz9Af&%%MuK z>DL*qh>KZ@iMQaGNuJfskZ!QLlY1?MChykve7r3pPoY1Gt9W+bIA}Fvm>PJPtzl zl1n&s(0@$4PLR|W!7hV>1cQ9F5S}V&f~6YSpKB_1y)c!beEKYk*wBvjXlCDUAru&% zcJi_ew}0>-Vl<-e1BZO|%S}m_D7hyG9m8`hBTT0aDZJf!J@O{j}D9Fn8TnCj>)zwPu}yH#;MQ;j|Bxx$ujd@9g& z<%L)-Ns7f2JsL|Pp(b3W3@B2q#!7&X0V%UJ<@UXznM2F~==|g2y?H9eHDsfC;b+{5D+Frv}6iGrUkD-zywxSw4ilnH# zY(?m-3*jsBkggNe8s)kDzKTDri%jAf3)=GsmP%I1Y@&{t$CfSA={>eObSxIjpRfNg z{Ms&eUQN*?qb5ccgB@77tXPq4h7@EG=Y@0124oV%TGbIjJ7iVet7^k)9?d89Op&RK>&B&xUWcUI zsS=EZeuc7B5fDs@YDL~m)OHsXYssH0HQH{F*noG73Gtdpi*=Dh1%`8g_W?Hhgm*Wl zMCbvw4dspMT(X0?tz&gG!EE?<{GH#iw-;Rf|6HUNk6c*&Q{QQctdyRYzfIBE^Jk-@ z^l_u)n51Ec*gG;M`(Gc%s$mjEd z1{3&iL-gHf0C9*tt?vCv;;qI~yb#$S1Mlm?NKNs|tB2Nwm!_quHaH}~Ve!m2&NrC| zI_Wz5a&iO2QU+8h{}3%-1RsIl^kbu>DYb7PeHAkdzG_pE5XOit`%?oxXN3w;G!rNHK`T1yqx+A-T>g$Ip_s(jNk`L9gTrNGysE&_@`DDyp!# zN9|#dbVT4I7ABuIAGj9@gOhq?bL;-TDpAaHa^T+_3vnfFKB1i(p!19!6H9{zwj?tt zklTRsfeu%TppnxXIV+fQah8p9?%og*6zzX13E8-pllbPW_CTz8Y(d%!pyKH+zy`rf6B%hImGf*(Iy71twgm9G#rYmWUO?;ksl|En~gd~QzDl{|ox|kB_cdVe^ zo@dqaTf{H_Lgf-edeg9~DdGmx2T)(4KAcY|P_%?S3s2C;W2nV~G^zkpqMZ)nCXz9u z0%STWo}gzR$eqE*PVg!BXN-e}CWBcirGEF;Bk&m(wY5j-Wj~Kj-6j^(n?6n0x%y z?o|ch5Be;@$#~wGy0bRC`C8Q@Z+M&PYqcVOG83y2Pw0l@?t=7)Dtb)Pj)%VyDe2O` z0Z2zWe$CH}*Xr^!`HpZLT_Y53qB!egKI8MswqZS^zec|qDWnimP7GybQ8q5d#%|`N_tFbzK+nX}BY_xGAB@aYM3qhRLZ1E3}7F z%2WP4{eItVGbCpF#~DxdQ*h-WCfL(}7Wo*g9oDt8xYQ>8`@(S@!FVy>3$5Zh)i!O` z@CER7{n>)334xREK!?<9v0aWye2*m>IDZiW81~@TlA;Bec6g?_?ZUW-cUi~BK8bpo z5h>`M$CcFf(Tfl@;?`EFfw9fv{*k~X)5Jj0c_C}b_}y_AO)s9Ny_iqaj>g!!yTOiA zQWppGCY#fc%k;T>MpWW+!hUhzy$Bn#ua_`|5_4AMtt(DrGMPyy^_Gr^7NMVZXW;*L zQ#ldILK*l+QIZS0KJY>P05Xq+E}S$7xQH0u6MFFh86UdT1&zX-=Hwx!w`^kvG{uX3 zSYO9DRk~7-ET8vW&nS#nH5ekZWBnYnIaZI0&uU5PTIzwzRKWKl*k~cr7O1E!VyqUc z;b)nOA0#d>!eup{XfLNOjmZ+ngMQV_huR8|lF&hIo}A5?sG?_i*HQ$>fo?FEzU+V<^ep$1unuZ1c7?*U;?BLPOYBKzv#ER;!N*bfKm`e(1Cas!rxT*=T z(GD}}l)6j}(V{F`vq|ec6s0|*atGLPTDN|>OsPYw1ws_|KTe5%Mht7e+NZRyJyr54 zyU;)I_M&kgAY;G*u^WZNJ5!zw9gOSuPbJ^cOAgb`iI1tldkcov#ArI z24p@`=V{;Gd40Za!JrIU=I(}-;U8*LI3>o#Ei8M|U1DYY=mdj%C+&ImPvj{t(;0j9 zFtPmpPK@uRWh7_2QX1(wTVXGL9L0-R z@9T`obyGz}_&yS202*FT6X*<>BDqy#u0$+K2t~P+I;JrEv z`SZz8cW?XGj;?Vh-wP*94v~@(VV+y}+~R-J$f!Co4CjtpcnY)l*%=`i>xv795S33K z%r=heYHLq|8k7Y7AT`tR*W6QB78>Rf)Qn%L0Bw8YHNNB!P-!g8j>TL^Kki`T@86(g zV@x!9?UpvbmsxpHSQ{9U@hBlVW+>lxF~Zh-pV)A%Kay;RkDjlzAbA>1Kf&}}2)WY) zGfGJ;;=+&zZtwtS_?t%T!l8Iit~$0zkD=Q{KLu4(0x5?fEu6lDGvQY~dU(&Q%ZYSB9LwyaZ^%5%T@FO$l;ElyKu@Y?R6sLLKDr~q=z ztfSIMH-*IM{tVw-|1YJRn4A?F9~6WB+avXM?7Uzr>&D$eE`AFt*i=Lc?6jsBm+!77 zFNqy2jGHdnscV({-*!-km6%$zYx@G0>n2%b@w~;KsUFOkgpP6NhrSvV%w4I9cCF-o zS_$$`R5ng+UvR>?mhiowXb%o1`2+ZPc7$>S*Vyt9>LT0_@`lUC6ULhITne`+y0w5R zTTgG#FLT0TwvyN{B6l7dv8V#N23@_ij2!41t@j|YEx4l8IUTgjH?djU`$8x0_5i$K zEz`0^*lcyF#(9%7(4-F+B_?pa4+{EMU0phc>B+31N<-O=cj?!yjKrKU1Q8guTa(tx zhQ`n%XRomGJDB(C4GO`5 zs#Ec`z3<1Cv#`F*%WbVmbM+v%ArTSjloZ@*-~|*VioH*+wpD(OatGM?_D%B@kXw^I z6j{=@s%Je>xDCW*+RUS<`=jvP2z@lUYDEZ35rsX}90lO%%GWtP*U4ibzcDp13=VG~ zWWP-ZdYhgFT|cc}N^MwHyVx@4{kDpgW3<8um1<*go6iN6!w@PhS0Qezw@%I zcdpm2Y_heNAFfQvlABvV>b9c#Xk}Coavx&@&xmmoDB6!nQ(m3zhy9Rw?RLp2F6C2E zIII!mx|)=>%2ehat4hb?c>PQex0Iu?u=G=A>O!dAB)0xpfG8I&uAjpuJAo$pcEtZM zQ;>P3Hr?o_YK3f-yRWIt;9NhRCZ`CyQ4S)JFLk4F#R`!Lcz*20ETX=Td|eJ%P0~>G zDiZl!`FSXZt?v|EFRX?dE!1kFP^I=h1)yq5#>B5rbUAxOFsH&?e-tKKt9HLta=s?AknMzWAv@}$8d~YmcwBNX&2S^P3s625Fc`8QYI*qtU(4+QY#1QsA8?* zoWHUO473EgNH@=z(eOU&l=CeE3Q-DPmh}S(XGfd?lq$xT>^dYqDwUc#fn+6>PY6n zEvLV5;yBmb{wsYPq~oOos}akdYn|&U&0266Z}C#lkh<6Ww)02<{+WIZ@K*Ng za>-a-G>IDeF-1d1$TOFPq}nc&Wi*d3a8tK+YL@maY~@>-Y)O!%tG}F)C!ns>uxy>o zYB^w{yjar3RTBPiBUCSGJOE;X5KW@>h;~WZb-GvWq#e-$e`6n#&vY;iD=_n$-v}qs zx5XAbokqnAemLHJ#s3Io?G^!bh4LL>MS?q=@*NGSEGW154$p7dAy9T>T(%&8+GptZ zh9Ba0u!9eqLya!LuHM*R08p#aP9Y7ivWx@ui`+F z>Ab)0!My-QK)S!(t-e}Z`~M1PoBI^3SMk!GmyMLL=U4~II#)Xq&wd<=rq>eKt0#oTIGT@l8YiVNB9`1<2ecK5F{x)vTI*Nx21a3pA*<6eL5&i z(RBSYIYFR;R;%X=tvptMEcIdUo8Y|Ecj7WD$1%cAadmJk>RvX02+0KZb-!bnacR$d zWe<_%Ws$6l*f^1o%DXO*>R*XhNaXaG_`Q`lAqoX(25gln?;T%;{w%6l^fDo>31_N> zXNl8u_0iyM=VvjRa?)w;`@A1bIcXEmX~N#@v{#qwh)|hESM2jjMHXmsK%Goy61h}V zIW!pYjRWJ^2%{5sm}=56`Egy1_`e-Nn$QCROwq{!Aqi-%afFlJCZh-w9R+U~P{qCj zDL7Hc6V0BRbOlOultMenFOLVQvrGeD?QWQ0&Q_BbO{4GLqCHyf;1-}N+-+;! zsTar}mdgl*c&%bhrkf*gXDRUu&mc*!7BeTiGbzKnB_=xN9S_w`Yl!uhi>^D{GIfbt z}R;0Umw@P1G^M59b*Ct{%R*W^niI_k-&9Pjy4VG z`o}C)?7|a(#;f-p0A8U{b}QJ}m{kN6@l0W4lxL{jv+Y8=f^!IoT7yco>6B?RhMg!{ z#?iRMA>LZ-;@+U&92!I77>VOeNJYt~(7b6Y0(^Tje-pNQ{DaweFww3)<*q4!8Z-uB z=K;zcwA5QF>tmXZaD_(YJgnD%b%iKnt(5HUe4f)+hJy8ZQOV+TP6Vw?F5Xv|AB@PQ z232f1!(C}}c5F`E*OH}2uDWDBGuQ-0)))mFU{V!?G@Xj(1M!!=VAKIb+k*Afb!5-M z7^6h({nL?*68W@Ulf|F#%*i8JYcw9*7yDXHqj*R=#rH4IgyRmEQOw!M4Zh8xG#%&y zH)-nM1TYC=b)-uZU3h(>#8KdZhP$8h{Ox94Z2-wAHygg2rL$-BWj(G)qJ>5-8_*+P$JOR9#pv-G0lyF~zE_)|1 zqxrqAGZY-D9!KAmSu$;;5(z9_wBgjSHkNESbG0hM@ddm^h7UO%iT0bDhmxCS4p955 z*FRK?Cxc^C4b~4v^Ll#vI_}R)JklZj5?HTtPh|561z5c z7V6Dc{VjyR4lVlR!+}=}rB3JTuEahUE41PC>Ufgd_O2IfqI5)ItMpGXS3KBGPf(@hzUK=BC&TIdh-i~uty;Owg7Z^*mJ^CL7t;d+P9Dj$Ue(k%@hIH46i zkJ|W>+%cLI2WO6aNlheVjLY0?P~4zR&p};9O=vE497+E}`&gi+Y5;GF!ou*_g>w(Q zKnrMoO>_c;Wqk^Fb0dG8ozhP;5$%~ZS3$t=jByG5Az8l^B@W9me#MeunI2C@<#K7$ z(y5gTE$!k>fC)Pe0f%`aR#iW)Ha$IE*knGypH*Sb5c0f(a^guY?Az?gSvt~!nxCf( z%2Kvf16R}jB#j<}*MK-;j`T%8e(|Vc6hl-F0P8LPI<~nAx_*{65hlTq#0W0cAZ-d> zq}1TxpGP=d8&ZHKUu574KWS_0e|;Ii6yEB-`wj2WRsi&WbYFcO_t;SQm*MtfwuCwM z_8=xP-;R_#RlUlDk!G&g4yQHR=l zXJOUbk{!{+DxjhahnRVf4%pM8zE#6ByFnbTx&Js$jA#Wpq$9=J@n>BzsrDz4=H;mRG5}?zWi((RIv<8Ib54 z*8#XC8BcN^$SQli#YVNE1S2cQ^nh;ewF+HF-$9zGL>UE9eSU#$1k%v09HF&bK~IyF z-hop;CLJ3(w6^3m1ltD3t)9=Og5n*6$!M)LhEIYM5OJO>MHSV15$-1~6%<=))f%=R zLxj}<(hx9I4w^EoVlR>UjkF#v+>ViX5r^dfFHSJ3zf-;Mld# zXsnsNbnDi$k&3@vs>sL6VZ-TR*k`vm1z@6w^=Ded$+7`}p3bL9l28XKYRBK_b$`i1 z=m@lA93B(#r_fm0+klc3M#~i?vk@f)DJwbnlTQl*4)tikJc+g0B%CA>80DW=k`+oS zdH@>!8*me;^Nq&wdNS70r%F2UW|@#;2&1pc>~7XZdPa3KVk0rBx6Vy=Y8!_q-|cs) z8X_+Mn7Lu0{&=@{Ef|}Q=+b_3jXh@UkP!(`Bs{6JrVd_avij(4%{R`DGNc}%#*-t> z)V0j_uY$c^FIc#zzRfVmcBxtYW(Vb6Sn`~I-R8;A58JSWtSC!b25G0M(Rc>Y)IZ^= zHLNr?fZ6j@JGY~U7V`%iUXX4=LSJ&wmg48fm*B9vmp@#ko#@(+D__34NfgA;lxcE$T!fE-!OnuC7_Hrf$^l?ME;($ zNP69YZS$BiB?jT*4ILkUH?qfZlePN4(1ln)20hS$xUNuk@v)`#Xzb)&VlP zE^cQTF6L@X)Lz56OK%*<>TcufMyIvvGYO}VvPlr?4LXYHw=~Ew(at??Msd0^gb3+k-IQ0KY<+dO zvo?_hq9AP|#)V={G7=xAR(lpTY!eG8G=)J(3pv*LP1+A@*(wHtRwTRUZaj$Py8-6n zic+0Hmr;JS(i0F63ETifX{@ntJh#9W2It0(Ht!|nMJ&(S_x#leDgkI z%Vbr)rl9iKX0ia5aSuqi%fRamf^S!{Vv&f@`C1lp@dE!O?s6X} z#UdUqERjEJ^CKPB$g0jfI6-5pAL;-)SJso~^ov*kJ!0t|Yj5QrbR!S2@vwR``V6cS zgG~a1NU_V2??lFd#5-IOy_Px>4#y!5Pl8=NHL>rFw)kt0jP zKu4erZKsVp_)xbz$xbiz^AmqGcPIFl@;hvxI`>=jZ&BxBA~Y%GHF%NqNh!@faz6y! z(E^Fh6v*FD1=`?yN%w*85`pCV`CrD}N=Scvo`oOccFw=jNa;&eT@g(O~}Tq$(jO9ivn_N|8rwE&6R6-oTlUpS}JM&05Esl60it+uJ4{fN14L`bpU zN;6idMBF3d>%xz6N$$N8-TQx#Zm05k@rd|(5sU1_lji=e2u_k}t^zVi8Y#vj`&d+$ zHRT==1YrA8_mWrr0MU^p%Mar4h{YHSRkSE*_C1Hqq^Pj2TB!0 z_gmeHSS%$CHN*qnSSK>Y-x|P+Fx}+E8sR|o9ZKSe-8rbV?#Qs|1~aJmC2y%iQ9g$R zWqb?#{9BM!PiS))uqMxJ;qFJH_qC!RbEqzq#B0wi90$}S8^UOukZmuZw2kavoI$fd zav=fWA-F4i7EUUl0o)@nP=L8z3ur$4t*J&#G1+X-tCTL&pOd__0r-KRhs;WRg*X;3 zI!7%s91620Q+VU)Bi~u8qW>FAYQF5FC|(Np`6cziK|14PAXVB}17B<`c~d;u3k@bV z)aPTmWc^tputfl2ssWX=nocOi1JT81c1Lft6i&hR1-J%i=N-xG5=2s|BhAvvNzZyB=8+^oO&{s{$DN%u41$*{LVgz9pRvY~?v^u6Z z!P}Gx^}rB*cZbf!oN@7R?ALeaNCX@J&M?RM_MbjH${+9XyMvhcQz%^E4`264_qKiX zw*Y$oT_@h~_toqH>)z?!_dmXzfcPsz{h=aCqiI&N3f448!4aH5lT-~SzN|G=w4tIt z^7Xfm^obN<=Z+*AcJEvwdbJah1H*7x;|hbA@( z%aQ9dyM~4skqZ={kF#_6XDI8e_z+o=;#*ON$Ut!D!~SYw9K^%7341m-Op3^p_!p`N zJD0FEJVZ*x=SS5J++$xbxsV++bO>J4FB*Um5zS*B z?`^CwON3sKj6UKP>wDs3lZ`YJJ$uP)ot}@9G_5gZZfkZ-rMZ!%=i*AouzaL$^Y4Ko zfmKDsoHn4jk{AXadwQyJiq9rT&YMDeaYQp-@(*hV!^gfyua;a!3bJC;U2!obG2j+9 zX(C|0!M?5ZB%v_;8DnzqyE@!G=2pBBEo&V*BfZz0Se%d5H)q_f*!+dp^ld>tN5X{o zz3nRbo#xt=OZ3^L)MP^~7HQ(Rh%WIFRbetjgvm%Fd|(c5Z5(ISZDY)+NC*dQ3sMg? zV<^*o;DqKneQJQB4Y8~&*3}|&)*i5yt>G6&@7HEjOR+;*>xaz%dz2acwE$Dmc>yjf4G2p^kS_mwqE>fz(iQK(q6e>4zJ&9|m7FQ|bO)RZqBUhc;)Ti> z+vNi!3qKlTOCOJO+dD3iHBP&eZ5+(H*0uH)pL)$(d;uHWSr?@lbXim=dATK64pPU2 z^J9Wa9Snan8!sT&QD<+CCbNi?1^1A}FG3Snw>9e# zJw^t1SYBdJDz@^%9-I!zX_`dBLcyb!_dazASf}W2PgsR>woN7AhVG;{5JN$Z$J*~ciy8kQl@=45BLt9bONmK|$ zP}Uy3XHwzOcaiP!vXq5cJx$n?cWK2b@#36gFxcS*z}pq*KwiY&x)z=M$m9r9Y`;`zO~C%lWIi2&A#)~coPvJm_SjFW!rc?__%kMmMuPti zlm4Y*p3}~iK&|8=FFf?tL9ikU@6ndB30Vn448#2yvZ&F1^q-wag41s)#%Bj7=_R4sraf5?_ScSz5JXO{pU#w*%C)%2&B$PSVMUsDXR(KH0Fj7Cm&t^p^^|cOb zmp5|Q5E~lj=)geYHY5B<4e1Ilvwc_0(yQeSjAqKd#BwZz6FV2SdiJT|i>!%`DL&pIa8~Lz=nl^jFte3G$ID{`gn54U5v2=?NQy>NQY}jc z{@iw}c?M2ptgPu^76_$xVjg>d=Ge>d>LblsyqsR~lbjN9!+*Ek;Hg7g4oDq+$Q~7B z_>+eO{(99qnLBxS2Uhi79-U-{&}Kgx6XRe(4Ic%IGM>)jrTdQiYX*|Pd-GmK@1(plgB5FPAjavEQ%r7I&801maBw6d;Wii?4#mhI7+&7 zYqaHd*<_|bI;a#}Z)f*WgZEp60d|EQz`qx)K3x(lMDz1WbVc`vZh=-(U38lcB|qx$ zgGE60i#R{P+ESJAHPu>Kbc2EaD^nzS%jq=A-aB}M&p-9`6RZ8CbKmQxOdfI0?nOn`Ku#?W-sT8{(N1_az zoF*z36vA}>J=(td-w=ah>HWrT*@Ue>%5SbS16^&%nho&WzB^^{An<46-(F<`Q67El zEdu-F!5d_btm_Hx5k)}v8!t*lqeZU16Nin}w0R|$q2&)_vi~_~Hzn2uMg+nTv_M+HsFiU(*d97#)MN>Yyy9nyh z<65JC|9|^=6E;s4jf_Bb6_mQfh^Yf_SwW%P7PCWM8TCXb0d1}}%KlQPcVxbwrBqAp`F%D3=cAKs}dg6cp zp|t#L-Hj4XbiQiPatXEU@YRed@9}@8H1Ef%HkK@@fC=VQG3@O~8>(GX54dsNpWmx( z=0l7yKaZHfWRx2<6zapx&6*Qi4+ zxxpx`61OHy^`>=CJh^CekUE^z5zHtj`_=9gc6wuvsAXqh)zXjW@skqxT2g&LzVa?B zdxizovq7(GBr3K1wxo(eb(i#1;h?roJB=J=ClB$v1k@C~8Qim4MjTqHX1Z#Tb@*NO zb;s|$mD065I&&ZD9r~-H{+i7<*|3CG+7Uy#p@bTWT=qni?Fw#g}QlFd;ptawMA+@0vA~5DbJ*v9gcF* z{;K*eTU3hFh#Z>c0X{3@--TJWJvawf1heUCt@D4%h?jH5j-o0&WcNfr9Al4{t|EXR z;Wtk;2HTT+U)YD@dGX#XfuS$yIF8W!)f)Hj zjQAMkpCZ#0^ZYkzeO{Ga_Vkc{Z! zGW&YU{l1VNw?ujV8*%;ppZ3 zG{g9Jll(gm{vMQ<+kXJ?4PfTzYBGLpV|)0w;zX0bvQzK1m%YZFn+xJoX+Hp>6$u?*E$R}hY;pA97B7X-SUxexy12|m_UN= z1UKz}%D~z+hO`FB^+x|CL`u{i7TT(SEU|io9e##E^Gbj7o-sl&Gyukv zx?9nzL0W6}gQRWnCVFFo6X~ej-<~({OZzg0s@}#Y-O=A3=NK=(|9uJuHQOfLxb~#Jbt- zCbn4fW#4T{&mRzt&(^En7KzB448$+o6hShLT%+v>EM4%wxd<$7MI>oL5{8lgFr^AZ zj!kylT=&xtuE}`r;PwPgS!%p&N{=NK|XeNFPO-9J|W7|Mf{aAmQSv+cDk^BxzMIky%$mY z!~IN47JL$MKy&mF>iUMKcOw(kqJ*oV@I((CYm_|kJm`{G3QV}+#VAlPH!x6kSELcE zq$nvY&A}vGYLOK_`hU%8%bj;;1!eP86``rKEL}K`61Yh$vP{ZmkCFZ!q`rV-LmQ7( z`F^fE=%klr>VKpIHf95+o}k;i5ucAoQjlQq`K2pHab1=Od}s;5v0FlFGH~$kmr(LB zALO-Wrfua~{z|oicK-5SJOTs8h6dVG2u16aq0nENcbh!E4_JyD$vL!s=f=+vF&-`{ zma)s>K4%FU8z(d&@Mb2F$@Rl!z1N0SQXF)c3p=z`ojSG+mtpllHHOPE16IPhUiEZ@ zHS@2RnHdUpDG&Yy7bQ4h`6p#3yG1|r_(w^}SYZXLUQC8P-n4sIcU$zoFpmca8h#^` zkS-h5AE;e#38#LZBGI-(pP+ucutDp*`creNjNpJ$q54Kw)YD<8ateCAzWv9f#9k1@ zklhkOybUac3{>Atf;fM=%)=@+t!$4ihE@s@@QxpBUb1YxZ6M+rPZ(I?|5%ZIRnSUa zXnpfR9kTOCEJIg~7Ms1lwaBhy)7!W1n>3VN5o&E6w~UYSvWJ>p0O9@tk^m^05!{kS zfDY`X?3~{$A=ByEccAK%JfS6Q^5rrKa1f{L#2=&LaC@Akr9)g+R8Du>$+ctTg?F)LJ08#YOd}U?5Zr&cvqQT)kYWEgy-SP>+`aCqsy@%m*+S zs+rCf93ze%3fv?|`)itDx_C>YC5%E{IR^6}%(1-yzSC8_=4U}8OmyWUP92sdZ$oj9 zIH!;phszlW+ig}Z!){O|g)TS_-ujea5<8E>_#eN58@EMePX)%G?{x;j;o7T5CXdy9 ztZm=6-689_F7%AmJVuVZMQOxaJ8ZT)EP^d>L+YJZX%HaTvu6^}UZQdzf**@NG0Mrv#u{N(T<{_?ps@}?>9!mib0OIwuZC*tDj_q&2q)|z7hd$ z)V(P}PzIF^)u1KIW&DrgcyCMSy|J7DTfG#=HYv8o*=?{n31}{GA-n^|7Q%OYFvILt z5T*`WZD|ZT-!26lr*kFSy_^JKUt3(;i4b|_{(aG3O*ECgY|=1mgrZAl=|s($HuhGw^aadh7;73o(EH zOT}r-5$|+KRm%J~3F6>G&nbX@Q~o)y+{eHHQGq(e7TaZXDSbH{^fw{*3;0TelTnFo zSiUdzScolRth+5js5CD-VfnR+AP4!3188o9r#Nhh$~AD_$Xh8PQvUQL`6i~dc|QF{_BaI~#6W%v@$$Ze-xL6V zG^U>Y-vs@xQk~W$wJYxcL>>M--Q_^Ti@BwJx6-@+Go9|V%e5G!Os-!2dLtQwO;8a_ zVwn*g#2k3*$iNagENnW+B85zkTzV)W6Ji#I^HVA(%t1hLJpDDj-8rQCjbob?W>RK~ zGB!b_O0wV}fQ;hWPINm&an5>%zSu&zQp=pjpIi6~X^)D8xih0D;p?SbBkK^sxbb&j z{e6W`bI?vujMuyq=B!bSd)+i!73$uvut>+$y%4iN_@iPn>Vk?PVWBz%boj&HJIWpR zcN6x*KQW9oI#fP&Z$TVIw_`I9PTBXip|5k?3Li`z=|Ic)p!lMP#GCg&_02g65FH8w z!C8y6q3A>XoYhk5A}9$Fdr{+}V~867u zcn^XRv5?ZhuwlN&GUb-O8)&M$gI7ibLd&g*=Rsj*{+M0)nW2$T5vC z09z6Gd?;%X2uo29x;_UD%VIX;EdM?}`bhg*6W5z!yi&QI$7>>^*8gK1)mZ3Rcf}_O zF5C|ZTvh2XDv5pB!!)YjYsHr|c#9{*xLZF!E9Z^D7^lT;64G1{jVLWegkhtiDlw$# z1e%5VEXBKuQhDqL6b47?_#(m!UBQ23=iI6oEU>6-9#QG31{zS7RL7q5_0|sWVAF> zguRW3h!6{d#+6)PpZYM`nRPI*>KxDTKq~q*CspG~0{E&TEaxVrv&c#d5jXpBA_= ztO4C(-%^43Io;$M+C4m>)SDaTHx`p?Ea-oGmmL$dV_)7&((`u4=Y&eJbC?~bp=eXt z=ax-a_%qaFj}W0e@__FSHAKiXRud8)xn7|ey@@mOiT-kYkf2 zZPks1CPYJ)_T@;NZZdO?AHnDFDhU6GZ|`E%9C|Y40kw1s%3pkcZ6JGe-!$chWu{sv zO%@!$3tjP%6Cl=8eSl~GQhYN;MmL5aWPGe6>Y|Dfc|7hc7yxP_XSIG8A=tm?@(zgw zFpTp1Z!@cc2QVp|o(?c2rdOdeXPT7Qnv*9iaV5dI4`pdhj7eYR!A-0J61uQTa2#ds z%`sQ2eCI!}CjBrbF|1ZOx$5E5vTdU8UsHwaK%n6jhK{B&&&=6_v9AJ+4liNBf?V#4 zV|t39JkqNI3Dvtl|6i+op@)`^V{TxQ`euK|nuWqaAv*D^JM@;g`oPH>k4I9+UCE7# zXVHDq;>RGoA!a#HU>be8!aMSfM>B*@8OzZ`>~fVOp})yiu(RglS4N;^WT?r*a<#WY z!P+*{liNe=auH5NBF25I)BT!&pCn+7yS$!?wz4ZU1EhLC1KH>|6jgNK%MDb?s^-ua z3KKcD>Z50QJ9K&2c{bt$$+gc@*WA=7El$=sUp=K{@Q@R`$*889+TIO*;Ht(*7iZ7A zi#bD(sJD?#147xt3icbWDF&GED=6Ut&y)Rbm{X~fXs7%%U$JfQX^)H;#hfaUCaL_= zfQxNCNXt7;qK`vKV-Q{$YSsWbirEdUt=O`77S_2mBKFtC0uKx#^72+n+p~PWt&_q? zqOviCHJvkMl7BaGCrzke_Qln{)~;G27|GD!wU$n0trw3DdOBamL$lbQ){z%86;K_R zkd0Vda=|$P5h*JIV#77R@hM5P2+ONC;gBGob_`;<){6qt31Xg%O((~ci1gGQC0*bU zg2!tcM`DGJ3LP4T-c635$6{MV1`)T^t(2e7tyJb?E2h2*(vI`bTVj3uFkXdIibI@( zS$8C_eE4k+HB?rHG!L`)Ls@lD^9KF7FmIJt&U5=3Bc$g_ zr25gNl4l$q8E0Bk*vpe(6I)2dzax{g;W!hQ6;Dl|Gt@56xBAP~f9&{Mmez*2Cz%^l z3khae<;4Z+V$QsGn*=g1p5?7zrzI2LhA~WJ8Ctf+(ihxV2`c4bz9~hz(GZw`2RX|5^U|iamb+|e^TlUX0tXp9j`sUSTri5Cj$$H)nTeZ zD!{8~&5%!<1GWkmoIUT~H2yI&>d$$yMk3ve=ix85m&3V7SAvZVYHiW8Ql96Jso)15 zPef3TsNaoTwc$^o(B@l|s%?Noc#q(LcuY>a&0@<0CGY8>_cIs2nxNIF5QL~%&yq)N zJ_j+FFxSW0<103gBBW{{WA!?#oO#AYV3CywjhKc~!7{Z`(f9g`K`cY1RZs~UV)rQFwAuY(|cnZkOXlu6ytsP3C#yAIG}Svjc% z(tR}nB^cnqEAXH}-jj-q?1`luhXDq|&C0~KZK1W*{Lovzl^IcZgwFh#zAKppE4DTm zvBj225l~$k)*b-I=q+m%b4X&|dnBYC@T&>&gczZ0&0XY1g(#hKOCSbE7b6~k-I!|% zf|~e3t7F6S8-Wxe!-9~bJnp33`9$KKngxdt+i>mCCrDZd;)x}UHzvYKGe?Dhq^g!{ z!h8NmGQNbq*7=g<>z}&;{{Jz~JJ|YURK8-!c5M=Wh3t6?twMz{@NEihYV24vyXJ_#|K0U z!XXZoO+ZIM7KVH7{~>!#aKY}7NeCZ34n1#}C&MZMuoGAtGdh$+&9OFIyFoh_3!KWa zGVf=czvp?K%4paOLmK0j(Ww@Cys-7VhQcv&8o0!nzOV!_%&B^3T)Vp9ezrp32%1G4 zRH$6FO4)_I0HqA+mJHF7WlX<3;pfZ&1bm^SX_f`S*eduMH6IUIL-1@rP;E8_Q+`S( z2tZj@@{K4xyz?pgej!I22B+&+aAU3g+%psSJx*NK!<~aEVmRqK!kdHR?Hk&8b z2@vIwbJHLEizrfsI{-~1!>k%yKqN-$WrXv%xsKClr*bK6o0E%1D zFi?@J&QpCSO1}i$uo>9_0JN^Pxc+YRsf%6AlPp2`C=#t3xurjh4A6XO0&*~OllA)u zfQ$AB5k+4(yNW>clSmm>*Z5J|)>AszE9nhrG|FBd|S?BxJv9(MMAm)80jYZWVcQ$^h=8 zp=?!Kz@z9lC{ah_MQKaqLs$j!HJ6Gk z%FioV`~wYt(g@dskWkj${)98|A4V&Z#EX{6AR|w&w-0d>E&<5suYAh~OL=yQsnq=A z_Yd!IX`cU3$T>E~3y3TFr={ks?~c@Qg9-q0gD zUZ<_D3>VkaLVD~vYyE;{<^u4{Pz8D7s+!-Nx>Wwb7b@Pw zGyW;}%bX5=>#tr;K33_`mp6p5B(|SOKf&9p`nDtAsU0v&c9|u++W}=&nV0$lVi64Q z>@mFXE&ZTT81t^&=`b!I^}M(&(PR92)#Z$jl{N<<7ibJuhXU|^F{mz*ITOv{c*`CV z5=kM*`klvs(SritamC!cfCAmpt;-%xY-Ftta7SpZd?xFfk>I$SYiH4hIL4KXqZIHh zv5gFZpZ(8`_953{$rayYgbE6OLY2;Cb^$RVZ5CL}GE2M)mB=Mp3z9KU5TqWvu+l(E z6)$*Bf0od#CmgFs-4yb&)jg^K>!2s;9XXC>R+C2h8I@hEW7_HfM6CRENKBB{2RI=< zO~RR}niat8G1$7sSR;RPcoDE5@lCb1{$6`VJljQGArxorro%!u3hHwg?SxF!P*Hm9 zo-?bG|3FO-Hwk0_Mm&#TqtC-Zv^`pX!v@uTUQWZkkp4qmBJYHF@`P%)MwAK3b)s`L zHhQLBiv;J0=X)ccUn^mqieUmYysU;raCej+GM)~#mS~WL!DLmKi^J#2hFW88nlK%! z$@KRX78?bitHwHV#EjdoO}SQ3Y98Fji%qGO>^GWwXRC{owhFh68HjiV{goJK*Pp1%expD*kl^+E$x78@o)0Ad7YIb? z)N7y5xEdOmvLYk|h!0_{^S0FWcy{+F7QBk1emuqKE9;TbJtP6L^5^OaX4T7}zBemc zC^F_m2Wd@-Yn_GmCh*&INPnP`-=K!sWX;NcCkrHX}BwO|`QOz&5-)?NT~ z7w9kEm1;-hf@gLrqs7fYz(^MmJeRJ-+xAtF0Jt53W4hLY9eCBRUDOFt3cIqlK?G4% zzrH+d?xjRdjfzjGHkOo14O$Ot>+AWF_cP zu6@;b>j44NgalV zWT1ohDgsh2Fyk*y*GtzgzC-#h|HvQ1Fnat!AY@@sX zT^tc+RzC~y)VMtB7qG&Mw4y~CRh}Y9Ynv^@inN5zM_T}Qbc2>>T?X=m;Yb*u&-Fdv zxoOsDxNA~py5k!t03^Aw$X}i?XK?W})(0LRXB-A!PreXJA`Wa-Sd_YQf-cUvy=Cw1 z;xD>tqgGGz13ja!sM1Wzn9-dM);vA)ISdqchWeU>r>eXyZ;HNdqE=CbW!x|-S4WKQ z+N=%SZP+RhqPUX$@%#L071~CzEsA1FHS2;tyi#WCQBU3avE)}Q{=U{!UFn))g8t0c04AwV5r>}3MjSu){N zzpLcXKg(ym-DnNayKY7SHZ4^31Gzp{4}4#{-JU7r{>LEy1k5(9xW{9kF0hR%-Z^iw znP1a`2pyg)PPZydr}8_Eh044ua8;RfGChW9Gars)>0i`Gyp0Ob^;b7_JY0$as~Ma# z16!QUGiV#p3dbhkef(5?a^R_%YFAvbHzQGKTroz)(;Sv@mL;zh-Ltls85YYX4QFZ` zNBHa7J~0wCGSPl&FOJ|8G%0X`%_Z8fm0BUk_gd_(BA+%heIyhAMEz6|j*54VkU1k` zbwc>Zu}OyiPhPaeb_b6dE-!`+C3&{pZ=KD2VXIwI z8yjsze(Ywm7hogB*gh(*;XHgg_!0DvD1cs)(B(?kq*jmWo;v3Iz6La*` zqBR+y4`|i8sjY92B{RvsmnAdv0rkI!sZ(>^Msu5DOz_NF@viL=lsjbw4&roAHGhH3 z{bk@``&W4)w)S7>IyXS5WPM-5?0Fom*z{F|pg7wbEdxNkkk#Ce8GE8yUX1pUMrkm> z7W0ge-N;->Qj4J*#{=fXxVH|eRc%)uJb^6);%oQq+d)lA-Vv)IR?N9oE?3n{YUsQ~ z_On9&73DL#fdl?E=0GJ=>AX5(ll{DNy(wLw!Rmx2$4l3-utD zBX^P+^@c^xM{bXc`?Bt$W5qWeRZrZn`sz$}7^_~YQsr0ze$#V$LSgv4ks}~@MJ(r? z(+MV>V@eBQD5xUwMCp1o5ARf$*NSwyLoAgE+B78Tl~=~11pzpspb*Cuz*RKc<{#7( z7O~sU^sGHh4X9g5I7f%fLZ)0{3Z#C{(@*CD_`FZ@LQx8zMP}g)Yo5;zWOKhXJ}$Xh z5j%&9T{YNBO~vLGUx#=TXosJ|>m} zRmCI3J@#5lB-{eKF8$GP=G?JeuoS$LeN{e*{}!B-3}7lk+Ok#Xjr^$g&=QsLFpq zwQYGJVCK9l3brH|B5y3{wwkE_0$P^B3{*jnBnU}{>jO;iRl9Is_x4c*prm=>bY74$ z6mMoMcV)Xr56ZF{Re5Tn+M8XmD&DTDY0V=_U2S(K61@-{qY8ev-YUfo-oy0K&F(E( zQB)uZzFeZox;}qJu8)p4T?E+T)iS6F=+Ad(%as69_LGyp^bSkFqSU?~(+U z6wP%sFa^hm)M)IgK^a-tpbmRfTzFqrl#nLYPya^pZs%0jju2qzB!YM*A^qqGJ=G=R zmeL3loK=|>@{E0Xq*r|U;9p(&WP8LW9-UQ9CTmG}4o06|dSK+OthX}1x*7m23kZ4=wy|0W5J}{$72* zeUi_;1YOV zPaI{`?bM06vk#?fT&e8?TyyJ`Hz4^rNf!Zr6*)eeP|`89*qkZ+)c^@lpsdJ$6`zsn z6d(Y{Ez(|t7f1_bomBlY$da=+bG=l(E5bcSFWQJJJH27#udO zK3M%@LA^mrR?#2(8JZD?>a=5n0_yaz0arC^CWuZjw2XuG#S>gQ17kKG{>sv?_^ddZqtZvY#B{R1HIIMc#hk1c zdAU~T2(gw+?rAFOMYDgFqPn9@`7WwDfTVAk_#yj#1*Frx+}Yo9BfB9K;R!E(xJ;A< z_e=8#Qfp#RDuG$PBB2x2+0t`5TCxS<>jQ~ z3~VB{*MN80dtozAfRv~lwWZ^=8$c*e+uL$}DBa*?VNADUZbkoQ@a_#Z;`-Ls+uOwI z`WZPor%}612g)tnO8^r8cu|curOao17V##-!ti~^^0zjTqqmWEvOk`o;u+YNs?2s! zdDE7m`~l6!cB!GuH4ubLJRmRQCGRrvxtsDW(+YRL060L$zjQ~-EZ8@kx{IWfL|~N1 z>oQtwmAm0dJHPKT0RxT4@#kTrLIZ-e>T4D%D_|+pR4*gvY1=b6^D)ic&{^uJ#l|fr z^i9X;F+33mAq)Vh6n3F9!fc2uPJs}5)?0ojXRCvI?TrSiKCsbPqEf=Yc4gKZ$p((V z|6PtmQVUaeKT{l@>+8HkR!Nvr<$p+7R`>j$S+rhkwjnF>fOfh3#8G6LQ}&~EPG);% zRwU9m_`r!*s|`}xtWLle7tJ4-;{)oGowZTrMhfcHJri)hP$v|g*sH_P@#6y8xxOnE z8-cK?y*p*m9vkP#p@%w#-6o66u|K@VZMylKckfP$mR}&99&J%E zK^-N`xh4nh%{ST6FySGf>CxY3abxd|<~vAnXgZbXi_kvpD%%mV6mk|hWp0%RjOKEtstyj(E4 z@$bFyJKJCc@QH>6;HSHeMpEc`T_AnIW|^XAEMxm$Myvv2W~|W#o+`;XC-jWopo^GD z?axsf!4%%A=TdzQ8O%d&_u&)dsje^xn)gR4^=$8`-sQKv8LiIfvFZ)0gVTijKzKM% znNA_cUklaQQh9E-XC~U$(NP%VxU7+i^7X066-YQTXtx$L`ug|%Tf7i>^3YbI0111V zbwgy*w2}sKUAC`=ZSlXjp}RfI+Gbnh;2JXlJGeq|B`|d9ZNwfu7XedOA$uGyOmTq1 zx7|(KvG2uSTKPDu9U7UsrjymSEg$fCb3f3*(sTc44u@zqp13^*e4GKlb8&ZsB`dqAi7JA4+=TKOd5 z$jQm~W`2}vg2RWBit4@5Hfo8e*NJz@hN(M7RxS?mJ~hF7Ijw1D3}Yw&XOwKczaToM z-tatQ2IQsG+}2K0omGH&xl6o$bOlFzP(o0uEfPu|-Oe(PwRk5X)gZ)30@oZzhV#W# zxILD_?I_if?B>OV1ZkMzgX3>{D>OxU5iKN>Bm0OX3VslHF z!PG7i!r6N5PR*Q}%ip~b)?j4o;N!|;O-^hmbR1YM-y2D7MJYGGP8FjCIWO0r6+akk z>2+9S(0%j+OV`qjg_NR2YX)IQN!#6@v7RmFP;t$)4z~U^Lg?>(tK>n237nbEnbOSQ zt%|EeHy*gQ$3J<$GX%I{(%13`vvdKerN>w`axZ@v+!CZ_L;#b2@5`ObhmZ`NchRm{ zCNG9Hs{LkR_b2kFYL2h7As)G{y@LZ~vaWCH^3MrDV_ntS8n!V{R=#Eu8cjWFYeO36?ESHcM$!Nq=rsLu8RWmF z-K9ILXV`_M(3RX}lCjKp7wC%reL%)g)+->Pg|Yl+59c<$o0v{y2;LLORezs2F{iQc zpzkvC_6|0E^S+kHBU1MAln40qfy|49ooT#;LJxi zWitz|T*SdQ9>O~|fJ;`*icATh$YIsZeK#cK05WFYrHl%PG`I>PAO-V-t)};5Xc|#8 zTk?hkC}qCI0{CB$?&Smc69R9pCZZ=!{d^%m8Td0uvboYL>VktRNQ`l~oFA{<^TB9W zFHgxTts|oj7wMI>&3LK>LFPuxWrZM4-TVWSt}Ms$mSX(!6-&gO;Leb4WFy-61ZiV4 z0`p;x21@HzsBS68*s*Y~)(xO#LL+LBhYTw%u0i*i>hP3?HR?Y)=dCb79_V!QpP8S=T`WO#7hkkbw0!?@>vTRQ+izl z7@h>r@J>3QlA2Wh{@6k5ry5_Oo}TOqaLF=v%s2LU&5SviRkckO$@>%#qy^854q%#7 zIRnGknFFhP&Y1a>t0^LWbwE7@wvkm%bzPN_jqS+L>Mx12YK;9gOdyHp}y=am&>ej5#fP zjpIXM;hDQFHNKEZXgdDqGX>zpR~H=(Svx4k8($P8R$11LZC*d6BnMR=uViJWT!9@rDb|pWhZfEh$VJe6Cz68)>^+Gg2%+pzwxCepD}P? zPp@#9izKF>E=GwvKM#{6w1vVn0EBAOwE*#1dB}68nH*b-FoR)c>*zOx_XW3APpP4E zZzrsXF6rzDi{TeLK(pd!6h3%*p&sqo$ieq#Cmh=AuvIqtI|3J@Y+w9fAiHY^iJnsC zn~Fu$=1F&A@MIvo*_|h8=;s?L&`aHk)Gr@HnBiZCZPaWUO=it4L|p`bX(sFJ<7SVk z*MKs}K1ruE0>49JMdA+v-vPiGVD;yr^*xlNZe1^Uwbc?;q0!>#DDb<$l=+#gs(!i| zkHdCpz^%XX8H~8_a>1GUCu?l05p)r~r#K1}CsKiISy)&o=j{pSu4|B)$7Ch&G*8Iv z2B=i=m1|g;^+6?3pBT>5Xf3>D^Xtr1T)a|6Jq5j-IQT zxU-nMmApuJ=I}}0*Pp&M7zZ$@jpC&^0sL`9>=XZRufYSsq9?iMs z!^`|bOC)-9t3JrsvvDc&u5I`JXEKod$kHel>Y0OFLhyj1lgz__Zszci+tr~UqF+D8 zHrZEqi(bXdtSud_xvz$kGj|&B@Nh-{UVn(<<&Hrn=RIn-)_94IG09oVWzk@l!;Bx- z`;>(3-1H^+$A)~t(^JoJ?^Kz2P10y@Y~oLa5mxe6tHha=1_+JDqtT0jk&Iz;IJHGK z1D9unbl56|41nEF`r?w(DK0wa{FQ%&nGMk|n8i7DiZbLmD(!98=|7$@#<)>dObpm4 zP=UkzssfdROi#H13xrm=1UPz16ER8~M@89lnE(+Wk|7~=c#4mRPUm4pRuNh2Oz`dy z(I)1O5g~9o&IbohaXCr(iD5OscUT@xpN~v6n|1YNfd3hq=3Gwi6M|iT(xOWqGaha8 zA#op7scSXDwSVIfV~jSO?o%77cza>kz>6C_l+_TmH_hbR-@ZPMu$47Fp|D$Smn#Iw zA!34wIl?L2Q}IWZV@Qm{u0s$j(RR-yA8Al_>izeo5V0t^&E96&ZGVU87}dfQLC1y& z_MX^*j?WBa{QMIN9x-h#BmuLCp%I{`Mh!~w0bm>`3EYKWF*FrE*O2Jc&0;96%7G5~ zomP7Tlri$K9ik}X?4gAbT=eu*+wGR-VbQiM-G8pSV(CI8M=4?WvtBw8@H5UaVmt0Xx{v8e^IU^&N39 zqNA|fwtuF)@(LJdg(_Om8XqW3OYbRe7j#2zL%lRCOstjlTU)rD9`iN%PeK$Asuem@ z^8S()U>F{(X%D^#G*7+8;;(r4jGRr*l7Cl~mY6!*C+OKgD8iq7Vv4#tkhmg$wM2iZ zRpAo)5LnB!n>}+Zk>BP=r(n$maut*+PdNa#Bh+#y*37}UkY>U>EjODw zx0Fonu1}MuoPaNRhaS#4FV%`rn@pnYjXofZd(3yA5BlQ$aW3@1-ej4nY?X!BpW#69?yuvjwdn1v)6VEOx z)=V1KY@*+Z!|Mcw!+Lc?F*b;yLBRB^-0Tk*A^!IMxKXvxy{E>m z?rbkSTZaKU7Rd5OMcAa*R2Y9u^_i(eK!Mo z_7;NIx2*9KS~aItos_+kMOO?Y_2nbQP6P0ox43NNjRLS40AWcxG%oe3rPd$>o1b$4WUda&Nkq7Q5`iqpmWS*1t_~m;$ zFR4sLpQYAe3gSW`RaLl{qIkHDh+{bqL?RZo(cjr{p&&3%I8zrJ`cpY}XZ6W|i;Um@ zC9db6$4JzqI^RO`UO*l~u(!^l*#^vk>zzs32p6Qak9YE>oEMF^7Z6>67M2WNCD_9O zjqm+BpMBpyAQx2$92T6`vk?^K_arat9DM8RxKHKHAYVP$fADByJB6uV?`|WWh1k=u zIy1Q&S%23znTTZ1#tq;`ErC}6XqK|vXAO^uax7@(v=6d+u3|TMso#sv#PEl^xO8V@ zt@~_^241*c&<{!|ow=hFKIJmDq1ni=LVaf!3g@d!a0$v6Ig+i0Wb-qlzARtxDt*t( zNdWA5M;-F#a1x;z+^~OfS=@ln*5dfUu|GOZtf0u};_k*MYnB!%b*0XxE@$#nxI8iE z=}FdXP}ViTx{pQQgM}~Hb#Lf2<`SC4GF(CvU#C%lvndrMl~0Q7{&DRXs)fGn1_?p% zDc)hM6?y*%M86to`$gI`!IVDq#RYVZI96ZA5!%{ zSYVC%foGlt-~nxfFg5hqHfPBN`DM^4tRfB^OeeZHq7TR!Y#{E=p?V0lPUYEv6R#^! zpZY(TwH2Fz5#Br@Z4SFiMwU_ATu?V#e4ugE+WO(#ff6b#k}0Y=Hemv5T$z7@VCl;Dd!jq5~5SDl|5YV z%mRcDF+f1TiF66v<%;cRId?yDH$h8kaYgxYayQ`84}}MLz=v}b&#VzNOK*gL4Gi;( zy`n#mSPa8JNpfKV(6Y4v!1wXE^f=toC8gdD`->W zuW!j&7@hDEIqK*mxhGRYHzy+*Er#sT+7Awc5^K~dM>k=zOjKD?)_{o4&;L8x$YQOy zu-in7b0I1u&n-qnG&(5TDzrRWi@6~=oiX{ISSEZ^Wg}>X=c@O>zO<~EyiUe`9EV5~ z8r;c*|6cfhEGvMeI?uD7JP4m;-D)n?hpHdisM2=0hUWA)g|3ojNAc8*=Li6iLLqOT zbrUZKy)96{P=ei<`59x}C4*G}xv)A%y4G1{B{g#bGpD#(?=P{XN>A$INa1PxQvPSU z;aPfcvB9UeUwaW>kG*yxssDV1&4)VW7Q-NIjZEAZBBVOga_%WQ4!ek=*Lwn@E`A|( zB5O)QQ0p{N+cs5TuNrXTQ%L?cz5iE``I2C$XHtiLRyUo3!(OOju!1huCPmuE2)#p} zE#N_jiEK2Q6=f^> zQ*8fI6`!@C631AGq@()cp1O4bDnNkr0*_r5pzpNtWJXe+jl8C2w-)IJrf zFxQ}4Ju72s86sAWpJC`#wk%7be)$j$+lm}HDKi^dtW$n>sCcTyNtjqnod8XLyS~{1Z0UQt&y z7~OSIP;hz~I4bShMC@%*?d9(kU?rA^L(HOTY)sqBB{N(~_Gfq-N4VlzmO$)6B^Ch~ z$qMrl8pnyG?o|{+Ox@U}>IOawywoCU=zf~46dc3{>e`H)Q~6P&&(@wIk@1Xg;` zgDl7>N{|%FF`$@iZ z%4H*Au5dbzXj&OW49yKu0_5!c5?E1ywP#EVbtIGf8Pd-FF7PG`%sAg^!B0z-g;k41 z^m|*amHToI;0g@HSvlIV15~EpgDP?W zLZ2sW5f-%Wm2ihIUSpZG!!2ST8+7AT-@765K1p+LTsGLI`kmBks|c%)9Z6F#6WY!5 zO~Sgg4MUgObLx`{AN_-bT)c1DaH;F4l^(-ROBpZ~Iz8;~p-e-K>mke$!zT#VZ9X#& zLu*$Ah@UabT~xIy8rWxUe`vxB2OAKjIQ0QqQ2#<1zBe}~AYYj5Tzk!6Zuuw1t8{*b z%vmvoPl(|iaS7}T3#Tc8yY)HNzbdlP0$W=;bU7G&K!~Fo9hos_9-pI%I5bs*yo+2? z$IjG?(24|fzp4LZCgJb)4OUjHun@~ZH;z0w`uk05(*GDtukK?l(Jjssm{;vxe=q87|69bNr%CJ;TZJPf;Nxb;(P zrie;tWp|I*sl?J)3mYf1ndM*HC^gON$k?a$c3y+Iosa8H2)cDDlc@*vxTHfUYj3(f zUbZ}s(0;z}DRM;&N1D<3%}eo^zRLNZkegVpOADrySSp$UgP!xx7-m&fAuJ!~Y<~p+ z8`=Tgpp5!J`$e|q%vS^$U)-;e!|22Eql+s*FY-~-Rb>fZ`<9jGG*1E%! zh10|aXDIWeuKC^1${u}vVDt?jdV{xxKF0lR9I0cDA~H?QMl?vSlj<+{`*N@`_|bJ# zKHe%=n)Rg!j=n^SXV?^3?Nd=Dt?HK>e?Km`XGnmP`~DF^gAj0EfzraPvb5Bse3uG{ z%NaO>@`L1J;a0Gx6E~PXygS0IZK?NY_ds4z%QzKP$O*cjT*W(%J&V{`vk;Dlu#uQ8 z{e6r(Vw%abkhIS#qb+xFlRnli9=841M;dM^WdWevcfg!Lw*ktdxsqR0PbwV3j;Fgc@m6R#RuSrbB_0 z2AVcFWIl6!JeOFYY;)4oLC*DGU7u*fx+v3NsYy=8n=IN86I`%R&H}M3_5V^RKdCL` z+RnVWm78Nfk5^PZpI0?MeUPhQuBSUsTRf4`IajS6{&^N{dmr`!_mgYk ztf6|oRx)Pz2`^SoD+n~-k! z&c&3woc}<(Aa*{LIG-brjvc^Dc1L~ig;4^(G)i6csNhUZ^6r(&qnG{Oi~EXosS=#ibW+kA#bj^Okaf(jPsC7r`5vdP@;RlvW zqok~m3Mo(9``W{}9K`-3NkgUvUOBaJPiZxiz}+m5&+WkvL65EXMIrQA>Z%i*RdExz zII54$5_!?=)lLaVWhnL)zw#C6r;5k@g++Ej&-0HHiHT41^hTU;S?fI*#@Fltx82N- z*I)BpDw~uvg)_FLa^0#(-j&5ap75({0-BxF9OyqJ1#EHnnn}JR)&^i(3lo6RT&?+^ zlgoI*=?FkmKCs~B&2Ye*t>Y^lDX6GpvYRP?l#=prGgAV0sB<)Xi-y6I>_Dxba#fb( zu~f5e!4x|%kN#&ESKQJeL3RE&|Pn6Z*WpSXQQ{y}IrYNr*sfksi- ze(nzgQD5x{LFLh2D05l)$TDEi4z#^o$T08C^!+0TEFyt%I&zF4{uw{<%c!qFQLhR) zyd4DMw8BkVdRmj4?24avDkR$u_w&@ox6pV6lT<-OlKwi*GV0I#VS^9WRCe>d ziK4bCkkyG9L_*HzX;{wN9%brl9g~^yzG{f`UU2#*1}8Y|DmCJ`?L*x4fHmWswx zWfoM?MjmwHW)1=TC)diAdjY`5#-u=yj0EjYuLc=))_q~Pvc1PDe1oAxhC;4Nxmj( zV_8eg_LOI_@Tq3U*>Sp;qfBp%aTc zTTaEkxV1q`KMIOY=%!*Ar&1H~%^g<}Jw3T7AGJKVfvqs@@raFm3I=#T(xby>v&gUy zAd$l&#p+ms@G4S~v;|w&2aKebA<2%1+(FpI6tc@ zwYzX%rZ(OOEQ09lSWqW7g1i1;ri+iJ#OEYsc>DxHfSsV^r{Jbnzs?{4D*pmDP)34% z@^_|{0AviEzh@F>f^AY_56>!9nW6xFgblI-_&-;cCfOU`xfCB1GrQYGVu*}{$kNF% zoZ;huQ4+l8Q5ALKpaYPV1ZPB8f%F-J8D{yGsz1w6J!8^}x1=*(Ulr+};gLhL_IS8s zFq*7Kz;7u$(ir|>qz&2-|2FxlHtwQxEJ2OABt;D{!RP4M!W(Z2nyDP?3;dhom&lw~ z-`lZ!YaI@p#A5wUfy5V6=7Er$B%Eo(inXgTDh=z%^*57mKizz4QFPo0i;|VqH9E(q zx{Yj-LrF_XBLi}J2sQ5{awLi;v=Bx45}9FV2KlNu-lF)PQ~6WHb>D#tC+|qBquj(< zenSP(GZwYtcBNcOpu0HNB*U{2H|2T?Ui_zjT=)vwGOv#-ckryNNpp+BE%0JzbnRK} z@BEScu~w|GeTFRH-oMEYVxC8y5YB>Ed>(qP+5m7}q9xoge7kwOqVp~<2i7^CDz>-C`^nr*HMl4&jjUZ&bm;3DF+Mx@9j9y#Rip#&mGmQ+9}M6&U6P-rU;M+lkd?IM zY|fGV%_*YGvLS*^&SSVMfvpQ0cO61W+fqSt<@^_x6DmWg;_o|wFSDeazdMjFD za2Ath3dZ7TnD$>;N+0sRhtTDW>CuwsmVQIEz?PLC4b>c1){t1Zks(67ziwqqODEt~3TJMoM8Z!nGBxtzv&+- zT`~{(x&t)$c_Osd(pVn2#!BzQnNIFr`bmg3uG8H6oQSi%_I~*cjtcVILy&9Oc?3JR zj0i4u4ltJI&m&b9NldnaSOa6o3lA}7{^9>k>H0VvbkMC&2=-AIbK{|vg_7C7ofY@u z5*d|5asAFl-=#7DFhw^;ZD+K`esGov~dL#L373U=1~c-H8x1a@6>Y3fY{)I6LF=L4h?*kQ>LVDP%567WnTU z;fA3T?@l?{K*R~z;jDFG3iu$IGQN?rogtA0hmL*a0F>`idVx9MrGpmRrdMj0rG8-|4IV)n$11|XgL^1VHZz2EG#jcf4c}Oy~smUP-E~b zQ3q{L+fHRDjM5nH?@xpm$|G)!yYRx_NajacfK%J>?@^#K0MV8GS8{Dt>{crK{c zL_Szy7bEp&Lq4!KeRWsD_O`NXr$96K#q3|V`|F@>9u8+rNVf1@38+HZeY@GaVXh`V)PwZ4h_Q7^wC&^%3=hNBv+?l1J)LqR=9cRX{Q&G2<(tE| zDM6I+K7vAwB6b~VR!+j5+$u3(BG_1!L&rkG#78NlDR=FZ8 z1+j}EQ5100lJ zxiRf2hP`hj*bY(iwbmu(vtP0wXZga@=U0aErjd_19yPdXdP6pcay1pn#bf>|HiPRW z8d)~_rGrIKrAs5gxkx}DoLGHniNcmUk~binAtIoaCA%IGVCMiw&(9dAWU8q5V_?if z;U6No8vTgkm*87l*2ix@il87MtFa@GcM%|zl@bd)V`F5k2@!^s}*jU4`;K~AL3#oS|enH`*;p3dVNsuB$%4?5S#G8g#SHa?Z z@o*zp{n^at`u(y)d>5XV&3HBq*vxcV-PmRpjYvD8{I#9Ab9sV@fLaVa7cX#)9vq`A zk;SbkL;W23PwT@Ige?FNWmRPzrV}4g(tn;3`v4IOpA$SAgw5yvnG4~gt!7mUu;vx# zOKQHc>n!3}!I~5jwKuL&r!h^4@{N(PU+~uEb}a_y*i@)8qzleP8UlYt82bMLd#tLP zyFagiJ|VaQoAAGFOsXMM8_QeWg~`qxXkkEk~>gfe;e(%DjEi&eq98p%3hXHb16$;eOAYVTIKTs-wZ;86!g4mS&>$yOwyV-Gv1J5P2!Q8WyFn@VU+w`vlcyuiWswYN(Vtt8ZQ7?g(S6_=>Ck_KJz zS_>x_U7=wFlb+??dOeP3EXnP9xEX1us&zT#q0t;THabLYiQN4Pk`W4w12MYm| zs<(k=XZ-&2RbMvgT1(I7(E$>FYItD5QTtLP@E)Iv#LBBtjUv*E&povyQLVl#sAW#4 zk9($0bKTqjQP3UIn~L-nO*+D_6hSV0Ihiq<>=A!sF}uVKo|G67H5<*oX)RelH*#pJ z)aGOD1qgbO9zWx3xd%{_C^DA)Vii;MWA<0m*9e<@fNB)YARp0<+>O(b22F1=$V$wq z{mkjfRk0huGcFdty*g3ei4c7X!lX892@BZUHv0jM5>QQ=D}ZWkBRxH^-bx=4oXHRj z@-(iMN5Zj(ONDCbuW$_-rMLXP}A6@Jh&W;qe%lR#d1IVXa**$-SNO&}Nvm_AC4CmkP8BbB}ozEpbj ztg}%DgY^yD=5lTD!o8uEC83SghDaf8HLr1AA25>-QtPlFeuMOe^K*_ca$Lp3Sw*ppZ#=l3(0_x@Kd5Z{ zorn7x91}pl0(5J&PX<9Wt@klf-4z$ktvt?J0kSe&4ZbR zc%k7^fVfl`nvvpI@_l%FMY*I##Sjtqcd~*={Ky2|Ft#x3aI4WKYnp#@_tLY zCV|m&b{eJ7pC#KDHkV9&&7|SwkoOdNHUB6bUJ3Ator*W{Z3?zvwXEz%=Yj5kR6XoC zc^w|GXxgd<%DUW9=|JxeEkbe94i~o^U+!PXv89rX2TBWfUQ1G)UylcbVH7t9kNxIu}|#MNfjwl~wjY{U>I$Kx=GWIR6JA%)iIi z&g^#*1M=CG3EfLXqg~nFcbW8RmM=C~K&g9|SI9G*vn}`%XDS-Jh0!;EUGM*D8Cavi z;Dqd+dHKDUP@=)_XQk%4XF;eBPS4K4;BS^DWj)d#t)rW%Vk{bkY!e>B@AH~1AxYRx zte;q3tYTe@2giHOl&kfVIPqZ?$}|w`B8-31nBpE|*4X)DLswwj3oB+B<}@e-#&ez8 zTUJ7gThJ2BBj(m^Uf>ttQ|SLtDL{AQ{xd1%M5*@wXk2&lV3gwnReC*mX4{$3F5CDy9EN ze-qW7B7w^;?mjICjO+kgp;dg?x8l<){8o~eW3JHa5B||!JU%G@5vcawK1!v=o8T!U z&3U@d>mnk>rxIp5C%y3idILis`d~=eIay;tk;*3thmp{oSRnXU%qsU-vAFtostF}kaRnP}+)kNqQ=8Ki#q=4EEXEp~YWa|;j}@<4 z^J!dsynN|kyJ0s*+!Ph8<1=wRAB!XD^ZR85>}R<*4_=Bvt>AEOlCE__6@&bly}$h* z1CQk-1KMr^ChYp4`+FWRqZ+Uf!Hl!E&_d-TAus5+N3IhZwlE-nZl2#>0wlbtC59Yo z#64Yl5FmZnVc9DV4k4i8yW)DV1-8d&|9Y!nkTxSttN;}r<3h8r3bG}94piaL8_ofA;>uzOC6G7-)b`wWtOPjZlcC=M*qS@7 z>sx#N3Im@91pa;mkkk;IJoh}&G-T|B2UFEoQ(|XDUPs7U0Uo7VAC*Nji5j+XMMp2w zVEIsL&5s!N+LlwbI*o<$N_FA`)3?KYR@$TQG6?^Or z-c?VS{7{6Uu%(KxHVBV-N}W-@!^!Jlp&rygUvaD2c>A`?c>`x(d7rf|1E=o$VEfld3I<8bO8A|12K5CbLNXQZpZCIDxd z3Ox8Kjb{;8rUZhNzosXUgCZuCqMwk8Efn-B%V1PhwCnDgIQ*xx<6upzAr7<-y>w39 zBXPXG%Qr=gEMSnWA%wq*q(~$%6e8nYiJbI5X+UMnnu&agD9P)+!3O8|dWd!s-)BTV%Mo1!68Ur)m`p;jUHNZ*UcT z*bpi-FyK+64qWH^j!QJM{7ROkW4Qz|kz{Bt z3=adkr=u{;3|1>)VMB07L`3(vyt{ynuaSS3wJb~nS06J3K!NUt$flmJX{Smw!A{OM zjvEQ*_TjDfdPz)|rk_!ghItgtZm)z}Wj0|1QDUsSnIQy1oo3ImJd9|hQaiV1zKq~n z`0#)t=-HR<1}$!c^`KH31JZ{W$;n0@jZq0v43HR`o>EvuPN{q_(lgEDv<;yX_e(sr z;UPd+yhgp%5nM(H1k#IaCnId(t(aYo{>Mw{@-d!8t3J5pJN5b)x&(%Wbhan4&dX|O z9q1|Aiki~OQevN*t`uvM>p(@tm1YP!nm$*qaj3dwd5Tx1Nv-ax<4=1 z5R6wEl~%+4_tZM&9`^0RvUHi?-Thg-qoqlAH`uU}>uC@Pp;tJ};8PNZfMGvQ;9BuR zD*tke;jhTWv9PbX*b%luoLCT@2>1p{Gf{rYRKue@wD=o0wJn8UV}h_94I``=)Lhch zO?#I^uKv2Q|5^@%e42s;ExA`Z20uhQ7bZ$D#05WigxA0RixoiD=N)q5%VO4VQ@8;XB~rqe13LA0Au!r$XVZOGlF-Qed+Qs7 zpAZi8=u|<5X+4=hsCBB_O!D?fe{qQ2zEqo-d^>`m#;F->eQDVa-jqYI@b zSgB{~YDAzjlV@zmS}fCzFeY8PueGXx;B_V&v*qcz`?KjEA%Qb>bZSQ>4;qt0t4W4e zV=Xqi8=3bmGz--eB+&=EoY=EBh7*RS{uA%3BJb9Ldj}mfQNS8X3{m2GZ!PjXDvgYi zwvULhh^u}L+=kM18Fg~wg}$U)ZMerPr6X(n+O8kd3HY55dq=AST>4qD4paVy69fNP z2(>I$__67ZvZp3NRMe=Qsp7_eYVGL35HiL}4<5*lBJo^Vx7^lb&rLniJ$5c{xXdMR zqYuxT-}jqo9p|96TC)20e6eW7v0RCoks2bc1wB!NZ>rB8z@sBERCBt6ihGenFuf9u z;TWJezuFWu5dMoP+>+sl9+gLn^I(r`wOPYZjBAlem>17soj1den>s=$BDSJVs_-8x zmV8uwb#yQ$35o@Ignb@}S)dgT9F-ocbC^P<-BJw$W8n7Uv5h}l`AGem&=V$Cxm*jN zL78|e$N~i64h>XF+OUP|b#~Q*ybnYKoG;-Ur~${h3pMV-Z8E!t-9-K(=SNq*{ll4; z{2jHTk(O`4@_XL}m`++y6h--0X=fARKg&E-HK;Jn-Yn?C&)?ax*7a7;($1L!k$l!Q z#nriRV$?r$R(ac$)9{7I4_0|4bxD@A%ULc#eIxN8F^B1M6M0`79AN)g^l27jOj=Ua z&H;PrNu1`LHeYrpm7%jXoO9{s7lr{rQSCk0?{eNGzs&q|L;<4A1u-w1?AemrMl`k5 zlP~Kjb&cf5Ch6>mF)PRh{E{_Po5GR;=~xm(MH(t%6jq0*&#~@Yw>NlcWMNtVIvlK! z`1qSKvEfyhv~0O)0NN7>lD`X)J;j6m^ZD~}JgM0&FrpiW%Mz^M6?4CE3lP97k$fIL zk=)$N5&lc)YR2K!jRU8SLu@ekCgXqa9*747Ak?Q&i$g3eq0qE zU-+Pn(c2ski$4THv8QSAFJpVANf8osfqi%XE^PLv-i1v=xC!tz7ANRDw*k5nP0Ho# zgkpqR6t^2$N}>_!=t(KX73q@hLo?^Z8A96(psqj*ll9eHwv2K1YT$xIF;t1yGkwN8 zm3|RmOVR#$&ABK_-#}h)v}~xgn6IuMu)Glz3|`es`y+tFm@m^f*(vRi?+~ax6UA-n z)W9$5oIv>VZ8ba{@k;p3(@pXIt3OLx6u3rBhpe;X^do;w)y+_r@56X<3>3wK@&H>-DN=6g)5qSaTOG9r7>jGTFt(p#LH7&l7r6X9UgsAg)8W~{Sm=_ zA_!}kzk}lx3=ffr75$wd;j-daxqifqvt6#6HK)LQsKR}>ReVy~U-Ew9KK~3e)(h4n z%jYRS$XLEynMVl>fEg%BA(nZN1Mr6J>AmnJ^LQK8p3^jh%WhjQ$@46(Ja>DfNodX z(8UsM3+g8n++~!VNdY@i_X`z$ZCQRN;G8G6yXu|;Z9=s1ot>~RFoVS1n=0U6Tty_s z!&PcV%N{1wl*uqBAZ2eEzf90xGfFrGGgu1rhk+aL*@JhRpr!t<&SJfHKp;85cFgTQ z^T}h}@U0xkX;>*O<&)opDEZqTInfQLI1J& zgZS4)J`b%H($#L1sZ7%P!z~IMNG}c|0=?37Rc{A=iFq;OqtI2X9C86w64Dz;o-`vJ zPG;eHRCg`-(gN%8rRjxJ@y|tHc@b(cciCM%=`3Z-O2319UAzH6i|VMNLwTkHLce0` zJqFpDu(E+*N+%*tOrztf2X25?KPt%#}@}y;^@g=~10B?2j*VNdAg_uJP z0cs{4bRL4uo8%H@(^@#+ZM@*YyMHXsaX)AMAd2&A`v9fe2a9soT+!oNZZ zqlG@&e>0~EEcvL}c5|S(m^gnpo?eUD`m7T(0Ku`yAOks%n^t9Ks^f~a7zED=9@Ht^ zVSc~l1G`sLs1(+>C77@%Igd}y6Rem^T5Sd>w5+reD0-YQg{E69rU5y9XTP>u-~P+S zP{@W$W+umnV~Y-=WTGs^|6Cw19D0pITx}-WdgIHSA>oQe)pEbuiDPuD9S5Kgu7}wl z&cFa<)1i^%PbD+3!RmO^6Mg&s2NCT%FC#Ex)z}Nv23tJy!GPj|pWJs={e{k$qt-X` zE#A@Kl13M$8wBQ`!h%|u<-4AfFe<-abAhk^zO0~Q5jhOrtpkSqogI{BnFpm> zhH#Id>v7sTK^<38zd|W#CkIO`c*uz!n$h{0=99u2G<%VECK53{!(Fsl$^BmOpWsgf ze_IHN5A1;~v^tU0>z>!BC^8N)PL@PfP+(LQ@$#`mG6(Zc6^5^J(Fp2vQ z9J9BtuQxkQKMFiz5?K&Kuw>e)%Lh8&r#;b+Y8$v_=w8#kc4j%n-9hk5_kK7Hn-7z0 zGnK77)4JqvZ;xj_7~GNsmNf#~3<9Fy|ASsycHmcSO+A9eGgUqpZ3dzDF!yF39)qGo zOOXZ3oLsdaAg@q#Pc%5RKS1&q5j>}i5pKX>i8IymZ_21S?6ajwAFq_i&5UAZ33(U^ z2$Hl2QvFWreT^Pjy9NCP~-`3`$}vS<>(!h1*qgPed)aOteW@lJ^;`o{d~#L zBO%8VuXa6vNYAVXVZrLj-44KVLVb)|0vO4G0i7JcCy}C&RM8Ct(Vc}ifTv}imws(= zH9kT>1pr&5w@l`~1oB|q(7ak%Jt=?t@C1v(ynw>(@XPYV6*NY>LMJa09(CI0I?{Uc z#XTt*Uc+ifh_6$Gr{=Dst(QGyw%@&MC2;{my7~riD7qUuTI7`6Z@vNPL^BVd)pvEA zc6TsY8m&v^iD-Cu1uxNXO;SpNJ!Fm*ExGn47b@5}kcKrGUj~*Q=whdG2C_FR;3lLf zJ)!pS&g=hiN}TUK;jh|!tZ#jrv5WZmWY)*fVHURwffiP)F)Kd1^)m)|&;MoB<;Nhv zY4fpJ>pQk44m~#^pSouk z0>Ls=Z+}+O;K6M2N7@M~N5mIXg4gTh>R9f8?(FP4rYzN9Sw+Ag(k9!etq?EwPJCwo z_*>5_l8utRJt@V3KYFX{#A}y2+A3j2l=5FuQ8MTv=~P#FWdnztkgK)DO%2KwP6Yj z_?CwR2>`Ks^TBlmZm&2T0f`2sWCF(mo^8yBPDU&p;g=sEKUn%9seSbl=&O;;7md0g zx3gm07J)S{3XZJ&eu8rx+a)-}pMV6%WK>@4rD{9b$ULbS|30t?e)Rx@$l90Fvmr;_ zr$2;)bL=Z4T*p3jMTO1TwZ%YI0%$gtOtuJAs_ZvML5Zi zkEpgKa(Ugm`B0_zN!keKYX*%vvdV0rg5>}e zvYim0YXel2Av^QsAc_f35-A|f#&k%}EQV_dcaHfxR%~|0aXl|Hkesvrk4X*W8z9V4 z6*R!ep*deAd%yoj#u<(}9|Ev($jrkQHrs8s+e?#uj72$r{_*P$^yC4&+E2L9+T9TE z`|I(d7mFKM#LJ1;;iJ69KpyRut$qL+5*(kL+|p{tsSVp{cUmKV;o}k1%YQbD)OUF8 zd_Anbeq_>nh?!t%GXcDQqK7Uy30m$!sc8#^W~3UVrExUNiSw!FOx~rMCa^i52`s%< zfDW49T5TtRIgvE15sAKgBE7s0?3xEA#FbLsTZvQ2E0j1a8s(@9S8X?ZzWaNW##yw( zxj8yofB!#fKzu5Tk-Zu89!f|iNHZ;@hufjaO08+;@O)uj1w*JB&srIZ-;{m9kiRv; zD#WVp1Q;nKPKi5=BQr6Bv&x?P$94GzK=CltgXcevbIS3j!i;T-e7ITW5826?h%i7nq*@!XW|&xjiF4bgZ8$dcI@{j1#Wz zQSnp|i(|L!+cR#eTdMA%Hel~34u|RSULe43pn8&ir@lC)v~ZWmSg8<+{*4}>>!SaB z%wVWF@KMj4%q^CoqVmsg3F&H@|5)sBIGZAVkK6?rM04nkHxs?Yt-b#}?(Kq+5>DFB z7IgqADMty6hD0W3A`??P7F4YqYqD(;2P%Y&B=podGC{fGa4N*ETKTUpr67RThx19Tl;oIx*BhAR1J(-!0hIFwSOm(s8#k&*+ zc(klKW@N${L6$h)i7D3vvHySlD0tzKAV6ZicAfQM#A2-<5PBsJGz)Q;XnJsQ-nTY` zu4PSA+_CpLMR62R16eXCuf=>?6^U@p_LGzqp@zBpvw+uka4{D3p5WfjqN$d|y{FY07-w#*=UV+|!`#9FB! z$T`Z@f=0hR1YI2Ljj1KhL)l%9r)$|_)SO{ON~SxF2oVL3vLb7PF*qHri#FWsk`@?{ zoJ)*hH_CE_`c{66)`%}c$B*z{=m3oqQv;n*;G=)z;UbAZCA*lF&?*6Z#q41rFZwaG z1zkpDLOwpGc&o%3(TR!6R;PXhfrDHIFjcK0owGSICFI3#4uo`25`i;Emxy{A0WYOChOX1h$y#$G58Y&F9RnV(mB zrgSKiq@k_svDrwpOwPK@^Qu0V zS^@3MyDl%)@;$qh_YX zuqnm~{qt49$4{KxlW9xlC%6+ehtIu(cki{+ksYf(>8y^n(H*I?AzV3mt^?zYZ@ts! zr@2X`vJ!l&m{P%n#-ODBO|FjiKm>>d5&H8vxwg1Tl~4+=*2)$74_lCD-V$tZcfT7? zH-JIN_7oc@ppUK_P}52vLE(itXj1%v4W!*`{upmtzKzyFhL2Yo3qy zhJs*!GR_vi?g+T$HdMU7oL)ceag|7s9dK6`S+-Yp3C(;j^JzMpbP=FItnKfg#f2$e zHm)XJ6)@Gs)~sxN*S74z3}>virqcEsHZs|6s>M~ZguC%`0()sw%5cbw%uYP^D@SW= zc=`=?WeDWROJ~AJ_r3`YqW#1TXX9sw2&q&1k;F^7CWD+?^bF+;A>&$udQG{cOj^ry zXAr$P;>y9cj;a_tHfPN8iss*i}@A* zdwQR|T?yh2HiEMs)wkgH3nrss)7*cE-46Oy;}R>KgI#BD!+*;(dqsf4ie1$@WyL%H zL8d5h>$@CODESI6gc#ipjO1BmeSl@IAtd5!SWzYzZr7dZ{6}S^CPLAJRYl zO?<83a+w;vB#-rN6ai2LK=pQ7RsMI0Zpg3P-t;ccuHR_mfOmv4lr_e)Re2&N-Om4p zdVucX%!63`6JdoxF#M0OJ43}b`tFjA*5m=>kwsVK|epW zETImV+$I^z(;id2M^bnW^<-Mqk-WS9A^bXS4P0)%zviobbPH@UlrD&ZNHxR=Bz9BIGzqWtv45u(R@J;Ua zS;D_Dkor~+@YxfqKUQqIYtv<|`&(E&eY1F~7Df4F_h5REQ@uleu8#kmd!Cl#!Q5}Q!?1KCS(@euI$gcvIBX=#Wn+I?5g`K zLK!9ah_IS*ujq4&mLmc^v@ z^2X?V2?ls#ZIKj3Ro#Rq#91t~?|e90is2@SLg3{xt@2<62UfSUYwW;LNLLGq(QMB3 zB5v#ZxkV;Ebq5*s?7iJ-K6_A{?`}WW-=d3iFYZ}5{@jo)g#2ir)?t-4{%A7*41J$H zODzr3i{i#O$;Jjm$5DJ|hI+dqrlOOt!{QayldYZ}{kf|G5vII6up~*?3U}fF15 z@Xm95`9IZG@7bK}OV9Aq#%3m{*rk1AeD)boZ#vBcSiDFPy)tp|?LFJjr|RnC^VVd< zkU|Wy5C2Aya4&?BT`WN3^*AsJgp#j6yo#dq~Q2bxT*Adb3Tjks&V?&jl9?}9_j_yz(Gr7r&nQzM&`x_mE zQ9PpxFn8fFpC|S8B}Oz{iGjA&_#5>^J6DSmdn#F!=zWK-33eT!2v&kdrJ_T9g!Bxu zdtmubWpbrAwR`p|tMRw!`w}kp*hZqD{Z+nnNMK1U+B(V}P+|n-hbq`l}R9HsxwL0Zycm{d8Mvg+|;6aa^km%_joaWSS1p-N}xFG7`ZP5 zNv{W`Qo~!vbhmyWjZF}ky#0CqA*@|l$0<_?@3xu>uA?X#mRm?9W9Dg4fZu1J9Svre zon;yI{AFdb&HM6AqY(?hhsHcC_q|1q&so=K8XTer;x*8-MfB6feM_S#llgm;y`_AK z8nGJf9RsdlE}(^(96PP7!e=7T_Y80d%c_+(l||;&hG}(L3v(eFY06@7@RST@rVb9T zOlh9+YW=$5D4qQ`mDnicZGs5TAl#L~m}TZ(PK-RbDAeAmf0kTQ>E6yJ59`_m3k6Lg zbw2jSq8Y77+(sZ4)WY60G-qR+)A~-3b>pQ{V<3X~$$d}jK5q9&gS5k1(4}~033f4M zz7v=N1;MQOlV==yBik`ff(ZR*l?+TSW^h>emf1#=QQ~gUbv_tI_bNNu zAfDhBubps(fwiy@B_?_ia+91=NdO|<21{c`m|Az?s!(HF-7tJdAc46UW0@-;@W&p` ze#?;O!to}IH#yN%bZ0i~Uf8w4Bcp%%Kia%%7>jKzn|8vGqV7yL5)+r&pNrRXk&XM9 zEgJjg#)`q$TF^kR-*k$)2#p-Ds58)d??5%-O9vw$xfsL1`7=yQb243U1Twz?-WDRh zy@Lcting8Yu#E&nChxW)<0lM_8L>hxXYs%^E4@%Uri&BCSs=gl1h4x;aiwpp=8$3i z*kK1c-DNIDo{eW*%@xjzlLkIMIrZqS2Tm|jk+&LGu~C5*<@q1K<{YHeJCLDNitVkH zwm*9kh4yS#9oh3q9SFplHanLoE$ak?m5WNYuUzi>rM%f-6tN=wx?(kywlYR!m?<0f zNe;f`n+ip+bQd4$n@Spy2aA3-v4|u=5CJ$}-oyg!g1@3%>TPz_I)()Y(ZxgY|Gwj5o%!;j9E@nO_O)_|KLeFLABladwRbvzuV z`Poei;z5$HnoYcGkN!r6Xe(?g9MVoXCvL3|)>MI;;c6%r;f(7ZMZHsz<+d2B7H#9%XB9J*2vdBD|k?2>lS|gxtt2>}#l1 zj322*)L`VhLYFw(JZrG~D{;<8PdrzcmXujmZ<-B`!v zdb8`{_0S9WZrU`xnAY(DE3nA1Bzf~lnf@~Mu}9}9GT+{7p-Y7JGI`)*|8Eyr zQSj@vEetor{WcjP{UG`nZ^MFJvJ*fZ#eJB~vfp6cQZ&S!{B+fAIs4{Z{RX0%*bTkf z$jd6+36pG$Q`)XtmK+ywjKgON!nhBlOW5u>o=+8v5&GRFNz>!+qGfbrobNH>Vb*}8 z2z33AzjssN+X3YTSIg|~rHF`-@k5bZw_EQpIL~+Zn9V zCgh{E0ncG*lx@=v$~6-79sEwR;vki#GD}Np@aD6V{^&FIdm3sw_$IXbjptiPH#Ch- zO~GUJ30A5VoUx{(IvP+v^5B!{70~ecI3e#NqOIIC2Wy}`erZ}Ez|}R&hU3uZi%QEM zEr#oQi?1{Bqe-(PHFjz6R%RF%C$dX5fTW&+17G?A##+9XE&wd*VO1jAeXi3}$iXzq z=W+2r3m_Z0N;w@BTZGDF4>j|V{!Rk}+D)*u*LW2b)>1>B;Wxq1NlFnCGKazXcfFFL zwMBYdHKsPg6NvBbCVxq9FKJ&zTZZ9|v1k$d zd1o;LLhRX6tdy7L($n4W83}-Pq{78)I&qIQg}I%iKF7GS%at3Kh3iXD{9@B>V~U&= z#O-Cc@$bu!a=_rGgF&EjUe;SV!Hd_}VuY31oRe}axE8SXit}Th_AQaIQD!q1SOX!fNU9$)LzrcReV{b}WzM(XLF|_(2 zl4Q_Ta$y+vQq^qDi0bssK>-=_OCYX!GwqvNw2dS>Q+M7jHCwpq{ z;%O}{tlt5;*3ZfZ6YOOJ7Wk7p0&|U)WPR-fdsZh1t0Ous?@Pyd>+U04Nd9p8TWr!> zlFqsc4`i#dgMjlpeIDE;8S6tm1REXyfDGb^V>H?R3M6V~Y zEUGNZBvs^Kq(75m)C%!2wQP4t5!|z_EsrX&WUzdMO}+~ECP$&_7Y`FUMo)T_Zp?#S zRXY;7x_HnOPrWxvTR{Auk-m%q1+}R z>|!N3*t-D#VK-g!rr}P>Ko35#Qh-hH+|@uBx=o+Ze4!_U=D_jydm3NEHSqo#r;|4=KbHj&4OJ{pS?WyGinIuf6uh zDA~Coa+37DA{n$a)#+FKc(S$!nj3ZW0UW76>(Oxmd{tkxS%q>oz}BqZIoXkWY%ac9 zsVtv)=Xw$Dvf8av1G!E&`k*6kRpHz+Se8$eEB*+w=WZyi#dL1PK8G3002f?X{+4Jm zN61-rKUU$;xLayn+@3z?@?!+fz&4(z7l_E!p&dx6xaPr8V#Zc9460T#Mk&~SrguhT z<1hgmjb>Q$@_(4)r2@G#1TAyqSY;isx0^BE3SHiXyc&*QHLT}#3= z%|#0oO2w1eR|1Vksd`uC8_$%8K>DjmP#~;4ce~phv*xVXPe*>53>J^6u^3%NaUUC{ zPlq-YlI@WbA1MicSqj<4jb43EB-g9WalntDpKp^b*P+gtN!u-YjD14CYLc-mRX^C& zI>5*?#a*n8yW+N%>E~VFpMiVINNOQ;odRbINIt#NHl<>%19#+fMnSerBj*zFtY;!5 z@sn?`5MoV>8+aFadnSX6@XGo{GC18-bG5q~qsIRmMgsP8yW-~eDmg)BJCdi2#n&iv z3dFC*2+O&mJ1PCZ9EAWk9J(>LSo|yL#I7KHX8M?W7KbO2Hp?+^5T$@CC<|XyKh4d5#4X?eTQHtr zhA1`D6sBsCp-8wZ^poyNsvMl#=1{p&)rAXsWL3H4gRpZETruiUa=X1dmNLY(n_-yz; zg|qmBh8wURc*`m5u{83u0HomPaA4J!An;2IemqU}3{Hj4N0My_xkgUug~cLICXEqT zeY?|{X03OZsr6(tUg=sOHN^ z`6zN^t5s~D#3fi(9zsrX^1UqaI&+e?f4UDoOSKm=OZT-A@E>M`Tt%(hMA^|R9|*Cf zPysRNJt<$5D$;#t-BLi_j5M9sxnqQyDu^o#NI5C+j|cqyMlUB1K0~){Z}Gx{ZmFs4 zhz9Nr{ZnA-Vs?+O4}6sO7RN>mayh4cyt|wcQPWa(P8j!tniVsoN0yeecUgQ-k4X`( zmz?uCs)CyI^kcrfS+f*1kGG~c$SKi4GN?a=2F*%elSQbC6CvkWES>w;WxMy_ipQp) zPxq+S>Ph7DJ+##_&E%w@0)IAMnFu@~i<;_>?5;rbs5UlCc=O6?SOyHL)dFu&0|$uv zKc_97=0Zi{5X5dN-7*tl&+Q@4e7jqcjomh_=VgM?2#9Uk z*CQG+&I>I#A=s}#V%|OyRFJCqC`FBX3Bn3!WU|hm@M7&JPM7%BZXX(mhZBdu1%Jti zVNj`umBgv(vc=2pD*F1BP0+kIQL%8%-g4F!cC`oPHQ`%(ohnQ_ zwV`-He2-~OICu}noYq)@hfELJBN>d+c-Bs0pNW{Ey+?g>!ppk;`~3=Djk;7=LUl)z zYy%*0SlZsI#yoH+d%x0&<$pVaTw03$^jRE`1PM(6&0@}W${XEi_)KZyPM5&dlWVoRzwJ+iM-uY zRE$ePqbmKTyWd86>UTE=dZr{QTY)RKhj${cxQ z#t}NwWTq*w(}6`Bv3Fq@iwVE6*%rx<*+0a{t=Qzy+hsqKG-LI|Al4!Y*?8d4pLtPp zRqoZcAB%vi+Unx-uP1MVpuDPFIHNx`q<_0OT<+4iq;?0RlybWL4%Vhdn;6=eO?IsH zQ|T=w9k!M?I=-Nt#1d=-$Gn@NInNE>V@k3!-h?HG=0z$_*~X=cvx=c40bx33bR!K& zx!IyT6jFw?6`%M!M899sf2c<`OHm)dB?^lst&0-u5+-<+Pnh&=@)e98gIKuukU+~?Vt2Am#C43+6x*-^%leg!}hHN}})Gkg6@ zJHYMtiT?+GRAZ3#OA87(oYNLVi>yzsc`n=TutS2(2DDM!41zRE)=WT)UEokalYsKc zYyW23>FyXIL2hTyNCyt@*hCJ286@d5IoWw&NZAf0#}X)Bp6bY<4k_jQNhFQaPI|qW zS}y*&h(xB}-)I)a+~+#9wixNOHJK!2#JGGiPD?+WV_)?Y2u^F+F+%jur%TjPD&u9% zEb4VG;Om?NA*{4B!ubPAw(L0f7;2?j#5~tT9+(jzVDXX}E2@Bo_yP*IMp1h0I$0Cy z>fcjCdKEPGgK8Sg=GsK%y4wodIy-<>t`acYK>f2!ccVi#LMd>N6xAi zJ#Kys^}NpXH0dERQbQFhgHhW5hk6TB5|Bow+x{7jlNmmV(@uPHywU__NvI})U-~PD z^ILAp=33Lba9a0%m?xJWgiPMViMIi&ihEhMRu;=cpHF4OJxXDi+sAGME3FjS9mM2b zVIal$j+9EZ@W{m-{W7@^B9J{xry!rs=^bgC5I&jJTm#ySmw z$j_mAx0H zsqcWP!raZPb8|AQ@~#z8fNbCj+!Gz2q(DL&_l3qQMX!S^niQ5NrJ#fPweHUz=kWI1 zc}xI0gEyETJ0crj6vv*ox%!OJhyzClVfee{$|TqPbJ#ihbep|d`1`|ozJpgHMMDv8 z`PNx0>d=x;ti}p&$nYar?m&~BHC5Nd%2zHx<}bwj!TgD{XA@z=grDbB&QaYLq2Bp6 zfqKbTnZ7xcRPg9Q-+OG{64K;O+|7pV%hWE~ijU^5y{E#!Gr51xlOJ*$*RZVq0P zP~d0Terx&EWqR_?UR$FCiA;*2WRZ@maJ=1C88yW!W1?%6kwB8Q{6otBmIESK=o z0(R=EYiv1jRig*;7v%YZdYy=GEgE0zeF!1^nUZ^_Jzc>SXJj^_$YtbRzh_6;R0H(X&^mh}I*lrn z`6!JCCcI;v^k0zhRGOSZ1P#qY&}kO|)jJqSHmQ=5l!%NHWmCvlAlS3N+z{HSLf3?t z5caju&cj%RmMle2zKy-&cmQmF2UgQwstTQ#3i5^GZi;4u9TzkHg&(+g&hhm;jVrM< zEguvkcCuq~79jss+idK!0f0QJCj|5weYL;m3U; z^n>&*i9%37;Tz20gJ8YaTx~jl#diITwJKbAPZxRP)&N$O$Q1%O$LCKtrd>)Imc`UF z?nidC8nvDIVjCTnUnnp(O3zH|!D~5%kp7_7`)tdZWIRT^sxJbWl7M2Ej1S}`=$A9< z>lgV5D8wv;rD4UDz1jeij8-maT*%6YBtsrKuqc30s$(JmN=#B)I0 z{xIXCR1COH1}4v&Eal1}Ai^&?BHhP>Jp-Q}!x4`iT|5cM$Z8CBs_SM{K)b1pzg^7( z@pl-rs$jV(L`FcB_~=%D4>+A+T(EwTc^V9e+?0`EZ~%rf>2@Gb0`+rJ596@*CLzZN z>^8S_VvAY1FXFy%w&b$2H_!sH(V)1g|5-;o%VspMmM$g~;U_uVJ3UZvfo9%l7;&>O zw-vm(Ed0>O`kAq22|4atlaEQU4^+oF>wt%T2x1dH|wqq@3&G?T^kLbr7Y97 zbF0oVKPRCfgEI8gXR=e~cN@s_v#2wkrcUB|4Xip!W3|unOl*3=a0Hu!IX5%TRss=rK^_F=rQSkZVBzEa%l*w;iz_4t zVm&Sa7TIU&kw&A>d86{#A@ozlNw2+_Bnd>3E z`dD@FGUSCyTA70q@=c){RDolC>TdNuJV>rU+B-2X;P5MIa|uGLpAm70I<9k4l%_@2 zW}o=VCHY&O<&iD(zKhudK#_z8S7_I*kD9`F9IZr!75u~c!#(IL)n>ziN#`BAul)e)CEB=nM@}=Nj2ingbFBAx21{vf?M*q zX>w|vwK84VoCFo0&lSPXhLaWy#+5GPu|+#kkKBuu=l>{jS37!k6L4m^3jkMh5~lrk(sMs5Y$%s3p-Wpd_P<8E1_|Et$6raA zgT3RdFc2UIwZ52&{i}4HI68eLDH;&u0~$8Lce2M@dff5 zV`>?Gw2=s4A8QKAyzSV|AL|CSVr{`M)o=e2MEv_qcsUNd7!nTn*Hz9BILm1C(}%T1 zdXm@;dK1cJ)Y-M&!JwBDk1mu8+pJnH#9~b9ZNdz5Hg92GgVTJEr5D2O)s!u>V9wg` z4EkYDu{xt>vpH5q8^ZS87apSpcDPFtpaGzM()aF)GcfZe?OK_71+3p*!N&lwA6F0g zrJ#jI2DM0+!@22(V*?O@B@K^aBV@QER)UBm)A4qX==LejqP4=93NHQ=?=;x@T&C%x z0rb0b&>a0#n~Bv57l9_Py#r)1B)AA3>D`aUt#e&MkHv~hI1VdOKt$?hfB0W0k+|(6 zb~otb9u5H9NX1cz5#^B`=r^rhiZ+O3|1{*#S44pTiAUm#AfZev<0uFlBCW$! zCE(L{J_4W^%xjlGx8coh9^aB>n5YUd@JMfeb`svN&|R#eRk^vmQT6IpCZ{Hi@I^;7 z!uwfQQavc#3}P|1wgwXz-Ul7hL+zBC;)>iGLrx^sP$HMu+8E&kN7wb3r>#!+d~9m` zHh@SkUnZ!Zu5CK9femnecpVC(p|2Q*`yC}&nG3cWy%zaEISkt~eeCc;^DdYruQk_>}U?^KF>limnjT;c@${eI1lDw+X zuP=9xE|QhV9mBi&QXy}t$-&EfHTXxxH)CZKYkP6J)L}c&Vimrv_#(UdEYcu3&+zsB zGK*l=`;$IZzY?JRjnRD9;!JKx{{8_sFjxF08kN5ecE6BuJkX?niE=oWxhPGP`JRAD zJ<%|iy&f+)B$;eRb6f~CLRxe!KMk22&!^HY4CPtO;l4nlf>B;056n@#mjMf#{G@;}#R6ewa1kbaXkoF7)s z!ClqMP>&`a+vDxg+auVS=nxE1c)TQ1%hwGY=HuCNWTKk#*H{oJ`l@DLvexM+qPply zQ~A!@;5amA&%%^4XWsOuvWr;l))%#G`QqW9*M_tnFX{1q!RI0CPWTs=Upj91%kDLR znhU=%by@<3=>?D4kai;j=RQ59Zl3Fi@xze2^@iU-W=O+puF=a`Rl1Q4S*K+Pkqo02 zrF@!0&O%(5qi$1hHPg>>xqq(J+Li&M^j`mLsWw3ary32l zQ?aPx$!;|Y?l+iuFPR))RQ^j$GDn9b)4%|>Hy4wj7mn>QA+h$klm1UAf9uIsg+B*m|N-28p<(<#82iFF-JyR^#>BhFh=&|DtM))D<`K(E$+L$W%w zNlicF92r*+YH=>3;b#fEm~TL`Jsg`+PHv|`ZHn0jLtvZu-oD!_Ac8iUykFzW{eS(* zwzBH&$T1kz?rVMyL)10)(BS(yyfI(nv3CmZq?FjaX|LGvtF;ir9YqGmRg%J-N!wm(l{lvWdov^(PK5~RgKWJpt0Eh zYFlp&vkBK*ghn8z5@(@EP92vF+(n^DFliCRD`ULqO0F)Ov*IkoO%+vB zkhi0&T24lTlZ`<-8(-o{_}IaFxX9m0`UY+;&976{q5n22{84x~yGbgAq{&u7fmW`h_Yh{hS_AEUlmg8pUO& z%%i@b4PCp==`h8?r6IJk+|1s-5kW44XF?HEr&d4gQmUiYlnr=0dEWRZC7{I?G&PP` zjFy=LJNchKd^1Z43ENaqI%K?lrbyAL(Vvu{--8s#94d6@R7Sh7CA=;+jp2Y&I{`V< zIb=0eRT+gG;A8O4f3D|kf-agCjI!xMWAeyJb5>Wkrp8AsOv5Ve!5omHl1$RIg7oQG z(v5)H8sizt*l39)5(QxaHBD?Hiq-~dWdCd}dj`KdduigS66n=hUkUj`Yj6#^xj?ZH z{p?mpt!XQkw_%iSVwn(VU)trQ6}KfI9fEq;w0C2Nmdp5}5v7vacb|4}6`|!H4EA=r zP6EM$kgEDRN@Q(Iq$>6X_-|i)TYg3o@OaeUMDUC00Bj=$%Tuj7C z27kT`CkE6)x}-h2^!5V0n|`P6%J#5+^0;*DMqS0;eXV0S*T2^2zSiDAR)ry}v%#em z;SDXw=tmCLJ;6FEOZuRsS|xL{)Y*~6FkVTRFj=7nR>AFoZXVb=M|YlOzG%@~srWd5 zrs`o;*{iB~*{eV{esBL(QoqIc0zm&S=cIUwdn!SMwOvp%Z)DVk1OhSuWQG!|9|Sfg zA%TKU@!8w=4Cj0pVP2XjgQPg>^T_O1AP)52Z&gCR@P~-zy{OQRNty%e zj~aH6WN)RrB3l?|wjdvy5!O9-`hzQ-NiihhHE|WbgJaER+)6E_q&^>{V zj=>9|(7gK0I}9CvU6$j>0xh88)j?NWBfBwZFmxAzlEx-=u)Be*E42P0sL39YdeEth zu0n~)0)2*!O`2onQ>(%cbCm6F0HeELdGPef`As_f6IIt3Wy~Oxqofu@A&foke1FGx zR-J9UJ>R+^h74=+km2$nMd{=2Jc@c?GhY5qwY=FW1WDvJi^%VWHuHZer`U{@i+ zmXU&Z4gSOiu{1*mwcVZ-IIvvFOX_&&=!^xbTVu;yINpan(7N6*(4p{M7GQdlD7CeA zZU1_m{V5h`MGe-Me5%%hwmP_*gAA6vkpm&QtcrNRvVJZg4__W`;@Vh(i$P^hpqL(m zv_}_wO)8GA5=cuS>!h9cQV3Fi&ntwICW#w4i!Aj>ukE1e?kP#zdPg57JxM^l8ilKT zMi#9AMKJmHd*2m?UdR60wOS4@D?qBB?i3uKxGFWI+oVix6(96AhII3zEsb(EcaUz! zwI=gTG>2X{Pou-d8aU0F2Ov+<;G3Db zMC|q;_RX;+jV=Wi4@ULlu^;*h_nsQoXo9QrPPQ2@Zrd!Q13kKS8V&A@4b z-q8*h_|a97dlh;f>u=)fP$9@9K&XoCdLu=pb4J(Aeq)v&{r)T&WT$uChQrxlbmZNu z5KR7fwVZ*~tT#WlKp(1FV~PPzWc9%|Fmfxo;k}8ih*Io~lAO6xQ&p)5nj8_~`UvrH zlrHqPR2U%aWnn<+Dufc|7a!~SRhsAyQ(J}ssG%e3-dpXz{!UM44P+)UtnkUdm51@k z?7BB2Ngvwxjm+eoLT+r}TSy~t-UiR1iaP0nnW0Oqy)td^qmDM5Q5EtND}0P0gHV-s z@fuCe4Z|S6p2fQf#2m5v7}OGn0Za`-=73aN8v$Xrm1OP_vIIj|m=!ysP{7U1ka#oEy_M9WbhulIck6Q5F6nbHv(l}Aibcs=6Q2iF9MHQ7}}mF3oTBEdiGLs z5GOAPF0H0LTUvpoTok<#Z0CZAwUK;U|0lWvgCRbrs|!JP7Lq+q_+UQ_S13@~Eo*)o zz$(5qF{uf#@6&W=YJ{zuf(~M}3NgSccF)l#Ae8Hn-%s>}p$>Z+#TbM=w;5+8Td8`tPL(Y$g1u=>sm}%%6Dq; zC&Z@s*-_9!P$|nYrkou||H{ke}=F{p&yF-_KVgpAvep^2pUI`^ASxBXQLO z8dPfBmR1oXB#hZKy}9}pBy~=oi-}kd?h;a(l&v5WR{M$#)>>POzV0l}!R3MoQ_hXY z5zMrG!mAiKQna0c%%P_c)7)u*`Au1$(^O)I>*S)z^z<~RV7faQ9dr<&*f8S(+2Jc& zO*Vm>z16Hp&-A}S$ zgI4fZ_e98^Sd3J{O?PO}t8f}n`9QNFljk9w?9!)KsHH4cA` z*p0Q=u8FBO}#T1n%4(rj#tz< z3VYCYoP^utf8x9GrJ4%5l5NfL#%~tonZT>LI<+vCAz$7H#`SuP)07zHBGxFN372b0 z{A20<)uvgni*VLJt`x8b2DMcqP$Kw7~P)zXPx7Fqc*m)*AJ!a?{wM~S8F z(%b0g*Dyu^*>P3K2CkapN;MrFGzyRXJq)e#`GUfv%kgp9@3nPK-04f2@o8XOqW*)-NV-w+r*ADZKXIeBGn-- z4s-P7IqQk>+tK=Tsi>n-w8B8#n3ZhpWzsioSf|KrrOS_vh~nKe@Ba@(7-(ug1x8Xa zW>=hLuP_M9&ZGRrX+6rO{lBXKlPO!Fkc`r8fD99NxbNT>>xn!5P$QZ@t$x2l7c3uC zWT}qAcA0p&l~F{{p#0u}+-{cfl(8f>K}*X<4P_p1*lXNq6jZ zoDlVST;AZVJ>InQw?{b0#uFrc3!!buN&-dv!S1hUV##(g?0?nJPXlVRN zr$9`OH(LlMC+$gYC-j>&<=DG6vK@;_pOzr!xXfT8gQ5p*Fe~5AQAx>w@wQ0iqRzWezyr)jr^8_Y@ke#3Q6(Jh*Uu*gANE%%hkyXK&59dfBz)U~G?ItC z6!r&Km!PhJE$NoIG>xZgKJ@nNWpzAquA`y8PlCzaylR@&4Pgr2Jx`O6G`NM9ngv;? z8uIjL1V@K+0Km3$_276A6WkAKg#{}zP~I%`9*0$Spz4tj7o%#`YMWaYpy)3}nZ zh!dGN)pHZDSG+3(zb&?-kx&!8^*ha702Leno76Ar*)hrUx$N6dC_0(i@MUt9m)Uw= ztr00$Bx<}cPB`beRe>EWZc*TR1RYfU4it7-{{M%GJsvtZg! z6co&xgKUlNW-)!4IK)sjQ`_jS&`k;h$y`{ct@l6Dx{3d9gFwd?9Wmt(TIOP3<`t!0g8w|f1!95f^nu)1qGB9e`!%#T-AE6d=%Atd?Wa?=9h4%-XdbQ* z#A4d=QDK$|QY0K9o~~9|jT}~Q`BU)95gh_IsnqL}f$YcsFx5IP4$Ic(-Qga3p7V(X zadMWDmzE>EDX6j;l&)j(XiQ^Ol1_w(z=5JO$3Xuq=VjKJVIrcAOyGZfL!GmB-exPL zRRz%du5C)-j4C%R&&UGexCI+L^y8Yd>Gf?uVnwPJp-QOJ+I0RBNMC{H{?tfu4XtGx zGc&Gl8@~Q~Qn+2EZ1%=t!U}y-v{lL;=Y5O;0$A!MNI<)L1fW54lZ{8?zcJlA>La7V zCUr`1OOG*QOL&1@gFe*7kPUn%j3Et&Xt&xBea5!L&|eiLqL!IkuHAC*R_5w%pI31u zxH#8iCiRUQb`@@Z&0iuh((xYTo<^fgkJZ(x*eX@fn@{nl7R4|tDIP9Kp(at+pQq`U z!=}vcKnL1fTvvanfF?Mi3q=6fwqs#~ADyrj|5BC}!to!fh@Vh1#plKV+^zT+Q9bn_ z1g_JDIXXRBOB>1lWQs~Zb57WC4`+#a_~hcja;??NEk(6v1hWX@XtrHtYYF*Y%Fd!C zs+-Q+9?^@oUmF=%8}t}j6~efJRJ6zDA|JvuTnO>1Ud^|eL+@58NV@|E?8YaznB_rZ zsM!547O$ZE3#Zffl>a}U6kqeZC zGwWl~H~3Z4`PI88+kg)2en6|{oo-57Xf5Y2MKfPMdPb9Ei&j46S(;X=ur<7{r;k-& z15`1r^67P*ax3Z`kwS9D`Hrx?Yav&MH~me~0k3t?56cDvs>rT83cE=1WVRrAt9G(< zR*8@yD)%M0Fn&w9pdeRK0J&%SexG%B#znPQXR!vJAxX#OnU=8 zSS=l^l@06z^Vs1gDlFT9Tf4s+u+k-&XA2AAS&H#q1u81DE3YNP)4SZaduXHlm9Rbl z!n8FWjcPSZXWt2NUUE`<<uDR?=0IV^olX8_swKD$;(?QugOVF>s3Jt>{~ z8{M!v$;m_EpHe8Uc&1`xYd5f-rJw>S8HCm3Gs`+Bmk&1j{DiA;Nm!>b2#Ws{)YMCQ z9LPI9IA}KxPt(gWAY!G7W6MU*oc0^B&Vn#QnFi55)?zrI#=;$(CW)U)RI^NMnfD3N z#Ab84V$9918ILMlx@dO_I{69Q52i3{+hRyvI4{pU3se4J`EI}-ObBO>>7VLjubCI^ zi%^4Q{7KwsDcc+j>95N7C*^FjY1V$)2zpyynt3gDK#8Lknm0(|eex)LD?>e2$gnAN zhTF|y%l|Yz&L`vjd4>lOH04Georm2!br3D)ht=wyNdArvxp1P=!Duu~W~ zc(KWK>rfB_MmW&K%tPk7S(&niXT>gF!h_eHSrRKW2^uIc@-D>u6?-v1*wE_Zh054b zK?pdtQ4K5mqMGg8uRJ-B39>a&9XWtdeY1ak@4X&eU3o}pbM*%e@FZleGxpX3UF$~T z^Y6Eni_h|F`W@dnTRvtgx*};VkdkNzMG>ZkY06o-zhgXpe-^kDGx)Hqoz(!@pLkN) zw;*Dt1m1Eyn8=yhA(Ugk%eN(8>655F0y(wdBB4z8$?e)eG)?Mx)sl`_sSJ5VHp^_; zSNf5XsKdAp=UF3vIzBkjt+JMe45scOb3KkDeNjMgA||V@F;LIF$$!#InrCHBjZOA* zO5X+Zu4XfTyW5Da%&Z?%_Lpq$C4G8DJ@--E{pZZf$q_ulv90E9&VG}7z+wsHDjX$h zs8v@CuZz91pRvZ`-P^a9+ovE1IrlD60FA)Q%E1cZcI+BONnqbJFX-D*5iPJi716`= zEadH*9$f6dwxo<>dbO$KnkxJVoij$M;l_bNq41cq02`bk?vqVv-JBjUip5(G2ZoKrCk%@xu{PH ze$mcZMDJ~(A3QKv>>@L%rp1gCJ7OT57U$cTL%x@LjPk%u(L5|)kxP+?28S_`bP%0T zJ+Y=UDTwHlHLU3OJ4MetJG!X7i#OcEB_UH)WP-#yFF5tVTk6rFhuIdpA*2`~_Qkbc zRCP5pzw6#69e&#GGzhUH=!C6rXEZ!OxF8d`7MIg6Ay4|C0m1+u64+0H&Y)?MR6Vufr3CJHXw*$4=IXYvfOP+8#=u5lyz`gf%Rw`3|?KO&_EsR zav2kl=*Chdd&|DNu|jlQd>K$AiuvWwit0c#BmFey^IvUsBy-yXRLvvfw)YH^ma95S zUQMWPcR%C+Ke5!oyp2V$LRUD;-~T)o8N94NZ>iQ$D;V~WK`GdTYav{wPgBujItYh# z?5=nh1U-_G$s%Ysy+1651;x;7ce|ISti$C0Ox!SPz=1P=y%MK$P2GlaTIlT23-{~3 zY#f4Z(@-=L1m9?A_#{sqzIUPr;Rr+^2yrYn^()7AVjDI@E{Q28|O zOptFRIZ>h3s)L|^^E8pU(uirZBjsq=#FJK@9eo+k)P(^x-M0O3eFyqj3@ca}dMKiF zwUz~FX?4S4mi8_GUZM@{IrJndozOj8nwI21Empe!I@ex>Uqt@(m3wc!2k%OI+_m)v zL<8$zbl-YE_n`gnuis5Q?q7S8-$#A*-``B~AP=nl(EaGny<^_i{qJ9Td)~YExqbBx zzTo!6iWKXrCSS`<@CYYJZ(O@V5x7VB=xqz?mG~vFE_Xt-Z$jthOK7W+i;*yv`4yHu z69CT@IwQOClD8*Z2(^tNi~Z_~TqZj6;t_rNIx;7gyaMeG4@c-~8B99f^1=PKh{t#3 z22_B7W!o-`Rps<)FZX42Ol8d zRrLny4k~+?OD1p}>Hv9a6=rC4^|z{g+REk2oe+=YBFeCbK_xfgi&OD8-pj?V|Z;g-ZFqfCDd3cQbDM5j2 zl&?zdmWpu`8J)M)(x%~G)wGlnBJ5-Z zbQFX_lnP7k06!X>ej7VlcWqA7;q0XF)u7sEOK0a6>EluhDt&&Nax%NAB?qHRsNd{XJN0jGhR~5WJiGE z-Dx{RL8RjpobJ2fN4Vu1dcs{!k&RHEK%3^zJla_|fY735!3`1gZ)ubhLwXoOq7Kb9 znk{^;Jw%KM_BT-^WzPEc8*JXFF2Uaaff_G+K(u_%*>ona(M>V;a1-RS9pK_Io?BAe z{$aTYdp6UqvR{Q3g6P0fyVK%A#Sm!<<9(33x#|4yD06i+RD9|rqj&0Nh-Hp~1T;y= zG-)bsBC46yJ2l##eJ+GY0fQt{4Ri452^JzV-CA&cpU5Up3;5=g;S1DARiS^;C*pXh%i zH!P0*y_^#0#O2ugxsSsw-|UiOBUPu)Dl zoHPwoe(IL^j9@Z(EP=Tr(aw!aFNu5N69CTwrbZ}uAX=%u7uz%0Y;fkY#84RhJ;m;V^p9Q+jmUPWKLrCXHr3UTJp>Zb zi)Y{A9yq|jAR~yG*r1B-AaWghWb=VjQKf5C6F+96AJkC9w3|azc7f(GFU8_9^jD5yP&YBu9qAGCZ;>&Jrd1LI-b~U$Su&`Jvx<6 z*dOHH^MH8Zzsb)ae9N36iwcoH z>6@%jW8UF(R9~Nw|09$%#B(@nU}g1vEV-7o3tu@dI7}iNN(LH}{zyo#iy^w2F&n+r zy~N)l*QR#VMEK{K%kEMI?2Es(ozTHp$SUgHE*!R#F%PuhLOfN!~HRiuhuK!aX3i&>-Z~2T8|f)K12DYt88rh;}gCPWqt1X zQpO(P9con~mIdQobUgMKHyP?_P$JVuj{`boOO1`-2)!{DSo(GMbsql&aMnm&^0=;J zUwh17ow3LQHA&!cr#QMJzq8xgiyx%c`DmGt?2R9~z`C zPw?UJigs`0HhYB#p0FPIJt53eRJH?~SvlDfq*JM~@xyR+_2wDfdjEjqmjFZ!mw&4V z8q|=vE7m|B2H$Je7>##kZC^b!Y&JftZHyv@dIpr(hHimC0KKBjI~z0{XRw|T{rcf8 z1~PqlGKRAhQ-%t%UJZVa3hMjZZ>&<0#9W}Q41SzAZc9puYOYEm9sM3^SC))Ao#WOu zentLy?-dfF@}x?ouqhBkC*#%7-0UZ}URu)M+7Ml-s*wx3kQv#)&(!}GpK1?fYE0(D z+Jo8YLj%Uywif2_I@QISn>ycIFOgDyS=bWwD^b6L(0hnAQqy3qPLw%w;oNlN4~?IX zO#KIa+K4kZhUZ>lGzd|MSCW|5mpCw4dS4ez0)}G5!!dz^=A_cU3_lht{J*da{x`ht zP@+GTXEQw=b(aqm64}F$LWm*tdO+_kA+Y2-`nA{pI`$avdJl!{(C)DdzVC?>GVkx8 z9?FbTQ4OW{brALwj};1qyORch0zw|8ge6w*&UH%TkjMRFK}P!8-s&*?dk0+dLVWCP z2!FR6xlP0YQJvYZPe^I|_E@UX(LJDdO{*+Roy1N^#&SBml}~!8AYXBKw*EP?|17}} zSvYGrjUuE7GhkEsRqTpuYxGnAkC6z`mdCs-W>D@-Hkm)TLpE~u(Yg9#mp5}scQfj1 zCR6hxWTvu%Uu`36?j}By?-$x$u0eLp_9oJe;I}-no?nMSBSRSnDhAg=$e$QNuV)mv z)>lz<=_8)=!r3PFBFJ4HK9ZnP5p$SL4PLHZ#}~~6rhT3u0JS9z*Cr{4Pmz)xzGzWG z?tkIk7242z64>+|Yx-H=$AhFBC^7$JEpIHP#V_F$*SB=zwtY#IvJ)aS@!es&ir|)h z^8FM*&l(A!Dba^ksdnTZmC0a*7=L2`iY(@^5-&O^_ z=%aJ%5h`^j;G`_YE}X;RvTe+YyYUOpjfnEOs4t7xHBq-^I2sHqg5W0-OhlIB$EKKA z&+!t987Wb!0_*EB-&wEwJB%q4sCf%1uC^4)s`wu4gDl zuWbz!o;aIh({DcJ|9Jzs0pDp6wxpd*N9lK@u9hq%uQALGdGycI(9gnYm1jsGT?9G0 zp(vu|p1EQ`p*&>xSk^Ol@791-meB5QL1*B?%Zr$DYrczxtMk!Ij-f%RpeQ>!x$0|R z@QOa2U-Lx$QEgmI(Q z`l{?2`_>y0UPUWHu!QY-vTp+j8O*T7aSAC%jFly)zbs^ z1tRHT?~XKzmKKB(Ldy&Ih7i;kQk&WgYFlBGoCN99eOl!^N9gaQ$KLALU>H`)gy=u| zFp+w-R)&>m`(;EMHgs-q$|HEN#e(h9bMP^GWO0ziK8t#TGTXL7>-zawZ0r)}I2*%M zZ%7=?2jG=p*h`HczhpfSM3>{u%;Y~uJ2ykVK^1L1dM`1MYcIcn9o!ur1v5l-Pv?d= z3`pLJB5oe#8QeRlWP~+G!M9xFn15njZF&DCY zf%D0OX`+FM5RB4Y*H;=vNPW^h+H`dD6ETKpUW9H)f(hEK29q`bXoSWle#A}>JNMKG zHOkECz$kp$i{1O|oAaUfQOk8`00%S9`_3#uY{r?`*uz6LPM|+zf;wNZo_k^c3*sjv zx}FK7G~8PrO!Ej1l&A)-i0!%uy9^^!-d^IgwpMyp15Hb^!J_>{#MRU$i_;h3r zX}{c{d<2ZVH*Ix%D{n zvc>n0xCg}@hi719HBjTy3D?FA2Lcx&*L{*Ef-=DAE>JS7c&n5>MR^6&&3K>W^Sz$` zP==22;fKL0oYSH^HC)fP7QW`?ym<1Qy7&Mz^uvC^L}_7$f5fAYo!TvxA}?MpAC%?u zb6-YsSx=*L#Nd>n7U$7?Y`h<*i4{y{U&WxRuI~9;zq)bE_&TU0Y8vPLH3U}&qye<3 zvYY&FNSGUZQT}G{`18+X2fO)n{v%qm>RiEKuJE$}st71t9{0uH5kYMQRxc*UE}!QT zgFfR}b&g3^fI}REG#~5m!!1~C9~&BBt<1yRA3A2=U@IJUl52iLUfr%C`lo^r2OSb02KVhcg$>1(sa zAOUar*8GWW$vO+!e>WSU0FBXBPW-K}a?16u_fVZTpaq5ThDPc3rK)XkR5D3*-U`iA zZL?9Q5C^Z#1?vGs6ULC1lPG9<_;6Dmt*eCe^F%qJV7 zEomG~O&^5kx(1+3d6BH&FRj_PlJL><65|w@lb`QzQSe4;X#O1wNG;5Ok~(-?R)UH* z_Lerxqh+n0Pl*7E7EmBhg1H>?6$G$VnYsOTGJz3zjm%~O;XVg^UX9O9DEpJL=ffGx z>LC1&5WD5sGhr~CH&FMBETC$A?z4Ipb17F!V+|=c;JBGwfW!10F(uWPCTrEwg zlf8%L`J~z>25B1>>k?LVPtK-$Tx_=?QXvcQi{G~p(FgL2=7SfnQ}CS9W_YZOrEz{^ zkfD&LEW-6sQE^FKzN28ibV>dqzEgWQ*f2<8^B72{Qnz}F)%nKc%acVnP0`<=+0QQX-;|5tBBASdgY9#~wG zJnXr0VlMJKK&K8cAEXg*ZW+T%qgoGGM8>@>e^5vm%B7iuBh&PCZYAf4m@N5)H#z)x zEcL;zFC#XQvl-O|onJr2XJ5THPEgAfWIoK+=Df)V zmQrk{5y|$ohm`Us5EK^nUavF4)Ra2GmEescs4a_mT`h`uuFe##R`I^e}kss}2r zMscc_jmqOK{1RZA)mr-}t-Qvq^JY9c`Ka^1D=%>~&K~6xj-5;w*4k94Cd3xRHH$j& z(77!a&RjR3E-vy2lFV$f36*fYraS+BB)z&>CXbC*@_@3oXcOD&FFE$=e-C1$;MrD7 zV!(Eb_M?S9VNKyR>Wp$+PtNX8QJimpulg6EC0}HVNAMEf$otSbUH@NAM7t~g=SX_)rH<~wU3$hKAEeG!wP1hN^|N);3b+=zZVq69eU4v2E@0C&ntXrHMbUwrTAF_NM+)n z5uhMV!aQr@*XA&|!?~-QpSA7so5O7Qxy#zC>2|%}K&5gzhs`W~ z9aIKmma|sm2*S4TyY$S59l@Qa4Uxf1d0YZkqO-kf_*1^npGQJ9jM)BsOsVuNoymvB zLNp>(h>wEk(+P42Y5Z#%^TGuGLI&!yO;4Dc=AL}r`^X3nb**)*>7b~2y1szZ&{*Cp zu<~3UCK4x?0Q-0z%(TI%5U6c7#xIa2#z(p^!NR;g2Bz(clkSnX49{Mz5;QcLC0H)8 z!@TgWw`exP0l>3bP8BIngS133^%L-)$kos3O~)BobmenqpEyA>f4!=6W5B%}96TJN zI$iF0<<~*KaSbj3@eX1wcCZ)okzFqJ8eXSFHR;T>Lf~U3nZwd7$XFhgRf=qWxX(6= zScGmi1VPZ*Y9U2L^g8h`Zgd@+A9qfCa|#NsIr7c=#y^#`KXkcCY|Z8WRh*@n$jdBE zis7jMFa#(>JvJl*CEwT$9JJS(5==@txTAEb5&_o1ijx`e5M4X)PJf=%1ISNXI67qJ zwOZfH#EkJoV1JtFI%a$i(qi`3nPwy-7a^=H?Xtb64iCxaDEZM0Tmy?GFf|MFy+}>a z@jLag%?Y=p&)*(gc~;k(kM~cUA2H|LvMlbBTC#GsVh2tEtH*a@Z(y!B)Z-Ksj?eCB zaZ173zzfw`Y@HOxKrp#@*S#==Fcd`K#K09j-b)W@j7=&G&CrSvwVuNxDh$d|j~Rg- z={<2Dx>+kk^4V^ESG89jbMi0W{HbgGAP*LKo^Y$S5v1n8!=g zpNzHYGsh)M%cN8m2qw0dBZ%yxtJi80p?lUkQ3#q*RXnUy_x!7nMl(wyj> zIGZk+HYxgIhs=dE-^t+h;ny6jE!VX)pG{>Gs}%!)bC=?bZydREkWg5*G^cS=b!jsO zn&C`!h6hkJ+G4b#GS1%+xrWW;ccYm8+tcklpCuNJ9TB^C4QR)E@sll5d- z0s`rX2IDCK#1j`;Nc!uS(J#9^T>4+qb2DmnAtg_I$VUleTj2|Tz4~)PPMm^RvjQ_q z=u6`fyvM>7gxxAWXpMAcE5aBE+WsItvB{%iokoX4l;#J zP4K0Tym<8iCH_}|aiasMBchEZE(UEjAkUSv#hxbA2TQ`Vp|;{s_n~fDGQWIg?(?ca z9Sehxtqv@C6t>H**l+D>!OsxQ_{bR@rRSM&W1{vd>SNuJ#b!9?uJlPjE}^x_RGr?o z^m{$UA`--0ncc8}_<-BxTtF5ZW{WnpNk`UT_wc5=Z5cd4*yN47b93*q8XfUdN%Av* z#17_#6Do!J(@Z(reZw}y22Y`MMcwtvu%JQkvF`eM0gI!d(8^#8T`^XQ;`<{sf#|~8 z8w$M0!j;!v=S=xRkKa}$>@K=GP*k>DJc>L`#EvdN^_0=hS8W;}2X=(GY`ftVrNFh+ ziCX8$k5y~)O0u58`e^b6E^r>@)MB4Ih0DFtPA6Y%RF;a&AyXWxbNu8;rMe; z@&#w%y_BMxmI4p*5L50aVU&B@L5vJd3RNj^pA-*Kc+x0)!Z~W1r`I4K9`zvg+sE1LQoj^`XeN@Zp z+r@APi=F4llL>lnB1nncTa}N)8PkuYpj^V+xE9%;vY|2!w8;(YQ-7XAUh5UG`@er@_fw zlm^Hf%gM&OD$hRN@xVffFWbo6OHDv)=gmuvtHLeo5-1fC*aH+{zjz|;L~;A?FBH)! zDM%8ze>vb~ZBpz2L4!Qa{Eb$~ro`#`$aHhf$!cz7@#Eg`t`j0PRg`cssvU>)6vuq?`1^wn4=Fb=HRpn;S}@96;jPtobl&E`c}I;enBc@-%RKf z={0|&p*BGu+8`b5bag9v6U&UH-7y|8htgz*WmSB*gu2bYp*F8cNd%H_hU4^ow@**r z(u8_Go;Tx;XnoRgNkGbJDJ%L^l%?L~$i<9bA|J=pydf3=&yFN3!$c3LczEp7b{k0I z@7!DytX;;ns11Z5PqjJUN+E&7l$!CW?XEeUS=$jmb}tP`7RAzLY^|0f{l~i?V4Wiw z0dAc`EWwatDo`n%P$p>GyEf?1VP?3$A7>5)nQRPt{wP(9(s)-(cDqHims3dw9-_H* zXq9Qq&OUYzj60=98i)`r)m=Z)@u%$oooC6SOZz3WnCag1hPpm1%n$)#^q~xF^tBSI z;K3a{)0MmDTn2L*(6h1;w*3?mWnUh2*1%JcBH_R)EByU}?J^1z&5H=ha(P#j$SrGc z1i6yA^EO?9+2opJ6wJBO?VhSA%n*`J^PAZPeWS;BNWAsjvW@Mql!ind>^(JAW1d7f8`Wx5xYZy`1;5-}G z8FuG{H4~BY1^ChT++KPS44~YqIPf1;z+e_{DvbaRLNr%yGR?a!VG7g3_xD0{<*$JG zqM?L|Xnf4+Psfs=5!UcEJ@u?}`u;#>s#F?S{Xd(PQ-bAh zZ-th^%~BTW>3K@cU?H=IE+ua$wN!v-;K|QI>D~K?lGCKAnrosXERcmH1uI{M4LS$9 ziV(%&I2d>XzmW90I|;MgFJ`t6;9stI_i*kuKDz0s*W1?Ax7>#r?i*svdW3loOeGwD z@Vx<7e{0QMzqj4C&1$;eUtVooPhzMPNhURndeWog(;FfD=WH32 zuLb3#Ae;n$O>I7OIgFJnj2ME-?%`1izK8fXgdhgdKGq68EAzP#RTv4}bk_eBIbvJj zx=~C5!GG8%4~-Fy!f3*f(%83)e;A0{G7M6R8(N|mL+Z6weVMAyE3zQL0xWvGX|yu7 zb4sn`6zku5PL?Jvc+?)YF?TM=F^fYJGiK%fvZ3&=aQzM)dB4X7GUAtuw;Q-W_6kO9 zZq_5+8l*wc1(1)6a~`Om+}FLpH1;E_u_F~xTfXFP6Cmu&b#UEnY+Bstl1_v{T~J1Tr~Fg_jRKxizN z&_KZQF71+6`4Q+Hk#bI&*)rhXbg1jhyZ>bP2KZ#G98g@0`;tLjz}4(3DdOsOG(4A) z5%c8Rf7C42Mf2nMF^0uSshmPggrI>9}`mRPKZE(ZcMdgQJ}B?{yt2YblRar{1$WY2Z^ zRZj`^#Vt6hfG$1bc(H?Fst;%d%*IuUJ?y#&V)FnqIBQ7f_Bh%-?1BL3b!qkKKzl3I zq>)-Ss?GOHSwn&N<|%-~a?gSlUDDN~C3XsQa|vo9>UoOQ*uqF&pe_VJ{r)WY?#)>u z(;y(?;vxE*a)cX4+LAAP@MQBHP#{mFv)+DZmd|XmU<6eiVFl^wJi&YlItGqN%K%HJ z$pSnXM`e!%D~>^>08S2T6wmFy3s4=8%Bfe0ualM}iQ_WCwE=S>M}P40od-o%SrB*i zX3~3KNPMIINwai_=itkg^e@u{yMR88bIV)RSAx%ItU1AC2g3uTwCrS=rc1bbGFAYVY?wO|x{+58 z?iA~x4j^c2U_D>bZK9wevq~ApT{{)ErqBK^H>e9wCGtoh7{6H zK~fwyzDZTU+U>>4+*_Z536#cj_g*?{EbjvOv2C~p3oSp^S{#4p3%N%U+Yla^I`f6^ zUXthh-}c>)-=rpI>8Wx`bk{W7TtFL}+j2H}4es&m}#jckMup zq=SEc^B?%1k;yaZ==*mbfsf+}DG`%1E^E$uZHBBeD~Rzb;+ZdKTgGzv&^i|+70@EFX*EfY#4{n}sd*2=FRdhpb?*&^9v0m^@=C`(k z_i?Pd$h={Fe~r`qI>*~TMLA2RDvrO-mR!yuR*9U)BN<6(L*xvfCPat%C5==C zvYB-O+Y4&6K>TcgkkC*_o5=Q_t!360krn8=qq*V|yj>BMipBNdR!5w9k6Dmb}GHX7*PwaQ}jeJy72gHTTxwF zLKyR{+Tdp+mxDd|rmXb8#GMXx16c?Ht@Ct18)cd@qbEy*O1ag3Sb)$z^0}Ork-bc$ zC3EgJ)boD`phQK31ll7;89bGp4dk6I^~7Dc?Zq$s*IJ$g%Ph|SemnS#Ig*9hm~WrA z!)iN5?+ZaISogyz>Cqq+6hORlwwj_K6_a&mwJDH3vKs4XV}X@Nyn&(#6qJ^+ z9Zr-{V|A_w*n6`AZrB<)``#HC{jvCnyp{i2nuveJ#IC;b1Fu_S2@7!V))MbB8FBP- zBov}rBfHZ&C0bY5RFbLN6@a*!j=}ryh`1wjBR7HKP>f@Tpl;1DYKc$OP5G+7LCq?Skc$`1B(8M-h|ZnZRfmk+_yCA={A4@PNSgAYg>}mQr-6)IRH>xIuetOCu|9|Ej%AD$f*|I`LQ8#)|9?M)D2BxWg7mtL30KKp_|WsmLPZ8PmjbXSg#utYpFAq| z>RV@PrHrVrf(IgfuvOW>!ICEaOOnf?t7SS6bcS{hsJQ^pgk_?_0h|+bgEz$b`J*h7Oq$7P(e=uC zzj!e~XoR8>+GiQ$1IKKt_r4VmP7t>%6a{+gKt(Va%krI;-`img*ew-Zr87zUv03KS zQ*f+dSF?6Z{{(r$6bhe2)jGB<+;dQaKp*6JaB-6>01|>oAdp7Dz{UxjAk8a$fS`EdJkIWS0G<5s`1JlqnJYvLz=oE z2QEN)E7KO$*zLNGZ}HQSDfAir>s||cD#ZRu4cgGfGGe9!Hb*NIc2~@n*n}*NgS&m{ zfVZVmJ7C~;Sc)HkAovazd}&rG1DYiUii{HRU^>jG2fwh5OSiM~R_Lxn0tUbTfB%1d zdagqP2EYG*|9^dY#cXqqO+A=L{FdZ{5@VOlSEj_W_IOgrUNU!9AUBCz6R14Pw;=h@ zm(_CeN^!${M;J@Uw+N|uxA6$-9$R0d`ghFL_aaVFi`6hwWf_TbB1dOr7X#%=5pQ7#ymLqsvq3qFrx>N z-(H{@$ce;L4tOY4?LX2;avV?)C_iX6=~scGhs) zWdxcFx~T>ms^|Mlu+9DZ%ALs%{|_T&Vt_YpGReiL82g4;Hw77~MUbMB@(tUJRF+i` z9;Mq;Zo~~e`{dE|y#>xAvsQRS$9zLX0$-+65x_CBC8I24B?36JsJ;SjMuc%wjC)Au zDAC8YjO|nV7bI859&o!hAQ;E#*}K|O_nx*|mFf-O2()GaY_%QiQftWJ*4li70!`Ik zH6##S$mBm>Qy*Re=DzMHB~xC!r3$#HX~-^@ofX;|nu(F14zJ1f`RB3kYwGGnNmFcu z149*9+x#4jj@2#}ltOV1g)3R^%BW=>W)gz~YRdRiw<{+E&?5%M^~ye5hcYRE>?9ri zwzRETb!xW-jh^(q=%V;h$hIKMj)sH+JZ*UCpgri337|$HCs8g}F=lQA(+eZC{=`4? ztV?J=Ewe|Y`(B~YiH%}ETjc~=l?Nk&-%m(6Cmdz{HZeKQN*M$FnBwDFrU+d}#!uM* z Date: Sat, 7 Dec 2013 02:56:12 +0530 Subject: [PATCH 002/115] bit of refactoring and tidying things up --- .../mode/experimental/ASTGenerator.java | 33 +++++++++++-------- .../mode/experimental/CompletionPanel.java | 6 ++-- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 00ea002..b026fb5 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -109,7 +109,7 @@ public class ASTGenerator { /** * AST Window */ - protected JFrame frame2; + protected JFrame frmASTView; protected JFrame frameAutoComp; @@ -153,14 +153,15 @@ public ASTGenerator(ErrorCheckerService ecs) { } protected void setupGUI(){ - frame2 = new JFrame(); + frmASTView = new JFrame(); jtree = new JTree(); - frame2.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); - frame2.setBounds(new Rectangle(680, 100, 460, 620)); + frmASTView.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + frmASTView.setBounds(new Rectangle(680, 100, 460, 620)); + frmASTView.setTitle("AST View - " + editor.getSketch().getName()); JScrollPane sp = new JScrollPane(); sp.setViewportView(jtree); - frame2.add(sp); + frmASTView.add(sp); btnRename = new JButton("Rename"); btnListOccurrence = new JButton("Show Usage"); @@ -231,6 +232,8 @@ protected void setupGUI(){ } + + public static final boolean SHOWAST = true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { @@ -267,14 +270,16 @@ protected Object doInBackground() throws Exception { protected void done() { if (codeTree != null) { -// if (jtree.hasFocus() || frame2.hasFocus()) -// return; -// jtree.setModel(new DefaultTreeModel(codeTree)); -// ((DefaultTreeModel) jtree.getModel()).reload(); -// jtree.validate(); -// if (!frame2.isVisible()) { -// frame2.setVisible(true); -// } + if(SHOWAST){ + if (jtree.hasFocus() || frmASTView.hasFocus()) + return; + jtree.setModel(new DefaultTreeModel(codeTree)); + ((DefaultTreeModel) jtree.getModel()).reload(); + jtree.validate(); + if (!frmASTView.isVisible()) { + frmASTView.setVisible(true); + } + } // if (!frameAutoComp.isVisible()) { // // frameAutoComp.setVisible(true); @@ -3156,7 +3161,7 @@ public void actionPerformed(ActionEvent e) { } public void disposeAllWindows(){ - disposeWindow(frame2); + disposeWindow(frmASTView); disposeWindow(frameAutoComp); disposeWindow(frmImportSuggest); disposeWindow(frmOccurenceList); diff --git a/src/processing/mode/experimental/CompletionPanel.java b/src/processing/mode/experimental/CompletionPanel.java index a7fd9bb..7973b76 100644 --- a/src/processing/mode/experimental/CompletionPanel.java +++ b/src/processing/mode/experimental/CompletionPanel.java @@ -60,7 +60,7 @@ public CompletionPanel(final JEditTextArea textarea, int position, String subWor textarea.requestFocusInWindow(); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y); - log("Suggestion constructed" + System.nanoTime()); + //log("Suggestion constructed" + System.nanoTime()); } public boolean isVisible() { @@ -130,7 +130,7 @@ public void run() { completionList.setSelectedIndex(0); scrollPane.setViewportView(completionList); popupMenu.setPopupSize(popupMenu.getSize().width, setHeight(items.getSize())); - log("Suggestion updated" + System.nanoTime()); + //log("Suggestion updated" + System.nanoTime()); textarea.requestFocusInWindow(); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y); @@ -176,7 +176,7 @@ public boolean insertSelection() { public void hide() { popupMenu.setVisible(false); - log("Suggestion hidden" + System.nanoTime()); + //log("Suggestion hidden" + System.nanoTime()); //textarea.errorCheckerService.getASTGenerator().jdocWindowVisible(false); } From bfcd4598cc8d4e7f9c379868c70bd24664adc5d1 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 7 Dec 2013 03:22:16 +0530 Subject: [PATCH 003/115] Isolated the problem --- src/processing/mode/experimental/ASTGenerator.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index b026fb5..25a260f 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -566,6 +566,9 @@ public ClassMember resolveExpression3rdParty(ASTNode nearestNode, case ASTNode.FIELD_ACCESS: FieldAccess fa = (FieldAccess) astNode; if (fa.getExpression() == null) { + + // TODO: Check for existence of 'new' keyword. Could be a ClassInstanceCreation + // Local code or belongs to super class log("FA,Not implemented."); return null; @@ -607,6 +610,7 @@ public ClassMember resolveExpression3rdParty(ASTNode nearestNode, return new ClassMember(extracTypeInfo(temp)); } if (mi.getExpression() == null) { +// if() //Local code or belongs to super class log("MI,Not implemented."); return null; @@ -864,7 +868,11 @@ public void preparePredictions(final String word, final int line, final int line ASTNode testnode = parser.createAST(null); //logE("PREDICTION PARSER PROBLEMS: " + parser); // Find closest ASTNode of the document to this word - logE("Typed: " + word2 + "|"); + logE("Typed: " + word2 + "|" + " temp Node type: " + testnode.getClass().getSimpleName()); + if(testnode instanceof MethodInvocation){ + MethodInvocation mi = (MethodInvocation)testnode; + System.out.println(mi.getName() + "," + mi.getExpression() + "," + mi.typeArguments().size()); + } nearestNode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() .get(0)); if (nearestNode == null) From 336d885cce64bdc6cf8c150ebf8389d44a1502fc Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Thu, 2 Jan 2014 11:33:48 +0530 Subject: [PATCH 004/115] Outline window width fixed. Fixes #31 --- src/processing/mode/experimental/ASTGenerator.java | 2 +- src/processing/mode/experimental/SketchOutline.java | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 25a260f..03343de 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -233,7 +233,7 @@ protected void setupGUI(){ } - public static final boolean SHOWAST = true; + public static final boolean SHOWAST = !true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { diff --git a/src/processing/mode/experimental/SketchOutline.java b/src/processing/mode/experimental/SketchOutline.java index 6577adf..13cb729 100644 --- a/src/processing/mode/experimental/SketchOutline.java +++ b/src/processing/mode/experimental/SketchOutline.java @@ -67,7 +67,8 @@ public SketchOutline(DefaultMutableTreeNode codeTree, ErrorCheckerService ecs) { //TODO: ^Absolute dimensions are bad bro - int minWidth = 200; + int minWidth = (int) (editor.getMinimumSize().width * 0.7f), + maxWidth = (int) (editor.getMinimumSize().width * 0.9f); frmOutlineView.setLayout(new BoxLayout(frmOutlineView.getContentPane(), BoxLayout.Y_AXIS)); JPanel panelTop = new JPanel(), panelBottom = new JPanel(); @@ -95,19 +96,20 @@ public SketchOutline(DefaultMutableTreeNode codeTree, ErrorCheckerService ecs) { jsp.setViewportView(soTree); jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); - jsp.setMinimumSize(new Dimension(minWidth, 100)); + jsp.setMinimumSize(new Dimension(minWidth, editor.ta.getHeight() - 10)); + jsp.setMaximumSize(new Dimension(maxWidth, editor.ta.getHeight() - 10)); panelBottom.add(jsp); frmOutlineView.add(panelTop); frmOutlineView.add(panelBottom); frmOutlineView.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frmOutlineView.pack(); frmOutlineView.setBounds(tp.x + errorCheckerService.getEditor().ta .getWidth() - minWidth, tp.y, minWidth, - Math.min(editor.ta.getHeight(), 150)); + Math.min(editor.ta.getHeight(), frmOutlineView.getHeight())); frmOutlineView.setMinimumSize(new Dimension(minWidth, Math - .min(errorCheckerService.getEditor().ta.getHeight(), 150))); - frmOutlineView.pack(); + .min(errorCheckerService.getEditor().ta.getHeight(), frmOutlineView.getHeight()))); frmOutlineView.setLocation(tp.x + errorCheckerService.getEditor().ta .getWidth() - frmOutlineView.getWidth(), From 5a6fcf40e09dfd82700ab5c8ff567debfd1e5644 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 11 Jan 2014 20:28:31 +0530 Subject: [PATCH 005/115] Beginning auto save impl --- .../mode/experimental/AutoSaveUtil.java | 50 +++++++++++++++++++ .../mode/experimental/DebugEditor.java | 4 ++ 2 files changed, 54 insertions(+) create mode 100644 src/processing/mode/experimental/AutoSaveUtil.java diff --git a/src/processing/mode/experimental/AutoSaveUtil.java b/src/processing/mode/experimental/AutoSaveUtil.java new file mode 100644 index 0000000..6e36c35 --- /dev/null +++ b/src/processing/mode/experimental/AutoSaveUtil.java @@ -0,0 +1,50 @@ +package processing.mode.experimental; + +import java.util.Timer; +import java.util.TimerTask; + +public class AutoSaveUtil { + + private DebugEditor editor; + + private Timer timer; + + private int saveTime; + + /** + * + * @param dedit + * @param timeOut - in minutes + */ + public AutoSaveUtil(DebugEditor dedit, int timeOut){ + editor = dedit; + if (timeOut < 5) { + saveTime = -1; + throw new IllegalArgumentException(""); + } + else{ + saveTime = timeOut * 60 * 1000; + } + } + + public void init(){ + if(saveTime < 1000) return; + saveTime = 1000; + timer = new Timer(); + timer.schedule(new SaveTask(), saveTime, saveTime); + } + + private class SaveTask extends TimerTask{ + + @Override + public void run() { + ExperimentalMode.log("Saved " + editor.getSketch().getMainFilePath()); + } + + } + + public static void main(String[] args) { + + } + +} diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 953a4bf..dcbfa4d 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -177,6 +177,8 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ protected JCheckBoxMenuItem completionsEnabled; + protected AutoSaveUtil autosaver; + public DebugEditor(Base base, String path, EditorState state, Mode mode) { super(base, path, state, mode); @@ -244,6 +246,8 @@ public void actionPerformed(ActionEvent e) { addXQModeUI(); debugToolbarEnabled = new AtomicBoolean(false); log("Sketch Path: " + path); + autosaver = new AutoSaveUtil(this, 5); + autosaver.init(); } private void addXQModeUI(){ From 13868a3528782837a9e70fcde184c35424defc80 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 11 Jan 2014 21:01:37 +0530 Subject: [PATCH 006/115] added save funtion --- .../mode/experimental/AutoSaveUtil.java | 146 +++++++++++++++++- 1 file changed, 144 insertions(+), 2 deletions(-) diff --git a/src/processing/mode/experimental/AutoSaveUtil.java b/src/processing/mode/experimental/AutoSaveUtil.java index 6e36c35..d5a7285 100644 --- a/src/processing/mode/experimental/AutoSaveUtil.java +++ b/src/processing/mode/experimental/AutoSaveUtil.java @@ -1,8 +1,14 @@ package processing.mode.experimental; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; import java.util.Timer; import java.util.TimerTask; +import processing.app.Base; +import processing.app.Sketch; + public class AutoSaveUtil { private DebugEditor editor; @@ -29,16 +35,152 @@ public AutoSaveUtil(DebugEditor dedit, int timeOut){ public void init(){ if(saveTime < 1000) return; - saveTime = 1000; + saveTime = 3000; timer = new Timer(); timer.schedule(new SaveTask(), saveTime, saveTime); } + private boolean saveSketch() throws IOException{ + + Sketch sc = editor.getSketch(); + File autosaveDir = new File(sc.getFolder().getAbsolutePath() + File.separator + ".autosave"); + if(!autosaveDir.exists()){ + autosaveDir = new File(sc.getFolder().getAbsolutePath(), ".autosave"); + autosaveDir.mkdir(); + } + String newParentDir = autosaveDir + File.separator + sc.getName() + System.currentTimeMillis(); + String newName = sc.getName(); + + + // check on the sanity of the name + String sanitaryName = Sketch.checkName(newName); + File newFolder = new File(newParentDir, sanitaryName); + if (!sanitaryName.equals(newName) && newFolder.exists()) { + Base.showMessage("Cannot Save", + "A sketch with the cleaned name\n" + + "“" + sanitaryName + "” already exists."); + return false; + } + newName = sanitaryName; + +// String newPath = newFolder.getAbsolutePath(); +// String oldPath = folder.getAbsolutePath(); + +// if (newPath.equals(oldPath)) { +// return false; // Can't save a sketch over itself +// } + + // make sure there doesn't exist a tab with that name already + // but ignore this situation for the first tab, since it's probably being + // resaved (with the same name) to another location/folder. + for (int i = 1; i < sc.getCodeCount(); i++) { + if (newName.equalsIgnoreCase(sc.getCode()[i].getPrettyName())) { + Base.showMessage("Nope", + "You can't save the sketch as \"" + newName + "\"\n" + + "because the sketch already has a tab with that name."); + return false; + } + } + + + + // if the new folder already exists, then first remove its contents before + // copying everything over (user will have already been warned). + if (newFolder.exists()) { + Base.removeDir(newFolder); + } + // in fact, you can't do this on Windows because the file dialog + // will instead put you inside the folder, but it happens on OS X a lot. + + // now make a fresh copy of the folder + newFolder.mkdirs(); + + // grab the contents of the current tab before saving + // first get the contents of the editor text area + if (sc.getCurrentCode().isModified()) { + sc.getCurrentCode().setProgram(editor.getText()); + } + + File[] copyItems = sc.getFolder().listFiles(new FileFilter() { + public boolean accept(File file) { + String name = file.getName(); + // just in case the OS likes to return these as if they're legit + if (name.equals(".") || name.equals("..")) { + return false; + } + // list of files/folders to be ignored during "save as" + for (String ignorable : editor.getMode().getIgnorable()) { + if (name.equals(ignorable)) { + return false; + } + } + // ignore the extensions for code, since that'll be copied below + for (String ext : editor.getMode().getExtensions()) { + if (name.endsWith(ext)) { + return false; + } + } + // don't do screen captures, since there might be thousands. kind of + // a hack, but seems harmless. hm, where have i heard that before... + if (name.startsWith("screen-")) { + return false; + } + return true; + } + }); + // now copy over the items that make sense + for (File copyable : copyItems) { + if (copyable.isDirectory()) { + Base.copyDir(copyable, new File(newFolder, copyable.getName())); + } else { + Base.copyFile(copyable, new File(newFolder, copyable.getName())); + } + } + + // save the other tabs to their new location + for (int i = 1; i < sc.getCodeCount(); i++) { + File newFile = new File(newFolder, sc.getCode()[i].getFileName()); + sc.getCode()[i].saveAs(newFile); + } + + // While the old path to the main .pde is still set, remove the entry from + // the Recent menu so that it's not sticking around after the rename. + // If untitled, it won't be in the menu, so there's no point. +// if (!isUntitled()) { +// editor.removeRecent(); +// } + + // save the main tab with its new name + File newFile = new File(newFolder, newName + ".pde"); + sc.getCode()[0].saveAs(newFile); + +// updateInternal(newName, newFolder); +// +// // Make sure that it's not an untitled sketch +// setUntitled(false); +// +// // Add this sketch back using the new name +// editor.addRecent(); + + // let Editor know that the save was successful + return true; + } + private class SaveTask extends TimerTask{ @Override public void run() { - ExperimentalMode.log("Saved " + editor.getSketch().getMainFilePath()); + try { + saveSketch(); + ExperimentalMode.log("Saved " + editor.getSketch().getMainFilePath()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + //editor + + } } From 49d5383af2af9915d27212bc76cf4e926549f26f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 11 Jan 2014 21:02:38 +0530 Subject: [PATCH 007/115] updated ignorable files --- src/processing/mode/experimental/ExperimentalMode.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/processing/mode/experimental/ExperimentalMode.java b/src/processing/mode/experimental/ExperimentalMode.java index 9417f94..2ac6ad3 100755 --- a/src/processing/mode/experimental/ExperimentalMode.java +++ b/src/processing/mode/experimental/ExperimentalMode.java @@ -253,4 +253,14 @@ public static final void log2(Object message){ if(ExperimentalMode.DEBUG) System.out.print(message); } + + public String[] getIgnorable() { + return new String[] { + "applet", + "application.macosx", + "application.windows", + "application.linux", + ".autosave" + }; + } } From 6c7fdbfebc2ae3de25adec0c0173ded13b8c613c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 11 Jan 2014 21:14:25 +0530 Subject: [PATCH 008/115] only single backup remains --- .../mode/experimental/AutoSaveUtil.java | 21 ++++++++++++++++++- .../mode/experimental/DebugEditor.java | 3 ++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/processing/mode/experimental/AutoSaveUtil.java b/src/processing/mode/experimental/AutoSaveUtil.java index d5a7285..6eacf79 100644 --- a/src/processing/mode/experimental/AutoSaveUtil.java +++ b/src/processing/mode/experimental/AutoSaveUtil.java @@ -40,15 +40,30 @@ public void init(){ timer.schedule(new SaveTask(), saveTime, saveTime); } + public void shutDown(){ + timer.cancel(); + } + private boolean saveSketch() throws IOException{ Sketch sc = editor.getSketch(); File autosaveDir = new File(sc.getFolder().getAbsolutePath() + File.separator + ".autosave"); + boolean deleteOldSave = false; + String oldSave = null; if(!autosaveDir.exists()){ autosaveDir = new File(sc.getFolder().getAbsolutePath(), ".autosave"); autosaveDir.mkdir(); } - String newParentDir = autosaveDir + File.separator + sc.getName() + System.currentTimeMillis(); + else + { + // delete the previous backup after saving current one. + String prevSaves[] = Base.listFiles(autosaveDir, false); + if(prevSaves.length > 0){ + deleteOldSave = true; + oldSave = prevSaves[0]; + } + } + String newParentDir = autosaveDir + File.separator + System.currentTimeMillis(); String newName = sc.getName(); @@ -163,6 +178,10 @@ public boolean accept(File file) { // editor.addRecent(); // let Editor know that the save was successful + + if(deleteOldSave) + Base.removeDir(new File(oldSave)); + return true; } diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index dcbfa4d..c949225 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -331,9 +331,10 @@ public void windowGainedFocus(WindowEvent e) { */ @Override public void dispose() { + autosaver.shutDown(); //System.out.println("window dispose"); // quit running debug session - dbg.stopDebug(); + dbg.stopDebug(); // remove var.inspector vi.dispose(); errorCheckerService.stopThread(); From a0edae8148142ec9b34a0bfcdd4054c74897417b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 11 Jan 2014 21:34:28 +0530 Subject: [PATCH 009/115] further work on auto save --- .../mode/experimental/AutoSaveUtil.java | 21 +++++++++++++------ .../mode/experimental/DebugEditor.java | 2 +- .../mode/experimental/ExperimentalMode.java | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/processing/mode/experimental/AutoSaveUtil.java b/src/processing/mode/experimental/AutoSaveUtil.java index 6eacf79..5ed6f77 100644 --- a/src/processing/mode/experimental/AutoSaveUtil.java +++ b/src/processing/mode/experimental/AutoSaveUtil.java @@ -17,6 +17,9 @@ public class AutoSaveUtil { private int saveTime; + private File autosaveDir; + + private boolean isSaving; /** * * @param dedit @@ -31,27 +34,31 @@ public AutoSaveUtil(DebugEditor dedit, int timeOut){ else{ saveTime = timeOut * 60 * 1000; } + autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); } public void init(){ if(saveTime < 1000) return; - saveTime = 3000; + saveTime = 10 * 1000; timer = new Timer(); timer.schedule(new SaveTask(), saveTime, saveTime); + isSaving = false; } - public void shutDown(){ + public void stop(){ + while(isSaving); // save operation mustn't be interrupted timer.cancel(); + Base.removeDir(autosaveDir); } private boolean saveSketch() throws IOException{ - + isSaving = true; Sketch sc = editor.getSketch(); - File autosaveDir = new File(sc.getFolder().getAbsolutePath() + File.separator + ".autosave"); + boolean deleteOldSave = false; String oldSave = null; if(!autosaveDir.exists()){ - autosaveDir = new File(sc.getFolder().getAbsolutePath(), ".autosave"); + autosaveDir = new File(sc.getFolder().getAbsolutePath(), "_autosave"); autosaveDir.mkdir(); } else @@ -74,6 +81,7 @@ private boolean saveSketch() throws IOException{ Base.showMessage("Cannot Save", "A sketch with the cleaned name\n" + "“" + sanitaryName + "” already exists."); + isSaving = false; return false; } newName = sanitaryName; @@ -93,6 +101,7 @@ private boolean saveSketch() throws IOException{ Base.showMessage("Nope", "You can't save the sketch as \"" + newName + "\"\n" + "because the sketch already has a tab with that name."); + isSaving = false; return false; } } @@ -181,7 +190,7 @@ public boolean accept(File file) { if(deleteOldSave) Base.removeDir(new File(oldSave)); - + isSaving = false; return true; } diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index c949225..2fdfab0 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -331,7 +331,6 @@ public void windowGainedFocus(WindowEvent e) { */ @Override public void dispose() { - autosaver.shutDown(); //System.out.println("window dispose"); // quit running debug session dbg.stopDebug(); @@ -345,6 +344,7 @@ public void dispose() { // Added temporarily to dump error log. TODO: Remove this later public void internalCloseRunner(){ if(ExperimentalMode.errorLogsEnabled) writeErrorsToFile(); + autosaver.stop(); super.internalCloseRunner(); } diff --git a/src/processing/mode/experimental/ExperimentalMode.java b/src/processing/mode/experimental/ExperimentalMode.java index 2ac6ad3..faccbd0 100755 --- a/src/processing/mode/experimental/ExperimentalMode.java +++ b/src/processing/mode/experimental/ExperimentalMode.java @@ -260,7 +260,7 @@ public String[] getIgnorable() { "application.macosx", "application.windows", "application.linux", - ".autosave" + "_autosave" }; } } From 751fa62bc382b486146a409a63cfc616ec5a5922 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 12 Jan 2014 19:23:03 +0530 Subject: [PATCH 010/115] load prev save if found --- .../mode/experimental/AutoSaveUtil.java | 17 +++++++++++++- .../mode/experimental/DebugEditor.java | 22 +++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/processing/mode/experimental/AutoSaveUtil.java b/src/processing/mode/experimental/AutoSaveUtil.java index 5ed6f77..35e7835 100644 --- a/src/processing/mode/experimental/AutoSaveUtil.java +++ b/src/processing/mode/experimental/AutoSaveUtil.java @@ -17,7 +17,7 @@ public class AutoSaveUtil { private int saveTime; - private File autosaveDir; + private File autosaveDir, pastSave; private boolean isSaving; /** @@ -37,6 +37,21 @@ public AutoSaveUtil(DebugEditor dedit, int timeOut){ autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); } + public boolean checkForPastSave(){ + if(autosaveDir.exists()){ + String prevSaves[] = Base.listFiles(autosaveDir, false); + if(prevSaves.length > 0){ + pastSave = new File(prevSaves[0]); + return true; + } + } + return false; + } + + public File getPastSave(){ + return pastSave; + } + public void init(){ if(saveTime < 1000) return; saveTime = 10 * 1000; diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 2fdfab0..2cd201b 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -246,8 +246,7 @@ public void actionPerformed(ActionEvent e) { addXQModeUI(); debugToolbarEnabled = new AtomicBoolean(false); log("Sketch Path: " + path); - autosaver = new AutoSaveUtil(this, 5); - autosaver.init(); + loadAutoSaver(); } private void addXQModeUI(){ @@ -870,6 +869,25 @@ public boolean handleSaveAs() { } return saved; } + + public void loadAutoSaver(){ + autosaver = new AutoSaveUtil(this, 5); + if(!autosaver.checkForPastSave()) { + autosaver.init(); + return; + } + + File pastSave = autosaver.getPastSave(); + int response = Base.showYesNoQuestion(this, "Unsaved backup found!", "An automatic backup of this " + + "sketch has been found. This may mean Processing quit unexpectedly last time.", + "Select YES to view it or NO to delete the backup."); + if(response == JOptionPane.YES_OPTION){ + handleOpenInternal(pastSave.getAbsolutePath()); + } + else{ + autosaver.init(); + } + } /** * Set text contents of a specific tab. Updates underlying document and text From 636b548523958d7dc77bde62ecc7e582153715ee Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 12 Jan 2014 19:52:33 +0530 Subject: [PATCH 011/115] load prev save better --- src/processing/mode/experimental/AutoSaveUtil.java | 7 ++++--- src/processing/mode/experimental/DebugEditor.java | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/processing/mode/experimental/AutoSaveUtil.java b/src/processing/mode/experimental/AutoSaveUtil.java index 35e7835..7120144 100644 --- a/src/processing/mode/experimental/AutoSaveUtil.java +++ b/src/processing/mode/experimental/AutoSaveUtil.java @@ -41,7 +41,8 @@ public boolean checkForPastSave(){ if(autosaveDir.exists()){ String prevSaves[] = Base.listFiles(autosaveDir, false); if(prevSaves.length > 0){ - pastSave = new File(prevSaves[0]); + File t = new File(Base.listFiles(new File(prevSaves[0]), false)[0]); + pastSave = new File(t.getAbsolutePath() + File.separator + t.getName() + ".pde"); return true; } } @@ -62,8 +63,8 @@ public void init(){ public void stop(){ while(isSaving); // save operation mustn't be interrupted - timer.cancel(); - Base.removeDir(autosaveDir); + if(timer != null) timer.cancel(); + //Base.removeDir(autosaveDir); } private boolean saveSketch() throws IOException{ diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 2cd201b..c4a16a5 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -883,10 +883,10 @@ public void loadAutoSaver(){ "Select YES to view it or NO to delete the backup."); if(response == JOptionPane.YES_OPTION){ handleOpenInternal(pastSave.getAbsolutePath()); + //log(getSketch().getMainFilePath()); + autosaver = new AutoSaveUtil(this, 5); } - else{ - autosaver.init(); - } + autosaver.init(); } /** From dcdffb9d1879d1e71bf36a79c05d31aeae599fab Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 12 Jan 2014 20:04:03 +0530 Subject: [PATCH 012/115] loading prev save and restore too? Decisions --- src/processing/mode/experimental/AutoSaveUtil.java | 6 +++--- src/processing/mode/experimental/DebugEditor.java | 13 +++++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/processing/mode/experimental/AutoSaveUtil.java b/src/processing/mode/experimental/AutoSaveUtil.java index 7120144..954097c 100644 --- a/src/processing/mode/experimental/AutoSaveUtil.java +++ b/src/processing/mode/experimental/AutoSaveUtil.java @@ -55,7 +55,7 @@ public File getPastSave(){ public void init(){ if(saveTime < 1000) return; - saveTime = 10 * 1000; + saveTime = 10 * 1000; //TODO: remove timer = new Timer(); timer.schedule(new SaveTask(), saveTime, saveTime); isSaving = false; @@ -64,7 +64,7 @@ public void init(){ public void stop(){ while(isSaving); // save operation mustn't be interrupted if(timer != null) timer.cancel(); - //Base.removeDir(autosaveDir); + Base.removeDir(autosaveDir); } private boolean saveSketch() throws IOException{ @@ -216,7 +216,7 @@ private class SaveTask extends TimerTask{ public void run() { try { saveSketch(); - ExperimentalMode.log("Saved " + editor.getSketch().getMainFilePath()); + ExperimentalMode.log("Backup Saved " + editor.getSketch().getMainFilePath()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index c4a16a5..8bdfb92 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -245,8 +245,7 @@ public void actionPerformed(ActionEvent e) { ta.setECSandThemeforTextArea(errorCheckerService, dmode); addXQModeUI(); debugToolbarEnabled = new AtomicBoolean(false); - log("Sketch Path: " + path); - loadAutoSaver(); + log("Sketch Path: " + path); } private void addXQModeUI(){ @@ -735,6 +734,10 @@ protected boolean handleOpenInternal(String path) { clearBreakpointedLines(); // force clear breakpoint highlights variableInspector().reset(); // clear contents of variable inspector } + if(autosaver != null) + autosaver.stop(); + loadAutoSaver(); + //System.out.println("LOADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"); return didOpen; } @@ -884,9 +887,11 @@ public void loadAutoSaver(){ if(response == JOptionPane.YES_OPTION){ handleOpenInternal(pastSave.getAbsolutePath()); //log(getSketch().getMainFilePath()); - autosaver = new AutoSaveUtil(this, 5); + return; + } + else{ + autosaver.init(); } - autosaver.init(); } /** From 021319a448a8eafb21a23cf863b6c98af3aba2bc Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 13 Jan 2014 20:12:08 +0530 Subject: [PATCH 013/115] auto saver work done, i guess. --- .../mode/experimental/AutoSaveUtil.java | 10 +++++++--- src/processing/mode/experimental/DebugEditor.java | 15 ++++++++++----- .../mode/experimental/ExperimentalMode.java | 7 ++++++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/processing/mode/experimental/AutoSaveUtil.java b/src/processing/mode/experimental/AutoSaveUtil.java index 954097c..f2e2ae4 100644 --- a/src/processing/mode/experimental/AutoSaveUtil.java +++ b/src/processing/mode/experimental/AutoSaveUtil.java @@ -33,6 +33,7 @@ public AutoSaveUtil(DebugEditor dedit, int timeOut){ } else{ saveTime = timeOut * 60 * 1000; + ExperimentalMode.log("AutoSaver Interval(mins): " + timeOut); } autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); } @@ -42,7 +43,8 @@ public boolean checkForPastSave(){ String prevSaves[] = Base.listFiles(autosaveDir, false); if(prevSaves.length > 0){ File t = new File(Base.listFiles(new File(prevSaves[0]), false)[0]); - pastSave = new File(t.getAbsolutePath() + File.separator + t.getName() + ".pde"); + pastSave = new File(t.getAbsolutePath() + File.separator + t.getName() + ".pde"); + if(pastSave.exists()) return true; } } @@ -55,10 +57,11 @@ public File getPastSave(){ public void init(){ if(saveTime < 1000) return; - saveTime = 10 * 1000; //TODO: remove + //saveTime = 10 * 1000; //TODO: remove timer = new Timer(); timer.schedule(new SaveTask(), saveTime, saveTime); isSaving = false; + ExperimentalMode.log("AutoSaver started"); } public void stop(){ @@ -204,8 +207,9 @@ public boolean accept(File file) { // let Editor know that the save was successful - if(deleteOldSave) + if(deleteOldSave){ Base.removeDir(new File(oldSave)); + } isSaving = false; return true; } diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 8bdfb92..a0336a4 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -342,7 +342,7 @@ public void dispose() { // Added temporarily to dump error log. TODO: Remove this later public void internalCloseRunner(){ if(ExperimentalMode.errorLogsEnabled) writeErrorsToFile(); - autosaver.stop(); + if(autosaver != null) autosaver.stop(); super.internalCloseRunner(); } @@ -874,18 +874,23 @@ public boolean handleSaveAs() { } public void loadAutoSaver(){ - autosaver = new AutoSaveUtil(this, 5); + autosaver = new AutoSaveUtil(this, dmode.autoSaveInterval); if(!autosaver.checkForPastSave()) { autosaver.init(); return; } File pastSave = autosaver.getPastSave(); - int response = Base.showYesNoQuestion(this, "Unsaved backup found!", "An automatic backup of this " + - "sketch has been found. This may mean Processing quit unexpectedly last time.", - "Select YES to view it or NO to delete the backup."); + int response = Base + .showYesNoQuestion(this, + "Unsaved backup found!", + "An automatic backup of " + + pastSave.getParentFile().getName() + + "sketch has been found. This may mean Processing quit unexpectedly last time.", + "Select YES to view it or NO to delete the backup."); if(response == JOptionPane.YES_OPTION){ handleOpenInternal(pastSave.getAbsolutePath()); + Base.showMessage("Save it", "Remember to save the backup to a specific location if you want to."); //log(getSketch().getMainFilePath()); return; } diff --git a/src/processing/mode/experimental/ExperimentalMode.java b/src/processing/mode/experimental/ExperimentalMode.java index faccbd0..4645984 100755 --- a/src/processing/mode/experimental/ExperimentalMode.java +++ b/src/processing/mode/experimental/ExperimentalMode.java @@ -119,11 +119,12 @@ public File[] getKeywordFiles() { volatile public static boolean errorCheckEnabled = true, warningsEnabled = true, codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false; + public int autoSaveInterval = 5; //in minutes public final String prefErrorCheck = "pdex.errorCheckEnabled", prefWarnings = "pdex.warningsEnabled", prefCodeCompletionEnabled = "pdex.ccEnabled", - prefDebugOP = "pdex.dbgOutput", prefErrorLogs = "pdex.writeErrorLogs"; + prefDebugOP = "pdex.dbgOutput", prefErrorLogs = "pdex.writeErrorLogs", prefAutoSaveInterval = "pdex.autoSaveInterval"; public void loadPreferences(){ log("Load PDEX prefs"); @@ -133,6 +134,7 @@ public void loadPreferences(){ codeCompletionsEnabled = Preferences.getBoolean(prefCodeCompletionEnabled); DEBUG = Preferences.getBoolean(prefDebugOP); errorLogsEnabled = Preferences.getBoolean(prefErrorLogs); + autoSaveInterval = Preferences.getInteger(prefAutoSaveInterval); } public void savePreferences(){ @@ -142,6 +144,7 @@ public void savePreferences(){ Preferences.setBoolean(prefCodeCompletionEnabled, codeCompletionsEnabled); Preferences.setBoolean(prefDebugOP, DEBUG); Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); + Preferences.setInteger(prefAutoSaveInterval,autoSaveInterval); } public void ensurePrefsExist(){ @@ -155,6 +158,8 @@ public void ensurePrefsExist(){ Preferences.setBoolean(prefDebugOP,DEBUG); if(Preferences.get(prefErrorLogs) == null) Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); + if(Preferences.get(prefAutoSaveInterval) == null) + Preferences.setInteger(prefAutoSaveInterval,autoSaveInterval); } From 5fdd88bed07260ecaa9088f8a2006584667c5f13 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 13 Jan 2014 20:18:22 +0530 Subject: [PATCH 014/115] oops, missed that case --- src/processing/mode/experimental/AutoSaveUtil.java | 5 +++++ src/processing/mode/experimental/DebugEditor.java | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/src/processing/mode/experimental/AutoSaveUtil.java b/src/processing/mode/experimental/AutoSaveUtil.java index f2e2ae4..8811ed1 100644 --- a/src/processing/mode/experimental/AutoSaveUtil.java +++ b/src/processing/mode/experimental/AutoSaveUtil.java @@ -51,6 +51,11 @@ public boolean checkForPastSave(){ return false; } + public void reloadAutosaveDir(){ + while(isSaving); + autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); + } + public File getPastSave(){ return pastSave; } diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index a0336a4..5bcafd1 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -842,6 +842,8 @@ public void run() { }); } } + // if file location has changed, update autosaver + autosaver.reloadAutosaveDir(); return saved; } @@ -870,10 +872,15 @@ public boolean handleSaveAs() { // set new name of variable inspector vi.setTitle(getSketch().getName()); } + // if file location has changed, update autosaver + autosaver.reloadAutosaveDir(); return saved; } public void loadAutoSaver(){ + if(autosaver != null){ + autosaver.stop(); + } autosaver = new AutoSaveUtil(this, dmode.autoSaveInterval); if(!autosaver.checkForPastSave()) { autosaver.init(); From 6f52073887488d86c16651fd72e0b5c669a879e3 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 13 Jan 2014 20:43:48 +0530 Subject: [PATCH 015/115] fixes, tidying things up for auto save --- src/processing/mode/experimental/AutoSaveUtil.java | 7 ++++--- src/processing/mode/experimental/DebugEditor.java | 6 +++--- src/processing/mode/experimental/ExperimentalMode.java | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/processing/mode/experimental/AutoSaveUtil.java b/src/processing/mode/experimental/AutoSaveUtil.java index 8811ed1..54e883c 100644 --- a/src/processing/mode/experimental/AutoSaveUtil.java +++ b/src/processing/mode/experimental/AutoSaveUtil.java @@ -61,7 +61,7 @@ public File getPastSave(){ } public void init(){ - if(saveTime < 1000) return; + if(saveTime < 10000) saveTime = 10 * 1000; //saveTime = 10 * 1000; //TODO: remove timer = new Timer(); timer.schedule(new SaveTask(), saveTime, saveTime); @@ -76,6 +76,7 @@ public void stop(){ } private boolean saveSketch() throws IOException{ + if(!editor.getSketch().isModified()) return false; isSaving = true; Sketch sc = editor.getSketch(); @@ -224,8 +225,8 @@ private class SaveTask extends TimerTask{ @Override public void run() { try { - saveSketch(); - ExperimentalMode.log("Backup Saved " + editor.getSketch().getMainFilePath()); + if(saveSketch()) + ExperimentalMode.log("Backup Saved " + editor.getSketch().getMainFilePath()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 5bcafd1..9e9c306 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -245,7 +245,7 @@ public void actionPerformed(ActionEvent e) { ta.setECSandThemeforTextArea(errorCheckerService, dmode); addXQModeUI(); debugToolbarEnabled = new AtomicBoolean(false); - log("Sketch Path: " + path); + log("Sketch Path: " + path); } private void addXQModeUI(){ @@ -737,7 +737,6 @@ protected boolean handleOpenInternal(String path) { if(autosaver != null) autosaver.stop(); loadAutoSaver(); - //System.out.println("LOADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"); return didOpen; } @@ -878,10 +877,11 @@ public boolean handleSaveAs() { } public void loadAutoSaver(){ + log("Load Auto Saver()"); if(autosaver != null){ autosaver.stop(); } - autosaver = new AutoSaveUtil(this, dmode.autoSaveInterval); + autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); if(!autosaver.checkForPastSave()) { autosaver.init(); return; diff --git a/src/processing/mode/experimental/ExperimentalMode.java b/src/processing/mode/experimental/ExperimentalMode.java index 4645984..87b190d 100755 --- a/src/processing/mode/experimental/ExperimentalMode.java +++ b/src/processing/mode/experimental/ExperimentalMode.java @@ -119,9 +119,9 @@ public File[] getKeywordFiles() { volatile public static boolean errorCheckEnabled = true, warningsEnabled = true, codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false; - public int autoSaveInterval = 5; //in minutes + public static int autoSaveInterval = 5; //in minutes - public final String prefErrorCheck = "pdex.errorCheckEnabled", + public static final String prefErrorCheck = "pdex.errorCheckEnabled", prefWarnings = "pdex.warningsEnabled", prefCodeCompletionEnabled = "pdex.ccEnabled", prefDebugOP = "pdex.dbgOutput", prefErrorLogs = "pdex.writeErrorLogs", prefAutoSaveInterval = "pdex.autoSaveInterval"; From 0808e22f47fa4c8257eebd4a299f90c6bd3185e7 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 21 Jan 2014 16:25:18 +0530 Subject: [PATCH 016/115] last few minor touches --- src/processing/mode/experimental/DebugEditor.java | 7 ++++--- src/processing/mode/experimental/ExperimentalMode.java | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 9e9c306..5c7cf94 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -891,13 +891,14 @@ public void loadAutoSaver(){ int response = Base .showYesNoQuestion(this, "Unsaved backup found!", - "An automatic backup of " + "An automatic backup of \"" + pastSave.getParentFile().getName() - + "sketch has been found. This may mean Processing quit unexpectedly last time.", + + "\" sketch has been found. This may mean Processing " + + "was closed unexpectedly last time.", "Select YES to view it or NO to delete the backup."); if(response == JOptionPane.YES_OPTION){ handleOpenInternal(pastSave.getAbsolutePath()); - Base.showMessage("Save it", "Remember to save the backup to a specific location if you want to."); + Base.showMessage("Save it..", "Remember to save the backup sketch to a specific location if you want to."); //log(getSketch().getMainFilePath()); return; } diff --git a/src/processing/mode/experimental/ExperimentalMode.java b/src/processing/mode/experimental/ExperimentalMode.java index 87b190d..a756700 100755 --- a/src/processing/mode/experimental/ExperimentalMode.java +++ b/src/processing/mode/experimental/ExperimentalMode.java @@ -119,7 +119,7 @@ public File[] getKeywordFiles() { volatile public static boolean errorCheckEnabled = true, warningsEnabled = true, codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false; - public static int autoSaveInterval = 5; //in minutes + public static int autoSaveInterval = 3; //in minutes public static final String prefErrorCheck = "pdex.errorCheckEnabled", prefWarnings = "pdex.warningsEnabled", From 77a37fb52abff717afb53ebdd6cf84f43b57edb9 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 21 Jan 2014 16:45:03 +0530 Subject: [PATCH 017/115] release notes --- pdeX.txt | 4 ++-- revisions.txt | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/pdeX.txt b/pdeX.txt index 803ecd0..2cc551f 100644 --- a/pdeX.txt +++ b/pdeX.txt @@ -3,5 +3,5 @@ authorList=[The Processing Foundation](http://processing.org) url=https://github.com/processing/processing-experimental sentence=The next generation of PDE paragraph=Intelligent Code Completion, Live Error Checker, Debugger, Auto Refactor, etc. -version=5 -prettyVersion=1.0.2b +version=6 +prettyVersion=1.0.3b diff --git a/revisions.txt b/revisions.txt index 5581f04..3d99c4f 100644 --- a/revisions.txt +++ b/revisions.txt @@ -1,4 +1,22 @@ +PDE X v1.0.3b - January 21, 2014 + +New Feature + ++ PDE X now saves a backup of your sketch every 3 minutes(configurable in preferences.txt). +In case of an unexpected crash, this should save the day! +https://github.com/processing/processing-experimental/issues/36 + +Bug fixes + ++ Outline Window width is now fixed +https://github.com/processing/processing-experimental/issues/31 + ++ Export Application works again on OS X +https://github.com/processing/processing-experimental/issues/33 + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + PDE X v1.0.2b - October 21, 2013 Bug fixes From d371f01bb6a6d9ec26636390ce9090d3f1dadb61 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 21 Jan 2014 18:45:31 +0530 Subject: [PATCH 018/115] Major Blooper :( --- src/processing/mode/experimental/AutoSaveUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/processing/mode/experimental/AutoSaveUtil.java b/src/processing/mode/experimental/AutoSaveUtil.java index 54e883c..4586603 100644 --- a/src/processing/mode/experimental/AutoSaveUtil.java +++ b/src/processing/mode/experimental/AutoSaveUtil.java @@ -27,7 +27,7 @@ public class AutoSaveUtil { */ public AutoSaveUtil(DebugEditor dedit, int timeOut){ editor = dedit; - if (timeOut < 5) { + if (timeOut < 1) { // less than 1 minute not allowed! saveTime = -1; throw new IllegalArgumentException(""); } From e5683072b9eda168c69f8f5da175a03ed48eeb4a Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 31 Jan 2014 13:35:54 +0530 Subject: [PATCH 019/115] javadoc update for TextArea --- .../mode/experimental/TextArea.java | 61 +++++++++++++------ 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/src/processing/mode/experimental/TextArea.java b/src/processing/mode/experimental/TextArea.java index 8025f96..b74d484 100644 --- a/src/processing/mode/experimental/TextArea.java +++ b/src/processing/mode/experimental/TextArea.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Martin Leopold + * Copyright (C) 2012-14 Martin Leopold and Manindra Moharana * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software @@ -127,6 +127,10 @@ public void setECSandThemeforTextArea(ErrorCheckerService ecs, customPainter.setECSandTheme(ecs, mode); } + /** + * Handles KeyEvents for TextArea + * Code completion begins from here. + */ public void processKeyEvent(KeyEvent evt) { if(evt.getKeyCode() == KeyEvent.VK_ESCAPE){ @@ -215,7 +219,11 @@ protected Object doInBackground() throws Exception { } - + /** + * Retrieves the word on which the mouse pointer is present + * @param evt - the MouseEvent which triggered this method + * @return + */ private String fetchPhrase(MouseEvent evt) { log("--handle Mouse Right Click--"); int off = xyToOffset(evt.getX(), evt.getY()); @@ -276,6 +284,14 @@ else if (s.length() == 0) return word.trim(); } } + + /** + * Retrieves the current word typed just before the caret. + * Then triggers code completion for that word. + * + * @param evt - the KeyEvent which triggered this method + * @return + */ private String fetchPhrase(KeyEvent evt) { int off = getCaretPosition(); @@ -361,29 +377,29 @@ else if (s.charAt(x1) == ']') { break; } -// if (x2 >= 0 && x2 < s.length()) { -// if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' -// || s.charAt(x2) == '$') -// word = word + s.charAt(x2++); -// else -// x2 = -1; -// } else -// x2 = -1; - -// if (x1 < 0 )//&& x2 < 0 -// break; + // if (x2 >= 0 && x2 < s.length()) { + // if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' + // || s.charAt(x2) == '$') + // word = word + s.charAt(x2++); + // else + // x2 = -1; + // } else + // x2 = -1; + + // if (x1 < 0 )//&& x2 < 0 + // break; if (i > 200) { // time out! break; } } -// if (keyChar != KeyEvent.CHAR_UNDEFINED) + // if (keyChar != KeyEvent.CHAR_UNDEFINED) if (Character.isDigit(word.charAt(0))) return null; word = word.trim(); -// if (word.endsWith(".")) -// word = word.substring(0, word.length() - 1); + // if (word.endsWith(".")) + // word = word.substring(0, word.length() - 1); int lineStartNonWSOffset = 0; if(word.length() > 1) errorCheckerService.getASTGenerator().preparePredictions(word, line @@ -664,7 +680,7 @@ public void mouseMoved(MouseEvent me) { //JEditTextArea textarea; - // worthless + /* No longer used private void addCompletionPopupListner() { this.addKeyListener(new KeyListener() { @@ -695,7 +711,7 @@ public void keyReleased(KeyEvent e) { public void keyPressed(KeyEvent e) { } }); - } + }*/ public void showSuggestionLater(final DefaultListModel defListModel, final String word) { SwingUtilities.invokeLater(new Runnable() { @@ -707,6 +723,12 @@ public void run() { }); } + /** + * Calculates location of caret and displays the suggestion popup at the location. + * + * @param defListModel + * @param subWord + */ protected void showSuggestion(DefaultListModel defListModel,String subWord) { hideSuggestion(); if (defListModel.size() == 0) { @@ -745,6 +767,9 @@ protected void showSuggestion(DefaultListModel defListModel,String subWord) { // }); } + /** + * Hides suggestion popup + */ protected void hideSuggestion() { if (suggestion != null) { suggestion.hide(); From 505c55de52623e62b5f677dd69663d78e90d6d9f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 31 Jan 2014 13:50:19 +0530 Subject: [PATCH 020/115] javadoc update for ASTNodeWrapper --- .../mode/experimental/ASTNodeWrapper.java | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index 9e99ad5..b980f15 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-14 Manindra Moharana + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; import static processing.mode.experimental.ExperimentalMode.log2; @@ -19,6 +37,11 @@ import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; import org.eclipse.jdt.core.dom.TypeDeclaration; +/** + * Wrapper class for ASTNode objects + * @author Manindra Moharana + * + */ public class ASTNodeWrapper { private ASTNode Node; @@ -142,7 +165,7 @@ public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { /** - * + * Finds the difference in pde and java code offsets * @param source * @param inpOffset * @param nodeLen @@ -354,6 +377,13 @@ public int[][] getOffsetMapping(String source){ return new int[][]{javaCodeMap,pdeCodeMap}; } + /** + * Gets offset mapping between java and pde code + * int[0][x] stores the java code offset and + * int[1][x] is the corresponding offset in pde code + * @param ecs + * @return int[0] - java code offset, int[1] - pde code offset + */ public int[][] getOffsetMapping(ErrorCheckerService ecs){ int pdeoffsets[] = getPDECodeOffsets(ecs); String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); From f24ad4b03862e6b4f59c337322ef2799d9d7b3f0 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 31 Jan 2014 13:55:44 +0530 Subject: [PATCH 021/115] javadoc update for AutoSaveUtil --- .../mode/experimental/AutoSaveUtil.java | 60 ++++++++++++++++--- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/src/processing/mode/experimental/AutoSaveUtil.java b/src/processing/mode/experimental/AutoSaveUtil.java index 4586603..71b2245 100644 --- a/src/processing/mode/experimental/AutoSaveUtil.java +++ b/src/processing/mode/experimental/AutoSaveUtil.java @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-14 Manindra Moharana + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + package processing.mode.experimental; import java.io.File; @@ -9,6 +27,13 @@ import processing.app.Base; import processing.app.Sketch; +/** + * Autosave utility for saving sketch backups in the background after + * certain intervals + * + * @author Manindra Moharana + * + */ public class AutoSaveUtil { private DebugEditor editor; @@ -20,10 +45,11 @@ public class AutoSaveUtil { private File autosaveDir, pastSave; private boolean isSaving; + /** * * @param dedit - * @param timeOut - in minutes + * @param timeOut - in minutes, how frequently should saves occur */ public AutoSaveUtil(DebugEditor dedit, int timeOut){ editor = dedit; @@ -38,6 +64,10 @@ public AutoSaveUtil(DebugEditor dedit, int timeOut){ autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); } + /** + * Check if any previous autosave exists + * @return + */ public boolean checkForPastSave(){ if(autosaveDir.exists()){ String prevSaves[] = Base.listFiles(autosaveDir, false); @@ -51,6 +81,9 @@ public boolean checkForPastSave(){ return false; } + /** + * Refresh autosave directory if current sketch location in the editor changes + */ public void reloadAutosaveDir(){ while(isSaving); autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); @@ -60,6 +93,9 @@ public File getPastSave(){ return pastSave; } + /** + * Start the auto save service + */ public void init(){ if(saveTime < 10000) saveTime = 10 * 1000; //saveTime = 10 * 1000; //TODO: remove @@ -69,12 +105,21 @@ public void init(){ ExperimentalMode.log("AutoSaver started"); } + /** + * Stop the autosave service + */ public void stop(){ while(isSaving); // save operation mustn't be interrupted if(timer != null) timer.cancel(); Base.removeDir(autosaveDir); } + /** + * Main function that performs the save operation + * Code reused from processing.app.Sketch.saveAs() + * @return + * @throws IOException + */ private boolean saveSketch() throws IOException{ if(!editor.getSketch().isModified()) return false; isSaving = true; @@ -220,6 +265,11 @@ public boolean accept(File file) { return true; } + /** + * Timertask used to perform the save operation every X minutes + * @author quarkninja + * + */ private class SaveTask extends TimerTask{ @Override @@ -228,19 +278,11 @@ public void run() { if(saveSketch()) ExperimentalMode.log("Backup Saved " + editor.getSketch().getMainFilePath()); } catch (IOException e) { - // TODO Auto-generated catch block e.printStackTrace(); } - //editor - - } } - public static void main(String[] args) { - - } - } From efa62fc6ae8e9a708b00a8045dc470e98e8fabfc Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 31 Jan 2014 14:06:46 +0530 Subject: [PATCH 022/115] javadoc update for CompletionPanel --- .../mode/experimental/CompletionPanel.java | 77 ++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/src/processing/mode/experimental/CompletionPanel.java b/src/processing/mode/experimental/CompletionPanel.java index 7973b76..ab32e4b 100644 --- a/src/processing/mode/experimental/CompletionPanel.java +++ b/src/processing/mode/experimental/CompletionPanel.java @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-14 Manindra Moharana + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; import static processing.mode.experimental.ExperimentalMode.logE; @@ -23,21 +41,51 @@ import processing.app.syntax.JEditTextArea; +/** + * Manages the actual suggestion popup that gets displayed + * @author Manindra Moharana + * + */ public class CompletionPanel { + + /** + * The completion list generated by ASTGenerator + */ private JList completionList; + /** + * The popup menu in which the suggestion list is shown + */ private JPopupMenu popupMenu; + /** + * Partial word which triggered the code completion and which needs to be completed + */ private String subWord; + /** + * Postion where the completion has to be inserted + */ private int insertionPosition; private TextArea textarea; + /** + * Scroll pane in which the completion list is displayed + */ private JScrollPane scrollPane; protected DebugEditor editor; + /** + * Triggers the completion popup + * @param textarea + * @param position - insertion position(caret pos) + * @param subWord - Partial word which triggered the code completion and which needs to be completed + * @param items - completion candidates + * @param location - Point location where popup list is to be displayed + * @param dedit + */ public CompletionPanel(final JEditTextArea textarea, int position, String subWord, DefaultListModel items, final Point location, DebugEditor dedit) { this.textarea = (TextArea) textarea; @@ -72,7 +120,7 @@ public void setVisible(boolean v){ popupMenu.setVisible(v); } - protected int setHeight(int itemCount){ + private int setHeight(int itemCount){ if(scrollPane.getHorizontalScrollBar().isVisible()) itemCount++; FontMetrics fm = textarea.getFontMetrics(textarea.getFont()); float h = (fm.getHeight() + fm.getDescent()*0.5f) * (itemCount + 1); @@ -94,6 +142,12 @@ protected int setWidth(){ return Math.min(280,(int)min); // popup menu height }*/ + /** + * Created the popup list to be displayed + * @param position + * @param items + * @return + */ private JList createSuggestionList(final int position, final DefaultListModel items) { @@ -142,6 +196,10 @@ public void run() { return true; } + /** + * Inserts the CompletionCandidate chosen from the suggestion list + * @return + */ public boolean insertSelection() { if (completionList.getSelectedValue() != null) { try { @@ -174,12 +232,18 @@ public boolean insertSelection() { return false; } + /** + * Hide the suggestion list + */ public void hide() { popupMenu.setVisible(false); //log("Suggestion hidden" + System.nanoTime()); //textarea.errorCheckerService.getASTGenerator().jdocWindowVisible(false); } + /** + * When up arrow key is pressed, moves the highlighted selection up in the list + */ public void moveUp() { if (completionList.getSelectedIndex() == 0) { scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getMaximum()); @@ -200,6 +264,9 @@ public void moveUp() { } + /** + * When down arrow key is pressed, moves the highlighted selection down in the list + */ public void moveDown() { if (completionList.getSelectedIndex() == completionList.getModel().getSize() - 1) { scrollPane.getVerticalScrollBar().setValue(0); @@ -231,7 +298,13 @@ private void selectIndex(int index) { // }); } - protected class CustomListRenderer extends + + /** + * Custom cell renderer to display icons along with the completion candidates + * @author Manindra Moharana + * + */ + private class CustomListRenderer extends javax.swing.DefaultListCellRenderer { //protected final ImageIcon classIcon, fieldIcon, methodIcon; From d9de9fa77cf85bfeee85f759f8a4ef2e0c7b6def Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 31 Jan 2014 14:11:55 +0530 Subject: [PATCH 023/115] javadoc update for DebugEditor --- .../mode/experimental/DebugEditor.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 5c7cf94..74f9abc 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -346,6 +346,10 @@ public void internalCloseRunner(){ super.internalCloseRunner(); } + /** + * Writes all error messages to a csv file. + * For analytics purposes only. + */ private void writeErrorsToFile(){ if (errorCheckerService.tempErrorLog.size() == 0) return; @@ -417,9 +421,16 @@ public void actionPerformed(ActionEvent e) { return buildSketchMenu(new JMenuItem[]{runItem, presentItem, stopItem}); }*/ + /** + * Whether debug toolbar is enabled + */ AtomicBoolean debugToolbarEnabled; + protected EditorToolbar javaToolbar, debugToolbar; + /** + * Toggles between java mode and debug mode toolbar + */ protected void switchToolbars(){ final EditorToolbar nextToolbar; if(debugToolbarEnabled.get()){ @@ -876,6 +887,11 @@ public boolean handleSaveAs() { return saved; } + /** + * Loads and starts the auto save service + * Also handles the case where an auto save backup is found. + * The user is asked to save the sketch to a new location + */ public void loadAutoSaver(){ log("Load Auto Saver()"); if(autosaver != null){ @@ -1376,17 +1392,27 @@ synchronized public boolean updateTable(final TableModel tableModel) { return errorTable.updateTable(tableModel); } + /** + * Handle whether the tiny red error indicator is shown near the error button + * at the bottom of the PDE + */ public void updateErrorToggle(){ btnShowErrors.updateMarker(errorCheckerService.hasErrors(), errorBar.errorColor); } + /** + * Handle refactor operation + */ private void handleRefactor() { log("Caret at:"); log(ta.getLineText(ta.getCaretLine())); errorCheckerService.getASTGenerator().handleRefactor(); } + /** + * Handle show usage operation + */ private void handleShowUsage() { log("Caret at:"); log(ta.getLineText(ta.getCaretLine())); From 1e0eddfbbceaef4d498acf0b738f6bb727284190 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 31 Jan 2014 14:13:00 +0530 Subject: [PATCH 024/115] javadoc update for DebugEditor2 --- src/processing/mode/experimental/DebugEditor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 74f9abc..02e698b 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Martin Leopold + * Copyright (C) 2012-14 Martin Leopold and Manindra Moharana * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software From 3b804caf25e4f75d53e24b6225bb1655a6974474 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 31 Jan 2014 14:14:02 +0530 Subject: [PATCH 025/115] javadoc update for ECS --- .../experimental/ErrorCheckerService.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index b6b18e6..71afef3 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2012-14 Manindra Moharana + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; @@ -42,6 +59,12 @@ import processing.core.PApplet; import processing.mode.java.preproc.PdePreprocessor; +/** + * The main error checking service + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ public class ErrorCheckerService implements Runnable{ protected DebugEditor editor; From 10c9afd13634f913317dd4ef383f41129f6ed379 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 2 Feb 2014 00:36:33 +0530 Subject: [PATCH 026/115] beginning work on race condition bug --- .../mode/experimental/ASTGenerator.java | 16 ++- .../mode/experimental/CompletionPanel.java | 121 +++++++++++++++++- .../mode/experimental/TextArea.java | 5 +- 3 files changed, 136 insertions(+), 6 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 03343de..4d7602e 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -27,6 +27,7 @@ import java.util.Map; import java.util.Stack; import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; import javax.swing.BorderFactory; @@ -150,6 +151,7 @@ public ASTGenerator(ErrorCheckerService ecs) { //addCompletionPopupListner(); addListeners(); //loadJavaDoc(); + predictionOngoing = new AtomicBoolean(false); } protected void setupGUI(){ @@ -784,15 +786,24 @@ protected void trimCandidates(String newWord){ //protected AtomicBoolean predictionsEnabled; protected int predictionMinLength = 2; + + private AtomicBoolean predictionOngoing; + public void preparePredictions(final String word, final int line, final int lineStartNonWSOffset) { + if(predictionOngoing.get()) return; + if(!ExperimentalMode.codeCompletionsEnabled) return; - if(word.length() < predictionMinLength) return; + if(word.length() < predictionMinLength) return; + + predictionOngoing.set(true); // This method is called from TextArea.fetchPhrase, which is called via a SwingWorker instance // in TextArea.processKeyEvent if(caretWithinLineComment()){ log("No predictions."); + predictionOngoing.set(false); return; } + // SwingWorker worker = new SwingWorker() { // // @Override @@ -826,6 +837,7 @@ public void preparePredictions(final String word, final int line, final int line } showPredictions(word); lastPredictedWord = word2; + predictionOngoing.set(false); return; } } @@ -1006,7 +1018,7 @@ public void preparePredictions(final String word, final int line, final int line } showPredictions(word); - + predictionOngoing.set(false); // } // }; // diff --git a/src/processing/mode/experimental/CompletionPanel.java b/src/processing/mode/experimental/CompletionPanel.java index ab32e4b..610be8c 100644 --- a/src/processing/mode/experimental/CompletionPanel.java +++ b/src/processing/mode/experimental/CompletionPanel.java @@ -18,6 +18,7 @@ package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; +import static processing.mode.experimental.ExperimentalMode.log2; import static processing.mode.experimental.ExperimentalMode.logE; import java.awt.BorderLayout; @@ -25,6 +26,7 @@ import java.awt.Component; import java.awt.FontMetrics; import java.awt.Point; +import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Iterator; @@ -108,7 +110,7 @@ public CompletionPanel(final JEditTextArea textarea, int position, String subWor textarea.requestFocusInWindow(); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y); - //log("Suggestion constructed" + System.nanoTime()); + log("Suggestion shown: " + System.currentTimeMillis()); } public boolean isVisible() { @@ -205,7 +207,7 @@ public boolean insertSelection() { try { String selectedSuggestion = ((CompletionCandidate) completionList .getSelectedValue()).getCompletionString().substring(subWord.length()); - logE(subWord+" <= subword,Inserting suggestion=> " + selectedSuggestion); + logE(subWord+" <= subword,Inserting suggestion=> " + selectedSuggestion + " Current sub: " + fetchPhrase()); textarea.getDocument().remove(insertionPosition-subWord.length(), subWord.length()); textarea.getDocument().insertString(insertionPosition-subWord.length(), ((CompletionCandidate) completionList @@ -223,6 +225,7 @@ public boolean insertSelection() { else { textarea.setCaretPosition(insertionPosition + selectedSuggestion.length()); } + log("Suggestion inserted: " + System.currentTimeMillis()); return true; } catch (BadLocationException e1) { e1.printStackTrace(); @@ -231,6 +234,120 @@ public boolean insertSelection() { } return false; } + + private String fetchPhrase() { + TextArea ta = editor.ta; + int off = ta.getCaretPosition(); + log2("off " + off); + if (off < 0) + return null; + int line = ta.getCaretLine(); + if (line < 0) + return null; + String s = ta.getLineText(line); + log2("lin " + line); + /* + * if (s == null) return null; else if (s.length() == 0) return null; + */ +// else { + //log2(s + " len " + s.length()); + + int x = ta.getCaretPosition() - ta.getLineStartOffset(line) - 1, x2 = x + 1, x1 = x - 1; + if(x >= s.length() || x < 0) + return null; //TODO: Does this check cause problems? Verify. + log2(" x char: " + s.charAt(x)); + //int xLS = off - getLineStartNonWhiteSpaceOffset(line); + + String word = (x < s.length() ? s.charAt(x) : "") + ""; + if (s.trim().length() == 1) { +// word = "" +// + (keyChar == KeyEvent.CHAR_UNDEFINED ? s.charAt(x - 1) : keyChar); + //word = (x < s.length()?s.charAt(x):"") + ""; + word = word.trim(); + if (word.endsWith(".")) + word = word.substring(0, word.length() - 1); + + return word; + } +// if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) +// ; // accepted these keys +// else if (!(Character.isLetterOrDigit(keyChar) || keyChar == '_' || keyChar == '$')) +// return null; + int i = 0; + int closeB = 0; + + while (true) { + i++; + //TODO: currently works on single line only. "a. b()" won't be detected + if (x1 >= 0) { +// if (s.charAt(x1) != ';' && s.charAt(x1) != ',' && s.charAt(x1) != '(') + if (Character.isLetterOrDigit(s.charAt(x1)) || s.charAt(x1) == '_' + || s.charAt(x1) == '.' || s.charAt(x1) == ')' || s.charAt(x1) == ']') { + + if (s.charAt(x1) == ')') { + word = s.charAt(x1--) + word; + closeB++; + while (x1 >= 0 && closeB > 0) { + word = s.charAt(x1) + word; + if (s.charAt(x1) == '(') + closeB--; + if (s.charAt(x1) == ')') + closeB++; + x1--; + } + } + else if (s.charAt(x1) == ']') { + word = s.charAt(x1--) + word; + closeB++; + while (x1 >= 0 && closeB > 0) { + word = s.charAt(x1) + word; + if (s.charAt(x1) == '[') + closeB--; + if (s.charAt(x1) == ']') + closeB++; + x1--; + } + } + else { + word = s.charAt(x1--) + word; + } + } else { + break; + } + } else { + break; + } + + // if (x2 >= 0 && x2 < s.length()) { + // if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' + // || s.charAt(x2) == '$') + // word = word + s.charAt(x2++); + // else + // x2 = -1; + // } else + // x2 = -1; + + // if (x1 < 0 )//&& x2 < 0 + // break; + if (i > 200) { + // time out! + break; + } + } + // if (keyChar != KeyEvent.CHAR_UNDEFINED) + + if (Character.isDigit(word.charAt(0))) + return null; + word = word.trim(); + // if (word.endsWith(".")) + // word = word.substring(0, word.length() - 1); + if(word.length() > 1) + + //showSuggestionLater(); + return word; + else return ""; + //} + } /** * Hide the suggestion list diff --git a/src/processing/mode/experimental/TextArea.java b/src/processing/mode/experimental/TextArea.java index b74d484..6657353 100644 --- a/src/processing/mode/experimental/TextArea.java +++ b/src/processing/mode/experimental/TextArea.java @@ -205,11 +205,12 @@ public void processKeyEvent(KeyEvent evt) { final KeyEvent evt2 = evt; SwingWorker worker = new SwingWorker() { protected Object doInBackground() throws Exception { + log("[KeyEvent]" + evt2.getKeyChar() + " |Prediction started: " + System.currentTimeMillis()); errorCheckerService.runManualErrorCheck(); // Provide completions only if it's enabled if(ExperimentalMode.codeCompletionsEnabled) - log(" Typing: " + fetchPhrase(evt2) + " " - + (evt2.getKeyChar() == KeyEvent.VK_ENTER)); + log("Typing: " + fetchPhrase(evt2) + " " + + (evt2.getKeyChar() == KeyEvent.VK_ENTER) + " T: " + System.currentTimeMillis()); return null; } }; From 750a913aa66feb82145f9146c3f406b3d3d4608e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 2 Feb 2014 01:23:38 +0530 Subject: [PATCH 027/115] hopefully fixes the tricky #38 --- .../mode/experimental/CompletionPanel.java | 94 ++++++------------- 1 file changed, 30 insertions(+), 64 deletions(-) diff --git a/src/processing/mode/experimental/CompletionPanel.java b/src/processing/mode/experimental/CompletionPanel.java index 610be8c..4eae592 100644 --- a/src/processing/mode/experimental/CompletionPanel.java +++ b/src/processing/mode/experimental/CompletionPanel.java @@ -199,31 +199,37 @@ public void run() { } /** - * Inserts the CompletionCandidate chosen from the suggestion list + * Inserts the CompletionCandidate chosen from the suggestion list + * * @return */ public boolean insertSelection() { if (completionList.getSelectedValue() != null) { try { + String currentSubword = fetchCurrentSubword(); String selectedSuggestion = ((CompletionCandidate) completionList - .getSelectedValue()).getCompletionString().substring(subWord.length()); - logE(subWord+" <= subword,Inserting suggestion=> " + selectedSuggestion + " Current sub: " + fetchPhrase()); - textarea.getDocument().remove(insertionPosition-subWord.length(), subWord.length()); - textarea.getDocument().insertString(insertionPosition-subWord.length(), - ((CompletionCandidate) completionList - .getSelectedValue()).getCompletionString(), null); - if(selectedSuggestion.endsWith(")")) - { - if(!selectedSuggestion.endsWith("()")){ + .getSelectedValue()).getCompletionString().substring(currentSubword + .length()); + logE(subWord + " <= subword,Inserting suggestion=> " + + selectedSuggestion + " Current sub: " + currentSubword); + textarea.getDocument().remove(insertionPosition + - currentSubword.length(), + currentSubword.length()); + textarea.getDocument() + .insertString(insertionPosition - currentSubword.length(), + ((CompletionCandidate) completionList + .getSelectedValue()).getCompletionString(), null); + if (selectedSuggestion.endsWith(")")) { + if (!selectedSuggestion.endsWith("()")) { int x = selectedSuggestion.indexOf('('); - if(x != -1){ + if (x != -1) { //log("X................... " + x); - textarea.setCaretPosition(insertionPosition + (x+1)); + textarea.setCaretPosition(insertionPosition + (x + 1)); } } - } - else { - textarea.setCaretPosition(insertionPosition + selectedSuggestion.length()); + } else { + textarea.setCaretPosition(insertionPosition + + selectedSuggestion.length()); } log("Suggestion inserted: " + System.currentTimeMillis()); return true; @@ -235,17 +241,17 @@ public boolean insertSelection() { return false; } - private String fetchPhrase() { + private String fetchCurrentSubword() { TextArea ta = editor.ta; int off = ta.getCaretPosition(); - log2("off " + off); + //log2("off " + off); if (off < 0) return null; int line = ta.getCaretLine(); if (line < 0) return null; String s = ta.getLineText(line); - log2("lin " + line); + //log2("lin " + line); /* * if (s == null) return null; else if (s.length() == 0) return null; */ @@ -255,7 +261,7 @@ private String fetchPhrase() { int x = ta.getCaretPosition() - ta.getLineStartOffset(line) - 1, x2 = x + 1, x1 = x - 1; if(x >= s.length() || x < 0) return null; //TODO: Does this check cause problems? Verify. - log2(" x char: " + s.charAt(x)); + //log2(" x char: " + s.charAt(x)); //int xLS = off - getLineStartNonWhiteSpaceOffset(line); String word = (x < s.length() ? s.charAt(x) : "") + ""; @@ -281,54 +287,16 @@ private String fetchPhrase() { //TODO: currently works on single line only. "a. b()" won't be detected if (x1 >= 0) { // if (s.charAt(x1) != ';' && s.charAt(x1) != ',' && s.charAt(x1) != '(') - if (Character.isLetterOrDigit(s.charAt(x1)) || s.charAt(x1) == '_' - || s.charAt(x1) == '.' || s.charAt(x1) == ')' || s.charAt(x1) == ']') { + if (Character.isLetterOrDigit(s.charAt(x1)) || s.charAt(x1) == '_') { + + word = s.charAt(x1--) + word; - if (s.charAt(x1) == ')') { - word = s.charAt(x1--) + word; - closeB++; - while (x1 >= 0 && closeB > 0) { - word = s.charAt(x1) + word; - if (s.charAt(x1) == '(') - closeB--; - if (s.charAt(x1) == ')') - closeB++; - x1--; - } - } - else if (s.charAt(x1) == ']') { - word = s.charAt(x1--) + word; - closeB++; - while (x1 >= 0 && closeB > 0) { - word = s.charAt(x1) + word; - if (s.charAt(x1) == '[') - closeB--; - if (s.charAt(x1) == ']') - closeB++; - x1--; - } - } - else { - word = s.charAt(x1--) + word; - } } else { break; } } else { break; } - - // if (x2 >= 0 && x2 < s.length()) { - // if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' - // || s.charAt(x2) == '$') - // word = word + s.charAt(x2++); - // else - // x2 = -1; - // } else - // x2 = -1; - - // if (x1 < 0 )//&& x2 < 0 - // break; if (i > 200) { // time out! break; @@ -339,13 +307,11 @@ else if (s.charAt(x1) == ']') { if (Character.isDigit(word.charAt(0))) return null; word = word.trim(); - // if (word.endsWith(".")) - // word = word.substring(0, word.length() - 1); - if(word.length() > 1) + if (word.endsWith(".")) + word = word.substring(0, word.length() - 1); //showSuggestionLater(); return word; - else return ""; //} } From 7bf09ba3ad4c7a74ea1a9ecd1e344d15d1d082d4 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 2 Feb 2014 19:35:58 +0530 Subject: [PATCH 028/115] revisions updated --- revisions.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/revisions.txt b/revisions.txt index 3d99c4f..5a2a1fd 100644 --- a/revisions.txt +++ b/revisions.txt @@ -1,4 +1,13 @@ +PDE X v1.0.4b - February , 2014 + +Bug fixes + ++ Autocompletion bug, column is sometimes off by 1 +https://github.com/processing/processing-experimental/issues/38 + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + PDE X v1.0.3b - January 21, 2014 New Feature From 63347c62841c0535cdff009bd5509d88f3d13e23 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 2 Feb 2014 19:58:51 +0530 Subject: [PATCH 029/115] completion popup height bug fix --- .../mode/experimental/CompletionPanel.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/processing/mode/experimental/CompletionPanel.java b/src/processing/mode/experimental/CompletionPanel.java index 4eae592..cadc007 100644 --- a/src/processing/mode/experimental/CompletionPanel.java +++ b/src/processing/mode/experimental/CompletionPanel.java @@ -123,11 +123,15 @@ public void setVisible(boolean v){ } private int setHeight(int itemCount){ - if(scrollPane.getHorizontalScrollBar().isVisible()) itemCount++; - FontMetrics fm = textarea.getFontMetrics(textarea.getFont()); - float h = (fm.getHeight() + fm.getDescent()*0.5f) * (itemCount + 1); - log("popup height " + Math.min(250,h)); - return Math.min(250,(int)h); // popup menu height + FontMetrics fm = textarea.getFontMetrics(textarea.getFont()); + float h = (fm.getHeight() + (fm.getDescent()) * 0.5f) * (itemCount); + if (scrollPane.getHorizontalScrollBar().isVisible()) + h += scrollPane.getHorizontalScrollBar().getHeight() + fm.getHeight() + + (fm.getDescent() + fm.getAscent()) * 0.8f; + // 0.5f and 0.8f scaling give respectable results. + //log("popup height " + Math.min(250,h) + //+ scrollPane.getHorizontalScrollBar().isVisible()); + return Math.min(250, (int) h); // popup menu height } /*TODO: Make width dynamic From bdf6ee06bc4b6fe20b4b62094c226b112c727b1f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 23 Feb 2014 03:12:10 +0530 Subject: [PATCH 030/115] lookin into jdoc scroll bug, irritating one this --- .../mode/experimental/ASTGenerator.java | 5 +- .../mode/experimental/ASTNodeWrapper.java | 83 ++++++++++++++++++- .../experimental/ErrorCheckerService.java | 4 + 3 files changed, 88 insertions(+), 4 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 4d7602e..1d2a052 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -235,7 +235,10 @@ protected void setupGUI(){ } - public static final boolean SHOWAST = !true; + /** + * Toggle AST View window + */ + public static final boolean SHOWAST = true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index b980f15..340f956 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -29,6 +29,7 @@ import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.ExpressionStatement; import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.Javadoc; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.QualifiedName; @@ -99,6 +100,7 @@ public ASTNodeWrapper(ASTNode node, String label){ public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { int nodeOffset = Node.getStartPosition(), nodeLength = Node .getLength(); + log("0.nodeOffset " + nodeOffset); ASTNode thisNode = Node; while (thisNode.getParent() != null) { if (getLineNumber(thisNode.getParent()) == lineNumber) { @@ -119,8 +121,34 @@ public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { */ int altStartPos = thisNode.getStartPosition(); + log("1.Altspos " + altStartPos); thisNode = thisNode.getParent(); + int jdocOffset; Javadoc jd = null; + if(thisNode instanceof TypeDeclaration){ + jd = ((TypeDeclaration)thisNode).getJavadoc(); + log("Has t jdoc " + ((TypeDeclaration)thisNode).getJavadoc()); + } else if(thisNode instanceof MethodDeclaration){ + jd = ((MethodDeclaration)thisNode).getJavadoc(); + log("Has m jdoc " + jd); + } else if(thisNode instanceof FieldDeclaration){ + jd = ((FieldDeclaration)thisNode).getJavadoc(); + log("Has f jdoc " + ((FieldDeclaration)thisNode).getJavadoc()); + } + + if(jd != null){ + jdocOffset = jd.getLength(); + log("jdoc offset: " + jdocOffset); + while (thisNode.getParent() != null) { + if (getLineNumber2(thisNode.getParent()) == getLineNumber2(getNode())) { + thisNode = thisNode.getParent(); + } else { + break; + } + } + //thisNode = thisNode.getParent(); + } + log("Visiting children of node " + getNodeAsString(thisNode)); Iterator it = thisNode .structuralPropertiesForType().iterator(); boolean flag = true; @@ -130,15 +158,17 @@ public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { if (prop.isChildListProperty()) { List nodelist = (List) thisNode .getStructuralProperty(prop); + log("prop " + prop); for (ASTNode cnode : nodelist) { - if (getLineNumber(cnode) == lineNumber) { + log("Visiting node " + getNodeAsString(cnode)); + if (getLineNumber2(cnode) == lineNumber) { if (flag) { altStartPos = cnode.getStartPosition(); // log("multi..."); flag = false; } else { - if(cnode == Node){ + if (cnode == Node) { // loop only till the current node. break; } @@ -159,10 +189,36 @@ public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { if (vals != null) return new int[] { lineNumber, nodeOffset + vals[0] - altStartPos, vals[1] }; - else + else {// no offset mapping needed + log("joff[1] = " + (nodeOffset - altStartPos)); return new int[] { lineNumber, nodeOffset - altStartPos, nodeLength }; + } } + private boolean hasJavaDoc(ASTNode node){ + if(node != null){ + Iterator it = node + .structuralPropertiesForType().iterator(); + log("Checkin for javadoc in child node of " + getNodeAsString(node)); + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + log("prop " + prop); + for (ASTNode cnode : nodelist) { + log("Visiting node " + getNodeAsString(cnode)); + if(cnode instanceof Javadoc){ + log("Visiting jdoc " + cnode); + return true; + } + } + } + } + } + return false; + } /** * Finds the difference in pde and java code offsets @@ -492,6 +548,27 @@ private static int getLineNumber(ASTNode node) { return ((CompilationUnit) node.getRoot()).getLineNumber(node .getStartPosition()); } + + private static int getLineNumber2(ASTNode thisNode) { + int jdocOffset = 0; Javadoc jd = null; + if(thisNode instanceof TypeDeclaration){ + jd = ((TypeDeclaration)thisNode).getJavadoc(); + log("Has t jdoc " + ((TypeDeclaration)thisNode).getJavadoc()); + } else if(thisNode instanceof MethodDeclaration){ + jd = ((MethodDeclaration)thisNode).getJavadoc(); + log("Has m jdoc " + jd); + } else if(thisNode instanceof FieldDeclaration){ + jd = ((FieldDeclaration)thisNode).getJavadoc(); + log("Has f jdoc " + ((FieldDeclaration)thisNode).getJavadoc()); + } + if(jd != null){ + jdocOffset = 1+jd.getLength(); + } + log("ln 2 = " + ((CompilationUnit) thisNode.getRoot()).getLineNumber(thisNode + .getStartPosition() + jdocOffset)); + return ((CompilationUnit) thisNode.getRoot()).getLineNumber(thisNode + .getStartPosition() + jdocOffset); + } static private String getNodeAsString(ASTNode node) { if (node == null) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index 71afef3..89f6538 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -1278,9 +1278,13 @@ protected String preprocessCode(String pdeCode) { * @return true - if highlighting happened correctly. */ public boolean highlightNode(ASTNodeWrapper awrap){ + log("Highlighting: " + awrap); try { int pdeoffsets[] = awrap.getPDECodeOffsets(this); int javaoffsets[] = awrap.getJavaCodeOffsets(this); + log("offsets: " +pdeoffsets[0] + "," + + pdeoffsets[1]+ "," +javaoffsets[1]+ "," + + javaoffsets[2]); scrollToErrorLine(editor, pdeoffsets[0], pdeoffsets[1],javaoffsets[1], javaoffsets[2]); From 599eccc4cb4333cf9ca614e3b2496c5975d3f3c8 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 24 Feb 2014 00:48:57 +0530 Subject: [PATCH 031/115] Fixes #15 DIE BUG DIE --- .../mode/experimental/ASTNodeWrapper.java | 189 +++++++++++++----- 1 file changed, 140 insertions(+), 49 deletions(-) diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index 340f956..0f2ad87 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -36,7 +36,9 @@ import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; +import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; /** * Wrapper class for ASTNode objects @@ -127,31 +129,155 @@ public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { if(thisNode instanceof TypeDeclaration){ jd = ((TypeDeclaration)thisNode).getJavadoc(); + altStartPos = getLen((TypeDeclaration)thisNode); log("Has t jdoc " + ((TypeDeclaration)thisNode).getJavadoc()); } else if(thisNode instanceof MethodDeclaration){ + altStartPos = getLen((MethodDeclaration)thisNode); jd = ((MethodDeclaration)thisNode).getJavadoc(); log("Has m jdoc " + jd); } else if(thisNode instanceof FieldDeclaration){ - jd = ((FieldDeclaration)thisNode).getJavadoc(); - log("Has f jdoc " + ((FieldDeclaration)thisNode).getJavadoc()); + FieldDeclaration fd = ((FieldDeclaration)thisNode); + jd = fd.getJavadoc(); + log("Has f jdoc " + fd.getJavadoc()); + altStartPos = getLen(fd); + //nodeOffset = ((VariableDeclarationFragment)(fd.fragments().get(0))).getName().getStartPosition(); } if(jd != null){ - jdocOffset = jd.getLength(); - log("jdoc offset: " + jdocOffset); - while (thisNode.getParent() != null) { - if (getLineNumber2(thisNode.getParent()) == getLineNumber2(getNode())) { - thisNode = thisNode.getParent(); - } else { - break; +// jdocOffset = jd.getLength(); +// log("jdoc offset: " + jdocOffset); + //testForMultilineDecl(thisNode); + //thisNode = thisNode.getParent(); + } + else{ + log("Visiting children of node " + getNodeAsString(thisNode)); + Iterator it = thisNode + .structuralPropertiesForType().iterator(); + boolean flag = true; + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + if (prop.isChildListProperty()) { + List nodelist = (List) thisNode + .getStructuralProperty(prop); + log("prop " + prop); + for (ASTNode cnode : nodelist) { + log("Visiting node " + getNodeAsString(cnode)); + if (getLineNumber(cnode) == lineNumber) { + if (flag) { + altStartPos = cnode.getStartPosition(); + // log("multi..."); + + flag = false; + } else { + if (cnode == Node) { + // loop only till the current node. + break; + } + // We've located the first node in the line. + // Now normalize offsets till Node + //altStartPos += normalizeOffsets(cnode); + + } + + } + } } } - //thisNode = thisNode.getParent(); + log("Altspos " + altStartPos); + } + + int pdeoffsets[] = getPDECodeOffsets(ecs); + String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); + int vals[] = createOffsetMapping(pdeCode,nodeOffset - altStartPos,nodeLength); + if (vals != null) + return new int[] { + lineNumber, nodeOffset + vals[0] - altStartPos, vals[1] }; + else {// no offset mapping needed + log("joff[1] = " + (nodeOffset - altStartPos)); + return new int[] { lineNumber, nodeOffset - altStartPos, nodeLength }; } + } + + private int getLen(FieldDeclaration fd){ + List list= fd.modifiers(); + SimpleName sn = (SimpleName) getNode(); + + Type tp = fd.getType(); + int lineNum = getLineNumber(sn); + log("SN "+sn + ", " + lineNum); + for (ASTNode astNode : list) { + if(getLineNumber(astNode) == lineNum) + { + log("first node in that line " + astNode); + log("diff " + (sn.getStartPosition() - astNode.getStartPosition())); + return (astNode.getStartPosition()); + } + } + if(getLineNumber(fd.getType()) == lineNum) + { + log("first node in that line " + tp); + log("diff " + (sn.getStartPosition() - tp.getStartPosition())); + return (tp.getStartPosition()); + } + + + return 0; + } + + private int getLen(MethodDeclaration md) { + List list = md.modifiers(); + SimpleName sn = (SimpleName) getNode(); + int lineNum = getLineNumber(sn); + log("SN " + sn + ", " + lineNum); + + for (ASTNode astNode : list) { + if (getLineNumber(astNode) == lineNum) { + log("first node in that line " + astNode); + log("diff " + (sn.getStartPosition() - astNode.getStartPosition())); + return (astNode.getStartPosition()); + } + } + + if (!md.isConstructor()) { + Type tp = md.getReturnType2(); + if (getLineNumber(tp) == lineNum) { + log("first node in that line " + tp); + log("diff " + (sn.getStartPosition() - tp.getStartPosition())); + return (tp.getStartPosition()); + } + } + + return 0; + } + + private int getLen(TypeDeclaration td){ + List list= td.modifiers(); + list = td.modifiers(); + SimpleName sn = (SimpleName) getNode(); + + int lineNum = getLineNumber(sn); + log("SN "+sn + ", " + lineNum); + for (ASTNode astNode : list) { + if(getLineNumber(astNode) == lineNum) + { + log("first node in that line " + astNode); + log("diff " + (sn.getStartPosition() - astNode.getStartPosition())); + return (astNode.getStartPosition()); + } + } + + return 0; + } + + private void testForMultilineDecl(ASTNode thisNode){ + int minLineNum = lineNumber, maxLineNum = ((CompilationUnit) thisNode + .getRoot()).getLineNumber(thisNode.getStartPosition()); log("Visiting children of node " + getNodeAsString(thisNode)); Iterator it = thisNode .structuralPropertiesForType().iterator(); boolean flag = true; + int altStartPos = 0; while (it.hasNext()) { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it .next(); @@ -161,7 +287,7 @@ public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { log("prop " + prop); for (ASTNode cnode : nodelist) { log("Visiting node " + getNodeAsString(cnode)); - if (getLineNumber2(cnode) == lineNumber) { + if (getLineNumber(cnode) >= minLineNum && getLineNumber(cnode) <= maxLineNum) { if (flag) { altStartPos = cnode.getStartPosition(); // log("multi..."); @@ -177,49 +303,14 @@ public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { //altStartPos += normalizeOffsets(cnode); } - + testForMultilineDecl(cnode); FieldDeclaration f; } } } } log("Altspos " + altStartPos); - int pdeoffsets[] = getPDECodeOffsets(ecs); - String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); - int vals[] = createOffsetMapping(pdeCode,nodeOffset - altStartPos,nodeLength); - if (vals != null) - return new int[] { - lineNumber, nodeOffset + vals[0] - altStartPos, vals[1] }; - else {// no offset mapping needed - log("joff[1] = " + (nodeOffset - altStartPos)); - return new int[] { lineNumber, nodeOffset - altStartPos, nodeLength }; - } } - private boolean hasJavaDoc(ASTNode node){ - if(node != null){ - Iterator it = node - .structuralPropertiesForType().iterator(); - log("Checkin for javadoc in child node of " + getNodeAsString(node)); - while (it.hasNext()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); - if (prop.isChildListProperty()) { - List nodelist = (List) node - .getStructuralProperty(prop); - log("prop " + prop); - for (ASTNode cnode : nodelist) { - log("Visiting node " + getNodeAsString(cnode)); - if(cnode instanceof Javadoc){ - log("Visiting jdoc " + cnode); - return true; - } - } - } - } - } - return false; - } - /** * Finds the difference in pde and java code offsets * @param source @@ -549,7 +640,7 @@ private static int getLineNumber(ASTNode node) { .getStartPosition()); } - private static int getLineNumber2(ASTNode thisNode) { + /*private static int getLineNumber2(ASTNode thisNode) { int jdocOffset = 0; Javadoc jd = null; if(thisNode instanceof TypeDeclaration){ jd = ((TypeDeclaration)thisNode).getJavadoc(); @@ -568,7 +659,7 @@ private static int getLineNumber2(ASTNode thisNode) { .getStartPosition() + jdocOffset)); return ((CompilationUnit) thisNode.getRoot()).getLineNumber(thisNode .getStartPosition() + jdocOffset); - } + }*/ static private String getNodeAsString(ASTNode node) { if (node == null) From 5df669c6ff58fee2664bcc12f5c97bfe9e44c536 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 1 Mar 2014 16:25:02 +0530 Subject: [PATCH 032/115] comments and cleanup --- .../mode/experimental/ASTNodeWrapper.java | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index 0f2ad87..9e4a473 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -125,31 +125,33 @@ public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { int altStartPos = thisNode.getStartPosition(); log("1.Altspos " + altStartPos); thisNode = thisNode.getParent(); - int jdocOffset; Javadoc jd = null; + Javadoc jd = null; - if(thisNode instanceof TypeDeclaration){ - jd = ((TypeDeclaration)thisNode).getJavadoc(); - altStartPos = getLen((TypeDeclaration)thisNode); - log("Has t jdoc " + ((TypeDeclaration)thisNode).getJavadoc()); - } else if(thisNode instanceof MethodDeclaration){ - altStartPos = getLen((MethodDeclaration)thisNode); - jd = ((MethodDeclaration)thisNode).getJavadoc(); + /* + * There's another case that needs to be handled. If a TD, MD or FD + * contains javadoc comments(multi or single line) the starting position + * of the javadoc is treated as the beginning of the declaration by the AST parser. + * But that's clearly not what we need. The true decl begins after the javadoc ends. + * So this offset needs to be found carefully and stored in altStartPos + * + */ + if (thisNode instanceof TypeDeclaration) { + jd = ((TypeDeclaration) thisNode).getJavadoc(); + altStartPos = getLen((TypeDeclaration) thisNode); + log("Has t jdoc " + ((TypeDeclaration) thisNode).getJavadoc()); + } else if (thisNode instanceof MethodDeclaration) { + altStartPos = getLen((MethodDeclaration) thisNode); + jd = ((MethodDeclaration) thisNode).getJavadoc(); log("Has m jdoc " + jd); - } else if(thisNode instanceof FieldDeclaration){ - FieldDeclaration fd = ((FieldDeclaration)thisNode); + } else if (thisNode instanceof FieldDeclaration) { + FieldDeclaration fd = ((FieldDeclaration) thisNode); jd = fd.getJavadoc(); log("Has f jdoc " + fd.getJavadoc()); - altStartPos = getLen(fd); + altStartPos = getJavadocOffset(fd); //nodeOffset = ((VariableDeclarationFragment)(fd.fragments().get(0))).getName().getStartPosition(); } - if(jd != null){ -// jdocOffset = jd.getLength(); -// log("jdoc offset: " + jdocOffset); - //testForMultilineDecl(thisNode); - //thisNode = thisNode.getParent(); - } - else{ + if(jd == null){ log("Visiting children of node " + getNodeAsString(thisNode)); Iterator it = thisNode .structuralPropertiesForType().iterator(); @@ -199,7 +201,12 @@ public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { } } - private int getLen(FieldDeclaration fd){ + /** + * + * @param fd + * @return + */ + private int getJavadocOffset(FieldDeclaration fd){ List list= fd.modifiers(); SimpleName sn = (SimpleName) getNode(); From 93046ed302c1384f57b7e40d0b6d4932c6358ca4 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 1 Mar 2014 16:26:06 +0530 Subject: [PATCH 033/115] reafactored --- src/processing/mode/experimental/ASTNodeWrapper.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index 9e4a473..45518b4 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -137,10 +137,10 @@ public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { */ if (thisNode instanceof TypeDeclaration) { jd = ((TypeDeclaration) thisNode).getJavadoc(); - altStartPos = getLen((TypeDeclaration) thisNode); + altStartPos = getJavadocOffset((TypeDeclaration) thisNode); log("Has t jdoc " + ((TypeDeclaration) thisNode).getJavadoc()); } else if (thisNode instanceof MethodDeclaration) { - altStartPos = getLen((MethodDeclaration) thisNode); + altStartPos = getJavadocOffset((MethodDeclaration) thisNode); jd = ((MethodDeclaration) thisNode).getJavadoc(); log("Has m jdoc " + jd); } else if (thisNode instanceof FieldDeclaration) { @@ -232,7 +232,7 @@ private int getJavadocOffset(FieldDeclaration fd){ return 0; } - private int getLen(MethodDeclaration md) { + private int getJavadocOffset(MethodDeclaration md) { List list = md.modifiers(); SimpleName sn = (SimpleName) getNode(); int lineNum = getLineNumber(sn); @@ -258,7 +258,7 @@ private int getLen(MethodDeclaration md) { return 0; } - private int getLen(TypeDeclaration td){ + private int getJavadocOffset(TypeDeclaration td){ List list= td.modifiers(); list = td.modifiers(); SimpleName sn = (SimpleName) getNode(); From 6831b5595f61213fcc4eca7b980ced45a0171fd5 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 1 Mar 2014 16:54:09 +0530 Subject: [PATCH 034/115] clean up --- .../mode/experimental/ASTNodeWrapper.java | 42 +------------------ 1 file changed, 1 insertion(+), 41 deletions(-) diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index 45518b4..6c6cbc6 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -259,6 +259,7 @@ private int getJavadocOffset(MethodDeclaration md) { } private int getJavadocOffset(TypeDeclaration td){ + // TODO: This is still broken. Hence no refactoring or highlighting on scroll works :\ List list= td.modifiers(); list = td.modifiers(); SimpleName sn = (SimpleName) getNode(); @@ -277,47 +278,6 @@ private int getJavadocOffset(TypeDeclaration td){ return 0; } - private void testForMultilineDecl(ASTNode thisNode){ - int minLineNum = lineNumber, maxLineNum = ((CompilationUnit) thisNode - .getRoot()).getLineNumber(thisNode.getStartPosition()); - log("Visiting children of node " + getNodeAsString(thisNode)); - Iterator it = thisNode - .structuralPropertiesForType().iterator(); - boolean flag = true; - int altStartPos = 0; - while (it.hasNext()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); - if (prop.isChildListProperty()) { - List nodelist = (List) thisNode - .getStructuralProperty(prop); - log("prop " + prop); - for (ASTNode cnode : nodelist) { - log("Visiting node " + getNodeAsString(cnode)); - if (getLineNumber(cnode) >= minLineNum && getLineNumber(cnode) <= maxLineNum) { - if (flag) { - altStartPos = cnode.getStartPosition(); - // log("multi..."); - - flag = false; - } else { - if (cnode == Node) { - // loop only till the current node. - break; - } - // We've located the first node in the line. - // Now normalize offsets till Node - //altStartPos += normalizeOffsets(cnode); - - } - testForMultilineDecl(cnode); FieldDeclaration f; - } - } - } - } - log("Altspos " + altStartPos); - } - /** * Finds the difference in pde and java code offsets * @param source From cee31ad2e155c9df53560428d9e24843b3dbe484 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 2 Mar 2014 20:40:42 +0530 Subject: [PATCH 035/115] working on autosave --- .../mode/experimental/ASTGenerator.java | 6 +- .../mode/experimental/AutoSaveUtil.java | 30 +++++++++- .../mode/experimental/DebugEditor.java | 59 +++++++++++++++---- .../experimental/ErrorCheckerService.java | 6 +- 4 files changed, 81 insertions(+), 20 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 1d2a052..9d74fd4 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -238,7 +238,7 @@ protected void setupGUI(){ /** * Toggle AST View window */ - public static final boolean SHOWAST = true; + public static final boolean SHOWAST = !true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { @@ -254,14 +254,14 @@ protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { compilationUnit = (CompilationUnit) parser.createAST(null); } else { compilationUnit = cu; - log("Other cu"); + //log("Other cu"); } // OutlineVisitor visitor = new OutlineVisitor(); // compilationUnit.accept(visitor); getCodeComments(); codeTree = new DefaultMutableTreeNode(new ASTNodeWrapper((ASTNode) compilationUnit .types().get(0))); - log("Total CU " + compilationUnit.types().size()); + //log("Total CU " + compilationUnit.types().size()); if(compilationUnit.types() == null || compilationUnit.types().isEmpty()){ logE("No CU found!"); } diff --git a/src/processing/mode/experimental/AutoSaveUtil.java b/src/processing/mode/experimental/AutoSaveUtil.java index 71b2245..d02f510 100644 --- a/src/processing/mode/experimental/AutoSaveUtil.java +++ b/src/processing/mode/experimental/AutoSaveUtil.java @@ -46,6 +46,10 @@ public class AutoSaveUtil { private boolean isSaving; + private boolean isAutoSaveBackup; + + private File sketchFolder, sketchBackupFolder; + /** * * @param dedit @@ -62,8 +66,18 @@ public AutoSaveUtil(DebugEditor dedit, int timeOut){ ExperimentalMode.log("AutoSaver Interval(mins): " + timeOut); } autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); + sketchFolder = editor.getSketch().getFolder(); + checkIfBackup(); } + private void checkIfBackup(){ + + } + + public boolean isAutoSaveBackup() { + return isAutoSaveBackup; + } + /** * Check if any previous autosave exists * @return @@ -73,6 +87,7 @@ public boolean checkForPastSave(){ String prevSaves[] = Base.listFiles(autosaveDir, false); if(prevSaves.length > 0){ File t = new File(Base.listFiles(new File(prevSaves[0]), false)[0]); + sketchBackupFolder = t; pastSave = new File(t.getAbsolutePath() + File.separator + t.getName() + ".pde"); if(pastSave.exists()) return true; @@ -89,6 +104,18 @@ public void reloadAutosaveDir(){ autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); } + /** + * The folder of the original sketch + * @return + */ + public File getSketchFolder(){ + return sketchFolder; + } + + public File getSketchBackupFolder(){ + return sketchBackupFolder; + } + public File getPastSave(){ return pastSave; } @@ -98,7 +125,7 @@ public File getPastSave(){ */ public void init(){ if(saveTime < 10000) saveTime = 10 * 1000; - //saveTime = 10 * 1000; //TODO: remove + saveTime = 5 * 1000; //TODO: remove timer = new Timer(); timer.schedule(new SaveTask(), saveTime, saveTime); isSaving = false; @@ -112,6 +139,7 @@ public void stop(){ while(isSaving); // save operation mustn't be interrupted if(timer != null) timer.cancel(); Base.removeDir(autosaveDir); + ExperimentalMode.log("Stopping autosaver and deleting backup dir"); } /** diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 02e698b..42e6d23 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -245,7 +245,10 @@ public void actionPerformed(ActionEvent e) { ta.setECSandThemeforTextArea(errorCheckerService, dmode); addXQModeUI(); debugToolbarEnabled = new AtomicBoolean(false); - log("Sketch Path: " + path); + //log("Sketch Path: " + path); + + viewingAutosaveBackup = false; + log("DebugEdit constructed. Viewing auto save false " + viewingAutosaveBackup); } private void addXQModeUI(){ @@ -342,7 +345,10 @@ public void dispose() { // Added temporarily to dump error log. TODO: Remove this later public void internalCloseRunner(){ if(ExperimentalMode.errorLogsEnabled) writeErrorsToFile(); - if(autosaver != null) autosaver.stop(); + if(autosaver != null && !viewingAutosaveBackup) { + log("stopping autosaver in internalCloseRunner"); + autosaver.stop(); + } super.internalCloseRunner(); } @@ -738,6 +744,7 @@ public void handleStop() { */ @Override protected boolean handleOpenInternal(String path) { + log("handleOpenInternal, path: " + path); boolean didOpen = super.handleOpenInternal(path); if (didOpen && dbg != null) { // should already been stopped (open calls handleStop) @@ -745,9 +752,16 @@ protected boolean handleOpenInternal(String path) { clearBreakpointedLines(); // force clear breakpoint highlights variableInspector().reset(); // clear contents of variable inspector } - if(autosaver != null) - autosaver.stop(); - loadAutoSaver(); + + if(!viewingAutosaveBackup){ + log("Sketch isn't a backup"); + if(autosaver != null){ + log("stopping autosaver in handleOpenInternal"); + autosaver.stop(); + } + loadAutoSaver(); + } + log("handleOpenInternal, viewing autosave? " + viewingAutosaveBackup); return didOpen; } @@ -825,7 +839,25 @@ protected void addBreakpointComments(String tabFilename) { @Override public boolean handleSave(boolean immediately) { //System.out.println("handleSave " + immediately); - + + log("handleSave, viewing autosave? " + viewingAutosaveBackup); + /* If user wants to save a backup, the backup sketch should get + * copied to the main sketch directory, simply reload the main sketch. + */ + if(viewingAutosaveBackup){ + File files[] = autosaver.getSketchBackupFolder().listFiles(); + File src = autosaver.getSketchBackupFolder(), dst = autosaver + .getSketchFolder(); + for (File f : files) { + log("Copying " + f.getAbsolutePath() + " to " + dst.getAbsolutePath()); +// if(f.isFile()) + //Base.copyFile(f, new File(dst + File.separator + f.getName())); +// else +// Base.copyDir(f, new File(dst + File.separator + f.getName())); + } + //viewingAutosaveBackup = false; + } + // note modified tabs final List modified = new ArrayList(); for (int i = 0; i < getSketch().getCodeCount(); i++) { @@ -887,6 +919,8 @@ public boolean handleSaveAs() { return saved; } + private boolean viewingAutosaveBackup; + /** * Loads and starts the auto save service * Also handles the case where an auto save backup is found. @@ -894,15 +928,12 @@ public boolean handleSaveAs() { */ public void loadAutoSaver(){ log("Load Auto Saver()"); - if(autosaver != null){ - autosaver.stop(); - } - autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); + autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); if(!autosaver.checkForPastSave()) { autosaver.init(); return; } - + if(viewingAutosaveBackup) return; File pastSave = autosaver.getPastSave(); int response = Base .showYesNoQuestion(this, @@ -913,9 +944,11 @@ public void loadAutoSaver(){ "was closed unexpectedly last time.", "Select YES to view it or NO to delete the backup."); if(response == JOptionPane.YES_OPTION){ - handleOpenInternal(pastSave.getAbsolutePath()); - Base.showMessage("Save it..", "Remember to save the backup sketch to a specific location if you want to."); + viewingAutosaveBackup = true; + handleOpenInternal(pastSave.getAbsolutePath()); + // Base.showMessage("Save it..", "Remember to save the backup sketch to a specific location if you want to."); //log(getSketch().getMainFilePath()); + log("loadAutoSaver, viewing autosave? " + viewingAutosaveBackup); return; } else{ diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index 89f6538..e855a33 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -1387,9 +1387,9 @@ public static boolean scrollToErrorLine(Editor edt, int tabIndex, int lineNoInTa * compiler classpath needs to be updated. */ protected void checkForChangedImports() { - log("Imports: " + programImports.size() + - " Prev Imp: " - + previousImports.size()); +// log("Imports: " + programImports.size() + +// " Prev Imp: " +// + previousImports.size()); if (programImports.size() != previousImports.size()) { // log(1); loadCompClass = true; From 25f9db0edb75442288ff762d63bfa0dae2ccf639 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 2 Mar 2014 21:44:29 +0530 Subject: [PATCH 036/115] now going around in circles with autosave --- .../mode/experimental/AutoSaveUtil.java | 47 ++++++++++++++++--- .../mode/experimental/DebugEditor.java | 44 +++++++++-------- 2 files changed, 64 insertions(+), 27 deletions(-) diff --git a/src/processing/mode/experimental/AutoSaveUtil.java b/src/processing/mode/experimental/AutoSaveUtil.java index d02f510..3141ed6 100644 --- a/src/processing/mode/experimental/AutoSaveUtil.java +++ b/src/processing/mode/experimental/AutoSaveUtil.java @@ -27,6 +27,8 @@ import processing.app.Base; import processing.app.Sketch; +import static processing.mode.experimental.ExperimentalMode.log; + /** * Autosave utility for saving sketch backups in the background after * certain intervals @@ -50,6 +52,8 @@ public class AutoSaveUtil { private File sketchFolder, sketchBackupFolder; + private static final String AUTOSAVEFOLDER = "__autosave__"; + /** * * @param dedit @@ -63,15 +67,36 @@ public AutoSaveUtil(DebugEditor dedit, int timeOut){ } else{ saveTime = timeOut * 60 * 1000; - ExperimentalMode.log("AutoSaver Interval(mins): " + timeOut); + log("AutoSaver Interval(mins): " + timeOut); } - autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); - sketchFolder = editor.getSketch().getFolder(); checkIfBackup(); + if(isAutoSaveBackup){ + sketchBackupFolder = sketchFolder; + } + else{ + autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + AUTOSAVEFOLDER); + sketchFolder = editor.getSketch().getFolder(); + sketchBackupFolder = autosaveDir; + } } + /** + * If the sketch path looks like ../__autosave__/../FooSketch + * then assume this is a backup sketch + */ private void checkIfBackup(){ - + File parent = sketchFolder.getParentFile().getParentFile(); + if(parent.isDirectory() && parent.getName().equals(AUTOSAVEFOLDER)){ + isAutoSaveBackup = true; + log("IS AUTOSAVE " + sketchFolder.getAbsolutePath()); + } + } + + public File getActualSketchFolder(){ + if(isAutoSaveBackup) + return sketchFolder.getParentFile().getParentFile().getParentFile(); + else + return sketchFolder; } public boolean isAutoSaveBackup() { @@ -101,7 +126,11 @@ public boolean checkForPastSave(){ */ public void reloadAutosaveDir(){ while(isSaving); - autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); + autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + AUTOSAVEFOLDER); + } + + public File getAutoSaveDir(){ + return autosaveDir; } /** @@ -124,12 +153,16 @@ public File getPastSave(){ * Start the auto save service */ public void init(){ + if(isAutoSaveBackup) { + log("AutoSaver not started"); + return; + } if(saveTime < 10000) saveTime = 10 * 1000; saveTime = 5 * 1000; //TODO: remove timer = new Timer(); timer.schedule(new SaveTask(), saveTime, saveTime); isSaving = false; - ExperimentalMode.log("AutoSaver started"); + log("AutoSaver started"); } /** @@ -156,7 +189,7 @@ private boolean saveSketch() throws IOException{ boolean deleteOldSave = false; String oldSave = null; if(!autosaveDir.exists()){ - autosaveDir = new File(sc.getFolder().getAbsolutePath(), "_autosave"); + autosaveDir = new File(sc.getFolder().getAbsolutePath(), AUTOSAVEFOLDER); autosaveDir.mkdir(); } else diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 42e6d23..ee47350 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -246,9 +246,6 @@ public void actionPerformed(ActionEvent e) { addXQModeUI(); debugToolbarEnabled = new AtomicBoolean(false); //log("Sketch Path: " + path); - - viewingAutosaveBackup = false; - log("DebugEdit constructed. Viewing auto save false " + viewingAutosaveBackup); } private void addXQModeUI(){ @@ -744,7 +741,7 @@ public void handleStop() { */ @Override protected boolean handleOpenInternal(String path) { - log("handleOpenInternal, path: " + path); + log("handleOpenInternal, path: " + path); boolean didOpen = super.handleOpenInternal(path); if (didOpen && dbg != null) { // should already been stopped (open calls handleStop) @@ -752,16 +749,12 @@ protected boolean handleOpenInternal(String path) { clearBreakpointedLines(); // force clear breakpoint highlights variableInspector().reset(); // clear contents of variable inspector } - - if(!viewingAutosaveBackup){ - log("Sketch isn't a backup"); - if(autosaver != null){ - log("stopping autosaver in handleOpenInternal"); - autosaver.stop(); - } + //if(didOpen){ + loadAutoSaver(); - } - log("handleOpenInternal, viewing autosave? " + viewingAutosaveBackup); + viewingAutosaveBackup = autosaver.isAutoSaveBackup(); + log("handleOpenInternal, viewing autosave? " + viewingAutosaveBackup); + //} return didOpen; } @@ -845,17 +838,30 @@ public boolean handleSave(boolean immediately) { * copied to the main sketch directory, simply reload the main sketch. */ if(viewingAutosaveBackup){ + /* File files[] = autosaver.getSketchBackupFolder().listFiles(); File src = autosaver.getSketchBackupFolder(), dst = autosaver - .getSketchFolder(); + .getActualSketchFolder(); for (File f : files) { log("Copying " + f.getAbsolutePath() + " to " + dst.getAbsolutePath()); -// if(f.isFile()) - //Base.copyFile(f, new File(dst + File.separator + f.getName())); -// else -// Base.copyDir(f, new File(dst + File.separator + f.getName())); + try { + if (f.isFile()) { + f.delete(); + Base.copyFile(f, new File(dst + File.separator + f.getName())); + } else { + Base.removeDir(f); + Base.copyDir(f, new File(dst + File.separator + f.getName())); + } + } catch (IOException e) { + e.printStackTrace(); + } } + File sk = autosaver.getActualSketchFolder(); + Base.removeDir(autosaver.getAutoSaveDir()); + //handleOpenInternal(sk.getAbsolutePath() + File.separator + sk.getName() + ".pde"); + getBase().handleOpen(sk.getAbsolutePath() + File.separator + sk.getName() + ".pde"); //viewingAutosaveBackup = false; + */ } // note modified tabs @@ -933,7 +939,6 @@ public void loadAutoSaver(){ autosaver.init(); return; } - if(viewingAutosaveBackup) return; File pastSave = autosaver.getPastSave(); int response = Base .showYesNoQuestion(this, @@ -944,7 +949,6 @@ public void loadAutoSaver(){ "was closed unexpectedly last time.", "Select YES to view it or NO to delete the backup."); if(response == JOptionPane.YES_OPTION){ - viewingAutosaveBackup = true; handleOpenInternal(pastSave.getAbsolutePath()); // Base.showMessage("Save it..", "Remember to save the backup sketch to a specific location if you want to."); //log(getSketch().getMainFilePath()); From ad872d109a0bab22b8f8c7ac04551ccdebd80749 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 19 Mar 2014 13:50:50 +0530 Subject: [PATCH 037/115] diabling auto save, switching focus on other stuff for now --- src/processing/mode/experimental/AutoSaveUtil.java | 5 ++++- src/processing/mode/experimental/DebugEditor.java | 14 +++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/processing/mode/experimental/AutoSaveUtil.java b/src/processing/mode/experimental/AutoSaveUtil.java index 3141ed6..7efa14e 100644 --- a/src/processing/mode/experimental/AutoSaveUtil.java +++ b/src/processing/mode/experimental/AutoSaveUtil.java @@ -60,6 +60,7 @@ public class AutoSaveUtil { * @param timeOut - in minutes, how frequently should saves occur */ public AutoSaveUtil(DebugEditor dedit, int timeOut){ + /* editor = dedit; if (timeOut < 1) { // less than 1 minute not allowed! saveTime = -1; @@ -77,7 +78,7 @@ public AutoSaveUtil(DebugEditor dedit, int timeOut){ autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + AUTOSAVEFOLDER); sketchFolder = editor.getSketch().getFolder(); sketchBackupFolder = autosaveDir; - } + }*/ } /** @@ -153,6 +154,7 @@ public File getPastSave(){ * Start the auto save service */ public void init(){ + /* if(isAutoSaveBackup) { log("AutoSaver not started"); return; @@ -163,6 +165,7 @@ public void init(){ timer.schedule(new SaveTask(), saveTime, saveTime); isSaving = false; log("AutoSaver started"); + */ } /** diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index ee47350..20206c1 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -342,10 +342,10 @@ public void dispose() { // Added temporarily to dump error log. TODO: Remove this later public void internalCloseRunner(){ if(ExperimentalMode.errorLogsEnabled) writeErrorsToFile(); - if(autosaver != null && !viewingAutosaveBackup) { - log("stopping autosaver in internalCloseRunner"); - autosaver.stop(); - } +// if(autosaver != null && !viewingAutosaveBackup) { +// log("stopping autosaver in internalCloseRunner"); +// autosaver.stop(); +// } super.internalCloseRunner(); } @@ -750,8 +750,8 @@ protected boolean handleOpenInternal(String path) { variableInspector().reset(); // clear contents of variable inspector } //if(didOpen){ - - loadAutoSaver(); + autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); // this is used instead of loadAutosaver(), temp measure + //loadAutoSaver(); viewingAutosaveBackup = autosaver.isAutoSaveBackup(); log("handleOpenInternal, viewing autosave? " + viewingAutosaveBackup); //} @@ -932,7 +932,7 @@ public boolean handleSaveAs() { * Also handles the case where an auto save backup is found. * The user is asked to save the sketch to a new location */ - public void loadAutoSaver(){ + private void loadAutoSaver(){ log("Load Auto Saver()"); autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); if(!autosaver.checkForPastSave()) { From 651e5c06e28ebf087d35bf5f4a325d074691946d Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 19 Mar 2014 23:48:05 +0530 Subject: [PATCH 038/115] fixes #45, application export --- application/Info.plist.tmpl | 3 +-- .../template.app/Contents/MacOS/JavaApplicationStub | Bin application/template.app/Contents/PkgInfo | 0 application/template.exe | Bin application/template.plist | 0 5 files changed, 1 insertion(+), 2 deletions(-) mode change 100644 => 100755 application/template.app/Contents/MacOS/JavaApplicationStub mode change 100644 => 100755 application/template.app/Contents/PkgInfo mode change 100644 => 100755 application/template.exe mode change 100644 => 100755 application/template.plist diff --git a/application/Info.plist.tmpl b/application/Info.plist.tmpl index 787f56e..28a2e02 100644 --- a/application/Info.plist.tmpl +++ b/application/Info.plist.tmpl @@ -32,8 +32,7 @@ Created with Processing - JVMRuntime - @@jdk_folder@@ + @@jvm_runtime@@ JVMMainClassName @@sketch@@ diff --git a/application/template.app/Contents/MacOS/JavaApplicationStub b/application/template.app/Contents/MacOS/JavaApplicationStub old mode 100644 new mode 100755 diff --git a/application/template.app/Contents/PkgInfo b/application/template.app/Contents/PkgInfo old mode 100644 new mode 100755 diff --git a/application/template.exe b/application/template.exe old mode 100644 new mode 100755 diff --git a/application/template.plist b/application/template.plist old mode 100644 new mode 100755 From e025d77d433e02b42002224b04ae404e576ab24f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 26 Mar 2014 19:31:48 +0530 Subject: [PATCH 039/115] trying to look into the breakpoint issue --- src/processing/mode/experimental/DebugEditor.java | 2 +- src/processing/mode/experimental/LineBreakpoint.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 20206c1..3e4041e 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -891,7 +891,7 @@ public void run() { } } // if file location has changed, update autosaver - autosaver.reloadAutosaveDir(); + // autosaver.reloadAutosaveDir(); return saved; } diff --git a/src/processing/mode/experimental/LineBreakpoint.java b/src/processing/mode/experimental/LineBreakpoint.java index 8d006fd..931ea9b 100755 --- a/src/processing/mode/experimental/LineBreakpoint.java +++ b/src/processing/mode/experimental/LineBreakpoint.java @@ -53,6 +53,7 @@ public LineBreakpoint(LineID line, Debugger dbg) { this.dbg = dbg; theClass = dbg.getClass(className()); // try to get the class immediately, may return null if not yet loaded set(); // activate the breakpoint (show highlight, attach if debugger is running) + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.INFO, "LBP Created " +toString() + " class: " + theClass, new Object[]{}); } /** @@ -108,6 +109,7 @@ protected void attach() { return; } try { + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "BPs of class: {0}", new Object[]{theClass}); List locations = theClass.locationsOfLine(javaLine.lineIdx() + 1); if (locations.isEmpty()) { Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "no location found for line {0} -> {1}", new Object[]{line, javaLine}); From 596897490c094b5d5d7674d9f4b1f3d670b9b1a3 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 30 Mar 2014 02:35:07 +0530 Subject: [PATCH 040/115] wasn't too tough after all.. Fixes #51 --- src/processing/mode/experimental/ASTGenerator.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 9d74fd4..9392fcb 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1618,7 +1618,13 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, log("FLON3 "+lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); ASTNode simpName = pinpointOnLine(lineNode, altOff, lineNode.getStartPosition(), name); - log("+++> " + simpName); + + if(simpName == null){ //Added while fixing #51 + log("1+++> " + simpName); + simpName = pinpointOnLine(lineNode.getParent(), altOff, + lineNode.getStartPosition(), name); + } + log("2+++> " + simpName); if (simpName instanceof SimpleName) { nameOfNode = simpName.toString(); From f5b4b82e04901dde3d2805f94accd22f25ce757f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 30 Mar 2014 03:08:46 +0530 Subject: [PATCH 041/115] right click on classes with javadoc, related to #51 --- .../mode/experimental/ASTGenerator.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 9392fcb..325a98b 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -238,7 +238,7 @@ protected void setupGUI(){ /** * Toggle AST View window */ - public static final boolean SHOWAST = !true; + public static final boolean SHOWAST = true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { @@ -1625,6 +1625,21 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, lineNode.getStartPosition(), name); } log("2+++> " + simpName); + if(simpName == null && lineNode instanceof SimpleName){ + switch (lineNode.getParent().getNodeType()) { + case ASTNode.TYPE_DECLARATION: + + case ASTNode.METHOD_DECLARATION: + + case ASTNode.FIELD_DECLARATION: + + case ASTNode.VARIABLE_DECLARATION_FRAGMENT: + decl = lineNode.getParent(); + return new ASTNodeWrapper(decl,""); + default: + break; + } + } if (simpName instanceof SimpleName) { nameOfNode = simpName.toString(); @@ -2339,7 +2354,7 @@ public static ASTNode pinpointOnLine(ASTNode node, int offset, if (node instanceof SimpleName) { SimpleName sn = (SimpleName) node; - log(offset+ "off,pol " + getNodeAsString(sn)); + //log(offset+ "off,pol " + getNodeAsString(sn)); if ((lineStartOffset + offset) >= sn.getStartPosition() && (lineStartOffset + offset) <= sn.getStartPosition() + sn.getLength()) { From 04d02057cd9eaeeaef8d3ab4fbdc61523813f3b6 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 1 Apr 2014 18:30:30 +0530 Subject: [PATCH 042/115] Fixes #45 for ever and ever --- src/processing/mode/experimental/ExperimentalMode.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/processing/mode/experimental/ExperimentalMode.java b/src/processing/mode/experimental/ExperimentalMode.java index a756700..5b04896 100755 --- a/src/processing/mode/experimental/ExperimentalMode.java +++ b/src/processing/mode/experimental/ExperimentalMode.java @@ -117,6 +117,15 @@ public File[] getKeywordFiles() { }; } + public File getContentFile(String path) { + // workaround for #45 + if (path.startsWith("application" + File.separator)) { + return new File(Base.getContentFile("modes" + File.separator + "java") + .getAbsolutePath() + File.separator + path); + } + return new File(folder, path); + } + volatile public static boolean errorCheckEnabled = true, warningsEnabled = true, codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false; public static int autoSaveInterval = 3; //in minutes From 2dc6ee6d8d7a22f6b0f072d25bf92f963e8e5759 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 1 Apr 2014 19:35:14 +0530 Subject: [PATCH 043/115] Javadocs suck. Screwing the balance everywhere >.< --- .../mode/experimental/ASTNodeWrapper.java | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index 6c6cbc6..eb35e22 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -202,6 +202,9 @@ public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { } /** + * When FD has javadoc attached, the beginning of FD is marked as the + * start of the javadoc. This kind of screws things when trying to locate + * the exact name of the FD. So, offset compensations... * * @param fd * @return @@ -232,6 +235,14 @@ private int getJavadocOffset(FieldDeclaration fd){ return 0; } + /** + * When MD has javadoc attached, the beginning of FD is marked as the + * start of the javadoc. This kind of screws things when trying to locate + * the exact name of the MD. So, offset compensations... + * + * @param md + * @return + */ private int getJavadocOffset(MethodDeclaration md) { List list = md.modifiers(); SimpleName sn = (SimpleName) getNode(); @@ -258,8 +269,16 @@ private int getJavadocOffset(MethodDeclaration md) { return 0; } + /** + * When TD has javadoc attached, the beginning of FD is marked as the + * start of the javadoc. This kind of screws things when trying to locate + * the exact name of the TD. So, offset compensations... + * + * @param td + * @return + */ private int getJavadocOffset(TypeDeclaration td){ - // TODO: This is still broken. Hence no refactoring or highlighting on scroll works :\ + // TODO: This isn't perfect yet. Class \n \n \n className still breaks it.. :'( List list= td.modifiers(); list = td.modifiers(); SimpleName sn = (SimpleName) getNode(); @@ -275,7 +294,13 @@ private int getJavadocOffset(TypeDeclaration td){ } } - return 0; + if(td.getJavadoc() != null){ + log("diff " + + (td.getJavadoc().getStartPosition() + td.getJavadoc().getLength() + 1)); + return (td.getJavadoc().getStartPosition() + td.getJavadoc().getLength() + 1); + } + log("getJavadocOffset(TypeDeclaration td) "+sn + ", found nothing. Meh."); + return 0; } /** From c842212b20dbb540008ac5951ceada7188d0dfa5 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 1 Apr 2014 19:59:52 +0530 Subject: [PATCH 044/115] This minor change was long due. --- .../mode/experimental/ErrorCheckerService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index e855a33..78af0fb 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -511,7 +511,7 @@ protected void syntaxCheck() { // Populate the probList problemsList = new ArrayList(); for (int i = 0; i < problems.length; i++) { - int a[] = calculateTabIndexAndLineNumber(problems[i]); + int a[] = calculateTabIndexAndLineNumber(problems[i].getSourceLineNumber()); Problem p = new Problem(problems[i], a[0], a[1] + 1); //TODO: ^Why do cheeky stuff? problemsList.add(p); @@ -642,7 +642,7 @@ public boolean accept(File file) { // for (String j : problem.getArguments()) { // log("arg " + j); // } - int a[] = calculateTabIndexAndLineNumber(problem); + int a[] = calculateTabIndexAndLineNumber(problem.getSourceLineNumber()); Problem p = new Problem(problem, a[0], a[1]); if ((Boolean) errorList[i][8]) { p.setType(Problem.ERROR); @@ -1055,16 +1055,16 @@ public String getPDECodeAtLine(int tab, int linenumber){ * - IProblem * @return int[0] - tab number, int[1] - line number */ - public int[] calculateTabIndexAndLineNumber(IProblem problem) { + public int[] calculateTabIndexAndLineNumber(int javalineNumber) { // String[] lines = {};// = PApplet.split(sourceString, '\n'); int codeIndex = 0; - int x = problem.getSourceLineNumber() - mainClassOffset; + int x = javalineNumber - mainClassOffset; if (x < 0) { // log("Negative line number " // + problem.getSourceLineNumber() + " , offset " // + mainClassOffset); - x = problem.getSourceLineNumber() - 2; // Another -1 for 0 index + x = javalineNumber - 2; // Another -1 for 0 index if (x < programImports.size() && x >= 0) { ImportStatement is = programImports.get(x); // log(is.importName + ", " + is.tab + ", " From e965f73725f784d6971391535d6fa328e5c6826e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 5 Apr 2014 01:23:08 +0530 Subject: [PATCH 045/115] Further work on highlighting issue --- .../mode/experimental/ASTGenerator.java | 7 +- .../mode/experimental/ASTNodeWrapper.java | 76 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 325a98b..8a58ae2 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1678,7 +1678,12 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, ASTNode simpName2 = getNodeName(decl,nameOfNode); logE("FINAL String decl: " + getNodeAsString(decl)); logE("FINAL String label: " + getNodeAsString(simpName2)); - errorCheckerService.highlightNode(simpName2); + //errorCheckerService.highlightNode(simpName2); + ASTNodeWrapper declWrap = new ASTNodeWrapper(simpName2,nodeLabel); + errorCheckerService.highlightNode(declWrap); +// if (!declWrap.highlightNode(this)) { +// logE("Highlighting failed."); +// } } return new ASTNodeWrapper(decl,nodeLabel); diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index eb35e22..3ad8bb1 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -18,6 +18,7 @@ package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; +import static processing.mode.experimental.ExperimentalMode.logE; import static processing.mode.experimental.ExperimentalMode.log2; import java.util.Iterator; import java.util.List; @@ -25,6 +26,10 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.swing.text.BadLocationException; +import javax.swing.text.Element; +import javax.swing.text.PlainDocument; + import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.ExpressionStatement; @@ -516,6 +521,77 @@ public int[][] getOffsetMapping(String source){ return new int[][]{javaCodeMap,pdeCodeMap}; } + public boolean highlightNode(ASTGenerator astGenerator){ + if(!(Node instanceof SimpleName)){ + return false; + } + SimpleName nodeName = (SimpleName) Node; + try { + int javaLineNumber = getLineNumber(nodeName); + int pdeOffs[] = astGenerator.errorCheckerService + .calculateTabIndexAndLineNumber(javaLineNumber); + PlainDocument javaSource = new PlainDocument(); + javaSource.insertString(0, astGenerator.errorCheckerService.sourceCode, null); + Element lineElement = javaSource.getDefaultRootElement() + .getElement(javaLineNumber-1); + if(lineElement == null) { + log(lineNumber + " line element null while highlighting " + nodeName); + return false; + } + + String javaLine = javaSource.getText(lineElement.getStartOffset(), + lineElement.getEndOffset() + - lineElement.getStartOffset()); + astGenerator.editor.getSketch().setCurrentCode(pdeOffs[0]); + String pdeLine = astGenerator.editor.getLineText(pdeOffs[1]); + String lookingFor = nodeName.toString(); + log(lookingFor + ", " + nodeName.getStartPosition()); + log("JL " + javaLine + " LSO " + lineElement.getStartOffset() + "," + + lineElement.getEndOffset()); + log("PL " + pdeLine); + if (!javaLine.contains(lookingFor) || !pdeLine.contains(lookingFor)) { + logE("Logical error in highLightNode(). Please file a bug report."); + return false; + } + Pattern toFind = Pattern.compile("\\b" + nodeName.toString() + "\\b"); + Matcher matcher = toFind.matcher(javaLine); + int lsto = lineElement.getStartOffset(); + while(matcher.find()){ + System.out.println(matcher.start() + lsto); + } + // find the count of the name in the java code + int count = 0, index = 0; + do { + index = javaLine.indexOf(lookingFor, index); + if (index != -1) { + count++; + index += lookingFor.length(); + } else + break; + } while (true); + log("count=" + count); + // find the offset of the name of that index in the pde code + index = 0; + while (count > 0) { + index = pdeLine.indexOf(lookingFor, index); + if (index != -1) { + count--; + index += lookingFor.length(); + } + } + log("pde lso " + (index - lookingFor.length())); + + int lso = astGenerator.editor.ta.getLineStartOffset(pdeOffs[1]); + astGenerator.editor.setSelection(lso + index - lookingFor.length(), lso + + index); + return true; + } catch (BadLocationException e) { + logE("BLE in highLightNode() for " + nodeName); + e.printStackTrace(); + } + return false; + } + /** * Gets offset mapping between java and pde code * int[0][x] stores the java code offset and From f8bcab9568f771b0428e26dc9ee393016d31a241 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 5 Apr 2014 02:14:41 +0530 Subject: [PATCH 046/115] does it work? Or does it not? idk --- .../mode/experimental/ASTGenerator.java | 38 +++++++++++++++++-- .../mode/experimental/ASTNodeWrapper.java | 26 +++++++------ .../experimental/ErrorCheckerService.java | 23 ++++++++++- 3 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 8a58ae2..1188b76 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -53,6 +53,8 @@ import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.text.BadLocationException; +import javax.swing.text.Element; +import javax.swing.text.PlainDocument; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.MutableTreeNode; @@ -1680,10 +1682,10 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, logE("FINAL String label: " + getNodeAsString(simpName2)); //errorCheckerService.highlightNode(simpName2); ASTNodeWrapper declWrap = new ASTNodeWrapper(simpName2,nodeLabel); - errorCheckerService.highlightNode(declWrap); -// if (!declWrap.highlightNode(this)) { -// logE("Highlighting failed."); -// } + //errorCheckerService.highlightNode(declWrap); + if (!declWrap.highlightNode(this)) { + logE("Highlighting failed."); + } } return new ASTNodeWrapper(decl,nodeLabel); @@ -1812,6 +1814,34 @@ protected void done() { if (tnode.getUserObject() instanceof ASTNodeWrapper) { ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); errorCheckerService.highlightNode(awrap); + + //-- + try { + int javaLineNumber = getLineNumber(awrap.getNode()); + int pdeOffs[] = errorCheckerService + .calculateTabIndexAndLineNumber(javaLineNumber); + PlainDocument javaSource = new PlainDocument(); + javaSource.insertString(0, errorCheckerService.sourceCode, null); + Element lineElement = javaSource.getDefaultRootElement() + .getElement(javaLineNumber-1); + if(lineElement == null) { + return; + } + + String javaLine = javaSource.getText(lineElement.getStartOffset(), + lineElement.getEndOffset() + - lineElement.getStartOffset()); + editor.getSketch().setCurrentCode(pdeOffs[0]); + String pdeLine = editor.getLineText(pdeOffs[1]); + //String lookingFor = nodeName.toString(); + //log(lookingFor + ", " + nodeName.getStartPosition()); + log("JL " + javaLine + " LSO " + lineElement.getStartOffset() + "," + + lineElement.getEndOffset()); + log("PL " + pdeLine); + } catch (BadLocationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } } }; diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index 3ad8bb1..c0cb491 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -546,29 +546,33 @@ public boolean highlightNode(ASTGenerator astGenerator){ String pdeLine = astGenerator.editor.getLineText(pdeOffs[1]); String lookingFor = nodeName.toString(); log(lookingFor + ", " + nodeName.getStartPosition()); - log("JL " + javaLine + " LSO " + lineElement.getStartOffset() + "," + log(javaLineNumber +" JL " + javaLine + " LSO " + lineElement.getStartOffset() + "," + lineElement.getEndOffset()); - log("PL " + pdeLine); + log(pdeOffs[1] + " PL " + pdeLine); if (!javaLine.contains(lookingFor) || !pdeLine.contains(lookingFor)) { logE("Logical error in highLightNode(). Please file a bug report."); return false; } Pattern toFind = Pattern.compile("\\b" + nodeName.toString() + "\\b"); Matcher matcher = toFind.matcher(javaLine); + int count = 0, index = 0; int lsto = lineElement.getStartOffset(); while(matcher.find()){ + count++; System.out.println(matcher.start() + lsto); + if(lsto + matcher.start() == nodeName.getStartPosition()) + break; } // find the count of the name in the java code - int count = 0, index = 0; - do { - index = javaLine.indexOf(lookingFor, index); - if (index != -1) { - count++; - index += lookingFor.length(); - } else - break; - } while (true); + +// do { +// index = javaLine.indexOf(lookingFor, index); +// if (index != -1) { +// count++; +// index += lookingFor.length(); +// } else +// break; +// } while (true); log("count=" + count); // find the offset of the name of that index in the pde code index = 0; diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index 78af0fb..9a50c20 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -434,7 +434,7 @@ protected boolean checkCode() { // log(sourceCode); // log("--------------------------"); compileCheck(); - astGenerator.buildAST(cu); + //astGenerator.buildAST(cu); log(editor.getSketch().getName() + "2 MCO " + mainClassOffset); } @@ -535,6 +535,27 @@ protected void syntaxCheck() { protected URLClassLoader classLoader; protected void compileCheck() { + + // CU needs to be updated coz before compileCheck xqpreprocessor is run on the source code which makes some further changes + //TODO Check if this breaks things + + parser.setSource(sourceCode.toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + + Map options = JavaCore.getOptions(); + + JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); + options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + options.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED); + parser.setCompilerOptions(options); + + if (cu == null) + cu = (CompilationUnit) parser.createAST(null); + else { + synchronized (cu) { + cu = (CompilationUnit) parser.createAST(null); + } + } // Currently (Sept, 2012) I'm using Java's reflection api to load the // CompilationChecker class(from CompilationChecker.jar) that houses the From d0ddf3992498c61b136ed35a10ba262505eeaf4f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 5 Apr 2014 02:27:29 +0530 Subject: [PATCH 047/115] I guess this is the best that can be done.. --- src/processing/mode/experimental/ErrorCheckerService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index 9a50c20..4544b8e 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -433,11 +433,11 @@ protected boolean checkCode() { // } // log(sourceCode); // log("--------------------------"); - compileCheck(); - //astGenerator.buildAST(cu); + compileCheck(); log(editor.getSketch().getName() + "2 MCO " + mainClassOffset); } + astGenerator.buildAST(cu); if(ExperimentalMode.errorCheckEnabled){ updateErrorTable(); editor.updateErrorBar(problemsList); From 72ecf76fae393e231be0594426064103dd82df6e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 15 Apr 2014 02:28:39 +0530 Subject: [PATCH 048/115] Fixes #53 --- src/processing/mode/experimental/ErrorCheckerService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index 4544b8e..00a5501 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -53,6 +53,7 @@ import processing.app.Base; import processing.app.Editor; +import processing.app.EditorStatus; import processing.app.Library; import processing.app.SketchCode; import processing.app.syntax.SyntaxDocument; @@ -947,12 +948,16 @@ public void updatePaintedThingys() { } } + protected int lastCaretLine = -1; + /** * Updates editor status bar, depending on whether the caret is on an error * line or not */ public void updateEditorStatus() { + + if(editor.getStatusMode() == EditorStatus.EDIT) return; // editor.statusNotice("Position: " + // editor.getTextArea().getCaretLine()); if(ExperimentalMode.errorCheckEnabled) From d286aff8326484b45a78cad73553787f18d1ad53 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 15 Apr 2014 02:39:12 +0530 Subject: [PATCH 049/115] Fixes #29 --- .../mode/experimental/ErrorCheckerService.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index 00a5501..c422d33 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -978,10 +978,17 @@ public void updateEditorStatus() { } } } - if (editor.ta.getCaretLine() != lastCaretLine) { + + // This line isn't an error line anymore, so probably just clear it + if (editor.getStatusMode() == EditorStatus.ERR + || editor.getStatusMode() == EditorStatus.NOTICE) { editor.statusEmpty(); - lastCaretLine = editor.ta.getCaretLine(); + return; } +// if (editor.ta.getCaretLine() != lastCaretLine) { +// editor.statusEmpty(); +// lastCaretLine = editor.ta.getCaretLine(); +// } } /** From f288802233cf26a9586979b7f06e4c4eeb5a9677 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 15 Apr 2014 12:28:47 +0530 Subject: [PATCH 050/115] a bit of code cleanup --- .../mode/experimental/ASTGenerator.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 1188b76..ff3709c 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -240,7 +240,7 @@ protected void setupGUI(){ /** * Toggle AST View window */ - public static final boolean SHOWAST = true; + public static final boolean SHOWAST = !true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { @@ -3239,17 +3239,16 @@ public void actionPerformed(ActionEvent e) { } - public void disposeAllWindows(){ - disposeWindow(frmASTView); - disposeWindow(frameAutoComp); - disposeWindow(frmImportSuggest); - disposeWindow(frmOccurenceList); - disposeWindow(frmRename); + public void disposeAllWindows() { + disposeWindow(frmASTView, frameAutoComp, frmImportSuggest, + frmOccurenceList, frmRename); } - public static void disposeWindow(JFrame f) { - if(f != null) - f.dispose(); + public static void disposeWindow(JFrame... f) { + for (JFrame jFrame : f) { + if(jFrame != null) + jFrame.dispose(); + } } public static final String ignoredImports[] = { From 7a09ebf20dab11169a214a1e9955b6a3117b2734 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 19 Apr 2014 23:22:14 +0530 Subject: [PATCH 051/115] Found another bug in refactoring --- .../mode/experimental/ASTNodeWrapper.java | 2 ++ .../mode/experimental/LineBreakpoint.java | 13 +++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index c0cb491..2536e78 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -553,6 +553,7 @@ public boolean highlightNode(ASTGenerator astGenerator){ logE("Logical error in highLightNode(). Please file a bug report."); return false; } + //TODO: Asteriods example. Spaceship ship; wrong highlight Pattern toFind = Pattern.compile("\\b" + nodeName.toString() + "\\b"); Matcher matcher = toFind.matcher(javaLine); int count = 0, index = 0; @@ -583,6 +584,7 @@ public boolean highlightNode(ASTGenerator astGenerator){ index += lookingFor.length(); } } + log("pde lso " + (index - lookingFor.length())); int lso = astGenerator.editor.ta.getLineStartOffset(pdeOffs[1]); diff --git a/src/processing/mode/experimental/LineBreakpoint.java b/src/processing/mode/experimental/LineBreakpoint.java index 931ea9b..e35cea2 100755 --- a/src/processing/mode/experimental/LineBreakpoint.java +++ b/src/processing/mode/experimental/LineBreakpoint.java @@ -25,6 +25,10 @@ import java.util.logging.Level; import java.util.logging.Logger; +import static processing.mode.experimental.ExperimentalMode.log; +import static processing.mode.experimental.ExperimentalMode.logE; +import static processing.mode.experimental.ExperimentalMode.log2; + /** * Model/Controller of a line breakpoint. Can be set before or while debugging. * Adds a highlight using the debuggers view ({@link DebugEditor}). @@ -53,7 +57,7 @@ public LineBreakpoint(LineID line, Debugger dbg) { this.dbg = dbg; theClass = dbg.getClass(className()); // try to get the class immediately, may return null if not yet loaded set(); // activate the breakpoint (show highlight, attach if debugger is running) - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.INFO, "LBP Created " +toString() + " class: " + theClass, new Object[]{}); + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.INFO, "LBP Created " +toString() + " class: " + className(), new Object[]{}); } /** @@ -109,7 +113,7 @@ protected void attach() { return; } try { - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "BPs of class: {0}", new Object[]{theClass}); + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "BPs of class: {0} , line " + (javaLine.lineIdx() + 1), new Object[]{theClass}); List locations = theClass.locationsOfLine(javaLine.lineIdx() + 1); if (locations.isEmpty()) { Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "no location found for line {0} -> {1}", new Object[]{line, javaLine}); @@ -189,6 +193,7 @@ protected String className() { if (line.fileName().endsWith(".pde")) { // standard tab ReferenceType mainClass = dbg.getMainClass(); + //System.out.println(dbg.getMainClass().name()); if (mainClass == null) { return null; } @@ -212,9 +217,13 @@ protected String className() { @Override public void classLoaded(ReferenceType theClass) { // check if our class is being loaded + log("Class Loaded: " + theClass.name()); if (theClass.name().equals(className())) { this.theClass = theClass; attach(); } + for (ReferenceType ct : theClass.nestedTypes()) { + log("Nested " + ct.name()); + } } } From dfbfa580f67f624d9b7c68fca0bb6fc0991ccd98 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 19 Apr 2014 23:27:43 +0530 Subject: [PATCH 052/115] Refactoring bug fix --- .../mode/experimental/ASTNodeWrapper.java | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index 2536e78..3b03aa9 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -521,6 +521,12 @@ public int[][] getOffsetMapping(String source){ return new int[][]{javaCodeMap,pdeCodeMap}; } + /** + * Highlight the ASTNode in the editor, if it's of type + * SimpleName + * @param astGenerator + * @return - true if highlighting was successful + */ public boolean highlightNode(ASTGenerator astGenerator){ if(!(Node instanceof SimpleName)){ return false; @@ -553,7 +559,8 @@ public boolean highlightNode(ASTGenerator astGenerator){ logE("Logical error in highLightNode(). Please file a bug report."); return false; } - //TODO: Asteriods example. Spaceship ship; wrong highlight + + // First find the name in the java line, and marks its index Pattern toFind = Pattern.compile("\\b" + nodeName.toString() + "\\b"); Matcher matcher = toFind.matcher(javaLine); int count = 0, index = 0; @@ -564,27 +571,18 @@ public boolean highlightNode(ASTGenerator astGenerator){ if(lsto + matcher.start() == nodeName.getStartPosition()) break; } - // find the count of the name in the java code - -// do { -// index = javaLine.indexOf(lookingFor, index); -// if (index != -1) { -// count++; -// index += lookingFor.length(); -// } else -// break; -// } while (true); log("count=" + count); - // find the offset of the name of that index in the pde code index = 0; - while (count > 0) { - index = pdeLine.indexOf(lookingFor, index); - if (index != -1) { - count--; - index += lookingFor.length(); + // find the same name in the pde line by its index and get its offsets + matcher = toFind.matcher(pdeLine); + while(matcher.find()){ + count--; + if(count == 0){ + log("Found on pde line lso: " + matcher.start()); + index = matcher.end(); + break; } } - log("pde lso " + (index - lookingFor.length())); int lso = astGenerator.editor.ta.getLineStartOffset(pdeOffs[1]); From 3deb6e21cd347c11ab30f57b5e69e319f1ce5a35 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Thu, 1 May 2014 04:18:05 +0530 Subject: [PATCH 053/115] trying to get to the bottom of parameterized type bug --- .../mode/experimental/ASTGenerator.java | 18 +++++++++--------- .../mode/experimental/ErrorCheckerService.java | 8 +++++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index ff3709c..0650e86 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -240,7 +240,7 @@ protected void setupGUI(){ /** * Toggle AST View window */ - public static final boolean SHOWAST = !true; + public static final boolean SHOWAST = true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { @@ -1545,7 +1545,7 @@ public void scrollToDeclaration(int lineNumber, String name, int offset) { public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, boolean scrollOnly) { - log("----getASTNodeAt----"); + log("----getASTNodeAt---- CU State: " + errorCheckerService.compilationUnitState); if (errorCheckerService != null) { editor = errorCheckerService.getEditor(); int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab()); @@ -1558,10 +1558,10 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, } } - log("FLON: " + lineNumber); + log("FLON: Node line number " + lineNumber); ASTNode lineNode = findLineOfNode(compilationUnit, lineNumber, offset, name); - log("+> " + lineNode); + log("Node text +> " + lineNode); ASTNode decl = null; String nodeLabel = null; String nameOfNode = null; // The node name which is to be scrolled to @@ -1581,7 +1581,7 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, } } } - log("FLON2: " + lineNumber + " LN spos " + log("FLON2: " + lineNumber + " LN start pos " + lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); /* * Now I need to see if multiple statements exist with this same line number @@ -1617,16 +1617,16 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, } } } - log("FLON3 "+lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); + log("FLON3 new alt off: " + altOff); ASTNode simpName = pinpointOnLine(lineNode, altOff, lineNode.getStartPosition(), name); if(simpName == null){ //Added while fixing #51 - log("1+++> " + simpName); + log("pinpointOnLine 1+++> " + simpName); simpName = pinpointOnLine(lineNode.getParent(), altOff, lineNode.getStartPosition(), name); } - log("2+++> " + simpName); + log("pinpointOnLine 2+++> " + simpName); if(simpName == null && lineNode instanceof SimpleName){ switch (lineNode.getParent().getNodeType()) { case ASTNode.TYPE_DECLARATION: @@ -2386,7 +2386,7 @@ protected static ASTNode findLineOfNode(ASTNode node, int lineNumber, @SuppressWarnings("unchecked") public static ASTNode pinpointOnLine(ASTNode node, int offset, int lineStartOffset, String name) { - + //log("pinpointOnLine node class: " + node.getClass().getSimpleName()); if (node instanceof SimpleName) { SimpleName sn = (SimpleName) node; //log(offset+ "off,pol " + getNodeAsString(sn)); diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index c422d33..19ac719 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -409,13 +409,15 @@ public void changedUpdate(DocumentEvent e) { } + public int compilationUnitState = 0; + protected boolean checkCode() { //log("checkCode() " + textModified.get() ); log("checkCode() " + textModified.get()); lastTimeStamp = System.currentTimeMillis(); try { sourceCode = preprocessCode(editor.getSketch().getMainProgram()); - + compilationUnitState = 0; syntaxCheck(); log(editor.getSketch().getName() + "1 MCO " + mainClassOffset); @@ -503,7 +505,7 @@ protected void syntaxCheck() { cu = (CompilationUnit) parser.createAST(null); } } - + compilationUnitState = 1; synchronized (problemsList) { // Store errors returned by the ast parser @@ -557,7 +559,7 @@ protected void compileCheck() { cu = (CompilationUnit) parser.createAST(null); } } - + compilationUnitState = 2; // Currently (Sept, 2012) I'm using Java's reflection api to load the // CompilationChecker class(from CompilationChecker.jar) that houses the // Eclispe JDT compiler, and call its getErrorsAsObj method to obtain From d5a766dfe73f1e9cf7840f81b40b75af3f0fe08d Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 4 May 2014 16:01:45 +0530 Subject: [PATCH 054/115] before attempting fix --- .../mode/experimental/ASTGenerator.java | 20 +++++++++++++++++++ .../mode/experimental/ASTNodeWrapper.java | 5 ++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 0650e86..67bca78 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1179,6 +1179,26 @@ public ArrayList getMembersForType(ClassMember tehClass, return candidates; } + public String getJavaSourceCodeline(int jLineNumber){ + try { + PlainDocument javaSource = new PlainDocument(); + javaSource.insertString(0, errorCheckerService.sourceCode, null); + Element lineElement = javaSource.getDefaultRootElement() + .getElement(jLineNumber-1); + if(lineElement == null) { + log("Couldn't fetch jlinenum " + jLineNumber); + return null; + } + String javaLine = javaSource.getText(lineElement.getStartOffset(), + lineElement.getEndOffset() + - lineElement.getStartOffset()); + return javaLine; + } catch (BadLocationException e) { + logE(e + " in getJavaSourceCodeline() for jinenum: " + jLineNumber); + } + return null; + } + /** * Searches for the particular class in the default list of imports as well as * the Sketch classpath diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index 3b03aa9..542d0d8 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -377,7 +377,7 @@ public int[][] getOffsetMapping(String source){ * index correction needed. (2) Now all java conversions are applied after * marking the offsets. This ensures that the index order isn't disturbed by * one at a time conversions as done in preprocessCode() in ECS. Took me - * sometime to figure out this was a bug. (3) Next I create a tables(two + * sometime to figure out this was a bug. (3) Next I create a table(two * separate arrays) which allows me to look it up for matching any index * between pde or java version of the snippet. This also lets me find out * any difference in length between both versions. @@ -389,6 +389,8 @@ public int[][] getOffsetMapping(String source){ */ log("Src:" + source); + // Instead of converting pde into java, how can I simply extract the same source + // from the java code? Think. TODO String sourceAlt = new String(source); TreeMap offsetmap = new TreeMap(); @@ -533,6 +535,7 @@ public boolean highlightNode(ASTGenerator astGenerator){ } SimpleName nodeName = (SimpleName) Node; try { + //TODO: Redundant code. See ASTGenerator.getJavaSourceCodeline() int javaLineNumber = getLineNumber(nodeName); int pdeOffs[] = astGenerator.errorCheckerService .calculateTabIndexAndLineNumber(javaLineNumber); From 7b80247756c6993c93c4fdb6ad50e1cef038dc2b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 5 May 2014 02:01:52 +0530 Subject: [PATCH 055/115] work on offset bug fix --- .../mode/experimental/ASTGenerator.java | 2 +- .../mode/experimental/ASTNodeWrapper.java | 36 ++++++++++++------- .../experimental/ErrorCheckerService.java | 10 ++++++ 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 67bca78..ebda1f9 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -240,7 +240,7 @@ protected void setupGUI(){ /** * Toggle AST View window */ - public static final boolean SHOWAST = true; + public static final boolean SHOWAST = !true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index 542d0d8..3acb311 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -196,7 +196,7 @@ public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { int pdeoffsets[] = getPDECodeOffsets(ecs); String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); - int vals[] = createOffsetMapping(pdeCode,nodeOffset - altStartPos,nodeLength); + int vals[] = createOffsetMapping(ecs, pdeCode,nodeOffset - altStartPos,nodeLength); if (vals != null) return new int[] { lineNumber, nodeOffset + vals[0] - altStartPos, vals[1] }; @@ -315,9 +315,9 @@ private int getJavadocOffset(TypeDeclaration td){ * @param nodeLen * @return int[0] - difference in start offset, int[1] - node length */ - private int[] createOffsetMapping(String source, int inpOffset, int nodeLen) { + private int[] createOffsetMapping(ErrorCheckerService ecs, String source, int inpOffset, int nodeLen) { - int ret[][] = getOffsetMapping(source); + int ret[][] = getOffsetMapping(ecs, source); if(ret == null){ // no offset mapping needed return null; @@ -358,7 +358,7 @@ private int[] createOffsetMapping(String source, int inpOffset, int nodeLen) { * @param source * @return int[0] - java code offsets, int[1] = pde code offsets */ - public int[][] getOffsetMapping(String source){ + public int[][] getOffsetMapping(ErrorCheckerService ecs, String source){ /* * This is some tricky shiz. So detailed explanation follows: @@ -392,8 +392,13 @@ public int[][] getOffsetMapping(String source){ // Instead of converting pde into java, how can I simply extract the same source // from the java code? Think. TODO String sourceAlt = new String(source); + String sourceJava = ecs.astGenerator.getJavaSourceCodeline(lineNumber); TreeMap offsetmap = new TreeMap(); + if(sourceJava.trim().startsWith("public") && !source.startsWith("public")){ + offsetmap.put(0,6); + //TODO: This is a temp fix. You GOTTA rewrite offset matching + } // Find all #[web color] // Should be 6 digits only. final String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W"; @@ -435,7 +440,7 @@ public int[][] getOffsetMapping(String source){ + Character.toUpperCase(dataType.charAt(0)) + dataType.substring(1) + "("); - } + } if(offsetmap.isEmpty()){ log("No offset matching needed."); return null; @@ -452,8 +457,11 @@ public int[][] getOffsetMapping(String source){ colorMatcher = colorPattern.matcher(sourceAlt); sourceAlt = colorMatcher.replaceAll("int"); - + + log("From direct source: "); + sourceAlt = sourceJava; log(sourceAlt); + // Create code map. Beware! Dark magic ahead. int javaCodeMap[] = new int[source.length() * 2]; @@ -476,16 +484,20 @@ public int[][] getOffsetMapping(String source){ pi--; pj--; for (int i = 0; i < kval; i++, pi++, pj++) { - javaCodeMap[pi] = javaCodeMap[pi - 1]; - pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; + if (pi > 1 && pj > 1) { + javaCodeMap[pi] = javaCodeMap[pi - 1]; + pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; + } } } else { // repeat pde offsets pi--; pj--; for (int i = 0; i < -kval; i++, pi++, pj++) { - javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; - pdeCodeMap[pj] = pdeCodeMap[pj - 1]; + if (pi > 1 && pj > 1) { + javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; + pdeCodeMap[pj] = pdeCodeMap[pj - 1]; + } } } @@ -506,7 +518,7 @@ public int[][] getOffsetMapping(String source){ pj++; } - // deubg o/p + // debug o/p for (int i = 0; i < pdeCodeMap.length; i++) { if (pdeCodeMap[i] > 0 || javaCodeMap[i] > 0 || i == 0) { if (i < source.length()) @@ -609,7 +621,7 @@ public boolean highlightNode(ASTGenerator astGenerator){ public int[][] getOffsetMapping(ErrorCheckerService ecs){ int pdeoffsets[] = getPDECodeOffsets(ecs); String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); - return getOffsetMapping(pdeCode); + return getOffsetMapping(ecs, pdeCode); } /** diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index 19ac719..d390afb 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -1163,6 +1163,16 @@ public int[] calculateTabIndexAndLineNumber(int javalineNumber) { return new int[] { codeIndex, x }; } + + public int getJavaLineNumFromPDElineNum(int tab, int pdeLineNum){ + int jLineNum = programImports.size() + 1; + for (int i = 0; i < tab; i++) { + SketchCode sc = editor.getSketch().getCode(i); + int len = Base.countLines(sc.getProgram()) + 1; + jLineNum += len; + } + return jLineNum; + } /** * Fetches code from the editor tabs and pre-processes it into parsable pure From 032af4d791929f03aa2cb66b2f1585d55180259b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 5 May 2014 02:02:48 +0530 Subject: [PATCH 056/115] added Utils class, trying edit distance stuff for offset matching --- src/processing/mode/experimental/Utils.java | 145 ++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 src/processing/mode/experimental/Utils.java diff --git a/src/processing/mode/experimental/Utils.java b/src/processing/mode/experimental/Utils.java new file mode 100644 index 0000000..d471194 --- /dev/null +++ b/src/processing/mode/experimental/Utils.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2012-14 Manindra Moharana + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package processing.mode.experimental; + +/** + * A class containing multiple utility methods + * + * @author Manindra Moharana + * + */ + +public class Utils { + + public static int minDistance(String word1, String word2) { + int len1 = word1.length(); + int len2 = word2.length(); + + // len1+1, len2+1, because finally return dp[len1][len2] + int[][] dp = new int[len1 + 1][len2 + 1]; + + for (int i = 0; i <= len1; i++) { + dp[i][0] = i; + } + + for (int j = 0; j <= len2; j++) { + dp[0][j] = j; + } + + //iterate though, and check last char + for (int i = 0; i < len1; i++) { + char c1 = word1.charAt(i); + for (int j = 0; j < len2; j++) { + char c2 = word2.charAt(j); + //System.out.print(c1 + "<->" + c2); + //if last two chars equal + if (c1 == c2) { + //update dp value for +1 length + dp[i + 1][j + 1] = dp[i][j]; + System.out.println(); + } else { + int replace = dp[i][j] + 1; + int insert = dp[i][j + 1] + 1; + int delete = dp[i + 1][j] + 1; +// if (replace < delete) { +// System.out.println(" --- D"); +// } else +// System.out.println(" --- R"); + int min = replace > insert ? insert : replace; + min = delete > min ? min : delete; + dp[i + 1][j + 1] = min; + } + } + } +// for (int i = 0; i < dp.length; i++) { +// for (int j = 0; j < dp[0].length; j++) { +// System.out.print(dp[i][j] + " "); +// } +// System.out.println(); +// } + + System.out.println("Edit distance1: " + dp[len1][len2]); + minDistInGrid(dp, 0, 0, len1, len2, word1.toCharArray(), + word2.toCharArray()); + return dp[len1][len2]; + } + + public static int distance(String a, String b) { +// a = a.toLowerCase(); +// b = b.toLowerCase(); + + // i == 0 + int[] costs = new int[b.length() + 1]; + for (int j = 0; j < costs.length; j++) + costs[j] = j; + for (int i = 1; i <= a.length(); i++) { + // j == 0; nw = lev(i - 1, j) + costs[0] = i; + int nw = i - 1; + for (int j = 1; j <= b.length(); j++) { + int cj = Math.min(1 + Math.min(costs[j], costs[j - 1]), + a.charAt(i - 1) == b.charAt(j - 1) ? nw : nw + 1); + nw = costs[j]; + costs[j] = cj; + } + } + System.out.println("Edit distance2: " + costs[b.length()]); + return costs[b.length()]; + } + + public static void minDistInGrid(int g[][], int i, int j, int fi, int fj, + char s1[], char s2[]) { +// if(i < s1.length)System.out.print(s1[i] + " <->"); +// if(j < s2.length)System.out.print(s2[j]); + if (i < s1.length && j < s2.length) { + System.out.print(s1[i] + " <-> " + s2[j]); + if (s1[i] != s2[j]) + System.out.println("--"); + } + System.out.println(); + if (i == fi && j == fj) { + System.out.println("Reached end."); + } else { + int a = Integer.MAX_VALUE, b = a, c = a; + if (i < fi) + a = g[i + 1][j]; + if (i < fi && j < fj) + b = g[i][j + 1]; + if (i < fi && j < fj) + c = g[i + 1][j + 1]; + int mini = Math.min(a, Math.min(b, c)); + if (mini == a) { + //System.out.println(s1[i + 1] + " " + s2[j]); + minDistInGrid(g, i + 1, j, fi, fj, s1, s2); + } else if (mini == b) { + //System.out.println(s1[i] + " " + s2[j + 1]); + minDistInGrid(g, i, j + 1, fi, fj, s1, s2); + } else if (mini == c) { + //System.out.println(s1[i + 1] + " " + s2[j + 1]); + minDistInGrid(g, i + 1, j + 1, fi, fj, s1, s2); + } + } + } + + public static void main(String[] args) { + minDistance("c = #qwerty;", "c = 0xffqwerty;"); + //minDistance("c = #bb00aa;", "c = 0xffbb00aa;"); +// distance("c = #bb00aa;", "c = 0xffbb00aa;"); + } +} From d0e09b7e57e71520cd51c8e266ad0e275833661c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 7 May 2014 11:42:47 +0530 Subject: [PATCH 057/115] now that's some real progress ;) --- src/processing/mode/experimental/Utils.java | 50 ++++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/src/processing/mode/experimental/Utils.java b/src/processing/mode/experimental/Utils.java index d471194..68db300 100644 --- a/src/processing/mode/experimental/Utils.java +++ b/src/processing/mode/experimental/Utils.java @@ -27,10 +27,23 @@ public class Utils { + public static String reverse(String s){ + char w[] = s.toCharArray(); + for (int i = 0; i < w.length/2; i++) { + char t = w[i]; + w[i] = w[w.length - 1 - i]; + w[w.length - 1 - i] = t; + } + return new String(w); + } + public static int minDistance(String word1, String word2) { +// word1 = reverse(word1); +// word2 = reverse(word2); int len1 = word1.length(); int len2 = word2.length(); - + System.out.println(word1 + " len: " + len1); + System.out.println(word2 + " len: " + len2); // len1+1, len2+1, because finally return dp[len1][len2] int[][] dp = new int[len1 + 1][len2 + 1]; @@ -52,7 +65,7 @@ public static int minDistance(String word1, String word2) { if (c1 == c2) { //update dp value for +1 length dp[i + 1][j + 1] = dp[i][j]; - System.out.println(); +// System.out.println(); } else { int replace = dp[i][j] + 1; int insert = dp[i][j + 1] + 1; @@ -67,6 +80,7 @@ public static int minDistance(String word1, String word2) { } } } + // for (int i = 0; i < dp.length; i++) { // for (int j = 0; j < dp[0].length; j++) { // System.out.print(dp[i][j] + " "); @@ -75,7 +89,7 @@ public static int minDistance(String word1, String word2) { // } System.out.println("Edit distance1: " + dp[len1][len2]); - minDistInGrid(dp, 0, 0, len1, len2, word1.toCharArray(), + minDistInGrid(dp,len1, len2, 0, 0 , word1.toCharArray(), word2.toCharArray()); return dp[len1][len2]; } @@ -108,38 +122,40 @@ public static void minDistInGrid(int g[][], int i, int j, int fi, int fj, // if(i < s1.length)System.out.print(s1[i] + " <->"); // if(j < s2.length)System.out.print(s2[j]); if (i < s1.length && j < s2.length) { - System.out.print(s1[i] + " <-> " + s2[j]); - if (s1[i] != s2[j]) - System.out.println("--"); + System.out.print(s1[i] + " "+ i +" <-> " + j + " " + s2[j]); +// if (s1[i] != s2[j]) +// System.out.println("--"); } System.out.println(); if (i == fi && j == fj) { System.out.println("Reached end."); } else { int a = Integer.MAX_VALUE, b = a, c = a; - if (i < fi) - a = g[i + 1][j]; - if (i < fi && j < fj) - b = g[i][j + 1]; - if (i < fi && j < fj) - c = g[i + 1][j + 1]; + if (i > 0) + a = g[i - 1][j]; + if (j > 0) + b = g[i][j - 1]; + if (i > 0 && j > 0) + c = g[i - 1][j - 1]; int mini = Math.min(a, Math.min(b, c)); if (mini == a) { //System.out.println(s1[i + 1] + " " + s2[j]); - minDistInGrid(g, i + 1, j, fi, fj, s1, s2); + minDistInGrid(g, i - 1, j, fi, fj, s1, s2); } else if (mini == b) { //System.out.println(s1[i] + " " + s2[j + 1]); - minDistInGrid(g, i, j + 1, fi, fj, s1, s2); + minDistInGrid(g, i, j - 1, fi, fj, s1, s2); } else if (mini == c) { //System.out.println(s1[i + 1] + " " + s2[j + 1]); - minDistInGrid(g, i + 1, j + 1, fi, fj, s1, s2); + minDistInGrid(g, i - 1, j - 1, fi, fj, s1, s2); } } } public static void main(String[] args) { - minDistance("c = #qwerty;", "c = 0xffqwerty;"); - //minDistance("c = #bb00aa;", "c = 0xffbb00aa;"); +// minDistance("c = #qwerty;", "c = 0xffqwerty;"); +// minDistance("int a = int(4.5);", "int a = PApplet.parseInt(4.5f);"); + minDistance("static void main(){;", "public static void main(){;"); +// minDistance("#bb00aa", "0xffbb00aa"); // distance("c = #bb00aa;", "c = 0xffbb00aa;"); } } From ee1be6a659e1af3cedda1e10740d93f268cf380f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 7 May 2014 13:10:08 +0530 Subject: [PATCH 058/115] fixed size arrays don't cut it. --- src/processing/mode/experimental/Utils.java | 46 ++++++++++++++------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/processing/mode/experimental/Utils.java b/src/processing/mode/experimental/Utils.java index 68db300..bed7839 100644 --- a/src/processing/mode/experimental/Utils.java +++ b/src/processing/mode/experimental/Utils.java @@ -18,25 +18,27 @@ package processing.mode.experimental; +import java.util.HashMap; + /** * A class containing multiple utility methods * * @author Manindra Moharana - * + * */ public class Utils { - - public static String reverse(String s){ + + public static String reverse(String s) { char w[] = s.toCharArray(); - for (int i = 0; i < w.length/2; i++) { + for (int i = 0; i < w.length / 2; i++) { char t = w[i]; w[i] = w[w.length - 1 - i]; w[w.length - 1 - i] = t; } return new String(w); } - + public static int minDistance(String word1, String word2) { // word1 = reverse(word1); // word2 = reverse(word2); @@ -80,17 +82,24 @@ public static int minDistance(String word1, String word2) { } } } - + // for (int i = 0; i < dp.length; i++) { // for (int j = 0; j < dp[0].length; j++) { // System.out.print(dp[i][j] + " "); // } // System.out.println(); // } - + int maxLen = Math.max(len1, len2); + int pdeCodeMap[] = new int[maxLen], javaCodeMap[] = new int[maxLen]; System.out.println("Edit distance1: " + dp[len1][len2]); - minDistInGrid(dp,len1, len2, 0, 0 , word1.toCharArray(), - word2.toCharArray()); + minDistInGrid(dp, len1, len2, 0, 0, word1.toCharArray(), + word2.toCharArray(), pdeCodeMap, javaCodeMap, maxLen); + System.out.println("PDE-to-Java"); + for (int i = 0; i < maxLen; i++) { + System.out.print(pdeCodeMap[i] + " <-> " + javaCodeMap[i]); + System.out.println(", " + word1.charAt(pdeCodeMap[i]) + " <-> " + + word2.charAt(javaCodeMap[i])); + } return dp[len1][len2]; } @@ -118,11 +127,14 @@ public static int distance(String a, String b) { } public static void minDistInGrid(int g[][], int i, int j, int fi, int fj, - char s1[], char s2[]) { + char s1[], char s2[], int pdeCodeMap[], + int javaCodeMap[], int k) { // if(i < s1.length)System.out.print(s1[i] + " <->"); // if(j < s2.length)System.out.print(s2[j]); if (i < s1.length && j < s2.length) { - System.out.print(s1[i] + " "+ i +" <-> " + j + " " + s2[j]); + pdeCodeMap[k] = i; + javaCodeMap[k] = j; + System.out.print(s1[i] + " " + i + " <-> " + j + " " + s2[j] + " k = " + k); // if (s1[i] != s2[j]) // System.out.println("--"); } @@ -140,21 +152,25 @@ public static void minDistInGrid(int g[][], int i, int j, int fi, int fj, int mini = Math.min(a, Math.min(b, c)); if (mini == a) { //System.out.println(s1[i + 1] + " " + s2[j]); - minDistInGrid(g, i - 1, j, fi, fj, s1, s2); + minDistInGrid(g, i - 1, j, fi, fj, s1, s2, pdeCodeMap, javaCodeMap, + k - 1); } else if (mini == b) { //System.out.println(s1[i] + " " + s2[j + 1]); - minDistInGrid(g, i, j - 1, fi, fj, s1, s2); + minDistInGrid(g, i, j - 1, fi, fj, s1, s2, pdeCodeMap, javaCodeMap, + k - 1); } else if (mini == c) { //System.out.println(s1[i + 1] + " " + s2[j + 1]); - minDistInGrid(g, i - 1, j - 1, fi, fj, s1, s2); + minDistInGrid(g, i - 1, j - 1, fi, fj, s1, s2, pdeCodeMap, javaCodeMap, + k - 1); } } } public static void main(String[] args) { // minDistance("c = #qwerty;", "c = 0xffqwerty;"); + minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); // minDistance("int a = int(4.5);", "int a = PApplet.parseInt(4.5f);"); - minDistance("static void main(){;", "public static void main(){;"); +// minDistance("static void main(){;", "public static void main(){;"); // minDistance("#bb00aa", "0xffbb00aa"); // distance("c = #bb00aa;", "c = 0xffbb00aa;"); } From e698f2f6e442ba4d9360d93eb08f14213c80d15d Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 7 May 2014 14:24:40 +0530 Subject: [PATCH 059/115] too much trouble this --- src/processing/mode/experimental/Utils.java | 57 +++++++++++++-------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/src/processing/mode/experimental/Utils.java b/src/processing/mode/experimental/Utils.java index bed7839..09007ab 100644 --- a/src/processing/mode/experimental/Utils.java +++ b/src/processing/mode/experimental/Utils.java @@ -18,6 +18,7 @@ package processing.mode.experimental; +import java.util.ArrayList; import java.util.HashMap; /** @@ -39,7 +40,7 @@ public static String reverse(String s) { return new String(w); } - public static int minDistance(String word1, String word2) { + public int minDistance(String word1, String word2) { // word1 = reverse(word1); // word2 = reverse(word2); int len1 = word1.length(); @@ -89,17 +90,24 @@ public static int minDistance(String word1, String word2) { // } // System.out.println(); // } - int maxLen = Math.max(len1, len2); - int pdeCodeMap[] = new int[maxLen], javaCodeMap[] = new int[maxLen]; - System.out.println("Edit distance1: " + dp[len1][len2]); +// int maxLen = Math.max(len1, len2)+2; +// int pdeCodeMap[] = new int[maxLen], javaCodeMap[] = new int[maxLen]; +// System.out.println("Edit distance1: " + dp[len1][len2]); + ArrayList alist = new ArrayList(); minDistInGrid(dp, len1, len2, 0, 0, word1.toCharArray(), - word2.toCharArray(), pdeCodeMap, javaCodeMap, maxLen); + word2.toCharArray(), alist); System.out.println("PDE-to-Java"); - for (int i = 0; i < maxLen; i++) { - System.out.print(pdeCodeMap[i] + " <-> " + javaCodeMap[i]); - System.out.println(", " + word1.charAt(pdeCodeMap[i]) + " <-> " - + word2.charAt(javaCodeMap[i])); +// for (int i = 0; i < maxLen; i++) { +// System.out.print(pdeCodeMap[i] + " <-> " + javaCodeMap[i]); +// System.out.println(", " + word1.charAt(pdeCodeMap[i]) + " <-> " +// + word2.charAt(javaCodeMap[i])); +// } + for (int i = 0; i < alist.size(); i++) { + System.out.print(alist.get(i).pdeOffset + " <-> " + alist.get(i).javaOffset); + System.out.println(", " + word1.charAt(alist.get(i).pdeOffset) + " <-> " + + word2.charAt(alist.get(i).javaOffset)); } + System.out.println("Length " + alist.size()); return dp[len1][len2]; } @@ -126,15 +134,15 @@ public static int distance(String a, String b) { return costs[b.length()]; } - public static void minDistInGrid(int g[][], int i, int j, int fi, int fj, - char s1[], char s2[], int pdeCodeMap[], - int javaCodeMap[], int k) { + public void minDistInGrid(int g[][], int i, int j, int fi, int fj, + char s1[], char s2[], ArrayList set) { // if(i < s1.length)System.out.print(s1[i] + " <->"); // if(j < s2.length)System.out.print(s2[j]); if (i < s1.length && j < s2.length) { - pdeCodeMap[k] = i; - javaCodeMap[k] = j; - System.out.print(s1[i] + " " + i + " <-> " + j + " " + s2[j] + " k = " + k); +// pdeCodeMap[k] = i; +// javaCodeMap[k] = j; + System.out.print(s1[i] + " " + i + " <-> " + j + " " + s2[j]); + set.add(new OfsSet(i, j)); // if (s1[i] != s2[j]) // System.out.println("--"); } @@ -152,23 +160,28 @@ public static void minDistInGrid(int g[][], int i, int j, int fi, int fj, int mini = Math.min(a, Math.min(b, c)); if (mini == a) { //System.out.println(s1[i + 1] + " " + s2[j]); - minDistInGrid(g, i - 1, j, fi, fj, s1, s2, pdeCodeMap, javaCodeMap, - k - 1); + minDistInGrid(g, i - 1, j, fi, fj, s1, s2,set); } else if (mini == b) { //System.out.println(s1[i] + " " + s2[j + 1]); - minDistInGrid(g, i, j - 1, fi, fj, s1, s2, pdeCodeMap, javaCodeMap, - k - 1); + minDistInGrid(g, i, j - 1, fi, fj, s1, s2, set); } else if (mini == c) { //System.out.println(s1[i + 1] + " " + s2[j + 1]); - minDistInGrid(g, i - 1, j - 1, fi, fj, s1, s2, pdeCodeMap, javaCodeMap, - k - 1); + minDistInGrid(g, i - 1, j - 1, fi, fj, s1, s2, set); } } } + + public class OfsSet { + public final int pdeOffset, javaOffset; + public OfsSet(int pde, int java){ + pdeOffset = pde; + javaOffset = java; + } + } public static void main(String[] args) { // minDistance("c = #qwerty;", "c = 0xffqwerty;"); - minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); + new Utils().minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); // minDistance("int a = int(4.5);", "int a = PApplet.parseInt(4.5f);"); // minDistance("static void main(){;", "public static void main(){;"); // minDistance("#bb00aa", "0xffbb00aa"); From 3039e458b7fedb3da1ab5ca7c4c35cb1db4ede4f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 9 May 2014 22:06:54 +0530 Subject: [PATCH 060/115] release notes for 1.0.4 --- pdeX.txt | 4 ++-- revisions.txt | 24 ++++++++++++++++++- .../mode/experimental/ASTNodeWrapper.java | 4 ++-- .../experimental/ErrorCheckerService.java | 9 +++++++ 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/pdeX.txt b/pdeX.txt index 2cc551f..7c2a3aa 100644 --- a/pdeX.txt +++ b/pdeX.txt @@ -3,5 +3,5 @@ authorList=[The Processing Foundation](http://processing.org) url=https://github.com/processing/processing-experimental sentence=The next generation of PDE paragraph=Intelligent Code Completion, Live Error Checker, Debugger, Auto Refactor, etc. -version=6 -prettyVersion=1.0.3b +version=7 +prettyVersion=1.0.4b diff --git a/revisions.txt b/revisions.txt index 5a2a1fd..647859a 100644 --- a/revisions.txt +++ b/revisions.txt @@ -1,11 +1,33 @@ -PDE X v1.0.4b - February , 2014 +PDE X v1.0.4b - May 9, 2014 + +Requires Processing 2.1.2 or above. Bug fixes ++ Disabled auto-save. My sincere apologies to those who lost data due +to this bug. It was wrong of me to release an untested feature without +adding an option to enable/disable it. I've learnt a lesson and I shall +ensure this sort of thing doesn't happen again in the future. + + Autocompletion bug, column is sometimes off by 1 https://github.com/processing/processing-experimental/issues/38 ++ Persistent completion dialog on OS X +https://github.com/processing/processing-experimental/issues/32 + ++ Status bar update bug +https://github.com/processing/processing-experimental/issues/29 + ++ Export application broken +https://github.com/processing/processing-experimental/issues/45 + ++ Status Bar - New Tab prompt bug +https://github.com/processing/processing-experimental/issues/53 + ++ Show usage fails for methods which have javadoc comment +https://github.com/processing/processing-experimental/issues/51 + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PDE X v1.0.3b - January 21, 2014 diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index 3acb311..2823cc9 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -459,7 +459,7 @@ public int[][] getOffsetMapping(ErrorCheckerService ecs, String source){ sourceAlt = colorMatcher.replaceAll("int"); log("From direct source: "); - sourceAlt = sourceJava; +// sourceAlt = sourceJava; log(sourceAlt); @@ -582,7 +582,7 @@ public boolean highlightNode(ASTGenerator astGenerator){ int lsto = lineElement.getStartOffset(); while(matcher.find()){ count++; - System.out.println(matcher.start() + lsto); + //log(matcher.start() + lsto); if(lsto + matcher.start() == nodeName.getStartPosition()) break; } diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index d390afb..c026a56 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -213,6 +213,7 @@ public class ErrorCheckerService implements Runnable{ protected ErrorMessageSimplifier errorMsgSimplifier; public ErrorCheckerService(DebugEditor debugEditor) { + ensureMinP5Version(); this.editor = debugEditor; stopThread = new AtomicBoolean(false); pauseThread = new AtomicBoolean(false); @@ -283,6 +284,14 @@ public void run() { } }); } + + public void ensureMinP5Version(){ + // Processing 2.1.2 - Revision 0225 + if(Base.getRevision() < 225){ +// System.err.println("ERROR: PDE X requires Processing 2.1.2 or higher."); + Base.showWarning("Error", "ERROR: PDE X requires Processing 2.1.2 or higher.", null); + } + } public void run() { stopThread.set(false); From 787af5d2b9ffd6c5137e03e1f0c25588f63d166c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 1 Jun 2014 17:02:05 +0530 Subject: [PATCH 061/115] Fixes #66 --- .../mode/experimental/CompletionPanel.java | 63 +++++++++++-------- .../mode/experimental/DebugEditor.java | 2 +- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/processing/mode/experimental/CompletionPanel.java b/src/processing/mode/experimental/CompletionPanel.java index cadc007..00ee4e1 100644 --- a/src/processing/mode/experimental/CompletionPanel.java +++ b/src/processing/mode/experimental/CompletionPanel.java @@ -22,16 +22,12 @@ import static processing.mode.experimental.ExperimentalMode.logE; import java.awt.BorderLayout; -import java.awt.Color; import java.awt.Component; import java.awt.FontMetrics; import java.awt.Point; -import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.util.Iterator; -import javax.swing.BorderFactory; import javax.swing.DefaultListModel; import javax.swing.JLabel; import javax.swing.JList; @@ -210,17 +206,29 @@ public void run() { public boolean insertSelection() { if (completionList.getSelectedValue() != null) { try { + // If user types 'abc.', subword becomes '.' and null is returned String currentSubword = fetchCurrentSubword(); + int currentSubwordLen = currentSubword == null ? 0 : currentSubword + .length(); + //logE(currentSubword + " <= subword,len => " + currentSubword.length()); String selectedSuggestion = ((CompletionCandidate) completionList - .getSelectedValue()).getCompletionString().substring(currentSubword - .length()); - logE(subWord + " <= subword,Inserting suggestion=> " + .getSelectedValue()).getCompletionString(); + + if (currentSubword != null) { + selectedSuggestion = selectedSuggestion.substring(currentSubwordLen); + } else { + currentSubword = ""; + } + + logE(subWord + " <= subword, Inserting suggestion=> " + selectedSuggestion + " Current sub: " + currentSubword); - textarea.getDocument().remove(insertionPosition - - currentSubword.length(), - currentSubword.length()); + if (currentSubword.length() > 0) { + textarea.getDocument().remove(insertionPosition - currentSubwordLen, + currentSubwordLen); + } + textarea.getDocument() - .insertString(insertionPosition - currentSubword.length(), + .insertString(insertionPosition - currentSubwordLen, ((CompletionCandidate) completionList .getSelectedValue()).getCompletionString(), null); if (selectedSuggestion.endsWith(")")) { @@ -240,12 +248,16 @@ public boolean insertSelection() { } catch (BadLocationException e1) { e1.printStackTrace(); } + catch (Exception e) { + e.printStackTrace(); + } hide(); } return false; } private String fetchCurrentSubword() { + //log("Entering fetchCurrentSubword"); TextArea ta = editor.ta; int off = ta.getCaretPosition(); //log2("off " + off); @@ -256,35 +268,32 @@ private String fetchCurrentSubword() { return null; String s = ta.getLineText(line); //log2("lin " + line); - /* - * if (s == null) return null; else if (s.length() == 0) return null; - */ -// else { //log2(s + " len " + s.length()); - int x = ta.getCaretPosition() - ta.getLineStartOffset(line) - 1, x2 = x + 1, x1 = x - 1; + int x = ta.getCaretPosition() - ta.getLineStartOffset(line) - 1, x1 = x - 1; if(x >= s.length() || x < 0) return null; //TODO: Does this check cause problems? Verify. - //log2(" x char: " + s.charAt(x)); + log2(" x char: " + s.charAt(x)); //int xLS = off - getLineStartNonWhiteSpaceOffset(line); String word = (x < s.length() ? s.charAt(x) : "") + ""; if (s.trim().length() == 1) { -// word = "" -// + (keyChar == KeyEvent.CHAR_UNDEFINED ? s.charAt(x - 1) : keyChar); - //word = (x < s.length()?s.charAt(x):"") + ""; + // word = "" + // + (keyChar == KeyEvent.CHAR_UNDEFINED ? s.charAt(x - 1) : keyChar); + //word = (x < s.length()?s.charAt(x):"") + ""; word = word.trim(); if (word.endsWith(".")) word = word.substring(0, word.length() - 1); return word; } -// if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) -// ; // accepted these keys -// else if (!(Character.isLetterOrDigit(keyChar) || keyChar == '_' || keyChar == '$')) -// return null; + //log("fetchCurrentSubword 1 " + word); + if(word.equals(".")) return null; // If user types 'abc.', subword becomes '.' + // if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) + // ; // accepted these keys + // else if (!(Character.isLetterOrDigit(keyChar) || keyChar == '_' || keyChar == '$')) + // return null; int i = 0; - int closeB = 0; while (true) { i++; @@ -307,13 +316,13 @@ private String fetchCurrentSubword() { } } // if (keyChar != KeyEvent.CHAR_UNDEFINED) - + //log("fetchCurrentSubword 2 " + word); if (Character.isDigit(word.charAt(0))) return null; word = word.trim(); if (word.endsWith(".")) word = word.substring(0, word.length() - 1); - + //log("fetchCurrentSubword 3 " + word); //showSuggestionLater(); return word; //} diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 3e4041e..8813d5a 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -921,7 +921,7 @@ public boolean handleSaveAs() { vi.setTitle(getSketch().getName()); } // if file location has changed, update autosaver - autosaver.reloadAutosaveDir(); +// autosaver.reloadAutosaveDir(); return saved; } From c9db4e9447cc8ba6b56ce0c8e18db4e320534517 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 2 Jun 2014 01:12:42 +0530 Subject: [PATCH 062/115] more progress with offset matching --- src/processing/mode/experimental/Utils.java | 52 ++++++++++++++++----- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/src/processing/mode/experimental/Utils.java b/src/processing/mode/experimental/Utils.java index 09007ab..f160dcc 100644 --- a/src/processing/mode/experimental/Utils.java +++ b/src/processing/mode/experimental/Utils.java @@ -30,6 +30,8 @@ public class Utils { + public ArrayList offsetMatch; + String word1, word2; public static String reverse(String s) { char w[] = s.toCharArray(); for (int i = 0; i < w.length / 2; i++) { @@ -39,8 +41,19 @@ public static String reverse(String s) { } return new String(w); } + + public void getJavaOffForPdeOff(int start, int length){ + for (int i = 0; i < offsetMatch.size(); i++) { + System.out.print(offsetMatch.get(i).pdeOffset + " <-> " + offsetMatch.get(i).javaOffset); + System.out.println(", " + word1.charAt(offsetMatch.get(i).pdeOffset) + " <-> " + + word2.charAt(offsetMatch.get(i).javaOffset)); + } + System.out.println("Length " + offsetMatch.size()); + } public int minDistance(String word1, String word2) { + this.word1 = word1; + this.word2 = word2; // word1 = reverse(word1); // word2 = reverse(word2); int len1 = word1.length(); @@ -94,20 +107,21 @@ public int minDistance(String word1, String word2) { // int pdeCodeMap[] = new int[maxLen], javaCodeMap[] = new int[maxLen]; // System.out.println("Edit distance1: " + dp[len1][len2]); ArrayList alist = new ArrayList(); + offsetMatch = alist; minDistInGrid(dp, len1, len2, 0, 0, word1.toCharArray(), word2.toCharArray(), alist); - System.out.println("PDE-to-Java"); +// System.out.println("PDE-to-Java"); // for (int i = 0; i < maxLen; i++) { // System.out.print(pdeCodeMap[i] + " <-> " + javaCodeMap[i]); // System.out.println(", " + word1.charAt(pdeCodeMap[i]) + " <-> " // + word2.charAt(javaCodeMap[i])); // } - for (int i = 0; i < alist.size(); i++) { - System.out.print(alist.get(i).pdeOffset + " <-> " + alist.get(i).javaOffset); - System.out.println(", " + word1.charAt(alist.get(i).pdeOffset) + " <-> " - + word2.charAt(alist.get(i).javaOffset)); - } - System.out.println("Length " + alist.size()); +// for (int i = 0; i < alist.size(); i++) { +// System.out.print(alist.get(i).pdeOffset + " <-> " + alist.get(i).javaOffset); +// System.out.println(", " + word1.charAt(alist.get(i).pdeOffset) + " <-> " +// + word2.charAt(alist.get(i).javaOffset)); +// } +// System.out.println("Length " + alist.size()); return dp[len1][len2]; } @@ -141,14 +155,14 @@ public void minDistInGrid(int g[][], int i, int j, int fi, int fj, if (i < s1.length && j < s2.length) { // pdeCodeMap[k] = i; // javaCodeMap[k] = j; - System.out.print(s1[i] + " " + i + " <-> " + j + " " + s2[j]); + //System.out.print(s1[i] + " " + i + " <-> " + j + " " + s2[j]); set.add(new OfsSet(i, j)); // if (s1[i] != s2[j]) // System.out.println("--"); } - System.out.println(); + //System.out.println(); if (i == fi && j == fj) { - System.out.println("Reached end."); + //System.out.println("Reached end."); } else { int a = Integer.MAX_VALUE, b = a, c = a; if (i > 0) @@ -178,13 +192,27 @@ public OfsSet(int pde, int java){ javaOffset = java; } } + +// public class OffsetMatch{ +// public final ArrayList pdeOffset, javaOffset; +// +// public OffsetMatch(){ +// pdeOffset = new ArrayList(); +// javaOffset = new ArrayList(); +// } +// } public static void main(String[] args) { // minDistance("c = #qwerty;", "c = 0xffqwerty;"); - new Utils().minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); -// minDistance("int a = int(4.5);", "int a = PApplet.parseInt(4.5f);"); + Utils a = new Utils(); + + a.minDistance("int a = int(can); int ball;", "int a = PApplet.parseInt(can); int ball;"); + a.getJavaOffForPdeOff(10, 20); // minDistance("static void main(){;", "public static void main(){;"); // minDistance("#bb00aa", "0xffbb00aa"); + //a.minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); + a.minDistance("color abc = #qwerty;", "int abc = 0xffqwerty;"); + a.getJavaOffForPdeOff(10, 20); // distance("c = #bb00aa;", "c = 0xffbb00aa;"); } } From 875fca41d06dc68c339b23c784f3ca9583ac3f0f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 2 Jun 2014 02:31:17 +0530 Subject: [PATCH 063/115] things looking promising with offset matching --- src/processing/mode/experimental/Utils.java | 58 +++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/src/processing/mode/experimental/Utils.java b/src/processing/mode/experimental/Utils.java index f160dcc..4081bae 100644 --- a/src/processing/mode/experimental/Utils.java +++ b/src/processing/mode/experimental/Utils.java @@ -42,13 +42,64 @@ public static String reverse(String s) { return new String(w); } - public void getJavaOffForPdeOff(int start, int length){ + public void getPdeOffForJavaOff(int start, int length){ + System.out.println("PDE <-> Java" ); for (int i = 0; i < offsetMatch.size(); i++) { System.out.print(offsetMatch.get(i).pdeOffset + " <-> " + offsetMatch.get(i).javaOffset); System.out.println(", " + word1.charAt(offsetMatch.get(i).pdeOffset) + " <-> " + word2.charAt(offsetMatch.get(i).javaOffset)); } System.out.println("Length " + offsetMatch.size()); + System.out.println(start + " java start off, pde start off " + + getPdeOffForJavaOff(start)); + System.out.println((start + length - 1) + " java end off, pde end off " + + getPdeOffForJavaOff(start + length - 1)); + } + + public int getPdeOffForJavaOff(int javaOff){ + for (int i = offsetMatch.size() - 1; i >= 0;i--) { + if(offsetMatch.get(i).javaOffset < javaOff){ + continue; + } + else + if(offsetMatch.get(i).javaOffset == javaOff){ +// int j = i; + while(offsetMatch.get(--i).javaOffset == javaOff){ + System.out.println("MP " + offsetMatch.get(i).javaOffset + " " + + offsetMatch.get(i).pdeOffset); + } + int pdeOff = offsetMatch.get(++i).pdeOffset; + while(offsetMatch.get(--i).pdeOffset == pdeOff); + int j = i + 1; + if (j > -1 && j < offsetMatch.size()) + return offsetMatch.get(j).pdeOffset; + } + + } + return -1; + } + + public int getJavaOffForPdeOff(int pdeOff){ + for (int i = offsetMatch.size() - 1; i >= 0;i--) { + if(offsetMatch.get(i).pdeOffset < pdeOff){ + continue; + } + else + if(offsetMatch.get(i).pdeOffset == pdeOff){ +// int j = i; + while(offsetMatch.get(--i).pdeOffset == pdeOff){ +// System.out.println("MP " + offsetMatch.get(i).javaOffset + " " +// + offsetMatch.get(i).pdeOffset); + } + int javaOff = offsetMatch.get(++i).javaOffset; + while(offsetMatch.get(--i).javaOffset == javaOff); + int j = i + 1; + if (j > -1 && j < offsetMatch.size()) + return offsetMatch.get(j).javaOffset; + } + + } + return -1; } public int minDistance(String word1, String word2) { @@ -207,12 +258,13 @@ public static void main(String[] args) { Utils a = new Utils(); a.minDistance("int a = int(can); int ball;", "int a = PApplet.parseInt(can); int ball;"); - a.getJavaOffForPdeOff(10, 20); + a.getPdeOffForJavaOff(25, 3); // minDistance("static void main(){;", "public static void main(){;"); // minDistance("#bb00aa", "0xffbb00aa"); //a.minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); + System.out.println("--"); a.minDistance("color abc = #qwerty;", "int abc = 0xffqwerty;"); - a.getJavaOffForPdeOff(10, 20); + a.getPdeOffForJavaOff(4, 3); // distance("c = #bb00aa;", "c = 0xffbb00aa;"); } } From e980682bdaac22fb06f55927bbf838c4a63a0048 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 2 Jun 2014 02:50:41 +0530 Subject: [PATCH 064/115] Added OffsetMatcher. Time for a trial run --- .../mode/experimental/OffsetMatcher.java | 253 ++++++++++++++++++ src/processing/mode/experimental/Utils.java | 27 +- 2 files changed, 274 insertions(+), 6 deletions(-) create mode 100644 src/processing/mode/experimental/OffsetMatcher.java diff --git a/src/processing/mode/experimental/OffsetMatcher.java b/src/processing/mode/experimental/OffsetMatcher.java new file mode 100644 index 0000000..1fe0b62 --- /dev/null +++ b/src/processing/mode/experimental/OffsetMatcher.java @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2012-14 Manindra Moharana + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package processing.mode.experimental; + +import java.util.ArrayList; +import static processing.mode.experimental.ExperimentalMode.log; + +/** + * Performs offset matching between PDE and Java code (one line of code only) + * + * @author Manindra Moharana + * + */ + +public class OffsetMatcher { + + public ArrayList offsetMatch; + + String word1, word2; + + public OffsetMatcher(String pdeCode, String javaCode) { + this.word1 = pdeCode; + this.word2 = javaCode; + minDistance(); + log("PDE <-> Java"); + for (int i = 0; i < offsetMatch.size(); i++) { + log(offsetMatch.get(i).pdeOffset + " <-> " + + offsetMatch.get(i).javaOffset + + ", " + word1.charAt(offsetMatch.get(i).pdeOffset) + + " <-> " + word2.charAt(offsetMatch.get(i).javaOffset)); + } + log("Length " + offsetMatch.size()); + } + + public void getPdeOffForJavaOff(int start, int length) { + + log(start + " java start off, pde start off " + + getPdeOffForJavaOff(start)); + log((start + length - 1) + " java end off, pde end off " + + getPdeOffForJavaOff(start + length - 1)); + } + + public void getJavaOffForPdeOff(int start, int length) { +// System.out.println("PDE <-> Java" ); +// for (int i = 0; i < offsetMatch.size(); i++) { +// System.out.print(offsetMatch.get(i).pdeOffset + " <-> " + offsetMatch.get(i).javaOffset); +// System.out.println(", " + word1.charAt(offsetMatch.get(i).pdeOffset) + " <-> " +// + word2.charAt(offsetMatch.get(i).javaOffset)); +// } +// System.out.println("Length " + offsetMatch.size()); + log(start + " pde start off, java start off " + + getJavaOffForPdeOff(start)); + log((start + length - 1) + " pde end off, java end off " + + getJavaOffForPdeOff(start + length - 1)); + } + + public int getPdeOffForJavaOff(int javaOff) { + for (int i = offsetMatch.size() - 1; i >= 0; i--) { + if (offsetMatch.get(i).javaOffset < javaOff) { + continue; + } else if (offsetMatch.get(i).javaOffset == javaOff) { +// int j = i; + while (offsetMatch.get(--i).javaOffset == javaOff) { + log("MP " + offsetMatch.get(i).javaOffset + " " + + offsetMatch.get(i).pdeOffset); + } + int pdeOff = offsetMatch.get(++i).pdeOffset; + while (offsetMatch.get(--i).pdeOffset == pdeOff) + ; + int j = i + 1; + if (j > -1 && j < offsetMatch.size()) + return offsetMatch.get(j).pdeOffset; + } + + } + return -1; + } + + public int getJavaOffForPdeOff(int pdeOff) { + for (int i = offsetMatch.size() - 1; i >= 0; i--) { + if (offsetMatch.get(i).pdeOffset < pdeOff) { + continue; + } else if (offsetMatch.get(i).pdeOffset == pdeOff) { +// int j = i; + while (offsetMatch.get(--i).pdeOffset == pdeOff) { +// log("MP " + offsetMatch.get(i).javaOffset + " " +// + offsetMatch.get(i).pdeOffset); + } + int javaOff = offsetMatch.get(++i).javaOffset; + while (offsetMatch.get(--i).javaOffset == javaOff) + ; + int j = i + 1; + if (j > -1 && j < offsetMatch.size()) + return offsetMatch.get(j).javaOffset; + } + + } + return -1; + } + + private int minDistance() { + +// word1 = reverse(word1); +// word2 = reverse(word2); + int len1 = word1.length(); + int len2 = word2.length(); + log(word1 + " len: " + len1); + log(word2 + " len: " + len2); + // len1+1, len2+1, because finally return dp[len1][len2] + int[][] dp = new int[len1 + 1][len2 + 1]; + + for (int i = 0; i <= len1; i++) { + dp[i][0] = i; + } + + for (int j = 0; j <= len2; j++) { + dp[0][j] = j; + } + + //iterate though, and check last char + for (int i = 0; i < len1; i++) { + char c1 = word1.charAt(i); + for (int j = 0; j < len2; j++) { + char c2 = word2.charAt(j); + //System.out.print(c1 + "<->" + c2); + //if last two chars equal + if (c1 == c2) { + //update dp value for +1 length + dp[i + 1][j + 1] = dp[i][j]; +// log(); + } else { + int replace = dp[i][j] + 1; + int insert = dp[i][j + 1] + 1; + int delete = dp[i + 1][j] + 1; +// if (replace < delete) { +// log(" --- D"); +// } else +// log(" --- R"); + int min = replace > insert ? insert : replace; + min = delete > min ? min : delete; + dp[i + 1][j + 1] = min; + } + } + } + +// for (int i = 0; i < dp.length; i++) { +// for (int j = 0; j < dp[0].length; j++) { +// System.out.print(dp[i][j] + " "); +// } +// System.out.println(); +// } +// int maxLen = Math.max(len1, len2)+2; +// int pdeCodeMap[] = new int[maxLen], javaCodeMap[] = new int[maxLen]; +// System.out.println("Edit distance1: " + dp[len1][len2]); + ArrayList alist = new ArrayList(); + offsetMatch = alist; + minDistInGrid(dp, len1, len2, 0, 0, word1.toCharArray(), + word2.toCharArray(), alist); +// System.out.println("PDE-to-Java"); +// for (int i = 0; i < maxLen; i++) { +// System.out.print(pdeCodeMap[i] + " <-> " + javaCodeMap[i]); +// System.out.println(", " + word1.charAt(pdeCodeMap[i]) + " <-> " +// + word2.charAt(javaCodeMap[i])); +// } +// for (int i = 0; i < alist.size(); i++) { +// System.out.print(alist.get(i).pdeOffset + " <-> " + alist.get(i).javaOffset); +// System.out.println(", " + word1.charAt(alist.get(i).pdeOffset) + " <-> " +// + word2.charAt(alist.get(i).javaOffset)); +// } +// System.out.println("Length " + alist.size()); + return dp[len1][len2]; + } + + private void minDistInGrid(int g[][], int i, int j, int fi, int fj, + char s1[], char s2[], ArrayList set) { +// if(i < s1.length)System.out.print(s1[i] + " <->"); +// if(j < s2.length)System.out.print(s2[j]); + if (i < s1.length && j < s2.length) { +// pdeCodeMap[k] = i; +// javaCodeMap[k] = j; + //System.out.print(s1[i] + " " + i + " <-> " + j + " " + s2[j]); + set.add(new OffsetPair(i, j)); +// if (s1[i] != s2[j]) +// System.out.println("--"); + } + //System.out.println(); + if (i == fi && j == fj) { + //System.out.println("Reached end."); + } else { + int a = Integer.MAX_VALUE, b = a, c = a; + if (i > 0) + a = g[i - 1][j]; + if (j > 0) + b = g[i][j - 1]; + if (i > 0 && j > 0) + c = g[i - 1][j - 1]; + int mini = Math.min(a, Math.min(b, c)); + if (mini == a) { + //System.out.println(s1[i + 1] + " " + s2[j]); + minDistInGrid(g, i - 1, j, fi, fj, s1, s2, set); + } else if (mini == b) { + //System.out.println(s1[i] + " " + s2[j + 1]); + minDistInGrid(g, i, j - 1, fi, fj, s1, s2, set); + } else if (mini == c) { + //System.out.println(s1[i + 1] + " " + s2[j + 1]); + minDistInGrid(g, i - 1, j - 1, fi, fj, s1, s2, set); + } + } + } + + private class OffsetPair { + public final int pdeOffset, javaOffset; + + public OffsetPair(int pde, int java) { + pdeOffset = pde; + javaOffset = java; + } + } + + public static void main(String[] args) { +// minDistance("c = #qwerty;", "c = 0xffqwerty;"); + OffsetMatcher a; + + a = new OffsetMatcher("int a = int(can); int ball;", + "int a = PApplet.parseInt(can); int ball;"); + a.getPdeOffForJavaOff(25, 3); + a.getJavaOffForPdeOff(12, 3); +// minDistance("static void main(){;", "public static void main(){;"); +// minDistance("#bb00aa", "0xffbb00aa"); + //a.minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); + log("--"); + a = new OffsetMatcher("color abc = #qwerty;", "int abc = 0xffqwerty;"); + a.getPdeOffForJavaOff(4, 3); + a.getJavaOffForPdeOff(6, 3); +// distance("c = #bb00aa;", "c = 0xffbb00aa;"); + } +} diff --git a/src/processing/mode/experimental/Utils.java b/src/processing/mode/experimental/Utils.java index 4081bae..7992676 100644 --- a/src/processing/mode/experimental/Utils.java +++ b/src/processing/mode/experimental/Utils.java @@ -19,7 +19,6 @@ package processing.mode.experimental; import java.util.ArrayList; -import java.util.HashMap; /** * A class containing multiple utility methods @@ -30,7 +29,7 @@ public class Utils { - public ArrayList offsetMatch; + public ArrayList offsetMatch; String word1, word2; public static String reverse(String s) { char w[] = s.toCharArray(); @@ -56,6 +55,20 @@ public void getPdeOffForJavaOff(int start, int length){ + getPdeOffForJavaOff(start + length - 1)); } + public void getJavaOffForPdeOff(int start, int length){ +// System.out.println("PDE <-> Java" ); +// for (int i = 0; i < offsetMatch.size(); i++) { +// System.out.print(offsetMatch.get(i).pdeOffset + " <-> " + offsetMatch.get(i).javaOffset); +// System.out.println(", " + word1.charAt(offsetMatch.get(i).pdeOffset) + " <-> " +// + word2.charAt(offsetMatch.get(i).javaOffset)); +// } +// System.out.println("Length " + offsetMatch.size()); + System.out.println(start + " pde start off, java start off " + + getJavaOffForPdeOff(start)); + System.out.println((start + length - 1) + " pde end off, java end off " + + getJavaOffForPdeOff(start + length - 1)); + } + public int getPdeOffForJavaOff(int javaOff){ for (int i = offsetMatch.size() - 1; i >= 0;i--) { if(offsetMatch.get(i).javaOffset < javaOff){ @@ -157,7 +170,7 @@ public int minDistance(String word1, String word2) { // int maxLen = Math.max(len1, len2)+2; // int pdeCodeMap[] = new int[maxLen], javaCodeMap[] = new int[maxLen]; // System.out.println("Edit distance1: " + dp[len1][len2]); - ArrayList alist = new ArrayList(); + ArrayList alist = new ArrayList(); offsetMatch = alist; minDistInGrid(dp, len1, len2, 0, 0, word1.toCharArray(), word2.toCharArray(), alist); @@ -207,7 +220,7 @@ public void minDistInGrid(int g[][], int i, int j, int fi, int fj, // pdeCodeMap[k] = i; // javaCodeMap[k] = j; //System.out.print(s1[i] + " " + i + " <-> " + j + " " + s2[j]); - set.add(new OfsSet(i, j)); + set.add(new OfsSetTemp(i, j)); // if (s1[i] != s2[j]) // System.out.println("--"); } @@ -236,9 +249,9 @@ public void minDistInGrid(int g[][], int i, int j, int fi, int fj, } } - public class OfsSet { + public class OfsSetTemp { public final int pdeOffset, javaOffset; - public OfsSet(int pde, int java){ + public OfsSetTemp(int pde, int java){ pdeOffset = pde; javaOffset = java; } @@ -259,12 +272,14 @@ public static void main(String[] args) { a.minDistance("int a = int(can); int ball;", "int a = PApplet.parseInt(can); int ball;"); a.getPdeOffForJavaOff(25, 3); + a.getJavaOffForPdeOff(12,3); // minDistance("static void main(){;", "public static void main(){;"); // minDistance("#bb00aa", "0xffbb00aa"); //a.minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); System.out.println("--"); a.minDistance("color abc = #qwerty;", "int abc = 0xffqwerty;"); a.getPdeOffForJavaOff(4, 3); + a.getJavaOffForPdeOff(6,3); // distance("c = #bb00aa;", "c = 0xffbb00aa;"); } } From c99d4ee472af77b19fca1fbe7d0bf5480efdf525 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 2 Jun 2014 16:27:55 +0530 Subject: [PATCH 065/115] First phase of tests, no major casualties --- .../mode/experimental/ASTNodeWrapper.java | 15 ++++ .../mode/experimental/OffsetMatcher.java | 80 +++++++++---------- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index 2823cc9..734da04 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -575,6 +575,20 @@ public boolean highlightNode(ASTGenerator astGenerator){ return false; } + OffsetMatcher ofm = new OffsetMatcher(pdeLine, javaLine); + int highlightStart = ofm.getPdeOffForJavaOff(nodeName.getStartPosition() + - lineElement.getStartOffset(), + nodeName.getLength()); + if (highlightStart == -1) { + logE("Logical error in highLightNode() during offset matching. " + + "Please file a bug report."); + return false; + } + int lso = astGenerator.editor.ta.getLineStartOffset(pdeOffs[1]); + highlightStart += lso; + astGenerator.editor.setSelection(highlightStart, highlightStart + + nodeName.getLength()); + /* // First find the name in the java line, and marks its index Pattern toFind = Pattern.compile("\\b" + nodeName.toString() + "\\b"); Matcher matcher = toFind.matcher(javaLine); @@ -603,6 +617,7 @@ public boolean highlightNode(ASTGenerator astGenerator){ int lso = astGenerator.editor.ta.getLineStartOffset(pdeOffs[1]); astGenerator.editor.setSelection(lso + index - lookingFor.length(), lso + index); + */ return true; } catch (BadLocationException e) { logE("BLE in highLightNode() for " + nodeName); diff --git a/src/processing/mode/experimental/OffsetMatcher.java b/src/processing/mode/experimental/OffsetMatcher.java index 1fe0b62..d5aff52 100644 --- a/src/processing/mode/experimental/OffsetMatcher.java +++ b/src/processing/mode/experimental/OffsetMatcher.java @@ -33,44 +33,57 @@ public class OffsetMatcher { public ArrayList offsetMatch; String word1, word2; + + boolean matchingNeeded = false; public OffsetMatcher(String pdeCode, String javaCode) { this.word1 = pdeCode; this.word2 = javaCode; - minDistance(); - log("PDE <-> Java"); + if(word1.trim().equals(word2.trim())){ //TODO: trim() needed here? + matchingNeeded = false; + offsetMatch = new ArrayList(); + log("Offset Matching not needed"); + } + else + { + matchingNeeded = true; + minDistance(); + } + +// log("PDE <-> Java"); for (int i = 0; i < offsetMatch.size(); i++) { - log(offsetMatch.get(i).pdeOffset + " <-> " - + offsetMatch.get(i).javaOffset + - ", " + word1.charAt(offsetMatch.get(i).pdeOffset) - + " <-> " + word2.charAt(offsetMatch.get(i).javaOffset)); +// log(offsetMatch.get(i).pdeOffset + " <-> " +// + offsetMatch.get(i).javaOffset + +// ", " + word1.charAt(offsetMatch.get(i).pdeOffset) +// + " <-> " + word2.charAt(offsetMatch.get(i).javaOffset)); } - log("Length " + offsetMatch.size()); +// log("Length " + offsetMatch.size()); } - public void getPdeOffForJavaOff(int start, int length) { - + public int getPdeOffForJavaOff(int start, int length) { + if(!matchingNeeded) return start; + int ans = getPdeOffForJavaOff(start), end = getPdeOffForJavaOff(start + length - 1); log(start + " java start off, pde start off " - + getPdeOffForJavaOff(start)); + + ans); log((start + length - 1) + " java end off, pde end off " - + getPdeOffForJavaOff(start + length - 1)); + + end); + log("J: " + word2.substring(start, start + length) + "\nP: " + + word1.substring(ans, end + 1)); + return ans; } - public void getJavaOffForPdeOff(int start, int length) { -// System.out.println("PDE <-> Java" ); -// for (int i = 0; i < offsetMatch.size(); i++) { -// System.out.print(offsetMatch.get(i).pdeOffset + " <-> " + offsetMatch.get(i).javaOffset); -// System.out.println(", " + word1.charAt(offsetMatch.get(i).pdeOffset) + " <-> " -// + word2.charAt(offsetMatch.get(i).javaOffset)); -// } -// System.out.println("Length " + offsetMatch.size()); + public int getJavaOffForPdeOff(int start, int length) { + if(!matchingNeeded) return start; + int ans = getJavaOffForPdeOff(start); log(start + " pde start off, java start off " + getJavaOffForPdeOff(start)); log((start + length - 1) + " pde end off, java end off " + getJavaOffForPdeOff(start + length - 1)); + return ans; } public int getPdeOffForJavaOff(int javaOff) { + if(!matchingNeeded) return javaOff; for (int i = offsetMatch.size() - 1; i >= 0; i--) { if (offsetMatch.get(i).javaOffset < javaOff) { continue; @@ -93,6 +106,7 @@ public int getPdeOffForJavaOff(int javaOff) { } public int getJavaOffForPdeOff(int pdeOff) { + if(!matchingNeeded) return pdeOff; for (int i = offsetMatch.size() - 1; i >= 0; i--) { if (offsetMatch.get(i).pdeOffset < pdeOff) { continue; @@ -114,6 +128,13 @@ public int getJavaOffForPdeOff(int pdeOff) { return -1; } + /** + * Finds 'distance' between two Strings. + * See Edit Distance Problem + * https://secweb.cs.odu.edu/~zeil/cs361/web/website/Lectures/styles/pages/editdistance.html + * http://www.stanford.edu/class/cs124/lec/med.pdf + * + */ private int minDistance() { // word1 = reverse(word1); @@ -159,31 +180,10 @@ private int minDistance() { } } -// for (int i = 0; i < dp.length; i++) { -// for (int j = 0; j < dp[0].length; j++) { -// System.out.print(dp[i][j] + " "); -// } -// System.out.println(); -// } -// int maxLen = Math.max(len1, len2)+2; -// int pdeCodeMap[] = new int[maxLen], javaCodeMap[] = new int[maxLen]; -// System.out.println("Edit distance1: " + dp[len1][len2]); ArrayList alist = new ArrayList(); offsetMatch = alist; minDistInGrid(dp, len1, len2, 0, 0, word1.toCharArray(), word2.toCharArray(), alist); -// System.out.println("PDE-to-Java"); -// for (int i = 0; i < maxLen; i++) { -// System.out.print(pdeCodeMap[i] + " <-> " + javaCodeMap[i]); -// System.out.println(", " + word1.charAt(pdeCodeMap[i]) + " <-> " -// + word2.charAt(javaCodeMap[i])); -// } -// for (int i = 0; i < alist.size(); i++) { -// System.out.print(alist.get(i).pdeOffset + " <-> " + alist.get(i).javaOffset); -// System.out.println(", " + word1.charAt(alist.get(i).pdeOffset) + " <-> " -// + word2.charAt(alist.get(i).javaOffset)); -// } -// System.out.println("Length " + alist.size()); return dp[len1][len2]; } From 9f62f6de2569d430dabfd466558c8c45655ff04e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 2 Jun 2014 17:05:30 +0530 Subject: [PATCH 066/115] Testing the new markdown --- Todo, GSoC 2013.txt | 172 ++++++++++++++++++++++---------------------- 1 file changed, 86 insertions(+), 86 deletions(-) diff --git a/Todo, GSoC 2013.txt b/Todo, GSoC 2013.txt index d2e5777..c7020fc 100644 --- a/Todo, GSoC 2013.txt +++ b/Todo, GSoC 2013.txt @@ -4,7 +4,7 @@ This would also be a break down of my thought process and ideas as I tackle vari Manindra Moharana (me@mkmoharana.com) -* : Todo, x : Done, ? : Undecided Todo, ! : Critical, + : Minor Todo +[ ]: Todo, [x] : Done, ? : Undecided Todo, ! : Critical, + : Minor Todo Code Completion =============== @@ -16,122 +16,122 @@ The big stuff: - Many of the cases seem to have been covered, and I'm achieving more and more code unification as I'm working through the problem step by step - Looks almost complete now, nearly all cases covered(July 13th) x After popup appears, the popup location is fixed for the current line. So if editor window is moved while staying in the same line, popup appears at the prev location. Need to ensure editor is still at last know location. Fixed. -* Keyboard Shortcut for completion popup - Ctrl + Space -* Scope handling? Static/non static scope? -* Disable completions on comment line -* Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. +[ ]Keyboard Shortcut for completion popup - Ctrl + Space +[ ]Scope handling? Static/non static scope? +[ ]Disable completions on comment line +[ ]Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. -x Ensure that a compilation unit is created at startup! +[x]Ensure that a compilation unit is created at startup! x! Code competition for local code is working with recursive look up. -x Completion doesn't seem to show up for fields of a type defined locally. But works for methods with return type defined locally. Take ideas. Some case missing most probably. Fixed -x Discovered another major issue due to offset differences -> While looking for predictions, if the parsed string contains pde enhancements, predictions FAIL! Zomg. +[x]Completion doesn't seem to show up for fields of a type defined locally. But works for methods with return type defined locally. Take ideas. Some case missing most probably. Fixed +[x]Discovered another major issue due to offset differences -> While looking for predictions, if the parsed string contains pde enhancements, predictions FAIL! Zomg. Ex - "s.substring(int(13.4))." fails. Thinking to just do the substitutions before sending it to updatePredictions(), coz offsets aren't really a concern here, right? Yup, fixed it! x! Code completion with library code, non-nested seems to be broken, fix it. Fixed. -x Completion for external classes - ArrayList, HashMap, etc. +[x]Completion for external classes - ArrayList, HashMap, etc. x! Recursive lookup for compiled(library) code! x! Library CC for nested would be tricky. Need to jump from local->compiled code while searching recursively. Recursive find's current implementation is based on ASTNode return type. Afaik, no way to instantiate orphaned ASTNode objects(or did I miss it?). ASTNode objects have to be created only from the main ast instance. But I need to find a way to switch to compiled instances from local class instance. x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done. -x Differentiating between multiple statements on the same line. How to? Done with offset handling. -x - Cache predictions if current 'word' is increasing in length. If already showing predictions beginning with 's', for 'sa', remove extra completions, rather than recalculating predictions. Performance increase. -x Parameterized type support is broken. -x Array types, all all other types support broken. :\ -x Completion for array access, strings[0]. +[x]Differentiating between multiple statements on the same line. How to? Done with offset handling. +[x]- Cache predictions if current 'word' is increasing in length. If already showing predictions beginning with 's', for 'sa', remove extra completions, rather than recalculating predictions. Performance increase. +[x]Parameterized type support is broken. +[x]Array types, all all other types support broken. :\ +[x]Completion for array access, strings[0]. Finer details -* findDeclarations should support 3rd party classes too. It's about time. ;) -* printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of(done). Argument list as tooltip if possible? +[ ]findDeclarations should support 3rd party classes too. It's about time. ;) +[ ]printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of(done). Argument list as tooltip if possible? *! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. -* Diamond operator isn't supported for now. Bummer. +[ ]Diamond operator isn't supported for now. Bummer. -x Completion popup height is now dynamic, decreases to fit. -* Completion width can be dynamic, if really needed.. -x Icons for completions? Or overkill right now? -x 'Show Usage' menu item added -x Show declaring class for completions +[x]Completion popup height is now dynamic, decreases to fit. +[ ]Completion width can be dynamic, if really needed.. +[x]Icons for completions? Or overkill right now? +[x]'Show Usage' menu item added +[x]Show declaring class for completions x! Ignore String case while finding completion candidates -x Multiple 3rd party classes found in various packages. Not a chance no more. -x Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. Began working again by itself. Yay! -x Cursor positioning should be after the first ( if arguments present, else after () -x Display the type of Completion(method return type, variable type) in the popup. +[x]Multiple 3rd party classes found in various packages. Not a chance no more. +[x]Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. Began working again by itself. Yay! +[x]Cursor positioning should be after the first ( if arguments present, else after () +[x]Display the type of Completion(method return type, variable type) in the popup. - facing some issues for local types. Fixed. -x Sorted list of completion candidates - fields, then methods. It's unsorted presently. -x Reflection API - getMethods vs getDeclaredMethods. declared. -x Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? All set to implement -x Completion List should get hidden on hitting esc key +[x]Sorted list of completion candidates - fields, then methods. It's unsorted presently. +[x]Reflection API - getMethods vs getDeclaredMethods. declared. +[x]Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? All set to implement +[x]Completion List should get hidden on hitting esc key Offset Mapping ============== First major hurdle is offset mapping *! pde<->java code offset : precise conversion needed -* W.r.t PDE specific enhancements, things are almost working. There are some offset issues when multiple pde statements are in the same line, but I guess it's good enough for now to proceed ahead. Will keep a close watch for potential bugs. -x for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. -x This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration. -x Edge case - multiple statements in a single line -x PDE specific enhancements will also have to be tackled like int(), # literals. The length of the node returned needs to be modified to make up for extra chars added like PApplet.parseFloat, etc. Also the 2nd or futher pde enhancements in the same line means even the beginning offset would need adjustment. Meh. +[ ]W.r.t PDE specific enhancements, things are almost working. There are some offset issues when multiple pde statements are in the same line, but I guess it's good enough for now to proceed ahead. Will keep a close watch for potential bugs. +[x]for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. +[x]This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration. +[x]Edge case - multiple statements in a single line +[x]PDE specific enhancements will also have to be tackled like int(), # literals. The length of the node returned needs to be modified to make up for extra chars added like PApplet.parseFloat, etc. Also the 2nd or futher pde enhancements in the same line means even the beginning offset would need adjustment. Meh. Refactoring =========== -* Undo misbehaves here, handle carefully. -* Fails to rename the first defined global variable, if a javadoc comment precedes it. But owrds for single/multiline comments. Wth! -x New Name is validated. -x Ordered list in 'Show Usage' window -x Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully +[ ]Undo misbehaves here, handle carefully. +[ ]Fails to rename the first defined global variable, if a javadoc comment precedes it. But owrds for single/multiline comments. Wth! +[x]New Name is validated. +[x]Ordered list in 'Show Usage' window +[x]Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code. 1. First identify the declaration of the variable in the AST. We'll then make a list of all its occurrences. 2. DFS through the AST, for each (SimpleName)instance of the word in code, find if the matched word is the same one whose declaration we found. -x Edge Case: For renaming a TypeDeclaration, the declaration of SimpleName instance of the TD and it's constructor(s) aren't added to the list generated by DFS. So for renaming TD, will have to manually add the TD SimpleName and it's constructors' SimpleNames to the a list of declaration nodes that can be positively matched against. -x Renaming any constructor is equivalent to renaming the TD +[x]Edge Case: For renaming a TypeDeclaration, the declaration of SimpleName instance of the TD and it's constructor(s) aren't added to the list generated by DFS. So for renaming TD, will have to manually add the TD SimpleName and it's constructors' SimpleNames to the a list of declaration nodes that can be positively matched against. +[x]Renaming any constructor is equivalent to renaming the TD 3. Find corresponding PDE offsets of the SimpleNames, rename in each line. -x Edge Case: Need to take displaced offsets on a line, due to pde enhancements, into consideration. +[x]Edge Case: Need to take displaced offsets on a line, due to pde enhancements, into consideration. 4. All the changes in code would be made in a separate copy of the code(?). After all the renaming is done, allow it only if the new code compiles. Basically an undo should be possible in case of conflicts. -x Refactoring ui -x For now, user needs to highlight the name of the var, and then right-click -> Rename.. -x Handle saving. If sketch closed after renaming w/o saving find bugs. Done, marking the sketch as modified after renaming. +[x]Refactoring ui +[x]For now, user needs to highlight the name of the var, and then right-click -> Rename.. +[x]Handle saving. If sketch closed after renaming w/o saving find bugs. Done, marking the sketch as modified after renaming. Quick Navigation ================ *+ A silly bug where the name of the first field declaration isn't highlighted correctly. Seems to be happening if there's a javadoc or multiline comment near about the top. -x On OS X, Ctrl + Click is right mouse click, so implement Cmd + Click instead. isMetaDown()? -x Ctrl + Click on an element to scroll to its definition in code -x Local Vars -x Local Methods -x Local Classes -x Recursive lookup, a.b().c() -x Now highlihgting the declaration name, rather than the whole declaration. +[x]On OS X, Ctrl + Click is right mouse click, so implement Cmd + Click instead. isMetaDown()? +[x]Ctrl + Click on an element to scroll to its definition in code +[x]Local Vars +[x]Local Methods +[x]Local Classes +[x]Recursive lookup, a.b().c() +[x]Now highlihgting the declaration name, rather than the whole declaration. Sketch Outline ============== -x Show Sketch Outline Tree -x Filter stuff in text field -x Add icons - custom cell renderer +[x]Show Sketch Outline Tree +[x]Filter stuff in text field +[x]Add icons - custom cell renderer Suggestion for missing imports ============================== -* Find a more subtle way to suggest for imports. The current method is too troublesome. Randomly pops up offering suggestions. May intimidate beginners. +[ ]Find a more subtle way to suggest for imports. The current method is too troublesome. Randomly pops up offering suggestions. May intimidate beginners. 1. In compileCheck() in ECS, check if error message is of the type "__" cannot be resolved to a type. 2. Find the class name via astGen, and suggest import as a popup. -x Barebones functionality done. -x Add imports only to beginning of first tab. -x Search within contributed libraries folder -x Hide suggestion list before showing import suggestions -x Search within code folder of sketch +[x]Barebones functionality done. +[x]Add imports only to beginning of first tab. +[x]Search within contributed libraries folder +[x]Hide suggestion list before showing import suggestions +[x]Search within code folder of sketch Labels for Java elements ======================== -x Working for local code -* Need to modify getASTNodeAt to also fetch the type for predefined classes. -* Labels for predefined class objects -* Chaining support for labels +[x]Working for local code +[ ]Need to modify getASTNodeAt to also fetch the type for predefined classes. +[ ]Labels for predefined class objects +[ ]Chaining support for labels Synchronization =============== @@ -140,31 +140,31 @@ Gotta do it carefully between main thread, ECS Thread, and SwingWorker threads Fields that are concurrently accessed: ECS members: -x ArrayList problems - updated in ECS, accessed by ErrorBar.update() -x ArrayList classpathJars - updated in ECS, accessed by ASTGenerator.loadJars() -x hasErrors, syntaxErrors - Atomic Boolean -x boolean warningsEnabled - made it volatile -* CompilationUnit cu - updated in ECS, accessed a zillion times in ASTGenerator :'( +[x]ArrayList problems - updated in ECS, accessed by ErrorBar.update() +[x]ArrayList classpathJars - updated in ECS, accessed by ASTGenerator.loadJars() +[x]hasErrors, syntaxErrors - Atomic Boolean +[x]boolean warningsEnabled - made it volatile +[ ]CompilationUnit cu - updated in ECS, accessed a zillion times in ASTGenerator :'( General Stuff ============= -* [Critical] PermGen out of memory bug. Manually triggering GC after making the classloader null ensures permgen memory is reclaimed on editor exit. Max open window still limited by max permgen size. Also, added a classloadcounter in ECS to trigger GC periodically. +[ ][Critical] PermGen out of memory bug. Manually triggering GC after making the classloader null ensures permgen memory is reclaimed on editor exit. Max open window still limited by max permgen size. Also, added a classloadcounter in ECS to trigger GC periodically. https://github.com/processing/processing-experimental/issues/1 See: http://stackoverflow.com/questions/2095974/how-to-unload-a-already-loaded-class-in-java I'm making the classLoader null, but what about the classes loaded by ASTGen? Investigate. -x Disabling Error Checking disables predictions as well! Fixed. -x Added doc listener for text area updates -x Consult Ben on where to save preferences - main preferences.txt or custom one. - Main prefs file -x Save preferences to main preference.txt -x Hide breakpoint markers when Debugger isn't active -x Ensure gutter mouse handler is taken care of when hiding Debugger breakpoint bar. -x Ensure all editor windows are closed when editor is closed. -x Add a red marker near Errors label in console toggle, to indicate errors present in sketch. -x Add option for toggling debug output -x On Run/Debug Console is visible(ProblemsList hidden) -* Update wiki for Ctrl + H instead of Ctrl + J shortcuts -x update build.xml to produce dists -x Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc -x Add GitHub link to PDE X Menu +[x]Disabling Error Checking disables predictions as well! Fixed. +[x]Added doc listener for text area updates +[x]Consult Ben on where to save preferences - main preferences.txt or custom one. - Main prefs file +[x]Save preferences to main preference.txt +[x]Hide breakpoint markers when Debugger isn't active +[x]Ensure gutter mouse handler is taken care of when hiding Debugger breakpoint bar. +[x]Ensure all editor windows are closed when editor is closed. +[x]Add a red marker near Errors label in console toggle, to indicate errors present in sketch. +[x]Add option for toggling debug output +[x]On Run/Debug Console is visible(ProblemsList hidden) +[ ]Update wiki for Ctrl + H instead of Ctrl + J shortcuts +[x]update build.xml to produce dists +[x]Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc +[x]Add GitHub link to PDE X Menu From d1d11a24c190ea09e8d2615db7e9eb75a08a9d8d Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 2 Jun 2014 21:41:59 +0530 Subject: [PATCH 067/115] Added a new todo.txt --- todo.txt | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 todo.txt diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..acc6cc5 --- /dev/null +++ b/todo.txt @@ -0,0 +1,38 @@ +TODO List for PDE X +=================== + +This would also be a break down of my thought process and ideas as I tackle +various tasks. Previously, a different todo file was used for GSoC 2013. + +Manindra Moharana (me@mkmoharana.com) + +[ ]: Todo, [x] : Done, ? : Undecided Todo, ! : Critical, + : Minor Todo + + +Critical Bugs +------------- + +[ ] Better memory management. #1 + +[ ] Breakpoints in classes. #47 + + +Normal Bugs +----------- +[ ] Sketch NOC 6_09: steer PVector, doesn't show completion. +Classname in Template, doesn't scroll to decl. This is happening due certain +post processing offsets not being accounted for. "public void" + +Enhancements/New Features +------------------------- + +[ ] When viewing Outline View, instead of showing the beginning of the list, +it should select the current node element within which the cursor is presently positioned. + +[ ] Begin work on code snippets. + +[ ] JUnit Testing? + +[ ] Preferences panel + +[ ] Line Numbers From 973816e46768c26b6cf9bb872d40141577364d93 Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Mon, 2 Jun 2014 23:49:55 +0530 Subject: [PATCH 068/115] Basic fnctionality of autosave before running TODO: Add preferences Improve UI --- .../mode/experimental/DebugEditor.java | 80 ++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 3e4041e..7ab11b6 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -48,6 +48,7 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; import javax.swing.border.EtchedBorder; import javax.swing.table.TableModel; import javax.swing.text.Document; @@ -921,7 +922,7 @@ public boolean handleSaveAs() { vi.setTitle(getSketch().getName()); } // if file location has changed, update autosaver - autosaver.reloadAutosaveDir(); +// autosaver.reloadAutosaveDir(); return saved; } @@ -1071,6 +1072,83 @@ public TextArea textArea() { return ta; } + /** + * Grab current contents of the sketch window, advance the console, stop any + * other running sketches, auto-save the user's code... not in that order. + */ + @Override + public void prepareRun() { + super.prepareRun(); + try { + if (sketch.isUntitled()) { + if (handleSave(true)) + statusTimedNotice("Saved. Running...", 5); + else + statusTimedNotice("Save Canceled. Running anyway...", 5); + } + else if (sketch.isModified())// TODO: Fix ugly UI + // TODO: Add to preferences + { + Object[] options = { "Save", "Continue Without Saving" }; + int op = JOptionPane + .showOptionDialog( + new Frame(), + "There are unsaved changes in your sketch. Save before proceeding?", + this.getSketch().getName(), JOptionPane.YES_NO_OPTION, + JOptionPane.PLAIN_MESSAGE, null, options, options[0]); + if (op == JOptionPane.YES_OPTION) { + if (handleSave(true)) + statusTimedNotice("Saved. Running...", 5); + } + else + if (op == JOptionPane.NO_OPTION) + statusTimedNotice("Not saved. Running...", 5); + } + } catch (Exception e) { + // show the error as a message in the window + statusError(e); + } + } + + /** + * Shows a notice message in the editor status bar for a certain duration of + * time. + * + * @param msg + * @param secs + */ + public void statusTimedNotice(final String msg, final int secs) { +// EventQueue.invokeLater(new Runnable() { +// +// @Override +// public void run() { +// statusNotice(msg); +// try { +// Thread.sleep(secs * 1000); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// statusEmpty(); +// +// } +// }); + SwingWorker s = new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + statusNotice(msg); + try { + Thread.sleep(secs * 1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + statusEmpty(); + return null; + } + }; + s.execute(); + } + /** * Access variable inspector window. * From be0378ce54343fab28420c92b75c77e6998abc32 Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Wed, 4 Jun 2014 20:19:42 +0530 Subject: [PATCH 069/115] Added untitledAutoSave, autoSave to preferences --- .../mode/experimental/DebugEditor.java | 19 ++++--------------- .../mode/experimental/ExperimentalMode.java | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 7ab11b6..51e7341 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -1079,8 +1079,11 @@ public TextArea textArea() { @Override public void prepareRun() { super.prepareRun(); + if (!ExperimentalMode.autoSaveEnabled) + return; + try { - if (sketch.isUntitled()) { + if (sketch.isUntitled() && ExperimentalMode.untitledAutoSaveEnabled) { if (handleSave(true)) statusTimedNotice("Saved. Running...", 5); else @@ -1118,20 +1121,6 @@ else if (sketch.isModified())// TODO: Fix ugly UI * @param secs */ public void statusTimedNotice(final String msg, final int secs) { -// EventQueue.invokeLater(new Runnable() { -// -// @Override -// public void run() { -// statusNotice(msg); -// try { -// Thread.sleep(secs * 1000); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } -// statusEmpty(); -// -// } -// }); SwingWorker s = new SwingWorker() { @Override diff --git a/src/processing/mode/experimental/ExperimentalMode.java b/src/processing/mode/experimental/ExperimentalMode.java index 5b04896..b90b5a5 100755 --- a/src/processing/mode/experimental/ExperimentalMode.java +++ b/src/processing/mode/experimental/ExperimentalMode.java @@ -127,13 +127,15 @@ public File getContentFile(String path) { } volatile public static boolean errorCheckEnabled = true, warningsEnabled = true, - codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false; + codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false, + untitledAutoSaveEnabled = false, autoSaveEnabled = true; public static int autoSaveInterval = 3; //in minutes public static final String prefErrorCheck = "pdex.errorCheckEnabled", prefWarnings = "pdex.warningsEnabled", prefCodeCompletionEnabled = "pdex.ccEnabled", - prefDebugOP = "pdex.dbgOutput", prefErrorLogs = "pdex.writeErrorLogs", prefAutoSaveInterval = "pdex.autoSaveInterval"; + prefDebugOP = "pdex.dbgOutput", prefErrorLogs = "pdex.writeErrorLogs", prefAutoSaveInterval = "pdex.autoSaveInterval", + prefUntitledAutoSave = "pdex.autoSave.untitledAutoSaveEnabled", prefAutoSave = "pdex.autoSaveEnabled"; public void loadPreferences(){ log("Load PDEX prefs"); @@ -144,6 +146,8 @@ public void loadPreferences(){ DEBUG = Preferences.getBoolean(prefDebugOP); errorLogsEnabled = Preferences.getBoolean(prefErrorLogs); autoSaveInterval = Preferences.getInteger(prefAutoSaveInterval); + untitledAutoSaveEnabled = Preferences.getBoolean(prefUntitledAutoSave); + autoSaveEnabled = Preferences.getBoolean(prefAutoSave); } public void savePreferences(){ @@ -154,6 +158,8 @@ public void savePreferences(){ Preferences.setBoolean(prefDebugOP, DEBUG); Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); Preferences.setInteger(prefAutoSaveInterval,autoSaveInterval); + Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled); + Preferences.setBoolean(prefAutoSave,autoSaveEnabled); } public void ensurePrefsExist(){ @@ -169,6 +175,10 @@ public void ensurePrefsExist(){ Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); if(Preferences.get(prefAutoSaveInterval) == null) Preferences.setInteger(prefAutoSaveInterval,autoSaveInterval); + if(Preferences.get(prefUntitledAutoSave) == null) + Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled); + if(Preferences.get(prefAutoSave) == null) + Preferences.setBoolean(prefAutoSave,autoSaveEnabled); } From ce3ee9f79734fd94589f409aa7a5b3a1f228b9f8 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 4 Jun 2014 21:25:12 +0530 Subject: [PATCH 070/115] minor todo update --- todo.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/todo.txt b/todo.txt index acc6cc5..a56bb9b 100644 --- a/todo.txt +++ b/todo.txt @@ -19,9 +19,10 @@ Critical Bugs Normal Bugs ----------- -[ ] Sketch NOC 6_09: steer PVector, doesn't show completion. -Classname in Template, doesn't scroll to decl. This is happening due certain -post processing offsets not being accounted for. "public void" +[ ] Sketch NOC 6_09: steer PVector, doesn't show completion. #68 + +[x] Sketch NOC 6_09: Classname in Template, doesn't scroll to decl. This is +happening due certain post processing offsets not being accounted for - "public void" Enhancements/New Features ------------------------- From 628f3c230b90c8e0f0bcb54d43c7a0c31d117f15 Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Wed, 4 Jun 2014 22:10:40 +0530 Subject: [PATCH 071/115] Commenting out untitledAutoSave --- src/processing/mode/experimental/DebugEditor.java | 15 ++++++++------- .../mode/experimental/ExperimentalMode.java | 12 ++++++------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 51e7341..5ac4a98 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -1083,13 +1083,14 @@ public void prepareRun() { return; try { - if (sketch.isUntitled() && ExperimentalMode.untitledAutoSaveEnabled) { - if (handleSave(true)) - statusTimedNotice("Saved. Running...", 5); - else - statusTimedNotice("Save Canceled. Running anyway...", 5); - } - else if (sketch.isModified())// TODO: Fix ugly UI +// if (sketch.isUntitled() && ExperimentalMode.untitledAutoSaveEnabled) { +// if (handleSave(true)) +// statusTimedNotice("Saved. Running...", 5); +// else +// statusTimedNotice("Save Canceled. Running anyway...", 5); +// } +// else + if (sketch.isModified() && !sketch.isUntitled())// TODO: Fix ugly UI // TODO: Add to preferences { Object[] options = { "Save", "Continue Without Saving" }; diff --git a/src/processing/mode/experimental/ExperimentalMode.java b/src/processing/mode/experimental/ExperimentalMode.java index b90b5a5..29941ad 100755 --- a/src/processing/mode/experimental/ExperimentalMode.java +++ b/src/processing/mode/experimental/ExperimentalMode.java @@ -128,14 +128,14 @@ public File getContentFile(String path) { volatile public static boolean errorCheckEnabled = true, warningsEnabled = true, codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false, - untitledAutoSaveEnabled = false, autoSaveEnabled = true; + autoSaveEnabled = true; //,untitledAutoSaveEnabled; public static int autoSaveInterval = 3; //in minutes public static final String prefErrorCheck = "pdex.errorCheckEnabled", prefWarnings = "pdex.warningsEnabled", prefCodeCompletionEnabled = "pdex.ccEnabled", prefDebugOP = "pdex.dbgOutput", prefErrorLogs = "pdex.writeErrorLogs", prefAutoSaveInterval = "pdex.autoSaveInterval", - prefUntitledAutoSave = "pdex.autoSave.untitledAutoSaveEnabled", prefAutoSave = "pdex.autoSaveEnabled"; + prefAutoSave = "pdex.autoSaveEnabled"; //prefUntitledAutoSave = "pdex.autoSave.untitledAutoSaveEnabled" public void loadPreferences(){ log("Load PDEX prefs"); @@ -146,7 +146,7 @@ public void loadPreferences(){ DEBUG = Preferences.getBoolean(prefDebugOP); errorLogsEnabled = Preferences.getBoolean(prefErrorLogs); autoSaveInterval = Preferences.getInteger(prefAutoSaveInterval); - untitledAutoSaveEnabled = Preferences.getBoolean(prefUntitledAutoSave); +// untitledAutoSaveEnabled = Preferences.getBoolean(prefUntitledAutoSave); autoSaveEnabled = Preferences.getBoolean(prefAutoSave); } @@ -158,7 +158,7 @@ public void savePreferences(){ Preferences.setBoolean(prefDebugOP, DEBUG); Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); Preferences.setInteger(prefAutoSaveInterval,autoSaveInterval); - Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled); +// Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled); Preferences.setBoolean(prefAutoSave,autoSaveEnabled); } @@ -175,8 +175,8 @@ public void ensurePrefsExist(){ Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); if(Preferences.get(prefAutoSaveInterval) == null) Preferences.setInteger(prefAutoSaveInterval,autoSaveInterval); - if(Preferences.get(prefUntitledAutoSave) == null) - Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled); +// if(Preferences.get(prefUntitledAutoSave) == null) +// Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled); if(Preferences.get(prefAutoSave) == null) Preferences.setBoolean(prefAutoSave,autoSaveEnabled); } From 6ec10b8d0be5719a63bedd4ce581f8b503239a32 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Thu, 5 Jun 2014 02:27:33 +0530 Subject: [PATCH 072/115] some tidying up, tinkering around --- .../mode/experimental/ASTGenerator.java | 16 +++++++++++++--- .../mode/experimental/ErrorCheckerService.java | 11 +++++++---- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index ebda1f9..141c388 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -240,7 +240,7 @@ protected void setupGUI(){ /** * Toggle AST View window */ - public static final boolean SHOWAST = !true; + public static final boolean SHOWAST = true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { @@ -794,6 +794,13 @@ protected void trimCandidates(String newWord){ private AtomicBoolean predictionOngoing; + /** + * The main function that calculates possible code completion candidates + * + * @param word + * @param line + * @param lineStartNonWSOffset + */ public void preparePredictions(final String word, final int line, final int lineStartNonWSOffset) { if(predictionOngoing.get()) return; @@ -890,11 +897,14 @@ public void preparePredictions(final String word, final int line, final int line MethodInvocation mi = (MethodInvocation)testnode; System.out.println(mi.getName() + "," + mi.getExpression() + "," + mi.typeArguments().size()); } + + // find nearest ASTNode nearestNode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() .get(0)); - if (nearestNode == null) - //Make sure nearestNode is not NULL if couldn't find a closeset node + if (nearestNode == null) { + // Make sure nearestNode is not NULL if couldn't find a closeset node nearestNode = (ASTNode) compilationUnit.types().get(0); + } logE(lineNumber + " Nearest ASTNode to PRED " + getNodeAsString(nearestNode)); diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index c026a56..ead109c 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -36,11 +36,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.swing.JCheckBoxMenuItem; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.table.DefaultTableModel; -import javax.swing.text.AbstractDocument; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.IProblem; @@ -137,7 +135,7 @@ public class ErrorCheckerService implements Runnable{ /** * Compilation Unit for current sketch */ - protected CompilationUnit cu; + protected CompilationUnit cu, lastCorrectCu; /** * If true, compilation checker will be reloaded with updated classpath @@ -537,7 +535,10 @@ protected void syntaxCheck() { if (problems.length == 0) { syntaxErrors.set(false); containsErrors.set(false); + lastCorrectCu = cu; } else { + CompilationUnit cuTemp = null; + lastCorrectCu = cuTemp; syntaxErrors.set(true); containsErrors.set(true); } @@ -548,7 +549,8 @@ protected void syntaxCheck() { protected void compileCheck() { - // CU needs to be updated coz before compileCheck xqpreprocessor is run on the source code which makes some further changes + // CU needs to be updated coz before compileCheck xqpreprocessor is run on + // the source code which makes some further changes //TODO Check if this breaks things parser.setSource(sourceCode.toCharArray()); @@ -565,6 +567,7 @@ protected void compileCheck() { cu = (CompilationUnit) parser.createAST(null); else { synchronized (cu) { + if (!hasSyntaxErrors()) cu = (CompilationUnit) parser.createAST(null); } } From 4d6781774bbab6e2aabafc062e2575b2c5e06b95 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Thu, 5 Jun 2014 21:38:46 +0530 Subject: [PATCH 073/115] reverting changes before branching --- src/processing/mode/experimental/ErrorCheckerService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index ead109c..af6702a 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -135,7 +135,7 @@ public class ErrorCheckerService implements Runnable{ /** * Compilation Unit for current sketch */ - protected CompilationUnit cu, lastCorrectCu; + protected CompilationUnit cu; /** * If true, compilation checker will be reloaded with updated classpath @@ -535,10 +535,10 @@ protected void syntaxCheck() { if (problems.length == 0) { syntaxErrors.set(false); containsErrors.set(false); - lastCorrectCu = cu; + //lastCorrectCu = cu; } else { CompilationUnit cuTemp = null; - lastCorrectCu = cuTemp; + //lastCorrectCu = cuTemp; syntaxErrors.set(true); containsErrors.set(true); } @@ -567,7 +567,7 @@ protected void compileCheck() { cu = (CompilationUnit) parser.createAST(null); else { synchronized (cu) { - if (!hasSyntaxErrors()) + //if (!hasSyntaxErrors()) cu = (CompilationUnit) parser.createAST(null); } } From e258b916841082b099ea93c4f32106fd86aedfa5 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Thu, 5 Jun 2014 21:39:47 +0530 Subject: [PATCH 074/115] Added a 2nd CU --- .../mode/experimental/ErrorCheckerService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index af6702a..f75e744 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -135,7 +135,7 @@ public class ErrorCheckerService implements Runnable{ /** * Compilation Unit for current sketch */ - protected CompilationUnit cu; + protected CompilationUnit cu, lastCorrectCu; /** * If true, compilation checker will be reloaded with updated classpath @@ -535,10 +535,10 @@ protected void syntaxCheck() { if (problems.length == 0) { syntaxErrors.set(false); containsErrors.set(false); - //lastCorrectCu = cu; + lastCorrectCu = cu; } else { CompilationUnit cuTemp = null; - //lastCorrectCu = cuTemp; + lastCorrectCu = cuTemp; syntaxErrors.set(true); containsErrors.set(true); } @@ -567,8 +567,8 @@ protected void compileCheck() { cu = (CompilationUnit) parser.createAST(null); else { synchronized (cu) { - //if (!hasSyntaxErrors()) - cu = (CompilationUnit) parser.createAST(null); + if (!hasSyntaxErrors()) + cu = (CompilationUnit) parser.createAST(null); } } compilationUnitState = 2; From 41977f7876b26400570732924dd19798e92279df Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 6 Jun 2014 01:30:29 +0530 Subject: [PATCH 075/115] A possible solution to #68 --- .../mode/experimental/ASTGenerator.java | 4 +- .../experimental/ErrorCheckerService.java | 43 +++++++++++++++---- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 141c388..6415787 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -899,11 +899,11 @@ public void preparePredictions(final String word, final int line, final int line } // find nearest ASTNode - nearestNode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() + nearestNode = findClosestNode(lineNumber, (ASTNode) errorCheckerService.getLastCorrectCU().types() .get(0)); if (nearestNode == null) { // Make sure nearestNode is not NULL if couldn't find a closeset node - nearestNode = (ASTNode) compilationUnit.types().get(0); + nearestNode = (ASTNode) errorCheckerService.getLastCorrectCU().types().get(0); } logE(lineNumber + " Nearest ASTNode to PRED " + getNodeAsString(nearestNode)); diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index f75e744..1a507fb 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -135,7 +135,17 @@ public class ErrorCheckerService implements Runnable{ /** * Compilation Unit for current sketch */ - protected CompilationUnit cu, lastCorrectCu; + protected CompilationUnit cu; + + /** + * The Compilation Unit generated during compile check + */ + protected CompilationUnit compileCheckCU; + + /** + * This Compilation Unit points to the last error free CU + */ + protected CompilationUnit lastCorrectCU; /** * If true, compilation checker will be reloaded with updated classpath @@ -431,6 +441,9 @@ protected boolean checkCode() { // No syntax errors, proceed for compilation check, Stage 2. //if(hasSyntaxErrors()) astGenerator.buildAST(null); + if (!hasSyntaxErrors()) { + + } if (problems.length == 0 && editor.compilationCheckEnabled) { //mainClassOffset++; // just a hack. @@ -535,10 +548,11 @@ protected void syntaxCheck() { if (problems.length == 0) { syntaxErrors.set(false); containsErrors.set(false); - lastCorrectCu = cu; + parser.setSource(sourceCode.toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + parser.setCompilerOptions(options); + lastCorrectCU = (CompilationUnit) parser.createAST(null); } else { - CompilationUnit cuTemp = null; - lastCorrectCu = cuTemp; syntaxErrors.set(true); containsErrors.set(true); } @@ -563,14 +577,17 @@ protected void compileCheck() { options.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED); parser.setCompilerOptions(options); - if (cu == null) - cu = (CompilationUnit) parser.createAST(null); + if (compileCheckCU == null) + compileCheckCU = (CompilationUnit) parser.createAST(null); else { - synchronized (cu) { - if (!hasSyntaxErrors()) - cu = (CompilationUnit) parser.createAST(null); + synchronized (compileCheckCU) { + compileCheckCU = (CompilationUnit) parser.createAST(null); } } + if(!hasSyntaxErrors()) + lastCorrectCU = compileCheckCU; + cu = compileCheckCU; + compilationUnitState = 2; // Currently (Sept, 2012) I'm using Java's reflection api to load the // CompilationChecker class(from CompilationChecker.jar) that houses the @@ -722,6 +739,14 @@ public boolean accept(File file) { // log("Compilecheck, Done."); } + public CompilationUnit getLastCorrectCU(){ + return lastCorrectCU; + } + + public CompilationUnit getLatestCU(){ + return compileCheckCU; + } + private int loadClassCounter = 0; public URLClassLoader getSketchClassLoader() { loadClassCounter++; From 3b5deb07cfa032f3551455668d986514e95f9da8 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 6 Jun 2014 14:19:51 +0530 Subject: [PATCH 076/115] Dealing with better status messages --- .../mode/experimental/ASTGenerator.java | 23 +++++-- .../mode/experimental/DebugEditor.java | 60 +++++++++++++++++++ .../experimental/ErrorCheckerService.java | 9 +-- 3 files changed, 82 insertions(+), 10 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 6415787..00758a0 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1681,8 +1681,13 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, logE("DECLA: " + decl.getClass().getName()); nodeLabel = getLabelIfType(new ASTNodeWrapper(decl), (SimpleName) simpName); //retLabelString = getNodeAsString(decl); - } else + } else { logE("null"); + if(scrollOnly) { + editor.statusMessage("Can't find definition of " + simpName, + DebugEditor.STATUS_ERR); + } + } log(getNodeAsString(decl)); @@ -2027,19 +2032,22 @@ protected void refactorIt(){ public void handleShowUsage(){ log("Last clicked word:" + lastClickedWord); if(lastClickedWord == null && editor.ta.getSelectedText() == null){ - editor.statusError("Highlight the class/function/variable name first"); + editor.statusMessage("Highlight the class/function/variable name first" + , DebugEditor.STATUS_INFO); return; } if(errorCheckerService.hasSyntaxErrors()){ - editor.statusError("Can't perform action until syntax errors are fixed :("); + editor.statusMessage("Can't perform action until syntax errors are " + + "fixed :(", DebugEditor.STATUS_WARNING); return; } DefaultMutableTreeNode defCU = findAllOccurrences(); String selText = lastClickedWord == null ? editor.ta.getSelectedText() : lastClickedWord; if(defCU == null){ - editor.statusError("Can't locate definition of " + selText); + editor.statusMessage("Can't locate definition of " + selText, + DebugEditor.STATUS_ERR); return; } if(defCU.getChildCount() == 0) @@ -2291,12 +2299,15 @@ protected boolean isInstanceOfType(ASTNode node,ASTNode decl, String name){ public void handleRefactor(){ log("Last clicked word:" + lastClickedWord); if(lastClickedWord == null && editor.ta.getSelectedText() == null){ - editor.statusError("Highlight the class/function/variable name first"); + editor.statusMessage("Highlight the class/function/variable name first", + DebugEditor.STATUS_INFO); return; } if(errorCheckerService.hasSyntaxErrors()){ - editor.statusError("Can't perform action until syntax errors are fixed :("); + editor + .statusMessage("Can't perform action until syntax errors are fixed :(", + DebugEditor.STATUS_WARNING); return; } if (!frmRename.isVisible()){ diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 8813d5a..cd7ce4c 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -36,6 +36,8 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; @@ -48,6 +50,7 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; import javax.swing.border.EtchedBorder; import javax.swing.table.TableModel; import javax.swing.text.Document; @@ -1377,6 +1380,63 @@ public void statusHalted() { statusNotice("Debugger halted."); } + public static final int STATUS_EMPTY = 100, STATUS_COMPILER_ERR = 200, + STATUS_WARNING = 300, STATUS_INFO = 400, STATUS_ERR = 500; + public int statusMessageType = STATUS_EMPTY; + public String statusMessage; + public void statusMessage(final String what, int type){ + // Don't re-display the old message again + if(what.equals(statusMessage) && type == statusMessageType) { + return; + } + statusMessage = what; + statusMessageType = type; + switch (type) { + case STATUS_COMPILER_ERR: + case STATUS_ERR: + super.statusError(what); + break; + case STATUS_INFO: + case STATUS_WARNING: + statusNotice(what); + break; + } +// log("SW 0"); +// final Timer t = new Timer(); +// t.schedule(new TimerTask() { +// @Override +// public void run() { +// log("SW 1"); +// statusEmpty(); +// log("SW 2"); +// t.cancel(); +// } +// }, 2000); + SwingWorker s = new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + + try { + log("SW 1"); + Thread.sleep(2 * 1000); + log("SW 2"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + statusEmpty(); + return null; + } + }; + s.execute(); + } + + public void statusEmpty(){ + statusMessage = null; + statusMessageType = STATUS_EMPTY; + super.statusEmpty(); + } + ErrorCheckerService errorCheckerService; /** diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index 1a507fb..0c7fbf5 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -1005,12 +1005,14 @@ public void updateEditorStatus() { if (emarker.getProblem().getLineNumber() == editor.getTextArea() .getCaretLine() + 1) { if (emarker.getType() == ErrorMarker.Warning) { - editor.statusNotice(emarker.getProblem().getMessage()); + editor.statusMessage(emarker.getProblem().getMessage(), + DebugEditor.STATUS_INFO); //+ " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); //TODO: this is temporary } else { - editor.statusError(emarker.getProblem().getMessage()); + editor.statusMessage(emarker.getProblem().getMessage(), + DebugEditor.STATUS_COMPILER_ERR); //+ " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); } return; @@ -1019,8 +1021,7 @@ public void updateEditorStatus() { } // This line isn't an error line anymore, so probably just clear it - if (editor.getStatusMode() == EditorStatus.ERR - || editor.getStatusMode() == EditorStatus.NOTICE) { + if (editor.statusMessageType == DebugEditor.STATUS_COMPILER_ERR) { editor.statusEmpty(); return; } From f2b9efac8bfe343940f5946180be70a38b03f02a Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 6 Jun 2014 14:27:32 +0530 Subject: [PATCH 077/115] A possible solution to #65 --- .../mode/experimental/ASTGenerator.java | 2 +- .../mode/experimental/DebugEditor.java | 27 +++++++------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 00758a0..d4fdbff 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -240,7 +240,7 @@ protected void setupGUI(){ /** * Toggle AST View window */ - public static final boolean SHOWAST = true; + public static final boolean SHOWAST = !true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index cd7ce4c..19eaa3e 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -1386,10 +1386,12 @@ public void statusHalted() { public String statusMessage; public void statusMessage(final String what, int type){ // Don't re-display the old message again - if(what.equals(statusMessage) && type == statusMessageType) { - return; + if(type != STATUS_EMPTY) { + if(what.equals(statusMessage) && type == statusMessageType) { + return; + } } - statusMessage = what; + statusMessage = new String(what); statusMessageType = type; switch (type) { case STATUS_COMPILER_ERR: @@ -1401,26 +1403,15 @@ public void statusMessage(final String what, int type){ statusNotice(what); break; } -// log("SW 0"); -// final Timer t = new Timer(); -// t.schedule(new TimerTask() { -// @Override -// public void run() { -// log("SW 1"); -// statusEmpty(); -// log("SW 2"); -// t.cancel(); -// } -// }, 2000); + // Don't need to clear compiler error messages + if(type == STATUS_COMPILER_ERR) return; + + // Clear the message after a delay SwingWorker s = new SwingWorker() { - @Override protected Void doInBackground() throws Exception { - try { - log("SW 1"); Thread.sleep(2 * 1000); - log("SW 2"); } catch (InterruptedException e) { e.printStackTrace(); } From 8e872eb9c3ccdd3e347e3a54b67104e54c9a0d56 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 6 Jun 2014 14:38:43 +0530 Subject: [PATCH 078/115] Fixes #69 --- src/processing/mode/experimental/ASTGenerator.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index d4fdbff..3e9d608 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1684,7 +1684,7 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, } else { logE("null"); if(scrollOnly) { - editor.statusMessage("Can't find definition of " + simpName, + editor.statusMessage(simpName + " is not defined in this sketch", DebugEditor.STATUS_ERR); } } @@ -2310,6 +2310,15 @@ public void handleRefactor(){ DebugEditor.STATUS_WARNING); return; } + + DefaultMutableTreeNode defCU = findAllOccurrences(); + String selText = lastClickedWord == null ? editor.ta.getSelectedText() + : lastClickedWord; + if(defCU == null){ + editor.statusMessage(selText + " isn't defined in this sketch, so it can't" + + " be renamed", DebugEditor.STATUS_ERR); + return; + } if (!frmRename.isVisible()){ frmRename.setLocation(editor.getX() + (editor.getWidth() - frmRename.getWidth()) / 2, From 86411f04ac93bc9444598f8bab7a86aa3a155f77 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 6 Jun 2014 17:06:41 +0530 Subject: [PATCH 079/115] todo formatting --- todo.txt | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/todo.txt b/todo.txt index a56bb9b..af2cc8d 100644 --- a/todo.txt +++ b/todo.txt @@ -12,28 +12,29 @@ Manindra Moharana (me@mkmoharana.com) Critical Bugs ------------- -[ ] Better memory management. #1 +-[ ] Better memory management. #1 -[ ] Breakpoints in classes. #47 +-[ ] Breakpoints in classes. #47 Normal Bugs ----------- -[ ] Sketch NOC 6_09: steer PVector, doesn't show completion. #68 +-[x] Sketch NOC 6_09: steer PVector, doesn't show completion. #68 -[x] Sketch NOC 6_09: Classname in Template, doesn't scroll to decl. This is +-[ ] Sketch NOC 6_09: Classname in Template, doesn't scroll to decl. This is happening due certain post processing offsets not being accounted for - "public void" Enhancements/New Features ------------------------- -[ ] When viewing Outline View, instead of showing the beginning of the list, -it should select the current node element within which the cursor is presently positioned. +-[ ] When viewing Outline View, instead of showing the beginning of the list, +it should select the current node element within which the cursor is presently +positioned. -[ ] Begin work on code snippets. +-[ ] Begin work on code snippets. -[ ] JUnit Testing? +-[ ] JUnit Testing? -[ ] Preferences panel +-[ ] Preferences panel -[ ] Line Numbers +-[ ] Line Numbers From f2a0ed27061a3cd5b06d2ab86b495f10fe2c9dbc Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 6 Jun 2014 18:47:59 +0530 Subject: [PATCH 080/115] hey look, sweeping changes --- .../mode/experimental/ASTGenerator.java | 133 ++++++++++-------- .../mode/experimental/OffsetMatcher.java | 26 ++-- .../mode/experimental/TextAreaPainter.java | 5 +- 3 files changed, 90 insertions(+), 74 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 3e9d608..97f9566 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1574,7 +1574,7 @@ public void scrollToDeclaration(int lineNumber, String name, int offset) { */ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, boolean scrollOnly) { - + int originalLN = lineNumber - errorCheckerService.mainClassOffset; log("----getASTNodeAt---- CU State: " + errorCheckerService.compilationUnitState); if (errorCheckerService != null) { editor = errorCheckerService.getEditor(); @@ -1596,67 +1596,80 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, String nodeLabel = null; String nameOfNode = null; // The node name which is to be scrolled to if (lineNode != null) { + // Being test + + //ASTNodeWrapper lineNodeWrap = new ASTNodeWrapper(lineNode); + String pdeCodeLine = errorCheckerService.getPDECodeAtLine(editor + .getSketch().getCurrentCodeIndex(), originalLN); + String javaCodeLine = getJavaSourceCodeline(lineNumber); - // Some delicate offset handling follows. - ASTNodeWrapper lineNodeWrap = new ASTNodeWrapper(lineNode); - int altOff = offset; - int ret[][] = lineNodeWrap.getOffsetMapping(errorCheckerService); - if(ret != null){ - altOff = 0; - int javaCodeMap[] = ret[0], pdeCodeMap[] = ret[1]; - - for (; altOff < javaCodeMap.length; altOff++) { - if (javaCodeMap[altOff] == pdeCodeMap[offset]) { - break; - } - } - } - log("FLON2: " + lineNumber + " LN start pos " - + lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); - /* - * Now I need to see if multiple statements exist with this same line number - * If that's the case, I need to ensure the offset is right. - */ - ASTNode parLineNode = lineNode.getParent(); - - Iterator it = parLineNode - .structuralPropertiesForType().iterator(); - boolean flag = true; - int offAdjust = 0; - while (it.hasNext() && flag) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); - if (prop.isChildListProperty()) { - List nodelist = (List) parLineNode - .getStructuralProperty(prop); - for (ASTNode cnode : nodelist) { - if (getLineNumber(cnode) == lineNumber) { - if (cnode.getStartPosition() <= lineNode.getStartPosition() - + altOff - && cnode.getStartPosition() + cnode.getLength() > lineNode - .getStartPosition() + altOff) { - log(cnode); - offAdjust = cnode.getStartPosition() - lineNode.getStartPosition(); - lineNode = cnode; - altOff -= offAdjust; - flag = false; - break; - } - - } - } - } - } - log("FLON3 new alt off: " + altOff); - ASTNode simpName = pinpointOnLine(lineNode, altOff, - lineNode.getStartPosition(), name); + log(originalLN + " PDE :" + pdeCodeLine); + log("JAVA:" + javaCodeLine); + log("Clicked on: " + name + " start offset: " + offset); + OffsetMatcher ofm = new OffsetMatcher(pdeCodeLine, javaCodeLine); + int javaOffset = ofm.getJavaOffForPdeOff(offset, name.length()); - if(simpName == null){ //Added while fixing #51 - log("pinpointOnLine 1+++> " + simpName); - simpName = pinpointOnLine(lineNode.getParent(), altOff, - lineNode.getStartPosition(), name); - } - log("pinpointOnLine 2+++> " + simpName); + ASTNode simpName = null; + if(simpName == null) return null; + // End test +// int altOff = offset; +// int ret[][] = lineNodeWrap.getOffsetMapping(errorCheckerService); +// if(ret != null){ +// altOff = 0; +// int javaCodeMap[] = ret[0], pdeCodeMap[] = ret[1]; +// +// for (; altOff < javaCodeMap.length; altOff++) { +// if (javaCodeMap[altOff] == pdeCodeMap[offset]) { +// break; +// } +// } +// } +// log("FLON2: " + lineNumber + " LN start pos " +// + lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); +// /* +// * Now I need to see if multiple statements exist with this same line number +// * If that's the case, I need to ensure the offset is right. +// */ +// ASTNode parLineNode = lineNode.getParent(); +// +// Iterator it = parLineNode +// .structuralPropertiesForType().iterator(); +// boolean flag = true; +// int offAdjust = 0; +// while (it.hasNext() && flag) { +// StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it +// .next(); +// if (prop.isChildListProperty()) { +// List nodelist = (List) parLineNode +// .getStructuralProperty(prop); +// for (ASTNode cnode : nodelist) { +// if (getLineNumber(cnode) == lineNumber) { +// if (cnode.getStartPosition() <= lineNode.getStartPosition() +// + altOff +// && cnode.getStartPosition() + cnode.getLength() > lineNode +// .getStartPosition() + altOff) { +// log(cnode); +// offAdjust = cnode.getStartPosition() - lineNode.getStartPosition(); +// lineNode = cnode; +// altOff -= offAdjust; +// flag = false; +// break; +// } +// +// } +// } +// } +// } +// log("FLON3 new alt off: " + altOff); +// ASTNode simpName = pinpointOnLine(lineNode, altOff, +// lineNode.getStartPosition(), name); +// +// if(simpName == null){ //Added while fixing #51 +// log("pinpointOnLine 1+++> " + simpName); +// simpName = pinpointOnLine(lineNode.getParent(), altOff, +// lineNode.getStartPosition(), name); +// } +// log("pinpointOnLine 2+++> " + simpName); if(simpName == null && lineNode instanceof SimpleName){ switch (lineNode.getParent().getNodeType()) { case ASTNode.TYPE_DECLARATION: diff --git a/src/processing/mode/experimental/OffsetMatcher.java b/src/processing/mode/experimental/OffsetMatcher.java index d5aff52..d0707a9 100644 --- a/src/processing/mode/experimental/OffsetMatcher.java +++ b/src/processing/mode/experimental/OffsetMatcher.java @@ -52,10 +52,10 @@ public OffsetMatcher(String pdeCode, String javaCode) { // log("PDE <-> Java"); for (int i = 0; i < offsetMatch.size(); i++) { -// log(offsetMatch.get(i).pdeOffset + " <-> " -// + offsetMatch.get(i).javaOffset + -// ", " + word1.charAt(offsetMatch.get(i).pdeOffset) -// + " <-> " + word2.charAt(offsetMatch.get(i).javaOffset)); + log(offsetMatch.get(i).pdeOffset + " <-> " + + offsetMatch.get(i).javaOffset + + ", " + word1.charAt(offsetMatch.get(i).pdeOffset) + + " <-> " + word2.charAt(offsetMatch.get(i).javaOffset)); } // log("Length " + offsetMatch.size()); } @@ -237,17 +237,19 @@ public static void main(String[] args) { // minDistance("c = #qwerty;", "c = 0xffqwerty;"); OffsetMatcher a; - a = new OffsetMatcher("int a = int(can); int ball;", - "int a = PApplet.parseInt(can); int ball;"); - a.getPdeOffForJavaOff(25, 3); - a.getJavaOffForPdeOff(12, 3); +// a = new OffsetMatcher("int a = int(can); int ball;", +// "int a = PApplet.parseInt(can); int ball;"); +// a.getPdeOffForJavaOff(25, 3); +// a.getJavaOffForPdeOff(12, 3); // minDistance("static void main(){;", "public static void main(){;"); // minDistance("#bb00aa", "0xffbb00aa"); - //a.minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); + a = new OffsetMatcher("void test(ArrayList boids){", + "public void test(ArrayList boids){"); + a.getJavaOffForPdeOff(20,4); log("--"); - a = new OffsetMatcher("color abc = #qwerty;", "int abc = 0xffqwerty;"); - a.getPdeOffForJavaOff(4, 3); - a.getJavaOffForPdeOff(6, 3); +// a = new OffsetMatcher("color abc = #qwerty;", "int abc = 0xffqwerty;"); +// a.getPdeOffForJavaOff(4, 3); +// a.getJavaOffForPdeOff(6, 3); // distance("c = #bb00aa;", "c = 0xffbb00aa;"); } } diff --git a/src/processing/mode/experimental/TextAreaPainter.java b/src/processing/mode/experimental/TextAreaPainter.java index 4e8b888..30f031b 100644 --- a/src/processing/mode/experimental/TextAreaPainter.java +++ b/src/processing/mode/experimental/TextAreaPainter.java @@ -101,7 +101,7 @@ else if (s.length() == 0) else { int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; log("x="+x); - int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line); + int xLS = off - ta.getLineStartOffset(line); if (x < 0 || x >= s.length()) return; String word = s.charAt(x) + ""; @@ -116,6 +116,7 @@ else if (s.length() == 0) if (x1 >= 0 && x1 < s.length()) { if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') { word = s.charAt(x1--) + word; + xLS--; } else x1 = -1; } else @@ -140,7 +141,7 @@ else if (s.length() == 0) } if (Character.isDigit(word.charAt(0))) return; - + log(errorCheckerService.mainClassOffset + line + "|" + line + "| offset " + xLS + word + " <= \n"); errorCheckerService.getASTGenerator().scrollToDeclaration(line From 875cad0f26e3a3e9e3c5d7126321bf3a965d44a9 Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Sun, 8 Jun 2014 12:31:10 +0530 Subject: [PATCH 081/115] Done with adding autoSave to PDE X --- .../mode/experimental/DebugEditor.java | 140 +++++++++++++----- .../mode/experimental/ExperimentalMode.java | 14 +- 2 files changed, 117 insertions(+), 37 deletions(-) diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 5ac4a98..6405894 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -22,7 +22,10 @@ import java.awt.CardLayout; import java.awt.Color; import java.awt.Component; +import java.awt.Container; import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Font; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -40,8 +43,14 @@ import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.BorderFactory; import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; +import javax.swing.JDialog; +import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; @@ -49,6 +58,7 @@ import javax.swing.JScrollPane; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; +import javax.swing.border.Border; import javax.swing.border.EtchedBorder; import javax.swing.table.TableModel; import javax.swing.text.Document; @@ -59,6 +69,7 @@ import processing.app.EditorState; import processing.app.EditorToolbar; import processing.app.Mode; +import processing.app.Preferences; import processing.app.Sketch; import processing.app.SketchCode; import processing.app.Toolkit; @@ -922,7 +933,7 @@ public boolean handleSaveAs() { vi.setTitle(getSketch().getName()); } // if file location has changed, update autosaver -// autosaver.reloadAutosaveDir(); + autosaver.reloadAutosaveDir(); return saved; } @@ -1080,36 +1091,95 @@ public TextArea textArea() { public void prepareRun() { super.prepareRun(); if (!ExperimentalMode.autoSaveEnabled) - return; - + return; + try { -// if (sketch.isUntitled() && ExperimentalMode.untitledAutoSaveEnabled) { -// if (handleSave(true)) -// statusTimedNotice("Saved. Running...", 5); -// else -// statusTimedNotice("Save Canceled. Running anyway...", 5); -// } -// else - if (sketch.isModified() && !sketch.isUntitled())// TODO: Fix ugly UI - // TODO: Add to preferences - { - Object[] options = { "Save", "Continue Without Saving" }; - int op = JOptionPane - .showOptionDialog( - new Frame(), - "There are unsaved changes in your sketch. Save before proceeding?", - this.getSketch().getName(), JOptionPane.YES_NO_OPTION, - JOptionPane.PLAIN_MESSAGE, null, options, options[0]); - if (op == JOptionPane.YES_OPTION) { - if (handleSave(true)) - statusTimedNotice("Saved. Running...", 5); - } - else - if (op == JOptionPane.NO_OPTION) - statusTimedNotice("Not saved. Running...", 5); + // if (sketch.isUntitled() && + // ExperimentalMode.untitledAutoSaveEnabled) { + // if (handleSave(true)) + // statusTimedNotice("Saved. Running...", 5); + // else + // statusTimedNotice("Save Canceled. Running anyway...", 5); + // } + // else + if (sketch.isModified() && !sketch.isUntitled()) { + if (ExperimentalMode.autoSavePromptEnabled) { + final JDialog autoSaveDialog = new JDialog( + base.getActiveEditor(), this.getSketch().getName(), + true); + Container container = autoSaveDialog.getContentPane(); + + JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createEmptyBorder(4, 0, 2, 2)); + panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); + + JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.LEFT)); + JLabel label = new JLabel( + " There are unsaved" + + " changes in your sketch.
" + + "    Do you want to save it before" + + " running? "); + label.setFont(new Font(label.getFont().getName(), + Font.PLAIN, label.getFont().getSize() + 1)); + panel1.add(label); + panel.add(panel1); + final JCheckBox dontRedisplay = new JCheckBox( + "Remember this decision"); + + panel1 = new JPanel(new FlowLayout( + FlowLayout.CENTER, 8, 2)); + JButton button = new JButton("Save and Run"); + button.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (handleSave(true)) + statusTimedNotice("Saved. Running...", 5); + if (dontRedisplay.isSelected()) { + ExperimentalMode.autoSavePromptEnabled = !dontRedisplay + .isSelected(); + ExperimentalMode.defaultAutoSaveEnabled = true; + dmode.savePreferences(); + } + autoSaveDialog.dispose(); + } + }); + panel1.add(button); + button = new JButton("Run, Don't Save"); + button.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + statusTimedNotice("Not saved. Running...", 5); + if (dontRedisplay.isSelected()) { + ExperimentalMode.autoSavePromptEnabled = !dontRedisplay + .isSelected(); + ExperimentalMode.defaultAutoSaveEnabled = false; + dmode.savePreferences(); + } + autoSaveDialog.dispose(); + } + }); + panel1.add(button); + panel.add(panel1); + + panel1 = new JPanel(); + panel1.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0)); + panel1.add(dontRedisplay); + panel.add(panel1); + + container.add(panel); + + autoSaveDialog.setResizable(false); + autoSaveDialog.pack(); + autoSaveDialog + .setLocationRelativeTo(base.getActiveEditor()); + autoSaveDialog.setVisible(true); + + } else if (ExperimentalMode.defaultAutoSaveEnabled) + handleSave(true); } } catch (Exception e) { - // show the error as a message in the window statusError(e); } } @@ -1126,13 +1196,13 @@ public void statusTimedNotice(final String msg, final int secs) { @Override protected Void doInBackground() throws Exception { - statusNotice(msg); - try { - Thread.sleep(secs * 1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - statusEmpty(); + statusNotice(msg); + try { + Thread.sleep(secs * 1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + statusEmpty(); return null; } }; diff --git a/src/processing/mode/experimental/ExperimentalMode.java b/src/processing/mode/experimental/ExperimentalMode.java index 29941ad..26cb99f 100755 --- a/src/processing/mode/experimental/ExperimentalMode.java +++ b/src/processing/mode/experimental/ExperimentalMode.java @@ -128,14 +128,16 @@ public File getContentFile(String path) { volatile public static boolean errorCheckEnabled = true, warningsEnabled = true, codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false, - autoSaveEnabled = true; //,untitledAutoSaveEnabled; + autoSaveEnabled = true, autoSavePromptEnabled = true, + defaultAutoSaveEnabled = true; // ,untitledAutoSaveEnabled; public static int autoSaveInterval = 3; //in minutes public static final String prefErrorCheck = "pdex.errorCheckEnabled", prefWarnings = "pdex.warningsEnabled", prefCodeCompletionEnabled = "pdex.ccEnabled", prefDebugOP = "pdex.dbgOutput", prefErrorLogs = "pdex.writeErrorLogs", prefAutoSaveInterval = "pdex.autoSaveInterval", - prefAutoSave = "pdex.autoSaveEnabled"; //prefUntitledAutoSave = "pdex.autoSave.untitledAutoSaveEnabled" + prefAutoSave = "pdex.autoSave.autoSaveEnabled", // prefUntitledAutoSave = "pdex.autoSave.untitledAutoSaveEnabled", + prefAutoSavePrompt = "pdex.autoSave.promptDisplay", prefDefaultAutoSave = "pdex.autoSave.autoSaveByDefault"; public void loadPreferences(){ log("Load PDEX prefs"); @@ -148,6 +150,8 @@ public void loadPreferences(){ autoSaveInterval = Preferences.getInteger(prefAutoSaveInterval); // untitledAutoSaveEnabled = Preferences.getBoolean(prefUntitledAutoSave); autoSaveEnabled = Preferences.getBoolean(prefAutoSave); + autoSavePromptEnabled = Preferences.getBoolean(prefAutoSavePrompt); + defaultAutoSaveEnabled = Preferences.getBoolean(prefDefaultAutoSave); } public void savePreferences(){ @@ -160,6 +164,8 @@ public void savePreferences(){ Preferences.setInteger(prefAutoSaveInterval,autoSaveInterval); // Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled); Preferences.setBoolean(prefAutoSave,autoSaveEnabled); + Preferences.setBoolean(prefAutoSavePrompt, autoSavePromptEnabled); + Preferences.setBoolean(prefDefaultAutoSave, defaultAutoSaveEnabled); } public void ensurePrefsExist(){ @@ -179,6 +185,10 @@ public void ensurePrefsExist(){ // Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled); if(Preferences.get(prefAutoSave) == null) Preferences.setBoolean(prefAutoSave,autoSaveEnabled); + if(Preferences.get(prefAutoSavePrompt) == null) + Preferences.setBoolean(prefAutoSavePrompt,autoSavePromptEnabled); + if(Preferences.get(prefDefaultAutoSave) == null) + Preferences.setBoolean(prefDefaultAutoSave,defaultAutoSaveEnabled); } From f2c9a25bf7248e9173d9f109082543366686f92f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 9 Jun 2014 20:38:01 +0530 Subject: [PATCH 082/115] Initial dfs name search impl --- .../mode/experimental/ASTGenerator.java | 62 +++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 97f9566..a0f2f98 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -240,7 +240,7 @@ protected void setupGUI(){ /** * Toggle AST View window */ - public static final boolean SHOWAST = !true; + public static final boolean SHOWAST = true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { @@ -1607,8 +1607,11 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, log("JAVA:" + javaCodeLine); log("Clicked on: " + name + " start offset: " + offset); OffsetMatcher ofm = new OffsetMatcher(pdeCodeLine, javaCodeLine); - int javaOffset = ofm.getJavaOffForPdeOff(offset, name.length()); - + int javaOffset = ofm.getJavaOffForPdeOff(offset, name.length()) + + lineNode.getStartPosition(); + log("JAVA ast offset: " + (javaOffset)); + dfsLookForASTNode(errorCheckerService.getLatestCU(), name, + javaOffset, javaOffset + name.length() - 1); ASTNode simpName = null; if(simpName == null) return null; // End test @@ -2224,7 +2227,8 @@ public void dfsNameOnly(DefaultMutableTreeNode tnode,ASTNode decl, String name) ASTNodeWrapper awnode = (ASTNodeWrapper) cnode.getUserObject(); // log("Visiting: " + getNodeAsString(awnode.getNode())); if(isInstanceOfType(awnode.getNode(), decl, name)){ - int val[] = errorCheckerService.JavaToPdeOffsets(awnode.getLineNumber(), 0); + int val[] = errorCheckerService + .JavaToPdeOffsets(awnode.getLineNumber(), 0); tnode.add(new DefaultMutableTreeNode(new ASTNodeWrapper(awnode .getNode(), "Line " + (val[1] + 1) + " | Tab: " + editor.getSketch().getCode(val[0]).getPrettyName()))); @@ -2233,6 +2237,56 @@ public void dfsNameOnly(DefaultMutableTreeNode tnode,ASTNode decl, String name) } } + public ASTNode dfsLookForASTNode(ASTNode root, String name, int startOffset, + int endOffset) { + log("dfsLookForASTNode() lookin for " + name + " Offsets: " + startOffset + + "," + endOffset); + Stack stack = new Stack(); + stack.push(root); + + while (!stack.isEmpty()) { + ASTNode node = (ASTNode) stack.pop(); + log("Popped from stack: " + getNodeAsString(node)); + Iterator it = node + .structuralPropertiesForType().iterator(); + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode temp = (ASTNode) node.getStructuralProperty(prop); + if (temp.getStartPosition() <= startOffset + && (temp.getStartPosition() + temp.getLength()) >= endOffset) { + if(temp instanceof SimpleName){ + if(name.equals(temp.toString())){ + log("Found simplename: " + getNodeAsString(temp)); + return temp; + } + } + else + stack.push(temp); + log("Pushed onto stack: " + getNodeAsString(temp)); + } + } + } + else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode temp : nodelist) { + if (temp.getStartPosition() <= startOffset + && (temp.getStartPosition() + temp.getLength()) >= endOffset) { + stack.push(temp); + log("Pushed onto stack: " + getNodeAsString(temp)); + } + } + } + } + } + log("dfsLookForASTNode() not found " + name); + return null; + } + protected SketchOutline sketchOutline; protected void showSketchOutline(){ sketchOutline = new SketchOutline(codeTree, errorCheckerService); From c9f7f3e4e4d49d30b2219c1dd71b6de90e70760f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 9 Jun 2014 21:02:04 +0530 Subject: [PATCH 083/115] non white space offset it is --- src/processing/mode/experimental/ASTGenerator.java | 6 ++++-- src/processing/mode/experimental/TextAreaPainter.java | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index a0f2f98..536cf6f 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1603,7 +1603,7 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, .getSketch().getCurrentCodeIndex(), originalLN); String javaCodeLine = getJavaSourceCodeline(lineNumber); - log(originalLN + " PDE :" + pdeCodeLine); + log(originalLN + " Original Line num.\nPDE :" + pdeCodeLine); log("JAVA:" + javaCodeLine); log("Clicked on: " + name + " start offset: " + offset); OffsetMatcher ofm = new OffsetMatcher(pdeCodeLine, javaCodeLine); @@ -1611,7 +1611,7 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, + lineNode.getStartPosition(); log("JAVA ast offset: " + (javaOffset)); dfsLookForASTNode(errorCheckerService.getLatestCU(), name, - javaOffset, javaOffset + name.length() - 1); + javaOffset, javaOffset + name.length()); ASTNode simpName = null; if(simpName == null) return null; // End test @@ -2259,10 +2259,12 @@ public ASTNode dfsLookForASTNode(ASTNode root, String name, int startOffset, if (temp.getStartPosition() <= startOffset && (temp.getStartPosition() + temp.getLength()) >= endOffset) { if(temp instanceof SimpleName){ + log("Found possible simplename: " + getNodeAsString(temp)); if(name.equals(temp.toString())){ log("Found simplename: " + getNodeAsString(temp)); return temp; } + log("Bummer, didn't match"); } else stack.push(temp); diff --git a/src/processing/mode/experimental/TextAreaPainter.java b/src/processing/mode/experimental/TextAreaPainter.java index 30f031b..d7571fb 100644 --- a/src/processing/mode/experimental/TextAreaPainter.java +++ b/src/processing/mode/experimental/TextAreaPainter.java @@ -101,7 +101,7 @@ else if (s.length() == 0) else { int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; log("x="+x); - int xLS = off - ta.getLineStartOffset(line); + int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line); if (x < 0 || x >= s.length()) return; String word = s.charAt(x) + ""; From 6de00b391173eb0d49c67c6d8536127f7b4ba1b7 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 9 Jun 2014 21:04:38 +0530 Subject: [PATCH 084/115] things look good, real good --- .../mode/experimental/ASTGenerator.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 536cf6f..51d2303 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -2246,7 +2246,7 @@ public ASTNode dfsLookForASTNode(ASTNode root, String name, int startOffset, while (!stack.isEmpty()) { ASTNode node = (ASTNode) stack.pop(); - log("Popped from stack: " + getNodeAsString(node)); + //log("Popped from stack: " + getNodeAsString(node)); Iterator it = node .structuralPropertiesForType().iterator(); while (it.hasNext()) { @@ -2259,7 +2259,6 @@ public ASTNode dfsLookForASTNode(ASTNode root, String name, int startOffset, if (temp.getStartPosition() <= startOffset && (temp.getStartPosition() + temp.getLength()) >= endOffset) { if(temp instanceof SimpleName){ - log("Found possible simplename: " + getNodeAsString(temp)); if(name.equals(temp.toString())){ log("Found simplename: " + getNodeAsString(temp)); return temp; @@ -2268,7 +2267,7 @@ public ASTNode dfsLookForASTNode(ASTNode root, String name, int startOffset, } else stack.push(temp); - log("Pushed onto stack: " + getNodeAsString(temp)); + //log("Pushed onto stack: " + getNodeAsString(temp)); } } } @@ -2280,6 +2279,16 @@ else if (prop.isChildListProperty()) { && (temp.getStartPosition() + temp.getLength()) >= endOffset) { stack.push(temp); log("Pushed onto stack: " + getNodeAsString(temp)); + if(temp instanceof SimpleName){ + if(name.equals(temp.toString())){ + log("Found simplename: " + getNodeAsString(temp)); + return temp; + } + log("Bummer, didn't match"); + } + else + stack.push(temp); + //log("Pushed onto stack: " + getNodeAsString(temp)); } } } From 0a33d949e32a05a76152ac05ad933a1aa45aa5df Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 9 Jun 2014 21:32:53 +0530 Subject: [PATCH 085/115] code cleanup --- .../mode/experimental/ASTGenerator.java | 71 ++----------------- .../mode/experimental/OffsetMatcher.java | 8 +-- 2 files changed, 10 insertions(+), 69 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 51d2303..7d8c38b 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1565,7 +1565,7 @@ public void scrollToDeclaration(int lineNumber, String name, int offset) { /** - * + * Given a word(identifier) in pde code, finds its location in the ASTNode * @param lineNumber * @param name * @param offset - line start nonwhitespace offset @@ -1588,7 +1588,7 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, } } - log("FLON: Node line number " + lineNumber); + log("getASTNodeAt: Node line number " + lineNumber); ASTNode lineNode = findLineOfNode(compilationUnit, lineNumber, offset, name); log("Node text +> " + lineNode); @@ -1610,69 +1610,10 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, int javaOffset = ofm.getJavaOffForPdeOff(offset, name.length()) + lineNode.getStartPosition(); log("JAVA ast offset: " + (javaOffset)); - dfsLookForASTNode(errorCheckerService.getLatestCU(), name, - javaOffset, javaOffset + name.length()); - ASTNode simpName = null; - if(simpName == null) return null; - // End test -// int altOff = offset; -// int ret[][] = lineNodeWrap.getOffsetMapping(errorCheckerService); -// if(ret != null){ -// altOff = 0; -// int javaCodeMap[] = ret[0], pdeCodeMap[] = ret[1]; -// -// for (; altOff < javaCodeMap.length; altOff++) { -// if (javaCodeMap[altOff] == pdeCodeMap[offset]) { -// break; -// } -// } -// } -// log("FLON2: " + lineNumber + " LN start pos " -// + lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); -// /* -// * Now I need to see if multiple statements exist with this same line number -// * If that's the case, I need to ensure the offset is right. -// */ -// ASTNode parLineNode = lineNode.getParent(); -// -// Iterator it = parLineNode -// .structuralPropertiesForType().iterator(); -// boolean flag = true; -// int offAdjust = 0; -// while (it.hasNext() && flag) { -// StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it -// .next(); -// if (prop.isChildListProperty()) { -// List nodelist = (List) parLineNode -// .getStructuralProperty(prop); -// for (ASTNode cnode : nodelist) { -// if (getLineNumber(cnode) == lineNumber) { -// if (cnode.getStartPosition() <= lineNode.getStartPosition() -// + altOff -// && cnode.getStartPosition() + cnode.getLength() > lineNode -// .getStartPosition() + altOff) { -// log(cnode); -// offAdjust = cnode.getStartPosition() - lineNode.getStartPosition(); -// lineNode = cnode; -// altOff -= offAdjust; -// flag = false; -// break; -// } -// -// } -// } -// } -// } -// log("FLON3 new alt off: " + altOff); -// ASTNode simpName = pinpointOnLine(lineNode, altOff, -// lineNode.getStartPosition(), name); -// -// if(simpName == null){ //Added while fixing #51 -// log("pinpointOnLine 1+++> " + simpName); -// simpName = pinpointOnLine(lineNode.getParent(), altOff, -// lineNode.getStartPosition(), name); -// } -// log("pinpointOnLine 2+++> " + simpName); + ASTNode simpName = dfsLookForASTNode(errorCheckerService.getLatestCU(), + name, javaOffset, + javaOffset + name.length()); + if(simpName == null && lineNode instanceof SimpleName){ switch (lineNode.getParent().getNodeType()) { case ASTNode.TYPE_DECLARATION: diff --git a/src/processing/mode/experimental/OffsetMatcher.java b/src/processing/mode/experimental/OffsetMatcher.java index d0707a9..9c2f00f 100644 --- a/src/processing/mode/experimental/OffsetMatcher.java +++ b/src/processing/mode/experimental/OffsetMatcher.java @@ -52,10 +52,10 @@ public OffsetMatcher(String pdeCode, String javaCode) { // log("PDE <-> Java"); for (int i = 0; i < offsetMatch.size(); i++) { - log(offsetMatch.get(i).pdeOffset + " <-> " - + offsetMatch.get(i).javaOffset + - ", " + word1.charAt(offsetMatch.get(i).pdeOffset) - + " <-> " + word2.charAt(offsetMatch.get(i).javaOffset)); +// log(offsetMatch.get(i).pdeOffset + " <-> " +// + offsetMatch.get(i).javaOffset + +// ", " + word1.charAt(offsetMatch.get(i).pdeOffset) +// + " <-> " + word2.charAt(offsetMatch.get(i).javaOffset)); } // log("Length " + offsetMatch.size()); } From d8cd711c499bd8b27f4b86857ef02380d9205f91 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 9 Jun 2014 21:41:53 +0530 Subject: [PATCH 086/115] refactoring --- .../mode/experimental/ASTGenerator.java | 23 +++++++++++-------- .../mode/experimental/TextAreaPainter.java | 4 ++-- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 7d8c38b..fc20917 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1574,7 +1574,8 @@ public void scrollToDeclaration(int lineNumber, String name, int offset) { */ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, boolean scrollOnly) { - int originalLN = lineNumber - errorCheckerService.mainClassOffset; + int originalLN = lineNumber; + lineNumber += errorCheckerService.mainClassOffset; log("----getASTNodeAt---- CU State: " + errorCheckerService.compilationUnitState); if (errorCheckerService != null) { editor = errorCheckerService.getEditor(); @@ -1588,6 +1589,7 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, } } + lineNumber = pdeLineNumToJavaLineNum(lineNumber); log("getASTNodeAt: Node line number " + lineNumber); ASTNode lineNode = findLineOfNode(compilationUnit, lineNumber, offset, name); @@ -1595,10 +1597,8 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, ASTNode decl = null; String nodeLabel = null; String nameOfNode = null; // The node name which is to be scrolled to + if (lineNode != null) { - // Being test - - //ASTNodeWrapper lineNodeWrap = new ASTNodeWrapper(lineNode); String pdeCodeLine = errorCheckerService.getPDECodeAtLine(editor .getSketch().getCurrentCodeIndex(), originalLN); String javaCodeLine = getJavaSourceCodeline(lineNumber); @@ -2247,7 +2247,7 @@ protected void showSketchOutline(){ public int javaCodeOffsetToLineStartOffset(int line, int jOffset){ // Find the first node with this line number, return its offset - jOffset - line = PdeToJavaLineNumber(line); + line = pdeLineNumToJavaLineNum(line); log("Looking for line: " + line + ", jOff " + jOffset); Stack temp = new Stack(); temp.push(codeTree); @@ -2271,17 +2271,22 @@ public int javaCodeOffsetToLineStartOffset(int line, int jOffset){ return -1; } - protected int PdeToJavaLineNumber(int lineNum){ - int lineNumber = lineNum + errorCheckerService.getPdeImportsCount(); + /** + * Converts pde line number to java line number + * @param pdeLineNum - pde line number + * @return + */ + protected int pdeLineNumToJavaLineNum(int pdeLineNum){ + int javaLineNumber = pdeLineNum + errorCheckerService.getPdeImportsCount(); // Adjust line number for tabbed sketches int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab()); if (codeIndex > 0) for (int i = 0; i < codeIndex; i++) { SketchCode sc = editor.getSketch().getCode(i); int len = Base.countLines(sc.getProgram()) + 1; - lineNumber += len; + javaLineNumber += len; } - return lineNumber; + return javaLineNumber; } protected boolean isInstanceOfType(ASTNode node,ASTNode decl, String name){ diff --git a/src/processing/mode/experimental/TextAreaPainter.java b/src/processing/mode/experimental/TextAreaPainter.java index d7571fb..bf0a9a2 100644 --- a/src/processing/mode/experimental/TextAreaPainter.java +++ b/src/processing/mode/experimental/TextAreaPainter.java @@ -144,8 +144,8 @@ else if (s.length() == 0) log(errorCheckerService.mainClassOffset + line + "|" + line + "| offset " + xLS + word + " <= \n"); - errorCheckerService.getASTGenerator().scrollToDeclaration(line - + errorCheckerService.mainClassOffset, word, xLS); + errorCheckerService.getASTGenerator() + .scrollToDeclaration(line, word, xLS); } } From 262f0bd484aad8a9bf3c1bf0e4170b937718c4b2 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 9 Jun 2014 21:49:02 +0530 Subject: [PATCH 087/115] code cleanup --- .../mode/experimental/ASTGenerator.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index fc20917..e785ac6 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1574,8 +1574,8 @@ public void scrollToDeclaration(int lineNumber, String name, int offset) { */ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, boolean scrollOnly) { - int originalLN = lineNumber; - lineNumber += errorCheckerService.mainClassOffset; + //int originalLN = lineNumber; + int pdeLineNumber = lineNumber + errorCheckerService.mainClassOffset; log("----getASTNodeAt---- CU State: " + errorCheckerService.compilationUnitState); if (errorCheckerService != null) { editor = errorCheckerService.getEditor(); @@ -1584,14 +1584,14 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, for (int i = 0; i < codeIndex; i++) { SketchCode sc = editor.getSketch().getCode(i); int len = Base.countLines(sc.getProgram()) + 1; - lineNumber += len; + pdeLineNumber += len; } } } - lineNumber = pdeLineNumToJavaLineNum(lineNumber); - log("getASTNodeAt: Node line number " + lineNumber); - ASTNode lineNode = findLineOfNode(compilationUnit, lineNumber, offset, name); + + log("getASTNodeAt: Node line number " + pdeLineNumber); + ASTNode lineNode = findLineOfNode(compilationUnit, pdeLineNumber, offset, name); log("Node text +> " + lineNode); ASTNode decl = null; @@ -1600,10 +1600,10 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, if (lineNode != null) { String pdeCodeLine = errorCheckerService.getPDECodeAtLine(editor - .getSketch().getCurrentCodeIndex(), originalLN); - String javaCodeLine = getJavaSourceCodeline(lineNumber); + .getSketch().getCurrentCodeIndex(), lineNumber); + String javaCodeLine = getJavaSourceCodeline(pdeLineNumber); - log(originalLN + " Original Line num.\nPDE :" + pdeCodeLine); + log(lineNumber + " Original Line num.\nPDE :" + pdeCodeLine); log("JAVA:" + javaCodeLine); log("Clicked on: " + name + " start offset: " + offset); OffsetMatcher ofm = new OffsetMatcher(pdeCodeLine, javaCodeLine); From 1debe4857fd15a50e5e58d8d042bcba4f10fab5c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 9 Jun 2014 22:18:32 +0530 Subject: [PATCH 088/115] code cleanup. --- .../mode/experimental/ASTGenerator.java | 64 ++++++++++--------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index e785ac6..296fecf 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1576,7 +1576,8 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, boolean scrollOnly) { //int originalLN = lineNumber; int pdeLineNumber = lineNumber + errorCheckerService.mainClassOffset; - log("----getASTNodeAt---- CU State: " + errorCheckerService.compilationUnitState); + log("----getASTNodeAt---- CU State: " + + errorCheckerService.compilationUnitState); if (errorCheckerService != null) { editor = errorCheckerService.getEditor(); int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab()); @@ -1591,18 +1592,19 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, } log("getASTNodeAt: Node line number " + pdeLineNumber); - ASTNode lineNode = findLineOfNode(compilationUnit, pdeLineNumber, offset, name); - + ASTNode lineNode = findLineOfNode(compilationUnit, pdeLineNumber, offset, + name); + log("Node text +> " + lineNode); ASTNode decl = null; String nodeLabel = null; String nameOfNode = null; // The node name which is to be scrolled to - + if (lineNode != null) { String pdeCodeLine = errorCheckerService.getPDECodeAtLine(editor .getSketch().getCurrentCodeIndex(), lineNumber); String javaCodeLine = getJavaSourceCodeline(pdeLineNumber); - + log(lineNumber + " Original Line num.\nPDE :" + pdeCodeLine); log("JAVA:" + javaCodeLine); log("Clicked on: " + name + " start offset: " + offset); @@ -1613,76 +1615,78 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, ASTNode simpName = dfsLookForASTNode(errorCheckerService.getLatestCU(), name, javaOffset, javaOffset + name.length()); - - if(simpName == null && lineNode instanceof SimpleName){ + + if (simpName == null && lineNode instanceof SimpleName) { switch (lineNode.getParent().getNodeType()) { case ASTNode.TYPE_DECLARATION: - + case ASTNode.METHOD_DECLARATION: case ASTNode.FIELD_DECLARATION: case ASTNode.VARIABLE_DECLARATION_FRAGMENT: decl = lineNode.getParent(); - return new ASTNodeWrapper(decl,""); + return new ASTNodeWrapper(decl, ""); default: break; } } - + if (simpName instanceof SimpleName) { nameOfNode = simpName.toString(); log(getNodeAsString(simpName)); decl = findDeclaration((SimpleName) simpName); if (decl != null) { logE("DECLA: " + decl.getClass().getName()); - nodeLabel = getLabelIfType(new ASTNodeWrapper(decl), (SimpleName) simpName); + nodeLabel = getLabelIfType(new ASTNodeWrapper(decl), + (SimpleName) simpName); //retLabelString = getNodeAsString(decl); } else { logE("null"); - if(scrollOnly) { + if (scrollOnly) { editor.statusMessage(simpName + " is not defined in this sketch", DebugEditor.STATUS_ERR); } } log(getNodeAsString(decl)); - + // - findDecl3 testing - - ASTNode nearestNode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() - .get(0)); + + ASTNode nearestNode = findClosestNode(lineNumber, + (ASTNode) compilationUnit.types() + .get(0)); ClassMember cmem = resolveExpression3rdParty(nearestNode, - (SimpleName) simpName, false); - if(cmem != null){ - log("CMEM-> "+cmem); - } - else + (SimpleName) simpName, + false); + if (cmem != null) { + log("CMEM-> " + cmem); + } else log("CMEM-> null"); } } if (decl != null && scrollOnly) { /* - * For scrolling, we highlight just the name of the node, - * i.e., a SimpleName instance. But the declared node always - * points to the declared node itself, like TypeDecl, MethodDecl, etc. - * This is important since it contains all the properties. + * For scrolling, we highlight just the name of the node, i.e., a + * SimpleName instance. But the declared node always points to the + * declared node itself, like TypeDecl, MethodDecl, etc. This is important + * since it contains all the properties. */ - ASTNode simpName2 = getNodeName(decl,nameOfNode); + ASTNode simpName2 = getNodeName(decl, nameOfNode); logE("FINAL String decl: " + getNodeAsString(decl)); logE("FINAL String label: " + getNodeAsString(simpName2)); //errorCheckerService.highlightNode(simpName2); - ASTNodeWrapper declWrap = new ASTNodeWrapper(simpName2,nodeLabel); + ASTNodeWrapper declWrap = new ASTNodeWrapper(simpName2, nodeLabel); //errorCheckerService.highlightNode(declWrap); if (!declWrap.highlightNode(this)) { logE("Highlighting failed."); } - } + } - return new ASTNodeWrapper(decl,nodeLabel); + return new ASTNodeWrapper(decl, nodeLabel); } - + /** * Given a declaration type astnode, returns the SimpleName peroperty * of that node. From 43c55aea7e43f371ce0704552fbe341885a16bdd Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 9 Jun 2014 22:36:38 +0530 Subject: [PATCH 089/115] Removed unnecessary stuff --- src/processing/mode/experimental/ASTGenerator.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 296fecf..40f4729 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1651,6 +1651,7 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, log(getNodeAsString(decl)); + /* // - findDecl3 testing ASTNode nearestNode = findClosestNode(lineNumber, @@ -1663,6 +1664,7 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, log("CMEM-> " + cmem); } else log("CMEM-> null"); + */ } } From 2a0d44951a6035ff990a59f3aa28bc6c6a1799fc Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 9 Jun 2014 22:42:28 +0530 Subject: [PATCH 090/115] code comments, coz I am not a mean person --- src/processing/mode/experimental/ASTGenerator.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 40f4729..b6f32a8 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1574,7 +1574,8 @@ public void scrollToDeclaration(int lineNumber, String name, int offset) { */ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, boolean scrollOnly) { - //int originalLN = lineNumber; + + // Convert tab based pde line number to actual line number int pdeLineNumber = lineNumber + errorCheckerService.mainClassOffset; log("----getASTNodeAt---- CU State: " + errorCheckerService.compilationUnitState); @@ -1591,6 +1592,7 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, } + // Find closest ASTNode to the linenumber log("getASTNodeAt: Node line number " + pdeLineNumber); ASTNode lineNode = findLineOfNode(compilationUnit, pdeLineNumber, offset, name); @@ -1600,6 +1602,7 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, String nodeLabel = null; String nameOfNode = null; // The node name which is to be scrolled to + // Obtain correspondin java code at that line, match offsets if (lineNode != null) { String pdeCodeLine = errorCheckerService.getPDECodeAtLine(editor .getSketch().getCurrentCodeIndex(), lineNumber); @@ -1608,14 +1611,18 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, log(lineNumber + " Original Line num.\nPDE :" + pdeCodeLine); log("JAVA:" + javaCodeLine); log("Clicked on: " + name + " start offset: " + offset); + // Calculate expected java offset based on the pde line OffsetMatcher ofm = new OffsetMatcher(pdeCodeLine, javaCodeLine); int javaOffset = ofm.getJavaOffForPdeOff(offset, name.length()) + lineNode.getStartPosition(); log("JAVA ast offset: " + (javaOffset)); + + // Find the corresponding node in the AST ASTNode simpName = dfsLookForASTNode(errorCheckerService.getLatestCU(), name, javaOffset, javaOffset + name.length()); + // If node wasn't found in the AST, lineNode may contain something if (simpName == null && lineNode instanceof SimpleName) { switch (lineNode.getParent().getNodeType()) { case ASTNode.TYPE_DECLARATION: @@ -1632,6 +1639,7 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, } } + // SimpleName instance found, now find its declaration in code if (simpName instanceof SimpleName) { nameOfNode = simpName.toString(); log(getNodeAsString(simpName)); @@ -1686,6 +1694,7 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, } } + // Return the declaration wrapped as ASTNodeWrapper return new ASTNodeWrapper(decl, nodeLabel); } From 6e2805b0f3e785f6edb79a78537cd69989a6d891 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 9 Jun 2014 23:23:15 +0530 Subject: [PATCH 091/115] managing collateral damage from offset algo change --- src/processing/mode/experimental/ASTGenerator.java | 4 +++- src/processing/mode/experimental/TextArea.java | 4 ++-- src/processing/mode/experimental/TextAreaPainter.java | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index b6f32a8..8ce8b71 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1798,6 +1798,7 @@ public static void traversal2() { } } + final ASTGenerator thisASTGenerator = this; protected void addListeners(){ jtree.addTreeSelectionListener(new TreeSelectionListener() { @@ -1918,7 +1919,8 @@ protected void done() { if (tnode.getUserObject() instanceof ASTNodeWrapper) { ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); - errorCheckerService.highlightNode(awrap); + //errorCheckerService.highlightNode(awrap); + awrap.highlightNode(thisASTGenerator); } } }; diff --git a/src/processing/mode/experimental/TextArea.java b/src/processing/mode/experimental/TextArea.java index 6657353..b0971b3 100644 --- a/src/processing/mode/experimental/TextArea.java +++ b/src/processing/mode/experimental/TextArea.java @@ -256,6 +256,7 @@ else if (s.length() == 0) if (x1 >= 0 && x1 < s.length()) { if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') { word = s.charAt(x1--) + word; + xLS--; } else x1 = -1; } else @@ -280,8 +281,7 @@ else if (s.length() == 0) if (Character.isDigit(word.charAt(0))) return null; log("Mouse click, word: " + word.trim()); - errorCheckerService.getASTGenerator().setLastClickedWord(line - + errorCheckerService.mainClassOffset, word, xLS); + errorCheckerService.getASTGenerator().setLastClickedWord(line, word, xLS); return word.trim(); } } diff --git a/src/processing/mode/experimental/TextAreaPainter.java b/src/processing/mode/experimental/TextAreaPainter.java index bf0a9a2..8b7f5e9 100644 --- a/src/processing/mode/experimental/TextAreaPainter.java +++ b/src/processing/mode/experimental/TextAreaPainter.java @@ -458,6 +458,7 @@ else if (s.length() == 0) if (x1 >= 0 && x1 < s.length()) { if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') { word = s.charAt(x1--) + word; + xLS--; } else x1 = -1; } else @@ -483,8 +484,7 @@ else if (s.length() == 0) if (Character.isDigit(word.charAt(0))) return null; String tooltipText = errorCheckerService.getASTGenerator() - .getLabelForASTNode(line + errorCheckerService.mainClassOffset, word, - xLS); + .getLabelForASTNode(line, word, xLS); log(errorCheckerService.mainClassOffset + " MCO " + "|" + line + "| offset " + xLS + word + " <= offf: "+off+ "\n"); From e95ccfb032d666698298cfbcd57ef131e3224f17 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 10 Jun 2014 01:42:14 +0530 Subject: [PATCH 092/115] some utility methods --- .../mode/experimental/ASTGenerator.java | 123 +++++++++++++++++- 1 file changed, 117 insertions(+), 6 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 8ce8b71..fd0e047 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1189,22 +1189,54 @@ public ArrayList getMembersForType(ClassMember tehClass, return candidates; } - public String getJavaSourceCodeline(int jLineNumber){ + /** + * Returns the java source code line at the given line number + * @param javaLineNumber + * @return + */ + public String getJavaSourceCodeline(int javaLineNumber) { try { PlainDocument javaSource = new PlainDocument(); javaSource.insertString(0, errorCheckerService.sourceCode, null); Element lineElement = javaSource.getDefaultRootElement() - .getElement(jLineNumber-1); - if(lineElement == null) { - log("Couldn't fetch jlinenum " + jLineNumber); + .getElement(javaLineNumber - 1); + if (lineElement == null) { + log("Couldn't fetch jlinenum " + javaLineNumber); return null; - } + } String javaLine = javaSource.getText(lineElement.getStartOffset(), lineElement.getEndOffset() - lineElement.getStartOffset()); return javaLine; } catch (BadLocationException e) { - logE(e + " in getJavaSourceCodeline() for jinenum: " + jLineNumber); + logE(e + " in getJavaSourceCodeline() for jinenum: " + javaLineNumber); + } + return null; + } + + /** + * Returns the java source code line Element at the given line number. + * The Element object stores the offset data, but not the actual line + * of code. + * @param javaLineNumber + * @return + */ + public Element getJavaSourceCodeElement(int javaLineNumber) { + try { + PlainDocument javaSource = new PlainDocument(); + javaSource.insertString(0, errorCheckerService.sourceCode, null); + Element lineElement = javaSource.getDefaultRootElement() + .getElement(javaLineNumber - 1); + if (lineElement == null) { + log("Couldn't fetch jlinenum " + javaLineNumber); + return null; + } +// String javaLine = javaSource.getText(lineElement.getStartOffset(), +// lineElement.getEndOffset() +// - lineElement.getStartOffset()); + return lineElement; + } catch (BadLocationException e) { + logE(e + " in getJavaSourceCodeline() for jinenum: " + javaLineNumber); } return null; } @@ -1929,6 +1961,7 @@ protected void done() { }); } + /* protected void refactorIt(){ String newName = txtRenameField.getText().trim(); String selText = lastClickedWord == null ? editor.ta.getSelectedText() @@ -1994,6 +2027,84 @@ protected void refactorIt(){ // for (Integer lineNum : lineOffsetDisplacement.keySet()) { // log(lineNum + "line, disp" // + lineOffsetDisplacement.get(lineNum)); +// } + editor.getSketch().setModified(true); + errorCheckerService.runManualErrorCheck(); + frmOccurenceList.setVisible(false); + frmRename.setVisible(false); + lastClickedWord = null; + lastClickedWordNode = null; + } + */ + + protected void refactorIt(){ + String newName = txtRenameField.getText().trim(); + String selText = lastClickedWord == null ? editor.ta.getSelectedText() + : lastClickedWord; + // Find all occurrences of last clicked word + DefaultMutableTreeNode defCU = findAllOccurrences(); //TODO: Repetition here + if(defCU == null){ + editor.statusMessage("Can't locate definition of " + selText, + DebugEditor.STATUS_ERR); + return; + } + + // Verify if the new name is a valid java identifier + if(!newName.matches("([a-zA-Z][a-zA-Z0-9_]*)|([_][a-zA-Z0-9_]+)")) + { + JOptionPane.showConfirmDialog(new JFrame(), newName + + " isn't a valid name.", "Uh oh..", JOptionPane.PLAIN_MESSAGE); + return; + } + //else log("New name looks K."); + + errorCheckerService.pauseThread(); + if(treeRename.isVisible()){ + treeRename.setModel(new DefaultTreeModel(defCU)); + ((DefaultTreeModel) treeRename.getModel()).reload(); + } + frmOccurenceList.setTitle("Usage of " + selText); + frmOccurenceList.setLocation(editor.getX() + editor.getWidth(),editor.getY()); + frmOccurenceList.setVisible(true); + int lineOffsetDisplacementConst = newName.length() + - selText.length(); + HashMap lineOffsetDisplacement = new HashMap(); + + // I need to store the pde and java offsets beforehand because once + // the replace starts, all offsets returned are affected + int offsetsMap[][][] = new int[defCU.getChildCount()][2][]; + for (int i = 0; i < defCU.getChildCount(); i++) { + ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) (defCU + .getChildAt(i))).getUserObject(); + offsetsMap[i][0] = awrap.getPDECodeOffsets(errorCheckerService); + offsetsMap[i][1] = awrap.getJavaCodeOffsets(errorCheckerService); + } + + for (int i = 0; i < defCU.getChildCount(); i++) { + int pdeoffsets[] = offsetsMap[i][0]; + int javaoffsets[] = offsetsMap[i][1]; + // correction for pde enhancements related displacement on a line + int off = 0; + if (lineOffsetDisplacement.get(javaoffsets[0]) != null) { + off = lineOffsetDisplacement.get(javaoffsets[0]); + + lineOffsetDisplacement.put(javaoffsets[0], + lineOffsetDisplacementConst + off); + } else { + lineOffsetDisplacement.put(javaoffsets[0], + lineOffsetDisplacementConst); + } + ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], + pdeoffsets[1], + javaoffsets[1] + off, + javaoffsets[2]); + //int k = JOptionPane.showConfirmDialog(new JFrame(), "Rename?","", JOptionPane.INFORMATION_MESSAGE)); + editor.ta.setSelectedText(newName); + } + errorCheckerService.resumeThread(); +// for (Integer lineNum : lineOffsetDisplacement.keySet()) { +// log(lineNum + "line, disp" +// + lineOffsetDisplacement.get(lineNum)); // } editor.getSketch().setModified(true); errorCheckerService.runManualErrorCheck(); From 5313f9c18a02ce689f1a1d2b7e7fe3b205a61828 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 10 Jun 2014 02:12:07 +0530 Subject: [PATCH 093/115] moar utility methods --- .../mode/experimental/ASTGenerator.java | 13 +++++++++++-- .../mode/experimental/ASTNodeWrapper.java | 19 ++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index fd0e047..f970575 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1189,12 +1189,21 @@ public ArrayList getMembersForType(ClassMember tehClass, return candidates; } + public String getPDESourceCodeLine(int javaLineNumber) { + int res[] = errorCheckerService + .calculateTabIndexAndLineNumber(javaLineNumber); + if (res != null) { + return errorCheckerService.getPDECodeAtLine(res[0], res[1]); + } + return null; + } + /** * Returns the java source code line at the given line number * @param javaLineNumber * @return */ - public String getJavaSourceCodeline(int javaLineNumber) { + public String getJavaSourceCodeLine(int javaLineNumber) { try { PlainDocument javaSource = new PlainDocument(); javaSource.insertString(0, errorCheckerService.sourceCode, null); @@ -1638,7 +1647,7 @@ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, if (lineNode != null) { String pdeCodeLine = errorCheckerService.getPDECodeAtLine(editor .getSketch().getCurrentCodeIndex(), lineNumber); - String javaCodeLine = getJavaSourceCodeline(pdeLineNumber); + String javaCodeLine = getJavaSourceCodeLine(pdeLineNumber); log(lineNumber + " Original Line num.\nPDE :" + pdeCodeLine); log("JAVA:" + javaCodeLine); diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index 734da04..450dfb6 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -392,7 +392,7 @@ public int[][] getOffsetMapping(ErrorCheckerService ecs, String source){ // Instead of converting pde into java, how can I simply extract the same source // from the java code? Think. TODO String sourceAlt = new String(source); - String sourceJava = ecs.astGenerator.getJavaSourceCodeline(lineNumber); + String sourceJava = ecs.astGenerator.getJavaSourceCodeLine(lineNumber); TreeMap offsetmap = new TreeMap(); if(sourceJava.trim().startsWith("public") && !source.startsWith("public")){ @@ -650,6 +650,23 @@ public int[][] getOffsetMapping(ErrorCheckerService ecs){ public int[] getPDECodeOffsets(ErrorCheckerService ecs) { return ecs.JavaToPdeOffsets(lineNumber + 1, Node.getStartPosition()); } + + public int getPDECodeOffsetForSN(ASTGenerator astGen){ + if (Node instanceof SimpleName) { + Element lineElement = astGen.getJavaSourceCodeElement(lineNumber); + + OffsetMatcher ofm = new OffsetMatcher( + astGen + .getPDESourceCodeLine(lineNumber), + astGen + .getJavaSourceCodeLine(lineNumber)); + //log(""); + int pdeOffset = ofm.getPdeOffForJavaOff(Node.getStartPosition() + - lineElement.getStartOffset(), Node.toString().length()); + return pdeOffset; + } + return -1; + } public String toString() { return label; From 240d32d613f489b657c7e8a2bbd613f4bc5e28f1 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 10 Jun 2014 02:18:48 +0530 Subject: [PATCH 094/115] further work --- src/processing/mode/experimental/ASTGenerator.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index f970575..f8d2771 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -2087,8 +2087,10 @@ protected void refactorIt(){ .getChildAt(i))).getUserObject(); offsetsMap[i][0] = awrap.getPDECodeOffsets(errorCheckerService); offsetsMap[i][1] = awrap.getJavaCodeOffsets(errorCheckerService); + log(getNodeAsString(awrap.getNode()) + ", " + + awrap.getPDECodeOffsetForSN(this)); } - + /* for (int i = 0; i < defCU.getChildCount(); i++) { int pdeoffsets[] = offsetsMap[i][0]; int javaoffsets[] = offsetsMap[i][1]; @@ -2109,7 +2111,7 @@ protected void refactorIt(){ javaoffsets[2]); //int k = JOptionPane.showConfirmDialog(new JFrame(), "Rename?","", JOptionPane.INFORMATION_MESSAGE)); editor.ta.setSelectedText(newName); - } + }*/ errorCheckerService.resumeThread(); // for (Integer lineNum : lineOffsetDisplacement.keySet()) { // log(lineNum + "line, disp" From 92f21776a13b25283f6a6369efe13e6459bc8a77 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 10 Jun 2014 02:19:35 +0530 Subject: [PATCH 095/115] refactoring.. --- .../mode/experimental/OffsetMatcher.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/processing/mode/experimental/OffsetMatcher.java b/src/processing/mode/experimental/OffsetMatcher.java index 9c2f00f..5161808 100644 --- a/src/processing/mode/experimental/OffsetMatcher.java +++ b/src/processing/mode/experimental/OffsetMatcher.java @@ -32,14 +32,14 @@ public class OffsetMatcher { public ArrayList offsetMatch; - String word1, word2; + String pdeCodeLine, javaCodeLine; boolean matchingNeeded = false; public OffsetMatcher(String pdeCode, String javaCode) { - this.word1 = pdeCode; - this.word2 = javaCode; - if(word1.trim().equals(word2.trim())){ //TODO: trim() needed here? + this.pdeCodeLine = pdeCode; + this.javaCodeLine = javaCode; + if(pdeCodeLine.trim().equals(javaCodeLine.trim())){ //TODO: trim() needed here? matchingNeeded = false; offsetMatch = new ArrayList(); log("Offset Matching not needed"); @@ -67,8 +67,8 @@ public int getPdeOffForJavaOff(int start, int length) { + ans); log((start + length - 1) + " java end off, pde end off " + end); - log("J: " + word2.substring(start, start + length) + "\nP: " - + word1.substring(ans, end + 1)); + log("J: " + javaCodeLine.substring(start, start + length) + "\nP: " + + pdeCodeLine.substring(ans, end + 1)); return ans; } @@ -139,10 +139,10 @@ private int minDistance() { // word1 = reverse(word1); // word2 = reverse(word2); - int len1 = word1.length(); - int len2 = word2.length(); - log(word1 + " len: " + len1); - log(word2 + " len: " + len2); + int len1 = pdeCodeLine.length(); + int len2 = javaCodeLine.length(); + log(pdeCodeLine + " len: " + len1); + log(javaCodeLine + " len: " + len2); // len1+1, len2+1, because finally return dp[len1][len2] int[][] dp = new int[len1 + 1][len2 + 1]; @@ -156,9 +156,9 @@ private int minDistance() { //iterate though, and check last char for (int i = 0; i < len1; i++) { - char c1 = word1.charAt(i); + char c1 = pdeCodeLine.charAt(i); for (int j = 0; j < len2; j++) { - char c2 = word2.charAt(j); + char c2 = javaCodeLine.charAt(j); //System.out.print(c1 + "<->" + c2); //if last two chars equal if (c1 == c2) { @@ -182,8 +182,8 @@ private int minDistance() { ArrayList alist = new ArrayList(); offsetMatch = alist; - minDistInGrid(dp, len1, len2, 0, 0, word1.toCharArray(), - word2.toCharArray(), alist); + minDistInGrid(dp, len1, len2, 0, 0, pdeCodeLine.toCharArray(), + javaCodeLine.toCharArray(), alist); return dp[len1][len2]; } From 99c6d6af30b86e917b3be82f54d87bfdbab47764 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 10 Jun 2014 02:57:12 +0530 Subject: [PATCH 096/115] Refactoring rewritten. Hail Daft Punk --- .../mode/experimental/ASTGenerator.java | 63 +++++++++++++------ .../mode/experimental/ASTNodeWrapper.java | 2 +- .../mode/experimental/OffsetMatcher.java | 1 + 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index f8d2771..7f8753b 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -2081,37 +2081,49 @@ protected void refactorIt(){ // I need to store the pde and java offsets beforehand because once // the replace starts, all offsets returned are affected - int offsetsMap[][][] = new int[defCU.getChildCount()][2][]; + //int offsetsMap[][][] = new int[defCU.getChildCount()][2][]; + int pdeOffsets[][] = new int[defCU.getChildCount()][3]; for (int i = 0; i < defCU.getChildCount(); i++) { ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) (defCU .getChildAt(i))).getUserObject(); - offsetsMap[i][0] = awrap.getPDECodeOffsets(errorCheckerService); - offsetsMap[i][1] = awrap.getJavaCodeOffsets(errorCheckerService); - log(getNodeAsString(awrap.getNode()) + ", " - + awrap.getPDECodeOffsetForSN(this)); +// offsetsMap[i][0] = awrap.getPDECodeOffsets(errorCheckerService); +// offsetsMap[i][1] = awrap.getJavaCodeOffsets(errorCheckerService); + int ans[] = errorCheckerService.calculateTabIndexAndLineNumber(awrap + .getLineNumber()); + pdeOffsets[i][0] = ans[0]; + pdeOffsets[i][1] = ans[1]; + pdeOffsets[i][2] = awrap.getPDECodeOffsetForSN(this); +// logE(getNodeAsString(awrap.getNode()) + ", " +// + pdeOffsets[i][2]); } - /* + for (int i = 0; i < defCU.getChildCount(); i++) { - int pdeoffsets[] = offsetsMap[i][0]; - int javaoffsets[] = offsetsMap[i][1]; + ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) (defCU + .getChildAt(i))).getUserObject(); // correction for pde enhancements related displacement on a line int off = 0; - if (lineOffsetDisplacement.get(javaoffsets[0]) != null) { - off = lineOffsetDisplacement.get(javaoffsets[0]); + if (lineOffsetDisplacement.get(awrap.getLineNumber()) != null) { + off = lineOffsetDisplacement.get(awrap.getLineNumber()); - lineOffsetDisplacement.put(javaoffsets[0], + lineOffsetDisplacement.put(awrap.getLineNumber(), lineOffsetDisplacementConst + off); } else { - lineOffsetDisplacement.put(javaoffsets[0], + lineOffsetDisplacement.put(awrap.getLineNumber(), lineOffsetDisplacementConst); } - ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], - pdeoffsets[1], - javaoffsets[1] + off, - javaoffsets[2]); - //int k = JOptionPane.showConfirmDialog(new JFrame(), "Rename?","", JOptionPane.INFORMATION_MESSAGE)); + logE(getNodeAsString(awrap.getNode()) + ", T:" + pdeOffsets[i][0] + + ", L:" + pdeOffsets[i][1] + ", O:" + pdeOffsets[i][2]); +// ErrorCheckerService.scrollToErrorLine(editor, pdeOffsets[i][0], +// pdeOffsets[i][1] - 1, pdeOffsets[i][2] +// + off, awrap.getNode() +// .toString().length()); + highlightPDECode(pdeOffsets[i][0], + pdeOffsets[i][1], pdeOffsets[i][2] + + off, awrap.getNode() + .toString().length()); + //int k = JOptionPane.showConfirmDialog(new JFrame(), "Rename?","", JOptionPane.INFORMATION_MESSAGE); editor.ta.setSelectedText(newName); - }*/ + } errorCheckerService.resumeThread(); // for (Integer lineNum : lineOffsetDisplacement.keySet()) { // log(lineNum + "line, disp" @@ -2125,6 +2137,21 @@ protected void refactorIt(){ lastClickedWordNode = null; } + /** + * Highlights text in the editor + * @param tab + * @param lineNumber + * @param lineStartWSOffset - line start offset including initial white space + * @param length + */ + public void highlightPDECode(int tab, int lineNumber, int lineStartWSOffset, + int length) { + editor.toFront(); + editor.getSketch().setCurrentCode(tab); + lineStartWSOffset += editor.ta.getLineStartOffset(lineNumber); + editor.ta.select(lineStartWSOffset, lineStartWSOffset + length); + } + public void handleShowUsage(){ log("Last clicked word:" + lastClickedWord); if(lastClickedWord == null && editor.ta.getSelectedText() == null){ diff --git a/src/processing/mode/experimental/ASTNodeWrapper.java b/src/processing/mode/experimental/ASTNodeWrapper.java index 450dfb6..9798f3e 100644 --- a/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/src/processing/mode/experimental/ASTNodeWrapper.java @@ -654,7 +654,7 @@ public int[] getPDECodeOffsets(ErrorCheckerService ecs) { public int getPDECodeOffsetForSN(ASTGenerator astGen){ if (Node instanceof SimpleName) { Element lineElement = astGen.getJavaSourceCodeElement(lineNumber); - + log("Line element off " + lineElement.getStartOffset()); OffsetMatcher ofm = new OffsetMatcher( astGen .getPDESourceCodeLine(lineNumber), diff --git a/src/processing/mode/experimental/OffsetMatcher.java b/src/processing/mode/experimental/OffsetMatcher.java index 5161808..af48dfe 100644 --- a/src/processing/mode/experimental/OffsetMatcher.java +++ b/src/processing/mode/experimental/OffsetMatcher.java @@ -61,6 +61,7 @@ public OffsetMatcher(String pdeCode, String javaCode) { } public int getPdeOffForJavaOff(int start, int length) { + log("PDE :" + pdeCodeLine + "\nJAVA:" + javaCodeLine); if(!matchingNeeded) return start; int ans = getPdeOffForJavaOff(start), end = getPdeOffForJavaOff(start + length - 1); log(start + " java start off, pde start off " From 03f7732a86efa16b9874407cce4d01000bfff87a Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 10 Jun 2014 02:58:26 +0530 Subject: [PATCH 097/115] Dunno how I wrote such bad code earlier. Lol --- .../mode/experimental/ASTGenerator.java | 92 +------------------ 1 file changed, 2 insertions(+), 90 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 7f8753b..017874f 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1970,82 +1970,6 @@ protected void done() { }); } - /* - protected void refactorIt(){ - String newName = txtRenameField.getText().trim(); - String selText = lastClickedWord == null ? editor.ta.getSelectedText() - : lastClickedWord; - DefaultMutableTreeNode defCU = findAllOccurrences(); - if(defCU == null){ - editor.statusError("Can't locate definition of " + selText); - return; - } - - if(!newName.matches("([a-zA-Z][a-zA-Z0-9_]*)|([_][a-zA-Z0-9_]+)")) - { - JOptionPane.showConfirmDialog(new JFrame(), newName - + " isn't a valid name.", "Uh oh..", JOptionPane.PLAIN_MESSAGE); - return; - } - //else log("New name looks K."); - - errorCheckerService.pauseThread(); - if(treeRename.isVisible()){ - treeRename.setModel(new DefaultTreeModel(defCU)); - ((DefaultTreeModel) treeRename.getModel()).reload(); - } - frmOccurenceList.setTitle("Usage of " + selText); - frmOccurenceList.setLocation(editor.getX() + editor.getWidth(),editor.getY()); - frmOccurenceList.setVisible(true); - int lineOffsetDisplacementConst = newName.length() - - selText.length(); - HashMap lineOffsetDisplacement = new HashMap(); - - // I need to store the pde and java offsets beforehand because once - // the replace starts, all offsets returned are affected - int offsetsMap[][][] = new int[defCU.getChildCount()][2][]; - for (int i = 0; i < defCU.getChildCount(); i++) { - ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) (defCU - .getChildAt(i))).getUserObject(); - offsetsMap[i][0] = awrap.getPDECodeOffsets(errorCheckerService); - offsetsMap[i][1] = awrap.getJavaCodeOffsets(errorCheckerService); - } - - for (int i = 0; i < defCU.getChildCount(); i++) { - int pdeoffsets[] = offsetsMap[i][0]; - int javaoffsets[] = offsetsMap[i][1]; - // correction for pde enhancements related displacement on a line - int off = 0; - if (lineOffsetDisplacement.get(javaoffsets[0]) != null) { - off = lineOffsetDisplacement.get(javaoffsets[0]); - - lineOffsetDisplacement.put(javaoffsets[0], - lineOffsetDisplacementConst + off); - } else { - lineOffsetDisplacement.put(javaoffsets[0], - lineOffsetDisplacementConst); - } - ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], - pdeoffsets[1], - javaoffsets[1] + off, - javaoffsets[2]); - //int k = JOptionPane.showConfirmDialog(new JFrame(), "Rename?","", JOptionPane.INFORMATION_MESSAGE)); - editor.ta.setSelectedText(newName); - } - errorCheckerService.resumeThread(); -// for (Integer lineNum : lineOffsetDisplacement.keySet()) { -// log(lineNum + "line, disp" -// + lineOffsetDisplacement.get(lineNum)); -// } - editor.getSketch().setModified(true); - errorCheckerService.runManualErrorCheck(); - frmOccurenceList.setVisible(false); - frmRename.setVisible(false); - lastClickedWord = null; - lastClickedWordNode = null; - } - */ - protected void refactorIt(){ String newName = txtRenameField.getText().trim(); String selText = lastClickedWord == null ? editor.ta.getSelectedText() @@ -2086,15 +2010,11 @@ protected void refactorIt(){ for (int i = 0; i < defCU.getChildCount(); i++) { ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) (defCU .getChildAt(i))).getUserObject(); -// offsetsMap[i][0] = awrap.getPDECodeOffsets(errorCheckerService); -// offsetsMap[i][1] = awrap.getJavaCodeOffsets(errorCheckerService); int ans[] = errorCheckerService.calculateTabIndexAndLineNumber(awrap .getLineNumber()); pdeOffsets[i][0] = ans[0]; pdeOffsets[i][1] = ans[1]; pdeOffsets[i][2] = awrap.getPDECodeOffsetForSN(this); -// logE(getNodeAsString(awrap.getNode()) + ", " -// + pdeOffsets[i][2]); } for (int i = 0; i < defCU.getChildCount(); i++) { @@ -2111,12 +2031,8 @@ protected void refactorIt(){ lineOffsetDisplacement.put(awrap.getLineNumber(), lineOffsetDisplacementConst); } - logE(getNodeAsString(awrap.getNode()) + ", T:" + pdeOffsets[i][0] - + ", L:" + pdeOffsets[i][1] + ", O:" + pdeOffsets[i][2]); -// ErrorCheckerService.scrollToErrorLine(editor, pdeOffsets[i][0], -// pdeOffsets[i][1] - 1, pdeOffsets[i][2] -// + off, awrap.getNode() -// .toString().length()); +// logE(getNodeAsString(awrap.getNode()) + ", T:" + pdeOffsets[i][0] +// + ", L:" + pdeOffsets[i][1] + ", O:" + pdeOffsets[i][2]); highlightPDECode(pdeOffsets[i][0], pdeOffsets[i][1], pdeOffsets[i][2] + off, awrap.getNode() @@ -2125,10 +2041,6 @@ protected void refactorIt(){ editor.ta.setSelectedText(newName); } errorCheckerService.resumeThread(); -// for (Integer lineNum : lineOffsetDisplacement.keySet()) { -// log(lineNum + "line, disp" -// + lineOffsetDisplacement.get(lineNum)); -// } editor.getSketch().setModified(true); errorCheckerService.runManualErrorCheck(); frmOccurenceList.setVisible(false); From bf6ec9b8e3f06feb52a79e62e7b76f6808582054 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 10 Jun 2014 03:04:01 +0530 Subject: [PATCH 098/115] Minor modifications to show usage window. --- src/processing/mode/experimental/ASTGenerator.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 017874f..97970ce 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -1996,9 +1996,10 @@ protected void refactorIt(){ treeRename.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) treeRename.getModel()).reload(); } - frmOccurenceList.setTitle("Usage of " + selText); - frmOccurenceList.setLocation(editor.getX() + editor.getWidth(),editor.getY()); - frmOccurenceList.setVisible(true); +// frmOccurenceList.setTitle("Usage of \"" + selText + "\" : " +// + defCU.getChildCount() + " time(s)"); +// frmOccurenceList.setLocation(editor.getX() + editor.getWidth(),editor.getY()); +// frmOccurenceList.setVisible(true); int lineOffsetDisplacementConst = newName.length() - selText.length(); HashMap lineOffsetDisplacement = new HashMap(); @@ -2043,7 +2044,7 @@ protected void refactorIt(){ errorCheckerService.resumeThread(); editor.getSketch().setModified(true); errorCheckerService.runManualErrorCheck(); - frmOccurenceList.setVisible(false); +// frmOccurenceList.setVisible(false); frmRename.setVisible(false); lastClickedWord = null; lastClickedWordNode = null; @@ -2090,7 +2091,8 @@ public void handleShowUsage(){ treeRename.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) treeRename.getModel()).reload(); treeRename.setRootVisible(false); - frmOccurenceList.setTitle("Usage of \"" + selText+ "\""); + frmOccurenceList.setTitle("Usage of \"" + selText + "\" : " + + defCU.getChildCount() + " time(s)"); frmOccurenceList.setLocation(editor.getX() + editor.getWidth(),editor.getY()); frmOccurenceList.setVisible(true); lastClickedWord = null; From 5dbe1a58e5e35ebe2562134e81ab240ea224efdb Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 10 Jun 2014 15:16:33 +0530 Subject: [PATCH 099/115] updated todo --- src/processing/mode/experimental/ASTGenerator.java | 2 +- todo.txt | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 97970ce..83a659c 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -240,7 +240,7 @@ protected void setupGUI(){ /** * Toggle AST View window */ - public static final boolean SHOWAST = true; + public static final boolean SHOWAST = !true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { diff --git a/todo.txt b/todo.txt index af2cc8d..d7a2337 100644 --- a/todo.txt +++ b/todo.txt @@ -21,9 +21,13 @@ Normal Bugs ----------- -[x] Sketch NOC 6_09: steer PVector, doesn't show completion. #68 --[ ] Sketch NOC 6_09: Classname in Template, doesn't scroll to decl. This is +-[x] Sketch NOC 6_09: Classname in Template, doesn't scroll to decl. This is happening due certain post processing offsets not being accounted for - "public void" +-[x] New offset matching now used by Show Usage + +-[x] New offset matching now used by Refactoring + Enhancements/New Features ------------------------- From 71a5a1dcafaf0c382dec50ec73064d7fee691354 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 10 Jun 2014 18:36:34 +0530 Subject: [PATCH 100/115] Removed ErrorWindow, wasn't getting used much --- .../mode/experimental/DebugEditor.java | 4 +-- .../experimental/ErrorCheckerService.java | 30 ++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 19eaa3e..28feed5 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -567,7 +567,7 @@ public void actionPerformed(ActionEvent e) { }); debugMenu.add(item); - problemWindowMenuCB = new JCheckBoxMenuItem("Show Problem Window"); + /*problemWindowMenuCB = new JCheckBoxMenuItem("Show Problem Window"); // problemWindowMenuCB.setSelected(true); problemWindowMenuCB.addActionListener(new ActionListener() { @@ -583,7 +583,7 @@ public void actionPerformed(ActionEvent e) { showProblemListView(XQConsoleToggle.CONSOLE); } }); - debugMenu.add(problemWindowMenuCB); + debugMenu.add(problemWindowMenuCB);*/ showWarnings = new JCheckBoxMenuItem("Warnings Enabled"); showWarnings.setSelected(ExperimentalMode.warningsEnabled); diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index 0c7fbf5..e2dafdd 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -87,7 +87,7 @@ public class ErrorCheckerService implements Runnable{ */ protected AtomicBoolean pauseThread; - protected ErrorWindow errorWindow; + //protected ErrorWindow errorWindow; /** * IProblem[] returned by parser stored in here @@ -230,7 +230,7 @@ public ErrorCheckerService(DebugEditor debugEditor) { classpathJars = new ArrayList(); initParser(); - initializeErrorWindow(); + //initializeErrorWindow(); xqpreproc = new XQPreprocessor(); PdePreprocessor pdePrepoc = new PdePreprocessor(null); defaultImportsOffset = pdePrepoc.getCoreImports().length + @@ -266,7 +266,7 @@ protected void initParser() { /** * Initialiazes the Error Window */ - public void initializeErrorWindow() { + /*public void initializeErrorWindow() { if (editor == null) { return; @@ -291,7 +291,7 @@ public void run() { } } }); - } + }*/ public void ensureMinP5Version(){ // Processing 2.1.2 - Revision 0225 @@ -927,26 +927,28 @@ public void updateErrorTable() { String[][] errorData = new String[problemsList.size()][3]; for (int i = 0; i < problemsList.size(); i++) { errorData[i][0] = problemsList.get(i).getMessage(); ////TODO: this is temporary - //+ " : " + errorMsgSimplifier.getIDName(problemsList.get(i).getIProblem().getID()); + //+ " : " + errorMsgSimplifier.getIDName(problemsList.get(i).getIProblem().getID()); errorData[i][1] = editor.getSketch() .getCode(problemsList.get(i).getTabIndex()).getPrettyName(); errorData[i][2] = problemsList.get(i).getLineNumber() + ""; - + //TODO: This is temporary - if(tempErrorLog.size() < 200) - tempErrorLog.put(problemsList.get(i).getMessage(),problemsList.get(i).getIProblem()); + if (tempErrorLog.size() < 200) + tempErrorLog.put(problemsList.get(i).getMessage(), problemsList + .get(i).getIProblem()); } + + DefaultTableModel tm = new DefaultTableModel(errorData, + XQErrorTable.columnNames); + // Update error table in the editor + editor.updateTable(tm); + /* if (errorWindow != null) { - DefaultTableModel tm = new DefaultTableModel(errorData, - XQErrorTable.columnNames); if (errorWindow.isVisible()) { errorWindow.updateTable(tm); } - // Update error table in the editor - editor.updateTable(tm); - // A rotating slash animation on the title bar to show // that error checker thread is running @@ -961,7 +963,7 @@ public void updateErrorTable() { errorWindow.setTitle("Problems - " + editor.getSketch().getName() + " " + info); } - } + }*/ } catch (Exception e) { log("Exception at updateErrorTable() " + e); From ea25389befccc98e1e819d7c5afe01e3e347d921 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 10 Jun 2014 21:36:20 +0530 Subject: [PATCH 101/115] Precise error highlighting :D --- .../mode/experimental/ASTGenerator.java | 4 +- .../experimental/ErrorCheckerService.java | 41 ++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/processing/mode/experimental/ASTGenerator.java b/src/processing/mode/experimental/ASTGenerator.java index 83a659c..d254db7 100644 --- a/src/processing/mode/experimental/ASTGenerator.java +++ b/src/processing/mode/experimental/ASTGenerator.java @@ -240,7 +240,7 @@ protected void setupGUI(){ /** * Toggle AST View window */ - public static final boolean SHOWAST = !true; + public static final boolean SHOWAST = true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { @@ -2059,6 +2059,8 @@ protected void refactorIt(){ */ public void highlightPDECode(int tab, int lineNumber, int lineStartWSOffset, int length) { + log("ASTGen.highlightPDECode: T " + tab + ",L: " + lineNumber + ",LSO: " + + lineStartWSOffset + ",Len: " + length); editor.toFront(); editor.getSketch().setCurrentCode(tab); lineStartWSOffset += editor.ta.getLineStartOffset(lineNumber); diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index e2dafdd..ac43898 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -39,6 +39,7 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.table.DefaultTableModel; +import javax.swing.text.Element; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.IProblem; @@ -1404,7 +1405,7 @@ public void scrollToErrorLine(int errorIndex) { } } - public void scrollToErrorLine(Problem p) { + /*public void scrollToErrorLine(Problem p) { if (editor == null) { return; } @@ -1429,6 +1430,44 @@ public void scrollToErrorLine(Problem p) { e.printStackTrace(); } // log("---"); + }*/ + + public void scrollToErrorLine(Problem p) { + if (editor == null) { + return; + } + if (p == null) + return; + try { + int pkgNameOffset = ("package " + className + ";\n").length(); + int prbStart = p.getIProblem().getSourceStart() - pkgNameOffset, prbEnd = p + .getIProblem().getSourceEnd() - pkgNameOffset; + log("Scrolling to problem: " + p.toString()); + log("P start: " + prbStart + " to " + + prbEnd + " pkgOffset " + pkgNameOffset); + int lineNumber = p + .getIProblem().getSourceLineNumber(); + Element lineElement = astGenerator.getJavaSourceCodeElement(lineNumber); + log("Line element off " + lineElement.getStartOffset()); + OffsetMatcher ofm = new OffsetMatcher( + astGenerator + .getPDESourceCodeLine(lineNumber), + astGenerator + .getJavaSourceCodeLine(lineNumber)); + //log(""); + int pdeOffset = ofm.getPdeOffForJavaOff(prbStart + - lineElement.getStartOffset(), (prbEnd - p + .getIProblem().getSourceStart())); + astGenerator.highlightPDECode(p.getTabIndex(), p.getLineNumber(), + pdeOffset, (prbEnd - prbStart + 1)); + editor.getTextArea().scrollTo(p.getLineNumber() - 1, 0); + editor.repaint(); + } catch (Exception e) { + System.err.println(e + + " : Error while selecting text in scrollToErrorLine()"); + e.printStackTrace(); + } + // log("---"); } /** From 2aeb6117b408ef008df1cf2d804355ab5821deef Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 10 Jun 2014 21:59:15 +0530 Subject: [PATCH 102/115] err underline, nearly there.. --- .../experimental/ErrorCheckerService.java | 40 +++++++++++++++++++ src/processing/mode/experimental/Problem.java | 9 +++++ 2 files changed, 49 insertions(+) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index ac43898..8c62a0c 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -39,7 +39,9 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.table.DefaultTableModel; +import javax.swing.text.BadLocationException; import javax.swing.text.Element; +import javax.swing.text.PlainDocument; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.IProblem; @@ -740,6 +742,44 @@ public boolean accept(File file) { // log("Compilecheck, Done."); } + private void calcPDEOffsetsForProbList() { + PlainDocument javaSource = new PlainDocument(); + try { + javaSource.insertString(0, sourceCode, null); + int pkgNameOffset = ("package " + className + ";\n").length(); + for (Problem p : problemsList) { + int javaLineNumber = p.getIProblem().getSourceLineNumber(); + Element lineElement = javaSource.getDefaultRootElement() + .getElement(javaLineNumber - 1); + if (lineElement == null) { + log("calcPDEOffsetsForProbList(): Couldn't fetch javalinenum " + + javaLineNumber); + continue; + } + String javaLine = javaSource + .getText(lineElement.getStartOffset(), lineElement.getEndOffset() + - lineElement.getStartOffset()); + int prbStart = p.getIProblem().getSourceStart() - pkgNameOffset, prbEnd = p + .getIProblem().getSourceEnd() - pkgNameOffset; + + OffsetMatcher ofm = new OffsetMatcher( + astGenerator + .getPDESourceCodeLine(javaLineNumber), + javaLine); + //log(""); + int pdeOffset = ofm.getPdeOffForJavaOff(prbStart + - lineElement.getStartOffset(), (prbEnd - p + .getIProblem().getSourceStart())); +// astGenerator.highlightPDECode(p.getTabIndex(), p.getLineNumber(), +// pdeOffset, (prbEnd - prbStart + 1)); + p.setPDEOffsets(pdeOffset, prbEnd - prbStart); + } + } catch (BadLocationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + public CompilationUnit getLastCorrectCU(){ return lastCorrectCU; } diff --git a/src/processing/mode/experimental/Problem.java b/src/processing/mode/experimental/Problem.java index aaa8cca..1225238 100644 --- a/src/processing/mode/experimental/Problem.java +++ b/src/processing/mode/experimental/Problem.java @@ -49,6 +49,10 @@ public class Problem { * Line number(pde code) of the error */ private int lineNumber; + + private int lineStartOffset; + + private int lineStopOffset; /** * Error Message. Processed form of IProblem.getMessage() @@ -80,6 +84,11 @@ else if(iProblem.isWarning()) { this.lineNumber = lineNumber; this.message = process(iProblem); } + + public void setPDEOffsets(int startOffset, int stopOffset){ + lineStartOffset = startOffset; + lineStopOffset = stopOffset; + } public String toString() { return new String("TAB " + tabIndex + ",LN " + lineNumber + ",PROB: " From fb432de3abe38ef8fca34b24ef212dd8f0918210 Mon Sep 17 00:00:00 2001 From: Joel Moniz Date: Tue, 10 Jun 2014 23:44:10 +0530 Subject: [PATCH 103/115] Polishing up autosave implementation --- .../mode/experimental/DebugEditor.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 62c6db7..05bd025 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -1085,13 +1085,24 @@ public TextArea textArea() { return ta; } + private boolean wasSaved; + /** * Grab current contents of the sketch window, advance the console, stop any * other running sketches, auto-save the user's code... not in that order. */ @Override public void prepareRun() { + wasSaved = false; + autoSave(); super.prepareRun(); + if (wasSaved) + statusTimedNotice("Saved. Running...", 5); + else + statusTimedNotice("Not saved. Running...", 5); + } + + protected void autoSave() { if (!ExperimentalMode.autoSaveEnabled) return; @@ -1128,15 +1139,14 @@ public void prepareRun() { final JCheckBox dontRedisplay = new JCheckBox( "Remember this decision"); - panel1 = new JPanel(new FlowLayout( - FlowLayout.CENTER, 8, 2)); + panel1 = new JPanel(new FlowLayout(FlowLayout.CENTER, 8, 2)); JButton button = new JButton("Save and Run"); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (handleSave(true)) - statusTimedNotice("Saved. Running...", 5); + wasSaved = true; if (dontRedisplay.isSelected()) { ExperimentalMode.autoSavePromptEnabled = !dontRedisplay .isSelected(); @@ -1152,7 +1162,6 @@ public void actionPerformed(ActionEvent e) { @Override public void actionPerformed(ActionEvent e) { - statusTimedNotice("Not saved. Running...", 5); if (dontRedisplay.isSelected()) { ExperimentalMode.autoSavePromptEnabled = !dontRedisplay .isSelected(); @@ -1179,11 +1188,13 @@ public void actionPerformed(ActionEvent e) { autoSaveDialog.setVisible(true); } else if (ExperimentalMode.defaultAutoSaveEnabled) - handleSave(true); + if (handleSave(true)) + wasSaved = true; } } catch (Exception e) { statusError(e); } + } /** From 45035f81f383a0280bcd6237dbe94bd8093bd298 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 11 Jun 2014 00:06:46 +0530 Subject: [PATCH 104/115] meh. broke something again --- .../experimental/ErrorCheckerService.java | 45 ++++++++++++++++--- src/processing/mode/experimental/Problem.java | 13 +++++- .../mode/experimental/TextAreaPainter.java | 15 ++++--- 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index 8c62a0c..50e912c 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -715,6 +715,7 @@ public boolean accept(File file) { } problemsList.add(p); } + calcPDEOffsetsForProbList(); } } catch (ClassNotFoundException e) { System.err.println("Compiltation Checker files couldn't be found! " @@ -742,15 +743,37 @@ public boolean accept(File file) { // log("Compilecheck, Done."); } + /** + * Calculates PDE Offsets from Java Offsets for Problems + */ private void calcPDEOffsetsForProbList() { PlainDocument javaSource = new PlainDocument(); - try { + // Code in pde tabs stored as PlainDocument + PlainDocument pdeTabs[] = new PlainDocument[editor.getSketch() + .getCodeCount()]; + + try { javaSource.insertString(0, sourceCode, null); + for (int i = 0; i < pdeTabs.length; i++) { + SketchCode sc = editor.getSketch().getCode(i); + pdeTabs[i] = new PlainDocument(); + if (editor.getSketch().getCurrentCode().equals(sc)) { + pdeTabs[i].insertString(0, + sc.getDocument().getText(0, + sc.getDocument() + .getLength()), + null); + } else { + pdeTabs[i].insertString(0, + sc.getProgram(), + null); + } + } int pkgNameOffset = ("package " + className + ";\n").length(); for (Problem p : problemsList) { int javaLineNumber = p.getIProblem().getSourceLineNumber(); Element lineElement = javaSource.getDefaultRootElement() - .getElement(javaLineNumber - 1); + .getElement(javaLineNumber - 2); if (lineElement == null) { log("calcPDEOffsetsForProbList(): Couldn't fetch javalinenum " + javaLineNumber); @@ -761,11 +784,19 @@ private void calcPDEOffsetsForProbList() { - lineElement.getStartOffset()); int prbStart = p.getIProblem().getSourceStart() - pkgNameOffset, prbEnd = p .getIProblem().getSourceEnd() - pkgNameOffset; - - OffsetMatcher ofm = new OffsetMatcher( - astGenerator - .getPDESourceCodeLine(javaLineNumber), - javaLine); + Element pdeLineElement = pdeTabs[p.getTabIndex()] + .getDefaultRootElement().getElement(p.getLineNumber()-1); + if (pdeLineElement == null) { + log("calcPDEOffsetsForProbList(): Couldn't fetch pdelinenum " + + javaLineNumber); + continue; + } + String pdeLine = pdeTabs[p.getTabIndex()] + .getText(pdeLineElement.getStartOffset(), pdeLineElement.getEndOffset() + - pdeLineElement.getStartOffset()); + log("calcPDEOffsetsForProbList(): P " + pdeLine); + log("calcPDEOffsetsForProbList(): J " + javaLine); + OffsetMatcher ofm = new OffsetMatcher(pdeLine, javaLine); //log(""); int pdeOffset = ofm.getPdeOffForJavaOff(prbStart - lineElement.getStartOffset(), (prbEnd - p diff --git a/src/processing/mode/experimental/Problem.java b/src/processing/mode/experimental/Problem.java index 1225238..4f7e9c4 100644 --- a/src/processing/mode/experimental/Problem.java +++ b/src/processing/mode/experimental/Problem.java @@ -89,10 +89,19 @@ public void setPDEOffsets(int startOffset, int stopOffset){ lineStartOffset = startOffset; lineStopOffset = stopOffset; } + + public int getPDELineStartOffset(){ + return lineStartOffset; + } + + public int getPDELineStopOffset(){ + return lineStopOffset; + } public String toString() { - return new String("TAB " + tabIndex + ",LN " + lineNumber + ",PROB: " - + message); + return new String("TAB " + tabIndex + ",LN " + lineNumber + "LN START OFF: " + + lineStartOffset + ",LN STOP OFF: " + lineStopOffset + ",PROB: " + + message); } public boolean isError(){ diff --git a/src/processing/mode/experimental/TextAreaPainter.java b/src/processing/mode/experimental/TextAreaPainter.java index 8b7f5e9..4a5c628 100644 --- a/src/processing/mode/experimental/TextAreaPainter.java +++ b/src/processing/mode/experimental/TextAreaPainter.java @@ -314,7 +314,8 @@ protected void paintErrorLine(Graphics gfx, int line, int x) { boolean notFound = true; boolean isWarning = false; - + Problem problem = null; + // Check if current line contains an error. If it does, find if it's an // error or warning for (ErrorMarker emarker : errorCheckerService.getEditor().errorBar.errorPoints) { @@ -323,6 +324,8 @@ protected void paintErrorLine(Graphics gfx, int line, int x) { if (emarker.getType() == ErrorMarker.Warning) { isWarning = true; } + problem = emarker.getProblem(); + log(problem.toString()); break; } } @@ -337,15 +340,15 @@ protected void paintErrorLine(Graphics gfx, int line, int x) { int y = ta.lineToY(line); y += fm.getLeading() + fm.getMaxDescent(); int height = fm.getHeight(); - int start = ta.getLineStartOffset(line); - + int start = ta.getLineStartOffset(line) + problem.getPDELineStartOffset(); + int pLength = problem.getPDELineStopOffset() + 1 + - problem.getPDELineStartOffset(); try { String linetext = null; try { - linetext = ta.getDocument().getText(start, - ta.getLineStopOffset(line) - start - - 1); + linetext = ta.getDocument().getText(start, pLength); + log("paintErrorLine() LineText: " + linetext); } catch (BadLocationException bl) { // Error in the import statements or end of code. // System.out.print("BL caught. " + ta.getLineCount() + " ," From e8bfb33ad6db1a52c4f959bb2ed6bf59dfbb5c83 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 11 Jun 2014 00:43:32 +0530 Subject: [PATCH 105/115] precisise highlighting working only for specific compiler errors, needs more work --- .../experimental/ErrorCheckerService.java | 4 ++-- .../mode/experimental/TextAreaPainter.java | 21 ++++++++++++------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index 50e912c..89ca039 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -751,7 +751,7 @@ private void calcPDEOffsetsForProbList() { // Code in pde tabs stored as PlainDocument PlainDocument pdeTabs[] = new PlainDocument[editor.getSketch() .getCodeCount()]; - + log("calcPDEOffsetsForProbList() mco: " + mainClassOffset); try { javaSource.insertString(0, sourceCode, null); for (int i = 0; i < pdeTabs.length; i++) { @@ -803,7 +803,7 @@ private void calcPDEOffsetsForProbList() { .getIProblem().getSourceStart())); // astGenerator.highlightPDECode(p.getTabIndex(), p.getLineNumber(), // pdeOffset, (prbEnd - prbStart + 1)); - p.setPDEOffsets(pdeOffset, prbEnd - prbStart); + p.setPDEOffsets(pdeOffset, pdeOffset + prbEnd - prbStart); } } catch (BadLocationException e) { // TODO Auto-generated catch block diff --git a/src/processing/mode/experimental/TextAreaPainter.java b/src/processing/mode/experimental/TextAreaPainter.java index 4a5c628..04714dd 100644 --- a/src/processing/mode/experimental/TextAreaPainter.java +++ b/src/processing/mode/experimental/TextAreaPainter.java @@ -325,7 +325,7 @@ protected void paintErrorLine(Graphics gfx, int line, int x) { isWarning = true; } problem = emarker.getProblem(); - log(problem.toString()); + //log(problem.toString()); break; } } @@ -343,12 +343,16 @@ protected void paintErrorLine(Graphics gfx, int line, int x) { int start = ta.getLineStartOffset(line) + problem.getPDELineStartOffset(); int pLength = problem.getPDELineStopOffset() + 1 - problem.getPDELineStartOffset(); + try { - String linetext = null; - + String badCode = null; + String goodCode = null; try { - linetext = ta.getDocument().getText(start, pLength); - log("paintErrorLine() LineText: " + linetext); + badCode = ta.getDocument().getText(start, pLength); + goodCode = ta.getDocument().getText(ta.getLineStartOffset(line), + problem.getPDELineStartOffset()); + //log("paintErrorLine() LineText GC: " + goodCode); + //log("paintErrorLine() LineText BC: " + badCode); } catch (BadLocationException bl) { // Error in the import statements or end of code. // System.out.print("BL caught. " + ta.getLineCount() + " ," @@ -358,11 +362,12 @@ protected void paintErrorLine(Graphics gfx, int line, int x) { } // Take care of offsets - int aw = fm.stringWidth(trimRight(linetext)) + ta.getHorizontalOffset(); // apparent width. Whitespaces + int aw = fm.stringWidth(trimRight(badCode)) + ta.getHorizontalOffset(); // apparent width. Whitespaces // to the left of line + text // width - int rw = fm.stringWidth(linetext.trim()); // real width - int x1 = 0 + (aw - rw), y1 = y + fm.getHeight() - 2, x2 = x1 + rw; + int rw = fm.stringWidth(badCode.trim()); // real width + int x1 = fm.stringWidth(goodCode) + (aw - rw), y1 = y + fm.getHeight() + - 2, x2 = x1 + rw; // Adding offsets for the gutter x1 += ta.getGutterWidth(); x2 += ta.getGutterWidth(); From ecf071d617d521a8694ce26515aa8ac724a75255 Mon Sep 17 00:00:00 2001 From: Joel Moniz Date: Wed, 11 Jun 2014 00:59:18 +0530 Subject: [PATCH 106/115] More changes to auto-save Removing status notices --- .../mode/experimental/DebugEditor.java | 88 +++++++------------ 1 file changed, 32 insertions(+), 56 deletions(-) diff --git a/src/processing/mode/experimental/DebugEditor.java b/src/processing/mode/experimental/DebugEditor.java index 05bd025..7fa9713 100755 --- a/src/processing/mode/experimental/DebugEditor.java +++ b/src/processing/mode/experimental/DebugEditor.java @@ -1085,23 +1085,21 @@ public TextArea textArea() { return ta; } - private boolean wasSaved; - + /** * Grab current contents of the sketch window, advance the console, stop any * other running sketches, auto-save the user's code... not in that order. */ @Override public void prepareRun() { - wasSaved = false; autoSave(); super.prepareRun(); - if (wasSaved) - statusTimedNotice("Saved. Running...", 5); - else - statusTimedNotice("Not saved. Running...", 5); } + /** + * Displays a JDialog prompting the user to save when the user hits + * run/present/etc. + */ protected void autoSave() { if (!ExperimentalMode.autoSaveEnabled) return; @@ -1122,11 +1120,14 @@ protected void autoSave() { true); Container container = autoSaveDialog.getContentPane(); - JPanel panel = new JPanel(); - panel.setBorder(BorderFactory.createEmptyBorder(4, 0, 2, 2)); - panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); + JPanel panelMain = new JPanel(); + panelMain.setBorder(BorderFactory.createEmptyBorder(4, 0, + 2, 2)); + panelMain.setLayout(new BoxLayout(panelMain, + BoxLayout.PAGE_AXIS)); - JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.LEFT)); + JPanel panelLabel = new JPanel(new FlowLayout( + FlowLayout.LEFT)); JLabel label = new JLabel( " There are unsaved" + " changes in your sketch.
" @@ -1134,19 +1135,19 @@ protected void autoSave() { + " running? "); label.setFont(new Font(label.getFont().getName(), Font.PLAIN, label.getFont().getSize() + 1)); - panel1.add(label); - panel.add(panel1); + panelLabel.add(label); + panelMain.add(panelLabel); final JCheckBox dontRedisplay = new JCheckBox( "Remember this decision"); - panel1 = new JPanel(new FlowLayout(FlowLayout.CENTER, 8, 2)); - JButton button = new JButton("Save and Run"); - button.addActionListener(new ActionListener() { + JPanel panelButtons = new JPanel(new FlowLayout( + FlowLayout.CENTER, 8, 2)); + JButton btnRunSave = new JButton("Save and Run"); + btnRunSave.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - if (handleSave(true)) - wasSaved = true; + handleSave(true); if (dontRedisplay.isSelected()) { ExperimentalMode.autoSavePromptEnabled = !dontRedisplay .isSelected(); @@ -1156,9 +1157,9 @@ public void actionPerformed(ActionEvent e) { autoSaveDialog.dispose(); } }); - panel1.add(button); - button = new JButton("Run, Don't Save"); - button.addActionListener(new ActionListener() { + panelButtons.add(btnRunSave); + JButton btnRunNoSave = new JButton("Run, Don't Save"); + btnRunNoSave.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -1171,15 +1172,16 @@ public void actionPerformed(ActionEvent e) { autoSaveDialog.dispose(); } }); - panel1.add(button); - panel.add(panel1); + panelButtons.add(btnRunNoSave); + panelMain.add(panelButtons); - panel1 = new JPanel(); - panel1.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0)); - panel1.add(dontRedisplay); - panel.add(panel1); + JPanel panelCheck = new JPanel(); + panelCheck + .setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0)); + panelCheck.add(dontRedisplay); + panelMain.add(panelCheck); - container.add(panel); + container.add(panelMain); autoSaveDialog.setResizable(false); autoSaveDialog.pack(); @@ -1188,39 +1190,13 @@ public void actionPerformed(ActionEvent e) { autoSaveDialog.setVisible(true); } else if (ExperimentalMode.defaultAutoSaveEnabled) - if (handleSave(true)) - wasSaved = true; + handleSave(true); } } catch (Exception e) { statusError(e); } - } - - /** - * Shows a notice message in the editor status bar for a certain duration of - * time. - * - * @param msg - * @param secs - */ - public void statusTimedNotice(final String msg, final int secs) { - SwingWorker s = new SwingWorker() { - - @Override - protected Void doInBackground() throws Exception { - statusNotice(msg); - try { - Thread.sleep(secs * 1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - statusEmpty(); - return null; - } - }; - s.execute(); - } + } /** * Access variable inspector window. From 2eaf4acf751aa0bcf2dc3732224cb02ea18c1048 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 11 Jun 2014 02:49:34 +0530 Subject: [PATCH 107/115] one simply doesn't have enough scrolling routines --- .../experimental/ErrorCheckerService.java | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index 89ca039..3590c08 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -1503,7 +1503,7 @@ public void scrollToErrorLine(int errorIndex) { // log("---"); }*/ - public void scrollToErrorLine(Problem p) { + /*public void scrollToErrorLine(Problem p) { if (editor == null) { return; } @@ -1517,7 +1517,7 @@ public void scrollToErrorLine(Problem p) { log("P start: " + prbStart + " to " + prbEnd + " pkgOffset " + pkgNameOffset); int lineNumber = p - .getIProblem().getSourceLineNumber(); + .getIProblem().getSourceLineNumber()-1; Element lineElement = astGenerator.getJavaSourceCodeElement(lineNumber); log("Line element off " + lineElement.getStartOffset()); OffsetMatcher ofm = new OffsetMatcher( @@ -1529,7 +1529,7 @@ public void scrollToErrorLine(Problem p) { int pdeOffset = ofm.getPdeOffForJavaOff(prbStart - lineElement.getStartOffset(), (prbEnd - p .getIProblem().getSourceStart())); - astGenerator.highlightPDECode(p.getTabIndex(), p.getLineNumber(), + astGenerator.highlightPDECode(p.getTabIndex(), p.getLineNumber()-1, pdeOffset, (prbEnd - prbStart + 1)); editor.getTextArea().scrollTo(p.getLineNumber() - 1, 0); editor.repaint(); @@ -1539,6 +1539,28 @@ public void scrollToErrorLine(Problem p) { e.printStackTrace(); } // log("---"); + }*/ + + public void scrollToErrorLine(Problem p) { + if (editor == null) { + return; + } + if (p == null) + return; + try { + astGenerator.highlightPDECode(p.getTabIndex(), + p.getLineNumber() - 1, + p.getPDELineStartOffset(), + (p.getPDELineStopOffset() + - p.getPDELineStartOffset() + 1)); + editor.getTextArea().scrollTo(p.getLineNumber() - 1, 0); + editor.repaint(); + } catch (Exception e) { + System.err.println(e + + " : Error while selecting text in scrollToErrorLine()"); + e.printStackTrace(); + } + // log("---"); } /** From f3330884c85211f24601d03a869f5d4ad157c8cc Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 11 Jun 2014 03:06:38 +0530 Subject: [PATCH 108/115] declicate +1 -1 changes --- .../experimental/ErrorCheckerService.java | 42 +++++++++++-------- .../mode/experimental/TextAreaPainter.java | 2 +- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index 3590c08..abcb5a1 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -463,8 +463,10 @@ protected boolean checkCode() { log(editor.getSketch().getName() + "2 MCO " + mainClassOffset); } + astGenerator.buildAST(cu); if(ExperimentalMode.errorCheckEnabled){ + calcPDEOffsetsForProbList(); updateErrorTable(); editor.updateErrorBar(problemsList); updateEditorStatus(); @@ -686,7 +688,10 @@ public boolean accept(File file) { ((Integer) errorList[i][4]).intValue(), ((Integer) errorList[i][5]).intValue(), ((Integer) errorList[i][6]).intValue(), - ((Integer) errorList[i][7]).intValue(), 0); + ((Integer) errorList[i][7]).intValue() - 1, 0); + // added a -1 to line number because in compile check code + // an extra package statement is added, so all line numbers + // are increased by 1 // System.out // .println("ECS: " + problems[i].getMessage() + "," @@ -715,7 +720,6 @@ public boolean accept(File file) { } problemsList.add(p); } - calcPDEOffsetsForProbList(); } } catch (ClassNotFoundException e) { System.err.println("Compiltation Checker files couldn't be found! " @@ -747,12 +751,14 @@ public boolean accept(File file) { * Calculates PDE Offsets from Java Offsets for Problems */ private void calcPDEOffsetsForProbList() { - PlainDocument javaSource = new PlainDocument(); - // Code in pde tabs stored as PlainDocument - PlainDocument pdeTabs[] = new PlainDocument[editor.getSketch() - .getCodeCount()]; - log("calcPDEOffsetsForProbList() mco: " + mainClassOffset); - try { + try { + PlainDocument javaSource = new PlainDocument(); + // Code in pde tabs stored as PlainDocument + PlainDocument pdeTabs[] = new PlainDocument[editor.getSketch() + .getCodeCount()]; + log("calcPDEOffsetsForProbList() mco: " + mainClassOffset + " CU state: " + + compilationUnitState); + javaSource.insertString(0, sourceCode, null); for (int i = 0; i < pdeTabs.length; i++) { SketchCode sc = editor.getSketch().getCode(i); @@ -771,9 +777,10 @@ private void calcPDEOffsetsForProbList() { } int pkgNameOffset = ("package " + className + ";\n").length(); for (Problem p : problemsList) { - int javaLineNumber = p.getIProblem().getSourceLineNumber(); + log(p.toString()); + int javaLineNumber = p.getIProblem().getSourceLineNumber() - 1; Element lineElement = javaSource.getDefaultRootElement() - .getElement(javaLineNumber - 2); + .getElement(javaLineNumber); if (lineElement == null) { log("calcPDEOffsetsForProbList(): Couldn't fetch javalinenum " + javaLineNumber); @@ -785,7 +792,7 @@ private void calcPDEOffsetsForProbList() { int prbStart = p.getIProblem().getSourceStart() - pkgNameOffset, prbEnd = p .getIProblem().getSourceEnd() - pkgNameOffset; Element pdeLineElement = pdeTabs[p.getTabIndex()] - .getDefaultRootElement().getElement(p.getLineNumber()-1); + .getDefaultRootElement().getElement(p.getLineNumber()); if (pdeLineElement == null) { log("calcPDEOffsetsForProbList(): Couldn't fetch pdelinenum " + javaLineNumber); @@ -794,8 +801,8 @@ private void calcPDEOffsetsForProbList() { String pdeLine = pdeTabs[p.getTabIndex()] .getText(pdeLineElement.getStartOffset(), pdeLineElement.getEndOffset() - pdeLineElement.getStartOffset()); - log("calcPDEOffsetsForProbList(): P " + pdeLine); - log("calcPDEOffsetsForProbList(): J " + javaLine); + //log("calcPDEOffsetsForProbList(): P " + pdeLine); + //log("calcPDEOffsetsForProbList(): J " + javaLine); OffsetMatcher ofm = new OffsetMatcher(pdeLine, javaLine); //log(""); int pdeOffset = ofm.getPdeOffForJavaOff(prbStart @@ -805,8 +812,9 @@ private void calcPDEOffsetsForProbList() { // pdeOffset, (prbEnd - prbStart + 1)); p.setPDEOffsets(pdeOffset, pdeOffset + prbEnd - prbStart); } - } catch (BadLocationException e) { - // TODO Auto-generated catch block + } catch (BadLocationException ble) { + ble.printStackTrace(); + } catch (Exception e) { e.printStackTrace(); } } @@ -1549,11 +1557,11 @@ public void scrollToErrorLine(Problem p) { return; try { astGenerator.highlightPDECode(p.getTabIndex(), - p.getLineNumber() - 1, + p.getLineNumber(), p.getPDELineStartOffset(), (p.getPDELineStopOffset() - p.getPDELineStartOffset() + 1)); - editor.getTextArea().scrollTo(p.getLineNumber() - 1, 0); + editor.getTextArea().scrollTo(p.getLineNumber(), 0); editor.repaint(); } catch (Exception e) { System.err.println(e diff --git a/src/processing/mode/experimental/TextAreaPainter.java b/src/processing/mode/experimental/TextAreaPainter.java index 04714dd..4961510 100644 --- a/src/processing/mode/experimental/TextAreaPainter.java +++ b/src/processing/mode/experimental/TextAreaPainter.java @@ -319,7 +319,7 @@ protected void paintErrorLine(Graphics gfx, int line, int x) { // Check if current line contains an error. If it does, find if it's an // error or warning for (ErrorMarker emarker : errorCheckerService.getEditor().errorBar.errorPoints) { - if (emarker.getProblem().getLineNumber() == line + 1) { + if (emarker.getProblem().getLineNumber() == line) { notFound = false; if (emarker.getType() == ErrorMarker.Warning) { isWarning = true; From 0528fb3613408c6cf4ebabf85754c6ed90795d28 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 11 Jun 2014 03:13:39 +0530 Subject: [PATCH 109/115] no more cheeky stuff --- .../mode/experimental/ErrorCheckerService.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index abcb5a1..a6e936d 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -540,8 +540,7 @@ protected void syntaxCheck() { problemsList = new ArrayList(); for (int i = 0; i < problems.length; i++) { int a[] = calculateTabIndexAndLineNumber(problems[i].getSourceLineNumber()); - Problem p = new Problem(problems[i], a[0], a[1] + 1); - //TODO: ^Why do cheeky stuff? + Problem p = new Problem(problems[i], a[0], a[1]); problemsList.add(p); // log(problems[i].getMessage()); // for (String j : problems[i].getArguments()) { @@ -777,7 +776,10 @@ private void calcPDEOffsetsForProbList() { } int pkgNameOffset = ("package " + className + ";\n").length(); for (Problem p : problemsList) { + int prbStart = p.getIProblem().getSourceStart() - pkgNameOffset, prbEnd = p + .getIProblem().getSourceEnd() - pkgNameOffset; log(p.toString()); + log("IProblem Start " + prbStart + ", End " + prbEnd); int javaLineNumber = p.getIProblem().getSourceLineNumber() - 1; Element lineElement = javaSource.getDefaultRootElement() .getElement(javaLineNumber); @@ -789,8 +791,7 @@ private void calcPDEOffsetsForProbList() { String javaLine = javaSource .getText(lineElement.getStartOffset(), lineElement.getEndOffset() - lineElement.getStartOffset()); - int prbStart = p.getIProblem().getSourceStart() - pkgNameOffset, prbEnd = p - .getIProblem().getSourceEnd() - pkgNameOffset; + Element pdeLineElement = pdeTabs[p.getTabIndex()] .getDefaultRootElement().getElement(p.getLineNumber()); if (pdeLineElement == null) { @@ -806,8 +807,7 @@ private void calcPDEOffsetsForProbList() { OffsetMatcher ofm = new OffsetMatcher(pdeLine, javaLine); //log(""); int pdeOffset = ofm.getPdeOffForJavaOff(prbStart - - lineElement.getStartOffset(), (prbEnd - p - .getIProblem().getSourceStart())); + - lineElement.getStartOffset(), (prbEnd - prbStart + 1)); // astGenerator.highlightPDECode(p.getTabIndex(), p.getLineNumber(), // pdeOffset, (prbEnd - prbStart + 1)); p.setPDEOffsets(pdeOffset, pdeOffset + prbEnd - prbStart); From 8115c9873136293b3f07a8e43fa5c41fff4f1af5 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 11 Jun 2014 03:17:53 +0530 Subject: [PATCH 110/115] should've done it like this --- src/processing/mode/experimental/ErrorCheckerService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index a6e936d..7e4280d 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -1010,7 +1010,8 @@ public void updateErrorTable() { //+ " : " + errorMsgSimplifier.getIDName(problemsList.get(i).getIProblem().getID()); errorData[i][1] = editor.getSketch() .getCode(problemsList.get(i).getTabIndex()).getPrettyName(); - errorData[i][2] = problemsList.get(i).getLineNumber() + ""; + errorData[i][2] = (problemsList.get(i).getLineNumber() + 1) + ""; + // Added +1 because lineNumbers internally are 0-indexed //TODO: This is temporary if (tempErrorLog.size() < 200) From ddceda2e07aa37e077d276aa6d03e6845bbf4994 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 11 Jun 2014 03:29:57 +0530 Subject: [PATCH 111/115] precise error highlighting. Nailed it \m/ --- src/processing/mode/experimental/ErrorCheckerService.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index 7e4280d..a8ba5e9 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -775,6 +775,9 @@ private void calcPDEOffsetsForProbList() { } } int pkgNameOffset = ("package " + className + ";\n").length(); + // package name is added only during compile check + if(compilationUnitState != 2) pkgNameOffset = 0; + for (Problem p : problemsList) { int prbStart = p.getIProblem().getSourceStart() - pkgNameOffset, prbEnd = p .getIProblem().getSourceEnd() - pkgNameOffset; @@ -1086,7 +1089,7 @@ public void updateEditorStatus() { synchronized (editor.errorBar.errorPoints) { for (ErrorMarker emarker : editor.errorBar.errorPoints) { if (emarker.getProblem().getLineNumber() == editor.getTextArea() - .getCaretLine() + 1) { + .getCaretLine()) { if (emarker.getType() == ErrorMarker.Warning) { editor.statusMessage(emarker.getProblem().getMessage(), DebugEditor.STATUS_INFO); From 437244ea95119bba3963a45049b407f3ea981c43 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 11 Jun 2014 03:34:49 +0530 Subject: [PATCH 112/115] updated todo --- todo.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/todo.txt b/todo.txt index d7a2337..c177853 100644 --- a/todo.txt +++ b/todo.txt @@ -31,6 +31,10 @@ happening due certain post processing offsets not being accounted for - "public Enhancements/New Features ------------------------- +-[x] Precise error highlighting(PEH). Now working for one error per line. Hell yeah! + +-[ ] Gotta fix PEH for multiple errors per line. Will be slightly meticulous. + -[ ] When viewing Outline View, instead of showing the beginning of the list, it should select the current node element within which the cursor is presently positioned. @@ -42,3 +46,5 @@ positioned. -[ ] Preferences panel -[ ] Line Numbers + + From ffe9159d0a70ef673b664f68ab13e5e2192dc42b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 11 Jun 2014 03:35:27 +0530 Subject: [PATCH 113/115] sweet joys of trimming code --- .../experimental/ErrorCheckerService.java | 65 ------------------- 1 file changed, 65 deletions(-) diff --git a/src/processing/mode/experimental/ErrorCheckerService.java b/src/processing/mode/experimental/ErrorCheckerService.java index a8ba5e9..61cc974 100644 --- a/src/processing/mode/experimental/ErrorCheckerService.java +++ b/src/processing/mode/experimental/ErrorCheckerService.java @@ -1488,71 +1488,6 @@ public void scrollToErrorLine(int errorIndex) { } } - /*public void scrollToErrorLine(Problem p) { - if (editor == null) { - return; - } - if (p == null) - return; - try { - editor.toFront(); - editor.getSketch().setCurrentCode(p.getTabIndex()); - - editor - .setSelection(editor.getTextArea() - .getLineStartNonWhiteSpaceOffset(p.getLineNumber() - 1) - + editor.getTextArea() - .getLineText(p.getLineNumber() - 1).trim().length(), - editor.getTextArea() - .getLineStartNonWhiteSpaceOffset(p.getLineNumber() - 1)); - editor.getTextArea().scrollTo(p.getLineNumber() - 1, 0); - editor.repaint(); - } catch (Exception e) { - System.err.println(e - + " : Error while selecting text in scrollToErrorLine()"); - e.printStackTrace(); - } - // log("---"); - }*/ - - /*public void scrollToErrorLine(Problem p) { - if (editor == null) { - return; - } - if (p == null) - return; - try { - int pkgNameOffset = ("package " + className + ";\n").length(); - int prbStart = p.getIProblem().getSourceStart() - pkgNameOffset, prbEnd = p - .getIProblem().getSourceEnd() - pkgNameOffset; - log("Scrolling to problem: " + p.toString()); - log("P start: " + prbStart + " to " - + prbEnd + " pkgOffset " + pkgNameOffset); - int lineNumber = p - .getIProblem().getSourceLineNumber()-1; - Element lineElement = astGenerator.getJavaSourceCodeElement(lineNumber); - log("Line element off " + lineElement.getStartOffset()); - OffsetMatcher ofm = new OffsetMatcher( - astGenerator - .getPDESourceCodeLine(lineNumber), - astGenerator - .getJavaSourceCodeLine(lineNumber)); - //log(""); - int pdeOffset = ofm.getPdeOffForJavaOff(prbStart - - lineElement.getStartOffset(), (prbEnd - p - .getIProblem().getSourceStart())); - astGenerator.highlightPDECode(p.getTabIndex(), p.getLineNumber()-1, - pdeOffset, (prbEnd - prbStart + 1)); - editor.getTextArea().scrollTo(p.getLineNumber() - 1, 0); - editor.repaint(); - } catch (Exception e) { - System.err.println(e - + " : Error while selecting text in scrollToErrorLine()"); - e.printStackTrace(); - } - // log("---"); - }*/ - public void scrollToErrorLine(Problem p) { if (editor == null) { return; From 786f26f263eb062e9d327fbc300ae970064b1784 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Thu, 12 Jun 2014 19:24:14 +0530 Subject: [PATCH 114/115] tracking build props file again --- build.properties | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/build.properties b/build.properties index 4dfc002..ed26d76 100644 --- a/build.properties +++ b/build.properties @@ -1,10 +1,10 @@ -sketchbook.location= -classpath.local.location= -core.library.location= -app.library.location= -java.target.version=1.6 +sketchbook.location=${user.home}/Documents/Processing +classpath.local.location=${user.home}/Documents/workspace/libs +core.library.location=/home/quarkninja/Workspaces/processing-workspace/processing/app/core/library +app.library.location=/home/quarkninja/Workspaces/processing-workspace/processing/app/ +java.target.version=1.7 lib.name=ExperimentalMode prettyName=PDE X dist=dist -release=3 -prettyVersion=1.0.0b +release=7 +prettyVersion=1.0.4b From 2efe9b256724e1b13baf0f6e1b1074305d79ec47 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 21 Sep 2014 10:00:14 -0700 Subject: [PATCH 115/115] updated readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b536249..a49be85 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +**Update**: This repo is no longer active. PDE X codebase was merged into the [main processing repo](https://github.com/processing/processing/) starting with the 3.0 alpha releases (July 2014), further development continues in the main repo. So please report any issues in the main Processing repo. + PDE X =====