difference-2.0.0/.gitignore01006440000765000002400000000463130471654310014021 0ustar0000000000000000# Compiled files *.o *.so *.rlib *.dll # Executables *.exe # Project specific stuff target Cargo.lock # rustfmt *.bk # Editor Stuff *.sublime-project *.sublime-workspace .*.swp *.bak *~ .vscode # System stuff .DS_Store .Spotlight-V100 .Trashes Thumbs.db ehthumbs.db Desktop.ini $RECYCLE.BIN/ .directory difference-2.0.0/.travis.yml01006440000765000002400000004372131347365660014157 0ustar0000000000000000dist: trusty sudo: false language: rust rust: - stable - beta - nightly install: # Install rustfmt # There are no linux binaries for rustfmt-bin available right now. See https://github.com/japaric/rustfmt-bin/issues/2. #- curl -LSfs https://japaric.github.io/trust/install.sh | sh -s -- --force --crate rustfmt --git japaric/rustfmt-bin --tag v0.9.0-20170614 - if [ "$TRAVIS_RUST_VERSION" = "stable" ]; then (cargo install rustfmt --vers 0.9.0 --force) fi # Install clippy - if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then (cargo install clippy --force) fi - export PATH=$HOME/.cargo/bin:$PATH script: - cargo build --features=bin - cargo test - if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then (cargo clippy) fi - if [ "$TRAVIS_RUST_VERSION" = "stable" ]; then (cargo fmt -- --write-mode=diff) fi addons: apt: packages: - libcurl4-openssl-dev - libelf-dev - libdw-dev - cmake - gcc - binutils-dev cache: apt: true directories: - $HOME/.cargo - target/debug/build before_cache: # Travis can't cache files that are not readable by "others" - chmod -R a+r $HOME/.cargo after_success: | [ $TRAVIS_RUST_VERSION = stable ] && wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. && ls target/debug && ./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=$TRAVIS_JOB_ID --exclude-pattern=/.cargo target/kcov target/debug/difference-* env: global: - secure: by21VBcjZUvTcgLKxo9lSKIoHfPCHPHitazvLgebRInyI82hH39HiCsNLVwjU6BGGjTnj9Y/j/ygr8qogq+WW+Wls2LrMsomid+I5WvldgJNPoKaHNNa68zTK18zVq68nM351CU9CjMSMS7MPpWsrgD6avAB50nmrEjWhi8n6jwu6FIXkRZtOyIgdlR/Qm1CnOA5OX2i3EiGe0r90tLpEpyaQ2Ml0pLyBdlxftqef++nvY9e0ufihGdzkRyVAsDs7td4JkHkEPN9rKMRx0jq42daB5Mvu9nWKPGbz04RfOug0SxaT7BnUhRsIJGwd9be7Hz2Wdvb5I7uV/g86INojMhU8S4/BlXKkIy1CZvLrQc+fGjeA9MXFeKFBVbC3L+qAfTPdkhjw6VAdg37tiYzV4lnPYyujiY00qGmKTKoG+xGTx/jEX2kRt8p7OGXgougwxIbEowHOduYtbCnBmhng6bcy3qyr8AztcM44AIlEy3OLKB7ocgvoFv+Fz4kjROQCVq+oW86bZ014Ex8k32wAlibU8M3mVALRk6Cgk7nbCl6s1+Y5uZE/TeDaLEYpLGSqYWeU9in8o4m6U65bh9XEUCnEgY7IcwV93zHUA+i50bwOROkS7c57bvAfdq/dwaW79VHqpq5D2toDVlKXYN90r6vAX0VhH91rW31FNXe0X0= difference-2.0.0/appveyor.yml01006440000765000002400000002010130471665040014411 0ustar0000000000000000environment: global: RUST_VERSION: stable matrix: # Stable channel - TARGET: x86_64-pc-windows-gnu CHANNEL: stable - TARGET: i686-pc-windows-msvc CHANNEL: stable - TARGET: x86_64-pc-windows-msvc CHANNEL: stable # Beta channel - TARGET: x86_64-pc-windows-msvc CHANNEL: beta # Nightly channel - TARGET: x86_64-pc-windows-msvc CHANNEL: nightly install: - ps: >- If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') { $Env:PATH += ';C:\msys64\mingw64\bin' } ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') { $Env:PATH += ';C:\msys64\mingw32\bin' } - curl -sSf -o rustup-init.exe https://win.rustup.rs/ - rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION% - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - rustc -Vv - cargo -V # Build and test test_script: - cargo build --features=bin - cargo test cache: - C:\Users\appveyor\.cargo\registry - target # disable automatic builds build: false difference-2.0.0/assets/fox.png01006440000765000002400000157057130471654270014656 0ustar0000000000000000PNG  IHDR"l&.u] iCCPICC ProfileHWXS[R -)7Az;FHB ؑEׂVtUDŵذ`AuADEY 6T$~{9Νoy[@*F{1?P@b <#"B?[usq@" N䲳 >  t@<XY @$qkq[Jl#!Leȉ3٩0bK>LJx;n4n'eeeC,O883y<&:Hdߒ)C6j0 R3ތ`1ܑf~rX8J_q$b|/M3j?5 6 1%exbkP 0^^`(NfGG󹹾Qc82s9?3l oMB gz -:N=ϋ X܌QGiac6BQ>R~RL5+w,/̂͒pP#/-:@ssCƸq>Rˏ9[,ȌǶr3#uGv &8!叽EDK80d }a~I{ A*Q͘GQyIz 꿎kOs"͗xdglָ#4ǔK!&<ؐu&lBOwOSB'1&p^.Y̐?Y,x"2=W(9n7]2 !k; w!wsf≻Gqkxb~?83e<{(?Ԉ?[b˱#X+v5c 6τ'06Z[F%qw`;2g[LbZ[Z ߥ[dFrNTu,=?N \^k8 :\ +C h=` sx_A4H3a@d=K@1(kP `/8 ΀ 7}87K0ރaAH #j6b!ֈ#"!H$$!!H)RT";w8rt"wy|F1*!:uD=`49hZB+jt?ZA7n%:Lc`:9ycX" X VUc&c 'tl<_+x=~7A0#8 TlB1pp>{" L W눧^DR#\I$)TLDO:E">edk9'']gagp\2dd S)FWJ4%RA9H9Oy@y++++$;U'XBEOT%)՛:*ޥh4Z"-VC;K{D(G -{%/#o )?S@\5CoB* VY+)^R|DR2TU()T:Kzto:~ާLT6RTNW.U>ܮx;{/>*V>K:6vf ;&p0!hAй`jpTpeaHS(.AA?! aTԈUSFZEΏlG͊>+zuQLK|ؚq>qeq_IPO%4&cw'MaZto01gƥ33g%?5H!).i_V859y~s]eg))e)S]Sץ y?dgɌˬ"g%e+3粵dw ł 9`\$wFnc2<괉Ez?Ύ}dsW}VW<|{^|K,\c!0ya"EE/޻$cB²wK6i-.bbae.˶-Ǘ󖷯YiŷNR/++/jků#RV_u q ͭk) ]Wd 6\*-߶Q"q5TUެ۬y[8[zl=Ms[yQ_mX]3]Zsf_t{ơfƾյh|44?QWzz{n9xQя#s;oiri:{uNX}rȩSCΤmrl禞k?| g[=[O]t|ˎ_ok;vvk;::tr:s7 y+֝owy~7{/~@xPPa#GYm}ǧqޗOr|+zJ{ZLYs~/{)x9n-?˿jEWT pHYs%%IR$iTXtXML:com.adobe.xmp 1826 108 d0+@IDATx} \UUAA*o HB:`:ecNTR4Jks~I̿V6#:e5CAoEE+s_p﹗ p9{c~hF`F`F`F`F`F`F`@QbB#0#0#0#0#0#0#("#0#0#0#0#0#0#xVDzR&0#0#0#0#0#0#0:0#0#0#0#0#0#0^G^ 2#0#0#0#0#0#0+"0#0#0#0#0#0#0:˖` ,hĩ#/(l3#0#0#0#0#0#0Awazs2P8~zP|7‹p-TRr*=Vhb{Vkv0#;q0zR*΢ě|:)I@Ѿ-0CKv1GȀ )0v:I@Csd/}wEzwᬩ8J&E,"Riƞ5sC5#0O~>||&k{D"og?vn/ /SGJJHE߫<=~B^Psk{Q%Uq~r6GzM.oCs蘍CY#357`\gAGKtZ7/,=ΝZlQO`T.03A>xOwP9YCG?\6uY U2F5Jcz";;`5Z_Uޏ}Amm.uvp?!F»[526˷ EUgP'#J}HUHIŖl #U^@ibY'gw:o͝.9ҏ o4Xt*#;<##Yrp~ϒ.xç}GjCߦ^_kJE:%$˳h#MݕO]MttW)bSMb_&`=^LF uHܗbuh#pVdgF`A@rz˰@D+$&S)(8Fj]Y嘔 e\^: uE y {zNj|($ь%ê]3-!yp]t .I-#>aA%# P,m v멃 Yuݶr'AՉ@2};>2P~Ĩ\`4@.Il<|A.8:*R> $P4PAy>_S4{ogh7j ϾTMɺ7P:3ҶHLu \9=DijY\1#XDQxfzDک$uز"”Ϯh7$(qlӀHa#(ŃLCG.lKBqܾX++Fs@RB }E{NP()VoRe'|I'ħ8(Nc9g3<#prpIutʧ;ܜ#/">Hhqpj  1Hq l#Yorh8\܎]@()D>BN}gYrUb#+]rF)+ 뻥LXŧN>` }9傀I]@G%^QBZ2_{&c /OK ;Cv9D@49ĎumzgV3Ce\9m3>q1NqEdZ\]Mty9H0'{ dE PJpdXsSL\f7V0 &[-UM0- (db2{W, Oݦ4t : ֌lSC!m_!- P8Gqi_'MO *ޔƙ=~mg(3D>;Kg,ErXRt$<K3k$KTN w-.a2 t!#Oir̸[9ɄctC?YMGRLi5չ'm˃WTGS%zz%,-ǥ`xҏ7b߆Mb9ٸD#?uS:n;\`>' }) @, s$]| iYK0u0D(>ٺdRC >CaI_͹'|l_ؾ E-4A~e.yÜ?)MNtNnrOlqħM!R]>Y/.[Fb0RPAvPUlεTn[1A]Enf!ԎO¦B+NM(1?슚K};3NCx! MՇu M!_}J I5Jߌ}/W;_fG)K6e;7Kz Ou-N^#+zS,I]f91`d=H}5=g+X\R$(C'ߞt9B6~~v?2;ӑ`ٟ794`onPZRc(1AR< ON&҈~" E] ŜCeԇ`uZ~(6k4&Gɘ/軈 OW [3QJ|Q| R&mLZOjwT7l>ǣ1m׎"_0A ObR]t 폎T>r*V~{O ~&XoRv<̊!h}xiҖԶǐI<s!l8q58&x/at=oo/٤ w3I&$F*~zinS_tͿ[d3I2ܶQjzE`h`:)Q$&%2<)2 iͬ6P#nO*RH`_7OoRfrtr۽?+V 8.z~t "+\BB"&M΅6;0/] ~ssmRpG<sEMr+~1o @iF9Rc,&w-1ߎ -,ēƦNǝif @y{HҊ3!6QPMwT pz\߸ȝ(Qt&qt23Ӿykc~␳Yx$yM(wƧwMrcWعGE ]qHo!H4E c9ImAx4s$\[nMK/v cTdĆ`po š,ǽ0o\Iƅ_5L8ҿY+R访{{ٵ]PpI+*XbH& ӧw/ݕJ!Zޯ4+Zj≯'R[*Tmg(̿C䂦@\0;&M *IWq")DS& 癑NB z~XS>O>a8=E==eٌQ$`[?vu:}csOJkx1hL 1>;PfHv , aB1dyn %O*:.߽E뜌?MλZLC:1:<~_(êb'KNZ'k⣠C2Q,ެ5bVmAr*ciםܥUw{8/ J)IA&aWB|U֟&tv h멸:%d 1QWĎV_j#GQ蔐TliNiPL|M PÇ6x'-sꦛhR ѳ^ DS5-7>}E YW]@$zٺ.Ou=qT(Ş={Q~Fmnɢl#/`ժb$wR8ؚb:%dC WUK,Qx yxIN iFuʧyWgO`j)z$!,L%dÙ&Ԩ$L%Ӭ'Lw jJȚ#[R*%\`D0=4}VJȪ# (?$;ZI )HzL٨f kQ'xjMJ ̴;ADs QK{ VOU+歵t| =N gi~54mVr_EGI UMXM+ͣx4 ?fYB4ySCT㣁&Z_$k(Mڦ%2 K_i9˃p2-=Jx=B /\KiWZ(@ؼMe)̨˓;5Za9Esp}R~7 똨+kМ3b 3?,곔G\ޓdq{Ac2/V5˱,_ )}  &04圖$9㻏5(@FeWfcRVcɼdd7OM uE">%a=%TWE^!*ڳ_xthK:+_AƢ d!'0 >{+U|lPWT;vԔL-P[{ )L9\פ>ظ%B Okm!;4Ṭ^;O]UXzJK틕~;}Q?OAH~Ә0"F"~=w 7% G([aPI6w?<+RuKEDkwJӯk }OwPF>3 N]ƝO>B/z6SgG䤻c[G,4~=]%sé7=:Y^{ʽ`c [CMOY@vdYG+o$ʻu{/MVԁع:督|Nn|̵;} i}x֯>DGނ!Hƛ$~}'p\EWӳV Ejl.'tʛ( VU )u <{KF(_wHCWvO {|NyQj7敞/%?49Ms|zRB(P=þf4D9aUJ?'J^5ecуnAٳKgl43{_7];bExX$]/>( .ZUhG'JI6o䚱VU)!]d 6gJQc.ʸMSÕg7*enWӔR|,WUÌg˰-5yuX<>D0I/OD"z&%ax)Q@}Wx`d[ޗ=)!}Dsv/ (rtq8޸]a(mh"wB|h7CuzW^*:vYΓRz Q;KYu|KTQ=(!h{Eg`PܞRڠ^Čju#+.`#]ywr/"@!4➖R0T>w]i`o5>_܋|<8YNq:V/e_ Xvw5)mxWj?%8Y .?hvŭܤ*7&p).?F̂wM )W7Btܰ5u(eVJYMҥsQ,: P =ϟu;?iČ3oAݭ3|)g9J+G vֶ-qQn4\͔ H !ʬo#?^ V|S P'՝.4E6L٭ѴA1?‚8/蔁nQ GUaP<0#t13߷ ݈U<8MJ*g3b ) )վ際i6o<ٟ0T:᮹40mU@>hpőnB+Li7맛h螅.weޑӑB&Ϯ> #xj74F:Ax @!̞wPhxR5P5a^ .)@)i?)!Ug-A S溒#4ڲjSû ڄK|rK EgKr#c`u7]VX\"Rr4LS"ĸ9rMJ=_{!i»9HK:Z{7uʧʰ.ޒbWÈDzN ޒHݮkU^ьӴ_Jr3WJnH`Whtcග[v/pTW6?:k1Q>O^VJȪ "I$îrUN DVꕐ*}gP@D#)N:i7ia!˻~:'d$RѮN'0nPND"sNy? :ŕŚU9B,, scGaQ id}QhA׎d/ג~QzucĮZT:QaXX_(ryɚpYoWkLtdLVvueCZ]J{קȃwqP|̝\8{ݗkV+ng%{qdQ|;8vߪTLrO[]:9c-&Ʊ:ݲ^TB5uSqYq=zZtiifqpyv'}_Y4Pm\;9A\_!7iۑTw8aKﵸAV+Z עVIqh8bA|r10Z:ЀX$O;Q} eGalT$H\ W7"Ktp _/)"tu'p>fO)&Wakӄ+U>m|S4hk"F׆&eAUq^:|@$[0tŠJFi􌖎l6}ڎ$wg|(X3Pqݯ]Mnjnݎj'KιwE??:|} ?>x[yDD ~¢!ξ.J?q ;rǦ*Ǻj6z3>2Oa힍9#Yٽ|H.Nң",xRoS?"`ZO<)ԡ@/GGYP+%hMN0f!ݗM&Is{#b,J#q`Chg'[άYXRUuw4j>:u-К&6CJih~ .;&Z#eu\su>iX;YH4TlP%x ĝe^4g6ߘڳG}Qo/3px_6Y+bW#*BYNDdtKM7࡙$co& A gQ̓eT(Wd;v[fq{3M;OATBis .r2*Tn]2}e5D )QsBzm[QMULwARe2)]tɶyZ\6t/ JGJƥd c188:O< u{ շOB_A}#Iz%~:/H>;)r>T 1ԌU|J܎ n9Yl&|].bmX;y׭ ~0z;y4fWޝ/n;DC}+G^i3vPts ǿw.A.[Z(?7,Gk@ J\=#B'wIn Hq-6|i}Lw- D~1զ>۰#yꏭꙭC2KDƔ 혯8hkyo9y=vt PHVn\u-x_O["Boqq7:wSB6:*D<Df0V^#5tsäӉ Du _%^ݜ8e%/>qCo{I;Cy h1_;RZͳS>a=9.,ZmLKȃm/gion/n?R=}yqg\l=oS?"ВmuS2Τ]Sعvj#SD&U]v~G3t>|A 4iڭFu?1AG x>sMI)yk**fja8(muq{4ȺMgIcnq.{kI]G~M#gue:tYJNd:Gԉf]LrD[%w7<4"tA[׮\4M5Z%1l8衡{B+n<#SFIo?GQ?qLi7(ێrpf(Hڦ&PŪ'JKlӓ0[QFu")=nI?o{c,}IAt}JflArYۨbظIDZrK5>|R%W(Vtv{E:]Q]]4,snU~ʽo_+OgR'02OEoR?I7XORf)6 K~- !{LdWOb 4*վ#?$7Wcq[XCSh 6Ԯ5^(}'Ҧz`󑈖:f| ZN+b60Kxu0ٌgIGIy)!EՋ<J?^W3h97cҮL4FJX=R$6/ZX2)A0rg(BOU4y|Y^]*_.;C_m<H#payPW>~?AHYƋhOOѐFۃpF1p@A@q)E#Mhuoogת:9تMhfUb%?/XOPUnw8IGK<^l8Ց ?}Τɧ:GdD'q35E>vG [DZRn֓N-({@uaW.w;.Zn8"}F ,@X|= B;1Q;*n\tYBm6EI:j7.HeGrAt_JHrG>TK6{qP40Po3KѳrTyB_@iM *L E% OO);K~-sw3H*gݤHd1n0. w/{Q/8nE6h˸}/l?CW°Ivr_,ڋ/WaKCꅭOFZ{װtP*v_YDJ+woQU\E|a Y(!RI7P?!O*wsWWgiehȩ|귽-c? .b'G!'ٗMڟ}4miO y[Nh#ՠ]9KMi yZ"կWDRKL^yK=|_6 lMl31SŁCmS%TlQyjGy<1Jo) Ӥh n멅O@K|/v\r,L s*P+]0i K wx;De\Uj̽ ={V`Sv; g3~ ABc?bg ˃A[uy؝K9hymiiu.8#\\ nt\l= <%, %n)"@S8 -k4J ۪f%6vBM'iH$R!@M-ţ3lTf>F%8dnk IRILorN?&&IWA 0zhʣ6AuFQ?J3iUzL yg ƛ4ȳ()_.);):)&Mv6Sx;uҤ^%,n#X})vPY]E=E7.jqsÎTTSfJ|] OR3Jˈ2XVHxע/pXW J^Q)XqRc1'CQꅨXXL!%#~2Us GD9]:h!=݀V`٫(DSm}ӖTwͧWcÐmQ:#hy a*3hPy#Yt? ˱%e>~X?Wpx9ĶpO]R=haˡփ ^}_(91mc4L ))swثc1/rOoEO苵wnYv*8 ("=0M_q{/x┮vSo`0颮<kuGj3>@DTDDždžaEY\gPq DcCwܓa.w99S={e|QY˽`l/U;U%f0Rf7hhC; ɇhV(}M.I_8Gak#<3KJ*|%gRd>^,&y`E/贶GܬAX6TH\dfbœ?PǥPQ_}P 8Y##9Kǧ.x'G{pm:)‘|s$sJM)?!Q:Z)wwY{`e?c|ZӘ\`@<էlPEA)]] '^%_u*Ve&H)LHݷp:ݼ;5C\6%GG5=vH): ˮꀨ :,\]7h9W0f-Ylk{ _9g_ǚ{$ځg^JſĪɓ#za=mҗf2@IDATH Q6]KXF=q7?=H6\׌ ] ([0z d]b5ψJR4U5tG;-%[ZI嗹Ԛp]9,Ed*Utt^X.&eGC~P[[[^ MVC ׍JVRFtǣhA7o VX-M`k=gM!JJc)%E(U Go[U<{ h_I)i@y+Lp̝WVC-u(Σit-ފn#tm[E'1c1tJHsM# }ZU~QgyUn[릋_q#*ղq of",Ȍ >:sڲ(Nvo/ZEҭ12 zE.>:yT2.U5șk{㘜| kr.6W5X>;?AMkU$R ׵$UqJMB=r biFUy-BoX*dAy&",9@SBxsϛgQ5j]n[uߢjFkњxށu %>]6OOј+'A,nvbWt~IY\TCN C :PN'GzOc3 ˃n#v /FڟA> 2$gS>"F". g\-v0$RRd$zXj?u(f=4 SF+@*W>vgo5#v^Oҟ+p5swK9R>dW^+S8QY-&GlDi4ILt|xRRDb?$ap8%ED8:͠\$\{!wQZpӝ> 6$L] j[\r/LMiq6lNA:4.tloʾs6 tp 3H>rmR]Uҿ5uHc'Pw_%>itP\ބ}A;ry (8rB;+ݩ.#׎],yOh[ڮ\4~ҌSGϊEmmQOaGK`1}w1;ȵvN`IVh&dsǯĪőof|; fu6"O ]#X| ˃dw?JT@rLh§fЧ]NOb5[Fۃpj?Y.p3 c: )SI )27+WoE=uD9g֝~4 qgG;& #`3k<`ah?`yE13@CkRFn_ZDlFWVЏ #0%A5&A/ԉwC;@3x 5xK =Np[|_;TUn]I`OϠOwDD`v~i;AMHK9E<똅ixŲME.'3BJZ3Sr*=Vr26C"]gqX;>?df^Rƣw:sXi6:(T:ll{a"E<5ccݎ#\Pr+/U|yͮ?AuBGmŠ`=pЧȝKt^ ^ۉX[\ɨƚ^g򒿀/_rgY[Wھx=|hvpM@zwt1=5S~3]@z]ZWy4_'_Ȗ~}`r;u$nq7>Џ3EI7-X!N';9sHD 7Nun("tul 5וH }h(q~FGKĎl:亠I_9S-9574:d,/\* ,KCzRM LR&]-9K*nP-e%w'ki}b{'޶$۰xe_܊H}Hh HIXjt\E$IKN\/p^r[V.xMKc7ʧxhidŖ='Uj3gy0}8C!pY%nCENȃ\n6d . `0g=3xfFy'՝J{i\w%Gt%4⛟uzQ;m1pbo/U-ߒBzeUW~r6d,s!΋r>Zcv  ,#A)nx9v O/_ I'滕cS N}gBNrHh8ز!PY0-xɢ,-ڈ\W |x1Gw/FΤ˭_|?*N!7aIXrT|GzO+"qQ"r0W,"aƫ1zrDD픓?\4FFЅwa Q_?@ӡ8mn GGn0QWFʰ߿o+qJdjZvI4؃8<ճDW,=" K 8>G^Fο  Et9l0 I;1]K˴Mnh}-8GV!ΰTNJ:rnQY6ё? +3R0gb}6Ir-' 2$hl靴%qHT~U5iY7u _fބ1PS}t%;io(11F_x6i:qj>"C$,NVNj?˵ :֯O)Oͽ "aP~?ritd%N.ޝ\d0ՙ}Tg4^~47ul] G20qh*ڣ']J~JcpEoqܪh5(=uI8de;(p&8 ߂;O={+Iy!gH3>>oB9k?K5;O8'P7dW~)7݁yJم\۩ܑ5TsE9gI*x^1doC`yN+="tڷzf;[_ÏQ0})X;Y'F*끙*)뀮]/!ߪ25+-g='aC cS] qtJv"[ax< }oF/S`X ֖8|,ы{垂G $h3M xzk@ۭ5_{Ez2vxL|L7 7M$βDZ8=`J<ܳΞۤM9FKqM V%ڑT/t+j/w#'g,Xs<RD0 M!"Ʃ5@]=(:[.-C3?penzUr(ȕ6Yr93׌^ ܬ]0pDpbg4T#v)vw⛰7J \߀:kD͍Q[zeEo"0/C[0#g3@?Qe;3ʿHҖM`$MK4%0ًjշ\s_~BMAfZkJȚåػKT)A#b1oKJg+{?蔐fTUp!tbuOZ(bFg!dE YW}j,.R- "տZu\ Us44 1Z~<=(?#xn^JQyKҴd/%$j3ٺ=H{oF>07P?&^ceNLJν2v4F'e<0 cbh_b zjBh8'hS브XSBVWbMնmqCJ&8:vZrI޲c>j9@ꔐ 58^UyHWI[Zw6^,%2!բlB$?%~e}J YuX*% ˒&k#]Uo{J YGxյ?{WUGPEEPQPPPDT4JJbQ@38#J3? >r_3mpBY&8cy!A%IQBrgp@]aZz]ztkC\nZIXi$rӳ?Xl5%؅];!djqyhS~lfvrъHcP\捕%(RWon8+QmRGkraqȅo5Q~j|Ϗ0Ơ“a1+UY^вIZ"1j>Y2MyepN >.UR ypa8WC&3k]/i?9>fy[%SbKk?mv>c3KۏeG{8KI}Zk6o:-kzO:jM0*9q. "[<=?O@Wg98+W?M>şdߜ&0xZ_GM^x5A# y/A acN_xH!ؿL~o/Z.a='J_>L7'N녒܃0 7n"̜YQJ]1}a"b␐iSEvXPLQJ1n4`kQmWE|^[8,/MFm= IbfQ9\k5QqIXxb&bAXJ>mŰJ_MT251F()iِ.|Jr6bʴY³+Q" iK{_ bk\yYӊg>oB(AX'-㑘x%&#B)?Ψ\i<_H*q !5$,!zaa!kec-J辸ѯ^|&vW!tr4IL 4m}ⓐLcS¬(l=$Ԉγ)E"a|vG(Qz0{aֽ#aJо_掖,9(̊)[ߥڊ ͏Z3~[#&OAJŁ JiqBch-+E곈L|O!4rP04権sy-ڸTF|-1|[{a# +qz$ؖ=Ug&iuk?g[7kzrx`죊f Yx}%1-mh=_/xe8).Nym1OGBbG¼P(T[/c$R'GѺn{"QzzJ;2./T{!Ysw)c<6yLͤUw7SY߸q*4U ͟Pnt+ɇBh^kGEkHwKOjwrg"_4Op(9vݣis-K{Vo"+MP_1AkZ_̻'Ϫ S9:ۂJn1, ijp5T̵SG&fϲ|=T&`*=)!,jN Rs&0acmath3&>q",Oz_8B_q"2?b*R$Exwʴi}fQo.gs9, (|,K*=l<hEE!3c'g?˄[$|8KP뙻o~tD*ʱC*f2U(kdKBi ܱ2IӁZϘex*YS6I H/,i2De؊w\S['%KL-…K_dM<̈YN39$r$@=)) >/-OH A 2kM'lO#\.Oqx(9KMSEnz*p4L?~]C t3xkSyWy]r7#ti#΢l[2^ۯl٩ӰL#tai5@bqBbgo#d >HSmS,liL&StI Y㐦<@6;G)q{" <[% @P.Ƽx$V77(Dqq{) 4BByx\EpDm2T0km{זwauUA;شFfQQ @`ޘމ3[n/s^xT*D$GR(Rih]/iG{^fǥ[|jNksw>c3k [đSLYi7Mrao=U|5]me-r({ ґukol>7XC qUZөX~9ΊpܭSOU"ōg<ǿ-|Ovc 𙛁7V5Nj*X{/i“ ci&^-tsWӨ,=#ٟcfC K7^>d!3qtZ' *̟@N"1WX6+uax}wF3my`pGC8!߬zl6-qhIpjÒkwJw-e?w5JW.Q9uq6jEZ;.o^1; Z] ;c{v2hА7ƛ$S*~.i݆@ փ mwS0k& '_XotM Ҿc黮E!,fIZ?S#NϴK8nc̑ 1q|dݚT-4)9m-v9Bkq:J]usmU8t#_Va@} }뚬Ub qCvՃЯw;}r>Y'8F&yGVvfjݴDNek۰$*&kD͐ _BNp q/90^n&{e*6بӛ#S uvB_ [oDӒY؊[SnfX5'M +Ljvv?4ϥ5Mxryolj[CcN[&חo"de(IT =vjgd{-x☉:<6.n A>7GNjqKmA @'Bc1P/ĉ:ymi #qQ%/O䟿vk.8Y;ߪ w8rWqmNf]pڄ!Wea~C]]4 㵥]=ͯ퐋 !fI> bN+_df?`0z;tXN63fhpl bbK,.Mڣ [ig;%0pcb*dvv)")'FH'ׁxj3 hj"I\҈_ 4˅Q;a0Q®xmk.MZV~϶_}y2ϿÏ,7.meA{եGuiEɟ󭒚-: ZvHZ~3zw'D347/uZ*F\Zk?|'P]if5wTW2y0ڷHè|#m`udK?}̠mmv^ [5[-EfnYGDY>o:VYkS(9grֶxw)8(:z`vpMTJ|[=];~ 6uWjp86yD"FkW7 SMpQȦá0oY2ri߃ҏh6 h-X(s:Ņ`#&NKB͇[#h3s o$+w_}r!zShE #O)f^(&R"Ykөןx !Rw.>QH ^!2 eW9\1K8G?*/~x 'Wvf8B\,I7#D|Hõ 㵒[DNgUXLbf[xgǫ󟦜m&&[! eO. ɡ/,@ סXy1;{~ s{6~7 Lw1փw .o.Zp/ᅴo-Nrעik/Xads_[v%i[/֏lyLwc?yEK.l}zȶEw[_qL:lݣ&?[MkMV{5V Y@~s9 otJu.Q'F` IݧEgSVkuTq@~j{=\#%Ã=-x^|7bqw0U;8kQbBJ<#)) .ż$,K3o)(3"lԟfCh<әh$౑jy=%W2o'/?7Qu !7"J<K4u޼-w kcIDS[jEي7搱0ޕfg3!7Hi)_.Yq5 o2=iIAʊutXOfʐc' (doitV/箖hD1}9e(w>-άgR:NXg. I0~:y,/qGI[xboo؋A>U sH۶{u$aTHk@,v6%UΚZb|O[mW%iu8-,wR81S8$"1c;Gg2ڇWVZjlXn՚QćBlyߌHنѢ /M"4A.0,k%DC*~duzw~yy-xMvxV0yE[&.l}f YX5B:][i̛95?OO=,#[ZtSOƥu2AdKn#v 娒?G #0xji>!/Ek1ff7ֈ}?yq, l*&Γ?bA jT,Vhڞf e%W$Goe>&.BZn_2 >-J1u,Voۃa8FV1z!؏={-mxmZh62v=HONC%d56&REÅ]W\Z<B#:$FyoLכmpKBs GvFhIڹV_]I!~mIx=JɧĥPTfmMقg鈔r(JźlQ ؗ7}aOekmg<#Kш&ވvkX7t_}1>xa,GD|2~I R܏4%)W^{1Ek%P`mXD b10%RСhšĢ3U-ㄖbePhS[[{ xowcvm[kM=Xb'r!-HLYRH++sl#d3.cB֙`6Cc?$ fj#::[ :۴kRߣq>up"P)y̖za߼GbXOLZǖ#փKD4!M# ֖ܳïToǯ*}K1|+k+LrZ"[Ѻ^i}mo/pGʌ'w5&lW4{kgZ]28|}}iR04+ip[{5x{󴲵V"gEv8N8Y`)F4Hd:sslH|"_F01Ov{S; P*78/ߴsK5vL=,(Zk@IDAT.wW> Qr),mkfЦ{4~ՍpqtOnS:77wx`x`_Z,j!cճE;aT~Q$W;J¥{-AG2V)I5&#u6/t+I]q|(09W[Ui\.v@jB>=(<(aRj?xy[WHӅƉjd)g<= )IPlZYhAĊeTJ+mu6.^Ig/ו`:7gA@^$Z-S' TӦ5#gEW'$XO?8+RS^3CJOANNV9 5+2IX0LϯGRmZ{ZįhnI1[kodPlr- 美iPMKt翦iʹ&6_x;̷-QgȟkxBȔ_Ȩq WyLc@ľOv#ZŨ֭qƂWRgDEjU-F0F3ƪ,xӯU9i0S֙)ui 1{|sңk:V뼢=N[[pܝgZ'Zsy>4OkOƥ[@{*Rж5zP"~)_H+ԁEx7oJ_X>W"-|/@mTſqwW^NtDKCApi˯ϫV!TDWTUL%]&I8j׈<]$9FOsWalZ6O# !u3͛*r57%KՃ&nB!onUй_d#ΈF_n_LBBV#g#)@1 h?bEq4S$MFZ^!iLWOQ+Yn)*L.Jf"/fkMgDȎ0m d(5FP?|Z{W g~. +2|CrYZ2J_9:/VLI0Zkvfě9\o4j 5'#s c8!dz6y1H FrkQ1 eyeq6oW٤YZϖOkw]72a)ⱱ6T0.gUqaMm5oр'`'I5em@NdI~;i}.Ǩ,AJqZawŠo5ɯqߕj[k \53O!NBi|߼` D̏P$l8Ѽ^0~j~S.8%7)O[ϭlZ]![YnºGzBK8o mtT.K-zkyZ} T)ӹo !Kkd787 ʣ(k{0G~U1]lbPnOBS݄[(6J3t8դID { ."#3\G`T|XWqMҏxmRY-HU HkL"7TDYY\!8y oH^dP^d´ g;r-%|d61=(nZg(bG&ov3Ć 2֟iӐuViy! LS~z"DN@^BU|L[wTelΐ?2;A;s8͹C(͑s$tHhHOKk)]2ZYȄck1nt ?`CI۠\ ÝtrBH8321i8 VB`ܟ8 k 8; +5CEO>fG8 &c~?6++C#p?̷m"ΈA!`0 C!`0 C!`0 C!0BT͘c0 C!`0 C!`0 C!`0E "'`0 C!`0 C!`0 C!`LɚC!`0 C!`0 C!`0 C!`w 2 C!`0 C!`0 C!`0 D6`0 C!`0 C!`0 C!`&; C!`0 C!`0 C!`0 C! 0 C!`0 C!`0 C!`0vG ")#`0 C!`0 C!`0 C!`8;9.[ =#. գ@`tYC2lrؓ,n<*`Ol?莺W>g~C>DO)}H"Cn:,Z"{&UŠ9&i=H 땉{ \W3y%0 C!`0 @+ -oh2 w.x!j!<A?c,trƅ?bxl3UCItqb$4 N\2 e$ףD#5O_鈚^/h t8ܝYWڄRߥw})KvŧwiIw1䊠6~6ZsyF~2 g<k?zwuH ƌ G # 691tX#׷da gFƃ1 C!`0 c\#2tvM abE999$; ! 8sx0!g(zR3!݅%Z(Xv&ѻ%B-DŽ",ƾ )$r:j..d~X~xMNiTla8'cʭjBr`\яƂHu"^~ !|Ya?0X5 {'k C!`0 C!r7wo7,~\Y|)ZF~uCPqn@=F@:`3)P7PMٕ!`O"RXB"/} 7,֬}HU̳hm,߻ hDu܆&]_ݵ9~pu(>}hBT3A ".1!ql&t0L]KVZY}yT4+&C!`0 C!hcX.,;/ۣ|:( A^}1| : QRI99OBdWg|7,N"2CઇyGv<ڢL,-kPI:лxzvƥ+gӆMq]IIp 57sH{,)3meQ08}}kqo\}v դj5( Y C!`0 @"` ( IHBmېN~T{ Kv!K`pyCqc>EMzgnsO US6/c.CGue0 C!`0 C!6\igR ZzAA_z`1ԕSGsB,9{b夡(mM戹-}3z};ܮۿjJ1zg&ϖ4 ;߲R"VLfЫ`c^p݀vݜQs<$Ch&` 1z}vm=}dX0Q74ʅxgG 12LwD'&c wtt)Ebt@_tⲫc]Bc1?>mk&bTZL}P$EimF&}=e+]˰o~zxGo!.D<">nTPsTOQ rxTzqƗPD93+%F 4K5xIp[w;=v$L$m'#5x)GG!q~*ֽG̸ |({uAvXvW*cn0LH!'^4 {v[kqbɱsPuT|*rp75#. wOS~4ͻKƔb% Lc_*Ɯ'L*TFԹPzν*;\vZsC˜xnSPQ!SLY) v Ftq;$mǩ&P{:RDIhߑƈ5FS }ƩCZsDV | UZYWK6͑))$MНj⌲ H A_D^{oeΖŵ5Yy8miV?ZO.hOkn<gzgYF<_3 Z: ɵ:"_fKqgїZmj$QyNzH}>~dn nMhiWcF6>pYgpd͙&ȷGn^hxEWgIÑӚ V#C!`0 C!`Mvջ-{8!#>bD(Vhj>?OԸ'l2fj3X䏘腇3|8BǙJpO}y@AMx!l iẛZ`=dtNU}?lyHOx)Hr3ާ?ÒcSSt&X yAޜy`ۧ |I? {u,zpB7AB.W=m+]{xUNsB? p߁cm>*S7סi?=L0'  B#Y01 p>~h3A#((SOW]/_C(xpWBFcf,3k!D/FBgy a("H07W&!֏&$FTPWo<d!%?Fc!<ԀH.:/5J5`Gc0 `b$0WCB A/o@?FR_''P}0"o|WK;3h)0{w?c; %\g {>Ԛ īcArsDê:D5ǎ/8 0>}e,Ղ̌|4\G9ysPP&innܞM\ZOl~6I:r@a}eH@rȦ7o@nsJB#1|vI`7w)FNyZ&=q+1ltqM/C>Fi1 㣧Rߤ0˭Ӄj t2&c xԇdڹƓd!*\ʾHj;ը E$&8bVBHݹ+t5B>=SRpAY[YҊjbW"uwrYBH]%iV0zGۖ(jWT\B?}ɋAHM]9i5I{&}M.FlXHf%"e򦿓;0z4/$d<Y ~{ )D!hlkxNB$L.?Q_w@XO"IgF۞%qh7UFhs:BȆj|Sr1b%=Ί"ByU-)E4A8c7^P]dLG( :X ?Q$ۧ+P$We!deU|u :+1Ob@H+ !PL8:wꅇ{sB`nPrjowPPn^5k$R068Xͣv\l( LR! W89G pۍvF?7P=ڋ9`T,7S!ܺGH՗?ҷpqu6y䂼ȱD1qa!}.%9XG/ª ۚdldFyKG%>~MfxWrh+no"#c\>?W?.-$Mm5(.k,^Oc-J.AЈly=<686}sky rI5#׮I` aorY. jE>틋%i~+Ǡou)^dX;gv>v<q"У>_#}svY~f,:|cqs?r^*zRHYѤ3!YfCFf"dM8$e!$46gi*ӽi4"YYYS !u(za 3)/;!3!A+{SBr-(X;t Tguztn|Bra7ws*KBHnQįF[Pϱ^z))ԇU"3%FBrOrIV}9#[t%-^?OS&\Dix q 1^GaG{m9J9Br*.٨0 +#W_VF2Q=ƤOH:yb.kOO/i¤*7  ) !bwy:S\oS5S ɰttW[!$f:/inv* E2iRɑ9;OH׳`G%!$a6~?o[n*I~[KRG KYeZ|Eڏfm+稺 v.qy,\J.3~ando(ïc)#ˡ8v ZϦuOAvvف-CBHt;.:R)sx}r?LBQ}|sW8{lL`'pBtU#6Y<&;AxHzO,WILKaњ#C!`0 C!`0Zcוbxei B^^b("F8_XXʿz\(nR'v6hsp)sgD!%{-Vr$^5IAw &!dYVv=v4L! }NgSĴVTlSdKT 䯾ET2wOc#|cP3Ϩ:Hܦk5f9Ţ(+0W}LD& yQDac~6(+z;˕|t0Pf(_IN1!X&wo\+2UR 5xhmA'g65eTV% ;³Oӗv.? ơJwIz۷࿃W034LŽ]ݑ 4.9A;S$6Z'of}!R<iWpAZ?О.0hS\5="қ3^ksl8So JGd";}+  R'a0_Q;K73+7,,i7Z9Y"ԟL̶~$1q  .z8=E#9i"|!Rً-S"2#i)8Xӻ+=2-h`oMzԋ_nI`u$3Ty(lv08fDZ:|&灾ŕJ dMFy|9Zәd2 C!`0 C!ɌˤA> Iδ 7}RR=I9!| }ԢO|UﭻvBw{  (q@Mt,Mt,G> ]8lwCg ˼ƢϖLA̅=D2Vw`L mђ9L`sq śƱ*^2VzlAϮIyeH6]1rCn..@;\z,7Hr0ǷwABd-.JI.YԱg-@;.Jǿ[4!mU#λ_kMKfr+6wR;!fT<ԙcC_y{Μsy'-ɺ8]˭8K%>lI`Z̛&(|fT4قɲjᒐccR.=bc:I F~Oӿmt2j.3gc"5d w'],-O,7 򿔴HpڷÐĵ)/X9!Dts,ngFD, atiwT>Z{? `Ю4Oiۛo.=[7utp`%Ww74ϛ. ==CcPWtr m2OG?$!?#3A-i/#7qڮ|5IwC@xiexnhLW4;)C!`0 C!`0Zi+FtkTt:~$tDSQqdF\Ж{;uf s.? G]-7HgiC?֙۬5Ej$)wg!]BMEAMr7LVK> Ob`/J8k E pj&RSUf*65cQ{4Vt:wéK&v5qxe:f8g4v2꒦4Lf`A, 3?)t$ulff|OԑZy.h_WOcM h!bKUOt2`v-F z4u6NDTE 05Hd@&vY+ܩ˂)xgD ڷ #} Նkgtoo4EXnӛGgHW÷nբ$= gTdV1x7/!Tgz!`CGgdi"ݺariم@*=3n>tb.;Q:'LY>2'}'B`Uw/0L'pc2Fږaҏ.-%A<Ν1Z = Xe^=Eᖪq)XBUAY¹/K s&-ĺ`XHn=@/]>\Cm\r !dV' /%k֣j:&%g TO1J~tfxn Phi)s5I1$056VjYzF)ax3i~8`D^4yI{L6z\0Tټ[p3PB~!¾8Mg# !MRcnB[W1^ 5Nh:wT\Ň9asm4 Θ ^}܅tu8\8p+vdi{͐%~<}w玎,Isyt?`2Ffl˂ߒ:}zz7ʄ.5moh7RnZYP!`0 C!`0-@Df33"lԟSgCh$^ďbCO|9e2oL4A0:۴DB3Aʫ'05tqS(liHAg w.'lוE$'9qc\G!X9rkN![9Z'?[kh[ 5QZ%ƙb]Rl(8r8l,'~lR5?@:Jw{/eGN6ΚUrVkaSycsT`LK'Lٽa;>@|lSy7f>n܇ͧͅ{`BĶk"|*xZ2;'I16*ITґA&RDI@U17;xzv½ DĀ⻲egk=]oC76Z /`iXP{E(z SehOz2݅$&X[eWĦC:ZrbOMٹ3!_1*h0aFܣ>%`u OT #昍spls|e.B ӯJmT .M| /T("?Y<7=fF #[0 ^hI ]Qq@4FrFgCZf~Eq/fq8D4x-s-;b/+PkM4ktJaƙ؆J|uR+E|t]Gv"Tl_~*E^ǯGL[F^MRv="ԟבaB9"@-dtm<-] ;}uEJ†eZюb33K_mm9Ϻ \Ui QmYE<;\ٖ-i(W*¦9["y0hr Xjb&|:WVX҇fc+-@ 0adH]>8xB:XS}!.oXɯ.w3̞jjHϲ;>oό(|M/}1<+m:TEчv2 i.V~66WCЗ;]" rlm_}kUږ2ÿŪUH@TRBN(5$W z3ʢj.bGb.%CEДg OMjv).zdDD "4hw1=ݤvWUH-Bj5 {HF{OfZq0>=+o߰ oS*xvɕ`OCJLUNg퀋աT- <7ҽe%V|5<82κqqђ{z,PScu\7R7%Ƀ~lݯXyL zԫ<, =B>JZJْv`3`i$zƝb|1NڨZ2ˊKcP)l9鸬Gi#;jQ*d~c{Z{B~x׬(:OI֣cAR)Q.$@$@$@$@$@$@$0KҴy;"3 `PDz[a 1g^FYHEt$"0ˢX[kg/0[[V$;[SA[*"UCfwYӇbJ qtLsIsLxJ{& |N|sS.{HzmK꧛RDg{k!ph+!u8s@$@$@$@$@$@$@$@=:뇙 p*Np PŸd 1P9"@-kܥzm4IEk%ϳ~f\YSΕ2]݅Rr/ QR2R©.;ɍc[e@&7D(!"8bʠ4^}*@+84!>pvq ĩPIbR!0H@|]0{G_ 43^ # m\%S otjQ)ǷYދԁ_}6+Pg1"5:Kg-4Y=VreQWF-xós'p_Wܲb= μ4d~^\7'Kf)%l2$.u7_ x+y:Q Om+c7Eyt>]KסJ'ȿ <3b@cIf`0sPZpp4APHJ$@$@$@$@$@$@$@mA{DuI$@$@$@$@$@$@$@$@$@$@$@$@#            @Ed[Pg$@$@$@$@$@$@$@$@$@$@$@$@$ P0G$@$@$@$@$@$@$@$@$@$@$@$@mAȶ4IHHHHHHHHHHHHpcHC8qC;vCHHHHHHHHHHHK%$@$@$@$@$@$@$@$@$@$@$@$@$@6kIENDB`difference-2.0.0/assets/git-style.png01006440000765000002400000102413130471654270015765 0ustar0000000000000000PNG  IHDRKO iCCPICC ProfileHWXS[R -)7Az;FHB ؑEׂVtUDŵذ`AuADEY 6T$~{9Νoy[@*F{1?P@b <#"B?[usq@" N䲳 >  t@<XY @$qkq[Jl#!Leȉ3٩0bK>LJx;n4n'eeeC,O883y<&:Hdߒ)C6j0 R3ތ`1ܑf~rX8J_q$b|/M3j?5 6 1%exbkP 0^^`(NfGG󹹾Qc82s9?3l oMB gz -:N=ϋ X܌QGiac6BQ>R~RL5+w,/̂͒pP#/-:@ssCƸq>Rˏ9[,ȌǶr3#uGv &8!叽EDK80d }a~I{ A*Q͘GQyIz 꿎kOs"͗xdglָ#4ǔK!&<ؐu&lBOwOSB'1&p^.Y̐?Y,x"2=W(9n7]2 !k; w!wsf≻Gqkxb~?83e<{(?Ԉ?[b˱#X+v5c 6τ'06Z[F%qw`;2g[LbZ[Z ߥ[dFrNTu,=?N \^k8 :\ +C h=` sx_A4H3a@d=K@1(kP `/8 ΀ 7}87K0ރaAH #j6b!ֈ#"!H$$!!H)RT";w8rt"wy|F1*!:uD=`49hZB+jt?ZA7n%:Lc`:9ycX" X VUc&c 'tl<_+x=~7A0#8 TlB1pp>{" L W눧^DR#\I$)TLDO:E">edk9'']gagp\2dd S)FWJ4%RA9H9Oy@y++++$;U'XBEOT%)՛:*ޥh4Z"-VC;K{D(G -{%/#o )?S@\5CoB* VY+)^R|DR2TU()T:Kzto:~ާLT6RTNW.U>ܮx;{/>*V>K:6vf ;&p0!hAй`jpTpeaHS(.AA?! aTԈUSFZEΏlG͊>+zuQLK|ؚq>qeq_IPO%4&cw'MaZto01gƥ33g%?5H!).i_V859y~s]eg))e)S]Sץ y?dgɌˬ"g%e+3粵dw ł 9`\$wFnc2<괉Ez?Ύ}dsW}VW<|{^|K,\c!0ya"EE/޻$cB²wK6i-.bbae.˶-Ǘ󖷯YiŷNR/++/jků#RV_u q ͭk) ]Wd 6\*-߶Q"q5TUެ۬y[8[zl=Ms[yQ_mX]3]Zsf_t{ơfƾյh|44?QWzz{n9xQя#s;oiri:{uNX}rȩSCΤmrl禞k?| g[=[O]t|ˎ_ok;vvk;::tr:s7 y+֝owy~7{/~@xPPa#GYm}ǧqޗOr|+zJ{ZLYs~/{)x9n-?˿jEWT pHYs%%IR$iTXtXML:com.adobe.xmp 1024 230 h@@IDATx|Tՙ d?"&nZZQ!Jiq⦻qT\v)[b]VmhM]^_Vv5[ ZiKVJ#D Đd93ܙ3's|s=w9<71MEXpEF=C=7]| VCͽ.=ZDHHHHHH Y&"#1c'!yS2 @ŔwM-2{'967$    R095{I$@$@$@$@$@$0 L}gIHHHHHH``jvHHHHHH`2`2}HHHHHH``jvHHHHHH`2`2}HHHHHH``jvHHHHHH`2`2}HHHHHH``jvHHHHHH`2H̝gI |E()*Ż~ZHxh(|Ž L&ԡH9iNsLΐ $/Qm$yգf$8{l]Tɡ5-??kqʪ QQfhi؊ʚqM/Op(>BI[ G $@BVl؃]a1ӫT ;}]rs'$4'Ooo_`N m/d7jbKBC tV [K*{[ƿKRI*C$@$@$0 $n @ie>K*qX& 3HbGgИbl/ǫF/z;%P3jj Ýȇc7^&2UHHH $D_L yS1ɷ~)TlJ/3@l 4("_!ǶyOkMɍA6f/F3h83c3^b>"   qA >rWjbCQK湀R ր8LJB%I Qi}Ō:ˀcu(HHHH ) $`CocDZ@mKLSTEX]u_LzN<+ź;PrldHַ“8짇wnltw#7SQlmuUy>+-GٹOAV ];=MWTKAZh)[];n a2U.A =Fzڻn Z_ÿn `& b5> Nɽ$`HnF]Qzfuhf3ȋ0q|#Oj-}F1 33 o0&,~OD)o=앃 X9\^Ïsn%廬޴]}{U@d' _ y @i>[,P5&7HJe1n*v2th߻{Le{ {8ҿc#uKV ?0d-Jԙ*/@2Jyf |7VI{ݑO9O߁&uvB7`V+:7zzϷQnƳ-PX,8xמ#[o_D]ϚovY+ǩpڐ7iTdt#DgF~wS(Y0`!Oa[N=U5`[+Ł5(TAZbQoxHHH1)ɡ{n2$ɏ5lua߃эNϞb{>zl='N[+iG8gOM%^㿻N| *$[n!|B }UyV߉6jAgֆ|M*-/[5hkM"(r4Abܰ߉u*pw!/<-Ļ/^Hr> 4pL5. sV?o YgZ9?D\U.pM [3CKX}hпs19l~XdXn 1,1g 83! Wc()[=ϭm_^V.P>Wj=7߾ w\E{ѪYJ,5wx{WAUFT޽ {ɢQxZeyNƲUkqXyWRC6k>\fXDD'돢MGI",[ k*|}8rJ3\msPrZ߷ -Gs1lܯLֹɳ7=K׻_ Ջfy a,ʶPrۑ&s$j|XtgЀ_ϯ0O-3շoaѣG]%Gy͋P%p[ [e} Y=XnZ m=M^_|*d^8['   H +w+x|z\wGw{:^/0G;|*67֡ox e?aV)= rzO䨱nFba{ɆU(T:j܋v9Ӧy> Dz\U6ްL_XزG=g}S![n?\ʇjPԋ(熿M[|q7[QjͻVmJ3:"ZC륣y6"8+TaٹQ'>ngFFV;N#K4ލG<Ιs}mE:gVe 5Ul6}>O+{?p5B8W+P隽tC3Bw48><_2T>`y| sxGfK1`C\0?;PP`jXw>CnSJߚ%#dz:Wy{ 75Thg?t%G3z*T{ GA-*Je#.mՋG͂TxJs21ge훝5>3cI?Xt"p}/2u`dO=L$@$@$@q%`/9 ]6l]V1=4}kz8uFsdO|jqs;`܂Bٗζ#FаaXb~oȶ$PʡXam({9s<[m G%- ճyJA{e}TJڱn=\>^63o`ORw?MjMZ1gu`5   #  3?ݻ yV#ͷe{-#W.#'ѭ-vն!|X[iZ`i49$;ИDiR^@BgTlۇ'iWv]-j\,/zDnVL퇍0^b<[Y͙։v}o?o;b0Ά²hܪgVoiXVNvZ˲# 0`]G    Z1l4dSޫu+ Vx}(wy2eD|nFEvTrfj}b<:,h-*EfQ-ӕ hcxpYVځ^/<&r]\}Gx->[Cx\h=hyPY.<f^]C>,M{dgn8 !/ @[HVhwwRgCv0ם87E}[ #EK`YZ<6Rl{-5zg%ARQ)eULYʮ͚=e%er;>zԩrM+GY >ϴ~Vb¿c_AsxXOq>g@Q H}ɲE 9L+g$@$@$@$`@T^=UPsoCCRm!-z#Wy_XVC[]qIk95~7Pu\m9Z .³;}Dr u[hӭ3t3֬0n9DO}- XZ]@KVTJ܅.a5l^(zV15P̵\y%W1^\eK垔{I~9_G jn8/>BlΓ{aXyqt|+ $D*;zaBh%y>Ph \_A|n=X|<P5Z}x)j*{IP?].F=yvG$@$@$@$`@Wss~ *gO`qa,o^oNh9W \In؎7oő[=KD}+;KoB{V;#y݊ƿKq*Aq&DQqݠ5IHHHqCV"D(Z\ (Cӯd Ɣ@$@$@$s s $ ~{G)ԏHHHH4 s53mpOM㮿^g8$ Ԯ7# #Nl} س?};.#[/5 Ib+f##ٱsz:tULمY,Fs|vZ LF s=978ۏtEtM)-j)[ClOeDFO26MRG:&{" $19z=KKliPTF?؟D3p@.=KNԞ$MI &0r$ce:.5BP%9Q"DC6wY6WWN,ܑ|uXV0Ėy-lXS)ej/KꩩH6mZcauR۵#½2bY}շ4nM"[J.GG|%ze.t (Pyy^&fiL\@?WpI7LAF0^C &|Ud #;q'rY>GhuF1ȸ~Ggd ܘn^0v^2}:I$rϟ.=Poe Lr_ P\{AùN0߆Qiwwحii(^|waT{QiTMߞݧ>]E E9i{g.g=|LO:)"eSVBZ3#Gfۑ+:X5R-|{Tw ʦaSNj@]w!751t:LCG} yK8&N>apC : / v mb:Vh.ɷ.vϪlTlv?eG4ܯǧ4n~ L*8lkjgfV.ȬT<Ԟ3CW˔l/N%6_ Lž|/3Ү=5WMEG5eʪ2z91UɁathۦذvVJBO]l=c;K3dcz;Sd; e,7 ƿ?10tÕRPC ?zSX3eS\MӰ!Ϳ#2Y>Ӊy:\_稾kK-ŝ b P#̌HǧOKž0 #2y%[a^ w$X[B8D.Ȓv1"S!l9*Ӵz՗PKJ|Zd6^ <<5 ;U^gX03331OJ+36<Ї姵 ?*O7FpU]4<KԻSRx^fe=e}xĥM,v-N\3ʔZIߢT}8Յ]6KiYZa% 9?n}2δ EY>==dqzvz8,[WϖCs%6l+2AnC:Ggkd\M8olגCC~| Z< w|Jn $?bm\vl)X6bR-,NZ' HizQ=e|]Z ߏvsJ7եTAyNŬ Ѫu:ƿS΀<õTÜ֏:dfWUdZ v9ۏgf@!;975f{k gx<CS N4,B:| K,EIHHH=2r)5![e(vrЫ P/Au=)h$w/ 7J9wLf]pБ. TLw%ܟ !ܤp=3x UaY'Y^ ZL +DFQ! 1+hW9ͷ "?nUKYp7!̮l%' xN;Y0/d2\2E(׭]COCzCc~@p9Xݓ\YYXIN^Gߐb1.fb$t^ YƵRlؐ"i0_{p}ܔ#{P&oI<)wKfԄHHHH`D~E7` >!3"?zGp̾$_L{Ͻ,i'H{ lAm;Qs+泡A [Ω;ߍ:R 7e3@IQ Ƹl{GI)'o =듷PH<xUr ƿ8x^m+oC6*L<<xS5^/>,aQ!oԽf?㿕S1=s>Ky$@$@$@$@1'1W+@j,{$>hqN4F%ngװI%Yn47Rכ Zq zp,4c/Jnm+]w/`aJ,wG6úp}X&+(i$v}h=CFaF2 Yyi w^=Vml1o5V~-/V @q6<>HpZtse@-w!8Mrx/FN-0$Nf[ ԕ%FJr3Q &<xj+΁vu 1NcB:vz6e=Ѫ)ƅ,I^u-D2m<8Fv>'eżtXwh f/勲gSɓ3smzv~x   )wBT/Yʩi(7D@ZWʉV Y~uo=+dWO]31,˳lǕy;\]nUw~%g1L,eΔ~>${eB ~NJ@wTr*؏n<І,}%=X9JPA)nDp4-'./2^tGNӲt~L˖4\5 zoCik[?x4'SzNrK,~%~>,(&\M8'J,׏E2˲q^wiv옑%3p !IF^:>6YtK[G9$@$@$@$0 x-ḢH3Q #K$-9C)6Q%¼Ӊ4áo9.XK3 bk.8ph&FyBWoL}*|Vz{nN@(t1(ӽ]a/ Y}ȟ;n,`$)"=~7R1hsLjK`Up;~}Mbw",N@.rqb$l\+2Q#i59!yG:3,8Omנ,be̴ttb\C`EXʖ/NO8FL/d_=r)HHHH 9 s c'Z̀XopJ0w:' k֥J_,o F*"s*a}b>no-XzǫG@D8׏1SsEX}t7n2;e5EÅ./ئ{Q,O99QyI=rYShW,n} ~NGp.b0\,WCGWK䍺 3KZqđw)^_qE{c%yƎci#ۉb3f|Z|,s([ykoƪ!THHHH&6ex~bO&wEn݆;x5GQ,=#}ԥܲ\UwSe[CkwXx+Ӿ er1!}D&D{cc~4ƩebȵugeEt=# GfgVt:dQ5h?񄼵aF~Nxa$@$@$@$@ICS0i"$@@lP螪vy>gNlIixLX9n_9yo!{N$@$@$@HP hd} M - _N4iȕWah0\* $:vP      :Õ @R n!       >\* $:vP      :Õ @RHM*m$jjKdh|x}bĺ #@Ļӣs=nM\i@~ f7NkE)SϞ (3Y qm4VϻY#    9vn&Ae?x+&c#I@ [ v= v!>p>#75i?aW &xfb<    ͓4'2􃥫ӂ]܆-|Ggᶥ{G xy(Ϙ6c侰    3; qY*=%z&'(MYRY&^ N'Er{se;"\!2 'z|F!:#   G J@l@>csmz8TQ vXusSvZ!ѕ/zʊG݌/ F ӲN@1 Wu_rƿ?^+l{4gП c:PM2q9z2>A G7}ƋtA|X2?ruIo1Rr`XVƋUvneku?9 ! Sf55C@5b|M#{݆8-6SO{U~Vn7dϕ>گ{JJfwʲ=q@d Ebl)Yb$}]S5syY=Yt\x r_a_fl`xʒm Ko2-=_z7%,KW?D+JL E*/ߤ2\Fd\+V!c󗲼;ڴHFڼYr˾c2d8}DVVjK״| / K%gp  mԿNb5>E,6IEƷ Cu3e~hYQ7!0yԉ$=VEuˋ @ (+$?{`GSZpM."O_~wR*2WǢ{S#]:ƿm%zzj*c_6|~9 z"O\*L*C /7#u9>Qw `SQNFa,۠*/߯ͽqm 8K qӠOաR(N"1~kv_qE?+΍4a:'z*ֿ7 3Ry>VNj,<}ڈ$=&E-Xʋ ˒ @0K-?uG/u-[3Ӧ/6%P Nsuf%`0J? (E=~ vK[lk݆3i@s%i{K-[N2#-~e˴.^G{yq*O͖4Z=#=9c)#3{W&ӳ2_㛦/rB4(PrqBÕxY!+Ys3է W% 3k3`e9|\ x,Ox!ʧ%%;(Ӓhw;RobD݇vi\ $30P?VAdEȉ8ViC_Vo+$ղo_:)pO-Zx~$?1i g|vij4*3>y$lkJ#/ jXJ0+lj~xQG}-utp%#   d" I&PwkK̻eF*z ƷZe~TUJOӲ1*)GYi)}{ӄg.2{~׊W%-'|8*Zqb"2oq}'$d[1qQs> hT۷X,Ƌj1<}YTB{lHHHM v+i${ʏEZ ws2E粽7jڣI_4>]T̒'4n *:Py- =)>Xۋd e?# UV PuC6}ޤŪ0/ՒzEbJ.Uc y>g-G^$-2Nԟz;ae~!bh&z$Z^F$@$@$@@CzYT (ec^3R'7:A~Wf8/% OL+;}8 zBkŠfR&zJGyg&   'pW=+ǡ~@&=@*,e~1l}Iڒ?J_1,%e{7Wf QT"kɞt"1BiehFgxX 6[*3+wJ._ XHFfJ]ffu9s~Z/ƿb^xNf" U±Bc3PZ"զVrO~ _8_=@#IuTǖNj;*}PA UM)mrYCgT)7pPr_ߪ$urlS6)7_f yVT*@3}My2-S/3%&;h&TH}uJ#Z2/g,⯟<ɳn| 'A<    #c0Xj5$AgI ;U5-%?IZWR_/h=aWųY}O1*~.B|'DMR'r*!u( ϘJ{G z]1b"гWtד>4CThiG& VYϿ7Z_~; I?]ΥCc=A/ctߟ*{D/csV Xu燚䯳r*5tgki|jm z}*>񩜍Ky}$3X SB MMׇVƋeFF9y4^De]ӛU8g[' WYL1%HfXi5)#^)$}v e+e70%Of*YSz[J$eн"ΐiyD^H)#<\YьUSO9|dRrDOTp4Ƨ|'sD=ьxXbY|d{W8' $9:Q=  $$P(۔ʟJ-v$w.%   #@@*D$@$dS2_hn&ԎHHHT9&   <$Eb3aWcA   k\0wIH_'l{,ċg$@$@$@^'$@$@$@$@$@$@$E $@$@$@$@$@$@$0q0q%{B$@$@$@$@$@$@A  / !@Ĺ %@@P4@$@$@$@$@$@$@^'$@$@$@$@$@$@$A LtL{ɞ @PA(BYŭh@F>PMcE {)҃E =>kA)K7_Z|:-ǰrfHHHHHH"0[Jm [PZP}NNL޳c$@$@$@$@$@$@$0ޡx-ʶK^> ^yʢlmظX+ևbc}58Gר M5sw}lν"'l.ȇ];ϝAK 攖|Y8oP~s6U'DT6#      |W>Y9k]gnx̿Bw&ܿliR^$@$@$@$@$@$@@b%Xp0O&N`_{UF)nZWFWìtiܫ]%J\3l} /o(>BWSOUcMe\kPĢ>U뵥>āS/;:;kS8b,ЍUՖ bɗ믿w.Y=h0h5^p=@˴x D[[rb,(v$G^iWlvb2ě j5 ˶e-=jVz[*1"d }hm~ ηxxOZE&m%C:oYyjEV!R UCvVUv)'Da1lbs8UŢKnl=j|r{p- ! !ĚnpmNw/y7m7z'MAָ~аu|ޞϦ[PYQ5k卑r^YY[q{@샊9|WyuԮ\(qBL䷟5UzT>ToB4/۴ p2J@yOoD7+0;O >b8u]F1\ m'_X]U݇8#~Ѣnѱm渗wy0v]'  kq"=rZ@!|X[3#v28A0!{9x^7uV|N?[-87WU,Fȁ/bUJ$@$@$@$@$@v`n 귣nF\v;ޅ^GGwU}b<:hO)Ҙdg"U[hG/t3ډ;LJț߻`Z.g, X! .iϻ c׿/uA$@$@$@$@$@@r;ҍMᳳ(7l8onMr":i8k#78gq朶^Wkni 4lij\wu3^W!DѿhƋQ] $W=勵z][bo;E}[-OU[`Ccks]%PG_]d¿>2x11zrxQ! xIWVg}i^R;wb綪@~EyJ$@$@$@$@$@@R;&ڴn՚2Qlx  PYU/BiE= ӖwlLھuif_bހb{'(apJ>l(sR(ő%pZ~!^4S> G믱9Y/awĊŋxٽ;yF$@$@$@$@$@㔀7R\t 0T]PS9ߥ]rג$%K }ӲmTT_rb<'     ._\w& O#e@ſ7]To?^ґA<`vإy - \A%4)1YoADLS+/R pe.}M*1HHHHHH (1qln~ĉ]AuSO+@@hqT/"/<Џw4'G/WIHHHHH`@:Ŏ.ԇI/X.MSS.eZY\+ [ <6 k%@:MWo n0^؇1CEұZ:.=}\)}߁a:מ3qaebW1u4MqSt_A w9͘c ̲C̷۱#e @P%@/L@n;12vײj/|Cbv d :b6(_6=Ĺ>= Rt Xa+\'V1,|?|{*fNUYXՙr k:MDv)<:-ƛ!i#7;Pg7{TlV:\qc @pw =.#N8ui)1@ kq_Uzg>Eoz_BRw%q de,a:E?]X_0 _>% 5π 05ׯL{x'ѡMa<|>ߏ=MV)l      Spe2c[ OU ;h+BO/Kş 5 9>,?9sptFkVfÊ2;+dW6vy boZf3b?%m`>xe@A / 1B*OGpU]:4<KdH5ׯ7P|VSp[P^<     ,"sddaS~FwZݙS?X[FЖeX4QV5jRػUȵsߘ c8 _[a[*ύ<%ԛ 8,o0U!z/}QWӉ]o+Wirl}Ug$@$@$@$@$@$0)$v#D?3RQP)w>n)ӎ oͲ]bX2ȋ[ؿƽ9HlAn-9^6ҦU@H2 O BpFA '3|EUȊK+s%ȌJjgZϾ^aߪ鮤Mҏ`uп~+Rjqt;nMsf_ROOD?1~fd`/T}pHJۛgb,L!     B"{xsy{&jC~#lrkNMKG/\> 8h46834  b>6P n eF18\ 1%ӲGHCUpg?6ڱ6ώyZn1\cx/ܳ; ͖_+qLǶ,,~4_4w`Dqr*؏nц,rVڃ!4e6]Es_<fe5dyOgrK$@$@$@$@$@@@c/yU`( %U~rܸkvyZf`Av&ڳ.獆HĨD*UŔ)r3HD mGM{xrn8VF{-6^2\fsGwL{Q=+[x{A7^j2uJIHHHHH`Uԏ= eK]Dhђz7|45Ѣ4®.Fe=8.7q+ۅz QG?s3?( u_^'FoW6}on;eFÅ.!],r}_(?8GANI22     x>F1*ȫ(Q֒V̪iĊ6l) hJ%6D/Qےb166!]ZhIjDwm3safޙ;;{Iww}9s.s=cKC~h҅Q1w78o-&Z  h^@+Փ'O=V_0V)g.>n|LEvQ    @mMXvwjhYZ)!{wU &'o[f#  @jMMX+>>n׳}cqu?>q-۽ɴ0sV@@h)>R4@@@& 4}@Υ@@@h-4@@@Hrv@@@ 2]MC@@@ZY@+>mG@@h-4@@@Hrv@@@ 2]MC@@@ZY@o\[@@@)p怨c8wvϹU*TI`=ܽ:Ih#usvnѾֵJ˟ȹ+[wйWVz"  @YmsHZsXޓoйk9lP[_Á9۹+,:oQ`tnW@Ib$1 ףfsT @@'zwK",p>W* ot XO3۩6؉R"p`^ r z&̚unfe@[o@@Ȯ@ 6Х#IY:7̹?5UGmUyCn_hGأ$Ciu]Htiϝf~lhtVh>!X-ܥrp]Guآ unsG'ޣCR*Zk~y]mDI=oS!@Yʕ9!dn%?Vlw텿iαPm_z6VHjzmKeQjfG|C%wkw.zd ݣVvo  @!&SjM xt(8+۳w[t[˕uXRY)7MU0xڽV *?7L/Y`p((=Yt+^ 7E4|iu<%,Gl@e',)W)pJ0g:Y}2MmUuyh[or#HTzNYK޲{1km   i- Fn1\98z?oylD9s[9:ُ/}ndA_ E@@* ]}Yڠi N-U&`zyxXگ2:sQ4Jk eKXBoɄnwoo_)0[ɘ|>Ykж \nu&r'~%gx^"%|٬\׿s]ޔtZr~$   pz ak-V ĞD`nz}pA~{-|#~~ۮڨj - GRd<"2QaI -7O Ҿⵟ!I?\Qoj %>mߩrjEG&gсzӭFG%meb  H5OJZsc[FOYTdmg}R}}S#ťu[+ϴfoiQTVW(NyNR}~(ܕKM)1YZ Zil֬PRS#  @j qu3i@w:Utx "JQ`)Q( b'iJ\%i,$._"~ɱ:e$KFS).Qꔓ@@NG˜b4N% ?cim%GS;4MhW?4 &sZz=RmZok4lFpRT>zΐR@W?^'I @@@q1ץq6ޔ8׻jOJSoNޥ+0 -QOQd[;/~ˌC~ fĨgv4X)Ճ@@@_!Ј-fž#`kKF; :"MpBx׏kUF?\}JF+oE\ ܡk_2mJJ|jߝeg'n [T2oԳ6i|'or73R<}C]@@@k4]LWڥ@c=VtxQE~=z+n5bjO(L?VUo5cĽ>Qo8UK=qQKGv^דڴe:Q>"vVU3To#վ7/'j T \'ujD%I=8ع~HӥM[+u_,T?+Su@@@Ȍ"a(@]#WL޻E]_ ::7x_19>p)=I>m+ݚ1ݧңDŌ}9BπT9ľ*pFоJ̄EmPR>V 1PAMc7(HA~PF\CnҺTU]S+ @.*r3Qk?jZRZP{ w   x*CïuG*L]^'ժ㟍.o;*XA 8.{|4zMo٢k봂r_/mR\Y]_ݨ__ j?w߯RwdеW~Xxv8Qѭ =K5bܟ~HŒ9~D}V.ʮ87Dao^   h kas~@=>榢7XS#Vqj{[42?6UѵmtqԬQWUYW+"fW:p>3G?t\e:J~)W/YA8٠ruC-.E3G$zQ d*Du{G١}p6#  @Pm*Q@nߤME y,U)\SdK`Bgߗ   y&<T(4M:2oJ`3   @KX 0FM F(koGwX>J-">?uMG(L@@WJl#lˎ6.͕Lz۞?bmM}%Z'b_Ђ~5@@@ [ hT@@@ yY7E@@@$`+   Y ՞   $ ]@@@Ȫ F@@@ X   @VHd7    H$bW@@@*@ =G@@@H @ "   UY9   @ @@@ jQo@@@HŮ   dU@V{z#   @@,vE@@@ $s@@@$`+   Y ՞   $ ]@@@Ȫ F@@@ X   @V},89IENDB`difference-2.0.0/assets/github-style.png01006440000765000002400000112767130471654300016473 0ustar0000000000000000PNG  IHDRkC iCCPICC ProfileHWXS[R -)7Az;FHB ؑEׂVtUDŵذ`AuADEY 6T$~{9Νoy[@*F{1?P@b <#"B?[usq@" N䲳 >  t@<XY @$qkq[Jl#!Leȉ3٩0bK>LJx;n4n'eeeC,O883y<&:Hdߒ)C6j0 R3ތ`1ܑf~rX8J_q$b|/M3j?5 6 1%exbkP 0^^`(NfGG󹹾Qc82s9?3l oMB gz -:N=ϋ X܌QGiac6BQ>R~RL5+w,/̂͒pP#/-:@ssCƸq>Rˏ9[,ȌǶr3#uGv &8!叽EDK80d }a~I{ A*Q͘GQyIz 꿎kOs"͗xdglָ#4ǔK!&<ؐu&lBOwOSB'1&p^.Y̐?Y,x"2=W(9n7]2 !k; w!wsf≻Gqkxb~?83e<{(?Ԉ?[b˱#X+v5c 6τ'06Z[F%qw`;2g[LbZ[Z ߥ[dFrNTu,=?N \^k8 :\ +C h=` sx_A4H3a@d=K@1(kP `/8 ΀ 7}87K0ރaAH #j6b!ֈ#"!H$$!!H)RT";w8rt"wy|F1*!:uD=`49hZB+jt?ZA7n%:Lc`:9ycX" X VUc&c 'tl<_+x=~7A0#8 TlB1pp>{" L W눧^DR#\I$)TLDO:E">edk9'']gagp\2dd S)FWJ4%RA9H9Oy@y++++$;U'XBEOT%)՛:*ޥh4Z"-VC;K{D(G -{%/#o )?S@\5CoB* VY+)^R|DR2TU()T:Kzto:~ާLT6RTNW.U>ܮx;{/>*V>K:6vf ;&p0!hAй`jpTpeaHS(.AA?! aTԈUSFZEΏlG͊>+zuQLK|ؚq>qeq_IPO%4&cw'MaZto01gƥ33g%?5H!).i_V859y~s]eg))e)S]Sץ y?dgɌˬ"g%e+3粵dw ł 9`\$wFnc2<괉Ez?Ύ}dsW}VW<|{^|K,\c!0ya"EE/޻$cB²wK6i-.bbae.˶-Ǘ󖷯YiŷNR/++/jků#RV_u q ͭk) ]Wd 6\*-߶Q"q5TUެ۬y[8[zl=Ms[yQ_mX]3]Zsf_t{ơfƾյh|44?QWzz{n9xQя#s;oiri:{uNX}rȩSCΤmrl禞k?| g[=[O]t|ˎ_ok;vvk;::tr:s7 y+֝owy~7{/~@xPPa#GYm}ǧqޗOr|+zJ{ZLYs~/{)x9n-?˿jEWT pHYs%%IR$iTXtXML:com.adobe.xmp 1484 222 <5'@IDATx|TK&HB6a5a% b⦻t%R>|/nZ_ZPhY5JhqMT !&$u9̙30߭9{s;\w0'PX'ƞ?#NHHHHHHHHH d0 $αHHHHHHHHHH@rBZEHHHHHHHHHHH (8#         HL*          8`gHHHHHHHHHH 1 P0OBHHHHHHHHHHLys8          $@<1 "         3 qHHHHHHHHHH@JbEH 䣰pu Mf\ٓ/4Z>aGz&ԡqȤ}ƕzV'C$@$@$@$@$@$@#@?0'@I *ߋ{fdf+*Þx :\c݇ǧ7UnHU;$/3u( gNTi'Gwb W @yክ\v\}>NIIA_ ǑzKO9OH awJGFX.@w=fM* !OsIylGao ExwbOC^J      T`/D- 0Iu@f Ď@ǹnKg.X:߶|^s:tI>/ĦڇqH_: `R[/2U΍HHHHHHH q̽rU'1yLIתdv}#JˌG$[ [_L& /{/ ;b۽[C} p}I"˻9h3 B ΂y'5~{oS5S'a^/Ki@Pjy$n{]w&Ue$@$@$@$@$@$@$@$,;vpwf~ TXlLE{1`2F}]xhjv Up$dHtixwBiw7nIhoB(݆}ذm(H=3g n'eK<[|u8GZ.>適j+V ;مKVo hXXWEN`uۛefD:^!eb5X83׾w}5S8+wʵ4݅n ;K2H8xnGĎg 4Lt6a^/Vc~]w#][EPǴ{ͅ]UbqVac%uI͠#T+cݍu(_fEA̹/V/cp yryj s w5p %C\/*yϲ_TaI؍ޜyy* 5XPt#n>:ˈ(יۍ2"=OՀϮI7lm`!޷yZ [1o]Xh>][_zrж[:^; @`E2[3X+c-&M)Y(]e R '̖xŴdQU/ϰspbq ۬. X]'\qOA'M۰^ܺx%j-aSTK~n9W[M({?..f'Q +=t~ml^-G>F͛-l'y߷~o{>:s^g bul(C^lڴg J75_fdϐY1Xgq0C 'Y9>8x|J,vDR+v"ME@ux!41oPY ϳ_A:}/2~S8P< \xG%oNƻ'\MS| oH3!?cxKSal7+7Ąg4lglv%W27ljg 7`r+ KKW o /dYtowyf*z$x",ԞcpyXyrbΆ/<"?/1c:Y}ec}ys#; v'u{Z^FF6Jb"HHHHHHH@r|-jelį*훼pV,x2r L=V.*ڮZ;3e.‹Om|\agcA~x3*k9Bw܅YcS}-6ZEyoטiaӧ)jY{AxaGCSJ- XB?ۭw P| &`[L41șbRɅ?:FCEyE`E~l|VC%޷C\~3fäi]ks,0U]gZB       H lw2u^):+o'O߄D(M%q{^'!ެ7QP=FԮ}-z(]R1Vog!K ڇk),EE%gXw܉@wrLe9|Gjgc)L[15_-BHdmٸ*̗0(o=ec欩ױ/,E~fzQY/§N*} N;#]aV̟Imow:%#z FiEwse. y!bTq߭HHHHHHH`x wV/sTRsukN4{&6~+=^%5[52{ R!Vq^&B`Se.~YZ')(dn|ٴ 2ؼ{'*Mq<j6bk9̉}`95^a?؍sqr(κu8f@2z Xk- kmS1v,;K֊Ufölz}O|'JJW(by9i ̻ #T{ge3^)S㕠3U[>~)1aWWu|=˗mV}k<3Eqȝ5r9Q(jNl^:O]zA0~h0x.;^99oB{3       $$ og@:QW5+[eܶ וhq΃ټ\+r`󭥨v3AI2p":ZWeպ;o4M5W=B{ٲlü2o֡LƇ"RmrQgo}Z]g\5C|GYp52󥑿Ϊ.9o;=0$C8jUz;I '8{~S/gvNJKȓ=Xpf>HмVE6`p}n8R} *Z=g-+6ьڇ7`8axߋ)pn2׹s>wk7=p} :P}Ro;kj~,N߹Z^{7:z 1yI6X$GzxV i8^g{hHɍ.B޷} \Vղ W enI~2luԼ`xaܷ:_ѮpkpHHHHHHH` đmOAGq͸lܸ^}l9h#O(٪|ڛQ+komKKˑh)}uCgMxq oԎ|ތrӄv>1C9wEռe!f_X?Et]m "~nKK= V#޷>8br"a";{)\ QR~-&cܶcm?ub5IHHHHHḢ%ȯO. *M~ @xׄ @ 9$K ,f$ QrM,Gg#XWF@l~ GB$@$@$@$@$@$@Gy]Z4 8*1[){7-A[d \$@$@$@$@$@$@$pp]H >Z~ߊ9%>r ByAIHHHHHH .<.9 @`HDBHHHHHHHHHH .(3!         Ht >          `HHHHHHHHHH P0O+DHHHHHHHHHHBy\0s          D'@<ѯ#           qAHHHHHHHHHH@JHF: S=shuڟ*3td͋ɱrNtrpP. (s L잔5B?v G'$|rHz6UƠ$5)sPv' 6#9ǏFhn?8l虱Z>OG$@$@$@$@$@$@$@$2 b(\ƥ$Յŧl˙9 5ML, JxVe25݉tZρy8օGi5  k9{D{2<zcG^K-ڔIE<9a9ΆO:,j};MCzEֵ }~aLUIHHHHHHHH`D`p QH\q`#<jc,~vQsl'0=^K4HHHHHHHH%7jE$xkЏ%uEFxGD ޴p(\+zzPץ<ӡG/F Gl\=XI0߁QQ2tĝnv(4Ǒi:t9ȖZsvRQ1>7x$[xθOJ.i(7zm}x^bdMt1'QO 22qL.UD?8?|1c~zT:0]6^~"u3~xY6E]v~-7@?^:cb^8e_\|Ms<<#       GR9cPԝjCu \qq=Qjj*2d}W-$%RwUEX+b\n[lw|~hԌK5_r񳨳‹͍1E>}.x'Ke "^;Z`1:!gEjgFNJG &H8Gϝò~/>iӍ[O e1X5:%gKZc 6˜dS{cd(J u?Ar|]bYXhsݴp5BѳX^5_4<7d:F!-+)GrE~"oH@$@$@$@$@$@$@$@$C P)y'Gz oK3j&ezb6vױT3%8j(W1ּfg2c]C}hw$;t8Nc؜4S,w v/f5,=m4nebl|"+ݽhV? R 2GaR^1/stSXssҤd\4+R'κ.(G,ow,Xѝ6X}T/6MK O6z!f># p?_vȌHHHHHHHHB$vH h!3XR挃C 6n7:{=S&bRtNQyx3=\ p?ҽS337yXy3ToKWJỌFv(LUc%9IP^݉fƾ4!e>c Aqtᡝ\9Flx*F'Vkbӥ1G k/ :fFxgh=/J1á3gOdX#Iyiq9p~VZ:eY0>ódi|&u PB˲$4N_/nGfc&`;DOCl$KYiI^'NX]ֵ$Wo_OOB]⢞_q#f$@$@$@$@$@$@$@$p!O0rUNF`1ΦYY2U>"_z)7lPS5V0ע25|NHņzQvj%I630Eo*O' -t9 ۼδZKg#$r ytC+^ \\9"£@F±wP!kX+!iҴ4Y)O֚8R5ۡ g1VjVAOl8X4utʺN6_dGEjg:3e]ku{e^x9zpc l&y_DcXC[ {";sRTowEjv X0mf O0dMkϙዀC9kge8,v;pjʆ dL߇ Vܨ$xzc;pl,Iuƫ\i[]Kxoc߷YqH)c[pJ\y!bhwvZrFXtzq!9U-*\0z4f'W/~#}_<4 8j& u crP.[gQHڻX/%ݏ3;ײ0ƫ=Ӌ`OF zGf1 Ǣ g} KHHHHHHHH 8s C̕M'OrIb6]>b`x]Me'r1 h$CǓ8G9(¶!O_۲A"P'aM,C QYqvZ:_ 8U|-xX{7OY59ꓕ66H菑lrmJmޙqYQh(_B|0G^[cƓKM){EKj&./@/;Rd} K  @xȚ{:쥥DxDi(onِp@&3%?[GJXOA`~5z9Ͳ"zZQ+li:S Ô³s+?8qL!G6^]86_JÃCxyd h.eزt0ơ¤ u]ɖ^4H\hR8q6m~!salz\yMyIIr9-!       %n+3V_.1+Ļ!oXxbKw#T8밌ѦަnTw&޶8 !mc?*n\MOIòp;`KL m}{Qy8!cڥP֫j?&"Ho$=n^hmNqP3݅7es֙+Sbo>~?0as~7^G$@$@$@$@$@$@$@@lGRSy^ m7&Pks~Ά*q6wI|tC!dw*1tcw& Yq~RҐv$uIw& #Y,z46[~1F6VqG9K[|X,4}Yk':$x=2y =xFaOJq~[ %L}ʍbʼn H$p^s@{f*p {=ⶱ))̣M1TfɂӿC|v}#JH7BXZH o'٣Pjnx(xb"0g-N~lZoPvjgJ±\i\qZtԺ$^t~^sI!T(ka>n7<ͼhiOK )qZFX>_Ɠgš ~(uŶ$@$@$@$@$@$@$@$0ÅtzQ;1^.εxMMSdQj `"ԍslIx]/1w>–^d_Saț]!T$I%NaыJ g=[6[t$l7IƖl<OBM,ԁҜL,l9+L9mCl"*BMjd]˂%x)״8# efTTfۺ%Vt,n d ]m-4ֵ)2\K/W:C$!p /UY^4JX3f2n8 OvxLMƋFanqY-q'xU{W"[0jpҰsb& /^n=0mϺ$@$@$@$@$@$@$@$0.B^I;n4^??(n7^Ѕ>NdX(p=Xrڅk:D./2NFymnǃN¬Qewz]bn<31rp8pOhݵjȈ;,;E3pu\5ڦldn'd}]>qDoCgsHuNv {'cqdu LjٯғpGm6!~ebE{:$5gz$JhBz:, clF6FB(}i|my K],W S(ﺘeg$@$@$@$@$@$@$@$0 z(Kfa,将nlI\h2Fш.!,"6сv톞h¼yXDS]hA?捛?:kwwŀ5[N2c°Sч5)^>Ɍsn@>'@_NgPNki,bV5u\b~F-ݶ,u-/V~¼vI^\B 0b5|xrnnO?89Q/vdC8VWS>fV6gmONea02ƚϐq?;cpHgi~R_gX2_' >,FJ"/ f4f@{ 7\|/ t2쥩$@( ct}o'VB$r6M ^Jg/ R >J!LUHHHHHHHH`)p~I.ZV٨ICvz*fy({HD75=b.by,ٔHHHHHHHB&@B J,W),Vt圇pli/bO$ | >I@K L\ı-1ُY_>BLk@sp9B@3IHHHHHHH <9 @HNx i ā8@$@$@$@$@$@$@$@$@$@$@Oy_#ZH$@$@$@$@$@$@$@$@$@$C $>7@xiZEH JelN$@$@$@$@$@$@$@#=G$@$@$@$@$@$@$@$@$@$@1"@5ܿJTCC+V{h 7;`N☈ߋ32Qvzdm]x %"8Or|{NG7)';%,/$9R8=,~) F ~g)ƃiJ>=°[/O9age )ܒaǀ0b<dlJYENWu@~ua&N# V>&      0D/牀z8`lB'h#L^9H՗S.,5W^* } <`֏$%2 ^ `Z&&ib9nQ5?_¤ Kv[9 P3&_=k:&׫1tr&s/v{柳As @S<xxX1HHHHHHHHB$`nEHh1M׈ M[TߊH?颱?@'-JuLoH2d}"[1[~C.hn7 vZM;|xV/T/},>S(gvƚ9")^1KivƔ]$e~*D9Qw o^67, |p4/\p0=b5!۱4y.o> Ĥ23(P|IJ$o /fNä"T%_ʘvٴN;^?J~@ZZmUT8*qs8CνJ1S^uoÖ6i7$OD@_ )U;SϡNj'w$OEL2[>z$]i궑4IR 'Mn_?I "LO-O@;#;E3X[m0kͳ?gD~rùߵ|Es  H") ($xۉ6}Rn%bXmS'ҬspP}O^ AȚFp6wY8MHuǽ:)!k9[$"wE*} vck`2aTz?ž_'HFGJo!6fXj,/**`.ped$/Bk>iz8TCIkhKDg1gB򓾆/@I%#Dc2%,Iڍ):i4/,cgڿ!OjE.y>>A@ʼu4)LZSoAy+v+9rzGK?`~~zn[9Xڙdn7js8)>i)v/c_ڝ1iK;b2[޵;L=y:BJ$@$@$@$@$@$@$@#RH"Jz-JY=F;TKV{D$"wEmFنX#'}ΰ(K-byiԿXE5uHb8$EOj XyMby;NbS*( h|%G,h l]m;E Y`t] S4'8oFQxsI1Xgr%H~N5EA2S,Wk79034UN_EF-ҏWZX ~E.FQ+wX#Voxzg2½c< yg؄HHHHHHH#$oO+†tD!A%rQ'Š^QO^ۮuKU Íj%+yM<~_oy2$V rViWnt&~/j]4-'^Qf HoI*.|nJ_5P]ec<w ]O&缼 _݇C7b;;>m;S윬oR4xʡt6Gwf>";X>xBc}pr!LzM K&} ObmEx(Z-FMr*Pg"_$ q~[#!X* pdlLYs╯⼫\[_xxw- u"&BG0.gbzt*&v,:0'u5 Q;橁c7]u`t}K"ل59rMSw, =F8{g!=e/L$N$@$@$@$@$@$@$02许106U(cU]"MkZO%-]w0O~q7L|XR$ 39Yk$xe44w Yy6%g,+ۆO/H%xL|>J:̓ڧL\6-MBlAuC oȽڍ~3n9#;?[x7znJvhgdղ_Cӡdzm6df,֋Z/]8~tz]2K?-Av!B sAv/  >Wx~{x[eAPGq̳꒮Ǵ#1Ȱ#w%po`wI8zKF_Xۑ$gʗܓঀl|6y;=: } Ml jLK. ϳxhi ̃9:p(6Tɡ/9~] ZU֧){z#FԺ٢Iލ({At^+[]7-Q"ްY[kF<1}K; Fom-Fߒ+k0yX -W2 (Ȟyq+yeCSˤ=Y-RnZ\3uI6*,YZx5Q w0{GbKa*TlaL>{*/QhٴO'C7x॑=&XIgO=cMڿJ04HHHHHHH DQ /zGʧn_p|("!2rL!Nx?$/)\ҟ o_OqDD1IKeN7.iWl{ <$"LYq!J۝2qx8.2(6);7OiEa>Ik$oͼX.0Av]-- E:usɷ`_ʷ$d&`E%*@.#*lL]NJMڛj-!M^O 1X)2t<~ji+Ƶؚ|eٴ<./1w"GH%1UqᶔXQ,w}4D oeV"4wN[ҨƟWfN÷T?BzT˂-"]'+/5~UH>v)ɿO4rR~-),6x7 ƻ_<.*Qo/(߉]ii ]"7zA|T;ϭq?P)M"hz+s#8?G:*mfX.ڐp*_cwꝐW"re?DV)x3hOGEX_RN2ڱ[·H"=%v^$߉'na9-46OiyҵXY;,u"_/ ň#~M~ ,= SGˠ_={"*nrW>m P]=+ZPu,Ҭ gnVxAz".&w`sZ(\K?ŪᄹL,b'8겐[_a{n cF^bӴ`hHg>#Ϡp@1rM$@$@$@$@$@$@$pC)ƓWr:<'uXRIبQ5u5<'IHHHHHHF 8ddh2 ߓ͙U_P,_      P0."@$@$GfhɞxP$@$@$@$@$@$@$@Mv %# A툝 '      !@ HHH 8T"+7%$@$@$@$@$@$@$@D!Y ,%         Y(EkIHHHHHHHHHanIHHHHHHHHHF #zZ          a"$ SHHHHHHHHHHF zKECIHHHHHHHHH˾IHHHHHHHHHF  #RP          $2H 䣸ft@wFR= v$@$@$@$@$@$@$@$@$@$@8ϛ~bkP18Qd5C\ }yrlkޏe7g$@$@$@$@$@$@$@$@$@$@1"p~C8o-3r܂thV#5O+].[Q8BFIHHHHHHHHH _7bSnxeN*\X҉;ס[Qto5{pf`$@$@$@$@$@$@$@$@$@$)%p~c7Tc\8o!daRn%4q4q-218Q3bSVnB3;5HHHHHHHHH>}ί`.k7T6QP\g>vpƥ:>~_o"         @|T̞KCϩQ[_+ю׶¯T[R^ik5 '!#EMm-G5KKkӃWcȖl="c\_fհGy彘U0dz}]xhjv4߉jtƴ89)[QX\k/˖y~da/&sHHHHHHHHHG I<ix|f*GQ5oZj'K򴚍’kvbj䩰)-PT⪭XU2SuS$'.4Xz/V/D7.ܸw,C:f1.PsfAIp諍} 5 /pjd䗮G`ca^fv͗zju cߺwzQVmQljf4H>L>r3bw'ZGa6~0t)Z:˜_(]{;+Pv)*G<|u;5X\S';yxt P dH(㪩xWK, n!KHHHHHHHHHHK a(* {|πVۿ8C?ê 1GWYB{tIÎ(+-Ò%Kwo$;i%+7n/⩍;bʫ߆މ6|l?[bjTQ=DA.n_Sәr.r?gr~f<          !\y Ja3;i 8uf9JW^fMˁ%%wM_Bd :J>n1iŮ̡i v6$1oE06y7ԡ?9Cn:mU鶛yN-x y IkWP[Ba2T?yzk*{c_t^r/Ť1EΓ8D>xSG_i?ءFͺ|WOcises/v`O$@$@$@$@$@$@$@$@$@`.IrQ=v}gP:3e.‹Omxv{c\= au-qg7=d查r8)tګvz h          O Ӭ;++f,A%`vS}-6ZEyoiӡ57|k-=8~JO]26N66;C㙗[\ܱWL^ Y/VsyL$@$@$@$@$@$@$@$@$$ЂyM0L+#@^/s%B]GCUZ(w׮}-kׅE||>5 K+PjSW:fK6lOׇx>>v 6ʞ 9p,mxIrHz񳼰k6m¦lHHHHHHHHH!Ђ91]1wLJ͝Xn̟j/xU P3TY*χO>?{dؽD#e@9lދu{|3YM!|"濽At~#W3)Hɺȧ'$@$@$@$@$@$@$@$@$@.0lc]e6: áXގnš6=ǥj_ n\[̐.ݺq Xwk)j} ,g">zf%8s\=Xpf>&^Ʌ1l-;ε͆;i4݂ [=E^jft|{#         @n .3,,a\0UQ)j>SFF̜|UjoXaq_- |Ud_U&'^X~\fNHHHHwqrUuǿ@  0EL7+#5. aX@YYE_Yvf^FX#8 :J #ptAIIHtjު]UNsyuֽs=}.  I`\Mmq\\n=Y^zr0ޣEfXxikC]zi׉Z{͹Ϭ!    D lXeۿ{木;ֱzG'צP*]\Y     P8a^BO(     @ j6M#     0a'̥#      0>m#    L s)     @-kO     F|\ :     PKZ6      00     R 1͏P"     GWM͚_: OkwmуǷ놆 ׽IۡUǶ:M91@@@@Xv''4H(ӍHTL 뺮D[WMoӵaRmH(]Z7JQ[ f*1]PysFc6Όk;`yv      pyTgTR?գ\XNoF$X[0>ҏ{biDU~ReRGꁲ•xvC:GtISj(    !P̰ԽFW\\o^tP)_x H@"ԖGؓҁm9BojB=Xv4jFF,4٪7wtkS؎    T P|ay@Xkl@:?mMs/Ʉ6^Jh`ʂ#c.ϯ,/׫oJNBswפǞh@@@@&@ >7Otj]rE3쨮j(f6lljmӬdF9:|=NSI#cZ556MLw쁁AC!=]9]*8hLWىL_6h;N=I=zOD_jv}V{trgX16     ^iYI54z)=9FSkRFׇ}h泿mKVӣ{g~+?(7Ur7mqCӋM{R⥢#a!~6,nL.tk_"+o֪ay^>|.ӧh@Oݫ-1Q-P     a [Vb<#R D?B?iЁV,mNj*ί}t6/onOG}o9xP+Gjbsoyϯhd Bg̅ -4B[4=2RŷU\ClmMu]s(ޡB{cal|gn]^iFT_\'5=ӢV_V!    @yyCnh>_[wwc.9cCT'x#wK UpI=nZndv.l٭MMAU؛Ғ`[ߞ~g@XЭzYMaNYՋҚ}Ҧqcƶ‚    TIF{t|S];#;sURHJ?vzō化!_O7~Ӂ.-?+9 ~_ 0SDJo S_l鷕uSʳ     (/0iVv#BsaW֕ҫG0-_ާu{邙-:ˈ[#a]~t~ٙ?wym/]m`|SJ+/loх>rI~=z]#V@@@@@@yŔOT'̾ X謁o Y Tu;k11i>%1ݸ{Brϯ'EsyՇ Bz)+Ǫԋ    G揖tP=v 66hyKL6Xxe8Q4 J%ǖy~Uvs2wBn|$D%S @@@@@N;]^;-q!R뵤!Wfν]/0*ʘ_0ιl-9^֩;x4@@@@6NFpDK;gJޙCTomjtkfbӱ,Vokm2ioCo"M` A8i;_.lj\% 4V}K؁    Gy a.lu͆{{qasZ(kgsp[43w{h0 ΁T.fH t'~Xi]aEf7tս'\a-l):+mAo5_9'fScpT׬ft&]],l ̋P}3xWVwI+m}9ky)kIvZە mc&ZTBw*ιYC@@@@(0΁v[`>4;,ԾB1}f;[t=1oa~mnziHg77@}1 rW7Y~@uCu@)3TBuhJ6ƗMw]:Y1{ʎt>}zCza}~}}!-3}kos󝻪"uy#    L|ZߗdBMc2T m-E u^m 70tU;أ˷ԏsSIKovj]?w~=̈rN>\)^ο\f oH_ߩO/|O%r{ͷ ͞Wo\}J%{0+     p4 +#qp'L/ץ6X/[3#SI`|Qʇա4O݈êZb#g٭c<[Mouwt$4,VlV}B ϔ~~K7wBQ]Uh]D@@@@.PX6UGzB+!4t2)Mߓ ˥-==ZQɄ     .0S:zfN C:n84T+z=pBΎ3l.uX@@@@@SխOTh~,+Q*Ҍ@X,',?JoN@@@@qi`ssA]G$Ӳ\9}#0M@?A=w>4,1     P@Md)G@@@@@`j>|Ό@@@@@(C ,"    L^{m93@@@@@2(     LSgIzb֢7*@@@@@h`~p     isn@@@@@L@@@@@ 0/68ISJA     㥟_>AZ:$}|IJL[M饉սz RŴ+V$~PnjOoǞn=PqD@@@@(q`n#7]:.!?>|mQ ,6vښsX9dsu>4Hsa[͙߅uKtv]{aN#G;ʄ>^ǾCnMz^Z;@@@@@ +P)Y,~<GlyI.賰:V X;߱ѵ8[zFXۖ5 Q_`C>^FJ?=_k]/ؼOlS~ V@@@@&@#Xvyl r Zl.kgYN›{h~AےiMIڤcmTmV"K[J:*_jۼgU5ٟf`}l;     * -y{Ђo=am$k) n]]OZjs6&-%^rr7uKg=C`>\N|eѶ{џڭͣþ_j~ɾ3Ex#}h]u,     %%-z_»wdV|7*}v[Zjpnu}72QBlqEkC#6k6q XVwNԁԫz4vP&l?UuS^LnԦʒeހ_kMjJ{L]U7OT\{XɡFw=yV?ȿ    8xVZX@±XxfZn/.YK̽gZJgHW˝n%vZXmoφъykwjfJ:w/\95]tu2?>M~RsD‚5 ]2џlC[(~M4,a WF6lʗkuGtѰgֽ_N5Mj9JXԻgZ}#=uvO\fvf*v/\bhc!Je=8[?̳v>ju\߸O'=DyҶ     p xiˀr-e]F׎T=V['/6ۼ傿ւįyHXB`Xoy}q" AUXVK-}r׎3Ɣgܔ4d{wկڀL gXR_Փ u7@Xޝ|M/$^CZ~x8u\Ғ vn;rNjL/$Fu-}^ieVvh[ڸxWr=9Q$ŏ`/    ^]oW qM4Y{oϟʸxŽj}]d?nt ֮[nog 2kv?}+-LBN7m?ҕ-Ojy؏nӝ) @eZNPty1֏GKh*o5pL?'K#Է ޮF}npHޣ򉙺;E]Tg7^t{!W~q&aМ)6T{y=:X'a'ĬGnߴT{d>ge)vھ_ÛKt{RAi@@@@teVt@$,p]8l,i&Ū:/[FVdk3>GjCg Slar.,w'KTnдڈp y6uo7sayzjS|?YNUi`ldlinB]Jk-|?lX*n9i mslT[)f_@@@@&@0-˥1/NOw"OE\"ԌvѽnrͦʰݏZܿ;U6U~WS1|>0Ѷ䦃º" !٩ȋۤ0o؋DgKCfim}zJK_mt0,|iqG>?Զk6ˇVg~_H9@@@@$PFJfS?ּs)…ma//+Xh`[QFVޭ6q ʧy)q62c\tNTV*9r=da~SuaV]8Jccpˋcx9UvUlQz9@@@@#T—~κԗxulU[<. ?Qn$~vpsp K{ PVQ nѸ4^j M>r,~ .2_}G,Tpn#    p dǬy47J oeo6rzM^09>nn_Yṇ}ާYcZ\J٪{ *ṹ_mZ#LS|v0Α    !P4F_<58r)WZNc, T^xmQIYt*^OGh[kE~c:nan,yf9Qz#VQcx ^|~%WTj^JZ.Q    (̕ѥ9XbB[p :,kq^Pi:n)W0cSӦwU*iA|z MW!rFɆ$/ܼn/*:9azאc.] oy:fsG>?2;hU4PoT`xsd6v}j+lUeٰ-]?@[~]w۴B_*    G@Yqsηlz^*ł-u!eK-$NnHk.+7wi:7BHos67ǵ&}sg#_tk}DI]~vY;; VN5 lDŽC}۴faS4uQ].|Rmڮ4'}?|Dun.+%P۽h-{:MXU/2ϝqAbz~ _ꦩ?ٮulN}W/.IDATNݥթۆv-F+#j?xMVe<"n-_wC>s]YfAvm{};;"s̱zt[֎v_{_%n    $p7{Bg-K/IϷI/jB vHxgua|ݎ-|sV.0ScwjgoD]V3k    L&:ދMOK7- L-oV G[G,g6 ;}~B+ ]OHE;bmb+ uoJ?j\/ ӿs )!y|%U?,Oa#G>Nِ|L2dGotu2%~x1in<Ŝ Z?LX> y,7KzFvK6,: ݯ^ \VY݃_{XX~=0-,w}h.5.{      p `3'~xlNnMOI}_ld[.O88sDP+lZhḵ ;-eTQ賳]XB֮QwɟhFk:3݅٣g+43}A=omەšvO9#Nmֺ,~Vmyq_ljb'a{T2ǾGd]zgFiq*.# Q;Ҏ[v%G!@@@@& 17]^p,]|ziyj"cI_J_Xj2_    5SuSK< ;φ?n:/8 9EU[ߝ54,Φ})e*q'!    P[)!4{ 9[xӗHp'D+aU?(q#o-c ZP@@@@$H;//?W.8dJ}] ۫:_WGq tIkE^Y~     P9̏ݱ8ggEG~a~_C@@@@ 4Ը4     @mkO     D|\     P[:     य़B @@@@@ 0¼     0A'ȅ      0?#    L r!     @mkO     D|\     P[:      0 n     V     0A'ȅ      0?#    LnB,IENDB`difference-2.0.0/assets/word-underline.png01006440000765000002400000036637130471654270017020 0ustar0000000000000000PNG  IHDRP߳? iCCPICC ProfileHWXS[R -)7Az;FHB ؑEׂVtUDŵذ`AuADEY 6T$~{9Νoy[@*F{1?P@b <#"B?[usq@" N䲳 >  t@<XY @$qkq[Jl#!Leȉ3٩0bK>LJx;n4n'eeeC,O883y<&:Hdߒ)C6j0 R3ތ`1ܑf~rX8J_q$b|/M3j?5 6 1%exbkP 0^^`(NfGG󹹾Qc82s9?3l oMB gz -:N=ϋ X܌QGiac6BQ>R~RL5+w,/̂͒pP#/-:@ssCƸq>Rˏ9[,ȌǶr3#uGv &8!叽EDK80d }a~I{ A*Q͘GQyIz 꿎kOs"͗xdglָ#4ǔK!&<ؐu&lBOwOSB'1&p^.Y̐?Y,x"2=W(9n7]2 !k; w!wsf≻Gqkxb~?83e<{(?Ԉ?[b˱#X+v5c 6τ'06Z[F%qw`;2g[LbZ[Z ߥ[dFrNTu,=?N \^k8 :\ +C h=` sx_A4H3a@d=K@1(kP `/8 ΀ 7}87K0ރaAH #j6b!ֈ#"!H$$!!H)RT";w8rt"wy|F1*!:uD=`49hZB+jt?ZA7n%:Lc`:9ycX" X VUc&c 'tl<_+x=~7A0#8 TlB1pp>{" L W눧^DR#\I$)TLDO:E">edk9'']gagp\2dd S)FWJ4%RA9H9Oy@y++++$;U'XBEOT%)՛:*ޥh4Z"-VC;K{D(G -{%/#o )?S@\5CoB* VY+)^R|DR2TU()T:Kzto:~ާLT6RTNW.U>ܮx;{/>*V>K:6vf ;&p0!hAй`jpTpeaHS(.AA?! aTԈUSFZEΏlG͊>+zuQLK|ؚq>qeq_IPO%4&cw'MaZto01gƥ33g%?5H!).i_V859y~s]eg))e)S]Sץ y?dgɌˬ"g%e+3粵dw ł 9`\$wFnc2<괉Ez?Ύ}dsW}VW<|{^|K,\c!0ya"EE/޻$cB²wK6i-.bbae.˶-Ǘ󖷯YiŷNR/++/jků#RV_u q ͭk) ]Wd 6\*-߶Q"q5TUެ۬y[8[zl=Ms[yQ_mX]3]Zsf_t{ơfƾյh|44?QWzz{n9xQя#s;oiri:{uNX}rȩSCΤmrl禞k?| g[=[O]t|ˎ_ok;vvk;::tr:s7 y+֝owy~7{/~@xPPa#GYm}ǧqޗOr|+zJ{ZLYs~/{)x9n-?˿jEWT pHYs%%IR$iTXtXML:com.adobe.xmp 964 80 /IDATx ՝==>n@ 8hC.&ܠDH$YL 1 FD I4\510*ü{Tש>]]]3·:9EΩD&/ǖe|Q6o8QXaYٓz4lU| >¯"k+[6\3)!6B< **B2WZ7H.4喷䇴g̍IHHHH`LV'     !Hh3OHHHHHHHHHHHH`H 'M$@$@$@$@$@$@A6@$@$@$@$@$@$0$ p!ypȾ<911+( kDHH:ZdIHHHHH| HHHHHH: ~Y      _86&xƊLFE|05. Jl2 #";M?"ZOgOjc   #@A\`#|Gd qAsQ!mI?\^g,-=Lmhiō$z I䒉yG"8ZG*?~ȏ^J q]0oXtG .,HD^oU;y@C@]LVLff;L,+emon{T_Oޱ;(tuۧ,?B T-!!   B%eBUX B+-.s!.+H Z-3JcŰye{yH*%*R{dN}LVR$шnl֧msi5E[ueHHHH 6ˮ. ˀ k8C7QݲCZ- C}@`ViIԡn }Pr[=4,$>*#9ۀH`;@!XM'@d' H8*/j]薌.+ Y<)bC+F^JwgD.8 6be/|H==2U~.S0W7qxY"KH[5'e?.R]L8Ȧs.n8X,'Xe`&t逄#ݲ%IBqySM>xH@ЗrnqL8Gd+Z?>0Y"G>0   !E kAMK%6:4Jքd08JUr#ɕF9LnXR-PgTemrAwi"uêd5sji\6lu"oyb2<,Uť~BEMeka}U,VoDn,45v1X΃^`_.NȥxXU8xqUtt ,9_Yznl-!OZVmƷ@8xoƩUvb~8 je v][U:4Z^eTunermMiR_[MzI9ɺaKafA# uwz b[Ɩ/ ܌yFb)K/}xh6^պ=/Ֆ^A`bDb<"   d5ISWʘ]jyx!aݏ;ZkqeN`o'UW͆VV1A@-+qrY!ax[ɂEAY:f۹tlFU$aRwC8"+ˢuR݃1P\T|IvEq1>x.5'ǬEbx0%fVUq'B@߭cǷ_!Ѻv5\DoX]z\;r5VĨum#?& |?3l}3NPTӯ*~}?%ūD-u\BK6?kΪȣ_S"~F%   E0RWY.0z+sQO萅[%e %s1y%|˚y"{dȳY.rDڰC)Bw[T]:yİ= *v6?瓭vpn65uUjz'ϵWSTi2<:ݶ%B[f+r?_,lgUVsh5W&e&9g)U>eS1!G11*Ch5 "yk-U7MobXy4 NM9S,mbX s!6}m-*QTu3=x~8.1|3e!4W&"m ~!Ѷ(.UWя}&s|}"HHH`B(M RXv=npr*Š!М( bkm@Fvm[N7#_]XLk l;t$i83ټz )iHTAշ6J <<|@nRI m=҄o݈KwVu'ssN3&~۶4y<¤cpqHÝ"ê?/3qD-ҥ\xamyYUd)w7v5uU~-+1E Vň<krn.켴3 Ʊ&ϲa6N~^( bXlMO{EY @ ʫqɪذeeռuO#.c'Z`>)_pՂRۧYUauqPV29yG=V65UFZ-⫼8 C $8չ5SbV9pɴ.im:mFXu;D<6E{G ٘=sNyO5(%=Aea/b5t󅆿Rsk;߰Zzo6Nȼ}aK17%&g> }HHHH@&܌i&^HnJ*Ek6.9&nxx<l5arj(z z~Y7RѨaC 7?CDG*VܾrqqԘ}"V~zvօ7/h˯0 d.*lXȞ#:i y7v֥1-~Z/XDz+꫻m, 7/s#Ա}hW *]{4@6cʬE&9ǘL273, ka'(o*"Ya~m=E&ZMػ)փ)FSd[^*f>?3nyjgI/R׀65CЗAiHN:X}nGxr >NJEVyЛHHH`B@̚lqROɄeZ:jXfcbz 2'l;6}&sJevtT[ʪ7yZD巘 }6m]aunerⒷZd rZuL-\qw=t,UåaU|!3KͦDuRɱ)1T^@ޫcQpa0rFw.Ǩ ]++ W6<$   E 7A X}.0R-rưʤo ˺О7)gg((kGVQi6D˩Dzf;g=LUw+.6M|eܨj{XOy璇³woٱqUxw X ~Zb1T/'ϟ僶q*md+Z>u^d~)-YƊeY;z^ڙ"T8PW].M!~+3/!'ZOM\=9ԓc!q<'nOy}u/FWc   !D gA,B}~tܬ MU;L1X۔Z۝!u5rz Țje J}u<\[#֗W;\V87(TXi*yh`b{;) Uƅ{I5Fgs?_.*?|_~X7܃o_}OgؼbS{.V"/SgoGT!9\wlC sM廭St߰#;S%( ɂ* a!7p/9 Ys:!$@$@$@C@ ys'Tb܎ʹxڹSP;Vţ j ˭4k "惪4(!/E'M6v/? YdP(婜wkOcJQKKCҌX\o?.}St6@LVdX_U.¢G9 t.גhkA-tgZNB`?>rM&BsNR"%ojl+!KyN&Y촷 ? a .1tŖӵZYZ.Yb$hv쯝vXP 㙙byD3|<\tȆqK|WM Ò=> l"g ]R%g~nbKa-Nr~2pHW{XU`s;?. * #3TR=6qSG6eAkE M5L՜ju5cX*ˡ{΃oR0v>e|cKo&;O_\2+R+LXt%G!iXUB 2w20v6:6ң}鿹~.M^/́=^0^pK4q'DOQEn s<<Q0   7c,lDDD֎avtmX    }Õ0#+ k-GG`6y.VIF,coN@תN wg@;.Z7̈HHHH d&ChH ¿vه}^i0x g8 ۤU.Kqw)Vo1y"%z|!e6e"?/eL & ֱ'we~9G`9Q30C`[v6ɀi **rls'$/Z KU~_.Cu3%_8<%u岺dHZt\}K6t}Mֹm*LwmBU:Aծ _6vuR)o.,9 m| ~n7-߽$@$@$@$08ؓn)D5C84fÃS&Wb!D)wGr̆8%cTy 1B媡,Rfn[+ a5q* Y!qB@ h1ӽT_.kKhm'jZɂ^r,8 ޝҕXOD=`r 9h >"KKnTyIU9xaV5qY(+ig[#V^VW?ί#`}4qHHH|’T[cᾎP^bXj~k*4_U* ܾ|v6`v)/Ax_aydz0SHR_تaCsau@qy*ি);,.^e+=YyJ5)IxFhdggc"+O3kUVhrV*E- LN-G;Vf(7 2i>N_HdW`~@W8~my{E>չͶm_7uy%e& nYZD~'!іkʼne<|ѦŰC1ڙR}`[ȣx~Q61"nԆS<3Ű"vK[aԀ7|(8\`d#UڝdQ!h,6<ůPkD~V{eVXnBiQ42g~lBP?v?uɥߦ2w>4y.>B1HHH0Srj157qxBW aYc65_ði*Ķ` *w ?5gH|GK+FtP e΅6!8xNCy,q D2)/έ"_8,*^&%9|pu=! îW3(gB_98?}>}N cFE-0hhD.~OLz-~J1 :Y0xV{=7`hy"JaUaz(&KwAlF§zfy }f*EYfc1x 1j(W0idwRf {]ۧFZW8 LbKG}"Oojnr_m!c B,4ǿFLKI0ۥ϶}fjI.c @'f2>|KYi1Y ǴY箷Zb[?,26b~Z|Y[ ^W9)/ìhQԧX~ -x`3}jLCl\.\)lj[%nO8/,׆yNyٙ.ǧEKք*RVf3;S 4`'OO->Po`IHHH`PBbaElfuJb7X @'Blg,; ;HmbUؘ{{o]Zٽ𐑕箟<3,]g-eXݟQ~J@%Jm_57ٍu<8|63T8k/U O+hG{VUk4>LJy]O->wfsՅ= ! V5-k[4!P?wN T/CC1+렼+S:.t4y-?b?3ĽN>AO蛋yInѿɳK!t- w9Uޤt"g; y> t v$sGіhv3E=~tlȲ`5^i49SWSmB\Y%.AņHHHi%vCPf>-W cbgzseCʘbXiшtx]a`gGPY.Hʼp댱~˳7va_wib!mrɭT+u0p<]B@T)2xW<& p w &! 9ѿ;Uw/EIr[A|(kgiir_ɝ5h<Z";n(4m[ 䭢kN]Dk>\se, 7oU^ GSuPa{./sO Z,o?]%(W;w- !jO:K@+h~maɵLăK,x0 BdwMO$@$@$@$@L‹S"     qHHHHHH` D$@$@$@$@$@$; 1 $S"      h!N$@$@$@$@$@$@`"] description = "A Rust text diffing and assertion library." repository = "https://github.com/johannhof/difference.rs" documentation = "https://johannhof.github.io/difference.rs/difference/index.html" readme = "README.md" categories = ["text-processing", "development-tools::testing"] keywords = ["diff", "text", "compare", "changes", "assert"] license = "MIT" [badges] travis-ci = { repository = "johannhof/difference.rs" } appveyor = { repository = "johannhof/difference.rs" } [[bin]] name = "difference" doc = false [features] default = [] bin = ["getopts"] [dependencies] getopts = {version = "0.2", optional = true} [dev-dependencies] term = "0.2.7" quickcheck = "0.4" difference-2.0.0/Cargo.toml0000644000000024620010146 0ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g. crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "difference" version = "2.0.0" authors = ["Johann Hofmann "] description = "A Rust text diffing and assertion library." documentation = "https://johannhof.github.io/difference.rs/difference/index.html" readme = "README.md" keywords = ["diff", "text", "compare", "changes", "assert"] categories = ["text-processing", "development-tools::testing"] license = "MIT" repository = "https://github.com/johannhof/difference.rs" [[bin]] name = "difference" doc = false [dependencies.getopts] version = "0.2" optional = true [dev-dependencies.quickcheck] version = "0.4" [dev-dependencies.term] version = "0.2.7" [features] bin = ["getopts"] default = [] [badges.appveyor] repository = "johannhof/difference.rs" [badges.travis-ci] repository = "johannhof/difference.rs" difference-2.0.0/Examples.md01006440000765000002400000001241131361617310014122 0ustar0000000000000000# Diff Examples These examples use the official term library to format output. ## Line-by-line (Git Style) [examples/line-by-line.rs](examples/line-by-line.rs) ![line-by-line.rs](https://raw.githubusercontent.com/johannhof/difference.rs/master/assets/git-style.png) ## Underline words (GitHub Style) [examples/underline-words.rs](examples/underline-words.rs) ![underline-words.rs](https://raw.githubusercontent.com/johannhof/difference.rs/master/assets/word-underline.png) ## GitHub Style (Multiline) [examples/github-style.rs](examples/github-style.rs) ![github-style.rs](https://raw.githubusercontent.com/johannhof/difference.rs/master/assets/github-style.png) difference-2.0.0/examples/github-style.rs01006440000765000002400000004725130471665440016650 0ustar0000000000000000extern crate term; extern crate difference; use difference::{Difference, Changeset}; use std::io::Write; // Screenshot: // https://raw.githubusercontent.com/johannhof/difference.rs/master/assets/github-style.png #[allow(unused_must_use)] fn main() { let text1 = "Roses are red, violets are blue,\n\ I wrote this library here,\n\ just for you.\n\ (It's true)."; let text2 = "Roses are red, violets are blue,\n\ I wrote this documentation here,\n\ just for you.\n\ (It's quite true)."; let Changeset { diffs, .. } = Changeset::new(text1, text2, "\n"); let mut t = term::stdout().unwrap(); for i in 0..diffs.len() { match diffs[i] { Difference::Same(ref x) => { t.reset().unwrap(); writeln!(t, " {}", x); } Difference::Add(ref x) => { match diffs[i - 1] { Difference::Rem(ref y) => { t.fg(term::color::GREEN).unwrap(); write!(t, "+"); let Changeset { diffs, .. } = Changeset::new(y, x, " "); for c in diffs { match c { Difference::Same(ref z) => { t.fg(term::color::GREEN).unwrap(); write!(t, "{}", z); write!(t, " "); } Difference::Add(ref z) => { t.fg(term::color::WHITE).unwrap(); t.bg(term::color::GREEN).unwrap(); write!(t, "{}", z); t.reset().unwrap(); write!(t, " "); } _ => (), } } writeln!(t, ""); } _ => { t.fg(term::color::BRIGHT_GREEN).unwrap(); writeln!(t, "+{}", x); } }; } Difference::Rem(ref x) => { t.fg(term::color::RED).unwrap(); writeln!(t, "-{}", x); } } } t.reset().unwrap(); t.flush().unwrap(); } difference-2.0.0/examples/line-by-line.rs01006440000765000002400000003104130471671470016502 0ustar0000000000000000extern crate term; extern crate difference; use difference::{Difference, Changeset}; use std::io::Write; /* * The only thing to do here is to create a diff based on line * splits (passing the newline character as a split symbol) * and iterate over the results, matching and formatting them based * on the type of `Difference`. * * Screenshot: * https://raw.githubusercontent.com/johannhof/difference.rs/master/assets/git-style.png */ #[allow(unused_must_use)] #[cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))] fn main() { let text1 = "Roses are red, violets are blue,\n\ I wrote this library here,\n\ just for you.\n\ (It's true)."; let text2 = "Roses are red, violets are blue,\n\ I wrote this documentation here,\n\ just for you.\n\ (It's quite true)."; // Compare both texts, the third parameter defines the split level. let Changeset { diffs, .. } = Changeset::new(text1, text2, "\n"); let mut t = term::stdout().unwrap(); for i in 0..diffs.len() { match diffs[i] { Difference::Same(ref x) => { t.reset().unwrap(); writeln!(t, " {}", x); } Difference::Add(ref x) => { t.fg(term::color::GREEN).unwrap(); writeln!(t, "+{}", x); } Difference::Rem(ref x) => { t.fg(term::color::RED).unwrap(); writeln!(t, "-{}", x); } } } t.reset().unwrap(); t.flush().unwrap(); } difference-2.0.0/examples/underline-words.rs01006440000765000002400000002656130471667410017351 0ustar0000000000000000extern crate term; extern crate difference; use difference::{Difference, Changeset}; use std::io::Write; // Screenshot: // https://raw.githubusercontent.com/johannhof/difference.rs/master/assets/word-underline.png #[allow(unused_must_use)] fn main() { let text1 = "Roses are red, violets are blue."; let text2 = "Roses are blue, violets are"; let mut t = term::stdout().unwrap(); let Changeset { diffs, .. } = Changeset::new(text1, text2, ""); for c in &diffs { match *c { Difference::Same(ref z) => { t.fg(term::color::RED).unwrap(); write!(t, "{}", z); } Difference::Rem(ref z) => { t.fg(term::color::WHITE).unwrap(); t.bg(term::color::RED).unwrap(); write!(t, "{}", z); t.reset().unwrap(); } _ => (), } } t.reset().unwrap(); writeln!(t, ""); for c in &diffs { match *c { Difference::Same(ref z) => { t.fg(term::color::GREEN).unwrap(); write!(t, "{}", z); } Difference::Add(ref z) => { t.fg(term::color::WHITE).unwrap(); t.bg(term::color::GREEN).unwrap(); write!(t, "{}", z); t.reset().unwrap(); } _ => (), } } t.reset().unwrap(); t.flush().unwrap(); } difference-2.0.0/LICENSE01006440000765000002400000002072130471654240013036 0ustar0000000000000000The MIT License (MIT) Copyright (c) 2015 Johann Hofmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. difference-2.0.0/README.md01006440000765000002400000002756132316660420013316 0ustar0000000000000000# difference.rs [![](https://travis-ci.org/johannhof/difference.rs.svg?branch=master)](https://travis-ci.org/johannhof/difference.rs) [![](https://ci.appveyor.com/api/projects/status/n1nqaitd5uja8tsi/branch/master?svg=true)](https://ci.appveyor.com/project/johannhof/liquid-rust/branch/master) [![](https://coveralls.io/repos/johannhof/difference.rs/badge.svg?branch=master&service=github)](https://coveralls.io/github/johannhof/difference.rs?branch=master) [![](https://img.shields.io/crates/v/difference.svg)](https://crates.io/crates/difference) A Rust text diffing library with built-in diffing assertion. __[Documentation](https://johannhof.github.io/difference.rs)__ __[Examples](/Examples.md)__ ```rust use difference::Changeset; let changeset = Changeset::new("test", "tent", ""); assert_eq!(changeset.diffs, vec![ Difference::Same("te".to_string()), Difference::Rem("s".to_string()), Difference::Add("n".to_string()), Difference::Same("t".to_string()) ]); ``` ![](https://raw.githubusercontent.com/johannhof/difference.rs/master/assets/fox.png) ![](https://raw.githubusercontent.com/johannhof/difference.rs/master/assets/github-style.png) Usage ---------- Add the following to your Cargo.toml: ```toml [dependencies] difference = "2.0" ``` Now you can use the crate in your code ```rust extern crate difference; ``` Using the binary ----------------- difference can also be used as a command-line application. The best way to install it is using: ```sh $ cargo install --features=bin ``` difference-2.0.0/rustfmt.toml01006440000765000002400000000115132245072000014413 0ustar0000000000000000format_strings = false reorder_imports = true error_on_line_overflow = false difference-2.0.0/src/display.rs01006440000765000002400000006060130471665440014640 0ustar0000000000000000 use super::{Changeset, Difference}; use std::fmt; impl fmt::Display for Changeset { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for d in &self.diffs { match *d { Difference::Same(ref x) => { try!(write!(f, "{}{}", x, self.split)); } Difference::Add(ref x) => { try!(write!(f, "\x1b[92m{}\x1b[0m{}", x, self.split)); } Difference::Rem(ref x) => { try!(write!(f, "\x1b[91m{}\x1b[0m{}", x, self.split)); } } } Ok(()) } } #[cfg(test)] mod tests { use super::super::Changeset; use std::io::Write; use std::iter::FromIterator; use std::thread; use std::time; /// convert slice to vector for assert_eq fn vb(b: &'static [u8]) -> Vec { Vec::from_iter(b.iter().cloned()) } /// if the format changes, you can use this to help create the test for color /// just pass it in and copy-paste (validating that it looks right first of course...) #[allow(dead_code)] fn debug_bytes(result: &[u8], expected: &[u8]) { // sleep for a bit so stderr passes us thread::sleep(time::Duration::new(0, 2e8 as u32)); println!("Debug Result:"); for b in result { print!("{}", *b as char); } println!("Repr Result:"); repr_bytes(result); println!(""); println!("--Result Repr DONE"); println!("Debug Expected:"); for b in expected { print!("{}", *b as char); } println!("Repr Expected:"); repr_bytes(expected); println!(""); println!("--Expected Repr DONE"); } /// for helping debugging what the actual bytes are /// for writing user tests fn repr_bytes(bytes: &[u8]) { for b in bytes { match *b { // 9 => print!("{}", *b as char), // TAB b'\n' => print!("\\n"), b'\r' => print!("\\r"), 32...126 => print!("{}", *b as char), // visible ASCII _ => print!(r"\x{:0>2x}", b), } } } #[test] fn test_display() { let text1 = "Roses are red, violets are blue,\n\ I wrote this library,\n\ just for you.\n\ (It's true)."; let text2 = "Roses are red, violets are blue,\n\ I wrote this documentation,\n\ just for you.\n\ (It's quite true)."; let expected = b"Roses are red, violets are blue,\n\x1b[91mI wrote this library,\x1b\ [0m\n\x1b[92mI wrote this documentation,\x1b[0m\njust for you.\n\x1b\ [91m(It's true).\x1b[0m\n\x1b[92m(It's quite true).\x1b[0m\n"; let ch = Changeset::new(text1, text2, "\n"); let mut result: Vec = Vec::new(); write!(result, "{}", ch).unwrap(); debug_bytes(&result, expected); assert_eq!(result, vb(expected)); } } difference-2.0.0/src/lcs.rs01006440000765000002400000007231132245072000013736 0ustar0000000000000000use std::cmp::max; // strsplit is like `s.split(split)`, except that if `split` is "", it // trims the leading and trailing empty elements, since the `lcs` // logic won't handle those properly. fn strsplit<'a>(s: &'a str, split: &str) -> Vec<&'a str> { let mut si = s.split(split); if split == "" { si.next(); } let mut v: Vec<&str> = si.collect(); if split == "" { v.pop(); } v } // finds the longest common subsequences // outputs the edit distance and a string containing // all chars both inputs have in common // // This algorithm is based on // https://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Code_for_the_dynamic_programming_solution #[allow(non_snake_case)] #[cfg_attr(feature = "cargo-clippy", allow(many_single_char_names))] pub fn lcs(orig: &str, edit: &str, split: &str) -> (i32, String) { // make list by custom splits let a = strsplit(orig, split); let b = strsplit(edit, split); let N = a.len(); let M = b.len(); let mut idx: Vec = Vec::with_capacity(N * M); idx.resize(N * M, 0); for i in 0..N { for j in 0..M { if b[j] == a[i] { if i == 0 || j == 0 { idx[i * M + j] = 1; } else { idx[i * M + j] = idx[(i - 1) * M + j - 1] + 1; } } else if i == 0 { if j == 0 { idx[i * M + j] = 0; } else { idx[i * M + j] = idx[i * M + j - 1]; } } else if j == 0 { idx[i * M + j] = idx[(i - 1) * M + j]; } else { idx[i * M + j] = max(idx[i * M + j - 1], idx[(i - 1) * M + j]); } } } let mut i = (N as isize) - 1; let mut j = (M as isize) - 1; let mut lcs = Vec::new(); while i >= 0 && j >= 0 { let ui = i as usize; let uj = j as usize; if a[ui] == b[uj] { lcs.push(a[ui]); i -= 1; j -= 1; } else if j == 0 && i == 0 { break; } else if i == 0 || idx[ui * M + uj - 1] > idx[(ui - 1) * M + uj] { j -= 1; } else { i -= 1; } } lcs.reverse(); ((N + M - 2 * lcs.len()) as i32, lcs.join(split)) } #[test] fn test_lcs() { assert_eq!(lcs("test", "tost", ""), (2, "tst".to_string())); assert_eq!(lcs("test", "test", ""), (0, "test".to_string())); assert_eq!(lcs("test", "test", " "), (0, "test".to_string())); assert_eq!( lcs( "The quick brown fox jumps over the lazy dog", "The quick brown dog leaps over the lazy cat", "", ), (16, "The quick brown o ps over the lazy ".to_string()) ); assert_eq!( lcs( "The quick brown fox jumps over the lazy dog", "The quick brown dog leaps over the lazy cat", " ", ), (6, "The quick brown over the lazy".to_string()) ); assert_eq!( lcs( "The quick brown fox jumps over the lazy dog", "The quick brown dog leaps over the lazy cat", "\n", ), (2, "".to_string()) ); assert_eq!( lcs( "The quick brown fox jumps over the lazy dog", "The quick brown fox jumps over the lazy dog", "\n", ), (0, "The quick brown fox jumps over the lazy dog".to_string()) ); assert_eq!( lcs("a b : c", "b a : b : c", " "), (2, "a b : c".to_string()) ); assert_eq!(lcs("", "a b c", ""), (5, "".to_string())); assert_eq!(lcs("", " a", " "), (1, "".to_string())); } difference-2.0.0/src/lib.rs01006440000765000002400000023555132316660660013750 0ustar0000000000000000//! Functions to find the difference between two texts (strings). //! Usage //! ---------- //! //! Add the following to your `Cargo.toml`: //! //! ```toml //! [dependencies] //! difference = "2.0" //! ``` //! //! Now you can use the crate in your code //! ```ignore //! extern crate difference; //! ``` //! //! ## Examples //! //! See [Examples.md](Examples.md) for more examples. //! //! ```rust //! use difference::{Difference, Changeset}; //! //! let changeset = Changeset::new("test", "tent", ""); //! //! assert_eq!(changeset.diffs, vec![ //! Difference::Same("te".to_string()), //! Difference::Rem("s".to_string()), //! Difference::Add("n".to_string()), //! Difference::Same("t".to_string()) //! ]); //! ``` #![crate_name = "difference"] #![doc(html_root_url = "http://docs.rs/difference")] #![deny(missing_docs)] #![deny(warnings)] mod lcs; mod merge; mod display; use lcs::lcs; use merge::merge; /// Defines the contents of a changeset /// Changesets will be delivered in order of appearance in the original string /// Sequences of the same kind will be grouped into one Difference #[derive(PartialEq, Debug)] pub enum Difference { /// Sequences that are the same Same(String), /// Sequences that are an addition (don't appear in the first string) Add(String), /// Sequences that are a removal (don't appear in the second string) Rem(String), } /// The information about a full changeset pub struct Changeset { /// An ordered vector of `Difference` objects, coresponding /// to the differences within the text pub diffs: Vec, /// The split used when creating the `Changeset` /// Common splits are `""` for char-level, `" "` for word-level and `"\n"` for line-level. pub split: String, /// The edit distance of the `Changeset` pub distance: i32, } impl Changeset { /// Calculates the edit distance and the changeset for two given strings. /// The first string is assumed to be the "original", the second to be an /// edited version of the first. The third parameter specifies how to split /// the input strings, leading to a more or less exact comparison. /// /// Common splits are `""` for char-level, `" "` for word-level and `"\n"` for line-level. /// /// Outputs the edit distance (how much the two strings differ) and a "changeset", that is /// a `Vec` containing `Difference`s. /// /// # Examples /// /// ``` /// use difference::{Changeset, Difference}; /// /// let changeset = Changeset::new("test", "tent", ""); /// /// assert_eq!(changeset.diffs, vec![ /// Difference::Same("te".to_string()), /// Difference::Rem("s".to_string()), /// Difference::Add("n".to_string()), /// Difference::Same("t".to_string()) /// ]); /// ``` pub fn new(orig: &str, edit: &str, split: &str) -> Changeset { let (dist, common) = lcs(orig, edit, split); Changeset { diffs: merge(orig, edit, &common, split), split: split.to_string(), distance: dist, } } } /// **This function is deprecated, please use `Changeset::new` instead** /// /// Calculates the edit distance and the changeset for two given strings. /// The first string is assumed to be the "original", the second to be an /// edited version of the first. The third parameter specifies how to split /// the input strings, leading to a more or less exact comparison. /// /// Common splits are `""` for char-level, `" "` for word-level and `"\n"` for line-level. /// /// Outputs the edit distance (how much the two strings differ) and a "changeset", that is /// a `Vec` containing `Difference`s. /// /// # Examples /// /// ``` /// use difference::diff; /// use difference::Difference; /// /// let (dist, changeset) = diff("test", "tent", ""); /// /// assert_eq!(changeset, vec![ /// Difference::Same("te".to_string()), /// Difference::Rem("s".to_string()), /// Difference::Add("n".to_string()), /// Difference::Same("t".to_string()) /// ]); /// ``` #[deprecated(since = "1.0.0", note = "please use `Changeset::new` instead")] pub fn diff(orig: &str, edit: &str, split: &str) -> (i32, Vec) { let ch = Changeset::new(orig, edit, split); (ch.distance, ch.diffs) } /// Assert the difference between two strings. Works like diff, but takes /// a fourth parameter that is the expected edit distance (e.g. 0 if you want to /// test for equality). /// /// To include this macro use: /// /// ``` /// #[macro_use(assert_diff)] /// extern crate difference; /// # fn main() { } /// ``` /// /// Remember that edit distance might not be equal to your understanding of difference, /// for example the words "Rust" and "Dust" have an edit distance of 2 because two changes (a /// removal and an addition) are required to make them look the same. /// /// Will print an error with a colorful diff in case of failure. #[macro_export] macro_rules! assert_diff { ($orig:expr , $edit:expr, $split: expr, $expected: expr) => ({ let orig = $orig; let edit = $edit; let changeset = $crate::Changeset::new(orig, edit, &($split)); if changeset.distance != $expected { println!("{}", changeset); panic!("assertion failed: edit distance between {:?} and {:?} is {} and not {}, see \ diffset above", orig, edit, changeset.distance, &($expected)) } }) } /// **This function is deprecated, `Changeset` now implements the `Display` trait instead** /// /// Prints a colorful visual representation of the diff. /// This is just a convenience function for those who want quick results. /// /// I recommend checking out the examples on how to build your /// own diff output. /// # Examples /// /// ``` /// use difference::print_diff; /// print_diff("Diffs are awesome", "Diffs are cool", " "); /// ``` #[deprecated(since = "1.0.0", note = "`Changeset` now implements the `Display` trait instead")] pub fn print_diff(orig: &str, edit: &str, split: &str) { let ch = Changeset::new(orig, edit, split); println!("{}", ch); } #[test] fn test_diff() { let text1 = "Roses are red, violets are blue,\n\ I wrote this library,\n\ just for you.\n\ (It's true)."; let text2 = "Roses are red, violets are blue,\n\ I wrote this documentation,\n\ just for you.\n\ (It's quite true)."; let changeset = Changeset::new(text1, text2, "\n"); assert_eq!(changeset.distance, 4); assert_eq!( changeset.diffs, vec![ Difference::Same("Roses are red, violets are blue,".to_string()), Difference::Rem("I wrote this library,".to_string()), Difference::Add("I wrote this documentation,".to_string()), Difference::Same("just for you.".to_string()), Difference::Rem("(It's true).".to_string()), Difference::Add("(It's quite true).".to_string()), ] ); } #[test] fn test_diff_brief() { let text1 = "Hello\nworld"; let text2 = "Ola\nmundo"; let changeset = Changeset::new(text1, text2, "\n"); assert_eq!( changeset.diffs, vec![ Difference::Rem("Hello\nworld".to_string()), Difference::Add("Ola\nmundo".to_string()), ] ); } #[test] fn test_diff_smaller_line_count_on_left() { let text1 = "Hello\nworld"; let text2 = "Ola\nworld\nHow is it\ngoing?"; let changeset = Changeset::new(text1, text2, "\n"); assert_eq!( changeset.diffs, vec![ Difference::Rem("Hello".to_string()), Difference::Add("Ola".to_string()), Difference::Same("world".to_string()), Difference::Add("How is it\ngoing?".to_string()), ] ); } #[test] fn test_diff_smaller_line_count_on_right() { let text1 = "Hello\nworld\nWhat a \nbeautiful\nday!"; let text2 = "Ola\nworld"; let changeset = Changeset::new(text1, text2, "\n"); assert_eq!( changeset.diffs, vec![ Difference::Rem("Hello".to_string()), Difference::Add("Ola".to_string()), Difference::Same("world".to_string()), Difference::Rem("What a \nbeautiful\nday!".to_string()), ] ); } #[test] fn test_diff_similar_text_with_smaller_line_count_on_right() { let text1 = "Hello\nworld\nWhat a \nbeautiful\nday!"; let text2 = "Hello\nwoRLd"; let changeset = Changeset::new(text1, text2, "\n"); assert_eq!( changeset.diffs, vec![ Difference::Same("Hello".to_string()), Difference::Rem("world\nWhat a \nbeautiful\nday!".to_string()), Difference::Add("woRLd".to_string()), ] ); } #[test] fn test_diff_similar_text_with_similar_line_count() { let text1 = "Hello\nworld\nWhat a \nbeautiful\nday!"; let text2 = "Hello\nwoRLd\nbeautiful"; let changeset = Changeset::new(text1, text2, "\n"); assert_eq!( changeset.diffs, vec![ Difference::Same("Hello".to_string()), Difference::Rem("world\nWhat a ".to_string()), Difference::Add("woRLd".to_string()), Difference::Same("beautiful".to_string()), Difference::Rem("day!".to_string()), ] ); } #[test] #[should_panic] fn test_assert_diff_panic() { let text1 = "Roses are red, violets are blue,\n\ I wrote this library,\n\ just for you.\n\ (It's true)."; let text2 = "Roses are red, violets are blue,\n\ I wrote this documentation,\n\ just for you.\n\ (It's quite true)."; assert_diff!(text1, text2, "\n'", 0); } #[test] fn test_assert_diff() { let text1 = "Roses are red, violets are blue"; let text2 = "Roses are green, violets are blue"; assert_diff!(text1, text2, " ", 2); } difference-2.0.0/src/main.rs01006440000765000002400000002106132245072000014075 0ustar0000000000000000#![deny(warnings)] #[cfg(feature = "bin")] extern crate difference; #[cfg(feature = "bin")] extern crate getopts; #[cfg(feature = "bin")] use getopts::Options; #[cfg(feature = "bin")] use std::env; #[cfg(not(feature = "bin"))] fn main() { panic!("Needs to be compiled with --features=bin"); } #[cfg(feature = "bin")] fn main() { let args: Vec = env::args().collect(); let program = args[0].clone(); let mut opts = Options::new(); opts.optopt("s", "split", "", "char|word|line"); let matches = match opts.parse(&args[1..]) { Ok(m) => m, Err(f) => panic!(f.to_string()), }; let split = match matches.opt_str("s") { Some(ref x) if x == "char" => "", Some(ref x) if x == "word" => " ", Some(ref x) if x == "line" => "\n", _ => " ", }; if matches.free.len() > 1 { let ch = difference::Changeset::new(&matches.free[0], &matches.free[1], split); println!("{}", ch); } else { print!("{}", opts.usage(&format!("Usage: {} [options]", program))); return; }; } difference-2.0.0/src/merge.rs01006440000765000002400000004531132245072000014254 0ustar0000000000000000use Difference; // merges the changes from two strings, given a common substring pub fn merge(orig: &str, edit: &str, common: &str, split: &str) -> Vec { let mut ret = Vec::new(); let mut l = orig.split(split).peekable(); let mut r = edit.split(split).peekable(); let mut c = common.split(split).peekable(); // Turn empty strings into [], not [""] if orig == "" { l.next(); } if edit == "" { r.next(); } if common == "" { c.next(); } while l.peek().is_some() || r.peek().is_some() { let mut same = Vec::new(); while l.peek().is_some() && l.peek() == c.peek() && r.peek() == c.peek() { same.push(l.next().unwrap()); r.next(); c.next(); } if !same.is_empty() { let joined = same.join(split); if split != "" || joined != "" { ret.push(Difference::Same(joined)); } } let mut rem = Vec::new(); while l.peek().is_some() && l.peek() != c.peek() { rem.push(l.next().unwrap()); } if !rem.is_empty() { ret.push(Difference::Rem(rem.join(split))); } let mut add = Vec::new(); while r.peek().is_some() && r.peek() != c.peek() { add.push(r.next().unwrap()); } if !add.is_empty() { ret.push(Difference::Add(add.join(split))); } } ret } #[test] fn test_merge() { assert_eq!( merge("testa", "tost", "tst", ""), vec![ Difference::Same("t".to_string()), Difference::Rem("e".to_string()), Difference::Add("o".to_string()), Difference::Same("st".to_string()), Difference::Rem("a".to_string()), ] ); assert_eq!( merge("", "a", "", ""), vec![Difference::Add("a".to_string())] ); assert_eq!( merge("a\nb", "a\n\nb", "a\nb", "\n"), vec![ Difference::Same("a".to_string()), Difference::Add("".to_string()), Difference::Same("b".to_string()), ] ); assert_eq!( merge("a\n", "c\n", "\n", "\n"), vec![ Difference::Rem("a".to_string()), Difference::Add("c".to_string()), Difference::Same("".to_string()), ] ); } difference-2.0.0/tests/quickcheck.rs01006440000765000002400000006702132245072000015644 0ustar0000000000000000extern crate difference; extern crate quickcheck; use difference::{Changeset, Difference}; use quickcheck::{TestResult, quickcheck, QuickCheck}; use std::fmt; const DEBUG: bool = false; struct Check<'a> { old: &'a str, new: &'a str, changeset: Changeset, } impl<'a> fmt::Display for Check<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "Changeset::new({:?}, {:?}, {:?}) -> [", self.old, self.new, self.changeset.split )?; let mut iter = self.changeset.diffs.iter(); if let Some(d) = iter.next() { write!(f, "{:?}", d)?; } for d in iter { write!(f, " {:?}", d)?; } write!(f, "]") } } fn check_changeset(old: &str, new: &str, split: &str) -> TestResult { Check::new(old, new, split).check() } impl<'a> Check<'a> { fn new(old: &'a str, new: &'a str, split: &'a str) -> Check<'a> { Check { old: old, new: new, changeset: Changeset::new(old, new, split), } } fn check(&self) -> TestResult { let split = &self.changeset.split; let mut old: Vec<&str> = Vec::new(); let mut new: Vec<&str> = Vec::new(); for d in &self.changeset.diffs { if DEBUG { println!("assert `{:?}` (old: {:?}, new: {:?})", d, old, new); } match *d { Difference::Same(ref x) => { old.push(x); new.push(x); } Difference::Add(ref x) => { new.push(x); } Difference::Rem(ref x) => { old.push(x); } } } let got_old = old.join(split); let got_new = new.join(split); if got_old != self.old { return TestResult::error(format!("Diff output implies old=`{:?}`, not `{:?}` in {}", got_old, self.old, self, )); } if got_new != self.new { return TestResult::error(format!("Diff output implies new=`{:?}`, not `{:?}` in {}", got_new, self.new, self, )); } TestResult::passed() } } #[test] fn simple() { quickcheck(check_changeset("a", "a a", " ")); } #[test] fn issue_19() { // https://github.com/johannhof/difference.rs/issues/19 quickcheck(check_changeset("a b : g", "b a : b b : g g", " ")); } #[test] #[allow(needless_pass_by_value)] fn fuzzy() { fn prop(old: Vec, new: Vec, words: Vec) -> TestResult { if words.is_empty() { return TestResult::discard(); } fn map_to_words(input: &[usize], words: &[char]) -> String { input.iter().enumerate().fold( String::new(), |mut acc, (i, x)| { if i > 0 { acc.push(' '); } acc.push(words[x % words.len()]); acc }, ) } let old = map_to_words(&old, &words); let new = map_to_words(&new, &words); check_changeset(&old, &new, " ") } QuickCheck::new() .tests(100) // max successful tests .max_tests(10_000) // max attempts .quickcheck(prop as fn(Vec, Vec, Vec) -> TestResult); }